codemirror-rails 4.7 → 4.8

Sign up to get free protection for your applications and to get access to all the features.
Files changed (26) hide show
  1. checksums.yaml +4 -4
  2. data/lib/codemirror/rails/version.rb +2 -2
  3. data/vendor/assets/javascripts/codemirror.js +229 -137
  4. data/vendor/assets/javascripts/codemirror/addons/edit/closebrackets.js +1 -1
  5. data/vendor/assets/javascripts/codemirror/addons/hint/javascript-hint.js +9 -9
  6. data/vendor/assets/javascripts/codemirror/addons/hint/xml-hint.js +9 -1
  7. data/vendor/assets/javascripts/codemirror/addons/mode/loadmode.js +19 -16
  8. data/vendor/assets/javascripts/codemirror/addons/mode/overlay.js +3 -3
  9. data/vendor/assets/javascripts/codemirror/keymaps/emacs.js +19 -28
  10. data/vendor/assets/javascripts/codemirror/keymaps/sublime.js +14 -15
  11. data/vendor/assets/javascripts/codemirror/keymaps/vim.js +694 -752
  12. data/vendor/assets/javascripts/codemirror/modes/clike.js +15 -0
  13. data/vendor/assets/javascripts/codemirror/modes/css.js +1 -1
  14. data/vendor/assets/javascripts/codemirror/modes/dockerfile.js +80 -0
  15. data/vendor/assets/javascripts/codemirror/modes/gfm.js +2 -1
  16. data/vendor/assets/javascripts/codemirror/modes/htmlmixed.js +2 -2
  17. data/vendor/assets/javascripts/codemirror/modes/idl.js +290 -0
  18. data/vendor/assets/javascripts/codemirror/modes/markdown.js +62 -55
  19. data/vendor/assets/javascripts/codemirror/modes/sparql.js +19 -5
  20. data/vendor/assets/javascripts/codemirror/modes/sql.js +0 -2
  21. data/vendor/assets/javascripts/codemirror/modes/stex.js +184 -193
  22. data/vendor/assets/javascripts/codemirror/modes/yaml.js +6 -1
  23. data/vendor/assets/stylesheets/codemirror.css +11 -2
  24. data/vendor/assets/stylesheets/codemirror/themes/3024-day.css +1 -1
  25. data/vendor/assets/stylesheets/codemirror/themes/solarized.css +0 -5
  26. metadata +3 -1
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 926ba7eaf6d3a5946a51a9edd1dc6d99ed211cb8
4
- data.tar.gz: e2c1f08a582fd76a0ecc35be5a393b1d2c0f25ff
3
+ metadata.gz: 0d7ed536cdd6c54bf26a2267fc6cf13ed09e4624
4
+ data.tar.gz: 62813e43c76250a3ff56dc69e5d4123a1d42217f
5
5
  SHA512:
6
- metadata.gz: ac13c0485f7879662c60063b1e4cc13b8e7b8e4c733806c14a5099f6a506c6c7b735b99ace5f6596c3f5225a3816db098d1878d48ce2ec640c5d985d8458a649
7
- data.tar.gz: ca0484ab6b9734f44a2a160d471a6584867b3d22f374485ea5c1810b898fd6859a9e86be18f762e3e1ec99d383d291dd8dbdc2c6a5f870157c90978de28d1325
6
+ metadata.gz: 3317a5d5a1f262e96ee51ce496be3108871e07f081140d3c35636beba654d2dc665a10004384f6cb49a7d6feca12a5aea7c634675cb905819226d32ed8798b79
7
+ data.tar.gz: f48c7e94303a13be7f6ef197dc5346ed5c113c829fcf9b8be8e858511b989c641bf7957082514f86df44e32140d8ee5c296118ff2e29f6703b6ce886f8ca608c
@@ -1,6 +1,6 @@
1
1
  module Codemirror
2
2
  module Rails
3
- VERSION = '4.7'
4
- CODEMIRROR_VERSION = '4.7'
3
+ VERSION = '4.8'
4
+ CODEMIRROR_VERSION = '4.8'
5
5
  end
6
6
  end
@@ -86,7 +86,8 @@
86
86
  suppressEdits: false, // used to disable editing during key handlers when in readOnly mode
87
87
  pasteIncoming: false, cutIncoming: false, // help recognize paste/cut edits in readInput
88
88
  draggingText: false,
89
- highlight: new Delayed() // stores highlight worker timeout
89
+ highlight: new Delayed(), // stores highlight worker timeout
90
+ keySeq: null // Unfinished key sequence
90
91
  };
91
92
 
92
93
  // Override magic textarea content restore that IE sometimes does
@@ -184,8 +185,10 @@
184
185
  // Need to set a minimum width to see the scrollbar on IE7 (but must not set it on IE8).
185
186
  if (ie && ie_version < 8) d.scrollbarH.style.minHeight = d.scrollbarV.style.minWidth = "18px";
186
187
 
187
- if (place.appendChild) place.appendChild(d.wrapper);
188
- else place(d.wrapper);
188
+ if (place) {
189
+ if (place.appendChild) place.appendChild(d.wrapper);
190
+ else place(d.wrapper);
191
+ }
189
192
 
190
193
  // Current rendered range (may be bigger than the view window).
191
194
  d.viewFrom = d.viewTo = doc.first;
@@ -196,7 +199,7 @@
196
199
  d.externalMeasured = null;
197
200
  // Empty space (in pixels) above the view
198
201
  d.viewOffset = 0;
199
- d.lastSizeC = 0;
202
+ d.lastWrapHeight = d.lastWrapWidth = 0;
200
203
  d.updateLineNumbers = null;
201
204
 
202
205
  // Used to only resize the line number gutter when necessary (when
@@ -301,12 +304,6 @@
301
304
  });
302
305
  }
303
306
 
304
- function keyMapChanged(cm) {
305
- var map = keyMap[cm.options.keyMap], style = map.style;
306
- cm.display.wrapper.className = cm.display.wrapper.className.replace(/\s*cm-keymap-\S+/g, "") +
307
- (style ? " cm-keymap-" + style : "");
308
- }
309
-
310
307
  function themeChanged(cm) {
311
308
  cm.display.wrapper.className = cm.display.wrapper.className.replace(/\s*cm-s-\S+/g, "") +
312
309
  cm.options.theme.replace(/(^|\s)\s*/g, " cm-s-");
@@ -551,6 +548,7 @@
551
548
  this.visible = visibleLines(display, cm.doc, viewport);
552
549
  this.editorIsHidden = !display.wrapper.offsetWidth;
553
550
  this.wrapperHeight = display.wrapper.clientHeight;
551
+ this.wrapperWidth = display.wrapper.clientWidth;
554
552
  this.oldViewFrom = display.viewFrom; this.oldViewTo = display.viewTo;
555
553
  this.oldScrollerWidth = display.scroller.clientWidth;
556
554
  this.force = force;
@@ -591,7 +589,7 @@
591
589
  }
592
590
 
593
591
  var different = from != display.viewFrom || to != display.viewTo ||
594
- display.lastSizeC != update.wrapperHeight;
592
+ display.lastWrapHeight != update.wrapperHeight || display.lastWrapWidth != update.wrapperWidth;
595
593
  adjustView(cm, from, to);
596
594
 
597
595
  display.viewOffset = heightAtLine(getLine(cm.doc, display.viewFrom));
@@ -619,7 +617,8 @@
619
617
  removeChildren(display.selectionDiv);
620
618
 
621
619
  if (different) {
622
- display.lastSizeC = update.wrapperHeight;
620
+ display.lastWrapHeight = update.wrapperHeight;
621
+ display.lastWrapWidth = update.wrapperWidth;
623
622
  startWorker(cm, 400);
624
623
  }
625
624
 
@@ -868,9 +867,12 @@
868
867
  if (cm.options.lineNumbers || markers) {
869
868
  var wrap = ensureLineWrapped(lineView);
870
869
  var gutterWrap = lineView.gutter =
871
- wrap.insertBefore(elt("div", null, "CodeMirror-gutter-wrapper", "position: absolute; left: " +
872
- (cm.options.fixedGutter ? dims.fixedPos : -dims.gutterTotalWidth) + "px"),
870
+ wrap.insertBefore(elt("div", null, "CodeMirror-gutter-wrapper", "left: " +
871
+ (cm.options.fixedGutter ? dims.fixedPos : -dims.gutterTotalWidth) +
872
+ "px; width: " + dims.gutterTotalWidth + "px"),
873
873
  lineView.text);
874
+ if (lineView.line.gutterClass)
875
+ gutterWrap.className += " " + lineView.line.gutterClass;
874
876
  if (cm.options.lineNumbers && (!markers || !markers["CodeMirror-linenumbers"]))
875
877
  lineView.lineNumber = gutterWrap.appendChild(
876
878
  elt("div", lineNumberFor(cm.options, lineN),
@@ -2397,7 +2399,7 @@
2397
2399
  // possible when it is clear that nothing happened. hasSelection
2398
2400
  // will be the case when there is a lot of text in the textarea,
2399
2401
  // in which case reading its value would be expensive.
2400
- if (!cm.state.focused || (hasSelection(input) && !prevInput) || isReadOnly(cm) || cm.options.disableInput)
2402
+ if (!cm.state.focused || (hasSelection(input) && !prevInput) || isReadOnly(cm) || cm.options.disableInput || cm.state.keySeq)
2401
2403
  return false;
2402
2404
  // See paste handler for more on the fakedLastChar kludge
2403
2405
  if (cm.state.pasteIncoming && cm.state.fakedLastChar) {
@@ -2652,8 +2654,10 @@
2652
2654
 
2653
2655
  // Called when the window resizes
2654
2656
  function onResize(cm) {
2655
- // Might be a text scaling operation, clear size caches.
2656
2657
  var d = cm.display;
2658
+ if (d.lastWrapHeight == d.wrapper.clientHeight && d.lastWrapWidth == d.wrapper.clientWidth)
2659
+ return;
2660
+ // Might be a text scaling operation, clear size caches.
2657
2661
  d.cachedCharWidth = d.cachedTextHeight = d.cachedPaddingH = null;
2658
2662
  cm.setSize();
2659
2663
  }
@@ -3167,62 +3171,70 @@
3167
3171
  return done;
3168
3172
  }
3169
3173
 
3170
- // Collect the currently active keymaps.
3171
- function allKeyMaps(cm) {
3172
- var maps = cm.state.keyMaps.slice(0);
3173
- if (cm.options.extraKeys) maps.push(cm.options.extraKeys);
3174
- maps.push(cm.options.keyMap);
3175
- return maps;
3174
+ function lookupKeyForEditor(cm, name, handle) {
3175
+ for (var i = 0; i < cm.state.keyMaps.length; i++) {
3176
+ var result = lookupKey(name, cm.state.keyMaps[i], handle);
3177
+ if (result) return result;
3178
+ }
3179
+ return (cm.options.extraKeys && lookupKey(name, cm.options.extraKeys, handle))
3180
+ || lookupKey(name, cm.options.keyMap, handle);
3181
+ }
3182
+
3183
+ var stopSeq = new Delayed;
3184
+ function dispatchKey(cm, name, e, handle) {
3185
+ var seq = cm.state.keySeq;
3186
+ if (seq) {
3187
+ if (isModifierKey(name)) return "handled";
3188
+ stopSeq.set(50, function() {
3189
+ if (cm.state.keySeq == seq) {
3190
+ cm.state.keySeq = null;
3191
+ resetInput(cm);
3192
+ }
3193
+ });
3194
+ name = seq + " " + name;
3195
+ }
3196
+ var result = lookupKeyForEditor(cm, name, handle);
3197
+
3198
+ if (result == "multi")
3199
+ cm.state.keySeq = name;
3200
+ if (result == "handled")
3201
+ signalLater(cm, "keyHandled", cm, name, e);
3202
+
3203
+ if (result == "handled" || result == "multi") {
3204
+ e_preventDefault(e);
3205
+ restartBlink(cm);
3206
+ }
3207
+
3208
+ if (seq && !result && /\'$/.test(name)) {
3209
+ e_preventDefault(e);
3210
+ return true;
3211
+ }
3212
+ return !!result;
3176
3213
  }
3177
3214
 
3178
- var maybeTransition;
3179
3215
  // Handle a key from the keydown event.
3180
3216
  function handleKeyBinding(cm, e) {
3181
- // Handle automatic keymap transitions
3182
- var startMap = getKeyMap(cm.options.keyMap), next = startMap.auto;
3183
- clearTimeout(maybeTransition);
3184
- if (next && !isModifierKey(e)) maybeTransition = setTimeout(function() {
3185
- if (getKeyMap(cm.options.keyMap) == startMap) {
3186
- cm.options.keyMap = (next.call ? next.call(null, cm) : next);
3187
- keyMapChanged(cm);
3188
- }
3189
- }, 50);
3190
-
3191
- var name = keyName(e, true), handled = false;
3217
+ var name = keyName(e, true);
3192
3218
  if (!name) return false;
3193
- var keymaps = allKeyMaps(cm);
3194
3219
 
3195
- if (e.shiftKey) {
3220
+ if (e.shiftKey && !cm.state.keySeq) {
3196
3221
  // First try to resolve full name (including 'Shift-'). Failing
3197
3222
  // that, see if there is a cursor-motion command (starting with
3198
3223
  // 'go') bound to the keyname without 'Shift-'.
3199
- handled = lookupKey("Shift-" + name, keymaps, function(b) {return doHandleBinding(cm, b, true);})
3200
- || lookupKey(name, keymaps, function(b) {
3201
- if (typeof b == "string" ? /^go[A-Z]/.test(b) : b.motion)
3202
- return doHandleBinding(cm, b);
3203
- });
3224
+ return dispatchKey(cm, "Shift-" + name, e, function(b) {return doHandleBinding(cm, b, true);})
3225
+ || dispatchKey(cm, name, e, function(b) {
3226
+ if (typeof b == "string" ? /^go[A-Z]/.test(b) : b.motion)
3227
+ return doHandleBinding(cm, b);
3228
+ });
3204
3229
  } else {
3205
- handled = lookupKey(name, keymaps, function(b) { return doHandleBinding(cm, b); });
3230
+ return dispatchKey(cm, name, e, function(b) { return doHandleBinding(cm, b); });
3206
3231
  }
3207
-
3208
- if (handled) {
3209
- e_preventDefault(e);
3210
- restartBlink(cm);
3211
- signalLater(cm, "keyHandled", cm, name, e);
3212
- }
3213
- return handled;
3214
3232
  }
3215
3233
 
3216
3234
  // Handle a key from the keypress event
3217
3235
  function handleCharBinding(cm, e, ch) {
3218
- var handled = lookupKey("'" + ch + "'", allKeyMaps(cm),
3219
- function(b) { return doHandleBinding(cm, b, true); });
3220
- if (handled) {
3221
- e_preventDefault(e);
3222
- restartBlink(cm);
3223
- signalLater(cm, "keyHandled", cm, "'" + ch + "'", e);
3224
- }
3225
- return handled;
3236
+ return dispatchKey(cm, "'" + ch + "'", e,
3237
+ function(b) { return doHandleBinding(cm, b, true); });
3226
3238
  }
3227
3239
 
3228
3240
  var lastStoppedKey = null;
@@ -3701,6 +3713,8 @@
3701
3713
  // If an editor sits on the top or bottom of the window, partially
3702
3714
  // scrolled out of view, this ensures that the cursor is visible.
3703
3715
  function maybeScrollWindow(cm, coords) {
3716
+ if (signalDOMEvent(cm, "scrollCursorIntoView")) return;
3717
+
3704
3718
  var display = cm.display, box = display.sizer.getBoundingClientRect(), doScroll = null;
3705
3719
  if (coords.top + box.top < 0) doScroll = true;
3706
3720
  else if (coords.bottom + box.top > (window.innerHeight || document.documentElement.clientHeight)) doScroll = false;
@@ -4024,12 +4038,12 @@
4024
4038
  getDoc: function() {return this.doc;},
4025
4039
 
4026
4040
  addKeyMap: function(map, bottom) {
4027
- this.state.keyMaps[bottom ? "push" : "unshift"](map);
4041
+ this.state.keyMaps[bottom ? "push" : "unshift"](getKeyMap(map));
4028
4042
  },
4029
4043
  removeKeyMap: function(map) {
4030
4044
  var maps = this.state.keyMaps;
4031
4045
  for (var i = 0; i < maps.length; ++i)
4032
- if (maps[i] == map || (typeof maps[i] != "string" && maps[i].name == map)) {
4046
+ if (maps[i] == map || maps[i].name == map) {
4033
4047
  maps.splice(i, 1);
4034
4048
  return true;
4035
4049
  }
@@ -4086,20 +4100,11 @@
4086
4100
  // Fetch the parser token for a given character. Useful for hacks
4087
4101
  // that want to inspect the mode state (say, for completion).
4088
4102
  getTokenAt: function(pos, precise) {
4089
- var doc = this.doc;
4090
- pos = clipPos(doc, pos);
4091
- var state = getStateBefore(this, pos.line, precise), mode = this.doc.mode;
4092
- var line = getLine(doc, pos.line);
4093
- var stream = new StringStream(line.text, this.options.tabSize);
4094
- while (stream.pos < pos.ch && !stream.eol()) {
4095
- stream.start = stream.pos;
4096
- var style = readToken(mode, stream, state);
4097
- }
4098
- return {start: stream.start,
4099
- end: stream.pos,
4100
- string: stream.current(),
4101
- type: style || null,
4102
- state: state};
4103
+ return takeToken(this, pos, precise);
4104
+ },
4105
+
4106
+ getLineTokens: function(line, precise) {
4107
+ return takeToken(this, Pos(line), precise, true);
4103
4108
  },
4104
4109
 
4105
4110
  getTokenTypeAt: function(pos) {
@@ -4502,7 +4507,12 @@
4502
4507
  themeChanged(cm);
4503
4508
  guttersChanged(cm);
4504
4509
  }, true);
4505
- option("keyMap", "default", keyMapChanged);
4510
+ option("keyMap", "default", function(cm, val, old) {
4511
+ var next = getKeyMap(val);
4512
+ var prev = old != CodeMirror.Init && getKeyMap(old);
4513
+ if (prev && prev.detach) prev.detach(cm, next);
4514
+ if (next.attach) next.attach(cm, prev || null);
4515
+ });
4506
4516
  option("extraKeys", null);
4507
4517
 
4508
4518
  option("lineWrapping", false, wrappingChanged, true);
@@ -4847,9 +4857,11 @@
4847
4857
  toggleOverwrite: function(cm) {cm.toggleOverwrite();}
4848
4858
  };
4849
4859
 
4860
+
4850
4861
  // STANDARD KEYMAPS
4851
4862
 
4852
4863
  var keyMap = CodeMirror.keyMap = {};
4864
+
4853
4865
  keyMap.basic = {
4854
4866
  "Left": "goCharLeft", "Right": "goCharRight", "Up": "goLineUp", "Down": "goLineDown",
4855
4867
  "End": "goLineEnd", "Home": "goLineStartSmart", "PageUp": "goPageUp", "PageDown": "goPageDown",
@@ -4871,6 +4883,13 @@
4871
4883
  "Ctrl-U": "undoSelection", "Shift-Ctrl-U": "redoSelection", "Alt-U": "redoSelection",
4872
4884
  fallthrough: "basic"
4873
4885
  };
4886
+ // Very basic readline/emacs-style bindings, which are standard on Mac.
4887
+ keyMap.emacsy = {
4888
+ "Ctrl-F": "goCharRight", "Ctrl-B": "goCharLeft", "Ctrl-P": "goLineUp", "Ctrl-N": "goLineDown",
4889
+ "Alt-F": "goWordRight", "Alt-B": "goWordLeft", "Ctrl-A": "goLineStart", "Ctrl-E": "goLineEnd",
4890
+ "Ctrl-V": "goPageDown", "Shift-Ctrl-V": "goPageUp", "Ctrl-D": "delCharAfter", "Ctrl-H": "delCharBefore",
4891
+ "Alt-D": "delWordAfter", "Alt-Backspace": "delWordBefore", "Ctrl-K": "killLine", "Ctrl-T": "transposeChars"
4892
+ };
4874
4893
  keyMap.macDefault = {
4875
4894
  "Cmd-A": "selectAll", "Cmd-D": "deleteLine", "Cmd-Z": "undo", "Shift-Cmd-Z": "redo", "Cmd-Y": "redo",
4876
4895
  "Cmd-Home": "goDocStart", "Cmd-Up": "goDocStart", "Cmd-End": "goDocEnd", "Cmd-Down": "goDocEnd", "Alt-Left": "goGroupLeft",
@@ -4881,70 +4900,100 @@
4881
4900
  "Cmd-U": "undoSelection", "Shift-Cmd-U": "redoSelection", "Ctrl-Up": "goDocStart", "Ctrl-Down": "goDocEnd",
4882
4901
  fallthrough: ["basic", "emacsy"]
4883
4902
  };
4884
- // Very basic readline/emacs-style bindings, which are standard on Mac.
4885
- keyMap.emacsy = {
4886
- "Ctrl-F": "goCharRight", "Ctrl-B": "goCharLeft", "Ctrl-P": "goLineUp", "Ctrl-N": "goLineDown",
4887
- "Alt-F": "goWordRight", "Alt-B": "goWordLeft", "Ctrl-A": "goLineStart", "Ctrl-E": "goLineEnd",
4888
- "Ctrl-V": "goPageDown", "Shift-Ctrl-V": "goPageUp", "Ctrl-D": "delCharAfter", "Ctrl-H": "delCharBefore",
4889
- "Alt-D": "delWordAfter", "Alt-Backspace": "delWordBefore", "Ctrl-K": "killLine", "Ctrl-T": "transposeChars"
4890
- };
4891
4903
  keyMap["default"] = mac ? keyMap.macDefault : keyMap.pcDefault;
4892
4904
 
4893
4905
  // KEYMAP DISPATCH
4894
4906
 
4895
- function getKeyMap(val) {
4896
- if (typeof val == "string") return keyMap[val];
4897
- else return val;
4898
- }
4899
-
4900
- // Given an array of keymaps and a key name, call handle on any
4901
- // bindings found, until that returns a truthy value, at which point
4902
- // we consider the key handled. Implements things like binding a key
4903
- // to false stopping further handling and keymap fallthrough.
4904
- var lookupKey = CodeMirror.lookupKey = function(name, maps, handle) {
4905
- function lookup(map) {
4906
- map = getKeyMap(map);
4907
- var found = map[name];
4908
- if (found === false) return "stop";
4909
- if (found != null && handle(found)) return true;
4910
- if (map.nofallthrough) return "stop";
4911
-
4912
- var fallthrough = map.fallthrough;
4913
- if (fallthrough == null) return false;
4914
- if (Object.prototype.toString.call(fallthrough) != "[object Array]")
4915
- return lookup(fallthrough);
4916
- for (var i = 0; i < fallthrough.length; ++i) {
4917
- var done = lookup(fallthrough[i]);
4918
- if (done) return done;
4907
+ function normalizeKeyName(name) {
4908
+ var parts = name.split(/-(?!$)/), name = parts[parts.length - 1];
4909
+ var alt, ctrl, shift, cmd;
4910
+ for (var i = 0; i < parts.length - 1; i++) {
4911
+ var mod = parts[i];
4912
+ if (/^(cmd|meta|m)$/i.test(mod)) cmd = true;
4913
+ else if (/^a(lt)?$/i.test(mod)) alt = true;
4914
+ else if (/^(c|ctrl|control)$/i.test(mod)) ctrl = true;
4915
+ else if (/^s(hift)$/i.test(mod)) shift = true;
4916
+ else throw new Error("Unrecognized modifier name: " + mod);
4917
+ }
4918
+ if (alt) name = "Alt-" + name;
4919
+ if (ctrl) name = "Ctrl-" + name;
4920
+ if (cmd) name = "Cmd-" + name;
4921
+ if (shift) name = "Shift-" + name;
4922
+ return name;
4923
+ }
4924
+
4925
+ // This is a kludge to keep keymaps mostly working as raw objects
4926
+ // (backwards compatibility) while at the same time support features
4927
+ // like normalization and multi-stroke key bindings. It compiles a
4928
+ // new normalized keymap, and then updates the old object to reflect
4929
+ // this.
4930
+ CodeMirror.normalizeKeyMap = function(keymap) {
4931
+ var copy = {};
4932
+ for (var keyname in keymap) if (keymap.hasOwnProperty(keyname)) {
4933
+ var value = keymap[keyname];
4934
+ if (/^(name|fallthrough|(de|at)tach)$/.test(keyname)) continue;
4935
+ if (value == "...") { delete keymap[keyname]; continue; }
4936
+
4937
+ var keys = map(keyname.split(" "), normalizeKeyName);
4938
+ for (var i = 0; i < keys.length; i++) {
4939
+ var val, name;
4940
+ if (i == keys.length - 1) {
4941
+ name = keyname;
4942
+ val = value;
4943
+ } else {
4944
+ name = keys.slice(0, i + 1).join(" ");
4945
+ val = "...";
4946
+ }
4947
+ var prev = copy[name];
4948
+ if (!prev) copy[name] = val;
4949
+ else if (prev != val) throw new Error("Inconsistent bindings for " + name);
4919
4950
  }
4920
- return false;
4951
+ delete keymap[keyname];
4921
4952
  }
4953
+ for (var prop in copy) keymap[prop] = copy[prop];
4954
+ return keymap;
4955
+ };
4922
4956
 
4923
- for (var i = 0; i < maps.length; ++i) {
4924
- var done = lookup(maps[i]);
4925
- if (done) return done != "stop";
4957
+ var lookupKey = CodeMirror.lookupKey = function(key, map, handle) {
4958
+ map = getKeyMap(map);
4959
+ var found = map.call ? map.call(key) : map[key];
4960
+ if (found === false) return "nothing";
4961
+ if (found === "...") return "multi";
4962
+ if (found != null && handle(found)) return "handled";
4963
+
4964
+ if (map.fallthrough) {
4965
+ if (Object.prototype.toString.call(map.fallthrough) != "[object Array]")
4966
+ return lookupKey(key, map.fallthrough, handle);
4967
+ for (var i = 0; i < map.fallthrough.length; i++) {
4968
+ var result = lookupKey(key, map.fallthrough[i], handle);
4969
+ if (result) return result;
4970
+ }
4926
4971
  }
4927
4972
  };
4928
4973
 
4929
4974
  // Modifier key presses don't count as 'real' key presses for the
4930
4975
  // purpose of keymap fallthrough.
4931
- var isModifierKey = CodeMirror.isModifierKey = function(event) {
4932
- var name = keyNames[event.keyCode];
4976
+ var isModifierKey = CodeMirror.isModifierKey = function(value) {
4977
+ var name = typeof value == "string" ? value : keyNames[value.keyCode];
4933
4978
  return name == "Ctrl" || name == "Alt" || name == "Shift" || name == "Mod";
4934
4979
  };
4935
4980
 
4936
4981
  // Look up the name of a key as indicated by an event object.
4937
4982
  var keyName = CodeMirror.keyName = function(event, noShift) {
4938
4983
  if (presto && event.keyCode == 34 && event["char"]) return false;
4939
- var name = keyNames[event.keyCode];
4984
+ var base = keyNames[event.keyCode], name = base;
4940
4985
  if (name == null || event.altGraphKey) return false;
4941
- if (event.altKey) name = "Alt-" + name;
4942
- if (flipCtrlCmd ? event.metaKey : event.ctrlKey) name = "Ctrl-" + name;
4943
- if (flipCtrlCmd ? event.ctrlKey : event.metaKey) name = "Cmd-" + name;
4944
- if (!noShift && event.shiftKey) name = "Shift-" + name;
4986
+ if (event.altKey && base != "Alt") name = "Alt-" + name;
4987
+ if ((flipCtrlCmd ? event.metaKey : event.ctrlKey) && base != "Ctrl") name = "Ctrl-" + name;
4988
+ if ((flipCtrlCmd ? event.ctrlKey : event.metaKey) && base != "Cmd") name = "Cmd-" + name;
4989
+ if (!noShift && event.shiftKey && base != "Shift") name = "Shift-" + name;
4945
4990
  return name;
4946
4991
  };
4947
4992
 
4993
+ function getKeyMap(val) {
4994
+ return typeof val == "string" ? keyMap[val] : val;
4995
+ }
4996
+
4948
4997
  // FROMTEXTAREA
4949
4998
 
4950
4999
  CodeMirror.fromTextArea = function(textarea, options) {
@@ -5794,20 +5843,44 @@
5794
5843
  if (inner.mode.blankLine) return inner.mode.blankLine(inner.state);
5795
5844
  }
5796
5845
 
5797
- function readToken(mode, stream, state) {
5846
+ function readToken(mode, stream, state, inner) {
5798
5847
  for (var i = 0; i < 10; i++) {
5848
+ if (inner) inner[0] = CodeMirror.innerMode(mode, state).mode;
5799
5849
  var style = mode.token(stream, state);
5800
5850
  if (stream.pos > stream.start) return style;
5801
5851
  }
5802
5852
  throw new Error("Mode " + mode.name + " failed to advance stream.");
5803
5853
  }
5804
5854
 
5855
+ // Utility for getTokenAt and getLineTokens
5856
+ function takeToken(cm, pos, precise, asArray) {
5857
+ function getObj(copy) {
5858
+ return {start: stream.start, end: stream.pos,
5859
+ string: stream.current(),
5860
+ type: style || null,
5861
+ state: copy ? copyState(doc.mode, state) : state};
5862
+ }
5863
+
5864
+ var doc = cm.doc, mode = doc.mode, style;
5865
+ pos = clipPos(doc, pos);
5866
+ var line = getLine(doc, pos.line), state = getStateBefore(cm, pos.line, precise);
5867
+ var stream = new StringStream(line.text, cm.options.tabSize), tokens;
5868
+ if (asArray) tokens = [];
5869
+ while ((asArray || stream.pos < pos.ch) && !stream.eol()) {
5870
+ stream.start = stream.pos;
5871
+ style = readToken(mode, stream, state);
5872
+ if (asArray) tokens.push(getObj(true));
5873
+ }
5874
+ return asArray ? tokens : getObj();
5875
+ }
5876
+
5805
5877
  // Run the given mode's parser over a line, calling f for each token.
5806
5878
  function runMode(cm, text, mode, state, f, lineClasses, forceToEnd) {
5807
5879
  var flattenSpans = mode.flattenSpans;
5808
5880
  if (flattenSpans == null) flattenSpans = cm.options.flattenSpans;
5809
5881
  var curStart = 0, curStyle = null;
5810
5882
  var stream = new StringStream(text, cm.options.tabSize), style;
5883
+ var inner = cm.options.addModeClass && [null];
5811
5884
  if (text == "") extractLineClasses(callBlankLine(mode, state), lineClasses);
5812
5885
  while (!stream.eol()) {
5813
5886
  if (stream.pos > cm.options.maxHighlightLength) {
@@ -5816,10 +5889,10 @@
5816
5889
  stream.pos = text.length;
5817
5890
  style = null;
5818
5891
  } else {
5819
- style = extractLineClasses(readToken(mode, stream, state), lineClasses);
5892
+ style = extractLineClasses(readToken(mode, stream, state, inner), lineClasses);
5820
5893
  }
5821
- if (cm.options.addModeClass) {
5822
- var mName = CodeMirror.innerMode(mode, state).mode.name;
5894
+ if (inner) {
5895
+ var mName = inner[0].name;
5823
5896
  if (mName) style = "m-" + (style ? mName + " " + style : mName);
5824
5897
  }
5825
5898
  if (!flattenSpans || curStyle != style) {
@@ -5878,12 +5951,13 @@
5878
5951
  return {styles: st, classes: lineClasses.bgClass || lineClasses.textClass ? lineClasses : null};
5879
5952
  }
5880
5953
 
5881
- function getLineStyles(cm, line) {
5954
+ function getLineStyles(cm, line, updateFrontier) {
5882
5955
  if (!line.styles || line.styles[0] != cm.state.modeGen) {
5883
5956
  var result = highlightLine(cm, line, line.stateAfter = getStateBefore(cm, lineNo(line)));
5884
5957
  line.styles = result.styles;
5885
5958
  if (result.classes) line.styleClasses = result.classes;
5886
5959
  else if (line.styleClasses) line.styleClasses = null;
5960
+ if (updateFrontier === cm.doc.frontier) cm.doc.frontier++;
5887
5961
  }
5888
5962
  return line.styles;
5889
5963
  }
@@ -5938,7 +6012,8 @@
5938
6012
  if (hasBadBidiRects(cm.display.measure) && (order = getOrder(line)))
5939
6013
  builder.addToken = buildTokenBadBidi(builder.addToken, order);
5940
6014
  builder.map = [];
5941
- insertLineContent(line, builder, getLineStyles(cm, line));
6015
+ var allowFrontierUpdate = lineView != cm.display.externalMeasured && lineNo(line);
6016
+ insertLineContent(line, builder, getLineStyles(cm, line, allowFrontierUpdate));
5942
6017
  if (line.styleClasses) {
5943
6018
  if (line.styleClasses.bgClass)
5944
6019
  builder.bgClass = joinClasses(line.styleClasses.bgClass, builder.bgClass || "");
@@ -5960,9 +6035,14 @@
5960
6035
  }
5961
6036
  }
5962
6037
 
6038
+ // See issue #2901
6039
+ if (webkit && /\bcm-tab\b/.test(builder.content.lastChild.className))
6040
+ builder.content.className = "cm-tab-wrap-hack";
6041
+
5963
6042
  signal(cm, "renderLine", cm, lineView.line, builder.pre);
5964
6043
  if (builder.pre.className)
5965
6044
  builder.textClass = joinClasses(builder.pre.className, builder.textClass || "");
6045
+
5966
6046
  return builder;
5967
6047
  }
5968
6048
 
@@ -6531,22 +6611,26 @@
6531
6611
  },
6532
6612
 
6533
6613
  addLineClass: docMethodOp(function(handle, where, cls) {
6534
- return changeLine(this, handle, "class", function(line) {
6535
- var prop = where == "text" ? "textClass" : where == "background" ? "bgClass" : "wrapClass";
6614
+ return changeLine(this, handle, where == "gutter" ? "gutter" : "class", function(line) {
6615
+ var prop = where == "text" ? "textClass"
6616
+ : where == "background" ? "bgClass"
6617
+ : where == "gutter" ? "gutterClass" : "wrapClass";
6536
6618
  if (!line[prop]) line[prop] = cls;
6537
- else if (new RegExp("(?:^|\\s)" + cls + "(?:$|\\s)").test(line[prop])) return false;
6619
+ else if (classTest(cls).test(line[prop])) return false;
6538
6620
  else line[prop] += " " + cls;
6539
6621
  return true;
6540
6622
  });
6541
6623
  }),
6542
6624
  removeLineClass: docMethodOp(function(handle, where, cls) {
6543
6625
  return changeLine(this, handle, "class", function(line) {
6544
- var prop = where == "text" ? "textClass" : where == "background" ? "bgClass" : "wrapClass";
6626
+ var prop = where == "text" ? "textClass"
6627
+ : where == "background" ? "bgClass"
6628
+ : where == "gutter" ? "gutterClass" : "wrapClass";
6545
6629
  var cur = line[prop];
6546
6630
  if (!cur) return false;
6547
6631
  else if (cls == null) line[prop] = null;
6548
6632
  else {
6549
- var found = cur.match(new RegExp("(?:^|\\s+)" + cls + "(?:$|\\s+)"));
6633
+ var found = cur.match(classTest(cls));
6550
6634
  if (!found) return false;
6551
6635
  var end = found.index + found[0].length;
6552
6636
  line[prop] = cur.slice(0, found.index) + (!found.index || end == cur.length ? "" : " ") + cur.slice(end) || null;
@@ -7165,6 +7249,8 @@
7165
7249
  // registering a (non-DOM) handler on the editor for the event name,
7166
7250
  // and preventDefault-ing the event in that handler.
7167
7251
  function signalDOMEvent(cm, e, override) {
7252
+ if (typeof e == "string")
7253
+ e = {type: e, preventDefault: function() { this.defaultPrevented = true; }};
7168
7254
  signal(cm, override || e.type, cm, e);
7169
7255
  return e_defaultPrevented(e) || e.codemirrorIgnore;
7170
7256
  }
@@ -7338,7 +7424,8 @@
7338
7424
  };
7339
7425
  else range = function(node, start, end) {
7340
7426
  var r = document.body.createTextRange();
7341
- r.moveToElementText(node.parentNode);
7427
+ try { r.moveToElementText(node.parentNode); }
7428
+ catch(e) { return r; }
7342
7429
  r.collapse(true);
7343
7430
  r.moveEnd("character", end);
7344
7431
  r.moveStart("character", start);
@@ -7370,14 +7457,19 @@
7370
7457
  catch(e) { return document.body; }
7371
7458
  };
7372
7459
 
7373
- function classTest(cls) { return new RegExp("\\b" + cls + "\\b\\s*"); }
7374
- function rmClass(node, cls) {
7375
- var test = classTest(cls);
7376
- if (test.test(node.className)) node.className = node.className.replace(test, "");
7377
- }
7378
- function addClass(node, cls) {
7379
- if (!classTest(cls).test(node.className)) node.className += " " + cls;
7380
- }
7460
+ function classTest(cls) { return new RegExp("(^|\\s)" + cls + "(?:$|\\s)\\s*"); }
7461
+ var rmClass = CodeMirror.rmClass = function(node, cls) {
7462
+ var current = node.className;
7463
+ var match = classTest(cls).exec(current);
7464
+ if (match) {
7465
+ var after = current.slice(match.index + match[0].length);
7466
+ node.className = current.slice(0, match.index) + (after ? match[1] + after : "");
7467
+ }
7468
+ };
7469
+ var addClass = CodeMirror.addClass = function(node, cls) {
7470
+ var current = node.className;
7471
+ if (!classTest(cls).test(current)) node.className += (current ? " " : "") + cls;
7472
+ };
7381
7473
  function joinClasses(a, b) {
7382
7474
  var as = a.split(" ");
7383
7475
  for (var i = 0; i < as.length; i++)
@@ -7824,7 +7916,7 @@
7824
7916
 
7825
7917
  // THE END
7826
7918
 
7827
- CodeMirror.version = "4.7.0";
7919
+ CodeMirror.version = "4.8.0";
7828
7920
 
7829
7921
  return CodeMirror;
7830
7922
  });