browser/devtools/sourceeditor/test/cm_vim_test.js

changeset 0
6474c204b198
     1.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     1.2 +++ b/browser/devtools/sourceeditor/test/cm_vim_test.js	Wed Dec 31 06:09:35 2014 +0100
     1.3 @@ -0,0 +1,2859 @@
     1.4 +var code = '' +
     1.5 +' wOrd1 (#%\n' +
     1.6 +' word3] \n' +
     1.7 +'aopop pop 0 1 2 3 4\n' +
     1.8 +' (a) [b] {c} \n' +
     1.9 +'int getchar(void) {\n' +
    1.10 +'  static char buf[BUFSIZ];\n' +
    1.11 +'  static char *bufp = buf;\n' +
    1.12 +'  if (n == 0) {  /* buffer is empty */\n' +
    1.13 +'    n = read(0, buf, sizeof buf);\n' +
    1.14 +'    bufp = buf;\n' +
    1.15 +'  }\n' +
    1.16 +'\n' +
    1.17 +'  return (--n >= 0) ? (unsigned char) *bufp++ : EOF;\n' +
    1.18 +' \n' +
    1.19 +'}\n';
    1.20 +
    1.21 +var lines = (function() {
    1.22 +  lineText = code.split('\n');
    1.23 +  var ret = [];
    1.24 +  for (var i = 0; i < lineText.length; i++) {
    1.25 +    ret[i] = {
    1.26 +      line: i,
    1.27 +      length: lineText[i].length,
    1.28 +      lineText: lineText[i],
    1.29 +      textStart: /^\s*/.exec(lineText[i])[0].length
    1.30 +    };
    1.31 +  }
    1.32 +  return ret;
    1.33 +})();
    1.34 +var endOfDocument = makeCursor(lines.length - 1,
    1.35 +    lines[lines.length - 1].length);
    1.36 +var wordLine = lines[0];
    1.37 +var bigWordLine = lines[1];
    1.38 +var charLine = lines[2];
    1.39 +var bracesLine = lines[3];
    1.40 +var seekBraceLine = lines[4];
    1.41 +
    1.42 +var word1 = {
    1.43 +  start: { line: wordLine.line, ch: 1 },
    1.44 +  end: { line: wordLine.line, ch: 5 }
    1.45 +};
    1.46 +var word2 = {
    1.47 +  start: { line: wordLine.line, ch: word1.end.ch + 2 },
    1.48 +  end: { line: wordLine.line, ch: word1.end.ch + 4 }
    1.49 +};
    1.50 +var word3 = {
    1.51 +  start: { line: bigWordLine.line, ch: 1 },
    1.52 +  end: { line: bigWordLine.line, ch: 5 }
    1.53 +};
    1.54 +var bigWord1 = word1;
    1.55 +var bigWord2 = word2;
    1.56 +var bigWord3 = {
    1.57 +  start: { line: bigWordLine.line, ch: 1 },
    1.58 +  end: { line: bigWordLine.line, ch: 7 }
    1.59 +};
    1.60 +var bigWord4 = {
    1.61 +  start: { line: bigWordLine.line, ch: bigWord1.end.ch + 3 },
    1.62 +  end: { line: bigWordLine.line, ch: bigWord1.end.ch + 7 }
    1.63 +};
    1.64 +
    1.65 +var oChars = [ { line: charLine.line, ch: 1 },
    1.66 +    { line: charLine.line, ch: 3 },
    1.67 +    { line: charLine.line, ch: 7 } ];
    1.68 +var pChars = [ { line: charLine.line, ch: 2 },
    1.69 +    { line: charLine.line, ch: 4 },
    1.70 +    { line: charLine.line, ch: 6 },
    1.71 +    { line: charLine.line, ch: 8 } ];
    1.72 +var numChars = [ { line: charLine.line, ch: 10 },
    1.73 +    { line: charLine.line, ch: 12 },
    1.74 +    { line: charLine.line, ch: 14 },
    1.75 +    { line: charLine.line, ch: 16 },
    1.76 +    { line: charLine.line, ch: 18 }];
    1.77 +var parens1 = {
    1.78 +  start: { line: bracesLine.line, ch: 1 },
    1.79 +  end: { line: bracesLine.line, ch: 3 }
    1.80 +};
    1.81 +var squares1 = {
    1.82 +  start: { line: bracesLine.line, ch: 5 },
    1.83 +  end: { line: bracesLine.line, ch: 7 }
    1.84 +};
    1.85 +var curlys1 = {
    1.86 +  start: { line: bracesLine.line, ch: 9 },
    1.87 +  end: { line: bracesLine.line, ch: 11 }
    1.88 +};
    1.89 +var seekOutside = {
    1.90 +  start: { line: seekBraceLine.line, ch: 1 },
    1.91 +  end: { line: seekBraceLine.line, ch: 16 }
    1.92 +};
    1.93 +var seekInside = {
    1.94 +  start: { line: seekBraceLine.line, ch: 14 },
    1.95 +  end: { line: seekBraceLine.line, ch: 11 }
    1.96 +};
    1.97 +
    1.98 +function copyCursor(cur) {
    1.99 +  return { ch: cur.ch, line: cur.line };
   1.100 +}
   1.101 +
   1.102 +function forEach(arr, func) {
   1.103 +  for (var i = 0; i < arr.length; i++) {
   1.104 +    func(arr[i]);
   1.105 +  }
   1.106 +}
   1.107 +
   1.108 +function testVim(name, run, opts, expectedFail) {
   1.109 +  var vimOpts = {
   1.110 +    lineNumbers: true,
   1.111 +    vimMode: true,
   1.112 +    showCursorWhenSelecting: true,
   1.113 +    value: code
   1.114 +  };
   1.115 +  for (var prop in opts) {
   1.116 +    if (opts.hasOwnProperty(prop)) {
   1.117 +      vimOpts[prop] = opts[prop];
   1.118 +    }
   1.119 +  }
   1.120 +  return test('vim_' + name, function() {
   1.121 +    var place = document.getElementById("testground");
   1.122 +    var cm = CodeMirror(place, vimOpts);
   1.123 +    var vim = CodeMirror.Vim.maybeInitVimState_(cm);
   1.124 +
   1.125 +    function doKeysFn(cm) {
   1.126 +      return function(args) {
   1.127 +        if (args instanceof Array) {
   1.128 +          arguments = args;
   1.129 +        }
   1.130 +        for (var i = 0; i < arguments.length; i++) {
   1.131 +          CodeMirror.Vim.handleKey(cm, arguments[i]);
   1.132 +        }
   1.133 +      }
   1.134 +    }
   1.135 +    function doInsertModeKeysFn(cm) {
   1.136 +      return function(args) {
   1.137 +        if (args instanceof Array) { arguments = args; }
   1.138 +        function executeHandler(handler) {
   1.139 +          if (typeof handler == 'string') {
   1.140 +            CodeMirror.commands[handler](cm);
   1.141 +          } else {
   1.142 +            handler(cm);
   1.143 +          }
   1.144 +          return true;
   1.145 +        }
   1.146 +        for (var i = 0; i < arguments.length; i++) {
   1.147 +          var key = arguments[i];
   1.148 +          // Find key in keymap and handle.
   1.149 +          var handled = CodeMirror.lookupKey(key, ['vim-insert'], executeHandler);
   1.150 +          // Record for insert mode.
   1.151 +          if (handled === true && cm.state.vim.insertMode && arguments[i] != 'Esc') {
   1.152 +            var lastChange = CodeMirror.Vim.getVimGlobalState_().macroModeState.lastInsertModeChanges;
   1.153 +            if (lastChange) {
   1.154 +              lastChange.changes.push(new CodeMirror.Vim.InsertModeKey(key));
   1.155 +            }
   1.156 +          }
   1.157 +        }
   1.158 +      }
   1.159 +    }
   1.160 +    function doExFn(cm) {
   1.161 +      return function(command) {
   1.162 +        cm.openDialog = helpers.fakeOpenDialog(command);
   1.163 +        helpers.doKeys(':');
   1.164 +      }
   1.165 +    }
   1.166 +    function assertCursorAtFn(cm) {
   1.167 +      return function(line, ch) {
   1.168 +        var pos;
   1.169 +        if (ch == null && typeof line.line == 'number') {
   1.170 +          pos = line;
   1.171 +        } else {
   1.172 +          pos = makeCursor(line, ch);
   1.173 +        }
   1.174 +        eqPos(pos, cm.getCursor());
   1.175 +      }
   1.176 +    }
   1.177 +    function fakeOpenDialog(result) {
   1.178 +      return function(text, callback) {
   1.179 +        return callback(result);
   1.180 +      }
   1.181 +    }
   1.182 +    function fakeOpenNotification(matcher) {
   1.183 +      return function(text) {
   1.184 +        matcher(text);
   1.185 +      }
   1.186 +    }
   1.187 +    var helpers = {
   1.188 +      doKeys: doKeysFn(cm),
   1.189 +      // Warning: Only emulates keymap events, not character insertions. Use
   1.190 +      // replaceRange to simulate character insertions.
   1.191 +      // Keys are in CodeMirror format, NOT vim format.
   1.192 +      doInsertModeKeys: doInsertModeKeysFn(cm),
   1.193 +      doEx: doExFn(cm),
   1.194 +      assertCursorAt: assertCursorAtFn(cm),
   1.195 +      fakeOpenDialog: fakeOpenDialog,
   1.196 +      fakeOpenNotification: fakeOpenNotification,
   1.197 +      getRegisterController: function() {
   1.198 +        return CodeMirror.Vim.getRegisterController();
   1.199 +      }
   1.200 +    }
   1.201 +    CodeMirror.Vim.resetVimGlobalState_();
   1.202 +    var successful = false;
   1.203 +    var savedOpenNotification = cm.openNotification;
   1.204 +    try {
   1.205 +      run(cm, vim, helpers);
   1.206 +      successful = true;
   1.207 +    } finally {
   1.208 +      cm.openNotification = savedOpenNotification;
   1.209 +      if (!successful || verbose) {
   1.210 +        place.style.visibility = "visible";
   1.211 +      } else {
   1.212 +        place.removeChild(cm.getWrapperElement());
   1.213 +      }
   1.214 +    }
   1.215 +  }, expectedFail);
   1.216 +};
   1.217 +testVim('qq@q', function(cm, vim, helpers) {
   1.218 +  cm.setCursor(0, 0);
   1.219 +  helpers.doKeys('q', 'q', 'l', 'l', 'q');
   1.220 +  helpers.assertCursorAt(0,2);
   1.221 +  helpers.doKeys('@', 'q');
   1.222 +  helpers.assertCursorAt(0,4);
   1.223 +}, { value: '            '});
   1.224 +testVim('@@', function(cm, vim, helpers) {
   1.225 +  cm.setCursor(0, 0);
   1.226 +  helpers.doKeys('q', 'q', 'l', 'l', 'q');
   1.227 +  helpers.assertCursorAt(0,2);
   1.228 +  helpers.doKeys('@', 'q');
   1.229 +  helpers.assertCursorAt(0,4);
   1.230 +  helpers.doKeys('@', '@');
   1.231 +  helpers.assertCursorAt(0,6);
   1.232 +}, { value: '            '});
   1.233 +var jumplistScene = ''+
   1.234 +  'word\n'+
   1.235 +  '(word)\n'+
   1.236 +  '{word\n'+
   1.237 +  'word.\n'+
   1.238 +  '\n'+
   1.239 +  'word search\n'+
   1.240 +  '}word\n'+
   1.241 +  'word\n'+
   1.242 +  'word\n';
   1.243 +function testJumplist(name, keys, endPos, startPos, dialog) {
   1.244 +  endPos = makeCursor(endPos[0], endPos[1]);
   1.245 +  startPos = makeCursor(startPos[0], startPos[1]);
   1.246 +  testVim(name, function(cm, vim, helpers) {
   1.247 +    CodeMirror.Vim.resetVimGlobalState_();
   1.248 +    if(dialog)cm.openDialog = helpers.fakeOpenDialog('word');
   1.249 +    cm.setCursor(startPos);
   1.250 +    helpers.doKeys.apply(null, keys);
   1.251 +    helpers.assertCursorAt(endPos);
   1.252 +  }, {value: jumplistScene});
   1.253 +};
   1.254 +testJumplist('jumplist_H', ['H', '<C-o>'], [5,2], [5,2]);
   1.255 +testJumplist('jumplist_M', ['M', '<C-o>'], [2,2], [2,2]);
   1.256 +testJumplist('jumplist_L', ['L', '<C-o>'], [2,2], [2,2]);
   1.257 +testJumplist('jumplist_[[', ['[', '[', '<C-o>'], [5,2], [5,2]);
   1.258 +testJumplist('jumplist_]]', [']', ']', '<C-o>'], [2,2], [2,2]);
   1.259 +testJumplist('jumplist_G', ['G', '<C-o>'], [5,2], [5,2]);
   1.260 +testJumplist('jumplist_gg', ['g', 'g', '<C-o>'], [5,2], [5,2]);
   1.261 +testJumplist('jumplist_%', ['%', '<C-o>'], [1,5], [1,5]);
   1.262 +testJumplist('jumplist_{', ['{', '<C-o>'], [1,5], [1,5]);
   1.263 +testJumplist('jumplist_}', ['}', '<C-o>'], [1,5], [1,5]);
   1.264 +testJumplist('jumplist_\'', ['m', 'a', 'h', '\'', 'a', 'h', '<C-i>'], [1,5], [1,5]);
   1.265 +testJumplist('jumplist_`', ['m', 'a', 'h', '`', 'a', 'h', '<C-i>'], [1,5], [1,5]);
   1.266 +testJumplist('jumplist_*_cachedCursor', ['*', '<C-o>'], [1,3], [1,3]);
   1.267 +testJumplist('jumplist_#_cachedCursor', ['#', '<C-o>'], [1,3], [1,3]);
   1.268 +testJumplist('jumplist_n', ['#', 'n', '<C-o>'], [1,1], [2,3]);
   1.269 +testJumplist('jumplist_N', ['#', 'N', '<C-o>'], [1,1], [2,3]);
   1.270 +testJumplist('jumplist_repeat_<c-o>', ['*', '*', '*', '3', '<C-o>'], [2,3], [2,3]);
   1.271 +testJumplist('jumplist_repeat_<c-i>', ['*', '*', '*', '3', '<C-o>', '2', '<C-i>'], [5,0], [2,3]);
   1.272 +testJumplist('jumplist_repeated_motion', ['3', '*', '<C-o>'], [2,3], [2,3]);
   1.273 +testJumplist('jumplist_/', ['/', '<C-o>'], [2,3], [2,3], 'dialog');
   1.274 +testJumplist('jumplist_?', ['?', '<C-o>'], [2,3], [2,3], 'dialog');
   1.275 +testJumplist('jumplist_skip_delted_mark<c-o>',
   1.276 +             ['*', 'n', 'n', 'k', 'd', 'k', '<C-o>', '<C-o>', '<C-o>'],
   1.277 +             [0,2], [0,2]);
   1.278 +testJumplist('jumplist_skip_delted_mark<c-i>',
   1.279 +             ['*', 'n', 'n', 'k', 'd', 'k', '<C-o>', '<C-i>', '<C-i>'],
   1.280 +             [1,0], [0,2]);
   1.281 +
   1.282 +/**
   1.283 + * @param name Name of the test
   1.284 + * @param keys An array of keys or a string with a single key to simulate.
   1.285 + * @param endPos The expected end position of the cursor.
   1.286 + * @param startPos The position the cursor should start at, defaults to 0, 0.
   1.287 + */
   1.288 +function testMotion(name, keys, endPos, startPos) {
   1.289 +  testVim(name, function(cm, vim, helpers) {
   1.290 +    if (!startPos) {
   1.291 +      startPos = { line: 0, ch: 0 };
   1.292 +    }
   1.293 +    cm.setCursor(startPos);
   1.294 +    helpers.doKeys(keys);
   1.295 +    helpers.assertCursorAt(endPos);
   1.296 +  });
   1.297 +};
   1.298 +
   1.299 +function makeCursor(line, ch) {
   1.300 +  return { line: line, ch: ch };
   1.301 +};
   1.302 +
   1.303 +function offsetCursor(cur, offsetLine, offsetCh) {
   1.304 +  return { line: cur.line + offsetLine, ch: cur.ch + offsetCh };
   1.305 +};
   1.306 +
   1.307 +// Motion tests
   1.308 +testMotion('|', '|', makeCursor(0, 0), makeCursor(0,4));
   1.309 +testMotion('|_repeat', ['3', '|'], makeCursor(0, 2), makeCursor(0,4));
   1.310 +testMotion('h', 'h', makeCursor(0, 0), word1.start);
   1.311 +testMotion('h_repeat', ['3', 'h'], offsetCursor(word1.end, 0, -3), word1.end);
   1.312 +testMotion('l', 'l', makeCursor(0, 1));
   1.313 +testMotion('l_repeat', ['2', 'l'], makeCursor(0, 2));
   1.314 +testMotion('j', 'j', offsetCursor(word1.end, 1, 0), word1.end);
   1.315 +testMotion('j_repeat', ['2', 'j'], offsetCursor(word1.end, 2, 0), word1.end);
   1.316 +testMotion('j_repeat_clip', ['1000', 'j'], endOfDocument);
   1.317 +testMotion('k', 'k', offsetCursor(word3.end, -1, 0), word3.end);
   1.318 +testMotion('k_repeat', ['2', 'k'], makeCursor(0, 4), makeCursor(2, 4));
   1.319 +testMotion('k_repeat_clip', ['1000', 'k'], makeCursor(0, 4), makeCursor(2, 4));
   1.320 +testMotion('w', 'w', word1.start);
   1.321 +testMotion('w_multiple_newlines_no_space', 'w', makeCursor(12, 2), makeCursor(11, 2));
   1.322 +testMotion('w_multiple_newlines_with_space', 'w', makeCursor(14, 0), makeCursor(12, 51));
   1.323 +testMotion('w_repeat', ['2', 'w'], word2.start);
   1.324 +testMotion('w_wrap', ['w'], word3.start, word2.start);
   1.325 +testMotion('w_endOfDocument', 'w', endOfDocument, endOfDocument);
   1.326 +testMotion('w_start_to_end', ['1000', 'w'], endOfDocument, makeCursor(0, 0));
   1.327 +testMotion('W', 'W', bigWord1.start);
   1.328 +testMotion('W_repeat', ['2', 'W'], bigWord3.start, bigWord1.start);
   1.329 +testMotion('e', 'e', word1.end);
   1.330 +testMotion('e_repeat', ['2', 'e'], word2.end);
   1.331 +testMotion('e_wrap', 'e', word3.end, word2.end);
   1.332 +testMotion('e_endOfDocument', 'e', endOfDocument, endOfDocument);
   1.333 +testMotion('e_start_to_end', ['1000', 'e'], endOfDocument, makeCursor(0, 0));
   1.334 +testMotion('b', 'b', word3.start, word3.end);
   1.335 +testMotion('b_repeat', ['2', 'b'], word2.start, word3.end);
   1.336 +testMotion('b_wrap', 'b', word2.start, word3.start);
   1.337 +testMotion('b_startOfDocument', 'b', makeCursor(0, 0), makeCursor(0, 0));
   1.338 +testMotion('b_end_to_start', ['1000', 'b'], makeCursor(0, 0), endOfDocument);
   1.339 +testMotion('ge', ['g', 'e'], word2.end, word3.end);
   1.340 +testMotion('ge_repeat', ['2', 'g', 'e'], word1.end, word3.start);
   1.341 +testMotion('ge_wrap', ['g', 'e'], word2.end, word3.start);
   1.342 +testMotion('ge_startOfDocument', ['g', 'e'], makeCursor(0, 0),
   1.343 +    makeCursor(0, 0));
   1.344 +testMotion('ge_end_to_start', ['1000', 'g', 'e'], makeCursor(0, 0), endOfDocument);
   1.345 +testMotion('gg', ['g', 'g'], makeCursor(lines[0].line, lines[0].textStart),
   1.346 +    makeCursor(3, 1));
   1.347 +testMotion('gg_repeat', ['3', 'g', 'g'],
   1.348 +    makeCursor(lines[2].line, lines[2].textStart));
   1.349 +testMotion('G', 'G',
   1.350 +    makeCursor(lines[lines.length - 1].line, lines[lines.length - 1].textStart),
   1.351 +    makeCursor(3, 1));
   1.352 +testMotion('G_repeat', ['3', 'G'], makeCursor(lines[2].line,
   1.353 +    lines[2].textStart));
   1.354 +// TODO: Make the test code long enough to test Ctrl-F and Ctrl-B.
   1.355 +testMotion('0', '0', makeCursor(0, 0), makeCursor(0, 8));
   1.356 +testMotion('^', '^', makeCursor(0, lines[0].textStart), makeCursor(0, 8));
   1.357 +testMotion('+', '+', makeCursor(1, lines[1].textStart), makeCursor(0, 8));
   1.358 +testMotion('-', '-', makeCursor(0, lines[0].textStart), makeCursor(1, 4));
   1.359 +testMotion('_', ['6','_'], makeCursor(5, lines[5].textStart), makeCursor(0, 8));
   1.360 +testMotion('$', '$', makeCursor(0, lines[0].length - 1), makeCursor(0, 1));
   1.361 +testMotion('$_repeat', ['2', '$'], makeCursor(1, lines[1].length - 1),
   1.362 +    makeCursor(0, 3));
   1.363 +testMotion('f', ['f', 'p'], pChars[0], makeCursor(charLine.line, 0));
   1.364 +testMotion('f_repeat', ['2', 'f', 'p'], pChars[2], pChars[0]);
   1.365 +testMotion('f_num', ['f', '2'], numChars[2], makeCursor(charLine.line, 0));
   1.366 +testMotion('t', ['t','p'], offsetCursor(pChars[0], 0, -1),
   1.367 +    makeCursor(charLine.line, 0));
   1.368 +testMotion('t_repeat', ['2', 't', 'p'], offsetCursor(pChars[2], 0, -1),
   1.369 +    pChars[0]);
   1.370 +testMotion('F', ['F', 'p'], pChars[0], pChars[1]);
   1.371 +testMotion('F_repeat', ['2', 'F', 'p'], pChars[0], pChars[2]);
   1.372 +testMotion('T', ['T', 'p'], offsetCursor(pChars[0], 0, 1), pChars[1]);
   1.373 +testMotion('T_repeat', ['2', 'T', 'p'], offsetCursor(pChars[0], 0, 1), pChars[2]);
   1.374 +testMotion('%_parens', ['%'], parens1.end, parens1.start);
   1.375 +testMotion('%_squares', ['%'], squares1.end, squares1.start);
   1.376 +testMotion('%_braces', ['%'], curlys1.end, curlys1.start);
   1.377 +testMotion('%_seek_outside', ['%'], seekOutside.end, seekOutside.start);
   1.378 +testMotion('%_seek_inside', ['%'], seekInside.end, seekInside.start);
   1.379 +testVim('%_seek_skip', function(cm, vim, helpers) {
   1.380 +  cm.setCursor(0,0);
   1.381 +  helpers.doKeys(['%']);
   1.382 +  helpers.assertCursorAt(0,9);
   1.383 +}, {value:'01234"("()'});
   1.384 +testVim('%_skip_string', function(cm, vim, helpers) {
   1.385 +  cm.setCursor(0,0);
   1.386 +  helpers.doKeys(['%']);
   1.387 +  helpers.assertCursorAt(0,4);
   1.388 +  cm.setCursor(0,2);
   1.389 +  helpers.doKeys(['%']);
   1.390 +  helpers.assertCursorAt(0,0);
   1.391 +}, {value:'(")")'});
   1.392 +(')')
   1.393 +testVim('%_skip_comment', function(cm, vim, helpers) {
   1.394 +  cm.setCursor(0,0);
   1.395 +  helpers.doKeys(['%']);
   1.396 +  helpers.assertCursorAt(0,6);
   1.397 +  cm.setCursor(0,3);
   1.398 +  helpers.doKeys(['%']);
   1.399 +  helpers.assertCursorAt(0,0);
   1.400 +}, {value:'(/*)*/)'});
   1.401 +// Make sure that moving down after going to the end of a line always leaves you
   1.402 +// at the end of a line, but preserves the offset in other cases
   1.403 +testVim('Changing lines after Eol operation', function(cm, vim, helpers) {
   1.404 +  cm.setCursor(0,0);
   1.405 +  helpers.doKeys(['$']);
   1.406 +  helpers.doKeys(['j']);
   1.407 +  // After moving to Eol and then down, we should be at Eol of line 2
   1.408 +  helpers.assertCursorAt({ line: 1, ch: lines[1].length - 1 });
   1.409 +  helpers.doKeys(['j']);
   1.410 +  // After moving down, we should be at Eol of line 3
   1.411 +  helpers.assertCursorAt({ line: 2, ch: lines[2].length - 1 });
   1.412 +  helpers.doKeys(['h']);
   1.413 +  helpers.doKeys(['j']);
   1.414 +  // After moving back one space and then down, since line 4 is shorter than line 2, we should
   1.415 +  // be at Eol of line 2 - 1
   1.416 +  helpers.assertCursorAt({ line: 3, ch: lines[3].length - 1 });
   1.417 +  helpers.doKeys(['j']);
   1.418 +  helpers.doKeys(['j']);
   1.419 +  // After moving down again, since line 3 has enough characters, we should be back to the
   1.420 +  // same place we were at on line 1
   1.421 +  helpers.assertCursorAt({ line: 5, ch: lines[2].length - 2 });
   1.422 +});
   1.423 +//making sure gj and gk recover from clipping
   1.424 +testVim('gj_gk_clipping', function(cm,vim,helpers){
   1.425 +  cm.setCursor(0, 1);
   1.426 +  helpers.doKeys('g','j','g','j');
   1.427 +  helpers.assertCursorAt(2, 1);
   1.428 +  helpers.doKeys('g','k','g','k');
   1.429 +  helpers.assertCursorAt(0, 1);
   1.430 +},{value: 'line 1\n\nline 2'});
   1.431 +//testing a mix of j/k and gj/gk
   1.432 +testVim('j_k_and_gj_gk', function(cm,vim,helpers){
   1.433 +  cm.setSize(120);
   1.434 +  cm.setCursor(0, 0);
   1.435 +  //go to the last character on the first line
   1.436 +  helpers.doKeys('$');
   1.437 +  //move up/down on the column within the wrapped line
   1.438 +  //side-effect: cursor is not locked to eol anymore
   1.439 +  helpers.doKeys('g','k');
   1.440 +  var cur=cm.getCursor();
   1.441 +  eq(cur.line,0);
   1.442 +  is((cur.ch<176),'gk didn\'t move cursor back (1)');
   1.443 +  helpers.doKeys('g','j');
   1.444 +  helpers.assertCursorAt(0, 176);
   1.445 +  //should move to character 177 on line 2 (j/k preserve character index within line)
   1.446 +  helpers.doKeys('j');
   1.447 +  //due to different line wrapping, the cursor can be on a different screen-x now
   1.448 +  //gj and gk preserve screen-x on movement, much like moveV
   1.449 +  helpers.doKeys('3','g','k');
   1.450 +  cur=cm.getCursor();
   1.451 +  eq(cur.line,1);
   1.452 +  is((cur.ch<176),'gk didn\'t move cursor back (2)');
   1.453 +  helpers.doKeys('g','j','2','g','j');
   1.454 +  //should return to the same character-index
   1.455 +  helpers.doKeys('k');
   1.456 +  helpers.assertCursorAt(0, 176);
   1.457 +},{ 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.'});
   1.458 +testVim('gj_gk', function(cm, vim, helpers) {
   1.459 +  if (phantom) return;
   1.460 +  cm.setSize(120);
   1.461 +  // Test top of document edge case.
   1.462 +  cm.setCursor(0, 4);
   1.463 +  helpers.doKeys('g', 'j');
   1.464 +  helpers.doKeys('10', 'g', 'k');
   1.465 +  helpers.assertCursorAt(0, 4);
   1.466 +
   1.467 +  // Test moving down preserves column position.
   1.468 +  helpers.doKeys('g', 'j');
   1.469 +  var pos1 = cm.getCursor();
   1.470 +  var expectedPos2 = { line: 0, ch: (pos1.ch - 4) * 2 + 4};
   1.471 +  helpers.doKeys('g', 'j');
   1.472 +  helpers.assertCursorAt(expectedPos2);
   1.473 +
   1.474 +  // Move to the last character
   1.475 +  cm.setCursor(0, 0);
   1.476 +  // Move left to reset HSPos
   1.477 +  helpers.doKeys('h');
   1.478 +  // Test bottom of document edge case.
   1.479 +  helpers.doKeys('100', 'g', 'j');
   1.480 +  var endingPos = cm.getCursor();
   1.481 +  is(endingPos != 0, 'gj should not be on wrapped line 0');
   1.482 +  var topLeftCharCoords = cm.charCoords(makeCursor(0, 0));
   1.483 +  var endingCharCoords = cm.charCoords(endingPos);
   1.484 +  is(topLeftCharCoords.left == endingCharCoords.left, 'gj should end up on column 0');
   1.485 +},{ lineNumbers: false, lineWrapping:true, value: 'Thislineisintentiallylongtotestmovementofgjandgkoverwrappedlines.' });
   1.486 +testVim('}', function(cm, vim, helpers) {
   1.487 +  cm.setCursor(0, 0);
   1.488 +  helpers.doKeys('}');
   1.489 +  helpers.assertCursorAt(1, 0);
   1.490 +  cm.setCursor(0, 0);
   1.491 +  helpers.doKeys('2', '}');
   1.492 +  helpers.assertCursorAt(4, 0);
   1.493 +  cm.setCursor(0, 0);
   1.494 +  helpers.doKeys('6', '}');
   1.495 +  helpers.assertCursorAt(5, 0);
   1.496 +}, { value: 'a\n\nb\nc\n\nd' });
   1.497 +testVim('{', function(cm, vim, helpers) {
   1.498 +  cm.setCursor(5, 0);
   1.499 +  helpers.doKeys('{');
   1.500 +  helpers.assertCursorAt(4, 0);
   1.501 +  cm.setCursor(5, 0);
   1.502 +  helpers.doKeys('2', '{');
   1.503 +  helpers.assertCursorAt(1, 0);
   1.504 +  cm.setCursor(5, 0);
   1.505 +  helpers.doKeys('6', '{');
   1.506 +  helpers.assertCursorAt(0, 0);
   1.507 +}, { value: 'a\n\nb\nc\n\nd' });
   1.508 +
   1.509 +// Operator tests
   1.510 +testVim('dl', function(cm, vim, helpers) {
   1.511 +  var curStart = makeCursor(0, 0);
   1.512 +  cm.setCursor(curStart);
   1.513 +  helpers.doKeys('d', 'l');
   1.514 +  eq('word1 ', cm.getValue());
   1.515 +  var register = helpers.getRegisterController().getRegister();
   1.516 +  eq(' ', register.toString());
   1.517 +  is(!register.linewise);
   1.518 +  eqPos(curStart, cm.getCursor());
   1.519 +}, { value: ' word1 ' });
   1.520 +testVim('dl_eol', function(cm, vim, helpers) {
   1.521 +  cm.setCursor(0, 6);
   1.522 +  helpers.doKeys('d', 'l');
   1.523 +  eq(' word1', cm.getValue());
   1.524 +  var register = helpers.getRegisterController().getRegister();
   1.525 +  eq(' ', register.toString());
   1.526 +  is(!register.linewise);
   1.527 +  helpers.assertCursorAt(0, 5);
   1.528 +}, { value: ' word1 ' });
   1.529 +testVim('dl_repeat', function(cm, vim, helpers) {
   1.530 +  var curStart = makeCursor(0, 0);
   1.531 +  cm.setCursor(curStart);
   1.532 +  helpers.doKeys('2', 'd', 'l');
   1.533 +  eq('ord1 ', cm.getValue());
   1.534 +  var register = helpers.getRegisterController().getRegister();
   1.535 +  eq(' w', register.toString());
   1.536 +  is(!register.linewise);
   1.537 +  eqPos(curStart, cm.getCursor());
   1.538 +}, { value: ' word1 ' });
   1.539 +testVim('dh', function(cm, vim, helpers) {
   1.540 +  var curStart = makeCursor(0, 3);
   1.541 +  cm.setCursor(curStart);
   1.542 +  helpers.doKeys('d', 'h');
   1.543 +  eq(' wrd1 ', cm.getValue());
   1.544 +  var register = helpers.getRegisterController().getRegister();
   1.545 +  eq('o', register.toString());
   1.546 +  is(!register.linewise);
   1.547 +  eqPos(offsetCursor(curStart, 0 , -1), cm.getCursor());
   1.548 +}, { value: ' word1 ' });
   1.549 +testVim('dj', function(cm, vim, helpers) {
   1.550 +  var curStart = makeCursor(0, 3);
   1.551 +  cm.setCursor(curStart);
   1.552 +  helpers.doKeys('d', 'j');
   1.553 +  eq(' word3', cm.getValue());
   1.554 +  var register = helpers.getRegisterController().getRegister();
   1.555 +  eq(' word1\nword2\n', register.toString());
   1.556 +  is(register.linewise);
   1.557 +  helpers.assertCursorAt(0, 1);
   1.558 +}, { value: ' word1\nword2\n word3' });
   1.559 +testVim('dj_end_of_document', function(cm, vim, helpers) {
   1.560 +  var curStart = makeCursor(0, 3);
   1.561 +  cm.setCursor(curStart);
   1.562 +  helpers.doKeys('d', 'j');
   1.563 +  eq(' word1 ', cm.getValue());
   1.564 +  var register = helpers.getRegisterController().getRegister();
   1.565 +  eq('', register.toString());
   1.566 +  is(!register.linewise);
   1.567 +  helpers.assertCursorAt(0, 3);
   1.568 +}, { value: ' word1 ' });
   1.569 +testVim('dk', function(cm, vim, helpers) {
   1.570 +  var curStart = makeCursor(1, 3);
   1.571 +  cm.setCursor(curStart);
   1.572 +  helpers.doKeys('d', 'k');
   1.573 +  eq(' word3', cm.getValue());
   1.574 +  var register = helpers.getRegisterController().getRegister();
   1.575 +  eq(' word1\nword2\n', register.toString());
   1.576 +  is(register.linewise);
   1.577 +  helpers.assertCursorAt(0, 1);
   1.578 +}, { value: ' word1\nword2\n word3' });
   1.579 +testVim('dk_start_of_document', function(cm, vim, helpers) {
   1.580 +  var curStart = makeCursor(0, 3);
   1.581 +  cm.setCursor(curStart);
   1.582 +  helpers.doKeys('d', 'k');
   1.583 +  eq(' word1 ', cm.getValue());
   1.584 +  var register = helpers.getRegisterController().getRegister();
   1.585 +  eq('', register.toString());
   1.586 +  is(!register.linewise);
   1.587 +  helpers.assertCursorAt(0, 3);
   1.588 +}, { value: ' word1 ' });
   1.589 +testVim('dw_space', function(cm, vim, helpers) {
   1.590 +  var curStart = makeCursor(0, 0);
   1.591 +  cm.setCursor(curStart);
   1.592 +  helpers.doKeys('d', 'w');
   1.593 +  eq('word1 ', cm.getValue());
   1.594 +  var register = helpers.getRegisterController().getRegister();
   1.595 +  eq(' ', register.toString());
   1.596 +  is(!register.linewise);
   1.597 +  eqPos(curStart, cm.getCursor());
   1.598 +}, { value: ' word1 ' });
   1.599 +testVim('dw_word', function(cm, vim, helpers) {
   1.600 +  var curStart = makeCursor(0, 1);
   1.601 +  cm.setCursor(curStart);
   1.602 +  helpers.doKeys('d', 'w');
   1.603 +  eq(' word2', cm.getValue());
   1.604 +  var register = helpers.getRegisterController().getRegister();
   1.605 +  eq('word1 ', register.toString());
   1.606 +  is(!register.linewise);
   1.607 +  eqPos(curStart, cm.getCursor());
   1.608 +}, { value: ' word1 word2' });
   1.609 +testVim('dw_only_word', function(cm, vim, helpers) {
   1.610 +  // Test that if there is only 1 word left, dw deletes till the end of the
   1.611 +  // line.
   1.612 +  cm.setCursor(0, 1);
   1.613 +  helpers.doKeys('d', 'w');
   1.614 +  eq(' ', cm.getValue());
   1.615 +  var register = helpers.getRegisterController().getRegister();
   1.616 +  eq('word1 ', register.toString());
   1.617 +  is(!register.linewise);
   1.618 +  helpers.assertCursorAt(0, 0);
   1.619 +}, { value: ' word1 ' });
   1.620 +testVim('dw_eol', function(cm, vim, helpers) {
   1.621 +  // Assert that dw does not delete the newline if last word to delete is at end
   1.622 +  // of line.
   1.623 +  cm.setCursor(0, 1);
   1.624 +  helpers.doKeys('d', 'w');
   1.625 +  eq(' \nword2', cm.getValue());
   1.626 +  var register = helpers.getRegisterController().getRegister();
   1.627 +  eq('word1', register.toString());
   1.628 +  is(!register.linewise);
   1.629 +  helpers.assertCursorAt(0, 0);
   1.630 +}, { value: ' word1\nword2' });
   1.631 +testVim('dw_eol_with_multiple_newlines', function(cm, vim, helpers) {
   1.632 +  // Assert that dw does not delete the newline if last word to delete is at end
   1.633 +  // of line and it is followed by multiple newlines.
   1.634 +  cm.setCursor(0, 1);
   1.635 +  helpers.doKeys('d', 'w');
   1.636 +  eq(' \n\nword2', cm.getValue());
   1.637 +  var register = helpers.getRegisterController().getRegister();
   1.638 +  eq('word1', register.toString());
   1.639 +  is(!register.linewise);
   1.640 +  helpers.assertCursorAt(0, 0);
   1.641 +}, { value: ' word1\n\nword2' });
   1.642 +testVim('dw_empty_line_followed_by_whitespace', function(cm, vim, helpers) {
   1.643 +  cm.setCursor(0, 0);
   1.644 +  helpers.doKeys('d', 'w');
   1.645 +  eq('  \nword', cm.getValue());
   1.646 +}, { value: '\n  \nword' });
   1.647 +testVim('dw_empty_line_followed_by_word', function(cm, vim, helpers) {
   1.648 +  cm.setCursor(0, 0);
   1.649 +  helpers.doKeys('d', 'w');
   1.650 +  eq('word', cm.getValue());
   1.651 +}, { value: '\nword' });
   1.652 +testVim('dw_empty_line_followed_by_empty_line', function(cm, vim, helpers) {
   1.653 +  cm.setCursor(0, 0);
   1.654 +  helpers.doKeys('d', 'w');
   1.655 +  eq('\n', cm.getValue());
   1.656 +}, { value: '\n\n' });
   1.657 +testVim('dw_whitespace_followed_by_whitespace', function(cm, vim, helpers) {
   1.658 +  cm.setCursor(0, 0);
   1.659 +  helpers.doKeys('d', 'w');
   1.660 +  eq('\n   \n', cm.getValue());
   1.661 +}, { value: '  \n   \n' });
   1.662 +testVim('dw_whitespace_followed_by_empty_line', function(cm, vim, helpers) {
   1.663 +  cm.setCursor(0, 0);
   1.664 +  helpers.doKeys('d', 'w');
   1.665 +  eq('\n\n', cm.getValue());
   1.666 +}, { value: '  \n\n' });
   1.667 +testVim('dw_word_whitespace_word', function(cm, vim, helpers) {
   1.668 +  cm.setCursor(0, 0);
   1.669 +  helpers.doKeys('d', 'w');
   1.670 +  eq('\n   \nword2', cm.getValue());
   1.671 +}, { value: 'word1\n   \nword2'})
   1.672 +testVim('dw_end_of_document', function(cm, vim, helpers) {
   1.673 +  cm.setCursor(1, 2);
   1.674 +  helpers.doKeys('d', 'w');
   1.675 +  eq('\nab', cm.getValue());
   1.676 +}, { value: '\nabc' });
   1.677 +testVim('dw_repeat', function(cm, vim, helpers) {
   1.678 +  // Assert that dw does delete newline if it should go to the next line, and
   1.679 +  // that repeat works properly.
   1.680 +  cm.setCursor(0, 1);
   1.681 +  helpers.doKeys('d', '2', 'w');
   1.682 +  eq(' ', cm.getValue());
   1.683 +  var register = helpers.getRegisterController().getRegister();
   1.684 +  eq('word1\nword2', register.toString());
   1.685 +  is(!register.linewise);
   1.686 +  helpers.assertCursorAt(0, 0);
   1.687 +}, { value: ' word1\nword2' });
   1.688 +testVim('de_word_start_and_empty_lines', function(cm, vim, helpers) {
   1.689 +  cm.setCursor(0, 0);
   1.690 +  helpers.doKeys('d', 'e');
   1.691 +  eq('\n\n', cm.getValue());
   1.692 +}, { value: 'word\n\n' });
   1.693 +testVim('de_word_end_and_empty_lines', function(cm, vim, helpers) {
   1.694 +  cm.setCursor(0, 3);
   1.695 +  helpers.doKeys('d', 'e');
   1.696 +  eq('wor', cm.getValue());
   1.697 +}, { value: 'word\n\n\n' });
   1.698 +testVim('de_whitespace_and_empty_lines', function(cm, vim, helpers) {
   1.699 +  cm.setCursor(0, 0);
   1.700 +  helpers.doKeys('d', 'e');
   1.701 +  eq('', cm.getValue());
   1.702 +}, { value: '   \n\n\n' });
   1.703 +testVim('de_end_of_document', function(cm, vim, helpers) {
   1.704 +  cm.setCursor(1, 2);
   1.705 +  helpers.doKeys('d', 'e');
   1.706 +  eq('\nab', cm.getValue());
   1.707 +}, { value: '\nabc' });
   1.708 +testVim('db_empty_lines', function(cm, vim, helpers) {
   1.709 +  cm.setCursor(2, 0);
   1.710 +  helpers.doKeys('d', 'b');
   1.711 +  eq('\n\n', cm.getValue());
   1.712 +}, { value: '\n\n\n' });
   1.713 +testVim('db_word_start_and_empty_lines', function(cm, vim, helpers) {
   1.714 +  cm.setCursor(2, 0);
   1.715 +  helpers.doKeys('d', 'b');
   1.716 +  eq('\nword', cm.getValue());
   1.717 +}, { value: '\n\nword' });
   1.718 +testVim('db_word_end_and_empty_lines', function(cm, vim, helpers) {
   1.719 +  cm.setCursor(2, 3);
   1.720 +  helpers.doKeys('d', 'b');
   1.721 +  eq('\n\nd', cm.getValue());
   1.722 +}, { value: '\n\nword' });
   1.723 +testVim('db_whitespace_and_empty_lines', function(cm, vim, helpers) {
   1.724 +  cm.setCursor(2, 0);
   1.725 +  helpers.doKeys('d', 'b');
   1.726 +  eq('', cm.getValue());
   1.727 +}, { value: '\n   \n' });
   1.728 +testVim('db_start_of_document', function(cm, vim, helpers) {
   1.729 +  cm.setCursor(0, 0);
   1.730 +  helpers.doKeys('d', 'b');
   1.731 +  eq('abc\n', cm.getValue());
   1.732 +}, { value: 'abc\n' });
   1.733 +testVim('dge_empty_lines', function(cm, vim, helpers) {
   1.734 +  cm.setCursor(1, 0);
   1.735 +  helpers.doKeys('d', 'g', 'e');
   1.736 +  // Note: In real VIM the result should be '', but it's not quite consistent,
   1.737 +  // since 2 newlines are deleted. But in the similar case of word\n\n, only
   1.738 +  // 1 newline is deleted. We'll diverge from VIM's behavior since it's much
   1.739 +  // easier this way.
   1.740 +  eq('\n', cm.getValue());
   1.741 +}, { value: '\n\n' });
   1.742 +testVim('dge_word_and_empty_lines', function(cm, vim, helpers) {
   1.743 +  cm.setCursor(1, 0);
   1.744 +  helpers.doKeys('d', 'g', 'e');
   1.745 +  eq('wor\n', cm.getValue());
   1.746 +}, { value: 'word\n\n'});
   1.747 +testVim('dge_whitespace_and_empty_lines', function(cm, vim, helpers) {
   1.748 +  cm.setCursor(2, 0);
   1.749 +  helpers.doKeys('d', 'g', 'e');
   1.750 +  eq('', cm.getValue());
   1.751 +}, { value: '\n  \n' });
   1.752 +testVim('dge_start_of_document', function(cm, vim, helpers) {
   1.753 +  cm.setCursor(0, 0);
   1.754 +  helpers.doKeys('d', 'g', 'e');
   1.755 +  eq('bc\n', cm.getValue());
   1.756 +}, { value: 'abc\n' });
   1.757 +testVim('d_inclusive', function(cm, vim, helpers) {
   1.758 +  // Assert that when inclusive is set, the character the cursor is on gets
   1.759 +  // deleted too.
   1.760 +  var curStart = makeCursor(0, 1);
   1.761 +  cm.setCursor(curStart);
   1.762 +  helpers.doKeys('d', 'e');
   1.763 +  eq('  ', cm.getValue());
   1.764 +  var register = helpers.getRegisterController().getRegister();
   1.765 +  eq('word1', register.toString());
   1.766 +  is(!register.linewise);
   1.767 +  eqPos(curStart, cm.getCursor());
   1.768 +}, { value: ' word1 ' });
   1.769 +testVim('d_reverse', function(cm, vim, helpers) {
   1.770 +  // Test that deleting in reverse works.
   1.771 +  cm.setCursor(1, 0);
   1.772 +  helpers.doKeys('d', 'b');
   1.773 +  eq(' word2 ', cm.getValue());
   1.774 +  var register = helpers.getRegisterController().getRegister();
   1.775 +  eq('word1\n', register.toString());
   1.776 +  is(!register.linewise);
   1.777 +  helpers.assertCursorAt(0, 1);
   1.778 +}, { value: ' word1\nword2 ' });
   1.779 +testVim('dd', function(cm, vim, helpers) {
   1.780 +  cm.setCursor(0, 3);
   1.781 +  var expectedBuffer = cm.getRange({ line: 0, ch: 0 },
   1.782 +    { line: 1, ch: 0 });
   1.783 +  var expectedLineCount = cm.lineCount() - 1;
   1.784 +  helpers.doKeys('d', 'd');
   1.785 +  eq(expectedLineCount, cm.lineCount());
   1.786 +  var register = helpers.getRegisterController().getRegister();
   1.787 +  eq(expectedBuffer, register.toString());
   1.788 +  is(register.linewise);
   1.789 +  helpers.assertCursorAt(0, lines[1].textStart);
   1.790 +});
   1.791 +testVim('dd_prefix_repeat', function(cm, vim, helpers) {
   1.792 +  cm.setCursor(0, 3);
   1.793 +  var expectedBuffer = cm.getRange({ line: 0, ch: 0 },
   1.794 +    { line: 2, ch: 0 });
   1.795 +  var expectedLineCount = cm.lineCount() - 2;
   1.796 +  helpers.doKeys('2', 'd', 'd');
   1.797 +  eq(expectedLineCount, cm.lineCount());
   1.798 +  var register = helpers.getRegisterController().getRegister();
   1.799 +  eq(expectedBuffer, register.toString());
   1.800 +  is(register.linewise);
   1.801 +  helpers.assertCursorAt(0, lines[2].textStart);
   1.802 +});
   1.803 +testVim('dd_motion_repeat', function(cm, vim, helpers) {
   1.804 +  cm.setCursor(0, 3);
   1.805 +  var expectedBuffer = cm.getRange({ line: 0, ch: 0 },
   1.806 +    { line: 2, ch: 0 });
   1.807 +  var expectedLineCount = cm.lineCount() - 2;
   1.808 +  helpers.doKeys('d', '2', 'd');
   1.809 +  eq(expectedLineCount, cm.lineCount());
   1.810 +  var register = helpers.getRegisterController().getRegister();
   1.811 +  eq(expectedBuffer, register.toString());
   1.812 +  is(register.linewise);
   1.813 +  helpers.assertCursorAt(0, lines[2].textStart);
   1.814 +});
   1.815 +testVim('dd_multiply_repeat', function(cm, vim, helpers) {
   1.816 +  cm.setCursor(0, 3);
   1.817 +  var expectedBuffer = cm.getRange({ line: 0, ch: 0 },
   1.818 +    { line: 6, ch: 0 });
   1.819 +  var expectedLineCount = cm.lineCount() - 6;
   1.820 +  helpers.doKeys('2', 'd', '3', 'd');
   1.821 +  eq(expectedLineCount, cm.lineCount());
   1.822 +  var register = helpers.getRegisterController().getRegister();
   1.823 +  eq(expectedBuffer, register.toString());
   1.824 +  is(register.linewise);
   1.825 +  helpers.assertCursorAt(0, lines[6].textStart);
   1.826 +});
   1.827 +testVim('dd_lastline', function(cm, vim, helpers) {
   1.828 +  cm.setCursor(cm.lineCount(), 0);
   1.829 +  var expectedLineCount = cm.lineCount() - 1;
   1.830 +  helpers.doKeys('d', 'd');
   1.831 +  eq(expectedLineCount, cm.lineCount());
   1.832 +  helpers.assertCursorAt(cm.lineCount() - 1, 0);
   1.833 +});
   1.834 +// Yank commands should behave the exact same as d commands, expect that nothing
   1.835 +// gets deleted.
   1.836 +testVim('yw_repeat', function(cm, vim, helpers) {
   1.837 +  // Assert that yw does yank newline if it should go to the next line, and
   1.838 +  // that repeat works properly.
   1.839 +  var curStart = makeCursor(0, 1);
   1.840 +  cm.setCursor(curStart);
   1.841 +  helpers.doKeys('y', '2', 'w');
   1.842 +  eq(' word1\nword2', cm.getValue());
   1.843 +  var register = helpers.getRegisterController().getRegister();
   1.844 +  eq('word1\nword2', register.toString());
   1.845 +  is(!register.linewise);
   1.846 +  eqPos(curStart, cm.getCursor());
   1.847 +}, { value: ' word1\nword2' });
   1.848 +testVim('yy_multiply_repeat', function(cm, vim, helpers) {
   1.849 +  var curStart = makeCursor(0, 3);
   1.850 +  cm.setCursor(curStart);
   1.851 +  var expectedBuffer = cm.getRange({ line: 0, ch: 0 },
   1.852 +    { line: 6, ch: 0 });
   1.853 +  var expectedLineCount = cm.lineCount();
   1.854 +  helpers.doKeys('2', 'y', '3', 'y');
   1.855 +  eq(expectedLineCount, cm.lineCount());
   1.856 +  var register = helpers.getRegisterController().getRegister();
   1.857 +  eq(expectedBuffer, register.toString());
   1.858 +  is(register.linewise);
   1.859 +  eqPos(curStart, cm.getCursor());
   1.860 +});
   1.861 +// Change commands behave like d commands except that it also enters insert
   1.862 +// mode. In addition, when the change is linewise, an additional newline is
   1.863 +// inserted so that insert mode starts on that line.
   1.864 +testVim('cw', function(cm, vim, helpers) {
   1.865 +  cm.setCursor(0, 0);
   1.866 +  helpers.doKeys('c', '2', 'w');
   1.867 +  eq(' word3', cm.getValue());
   1.868 +  helpers.assertCursorAt(0, 0);
   1.869 +}, { value: 'word1 word2 word3'});
   1.870 +testVim('cw_repeat', function(cm, vim, helpers) {
   1.871 +  // Assert that cw does delete newline if it should go to the next line, and
   1.872 +  // that repeat works properly.
   1.873 +  var curStart = makeCursor(0, 1);
   1.874 +  cm.setCursor(curStart);
   1.875 +  helpers.doKeys('c', '2', 'w');
   1.876 +  eq(' ', cm.getValue());
   1.877 +  var register = helpers.getRegisterController().getRegister();
   1.878 +  eq('word1\nword2', register.toString());
   1.879 +  is(!register.linewise);
   1.880 +  eqPos(curStart, cm.getCursor());
   1.881 +  eq('vim-insert', cm.getOption('keyMap'));
   1.882 +}, { value: ' word1\nword2' });
   1.883 +testVim('cc_multiply_repeat', function(cm, vim, helpers) {
   1.884 +  cm.setCursor(0, 3);
   1.885 +  var expectedBuffer = cm.getRange({ line: 0, ch: 0 },
   1.886 +    { line: 6, ch: 0 });
   1.887 +  var expectedLineCount = cm.lineCount() - 5;
   1.888 +  helpers.doKeys('2', 'c', '3', 'c');
   1.889 +  eq(expectedLineCount, cm.lineCount());
   1.890 +  var register = helpers.getRegisterController().getRegister();
   1.891 +  eq(expectedBuffer, register.toString());
   1.892 +  is(register.linewise);
   1.893 +  eq('vim-insert', cm.getOption('keyMap'));
   1.894 +});
   1.895 +testVim('cc_append', function(cm, vim, helpers) {
   1.896 +  var expectedLineCount = cm.lineCount();
   1.897 +  cm.setCursor(cm.lastLine(), 0);
   1.898 +  helpers.doKeys('c', 'c');
   1.899 +  eq(expectedLineCount, cm.lineCount());
   1.900 +});
   1.901 +// Swapcase commands edit in place and do not modify registers.
   1.902 +testVim('g~w_repeat', function(cm, vim, helpers) {
   1.903 +  // Assert that dw does delete newline if it should go to the next line, and
   1.904 +  // that repeat works properly.
   1.905 +  var curStart = makeCursor(0, 1);
   1.906 +  cm.setCursor(curStart);
   1.907 +  helpers.doKeys('g', '~', '2', 'w');
   1.908 +  eq(' WORD1\nWORD2', cm.getValue());
   1.909 +  var register = helpers.getRegisterController().getRegister();
   1.910 +  eq('', register.toString());
   1.911 +  is(!register.linewise);
   1.912 +  eqPos(curStart, cm.getCursor());
   1.913 +}, { value: ' word1\nword2' });
   1.914 +testVim('g~g~', function(cm, vim, helpers) {
   1.915 +  var curStart = makeCursor(0, 3);
   1.916 +  cm.setCursor(curStart);
   1.917 +  var expectedLineCount = cm.lineCount();
   1.918 +  var expectedValue = cm.getValue().toUpperCase();
   1.919 +  helpers.doKeys('2', 'g', '~', '3', 'g', '~');
   1.920 +  eq(expectedValue, cm.getValue());
   1.921 +  var register = helpers.getRegisterController().getRegister();
   1.922 +  eq('', register.toString());
   1.923 +  is(!register.linewise);
   1.924 +  eqPos(curStart, cm.getCursor());
   1.925 +}, { value: ' word1\nword2\nword3\nword4\nword5\nword6' });
   1.926 +testVim('>{motion}', function(cm, vim, helpers) {
   1.927 +  cm.setCursor(1, 3);
   1.928 +  var expectedLineCount = cm.lineCount();
   1.929 +  var expectedValue = '   word1\n  word2\nword3 ';
   1.930 +  helpers.doKeys('>', 'k');
   1.931 +  eq(expectedValue, cm.getValue());
   1.932 +  var register = helpers.getRegisterController().getRegister();
   1.933 +  eq('', register.toString());
   1.934 +  is(!register.linewise);
   1.935 +  helpers.assertCursorAt(0, 3);
   1.936 +}, { value: ' word1\nword2\nword3 ', indentUnit: 2 });
   1.937 +testVim('>>', function(cm, vim, helpers) {
   1.938 +  cm.setCursor(0, 3);
   1.939 +  var expectedLineCount = cm.lineCount();
   1.940 +  var expectedValue = '   word1\n  word2\nword3 ';
   1.941 +  helpers.doKeys('2', '>', '>');
   1.942 +  eq(expectedValue, cm.getValue());
   1.943 +  var register = helpers.getRegisterController().getRegister();
   1.944 +  eq('', register.toString());
   1.945 +  is(!register.linewise);
   1.946 +  helpers.assertCursorAt(0, 3);
   1.947 +}, { value: ' word1\nword2\nword3 ', indentUnit: 2 });
   1.948 +testVim('<{motion}', function(cm, vim, helpers) {
   1.949 +  cm.setCursor(1, 3);
   1.950 +  var expectedLineCount = cm.lineCount();
   1.951 +  var expectedValue = ' word1\nword2\nword3 ';
   1.952 +  helpers.doKeys('<', 'k');
   1.953 +  eq(expectedValue, cm.getValue());
   1.954 +  var register = helpers.getRegisterController().getRegister();
   1.955 +  eq('', register.toString());
   1.956 +  is(!register.linewise);
   1.957 +  helpers.assertCursorAt(0, 1);
   1.958 +}, { value: '   word1\n  word2\nword3 ', indentUnit: 2 });
   1.959 +testVim('<<', function(cm, vim, helpers) {
   1.960 +  cm.setCursor(0, 3);
   1.961 +  var expectedLineCount = cm.lineCount();
   1.962 +  var expectedValue = ' word1\nword2\nword3 ';
   1.963 +  helpers.doKeys('2', '<', '<');
   1.964 +  eq(expectedValue, cm.getValue());
   1.965 +  var register = helpers.getRegisterController().getRegister();
   1.966 +  eq('', register.toString());
   1.967 +  is(!register.linewise);
   1.968 +  helpers.assertCursorAt(0, 1);
   1.969 +}, { value: '   word1\n  word2\nword3 ', indentUnit: 2 });
   1.970 +
   1.971 +// Edit tests
   1.972 +function testEdit(name, before, pos, edit, after) {
   1.973 +  return testVim(name, function(cm, vim, helpers) {
   1.974 +             var ch = before.search(pos)
   1.975 +             var line = before.substring(0, ch).split('\n').length - 1;
   1.976 +             if (line) {
   1.977 +               ch = before.substring(0, ch).split('\n').pop().length;
   1.978 +             }
   1.979 +             cm.setCursor(line, ch);
   1.980 +             helpers.doKeys.apply(this, edit.split(''));
   1.981 +             eq(after, cm.getValue());
   1.982 +           }, {value: before});
   1.983 +}
   1.984 +
   1.985 +// These Delete tests effectively cover word-wise Change, Visual & Yank.
   1.986 +// Tabs are used as differentiated whitespace to catch edge cases.
   1.987 +// Normal word:
   1.988 +testEdit('diw_mid_spc', 'foo \tbAr\t baz', /A/, 'diw', 'foo \t\t baz');
   1.989 +testEdit('daw_mid_spc', 'foo \tbAr\t baz', /A/, 'daw', 'foo \tbaz');
   1.990 +testEdit('diw_mid_punct', 'foo \tbAr.\t baz', /A/, 'diw', 'foo \t.\t baz');
   1.991 +testEdit('daw_mid_punct', 'foo \tbAr.\t baz', /A/, 'daw', 'foo.\t baz');
   1.992 +testEdit('diw_mid_punct2', 'foo \t,bAr.\t baz', /A/, 'diw', 'foo \t,.\t baz');
   1.993 +testEdit('daw_mid_punct2', 'foo \t,bAr.\t baz', /A/, 'daw', 'foo \t,.\t baz');
   1.994 +testEdit('diw_start_spc', 'bAr \tbaz', /A/, 'diw', ' \tbaz');
   1.995 +testEdit('daw_start_spc', 'bAr \tbaz', /A/, 'daw', 'baz');
   1.996 +testEdit('diw_start_punct', 'bAr. \tbaz', /A/, 'diw', '. \tbaz');
   1.997 +testEdit('daw_start_punct', 'bAr. \tbaz', /A/, 'daw', '. \tbaz');
   1.998 +testEdit('diw_end_spc', 'foo \tbAr', /A/, 'diw', 'foo \t');
   1.999 +testEdit('daw_end_spc', 'foo \tbAr', /A/, 'daw', 'foo');
  1.1000 +testEdit('diw_end_punct', 'foo \tbAr.', /A/, 'diw', 'foo \t.');
  1.1001 +testEdit('daw_end_punct', 'foo \tbAr.', /A/, 'daw', 'foo.');
  1.1002 +// Big word:
  1.1003 +testEdit('diW_mid_spc', 'foo \tbAr\t baz', /A/, 'diW', 'foo \t\t baz');
  1.1004 +testEdit('daW_mid_spc', 'foo \tbAr\t baz', /A/, 'daW', 'foo \tbaz');
  1.1005 +testEdit('diW_mid_punct', 'foo \tbAr.\t baz', /A/, 'diW', 'foo \t\t baz');
  1.1006 +testEdit('daW_mid_punct', 'foo \tbAr.\t baz', /A/, 'daW', 'foo \tbaz');
  1.1007 +testEdit('diW_mid_punct2', 'foo \t,bAr.\t baz', /A/, 'diW', 'foo \t\t baz');
  1.1008 +testEdit('daW_mid_punct2', 'foo \t,bAr.\t baz', /A/, 'daW', 'foo \tbaz');
  1.1009 +testEdit('diW_start_spc', 'bAr\t baz', /A/, 'diW', '\t baz');
  1.1010 +testEdit('daW_start_spc', 'bAr\t baz', /A/, 'daW', 'baz');
  1.1011 +testEdit('diW_start_punct', 'bAr.\t baz', /A/, 'diW', '\t baz');
  1.1012 +testEdit('daW_start_punct', 'bAr.\t baz', /A/, 'daW', 'baz');
  1.1013 +testEdit('diW_end_spc', 'foo \tbAr', /A/, 'diW', 'foo \t');
  1.1014 +testEdit('daW_end_spc', 'foo \tbAr', /A/, 'daW', 'foo');
  1.1015 +testEdit('diW_end_punct', 'foo \tbAr.', /A/, 'diW', 'foo \t');
  1.1016 +testEdit('daW_end_punct', 'foo \tbAr.', /A/, 'daW', 'foo');
  1.1017 +// Deleting text objects
  1.1018 +//    Open and close on same line
  1.1019 +testEdit('di(_open_spc', 'foo (bAr) baz', /\(/, 'di(', 'foo () baz');
  1.1020 +testEdit('di)_open_spc', 'foo (bAr) baz', /\(/, 'di)', 'foo () baz');
  1.1021 +testEdit('da(_open_spc', 'foo (bAr) baz', /\(/, 'da(', 'foo  baz');
  1.1022 +testEdit('da)_open_spc', 'foo (bAr) baz', /\(/, 'da)', 'foo  baz');
  1.1023 +
  1.1024 +testEdit('di(_middle_spc', 'foo (bAr) baz', /A/, 'di(', 'foo () baz');
  1.1025 +testEdit('di)_middle_spc', 'foo (bAr) baz', /A/, 'di)', 'foo () baz');
  1.1026 +testEdit('da(_middle_spc', 'foo (bAr) baz', /A/, 'da(', 'foo  baz');
  1.1027 +testEdit('da)_middle_spc', 'foo (bAr) baz', /A/, 'da)', 'foo  baz');
  1.1028 +
  1.1029 +testEdit('di(_close_spc', 'foo (bAr) baz', /\)/, 'di(', 'foo () baz');
  1.1030 +testEdit('di)_close_spc', 'foo (bAr) baz', /\)/, 'di)', 'foo () baz');
  1.1031 +testEdit('da(_close_spc', 'foo (bAr) baz', /\)/, 'da(', 'foo  baz');
  1.1032 +testEdit('da)_close_spc', 'foo (bAr) baz', /\)/, 'da)', 'foo  baz');
  1.1033 +
  1.1034 +//  Open and close on different lines, equally indented
  1.1035 +testEdit('di{_middle_spc', 'a{\n\tbar\n}b', /r/, 'di{', 'a{}b');
  1.1036 +testEdit('di}_middle_spc', 'a{\n\tbar\n}b', /r/, 'di}', 'a{}b');
  1.1037 +testEdit('da{_middle_spc', 'a{\n\tbar\n}b', /r/, 'da{', 'ab');
  1.1038 +testEdit('da}_middle_spc', 'a{\n\tbar\n}b', /r/, 'da}', 'ab');
  1.1039 +
  1.1040 +// open and close on diff lines, open indented less than close
  1.1041 +testEdit('di{_middle_spc', 'a{\n\tbar\n\t}b', /r/, 'di{', 'a{}b');
  1.1042 +testEdit('di}_middle_spc', 'a{\n\tbar\n\t}b', /r/, 'di}', 'a{}b');
  1.1043 +testEdit('da{_middle_spc', 'a{\n\tbar\n\t}b', /r/, 'da{', 'ab');
  1.1044 +testEdit('da}_middle_spc', 'a{\n\tbar\n\t}b', /r/, 'da}', 'ab');
  1.1045 +
  1.1046 +// open and close on diff lines, open indented more than close
  1.1047 +testEdit('di[_middle_spc', 'a\t[\n\tbar\n]b', /r/, 'di[', 'a\t[]b');
  1.1048 +testEdit('di]_middle_spc', 'a\t[\n\tbar\n]b', /r/, 'di]', 'a\t[]b');
  1.1049 +testEdit('da[_middle_spc', 'a\t[\n\tbar\n]b', /r/, 'da[', 'a\tb');
  1.1050 +testEdit('da]_middle_spc', 'a\t[\n\tbar\n]b', /r/, 'da]', 'a\tb');
  1.1051 +
  1.1052 +// Operator-motion tests
  1.1053 +testVim('D', function(cm, vim, helpers) {
  1.1054 +  cm.setCursor(0, 3);
  1.1055 +  helpers.doKeys('D');
  1.1056 +  eq(' wo\nword2\n word3', cm.getValue());
  1.1057 +  var register = helpers.getRegisterController().getRegister();
  1.1058 +  eq('rd1', register.toString());
  1.1059 +  is(!register.linewise);
  1.1060 +  helpers.assertCursorAt(0, 2);
  1.1061 +}, { value: ' word1\nword2\n word3' });
  1.1062 +testVim('C', function(cm, vim, helpers) {
  1.1063 +  var curStart = makeCursor(0, 3);
  1.1064 +  cm.setCursor(curStart);
  1.1065 +  helpers.doKeys('C');
  1.1066 +  eq(' wo\nword2\n word3', cm.getValue());
  1.1067 +  var register = helpers.getRegisterController().getRegister();
  1.1068 +  eq('rd1', register.toString());
  1.1069 +  is(!register.linewise);
  1.1070 +  eqPos(curStart, cm.getCursor());
  1.1071 +  eq('vim-insert', cm.getOption('keyMap'));
  1.1072 +}, { value: ' word1\nword2\n word3' });
  1.1073 +testVim('Y', function(cm, vim, helpers) {
  1.1074 +  var curStart = makeCursor(0, 3);
  1.1075 +  cm.setCursor(curStart);
  1.1076 +  helpers.doKeys('Y');
  1.1077 +  eq(' word1\nword2\n word3', cm.getValue());
  1.1078 +  var register = helpers.getRegisterController().getRegister();
  1.1079 +  eq('rd1', register.toString());
  1.1080 +  is(!register.linewise);
  1.1081 +  helpers.assertCursorAt(0, 3);
  1.1082 +}, { value: ' word1\nword2\n word3' });
  1.1083 +testVim('~', function(cm, vim, helpers) {
  1.1084 +  helpers.doKeys('3', '~');
  1.1085 +  eq('ABCdefg', cm.getValue());
  1.1086 +  helpers.assertCursorAt(0, 3);
  1.1087 +}, { value: 'abcdefg' });
  1.1088 +
  1.1089 +// Action tests
  1.1090 +testVim('ctrl-a', function(cm, vim, helpers) {
  1.1091 +  cm.setCursor(0, 0);
  1.1092 +  helpers.doKeys('<C-a>');
  1.1093 +  eq('-9', cm.getValue());
  1.1094 +  helpers.assertCursorAt(0, 1);
  1.1095 +  helpers.doKeys('2','<C-a>');
  1.1096 +  eq('-7', cm.getValue());
  1.1097 +}, {value: '-10'});
  1.1098 +testVim('ctrl-x', function(cm, vim, helpers) {
  1.1099 +  cm.setCursor(0, 0);
  1.1100 +  helpers.doKeys('<C-x>');
  1.1101 +  eq('-1', cm.getValue());
  1.1102 +  helpers.assertCursorAt(0, 1);
  1.1103 +  helpers.doKeys('2','<C-x>');
  1.1104 +  eq('-3', cm.getValue());
  1.1105 +}, {value: '0'});
  1.1106 +testVim('<C-x>/<C-a> search forward', function(cm, vim, helpers) {
  1.1107 +  forEach(['<C-x>', '<C-a>'], function(key) {
  1.1108 +    cm.setCursor(0, 0);
  1.1109 +    helpers.doKeys(key);
  1.1110 +    helpers.assertCursorAt(0, 5);
  1.1111 +    helpers.doKeys('l');
  1.1112 +    helpers.doKeys(key);
  1.1113 +    helpers.assertCursorAt(0, 10);
  1.1114 +    cm.setCursor(0, 11);
  1.1115 +    helpers.doKeys(key);
  1.1116 +    helpers.assertCursorAt(0, 11);
  1.1117 +  });
  1.1118 +}, {value: '__jmp1 jmp2 jmp'});
  1.1119 +testVim('a', function(cm, vim, helpers) {
  1.1120 +  cm.setCursor(0, 1);
  1.1121 +  helpers.doKeys('a');
  1.1122 +  helpers.assertCursorAt(0, 2);
  1.1123 +  eq('vim-insert', cm.getOption('keyMap'));
  1.1124 +});
  1.1125 +testVim('a_eol', function(cm, vim, helpers) {
  1.1126 +  cm.setCursor(0, lines[0].length - 1);
  1.1127 +  helpers.doKeys('a');
  1.1128 +  helpers.assertCursorAt(0, lines[0].length);
  1.1129 +  eq('vim-insert', cm.getOption('keyMap'));
  1.1130 +});
  1.1131 +testVim('i', function(cm, vim, helpers) {
  1.1132 +  cm.setCursor(0, 1);
  1.1133 +  helpers.doKeys('i');
  1.1134 +  helpers.assertCursorAt(0, 1);
  1.1135 +  eq('vim-insert', cm.getOption('keyMap'));
  1.1136 +});
  1.1137 +testVim('i_repeat', function(cm, vim, helpers) {
  1.1138 +  helpers.doKeys('3', 'i');
  1.1139 +  cm.replaceRange('test', cm.getCursor());
  1.1140 +  helpers.doInsertModeKeys('Esc');
  1.1141 +  eq('testtesttest', cm.getValue());
  1.1142 +  helpers.assertCursorAt(0, 11);
  1.1143 +}, { value: '' });
  1.1144 +testVim('i_repeat_delete', function(cm, vim, helpers) {
  1.1145 +  cm.setCursor(0, 4);
  1.1146 +  helpers.doKeys('2', 'i');
  1.1147 +  cm.replaceRange('z', cm.getCursor());
  1.1148 +  helpers.doInsertModeKeys('Backspace', 'Backspace', 'Esc');
  1.1149 +  eq('abe', cm.getValue());
  1.1150 +  helpers.assertCursorAt(0, 1);
  1.1151 +}, { value: 'abcde' });
  1.1152 +testVim('A', function(cm, vim, helpers) {
  1.1153 +  helpers.doKeys('A');
  1.1154 +  helpers.assertCursorAt(0, lines[0].length);
  1.1155 +  eq('vim-insert', cm.getOption('keyMap'));
  1.1156 +});
  1.1157 +testVim('I', function(cm, vim, helpers) {
  1.1158 +  cm.setCursor(0, 4);
  1.1159 +  helpers.doKeys('I');
  1.1160 +  helpers.assertCursorAt(0, lines[0].textStart);
  1.1161 +  eq('vim-insert', cm.getOption('keyMap'));
  1.1162 +});
  1.1163 +testVim('I_repeat', function(cm, vim, helpers) {
  1.1164 +  cm.setCursor(0, 1);
  1.1165 +  helpers.doKeys('3', 'I');
  1.1166 +  cm.replaceRange('test', cm.getCursor());
  1.1167 +  helpers.doInsertModeKeys('Esc');
  1.1168 +  eq('testtesttestblah', cm.getValue());
  1.1169 +  helpers.assertCursorAt(0, 11);
  1.1170 +}, { value: 'blah' });
  1.1171 +testVim('o', function(cm, vim, helpers) {
  1.1172 +  cm.setCursor(0, 4);
  1.1173 +  helpers.doKeys('o');
  1.1174 +  eq('word1\n\nword2', cm.getValue());
  1.1175 +  helpers.assertCursorAt(1, 0);
  1.1176 +  eq('vim-insert', cm.getOption('keyMap'));
  1.1177 +}, { value: 'word1\nword2' });
  1.1178 +testVim('o_repeat', function(cm, vim, helpers) {
  1.1179 +  cm.setCursor(0, 0);
  1.1180 +  helpers.doKeys('3', 'o');
  1.1181 +  cm.replaceRange('test', cm.getCursor());
  1.1182 +  helpers.doInsertModeKeys('Esc');
  1.1183 +  eq('\ntest\ntest\ntest', cm.getValue());
  1.1184 +  helpers.assertCursorAt(3, 3);
  1.1185 +}, { value: '' });
  1.1186 +testVim('O', function(cm, vim, helpers) {
  1.1187 +  cm.setCursor(0, 4);
  1.1188 +  helpers.doKeys('O');
  1.1189 +  eq('\nword1\nword2', cm.getValue());
  1.1190 +  helpers.assertCursorAt(0, 0);
  1.1191 +  eq('vim-insert', cm.getOption('keyMap'));
  1.1192 +}, { value: 'word1\nword2' });
  1.1193 +testVim('J', function(cm, vim, helpers) {
  1.1194 +  cm.setCursor(0, 4);
  1.1195 +  helpers.doKeys('J');
  1.1196 +  var expectedValue = 'word1  word2\nword3\n word4';
  1.1197 +  eq(expectedValue, cm.getValue());
  1.1198 +  helpers.assertCursorAt(0, expectedValue.indexOf('word2') - 1);
  1.1199 +}, { value: 'word1 \n    word2\nword3\n word4' });
  1.1200 +testVim('J_repeat', function(cm, vim, helpers) {
  1.1201 +  cm.setCursor(0, 4);
  1.1202 +  helpers.doKeys('3', 'J');
  1.1203 +  var expectedValue = 'word1  word2 word3\n word4';
  1.1204 +  eq(expectedValue, cm.getValue());
  1.1205 +  helpers.assertCursorAt(0, expectedValue.indexOf('word3') - 1);
  1.1206 +}, { value: 'word1 \n    word2\nword3\n word4' });
  1.1207 +testVim('p', function(cm, vim, helpers) {
  1.1208 +  cm.setCursor(0, 1);
  1.1209 +  helpers.getRegisterController().pushText('"', 'yank', 'abc\ndef', false);
  1.1210 +  helpers.doKeys('p');
  1.1211 +  eq('__abc\ndef_', cm.getValue());
  1.1212 +  helpers.assertCursorAt(1, 2);
  1.1213 +}, { value: '___' });
  1.1214 +testVim('p_register', function(cm, vim, helpers) {
  1.1215 +  cm.setCursor(0, 1);
  1.1216 +  helpers.getRegisterController().getRegister('a').setText('abc\ndef', false);
  1.1217 +  helpers.doKeys('"', 'a', 'p');
  1.1218 +  eq('__abc\ndef_', cm.getValue());
  1.1219 +  helpers.assertCursorAt(1, 2);
  1.1220 +}, { value: '___' });
  1.1221 +testVim('p_wrong_register', function(cm, vim, helpers) {
  1.1222 +  cm.setCursor(0, 1);
  1.1223 +  helpers.getRegisterController().getRegister('a').setText('abc\ndef', false);
  1.1224 +  helpers.doKeys('p');
  1.1225 +  eq('___', cm.getValue());
  1.1226 +  helpers.assertCursorAt(0, 1);
  1.1227 +}, { value: '___' });
  1.1228 +testVim('p_line', function(cm, vim, helpers) {
  1.1229 +  cm.setCursor(0, 1);
  1.1230 +  helpers.getRegisterController().pushText('"', 'yank', '  a\nd\n', true);
  1.1231 +  helpers.doKeys('2', 'p');
  1.1232 +  eq('___\n  a\nd\n  a\nd', cm.getValue());
  1.1233 +  helpers.assertCursorAt(1, 2);
  1.1234 +}, { value: '___' });
  1.1235 +testVim('p_lastline', function(cm, vim, helpers) {
  1.1236 +  cm.setCursor(0, 1);
  1.1237 +  helpers.getRegisterController().pushText('"', 'yank', '  a\nd', true);
  1.1238 +  helpers.doKeys('2', 'p');
  1.1239 +  eq('___\n  a\nd\n  a\nd', cm.getValue());
  1.1240 +  helpers.assertCursorAt(1, 2);
  1.1241 +}, { value: '___' });
  1.1242 +testVim('P', function(cm, vim, helpers) {
  1.1243 +  cm.setCursor(0, 1);
  1.1244 +  helpers.getRegisterController().pushText('"', 'yank', 'abc\ndef', false);
  1.1245 +  helpers.doKeys('P');
  1.1246 +  eq('_abc\ndef__', cm.getValue());
  1.1247 +  helpers.assertCursorAt(1, 3);
  1.1248 +}, { value: '___' });
  1.1249 +testVim('P_line', function(cm, vim, helpers) {
  1.1250 +  cm.setCursor(0, 1);
  1.1251 +  helpers.getRegisterController().pushText('"', 'yank', '  a\nd\n', true);
  1.1252 +  helpers.doKeys('2', 'P');
  1.1253 +  eq('  a\nd\n  a\nd\n___', cm.getValue());
  1.1254 +  helpers.assertCursorAt(0, 2);
  1.1255 +}, { value: '___' });
  1.1256 +testVim('r', function(cm, vim, helpers) {
  1.1257 +  cm.setCursor(0, 1);
  1.1258 +  helpers.doKeys('3', 'r', 'u');
  1.1259 +  eq('wuuuet\nanother', cm.getValue(),'3r failed');
  1.1260 +  helpers.assertCursorAt(0, 3);
  1.1261 +  cm.setCursor(0, 4);
  1.1262 +  helpers.doKeys('v', 'j', 'h', 'r', '<Space>');
  1.1263 +  eq('wuuu  \n    her', cm.getValue(),'Replacing selection by space-characters failed');
  1.1264 +}, { value: 'wordet\nanother' });
  1.1265 +testVim('R', function(cm, vim, helpers) {
  1.1266 +  cm.setCursor(0, 1);
  1.1267 +  helpers.doKeys('R');
  1.1268 +  helpers.assertCursorAt(0, 1);
  1.1269 +  eq('vim-replace', cm.getOption('keyMap'));
  1.1270 +  is(cm.state.overwrite, 'Setting overwrite state failed');
  1.1271 +});
  1.1272 +testVim('mark', function(cm, vim, helpers) {
  1.1273 +  cm.setCursor(2, 2);
  1.1274 +  helpers.doKeys('m', 't');
  1.1275 +  cm.setCursor(0, 0);
  1.1276 +  helpers.doKeys('\'', 't');
  1.1277 +  helpers.assertCursorAt(2, 2);
  1.1278 +  cm.setCursor(0, 0);
  1.1279 +  helpers.doKeys('`', 't');
  1.1280 +  helpers.assertCursorAt(2, 2);
  1.1281 +});
  1.1282 +testVim('jumpToMark_next', function(cm, vim, helpers) {
  1.1283 +  cm.setCursor(2, 2);
  1.1284 +  helpers.doKeys('m', 't');
  1.1285 +  cm.setCursor(0, 0);
  1.1286 +  helpers.doKeys(']', '`');
  1.1287 +  helpers.assertCursorAt(2, 2);
  1.1288 +  cm.setCursor(0, 0);
  1.1289 +  helpers.doKeys(']', '\'');
  1.1290 +  helpers.assertCursorAt(2, 0);
  1.1291 +});
  1.1292 +testVim('jumpToMark_next_repeat', function(cm, vim, helpers) {
  1.1293 +  cm.setCursor(2, 2);
  1.1294 +  helpers.doKeys('m', 'a');
  1.1295 +  cm.setCursor(3, 2);
  1.1296 +  helpers.doKeys('m', 'b');
  1.1297 +  cm.setCursor(4, 2);
  1.1298 +  helpers.doKeys('m', 'c');
  1.1299 +  cm.setCursor(0, 0);
  1.1300 +  helpers.doKeys('2', ']', '`');
  1.1301 +  helpers.assertCursorAt(3, 2);
  1.1302 +  cm.setCursor(0, 0);
  1.1303 +  helpers.doKeys('2', ']', '\'');
  1.1304 +  helpers.assertCursorAt(3, 1);
  1.1305 +});
  1.1306 +testVim('jumpToMark_next_sameline', function(cm, vim, helpers) {
  1.1307 +  cm.setCursor(2, 0);
  1.1308 +  helpers.doKeys('m', 'a');
  1.1309 +  cm.setCursor(2, 4);
  1.1310 +  helpers.doKeys('m', 'b');
  1.1311 +  cm.setCursor(2, 2);
  1.1312 +  helpers.doKeys(']', '`');
  1.1313 +  helpers.assertCursorAt(2, 4);
  1.1314 +});
  1.1315 +testVim('jumpToMark_next_onlyprev', function(cm, vim, helpers) {
  1.1316 +  cm.setCursor(2, 0);
  1.1317 +  helpers.doKeys('m', 'a');
  1.1318 +  cm.setCursor(4, 0);
  1.1319 +  helpers.doKeys(']', '`');
  1.1320 +  helpers.assertCursorAt(4, 0);
  1.1321 +});
  1.1322 +testVim('jumpToMark_next_nomark', function(cm, vim, helpers) {
  1.1323 +  cm.setCursor(2, 2);
  1.1324 +  helpers.doKeys(']', '`');
  1.1325 +  helpers.assertCursorAt(2, 2);
  1.1326 +  helpers.doKeys(']', '\'');
  1.1327 +  helpers.assertCursorAt(2, 0);
  1.1328 +});
  1.1329 +testVim('jumpToMark_next_linewise_over', function(cm, vim, helpers) {
  1.1330 +  cm.setCursor(2, 2);
  1.1331 +  helpers.doKeys('m', 'a');
  1.1332 +  cm.setCursor(3, 4);
  1.1333 +  helpers.doKeys('m', 'b');
  1.1334 +  cm.setCursor(2, 1);
  1.1335 +  helpers.doKeys(']', '\'');
  1.1336 +  helpers.assertCursorAt(3, 1);
  1.1337 +});
  1.1338 +testVim('jumpToMark_next_action', function(cm, vim, helpers) {
  1.1339 +  cm.setCursor(2, 2);
  1.1340 +  helpers.doKeys('m', 't');
  1.1341 +  cm.setCursor(0, 0);
  1.1342 +  helpers.doKeys('d', ']', '`');
  1.1343 +  helpers.assertCursorAt(0, 0);
  1.1344 +  var actual = cm.getLine(0);
  1.1345 +  var expected = 'pop pop 0 1 2 3 4';
  1.1346 +  eq(actual, expected, "Deleting while jumping to the next mark failed.");
  1.1347 +});
  1.1348 +testVim('jumpToMark_next_line_action', function(cm, vim, helpers) {
  1.1349 +  cm.setCursor(2, 2);
  1.1350 +  helpers.doKeys('m', 't');
  1.1351 +  cm.setCursor(0, 0);
  1.1352 +  helpers.doKeys('d', ']', '\'');
  1.1353 +  helpers.assertCursorAt(0, 1);
  1.1354 +  var actual = cm.getLine(0);
  1.1355 +  var expected = ' (a) [b] {c} '
  1.1356 +  eq(actual, expected, "Deleting while jumping to the next mark line failed.");
  1.1357 +});
  1.1358 +testVim('jumpToMark_prev', function(cm, vim, helpers) {
  1.1359 +  cm.setCursor(2, 2);
  1.1360 +  helpers.doKeys('m', 't');
  1.1361 +  cm.setCursor(4, 0);
  1.1362 +  helpers.doKeys('[', '`');
  1.1363 +  helpers.assertCursorAt(2, 2);
  1.1364 +  cm.setCursor(4, 0);
  1.1365 +  helpers.doKeys('[', '\'');
  1.1366 +  helpers.assertCursorAt(2, 0);
  1.1367 +});
  1.1368 +testVim('jumpToMark_prev_repeat', function(cm, vim, helpers) {
  1.1369 +  cm.setCursor(2, 2);
  1.1370 +  helpers.doKeys('m', 'a');
  1.1371 +  cm.setCursor(3, 2);
  1.1372 +  helpers.doKeys('m', 'b');
  1.1373 +  cm.setCursor(4, 2);
  1.1374 +  helpers.doKeys('m', 'c');
  1.1375 +  cm.setCursor(5, 0);
  1.1376 +  helpers.doKeys('2', '[', '`');
  1.1377 +  helpers.assertCursorAt(3, 2);
  1.1378 +  cm.setCursor(5, 0);
  1.1379 +  helpers.doKeys('2', '[', '\'');
  1.1380 +  helpers.assertCursorAt(3, 1);
  1.1381 +});
  1.1382 +testVim('jumpToMark_prev_sameline', function(cm, vim, helpers) {
  1.1383 +  cm.setCursor(2, 0);
  1.1384 +  helpers.doKeys('m', 'a');
  1.1385 +  cm.setCursor(2, 4);
  1.1386 +  helpers.doKeys('m', 'b');
  1.1387 +  cm.setCursor(2, 2);
  1.1388 +  helpers.doKeys('[', '`');
  1.1389 +  helpers.assertCursorAt(2, 0);
  1.1390 +});
  1.1391 +testVim('jumpToMark_prev_onlynext', function(cm, vim, helpers) {
  1.1392 +  cm.setCursor(4, 4);
  1.1393 +  helpers.doKeys('m', 'a');
  1.1394 +  cm.setCursor(2, 0);
  1.1395 +  helpers.doKeys('[', '`');
  1.1396 +  helpers.assertCursorAt(2, 0);
  1.1397 +});
  1.1398 +testVim('jumpToMark_prev_nomark', function(cm, vim, helpers) {
  1.1399 +  cm.setCursor(2, 2);
  1.1400 +  helpers.doKeys('[', '`');
  1.1401 +  helpers.assertCursorAt(2, 2);
  1.1402 +  helpers.doKeys('[', '\'');
  1.1403 +  helpers.assertCursorAt(2, 0);
  1.1404 +});
  1.1405 +testVim('jumpToMark_prev_linewise_over', function(cm, vim, helpers) {
  1.1406 +  cm.setCursor(2, 2);
  1.1407 +  helpers.doKeys('m', 'a');
  1.1408 +  cm.setCursor(3, 4);
  1.1409 +  helpers.doKeys('m', 'b');
  1.1410 +  cm.setCursor(3, 6);
  1.1411 +  helpers.doKeys('[', '\'');
  1.1412 +  helpers.assertCursorAt(2, 0);
  1.1413 +});
  1.1414 +testVim('delmark_single', function(cm, vim, helpers) {
  1.1415 +  cm.setCursor(1, 2);
  1.1416 +  helpers.doKeys('m', 't');
  1.1417 +  helpers.doEx('delmarks t');
  1.1418 +  cm.setCursor(0, 0);
  1.1419 +  helpers.doKeys('`', 't');
  1.1420 +  helpers.assertCursorAt(0, 0);
  1.1421 +});
  1.1422 +testVim('delmark_range', function(cm, vim, helpers) {
  1.1423 +  cm.setCursor(1, 2);
  1.1424 +  helpers.doKeys('m', 'a');
  1.1425 +  cm.setCursor(2, 2);
  1.1426 +  helpers.doKeys('m', 'b');
  1.1427 +  cm.setCursor(3, 2);
  1.1428 +  helpers.doKeys('m', 'c');
  1.1429 +  cm.setCursor(4, 2);
  1.1430 +  helpers.doKeys('m', 'd');
  1.1431 +  cm.setCursor(5, 2);
  1.1432 +  helpers.doKeys('m', 'e');
  1.1433 +  helpers.doEx('delmarks b-d');
  1.1434 +  cm.setCursor(0, 0);
  1.1435 +  helpers.doKeys('`', 'a');
  1.1436 +  helpers.assertCursorAt(1, 2);
  1.1437 +  helpers.doKeys('`', 'b');
  1.1438 +  helpers.assertCursorAt(1, 2);
  1.1439 +  helpers.doKeys('`', 'c');
  1.1440 +  helpers.assertCursorAt(1, 2);
  1.1441 +  helpers.doKeys('`', 'd');
  1.1442 +  helpers.assertCursorAt(1, 2);
  1.1443 +  helpers.doKeys('`', 'e');
  1.1444 +  helpers.assertCursorAt(5, 2);
  1.1445 +});
  1.1446 +testVim('delmark_multi', function(cm, vim, helpers) {
  1.1447 +  cm.setCursor(1, 2);
  1.1448 +  helpers.doKeys('m', 'a');
  1.1449 +  cm.setCursor(2, 2);
  1.1450 +  helpers.doKeys('m', 'b');
  1.1451 +  cm.setCursor(3, 2);
  1.1452 +  helpers.doKeys('m', 'c');
  1.1453 +  cm.setCursor(4, 2);
  1.1454 +  helpers.doKeys('m', 'd');
  1.1455 +  cm.setCursor(5, 2);
  1.1456 +  helpers.doKeys('m', 'e');
  1.1457 +  helpers.doEx('delmarks bcd');
  1.1458 +  cm.setCursor(0, 0);
  1.1459 +  helpers.doKeys('`', 'a');
  1.1460 +  helpers.assertCursorAt(1, 2);
  1.1461 +  helpers.doKeys('`', 'b');
  1.1462 +  helpers.assertCursorAt(1, 2);
  1.1463 +  helpers.doKeys('`', 'c');
  1.1464 +  helpers.assertCursorAt(1, 2);
  1.1465 +  helpers.doKeys('`', 'd');
  1.1466 +  helpers.assertCursorAt(1, 2);
  1.1467 +  helpers.doKeys('`', 'e');
  1.1468 +  helpers.assertCursorAt(5, 2);
  1.1469 +});
  1.1470 +testVim('delmark_multi_space', function(cm, vim, helpers) {
  1.1471 +  cm.setCursor(1, 2);
  1.1472 +  helpers.doKeys('m', 'a');
  1.1473 +  cm.setCursor(2, 2);
  1.1474 +  helpers.doKeys('m', 'b');
  1.1475 +  cm.setCursor(3, 2);
  1.1476 +  helpers.doKeys('m', 'c');
  1.1477 +  cm.setCursor(4, 2);
  1.1478 +  helpers.doKeys('m', 'd');
  1.1479 +  cm.setCursor(5, 2);
  1.1480 +  helpers.doKeys('m', 'e');
  1.1481 +  helpers.doEx('delmarks b c d');
  1.1482 +  cm.setCursor(0, 0);
  1.1483 +  helpers.doKeys('`', 'a');
  1.1484 +  helpers.assertCursorAt(1, 2);
  1.1485 +  helpers.doKeys('`', 'b');
  1.1486 +  helpers.assertCursorAt(1, 2);
  1.1487 +  helpers.doKeys('`', 'c');
  1.1488 +  helpers.assertCursorAt(1, 2);
  1.1489 +  helpers.doKeys('`', 'd');
  1.1490 +  helpers.assertCursorAt(1, 2);
  1.1491 +  helpers.doKeys('`', 'e');
  1.1492 +  helpers.assertCursorAt(5, 2);
  1.1493 +});
  1.1494 +testVim('delmark_all', function(cm, vim, helpers) {
  1.1495 +  cm.setCursor(1, 2);
  1.1496 +  helpers.doKeys('m', 'a');
  1.1497 +  cm.setCursor(2, 2);
  1.1498 +  helpers.doKeys('m', 'b');
  1.1499 +  cm.setCursor(3, 2);
  1.1500 +  helpers.doKeys('m', 'c');
  1.1501 +  cm.setCursor(4, 2);
  1.1502 +  helpers.doKeys('m', 'd');
  1.1503 +  cm.setCursor(5, 2);
  1.1504 +  helpers.doKeys('m', 'e');
  1.1505 +  helpers.doEx('delmarks a b-de');
  1.1506 +  cm.setCursor(0, 0);
  1.1507 +  helpers.doKeys('`', 'a');
  1.1508 +  helpers.assertCursorAt(0, 0);
  1.1509 +  helpers.doKeys('`', 'b');
  1.1510 +  helpers.assertCursorAt(0, 0);
  1.1511 +  helpers.doKeys('`', 'c');
  1.1512 +  helpers.assertCursorAt(0, 0);
  1.1513 +  helpers.doKeys('`', 'd');
  1.1514 +  helpers.assertCursorAt(0, 0);
  1.1515 +  helpers.doKeys('`', 'e');
  1.1516 +  helpers.assertCursorAt(0, 0);
  1.1517 +});
  1.1518 +testVim('visual', function(cm, vim, helpers) {
  1.1519 +  helpers.doKeys('l', 'v', 'l', 'l');
  1.1520 +  helpers.assertCursorAt(0, 3);
  1.1521 +  eqPos(makeCursor(0, 1), cm.getCursor('anchor'));
  1.1522 +  helpers.doKeys('d');
  1.1523 +  eq('15', cm.getValue());
  1.1524 +}, { value: '12345' });
  1.1525 +testVim('visual_line', function(cm, vim, helpers) {
  1.1526 +  helpers.doKeys('l', 'V', 'l', 'j', 'j', 'd');
  1.1527 +  eq(' 4\n 5', cm.getValue());
  1.1528 +}, { value: ' 1\n 2\n 3\n 4\n 5' });
  1.1529 +testVim('visual_marks', function(cm, vim, helpers) {
  1.1530 +  helpers.doKeys('l', 'v', 'l', 'l', 'v');
  1.1531 +  // Test visual mode marks
  1.1532 +  cm.setCursor(0, 0);
  1.1533 +  helpers.doKeys('\'', '<');
  1.1534 +  helpers.assertCursorAt(0, 1);
  1.1535 +  helpers.doKeys('\'', '>');
  1.1536 +  helpers.assertCursorAt(0, 3);
  1.1537 +});
  1.1538 +testVim('visual_join', function(cm, vim, helpers) {
  1.1539 +  helpers.doKeys('l', 'V', 'l', 'j', 'j', 'J');
  1.1540 +  eq(' 1 2 3\n 4\n 5', cm.getValue());
  1.1541 +}, { value: ' 1\n 2\n 3\n 4\n 5' });
  1.1542 +testVim('visual_blank', function(cm, vim, helpers) {
  1.1543 +  helpers.doKeys('v', 'k');
  1.1544 +  eq(vim.visualMode, true);
  1.1545 +}, { value: '\n' });
  1.1546 +testVim('reselect_visual', function(cm, vim, helpers) {
  1.1547 +  helpers.doKeys('l', 'v', 'l', 'l', 'y', 'g', 'v');
  1.1548 +  helpers.assertCursorAt(0, 3);
  1.1549 +  eqPos(makeCursor(0, 1), cm.getCursor('anchor'));
  1.1550 +  helpers.doKeys('d');
  1.1551 +  eq('15', cm.getValue());
  1.1552 +}, { value: '12345' });
  1.1553 +testVim('reselect_visual_line', function(cm, vim, helpers) {
  1.1554 +  helpers.doKeys('l', 'V', 'l', 'j', 'j', 'V', 'g', 'v', 'd');
  1.1555 +  eq(' 4\n 5', cm.getValue());
  1.1556 +}, { value: ' 1\n 2\n 3\n 4\n 5' });
  1.1557 +testVim('s_normal', function(cm, vim, helpers) {
  1.1558 +  cm.setCursor(0, 1);
  1.1559 +  helpers.doKeys('s');
  1.1560 +  helpers.doInsertModeKeys('Esc');
  1.1561 +  helpers.assertCursorAt(0, 0);
  1.1562 +  eq('ac', cm.getValue());
  1.1563 +}, { value: 'abc'});
  1.1564 +testVim('s_visual', function(cm, vim, helpers) {
  1.1565 +  cm.setCursor(0, 1);
  1.1566 +  helpers.doKeys('v', 's');
  1.1567 +  helpers.doInsertModeKeys('Esc');
  1.1568 +  helpers.assertCursorAt(0, 0);
  1.1569 +  eq('ac', cm.getValue());
  1.1570 +}, { value: 'abc'});
  1.1571 +testVim('o_visual', function(cm,vim,helpers) {
  1.1572 +  cm.setCursor(0,0);
  1.1573 +  helpers.doKeys('v','l','l','l','o');
  1.1574 +  helpers.assertCursorAt(0,0);
  1.1575 +  helpers.doKeys('v','v','j','j','j','o');
  1.1576 +  helpers.assertCursorAt(0,0);
  1.1577 +  helpers.doKeys('o');
  1.1578 +  helpers.doKeys('l','l')
  1.1579 +  helpers.assertCursorAt(3,2);
  1.1580 +  helpers.doKeys('d');
  1.1581 +  eq('p',cm.getValue());
  1.1582 +}, { value: 'abcd\nefgh\nijkl\nmnop'});
  1.1583 +
  1.1584 +testVim('S_normal', function(cm, vim, helpers) {
  1.1585 +  cm.setCursor(0, 1);
  1.1586 +  helpers.doKeys('j', 'S');
  1.1587 +  helpers.doInsertModeKeys('Esc');
  1.1588 +  helpers.assertCursorAt(1, 0);
  1.1589 +  eq('aa\n\ncc', cm.getValue());
  1.1590 +}, { value: 'aa\nbb\ncc'});
  1.1591 +testVim('S_visual', function(cm, vim, helpers) {
  1.1592 +  cm.setCursor(0, 1);
  1.1593 +  helpers.doKeys('v', 'j', 'S');
  1.1594 +  helpers.doInsertModeKeys('Esc');
  1.1595 +  helpers.assertCursorAt(0, 0);
  1.1596 +  eq('\ncc', cm.getValue());
  1.1597 +}, { value: 'aa\nbb\ncc'});
  1.1598 +
  1.1599 +testVim('/ and n/N', function(cm, vim, helpers) {
  1.1600 +  cm.openDialog = helpers.fakeOpenDialog('match');
  1.1601 +  helpers.doKeys('/');
  1.1602 +  helpers.assertCursorAt(0, 11);
  1.1603 +  helpers.doKeys('n');
  1.1604 +  helpers.assertCursorAt(1, 6);
  1.1605 +  helpers.doKeys('N');
  1.1606 +  helpers.assertCursorAt(0, 11);
  1.1607 +
  1.1608 +  cm.setCursor(0, 0);
  1.1609 +  helpers.doKeys('2', '/');
  1.1610 +  helpers.assertCursorAt(1, 6);
  1.1611 +}, { value: 'match nope match \n nope Match' });
  1.1612 +testVim('/_case', function(cm, vim, helpers) {
  1.1613 +  cm.openDialog = helpers.fakeOpenDialog('Match');
  1.1614 +  helpers.doKeys('/');
  1.1615 +  helpers.assertCursorAt(1, 6);
  1.1616 +}, { value: 'match nope match \n nope Match' });
  1.1617 +testVim('/_2_pcre', function(cm, vim, helpers) {
  1.1618 +  CodeMirror.Vim.setOption('pcre', true);
  1.1619 +  cm.openDialog = helpers.fakeOpenDialog('(word){2}');
  1.1620 +  helpers.doKeys('/');
  1.1621 +  helpers.assertCursorAt(1, 9);
  1.1622 +  helpers.doKeys('n');
  1.1623 +  helpers.assertCursorAt(2, 1);
  1.1624 +}, { value: 'word\n another wordword\n wordwordword\n' });
  1.1625 +testVim('/_2_nopcre', function(cm, vim, helpers) {
  1.1626 +  CodeMirror.Vim.setOption('pcre', false);
  1.1627 +  cm.openDialog = helpers.fakeOpenDialog('\\(word\\)\\{2}');
  1.1628 +  helpers.doKeys('/');
  1.1629 +  helpers.assertCursorAt(1, 9);
  1.1630 +  helpers.doKeys('n');
  1.1631 +  helpers.assertCursorAt(2, 1);
  1.1632 +}, { value: 'word\n another wordword\n wordwordword\n' });
  1.1633 +testVim('/_nongreedy', function(cm, vim, helpers) {
  1.1634 +  cm.openDialog = helpers.fakeOpenDialog('aa');
  1.1635 +  helpers.doKeys('/');
  1.1636 +  helpers.assertCursorAt(0, 4);
  1.1637 +  helpers.doKeys('n');
  1.1638 +  helpers.assertCursorAt(1, 3);
  1.1639 +  helpers.doKeys('n');
  1.1640 +  helpers.assertCursorAt(0, 0);
  1.1641 +}, { value: 'aaa aa \n a aa'});
  1.1642 +testVim('?_nongreedy', function(cm, vim, helpers) {
  1.1643 +  cm.openDialog = helpers.fakeOpenDialog('aa');
  1.1644 +  helpers.doKeys('?');
  1.1645 +  helpers.assertCursorAt(1, 3);
  1.1646 +  helpers.doKeys('n');
  1.1647 +  helpers.assertCursorAt(0, 4);
  1.1648 +  helpers.doKeys('n');
  1.1649 +  helpers.assertCursorAt(0, 0);
  1.1650 +}, { value: 'aaa aa \n a aa'});
  1.1651 +testVim('/_greedy', function(cm, vim, helpers) {
  1.1652 +  cm.openDialog = helpers.fakeOpenDialog('a+');
  1.1653 +  helpers.doKeys('/');
  1.1654 +  helpers.assertCursorAt(0, 4);
  1.1655 +  helpers.doKeys('n');
  1.1656 +  helpers.assertCursorAt(1, 1);
  1.1657 +  helpers.doKeys('n');
  1.1658 +  helpers.assertCursorAt(1, 3);
  1.1659 +  helpers.doKeys('n');
  1.1660 +  helpers.assertCursorAt(0, 0);
  1.1661 +}, { value: 'aaa aa \n a aa'});
  1.1662 +testVim('?_greedy', function(cm, vim, helpers) {
  1.1663 +  cm.openDialog = helpers.fakeOpenDialog('a+');
  1.1664 +  helpers.doKeys('?');
  1.1665 +  helpers.assertCursorAt(1, 3);
  1.1666 +  helpers.doKeys('n');
  1.1667 +  helpers.assertCursorAt(1, 1);
  1.1668 +  helpers.doKeys('n');
  1.1669 +  helpers.assertCursorAt(0, 4);
  1.1670 +  helpers.doKeys('n');
  1.1671 +  helpers.assertCursorAt(0, 0);
  1.1672 +}, { value: 'aaa aa \n a aa'});
  1.1673 +testVim('/_greedy_0_or_more', function(cm, vim, helpers) {
  1.1674 +  cm.openDialog = helpers.fakeOpenDialog('a*');
  1.1675 +  helpers.doKeys('/');
  1.1676 +  helpers.assertCursorAt(0, 3);
  1.1677 +  helpers.doKeys('n');
  1.1678 +  helpers.assertCursorAt(0, 4);
  1.1679 +  helpers.doKeys('n');
  1.1680 +  helpers.assertCursorAt(0, 5);
  1.1681 +  helpers.doKeys('n');
  1.1682 +  helpers.assertCursorAt(1, 0);
  1.1683 +  helpers.doKeys('n');
  1.1684 +  helpers.assertCursorAt(1, 1);
  1.1685 +  helpers.doKeys('n');
  1.1686 +  helpers.assertCursorAt(0, 0);
  1.1687 +}, { value: 'aaa  aa\n aa'});
  1.1688 +testVim('?_greedy_0_or_more', function(cm, vim, helpers) {
  1.1689 +  cm.openDialog = helpers.fakeOpenDialog('a*');
  1.1690 +  helpers.doKeys('?');
  1.1691 +  helpers.assertCursorAt(1, 1);
  1.1692 +  helpers.doKeys('n');
  1.1693 +  helpers.assertCursorAt(1, 0);
  1.1694 +  helpers.doKeys('n');
  1.1695 +  helpers.assertCursorAt(0, 5);
  1.1696 +  helpers.doKeys('n');
  1.1697 +  helpers.assertCursorAt(0, 4);
  1.1698 +  helpers.doKeys('n');
  1.1699 +  helpers.assertCursorAt(0, 3);
  1.1700 +  helpers.doKeys('n');
  1.1701 +  helpers.assertCursorAt(0, 0);
  1.1702 +}, { value: 'aaa  aa\n aa'});
  1.1703 +testVim('? and n/N', function(cm, vim, helpers) {
  1.1704 +  cm.openDialog = helpers.fakeOpenDialog('match');
  1.1705 +  helpers.doKeys('?');
  1.1706 +  helpers.assertCursorAt(1, 6);
  1.1707 +  helpers.doKeys('n');
  1.1708 +  helpers.assertCursorAt(0, 11);
  1.1709 +  helpers.doKeys('N');
  1.1710 +  helpers.assertCursorAt(1, 6);
  1.1711 +
  1.1712 +  cm.setCursor(0, 0);
  1.1713 +  helpers.doKeys('2', '?');
  1.1714 +  helpers.assertCursorAt(0, 11);
  1.1715 +}, { value: 'match nope match \n nope Match' });
  1.1716 +testVim('*', function(cm, vim, helpers) {
  1.1717 +  cm.setCursor(0, 9);
  1.1718 +  helpers.doKeys('*');
  1.1719 +  helpers.assertCursorAt(0, 22);
  1.1720 +
  1.1721 +  cm.setCursor(0, 9);
  1.1722 +  helpers.doKeys('2', '*');
  1.1723 +  helpers.assertCursorAt(1, 8);
  1.1724 +}, { value: 'nomatch match nomatch match \nnomatch Match' });
  1.1725 +testVim('*_no_word', function(cm, vim, helpers) {
  1.1726 +  cm.setCursor(0, 0);
  1.1727 +  helpers.doKeys('*');
  1.1728 +  helpers.assertCursorAt(0, 0);
  1.1729 +}, { value: ' \n match \n' });
  1.1730 +testVim('*_symbol', function(cm, vim, helpers) {
  1.1731 +  cm.setCursor(0, 0);
  1.1732 +  helpers.doKeys('*');
  1.1733 +  helpers.assertCursorAt(1, 0);
  1.1734 +}, { value: ' /}\n/} match \n' });
  1.1735 +testVim('#', function(cm, vim, helpers) {
  1.1736 +  cm.setCursor(0, 9);
  1.1737 +  helpers.doKeys('#');
  1.1738 +  helpers.assertCursorAt(1, 8);
  1.1739 +
  1.1740 +  cm.setCursor(0, 9);
  1.1741 +  helpers.doKeys('2', '#');
  1.1742 +  helpers.assertCursorAt(0, 22);
  1.1743 +}, { value: 'nomatch match nomatch match \nnomatch Match' });
  1.1744 +testVim('*_seek', function(cm, vim, helpers) {
  1.1745 +  // Should skip over space and symbols.
  1.1746 +  cm.setCursor(0, 3);
  1.1747 +  helpers.doKeys('*');
  1.1748 +  helpers.assertCursorAt(0, 22);
  1.1749 +}, { value: '    :=  match nomatch match \nnomatch Match' });
  1.1750 +testVim('#', function(cm, vim, helpers) {
  1.1751 +  // Should skip over space and symbols.
  1.1752 +  cm.setCursor(0, 3);
  1.1753 +  helpers.doKeys('#');
  1.1754 +  helpers.assertCursorAt(1, 8);
  1.1755 +}, { value: '    :=  match nomatch match \nnomatch Match' });
  1.1756 +testVim('macro_insert', function(cm, vim, helpers) {
  1.1757 +  cm.setCursor(0, 0);
  1.1758 +  helpers.doKeys('q', 'a', '0', 'i');
  1.1759 +  cm.replaceRange('foo', cm.getCursor());
  1.1760 +  helpers.doInsertModeKeys('Esc');
  1.1761 +  helpers.doKeys('q', '@', 'a');
  1.1762 +  eq('foofoo', cm.getValue());
  1.1763 +}, { value: ''});
  1.1764 +testVim('macro_space', function(cm, vim, helpers) {
  1.1765 +  cm.setCursor(0, 0);
  1.1766 +  helpers.doKeys('<Space>', '<Space>');
  1.1767 +  helpers.assertCursorAt(0, 2);
  1.1768 +  helpers.doKeys('q', 'a', '<Space>', '<Space>', 'q');
  1.1769 +  helpers.assertCursorAt(0, 4);
  1.1770 +  helpers.doKeys('@', 'a');
  1.1771 +  helpers.assertCursorAt(0, 6);
  1.1772 +  helpers.doKeys('@', 'a');
  1.1773 +  helpers.assertCursorAt(0, 8);
  1.1774 +}, { value: 'one line of text.'});
  1.1775 +testVim('macro_parens', function(cm, vim, helpers) {
  1.1776 +  cm.setCursor(0, 0);
  1.1777 +  helpers.doKeys('q', 'z', 'i');
  1.1778 +  cm.replaceRange('(', cm.getCursor());
  1.1779 +  helpers.doInsertModeKeys('Esc');
  1.1780 +  helpers.doKeys('e', 'a');
  1.1781 +  cm.replaceRange(')', cm.getCursor());
  1.1782 +  helpers.doInsertModeKeys('Esc');
  1.1783 +  helpers.doKeys('q');
  1.1784 +  helpers.doKeys('w', '@', 'z');
  1.1785 +  helpers.doKeys('w', '@', 'z');
  1.1786 +  eq('(see) (spot) (run)', cm.getValue());
  1.1787 +}, { value: 'see spot run'});
  1.1788 +testVim('macro_overwrite', function(cm, vim, helpers) {
  1.1789 +  cm.setCursor(0, 0);
  1.1790 +  helpers.doKeys('q', 'z', '0', 'i');
  1.1791 +  cm.replaceRange('I ', cm.getCursor());
  1.1792 +  helpers.doInsertModeKeys('Esc');
  1.1793 +  helpers.doKeys('q');
  1.1794 +  helpers.doKeys('e');
  1.1795 +  // Now replace the macro with something else.
  1.1796 +  helpers.doKeys('q', 'z', 'a');
  1.1797 +  cm.replaceRange('.', cm.getCursor());
  1.1798 +  helpers.doInsertModeKeys('Esc');
  1.1799 +  helpers.doKeys('q');
  1.1800 +  helpers.doKeys('e', '@', 'z');
  1.1801 +  helpers.doKeys('e', '@', 'z');
  1.1802 +  eq('I see. spot. run.', cm.getValue());
  1.1803 +}, { value: 'see spot run'});
  1.1804 +testVim('macro_search_f', function(cm, vim, helpers) {
  1.1805 +  cm.setCursor(0, 0);
  1.1806 +  helpers.doKeys('q', 'a', 'f', ' ');
  1.1807 +  helpers.assertCursorAt(0,3);
  1.1808 +  helpers.doKeys('q', '0');
  1.1809 +  helpers.assertCursorAt(0,0);
  1.1810 +  helpers.doKeys('@', 'a');
  1.1811 +  helpers.assertCursorAt(0,3);
  1.1812 +}, { value: 'The quick brown fox jumped over the lazy dog.'});
  1.1813 +testVim('macro_search_2f', function(cm, vim, helpers) {
  1.1814 +  cm.setCursor(0, 0);
  1.1815 +  helpers.doKeys('q', 'a', '2', 'f', ' ');
  1.1816 +  helpers.assertCursorAt(0,9);
  1.1817 +  helpers.doKeys('q', '0');
  1.1818 +  helpers.assertCursorAt(0,0);
  1.1819 +  helpers.doKeys('@', 'a');
  1.1820 +  helpers.assertCursorAt(0,9);
  1.1821 +}, { value: 'The quick brown fox jumped over the lazy dog.'});
  1.1822 +testVim('yank_register', function(cm, vim, helpers) {
  1.1823 +  cm.setCursor(0, 0);
  1.1824 +  helpers.doKeys('"', 'a', 'y', 'y');
  1.1825 +  helpers.doKeys('j', '"', 'b', 'y', 'y');
  1.1826 +  cm.openDialog = helpers.fakeOpenDialog('registers');
  1.1827 +  cm.openNotification = helpers.fakeOpenNotification(function(text) {
  1.1828 +    is(/a\s+foo/.test(text));
  1.1829 +    is(/b\s+bar/.test(text));
  1.1830 +  });
  1.1831 +  helpers.doKeys(':');
  1.1832 +}, { value: 'foo\nbar'});
  1.1833 +testVim('macro_register', function(cm, vim, helpers) {
  1.1834 +  cm.setCursor(0, 0);
  1.1835 +  helpers.doKeys('q', 'a', 'i');
  1.1836 +  cm.replaceRange('gangnam', cm.getCursor());
  1.1837 +  helpers.doInsertModeKeys('Esc');
  1.1838 +  helpers.doKeys('q');
  1.1839 +  helpers.doKeys('q', 'b', 'o');
  1.1840 +  cm.replaceRange('style', cm.getCursor());
  1.1841 +  helpers.doInsertModeKeys('Esc');
  1.1842 +  helpers.doKeys('q');
  1.1843 +  cm.openDialog = helpers.fakeOpenDialog('registers');
  1.1844 +  cm.openNotification = helpers.fakeOpenNotification(function(text) {
  1.1845 +    is(/a\s+i/.test(text));
  1.1846 +    is(/b\s+o/.test(text));
  1.1847 +  });
  1.1848 +  helpers.doKeys(':');
  1.1849 +}, { value: ''});
  1.1850 +testVim('.', function(cm, vim, helpers) {
  1.1851 +  cm.setCursor(0, 0);
  1.1852 +  helpers.doKeys('2', 'd', 'w');
  1.1853 +  helpers.doKeys('.');
  1.1854 +  eq('5 6', cm.getValue());
  1.1855 +}, { value: '1 2 3 4 5 6'});
  1.1856 +testVim('._repeat', function(cm, vim, helpers) {
  1.1857 +  cm.setCursor(0, 0);
  1.1858 +  helpers.doKeys('2', 'd', 'w');
  1.1859 +  helpers.doKeys('3', '.');
  1.1860 +  eq('6', cm.getValue());
  1.1861 +}, { value: '1 2 3 4 5 6'});
  1.1862 +testVim('._insert', function(cm, vim, helpers) {
  1.1863 +  helpers.doKeys('i');
  1.1864 +  cm.replaceRange('test', cm.getCursor());
  1.1865 +  helpers.doInsertModeKeys('Esc');
  1.1866 +  helpers.doKeys('.');
  1.1867 +  eq('testestt', cm.getValue());
  1.1868 +  helpers.assertCursorAt(0, 6);
  1.1869 +}, { value: ''});
  1.1870 +testVim('._insert_repeat', function(cm, vim, helpers) {
  1.1871 +  helpers.doKeys('i');
  1.1872 +  cm.replaceRange('test', cm.getCursor());
  1.1873 +  cm.setCursor(0, 4);
  1.1874 +  helpers.doInsertModeKeys('Esc');
  1.1875 +  helpers.doKeys('2', '.');
  1.1876 +  eq('testesttestt', cm.getValue());
  1.1877 +  helpers.assertCursorAt(0, 10);
  1.1878 +}, { value: ''});
  1.1879 +testVim('._repeat_insert', function(cm, vim, helpers) {
  1.1880 +  helpers.doKeys('3', 'i');
  1.1881 +  cm.replaceRange('te', cm.getCursor());
  1.1882 +  cm.setCursor(0, 2);
  1.1883 +  helpers.doInsertModeKeys('Esc');
  1.1884 +  helpers.doKeys('.');
  1.1885 +  eq('tetettetetee', cm.getValue());
  1.1886 +  helpers.assertCursorAt(0, 10);
  1.1887 +}, { value: ''});
  1.1888 +testVim('._insert_o', function(cm, vim, helpers) {
  1.1889 +  helpers.doKeys('o');
  1.1890 +  cm.replaceRange('z', cm.getCursor());
  1.1891 +  cm.setCursor(1, 1);
  1.1892 +  helpers.doInsertModeKeys('Esc');
  1.1893 +  helpers.doKeys('.');
  1.1894 +  eq('\nz\nz', cm.getValue());
  1.1895 +  helpers.assertCursorAt(2, 0);
  1.1896 +}, { value: ''});
  1.1897 +testVim('._insert_o_repeat', function(cm, vim, helpers) {
  1.1898 +  helpers.doKeys('o');
  1.1899 +  cm.replaceRange('z', cm.getCursor());
  1.1900 +  helpers.doInsertModeKeys('Esc');
  1.1901 +  cm.setCursor(1, 0);
  1.1902 +  helpers.doKeys('2', '.');
  1.1903 +  eq('\nz\nz\nz', cm.getValue());
  1.1904 +  helpers.assertCursorAt(3, 0);
  1.1905 +}, { value: ''});
  1.1906 +testVim('._insert_o_indent', function(cm, vim, helpers) {
  1.1907 +  helpers.doKeys('o');
  1.1908 +  cm.replaceRange('z', cm.getCursor());
  1.1909 +  helpers.doInsertModeKeys('Esc');
  1.1910 +  cm.setCursor(1, 2);
  1.1911 +  helpers.doKeys('.');
  1.1912 +  eq('{\n  z\n  z', cm.getValue());
  1.1913 +  helpers.assertCursorAt(2, 2);
  1.1914 +}, { value: '{'});
  1.1915 +testVim('._insert_cw', function(cm, vim, helpers) {
  1.1916 +  helpers.doKeys('c', 'w');
  1.1917 +  cm.replaceRange('test', cm.getCursor());
  1.1918 +  helpers.doInsertModeKeys('Esc');
  1.1919 +  cm.setCursor(0, 3);
  1.1920 +  helpers.doKeys('2', 'l');
  1.1921 +  helpers.doKeys('.');
  1.1922 +  eq('test test word3', cm.getValue());
  1.1923 +  helpers.assertCursorAt(0, 8);
  1.1924 +}, { value: 'word1 word2 word3' });
  1.1925 +testVim('._insert_cw_repeat', function(cm, vim, helpers) {
  1.1926 +  // For some reason, repeat cw in desktop VIM will does not repeat insert mode
  1.1927 +  // changes. Will conform to that behavior.
  1.1928 +  helpers.doKeys('c', 'w');
  1.1929 +  cm.replaceRange('test', cm.getCursor());
  1.1930 +  helpers.doInsertModeKeys('Esc');
  1.1931 +  cm.setCursor(0, 4);
  1.1932 +  helpers.doKeys('l');
  1.1933 +  helpers.doKeys('2', '.');
  1.1934 +  eq('test test', cm.getValue());
  1.1935 +  helpers.assertCursorAt(0, 8);
  1.1936 +}, { value: 'word1 word2 word3' });
  1.1937 +testVim('._delete', function(cm, vim, helpers) {
  1.1938 +  cm.setCursor(0, 5);
  1.1939 +  helpers.doKeys('i');
  1.1940 +  helpers.doInsertModeKeys('Backspace', 'Esc');
  1.1941 +  helpers.doKeys('.');
  1.1942 +  eq('zace', cm.getValue());
  1.1943 +  helpers.assertCursorAt(0, 1);
  1.1944 +}, { value: 'zabcde'});
  1.1945 +testVim('._delete_repeat', function(cm, vim, helpers) {
  1.1946 +  cm.setCursor(0, 6);
  1.1947 +  helpers.doKeys('i');
  1.1948 +  helpers.doInsertModeKeys('Backspace', 'Esc');
  1.1949 +  helpers.doKeys('2', '.');
  1.1950 +  eq('zzce', cm.getValue());
  1.1951 +  helpers.assertCursorAt(0, 1);
  1.1952 +}, { value: 'zzabcde'});
  1.1953 +testVim('f;', function(cm, vim, helpers) {
  1.1954 +  cm.setCursor(0, 0);
  1.1955 +  helpers.doKeys('f', 'x');
  1.1956 +  helpers.doKeys(';');
  1.1957 +  helpers.doKeys('2', ';');
  1.1958 +  eq(9, cm.getCursor().ch);
  1.1959 +}, { value: '01x3xx678x'});
  1.1960 +testVim('F;', function(cm, vim, helpers) {
  1.1961 +  cm.setCursor(0, 8);
  1.1962 +  helpers.doKeys('F', 'x');
  1.1963 +  helpers.doKeys(';');
  1.1964 +  helpers.doKeys('2', ';');
  1.1965 +  eq(2, cm.getCursor().ch);
  1.1966 +}, { value: '01x3xx6x8x'});
  1.1967 +testVim('t;', function(cm, vim, helpers) {
  1.1968 +  cm.setCursor(0, 0);
  1.1969 +  helpers.doKeys('t', 'x');
  1.1970 +  helpers.doKeys(';');
  1.1971 +  helpers.doKeys('2', ';');
  1.1972 +  eq(8, cm.getCursor().ch);
  1.1973 +}, { value: '01x3xx678x'});
  1.1974 +testVim('T;', function(cm, vim, helpers) {
  1.1975 +  cm.setCursor(0, 9);
  1.1976 +  helpers.doKeys('T', 'x');
  1.1977 +  helpers.doKeys(';');
  1.1978 +  helpers.doKeys('2', ';');
  1.1979 +  eq(2, cm.getCursor().ch);
  1.1980 +}, { value: '0xx3xx678x'});
  1.1981 +testVim('f,', function(cm, vim, helpers) {
  1.1982 +  cm.setCursor(0, 6);
  1.1983 +  helpers.doKeys('f', 'x');
  1.1984 +  helpers.doKeys(',');
  1.1985 +  helpers.doKeys('2', ',');
  1.1986 +  eq(2, cm.getCursor().ch);
  1.1987 +}, { value: '01x3xx678x'});
  1.1988 +testVim('F,', function(cm, vim, helpers) {
  1.1989 +  cm.setCursor(0, 3);
  1.1990 +  helpers.doKeys('F', 'x');
  1.1991 +  helpers.doKeys(',');
  1.1992 +  helpers.doKeys('2', ',');
  1.1993 +  eq(9, cm.getCursor().ch);
  1.1994 +}, { value: '01x3xx678x'});
  1.1995 +testVim('t,', function(cm, vim, helpers) {
  1.1996 +  cm.setCursor(0, 6);
  1.1997 +  helpers.doKeys('t', 'x');
  1.1998 +  helpers.doKeys(',');
  1.1999 +  helpers.doKeys('2', ',');
  1.2000 +  eq(3, cm.getCursor().ch);
  1.2001 +}, { value: '01x3xx678x'});
  1.2002 +testVim('T,', function(cm, vim, helpers) {
  1.2003 +  cm.setCursor(0, 4);
  1.2004 +  helpers.doKeys('T', 'x');
  1.2005 +  helpers.doKeys(',');
  1.2006 +  helpers.doKeys('2', ',');
  1.2007 +  eq(8, cm.getCursor().ch);
  1.2008 +}, { value: '01x3xx67xx'});
  1.2009 +testVim('fd,;', function(cm, vim, helpers) {
  1.2010 +  cm.setCursor(0, 0);
  1.2011 +  helpers.doKeys('f', '4');
  1.2012 +  cm.setCursor(0, 0);
  1.2013 +  helpers.doKeys('d', ';');
  1.2014 +  eq('56789', cm.getValue());
  1.2015 +  helpers.doKeys('u');
  1.2016 +  cm.setCursor(0, 9);
  1.2017 +  helpers.doKeys('d', ',');
  1.2018 +  eq('01239', cm.getValue());
  1.2019 +}, { value: '0123456789'});
  1.2020 +testVim('Fd,;', function(cm, vim, helpers) {
  1.2021 +  cm.setCursor(0, 9);
  1.2022 +  helpers.doKeys('F', '4');
  1.2023 +  cm.setCursor(0, 9);
  1.2024 +  helpers.doKeys('d', ';');
  1.2025 +  eq('01239', cm.getValue());
  1.2026 +  helpers.doKeys('u');
  1.2027 +  cm.setCursor(0, 0);
  1.2028 +  helpers.doKeys('d', ',');
  1.2029 +  eq('56789', cm.getValue());
  1.2030 +}, { value: '0123456789'});
  1.2031 +testVim('td,;', function(cm, vim, helpers) {
  1.2032 +  cm.setCursor(0, 0);
  1.2033 +  helpers.doKeys('t', '4');
  1.2034 +  cm.setCursor(0, 0);
  1.2035 +  helpers.doKeys('d', ';');
  1.2036 +  eq('456789', cm.getValue());
  1.2037 +  helpers.doKeys('u');
  1.2038 +  cm.setCursor(0, 9);
  1.2039 +  helpers.doKeys('d', ',');
  1.2040 +  eq('012349', cm.getValue());
  1.2041 +}, { value: '0123456789'});
  1.2042 +testVim('Td,;', function(cm, vim, helpers) {
  1.2043 +  cm.setCursor(0, 9);
  1.2044 +  helpers.doKeys('T', '4');
  1.2045 +  cm.setCursor(0, 9);
  1.2046 +  helpers.doKeys('d', ';');
  1.2047 +  eq('012349', cm.getValue());
  1.2048 +  helpers.doKeys('u');
  1.2049 +  cm.setCursor(0, 0);
  1.2050 +  helpers.doKeys('d', ',');
  1.2051 +  eq('456789', cm.getValue());
  1.2052 +}, { value: '0123456789'});
  1.2053 +testVim('fc,;', function(cm, vim, helpers) {
  1.2054 +  cm.setCursor(0, 0);
  1.2055 +  helpers.doKeys('f', '4');
  1.2056 +  cm.setCursor(0, 0);
  1.2057 +  helpers.doKeys('c', ';', 'Esc');
  1.2058 +  eq('56789', cm.getValue());
  1.2059 +  helpers.doKeys('u');
  1.2060 +  cm.setCursor(0, 9);
  1.2061 +  helpers.doKeys('c', ',');
  1.2062 +  eq('01239', cm.getValue());
  1.2063 +}, { value: '0123456789'});
  1.2064 +testVim('Fc,;', function(cm, vim, helpers) {
  1.2065 +  cm.setCursor(0, 9);
  1.2066 +  helpers.doKeys('F', '4');
  1.2067 +  cm.setCursor(0, 9);
  1.2068 +  helpers.doKeys('c', ';', 'Esc');
  1.2069 +  eq('01239', cm.getValue());
  1.2070 +  helpers.doKeys('u');
  1.2071 +  cm.setCursor(0, 0);
  1.2072 +  helpers.doKeys('c', ',');
  1.2073 +  eq('56789', cm.getValue());
  1.2074 +}, { value: '0123456789'});
  1.2075 +testVim('tc,;', function(cm, vim, helpers) {
  1.2076 +  cm.setCursor(0, 0);
  1.2077 +  helpers.doKeys('t', '4');
  1.2078 +  cm.setCursor(0, 0);
  1.2079 +  helpers.doKeys('c', ';', 'Esc');
  1.2080 +  eq('456789', cm.getValue());
  1.2081 +  helpers.doKeys('u');
  1.2082 +  cm.setCursor(0, 9);
  1.2083 +  helpers.doKeys('c', ',');
  1.2084 +  eq('012349', cm.getValue());
  1.2085 +}, { value: '0123456789'});
  1.2086 +testVim('Tc,;', function(cm, vim, helpers) {
  1.2087 +  cm.setCursor(0, 9);
  1.2088 +  helpers.doKeys('T', '4');
  1.2089 +  cm.setCursor(0, 9);
  1.2090 +  helpers.doKeys('c', ';', 'Esc');
  1.2091 +  eq('012349', cm.getValue());
  1.2092 +  helpers.doKeys('u');
  1.2093 +  cm.setCursor(0, 0);
  1.2094 +  helpers.doKeys('c', ',');
  1.2095 +  eq('456789', cm.getValue());
  1.2096 +}, { value: '0123456789'});
  1.2097 +testVim('fy,;', function(cm, vim, helpers) {
  1.2098 +  cm.setCursor(0, 0);
  1.2099 +  helpers.doKeys('f', '4');
  1.2100 +  cm.setCursor(0, 0);
  1.2101 +  helpers.doKeys('y', ';', 'P');
  1.2102 +  eq('012340123456789', cm.getValue());
  1.2103 +  helpers.doKeys('u');
  1.2104 +  cm.setCursor(0, 9);
  1.2105 +  helpers.doKeys('y', ',', 'P');
  1.2106 +  eq('012345678456789', cm.getValue());
  1.2107 +}, { value: '0123456789'});
  1.2108 +testVim('Fy,;', function(cm, vim, helpers) {
  1.2109 +  cm.setCursor(0, 9);
  1.2110 +  helpers.doKeys('F', '4');
  1.2111 +  cm.setCursor(0, 9);
  1.2112 +  helpers.doKeys('y', ';', 'p');
  1.2113 +  eq('012345678945678', cm.getValue());
  1.2114 +  helpers.doKeys('u');
  1.2115 +  cm.setCursor(0, 0);
  1.2116 +  helpers.doKeys('y', ',', 'P');
  1.2117 +  eq('012340123456789', cm.getValue());
  1.2118 +}, { value: '0123456789'});
  1.2119 +testVim('ty,;', function(cm, vim, helpers) {
  1.2120 +  cm.setCursor(0, 0);
  1.2121 +  helpers.doKeys('t', '4');
  1.2122 +  cm.setCursor(0, 0);
  1.2123 +  helpers.doKeys('y', ';', 'P');
  1.2124 +  eq('01230123456789', cm.getValue());
  1.2125 +  helpers.doKeys('u');
  1.2126 +  cm.setCursor(0, 9);
  1.2127 +  helpers.doKeys('y', ',', 'p');
  1.2128 +  eq('01234567895678', cm.getValue());
  1.2129 +}, { value: '0123456789'});
  1.2130 +testVim('Ty,;', function(cm, vim, helpers) {
  1.2131 +  cm.setCursor(0, 9);
  1.2132 +  helpers.doKeys('T', '4');
  1.2133 +  cm.setCursor(0, 9);
  1.2134 +  helpers.doKeys('y', ';', 'p');
  1.2135 +  eq('01234567895678', cm.getValue());
  1.2136 +  helpers.doKeys('u');
  1.2137 +  cm.setCursor(0, 0);
  1.2138 +  helpers.doKeys('y', ',', 'P');
  1.2139 +  eq('01230123456789', cm.getValue());
  1.2140 +}, { value: '0123456789'});
  1.2141 +testVim('HML', function(cm, vim, helpers) {
  1.2142 +  var lines = 35;
  1.2143 +  var textHeight = cm.defaultTextHeight();
  1.2144 +  cm.setSize(600, lines*textHeight);
  1.2145 +  cm.setCursor(120, 0);
  1.2146 +  helpers.doKeys('H');
  1.2147 +  helpers.assertCursorAt(86, 2);
  1.2148 +  helpers.doKeys('L');
  1.2149 +  helpers.assertCursorAt(120, 4);
  1.2150 +  helpers.doKeys('M');
  1.2151 +  helpers.assertCursorAt(103,4);
  1.2152 +}, { value: (function(){
  1.2153 +  var lines = new Array(100);
  1.2154 +  var upper = '  xx\n';
  1.2155 +  var lower = '    xx\n';
  1.2156 +  upper = lines.join(upper);
  1.2157 +  lower = lines.join(lower);
  1.2158 +  return upper + lower;
  1.2159 +})()});
  1.2160 +
  1.2161 +var zVals = ['zb','zz','zt','z-','z.','z<CR>'].map(function(e, idx){
  1.2162 +  var lineNum = 250;
  1.2163 +  var lines = 35;
  1.2164 +  testVim(e, function(cm, vim, helpers) {
  1.2165 +    var k1 = e[0];
  1.2166 +    var k2 = e.substring(1);
  1.2167 +    var textHeight = cm.defaultTextHeight();
  1.2168 +    cm.setSize(600, lines*textHeight);
  1.2169 +    cm.setCursor(lineNum, 0);
  1.2170 +    helpers.doKeys(k1, k2);
  1.2171 +    zVals[idx] = cm.getScrollInfo().top;
  1.2172 +  }, { value: (function(){
  1.2173 +    return new Array(500).join('\n');
  1.2174 +  })()});
  1.2175 +});
  1.2176 +testVim('zb<zz', function(cm, vim, helpers){
  1.2177 +  eq(zVals[0]<zVals[1], true);
  1.2178 +});
  1.2179 +testVim('zz<zt', function(cm, vim, helpers){
  1.2180 +  eq(zVals[1]<zVals[2], true);
  1.2181 +});
  1.2182 +testVim('zb==z-', function(cm, vim, helpers){
  1.2183 +  eq(zVals[0], zVals[3]);
  1.2184 +});
  1.2185 +testVim('zz==z.', function(cm, vim, helpers){
  1.2186 +  eq(zVals[1], zVals[4]);
  1.2187 +});
  1.2188 +testVim('zt==z<CR>', function(cm, vim, helpers){
  1.2189 +  eq(zVals[2], zVals[5]);
  1.2190 +});
  1.2191 +
  1.2192 +var moveTillCharacterSandbox =
  1.2193 +  'The quick brown fox \n'
  1.2194 +  'jumped over the lazy dog.'
  1.2195 +testVim('moveTillCharacter', function(cm, vim, helpers){
  1.2196 +  cm.setCursor(0, 0);
  1.2197 +  // Search for the 'q'.
  1.2198 +  cm.openDialog = helpers.fakeOpenDialog('q');
  1.2199 +  helpers.doKeys('/');
  1.2200 +  eq(4, cm.getCursor().ch);
  1.2201 +  // Jump to just before the first o in the list.
  1.2202 +  helpers.doKeys('t');
  1.2203 +  helpers.doKeys('o');
  1.2204 +  eq('The quick brown fox \n', cm.getValue());
  1.2205 +  // Delete that one character.
  1.2206 +  helpers.doKeys('d');
  1.2207 +  helpers.doKeys('t');
  1.2208 +  helpers.doKeys('o');
  1.2209 +  eq('The quick bown fox \n', cm.getValue());
  1.2210 +  // Delete everything until the next 'o'.
  1.2211 +  helpers.doKeys('.');
  1.2212 +  eq('The quick box \n', cm.getValue());
  1.2213 +  // An unmatched character should have no effect.
  1.2214 +  helpers.doKeys('d');
  1.2215 +  helpers.doKeys('t');
  1.2216 +  helpers.doKeys('q');
  1.2217 +  eq('The quick box \n', cm.getValue());
  1.2218 +  // Matches should only be possible on single lines.
  1.2219 +  helpers.doKeys('d');
  1.2220 +  helpers.doKeys('t');
  1.2221 +  helpers.doKeys('z');
  1.2222 +  eq('The quick box \n', cm.getValue());
  1.2223 +  // After all that, the search for 'q' should still be active, so the 'N' command
  1.2224 +  // can run it again in reverse. Use that to delete everything back to the 'q'.
  1.2225 +  helpers.doKeys('d');
  1.2226 +  helpers.doKeys('N');
  1.2227 +  eq('The ox \n', cm.getValue());
  1.2228 +  eq(4, cm.getCursor().ch);
  1.2229 +}, { value: moveTillCharacterSandbox});
  1.2230 +testVim('searchForPipe', function(cm, vim, helpers){
  1.2231 +  CodeMirror.Vim.setOption('pcre', false);
  1.2232 +  cm.setCursor(0, 0);
  1.2233 +  // Search for the '|'.
  1.2234 +  cm.openDialog = helpers.fakeOpenDialog('|');
  1.2235 +  helpers.doKeys('/');
  1.2236 +  eq(4, cm.getCursor().ch);
  1.2237 +}, { value: 'this|that'});
  1.2238 +
  1.2239 +
  1.2240 +var scrollMotionSandbox =
  1.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'
  1.2242 +  '\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'
  1.2243 +  '\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'
  1.2244 +  '\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';
  1.2245 +testVim('scrollMotion', function(cm, vim, helpers){
  1.2246 +  var prevCursor, prevScrollInfo;
  1.2247 +  cm.setCursor(0, 0);
  1.2248 +  // ctrl-y at the top of the file should have no effect.
  1.2249 +  helpers.doKeys('<C-y>');
  1.2250 +  eq(0, cm.getCursor().line);
  1.2251 +  prevScrollInfo = cm.getScrollInfo();
  1.2252 +  helpers.doKeys('<C-e>');
  1.2253 +  eq(1, cm.getCursor().line);
  1.2254 +  is(prevScrollInfo.top < cm.getScrollInfo().top);
  1.2255 +  // Jump to the end of the sandbox.
  1.2256 +  cm.setCursor(1000, 0);
  1.2257 +  prevCursor = cm.getCursor();
  1.2258 +  // ctrl-e at the bottom of the file should have no effect.
  1.2259 +  helpers.doKeys('<C-e>');
  1.2260 +  eq(prevCursor.line, cm.getCursor().line);
  1.2261 +  prevScrollInfo = cm.getScrollInfo();
  1.2262 +  helpers.doKeys('<C-y>');
  1.2263 +  eq(prevCursor.line - 1, cm.getCursor().line);
  1.2264 +  is(prevScrollInfo.top > cm.getScrollInfo().top);
  1.2265 +}, { value: scrollMotionSandbox});
  1.2266 +
  1.2267 +var squareBracketMotionSandbox = ''+
  1.2268 +  '({\n'+//0
  1.2269 +  '  ({\n'+//11
  1.2270 +  '  /*comment {\n'+//2
  1.2271 +  '            */(\n'+//3
  1.2272 +  '#else                \n'+//4
  1.2273 +  '  /*       )\n'+//5
  1.2274 +  '#if        }\n'+//6
  1.2275 +  '  )}*/\n'+//7
  1.2276 +  ')}\n'+//8
  1.2277 +  '{}\n'+//9
  1.2278 +  '#else {{\n'+//10
  1.2279 +  '{}\n'+//11
  1.2280 +  '}\n'+//12
  1.2281 +  '{\n'+//13
  1.2282 +  '#endif\n'+//14
  1.2283 +  '}\n'+//15
  1.2284 +  '}\n'+//16
  1.2285 +  '#else';//17
  1.2286 +testVim('[[, ]]', function(cm, vim, helpers) {
  1.2287 +  cm.setCursor(0, 0);
  1.2288 +  helpers.doKeys(']', ']');
  1.2289 +  helpers.assertCursorAt(9,0);
  1.2290 +  helpers.doKeys('2', ']', ']');
  1.2291 +  helpers.assertCursorAt(13,0);
  1.2292 +  helpers.doKeys(']', ']');
  1.2293 +  helpers.assertCursorAt(17,0);
  1.2294 +  helpers.doKeys('[', '[');
  1.2295 +  helpers.assertCursorAt(13,0);
  1.2296 +  helpers.doKeys('2', '[', '[');
  1.2297 +  helpers.assertCursorAt(9,0);
  1.2298 +  helpers.doKeys('[', '[');
  1.2299 +  helpers.assertCursorAt(0,0);
  1.2300 +}, { value: squareBracketMotionSandbox});
  1.2301 +testVim('[], ][', function(cm, vim, helpers) {
  1.2302 +  cm.setCursor(0, 0);
  1.2303 +  helpers.doKeys(']', '[');
  1.2304 +  helpers.assertCursorAt(12,0);
  1.2305 +  helpers.doKeys('2', ']', '[');
  1.2306 +  helpers.assertCursorAt(16,0);
  1.2307 +  helpers.doKeys(']', '[');
  1.2308 +  helpers.assertCursorAt(17,0);
  1.2309 +  helpers.doKeys('[', ']');
  1.2310 +  helpers.assertCursorAt(16,0);
  1.2311 +  helpers.doKeys('2', '[', ']');
  1.2312 +  helpers.assertCursorAt(12,0);
  1.2313 +  helpers.doKeys('[', ']');
  1.2314 +  helpers.assertCursorAt(0,0);
  1.2315 +}, { value: squareBracketMotionSandbox});
  1.2316 +testVim('[{, ]}', function(cm, vim, helpers) {
  1.2317 +  cm.setCursor(4, 10);
  1.2318 +  helpers.doKeys('[', '{');
  1.2319 +  helpers.assertCursorAt(2,12);
  1.2320 +  helpers.doKeys('2', '[', '{');
  1.2321 +  helpers.assertCursorAt(0,1);
  1.2322 +  cm.setCursor(4, 10);
  1.2323 +  helpers.doKeys(']', '}');
  1.2324 +  helpers.assertCursorAt(6,11);
  1.2325 +  helpers.doKeys('2', ']', '}');
  1.2326 +  helpers.assertCursorAt(8,1);
  1.2327 +  cm.setCursor(0,1);
  1.2328 +  helpers.doKeys(']', '}');
  1.2329 +  helpers.assertCursorAt(8,1);
  1.2330 +  helpers.doKeys('[', '{');
  1.2331 +  helpers.assertCursorAt(0,1);
  1.2332 +}, { value: squareBracketMotionSandbox});
  1.2333 +testVim('[(, ])', function(cm, vim, helpers) {
  1.2334 +  cm.setCursor(4, 10);
  1.2335 +  helpers.doKeys('[', '(');
  1.2336 +  helpers.assertCursorAt(3,14);
  1.2337 +  helpers.doKeys('2', '[', '(');
  1.2338 +  helpers.assertCursorAt(0,0);
  1.2339 +  cm.setCursor(4, 10);
  1.2340 +  helpers.doKeys(']', ')');
  1.2341 +  helpers.assertCursorAt(5,11);
  1.2342 +  helpers.doKeys('2', ']', ')');
  1.2343 +  helpers.assertCursorAt(8,0);
  1.2344 +  helpers.doKeys('[', '(');
  1.2345 +  helpers.assertCursorAt(0,0);
  1.2346 +  helpers.doKeys(']', ')');
  1.2347 +  helpers.assertCursorAt(8,0);
  1.2348 +}, { value: squareBracketMotionSandbox});
  1.2349 +testVim('[*, ]*, [/, ]/', function(cm, vim, helpers) {
  1.2350 +  forEach(['*', '/'], function(key){
  1.2351 +    cm.setCursor(7, 0);
  1.2352 +    helpers.doKeys('2', '[', key);
  1.2353 +    helpers.assertCursorAt(2,2);
  1.2354 +    helpers.doKeys('2', ']', key);
  1.2355 +    helpers.assertCursorAt(7,5);
  1.2356 +  });
  1.2357 +}, { value: squareBracketMotionSandbox});
  1.2358 +testVim('[#, ]#', function(cm, vim, helpers) {
  1.2359 +  cm.setCursor(10, 3);
  1.2360 +  helpers.doKeys('2', '[', '#');
  1.2361 +  helpers.assertCursorAt(4,0);
  1.2362 +  helpers.doKeys('5', ']', '#');
  1.2363 +  helpers.assertCursorAt(17,0);
  1.2364 +  cm.setCursor(10, 3);
  1.2365 +  helpers.doKeys(']', '#');
  1.2366 +  helpers.assertCursorAt(14,0);
  1.2367 +}, { value: squareBracketMotionSandbox});
  1.2368 +testVim('[m, ]m, [M, ]M', function(cm, vim, helpers) {
  1.2369 +  cm.setCursor(11, 0);
  1.2370 +  helpers.doKeys('[', 'm');
  1.2371 +  helpers.assertCursorAt(10,7);
  1.2372 +  helpers.doKeys('4', '[', 'm');
  1.2373 +  helpers.assertCursorAt(1,3);
  1.2374 +  helpers.doKeys('5', ']', 'm');
  1.2375 +  helpers.assertCursorAt(11,0);
  1.2376 +  helpers.doKeys('[', 'M');
  1.2377 +  helpers.assertCursorAt(9,1);
  1.2378 +  helpers.doKeys('3', ']', 'M');
  1.2379 +  helpers.assertCursorAt(15,0);
  1.2380 +  helpers.doKeys('5', '[', 'M');
  1.2381 +  helpers.assertCursorAt(7,3);
  1.2382 +}, { value: squareBracketMotionSandbox});
  1.2383 +
  1.2384 +// Ex mode tests
  1.2385 +testVim('ex_go_to_line', function(cm, vim, helpers) {
  1.2386 +  cm.setCursor(0, 0);
  1.2387 +  helpers.doEx('4');
  1.2388 +  helpers.assertCursorAt(3, 0);
  1.2389 +}, { value: 'a\nb\nc\nd\ne\n'});
  1.2390 +testVim('ex_write', function(cm, vim, helpers) {
  1.2391 +  var tmp = CodeMirror.commands.save;
  1.2392 +  var written;
  1.2393 +  var actualCm;
  1.2394 +  CodeMirror.commands.save = function(cm) {
  1.2395 +    written = true;
  1.2396 +    actualCm = cm;
  1.2397 +  };
  1.2398 +  // Test that w, wr, wri ... write all trigger :write.
  1.2399 +  var command = 'write';
  1.2400 +  for (var i = 1; i < command.length; i++) {
  1.2401 +    written = false;
  1.2402 +    actualCm = null;
  1.2403 +    helpers.doEx(command.substring(0, i));
  1.2404 +    eq(written, true);
  1.2405 +    eq(actualCm, cm);
  1.2406 +  }
  1.2407 +  CodeMirror.commands.save = tmp;
  1.2408 +});
  1.2409 +testVim('ex_sort', function(cm, vim, helpers) {
  1.2410 +  helpers.doEx('sort');
  1.2411 +  eq('Z\na\nb\nc\nd', cm.getValue());
  1.2412 +}, { value: 'b\nZ\nd\nc\na'});
  1.2413 +testVim('ex_sort_reverse', function(cm, vim, helpers) {
  1.2414 +  helpers.doEx('sort!');
  1.2415 +  eq('d\nc\nb\na', cm.getValue());
  1.2416 +}, { value: 'b\nd\nc\na'});
  1.2417 +testVim('ex_sort_range', function(cm, vim, helpers) {
  1.2418 +  helpers.doEx('2,3sort');
  1.2419 +  eq('b\nc\nd\na', cm.getValue());
  1.2420 +}, { value: 'b\nd\nc\na'});
  1.2421 +testVim('ex_sort_oneline', function(cm, vim, helpers) {
  1.2422 +  helpers.doEx('2sort');
  1.2423 +  // Expect no change.
  1.2424 +  eq('b\nd\nc\na', cm.getValue());
  1.2425 +}, { value: 'b\nd\nc\na'});
  1.2426 +testVim('ex_sort_ignoreCase', function(cm, vim, helpers) {
  1.2427 +  helpers.doEx('sort i');
  1.2428 +  eq('a\nb\nc\nd\nZ', cm.getValue());
  1.2429 +}, { value: 'b\nZ\nd\nc\na'});
  1.2430 +testVim('ex_sort_unique', function(cm, vim, helpers) {
  1.2431 +  helpers.doEx('sort u');
  1.2432 +  eq('Z\na\nb\nc\nd', cm.getValue());
  1.2433 +}, { value: 'b\nZ\na\na\nd\na\nc\na'});
  1.2434 +testVim('ex_sort_decimal', function(cm, vim, helpers) {
  1.2435 +  helpers.doEx('sort d');
  1.2436 +  eq('d3\n s5\n6\n.9', cm.getValue());
  1.2437 +}, { value: '6\nd3\n s5\n.9'});
  1.2438 +testVim('ex_sort_decimal_negative', function(cm, vim, helpers) {
  1.2439 +  helpers.doEx('sort d');
  1.2440 +  eq('z-9\nd3\n s5\n6\n.9', cm.getValue());
  1.2441 +}, { value: '6\nd3\n s5\n.9\nz-9'});
  1.2442 +testVim('ex_sort_decimal_reverse', function(cm, vim, helpers) {
  1.2443 +  helpers.doEx('sort! d');
  1.2444 +  eq('.9\n6\n s5\nd3', cm.getValue());
  1.2445 +}, { value: '6\nd3\n s5\n.9'});
  1.2446 +testVim('ex_sort_hex', function(cm, vim, helpers) {
  1.2447 +  helpers.doEx('sort x');
  1.2448 +  eq(' s5\n6\n.9\n&0xB\nd3', cm.getValue());
  1.2449 +}, { value: '6\nd3\n s5\n&0xB\n.9'});
  1.2450 +testVim('ex_sort_octal', function(cm, vim, helpers) {
  1.2451 +  helpers.doEx('sort o');
  1.2452 +  eq('.8\n.9\nd3\n s5\n6', cm.getValue());
  1.2453 +}, { value: '6\nd3\n s5\n.9\n.8'});
  1.2454 +testVim('ex_sort_decimal_mixed', function(cm, vim, helpers) {
  1.2455 +  helpers.doEx('sort d');
  1.2456 +  eq('y\nz\nc1\nb2\na3', cm.getValue());
  1.2457 +}, { value: 'a3\nz\nc1\ny\nb2'});
  1.2458 +testVim('ex_sort_decimal_mixed_reverse', function(cm, vim, helpers) {
  1.2459 +  helpers.doEx('sort! d');
  1.2460 +  eq('a3\nb2\nc1\nz\ny', cm.getValue());
  1.2461 +}, { value: 'a3\nz\nc1\ny\nb2'});
  1.2462 +
  1.2463 +// Basic substitute tests.
  1.2464 +testVim('ex_substitute_same_line', function(cm, vim, helpers) {
  1.2465 +  cm.setCursor(1, 0);
  1.2466 +  helpers.doEx('s/one/two');
  1.2467 +  eq('one one\n two two', cm.getValue());
  1.2468 +}, { value: 'one one\n one one'});
  1.2469 +testVim('ex_substitute_global', function(cm, vim, helpers) {
  1.2470 +  cm.setCursor(1, 0);
  1.2471 +  helpers.doEx('%s/one/two');
  1.2472 +  eq('two two\n two two', cm.getValue());
  1.2473 +}, { value: 'one one\n one one'});
  1.2474 +testVim('ex_substitute_input_range', function(cm, vim, helpers) {
  1.2475 +  cm.setCursor(1, 0);
  1.2476 +  helpers.doEx('1,3s/\\d/0');
  1.2477 +  eq('0\n0\n0\n4', cm.getValue());
  1.2478 +}, { value: '1\n2\n3\n4' });
  1.2479 +testVim('ex_substitute_visual_range', function(cm, vim, helpers) {
  1.2480 +  cm.setCursor(1, 0);
  1.2481 +  // Set last visual mode selection marks '< and '> at lines 2 and 4
  1.2482 +  helpers.doKeys('V', '2', 'j', 'v');
  1.2483 +  helpers.doEx('\'<,\'>s/\\d/0');
  1.2484 +  eq('1\n0\n0\n0\n5', cm.getValue());
  1.2485 +}, { value: '1\n2\n3\n4\n5' });
  1.2486 +testVim('ex_substitute_empty_query', function(cm, vim, helpers) {
  1.2487 +  // If the query is empty, use last query.
  1.2488 +  cm.setCursor(1, 0);
  1.2489 +  cm.openDialog = helpers.fakeOpenDialog('1');
  1.2490 +  helpers.doKeys('/');
  1.2491 +  helpers.doEx('s//b');
  1.2492 +  eq('abb ab2 ab3', cm.getValue());
  1.2493 +}, { value: 'a11 a12 a13' });
  1.2494 +testVim('ex_substitute_javascript', function(cm, vim, helpers) {
  1.2495 +  CodeMirror.Vim.setOption('pcre', false);
  1.2496 +  cm.setCursor(1, 0);
  1.2497 +  // Throw all the things that javascript likes to treat as special values
  1.2498 +  // into the replace part. All should be literal (this is VIM).
  1.2499 +  helpers.doEx('s/\\(\\d+\\)/$$ $\' $` $& \\1/')
  1.2500 +  eq('a $$ $\' $` $& 0 b', cm.getValue());
  1.2501 +}, { value: 'a 0 b' });
  1.2502 +
  1.2503 +// More complex substitute tests that test both pcre and nopcre options.
  1.2504 +function testSubstitute(name, options) {
  1.2505 +  testVim(name + '_pcre', function(cm, vim, helpers) {
  1.2506 +    cm.setCursor(1, 0);
  1.2507 +    CodeMirror.Vim.setOption('pcre', true);
  1.2508 +    helpers.doEx(options.expr);
  1.2509 +    eq(options.expectedValue, cm.getValue());
  1.2510 +  }, options);
  1.2511 +  // If no noPcreExpr is defined, assume that it's the same as the expr.
  1.2512 +  var noPcreExpr = options.noPcreExpr ? options.noPcreExpr : options.expr;
  1.2513 +  testVim(name + '_nopcre', function(cm, vim, helpers) {
  1.2514 +    cm.setCursor(1, 0);
  1.2515 +    CodeMirror.Vim.setOption('pcre', false);
  1.2516 +    helpers.doEx(noPcreExpr);
  1.2517 +    eq(options.expectedValue, cm.getValue());
  1.2518 +  }, options);
  1.2519 +}
  1.2520 +testSubstitute('ex_substitute_capture', {
  1.2521 +  value: 'a11 a12 a13',
  1.2522 +  expectedValue: 'a1111 a1212 a1313',
  1.2523 +  // $n is a backreference
  1.2524 +  expr: 's/(\\d+)/$1$1/',
  1.2525 +  // \n is a backreference.
  1.2526 +  noPcreExpr: 's/\\(\\d+\\)/\\1\\1/'});
  1.2527 +testSubstitute('ex_substitute_capture2', {
  1.2528 +  value: 'a 0 b',
  1.2529 +  expectedValue: 'a $00 b',
  1.2530 +  expr: 's/(\\d+)/$$$1$1/',
  1.2531 +  noPcreExpr: 's/\\(\\d+\\)/$\\1\\1/'});
  1.2532 +testSubstitute('ex_substitute_nocapture', {
  1.2533 +  value: 'a11 a12 a13',
  1.2534 +  expectedValue: 'a$1$1 a$1$1 a$1$1',
  1.2535 +  expr: 's/(\\d+)/$$1$$1',
  1.2536 +  noPcreExpr: 's/\\(\\d+\\)/$1$1/'});
  1.2537 +testSubstitute('ex_substitute_nocapture2', {
  1.2538 +  value: 'a 0 b',
  1.2539 +  expectedValue: 'a $10 b',
  1.2540 +  expr: 's/(\\d+)/$$1$1',
  1.2541 +  noPcreExpr: 's/\\(\\d+\\)/\\$1\\1/'});
  1.2542 +testSubstitute('ex_substitute_nocapture', {
  1.2543 +  value: 'a b c',
  1.2544 +  expectedValue: 'a $ c',
  1.2545 +  expr: 's/b/$$/',
  1.2546 +  noPcreExpr: 's/b/$/'});
  1.2547 +testSubstitute('ex_substitute_slash_regex', {
  1.2548 +  value: 'one/two \n three/four',
  1.2549 +  expectedValue: 'one|two \n three|four',
  1.2550 +  expr: '%s/\\//|'});
  1.2551 +testSubstitute('ex_substitute_pipe_regex', {
  1.2552 +  value: 'one|two \n three|four',
  1.2553 +  expectedValue: 'one,two \n three,four',
  1.2554 +  expr: '%s/\\|/,/',
  1.2555 +  noPcreExpr: '%s/|/,/'});
  1.2556 +testSubstitute('ex_substitute_or_regex', {
  1.2557 +  value: 'one|two \n three|four',
  1.2558 +  expectedValue: 'ana|twa \n thraa|faar',
  1.2559 +  expr: '%s/o|e|u/a',
  1.2560 +  noPcreExpr: '%s/o\\|e\\|u/a'});
  1.2561 +testSubstitute('ex_substitute_or_word_regex', {
  1.2562 +  value: 'one|two \n three|four',
  1.2563 +  expectedValue: 'five|five \n three|four',
  1.2564 +  expr: '%s/(one|two)/five/',
  1.2565 +  noPcreExpr: '%s/\\(one\\|two\\)/five'});
  1.2566 +testSubstitute('ex_substitute_backslashslash_regex', {
  1.2567 +  value: 'one\\two \n three\\four',
  1.2568 +  expectedValue: 'one,two \n three,four',
  1.2569 +  expr: '%s/\\\\/,'});
  1.2570 +testSubstitute('ex_substitute_slash_replacement', {
  1.2571 +  value: 'one,two \n three,four',
  1.2572 +  expectedValue: 'one/two \n three/four',
  1.2573 +  expr: '%s/,/\\/'});
  1.2574 +testSubstitute('ex_substitute_backslash_replacement', {
  1.2575 +  value: 'one,two \n three,four',
  1.2576 +  expectedValue: 'one\\two \n three\\four',
  1.2577 +  expr: '%s/,/\\\\/g'});
  1.2578 +testSubstitute('ex_substitute_multibackslash_replacement', {
  1.2579 +  value: 'one,two \n three,four',
  1.2580 +  expectedValue: 'one\\\\\\\\two \n three\\\\\\\\four', // 2*8 backslashes.
  1.2581 +  expr: '%s/,/\\\\\\\\\\\\\\\\/g'}); // 16 backslashes.
  1.2582 +testSubstitute('ex_substitute_braces_word', {
  1.2583 +  value: 'ababab abb ab{2}',
  1.2584 +  expectedValue: 'ab abb ab{2}',
  1.2585 +  expr: '%s/(ab){2}//g',
  1.2586 +  noPcreExpr: '%s/\\(ab\\)\\{2\\}//g'});
  1.2587 +testSubstitute('ex_substitute_braces_range', {
  1.2588 +  value: 'a aa aaa aaaa',
  1.2589 +  expectedValue: 'a   a',
  1.2590 +  expr: '%s/a{2,3}//g',
  1.2591 +  noPcreExpr: '%s/a\\{2,3\\}//g'});
  1.2592 +testSubstitute('ex_substitute_braces_literal', {
  1.2593 +  value: 'ababab abb ab{2}',
  1.2594 +  expectedValue: 'ababab abb ',
  1.2595 +  expr: '%s/ab\\{2\\}//g',
  1.2596 +  noPcreExpr: '%s/ab{2}//g'});
  1.2597 +testSubstitute('ex_substitute_braces_char', {
  1.2598 +  value: 'ababab abb ab{2}',
  1.2599 +  expectedValue: 'ababab  ab{2}',
  1.2600 +  expr: '%s/ab{2}//g',
  1.2601 +  noPcreExpr: '%s/ab\\{2\\}//g'});
  1.2602 +testSubstitute('ex_substitute_braces_no_escape', {
  1.2603 +  value: 'ababab abb ab{2}',
  1.2604 +  expectedValue: 'ababab  ab{2}',
  1.2605 +  expr: '%s/ab{2}//g',
  1.2606 +  noPcreExpr: '%s/ab\\{2}//g'});
  1.2607 +testSubstitute('ex_substitute_count', {
  1.2608 +  value: '1\n2\n3\n4',
  1.2609 +  expectedValue: '1\n0\n0\n4',
  1.2610 +  expr: 's/\\d/0/i 2'});
  1.2611 +testSubstitute('ex_substitute_count_with_range', {
  1.2612 +  value: '1\n2\n3\n4',
  1.2613 +  expectedValue: '1\n2\n0\n0',
  1.2614 +  expr: '1,3s/\\d/0/ 3'});
  1.2615 +function testSubstituteConfirm(name, command, initialValue, expectedValue, keys, finalPos) {
  1.2616 +  testVim(name, function(cm, vim, helpers) {
  1.2617 +    var savedOpenDialog = cm.openDialog;
  1.2618 +    var savedKeyName = CodeMirror.keyName;
  1.2619 +    var onKeyDown;
  1.2620 +    var recordedCallback;
  1.2621 +    var closed = true; // Start out closed, set false on second openDialog.
  1.2622 +    function close() {
  1.2623 +      closed = true;
  1.2624 +    }
  1.2625 +    // First openDialog should save callback.
  1.2626 +    cm.openDialog = function(template, callback, options) {
  1.2627 +      recordedCallback = callback;
  1.2628 +    }
  1.2629 +    // Do first openDialog.
  1.2630 +    helpers.doKeys(':');
  1.2631 +    // Second openDialog should save keyDown handler.
  1.2632 +    cm.openDialog = function(template, callback, options) {
  1.2633 +      onKeyDown = options.onKeyDown;
  1.2634 +      closed = false;
  1.2635 +    };
  1.2636 +    // Return the command to Vim and trigger second openDialog.
  1.2637 +    recordedCallback(command);
  1.2638 +    // The event should really use keyCode, but here just mock it out and use
  1.2639 +    // key and replace keyName to just return key.
  1.2640 +    CodeMirror.keyName = function (e) { return e.key; }
  1.2641 +    keys = keys.toUpperCase();
  1.2642 +    for (var i = 0; i < keys.length; i++) {
  1.2643 +      is(!closed);
  1.2644 +      onKeyDown({ key: keys.charAt(i) }, '', close);
  1.2645 +    }
  1.2646 +    try {
  1.2647 +      eq(expectedValue, cm.getValue());
  1.2648 +      helpers.assertCursorAt(finalPos);
  1.2649 +      is(closed);
  1.2650 +    } catch(e) {
  1.2651 +      throw e
  1.2652 +    } finally {
  1.2653 +      // Restore overriden functions.
  1.2654 +      CodeMirror.keyName = savedKeyName;
  1.2655 +      cm.openDialog = savedOpenDialog;
  1.2656 +    }
  1.2657 +  }, { value: initialValue });
  1.2658 +};
  1.2659 +testSubstituteConfirm('ex_substitute_confirm_emptydoc',
  1.2660 +    '%s/x/b/c', '', '', '', makeCursor(0, 0));
  1.2661 +testSubstituteConfirm('ex_substitute_confirm_nomatch',
  1.2662 +    '%s/x/b/c', 'ba a\nbab', 'ba a\nbab', '', makeCursor(0, 0));
  1.2663 +testSubstituteConfirm('ex_substitute_confirm_accept',
  1.2664 +    '%s/a/b/c', 'ba a\nbab', 'bb b\nbbb', 'yyy', makeCursor(1, 1));
  1.2665 +testSubstituteConfirm('ex_substitute_confirm_random_keys',
  1.2666 +    '%s/a/b/c', 'ba a\nbab', 'bb b\nbbb', 'ysdkywerty', makeCursor(1, 1));
  1.2667 +testSubstituteConfirm('ex_substitute_confirm_some',
  1.2668 +    '%s/a/b/c', 'ba a\nbab', 'bb a\nbbb', 'yny', makeCursor(1, 1));
  1.2669 +testSubstituteConfirm('ex_substitute_confirm_all',
  1.2670 +    '%s/a/b/c', 'ba a\nbab', 'bb b\nbbb', 'a', makeCursor(1, 1));
  1.2671 +testSubstituteConfirm('ex_substitute_confirm_accept_then_all',
  1.2672 +    '%s/a/b/c', 'ba a\nbab', 'bb b\nbbb', 'ya', makeCursor(1, 1));
  1.2673 +testSubstituteConfirm('ex_substitute_confirm_quit',
  1.2674 +    '%s/a/b/c', 'ba a\nbab', 'bb a\nbab', 'yq', makeCursor(0, 3));
  1.2675 +testSubstituteConfirm('ex_substitute_confirm_last',
  1.2676 +    '%s/a/b/c', 'ba a\nbab', 'bb b\nbab', 'yl', makeCursor(0, 3));
  1.2677 +testSubstituteConfirm('ex_substitute_confirm_oneline',
  1.2678 +    '1s/a/b/c', 'ba a\nbab', 'bb b\nbab', 'yl', makeCursor(0, 3));
  1.2679 +testSubstituteConfirm('ex_substitute_confirm_range_accept',
  1.2680 +    '1,2s/a/b/c', 'aa\na \na\na', 'bb\nb \na\na', 'yyy', makeCursor(1, 0));
  1.2681 +testSubstituteConfirm('ex_substitute_confirm_range_some',
  1.2682 +    '1,3s/a/b/c', 'aa\na \na\na', 'ba\nb \nb\na', 'ynyy', makeCursor(2, 0));
  1.2683 +testSubstituteConfirm('ex_substitute_confirm_range_all',
  1.2684 +    '1,3s/a/b/c', 'aa\na \na\na', 'bb\nb \nb\na', 'a', makeCursor(2, 0));
  1.2685 +testSubstituteConfirm('ex_substitute_confirm_range_last',
  1.2686 +    '1,3s/a/b/c', 'aa\na \na\na', 'bb\nb \na\na', 'yyl', makeCursor(1, 0));
  1.2687 +//:noh should clear highlighting of search-results but allow to resume search through n
  1.2688 +testVim('ex_noh_clearSearchHighlight', function(cm, vim, helpers) {
  1.2689 +  cm.openDialog = helpers.fakeOpenDialog('match');
  1.2690 +  helpers.doKeys('?');
  1.2691 +  helpers.doEx('noh');
  1.2692 +  eq(vim.searchState_.getOverlay(),null,'match-highlighting wasn\'t cleared');
  1.2693 +  helpers.doKeys('n');
  1.2694 +  helpers.assertCursorAt(0, 11,'can\'t resume search after clearing highlighting');
  1.2695 +}, { value: 'match nope match \n nope Match' });
  1.2696 +testVim('set_boolean', function(cm, vim, helpers) {
  1.2697 +  CodeMirror.Vim.defineOption('testoption', true, 'boolean');
  1.2698 +  // Test default value is set.
  1.2699 +  is(CodeMirror.Vim.getOption('testoption'));
  1.2700 +  try {
  1.2701 +    // Test fail to set to non-boolean
  1.2702 +    CodeMirror.Vim.setOption('testoption', '5');
  1.2703 +    fail();
  1.2704 +  } catch (expected) {};
  1.2705 +  // Test setOption
  1.2706 +  CodeMirror.Vim.setOption('testoption', false);
  1.2707 +  is(!CodeMirror.Vim.getOption('testoption'));
  1.2708 +});
  1.2709 +testVim('ex_set_boolean', function(cm, vim, helpers) {
  1.2710 +  CodeMirror.Vim.defineOption('testoption', true, 'boolean');
  1.2711 +  // Test default value is set.
  1.2712 +  is(CodeMirror.Vim.getOption('testoption'));
  1.2713 +  try {
  1.2714 +    // Test fail to set to non-boolean
  1.2715 +    helpers.doEx('set testoption=22');
  1.2716 +    fail();
  1.2717 +  } catch (expected) {};
  1.2718 +  // Test setOption
  1.2719 +  helpers.doEx('set notestoption');
  1.2720 +  is(!CodeMirror.Vim.getOption('testoption'));
  1.2721 +});
  1.2722 +testVim('set_string', function(cm, vim, helpers) {
  1.2723 +  CodeMirror.Vim.defineOption('testoption', 'a', 'string');
  1.2724 +  // Test default value is set.
  1.2725 +  eq('a', CodeMirror.Vim.getOption('testoption'));
  1.2726 +  try {
  1.2727 +    // Test fail to set non-string.
  1.2728 +    CodeMirror.Vim.setOption('testoption', true);
  1.2729 +    fail();
  1.2730 +  } catch (expected) {};
  1.2731 +  try {
  1.2732 +    // Test fail to set 'notestoption'
  1.2733 +    CodeMirror.Vim.setOption('notestoption', 'b');
  1.2734 +    fail();
  1.2735 +  } catch (expected) {};
  1.2736 +  // Test setOption
  1.2737 +  CodeMirror.Vim.setOption('testoption', 'c');
  1.2738 +  eq('c', CodeMirror.Vim.getOption('testoption'));
  1.2739 +});
  1.2740 +testVim('ex_set_string', function(cm, vim, helpers) {
  1.2741 +  CodeMirror.Vim.defineOption('testoption', 'a', 'string');
  1.2742 +  // Test default value is set.
  1.2743 +  eq('a', CodeMirror.Vim.getOption('testoption'));
  1.2744 +  try {
  1.2745 +    // Test fail to set 'notestoption'
  1.2746 +    helpers.doEx('set notestoption=b');
  1.2747 +    fail();
  1.2748 +  } catch (expected) {};
  1.2749 +  // Test setOption
  1.2750 +  helpers.doEx('set testoption=c')
  1.2751 +  eq('c', CodeMirror.Vim.getOption('testoption'));
  1.2752 +});
  1.2753 +// TODO: Reset key maps after each test.
  1.2754 +testVim('ex_map_key2key', function(cm, vim, helpers) {
  1.2755 +  helpers.doEx('map a x');
  1.2756 +  helpers.doKeys('a');
  1.2757 +  helpers.assertCursorAt(0, 0);
  1.2758 +  eq('bc', cm.getValue());
  1.2759 +}, { value: 'abc' });
  1.2760 +testVim('ex_unmap_key2key', function(cm, vim, helpers) {
  1.2761 +  helpers.doEx('unmap a');
  1.2762 +  helpers.doKeys('a');
  1.2763 +  eq('vim-insert', cm.getOption('keyMap'));
  1.2764 +}, { value: 'abc' });
  1.2765 +testVim('ex_unmap_key2key_does_not_remove_default', function(cm, vim, helpers) {
  1.2766 +  try {
  1.2767 +    helpers.doEx('unmap a');
  1.2768 +    fail();
  1.2769 +  } catch (expected) {}
  1.2770 +  helpers.doKeys('a');
  1.2771 +  eq('vim-insert', cm.getOption('keyMap'));
  1.2772 +}, { value: 'abc' });
  1.2773 +testVim('ex_map_key2key_to_colon', function(cm, vim, helpers) {
  1.2774 +  helpers.doEx('map ; :');
  1.2775 +  var dialogOpened = false;
  1.2776 +  cm.openDialog = function() {
  1.2777 +    dialogOpened = true;
  1.2778 +  }
  1.2779 +  helpers.doKeys(';');
  1.2780 +  eq(dialogOpened, true);
  1.2781 +});
  1.2782 +testVim('ex_map_ex2key:', function(cm, vim, helpers) {
  1.2783 +  helpers.doEx('map :del x');
  1.2784 +  helpers.doEx('del');
  1.2785 +  helpers.assertCursorAt(0, 0);
  1.2786 +  eq('bc', cm.getValue());
  1.2787 +}, { value: 'abc' });
  1.2788 +testVim('ex_map_ex2ex', function(cm, vim, helpers) {
  1.2789 +  helpers.doEx('map :del :w');
  1.2790 +  var tmp = CodeMirror.commands.save;
  1.2791 +  var written = false;
  1.2792 +  var actualCm;
  1.2793 +  CodeMirror.commands.save = function(cm) {
  1.2794 +    written = true;
  1.2795 +    actualCm = cm;
  1.2796 +  };
  1.2797 +  helpers.doEx('del');
  1.2798 +  CodeMirror.commands.save = tmp;
  1.2799 +  eq(written, true);
  1.2800 +  eq(actualCm, cm);
  1.2801 +});
  1.2802 +testVim('ex_map_key2ex', function(cm, vim, helpers) {
  1.2803 +  helpers.doEx('map a :w');
  1.2804 +  var tmp = CodeMirror.commands.save;
  1.2805 +  var written = false;
  1.2806 +  var actualCm;
  1.2807 +  CodeMirror.commands.save = function(cm) {
  1.2808 +    written = true;
  1.2809 +    actualCm = cm;
  1.2810 +  };
  1.2811 +  helpers.doKeys('a');
  1.2812 +  CodeMirror.commands.save = tmp;
  1.2813 +  eq(written, true);
  1.2814 +  eq(actualCm, cm);
  1.2815 +});
  1.2816 +testVim('ex_map_key2key_visual_api', function(cm, vim, helpers) {
  1.2817 +  CodeMirror.Vim.map('b', ':w', 'visual');
  1.2818 +  var tmp = CodeMirror.commands.save;
  1.2819 +  var written = false;
  1.2820 +  var actualCm;
  1.2821 +  CodeMirror.commands.save = function(cm) {
  1.2822 +    written = true;
  1.2823 +    actualCm = cm;
  1.2824 +  };
  1.2825 +  // Mapping should not work in normal mode.
  1.2826 +  helpers.doKeys('b');
  1.2827 +  eq(written, false);
  1.2828 +  // Mapping should work in visual mode.
  1.2829 +  helpers.doKeys('v', 'b');
  1.2830 +  eq(written, true);
  1.2831 +  eq(actualCm, cm);
  1.2832 +
  1.2833 +  CodeMirror.commands.save = tmp;
  1.2834 +});
  1.2835 +
  1.2836 +// Testing registration of functions as ex-commands and mapping to <Key>-keys
  1.2837 +testVim('ex_api_test', function(cm, vim, helpers) {
  1.2838 +  var res=false;
  1.2839 +  var val='from';
  1.2840 +  CodeMirror.Vim.defineEx('extest','ext',function(cm,params){
  1.2841 +    if(params.args)val=params.args[0];
  1.2842 +    else res=true;
  1.2843 +  });
  1.2844 +  helpers.doEx(':ext to');
  1.2845 +  eq(val,'to','Defining ex-command failed');
  1.2846 +  CodeMirror.Vim.map('<C-CR><Space>',':ext');
  1.2847 +  helpers.doKeys('<C-CR>','<Space>');
  1.2848 +  is(res,'Mapping to key failed');
  1.2849 +});
  1.2850 +// For now, this test needs to be last because it messes up : for future tests.
  1.2851 +testVim('ex_map_key2key_from_colon', function(cm, vim, helpers) {
  1.2852 +  helpers.doEx('map : x');
  1.2853 +  helpers.doKeys(':');
  1.2854 +  helpers.assertCursorAt(0, 0);
  1.2855 +  eq('bc', cm.getValue());
  1.2856 +}, { value: 'abc' });
  1.2857 +
  1.2858 +// Test event handlers
  1.2859 +testVim('beforeSelectionChange', function(cm, vim, helpers) {
  1.2860 +  cm.setCursor(0, 100);
  1.2861 +  eqPos(cm.getCursor('head'), cm.getCursor('anchor'));
  1.2862 +}, { value: 'abc' });

mercurial