codemirror-rails 3.14 → 3.15

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (61) hide show
  1. checksums.yaml +4 -4
  2. data/lib/codemirror/rails/version.rb +2 -2
  3. data/vendor/assets/javascripts/codemirror.js +178 -94
  4. data/vendor/assets/javascripts/codemirror/addons/comment/comment.js +3 -3
  5. data/vendor/assets/javascripts/codemirror/addons/edit/closebrackets.js +3 -1
  6. data/vendor/assets/javascripts/codemirror/addons/edit/matchtags.js +51 -0
  7. data/vendor/assets/javascripts/codemirror/addons/fold/brace-fold.js +9 -6
  8. data/vendor/assets/javascripts/codemirror/addons/fold/foldcode.js +9 -4
  9. data/vendor/assets/javascripts/codemirror/addons/fold/foldgutter.js +122 -0
  10. data/vendor/assets/javascripts/codemirror/addons/fold/indent-fold.js +3 -2
  11. data/vendor/assets/javascripts/codemirror/addons/fold/xml-fold.js +24 -17
  12. data/vendor/assets/javascripts/codemirror/addons/hint/anyword-hint.js +34 -0
  13. data/vendor/assets/javascripts/codemirror/addons/hint/html-hint.js +5 -3
  14. data/vendor/assets/javascripts/codemirror/addons/hint/javascript-hint.js +7 -3
  15. data/vendor/assets/javascripts/codemirror/addons/hint/pig-hint.js +4 -2
  16. data/vendor/assets/javascripts/codemirror/addons/hint/python-hint.js +4 -2
  17. data/vendor/assets/javascripts/codemirror/addons/hint/show-hint.js +6 -2
  18. data/vendor/assets/javascripts/codemirror/addons/hint/xml-hint.js +5 -2
  19. data/vendor/assets/javascripts/codemirror/addons/lint/coffeescript-lint.js +3 -2
  20. data/vendor/assets/javascripts/codemirror/addons/lint/javascript-lint.js +3 -6
  21. data/vendor/assets/javascripts/codemirror/addons/lint/json-lint.js +3 -2
  22. data/vendor/assets/javascripts/codemirror/addons/lint/lint.js +12 -6
  23. data/vendor/assets/javascripts/codemirror/addons/merge/dep/diff_match_patch.js +50 -0
  24. data/vendor/assets/javascripts/codemirror/addons/merge/merge.js +40 -24
  25. data/vendor/assets/javascripts/codemirror/addons/runmode/runmode-standalone.js +3 -1
  26. data/vendor/assets/javascripts/codemirror/addons/runmode/runmode.node.js +3 -1
  27. data/vendor/assets/javascripts/codemirror/addons/search/match-highlighter.js +11 -9
  28. data/vendor/assets/javascripts/codemirror/addons/selection/active-line.js +1 -1
  29. data/vendor/assets/javascripts/codemirror/addons/tern/tern.js +608 -0
  30. data/vendor/assets/javascripts/codemirror/addons/tern/worker.js +39 -0
  31. data/vendor/assets/javascripts/codemirror/keymaps/vim.js +120 -101
  32. data/vendor/assets/javascripts/codemirror/modes/clike.js +2 -1
  33. data/vendor/assets/javascripts/codemirror/modes/coffeescript.js +2 -1
  34. data/vendor/assets/javascripts/codemirror/modes/css.js +33 -16
  35. data/vendor/assets/javascripts/codemirror/modes/groovy.js +2 -1
  36. data/vendor/assets/javascripts/codemirror/modes/jade.js +90 -0
  37. data/vendor/assets/javascripts/codemirror/modes/javascript.js +21 -18
  38. data/vendor/assets/javascripts/codemirror/modes/markdown.js +26 -1
  39. data/vendor/assets/javascripts/codemirror/modes/nginx.js +163 -0
  40. data/vendor/assets/javascripts/codemirror/modes/python.js +19 -2
  41. data/vendor/assets/javascripts/codemirror/modes/rst.js +30 -19
  42. data/vendor/assets/javascripts/codemirror/modes/ruby.js +4 -4
  43. data/vendor/assets/javascripts/codemirror/modes/rust.js +2 -1
  44. data/vendor/assets/javascripts/codemirror/modes/scss_test.js +1 -1
  45. data/vendor/assets/javascripts/codemirror/modes/smalltalk.js +12 -2
  46. data/vendor/assets/javascripts/codemirror/modes/smartymixed.js +170 -0
  47. data/vendor/assets/javascripts/codemirror/modes/sparql.js +4 -2
  48. data/vendor/assets/javascripts/codemirror/modes/vbscript.js +330 -22
  49. data/vendor/assets/javascripts/codemirror/modes/xml.js +18 -3
  50. data/vendor/assets/stylesheets/codemirror.css +10 -0
  51. data/vendor/assets/stylesheets/codemirror/addons/merge/merge.css +39 -29
  52. data/vendor/assets/stylesheets/codemirror/addons/tern/tern.css +85 -0
  53. data/vendor/assets/stylesheets/codemirror/themes/3024-day.css +33 -0
  54. data/vendor/assets/stylesheets/codemirror/themes/3024-night.css +33 -0
  55. data/vendor/assets/stylesheets/codemirror/themes/base16-dark.css +33 -0
  56. data/vendor/assets/stylesheets/codemirror/themes/base16-light.css +33 -0
  57. data/vendor/assets/stylesheets/codemirror/themes/lesser-dark.css +1 -1
  58. data/vendor/assets/stylesheets/codemirror/themes/midnight.css +5 -14
  59. data/vendor/assets/stylesheets/codemirror/themes/tomorrow-night-eighties.css +33 -0
  60. data/vendor/assets/stylesheets/codemirror/themes/vibrant-ink.css +2 -2
  61. metadata +17 -2
