marijnh/CodeMirror — pull request #1262 by metatheos (2013-02-18 20:25:48+00:00)
Title: [vim keymap] Visual mode rewrite and other changes

My second batch of changes, containing the remaining additions from my local setup. Should also fix some problems discussed in Issue #1246.

Changes
-------

1. New `moveByLinesToFirstNonWhiteSpaceCharacter`, used to implement the motions `+` (move `{repeat}` lines down, then to the first non-whitespace-character on that line), `-` (same for up) and `_` (same as `+` but with repeat reduced by 1, so with a repeat of 1 it behaves like `^`).
2. Some commands require the user to input a character to operate on. Previously pressing any handled special key (like `Enter`, `Space` or `Down`) would pass it on as string (see Issue #1246). These keys are now converted to a printable character if possible and rejected otherwise.
3. If there is text selected, `r{character}` replaces all individual characters in the selection by `{character}`, while leaving linebreaks intact. Special case as by vim help is `\n` as `{character}`, which creates only one linebreak for an `r` operation.
4. Visual mode is significantly changed, using some of the properties of CodeMirror v3. Notes below.

DIY-Example: Inputting `ggOTitleyypVr=` (with `` being the escape-key) should now behave just as it does in vim.

Notes on moveByLinesToFirstNonWhiteSpaceCharacter
-------------------------------------------------

I'm on the fence about whether to keep `moveByLinesToFirstNonWhiteSpaceCharacter` or merge it with `moveToFirstNonWhiteSpaceCharacter`. Merging means there would be one less motion, but instead one with an `if` at the start picking between the two code paths. I also find the name to be obscenely long. @mightyguava what would you prefer here?

Notes on visual mode (selection)
--------------------------------

Vim's cursor is not between characters but on one. This also has implications on the selection model. For the beginning of the selection the left side of the cursor is used, while for the end it is the right side. This requires `sel.to` to be incremented by 1 from the position CodeMirror's `setSelection` would place it at. Even more of a special case is linewise selection. Here `sel.from` is moved to the first character of the line, while `sel.to` is moved behind the last one.

CodeMirror as it is doesn't seem to require `sel.from` and `sel.to` to be either `sel.anchor` or `sel.head`. I'm not sure if I should expect this special case to be stable and especially whether expecting @marijnh to maintain this rather exotic use-case is fair. I am replicating `setSelection`'s behavior for now in an own function ([vim.js:1511](https://github.com/metatheos/CodeMirror/blob/7bfb17ec7dd1977388cced4ddd10affc54e81f99/keymap/vim.js#L1511)) and adapt the values at the end. From my testing it seemed to work out quite well. The only problem I ran into is how CodeMirror restores selection on undo, which is a separate issue I'll look into as well.

I made one change to `codemirror.css`. The reason is that setting `showCursorWhenSelecting` doesn't help if the cursor is covered by the selection (selection has `z-index` set to 1).