Fix: merge conflict
[myslice.git] / to-be-integrated / third-party / codemirror-3.15 / test / vim_test.js
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 testVim(name, run, opts, expectedFail) {
100   var vimOpts = {
101     lineNumbers: true,
102     vimMode: true,
103     showCursorWhenSelecting: true,
104     value: code
105   };
106   for (var prop in opts) {
107     if (opts.hasOwnProperty(prop)) {
108       vimOpts[prop] = opts[prop];
109     }
110   }
111   return test('vim_' + name, function() {
112     var place = document.getElementById("testground");
113     var cm = CodeMirror(place, vimOpts);
114     var vim = CodeMirror.Vim.maybeInitVimState_(cm);
115
116     function doKeysFn(cm) {
117       return function(args) {
118         if (args instanceof Array) {
119           arguments = args;
120         }
121         for (var i = 0; i < arguments.length; i++) {
122           CodeMirror.Vim.handleKey(cm, arguments[i]);
123         }
124       }
125     }
126     function doInsertModeKeysFn(cm) {
127       return function(args) {
128         if (args instanceof Array) { arguments = args; }
129         function executeHandler(handler) {
130           if (typeof handler == 'string') {
131             CodeMirror.commands[handler](cm);
132           } else {
133             handler(cm);
134           }
135           return true;
136         }
137         for (var i = 0; i < arguments.length; i++) {
138           var key = arguments[i];
139           // Find key in keymap and handle.
140           var handled = CodeMirror.lookupKey(key, ['vim-insert'], executeHandler);
141           // Record for insert mode.
142           if (handled === true && cm.state.vim.insertMode && arguments[i] != 'Esc') {
143             var lastChange = CodeMirror.Vim.getVimGlobalState_().macroModeState.lastInsertModeChanges;
144             if (lastChange) {
145               lastChange.changes.push(new CodeMirror.Vim.InsertModeKey(key));
146             }
147           }
148         }
149       }
150     }
151     function doExFn(cm) {
152       return function(command) {
153         cm.openDialog = helpers.fakeOpenDialog(command);
154         helpers.doKeys(':');
155       }
156     }
157     function assertCursorAtFn(cm) {
158       return function(line, ch) {
159         var pos;
160         if (ch == null && typeof line.line == 'number') {
161           pos = line;
162         } else {
163           pos = makeCursor(line, ch);
164         }
165         eqPos(pos, cm.getCursor());
166       }
167     }
168     function fakeOpenDialog(result) {
169       return function(text, callback) {
170         return callback(result);
171       }
172     }
173     var helpers = {
174       doKeys: doKeysFn(cm),
175       // Warning: Only emulates keymap events, not character insertions. Use
176       // replaceRange to simulate character insertions.
177       // Keys are in CodeMirror format, NOT vim format.
178       doInsertModeKeys: doInsertModeKeysFn(cm),
179       doEx: doExFn(cm),
180       assertCursorAt: assertCursorAtFn(cm),
181       fakeOpenDialog: fakeOpenDialog,
182       getRegisterController: function() {
183         return CodeMirror.Vim.getRegisterController();
184       }
185     }
186     CodeMirror.Vim.resetVimGlobalState_();
187     var successful = false;
188     try {
189       run(cm, vim, helpers);
190       successful = true;
191     } finally {
192       if ((debug && !successful) || verbose) {
193         place.style.visibility = "visible";
194       } else {
195         place.removeChild(cm.getWrapperElement());
196       }
197     }
198   }, expectedFail);
199 };
200 testVim('qq@q', function(cm, vim, helpers) {
201   cm.setCursor(0, 0);
202   helpers.doKeys('q', 'q', 'l', 'l', 'q');
203   helpers.assertCursorAt(0,2);
204   helpers.doKeys('@', 'q');
205   helpers.assertCursorAt(0,4);
206 }, { value: '            '});
207 testVim('@@', function(cm, vim, helpers) {
208   cm.setCursor(0, 0);
209   helpers.doKeys('q', 'q', 'l', 'l', 'q');
210   helpers.assertCursorAt(0,2);
211   helpers.doKeys('@', 'q');
212   helpers.assertCursorAt(0,4);
213   helpers.doKeys('@', '@');
214   helpers.assertCursorAt(0,6);
215 }, { value: '            '});
216 var jumplistScene = ''+
217   'word\n'+
218   '(word)\n'+
219   '{word\n'+
220   'word.\n'+
221   '\n'+
222   'word search\n'+
223   '}word\n'+
224   'word\n'+
225   'word\n';
226 function testJumplist(name, keys, endPos, startPos, dialog) {
227   endPos = makeCursor(endPos[0], endPos[1]);
228   startPos = makeCursor(startPos[0], startPos[1]);
229   testVim(name, function(cm, vim, helpers) {
230     CodeMirror.Vim.resetVimGlobalState_();
231     if(dialog)cm.openDialog = helpers.fakeOpenDialog('word');
232     cm.setCursor(startPos);
233     helpers.doKeys.apply(null, keys);
234     helpers.assertCursorAt(endPos);
235   }, {value: jumplistScene});
236 };
237 testJumplist('jumplist_H', ['H', '<C-o>'], [5,2], [5,2]);
238 testJumplist('jumplist_M', ['M', '<C-o>'], [2,2], [2,2]);
239 testJumplist('jumplist_L', ['L', '<C-o>'], [2,2], [2,2]);
240 testJumplist('jumplist_[[', ['[', '[', '<C-o>'], [5,2], [5,2]);
241 testJumplist('jumplist_]]', [']', ']', '<C-o>'], [2,2], [2,2]);
242 testJumplist('jumplist_G', ['G', '<C-o>'], [5,2], [5,2]);
243 testJumplist('jumplist_gg', ['g', 'g', '<C-o>'], [5,2], [5,2]);
244 testJumplist('jumplist_%', ['%', '<C-o>'], [1,5], [1,5]);
245 testJumplist('jumplist_{', ['{', '<C-o>'], [1,5], [1,5]);
246 testJumplist('jumplist_}', ['}', '<C-o>'], [1,5], [1,5]);
247 testJumplist('jumplist_\'', ['m', 'a', 'h', '\'', 'a', 'h', '<C-i>'], [1,5], [1,5]);
248 testJumplist('jumplist_`', ['m', 'a', 'h', '`', 'a', 'h', '<C-i>'], [1,5], [1,5]);
249 testJumplist('jumplist_*_cachedCursor', ['*', '<C-o>'], [1,3], [1,3]);
250 testJumplist('jumplist_#_cachedCursor', ['#', '<C-o>'], [1,3], [1,3]);
251 testJumplist('jumplist_n', ['#', 'n', '<C-o>'], [1,1], [2,3]);
252 testJumplist('jumplist_N', ['#', 'N', '<C-o>'], [1,1], [2,3]);
253 testJumplist('jumplist_repeat_<c-o>', ['*', '*', '*', '3', '<C-o>'], [2,3], [2,3]);
254 testJumplist('jumplist_repeat_<c-i>', ['*', '*', '*', '3', '<C-o>', '2', '<C-i>'], [5,0], [2,3]);
255 testJumplist('jumplist_repeated_motion', ['3', '*', '<C-o>'], [2,3], [2,3]);
256 testJumplist('jumplist_/', ['/', '<C-o>'], [2,3], [2,3], 'dialog');
257 testJumplist('jumplist_?', ['?', '<C-o>'], [2,3], [2,3], 'dialog');
258 testJumplist('jumplist_skip_delted_mark<c-o>',
259              ['*', 'n', 'n', 'k', 'd', 'k', '<C-o>', '<C-o>', '<C-o>'],
260              [0,2], [0,2]);
261 testJumplist('jumplist_skip_delted_mark<c-i>',
262              ['*', 'n', 'n', 'k', 'd', 'k', '<C-o>', '<C-i>', '<C-i>'],
263              [1,0], [0,2]);
264 /**
265  * @param name Name of the test
266  * @param keys An array of keys or a string with a single key to simulate.
267  * @param endPos The expected end position of the cursor.
268  * @param startPos The position the cursor should start at, defaults to 0, 0.
269  */
270 function testMotion(name, keys, endPos, startPos) {
271   testVim(name, function(cm, vim, helpers) {
272     if (!startPos) {
273       startPos = { line: 0, ch: 0 };
274     }
275     cm.setCursor(startPos);
276     helpers.doKeys(keys);
277     helpers.assertCursorAt(endPos);
278   });
279 };
280
281 function makeCursor(line, ch) {
282   return { line: line, ch: ch };
283 };
284
285 function offsetCursor(cur, offsetLine, offsetCh) {
286   return { line: cur.line + offsetLine, ch: cur.ch + offsetCh };
287 };
288
289 // Motion tests
290 testMotion('|', '|', makeCursor(0, 0), makeCursor(0,4));
291 testMotion('|_repeat', ['3', '|'], makeCursor(0, 2), makeCursor(0,4));
292 testMotion('h', 'h', makeCursor(0, 0), word1.start);
293 testMotion('h_repeat', ['3', 'h'], offsetCursor(word1.end, 0, -3), word1.end);
294 testMotion('l', 'l', makeCursor(0, 1));
295 testMotion('l_repeat', ['2', 'l'], makeCursor(0, 2));
296 testMotion('j', 'j', offsetCursor(word1.end, 1, 0), word1.end);
297 testMotion('j_repeat', ['2', 'j'], offsetCursor(word1.end, 2, 0), word1.end);
298 testMotion('j_repeat_clip', ['1000', 'j'], endOfDocument);
299 testMotion('k', 'k', offsetCursor(word3.end, -1, 0), word3.end);
300 testMotion('k_repeat', ['2', 'k'], makeCursor(0, 4), makeCursor(2, 4));
301 testMotion('k_repeat_clip', ['1000', 'k'], makeCursor(0, 4), makeCursor(2, 4));
302 testMotion('w', 'w', word1.start);
303 testMotion('w_multiple_newlines_no_space', 'w', makeCursor(12, 2), makeCursor(11, 2));
304 testMotion('w_multiple_newlines_with_space', 'w', makeCursor(14, 0), makeCursor(12, 51));
305 testMotion('w_repeat', ['2', 'w'], word2.start);
306 testMotion('w_wrap', ['w'], word3.start, word2.start);
307 testMotion('w_endOfDocument', 'w', endOfDocument, endOfDocument);
308 testMotion('w_start_to_end', ['1000', 'w'], endOfDocument, makeCursor(0, 0));
309 testMotion('W', 'W', bigWord1.start);
310 testMotion('W_repeat', ['2', 'W'], bigWord3.start, bigWord1.start);
311 testMotion('e', 'e', word1.end);
312 testMotion('e_repeat', ['2', 'e'], word2.end);
313 testMotion('e_wrap', 'e', word3.end, word2.end);
314 testMotion('e_endOfDocument', 'e', endOfDocument, endOfDocument);
315 testMotion('e_start_to_end', ['1000', 'e'], endOfDocument, makeCursor(0, 0));
316 testMotion('b', 'b', word3.start, word3.end);
317 testMotion('b_repeat', ['2', 'b'], word2.start, word3.end);
318 testMotion('b_wrap', 'b', word2.start, word3.start);
319 testMotion('b_startOfDocument', 'b', makeCursor(0, 0), makeCursor(0, 0));
320 testMotion('b_end_to_start', ['1000', 'b'], makeCursor(0, 0), endOfDocument);
321 testMotion('ge', ['g', 'e'], word2.end, word3.end);
322 testMotion('ge_repeat', ['2', 'g', 'e'], word1.end, word3.start);
323 testMotion('ge_wrap', ['g', 'e'], word2.end, word3.start);
324 testMotion('ge_startOfDocument', ['g', 'e'], makeCursor(0, 0),
325     makeCursor(0, 0));
326 testMotion('ge_end_to_start', ['1000', 'g', 'e'], makeCursor(0, 0), endOfDocument);
327 testMotion('gg', ['g', 'g'], makeCursor(lines[0].line, lines[0].textStart),
328     makeCursor(3, 1));
329 testMotion('gg_repeat', ['3', 'g', 'g'],
330     makeCursor(lines[2].line, lines[2].textStart));
331 testMotion('G', 'G',
332     makeCursor(lines[lines.length - 1].line, lines[lines.length - 1].textStart),
333     makeCursor(3, 1));
334 testMotion('G_repeat', ['3', 'G'], makeCursor(lines[2].line,
335     lines[2].textStart));
336 // TODO: Make the test code long enough to test Ctrl-F and Ctrl-B.
337 testMotion('0', '0', makeCursor(0, 0), makeCursor(0, 8));
338 testMotion('^', '^', makeCursor(0, lines[0].textStart), makeCursor(0, 8));
339 testMotion('+', '+', makeCursor(1, lines[1].textStart), makeCursor(0, 8));
340 testMotion('-', '-', makeCursor(0, lines[0].textStart), makeCursor(1, 4));
341 testMotion('_', ['6','_'], makeCursor(5, lines[5].textStart), makeCursor(0, 8));
342 testMotion('$', '$', makeCursor(0, lines[0].length - 1), makeCursor(0, 1));
343 testMotion('$_repeat', ['2', '$'], makeCursor(1, lines[1].length - 1),
344     makeCursor(0, 3));
345 testMotion('f', ['f', 'p'], pChars[0], makeCursor(charLine.line, 0));
346 testMotion('f_repeat', ['2', 'f', 'p'], pChars[2], pChars[0]);
347 testMotion('f_num', ['f', '2'], numChars[2], makeCursor(charLine.line, 0));
348 testMotion('t', ['t','p'], offsetCursor(pChars[0], 0, -1),
349     makeCursor(charLine.line, 0));
350 testMotion('t_repeat', ['2', 't', 'p'], offsetCursor(pChars[2], 0, -1),
351     pChars[0]);
352 testMotion('F', ['F', 'p'], pChars[0], pChars[1]);
353 testMotion('F_repeat', ['2', 'F', 'p'], pChars[0], pChars[2]);
354 testMotion('T', ['T', 'p'], offsetCursor(pChars[0], 0, 1), pChars[1]);
355 testMotion('T_repeat', ['2', 'T', 'p'], offsetCursor(pChars[0], 0, 1), pChars[2]);
356 testMotion('%_parens', ['%'], parens1.end, parens1.start);
357 testMotion('%_squares', ['%'], squares1.end, squares1.start);
358 testMotion('%_braces', ['%'], curlys1.end, curlys1.start);
359 testMotion('%_seek_outside', ['%'], seekOutside.end, seekOutside.start);
360 testMotion('%_seek_inside', ['%'], seekInside.end, seekInside.start);
361 testVim('%_seek_skip', function(cm, vim, helpers) {
362   cm.setCursor(0,0);
363   helpers.doKeys(['%']);
364   helpers.assertCursorAt(0,9);
365 }, {value:'01234"("()'});
366 testVim('%_skip_string', function(cm, vim, helpers) {
367   cm.setCursor(0,0);
368   helpers.doKeys(['%']);
369   helpers.assertCursorAt(0,4);
370   cm.setCursor(0,2);
371   helpers.doKeys(['%']);
372   helpers.assertCursorAt(0,0);
373 }, {value:'(")")'});
374 (')')
375 testVim('%_skip_comment', function(cm, vim, helpers) {
376   cm.setCursor(0,0);
377   helpers.doKeys(['%']);
378   helpers.assertCursorAt(0,6);
379   cm.setCursor(0,3);
380   helpers.doKeys(['%']);
381   helpers.assertCursorAt(0,0);
382 }, {value:'(/*)*/)'});
383 // Make sure that moving down after going to the end of a line always leaves you
384 // at the end of a line, but preserves the offset in other cases
385 testVim('Changing lines after Eol operation', function(cm, vim, helpers) {
386   cm.setCursor(0,0);
387   helpers.doKeys(['$']);
388   helpers.doKeys(['j']);
389   // After moving to Eol and then down, we should be at Eol of line 2
390   helpers.assertCursorAt({ line: 1, ch: lines[1].length - 1 });
391   helpers.doKeys(['j']);
392   // After moving down, we should be at Eol of line 3
393   helpers.assertCursorAt({ line: 2, ch: lines[2].length - 1 });
394   helpers.doKeys(['h']);
395   helpers.doKeys(['j']);
396   // After moving back one space and then down, since line 4 is shorter than line 2, we should
397   // be at Eol of line 2 - 1
398   helpers.assertCursorAt({ line: 3, ch: lines[3].length - 1 });
399   helpers.doKeys(['j']);
400   helpers.doKeys(['j']);
401   // After moving down again, since line 3 has enough characters, we should be back to the
402   // same place we were at on line 1
403   helpers.assertCursorAt({ line: 5, ch: lines[2].length - 2 });
404 });
405 //making sure gj and gk recover from clipping
406 testVim('gj_gk_clipping', function(cm,vim,helpers){
407   cm.setCursor(0, 1);
408   helpers.doKeys('g','j','g','j');
409   helpers.assertCursorAt(2, 1);
410   helpers.doKeys('g','k','g','k');
411   helpers.assertCursorAt(0, 1);
412 },{value: 'line 1\n\nline 2'});
413 //testing a mix of j/k and gj/gk
414 testVim('j_k_and_gj_gk', function(cm,vim,helpers){
415   cm.setSize(120);
416   cm.setCursor(0, 0);
417   //go to the last character on the first line
418   helpers.doKeys('$');
419   //move up/down on the column within the wrapped line
420   //side-effect: cursor is not locked to eol anymore
421   helpers.doKeys('g','k');
422   var cur=cm.getCursor();
423   eq(cur.line,0);
424   is((cur.ch<176),'gk didn\'t move cursor back (1)');
425   helpers.doKeys('g','j');
426   helpers.assertCursorAt(0, 176);
427   //should move to character 177 on line 2 (j/k preserve character index within line)
428   helpers.doKeys('j');
429   //due to different line wrapping, the cursor can be on a different screen-x now
430   //gj and gk preserve screen-x on movement, much like moveV
431   helpers.doKeys('3','g','k');
432   cur=cm.getCursor();
433   eq(cur.line,1);
434   is((cur.ch<176),'gk didn\'t move cursor back (2)');
435   helpers.doKeys('g','j','2','g','j');
436   //should return to the same character-index
437   helpers.doKeys('k');
438   helpers.assertCursorAt(0, 176);
439 },{ 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.'});
440 testVim('gj_gk', function(cm, vim, helpers) {
441   if (phantom) return;
442   cm.setSize(120);
443   // Test top of document edge case.
444   cm.setCursor(0, 4);
445   helpers.doKeys('g', 'j');
446   helpers.doKeys('10', 'g', 'k');
447   helpers.assertCursorAt(0, 4);
448
449   // Test moving down preserves column position.
450   helpers.doKeys('g', 'j');
451   var pos1 = cm.getCursor();
452   var expectedPos2 = { line: 0, ch: (pos1.ch - 4) * 2 + 4};
453   helpers.doKeys('g', 'j');
454   helpers.assertCursorAt(expectedPos2);
455
456   // Move to the last character
457   cm.setCursor(0, 0);
458   // Move left to reset HSPos
459   helpers.doKeys('h');
460   // Test bottom of document edge case.
461   helpers.doKeys('100', 'g', 'j');
462   var endingPos = cm.getCursor();
463   is(endingPos != 0, 'gj should not be on wrapped line 0');
464   var topLeftCharCoords = cm.charCoords(makeCursor(0, 0));
465   var endingCharCoords = cm.charCoords(endingPos);
466   is(topLeftCharCoords.left == endingCharCoords.left, 'gj should end up on column 0');
467 },{ lineNumbers: false, lineWrapping:true, value: 'Thislineisintentiallylongtotestmovementofgjandgkoverwrappedlines.' });
468 testVim('}', function(cm, vim, helpers) {
469   cm.setCursor(0, 0);
470   helpers.doKeys('}');
471   helpers.assertCursorAt(1, 0);
472   cm.setCursor(0, 0);
473   helpers.doKeys('2', '}');
474   helpers.assertCursorAt(4, 0);
475   cm.setCursor(0, 0);
476   helpers.doKeys('6', '}');
477   helpers.assertCursorAt(5, 0);
478 }, { value: 'a\n\nb\nc\n\nd' });
479 testVim('{', function(cm, vim, helpers) {
480   cm.setCursor(5, 0);
481   helpers.doKeys('{');
482   helpers.assertCursorAt(4, 0);
483   cm.setCursor(5, 0);
484   helpers.doKeys('2', '{');
485   helpers.assertCursorAt(1, 0);
486   cm.setCursor(5, 0);
487   helpers.doKeys('6', '{');
488   helpers.assertCursorAt(0, 0);
489 }, { value: 'a\n\nb\nc\n\nd' });
490
491 // Operator tests
492 testVim('dl', function(cm, vim, helpers) {
493   var curStart = makeCursor(0, 0);
494   cm.setCursor(curStart);
495   helpers.doKeys('d', 'l');
496   eq('word1 ', cm.getValue());
497   var register = helpers.getRegisterController().getRegister();
498   eq(' ', register.text);
499   is(!register.linewise);
500   eqPos(curStart, cm.getCursor());
501 }, { value: ' word1 ' });
502 testVim('dl_eol', function(cm, vim, helpers) {
503   cm.setCursor(0, 6);
504   helpers.doKeys('d', 'l');
505   eq(' word1', cm.getValue());
506   var register = helpers.getRegisterController().getRegister();
507   eq(' ', register.text);
508   is(!register.linewise);
509   helpers.assertCursorAt(0, 5);
510 }, { value: ' word1 ' });
511 testVim('dl_repeat', function(cm, vim, helpers) {
512   var curStart = makeCursor(0, 0);
513   cm.setCursor(curStart);
514   helpers.doKeys('2', 'd', 'l');
515   eq('ord1 ', cm.getValue());
516   var register = helpers.getRegisterController().getRegister();
517   eq(' w', register.text);
518   is(!register.linewise);
519   eqPos(curStart, cm.getCursor());
520 }, { value: ' word1 ' });
521 testVim('dh', function(cm, vim, helpers) {
522   var curStart = makeCursor(0, 3);
523   cm.setCursor(curStart);
524   helpers.doKeys('d', 'h');
525   eq(' wrd1 ', cm.getValue());
526   var register = helpers.getRegisterController().getRegister();
527   eq('o', register.text);
528   is(!register.linewise);
529   eqPos(offsetCursor(curStart, 0 , -1), cm.getCursor());
530 }, { value: ' word1 ' });
531 testVim('dj', function(cm, vim, helpers) {
532   var curStart = makeCursor(0, 3);
533   cm.setCursor(curStart);
534   helpers.doKeys('d', 'j');
535   eq(' word3', cm.getValue());
536   var register = helpers.getRegisterController().getRegister();
537   eq(' word1\nword2\n', register.text);
538   is(register.linewise);
539   helpers.assertCursorAt(0, 1);
540 }, { value: ' word1\nword2\n word3' });
541 testVim('dj_end_of_document', function(cm, vim, helpers) {
542   var curStart = makeCursor(0, 3);
543   cm.setCursor(curStart);
544   helpers.doKeys('d', 'j');
545   eq(' word1 ', cm.getValue());
546   var register = helpers.getRegisterController().getRegister();
547   eq('', register.text);
548   is(!register.linewise);
549   helpers.assertCursorAt(0, 3);
550 }, { value: ' word1 ' });
551 testVim('dk', function(cm, vim, helpers) {
552   var curStart = makeCursor(1, 3);
553   cm.setCursor(curStart);
554   helpers.doKeys('d', 'k');
555   eq(' word3', cm.getValue());
556   var register = helpers.getRegisterController().getRegister();
557   eq(' word1\nword2\n', register.text);
558   is(register.linewise);
559   helpers.assertCursorAt(0, 1);
560 }, { value: ' word1\nword2\n word3' });
561 testVim('dk_start_of_document', function(cm, vim, helpers) {
562   var curStart = makeCursor(0, 3);
563   cm.setCursor(curStart);
564   helpers.doKeys('d', 'k');
565   eq(' word1 ', cm.getValue());
566   var register = helpers.getRegisterController().getRegister();
567   eq('', register.text);
568   is(!register.linewise);
569   helpers.assertCursorAt(0, 3);
570 }, { value: ' word1 ' });
571 testVim('dw_space', function(cm, vim, helpers) {
572   var curStart = makeCursor(0, 0);
573   cm.setCursor(curStart);
574   helpers.doKeys('d', 'w');
575   eq('word1 ', cm.getValue());
576   var register = helpers.getRegisterController().getRegister();
577   eq(' ', register.text);
578   is(!register.linewise);
579   eqPos(curStart, cm.getCursor());
580 }, { value: ' word1 ' });
581 testVim('dw_word', function(cm, vim, helpers) {
582   var curStart = makeCursor(0, 1);
583   cm.setCursor(curStart);
584   helpers.doKeys('d', 'w');
585   eq(' word2', cm.getValue());
586   var register = helpers.getRegisterController().getRegister();
587   eq('word1 ', register.text);
588   is(!register.linewise);
589   eqPos(curStart, cm.getCursor());
590 }, { value: ' word1 word2' });
591 testVim('dw_only_word', function(cm, vim, helpers) {
592   // Test that if there is only 1 word left, dw deletes till the end of the
593   // line.
594   cm.setCursor(0, 1);
595   helpers.doKeys('d', 'w');
596   eq(' ', cm.getValue());
597   var register = helpers.getRegisterController().getRegister();
598   eq('word1 ', register.text);
599   is(!register.linewise);
600   helpers.assertCursorAt(0, 0);
601 }, { value: ' word1 ' });
602 testVim('dw_eol', function(cm, vim, helpers) {
603   // Assert that dw does not delete the newline if last word to delete is at end
604   // of line.
605   cm.setCursor(0, 1);
606   helpers.doKeys('d', 'w');
607   eq(' \nword2', cm.getValue());
608   var register = helpers.getRegisterController().getRegister();
609   eq('word1', register.text);
610   is(!register.linewise);
611   helpers.assertCursorAt(0, 0);
612 }, { value: ' word1\nword2' });
613 testVim('dw_eol_with_multiple_newlines', function(cm, vim, helpers) {
614   // Assert that dw does not delete the newline if last word to delete is at end
615   // of line and it is followed by multiple newlines.
616   cm.setCursor(0, 1);
617   helpers.doKeys('d', 'w');
618   eq(' \n\nword2', cm.getValue());
619   var register = helpers.getRegisterController().getRegister();
620   eq('word1', register.text);
621   is(!register.linewise);
622   helpers.assertCursorAt(0, 0);
623 }, { value: ' word1\n\nword2' });
624 testVim('dw_empty_line_followed_by_whitespace', function(cm, vim, helpers) {
625   cm.setCursor(0, 0);
626   helpers.doKeys('d', 'w');
627   eq('  \nword', cm.getValue());
628 }, { value: '\n  \nword' });
629 testVim('dw_empty_line_followed_by_word', function(cm, vim, helpers) {
630   cm.setCursor(0, 0);
631   helpers.doKeys('d', 'w');
632   eq('word', cm.getValue());
633 }, { value: '\nword' });
634 testVim('dw_empty_line_followed_by_empty_line', function(cm, vim, helpers) {
635   cm.setCursor(0, 0);
636   helpers.doKeys('d', 'w');
637   eq('\n', cm.getValue());
638 }, { value: '\n\n' });
639 testVim('dw_whitespace_followed_by_whitespace', function(cm, vim, helpers) {
640   cm.setCursor(0, 0);
641   helpers.doKeys('d', 'w');
642   eq('\n   \n', cm.getValue());
643 }, { value: '  \n   \n' });
644 testVim('dw_whitespace_followed_by_empty_line', function(cm, vim, helpers) {
645   cm.setCursor(0, 0);
646   helpers.doKeys('d', 'w');
647   eq('\n\n', cm.getValue());
648 }, { value: '  \n\n' });
649 testVim('dw_word_whitespace_word', function(cm, vim, helpers) {
650   cm.setCursor(0, 0);
651   helpers.doKeys('d', 'w');
652   eq('\n   \nword2', cm.getValue());
653 }, { value: 'word1\n   \nword2'})
654 testVim('dw_end_of_document', function(cm, vim, helpers) {
655   cm.setCursor(1, 2);
656   helpers.doKeys('d', 'w');
657   eq('\nab', cm.getValue());
658 }, { value: '\nabc' });
659 testVim('dw_repeat', function(cm, vim, helpers) {
660   // Assert that dw does delete newline if it should go to the next line, and
661   // that repeat works properly.
662   cm.setCursor(0, 1);
663   helpers.doKeys('d', '2', 'w');
664   eq(' ', cm.getValue());
665   var register = helpers.getRegisterController().getRegister();
666   eq('word1\nword2', register.text);
667   is(!register.linewise);
668   helpers.assertCursorAt(0, 0);
669 }, { value: ' word1\nword2' });
670 testVim('de_word_start_and_empty_lines', function(cm, vim, helpers) {
671   cm.setCursor(0, 0);
672   helpers.doKeys('d', 'e');
673   eq('\n\n', cm.getValue());
674 }, { value: 'word\n\n' });
675 testVim('de_word_end_and_empty_lines', function(cm, vim, helpers) {
676   cm.setCursor(0, 3);
677   helpers.doKeys('d', 'e');
678   eq('wor', cm.getValue());
679 }, { value: 'word\n\n\n' });
680 testVim('de_whitespace_and_empty_lines', function(cm, vim, helpers) {
681   cm.setCursor(0, 0);
682   helpers.doKeys('d', 'e');
683   eq('', cm.getValue());
684 }, { value: '   \n\n\n' });
685 testVim('de_end_of_document', function(cm, vim, helpers) {
686   cm.setCursor(1, 2);
687   helpers.doKeys('d', 'e');
688   eq('\nab', cm.getValue());
689 }, { value: '\nabc' });
690 testVim('db_empty_lines', function(cm, vim, helpers) {
691   cm.setCursor(2, 0);
692   helpers.doKeys('d', 'b');
693   eq('\n\n', cm.getValue());
694 }, { value: '\n\n\n' });
695 testVim('db_word_start_and_empty_lines', function(cm, vim, helpers) {
696   cm.setCursor(2, 0);
697   helpers.doKeys('d', 'b');
698   eq('\nword', cm.getValue());
699 }, { value: '\n\nword' });
700 testVim('db_word_end_and_empty_lines', function(cm, vim, helpers) {
701   cm.setCursor(2, 3);
702   helpers.doKeys('d', 'b');
703   eq('\n\nd', cm.getValue());
704 }, { value: '\n\nword' });
705 testVim('db_whitespace_and_empty_lines', function(cm, vim, helpers) {
706   cm.setCursor(2, 0);
707   helpers.doKeys('d', 'b');
708   eq('', cm.getValue());
709 }, { value: '\n   \n' });
710 testVim('db_start_of_document', function(cm, vim, helpers) {
711   cm.setCursor(0, 0);
712   helpers.doKeys('d', 'b');
713   eq('abc\n', cm.getValue());
714 }, { value: 'abc\n' });
715 testVim('dge_empty_lines', function(cm, vim, helpers) {
716   cm.setCursor(1, 0);
717   helpers.doKeys('d', 'g', 'e');
718   // Note: In real VIM the result should be '', but it's not quite consistent,
719   // since 2 newlines are deleted. But in the similar case of word\n\n, only
720   // 1 newline is deleted. We'll diverge from VIM's behavior since it's much
721   // easier this way.
722   eq('\n', cm.getValue());
723 }, { value: '\n\n' });
724 testVim('dge_word_and_empty_lines', function(cm, vim, helpers) {
725   cm.setCursor(1, 0);
726   helpers.doKeys('d', 'g', 'e');
727   eq('wor\n', cm.getValue());
728 }, { value: 'word\n\n'});
729 testVim('dge_whitespace_and_empty_lines', function(cm, vim, helpers) {
730   cm.setCursor(2, 0);
731   helpers.doKeys('d', 'g', 'e');
732   eq('', cm.getValue());
733 }, { value: '\n  \n' });
734 testVim('dge_start_of_document', function(cm, vim, helpers) {
735   cm.setCursor(0, 0);
736   helpers.doKeys('d', 'g', 'e');
737   eq('bc\n', cm.getValue());
738 }, { value: 'abc\n' });
739 testVim('d_inclusive', function(cm, vim, helpers) {
740   // Assert that when inclusive is set, the character the cursor is on gets
741   // deleted too.
742   var curStart = makeCursor(0, 1);
743   cm.setCursor(curStart);
744   helpers.doKeys('d', 'e');
745   eq('  ', cm.getValue());
746   var register = helpers.getRegisterController().getRegister();
747   eq('word1', register.text);
748   is(!register.linewise);
749   eqPos(curStart, cm.getCursor());
750 }, { value: ' word1 ' });
751 testVim('d_reverse', function(cm, vim, helpers) {
752   // Test that deleting in reverse works.
753   cm.setCursor(1, 0);
754   helpers.doKeys('d', 'b');
755   eq(' word2 ', cm.getValue());
756   var register = helpers.getRegisterController().getRegister();
757   eq('word1\n', register.text);
758   is(!register.linewise);
759   helpers.assertCursorAt(0, 1);
760 }, { value: ' word1\nword2 ' });
761 testVim('dd', function(cm, vim, helpers) {
762   cm.setCursor(0, 3);
763   var expectedBuffer = cm.getRange({ line: 0, ch: 0 },
764     { line: 1, ch: 0 });
765   var expectedLineCount = cm.lineCount() - 1;
766   helpers.doKeys('d', 'd');
767   eq(expectedLineCount, cm.lineCount());
768   var register = helpers.getRegisterController().getRegister();
769   eq(expectedBuffer, register.text);
770   is(register.linewise);
771   helpers.assertCursorAt(0, lines[1].textStart);
772 });
773 testVim('dd_prefix_repeat', function(cm, vim, helpers) {
774   cm.setCursor(0, 3);
775   var expectedBuffer = cm.getRange({ line: 0, ch: 0 },
776     { line: 2, ch: 0 });
777   var expectedLineCount = cm.lineCount() - 2;
778   helpers.doKeys('2', 'd', 'd');
779   eq(expectedLineCount, cm.lineCount());
780   var register = helpers.getRegisterController().getRegister();
781   eq(expectedBuffer, register.text);
782   is(register.linewise);
783   helpers.assertCursorAt(0, lines[2].textStart);
784 });
785 testVim('dd_motion_repeat', function(cm, vim, helpers) {
786   cm.setCursor(0, 3);
787   var expectedBuffer = cm.getRange({ line: 0, ch: 0 },
788     { line: 2, ch: 0 });
789   var expectedLineCount = cm.lineCount() - 2;
790   helpers.doKeys('d', '2', 'd');
791   eq(expectedLineCount, cm.lineCount());
792   var register = helpers.getRegisterController().getRegister();
793   eq(expectedBuffer, register.text);
794   is(register.linewise);
795   helpers.assertCursorAt(0, lines[2].textStart);
796 });
797 testVim('dd_multiply_repeat', function(cm, vim, helpers) {
798   cm.setCursor(0, 3);
799   var expectedBuffer = cm.getRange({ line: 0, ch: 0 },
800     { line: 6, ch: 0 });
801   var expectedLineCount = cm.lineCount() - 6;
802   helpers.doKeys('2', 'd', '3', 'd');
803   eq(expectedLineCount, cm.lineCount());
804   var register = helpers.getRegisterController().getRegister();
805   eq(expectedBuffer, register.text);
806   is(register.linewise);
807   helpers.assertCursorAt(0, lines[6].textStart);
808 });
809 testVim('dd_lastline', function(cm, vim, helpers) {
810   cm.setCursor(cm.lineCount(), 0);
811   var expectedLineCount = cm.lineCount() - 1;
812   helpers.doKeys('d', 'd');
813   eq(expectedLineCount, cm.lineCount());
814   helpers.assertCursorAt(cm.lineCount() - 1, 0);
815 });
816 // Yank commands should behave the exact same as d commands, expect that nothing
817 // gets deleted.
818 testVim('yw_repeat', function(cm, vim, helpers) {
819   // Assert that yw does yank newline if it should go to the next line, and
820   // that repeat works properly.
821   var curStart = makeCursor(0, 1);
822   cm.setCursor(curStart);
823   helpers.doKeys('y', '2', 'w');
824   eq(' word1\nword2', cm.getValue());
825   var register = helpers.getRegisterController().getRegister();
826   eq('word1\nword2', register.text);
827   is(!register.linewise);
828   eqPos(curStart, cm.getCursor());
829 }, { value: ' word1\nword2' });
830 testVim('yy_multiply_repeat', function(cm, vim, helpers) {
831   var curStart = makeCursor(0, 3);
832   cm.setCursor(curStart);
833   var expectedBuffer = cm.getRange({ line: 0, ch: 0 },
834     { line: 6, ch: 0 });
835   var expectedLineCount = cm.lineCount();
836   helpers.doKeys('2', 'y', '3', 'y');
837   eq(expectedLineCount, cm.lineCount());
838   var register = helpers.getRegisterController().getRegister();
839   eq(expectedBuffer, register.text);
840   is(register.linewise);
841   eqPos(curStart, cm.getCursor());
842 });
843 // Change commands behave like d commands except that it also enters insert
844 // mode. In addition, when the change is linewise, an additional newline is
845 // inserted so that insert mode starts on that line.
846 testVim('cw', function(cm, vim, helpers) {
847   cm.setCursor(0, 0);
848   helpers.doKeys('c', '2', 'w');
849   eq(' word3', cm.getValue());
850   helpers.assertCursorAt(0, 0);
851 }, { value: 'word1 word2 word3'});
852 testVim('cw_repeat', function(cm, vim, helpers) {
853   // Assert that cw does delete newline if it should go to the next line, and
854   // that repeat works properly.
855   var curStart = makeCursor(0, 1);
856   cm.setCursor(curStart);
857   helpers.doKeys('c', '2', 'w');
858   eq(' ', cm.getValue());
859   var register = helpers.getRegisterController().getRegister();
860   eq('word1\nword2', register.text);
861   is(!register.linewise);
862   eqPos(curStart, cm.getCursor());
863   eq('vim-insert', cm.getOption('keyMap'));
864 }, { value: ' word1\nword2' });
865 testVim('cc_multiply_repeat', function(cm, vim, helpers) {
866   cm.setCursor(0, 3);
867   var expectedBuffer = cm.getRange({ line: 0, ch: 0 },
868     { line: 6, ch: 0 });
869   var expectedLineCount = cm.lineCount() - 5;
870   helpers.doKeys('2', 'c', '3', 'c');
871   eq(expectedLineCount, cm.lineCount());
872   var register = helpers.getRegisterController().getRegister();
873   eq(expectedBuffer, register.text);
874   is(register.linewise);
875   eq('vim-insert', cm.getOption('keyMap'));
876 });
877 testVim('cc_append', function(cm, vim, helpers) {
878   var expectedLineCount = cm.lineCount();
879   cm.setCursor(cm.lastLine(), 0);
880   helpers.doKeys('c', 'c');
881   eq(expectedLineCount, cm.lineCount());
882 });
883 // Swapcase commands edit in place and do not modify registers.
884 testVim('g~w_repeat', function(cm, vim, helpers) {
885   // Assert that dw does delete newline if it should go to the next line, and
886   // that repeat works properly.
887   var curStart = makeCursor(0, 1);
888   cm.setCursor(curStart);
889   helpers.doKeys('g', '~', '2', 'w');
890   eq(' WORD1\nWORD2', cm.getValue());
891   var register = helpers.getRegisterController().getRegister();
892   eq('', register.text);
893   is(!register.linewise);
894   eqPos(curStart, cm.getCursor());
895 }, { value: ' word1\nword2' });
896 testVim('g~g~', function(cm, vim, helpers) {
897   var curStart = makeCursor(0, 3);
898   cm.setCursor(curStart);
899   var expectedLineCount = cm.lineCount();
900   var expectedValue = cm.getValue().toUpperCase();
901   helpers.doKeys('2', 'g', '~', '3', 'g', '~');
902   eq(expectedValue, cm.getValue());
903   var register = helpers.getRegisterController().getRegister();
904   eq('', register.text);
905   is(!register.linewise);
906   eqPos(curStart, cm.getCursor());
907 }, { value: ' word1\nword2\nword3\nword4\nword5\nword6' });
908 testVim('>{motion}', function(cm, vim, helpers) {
909   cm.setCursor(1, 3);
910   var expectedLineCount = cm.lineCount();
911   var expectedValue = '   word1\n  word2\nword3 ';
912   helpers.doKeys('>', 'k');
913   eq(expectedValue, cm.getValue());
914   var register = helpers.getRegisterController().getRegister();
915   eq('', register.text);
916   is(!register.linewise);
917   helpers.assertCursorAt(0, 3);
918 }, { value: ' word1\nword2\nword3 ', indentUnit: 2 });
919 testVim('>>', function(cm, vim, helpers) {
920   cm.setCursor(0, 3);
921   var expectedLineCount = cm.lineCount();
922   var expectedValue = '   word1\n  word2\nword3 ';
923   helpers.doKeys('2', '>', '>');
924   eq(expectedValue, cm.getValue());
925   var register = helpers.getRegisterController().getRegister();
926   eq('', register.text);
927   is(!register.linewise);
928   helpers.assertCursorAt(0, 3);
929 }, { value: ' word1\nword2\nword3 ', indentUnit: 2 });
930 testVim('<{motion}', function(cm, vim, helpers) {
931   cm.setCursor(1, 3);
932   var expectedLineCount = cm.lineCount();
933   var expectedValue = ' word1\nword2\nword3 ';
934   helpers.doKeys('<', 'k');
935   eq(expectedValue, cm.getValue());
936   var register = helpers.getRegisterController().getRegister();
937   eq('', register.text);
938   is(!register.linewise);
939   helpers.assertCursorAt(0, 1);
940 }, { value: '   word1\n  word2\nword3 ', indentUnit: 2 });
941 testVim('<<', function(cm, vim, helpers) {
942   cm.setCursor(0, 3);
943   var expectedLineCount = cm.lineCount();
944   var expectedValue = ' word1\nword2\nword3 ';
945   helpers.doKeys('2', '<', '<');
946   eq(expectedValue, cm.getValue());
947   var register = helpers.getRegisterController().getRegister();
948   eq('', register.text);
949   is(!register.linewise);
950   helpers.assertCursorAt(0, 1);
951 }, { value: '   word1\n  word2\nword3 ', indentUnit: 2 });
952
953 // Edit tests
954 function testEdit(name, before, pos, edit, after) {
955   return testVim(name, function(cm, vim, helpers) {
956              cm.setCursor(0, before.search(pos));
957              helpers.doKeys.apply(this, edit.split(''));
958              eq(after, cm.getValue());
959            }, {value: before});
960 }
961
962 // These Delete tests effectively cover word-wise Change, Visual & Yank.
963 // Tabs are used as differentiated whitespace to catch edge cases.
964 // Normal word:
965 testEdit('diw_mid_spc', 'foo \tbAr\t baz', /A/, 'diw', 'foo \t\t baz');
966 testEdit('daw_mid_spc', 'foo \tbAr\t baz', /A/, 'daw', 'foo \tbaz');
967 testEdit('diw_mid_punct', 'foo \tbAr.\t baz', /A/, 'diw', 'foo \t.\t baz');
968 testEdit('daw_mid_punct', 'foo \tbAr.\t baz', /A/, 'daw', 'foo.\t baz');
969 testEdit('diw_mid_punct2', 'foo \t,bAr.\t baz', /A/, 'diw', 'foo \t,.\t baz');
970 testEdit('daw_mid_punct2', 'foo \t,bAr.\t baz', /A/, 'daw', 'foo \t,.\t baz');
971 testEdit('diw_start_spc', 'bAr \tbaz', /A/, 'diw', ' \tbaz');
972 testEdit('daw_start_spc', 'bAr \tbaz', /A/, 'daw', 'baz');
973 testEdit('diw_start_punct', 'bAr. \tbaz', /A/, 'diw', '. \tbaz');
974 testEdit('daw_start_punct', 'bAr. \tbaz', /A/, 'daw', '. \tbaz');
975 testEdit('diw_end_spc', 'foo \tbAr', /A/, 'diw', 'foo \t');
976 testEdit('daw_end_spc', 'foo \tbAr', /A/, 'daw', 'foo');
977 testEdit('diw_end_punct', 'foo \tbAr.', /A/, 'diw', 'foo \t.');
978 testEdit('daw_end_punct', 'foo \tbAr.', /A/, 'daw', 'foo.');
979 // Big word:
980 testEdit('diW_mid_spc', 'foo \tbAr\t baz', /A/, 'diW', 'foo \t\t baz');
981 testEdit('daW_mid_spc', 'foo \tbAr\t baz', /A/, 'daW', 'foo \tbaz');
982 testEdit('diW_mid_punct', 'foo \tbAr.\t baz', /A/, 'diW', 'foo \t\t baz');
983 testEdit('daW_mid_punct', 'foo \tbAr.\t baz', /A/, 'daW', 'foo \tbaz');
984 testEdit('diW_mid_punct2', 'foo \t,bAr.\t baz', /A/, 'diW', 'foo \t\t baz');
985 testEdit('daW_mid_punct2', 'foo \t,bAr.\t baz', /A/, 'daW', 'foo \tbaz');
986 testEdit('diW_start_spc', 'bAr\t baz', /A/, 'diW', '\t baz');
987 testEdit('daW_start_spc', 'bAr\t baz', /A/, 'daW', 'baz');
988 testEdit('diW_start_punct', 'bAr.\t baz', /A/, 'diW', '\t baz');
989 testEdit('daW_start_punct', 'bAr.\t baz', /A/, 'daW', 'baz');
990 testEdit('diW_end_spc', 'foo \tbAr', /A/, 'diW', 'foo \t');
991 testEdit('daW_end_spc', 'foo \tbAr', /A/, 'daW', 'foo');
992 testEdit('diW_end_punct', 'foo \tbAr.', /A/, 'diW', 'foo \t');
993 testEdit('daW_end_punct', 'foo \tbAr.', /A/, 'daW', 'foo');
994
995 // Operator-motion tests
996 testVim('D', function(cm, vim, helpers) {
997   cm.setCursor(0, 3);
998   helpers.doKeys('D');
999   eq(' wo\nword2\n word3', cm.getValue());
1000   var register = helpers.getRegisterController().getRegister();
1001   eq('rd1', register.text);
1002   is(!register.linewise);
1003   helpers.assertCursorAt(0, 2);
1004 }, { value: ' word1\nword2\n word3' });
1005 testVim('C', function(cm, vim, helpers) {
1006   var curStart = makeCursor(0, 3);
1007   cm.setCursor(curStart);
1008   helpers.doKeys('C');
1009   eq(' wo\nword2\n word3', cm.getValue());
1010   var register = helpers.getRegisterController().getRegister();
1011   eq('rd1', register.text);
1012   is(!register.linewise);
1013   eqPos(curStart, cm.getCursor());
1014   eq('vim-insert', cm.getOption('keyMap'));
1015 }, { value: ' word1\nword2\n word3' });
1016 testVim('Y', function(cm, vim, helpers) {
1017   var curStart = makeCursor(0, 3);
1018   cm.setCursor(curStart);
1019   helpers.doKeys('Y');
1020   eq(' word1\nword2\n word3', cm.getValue());
1021   var register = helpers.getRegisterController().getRegister();
1022   eq('rd1', register.text);
1023   is(!register.linewise);
1024   helpers.assertCursorAt(0, 3);
1025 }, { value: ' word1\nword2\n word3' });
1026 testVim('~', function(cm, vim, helpers) {
1027   helpers.doKeys('3', '~');
1028   eq('ABCdefg', cm.getValue());
1029   helpers.assertCursorAt(0, 3);
1030 }, { value: 'abcdefg' });
1031
1032 // Action tests
1033 testVim('ctrl-a', function(cm, vim, helpers) {
1034   cm.setCursor(0, 0);
1035   helpers.doKeys('<C-a>');
1036   eq('-9', cm.getValue());
1037   helpers.assertCursorAt(0, 1);
1038   helpers.doKeys('2','<C-a>');
1039   eq('-7', cm.getValue());
1040 }, {value: '-10'});
1041 testVim('ctrl-x', function(cm, vim, helpers) {
1042   cm.setCursor(0, 0);
1043   helpers.doKeys('<C-x>');
1044   eq('-1', cm.getValue());
1045   helpers.assertCursorAt(0, 1);
1046   helpers.doKeys('2','<C-x>');
1047   eq('-3', cm.getValue());
1048 }, {value: '0'});
1049 testVim('<C-x>/<C-a> search forward', function(cm, vim, helpers) {
1050   ['<C-x>', '<C-a>'].forEach(function(key) {
1051     cm.setCursor(0, 0);
1052     helpers.doKeys(key);
1053     helpers.assertCursorAt(0, 5);
1054     helpers.doKeys('l');
1055     helpers.doKeys(key);
1056     helpers.assertCursorAt(0, 10);
1057     cm.setCursor(0, 11);
1058     helpers.doKeys(key);
1059     helpers.assertCursorAt(0, 11);
1060   });
1061 }, {value: '__jmp1 jmp2 jmp'});
1062 testVim('a', function(cm, vim, helpers) {
1063   cm.setCursor(0, 1);
1064   helpers.doKeys('a');
1065   helpers.assertCursorAt(0, 2);
1066   eq('vim-insert', cm.getOption('keyMap'));
1067 });
1068 testVim('a_eol', function(cm, vim, helpers) {
1069   cm.setCursor(0, lines[0].length - 1);
1070   helpers.doKeys('a');
1071   helpers.assertCursorAt(0, lines[0].length);
1072   eq('vim-insert', cm.getOption('keyMap'));
1073 });
1074 testVim('i', function(cm, vim, helpers) {
1075   cm.setCursor(0, 1);
1076   helpers.doKeys('i');
1077   helpers.assertCursorAt(0, 1);
1078   eq('vim-insert', cm.getOption('keyMap'));
1079 });
1080 testVim('i_repeat', function(cm, vim, helpers) {
1081   helpers.doKeys('3', 'i');
1082   cm.replaceRange('test', cm.getCursor());
1083   helpers.doInsertModeKeys('Esc');
1084   eq('testtesttest', cm.getValue());
1085   helpers.assertCursorAt(0, 11);
1086 }, { value: '' });
1087 testVim('i_repeat_delete', function(cm, vim, helpers) {
1088   cm.setCursor(0, 4);
1089   helpers.doKeys('2', 'i');
1090   cm.replaceRange('z', cm.getCursor());
1091   helpers.doInsertModeKeys('Backspace', 'Backspace', 'Esc');
1092   eq('abe', cm.getValue());
1093   helpers.assertCursorAt(0, 1);
1094 }, { value: 'abcde' });
1095 testVim('A', function(cm, vim, helpers) {
1096   helpers.doKeys('A');
1097   helpers.assertCursorAt(0, lines[0].length);
1098   eq('vim-insert', cm.getOption('keyMap'));
1099 });
1100 testVim('I', function(cm, vim, helpers) {
1101   cm.setCursor(0, 4);
1102   helpers.doKeys('I');
1103   helpers.assertCursorAt(0, lines[0].textStart);
1104   eq('vim-insert', cm.getOption('keyMap'));
1105 });
1106 testVim('I_repeat', function(cm, vim, helpers) {
1107   cm.setCursor(0, 1);
1108   helpers.doKeys('3', 'I');
1109   cm.replaceRange('test', cm.getCursor());
1110   helpers.doInsertModeKeys('Esc');
1111   eq('testtesttestblah', cm.getValue());
1112   helpers.assertCursorAt(0, 11);
1113 }, { value: 'blah' });
1114 testVim('o', function(cm, vim, helpers) {
1115   cm.setCursor(0, 4);
1116   helpers.doKeys('o');
1117   eq('word1\n\nword2', cm.getValue());
1118   helpers.assertCursorAt(1, 0);
1119   eq('vim-insert', cm.getOption('keyMap'));
1120 }, { value: 'word1\nword2' });
1121 testVim('o_repeat', function(cm, vim, helpers) {
1122   cm.setCursor(0, 0);
1123   helpers.doKeys('3', 'o');
1124   cm.replaceRange('test', cm.getCursor());
1125   helpers.doInsertModeKeys('Esc');
1126   eq('\ntest\ntest\ntest', cm.getValue());
1127   helpers.assertCursorAt(3, 3);
1128 }, { value: '' });
1129 testVim('O', function(cm, vim, helpers) {
1130   cm.setCursor(0, 4);
1131   helpers.doKeys('O');
1132   eq('\nword1\nword2', cm.getValue());
1133   helpers.assertCursorAt(0, 0);
1134   eq('vim-insert', cm.getOption('keyMap'));
1135 }, { value: 'word1\nword2' });
1136 testVim('J', function(cm, vim, helpers) {
1137   cm.setCursor(0, 4);
1138   helpers.doKeys('J');
1139   var expectedValue = 'word1  word2\nword3\n word4';
1140   eq(expectedValue, cm.getValue());
1141   helpers.assertCursorAt(0, expectedValue.indexOf('word2') - 1);
1142 }, { value: 'word1 \n    word2\nword3\n word4' });
1143 testVim('J_repeat', function(cm, vim, helpers) {
1144   cm.setCursor(0, 4);
1145   helpers.doKeys('3', 'J');
1146   var expectedValue = 'word1  word2 word3\n word4';
1147   eq(expectedValue, cm.getValue());
1148   helpers.assertCursorAt(0, expectedValue.indexOf('word3') - 1);
1149 }, { value: 'word1 \n    word2\nword3\n word4' });
1150 testVim('p', function(cm, vim, helpers) {
1151   cm.setCursor(0, 1);
1152   helpers.getRegisterController().pushText('"', 'yank', 'abc\ndef', false);
1153   helpers.doKeys('p');
1154   eq('__abc\ndef_', cm.getValue());
1155   helpers.assertCursorAt(1, 2);
1156 }, { value: '___' });
1157 testVim('p_register', function(cm, vim, helpers) {
1158   cm.setCursor(0, 1);
1159   helpers.getRegisterController().getRegister('a').set('abc\ndef', false);
1160   helpers.doKeys('"', 'a', 'p');
1161   eq('__abc\ndef_', cm.getValue());
1162   helpers.assertCursorAt(1, 2);
1163 }, { value: '___' });
1164 testVim('p_wrong_register', function(cm, vim, helpers) {
1165   cm.setCursor(0, 1);
1166   helpers.getRegisterController().getRegister('a').set('abc\ndef', false);
1167   helpers.doKeys('p');
1168   eq('___', cm.getValue());
1169   helpers.assertCursorAt(0, 1);
1170 }, { value: '___' });
1171 testVim('p_line', function(cm, vim, helpers) {
1172   cm.setCursor(0, 1);
1173   helpers.getRegisterController().pushText('"', 'yank', '  a\nd\n', true);
1174   helpers.doKeys('2', 'p');
1175   eq('___\n  a\nd\n  a\nd', cm.getValue());
1176   helpers.assertCursorAt(1, 2);
1177 }, { value: '___' });
1178 testVim('P', function(cm, vim, helpers) {
1179   cm.setCursor(0, 1);
1180   helpers.getRegisterController().pushText('"', 'yank', 'abc\ndef', false);
1181   helpers.doKeys('P');
1182   eq('_abc\ndef__', cm.getValue());
1183   helpers.assertCursorAt(1, 3);
1184 }, { value: '___' });
1185 testVim('P_line', function(cm, vim, helpers) {
1186   cm.setCursor(0, 1);
1187   helpers.getRegisterController().pushText('"', 'yank', '  a\nd\n', true);
1188   helpers.doKeys('2', 'P');
1189   eq('  a\nd\n  a\nd\n___', cm.getValue());
1190   helpers.assertCursorAt(0, 2);
1191 }, { value: '___' });
1192 testVim('r', function(cm, vim, helpers) {
1193   cm.setCursor(0, 1);
1194   helpers.doKeys('3', 'r', 'u');
1195   eq('wuuuet\nanother', cm.getValue(),'3r failed');
1196   helpers.assertCursorAt(0, 3);
1197   cm.setCursor(0, 4);
1198   helpers.doKeys('v', 'j', 'h', 'r', '<Space>');
1199   eq('wuuu  \n    her', cm.getValue(),'Replacing selection by space-characters failed');
1200 }, { value: 'wordet\nanother' });
1201 testVim('R', function(cm, vim, helpers) {
1202   cm.setCursor(0, 1);
1203   helpers.doKeys('R');
1204   helpers.assertCursorAt(0, 1);
1205   eq('vim-replace', cm.getOption('keyMap'));
1206   is(cm.state.overwrite, 'Setting overwrite state failed');
1207 });
1208 testVim('mark', function(cm, vim, helpers) {
1209   cm.setCursor(2, 2);
1210   helpers.doKeys('m', 't');
1211   cm.setCursor(0, 0);
1212   helpers.doKeys('\'', 't');
1213   helpers.assertCursorAt(2, 2);
1214   cm.setCursor(0, 0);
1215   helpers.doKeys('`', 't');
1216   helpers.assertCursorAt(2, 2);
1217 });
1218 testVim('jumpToMark_next', function(cm, vim, helpers) {
1219   cm.setCursor(2, 2);
1220   helpers.doKeys('m', 't');
1221   cm.setCursor(0, 0);
1222   helpers.doKeys(']', '`');
1223   helpers.assertCursorAt(2, 2);
1224   cm.setCursor(0, 0);
1225   helpers.doKeys(']', '\'');
1226   helpers.assertCursorAt(2, 0);
1227 });
1228 testVim('jumpToMark_next_repeat', function(cm, vim, helpers) {
1229   cm.setCursor(2, 2);
1230   helpers.doKeys('m', 'a');
1231   cm.setCursor(3, 2);
1232   helpers.doKeys('m', 'b');
1233   cm.setCursor(4, 2);
1234   helpers.doKeys('m', 'c');
1235   cm.setCursor(0, 0);
1236   helpers.doKeys('2', ']', '`');
1237   helpers.assertCursorAt(3, 2);
1238   cm.setCursor(0, 0);
1239   helpers.doKeys('2', ']', '\'');
1240   helpers.assertCursorAt(3, 1);
1241 });
1242 testVim('jumpToMark_next_sameline', function(cm, vim, helpers) {
1243   cm.setCursor(2, 0);
1244   helpers.doKeys('m', 'a');
1245   cm.setCursor(2, 4);
1246   helpers.doKeys('m', 'b');
1247   cm.setCursor(2, 2);
1248   helpers.doKeys(']', '`');
1249   helpers.assertCursorAt(2, 4);
1250 });
1251 testVim('jumpToMark_next_onlyprev', function(cm, vim, helpers) {
1252   cm.setCursor(2, 0);
1253   helpers.doKeys('m', 'a');
1254   cm.setCursor(4, 0);
1255   helpers.doKeys(']', '`');
1256   helpers.assertCursorAt(4, 0);
1257 });
1258 testVim('jumpToMark_next_nomark', function(cm, vim, helpers) {
1259   cm.setCursor(2, 2);
1260   helpers.doKeys(']', '`');
1261   helpers.assertCursorAt(2, 2);
1262   helpers.doKeys(']', '\'');
1263   helpers.assertCursorAt(2, 0);
1264 });
1265 testVim('jumpToMark_next_linewise_over', function(cm, vim, helpers) {
1266   cm.setCursor(2, 2);
1267   helpers.doKeys('m', 'a');
1268   cm.setCursor(3, 4);
1269   helpers.doKeys('m', 'b');
1270   cm.setCursor(2, 1);
1271   helpers.doKeys(']', '\'');
1272   helpers.assertCursorAt(3, 1);
1273 });
1274 testVim('jumpToMark_next_action', function(cm, vim, helpers) {
1275   cm.setCursor(2, 2);
1276   helpers.doKeys('m', 't');
1277   cm.setCursor(0, 0);
1278   helpers.doKeys('d', ']', '`');
1279   helpers.assertCursorAt(0, 0);
1280   var actual = cm.getLine(0);
1281   var expected = 'pop pop 0 1 2 3 4';
1282   eq(actual, expected, "Deleting while jumping to the next mark failed.");
1283 });
1284 testVim('jumpToMark_next_line_action', function(cm, vim, helpers) {
1285   cm.setCursor(2, 2);
1286   helpers.doKeys('m', 't');
1287   cm.setCursor(0, 0);
1288   helpers.doKeys('d', ']', '\'');
1289   helpers.assertCursorAt(0, 1);
1290   var actual = cm.getLine(0);
1291   var expected = ' (a) [b] {c} '
1292   eq(actual, expected, "Deleting while jumping to the next mark line failed.");
1293 });
1294 testVim('jumpToMark_prev', function(cm, vim, helpers) {
1295   cm.setCursor(2, 2);
1296   helpers.doKeys('m', 't');
1297   cm.setCursor(4, 0);
1298   helpers.doKeys('[', '`');
1299   helpers.assertCursorAt(2, 2);
1300   cm.setCursor(4, 0);
1301   helpers.doKeys('[', '\'');
1302   helpers.assertCursorAt(2, 0);
1303 });
1304 testVim('jumpToMark_prev_repeat', function(cm, vim, helpers) {
1305   cm.setCursor(2, 2);
1306   helpers.doKeys('m', 'a');
1307   cm.setCursor(3, 2);
1308   helpers.doKeys('m', 'b');
1309   cm.setCursor(4, 2);
1310   helpers.doKeys('m', 'c');
1311   cm.setCursor(5, 0);
1312   helpers.doKeys('2', '[', '`');
1313   helpers.assertCursorAt(3, 2);
1314   cm.setCursor(5, 0);
1315   helpers.doKeys('2', '[', '\'');
1316   helpers.assertCursorAt(3, 1);
1317 });
1318 testVim('jumpToMark_prev_sameline', function(cm, vim, helpers) {
1319   cm.setCursor(2, 0);
1320   helpers.doKeys('m', 'a');
1321   cm.setCursor(2, 4);
1322   helpers.doKeys('m', 'b');
1323   cm.setCursor(2, 2);
1324   helpers.doKeys('[', '`');
1325   helpers.assertCursorAt(2, 0);
1326 });
1327 testVim('jumpToMark_prev_onlynext', function(cm, vim, helpers) {
1328   cm.setCursor(4, 4);
1329   helpers.doKeys('m', 'a');
1330   cm.setCursor(2, 0);
1331   helpers.doKeys('[', '`');
1332   helpers.assertCursorAt(2, 0);
1333 });
1334 testVim('jumpToMark_prev_nomark', function(cm, vim, helpers) {
1335   cm.setCursor(2, 2);
1336   helpers.doKeys('[', '`');
1337   helpers.assertCursorAt(2, 2);
1338   helpers.doKeys('[', '\'');
1339   helpers.assertCursorAt(2, 0);
1340 });
1341 testVim('jumpToMark_prev_linewise_over', function(cm, vim, helpers) {
1342   cm.setCursor(2, 2);
1343   helpers.doKeys('m', 'a');
1344   cm.setCursor(3, 4);
1345   helpers.doKeys('m', 'b');
1346   cm.setCursor(3, 6);
1347   helpers.doKeys('[', '\'');
1348   helpers.assertCursorAt(2, 0);
1349 });
1350 testVim('delmark_single', function(cm, vim, helpers) {
1351   cm.setCursor(1, 2);
1352   helpers.doKeys('m', 't');
1353   helpers.doEx('delmarks t');
1354   cm.setCursor(0, 0);
1355   helpers.doKeys('`', 't');
1356   helpers.assertCursorAt(0, 0);
1357 });
1358 testVim('delmark_range', function(cm, vim, helpers) {
1359   cm.setCursor(1, 2);
1360   helpers.doKeys('m', 'a');
1361   cm.setCursor(2, 2);
1362   helpers.doKeys('m', 'b');
1363   cm.setCursor(3, 2);
1364   helpers.doKeys('m', 'c');
1365   cm.setCursor(4, 2);
1366   helpers.doKeys('m', 'd');
1367   cm.setCursor(5, 2);
1368   helpers.doKeys('m', 'e');
1369   helpers.doEx('delmarks b-d');
1370   cm.setCursor(0, 0);
1371   helpers.doKeys('`', 'a');
1372   helpers.assertCursorAt(1, 2);
1373   helpers.doKeys('`', 'b');
1374   helpers.assertCursorAt(1, 2);
1375   helpers.doKeys('`', 'c');
1376   helpers.assertCursorAt(1, 2);
1377   helpers.doKeys('`', 'd');
1378   helpers.assertCursorAt(1, 2);
1379   helpers.doKeys('`', 'e');
1380   helpers.assertCursorAt(5, 2);
1381 });
1382 testVim('delmark_multi', function(cm, vim, helpers) {
1383   cm.setCursor(1, 2);
1384   helpers.doKeys('m', 'a');
1385   cm.setCursor(2, 2);
1386   helpers.doKeys('m', 'b');
1387   cm.setCursor(3, 2);
1388   helpers.doKeys('m', 'c');
1389   cm.setCursor(4, 2);
1390   helpers.doKeys('m', 'd');
1391   cm.setCursor(5, 2);
1392   helpers.doKeys('m', 'e');
1393   helpers.doEx('delmarks bcd');
1394   cm.setCursor(0, 0);
1395   helpers.doKeys('`', 'a');
1396   helpers.assertCursorAt(1, 2);
1397   helpers.doKeys('`', 'b');
1398   helpers.assertCursorAt(1, 2);
1399   helpers.doKeys('`', 'c');
1400   helpers.assertCursorAt(1, 2);
1401   helpers.doKeys('`', 'd');
1402   helpers.assertCursorAt(1, 2);
1403   helpers.doKeys('`', 'e');
1404   helpers.assertCursorAt(5, 2);
1405 });
1406 testVim('delmark_multi_space', function(cm, vim, helpers) {
1407   cm.setCursor(1, 2);
1408   helpers.doKeys('m', 'a');
1409   cm.setCursor(2, 2);
1410   helpers.doKeys('m', 'b');
1411   cm.setCursor(3, 2);
1412   helpers.doKeys('m', 'c');
1413   cm.setCursor(4, 2);
1414   helpers.doKeys('m', 'd');
1415   cm.setCursor(5, 2);
1416   helpers.doKeys('m', 'e');
1417   helpers.doEx('delmarks b c d');
1418   cm.setCursor(0, 0);
1419   helpers.doKeys('`', 'a');
1420   helpers.assertCursorAt(1, 2);
1421   helpers.doKeys('`', 'b');
1422   helpers.assertCursorAt(1, 2);
1423   helpers.doKeys('`', 'c');
1424   helpers.assertCursorAt(1, 2);
1425   helpers.doKeys('`', 'd');
1426   helpers.assertCursorAt(1, 2);
1427   helpers.doKeys('`', 'e');
1428   helpers.assertCursorAt(5, 2);
1429 });
1430 testVim('delmark_all', function(cm, vim, helpers) {
1431   cm.setCursor(1, 2);
1432   helpers.doKeys('m', 'a');
1433   cm.setCursor(2, 2);
1434   helpers.doKeys('m', 'b');
1435   cm.setCursor(3, 2);
1436   helpers.doKeys('m', 'c');
1437   cm.setCursor(4, 2);
1438   helpers.doKeys('m', 'd');
1439   cm.setCursor(5, 2);
1440   helpers.doKeys('m', 'e');
1441   helpers.doEx('delmarks a b-de');
1442   cm.setCursor(0, 0);
1443   helpers.doKeys('`', 'a');
1444   helpers.assertCursorAt(0, 0);
1445   helpers.doKeys('`', 'b');
1446   helpers.assertCursorAt(0, 0);
1447   helpers.doKeys('`', 'c');
1448   helpers.assertCursorAt(0, 0);
1449   helpers.doKeys('`', 'd');
1450   helpers.assertCursorAt(0, 0);
1451   helpers.doKeys('`', 'e');
1452   helpers.assertCursorAt(0, 0);
1453 });
1454 testVim('visual', function(cm, vim, helpers) {
1455   helpers.doKeys('l', 'v', 'l', 'l');
1456   helpers.assertCursorAt(0, 3);
1457   eqPos(makeCursor(0, 1), cm.getCursor('anchor'));
1458   helpers.doKeys('d');
1459   eq('15', cm.getValue());
1460 }, { value: '12345' });
1461 testVim('visual_line', function(cm, vim, helpers) {
1462   helpers.doKeys('l', 'V', 'l', 'j', 'j', 'd');
1463   eq(' 4\n 5', cm.getValue());
1464 }, { value: ' 1\n 2\n 3\n 4\n 5' });
1465 testVim('visual_marks', function(cm, vim, helpers) {
1466   helpers.doKeys('l', 'v', 'l', 'l', 'v');
1467   // Test visual mode marks
1468   cm.setCursor(0, 0);
1469   helpers.doKeys('\'', '<');
1470   helpers.assertCursorAt(0, 1);
1471   helpers.doKeys('\'', '>');
1472   helpers.assertCursorAt(0, 3);
1473 });
1474 testVim('visual_join', function(cm, vim, helpers) {
1475   helpers.doKeys('l', 'V', 'l', 'j', 'j', 'J');
1476   eq(' 1 2 3\n 4\n 5', cm.getValue());
1477 }, { value: ' 1\n 2\n 3\n 4\n 5' });
1478 testVim('visual_blank', function(cm, vim, helpers) {
1479   helpers.doKeys('v', 'k');
1480   eq(vim.visualMode, true);
1481 }, { value: '\n' });
1482 testVim('/ and n/N', function(cm, vim, helpers) {
1483   cm.openDialog = helpers.fakeOpenDialog('match');
1484   helpers.doKeys('/');
1485   helpers.assertCursorAt(0, 11);
1486   helpers.doKeys('n');
1487   helpers.assertCursorAt(1, 6);
1488   helpers.doKeys('N');
1489   helpers.assertCursorAt(0, 11);
1490
1491   cm.setCursor(0, 0);
1492   helpers.doKeys('2', '/');
1493   helpers.assertCursorAt(1, 6);
1494 }, { value: 'match nope match \n nope Match' });
1495 testVim('/_case', function(cm, vim, helpers) {
1496   cm.openDialog = helpers.fakeOpenDialog('Match');
1497   helpers.doKeys('/');
1498   helpers.assertCursorAt(1, 6);
1499 }, { value: 'match nope match \n nope Match' });
1500 testVim('/_nongreedy', function(cm, vim, helpers) {
1501   cm.openDialog = helpers.fakeOpenDialog('aa');
1502   helpers.doKeys('/');
1503   helpers.assertCursorAt(0, 4);
1504   helpers.doKeys('n');
1505   helpers.assertCursorAt(1, 3);
1506   helpers.doKeys('n');
1507   helpers.assertCursorAt(0, 0);
1508 }, { value: 'aaa aa \n a aa'});
1509 testVim('?_nongreedy', function(cm, vim, helpers) {
1510   cm.openDialog = helpers.fakeOpenDialog('aa');
1511   helpers.doKeys('?');
1512   helpers.assertCursorAt(1, 3);
1513   helpers.doKeys('n');
1514   helpers.assertCursorAt(0, 4);
1515   helpers.doKeys('n');
1516   helpers.assertCursorAt(0, 0);
1517 }, { value: 'aaa aa \n a aa'});
1518 testVim('/_greedy', function(cm, vim, helpers) {
1519   cm.openDialog = helpers.fakeOpenDialog('a+');
1520   helpers.doKeys('/');
1521   helpers.assertCursorAt(0, 4);
1522   helpers.doKeys('n');
1523   helpers.assertCursorAt(1, 1);
1524   helpers.doKeys('n');
1525   helpers.assertCursorAt(1, 3);
1526   helpers.doKeys('n');
1527   helpers.assertCursorAt(0, 0);
1528 }, { value: 'aaa aa \n a aa'});
1529 testVim('?_greedy', function(cm, vim, helpers) {
1530   cm.openDialog = helpers.fakeOpenDialog('a+');
1531   helpers.doKeys('?');
1532   helpers.assertCursorAt(1, 3);
1533   helpers.doKeys('n');
1534   helpers.assertCursorAt(1, 1);
1535   helpers.doKeys('n');
1536   helpers.assertCursorAt(0, 4);
1537   helpers.doKeys('n');
1538   helpers.assertCursorAt(0, 0);
1539 }, { value: 'aaa aa \n a aa'});
1540 testVim('/_greedy_0_or_more', function(cm, vim, helpers) {
1541   cm.openDialog = helpers.fakeOpenDialog('a*');
1542   helpers.doKeys('/');
1543   helpers.assertCursorAt(0, 3);
1544   helpers.doKeys('n');
1545   helpers.assertCursorAt(0, 4);
1546   helpers.doKeys('n');
1547   helpers.assertCursorAt(0, 5);
1548   helpers.doKeys('n');
1549   helpers.assertCursorAt(1, 0);
1550   helpers.doKeys('n');
1551   helpers.assertCursorAt(1, 1);
1552   helpers.doKeys('n');
1553   helpers.assertCursorAt(0, 0);
1554 }, { value: 'aaa  aa\n aa'});
1555 testVim('?_greedy_0_or_more', function(cm, vim, helpers) {
1556   cm.openDialog = helpers.fakeOpenDialog('a*');
1557   helpers.doKeys('?');
1558   helpers.assertCursorAt(1, 1);
1559   helpers.doKeys('n');
1560   helpers.assertCursorAt(1, 0);
1561   helpers.doKeys('n');
1562   helpers.assertCursorAt(0, 5);
1563   helpers.doKeys('n');
1564   helpers.assertCursorAt(0, 4);
1565   helpers.doKeys('n');
1566   helpers.assertCursorAt(0, 3);
1567   helpers.doKeys('n');
1568   helpers.assertCursorAt(0, 0);
1569 }, { value: 'aaa  aa\n aa'});
1570 testVim('? and n/N', function(cm, vim, helpers) {
1571   cm.openDialog = helpers.fakeOpenDialog('match');
1572   helpers.doKeys('?');
1573   helpers.assertCursorAt(1, 6);
1574   helpers.doKeys('n');
1575   helpers.assertCursorAt(0, 11);
1576   helpers.doKeys('N');
1577   helpers.assertCursorAt(1, 6);
1578
1579   cm.setCursor(0, 0);
1580   helpers.doKeys('2', '?');
1581   helpers.assertCursorAt(0, 11);
1582 }, { value: 'match nope match \n nope Match' });
1583 testVim('*', function(cm, vim, helpers) {
1584   cm.setCursor(0, 9);
1585   helpers.doKeys('*');
1586   helpers.assertCursorAt(0, 22);
1587
1588   cm.setCursor(0, 9);
1589   helpers.doKeys('2', '*');
1590   helpers.assertCursorAt(1, 8);
1591 }, { value: 'nomatch match nomatch match \nnomatch Match' });
1592 testVim('*_no_word', function(cm, vim, helpers) {
1593   cm.setCursor(0, 0);
1594   helpers.doKeys('*');
1595   helpers.assertCursorAt(0, 0);
1596 }, { value: ' \n match \n' });
1597 testVim('*_symbol', function(cm, vim, helpers) {
1598   cm.setCursor(0, 0);
1599   helpers.doKeys('*');
1600   helpers.assertCursorAt(1, 0);
1601 }, { value: ' /}\n/} match \n' });
1602 testVim('#', function(cm, vim, helpers) {
1603   cm.setCursor(0, 9);
1604   helpers.doKeys('#');
1605   helpers.assertCursorAt(1, 8);
1606
1607   cm.setCursor(0, 9);
1608   helpers.doKeys('2', '#');
1609   helpers.assertCursorAt(0, 22);
1610 }, { value: 'nomatch match nomatch match \nnomatch Match' });
1611 testVim('*_seek', function(cm, vim, helpers) {
1612   // Should skip over space and symbols.
1613   cm.setCursor(0, 3);
1614   helpers.doKeys('*');
1615   helpers.assertCursorAt(0, 22);
1616 }, { value: '    :=  match nomatch match \nnomatch Match' });
1617 testVim('#', function(cm, vim, helpers) {
1618   // Should skip over space and symbols.
1619   cm.setCursor(0, 3);
1620   helpers.doKeys('#');
1621   helpers.assertCursorAt(1, 8);
1622 }, { value: '    :=  match nomatch match \nnomatch Match' });
1623 testVim('.', function(cm, vim, helpers) {
1624   cm.setCursor(0, 0);
1625   helpers.doKeys('2', 'd', 'w');
1626   helpers.doKeys('.');
1627   eq('5 6', cm.getValue());
1628 }, { value: '1 2 3 4 5 6'});
1629 testVim('._repeat', function(cm, vim, helpers) {
1630   cm.setCursor(0, 0);
1631   helpers.doKeys('2', 'd', 'w');
1632   helpers.doKeys('3', '.');
1633   eq('6', cm.getValue());
1634 }, { value: '1 2 3 4 5 6'});
1635 testVim('._insert', function(cm, vim, helpers) {
1636   helpers.doKeys('i');
1637   cm.replaceRange('test', cm.getCursor());
1638   helpers.doInsertModeKeys('Esc');
1639   helpers.doKeys('.');
1640   eq('testestt', cm.getValue());
1641   helpers.assertCursorAt(0, 6);
1642 }, { value: ''});
1643 testVim('._insert_repeat', function(cm, vim, helpers) {
1644   helpers.doKeys('i');
1645   cm.replaceRange('test', cm.getCursor());
1646   cm.setCursor(0, 4);
1647   helpers.doInsertModeKeys('Esc');
1648   helpers.doKeys('2', '.');
1649   eq('testesttestt', cm.getValue());
1650   helpers.assertCursorAt(0, 10);
1651 }, { value: ''});
1652 testVim('._repeat_insert', function(cm, vim, helpers) {
1653   helpers.doKeys('3', 'i');
1654   cm.replaceRange('te', cm.getCursor());
1655   cm.setCursor(0, 2);
1656   helpers.doInsertModeKeys('Esc');
1657   helpers.doKeys('.');
1658   eq('tetettetetee', cm.getValue());
1659   helpers.assertCursorAt(0, 10);
1660 }, { value: ''});
1661 testVim('._insert_o', function(cm, vim, helpers) {
1662   helpers.doKeys('o');
1663   cm.replaceRange('z', cm.getCursor());
1664   cm.setCursor(1, 1);
1665   helpers.doInsertModeKeys('Esc');
1666   helpers.doKeys('.');
1667   eq('\nz\nz', cm.getValue());
1668   helpers.assertCursorAt(2, 0);
1669 }, { value: ''});
1670 testVim('._insert_o_repeat', function(cm, vim, helpers) {
1671   helpers.doKeys('o');
1672   cm.replaceRange('z', cm.getCursor());
1673   helpers.doInsertModeKeys('Esc');
1674   cm.setCursor(1, 0);
1675   helpers.doKeys('2', '.');
1676   eq('\nz\nz\nz', cm.getValue());
1677   helpers.assertCursorAt(3, 0);
1678 }, { value: ''});
1679 testVim('._insert_o_indent', function(cm, vim, helpers) {
1680   helpers.doKeys('o');
1681   cm.replaceRange('z', cm.getCursor());
1682   helpers.doInsertModeKeys('Esc');
1683   cm.setCursor(1, 2);
1684   helpers.doKeys('.');
1685   eq('{\n  z\n  z', cm.getValue());
1686   helpers.assertCursorAt(2, 2);
1687 }, { value: '{'});
1688 testVim('._insert_cw', function(cm, vim, helpers) {
1689   helpers.doKeys('c', 'w');
1690   cm.replaceRange('test', cm.getCursor());
1691   helpers.doInsertModeKeys('Esc');
1692   cm.setCursor(0, 3);
1693   helpers.doKeys('2', 'l');
1694   helpers.doKeys('.');
1695   eq('test test word3', cm.getValue());
1696   helpers.assertCursorAt(0, 8);
1697 }, { value: 'word1 word2 word3' });
1698 testVim('._insert_cw_repeat', function(cm, vim, helpers) {
1699   // For some reason, repeat cw in desktop VIM will does not repeat insert mode
1700   // changes. Will conform to that behavior.
1701   helpers.doKeys('c', 'w');
1702   cm.replaceRange('test', cm.getCursor());
1703   helpers.doInsertModeKeys('Esc');
1704   cm.setCursor(0, 4);
1705   helpers.doKeys('l');
1706   helpers.doKeys('2', '.');
1707   eq('test test', cm.getValue());
1708   helpers.assertCursorAt(0, 8);
1709 }, { value: 'word1 word2 word3' });
1710 testVim('._delete', function(cm, vim, helpers) {
1711   cm.setCursor(0, 5);
1712   helpers.doKeys('i');
1713   helpers.doInsertModeKeys('Backspace', 'Esc');
1714   helpers.doKeys('.');
1715   eq('zace', cm.getValue());
1716   helpers.assertCursorAt(0, 1);
1717 }, { value: 'zabcde'});
1718 testVim('._delete_repeat', function(cm, vim, helpers) {
1719   cm.setCursor(0, 6);
1720   helpers.doKeys('i');
1721   helpers.doInsertModeKeys('Backspace', 'Esc');
1722   helpers.doKeys('2', '.');
1723   eq('zzce', cm.getValue());
1724   helpers.assertCursorAt(0, 1);
1725 }, { value: 'zzabcde'});
1726 testVim('f;', function(cm, vim, helpers) {
1727   cm.setCursor(0, 0);
1728   helpers.doKeys('f', 'x');
1729   helpers.doKeys(';');
1730   helpers.doKeys('2', ';');
1731   eq(9, cm.getCursor().ch);
1732 }, { value: '01x3xx678x'});
1733 testVim('F;', function(cm, vim, helpers) {
1734   cm.setCursor(0, 8);
1735   helpers.doKeys('F', 'x');
1736   helpers.doKeys(';');
1737   helpers.doKeys('2', ';');
1738   eq(2, cm.getCursor().ch);
1739 }, { value: '01x3xx6x8x'});
1740 testVim('t;', function(cm, vim, helpers) {
1741   cm.setCursor(0, 0);
1742   helpers.doKeys('t', 'x');
1743   helpers.doKeys(';');
1744   helpers.doKeys('2', ';');
1745   eq(8, cm.getCursor().ch);
1746 }, { value: '01x3xx678x'});
1747 testVim('T;', function(cm, vim, helpers) {
1748   cm.setCursor(0, 9);
1749   helpers.doKeys('T', 'x');
1750   helpers.doKeys(';');
1751   helpers.doKeys('2', ';');
1752   eq(2, cm.getCursor().ch);
1753 }, { value: '0xx3xx678x'});
1754 testVim('f,', function(cm, vim, helpers) {
1755   cm.setCursor(0, 6);
1756   helpers.doKeys('f', 'x');
1757   helpers.doKeys(',');
1758   helpers.doKeys('2', ',');
1759   eq(2, cm.getCursor().ch);
1760 }, { value: '01x3xx678x'});
1761 testVim('F,', function(cm, vim, helpers) {
1762   cm.setCursor(0, 3);
1763   helpers.doKeys('F', 'x');
1764   helpers.doKeys(',');
1765   helpers.doKeys('2', ',');
1766   eq(9, cm.getCursor().ch);
1767 }, { value: '01x3xx678x'});
1768 testVim('t,', function(cm, vim, helpers) {
1769   cm.setCursor(0, 6);
1770   helpers.doKeys('t', 'x');
1771   helpers.doKeys(',');
1772   helpers.doKeys('2', ',');
1773   eq(3, cm.getCursor().ch);
1774 }, { value: '01x3xx678x'});
1775 testVim('T,', function(cm, vim, helpers) {
1776   cm.setCursor(0, 4);
1777   helpers.doKeys('T', 'x');
1778   helpers.doKeys(',');
1779   helpers.doKeys('2', ',');
1780   eq(8, cm.getCursor().ch);
1781 }, { value: '01x3xx67xx'});
1782 testVim('fd,;', function(cm, vim, helpers) {
1783   cm.setCursor(0, 0);
1784   helpers.doKeys('f', '4');
1785   cm.setCursor(0, 0);
1786   helpers.doKeys('d', ';');
1787   eq('56789', cm.getValue());
1788   helpers.doKeys('u');
1789   cm.setCursor(0, 9);
1790   helpers.doKeys('d', ',');
1791   eq('01239', cm.getValue());
1792 }, { value: '0123456789'});
1793 testVim('Fd,;', function(cm, vim, helpers) {
1794   cm.setCursor(0, 9);
1795   helpers.doKeys('F', '4');
1796   cm.setCursor(0, 9);
1797   helpers.doKeys('d', ';');
1798   eq('01239', cm.getValue());
1799   helpers.doKeys('u');
1800   cm.setCursor(0, 0);
1801   helpers.doKeys('d', ',');
1802   eq('56789', cm.getValue());
1803 }, { value: '0123456789'});
1804 testVim('td,;', function(cm, vim, helpers) {
1805   cm.setCursor(0, 0);
1806   helpers.doKeys('t', '4');
1807   cm.setCursor(0, 0);
1808   helpers.doKeys('d', ';');
1809   eq('456789', cm.getValue());
1810   helpers.doKeys('u');
1811   cm.setCursor(0, 9);
1812   helpers.doKeys('d', ',');
1813   eq('012349', cm.getValue());
1814 }, { value: '0123456789'});
1815 testVim('Td,;', function(cm, vim, helpers) {
1816   cm.setCursor(0, 9);
1817   helpers.doKeys('T', '4');
1818   cm.setCursor(0, 9);
1819   helpers.doKeys('d', ';');
1820   eq('012349', cm.getValue());
1821   helpers.doKeys('u');
1822   cm.setCursor(0, 0);
1823   helpers.doKeys('d', ',');
1824   eq('456789', cm.getValue());
1825 }, { value: '0123456789'});
1826 testVim('fc,;', function(cm, vim, helpers) {
1827   cm.setCursor(0, 0);
1828   helpers.doKeys('f', '4');
1829   cm.setCursor(0, 0);
1830   helpers.doKeys('c', ';', 'Esc');
1831   eq('56789', cm.getValue());
1832   helpers.doKeys('u');
1833   cm.setCursor(0, 9);
1834   helpers.doKeys('c', ',');
1835   eq('01239', cm.getValue());
1836 }, { value: '0123456789'});
1837 testVim('Fc,;', function(cm, vim, helpers) {
1838   cm.setCursor(0, 9);
1839   helpers.doKeys('F', '4');
1840   cm.setCursor(0, 9);
1841   helpers.doKeys('c', ';', 'Esc');
1842   eq('01239', cm.getValue());
1843   helpers.doKeys('u');
1844   cm.setCursor(0, 0);
1845   helpers.doKeys('c', ',');
1846   eq('56789', cm.getValue());
1847 }, { value: '0123456789'});
1848 testVim('tc,;', function(cm, vim, helpers) {
1849   cm.setCursor(0, 0);
1850   helpers.doKeys('t', '4');
1851   cm.setCursor(0, 0);
1852   helpers.doKeys('c', ';', 'Esc');
1853   eq('456789', cm.getValue());
1854   helpers.doKeys('u');
1855   cm.setCursor(0, 9);
1856   helpers.doKeys('c', ',');
1857   eq('012349', cm.getValue());
1858 }, { value: '0123456789'});
1859 testVim('Tc,;', function(cm, vim, helpers) {
1860   cm.setCursor(0, 9);
1861   helpers.doKeys('T', '4');
1862   cm.setCursor(0, 9);
1863   helpers.doKeys('c', ';', 'Esc');
1864   eq('012349', cm.getValue());
1865   helpers.doKeys('u');
1866   cm.setCursor(0, 0);
1867   helpers.doKeys('c', ',');
1868   eq('456789', cm.getValue());
1869 }, { value: '0123456789'});
1870 testVim('fy,;', function(cm, vim, helpers) {
1871   cm.setCursor(0, 0);
1872   helpers.doKeys('f', '4');
1873   cm.setCursor(0, 0);
1874   helpers.doKeys('y', ';', 'P');
1875   eq('012340123456789', cm.getValue());
1876   helpers.doKeys('u');
1877   cm.setCursor(0, 9);
1878   helpers.doKeys('y', ',', 'P');
1879   eq('012345678456789', cm.getValue());
1880 }, { value: '0123456789'});
1881 testVim('Fy,;', function(cm, vim, helpers) {
1882   cm.setCursor(0, 9);
1883   helpers.doKeys('F', '4');
1884   cm.setCursor(0, 9);
1885   helpers.doKeys('y', ';', 'p');
1886   eq('012345678945678', cm.getValue());
1887   helpers.doKeys('u');
1888   cm.setCursor(0, 0);
1889   helpers.doKeys('y', ',', 'P');
1890   eq('012340123456789', cm.getValue());
1891 }, { value: '0123456789'});
1892 testVim('ty,;', function(cm, vim, helpers) {
1893   cm.setCursor(0, 0);
1894   helpers.doKeys('t', '4');
1895   cm.setCursor(0, 0);
1896   helpers.doKeys('y', ';', 'P');
1897   eq('01230123456789', cm.getValue());
1898   helpers.doKeys('u');
1899   cm.setCursor(0, 9);
1900   helpers.doKeys('y', ',', 'p');
1901   eq('01234567895678', cm.getValue());
1902 }, { value: '0123456789'});
1903 testVim('Ty,;', function(cm, vim, helpers) {
1904   cm.setCursor(0, 9);
1905   helpers.doKeys('T', '4');
1906   cm.setCursor(0, 9);
1907   helpers.doKeys('y', ';', 'p');
1908   eq('01234567895678', cm.getValue());
1909   helpers.doKeys('u');
1910   cm.setCursor(0, 0);
1911   helpers.doKeys('y', ',', 'P');
1912   eq('01230123456789', cm.getValue());
1913 }, { value: '0123456789'});
1914 testVim('HML', function(cm, vim, helpers) {
1915   var lines = 35;
1916   var textHeight = cm.defaultTextHeight();
1917   cm.setSize(600, lines*textHeight);
1918   cm.setCursor(120, 0);
1919   helpers.doKeys('H');
1920   helpers.assertCursorAt(86, 2);
1921   helpers.doKeys('L');
1922   helpers.assertCursorAt(120, 4);
1923   helpers.doKeys('M');
1924   helpers.assertCursorAt(103,4);
1925 }, { value: (function(){
1926   var lines = new Array(100);
1927   var upper = '  xx\n';
1928   var lower = '    xx\n';
1929   upper = lines.join(upper);
1930   lower = lines.join(lower);
1931   return upper + lower;
1932 })()});
1933
1934 var zVals = ['zb','zz','zt','z-','z.','z<CR>'].map(function(e, idx){
1935   var lineNum = 250;
1936   var lines = 35;
1937   testVim(e, function(cm, vim, helpers) {
1938     var k1 = e[0];
1939     var k2 = e.substring(1);
1940     var textHeight = cm.defaultTextHeight();
1941     cm.setSize(600, lines*textHeight);
1942     cm.setCursor(lineNum, 0);
1943     helpers.doKeys(k1, k2);
1944     zVals[idx] = cm.getScrollInfo().top;
1945   }, { value: (function(){
1946     return new Array(500).join('\n');
1947   })()});
1948 });
1949 testVim('zb<zz', function(cm, vim, helpers){
1950   eq(zVals[0]<zVals[1], true);
1951 });
1952 testVim('zz<zt', function(cm, vim, helpers){
1953   eq(zVals[1]<zVals[2], true);
1954 });
1955 testVim('zb==z-', function(cm, vim, helpers){
1956   eq(zVals[0], zVals[3]);
1957 });
1958 testVim('zz==z.', function(cm, vim, helpers){
1959   eq(zVals[1], zVals[4]);
1960 });
1961 testVim('zt==z<CR>', function(cm, vim, helpers){
1962   eq(zVals[2], zVals[5]);
1963 });
1964
1965 var squareBracketMotionSandbox = ''+
1966   '({\n'+//0
1967   '  ({\n'+//11
1968   '  /*comment {\n'+//2
1969   '            */(\n'+//3
1970   '#else                \n'+//4
1971   '  /*       )\n'+//5
1972   '#if        }\n'+//6
1973   '  )}*/\n'+//7
1974   ')}\n'+//8
1975   '{}\n'+//9
1976   '#else {{\n'+//10
1977   '{}\n'+//11
1978   '}\n'+//12
1979   '{\n'+//13
1980   '#endif\n'+//14
1981   '}\n'+//15
1982   '}\n'+//16
1983   '#else';//17
1984 testVim('[[, ]]', function(cm, vim, helpers) {
1985   cm.setCursor(0, 0);
1986   helpers.doKeys(']', ']');
1987   helpers.assertCursorAt(9,0);
1988   helpers.doKeys('2', ']', ']');
1989   helpers.assertCursorAt(13,0);
1990   helpers.doKeys(']', ']');
1991   helpers.assertCursorAt(17,0);
1992   helpers.doKeys('[', '[');
1993   helpers.assertCursorAt(13,0);
1994   helpers.doKeys('2', '[', '[');
1995   helpers.assertCursorAt(9,0);
1996   helpers.doKeys('[', '[');
1997   helpers.assertCursorAt(0,0);
1998 }, { value: squareBracketMotionSandbox});
1999 testVim('[], ][', function(cm, vim, helpers) {
2000   cm.setCursor(0, 0);
2001   helpers.doKeys(']', '[');
2002   helpers.assertCursorAt(12,0);
2003   helpers.doKeys('2', ']', '[');
2004   helpers.assertCursorAt(16,0);
2005   helpers.doKeys(']', '[');
2006   helpers.assertCursorAt(17,0);
2007   helpers.doKeys('[', ']');
2008   helpers.assertCursorAt(16,0);
2009   helpers.doKeys('2', '[', ']');
2010   helpers.assertCursorAt(12,0);
2011   helpers.doKeys('[', ']');
2012   helpers.assertCursorAt(0,0);
2013 }, { value: squareBracketMotionSandbox});
2014 testVim('[{, ]}', function(cm, vim, helpers) {
2015   cm.setCursor(4, 10);
2016   helpers.doKeys('[', '{');
2017   helpers.assertCursorAt(2,12);
2018   helpers.doKeys('2', '[', '{');
2019   helpers.assertCursorAt(0,1);
2020   cm.setCursor(4, 10);
2021   helpers.doKeys(']', '}');
2022   helpers.assertCursorAt(6,11);
2023   helpers.doKeys('2', ']', '}');
2024   helpers.assertCursorAt(8,1);
2025   cm.setCursor(0,1);
2026   helpers.doKeys(']', '}');
2027   helpers.assertCursorAt(8,1);
2028   helpers.doKeys('[', '{');
2029   helpers.assertCursorAt(0,1);
2030 }, { value: squareBracketMotionSandbox});
2031 testVim('[(, ])', function(cm, vim, helpers) {
2032   cm.setCursor(4, 10);
2033   helpers.doKeys('[', '(');
2034   helpers.assertCursorAt(3,14);
2035   helpers.doKeys('2', '[', '(');
2036   helpers.assertCursorAt(0,0);
2037   cm.setCursor(4, 10);
2038   helpers.doKeys(']', ')');
2039   helpers.assertCursorAt(5,11);
2040   helpers.doKeys('2', ']', ')');
2041   helpers.assertCursorAt(8,0);
2042   helpers.doKeys('[', '(');
2043   helpers.assertCursorAt(0,0);
2044   helpers.doKeys(']', ')');
2045   helpers.assertCursorAt(8,0);
2046 }, { value: squareBracketMotionSandbox});
2047 testVim('[*, ]*, [/, ]/', function(cm, vim, helpers) {
2048   ['*', '/'].forEach(function(key){
2049     cm.setCursor(7, 0);
2050     helpers.doKeys('2', '[', key);
2051     helpers.assertCursorAt(2,2);
2052     helpers.doKeys('2', ']', key);
2053     helpers.assertCursorAt(7,5);
2054   });
2055 }, { value: squareBracketMotionSandbox});
2056 testVim('[#, ]#', function(cm, vim, helpers) {
2057   cm.setCursor(10, 3);
2058   helpers.doKeys('2', '[', '#');
2059   helpers.assertCursorAt(4,0);
2060   helpers.doKeys('5', ']', '#');
2061   helpers.assertCursorAt(17,0);
2062   cm.setCursor(10, 3);
2063   helpers.doKeys(']', '#');
2064   helpers.assertCursorAt(14,0);
2065 }, { value: squareBracketMotionSandbox});
2066 testVim('[m, ]m, [M, ]M', function(cm, vim, helpers) {
2067   cm.setCursor(11, 0);
2068   helpers.doKeys('[', 'm');
2069   helpers.assertCursorAt(10,7);
2070   helpers.doKeys('4', '[', 'm');
2071   helpers.assertCursorAt(1,3);
2072   helpers.doKeys('5', ']', 'm');
2073   helpers.assertCursorAt(11,0);
2074   helpers.doKeys('[', 'M');
2075   helpers.assertCursorAt(9,1);
2076   helpers.doKeys('3', ']', 'M');
2077   helpers.assertCursorAt(15,0);
2078   helpers.doKeys('5', '[', 'M');
2079   helpers.assertCursorAt(7,3);
2080 }, { value: squareBracketMotionSandbox});
2081
2082 // Ex mode tests
2083 testVim('ex_go_to_line', function(cm, vim, helpers) {
2084   cm.setCursor(0, 0);
2085   helpers.doEx('4');
2086   helpers.assertCursorAt(3, 0);
2087 }, { value: 'a\nb\nc\nd\ne\n'});
2088 testVim('ex_write', function(cm, vim, helpers) {
2089   var tmp = CodeMirror.commands.save;
2090   var written;
2091   var actualCm;
2092   CodeMirror.commands.save = function(cm) {
2093     written = true;
2094     actualCm = cm;
2095   };
2096   // Test that w, wr, wri ... write all trigger :write.
2097   var command = 'write';
2098   for (var i = 1; i < command.length; i++) {
2099     written = false;
2100     actualCm = null;
2101     helpers.doEx(command.substring(0, i));
2102     eq(written, true);
2103     eq(actualCm, cm);
2104   }
2105   CodeMirror.commands.save = tmp;
2106 });
2107 testVim('ex_sort', function(cm, vim, helpers) {
2108   helpers.doEx('sort');
2109   eq('Z\na\nb\nc\nd', cm.getValue());
2110 }, { value: 'b\nZ\nd\nc\na'});
2111 testVim('ex_sort_reverse', function(cm, vim, helpers) {
2112   helpers.doEx('sort!');
2113   eq('d\nc\nb\na', cm.getValue());
2114 }, { value: 'b\nd\nc\na'});
2115 testVim('ex_sort_range', function(cm, vim, helpers) {
2116   helpers.doEx('2,3sort');
2117   eq('b\nc\nd\na', cm.getValue());
2118 }, { value: 'b\nd\nc\na'});
2119 testVim('ex_sort_oneline', function(cm, vim, helpers) {
2120   helpers.doEx('2sort');
2121   // Expect no change.
2122   eq('b\nd\nc\na', cm.getValue());
2123 }, { value: 'b\nd\nc\na'});
2124 testVim('ex_sort_ignoreCase', function(cm, vim, helpers) {
2125   helpers.doEx('sort i');
2126   eq('a\nb\nc\nd\nZ', cm.getValue());
2127 }, { value: 'b\nZ\nd\nc\na'});
2128 testVim('ex_sort_unique', function(cm, vim, helpers) {
2129   helpers.doEx('sort u');
2130   eq('Z\na\nb\nc\nd', cm.getValue());
2131 }, { value: 'b\nZ\na\na\nd\na\nc\na'});
2132 testVim('ex_sort_decimal', function(cm, vim, helpers) {
2133   helpers.doEx('sort d');
2134   eq('d3\n s5\n6\n.9', cm.getValue());
2135 }, { value: '6\nd3\n s5\n.9'});
2136 testVim('ex_sort_decimal_negative', function(cm, vim, helpers) {
2137   helpers.doEx('sort d');
2138   eq('z-9\nd3\n s5\n6\n.9', cm.getValue());
2139 }, { value: '6\nd3\n s5\n.9\nz-9'});
2140 testVim('ex_sort_decimal_reverse', function(cm, vim, helpers) {
2141   helpers.doEx('sort! d');
2142   eq('.9\n6\n s5\nd3', cm.getValue());
2143 }, { value: '6\nd3\n s5\n.9'});
2144 testVim('ex_sort_hex', function(cm, vim, helpers) {
2145   helpers.doEx('sort x');
2146   eq(' s5\n6\n.9\n&0xB\nd3', cm.getValue());
2147 }, { value: '6\nd3\n s5\n&0xB\n.9'});
2148 testVim('ex_sort_octal', function(cm, vim, helpers) {
2149   helpers.doEx('sort o');
2150   eq('.8\n.9\nd3\n s5\n6', cm.getValue());
2151 }, { value: '6\nd3\n s5\n.9\n.8'});
2152 testVim('ex_sort_decimal_mixed', function(cm, vim, helpers) {
2153   helpers.doEx('sort d');
2154   eq('y\nz\nc1\nb2\na3', cm.getValue());
2155 }, { value: 'a3\nz\nc1\ny\nb2'});
2156 testVim('ex_sort_decimal_mixed_reverse', function(cm, vim, helpers) {
2157   helpers.doEx('sort! d');
2158   eq('a3\nb2\nc1\nz\ny', cm.getValue());
2159 }, { value: 'a3\nz\nc1\ny\nb2'});
2160 testVim('ex_substitute_same_line', function(cm, vim, helpers) {
2161   cm.setCursor(1, 0);
2162   helpers.doEx('s/one/two');
2163   eq('one one\n two two', cm.getValue());
2164 }, { value: 'one one\n one one'});
2165 testVim('ex_substitute_global', function(cm, vim, helpers) {
2166   cm.setCursor(1, 0);
2167   helpers.doEx('%s/one/two');
2168   eq('two two\n two two', cm.getValue());
2169 }, { value: 'one one\n one one'});
2170 testVim('ex_substitute_input_range', function(cm, vim, helpers) {
2171   cm.setCursor(1, 0);
2172   helpers.doEx('1,3s/\\d/0');
2173   eq('0\n0\n0\n4', cm.getValue());
2174 }, { value: '1\n2\n3\n4' });
2175 testVim('ex_substitute_visual_range', function(cm, vim, helpers) {
2176   cm.setCursor(1, 0);
2177   // Set last visual mode selection marks '< and '> at lines 2 and 4
2178   helpers.doKeys('V', '2', 'j', 'v');
2179   helpers.doEx('\'<,\'>s/\\d/0');
2180   eq('1\n0\n0\n0\n5', cm.getValue());
2181 }, { value: '1\n2\n3\n4\n5' });
2182 testVim('ex_substitute_capture', function(cm, vim, helpers) {
2183   cm.setCursor(1, 0);
2184   helpers.doEx('s/(\\d+)/$1$1/')
2185   eq('a1111 a1212 a1313', cm.getValue());
2186 }, { value: 'a11 a12 a13' });
2187 testVim('ex_substitute_empty_query', function(cm, vim, helpers) {
2188   // If the query is empty, use last query.
2189   cm.setCursor(1, 0);
2190   cm.openDialog = helpers.fakeOpenDialog('1');
2191   helpers.doKeys('/');
2192   helpers.doEx('s//b');
2193   eq('abb ab2 ab3', cm.getValue());
2194 }, { value: 'a11 a12 a13' });
2195 testVim('ex_substitute_count', function(cm, vim, helpers) {
2196   cm.setCursor(1, 0);
2197   helpers.doEx('s/\\d/0/i 2');
2198   eq('1\n0\n0\n4', cm.getValue());
2199 }, { value: '1\n2\n3\n4' });
2200 testVim('ex_substitute_count_with_range', function(cm, vim, helpers) {
2201   cm.setCursor(1, 0);
2202   helpers.doEx('1,3s/\\d/0/ 3');
2203   eq('1\n2\n0\n0', cm.getValue());
2204 }, { value: '1\n2\n3\n4' });
2205 function testSubstituteConfirm(name, command, initialValue, expectedValue, keys, finalPos) {
2206   testVim(name, function(cm, vim, helpers) {
2207     var savedOpenDialog = cm.openDialog;
2208     var savedKeyName = CodeMirror.keyName;
2209     var onKeyDown;
2210     var recordedCallback;
2211     var closed = true; // Start out closed, set false on second openDialog.
2212     function close() {
2213       closed = true;
2214     }
2215     // First openDialog should save callback.
2216     cm.openDialog = function(template, callback, options) {
2217       recordedCallback = callback;
2218     }
2219     // Do first openDialog.
2220     helpers.doKeys(':');
2221     // Second openDialog should save keyDown handler.
2222     cm.openDialog = function(template, callback, options) {
2223       onKeyDown = options.onKeyDown;
2224       closed = false;
2225     };
2226     // Return the command to Vim and trigger second openDialog.
2227     recordedCallback(command);
2228     // The event should really use keyCode, but here just mock it out and use
2229     // key and replace keyName to just return key.
2230     CodeMirror.keyName = function (e) { return e.key; }
2231     keys = keys.toUpperCase();
2232     for (var i = 0; i < keys.length; i++) {
2233       is(!closed);
2234       onKeyDown({ key: keys.charAt(i) }, '', close);
2235     }
2236     try {
2237       eq(expectedValue, cm.getValue());
2238       helpers.assertCursorAt(finalPos);
2239       is(closed);
2240     } catch(e) {
2241       throw e
2242     } finally {
2243       // Restore overriden functions.
2244       CodeMirror.keyName = savedKeyName;
2245       cm.openDialog = savedOpenDialog;
2246     }
2247   }, { value: initialValue });
2248 };
2249 testSubstituteConfirm('ex_substitute_confirm_emptydoc',
2250     '%s/x/b/c', '', '', '', makeCursor(0, 0));
2251 testSubstituteConfirm('ex_substitute_confirm_nomatch',
2252     '%s/x/b/c', 'ba a\nbab', 'ba a\nbab', '', makeCursor(0, 0));
2253 testSubstituteConfirm('ex_substitute_confirm_accept',
2254     '%s/a/b/c', 'ba a\nbab', 'bb b\nbbb', 'yyy', makeCursor(1, 1));
2255 testSubstituteConfirm('ex_substitute_confirm_random_keys',
2256     '%s/a/b/c', 'ba a\nbab', 'bb b\nbbb', 'ysdkywerty', makeCursor(1, 1));
2257 testSubstituteConfirm('ex_substitute_confirm_some',
2258     '%s/a/b/c', 'ba a\nbab', 'bb a\nbbb', 'yny', makeCursor(1, 1));
2259 testSubstituteConfirm('ex_substitute_confirm_all',
2260     '%s/a/b/c', 'ba a\nbab', 'bb b\nbbb', 'a', makeCursor(1, 1));
2261 testSubstituteConfirm('ex_substitute_confirm_accept_then_all',
2262     '%s/a/b/c', 'ba a\nbab', 'bb b\nbbb', 'ya', makeCursor(1, 1));
2263 testSubstituteConfirm('ex_substitute_confirm_quit',
2264     '%s/a/b/c', 'ba a\nbab', 'bb a\nbab', 'yq', makeCursor(0, 3));
2265 testSubstituteConfirm('ex_substitute_confirm_last',
2266     '%s/a/b/c', 'ba a\nbab', 'bb b\nbab', 'yl', makeCursor(0, 3));
2267 testSubstituteConfirm('ex_substitute_confirm_oneline',
2268     '1s/a/b/c', 'ba a\nbab', 'bb b\nbab', 'yl', makeCursor(0, 3));
2269 testSubstituteConfirm('ex_substitute_confirm_range_accept',
2270     '1,2s/a/b/c', 'aa\na \na\na', 'bb\nb \na\na', 'yyy', makeCursor(1, 0));
2271 testSubstituteConfirm('ex_substitute_confirm_range_some',
2272     '1,3s/a/b/c', 'aa\na \na\na', 'ba\nb \nb\na', 'ynyy', makeCursor(2, 0));
2273 testSubstituteConfirm('ex_substitute_confirm_range_all',
2274     '1,3s/a/b/c', 'aa\na \na\na', 'bb\nb \nb\na', 'a', makeCursor(2, 0));
2275 testSubstituteConfirm('ex_substitute_confirm_range_last',
2276     '1,3s/a/b/c', 'aa\na \na\na', 'bb\nb \na\na', 'yyl', makeCursor(1, 0));
2277 //:noh should clear highlighting of search-results but allow to resume search through n
2278 testVim('ex_noh_clearSearchHighlight', function(cm, vim, helpers) {
2279   cm.openDialog = helpers.fakeOpenDialog('match');
2280   helpers.doKeys('?');
2281   helpers.doEx('noh');
2282   eq(vim.searchState_.getOverlay(),null,'match-highlighting wasn\'t cleared');
2283   helpers.doKeys('n');
2284   helpers.assertCursorAt(0, 11,'can\'t resume search after clearing highlighting');
2285 }, { value: 'match nope match \n nope Match' });
2286 // TODO: Reset key maps after each test.
2287 testVim('ex_map_key2key', function(cm, vim, helpers) {
2288   helpers.doEx('map a x');
2289   helpers.doKeys('a');
2290   helpers.assertCursorAt(0, 0);
2291   eq('bc', cm.getValue());
2292 }, { value: 'abc' });
2293 testVim('ex_map_key2key_to_colon', function(cm, vim, helpers) {
2294   helpers.doEx('map ; :');
2295   var dialogOpened = false;
2296   cm.openDialog = function() {
2297     dialogOpened = true;
2298   }
2299   helpers.doKeys(';');
2300   eq(dialogOpened, true);
2301 });
2302 testVim('ex_map_ex2key:', function(cm, vim, helpers) {
2303   helpers.doEx('map :del x');
2304   helpers.doEx('del');
2305   helpers.assertCursorAt(0, 0);
2306   eq('bc', cm.getValue());
2307 }, { value: 'abc' });
2308 testVim('ex_map_ex2ex', function(cm, vim, helpers) {
2309   helpers.doEx('map :del :w');
2310   var tmp = CodeMirror.commands.save;
2311   var written = false;
2312   var actualCm;
2313   CodeMirror.commands.save = function(cm) {
2314     written = true;
2315     actualCm = cm;
2316   };
2317   helpers.doEx('del');
2318   CodeMirror.commands.save = tmp;
2319   eq(written, true);
2320   eq(actualCm, cm);
2321 });
2322 testVim('ex_map_key2ex', function(cm, vim, helpers) {
2323   helpers.doEx('map a :w');
2324   var tmp = CodeMirror.commands.save;
2325   var written = false;
2326   var actualCm;
2327   CodeMirror.commands.save = function(cm) {
2328     written = true;
2329     actualCm = cm;
2330   };
2331   helpers.doKeys('a');
2332   CodeMirror.commands.save = tmp;
2333   eq(written, true);
2334   eq(actualCm, cm);
2335 });
2336 // Testing registration of functions as ex-commands and mapping to <Key>-keys
2337 testVim('ex_api_test', function(cm, vim, helpers) {
2338   var res=false;
2339   var val='from';
2340   CodeMirror.Vim.defineEx('extest','ext',function(cm,params){
2341     if(params.args)val=params.args[0];
2342     else res=true;
2343   });
2344   helpers.doEx(':ext to');
2345   eq(val,'to','Defining ex-command failed');
2346   CodeMirror.Vim.map('<C-CR><Space>',':ext');
2347   helpers.doKeys('<C-CR>','<Space>');
2348   is(res,'Mapping to key failed');
2349 });
2350 // For now, this test needs to be last because it messes up : for future tests.
2351 testVim('ex_map_key2key_from_colon', function(cm, vim, helpers) {
2352   helpers.doEx('map : x');
2353   helpers.doKeys(':');
2354   helpers.assertCursorAt(0, 0);
2355   eq('bc', cm.getValue());
2356 }, { value: 'abc' });