browser/devtools/sourceeditor/test/cm_vim_test.js

changeset 0
6474c204b198
equal deleted inserted replaced
-1:000000000000 0:add2654104bb
1 var code = '' +
2 ' wOrd1 (#%\n' +
3 ' word3] \n' +
4 'aopop pop 0 1 2 3 4\n' +
5 ' (a) [b] {c} \n' +
6 'int getchar(void) {\n' +
7 ' static char buf[BUFSIZ];\n' +
8 ' static char *bufp = buf;\n' +
9 ' if (n == 0) { /* buffer is empty */\n' +
10 ' n = read(0, buf, sizeof buf);\n' +
11 ' bufp = buf;\n' +
12 ' }\n' +
13 '\n' +
14 ' return (--n >= 0) ? (unsigned char) *bufp++ : EOF;\n' +
15 ' \n' +
16 '}\n';
17
18 var lines = (function() {
19 lineText = code.split('\n');
20 var ret = [];
21 for (var i = 0; i < lineText.length; i++) {
22 ret[i] = {
23 line: i,
24 length: lineText[i].length,
25 lineText: lineText[i],
26 textStart: /^\s*/.exec(lineText[i])[0].length
27 };
28 }
29 return ret;
30 })();
31 var endOfDocument = makeCursor(lines.length - 1,
32 lines[lines.length - 1].length);
33 var wordLine = lines[0];
34 var bigWordLine = lines[1];
35 var charLine = lines[2];
36 var bracesLine = lines[3];
37 var seekBraceLine = lines[4];
38
39 var word1 = {
40 start: { line: wordLine.line, ch: 1 },
41 end: { line: wordLine.line, ch: 5 }
42 };
43 var word2 = {
44 start: { line: wordLine.line, ch: word1.end.ch + 2 },
45 end: { line: wordLine.line, ch: word1.end.ch + 4 }
46 };
47 var word3 = {
48 start: { line: bigWordLine.line, ch: 1 },
49 end: { line: bigWordLine.line, ch: 5 }
50 };
51 var bigWord1 = word1;
52 var bigWord2 = word2;
53 var bigWord3 = {
54 start: { line: bigWordLine.line, ch: 1 },
55 end: { line: bigWordLine.line, ch: 7 }
56 };
57 var bigWord4 = {
58 start: { line: bigWordLine.line, ch: bigWord1.end.ch + 3 },
59 end: { line: bigWordLine.line, ch: bigWord1.end.ch + 7 }
60 };
61
62 var oChars = [ { line: charLine.line, ch: 1 },
63 { line: charLine.line, ch: 3 },
64 { line: charLine.line, ch: 7 } ];
65 var pChars = [ { line: charLine.line, ch: 2 },
66 { line: charLine.line, ch: 4 },
67 { line: charLine.line, ch: 6 },
68 { line: charLine.line, ch: 8 } ];
69 var numChars = [ { line: charLine.line, ch: 10 },
70 { line: charLine.line, ch: 12 },
71 { line: charLine.line, ch: 14 },
72 { line: charLine.line, ch: 16 },
73 { line: charLine.line, ch: 18 }];
74 var parens1 = {
75 start: { line: bracesLine.line, ch: 1 },
76 end: { line: bracesLine.line, ch: 3 }
77 };
78 var squares1 = {
79 start: { line: bracesLine.line, ch: 5 },
80 end: { line: bracesLine.line, ch: 7 }
81 };
82 var curlys1 = {
83 start: { line: bracesLine.line, ch: 9 },
84 end: { line: bracesLine.line, ch: 11 }
85 };
86 var seekOutside = {
87 start: { line: seekBraceLine.line, ch: 1 },
88 end: { line: seekBraceLine.line, ch: 16 }
89 };
90 var seekInside = {
91 start: { line: seekBraceLine.line, ch: 14 },
92 end: { line: seekBraceLine.line, ch: 11 }
93 };
94
95 function copyCursor(cur) {
96 return { ch: cur.ch, line: cur.line };
97 }
98
99 function forEach(arr, func) {
100 for (var i = 0; i < arr.length; i++) {
101 func(arr[i]);
102 }
103 }
104
105 function testVim(name, run, opts, expectedFail) {
106 var vimOpts = {
107 lineNumbers: true,
108 vimMode: true,
109 showCursorWhenSelecting: true,
110 value: code
111 };
112 for (var prop in opts) {
113 if (opts.hasOwnProperty(prop)) {
114 vimOpts[prop] = opts[prop];
115 }
116 }
117 return test('vim_' + name, function() {
118 var place = document.getElementById("testground");
119 var cm = CodeMirror(place, vimOpts);
120 var vim = CodeMirror.Vim.maybeInitVimState_(cm);
121
122 function doKeysFn(cm) {
123 return function(args) {
124 if (args instanceof Array) {
125 arguments = args;
126 }
127 for (var i = 0; i < arguments.length; i++) {
128 CodeMirror.Vim.handleKey(cm, arguments[i]);
129 }
130 }
131 }
132 function doInsertModeKeysFn(cm) {
133 return function(args) {
134 if (args instanceof Array) { arguments = args; }
135 function executeHandler(handler) {
136 if (typeof handler == 'string') {
137 CodeMirror.commands[handler](cm);
138 } else {
139 handler(cm);
140 }
141 return true;
142 }
143 for (var i = 0; i < arguments.length; i++) {
144 var key = arguments[i];
145 // Find key in keymap and handle.
146 var handled = CodeMirror.lookupKey(key, ['vim-insert'], executeHandler);
147 // Record for insert mode.
148 if (handled === true && cm.state.vim.insertMode && arguments[i] != 'Esc') {
149 var lastChange = CodeMirror.Vim.getVimGlobalState_().macroModeState.lastInsertModeChanges;
150 if (lastChange) {
151 lastChange.changes.push(new CodeMirror.Vim.InsertModeKey(key));
152 }
153 }
154 }
155 }
156 }
157 function doExFn(cm) {
158 return function(command) {
159 cm.openDialog = helpers.fakeOpenDialog(command);
160 helpers.doKeys(':');
161 }
162 }
163 function assertCursorAtFn(cm) {
164 return function(line, ch) {
165 var pos;
166 if (ch == null && typeof line.line == 'number') {
167 pos = line;
168 } else {
169 pos = makeCursor(line, ch);
170 }
171 eqPos(pos, cm.getCursor());
172 }
173 }
174 function fakeOpenDialog(result) {
175 return function(text, callback) {
176 return callback(result);
177 }
178 }
179 function fakeOpenNotification(matcher) {
180 return function(text) {
181 matcher(text);
182 }
183 }
184 var helpers = {
185 doKeys: doKeysFn(cm),
186 // Warning: Only emulates keymap events, not character insertions. Use
187 // replaceRange to simulate character insertions.
188 // Keys are in CodeMirror format, NOT vim format.
189 doInsertModeKeys: doInsertModeKeysFn(cm),
190 doEx: doExFn(cm),
191 assertCursorAt: assertCursorAtFn(cm),
192 fakeOpenDialog: fakeOpenDialog,
193 fakeOpenNotification: fakeOpenNotification,
194 getRegisterController: function() {
195 return CodeMirror.Vim.getRegisterController();
196 }
197 }
198 CodeMirror.Vim.resetVimGlobalState_();
199 var successful = false;
200 var savedOpenNotification = cm.openNotification;
201 try {
202 run(cm, vim, helpers);
203 successful = true;
204 } finally {
205 cm.openNotification = savedOpenNotification;
206 if (!successful || verbose) {
207 place.style.visibility = "visible";
208 } else {
209 place.removeChild(cm.getWrapperElement());
210 }
211 }
212 }, expectedFail);
213 };
214 testVim('qq@q', function(cm, vim, helpers) {
215 cm.setCursor(0, 0);
216 helpers.doKeys('q', 'q', 'l', 'l', 'q');
217 helpers.assertCursorAt(0,2);
218 helpers.doKeys('@', 'q');
219 helpers.assertCursorAt(0,4);
220 }, { value: ' '});
221 testVim('@@', function(cm, vim, helpers) {
222 cm.setCursor(0, 0);
223 helpers.doKeys('q', 'q', 'l', 'l', 'q');
224 helpers.assertCursorAt(0,2);
225 helpers.doKeys('@', 'q');
226 helpers.assertCursorAt(0,4);
227 helpers.doKeys('@', '@');
228 helpers.assertCursorAt(0,6);
229 }, { value: ' '});
230 var jumplistScene = ''+
231 'word\n'+
232 '(word)\n'+
233 '{word\n'+
234 'word.\n'+
235 '\n'+
236 'word search\n'+
237 '}word\n'+
238 'word\n'+
239 'word\n';
240 function testJumplist(name, keys, endPos, startPos, dialog) {
241 endPos = makeCursor(endPos[0], endPos[1]);
242 startPos = makeCursor(startPos[0], startPos[1]);
243 testVim(name, function(cm, vim, helpers) {
244 CodeMirror.Vim.resetVimGlobalState_();
245 if(dialog)cm.openDialog = helpers.fakeOpenDialog('word');
246 cm.setCursor(startPos);
247 helpers.doKeys.apply(null, keys);
248 helpers.assertCursorAt(endPos);
249 }, {value: jumplistScene});
250 };
251 testJumplist('jumplist_H', ['H', '<C-o>'], [5,2], [5,2]);
252 testJumplist('jumplist_M', ['M', '<C-o>'], [2,2], [2,2]);
253 testJumplist('jumplist_L', ['L', '<C-o>'], [2,2], [2,2]);
254 testJumplist('jumplist_[[', ['[', '[', '<C-o>'], [5,2], [5,2]);
255 testJumplist('jumplist_]]', [']', ']', '<C-o>'], [2,2], [2,2]);
256 testJumplist('jumplist_G', ['G', '<C-o>'], [5,2], [5,2]);
257 testJumplist('jumplist_gg', ['g', 'g', '<C-o>'], [5,2], [5,2]);
258 testJumplist('jumplist_%', ['%', '<C-o>'], [1,5], [1,5]);
259 testJumplist('jumplist_{', ['{', '<C-o>'], [1,5], [1,5]);
260 testJumplist('jumplist_}', ['}', '<C-o>'], [1,5], [1,5]);
261 testJumplist('jumplist_\'', ['m', 'a', 'h', '\'', 'a', 'h', '<C-i>'], [1,5], [1,5]);
262 testJumplist('jumplist_`', ['m', 'a', 'h', '`', 'a', 'h', '<C-i>'], [1,5], [1,5]);
263 testJumplist('jumplist_*_cachedCursor', ['*', '<C-o>'], [1,3], [1,3]);
264 testJumplist('jumplist_#_cachedCursor', ['#', '<C-o>'], [1,3], [1,3]);
265 testJumplist('jumplist_n', ['#', 'n', '<C-o>'], [1,1], [2,3]);
266 testJumplist('jumplist_N', ['#', 'N', '<C-o>'], [1,1], [2,3]);
267 testJumplist('jumplist_repeat_<c-o>', ['*', '*', '*', '3', '<C-o>'], [2,3], [2,3]);
268 testJumplist('jumplist_repeat_<c-i>', ['*', '*', '*', '3', '<C-o>', '2', '<C-i>'], [5,0], [2,3]);
269 testJumplist('jumplist_repeated_motion', ['3', '*', '<C-o>'], [2,3], [2,3]);
270 testJumplist('jumplist_/', ['/', '<C-o>'], [2,3], [2,3], 'dialog');
271 testJumplist('jumplist_?', ['?', '<C-o>'], [2,3], [2,3], 'dialog');
272 testJumplist('jumplist_skip_delted_mark<c-o>',
273 ['*', 'n', 'n', 'k', 'd', 'k', '<C-o>', '<C-o>', '<C-o>'],
274 [0,2], [0,2]);
275 testJumplist('jumplist_skip_delted_mark<c-i>',
276 ['*', 'n', 'n', 'k', 'd', 'k', '<C-o>', '<C-i>', '<C-i>'],
277 [1,0], [0,2]);
278
279 /**
280 * @param name Name of the test
281 * @param keys An array of keys or a string with a single key to simulate.
282 * @param endPos The expected end position of the cursor.
283 * @param startPos The position the cursor should start at, defaults to 0, 0.
284 */
285 function testMotion(name, keys, endPos, startPos) {
286 testVim(name, function(cm, vim, helpers) {
287 if (!startPos) {
288 startPos = { line: 0, ch: 0 };
289 }
290 cm.setCursor(startPos);
291 helpers.doKeys(keys);
292 helpers.assertCursorAt(endPos);
293 });
294 };
295
296 function makeCursor(line, ch) {
297 return { line: line, ch: ch };
298 };
299
300 function offsetCursor(cur, offsetLine, offsetCh) {
301 return { line: cur.line + offsetLine, ch: cur.ch + offsetCh };
302 };
303
304 // Motion tests
305 testMotion('|', '|', makeCursor(0, 0), makeCursor(0,4));
306 testMotion('|_repeat', ['3', '|'], makeCursor(0, 2), makeCursor(0,4));
307 testMotion('h', 'h', makeCursor(0, 0), word1.start);
308 testMotion('h_repeat', ['3', 'h'], offsetCursor(word1.end, 0, -3), word1.end);
309 testMotion('l', 'l', makeCursor(0, 1));
310 testMotion('l_repeat', ['2', 'l'], makeCursor(0, 2));
311 testMotion('j', 'j', offsetCursor(word1.end, 1, 0), word1.end);
312 testMotion('j_repeat', ['2', 'j'], offsetCursor(word1.end, 2, 0), word1.end);
313 testMotion('j_repeat_clip', ['1000', 'j'], endOfDocument);
314 testMotion('k', 'k', offsetCursor(word3.end, -1, 0), word3.end);
315 testMotion('k_repeat', ['2', 'k'], makeCursor(0, 4), makeCursor(2, 4));
316 testMotion('k_repeat_clip', ['1000', 'k'], makeCursor(0, 4), makeCursor(2, 4));
317 testMotion('w', 'w', word1.start);
318 testMotion('w_multiple_newlines_no_space', 'w', makeCursor(12, 2), makeCursor(11, 2));
319 testMotion('w_multiple_newlines_with_space', 'w', makeCursor(14, 0), makeCursor(12, 51));
320 testMotion('w_repeat', ['2', 'w'], word2.start);
321 testMotion('w_wrap', ['w'], word3.start, word2.start);
322 testMotion('w_endOfDocument', 'w', endOfDocument, endOfDocument);
323 testMotion('w_start_to_end', ['1000', 'w'], endOfDocument, makeCursor(0, 0));
324 testMotion('W', 'W', bigWord1.start);
325 testMotion('W_repeat', ['2', 'W'], bigWord3.start, bigWord1.start);
326 testMotion('e', 'e', word1.end);
327 testMotion('e_repeat', ['2', 'e'], word2.end);
328 testMotion('e_wrap', 'e', word3.end, word2.end);
329 testMotion('e_endOfDocument', 'e', endOfDocument, endOfDocument);
330 testMotion('e_start_to_end', ['1000', 'e'], endOfDocument, makeCursor(0, 0));
331 testMotion('b', 'b', word3.start, word3.end);
332 testMotion('b_repeat', ['2', 'b'], word2.start, word3.end);
333 testMotion('b_wrap', 'b', word2.start, word3.start);
334 testMotion('b_startOfDocument', 'b', makeCursor(0, 0), makeCursor(0, 0));
335 testMotion('b_end_to_start', ['1000', 'b'], makeCursor(0, 0), endOfDocument);
336 testMotion('ge', ['g', 'e'], word2.end, word3.end);
337 testMotion('ge_repeat', ['2', 'g', 'e'], word1.end, word3.start);
338 testMotion('ge_wrap', ['g', 'e'], word2.end, word3.start);
339 testMotion('ge_startOfDocument', ['g', 'e'], makeCursor(0, 0),
340 makeCursor(0, 0));
341 testMotion('ge_end_to_start', ['1000', 'g', 'e'], makeCursor(0, 0), endOfDocument);
342 testMotion('gg', ['g', 'g'], makeCursor(lines[0].line, lines[0].textStart),
343 makeCursor(3, 1));
344 testMotion('gg_repeat', ['3', 'g', 'g'],
345 makeCursor(lines[2].line, lines[2].textStart));
346 testMotion('G', 'G',
347 makeCursor(lines[lines.length - 1].line, lines[lines.length - 1].textStart),
348 makeCursor(3, 1));
349 testMotion('G_repeat', ['3', 'G'], makeCursor(lines[2].line,
350 lines[2].textStart));
351 // TODO: Make the test code long enough to test Ctrl-F and Ctrl-B.
352 testMotion('0', '0', makeCursor(0, 0), makeCursor(0, 8));
353 testMotion('^', '^', makeCursor(0, lines[0].textStart), makeCursor(0, 8));
354 testMotion('+', '+', makeCursor(1, lines[1].textStart), makeCursor(0, 8));
355 testMotion('-', '-', makeCursor(0, lines[0].textStart), makeCursor(1, 4));
356 testMotion('_', ['6','_'], makeCursor(5, lines[5].textStart), makeCursor(0, 8));
357 testMotion('$', '$', makeCursor(0, lines[0].length - 1), makeCursor(0, 1));
358 testMotion('$_repeat', ['2', '$'], makeCursor(1, lines[1].length - 1),
359 makeCursor(0, 3));
360 testMotion('f', ['f', 'p'], pChars[0], makeCursor(charLine.line, 0));
361 testMotion('f_repeat', ['2', 'f', 'p'], pChars[2], pChars[0]);
362 testMotion('f_num', ['f', '2'], numChars[2], makeCursor(charLine.line, 0));
363 testMotion('t', ['t','p'], offsetCursor(pChars[0], 0, -1),
364 makeCursor(charLine.line, 0));
365 testMotion('t_repeat', ['2', 't', 'p'], offsetCursor(pChars[2], 0, -1),
366 pChars[0]);
367 testMotion('F', ['F', 'p'], pChars[0], pChars[1]);
368 testMotion('F_repeat', ['2', 'F', 'p'], pChars[0], pChars[2]);
369 testMotion('T', ['T', 'p'], offsetCursor(pChars[0], 0, 1), pChars[1]);
370 testMotion('T_repeat', ['2', 'T', 'p'], offsetCursor(pChars[0], 0, 1), pChars[2]);
371 testMotion('%_parens', ['%'], parens1.end, parens1.start);
372 testMotion('%_squares', ['%'], squares1.end, squares1.start);
373 testMotion('%_braces', ['%'], curlys1.end, curlys1.start);
374 testMotion('%_seek_outside', ['%'], seekOutside.end, seekOutside.start);
375 testMotion('%_seek_inside', ['%'], seekInside.end, seekInside.start);
376 testVim('%_seek_skip', function(cm, vim, helpers) {
377 cm.setCursor(0,0);
378 helpers.doKeys(['%']);
379 helpers.assertCursorAt(0,9);
380 }, {value:'01234"("()'});
381 testVim('%_skip_string', function(cm, vim, helpers) {
382 cm.setCursor(0,0);
383 helpers.doKeys(['%']);
384 helpers.assertCursorAt(0,4);
385 cm.setCursor(0,2);
386 helpers.doKeys(['%']);
387 helpers.assertCursorAt(0,0);
388 }, {value:'(")")'});
389 (')')
390 testVim('%_skip_comment', function(cm, vim, helpers) {
391 cm.setCursor(0,0);
392 helpers.doKeys(['%']);
393 helpers.assertCursorAt(0,6);
394 cm.setCursor(0,3);
395 helpers.doKeys(['%']);
396 helpers.assertCursorAt(0,0);
397 }, {value:'(/*)*/)'});
398 // Make sure that moving down after going to the end of a line always leaves you
399 // at the end of a line, but preserves the offset in other cases
400 testVim('Changing lines after Eol operation', function(cm, vim, helpers) {
401 cm.setCursor(0,0);
402 helpers.doKeys(['$']);
403 helpers.doKeys(['j']);
404 // After moving to Eol and then down, we should be at Eol of line 2
405 helpers.assertCursorAt({ line: 1, ch: lines[1].length - 1 });
406 helpers.doKeys(['j']);
407 // After moving down, we should be at Eol of line 3
408 helpers.assertCursorAt({ line: 2, ch: lines[2].length - 1 });
409 helpers.doKeys(['h']);
410 helpers.doKeys(['j']);
411 // After moving back one space and then down, since line 4 is shorter than line 2, we should
412 // be at Eol of line 2 - 1
413 helpers.assertCursorAt({ line: 3, ch: lines[3].length - 1 });
414 helpers.doKeys(['j']);
415 helpers.doKeys(['j']);
416 // After moving down again, since line 3 has enough characters, we should be back to the
417 // same place we were at on line 1
418 helpers.assertCursorAt({ line: 5, ch: lines[2].length - 2 });
419 });
420 //making sure gj and gk recover from clipping
421 testVim('gj_gk_clipping', function(cm,vim,helpers){
422 cm.setCursor(0, 1);
423 helpers.doKeys('g','j','g','j');
424 helpers.assertCursorAt(2, 1);
425 helpers.doKeys('g','k','g','k');
426 helpers.assertCursorAt(0, 1);
427 },{value: 'line 1\n\nline 2'});
428 //testing a mix of j/k and gj/gk
429 testVim('j_k_and_gj_gk', function(cm,vim,helpers){
430 cm.setSize(120);
431 cm.setCursor(0, 0);
432 //go to the last character on the first line
433 helpers.doKeys('$');
434 //move up/down on the column within the wrapped line
435 //side-effect: cursor is not locked to eol anymore
436 helpers.doKeys('g','k');
437 var cur=cm.getCursor();
438 eq(cur.line,0);
439 is((cur.ch<176),'gk didn\'t move cursor back (1)');
440 helpers.doKeys('g','j');
441 helpers.assertCursorAt(0, 176);
442 //should move to character 177 on line 2 (j/k preserve character index within line)
443 helpers.doKeys('j');
444 //due to different line wrapping, the cursor can be on a different screen-x now
445 //gj and gk preserve screen-x on movement, much like moveV
446 helpers.doKeys('3','g','k');
447 cur=cm.getCursor();
448 eq(cur.line,1);
449 is((cur.ch<176),'gk didn\'t move cursor back (2)');
450 helpers.doKeys('g','j','2','g','j');
451 //should return to the same character-index
452 helpers.doKeys('k');
453 helpers.assertCursorAt(0, 176);
454 },{ lineWrapping:true, value: 'This line is intentially long to test movement of gj and gk over wrapped lines. I will start on the end of this line, then make a step up and back to set the origin for j and k.\nThis line is supposed to be even longer than the previous. I will jump here and make another wiggle with gj and gk, before I jump back to the line above. Both wiggles should not change my cursor\'s target character but both j/k and gj/gk change each other\'s reference position.'});
455 testVim('gj_gk', function(cm, vim, helpers) {
456 if (phantom) return;
457 cm.setSize(120);
458 // Test top of document edge case.
459 cm.setCursor(0, 4);
460 helpers.doKeys('g', 'j');
461 helpers.doKeys('10', 'g', 'k');
462 helpers.assertCursorAt(0, 4);
463
464 // Test moving down preserves column position.
465 helpers.doKeys('g', 'j');
466 var pos1 = cm.getCursor();
467 var expectedPos2 = { line: 0, ch: (pos1.ch - 4) * 2 + 4};
468 helpers.doKeys('g', 'j');
469 helpers.assertCursorAt(expectedPos2);
470
471 // Move to the last character
472 cm.setCursor(0, 0);
473 // Move left to reset HSPos
474 helpers.doKeys('h');
475 // Test bottom of document edge case.
476 helpers.doKeys('100', 'g', 'j');
477 var endingPos = cm.getCursor();
478 is(endingPos != 0, 'gj should not be on wrapped line 0');
479 var topLeftCharCoords = cm.charCoords(makeCursor(0, 0));
480 var endingCharCoords = cm.charCoords(endingPos);
481 is(topLeftCharCoords.left == endingCharCoords.left, 'gj should end up on column 0');
482 },{ lineNumbers: false, lineWrapping:true, value: 'Thislineisintentiallylongtotestmovementofgjandgkoverwrappedlines.' });
483 testVim('}', function(cm, vim, helpers) {
484 cm.setCursor(0, 0);
485 helpers.doKeys('}');
486 helpers.assertCursorAt(1, 0);
487 cm.setCursor(0, 0);
488 helpers.doKeys('2', '}');
489 helpers.assertCursorAt(4, 0);
490 cm.setCursor(0, 0);
491 helpers.doKeys('6', '}');
492 helpers.assertCursorAt(5, 0);
493 }, { value: 'a\n\nb\nc\n\nd' });
494 testVim('{', function(cm, vim, helpers) {
495 cm.setCursor(5, 0);
496 helpers.doKeys('{');
497 helpers.assertCursorAt(4, 0);
498 cm.setCursor(5, 0);
499 helpers.doKeys('2', '{');
500 helpers.assertCursorAt(1, 0);
501 cm.setCursor(5, 0);
502 helpers.doKeys('6', '{');
503 helpers.assertCursorAt(0, 0);
504 }, { value: 'a\n\nb\nc\n\nd' });
505
506 // Operator tests
507 testVim('dl', function(cm, vim, helpers) {
508 var curStart = makeCursor(0, 0);
509 cm.setCursor(curStart);
510 helpers.doKeys('d', 'l');
511 eq('word1 ', cm.getValue());
512 var register = helpers.getRegisterController().getRegister();
513 eq(' ', register.toString());
514 is(!register.linewise);
515 eqPos(curStart, cm.getCursor());
516 }, { value: ' word1 ' });
517 testVim('dl_eol', function(cm, vim, helpers) {
518 cm.setCursor(0, 6);
519 helpers.doKeys('d', 'l');
520 eq(' word1', cm.getValue());
521 var register = helpers.getRegisterController().getRegister();
522 eq(' ', register.toString());
523 is(!register.linewise);
524 helpers.assertCursorAt(0, 5);
525 }, { value: ' word1 ' });
526 testVim('dl_repeat', function(cm, vim, helpers) {
527 var curStart = makeCursor(0, 0);
528 cm.setCursor(curStart);
529 helpers.doKeys('2', 'd', 'l');
530 eq('ord1 ', cm.getValue());
531 var register = helpers.getRegisterController().getRegister();
532 eq(' w', register.toString());
533 is(!register.linewise);
534 eqPos(curStart, cm.getCursor());
535 }, { value: ' word1 ' });
536 testVim('dh', function(cm, vim, helpers) {
537 var curStart = makeCursor(0, 3);
538 cm.setCursor(curStart);
539 helpers.doKeys('d', 'h');
540 eq(' wrd1 ', cm.getValue());
541 var register = helpers.getRegisterController().getRegister();
542 eq('o', register.toString());
543 is(!register.linewise);
544 eqPos(offsetCursor(curStart, 0 , -1), cm.getCursor());
545 }, { value: ' word1 ' });
546 testVim('dj', function(cm, vim, helpers) {
547 var curStart = makeCursor(0, 3);
548 cm.setCursor(curStart);
549 helpers.doKeys('d', 'j');
550 eq(' word3', cm.getValue());
551 var register = helpers.getRegisterController().getRegister();
552 eq(' word1\nword2\n', register.toString());
553 is(register.linewise);
554 helpers.assertCursorAt(0, 1);
555 }, { value: ' word1\nword2\n word3' });
556 testVim('dj_end_of_document', function(cm, vim, helpers) {
557 var curStart = makeCursor(0, 3);
558 cm.setCursor(curStart);
559 helpers.doKeys('d', 'j');
560 eq(' word1 ', cm.getValue());
561 var register = helpers.getRegisterController().getRegister();
562 eq('', register.toString());
563 is(!register.linewise);
564 helpers.assertCursorAt(0, 3);
565 }, { value: ' word1 ' });
566 testVim('dk', function(cm, vim, helpers) {
567 var curStart = makeCursor(1, 3);
568 cm.setCursor(curStart);
569 helpers.doKeys('d', 'k');
570 eq(' word3', cm.getValue());
571 var register = helpers.getRegisterController().getRegister();
572 eq(' word1\nword2\n', register.toString());
573 is(register.linewise);
574 helpers.assertCursorAt(0, 1);
575 }, { value: ' word1\nword2\n word3' });
576 testVim('dk_start_of_document', function(cm, vim, helpers) {
577 var curStart = makeCursor(0, 3);
578 cm.setCursor(curStart);
579 helpers.doKeys('d', 'k');
580 eq(' word1 ', cm.getValue());
581 var register = helpers.getRegisterController().getRegister();
582 eq('', register.toString());
583 is(!register.linewise);
584 helpers.assertCursorAt(0, 3);
585 }, { value: ' word1 ' });
586 testVim('dw_space', function(cm, vim, helpers) {
587 var curStart = makeCursor(0, 0);
588 cm.setCursor(curStart);
589 helpers.doKeys('d', 'w');
590 eq('word1 ', cm.getValue());
591 var register = helpers.getRegisterController().getRegister();
592 eq(' ', register.toString());
593 is(!register.linewise);
594 eqPos(curStart, cm.getCursor());
595 }, { value: ' word1 ' });
596 testVim('dw_word', function(cm, vim, helpers) {
597 var curStart = makeCursor(0, 1);
598 cm.setCursor(curStart);
599 helpers.doKeys('d', 'w');
600 eq(' word2', cm.getValue());
601 var register = helpers.getRegisterController().getRegister();
602 eq('word1 ', register.toString());
603 is(!register.linewise);
604 eqPos(curStart, cm.getCursor());
605 }, { value: ' word1 word2' });
606 testVim('dw_only_word', function(cm, vim, helpers) {
607 // Test that if there is only 1 word left, dw deletes till the end of the
608 // line.
609 cm.setCursor(0, 1);
610 helpers.doKeys('d', 'w');
611 eq(' ', cm.getValue());
612 var register = helpers.getRegisterController().getRegister();
613 eq('word1 ', register.toString());
614 is(!register.linewise);
615 helpers.assertCursorAt(0, 0);
616 }, { value: ' word1 ' });
617 testVim('dw_eol', function(cm, vim, helpers) {
618 // Assert that dw does not delete the newline if last word to delete is at end
619 // of line.
620 cm.setCursor(0, 1);
621 helpers.doKeys('d', 'w');
622 eq(' \nword2', cm.getValue());
623 var register = helpers.getRegisterController().getRegister();
624 eq('word1', register.toString());
625 is(!register.linewise);
626 helpers.assertCursorAt(0, 0);
627 }, { value: ' word1\nword2' });
628 testVim('dw_eol_with_multiple_newlines', function(cm, vim, helpers) {
629 // Assert that dw does not delete the newline if last word to delete is at end
630 // of line and it is followed by multiple newlines.
631 cm.setCursor(0, 1);
632 helpers.doKeys('d', 'w');
633 eq(' \n\nword2', cm.getValue());
634 var register = helpers.getRegisterController().getRegister();
635 eq('word1', register.toString());
636 is(!register.linewise);
637 helpers.assertCursorAt(0, 0);
638 }, { value: ' word1\n\nword2' });
639 testVim('dw_empty_line_followed_by_whitespace', function(cm, vim, helpers) {
640 cm.setCursor(0, 0);
641 helpers.doKeys('d', 'w');
642 eq(' \nword', cm.getValue());
643 }, { value: '\n \nword' });
644 testVim('dw_empty_line_followed_by_word', function(cm, vim, helpers) {
645 cm.setCursor(0, 0);
646 helpers.doKeys('d', 'w');
647 eq('word', cm.getValue());
648 }, { value: '\nword' });
649 testVim('dw_empty_line_followed_by_empty_line', function(cm, vim, helpers) {
650 cm.setCursor(0, 0);
651 helpers.doKeys('d', 'w');
652 eq('\n', cm.getValue());
653 }, { value: '\n\n' });
654 testVim('dw_whitespace_followed_by_whitespace', function(cm, vim, helpers) {
655 cm.setCursor(0, 0);
656 helpers.doKeys('d', 'w');
657 eq('\n \n', cm.getValue());
658 }, { value: ' \n \n' });
659 testVim('dw_whitespace_followed_by_empty_line', function(cm, vim, helpers) {
660 cm.setCursor(0, 0);
661 helpers.doKeys('d', 'w');
662 eq('\n\n', cm.getValue());
663 }, { value: ' \n\n' });
664 testVim('dw_word_whitespace_word', function(cm, vim, helpers) {
665 cm.setCursor(0, 0);
666 helpers.doKeys('d', 'w');
667 eq('\n \nword2', cm.getValue());
668 }, { value: 'word1\n \nword2'})
669 testVim('dw_end_of_document', function(cm, vim, helpers) {
670 cm.setCursor(1, 2);
671 helpers.doKeys('d', 'w');
672 eq('\nab', cm.getValue());
673 }, { value: '\nabc' });
674 testVim('dw_repeat', function(cm, vim, helpers) {
675 // Assert that dw does delete newline if it should go to the next line, and
676 // that repeat works properly.
677 cm.setCursor(0, 1);
678 helpers.doKeys('d', '2', 'w');
679 eq(' ', cm.getValue());
680 var register = helpers.getRegisterController().getRegister();
681 eq('word1\nword2', register.toString());
682 is(!register.linewise);
683 helpers.assertCursorAt(0, 0);
684 }, { value: ' word1\nword2' });
685 testVim('de_word_start_and_empty_lines', function(cm, vim, helpers) {
686 cm.setCursor(0, 0);
687 helpers.doKeys('d', 'e');
688 eq('\n\n', cm.getValue());
689 }, { value: 'word\n\n' });
690 testVim('de_word_end_and_empty_lines', function(cm, vim, helpers) {
691 cm.setCursor(0, 3);
692 helpers.doKeys('d', 'e');
693 eq('wor', cm.getValue());
694 }, { value: 'word\n\n\n' });
695 testVim('de_whitespace_and_empty_lines', function(cm, vim, helpers) {
696 cm.setCursor(0, 0);
697 helpers.doKeys('d', 'e');
698 eq('', cm.getValue());
699 }, { value: ' \n\n\n' });
700 testVim('de_end_of_document', function(cm, vim, helpers) {
701 cm.setCursor(1, 2);
702 helpers.doKeys('d', 'e');
703 eq('\nab', cm.getValue());
704 }, { value: '\nabc' });
705 testVim('db_empty_lines', function(cm, vim, helpers) {
706 cm.setCursor(2, 0);
707 helpers.doKeys('d', 'b');
708 eq('\n\n', cm.getValue());
709 }, { value: '\n\n\n' });
710 testVim('db_word_start_and_empty_lines', function(cm, vim, helpers) {
711 cm.setCursor(2, 0);
712 helpers.doKeys('d', 'b');
713 eq('\nword', cm.getValue());
714 }, { value: '\n\nword' });
715 testVim('db_word_end_and_empty_lines', function(cm, vim, helpers) {
716 cm.setCursor(2, 3);
717 helpers.doKeys('d', 'b');
718 eq('\n\nd', cm.getValue());
719 }, { value: '\n\nword' });
720 testVim('db_whitespace_and_empty_lines', function(cm, vim, helpers) {
721 cm.setCursor(2, 0);
722 helpers.doKeys('d', 'b');
723 eq('', cm.getValue());
724 }, { value: '\n \n' });
725 testVim('db_start_of_document', function(cm, vim, helpers) {
726 cm.setCursor(0, 0);
727 helpers.doKeys('d', 'b');
728 eq('abc\n', cm.getValue());
729 }, { value: 'abc\n' });
730 testVim('dge_empty_lines', function(cm, vim, helpers) {
731 cm.setCursor(1, 0);
732 helpers.doKeys('d', 'g', 'e');
733 // Note: In real VIM the result should be '', but it's not quite consistent,
734 // since 2 newlines are deleted. But in the similar case of word\n\n, only
735 // 1 newline is deleted. We'll diverge from VIM's behavior since it's much
736 // easier this way.
737 eq('\n', cm.getValue());
738 }, { value: '\n\n' });
739 testVim('dge_word_and_empty_lines', function(cm, vim, helpers) {
740 cm.setCursor(1, 0);
741 helpers.doKeys('d', 'g', 'e');
742 eq('wor\n', cm.getValue());
743 }, { value: 'word\n\n'});
744 testVim('dge_whitespace_and_empty_lines', function(cm, vim, helpers) {
745 cm.setCursor(2, 0);
746 helpers.doKeys('d', 'g', 'e');
747 eq('', cm.getValue());
748 }, { value: '\n \n' });
749 testVim('dge_start_of_document', function(cm, vim, helpers) {
750 cm.setCursor(0, 0);
751 helpers.doKeys('d', 'g', 'e');
752 eq('bc\n', cm.getValue());
753 }, { value: 'abc\n' });
754 testVim('d_inclusive', function(cm, vim, helpers) {
755 // Assert that when inclusive is set, the character the cursor is on gets
756 // deleted too.
757 var curStart = makeCursor(0, 1);
758 cm.setCursor(curStart);
759 helpers.doKeys('d', 'e');
760 eq(' ', cm.getValue());
761 var register = helpers.getRegisterController().getRegister();
762 eq('word1', register.toString());
763 is(!register.linewise);
764 eqPos(curStart, cm.getCursor());
765 }, { value: ' word1 ' });
766 testVim('d_reverse', function(cm, vim, helpers) {
767 // Test that deleting in reverse works.
768 cm.setCursor(1, 0);
769 helpers.doKeys('d', 'b');
770 eq(' word2 ', cm.getValue());
771 var register = helpers.getRegisterController().getRegister();
772 eq('word1\n', register.toString());
773 is(!register.linewise);
774 helpers.assertCursorAt(0, 1);
775 }, { value: ' word1\nword2 ' });
776 testVim('dd', function(cm, vim, helpers) {
777 cm.setCursor(0, 3);
778 var expectedBuffer = cm.getRange({ line: 0, ch: 0 },
779 { line: 1, ch: 0 });
780 var expectedLineCount = cm.lineCount() - 1;
781 helpers.doKeys('d', 'd');
782 eq(expectedLineCount, cm.lineCount());
783 var register = helpers.getRegisterController().getRegister();
784 eq(expectedBuffer, register.toString());
785 is(register.linewise);
786 helpers.assertCursorAt(0, lines[1].textStart);
787 });
788 testVim('dd_prefix_repeat', function(cm, vim, helpers) {
789 cm.setCursor(0, 3);
790 var expectedBuffer = cm.getRange({ line: 0, ch: 0 },
791 { line: 2, ch: 0 });
792 var expectedLineCount = cm.lineCount() - 2;
793 helpers.doKeys('2', 'd', 'd');
794 eq(expectedLineCount, cm.lineCount());
795 var register = helpers.getRegisterController().getRegister();
796 eq(expectedBuffer, register.toString());
797 is(register.linewise);
798 helpers.assertCursorAt(0, lines[2].textStart);
799 });
800 testVim('dd_motion_repeat', function(cm, vim, helpers) {
801 cm.setCursor(0, 3);
802 var expectedBuffer = cm.getRange({ line: 0, ch: 0 },
803 { line: 2, ch: 0 });
804 var expectedLineCount = cm.lineCount() - 2;
805 helpers.doKeys('d', '2', 'd');
806 eq(expectedLineCount, cm.lineCount());
807 var register = helpers.getRegisterController().getRegister();
808 eq(expectedBuffer, register.toString());
809 is(register.linewise);
810 helpers.assertCursorAt(0, lines[2].textStart);
811 });
812 testVim('dd_multiply_repeat', function(cm, vim, helpers) {
813 cm.setCursor(0, 3);
814 var expectedBuffer = cm.getRange({ line: 0, ch: 0 },
815 { line: 6, ch: 0 });
816 var expectedLineCount = cm.lineCount() - 6;
817 helpers.doKeys('2', 'd', '3', 'd');
818 eq(expectedLineCount, cm.lineCount());
819 var register = helpers.getRegisterController().getRegister();
820 eq(expectedBuffer, register.toString());
821 is(register.linewise);
822 helpers.assertCursorAt(0, lines[6].textStart);
823 });
824 testVim('dd_lastline', function(cm, vim, helpers) {
825 cm.setCursor(cm.lineCount(), 0);
826 var expectedLineCount = cm.lineCount() - 1;
827 helpers.doKeys('d', 'd');
828 eq(expectedLineCount, cm.lineCount());
829 helpers.assertCursorAt(cm.lineCount() - 1, 0);
830 });
831 // Yank commands should behave the exact same as d commands, expect that nothing
832 // gets deleted.
833 testVim('yw_repeat', function(cm, vim, helpers) {
834 // Assert that yw does yank newline if it should go to the next line, and
835 // that repeat works properly.
836 var curStart = makeCursor(0, 1);
837 cm.setCursor(curStart);
838 helpers.doKeys('y', '2', 'w');
839 eq(' word1\nword2', cm.getValue());
840 var register = helpers.getRegisterController().getRegister();
841 eq('word1\nword2', register.toString());
842 is(!register.linewise);
843 eqPos(curStart, cm.getCursor());
844 }, { value: ' word1\nword2' });
845 testVim('yy_multiply_repeat', function(cm, vim, helpers) {
846 var curStart = makeCursor(0, 3);
847 cm.setCursor(curStart);
848 var expectedBuffer = cm.getRange({ line: 0, ch: 0 },
849 { line: 6, ch: 0 });
850 var expectedLineCount = cm.lineCount();
851 helpers.doKeys('2', 'y', '3', 'y');
852 eq(expectedLineCount, cm.lineCount());
853 var register = helpers.getRegisterController().getRegister();
854 eq(expectedBuffer, register.toString());
855 is(register.linewise);
856 eqPos(curStart, cm.getCursor());
857 });
858 // Change commands behave like d commands except that it also enters insert
859 // mode. In addition, when the change is linewise, an additional newline is
860 // inserted so that insert mode starts on that line.
861 testVim('cw', function(cm, vim, helpers) {
862 cm.setCursor(0, 0);
863 helpers.doKeys('c', '2', 'w');
864 eq(' word3', cm.getValue());
865 helpers.assertCursorAt(0, 0);
866 }, { value: 'word1 word2 word3'});
867 testVim('cw_repeat', function(cm, vim, helpers) {
868 // Assert that cw does delete newline if it should go to the next line, and
869 // that repeat works properly.
870 var curStart = makeCursor(0, 1);
871 cm.setCursor(curStart);
872 helpers.doKeys('c', '2', 'w');
873 eq(' ', cm.getValue());
874 var register = helpers.getRegisterController().getRegister();
875 eq('word1\nword2', register.toString());
876 is(!register.linewise);
877 eqPos(curStart, cm.getCursor());
878 eq('vim-insert', cm.getOption('keyMap'));
879 }, { value: ' word1\nword2' });
880 testVim('cc_multiply_repeat', function(cm, vim, helpers) {
881 cm.setCursor(0, 3);
882 var expectedBuffer = cm.getRange({ line: 0, ch: 0 },
883 { line: 6, ch: 0 });
884 var expectedLineCount = cm.lineCount() - 5;
885 helpers.doKeys('2', 'c', '3', 'c');
886 eq(expectedLineCount, cm.lineCount());
887 var register = helpers.getRegisterController().getRegister();
888 eq(expectedBuffer, register.toString());
889 is(register.linewise);
890 eq('vim-insert', cm.getOption('keyMap'));
891 });
892 testVim('cc_append', function(cm, vim, helpers) {
893 var expectedLineCount = cm.lineCount();
894 cm.setCursor(cm.lastLine(), 0);
895 helpers.doKeys('c', 'c');
896 eq(expectedLineCount, cm.lineCount());
897 });
898 // Swapcase commands edit in place and do not modify registers.
899 testVim('g~w_repeat', function(cm, vim, helpers) {
900 // Assert that dw does delete newline if it should go to the next line, and
901 // that repeat works properly.
902 var curStart = makeCursor(0, 1);
903 cm.setCursor(curStart);
904 helpers.doKeys('g', '~', '2', 'w');
905 eq(' WORD1\nWORD2', cm.getValue());
906 var register = helpers.getRegisterController().getRegister();
907 eq('', register.toString());
908 is(!register.linewise);
909 eqPos(curStart, cm.getCursor());
910 }, { value: ' word1\nword2' });
911 testVim('g~g~', function(cm, vim, helpers) {
912 var curStart = makeCursor(0, 3);
913 cm.setCursor(curStart);
914 var expectedLineCount = cm.lineCount();
915 var expectedValue = cm.getValue().toUpperCase();
916 helpers.doKeys('2', 'g', '~', '3', 'g', '~');
917 eq(expectedValue, cm.getValue());
918 var register = helpers.getRegisterController().getRegister();
919 eq('', register.toString());
920 is(!register.linewise);
921 eqPos(curStart, cm.getCursor());
922 }, { value: ' word1\nword2\nword3\nword4\nword5\nword6' });
923 testVim('>{motion}', function(cm, vim, helpers) {
924 cm.setCursor(1, 3);
925 var expectedLineCount = cm.lineCount();
926 var expectedValue = ' word1\n word2\nword3 ';
927 helpers.doKeys('>', 'k');
928 eq(expectedValue, cm.getValue());
929 var register = helpers.getRegisterController().getRegister();
930 eq('', register.toString());
931 is(!register.linewise);
932 helpers.assertCursorAt(0, 3);
933 }, { value: ' word1\nword2\nword3 ', indentUnit: 2 });
934 testVim('>>', function(cm, vim, helpers) {
935 cm.setCursor(0, 3);
936 var expectedLineCount = cm.lineCount();
937 var expectedValue = ' word1\n word2\nword3 ';
938 helpers.doKeys('2', '>', '>');
939 eq(expectedValue, cm.getValue());
940 var register = helpers.getRegisterController().getRegister();
941 eq('', register.toString());
942 is(!register.linewise);
943 helpers.assertCursorAt(0, 3);
944 }, { value: ' word1\nword2\nword3 ', indentUnit: 2 });
945 testVim('<{motion}', function(cm, vim, helpers) {
946 cm.setCursor(1, 3);
947 var expectedLineCount = cm.lineCount();
948 var expectedValue = ' word1\nword2\nword3 ';
949 helpers.doKeys('<', 'k');
950 eq(expectedValue, cm.getValue());
951 var register = helpers.getRegisterController().getRegister();
952 eq('', register.toString());
953 is(!register.linewise);
954 helpers.assertCursorAt(0, 1);
955 }, { value: ' word1\n word2\nword3 ', indentUnit: 2 });
956 testVim('<<', function(cm, vim, helpers) {
957 cm.setCursor(0, 3);
958 var expectedLineCount = cm.lineCount();
959 var expectedValue = ' word1\nword2\nword3 ';
960 helpers.doKeys('2', '<', '<');
961 eq(expectedValue, cm.getValue());
962 var register = helpers.getRegisterController().getRegister();
963 eq('', register.toString());
964 is(!register.linewise);
965 helpers.assertCursorAt(0, 1);
966 }, { value: ' word1\n word2\nword3 ', indentUnit: 2 });
967
968 // Edit tests
969 function testEdit(name, before, pos, edit, after) {
970 return testVim(name, function(cm, vim, helpers) {
971 var ch = before.search(pos)
972 var line = before.substring(0, ch).split('\n').length - 1;
973 if (line) {
974 ch = before.substring(0, ch).split('\n').pop().length;
975 }
976 cm.setCursor(line, ch);
977 helpers.doKeys.apply(this, edit.split(''));
978 eq(after, cm.getValue());
979 }, {value: before});
980 }
981
982 // These Delete tests effectively cover word-wise Change, Visual & Yank.
983 // Tabs are used as differentiated whitespace to catch edge cases.
984 // Normal word:
985 testEdit('diw_mid_spc', 'foo \tbAr\t baz', /A/, 'diw', 'foo \t\t baz');
986 testEdit('daw_mid_spc', 'foo \tbAr\t baz', /A/, 'daw', 'foo \tbaz');
987 testEdit('diw_mid_punct', 'foo \tbAr.\t baz', /A/, 'diw', 'foo \t.\t baz');
988 testEdit('daw_mid_punct', 'foo \tbAr.\t baz', /A/, 'daw', 'foo.\t baz');
989 testEdit('diw_mid_punct2', 'foo \t,bAr.\t baz', /A/, 'diw', 'foo \t,.\t baz');
990 testEdit('daw_mid_punct2', 'foo \t,bAr.\t baz', /A/, 'daw', 'foo \t,.\t baz');
991 testEdit('diw_start_spc', 'bAr \tbaz', /A/, 'diw', ' \tbaz');
992 testEdit('daw_start_spc', 'bAr \tbaz', /A/, 'daw', 'baz');
993 testEdit('diw_start_punct', 'bAr. \tbaz', /A/, 'diw', '. \tbaz');
994 testEdit('daw_start_punct', 'bAr. \tbaz', /A/, 'daw', '. \tbaz');
995 testEdit('diw_end_spc', 'foo \tbAr', /A/, 'diw', 'foo \t');
996 testEdit('daw_end_spc', 'foo \tbAr', /A/, 'daw', 'foo');
997 testEdit('diw_end_punct', 'foo \tbAr.', /A/, 'diw', 'foo \t.');
998 testEdit('daw_end_punct', 'foo \tbAr.', /A/, 'daw', 'foo.');
999 // Big word:
1000 testEdit('diW_mid_spc', 'foo \tbAr\t baz', /A/, 'diW', 'foo \t\t baz');
1001 testEdit('daW_mid_spc', 'foo \tbAr\t baz', /A/, 'daW', 'foo \tbaz');
1002 testEdit('diW_mid_punct', 'foo \tbAr.\t baz', /A/, 'diW', 'foo \t\t baz');
1003 testEdit('daW_mid_punct', 'foo \tbAr.\t baz', /A/, 'daW', 'foo \tbaz');
1004 testEdit('diW_mid_punct2', 'foo \t,bAr.\t baz', /A/, 'diW', 'foo \t\t baz');
1005 testEdit('daW_mid_punct2', 'foo \t,bAr.\t baz', /A/, 'daW', 'foo \tbaz');
1006 testEdit('diW_start_spc', 'bAr\t baz', /A/, 'diW', '\t baz');
1007 testEdit('daW_start_spc', 'bAr\t baz', /A/, 'daW', 'baz');
1008 testEdit('diW_start_punct', 'bAr.\t baz', /A/, 'diW', '\t baz');
1009 testEdit('daW_start_punct', 'bAr.\t baz', /A/, 'daW', 'baz');
1010 testEdit('diW_end_spc', 'foo \tbAr', /A/, 'diW', 'foo \t');
1011 testEdit('daW_end_spc', 'foo \tbAr', /A/, 'daW', 'foo');
1012 testEdit('diW_end_punct', 'foo \tbAr.', /A/, 'diW', 'foo \t');
1013 testEdit('daW_end_punct', 'foo \tbAr.', /A/, 'daW', 'foo');
1014 // Deleting text objects
1015 // Open and close on same line
1016 testEdit('di(_open_spc', 'foo (bAr) baz', /\(/, 'di(', 'foo () baz');
1017 testEdit('di)_open_spc', 'foo (bAr) baz', /\(/, 'di)', 'foo () baz');
1018 testEdit('da(_open_spc', 'foo (bAr) baz', /\(/, 'da(', 'foo baz');
1019 testEdit('da)_open_spc', 'foo (bAr) baz', /\(/, 'da)', 'foo baz');
1020
1021 testEdit('di(_middle_spc', 'foo (bAr) baz', /A/, 'di(', 'foo () baz');
1022 testEdit('di)_middle_spc', 'foo (bAr) baz', /A/, 'di)', 'foo () baz');
1023 testEdit('da(_middle_spc', 'foo (bAr) baz', /A/, 'da(', 'foo baz');
1024 testEdit('da)_middle_spc', 'foo (bAr) baz', /A/, 'da)', 'foo baz');
1025
1026 testEdit('di(_close_spc', 'foo (bAr) baz', /\)/, 'di(', 'foo () baz');
1027 testEdit('di)_close_spc', 'foo (bAr) baz', /\)/, 'di)', 'foo () baz');
1028 testEdit('da(_close_spc', 'foo (bAr) baz', /\)/, 'da(', 'foo baz');
1029 testEdit('da)_close_spc', 'foo (bAr) baz', /\)/, 'da)', 'foo baz');
1030
1031 // Open and close on different lines, equally indented
1032 testEdit('di{_middle_spc', 'a{\n\tbar\n}b', /r/, 'di{', 'a{}b');
1033 testEdit('di}_middle_spc', 'a{\n\tbar\n}b', /r/, 'di}', 'a{}b');
1034 testEdit('da{_middle_spc', 'a{\n\tbar\n}b', /r/, 'da{', 'ab');
1035 testEdit('da}_middle_spc', 'a{\n\tbar\n}b', /r/, 'da}', 'ab');
1036
1037 // open and close on diff lines, open indented less than close
1038 testEdit('di{_middle_spc', 'a{\n\tbar\n\t}b', /r/, 'di{', 'a{}b');
1039 testEdit('di}_middle_spc', 'a{\n\tbar\n\t}b', /r/, 'di}', 'a{}b');
1040 testEdit('da{_middle_spc', 'a{\n\tbar\n\t}b', /r/, 'da{', 'ab');
1041 testEdit('da}_middle_spc', 'a{\n\tbar\n\t}b', /r/, 'da}', 'ab');
1042
1043 // open and close on diff lines, open indented more than close
1044 testEdit('di[_middle_spc', 'a\t[\n\tbar\n]b', /r/, 'di[', 'a\t[]b');
1045 testEdit('di]_middle_spc', 'a\t[\n\tbar\n]b', /r/, 'di]', 'a\t[]b');
1046 testEdit('da[_middle_spc', 'a\t[\n\tbar\n]b', /r/, 'da[', 'a\tb');
1047 testEdit('da]_middle_spc', 'a\t[\n\tbar\n]b', /r/, 'da]', 'a\tb');
1048
1049 // Operator-motion tests
1050 testVim('D', function(cm, vim, helpers) {
1051 cm.setCursor(0, 3);
1052 helpers.doKeys('D');
1053 eq(' wo\nword2\n word3', cm.getValue());
1054 var register = helpers.getRegisterController().getRegister();
1055 eq('rd1', register.toString());
1056 is(!register.linewise);
1057 helpers.assertCursorAt(0, 2);
1058 }, { value: ' word1\nword2\n word3' });
1059 testVim('C', function(cm, vim, helpers) {
1060 var curStart = makeCursor(0, 3);
1061 cm.setCursor(curStart);
1062 helpers.doKeys('C');
1063 eq(' wo\nword2\n word3', cm.getValue());
1064 var register = helpers.getRegisterController().getRegister();
1065 eq('rd1', register.toString());
1066 is(!register.linewise);
1067 eqPos(curStart, cm.getCursor());
1068 eq('vim-insert', cm.getOption('keyMap'));
1069 }, { value: ' word1\nword2\n word3' });
1070 testVim('Y', function(cm, vim, helpers) {
1071 var curStart = makeCursor(0, 3);
1072 cm.setCursor(curStart);
1073 helpers.doKeys('Y');
1074 eq(' word1\nword2\n word3', cm.getValue());
1075 var register = helpers.getRegisterController().getRegister();
1076 eq('rd1', register.toString());
1077 is(!register.linewise);
1078 helpers.assertCursorAt(0, 3);
1079 }, { value: ' word1\nword2\n word3' });
1080 testVim('~', function(cm, vim, helpers) {
1081 helpers.doKeys('3', '~');
1082 eq('ABCdefg', cm.getValue());
1083 helpers.assertCursorAt(0, 3);
1084 }, { value: 'abcdefg' });
1085
1086 // Action tests
1087 testVim('ctrl-a', function(cm, vim, helpers) {
1088 cm.setCursor(0, 0);
1089 helpers.doKeys('<C-a>');
1090 eq('-9', cm.getValue());
1091 helpers.assertCursorAt(0, 1);
1092 helpers.doKeys('2','<C-a>');
1093 eq('-7', cm.getValue());
1094 }, {value: '-10'});
1095 testVim('ctrl-x', function(cm, vim, helpers) {
1096 cm.setCursor(0, 0);
1097 helpers.doKeys('<C-x>');
1098 eq('-1', cm.getValue());
1099 helpers.assertCursorAt(0, 1);
1100 helpers.doKeys('2','<C-x>');
1101 eq('-3', cm.getValue());
1102 }, {value: '0'});
1103 testVim('<C-x>/<C-a> search forward', function(cm, vim, helpers) {
1104 forEach(['<C-x>', '<C-a>'], function(key) {
1105 cm.setCursor(0, 0);
1106 helpers.doKeys(key);
1107 helpers.assertCursorAt(0, 5);
1108 helpers.doKeys('l');
1109 helpers.doKeys(key);
1110 helpers.assertCursorAt(0, 10);
1111 cm.setCursor(0, 11);
1112 helpers.doKeys(key);
1113 helpers.assertCursorAt(0, 11);
1114 });
1115 }, {value: '__jmp1 jmp2 jmp'});
1116 testVim('a', function(cm, vim, helpers) {
1117 cm.setCursor(0, 1);
1118 helpers.doKeys('a');
1119 helpers.assertCursorAt(0, 2);
1120 eq('vim-insert', cm.getOption('keyMap'));
1121 });
1122 testVim('a_eol', function(cm, vim, helpers) {
1123 cm.setCursor(0, lines[0].length - 1);
1124 helpers.doKeys('a');
1125 helpers.assertCursorAt(0, lines[0].length);
1126 eq('vim-insert', cm.getOption('keyMap'));
1127 });
1128 testVim('i', function(cm, vim, helpers) {
1129 cm.setCursor(0, 1);
1130 helpers.doKeys('i');
1131 helpers.assertCursorAt(0, 1);
1132 eq('vim-insert', cm.getOption('keyMap'));
1133 });
1134 testVim('i_repeat', function(cm, vim, helpers) {
1135 helpers.doKeys('3', 'i');
1136 cm.replaceRange('test', cm.getCursor());
1137 helpers.doInsertModeKeys('Esc');
1138 eq('testtesttest', cm.getValue());
1139 helpers.assertCursorAt(0, 11);
1140 }, { value: '' });
1141 testVim('i_repeat_delete', function(cm, vim, helpers) {
1142 cm.setCursor(0, 4);
1143 helpers.doKeys('2', 'i');
1144 cm.replaceRange('z', cm.getCursor());
1145 helpers.doInsertModeKeys('Backspace', 'Backspace', 'Esc');
1146 eq('abe', cm.getValue());
1147 helpers.assertCursorAt(0, 1);
1148 }, { value: 'abcde' });
1149 testVim('A', function(cm, vim, helpers) {
1150 helpers.doKeys('A');
1151 helpers.assertCursorAt(0, lines[0].length);
1152 eq('vim-insert', cm.getOption('keyMap'));
1153 });
1154 testVim('I', function(cm, vim, helpers) {
1155 cm.setCursor(0, 4);
1156 helpers.doKeys('I');
1157 helpers.assertCursorAt(0, lines[0].textStart);
1158 eq('vim-insert', cm.getOption('keyMap'));
1159 });
1160 testVim('I_repeat', function(cm, vim, helpers) {
1161 cm.setCursor(0, 1);
1162 helpers.doKeys('3', 'I');
1163 cm.replaceRange('test', cm.getCursor());
1164 helpers.doInsertModeKeys('Esc');
1165 eq('testtesttestblah', cm.getValue());
1166 helpers.assertCursorAt(0, 11);
1167 }, { value: 'blah' });
1168 testVim('o', function(cm, vim, helpers) {
1169 cm.setCursor(0, 4);
1170 helpers.doKeys('o');
1171 eq('word1\n\nword2', cm.getValue());
1172 helpers.assertCursorAt(1, 0);
1173 eq('vim-insert', cm.getOption('keyMap'));
1174 }, { value: 'word1\nword2' });
1175 testVim('o_repeat', function(cm, vim, helpers) {
1176 cm.setCursor(0, 0);
1177 helpers.doKeys('3', 'o');
1178 cm.replaceRange('test', cm.getCursor());
1179 helpers.doInsertModeKeys('Esc');
1180 eq('\ntest\ntest\ntest', cm.getValue());
1181 helpers.assertCursorAt(3, 3);
1182 }, { value: '' });
1183 testVim('O', function(cm, vim, helpers) {
1184 cm.setCursor(0, 4);
1185 helpers.doKeys('O');
1186 eq('\nword1\nword2', cm.getValue());
1187 helpers.assertCursorAt(0, 0);
1188 eq('vim-insert', cm.getOption('keyMap'));
1189 }, { value: 'word1\nword2' });
1190 testVim('J', function(cm, vim, helpers) {
1191 cm.setCursor(0, 4);
1192 helpers.doKeys('J');
1193 var expectedValue = 'word1 word2\nword3\n word4';
1194 eq(expectedValue, cm.getValue());
1195 helpers.assertCursorAt(0, expectedValue.indexOf('word2') - 1);
1196 }, { value: 'word1 \n word2\nword3\n word4' });
1197 testVim('J_repeat', function(cm, vim, helpers) {
1198 cm.setCursor(0, 4);
1199 helpers.doKeys('3', 'J');
1200 var expectedValue = 'word1 word2 word3\n word4';
1201 eq(expectedValue, cm.getValue());
1202 helpers.assertCursorAt(0, expectedValue.indexOf('word3') - 1);
1203 }, { value: 'word1 \n word2\nword3\n word4' });
1204 testVim('p', function(cm, vim, helpers) {
1205 cm.setCursor(0, 1);
1206 helpers.getRegisterController().pushText('"', 'yank', 'abc\ndef', false);
1207 helpers.doKeys('p');
1208 eq('__abc\ndef_', cm.getValue());
1209 helpers.assertCursorAt(1, 2);
1210 }, { value: '___' });
1211 testVim('p_register', function(cm, vim, helpers) {
1212 cm.setCursor(0, 1);
1213 helpers.getRegisterController().getRegister('a').setText('abc\ndef', false);
1214 helpers.doKeys('"', 'a', 'p');
1215 eq('__abc\ndef_', cm.getValue());
1216 helpers.assertCursorAt(1, 2);
1217 }, { value: '___' });
1218 testVim('p_wrong_register', function(cm, vim, helpers) {
1219 cm.setCursor(0, 1);
1220 helpers.getRegisterController().getRegister('a').setText('abc\ndef', false);
1221 helpers.doKeys('p');
1222 eq('___', cm.getValue());
1223 helpers.assertCursorAt(0, 1);
1224 }, { value: '___' });
1225 testVim('p_line', function(cm, vim, helpers) {
1226 cm.setCursor(0, 1);
1227 helpers.getRegisterController().pushText('"', 'yank', ' a\nd\n', true);
1228 helpers.doKeys('2', 'p');
1229 eq('___\n a\nd\n a\nd', cm.getValue());
1230 helpers.assertCursorAt(1, 2);
1231 }, { value: '___' });
1232 testVim('p_lastline', function(cm, vim, helpers) {
1233 cm.setCursor(0, 1);
1234 helpers.getRegisterController().pushText('"', 'yank', ' a\nd', true);
1235 helpers.doKeys('2', 'p');
1236 eq('___\n a\nd\n a\nd', cm.getValue());
1237 helpers.assertCursorAt(1, 2);
1238 }, { value: '___' });
1239 testVim('P', function(cm, vim, helpers) {
1240 cm.setCursor(0, 1);
1241 helpers.getRegisterController().pushText('"', 'yank', 'abc\ndef', false);
1242 helpers.doKeys('P');
1243 eq('_abc\ndef__', cm.getValue());
1244 helpers.assertCursorAt(1, 3);
1245 }, { value: '___' });
1246 testVim('P_line', function(cm, vim, helpers) {
1247 cm.setCursor(0, 1);
1248 helpers.getRegisterController().pushText('"', 'yank', ' a\nd\n', true);
1249 helpers.doKeys('2', 'P');
1250 eq(' a\nd\n a\nd\n___', cm.getValue());
1251 helpers.assertCursorAt(0, 2);
1252 }, { value: '___' });
1253 testVim('r', function(cm, vim, helpers) {
1254 cm.setCursor(0, 1);
1255 helpers.doKeys('3', 'r', 'u');
1256 eq('wuuuet\nanother', cm.getValue(),'3r failed');
1257 helpers.assertCursorAt(0, 3);
1258 cm.setCursor(0, 4);
1259 helpers.doKeys('v', 'j', 'h', 'r', '<Space>');
1260 eq('wuuu \n her', cm.getValue(),'Replacing selection by space-characters failed');
1261 }, { value: 'wordet\nanother' });
1262 testVim('R', function(cm, vim, helpers) {
1263 cm.setCursor(0, 1);
1264 helpers.doKeys('R');
1265 helpers.assertCursorAt(0, 1);
1266 eq('vim-replace', cm.getOption('keyMap'));
1267 is(cm.state.overwrite, 'Setting overwrite state failed');
1268 });
1269 testVim('mark', function(cm, vim, helpers) {
1270 cm.setCursor(2, 2);
1271 helpers.doKeys('m', 't');
1272 cm.setCursor(0, 0);
1273 helpers.doKeys('\'', 't');
1274 helpers.assertCursorAt(2, 2);
1275 cm.setCursor(0, 0);
1276 helpers.doKeys('`', 't');
1277 helpers.assertCursorAt(2, 2);
1278 });
1279 testVim('jumpToMark_next', function(cm, vim, helpers) {
1280 cm.setCursor(2, 2);
1281 helpers.doKeys('m', 't');
1282 cm.setCursor(0, 0);
1283 helpers.doKeys(']', '`');
1284 helpers.assertCursorAt(2, 2);
1285 cm.setCursor(0, 0);
1286 helpers.doKeys(']', '\'');
1287 helpers.assertCursorAt(2, 0);
1288 });
1289 testVim('jumpToMark_next_repeat', function(cm, vim, helpers) {
1290 cm.setCursor(2, 2);
1291 helpers.doKeys('m', 'a');
1292 cm.setCursor(3, 2);
1293 helpers.doKeys('m', 'b');
1294 cm.setCursor(4, 2);
1295 helpers.doKeys('m', 'c');
1296 cm.setCursor(0, 0);
1297 helpers.doKeys('2', ']', '`');
1298 helpers.assertCursorAt(3, 2);
1299 cm.setCursor(0, 0);
1300 helpers.doKeys('2', ']', '\'');
1301 helpers.assertCursorAt(3, 1);
1302 });
1303 testVim('jumpToMark_next_sameline', function(cm, vim, helpers) {
1304 cm.setCursor(2, 0);
1305 helpers.doKeys('m', 'a');
1306 cm.setCursor(2, 4);
1307 helpers.doKeys('m', 'b');
1308 cm.setCursor(2, 2);
1309 helpers.doKeys(']', '`');
1310 helpers.assertCursorAt(2, 4);
1311 });
1312 testVim('jumpToMark_next_onlyprev', function(cm, vim, helpers) {
1313 cm.setCursor(2, 0);
1314 helpers.doKeys('m', 'a');
1315 cm.setCursor(4, 0);
1316 helpers.doKeys(']', '`');
1317 helpers.assertCursorAt(4, 0);
1318 });
1319 testVim('jumpToMark_next_nomark', function(cm, vim, helpers) {
1320 cm.setCursor(2, 2);
1321 helpers.doKeys(']', '`');
1322 helpers.assertCursorAt(2, 2);
1323 helpers.doKeys(']', '\'');
1324 helpers.assertCursorAt(2, 0);
1325 });
1326 testVim('jumpToMark_next_linewise_over', function(cm, vim, helpers) {
1327 cm.setCursor(2, 2);
1328 helpers.doKeys('m', 'a');
1329 cm.setCursor(3, 4);
1330 helpers.doKeys('m', 'b');
1331 cm.setCursor(2, 1);
1332 helpers.doKeys(']', '\'');
1333 helpers.assertCursorAt(3, 1);
1334 });
1335 testVim('jumpToMark_next_action', function(cm, vim, helpers) {
1336 cm.setCursor(2, 2);
1337 helpers.doKeys('m', 't');
1338 cm.setCursor(0, 0);
1339 helpers.doKeys('d', ']', '`');
1340 helpers.assertCursorAt(0, 0);
1341 var actual = cm.getLine(0);
1342 var expected = 'pop pop 0 1 2 3 4';
1343 eq(actual, expected, "Deleting while jumping to the next mark failed.");
1344 });
1345 testVim('jumpToMark_next_line_action', function(cm, vim, helpers) {
1346 cm.setCursor(2, 2);
1347 helpers.doKeys('m', 't');
1348 cm.setCursor(0, 0);
1349 helpers.doKeys('d', ']', '\'');
1350 helpers.assertCursorAt(0, 1);
1351 var actual = cm.getLine(0);
1352 var expected = ' (a) [b] {c} '
1353 eq(actual, expected, "Deleting while jumping to the next mark line failed.");
1354 });
1355 testVim('jumpToMark_prev', function(cm, vim, helpers) {
1356 cm.setCursor(2, 2);
1357 helpers.doKeys('m', 't');
1358 cm.setCursor(4, 0);
1359 helpers.doKeys('[', '`');
1360 helpers.assertCursorAt(2, 2);
1361 cm.setCursor(4, 0);
1362 helpers.doKeys('[', '\'');
1363 helpers.assertCursorAt(2, 0);
1364 });
1365 testVim('jumpToMark_prev_repeat', function(cm, vim, helpers) {
1366 cm.setCursor(2, 2);
1367 helpers.doKeys('m', 'a');
1368 cm.setCursor(3, 2);
1369 helpers.doKeys('m', 'b');
1370 cm.setCursor(4, 2);
1371 helpers.doKeys('m', 'c');
1372 cm.setCursor(5, 0);
1373 helpers.doKeys('2', '[', '`');
1374 helpers.assertCursorAt(3, 2);
1375 cm.setCursor(5, 0);
1376 helpers.doKeys('2', '[', '\'');
1377 helpers.assertCursorAt(3, 1);
1378 });
1379 testVim('jumpToMark_prev_sameline', function(cm, vim, helpers) {
1380 cm.setCursor(2, 0);
1381 helpers.doKeys('m', 'a');
1382 cm.setCursor(2, 4);
1383 helpers.doKeys('m', 'b');
1384 cm.setCursor(2, 2);
1385 helpers.doKeys('[', '`');
1386 helpers.assertCursorAt(2, 0);
1387 });
1388 testVim('jumpToMark_prev_onlynext', function(cm, vim, helpers) {
1389 cm.setCursor(4, 4);
1390 helpers.doKeys('m', 'a');
1391 cm.setCursor(2, 0);
1392 helpers.doKeys('[', '`');
1393 helpers.assertCursorAt(2, 0);
1394 });
1395 testVim('jumpToMark_prev_nomark', function(cm, vim, helpers) {
1396 cm.setCursor(2, 2);
1397 helpers.doKeys('[', '`');
1398 helpers.assertCursorAt(2, 2);
1399 helpers.doKeys('[', '\'');
1400 helpers.assertCursorAt(2, 0);
1401 });
1402 testVim('jumpToMark_prev_linewise_over', function(cm, vim, helpers) {
1403 cm.setCursor(2, 2);
1404 helpers.doKeys('m', 'a');
1405 cm.setCursor(3, 4);
1406 helpers.doKeys('m', 'b');
1407 cm.setCursor(3, 6);
1408 helpers.doKeys('[', '\'');
1409 helpers.assertCursorAt(2, 0);
1410 });
1411 testVim('delmark_single', function(cm, vim, helpers) {
1412 cm.setCursor(1, 2);
1413 helpers.doKeys('m', 't');
1414 helpers.doEx('delmarks t');
1415 cm.setCursor(0, 0);
1416 helpers.doKeys('`', 't');
1417 helpers.assertCursorAt(0, 0);
1418 });
1419 testVim('delmark_range', function(cm, vim, helpers) {
1420 cm.setCursor(1, 2);
1421 helpers.doKeys('m', 'a');
1422 cm.setCursor(2, 2);
1423 helpers.doKeys('m', 'b');
1424 cm.setCursor(3, 2);
1425 helpers.doKeys('m', 'c');
1426 cm.setCursor(4, 2);
1427 helpers.doKeys('m', 'd');
1428 cm.setCursor(5, 2);
1429 helpers.doKeys('m', 'e');
1430 helpers.doEx('delmarks b-d');
1431 cm.setCursor(0, 0);
1432 helpers.doKeys('`', 'a');
1433 helpers.assertCursorAt(1, 2);
1434 helpers.doKeys('`', 'b');
1435 helpers.assertCursorAt(1, 2);
1436 helpers.doKeys('`', 'c');
1437 helpers.assertCursorAt(1, 2);
1438 helpers.doKeys('`', 'd');
1439 helpers.assertCursorAt(1, 2);
1440 helpers.doKeys('`', 'e');
1441 helpers.assertCursorAt(5, 2);
1442 });
1443 testVim('delmark_multi', function(cm, vim, helpers) {
1444 cm.setCursor(1, 2);
1445 helpers.doKeys('m', 'a');
1446 cm.setCursor(2, 2);
1447 helpers.doKeys('m', 'b');
1448 cm.setCursor(3, 2);
1449 helpers.doKeys('m', 'c');
1450 cm.setCursor(4, 2);
1451 helpers.doKeys('m', 'd');
1452 cm.setCursor(5, 2);
1453 helpers.doKeys('m', 'e');
1454 helpers.doEx('delmarks bcd');
1455 cm.setCursor(0, 0);
1456 helpers.doKeys('`', 'a');
1457 helpers.assertCursorAt(1, 2);
1458 helpers.doKeys('`', 'b');
1459 helpers.assertCursorAt(1, 2);
1460 helpers.doKeys('`', 'c');
1461 helpers.assertCursorAt(1, 2);
1462 helpers.doKeys('`', 'd');
1463 helpers.assertCursorAt(1, 2);
1464 helpers.doKeys('`', 'e');
1465 helpers.assertCursorAt(5, 2);
1466 });
1467 testVim('delmark_multi_space', function(cm, vim, helpers) {
1468 cm.setCursor(1, 2);
1469 helpers.doKeys('m', 'a');
1470 cm.setCursor(2, 2);
1471 helpers.doKeys('m', 'b');
1472 cm.setCursor(3, 2);
1473 helpers.doKeys('m', 'c');
1474 cm.setCursor(4, 2);
1475 helpers.doKeys('m', 'd');
1476 cm.setCursor(5, 2);
1477 helpers.doKeys('m', 'e');
1478 helpers.doEx('delmarks b c d');
1479 cm.setCursor(0, 0);
1480 helpers.doKeys('`', 'a');
1481 helpers.assertCursorAt(1, 2);
1482 helpers.doKeys('`', 'b');
1483 helpers.assertCursorAt(1, 2);
1484 helpers.doKeys('`', 'c');
1485 helpers.assertCursorAt(1, 2);
1486 helpers.doKeys('`', 'd');
1487 helpers.assertCursorAt(1, 2);
1488 helpers.doKeys('`', 'e');
1489 helpers.assertCursorAt(5, 2);
1490 });
1491 testVim('delmark_all', function(cm, vim, helpers) {
1492 cm.setCursor(1, 2);
1493 helpers.doKeys('m', 'a');
1494 cm.setCursor(2, 2);
1495 helpers.doKeys('m', 'b');
1496 cm.setCursor(3, 2);
1497 helpers.doKeys('m', 'c');
1498 cm.setCursor(4, 2);
1499 helpers.doKeys('m', 'd');
1500 cm.setCursor(5, 2);
1501 helpers.doKeys('m', 'e');
1502 helpers.doEx('delmarks a b-de');
1503 cm.setCursor(0, 0);
1504 helpers.doKeys('`', 'a');
1505 helpers.assertCursorAt(0, 0);
1506 helpers.doKeys('`', 'b');
1507 helpers.assertCursorAt(0, 0);
1508 helpers.doKeys('`', 'c');
1509 helpers.assertCursorAt(0, 0);
1510 helpers.doKeys('`', 'd');
1511 helpers.assertCursorAt(0, 0);
1512 helpers.doKeys('`', 'e');
1513 helpers.assertCursorAt(0, 0);
1514 });
1515 testVim('visual', function(cm, vim, helpers) {
1516 helpers.doKeys('l', 'v', 'l', 'l');
1517 helpers.assertCursorAt(0, 3);
1518 eqPos(makeCursor(0, 1), cm.getCursor('anchor'));
1519 helpers.doKeys('d');
1520 eq('15', cm.getValue());
1521 }, { value: '12345' });
1522 testVim('visual_line', function(cm, vim, helpers) {
1523 helpers.doKeys('l', 'V', 'l', 'j', 'j', 'd');
1524 eq(' 4\n 5', cm.getValue());
1525 }, { value: ' 1\n 2\n 3\n 4\n 5' });
1526 testVim('visual_marks', function(cm, vim, helpers) {
1527 helpers.doKeys('l', 'v', 'l', 'l', 'v');
1528 // Test visual mode marks
1529 cm.setCursor(0, 0);
1530 helpers.doKeys('\'', '<');
1531 helpers.assertCursorAt(0, 1);
1532 helpers.doKeys('\'', '>');
1533 helpers.assertCursorAt(0, 3);
1534 });
1535 testVim('visual_join', function(cm, vim, helpers) {
1536 helpers.doKeys('l', 'V', 'l', 'j', 'j', 'J');
1537 eq(' 1 2 3\n 4\n 5', cm.getValue());
1538 }, { value: ' 1\n 2\n 3\n 4\n 5' });
1539 testVim('visual_blank', function(cm, vim, helpers) {
1540 helpers.doKeys('v', 'k');
1541 eq(vim.visualMode, true);
1542 }, { value: '\n' });
1543 testVim('reselect_visual', function(cm, vim, helpers) {
1544 helpers.doKeys('l', 'v', 'l', 'l', 'y', 'g', 'v');
1545 helpers.assertCursorAt(0, 3);
1546 eqPos(makeCursor(0, 1), cm.getCursor('anchor'));
1547 helpers.doKeys('d');
1548 eq('15', cm.getValue());
1549 }, { value: '12345' });
1550 testVim('reselect_visual_line', function(cm, vim, helpers) {
1551 helpers.doKeys('l', 'V', 'l', 'j', 'j', 'V', 'g', 'v', 'd');
1552 eq(' 4\n 5', cm.getValue());
1553 }, { value: ' 1\n 2\n 3\n 4\n 5' });
1554 testVim('s_normal', function(cm, vim, helpers) {
1555 cm.setCursor(0, 1);
1556 helpers.doKeys('s');
1557 helpers.doInsertModeKeys('Esc');
1558 helpers.assertCursorAt(0, 0);
1559 eq('ac', cm.getValue());
1560 }, { value: 'abc'});
1561 testVim('s_visual', function(cm, vim, helpers) {
1562 cm.setCursor(0, 1);
1563 helpers.doKeys('v', 's');
1564 helpers.doInsertModeKeys('Esc');
1565 helpers.assertCursorAt(0, 0);
1566 eq('ac', cm.getValue());
1567 }, { value: 'abc'});
1568 testVim('o_visual', function(cm,vim,helpers) {
1569 cm.setCursor(0,0);
1570 helpers.doKeys('v','l','l','l','o');
1571 helpers.assertCursorAt(0,0);
1572 helpers.doKeys('v','v','j','j','j','o');
1573 helpers.assertCursorAt(0,0);
1574 helpers.doKeys('o');
1575 helpers.doKeys('l','l')
1576 helpers.assertCursorAt(3,2);
1577 helpers.doKeys('d');
1578 eq('p',cm.getValue());
1579 }, { value: 'abcd\nefgh\nijkl\nmnop'});
1580
1581 testVim('S_normal', function(cm, vim, helpers) {
1582 cm.setCursor(0, 1);
1583 helpers.doKeys('j', 'S');
1584 helpers.doInsertModeKeys('Esc');
1585 helpers.assertCursorAt(1, 0);
1586 eq('aa\n\ncc', cm.getValue());
1587 }, { value: 'aa\nbb\ncc'});
1588 testVim('S_visual', function(cm, vim, helpers) {
1589 cm.setCursor(0, 1);
1590 helpers.doKeys('v', 'j', 'S');
1591 helpers.doInsertModeKeys('Esc');
1592 helpers.assertCursorAt(0, 0);
1593 eq('\ncc', cm.getValue());
1594 }, { value: 'aa\nbb\ncc'});
1595
1596 testVim('/ and n/N', function(cm, vim, helpers) {
1597 cm.openDialog = helpers.fakeOpenDialog('match');
1598 helpers.doKeys('/');
1599 helpers.assertCursorAt(0, 11);
1600 helpers.doKeys('n');
1601 helpers.assertCursorAt(1, 6);
1602 helpers.doKeys('N');
1603 helpers.assertCursorAt(0, 11);
1604
1605 cm.setCursor(0, 0);
1606 helpers.doKeys('2', '/');
1607 helpers.assertCursorAt(1, 6);
1608 }, { value: 'match nope match \n nope Match' });
1609 testVim('/_case', function(cm, vim, helpers) {
1610 cm.openDialog = helpers.fakeOpenDialog('Match');
1611 helpers.doKeys('/');
1612 helpers.assertCursorAt(1, 6);
1613 }, { value: 'match nope match \n nope Match' });
1614 testVim('/_2_pcre', function(cm, vim, helpers) {
1615 CodeMirror.Vim.setOption('pcre', true);
1616 cm.openDialog = helpers.fakeOpenDialog('(word){2}');
1617 helpers.doKeys('/');
1618 helpers.assertCursorAt(1, 9);
1619 helpers.doKeys('n');
1620 helpers.assertCursorAt(2, 1);
1621 }, { value: 'word\n another wordword\n wordwordword\n' });
1622 testVim('/_2_nopcre', function(cm, vim, helpers) {
1623 CodeMirror.Vim.setOption('pcre', false);
1624 cm.openDialog = helpers.fakeOpenDialog('\\(word\\)\\{2}');
1625 helpers.doKeys('/');
1626 helpers.assertCursorAt(1, 9);
1627 helpers.doKeys('n');
1628 helpers.assertCursorAt(2, 1);
1629 }, { value: 'word\n another wordword\n wordwordword\n' });
1630 testVim('/_nongreedy', function(cm, vim, helpers) {
1631 cm.openDialog = helpers.fakeOpenDialog('aa');
1632 helpers.doKeys('/');
1633 helpers.assertCursorAt(0, 4);
1634 helpers.doKeys('n');
1635 helpers.assertCursorAt(1, 3);
1636 helpers.doKeys('n');
1637 helpers.assertCursorAt(0, 0);
1638 }, { value: 'aaa aa \n a aa'});
1639 testVim('?_nongreedy', function(cm, vim, helpers) {
1640 cm.openDialog = helpers.fakeOpenDialog('aa');
1641 helpers.doKeys('?');
1642 helpers.assertCursorAt(1, 3);
1643 helpers.doKeys('n');
1644 helpers.assertCursorAt(0, 4);
1645 helpers.doKeys('n');
1646 helpers.assertCursorAt(0, 0);
1647 }, { value: 'aaa aa \n a aa'});
1648 testVim('/_greedy', function(cm, vim, helpers) {
1649 cm.openDialog = helpers.fakeOpenDialog('a+');
1650 helpers.doKeys('/');
1651 helpers.assertCursorAt(0, 4);
1652 helpers.doKeys('n');
1653 helpers.assertCursorAt(1, 1);
1654 helpers.doKeys('n');
1655 helpers.assertCursorAt(1, 3);
1656 helpers.doKeys('n');
1657 helpers.assertCursorAt(0, 0);
1658 }, { value: 'aaa aa \n a aa'});
1659 testVim('?_greedy', function(cm, vim, helpers) {
1660 cm.openDialog = helpers.fakeOpenDialog('a+');
1661 helpers.doKeys('?');
1662 helpers.assertCursorAt(1, 3);
1663 helpers.doKeys('n');
1664 helpers.assertCursorAt(1, 1);
1665 helpers.doKeys('n');
1666 helpers.assertCursorAt(0, 4);
1667 helpers.doKeys('n');
1668 helpers.assertCursorAt(0, 0);
1669 }, { value: 'aaa aa \n a aa'});
1670 testVim('/_greedy_0_or_more', function(cm, vim, helpers) {
1671 cm.openDialog = helpers.fakeOpenDialog('a*');
1672 helpers.doKeys('/');
1673 helpers.assertCursorAt(0, 3);
1674 helpers.doKeys('n');
1675 helpers.assertCursorAt(0, 4);
1676 helpers.doKeys('n');
1677 helpers.assertCursorAt(0, 5);
1678 helpers.doKeys('n');
1679 helpers.assertCursorAt(1, 0);
1680 helpers.doKeys('n');
1681 helpers.assertCursorAt(1, 1);
1682 helpers.doKeys('n');
1683 helpers.assertCursorAt(0, 0);
1684 }, { value: 'aaa aa\n aa'});
1685 testVim('?_greedy_0_or_more', function(cm, vim, helpers) {
1686 cm.openDialog = helpers.fakeOpenDialog('a*');
1687 helpers.doKeys('?');
1688 helpers.assertCursorAt(1, 1);
1689 helpers.doKeys('n');
1690 helpers.assertCursorAt(1, 0);
1691 helpers.doKeys('n');
1692 helpers.assertCursorAt(0, 5);
1693 helpers.doKeys('n');
1694 helpers.assertCursorAt(0, 4);
1695 helpers.doKeys('n');
1696 helpers.assertCursorAt(0, 3);
1697 helpers.doKeys('n');
1698 helpers.assertCursorAt(0, 0);
1699 }, { value: 'aaa aa\n aa'});
1700 testVim('? and n/N', function(cm, vim, helpers) {
1701 cm.openDialog = helpers.fakeOpenDialog('match');
1702 helpers.doKeys('?');
1703 helpers.assertCursorAt(1, 6);
1704 helpers.doKeys('n');
1705 helpers.assertCursorAt(0, 11);
1706 helpers.doKeys('N');
1707 helpers.assertCursorAt(1, 6);
1708
1709 cm.setCursor(0, 0);
1710 helpers.doKeys('2', '?');
1711 helpers.assertCursorAt(0, 11);
1712 }, { value: 'match nope match \n nope Match' });
1713 testVim('*', function(cm, vim, helpers) {
1714 cm.setCursor(0, 9);
1715 helpers.doKeys('*');
1716 helpers.assertCursorAt(0, 22);
1717
1718 cm.setCursor(0, 9);
1719 helpers.doKeys('2', '*');
1720 helpers.assertCursorAt(1, 8);
1721 }, { value: 'nomatch match nomatch match \nnomatch Match' });
1722 testVim('*_no_word', function(cm, vim, helpers) {
1723 cm.setCursor(0, 0);
1724 helpers.doKeys('*');
1725 helpers.assertCursorAt(0, 0);
1726 }, { value: ' \n match \n' });
1727 testVim('*_symbol', function(cm, vim, helpers) {
1728 cm.setCursor(0, 0);
1729 helpers.doKeys('*');
1730 helpers.assertCursorAt(1, 0);
1731 }, { value: ' /}\n/} match \n' });
1732 testVim('#', function(cm, vim, helpers) {
1733 cm.setCursor(0, 9);
1734 helpers.doKeys('#');
1735 helpers.assertCursorAt(1, 8);
1736
1737 cm.setCursor(0, 9);
1738 helpers.doKeys('2', '#');
1739 helpers.assertCursorAt(0, 22);
1740 }, { value: 'nomatch match nomatch match \nnomatch Match' });
1741 testVim('*_seek', function(cm, vim, helpers) {
1742 // Should skip over space and symbols.
1743 cm.setCursor(0, 3);
1744 helpers.doKeys('*');
1745 helpers.assertCursorAt(0, 22);
1746 }, { value: ' := match nomatch match \nnomatch Match' });
1747 testVim('#', function(cm, vim, helpers) {
1748 // Should skip over space and symbols.
1749 cm.setCursor(0, 3);
1750 helpers.doKeys('#');
1751 helpers.assertCursorAt(1, 8);
1752 }, { value: ' := match nomatch match \nnomatch Match' });
1753 testVim('macro_insert', function(cm, vim, helpers) {
1754 cm.setCursor(0, 0);
1755 helpers.doKeys('q', 'a', '0', 'i');
1756 cm.replaceRange('foo', cm.getCursor());
1757 helpers.doInsertModeKeys('Esc');
1758 helpers.doKeys('q', '@', 'a');
1759 eq('foofoo', cm.getValue());
1760 }, { value: ''});
1761 testVim('macro_space', function(cm, vim, helpers) {
1762 cm.setCursor(0, 0);
1763 helpers.doKeys('<Space>', '<Space>');
1764 helpers.assertCursorAt(0, 2);
1765 helpers.doKeys('q', 'a', '<Space>', '<Space>', 'q');
1766 helpers.assertCursorAt(0, 4);
1767 helpers.doKeys('@', 'a');
1768 helpers.assertCursorAt(0, 6);
1769 helpers.doKeys('@', 'a');
1770 helpers.assertCursorAt(0, 8);
1771 }, { value: 'one line of text.'});
1772 testVim('macro_parens', function(cm, vim, helpers) {
1773 cm.setCursor(0, 0);
1774 helpers.doKeys('q', 'z', 'i');
1775 cm.replaceRange('(', cm.getCursor());
1776 helpers.doInsertModeKeys('Esc');
1777 helpers.doKeys('e', 'a');
1778 cm.replaceRange(')', cm.getCursor());
1779 helpers.doInsertModeKeys('Esc');
1780 helpers.doKeys('q');
1781 helpers.doKeys('w', '@', 'z');
1782 helpers.doKeys('w', '@', 'z');
1783 eq('(see) (spot) (run)', cm.getValue());
1784 }, { value: 'see spot run'});
1785 testVim('macro_overwrite', function(cm, vim, helpers) {
1786 cm.setCursor(0, 0);
1787 helpers.doKeys('q', 'z', '0', 'i');
1788 cm.replaceRange('I ', cm.getCursor());
1789 helpers.doInsertModeKeys('Esc');
1790 helpers.doKeys('q');
1791 helpers.doKeys('e');
1792 // Now replace the macro with something else.
1793 helpers.doKeys('q', 'z', 'a');
1794 cm.replaceRange('.', cm.getCursor());
1795 helpers.doInsertModeKeys('Esc');
1796 helpers.doKeys('q');
1797 helpers.doKeys('e', '@', 'z');
1798 helpers.doKeys('e', '@', 'z');
1799 eq('I see. spot. run.', cm.getValue());
1800 }, { value: 'see spot run'});
1801 testVim('macro_search_f', function(cm, vim, helpers) {
1802 cm.setCursor(0, 0);
1803 helpers.doKeys('q', 'a', 'f', ' ');
1804 helpers.assertCursorAt(0,3);
1805 helpers.doKeys('q', '0');
1806 helpers.assertCursorAt(0,0);
1807 helpers.doKeys('@', 'a');
1808 helpers.assertCursorAt(0,3);
1809 }, { value: 'The quick brown fox jumped over the lazy dog.'});
1810 testVim('macro_search_2f', function(cm, vim, helpers) {
1811 cm.setCursor(0, 0);
1812 helpers.doKeys('q', 'a', '2', 'f', ' ');
1813 helpers.assertCursorAt(0,9);
1814 helpers.doKeys('q', '0');
1815 helpers.assertCursorAt(0,0);
1816 helpers.doKeys('@', 'a');
1817 helpers.assertCursorAt(0,9);
1818 }, { value: 'The quick brown fox jumped over the lazy dog.'});
1819 testVim('yank_register', function(cm, vim, helpers) {
1820 cm.setCursor(0, 0);
1821 helpers.doKeys('"', 'a', 'y', 'y');
1822 helpers.doKeys('j', '"', 'b', 'y', 'y');
1823 cm.openDialog = helpers.fakeOpenDialog('registers');
1824 cm.openNotification = helpers.fakeOpenNotification(function(text) {
1825 is(/a\s+foo/.test(text));
1826 is(/b\s+bar/.test(text));
1827 });
1828 helpers.doKeys(':');
1829 }, { value: 'foo\nbar'});
1830 testVim('macro_register', function(cm, vim, helpers) {
1831 cm.setCursor(0, 0);
1832 helpers.doKeys('q', 'a', 'i');
1833 cm.replaceRange('gangnam', cm.getCursor());
1834 helpers.doInsertModeKeys('Esc');
1835 helpers.doKeys('q');
1836 helpers.doKeys('q', 'b', 'o');
1837 cm.replaceRange('style', cm.getCursor());
1838 helpers.doInsertModeKeys('Esc');
1839 helpers.doKeys('q');
1840 cm.openDialog = helpers.fakeOpenDialog('registers');
1841 cm.openNotification = helpers.fakeOpenNotification(function(text) {
1842 is(/a\s+i/.test(text));
1843 is(/b\s+o/.test(text));
1844 });
1845 helpers.doKeys(':');
1846 }, { value: ''});
1847 testVim('.', function(cm, vim, helpers) {
1848 cm.setCursor(0, 0);
1849 helpers.doKeys('2', 'd', 'w');
1850 helpers.doKeys('.');
1851 eq('5 6', cm.getValue());
1852 }, { value: '1 2 3 4 5 6'});
1853 testVim('._repeat', function(cm, vim, helpers) {
1854 cm.setCursor(0, 0);
1855 helpers.doKeys('2', 'd', 'w');
1856 helpers.doKeys('3', '.');
1857 eq('6', cm.getValue());
1858 }, { value: '1 2 3 4 5 6'});
1859 testVim('._insert', function(cm, vim, helpers) {
1860 helpers.doKeys('i');
1861 cm.replaceRange('test', cm.getCursor());
1862 helpers.doInsertModeKeys('Esc');
1863 helpers.doKeys('.');
1864 eq('testestt', cm.getValue());
1865 helpers.assertCursorAt(0, 6);
1866 }, { value: ''});
1867 testVim('._insert_repeat', function(cm, vim, helpers) {
1868 helpers.doKeys('i');
1869 cm.replaceRange('test', cm.getCursor());
1870 cm.setCursor(0, 4);
1871 helpers.doInsertModeKeys('Esc');
1872 helpers.doKeys('2', '.');
1873 eq('testesttestt', cm.getValue());
1874 helpers.assertCursorAt(0, 10);
1875 }, { value: ''});
1876 testVim('._repeat_insert', function(cm, vim, helpers) {
1877 helpers.doKeys('3', 'i');
1878 cm.replaceRange('te', cm.getCursor());
1879 cm.setCursor(0, 2);
1880 helpers.doInsertModeKeys('Esc');
1881 helpers.doKeys('.');
1882 eq('tetettetetee', cm.getValue());
1883 helpers.assertCursorAt(0, 10);
1884 }, { value: ''});
1885 testVim('._insert_o', function(cm, vim, helpers) {
1886 helpers.doKeys('o');
1887 cm.replaceRange('z', cm.getCursor());
1888 cm.setCursor(1, 1);
1889 helpers.doInsertModeKeys('Esc');
1890 helpers.doKeys('.');
1891 eq('\nz\nz', cm.getValue());
1892 helpers.assertCursorAt(2, 0);
1893 }, { value: ''});
1894 testVim('._insert_o_repeat', function(cm, vim, helpers) {
1895 helpers.doKeys('o');
1896 cm.replaceRange('z', cm.getCursor());
1897 helpers.doInsertModeKeys('Esc');
1898 cm.setCursor(1, 0);
1899 helpers.doKeys('2', '.');
1900 eq('\nz\nz\nz', cm.getValue());
1901 helpers.assertCursorAt(3, 0);
1902 }, { value: ''});
1903 testVim('._insert_o_indent', function(cm, vim, helpers) {
1904 helpers.doKeys('o');
1905 cm.replaceRange('z', cm.getCursor());
1906 helpers.doInsertModeKeys('Esc');
1907 cm.setCursor(1, 2);
1908 helpers.doKeys('.');
1909 eq('{\n z\n z', cm.getValue());
1910 helpers.assertCursorAt(2, 2);
1911 }, { value: '{'});
1912 testVim('._insert_cw', function(cm, vim, helpers) {
1913 helpers.doKeys('c', 'w');
1914 cm.replaceRange('test', cm.getCursor());
1915 helpers.doInsertModeKeys('Esc');
1916 cm.setCursor(0, 3);
1917 helpers.doKeys('2', 'l');
1918 helpers.doKeys('.');
1919 eq('test test word3', cm.getValue());
1920 helpers.assertCursorAt(0, 8);
1921 }, { value: 'word1 word2 word3' });
1922 testVim('._insert_cw_repeat', function(cm, vim, helpers) {
1923 // For some reason, repeat cw in desktop VIM will does not repeat insert mode
1924 // changes. Will conform to that behavior.
1925 helpers.doKeys('c', 'w');
1926 cm.replaceRange('test', cm.getCursor());
1927 helpers.doInsertModeKeys('Esc');
1928 cm.setCursor(0, 4);
1929 helpers.doKeys('l');
1930 helpers.doKeys('2', '.');
1931 eq('test test', cm.getValue());
1932 helpers.assertCursorAt(0, 8);
1933 }, { value: 'word1 word2 word3' });
1934 testVim('._delete', function(cm, vim, helpers) {
1935 cm.setCursor(0, 5);
1936 helpers.doKeys('i');
1937 helpers.doInsertModeKeys('Backspace', 'Esc');
1938 helpers.doKeys('.');
1939 eq('zace', cm.getValue());
1940 helpers.assertCursorAt(0, 1);
1941 }, { value: 'zabcde'});
1942 testVim('._delete_repeat', function(cm, vim, helpers) {
1943 cm.setCursor(0, 6);
1944 helpers.doKeys('i');
1945 helpers.doInsertModeKeys('Backspace', 'Esc');
1946 helpers.doKeys('2', '.');
1947 eq('zzce', cm.getValue());
1948 helpers.assertCursorAt(0, 1);
1949 }, { value: 'zzabcde'});
1950 testVim('f;', function(cm, vim, helpers) {
1951 cm.setCursor(0, 0);
1952 helpers.doKeys('f', 'x');
1953 helpers.doKeys(';');
1954 helpers.doKeys('2', ';');
1955 eq(9, cm.getCursor().ch);
1956 }, { value: '01x3xx678x'});
1957 testVim('F;', function(cm, vim, helpers) {
1958 cm.setCursor(0, 8);
1959 helpers.doKeys('F', 'x');
1960 helpers.doKeys(';');
1961 helpers.doKeys('2', ';');
1962 eq(2, cm.getCursor().ch);
1963 }, { value: '01x3xx6x8x'});
1964 testVim('t;', function(cm, vim, helpers) {
1965 cm.setCursor(0, 0);
1966 helpers.doKeys('t', 'x');
1967 helpers.doKeys(';');
1968 helpers.doKeys('2', ';');
1969 eq(8, cm.getCursor().ch);
1970 }, { value: '01x3xx678x'});
1971 testVim('T;', function(cm, vim, helpers) {
1972 cm.setCursor(0, 9);
1973 helpers.doKeys('T', 'x');
1974 helpers.doKeys(';');
1975 helpers.doKeys('2', ';');
1976 eq(2, cm.getCursor().ch);
1977 }, { value: '0xx3xx678x'});
1978 testVim('f,', function(cm, vim, helpers) {
1979 cm.setCursor(0, 6);
1980 helpers.doKeys('f', 'x');
1981 helpers.doKeys(',');
1982 helpers.doKeys('2', ',');
1983 eq(2, cm.getCursor().ch);
1984 }, { value: '01x3xx678x'});
1985 testVim('F,', function(cm, vim, helpers) {
1986 cm.setCursor(0, 3);
1987 helpers.doKeys('F', 'x');
1988 helpers.doKeys(',');
1989 helpers.doKeys('2', ',');
1990 eq(9, cm.getCursor().ch);
1991 }, { value: '01x3xx678x'});
1992 testVim('t,', function(cm, vim, helpers) {
1993 cm.setCursor(0, 6);
1994 helpers.doKeys('t', 'x');
1995 helpers.doKeys(',');
1996 helpers.doKeys('2', ',');
1997 eq(3, cm.getCursor().ch);
1998 }, { value: '01x3xx678x'});
1999 testVim('T,', function(cm, vim, helpers) {
2000 cm.setCursor(0, 4);
2001 helpers.doKeys('T', 'x');
2002 helpers.doKeys(',');
2003 helpers.doKeys('2', ',');
2004 eq(8, cm.getCursor().ch);
2005 }, { value: '01x3xx67xx'});
2006 testVim('fd,;', function(cm, vim, helpers) {
2007 cm.setCursor(0, 0);
2008 helpers.doKeys('f', '4');
2009 cm.setCursor(0, 0);
2010 helpers.doKeys('d', ';');
2011 eq('56789', cm.getValue());
2012 helpers.doKeys('u');
2013 cm.setCursor(0, 9);
2014 helpers.doKeys('d', ',');
2015 eq('01239', cm.getValue());
2016 }, { value: '0123456789'});
2017 testVim('Fd,;', function(cm, vim, helpers) {
2018 cm.setCursor(0, 9);
2019 helpers.doKeys('F', '4');
2020 cm.setCursor(0, 9);
2021 helpers.doKeys('d', ';');
2022 eq('01239', cm.getValue());
2023 helpers.doKeys('u');
2024 cm.setCursor(0, 0);
2025 helpers.doKeys('d', ',');
2026 eq('56789', cm.getValue());
2027 }, { value: '0123456789'});
2028 testVim('td,;', function(cm, vim, helpers) {
2029 cm.setCursor(0, 0);
2030 helpers.doKeys('t', '4');
2031 cm.setCursor(0, 0);
2032 helpers.doKeys('d', ';');
2033 eq('456789', cm.getValue());
2034 helpers.doKeys('u');
2035 cm.setCursor(0, 9);
2036 helpers.doKeys('d', ',');
2037 eq('012349', cm.getValue());
2038 }, { value: '0123456789'});
2039 testVim('Td,;', function(cm, vim, helpers) {
2040 cm.setCursor(0, 9);
2041 helpers.doKeys('T', '4');
2042 cm.setCursor(0, 9);
2043 helpers.doKeys('d', ';');
2044 eq('012349', cm.getValue());
2045 helpers.doKeys('u');
2046 cm.setCursor(0, 0);
2047 helpers.doKeys('d', ',');
2048 eq('456789', cm.getValue());
2049 }, { value: '0123456789'});
2050 testVim('fc,;', function(cm, vim, helpers) {
2051 cm.setCursor(0, 0);
2052 helpers.doKeys('f', '4');
2053 cm.setCursor(0, 0);
2054 helpers.doKeys('c', ';', 'Esc');
2055 eq('56789', cm.getValue());
2056 helpers.doKeys('u');
2057 cm.setCursor(0, 9);
2058 helpers.doKeys('c', ',');
2059 eq('01239', cm.getValue());
2060 }, { value: '0123456789'});
2061 testVim('Fc,;', function(cm, vim, helpers) {
2062 cm.setCursor(0, 9);
2063 helpers.doKeys('F', '4');
2064 cm.setCursor(0, 9);
2065 helpers.doKeys('c', ';', 'Esc');
2066 eq('01239', cm.getValue());
2067 helpers.doKeys('u');
2068 cm.setCursor(0, 0);
2069 helpers.doKeys('c', ',');
2070 eq('56789', cm.getValue());
2071 }, { value: '0123456789'});
2072 testVim('tc,;', function(cm, vim, helpers) {
2073 cm.setCursor(0, 0);
2074 helpers.doKeys('t', '4');
2075 cm.setCursor(0, 0);
2076 helpers.doKeys('c', ';', 'Esc');
2077 eq('456789', cm.getValue());
2078 helpers.doKeys('u');
2079 cm.setCursor(0, 9);
2080 helpers.doKeys('c', ',');
2081 eq('012349', cm.getValue());
2082 }, { value: '0123456789'});
2083 testVim('Tc,;', function(cm, vim, helpers) {
2084 cm.setCursor(0, 9);
2085 helpers.doKeys('T', '4');
2086 cm.setCursor(0, 9);
2087 helpers.doKeys('c', ';', 'Esc');
2088 eq('012349', cm.getValue());
2089 helpers.doKeys('u');
2090 cm.setCursor(0, 0);
2091 helpers.doKeys('c', ',');
2092 eq('456789', cm.getValue());
2093 }, { value: '0123456789'});
2094 testVim('fy,;', function(cm, vim, helpers) {
2095 cm.setCursor(0, 0);
2096 helpers.doKeys('f', '4');
2097 cm.setCursor(0, 0);
2098 helpers.doKeys('y', ';', 'P');
2099 eq('012340123456789', cm.getValue());
2100 helpers.doKeys('u');
2101 cm.setCursor(0, 9);
2102 helpers.doKeys('y', ',', 'P');
2103 eq('012345678456789', cm.getValue());
2104 }, { value: '0123456789'});
2105 testVim('Fy,;', function(cm, vim, helpers) {
2106 cm.setCursor(0, 9);
2107 helpers.doKeys('F', '4');
2108 cm.setCursor(0, 9);
2109 helpers.doKeys('y', ';', 'p');
2110 eq('012345678945678', cm.getValue());
2111 helpers.doKeys('u');
2112 cm.setCursor(0, 0);
2113 helpers.doKeys('y', ',', 'P');
2114 eq('012340123456789', cm.getValue());
2115 }, { value: '0123456789'});
2116 testVim('ty,;', function(cm, vim, helpers) {
2117 cm.setCursor(0, 0);
2118 helpers.doKeys('t', '4');
2119 cm.setCursor(0, 0);
2120 helpers.doKeys('y', ';', 'P');
2121 eq('01230123456789', cm.getValue());
2122 helpers.doKeys('u');
2123 cm.setCursor(0, 9);
2124 helpers.doKeys('y', ',', 'p');
2125 eq('01234567895678', cm.getValue());
2126 }, { value: '0123456789'});
2127 testVim('Ty,;', function(cm, vim, helpers) {
2128 cm.setCursor(0, 9);
2129 helpers.doKeys('T', '4');
2130 cm.setCursor(0, 9);
2131 helpers.doKeys('y', ';', 'p');
2132 eq('01234567895678', cm.getValue());
2133 helpers.doKeys('u');
2134 cm.setCursor(0, 0);
2135 helpers.doKeys('y', ',', 'P');
2136 eq('01230123456789', cm.getValue());
2137 }, { value: '0123456789'});
2138 testVim('HML', function(cm, vim, helpers) {
2139 var lines = 35;
2140 var textHeight = cm.defaultTextHeight();
2141 cm.setSize(600, lines*textHeight);
2142 cm.setCursor(120, 0);
2143 helpers.doKeys('H');
2144 helpers.assertCursorAt(86, 2);
2145 helpers.doKeys('L');
2146 helpers.assertCursorAt(120, 4);
2147 helpers.doKeys('M');
2148 helpers.assertCursorAt(103,4);
2149 }, { value: (function(){
2150 var lines = new Array(100);
2151 var upper = ' xx\n';
2152 var lower = ' xx\n';
2153 upper = lines.join(upper);
2154 lower = lines.join(lower);
2155 return upper + lower;
2156 })()});
2157
2158 var zVals = ['zb','zz','zt','z-','z.','z<CR>'].map(function(e, idx){
2159 var lineNum = 250;
2160 var lines = 35;
2161 testVim(e, function(cm, vim, helpers) {
2162 var k1 = e[0];
2163 var k2 = e.substring(1);
2164 var textHeight = cm.defaultTextHeight();
2165 cm.setSize(600, lines*textHeight);
2166 cm.setCursor(lineNum, 0);
2167 helpers.doKeys(k1, k2);
2168 zVals[idx] = cm.getScrollInfo().top;
2169 }, { value: (function(){
2170 return new Array(500).join('\n');
2171 })()});
2172 });
2173 testVim('zb<zz', function(cm, vim, helpers){
2174 eq(zVals[0]<zVals[1], true);
2175 });
2176 testVim('zz<zt', function(cm, vim, helpers){
2177 eq(zVals[1]<zVals[2], true);
2178 });
2179 testVim('zb==z-', function(cm, vim, helpers){
2180 eq(zVals[0], zVals[3]);
2181 });
2182 testVim('zz==z.', function(cm, vim, helpers){
2183 eq(zVals[1], zVals[4]);
2184 });
2185 testVim('zt==z<CR>', function(cm, vim, helpers){
2186 eq(zVals[2], zVals[5]);
2187 });
2188
2189 var moveTillCharacterSandbox =
2190 'The quick brown fox \n'
2191 'jumped over the lazy dog.'
2192 testVim('moveTillCharacter', function(cm, vim, helpers){
2193 cm.setCursor(0, 0);
2194 // Search for the 'q'.
2195 cm.openDialog = helpers.fakeOpenDialog('q');
2196 helpers.doKeys('/');
2197 eq(4, cm.getCursor().ch);
2198 // Jump to just before the first o in the list.
2199 helpers.doKeys('t');
2200 helpers.doKeys('o');
2201 eq('The quick brown fox \n', cm.getValue());
2202 // Delete that one character.
2203 helpers.doKeys('d');
2204 helpers.doKeys('t');
2205 helpers.doKeys('o');
2206 eq('The quick bown fox \n', cm.getValue());
2207 // Delete everything until the next 'o'.
2208 helpers.doKeys('.');
2209 eq('The quick box \n', cm.getValue());
2210 // An unmatched character should have no effect.
2211 helpers.doKeys('d');
2212 helpers.doKeys('t');
2213 helpers.doKeys('q');
2214 eq('The quick box \n', cm.getValue());
2215 // Matches should only be possible on single lines.
2216 helpers.doKeys('d');
2217 helpers.doKeys('t');
2218 helpers.doKeys('z');
2219 eq('The quick box \n', cm.getValue());
2220 // After all that, the search for 'q' should still be active, so the 'N' command
2221 // can run it again in reverse. Use that to delete everything back to the 'q'.
2222 helpers.doKeys('d');
2223 helpers.doKeys('N');
2224 eq('The ox \n', cm.getValue());
2225 eq(4, cm.getCursor().ch);
2226 }, { value: moveTillCharacterSandbox});
2227 testVim('searchForPipe', function(cm, vim, helpers){
2228 CodeMirror.Vim.setOption('pcre', false);
2229 cm.setCursor(0, 0);
2230 // Search for the '|'.
2231 cm.openDialog = helpers.fakeOpenDialog('|');
2232 helpers.doKeys('/');
2233 eq(4, cm.getCursor().ch);
2234 }, { value: 'this|that'});
2235
2236
2237 var scrollMotionSandbox =
2238 '\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n'
2239 '\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n'
2240 '\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n'
2241 '\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n';
2242 testVim('scrollMotion', function(cm, vim, helpers){
2243 var prevCursor, prevScrollInfo;
2244 cm.setCursor(0, 0);
2245 // ctrl-y at the top of the file should have no effect.
2246 helpers.doKeys('<C-y>');
2247 eq(0, cm.getCursor().line);
2248 prevScrollInfo = cm.getScrollInfo();
2249 helpers.doKeys('<C-e>');
2250 eq(1, cm.getCursor().line);
2251 is(prevScrollInfo.top < cm.getScrollInfo().top);
2252 // Jump to the end of the sandbox.
2253 cm.setCursor(1000, 0);
2254 prevCursor = cm.getCursor();
2255 // ctrl-e at the bottom of the file should have no effect.
2256 helpers.doKeys('<C-e>');
2257 eq(prevCursor.line, cm.getCursor().line);
2258 prevScrollInfo = cm.getScrollInfo();
2259 helpers.doKeys('<C-y>');
2260 eq(prevCursor.line - 1, cm.getCursor().line);
2261 is(prevScrollInfo.top > cm.getScrollInfo().top);
2262 }, { value: scrollMotionSandbox});
2263
2264 var squareBracketMotionSandbox = ''+
2265 '({\n'+//0
2266 ' ({\n'+//11
2267 ' /*comment {\n'+//2
2268 ' */(\n'+//3
2269 '#else \n'+//4
2270 ' /* )\n'+//5
2271 '#if }\n'+//6
2272 ' )}*/\n'+//7
2273 ')}\n'+//8
2274 '{}\n'+//9
2275 '#else {{\n'+//10
2276 '{}\n'+//11
2277 '}\n'+//12
2278 '{\n'+//13
2279 '#endif\n'+//14
2280 '}\n'+//15
2281 '}\n'+//16
2282 '#else';//17
2283 testVim('[[, ]]', function(cm, vim, helpers) {
2284 cm.setCursor(0, 0);
2285 helpers.doKeys(']', ']');
2286 helpers.assertCursorAt(9,0);
2287 helpers.doKeys('2', ']', ']');
2288 helpers.assertCursorAt(13,0);
2289 helpers.doKeys(']', ']');
2290 helpers.assertCursorAt(17,0);
2291 helpers.doKeys('[', '[');
2292 helpers.assertCursorAt(13,0);
2293 helpers.doKeys('2', '[', '[');
2294 helpers.assertCursorAt(9,0);
2295 helpers.doKeys('[', '[');
2296 helpers.assertCursorAt(0,0);
2297 }, { value: squareBracketMotionSandbox});
2298 testVim('[], ][', function(cm, vim, helpers) {
2299 cm.setCursor(0, 0);
2300 helpers.doKeys(']', '[');
2301 helpers.assertCursorAt(12,0);
2302 helpers.doKeys('2', ']', '[');
2303 helpers.assertCursorAt(16,0);
2304 helpers.doKeys(']', '[');
2305 helpers.assertCursorAt(17,0);
2306 helpers.doKeys('[', ']');
2307 helpers.assertCursorAt(16,0);
2308 helpers.doKeys('2', '[', ']');
2309 helpers.assertCursorAt(12,0);
2310 helpers.doKeys('[', ']');
2311 helpers.assertCursorAt(0,0);
2312 }, { value: squareBracketMotionSandbox});
2313 testVim('[{, ]}', function(cm, vim, helpers) {
2314 cm.setCursor(4, 10);
2315 helpers.doKeys('[', '{');
2316 helpers.assertCursorAt(2,12);
2317 helpers.doKeys('2', '[', '{');
2318 helpers.assertCursorAt(0,1);
2319 cm.setCursor(4, 10);
2320 helpers.doKeys(']', '}');
2321 helpers.assertCursorAt(6,11);
2322 helpers.doKeys('2', ']', '}');
2323 helpers.assertCursorAt(8,1);
2324 cm.setCursor(0,1);
2325 helpers.doKeys(']', '}');
2326 helpers.assertCursorAt(8,1);
2327 helpers.doKeys('[', '{');
2328 helpers.assertCursorAt(0,1);
2329 }, { value: squareBracketMotionSandbox});
2330 testVim('[(, ])', function(cm, vim, helpers) {
2331 cm.setCursor(4, 10);
2332 helpers.doKeys('[', '(');
2333 helpers.assertCursorAt(3,14);
2334 helpers.doKeys('2', '[', '(');
2335 helpers.assertCursorAt(0,0);
2336 cm.setCursor(4, 10);
2337 helpers.doKeys(']', ')');
2338 helpers.assertCursorAt(5,11);
2339 helpers.doKeys('2', ']', ')');
2340 helpers.assertCursorAt(8,0);
2341 helpers.doKeys('[', '(');
2342 helpers.assertCursorAt(0,0);
2343 helpers.doKeys(']', ')');
2344 helpers.assertCursorAt(8,0);
2345 }, { value: squareBracketMotionSandbox});
2346 testVim('[*, ]*, [/, ]/', function(cm, vim, helpers) {
2347 forEach(['*', '/'], function(key){
2348 cm.setCursor(7, 0);
2349 helpers.doKeys('2', '[', key);
2350 helpers.assertCursorAt(2,2);
2351 helpers.doKeys('2', ']', key);
2352 helpers.assertCursorAt(7,5);
2353 });
2354 }, { value: squareBracketMotionSandbox});
2355 testVim('[#, ]#', function(cm, vim, helpers) {
2356 cm.setCursor(10, 3);
2357 helpers.doKeys('2', '[', '#');
2358 helpers.assertCursorAt(4,0);
2359 helpers.doKeys('5', ']', '#');
2360 helpers.assertCursorAt(17,0);
2361 cm.setCursor(10, 3);
2362 helpers.doKeys(']', '#');
2363 helpers.assertCursorAt(14,0);
2364 }, { value: squareBracketMotionSandbox});
2365 testVim('[m, ]m, [M, ]M', function(cm, vim, helpers) {
2366 cm.setCursor(11, 0);
2367 helpers.doKeys('[', 'm');
2368 helpers.assertCursorAt(10,7);
2369 helpers.doKeys('4', '[', 'm');
2370 helpers.assertCursorAt(1,3);
2371 helpers.doKeys('5', ']', 'm');
2372 helpers.assertCursorAt(11,0);
2373 helpers.doKeys('[', 'M');
2374 helpers.assertCursorAt(9,1);
2375 helpers.doKeys('3', ']', 'M');
2376 helpers.assertCursorAt(15,0);
2377 helpers.doKeys('5', '[', 'M');
2378 helpers.assertCursorAt(7,3);
2379 }, { value: squareBracketMotionSandbox});
2380
2381 // Ex mode tests
2382 testVim('ex_go_to_line', function(cm, vim, helpers) {
2383 cm.setCursor(0, 0);
2384 helpers.doEx('4');
2385 helpers.assertCursorAt(3, 0);
2386 }, { value: 'a\nb\nc\nd\ne\n'});
2387 testVim('ex_write', function(cm, vim, helpers) {
2388 var tmp = CodeMirror.commands.save;
2389 var written;
2390 var actualCm;
2391 CodeMirror.commands.save = function(cm) {
2392 written = true;
2393 actualCm = cm;
2394 };
2395 // Test that w, wr, wri ... write all trigger :write.
2396 var command = 'write';
2397 for (var i = 1; i < command.length; i++) {
2398 written = false;
2399 actualCm = null;
2400 helpers.doEx(command.substring(0, i));
2401 eq(written, true);
2402 eq(actualCm, cm);
2403 }
2404 CodeMirror.commands.save = tmp;
2405 });
2406 testVim('ex_sort', function(cm, vim, helpers) {
2407 helpers.doEx('sort');
2408 eq('Z\na\nb\nc\nd', cm.getValue());
2409 }, { value: 'b\nZ\nd\nc\na'});
2410 testVim('ex_sort_reverse', function(cm, vim, helpers) {
2411 helpers.doEx('sort!');
2412 eq('d\nc\nb\na', cm.getValue());
2413 }, { value: 'b\nd\nc\na'});
2414 testVim('ex_sort_range', function(cm, vim, helpers) {
2415 helpers.doEx('2,3sort');
2416 eq('b\nc\nd\na', cm.getValue());
2417 }, { value: 'b\nd\nc\na'});
2418 testVim('ex_sort_oneline', function(cm, vim, helpers) {
2419 helpers.doEx('2sort');
2420 // Expect no change.
2421 eq('b\nd\nc\na', cm.getValue());
2422 }, { value: 'b\nd\nc\na'});
2423 testVim('ex_sort_ignoreCase', function(cm, vim, helpers) {
2424 helpers.doEx('sort i');
2425 eq('a\nb\nc\nd\nZ', cm.getValue());
2426 }, { value: 'b\nZ\nd\nc\na'});
2427 testVim('ex_sort_unique', function(cm, vim, helpers) {
2428 helpers.doEx('sort u');
2429 eq('Z\na\nb\nc\nd', cm.getValue());
2430 }, { value: 'b\nZ\na\na\nd\na\nc\na'});
2431 testVim('ex_sort_decimal', function(cm, vim, helpers) {
2432 helpers.doEx('sort d');
2433 eq('d3\n s5\n6\n.9', cm.getValue());
2434 }, { value: '6\nd3\n s5\n.9'});
2435 testVim('ex_sort_decimal_negative', function(cm, vim, helpers) {
2436 helpers.doEx('sort d');
2437 eq('z-9\nd3\n s5\n6\n.9', cm.getValue());
2438 }, { value: '6\nd3\n s5\n.9\nz-9'});
2439 testVim('ex_sort_decimal_reverse', function(cm, vim, helpers) {
2440 helpers.doEx('sort! d');
2441 eq('.9\n6\n s5\nd3', cm.getValue());
2442 }, { value: '6\nd3\n s5\n.9'});
2443 testVim('ex_sort_hex', function(cm, vim, helpers) {
2444 helpers.doEx('sort x');
2445 eq(' s5\n6\n.9\n&0xB\nd3', cm.getValue());
2446 }, { value: '6\nd3\n s5\n&0xB\n.9'});
2447 testVim('ex_sort_octal', function(cm, vim, helpers) {
2448 helpers.doEx('sort o');
2449 eq('.8\n.9\nd3\n s5\n6', cm.getValue());
2450 }, { value: '6\nd3\n s5\n.9\n.8'});
2451 testVim('ex_sort_decimal_mixed', function(cm, vim, helpers) {
2452 helpers.doEx('sort d');
2453 eq('y\nz\nc1\nb2\na3', cm.getValue());
2454 }, { value: 'a3\nz\nc1\ny\nb2'});
2455 testVim('ex_sort_decimal_mixed_reverse', function(cm, vim, helpers) {
2456 helpers.doEx('sort! d');
2457 eq('a3\nb2\nc1\nz\ny', cm.getValue());
2458 }, { value: 'a3\nz\nc1\ny\nb2'});
2459
2460 // Basic substitute tests.
2461 testVim('ex_substitute_same_line', function(cm, vim, helpers) {
2462 cm.setCursor(1, 0);
2463 helpers.doEx('s/one/two');
2464 eq('one one\n two two', cm.getValue());
2465 }, { value: 'one one\n one one'});
2466 testVim('ex_substitute_global', function(cm, vim, helpers) {
2467 cm.setCursor(1, 0);
2468 helpers.doEx('%s/one/two');
2469 eq('two two\n two two', cm.getValue());
2470 }, { value: 'one one\n one one'});
2471 testVim('ex_substitute_input_range', function(cm, vim, helpers) {
2472 cm.setCursor(1, 0);
2473 helpers.doEx('1,3s/\\d/0');
2474 eq('0\n0\n0\n4', cm.getValue());
2475 }, { value: '1\n2\n3\n4' });
2476 testVim('ex_substitute_visual_range', function(cm, vim, helpers) {
2477 cm.setCursor(1, 0);
2478 // Set last visual mode selection marks '< and '> at lines 2 and 4
2479 helpers.doKeys('V', '2', 'j', 'v');
2480 helpers.doEx('\'<,\'>s/\\d/0');
2481 eq('1\n0\n0\n0\n5', cm.getValue());
2482 }, { value: '1\n2\n3\n4\n5' });
2483 testVim('ex_substitute_empty_query', function(cm, vim, helpers) {
2484 // If the query is empty, use last query.
2485 cm.setCursor(1, 0);
2486 cm.openDialog = helpers.fakeOpenDialog('1');
2487 helpers.doKeys('/');
2488 helpers.doEx('s//b');
2489 eq('abb ab2 ab3', cm.getValue());
2490 }, { value: 'a11 a12 a13' });
2491 testVim('ex_substitute_javascript', function(cm, vim, helpers) {
2492 CodeMirror.Vim.setOption('pcre', false);
2493 cm.setCursor(1, 0);
2494 // Throw all the things that javascript likes to treat as special values
2495 // into the replace part. All should be literal (this is VIM).
2496 helpers.doEx('s/\\(\\d+\\)/$$ $\' $` $& \\1/')
2497 eq('a $$ $\' $` $& 0 b', cm.getValue());
2498 }, { value: 'a 0 b' });
2499
2500 // More complex substitute tests that test both pcre and nopcre options.
2501 function testSubstitute(name, options) {
2502 testVim(name + '_pcre', function(cm, vim, helpers) {
2503 cm.setCursor(1, 0);
2504 CodeMirror.Vim.setOption('pcre', true);
2505 helpers.doEx(options.expr);
2506 eq(options.expectedValue, cm.getValue());
2507 }, options);
2508 // If no noPcreExpr is defined, assume that it's the same as the expr.
2509 var noPcreExpr = options.noPcreExpr ? options.noPcreExpr : options.expr;
2510 testVim(name + '_nopcre', function(cm, vim, helpers) {
2511 cm.setCursor(1, 0);
2512 CodeMirror.Vim.setOption('pcre', false);
2513 helpers.doEx(noPcreExpr);
2514 eq(options.expectedValue, cm.getValue());
2515 }, options);
2516 }
2517 testSubstitute('ex_substitute_capture', {
2518 value: 'a11 a12 a13',
2519 expectedValue: 'a1111 a1212 a1313',
2520 // $n is a backreference
2521 expr: 's/(\\d+)/$1$1/',
2522 // \n is a backreference.
2523 noPcreExpr: 's/\\(\\d+\\)/\\1\\1/'});
2524 testSubstitute('ex_substitute_capture2', {
2525 value: 'a 0 b',
2526 expectedValue: 'a $00 b',
2527 expr: 's/(\\d+)/$$$1$1/',
2528 noPcreExpr: 's/\\(\\d+\\)/$\\1\\1/'});
2529 testSubstitute('ex_substitute_nocapture', {
2530 value: 'a11 a12 a13',
2531 expectedValue: 'a$1$1 a$1$1 a$1$1',
2532 expr: 's/(\\d+)/$$1$$1',
2533 noPcreExpr: 's/\\(\\d+\\)/$1$1/'});
2534 testSubstitute('ex_substitute_nocapture2', {
2535 value: 'a 0 b',
2536 expectedValue: 'a $10 b',
2537 expr: 's/(\\d+)/$$1$1',
2538 noPcreExpr: 's/\\(\\d+\\)/\\$1\\1/'});
2539 testSubstitute('ex_substitute_nocapture', {
2540 value: 'a b c',
2541 expectedValue: 'a $ c',
2542 expr: 's/b/$$/',
2543 noPcreExpr: 's/b/$/'});
2544 testSubstitute('ex_substitute_slash_regex', {
2545 value: 'one/two \n three/four',
2546 expectedValue: 'one|two \n three|four',
2547 expr: '%s/\\//|'});
2548 testSubstitute('ex_substitute_pipe_regex', {
2549 value: 'one|two \n three|four',
2550 expectedValue: 'one,two \n three,four',
2551 expr: '%s/\\|/,/',
2552 noPcreExpr: '%s/|/,/'});
2553 testSubstitute('ex_substitute_or_regex', {
2554 value: 'one|two \n three|four',
2555 expectedValue: 'ana|twa \n thraa|faar',
2556 expr: '%s/o|e|u/a',
2557 noPcreExpr: '%s/o\\|e\\|u/a'});
2558 testSubstitute('ex_substitute_or_word_regex', {
2559 value: 'one|two \n three|four',
2560 expectedValue: 'five|five \n three|four',
2561 expr: '%s/(one|two)/five/',
2562 noPcreExpr: '%s/\\(one\\|two\\)/five'});
2563 testSubstitute('ex_substitute_backslashslash_regex', {
2564 value: 'one\\two \n three\\four',
2565 expectedValue: 'one,two \n three,four',
2566 expr: '%s/\\\\/,'});
2567 testSubstitute('ex_substitute_slash_replacement', {
2568 value: 'one,two \n three,four',
2569 expectedValue: 'one/two \n three/four',
2570 expr: '%s/,/\\/'});
2571 testSubstitute('ex_substitute_backslash_replacement', {
2572 value: 'one,two \n three,four',
2573 expectedValue: 'one\\two \n three\\four',
2574 expr: '%s/,/\\\\/g'});
2575 testSubstitute('ex_substitute_multibackslash_replacement', {
2576 value: 'one,two \n three,four',
2577 expectedValue: 'one\\\\\\\\two \n three\\\\\\\\four', // 2*8 backslashes.
2578 expr: '%s/,/\\\\\\\\\\\\\\\\/g'}); // 16 backslashes.
2579 testSubstitute('ex_substitute_braces_word', {
2580 value: 'ababab abb ab{2}',
2581 expectedValue: 'ab abb ab{2}',
2582 expr: '%s/(ab){2}//g',
2583 noPcreExpr: '%s/\\(ab\\)\\{2\\}//g'});
2584 testSubstitute('ex_substitute_braces_range', {
2585 value: 'a aa aaa aaaa',
2586 expectedValue: 'a a',
2587 expr: '%s/a{2,3}//g',
2588 noPcreExpr: '%s/a\\{2,3\\}//g'});
2589 testSubstitute('ex_substitute_braces_literal', {
2590 value: 'ababab abb ab{2}',
2591 expectedValue: 'ababab abb ',
2592 expr: '%s/ab\\{2\\}//g',
2593 noPcreExpr: '%s/ab{2}//g'});
2594 testSubstitute('ex_substitute_braces_char', {
2595 value: 'ababab abb ab{2}',
2596 expectedValue: 'ababab ab{2}',
2597 expr: '%s/ab{2}//g',
2598 noPcreExpr: '%s/ab\\{2\\}//g'});
2599 testSubstitute('ex_substitute_braces_no_escape', {
2600 value: 'ababab abb ab{2}',
2601 expectedValue: 'ababab ab{2}',
2602 expr: '%s/ab{2}//g',
2603 noPcreExpr: '%s/ab\\{2}//g'});
2604 testSubstitute('ex_substitute_count', {
2605 value: '1\n2\n3\n4',
2606 expectedValue: '1\n0\n0\n4',
2607 expr: 's/\\d/0/i 2'});
2608 testSubstitute('ex_substitute_count_with_range', {
2609 value: '1\n2\n3\n4',
2610 expectedValue: '1\n2\n0\n0',
2611 expr: '1,3s/\\d/0/ 3'});
2612 function testSubstituteConfirm(name, command, initialValue, expectedValue, keys, finalPos) {
2613 testVim(name, function(cm, vim, helpers) {
2614 var savedOpenDialog = cm.openDialog;
2615 var savedKeyName = CodeMirror.keyName;
2616 var onKeyDown;
2617 var recordedCallback;
2618 var closed = true; // Start out closed, set false on second openDialog.
2619 function close() {
2620 closed = true;
2621 }
2622 // First openDialog should save callback.
2623 cm.openDialog = function(template, callback, options) {
2624 recordedCallback = callback;
2625 }
2626 // Do first openDialog.
2627 helpers.doKeys(':');
2628 // Second openDialog should save keyDown handler.
2629 cm.openDialog = function(template, callback, options) {
2630 onKeyDown = options.onKeyDown;
2631 closed = false;
2632 };
2633 // Return the command to Vim and trigger second openDialog.
2634 recordedCallback(command);
2635 // The event should really use keyCode, but here just mock it out and use
2636 // key and replace keyName to just return key.
2637 CodeMirror.keyName = function (e) { return e.key; }
2638 keys = keys.toUpperCase();
2639 for (var i = 0; i < keys.length; i++) {
2640 is(!closed);
2641 onKeyDown({ key: keys.charAt(i) }, '', close);
2642 }
2643 try {
2644 eq(expectedValue, cm.getValue());
2645 helpers.assertCursorAt(finalPos);
2646 is(closed);
2647 } catch(e) {
2648 throw e
2649 } finally {
2650 // Restore overriden functions.
2651 CodeMirror.keyName = savedKeyName;
2652 cm.openDialog = savedOpenDialog;
2653 }
2654 }, { value: initialValue });
2655 };
2656 testSubstituteConfirm('ex_substitute_confirm_emptydoc',
2657 '%s/x/b/c', '', '', '', makeCursor(0, 0));
2658 testSubstituteConfirm('ex_substitute_confirm_nomatch',
2659 '%s/x/b/c', 'ba a\nbab', 'ba a\nbab', '', makeCursor(0, 0));
2660 testSubstituteConfirm('ex_substitute_confirm_accept',
2661 '%s/a/b/c', 'ba a\nbab', 'bb b\nbbb', 'yyy', makeCursor(1, 1));
2662 testSubstituteConfirm('ex_substitute_confirm_random_keys',
2663 '%s/a/b/c', 'ba a\nbab', 'bb b\nbbb', 'ysdkywerty', makeCursor(1, 1));
2664 testSubstituteConfirm('ex_substitute_confirm_some',
2665 '%s/a/b/c', 'ba a\nbab', 'bb a\nbbb', 'yny', makeCursor(1, 1));
2666 testSubstituteConfirm('ex_substitute_confirm_all',
2667 '%s/a/b/c', 'ba a\nbab', 'bb b\nbbb', 'a', makeCursor(1, 1));
2668 testSubstituteConfirm('ex_substitute_confirm_accept_then_all',
2669 '%s/a/b/c', 'ba a\nbab', 'bb b\nbbb', 'ya', makeCursor(1, 1));
2670 testSubstituteConfirm('ex_substitute_confirm_quit',
2671 '%s/a/b/c', 'ba a\nbab', 'bb a\nbab', 'yq', makeCursor(0, 3));
2672 testSubstituteConfirm('ex_substitute_confirm_last',
2673 '%s/a/b/c', 'ba a\nbab', 'bb b\nbab', 'yl', makeCursor(0, 3));
2674 testSubstituteConfirm('ex_substitute_confirm_oneline',
2675 '1s/a/b/c', 'ba a\nbab', 'bb b\nbab', 'yl', makeCursor(0, 3));
2676 testSubstituteConfirm('ex_substitute_confirm_range_accept',
2677 '1,2s/a/b/c', 'aa\na \na\na', 'bb\nb \na\na', 'yyy', makeCursor(1, 0));
2678 testSubstituteConfirm('ex_substitute_confirm_range_some',
2679 '1,3s/a/b/c', 'aa\na \na\na', 'ba\nb \nb\na', 'ynyy', makeCursor(2, 0));
2680 testSubstituteConfirm('ex_substitute_confirm_range_all',
2681 '1,3s/a/b/c', 'aa\na \na\na', 'bb\nb \nb\na', 'a', makeCursor(2, 0));
2682 testSubstituteConfirm('ex_substitute_confirm_range_last',
2683 '1,3s/a/b/c', 'aa\na \na\na', 'bb\nb \na\na', 'yyl', makeCursor(1, 0));
2684 //:noh should clear highlighting of search-results but allow to resume search through n
2685 testVim('ex_noh_clearSearchHighlight', function(cm, vim, helpers) {
2686 cm.openDialog = helpers.fakeOpenDialog('match');
2687 helpers.doKeys('?');
2688 helpers.doEx('noh');
2689 eq(vim.searchState_.getOverlay(),null,'match-highlighting wasn\'t cleared');
2690 helpers.doKeys('n');
2691 helpers.assertCursorAt(0, 11,'can\'t resume search after clearing highlighting');
2692 }, { value: 'match nope match \n nope Match' });
2693 testVim('set_boolean', function(cm, vim, helpers) {
2694 CodeMirror.Vim.defineOption('testoption', true, 'boolean');
2695 // Test default value is set.
2696 is(CodeMirror.Vim.getOption('testoption'));
2697 try {
2698 // Test fail to set to non-boolean
2699 CodeMirror.Vim.setOption('testoption', '5');
2700 fail();
2701 } catch (expected) {};
2702 // Test setOption
2703 CodeMirror.Vim.setOption('testoption', false);
2704 is(!CodeMirror.Vim.getOption('testoption'));
2705 });
2706 testVim('ex_set_boolean', function(cm, vim, helpers) {
2707 CodeMirror.Vim.defineOption('testoption', true, 'boolean');
2708 // Test default value is set.
2709 is(CodeMirror.Vim.getOption('testoption'));
2710 try {
2711 // Test fail to set to non-boolean
2712 helpers.doEx('set testoption=22');
2713 fail();
2714 } catch (expected) {};
2715 // Test setOption
2716 helpers.doEx('set notestoption');
2717 is(!CodeMirror.Vim.getOption('testoption'));
2718 });
2719 testVim('set_string', function(cm, vim, helpers) {
2720 CodeMirror.Vim.defineOption('testoption', 'a', 'string');
2721 // Test default value is set.
2722 eq('a', CodeMirror.Vim.getOption('testoption'));
2723 try {
2724 // Test fail to set non-string.
2725 CodeMirror.Vim.setOption('testoption', true);
2726 fail();
2727 } catch (expected) {};
2728 try {
2729 // Test fail to set 'notestoption'
2730 CodeMirror.Vim.setOption('notestoption', 'b');
2731 fail();
2732 } catch (expected) {};
2733 // Test setOption
2734 CodeMirror.Vim.setOption('testoption', 'c');
2735 eq('c', CodeMirror.Vim.getOption('testoption'));
2736 });
2737 testVim('ex_set_string', function(cm, vim, helpers) {
2738 CodeMirror.Vim.defineOption('testoption', 'a', 'string');
2739 // Test default value is set.
2740 eq('a', CodeMirror.Vim.getOption('testoption'));
2741 try {
2742 // Test fail to set 'notestoption'
2743 helpers.doEx('set notestoption=b');
2744 fail();
2745 } catch (expected) {};
2746 // Test setOption
2747 helpers.doEx('set testoption=c')
2748 eq('c', CodeMirror.Vim.getOption('testoption'));
2749 });
2750 // TODO: Reset key maps after each test.
2751 testVim('ex_map_key2key', function(cm, vim, helpers) {
2752 helpers.doEx('map a x');
2753 helpers.doKeys('a');
2754 helpers.assertCursorAt(0, 0);
2755 eq('bc', cm.getValue());
2756 }, { value: 'abc' });
2757 testVim('ex_unmap_key2key', function(cm, vim, helpers) {
2758 helpers.doEx('unmap a');
2759 helpers.doKeys('a');
2760 eq('vim-insert', cm.getOption('keyMap'));
2761 }, { value: 'abc' });
2762 testVim('ex_unmap_key2key_does_not_remove_default', function(cm, vim, helpers) {
2763 try {
2764 helpers.doEx('unmap a');
2765 fail();
2766 } catch (expected) {}
2767 helpers.doKeys('a');
2768 eq('vim-insert', cm.getOption('keyMap'));
2769 }, { value: 'abc' });
2770 testVim('ex_map_key2key_to_colon', function(cm, vim, helpers) {
2771 helpers.doEx('map ; :');
2772 var dialogOpened = false;
2773 cm.openDialog = function() {
2774 dialogOpened = true;
2775 }
2776 helpers.doKeys(';');
2777 eq(dialogOpened, true);
2778 });
2779 testVim('ex_map_ex2key:', function(cm, vim, helpers) {
2780 helpers.doEx('map :del x');
2781 helpers.doEx('del');
2782 helpers.assertCursorAt(0, 0);
2783 eq('bc', cm.getValue());
2784 }, { value: 'abc' });
2785 testVim('ex_map_ex2ex', function(cm, vim, helpers) {
2786 helpers.doEx('map :del :w');
2787 var tmp = CodeMirror.commands.save;
2788 var written = false;
2789 var actualCm;
2790 CodeMirror.commands.save = function(cm) {
2791 written = true;
2792 actualCm = cm;
2793 };
2794 helpers.doEx('del');
2795 CodeMirror.commands.save = tmp;
2796 eq(written, true);
2797 eq(actualCm, cm);
2798 });
2799 testVim('ex_map_key2ex', function(cm, vim, helpers) {
2800 helpers.doEx('map a :w');
2801 var tmp = CodeMirror.commands.save;
2802 var written = false;
2803 var actualCm;
2804 CodeMirror.commands.save = function(cm) {
2805 written = true;
2806 actualCm = cm;
2807 };
2808 helpers.doKeys('a');
2809 CodeMirror.commands.save = tmp;
2810 eq(written, true);
2811 eq(actualCm, cm);
2812 });
2813 testVim('ex_map_key2key_visual_api', function(cm, vim, helpers) {
2814 CodeMirror.Vim.map('b', ':w', 'visual');
2815 var tmp = CodeMirror.commands.save;
2816 var written = false;
2817 var actualCm;
2818 CodeMirror.commands.save = function(cm) {
2819 written = true;
2820 actualCm = cm;
2821 };
2822 // Mapping should not work in normal mode.
2823 helpers.doKeys('b');
2824 eq(written, false);
2825 // Mapping should work in visual mode.
2826 helpers.doKeys('v', 'b');
2827 eq(written, true);
2828 eq(actualCm, cm);
2829
2830 CodeMirror.commands.save = tmp;
2831 });
2832
2833 // Testing registration of functions as ex-commands and mapping to <Key>-keys
2834 testVim('ex_api_test', function(cm, vim, helpers) {
2835 var res=false;
2836 var val='from';
2837 CodeMirror.Vim.defineEx('extest','ext',function(cm,params){
2838 if(params.args)val=params.args[0];
2839 else res=true;
2840 });
2841 helpers.doEx(':ext to');
2842 eq(val,'to','Defining ex-command failed');
2843 CodeMirror.Vim.map('<C-CR><Space>',':ext');
2844 helpers.doKeys('<C-CR>','<Space>');
2845 is(res,'Mapping to key failed');
2846 });
2847 // For now, this test needs to be last because it messes up : for future tests.
2848 testVim('ex_map_key2key_from_colon', function(cm, vim, helpers) {
2849 helpers.doEx('map : x');
2850 helpers.doKeys(':');
2851 helpers.assertCursorAt(0, 0);
2852 eq('bc', cm.getValue());
2853 }, { value: 'abc' });
2854
2855 // Test event handlers
2856 testVim('beforeSelectionChange', function(cm, vim, helpers) {
2857 cm.setCursor(0, 100);
2858 eqPos(cm.getCursor('head'), cm.getCursor('anchor'));
2859 }, { value: 'abc' });

mercurial