@@ -0,0 +1,39 @@
1
+ var server;
2
+
3
+ this.onmessage = function(e) {
4
+ var data = e.data;
5
+ switch (data.type) {
6
+ case "init": return startServer(data.defs, data.plugins, data.scripts);
7
+ case "add": return server.addFile(data.name, data.text);
8
+ case "del": return server.delFile(data.name);
9
+ case "req": return server.request(data.body, function(err, reqData) {
10
+ postMessage({id: data.id, body: reqData, err: err && String(err)});
11
+ });
12
+ case "getFile":
13
+ var c = pending[data.id];
14
+ delete pending[data.id];
15
+ return c(data.err, data.text);
16
+ default: throw new Error("Unknown message type: " + data.type);
17
+ }
18
+ };
19
+
20
+ var nextId = 0, pending = {};
21
+ function getFile(file, c) {
22
+ postMessage({type: "getFile", name: file, id: ++nextId});
23
+ pending[nextId] = c;
24
+ }
25
+
26
+ function startServer(defs, plugins, scripts) {
27
+ if (scripts) importScripts.apply(null, scripts);
28
+
29
+ server = new tern.Server({
30
+ getFile: getFile,
31
+ async: true,
32
+ defs: defs,
33
+ plugins: plugins
34
+ });
35
+ }
36
+
37
+ var console = {
38
+ log: function(v) { postMessage({type: "debug", message: v}); }
39
+ };
@@ -206,8 +206,7 @@
206
206
  // Operators
207
207
  { keys: ['d'], type: 'operator', operator: 'delete' },
208
208
  { keys: ['y'], type: 'operator', operator: 'yank' },
209
- { keys: ['c'], type: 'operator', operator: 'change',
210
- operatorArgs: { enterInsertMode: true } },
209
+ { keys: ['c'], type: 'operator', operator: 'change' },
211
210
  { keys: ['>'], type: 'operator', operator: 'indent',
212
211
  operatorArgs: { indentRight: true }},
213
212
  { keys: ['<'], type: 'operator', operator: 'indent',
@@ -231,10 +230,11 @@
231
230
  motion: 'moveToEol', motionArgs: { inclusive: true },
232
231
  operatorMotionArgs: { visualLine: true }},
233
232
  { keys: ['C'], type: 'operatorMotion',
234
- operator: 'change', operatorArgs: { enterInsertMode: true },
233
+ operator: 'change',
235
234
  motion: 'moveToEol', motionArgs: { inclusive: true },
236
235
  operatorMotionArgs: { visualLine: true }},
