SLOPSHOPPER

vim-keys

/vim toggles a pane with a beginner cheat sheet for Neovim + NvChad keys. /vim <word> filters it.

newpanecommand
v0.1.0MITupdated 2026-10-09AliakbarNateghi/cc-vim-keys
A shopper browsing a rack in a slop shop
Preview · a replayed session in a sandbox
claude · ~/work/app · vim-keys
│ ┃ Vim / NvChad keys ✕ › fix the failing auth test and add an audit log call │ ┃ │ ┃ Modes and saving ⏺ Read(src/auth.ts) │ ┃ i insert mode ⎿ Read 6 lines │ ┃ Esc back to normal mode ⏺ Update(src/auth.ts) │ ┃ :w save ⎿ Added 2 lines, removed 1 line │ ┃ :q quit ⏺ Bash(bun test) │ ┃ :wq save and quit ⎿ 3 pass, 1 fail │ ┃ :q! quit, drop changes │ ┃ Moving ● Done. refresh now rejects expired claims and logs an audit event. │ ┃ h j k l left down up right │ ┃ w b next / prev word ✻ Worked for 42s · done 4:20 PM │ ┃ gg G top / bottom of file │ ┃ 0 $ start / end of line › /vim │ ┃ Ctrl-d Ctrl-u half page down / up ⎿ vim-keys: Vim keys pane opened. │ ┃ % jump to matching bracket │ ┃ Editing │ ┃ dd delete (cut) line │ ┃ yy copy (yank) line │ ┃ p paste after cursor │ ┃ u undo │ ┃ Ctrl-r redo │ ┃ . repeat last change │ ┃ ciw change inner word │ ┃ x delete char │ ┃ v / V visual char / line ────────────────────────────────────────────────────────────────────────────────────────────────────────────────────── › ? for shortcuts

Draws

Pane · Vim / NvChad keys
Modes and saving i insert mode Esc back to normal mode :w save :q quit :wq save and quit :q! quit, drop changes Moving h j k l left down up right w b next / prev word gg G top / bottom of file 0 $ start / end of line Ctrl-d Ctrl-u half page down / up % jump to matching bracket Editing dd delete (cut) line yy copy (yank) line p paste after cursor u undo Ctrl-r redo . repeat last change ciw change inner word x delete char v / V visual char / line Search /text search for text n N next / prev match * search word under cursor :%s/a/b/g replace a with b Files (NvChad) Space ff find files Space fw live grep Space fo recent files Ctrl-n file tree Tab next buffer Shift-Tab prev buffer Space x close buffer Windows Ctrl-h/j/k/l move between splits :vsp vertical split :sp horizontal split Terminal and help Space h horizontal terminal Space v vertical terminal Space ch cheatsheet Space th themes
README

vim-keys

A Claude Code pane with a beginner cheat sheet for Neovim + NvChad v2.5 (leader = Space).

  • /vim opens or closes the "Vim / NvChad keys" pane
  • /vim <word> shows only the lines with that word, e.g. /vim buffer

Sections: modes and saving, moving, editing, search, files (NvChad), windows, terminal and help. About 40 columns wide.

Install

/plugin install vim-keys --marketplace AliakbarNateghi/cc-vim-keys

Answer y to add the marketplace, then pick a scope.

