Skip to content

Commit f01ee93

Browse files
committed
Implement per-word (B/E/W/GE) movement in vim mode
1 parent 63f7ce2 commit f01ee93

File tree

1 file changed

+44
-0
lines changed

1 file changed

+44
-0
lines changed

keymap/vim.js

Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,9 +11,41 @@
1111
for (var prop in o) if (o.hasOwnProperty(prop)) f(prop, o[prop]);
1212
}
1313

14+
var word = [/\w/, /[^\w\s]/], bigWord = [/\S/];
15+
function findWord(line, pos, dir, regexps) {
16+
var stop = 0, next = -1;
17+
if (dir > 0) { stop = line.length; next = 0; }
18+
var start = stop, end = stop;
19+
// Find bounds of next one.
20+
outer: for (; pos != stop; pos += dir) {
21+
for (var i = 0; i < regexps.length; ++i) {
22+
if (regexps[i].test(line.charAt(pos + next))) {
23+
start = pos;
24+
for (; pos != stop; pos += dir) {
25+
if (!regexps[i].test(line.charAt(pos + next))) break;
26+
}
27+
end = pos;
28+
break outer;
29+
}
30+
}
31+
}
32+
return {from: Math.min(start, end), to: Math.max(start, end)};
33+
}
34+
function moveToWord(cm, regexps, dir, where) {
35+
var cur = cm.getCursor(), ch = cur.ch, line = cm.getLine(cur.line), word;
36+
while (true) {
37+
word = findWord(line, ch, dir, regexps);
38+
ch = word[where == "end" ? "to" : "from"];
39+
if (ch == cur.ch && word.from != word.to) ch = word[dir < 0 ? "from" : "to"];
40+
else break;
41+
}
42+
cm.setCursor(cur.line, word[where == "end" ? "to" : "from"], true);
43+
}
44+
1445
var map = CodeMirror.keyMap.vim = {
1546
"0": function(cm) {count.length > 0 ? pushCountDigit("0")(cm) : CodeMirror.commands.goLineStart(cm);},
1647
"I": function(cm) {popCount(); cm.setOption("keyMap", "vim-insert");},
48+
"G": function(cm) {cm.setOption("keyMap", "vim-prefix-g");},
1749
catchall: function(cm) {/*ignore*/}
1850
};
1951
// Add bindings for number keys
@@ -22,9 +54,21 @@
2254
iterObj({"H": "goColumnLeft", "L": "goColumnRight", "J": "goLineDown", "K": "goLineUp",
2355
"Left": "goColumnLeft", "Right": "goColumnRight", "Down": "goLineDown", "Up": "goLineUp",
2456
"Backspace": "goCharLeft", "Space": "goCharRight",
57+
"B": function(cm) {moveToWord(cm, word, -1, "end");},
58+
"E": function(cm) {moveToWord(cm, word, 1, "end");},
59+
"W": function(cm) {moveToWord(cm, word, 1, "start");},
60+
"Shift-B": function(cm) {moveToWord(cm, bigWord, -1, "end");},
61+
"Shift-E": function(cm) {moveToWord(cm, bigWord, 1, "end");},
62+
"Shift-W": function(cm) {moveToWord(cm, bigWord, 1, "start");},
2563
"U": "undo", "Ctrl-R": "redo", "Shift-4": "goLineEnd"},
2664
function(key, cmd) { map[key] = countTimes(cmd); });
2765

66+
CodeMirror.keyMap["vim-prefix-g"] = {
67+
"E": countTimes(function(cm) { moveToWord(cm, word, -1, "start");}),
68+
"Shift-E": countTimes(function(cm) { moveToWord(cm, bigWord, -1, "start");}),
69+
auto: "vim", catchall: function(cm) {/*ignore*/}
70+
};
71+
2872
CodeMirror.keyMap["vim-insert"] = {
2973
"Esc": function(cm) {cm.setOption("keyMap", "vim");},
3074
fallthrough: ["default"]

0 commit comments

Comments
 (0)