237
- { keys: ['~'], type: 'operatorMotion', operator: 'swapcase',
236
+ { keys: ['~'], type: 'operatorMotion',
237
+ operator: 'swapcase', operatorArgs: { shouldMoveCursor: true },
238
238
  motion: 'moveByCharacters', motionArgs: { forward: true }},
239
239
  // Actions
240
240
  { keys: ['<C-i>'], type: 'action', action: 'jumpListWalk',
@@ -315,6 +315,27 @@
315
315
  ];
316
316
 
317
317
  var Vim = function() {
318
+ CodeMirror.defineOption('vimMode', false, function(cm, val) {
319
+ if (val) {
320
+ cm.setOption('keyMap', 'vim');
321
+ cm.on('beforeSelectionChange', beforeSelectionChange);
322
+ maybeInitVimState(cm);
323
+ } else if (cm.state.vim) {
324
+ cm.setOption('keyMap', 'default');
325
+ cm.off('beforeSelectionChange', beforeSelectionChange);
326
+ cm.state.vim = null;
327
+ }
328
+ });
329
+ function beforeSelectionChange(cm, cur) {
330
+ var vim = cm.state.vim;
331
+ if (vim.insertMode || vim.exMode) return;
332
+
333
+ var head = cur.head;
334
+ if (head.ch && head.ch == cm.doc.getLine(head.line).length) {
335
+ head.ch--;
336
+ }
337
+ }
338
+
318
339
  var numberRegex = /[\d]/;
319
340
  var wordRegexp = [(/\w/), (/[^\w\s]/)], bigWordRegexp = [(/\S/)];
320
341
  function makeKeyRange(start, size) {
@@ -450,28 +471,11 @@
450
471
  };
451
472
  };
452
473
 
453
- // Global Vim state. Call getVimGlobalState to get and initialize.
454
- var vimGlobalState;
455
- function getVimGlobalState() {
456
- if (!vimGlobalState) {
457
- vimGlobalState = {
458
- // The current search query.
459
- searchQuery: null,
460
- // Whether we are searching backwards.
461
- searchIsReversed: false,
462
- jumpList: createCircularJumpList(),
463
- macroModeState: createMacroState(),
464
- // Recording latest f, t, F or T motion command.
465
- lastChararacterSearch: {increment:0, forward:true, selectedCharacter:''},
466
- registerController: new RegisterController({})
467
- };
468
- }
469
- return vimGlobalState;
470
- }
471
- function getVimState(cm) {
472
- if (!cm.vimState) {
474
+
475
+ function maybeInitVimState(cm) {
476
+ if (!cm.state.vim) {
473
477
  // Store instance state in the CodeMirror object.
474
- cm.vimState = {
478
+ cm.state.vim = {
475
479
  inputState: new InputState(),
476
480
  // Vim's input state that triggered the last edit, used to repeat
477
481
  // motions and operators with '.'.
@@ -500,7 +504,21 @@
500
504
  visualLine: false
501
505
  };
502
506
  }
503
- return cm.vimState;
507
+ return cm.state.vim;
508
+ }
509
+ var vimGlobalState;
510
+ function resetVimGlobalState() {
511
+ vimGlobalState = {
512
+ // The current search query.
513
+ searchQuery: null,
514
+ // Whether we are searching backwards.
515
+ searchIsReversed: false,
516
+ jumpList: createCircularJumpList(),
517
+ macroModeState: createMacroState(),
518
+ // Recording latest f, t, F or T motion command.
519
+ lastChararacterSearch: {increment:0, forward:true, selectedCharacter:''},
520
+ registerController: new RegisterController({})
521
+ };
504
522
  }
505
523
 
506
524
  var vimApi= {
@@ -510,16 +528,19 @@
510
528
  // Testing hook, though it might be useful to expose the register
511
529
  // controller anyways.
512
530
  getRegisterController: function() {
513
- return getVimGlobalState().registerController;
531
+ return vimGlobalState.registerController;
514
532
  },
515
533
  // Testing hook.
516
- clearVimGlobalState_: function() {
517
- vimGlobalState = null;
518
- },
534
+ resetVimGlobalState_: resetVimGlobalState,
535
+
519
536
  // Testing hook.
520
537
  getVimGlobalState_: function() {
521
538
  return vimGlobalState;
522
539
  },
540
+
541
+ // Testing hook.
542
+ maybeInitVimState_: maybeInitVimState,
543
+
523
544
  InsertModeKey: InsertModeKey,
524
545
  map: function(lhs, rhs) {
525
546
  // Add user defined key bindings.
@@ -532,17 +553,12 @@
532
553
  exCommands[name]=func;
533
554
  exCommandDispatcher.commandMap_[prefix]={name:name, shortName:prefix, type:'api'};
534
555
  },
535
- // Initializes vim state variable on the CodeMirror object. Should only be
536
- // called lazily by handleKey or for testing.
537
- maybeInitState: function(cm) {
538
- getVimState(cm);
539
- },
540
556
  // This is the outermost function called by CodeMirror, after keys have
541
557
  // been mapped to their Vim equivalents.
542
558
  handleKey: function(cm, key) {
543
559
  var command;
544
- var vim = getVimState(cm);
545
- var macroModeState = getVimGlobalState().macroModeState;
560
+ var vim = maybeInitVimState(cm);
561
+ var macroModeState = vimGlobalState.macroModeState;
546
562
  if (macroModeState.enteredMacroMode) {
547
563
  if (key == 'q') {
548
564
  actions.exitMacroRecordMode();
@@ -554,19 +570,16 @@
554
570
  // Clear input state and get back to normal mode.
555
571
  vim.inputState = new InputState();
556
572
  if (vim.visualMode) {
557
- exitVisualMode(cm, vim);
573
+ exitVisualMode(cm);
558
574
  }
559
575
  return;
560
576
  }
561
- if (vim.visualMode &&
562
- cursorEqual(cm.getCursor('head'), cm.getCursor('anchor'))) {
563
- // The selection was cleared. Exit visual mode.
564
- exitVisualMode(cm, vim);
565
- }
577
+ // Enter visual mode when the mouse selects text.
566
578
  if (!vim.visualMode &&
567
579
  !cursorEqual(cm.getCursor('head'), cm.getCursor('anchor'))) {
568
580
  vim.visualMode = true;
569
581
  vim.visualLine = false;
582
+ cm.on('mousedown', exitVisualMode);
570
583
  }
571
584
  if (key != '0' || (key == '0' && vim.inputState.getRepeat() === 0)) {
572
585
  // Have to special case 0 since it's both a motion and a number.
@@ -970,7 +983,7 @@
970
983
  // cachedCursor is used to save the old position of the cursor
971
984
  // when * or # causes vim to seek for the nearest word and shift
972
985
  // the cursor before entering the motion.
973
- getVimGlobalState().jumpList.cachedCursor = cm.getCursor();
986
+ vimGlobalState.jumpList.cachedCursor = cm.getCursor();
974
987
  cm.setCursor(word.start);
975
988
 
976
989
  handleQuery(query, true /** ignoreCase */, false /** smartCase */);
@@ -1052,7 +1065,7 @@
1052
1065
  return;
1053
1066
  }
1054
1067
  if (motionArgs.toJumplist) {
1055
- var jumpList = getVimGlobalState().jumpList;
1068
+ var jumpList = vimGlobalState.jumpList;
1056
1069
  // if the current motion is # or *, use cachedCursor
1057
1070
  var cachedCursor = jumpList.cachedCursor;
1058
1071
  if (cachedCursor) {
@@ -1146,15 +1159,12 @@
1146
1159
  operators[operator](cm, operatorArgs, vim, curStart,
1147
1160
  curEnd, curOriginal);
1148
1161
  if (vim.visualMode) {
1149
- exitVisualMode(cm, vim);
1150
- }
1151
- if (operatorArgs.enterInsertMode) {
1152
- actions.enterInsertMode(cm, {}, vim);
1162
+ exitVisualMode(cm);
1153
1163
  }
1154
1164
  }
1155
1165
  },
1156
1166
  recordLastEdit: function(vim, inputState, actionCommand) {
1157
- var macroModeState = getVimGlobalState().macroModeState;
1167
+ var macroModeState = vimGlobalState.macroModeState;
1158
1168
  if (macroModeState.inReplay) { return; }
1159
1169
  vim.lastEditInputState = inputState;
1160
1170
  vim.lastEditActionCommand = actionCommand;
@@ -1272,8 +1282,13 @@
1272
1282
  }
1273
1283
  var repeat = motionArgs.repeat+(motionArgs.repeatOffset||0);
1274
1284
  var line = motionArgs.forward ? cur.line + repeat : cur.line - repeat;
1275
- if (line < cm.firstLine() || line > cm.lastLine() ) {
1276
- return null;
1285
+ var first = cm.firstLine();
1286
+ var last = cm.lastLine();
1287
+ // Vim cancels linewise motions that start on an edge and move beyond
1288
+ // that edge. It does not cancel motions that do not start on an edge.
1289
+ if ((line < first && cur.line == first) ||
1290
+ (line > last && cur.line == last)) {
1291
+ return;
1277
1292
  }
1278
1293
  if(motionArgs.toFirstChar){
1279
1294
  endCh=findFirstNonWhiteSpaceCharacter(cm.getLine(line));
@@ -1456,7 +1471,7 @@
1456
1471
  return [start, end];
1457
1472
  },
1458
1473
  repeatLastCharacterSearch: function(cm, motionArgs) {
1459
- var lastSearch = getVimGlobalState().lastChararacterSearch;
1474
+ var lastSearch = vimGlobalState.lastChararacterSearch;
1460
1475
  var repeat = motionArgs.repeat;
1461
1476
  var forward = motionArgs.forward === lastSearch.forward;
1462
1477
  var increment = (lastSearch.increment ? 1 : 0) * (forward ? -1 : 1);
@@ -1474,22 +1489,16 @@
1474
1489
 
1475
1490
  var operators = {
1476
1491
  change: function(cm, operatorArgs, _vim, curStart, curEnd) {
1477
- getVimGlobalState().registerController.pushText(
1492
+ vimGlobalState.registerController.pushText(
1478
1493
  operatorArgs.registerName, 'change', cm.getRange(curStart, curEnd),
1479
1494
  operatorArgs.linewise);
1480
1495
  if (operatorArgs.linewise) {
1481
- // Delete starting at the first nonwhitespace character of the first
1482
- // line, instead of from the start of the first line. This way we get
1483
- // an indent when we get into insert mode. This behavior isn't quite
1484
- // correct because we should treat this as a completely new line, and
1485
- // indent should be whatever codemirror thinks is the right indent.
1486
- // But cm.indentLine doesn't seem work on empty lines.
1487
- // TODO: Fix the above.
1488
- curStart.ch =
1489
- findFirstNonWhiteSpaceCharacter(cm.getLine(curStart.line));
1490
- // Insert an additional newline so that insert mode can start there.
1491
- // curEnd should be on the first character of the new line.
1492
- cm.replaceRange('\n', curStart, curEnd);
1496
+ // Push the next line back down, if there is a next line.
1497
+ var replacement = curEnd.line > cm.lastLine() ? '' : '\n';
1498
+ cm.replaceRange(replacement, curStart, curEnd);
1499
+ cm.indentLine(curStart.line, 'smart');
1500
+ // null ch so setCursor moves to end of line.
1501
+ curStart.ch = null;
1493
1502
  } else {
1494
1503
  // Exclude trailing whitespace if the range is not all whitespace.
1495
1504
  var text = cm.getRange(curStart, curEnd);
@@ -1501,6 +1510,7 @@
1501
1510
  }
1502
1511
  cm.replaceRange('', curStart, curEnd);
1503
1512
  }
1513
+ actions.enterInsertMode(cm, {}, cm.state.vim);
1504
1514
  cm.setCursor(curStart);
1505
1515
  },
1506
1516
  // delete is a javascript keyword.
@@ -1512,7 +1522,7 @@
1512
1522
  curStart.line--;
1513
1523
  curStart.ch = lineLength(cm, curStart.line);
1514
1524
  }
1515
- getVimGlobalState().registerController.pushText(
1525
+ vimGlobalState.registerController.pushText(
1516
1526
  operatorArgs.registerName, 'delete', cm.getRange(curStart, curEnd),
1517
1527
  operatorArgs.linewise);
1518
1528
  cm.replaceRange('', curStart, curEnd);
@@ -1542,7 +1552,7 @@
1542
1552
  cm.setCursor(curStart);
1543
1553
  cm.setCursor(motions.moveToFirstNonWhiteSpaceCharacter(cm));
1544
1554
  },
1545
- swapcase: function(cm, _operatorArgs, _vim, curStart, curEnd, curOriginal) {
1555
+ swapcase: function(cm, operatorArgs, _vim, curStart, curEnd, curOriginal) {
1546
1556
  var toSwap = cm.getRange(curStart, curEnd);
1547
1557
  var swapped = '';
1548
1558
  for (var i = 0; i < toSwap.length; i++) {
@@ -1551,10 +1561,12 @@
1551
1561
  character.toUpperCase();
1552
1562
  }
1553
1563
  cm.replaceRange(swapped, curStart, curEnd);
1554
- cm.setCursor(curOriginal);
1564
+ if (!operatorArgs.shouldMoveCursor) {
1565
+ cm.setCursor(curOriginal);
1566
+ }
1555
1567
  },
1556
1568
  yank: function(cm, operatorArgs, _vim, curStart, curEnd, curOriginal) {
1557
- getVimGlobalState().registerController.pushText(
1569
+ vimGlobalState.registerController.pushText(
1558
1570
  operatorArgs.registerName, 'yank',
1559
1571
  cm.getRange(curStart, curEnd), operatorArgs.linewise);
1560
1572
  cm.setCursor(curOriginal);
@@ -1568,7 +1580,7 @@
1568
1580
  }
1569
1581
  var repeat = actionArgs.repeat;
1570
1582
  var forward = actionArgs.forward;
1571
- var jumpList = getVimGlobalState().jumpList;
1583
+ var jumpList = vimGlobalState.jumpList;
1572
1584
 
1573
1585
  var mark = jumpList.move(cm, forward ? repeat : -repeat);
1574
1586
  var markPos = mark ? mark.find() : undefined;
@@ -1594,7 +1606,7 @@
1594
1606
  replayMacro: function(cm, actionArgs) {
1595
1607
  var registerName = actionArgs.selectedCharacter;
1596
1608
  var repeat = actionArgs.repeat;
1597
- var macroModeState = getVimGlobalState().macroModeState;
1609
+ var macroModeState = vimGlobalState.macroModeState;
1598
1610
  if (registerName == '@') {
1599
1611
  registerName = macroModeState.latestRegister;
1600
1612
  }
@@ -1604,18 +1616,19 @@
1604
1616
  }
1605
1617
  },
1606
1618
  exitMacroRecordMode: function() {
1607
- var macroModeState = getVimGlobalState().macroModeState;
1619
+ var macroModeState = vimGlobalState.macroModeState;
1608
1620
  macroModeState.toggle();
1609
1621
  parseKeyBufferToRegister(macroModeState.latestRegister,
1610
1622
  macroModeState.macroKeyBuffer);
1611
1623
  },
1612
1624
  enterMacroRecordMode: function(cm, actionArgs) {
1613
- var macroModeState = getVimGlobalState().macroModeState;
1625
+ var macroModeState = vimGlobalState.macroModeState;
1614
1626
  var registerName = actionArgs.selectedCharacter;
1615
1627
  macroModeState.toggle(cm, registerName);
1616
1628
  emptyMacroKeyBuffer(macroModeState);
1617
1629
  },
1618
1630
  enterInsertMode: function(cm, actionArgs, vim) {
1631
+ if (cm.getOption('readOnly')) { return; }
1619
1632
  vim.insertMode = true;
1620
1633
  vim.insertModeRepeat = actionArgs && actionArgs.repeat || 1;
1621
1634
  var insertAt = (actionArgs) ? actionArgs.insertAt : null;
@@ -1636,7 +1649,7 @@
1636
1649
  } else {
1637
1650
  cm.setOption('keyMap', 'vim-insert');
1638
1651
  }
1639
- if (!getVimGlobalState().macroModeState.inReplay) {
1652
+ if (!vimGlobalState.macroModeState.inReplay) {
1640
1653
  // Only record if not replaying.
1641
1654
  cm.on('change', onChange);
1642
1655
  cm.on('cursorActivity', onCursorActivity);
@@ -1651,6 +1664,7 @@
1651
1664
  // equal to the repeat times the size of the previous visual
1652
1665
  // operation.
1653
1666
  if (!vim.visualMode) {
1667
+ cm.on('mousedown', exitVisualMode);
1654
1668
  vim.visualMode = true;
1655
1669
  vim.visualLine = !!actionArgs.linewise;
1656
1670
  if (vim.visualLine) {
@@ -1692,7 +1706,7 @@
1692
1706
  // mode instead of exiting visual mode.
1693
1707
  vim.visualLine = false;
1694
1708
  } else {
1695
- exitVisualMode(cm, vim);
1709
+ exitVisualMode(cm);
1696
1710
  }
1697
1711
  }
1698
1712
  updateMark(cm, vim, '<', cursorIsBefore(curStart, curEnd) ? curStart
@@ -1728,6 +1742,7 @@
1728
1742
  });
1729
1743
  },
1730
1744
  newLineAndEnterInsertMode: function(cm, actionArgs, vim) {
1745
+ vim.insertMode = true;
1731
1746
  var insertAt = cm.getCursor();
1732
1747
  if (insertAt.line === cm.firstLine() && !actionArgs.after) {
1733
1748
  // Special case for inserting newline before start of document.
@@ -1746,7 +1761,7 @@
1746
1761
  },
1747
1762
  paste: function(cm, actionArgs) {
1748
1763
  var cur = cm.getCursor();
1749
- var register = getVimGlobalState().registerController.getRegister(
1764
+ var register = vimGlobalState.registerController.getRegister(
1750
1765
  actionArgs.registerName);
1751
1766
  if (!register.text) {
1752
1767
  return;
@@ -1832,7 +1847,7 @@
1832
1847
  cm.replaceRange(replaceWithStr, curStart, curEnd);
1833
1848
  if(vim.visualMode){
1834
1849
  cm.setCursor(curStart);
1835
- exitVisualMode(cm,vim);
1850
+ exitVisualMode(cm);
1836
1851
  }else{
1837
1852
  cm.setCursor(offsetCursor(curEnd, 0, -1));
1838
1853
  }
@@ -1989,7 +2004,9 @@
1989
2004
  return s.replace(/([.?*+$\[\]\/\\(){}|\-])/g, '\\$1');
1990
2005
  }
1991
2006
 
1992
- function exitVisualMode(cm, vim) {
2007
+ function exitVisualMode(cm) {
2008
+ cm.off('mousedown', exitVisualMode);
2009
+ var vim = cm.state.vim;
1993
2010
  vim.visualMode = false;
1994
2011
  vim.visualLine = false;
1995
2012
  var selectionStart = cm.getCursor('anchor');
@@ -2113,12 +2130,11 @@
2113
2130
 
2114
2131
  function recordJumpPosition(cm, oldCur, newCur) {
2115
2132
  if(!cursorEqual(oldCur, newCur)) {
2116
- getVimGlobalState().jumpList.add(cm, oldCur, newCur);
2133
+ vimGlobalState.jumpList.add(cm, oldCur, newCur);
2117
2134
  }
2118
2135
  }
2119
2136
 
2120
2137
  function recordLastCharacterSearch(increment, args) {
2121
- var vimGlobalState = getVimGlobalState();
2122
2138
  vimGlobalState.lastChararacterSearch.increment = increment;
2123
2139
  vimGlobalState.lastChararacterSearch.forward = args.forward;
2124
2140
  vimGlobalState.lastChararacterSearch.selectedCharacter = args.selectedCharacter;
@@ -2572,10 +2588,10 @@
2572
2588
  function SearchState() {}
2573
2589
  SearchState.prototype = {
2574
2590
  getQuery: function() {
2575
- return getVimGlobalState().query;
2591
+ return vimGlobalState.query;
2576
2592
  },
2577
2593
  setQuery: function(query) {
2578
- getVimGlobalState().query = query;
2594
+ vimGlobalState.query = query;
2579
2595
  },
2580
2596
  getOverlay: function() {
2581
2597
  return this.searchOverlay;
@@ -2584,14 +2600,14 @@
2584
2600
  this.searchOverlay = overlay;
2585
2601
  },
2586
2602
  isReversed: function() {
2587
- return getVimGlobalState().isReversed;
2603
+ return vimGlobalState.isReversed;
2588
2604
  },
2589
2605
  setReversed: function(reversed) {
2590
- getVimGlobalState().isReversed = reversed;
2606
+ vimGlobalState.isReversed = reversed;
2591
2607
  }
2592
2608
  };
2593
2609
  function getSearchState(cm) {
2594
- var vim = getVimState(cm);
2610
+ var vim = cm.state.vim;
2595
2611
  return vim.searchState_ || (vim.searchState_ = new SearchState());
2596
2612
  }
2597
2613
  function dialog(cm, template, shortText, onClose, options) {
@@ -2840,9 +2856,9 @@
2840
2856
  };
2841
2857
  Vim.ExCommandDispatcher.prototype = {
2842
2858
  processCommand: function(cm, input) {
2843
- var vim = getVimState(cm);
2859
+ var vim = cm.state.vim;
2844
2860
  if (vim.visualMode) {
2845
- exitVisualMode(cm, vim);
2861
+ exitVisualMode(cm);
2846
2862
  }
2847
2863
  var inputStream = new CodeMirror.StringStream(input);
2848
2864
  var params = {};
@@ -2921,7 +2937,7 @@
2921
2937
  case '$':
2922
2938
  return cm.lastLine();
2923
2939
  case '\'':
2924
- var mark = getVimState(cm).marks[inputStream.next()];
2940
+ var mark = cm.state.vim.marks[inputStream.next()];
2925
2941
  if (mark && mark.find()) {
2926
2942
  return mark.find().line;
2927
2943
  }
@@ -3031,7 +3047,7 @@
3031
3047
  exCommandDispatcher.map(mapArgs[0], mapArgs[1], cm);
3032
3048
  },
3033
3049
  move: function(cm, params) {
3034
- commandDispatcher.processCommand(cm, getVimState(cm), {
3050
+ commandDispatcher.processCommand(cm, cm.state.vim, {
3035
3051
  type: 'motion',
3036
3052
  motion: 'moveToLineOrEdgeOfDocument',
3037
3053
  motionArgs: { forward: false, explicitRepeat: true,
@@ -3186,7 +3202,7 @@
3186
3202
  return;
3187
3203
  }
3188
3204
 
3189
- var state = getVimState(cm);
3205
+ var state = cm.state.vim;
3190
3206
  var stream = new CodeMirror.StringStream(params.argString.trim());
3191
3207
  while (!stream.eol()) {
3192
3208
  stream.eatSpace();
@@ -3257,6 +3273,7 @@
3257
3273
  function doReplace(cm, confirm, lineStart, lineEnd, searchCursor, query,
3258
3274
  replaceWith) {
3259
3275
  // Set up all the functions.
3276
+ cm.state.vim.exMode = true;
3260
3277
  var done = false;
3261
3278
  var lastPos = searchCursor.from();
3262
3279
  function replaceAll() {
@@ -3291,7 +3308,8 @@
3291
3308
  cm.focus();
3292
3309
  if (lastPos) {
3293
3310
  cm.setCursor(lastPos);
3294
- var vim = getVimState(cm);
3311
+ var vim = cm.state.vim;
3312
+ vim.exMode = false;
3295
3313
  vim.lastHPos = vim.lastHSPos = lastPos.ch;
3296
3314
  }
3297
3315
  }
@@ -3403,9 +3421,8 @@
3403
3421
  CodeMirror.keyMap.vim = buildVimKeyMap();
3404
3422
 
3405
3423
  function exitInsertMode(cm) {
3406
- var vim = getVimState(cm);
3407
- vim.insertMode = false;
3408
- var inReplay = getVimGlobalState().macroModeState.inReplay;
3424
+ var vim = cm.state.vim;
3425
+ var inReplay = vimGlobalState.macroModeState.inReplay;
3409
3426
  if (!inReplay) {
3410
3427
  cm.off('change', onChange);
3411
3428
  cm.off('cursorActivity', onCursorActivity);
@@ -3419,6 +3436,7 @@
3419
3436
  }
3420
3437
  delete vim.insertModeRepeat;
3421
3438
  cm.setCursor(cm.getCursor().line, cm.getCursor().ch-1, true);
3439
+ vim.insertMode = false;
3422
3440
  cm.setOption('keyMap', 'vim');
3423
3441
  cm.toggleOverwrite(false); // exit replace mode if we were in it.
3424
3442
  }
@@ -3446,7 +3464,7 @@
3446
3464
 
3447
3465
  function parseRegisterToKeyBuffer(macroModeState, registerName) {
3448
3466
  var match, key;
3449
- var register = getVimGlobalState().registerController.getRegister(registerName);
3467
+ var register = vimGlobalState.registerController.getRegister(registerName);
3450
3468
  var text = register.toString();
3451
3469
  var macroKeyBuffer = macroModeState.macroKeyBuffer;
3452
3470
  emptyMacroKeyBuffer(macroModeState);
@@ -3462,7 +3480,7 @@
3462
3480
 
3463
3481
  function parseKeyBufferToRegister(registerName, keyBuffer) {
3464
3482
  var text = keyBuffer.join('');
3465
- getVimGlobalState().registerController.setRegisterText(registerName, text);
3483
+ vimGlobalState.registerController.setRegisterText(registerName, text);
3466
3484
  }
3467
3485
 
3468
3486
  function emptyMacroKeyBuffer(macroModeState) {
@@ -3490,7 +3508,7 @@
3490
3508
  * Should only be active in insert mode.
3491
3509
  */
3492
3510
  function onChange(_cm, changeObj) {
3493
- var macroModeState = getVimGlobalState().macroModeState;
3511
+ var macroModeState = vimGlobalState.macroModeState;
3494
3512
  var lastChange = macroModeState.lastInsertModeChanges;
3495
3513
  while (changeObj) {
3496
3514
  lastChange.expectCursorActivityForChange = true;
@@ -3510,7 +3528,7 @@
3510
3528
  * - Should only be active in insert mode.
3511
3529
  */
3512
3530
  function onCursorActivity() {
3513
- var macroModeState = getVimGlobalState().macroModeState;
3531
+ var macroModeState = vimGlobalState.macroModeState;
3514
3532
  var lastChange = macroModeState.lastInsertModeChanges;
3515
3533
  if (lastChange.expectCursorActivityForChange) {
3516
3534
  lastChange.expectCursorActivityForChange = false;
@@ -3531,7 +3549,7 @@
3531
3549
  * - For recording deletes in insert mode.
3532
3550
  */
3533
3551
  function onKeyEventTargetKeyDown(e) {
3534
- var macroModeState = getVimGlobalState().macroModeState;
3552
+ var macroModeState = vimGlobalState.macroModeState;
3535
3553
  var lastChange = macroModeState.lastInsertModeChanges;
3536
3554
  var keyName = CodeMirror.keyName(e);
3537
3555
  function onKeyFound() {
@@ -3553,7 +3571,7 @@
3553
3571
  * corresponding enterInsertMode call was made with a count.
3554
3572
  */
3555
3573
  function repeatLastEdit(cm, vim, repeat, repeatForInsert) {
3556
- var macroModeState = getVimGlobalState().macroModeState;
3574
+ var macroModeState = vimGlobalState.macroModeState;
3557
3575
  macroModeState.inReplay = true;
3558
3576
  var isAction = !!vim.lastEditActionCommand;
3559
3577
  var cachedInputState = vim.inputState;
@@ -3621,6 +3639,7 @@
3621
3639
  }
3622
3640
  }
3623
3641
 
3642
+ resetVimGlobalState();
3624
3643
  return vimApi;
3625
3644
  };
3626
3645
  // Initialize Vim and make it available as an API.