Bug: Insert Mode Multi-Key Mappings Delete Character Before Cursor

Open
#238 0 comments 0 reactions 0 assignees View on GitHub

Nobody has claimed this yet.

Assessment

Difficulty
3/5
Estimated time
1-2 days
Newbie friendliness
48/100
Issue type
Bug
Clarity
Mostly clear
Activity status
Stale
Tech stack
javascript, react
Domain
frontend

Research direction

Start at the Vim.map("jk", "A", "insert") entry point in codemirror-vim and reproduce the behavior described with the provided React and CodeMirror example. Compare the multi-key mapping with the working single-character mapping; done means the character before the cursor remains intact while the mapped action runs.

Written by the indexing model from the issue text.

Description

Problem

any multi-key insert mode mapping (e.g., Vim.map("jk", "<C-o>A", "insert")) causes the character before the cursor to be deleted when the mapping is triggered.

Example:

$ represents the cursor.

Cursor is after h: th$is is a line
If you type jk, you get: tis is a line$
The h disappears.

Steps to Reproduce
  1. Add a mapping: Vim.map("jk", "<C-o>A", "insert")
  2. In insert mode, place the cursor after a character (e.g., th$is is a line)
  3. Type "jk"
Expected

Mapped action runs, buffer remains unchanged except for the intended command.

Actual

The character before the cursor is deleted before the mapped action runs.

Note

Vim.map("g", "<C-o>A", "insert") works as expected.
Since 'g' is a single character, It works.

Code
import { useEffect, useRef } from "react";
import { EditorView, basicSetup } from "codemirror";
import { Vim, vim } from "@replit/codemirror-vim";

function App() {
  const editorRef = useRef(null);
  const viewRef = useRef(null); // Store the EditorView instance

  Vim.map("jj", "<Esc>", "insert");
  Vim.map("kk", "<C-o>l", "insert");

  useEffect(() => {
    if (editorRef.current && !viewRef.current) {
      viewRef.current = new EditorView({
        doc: "",
        extensions: [
          vim(), // Vim keymap support
          basicSetup, // Default setup (includes line numbers, history, etc.)
        ],
        parent: editorRef.current, // Mount the editor here
      });
    }

    // Optional cleanup if needed
    return () => {
      if (viewRef.current) {
        viewRef.current.destroy();
        viewRef.current = null;
      }
    };
  }, []);

  return (
    <div className="bg-neutral-900 h-screen grid place-items-center">
      <div
        ref={editorRef}
        className="w-full max-w-3xl h-[500px] bg-white rounded-md shadow-lg"
      />
    </div>
  );
}

export default App;

Dominant language
JavaScript
Stars
470
Forks
53
PR merge metrics
No merged PRs in 30d

Contributor guide

No contributing guide indexed for this repository

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. Open a pull request that references the issue number.

More from replit/codemirror-vim

All issues in replit/codemirror-vim

Similar issues

More JavaScript issues

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.