replit/codemirror-vim

Cursor moves past end of line in vim

Opened this issue · 2 comments

Copied from codemirror/codemirror5#5422:

To reproduce

  • Open the vim demo.
  • Enter normal mode.
  • Click past the end of a line.

Expected

Cursor should be over the last character in the line.
expected

Actual

Cursor moves past the last character in the line.
actual
Interestingly, if you move the cursor left, it goes to the correct position, and then it can't be moved right again, so it looks like CodeMirror already knows that this is an illegal position.

I'd like to help with a pull request, but I'm not sure where to start- any pointers would be appreciated :)

We noticed this too, and I believe it's leading to another bug where the cursor will flash the next character of the wrapped line:

Screen capture of clicking on the space at the end of a wrapped line which then starts flashing the next character of the wrapped line

Minimal reproduction in this CodeSandbox.

My guess is that this is because the cursor shouldn't be allowed in this position in the first place - as noted above, you cannot put the cursor here with the keyboard only - and therefore it's calculating the underlying character incorrectly.

i've scribbled up an small extension that patches this problem: codemirror.net/try.

i may contribute it to core here when i have time. the gist is the below:

EditorState.transactionFilter.of(tr => {
  const { vim } = getCM(view).state
  const insertMode = vim.insertMode
  const { to: selectionTo, from: selectionFrom } = tr.newSelection.main
  const noSelection = selectionTo === selectionFrom
  const { from: lineFrom } = tr.newDoc.lineAt(tr.newSelection.main.from)
  const { to: lineTo } = tr.newDoc.lineAt(tr.newSelection.main.to)
  const isEmpty = lineTo === lineFrom
  if (!isEmpty && noSelection && !insertMode && selectionTo >= lineTo) {
    tr.newSelection.main.to = lineTo - 1
  }
  if (!isEmpty && noSelection && !insertMode && selectionFrom >= lineTo) {
    tr.newSelection.main.from = lineTo - 1
  }
  return [tr]
}),

cheers! cc @nakulj and @40thieves.