Source 2 files
hooks/register.tsx 111 lines
1import { atom, read, update } from 'claude-code'
2import type { Register } from 'claude-code'
3
4const PANE = 'vim-keys'
5const TITLE = 'Vim / NvChad keys'
6const filter = atom({ plugin: 'vim-keys', key: 'filter' } as const, '')
7
8// Checked against NvChad v2.5 lua/nvchad/mappings.lua. Leader = Space.
9export const SHEET: [string, [string, string][]][] = [
10  ['Modes and saving', [
11    ['i', 'insert mode'],
12    ['Esc', 'back to normal mode'],
13    [':w', 'save'],
14    [':q', 'quit'],
15    [':wq', 'save and quit'],
16    [':q!', 'quit, drop changes'],
17  ]],
18  ['Moving', [
19    ['h j k l', 'left down up right'],
20    ['w b', 'next / prev word'],
21    ['gg G', 'top / bottom of file'],
22    ['0 $', 'start / end of line'],
23    ['Ctrl-d Ctrl-u', 'half page down / up'],
24    ['%', 'jump to matching bracket'],
25  ]],
26  ['Editing', [
27    ['dd', 'delete (cut) line'],
28    ['yy', 'copy (yank) line'],
29    ['p', 'paste after cursor'],
30    ['u', 'undo'],
31    ['Ctrl-r', 'redo'],
32    ['.', 'repeat last change'],
33    ['ciw', 'change inner word'],
34    ['x', 'delete char'],
35    ['v / V', 'visual char / line'],
36  ]],
37  ['Search', [
38    ['/text', 'search for text'],
39    ['n N', 'next / prev match'],
40    ['*', 'search word under cursor'],
41    [':%s/a/b/g', 'replace a with b'],
42  ]],
43  ['Files (NvChad)', [
44    ['Space ff', 'find files'],
45    ['Space fw', 'live grep'],
46    ['Space fo', 'recent files'],
47    ['Ctrl-n', 'file tree'],
48    ['Tab', 'next buffer'],
49    ['Shift-Tab', 'prev buffer'],
50    ['Space x', 'close buffer'],
51  ]],
52  ['Windows', [
53    ['Ctrl-h/j/k/l', 'move between splits'],
54    [':vsp', 'vertical split'],
55    [':sp', 'horizontal split'],
56  ]],
57  ['Terminal and help', [
58    ['Space h', 'horizontal terminal'],
59    ['Space v', 'vertical terminal'],
60    ['Space ch', 'cheatsheet'],
61    ['Space th', 'themes'],
62  ]],
63]
64
65// Section headers (h) and key lines; a word keeps only the lines containing it.
66export function lines(word: string): { text: string; h?: boolean }[] {
67  const w = word.trim().toLowerCase()
68  return SHEET.flatMap(([title, rows]) => {
69    const hits = rows
70      .map(([key, what]) => `${key.padEnd(13)} ${what}`)
71      .filter(line => line.toLowerCase().includes(w))
72    return hits.length ? [{ text: title, h: true }, ...hits.map(text => ({ text }))] : []
73  })
74}
75
76export const register: Register = on => {
77  on('session.start', async ($, e, next) => {
78    await $.command.register({
79      name: 'vim',
80      description: 'Toggle the Vim / NvChad keys pane; /vim <word> filters it',
81      argumentHint: '[word]',
82    })
83    return next(e)
84  })
85
86  on('command.run', { command: 'vim' }, async ($, e) => {
87    const word = e.args.trim()
88    const isOpen = (await $.ui.panes()).some(p => p.id === PANE)
89    if (!word && isOpen) {
90      await $.ui.close({ id: PANE })
91      return { text: 'Vim keys pane closed.' }
92    }
93    await update($, filter, () => word)
94    await $.ui.open({ id: PANE, title: TITLE })
95    return { text: word ? `Vim keys filtered by "${word}".` : 'Vim keys pane opened.' }
96  })
97
98  on('ui.render', { component: 'Pane', requestId: PANE }, async ($, e) => {
99    const { Box, Text } = $.ui.resolve(e)
100    const word = await read($, filter)
101    const shown = lines(word)
102    return (
103      <Box flexDirection="column">
104        {word && <Text dimColor>filter: {word}</Text>}
105        {shown.length === 0 && <Text dimColor>No key matches "{word}".</Text>}
106        {shown.map(l => (l.h ? <Text bold>{l.text}</Text> : <Text>{l.text}</Text>))}
107      </Box>
108    )
109  })
110}
111
types/index.d.ts 7 lines
1declare module 'claude-code' {
2  interface PluginState {
3    'vim-keys': { filter: Filter }
4  }
5}
6export type Filter = string
7