aboutsummaryrefslogtreecommitdiff
path: root/imports/codemirror/keymap/vim.js
diff options
context:
space:
mode:
Diffstat (limited to 'imports/codemirror/keymap/vim.js')
-rwxr-xr-ximports/codemirror/keymap/vim.js76
1 files changed, 76 insertions, 0 deletions
diff --git a/imports/codemirror/keymap/vim.js b/imports/codemirror/keymap/vim.js
new file mode 100755
index 00000000..e03e0128
--- /dev/null
+++ b/imports/codemirror/keymap/vim.js
@@ -0,0 +1,76 @@
1(function() {
2 var count = "";
3 function pushCountDigit(digit) { return function(cm) {count += digit;} }
4 function popCount() { var i = parseInt(count); count = ""; return i || 1; }
5 function countTimes(func) {
6 if (typeof func == "string") func = CodeMirror.commands[func];
7 return function(cm) { for (var i = 0, c = popCount(); i < c; ++i) func(cm); }
8 }
9
10 function iterObj(o, f) {
11 for (var prop in o) if (o.hasOwnProperty(prop)) f(prop, o[prop]);
12 }
13
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
45 var map = CodeMirror.keyMap.vim = {
46 "0": function(cm) {count.length > 0 ? pushCountDigit("0")(cm) : CodeMirror.commands.goLineStart(cm);},
47 "I": function(cm) {popCount(); cm.setOption("keyMap", "vim-insert");},
48 "G": function(cm) {cm.setOption("keyMap", "vim-prefix-g");},
49 catchall: function(cm) {/*ignore*/}
50 };
51 // Add bindings for number keys
52 for (var i = 1; i < 10; ++i) map[i] = pushCountDigit(i);
53 // Add bindings that are influenced by number keys
54 iterObj({"H": "goColumnLeft", "L": "goColumnRight", "J": "goLineDown", "K": "goLineUp",
55 "Left": "goColumnLeft", "Right": "goColumnRight", "Down": "goLineDown", "Up": "goLineUp",
56 "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");},
63 "U": "undo", "Ctrl-R": "redo", "Shift-4": "goLineEnd"},
64 function(key, cmd) { map[key] = countTimes(cmd); });
65
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
72 CodeMirror.keyMap["vim-insert"] = {
73 "Esc": function(cm) {cm.setOption("keyMap", "vim");},
74 fallthrough: ["default"]
75 };
76})();