browser/devtools/sourceeditor/test/cm_vim_test.js

Wed, 31 Dec 2014 06:09:35 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Wed, 31 Dec 2014 06:09:35 +0100
changeset 0
6474c204b198
permissions
-rw-r--r--

Cloned upstream origin tor-browser at tor-browser-31.3.0esr-4.5-1-build1
revision ID fc1c9ff7c1b2defdbc039f12214767608f46423f for hacking purpose.

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

mercurial