Hacktoberfest 2026:メンテナが10月に向けて印を付けた、オープンで初心者向けの issue。 Hacktoberfest の issue を見る

[Bug] Exiting Visual mode at end of line leaves the Normal-mode cursor past the final character

オープン
#277 コメント 0 件 リアクション 0 件 担当者 0 名 GitHub で見る

まだ誰も着手していません。

評価

難易度
3/5
見積もり時間
1〜2日
初心者へのやさしさ
65/100
issue の種類
バグ
明瞭さ
明確に書かれている
活発さ
活発
技術スタック
javascript, vim
領域
devtools

調査の方向性

The bug is in the exitVisualMode function in packages/codemirror-vim-core/vim.js. Start by reading the reproduction steps and the provided code snippet to understand the cursor behavior. Examine the clipCursorToContent helper and how visual mode flags are cleared. The candidate fix shows the necessary reordering of operations. Test the fix with the provided minimal setup and check edge cases like empty lines and supplementary characters.

索引モデルが issue の本文から書いたものです。

説明

Related: #38 reports entering an invalid end-of-line cursor position by clicking with the mouse. This report reproduces a similar symptom entirely through Vim keys and identifies a separate path in exitVisualMode.

Versions and environment

  • @replit/codemirror-vim: 6.4.0
  • @replit/codemirror-vim-core: 0.1.0
  • @codemirror/state: 6.7.5
  • @codemirror/view: 6.43.12
  • Reproduced in native macOS WebKit, both with a bare CodeMirror editor and in an application integration.

Reproduction

  1. Start with a single line containing alpha, with the cursor on a in Normal mode.
  2. Press v, then press l five times to reach the position after the final character.
  3. Press Escape.
  4. Press l once more.

After step 3, the Normal-mode cursor remains at zero-based column 5, after the final a. Step 4 moves it backward to column 4 despite being a rightward motion.

Expected: Escape should leave the Normal-mode cursor at column 4 immediately, and the following l should not move it. Unconfigured Vim behaves this way.

Minimal setup and programmatic reproduction:

import { EditorView, drawSelection } from '@codemirror/view';
import { vim, Vim, getCM } from '@replit/codemirror-vim';

const view = new EditorView({
  doc: 'alpha',
  extensions: [vim(), drawSelection()],
  parent: document.body,
});

const cm = getCM(view);
for (const key of ['v', 'l', 'l', 'l', 'l', 'l', '<Esc>']) {
  Vim.handleKey(cm, key, 'user');
}
console.log(cm.getCursor()); // Actual: { line: 0, ch: 5 }; expected ch: 4
Vim.handleKey(cm, 'l', 'user');
console.log(cm.getCursor()); // { line: 0, ch: 4 }

Apparent cause and candidate fix

In packages/codemirror-vim-core/vim.js, exitVisualMode calls clipCursorToContent before clearing vim.visualMode. That helper permits the line-break position while Visual mode is active, so it uses Visual-mode bounds for the resulting Normal-mode cursor.

Moving the cursor-clipping block after clearing the Visual-mode flags corrects this reproduction. updateLastSelection must still run before clearing the flags so gv retains the previous selection:

function exitVisualMode(cm, moveHead) {
  var vim = cm.state.vim;
  updateLastSelection(cm, vim);
  vim.visualMode = false;
  vim.visualLine = false;
  vim.visualBlock = false;
  if (moveHead !== false) {
    cm.setCursor(clipCursorToContent(cm, vim.sel.head));
  }
  if (!vim.insertMode) CM.signal(cm, "vim-mode-change", {mode: "normal"});
}

Local checks with that change covered nonempty and empty lines, a supplementary-plane emoji, gv, visual yank, linewise put, and undo.

主要言語
JavaScript
スター
477
フォーク
55
PR マージ指標
30日以内にマージされた PR はありません

環境構築

  • Dockerfile・Docker Compose ファイルなし
  • プルリクエストのテンプレートあり
  • コントリビューションガイドなし

はじめの一歩

  1. issue を最後まで読み、次にプロジェクトのコントリビューションガイドを読みます。
  2. 着手することを issue にコメントします — 二人が同じ作業をするのを防げます。
  3. リポジトリをフォークし、ブランチを切って変更します。
  4. issue 番号を参照したプルリクエストを送ります。

replit/codemirror-vim のほかの issue

replit/codemirror-vim の issue をすべて見る

似ている issue

JavaScript の issue をもっと見る

新しい issue をメールで受け取る

初心者向けの GitHub issue を短くまとめたダイジェスト。