tor-browser

The Tor Browser
git clone https://git.dasho.dev/tor-browser.git
Log | Files | Refs | README | LICENSE

vim_test.js (165600B)


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