Skip to content

[Feature]: Vim keybindings in the visual and Markdown source editors #578

Description

@amikofalvy

Summary

Add opt-in Vim keybindings (modal editing) to both document editing modes, the visual editor and the Markdown source editor: normal/insert/visual modes, hjkl navigation, and composable operators/motions (dd, ciw, / search) alongside the existing standard shortcuts.

Credit: originally suggested by @lmist in our Discord ("looking to add (hopefully) vim key integration"). On follow-up they confirmed the ask covers both the visual and source editors.

Motivation

Vim-style modal editing is a recurring power-user requirement for markdown and knowledge tools: the VSCodeVim extension has ~8M installs, Obsidian ships a native vim mode, and Notion's lack of one has spawned multiple community browser extensions. OpenKnowledge's audience (git-backed, markdown-native, agent-integrated) overlaps heavily with that crowd. It would be off by default, so there is zero impact on anyone who doesn't opt in.

Proposed approach: two phases

The two editors sit on different engines with very different vim maturity, so this splits naturally.

Phase 1: Markdown source editor. The source editor (packages/app/src/editor/SourceEditor.tsx) is CodeMirror 6, where @replit/codemirror-vim is the mature, well-trodden vim layer (same engine family Obsidian uses). Scope:

  • A new user-scope setting in the Settings dialog, off by default. A project-scoped value would force modal editing on every collaborator.
  • Lazy-loaded: the vim engine ships in its own chunk and only loads when the setting is enabled, keeping the main bundle inside the size budget.
  • Wired through a CodeMirror Compartment, the same live-reconfigure pattern the source editor already uses for theme/word-wrap/placeholder, so toggling applies to open editors without losing state.

Phase 2: visual editor. The visual editor is Tiptap/ProseMirror, where no production-grade vim layer exists: Tiptap maintainers have declined to build one in, and community prior art (vimirror, prose-motions) is early-stage. This phase needs a spike first. The realistic shape is a curated vim subset (modal navigation, core motions/operators/text-objects within text blocks) rather than full emulation, because block-structured documents (tables, embeds, nested nodes) don't map 1:1 onto vim's line/character model. The spike should decide whether to build on one of the community extensions or implement the subset directly against ProseMirror commands.

Out of scope

  • Read-only CodeMirror surfaces (diff view, file viewer).
  • Full vim emulation parity in the visual editor. Registers, macros, and ex-commands there are explicitly non-goals for phase 2.

Open questions

  • Esc semantics: vim needs Esc for mode switching; the editor uses Esc for focus release. Likely resolution: vim consumes Esc in insert/visual mode, and a second Esc in normal mode blurs (matches Obsidian/VS Code vim behavior). Should be pinned with a test.
  • Mode continuity: when switching visual/source on the same doc, should the current vim mode (normal/insert) carry over?
  • Should nested code-block editors inside the visual editor get vim mode with phase 1's engine, since they're also CodeMirror?
  • Verify vim's u/Ctrl-r undo routes through the collaborative undo manager.

Metadata

Metadata

Assignees

No one assigned

    Labels

    Type

    No type

    Fields

    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions