fix: keymap conflicts + generated Vim keymap cheatsheet #10

Merged
rootiest merged 4 commits from fix/keymap-conflicts-cheatsheet into main 2026-10-04 06:42:33 +00:00
10 changed files with 6776 additions and 0 deletions
Showing only changes of commit 6e1c6d081a - Show all commits

No files matched your search

+1
View File
@@ -377,3 +377,4 @@ docs/specs
docs/devlogs docs/devlogs
# ────────────────────────────────────────────────────────────── # ──────────────────────────────────────────────────────────────
/docs/cheatsheet/__pycache__/
File diff suppressed because it is too large. Load diff
File diff suppressed because it is too large. Load diff
+994
View File
@@ -0,0 +1,994 @@
{
"essentials": [
{"t": "h"},
{"t": "j"},
{"t": "k"},
{"t": "l"},
{"t": "w"},
{"t": "b"},
{"t": "e"},
{"t": "ge"},
{"t": "W"},
{"t": "B"},
{"t": "E"},
{"t": "0"},
{"t": "^"},
{"t": "$"},
{"t": "gg"},
{"t": "G"},
{"t": "%"},
{"t": "{"},
{"t": "}"},
{"t": "("},
{"t": ")"},
{"t": "H"},
{"t": "M"},
{"t": "L"},
{"t": "f"},
{"t": "F"},
{"t": "t"},
{"t": "T"},
{"t": ";"},
{"t": ","},
{"t": "star"},
{"t": "#"},
{"t": "n"},
{"t": "N"},
{"t": "/"},
{"t": "?"},
{"t": "gj"},
{"t": "gk"},
{"t": "d"},
{"t": "c"},
{"t": "y"},
{"t": "p"},
{"t": "P"},
{"t": "dd"},
{"t": "cc"},
{"t": "yy"},
{"t": "D"},
{"t": "C"},
{"t": "Y"},
{"t": ">"},
{"t": "<"},
{"t": ">>"},
{"t": "<<"},
{"t": "="},
{"t": "=="},
{"t": "gu"},
{"t": "gU"},
{"t": "g~"},
{"t": "gq"},
{"t": "x"},
{"t": "r"},
{"t": "R"},
{"t": "J"},
{"t": "u"},
{"t": "CTRL-R"},
{"t": "."},
{"t": "~"},
{"t": "CTRL-A"},
{"t": "CTRL-X"},
{"t": "o"},
{"t": "O"},
{"t": "i"},
{"t": "a"},
{"t": "I"},
{"t": "A"},
{"t": "gi"},
{"t": "&"},
{"t": "v"},
{"t": "V"},
{"t": "CTRL-V"},
{"t": "gv"},
{"t": "v_o"},
{"t": "v_b_I"},
{"t": "v_b_A"},
{"t": "v_P"},
{"t": "gn"},
{"t": "m"},
{"t": "'"},
{"t": "`"},
{"t": "''"},
{"t": "CTRL-O"},
{"t": "CTRL-I"},
{"t": "g;"},
{"t": "quote"},
{"t": "q"},
{"t": "@"},
{"t": "@@"},
{"t": "Q"},
{"t": "CTRL-D"},
{"t": "CTRL-U"},
{"t": "CTRL-F"},
{"t": "CTRL-B"},
{"t": "CTRL-E"},
{"t": "CTRL-Y"},
{"t": "zz"},
{"t": "zt"},
{"t": "zb"},
{"t": "CTRL-W_s"},
{"t": "CTRL-W_v"},
{"t": "CTRL-W_w"},
{"t": "CTRL-W_h"},
{"t": "CTRL-W_j"},
{"t": "CTRL-W_k"},
{"t": "CTRL-W_l"},
{"t": "CTRL-W_q"},
{"t": "CTRL-W_o"},
{"t": "CTRL-W_="},
{"t": "za"},
{"t": "zo"},
{"t": "zc"},
{"t": "zR"},
{"t": "zM"},
{"t": "z="},
{"t": "]s"},
{"t": "CTRL-]"},
{"t": "CTRL-T"},
{"t": "gf"},
{"t": "gx"},
{"t": "CTRL-^"},
{"t": "ZZ"},
{"t": "gt"},
{"t": "CTRL-L"},
{"t": "i_<Esc>"},
{"t": "i_CTRL-R"},
{"t": "i_CTRL-W"},
{"t": "i_CTRL-U"},
{"t": "i_CTRL-O"},
{"t": "i_CTRL-X_CTRL-F"},
{"t": "i_CTRL-V"},
{"t": "c_CTRL-R"},
{"t": "c_<Tab>"},
{"t": "c_<Up>"},
{"t": "c_CTRL-U"},
{"t": "v_iw"},
{"t": "v_aw"},
{"t": "v_ip"},
{"t": "v_ap"},
{"t": "v_iquote"},
{"t": "v_aquote"},
{"t": "v_i'"},
{"t": "v_i("},
{"t": "v_a("},
{"t": "v_iB"},
{"t": "v_aB"},
{"t": "v_i["},
{"t": "v_it"},
{"t": "v_at"},
{"t": ":write"},
{"t": ":quit"},
{"t": ":wq"},
{"t": ":xit"},
{"t": ":edit"},
{"t": ":substitute"},
{"t": ":global"},
{"t": ":normal"},
{"t": ":sort"},
{"t": ":earlier"},
{"t": ":cdo"},
{"t": ":buffer"},
{"t": ":ls"},
{"t": ":split"},
{"t": ":vsplit"},
{"t": ":tabnew"},
{"t": ":nohlsearch"},
{"t": ":registers"},
{"t": ":marks"},
{"t": ":help"},
{"t": ":copen"},
{"t": ":update"},
{"t": ":wall"},
{"t": ":qall"},
{"t": ":move"},
{"t": ":copy"},
{"t": ":!"},
{"t": ":source"},
{"t": ":set"},
{"t": ":verbose"},
{"t": ":terminal"},
{"t": ":checkhealth"}
],
"builtin": {
"h": {"d": "Left N characters", "cat": "Motion"},
"l": {"d": "Right N characters", "cat": "Motion"},
"j": {"d": "Down N lines", "cat": "Motion", "n": "This config maps count-less <kbd>j</kbd>/<kbd>k</kbd> to <kbd>gj</kbd>/<kbd>gk</kbd> (display lines); <kbd>5j</kbd> still moves 5 real lines"},
"k": {"d": "Up N lines", "cat": "Motion"},
"w": {"d": "Forward to start of next word", "cat": "Motion", "n": "word = letters, digits, underscore (or a run of other non-blanks); WORD = anything up to whitespace"},
"W": {"d": "Forward to start of next WORD (blank-delimited)", "cat": "Motion", "n": "WORD = any run of non-blank characters, e.g. <code>foo.bar(baz)</code> is one WORD"},
"b": {"d": "Back to start of word", "cat": "Motion"},
"B": {"d": "Back to start of WORD", "cat": "Motion"},
"e": {"d": "Forward to end of word", "cat": "Motion"},
"E": {"d": "Forward to end of WORD", "cat": "Motion"},
"ge": {"d": "Back to end of previous word", "cat": "Motion"},
"gE": {"d": "Back to end of previous WORD", "cat": "Motion"},
"0": {"d": "To first column of the line", "cat": "Motion"},
"^": {"d": "To first non-blank character of the line", "cat": "Motion"},
"$": {"d": "To end of line (with N: end of line N-1 lines down)", "cat": "Motion", "n": "In Visual block mode <kbd>$</kbd> extends every line to its own end"},
"g_": {"d": "To last non-blank character of the line (N-1 lines down)", "cat": "Motion"},
"gg": {"d": "To first line, or to line N", "cat": "Motion"},
"G": {"d": "To last line, or to line N", "cat": "Motion"},
"N%": {"d": "To N percent through the file", "cat": "Motion"},
"%": {"d": "Jump to the matching bracket, or to the next bracket on the line", "cat": "Motion", "n": "matchit (loaded by default) also jumps between if/else/endif, HTML tags and similar pairs; see <kbd>g%</kbd>, <kbd>[%</kbd>, <kbd>]%</kbd>"},
"{": {"d": "Back to previous blank line (paragraph)", "cat": "Motion"},
"}": {"d": "Forward to next blank line (paragraph)", "cat": "Motion"},
"(": {"d": "Back N sentences", "cat": "Motion"},
")": {"d": "Forward N sentences", "cat": "Motion"},
"H": {"d": "To top line of the window (Nth line from top)", "cat": "Motion"},
"M": {"d": "To middle line of the window", "cat": "Motion"},
"L": {"d": "To bottom line of the window (Nth line from bottom)", "cat": "Motion"},
"f": {"d": "To Nth {char} to the right on this line", "cat": "Motion"},
"F": {"d": "To Nth {char} to the left on this line", "cat": "Motion"},
"t": {"d": "Till before Nth {char} to the right", "cat": "Motion"},
"T": {"d": "Till after Nth {char} to the left", "cat": "Motion"},
";": {"d": "Repeat last f/t/F/T in the same direction", "cat": "Motion"},
",": {"d": "Repeat last f/t/F/T in the opposite direction", "cat": "Motion"},
"bar": {"d": "To column N of the line", "cat": "Motion"},
"-": {"d": "Up N lines, on first non-blank", "cat": "Motion"},
"+": {"d": "Down N lines, on first non-blank", "cat": "Motion"},
"<CR>": {"d": "Down N lines, on first non-blank (same as +)", "cat": "Motion"},
"CTRL-M": {"d": "Same as <CR>: down N lines, first non-blank", "cat": "Motion"},
"_": {"d": "To first non-blank, N-1 lines down (linewise)", "cat": "Motion"},
"gj": {"d": "Down N display (wrapped) lines", "cat": "Motion"},
"gk": {"d": "Up N display (wrapped) lines", "cat": "Motion"},
"g0": {"d": "To first character of the screen line", "cat": "Motion"},
"g^": {"d": "To first non-blank of the screen line", "cat": "Motion"},
"g$": {"d": "To last character of the screen line", "cat": "Motion"},
"gm": {"d": "To middle of the screen width", "cat": "Motion"},
"gM": {"d": "To middle of the text line (N percent with a count)", "cat": "Motion"},
"go": {"d": "To byte N in the buffer", "cat": "Motion"},
"<Space>": {"d": "Right N characters (same as l)", "cat": "Motion"},
"<BS>": {"d": "Left N characters (same as h)", "cat": "Motion"},
"CTRL-H": {"d": "Left N characters (same as h)", "cat": "Motion"},
"CTRL-N": {"d": "Down N lines (same as j)", "cat": "Motion"},
"CTRL-P": {"d": "Up N lines (same as k)", "cat": "Motion"},
"CTRL-J": {"d": "Down N lines (same as j)", "cat": "Motion"},
"<NL>": {"d": "Down N lines (same as j)", "cat": "Motion"},
"[(": {"d": "Back to unmatched '('", "cat": "Motion"},
"[{": {"d": "Back to unmatched '{' (start of block)", "cat": "Motion"},
"])": {"d": "Forward to unmatched ')'", "cat": "Motion"},
"]}": {"d": "Forward to unmatched '}' (end of block)", "cat": "Motion"},
"[[": {"d": "Back to previous section ('{' in column 1)", "cat": "Motion"},
"]]": {"d": "Forward to next section ('{' in column 1)", "cat": "Motion"},
"[]": {"d": "Back to previous section end ('}' in column 1)", "cat": "Motion"},
"][": {"d": "Forward to next section end ('}' in column 1)", "cat": "Motion"},
"[m": {"d": "Back to start of a method (Java/C++ style class)", "cat": "Motion"},
"]m": {"d": "Forward to start of the next method (Java/C++ style class)", "cat": "Motion"},
"[/": {"d": "Back to start of a C comment /*", "cat": "Motion"},
"]/": {"d": "Forward to end of a C comment */", "cat": "Motion"},
"[#": {"d": "Back to unmatched #if / #else", "cat": "Motion"},
"]#": {"d": "Forward to unmatched #else / #endif", "cat": "Motion"},
"star": {"d": "Search forward for the whole word under the cursor", "cat": "Search", "n": "Whole-word match (<code>\\&lt;word\\&gt;</code>); 'ignorecase' applies, 'smartcase' does not. In Visual mode Neovim's default <kbd>*</kbd> searches for the selected text instead"},
"#": {"d": "Search backward for the whole word under the cursor", "cat": "Search"},
"gstar": {"d": "Like * but also matches inside longer words", "cat": "Search"},
"g#": {"d": "Like # but also matches inside longer words", "cat": "Search"},
"n": {"d": "Repeat last search in the same direction", "cat": "Search", "n": "<kbd>n</kbd> follows the direction of the last / or ?, so after <kbd>?</kbd> it goes backward"},
"N": {"d": "Repeat last search in the opposite direction", "cat": "Search", "n": "Opposite of the last search direction, not always 'backward'"},
"/": {"d": "Search forward for {pattern}", "cat": "Search", "n": "Case-sensitive in this config ('ignorecase' off); add <code>\\c</code> to the pattern to ignore case. Search offsets: <code>/foo/e</code> end, <code>/foo/+1</code> next line"},
"?": {"d": "Search backward for {pattern}", "cat": "Search"},
"/<CR>": {"d": "Search forward again with the last pattern", "cat": "Search"},
"?<CR>": {"d": "Search backward again with the last pattern", "cat": "Search"},
"gn": {"d": "Select next match of the last search (cgn + . changes them one by one)", "cat": "Search", "n": "Works as a text object: <kbd>cgn</kbd> changes the next match, then <kbd>.</kbd> repeats on the next one"},
"gN": {"d": "Select previous match of the last search", "cat": "Search"},
"gd": {"d": "Go to local declaration of the word (searches back in the function)", "cat": "Search", "n": "This config maps <kbd>gd</kbd> to the Snacks LSP definitions picker"},
"gD": {"d": "Go to global declaration of the word (searches from top of file)", "cat": "Search", "n": "This config maps <kbd>gD</kbd> to the Snacks LSP declarations picker"},
"CTRL-C": {"d": "Interrupt the current command or search", "cat": "Search"},
"[I": {"d": "List lines containing the word under cursor (also in included files)", "cat": "Search"},
"]I": {"d": "List lines containing the word under cursor, starting at the cursor", "cat": "Search"},
"[i": {"d": "Show first line containing the word under cursor (incl. included files)", "cat": "Search"},
"]i": {"d": "Show first line below the cursor containing the word", "cat": "Search"},
"[_CTRL-I": {"d": "Jump to first line containing the word under cursor", "cat": "Search"},
"]_CTRL-I": {"d": "Jump to first line below the cursor containing the word", "cat": "Search"},
"[D": {"d": "List #defines matching the word under cursor", "cat": "Search", "n": "Neovim remaps this key to diagnostic navigation; the #define search is only reachable via <code>:normal!</code>"},
"]D": {"d": "List #defines matching the word under cursor, starting at the cursor", "cat": "Search", "n": "Neovim remaps this key to diagnostic navigation; the #define search is only reachable via <code>:normal!</code>"},
"[d": {"d": "Show first #define matching the word under cursor", "cat": "Search", "n": "Neovim remaps this key to diagnostic navigation; the #define search is only reachable via <code>:normal!</code>"},
"]d": {"d": "Show first #define below the cursor matching the word", "cat": "Search", "n": "Neovim remaps this key to diagnostic navigation; the #define search is only reachable via <code>:normal!</code>"},
"[_CTRL-D": {"d": "Jump to first #define matching the word under cursor", "cat": "Search"},
"]_CTRL-D": {"d": "Jump to first #define below the cursor matching the word", "cat": "Search"},
"<S-LeftMouse>": {"d": "Extend the selection to the mouse click", "cat": "Visual", "n": "Neovim's default 'mousemodel' is <code>popup_setpos</code>; only with <code>extend</code> does it search the clicked word like <kbd>*</kbd>"},
"<S-RightMouse>": {"d": "Search backward for the word at the mouse click (like #)", "cat": "Search"},
"d": {"d": "Delete {motion} text [into register x]", "cat": "Operator", "n": "This config maps <kbd>d</kbd>, <kbd>D</kbd>, <kbd>c</kbd>, <kbd>C</kbd>, <kbd>x</kbd>, <kbd>X</kbd> to <code>\"d</code>…: deleted text goes to register <code>d</code>, not the clipboard. Paste it with <kbd>\"dp</kbd>"},
"c": {"d": "Change: delete {motion} text and start Insert", "cat": "Operator", "n": "Deleted text goes to register <code>d</code> in this config (see <kbd>d</kbd>)"},
"y": {"d": "Yank (copy) {motion} text [into register x]", "cat": "Operator", "n": "With 'clipboard' = unnamedplus, yanks go to the system clipboard (<code>\"+</code>)"},
">": {"d": "Indent {motion} lines one 'shiftwidth'", "cat": "Operator"},
"<": {"d": "Dedent {motion} lines one 'shiftwidth'", "cat": "Operator"},
"=": {"d": "Re-indent {motion} lines (indent rules or 'equalprg')", "cat": "Operator", "n": "Doubled operators act on lines: <kbd>==</kbd>, <kbd>dd</kbd>, <kbd>yy</kbd>, <kbd>gUU</kbd>, <kbd>gqq</kbd>"},
"!": {"d": "Filter {motion} lines through an external command", "cat": "Operator"},
"gu": {"d": "Lowercase {motion} text", "cat": "Operator"},
"gU": {"d": "Uppercase {motion} text", "cat": "Operator"},
"g~": {"d": "Toggle case of {motion} text", "cat": "Operator"},
"g?": {"d": "ROT13-encode {motion} text", "cat": "Operator"},
"gq": {"d": "Format {motion} lines ('textwidth' / 'formatexpr'); cursor moves", "cat": "Operator", "n": "When an LSP attaches, Neovim sets 'formatexpr' to the LSP formatter if it was empty"},
"gw": {"d": "Format {motion} lines and keep the cursor where it was", "cat": "Operator"},
"g@": {"d": "Run 'operatorfunc' on {motion} (custom operators)", "cat": "Operator"},
"o_v": {"d": "Force the operator to work charwise (e.g. dvj)", "cat": "Operator", "n": "Also toggles inclusive/exclusive for charwise motions: <kbd>dve</kbd> leaves the last char"},
"o_V": {"d": "Force the operator to work linewise (e.g. dVw)", "cat": "Operator"},
"o_CTRL-V": {"d": "Force the operator to work blockwise", "cat": "Operator"},
"dd": {"d": "Delete N lines", "cat": "Edit"},
"cc": {"d": "Change N whole lines", "cat": "Edit"},
"yy": {"d": "Yank N lines", "cat": "Edit"},
"D": {"d": "Delete to end of line (and N-1 more lines)", "cat": "Edit"},
"C": {"d": "Change to end of line (and N-1 more lines)", "cat": "Edit"},
"Y": {"d": "Yank N lines (Neovim maps Y to y$: yank to end of line)", "cat": "Edit", "n": "Neovim default mapping <code>Y</code> → <code>y$</code> (like D and C); use <kbd>yy</kbd> for whole lines"},
"p": {"d": "Put (paste) after the cursor N times", "cat": "Edit", "n": "With 'clipboard' = unnamedplus, <kbd>p</kbd> pastes the system clipboard. Deletes go to <code>\"d</code> in this config, so use <kbd>\"dp</kbd> to paste deleted text"},
"P": {"d": "Put (paste) before the cursor N times", "cat": "Edit", "n": "Unlike <kbd>p</kbd>, <kbd>P</kbd> in Visual mode keeps the register, so you can paste repeatedly"},
"gp": {"d": "Put after the cursor and leave the cursor after the pasted text", "cat": "Edit"},
"gP": {"d": "Put before the cursor and leave the cursor after the pasted text", "cat": "Edit"},
"]p": {"d": "Put after, adjusting indent to the current line", "cat": "Edit"},
"[p": {"d": "Put before, adjusting indent to the current line", "cat": "Edit"},
"]P": {"d": "Put before, adjusting indent (same as [p)", "cat": "Edit"},
"[P": {"d": "Put before, adjusting indent (same as [p)", "cat": "Edit"},
">>": {"d": "Indent N lines one 'shiftwidth'", "cat": "Edit"},
"<<": {"d": "Dedent N lines one 'shiftwidth'", "cat": "Edit"},
"==": {"d": "Re-indent N lines", "cat": "Edit"},
"!!": {"d": "Filter N lines through an external command", "cat": "Edit"},
"x": {"d": "Delete N characters under and after the cursor", "cat": "Edit", "n": "Mapped to <code>\"dx</code> here: the character goes to register <code>d</code>"},
"X": {"d": "Delete N characters before the cursor", "cat": "Edit"},
"s": {"d": "Delete N characters and start Insert", "cat": "Edit"},
"S": {"d": "Delete N lines and start Insert (same as cc)", "cat": "Edit"},
"r": {"d": "Replace N characters with {char}", "cat": "Edit"},
"R": {"d": "Enter Replace mode (overtype)", "cat": "Edit"},
"gR": {"d": "Enter Virtual Replace mode (overtype screen cells, tabs stay intact)", "cat": "Edit"},
"gr": {"d": "Virtual-replace N characters with {char}", "cat": "Edit", "n": "Neovim's <kbd>grn</kbd>/<kbd>gra</kbd>/<kbd>grr</kbd>/<kbd>gri</kbd>/<kbd>grt</kbd>/<kbd>grx</kbd> LSP maps extend <kbd>gr</kbd>, so it waits for 'timeoutlen' before acting"},
"J": {"d": "Join N lines (default 2) with one space", "cat": "Edit", "n": "In Visual mode joins the selected lines"},
"gJ": {"d": "Join lines without inserting or removing spaces", "cat": "Edit"},
"CTRL-A": {"d": "Increment the number at or after the cursor by N", "cat": "Edit", "n": "Works on decimal, 0x hex, 0b binary and (with 'nrformats') letters; <kbd>g&lt;C-a&gt;</kbd> in Visual makes a sequence"},
"CTRL-X": {"d": "Decrement the number at or after the cursor by N", "cat": "Edit"},
"g?g?": {"d": "ROT13-encode the current line", "cat": "Edit"},
"zp": {"d": "Put block without trailing spaces (after)", "cat": "Edit"},
"zP": {"d": "Put block without trailing spaces (before)", "cat": "Edit"},
"zy": {"d": "Yank {motion} without trailing spaces (block mode)", "cat": "Edit"},
"<MiddleMouse>": {"d": "Paste at the mouse position (like gP)", "cat": "Edit"},
"<Del>": {"d": "Delete N characters under the cursor (same as x)", "cat": "Edit"},
"i": {"d": "Insert before the cursor", "cat": "Insert", "n": "A count repeats the inserted text: <kbd>3ihey&lt;Esc&gt;</kbd> → heyheyhey"},
"a": {"d": "Append after the cursor", "cat": "Insert"},
"I": {"d": "Insert at first non-blank of the line", "cat": "Insert"},
"A": {"d": "Append at end of line", "cat": "Insert"},
"gI": {"d": "Insert at column 1", "cat": "Insert", "n": "This config maps <kbd>gI</kbd> to the Snacks LSP implementations picker"},
"gi": {"d": "Insert where Insert mode was last stopped", "cat": "Insert"},
"o": {"d": "Open a new line below and start Insert", "cat": "Insert"},
"O": {"d": "Open a new line above and start Insert", "cat": "Insert"},
"<Insert>": {"d": "Start Insert mode (same as i)", "cat": "Insert"},
"u": {"d": "Undo the last change", "cat": "Undo & repeat", "n": "'undofile' is on in this config, so undo history survives closing the file"},
"CTRL-R": {"d": "Redo the last undone change", "cat": "Undo & repeat"},
"U": {"d": "Undo all recent changes on the last changed line (is itself undoable)", "cat": "Undo & repeat"},
".": {"d": "Repeat the last change (a count replaces the original count)", "cat": "Undo & repeat", "n": "Repeats inserts too: <kbd>A;&lt;Esc&gt;</kbd> then <kbd>j.</kbd> appends ; to the next line"},
"&": {"d": "Repeat last :s on the current line (Neovim: same flags, :&&)", "cat": "Undo & repeat", "n": "Neovim default mapping <code>&amp;</code> → <code>:&amp;&amp;&lt;CR&gt;</code> keeps the last flags (Vim's plain & drops them)"},
"g&": {"d": "Repeat last :s on all lines with the same pattern and flags", "cat": "Undo & repeat"},
"g-": {"d": "Go to older text state (walks undo branches by time)", "cat": "Undo & repeat"},
"g+": {"d": "Go to newer text state (walks undo branches by time)", "cat": "Undo & repeat"},
"<Undo>": {"d": "Undo (same as u)", "cat": "Undo & repeat"},
"@:": {"d": "Repeat the last command-line command N times", "cat": "Undo & repeat", "n": "After the first <kbd>@:</kbd>, <kbd>@@</kbd> repeats it again"},
"v": {"d": "Start charwise Visual mode", "cat": "Visual"},
"V": {"d": "Start linewise Visual mode", "cat": "Visual"},
"CTRL-V": {"d": "Start blockwise Visual mode", "cat": "Visual"},
"gv": {"d": "Reselect the previous Visual area", "cat": "Visual"},
"v_o": {"d": "Move the cursor to the other end of the selection", "cat": "Visual"},
"v_O": {"d": "Block mode: move to the other corner on the same line", "cat": "Visual"},
"v_b_I": {"d": "Block mode: insert the same text before the block on every line", "cat": "Visual", "n": "Type the text, then <kbd>&lt;Esc&gt;</kbd>: it appears on every line of the block"},
"v_b_A": {"d": "Block mode: append the same text after the block on every line", "cat": "Visual"},
"v_gv": {"d": "Swap the current and previous Visual areas", "cat": "Visual"},
"v_v": {"d": "Switch to charwise Visual, or stop Visual mode", "cat": "Visual"},
"v_V": {"d": "Switch to linewise Visual, or stop Visual mode", "cat": "Visual"},
"v_CTRL-V": {"d": "Switch to blockwise Visual, or stop Visual mode", "cat": "Visual"},
"v_<Esc>": {"d": "Stop Visual mode", "cat": "Visual"},
"v_CTRL-C": {"d": "Stop Visual mode", "cat": "Visual"},
"v_CTRL-G": {"d": "Toggle between Visual and Select mode", "cat": "Visual"},
"v_CTRL-O": {"d": "Select mode: switch to Visual mode for one command", "cat": "Visual"},
"gh": {"d": "Start Select mode (charwise)", "cat": "Visual"},
"gH": {"d": "Start Select mode (linewise)", "cat": "Visual"},
"g_CTRL-H": {"d": "Start Select mode (blockwise)", "cat": "Visual"},
"gV": {"d": "In a Select-mode mapping: don't reselect the area afterwards", "cat": "Visual"},
"v_CTRL-\\_CTRL-N": {"d": "Stop Visual mode", "cat": "Visual"},
"v_CTRL-\\_CTRL-G": {"d": "Stop Visual mode (go to Normal)", "cat": "Visual"},
"<RightMouse>": {"d": "Open the right-click popup menu (moves the cursor to the click)", "cat": "Misc", "n": "Neovim's default 'mousemodel' is <code>popup_setpos</code>; with <code>extend</code> it starts or extends Visual mode instead"},
"v_c": {"d": "Change the selection (delete and start Insert)", "n": "Mapped to <code>\"dc</code> in this config (register <code>d</code>)"},
"v_s": {"d": "Change the selection (same as c)"},
"v_d": {"d": "Delete the selection", "n": "Mapped to <code>\"dd</code> in this config (register <code>d</code>)"},
"v_x": {"d": "Delete the selection (same as d)", "n": "Mapped to <code>\"dx</code> in this config (register <code>d</code>)"},
"v_y": {"d": "Yank the selection"},
"v_C": {"d": "Change the selected lines (block: to end of each line)"},
"v_S": {"d": "Change the selected lines"},
"v_R": {"d": "Change the selected lines"},
"v_D": {"d": "Delete the selected lines (block: to end of each line)"},
"v_X": {"d": "Delete the selected lines"},
"v_Y": {"d": "Yank the selected lines"},
"v_p": {"d": "Replace the selection with the register (old text goes to the unnamed register)", "n": "The replaced text goes to the unnamed register, so a second <kbd>p</kbd> pastes the old text; use <kbd>P</kbd> to keep pasting the same thing"},
"v_P": {"d": "Replace the selection with the register (registers unchanged)"},
"v_r": {"d": "Replace every selected character with {char}"},
"v_J": {"d": "Join the selected lines"},
"v_gJ": {"d": "Join the selected lines without spaces"},
"v_u": {"d": "Lowercase the selection"},
"v_U": {"d": "Uppercase the selection"},
"v_~": {"d": "Toggle case of the selection"},
"v_>": {"d": "Indent the selected lines (N times)"},
"v_<": {"d": "Dedent the selected lines (N times)"},
"v_=": {"d": "Re-indent the selected lines"},
"v_gq": {"d": "Format the selected lines"},
"v_!": {"d": "Filter the selected lines through an external command"},
"v_CTRL-A": {"d": "Increment numbers in the selection by N"},
"v_CTRL-X": {"d": "Decrement numbers in the selection by N"},
"v_g_CTRL-A": {"d": "Increment numbers progressively (+N, +2N, … per line)", "n": "Select a column of 0s and press <kbd>g&lt;C-a&gt;</kbd> to number them 1, 2, 3…"},
"v_g_CTRL-X": {"d": "Decrement numbers progressively (-N, -2N, … per line)"},
"v_:": {"d": "Start a command line with the range '<,'> of the selection", "cat": "Command line"},
"v_<BS>": {"d": "Select mode: delete the selection"},
"v_CTRL-H": {"d": "Select mode: delete the selection"},
"m": {"d": "Set mark {a-zA-Z} at the cursor (A-Z are global, across files)", "cat": "Mark & jump", "n": "Special marks: <code>.</code> last change, <code>^</code> last insert, <code>\"</code> last exit, <code>[ ]</code> last change/yank, <code>&lt; &gt;</code> last selection"},
"'": {"d": "Jump to the line of mark {a-zA-Z0-9} (first non-blank)", "cat": "Mark & jump"},
"`": {"d": "Jump to the exact position of mark {a-zA-Z0-9}", "cat": "Mark & jump"},
"''": {"d": "Jump back to the line before the latest jump", "cat": "Mark & jump"},
"``": {"d": "Jump back to the position before the latest jump", "cat": "Mark & jump"},
"CTRL-O": {"d": "Jump to an older position in the jump list", "cat": "Mark & jump", "n": "Jumps are made by G, /, n, %, (, {, marks, etc. — not by j/k or w"},
"CTRL-I": {"d": "Jump to a newer position in the jump list", "cat": "Mark & jump", "n": "<b>Shadowed here:</b> this config maps <kbd>&lt;Tab&gt;</kbd> (Sidekick NES, no fallback) and <kbd>&lt;C-i&gt;</kbd> is not mapped separately, so per <code>:h CTRL-I</code> the <kbd>&lt;Tab&gt;</kbd> map also catches <kbd>&lt;C-i&gt;</kbd>, even in kitty or Neovide; use <kbd>&lt;leader&gt;sj</kbd>"},
"<Tab>": {"d": "Jump to a newer position in the jump list (same as CTRL-I)", "cat": "Mark & jump", "n": "This config maps Normal-mode <kbd>&lt;Tab&gt;</kbd> to Sidekick NES jump/apply (no fallback)"},
"g;": {"d": "Go to an older position in the change list", "cat": "Mark & jump", "n": "Change list = positions of your edits; <kbd>:changes</kbd> lists them"},
"g,": {"d": "Go to a newer position in the change list", "cat": "Mark & jump"},
"`[": {"d": "To start of the last changed, yanked or put text", "cat": "Mark & jump"},
"`]": {"d": "To end of the last changed, yanked or put text", "cat": "Mark & jump"},
"'[": {"d": "To first line of the last changed, yanked or put text", "cat": "Mark & jump"},
"']": {"d": "To last line of the last changed, yanked or put text", "cat": "Mark & jump"},
"`<": {"d": "To start of the last Visual selection", "cat": "Mark & jump"},
"`>": {"d": "To end of the last Visual selection", "cat": "Mark & jump"},
"'<": {"d": "To first line of the last Visual selection", "cat": "Mark & jump"},
"'>": {"d": "To last line of the last Visual selection", "cat": "Mark & jump"},
"g'": {"d": "Jump to mark without adding to the jump list (line)", "cat": "Mark & jump"},
"g`": {"d": "Jump to mark without adding to the jump list (exact position)", "cat": "Mark & jump"},
"['": {"d": "To previous line with a lowercase mark", "cat": "Mark & jump"},
"]'": {"d": "To next line with a lowercase mark", "cat": "Mark & jump"},
"[`": {"d": "To previous lowercase mark", "cat": "Mark & jump"},
"]`": {"d": "To next lowercase mark", "cat": "Mark & jump"},
"quote": {"d": "Use register {x} for the next delete, yank or put", "cat": "Register & macro", "n": "<code>\"\"</code> unnamed, <code>\"0</code> last yank, <code>\"1-9</code> deletes, <code>\"+</code> clipboard, <code>\"_</code> black hole, <code>\"/</code> search, <code>\":</code> last command. In this config d/c/x default to <code>\"d</code> but honour a register you type (except <code>\"+</code>)"},
"@": {"d": "Run the macro in register {a-z} N times", "cat": "Register & macro", "n": "Macros are just registers: <kbd>\"ap</kbd> pastes one to edit, <kbd>\"ayy</kbd> stores it back"},
"@@": {"d": "Repeat the last executed macro (or @:) N times", "cat": "Register & macro"},
"Q": {"d": "Replay the last recorded macro N times", "cat": "Register & macro", "n": "Neovim: <kbd>Q</kbd> replays the last recorded register (Vim's Ex mode is <kbd>gQ</kbd>). In linewise Visual it runs on every selected line"},
"CTRL-D": {"d": "Scroll half a screen down (N lines with a count)", "cat": "Scroll & view"},
"CTRL-U": {"d": "Scroll half a screen up (N lines with a count)", "cat": "Scroll & view"},
"CTRL-F": {"d": "Scroll one screen forward (page down)", "cat": "Scroll & view"},
"CTRL-B": {"d": "Scroll one screen back (page up)", "cat": "Scroll & view"},
"CTRL-E": {"d": "Scroll the view N lines down (text moves up, cursor stays)", "cat": "Scroll & view"},
"CTRL-Y": {"d": "Scroll the view N lines up (text moves down, cursor stays)", "cat": "Scroll & view"},
"zz": {"d": "Scroll so the cursor line is centered", "cat": "Scroll & view"},
"zt": {"d": "Scroll so the cursor line is at the top", "cat": "Scroll & view"},
"zb": {"d": "Scroll so the cursor line is at the bottom", "cat": "Scroll & view"},
"z<CR>": {"d": "Cursor line to top of window, cursor on first non-blank", "cat": "Scroll & view"},
"z.": {"d": "Cursor line to center of window, cursor on first non-blank", "cat": "Scroll & view"},
"z-": {"d": "Cursor line to bottom of window, cursor on first non-blank", "cat": "Scroll & view"},
"zh": {"d": "Scroll the view N characters left (nowrap only)", "cat": "Scroll & view"},
"zl": {"d": "Scroll the view N characters right (nowrap only)", "cat": "Scroll & view"},
"zH": {"d": "Scroll the view half a screen width left (nowrap only)", "cat": "Scroll & view"},
"zL": {"d": "Scroll the view half a screen width right (nowrap only)", "cat": "Scroll & view"},
"zs": {"d": "Scroll horizontally so the cursor is at the left edge (nowrap only)", "cat": "Scroll & view"},
"ze": {"d": "Scroll horizontally so the cursor is at the right edge (nowrap only)", "cat": "Scroll & view"},
"<PageDown>": {"d": "Scroll one screen forward (same as CTRL-F)", "cat": "Scroll & view"},
"<PageUp>": {"d": "Scroll one screen back (same as CTRL-B)", "cat": "Scroll & view"},
"i_<PageUp>": {"d": "Scroll one screen back", "cat": "Scroll & view"},
"i_<PageDown>": {"d": "Scroll one screen forward", "cat": "Scroll & view"},
"i_CTRL-X_CTRL-E": {"d": "Scroll the window one line down (like CTRL-E) in CTRL-X mode", "cat": "Scroll & view"},
"i_CTRL-X_CTRL-Y": {"d": "Scroll the window one line up (like CTRL-Y) in CTRL-X mode", "cat": "Scroll & view"},
"i_<ScrollWheelDown>": {"cat": "Scroll & view"},
"i_<S-ScrollWheelDown>": {"cat": "Scroll & view"},
"i_<ScrollWheelUp>": {"cat": "Scroll & view"},
"i_<S-ScrollWheelUp>": {"cat": "Scroll & view"},
"i_<ScrollWheelLeft>": {"cat": "Scroll & view"},
"i_<S-ScrollWheelLeft>": {"cat": "Scroll & view"},
"i_<ScrollWheelRight>": {"cat": "Scroll & view"},
"i_<S-ScrollWheelRight>": {"cat": "Scroll & view"},
"CTRL-W": {"d": "Window command prefix (see the <C-w> keys)", "cat": "Window"},
"CTRL-W_s": {"d": "Split the window horizontally", "cat": "Window"},
"CTRL-W_S": {"d": "Split the window horizontally (same as s)", "cat": "Window"},
"CTRL-W_v": {"d": "Split the window vertically", "cat": "Window"},
"CTRL-W_w": {"d": "Go to the next window (wraps); with N: go to window N", "cat": "Window", "n": "Most CTRL-W keys also work with CTRL held for the second key: <kbd>&lt;C-w&gt;&lt;C-w&gt;</kbd>"},
"CTRL-W_W": {"d": "Go to the previous window (wraps)", "cat": "Window"},
"CTRL-W_h": {"d": "Go to the window on the left", "cat": "Window"},
"CTRL-W_j": {"d": "Go to the window below", "cat": "Window"},
"CTRL-W_k": {"d": "Go to the window above", "cat": "Window"},
"CTRL-W_l": {"d": "Go to the window on the right", "cat": "Window"},
"CTRL-W_t": {"d": "Go to the top-left window", "cat": "Window"},
"CTRL-W_b": {"d": "Go to the bottom-right window", "cat": "Window"},
"CTRL-W_p": {"d": "Go to the previous (last accessed) window", "cat": "Window"},
"CTRL-W_q": {"d": "Quit the window (like :quit; quits Neovim if it is the last)", "cat": "Window"},
"CTRL-W_c": {"d": "Close the window (like :close; never closes the last one)", "cat": "Window", "n": "<kbd>&lt;C-w&gt;c</kbd> rather than <kbd>&lt;C-w&gt;&lt;C-c&gt;</kbd> (CTRL-C cancels)"},
"CTRL-W_o": {"d": "Close all other windows (like :only)", "cat": "Window"},
"CTRL-W_=": {"d": "Make all windows (almost) the same size", "cat": "Window"},
"CTRL-W__": {"d": "Maximize window height (or set it to N)", "cat": "Window"},
"CTRL-W_bar": {"d": "Maximize window width (or set it to N columns)", "cat": "Window"},
"CTRL-W_+": {"d": "Increase window height by N lines", "cat": "Window"},
"CTRL-W_-": {"d": "Decrease window height by N lines", "cat": "Window"},
"CTRL-W_>": {"d": "Increase window width by N columns", "cat": "Window"},
"CTRL-W_<": {"d": "Decrease window width by N columns", "cat": "Window"},
"CTRL-W_x": {"d": "Swap with the next window (or window N)", "cat": "Window"},
"CTRL-W_r": {"d": "Rotate windows downwards / rightwards", "cat": "Window"},
"CTRL-W_R": {"d": "Rotate windows upwards / leftwards", "cat": "Window"},
"CTRL-W_H": {"d": "Move the window to the far left (full height)", "cat": "Window"},
"CTRL-W_J": {"d": "Move the window to the very bottom (full width)", "cat": "Window"},
"CTRL-W_K": {"d": "Move the window to the very top (full width)", "cat": "Window"},
"CTRL-W_L": {"d": "Move the window to the far right (full height)", "cat": "Window"},
"CTRL-W_T": {"d": "Move the window to a new tab page", "cat": "Window"},
"CTRL-W_n": {"d": "Open a new window with an empty buffer", "cat": "Window"},
"CTRL-W_f": {"d": "Split and edit the file name under the cursor", "cat": "Window"},
"CTRL-W_F": {"d": "Split, edit the file under the cursor and go to its line number", "cat": "Window"},
"CTRL-W_gf": {"d": "Edit the file name under the cursor in a new tab", "cat": "Window"},
"CTRL-W_]": {"d": "Split and jump to the tag under the cursor", "cat": "Window"},
"CTRL-W_}": {"d": "Show the tag under the cursor in the preview window", "cat": "Window"},
"CTRL-W_z": {"d": "Close the preview window", "cat": "Window"},
"CTRL-W_P": {"d": "Go to the preview window", "cat": "Window"},
"CTRL-W_^": {"d": "Split and edit the alternate file (or buffer N)", "cat": "Window"},
"CTRL-W_d": {"d": "Split and jump to the #define of the word under the cursor", "cat": "Window", "n": "Neovim remaps <kbd>&lt;C-w&gt;d</kbd> / <kbd>&lt;C-w&gt;&lt;C-d&gt;</kbd> to show diagnostics in a float"},
"CTRL-W_i": {"d": "Split and jump to the declaration of the word under the cursor", "cat": "Window"},
"CTRL-W_CTRL-C": {"d": "Does nothing (cancels a pending CTRL-W)", "cat": "Window"},
"za": {"d": "Toggle the fold under the cursor", "cat": "Fold"},
"zA": {"d": "Toggle the fold under the cursor recursively", "cat": "Fold"},
"zo": {"d": "Open the fold under the cursor", "cat": "Fold"},
"zO": {"d": "Open all folds under the cursor recursively", "cat": "Fold"},
"zc": {"d": "Close the fold under the cursor", "cat": "Fold"},
"zC": {"d": "Close all folds under the cursor recursively", "cat": "Fold"},
"zR": {"d": "Open all folds (set 'foldlevel' to the deepest)", "cat": "Fold"},
"zM": {"d": "Close all folds (set 'foldlevel' to 0)", "cat": "Fold"},
"zr": {"d": "Open one more fold level everywhere ('foldlevel' + 1)", "cat": "Fold"},
"zm": {"d": "Close one more fold level everywhere ('foldlevel' - 1)", "cat": "Fold"},
"zv": {"d": "Open just enough folds to show the cursor line", "cat": "Fold"},
"zx": {"d": "Reset folds to 'foldlevel', then show the cursor line", "cat": "Fold"},
"zX": {"d": "Reset folds to 'foldlevel'", "cat": "Fold"},
"zj": {"d": "Move down to the start of the next fold", "cat": "Fold"},
"zk": {"d": "Move up to the end of the previous fold", "cat": "Fold"},
"[z": {"d": "Move to the start of the current open fold", "cat": "Fold"},
"]z": {"d": "Move to the end of the current open fold", "cat": "Fold"},
"zf": {"d": "Create a fold over {motion} (manual / marker folding)", "cat": "Fold"},
"zF": {"d": "Create a fold for N lines", "cat": "Fold"},
"zd": {"d": "Delete the fold under the cursor", "cat": "Fold"},
"zD": {"d": "Delete folds under the cursor recursively", "cat": "Fold"},
"zE": {"d": "Delete all folds in the window", "cat": "Fold"},
"zi": {"d": "Toggle folding on/off ('foldenable')", "cat": "Fold"},
"zn": {"d": "Disable folding (open everything)", "cat": "Fold"},
"zN": {"d": "Re-enable folding", "cat": "Fold"},
"z=": {"d": "Spelling suggestions for the word under the cursor", "cat": "Spell", "n": "Needs 'spell' on (<code>:set spell</code>); a count picks suggestion N directly"},
"zg": {"d": "Add the word to the spell file as correct", "cat": "Spell"},
"zw": {"d": "Add the word to the spell file as wrong", "cat": "Spell"},
"zG": {"d": "Mark the word correct for this session only", "cat": "Spell"},
"zW": {"d": "Mark the word wrong for this session only", "cat": "Spell"},
"zug": {"d": "Undo zg (remove the word from the spell file)", "cat": "Spell"},
"zuw": {"d": "Undo zw", "cat": "Spell"},
"zuG": {"d": "Undo zG", "cat": "Spell"},
"zuW": {"d": "Undo zW", "cat": "Spell"},
"]s": {"d": "Move to the next misspelled word", "cat": "Spell"},
"[s": {"d": "Move to the previous misspelled word", "cat": "Spell"},
"do": {"d": "Diff: obtain the change from the other window (:diffget)", "cat": "Diff"},
"dp": {"d": "Diff: put the change into the other window (:diffput)", "cat": "Diff"},
"]c": {"d": "Diff: next change", "cat": "Diff", "n": "Not remapped here: gitsigns is set up without keymaps, so <kbd>]c</kbd>/<kbd>[c</kbd> only move between diff changes"},
"[c": {"d": "Diff: previous change", "cat": "Diff"},
"CTRL-]": {"d": "Jump to the definition (tag) of the word under the cursor", "cat": "Tags", "n": "When an LSP client attaches, Neovim sets 'tagfunc', so <kbd>&lt;C-]&gt;</kbd> goes to the LSP definition and <kbd>&lt;C-t&gt;</kbd> comes back"},
"CTRL-T": {"d": "Jump back up the tag stack", "cat": "Tags"},
"g]": {"d": "List all tags matching the word under the cursor (:tselect)", "cat": "Tags"},
"g_CTRL-]": {"d": "Jump to the tag, or list matches if there are several (:tjump)", "cat": "Tags"},
"v_CTRL-]": {"d": "Jump to the tag of the selected text", "cat": "Tags"},
"<C-LeftMouse>": {"d": "Jump to the tag of the word at the mouse click", "cat": "Tags"},
"<C-RightMouse>": {"d": "Jump back up the tag stack (same as CTRL-T)", "cat": "Tags"},
"gf": {"d": "Edit the file whose name is under the cursor", "cat": "Files"},
"gF": {"d": "Edit the file under the cursor and jump to the line number after it", "cat": "Files"},
"gx": {"d": "Open the file path or URL under the cursor with the system handler", "cat": "Files", "n": "Neovim maps <kbd>gx</kbd> (Normal and Visual) to <code>vim.ui.open()</code>: URLs, paths, LSP document links; in help files, help tags"},
"CTRL-G": {"d": "Show the file name, line count and cursor position", "cat": "Files"},
"g_CTRL-G": {"d": "Show cursor position plus word, character and byte counts", "cat": "Files"},
"ZZ": {"d": "Write if changed and close the window (like :x)", "cat": "Files"},
"ZQ": {"d": "Close the window without writing (like :q!)", "cat": "Files"},
"CTRL-Z": {"d": "Suspend Neovim (resume with fg in the shell)", "cat": "Files"},
"[f": {"d": "Edit the file under the cursor (same as gf)", "cat": "Files"},
"]f": {"d": "Edit the file under the cursor (same as gf)", "cat": "Files"},
"CTRL-^": {"d": "Switch to the alternate (previous) buffer; with N: buffer N", "cat": "Buffer & tab", "n": "The quickest way to toggle between two files"},
"gt": {"d": "Go to the next tab page (with N: tab page N)", "cat": "Buffer & tab"},
"gT": {"d": "Go to the previous tab page", "cat": "Buffer & tab"},
"g<Tab>": {"d": "Go to the last accessed tab page", "cat": "Buffer & tab"},
"CTRL-<Tab>": {"d": "Go to the last accessed tab page", "cat": "Buffer & tab"},
"<C-Tab>": {"d": "Go to the last accessed tab page", "cat": "Buffer & tab"},
"K": {"d": "Look up the keyword under the cursor with 'keywordprg'", "cat": "Help", "n": "This config maps <kbd>K</kbd> to LSP hover"},
"v_K": {"d": "Look up the selected text with 'keywordprg'", "cat": "Help"},
"<Help>": {"d": "Open the help window", "cat": "Help"},
"<F1>": {"d": "Open the help window", "cat": "Help"},
"i_<Help>": {"d": "Leave Insert mode and open the help window", "cat": "Help"},
"CTRL-L": {"d": "Redraw the screen (Neovim default: also clears search highlight)", "cat": "Search", "n": "Neovim default mapping: <code>:nohlsearch | diffupdate | normal! &lt;C-L&gt;</code>"},
"ga": {"d": "Show the character code under the cursor (decimal, hex, octal)", "cat": "Help", "n": "This config's <kbd>gai</kbd>/<kbd>gao</kbd> (LSP calls) make <kbd>ga</kbd> wait for 'timeoutlen'"},
"g8": {"d": "Show the UTF-8 bytes of the character under the cursor", "cat": "Help"},
"g<": {"d": "Show the output of the previous command again", "cat": "Misc"},
"gs": {"d": "Sleep N seconds (default 1)", "cat": "Misc"},
"count": {"d": "Count: repeat or scale the next command (3w, 5dd, 2p)", "cat": "Misc"},
"N<Del>": {"d": "While typing a count: remove its last digit", "cat": "Misc"},
"CTRL-\\_CTRL-N": {"d": "Go to Normal mode (no-op in Normal mode; useful in mappings)", "cat": "Misc"},
"CTRL-\\_CTRL-G": {"d": "Go to Normal mode (no-op in Normal mode)", "cat": "Misc"},
"[": {"d": "Square-bracket command prefix ([( [{ [s [c [d …)", "cat": "Misc"},
"]": {"d": "Square-bracket command prefix (]) ]} ]s ]c ]d …)", "cat": "Misc"},
"g": {"d": "Extended command prefix (gg, gu, gq, gv, gx …)", "cat": "Misc"},
"z": {"d": "Fold / scroll / spell command prefix (za, zz, z= …)", "cat": "Misc"},
":": {"d": "Start an Ex command (command-line mode)", "cat": "Command line"},
"N:": {"d": "Start an Ex command with the range .,.+(N-1)", "cat": "Command line", "n": "<kbd>5:</kbd> pre-fills <code>:.,.+4</code>"},
"q:": {"d": "Open the command-line window with : history (edit and re-run)", "cat": "Command line", "n": "In this config <kbd>&lt;CR&gt;</kbd> in Normal mode starts Leap here; press <kbd>i</kbd> then <kbd>&lt;CR&gt;</kbd> to run the line"},
"q/": {"d": "Open the command-line window with / search history", "cat": "Command line"},
"q?": {"d": "Open the command-line window with ? search history", "cat": "Command line"},
"gQ": {"d": "Enter Ex mode (keep entering : commands; :vi to return)", "cat": "Command line"},
"<LeftMouse>": {"d": "Move the cursor to the mouse click", "cat": "Motion"},
"v_iw": {"d": "Inner word", "cat": "Text object", "n": "Text objects work after an operator (<kbd>diw</kbd>, <kbd>ci\"</kbd>, <kbd>yap</kbd>) or in Visual mode; <kbd>i</kbd> = inner, <kbd>a</kbd> = around"},
"v_aw": {"d": "A word, plus surrounding white space", "cat": "Text object", "n": "<kbd>daw</kbd> deletes the word and one space, so the sentence stays tidy"},
"v_iW": {"d": "Inner WORD", "cat": "Text object"},
"v_aW": {"d": "A WORD, plus surrounding white space", "cat": "Text object"},
"v_is": {"d": "Inner sentence", "cat": "Text object"},
"v_as": {"d": "A sentence, plus white space", "cat": "Text object"},
"v_ip": {"d": "Inner paragraph", "cat": "Text object"},
"v_ap": {"d": "A paragraph, plus the following blank lines", "cat": "Text object"},
"v_iquote": {"d": "Inside double quotes", "cat": "Text object"},
"v_aquote": {"d": "Double-quoted string including the quotes", "cat": "Text object"},
"v_i'": {"d": "Inside single quotes", "cat": "Text object"},
"v_a'": {"d": "Single-quoted string including the quotes", "cat": "Text object"},
"v_i`": {"d": "Inside backticks", "cat": "Text object"},
"v_a`": {"d": "Backtick string including the backticks", "cat": "Text object"},
"v_ib": {"d": "Inside ( ) parentheses", "cat": "Text object"},
"v_ab": {"d": "( ) block including the parentheses", "cat": "Text object"},
"v_i(": {"d": "Inside ( ) parentheses (same as ib)", "cat": "Text object"},
"v_i)": {"d": "Inside ( ) parentheses (same as ib)", "cat": "Text object"},
"v_a(": {"d": "( ) block including the parentheses (same as ab)", "cat": "Text object"},
"v_a)": {"d": "( ) block including the parentheses (same as ab)", "cat": "Text object"},
"v_iB": {"d": "Inside { } braces", "cat": "Text object"},
"v_aB": {"d": "{ } block including the braces", "cat": "Text object"},
"v_i{": {"d": "Inside { } braces (same as iB)", "cat": "Text object"},
"v_i}": {"d": "Inside { } braces (same as iB)", "cat": "Text object"},
"v_a{": {"d": "{ } block including the braces (same as aB)", "cat": "Text object"},
"v_a}": {"d": "{ } block including the braces (same as aB)", "cat": "Text object"},
"v_i[": {"d": "Inside [ ] brackets", "cat": "Text object"},
"v_i]": {"d": "Inside [ ] brackets", "cat": "Text object"},
"v_a[": {"d": "[ ] block including the brackets", "cat": "Text object"},
"v_a]": {"d": "[ ] block including the brackets", "cat": "Text object"},
"v_i<": {"d": "Inside < > angle brackets", "cat": "Text object"},
"v_i>": {"d": "Inside < > angle brackets", "cat": "Text object"},
"v_a<": {"d": "< > block including the angle brackets", "cat": "Text object"},
"v_a>": {"d": "< > block including the angle brackets", "cat": "Text object"},
"v_it": {"d": "Inside an XML/HTML tag pair", "cat": "Text object"},
"v_at": {"d": "XML/HTML tag pair including the tags", "cat": "Text object"},
"i_<Esc>": {"d": "Leave Insert mode", "cat": "Insert"},
"i_CTRL-[": {"d": "Leave Insert mode (same as <Esc>)", "cat": "Insert"},
"i_CTRL-C": {"d": "Leave Insert mode without abbreviations or InsertLeave", "cat": "Insert", "n": "Skips InsertLeave autocmds, which plugins may rely on; prefer <kbd>&lt;Esc&gt;</kbd>"},
"i_CTRL-R": {"d": "Insert the contents of register {reg}", "cat": "Insert", "n": "<kbd>&lt;C-r&gt;+</kbd> clipboard, <kbd>&lt;C-r&gt;\"</kbd> unnamed, <kbd>&lt;C-r&gt;=</kbd> expression (e.g. <code>=5*7</code>), <kbd>&lt;C-r&gt;/</kbd> last search"},
"i_CTRL-R_CTRL-R": {"d": "Insert register literally (keys like <BS> in it are not applied)", "cat": "Insert"},
"i_CTRL-R_CTRL-O": {"d": "Insert register literally, without auto-indent", "cat": "Insert"},
"i_CTRL-R_CTRL-P": {"d": "Insert register literally and fix the indent", "cat": "Insert"},
"i_CTRL-W": {"d": "Delete the word before the cursor", "cat": "Insert", "n": "Neovim default: sets an undo point first, so <kbd>u</kbd> can bring the text back"},
"i_CTRL-U": {"d": "Delete text typed before the cursor (if none, all text before it)", "cat": "Insert", "n": "Neovim default: sets an undo point first, so <kbd>u</kbd> can bring the text back"},
"i_CTRL-H": {"d": "Delete the character before the cursor (same as <BS>)", "cat": "Insert"},
"i_<BS>": {"d": "Delete the character before the cursor", "cat": "Insert"},
"i_<Del>": {"d": "Delete the character under the cursor", "cat": "Insert"},
"i_CTRL-O": {"d": "Run one Normal-mode command, then return to Insert", "cat": "Insert", "n": "Handy for one-off moves: <kbd>&lt;C-o&gt;zz</kbd>, <kbd>&lt;C-o&gt;$</kbd>, <kbd>&lt;C-o&gt;p</kbd>"},
"i_CTRL-T": {"d": "Indent the current line one 'shiftwidth'", "cat": "Insert"},
"i_CTRL-D": {"d": "Dedent the current line one 'shiftwidth'", "cat": "Insert"},
"i_0_CTRL-D": {"d": "Delete all indent of the current line", "cat": "Insert"},
"i_CTRL-A": {"d": "Insert the text from the last Insert session", "cat": "Insert"},
"i_CTRL-@": {"d": "Insert the text from the last Insert session and leave Insert", "cat": "Insert"},
"i_CTRL-E": {"d": "Insert the character below the cursor", "cat": "Insert"},
"i_CTRL-Y": {"d": "Insert the character above the cursor", "cat": "Insert"},
"i_CTRL-V": {"d": "Insert the next key literally (e.g. a real <Tab>)", "cat": "Insert"},
"i_CTRL-Q": {"d": "Insert the next key literally (same as CTRL-V)", "cat": "Insert"},
"i_CTRL-V_digit": {"d": "Insert a character by code: 065, x41, u20ac, o101", "cat": "Insert"},
"i_CTRL-K": {"d": "Insert a digraph (e.g. <C-k>e: → ë, <C-k>Eu → €)", "cat": "Insert"},
"i_CTRL-G_u": {"d": "Start a new undoable change (undo break)", "cat": "Insert"},
"i_CTRL-G_U": {"d": "Don't start a new undo step for the next cursor movement", "cat": "Insert"},
"i_CTRL-G_j": {"d": "Down a line, to the column where Insert started", "cat": "Insert"},
"i_CTRL-G_k": {"d": "Up a line, to the column where Insert started", "cat": "Insert"},
"i_CTRL-]": {"d": "Expand an abbreviation without typing a character", "cat": "Insert"},
"i_<Insert>": {"d": "Toggle Insert / Replace mode", "cat": "Insert"},
"i_CTRL-\\_CTRL-N": {"d": "Go to Normal mode", "cat": "Insert"},
"i_CTRL-\\_CTRL-G": {"d": "Go to Normal mode", "cat": "Insert"},
"i_<Tab>": {"d": "Insert a tab (or spaces with 'expandtab')", "cat": "Insert", "n": "In buffers where blink.cmp is attached, <kbd>&lt;Tab&gt;</kbd> tries in order: next snippet placeholder, Sidekick next-edit suggestion, accept Copilot ghost text, else a normal Tab (<code>lua/plugins.lua:331-340</code>)"},
"i_CTRL-I": {"d": "Insert a tab (same as <Tab>)", "cat": "Insert"},
"i_<CR>": {"d": "Start a new line", "cat": "Insert"},
"i_CTRL-M": {"d": "Start a new line (same as <CR>)", "cat": "Insert"},
"i_CTRL-J": {"d": "Start a new line (same as <CR>)", "cat": "Insert"},
"i_<NL>": {"d": "Start a new line (same as <CR>)", "cat": "Insert"},
"i_CTRL-N": {"d": "Complete keyword: next match (sources from 'complete')", "cat": "Completion & AI", "n": "With blink.cmp's menu closed, <kbd>&lt;C-n&gt;</kbd>/<kbd>&lt;C-p&gt;</kbd> open blink's menu instead (first / last item selected). <kbd>&lt;C-x&gt;&lt;C-n&gt;</kbd> still runs built-in keyword completion"},
"i_CTRL-P": {"d": "Complete keyword: previous match", "cat": "Completion & AI"},
"i_CTRL-X": {"d": "Enter CTRL-X completion mode (next key picks the source)", "cat": "Completion & AI"},
"i_CTRL-X_CTRL-F": {"d": "Complete file names", "cat": "Completion & AI"},
"i_CTRL-X_CTRL-L": {"d": "Complete whole lines", "cat": "Completion & AI"},
"i_CTRL-X_CTRL-O": {"d": "Omni completion ('omnifunc'; LSP when a client is attached)", "cat": "Completion & AI", "n": "Neovim sets 'omnifunc' to <code>vim.lsp.omnifunc</code> when an LSP attaches"},
"i_CTRL-X_CTRL-N": {"d": "Complete keywords from the current buffer (forward)", "cat": "Completion & AI"},
"i_CTRL-X_CTRL-P": {"d": "Complete keywords from the current buffer (backward)", "cat": "Completion & AI"},
"i_CTRL-X_CTRL-I": {"d": "Complete keywords from current and included files", "cat": "Completion & AI"},
"i_CTRL-X_CTRL-D": {"d": "Complete defined identifiers (#define)", "cat": "Completion & AI"},
"i_CTRL-X_CTRL-K": {"d": "Complete words from 'dictionary'", "cat": "Completion & AI"},
"i_CTRL-X_CTRL-T": {"d": "Complete words from 'thesaurus'", "cat": "Completion & AI"},
"i_CTRL-X_CTRL-]": {"d": "Complete tags", "cat": "Completion & AI"},
"i_CTRL-X_CTRL-U": {"d": "Complete with 'completefunc'", "cat": "Completion & AI"},
"i_CTRL-X_CTRL-V": {"d": "Complete Vim command-line text", "cat": "Completion & AI"},
"i_CTRL-X_CTRL-R": {"d": "Complete from register contents", "cat": "Completion & AI"},
"i_CTRL-X_CTRL-S": {"d": "Spelling suggestions", "cat": "Completion & AI"},
"i_CTRL-X_s": {"d": "Spelling suggestions", "cat": "Completion & AI"},
"i_CTRL-X_CTRL-Z": {"d": "Stop completion, keep the typed text", "cat": "Completion & AI"},
"complete_CTRL-Y": {"d": "Accept the selected completion", "cat": "Completion & AI"},
"complete_CTRL-E": {"d": "Cancel completion, restore the text", "cat": "Completion & AI"},
"c_CTRL-R": {"d": "Insert a register; <C-r><C-w> word, <C-r><C-a> WORD, <C-r><C-l> line", "cat": "Command line", "n": "<kbd>:%s/&lt;C-r&gt;&lt;C-w&gt;/</kbd> pre-fills a substitute for the word under the cursor"},
"c_CTRL-R_CTRL-O": {"d": "Insert a register or cursor object literally", "cat": "Command line"},
"c_<Tab>": {"d": "Complete the command or argument before the cursor", "cat": "Command line", "n": "In this config blink.cmp handles command-line completion: <kbd>&lt;Tab&gt;</kbd> opens its menu and inserts the first match (accepts a lone match), then cycles; <kbd>&lt;C-n&gt;</kbd>/<kbd>&lt;C-p&gt;</kbd> move, <kbd>&lt;C-y&gt;</kbd> accepts"},
"c_CTRL-I": {"d": "Complete before the cursor (same as <Tab>)", "cat": "Command line"},
"c_<S-Tab>": {"d": "Previous completion match", "cat": "Command line"},
"c_wildchar": {"d": "Complete before the cursor ('wildchar', <Tab>)", "cat": "Command line"},
"c_CTRL-N": {"d": "Next completion match, else next (newer) history entry", "cat": "Command line"},
"c_CTRL-P": {"d": "Previous completion match, else older history entry", "cat": "Command line"},
"c_<Up>": {"d": "Older history entry starting with the typed text", "cat": "Command line"},
"c_<Down>": {"d": "Newer history entry starting with the typed text", "cat": "Command line"},
"c_<S-Up>": {"d": "Older history entry", "cat": "Command line"},
"c_<S-Down>": {"d": "Newer history entry", "cat": "Command line"},
"c_CTRL-U": {"d": "Delete everything before the cursor", "cat": "Command line"},
"c_CTRL-W": {"d": "Delete the word before the cursor", "cat": "Command line"},
"c_CTRL-B": {"d": "Cursor to start of the command line", "cat": "Command line"},
"c_CTRL-E": {"d": "Cursor to end of the command line", "cat": "Command line"},
"c_CTRL-D": {"d": "List completions matching the text before the cursor", "cat": "Command line"},
"c_CTRL-A": {"d": "Insert all completion matches", "cat": "Command line"},
"c_CTRL-L": {"d": "Insert the longest common part of the matches", "cat": "Command line"},
"c_CTRL-G": {"d": "While typing a search: go to the next match ('incsearch')", "cat": "Command line"},
"c_CTRL-T": {"d": "While typing a search: go to the previous match ('incsearch')", "cat": "Command line"},
"c_CTRL-V": {"d": "Insert the next key literally (or a character code)", "cat": "Command line"},
"c_CTRL-K": {"d": "Insert a digraph", "cat": "Command line"},
"c_CTRL-\\_e": {"d": "Replace the command line with the result of {expr}", "cat": "Command line"},
"c_<Esc>": {"d": "Abandon the command line", "cat": "Command line"},
"c_CTRL-C": {"d": "Abandon the command line", "cat": "Command line"},
"c_<CR>": {"d": "Execute the command", "cat": "Command line"},
"c_CTRL-]": {"d": "Expand an abbreviation", "cat": "Command line"},
":buffer": {"cat": "Buffer & tab", "d": "Go to buffer N, or by (partial) name with Tab completion"},
":bNext": {"cat": "Buffer & tab"},
":ball": {"cat": "Buffer & tab"},
":badd": {"cat": "Buffer & tab"},
":balt": {"cat": "Buffer & tab"},
":bdelete": {"cat": "Buffer & tab", "d": "Unload a buffer and remove it from the list (closes its windows)", "n": "This config's <kbd>&lt;leader&gt;bd</kbd> uses Snacks.bufdelete, which keeps the window layout"},
":bfirst": {"cat": "Buffer & tab", "d": "Go to the first buffer"},
":blast": {"cat": "Buffer & tab", "d": "Go to the last buffer"},
":bmodified": {"cat": "Buffer & tab"},
":bnext": {"cat": "Buffer & tab", "d": "Go to the next buffer"},
":bprevious": {"cat": "Buffer & tab", "d": "Go to the previous buffer"},
":brewind": {"cat": "Buffer & tab"},
":bufdo": {"cat": "Buffer & tab", "d": "Run a command in every listed buffer"},
":buffers": {"cat": "Buffer & tab", "d": "List buffers (same as :ls)"},
":bunload": {"cat": "Buffer & tab"},
":bwipeout": {"cat": "Buffer & tab", "d": "Wipe a buffer completely (marks, options, everything)"},
":files": {"cat": "Buffer & tab", "d": "List buffers (same as :ls)"},
":ls": {"cat": "Buffer & tab", "d": "List buffers (% current, # alternate, + modified)"},
":sbuffer": {"cat": "Buffer & tab"},
":sbNext": {"cat": "Buffer & tab"},
":sball": {"cat": "Buffer & tab"},
":sbfirst": {"cat": "Buffer & tab"},
":sblast": {"cat": "Buffer & tab"},
":sbmodified": {"cat": "Buffer & tab"},
":sbnext": {"cat": "Buffer & tab"},
":sbprevious": {"cat": "Buffer & tab"},
":sbrewind": {"cat": "Buffer & tab"},
":unhide": {"cat": "Buffer & tab"},
":sunhide": {"cat": "Buffer & tab"},
":marks": {"cat": "Mark & jump", "d": "List marks"},
":jumps": {"cat": "Mark & jump", "d": "Show the jump list"},
":changes": {"cat": "Mark & jump", "d": "Show the change list"},
":k": {"cat": "Mark & jump"},
":mark": {"cat": "Mark & jump"},
":delmarks": {"cat": "Mark & jump", "d": "Delete marks (:delm a b, :delm! for all lowercase)"},
":clearjumps": {"cat": "Mark & jump", "d": "Clear the jump list"},
":keepjumps": {"cat": "Mark & jump", "d": "Run a command without changing the jump list"},
":keepmarks": {"cat": "Mark & jump"},
":lockmarks": {"cat": "Mark & jump"},
":registers": {"cat": "Register & macro", "d": "Show register contents (:reg a b for specific ones)", "n": "Register <code>d</code> holds deletes in this config"},
":display": {"cat": "Register & macro", "d": "Show register contents (same as :registers)"},
":@": {"cat": "Register & macro"},
":@@": {"cat": "Register & macro"},
":global": {"cat": "Edit", "d": "Run an Ex command on every line matching {pattern}: :g/pat/cmd", "n": "<code>:g/TODO/d</code> deletes matching lines; <code>:g/^/m0</code> reverses the file"},
":vglobal": {"cat": "Edit", "d": "Run an Ex command on every line NOT matching {pattern}: :v/pat/cmd"},
":normal": {"cat": "Edit", "d": "Run Normal-mode keys, on each line of [range]: :%norm A;", "n": "Use <code>:normal!</code> to ignore mappings (this config remaps d, c, x, j, k, s …)"},
":read": {"cat": "Files", "d": "Insert {file} (or :r !cmd output) below the cursor"},
":terminal": {"cat": "Terminal", "d": "Open a terminal buffer"},
":source": {"cat": "Misc", "d": "Run a Vim script or Lua file (:so % runs the current file)"},
":runtime": {"cat": "Misc"},
":packadd": {"cat": "Misc"},
":packloadall": {"cat": "Misc"},
":scriptnames": {"cat": "Misc"},
":scriptencoding": {"cat": "Misc"},
":finish": {"cat": "Misc"},
":debug": {"cat": "Misc"},
":debuggreedy": {"cat": "Misc"},
":breakadd": {"cat": "Misc"},
":breakdel": {"cat": "Misc"},
":breaklist": {"cat": "Misc"},
":profile": {"cat": "Misc"},
":profdel": {"cat": "Misc"},
":write": {"d": "Write the buffer to its file (or to {file})"},
":quit": {"d": "Close the window; exits Neovim when it is the last one"},
":wq": {"d": "Write and close the window"},
":xit": {"d": "Write only if changed, then close the window"},
":edit": {"d": "Edit {file}; with no argument, reload the current file"},
":enew": {"d": "Edit a new unnamed buffer"},
":substitute": {"d": "Find & replace: :[range]s/{pattern}/{string}/[flags]", "n": "Flags: <code>g</code> all on line, <code>c</code> confirm, <code>i</code>/<code>I</code> case, <code>n</code> count only. <code>&amp;</code> in {string} = whole match, <code>\\1</code> = group"},
":sort": {"d": "Sort lines in [range] (n numeric, i ignore case, u unique, r /pat/)"},
":uniq": {"d": "Remove adjacent duplicate lines in [range]"},
":earlier": {"d": "Go back in undo time: :earlier 10m, :earlier 3f (file writes)", "n": "'undofile' is on in this config, so this reaches back across sessions"},
":later": {"d": "Go forward in undo time (counterpart of :earlier)"},
":undolist": {"d": "List the leaves of the undo tree"},
":make": {"d": "Run 'makeprg' and load errors into the quickfix list"},
":cdo": {"d": "Run a command on each quickfix entry: :cdo s/a/b/ | update"},
":cfdo": {"d": "Run a command once per file in the quickfix list"},
":ldo": {"d": "Run a command on each location-list entry"},
":lfdo": {"d": "Run a command once per file in the location list"},
":windo": {"d": "Run a command in every window"},
":argdo": {"d": "Run a command on every file in the argument list"},
":split": {"d": "Split the window horizontally (optionally editing {file})"},
":vsplit": {"d": "Split the window vertically (optionally editing {file})"},
":new": {"d": "Open a new window with an empty buffer"},
":vnew": {"d": "Open a new vertical window with an empty buffer"},
":only": {"d": "Close all other windows"},
":close": {"d": "Close the current window"},
":tabnew": {"d": "Open a new tab page (optionally editing {file})"},
":tabedit": {"d": "Edit {file} in a new tab page"},
":tabclose": {"d": "Close the current tab page"},
":tabonly": {"d": "Close all other tab pages"},
":tabnext": {"d": "Go to the next tab page"},
":tabprevious": {"d": "Go to the previous tab page"},
":tabmove": {"d": "Move the tab page to position N (or +N / -N)"},
":nohlsearch": {"d": "Clear search highlighting until the next search"},
":help": {"d": "Open help for {subject} (:h i_CTRL-R, :h :s, :h 'wrap')"},
":copen": {"d": "Open the quickfix window"},
":cclose": {"d": "Close the quickfix window"},
":cwindow": {"d": "Open the quickfix window only if there are entries"},
":cnext": {"d": "Go to the next quickfix entry"},
":cprevious": {"d": "Go to the previous quickfix entry"},
":colder": {"d": "Go to the older quickfix list"},
":cnewer": {"d": "Go to the newer quickfix list"},
":vimgrep": {"d": "Search files into the quickfix list: :vim /pat/ **/*.lua"},
":grep": {"d": "Run 'grepprg' and load matches into the quickfix list"},
":saveas": {"d": "Save to {file} and make it the current file"},
":update": {"d": "Write only if the buffer was modified"},
":wall": {"d": "Write all modified buffers"},
":qall": {"d": "Quit Neovim (:qa! discards all changes)"},
":wqall": {"d": "Write all modified buffers and quit"},
":xall": {"d": "Write all modified buffers and quit"},
":move": {"d": "Move [range] lines below line {address}: :m+1, :m0"},
":copy": {"d": "Copy [range] lines below line {address}"},
":t": {"d": "Copy lines (same as :copy): :t. duplicates a line"},
":delete": {"d": "Delete [range] lines [into register]"},
":yank": {"d": "Yank [range] lines [into register]"},
":put": {"d": "Put a register linewise below the line (above with :put!)"},
":cd": {"d": "Change the global working directory"},
":lcd": {"d": "Change the working directory for this window"},
":tcd": {"d": "Change the working directory for this tab page"},
":pwd": {"d": "Show the working directory"},
":!": {"d": "Run a shell command; with a range, filter the lines through it"},
":lua": {"d": "Run Lua code: :lua print(vim.bo.filetype)"},
":=": {"d": "Print the last line number; := {expr} evaluates Lua (like :lua =)"},
":set": {"d": "Show or set options (:set wrap?, :set nowrap, :set sw=4)"},
":setlocal": {"d": "Set an option for this buffer/window only"},
":map": {"d": "Show or create mappings (:map with no args lists them)"},
":verbose": {"d": "Run a command verbosely; :verbose map x shows where x was set"},
":messages": {"d": "Show the message history"},
":checkhealth": {"d": "Run health checks (:checkhealth vim.lsp)"},
":diffthis": {"d": "Add this window to the diff"},
":diffoff": {"d": "Leave diff mode"},
":diffupdate": {"d": "Recompute the diff"},
":diffget": {"d": "Get the change from the other diff buffer"},
":diffput": {"d": "Put the change into the other diff buffer"},
":retab": {"d": "Convert tabs/spaces to match 'expandtab' / 'tabstop'"},
":&": {"d": "Repeat the last :substitute (:&& keeps the flags)"},
":restart": {"d": "Restart Neovim, restoring the session (:restart! does not)"},
":lsp": {"d": "Manage LSP: :lsp enable/disable/restart/stop [name]"},
":startinsert": {"d": "Start Insert mode"},
":stopinsert": {"d": "Stop Insert mode"},
":center": {"d": "Center lines in [range]"},
":right": {"d": "Right-align lines"},
":left": {"d": "Left-align lines"},
":join": {"d": "Join [range] lines"},
":oldfiles": {"d": "List recently edited files"},
":mksession": {"d": "Save the session (windows, buffers) to a file"},
":noautocmd": {"d": "Run a command without triggering autocommands"},
":silent": {"d": "Run a command without showing messages"},
":filter": {"d": "Filter the output of a listing command: :filter /pat/ ls"},
":redir": {"d": "Redirect messages to a file, register or variable"},
":wincmd": {"d": "Run a CTRL-W command: :wincmd l"},
":vertical": {"d": "Make the following split vertical: :vert help x"},
":tab": {"d": "Open the following command's window in a new tab: :tab help x"},
"n|q{0-9a-zA-Z\"}": {"d": "Record keystrokes into register {a-z} (A-Z appends)", "cat": "Register & macro", "n": "Press <kbd>q</kbd> again to stop; then <kbd>@a</kbd> plays it, <kbd>@@</kbd> / <kbd>Q</kbd> repeat"},
"n|q": {"d": "Stop recording (while recording a macro)", "cat": "Register & macro"},
"n|~": {"d": "Toggle case of N characters and move right", "cat": "Edit"},
"n|~{motion}": {"d": "Toggle case of {motion} text (only when 'tildeop' is set)", "cat": "Operator"},
"c|<C-F>": {"d": "Open the command-line window to edit the command", "cat": "Command line", "n": "Edit the command with Normal-mode keys. In this config <kbd>&lt;CR&gt;</kbd> in Normal mode starts Leap, so press <kbd>i</kbd> then <kbd>&lt;CR&gt;</kbd> to run the line"},
"i|<C-L>": {"d": "Completion menu: insert one more character from the current match", "cat": "Completion & AI"},
"i|other": {"d": "Completion menu: any other key stops completion and inserts itself", "cat": "Completion & AI"},
"n|g<MiddleMouse>": {"d": "Paste at the mouse click (same as <C-MiddleMouse>)", "cat": "Edit"}
},
"entries": [
{"k": "<C-\\><C-N>", "m": ["t"], "d": "Leave Terminal mode for Normal mode (scroll, search, yank output)", "s": "builtin", "cat": "Terminal", "h": "CTRL-\\_CTRL-N", "e": 1, "n": "Every key except <kbd>&lt;C-\\&gt;</kbd> goes to the job. Snacks terminals also accept a quick double <kbd>&lt;Esc&gt;</kbd>"},
{"k": "<C-\\><C-O>", "m": ["t"], "d": "Run one Normal-mode command, then return to Terminal mode", "s": "builtin", "cat": "Terminal", "h": "t_CTRL-\\_CTRL-O"},
{"k": "<C-\\>{char}", "m": ["t"], "d": "Send {char} to the job (the <C-\\> itself is not sent)", "s": "builtin", "cat": "Terminal", "h": "terminal-input", "n": "Only <kbd>&lt;C-n&gt;</kbd> and <kbd>&lt;C-o&gt;</kbd> after <kbd>&lt;C-\\&gt;</kbd> are handled by Neovim; <kbd>&lt;C-\\&gt;&lt;C-\\&gt;</kbd> sends one <kbd>&lt;C-\\&gt;</kbd>"},
{"k": "i", "m": ["n"], "d": "Enter Terminal mode (keys go to the shell / job)", "s": "builtin", "cat": "Terminal", "ctx": "terminal buffers", "h": "terminal-input", "e": 1, "n": "<kbd>a</kbd>, <kbd>I</kbd>, <kbd>A</kbd> and <code>:startinsert</code> do the same. Snacks terminals re-enter Terminal mode automatically when you switch back to them"},
{"k": "a", "m": ["n"], "d": "Enter Terminal mode (same as i)", "s": "builtin", "cat": "Terminal", "ctx": "terminal buffers", "h": "terminal-input"},
{"k": "[[", "m": ["n", "x", "o"], "d": "Jump to the previous shell prompt", "s": "neovim", "cat": "Terminal", "ctx": "terminal buffers", "h": "terminal-config", "n": "Neovim 0.12 buffer-local default; needs a shell that emits OSC 133 prompt marks. In Normal mode it wins over this config's global <kbd>[[</kbd>/<kbd>]]</kbd> (Snacks words)"},
{"k": "]]", "m": ["n", "x", "o"], "d": "Jump to the next shell prompt", "s": "neovim", "cat": "Terminal", "ctx": "terminal buffers", "h": "terminal-config"},
{"k": "<Esc><Esc>", "m": ["t"], "d": "Leave Terminal mode (two quick presses, within 200 ms)", "s": "snacks", "cat": "Terminal", "ctx": "Snacks terminal", "e": 1, "n": "A single <kbd>&lt;Esc&gt;</kbd> is still sent to the program (e.g. to leave vi-mode in the shell)"},
{"k": "<C-/>", "m": ["t"], "d": "Hide the terminal window (job keeps running)", "s": "snacks", "cat": "Terminal", "ctx": "Snacks terminal", "n": "Set in lua/plugins.lua (Snacks terminal win keys). From Normal mode the global <kbd>&lt;C-/&gt;</kbd> toggles it back; <kbd>2&lt;C-/&gt;</kbd> opens a second terminal"},
{"k": "q", "m": ["n"], "d": "Hide the terminal window", "s": "snacks", "cat": "Terminal", "ctx": "Snacks terminal"},
{"k": "gf", "m": ["n"], "d": "Hide the terminal and edit the file name under the cursor", "s": "snacks", "cat": "Terminal", "ctx": "Snacks terminal"},
{"k": "{char}", "m": ["s"], "d": "Typing replaces the selection and starts Insert mode", "s": "builtin", "cat": "Visual", "h": "Select-mode", "e": 1, "n": "Select mode is where snippet placeholders land. <b>Caveat:</b> this config maps d/D/c/C/x/X with <code>{\"n\",\"v\"}</code>, which includes Select mode, so typing those letters over a placeholder deletes it instead of replacing it"},
{"k": "<C-G>", "m": ["s"], "d": "Switch from Select to Visual mode", "s": "builtin", "cat": "Visual", "h": "v_CTRL-G"},
{"k": "<C-O>", "m": ["s"], "d": "Switch to Visual mode for one command", "s": "builtin", "cat": "Visual", "h": "v_CTRL-O"},
{"k": "<C-R>{register}", "m": ["s"], "d": "Pick the register that receives the replaced text", "s": "builtin", "cat": "Visual", "h": "v_CTRL-R"},
{"k": "<BS>", "m": ["s"], "d": "Delete the selection", "s": "builtin", "cat": "Visual", "h": "v_<BS>"},
{"k": "<Esc>", "m": ["s"], "d": "Stop Select mode", "s": "builtin", "cat": "Visual", "h": "Select-mode"},
{"k": "<C-R><C-W>", "m": ["c"], "d": "Insert the word under the cursor", "s": "builtin", "cat": "Command line", "h": "c_CTRL-R_CTRL-W", "e": 1},
{"k": "<C-R><C-A>", "m": ["c"], "d": "Insert the WORD under the cursor", "s": "builtin", "cat": "Command line", "h": "c_CTRL-R_CTRL-A"},
{"k": "<C-R><C-L>", "m": ["c"], "d": "Insert the line under the cursor", "s": "builtin", "cat": "Command line", "h": "c_CTRL-R_CTRL-L"},
{"k": "<C-R><C-F>", "m": ["c"], "d": "Insert the file name under the cursor", "s": "builtin", "cat": "Command line", "h": "c_CTRL-R_CTRL-F"},
{"k": "ZR", "m": ["n"], "d": "Restart Neovim and restore the session (:restart)", "s": "builtin", "cat": "Session", "h": "ZR", "n": "With a count 1-8 the session is not restored; 9 also skips the unsaved-changes check"}
],
"map_desc": [
{"s": "neovim", "m": "n", "k": "Y", "d": "Yank to end of line (y$)", "cat": "Edit", "e": 1, "force": true},
{"s": "neovim", "m": "n", "k": "&", "d": "Repeat last :s on this line, keeping its flags (:&&)", "cat": "Undo & repeat", "force": true},
{"s": "neovim", "m": "n", "k": "<C-L>", "d": "Clear search highlight, update diffs and redraw", "cat": "Search", "e": 1, "force": true},
{"s": "neovim", "m": "x", "k": "*", "d": "Search forward for the selected text", "cat": "Search", "e": 1, "force": true},
{"s": "neovim", "m": "x", "k": "#", "d": "Search backward for the selected text", "cat": "Search", "force": true},
{"s": "neovim", "m": "x", "k": "@", "d": "Linewise Visual: run macro {reg} on every selected line", "cat": "Register & macro", "n": "Only in linewise Visual (<kbd>V</kbd>); otherwise plain <kbd>@</kbd>", "force": true},
{"s": "neovim", "m": "x", "k": "Q", "d": "Linewise Visual: replay the last recorded macro on every line", "cat": "Register & macro", "force": true},
{"s": "neovim", "m": "i", "k": "<C-U>", "d": "Delete text before the cursor on this line (undo point first)", "cat": "Insert", "force": true},
{"s": "neovim", "m": "i", "k": "<C-W>", "d": "Delete the word before the cursor (undo point first)", "cat": "Insert", "force": true},
{"s": "neovim", "m": "n", "k": "[<Space>", "d": "Add N empty lines above the cursor (stay in Normal)", "cat": "Edit", "force": true},
{"s": "neovim", "m": "n", "k": "]<Space>", "d": "Add N empty lines below the cursor (stay in Normal)", "cat": "Edit", "force": true},
{"s": "neovim", "m": "n", "k": "[q", "d": "Previous quickfix entry (:cprevious)", "cat": "Quickfix & lists", "e": 1, "force": true},
{"s": "neovim", "m": "n", "k": "]q", "d": "Next quickfix entry (:cnext)", "cat": "Quickfix & lists", "e": 1, "force": true},
{"s": "neovim", "m": "n", "k": "[Q", "d": "First quickfix entry, or entry N (:crewind)", "cat": "Quickfix & lists", "force": true},
{"s": "neovim", "m": "n", "k": "]Q", "d": "Last quickfix entry, or entry N (:clast)", "cat": "Quickfix & lists", "force": true},
{"s": "neovim", "m": "n", "k": "[<C-Q>", "d": "Last entry in the previous file of the quickfix list (:cpfile)", "cat": "Quickfix & lists", "force": true},
{"s": "neovim", "m": "n", "k": "]<C-Q>", "d": "First entry in the next file of the quickfix list (:cnfile)", "cat": "Quickfix & lists", "force": true},
{"s": "neovim", "m": "n", "k": "[l", "d": "Previous location-list entry (:lprevious)", "cat": "Quickfix & lists", "force": true},
{"s": "neovim", "m": "n", "k": "]l", "d": "Next location-list entry (:lnext)", "cat": "Quickfix & lists", "force": true},
{"s": "neovim", "m": "n", "k": "[L", "d": "First location-list entry, or entry N (:lrewind)", "cat": "Quickfix & lists", "force": true},
{"s": "neovim", "m": "n", "k": "]L", "d": "Last location-list entry, or entry N (:llast)", "cat": "Quickfix & lists", "force": true},
{"s": "neovim", "m": "n", "k": "[<C-L>", "d": "Last entry in the previous file of the location list (:lpfile)", "cat": "Quickfix & lists", "force": true},
{"s": "neovim", "m": "n", "k": "]<C-L>", "d": "First entry in the next file of the location list (:lnfile)", "cat": "Quickfix & lists", "force": true},
{"s": "neovim", "m": "n", "k": "[a", "d": "Previous file in the argument list (:previous)", "cat": "Files", "force": true},
{"s": "neovim", "m": "n", "k": "]a", "d": "Next file in the argument list (:next)", "cat": "Files", "force": true},
{"s": "neovim", "m": "n", "k": "[A", "d": "First argument-list file, or file N (:rewind)", "cat": "Files", "force": true},
{"s": "neovim", "m": "n", "k": "]A", "d": "Last argument-list file, or file N (:last)", "cat": "Files", "force": true},
{"s": "neovim", "m": "n", "k": "[t", "d": "Previous matching tag (:tprevious)", "cat": "Tags", "force": true},
{"s": "neovim", "m": "n", "k": "]t", "d": "Next matching tag (:tnext)", "cat": "Tags", "force": true},
{"s": "neovim", "m": "n", "k": "[T", "d": "First matching tag, or tag N (:trewind)", "cat": "Tags", "force": true},
{"s": "neovim", "m": "n", "k": "]T", "d": "Last matching tag, or tag N (:tlast)", "cat": "Tags", "force": true},
{"s": "neovim", "m": "n", "k": "[<C-T>", "d": "Previous matching tag in the preview window (:ptprevious)", "cat": "Tags", "force": true},
{"s": "neovim", "m": "n", "k": "]<C-T>", "d": "Next matching tag in the preview window (:ptnext)", "cat": "Tags", "force": true},
{"s": "neovim", "m": "n", "k": "[b", "d": "Previous buffer (:bprevious)", "cat": "Buffer & tab", "e": 1, "force": true},
{"s": "neovim", "m": "n", "k": "]b", "d": "Next buffer (:bnext)", "cat": "Buffer & tab", "e": 1, "force": true},
{"s": "neovim", "m": "n", "k": "[B", "d": "First buffer, or buffer N (:brewind)", "cat": "Buffer & tab", "force": true},
{"s": "neovim", "m": "n", "k": "]B", "d": "Last buffer, or buffer N (:blast)", "cat": "Buffer & tab", "force": true},
{"s": "neovim", "m": "n", "k": "[d", "d": "Previous diagnostic in this buffer", "cat": "LSP & diagnostics", "e": 1},
{"s": "neovim", "m": "n", "k": "]d", "d": "Next diagnostic in this buffer", "cat": "LSP & diagnostics", "e": 1},
{"s": "neovim", "m": "n", "k": "[D", "d": "First diagnostic in this buffer", "cat": "LSP & diagnostics"},
{"s": "neovim", "m": "n", "k": "]D", "d": "Last diagnostic in this buffer", "cat": "LSP & diagnostics"},
{"s": "neovim", "m": "n", "k": "<C-W>d", "d": "Show diagnostics under the cursor in a float", "cat": "LSP & diagnostics", "e": 1},
{"s": "neovim", "m": "n", "k": "<C-W><C-D>", "d": "Show diagnostics under the cursor in a float", "cat": "LSP & diagnostics"},
{"s": "neovim", "m": "n", "k": "grn", "d": "LSP: rename the symbol under the cursor", "cat": "LSP & diagnostics", "force": true},
{"s": "neovim", "m": "n", "k": "gra", "d": "LSP: code actions", "cat": "LSP & diagnostics", "force": true},
{"s": "neovim", "m": "x", "k": "gra", "d": "LSP: code actions for the selection", "cat": "LSP & diagnostics", "force": true},
{"s": "neovim", "m": "n", "k": "gri", "d": "LSP: go to implementation", "cat": "LSP & diagnostics", "force": true},
{"s": "neovim", "m": "n", "k": "grt", "d": "LSP: go to type definition", "cat": "LSP & diagnostics", "force": true},
{"s": "neovim", "m": "n", "k": "grx", "d": "LSP: run the code lens on this line", "cat": "LSP & diagnostics", "force": true},
{"s": "neovim", "m": "n", "k": "gO", "d": "Document outline: LSP symbols (or help / man / markdown headings)", "cat": "LSP & diagnostics", "force": true},
{"s": "neovim", "m": "i", "k": "<C-S>", "d": "LSP: show signature help", "cat": "LSP & diagnostics", "n": "blink.cmp's own signature help (<kbd>&lt;C-k&gt;</kbd>) is also enabled here", "force": true},
{"s": "neovim", "m": "s", "k": "<C-S>", "d": "LSP: show signature help", "cat": "LSP & diagnostics", "force": true},
{"s": "neovim", "m": "i", "k": "<Tab>", "d": "Jump to the next snippet placeholder, else insert <Tab>", "cat": "Completion & AI", "force": true},
{"s": "neovim", "m": "s", "k": "<Tab>", "d": "Jump to the next snippet placeholder, else <Tab>", "cat": "Completion & AI", "force": true},
{"s": "neovim", "m": "i", "k": "<S-Tab>", "d": "Jump to the previous snippet placeholder", "cat": "Completion & AI", "force": true},
{"s": "neovim", "m": "s", "k": "<S-Tab>", "d": "Jump to the previous snippet placeholder", "cat": "Completion & AI", "force": true},
{"s": "matchit", "m": "n", "k": "%", "d": "Jump to the matching bracket, if/else/endif or HTML tag", "cat": "Motion", "e": 1, "force": true},
{"s": "matchit", "m": "x", "k": "%", "d": "Extend the selection to the matching pair", "cat": "Motion", "force": true},
{"s": "matchit", "m": "o", "k": "%", "d": "Up to the matching pair (d%, y%)", "cat": "Motion", "force": true},
{"s": "matchit", "m": "n", "k": "g%", "d": "Jump backwards through the matching group", "cat": "Motion", "force": true},
{"s": "matchit", "m": "x", "k": "g%", "d": "Extend the selection backwards through the matching group", "cat": "Motion", "force": true},
{"s": "matchit", "m": "o", "k": "g%", "d": "Backwards through the matching group", "cat": "Motion", "force": true},
{"s": "matchit", "m": "n", "k": "[%", "d": "To the previous unmatched group start (like [{ for if/endif)", "cat": "Motion", "force": true},
{"s": "matchit", "m": "n", "k": "]%", "d": "To the next unmatched group end (like ]} for if/endif)", "cat": "Motion", "force": true},
{"s": "matchit", "m": "x", "k": "[%", "d": "Extend to the previous unmatched group start", "cat": "Motion", "force": true},
{"s": "matchit", "m": "x", "k": "]%", "d": "Extend to the next unmatched group end", "cat": "Motion", "force": true},
{"s": "matchit", "m": "o", "k": "[%", "d": "To the previous unmatched group start", "cat": "Motion", "force": true},
{"s": "matchit", "m": "o", "k": "]%", "d": "To the next unmatched group end", "cat": "Motion", "force": true},
{"s": "ftplugin", "m": "n", "k": "gO", "d": "Outline of the Markdown headings", "cat": "Notes", "force": true}
],
"notes": [
{"title": "The grammar: operator + count + motion", "kind": "tip", "lead": "Most editing is a sentence: a verb (operator) applied to a noun (motion or text object).", "rows": [["<kbd>d</kbd><kbd>w</kbd>", "delete to the next word"], ["<kbd>c</kbd><kbd>i</kbd><kbd>\"</kbd>", "change inside the quotes"], ["<kbd>y</kbd><kbd>a</kbd><kbd>p</kbd>", "yank a paragraph"], ["<kbd>g</kbd><kbd>U</kbd><kbd>i</kbd><kbd>w</kbd>", "uppercase the word"], ["<kbd>&gt;</kbd><kbd>i</kbd><kbd>B</kbd>", "indent the inside of a { } block"], ["<kbd>d</kbd><kbd>t</kbd><kbd>)</kbd>", "delete up to the next )"], ["<kbd>d</kbd><kbd>d</kbd> · <kbd>g</kbd><kbd>c</kbd><kbd>c</kbd>", "doubling the operator acts on the whole line"]], "note": "Learn one new operator and it works with every motion you already know.", "keys": ["d", "c", "y", "gU", ">", "gc"]},
{"title": "Counts and the dot", "kind": "tip", "lead": "A number in front repeats or scales; <kbd>.</kbd> repeats the last change.", "rows": [["<kbd>3</kbd><kbd>w</kbd> · <kbd>d</kbd><kbd>3</kbd><kbd>w</kbd> · <kbd>3</kbd><kbd>d</kbd><kbd>w</kbd>", "all the same: the count can go before the operator or the motion"], ["<kbd>5</kbd><kbd>j</kbd>", "5 real lines down (relative numbers are on in this config)"], ["<kbd>4</kbd><kbd>G</kbd> · <kbd>50</kbd><kbd>%</kbd>", "go to line 4 · go halfway through the file"], ["<kbd>.</kbd> · <kbd>3</kbd><kbd>.</kbd>", "repeat the last change · repeat it with count 3"], ["<kbd>*</kbd><kbd>c</kbd><kbd>g</kbd><kbd>n</kbd>…<kbd>.</kbd><kbd>.</kbd>", "change the word under the cursor, then each next match"], ["<kbd>q</kbd><kbd>a</kbd> … <kbd>q</kbd> · <kbd>10</kbd><kbd>@</kbd><kbd>a</kbd>", "record a macro, replay it 10 times (<kbd>Q</kbd> replays the last one)"]], "keys": [".", "@", "Q", "gn"]},
{"title": "Registers in this config", "kind": "tip", "lead": "Put <kbd>\"</kbd>{reg} before a yank, delete or put to choose where text goes.", "rows": [["<kbd>y</kbd> · <kbd>p</kbd>", "'clipboard' is unnamedplus: yank and put use the system clipboard"], ["<kbd>d</kbd> <kbd>c</kbd> <kbd>x</kbd> <kbd>D</kbd> <kbd>C</kbd> <kbd>X</kbd>", "mapped to <code>\"d</code>…: deleted text lands in register <code>d</code>, the clipboard stays clean"], ["<kbd>\"</kbd><kbd>d</kbd><kbd>p</kbd>", "paste what you just deleted"], ["<kbd>\"</kbd><kbd>0</kbd><kbd>p</kbd>", "paste the last yank"], ["<kbd>\"</kbd><kbd>_</kbd><kbd>d</kbd>…", "black hole register: in this config it is overridden by the <code>\"d</code> mapping, use <code>:normal! \"_d…</code>"], ["<kbd>&lt;C-r&gt;</kbd>{reg}", "insert a register in Insert or Command-line mode"], ["<kbd>:reg</kbd>", "show what every register holds"]], "note": "Because d/c/x are mappings that prepend <code>\"d</code>, any register you type before them is replaced by <code>d</code> (checked: <code>\"adiw</code> fills <code>\"d</code>, not <code>\"a</code>).", "keys": ["\"", "p", "d"]}
]
}
+156
View File
@@ -0,0 +1,156 @@
{
"groups": {
"<leader>b": {"name": "Buffer", "cat": "Buffer & tab"},
"<leader>c": {"name": "Code", "cat": "LSP & diagnostics"},
"<leader>cb": {"name": "Comment box", "cat": "Comment"},
"<leader>f": {"name": "Find", "cat": "Find & pick"},
"<leader>g": {"name": "Git", "cat": "Git"},
"<leader>h": {"name": "Haunt bookmarks", "cat": "Mark & jump"},
"<leader>q": {"name": "Session", "cat": "Session"},
"<leader>s": {"name": "Search", "cat": "Find & pick"},
"<leader>u": {"name": "UI / toggles", "cat": "UI & toggles"}
},
"map_desc": [
{"s": "config", "m": "*", "k": "<leader><Space>", "cat": "Find & pick", "sl": "smart find", "e": 1, "n": "Snacks smart picker: open buffers, recent files and project files ranked together (frecency)"},
{"s": "config", "m": "*", "k": "<leader>,", "cat": "Buffer & tab", "sl": "buffers", "e": 1},
{"s": "config", "m": "*", "k": "<leader>/", "cat": "Find & pick", "sl": "grep", "e": 1, "n": "Live grep (ripgrep) from the current working directory, which auto-cd keeps at the project root"},
{"s": "config", "m": "*", "k": "<leader>:", "cat": "Command line", "sl": "cmd hist"},
{"s": "config", "m": "*", "k": "<leader>n", "cat": "UI & toggles", "sl": "notifs", "n": "Snacks notifier history window (<code>lua/keymaps.lua:291</code>)"},
{"s": "config", "m": "*", "k": "<leader>e", "cat": "Files", "sl": "explorer", "e": 1, "n": "Snacks file explorer (sidebar)"},
{"s": "config", "m": "*", "k": "<leader>N", "cat": "Help", "sl": "news", "n": "Shows Neovim's <code>news.txt</code> in a floating window"},
{"s": "config", "m": "*", "k": "<leader>.", "cat": "Misc", "sl": "scratch", "n": "Toggle a persistent scratch buffer (Snacks)"},
{"s": "config", "m": "*", "k": "<leader>S", "cat": "Misc", "sl": "scratches", "n": "Pick one of the saved scratch buffers"},
{"s": "config", "m": "*", "k": "<leader>z", "cat": "UI & toggles", "sl": "zen", "n": "Snacks zen mode: distraction-free centered window"},
{"s": "config", "m": "*", "k": "<leader>Z", "cat": "Window", "sl": "zoom", "n": "Snacks zoom: maximize the current window, again to restore"},
{"s": "config", "m": "*", "k": "<leader>fb", "cat": "Buffer & tab", "sl": "buffers"},
{"s": "config", "m": "*", "k": "<leader>fc", "cat": "Files", "sl": "config", "n": "Files under <code>stdpath('config')</code> (~/.config/nvim)"},
{"s": "config", "m": "*", "k": "<leader>ff", "cat": "Find & pick", "sl": "files", "e": 1},
{"s": "config", "m": "*", "k": "<leader>fg", "cat": "Find & pick", "sl": "git files", "n": "Only files tracked by git"},
{"s": "config", "m": "*", "k": "<leader>fp", "cat": "Find & pick", "sl": "projects"},
{"s": "config", "m": "*", "k": "<leader>fr", "cat": "Find & pick", "sl": "recent", "e": 1},
{"s": "config", "m": "*", "k": "<leader>gb", "cat": "Git", "sl": "branches"},
{"s": "config", "m": "*", "k": "<leader>gl", "cat": "Git", "sl": "log"},
{"s": "config", "m": "*", "k": "<leader>gL", "cat": "Git", "sl": "line log", "n": "Git log of the current line"},
{"s": "config", "m": "*", "k": "<leader>gs", "cat": "Git", "sl": "status", "e": 1},
{"s": "config", "m": "*", "k": "<leader>gS", "cat": "Git", "sl": "stash"},
{"s": "config", "m": "*", "k": "<leader>gd", "cat": "Git", "sl": "hunks", "n": "Picker of changed hunks (<code>git diff</code>)"},
{"s": "config", "m": "*", "k": "<leader>gf", "cat": "Git", "sl": "file log", "n": "Git log of the current file"},
{"s": "config", "m": "*", "k": "<leader>gB", "cat": "Git", "sl": "browse", "n": "Open the file on the remote's web UI; from Visual mode the selected lines are linked"},
{"s": "config", "m": "*", "k": "<leader>gg", "cat": "Git", "sl": "lazygit", "e": 1, "n": "Lazygit in a Snacks floating terminal"},
{"s": "config", "m": "*", "k": "<leader>gi", "cat": "Git", "sl": "issues", "n": "Snacks GitHub picker; needs the <code>gh</code> CLI, logged in"},
{"s": "config", "m": "*", "k": "<leader>gI", "cat": "Git", "sl": "all issues", "n": "Snacks GitHub picker; needs the <code>gh</code> CLI, logged in"},
{"s": "config", "m": "*", "k": "<leader>gp", "cat": "Git", "sl": "PRs", "n": "Snacks GitHub picker; needs the <code>gh</code> CLI, logged in"},
{"s": "config", "m": "*", "k": "<leader>gP", "cat": "Git", "sl": "all PRs", "n": "Snacks GitHub picker; needs the <code>gh</code> CLI, logged in"},
{"s": "config", "m": "*", "k": "<leader>gt", "cat": "Git", "sl": "tea PRs", "n": "snacks-tea (Gitea/Forgejo); needs the <code>tea</code> CLI logged in, uses the <code>origin</code> remote"},
{"s": "config", "m": "*", "k": "<leader>gT", "cat": "Git", "sl": "tea all PRs", "n": "snacks-tea (Gitea/Forgejo); needs the <code>tea</code> CLI logged in, uses the <code>origin</code> remote"},
{"s": "config", "m": "*", "k": "<leader>gc", "cat": "Git", "sl": "tea new PR", "n": "snacks-tea (Gitea/Forgejo); needs the <code>tea</code> CLI logged in, uses the <code>origin</code> remote"},
{"s": "config", "m": "*", "k": "<leader>sb", "cat": "Search", "sl": "lines", "n": "Fuzzy search the lines of the current buffer"},
{"s": "config", "m": "*", "k": "<leader>sB", "cat": "Search", "sl": "grep bufs"},
{"s": "config", "m": "*", "k": "<leader>sg", "cat": "Find & pick", "sl": "grep", "n": "Same as <kbd>&lt;leader&gt;/</kbd>"},
{"s": "config", "m": "*", "k": "<leader>sw", "cat": "Search", "sl": "grep word", "n": "Normal: word under the cursor. Visual: the selection"},
{"s": "config", "m": "*", "k": "<leader>s\"", "cat": "Register & macro", "sl": "registers"},
{"s": "config", "m": "*", "k": "<leader>s/", "cat": "Search", "sl": "search hist"},
{"s": "config", "m": "*", "k": "<leader>sa", "cat": "Misc", "sl": "autocmds"},
{"s": "config", "m": "*", "k": "<leader>sc", "cat": "Command line", "sl": "cmd hist"},
{"s": "config", "m": "*", "k": "<leader>sC", "cat": "Command line", "sl": "commands"},
{"s": "config", "m": "*", "k": "<leader>sd", "cat": "LSP & diagnostics", "sl": "diagnostics", "e": 1},
{"s": "config", "m": "*", "k": "<leader>sD", "cat": "LSP & diagnostics", "sl": "buf diags"},
{"s": "config", "m": "*", "k": "<leader>sh", "cat": "Help", "sl": "help", "e": 1},
{"s": "config", "m": "*", "k": "<leader>sH", "cat": "UI & toggles", "sl": "highlights"},
{"s": "config", "m": "*", "k": "<leader>si", "cat": "Misc", "sl": "icons"},
{"s": "config", "m": "*", "k": "<leader>sj", "cat": "Mark & jump", "sl": "jumps", "n": "Jumplist picker: a way to go forward in the jumplist now that <kbd>&lt;Tab&gt;</kbd>/<kbd>&lt;C-I&gt;</kbd> is Sidekick NES"},
{"s": "config", "m": "*", "k": "<leader>sk", "cat": "Help", "sl": "keymaps", "e": 1},
{"s": "config", "m": "*", "k": "<leader>sl", "cat": "Quickfix & lists", "sl": "loclist"},
{"s": "config", "m": "*", "k": "<leader>sm", "cat": "Mark & jump", "sl": "marks"},
{"s": "config", "m": "*", "k": "<leader>sM", "cat": "Help", "sl": "man pages"},
{"s": "config", "m": "*", "k": "<leader>sp", "cat": "Find & pick", "sl": "plugin spec", "n": "Greps <code>lua/plugins.lua</code> for every <code>vim.pack</code> spec (<code>src = \"https://…</code>); type to filter by plugin name"},
{"s": "config", "m": "*", "k": "<leader>sq", "cat": "Quickfix & lists", "sl": "quickfix", "n": "Snacks picker over the quickfix list"},
{"s": "config", "m": "*", "k": "<leader>sR", "cat": "Find & pick", "sl": "resume", "n": "Reopen the last picker with its query"},
{"s": "config", "m": "*", "k": "<leader>su", "cat": "Undo & repeat", "sl": "undo hist", "n": "Snacks undo-tree picker with diff preview"},
{"s": "config", "m": "*", "k": "<leader>ss", "cat": "LSP & diagnostics", "sl": "symbols"},
{"s": "config", "m": "*", "k": "<leader>sS", "cat": "LSP & diagnostics", "sl": "ws symbols"},
{"s": "config", "m": "*", "k": "<leader>sr", "cat": "Search", "sl": "replace", "e": 1, "n": "Grug-far project-wide search &amp; replace, prefilled with the word under the cursor; <kbd>q</kbd> closes it"},
{"s": "config", "m": "*", "k": "<leader>uC", "cat": "UI & toggles", "sl": "colors"},
{"s": "config", "m": "*", "k": "<leader>un", "cat": "UI & toggles", "sl": "dismiss"},
{"s": "config", "m": "*", "k": "<leader>uu", "cat": "Undo & repeat", "sl": "undotree", "e": 1, "n": "Toggle the undotree side panel (persistent undo is on)"},
{"s": "config", "m": "*", "k": "<leader>ca", "cat": "LSP & diagnostics", "sl": "code action", "e": 1, "n": "Neovim's <kbd>gra</kbd> does the same"},
{"s": "config", "m": "*", "k": "<leader>cr", "cat": "LSP & diagnostics", "sl": "rename", "e": 1, "n": "Puts <code>:IncRename &lt;cword&gt;</code> on the command line with a live preview: edit the name, then <kbd>&lt;CR&gt;</kbd>. Neovim's <kbd>grn</kbd> renames without the preview"},
{"s": "config", "m": "*", "k": "<leader>cR", "cat": "Files", "sl": "rename file", "n": "Rename the current file on disk; tells LSP servers (willRenameFiles) so imports can follow"},
{"s": "config", "m": "*", "k": "<leader>cf", "cat": "Edit", "sl": "format", "e": 1, "n": "conform.nvim with LSP fallback; in Visual mode only the selection is formatted"},
{"s": "config", "m": "*", "k": "<leader>cbb", "cat": "Comment", "sl": "box", "n": "Wrap the line(s) in a centered comment box (comment-box.nvim)"},
{"s": "config", "m": "*", "k": "<leader>cbl", "cat": "Comment", "sl": "line", "n": "Insert a centered comment line"},
{"s": "config", "m": "*", "k": "<leader>cbd", "cat": "Comment", "sl": "del box", "n": "Remove a comment box or titled line around the text"},
{"s": "config", "m": "*", "k": "<leader>cbk", "cat": "Comment", "sl": "catalog", "n": "Show all box and line styles"},
{"s": "config", "m": "*", "k": "<leader>bd", "cat": "Buffer & tab", "sl": "del buffer", "e": 1, "n": "Snacks.bufdelete(): delete the buffer but keep the window layout"},
{"s": "config", "m": "*", "k": "<leader>qs", "cat": "Session", "sl": "restore", "n": "persistence.nvim: one session per directory and git branch, saved automatically on exit"},
{"s": "config", "m": "*", "k": "<leader>qS", "cat": "Session", "sl": "select", "n": "persistence.nvim: one session per directory and git branch, saved automatically on exit"},
{"s": "config", "m": "*", "k": "<leader>ql", "cat": "Session", "sl": "last"},
{"s": "config", "m": "*", "k": "<leader>qd", "cat": "Session", "sl": "no save", "n": "Stop persistence from saving the session when you quit"},
{"s": "config", "m": "*", "k": "<leader>ha", "cat": "Mark & jump", "sl": "annotate", "n": "Bookmark the current line with an annotation shown as virtual text (prompts for the text)"},
{"s": "config", "m": "*", "k": "<leader>ht", "cat": "Mark & jump", "sl": "show note", "n": "Show/hide the annotation of the bookmark on this line"},
{"s": "config", "m": "*", "k": "<leader>hd", "cat": "Mark & jump", "sl": "del mark"},
{"s": "config", "m": "*", "k": "<leader>hn", "cat": "Mark & jump", "sl": "next mark"},
{"s": "config", "m": "*", "k": "<leader>hp", "cat": "Mark & jump", "sl": "prev mark"},
{"s": "config", "m": "*", "k": "<leader>hl", "cat": "Mark & jump", "sl": "bookmarks", "n": "Snacks picker of all Haunt bookmarks"},
{"s": "config", "m": "*", "k": "<Tab>", "cat": "Completion & AI", "sl": "NES", "e": 1, "n": "Jumps to, then applies, the Sidekick next-edit suggestion. With no suggestion it is a plain jump forward (count works). <kbd>&lt;C-i&gt;</kbd> is mapped separately, so terminals that can tell them apart (kitty, Neovide) keep it as jump forward"},
{"s": "config", "m": "*", "k": "d", "cat": "Operator", "d": "Delete {motion} into register d (clipboard untouched)", "force": false, "sl": "del→\"d", "e": 1, "n": "Remapped to <code>\"d{key}</code> (<code>lua/keymaps.lua:23-28</code>) so the system clipboard keeps your last yank. Paste deleted text with <kbd>\"dp</kbd>. A register you type first wins (<kbd>\"add</kbd>, <kbd>\"_dd</kbd>), except <kbd>\"+</kbd>, which looks like the default. Normal and Visual mode only"},
{"s": "config", "m": "*", "k": "D", "cat": "Edit", "d": "Delete to end of line into register d", "force": false, "sl": "D→\"d", "n": "Remapped to <code>\"d{key}</code> (<code>lua/keymaps.lua:23-28</code>) so the system clipboard keeps your last yank. Paste deleted text with <kbd>\"dp</kbd>. A register you type first wins (<kbd>\"add</kbd>, <kbd>\"_dd</kbd>), except <kbd>\"+</kbd>, which looks like the default. Normal and Visual mode only"},
{"s": "config", "m": "*", "k": "c", "cat": "Operator", "d": "Change {motion}; the old text goes to register d", "force": false, "sl": "chg→\"d", "e": 1, "n": "Remapped to <code>\"d{key}</code> (<code>lua/keymaps.lua:23-28</code>) so the system clipboard keeps your last yank. Paste deleted text with <kbd>\"dp</kbd>. A register you type first wins (<kbd>\"add</kbd>, <kbd>\"_dd</kbd>), except <kbd>\"+</kbd>, which looks like the default. Normal and Visual mode only"},
{"s": "config", "m": "*", "k": "C", "cat": "Edit", "d": "Change to end of line; the old text goes to register d", "force": false, "sl": "C→\"d", "n": "Remapped to <code>\"d{key}</code> (<code>lua/keymaps.lua:23-28</code>) so the system clipboard keeps your last yank. Paste deleted text with <kbd>\"dp</kbd>. A register you type first wins (<kbd>\"add</kbd>, <kbd>\"_dd</kbd>), except <kbd>\"+</kbd>, which looks like the default. Normal and Visual mode only"},
{"s": "config", "m": "*", "k": "x", "cat": "Edit", "d": "Delete character(s) under the cursor into register d", "force": false, "sl": "x→\"d", "e": 1, "n": "Remapped to <code>\"d{key}</code> (<code>lua/keymaps.lua:23-28</code>) so the system clipboard keeps your last yank. Paste deleted text with <kbd>\"dp</kbd>. A register you type first wins (<kbd>\"add</kbd>, <kbd>\"_dd</kbd>), except <kbd>\"+</kbd>, which looks like the default. Normal and Visual mode only"},
{"s": "config", "m": "*", "k": "X", "cat": "Edit", "d": "Delete character(s) before the cursor into register d", "force": false, "sl": "X→\"d", "n": "Remapped to <code>\"d{key}</code> (<code>lua/keymaps.lua:23-28</code>) so the system clipboard keeps your last yank. Paste deleted text with <kbd>\"dp</kbd>. A register you type first wins (<kbd>\"add</kbd>, <kbd>\"_dd</kbd>), except <kbd>\"+</kbd>, which looks like the default. Normal and Visual mode only"},
{"s": "config", "m": "*", "k": "K", "cat": "LSP & diagnostics", "sl": "hover", "e": 1, "n": "Always LSP hover, in every buffer: no fallback to <code>'keywordprg'</code> (<code>:Man</code>, <code>:help</code>) when no LSP is attached"},
{"s": "config", "m": "*", "k": "gd", "cat": "LSP & diagnostics", "sl": "definition", "e": 1, "n": "Snacks LSP picker (jumps directly when there is a single result). Needs an attached LSP server; replaces Vim's search-based <kbd>gd</kbd>"},
{"s": "config", "m": "*", "k": "gD", "cat": "LSP & diagnostics", "sl": "declaration", "n": "Snacks LSP picker (jumps directly when there is a single result). Needs an attached LSP server; replaces Vim's search-based <kbd>gD</kbd>"},
{"s": "config", "m": "*", "k": "gI", "cat": "LSP & diagnostics", "sl": "impl", "n": "Snacks LSP picker (jumps directly when there is a single result). Needs an attached LSP server; replaces Vim's <kbd>gI</kbd> (insert at column 1, use <kbd>0i</kbd>)"},
{"s": "config", "m": "*", "k": "gy", "cat": "LSP & diagnostics", "sl": "type def", "n": "Snacks LSP picker (jumps directly when there is a single result). Needs an attached LSP server"},
{"s": "config", "m": "*", "k": "gai", "cat": "LSP & diagnostics", "sl": "calls in", "n": "Incoming calls picker. Makes Vim's <kbd>ga</kbd> wait <code>'timeoutlen'</code>"},
{"s": "config", "m": "*", "k": "gao", "cat": "LSP & diagnostics", "sl": "calls out", "n": "Outgoing calls picker. Makes Vim's <kbd>ga</kbd> wait <code>'timeoutlen'</code>"},
{"s": "config", "m": "*", "k": "j", "cat": "Motion", "sl": "down", "e": 1, "n": "Without a count moves by display (wrapped) line like <kbd>gj</kbd>/<kbd>gk</kbd>; with a count (<kbd>5j</kbd>, even <kbd>1j</kbd>) moves by real lines. Not mapped in Operator-pending mode, so <kbd>dj</kbd> stays linewise"},
{"s": "config", "m": "*", "k": "k", "cat": "Motion", "sl": "up", "e": 1, "n": "Without a count moves by display (wrapped) line like <kbd>gj</kbd>/<kbd>gk</kbd>; with a count (<kbd>5j</kbd>, even <kbd>1j</kbd>) moves by real lines. Not mapped in Operator-pending mode, so <kbd>dj</kbd> stays linewise"},
{"s": "config", "m": "*", "k": "<Down>", "cat": "Motion", "sl": "down", "n": "Without a count moves by display (wrapped) line like <kbd>gj</kbd>/<kbd>gk</kbd>; with a count (<kbd>5j</kbd>, even <kbd>1j</kbd>) moves by real lines. Not mapped in Operator-pending mode, so <kbd>dj</kbd> stays linewise"},
{"s": "config", "m": "*", "k": "<Up>", "cat": "Motion", "sl": "up", "n": "Without a count moves by display (wrapped) line like <kbd>gj</kbd>/<kbd>gk</kbd>; with a count (<kbd>5j</kbd>, even <kbd>1j</kbd>) moves by real lines. Not mapped in Operator-pending mode, so <kbd>dj</kbd> stays linewise"},
{"s": "config", "m": "i", "k": "<Down>", "cat": "Insert", "sl": "down", "n": "Moves by display line in Insert mode (<code>normal! gj</code>/<code>gk</code>); the native popup menu and blink.cmp's menu keep their own arrow keys"},
{"s": "config", "m": "i", "k": "<Up>", "cat": "Insert", "sl": "up", "n": "Moves by display line in Insert mode (<code>normal! gj</code>/<code>gk</code>); the native popup menu and blink.cmp's menu keep their own arrow keys"},
{"s": "config", "m": "*", "k": "<C-/>", "cat": "Terminal", "sl": "terminal", "e": 1, "n": "Toggle a Snacks floating terminal (Normal and Terminal mode). <kbd>&lt;C-_&gt;</kbd> is the same for terminals that send Ctrl+/ as Ctrl+_"},
{"s": "config", "m": "*", "k": "grr", "cat": "LSP & diagnostics", "sl": "references", "e": 1, "n": "Snacks picker for LSP references; replaces Neovim's <kbd>grr</kbd> list. The other <kbd>gr</kbd>* defaults (<kbd>grn</kbd> <kbd>gra</kbd> <kbd>gri</kbd> <kbd>grt</kbd> <kbd>grx</kbd>) work as normal"},
{"s": "config", "m": "*", "k": "<leader>ur", "cat": "Search", "sl": "nohl", "n": "Clears search highlighting; Neovim's <kbd>&lt;C-L&gt;</kbd> does it too"},
{"s": "config", "m": "*", "k": "<C-I>", "cat": "Mark & jump", "sl": "jump fwd", "n": "Mapped to itself so it stays jump forward where the terminal can tell it from <kbd>&lt;Tab&gt;</kbd> (<code>:h CTRL-I</code>)"},
{"s": "config", "m": "*", "k": "gx", "cat": "Files", "sl": "open", "e": 1, "n": "gx.nvim's <code>:Browse</code>: URLs, files, plugin names → GitHub, <code>#123</code> issues, package.json deps, otherwise a web search. Works on a Visual selection too"}
],
"entries": [
{"k": "<C-S-v>", "m": ["n"], "s": "config", "cat": "Register & macro", "ctx": "Neovide only", "sl": "paste", "d": "Paste the system clipboard (an empty line is replaced by the paste)", "n": "On an empty line the clipboard lines replace it and the cursor goes to the end of the paste; otherwise runs <code>\"+]p</code> (put after, indent adjusted). <code>lua/options.lua:203</code>"},
{"k": "<C-S-v>", "m": ["i", "c"], "s": "config", "cat": "Register & macro", "ctx": "Neovide only", "sl": "paste", "d": "Paste the system clipboard (<C-R>+)", "n": "<code>lua/options.lua:222-223</code>"},
{"k": "<C-S-v>", "m": ["x", "s"], "s": "config", "cat": "Register & macro", "ctx": "Neovide only", "sl": "paste", "d": "Replace the selection with the system clipboard", "n": "<code>\"+p</code>, <code>lua/options.lua:224</code>"},
{"k": "<C-S-v>", "m": ["t"], "s": "config", "cat": "Terminal", "ctx": "Neovide only", "sl": "paste", "d": "Paste the system clipboard into the terminal", "n": "<code>&lt;C-\\&gt;&lt;C-n&gt;\"+pi</code>, <code>lua/options.lua:225</code>"},
{"k": "<C-S-c>", "m": ["x", "s"], "s": "config", "cat": "Register & macro", "ctx": "Neovide only", "sl": "copy", "d": "Copy the selection to the system clipboard", "n": "<code>lua/options.lua:231</code>"},
{"k": "<C-S-c>", "m": ["n"], "s": "config", "cat": "Register & macro", "ctx": "Neovide only", "sl": "copy line", "d": "Copy the current line to the system clipboard", "n": "<code>lua/options.lua:233</code>"},
{"k": "<C-S-x>", "m": ["x", "s"], "s": "config", "cat": "Register & macro", "ctx": "Neovide only", "sl": "cut", "d": "Cut the selection to the system clipboard", "n": "Uses <code>\"+d</code> without remapping, so unlike <kbd>d</kbd> it really fills the clipboard. <code>lua/options.lua:239</code>"},
{"k": "<C-S-x>", "m": ["n"], "s": "config", "cat": "Register & macro", "ctx": "Neovide only", "sl": "cut line", "d": "Cut the current line to the system clipboard", "n": "<code>lua/options.lua:241</code>"},
{"k": "<C-_>", "m": ["n", "t"], "s": "config", "cat": "Terminal", "sl": "terminal", "d": "Toggle the Snacks terminal (alias of <C-/>)", "n": "For terminals that encode Ctrl+/ as Ctrl+_ (no CSI u). Hidden from which-key (<code>which_key_ignore</code>), <code>lua/keymaps.lua:312</code>"},
{"k": "q", "m": ["n"], "s": "config", "cat": "Search", "ctx": "Grug-far buffer", "sl": "close", "d": "Close the Grug-far window", "n": "Buffer-local, replaces macro recording there. <code>lua/options.lua:127-133</code>"}
],
"commands": {
"Q": "Write all changed buffers (even read-only ones) and quit, no prompts (:xa!)",
"Format": "Format the buffer, or [range], with conform.nvim (async, LSP fallback)"
},
"notes": [
{"title": "Leader is Space, local leader is backslash", "kind": "change", "lead": "Set before any plugin loads, so every plugin sees them.", "rows": [["<kbd>&lt;Space&gt;</kbd>", "<code>&lt;leader&gt;</code>: 80+ Normal-mode maps and a few Visual ones, grouped as listed in the which-key popup"], ["<kbd>\\</kbd>", "<code>&lt;localleader&gt;</code> (plugin buffer keys such as Grug-far's)"], ["<kbd>&lt;Space&gt;</kbd> alone", "No longer moves right like <kbd>l</kbd>: Neovim waits for the next key (which-key shows the options)"]], "note": "<code>lua/options.lua:15-16</code>", "keys": ["<Space>"]},
{"title": "Yank and put use the system clipboard", "kind": "change", "lead": "<code>clipboard=unnamedplus</code>: every yank, delete and put that would use the unnamed register uses <code>\"+</code> instead.", "rows": [["<kbd>y</kbd> <kbd>yy</kbd> <kbd>Y</kbd>", "Copy to the system clipboard (<code>\"+</code>) and <code>\"0</code>"], ["<kbd>p</kbd> <kbd>P</kbd>", "Paste the system clipboard: your last yank, or whatever another app copied"], ["<kbd>\"0p</kbd>", "Last yank made inside Neovim, even after copying elsewhere"]], "note": "<code>lua/keymaps.lua:13</code>. Deletes are redirected, see the next card.", "keys": ["y", "p", "P"]},
{"title": "Deleting never touches the clipboard: d c x go to register d", "kind": "change", "lead": "Applies in Normal and Visual mode. A register you type first still wins.", "rows": [["<kbd>d</kbd> <kbd>D</kbd> <kbd>c</kbd> <kbd>C</kbd> <kbd>x</kbd> <kbd>X</kbd>", "Run as <code>\"dd</code>, <code>\"dD</code>, … so the deleted text lands in <code>\"d</code> (and <code>\"1</code> for whole lines)"], ["<kbd>\"a</kbd><kbd>d</kbd>… <kbd>\"_</kbd><kbd>d</kbd>…", "An explicit register is honoured (black hole works); only <kbd>\"+</kbd> is treated as the default, so use <kbd>yy</kbd> then <kbd>dd</kbd> to cut to the clipboard"], ["<kbd>\"dp</kbd>", "Paste what you just deleted (plain <kbd>p</kbd> pastes the clipboard)"], ["<kbd>xp</kbd> <kbd>ddp</kbd>", "Classic swap idioms paste the clipboard instead; use <kbd>x\"dp</kbd> / <kbd>dd\"dp</kbd>"], ["<kbd>cc</kbd> <kbd>cw</kbd> <kbd>ciw</kbd>…", "Change commands also go to <code>\"d</code>"], ["Visual <kbd>p</kbd>", "Not remapped: the replaced text overwrites the clipboard. Use Visual <kbd>P</kbd> to keep it"]], "note": "<code>lua/keymaps.lua:17-28</code>", "keys": ["d", "D", "c", "C", "x", "X", "p"]},
{"title": "j k and arrows move by display line", "kind": "change", "lead": "'wrap' is on, so long lines span several screen rows.", "rows": [["<kbd>j</kbd> <kbd>k</kbd> <kbd>&lt;Down&gt;</kbd> <kbd>&lt;Up&gt;</kbd>", "No count: like <kbd>gj</kbd>/<kbd>gk</kbd>, one wrapped screen row at a time"], ["<kbd>5j</kbd> <kbd>12k</kbd>", "With a count: real lines, so relative numbers still line up"], ["<kbd>1j</kbd>", "A real line down even on wrapped text (useful in macros)"], ["<kbd>dj</kbd> <kbd>yk</kbd>", "Operator-pending is not mapped: still linewise"], ["Insert <kbd>&lt;Down&gt;</kbd> <kbd>&lt;Up&gt;</kbd>", "Display-line moves too, unless a completion menu is open"]], "note": "A recorded macro that uses a bare <kbd>j</kbd> moves by screen row on wrapped lines; use <kbd>+</kbd> or <kbd>1j</kbd>. <code>lua/keymaps.lua:36-52</code>", "keys": ["j", "k", "<Down>", "<Up>"]},
{"title": "Enter does not work in quickfix and q: windows", "kind": "warn", "lead": "The global <code>&lt;CR&gt;</code> map wins because those windows have no buffer-local <code>&lt;CR&gt;</code> map.", "rows": [["Quickfix / location list <kbd>&lt;CR&gt;</kbd>", "Starts a Leap instead of opening the entry under the cursor"], ["Command-line window <kbd>q:</kbd> <kbd>q/</kbd> <kbd>&lt;CR&gt;</kbd>", "Starts a Leap instead of running the line"], ["Instead", "<code>:.cc</code> / <code>:.ll</code>, <kbd>&lt;C-W&gt;&lt;CR&gt;</kbd> (opens the entry in a split), or <kbd>i</kbd> then <kbd>&lt;CR&gt;</kbd> in <kbd>q:</kbd>"], ["Fix", "Map <kbd>&lt;CR&gt;</kbd> back buffer-locally on <code>FileType qf</code> and <code>CmdwinEnter</code>, or pick a different Leap key"]], "note": "Verified headless for both windows. <code>lua/keymaps.lua:352</code>", "keys": ["<CR>"]},
{"title": "LSP keys open Snacks pickers", "kind": "change", "rows": [["<kbd>gd</kbd> <kbd>gD</kbd> <kbd>gI</kbd> <kbd>gy</kbd>", "Definition, declaration, implementation, type definition"], ["<kbd>grr</kbd> <kbd>gai</kbd> <kbd>gao</kbd>", "References, incoming calls, outgoing calls"], ["<kbd>&lt;leader&gt;ss</kbd> <kbd>&lt;leader&gt;sS</kbd>", "Document / workspace symbols"], ["<kbd>grn</kbd> <kbd>gra</kbd> <kbd>gri</kbd> <kbd>grt</kbd> <kbd>grx</kbd>", "Neovim's own LSP keys: rename, code action, implementation, type definition, run code lens"], ["<kbd>K</kbd> <kbd>&lt;leader&gt;ca</kbd> <kbd>&lt;leader&gt;cr</kbd>", "Hover, code action, rename (IncRename with live preview)"], ["Lost", "Vim's search-based <kbd>gd</kbd>/<kbd>gD</kbd> (work without LSP), <kbd>gI</kbd> (use <kbd>0i</kbd>), and <kbd>K</kbd>'s <code>'keywordprg'</code> (use <code>:Man</code> / <code>:help</code>)"]], "note": "Global maps, active in every buffer; without an LSP client they find nothing. <code>lua/keymaps.lua:233-276</code>", "keys": ["gd", "gD", "gI", "gy", "grr", "grn", "gra", "gai", "gao", "K"]},
{"title": "Tab is Sidekick's next-edit suggestion", "kind": "change", "lead": "Copilot runs as an LSP server; ghost text comes from <code>vim.lsp.inline_completion</code>.", "rows": [["Normal <kbd>&lt;Tab&gt;</kbd>", "Jump to the next-edit suggestion, press again to apply it; with none, a plain jump forward"], ["Insert <kbd>&lt;Tab&gt;</kbd>", "In order: next snippet placeholder, Sidekick NES jump/apply, accept the Copilot ghost text, else a normal Tab"], ["<kbd>&lt;C-I&gt;</kbd>", "Mapped to itself, so where the terminal tells it apart from <kbd>&lt;Tab&gt;</kbd> (kitty, Neovide) it is always jump forward"]], "note": "<code>lua/keymaps.lua:338-347</code>; Insert chain <code>lua/plugins.lua</code> (blink <code>keymap</code>); see <code>:help CTRL-I</code>", "keys": ["<Tab>", "<C-I>"]},
{"title": ":Q writes everything and quits", "kind": "change", "rows": [["<code>:Q</code>", "Runs <code>:xa!</code>: write all changed buffers, read-only ones too, then quit"], ["Still blocked by", "Unnamed buffers or files that cannot be written"]], "note": "<code>lua/keymaps.lua:58</code>", "keys": [":Q"]},
{"title": "Files save themselves", "kind": "change", "lead": "Only normal file buffers (empty 'buftype').", "rows": [["Leaving Insert mode", "<code>:update</code> (only if modified)"], ["Any Normal-mode change", "<kbd>x</kbd>, <kbd>dd</kbd>, <kbd>p</kbd>, <kbd>u</kbd>, <kbd>.</kbd>… also save at once"], ["<code>'autowrite'</code>", "On: <code>:make</code>, <code>:next</code>, <kbd>&lt;C-]&gt;</kbd>… write first"], ["Undo", "Persistent ('undofile'): <kbd>u</kbd>, <kbd>&lt;leader&gt;uu</kbd> undotree, <kbd>&lt;leader&gt;su</kbd> picker; <code>:e!</code> cannot revert what is already saved"]], "note": "Each save also runs format-on-save, see the next card. <code>lua/options.lua:25</code>, <code>:34</code>, <code>:38-47</code>", "keys": ["u"]},
{"title": "Formatting", "kind": "tip", "rows": [["On save", "conform formats every write (<code>format_on_save</code>, 500 ms); autosave makes that after each change. Turn off with <code>vim.g.disable_autoformat</code> / <code>vim.b.disable_autoformat</code>"], ["<kbd>&lt;leader&gt;cf</kbd>", "Format the buffer; in Visual mode only the selected lines"], ["<code>:Format</code> <code>:'&lt;,'&gt;Format</code>", "Same, async, optional range"], ["Formatters", "stylua (Lua), clang-format (C/C++), rustfmt, ruff_format (Python), fish_indent, shfmt (sh/bash). Install them yourself (PATH or <code>:MasonInstall</code>): mason-lspconfig only installs LSP servers"], ["Other filetypes", "LSP formatting when the server supports it (<code>lsp_format = \"fallback\"</code>)"]], "note": "<code>lua/plugins.lua:249-268</code>; <code>lua/keymaps.lua:363-365</code>; <code>lua/options.lua:69-79</code>", "keys": ["<Space>cf"]},
{"title": "Working directory follows the buffer", "kind": "change", "rows": [["On <code>BufEnter</code>", "<code>:cd</code> to the project root of the file (global, all windows)"], ["Root markers", "Tried in order over all parent dirs: <code>.git</code>, then <code>lua</code>, <code>package.json</code>, <code>go.mod</code>, <code>Cargo.toml</code>, <code>Makefile</code>; else the file's own directory"], ["Affects", "<kbd>&lt;leader&gt;ff</kbd>, <kbd>&lt;leader&gt;/</kbd>, <kbd>&lt;leader&gt;sr</kbd>, <code>:e relative/path</code>, new terminals, <code>:make</code>"], ["Skipped", "Special buffers (help, terminals, pickers), except the Snacks explorer"]], "note": "<code>lua/options.lua:100-124</code>; marker order per <code>vim.fs.root()</code>"},
{"title": "Small automatic behaviours", "kind": "change", "rows": [["Reopen a file", "Cursor returns to where you left it (<kbd>g`\"</kbd>), <code>lua/options.lua:82-91</code>"], ["File changed outside", "Reloaded on focus and when idle (<code>checktime</code> on FocusGained/CursorHold, 'updatetime' 200 ms) if the buffer has no unsaved edits, <code>lua/options.lua:50-63</code>"], ["Line numbers", "Absolute current line + relative others, made for counts like <kbd>5j</kbd>, <code>lua/options.lua:26-27</code>"], ["Indent", "2 spaces, 'expandtab', <code>lua/options.lua:19-21</code>"], ["Terminal title", "<code>NVIM: file</code>, reset to the shell name on exit, <code>lua/options.lua:139-192</code>"]]},
{"title": "]] and [[ jump between references", "kind": "change", "rows": [["<kbd>]]</kbd> <kbd>[[</kbd>", "Next / previous LSP reference of the word under the cursor (Snacks words, counts work)"], ["Markdown buffers", "Buffer-local ftplugin maps win: next / previous heading"], ["Terminal buffers (Normal mode)", "Neovim's buffer-local defaults win: previous / next shell prompt"], ["Section motions", "Still available in Visual and Operator-pending mode (<kbd>v]]</kbd>, <kbd>d]]</kbd>)"]], "note": "<code>lua/keymaps.lua:315-320</code>", "keys": ["]]", "[["]},
{"title": "Terminal and scratch", "kind": "tip", "rows": [["<kbd>&lt;C-/&gt;</kbd>", "Toggle a floating terminal (Normal and Terminal mode; <kbd>&lt;C-_&gt;</kbd> in legacy terminals)"], ["<kbd>&lt;C-\\&gt;&lt;C-N&gt;</kbd>", "Terminal mode to Normal mode (built-in)"], ["<kbd>&lt;leader&gt;gg</kbd>", "Lazygit in a floating terminal"], ["<kbd>&lt;leader&gt;.</kbd> <kbd>&lt;leader&gt;S</kbd>", "Toggle / pick a persistent scratch buffer"]], "note": "<code>lua/keymaps.lua:285-314</code>; <code>lua/plugins.lua:106-120</code>", "keys": ["<C-/>", "<C-_>"]},
{"title": "Picker extras from this config", "kind": "tip", "rows": [["<kbd>s</kbd> (input, Normal)", "Flash labels on the result list: jump to an item in 2 keys"], ["<kbd>&lt;A-s&gt;</kbd>", "The same from Insert mode"], ["<kbd>&lt;A-a&gt;</kbd>", "Send the item(s) to the Sidekick AI CLI"], ["Matching", "Fuzzy, smart-case, frecency and cwd bonus"]], "note": "<code>lua/plugins.lua:46-91</code>", "keys": ["<A-s>", "<A-a>"]},
{"title": "Sessions and bookmarks", "kind": "tip", "rows": [["<kbd>&lt;leader&gt;qs</kbd> <kbd>&lt;leader&gt;ql</kbd> <kbd>&lt;leader&gt;qS</kbd>", "Restore the session for this directory + git branch, the last one, or pick one"], ["<kbd>&lt;leader&gt;qd</kbd>", "Do not save this session on exit (saved automatically otherwise)"], ["<kbd>&lt;leader&gt;ha</kbd>", "Bookmark the line with a note (virtual text), <kbd>&lt;leader&gt;ht</kbd> shows/hides it"], ["<kbd>&lt;leader&gt;hn</kbd> <kbd>&lt;leader&gt;hp</kbd> <kbd>&lt;leader&gt;hl</kbd>", "Next / previous bookmark, bookmark picker"]], "note": "<code>lua/keymaps.lua:382-416</code>; <code>lua/plugins.lua:133-138</code>, <code>:541-546</code>", "keys": ["<Space>qs", "<Space>ha"]},
{"title": "Neovide-only clipboard keys", "kind": "tip", "rows": [["<kbd>&lt;C-S-v&gt;</kbd>", "Paste the clipboard in every mode (Normal: an empty line is replaced)"], ["<kbd>&lt;C-S-c&gt;</kbd>", "Copy the selection, or the current line in Normal mode"], ["<kbd>&lt;C-S-x&gt;</kbd>", "Cut the selection or line to the clipboard (bypasses the <code>\"d</code> remap)"]], "note": "<code>lua/options.lua:198-242</code>; only when <code>vim.g.neovide</code> is set.", "keys": ["<C-S-V>", "<C-S-C>", "<C-S-X>"]}
]
}
+65
View File
@@ -0,0 +1,65 @@
{
"map_desc": [
{"s": "config", "m": "n", "k": "<leader>.", "cat": "Buffer & tab", "sl": "scratch", "n": "Toggle a persistent scratch buffer (Snacks)"},
{"s": "config", "m": "n", "k": "<leader>S", "cat": "Buffer & tab", "sl": "scratches", "n": "Pick one of the saved scratch buffers"},
{"s": "config", "m": "n", "k": "<leader>sa", "cat": "Help", "sl": "autocmds", "n": "Snacks picker of every autocommand; <kbd>&lt;CR&gt;</kbd> jumps to where it was defined"},
{"s": "config", "m": "n", "k": "<leader>si", "cat": "Insert", "sl": "icons", "n": "Snacks icon picker; <kbd>&lt;CR&gt;</kbd> puts the icon at the cursor (<code>confirm = \"put\"</code>)"},
{"s": "snacks", "m": "x", "k": "ii", "d": "Inner scope: the indented block around the cursor, without its header/footer", "cat": "Text object", "n": "Snacks scope (loaded on UIEnter, so the headless key dump misses it). Tested: inside an <code>if</code> body, <kbd>yii</kbd> yanks the body lines", "sl": "in scope", "force": true},
{"s": "snacks", "m": "o", "k": "ii", "d": "Inner scope: the indented block around the cursor, without its header/footer", "cat": "Text object", "n": "Snacks scope (loaded on UIEnter, so the headless key dump misses it). Tested: inside an <code>if</code> body, <kbd>yii</kbd> yanks the body lines", "sl": "in scope", "force": true},
{"s": "snacks", "m": "x", "k": "ai", "d": "Full scope: the indented block plus its header and closing lines", "cat": "Text object", "n": "Tested: inside an <code>if</code> body, <kbd>yai</kbd> yanks <code>if … end</code>; from the function body it takes the whole function", "sl": "a scope", "force": true},
{"s": "snacks", "m": "o", "k": "ai", "d": "Full scope: the indented block plus its header and closing lines", "cat": "Text object", "n": "Tested: inside an <code>if</code> body, <kbd>yai</kbd> yanks <code>if … end</code>; from the function body it takes the whole function", "sl": "a scope", "force": true},
{"s": "snacks", "m": "n", "k": "[i", "d": "Jump to the start of the current scope; repeat for the enclosing one", "cat": "Motion", "n": "Snacks scope, UI sessions only. Replaces Vim's <kbd>[i</kbd> (show the first line containing the keyword)", "sl": "scope↑", "force": true},
{"s": "snacks", "m": "x", "k": "[i", "d": "Jump to the start of the current scope; repeat for the enclosing one", "cat": "Motion", "n": "Snacks scope, UI sessions only. Replaces Vim's <kbd>[i</kbd> (show the first line containing the keyword)", "sl": "scope↑", "force": true},
{"s": "snacks", "m": "o", "k": "[i", "d": "Jump to the start of the current scope; repeat for the enclosing one", "cat": "Motion", "n": "Snacks scope, UI sessions only. Replaces Vim's <kbd>[i</kbd> (show the first line containing the keyword)", "sl": "scope↑", "force": true},
{"s": "snacks", "m": "n", "k": "]i", "d": "Jump to the end of the current scope", "cat": "Motion", "n": "Snacks scope, UI sessions only. Replaces Vim's <kbd>]i</kbd> (show the next line containing the keyword)", "sl": "scope↓", "force": true},
{"s": "snacks", "m": "x", "k": "]i", "d": "Jump to the end of the current scope", "cat": "Motion", "n": "Snacks scope, UI sessions only. Replaces Vim's <kbd>]i</kbd> (show the next line containing the keyword)", "sl": "scope↓", "force": true},
{"s": "snacks", "m": "o", "k": "]i", "d": "Jump to the end of the current scope", "cat": "Motion", "n": "Snacks scope, UI sessions only. Replaces Vim's <kbd>]i</kbd> (show the next line containing the keyword)", "sl": "scope↓", "force": true}
],
"entries": [
{"k": "`.", "m": ["n", "x", "o"], "s": "builtin", "cat": "Mark & jump", "h": "'.", "d": "Jump to where the last change was made (<kbd>'.</kbd> for its line)", "n": "For older changes use <kbd>g;</kbd> / <kbd>g,</kbd>"},
{"k": "`^", "m": ["n", "x", "o"], "s": "builtin", "cat": "Mark & jump", "h": "'^", "d": "Jump to where Insert mode was last stopped (<kbd>gi</kbd> also re-enters Insert)"},
{"k": "`\"", "m": ["n", "x", "o"], "s": "builtin", "cat": "Mark & jump", "h": "'quote", "d": "Jump to the cursor position when this buffer was last exited", "n": "This config jumps there automatically when a file is opened (<code>lua/options.lua:82-91</code>)"},
{"k": "`0", "m": ["n", "x", "o"], "s": "builtin", "cat": "Mark & jump", "h": "'0", "d": "Jump to where you were when Neovim last exited ('1 the time before, …)", "n": "Numbered marks come from the ShaDa file and can't be set by hand"},
{"k": "\"{1-9}", "m": ["n"], "s": "builtin", "cat": "Register & macro", "h": "quote_number", "d": "Last nine deletes of a line or more, newest in \"1 (still filled in this config)", "n": "Tested: <kbd>dd</kbd> fills both <code>\"d</code> and <code>\"1</code>, and the next <kbd>dd</kbd> shifts the old text to <code>\"2</code>"},
{"k": "\"-", "m": ["n"], "s": "builtin", "cat": "Register & macro", "h": "quote_-", "d": "Small-delete register: stays empty here because d/c/x always name register d", "n": "Vim skips <code>\"-</code> when a register is given; tested: <kbd>dw</kbd> fills <code>\"d</code>, not <code>\"-</code>"},
{"k": "\".", "m": ["n"], "s": "builtin", "cat": "Register & macro", "h": "quote_.", "d": "Last inserted text (read-only): \".p puts it again", "n": "Read-only registers <code>\".</code> <code>\"%</code> <code>\":</code> work with <kbd>p</kbd>, <kbd>P</kbd>, <code>:put</code> and <kbd>&lt;C-r&gt;</kbd>"},
{"k": "\"%", "m": ["n"], "s": "builtin", "cat": "Register & macro", "h": "quote_%", "d": "Name of the current file (read-only): \"%p, or <C-r>% in Insert mode"},
{"k": "\"=", "m": ["n"], "s": "builtin", "cat": "Register & macro", "h": "quote_=", "d": "Expression register: \"=5*7<CR>p puts 35; <C-r>=… inserts a result in Insert mode"},
{"k": "<CR>", "m": ["i"], "s": "builtin", "cat": "Command line", "h": "cmdwin", "ctx": "Command-line window (q: q/ <C-f>)", "d": "Run the line under the cursor (Normal-mode Enter is Leap here, so press i first)", "n": "Tested: <kbd>q:</kbd> <kbd>i</kbd> <code>let g:x=3</code> <kbd>&lt;CR&gt;</kbd> runs it"},
{"k": "<C-C>", "m": ["n", "i"], "s": "builtin", "cat": "Command line", "h": "cmdwin", "ctx": "Command-line window (q: q/ <C-f>)", "d": "Put the line under the cursor on the command line without running it", "n": "Edit further, then <kbd>&lt;CR&gt;</kbd> runs it from the normal command line (tested)"},
{"k": ":q", "m": [":"], "s": "builtin", "cat": "Command line", "h": "cmdwin", "ctx": "Command-line window (q: q/ <C-f>)", "d": "Close the command-line window without running anything (<C-w>c also works)"},
{"k": "<C-W><CR>", "m": ["n"], "s": "builtin", "cat": "Quickfix & lists", "h": "CTRL-W_<CR>", "ctx": "Quickfix / location-list window", "d": "Open the entry under the cursor in a new split", "n": "Works even though plain <kbd>&lt;CR&gt;</kbd> is Leap here (tested: opens the file at the entry's line)"},
{"k": "<C-V>{motion}$A{text}<Esc>", "m": ["n"], "s": "builtin", "cat": "Visual", "h": "v_b_A", "d": "Append {text} at the end of every selected line, even ragged ones", "n": "Without <kbd>$</kbd>, <kbd>A</kbd> appends at the block's right edge instead. Tested: <code>a / bbb / cc</code> + <kbd>&lt;C-v&gt;jj$AX&lt;Esc&gt;</kbd> → <code>aX / bbbX / ccX</code>"},
{"k": "<C-X><C-N>", "m": ["i"], "s": "builtin", "cat": "Completion & AI", "h": "i_CTRL-X_CTRL-N", "ctx": "This config (blink.cmp)", "d": "Built-in keyword completion through CTRL-X (plain <C-n>/<C-p> open blink's menu)", "n": "Tested with blink active: <kbd>&lt;C-x&gt;&lt;C-n&gt;</kbd>, <kbd>&lt;C-x&gt;&lt;C-p&gt;</kbd>, <kbd>&lt;C-x&gt;&lt;C-l&gt;</kbd> (lines) and <kbd>&lt;C-x&gt;&lt;C-f&gt;</kbd> (file names) complete"},
{"k": ":lua vim.pack.update()", "m": [":"], "s": "neovim", "cat": "Misc", "h": "vim.pack.update()", "d": "Fetch plugin updates and review them in a confirmation tab before applying", "n": "<code>vim.pack.update(nil, { offline = true })</code> just lists installed plugins. Plugins on disk but not added (here: <code>cord.nvim</code>, <code>git-blame</code>, <code>nvim-treesitter</code>) show as \"(not active)\""},
{"k": ":w", "m": [":"], "s": "neovim", "cat": "Misc", "h": "vim.pack.update()", "ctx": "vim.pack update tab", "d": "Apply the listed updates"},
{"k": ":q", "m": [":"], "s": "neovim", "cat": "Misc", "h": "vim.pack.update()", "ctx": "vim.pack update tab", "d": "Discard the updates and close the tab"},
{"k": "]]", "m": ["n", "x"], "s": "neovim", "cat": "Misc", "h": "vim.pack.update()", "ctx": "vim.pack update tab", "d": "Next plugin section ([[ for the previous one)", "n": "Buffer-local (<code>ftplugin/nvim-pack.lua</code>), so it wins over this config's Snacks reference jump"},
{"k": "K", "m": ["n"], "s": "neovim", "cat": "Misc", "h": "vim.pack.update()", "ctx": "vim.pack update tab", "d": "Details of the pending change or newer tag under the cursor (LSP hover)"},
{"k": "gra", "m": ["n"], "s": "neovim", "cat": "Misc", "h": "vim.pack.update()", "ctx": "vim.pack update tab", "d": "Plugin actions: update, skip updating, or delete a plugin that isn't active", "n": "Neovim's code-action key (<kbd>&lt;leader&gt;ca</kbd> works too). Tested: on <code>cord.nvim</code> the actions are Update / Skip updating / Delete"},
{"k": ":checkhealth vim.lsp", "m": [":"], "s": "neovim", "cat": "LSP & diagnostics", "h": ":checkhealth", "d": "Show attached LSP clients, their configs and the log path (there is no :LspInfo)", "n": "nvim-lspconfig skips its <code>:LspInfo</code>/<code>:LspStart</code>/<code>:LspStop</code>/<code>:LspRestart</code>/<code>:LspLog</code> when Neovim has <code>:lsp</code> (<code>plugin/lspconfig.lua:6-8</code>); use <code>:lsp restart</code>, <code>:lsp stop</code>, <code>:lsp enable</code>"}
],
"commands": {
"Man": "Open a man page: :Man {name}, :Man {sect} {name}; no arg = word under cursor",
"Explore": "netrw: browse the current file's directory (or [dir]) in this window",
"Hexplore": "netrw: browse the directory in a horizontal split (! = above)",
"Lexplore": "netrw: toggle a full-height explorer on the left",
"Sexplore": "netrw: split, then browse the current file's directory (! = vertical)",
"Vexplore": "netrw: browse the directory in a vertical split",
"Texplore": "netrw: browse the directory in a new tab",
"Nexplore": "netrw: next file matched by :Explore **/pattern",
"Pexplore": "netrw: previous file matched by :Explore **/pattern",
"Ntree": "netrw: make [dirname] (or the line under the cursor) the tree top",
"Nread": "netrw: re-read the last remote file into this buffer",
"Nwrite": "netrw: write [range] to the last remote file",
"Nsource": "netrw: source a remote {netfile}",
"NetUserPass": "netrw: set the user id and password for remote (ftp) access",
"DoMatchParen": "Turn matching-paren highlighting back on",
"NoMatchParen": "Turn off highlighting of the matching paren under the cursor",
"MatchDisable": "matchit: drop its % g% [% ]% maps (plain bracket %)",
"MatchEnable": "matchit: restore its % g% [% ]% maps",
"MatchDebug": "matchit: debug b:match_words (adds a Matchit menu)",
"Tutor": "Open the interactive Vim tutorial (:Tutor {name} for others)",
"UpdateRemotePlugins": "Register remote (rplugin/) plugins; run after installing or updating one"
}
}
+250
View File
@@ -0,0 +1,250 @@
{
"entries": [
{"k": "i(", "m": ["x", "o"], "d": "Inside (…) parentheses, leaving out whitespace next to the brackets", "s": "mini.ai", "cat": "Text object", "h": "MiniAi-builtin-textobjects", "n": "Opening bracket leaves out the whitespace just inside the brackets (<code>di(</code> on <code>( a )</code> gives <code>( )</code>), closing bracket (<code>i)</code>) includes it (<code>di)</code> gives <code>()</code>). Unlike Vim's built-in, it also works when the cursor is <em>before</em> the pair: mini.ai takes the pair covering the cursor, else the next one (first on the cursor line, then within 50 lines)."},
{"k": "i)", "m": ["x", "o"], "d": "Inside (…) parentheses, including whitespace next to the brackets", "s": "mini.ai", "cat": "Text object", "h": "MiniAi-builtin-textobjects"},
{"k": "a(", "m": ["x", "o"], "d": "Around (…) including the parentheses (same as a))", "s": "mini.ai", "cat": "Text object", "h": "MiniAi-builtin-textobjects", "n": "<code>2a(</code>, or typing <code>a(</code> again in Visual mode, selects the next enclosing pair."},
{"k": "a)", "m": ["x", "o"], "d": "Around (…) including the parentheses (same as a()", "s": "mini.ai", "cat": "Text object", "h": "MiniAi-builtin-textobjects"},
{"k": "i[", "m": ["x", "o"], "d": "Inside […] brackets, leaving out whitespace next to the brackets", "s": "mini.ai", "cat": "Text object", "h": "MiniAi-builtin-textobjects"},
{"k": "i]", "m": ["x", "o"], "d": "Inside […] brackets, including whitespace next to the brackets", "s": "mini.ai", "cat": "Text object", "h": "MiniAi-builtin-textobjects"},
{"k": "a[", "m": ["x", "o"], "d": "Around […] including the brackets (same as a])", "s": "mini.ai", "cat": "Text object", "h": "MiniAi-builtin-textobjects"},
{"k": "i{", "m": ["x", "o"], "d": "Inside {…} braces, leaving out whitespace next to the braces", "s": "mini.ai", "cat": "Text object", "h": "MiniAi-builtin-textobjects"},
{"k": "i}", "m": ["x", "o"], "d": "Inside {…} braces, including whitespace next to the braces", "s": "mini.ai", "cat": "Text object", "h": "MiniAi-builtin-textobjects"},
{"k": "a{", "m": ["x", "o"], "d": "Around {…} including the braces (same as a})", "s": "mini.ai", "cat": "Text object", "h": "MiniAi-builtin-textobjects"},
{"k": "i<", "m": ["x", "o"], "d": "Inside <…> angle brackets, leaving out whitespace next to them", "s": "mini.ai", "cat": "Text object", "h": "MiniAi-builtin-textobjects"},
{"k": "i>", "m": ["x", "o"], "d": "Inside <…> angle brackets, including whitespace next to them", "s": "mini.ai", "cat": "Text object", "h": "MiniAi-builtin-textobjects"},
{"k": "a<", "m": ["x", "o"], "d": "Around <…> including the angle brackets (same as a>)", "s": "mini.ai", "cat": "Text object", "h": "MiniAi-builtin-textobjects"},
{"k": "ib", "m": ["x", "o"], "d": "Inside the nearest (), [] or {} block", "s": "mini.ai", "cat": "Text object", "h": "MiniAi-builtin-textobjects", "e": 1, "n": "Vim's built-in <code>ib</code> only knows <code>()</code>; mini.ai's <code>b</code> is an alias for <code>)</code>, <code>]</code> and <code>}</code> (edge whitespace included) and searches cover-or-next."},
{"k": "ab", "m": ["x", "o"], "d": "Around the nearest (), [] or {} block, brackets included", "s": "mini.ai", "cat": "Text object", "h": "MiniAi-builtin-textobjects"},
{"k": "i\"", "m": ["x", "o"], "d": "Inside \"…\" double quotes", "s": "mini.ai", "cat": "Text object", "h": "MiniAi-builtin-textobjects", "n": "mini.ai matches balanced quote pairs and searches 50 lines (cover, else next). Built-in <code>i\"</code> only looked at the cursor line."},
{"k": "a\"", "m": ["x", "o"], "d": "Around \"…\" including the quotes, without trailing whitespace", "s": "mini.ai", "cat": "Text object", "h": "MiniAi-builtin-textobjects", "n": "Differs from Vim's built-in <code>a\"</code>, which also takes the whitespace after the closing quote."},
{"k": "i'", "m": ["x", "o"], "d": "Inside '…' single quotes", "s": "mini.ai", "cat": "Text object", "h": "MiniAi-builtin-textobjects"},
{"k": "a'", "m": ["x", "o"], "d": "Around '…' including the quotes, without trailing whitespace", "s": "mini.ai", "cat": "Text object", "h": "MiniAi-builtin-textobjects"},
{"k": "i`", "m": ["x", "o"], "d": "Inside `…` backticks", "s": "mini.ai", "cat": "Text object", "h": "MiniAi-builtin-textobjects"},
{"k": "a`", "m": ["x", "o"], "d": "Around `…` including the backticks, without trailing whitespace", "s": "mini.ai", "cat": "Text object", "h": "MiniAi-builtin-textobjects"},
{"k": "iq", "m": ["x", "o"], "d": "Inside the nearest quotes of any kind: '…', \"…\" or `…`", "s": "mini.ai", "cat": "Text object", "h": "MiniAi-builtin-textobjects", "sl": "in quote"},
{"k": "aq", "m": ["x", "o"], "d": "Around the nearest quotes of any kind, quotes included", "s": "mini.ai", "cat": "Text object", "h": "MiniAi-builtin-textobjects"},
{"k": "if", "m": ["x", "o"], "d": "Inside a function call: the arguments between its parentheses", "s": "mini.ai", "cat": "Text object", "h": "MiniAi-builtin-textobjects", "e": 1, "sl": "in call", "n": "A function call is a name made of letters, digits, <code>_</code> or <code>.</code> followed by balanced <code>()</code>, e.g. <code>vim.fn.getline(1)</code>. Pattern-based, so a <code>)</code> inside a string can confuse it."},
{"k": "af", "m": ["x", "o"], "d": "Around a function call, name and parentheses included", "s": "mini.ai", "cat": "Text object", "h": "MiniAi-builtin-textobjects"},
{"k": "ia", "m": ["x", "o"], "d": "Inside an argument: just the argument, no comma or edge whitespace", "s": "mini.ai", "cat": "Text object", "h": "MiniAi-builtin-textobjects", "n": "Arguments live inside <code>()</code>, <code>[]</code> or <code>{}</code>, separated by commas; commas inside nested brackets or <code>\"…\"</code>/<code>'…'</code> strings are ignored (not inside <code>`…`</code>)."},
{"k": "aa", "m": ["x", "o"], "d": "Around an argument plus one adjacent comma, so daa leaves a valid list", "s": "mini.ai", "cat": "Text object", "h": "MiniAi-builtin-textobjects", "e": 1, "sl": "arg", "n": "First argument takes the comma on its right; middle and last arguments take the comma on their left. On the first argument the following space stays: <code>daa</code> turns <code>f(a, b)</code> into <code>f( b)</code>."},
{"k": "it", "m": ["x", "o"], "d": "Inside a tag pair: the content between <x> and </x>", "s": "mini.ai", "cat": "Text object", "h": "MiniAi-builtin-textobjects", "n": "Replaces Vim's built-in <code>it</code>/<code>at</code> with a pattern match, so same-name nested tags (<code>&lt;a&gt;&lt;a&gt;&lt;/a&gt;&lt;/a&gt;</code>) can mis-match."},
{"k": "at", "m": ["x", "o"], "d": "Around a tag pair, opening and closing tags included", "s": "mini.ai", "cat": "Text object", "h": "MiniAi-builtin-textobjects"},
{"k": "i?", "m": ["x", "o"], "d": "Inside custom edges: prompts for the left and right strings", "s": "mini.ai", "cat": "Text object", "h": "MiniAi-builtin-textobjects", "n": "Edges are literal strings, not patterns. Dot-repeat reuses the answers without asking again."},
{"k": "a?", "m": ["x", "o"], "d": "Around custom edges (prompted), edges included", "s": "mini.ai", "cat": "Text object", "h": "MiniAi-builtin-textobjects"},
{"k": "ig", "m": ["x", "o"], "d": "Entire buffer (custom textobject from lua/plugins.lua)", "s": "config", "cat": "Text object", "e": 1, "sl": "buffer", "n": "Defined in <code>Config.plugins.mini_ai.custom_textobjects.g</code>: charwise from line 1, column 1 to the end of the last line. <code>ig</code> and <code>ag</code> are identical. Try <code>yig</code>, <code>=ig</code>, <code>cig</code>, <code>vig</code>."},
{"k": "ag", "m": ["x", "o"], "d": "Entire buffer (same as ig)", "s": "config", "cat": "Text object"},
{"k": "i{punct}", "m": ["x", "o"], "d": "Between two {punct} characters, e.g. i_ i, i* i/ i- i<Space>", "s": "mini.ai", "cat": "Text object", "h": "MiniAi-builtin-textobjects", "n": "Any id that is not a Latin letter and not defined above works as a separator, e.g. <code>ci_</code> in <code>foo_bar_baz</code>. Digits count too."},
{"k": "a{punct}", "m": ["x", "o"], "d": "Like i{punct} plus the run of separators on its right", "s": "mini.ai", "cat": "Text object", "h": "MiniAi-builtin-textobjects"},
{"k": "i{letter}", "m": ["x", "o"], "d": "Letters mini.ai doesn't define (w W s p B) fall back to Vim's text objects", "s": "mini.ai", "cat": "Text object", "n": "So <code>iw</code>, <code>aW</code>, <code>is</code>, <code>ap</code>, <code>iB</code>, <code>aB</code> behave exactly as in stock Vim."},
{"k": "iN{id}", "m": ["x", "o"], "d": "Inside the next {id} textobject, e.g. ciN( diN\" viNq", "s": "mini.ai", "cat": "Text object", "h": "MiniAi.config", "e": 1, "sl": "in next", "n": "Uses search method <code>next</code>: always the one after the cursor, even if the cursor is inside one."},
{"k": "aN{id}", "m": ["x", "o"], "d": "Around the next {id} textobject, e.g. daN) yaNf", "s": "mini.ai", "cat": "Text object", "h": "MiniAi.config"},
{"k": "il{id}", "m": ["x", "o"], "d": "Inside the previous (last) {id} textobject, e.g. cil\"", "s": "mini.ai", "cat": "Text object", "h": "MiniAi.config"},
{"k": "al{id}", "m": ["x", "o"], "d": "Around the previous (last) {id} textobject", "s": "mini.ai", "cat": "Text object", "h": "MiniAi.config"},
{"k": "[count]i{id}", "m": ["x", "o"], "d": "The [count]-th enclosing textobject, e.g. d2i) empties the outer parens", "s": "mini.ai", "cat": "Text object", "h": "MiniAi-builtin-textobjects"},
{"k": "{Visual}i{id}", "m": ["x"], "d": "Repeat i{id}/a{id} while selected to grow to the next enclosing one", "s": "mini.ai", "cat": "Text object", "h": "MiniAi-builtin-textobjects", "n": "E.g. <code>vi)</code> then <code>i)</code> again, or <code>va\"a\"</code>. The current selection is the reference, so the result never equals it."},
{"k": "g[{id}", "m": ["n", "x", "o"], "d": "Move to the left edge of the a{id} textobject, e.g. g[( g[f g[\"", "s": "mini.ai", "cat": "Motion", "h": "MiniAi.move_cursor()"},
{"k": "g]{id}", "m": ["n", "x", "o"], "d": "Move to the right edge of the a{id} textobject, e.g. g]) g]t", "s": "mini.ai", "cat": "Motion", "h": "MiniAi.move_cursor()"},
{"k": "sa{motion}{char}", "m": ["n"], "d": "Add surrounding {char} around {motion} or textobject", "s": "mini.surround", "cat": "Surround", "h": "MiniSurround-builtin-surroundings", "e": 1, "sl": "surround", "n": "<code>sa</code> is an operator, so any motion or text object works, including mini.ai ones (<code>saif\"</code>, <code>saaa]</code>). Dot-repeatable."},
{"k": "saiw)", "m": ["n"], "d": "Surround the word with parentheses: (word)", "s": "mini.surround", "cat": "Surround"},
{"k": "saiw(", "m": ["n"], "d": "Surround the word with padded parentheses: ( word )", "s": "mini.surround", "cat": "Surround"},
{"k": "saiw\"", "m": ["n"], "d": "Surround the word with double quotes", "s": "mini.surround", "cat": "Surround"},
{"k": "saiwf", "m": ["n"], "d": "Wrap the word in a function call; prompts for the name: name(word)", "s": "mini.surround", "cat": "Surround"},
{"k": "saiwt", "m": ["n"], "d": "Wrap the word in a tag; prompts for it, e.g. div class=\"x\"", "s": "mini.surround", "cat": "Surround", "n": "The prompt takes the tag name plus attributes; the closing tag uses only the name."},
{"k": "saiw?", "m": ["n"], "d": "Surround the word with custom text (prompts for left and right)", "s": "mini.surround", "cat": "Surround"},
{"k": "sa$\"", "m": ["n"], "d": "Quote from the cursor to the end of the line", "s": "mini.surround", "cat": "Surround"},
{"k": "[count]sa{motion}{char}", "m": ["n"], "d": "Repeat the surrounding [count] times, e.g. 2saiw) gives ((word))", "s": "mini.surround", "cat": "Surround", "h": "MiniSurround-count-with-actions"},
{"k": "{Visual}sa{char}", "m": ["x"], "d": "Surround the selection with {char}", "s": "mini.surround", "cat": "Surround"},
{"k": "sd{char}", "m": ["n"], "d": "Delete the surrounding {char} around the cursor", "s": "mini.surround", "cat": "Surround", "h": "MiniSurround-builtin-surroundings", "e": 1, "sl": "del surr", "n": "Search method is <code>cover</code> (it must enclose the cursor) within 20 lines. Add <code>n</code>/<code>l</code> after <code>sd</code> to target the next/previous one instead."},
{"k": "sd'", "m": ["n"], "d": "Delete the surrounding single quotes", "s": "mini.surround", "cat": "Surround"},
{"k": "sdq", "m": ["n"], "d": "Delete the nearest surrounding quotes of any kind", "s": "mini.surround", "cat": "Surround"},
{"k": "sdb", "m": ["n"], "d": "Delete the nearest surrounding (), [] or {}", "s": "mini.surround", "cat": "Surround"},
{"k": "sdf", "m": ["n"], "d": "Remove a function call but keep its arguments: f(x) → x", "s": "mini.surround", "cat": "Surround"},
{"k": "sdt", "m": ["n"], "d": "Remove the surrounding tag pair, keeping the content", "s": "mini.surround", "cat": "Surround"},
{"k": "sd(", "m": ["n"], "d": "Delete parentheses and the whitespace just inside them", "s": "mini.surround", "cat": "Surround"},
{"k": "sr{old}{new}", "m": ["n"], "d": "Replace surrounding {old} with {new}", "s": "mini.surround", "cat": "Surround", "h": "MiniSurround-builtin-surroundings", "e": 1, "sl": "repl surr"},
{"k": "sr)]", "m": ["n"], "d": "Replace (…) with […]", "s": "mini.surround", "cat": "Surround"},
{"k": "sr'\"", "m": ["n"], "d": "Replace single quotes with double quotes", "s": "mini.surround", "cat": "Surround"},
{"k": "srtt", "m": ["n"], "d": "Change the surrounding tag (prompts for the new one)", "s": "mini.surround", "cat": "Surround"},
{"k": "sr)tdiv<CR>", "m": ["n"], "d": "Replace parentheses with a <div> tag pair", "s": "mini.surround", "cat": "Surround"},
{"k": "sf{char}", "m": ["n", "x", "o"], "d": "Move the cursor to the right part of surrounding {char}", "s": "mini.surround", "cat": "Surround"},
{"k": "sF{char}", "m": ["n", "x", "o"], "d": "Move the cursor to the left part of surrounding {char}", "s": "mini.surround", "cat": "Surround"},
{"k": "sh{char}", "m": ["n"], "d": "Flash-highlight the surrounding {char} for 500 ms", "s": "mini.surround", "cat": "Surround"},
{"k": "sdn{char}", "m": ["n"], "d": "Delete the next {char} surrounding (after the cursor)", "s": "mini.surround", "cat": "Surround", "n": "The <code>n</code> (next) and <code>l</code> (last/previous) suffixes work after <code>sd</code>, <code>sr</code>, <code>sf</code>, <code>sF</code> and <code>sh</code>: <code>srn)]</code>, <code>sfl\"</code>, <code>shnt</code>."},
{"k": "sdl{char}", "m": ["n"], "d": "Delete the previous (last) {char} surrounding", "s": "mini.surround", "cat": "Surround"},
{"k": "[count]sd{char}", "m": ["n"], "d": "Act on the [count]-th enclosing surrounding: 2sd) on (a(b(c)b)a) gives (ab(c)ba)", "s": "mini.surround", "cat": "Surround", "h": "MiniSurround-count-with-actions"},
{"k": "(", "m": ["n", "x"], "d": "Surround id: find () and drop inner spaces; add pads with spaces: ( x )", "s": "mini.surround", "cat": "Surround", "ctx": "Surround id (after sa/sd/sr/sf/sh)", "n": "Same for <code>[</code>, <code>{</code>, <code>&lt;</code>."},
{"k": ")", "m": ["n", "x"], "d": "Surround id: () with no padding, inner spaces kept", "s": "mini.surround", "cat": "Surround", "ctx": "Surround id (after sa/sd/sr/sf/sh)", "n": "Same for <code>]</code>, <code>}</code>, <code>&gt;</code>."},
{"k": "b", "m": ["n", "x"], "d": "Surround id: finds any of (), [], {}; adds ()", "s": "mini.surround", "cat": "Surround", "ctx": "Surround id (after sa/sd/sr/sf/sh)"},
{"k": "q", "m": ["n", "x"], "d": "Surround id: finds any quote ' \" `; adds \"…\"", "s": "mini.surround", "cat": "Surround", "ctx": "Surround id (after sa/sd/sr/sf/sh)", "n": "Not balanced, unlike mini.ai's <code>q</code>: with the cursor on <code>x</code> in <code>\"a\" x \"b\"</code>, <code>sdq</code> strips the quotes around <code>\" x \"</code>."},
{"k": "t", "m": ["n", "x"], "d": "Surround id: finds a same-name tag pair; when adding, prompts for the tag", "s": "mini.surround", "cat": "Surround", "ctx": "Surround id (after sa/sd/sr/sf/sh)"},
{"k": "f", "m": ["n", "x"], "d": "Surround id: finds name(…); when adding, prompts for the function name", "s": "mini.surround", "cat": "Surround", "ctx": "Surround id (after sa/sd/sr/sf/sh)"},
{"k": "?", "m": ["n", "x"], "d": "Surround id: interactive, prompts for left and right parts", "s": "mini.surround", "cat": "Surround", "ctx": "Surround id (after sa/sd/sr/sf/sh)"},
{"k": "{other}", "m": ["n", "x"], "d": "Surround id: any other char surrounds with itself, e.g. * _ | $", "s": "mini.surround", "cat": "Surround", "ctx": "Surround id (after sa/sd/sr/sf/sh)"},
{"k": "\\(", "m": ["i"], "d": "No auto-pair right after a backslash: \\( types only (", "s": "config", "cat": "Pairs", "n": "Applies to every opener and quote (lua/smart_pairs.lua <code>should_pair</code>)."},
{"k": "({text}", "m": ["i"], "d": "Opener before text types only the opener (wrapping existing text)", "s": "config", "cat": "Pairs", "e": 1, "n": "smart_pairs only inserts the pair when nothing but whitespace follows the cursor, or the next char is a closing <code>)</code> <code>]</code> <code>}</code>. Also blocks pairing before a quote or comma, e.g. typing <code>(</code> inside an empty <code>\"\"</code>."},
{"k": "don't", "m": ["i"], "d": "A quote right after a letter or digit is typed alone (apostrophes, closing quotes)", "s": "config", "cat": "Pairs"},
{"k": "\"\"\"", "m": ["i"], "d": "A quote right after the same quote is typed alone, so \"\"\" docstrings work", "s": "config", "cat": "Pairs"},
{"k": "```", "m": ["i"], "d": "On a blank line: create a fenced code block pair, cursor after the opener", "s": "config", "cat": "Pairs", "ctx": "Markdown buffers", "e": 1, "n": "Type <code>`</code> three times: the first pairs to <code>``</code>, the second steps over, the third turns the line into <code>```</code> with a twin <code>```</code> below. Only when the next line is blank, the buffer ends, or the next line closes the block you're in. Type the language name right away."},
{"k": "````", "m": ["i"], "d": "Each extra ` lengthens both fences while the closer is untouched", "s": "config", "cat": "Pairs", "ctx": "Markdown buffers"},
{"k": "~~~", "m": ["i"], "d": "Tilde fences work the same way (a lone ~ is never paired)", "s": "config", "cat": "Pairs", "ctx": "Markdown buffers"},
{"k": "```", "m": ["i"], "d": "Inside a code block, a fence that can't close it (shorter, or ~ vs `) pairs as nested", "s": "config", "cat": "Pairs", "ctx": "Inside a Markdown code block", "n": "If the new run is long enough to close the enclosing block, it is not paired; growing a nested pair to that length collapses it into the block's closer."},
{"k": "<BS>", "m": ["i"], "d": "At the end of an untouched fence pair: shrink both; below 3 the closer goes", "s": "config", "cat": "Pairs", "ctx": "Markdown buffers"},
{"k": "<CR>", "m": ["i"], "d": "Between (), [] or {}: put the closer on its own line, cursor between", "s": "mini.pairs", "cat": "Pairs", "n": "Quotes are registered with <code>cr = false</code>, so <kbd>Enter</kbd> between <code>\"\"</code> is a plain newline."},
{"k": "f", "m": ["n", "x", "o"], "d": "After f/F: next match in that motion's direction (no new {char})", "s": "flash", "cat": "Motion", "ctx": "Right after f/F/t/T (highlights visible)", "n": "Flash's clever-f style <code>char_actions</code>: the lowercase motion key is <em>next</em>, the uppercase one <em>prev</em>. After <code>Fx</code> that means <kbd>f</kbd> keeps going left and <kbd>F</kbd> goes right. Ends once the highlights go away (cursor moved by something else, <kbd>Esc</kbd>, Insert mode, leaving the buffer)."},
{"k": "F", "m": ["n", "x", "o"], "d": "After f/F: match in the opposite direction (no new {char})", "s": "flash", "cat": "Motion", "ctx": "Right after f/F/t/T (highlights visible)"},
{"k": "t", "m": ["n", "x", "o"], "d": "After t/T: next match in that motion's direction (no new {char})", "s": "flash", "cat": "Motion", "ctx": "Right after f/F/t/T (highlights visible)"},
{"k": "T", "m": ["n", "x", "o"], "d": "After t/T: match in the opposite direction (no new {char})", "s": "flash", "cat": "Motion", "ctx": "Right after f/F/t/T (highlights visible)"},
{"k": "<Esc>", "m": ["n", "x"], "d": "Clear the Flash f/t highlights", "s": "flash", "cat": "Motion", "ctx": "Right after f/F/t/T (highlights visible)"},
{"k": "[count]f{char}", "m": ["n", "x", "o"], "d": "Jump to the [count]-th {char} on the line (also with F t T ; ,)", "s": "flash", "cat": "Motion"},
{"k": "s", "m": ["n"], "d": "Flash: label every visible result; type a label to move the selection there", "s": "snacks", "cat": "Find & pick", "ctx": "Snacks picker", "n": "Picker input window, Normal mode (<code>picker.win.input.keys</code> in lua/plugins.lua). Runs <code>flash.jump</code> with pattern <code>^</code> restricted to the <code>snacks_picker_list</code> window; picking a label moves the list cursor, it does not confirm."},
{"k": "<M-s>", "m": ["n", "i"], "d": "Flash: label every visible result; type a label to move the selection there", "s": "snacks", "cat": "Find & pick", "ctx": "Snacks picker"},
{"k": "{char1}{char2}", "m": ["n", "x", "o"], "d": "Type the first two chars of the target; labels preview after the first", "s": "leap", "cat": "Motion", "ctx": "During a Leap jump", "h": "leap-usage", "n": "If the closest match is unlabeled you are already there (autojump) and the remaining labels are \"safe\" keys you would not type next (<code>sfnut/SFNLHMUGTZ?</code>); any other key just runs as a normal command. Case-sensitive here ('ignorecase' is off). In Operator-pending mode with several matches you always pick a label."},
{"k": "{label}", "m": ["n", "x", "o"], "d": "Jump to the target showing that label", "s": "leap", "cat": "Motion", "ctx": "During a Leap jump"},
{"k": "<Space>", "m": ["n", "x", "o"], "d": "After the 2 chars: show the next group of labels (too many matches)", "s": "leap", "cat": "Motion", "ctx": "During a Leap jump", "h": "leap.opts.keys", "n": "Labels of later groups show dimmed/concealed until you switch to them."},
{"k": "<BS>", "m": ["n", "x", "o"], "d": "Back to the previous group of labels", "s": "leap", "cat": "Motion", "ctx": "During a Leap jump", "h": "leap.opts.keys"},
{"k": "<CR>", "m": ["n", "x", "o"], "d": "As the first key: repeat the previous Leap search (so <CR><CR> re-leaps)", "s": "leap", "cat": "Motion", "ctx": "During a Leap jump", "h": "leap-repeat"},
{"k": "{char}<CR>", "m": ["n", "x", "o"], "d": "Jump straight to the closest {char} (one-char shortcut)", "s": "leap", "cat": "Motion", "ctx": "During a Leap jump", "h": "leap-shortcut"},
{"k": "{char}<Space>", "m": ["n", "x", "o"], "d": "Target {char} followed by a space, a tab or the end of the line", "s": "leap", "cat": "Motion", "ctx": "During a Leap jump", "h": "leap-till-eol"},
{"k": "<Space><Space>", "m": ["n", "x", "o"], "d": "Target an empty line or an end-of-line position", "s": "leap", "cat": "Motion", "ctx": "During a Leap jump", "h": "leap-to-eol"},
{"k": "(", "m": ["n", "x", "o"], "d": "Equivalence classes: ( [ { match each other, ) ] } too, and ' \" ` too", "s": "leap", "cat": "Motion", "ctx": "During a Leap jump", "h": "leap.opts.equivalence_classes", "n": "Space also stands for Tab and end of line. Typing any member matches the whole class."},
{"k": "<Esc>", "m": ["n", "x", "o"], "d": "Cancel the Leap", "s": "leap", "cat": "Motion", "ctx": "During a Leap jump"},
{"k": "gcip", "m": ["n"], "d": "Toggle comment on the current paragraph", "s": "neovim", "cat": "Comment", "h": "gc-default"},
{"k": "[count]gcc", "m": ["n"], "d": "Toggle comment on [count] lines from the cursor", "s": "neovim", "cat": "Comment", "h": "gcc-default"},
{"k": "gcgc", "m": ["n"], "d": "Uncomment the whole comment block under the cursor", "s": "neovim", "cat": "Comment", "h": "o_gc-default"},
{"k": "dgc", "m": ["n"], "d": "Delete the comment block under the cursor", "s": "neovim", "cat": "Comment", "h": "o_gc-default"},
{"k": "a%", "m": ["o"], "d": "In Operator-pending mode a% is mini.ai's 'between % signs', not matchit's", "s": "mini.ai", "cat": "Text object", "n": "matchit only maps <code>a%</code> in Visual mode, so <code>da%</code> goes through mini.ai's <code>a</code> with <code>%</code> as a separator id. For matchit's group use <code>va%</code>, which stops on the first character of the closing word (<code>e</code> of <code>end</code>)."}
],
"map_desc": [
{"s": "flash", "m": "*", "k": "f", "d": "Flash: jump to the next {char} on this line", "cat": "Motion", "e": 1, "sl": "find→", "n": "flash.nvim char mode (lua/plugins.lua: <code>modes.char.multi_line = false</code>): never leaves the cursor line or wraps, no jump labels. All matches on the line light up and the window is dimmed until the cursor moves. Press <kbd>f</kbd> again for the next match. Each jump sets the <code>'</code> mark, so <kbd>`</kbd><kbd>`</kbd> jumps back (<kbd>Ctrl-O</kbd> can't: the jumplist keeps one entry per line). Inclusive with operators, like Vim."},
{"s": "flash", "m": "*", "k": "F", "d": "Flash: jump to the previous {char} on this line", "cat": "Motion", "e": 1, "sl": "←find", "n": "Right after <code>Fx</code>, <kbd>F</kbd> moves to the <em>right</em> and <kbd>f</kbd> keeps going left (flash's clever-f mapping: lowercase = next in the motion's direction)."},
{"s": "flash", "m": "*", "k": "t", "d": "Flash: jump till before the next {char} on this line", "cat": "Motion", "e": 1, "sl": "till→", "n": "Repeat with <kbd>t</kbd> (next) or <kbd>T</kbd> (opposite) while highlighted."},
{"s": "flash", "m": "*", "k": "T", "d": "Flash: jump till after the previous {char} on this line", "cat": "Motion", "sl": "←till"},
{"s": "flash", "m": "*", "k": ";", "d": "Flash: repeat the last f/F/t/T in the same direction", "cat": "Motion", "e": 1, "sl": "rep ft", "n": "Works any time later (not only while highlighted). After a yank (<code>yf.</code>) flash auto-hides its highlights."},
{"s": "flash", "m": "*", "k": ",", "d": "Flash: repeat the last f/F/t/T in the opposite direction", "cat": "Motion", "sl": "ft rep←"},
{"s": "config", "m": "*", "k": "<CR>", "d": "Leap: jump anywhere in this window (2 chars, then a label)", "cat": "Motion", "e": 1, "sl": "leap", "force": true, "n": "<code>&lt;Plug&gt;(leap)</code>, lua/keymaps.lua. Bidirectional in the current window, closest targets first; inclusive with operators (<code>d&lt;CR&gt;ab</code>). Replaces Vim's <kbd>Enter</kbd> = <em>next line</em> (use <kbd>+</kbd> or <kbd>j</kbd>). Being a global Normal map it also takes over <kbd>Enter</kbd> in the quickfix/location list and the command-line window. No traversal and [count] is ignored (bidirectional mode). Dot-repeat of Leap operations needs vim-repeat, which isn't installed."},
{"s": "config", "m": "n", "k": "S", "d": "Leap from window: jump to a spot in another window (2 chars + label)", "cat": "Motion", "e": 1, "sl": "leap win", "force": true, "n": "<code>&lt;Plug&gt;(leap-from-window)</code>, Normal mode only: targets every other focusable, non-floating window in the tab and moves you there. Replaces Vim's <kbd>S</kbd> (use <kbd>cc</kbd>). Visual <kbd>S</kbd> is unchanged."},
{"s": "mini.ai", "m": "*", "k": "a", "d": "Around textobject: a + id (mini.ai), e.g. af aa aq ab a)", "cat": "Text object", "e": 1, "sl": "around", "force": true, "n": "Waits for one id character (reminder after 1 s). Search method <code>cover_or_next</code> within <code>n_lines = 50</code>: the textobject covering the cursor, else the next one (first on the cursor line). Unknown letters fall back to Vim's built-ins (<code>aw</code>, <code>ap</code>, …)."},
{"s": "mini.ai", "m": "*", "k": "i", "d": "Inside textobject: i + id (mini.ai), e.g. if ia iq ib i) ig", "cat": "Text object", "e": 1, "sl": "inside", "force": true},
{"s": "mini.ai", "m": "*", "k": "aN", "d": "Around the next textobject: aN + id, e.g. daN)", "cat": "Text object", "sl": "a next"},
{"s": "mini.ai", "m": "*", "k": "iN", "d": "Inside the next textobject: iN + id, e.g. ciN\"", "cat": "Text object", "sl": "i next"},
{"s": "mini.ai", "m": "*", "k": "al", "d": "Around the previous (last) textobject: al + id", "cat": "Text object", "sl": "a last"},
{"s": "mini.ai", "m": "*", "k": "il", "d": "Inside the previous (last) textobject: il + id", "cat": "Text object", "sl": "i last"},
{"s": "mini.ai", "m": "*", "k": "g[", "d": "Move to the left edge of an a{id} textobject, e.g. g[(", "cat": "Motion", "sl": "obj start", "force": true},
{"s": "mini.ai", "m": "*", "k": "g]", "d": "Move to the right edge of an a{id} textobject, e.g. g])", "cat": "Motion", "sl": "obj end", "force": true, "n": "Replaces Vim's <code>g]</code> (<code>:tselect</code> on the tag under the cursor); use <code>:tselect</code> or <code>g&lt;C-]&gt;</code> instead."},
{"s": "mini.surround", "m": "*", "k": "s", "d": "Disabled by mini.surround (it's the sa/sd/sr/sf/sh prefix); use cl", "cat": "Surround", "sl": "surr…", "force": true, "n": "mini.surround maps a bare <code>s</code> to <code>&lt;Nop&gt;</code> in Normal, Visual and Operator-pending mode. Built-in <code>s</code> = <code>cl</code>; Visual <code>s</code> = <code>c</code>."},
{"s": "mini.surround", "m": "n", "k": "sa", "d": "Add surrounding: sa{motion}{char}, e.g. saiw)", "cat": "Surround", "sl": "surr add", "force": true},
{"s": "mini.surround", "m": "x", "k": "sa", "d": "Add surrounding to the selection: sa{char}", "cat": "Surround", "sl": "surr add", "force": true},
{"s": "mini.surround", "m": "n", "k": "sd", "d": "Delete surrounding: sd{char}, e.g. sd\" sdf sdt", "cat": "Surround", "sl": "surr del", "force": true},
{"s": "mini.surround", "m": "n", "k": "sdn", "d": "Delete the next surrounding: sdn{char}", "cat": "Surround", "sl": "del next"},
{"s": "mini.surround", "m": "n", "k": "sdl", "d": "Delete the previous surrounding: sdl{char}", "cat": "Surround", "sl": "del prev"},
{"s": "mini.surround", "m": "n", "k": "sr", "d": "Replace surrounding: sr{old}{new}, e.g. sr)] sr'\"", "cat": "Surround", "sl": "surr repl", "force": true},
{"s": "mini.surround", "m": "n", "k": "srn", "d": "Replace the next surrounding: srn{old}{new}", "cat": "Surround", "sl": "repl next"},
{"s": "mini.surround", "m": "n", "k": "srl", "d": "Replace the previous surrounding: srl{old}{new}", "cat": "Surround", "sl": "repl prev"},
{"s": "mini.surround", "m": "*", "k": "sf", "d": "Find surrounding: move to its right part, sf{char}", "cat": "Surround", "sl": "surr →", "force": true},
{"s": "mini.surround", "m": "*", "k": "sfn", "d": "Find the next surrounding's right part: sfn{char}", "cat": "Surround", "sl": "next →"},
{"s": "mini.surround", "m": "*", "k": "sfl", "d": "Find the previous surrounding's right part: sfl{char}", "cat": "Surround", "sl": "prev →"},
{"s": "mini.surround", "m": "*", "k": "sF", "d": "Find surrounding: move to its left part, sF{char}", "cat": "Surround", "sl": "← surr", "force": true},
{"s": "mini.surround", "m": "*", "k": "sFn", "d": "Find the next surrounding's left part: sFn{char}", "cat": "Surround", "sl": "← next"},
{"s": "mini.surround", "m": "*", "k": "sFl", "d": "Find the previous surrounding's left part: sFl{char}", "cat": "Surround", "sl": "← prev"},
{"s": "mini.surround", "m": "n", "k": "sh", "d": "Highlight surrounding for 500 ms: sh{char}", "cat": "Surround", "sl": "surr hl", "force": true},
{"s": "mini.surround", "m": "n", "k": "shn", "d": "Highlight the next surrounding: shn{char}", "cat": "Surround", "sl": "hl next"},
{"s": "mini.surround", "m": "n", "k": "shl", "d": "Highlight the previous surrounding: shl{char}", "cat": "Surround", "sl": "hl prev"},
{"s": "config", "m": "i", "k": "(", "d": "Smart pair (): only if the rest of the line is blank or starts with ) ] }", "cat": "Pairs", "e": 1, "sl": "( )", "force": true, "n": "lua/smart_pairs.lua gates mini.pairs: never after <code>\\</code>; otherwise types just <code>(</code>. Disable all pairing with <code>vim.g.minipairs_disable</code> or <code>vim.b.minipairs_disable</code>."},
{"s": "config", "m": "i", "k": "[", "d": "Smart pair []: only if the rest of the line is blank or starts with ) ] }", "cat": "Pairs", "sl": "[ ]", "force": true},
{"s": "config", "m": "i", "k": "{", "d": "Smart pair {}: only if the rest of the line is blank or starts with ) ] }", "cat": "Pairs", "sl": "{ }", "force": true},
{"s": "config", "m": "i", "k": "\"", "d": "Smart quote: step over a \" right after the cursor, else pair if allowed", "cat": "Pairs", "sl": "\" \"", "force": true, "n": "Pairs only when the rest of the line is blank or starts with <code>)</code> <code>]</code> <code>}</code>, and not after a letter, digit, backslash or another <code>\"</code>."},
{"s": "config", "m": "i", "k": "'", "d": "Smart quote: step over a ' right after the cursor, else pair if allowed", "cat": "Pairs", "sl": "' '", "force": true, "n": "Never pairs after a letter or digit, so <code>don't</code> and <code>it's</code> type normally."},
{"s": "config", "m": "i", "k": "`", "d": "Smart backtick: step over a ` right after the cursor, else pair if allowed", "cat": "Pairs", "sl": "` `", "force": true},
{"s": "config", "m": "i", "k": "`", "ctx": "markdown buffers", "d": "Markdown backtick: the 3rd ` on a blank line opens a ``` fence pair", "cat": "Pairs", "sl": "```", "force": true, "n": "More backticks lengthen both fences; otherwise behaves like the smart backtick pair."},
{"s": "config", "m": "i", "k": "~", "ctx": "markdown buffers", "d": "Markdown tilde: the 3rd ~ on a blank line opens a ~~~ fence pair", "cat": "Pairs", "sl": "~~~", "force": true},
{"s": "config", "m": "i", "k": "<BS>", "ctx": "markdown buffers", "d": "Markdown backspace: shrink an untouched fence pair, else mini.pairs <BS>", "cat": "Pairs", "sl": "fence ⌫", "force": true},
{"s": "mini.pairs", "m": "i", "k": ")", "d": "Close (): step over a ) right after the cursor, else type it", "cat": "Pairs", "sl": ")", "force": true},
{"s": "mini.pairs", "m": "i", "k": "]", "d": "Close []: step over a ] right after the cursor, else type it", "cat": "Pairs", "sl": "]", "force": true},
{"s": "mini.pairs", "m": "i", "k": "}", "d": "Close {}: step over a } right after the cursor, else type it", "cat": "Pairs", "sl": "}", "force": true},
{"s": "mini.pairs", "m": "i", "k": "<BS>", "d": "Backspace; inside an empty pair (), [], {}, \"\", '', `` delete both", "cat": "Pairs", "sl": "⌫ pair", "force": true},
{"s": "mini.pairs", "m": "i", "k": "<CR>", "d": "Newline; between (), [] or {} put the closer on its own line", "cat": "Pairs", "sl": "⏎ pair", "force": true},
{"s": "neovim", "m": "n", "k": "gc", "d": "Toggle comment over {motion}, e.g. gcip gcj gcap", "cat": "Comment", "e": 1, "sl": "comment", "force": true, "n": "Neovim's built-in commenting, uses <code>'commentstring'</code> (treesitter-aware for injected languages)."},
{"s": "neovim", "m": "x", "k": "gc", "d": "Toggle comment on the selected lines", "cat": "Comment", "sl": "comment", "force": true},
{"s": "neovim", "m": "n", "k": "gcc", "d": "Toggle comment on the current line ([count] lines)", "cat": "Comment", "e": 1, "sl": "comment ln", "force": true},
{"s": "neovim", "m": "o", "k": "gc", "d": "Comment block textobject: contiguous commented lines (gcgc, dgc)", "cat": "Comment", "sl": "cmt obj", "force": true},
{"s": "neovim", "m": "x", "k": "]n", "d": "Select the next treesitter node (replaces the selection)", "cat": "Visual", "sl": "node→", "force": true, "n": "Neovim 0.12 incremental selection. Its <code>an</code>/<code>in</code> (parent/child) are shadowed by mini.ai here."},
{"s": "neovim", "m": "x", "k": "[n", "d": "Select the previous treesitter node (replaces the selection)", "cat": "Visual", "sl": "←node", "force": true},
{"s": "neovim", "m": "x", "k": "]N", "d": "Extend the selection over the next treesitter node", "cat": "Visual", "sl": "node+→", "force": true},
{"s": "neovim", "m": "x", "k": "[N", "d": "Extend the selection over the previous treesitter node", "cat": "Visual", "sl": "←node+", "force": true},
{"s": "matchit", "m": "*", "k": "%", "d": "Jump to the matching bracket or keyword (if/else/end, tags…)", "cat": "Motion", "e": 1, "sl": "match", "force": true, "n": "matchit extends <code>%</code> with <code>b:match_words</code>: cycles forward through groups like <code>if</code> → <code>else</code> → <code>end</code>."},
{"s": "matchit", "m": "*", "k": "g%", "d": "Cycle backwards through matching keywords", "cat": "Motion", "sl": "match←", "force": true},
{"s": "matchit", "m": "*", "k": "[%", "d": "Go back to the [count]-th unmatched group word (e.g. if, or else from its branch)", "cat": "Motion", "sl": "[match", "force": true},
{"s": "matchit", "m": "*", "k": "]%", "d": "Go to the [count]-th next unmatched group word (e.g. else, end)", "cat": "Motion", "sl": "match]", "force": true},
{"s": "matchit", "m": "x", "k": "a%", "d": "Select the enclosing group, from its opener to the first char of the closer", "cat": "Text object", "sl": "a match", "force": true, "n": "Visual mode only. Per matchit's docs only the first character of the closing word is selected (<code>va%d</code> on an <code>if … end</code> block leaves <code>nd</code>), and a [count] is ignored. In Operator-pending mode <code>a%</code> is mini.ai's separator textobject instead."},
{"s": "focusline.nvim", "m": "n", "k": "zz", "d": "Scroll so the cursor line sits 30% from the top (not centred)", "cat": "Scroll & view", "e": 1, "sl": "focus", "force": true, "n": "focusline.nvim (<code>focus_target = \"30%\"</code>) runs the real <code>zz</code>, then scrolls with <kbd>Ctrl-E</kbd>/<kbd>Ctrl-Y</kbd> to put the line at 30% of the window height. Near the top of the buffer it just shows line 1 at the top. Normal mode only: Visual <code>zz</code> still centres."},
{"s": "focusline.nvim", "m": "n", "k": "z,", "d": "Put the cursor line 30% from the top of the window", "cat": "Scroll & view", "sl": "focus", "force": true, "n": "<code>z,</code> is not a Vim command; focusline adds it, so it only does the 30% repositioning."},
{"s": "focusline.nvim", "m": "n", "k": "<C-D>", "d": "Scroll half a page down, then put the cursor line 30% from the top", "cat": "Scroll & view", "e": 1, "sl": "½pg↓ 30%", "force": true, "n": "A [count] is passed to the real <code>&lt;C-D&gt;</code> (it sets <code>'scroll'</code>)."},
{"s": "focusline.nvim", "m": "n", "k": "<C-U>", "d": "Scroll half a page up, then put the cursor line 30% from the top", "cat": "Scroll & view", "sl": "½pg↑ 30%", "force": true},
{"s": "config", "m": "*", "k": "]]", "d": "Jump to the next LSP reference of the word under the cursor (Snacks words)", "cat": "LSP & diagnostics", "e": 1, "sl": "next ref", "force": true, "n": "<code>Snacks.words.jump</code> (lua/keymaps.lua) over the LSP document highlights; sets a jumplist entry and opens folds. Replaces Vim's <code>]]</code> section motion in Normal mode; Markdown buffers override it with heading jumps."},
{"s": "config", "m": "*", "k": "[[", "d": "Jump to the previous LSP reference of the word under the cursor (Snacks words)", "cat": "LSP & diagnostics", "sl": "prev ref", "force": true},
{"s": "ftplugin", "m": "n", "k": "]]", "d": "Jump to the next Markdown heading (treesitter)", "cat": "Motion", "sl": "next hdg", "force": true, "n": "From <code>$VIMRUNTIME/ftplugin/markdown.lua</code>; buffer-local, so it beats the global Snacks words <code>]]</code>."},
{"s": "ftplugin", "m": "n", "k": "[[", "d": "Jump to the previous Markdown heading (treesitter)", "cat": "Motion", "sl": "prev hdg", "force": true},
{"s": "ftplugin", "m": "x", "k": "]]", "d": "Extend the selection to the next Markdown heading", "cat": "Motion", "sl": "next hdg", "force": true},
{"s": "ftplugin", "m": "x", "k": "[[", "d": "Extend the selection to the previous Markdown heading", "cat": "Motion", "sl": "prev hdg", "force": true},
{"s": "neovim", "m": "x", "k": "an", "d": "Select the parent (outer) node: treesitter, or LSP selection range", "cat": "Visual", "sl": "parent node", "n": "Repeat to keep growing the selection. mini.ai's \"next\" objects moved to <kbd>aN</kbd>/<kbd>iN</kbd> so this stays reachable", "force": true},
{"s": "neovim", "m": "x", "k": "in", "d": "Select the child (inner) node: treesitter, or LSP selection range", "cat": "Visual", "sl": "child node", "force": true},
{"s": "neovim", "m": "o", "k": "an", "d": "Operate on the parent (outer) node", "cat": "Text object", "sl": "parent node", "force": true},
{"s": "neovim", "m": "o", "k": "in", "d": "Operate on the child (inner) node", "cat": "Text object", "sl": "child node", "force": true}
],
"builtin": {
"v_ab": {"n": "Handled by mini.ai here: <code>b</code> matches any of <code>()</code>, <code>[]</code>, <code>{}</code>, and it works from outside the pair (cover-or-next search)."},
"v_ib": {"n": "Handled by mini.ai here: <code>b</code> matches any of <code>()</code>, <code>[]</code>, <code>{}</code>, and it works from outside the pair (cover-or-next search)."},
"v_a(": {"n": "Handled by mini.ai: also finds the next pair when the cursor isn't inside one (within 50 lines)."},
"v_a)": {"n": "Handled by mini.ai: also finds the next pair when the cursor isn't inside one (within 50 lines)."},
"v_i(": {"n": "Handled by mini.ai: <code>i(</code> leaves out the whitespace just inside the brackets, <code>i)</code> includes it; searches forward if not inside a pair."},
"v_i)": {"n": "Handled by mini.ai: includes the whitespace just inside the brackets (<code>i(</code> leaves it out); searches forward if not inside a pair."},
"v_a[": {"n": "Handled by mini.ai: also finds the next pair when the cursor isn't inside one."},
"v_a]": {"n": "Handled by mini.ai: also finds the next pair when the cursor isn't inside one."},
"v_i[": {"n": "Handled by mini.ai: <code>i[</code> leaves out inner edge whitespace, <code>i]</code> includes it."},
"v_i]": {"n": "Handled by mini.ai: includes inner edge whitespace (<code>i[</code> leaves it out)."},
"v_a{": {"n": "Handled by mini.ai: also finds the next pair when the cursor isn't inside one."},
"v_a}": {"n": "Handled by mini.ai: also finds the next pair when the cursor isn't inside one."},
"v_i{": {"n": "Handled by mini.ai: <code>i{</code> leaves out inner edge whitespace, <code>i}</code> includes it."},
"v_i}": {"n": "Handled by mini.ai: includes inner edge whitespace (<code>i{</code> leaves it out)."},
"v_a<": {"n": "Handled by mini.ai: also finds the next pair when the cursor isn't inside one."},
"v_a>": {"n": "Handled by mini.ai: also finds the next pair when the cursor isn't inside one."},
"v_i<": {"n": "Handled by mini.ai: <code>i&lt;</code> leaves out inner edge whitespace, <code>i&gt;</code> includes it."},
"v_i>": {"n": "Handled by mini.ai: includes inner edge whitespace (<code>i&lt;</code> leaves it out)."},
"v_aquote": {"n": "Handled by mini.ai: balanced quotes searched over 50 lines; does not include the trailing whitespace."},
"v_iquote": {"n": "Handled by mini.ai: balanced quote pairs, cover-or-next search over 50 lines."},
"v_a'": {"n": "Handled by mini.ai: balanced quotes searched over 50 lines; does not include the trailing whitespace."},
"v_i'": {"n": "Handled by mini.ai: balanced quote pairs, cover-or-next search over 50 lines."},
"v_a`": {"n": "Handled by mini.ai: balanced backticks searched over 50 lines; does not include the trailing whitespace."},
"v_i`": {"n": "Handled by mini.ai: balanced backtick pairs, cover-or-next search over 50 lines."},
"v_at": {"n": "Handled by mini.ai's pattern-based tag textobject; same-name nested tags can mis-match."},
"v_it": {"n": "Handled by mini.ai's pattern-based tag textobject; same-name nested tags can mis-match."},
"v_aB": {"n": "Still Vim's built-in: mini.ai passes letters it doesn't define through."},
"v_iB": {"n": "Still Vim's built-in: mini.ai passes letters it doesn't define through."},
"s": {"n": "Disabled: <code>s</code> is mini.surround's prefix (<code>&lt;Nop&gt;</code>). Use <code>cl</code>."},
"v_s": {"n": "Disabled: <code>s</code> is mini.surround's prefix in Visual mode too. Use <code>c</code>."},
"S": {"n": "Now Leap from window (Normal mode). Use <code>cc</code>."},
"<CR>": {"n": "Now Leap (<code>&lt;Plug&gt;(leap)</code>) in Normal, Visual and Operator-pending mode. Use <code>+</code> or <code>j</code>."},
"g]": {"n": "Now mini.ai's <em>move to right edge of textobject</em>. Use <code>:tselect</code> or <code>g&lt;C-]&gt;</code>."},
"f": {"n": "Now flash.nvim: same line only, highlights matches, <kbd>f</kbd> again = next match."},
"F": {"n": "Now flash.nvim: same line only, highlights matches, <kbd>F</kbd> again = reverse."},
"t": {"n": "Now flash.nvim: same line only, highlights matches, <kbd>t</kbd> again = next match."},
"T": {"n": "Now flash.nvim: same line only, highlights matches, <kbd>T</kbd> again = reverse."},
";": {"n": "Now flash.nvim's repeat (same semantics)."},
",": {"n": "Now flash.nvim's reverse repeat (same semantics)."},
"zz": {"n": "focusline.nvim: puts the line 30% from the top instead of the centre."},
"CTRL-D": {"n": "focusline.nvim: scrolls, then puts the cursor line 30% from the top."},
"CTRL-U": {"n": "focusline.nvim: scrolls, then puts the cursor line 30% from the top."},
"[[": {"n": "Normal mode: Snacks words <em>previous LSP reference</em>; Markdown: previous heading."},
"]]": {"n": "Normal mode: Snacks words <em>next LSP reference</em>; Markdown: next heading."}
},
"notes": [
{"title": "f/t are Flash now", "kind": "change", "lead": "<kbd>f</kbd> <kbd>F</kbd> <kbd>t</kbd> <kbd>T</kbd> <kbd>;</kbd> <kbd>,</kbd> are flash.nvim's char mode, kept to the cursor line (<code>multi_line = false</code>) with no jump labels.", "rows": [["<kbd>f</kbd><kbd>x</kbd>", "Jump to the next <code>x</code>; every <code>x</code> on the line lights up and the rest dims"], ["<kbd>f</kbd> again", "While lit: next <code>x</code> without retyping it. <kbd>F</kbd> goes the other way"], ["<kbd>;</kbd> / <kbd>,</kbd>", "Repeat in the same / opposite direction, any time later"], ["<kbd>3</kbd><kbd>f</kbd><kbd>x</kbd>", "Counts work; no wrap, never leaves the line"], ["<kbd>`</kbd><kbd>`</kbd>", "Each Flash jump sets the <code>'</code> mark, so you can jump back (not <kbd>Ctrl-O</kbd>: same line)"], ["<kbd>Esc</kbd>", "Clears the highlights"]], "note": "After <code>Fx</code>, <kbd>F</kbd> again moves <em>right</em> (flash maps lowercase = next in the motion's direction, uppercase = previous).", "keys": ["f", "F", "t", "T", ";", ","]},
{"title": "Leap on Enter and S", "kind": "change", "lead": "<kbd>Enter</kbd> starts a Leap jump in the current window (Normal, Visual, Operator-pending); <kbd>S</kbd> leaps into another window.", "rows": [["<kbd>Enter</kbd><kbd>a</kbd><kbd>b</kbd>", "Jump to an <code>ab</code> pair; if the closest is unlabeled you're already there, else type its label"], ["<kbd>Enter</kbd><kbd>Enter</kbd>", "Repeat the previous Leap search"], ["<kbd>Enter</kbd><kbd>x</kbd><kbd>Enter</kbd>", "Jump to the closest <code>x</code>"], ["<kbd>Space</kbd> / <kbd>Backspace</kbd>", "Next / previous group of labels"], ["<kbd>x</kbd><kbd>Space</kbd>", "<code>x</code> before whitespace or at the end of a line; <kbd>Space</kbd><kbd>Space</kbd> targets line ends and empty lines"], ["<kbd>d</kbd><kbd>Enter</kbd><kbd>a</kbd><kbd>b</kbd>", "A motion for operators too (inclusive forward)"], ["Lost", "<kbd>Enter</kbd> = next line (use <kbd>+</kbd>/<kbd>j</kbd>); <kbd>S</kbd> = substitute line (use <kbd>cc</kbd>)"]], "note": "Brackets, quotes and whitespace match their whole class: <code>(</code> = <code>([{</code>, <code>'</code> = <code>'\"`</code>. Matching is case-sensitive ('ignorecase' is off). Buffer-local <kbd>Enter</kbd> maps (Snacks picker, explorer) still win over the Leap map.", "keys": ["<CR>", "S"]},
{"title": "Surround on s", "kind": "change", "lead": "mini.surround uses <kbd>s</kbd> as a prefix, so plain <kbd>s</kbd> does nothing in Normal, Visual and Operator-pending mode.", "rows": [["<kbd>sa</kbd>{motion}{char}", "Add: <code>saiw)</code> → <code>(word)</code>, <code>saiw(</code> → <code>( word )</code>"], ["<kbd>sd</kbd>{char}", "Delete: <code>sd\"</code>, <code>sdf</code> (keep args), <code>sdt</code> (keep content)"], ["<kbd>sr</kbd>{old}{new}", "Replace: <code>sr)]</code>, <code>sr'\"</code>, <code>srtt</code>"], ["<kbd>sf</kbd> / <kbd>sF</kbd> / <kbd>sh</kbd>", "Find right part / find left part / highlight"], ["<kbd>n</kbd> / <kbd>l</kbd> suffix", "Next / previous surrounding: <code>sdn)</code>, <code>srl\"'</code>"], ["Ids", "<code>( [ { &lt;</code> padded, <code>) ] } &gt;</code> tight, <code>b</code> brackets, <code>q</code> quotes, <code>t</code> tag, <code>f</code> call, <code>?</code> ask"], ["Lost", "<kbd>s</kbd> → use <kbd>cl</kbd>; Visual <kbd>s</kbd> → use <kbd>c</kbd>"]], "keys": ["s"]},
{"title": "Text objects (mini.ai)", "kind": "change", "lead": "<kbd>a</kbd>/<kbd>i</kbd> are mini.ai: they extend Vim's text objects, search forward when you're not inside one, and pass unknown letters (<code>w W s p B</code>) to Vim.", "rows": [["<kbd>if</kbd> / <kbd>af</kbd>", "Function call: arguments / whole call"], ["<kbd>ia</kbd> / <kbd>aa</kbd>", "Argument / argument plus its comma"], ["<kbd>iq</kbd> / <kbd>ib</kbd>", "Any quotes / any of <code>() [] {}</code>"], ["<kbd>it</kbd> / <kbd>i?</kbd>", "Tag content / custom edges (prompted)"], ["<kbd>ig</kbd>", "Whole buffer (custom, lua/plugins.lua)"], ["<kbd>i_</kbd> <kbd>i,</kbd> <kbd>i*</kbd> …", "Between any punctuation"], ["<kbd>iN(</kbd> / <kbd>il(</kbd>", "Next / previous one, e.g. <code>ciN\"</code> (capital N: <kbd>an</kbd>/<kbd>in</kbd> are Neovim's node selection)"], ["<kbd>g[</kbd> / <kbd>g]</kbd>", "Move to the start / end of <code>a{id}</code>"], ["<kbd>i(</kbd> vs <kbd>i)</kbd>", "Open bracket leaves out the inner edge spaces, close bracket includes them"]], "note": "Search: <code>cover_or_next</code> over 50 lines. <code>a\"</code> no longer grabs trailing whitespace.", "keys": ["a", "i"]},
{"title": "zz and half-page scrolls land at 30%", "kind": "change", "lead": "focusline.nvim re-targets these Normal-mode keys to put the cursor line 30% from the top of the window.", "rows": [["<kbd>zz</kbd>", "Line at 30%, not the centre (use <kbd>z.</kbd> to centre with the cursor at the first non-blank)"], ["<kbd>z,</kbd>", "New: same 30% placement"], ["<kbd>Ctrl-D</kbd> / <kbd>Ctrl-U</kbd>", "Half page down / up, then line at 30%"]], "keys": ["zz", "z,", "<C-D>", "<C-U>"]},
{"title": "Smart pairs", "kind": "change", "lead": "mini.pairs plus lua/smart_pairs.lua: an opener only auto-closes when nothing but whitespace, or a closing bracket, follows the cursor.", "rows": [["<kbd>(</kbd> before text", "Types just <code>(</code>, handy for wrapping existing text"], ["<kbd>'</kbd> after a letter", "Typed alone: <code>don't</code>; <code>\"\"</code> + <kbd>\"</kbd> gives <code>\"\"\"</code>"], ["<kbd>\\</kbd> then opener", "Never pairs after a backslash"], ["<kbd>)</kbd> <kbd>\"</kbd>", "Step over the closer that's already there"], ["<kbd>Backspace</kbd>", "Inside an empty pair deletes both"], ["<kbd>Enter</kbd>", "Between <code>()</code> <code>[]</code> <code>{}</code>: closer on its own line"]], "note": "Disable with <code>vim.g.minipairs_disable = true</code> (or <code>vim.b.</code> per buffer).", "keys": ["(", "[", "{", "\"", "'", "`"]},
{"title": "Markdown code fences", "kind": "tip", "lead": "In Markdown buffers, backticks and tildes build fenced code blocks for you.", "rows": [["<kbd>`</kbd><kbd>`</kbd><kbd>`</kbd> on a blank line", "Opener and closer, cursor after the opener: type the language"], ["more <kbd>`</kbd>", "Lengthens both fences (<code>````</code> to wrap a block that contains <code>```</code>)"], ["<kbd>Backspace</kbd>", "Shrinks both; below 3 the closer disappears"], ["<kbd>~</kbd><kbd>~</kbd><kbd>~</kbd>", "Same with tilde fences"]], "note": "Only opens a pair when the next line is blank, the buffer ends there, or it closes the block you're in.", "keys": ["`", "~"]},
{"title": "an / in select syntax nodes", "kind": "tip", "lead": "Neovim 0.12's incremental selection, free because mini.ai's \"next\" objects live on <kbd>aN</kbd>/<kbd>iN</kbd>.", "rows": [["<kbd>v</kbd> <kbd>an</kbd> <kbd>an</kbd>…", "Grow the selection to the enclosing node each time"], ["<kbd>in</kbd>", "Shrink back to a child node"], ["<kbd>]n</kbd> <kbd>[n</kbd>", "Select the next / previous node"], ["<kbd>]N</kbd> <kbd>[N</kbd>", "Extend over the next / previous sibling"]], "note": "Treesitter where a parser exists, otherwise LSP selection range (<code>:h v_an</code>). <code>lua/plugins.lua:424-429</code>", "keys": ["an", "in"]}
]
}
+561
View File
@@ -0,0 +1,561 @@
{
"entries": [
{"k": "<C-r><C-p>", "m": ["i"], "d": "Insert the full path of the file under the cursor", "s": "snacks", "cat": "Find & pick", "ctx": "Snacks picker · input"},
{"k": "<C-r><C-w>", "m": ["i"], "d": "Insert the word under the cursor (in the original buffer)", "s": "snacks", "cat": "Find & pick", "ctx": "Snacks picker · input"},
{"k": "j", "m": ["n"], "d": "Move to the next result", "s": "snacks", "cat": "Find & pick", "ctx": "Snacks picker · input"},
{"k": "<Down>", "m": ["n", "i"], "d": "Move to the next result", "s": "snacks", "cat": "Find & pick", "ctx": "Snacks picker · input"},
{"k": "<C-q>", "m": ["n", "i"], "d": "Send the selected items (or all results) to the quickfix list and open it", "s": "snacks", "cat": "Find & pick", "ctx": "Snacks picker · input", "e": 1, "sl": "→qf"},
{"k": "<Up>", "m": ["n", "i"], "d": "Move to the previous result", "s": "snacks", "cat": "Find & pick", "ctx": "Snacks picker · input"},
{"k": "/", "m": ["n"], "d": "Toggle focus between the input and the result list", "s": "snacks", "cat": "Find & pick", "ctx": "Snacks picker · input"},
{"k": "<CR>", "m": ["n", "i"], "d": "Open / jump to the item (or every selected item)", "s": "snacks", "cat": "Find & pick", "ctx": "Snacks picker · input", "n": "Runs the source's own confirm action: most open the file, some check out, apply or insert (see the per-picker entries).", "e": 1, "sl": "open"},
{"k": "<C-p>", "m": ["n", "i"], "d": "Move to the previous result", "s": "snacks", "cat": "Find & pick", "ctx": "Snacks picker · input"},
{"k": "<C-r>#", "m": ["i"], "d": "Insert the alternate file name (#) into the search", "s": "snacks", "cat": "Find & pick", "ctx": "Snacks picker · input"},
{"k": "<M-f>", "m": ["n", "i"], "d": "Toggle following symlinks (files / grep)", "s": "snacks", "cat": "Find & pick", "ctx": "Snacks picker · input", "n": "Toggle flags show as letters in the picker title: f follow, h hidden, i ignored, R regex."},
{"k": "<M-r>", "m": ["n", "i"], "d": "Toggle regex vs literal matching for the search", "s": "snacks", "cat": "Find & pick", "ctx": "Snacks picker · input", "n": "Toggle flags show as letters in the picker title: f follow, h hidden, i ignored, R regex."},
{"k": "<C-j>", "m": ["n", "i"], "d": "Move to the next result", "s": "snacks", "cat": "Find & pick", "ctx": "Snacks picker · input"},
{"k": "<M-s>", "m": ["n", "i"], "d": "Flash-jump: label every result and type a label to move there", "s": "config", "cat": "Find & pick", "ctx": "Snacks picker · input", "n": "Custom action in <code>lua/plugins.lua</code>: runs <code>flash.jump</code> with pattern <code>^</code> restricted to the list window, then moves the cursor to the picked row (it does not confirm).", "e": 1, "sl": "flash"},
{"k": "<M-h>", "m": ["n", "i"], "d": "Toggle showing hidden (dot) files", "s": "snacks", "cat": "Find & pick", "ctx": "Snacks picker · input", "n": "Toggle flags show as letters in the picker title: f follow, h hidden, i ignored, R regex.", "sl": "hidden"},
{"k": "<M-a>", "m": ["n", "i"], "d": "Send the selected items (or current) to the Sidekick AI CLI", "s": "config", "cat": "Find & pick", "ctx": "Snacks picker · input", "n": "Custom action in <code>lua/plugins.lua</code> calling <code>sidekick.cli.picker.snacks.send</code>: closes the picker and sends file/position references to the running AI CLI tool."},
{"k": "<C-w>H", "m": ["n"], "d": "Move the picker to a left sidebar layout", "s": "snacks", "cat": "Find & pick", "ctx": "Snacks picker · input", "n": "Split layouts disable auto-close and preview; the picker stays open after confirm."},
{"k": "<C-w>J", "m": ["n"], "d": "Move the picker to a bottom split layout", "s": "snacks", "cat": "Find & pick", "ctx": "Snacks picker · input", "n": "Split layouts disable auto-close and preview; the picker stays open after confirm."},
{"k": "<C-w>K", "m": ["n"], "d": "Move the picker to a top split layout", "s": "snacks", "cat": "Find & pick", "ctx": "Snacks picker · input", "n": "Split layouts disable auto-close and preview; the picker stays open after confirm."},
{"k": "<C-w>L", "m": ["n"], "d": "Move the picker to a right sidebar layout", "s": "snacks", "cat": "Find & pick", "ctx": "Snacks picker · input", "n": "Split layouts disable auto-close and preview; the picker stays open after confirm."},
{"k": "s", "m": ["n"], "d": "Flash-jump: label every result and type a label to move there", "s": "config", "cat": "Find & pick", "ctx": "Snacks picker · input", "n": "Custom action in <code>lua/plugins.lua</code>: runs <code>flash.jump</code> with pattern <code>^</code> restricted to the list window, then moves the cursor to the picked row (it does not confirm). Normal mode only and buffer-local, so it beats mini.surround's <kbd>s</kbd> prefix inside the picker.", "sl": "flash"},
{"k": "<M-d>", "m": ["n", "i"], "d": "Debug-inspect the item under the cursor (Snacks.debug)", "s": "snacks", "cat": "Find & pick", "ctx": "Snacks picker · input"},
{"k": "<C-u>", "m": ["n", "i"], "d": "Scroll the result list up half a page", "s": "snacks", "cat": "Find & pick", "ctx": "Snacks picker · input"},
{"k": "<M-p>", "m": ["n", "i"], "d": "Show / hide the preview window", "s": "snacks", "cat": "Find & pick", "ctx": "Snacks picker · input"},
{"k": "<C-t>", "m": ["n", "i"], "d": "Open the item in a new tab", "s": "snacks", "cat": "Find & pick", "ctx": "Snacks picker · input"},
{"k": "<C-c>", "m": ["i"], "d": "Close the picker and go back to the window it was opened from", "s": "snacks", "cat": "Find & pick", "ctx": "Snacks picker · input", "sl": "close"},
{"k": "<C-r><C-a>", "m": ["i"], "d": "Insert the WORD under the cursor (in the original buffer)", "s": "snacks", "cat": "Find & pick", "ctx": "Snacks picker · input"},
{"k": "<C-r><C-f>", "m": ["i"], "d": "Insert the file path under the cursor (<cfile>)", "s": "snacks", "cat": "Find & pick", "ctx": "Snacks picker · input"},
{"k": "<C-Down>", "m": ["n", "i"], "d": "Recall the next search from picker history", "s": "snacks", "cat": "Find & pick", "ctx": "Snacks picker · input"},
{"k": "<C-n>", "m": ["n", "i"], "d": "Move to the next result", "s": "snacks", "cat": "Find & pick", "ctx": "Snacks picker · input"},
{"k": "<C-Up>", "m": ["n", "i"], "d": "Recall the previous search from picker history", "s": "snacks", "cat": "Find & pick", "ctx": "Snacks picker · input"},
{"k": "<C-b>", "m": ["n", "i"], "d": "Scroll the preview window up", "s": "snacks", "cat": "Find & pick", "ctx": "Snacks picker · input"},
{"k": "?", "m": ["n"], "d": "Show the key help for the input window", "s": "snacks", "cat": "Find & pick", "ctx": "Snacks picker · input"},
{"k": "<C-g>", "m": ["n", "i"], "d": "Toggle live mode: re-run the search on every keystroke vs filter results", "s": "snacks", "cat": "Find & pick", "ctx": "Snacks picker · input", "n": "In the list window <kbd>Ctrl-g</kbd> prints the item path instead."},
{"k": "<C-w>", "m": ["i"], "d": "Delete the word before the cursor in the search input", "s": "snacks", "cat": "Find & pick", "ctx": "Snacks picker · input", "n": "Maps <code>&lt;C-w&gt;</code> to <code>&lt;C-S-w&gt;</code>, which works in the prompt buffer."},
{"k": "<C-f>", "m": ["n", "i"], "d": "Scroll the preview window down", "s": "snacks", "cat": "Find & pick", "ctx": "Snacks picker · input"},
{"k": "q", "m": ["n"], "d": "Close the picker and go back to the window it was opened from", "s": "snacks", "cat": "Find & pick", "ctx": "Snacks picker · input", "sl": "close"},
{"k": "<Tab>", "m": ["n", "i"], "d": "Toggle selection of the item and move down (multi-select)", "s": "snacks", "cat": "Find & pick", "ctx": "Snacks picker · input", "e": 1, "sl": "select"},
{"k": "<M-w>", "m": ["n", "i"], "d": "Cycle focus between the input, preview and list windows", "s": "snacks", "cat": "Find & pick", "ctx": "Snacks picker · input"},
{"k": "G", "m": ["n"], "d": "Jump to the last result", "s": "snacks", "cat": "Find & pick", "ctx": "Snacks picker · input"},
{"k": "<Esc>", "m": ["n"], "d": "Close the picker and go back to the window it was opened from", "s": "snacks", "cat": "Find & pick", "ctx": "Snacks picker · input", "sl": "close", "n": "Normal mode only: in insert mode the first <kbd>Esc</kbd> just leaves insert mode in the search box, the second closes the picker (or use <kbd>q</kbd> / insert-mode <kbd>Ctrl-c</kbd>)."},
{"k": "<C-d>", "m": ["n", "i"], "d": "Scroll the result list down half a page", "s": "snacks", "cat": "Find & pick", "ctx": "Snacks picker · input"},
{"k": "<S-Tab>", "m": ["n", "i"], "d": "Toggle selection of the item and move up (multi-select)", "s": "snacks", "cat": "Find & pick", "ctx": "Snacks picker · input"},
{"k": "k", "m": ["n"], "d": "Move to the previous result", "s": "snacks", "cat": "Find & pick", "ctx": "Snacks picker · input"},
{"k": "<S-CR>", "m": ["n", "i"], "d": "Pick a window with labels, then open the item there", "s": "snacks", "cat": "Find & pick", "ctx": "Snacks picker · input", "n": "<code>{ \"pick_win\", \"jump\" }</code>: the picker hides, every window gets a letter label; type it to open the item in that window."},
{"k": "<C-r>%", "m": ["i"], "d": "Insert the current file name (%)", "s": "snacks", "cat": "Find & pick", "ctx": "Snacks picker · input"},
{"k": "<C-s>", "m": ["n", "i"], "d": "Open the item in a horizontal split", "s": "snacks", "cat": "Find & pick", "ctx": "Snacks picker · input", "sl": "split"},
{"k": "<M-i>", "m": ["n", "i"], "d": "Toggle showing git-ignored files", "s": "snacks", "cat": "Find & pick", "ctx": "Snacks picker · input", "n": "Toggle flags show as letters in the picker title: f follow, h hidden, i ignored, R regex.", "sl": "ignored"},
{"k": "<M-m>", "m": ["n", "i"], "d": "Maximize / restore the picker layout", "s": "snacks", "cat": "Find & pick", "ctx": "Snacks picker · input"},
{"k": "<C-a>", "m": ["n", "i"], "d": "Select every result, or clear the selection if all are selected", "s": "snacks", "cat": "Find & pick", "ctx": "Snacks picker · input"},
{"k": "<C-v>", "m": ["n", "i"], "d": "Open the item in a vertical split", "s": "snacks", "cat": "Find & pick", "ctx": "Snacks picker · input", "sl": "vsplit"},
{"k": "<C-k>", "m": ["n", "i"], "d": "Move to the previous result", "s": "snacks", "cat": "Find & pick", "ctx": "Snacks picker · input"},
{"k": "gg", "m": ["n"], "d": "Jump to the first result", "s": "snacks", "cat": "Find & pick", "ctx": "Snacks picker · input"},
{"k": "<C-r><C-l>", "m": ["i"], "d": "Insert the current line of the original buffer", "s": "snacks", "cat": "Find & pick", "ctx": "Snacks picker · input"},
{"k": "<C-t>", "m": ["n"], "d": "Open the item in a new tab", "s": "snacks", "cat": "Find & pick", "ctx": "Snacks picker · list"},
{"k": "j", "m": ["n"], "d": "Move to the next result", "s": "snacks", "cat": "Find & pick", "ctx": "Snacks picker · list"},
{"k": "<Down>", "m": ["n"], "d": "Move to the next result", "s": "snacks", "cat": "Find & pick", "ctx": "Snacks picker · list"},
{"k": "<C-q>", "m": ["n"], "d": "Send the selected items (or all results) to the quickfix list and open it", "s": "snacks", "cat": "Find & pick", "ctx": "Snacks picker · list", "sl": "→qf"},
{"k": "<Up>", "m": ["n"], "d": "Move to the previous result", "s": "snacks", "cat": "Find & pick", "ctx": "Snacks picker · list"},
{"k": "/", "m": ["n"], "d": "Toggle focus between the input and the result list", "s": "snacks", "cat": "Find & pick", "ctx": "Snacks picker · list"},
{"k": "<Esc>", "m": ["n"], "d": "Close the picker and go back to the window it was opened from", "s": "snacks", "cat": "Find & pick", "ctx": "Snacks picker · list", "sl": "close"},
{"k": "gg", "m": ["n"], "d": "Jump to the first result", "s": "snacks", "cat": "Find & pick", "ctx": "Snacks picker · list"},
{"k": "zb", "m": ["n"], "d": "Scroll the list so the current item is at the bottom", "s": "snacks", "cat": "Find & pick", "ctx": "Snacks picker · list"},
{"k": "<C-v>", "m": ["n"], "d": "Open the item in a vertical split", "s": "snacks", "cat": "Find & pick", "ctx": "Snacks picker · list", "sl": "vsplit"},
{"k": "<M-h>", "m": ["n"], "d": "Toggle showing hidden (dot) files", "s": "snacks", "cat": "Find & pick", "ctx": "Snacks picker · list", "n": "Toggle flags show as letters in the picker title: f follow, h hidden, i ignored, R regex.", "sl": "hidden"},
{"k": "<C-w>H", "m": ["n"], "d": "Move the picker to a left sidebar layout", "s": "snacks", "cat": "Find & pick", "ctx": "Snacks picker · list", "n": "Split layouts disable auto-close and preview; the picker stays open after confirm."},
{"k": "<C-w>J", "m": ["n"], "d": "Move the picker to a bottom split layout", "s": "snacks", "cat": "Find & pick", "ctx": "Snacks picker · list", "n": "Split layouts disable auto-close and preview; the picker stays open after confirm."},
{"k": "<C-b>", "m": ["n"], "d": "Scroll the preview window up", "s": "snacks", "cat": "Find & pick", "ctx": "Snacks picker · list"},
{"k": "<C-w>L", "m": ["n"], "d": "Move the picker to a right sidebar layout", "s": "snacks", "cat": "Find & pick", "ctx": "Snacks picker · list", "n": "Split layouts disable auto-close and preview; the picker stays open after confirm."},
{"k": "<2-LeftMouse>", "m": ["n"], "d": "Open / jump to the item (or every selected item)", "s": "snacks", "cat": "Find & pick", "ctx": "Snacks picker · list", "n": "Runs the source's own confirm action: most open the file, some check out, apply or insert (see the per-picker entries).", "sl": "open"},
{"k": "<M-d>", "m": ["n"], "d": "Debug-inspect the item under the cursor (Snacks.debug)", "s": "snacks", "cat": "Find & pick", "ctx": "Snacks picker · list"},
{"k": "<M-p>", "m": ["n"], "d": "Show / hide the preview window", "s": "snacks", "cat": "Find & pick", "ctx": "Snacks picker · list"},
{"k": "i", "m": ["n"], "d": "Focus the search input", "s": "snacks", "cat": "Find & pick", "ctx": "Snacks picker · list"},
{"k": "<C-u>", "m": ["n"], "d": "Scroll the result list up half a page", "s": "snacks", "cat": "Find & pick", "ctx": "Snacks picker · list"},
{"k": "<C-d>", "m": ["n"], "d": "Scroll the result list down half a page", "s": "snacks", "cat": "Find & pick", "ctx": "Snacks picker · list"},
{"k": "<C-n>", "m": ["n"], "d": "Move to the next result", "s": "snacks", "cat": "Find & pick", "ctx": "Snacks picker · list"},
{"k": "<C-p>", "m": ["n"], "d": "Move to the previous result", "s": "snacks", "cat": "Find & pick", "ctx": "Snacks picker · list"},
{"k": "<C-g>", "m": ["n"], "d": "Print the path of the item under the cursor", "s": "snacks", "cat": "Find & pick", "ctx": "Snacks picker · list"},
{"k": "<C-j>", "m": ["n"], "d": "Move to the next result", "s": "snacks", "cat": "Find & pick", "ctx": "Snacks picker · list"},
{"k": "<C-f>", "m": ["n"], "d": "Scroll the preview window down", "s": "snacks", "cat": "Find & pick", "ctx": "Snacks picker · list"},
{"k": "<S-CR>", "m": ["n"], "d": "Pick a window with labels, then open the item there", "s": "snacks", "cat": "Find & pick", "ctx": "Snacks picker · list", "n": "<code>{ \"pick_win\", \"jump\" }</code>: the picker hides, every window gets a letter label; type it to open the item in that window."},
{"k": "<Tab>", "m": ["n", "x"], "d": "Toggle selection of the item and move down (multi-select)", "s": "snacks", "cat": "Find & pick", "ctx": "Snacks picker · list", "sl": "select"},
{"k": "?", "m": ["n"], "d": "Show the key help for the list window", "s": "snacks", "cat": "Find & pick", "ctx": "Snacks picker · list"},
{"k": "k", "m": ["n"], "d": "Move to the previous result", "s": "snacks", "cat": "Find & pick", "ctx": "Snacks picker · list"},
{"k": "<M-m>", "m": ["n"], "d": "Maximize / restore the picker layout", "s": "snacks", "cat": "Find & pick", "ctx": "Snacks picker · list"},
{"k": "<M-f>", "m": ["n"], "d": "Toggle following symlinks (files / grep)", "s": "snacks", "cat": "Find & pick", "ctx": "Snacks picker · list", "n": "Toggle flags show as letters in the picker title: f follow, h hidden, i ignored, R regex."},
{"k": "<C-w>K", "m": ["n"], "d": "Move the picker to a top split layout", "s": "snacks", "cat": "Find & pick", "ctx": "Snacks picker · list", "n": "Split layouts disable auto-close and preview; the picker stays open after confirm."},
{"k": "<C-s>", "m": ["n"], "d": "Open the item in a horizontal split", "s": "snacks", "cat": "Find & pick", "ctx": "Snacks picker · list", "sl": "split"},
{"k": "<S-Tab>", "m": ["n", "x"], "d": "Toggle selection of the item and move up (multi-select)", "s": "snacks", "cat": "Find & pick", "ctx": "Snacks picker · list"},
{"k": "zt", "m": ["n"], "d": "Scroll the list so the current item is at the top", "s": "snacks", "cat": "Find & pick", "ctx": "Snacks picker · list"},
{"k": "<M-w>", "m": ["n"], "d": "Cycle focus between the input, preview and list windows", "s": "snacks", "cat": "Find & pick", "ctx": "Snacks picker · list"},
{"k": "zz", "m": ["n"], "d": "Scroll the list so the current item is centred", "s": "snacks", "cat": "Find & pick", "ctx": "Snacks picker · list"},
{"k": "G", "m": ["n"], "d": "Jump to the last result", "s": "snacks", "cat": "Find & pick", "ctx": "Snacks picker · list"},
{"k": "<C-a>", "m": ["n"], "d": "Select every result, or clear the selection if all are selected", "s": "snacks", "cat": "Find & pick", "ctx": "Snacks picker · list"},
{"k": "<M-i>", "m": ["n"], "d": "Toggle showing git-ignored files", "s": "snacks", "cat": "Find & pick", "ctx": "Snacks picker · list", "n": "Toggle flags show as letters in the picker title: f follow, h hidden, i ignored, R regex.", "sl": "ignored"},
{"k": "<C-k>", "m": ["n"], "d": "Move to the previous result", "s": "snacks", "cat": "Find & pick", "ctx": "Snacks picker · list"},
{"k": "q", "m": ["n"], "d": "Close the picker and go back to the window it was opened from", "s": "snacks", "cat": "Find & pick", "ctx": "Snacks picker · list", "sl": "close"},
{"k": "<CR>", "m": ["n"], "d": "Open / jump to the item (or every selected item)", "s": "snacks", "cat": "Find & pick", "ctx": "Snacks picker · list", "n": "Runs the source's own confirm action: most open the file, some check out, apply or insert (see the per-picker entries).", "sl": "open"},
{"k": "<Esc>", "m": ["n"], "d": "Close the picker and go back to the window it was opened from", "s": "snacks", "cat": "Find & pick", "ctx": "Snacks picker · preview", "sl": "close"},
{"k": "<M-w>", "m": ["n"], "d": "Cycle focus between the input, preview and list windows", "s": "snacks", "cat": "Find & pick", "ctx": "Snacks picker · preview"},
{"k": "q", "m": ["n"], "d": "Close the picker and go back to the window it was opened from", "s": "snacks", "cat": "Find & pick", "ctx": "Snacks picker · preview", "sl": "close"},
{"k": "i", "m": ["n"], "d": "Focus the search input", "s": "snacks", "cat": "Find & pick", "ctx": "Snacks picker · preview"},
{"k": "<C-x>", "m": ["n", "i"], "d": "Delete (unload) the buffer under the cursor or the selected buffers", "s": "snacks", "cat": "Find & pick", "ctx": "Snacks picker · buffers", "n": "Opened with <kbd><leader>, / <leader>fb</kbd>."},
{"k": "dd", "m": ["n"], "d": "Delete the buffer (list window)", "s": "snacks", "cat": "Find & pick", "ctx": "Snacks picker · buffers", "n": "Opened with <kbd><leader>, / <leader>fb</kbd>."},
{"k": "<Tab>", "m": ["n", "i"], "d": "Stage / unstage the file (replaces multi-select here)", "s": "snacks", "cat": "Git", "ctx": "Snacks picker · git_status", "n": "Opened with <kbd><leader>gs</kbd>. Runs <code>git add</code> or <code>git restore --staged</code>."},
{"k": "<C-r>", "m": ["n", "i"], "d": "Restore (discard) the file's changes after a confirm prompt", "s": "snacks", "cat": "Git", "ctx": "Snacks picker · git_status", "n": "Opened with <kbd><leader>gs</kbd>. Runs <code>git restore</code>; irreversible for unstaged edits."},
{"k": "<Tab>", "m": ["n", "i"], "d": "Stage / unstage the hunk under the cursor", "s": "snacks", "cat": "Git", "ctx": "Snacks picker · git_diff", "n": "Opened with <kbd><leader>gd</kbd>. Uses <code>git apply --cached</code> (or <code>--reverse</code>)."},
{"k": "<C-r>", "m": ["n", "i"], "d": "Discard the hunk after a confirm prompt", "s": "snacks", "cat": "Git", "ctx": "Snacks picker · git_diff", "n": "Opened with <kbd><leader>gd</kbd>."},
{"k": "<CR>", "m": ["n", "i"], "d": "Check out the branch (remote branches get a local tracking branch)", "s": "snacks", "cat": "Git", "ctx": "Snacks picker · git_branches", "n": "Opened with <kbd><leader>gb</kbd>."},
{"k": "<C-a>", "m": ["n", "i"], "d": "Create and check out a new branch (name prompt prefilled with the search text)", "s": "snacks", "cat": "Git", "ctx": "Snacks picker · git_branches", "n": "Opened with <kbd><leader>gb</kbd>."},
{"k": "<C-x>", "m": ["n", "i"], "d": "Force-delete the branch (git branch -D) after a confirm prompt", "s": "snacks", "cat": "Git", "ctx": "Snacks picker · git_branches", "n": "Opened with <kbd><leader>gb</kbd>."},
{"k": "<CR>", "m": ["n", "i"], "d": "Check out the commit: puts the repo in detached HEAD", "s": "snacks", "cat": "Git", "ctx": "Snacks picker · git_log", "n": "Opened with <kbd><leader>gl</kbd>. The source's confirm is <code>git_checkout</code>, so Enter on a commit really runs <code>git checkout &lt;sha&gt;</code>. Use <kbd>Esc</kbd> to just browse."},
{"k": "<CR>", "m": ["n", "i"], "d": "Restore this file to the chosen commit's version (overwrites it)", "s": "snacks", "cat": "Git", "ctx": "Snacks picker · git_log_file / git_log_line", "n": "Opened with <kbd><leader>gf</kbd> (file history) or <kbd><leader>gL</kbd> (line history). Confirm is <code>git_checkout</code> with the file attached: <code>git checkout &lt;sha&gt; -- &lt;file&gt;</code> replaces the working copy."},
{"k": "<CR>", "m": ["n", "i"], "d": "Apply the stash (git stash apply)", "s": "snacks", "cat": "Git", "ctx": "Snacks picker · git_stash", "n": "Opened with <kbd><leader>gS</kbd>."},
{"k": "<CR>", "m": ["n", "i"], "d": "cd to the project and try to restore its session, else open files", "s": "snacks", "cat": "Find & pick", "ctx": "Snacks picker · projects", "n": "Opened with <kbd><leader>fp</kbd>. Session restore uses the dashboard's plugin detection, which only works with lazy.nvim, so here it just changes directory and opens the files picker after 100 ms."},
{"k": "<C-e>", "m": ["n", "i"], "d": "tcd to the project and open the explorer there", "s": "snacks", "cat": "Find & pick", "ctx": "Snacks picker · projects", "n": "Opened with <kbd><leader>fp</kbd>."},
{"k": "<C-f>", "m": ["n", "i"], "d": "tcd to the project and find files there", "s": "snacks", "cat": "Find & pick", "ctx": "Snacks picker · projects", "n": "Opened with <kbd><leader>fp</kbd>."},
{"k": "<C-g>", "m": ["n", "i"], "d": "tcd to the project and grep there", "s": "snacks", "cat": "Find & pick", "ctx": "Snacks picker · projects", "n": "Opened with <kbd><leader>fp</kbd>."},
{"k": "<C-r>", "m": ["n", "i"], "d": "tcd to the project and list its recent files", "s": "snacks", "cat": "Find & pick", "ctx": "Snacks picker · projects", "n": "Opened with <kbd><leader>fp</kbd>."},
{"k": "<C-w>", "m": ["n", "i"], "d": "Just tcd to the project (tab-local cwd)", "s": "snacks", "cat": "Find & pick", "ctx": "Snacks picker · projects", "n": "Opened with <kbd><leader>fp</kbd>."},
{"k": "<C-t>", "m": ["n", "i"], "d": "Open a new tab and pick a project for it", "s": "snacks", "cat": "Find & pick", "ctx": "Snacks picker · projects", "n": "Opened with <kbd><leader>fp</kbd>."},
{"k": "<CR>", "m": ["n", "i"], "d": "Restore the buffer to the chosen undo state", "s": "snacks", "cat": "Find & pick", "ctx": "Snacks picker · undo", "n": "Opened with <kbd><leader>su</kbd>."},
{"k": "<C-y>", "m": ["n", "i"], "d": "Yank the lines added in that undo state", "s": "snacks", "cat": "Find & pick", "ctx": "Snacks picker · undo", "n": "Opened with <kbd><leader>su</kbd>."},
{"k": "<C-S-y>", "m": ["n", "i"], "d": "Yank the lines removed in that undo state", "s": "snacks", "cat": "Find & pick", "ctx": "Snacks picker · undo", "n": "Opened with <kbd><leader>su</kbd>."},
{"k": "<C-x>", "m": ["n", "i"], "d": "Delete the mark under the cursor", "s": "snacks", "cat": "Find & pick", "ctx": "Snacks picker · marks", "n": "Opened with <kbd><leader>sm</kbd>."},
{"k": "<CR>", "m": ["n", "i"], "d": "Copy the register's contents to the default register (the clipboard here) and close", "s": "snacks", "cat": "Find & pick", "ctx": "Snacks picker · registers", "n": "Opened with <kbd><leader>s\"</kbd>. Uses <code>v:register</code>, which is <code>+</code> with <code>clipboard=unnamedplus</code>."},
{"k": "<CR>", "m": ["n", "i"], "d": "Put the command on the command line (edit, then Enter to run)", "s": "snacks", "cat": "Find & pick", "ctx": "Snacks picker · command_history", "n": "Opened with <kbd><leader>: / <leader>sc</kbd>."},
{"k": "<CR>", "m": ["n", "i"], "d": "Put the command on the command line", "s": "snacks", "cat": "Find & pick", "ctx": "Snacks picker · commands", "n": "Opened with <kbd><leader>sC</kbd>."},
{"k": "<CR>", "m": ["n", "i"], "d": "Start a / search pre-filled with that pattern", "s": "snacks", "cat": "Find & pick", "ctx": "Snacks picker · search_history", "n": "Opened with <kbd><leader>s/</kbd>."},
{"k": "<CR>", "m": ["n", "i"], "d": "Insert the icon at the cursor", "s": "snacks", "cat": "Find & pick", "ctx": "Snacks picker · icons", "n": "Opened with <kbd><leader>si</kbd>."},
{"k": "<CR>", "m": ["n", "i"], "d": "Apply the colorscheme (moving through the list previews it live)", "s": "snacks", "cat": "Find & pick", "ctx": "Snacks picker · colorschemes", "n": "Opened with <kbd><leader>uC</kbd>."},
{"k": "<CR>", "m": ["n", "i"], "d": "Open the help page; <C-v> vertical, <C-t> tab", "s": "snacks", "cat": "Find & pick", "ctx": "Snacks picker · help", "n": "Opened with <kbd><leader>sh</kbd>."},
{"k": "<CR>", "m": ["n", "i"], "d": "Close the picker and run the chosen keymap", "s": "snacks", "cat": "Find & pick", "ctx": "Snacks picker · keymaps", "n": "Opened with <kbd><leader>sk</kbd>. Feeds the mapping's lhs with <code>nvim_input</code>, so it runs as if typed."},
{"k": "<M-g>", "m": ["n", "i"], "d": "Toggle including global keymaps", "s": "snacks", "cat": "Find & pick", "ctx": "Snacks picker · keymaps", "n": "Opened with <kbd><leader>sk</kbd>."},
{"k": "<M-b>", "m": ["n", "i"], "d": "Toggle including buffer-local keymaps", "s": "snacks", "cat": "Find & pick", "ctx": "Snacks picker · keymaps", "n": "Opened with <kbd><leader>sk</kbd>."},
{"k": "<CR>", "m": ["n", "i"], "d": "Open the GitHub actions menu for the issue / PR", "s": "snacks", "cat": "Git", "ctx": "Snacks picker · gh_issue / gh_pr", "n": "Opened with <kbd><leader>gi / gI / gp / gP</kbd>."},
{"k": "<M-b>", "m": ["n", "i"], "d": "Open the issue / PR in the browser", "s": "snacks", "cat": "Git", "ctx": "Snacks picker · gh_issue / gh_pr", "n": "Opened with <kbd><leader>gi / gI / gp / gP</kbd>."},
{"k": "<C-y>", "m": ["n", "i"], "d": "Yank the issue / PR URL", "s": "snacks", "cat": "Git", "ctx": "Snacks picker · gh_issue / gh_pr", "n": "Opened with <kbd><leader>gi / gI / gp / gP</kbd>."},
{"k": "y", "m": ["n", "x"], "d": "Yank the URL(s) of the item(s) (list window)", "s": "snacks", "cat": "Git", "ctx": "Snacks picker · gh_issue / gh_pr", "n": "Opened with <kbd><leader>gi / gI / gp / gP</kbd>."},
{"k": "<CR>", "m": ["n", "i"], "d": "Open the PR in a tea:// buffer (c checkout, d diff, A approve, a comment, x close)", "s": "snacks-tea", "cat": "Git", "ctx": "Snacks picker · tea_pr", "n": "Opened with <kbd><leader>gt / gT</kbd>. This snacks-tea version registers its picker config only when <code>Snacks.picker.config.defaults</code> exists, which this snacks lacks, so it falls back to a bare picker: Enter is the default jump and the <kbd>Alt-b</kbd> / <kbd>Ctrl-y</kbd> / <kbd>y</kbd> keys are not mapped (verified headless)."},
{"k": "<CR>", "m": ["n", "i"], "d": "Open the scratch buffer", "s": "snacks", "cat": "Find & pick", "ctx": "Snacks picker · scratch", "n": "Opened with <kbd><leader>S</kbd>."},
{"k": "<C-n>", "m": ["n", "i"], "d": "Open the default scratch buffer for the current filetype (created if missing)", "s": "snacks", "cat": "Find & pick", "ctx": "Snacks picker · scratch", "n": "Opened with <kbd><leader>S</kbd>. Runs <code>Snacks.scratch.open()</code>, the same buffer <kbd><leader>.</kbd> toggles; it does not make an extra one."},
{"k": "<C-x>", "m": ["n", "i"], "d": "Delete the scratch file", "s": "snacks", "cat": "Find & pick", "ctx": "Snacks picker · scratch", "n": "Opened with <kbd><leader>S</kbd>."},
{"k": "<CR>", "m": ["n", "i"], "d": "Jump to the location; LSP pickers jump directly when there is only one result", "s": "snacks", "cat": "Find & pick", "ctx": "Snacks picker · lsp_* / smart / files / grep", "n": "Opened with <kbd>gd gr gI gy gai gao, <leader><space> …</kbd>. <code>auto_confirm</code> is on for lsp_definitions, references, implementations, type/declarations and call hierarchy."},
{"k": "<C-x>", "m": ["n", "i"], "d": "Create a new note named from the search text", "s": "obsidian.nvim", "cat": "Notes", "ctx": "Snacks picker · Obsidian notes", "n": "In <code>:Obsidian quick_switch</code> / <code>search</code> pickers (snacks backend). <kbd>Ctrl-b</kbd> here replaces snacks' preview scroll-up."},
{"k": "<C-l>", "m": ["n", "i"], "d": "Insert a [[link]] to the chosen note at the cursor", "s": "obsidian.nvim", "cat": "Notes", "ctx": "Snacks picker · Obsidian notes", "n": "In <code>:Obsidian quick_switch</code> / <code>search</code> pickers (snacks backend). <kbd>Ctrl-b</kbd> here replaces snacks' preview scroll-up."},
{"k": "<C-b>", "m": ["n", "i"], "d": "Bookmark the chosen note", "s": "obsidian.nvim", "cat": "Notes", "ctx": "Snacks picker · Obsidian notes", "n": "In <code>:Obsidian quick_switch</code> / <code>search</code> pickers (snacks backend). <kbd>Ctrl-b</kbd> here replaces snacks' preview scroll-up."},
{"k": "<C-x>", "m": ["n", "i"], "d": "Add the chosen tag(s) to the current note", "s": "obsidian.nvim", "cat": "Notes", "ctx": "Snacks picker · Obsidian tags", "n": "In the <code>:Obsidian tags</code> picker."},
{"k": "<C-l>", "m": ["n", "i"], "d": "Insert the chosen tag at the cursor", "s": "obsidian.nvim", "cat": "Notes", "ctx": "Snacks picker · Obsidian tags", "n": "In the <code>:Obsidian tags</code> picker."},
{"k": "<CR>", "m": ["n", "i"], "d": "Jump to the bookmark", "s": "haunt", "cat": "Mark & jump", "ctx": "Snacks picker · Haunt bookmarks", "n": "Opened with <kbd>Space h l</kbd> (picker = \"snacks\" in <code>lua/plugins.lua</code>)."},
{"k": "d", "m": ["n"], "d": "Delete the bookmark under the cursor", "s": "haunt", "cat": "Mark & jump", "ctx": "Snacks picker · Haunt bookmarks", "n": "Normal mode in both the input and list windows (default <code>picker_keys.delete</code>)."},
{"k": "a", "m": ["n"], "d": "Edit the bookmark's annotation", "s": "haunt", "cat": "Mark & jump", "ctx": "Snacks picker · Haunt bookmarks", "n": "Normal mode in both the input and list windows (default <code>picker_keys.edit_annotation</code>)."},
{"k": "<C-t>", "m": ["n"], "d": "Open a terminal in the directory under the cursor", "s": "snacks", "cat": "Files", "ctx": "Snacks explorer", "n": "Replaces the picker's usual <kbd>Ctrl-t</kbd> (open in tab)."},
{"k": "j", "m": ["n"], "d": "Move to the next result", "s": "snacks", "cat": "Files", "ctx": "Snacks explorer"},
{"k": "<Down>", "m": ["n"], "d": "Move to the next result", "s": "snacks", "cat": "Files", "ctx": "Snacks explorer"},
{"k": "<C-q>", "m": ["n"], "d": "Send the selected items (or all results) to the quickfix list and open it", "s": "snacks", "cat": "Files", "ctx": "Snacks explorer"},
{"k": "<Up>", "m": ["n"], "d": "Move to the previous result", "s": "snacks", "cat": "Files", "ctx": "Snacks explorer"},
{"k": "o", "m": ["n"], "d": "Open the file with the system default application", "s": "snacks", "cat": "Files", "ctx": "Snacks explorer"},
{"k": "<Esc>", "m": ["n"], "d": "Close the picker and go back to the window it was opened from", "s": "snacks", "cat": "Files", "ctx": "Snacks explorer"},
{"k": "r", "m": ["n"], "d": "Rename the file (LSP-aware: updates imports via Snacks.rename)", "s": "snacks", "cat": "Files", "ctx": "Snacks explorer", "e": 1, "sl": "rename"},
{"k": "zb", "m": ["n"], "d": "Scroll the list so the current item is at the bottom", "s": "snacks", "cat": "Files", "ctx": "Snacks explorer"},
{"k": "k", "m": ["n"], "d": "Move to the previous result", "s": "snacks", "cat": "Files", "ctx": "Snacks explorer"},
{"k": "P", "m": ["n"], "d": "Toggle the preview window", "s": "snacks", "cat": "Files", "ctx": "Snacks explorer"},
{"k": "I", "m": ["n"], "d": "Toggle showing git-ignored files", "s": "snacks", "cat": "Files", "ctx": "Snacks explorer"},
{"k": "i", "m": ["n"], "d": "Focus the search input", "s": "snacks", "cat": "Files", "ctx": "Snacks explorer"},
{"k": "zt", "m": ["n"], "d": "Scroll the list so the current item is at the top", "s": "snacks", "cat": "Files", "ctx": "Snacks explorer"},
{"k": "a", "m": ["n"], "d": "Create a file or directory (end the name with / for a directory)", "s": "snacks", "cat": "Files", "ctx": "Snacks explorer", "n": "Missing parent directories are created.", "e": 1, "sl": "new"},
{"k": "<C-n>", "m": ["n"], "d": "Move to the next result", "s": "snacks", "cat": "Files", "ctx": "Snacks explorer"},
{"k": "Z", "m": ["n"], "d": "Collapse every directory", "s": "snacks", "cat": "Files", "ctx": "Snacks explorer"},
{"k": "<C-g>", "m": ["n"], "d": "Print the path of the item under the cursor", "s": "snacks", "cat": "Files", "ctx": "Snacks explorer"},
{"k": "<C-f>", "m": ["n"], "d": "Scroll the preview window down", "s": "snacks", "cat": "Files", "ctx": "Snacks explorer"},
{"k": "<S-Tab>", "m": ["n", "x"], "d": "Toggle selection of the item and move up (multi-select)", "s": "snacks", "cat": "Files", "ctx": "Snacks explorer"},
{"k": "<Tab>", "m": ["n", "x"], "d": "Toggle selection of the item and move down (multi-select)", "s": "snacks", "cat": "Files", "ctx": "Snacks explorer"},
{"k": "]g", "m": ["n"], "d": "Jump to the next file with git changes", "s": "snacks", "cat": "Files", "ctx": "Snacks explorer"},
{"k": "[g", "m": ["n"], "d": "Jump to the previous file with git changes", "s": "snacks", "cat": "Files", "ctx": "Snacks explorer"},
{"k": "<C-a>", "m": ["n"], "d": "Select every result, or clear the selection if all are selected", "s": "snacks", "cat": "Files", "ctx": "Snacks explorer"},
{"k": "]d", "m": ["n"], "d": "Jump to the next file with diagnostics", "s": "snacks", "cat": "Files", "ctx": "Snacks explorer"},
{"k": "<C-c>", "m": ["n"], "d": "Set the tab-local working directory to the directory under the cursor", "s": "snacks", "cat": "Files", "ctx": "Snacks explorer"},
{"k": "[d", "m": ["n"], "d": "Jump to the previous file with diagnostics", "s": "snacks", "cat": "Files", "ctx": "Snacks explorer"},
{"k": "]w", "m": ["n"], "d": "Jump to the next file with warnings", "s": "snacks", "cat": "Files", "ctx": "Snacks explorer"},
{"k": "c", "m": ["n"], "d": "Copy the selection into this directory, or copy the file to a new name", "s": "snacks", "cat": "Files", "ctx": "Snacks explorer"},
{"k": "]e", "m": ["n"], "d": "Jump to the next file with errors", "s": "snacks", "cat": "Files", "ctx": "Snacks explorer"},
{"k": "?", "m": ["n"], "d": "Show the key help for the list window", "s": "snacks", "cat": "Files", "ctx": "Snacks explorer"},
{"k": "[e", "m": ["n"], "d": "Jump to the previous file with errors", "s": "snacks", "cat": "Files", "ctx": "Snacks explorer"},
{"k": "/", "m": ["n"], "d": "Toggle focus between the input and the result list", "s": "snacks", "cat": "Files", "ctx": "Snacks explorer"},
{"k": "gg", "m": ["n"], "d": "Jump to the first result", "s": "snacks", "cat": "Files", "ctx": "Snacks explorer"},
{"k": "h", "m": ["n"], "d": "Collapse the directory (or the parent of a file)", "s": "snacks", "cat": "Files", "ctx": "Snacks explorer"},
{"k": "<M-f>", "m": ["n"], "d": "Toggle following symlinks (files / grep)", "s": "snacks", "cat": "Files", "ctx": "Snacks explorer", "n": "Toggle flags show as letters in the picker title: f follow, h hidden, i ignored, R regex."},
{"k": "<C-v>", "m": ["n"], "d": "Open the item in a vertical split", "s": "snacks", "cat": "Files", "ctx": "Snacks explorer"},
{"k": "<M-h>", "m": ["n"], "d": "Toggle showing hidden (dot) files", "s": "snacks", "cat": "Files", "ctx": "Snacks explorer"},
{"k": "u", "m": ["n"], "d": "Refresh the tree from disk", "s": "snacks", "cat": "Files", "ctx": "Snacks explorer"},
{"k": "<C-w>J", "m": ["n"], "d": "Move the picker to a bottom split layout", "s": "snacks", "cat": "Files", "ctx": "Snacks explorer", "n": "Split layouts disable auto-close and preview; the picker stays open after confirm."},
{"k": "<C-w>K", "m": ["n"], "d": "Move the picker to a top split layout", "s": "snacks", "cat": "Files", "ctx": "Snacks explorer", "n": "Split layouts disable auto-close and preview; the picker stays open after confirm."},
{"k": "<M-m>", "m": ["n"], "d": "Maximize / restore the picker layout", "s": "snacks", "cat": "Files", "ctx": "Snacks explorer"},
{"k": "<2-LeftMouse>", "m": ["n"], "d": "Open the file, or expand / collapse the directory", "s": "snacks", "cat": "Files", "ctx": "Snacks explorer"},
{"k": "<M-d>", "m": ["n"], "d": "Debug-inspect the item under the cursor (Snacks.debug)", "s": "snacks", "cat": "Files", "ctx": "Snacks explorer"},
{"k": "<M-p>", "m": ["n"], "d": "Toggle the preview window", "s": "snacks", "cat": "Files", "ctx": "Snacks explorer"},
{"k": "<C-u>", "m": ["n"], "d": "Scroll the result list up half a page", "s": "snacks", "cat": "Files", "ctx": "Snacks explorer"},
{"k": "<C-d>", "m": ["n"], "d": "Scroll the result list down half a page", "s": "snacks", "cat": "Files", "ctx": "Snacks explorer"},
{"k": "<leader>/", "m": ["n"], "d": "Grep inside the directory under the cursor", "s": "snacks", "cat": "Files", "ctx": "Snacks explorer", "n": "Buffer-local <code>&lt;leader&gt;/</code>, shadowing the global Grep map while the explorer list has focus."},
{"k": "H", "m": ["n"], "d": "Toggle showing hidden (dot) files", "s": "snacks", "cat": "Files", "ctx": "Snacks explorer"},
{"k": "<C-w>H", "m": ["n"], "d": "Move the picker to a left sidebar layout", "s": "snacks", "cat": "Files", "ctx": "Snacks explorer", "n": "Split layouts disable auto-close and preview; the picker stays open after confirm."},
{"k": "l", "m": ["n"], "d": "Open the file, or expand / collapse the directory", "s": "snacks", "cat": "Files", "ctx": "Snacks explorer"},
{"k": "<BS>", "m": ["n"], "d": "Go up: make the parent directory the explorer root", "s": "snacks", "cat": "Files", "ctx": "Snacks explorer"},
{"k": ".", "m": ["n"], "d": "Make the directory under the cursor the explorer root", "s": "snacks", "cat": "Files", "ctx": "Snacks explorer"},
{"k": "q", "m": ["n"], "d": "Close the picker and go back to the window it was opened from", "s": "snacks", "cat": "Files", "ctx": "Snacks explorer"},
{"k": "<CR>", "m": ["n"], "d": "Open the file, or expand / collapse the directory", "s": "snacks", "cat": "Files", "ctx": "Snacks explorer", "e": 1},
{"k": "<C-k>", "m": ["n"], "d": "Move to the previous result", "s": "snacks", "cat": "Files", "ctx": "Snacks explorer"},
{"k": "<M-i>", "m": ["n"], "d": "Toggle showing git-ignored files", "s": "snacks", "cat": "Files", "ctx": "Snacks explorer"},
{"k": "y", "m": ["n", "x"], "d": "Yank the path(s) of the file(s) to the clipboard", "s": "snacks", "cat": "Files", "ctx": "Snacks explorer", "n": "Uses <code>v:register</code>, which is <code>+</code> with <code>clipboard=unnamedplus</code>."},
{"k": "G", "m": ["n"], "d": "Jump to the last result", "s": "snacks", "cat": "Files", "ctx": "Snacks explorer"},
{"k": "p", "m": ["n"], "d": "Paste (copy) files whose paths are in the clipboard into this directory", "s": "snacks", "cat": "Files", "ctx": "Snacks explorer"},
{"k": "zz", "m": ["n"], "d": "Scroll the list so the current item is centred", "s": "snacks", "cat": "Files", "ctx": "Snacks explorer"},
{"k": "m", "m": ["n"], "d": "Move the selected files into this directory (renames if nothing selected)", "s": "snacks", "cat": "Files", "ctx": "Snacks explorer"},
{"k": "<M-w>", "m": ["n"], "d": "Cycle focus between the input, preview and list windows", "s": "snacks", "cat": "Files", "ctx": "Snacks explorer"},
{"k": "<C-s>", "m": ["n"], "d": "Open the item in a horizontal split", "s": "snacks", "cat": "Files", "ctx": "Snacks explorer"},
{"k": "<S-CR>", "m": ["n"], "d": "Pick a window with labels, then open the item there", "s": "snacks", "cat": "Files", "ctx": "Snacks explorer", "n": "<code>{ \"pick_win\", \"jump\" }</code>: the picker hides, every window gets a letter label; type it to open the item in that window."},
{"k": "<C-p>", "m": ["n"], "d": "Move to the previous result", "s": "snacks", "cat": "Files", "ctx": "Snacks explorer"},
{"k": "<C-w>L", "m": ["n"], "d": "Move the picker to a right sidebar layout", "s": "snacks", "cat": "Files", "ctx": "Snacks explorer", "n": "Split layouts disable auto-close and preview; the picker stays open after confirm."},
{"k": "<C-j>", "m": ["n"], "d": "Move to the next result", "s": "snacks", "cat": "Files", "ctx": "Snacks explorer"},
{"k": "<C-b>", "m": ["n"], "d": "Scroll the preview window up", "s": "snacks", "cat": "Files", "ctx": "Snacks explorer"},
{"k": "d", "m": ["n"], "d": "Delete the file(s) after a confirm prompt (to the system trash)", "s": "snacks", "cat": "Files", "ctx": "Snacks explorer", "n": "Trash is on by default and <code>trash</code>, <code>gio</code> and <code>kioclient</code> are installed here, so deletes are recoverable. Works on the multi-selection.", "e": 1, "sl": "delete"},
{"k": "[w", "m": ["n"], "d": "Jump to the previous file with warnings", "s": "snacks", "cat": "Files", "ctx": "Snacks explorer"},
{"k": "f", "m": ["n"], "d": "Find file (Snacks files picker)", "s": "snacks", "cat": "UI & toggles", "ctx": "Snacks dashboard"},
{"k": "n", "m": ["n"], "d": "New empty buffer in insert mode (:ene | startinsert)", "s": "snacks", "cat": "UI & toggles", "ctx": "Snacks dashboard"},
{"k": "g", "m": ["n"], "d": "Find text (Snacks grep picker)", "s": "snacks", "cat": "UI & toggles", "ctx": "Snacks dashboard"},
{"k": "r", "m": ["n"], "d": "Recent files (Snacks recent picker)", "s": "snacks", "cat": "UI & toggles", "ctx": "Snacks dashboard"},
{"k": "c", "m": ["n"], "d": "Find a file in the Neovim config (stdpath('config'))", "s": "snacks", "cat": "UI & toggles", "ctx": "Snacks dashboard"},
{"k": "q", "m": ["n"], "d": "Quit Neovim (:qa)", "s": "snacks", "cat": "UI & toggles", "ctx": "Snacks dashboard", "n": "The item key overrides the dashboard's own <kbd>q</kbd> = <code>:bd</code>."},
{"k": "<CR>", "m": ["n"], "d": "Run the item under the cursor", "s": "snacks", "cat": "UI & toggles", "ctx": "Snacks dashboard", "n": "There is no <kbd>s</kbd> (Restore Session) or <kbd>L</kbd> (Lazy) item: Snacks detects session plugins only under lazy.nvim, so under <code>vim.pack</code> persistence is not found. Use <kbd>Space q s</kbd> / <kbd>Space q l</kbd> instead."},
{"k": "q", "m": ["n"], "d": "Close the scratch window (the buffer is saved automatically)", "s": "snacks", "cat": "Buffer & tab", "ctx": "Snacks scratch window", "n": "Scratch files live in <code>stdpath('data')/scratch</code>, keyed by name, filetype, count, cwd and git branch, and are written when hidden. <kbd>{count} Space .</kbd> opens scratch number {count}."},
{"k": "<CR>", "m": ["n", "x"], "d": "Run the Lua scratch buffer (or the selection) and show results inline", "s": "snacks", "cat": "Buffer & tab", "ctx": "Snacks scratch window", "n": "Only in Lua scratch buffers (<code>win_by_ft.lua</code>), via <code>Snacks.debug.run</code>."},
{"k": "<leader>z", "m": ["n"], "d": "Leave zen mode (zen windows do not map q)", "s": "snacks", "cat": "UI & toggles", "ctx": "Snacks zen / zoom", "n": "Zen opens the buffer in a centred 120-col float with dimming and git signs hidden; <kbd>Space Z</kbd> is the zoom variant (full width, keeps statusline/tabline). Run the same key again, or <code>:close</code>, to restore."},
{"k": "q", "m": ["n"], "d": "Close the notification history window", "s": "snacks", "cat": "UI & toggles", "ctx": "Snacks notification history", "n": "<kbd>Space n</kbd> opens <code>Snacks.notifier.show_history()</code> (the second of two <kbd>Space n</kbd> maps in <code>lua/keymaps.lua</code>, so it wins over the notifications picker)."},
{"k": "<CR>", "m": ["i", "n"], "d": "Confirm the input (or accept the completion item)", "s": "snacks", "cat": "UI & toggles", "ctx": "Snacks input (vim.ui.input prompts)", "n": "Used by rename (<kbd>Space c R</kbd>), explorer add/rename/copy and any plugin calling <code>vim.ui.input</code>."},
{"k": "<Esc>", "m": ["i"], "d": "Close completion, else leave insert mode in the prompt", "s": "snacks", "cat": "UI & toggles", "ctx": "Snacks input (vim.ui.input prompts)", "n": "Used by rename (<kbd>Space c R</kbd>), explorer add/rename/copy and any plugin calling <code>vim.ui.input</code>."},
{"k": "<Esc>", "m": ["n"], "d": "Cancel the prompt", "s": "snacks", "cat": "UI & toggles", "ctx": "Snacks input (vim.ui.input prompts)", "n": "Used by rename (<kbd>Space c R</kbd>), explorer add/rename/copy and any plugin calling <code>vim.ui.input</code>."},
{"k": "q", "m": ["n"], "d": "Cancel the prompt", "s": "snacks", "cat": "UI & toggles", "ctx": "Snacks input (vim.ui.input prompts)", "n": "Used by rename (<kbd>Space c R</kbd>), explorer add/rename/copy and any plugin calling <code>vim.ui.input</code>."},
{"k": "<Up>", "m": ["i", "n"], "d": "Previous entry from the input history", "s": "snacks", "cat": "UI & toggles", "ctx": "Snacks input (vim.ui.input prompts)", "n": "Used by rename (<kbd>Space c R</kbd>), explorer add/rename/copy and any plugin calling <code>vim.ui.input</code>."},
{"k": "<Down>", "m": ["i", "n"], "d": "Next entry from the input history", "s": "snacks", "cat": "UI & toggles", "ctx": "Snacks input (vim.ui.input prompts)", "n": "Used by rename (<kbd>Space c R</kbd>), explorer add/rename/copy and any plugin calling <code>vim.ui.input</code>."},
{"k": "<Tab>", "m": ["i"], "d": "Trigger / cycle completion (when the prompt supports it)", "s": "snacks", "cat": "UI & toggles", "ctx": "Snacks input (vim.ui.input prompts)", "n": "Used by rename (<kbd>Space c R</kbd>), explorer add/rename/copy and any plugin calling <code>vim.ui.input</code>."},
{"k": "<C-w>", "m": ["i"], "d": "Delete the word before the cursor", "s": "snacks", "cat": "UI & toggles", "ctx": "Snacks input (vim.ui.input prompts)", "n": "Used by rename (<kbd>Space c R</kbd>), explorer add/rename/copy and any plugin calling <code>vim.ui.input</code>."},
{"k": "<CR>", "m": ["n"], "d": "Open the actions menu for the issue / PR", "s": "snacks", "cat": "Git", "ctx": "GitHub / Forgejo PR buffer"},
{"k": "i", "m": ["n"], "d": "Edit the issue / PR (GitHub)", "s": "snacks", "cat": "Git", "ctx": "GitHub / Forgejo PR buffer"},
{"k": "a", "m": ["n"], "d": "Add a comment", "s": "snacks", "cat": "Git", "ctx": "GitHub / Forgejo PR buffer"},
{"k": "c", "m": ["n"], "d": "Close the issue / PR (GitHub) — or check out the PR (Forgejo)", "s": "snacks", "cat": "Git", "ctx": "GitHub / Forgejo PR buffer", "n": "In snacks-tea (Forgejo/Gitea) buffers <kbd>c</kbd> is checkout and <kbd>x</kbd> closes."},
{"k": "o", "m": ["n"], "d": "Reopen the issue / PR", "s": "snacks", "cat": "Git", "ctx": "GitHub / Forgejo PR buffer"},
{"k": "d", "m": ["n"], "d": "View the PR diff (Forgejo)", "s": "snacks-tea", "cat": "Git", "ctx": "GitHub / Forgejo PR buffer"},
{"k": "A", "m": ["n"], "d": "Approve the PR (Forgejo)", "s": "snacks-tea", "cat": "Git", "ctx": "GitHub / Forgejo PR buffer"},
{"k": "x", "m": ["n"], "d": "Close the PR (Forgejo)", "s": "snacks-tea", "cat": "Git", "ctx": "GitHub / Forgejo PR buffer"},
{"k": "r", "m": ["n"], "d": "Refresh the PR buffer (Forgejo)", "s": "snacks-tea", "cat": "Git", "ctx": "GitHub / Forgejo PR buffer"},
{"k": "<C-s>", "m": ["n", "i"], "d": "Submit the comment / review being written", "s": "snacks-tea", "cat": "Git", "ctx": "Forgejo comment window", "n": "The comment scratch window also has <kbd>Alt-w</kbd> cycle, <kbd>Ctrl-b</kbd>/<kbd>Ctrl-f</kbd> preview scroll."},
{"k": "a", "m": ["n", "x"], "d": "Comment on the diff line(s) under the cursor (preview window)", "s": "snacks", "cat": "Git", "ctx": "Snacks picker · gh_diff", "n": "GitHub PR diff picker (<code>snacks.gh</code>). snacks-tea's Forgejo diff picker maps the same keys to actions it never defines, so they do nothing there."},
{"k": "<CR>", "m": ["n", "x"], "d": "Open the actions menu for the diff line(s) (preview window)", "s": "snacks", "cat": "Git", "ctx": "Snacks picker · gh_diff", "n": "GitHub PR diff picker (<code>snacks.gh</code>). snacks-tea's Forgejo diff picker maps the same keys to actions it never defines, so they do nothing there."},
{"k": "<C-Space>", "m": ["i"], "d": "Open the completion menu; again: show docs, again: hide docs", "s": "blink.cmp", "cat": "Completion & AI", "ctx": "Completion menu (insert)", "n": "Never falls back, so <kbd>Ctrl-Space</kbd> always goes to blink in insert mode.", "e": 1, "sl": "complete"},
{"k": "<C-y>", "m": ["i"], "d": "Accept the selected item (the first one if none is selected)", "s": "blink.cmp", "cat": "Completion & AI", "ctx": "Completion menu (insert)", "n": "Falls back to <kbd>Ctrl-y</kbd> (insert the character above) when the menu is closed.", "e": 1, "sl": "accept"},
{"k": "<C-e>", "m": ["i"], "d": "Close the menu and undo the previewed insert", "s": "blink.cmp", "cat": "Completion & AI", "ctx": "Completion menu (insert)", "n": "Falls back to <kbd>Ctrl-e</kbd> (insert the character below) when the menu is closed.", "e": 1, "sl": "dismiss"},
{"k": "<C-n>", "m": ["i"], "d": "Select the next item; with the menu closed, open it on the first item", "s": "blink.cmp", "cat": "Completion & AI", "ctx": "Completion menu (insert)", "n": "Configured in <code>lua/plugins.lua</code>: <code>{ \"select_next\", \"show_and_insert\" }</code>. <kbd>Ctrl-p</kbd> mirrors it (opens on the last item). Built-in keyword completion is still on <kbd>Ctrl-x Ctrl-n</kbd>"},
{"k": "<C-p>", "m": ["i"], "d": "Select the previous item", "s": "blink.cmp", "cat": "Completion & AI", "ctx": "Completion menu (insert)", "n": "Same as <kbd>Ctrl-n</kbd>: no fallback to built-in completion."},
{"k": "<Down>", "m": ["i"], "d": "Select the next item", "s": "blink.cmp", "cat": "Completion & AI", "ctx": "Completion menu (insert)", "n": "With the menu closed it falls back to this config's insert <kbd>Down</kbd> (move by display line, <code>lua/keymaps.lua</code>)."},
{"k": "<Up>", "m": ["i"], "d": "Select the previous item", "s": "blink.cmp", "cat": "Completion & AI", "ctx": "Completion menu (insert)", "n": "With the menu closed it falls back to this config's insert <kbd>Up</kbd> (move by display line)."},
{"k": "<C-f>", "m": ["i"], "d": "Scroll the documentation window down", "s": "blink.cmp", "cat": "Completion & AI", "ctx": "Completion menu (insert)", "n": "Falls back to <kbd>Ctrl-f</kbd> when no docs window is open."},
{"k": "<C-b>", "m": ["i"], "d": "Scroll the documentation window up", "s": "blink.cmp", "cat": "Completion & AI", "ctx": "Completion menu (insert)", "n": "Falls back to <kbd>Ctrl-b</kbd> when no docs window is open."},
{"k": "<Tab>", "m": ["i", "s"], "d": "Next snippet field → apply AI next edit → accept ghost text → Tab", "s": "config", "cat": "Completion & AI", "ctx": "Completion menu (insert)", "n": "Custom chain in <code>lua/plugins.lua</code>: 1) <code>snippet_forward</code> if a snippet is active; 2) <code>sidekick.nes_jump_or_apply()</code> (jump to, then apply, a Copilot next-edit suggestion; suggestions are cleared on insert, so rarely fires here); 3) <code>vim.lsp.inline_completion.get()</code> accepts native LSP ghost text (Copilot); 4) a literal Tab. <kbd>Tab</kbd> does <em>not</em> accept the blink menu; use <kbd>Ctrl-y</kbd>.", "e": 1, "sl": "tab chain"},
{"k": "<S-Tab>", "m": ["i", "s"], "d": "Jump to the previous snippet field", "s": "blink.cmp", "cat": "Completion & AI", "ctx": "Completion menu (insert)", "n": "Falls back to <kbd>Shift-Tab</kbd>."},
{"k": "<Tab>", "m": ["c"], "d": "Show the menu and insert the first match (accepts if it's the only one); then next", "s": "blink.cmp", "cat": "Completion & AI", "ctx": "Completion menu (cmdline)", "n": "Ghost text previews the top match; the menu does not open by itself on <code>:</code> (only in the cmdline window)."},
{"k": "<S-Tab>", "m": ["c"], "d": "Show the menu and insert the last match; then previous item", "s": "blink.cmp", "cat": "Completion & AI", "ctx": "Completion menu (cmdline)"},
{"k": "<C-Space>", "m": ["c"], "d": "Open the completion menu", "s": "blink.cmp", "cat": "Completion & AI", "ctx": "Completion menu (cmdline)"},
{"k": "<C-n>", "m": ["c"], "d": "Select the next item", "s": "blink.cmp", "cat": "Completion & AI", "ctx": "Completion menu (cmdline)", "n": "With the menu closed it falls back to <kbd>Ctrl-n</kbd>: next completion match after <kbd>Tab</kbd>, otherwise the next (newer) command-line from history."},
{"k": "<C-p>", "m": ["c"], "d": "Select the previous item", "s": "blink.cmp", "cat": "Completion & AI", "ctx": "Completion menu (cmdline)", "n": "With the menu closed it falls back to <kbd>Ctrl-p</kbd>: previous completion match, otherwise the previous (older) command-line from history."},
{"k": "<Right>", "m": ["c"], "d": "Select the next item while the menu is open", "s": "blink.cmp", "cat": "Completion & AI", "ctx": "Completion menu (cmdline)", "n": "Arrow keys only move the cursor when the menu is closed."},
{"k": "<Left>", "m": ["c"], "d": "Select the previous item while the menu is open", "s": "blink.cmp", "cat": "Completion & AI", "ctx": "Completion menu (cmdline)", "n": "Arrow keys only move the cursor when the menu is closed."},
{"k": "<C-y>", "m": ["c"], "d": "Accept the selected item", "s": "blink.cmp", "cat": "Completion & AI", "ctx": "Completion menu (cmdline)"},
{"k": "<C-e>", "m": ["c"], "d": "Close the menu and undo the preview", "s": "blink.cmp", "cat": "Completion & AI", "ctx": "Completion menu (cmdline)", "n": "Falls back to <kbd>Ctrl-e</kbd> (cursor to end of line)."},
{"k": "<End>", "m": ["c"], "d": "Hide the menu", "s": "blink.cmp", "cat": "Completion & AI", "ctx": "Completion menu (cmdline)", "n": "Falls back to <kbd>End</kbd>."},
{"k": "<C-n> / <C-p> / <C-Space>", "m": ["t"], "d": "blink's terminal-mode keys: usually NOT active here", "s": "blink.cmp", "cat": "Completion & AI", "ctx": "Completion (terminal)", "n": "blink enables terminal mode by default and inherits the insert keymap (minus snippet keys), but has no terminal sources and installs the maps only on a direct <code>n→t</code> mode change. Snacks terminals go <code>n→nt→t</code>, so in testing no blink maps were set and keys reached the shell. If they ever do get installed, <kbd>Ctrl-n</kbd>/<kbd>Ctrl-p</kbd>/<kbd>Ctrl-Space</kbd> are swallowed (verified by forcing them)."},
{"k": "Copilot items", "m": ["i"], "d": "Copilot suggestions also appear as blink menu items (kind Copilot, ranked first)", "s": "blink-copilot", "cat": "Completion & AI", "ctx": "Completion menu (insert)", "n": "Source <code>copilot</code> via blink-copilot: up to 3 completions, <code>score_offset = 100</code>. Sources order: lsp, path, snippets, buffer, copilot. Accept like any item with <kbd>Ctrl-y</kbd>."},
{"k": "ghost text", "m": ["i"], "d": "Native LSP inline completion (Copilot ghost text) is enabled", "s": "config", "cat": "Completion & AI", "ctx": "Completion menu (insert)", "n": "<code>vim.lsp.inline_completion.enable()</code> in <code>lua/plugins.lua</code>. Accept with <kbd>Tab</kbd> (3rd step of the chain); there is no key to cycle alternatives (<code>vim.lsp.inline_completion.select()</code> is unmapped)."},
{"k": "<Tab>", "m": ["n"], "d": "Jump to the pending next-edit suggestion; press again to apply it", "s": "config", "cat": "Completion & AI", "ctx": "Sidekick NES (Copilot next edit)", "n": "<code>lua/keymaps.lua</code> maps normal <kbd>Tab</kbd> to <code>sidekick.nes_jump_or_apply()</code>; with no suggestion it falls back to jump forward. <kbd>Ctrl-i</kbd> is mapped separately for terminals that can tell the two apart", "e": 1, "sl": "NES"},
{"k": "<Esc>", "m": ["n", "i"], "d": "Dismiss the current next-edit suggestion", "s": "sidekick", "cat": "Completion & AI", "ctx": "Sidekick NES (Copilot next edit)", "n": "Not a mapping: a <code>vim.on_key</code> watcher clears suggestions whenever <kbd>Esc</kbd> is typed (<code>nes.clear.esc = true</code>). Suggestions refresh on leaving insert mode and on text changes."},
{"k": "<C-b>", "m": ["n", "t"], "d": "Pick buffers to send to the AI tool", "s": "sidekick", "cat": "Completion & AI", "ctx": "Sidekick AI CLI terminal", "n": "Defaults from <code>sidekick/config.lua</code> (CLI window opens on the right, 80 cols). No key opens it in this config: use <code>:Sidekick cli toggle</code>."},
{"k": "<C-f>", "m": ["n", "t"], "d": "Pick files to send to the AI tool", "s": "sidekick", "cat": "Completion & AI", "ctx": "Sidekick AI CLI terminal", "n": "Defaults from <code>sidekick/config.lua</code> (CLI window opens on the right, 80 cols). No key opens it in this config: use <code>:Sidekick cli toggle</code>."},
{"k": "<C-p>", "m": ["t"], "d": "Insert a prompt or context (incl. this config's haunt_all / haunt_buffer)", "s": "sidekick", "cat": "Completion & AI", "ctx": "Sidekick AI CLI terminal", "n": "Defaults from <code>sidekick/config.lua</code>. This config maps no key to open the CLI; use <code>:Sidekick cli toggle</code> / <code>select</code>. Custom prompts <code>haunt_all</code> and <code>haunt_buffer</code> send Haunt bookmarks."},
{"k": "<C-.>", "m": ["n", "t"], "d": "Hide the CLI window", "s": "sidekick", "cat": "Completion & AI", "ctx": "Sidekick AI CLI terminal", "n": "Defaults from <code>sidekick/config.lua</code> (CLI window opens on the right, 80 cols). No key opens it in this config: use <code>:Sidekick cli toggle</code>."},
{"k": "<C-z>", "m": ["n", "t"], "d": "Go back to the previous window, keeping the CLI open", "s": "sidekick", "cat": "Completion & AI", "ctx": "Sidekick AI CLI terminal", "n": "Defaults from <code>sidekick/config.lua</code> (CLI window opens on the right, 80 cols). No key opens it in this config: use <code>:Sidekick cli toggle</code>."},
{"k": "<C-q>", "m": ["t"], "d": "Leave terminal mode (normal mode in the CLI)", "s": "sidekick", "cat": "Completion & AI", "ctx": "Sidekick AI CLI terminal", "n": "Defaults from <code>sidekick/config.lua</code> (CLI window opens on the right, 80 cols). No key opens it in this config: use <code>:Sidekick cli toggle</code>."},
{"k": "<C-q>", "m": ["n"], "d": "Hide the CLI window", "s": "sidekick", "cat": "Completion & AI", "ctx": "Sidekick AI CLI terminal", "n": "Defaults from <code>sidekick/config.lua</code> (CLI window opens on the right, 80 cols). No key opens it in this config: use <code>:Sidekick cli toggle</code>."},
{"k": "q", "m": ["n"], "d": "Hide the CLI window", "s": "sidekick", "cat": "Completion & AI", "ctx": "Sidekick AI CLI terminal", "n": "Defaults from <code>sidekick/config.lua</code> (CLI window opens on the right, 80 cols). No key opens it in this config: use <code>:Sidekick cli toggle</code>."},
{"k": "<CR>", "m": ["n"], "d": "Send Enter to the tool and go back to terminal mode", "s": "sidekick", "cat": "Completion & AI", "ctx": "Sidekick AI CLI terminal", "n": "Defaults from <code>sidekick/config.lua</code> (CLI window opens on the right, 80 cols). No key opens it in this config: use <code>:Sidekick cli toggle</code>."},
{"k": "<C-h>", "m": ["t"], "d": "Move to the window on the left (split layouts only)", "s": "sidekick", "cat": "Completion & AI", "ctx": "Sidekick AI CLI terminal", "n": "Defaults from <code>sidekick/config.lua</code> (CLI window opens on the right, 80 cols). No key opens it in this config: use <code>:Sidekick cli toggle</code>."},
{"k": "<BS>", "m": ["n", "x", "o"], "d": "Go back up one level in the key tree", "s": "which-key", "cat": "Help", "ctx": "which-key popup", "e": 1},
{"k": "<Esc>", "m": ["n", "x", "o"], "d": "Close the popup (and cancel the pending keys)", "s": "which-key", "cat": "Help", "ctx": "which-key popup"},
{"k": "<C-d>", "m": ["n", "x", "o"], "d": "Scroll the popup down", "s": "which-key", "cat": "Help", "ctx": "which-key popup"},
{"k": "<C-u>", "m": ["n", "x", "o"], "d": "Scroll the popup up", "s": "which-key", "cat": "Help", "ctx": "which-key popup"},
{"k": "{key}", "m": ["n", "x", "o"], "d": "Continue the key sequence / run the mapping shown next to it", "s": "which-key", "cat": "Help", "ctx": "which-key popup", "n": "The popup appears 200 ms after a prefix such as <kbd>Space</kbd>, <kbd>g</kbd>, <kbd>z</kbd>, <kbd>]</kbd> (0 ms for its plugin popups). Groups show with <code>+</code>."},
{"k": "\"", "m": ["n", "x"], "d": "Popup listing every register with its contents; type the register name", "s": "which-key", "cat": "Register & macro", "ctx": "which-key popup", "n": "which-key's <code>registers</code> plugin; the popup appears immediately."},
{"k": "<C-r>", "m": ["i", "c"], "d": "Popup listing registers before inserting one", "s": "which-key", "cat": "Register & macro", "ctx": "which-key popup", "n": "Verified as a buffer-local <code>which-key-trigger registers</code> map in insert mode."},
{"k": "' ` g' g`", "m": ["n"], "d": "Popup listing marks with their line/file; type the mark name", "s": "which-key", "cat": "Mark & jump", "ctx": "which-key popup", "n": "which-key's <code>marks</code> plugin (normal mode only; its triggers are not installed in Visual or Operator-pending mode)."},
{"k": "z=", "m": ["n"], "d": "Spelling suggestions popup: press 1-9, 0, a-z… to replace the word", "s": "which-key", "cat": "Spell", "ctx": "which-key popup", "n": "Shows 20 suggestions for the bad word under the cursor. With a count (<kbd>2z=</kbd>) Vim's own behaviour runs."},
{"k": "<localleader>r", "m": ["n"], "d": "Replace: apply the replacement to every match", "s": "grug-far", "cat": "Search", "ctx": "Grug-far", "n": "Local leader is <kbd>\\</kbd>, so e.g. <kbd>\\ r</kbd>.", "e": 1},
{"k": "<localleader>s", "m": ["n"], "d": "Sync all: write your edits of result lines back to the files", "s": "grug-far", "cat": "Search", "ctx": "Grug-far", "n": "Edit the result lines like normal text, then sync. Local leader is <kbd>\\</kbd>, so e.g. <kbd>\\ r</kbd>."},
{"k": "<localleader>l", "m": ["n"], "d": "Sync the result line under the cursor", "s": "grug-far", "cat": "Search", "ctx": "Grug-far", "n": "Local leader is <kbd>\\</kbd>, so e.g. <kbd>\\ r</kbd>."},
{"k": "<localleader>n", "m": ["n"], "d": "Sync the result line under the cursor, then move to the next match", "s": "grug-far", "cat": "Search", "ctx": "Grug-far", "n": "Local leader is <kbd>\\</kbd>, so e.g. <kbd>\\ r</kbd>."},
{"k": "<localleader>p", "m": ["n"], "d": "Sync the result line under the cursor, then move to the previous match", "s": "grug-far", "cat": "Search", "ctx": "Grug-far", "n": "Local leader is <kbd>\\</kbd>, so e.g. <kbd>\\ r</kbd>."},
{"k": "<localleader>v", "m": ["n"], "d": "Sync all changes in the current file", "s": "grug-far", "cat": "Search", "ctx": "Grug-far", "n": "Local leader is <kbd>\\</kbd>, so e.g. <kbd>\\ r</kbd>."},
{"k": "<localleader>j", "m": ["n"], "d": "Apply the change on this line, drop it from the list, open the next one", "s": "grug-far", "cat": "Search", "ctx": "Grug-far", "n": "Local leader is <kbd>\\</kbd>, so e.g. <kbd>\\ r</kbd>."},
{"k": "<localleader>k", "m": ["n"], "d": "Apply the change on this line, drop it from the list, open the previous one", "s": "grug-far", "cat": "Search", "ctx": "Grug-far", "n": "Local leader is <kbd>\\</kbd>, so e.g. <kbd>\\ r</kbd>."},
{"k": "<localleader>q", "m": ["n"], "d": "Send the results to the quickfix list", "s": "grug-far", "cat": "Search", "ctx": "Grug-far", "n": "Local leader is <kbd>\\</kbd>, so e.g. <kbd>\\ r</kbd>."},
{"k": "<localleader>t", "m": ["n"], "d": "Open search history (Enter picks an entry)", "s": "grug-far", "cat": "Search", "ctx": "Grug-far", "n": "Local leader is <kbd>\\</kbd>, so e.g. <kbd>\\ r</kbd>."},
{"k": "<localleader>a", "m": ["n"], "d": "Add the current search to history", "s": "grug-far", "cat": "Search", "ctx": "Grug-far", "n": "Local leader is <kbd>\\</kbd>, so e.g. <kbd>\\ r</kbd>."},
{"k": "<localleader>f", "m": ["n"], "d": "Refresh (re-run the search)", "s": "grug-far", "cat": "Search", "ctx": "Grug-far", "n": "Local leader is <kbd>\\</kbd>, so e.g. <kbd>\\ r</kbd>."},
{"k": "<localleader>o", "m": ["n"], "d": "Open the match location (cursor stays in Grug-far)", "s": "grug-far", "cat": "Search", "ctx": "Grug-far", "n": "Local leader is <kbd>\\</kbd>, so e.g. <kbd>\\ r</kbd>."},
{"k": "<localleader>i", "m": ["n"], "d": "Preview the match location in a float", "s": "grug-far", "cat": "Search", "ctx": "Grug-far", "n": "Local leader is <kbd>\\</kbd>, so e.g. <kbd>\\ r</kbd>."},
{"k": "<localleader>b", "m": ["n"], "d": "Abort the running search / replace", "s": "grug-far", "cat": "Search", "ctx": "Grug-far", "n": "Local leader is <kbd>\\</kbd>, so e.g. <kbd>\\ r</kbd>."},
{"k": "<localleader>c", "m": ["n"], "d": "Close Grug-far", "s": "grug-far", "cat": "Search", "ctx": "Grug-far", "n": "Local leader is <kbd>\\</kbd>, so e.g. <kbd>\\ r</kbd>."},
{"k": "<localleader>w", "m": ["n"], "d": "Toggle showing the underlying search command (rg / ast-grep)", "s": "grug-far", "cat": "Search", "ctx": "Grug-far", "n": "Local leader is <kbd>\\</kbd>, so e.g. <kbd>\\ r</kbd>."},
{"k": "<localleader>e", "m": ["n"], "d": "Cycle the search engine (ripgrep → astgrep → astgrep-rules)", "s": "grug-far", "cat": "Search", "ctx": "Grug-far", "n": "Local leader is <kbd>\\</kbd>, so e.g. <kbd>\\ r</kbd>."},
{"k": "<localleader>x", "m": ["n"], "d": "Cycle the replacement interpreter (default → lua → vimscript)", "s": "grug-far", "cat": "Search", "ctx": "Grug-far", "n": "Local leader is <kbd>\\</kbd>, so e.g. <kbd>\\ r</kbd>."},
{"k": "<CR>", "m": ["n"], "d": "Go to the match location (in the other window)", "s": "grug-far", "cat": "Search", "ctx": "Grug-far", "n": "In the history buffer <kbd>Enter</kbd> picks the history entry."},
{"k": "<Down>", "m": ["n"], "d": "Open the next match location", "s": "grug-far", "cat": "Search", "ctx": "Grug-far"},
{"k": "<Up>", "m": ["n"], "d": "Open the previous match location", "s": "grug-far", "cat": "Search", "ctx": "Grug-far"},
{"k": "<Tab>", "m": ["n"], "d": "Jump to the next input field (Search, Replace, Files filter, Flags, Paths)", "s": "grug-far", "cat": "Search", "ctx": "Grug-far"},
{"k": "<S-Tab>", "m": ["n"], "d": "Jump to the previous input field", "s": "grug-far", "cat": "Search", "ctx": "Grug-far"},
{"k": "g?", "m": ["n"], "d": "Show Grug-far help", "s": "grug-far", "cat": "Search", "ctx": "Grug-far"},
{"k": "<CR>", "m": ["n"], "d": "Restore the buffer to the undo state under the cursor", "s": "undotree", "cat": "Undo & repeat", "ctx": "Undotree", "n": "Toggle with <kbd>Space u u</kbd>. Config: focus jumps into the tree on toggle, 32-col panel, diff panel closed by default (<kbd>D</kbd>), help line hidden (<kbd>?</kbd> still works), Nerd Font tree glyphs. Persistent <code>undofile</code> is on, so history survives restarts.", "e": 1},
{"k": "J", "m": ["n"], "d": "Move to the previous (older) undo state", "s": "undotree", "cat": "Undo & repeat", "ctx": "Undotree"},
{"k": "K", "m": ["n"], "d": "Move to the next (newer) undo state", "s": "undotree", "cat": "Undo & repeat", "ctx": "Undotree"},
{"k": "<", "m": ["n"], "d": "Move to the previous saved state", "s": "undotree", "cat": "Undo & repeat", "ctx": "Undotree"},
{"k": ">", "m": ["n"], "d": "Move to the next saved state", "s": "undotree", "cat": "Undo & repeat", "ctx": "Undotree"},
{"k": "u", "m": ["n"], "d": "Undo (in the target buffer)", "s": "undotree", "cat": "Undo & repeat", "ctx": "Undotree"},
{"k": "<C-r>", "m": ["n"], "d": "Redo (in the target buffer)", "s": "undotree", "cat": "Undo & repeat", "ctx": "Undotree"},
{"k": "D", "m": ["n"], "d": "Toggle the diff panel", "s": "undotree", "cat": "Undo & repeat", "ctx": "Undotree"},
{"k": "=", "m": ["n"], "d": "Set the diff marker on this state (diff against it)", "s": "undotree", "cat": "Undo & repeat", "ctx": "Undotree"},
{"k": "M", "m": ["n"], "d": "Clear the diff marker", "s": "undotree", "cat": "Undo & repeat", "ctx": "Undotree"},
{"k": "T", "m": ["n"], "d": "Toggle relative / absolute timestamps", "s": "undotree", "cat": "Undo & repeat", "ctx": "Undotree"},
{"k": "C", "m": ["n"], "d": "Clear the undo history (asks first)", "s": "undotree", "cat": "Undo & repeat", "ctx": "Undotree"},
{"k": "<Tab>", "m": ["n"], "d": "Move focus back to the edited buffer", "s": "undotree", "cat": "Undo & repeat", "ctx": "Undotree"},
{"k": "?", "m": ["n"], "d": "Toggle quick help", "s": "undotree", "cat": "Undo & repeat", "ctx": "Undotree"},
{"k": "q", "m": ["n"], "d": "Close the undotree panel", "s": "undotree", "cat": "Undo & repeat", "ctx": "Undotree"},
{"k": "<CR>", "m": ["n"], "d": "Smart action: follow link / list tag / fold heading / toggle checkbox", "s": "obsidian.nvim", "cat": "Notes", "ctx": "Obsidian notes", "n": "Only in Markdown notes inside the vaults <code>~/Documents/Notebook</code> and <code>~/Documents/Notes</code>. In order: accept an inlay-hint action; follow the link under the cursor; open the tag picker on a tag; <code>za</code> on a heading if Markdown folding is on; otherwise toggle the line's checkbox (<code>create_new = true</code>, so plain lines become <code>- [ ]</code>; states cycle <code>[ ] [~] [!] [&gt;] [x]</code>). In vault notes this shadows the global Leap <kbd>Enter</kbd>.", "e": 1},
{"k": "]o", "m": ["n"], "d": "Jump to the next link in the note", "s": "obsidian.nvim", "cat": "Notes", "ctx": "Obsidian notes", "n": "Only in Markdown notes inside the vaults <code>~/Documents/Notebook</code> and <code>~/Documents/Notes</code>."},
{"k": "[o", "m": ["n"], "d": "Jump to the previous link in the note", "s": "obsidian.nvim", "cat": "Notes", "ctx": "Obsidian notes", "n": "Only in Markdown notes inside the vaults <code>~/Documents/Notebook</code> and <code>~/Documents/Notes</code>."},
{"k": "gd", "m": ["n"], "d": "Follow the [[link]] under the cursor (obsidian LSP definition)", "s": "obsidian.nvim", "cat": "Notes", "ctx": "Obsidian notes", "n": "Only in Markdown notes inside the vaults <code>~/Documents/Notebook</code> and <code>~/Documents/Notes</code>. obsidian.nvim starts an in-process LSP server for notes (definition, references, rename, code actions, symbols, completion of <code>[[</code> links and <code>#</code> tags), so the config's LSP keys work on notes."},
{"k": "gr", "m": ["n"], "d": "List backlinks / references to this note or heading (obsidian LSP)", "s": "obsidian.nvim", "cat": "Notes", "ctx": "Obsidian notes", "n": "Only in Markdown notes inside the vaults <code>~/Documents/Notebook</code> and <code>~/Documents/Notes</code>. obsidian.nvim starts an in-process LSP server for notes (definition, references, rename, code actions, symbols, completion of <code>[[</code> links and <code>#</code> tags), so the config's LSP keys work on notes."},
{"k": "<leader>cr", "m": ["n"], "d": "Rename the note and update every link to it (LSP rename via IncRename)", "s": "obsidian.nvim", "cat": "Notes", "ctx": "Obsidian notes", "n": "Only in Markdown notes inside the vaults <code>~/Documents/Notebook</code> and <code>~/Documents/Notes</code>. obsidian.nvim starts an in-process LSP server for notes (definition, references, rename, code actions, symbols, completion of <code>[[</code> links and <code>#</code> tags), so the config's LSP keys work on notes."},
{"k": "<leader>ca", "m": ["n"], "d": "Obsidian code actions (e.g. link selection to new note, extract note)", "s": "obsidian.nvim", "cat": "Notes", "ctx": "Obsidian notes", "n": "Only in Markdown notes inside the vaults <code>~/Documents/Notebook</code> and <code>~/Documents/Notes</code>. obsidian.nvim starts an in-process LSP server for notes (definition, references, rename, code actions, symbols, completion of <code>[[</code> links and <code>#</code> tags), so the config's LSP keys work on notes."},
{"k": "<leader>ss", "m": ["n"], "d": "Headings outline of the note (LSP document symbols)", "s": "obsidian.nvim", "cat": "Notes", "ctx": "Obsidian notes", "n": "Only in Markdown notes inside the vaults <code>~/Documents/Notebook</code> and <code>~/Documents/Notes</code>. obsidian.nvim starts an in-process LSP server for notes (definition, references, rename, code actions, symbols, completion of <code>[[</code> links and <code>#</code> tags), so the config's LSP keys work on notes."},
{"k": ":Obsidian today", "m": [":"], "d": "Open (or create) today's daily note", "s": "obsidian.nvim", "cat": "Notes", "n": "<code>legacy_commands = false</code>: only the <code>:Obsidian &lt;sub&gt;</code> form exists. Bare <code>:Obsidian</code> opens a menu of all subcommands."},
{"k": ":Obsidian yesterday", "m": [":"], "d": "Open the daily note for the previous working day", "s": "obsidian.nvim", "cat": "Notes"},
{"k": ":Obsidian tomorrow", "m": [":"], "d": "Open the daily note for the next working day", "s": "obsidian.nvim", "cat": "Notes"},
{"k": ":Obsidian dailies", "m": [":"], "d": "Picker of daily notes", "s": "obsidian.nvim", "cat": "Notes"},
{"k": ":Obsidian new", "m": [":"], "d": "Create a new note (title as argument or prompt)", "s": "obsidian.nvim", "cat": "Notes"},
{"k": ":Obsidian new_from_template", "m": [":"], "d": "Create a new note from a template", "s": "obsidian.nvim", "cat": "Notes"},
{"k": ":Obsidian open", "m": [":"], "d": "Open a note in the Obsidian app", "s": "obsidian.nvim", "cat": "Notes"},
{"k": ":Obsidian quick_switch", "m": [":"], "d": "Fuzzy-find a note by name and open it", "s": "obsidian.nvim", "cat": "Notes"},
{"k": ":Obsidian search", "m": [":"], "d": "Grep the vault", "s": "obsidian.nvim", "cat": "Notes"},
{"k": ":Obsidian tags", "m": [":"], "d": "Picker of tags and the notes that use them", "s": "obsidian.nvim", "cat": "Notes"},
{"k": ":Obsidian backlinks", "m": [":"], "d": "Picker of notes linking to this note", "s": "obsidian.nvim", "cat": "Notes", "ctx": "Obsidian notes"},
{"k": ":Obsidian links", "m": [":"], "d": "Picker of all links in this note", "s": "obsidian.nvim", "cat": "Notes", "ctx": "Obsidian notes"},
{"k": ":Obsidian follow_link", "m": [":"], "d": "Follow the link under the cursor", "s": "obsidian.nvim", "cat": "Notes", "ctx": "Obsidian notes"},
{"k": ":Obsidian link", "m": [":"], "d": "Link the selection to an existing note", "s": "obsidian.nvim", "cat": "Notes", "ctx": "Obsidian notes"},
{"k": ":Obsidian link_new", "m": [":"], "d": "Link the selection to a new note", "s": "obsidian.nvim", "cat": "Notes", "ctx": "Obsidian notes"},
{"k": ":Obsidian extract_note", "m": [":"], "d": "Move the selection into a new note and link it", "s": "obsidian.nvim", "cat": "Notes", "ctx": "Obsidian notes"},
{"k": ":Obsidian toggle_checkbox", "m": [":"], "d": "Cycle the checkbox state on the line(s)", "s": "obsidian.nvim", "cat": "Notes", "ctx": "Obsidian notes"},
{"k": ":Obsidian rename", "m": [":"], "d": "Rename the note and update backlinks", "s": "obsidian.nvim", "cat": "Notes", "ctx": "Obsidian notes"},
{"k": ":Obsidian template", "m": [":"], "d": "Insert a template at the cursor", "s": "obsidian.nvim", "cat": "Notes", "ctx": "Obsidian notes"},
{"k": ":Obsidian paste_img", "m": [":"], "d": "Paste an image from the clipboard into the vault", "s": "obsidian.nvim", "cat": "Notes", "ctx": "Obsidian notes"},
{"k": ":Obsidian toc", "m": [":"], "d": "Table of contents of this note in a picker", "s": "obsidian.nvim", "cat": "Notes", "ctx": "Obsidian notes"},
{"k": ":Obsidian footnotes", "m": [":"], "d": "Picker of footnotes in this note", "s": "obsidian.nvim", "cat": "Notes", "ctx": "Obsidian notes"},
{"k": ":Obsidian workspace", "m": [":"], "d": "Show or switch the workspace (notebook / notes)", "s": "obsidian.nvim", "cat": "Notes"},
{"k": ":Obsidian unique_note", "m": [":"], "d": "Create a note with a unique (timestamp) id", "s": "obsidian.nvim", "cat": "Notes"},
{"k": ":Obsidian bookmarks", "m": [":"], "d": "Picker of bookmarked notes", "s": "obsidian.nvim", "cat": "Notes"},
{"k": ":Obsidian rebuild_cache", "m": [":"], "d": "Rebuild the vault cache", "s": "obsidian.nvim", "cat": "Notes"},
{"k": ":Obsidian check", "m": [":"], "d": "Check the vault for problems", "s": "obsidian.nvim", "cat": "Notes"},
{"k": ":Obsidian sync", "m": [":"], "d": "Run an Obsidian sync action", "s": "obsidian.nvim", "cat": "Notes"},
{"k": ":Obsidian help", "m": [":"], "d": "Find a page in obsidian.nvim's bundled help docs", "s": "obsidian.nvim", "cat": "Notes"},
{"k": ":Obsidian helpgrep", "m": [":"], "d": "Grep obsidian.nvim's help vault", "s": "obsidian.nvim", "cat": "Notes"},
{"k": "Bookmark signs", "m": ["n"], "d": "Haunt: bookmarks show a 󱙝 sign and the annotation as end-of-line virtual text", "s": "haunt", "cat": "Mark & jump", "ctx": "Haunt bookmarks", "n": "<kbd>Space h a</kbd> annotates (creating the bookmark if needed; empty input cancels), <kbd>Space h t</kbd> toggles the annotation text, <kbd>Space h n</kbd>/<kbd>p</kbd> walk bookmarks, <kbd>Space h d</kbd> deletes, <kbd>Space h l</kbd> lists. Stored per project and per git branch."},
{"k": ":IncRename {new}", "m": [":"], "d": "Rename the LSP symbol with a live preview of every change", "s": "inc-rename", "cat": "LSP & diagnostics", "ctx": "IncRename (Space c r)", "n": "<kbd>Space c r</kbd> types <code>:IncRename &lt;cword&gt;</code> for you; with Noice's <code>inc_rename</code> preset the command line appears as a small popup above the cursor. Edit the name and watch all occurrences update (highlighted <code>Substitute</code>); <kbd>Enter</kbd> renames across files, <kbd>Esc</kbd> cancels. An empty name cancels the preview.", "e": 1},
{"k": "format on save", "m": ["n"], "d": "Buffers are formatted on every write", "s": "conform", "cat": "Edit", "ctx": "Conform", "n": "<code>format_on_save</code> (500 ms, LSP fallback) in <code>lua/plugins.lua</code>; set <code>vim.g.disable_autoformat</code> / <code>vim.b.disable_autoformat</code> to turn it off. Autosave on InsertLeave/TextChanged means this runs often."},
{"k": ":Gitsigns nav_hunk next", "m": [":"], "d": "Jump to the next changed hunk", "s": "gitsigns", "cat": "Git", "n": "Hunk navigation is NOT mapped in this config (no ]c/[c, no <leader>h… gitsigns keys); use these commands. The older <code>next_hunk</code> / <code>prev_hunk</code> still work but are deprecated."},
{"k": ":Gitsigns nav_hunk prev", "m": [":"], "d": "Jump to the previous changed hunk", "s": "gitsigns", "cat": "Git", "n": "Hunk navigation is NOT mapped in this config (no ]c/[c, no <leader>h… gitsigns keys); use these commands. The older <code>next_hunk</code> / <code>prev_hunk</code> still work but are deprecated."},
{"k": ":Gitsigns nav_hunk first|last", "m": [":"], "d": "Jump to the first / last hunk in the file", "s": "gitsigns", "cat": "Git"},
{"k": ":Gitsigns preview_hunk", "m": [":"], "d": "Show the hunk's diff in a float", "s": "gitsigns", "cat": "Git"},
{"k": ":Gitsigns preview_hunk_inline", "m": [":"], "d": "Show the hunk's removed lines inline", "s": "gitsigns", "cat": "Git"},
{"k": ":Gitsigns stage_hunk", "m": [":"], "d": "Stage the hunk under the cursor (or the range); on a staged hunk it unstages", "s": "gitsigns", "cat": "Git"},
{"k": ":Gitsigns reset_hunk", "m": [":"], "d": "Discard the hunk under the cursor (or the range)", "s": "gitsigns", "cat": "Git"},
{"k": ":Gitsigns undo_stage_hunk", "m": [":"], "d": "Undo the last stage_hunk (deprecated: run stage_hunk on the staged hunk)", "s": "gitsigns", "cat": "Git"},
{"k": ":Gitsigns stage_buffer", "m": [":"], "d": "Stage the whole file", "s": "gitsigns", "cat": "Git"},
{"k": ":Gitsigns reset_buffer", "m": [":"], "d": "Discard all changes in the file", "s": "gitsigns", "cat": "Git"},
{"k": ":Gitsigns reset_buffer_index", "m": [":"], "d": "Unstage the whole file", "s": "gitsigns", "cat": "Git"},
{"k": ":Gitsigns select_hunk", "m": [":"], "d": "Visually select the hunk", "s": "gitsigns", "cat": "Git"},
{"k": ":Gitsigns blame_line", "m": [":"], "d": "Show blame for the current line in a float", "s": "gitsigns", "cat": "Git"},
{"k": ":Gitsigns blame", "m": [":"], "d": "Open a full-file blame side panel", "s": "gitsigns", "cat": "Git"},
{"k": ":Gitsigns diffthis", "m": [":"], "d": "Diff the file against the index (or a revision)", "s": "gitsigns", "cat": "Git"},
{"k": ":Gitsigns show", "m": [":"], "d": "Open the file as it was at a revision", "s": "gitsigns", "cat": "Git"},
{"k": ":Gitsigns toggle_current_line_blame", "m": [":"], "d": "Toggle line blame (shown in lualine here, not virtual text)", "s": "gitsigns", "cat": "Git"},
{"k": ":Gitsigns toggle_word_diff", "m": [":"], "d": "Toggle word-level diff highlighting", "s": "gitsigns", "cat": "Git"},
{"k": ":Gitsigns toggle_linehl", "m": [":"], "d": "Toggle highlighting changed lines", "s": "gitsigns", "cat": "Git"},
{"k": ":Gitsigns toggle_numhl", "m": [":"], "d": "Toggle highlighting changed line numbers", "s": "gitsigns", "cat": "Git"},
{"k": ":Gitsigns toggle_deleted", "m": [":"], "d": "Toggle showing deleted lines inline (deprecated: use preview_hunk_inline)", "s": "gitsigns", "cat": "Git"},
{"k": ":Gitsigns setqflist all", "m": [":"], "d": "Send hunks to the quickfix list (current file, or all)", "s": "gitsigns", "cat": "Git"},
{"k": ":Gitsigns change_base", "m": [":"], "d": "Diff signs against another revision", "s": "gitsigns", "cat": "Git"},
{"k": "<CR>", "m": ["n"], "d": "Open the blame context menu", "s": "gitsigns", "cat": "Git", "ctx": "Gitsigns blame panel (:Gitsigns blame)"},
{"k": "r", "m": ["n"], "d": "Re-blame at this commit", "s": "gitsigns", "cat": "Git", "ctx": "Gitsigns blame panel (:Gitsigns blame)"},
{"k": "R", "m": ["n"], "d": "Re-blame at the commit's parent", "s": "gitsigns", "cat": "Git", "ctx": "Gitsigns blame panel (:Gitsigns blame)"},
{"k": "d", "m": ["n"], "d": "Diff this commit (new tab)", "s": "gitsigns", "cat": "Git", "ctx": "Gitsigns blame panel (:Gitsigns blame)"},
{"k": "s", "m": ["n"], "d": "Show the commit in a vertical split", "s": "gitsigns", "cat": "Git", "ctx": "Gitsigns blame panel (:Gitsigns blame)"},
{"k": "S", "m": ["n"], "d": "Show the commit in a new tab", "s": "gitsigns", "cat": "Git", "ctx": "Gitsigns blame panel (:Gitsigns blame)"},
{"k": "q", "m": ["n"], "d": "Close the gitsigns popup (after entering it)", "s": "gitsigns", "cat": "Git", "ctx": "Gitsigns preview / blame float"},
{"k": "q", "m": ["n"], "d": "Close the message split / popup (:Noice, :Noice last, errors)", "s": "noice", "cat": "Command line", "ctx": "Noice", "n": "Long messages (≥ 20 lines) go to a split (<code>long_message_to_split</code>). <code>:</code> opens a centred command palette popup, <code>/</code> and <code>?</code> stay at the bottom (<code>bottom_search</code>). Noice defines no other keys; scrolling LSP docs with <kbd>Ctrl-f</kbd>/<kbd>Ctrl-b</kbd> is not configured."},
{"k": "K / gx", "m": ["n"], "d": "Inside Noice hover/docs windows: open the link under the cursor", "s": "noice", "cat": "LSP & diagnostics", "ctx": "Noice", "n": "Buffer-local in Noice markdown views; otherwise they fall through to normal <kbd>K</kbd>/<kbd>gx</kbd>."},
{"k": "i", "m": ["n"], "d": "Install the package under the cursor", "s": "mason", "cat": "LSP & diagnostics", "ctx": "Mason"},
{"k": "u", "m": ["n"], "d": "Update / reinstall the package", "s": "mason", "cat": "LSP & diagnostics", "ctx": "Mason"},
{"k": "X", "m": ["n"], "d": "Uninstall the package", "s": "mason", "cat": "LSP & diagnostics", "ctx": "Mason"},
{"k": "c", "m": ["n"], "d": "Check the package for a new version", "s": "mason", "cat": "LSP & diagnostics", "ctx": "Mason"},
{"k": "U", "m": ["n"], "d": "Update all installed packages", "s": "mason", "cat": "LSP & diagnostics", "ctx": "Mason"},
{"k": "C", "m": ["n"], "d": "Check which packages are outdated", "s": "mason", "cat": "LSP & diagnostics", "ctx": "Mason"},
{"k": "<CR>", "m": ["n"], "d": "Expand the package details / toggle its install log", "s": "mason", "cat": "LSP & diagnostics", "ctx": "Mason"},
{"k": "<C-c>", "m": ["n"], "d": "Cancel the installation", "s": "mason", "cat": "LSP & diagnostics", "ctx": "Mason"},
{"k": "<C-f>", "m": ["n"], "d": "Filter by language", "s": "mason", "cat": "LSP & diagnostics", "ctx": "Mason"},
{"k": "1 2 3 4 5", "m": ["n"], "d": "Show All / LSP / DAP / Linter / Formatter packages", "s": "mason", "cat": "LSP & diagnostics", "ctx": "Mason"},
{"k": "g?", "m": ["n"], "d": "Toggle help", "s": "mason", "cat": "LSP & diagnostics", "ctx": "Mason"},
{"k": "q", "m": ["n"], "d": "Close the window", "s": "mason", "cat": "LSP & diagnostics", "ctx": "Mason"},
{"k": "<Esc>", "m": ["n"], "d": "Clear the language filter / search, else close", "s": "mason", "cat": "LSP & diagnostics", "ctx": "Mason"},
{"k": "y{motion}", "m": ["n", "x"], "d": "Yank into the paste window (edit, then send it to the shell)", "s": "kitty-scrollback", "cat": "Terminal", "ctx": "Kitty scrollback", "n": "A plain yank opens a small paste window below; <code>\"+y</code> instead copies to the clipboard and quits back to Kitty. Only inside a kitty-scrollback.nvim session (opened from a Kitty mapping generated by <code>:KittyScrollbackGenerateKittens</code>)."},
{"k": "<leader>y{motion}", "m": ["n"], "d": "Yank {motion} to the system clipboard and return to Kitty", "s": "kitty-scrollback", "cat": "Terminal", "ctx": "Kitty scrollback"},
{"k": "<leader>y", "m": ["x"], "d": "Yank the selection to the system clipboard and return to Kitty", "s": "kitty-scrollback", "cat": "Terminal", "ctx": "Kitty scrollback"},
{"k": "<leader>yy", "m": ["n"], "d": "Yank the line to the clipboard and return to Kitty", "s": "kitty-scrollback", "cat": "Terminal", "ctx": "Kitty scrollback"},
{"k": "<leader>Y", "m": ["n"], "d": "Yank to end of line to the clipboard and return to Kitty", "s": "kitty-scrollback", "cat": "Terminal", "ctx": "Kitty scrollback", "n": "The visual <kbd>Space Y</kbd> default points at an undefined &lt;Plug&gt; map in this plugin version, so it does nothing."},
{"k": "<C-CR>", "m": ["n", "i", "x"], "d": "Execute the paste window text (or selection) in the shell", "s": "kitty-scrollback", "cat": "Terminal", "ctx": "Kitty scrollback"},
{"k": "<S-CR>", "m": ["n", "i", "x"], "d": "Paste the text (or selection) to the shell without running it", "s": "kitty-scrollback", "cat": "Terminal", "ctx": "Kitty scrollback"},
{"k": "g?", "m": ["n"], "d": "Toggle the paste window's key footer", "s": "kitty-scrollback", "cat": "Terminal", "ctx": "Kitty scrollback"},
{"k": "q", "m": ["n"], "d": "Close the paste window, or quit back to Kitty from the scrollback", "s": "kitty-scrollback", "cat": "Terminal", "ctx": "Kitty scrollback"},
{"k": "<C-c>", "m": ["n", "i", "t"], "d": "Quit back to Kitty", "s": "kitty-scrollback", "cat": "Terminal", "ctx": "Kitty scrollback"},
{"k": ":Browse [url]", "m": [":"], "d": "gx.nvim: open the URL / file / plugin / GitHub ref / package under the cursor", "s": "gx", "cat": "Misc", "n": "Also on <kbd>gx</kbd> (Normal and Visual, <code>lua/keymaps.lua:358</code>). Handlers: plugin names → GitHub, <code>#123</code> issues, package.json deps, search fallback."},
{"k": ":Qalc[!] [file]", "m": [":"], "d": "Open a calculator buffer: each line is evaluated by qalc as you type", "s": "qalc", "cat": "Misc", "n": "Results appear as virtual text; <code>!</code> makes it a scratch buffer. <code>*.qalc</code> files attach automatically. <code>:QalcYank [reg]</code> yanks the result of the current line (the unnamed register when none is given)."},
{"k": "<leader>cb…", "m": ["n", "v"], "d": "Comment boxes: cbb centred box, cbl centred line, cbd delete, cbk catalog", "s": "comment-box", "cat": "Comment", "ctx": "Comment-box", "n": "The box and line commands take a style number (see the catalog) and work on a range; e.g. <code>:CBccbox 3</code>. <code>:CBd</code> removes a box, <code>:CBy</code> yanks a box's text without the frame."},
{"k": ":Mason", "m": [":"], "d": "Open Mason's package manager window", "s": "mason", "cat": "LSP & diagnostics"},
{"k": ":Sidekick nes toggle", "m": [":"], "d": "Enable / disable Copilot next-edit suggestions", "s": "sidekick", "cat": "Completion & AI", "n": "Other subcommands: <code>nes apply|jump|update|clear|enable|disable</code>, <code>cli toggle|show|hide|close|focus|select|send|prompt</code>."},
{"k": ":Sidekick cli toggle", "m": [":"], "d": "Open / hide the AI CLI terminal (claude, codex, copilot, gemini…)", "s": "sidekick", "cat": "Completion & AI"},
{"k": ":Noice", "m": [":"], "d": "Message history in a split (also :Noice last / errors / all / dismiss)", "s": "noice", "cat": "Command line"},
{"k": "<C-k>", "m": ["i"], "d": "Not mapped by blink: insert a digraph (Vim's i_CTRL-K)", "s": "blink.cmp", "cat": "Completion & AI", "ctx": "Completion menu (insert)", "n": "The preset's signature toggle is disabled (<code>[\"&lt;C-k&gt;\"] = false</code>) so digraphs work; signature help shows automatically, or press Neovim's <kbd>Ctrl-s</kbd>"}
],
"commands": {
"BlinkCmp": "blink.cmp: status (checkhealth), build or build-log of the fuzzy matcher",
"Browse": "gx.nvim (also on gx): open URL, path, plugin, GitHub issue or package under the cursor / given arg",
"CBacbox": "Centred adapted box (box fits the text)",
"CBalbox": "Left-aligned adapted box (deprecated alias of CBlabox)",
"CBcabox": "Centred adapted box (deprecated alias of CBacbox)",
"CBcatalog": "Open the comment-box style catalog",
"CBccbox": "Centred box, text centred",
"CBccline": "Centred titled line, title centred",
"CBclbox": "Centred box, text left-aligned",
"CBcline": "Centred line (no title)",
"CBclline": "Centred titled line, title left-aligned",
"CBcrbox": "Centred box, text right-aligned",
"CBcrline": "Centred titled line, title right-aligned",
"CBd": "Remove the box or titled line around the range",
"CBlabox": "Left-aligned adapted box (box fits the text)",
"CBlcbox": "Left-aligned box, text centred",
"CBlcline": "Left-aligned titled line, title centred",
"CBline": "Left-aligned line (no title)",
"CBllbox": "Left-aligned box, text left-aligned",
"CBlline": "Left-aligned line (no title)",
"CBllline": "Left-aligned titled line, title left-aligned",
"CBlrbox": "Left-aligned box, text right-aligned",
"CBlrline": "Left-aligned titled line, title right-aligned",
"CBrabox": "Right-aligned adapted box (box fits the text)",
"CBrcbox": "Right-aligned box, text centred",
"CBrcline": "Right-aligned titled line, title centred",
"CBrlbox": "Right-aligned box, text left-aligned",
"CBrline": "Right-aligned line (no title)",
"CBrlline": "Right-aligned titled line, title left-aligned",
"CBrrbox": "Right-aligned box, text right-aligned",
"CBrrline": "Right-aligned titled line, title right-aligned",
"CBy": "Yank the text of a box or titled line without the frame",
"Catppuccin": "Switch Catppuccin flavour (latte, frappe, macchiato, mocha)",
"CatppuccinCompile": "Recompile the Catppuccin highlight cache",
"ConformInfo": "Show Conform's formatters, their status and the log",
"FZF": "fzf.vim (system): fuzzy-find files in a directory with the fzf binary",
"Gitsigns": "Gitsigns actions: nav_hunk, stage_hunk, blame_line, diffthis… (no keys mapped)",
"GrugFar": "Open Grug-far search & replace (optional engine arg; a visual range prefills the search)",
"GrugFarWithin": "Grug-far limited to the visual selection",
"HauntAnnotate": "Add or edit the annotation of the bookmark on this line",
"HauntChangeDataDir": "Change where Haunt stores bookmarks",
"HauntClear": "Clear all bookmarks in the current file",
"HauntClearAll": "Clear every bookmark",
"HauntDelete": "Delete the bookmark on this line",
"HauntList": "Picker of all bookmarks",
"HauntMigrate": "Migrate bookmarks from v1 to v2 storage",
"HauntNext": "Jump to the next bookmark",
"HauntPrev": "Jump to the previous bookmark",
"HauntQf": "Send this buffer's annotations to the quickfix list",
"HauntQfAll": "Send all annotations to the quickfix list",
"HauntReload": "Reload bookmarks from disk",
"HauntToggle": "Toggle annotation visibility",
"IncRename": "LSP rename with live preview of all changes (Space c r)",
"JdtShowLogs": "nvim-jdtls (system package): show the jdtls language server logs",
"JdtWipeDataAndRestart": "nvim-jdtls (system package): wipe the workspace data and restart jdtls",
"KittyScrollbackCheckHealth": "Run kitty-scrollback.nvim health checks",
"KittyScrollbackGenerateCommandLineEditing": "Print shell config to edit the command line in kitty-scrollback",
"KittyScrollbackGenerateKittens": "Print kitty.conf mappings that launch kitty-scrollback",
"LazyDev": "lazydev.nvim: debug info / show the Lua LSP library settings",
"LspInstall": "mason-lspconfig: install LSP servers",
"LspUninstall": "mason-lspconfig: uninstall LSP servers",
"Mason": "Open Mason's package manager window",
"MasonInstall": "Install Mason packages by name",
"MasonLog": "Open the Mason log",
"MasonUninstall": "Uninstall Mason packages",
"MasonUninstallAll": "Uninstall every Mason package",
"MasonUpdate": "Update the Mason registries",
"Noice": "Noice message history (subcommands: last, errors, all, dismiss, pick…)",
"NoiceAll": "All Noice messages in a split",
"NoiceConfig": "Show Noice's active configuration",
"NoiceDebug": "Toggle Noice debug mode",
"NoiceDisable": "Disable Noice (back to the native UI)",
"NoiceDismiss": "Dismiss all visible Noice messages",
"NoiceEnable": "Enable Noice",
"NoiceErrors": "Noice error messages in a popup",
"NoiceFzf": "Noice history in fzf-lua (not installed here)",
"NoiceHistory": "Noice message history in a split",
"NoiceLast": "Show the last Noice message in a popup",
"NoiceLog": "Open the Noice log file",
"NoicePick": "Noice history in the Snacks picker",
"NoiceRoutes": "Show Noice's message routes",
"NoiceSnacks": "Noice history in the Snacks picker",
"NoiceStats": "Show Noice statistics",
"NoiceTelescope": "Noice history in Telescope (not installed here)",
"NoiceViewstats": "Show Noice view statistics",
"Obsidian": "obsidian.nvim: :Obsidian today|new|search|quick_switch|tags|…; bare opens a menu",
"Qalc": "Open a qalc calculator buffer (! for a scratch buffer)",
"QalcAttach": "Evaluate the current buffer's lines with qalc",
"QalcYank": "Yank the qalc result of the current line (unnamed register unless one is given)",
"Sidekick": "Sidekick: nes {apply|jump|toggle|…}, cli {toggle|select|send|prompt|…}",
"TSContext": "Treesitter context: enable, disable or toggle the sticky header",
"UndotreeFocus": "Focus the undotree panel",
"UndotreeHide": "Close the undotree panel",
"UndotreePersistUndo": "Turn on persistent undo for this file (no-op here: 'undofile' is already on)",
"UndotreeShow": "Open the undotree panel",
"UndotreeToggle": "Toggle the undotree panel (Space u u)",
"WakaTimeApiKey": "Set the WakaTime API key",
"WakaTimeCliLocation": "Show the wakatime-cli path",
"WakaTimeCliVersion": "Show the wakatime-cli version",
"WakaTimeDebugDisable": "Turn WakaTime debug logging off",
"WakaTimeDebugEnable": "Turn WakaTime debug logging on",
"WakaTimeFileExpert": "Show who has spent the most time on this file",
"WakaTimeScreenRedrawDisable": "Never redraw the screen after sending heartbeats",
"WakaTimeScreenRedrawEnable": "Always redraw the screen after sending heartbeats",
"WakaTimeScreenRedrawEnableAuto": "Redraw the screen after heartbeats only when needed",
"WakaTimeStatusBarDisable": "Hide WakaTime's status bar text",
"WakaTimeStatusBarEnable": "Show WakaTime's status bar text",
"WakaTimeToday": "Show today's coding time",
"WhichKey": "Show the which-key popup: :WhichKey [mode] [keys]"
},
"notes": [
{"title": "Plugin keys that change stock behaviour", "kind": "warn", "lead": "Verified in plugin source and, where marked, by running the real config headless.", "rows": [["<kbd>Enter</kbd> in vault notes", "obsidian.nvim's smart action (buffer-local) shadows the global Leap <kbd>Enter</kbd> and turns plain lines into checkboxes."], ["<kbd>Enter</kbd> in git log pickers", "Snacks confirms with <code>git checkout</code>: detached HEAD (<kbd>Space g l</kbd>) or overwriting the file (<kbd>Space g f</kbd>, <kbd>Space g L</kbd>)."], ["Dashboard <kbd>s</kbd>", "Missing: Snacks only detects persistence.nvim under lazy.nvim, so there is no Restore Session item."]], "keys": ["<CR>"]}
]
}
+239
View File
@@ -0,0 +1,239 @@
-- Dump the live keymap/command state of this config as JSON.
--
-- Run by gen_cheatsheet.py as:
-- CHEATSHEET_DUMP=out.json nvim --headless -V1 -c "luafile /abs/path/dump.lua"
-- -V1 makes Neovim record "last set from <file>:<line>" for Lua mappings,
-- which is how each map is attributed to the config, a plugin or the runtime.
local out = assert(vim.env.CHEATSHEET_DUMP, "set CHEATSHEET_DUMP to the output path")
local MODES = { "n", "x", "s", "o", "i", "c", "t" }
local SAMPLES = {
{ name = "lua", path = vim.fn.stdpath("config") .. "/lua/keymaps.lua", lsp = true },
{ name = "markdown", ft = "markdown" },
}
local function script_path(sid)
if not sid or sid <= 0 then
return nil
end
local info = vim.fn.getscriptinfo({ sid = sid })[1]
if not info then
return nil
end
-- Lua modules compiled into Neovim (vim/_core/defaults.lua, …) are reported
-- by module path, which getscriptinfo() resolves against the cwd.
local mod = info.name:match("/(vim/_core/.*)$")
if mod and not vim.uv.fs_stat(info.name) then
return vim.env.VIMRUNTIME .. "/lua/" .. mod .. (mod:match("%.lua$") and "" or ".lua")
end
return info.name
end
local function collect(maps, scope)
local res = {}
for _, m in ipairs(maps) do
res[#res + 1] = {
mode = m.mode,
-- keytrans() turns a raw leader " " into <Space>, but would also fold
-- <C-I>/<C-M>/<C-[> into <Tab>/<CR>/<Esc>, which map separately.
lhs = m.lhs:find("<[Cc]%-[IiMm%[]>") and m.lhs
or vim.fn.keytrans(vim.api.nvim_replace_termcodes(m.lhs, true, true, true)),
rhs = m.rhs ~= "" and m.rhs or nil,
callback = m.callback ~= nil or nil,
desc = m.desc,
expr = m.expr == 1 or nil,
nowait = m.nowait == 1 or nil,
file = script_path(m.sid),
line = m.lnum ~= 0 and m.lnum or nil,
scope = scope,
}
end
return res
end
local function all_modes(get)
local res = {}
for _, mode in ipairs(MODES) do
for _, m in ipairs(get(mode)) do
-- nvim_get_keymap("x") etc. also report "v"/" " maps once per queried
-- mode; keep the queried mode so every entry belongs to exactly one.
m.mode = mode
res[#res + 1] = m
end
end
return res
end
local function commands(cmds, scope)
local res = {}
for name, c in pairs(cmds) do
local file, line
if c.script_id and c.script_id > 0 then
file = script_path(c.script_id)
end
res[#res + 1] = {
name = name,
desc = c.definition ~= "" and c.definition or nil,
nargs = c.nargs,
range = c.range,
bang = c.bang or nil,
file = file,
scope = scope,
}
end
table.sort(res, function(a, b)
return a.name < b.name
end)
return res
end
local function dump()
local data = {
version = tostring(vim.version()),
vimruntime = vim.env.VIMRUNTIME,
config = vim.fn.stdpath("config"),
data = vim.fn.stdpath("data"),
leader = vim.g.mapleader,
localleader = vim.g.maplocalleader,
neovide = vim.g.neovide and true or false,
options = {
clipboard = vim.o.clipboard,
relativenumber = vim.o.relativenumber,
timeoutlen = vim.o.timeoutlen,
wrap = vim.o.wrap,
ignorecase = vim.o.ignorecase,
smartcase = vim.o.smartcase,
autowrite = vim.o.autowrite,
undofile = vim.o.undofile,
shiftwidth = vim.o.shiftwidth,
},
maps = collect(all_modes(vim.api.nvim_get_keymap), "global"),
commands = commands(vim.api.nvim_get_commands({ builtin = false }), "global"),
buffers = {},
plugins = {},
}
for _, p in ipairs(vim.pack.get()) do
data.plugins[#data.plugins + 1] = { name = p.spec.name, src = p.spec.src, active = p.active }
end
-- Plugin-internal keys that only exist inside their own windows.
local ok, snacks_cfg = pcall(function()
return require("snacks.picker.config").get({})
end)
if ok then
local function keys(t)
local res = {}
for lhs, v in pairs(t or {}) do
if v then
local action = type(v) == "table" and (v[1] or v.action) or v
res[#res + 1] = {
lhs = lhs,
action = type(action) == "string" and action or "function",
mode = type(v) == "table" and v.mode or nil,
desc = type(v) == "table" and v.desc or nil,
}
end
end
return res
end
data.snacks_picker = {
input = keys(snacks_cfg.win.input.keys),
list = keys(snacks_cfg.win.list.keys),
preview = keys(snacks_cfg.win.preview.keys),
}
local eok, explorer = pcall(function()
return require("snacks.picker.config").get({ source = "explorer" })
end)
if eok then
data.snacks_explorer = keys(explorer.win.list.keys)
end
end
-- blink.cmp resolves its preset + overrides into keymap.mappings at setup.
local bok, blink_keymap = pcall(require, "blink.cmp.keymap")
if bok and blink_keymap.mappings then
data.blink = {}
for kind, mappings in pairs(blink_keymap.mappings) do
local res = {}
for lhs, actions in pairs(mappings) do
local names = {}
for _, a in ipairs(type(actions) == "table" and actions or {}) do
names[#names + 1] = type(a) == "string" and a or "function"
end
res[#res + 1] = { lhs = lhs, actions = names }
end
data.blink[kind] = res
end
end
local fok, flash_cfg = pcall(function()
return require("flash.config")
end)
if fok then
data.flash = {
char_keys = flash_cfg.modes.char.keys,
multi_line = flash_cfg.modes.char.multi_line,
jump_labels = flash_cfg.modes.char.jump_labels,
}
end
local function sample(s)
local buf
if s.path then
vim.cmd.edit(vim.fn.fnameescape(s.path))
buf = vim.api.nvim_get_current_buf()
else
buf = vim.api.nvim_create_buf(true, false)
vim.api.nvim_set_current_buf(buf)
vim.bo[buf].filetype = s.ft
end
if s.lsp then
vim.wait(15000, function()
return #vim.lsp.get_clients({ bufnr = buf }) > 0
end, 100)
vim.wait(500)
end
-- Plugins that attach on InsertEnter/BufEnter (blink.cmp, …).
vim.api.nvim_exec_autocmds({ "BufEnter", "InsertEnter" }, { buffer = buf, modeline = false })
local get = function(mode)
return vim.api.nvim_buf_get_keymap(buf, mode)
end
data.buffers[#data.buffers + 1] = {
name = s.name,
filetype = vim.bo[buf].filetype,
lsp = vim.tbl_map(function(c)
return c.name
end, vim.lsp.get_clients({ bufnr = buf })),
maps = collect(all_modes(get), "buffer"),
commands = commands(vim.api.nvim_buf_get_commands(buf, {}), "buffer"),
}
end
for _, s in ipairs(SAMPLES) do
local sok, err = pcall(sample, s)
if not sok then
io.stderr:write("sample " .. s.name .. " failed: " .. tostring(err) .. "\n")
end
end
local f = assert(io.open(out, "w"))
f:write(vim.json.encode(data))
f:close()
vim.cmd("qa!")
end
-- Plugins load on VimEnter (lua/lazyload.lua); wait for the last of them.
vim.api.nvim_create_autocmd("VimEnter", {
once = true,
callback = function()
-- Headless Neovim never fires UIEnter, which Snacks waits for before
-- setting up UI-only maps (scope: ii/ai/[i/]i).
vim.api.nvim_exec_autocmds("UIEnter", { modeline = false })
vim.defer_fn(function()
vim.wait(10000, function()
return package.loaded["obsidian"] ~= nil and package.loaded["sidekick"] ~= nil
end, 50)
vim.defer_fn(dump, 300)
end, 50)
end,
})
+553
View File
@@ -0,0 +1,553 @@
#!/usr/bin/env python3
"""Generate cheatsheet.html: every Vim/Neovim key and this config's keymaps.
Run from anywhere: python3 gen_cheatsheet.py [--dump FILE]
Sources, merged into one searchable single-file page:
* $VIMRUNTIME/doc/index.txt every built-in key in every mode, plus Ex commands
* the live config dump.lua runs Neovim headless with this config and
records every keymap/command with the file and
line that set it (config, plugin or runtime)
* curated/*.json plugin-internal keys (pickers, completion, text
objects, …), descriptions, categories and notes
Built-in keys that a mapping replaces, delays or makes unreachable are flagged.
--dump FILE reuses (or, when FILE is missing, writes) a dump instead of
starting Neovim each run.
"""
import json
import os
import re
import subprocess
import sys
import tempfile
from datetime import date
from pathlib import Path
HERE = Path(__file__).resolve().parent
OUT = HERE / "cheatsheet.html"
MOTION_MODES = ["n", "x", "o"]
# ---------------------------------------------------------------------------
# Live dump
# ---------------------------------------------------------------------------
def run_dump(path):
env = dict(os.environ, CHEATSHEET_DUMP=str(path))
subprocess.run(
["nvim", "--headless", "-V1", "-c", f"luafile {HERE / 'dump.lua'}"],
env=env, stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL, timeout=120, check=False,
)
if not Path(path).exists():
sys.exit("dump.lua produced no output — run it by hand to see the error:\n"
f" CHEATSHEET_DUMP=/tmp/d.json nvim --headless -V1 -c 'luafile {HERE / 'dump.lua'}'")
return json.loads(Path(path).read_text())
def load_dump():
args = sys.argv[1:]
if "--dump" in args:
path = Path(args[args.index("--dump") + 1])
return json.loads(path.read_text()) if path.exists() else run_dump(path)
with tempfile.TemporaryDirectory() as tmp:
return run_dump(Path(tmp) / "dump.json")
# ---------------------------------------------------------------------------
# Key notation
# ---------------------------------------------------------------------------
def index_keys(raw):
"""index.txt key column ("CTRL-W CTRL-B", "z<CR>", "a\"") -> Vim notation."""
out = []
if raw == '"``"': # index.txt quotes this one so the help syntax stays intact
return "``"
for word in raw.split(" "):
if not word:
continue
word = re.sub(r"CTRL-SHIFT-(.)", lambda m: f"<C-S-{m.group(1).upper()}>", word)
word = re.sub(r"CTRL-(<[^>]+>|\{char\}|.)", lambda m: ctrl(m.group(1)), word)
out.append(word)
return "".join(out)
def ctrl(k):
if k.startswith("<") and k.endswith(">"):
return f"<C-{k[1:-1]}>"
if k == "{char}":
return "<C-{char}>"
return f"<C-{k.upper() if k.isalpha() else k}>"
def canon(lhs):
"""Comparable form of a key sequence (keytrans style, case-folded names)."""
def fix(m):
inner = m.group(1)
parts = inner.split("-")
mods, key = parts[:-1], parts[-1] or "-"
if len(key) > 1:
key = {"cr": "CR", "esc": "Esc", "tab": "Tab", "bs": "BS", "space": "Space", "nl": "NL",
"lt": "lt", "bar": "Bar", "bslash": "Bslash"}.get(key.lower(), key[0].upper() + key[1:])
elif mods and set(m.upper() for m in mods) == {"C"} and key.isalpha():
key = key.upper()
return "<" + "-".join([*(x.upper() for x in mods), key]) + ">"
return re.sub(r"<([^<>]+)>", fix, lhs).replace("<lt>", "<").replace("<Lt>", "<")
TOKEN = re.compile(r'\["x\]|\{[^}]+\}|<(?:[A-Za-z0-9]+-)*(?:[A-Za-z0-9]+|[^>\s])>|.')
def tokens(lhs):
return TOKEN.findall(lhs)
def is_ph(tok):
return tok == '["x]' or (tok.startswith("{") and len(tok) > 1)
def base(lhs):
"""The keys a mapping would have to take over to replace this command:
leading count/register and trailing {placeholders} removed; None when a
placeholder sits in the middle (e.g. "<C-K>{char1}{char2}" is fine,
"{char1}<BS>{char2}" is not)."""
t = tokens(lhs)
# Only a count or register can come before the keys; "{char1}<BS>{char2}"
# starts with a typed character, so no mapping can replace it.
while t and t[0] in ('["x]', "{count}"):
t.pop(0)
while t and is_ph(t[-1]):
t.pop()
if not t or any(is_ph(x) for x in t):
return None
return t
def starts_with(longer, shorter):
return len(longer) > len(shorter) and longer[: len(shorter)] == shorter
# ---------------------------------------------------------------------------
# Built-ins: index.txt
# ---------------------------------------------------------------------------
SECTIONS = {
"insert-index": ("i", "Insert mode"),
"normal-index": ("n", "Normal mode"),
"objects": ("o", "Text objects"),
"CTRL-W": ("n", "Window commands"),
"[": ("n", "Square bracket commands"),
"g": ("n", "g commands"),
"z": ("n", "z commands"),
"operator-pending-index": ("o", "Operator-pending mode"),
"visual-index": ("x", "Visual mode"),
"ex-edit-index": ("c", "Command-line editing"),
"terminal-mode-index": ("t", "Terminal mode"),
"ex-cmd-index": (":", "Ex commands"),
}
# help file -> category, for built-ins without a more specific rule below.
FILE_CAT = {
"motion.txt": "Motion", "change.txt": "Edit", "undo.txt": "Undo & repeat", "scroll.txt": "Scroll & view",
"windows.txt": "Window", "tabpage.txt": "Buffer & tab", "fold.txt": "Fold", "pattern.txt": "Search",
"insert.txt": "Insert", "visual.txt": "Visual", "cmdline.txt": "Command line", "quickfix.txt": "Quickfix & lists",
"tagsrch.txt": "Tags", "diff.txt": "Diff", "spell.txt": "Spell", "editing.txt": "Files", "terminal.txt": "Terminal",
"lsp.txt": "LSP & diagnostics", "diagnostic.txt": "LSP & diagnostics", "repeat.txt": "Register & macro",
"digraph.txt": "Insert", "map.txt": "Misc", "options.txt": "Misc", "various.txt": "Misc", "message.txt": "Misc",
"starting.txt": "Files", "helphelp.txt": "Help", "eval.txt": "Misc", "gui.txt": "Misc", "sign.txt": "Misc",
"if_pyth.txt": "Misc", "if_lua.txt": "Misc", "lua.txt": "Misc", "syntax.txt": "Misc", "autocmd.txt": "Misc",
"usr_41.txt": "Misc", "vimfn.txt": "Misc", "vimeval.txt": "Misc", "print.txt": "Misc", "remote.txt": "Misc",
"mbyte.txt": "Misc", "arabic.txt": "Misc", "rileft.txt": "Misc", "provider.txt": "Misc", "pi_netrw.txt": "Files",
"pi_spec.txt": "Misc", "treesitter.txt": "Misc", "news.txt": "Misc", "uganda.txt": "Help", "intro.txt": "Help",
}
OPERATORS = {"c", "d", "y", "<", ">", "!", "=", "g~", "gu", "gU", "g?", "gq", "gw", "g@", "zf", "gc"}
MARKS = re.compile(r"^(m|'|`|g'|g`|<C-O>|<C-I>|<Tab>|g;|g,|''|``|\['|\]'|\[`|\]`|'\[|'\]|`\[|`\]|'<|'>|`<|`>|'\"|`\"|'\^|`\^|'\.|`\.)")
REGISTERS = re.compile(r'^("|q|@|Q)')
def parse_tags(runtime):
tags = {}
for line in (Path(runtime) / "doc/tags").read_text(errors="replace").splitlines():
parts = line.split("\t")
if len(parts) >= 2:
tags[parts[0]] = parts[1]
return tags
def parse_index(runtime, tags):
lines = (Path(runtime) / "doc/index.txt").read_text().splitlines()
entries, section, in_table, cur, sub = [], None, False, None, None
def flush():
nonlocal cur
if cur:
cur["desc"] = re.sub(r"\s+", " ", cur["desc"]).strip()
if cur["desc"] and not cur["desc"].startswith("not used") and cur["desc"] != "reserved":
entries.append(cur)
cur = None
for raw in lines:
m = re.search(r"\*([^*\s]+)\*", raw)
if raw.startswith(tuple("0123456789")) and m:
flush()
names = re.findall(r"\*([^*\s]+)\*", raw)
section = next((n for n in names if n in SECTIONS), None)
in_table, sub = False, None
continue
if section is None:
continue
if raw.rstrip().endswith("~") and raw.startswith("-----"):
in_table = True
continue
if not in_table:
continue
if raw.startswith("====="):
flush()
section, in_table = None, False
continue
line = raw.expandtabs(8)
if not line.strip():
flush()
continue
indent = len(line) - len(line.lstrip())
if raw.startswith("'") and "\t" in raw:
# "'cedit' CTRL-F ...": an option name in the tag column.
raw = raw.split("\t", 1)[1].lstrip("\t")
elif indent == 0 and not raw.startswith("|"):
# Sub-heading inside a table ("commands in CTRL-X submode").
flush()
sub = re.sub(r"\s*\*[^*]+\*\s*", "", raw).replace("|", "").strip()
continue
if indent >= 24 and cur is not None:
cur["desc"] += " " + line.strip()
continue
if indent >= 24:
continue
flush()
m = re.match(r"^(?:\|([^|]+)\|)?\s*(\S.*)$", raw)
if not m:
continue
tag, body = m.group(1), m.group(2)
sep = re.search(r"\t+|\s{2,}", body)
if sep:
key, rest = body[: sep.start()].strip(), body[sep.end():]
else:
# Key column overflowed into the description with single spaces:
# keep key-like words ("CTRL-V {number}", "CTRL-\\ e {expr}").
words, key_words = body.split(" "), []
while words and (not key_words or len(words[0]) == 1
or re.match(r"^(CTRL-|<|\{)", words[0])):
key_words.append(words.pop(0))
key, rest = " ".join(key_words), " ".join(words)
note = ""
nm = re.match(r"^([12])\s+(.*)$", rest.strip())
if nm and section in ("normal-index", "CTRL-W", "[", "g", "z", "visual-index"):
note, rest = nm.group(1), nm.group(2)
mode, sect_name = SECTIONS[section]
cur = {"raw": key, "tag": tag, "note": note, "desc": rest, "section": sect_name, "sect": section, "mode": mode,
"sub": sub}
flush()
out = []
for e in entries:
if e["mode"] == ":":
out.append(ex_entry(e, tags))
continue
keys = index_keys(e["raw"])
tag = e["tag"]
if e["sect"] == "objects":
modes = ["x", "o"]
elif e["note"] == "1" and e["mode"] == "n":
modes = MOTION_MODES
else:
modes = [e["mode"]]
out.append({
"k": keys, "m": modes, "d": e["desc"], "s": "builtin",
"t": tag, "h": tags.get(tag) if tag else None, "sec": e["section"],
"cat": builtin_cat(e, keys, tags.get(tag, "") if tag else ""),
"mo": 1 if e["note"] == "1" else None, "ch": 1 if e["note"] == "2" else None,
"ctx": e["sub"][0].upper() + e["sub"][1:] if e["sub"] else None,
})
return out
def ex_entry(e, tags):
name = e["raw"]
return {
"k": name, "m": [":"], "d": e["desc"], "s": "builtin", "t": e["tag"],
"h": tags.get(e["tag"]) if e["tag"] else None, "sec": "Ex commands",
"cat": FILE_CAT.get(tags.get(e["tag"], ""), "Misc") if e["tag"] else "Misc", "ex": 1,
}
def builtin_cat(e, keys, helpfile):
if e["sect"] == "objects":
return "Text object"
if e["sect"] == "CTRL-W":
return "Window"
if e["sect"] == "ex-edit-index":
return "Command line"
if e["sect"] == "insert-index":
return "Insert"
if e["sect"] in ("normal-index", "g", "z", "visual-index", "operator-pending-index", "["):
if keys in OPERATORS or (e["sect"] == "visual-index" and keys in OPERATORS):
return "Operator"
if MARKS.match(keys) and e["sect"] != "visual-index":
return "Mark & jump"
if REGISTERS.match(keys) and helpfile in ("change.txt", "repeat.txt", "undo.txt"):
return "Register & macro"
cat = FILE_CAT.get(helpfile)
if cat == "Motion" and e["note"] != "1":
return "Mark & jump" if "jump" in e["desc"] or "mark" in e["desc"] else "Motion"
return cat or ("Motion" if e["note"] == "1" else "Misc")
# ---------------------------------------------------------------------------
# Live maps
# ---------------------------------------------------------------------------
def source_of(path, d):
"""(source id, short file label) for the file that set a mapping."""
if not path:
return "unknown", None
cfg, runtime = d["config"].rstrip("/") + "/", d["vimruntime"].rstrip("/") + "/"
packs = d["data"].rstrip("/") + "/site/pack/"
if path.startswith(cfg):
return "config", path[len(cfg):]
if path.startswith(runtime):
rel = path[len(runtime):]
if rel.startswith("ftplugin/"):
return "ftplugin", rel
if "matchit" in rel:
return "matchit", rel
return "neovim", rel
if path.startswith(packs):
m = re.match(r"[^/]+/(?:opt|start)/([^/]+)/(.*)", path[len(packs):])
if m:
return m.group(1), m.group(2)
if "/vimfiles/" in path or path.startswith("/usr/share/vim"):
return Path(path).stem + " (system)", path
return "other", path
def live_entries(d, curated_desc):
out = []
leader = d.get("leader") or "\\"
lead = canon("<Space>") if leader == " " else leader
def add(m, buffer_ctx=None):
lhs = m["lhs"]
if lhs.startswith("<Plug>") or lhs.startswith("<SNR>") or "<Plug>" in lhs[:1]:
return
src, file = source_of(m.get("file"), d)
key = canon(lhs)
desc = m.get("desc")
rhs = m.get("rhs")
help_tag = desc[6:].strip() if desc and desc.startswith(":help ") else None
# map_desc may carry a `ctx` ("markdown buffers") to target one buffer-local
# map; entries without one apply everywhere.
cd = next((curated_desc[t] for c in dict.fromkeys((buffer_ctx, None))
for t in ((src, m["mode"], key, c), (src, "*", key, c)) if t in curated_desc), {})
# The config's own desc wins (which-key shows it too) unless it is
# missing or only a ":help" pointer; category/notes always apply.
if cd.get("d") and (not desc or desc.startswith(":help") or cd.get("force")):
desc = cd["d"]
if not desc:
if rhs and rhs.startswith("<Plug>("):
desc = rhs[7:-1].replace("-", " ")
elif rhs:
desc = f"runs {rhs}"
else:
desc = "(disabled)" if not m.get("callback") else "(Lua function)"
if desc == "which_key_ignore" or (src == "which-key" and not cd.get("d")):
return # which-key's own trigger maps: they only show the popup
e = {
"k": key, "m": [m["mode"]], "d": desc, "s": src, "f": file, "l": m.get("line"),
"rhs": rhs if rhs and not rhs.startswith("<Plug>(leap") else None,
"nw": 1 if m.get("nowait") else None,
"cat": cd.get("cat"), "n": cd.get("n"), "e": cd.get("e"), "sl": cd.get("sl"),
}
if key.startswith(lead) and leader == " " and m["mode"] in ("n", "x", "s", "o"):
e["ld"] = 1
if help_tag:
e["t"] = help_tag
if buffer_ctx:
e["ctx"] = buffer_ctx
out.append(e)
for m in d["maps"]:
add(m)
for b in d["buffers"]:
for m in b["maps"]:
add(m, f"{b['filetype']} buffers")
return merge_modes(out)
def merge_modes(entries):
"""Collapse identical maps registered for several modes into one entry."""
merged, order = {}, []
for e in entries:
k = (e["k"], e["d"], e["s"], e.get("f"), e.get("l"), e.get("ctx"))
if k in merged:
for mode in e["m"]:
if mode not in merged[k]["m"]:
merged[k]["m"].append(mode)
else:
merged[k] = e
order.append(k)
return [merged[k] for k in order]
# ---------------------------------------------------------------------------
# Curated data
# ---------------------------------------------------------------------------
def load_curated():
cur = {"entries": [], "notes": [], "map_desc": [], "builtin": {}, "essentials": [], "commands": {}, "groups": {}}
for f in sorted((HERE / "curated").glob("*.json")):
data = json.loads(f.read_text())
for k in ("entries", "notes", "map_desc", "essentials"):
cur[k] += data.get(k, [])
for tag, fields in data.get("builtin", {}).items():
cur["builtin"].setdefault(tag, {}).update(fields) # several files may add to one tag
cur["commands"].update(data.get("commands", {}))
cur["groups"].update(data.get("groups", {}))
return cur
# ---------------------------------------------------------------------------
# Conflicts: what the config changes about stock Vim
# ---------------------------------------------------------------------------
def annotate(builtins, live):
by_mode_key = {}
for i, b in enumerate(builtins):
if b.get("ex"):
continue
bt = base(canon(b["k"]))
if bt is None:
continue
b["_t"] = bt
for mode in b["m"]:
by_mode_key.setdefault((mode, tuple(bt)), []).append(i)
live_by_mode = {}
for j, e in enumerate(live):
e["_t"] = tokens(e["k"])
if e.get("ctx"):
continue
for mode in e["m"]:
live_by_mode.setdefault(mode, {})[tuple(e["_t"])] = j
for j, e in enumerate(live):
for mode in e["m"]:
for i in by_mode_key.get((mode, tuple(e["_t"])), []):
builtins[i].setdefault("ov", []).append({"m": mode, "by": j})
e.setdefault("rep", []).append({"m": mode, "b": i})
for mode, maps in live_by_mode.items():
# Longer maps that a shorter `nowait` map makes unreachable.
for lhs, j in maps.items():
if live[j].get("nw"):
for other, k in maps.items():
if starts_with(list(other), list(lhs)):
live[k].setdefault("sh", []).append({"m": mode, "by": j})
# Complete built-in commands that now wait for 'timeoutlen' because a
# mapping extends them (e.g. "ga" once "gai"/"gao" exist).
for (bmode, bkey), idxs in by_mode_key.items():
if bmode != mode or bkey in maps:
continue
ext = [live[j]["k"] for lhs, j in maps.items() if starts_with(list(lhs), list(bkey))]
if ext:
for i in idxs:
if not is_ph(tokens(builtins[i]["k"])[-1]):
builtins[i].setdefault("wait", []).append({"m": mode, "ext": sorted(ext)[:6], "n": len(ext)})
for x in builtins + live:
x.pop("_t", None)
# ---------------------------------------------------------------------------
def main():
d = load_dump()
runtime = d["vimruntime"]
tags = parse_tags(runtime)
builtins = parse_index(runtime, tags)
cur = load_curated()
for b in builtins:
extra = cur["builtin"].get(f"{''.join(b['m'])}|{b['k']}") or cur["builtin"].get(b.get("t") or "")
if extra:
b.update({k: v for k, v in extra.items() if v is not None})
ess = {(e.get("t") or "", e.get("k") or "") for e in cur["essentials"]}
for b in builtins:
if (b.get("t") or "", "") in ess or ("", b["k"]) in ess:
b["e"] = 1
curated_desc = {(c["s"], c.get("m", "*"), canon(c["k"].replace("<leader>", "<Space>")), c.get("ctx")): c
for c in cur["map_desc"]}
live = live_entries(d, curated_desc)
annotate(builtins, live)
# Help links for the template: Neovim's own defaults describe themselves as
# ":help <tag>"; curated entries name a tag in "h". "hf" is the runtime help
# file holding that tag (None for plugin docs, which neovim.io doesn't host).
for e in live:
if e.get("t"):
e["hf"] = tags.get(e["t"])
for c in cur["entries"]:
if c.get("h"):
c["hf"] = tags.get(c["h"])
for e in live:
if not e.get("cat"):
group = next((g for g in sorted(cur["groups"], key=len, reverse=True)
if canon(g.replace("<leader>", "<Space>")) == e["k"][: len(canon(g.replace("<leader>", "<Space>")))]
and cur["groups"][g].get("cat")), None)
if group:
e["cat"] = cur["groups"][group]["cat"]
elif e.get("rep"):
e["cat"] = builtins[e["rep"][0]["b"]]["cat"]
else:
e["cat"] = "Misc"
commands = []
for c in d["commands"] + [dict(c, ctx=b["filetype"]) for b in d["buffers"] for c in b["commands"]]:
src, file = source_of(c.get("file"), d)
commands.append({"k": ":" + c["name"], "d": cur["commands"].get(c["name"]) or c.get("desc") or "",
"s": src, "f": file, "na": c.get("nargs"), "r": 1 if c.get("range") else None,
"ctx": c.get("ctx")})
plugins = sorted({p["name"] for p in d["plugins"] if p.get("active")})
data = {
"meta": {
"version": d["version"], "leader": d["leader"], "localleader": d["localleader"],
"date": date.today().isoformat(), "plugins": plugins, "options": d["options"],
"timeoutlen": d["options"]["timeoutlen"],
},
"builtins": builtins,
"live": live,
"curated": cur["entries"],
"notes": cur["notes"],
"groups": cur["groups"],
"commands": commands,
"picker": d.get("snacks_picker"),
"explorer": d.get("snacks_explorer"),
"blink": d.get("blink"),
"flash": d.get("flash"),
}
payload = json.dumps(data, ensure_ascii=False, separators=(",", ":")).replace("</", "<\\/")
template = (HERE / "cheatsheet.template.html").read_text().split("\n", 1)[1] # drop the template note
OUT.write_text(template.replace("/*DATA*/null", payload))
n_ov = sum(1 for b in builtins if b.get("ov"))
print(f"wrote {OUT.name}: {len(builtins)} built-ins ({n_ov} overridden), {len(live)} live maps, "
f"{len(cur['entries'])} curated, {len(commands)} commands, {len(cur['notes'])} notes")
if __name__ == "__main__":
main()