openrat-cms

Unnamed repository; edit this file 'description' to name the repository.
Log | Files | Refs | README

vim_test.js (150445B)


      1 var Pos = CodeMirror.Pos;
      2 CodeMirror.Vim.suppressErrorLogging = true;
      3 
      4 var code = '' +
      5 ' wOrd1 (#%\n' +
      6 ' word3] \n' +
      7 'aopop pop 0 1 2 3 4\n' +
      8 ' (a) [b] {c} \n' +
      9 'int getchar(void) {\n' +
     10 '  static char buf[BUFSIZ];\n' +
     11 '  static char *bufp = buf;\n' +
     12 '  if (n == 0) {  /* buffer is empty */\n' +
     13 '    n = read(0, buf, sizeof buf);\n' +
     14 '    bufp = buf;\n' +
     15 '  }\n' +
     16 '\n' +
     17 '  return (--n >= 0) ? (unsigned char) *bufp++ : EOF;\n' +
     18 ' \n' +
     19 '}\n';
     20 
     21 var lines = (function() {
     22   lineText = code.split('\n');
     23   var ret = [];
     24   for (var i = 0; i < lineText.length; i++) {
     25     ret[i] = {
     26       line: i,
     27       length: lineText[i].length,
     28       lineText: lineText[i],
     29       textStart: /^\s*/.exec(lineText[i])[0].length
     30     };
     31   }
     32   return ret;
     33 })();
     34 var endOfDocument = makeCursor(lines.length - 1,
     35     lines[lines.length - 1].length);
     36 var wordLine = lines[0];
     37 var bigWordLine = lines[1];
     38 var charLine = lines[2];
     39 var bracesLine = lines[3];
     40 var seekBraceLine = lines[4];
     41 
     42 var word1 = {
     43   start: new Pos(wordLine.line, 1),
     44   end: new Pos(wordLine.line, 5)
     45 };
     46 var word2 = {
     47   start: new Pos(wordLine.line, word1.end.ch + 2),
     48   end: new Pos(wordLine.line, word1.end.ch + 4)
     49 };
     50 var word3 = {
     51   start: new Pos(bigWordLine.line, 1),
     52   end: new Pos(bigWordLine.line, 5)
     53 };
     54 var bigWord1 = word1;
     55 var bigWord2 = word2;
     56 var bigWord3 = {
     57   start: new Pos(bigWordLine.line, 1),
     58   end: new Pos(bigWordLine.line, 7)
     59 };
     60 var bigWord4 = {
     61   start: new Pos(bigWordLine.line, bigWord1.end.ch + 3),
     62   end: new Pos(bigWordLine.line, bigWord1.end.ch + 7)
     63 };
     64 
     65 var oChars = [ new Pos(charLine.line, 1),
     66     new Pos(charLine.line, 3),
     67     new Pos(charLine.line, 7) ];
     68 var pChars = [ new Pos(charLine.line, 2),
     69     new Pos(charLine.line, 4),
     70     new Pos(charLine.line, 6),
     71     new Pos(charLine.line, 8) ];
     72 var numChars = [ new Pos(charLine.line, 10),
     73     new Pos(charLine.line, 12),
     74     new Pos(charLine.line, 14),
     75     new Pos(charLine.line, 16),
     76     new Pos(charLine.line, 18)];
     77 var parens1 = {
     78   start: new Pos(bracesLine.line, 1),
     79   end: new Pos(bracesLine.line, 3)
     80 };
     81 var squares1 = {
     82   start: new Pos(bracesLine.line, 5),
     83   end: new Pos(bracesLine.line, 7)
     84 };
     85 var curlys1 = {
     86   start: new Pos(bracesLine.line, 9),
     87   end: new Pos(bracesLine.line, 11)
     88 };
     89 var seekOutside = {
     90   start: new Pos(seekBraceLine.line, 1),
     91   end: new Pos(seekBraceLine.line, 16)
     92 };
     93 var seekInside = {
     94   start: new Pos(seekBraceLine.line, 14),
     95   end: new Pos(seekBraceLine.line, 11)
     96 };
     97 
     98 function copyCursor(cur) {
     99   return new Pos(cur.line, cur.ch);
    100 }
    101 
    102 function forEach(arr, func) {
    103   for (var i = 0; i < arr.length; i++) {
    104     func(arr[i], i, arr);
    105   }
    106 }
    107 
    108 function testVim(name, run, opts, expectedFail) {
    109   var vimOpts = {
    110     lineNumbers: true,
    111     vimMode: true,
    112     showCursorWhenSelecting: true,
    113     value: code
    114   };
    115   for (var prop in opts) {
    116     if (opts.hasOwnProperty(prop)) {
    117       vimOpts[prop] = opts[prop];
    118     }
    119   }
    120   return test('vim_' + name, function() {
    121     var place = document.getElementById("testground");
    122     var cm = CodeMirror(place, vimOpts);
    123     var vim = CodeMirror.Vim.maybeInitVimState_(cm);
    124 
    125     function doKeysFn(cm) {
    126       return function(args) {
    127         if (args instanceof Array) {
    128           arguments = args;
    129         }
    130         for (var i = 0; i < arguments.length; i++) {
    131           var result = CodeMirror.Vim.handleKey(cm, arguments[i]);
    132           if (!result && cm.state.vim.insertMode) {
    133             cm.replaceSelections(fillArray(arguments[i], cm.listSelections().length));
    134           }
    135         }
    136       }
    137     }
    138     function doInsertModeKeysFn(cm) {
    139       return function(args) {
    140         if (args instanceof Array) { arguments = args; }
    141         function executeHandler(handler) {
    142           if (typeof handler == 'string') {
    143             CodeMirror.commands[handler](cm);
    144           } else {
    145             handler(cm);
    146           }
    147           return true;
    148         }
    149         for (var i = 0; i < arguments.length; i++) {
    150           var key = arguments[i];
    151           // Find key in keymap and handle.
    152           var handled = CodeMirror.lookupKey(key, cm.getOption('keyMap'), executeHandler, cm);
    153           // Record for insert mode.
    154           if (handled == "handled" && cm.state.vim.insertMode && arguments[i] != 'Esc') {
    155             var lastChange = CodeMirror.Vim.getVimGlobalState_().macroModeState.lastInsertModeChanges;
    156             if (lastChange && (key.indexOf('Delete') != -1 || key.indexOf('Backspace') != -1)) {
    157               lastChange.changes.push(new CodeMirror.Vim.InsertModeKey(key));
    158             }
    159           }
    160         }
    161       }
    162     }
    163     function doExFn(cm) {
    164       return function(command) {
    165         cm.openDialog = helpers.fakeOpenDialog(command);
    166         helpers.doKeys(':');
    167       }
    168     }
    169     function assertCursorAtFn(cm) {
    170       return function(line, ch) {
    171         var pos;
    172         if (ch == null && typeof line.line == 'number') {
    173           pos = line;
    174         } else {
    175           pos = makeCursor(line, ch);
    176         }
    177         eqCursorPos(cm.getCursor(), pos);
    178       }
    179     }
    180     function fakeOpenDialog(result) {
    181       return function(text, callback) {
    182         return callback(result);
    183       }
    184     }
    185     function fakeOpenNotification(matcher) {
    186       return function(text) {
    187         matcher(text);
    188       }
    189     }
    190     var helpers = {
    191       doKeys: doKeysFn(cm),
    192       // Warning: Only emulates keymap events, not character insertions. Use
    193       // replaceRange to simulate character insertions.
    194       // Keys are in CodeMirror format, NOT vim format.
    195       doInsertModeKeys: doInsertModeKeysFn(cm),
    196       doEx: doExFn(cm),
    197       assertCursorAt: assertCursorAtFn(cm),
    198       fakeOpenDialog: fakeOpenDialog,
    199       fakeOpenNotification: fakeOpenNotification,
    200       getRegisterController: function() {
    201         return CodeMirror.Vim.getRegisterController();
    202       }
    203     }
    204     CodeMirror.Vim.resetVimGlobalState_();
    205     var successful = false;
    206     var savedOpenNotification = cm.openNotification;
    207     var savedOpenDialog = cm.openDialog;
    208     try {
    209       run(cm, vim, helpers);
    210       successful = true;
    211     } finally {
    212       cm.openNotification = savedOpenNotification;
    213       cm.openDialog = savedOpenDialog;
    214       if (!successful || verbose) {
    215         place.style.visibility = "visible";
    216       } else {
    217         place.removeChild(cm.getWrapperElement());
    218       }
    219     }
    220   }, expectedFail);
    221 };
    222 testVim('qq@q', function(cm, vim, helpers) {
    223   cm.setCursor(0, 0);
    224   helpers.doKeys('q', 'q', 'l', 'l', 'q');
    225   helpers.assertCursorAt(0,2);
    226   helpers.doKeys('@', 'q');
    227   helpers.assertCursorAt(0,4);
    228 }, { value: '            '});
    229 testVim('@@', function(cm, vim, helpers) {
    230   cm.setCursor(0, 0);
    231   helpers.doKeys('q', 'q', 'l', 'l', 'q');
    232   helpers.assertCursorAt(0,2);
    233   helpers.doKeys('@', 'q');
    234   helpers.assertCursorAt(0,4);
    235   helpers.doKeys('@', '@');
    236   helpers.assertCursorAt(0,6);
    237 }, { value: '            '});
    238 var jumplistScene = ''+
    239   'word\n'+
    240   '(word)\n'+
    241   '{word\n'+
    242   'word.\n'+
    243   '\n'+
    244   'word search\n'+
    245   '}word\n'+
    246   'word\n'+
    247   'word\n';
    248 function testJumplist(name, keys, endPos, startPos, dialog) {
    249   endPos = makeCursor(endPos[0], endPos[1]);
    250   startPos = makeCursor(startPos[0], startPos[1]);
    251   testVim(name, function(cm, vim, helpers) {
    252     CodeMirror.Vim.resetVimGlobalState_();
    253     if(dialog)cm.openDialog = helpers.fakeOpenDialog('word');
    254     cm.setCursor(startPos);
    255     helpers.doKeys.apply(null, keys);
    256     helpers.assertCursorAt(endPos);
    257   }, {value: jumplistScene});
    258 };
    259 testJumplist('jumplist_H', ['H', '<C-o>'], [5,2], [5,2]);
    260 testJumplist('jumplist_M', ['M', '<C-o>'], [2,2], [2,2]);
    261 testJumplist('jumplist_L', ['L', '<C-o>'], [2,2], [2,2]);
    262 testJumplist('jumplist_[[', ['[', '[', '<C-o>'], [5,2], [5,2]);
    263 testJumplist('jumplist_]]', [']', ']', '<C-o>'], [2,2], [2,2]);
    264 testJumplist('jumplist_G', ['G', '<C-o>'], [5,2], [5,2]);
    265 testJumplist('jumplist_gg', ['g', 'g', '<C-o>'], [5,2], [5,2]);
    266 testJumplist('jumplist_%', ['%', '<C-o>'], [1,5], [1,5]);
    267 testJumplist('jumplist_{', ['{', '<C-o>'], [1,5], [1,5]);
    268 testJumplist('jumplist_}', ['}', '<C-o>'], [1,5], [1,5]);
    269 testJumplist('jumplist_\'', ['m', 'a', 'h', '\'', 'a', 'h', '<C-i>'], [1,0], [1,5]);
    270 testJumplist('jumplist_`', ['m', 'a', 'h', '`', 'a', 'h', '<C-i>'], [1,5], [1,5]);
    271 testJumplist('jumplist_*_cachedCursor', ['*', '<C-o>'], [1,3], [1,3]);
    272 testJumplist('jumplist_#_cachedCursor', ['#', '<C-o>'], [1,3], [1,3]);
    273 testJumplist('jumplist_n', ['#', 'n', '<C-o>'], [1,1], [2,3]);
    274 testJumplist('jumplist_N', ['#', 'N', '<C-o>'], [1,1], [2,3]);
    275 testJumplist('jumplist_repeat_<c-o>', ['*', '*', '*', '3', '<C-o>'], [2,3], [2,3]);
    276 testJumplist('jumplist_repeat_<c-i>', ['*', '*', '*', '3', '<C-o>', '2', '<C-i>'], [5,0], [2,3]);
    277 testJumplist('jumplist_repeated_motion', ['3', '*', '<C-o>'], [2,3], [2,3]);
    278 testJumplist('jumplist_/', ['/', '<C-o>'], [2,3], [2,3], 'dialog');
    279 testJumplist('jumplist_?', ['?', '<C-o>'], [2,3], [2,3], 'dialog');
    280 testJumplist('jumplist_skip_deleted_mark<c-o>',
    281              ['*', 'n', 'n', 'k', 'd', 'k', '<C-o>', '<C-o>', '<C-o>'],
    282              [0,2], [0,2]);
    283 testJumplist('jumplist_skip_deleted_mark<c-i>',
    284              ['*', 'n', 'n', 'k', 'd', 'k', '<C-o>', '<C-i>', '<C-i>'],
    285              [1,0], [0,2]);
    286 
    287 /**
    288  * @param name Name of the test
    289  * @param keys An array of keys or a string with a single key to simulate.
    290  * @param endPos The expected end position of the cursor.
    291  * @param startPos The position the cursor should start at, defaults to 0, 0.
    292  */
    293 function testMotion(name, keys, endPos, startPos) {
    294   testVim(name, function(cm, vim, helpers) {
    295     if (!startPos) {
    296       startPos = new Pos(0, 0);
    297     }
    298     cm.setCursor(startPos);
    299     helpers.doKeys(keys);
    300     helpers.assertCursorAt(endPos);
    301   });
    302 };
    303 
    304 function makeCursor(line, ch) {
    305   return new Pos(line, ch);
    306 };
    307 
    308 function offsetCursor(cur, offsetLine, offsetCh) {
    309   return new Pos(cur.line + offsetLine, cur.ch + offsetCh);
    310 };
    311 
    312 // Motion tests
    313 testMotion('|', '|', makeCursor(0, 0), makeCursor(0,4));
    314 testMotion('|_repeat', ['3', '|'], makeCursor(0, 2), makeCursor(0,4));
    315 testMotion('h', 'h', makeCursor(0, 0), word1.start);
    316 testMotion('h_repeat', ['3', 'h'], offsetCursor(word1.end, 0, -3), word1.end);
    317 testMotion('l', 'l', makeCursor(0, 1));
    318 testMotion('l_repeat', ['2', 'l'], makeCursor(0, 2));
    319 testMotion('j', 'j', offsetCursor(word1.end, 1, 0), word1.end);
    320 testMotion('j_repeat', ['2', 'j'], offsetCursor(word1.end, 2, 0), word1.end);
    321 testMotion('j_repeat_clip', ['1000', 'j'], endOfDocument);
    322 testMotion('k', 'k', offsetCursor(word3.end, -1, 0), word3.end);
    323 testMotion('k_repeat', ['2', 'k'], makeCursor(0, 4), makeCursor(2, 4));
    324 testMotion('k_repeat_clip', ['1000', 'k'], makeCursor(0, 4), makeCursor(2, 4));
    325 testMotion('w', 'w', word1.start);
    326 testMotion('w_multiple_newlines_no_space', 'w', makeCursor(12, 2), makeCursor(11, 2));
    327 testMotion('w_multiple_newlines_with_space', 'w', makeCursor(14, 0), makeCursor(12, 51));
    328 testMotion('w_repeat', ['2', 'w'], word2.start);
    329 testMotion('w_wrap', ['w'], word3.start, word2.start);
    330 testMotion('w_endOfDocument', 'w', endOfDocument, endOfDocument);
    331 testMotion('w_start_to_end', ['1000', 'w'], endOfDocument, makeCursor(0, 0));
    332 testMotion('W', 'W', bigWord1.start);
    333 testMotion('W_repeat', ['2', 'W'], bigWord3.start, bigWord1.start);
    334 testMotion('e', 'e', word1.end);
    335 testMotion('e_repeat', ['2', 'e'], word2.end);
    336 testMotion('e_wrap', 'e', word3.end, word2.end);
    337 testMotion('e_endOfDocument', 'e', endOfDocument, endOfDocument);
    338 testMotion('e_start_to_end', ['1000', 'e'], endOfDocument, makeCursor(0, 0));
    339 testMotion('b', 'b', word3.start, word3.end);
    340 testMotion('b_repeat', ['2', 'b'], word2.start, word3.end);
    341 testMotion('b_wrap', 'b', word2.start, word3.start);
    342 testMotion('b_startOfDocument', 'b', makeCursor(0, 0), makeCursor(0, 0));
    343 testMotion('b_end_to_start', ['1000', 'b'], makeCursor(0, 0), endOfDocument);
    344 testMotion('ge', ['g', 'e'], word2.end, word3.end);
    345 testMotion('ge_repeat', ['2', 'g', 'e'], word1.end, word3.start);
    346 testMotion('ge_wrap', ['g', 'e'], word2.end, word3.start);
    347 testMotion('ge_startOfDocument', ['g', 'e'], makeCursor(0, 0),
    348     makeCursor(0, 0));
    349 testMotion('ge_end_to_start', ['1000', 'g', 'e'], makeCursor(0, 0), endOfDocument);
    350 testMotion('gg', ['g', 'g'], makeCursor(lines[0].line, lines[0].textStart),
    351     makeCursor(3, 1));
    352 testMotion('gg_repeat', ['3', 'g', 'g'],
    353     makeCursor(lines[2].line, lines[2].textStart));
    354 testMotion('G', 'G',
    355     makeCursor(lines[lines.length - 1].line, lines[lines.length - 1].textStart),
    356     makeCursor(3, 1));
    357 testMotion('G_repeat', ['3', 'G'], makeCursor(lines[2].line,
    358     lines[2].textStart));
    359 // TODO: Make the test code long enough to test Ctrl-F and Ctrl-B.
    360 testMotion('0', '0', makeCursor(0, 0), makeCursor(0, 8));
    361 testMotion('^', '^', makeCursor(0, lines[0].textStart), makeCursor(0, 8));
    362 testMotion('+', '+', makeCursor(1, lines[1].textStart), makeCursor(0, 8));
    363 testMotion('-', '-', makeCursor(0, lines[0].textStart), makeCursor(1, 4));
    364 testMotion('_', ['6','_'], makeCursor(5, lines[5].textStart), makeCursor(0, 8));
    365 testMotion('$', '$', makeCursor(0, lines[0].length - 1), makeCursor(0, 1));
    366 testMotion('$_repeat', ['2', '$'], makeCursor(1, lines[1].length - 1),
    367     makeCursor(0, 3));
    368 testMotion('f', ['f', 'p'], pChars[0], makeCursor(charLine.line, 0));
    369 testMotion('f_repeat', ['2', 'f', 'p'], pChars[2], pChars[0]);
    370 testMotion('f_num', ['f', '2'], numChars[2], makeCursor(charLine.line, 0));
    371 testMotion('t', ['t','p'], offsetCursor(pChars[0], 0, -1),
    372     makeCursor(charLine.line, 0));
    373 testMotion('t_repeat', ['2', 't', 'p'], offsetCursor(pChars[2], 0, -1),
    374     pChars[0]);
    375 testMotion('F', ['F', 'p'], pChars[0], pChars[1]);
    376 testMotion('F_repeat', ['2', 'F', 'p'], pChars[0], pChars[2]);
    377 testMotion('T', ['T', 'p'], offsetCursor(pChars[0], 0, 1), pChars[1]);
    378 testMotion('T_repeat', ['2', 'T', 'p'], offsetCursor(pChars[0], 0, 1), pChars[2]);
    379 testMotion('%_parens', ['%'], parens1.end, parens1.start);
    380 testMotion('%_squares', ['%'], squares1.end, squares1.start);
    381 testMotion('%_braces', ['%'], curlys1.end, curlys1.start);
    382 testMotion('%_seek_outside', ['%'], seekOutside.end, seekOutside.start);
    383 testMotion('%_seek_inside', ['%'], seekInside.end, seekInside.start);
    384 testVim('%_seek_skip', function(cm, vim, helpers) {
    385   cm.setCursor(0,0);
    386   helpers.doKeys(['%']);
    387   helpers.assertCursorAt(0,9);
    388 }, {value:'01234"("()'});
    389 testVim('%_skip_string', function(cm, vim, helpers) {
    390   cm.setCursor(0,0);
    391   helpers.doKeys(['%']);
    392   helpers.assertCursorAt(0,4);
    393   cm.setCursor(0,2);
    394   helpers.doKeys(['%']);
    395   helpers.assertCursorAt(0,0);
    396 }, {value:'(")")'});
    397 testVim('%_skip_comment', function(cm, vim, helpers) {
    398   cm.setCursor(0,0);
    399   helpers.doKeys(['%']);
    400   helpers.assertCursorAt(0,6);
    401   cm.setCursor(0,3);
    402   helpers.doKeys(['%']);
    403   helpers.assertCursorAt(0,0);
    404 }, {value:'(/*)*/)'});
    405 // Make sure that moving down after going to the end of a line always leaves you
    406 // at the end of a line, but preserves the offset in other cases
    407 testVim('Changing lines after Eol operation', function(cm, vim, helpers) {
    408   cm.setCursor(0,0);
    409   helpers.doKeys(['$']);
    410   helpers.doKeys(['j']);
    411   // After moving to Eol and then down, we should be at Eol of line 2
    412   helpers.assertCursorAt(new Pos(1, lines[1].length - 1));
    413   helpers.doKeys(['j']);
    414   // After moving down, we should be at Eol of line 3
    415   helpers.assertCursorAt(new Pos(2, lines[2].length - 1));
    416   helpers.doKeys(['h']);
    417   helpers.doKeys(['j']);
    418   // After moving back one space and then down, since line 4 is shorter than line 2, we should
    419   // be at Eol of line 2 - 1
    420   helpers.assertCursorAt(new Pos(3, lines[3].length - 1));
    421   helpers.doKeys(['j']);
    422   helpers.doKeys(['j']);
    423   // After moving down again, since line 3 has enough characters, we should be back to the
    424   // same place we were at on line 1
    425   helpers.assertCursorAt(new Pos(5, lines[2].length - 2));
    426 });
    427 //making sure gj and gk recover from clipping
    428 testVim('gj_gk_clipping', function(cm,vim,helpers){
    429   cm.setCursor(0, 1);
    430   helpers.doKeys('g','j','g','j');
    431   helpers.assertCursorAt(2, 1);
    432   helpers.doKeys('g','k','g','k');
    433   helpers.assertCursorAt(0, 1);
    434 },{value: 'line 1\n\nline 2'});
    435 //testing a mix of j/k and gj/gk
    436 testVim('j_k_and_gj_gk', function(cm,vim,helpers){
    437   cm.setSize(120);
    438   cm.setCursor(0, 0);
    439   //go to the last character on the first line
    440   helpers.doKeys('$');
    441   //move up/down on the column within the wrapped line
    442   //side-effect: cursor is not locked to eol anymore
    443   helpers.doKeys('g','k');
    444   var cur=cm.getCursor();
    445   eq(cur.line,0);
    446   is((cur.ch<176),'gk didn\'t move cursor back (1)');
    447   helpers.doKeys('g','j');
    448   helpers.assertCursorAt(0, 176);
    449   //should move to character 177 on line 2 (j/k preserve character index within line)
    450   helpers.doKeys('j');
    451   //due to different line wrapping, the cursor can be on a different screen-x now
    452   //gj and gk preserve screen-x on movement, much like moveV
    453   helpers.doKeys('3','g','k');
    454   cur=cm.getCursor();
    455   eq(cur.line,1);
    456   is((cur.ch<176),'gk didn\'t move cursor back (2)');
    457   helpers.doKeys('g','j','2','g','j');
    458   //should return to the same character-index
    459   helpers.doKeys('k');
    460   helpers.assertCursorAt(0, 176);
    461 },{ 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.'});
    462 testVim('gj_gk', function(cm, vim, helpers) {
    463   if (phantom) return;
    464   cm.setSize(120);
    465   // Test top of document edge case.
    466   cm.setCursor(0, 4);
    467   helpers.doKeys('g', 'j');
    468   helpers.doKeys('10', 'g', 'k');
    469   helpers.assertCursorAt(0, 4);
    470 
    471   // Test moving down preserves column position.
    472   helpers.doKeys('g', 'j');
    473   var pos1 = cm.getCursor();
    474   var expectedPos2 = new Pos(0, (pos1.ch - 4) * 2 + 4);
    475   helpers.doKeys('g', 'j');
    476   helpers.assertCursorAt(expectedPos2);
    477 
    478   // Move to the last character
    479   cm.setCursor(0, 0);
    480   // Move left to reset HSPos
    481   helpers.doKeys('h');
    482   // Test bottom of document edge case.
    483   helpers.doKeys('100', 'g', 'j');
    484   var endingPos = cm.getCursor();
    485   is(endingPos != 0, 'gj should not be on wrapped line 0');
    486   var topLeftCharCoords = cm.charCoords(makeCursor(0, 0));
    487   var endingCharCoords = cm.charCoords(endingPos);
    488   is(topLeftCharCoords.left == endingCharCoords.left, 'gj should end up on column 0');
    489 },{ lineNumbers: false, lineWrapping:true, value: 'Thislineisintentionallylongtotestmovementofgjandgkoverwrappedlines.' });
    490 testVim('}', function(cm, vim, helpers) {
    491   cm.setCursor(0, 0);
    492   helpers.doKeys('}');
    493   helpers.assertCursorAt(1, 0);
    494   cm.setCursor(0, 0);
    495   helpers.doKeys('2', '}');
    496   helpers.assertCursorAt(4, 0);
    497   cm.setCursor(0, 0);
    498   helpers.doKeys('6', '}');
    499   helpers.assertCursorAt(5, 0);
    500 }, { value: 'a\n\nb\nc\n\nd' });
    501 testVim('{', function(cm, vim, helpers) {
    502   cm.setCursor(5, 0);
    503   helpers.doKeys('{');
    504   helpers.assertCursorAt(4, 0);
    505   cm.setCursor(5, 0);
    506   helpers.doKeys('2', '{');
    507   helpers.assertCursorAt(1, 0);
    508   cm.setCursor(5, 0);
    509   helpers.doKeys('6', '{');
    510   helpers.assertCursorAt(0, 0);
    511 }, { value: 'a\n\nb\nc\n\nd' });
    512 testVim('paragraph_motions', function(cm, vim, helpers) {
    513   cm.setCursor(10, 0);
    514   helpers.doKeys('{');
    515   helpers.assertCursorAt(4, 0);
    516   helpers.doKeys('{');
    517   helpers.assertCursorAt(0, 0);
    518   helpers.doKeys('2', '}');
    519   helpers.assertCursorAt(7, 0);
    520   helpers.doKeys('2', '}');
    521   helpers.assertCursorAt(16, 0);
    522 
    523   cm.setCursor(9, 0);
    524   helpers.doKeys('}');
    525   helpers.assertCursorAt(14, 0);
    526 
    527   cm.setCursor(6, 0);
    528   helpers.doKeys('}');
    529   helpers.assertCursorAt(7, 0);
    530 
    531   // ip inside empty space
    532   cm.setCursor(10, 0);
    533   helpers.doKeys('v', 'i', 'p');
    534   eqCursorPos(Pos(7, 0), cm.getCursor('anchor'));
    535   eqCursorPos(Pos(12, 0), cm.getCursor('head'));
    536   helpers.doKeys('i', 'p');
    537   eqCursorPos(Pos(7, 0), cm.getCursor('anchor'));
    538   eqCursorPos(Pos(13, 1), cm.getCursor('head'));
    539   helpers.doKeys('2', 'i', 'p');
    540   eqCursorPos(Pos(7, 0), cm.getCursor('anchor'));
    541   eqCursorPos(Pos(16, 1), cm.getCursor('head'));
    542 
    543   // should switch to visualLine mode
    544   cm.setCursor(14, 0);
    545   helpers.doKeys('<Esc>', 'v', 'i', 'p');
    546   helpers.assertCursorAt(14, 0);
    547 
    548   cm.setCursor(14, 0);
    549   helpers.doKeys('<Esc>', 'V', 'i', 'p');
    550   eqCursorPos(Pos(16, 1), cm.getCursor('head'));
    551 
    552   // ap inside empty space
    553   cm.setCursor(10, 0);
    554   helpers.doKeys('<Esc>', 'v', 'a', 'p');
    555   eqCursorPos(Pos(7, 0), cm.getCursor('anchor'));
    556   eqCursorPos(Pos(13, 1), cm.getCursor('head'));
    557   helpers.doKeys('a', 'p');
    558   eqCursorPos(Pos(7, 0), cm.getCursor('anchor'));
    559   eqCursorPos(Pos(16, 1), cm.getCursor('head'));
    560 
    561   cm.setCursor(13, 0);
    562   helpers.doKeys('v', 'a', 'p');
    563   eqCursorPos(Pos(13, 0), cm.getCursor('anchor'));
    564   eqCursorPos(Pos(14, 0), cm.getCursor('head'));
    565 
    566   cm.setCursor(16, 0);
    567   helpers.doKeys('v', 'a', 'p');
    568   eqCursorPos(Pos(14, 0), cm.getCursor('anchor'));
    569   eqCursorPos(Pos(16, 1), cm.getCursor('head'));
    570 
    571   cm.setCursor(0, 0);
    572   helpers.doKeys('v', 'a', 'p');
    573   eqCursorPos(Pos(0, 0), cm.getCursor('anchor'));
    574   eqCursorPos(Pos(4, 0), cm.getCursor('head'));
    575 
    576   cm.setCursor(0, 0);
    577   helpers.doKeys('d', 'i', 'p');
    578   var register = helpers.getRegisterController().getRegister();
    579   eq('a\na\n', register.toString());
    580   is(register.linewise);
    581   helpers.doKeys('3', 'j', 'p');
    582   helpers.doKeys('y', 'i', 'p');
    583   is(register.linewise);
    584   eq('b\na\na\nc\n', register.toString());
    585 }, { value: 'a\na\n\n\n\nb\nc\n\n\n\n\n\n\nd\n\ne\nf' });
    586 
    587 // Operator tests
    588 testVim('dl', function(cm, vim, helpers) {
    589   var curStart = makeCursor(0, 0);
    590   cm.setCursor(curStart);
    591   helpers.doKeys('d', 'l');
    592   eq('word1 ', cm.getValue());
    593   var register = helpers.getRegisterController().getRegister();
    594   eq(' ', register.toString());
    595   is(!register.linewise);
    596   eqCursorPos(curStart, cm.getCursor());
    597 }, { value: ' word1 ' });
    598 testVim('dl_eol', function(cm, vim, helpers) {
    599   cm.setCursor(0, 6);
    600   helpers.doKeys('d', 'l');
    601   eq(' word1', cm.getValue());
    602   var register = helpers.getRegisterController().getRegister();
    603   eq(' ', register.toString());
    604   is(!register.linewise);
    605   helpers.assertCursorAt(0, 5);
    606 }, { value: ' word1 ' });
    607 testVim('dl_repeat', function(cm, vim, helpers) {
    608   var curStart = makeCursor(0, 0);
    609   cm.setCursor(curStart);
    610   helpers.doKeys('2', 'd', 'l');
    611   eq('ord1 ', cm.getValue());
    612   var register = helpers.getRegisterController().getRegister();
    613   eq(' w', register.toString());
    614   is(!register.linewise);
    615   eqCursorPos(curStart, cm.getCursor());
    616 }, { value: ' word1 ' });
    617 testVim('dh', function(cm, vim, helpers) {
    618   var curStart = makeCursor(0, 3);
    619   cm.setCursor(curStart);
    620   helpers.doKeys('d', 'h');
    621   eq(' wrd1 ', cm.getValue());
    622   var register = helpers.getRegisterController().getRegister();
    623   eq('o', register.toString());
    624   is(!register.linewise);
    625   eqCursorPos(offsetCursor(curStart, 0 , -1), cm.getCursor());
    626 }, { value: ' word1 ' });
    627 testVim('dj', function(cm, vim, helpers) {
    628   var curStart = makeCursor(0, 3);
    629   cm.setCursor(curStart);
    630   helpers.doKeys('d', 'j');
    631   eq(' word3', cm.getValue());
    632   var register = helpers.getRegisterController().getRegister();
    633   eq(' word1\nword2\n', register.toString());
    634   is(register.linewise);
    635   helpers.assertCursorAt(0, 1);
    636 }, { value: ' word1\nword2\n word3' });
    637 testVim('dj_end_of_document', function(cm, vim, helpers) {
    638   var curStart = makeCursor(0, 3);
    639   cm.setCursor(curStart);
    640   helpers.doKeys('d', 'j');
    641   eq('', cm.getValue());
    642   var register = helpers.getRegisterController().getRegister();
    643   eq(' word1 \n', register.toString());
    644   is(register.linewise);
    645   helpers.assertCursorAt(0, 0);
    646 }, { value: ' word1 ' });
    647 testVim('dk', function(cm, vim, helpers) {
    648   var curStart = makeCursor(1, 3);
    649   cm.setCursor(curStart);
    650   helpers.doKeys('d', 'k');
    651   eq(' word3', cm.getValue());
    652   var register = helpers.getRegisterController().getRegister();
    653   eq(' word1\nword2\n', register.toString());
    654   is(register.linewise);
    655   helpers.assertCursorAt(0, 1);
    656 }, { value: ' word1\nword2\n word3' });
    657 testVim('dk_start_of_document', function(cm, vim, helpers) {
    658   var curStart = makeCursor(0, 3);
    659   cm.setCursor(curStart);
    660   helpers.doKeys('d', 'k');
    661   eq('', cm.getValue());
    662   var register = helpers.getRegisterController().getRegister();
    663   eq(' word1 \n', register.toString());
    664   is(register.linewise);
    665   helpers.assertCursorAt(0, 0);
    666 }, { value: ' word1 ' });
    667 testVim('dw_space', function(cm, vim, helpers) {
    668   var curStart = makeCursor(0, 0);
    669   cm.setCursor(curStart);
    670   helpers.doKeys('d', 'w');
    671   eq('word1 ', cm.getValue());
    672   var register = helpers.getRegisterController().getRegister();
    673   eq(' ', register.toString());
    674   is(!register.linewise);
    675   eqCursorPos(curStart, cm.getCursor());
    676 }, { value: ' word1 ' });
    677 testVim('dw_word', function(cm, vim, helpers) {
    678   var curStart = makeCursor(0, 1);
    679   cm.setCursor(curStart);
    680   helpers.doKeys('d', 'w');
    681   eq(' word2', cm.getValue());
    682   var register = helpers.getRegisterController().getRegister();
    683   eq('word1 ', register.toString());
    684   is(!register.linewise);
    685   eqCursorPos(curStart, cm.getCursor());
    686 }, { value: ' word1 word2' });
    687 testVim('dw_unicode_word', function(cm, vim, helpers) {
    688   helpers.doKeys('d', 'w');
    689   eq(cm.getValue().length, 10);
    690   helpers.doKeys('d', 'w');
    691   eq(cm.getValue().length, 6);
    692   helpers.doKeys('d', 'w');
    693   eq(cm.getValue().length, 5);
    694   helpers.doKeys('d', 'e');
    695   eq(cm.getValue().length, 2);
    696 }, { value: '  \u0562\u0561\u0580\u0587\xbbe\xb5g  ' });
    697 testVim('dw_only_word', function(cm, vim, helpers) {
    698   // Test that if there is only 1 word left, dw deletes till the end of the
    699   // line.
    700   cm.setCursor(0, 1);
    701   helpers.doKeys('d', 'w');
    702   eq(' ', cm.getValue());
    703   var register = helpers.getRegisterController().getRegister();
    704   eq('word1 ', register.toString());
    705   is(!register.linewise);
    706   helpers.assertCursorAt(0, 0);
    707 }, { value: ' word1 ' });
    708 testVim('dw_eol', function(cm, vim, helpers) {
    709   // Assert that dw does not delete the newline if last word to delete is at end
    710   // of line.
    711   cm.setCursor(0, 1);
    712   helpers.doKeys('d', 'w');
    713   eq(' \nword2', cm.getValue());
    714   var register = helpers.getRegisterController().getRegister();
    715   eq('word1', register.toString());
    716   is(!register.linewise);
    717   helpers.assertCursorAt(0, 0);
    718 }, { value: ' word1\nword2' });
    719 testVim('dw_eol_with_multiple_newlines', function(cm, vim, helpers) {
    720   // Assert that dw does not delete the newline if last word to delete is at end
    721   // of line and it is followed by multiple newlines.
    722   cm.setCursor(0, 1);
    723   helpers.doKeys('d', 'w');
    724   eq(' \n\nword2', cm.getValue());
    725   var register = helpers.getRegisterController().getRegister();
    726   eq('word1', register.toString());
    727   is(!register.linewise);
    728   helpers.assertCursorAt(0, 0);
    729 }, { value: ' word1\n\nword2' });
    730 testVim('dw_empty_line_followed_by_whitespace', function(cm, vim, helpers) {
    731   cm.setCursor(0, 0);
    732   helpers.doKeys('d', 'w');
    733   eq('  \nword', cm.getValue());
    734 }, { value: '\n  \nword' });
    735 testVim('dw_empty_line_followed_by_word', function(cm, vim, helpers) {
    736   cm.setCursor(0, 0);
    737   helpers.doKeys('d', 'w');
    738   eq('word', cm.getValue());
    739 }, { value: '\nword' });
    740 testVim('dw_empty_line_followed_by_empty_line', function(cm, vim, helpers) {
    741   cm.setCursor(0, 0);
    742   helpers.doKeys('d', 'w');
    743   eq('\n', cm.getValue());
    744 }, { value: '\n\n' });
    745 testVim('dw_whitespace_followed_by_whitespace', function(cm, vim, helpers) {
    746   cm.setCursor(0, 0);
    747   helpers.doKeys('d', 'w');
    748   eq('\n   \n', cm.getValue());
    749 }, { value: '  \n   \n' });
    750 testVim('dw_whitespace_followed_by_empty_line', function(cm, vim, helpers) {
    751   cm.setCursor(0, 0);
    752   helpers.doKeys('d', 'w');
    753   eq('\n\n', cm.getValue());
    754 }, { value: '  \n\n' });
    755 testVim('dw_word_whitespace_word', function(cm, vim, helpers) {
    756   cm.setCursor(0, 0);
    757   helpers.doKeys('d', 'w');
    758   eq('\n   \nword2', cm.getValue());
    759 }, { value: 'word1\n   \nword2'})
    760 testVim('dw_end_of_document', function(cm, vim, helpers) {
    761   cm.setCursor(1, 2);
    762   helpers.doKeys('d', 'w');
    763   eq('\nab', cm.getValue());
    764 }, { value: '\nabc' });
    765 testVim('dw_repeat', function(cm, vim, helpers) {
    766   // Assert that dw does delete newline if it should go to the next line, and
    767   // that repeat works properly.
    768   cm.setCursor(0, 1);
    769   helpers.doKeys('d', '2', 'w');
    770   eq(' ', cm.getValue());
    771   var register = helpers.getRegisterController().getRegister();
    772   eq('word1\nword2', register.toString());
    773   is(!register.linewise);
    774   helpers.assertCursorAt(0, 0);
    775 }, { value: ' word1\nword2' });
    776 testVim('de_word_start_and_empty_lines', function(cm, vim, helpers) {
    777   cm.setCursor(0, 0);
    778   helpers.doKeys('d', 'e');
    779   eq('\n\n', cm.getValue());
    780 }, { value: 'word\n\n' });
    781 testVim('de_word_end_and_empty_lines', function(cm, vim, helpers) {
    782   cm.setCursor(0, 3);
    783   helpers.doKeys('d', 'e');
    784   eq('wor', cm.getValue());
    785 }, { value: 'word\n\n\n' });
    786 testVim('de_whitespace_and_empty_lines', function(cm, vim, helpers) {
    787   cm.setCursor(0, 0);
    788   helpers.doKeys('d', 'e');
    789   eq('', cm.getValue());
    790 }, { value: '   \n\n\n' });
    791 testVim('de_end_of_document', function(cm, vim, helpers) {
    792   cm.setCursor(1, 2);
    793   helpers.doKeys('d', 'e');
    794   eq('\nab', cm.getValue());
    795 }, { value: '\nabc' });
    796 testVim('db_empty_lines', function(cm, vim, helpers) {
    797   cm.setCursor(2, 0);
    798   helpers.doKeys('d', 'b');
    799   eq('\n\n', cm.getValue());
    800 }, { value: '\n\n\n' });
    801 testVim('db_word_start_and_empty_lines', function(cm, vim, helpers) {
    802   cm.setCursor(2, 0);
    803   helpers.doKeys('d', 'b');
    804   eq('\nword', cm.getValue());
    805 }, { value: '\n\nword' });
    806 testVim('db_word_end_and_empty_lines', function(cm, vim, helpers) {
    807   cm.setCursor(2, 3);
    808   helpers.doKeys('d', 'b');
    809   eq('\n\nd', cm.getValue());
    810 }, { value: '\n\nword' });
    811 testVim('db_whitespace_and_empty_lines', function(cm, vim, helpers) {
    812   cm.setCursor(2, 0);
    813   helpers.doKeys('d', 'b');
    814   eq('', cm.getValue());
    815 }, { value: '\n   \n' });
    816 testVim('db_start_of_document', function(cm, vim, helpers) {
    817   cm.setCursor(0, 0);
    818   helpers.doKeys('d', 'b');
    819   eq('abc\n', cm.getValue());
    820 }, { value: 'abc\n' });
    821 testVim('dge_empty_lines', function(cm, vim, helpers) {
    822   cm.setCursor(1, 0);
    823   helpers.doKeys('d', 'g', 'e');
    824   // Note: In real VIM the result should be '', but it's not quite consistent,
    825   // since 2 newlines are deleted. But in the similar case of word\n\n, only
    826   // 1 newline is deleted. We'll diverge from VIM's behavior since it's much
    827   // easier this way.
    828   eq('\n', cm.getValue());
    829 }, { value: '\n\n' });
    830 testVim('dge_word_and_empty_lines', function(cm, vim, helpers) {
    831   cm.setCursor(1, 0);
    832   helpers.doKeys('d', 'g', 'e');
    833   eq('wor\n', cm.getValue());
    834 }, { value: 'word\n\n'});
    835 testVim('dge_whitespace_and_empty_lines', function(cm, vim, helpers) {
    836   cm.setCursor(2, 0);
    837   helpers.doKeys('d', 'g', 'e');
    838   eq('', cm.getValue());
    839 }, { value: '\n  \n' });
    840 testVim('dge_start_of_document', function(cm, vim, helpers) {
    841   cm.setCursor(0, 0);
    842   helpers.doKeys('d', 'g', 'e');
    843   eq('bc\n', cm.getValue());
    844 }, { value: 'abc\n' });
    845 testVim('d_inclusive', function(cm, vim, helpers) {
    846   // Assert that when inclusive is set, the character the cursor is on gets
    847   // deleted too.
    848   var curStart = makeCursor(0, 1);
    849   cm.setCursor(curStart);
    850   helpers.doKeys('d', 'e');
    851   eq('  ', cm.getValue());
    852   var register = helpers.getRegisterController().getRegister();
    853   eq('word1', register.toString());
    854   is(!register.linewise);
    855   eqCursorPos(curStart, cm.getCursor());
    856 }, { value: ' word1 ' });
    857 testVim('d_reverse', function(cm, vim, helpers) {
    858   // Test that deleting in reverse works.
    859   cm.setCursor(1, 0);
    860   helpers.doKeys('d', 'b');
    861   eq(' word2 ', cm.getValue());
    862   var register = helpers.getRegisterController().getRegister();
    863   eq('word1\n', register.toString());
    864   is(!register.linewise);
    865   helpers.assertCursorAt(0, 1);
    866 }, { value: ' word1\nword2 ' });
    867 testVim('dd', function(cm, vim, helpers) {
    868   cm.setCursor(0, 3);
    869   var expectedBuffer = cm.getRange(new Pos(0, 0),
    870     new Pos(1, 0));
    871   var expectedLineCount = cm.lineCount() - 1;
    872   helpers.doKeys('d', 'd');
    873   eq(expectedLineCount, cm.lineCount());
    874   var register = helpers.getRegisterController().getRegister();
    875   eq(expectedBuffer, register.toString());
    876   is(register.linewise);
    877   helpers.assertCursorAt(0, lines[1].textStart);
    878 });
    879 testVim('dd_prefix_repeat', function(cm, vim, helpers) {
    880   cm.setCursor(0, 3);
    881   var expectedBuffer = cm.getRange(new Pos(0, 0),
    882     new Pos(2, 0));
    883   var expectedLineCount = cm.lineCount() - 2;
    884   helpers.doKeys('2', 'd', 'd');
    885   eq(expectedLineCount, cm.lineCount());
    886   var register = helpers.getRegisterController().getRegister();
    887   eq(expectedBuffer, register.toString());
    888   is(register.linewise);
    889   helpers.assertCursorAt(0, lines[2].textStart);
    890 });
    891 testVim('dd_motion_repeat', function(cm, vim, helpers) {
    892   cm.setCursor(0, 3);
    893   var expectedBuffer = cm.getRange(new Pos(0, 0),
    894     new Pos(2, 0));
    895   var expectedLineCount = cm.lineCount() - 2;
    896   helpers.doKeys('d', '2', 'd');
    897   eq(expectedLineCount, cm.lineCount());
    898   var register = helpers.getRegisterController().getRegister();
    899   eq(expectedBuffer, register.toString());
    900   is(register.linewise);
    901   helpers.assertCursorAt(0, lines[2].textStart);
    902 });
    903 testVim('dd_multiply_repeat', function(cm, vim, helpers) {
    904   cm.setCursor(0, 3);
    905   var expectedBuffer = cm.getRange(new Pos(0, 0),
    906     new Pos(6, 0));
    907   var expectedLineCount = cm.lineCount() - 6;
    908   helpers.doKeys('2', 'd', '3', 'd');
    909   eq(expectedLineCount, cm.lineCount());
    910   var register = helpers.getRegisterController().getRegister();
    911   eq(expectedBuffer, register.toString());
    912   is(register.linewise);
    913   helpers.assertCursorAt(0, lines[6].textStart);
    914 });
    915 testVim('dd_lastline', function(cm, vim, helpers) {
    916   cm.setCursor(cm.lineCount(), 0);
    917   var expectedLineCount = cm.lineCount() - 1;
    918   helpers.doKeys('d', 'd');
    919   eq(expectedLineCount, cm.lineCount());
    920   helpers.assertCursorAt(cm.lineCount() - 1, 0);
    921 });
    922 testVim('dd_only_line', function(cm, vim, helpers) {
    923   cm.setCursor(0, 0);
    924   var expectedRegister = cm.getValue() + "\n";
    925   helpers.doKeys('d','d');
    926   eq(1, cm.lineCount());
    927   eq('', cm.getValue());
    928   var register = helpers.getRegisterController().getRegister();
    929   eq(expectedRegister, register.toString());
    930 }, { value: "thisistheonlyline" });
    931 // Yank commands should behave the exact same as d commands, expect that nothing
    932 // gets deleted.
    933 testVim('yw_repeat', function(cm, vim, helpers) {
    934   // Assert that yw does yank newline if it should go to the next line, and
    935   // that repeat works properly.
    936   var curStart = makeCursor(0, 1);
    937   cm.setCursor(curStart);
    938   helpers.doKeys('y', '2', 'w');
    939   eq(' word1\nword2', cm.getValue());
    940   var register = helpers.getRegisterController().getRegister();
    941   eq('word1\nword2', register.toString());
    942   is(!register.linewise);
    943   eqCursorPos(curStart, cm.getCursor());
    944 }, { value: ' word1\nword2' });
    945 testVim('yy_multiply_repeat', function(cm, vim, helpers) {
    946   var curStart = makeCursor(0, 3);
    947   cm.setCursor(curStart);
    948   var expectedBuffer = cm.getRange(new Pos(0, 0),
    949     new Pos(6, 0));
    950   var expectedLineCount = cm.lineCount();
    951   helpers.doKeys('2', 'y', '3', 'y');
    952   eq(expectedLineCount, cm.lineCount());
    953   var register = helpers.getRegisterController().getRegister();
    954   eq(expectedBuffer, register.toString());
    955   is(register.linewise);
    956   eqCursorPos(curStart, cm.getCursor());
    957 });
    958 testVim('2dd_blank_P', function(cm, vim, helpers) {
    959   helpers.doKeys('2', 'd', 'd', 'P');
    960   eq('\na\n\n', cm.getValue());
    961 }, { value: '\na\n\n' });
    962 // Change commands behave like d commands except that it also enters insert
    963 // mode. In addition, when the change is linewise, an additional newline is
    964 // inserted so that insert mode starts on that line.
    965 testVim('cw', function(cm, vim, helpers) {
    966   cm.setCursor(0, 0);
    967   helpers.doKeys('c', '2', 'w');
    968   eq(' word3', cm.getValue());
    969   helpers.assertCursorAt(0, 0);
    970 }, { value: 'word1 word2 word3'});
    971 testVim('cw_repeat', function(cm, vim, helpers) {
    972   // Assert that cw does delete newline if it should go to the next line, and
    973   // that repeat works properly.
    974   var curStart = makeCursor(0, 1);
    975   cm.setCursor(curStart);
    976   helpers.doKeys('c', '2', 'w');
    977   eq(' ', cm.getValue());
    978   var register = helpers.getRegisterController().getRegister();
    979   eq('word1\nword2', register.toString());
    980   is(!register.linewise);
    981   eqCursorPos(curStart, cm.getCursor());
    982   eq('vim-insert', cm.getOption('keyMap'));
    983 }, { value: ' word1\nword2' });
    984 testVim('cc_multiply_repeat', function(cm, vim, helpers) {
    985   cm.setCursor(0, 3);
    986   var expectedBuffer = cm.getRange(new Pos(0, 0),
    987     new Pos(6, 0));
    988   var expectedLineCount = cm.lineCount() - 5;
    989   helpers.doKeys('2', 'c', '3', 'c');
    990   eq(expectedLineCount, cm.lineCount());
    991   var register = helpers.getRegisterController().getRegister();
    992   eq(expectedBuffer, register.toString());
    993   is(register.linewise);
    994   eq('vim-insert', cm.getOption('keyMap'));
    995 });
    996 testVim('ct', function(cm, vim, helpers) {
    997   cm.setCursor(0, 9);
    998   helpers.doKeys('c', 't', 'w');
    999   eq('  word1  word3', cm.getValue());
   1000   helpers.doKeys('<Esc>', 'c', '|');
   1001   eq(' word3', cm.getValue());
   1002   helpers.assertCursorAt(0, 0);
   1003   helpers.doKeys('<Esc>', '2', 'u', 'w', 'h');
   1004   helpers.doKeys('c', '2', 'g', 'e');
   1005   eq('  wordword3', cm.getValue());
   1006 }, { value: '  word1  word2  word3'});
   1007 testVim('cc_should_not_append_to_document', function(cm, vim, helpers) {
   1008   var expectedLineCount = cm.lineCount();
   1009   cm.setCursor(cm.lastLine(), 0);
   1010   helpers.doKeys('c', 'c');
   1011   eq(expectedLineCount, cm.lineCount());
   1012 });
   1013 function fillArray(val, times) {
   1014   var arr = [];
   1015   for (var i = 0; i < times; i++) {
   1016     arr.push(val);
   1017   }
   1018   return arr;
   1019 }
   1020 testVim('c_visual_block', function(cm, vim, helpers) {
   1021   cm.setCursor(0, 1);
   1022   helpers.doKeys('<C-v>', '2', 'j', 'l', 'l', 'l', 'c');
   1023   var replacement = fillArray('hello', 3);
   1024   cm.replaceSelections(replacement);
   1025   eq('1hello\n5hello\nahellofg', cm.getValue());
   1026   helpers.doKeys('<Esc>');
   1027   cm.setCursor(2, 3);
   1028   helpers.doKeys('<C-v>', '2', 'k', 'h', 'C');
   1029   replacement = fillArray('world', 3);
   1030   cm.replaceSelections(replacement);
   1031   eq('1hworld\n5hworld\nahworld', cm.getValue());
   1032 }, {value: '1234\n5678\nabcdefg'});
   1033 testVim('c_visual_block_replay', function(cm, vim, helpers) {
   1034   cm.setCursor(0, 1);
   1035   helpers.doKeys('<C-v>', '2', 'j', 'l', 'c');
   1036   var replacement = fillArray('fo', 3);
   1037   cm.replaceSelections(replacement);
   1038   eq('1fo4\n5fo8\nafodefg', cm.getValue());
   1039   helpers.doKeys('<Esc>');
   1040   cm.setCursor(0, 0);
   1041   helpers.doKeys('.');
   1042   eq('foo4\nfoo8\nfoodefg', cm.getValue());
   1043 }, {value: '1234\n5678\nabcdefg'});
   1044 
   1045 testVim('d_visual_block', function(cm, vim, helpers) {
   1046   cm.setCursor(0, 1);
   1047   helpers.doKeys('<C-v>', '2', 'j', 'l', 'l', 'l', 'd');
   1048   eq('1\n5\nafg', cm.getValue());
   1049 }, {value: '1234\n5678\nabcdefg'});
   1050 testVim('D_visual_block', function(cm, vim, helpers) {
   1051   cm.setCursor(0, 1);
   1052   helpers.doKeys('<C-v>', '2', 'j', 'l', 'D');
   1053   eq('1\n5\na', cm.getValue());
   1054 }, {value: '1234\n5678\nabcdefg'});
   1055 
   1056 testVim('s_visual_block', function(cm, vim, helpers) {
   1057   cm.setCursor(0, 1);
   1058   helpers.doKeys('<C-v>', '2', 'j', 'l', 'l', 'l', 's');
   1059   var replacement = fillArray('hello{', 3);
   1060   cm.replaceSelections(replacement);
   1061   eq('1hello{\n5hello{\nahello{fg\n', cm.getValue());
   1062   helpers.doKeys('<Esc>');
   1063   cm.setCursor(2, 3);
   1064   helpers.doKeys('<C-v>', '1', 'k', 'h', 'S');
   1065   replacement = fillArray('world', 1);
   1066   cm.replaceSelections(replacement);
   1067   eq('1hello{\n  world\n', cm.getValue());
   1068 }, {value: '1234\n5678\nabcdefg\n'});
   1069 
   1070 // Swapcase commands edit in place and do not modify registers.
   1071 testVim('g~w_repeat', function(cm, vim, helpers) {
   1072   // Assert that dw does delete newline if it should go to the next line, and
   1073   // that repeat works properly.
   1074   var curStart = makeCursor(0, 1);
   1075   cm.setCursor(curStart);
   1076   helpers.doKeys('g', '~', '2', 'w');
   1077   eq(' WORD1\nWORD2', cm.getValue());
   1078   var register = helpers.getRegisterController().getRegister();
   1079   eq('', register.toString());
   1080   is(!register.linewise);
   1081   eqCursorPos(curStart, cm.getCursor());
   1082 }, { value: ' word1\nword2' });
   1083 testVim('g~g~', function(cm, vim, helpers) {
   1084   var curStart = makeCursor(0, 3);
   1085   cm.setCursor(curStart);
   1086   var expectedLineCount = cm.lineCount();
   1087   var expectedValue = cm.getValue().toUpperCase();
   1088   helpers.doKeys('2', 'g', '~', '3', 'g', '~');
   1089   eq(expectedValue, cm.getValue());
   1090   var register = helpers.getRegisterController().getRegister();
   1091   eq('', register.toString());
   1092   is(!register.linewise);
   1093   eqCursorPos(curStart, cm.getCursor());
   1094 }, { value: ' word1\nword2\nword3\nword4\nword5\nword6' });
   1095 testVim('gu_and_gU', function(cm, vim, helpers) {
   1096   var curStart = makeCursor(0, 7);
   1097   var value = cm.getValue();
   1098   cm.setCursor(curStart);
   1099   helpers.doKeys('2', 'g', 'U', 'w');
   1100   eq(cm.getValue(), 'wa wb xX WC wd');
   1101   eqCursorPos(curStart, cm.getCursor());
   1102   helpers.doKeys('2', 'g', 'u', 'w');
   1103   eq(cm.getValue(), value);
   1104 
   1105   helpers.doKeys('2', 'g', 'U', 'B');
   1106   eq(cm.getValue(), 'wa WB Xx wc wd');
   1107   eqCursorPos(makeCursor(0, 3), cm.getCursor());
   1108 
   1109   cm.setCursor(makeCursor(0, 4));
   1110   helpers.doKeys('g', 'u', 'i', 'w');
   1111   eq(cm.getValue(), 'wa wb Xx wc wd');
   1112   eqCursorPos(makeCursor(0, 3), cm.getCursor());
   1113 
   1114   // TODO: support gUgU guu
   1115   // eqCursorPos(makeCursor(0, 0), cm.getCursor());
   1116 
   1117   var register = helpers.getRegisterController().getRegister();
   1118   eq('', register.toString());
   1119   is(!register.linewise);
   1120 }, { value: 'wa wb xx wc wd' });
   1121 testVim('visual_block_~', function(cm, vim, helpers) {
   1122   cm.setCursor(1, 1);
   1123   helpers.doKeys('<C-v>', 'l', 'l', 'j', '~');
   1124   helpers.assertCursorAt(1, 1);
   1125   eq('hello\nwoRLd\naBCDe', cm.getValue());
   1126   cm.setCursor(2, 0);
   1127   helpers.doKeys('v', 'l', 'l', '~');
   1128   helpers.assertCursorAt(2, 0);
   1129   eq('hello\nwoRLd\nAbcDe', cm.getValue());
   1130 },{value: 'hello\nwOrld\nabcde' });
   1131 testVim('._swapCase_visualBlock', function(cm, vim, helpers) {
   1132   helpers.doKeys('<C-v>', 'j', 'j', 'l', '~');
   1133   cm.setCursor(0, 3);
   1134   helpers.doKeys('.');
   1135   eq('HelLO\nWorLd\nAbcdE', cm.getValue());
   1136 },{value: 'hEllo\nwOrlD\naBcDe' });
   1137 testVim('._delete_visualBlock', function(cm, vim, helpers) {
   1138   helpers.doKeys('<C-v>', 'j', 'x');
   1139   eq('ive\ne\nsome\nsugar', cm.getValue());
   1140   helpers.doKeys('.');
   1141   eq('ve\n\nsome\nsugar', cm.getValue());
   1142   helpers.doKeys('j', 'j', '.');
   1143   eq('ve\n\nome\nugar', cm.getValue());
   1144   helpers.doKeys('u', '<C-r>', '.');
   1145   eq('ve\n\nme\ngar', cm.getValue());
   1146 },{value: 'give\nme\nsome\nsugar' });
   1147 testVim('>{motion}', function(cm, vim, helpers) {
   1148   cm.setCursor(1, 3);
   1149   var expectedLineCount = cm.lineCount();
   1150   var expectedValue = '   word1\n  word2\nword3 ';
   1151   helpers.doKeys('>', 'k');
   1152   eq(expectedValue, cm.getValue());
   1153   var register = helpers.getRegisterController().getRegister();
   1154   eq('', register.toString());
   1155   is(!register.linewise);
   1156   helpers.assertCursorAt(0, 3);
   1157 }, { value: ' word1\nword2\nword3 ', indentUnit: 2 });
   1158 testVim('>>', function(cm, vim, helpers) {
   1159   cm.setCursor(0, 3);
   1160   var expectedLineCount = cm.lineCount();
   1161   var expectedValue = '   word1\n  word2\nword3 ';
   1162   helpers.doKeys('2', '>', '>');
   1163   eq(expectedValue, cm.getValue());
   1164   var register = helpers.getRegisterController().getRegister();
   1165   eq('', register.toString());
   1166   is(!register.linewise);
   1167   helpers.assertCursorAt(0, 3);
   1168 }, { value: ' word1\nword2\nword3 ', indentUnit: 2 });
   1169 testVim('<{motion}', function(cm, vim, helpers) {
   1170   cm.setCursor(1, 3);
   1171   var expectedLineCount = cm.lineCount();
   1172   var expectedValue = ' word1\nword2\nword3 ';
   1173   helpers.doKeys('<', 'k');
   1174   eq(expectedValue, cm.getValue());
   1175   var register = helpers.getRegisterController().getRegister();
   1176   eq('', register.toString());
   1177   is(!register.linewise);
   1178   helpers.assertCursorAt(0, 1);
   1179 }, { value: '   word1\n  word2\nword3 ', indentUnit: 2 });
   1180 testVim('<<', function(cm, vim, helpers) {
   1181   cm.setCursor(0, 3);
   1182   var expectedLineCount = cm.lineCount();
   1183   var expectedValue = ' word1\nword2\nword3 ';
   1184   helpers.doKeys('2', '<', '<');
   1185   eq(expectedValue, cm.getValue());
   1186   var register = helpers.getRegisterController().getRegister();
   1187   eq('', register.toString());
   1188   is(!register.linewise);
   1189   helpers.assertCursorAt(0, 1);
   1190 }, { value: '   word1\n  word2\nword3 ', indentUnit: 2 });
   1191 
   1192 // Edit tests
   1193 function testEdit(name, before, pos, edit, after) {
   1194   return testVim(name, function(cm, vim, helpers) {
   1195              var ch = before.search(pos)
   1196              var line = before.substring(0, ch).split('\n').length - 1;
   1197              if (line) {
   1198                ch = before.substring(0, ch).split('\n').pop().length;
   1199              }
   1200              cm.setCursor(line, ch);
   1201              helpers.doKeys.apply(this, edit.split(''));
   1202              eq(after, cm.getValue());
   1203            }, {value: before});
   1204 }
   1205 
   1206 // These Delete tests effectively cover word-wise Change, Visual & Yank.
   1207 // Tabs are used as differentiated whitespace to catch edge cases.
   1208 // Normal word:
   1209 testEdit('diw_mid_spc', 'foo \tbAr\t baz', /A/, 'diw', 'foo \t\t baz');
   1210 testEdit('daw_mid_spc', 'foo \tbAr\t baz', /A/, 'daw', 'foo \tbaz');
   1211 testEdit('diw_mid_punct', 'foo \tbAr.\t baz', /A/, 'diw', 'foo \t.\t baz');
   1212 testEdit('daw_mid_punct', 'foo \tbAr.\t baz', /A/, 'daw', 'foo.\t baz');
   1213 testEdit('diw_mid_punct2', 'foo \t,bAr.\t baz', /A/, 'diw', 'foo \t,.\t baz');
   1214 testEdit('daw_mid_punct2', 'foo \t,bAr.\t baz', /A/, 'daw', 'foo \t,.\t baz');
   1215 testEdit('diw_start_spc', 'bAr \tbaz', /A/, 'diw', ' \tbaz');
   1216 testEdit('daw_start_spc', 'bAr \tbaz', /A/, 'daw', 'baz');
   1217 testEdit('diw_start_punct', 'bAr. \tbaz', /A/, 'diw', '. \tbaz');
   1218 testEdit('daw_start_punct', 'bAr. \tbaz', /A/, 'daw', '. \tbaz');
   1219 testEdit('diw_end_spc', 'foo \tbAr', /A/, 'diw', 'foo \t');
   1220 testEdit('daw_end_spc', 'foo \tbAr', /A/, 'daw', 'foo');
   1221 testEdit('diw_end_punct', 'foo \tbAr.', /A/, 'diw', 'foo \t.');
   1222 testEdit('daw_end_punct', 'foo \tbAr.', /A/, 'daw', 'foo.');
   1223 // Big word:
   1224 testEdit('diW_mid_spc', 'foo \tbAr\t baz', /A/, 'diW', 'foo \t\t baz');
   1225 testEdit('daW_mid_spc', 'foo \tbAr\t baz', /A/, 'daW', 'foo \tbaz');
   1226 testEdit('diW_mid_punct', 'foo \tbAr.\t baz', /A/, 'diW', 'foo \t\t baz');
   1227 testEdit('daW_mid_punct', 'foo \tbAr.\t baz', /A/, 'daW', 'foo \tbaz');
   1228 testEdit('diW_mid_punct2', 'foo \t,bAr.\t baz', /A/, 'diW', 'foo \t\t baz');
   1229 testEdit('daW_mid_punct2', 'foo \t,bAr.\t baz', /A/, 'daW', 'foo \tbaz');
   1230 testEdit('diW_start_spc', 'bAr\t baz', /A/, 'diW', '\t baz');
   1231 testEdit('daW_start_spc', 'bAr\t baz', /A/, 'daW', 'baz');
   1232 testEdit('diW_start_punct', 'bAr.\t baz', /A/, 'diW', '\t baz');
   1233 testEdit('daW_start_punct', 'bAr.\t baz', /A/, 'daW', 'baz');
   1234 testEdit('diW_end_spc', 'foo \tbAr', /A/, 'diW', 'foo \t');
   1235 testEdit('daW_end_spc', 'foo \tbAr', /A/, 'daW', 'foo');
   1236 testEdit('diW_end_punct', 'foo \tbAr.', /A/, 'diW', 'foo \t');
   1237 testEdit('daW_end_punct', 'foo \tbAr.', /A/, 'daW', 'foo');
   1238 // Deleting text objects
   1239 //    Open and close on same line
   1240 testEdit('di(_open_spc', 'foo (bAr) baz', /\(/, 'di(', 'foo () baz');
   1241 testEdit('di)_open_spc', 'foo (bAr) baz', /\(/, 'di)', 'foo () baz');
   1242 testEdit('dib_open_spc', 'foo (bAr) baz', /\(/, 'dib', 'foo () baz');
   1243 testEdit('da(_open_spc', 'foo (bAr) baz', /\(/, 'da(', 'foo  baz');
   1244 testEdit('da)_open_spc', 'foo (bAr) baz', /\(/, 'da)', 'foo  baz');
   1245 
   1246 testEdit('di(_middle_spc', 'foo (bAr) baz', /A/, 'di(', 'foo () baz');
   1247 testEdit('di)_middle_spc', 'foo (bAr) baz', /A/, 'di)', 'foo () baz');
   1248 testEdit('da(_middle_spc', 'foo (bAr) baz', /A/, 'da(', 'foo  baz');
   1249 testEdit('da)_middle_spc', 'foo (bAr) baz', /A/, 'da)', 'foo  baz');
   1250 
   1251 testEdit('di(_close_spc', 'foo (bAr) baz', /\)/, 'di(', 'foo () baz');
   1252 testEdit('di)_close_spc', 'foo (bAr) baz', /\)/, 'di)', 'foo () baz');
   1253 testEdit('da(_close_spc', 'foo (bAr) baz', /\)/, 'da(', 'foo  baz');
   1254 testEdit('da)_close_spc', 'foo (bAr) baz', /\)/, 'da)', 'foo  baz');
   1255 
   1256 //  delete around and inner b.
   1257 testEdit('dab_on_(_should_delete_around_()block', 'o( in(abc) )', /\(a/, 'dab', 'o( in )');
   1258 
   1259 //  delete around and inner B.
   1260 testEdit('daB_on_{_should_delete_around_{}block', 'o{ in{abc} }', /{a/, 'daB', 'o{ in }');
   1261 testEdit('diB_on_{_should_delete_inner_{}block', 'o{ in{abc} }', /{a/, 'diB', 'o{ in{} }');
   1262 
   1263 testEdit('da{_on_{_should_delete_inner_block', 'o{ in{abc} }', /{a/, 'da{', 'o{ in }');
   1264 testEdit('di[_on_(_should_not_delete', 'foo (bAr) baz', /\(/, 'di[', 'foo (bAr) baz');
   1265 testEdit('di[_on_)_should_not_delete', 'foo (bAr) baz', /\)/, 'di[', 'foo (bAr) baz');
   1266 testEdit('da[_on_(_should_not_delete', 'foo (bAr) baz', /\(/, 'da[', 'foo (bAr) baz');
   1267 testEdit('da[_on_)_should_not_delete', 'foo (bAr) baz', /\)/, 'da[', 'foo (bAr) baz');
   1268 testMotion('di(_outside_should_stay', ['d', 'i', '('], new Pos(0, 0), new Pos(0, 0));
   1269 
   1270 //  Open and close on different lines, equally indented
   1271 testEdit('di{_middle_spc', 'a{\n\tbar\n}b', /r/, 'di{', 'a{}b');
   1272 testEdit('di}_middle_spc', 'a{\n\tbar\n}b', /r/, 'di}', 'a{}b');
   1273 testEdit('da{_middle_spc', 'a{\n\tbar\n}b', /r/, 'da{', 'ab');
   1274 testEdit('da}_middle_spc', 'a{\n\tbar\n}b', /r/, 'da}', 'ab');
   1275 testEdit('daB_middle_spc', 'a{\n\tbar\n}b', /r/, 'daB', 'ab');
   1276 
   1277 // open and close on diff lines, open indented less than close
   1278 testEdit('di{_middle_spc', 'a{\n\tbar\n\t}b', /r/, 'di{', 'a{}b');
   1279 testEdit('di}_middle_spc', 'a{\n\tbar\n\t}b', /r/, 'di}', 'a{}b');
   1280 testEdit('da{_middle_spc', 'a{\n\tbar\n\t}b', /r/, 'da{', 'ab');
   1281 testEdit('da}_middle_spc', 'a{\n\tbar\n\t}b', /r/, 'da}', 'ab');
   1282 
   1283 // open and close on diff lines, open indented more than close
   1284 testEdit('di[_middle_spc', 'a\t[\n\tbar\n]b', /r/, 'di[', 'a\t[]b');
   1285 testEdit('di]_middle_spc', 'a\t[\n\tbar\n]b', /r/, 'di]', 'a\t[]b');
   1286 testEdit('da[_middle_spc', 'a\t[\n\tbar\n]b', /r/, 'da[', 'a\tb');
   1287 testEdit('da]_middle_spc', 'a\t[\n\tbar\n]b', /r/, 'da]', 'a\tb');
   1288 
   1289 function testSelection(name, before, pos, keys, sel) {
   1290   return testVim(name, function(cm, vim, helpers) {
   1291              var ch = before.search(pos)
   1292              var line = before.substring(0, ch).split('\n').length - 1;
   1293              if (line) {
   1294                ch = before.substring(0, ch).split('\n').pop().length;
   1295              }
   1296              cm.setCursor(line, ch);
   1297              helpers.doKeys.apply(this, keys.split(''));
   1298              eq(sel, cm.getSelection());
   1299            }, {value: before});
   1300 }
   1301 testSelection('viw_middle_spc', 'foo \tbAr\t baz', /A/, 'viw', 'bAr');
   1302 testSelection('vaw_middle_spc', 'foo \tbAr\t baz', /A/, 'vaw', 'bAr\t ');
   1303 testSelection('viw_middle_punct', 'foo \tbAr,\t baz', /A/, 'viw', 'bAr');
   1304 testSelection('vaW_middle_punct', 'foo \tbAr,\t baz', /A/, 'vaW', 'bAr,\t ');
   1305 testSelection('viw_start_spc', 'foo \tbAr\t baz', /b/, 'viw', 'bAr');
   1306 testSelection('viw_end_spc', 'foo \tbAr\t baz', /r/, 'viw', 'bAr');
   1307 testSelection('viw_eol', 'foo \tbAr', /r/, 'viw', 'bAr');
   1308 testSelection('vi{_middle_spc', 'a{\n\tbar\n\t}b', /r/, 'vi{', '\n\tbar\n\t');
   1309 testSelection('va{_middle_spc', 'a{\n\tbar\n\t}b', /r/, 'va{', '{\n\tbar\n\t}');
   1310 
   1311 testVim('mouse_select', function(cm, vim, helpers) {
   1312   cm.setSelection(Pos(0, 2), Pos(0, 4), {origin: '*mouse'});
   1313   is(cm.state.vim.visualMode);
   1314   is(!cm.state.vim.visualLine);
   1315   is(!cm.state.vim.visualBlock);
   1316   helpers.doKeys('<Esc>');
   1317   is(!cm.somethingSelected());
   1318   helpers.doKeys('g', 'v');
   1319   eq('cd', cm.getSelection());
   1320 }, {value: 'abcdef'});
   1321 
   1322 // Operator-motion tests
   1323 testVim('D', function(cm, vim, helpers) {
   1324   cm.setCursor(0, 3);
   1325   helpers.doKeys('D');
   1326   eq(' wo\nword2\n word3', cm.getValue());
   1327   var register = helpers.getRegisterController().getRegister();
   1328   eq('rd1', register.toString());
   1329   is(!register.linewise);
   1330   helpers.assertCursorAt(0, 2);
   1331 }, { value: ' word1\nword2\n word3' });
   1332 testVim('C', function(cm, vim, helpers) {
   1333   var curStart = makeCursor(0, 3);
   1334   cm.setCursor(curStart);
   1335   helpers.doKeys('C');
   1336   eq(' wo\nword2\n word3', cm.getValue());
   1337   var register = helpers.getRegisterController().getRegister();
   1338   eq('rd1', register.toString());
   1339   is(!register.linewise);
   1340   eqCursorPos(curStart, cm.getCursor());
   1341   eq('vim-insert', cm.getOption('keyMap'));
   1342 }, { value: ' word1\nword2\n word3' });
   1343 testVim('Y', function(cm, vim, helpers) {
   1344   var curStart = makeCursor(0, 3);
   1345   cm.setCursor(curStart);
   1346   helpers.doKeys('Y');
   1347   eq(' word1\nword2\n word3', cm.getValue());
   1348   var register = helpers.getRegisterController().getRegister();
   1349   eq(' word1\n', register.toString());
   1350   is(register.linewise);
   1351   helpers.assertCursorAt(0, 3);
   1352 }, { value: ' word1\nword2\n word3' });
   1353 testVim('~', function(cm, vim, helpers) {
   1354   helpers.doKeys('3', '~');
   1355   eq('ABCdefg', cm.getValue());
   1356   helpers.assertCursorAt(0, 3);
   1357 }, { value: 'abcdefg' });
   1358 
   1359 // Action tests
   1360 testVim('ctrl-a', function(cm, vim, helpers) {
   1361   cm.setCursor(0, 0);
   1362   helpers.doKeys('<C-a>');
   1363   eq('-9', cm.getValue());
   1364   helpers.assertCursorAt(0, 1);
   1365   helpers.doKeys('2','<C-a>');
   1366   eq('-7', cm.getValue());
   1367 }, {value: '-10'});
   1368 testVim('ctrl-x', function(cm, vim, helpers) {
   1369   cm.setCursor(0, 0);
   1370   helpers.doKeys('<C-x>');
   1371   eq('-1', cm.getValue());
   1372   helpers.assertCursorAt(0, 1);
   1373   helpers.doKeys('2','<C-x>');
   1374   eq('-3', cm.getValue());
   1375 }, {value: '0'});
   1376 testVim('<C-x>/<C-a> search forward', function(cm, vim, helpers) {
   1377   forEach(['<C-x>', '<C-a>'], function(key) {
   1378     cm.setCursor(0, 0);
   1379     helpers.doKeys(key);
   1380     helpers.assertCursorAt(0, 5);
   1381     helpers.doKeys('l');
   1382     helpers.doKeys(key);
   1383     helpers.assertCursorAt(0, 10);
   1384     cm.setCursor(0, 11);
   1385     helpers.doKeys(key);
   1386     helpers.assertCursorAt(0, 11);
   1387   });
   1388 }, {value: '__jmp1 jmp2 jmp'});
   1389 testVim('insert_ctrl_w', function(cm, vim, helpers) {
   1390   var curStart = makeCursor(0, 10);
   1391   cm.setCursor(curStart);
   1392   helpers.doKeys('a');
   1393   helpers.doKeys('<C-w>');
   1394   eq('word1/', cm.getValue());
   1395   var register = helpers.getRegisterController().getRegister();
   1396   eq('word2', register.toString());
   1397   is(!register.linewise);
   1398   var curEnd = makeCursor(0, 6);
   1399   eqCursorPos(curEnd, cm.getCursor());
   1400   eq('vim-insert', cm.getOption('keyMap'));
   1401 }, { value: 'word1/word2' });
   1402 testVim('a', function(cm, vim, helpers) {
   1403   cm.setCursor(0, 1);
   1404   helpers.doKeys('a');
   1405   helpers.assertCursorAt(0, 2);
   1406   eq('vim-insert', cm.getOption('keyMap'));
   1407 });
   1408 testVim('a_eol', function(cm, vim, helpers) {
   1409   cm.setCursor(0, lines[0].length - 1);
   1410   helpers.doKeys('a');
   1411   helpers.assertCursorAt(0, lines[0].length);
   1412   eq('vim-insert', cm.getOption('keyMap'));
   1413 });
   1414 testVim('A_endOfSelectedArea', function(cm, vim, helpers) {
   1415   cm.setCursor(0, 0);
   1416   helpers.doKeys('v', 'j', 'l');
   1417   helpers.doKeys('A');
   1418   helpers.assertCursorAt(1, 2);
   1419   eq('vim-insert', cm.getOption('keyMap'));
   1420 }, {value: 'foo\nbar'});
   1421 testVim('i', function(cm, vim, helpers) {
   1422   cm.setCursor(0, 1);
   1423   helpers.doKeys('i');
   1424   helpers.assertCursorAt(0, 1);
   1425   eq('vim-insert', cm.getOption('keyMap'));
   1426 });
   1427 testVim('i_repeat', function(cm, vim, helpers) {
   1428   helpers.doKeys('3', 'i');
   1429   cm.replaceRange('test', cm.getCursor());
   1430   helpers.doKeys('<Esc>');
   1431   eq('testtesttest', cm.getValue());
   1432   helpers.assertCursorAt(0, 11);
   1433 }, { value: '' });
   1434 testVim('i_repeat_delete', function(cm, vim, helpers) {
   1435   cm.setCursor(0, 4);
   1436   helpers.doKeys('2', 'i');
   1437   cm.replaceRange('z', cm.getCursor());
   1438   helpers.doInsertModeKeys('Backspace', 'Backspace');
   1439   helpers.doKeys('<Esc>');
   1440   eq('abe', cm.getValue());
   1441   helpers.assertCursorAt(0, 1);
   1442 }, { value: 'abcde' });
   1443 testVim('insert', function(cm, vim, helpers) {
   1444   helpers.doKeys('i');
   1445   eq('vim-insert', cm.getOption('keyMap'));
   1446   eq(false, cm.state.overwrite);
   1447   helpers.doKeys('<Ins>');
   1448   eq('vim-replace', cm.getOption('keyMap'));
   1449   eq(true, cm.state.overwrite);
   1450   helpers.doKeys('<Ins>');
   1451   eq('vim-insert', cm.getOption('keyMap'));
   1452   eq(false, cm.state.overwrite);
   1453 });
   1454 testVim('i_backspace', function(cm, vim, helpers) {
   1455   cm.setCursor(0, 10);
   1456   helpers.doKeys('i');
   1457   helpers.doInsertModeKeys('Backspace');
   1458   helpers.assertCursorAt(0, 9);
   1459   eq('012345678', cm.getValue());
   1460 }, { value: '0123456789'});
   1461 testVim('i_overwrite_backspace', function(cm, vim, helpers) {
   1462   cm.setCursor(0, 10);
   1463   helpers.doKeys('i');
   1464   helpers.doKeys('<Ins>');
   1465   helpers.doInsertModeKeys('Backspace');
   1466   helpers.assertCursorAt(Pos(0, 9, "after"));
   1467   eq('0123456789', cm.getValue());
   1468 }, { value: '0123456789'});
   1469 testVim('A', function(cm, vim, helpers) {
   1470   helpers.doKeys('A');
   1471   helpers.assertCursorAt(0, lines[0].length);
   1472   eq('vim-insert', cm.getOption('keyMap'));
   1473 });
   1474 testVim('A_visual_block', function(cm, vim, helpers) {
   1475   cm.setCursor(0, 1);
   1476   helpers.doKeys('<C-v>', '2', 'j', 'l', 'l', 'A');
   1477   var replacement = new Array(cm.listSelections().length+1).join('hello ').split(' ');
   1478   replacement.pop();
   1479   cm.replaceSelections(replacement);
   1480   eq('testhello\nmehello\npleahellose', cm.getValue());
   1481   helpers.doKeys('<Esc>');
   1482   cm.setCursor(0, 0);
   1483   helpers.doKeys('.');
   1484   // TODO this doesn't work yet
   1485   // eq('teshellothello\nme hello hello\nplehelloahellose', cm.getValue());
   1486 }, {value: 'test\nme\nplease'});
   1487 testVim('I', function(cm, vim, helpers) {
   1488   cm.setCursor(0, 4);
   1489   helpers.doKeys('I');
   1490   helpers.assertCursorAt(0, lines[0].textStart);
   1491   eq('vim-insert', cm.getOption('keyMap'));
   1492 });
   1493 testVim('I_repeat', function(cm, vim, helpers) {
   1494   cm.setCursor(0, 1);
   1495   helpers.doKeys('3', 'I');
   1496   cm.replaceRange('test', cm.getCursor());
   1497   helpers.doKeys('<Esc>');
   1498   eq('testtesttestblah', cm.getValue());
   1499   helpers.assertCursorAt(0, 11);
   1500 }, { value: 'blah' });
   1501 testVim('I_visual_block', function(cm, vim, helpers) {
   1502   cm.setCursor(0, 0);
   1503   helpers.doKeys('<C-v>', '2', 'j', 'l', 'l', 'I');
   1504   var replacement = new Array(cm.listSelections().length+1).join('hello ').split(' ');
   1505   replacement.pop();
   1506   cm.replaceSelections(replacement);
   1507   eq('hellotest\nhellome\nhelloplease', cm.getValue());
   1508 }, {value: 'test\nme\nplease'});
   1509 testVim('o', function(cm, vim, helpers) {
   1510   cm.setCursor(0, 4);
   1511   helpers.doKeys('o');
   1512   eq('word1\n\nword2', cm.getValue());
   1513   helpers.assertCursorAt(1, 0);
   1514   eq('vim-insert', cm.getOption('keyMap'));
   1515 }, { value: 'word1\nword2' });
   1516 testVim('o_repeat', function(cm, vim, helpers) {
   1517   cm.setCursor(0, 0);
   1518   helpers.doKeys('3', 'o');
   1519   cm.replaceRange('test', cm.getCursor());
   1520   helpers.doKeys('<Esc>');
   1521   eq('\ntest\ntest\ntest', cm.getValue());
   1522   helpers.assertCursorAt(3, 3);
   1523 }, { value: '' });
   1524 testVim('O', function(cm, vim, helpers) {
   1525   cm.setCursor(0, 4);
   1526   helpers.doKeys('O');
   1527   eq('\nword1\nword2', cm.getValue());
   1528   helpers.assertCursorAt(0, 0);
   1529   eq('vim-insert', cm.getOption('keyMap'));
   1530 }, { value: 'word1\nword2' });
   1531 testVim('J', function(cm, vim, helpers) {
   1532   cm.setCursor(0, 4);
   1533   helpers.doKeys('J');
   1534   var expectedValue = 'word1  word2\nword3\n word4';
   1535   eq(expectedValue, cm.getValue());
   1536   helpers.assertCursorAt(0, expectedValue.indexOf('word2') - 1);
   1537 }, { value: 'word1 \n    word2\nword3\n word4' });
   1538 testVim('J_repeat', function(cm, vim, helpers) {
   1539   cm.setCursor(0, 4);
   1540   helpers.doKeys('3', 'J');
   1541   var expectedValue = 'word1  word2 word3\n word4';
   1542   eq(expectedValue, cm.getValue());
   1543   helpers.assertCursorAt(0, expectedValue.indexOf('word3') - 1);
   1544 }, { value: 'word1 \n    word2\nword3\n word4' });
   1545 testVim('p', function(cm, vim, helpers) {
   1546   cm.setCursor(0, 1);
   1547   helpers.getRegisterController().pushText('"', 'yank', 'abc\ndef', false);
   1548   helpers.doKeys('p');
   1549   eq('__abc\ndef_', cm.getValue());
   1550   helpers.assertCursorAt(1, 2);
   1551 }, { value: '___' });
   1552 testVim('p_register', function(cm, vim, helpers) {
   1553   cm.setCursor(0, 1);
   1554   helpers.getRegisterController().getRegister('a').setText('abc\ndef', false);
   1555   helpers.doKeys('"', 'a', 'p');
   1556   eq('__abc\ndef_', cm.getValue());
   1557   helpers.assertCursorAt(1, 2);
   1558 }, { value: '___' });
   1559 testVim('p_wrong_register', function(cm, vim, helpers) {
   1560   cm.setCursor(0, 1);
   1561   helpers.getRegisterController().getRegister('a').setText('abc\ndef', false);
   1562   helpers.doKeys('p');
   1563   eq('___', cm.getValue());
   1564   helpers.assertCursorAt(0, 1);
   1565 }, { value: '___' });
   1566 testVim('p_line', function(cm, vim, helpers) {
   1567   cm.setCursor(0, 1);
   1568   helpers.getRegisterController().pushText('"', 'yank', '  a\nd\n', true);
   1569   helpers.doKeys('2', 'p');
   1570   eq('___\n  a\nd\n  a\nd', cm.getValue());
   1571   helpers.assertCursorAt(1, 2);
   1572 }, { value: '___' });
   1573 testVim('p_lastline', function(cm, vim, helpers) {
   1574   cm.setCursor(0, 1);
   1575   helpers.getRegisterController().pushText('"', 'yank', '  a\nd', true);
   1576   helpers.doKeys('2', 'p');
   1577   eq('___\n  a\nd\n  a\nd', cm.getValue());
   1578   helpers.assertCursorAt(1, 2);
   1579 }, { value: '___' });
   1580 testVim(']p_first_indent_is_smaller', function(cm, vim, helpers) {
   1581   helpers.getRegisterController().pushText('"', 'yank', '  abc\n    def\n', true);
   1582   helpers.doKeys(']', 'p');
   1583   eq('  ___\n  abc\n    def', cm.getValue());
   1584 }, { value: '  ___' });
   1585 testVim(']p_first_indent_is_larger', function(cm, vim, helpers) {
   1586   helpers.getRegisterController().pushText('"', 'yank', '    abc\n  def\n', true);
   1587   helpers.doKeys(']', 'p');
   1588   eq('  ___\n  abc\ndef', cm.getValue());
   1589 }, { value: '  ___' });
   1590 testVim(']p_with_tab_indents', function(cm, vim, helpers) {
   1591   helpers.getRegisterController().pushText('"', 'yank', '\t\tabc\n\t\t\tdef\n', true);
   1592   helpers.doKeys(']', 'p');
   1593   eq('\t___\n\tabc\n\t\tdef', cm.getValue());
   1594 }, { value: '\t___', indentWithTabs: true});
   1595 testVim(']p_with_spaces_translated_to_tabs', function(cm, vim, helpers) {
   1596   helpers.getRegisterController().pushText('"', 'yank', '  abc\n    def\n', true);
   1597   helpers.doKeys(']', 'p');
   1598   eq('\t___\n\tabc\n\t\tdef', cm.getValue());
   1599 }, { value: '\t___', indentWithTabs: true, tabSize: 2 });
   1600 testVim('[p', function(cm, vim, helpers) {
   1601   helpers.getRegisterController().pushText('"', 'yank', '  abc\n    def\n', true);
   1602   helpers.doKeys('[', 'p');
   1603   eq('  abc\n    def\n  ___', cm.getValue());
   1604 }, { value: '  ___' });
   1605 testVim('P', function(cm, vim, helpers) {
   1606   cm.setCursor(0, 1);
   1607   helpers.getRegisterController().pushText('"', 'yank', 'abc\ndef', false);
   1608   helpers.doKeys('P');
   1609   eq('_abc\ndef__', cm.getValue());
   1610   helpers.assertCursorAt(1, 3);
   1611 }, { value: '___' });
   1612 testVim('P_line', function(cm, vim, helpers) {
   1613   cm.setCursor(0, 1);
   1614   helpers.getRegisterController().pushText('"', 'yank', '  a\nd\n', true);
   1615   helpers.doKeys('2', 'P');
   1616   eq('  a\nd\n  a\nd\n___', cm.getValue());
   1617   helpers.assertCursorAt(0, 2);
   1618 }, { value: '___' });
   1619 testVim('r', function(cm, vim, helpers) {
   1620   cm.setCursor(0, 1);
   1621   helpers.doKeys('3', 'r', 'u');
   1622   eq('wuuuet\nanother', cm.getValue(),'3r failed');
   1623   helpers.assertCursorAt(0, 3);
   1624   cm.setCursor(0, 4);
   1625   helpers.doKeys('v', 'j', 'h', 'r', '<Space>');
   1626   eq('wuuu  \n    her', cm.getValue(),'Replacing selection by space-characters failed');
   1627   cm.setValue("ox");
   1628   helpers.doKeys('r', '<C-c>');
   1629   eq('ox', cm.getValue());
   1630   helpers.doKeys('r', '<Del>');
   1631   eq('ox', cm.getValue());
   1632   helpers.doKeys('r', '<CR>');
   1633   eq('\nx', cm.getValue());
   1634 }, { value: 'wordet\nanother' });
   1635 testVim('r_visual_block', function(cm, vim, helpers) {
   1636   cm.setCursor(2, 3);
   1637   helpers.doKeys('<C-v>', 'k', 'k', 'h', 'h', 'r', 'l');
   1638   eq('1lll\n5lll\nalllefg', cm.getValue());
   1639   helpers.doKeys('<C-v>', 'l', 'j', 'r', '<Space>');
   1640   eq('1  l\n5  l\nalllefg', cm.getValue());
   1641   cm.setCursor(2, 0);
   1642   helpers.doKeys('o');
   1643   helpers.doKeys('<Esc>');
   1644   cm.replaceRange('\t\t', cm.getCursor());
   1645   helpers.doKeys('<C-v>', 'h', 'h', 'r', 'r');
   1646   eq('1  l\n5  l\nalllefg\nrrrrrrrr', cm.getValue());
   1647 }, {value: '1234\n5678\nabcdefg'});
   1648 testVim('R', function(cm, vim, helpers) {
   1649   cm.setCursor(0, 1);
   1650   helpers.doKeys('R');
   1651   helpers.assertCursorAt(0, 1);
   1652   eq('vim-replace', cm.getOption('keyMap'));
   1653   is(cm.state.overwrite, 'Setting overwrite state failed');
   1654 });
   1655 testVim('mark', function(cm, vim, helpers) {
   1656   cm.setCursor(2, 2);
   1657   helpers.doKeys('m', 't');
   1658   cm.setCursor(0, 0);
   1659   helpers.doKeys('`', 't');
   1660   helpers.assertCursorAt(2, 2);
   1661   cm.setCursor(2, 0);
   1662   cm.replaceRange('   h', cm.getCursor());
   1663   cm.setCursor(0, 0);
   1664   helpers.doKeys('\'', 't');
   1665   helpers.assertCursorAt(2, 3);
   1666 });
   1667 testVim('mark\'', function(cm, vim, helpers) {
   1668   cm.setCursor(2, 2);
   1669   cm.setCursor(0, 0);
   1670   helpers.doKeys('`', '\'');
   1671   helpers.assertCursorAt(2, 2);
   1672   cm.setCursor(2, 0);
   1673   cm.replaceRange('   h', cm.getCursor());
   1674   cm.setCursor(0, 0);
   1675   helpers.doKeys('\'', '\'');
   1676   helpers.assertCursorAt(2, 3);
   1677 });
   1678 testVim('mark.', function(cm, vim, helpers) {
   1679   cm.setCursor(0, 0);
   1680   helpers.doKeys('O', 'testing', '<Esc>');
   1681   cm.setCursor(3, 3);
   1682   helpers.doKeys('\'', '.');
   1683   helpers.assertCursorAt(0, 0);
   1684   cm.setCursor(4, 4);
   1685   helpers.doKeys('`', '.');
   1686   helpers.assertCursorAt(0, 6);
   1687 });
   1688 testVim('jumpToMark_next', function(cm, vim, helpers) {
   1689   cm.setCursor(2, 2);
   1690   helpers.doKeys('m', 't');
   1691   cm.setCursor(0, 0);
   1692   helpers.doKeys(']', '`');
   1693   helpers.assertCursorAt(2, 2);
   1694   cm.setCursor(0, 0);
   1695   helpers.doKeys(']', '\'');
   1696   helpers.assertCursorAt(2, 0);
   1697 });
   1698 testVim('jumpToMark_next_repeat', function(cm, vim, helpers) {
   1699   cm.setCursor(2, 2);
   1700   helpers.doKeys('m', 'a');
   1701   cm.setCursor(3, 2);
   1702   helpers.doKeys('m', 'b');
   1703   cm.setCursor(4, 2);
   1704   helpers.doKeys('m', 'c');
   1705   cm.setCursor(0, 0);
   1706   helpers.doKeys('2', ']', '`');
   1707   helpers.assertCursorAt(3, 2);
   1708   cm.setCursor(0, 0);
   1709   helpers.doKeys('2', ']', '\'');
   1710   helpers.assertCursorAt(3, 1);
   1711 });
   1712 testVim('jumpToMark_next_sameline', function(cm, vim, helpers) {
   1713   cm.setCursor(2, 0);
   1714   helpers.doKeys('m', 'a');
   1715   cm.setCursor(2, 4);
   1716   helpers.doKeys('m', 'b');
   1717   cm.setCursor(2, 2);
   1718   helpers.doKeys(']', '`');
   1719   helpers.assertCursorAt(2, 4);
   1720 });
   1721 testVim('jumpToMark_next_onlyprev', function(cm, vim, helpers) {
   1722   cm.setCursor(2, 0);
   1723   helpers.doKeys('m', 'a');
   1724   cm.setCursor(4, 0);
   1725   helpers.doKeys(']', '`');
   1726   helpers.assertCursorAt(4, 0);
   1727 });
   1728 testVim('jumpToMark_next_nomark', function(cm, vim, helpers) {
   1729   cm.setCursor(2, 2);
   1730   helpers.doKeys(']', '`');
   1731   helpers.assertCursorAt(2, 2);
   1732   helpers.doKeys(']', '\'');
   1733   helpers.assertCursorAt(2, 0);
   1734 });
   1735 testVim('jumpToMark_next_linewise_over', function(cm, vim, helpers) {
   1736   cm.setCursor(2, 2);
   1737   helpers.doKeys('m', 'a');
   1738   cm.setCursor(3, 4);
   1739   helpers.doKeys('m', 'b');
   1740   cm.setCursor(2, 1);
   1741   helpers.doKeys(']', '\'');
   1742   helpers.assertCursorAt(3, 1);
   1743 });
   1744 testVim('jumpToMark_next_action', function(cm, vim, helpers) {
   1745   cm.setCursor(2, 2);
   1746   helpers.doKeys('m', 't');
   1747   cm.setCursor(0, 0);
   1748   helpers.doKeys('d', ']', '`');
   1749   helpers.assertCursorAt(0, 0);
   1750   var actual = cm.getLine(0);
   1751   var expected = 'pop pop 0 1 2 3 4';
   1752   eq(actual, expected, "Deleting while jumping to the next mark failed.");
   1753 });
   1754 testVim('jumpToMark_next_line_action', function(cm, vim, helpers) {
   1755   cm.setCursor(2, 2);
   1756   helpers.doKeys('m', 't');
   1757   cm.setCursor(0, 0);
   1758   helpers.doKeys('d', ']', '\'');
   1759   helpers.assertCursorAt(0, 1);
   1760   var actual = cm.getLine(0);
   1761   var expected = ' (a) [b] {c} '
   1762   eq(actual, expected, "Deleting while jumping to the next mark line failed.");
   1763 });
   1764 testVim('jumpToMark_prev', function(cm, vim, helpers) {
   1765   cm.setCursor(2, 2);
   1766   helpers.doKeys('m', 't');
   1767   cm.setCursor(4, 0);
   1768   helpers.doKeys('[', '`');
   1769   helpers.assertCursorAt(2, 2);
   1770   cm.setCursor(4, 0);
   1771   helpers.doKeys('[', '\'');
   1772   helpers.assertCursorAt(2, 0);
   1773 });
   1774 testVim('jumpToMark_prev_repeat', function(cm, vim, helpers) {
   1775   cm.setCursor(2, 2);
   1776   helpers.doKeys('m', 'a');
   1777   cm.setCursor(3, 2);
   1778   helpers.doKeys('m', 'b');
   1779   cm.setCursor(4, 2);
   1780   helpers.doKeys('m', 'c');
   1781   cm.setCursor(5, 0);
   1782   helpers.doKeys('2', '[', '`');
   1783   helpers.assertCursorAt(3, 2);
   1784   cm.setCursor(5, 0);
   1785   helpers.doKeys('2', '[', '\'');
   1786   helpers.assertCursorAt(3, 1);
   1787 });
   1788 testVim('jumpToMark_prev_sameline', function(cm, vim, helpers) {
   1789   cm.setCursor(2, 0);
   1790   helpers.doKeys('m', 'a');
   1791   cm.setCursor(2, 4);
   1792   helpers.doKeys('m', 'b');
   1793   cm.setCursor(2, 2);
   1794   helpers.doKeys('[', '`');
   1795   helpers.assertCursorAt(2, 0);
   1796 });
   1797 testVim('jumpToMark_prev_onlynext', function(cm, vim, helpers) {
   1798   cm.setCursor(4, 4);
   1799   helpers.doKeys('m', 'a');
   1800   cm.setCursor(2, 0);
   1801   helpers.doKeys('[', '`');
   1802   helpers.assertCursorAt(2, 0);
   1803 });
   1804 testVim('jumpToMark_prev_nomark', function(cm, vim, helpers) {
   1805   cm.setCursor(2, 2);
   1806   helpers.doKeys('[', '`');
   1807   helpers.assertCursorAt(2, 2);
   1808   helpers.doKeys('[', '\'');
   1809   helpers.assertCursorAt(2, 0);
   1810 });
   1811 testVim('jumpToMark_prev_linewise_over', function(cm, vim, helpers) {
   1812   cm.setCursor(2, 2);
   1813   helpers.doKeys('m', 'a');
   1814   cm.setCursor(3, 4);
   1815   helpers.doKeys('m', 'b');
   1816   cm.setCursor(3, 6);
   1817   helpers.doKeys('[', '\'');
   1818   helpers.assertCursorAt(2, 0);
   1819 });
   1820 testVim('delmark_single', function(cm, vim, helpers) {
   1821   cm.setCursor(1, 2);
   1822   helpers.doKeys('m', 't');
   1823   helpers.doEx('delmarks t');
   1824   cm.setCursor(0, 0);
   1825   helpers.doKeys('`', 't');
   1826   helpers.assertCursorAt(0, 0);
   1827 });
   1828 testVim('delmark_range', function(cm, vim, helpers) {
   1829   cm.setCursor(1, 2);
   1830   helpers.doKeys('m', 'a');
   1831   cm.setCursor(2, 2);
   1832   helpers.doKeys('m', 'b');
   1833   cm.setCursor(3, 2);
   1834   helpers.doKeys('m', 'c');
   1835   cm.setCursor(4, 2);
   1836   helpers.doKeys('m', 'd');
   1837   cm.setCursor(5, 2);
   1838   helpers.doKeys('m', 'e');
   1839   helpers.doEx('delmarks b-d');
   1840   cm.setCursor(0, 0);
   1841   helpers.doKeys('`', 'a');
   1842   helpers.assertCursorAt(1, 2);
   1843   helpers.doKeys('`', 'b');
   1844   helpers.assertCursorAt(1, 2);
   1845   helpers.doKeys('`', 'c');
   1846   helpers.assertCursorAt(1, 2);
   1847   helpers.doKeys('`', 'd');
   1848   helpers.assertCursorAt(1, 2);
   1849   helpers.doKeys('`', 'e');
   1850   helpers.assertCursorAt(5, 2);
   1851 });
   1852 testVim('delmark_multi', function(cm, vim, helpers) {
   1853   cm.setCursor(1, 2);
   1854   helpers.doKeys('m', 'a');
   1855   cm.setCursor(2, 2);
   1856   helpers.doKeys('m', 'b');
   1857   cm.setCursor(3, 2);
   1858   helpers.doKeys('m', 'c');
   1859   cm.setCursor(4, 2);
   1860   helpers.doKeys('m', 'd');
   1861   cm.setCursor(5, 2);
   1862   helpers.doKeys('m', 'e');
   1863   helpers.doEx('delmarks bcd');
   1864   cm.setCursor(0, 0);
   1865   helpers.doKeys('`', 'a');
   1866   helpers.assertCursorAt(1, 2);
   1867   helpers.doKeys('`', 'b');
   1868   helpers.assertCursorAt(1, 2);
   1869   helpers.doKeys('`', 'c');
   1870   helpers.assertCursorAt(1, 2);
   1871   helpers.doKeys('`', 'd');
   1872   helpers.assertCursorAt(1, 2);
   1873   helpers.doKeys('`', 'e');
   1874   helpers.assertCursorAt(5, 2);
   1875 });
   1876 testVim('delmark_multi_space', function(cm, vim, helpers) {
   1877   cm.setCursor(1, 2);
   1878   helpers.doKeys('m', 'a');
   1879   cm.setCursor(2, 2);
   1880   helpers.doKeys('m', 'b');
   1881   cm.setCursor(3, 2);
   1882   helpers.doKeys('m', 'c');
   1883   cm.setCursor(4, 2);
   1884   helpers.doKeys('m', 'd');
   1885   cm.setCursor(5, 2);
   1886   helpers.doKeys('m', 'e');
   1887   helpers.doEx('delmarks b c d');
   1888   cm.setCursor(0, 0);
   1889   helpers.doKeys('`', 'a');
   1890   helpers.assertCursorAt(1, 2);
   1891   helpers.doKeys('`', 'b');
   1892   helpers.assertCursorAt(1, 2);
   1893   helpers.doKeys('`', 'c');
   1894   helpers.assertCursorAt(1, 2);
   1895   helpers.doKeys('`', 'd');
   1896   helpers.assertCursorAt(1, 2);
   1897   helpers.doKeys('`', 'e');
   1898   helpers.assertCursorAt(5, 2);
   1899 });
   1900 testVim('delmark_all', function(cm, vim, helpers) {
   1901   cm.setCursor(1, 2);
   1902   helpers.doKeys('m', 'a');
   1903   cm.setCursor(2, 2);
   1904   helpers.doKeys('m', 'b');
   1905   cm.setCursor(3, 2);
   1906   helpers.doKeys('m', 'c');
   1907   cm.setCursor(4, 2);
   1908   helpers.doKeys('m', 'd');
   1909   cm.setCursor(5, 2);
   1910   helpers.doKeys('m', 'e');
   1911   helpers.doEx('delmarks a b-de');
   1912   cm.setCursor(0, 0);
   1913   helpers.doKeys('`', 'a');
   1914   helpers.assertCursorAt(0, 0);
   1915   helpers.doKeys('`', 'b');
   1916   helpers.assertCursorAt(0, 0);
   1917   helpers.doKeys('`', 'c');
   1918   helpers.assertCursorAt(0, 0);
   1919   helpers.doKeys('`', 'd');
   1920   helpers.assertCursorAt(0, 0);
   1921   helpers.doKeys('`', 'e');
   1922   helpers.assertCursorAt(0, 0);
   1923 });
   1924 testVim('visual', function(cm, vim, helpers) {
   1925   helpers.doKeys('l', 'v', 'l', 'l');
   1926   helpers.assertCursorAt(0, 4);
   1927   eqCursorPos(makeCursor(0, 1), cm.getCursor('anchor'));
   1928   helpers.doKeys('d');
   1929   eq('15', cm.getValue());
   1930 }, { value: '12345' });
   1931 testVim('visual_yank', function(cm, vim, helpers) {
   1932   helpers.doKeys('v', '3', 'l', 'y');
   1933   helpers.assertCursorAt(0, 0);
   1934   helpers.doKeys('p');
   1935   eq('aa te test for yank', cm.getValue());
   1936 }, { value: 'a test for yank' })
   1937 testVim('visual_w', function(cm, vim, helpers) {
   1938   helpers.doKeys('v', 'w');
   1939   eq(cm.getSelection(), 'motion t');
   1940 }, { value: 'motion test'});
   1941 testVim('visual_initial_selection', function(cm, vim, helpers) {
   1942   cm.setCursor(0, 1);
   1943   helpers.doKeys('v');
   1944   cm.getSelection('n');
   1945 }, { value: 'init'});
   1946 testVim('visual_crossover_left', function(cm, vim, helpers) {
   1947   cm.setCursor(0, 2);
   1948   helpers.doKeys('v', 'l', 'h', 'h');
   1949   cm.getSelection('ro');
   1950 }, { value: 'cross'});
   1951 testVim('visual_crossover_left', function(cm, vim, helpers) {
   1952   cm.setCursor(0, 2);
   1953   helpers.doKeys('v', 'h', 'l', 'l');
   1954   cm.getSelection('os');
   1955 }, { value: 'cross'});
   1956 testVim('visual_crossover_up', function(cm, vim, helpers) {
   1957   cm.setCursor(3, 2);
   1958   helpers.doKeys('v', 'j', 'k', 'k');
   1959   eqCursorPos(Pos(2, 2), cm.getCursor('head'));
   1960   eqCursorPos(Pos(3, 3), cm.getCursor('anchor'));
   1961   helpers.doKeys('k');
   1962   eqCursorPos(Pos(1, 2), cm.getCursor('head'));
   1963   eqCursorPos(Pos(3, 3), cm.getCursor('anchor'));
   1964 }, { value: 'cross\ncross\ncross\ncross\ncross\n'});
   1965 testVim('visual_crossover_down', function(cm, vim, helpers) {
   1966   cm.setCursor(1, 2);
   1967   helpers.doKeys('v', 'k', 'j', 'j');
   1968   eqCursorPos(Pos(2, 3), cm.getCursor('head'));
   1969   eqCursorPos(Pos(1, 2), cm.getCursor('anchor'));
   1970   helpers.doKeys('j');
   1971   eqCursorPos(Pos(3, 3), cm.getCursor('head'));
   1972   eqCursorPos(Pos(1, 2), cm.getCursor('anchor'));
   1973 }, { value: 'cross\ncross\ncross\ncross\ncross\n'});
   1974 testVim('visual_exit', function(cm, vim, helpers) {
   1975   helpers.doKeys('<C-v>', 'l', 'j', 'j', '<Esc>');
   1976   eqCursorPos(cm.getCursor('anchor'), cm.getCursor('head'));
   1977   eq(vim.visualMode, false);
   1978 }, { value: 'hello\nworld\nfoo' });
   1979 testVim('visual_line', function(cm, vim, helpers) {
   1980   helpers.doKeys('l', 'V', 'l', 'j', 'j', 'd');
   1981   eq(' 4\n 5', cm.getValue());
   1982 }, { value: ' 1\n 2\n 3\n 4\n 5' });
   1983 testVim('visual_block_move_to_eol', function(cm, vim, helpers) {
   1984   // moveToEol should move all block cursors to end of line
   1985   cm.setCursor(0, 0);
   1986   helpers.doKeys('<C-v>', 'G', '$');
   1987   var selections = cm.getSelections().join();
   1988   eq('123,45,6', selections);
   1989   // Checks that with cursor at Infinity, finding words backwards still works.
   1990   helpers.doKeys('2', 'k', 'b');
   1991   selections = cm.getSelections().join();
   1992   eq('1', selections);
   1993 }, {value: '123\n45\n6'});
   1994 testVim('visual_block_different_line_lengths', function(cm, vim, helpers) {
   1995   // test the block selection with lines of different length
   1996   // i.e. extending the selection
   1997   // till the end of the longest line.
   1998   helpers.doKeys('<C-v>', 'l', 'j', 'j', '6', 'l', 'd');
   1999   helpers.doKeys('d', 'd', 'd', 'd');
   2000   eq('', cm.getValue());
   2001 }, {value: '1234\n5678\nabcdefg'});
   2002 testVim('visual_block_truncate_on_short_line', function(cm, vim, helpers) {
   2003   // check for left side selection in case
   2004   // of moving up to a shorter line.
   2005   cm.replaceRange('', cm.getCursor());
   2006   cm.setCursor(3, 4);
   2007   helpers.doKeys('<C-v>', 'l', 'k', 'k', 'd');
   2008   eq('hello world\n{\ntis\nsa!', cm.getValue());
   2009 }, {value: 'hello world\n{\nthis is\nsparta!'});
   2010 testVim('visual_block_corners', function(cm, vim, helpers) {
   2011   cm.setCursor(1, 2);
   2012   helpers.doKeys('<C-v>', '2', 'l', 'k');
   2013   // circle around the anchor
   2014   // and check the selections
   2015   var selections = cm.getSelections();
   2016   eq('345891', selections.join(''));
   2017   helpers.doKeys('4', 'h');
   2018   selections = cm.getSelections();
   2019   eq('123678', selections.join(''));
   2020   helpers.doKeys('j', 'j');
   2021   selections = cm.getSelections();
   2022   eq('678abc', selections.join(''));
   2023   helpers.doKeys('4', 'l');
   2024   selections = cm.getSelections();
   2025   eq('891cde', selections.join(''));
   2026 }, {value: '12345\n67891\nabcde'});
   2027 testVim('visual_block_mode_switch', function(cm, vim, helpers) {
   2028   // switch between visual modes
   2029   cm.setCursor(1, 1);
   2030   // blockwise to characterwise visual
   2031   helpers.doKeys('<C-v>', 'j', 'l', 'v');
   2032   var selections = cm.getSelections();
   2033   eq('7891\nabc', selections.join(''));
   2034   // characterwise to blockwise
   2035   helpers.doKeys('<C-v>');
   2036   selections = cm.getSelections();
   2037   eq('78bc', selections.join(''));
   2038   // blockwise to linewise visual
   2039   helpers.doKeys('V');
   2040   selections = cm.getSelections();
   2041   eq('67891\nabcde', selections.join(''));
   2042 }, {value: '12345\n67891\nabcde'});
   2043 testVim('visual_block_crossing_short_line', function(cm, vim, helpers) {
   2044   // visual block with long and short lines
   2045   cm.setCursor(0, 3);
   2046   helpers.doKeys('<C-v>', 'j', 'j', 'j');
   2047   var selections = cm.getSelections().join();
   2048   eq('4,,d,b', selections);
   2049   helpers.doKeys('3', 'k');
   2050   selections = cm.getSelections().join();
   2051   eq('4', selections);
   2052   helpers.doKeys('5', 'j', 'k');
   2053   selections = cm.getSelections().join("");
   2054   eq(10, selections.length);
   2055 }, {value: '123456\n78\nabcdefg\nfoobar\n}\n'});
   2056 testVim('visual_block_curPos_on_exit', function(cm, vim, helpers) {
   2057   cm.setCursor(0, 0);
   2058   helpers.doKeys('<C-v>', '3' , 'l', '<Esc>');
   2059   eqCursorPos(makeCursor(0, 3), cm.getCursor());
   2060   helpers.doKeys('h', '<C-v>', '2' , 'j' ,'3' , 'l');
   2061   eq(cm.getSelections().join(), "3456,,cdef");
   2062   helpers.doKeys('4' , 'h');
   2063   eq(cm.getSelections().join(), "23,8,bc");
   2064   helpers.doKeys('2' , 'l');
   2065   eq(cm.getSelections().join(), "34,,cd");
   2066 }, {value: '123456\n78\nabcdefg\nfoobar'});
   2067 
   2068 testVim('visual_marks', function(cm, vim, helpers) {
   2069   helpers.doKeys('l', 'v', 'l', 'l', 'j', 'j', 'v');
   2070   // Test visual mode marks
   2071   cm.setCursor(2, 1);
   2072   helpers.doKeys('\'', '<');
   2073   helpers.assertCursorAt(0, 1);
   2074   helpers.doKeys('\'', '>');
   2075   helpers.assertCursorAt(2, 0);
   2076 });
   2077 testVim('visual_join', function(cm, vim, helpers) {
   2078   helpers.doKeys('l', 'V', 'l', 'j', 'j', 'J');
   2079   eq(' 1 2 3\n 4\n 5', cm.getValue());
   2080   is(!vim.visualMode);
   2081 }, { value: ' 1\n 2\n 3\n 4\n 5' });
   2082 testVim('visual_join_2', function(cm, vim, helpers) {
   2083   helpers.doKeys('G', 'V', 'g', 'g', 'J');
   2084   eq('1 2 3 4 5 6 ', cm.getValue());
   2085   is(!vim.visualMode);
   2086 }, { value: '1\n2\n3\n4\n5\n6\n'});
   2087 testVim('visual_blank', function(cm, vim, helpers) {
   2088   helpers.doKeys('v', 'k');
   2089   eq(vim.visualMode, true);
   2090 }, { value: '\n' });
   2091 testVim('reselect_visual', function(cm, vim, helpers) {
   2092   helpers.doKeys('l', 'v', 'l', 'l', 'l', 'y', 'g', 'v');
   2093   helpers.assertCursorAt(0, 5);
   2094   eqCursorPos(makeCursor(0, 1), cm.getCursor('anchor'));
   2095   helpers.doKeys('v');
   2096   cm.setCursor(1, 0);
   2097   helpers.doKeys('v', 'l', 'l', 'p');
   2098   eq('123456\n2345\nbar', cm.getValue());
   2099   cm.setCursor(0, 0);
   2100   helpers.doKeys('g', 'v');
   2101   // here the fake cursor is at (1, 3)
   2102   helpers.assertCursorAt(1, 4);
   2103   eqCursorPos(makeCursor(1, 0), cm.getCursor('anchor'));
   2104   helpers.doKeys('v');
   2105   cm.setCursor(2, 0);
   2106   helpers.doKeys('v', 'l', 'l', 'g', 'v');
   2107   helpers.assertCursorAt(1, 4);
   2108   eqCursorPos(makeCursor(1, 0), cm.getCursor('anchor'));
   2109   helpers.doKeys('g', 'v');
   2110   helpers.assertCursorAt(2, 3);
   2111   eqCursorPos(makeCursor(2, 0), cm.getCursor('anchor'));
   2112   eq('123456\n2345\nbar', cm.getValue());
   2113 }, { value: '123456\nfoo\nbar' });
   2114 testVim('reselect_visual_line', function(cm, vim, helpers) {
   2115   helpers.doKeys('l', 'V', 'j', 'j', 'V', 'g', 'v', 'd');
   2116   eq('foo\nand\nbar', cm.getValue());
   2117   cm.setCursor(1, 0);
   2118   helpers.doKeys('V', 'y', 'j');
   2119   helpers.doKeys('V', 'p' , 'g', 'v', 'd');
   2120   eq('foo\nand', cm.getValue());
   2121 }, { value: 'hello\nthis\nis\nfoo\nand\nbar' });
   2122 testVim('reselect_visual_block', function(cm, vim, helpers) {
   2123   cm.setCursor(1, 2);
   2124   helpers.doKeys('<C-v>', 'k', 'h', '<C-v>');
   2125   cm.setCursor(2, 1);
   2126   helpers.doKeys('v', 'l', 'g', 'v');
   2127   eqCursorPos(Pos(1, 2), vim.sel.anchor);
   2128   eqCursorPos(Pos(0, 1), vim.sel.head);
   2129   // Ensure selection is done with visual block mode rather than one
   2130   // continuous range.
   2131   eq(cm.getSelections().join(''), '23oo')
   2132   helpers.doKeys('g', 'v');
   2133   eqCursorPos(Pos(2, 1), vim.sel.anchor);
   2134   eqCursorPos(Pos(2, 2), vim.sel.head);
   2135   helpers.doKeys('<Esc>');
   2136   // Ensure selection of deleted range
   2137   cm.setCursor(1, 1);
   2138   helpers.doKeys('v', '<C-v>', 'j', 'd', 'g', 'v');
   2139   eq(cm.getSelections().join(''), 'or');
   2140 }, { value: '123456\nfoo\nbar' });
   2141 testVim('s_normal', function(cm, vim, helpers) {
   2142   cm.setCursor(0, 1);
   2143   helpers.doKeys('s');
   2144   helpers.doKeys('<Esc>');
   2145   eq('ac', cm.getValue());
   2146 }, { value: 'abc'});
   2147 testVim('s_visual', function(cm, vim, helpers) {
   2148   cm.setCursor(0, 1);
   2149   helpers.doKeys('v', 's');
   2150   helpers.doKeys('<Esc>');
   2151   helpers.assertCursorAt(0, 0);
   2152   eq('ac', cm.getValue());
   2153 }, { value: 'abc'});
   2154 testVim('o_visual', function(cm, vim, helpers) {
   2155   cm.setCursor(0,0);
   2156   helpers.doKeys('v','l','l','l','o');
   2157   helpers.assertCursorAt(0,0);
   2158   helpers.doKeys('v','v','j','j','j','o');
   2159   helpers.assertCursorAt(0,0);
   2160   helpers.doKeys('O');
   2161   helpers.doKeys('l','l')
   2162   helpers.assertCursorAt(3, 3);
   2163   helpers.doKeys('d');
   2164   eq('p',cm.getValue());
   2165 }, { value: 'abcd\nefgh\nijkl\nmnop'});
   2166 testVim('o_visual_block', function(cm, vim, helpers) {
   2167   cm.setCursor(0, 1);
   2168   helpers.doKeys('<C-v>','3','j','l','l', 'o');
   2169   eqCursorPos(Pos(3, 3), vim.sel.anchor);
   2170   eqCursorPos(Pos(0, 1), vim.sel.head);
   2171   helpers.doKeys('O');
   2172   eqCursorPos(Pos(3, 1), vim.sel.anchor);
   2173   eqCursorPos(Pos(0, 3), vim.sel.head);
   2174   helpers.doKeys('o');
   2175   eqCursorPos(Pos(0, 3), vim.sel.anchor);
   2176   eqCursorPos(Pos(3, 1), vim.sel.head);
   2177 }, { value: 'abcd\nefgh\nijkl\nmnop'});
   2178 testVim('changeCase_visual', function(cm, vim, helpers) {
   2179   cm.setCursor(0, 0);
   2180   helpers.doKeys('v', 'l', 'l');
   2181   helpers.doKeys('U');
   2182   helpers.assertCursorAt(0, 0);
   2183   helpers.doKeys('v', 'l', 'l');
   2184   helpers.doKeys('u');
   2185   helpers.assertCursorAt(0, 0);
   2186   helpers.doKeys('l', 'l', 'l', '.');
   2187   helpers.assertCursorAt(0, 3);
   2188   cm.setCursor(0, 0);
   2189   helpers.doKeys('q', 'a', 'v', 'j', 'U', 'q');
   2190   helpers.assertCursorAt(0, 0);
   2191   helpers.doKeys('j', '@', 'a');
   2192   helpers.assertCursorAt(1, 0);
   2193   cm.setCursor(3, 0);
   2194   helpers.doKeys('V', 'U', 'j', '.');
   2195   eq('ABCDEF\nGHIJKL\nMnopq\nSHORT LINE\nLONG LINE OF TEXT', cm.getValue());
   2196 }, { value: 'abcdef\nghijkl\nmnopq\nshort line\nlong line of text'});
   2197 testVim('changeCase_visual_block', function(cm, vim, helpers) {
   2198   cm.setCursor(2, 1);
   2199   helpers.doKeys('<C-v>', 'k', 'k', 'h', 'U');
   2200   eq('ABcdef\nGHijkl\nMNopq\nfoo', cm.getValue());
   2201   cm.setCursor(0, 2);
   2202   helpers.doKeys('.');
   2203   eq('ABCDef\nGHIJkl\nMNOPq\nfoo', cm.getValue());
   2204   // check when last line is shorter.
   2205   cm.setCursor(2, 2);
   2206   helpers.doKeys('.');
   2207   eq('ABCDef\nGHIJkl\nMNOPq\nfoO', cm.getValue());
   2208 }, { value: 'abcdef\nghijkl\nmnopq\nfoo'});
   2209 testVim('visual_paste', function(cm, vim, helpers) {
   2210   cm.setCursor(0, 0);
   2211   helpers.doKeys('v', 'l', 'l', 'y');
   2212   helpers.assertCursorAt(0, 0);
   2213   helpers.doKeys('3', 'l', 'j', 'v', 'l', 'p');
   2214   helpers.assertCursorAt(1, 5);
   2215   eq('this is a\nunithitest for visual paste', cm.getValue());
   2216   cm.setCursor(0, 0);
   2217   // in case of pasting whole line
   2218   helpers.doKeys('y', 'y');
   2219   cm.setCursor(1, 6);
   2220   helpers.doKeys('v', 'l', 'l', 'l', 'p');
   2221   helpers.assertCursorAt(2, 0);
   2222   eq('this is a\nunithi\nthis is a\n for visual paste', cm.getValue());
   2223 }, { value: 'this is a\nunit test for visual paste'});
   2224 
   2225 // This checks the contents of the register used to paste the text
   2226 testVim('v_paste_from_register', function(cm, vim, helpers) {
   2227   cm.setCursor(0, 0);
   2228   helpers.doKeys('"', 'a', 'y', 'w');
   2229   cm.setCursor(1, 0);
   2230   helpers.doKeys('v', 'p');
   2231   cm.openDialog = helpers.fakeOpenDialog('registers');
   2232   cm.openNotification = helpers.fakeOpenNotification(function(text) {
   2233     is(/a\s+register/.test(text));
   2234   });
   2235 }, { value: 'register contents\nare not erased'});
   2236 testVim('S_normal', function(cm, vim, helpers) {
   2237   cm.setCursor(0, 1);
   2238   helpers.doKeys('j', 'S');
   2239   helpers.doKeys('<Esc>');
   2240   helpers.assertCursorAt(1, 1);
   2241   eq('aa{\n  \ncc', cm.getValue());
   2242   helpers.doKeys('j', 'S');
   2243   eq('aa{\n  \n  ', cm.getValue());
   2244   helpers.assertCursorAt(2, 2);
   2245   helpers.doKeys('<Esc>');
   2246   helpers.doKeys('d', 'd', 'd', 'd');
   2247   helpers.assertCursorAt(0, 0);
   2248   helpers.doKeys('S');
   2249   is(vim.insertMode);
   2250   eq('', cm.getValue());
   2251 }, { value: 'aa{\nbb\ncc'});
   2252 testVim('blockwise_paste', function(cm, vim, helpers) {
   2253   cm.setCursor(0, 0);
   2254   helpers.doKeys('<C-v>', '3', 'j', 'l', 'y');
   2255   cm.setCursor(0, 2);
   2256   // paste one char after the current cursor position
   2257   helpers.doKeys('p');
   2258   eq('helhelo\nworwold\nfoofo\nbarba', cm.getValue());
   2259   cm.setCursor(0, 0);
   2260   helpers.doKeys('v', '4', 'l', 'y');
   2261   cm.setCursor(0, 0);
   2262   helpers.doKeys('<C-v>', '3', 'j', 'p');
   2263   eq('helheelhelo\norwold\noofo\narba', cm.getValue());
   2264 }, { value: 'hello\nworld\nfoo\nbar'});
   2265 testVim('blockwise_paste_long/short_line', function(cm, vim, helpers) {
   2266   // extend short lines in case of different line lengths.
   2267   cm.setCursor(0, 0);
   2268   helpers.doKeys('<C-v>', 'j', 'j', 'y');
   2269   cm.setCursor(0, 3);
   2270   helpers.doKeys('p');
   2271   eq('hellho\nfoo f\nbar b', cm.getValue());
   2272 }, { value: 'hello\nfoo\nbar'});
   2273 testVim('blockwise_paste_cut_paste', function(cm, vim, helpers) {
   2274   cm.setCursor(0, 0);
   2275   helpers.doKeys('<C-v>', '2', 'j', 'x');
   2276   cm.setCursor(0, 0);
   2277   helpers.doKeys('P');
   2278   eq('cut\nand\npaste\nme', cm.getValue());
   2279 }, { value: 'cut\nand\npaste\nme'});
   2280 testVim('blockwise_paste_from_register', function(cm, vim, helpers) {
   2281   cm.setCursor(0, 0);
   2282   helpers.doKeys('<C-v>', '2', 'j', '"', 'a', 'y');
   2283   cm.setCursor(0, 3);
   2284   helpers.doKeys('"', 'a', 'p');
   2285   eq('foobfar\nhellho\nworlwd', cm.getValue());
   2286 }, { value: 'foobar\nhello\nworld'});
   2287 testVim('blockwise_paste_last_line', function(cm, vim, helpers) {
   2288   cm.setCursor(0, 0);
   2289   helpers.doKeys('<C-v>', '2', 'j', 'l', 'y');
   2290   cm.setCursor(3, 0);
   2291   helpers.doKeys('p');
   2292   eq('cut\nand\npaste\nmcue\n an\n pa', cm.getValue());
   2293 }, { value: 'cut\nand\npaste\nme'});
   2294 
   2295 testVim('S_visual', function(cm, vim, helpers) {
   2296   cm.setCursor(0, 1);
   2297   helpers.doKeys('v', 'j', 'S');
   2298   helpers.doKeys('<Esc>');
   2299   helpers.assertCursorAt(0, 0);
   2300   eq('\ncc', cm.getValue());
   2301 }, { value: 'aa\nbb\ncc'});
   2302 
   2303 testVim('d_/', function(cm, vim, helpers) {
   2304   cm.openDialog = helpers.fakeOpenDialog('match');
   2305   helpers.doKeys('2', 'd', '/');
   2306   helpers.assertCursorAt(0, 0);
   2307   eq('match \n next', cm.getValue());
   2308   cm.openDialog = helpers.fakeOpenDialog('2');
   2309   helpers.doKeys('d', ':');
   2310   // TODO eq(' next', cm.getValue());
   2311 }, { value: 'text match match \n next' });
   2312 testVim('/ and n/N', function(cm, vim, helpers) {
   2313   cm.openDialog = helpers.fakeOpenDialog('match');
   2314   helpers.doKeys('/');
   2315   helpers.assertCursorAt(0, 11);
   2316   helpers.doKeys('n');
   2317   helpers.assertCursorAt(1, 6);
   2318   helpers.doKeys('N');
   2319   helpers.assertCursorAt(0, 11);
   2320 
   2321   cm.setCursor(0, 0);
   2322   helpers.doKeys('2', '/');
   2323   helpers.assertCursorAt(1, 6);
   2324 }, { value: 'match nope match \n nope Match' });
   2325 testVim('/_case', function(cm, vim, helpers) {
   2326   cm.openDialog = helpers.fakeOpenDialog('Match');
   2327   helpers.doKeys('/');
   2328   helpers.assertCursorAt(1, 6);
   2329 }, { value: 'match nope match \n nope Match' });
   2330 testVim('/_2_pcre', function(cm, vim, helpers) {
   2331   CodeMirror.Vim.setOption('pcre', true);
   2332   cm.openDialog = helpers.fakeOpenDialog('(word){2}');
   2333   helpers.doKeys('/');
   2334   helpers.assertCursorAt(1, 9);
   2335   helpers.doKeys('n');
   2336   helpers.assertCursorAt(2, 1);
   2337 }, { value: 'word\n another wordword\n wordwordword\n' });
   2338 testVim('/_2_nopcre', function(cm, vim, helpers) {
   2339   CodeMirror.Vim.setOption('pcre', false);
   2340   cm.openDialog = helpers.fakeOpenDialog('\\(word\\)\\{2}');
   2341   helpers.doKeys('/');
   2342   helpers.assertCursorAt(1, 9);
   2343   helpers.doKeys('n');
   2344   helpers.assertCursorAt(2, 1);
   2345 }, { value: 'word\n another wordword\n wordwordword\n' });
   2346 testVim('/_nongreedy', function(cm, vim, helpers) {
   2347   cm.openDialog = helpers.fakeOpenDialog('aa');
   2348   helpers.doKeys('/');
   2349   helpers.assertCursorAt(0, 4);
   2350   helpers.doKeys('n');
   2351   helpers.assertCursorAt(1, 3);
   2352   helpers.doKeys('n');
   2353   helpers.assertCursorAt(0, 0);
   2354 }, { value: 'aaa aa \n a aa'});
   2355 testVim('?_nongreedy', function(cm, vim, helpers) {
   2356   cm.openDialog = helpers.fakeOpenDialog('aa');
   2357   helpers.doKeys('?');
   2358   helpers.assertCursorAt(1, 3);
   2359   helpers.doKeys('n');
   2360   helpers.assertCursorAt(0, 4);
   2361   helpers.doKeys('n');
   2362   helpers.assertCursorAt(0, 0);
   2363 }, { value: 'aaa aa \n a aa'});
   2364 testVim('/_greedy', function(cm, vim, helpers) {
   2365   cm.openDialog = helpers.fakeOpenDialog('a+');
   2366   helpers.doKeys('/');
   2367   helpers.assertCursorAt(0, 4);
   2368   helpers.doKeys('n');
   2369   helpers.assertCursorAt(1, 1);
   2370   helpers.doKeys('n');
   2371   helpers.assertCursorAt(1, 3);
   2372   helpers.doKeys('n');
   2373   helpers.assertCursorAt(0, 0);
   2374 }, { value: 'aaa aa \n a aa'});
   2375 testVim('?_greedy', function(cm, vim, helpers) {
   2376   cm.openDialog = helpers.fakeOpenDialog('a+');
   2377   helpers.doKeys('?');
   2378   helpers.assertCursorAt(1, 3);
   2379   helpers.doKeys('n');
   2380   helpers.assertCursorAt(1, 1);
   2381   helpers.doKeys('n');
   2382   helpers.assertCursorAt(0, 4);
   2383   helpers.doKeys('n');
   2384   helpers.assertCursorAt(0, 0);
   2385 }, { value: 'aaa aa \n a aa'});
   2386 testVim('/_greedy_0_or_more', function(cm, vim, helpers) {
   2387   cm.openDialog = helpers.fakeOpenDialog('a*');
   2388   helpers.doKeys('/');
   2389   helpers.assertCursorAt(0, 3);
   2390   helpers.doKeys('n');
   2391   helpers.assertCursorAt(0, 4);
   2392   helpers.doKeys('n');
   2393   helpers.assertCursorAt(0, 5);
   2394   helpers.doKeys('n');
   2395   helpers.assertCursorAt(1, 0);
   2396   helpers.doKeys('n');
   2397   helpers.assertCursorAt(1, 1);
   2398   helpers.doKeys('n');
   2399   helpers.assertCursorAt(0, 0);
   2400 }, { value: 'aaa  aa\n aa'});
   2401 testVim('?_greedy_0_or_more', function(cm, vim, helpers) {
   2402   cm.openDialog = helpers.fakeOpenDialog('a*');
   2403   helpers.doKeys('?');
   2404   helpers.assertCursorAt(1, 1);
   2405   helpers.doKeys('n');
   2406   helpers.assertCursorAt(0, 5);
   2407   helpers.doKeys('n');
   2408   helpers.assertCursorAt(0, 3);
   2409   helpers.doKeys('n');
   2410   helpers.assertCursorAt(0, 0);
   2411 }, { value: 'aaa  aa\n aa'});
   2412 testVim('? and n/N', function(cm, vim, helpers) {
   2413   cm.openDialog = helpers.fakeOpenDialog('match');
   2414   helpers.doKeys('?');
   2415   helpers.assertCursorAt(1, 6);
   2416   helpers.doKeys('n');
   2417   helpers.assertCursorAt(0, 11);
   2418   helpers.doKeys('N');
   2419   helpers.assertCursorAt(1, 6);
   2420 
   2421   cm.setCursor(0, 0);
   2422   helpers.doKeys('2', '?');
   2423   helpers.assertCursorAt(0, 11);
   2424 }, { value: 'match nope match \n nope Match' });
   2425 testVim('*', function(cm, vim, helpers) {
   2426   cm.setCursor(0, 9);
   2427   helpers.doKeys('*');
   2428   helpers.assertCursorAt(0, 22);
   2429 
   2430   cm.setCursor(0, 9);
   2431   helpers.doKeys('2', '*');
   2432   helpers.assertCursorAt(1, 8);
   2433 }, { value: 'nomatch match nomatch match \nnomatch Match' });
   2434 testVim('*_no_word', function(cm, vim, helpers) {
   2435   cm.setCursor(0, 0);
   2436   helpers.doKeys('*');
   2437   helpers.assertCursorAt(0, 0);
   2438 }, { value: ' \n match \n' });
   2439 testVim('*_symbol', function(cm, vim, helpers) {
   2440   cm.setCursor(0, 0);
   2441   helpers.doKeys('*');
   2442   helpers.assertCursorAt(1, 0);
   2443 }, { value: ' /}\n/} match \n' });
   2444 testVim('#', function(cm, vim, helpers) {
   2445   cm.setCursor(0, 9);
   2446   helpers.doKeys('#');
   2447   helpers.assertCursorAt(1, 8);
   2448 
   2449   cm.setCursor(0, 9);
   2450   helpers.doKeys('2', '#');
   2451   helpers.assertCursorAt(0, 22);
   2452 }, { value: 'nomatch match nomatch match \nnomatch Match' });
   2453 testVim('*_seek', function(cm, vim, helpers) {
   2454   // Should skip over space and symbols.
   2455   cm.setCursor(0, 3);
   2456   helpers.doKeys('*');
   2457   helpers.assertCursorAt(0, 22);
   2458 }, { value: '    :=  match nomatch match \nnomatch Match' });
   2459 testVim('#', function(cm, vim, helpers) {
   2460   // Should skip over space and symbols.
   2461   cm.setCursor(0, 3);
   2462   helpers.doKeys('#');
   2463   helpers.assertCursorAt(1, 8);
   2464 }, { value: '    :=  match nomatch match \nnomatch Match' });
   2465 testVim('g*', function(cm, vim, helpers) {
   2466   cm.setCursor(0, 8);
   2467   helpers.doKeys('g', '*');
   2468   helpers.assertCursorAt(0, 18);
   2469   cm.setCursor(0, 8);
   2470   helpers.doKeys('3', 'g', '*');
   2471   helpers.assertCursorAt(1, 8);
   2472 }, { value: 'matches match alsoMatch\nmatchme matching' });
   2473 testVim('g#', function(cm, vim, helpers) {
   2474   cm.setCursor(0, 8);
   2475   helpers.doKeys('g', '#');
   2476   helpers.assertCursorAt(0, 0);
   2477   cm.setCursor(0, 8);
   2478   helpers.doKeys('3', 'g', '#');
   2479   helpers.assertCursorAt(1, 0);
   2480 }, { value: 'matches match alsoMatch\nmatchme matching' });
   2481 testVim('macro_insert', function(cm, vim, helpers) {
   2482   cm.setCursor(0, 0);
   2483   helpers.doKeys('q', 'a', '0', 'i');
   2484   cm.replaceRange('foo', cm.getCursor());
   2485   helpers.doKeys('<Esc>');
   2486   helpers.doKeys('q', '@', 'a');
   2487   eq('foofoo', cm.getValue());
   2488 }, { value: ''});
   2489 testVim('macro_insert_repeat', function(cm, vim, helpers) {
   2490   cm.setCursor(0, 0);
   2491   helpers.doKeys('q', 'a', '$', 'a');
   2492   cm.replaceRange('larry.', cm.getCursor());
   2493   helpers.doKeys('<Esc>');
   2494   helpers.doKeys('a');
   2495   cm.replaceRange('curly.', cm.getCursor());
   2496   helpers.doKeys('<Esc>');
   2497   helpers.doKeys('q');
   2498   helpers.doKeys('a');
   2499   cm.replaceRange('moe.', cm.getCursor());
   2500   helpers.doKeys('<Esc>');
   2501   helpers.doKeys('@', 'a');
   2502   // At this point, the most recent edit should be the 2nd insert change
   2503   // inside the macro, i.e. "curly.".
   2504   helpers.doKeys('.');
   2505   eq('larry.curly.moe.larry.curly.curly.', cm.getValue());
   2506 }, { value: ''});
   2507 testVim('macro_space', function(cm, vim, helpers) {
   2508   cm.setCursor(0, 0);
   2509   helpers.doKeys('<Space>', '<Space>');
   2510   helpers.assertCursorAt(0, 2);
   2511   helpers.doKeys('q', 'a', '<Space>', '<Space>', 'q');
   2512   helpers.assertCursorAt(0, 4);
   2513   helpers.doKeys('@', 'a');
   2514   helpers.assertCursorAt(0, 6);
   2515   helpers.doKeys('@', 'a');
   2516   helpers.assertCursorAt(0, 8);
   2517 }, { value: 'one line of text.'});
   2518 testVim('macro_t_search', function(cm, vim, helpers) {
   2519   cm.setCursor(0, 0);
   2520   helpers.doKeys('q', 'a', 't', 'e', 'q');
   2521   helpers.assertCursorAt(0, 1);
   2522   helpers.doKeys('l', '@', 'a');
   2523   helpers.assertCursorAt(0, 6);
   2524   helpers.doKeys('l', ';');
   2525   helpers.assertCursorAt(0, 12);
   2526 }, { value: 'one line of text.'});
   2527 testVim('macro_f_search', function(cm, vim, helpers) {
   2528   cm.setCursor(0, 0);
   2529   helpers.doKeys('q', 'b', 'f', 'e', 'q');
   2530   helpers.assertCursorAt(0, 2);
   2531   helpers.doKeys('@', 'b');
   2532   helpers.assertCursorAt(0, 7);
   2533   helpers.doKeys(';');
   2534   helpers.assertCursorAt(0, 13);
   2535 }, { value: 'one line of text.'});
   2536 testVim('macro_slash_search', function(cm, vim, helpers) {
   2537   cm.setCursor(0, 0);
   2538   helpers.doKeys('q', 'c');
   2539   cm.openDialog = helpers.fakeOpenDialog('e');
   2540   helpers.doKeys('/', 'q');
   2541   helpers.assertCursorAt(0, 2);
   2542   helpers.doKeys('@', 'c');
   2543   helpers.assertCursorAt(0, 7);
   2544   helpers.doKeys('n');
   2545   helpers.assertCursorAt(0, 13);
   2546 }, { value: 'one line of text.'});
   2547 testVim('macro_multislash_search', function(cm, vim, helpers) {
   2548   cm.setCursor(0, 0);
   2549   helpers.doKeys('q', 'd');
   2550   cm.openDialog = helpers.fakeOpenDialog('e');
   2551   helpers.doKeys('/');
   2552   cm.openDialog = helpers.fakeOpenDialog('t');
   2553   helpers.doKeys('/', 'q');
   2554   helpers.assertCursorAt(0, 12);
   2555   helpers.doKeys('@', 'd');
   2556   helpers.assertCursorAt(0, 15);
   2557 }, { value: 'one line of text to rule them all.'});
   2558 testVim('macro_last_ex_command_register', function (cm, vim, helpers) {
   2559   cm.setCursor(0, 0);
   2560   helpers.doEx('s/a/b');
   2561   helpers.doKeys('2', '@', ':');
   2562   eq('bbbaa', cm.getValue());
   2563   helpers.assertCursorAt(0, 2);
   2564 }, { value: 'aaaaa'});
   2565 testVim('macro_parens', function(cm, vim, helpers) {
   2566   cm.setCursor(0, 0);
   2567   helpers.doKeys('q', 'z', 'i');
   2568   cm.replaceRange('(', cm.getCursor());
   2569   helpers.doKeys('<Esc>');
   2570   helpers.doKeys('e', 'a');
   2571   cm.replaceRange(')', cm.getCursor());
   2572   helpers.doKeys('<Esc>');
   2573   helpers.doKeys('q');
   2574   helpers.doKeys('w', '@', 'z');
   2575   helpers.doKeys('w', '@', 'z');
   2576   eq('(see) (spot) (run)', cm.getValue());
   2577 }, { value: 'see spot run'});
   2578 testVim('macro_overwrite', function(cm, vim, helpers) {
   2579   cm.setCursor(0, 0);
   2580   helpers.doKeys('q', 'z', '0', 'i');
   2581   cm.replaceRange('I ', cm.getCursor());
   2582   helpers.doKeys('<Esc>');
   2583   helpers.doKeys('q');
   2584   helpers.doKeys('e');
   2585   // Now replace the macro with something else.
   2586   helpers.doKeys('q', 'z', 'a');
   2587   cm.replaceRange('.', cm.getCursor());
   2588   helpers.doKeys('<Esc>');
   2589   helpers.doKeys('q');
   2590   helpers.doKeys('e', '@', 'z');
   2591   helpers.doKeys('e', '@', 'z');
   2592   eq('I see. spot. run.', cm.getValue());
   2593 }, { value: 'see spot run'});
   2594 testVim('macro_search_f', function(cm, vim, helpers) {
   2595   cm.setCursor(0, 0);
   2596   helpers.doKeys('q', 'a', 'f', ' ');
   2597   helpers.assertCursorAt(0,3);
   2598   helpers.doKeys('q', '0');
   2599   helpers.assertCursorAt(0,0);
   2600   helpers.doKeys('@', 'a');
   2601   helpers.assertCursorAt(0,3);
   2602 }, { value: 'The quick brown fox jumped over the lazy dog.'});
   2603 testVim('macro_search_2f', function(cm, vim, helpers) {
   2604   cm.setCursor(0, 0);
   2605   helpers.doKeys('q', 'a', '2', 'f', ' ');
   2606   helpers.assertCursorAt(0,9);
   2607   helpers.doKeys('q', '0');
   2608   helpers.assertCursorAt(0,0);
   2609   helpers.doKeys('@', 'a');
   2610   helpers.assertCursorAt(0,9);
   2611 }, { value: 'The quick brown fox jumped over the lazy dog.'});
   2612 testVim('macro_yank_tick', function(cm, vim, helpers) {
   2613   cm.setCursor(0, 0);
   2614   // Start recording a macro into the \' register.
   2615   helpers.doKeys('q', '\'');
   2616   helpers.doKeys('y', '<Right>', '<Right>', '<Right>', '<Right>', 'p');
   2617   helpers.assertCursorAt(0,4);
   2618   eq('the tex parrot', cm.getValue());
   2619 }, { value: 'the ex parrot'});
   2620 testVim('yank_register', function(cm, vim, helpers) {
   2621   cm.setCursor(0, 0);
   2622   helpers.doKeys('"', 'a', 'y', 'y');
   2623   helpers.doKeys('j', '"', 'b', 'y', 'y');
   2624   cm.openDialog = helpers.fakeOpenDialog('registers');
   2625   cm.openNotification = helpers.fakeOpenNotification(function(text) {
   2626     is(/a\s+foo/.test(text));
   2627     is(/b\s+bar/.test(text));
   2628   });
   2629   helpers.doKeys(':');
   2630 }, { value: 'foo\nbar'});
   2631 testVim('yank_visual_block', function(cm, vim, helpers) {
   2632   cm.setCursor(0, 1);
   2633   helpers.doKeys('<C-v>', 'l', 'j', '"', 'a', 'y');
   2634   cm.openNotification = helpers.fakeOpenNotification(function(text) {
   2635     is(/a\s+oo\nar/.test(text));
   2636   });
   2637   helpers.doKeys(':');
   2638 }, { value: 'foo\nbar'});
   2639 testVim('yank_append_line_to_line_register', function(cm, vim, helpers) {
   2640   cm.setCursor(0, 0);
   2641   helpers.doKeys('"', 'a', 'y', 'y');
   2642   helpers.doKeys('j', '"', 'A', 'y', 'y');
   2643   cm.openDialog = helpers.fakeOpenDialog('registers');
   2644   cm.openNotification = helpers.fakeOpenNotification(function(text) {
   2645     is(/a\s+foo\nbar/.test(text));
   2646     is(/"\s+foo\nbar/.test(text));
   2647   });
   2648   helpers.doKeys(':');
   2649 }, { value: 'foo\nbar'});
   2650 testVim('yank_append_word_to_word_register', function(cm, vim, helpers) {
   2651   cm.setCursor(0, 0);
   2652   helpers.doKeys('"', 'a', 'y', 'w');
   2653   helpers.doKeys('j', '"', 'A', 'y', 'w');
   2654   cm.openDialog = helpers.fakeOpenDialog('registers');
   2655   cm.openNotification = helpers.fakeOpenNotification(function(text) {
   2656     is(/a\s+foobar/.test(text));
   2657     is(/"\s+foobar/.test(text));
   2658   });
   2659   helpers.doKeys(':');
   2660 }, { value: 'foo\nbar'});
   2661 testVim('yank_append_line_to_word_register', function(cm, vim, helpers) {
   2662   cm.setCursor(0, 0);
   2663   helpers.doKeys('"', 'a', 'y', 'w');
   2664   helpers.doKeys('j', '"', 'A', 'y', 'y');
   2665   cm.openDialog = helpers.fakeOpenDialog('registers');
   2666   cm.openNotification = helpers.fakeOpenNotification(function(text) {
   2667     is(/a\s+foo\nbar/.test(text));
   2668     is(/"\s+foo\nbar/.test(text));
   2669   });
   2670   helpers.doKeys(':');
   2671 }, { value: 'foo\nbar'});
   2672 testVim('yank_append_word_to_line_register', function(cm, vim, helpers) {
   2673   cm.setCursor(0, 0);
   2674   helpers.doKeys('"', 'a', 'y', 'y');
   2675   helpers.doKeys('j', '"', 'A', 'y', 'w');
   2676   cm.openDialog = helpers.fakeOpenDialog('registers');
   2677   cm.openNotification = helpers.fakeOpenNotification(function(text) {
   2678     is(/a\s+foo\nbar/.test(text));
   2679     is(/"\s+foo\nbar/.test(text));
   2680   });
   2681   helpers.doKeys(':');
   2682 }, { value: 'foo\nbar'});
   2683 testVim('macro_register', function(cm, vim, helpers) {
   2684   cm.setCursor(0, 0);
   2685   helpers.doKeys('q', 'a', 'i');
   2686   cm.replaceRange('gangnam', cm.getCursor());
   2687   helpers.doKeys('<Esc>');
   2688   helpers.doKeys('q');
   2689   helpers.doKeys('q', 'b', 'o');
   2690   cm.replaceRange('style', cm.getCursor());
   2691   helpers.doKeys('<Esc>');
   2692   helpers.doKeys('q');
   2693   cm.openDialog = helpers.fakeOpenDialog('registers');
   2694   cm.openNotification = helpers.fakeOpenNotification(function(text) {
   2695     is(/a\s+i/.test(text));
   2696     is(/b\s+o/.test(text));
   2697   });
   2698   helpers.doKeys(':');
   2699 }, { value: ''});
   2700 testVim('._register', function(cm,vim,helpers) {
   2701   cm.setCursor(0,0);
   2702   helpers.doKeys('i');
   2703   cm.replaceRange('foo',cm.getCursor());
   2704   helpers.doKeys('<Esc>');
   2705   cm.openDialog = helpers.fakeOpenDialog('registers');
   2706   cm.openNotification = helpers.fakeOpenNotification(function(text) {
   2707     is(/\.\s+foo/.test(text));
   2708   });
   2709   helpers.doKeys(':');
   2710 }, {value: ''});
   2711 testVim(':_register', function(cm,vim,helpers) {
   2712   helpers.doEx('bar');
   2713   cm.openDialog = helpers.fakeOpenDialog('registers');
   2714   cm.openNotification = helpers.fakeOpenNotification(function(text) {
   2715     is(/:\s+bar/.test(text));
   2716   });
   2717   helpers.doKeys(':');
   2718 }, {value: ''});
   2719 testVim('search_register_escape', function(cm, vim, helpers) {
   2720   // Check that the register is restored if the user escapes rather than confirms.
   2721   cm.openDialog = helpers.fakeOpenDialog('waldo');
   2722   helpers.doKeys('/');
   2723   var onKeyDown;
   2724   var onKeyUp;
   2725   var KEYCODES = {
   2726     f: 70,
   2727     o: 79,
   2728     Esc: 27
   2729   };
   2730   cm.openDialog = function(template, callback, options) {
   2731     onKeyDown = options.onKeyDown;
   2732     onKeyUp = options.onKeyUp;
   2733   };
   2734   var close = function() {};
   2735   helpers.doKeys('/');
   2736   // Fake some keyboard events coming in.
   2737   onKeyDown({keyCode: KEYCODES.f}, '', close);
   2738   onKeyUp({keyCode: KEYCODES.f}, '', close);
   2739   onKeyDown({keyCode: KEYCODES.o}, 'f', close);
   2740   onKeyUp({keyCode: KEYCODES.o}, 'f', close);
   2741   onKeyDown({keyCode: KEYCODES.o}, 'fo', close);
   2742   onKeyUp({keyCode: KEYCODES.o}, 'fo', close);
   2743   onKeyDown({keyCode: KEYCODES.Esc}, 'foo', close);
   2744   cm.openDialog = helpers.fakeOpenDialog('registers');
   2745   cm.openNotification = helpers.fakeOpenNotification(function(text) {
   2746     is(/waldo/.test(text));
   2747     is(!/foo/.test(text));
   2748   });
   2749   helpers.doKeys(':');
   2750 }, {value: ''});
   2751 testVim('search_register', function(cm, vim, helpers) {
   2752   cm.openDialog = helpers.fakeOpenDialog('foo');
   2753   helpers.doKeys('/');
   2754   cm.openDialog = helpers.fakeOpenDialog('registers');
   2755   cm.openNotification = helpers.fakeOpenNotification(function(text) {
   2756     is(/\/\s+foo/.test(text));
   2757   });
   2758   helpers.doKeys(':');
   2759 }, {value: ''});
   2760 testVim('search_history', function(cm, vim, helpers) {
   2761   cm.openDialog = helpers.fakeOpenDialog('this');
   2762   helpers.doKeys('/');
   2763   cm.openDialog = helpers.fakeOpenDialog('checks');
   2764   helpers.doKeys('/');
   2765   cm.openDialog = helpers.fakeOpenDialog('search');
   2766   helpers.doKeys('/');
   2767   cm.openDialog = helpers.fakeOpenDialog('history');
   2768   helpers.doKeys('/');
   2769   cm.openDialog = helpers.fakeOpenDialog('checks');
   2770   helpers.doKeys('/');
   2771   var onKeyDown;
   2772   var onKeyUp;
   2773   var query = '';
   2774   var keyCodes = {
   2775     Up: 38,
   2776     Down: 40
   2777   };
   2778   cm.openDialog = function(template, callback, options) {
   2779     onKeyUp = options.onKeyUp;
   2780     onKeyDown = options.onKeyDown;
   2781   };
   2782   var close = function(newVal) {
   2783     if (typeof newVal == 'string') query = newVal;
   2784   }
   2785   helpers.doKeys('/');
   2786   onKeyDown({keyCode: keyCodes.Up}, query, close);
   2787   onKeyUp({keyCode: keyCodes.Up}, query, close);
   2788   eq(query, 'checks');
   2789   onKeyDown({keyCode: keyCodes.Up}, query, close);
   2790   onKeyUp({keyCode: keyCodes.Up}, query, close);
   2791   eq(query, 'history');
   2792   onKeyDown({keyCode: keyCodes.Up}, query, close);
   2793   onKeyUp({keyCode: keyCodes.Up}, query, close);
   2794   eq(query, 'search');
   2795   onKeyDown({keyCode: keyCodes.Up}, query, close);
   2796   onKeyUp({keyCode: keyCodes.Up}, query, close);
   2797   eq(query, 'this');
   2798   onKeyDown({keyCode: keyCodes.Down}, query, close);
   2799   onKeyUp({keyCode: keyCodes.Down}, query, close);
   2800   eq(query, 'search');
   2801 }, {value: ''});
   2802 testVim('exCommand_history', function(cm, vim, helpers) {
   2803   cm.openDialog = helpers.fakeOpenDialog('registers');
   2804   helpers.doKeys(':');
   2805   cm.openDialog = helpers.fakeOpenDialog('sort');
   2806   helpers.doKeys(':');
   2807   cm.openDialog = helpers.fakeOpenDialog('map');
   2808   helpers.doKeys(':');
   2809   cm.openDialog = helpers.fakeOpenDialog('invalid');
   2810   helpers.doKeys(':');
   2811   var onKeyDown;
   2812   var onKeyUp;
   2813   var input = '';
   2814   var keyCodes = {
   2815     Up: 38,
   2816     Down: 40,
   2817     s: 115
   2818   };
   2819   cm.openDialog = function(template, callback, options) {
   2820     onKeyUp = options.onKeyUp;
   2821     onKeyDown = options.onKeyDown;
   2822   };
   2823   var close = function(newVal) {
   2824     if (typeof newVal == 'string') input = newVal;
   2825   }
   2826   helpers.doKeys(':');
   2827   onKeyDown({keyCode: keyCodes.Up}, input, close);
   2828   eq(input, 'invalid');
   2829   onKeyDown({keyCode: keyCodes.Up}, input, close);
   2830   eq(input, 'map');
   2831   onKeyDown({keyCode: keyCodes.Up}, input, close);
   2832   eq(input, 'sort');
   2833   onKeyDown({keyCode: keyCodes.Up}, input, close);
   2834   eq(input, 'registers');
   2835   onKeyDown({keyCode: keyCodes.s}, '', close);
   2836   input = 's';
   2837   onKeyDown({keyCode: keyCodes.Up}, input, close);
   2838   eq(input, 'sort');
   2839 }, {value: ''});
   2840 testVim('search_clear', function(cm, vim, helpers) {
   2841   var onKeyDown;
   2842   var input = '';
   2843   var keyCodes = {
   2844     Ctrl: 17,
   2845     u: 85
   2846   };
   2847   cm.openDialog = function(template, callback, options) {
   2848     onKeyDown = options.onKeyDown;
   2849   };
   2850   var close = function(newVal) {
   2851     if (typeof newVal == 'string') input = newVal;
   2852   }
   2853   helpers.doKeys('/');
   2854   input = 'foo';
   2855   onKeyDown({keyCode: keyCodes.Ctrl}, input, close);
   2856   onKeyDown({keyCode: keyCodes.u, ctrlKey: true}, input, close);
   2857   eq(input, '');
   2858 });
   2859 testVim('exCommand_clear', function(cm, vim, helpers) {
   2860   var onKeyDown;
   2861   var input = '';
   2862   var keyCodes = {
   2863     Ctrl: 17,
   2864     u: 85
   2865   };
   2866   cm.openDialog = function(template, callback, options) {
   2867     onKeyDown = options.onKeyDown;
   2868   };
   2869   var close = function(newVal) {
   2870     if (typeof newVal == 'string') input = newVal;
   2871   }
   2872   helpers.doKeys(':');
   2873   input = 'foo';
   2874   onKeyDown({keyCode: keyCodes.Ctrl}, input, close);
   2875   onKeyDown({keyCode: keyCodes.u, ctrlKey: true}, input, close);
   2876   eq(input, '');
   2877 });
   2878 testVim('.', function(cm, vim, helpers) {
   2879   cm.setCursor(0, 0);
   2880   helpers.doKeys('2', 'd', 'w');
   2881   helpers.doKeys('.');
   2882   eq('5 6', cm.getValue());
   2883 }, { value: '1 2 3 4 5 6'});
   2884 testVim('._repeat', function(cm, vim, helpers) {
   2885   cm.setCursor(0, 0);
   2886   helpers.doKeys('2', 'd', 'w');
   2887   helpers.doKeys('3', '.');
   2888   eq('6', cm.getValue());
   2889 }, { value: '1 2 3 4 5 6'});
   2890 testVim('._insert', function(cm, vim, helpers) {
   2891   helpers.doKeys('i');
   2892   cm.replaceRange('test', cm.getCursor());
   2893   helpers.doKeys('<Esc>');
   2894   helpers.doKeys('.');
   2895   eq('testestt', cm.getValue());
   2896   helpers.assertCursorAt(0, 6);
   2897   helpers.doKeys('O');
   2898   cm.replaceRange('xyz', cm.getCursor());
   2899   helpers.doInsertModeKeys('Backspace');
   2900   helpers.doInsertModeKeys('Down');
   2901   helpers.doKeys('<Esc>');
   2902   helpers.doKeys('.');
   2903   eq('xy\nxy\ntestestt', cm.getValue());
   2904   helpers.assertCursorAt(1, 1);
   2905 }, { value: ''});
   2906 testVim('._insert_repeat', function(cm, vim, helpers) {
   2907   helpers.doKeys('i');
   2908   cm.replaceRange('test', cm.getCursor());
   2909   cm.setCursor(0, 4);
   2910   helpers.doKeys('<Esc>');
   2911   helpers.doKeys('2', '.');
   2912   eq('testesttestt', cm.getValue());
   2913   helpers.assertCursorAt(0, 10);
   2914 }, { value: ''});
   2915 testVim('._repeat_insert', function(cm, vim, helpers) {
   2916   helpers.doKeys('3', 'i');
   2917   cm.replaceRange('te', cm.getCursor());
   2918   cm.setCursor(0, 2);
   2919   helpers.doKeys('<Esc>');
   2920   helpers.doKeys('.');
   2921   eq('tetettetetee', cm.getValue());
   2922   helpers.assertCursorAt(0, 10);
   2923 }, { value: ''});
   2924 testVim('._insert_o', function(cm, vim, helpers) {
   2925   helpers.doKeys('o');
   2926   cm.replaceRange('z', cm.getCursor());
   2927   cm.setCursor(1, 1);
   2928   helpers.doKeys('<Esc>');
   2929   helpers.doKeys('.');
   2930   eq('\nz\nz', cm.getValue());
   2931   helpers.assertCursorAt(2, 0);
   2932 }, { value: ''});
   2933 testVim('._insert_o_repeat', function(cm, vim, helpers) {
   2934   helpers.doKeys('o');
   2935   cm.replaceRange('z', cm.getCursor());
   2936   helpers.doKeys('<Esc>');
   2937   cm.setCursor(1, 0);
   2938   helpers.doKeys('2', '.');
   2939   eq('\nz\nz\nz', cm.getValue());
   2940   helpers.assertCursorAt(3, 0);
   2941 }, { value: ''});
   2942 testVim('._insert_o_indent', function(cm, vim, helpers) {
   2943   helpers.doKeys('o');
   2944   cm.replaceRange('z', cm.getCursor());
   2945   helpers.doKeys('<Esc>');
   2946   cm.setCursor(1, 2);
   2947   helpers.doKeys('.');
   2948   eq('{\n  z\n  z', cm.getValue());
   2949   helpers.assertCursorAt(2, 2);
   2950 }, { value: '{'});
   2951 testVim('._insert_cw', function(cm, vim, helpers) {
   2952   helpers.doKeys('c', 'w');
   2953   cm.replaceRange('test', cm.getCursor());
   2954   helpers.doKeys('<Esc>');
   2955   cm.setCursor(0, 3);
   2956   helpers.doKeys('2', 'l');
   2957   helpers.doKeys('.');
   2958   eq('test test word3', cm.getValue());
   2959   helpers.assertCursorAt(0, 8);
   2960 }, { value: 'word1 word2 word3' });
   2961 testVim('._insert_cw_repeat', function(cm, vim, helpers) {
   2962   // For some reason, repeat cw in desktop VIM will does not repeat insert mode
   2963   // changes. Will conform to that behavior.
   2964   helpers.doKeys('c', 'w');
   2965   cm.replaceRange('test', cm.getCursor());
   2966   helpers.doKeys('<Esc>');
   2967   cm.setCursor(0, 4);
   2968   helpers.doKeys('l');
   2969   helpers.doKeys('2', '.');
   2970   eq('test test', cm.getValue());
   2971   helpers.assertCursorAt(0, 8);
   2972 }, { value: 'word1 word2 word3' });
   2973 testVim('._delete', function(cm, vim, helpers) {
   2974   cm.setCursor(0, 5);
   2975   helpers.doKeys('i');
   2976   helpers.doInsertModeKeys('Backspace');
   2977   helpers.doKeys('<Esc>');
   2978   helpers.doKeys('.');
   2979   eq('zace', cm.getValue());
   2980   helpers.assertCursorAt(0, 1);
   2981 }, { value: 'zabcde'});
   2982 testVim('._delete_repeat', function(cm, vim, helpers) {
   2983   cm.setCursor(0, 6);
   2984   helpers.doKeys('i');
   2985   helpers.doInsertModeKeys('Backspace');
   2986   helpers.doKeys('<Esc>');
   2987   helpers.doKeys('2', '.');
   2988   eq('zzce', cm.getValue());
   2989   helpers.assertCursorAt(0, 1);
   2990 }, { value: 'zzabcde'});
   2991 testVim('._visual_>', function(cm, vim, helpers) {
   2992   cm.setCursor(0, 0);
   2993   helpers.doKeys('V', 'j', '>');
   2994   cm.setCursor(2, 0)
   2995   helpers.doKeys('.');
   2996   eq('  1\n  2\n  3\n  4', cm.getValue());
   2997   helpers.assertCursorAt(2, 2);
   2998 }, { value: '1\n2\n3\n4'});
   2999 testVim('._replace_repeat', function(cm, vim, helpers) {
   3000   helpers.doKeys('R');
   3001   cm.replaceRange('123', cm.getCursor(), offsetCursor(cm.getCursor(), 0, 3));
   3002   cm.setCursor(0, 3);
   3003   helpers.doKeys('<Esc>');
   3004   helpers.doKeys('2', '.');
   3005   eq('12123123\nabcdefg', cm.getValue());
   3006   helpers.assertCursorAt(0, 7);
   3007   cm.setCursor(1, 0);
   3008   helpers.doKeys('.');
   3009   eq('12123123\n123123g', cm.getValue());
   3010   helpers.doKeys('l', '"', '.', 'p');
   3011   eq('12123123\n123123g123', cm.getValue());
   3012 }, { value: 'abcdef\nabcdefg'});
   3013 testVim('f;', function(cm, vim, helpers) {
   3014   cm.setCursor(0, 0);
   3015   helpers.doKeys('f', 'x');
   3016   helpers.doKeys(';');
   3017   helpers.doKeys('2', ';');
   3018   eq(9, cm.getCursor().ch);
   3019 }, { value: '01x3xx678x'});
   3020 testVim('F;', function(cm, vim, helpers) {
   3021   cm.setCursor(0, 8);
   3022   helpers.doKeys('F', 'x');
   3023   helpers.doKeys(';');
   3024   helpers.doKeys('2', ';');
   3025   eq(2, cm.getCursor().ch);
   3026 }, { value: '01x3xx6x8x'});
   3027 testVim('t;', function(cm, vim, helpers) {
   3028   cm.setCursor(0, 0);
   3029   helpers.doKeys('t', 'x');
   3030   helpers.doKeys(';');
   3031   helpers.doKeys('2', ';');
   3032   eq(8, cm.getCursor().ch);
   3033 }, { value: '01x3xx678x'});
   3034 testVim('T;', function(cm, vim, helpers) {
   3035   cm.setCursor(0, 9);
   3036   helpers.doKeys('T', 'x');
   3037   helpers.doKeys(';');
   3038   helpers.doKeys('2', ';');
   3039   eq(2, cm.getCursor().ch);
   3040 }, { value: '0xx3xx678x'});
   3041 testVim('f,', function(cm, vim, helpers) {
   3042   cm.setCursor(0, 6);
   3043   helpers.doKeys('f', 'x');
   3044   helpers.doKeys(',');
   3045   helpers.doKeys('2', ',');
   3046   eq(2, cm.getCursor().ch);
   3047 }, { value: '01x3xx678x'});
   3048 testVim('F,', function(cm, vim, helpers) {
   3049   cm.setCursor(0, 3);
   3050   helpers.doKeys('F', 'x');
   3051   helpers.doKeys(',');
   3052   helpers.doKeys('2', ',');
   3053   eq(9, cm.getCursor().ch);
   3054 }, { value: '01x3xx678x'});
   3055 testVim('t,', function(cm, vim, helpers) {
   3056   cm.setCursor(0, 6);
   3057   helpers.doKeys('t', 'x');
   3058   helpers.doKeys(',');
   3059   helpers.doKeys('2', ',');
   3060   eq(3, cm.getCursor().ch);
   3061 }, { value: '01x3xx678x'});
   3062 testVim('T,', function(cm, vim, helpers) {
   3063   cm.setCursor(0, 4);
   3064   helpers.doKeys('T', 'x');
   3065   helpers.doKeys(',');
   3066   helpers.doKeys('2', ',');
   3067   eq(8, cm.getCursor().ch);
   3068 }, { value: '01x3xx67xx'});
   3069 testVim('fd,;', function(cm, vim, helpers) {
   3070   cm.setCursor(0, 0);
   3071   helpers.doKeys('f', '4');
   3072   cm.setCursor(0, 0);
   3073   helpers.doKeys('d', ';');
   3074   eq('56789', cm.getValue());
   3075   helpers.doKeys('u');
   3076   cm.setCursor(0, 9);
   3077   helpers.doKeys('d', ',');
   3078   eq('01239', cm.getValue());
   3079 }, { value: '0123456789'});
   3080 testVim('Fd,;', function(cm, vim, helpers) {
   3081   cm.setCursor(0, 9);
   3082   helpers.doKeys('F', '4');
   3083   cm.setCursor(0, 9);
   3084   helpers.doKeys('d', ';');
   3085   eq('01239', cm.getValue());
   3086   helpers.doKeys('u');
   3087   cm.setCursor(0, 0);
   3088   helpers.doKeys('d', ',');
   3089   eq('56789', cm.getValue());
   3090 }, { value: '0123456789'});
   3091 testVim('td,;', function(cm, vim, helpers) {
   3092   cm.setCursor(0, 0);
   3093   helpers.doKeys('t', '4');
   3094   cm.setCursor(0, 0);
   3095   helpers.doKeys('d', ';');
   3096   eq('456789', cm.getValue());
   3097   helpers.doKeys('u');
   3098   cm.setCursor(0, 9);
   3099   helpers.doKeys('d', ',');
   3100   eq('012349', cm.getValue());
   3101 }, { value: '0123456789'});
   3102 testVim('Td,;', function(cm, vim, helpers) {
   3103   cm.setCursor(0, 9);
   3104   helpers.doKeys('T', '4');
   3105   cm.setCursor(0, 9);
   3106   helpers.doKeys('d', ';');
   3107   eq('012349', cm.getValue());
   3108   helpers.doKeys('u');
   3109   cm.setCursor(0, 0);
   3110   helpers.doKeys('d', ',');
   3111   eq('456789', cm.getValue());
   3112 }, { value: '0123456789'});
   3113 testVim('fc,;', function(cm, vim, helpers) {
   3114   cm.setCursor(0, 0);
   3115   helpers.doKeys('f', '4');
   3116   cm.setCursor(0, 0);
   3117   helpers.doKeys('c', ';', '<Esc>');
   3118   eq('56789', cm.getValue());
   3119   helpers.doKeys('u');
   3120   cm.setCursor(0, 9);
   3121   helpers.doKeys('c', ',');
   3122   eq('01239', cm.getValue());
   3123 }, { value: '0123456789'});
   3124 testVim('Fc,;', function(cm, vim, helpers) {
   3125   cm.setCursor(0, 9);
   3126   helpers.doKeys('F', '4');
   3127   cm.setCursor(0, 9);
   3128   helpers.doKeys('c', ';', '<Esc>');
   3129   eq('01239', cm.getValue());
   3130   helpers.doKeys('u');
   3131   cm.setCursor(0, 0);
   3132   helpers.doKeys('c', ',');
   3133   eq('56789', cm.getValue());
   3134 }, { value: '0123456789'});
   3135 testVim('tc,;', function(cm, vim, helpers) {
   3136   cm.setCursor(0, 0);
   3137   helpers.doKeys('t', '4');
   3138   cm.setCursor(0, 0);
   3139   helpers.doKeys('c', ';', '<Esc>');
   3140   eq('456789', cm.getValue());
   3141   helpers.doKeys('u');
   3142   cm.setCursor(0, 9);
   3143   helpers.doKeys('c', ',');
   3144   eq('012349', cm.getValue());
   3145 }, { value: '0123456789'});
   3146 testVim('Tc,;', function(cm, vim, helpers) {
   3147   cm.setCursor(0, 9);
   3148   helpers.doKeys('T', '4');
   3149   cm.setCursor(0, 9);
   3150   helpers.doKeys('c', ';', '<Esc>');
   3151   eq('012349', cm.getValue());
   3152   helpers.doKeys('u');
   3153   cm.setCursor(0, 0);
   3154   helpers.doKeys('c', ',');
   3155   eq('456789', cm.getValue());
   3156 }, { value: '0123456789'});
   3157 testVim('fy,;', function(cm, vim, helpers) {
   3158   cm.setCursor(0, 0);
   3159   helpers.doKeys('f', '4');
   3160   cm.setCursor(0, 0);
   3161   helpers.doKeys('y', ';', 'P');
   3162   eq('012340123456789', cm.getValue());
   3163   helpers.doKeys('u');
   3164   cm.setCursor(0, 9);
   3165   helpers.doKeys('y', ',', 'P');
   3166   eq('012345678456789', cm.getValue());
   3167 }, { value: '0123456789'});
   3168 testVim('Fy,;', function(cm, vim, helpers) {
   3169   cm.setCursor(0, 9);
   3170   helpers.doKeys('F', '4');
   3171   cm.setCursor(0, 9);
   3172   helpers.doKeys('y', ';', 'p');
   3173   eq('012345678945678', cm.getValue());
   3174   helpers.doKeys('u');
   3175   cm.setCursor(0, 0);
   3176   helpers.doKeys('y', ',', 'P');
   3177   eq('012340123456789', cm.getValue());
   3178 }, { value: '0123456789'});
   3179 testVim('ty,;', function(cm, vim, helpers) {
   3180   cm.setCursor(0, 0);
   3181   helpers.doKeys('t', '4');
   3182   cm.setCursor(0, 0);
   3183   helpers.doKeys('y', ';', 'P');
   3184   eq('01230123456789', cm.getValue());
   3185   helpers.doKeys('u');
   3186   cm.setCursor(0, 9);
   3187   helpers.doKeys('y', ',', 'p');
   3188   eq('01234567895678', cm.getValue());
   3189 }, { value: '0123456789'});
   3190 testVim('Ty,;', function(cm, vim, helpers) {
   3191   cm.setCursor(0, 9);
   3192   helpers.doKeys('T', '4');
   3193   cm.setCursor(0, 9);
   3194   helpers.doKeys('y', ';', 'p');
   3195   eq('01234567895678', cm.getValue());
   3196   helpers.doKeys('u');
   3197   cm.setCursor(0, 0);
   3198   helpers.doKeys('y', ',', 'P');
   3199   eq('01230123456789', cm.getValue());
   3200 }, { value: '0123456789'});
   3201 testVim('HML', function(cm, vim, helpers) {
   3202   var lines = 35;
   3203   var textHeight = cm.defaultTextHeight();
   3204   cm.setSize(600, lines*textHeight);
   3205   cm.setCursor(120, 0);
   3206   helpers.doKeys('H');
   3207   helpers.assertCursorAt(86, 2);
   3208   helpers.doKeys('L');
   3209   helpers.assertCursorAt(120, 4);
   3210   helpers.doKeys('M');
   3211   helpers.assertCursorAt(103,4);
   3212 }, { value: (function(){
   3213   var lines = new Array(100);
   3214   var upper = '  xx\n';
   3215   var lower = '    xx\n';
   3216   upper = lines.join(upper);
   3217   lower = lines.join(lower);
   3218   return upper + lower;
   3219 })()});
   3220 
   3221 var zVals = [];
   3222 forEach(['zb','zz','zt','z-','z.','z<CR>'], function(e, idx){
   3223   var lineNum = 250;
   3224   var lines = 35;
   3225   testVim(e, function(cm, vim, helpers) {
   3226     var k1 = e[0];
   3227     var k2 = e.substring(1);
   3228     var textHeight = cm.defaultTextHeight();
   3229     cm.setSize(600, lines*textHeight);
   3230     cm.setCursor(lineNum, 0);
   3231     helpers.doKeys(k1, k2);
   3232     zVals[idx] = cm.getScrollInfo().top;
   3233   }, { value: (function(){
   3234     return new Array(500).join('\n');
   3235   })()});
   3236 });
   3237 testVim('zb_to_bottom', function(cm, vim, helpers){
   3238   var lineNum = 250;
   3239   cm.setSize(600, 35*cm.defaultTextHeight());
   3240   cm.setCursor(lineNum, 0);
   3241   helpers.doKeys('z', 'b');
   3242   var scrollInfo = cm.getScrollInfo();
   3243   eq(scrollInfo.top + scrollInfo.clientHeight, cm.charCoords(Pos(lineNum, 0), 'local').bottom);
   3244 }, { value: (function(){
   3245   return new Array(500).join('\n');
   3246 })()});
   3247 testVim('zt_to_top', function(cm, vim, helpers){
   3248   var lineNum = 250;
   3249   cm.setSize(600, 35*cm.defaultTextHeight());
   3250   cm.setCursor(lineNum, 0);
   3251   helpers.doKeys('z', 't');
   3252   eq(cm.getScrollInfo().top, cm.charCoords(Pos(lineNum, 0), 'local').top);
   3253 }, { value: (function(){
   3254   return new Array(500).join('\n');
   3255 })()});
   3256 testVim('zb<zz', function(cm, vim, helpers){
   3257   eq(zVals[0]<zVals[1], true);
   3258 });
   3259 testVim('zz<zt', function(cm, vim, helpers){
   3260   eq(zVals[1]<zVals[2], true);
   3261 });
   3262 testVim('zb==z-', function(cm, vim, helpers){
   3263   eq(zVals[0], zVals[3]);
   3264 });
   3265 testVim('zz==z.', function(cm, vim, helpers){
   3266   eq(zVals[1], zVals[4]);
   3267 });
   3268 testVim('zt==z<CR>', function(cm, vim, helpers){
   3269   eq(zVals[2], zVals[5]);
   3270 });
   3271 
   3272 var moveTillCharacterSandbox =
   3273   'The quick brown fox \n';
   3274 testVim('moveTillCharacter', function(cm, vim, helpers){
   3275   cm.setCursor(0, 0);
   3276   // Search for the 'q'.
   3277   cm.openDialog = helpers.fakeOpenDialog('q');
   3278   helpers.doKeys('/');
   3279   eq(4, cm.getCursor().ch);
   3280   // Jump to just before the first o in the list.
   3281   helpers.doKeys('t');
   3282   helpers.doKeys('o');
   3283   eq('The quick brown fox \n', cm.getValue());
   3284   // Delete that one character.
   3285   helpers.doKeys('d');
   3286   helpers.doKeys('t');
   3287   helpers.doKeys('o');
   3288   eq('The quick bown fox \n', cm.getValue());
   3289   // Delete everything until the next 'o'.
   3290   helpers.doKeys('.');
   3291   eq('The quick box \n', cm.getValue());
   3292   // An unmatched character should have no effect.
   3293   helpers.doKeys('d');
   3294   helpers.doKeys('t');
   3295   helpers.doKeys('q');
   3296   eq('The quick box \n', cm.getValue());
   3297   // Matches should only be possible on single lines.
   3298   helpers.doKeys('d');
   3299   helpers.doKeys('t');
   3300   helpers.doKeys('z');
   3301   eq('The quick box \n', cm.getValue());
   3302   // After all that, the search for 'q' should still be active, so the 'N' command
   3303   // can run it again in reverse. Use that to delete everything back to the 'q'.
   3304   helpers.doKeys('d');
   3305   helpers.doKeys('N');
   3306   eq('The ox \n', cm.getValue());
   3307   eq(4, cm.getCursor().ch);
   3308 }, { value: moveTillCharacterSandbox});
   3309 testVim('searchForPipe', function(cm, vim, helpers){
   3310   CodeMirror.Vim.setOption('pcre', false);
   3311   cm.setCursor(0, 0);
   3312   // Search for the '|'.
   3313   cm.openDialog = helpers.fakeOpenDialog('|');
   3314   helpers.doKeys('/');
   3315   eq(4, cm.getCursor().ch);
   3316 }, { value: 'this|that'});
   3317 
   3318 
   3319 var scrollMotionSandbox =
   3320   '\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n';
   3321 testVim('scrollMotion', function(cm, vim, helpers){
   3322   var prevCursor, prevScrollInfo;
   3323   cm.setCursor(0, 0);
   3324   // ctrl-y at the top of the file should have no effect.
   3325   helpers.doKeys('<C-y>');
   3326   eq(0, cm.getCursor().line);
   3327   prevScrollInfo = cm.getScrollInfo();
   3328   helpers.doKeys('<C-e>');
   3329   eq(1, cm.getCursor().line);
   3330   is(prevScrollInfo.top < cm.getScrollInfo().top);
   3331   // Jump to the end of the sandbox.
   3332   cm.setCursor(1000, 0);
   3333   prevCursor = cm.getCursor();
   3334   // ctrl-e at the bottom of the file should have no effect.
   3335   helpers.doKeys('<C-e>');
   3336   eq(prevCursor.line, cm.getCursor().line);
   3337   prevScrollInfo = cm.getScrollInfo();
   3338   helpers.doKeys('<C-y>');
   3339   eq(prevCursor.line - 1, cm.getCursor().line, "Y");
   3340   is(prevScrollInfo.top > cm.getScrollInfo().top);
   3341 }, { value: scrollMotionSandbox});
   3342 
   3343 var squareBracketMotionSandbox = ''+
   3344   '({\n'+//0
   3345   '  ({\n'+//11
   3346   '  /*comment {\n'+//2
   3347   '            */(\n'+//3
   3348   '#else                \n'+//4
   3349   '  /*       )\n'+//5
   3350   '#if        }\n'+//6
   3351   '  )}*/\n'+//7
   3352   ')}\n'+//8
   3353   '{}\n'+//9
   3354   '#else {{\n'+//10
   3355   '{}\n'+//11
   3356   '}\n'+//12
   3357   '{\n'+//13
   3358   '#endif\n'+//14
   3359   '}\n'+//15
   3360   '}\n'+//16
   3361   '#else';//17
   3362 testVim('[[, ]]', function(cm, vim, helpers) {
   3363   cm.setCursor(0, 0);
   3364   helpers.doKeys(']', ']');
   3365   helpers.assertCursorAt(9,0);
   3366   helpers.doKeys('2', ']', ']');
   3367   helpers.assertCursorAt(13,0);
   3368   helpers.doKeys(']', ']');
   3369   helpers.assertCursorAt(17,0);
   3370   helpers.doKeys('[', '[');
   3371   helpers.assertCursorAt(13,0);
   3372   helpers.doKeys('2', '[', '[');
   3373   helpers.assertCursorAt(9,0);
   3374   helpers.doKeys('[', '[');
   3375   helpers.assertCursorAt(0,0);
   3376 }, { value: squareBracketMotionSandbox});
   3377 testVim('[], ][', function(cm, vim, helpers) {
   3378   cm.setCursor(0, 0);
   3379   helpers.doKeys(']', '[');
   3380   helpers.assertCursorAt(12,0);
   3381   helpers.doKeys('2', ']', '[');
   3382   helpers.assertCursorAt(16,0);
   3383   helpers.doKeys(']', '[');
   3384   helpers.assertCursorAt(17,0);
   3385   helpers.doKeys('[', ']');
   3386   helpers.assertCursorAt(16,0);
   3387   helpers.doKeys('2', '[', ']');
   3388   helpers.assertCursorAt(12,0);
   3389   helpers.doKeys('[', ']');
   3390   helpers.assertCursorAt(0,0);
   3391 }, { value: squareBracketMotionSandbox});
   3392 testVim('[{, ]}', function(cm, vim, helpers) {
   3393   cm.setCursor(4, 10);
   3394   helpers.doKeys('[', '{');
   3395   helpers.assertCursorAt(2,12);
   3396   helpers.doKeys('2', '[', '{');
   3397   helpers.assertCursorAt(0,1);
   3398   cm.setCursor(4, 10);
   3399   helpers.doKeys(']', '}');
   3400   helpers.assertCursorAt(6,11);
   3401   helpers.doKeys('2', ']', '}');
   3402   helpers.assertCursorAt(8,1);
   3403   cm.setCursor(0,1);
   3404   helpers.doKeys(']', '}');
   3405   helpers.assertCursorAt(8,1);
   3406   helpers.doKeys('[', '{');
   3407   helpers.assertCursorAt(0,1);
   3408 }, { value: squareBracketMotionSandbox});
   3409 testVim('[(, ])', function(cm, vim, helpers) {
   3410   cm.setCursor(4, 10);
   3411   helpers.doKeys('[', '(');
   3412   helpers.assertCursorAt(3,14);
   3413   helpers.doKeys('2', '[', '(');
   3414   helpers.assertCursorAt(0,0);
   3415   cm.setCursor(4, 10);
   3416   helpers.doKeys(']', ')');
   3417   helpers.assertCursorAt(5,11);
   3418   helpers.doKeys('2', ']', ')');
   3419   helpers.assertCursorAt(8,0);
   3420   helpers.doKeys('[', '(');
   3421   helpers.assertCursorAt(0,0);
   3422   helpers.doKeys(']', ')');
   3423   helpers.assertCursorAt(8,0);
   3424 }, { value: squareBracketMotionSandbox});
   3425 testVim('[*, ]*, [/, ]/', function(cm, vim, helpers) {
   3426   forEach(['*', '/'], function(key){
   3427     cm.setCursor(7, 0);
   3428     helpers.doKeys('2', '[', key);
   3429     helpers.assertCursorAt(2,2);
   3430     helpers.doKeys('2', ']', key);
   3431     helpers.assertCursorAt(7,5);
   3432   });
   3433 }, { value: squareBracketMotionSandbox});
   3434 testVim('[#, ]#', function(cm, vim, helpers) {
   3435   cm.setCursor(10, 3);
   3436   helpers.doKeys('2', '[', '#');
   3437   helpers.assertCursorAt(4,0);
   3438   helpers.doKeys('5', ']', '#');
   3439   helpers.assertCursorAt(17,0);
   3440   cm.setCursor(10, 3);
   3441   helpers.doKeys(']', '#');
   3442   helpers.assertCursorAt(14,0);
   3443 }, { value: squareBracketMotionSandbox});
   3444 testVim('[m, ]m, [M, ]M', function(cm, vim, helpers) {
   3445   cm.setCursor(11, 0);
   3446   helpers.doKeys('[', 'm');
   3447   helpers.assertCursorAt(10,7);
   3448   helpers.doKeys('4', '[', 'm');
   3449   helpers.assertCursorAt(1,3);
   3450   helpers.doKeys('5', ']', 'm');
   3451   helpers.assertCursorAt(11,0);
   3452   helpers.doKeys('[', 'M');
   3453   helpers.assertCursorAt(9,1);
   3454   helpers.doKeys('3', ']', 'M');
   3455   helpers.assertCursorAt(15,0);
   3456   helpers.doKeys('5', '[', 'M');
   3457   helpers.assertCursorAt(7,3);
   3458 }, { value: squareBracketMotionSandbox});
   3459 
   3460 testVim('i_indent_right', function(cm, vim, helpers) {
   3461   cm.setCursor(0, 3);
   3462   var expectedValue = '   word1\nword2\nword3 ';
   3463   helpers.doKeys('i', '<C-t>');
   3464   eq(expectedValue, cm.getValue());
   3465   helpers.assertCursorAt(0, 5);
   3466 }, { value: ' word1\nword2\nword3 ', indentUnit: 2 });
   3467 testVim('i_indent_left', function(cm, vim, helpers) {
   3468   cm.setCursor(0, 3);
   3469   var expectedValue = ' word1\nword2\nword3 ';
   3470   helpers.doKeys('i', '<C-d>');
   3471   eq(expectedValue, cm.getValue());
   3472   helpers.assertCursorAt(0, 1);
   3473 }, { value: '   word1\nword2\nword3 ', indentUnit: 2 });
   3474 
   3475 // Ex mode tests
   3476 testVim('ex_go_to_line', function(cm, vim, helpers) {
   3477   cm.setCursor(0, 0);
   3478   helpers.doEx('4');
   3479   helpers.assertCursorAt(3, 0);
   3480 }, { value: 'a\nb\nc\nd\ne\n'});
   3481 testVim('ex_go_to_mark', function(cm, vim, helpers) {
   3482   cm.setCursor(3, 0);
   3483   helpers.doKeys('m', 'a');
   3484   cm.setCursor(0, 0);
   3485   helpers.doEx('\'a');
   3486   helpers.assertCursorAt(3, 0);
   3487 }, { value: 'a\nb\nc\nd\ne\n'});
   3488 testVim('ex_go_to_line_offset', function(cm, vim, helpers) {
   3489   cm.setCursor(0, 0);
   3490   helpers.doEx('+3');
   3491   helpers.assertCursorAt(3, 0);
   3492   helpers.doEx('-1');
   3493   helpers.assertCursorAt(2, 0);
   3494   helpers.doEx('.2');
   3495   helpers.assertCursorAt(4, 0);
   3496   helpers.doEx('.-3');
   3497   helpers.assertCursorAt(1, 0);
   3498 }, { value: 'a\nb\nc\nd\ne\n'});
   3499 testVim('ex_go_to_mark_offset', function(cm, vim, helpers) {
   3500   cm.setCursor(2, 0);
   3501   helpers.doKeys('m', 'a');
   3502   cm.setCursor(0, 0);
   3503   helpers.doEx('\'a1');
   3504   helpers.assertCursorAt(3, 0);
   3505   helpers.doEx('\'a-1');
   3506   helpers.assertCursorAt(1, 0);
   3507   helpers.doEx('\'a+2');
   3508   helpers.assertCursorAt(4, 0);
   3509 }, { value: 'a\nb\nc\nd\ne\n'});
   3510 testVim('ex_write', function(cm, vim, helpers) {
   3511   var tmp = CodeMirror.commands.save;
   3512   var written;
   3513   var actualCm;
   3514   CodeMirror.commands.save = function(cm) {
   3515     written = true;
   3516     actualCm = cm;
   3517   };
   3518   // Test that w, wr, wri ... write all trigger :write.
   3519   var command = 'write';
   3520   for (var i = 1; i < command.length; i++) {
   3521     written = false;
   3522     actualCm = null;
   3523     helpers.doEx(command.substring(0, i));
   3524     eq(written, true);
   3525     eq(actualCm, cm);
   3526   }
   3527   CodeMirror.commands.save = tmp;
   3528 });
   3529 testVim('ex_sort', function(cm, vim, helpers) {
   3530   helpers.doEx('sort');
   3531   eq('Z\na\nb\nc\nd', cm.getValue());
   3532 }, { value: 'b\nZ\nd\nc\na'});
   3533 testVim('ex_sort_reverse', function(cm, vim, helpers) {
   3534   helpers.doEx('sort!');
   3535   eq('d\nc\nb\na', cm.getValue());
   3536 }, { value: 'b\nd\nc\na'});
   3537 testVim('ex_sort_range', function(cm, vim, helpers) {
   3538   helpers.doEx('2,3sort');
   3539   eq('b\nc\nd\na', cm.getValue());
   3540 }, { value: 'b\nd\nc\na'});
   3541 testVim('ex_sort_oneline', function(cm, vim, helpers) {
   3542   helpers.doEx('2sort');
   3543   // Expect no change.
   3544   eq('b\nd\nc\na', cm.getValue());
   3545 }, { value: 'b\nd\nc\na'});
   3546 testVim('ex_sort_ignoreCase', function(cm, vim, helpers) {
   3547   helpers.doEx('sort i');
   3548   eq('a\nb\nc\nd\nZ', cm.getValue());
   3549 }, { value: 'b\nZ\nd\nc\na'});
   3550 testVim('ex_sort_unique', function(cm, vim, helpers) {
   3551   helpers.doEx('sort u');
   3552   eq('Z\na\nb\nc\nd', cm.getValue());
   3553 }, { value: 'b\nZ\na\na\nd\na\nc\na'});
   3554 testVim('ex_sort_decimal', function(cm, vim, helpers) {
   3555   helpers.doEx('sort d');
   3556   eq('d3\n s5\n6\n.9', cm.getValue());
   3557 }, { value: '6\nd3\n s5\n.9'});
   3558 testVim('ex_sort_decimal_negative', function(cm, vim, helpers) {
   3559   helpers.doEx('sort d');
   3560   eq('z-9\nd3\n s5\n6\n.9', cm.getValue());
   3561 }, { value: '6\nd3\n s5\n.9\nz-9'});
   3562 testVim('ex_sort_decimal_reverse', function(cm, vim, helpers) {
   3563   helpers.doEx('sort! d');
   3564   eq('.9\n6\n s5\nd3', cm.getValue());
   3565 }, { value: '6\nd3\n s5\n.9'});
   3566 testVim('ex_sort_hex', function(cm, vim, helpers) {
   3567   helpers.doEx('sort x');
   3568   eq(' s5\n6\n.9\n&0xB\nd3', cm.getValue());
   3569 }, { value: '6\nd3\n s5\n&0xB\n.9'});
   3570 testVim('ex_sort_octal', function(cm, vim, helpers) {
   3571   helpers.doEx('sort o');
   3572   eq('.9\n.8\nd3\n s5\n6', cm.getValue());
   3573 }, { value: '6\nd3\n s5\n.9\n.8'});
   3574 testVim('ex_sort_decimal_mixed', function(cm, vim, helpers) {
   3575   helpers.doEx('sort d');
   3576   eq('z\ny\nc1\nb2\na3', cm.getValue());
   3577 }, { value: 'a3\nz\nc1\ny\nb2'});
   3578 testVim('ex_sort_decimal_mixed_reverse', function(cm, vim, helpers) {
   3579   helpers.doEx('sort! d');
   3580   eq('a3\nb2\nc1\nz\ny', cm.getValue());
   3581 }, { value: 'a3\nz\nc1\ny\nb2'});
   3582 testVim('ex_sort_pattern_alpha', function(cm, vim, helpers) {
   3583   helpers.doEx('sort /[a-z]/');
   3584   eq('a3\nb2\nc1\ny\nz', cm.getValue());
   3585 }, { value: 'z\ny\nc1\nb2\na3'});
   3586 testVim('ex_sort_pattern_alpha_reverse', function(cm, vim, helpers) {
   3587   helpers.doEx('sort! /[a-z]/');
   3588   eq('z\ny\nc1\nb2\na3', cm.getValue());
   3589 }, { value: 'z\ny\nc1\nb2\na3'});
   3590 testVim('ex_sort_pattern_alpha_ignoreCase', function(cm, vim, helpers) {
   3591   helpers.doEx('sort i/[a-z]/');
   3592   eq('a3\nb2\nC1\nY\nz', cm.getValue());
   3593 }, { value: 'z\nY\nC1\nb2\na3'});
   3594 testVim('ex_sort_pattern_alpha_longer', function(cm, vim, helpers) {
   3595   helpers.doEx('sort /[a-z]+/');
   3596   eq('a\naa\nab\nade\nadele\nadelle\nadriana\nalex\nalexandra\nb\nc\ny\nz', cm.getValue());
   3597 }, { value: 'z\nab\naa\nade\nadelle\nalexandra\nalex\nadriana\nadele\ny\nc\nb\na'});
   3598 testVim('ex_sort_pattern_alpha_only', function(cm, vim, helpers) {
   3599   helpers.doEx('sort /^[a-z]$/');
   3600   eq('z1\ny2\na3\nb\nc', cm.getValue());
   3601 }, { value: 'z1\ny2\na3\nc\nb'});
   3602 testVim('ex_sort_pattern_alpha_only_reverse', function(cm, vim, helpers) {
   3603   helpers.doEx('sort! /^[a-z]$/');
   3604   eq('c\nb\nz1\ny2\na3', cm.getValue());
   3605 }, { value: 'z1\ny2\na3\nc\nb'});
   3606 testVim('ex_sort_pattern_alpha_num', function(cm, vim, helpers) {
   3607   helpers.doEx('sort /[a-z][0-9]/');
   3608   eq('c\nb\na3\ny2\nz1', cm.getValue());
   3609 }, { value: 'z1\ny2\na3\nc\nb'});
   3610 // test for :global command
   3611 testVim('ex_global', function(cm, vim, helpers) {
   3612   cm.setCursor(0, 0);
   3613   helpers.doEx('g/one/s//two');
   3614   eq('two two\n two two\n two two', cm.getValue());
   3615   helpers.doEx('1,2g/two/s//one');
   3616   eq('one one\n one one\n two two', cm.getValue());
   3617 }, {value: 'one one\n one one\n one one'});
   3618 testVim('ex_global_confirm', function(cm, vim, helpers) {
   3619   cm.setCursor(0, 0);
   3620   var onKeyDown;
   3621   var openDialogSave = cm.openDialog;
   3622   var KEYCODES = {
   3623     a: 65,
   3624     n: 78,
   3625     q: 81,
   3626     y: 89
   3627   };
   3628   // Intercept the ex command, 'global'
   3629   cm.openDialog = function(template, callback, options) {
   3630     // Intercept the prompt for the embedded ex command, 'substitute'
   3631     cm.openDialog = function(template, callback, options) {
   3632       onKeyDown = options.onKeyDown;
   3633     };
   3634     callback('g/one/s//two/gc');
   3635   };
   3636   helpers.doKeys(':');
   3637   var close = function() {};
   3638   onKeyDown({keyCode: KEYCODES.n}, '', close);
   3639   onKeyDown({keyCode: KEYCODES.y}, '', close);
   3640   onKeyDown({keyCode: KEYCODES.a}, '', close);
   3641   onKeyDown({keyCode: KEYCODES.q}, '', close);
   3642   onKeyDown({keyCode: KEYCODES.y}, '', close);
   3643   eq('one two\n two two\n one one\n two one\n one one', cm.getValue());
   3644 }, {value: 'one one\n one one\n one one\n one one\n one one'});
   3645 // Basic substitute tests.
   3646 testVim('ex_substitute_same_line', function(cm, vim, helpers) {
   3647   cm.setCursor(1, 0);
   3648   helpers.doEx('s/one/two/g');
   3649   eq('one one\n two two', cm.getValue());
   3650 }, { value: 'one one\n one one'});
   3651 testVim('ex_substitute_full_file', function(cm, vim, helpers) {
   3652   cm.setCursor(1, 0);
   3653   helpers.doEx('%s/one/two/g');
   3654   eq('two two\n two two', cm.getValue());
   3655 }, { value: 'one one\n one one'});
   3656 testVim('ex_substitute_input_range', function(cm, vim, helpers) {
   3657   cm.setCursor(1, 0);
   3658   helpers.doEx('1,3s/\\d/0/g');
   3659   eq('0\n0\n0\n4', cm.getValue());
   3660 }, { value: '1\n2\n3\n4' });
   3661 testVim('ex_substitute_range_current_to_input', function(cm, vim, helpers) {
   3662   cm.setCursor(1, 0);
   3663   helpers.doEx('.,3s/\\d/0/g');
   3664   eq('1\n0\n0\n4', cm.getValue());
   3665 }, { value: '1\n2\n3\n4' });
   3666 testVim('ex_substitute_range_input_to_current', function(cm, vim, helpers) {
   3667   cm.setCursor(3, 0);
   3668   helpers.doEx('2,.s/\\d/0/g');
   3669   eq('1\n0\n0\n0\n5', cm.getValue());
   3670 }, { value: '1\n2\n3\n4\n5' });
   3671 testVim('ex_substitute_range_offset', function(cm, vim, helpers) {
   3672   cm.setCursor(2, 0);
   3673   helpers.doEx('-1,+1s/\\d/0/g');
   3674   eq('1\n0\n0\n0\n5', cm.getValue());
   3675 }, { value: '1\n2\n3\n4\n5' });
   3676 testVim('ex_substitute_range_implicit_offset', function(cm, vim, helpers) {
   3677   cm.setCursor(0, 0);
   3678   helpers.doEx('.1,.3s/\\d/0/g');
   3679   eq('1\n0\n0\n0\n5', cm.getValue());
   3680 }, { value: '1\n2\n3\n4\n5' });
   3681 testVim('ex_substitute_to_eof', function(cm, vim, helpers) {
   3682   cm.setCursor(2, 0);
   3683   helpers.doEx('.,$s/\\d/0/g');
   3684   eq('1\n2\n0\n0\n0', cm.getValue());
   3685 }, { value: '1\n2\n3\n4\n5' });
   3686 testVim('ex_substitute_to_relative_eof', function(cm, vim, helpers) {
   3687   cm.setCursor(4, 0);
   3688   helpers.doEx('2,$-2s/\\d/0/g');
   3689   eq('1\n0\n0\n4\n5', cm.getValue());
   3690 }, { value: '1\n2\n3\n4\n5' });
   3691 testVim('ex_substitute_range_mark', function(cm, vim, helpers) {
   3692   cm.setCursor(2, 0);
   3693   helpers.doKeys('ma');
   3694   cm.setCursor(0, 0);
   3695   helpers.doEx('.,\'as/\\d/0/g');
   3696   eq('0\n0\n0\n4\n5', cm.getValue());
   3697 }, { value: '1\n2\n3\n4\n5' });
   3698 testVim('ex_substitute_range_mark_offset', function(cm, vim, helpers) {
   3699   cm.setCursor(2, 0);
   3700   helpers.doKeys('ma');
   3701   cm.setCursor(0, 0);
   3702   helpers.doEx('\'a-1,\'a+1s/\\d/0/g');
   3703   eq('1\n0\n0\n0\n5', cm.getValue());
   3704 }, { value: '1\n2\n3\n4\n5' });
   3705 testVim('ex_substitute_visual_range', function(cm, vim, helpers) {
   3706   cm.setCursor(1, 0);
   3707   // Set last visual mode selection marks '< and '> at lines 2 and 4
   3708   helpers.doKeys('V', '2', 'j', 'v');
   3709   helpers.doEx('\'<,\'>s/\\d/0/g');
   3710   eq('1\n0\n0\n0\n5', cm.getValue());
   3711 }, { value: '1\n2\n3\n4\n5' });
   3712 testVim('ex_substitute_empty_query', function(cm, vim, helpers) {
   3713   // If the query is empty, use last query.
   3714   cm.setCursor(1, 0);
   3715   cm.openDialog = helpers.fakeOpenDialog('1');
   3716   helpers.doKeys('/');
   3717   helpers.doEx('s//b/g');
   3718   eq('abb ab2 ab3', cm.getValue());
   3719 }, { value: 'a11 a12 a13' });
   3720 testVim('ex_substitute_javascript', function(cm, vim, helpers) {
   3721   CodeMirror.Vim.setOption('pcre', false);
   3722   cm.setCursor(1, 0);
   3723   // Throw all the things that javascript likes to treat as special values
   3724   // into the replace part. All should be literal (this is VIM).
   3725   helpers.doEx('s/\\(\\d+\\)/$$ $\' $` $& \\1/g')
   3726   eq('a $$ $\' $` $& 0 b', cm.getValue());
   3727 }, { value: 'a 0 b' });
   3728 testVim('ex_substitute_empty_arguments', function(cm,vim,helpers) {
   3729   cm.setCursor(0, 0);
   3730   helpers.doEx('s/a/b/g');
   3731   cm.setCursor(1, 0);
   3732   helpers.doEx('s');
   3733   eq('b b\nb a', cm.getValue());
   3734 }, {value: 'a a\na a'});
   3735 
   3736 // More complex substitute tests that test both pcre and nopcre options.
   3737 function testSubstitute(name, options) {
   3738   testVim(name + '_pcre', function(cm, vim, helpers) {
   3739     cm.setCursor(1, 0);
   3740     CodeMirror.Vim.setOption('pcre', true);
   3741     helpers.doEx(options.expr);
   3742     eq(options.expectedValue, cm.getValue());
   3743   }, options);
   3744   // If no noPcreExpr is defined, assume that it's the same as the expr.
   3745   var noPcreExpr = options.noPcreExpr ? options.noPcreExpr : options.expr;
   3746   testVim(name + '_nopcre', function(cm, vim, helpers) {
   3747     cm.setCursor(1, 0);
   3748     CodeMirror.Vim.setOption('pcre', false);
   3749     helpers.doEx(noPcreExpr);
   3750     eq(options.expectedValue, cm.getValue());
   3751   }, options);
   3752 }
   3753 testSubstitute('ex_substitute_capture', {
   3754   value: 'a11 a12 a13',
   3755   expectedValue: 'a1111 a1212 a1313',
   3756   // $n is a backreference
   3757   expr: 's/(\\d+)/$1$1/g',
   3758   // \n is a backreference.
   3759   noPcreExpr: 's/\\(\\d+\\)/\\1\\1/g'});
   3760 testSubstitute('ex_substitute_capture2', {
   3761   value: 'a 0 b',
   3762   expectedValue: 'a $00 b',
   3763   expr: 's/(\\d+)/$$$1$1/g',
   3764   noPcreExpr: 's/\\(\\d+\\)/$\\1\\1/g'});
   3765 testSubstitute('ex_substitute_nocapture', {
   3766   value: 'a11 a12 a13',
   3767   expectedValue: 'a$1$1 a$1$1 a$1$1',
   3768   expr: 's/(\\d+)/$$1$$1/g',
   3769   noPcreExpr: 's/\\(\\d+\\)/$1$1/g'});
   3770 testSubstitute('ex_substitute_nocapture2', {
   3771   value: 'a 0 b',
   3772   expectedValue: 'a $10 b',
   3773   expr: 's/(\\d+)/$$1$1/g',
   3774   noPcreExpr: 's/\\(\\d+\\)/\\$1\\1/g'});
   3775 testSubstitute('ex_substitute_nocapture', {
   3776   value: 'a b c',
   3777   expectedValue: 'a $ c',
   3778   expr: 's/b/$$/',
   3779   noPcreExpr: 's/b/$/'});
   3780 testSubstitute('ex_substitute_slash_regex', {
   3781   value: 'one/two \n three/four',
   3782   expectedValue: 'one|two \n three|four',
   3783   expr: '%s/\\//|'});
   3784 testSubstitute('ex_substitute_pipe_regex', {
   3785   value: 'one|two \n three|four',
   3786   expectedValue: 'one,two \n three,four',
   3787   expr: '%s/\\|/,/',
   3788   noPcreExpr: '%s/|/,/'});
   3789 testSubstitute('ex_substitute_or_regex', {
   3790   value: 'one|two \n three|four',
   3791   expectedValue: 'ana|twa \n thraa|faar',
   3792   expr: '%s/o|e|u/a/g',
   3793   noPcreExpr: '%s/o\\|e\\|u/a/g'});
   3794 testSubstitute('ex_substitute_or_word_regex', {
   3795   value: 'one|two \n three|four',
   3796   expectedValue: 'five|five \n three|four',
   3797   expr: '%s/(one|two)/five/g',
   3798   noPcreExpr: '%s/\\(one\\|two\\)/five/g'});
   3799 testSubstitute('ex_substitute_backslashslash_regex', {
   3800   value: 'one\\two \n three\\four',
   3801   expectedValue: 'one,two \n three,four',
   3802   expr: '%s/\\\\/,'});
   3803 testSubstitute('ex_substitute_slash_replacement', {
   3804   value: 'one,two \n three,four',
   3805   expectedValue: 'one/two \n three/four',
   3806   expr: '%s/,/\\/'});
   3807 testSubstitute('ex_substitute_backslash_replacement', {
   3808   value: 'one,two \n three,four',
   3809   expectedValue: 'one\\two \n three\\four',
   3810   expr: '%s/,/\\\\/g'});
   3811 testSubstitute('ex_substitute_multibackslash_replacement', {
   3812   value: 'one,two \n three,four',
   3813   expectedValue: 'one\\\\\\\\two \n three\\\\\\\\four', // 2*8 backslashes.
   3814   expr: '%s/,/\\\\\\\\\\\\\\\\/g'}); // 16 backslashes.
   3815 testSubstitute('ex_substitute_dollar_match', {
   3816   value: 'one,two \n three,four',
   3817   expectedValue: 'one,two ,\n three,four',
   3818   expr: '%s/$/,/g'});
   3819 testSubstitute('ex_substitute_newline_match', {
   3820   value: 'one,two \n three,four',
   3821   expectedValue: 'one,two , three,four',
   3822   expr: '%s/\\n/,/g'});
   3823 testSubstitute('ex_substitute_newline_replacement', {
   3824   value: 'one,two \n three,four',
   3825   expectedValue: 'one\ntwo \n three\nfour',
   3826   expr: '%s/,/\\n/g'});
   3827 testSubstitute('ex_substitute_braces_word', {
   3828   value: 'ababab abb ab{2}',
   3829   expectedValue: 'ab abb ab{2}',
   3830   expr: '%s/(ab){2}//g',
   3831   noPcreExpr: '%s/\\(ab\\)\\{2\\}//g'});
   3832 testSubstitute('ex_substitute_braces_range', {
   3833   value: 'a aa aaa aaaa',
   3834   expectedValue: 'a   a',
   3835   expr: '%s/a{2,3}//g',
   3836   noPcreExpr: '%s/a\\{2,3\\}//g'});
   3837 testSubstitute('ex_substitute_braces_literal', {
   3838   value: 'ababab abb ab{2}',
   3839   expectedValue: 'ababab abb ',
   3840   expr: '%s/ab\\{2\\}//g',
   3841   noPcreExpr: '%s/ab{2}//g'});
   3842 testSubstitute('ex_substitute_braces_char', {
   3843   value: 'ababab abb ab{2}',
   3844   expectedValue: 'ababab  ab{2}',
   3845   expr: '%s/ab{2}//g',
   3846   noPcreExpr: '%s/ab\\{2\\}//g'});
   3847 testSubstitute('ex_substitute_braces_no_escape', {
   3848   value: 'ababab abb ab{2}',
   3849   expectedValue: 'ababab  ab{2}',
   3850   expr: '%s/ab{2}//g',
   3851   noPcreExpr: '%s/ab\\{2}//g'});
   3852 testSubstitute('ex_substitute_count', {
   3853   value: '1\n2\n3\n4',
   3854   expectedValue: '1\n0\n0\n4',
   3855   expr: 's/\\d/0/i 2'});
   3856 testSubstitute('ex_substitute_count_with_range', {
   3857   value: '1\n2\n3\n4',
   3858   expectedValue: '1\n2\n0\n0',
   3859   expr: '1,3s/\\d/0/ 3'});
   3860 testSubstitute('ex_substitute_not_global', {
   3861   value: 'aaa\nbaa\ncaa',
   3862   expectedValue: 'xaa\nbxa\ncxa',
   3863   expr: '%s/a/x/'});
   3864 function testSubstituteConfirm(name, command, initialValue, expectedValue, keys, finalPos) {
   3865   testVim(name, function(cm, vim, helpers) {
   3866     var savedOpenDialog = cm.openDialog;
   3867     var savedKeyName = CodeMirror.keyName;
   3868     var onKeyDown;
   3869     var recordedCallback;
   3870     var closed = true; // Start out closed, set false on second openDialog.
   3871     function close() {
   3872       closed = true;
   3873     }
   3874     // First openDialog should save callback.
   3875     cm.openDialog = function(template, callback, options) {
   3876       recordedCallback = callback;
   3877     }
   3878     // Do first openDialog.
   3879     helpers.doKeys(':');
   3880     // Second openDialog should save keyDown handler.
   3881     cm.openDialog = function(template, callback, options) {
   3882       onKeyDown = options.onKeyDown;
   3883       closed = false;
   3884     };
   3885     // Return the command to Vim and trigger second openDialog.
   3886     recordedCallback(command);
   3887     // The event should really use keyCode, but here just mock it out and use
   3888     // key and replace keyName to just return key.
   3889     CodeMirror.keyName = function (e) { return e.key; }
   3890     keys = keys.toUpperCase();
   3891     for (var i = 0; i < keys.length; i++) {
   3892       is(!closed);
   3893       onKeyDown({ key: keys.charAt(i) }, '', close);
   3894     }
   3895     try {
   3896       eq(expectedValue, cm.getValue());
   3897       helpers.assertCursorAt(finalPos);
   3898       is(closed);
   3899     } catch(e) {
   3900       throw e
   3901     } finally {
   3902       // Restore overridden functions.
   3903       CodeMirror.keyName = savedKeyName;
   3904       cm.openDialog = savedOpenDialog;
   3905     }
   3906   }, { value: initialValue });
   3907 };
   3908 testSubstituteConfirm('ex_substitute_confirm_emptydoc',
   3909     '%s/x/b/c', '', '', '', makeCursor(0, 0));
   3910 testSubstituteConfirm('ex_substitute_confirm_nomatch',
   3911     '%s/x/b/c', 'ba a\nbab', 'ba a\nbab', '', makeCursor(0, 0));
   3912 testSubstituteConfirm('ex_substitute_confirm_accept',
   3913     '%s/a/b/cg', 'ba a\nbab', 'bb b\nbbb', 'yyy', makeCursor(1, 1));
   3914 testSubstituteConfirm('ex_substitute_confirm_random_keys',
   3915     '%s/a/b/cg', 'ba a\nbab', 'bb b\nbbb', 'ysdkywerty', makeCursor(1, 1));
   3916 testSubstituteConfirm('ex_substitute_confirm_some',
   3917     '%s/a/b/cg', 'ba a\nbab', 'bb a\nbbb', 'yny', makeCursor(1, 1));
   3918 testSubstituteConfirm('ex_substitute_confirm_all',
   3919     '%s/a/b/cg', 'ba a\nbab', 'bb b\nbbb', 'a', makeCursor(1, 1));
   3920 testSubstituteConfirm('ex_substitute_confirm_accept_then_all',
   3921     '%s/a/b/cg', 'ba a\nbab', 'bb b\nbbb', 'ya', makeCursor(1, 1));
   3922 testSubstituteConfirm('ex_substitute_confirm_quit',
   3923     '%s/a/b/cg', 'ba a\nbab', 'bb a\nbab', 'yq', makeCursor(0, 3));
   3924 testSubstituteConfirm('ex_substitute_confirm_last',
   3925     '%s/a/b/cg', 'ba a\nbab', 'bb b\nbab', 'yl', makeCursor(0, 3));
   3926 testSubstituteConfirm('ex_substitute_confirm_oneline',
   3927     '1s/a/b/cg', 'ba a\nbab', 'bb b\nbab', 'yl', makeCursor(0, 3));
   3928 testSubstituteConfirm('ex_substitute_confirm_range_accept',
   3929     '1,2s/a/b/cg', 'aa\na \na\na', 'bb\nb \na\na', 'yyy', makeCursor(1, 0));
   3930 testSubstituteConfirm('ex_substitute_confirm_range_some',
   3931     '1,3s/a/b/cg', 'aa\na \na\na', 'ba\nb \nb\na', 'ynyy', makeCursor(2, 0));
   3932 testSubstituteConfirm('ex_substitute_confirm_range_all',
   3933     '1,3s/a/b/cg', 'aa\na \na\na', 'bb\nb \nb\na', 'a', makeCursor(2, 0));
   3934 testSubstituteConfirm('ex_substitute_confirm_range_last',
   3935     '1,3s/a/b/cg', 'aa\na \na\na', 'bb\nb \na\na', 'yyl', makeCursor(1, 0));
   3936 //:noh should clear highlighting of search-results but allow to resume search through n
   3937 testVim('ex_noh_clearSearchHighlight', function(cm, vim, helpers) {
   3938   cm.openDialog = helpers.fakeOpenDialog('match');
   3939   helpers.doKeys('?');
   3940   helpers.doEx('noh');
   3941   eq(vim.searchState_.getOverlay(),null,'match-highlighting wasn\'t cleared');
   3942   helpers.doKeys('n');
   3943   helpers.assertCursorAt(0, 11,'can\'t resume search after clearing highlighting');
   3944 }, { value: 'match nope match \n nope Match' });
   3945 testVim('ex_yank', function (cm, vim, helpers) {
   3946   var curStart = makeCursor(3, 0);
   3947   cm.setCursor(curStart);
   3948   helpers.doEx('y');
   3949   var register = helpers.getRegisterController().getRegister();
   3950   var line = cm.getLine(3);
   3951   eq(line + '\n', register.toString());
   3952 });
   3953 testVim('set_boolean', function(cm, vim, helpers) {
   3954   CodeMirror.Vim.defineOption('testoption', true, 'boolean');
   3955   // Test default value is set.
   3956   is(CodeMirror.Vim.getOption('testoption'));
   3957   try {
   3958     // Test fail to set to non-boolean
   3959     CodeMirror.Vim.setOption('testoption', '5');
   3960     fail();
   3961   } catch (expected) {}
   3962   // Test setOption
   3963   CodeMirror.Vim.setOption('testoption', false);
   3964   is(!CodeMirror.Vim.getOption('testoption'));
   3965 });
   3966 testVim('ex_set_boolean', function(cm, vim, helpers) {
   3967   CodeMirror.Vim.defineOption('testoption', true, 'boolean');
   3968   // Test default value is set.
   3969   is(CodeMirror.Vim.getOption('testoption'));
   3970   try {
   3971     // Test fail to set to non-boolean
   3972     helpers.doEx('set testoption=22');
   3973     fail();
   3974   } catch (expected) {}
   3975   // Test setOption
   3976   helpers.doEx('set notestoption');
   3977   is(!CodeMirror.Vim.getOption('testoption'));
   3978 });
   3979 testVim('set_string', function(cm, vim, helpers) {
   3980   CodeMirror.Vim.defineOption('testoption', 'a', 'string');
   3981   // Test default value is set.
   3982   eq('a', CodeMirror.Vim.getOption('testoption'));
   3983   try {
   3984     // Test fail to set non-string.
   3985     CodeMirror.Vim.setOption('testoption', true);
   3986     fail();
   3987   } catch (expected) {}
   3988   try {
   3989     // Test fail to set 'notestoption'
   3990     CodeMirror.Vim.setOption('notestoption', 'b');
   3991     fail();
   3992   } catch (expected) {}
   3993   // Test setOption
   3994   CodeMirror.Vim.setOption('testoption', 'c');
   3995   eq('c', CodeMirror.Vim.getOption('testoption'));
   3996 });
   3997 testVim('ex_set_string', function(cm, vim, helpers) {
   3998   CodeMirror.Vim.defineOption('testopt', 'a', 'string');
   3999   // Test default value is set.
   4000   eq('a', CodeMirror.Vim.getOption('testopt'));
   4001   try {
   4002     // Test fail to set 'notestopt'
   4003     helpers.doEx('set notestopt=b');
   4004     fail();
   4005   } catch (expected) {}
   4006   // Test setOption
   4007   helpers.doEx('set testopt=c')
   4008   eq('c', CodeMirror.Vim.getOption('testopt'));
   4009   helpers.doEx('set testopt=c')
   4010   eq('c', CodeMirror.Vim.getOption('testopt', cm)); //local || global
   4011   eq('c', CodeMirror.Vim.getOption('testopt', cm, {scope: 'local'})); // local
   4012   eq('c', CodeMirror.Vim.getOption('testopt', cm, {scope: 'global'})); // global
   4013   eq('c', CodeMirror.Vim.getOption('testopt')); // global
   4014   // Test setOption global
   4015   helpers.doEx('setg testopt=d')
   4016   eq('c', CodeMirror.Vim.getOption('testopt', cm));
   4017   eq('c', CodeMirror.Vim.getOption('testopt', cm, {scope: 'local'}));
   4018   eq('d', CodeMirror.Vim.getOption('testopt', cm, {scope: 'global'}));
   4019   eq('d', CodeMirror.Vim.getOption('testopt'));
   4020   // Test setOption local
   4021   helpers.doEx('setl testopt=e')
   4022   eq('e', CodeMirror.Vim.getOption('testopt', cm));
   4023   eq('e', CodeMirror.Vim.getOption('testopt', cm, {scope: 'local'}));
   4024   eq('d', CodeMirror.Vim.getOption('testopt', cm, {scope: 'global'}));
   4025   eq('d', CodeMirror.Vim.getOption('testopt'));
   4026 });
   4027 testVim('ex_set_callback', function(cm, vim, helpers) {
   4028   var global;
   4029 
   4030   function cb(val, cm, cfg) {
   4031     if (val === undefined) {
   4032       // Getter
   4033       if (cm) {
   4034         return cm._local;
   4035       } else {
   4036         return global;
   4037       }
   4038     } else {
   4039       // Setter
   4040       if (cm) {
   4041         cm._local = val;
   4042       } else {
   4043         global = val;
   4044       }
   4045     }
   4046   }
   4047 
   4048   CodeMirror.Vim.defineOption('testopt', 'a', 'string', cb);
   4049   // Test default value is set.
   4050   eq('a', CodeMirror.Vim.getOption('testopt'));
   4051   try {
   4052     // Test fail to set 'notestopt'
   4053     helpers.doEx('set notestopt=b');
   4054     fail();
   4055   } catch (expected) {}
   4056   // Test setOption (Identical to the string tests, but via callback instead)
   4057   helpers.doEx('set testopt=c')
   4058   eq('c', CodeMirror.Vim.getOption('testopt', cm)); //local || global
   4059   eq('c', CodeMirror.Vim.getOption('testopt', cm, {scope: 'local'})); // local
   4060   eq('c', CodeMirror.Vim.getOption('testopt', cm, {scope: 'global'})); // global
   4061   eq('c', CodeMirror.Vim.getOption('testopt')); // global
   4062   // Test setOption global
   4063   helpers.doEx('setg testopt=d')
   4064   eq('c', CodeMirror.Vim.getOption('testopt', cm));
   4065   eq('c', CodeMirror.Vim.getOption('testopt', cm, {scope: 'local'}));
   4066   eq('d', CodeMirror.Vim.getOption('testopt', cm, {scope: 'global'}));
   4067   eq('d', CodeMirror.Vim.getOption('testopt'));
   4068   // Test setOption local
   4069   helpers.doEx('setl testopt=e')
   4070   eq('e', CodeMirror.Vim.getOption('testopt', cm));
   4071   eq('e', CodeMirror.Vim.getOption('testopt', cm, {scope: 'local'}));
   4072   eq('d', CodeMirror.Vim.getOption('testopt', cm, {scope: 'global'}));
   4073   eq('d', CodeMirror.Vim.getOption('testopt'));
   4074 })
   4075 testVim('ex_set_filetype', function(cm, vim, helpers) {
   4076   CodeMirror.defineMode('test_mode', function() {
   4077     return {token: function(stream) {
   4078       stream.match(/^\s+|^\S+/);
   4079     }};
   4080   });
   4081   CodeMirror.defineMode('test_mode_2', function() {
   4082     return {token: function(stream) {
   4083       stream.match(/^\s+|^\S+/);
   4084     }};
   4085   });
   4086   // Test mode is set.
   4087   helpers.doEx('set filetype=test_mode');
   4088   eq('test_mode', cm.getMode().name);
   4089   // Test 'ft' alias also sets mode.
   4090   helpers.doEx('set ft=test_mode_2');
   4091   eq('test_mode_2', cm.getMode().name);
   4092 });
   4093 testVim('ex_set_filetype_null', function(cm, vim, helpers) {
   4094   CodeMirror.defineMode('test_mode', function() {
   4095     return {token: function(stream) {
   4096       stream.match(/^\s+|^\S+/);
   4097     }};
   4098   });
   4099   cm.setOption('mode', 'test_mode');
   4100   // Test mode is set to null.
   4101   helpers.doEx('set filetype=');
   4102   eq('null', cm.getMode().name);
   4103 });
   4104 // TODO: Reset key maps after each test.
   4105 testVim('ex_map_key2key', function(cm, vim, helpers) {
   4106   helpers.doEx('map a x');
   4107   helpers.doKeys('a');
   4108   helpers.assertCursorAt(0, 0);
   4109   eq('bc', cm.getValue());
   4110 }, { value: 'abc' });
   4111 testVim('ex_unmap_key2key', function(cm, vim, helpers) {
   4112   helpers.doEx('unmap a');
   4113   helpers.doKeys('a');
   4114   eq('vim-insert', cm.getOption('keyMap'));
   4115 }, { value: 'abc' });
   4116 testVim('ex_unmap_key2key_does_not_remove_default', function(cm, vim, helpers) {
   4117   try {
   4118     helpers.doEx('unmap a');
   4119     fail();
   4120   } catch (expected) {}
   4121   helpers.doKeys('a');
   4122   eq('vim-insert', cm.getOption('keyMap'));
   4123 }, { value: 'abc' });
   4124 testVim('ex_map_key2key_to_colon', function(cm, vim, helpers) {
   4125   helpers.doEx('map ; :');
   4126   var dialogOpened = false;
   4127   cm.openDialog = function() {
   4128     dialogOpened = true;
   4129   }
   4130   helpers.doKeys(';');
   4131   eq(dialogOpened, true);
   4132 });
   4133 testVim('ex_map_ex2key:', function(cm, vim, helpers) {
   4134   helpers.doEx('map :del x');
   4135   helpers.doEx('del');
   4136   helpers.assertCursorAt(0, 0);
   4137   eq('bc', cm.getValue());
   4138 }, { value: 'abc' });
   4139 testVim('ex_map_ex2ex', function(cm, vim, helpers) {
   4140   helpers.doEx('map :del :w');
   4141   var tmp = CodeMirror.commands.save;
   4142   var written = false;
   4143   var actualCm;
   4144   CodeMirror.commands.save = function(cm) {
   4145     written = true;
   4146     actualCm = cm;
   4147   };
   4148   helpers.doEx('del');
   4149   CodeMirror.commands.save = tmp;
   4150   eq(written, true);
   4151   eq(actualCm, cm);
   4152 });
   4153 testVim('ex_map_key2ex', function(cm, vim, helpers) {
   4154   helpers.doEx('map a :w');
   4155   var tmp = CodeMirror.commands.save;
   4156   var written = false;
   4157   var actualCm;
   4158   CodeMirror.commands.save = function(cm) {
   4159     written = true;
   4160     actualCm = cm;
   4161   };
   4162   helpers.doKeys('a');
   4163   CodeMirror.commands.save = tmp;
   4164   eq(written, true);
   4165   eq(actualCm, cm);
   4166 });
   4167 testVim('ex_map_key2key_visual_api', function(cm, vim, helpers) {
   4168   CodeMirror.Vim.map('b', ':w', 'visual');
   4169   var tmp = CodeMirror.commands.save;
   4170   var written = false;
   4171   var actualCm;
   4172   CodeMirror.commands.save = function(cm) {
   4173     written = true;
   4174     actualCm = cm;
   4175   };
   4176   // Mapping should not work in normal mode.
   4177   helpers.doKeys('b');
   4178   eq(written, false);
   4179   // Mapping should work in visual mode.
   4180   helpers.doKeys('v', 'b');
   4181   eq(written, true);
   4182   eq(actualCm, cm);
   4183 
   4184   CodeMirror.commands.save = tmp;
   4185 });
   4186 testVim('ex_imap', function(cm, vim, helpers) {
   4187   CodeMirror.Vim.map('jk', '<Esc>', 'insert');
   4188   helpers.doKeys('i');
   4189   is(vim.insertMode);
   4190   helpers.doKeys('j', 'k');
   4191   is(!vim.insertMode);
   4192   cm.setCursor(0, 1);
   4193   CodeMirror.Vim.map('jj', '<Esc>', 'insert');
   4194   helpers.doKeys('<C-v>', '2', 'j', 'l', 'c');
   4195   var replacement = fillArray('fo', 3);
   4196   cm.replaceSelections(replacement);
   4197   eq('1fo4\n5fo8\nafodefg', cm.getValue());
   4198   helpers.doKeys('j', 'j');
   4199   cm.setCursor(0, 0);
   4200   helpers.doKeys('.');
   4201   eq('foo4\nfoo8\nfoodefg', cm.getValue());
   4202 }, { value: '1234\n5678\nabcdefg' });
   4203 testVim('ex_unmap_api', function(cm, vim, helpers) {
   4204   CodeMirror.Vim.map('<Alt-X>', 'gg', 'normal');
   4205   is(CodeMirror.Vim.handleKey(cm, "<Alt-X>", "normal"), "Alt-X key is mapped");
   4206   CodeMirror.Vim.unmap("<Alt-X>", "normal");
   4207   is(!CodeMirror.Vim.handleKey(cm, "<Alt-X>", "normal"), "Alt-X key is unmapped");
   4208 });
   4209 
   4210 // Testing registration of functions as ex-commands and mapping to <Key>-keys
   4211 testVim('ex_api_test', function(cm, vim, helpers) {
   4212   var res=false;
   4213   var val='from';
   4214   CodeMirror.Vim.defineEx('extest','ext',function(cm,params){
   4215     if(params.args)val=params.args[0];
   4216     else res=true;
   4217   });
   4218   helpers.doEx(':ext to');
   4219   eq(val,'to','Defining ex-command failed');
   4220   CodeMirror.Vim.map('<C-CR><Space>',':ext');
   4221   helpers.doKeys('<C-CR>','<Space>');
   4222   is(res,'Mapping to key failed');
   4223 });
   4224 // For now, this test needs to be last because it messes up : for future tests.
   4225 testVim('ex_map_key2key_from_colon', function(cm, vim, helpers) {
   4226   helpers.doEx('map : x');
   4227   helpers.doKeys(':');
   4228   helpers.assertCursorAt(0, 0);
   4229   eq('bc', cm.getValue());
   4230 }, { value: 'abc' });
   4231 
   4232 // Test event handlers
   4233 testVim('beforeSelectionChange', function(cm, vim, helpers) {
   4234   cm.setCursor(0, 100);
   4235   eqCursorPos(cm.getCursor('head'), cm.getCursor('anchor'));
   4236 }, { value: 'abc' });
   4237 
   4238