aboutsummaryrefslogtreecommitdiff
path: root/imports/codemirror/keymap/vim.js
diff options
context:
space:
mode:
Diffstat (limited to 'imports/codemirror/keymap/vim.js')
-rw-r--r--imports/codemirror/keymap/vim.js927
1 files changed, 673 insertions, 254 deletions
diff --git a/imports/codemirror/keymap/vim.js b/imports/codemirror/keymap/vim.js
index f8fa5e07..2aa6e0f7 100644
--- a/imports/codemirror/keymap/vim.js
+++ b/imports/codemirror/keymap/vim.js
@@ -1,21 +1,96 @@
1// Supported keybindings:
2//
3// Cursor movement:
4// h, j, k, l
5// e, E, w, W, b, B
6// Ctrl-f, Ctrl-b
7// Ctrl-n, Ctrl-p
8// $, ^, 0
9// G
10// ge, gE
11// gg
12// f<char>, F<char>, t<char>, T<char>
13// Ctrl-o, Ctrl-i TODO (FIXME - Ctrl-O wont work in Chrome)
14// /, ?, n, N TODO (does not work)
15// #, * TODO
16//
17// Entering insert mode:
18// i, I, a, A, o, O
19// s
20// ce, cb (without support for number of actions like c3e - TODO)
21// cc
22// S, C TODO
23// cf<char>, cF<char>, ct<char>, cT<char>
24//
25// Deleting text:
26// x, X
27// J
28// dd, D
29// de, db (without support for number of actions like d3e - TODO)
30// df<char>, dF<char>, dt<char>, dT<char>
31//
32// Yanking and pasting:
33// yy, Y
34// p, P
35// p'<char> TODO - test
36// y'<char> TODO - test
37// m<char> TODO - test
38//
39// Changing text in place:
40// ~
41// r<char>
42//
43// Visual mode:
44// v, V TODO
45//
46// Misc:
47// . TODO
48//
49
1(function() { 50(function() {
2 var count = ""; 51 var count = "";
3 var sdir = "f"; 52 var sdir = "f";
4 var buf = ""; 53 var buf = "";
5 var yank = 0; 54 var yank = 0;
6 var mark = []; 55 var mark = [];
56 var reptTimes = 0;
7 function emptyBuffer() { buf = ""; } 57 function emptyBuffer() { buf = ""; }
8 function pushInBuffer(str) { buf += str; }; 58 function pushInBuffer(str) { buf += str; }
9 function pushCountDigit(digit) { return function(cm) {count += digit;} } 59 function pushCountDigit(digit) { return function(cm) {count += digit;}; }
10 function popCount() { var i = parseInt(count); count = ""; return i || 1; } 60 function popCount() { var i = parseInt(count, 10); count = ""; return i || 1; }
61 function iterTimes(func) {
62 for (var i = 0, c = popCount(); i < c; ++i) func(i, i == c - 1);
63 }
11 function countTimes(func) { 64 function countTimes(func) {
12 if (typeof func == "string") func = CodeMirror.commands[func]; 65 if (typeof func == "string") func = CodeMirror.commands[func];
13 return function(cm) { for (var i = 0, c = popCount(); i < c; ++i) func(cm); } 66 return function(cm) { iterTimes(function () { func(cm); }); };
14 } 67 }
15 68
16 function iterObj(o, f) { 69 function iterObj(o, f) {
17 for (var prop in o) if (o.hasOwnProperty(prop)) f(prop, o[prop]); 70 for (var prop in o) if (o.hasOwnProperty(prop)) f(prop, o[prop]);
18 } 71 }
72 function iterList(l, f) {
73 for (var i in l) f(l[i]);
74 }
75 function toLetter(ch) {
76 // T -> t, Shift-T -> T, '*' -> *, "Space" -> " "
77 if (ch.slice(0, 6) == "Shift-") {
78 return ch.slice(0, 1);
79 } else {
80 if (ch == "Space") return " ";
81 if (ch.length == 3 && ch[0] == "'" && ch[2] == "'") return ch[1];
82 return ch.toLowerCase();
83 }
84 }
85 var SPECIAL_SYMBOLS = "~`!@#$%^&*()_-+=[{}]\\|/?.,<>:;\"\'1234567890";
86 function toCombo(ch) {
87 // t -> T, T -> Shift-T, * -> '*', " " -> "Space"
88 if (ch == " ") return "Space";
89 var specialIdx = SPECIAL_SYMBOLS.indexOf(ch);
90 if (specialIdx != -1) return "'" + ch + "'";
91 if (ch.toLowerCase() == ch) return ch.toUpperCase();
92 return "Shift-" + ch.toUpperCase();
93 }
19 94
20 var word = [/\w/, /[^\w\s]/], bigWord = [/\S/]; 95 var word = [/\w/, /[^\w\s]/], bigWord = [/\S/];
21 function findWord(line, pos, dir, regexps) { 96 function findWord(line, pos, dir, regexps) {
@@ -37,62 +112,172 @@
37 } 112 }
38 return {from: Math.min(start, end), to: Math.max(start, end)}; 113 return {from: Math.min(start, end), to: Math.max(start, end)};
39 } 114 }
40 function moveToWord(cm, regexps, dir, where) { 115 function moveToWord(cm, regexps, dir, times, where) {
41 var cur = cm.getCursor(), ch = cur.ch, line = cm.getLine(cur.line), word; 116 var cur = cm.getCursor();
42 while (true) { 117
43 word = findWord(line, ch, dir, regexps); 118 for (var i = 0; i < times; i++) {
44 ch = word[where == "end" ? "to" : "from"]; 119 var line = cm.getLine(cur.line), startCh = cur.ch, word;
45 if (ch == cur.ch && word.from != word.to) ch = word[dir < 0 ? "from" : "to"]; 120 while (true) {
46 else break; 121 // If we're at start/end of line, start on prev/next respectivly
122 if (cur.ch == line.length && dir > 0) {
123 cur.line++;
124 cur.ch = 0;
125 line = cm.getLine(cur.line);
126 } else if (cur.ch == 0 && dir < 0) {
127 cur.line--;
128 cur.ch = line.length;
129 line = cm.getLine(cur.line);
130 }
131 if (!line) break;
132
133 // On to the actual searching
134 word = findWord(line, cur.ch, dir, regexps);
135 cur.ch = word[where == "end" ? "to" : "from"];
136 if (startCh == cur.ch && word.from != word.to) cur.ch = word[dir < 0 ? "from" : "to"];
137 else break;
138 }
47 } 139 }
48 cm.setCursor(cur.line, word[where == "end" ? "to" : "from"], true); 140 return cur;
49 } 141 }
50 function joinLineNext(cm) { 142 function joinLineNext(cm) {
51 var cur = cm.getCursor(), ch = cur.ch, line = cm.getLine(cur.line); 143 var cur = cm.getCursor(), ch = cur.ch, line = cm.getLine(cur.line);
52 CodeMirror.commands.goLineEnd(cm); 144 CodeMirror.commands.goLineEnd(cm);
53 if (cur.line != cm.lineCount()) { 145 if (cur.line != cm.lineCount()) {
54 CodeMirror.commands.goLineEnd(cm); 146 CodeMirror.commands.goLineEnd(cm);
55 cm.replaceSelection(" ", "end"); 147 cm.replaceSelection(" ", "end");
56 CodeMirror.commands.delCharRight(cm); 148 CodeMirror.commands.delCharRight(cm);
57 }
58 }
59 function editCursor(mode) {
60 if (mode == "vim-insert") {
61 // put in your cursor css changing code
62 } else if (mode == "vim") {
63 // put in your cursor css changing code
64 } 149 }
65 } 150 }
66 function delTillMark(cm, cHar) { 151 function delTillMark(cm, cHar) {
67 var i = mark[cHar], l = cm.getCursor().line, start = i > l ? l : i, end = i > l ? i : l; 152 var i = mark[cHar];
153 if (i === undefined) {
154 // console.log("Mark not set"); // TODO - show in status bar
155 return;
156 }
157 var l = cm.getCursor().line, start = i > l ? l : i, end = i > l ? i : l;
68 cm.setCursor(start); 158 cm.setCursor(start);
69 for (var c = start; c <= end; c++) { 159 for (var c = start; c <= end; c++) {
70 pushInBuffer("\n"+cm.getLine(start)); 160 pushInBuffer("\n"+cm.getLine(start));
71 cm.removeLine(start); 161 cm.removeLine(start);
72 } 162 }
73 } 163 }
74 function yankTillMark(cm, cHar) { 164 function yankTillMark(cm, cHar) {
75 var i = mark[cHar], l = cm.getCursor().line, start = i > l ? l : i, end = i > l ? i : l; 165 var i = mark[cHar];
166 if (i === undefined) {
167 // console.log("Mark not set"); // TODO - show in status bar
168 return;
169 }
170 var l = cm.getCursor().line, start = i > l ? l : i, end = i > l ? i : l;
76 for (var c = start; c <= end; c++) { 171 for (var c = start; c <= end; c++) {
77 pushInBuffer("\n"+cm.getLine(c)); 172 pushInBuffer("\n"+cm.getLine(c));
78 } 173 }
79 cm.setCursor(start); 174 cm.setCursor(start);
80 } 175 }
176 function goLineStartText(cm) {
177 // Go to the start of the line where the text begins, or the end for whitespace-only lines
178 var cur = cm.getCursor(), firstNonWS = cm.getLine(cur.line).search(/\S/);
179 cm.setCursor(cur.line, firstNonWS == -1 ? line.length : firstNonWS, true);
180 }
81 181
182 function charIdxInLine(cm, cHar, motion_options) {
183 // Search for cHar in line.
184 // motion_options: {forward, inclusive}
185 // If inclusive = true, include it too.
186 // If forward = true, search forward, else search backwards.
187 // If char is not found on this line, do nothing
188 var cur = cm.getCursor(), line = cm.getLine(cur.line), idx;
189 var ch = toLetter(cHar), mo = motion_options;
190 if (mo.forward) {
191 idx = line.indexOf(ch, cur.ch + 1);
192 if (idx != -1 && mo.inclusive) idx += 1;
193 } else {
194 idx = line.lastIndexOf(ch, cur.ch);
195 if (idx != -1 && !mo.inclusive) idx += 1;
196 }
197 return idx;
198 }
199
200 function moveTillChar(cm, cHar, motion_options) {
201 // Move to cHar in line, as found by charIdxInLine.
202 var idx = charIdxInLine(cm, cHar, motion_options), cur = cm.getCursor();
203 if (idx != -1) cm.setCursor({line: cur.line, ch: idx});
204 }
205
206 function delTillChar(cm, cHar, motion_options) {
207 // delete text in this line, untill cHar is met,
208 // as found by charIdxInLine.
209 // If char is not found on this line, do nothing
210 var idx = charIdxInLine(cm, cHar, motion_options);
211 var cur = cm.getCursor();
212 if (idx !== -1) {
213 if (motion_options.forward) {