Skip to content

Repository files navigation

vimcord

Modal vim-style editing for Discord's chat input, as a Vencord userplugin. Normal / insert / visual / replace modes, motions, operators, text objects, registers, repeat - right in the message box.

Installation

Vencord userplugins require building from source:

  1. Clone and set up Vencord:
    git clone https://github.com/Vendicated/Vencord
    cd Vencord
    pnpm i
  2. Clone this repo into src/userplugins/vimcord:
    git clone https://github.com/burneikis/vimcord src/userplugins/vimcord
  3. Build and inject:
    pnpm build
    pnpm inject
  4. Enable vimcord in Vencord's plugin settings and restart/reload Discord (Ctrl+R).

Testing

The vim logic is covered by a vitest suite that drives the real key dispatcher against a fake Slate editor (test/fakeEditor.ts), which applies the plugin's synthetic beforeinput events to an in-memory buffer the way Discord's Slate instance does. Expectations in test/vim-parity.spec.ts assert vim's behavior, so failures mean a divergence from vim (or a Slate-emulation gap in the fake).

npm install
npm test        # or: npm run test:watch

Not covered: the Discord/Slate integration itself (editor.ts event timing, cursor/statusline rendering) - test those manually in Discord.

Usage

Focus the chat box and press Escape to enter NORMAL mode. A mode indicator (badge and/or colored border, configurable) shows the current mode, and a block cursor is drawn in NORMAL mode.

Supported keys

Modes

  • Escape - NORMAL mode; i a I A o O - enter INSERT mode
  • v - charwise VISUAL mode
  • R - replace (overtype) mode, r<char> - replace single char

Motions (all accept counts, e.g. 3w, 5j)

  • h j k l, 0 ^ $
  • w b e / W B E
  • gg G
  • f F t T and ; ,

Operators / edits

  • d c y + motion or text object (dw, ce, yy, dd, di", ca(, daw, ...)
  • x X s D C S
  • p P paste from the yank register
  • ~ toggle case, J join lines
  • u / Ctrl-r undo/redo (forwarded to Discord's native history)
  • . repeat last change

Text objects: iw aw and quote/bracket pairs (i", a", i(, a(, etc.).

Settings

  • Default mode on focus - insert (default), normal, or remember last mode per editor
  • Escape in NORMAL mode - swallow, pass through to Discord (closes reply/edit), or require double-Escape
  • Mode indicator style - badge, border, both, or none
  • Yank to clipboard - also copy yanked/deleted text to the system clipboard (on by default; yanks always go to the internal register)

How it works

Discord's chat box is a Slate.js contenteditable. vimcord installs a single capturing keydown listener; when the focused element is a Discord Slate textbox and the key should be handled (NORMAL mode, or Escape in INSERT), the event is consumed and fed into a vim state machine. Edits go through input events / execCommand so Slate's model stays in sync - no raw DOM mutation, no fragile webpack patches.

Mode state is tracked per editor, so the main chat box, message-edit boxes, etc. each keep their own mode.

Notes / limitations

  • Autocomplete popups (mentions, emoji) are not specially handled yet; in NORMAL mode keys are consumed by vimcord. Use INSERT mode to interact with them.
  • Insert-mode typing is not recorded by . repeat; only the change command itself is replayed.
  • Rebuild Vencord (pnpm build) and reload Discord after updating the plugin.

License

GPL-3.0, matching Vencord.

About

vim mode for discord input boxes in vencord

Resources

Stars

Watchers

Forks

Releases

Packages

Contributors

Languages