Licitator 1.0
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

4801 lines
164 KiB

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