codemirror-rails 3.14 → 3.15

Sign up to get free protection for your applications and to get access to all the features.
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.