codemirror-rails 4.0 → 4.1

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 (43) hide show
  1. checksums.yaml +4 -4
  2. data/lib/codemirror/rails/version.rb +2 -2
  3. data/vendor/assets/javascripts/codemirror.js +302 -115
  4. data/vendor/assets/javascripts/codemirror/addons/display/rulers.js +2 -2
  5. data/vendor/assets/javascripts/codemirror/addons/edit/closebrackets.js +35 -18
  6. data/vendor/assets/javascripts/codemirror/addons/edit/matchbrackets.js +18 -9
  7. data/vendor/assets/javascripts/codemirror/addons/hint/css-hint.js +1 -1
  8. data/vendor/assets/javascripts/codemirror/addons/hint/show-hint.js +3 -1
  9. data/vendor/assets/javascripts/codemirror/addons/hint/xml-hint.js +31 -13
  10. data/vendor/assets/javascripts/codemirror/addons/lint/css-lint.js +1 -0
  11. data/vendor/assets/javascripts/codemirror/addons/lint/javascript-lint.js +1 -0
  12. data/vendor/assets/javascripts/codemirror/addons/merge/merge.js +15 -10
  13. data/vendor/assets/javascripts/codemirror/addons/mode/overlay.js +8 -2
  14. data/vendor/assets/javascripts/codemirror/addons/runmode/runmode-standalone.js +1 -0
  15. data/vendor/assets/javascripts/codemirror/addons/runmode/runmode.js +1 -0
  16. data/vendor/assets/javascripts/codemirror/addons/runmode/runmode.node.js +1 -0
  17. data/vendor/assets/javascripts/codemirror/addons/search/search.js +14 -14
  18. data/vendor/assets/javascripts/codemirror/keymaps/sublime.js +14 -2
  19. data/vendor/assets/javascripts/codemirror/keymaps/vim.js +212 -141
  20. data/vendor/assets/javascripts/codemirror/modes/clike.js +4 -5
  21. data/vendor/assets/javascripts/codemirror/modes/css.js +23 -6
  22. data/vendor/assets/javascripts/codemirror/modes/django.js +64 -0
  23. data/vendor/assets/javascripts/codemirror/modes/dylan.js +284 -0
  24. data/vendor/assets/javascripts/codemirror/modes/erlang.js +1 -1
  25. data/vendor/assets/javascripts/codemirror/modes/go.js +1 -0
  26. data/vendor/assets/javascripts/codemirror/modes/haml.js +3 -8
  27. data/vendor/assets/javascripts/codemirror/modes/haxe.js +75 -3
  28. data/vendor/assets/javascripts/codemirror/modes/javascript.js +14 -8
  29. data/vendor/assets/javascripts/codemirror/modes/jinja2.js +111 -35
  30. data/vendor/assets/javascripts/codemirror/modes/livescript.js +4 -4
  31. data/vendor/assets/javascripts/codemirror/modes/markdown.js +5 -2
  32. data/vendor/assets/javascripts/codemirror/modes/php.js +99 -9
  33. data/vendor/assets/javascripts/codemirror/modes/r.js +3 -1
  34. data/vendor/assets/javascripts/codemirror/modes/verilog.js +237 -78
  35. data/vendor/assets/javascripts/codemirror/modes/xml.js +61 -29
  36. data/vendor/assets/stylesheets/codemirror.css +5 -3
  37. data/vendor/assets/stylesheets/codemirror/themes/ambiance.css +0 -1
  38. data/vendor/assets/stylesheets/codemirror/themes/lesser-dark.css +0 -4
  39. data/vendor/assets/stylesheets/codemirror/themes/mdn-like.css +1 -1
  40. data/vendor/assets/stylesheets/codemirror/themes/pastel-on-dark.css +0 -1
  41. data/vendor/assets/stylesheets/codemirror/themes/rubyblue.css +0 -2
  42. data/vendor/assets/stylesheets/codemirror/themes/solarized.css +3 -17
  43. metadata +20 -18
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 7bd8d5f3cb73a14f9ba71c164bfece36e2bca49b
4
- data.tar.gz: 2175fad70b9f62dbd07033563e8026323f2903c2
3
+ metadata.gz: dd16e48b5a4bf97bb9b7d6e9fe4369007477156a
4
+ data.tar.gz: e2cd3b0008e31a240d67416decca66fde5d62ec5
5
5
  SHA512:
6
- metadata.gz: 879221d705829f88de678fd2f1f43e3b871ed0558641dadc9fa05b670e1758e15f0082bed65956667d526e859a2187e5a4507826b686aa94bf7fad5684ccdbbf
7
- data.tar.gz: 32321a4e855066e5b82d47b34b6b89ce26362d9ae656b4f62b4d24032cf92e4435f55aca7027b0229b6613c55e4f2704b4572416edf0a16dd8a2a62f6a8cece3
6
+ metadata.gz: 1a4dbd28831a7db000009ca3abf95ecda5f30352e637c49b26936ea258fbb9f5f8f2a2d0ef086bb4b5aff3c69211253985b47205e289365e02838dfa3900e020
7
+ data.tar.gz: 1006bd816e052f66e24cbfb00ac4500aca09d043b772880cd7b8445072f129fd27208a95172d9d53d6466fcf4a6f8b8052c22d62af167fb4c065c88ebb371d70
@@ -1,6 +1,6 @@
1
1
  module Codemirror
2
2
  module Rails
3
- VERSION = '4.0'
4
- CODEMIRROR_VERSION = '4.0'
3
+ VERSION = '4.1'
4
+ CODEMIRROR_VERSION = '4.1'
5
5
  end
6
6
  end
@@ -33,7 +33,6 @@
33
33
  var presto = /Opera\//.test(navigator.userAgent);
34
34
  var safari = /Apple Computer/.test(navigator.vendor);
35
35
  var khtml = /KHTML\//.test(navigator.userAgent);
36
- var mac_geLion = /Mac OS X 1\d\D([7-9]|\d\d)\D/.test(navigator.userAgent);
37
36
  var mac_geMountainLion = /Mac OS X 1\d\D([8-9]|\d\d)\D/.test(navigator.userAgent);
38
37
  var phantom = /PhantomJS/.test(navigator.userAgent);
39
38
 
@@ -63,8 +62,7 @@
63
62
 
64
63
  this.options = options = options || {};
65
64
  // Determine effective options based on given values and defaults.
66
- for (var opt in defaults) if (!options.hasOwnProperty(opt))
67
- options[opt] = defaults[opt];
65
+ copyObj(defaults, options, false);
68
66
  setGuttersForLineNumbers(options);
69
67
 
70
68
  var doc = options.value;
@@ -256,10 +254,10 @@
256
254
 
257
255
  function wrappingChanged(cm) {
258
256
  if (cm.options.lineWrapping) {
259
- cm.display.wrapper.className += " CodeMirror-wrap";
257
+ addClass(cm.display.wrapper, "CodeMirror-wrap");
260
258
  cm.display.sizer.style.minWidth = "";
261
259
  } else {
262
- cm.display.wrapper.className = cm.display.wrapper.className.replace(" CodeMirror-wrap", "");
260
+ rmClass(cm.display.wrapper, "CodeMirror-wrap");
263
261
  findMaxLine(cm);
264
262
  }
265
263
  estimateLineHeights(cm);
@@ -329,9 +327,13 @@
329
327
  }
330
328
  }
331
329
  gutters.style.display = i ? "" : "none";
332
- var width = gutters.offsetWidth;
330
+ updateGutterSpace(cm);
331
+ }
332
+
333
+ function updateGutterSpace(cm) {
334
+ var width = cm.display.gutters.offsetWidth;
333
335
  cm.display.sizer.style.marginLeft = width + "px";
334
- if (i) cm.display.scrollbarH.style.left = cm.options.fixedGutter ? width + "px" : 0;
336
+ cm.display.scrollbarH.style.left = cm.options.fixedGutter ? width + "px" : 0;
335
337
  }
336
338
 
337
339
  // Compute the character length of a line, taking into account
@@ -434,14 +436,18 @@
434
436
  d.gutterFiller.style.width = d.gutters.offsetWidth + "px";
435
437
  } else d.gutterFiller.style.display = "";
436
438
 
437
- if (mac_geLion && scrollbarWidth(d.measure) === 0) {
438
- d.scrollbarV.style.minWidth = d.scrollbarH.style.minHeight = mac_geMountainLion ? "18px" : "12px";
439
- var barMouseDown = function(e) {
440
- if (e_target(e) != d.scrollbarV && e_target(e) != d.scrollbarH)
441
- operation(cm, onMouseDown)(e);
442
- };
443
- on(d.scrollbarV, "mousedown", barMouseDown);
444
- on(d.scrollbarH, "mousedown", barMouseDown);
439
+ if (!cm.state.checkedOverlayScrollbar && measure.clientHeight > 0) {
440
+ if (scrollbarWidth(d.measure) === 0) {
441
+ var w = mac && !mac_geMountainLion ? "12px" : "18px";
442
+ d.scrollbarV.style.minWidth = d.scrollbarH.style.minHeight = w;
443
+ var barMouseDown = function(e) {
444
+ if (e_target(e) != d.scrollbarV && e_target(e) != d.scrollbarH)
445
+ operation(cm, onMouseDown)(e);
446
+ };
447
+ on(d.scrollbarV, "mousedown", barMouseDown);
448
+ on(d.scrollbarH, "mousedown", barMouseDown);
449
+ }
450
+ cm.state.checkedOverlayScrollbar = true;
445
451
  }
446
452
  }
447
453
 
@@ -503,9 +509,7 @@
503
509
  display.lineNumWidth = display.lineNumInnerWidth + padding;
504
510
  display.lineNumChars = display.lineNumInnerWidth ? last.length : -1;
505
511
  display.lineGutter.style.width = display.lineNumWidth + "px";
506
- var width = display.gutters.offsetWidth;
507
- display.scrollbarH.style.left = cm.options.fixedGutter ? width + "px" : 0;
508
- display.sizer.style.marginLeft = width + "px";
512
+ updateGutterSpace(cm);
509
513
  return true;
510
514
  }
511
515
  return false;
@@ -546,6 +550,8 @@
546
550
  updateSelection(cm);
547
551
  setDocumentHeight(cm, barMeasure);
548
552
  updateScrollbars(cm, barMeasure);
553
+ if (webkit && cm.options.lineWrapping)
554
+ checkForWebkitWidthBug(cm, barMeasure); // (Issue #2420)
549
555
  if (first && cm.options.lineWrapping && oldWidth != cm.display.scroller.clientWidth) {
550
556
  forced = true;
551
557
  continue;
@@ -653,6 +659,16 @@
653
659
  cm.display.gutters.style.height = Math.max(measure.docHeight, measure.clientHeight - scrollerCutOff) + "px";
654
660
  }
655
661
 
662
+
663
+ function checkForWebkitWidthBug(cm, measure) {
664
+ // Work around Webkit bug where it sometimes reserves space for a
665
+ // non-existing phantom scrollbar in the scroller (Issue #2420)
666
+ if (cm.display.sizer.offsetWidth + cm.display.gutters.offsetWidth < cm.display.scroller.clientWidth - 1) {
667
+ cm.display.sizer.style.minHeight = cm.display.heightForcer.style.top = "0px";
668
+ cm.display.gutters.style.height = measure.docHeight + "px";
669
+ }
670
+ }
671
+
656
672
  // Read the actual heights of the rendered lines, and update their
657
673
  // stored heights to match.
658
674
  function updateHeightsInViewport(cm) {
@@ -1138,9 +1154,10 @@
1138
1154
 
1139
1155
  doc.sel = sel;
1140
1156
 
1141
- if (doc.cm)
1142
- doc.cm.curOp.updateInput = doc.cm.curOp.selectionChanged =
1143
- doc.cm.curOp.cursorActivity = true;
1157
+ if (doc.cm) {
1158
+ doc.cm.curOp.updateInput = doc.cm.curOp.selectionChanged = true;
1159
+ signalCursorActivity(doc.cm);
1160
+ }
1144
1161
  signalLater(doc, "cursorActivity", doc);
1145
1162
  }
1146
1163
 
@@ -1229,9 +1246,9 @@
1229
1246
  var range = doc.sel.ranges[i];
1230
1247
  var collapsed = range.empty();
1231
1248
  if (collapsed || cm.options.showCursorWhenSelecting)
1232
- updateSelectionCursor(cm, range, curFragment);
1249
+ drawSelectionCursor(cm, range, curFragment);
1233
1250
  if (!collapsed)
1234
- updateSelectionRange(cm, range, selFragment);
1251
+ drawSelectionRange(cm, range, selFragment);
1235
1252
  }
1236
1253
 
1237
1254
  // Move the hidden textarea near the cursor to prevent scrolling artifacts
@@ -1251,7 +1268,7 @@
1251
1268
  }
1252
1269
 
1253
1270
  // Draws a cursor for the given range
1254
- function updateSelectionCursor(cm, range, output) {
1271
+ function drawSelectionCursor(cm, range, output) {
1255
1272
  var pos = cursorCoords(cm, range.head, "div");
1256
1273
 
1257
1274
  var cursor = output.appendChild(elt("div", "\u00a0", "CodeMirror-cursor"));
@@ -1270,13 +1287,15 @@
1270
1287
  }
1271
1288
 
1272
1289
  // Draws the given range as a highlighted selection
1273
- function updateSelectionRange(cm, range, output) {
1290
+ function drawSelectionRange(cm, range, output) {
1274
1291
  var display = cm.display, doc = cm.doc;
1275
1292
  var fragment = document.createDocumentFragment();
1276
1293
  var padding = paddingH(cm.display), leftSide = padding.left, rightSide = display.lineSpace.offsetWidth - padding.right;
1277
1294
 
1278
1295
  function add(left, top, width, bottom) {
1279
1296
  if (top < 0) top = 0;
1297
+ top = Math.round(top);
1298
+ bottom = Math.round(bottom);
1280
1299
  fragment.appendChild(elt("div", null, "CodeMirror-selected", "position: absolute; left: " + left +
1281
1300
  "px; top: " + top + "px; width: " + (width == null ? rightSide - left : width) +
1282
1301
  "px; height: " + (bottom - top) + "px"));
@@ -1372,7 +1391,10 @@
1372
1391
  doc.iter(doc.frontier, Math.min(doc.first + doc.size, cm.display.viewTo + 500), function(line) {
1373
1392
  if (doc.frontier >= cm.display.viewFrom) { // Visible
1374
1393
  var oldStyles = line.styles;
1375
- line.styles = highlightLine(cm, line, state, true);
1394
+ var highlighted = highlightLine(cm, line, state, true);
1395
+ line.styles = highlighted.styles;
1396
+ if (highlighted.classes) line.styleClasses = highlighted.classes;
1397
+ else if (line.styleClasses) line.styleClasses = null;
1376
1398
  var ischange = !oldStyles || oldStyles.length != line.styles.length;
1377
1399
  for (var i = 0; !ischange && i < oldStyles.length; ++i) ischange = oldStyles[i] != line.styles[i];
1378
1400
  if (ischange) regLineChange(cm, doc.frontier, "text");
@@ -1435,8 +1457,9 @@
1435
1457
  if (display.cachedPaddingH) return display.cachedPaddingH;
1436
1458
  var e = removeChildrenAndAdd(display.measure, elt("pre", "x"));
1437
1459
  var style = window.getComputedStyle ? window.getComputedStyle(e) : e.currentStyle;
1438
- return display.cachedPaddingH = {left: parseInt(style.paddingLeft),
1439
- right: parseInt(style.paddingRight)};
1460
+ var data = {left: parseInt(style.paddingLeft), right: parseInt(style.paddingRight)};
1461
+ if (!isNaN(data.left) && !isNaN(data.right)) display.cachedPaddingH = data;
1462
+ return data;
1440
1463
  }
1441
1464
 
1442
1465
  // Ensure the lineView.wrapping.heights array is populated. This is
@@ -1870,7 +1893,7 @@
1870
1893
  updateInput: null, // Whether to reset the input textarea
1871
1894
  typing: false, // Whether this reset should be careful to leave existing text (for compositing)
1872
1895
  changeObjs: null, // Accumulated changes, for firing change events
1873
- cursorActivity: false, // Whether to fire a cursorActivity event
1896
+ cursorActivityHandlers: null, // Set of handlers to fire cursorActivity on
1874
1897
  selectionChanged: false, // Whether the selection needs to be redrawn
1875
1898
  updateMaxLine: false, // Set when the widest line needs to be determined anew
1876
1899
  scrollLeft: null, scrollTop: null, // Intermediate scroll position, not pushed to DOM yet
@@ -1935,13 +1958,12 @@
1935
1958
  delayedCallbacks = null;
1936
1959
  }
1937
1960
  // Fire change events, and delayed event handlers
1938
- if (op.changeObjs) {
1939
- for (var i = 0; i < op.changeObjs.length; i++)
1940
- signal(cm, "change", cm, op.changeObjs[i]);
1961
+ if (op.changeObjs)
1941
1962
  signal(cm, "changes", cm, op.changeObjs);
1942
- }
1943
- if (op.cursorActivity) signal(cm, "cursorActivity", cm);
1944
1963
  if (delayed) for (var i = 0; i < delayed.length; ++i) delayed[i]();
1964
+ if (op.cursorActivityHandlers)
1965
+ for (var i = 0; i < op.cursorActivityHandlers.length; i++)
1966
+ op.cursorActivityHandlers[i](cm);
1945
1967
  }
1946
1968
 
1947
1969
  // Run the given function in an operation
@@ -2204,7 +2226,13 @@
2204
2226
  // possible when it is clear that nothing happened. hasSelection
2205
2227
  // will be the case when there is a lot of text in the textarea,
2206
2228
  // in which case reading its value would be expensive.
2207
- if (!cm.state.focused || hasSelection(input) || isReadOnly(cm) || cm.options.disableInput) return false;
2229
+ if (!cm.state.focused || (hasSelection(input) && !prevInput) || isReadOnly(cm) || cm.options.disableInput)
2230
+ return false;
2231
+ // See paste handler for more on the fakedLastChar kludge
2232
+ if (cm.state.pasteIncoming && cm.state.fakedLastChar) {
2233
+ input.value = input.value.substring(0, input.value.length - 1);
2234
+ cm.state.fakedLastChar = false;
2235
+ }
2208
2236
  var text = input.value;
2209
2237
  // If nothing changed, bail.
2210
2238
  if (text == prevInput && !cm.somethingSelected()) return false;
@@ -2245,12 +2273,18 @@
2245
2273
  if (inserted && !cm.state.pasteIncoming && cm.options.electricChars &&
2246
2274
  cm.options.smartIndent && range.head.ch < 100 &&
2247
2275
  (!i || doc.sel.ranges[i - 1].head.line != range.head.line)) {
2248
- var electric = cm.getModeAt(range.head).electricChars;
2249
- if (electric) for (var j = 0; j < electric.length; j++)
2250
- if (inserted.indexOf(electric.charAt(j)) > -1) {
2276
+ var mode = cm.getModeAt(range.head);
2277
+ if (mode.electricChars) {
2278
+ for (var j = 0; j < mode.electricChars.length; j++)
2279
+ if (inserted.indexOf(mode.electricChars.charAt(j)) > -1) {
2280
+ indentLine(cm, range.head.line, "smart");
2281
+ break;
2282
+ }
2283
+ } else if (mode.electricInput) {
2284
+ var end = changeEnd(changeEvent);
2285
+ if (mode.electricInput.test(getLine(doc, end.line).text.slice(0, end.ch)))
2251
2286
  indentLine(cm, range.head.line, "smart");
2252
- break;
2253
- }
2287
+ }
2254
2288
  }
2255
2289
  }
2256
2290
  ensureCursorVisible(cm);
@@ -2398,21 +2432,48 @@
2398
2432
  fastPoll(cm);
2399
2433
  });
2400
2434
  on(d.input, "paste", function() {
2435
+ // Workaround for webkit bug https://bugs.webkit.org/show_bug.cgi?id=90206
2436
+ // Add a char to the end of textarea before paste occur so that
2437
+ // selection doesn't span to the end of textarea.
2438
+ if (webkit && !cm.state.fakedLastChar && !(new Date - cm.state.lastMiddleDown < 200)) {
2439
+ var start = d.input.selectionStart, end = d.input.selectionEnd;
2440
+ d.input.value += "$";
2441
+ d.input.selectionStart = start;
2442
+ d.input.selectionEnd = end;
2443
+ cm.state.fakedLastChar = true;
2444
+ }
2401
2445
  cm.state.pasteIncoming = true;
2402
2446
  fastPoll(cm);
2403
2447
  });
2404
2448
 
2405
- function prepareCopy(e) {
2406
- if (d.inaccurateSelection) {
2407
- d.prevInput = "";
2408
- d.inaccurateSelection = false;
2409
- d.input.value = cm.getSelection();
2410
- selectInput(d.input);
2449
+ function prepareCopyCut(e) {
2450
+ if (cm.somethingSelected()) {
2451
+ if (d.inaccurateSelection) {
2452
+ d.prevInput = "";
2453
+ d.inaccurateSelection = false;
2454
+ d.input.value = cm.getSelection();
2455
+ selectInput(d.input);
2456
+ }
2457
+ } else {
2458
+ var text = "", ranges = [];
2459
+ for (var i = 0; i < cm.doc.sel.ranges.length; i++) {
2460
+ var line = cm.doc.sel.ranges[i].head.line;
2461
+ var lineRange = {anchor: Pos(line, 0), head: Pos(line + 1, 0)};
2462
+ ranges.push(lineRange);
2463
+ text += cm.getRange(lineRange.anchor, lineRange.head);
2464
+ }
2465
+ if (e.type == "cut") {
2466
+ cm.setSelections(ranges, null, sel_dontScroll);
2467
+ } else {
2468
+ d.prevInput = "";
2469
+ d.input.value = text;
2470
+ selectInput(d.input);
2471
+ }
2411
2472
  }
2412
2473
  if (e.type == "cut") cm.state.cutIncoming = true;
2413
2474
  }
2414
- on(d.input, "cut", prepareCopy);
2415
- on(d.input, "copy", prepareCopy);
2475
+ on(d.input, "cut", prepareCopyCut);
2476
+ on(d.input, "copy", prepareCopyCut);
2416
2477
 
2417
2478
  // Needed to handle Tab key in KHTML
2418
2479
  if (khtml) on(d.sizer, "mouseup", function() {
@@ -2449,7 +2510,7 @@
2449
2510
  var coords = coordsChar(cm, x, y), line;
2450
2511
  if (forRect && coords.xRel == 1 && (line = getLine(cm.doc, coords.line).text).length == coords.ch) {
2451
2512
  var colDiff = countColumn(line, line.length, cm.options.tabSize) - line.length;
2452
- coords = Pos(coords.line, Math.round((x - paddingH(cm.display).left) / charWidth(cm.display)) - colDiff);
2513
+ coords = Pos(coords.line, Math.max(0, Math.round((x - paddingH(cm.display).left) / charWidth(cm.display)) - colDiff));
2453
2514
  }
2454
2515
  return coords;
2455
2516
  }
@@ -2552,7 +2613,7 @@
2552
2613
  e_preventDefault(e);
2553
2614
 
2554
2615
  var ourRange, ourIndex, startSel = doc.sel;
2555
- if (addNew) {
2616
+ if (addNew && !e.shiftKey) {
2556
2617
  ourIndex = doc.sel.contains(start);
2557
2618
  if (ourIndex > -1)
2558
2619
  ourRange = doc.sel.ranges[ourIndex];
@@ -2586,6 +2647,7 @@
2586
2647
  if (!addNew) {
2587
2648
  ourIndex = 0;
2588
2649
  setSelection(doc, new Selection([ourRange], 0), sel_mouse);
2650
+ startSel = doc.sel;
2589
2651
  } else if (ourIndex > -1) {
2590
2652
  replaceOneSelection(doc, ourIndex, ourRange, sel_mouse);
2591
2653
  } else {
@@ -2719,7 +2781,7 @@
2719
2781
  if (signalDOMEvent(cm, e) || eventInWidget(cm.display, e))
2720
2782
  return;
2721
2783
  e_preventDefault(e);
2722
- if (ie_upto10) lastDrop = +new Date;
2784
+ if (ie) lastDrop = +new Date;
2723
2785
  var pos = posFromMouse(cm, e, true), files = e.dataTransfer.files;
2724
2786
  if (!pos || isReadOnly(cm)) return;
2725
2787
  // Might be a file drop, in which case we simply extract the text
@@ -2728,7 +2790,7 @@
2728
2790
  var n = files.length, text = Array(n), read = 0;
2729
2791
  var loadFile = function(file, i) {
2730
2792
  var reader = new FileReader;
2731
- reader.onload = function() {
2793
+ reader.onload = operation(cm, function() {
2732
2794
  text[i] = reader.result;
2733
2795
  if (++read == n) {
2734
2796
  pos = clipPos(cm.doc, pos);
@@ -2736,7 +2798,7 @@
2736
2798
  makeChange(cm.doc, change);
2737
2799
  setSelectionReplaceHistory(cm.doc, simpleSelection(pos, changeEnd(change)));
2738
2800
  }
2739
- };
2801
+ });
2740
2802
  reader.readAsText(file);
2741
2803
  };
2742
2804
  for (var i = 0; i < n; ++i) loadFile(files[i], i);
@@ -2764,7 +2826,7 @@
2764
2826
  }
2765
2827
 
2766
2828
  function onDragStart(cm, e) {
2767
- if (ie_upto10 && (!cm.state.draggingText || +new Date - lastDrop < 100)) { e_stop(e); return; }
2829
+ if (ie && (!cm.state.draggingText || +new Date - lastDrop < 100)) { e_stop(e); return; }
2768
2830
  if (signalDOMEvent(cm, e) || eventInWidget(cm.display, e)) return;
2769
2831
 
2770
2832
  e.dataTransfer.setData("Text", cm.getSelection());
@@ -2999,6 +3061,25 @@
2999
3061
  if (!handled && code == 88 && !hasCopyEvent && (mac ? e.metaKey : e.ctrlKey))
3000
3062
  cm.replaceSelection("", null, "cut");
3001
3063
  }
3064
+
3065
+ // Turn mouse into crosshair when Alt is held on Mac.
3066
+ if (code == 18 && !/\bCodeMirror-crosshair\b/.test(cm.display.lineDiv.className))
3067
+ showCrossHair(cm);
3068
+ }
3069
+
3070
+ function showCrossHair(cm) {
3071
+ var lineDiv = cm.display.lineDiv;
3072
+ addClass(lineDiv, "CodeMirror-crosshair");
3073
+
3074
+ function up(e) {
3075
+ if (e.keyCode == 18 || !e.altKey) {
3076
+ rmClass(lineDiv, "CodeMirror-crosshair");
3077
+ off(document, "keyup", up);
3078
+ off(document, "mouseover", up);
3079
+ }
3080
+ }
3081
+ on(document, "keyup", up);
3082
+ on(document, "mouseover", up);
3002
3083
  }
3003
3084
 
3004
3085
  function onKeyUp(e) {
@@ -3025,9 +3106,11 @@
3025
3106
  if (!cm.state.focused) {
3026
3107
  signal(cm, "focus", cm);
3027
3108
  cm.state.focused = true;
3028
- if (cm.display.wrapper.className.search(/\bCodeMirror-focused\b/) == -1)
3029
- cm.display.wrapper.className += " CodeMirror-focused";
3030
- if (!cm.curOp) {
3109
+ addClass(cm.display.wrapper, "CodeMirror-focused");
3110
+ // The prevInput test prevents this from firing when a context
3111
+ // menu is closed (since the resetInput would kill the
3112
+ // select-all detection hack)
3113
+ if (!cm.curOp && cm.display.selForContextMenu == cm.doc.sel) {
3031
3114
  resetInput(cm);
3032
3115
  if (webkit) setTimeout(bind(resetInput, cm, true), 0); // Issue #1730
3033
3116
  }
@@ -3039,7 +3122,7 @@
3039
3122
  if (cm.state.focused) {
3040
3123
  signal(cm, "blur", cm);
3041
3124
  cm.state.focused = false;
3042
- cm.display.wrapper.className = cm.display.wrapper.className.replace(" CodeMirror-focused", "");
3125
+ rmClass(cm.display.wrapper, "CodeMirror-focused");
3043
3126
  }
3044
3127
  clearInterval(cm.display.blinker);
3045
3128
  setTimeout(function() {if (!cm.state.focused) cm.display.shift = false;}, 150);
@@ -3075,14 +3158,16 @@
3075
3158
  resetInput(cm);
3076
3159
  // Adds "Select all" to context menu in FF
3077
3160
  if (!cm.somethingSelected()) display.input.value = display.prevInput = " ";
3161
+ display.selForContextMenu = cm.doc.sel;
3078
3162
 
3079
3163
  // Select-all will be greyed out if there's nothing to select, so
3080
3164
  // this adds a zero-width space so that we can later check whether
3081
3165
  // it got selected.
3082
3166
  function prepareSelectAllHack() {
3083
3167
  if (display.input.selectionStart != null) {
3084
- var extval = display.input.value = "\u200b" + (cm.somethingSelected() ? display.input.value : "");
3085
- display.prevInput = "\u200b";
3168
+ var selected = cm.somethingSelected();
3169
+ var extval = display.input.value = "\u200b" + (selected ? display.input.value : "");
3170
+ display.prevInput = selected ? "" : "\u200b";
3086
3171
  display.input.selectionStart = 1; display.input.selectionEnd = extval.length;
3087
3172
  }
3088
3173
  }
@@ -3096,8 +3181,8 @@
3096
3181
  if (display.input.selectionStart != null) {
3097
3182
  if (!ie || ie_upto8) prepareSelectAllHack();
3098
3183
  clearTimeout(detectingSelectAll);
3099
- var i = 0, poll = function(){
3100
- if (display.prevInput == "\u200b" && display.input.selectionStart == 0)
3184
+ var i = 0, poll = function() {
3185
+ if (display.selForContextMenu == cm.doc.sel && display.input.selectionStart == 0)
3101
3186
  operation(cm, commands.selectAll)(cm);
3102
3187
  else if (i++ < 10) detectingSelectAll = setTimeout(poll, 500);
3103
3188
  else resetInput(cm);
@@ -3373,7 +3458,7 @@
3373
3458
  }
3374
3459
 
3375
3460
  if (doc.sel.contains(change.from, change.to) > -1)
3376
- cm.curOp.cursorActivity = true;
3461
+ signalCursorActivity(cm);
3377
3462
 
3378
3463
  updateDoc(doc, change, spans, estimateHeight(cm));
3379
3464
 
@@ -3401,13 +3486,17 @@
3401
3486
  else
3402
3487
  regChange(cm, from.line, to.line + 1, lendiff);
3403
3488
 
3404
- if (hasHandler(cm, "change") || hasHandler(cm, "changes"))
3405
- (cm.curOp.changeObjs || (cm.curOp.changeObjs = [])).push({
3489
+ var changesHandler = hasHandler(cm, "changes"), changeHandler = hasHandler(cm, "change");
3490
+ if (changeHandler || changesHandler) {
3491
+ var obj = {
3406
3492
  from: from, to: to,
3407
3493
  text: change.text,
3408
3494
  removed: change.removed,
3409
3495
  origin: change.origin
3410
- });
3496
+ };
3497
+ if (changeHandler) signalLater(cm, "change", cm, obj);
3498
+ if (changesHandler) (cm.curOp.changeObjs || (cm.curOp.changeObjs = [])).push(obj);
3499
+ }
3411
3500
  }
3412
3501
 
3413
3502
  function replaceRange(doc, code, from, to, origin) {
@@ -3613,7 +3702,6 @@
3613
3702
  else no = lineNo(handle);
3614
3703
  if (no == null) return null;
3615
3704
  if (op(line, no)) regLineChange(cm, no, changeType);
3616
- else return null;
3617
3705
  return line;
3618
3706
  }
3619
3707
 
@@ -3826,7 +3914,7 @@
3826
3914
  var stream = new StringStream(line.text, this.options.tabSize);
3827
3915
  while (stream.pos < pos.ch && !stream.eol()) {
3828
3916
  stream.start = stream.pos;
3829
- var style = mode.token(stream, state);
3917
+ var style = readToken(mode, stream, state);
3830
3918
  }
3831
3919
  return {start: stream.start,
3832
3920
  end: stream.pos,
@@ -3839,13 +3927,16 @@
3839
3927
  pos = clipPos(this.doc, pos);
3840
3928
  var styles = getLineStyles(this, getLine(this.doc, pos.line));
3841
3929
  var before = 0, after = (styles.length - 1) / 2, ch = pos.ch;
3842
- if (ch == 0) return styles[2];
3843
- for (;;) {
3930
+ var type;
3931
+ if (ch == 0) type = styles[2];
3932
+ else for (;;) {
3844
3933
  var mid = (before + after) >> 1;
3845
3934
  if ((mid ? styles[mid * 2 - 1] : 0) >= ch) after = mid;
3846
3935
  else if (styles[mid * 2 + 1] < ch) before = mid + 1;
3847
- else return styles[mid * 2 + 2];
3936
+ else { type = styles[mid * 2 + 2]; break; }
3848
3937
  }
3938
+ var cut = type ? type.indexOf("cm-overlay ") : -1;
3939
+ return cut < 0 ? type : cut == 0 ? null : type.slice(0, cut - 1);
3849
3940
  },
3850
3941
 
3851
3942
  getModeAt: function(pos) {
@@ -4098,9 +4189,9 @@
4098
4189
  toggleOverwrite: function(value) {
4099
4190
  if (value != null && value == this.state.overwrite) return;
4100
4191
  if (this.state.overwrite = !this.state.overwrite)
4101
- this.display.cursorDiv.className += " CodeMirror-overwrite";
4192
+ addClass(this.display.cursorDiv, "CodeMirror-overwrite");
4102
4193
  else
4103
- this.display.cursorDiv.className = this.display.cursorDiv.className.replace(" CodeMirror-overwrite", "");
4194
+ rmClass(this.display.cursorDiv, "CodeMirror-overwrite");
4104
4195
 
4105
4196
  signal(this, "overwriteToggle", this, this.state.overwrite);
4106
4197
  },
@@ -4158,8 +4249,10 @@
4158
4249
  refresh: methodOp(function() {
4159
4250
  var oldHeight = this.display.cachedTextHeight;
4160
4251
  regChange(this);
4252
+ this.curOp.forceUpdate = true;
4161
4253
  clearCaches(this);
4162
4254
  this.scrollTo(this.doc.scrollLeft, this.doc.scrollTop);
4255
+ updateGutterSpace(this);
4163
4256
  if (oldHeight == null || Math.abs(oldHeight - textHeight(this.display)) > .5)
4164
4257
  estimateLineHeights(this);
4165
4258
  signal(this, "refresh", this);
@@ -4510,6 +4603,15 @@
4510
4603
  indentMore: function(cm) {cm.indentSelection("add");},
4511
4604
  indentLess: function(cm) {cm.indentSelection("subtract");},
4512
4605
  insertTab: function(cm) {cm.replaceSelection("\t");},
4606
+ insertSoftTab: function(cm) {
4607
+ var spaces = [], ranges = cm.listSelections(), tabSize = cm.options.tabSize;
4608
+ for (var i = 0; i < ranges.length; i++) {
4609
+ var pos = ranges[i].from();
4610
+ var col = countColumn(cm.getLine(pos.line), pos.ch, tabSize);
4611
+ spaces.push(new Array(tabSize - col % tabSize + 1).join(" "));
4612
+ }
4613
+ cm.replaceSelections(spaces);
4614
+ },
4513
4615
  defaultTab: function(cm) {
4514
4616
  if (cm.somethingSelected()) cm.indentSelection("add");
4515
4617
  else cm.execCommand("insertTab");
@@ -4826,6 +4928,7 @@
4826
4928
  }
4827
4929
  if (cm) signalLater(cm, "markerCleared", cm, this);
4828
4930
  if (withOp) endOperation(cm);
4931
+ if (this.parent) this.parent.clear();
4829
4932
  };
4830
4933
 
4831
4934
  // Find the position of the marker in the document. Returns a {from,
@@ -4905,7 +5008,7 @@
4905
5008
  if (doc.cm && !doc.cm.curOp) return operation(doc.cm, markText)(doc, from, to, options, type);
4906
5009
 
4907
5010
  var marker = new TextMarker(doc, type), diff = cmp(from, to);
4908
- if (options) copyObj(options, marker);
5011
+ if (options) copyObj(options, marker, false);
4909
5012
  // Don't connect empty markers unless clearWhenEmpty is false
4910
5013
  if (diff > 0 || diff == 0 && marker.clearWhenEmpty !== false)
4911
5014
  return marker;
@@ -4973,10 +5076,8 @@
4973
5076
  var SharedTextMarker = CodeMirror.SharedTextMarker = function(markers, primary) {
4974
5077
  this.markers = markers;
4975
5078
  this.primary = primary;
4976
- for (var i = 0, me = this; i < markers.length; ++i) {
5079
+ for (var i = 0; i < markers.length; ++i)
4977
5080
  markers[i].parent = this;
4978
- on(markers[i], "clear", function(){me.clear();});
4979
- }
4980
5081
  };
4981
5082
  eventMixin(SharedTextMarker);
4982
5083
 
@@ -5006,6 +5107,37 @@
5006
5107
  return new SharedTextMarker(markers, primary);
5007
5108
  }
5008
5109
 
5110
+ function findSharedMarkers(doc) {
5111
+ return doc.findMarks(Pos(doc.first, 0), doc.clipPos(Pos(doc.lastLine())),
5112
+ function(m) { return m.parent; });
5113
+ }
5114
+
5115
+ function copySharedMarkers(doc, markers) {
5116
+ for (var i = 0; i < markers.length; i++) {
5117
+ var marker = markers[i], pos = marker.find();
5118
+ var mFrom = doc.clipPos(pos.from), mTo = doc.clipPos(pos.to);
5119
+ if (cmp(mFrom, mTo)) {
5120
+ var subMark = markText(doc, mFrom, mTo, marker.primary, marker.primary.type);
5121
+ marker.markers.push(subMark);
5122
+ subMark.parent = marker;
5123
+ }
5124
+ }
5125
+ }
5126
+
5127
+ function detachSharedMarkers(markers) {
5128
+ for (var i = 0; i < markers.length; i++) {
5129
+ var marker = markers[i], linked = [marker.primary.doc];;
5130
+ linkedDocs(marker.primary.doc, function(d) { linked.push(d); });
5131
+ for (var j = 0; j < marker.markers.length; j++) {
5132
+ var subMarker = marker.markers[j];
5133
+ if (indexOf(linked, subMarker.doc) == -1) {
5134
+ subMarker.parent = null;
5135
+ marker.markers.splice(j--, 1);
5136
+ }
5137
+ }
5138
+ }
5139
+ }
5140
+
5009
5141
  // TEXTMARKER SPANS
5010
5142
 
5011
5143
  function MarkedSpan(marker, from, to) {
@@ -5430,13 +5562,41 @@
5430
5562
  detachMarkedSpans(line);
5431
5563
  }
5432
5564
 
5565
+ function extractLineClasses(type, output) {
5566
+ if (type) for (;;) {
5567
+ var lineClass = type.match(/(?:^|\s+)line-(background-)?(\S+)/);
5568
+ if (!lineClass) break;
5569
+ type = type.slice(0, lineClass.index) + type.slice(lineClass.index + lineClass[0].length);
5570
+ var prop = lineClass[1] ? "bgClass" : "textClass";
5571
+ if (output[prop] == null)
5572
+ output[prop] = lineClass[2];
5573
+ else if (!(new RegExp("(?:^|\s)" + lineClass[2] + "(?:$|\s)")).test(output[prop]))
5574
+ output[prop] += " " + lineClass[2];
5575
+ }
5576
+ return type;
5577
+ }
5578
+
5579
+ function callBlankLine(mode, state) {
5580
+ if (mode.blankLine) return mode.blankLine(state);
5581
+ if (!mode.innerMode) return;
5582
+ var inner = CodeMirror.innerMode(mode, state);
5583
+ if (inner.mode.blankLine) return inner.mode.blankLine(inner.state);
5584
+ }
5585
+
5586
+ function readToken(mode, stream, state) {
5587
+ var style = mode.token(stream, state);
5588
+ if (stream.pos <= stream.start)
5589
+ throw new Error("Mode " + mode.name + " failed to advance stream.");
5590
+ return style;
5591
+ }
5592
+
5433
5593
  // Run the given mode's parser over a line, calling f for each token.
5434
- function runMode(cm, text, mode, state, f, forceToEnd) {
5594
+ function runMode(cm, text, mode, state, f, lineClasses, forceToEnd) {
5435
5595
  var flattenSpans = mode.flattenSpans;
5436
5596
  if (flattenSpans == null) flattenSpans = cm.options.flattenSpans;
5437
5597
  var curStart = 0, curStyle = null;
5438
5598
  var stream = new StringStream(text, cm.options.tabSize), style;
5439
- if (text == "" && mode.blankLine) mode.blankLine(state);
5599
+ if (text == "") extractLineClasses(callBlankLine(mode, state), lineClasses);
5440
5600
  while (!stream.eol()) {
5441
5601
  if (stream.pos > cm.options.maxHighlightLength) {
5442
5602
  flattenSpans = false;
@@ -5444,7 +5604,7 @@
5444
5604
  stream.pos = text.length;
5445
5605
  style = null;
5446
5606
  } else {
5447
- style = mode.token(stream, state);
5607
+ style = extractLineClasses(readToken(mode, stream, state), lineClasses);
5448
5608
  }
5449
5609
  if (cm.options.addModeClass) {
5450
5610
  var mName = CodeMirror.innerMode(mode, state).mode.name;
@@ -5471,11 +5631,11 @@
5471
5631
  function highlightLine(cm, line, state, forceToEnd) {
5472
5632
  // A styles array always starts with a number identifying the
5473
5633
  // mode/overlays that it is based on (for easy invalidation).
5474
- var st = [cm.state.modeGen];
5634
+ var st = [cm.state.modeGen], lineClasses = {};
5475
5635
  // Compute the base array of styles
5476
5636
  runMode(cm, line.text, cm.doc.mode, state, function(end, style) {
5477
5637
  st.push(end, style);
5478
- }, forceToEnd);
5638
+ }, lineClasses, forceToEnd);
5479
5639
 
5480
5640
  // Run overlays, adjust style array.
5481
5641
  for (var o = 0; o < cm.state.overlays.length; ++o) {
@@ -5492,23 +5652,27 @@
5492
5652
  }
5493
5653
  if (!style) return;
5494
5654
  if (overlay.opaque) {
5495
- st.splice(start, i - start, end, style);
5655
+ st.splice(start, i - start, end, "cm-overlay " + style);
5496
5656
  i = start + 2;
5497
5657
  } else {
5498
5658
  for (; start < i; start += 2) {
5499
5659
  var cur = st[start+1];
5500
- st[start+1] = cur ? cur + " " + style : style;
5660
+ st[start+1] = (cur ? cur + " " : "") + "cm-overlay " + style;
5501
5661
  }
5502
5662
  }
5503
- });
5663
+ }, lineClasses);
5504
5664
  }
5505
5665
 
5506
- return st;
5666
+ return {styles: st, classes: lineClasses.bgClass || lineClasses.textClass ? lineClasses : null};
5507
5667
  }
5508
5668
 
5509
5669
  function getLineStyles(cm, line) {
5510
- if (!line.styles || line.styles[0] != cm.state.modeGen)
5511
- line.styles = highlightLine(cm, line, line.stateAfter = getStateBefore(cm, lineNo(line)));
5670
+ if (!line.styles || line.styles[0] != cm.state.modeGen) {
5671
+ var result = highlightLine(cm, line, line.stateAfter = getStateBefore(cm, lineNo(line)));
5672
+ line.styles = result.styles;
5673
+ if (result.classes) line.styleClasses = result.classes;
5674
+ else if (line.styleClasses) line.styleClasses = null;
5675
+ }
5512
5676
  return line.styles;
5513
5677
  }
5514
5678
 
@@ -5519,9 +5683,9 @@
5519
5683
  var mode = cm.doc.mode;
5520
5684
  var stream = new StringStream(text, cm.options.tabSize);
5521
5685
  stream.start = stream.pos = startAt || 0;
5522
- if (text == "" && mode.blankLine) mode.blankLine(state);
5686
+ if (text == "") callBlankLine(mode, state);
5523
5687
  while (!stream.eol() && stream.pos <= cm.options.maxHighlightLength) {
5524
- mode.token(stream, state);
5688
+ readToken(mode, stream, state);
5525
5689
  stream.start = stream.pos;
5526
5690
  }
5527
5691
  }
@@ -5530,20 +5694,9 @@
5530
5694
  // containing one or more styles) to a CSS style. This is cached,
5531
5695
  // and also looks for line-wide styles.
5532
5696
  var styleToClassCache = {}, styleToClassCacheWithMode = {};
5533
- function interpretTokenStyle(style, builder) {
5534
- if (!style) return null;
5535
- for (;;) {
5536
- var lineClass = style.match(/(?:^|\s+)line-(background-)?(\S+)/);
5537
- if (!lineClass) break;
5538
- style = style.slice(0, lineClass.index) + style.slice(lineClass.index + lineClass[0].length);
5539
- var prop = lineClass[1] ? "bgClass" : "textClass";
5540
- if (builder[prop] == null)
5541
- builder[prop] = lineClass[2];
5542
- else if (!(new RegExp("(?:^|\s)" + lineClass[2] + "(?:$|\s)")).test(builder[prop]))
5543
- builder[prop] += " " + lineClass[2];
5544
- }
5545
- if (/^\s*$/.test(style)) return null;
5546
- var cache = builder.cm.options.addModeClass ? styleToClassCacheWithMode : styleToClassCache;
5697
+ function interpretTokenStyle(style, options) {
5698
+ if (!style || /^\s*$/.test(style)) return null;
5699
+ var cache = options.addModeClass ? styleToClassCacheWithMode : styleToClassCache;
5547
5700
  return cache[style] ||
5548
5701
  (cache[style] = style.replace(/\S+/g, "cm-$&"));
5549
5702
  }
@@ -5574,6 +5727,12 @@
5574
5727
  builder.addToken = buildTokenBadBidi(builder.addToken, order);
5575
5728
  builder.map = [];
5576
5729
  insertLineContent(line, builder, getLineStyles(cm, line));
5730
+ if (line.styleClasses) {
5731
+ if (line.styleClasses.bgClass)
5732
+ builder.bgClass = joinClasses(line.styleClasses.bgClass, builder.bgClass || "");
5733
+ if (line.styleClasses.textClass)
5734
+ builder.textClass = joinClasses(line.styleClasses.textClass, builder.textClass || "");
5735
+ }
5577
5736
 
5578
5737
  // Ensure at least a single node is present, for measuring.
5579
5738
  if (builder.map.length == 0)
@@ -5699,7 +5858,7 @@
5699
5858
  var spans = line.markedSpans, allText = line.text, at = 0;
5700
5859
  if (!spans) {
5701
5860
  for (var i = 1; i < styles.length; i+=2)
5702
- builder.addToken(builder, allText.slice(at, at = styles[i]), interpretTokenStyle(styles[i+1], builder));
5861
+ builder.addToken(builder, allText.slice(at, at = styles[i]), interpretTokenStyle(styles[i+1], builder.cm.options));
5703
5862
  return;
5704
5863
  }
5705
5864
 
@@ -5749,7 +5908,7 @@
5749
5908
  spanStartStyle = "";
5750
5909
  }
5751
5910
  text = allText.slice(at, at = styles[i++]);
5752
- style = interpretTokenStyle(styles[i++], builder);
5911
+ style = interpretTokenStyle(styles[i++], builder.cm.options);
5753
5912
  }
5754
5913
  }
5755
5914
  }
@@ -6101,13 +6260,13 @@
6101
6260
  }
6102
6261
  return parts;
6103
6262
  },
6104
- replaceSelection: docMethodOp(function(code, collapse, origin) {
6263
+ replaceSelection: function(code, collapse, origin) {
6105
6264
  var dup = [];
6106
6265
  for (var i = 0; i < this.sel.ranges.length; i++)
6107
6266
  dup[i] = code;
6108
6267
  this.replaceSelections(dup, collapse, origin || "+input");
6109
- }),
6110
- replaceSelections: function(code, collapse, origin) {
6268
+ },
6269
+ replaceSelections: docMethodOp(function(code, collapse, origin) {
6111
6270
  var changes = [], sel = this.sel;
6112
6271
  for (var i = 0; i < sel.ranges.length; i++) {
6113
6272
  var range = sel.ranges[i];
@@ -6118,7 +6277,7 @@
6118
6277
  makeChange(this, changes[i]);
6119
6278
  if (newSel) setSelectionReplaceHistory(this, newSel);
6120
6279
  else if (this.cm) ensureCursorVisible(this.cm);
6121
- },
6280
+ }),
6122
6281
  undo: docMethodOp(function() {makeChangeFromHistory(this, "undo");}),
6123
6282
  redo: docMethodOp(function() {makeChangeFromHistory(this, "redo");}),
6124
6283
  undoSelection: docMethodOp(function() {makeChangeFromHistory(this, "undo", true);}),
@@ -6178,7 +6337,7 @@
6178
6337
  }
6179
6338
  return markers;
6180
6339
  },
6181
- findMarks: function(from, to) {
6340
+ findMarks: function(from, to, filter) {
6182
6341
  from = clipPos(this, from); to = clipPos(this, to);
6183
6342
  var found = [], lineNo = from.line;
6184
6343
  this.iter(from.line, to.line + 1, function(line) {
@@ -6187,7 +6346,8 @@
6187
6346
  var span = spans[i];
6188
6347
  if (!(lineNo == from.line && from.ch > span.to ||
6189
6348
  span.from == null && lineNo != from.line||
6190
- lineNo == to.line && span.from > to.ch))
6349
+ lineNo == to.line && span.from > to.ch) &&
6350
+ (!filter || filter(span.marker)))
6191
6351
  found.push(span.marker.parent || span.marker);
6192
6352
  }
6193
6353
  ++lineNo;
@@ -6245,6 +6405,7 @@
6245
6405
  if (options.sharedHist) copy.history = this.history;
6246
6406
  (this.linked || (this.linked = [])).push({doc: copy, sharedHist: options.sharedHist});
6247
6407
  copy.linked = [{doc: this, isParent: true, sharedHist: options.sharedHist}];
6408
+ copySharedMarkers(copy, findSharedMarkers(this));
6248
6409
  return copy;
6249
6410
  },
6250
6411
  unlinkDoc: function(other) {
@@ -6254,6 +6415,7 @@
6254
6415
  if (link.doc != other) continue;
6255
6416
  this.linked.splice(i, 1);
6256
6417
  other.unlinkDoc(this);
6418
+ detachSharedMarkers(findSharedMarkers(this));
6257
6419
  break;
6258
6420
  }
6259
6421
  // If the histories were shared, split them again
@@ -6765,6 +6927,14 @@
6765
6927
  return e_defaultPrevented(e) || e.codemirrorIgnore;
6766
6928
  }
6767
6929
 
6930
+ function signalCursorActivity(cm) {
6931
+ var arr = cm._handlers && cm._handlers.cursorActivity;
6932
+ if (!arr) return;
6933
+ var set = cm.curOp.cursorActivityHandlers || (cm.curOp.cursorActivityHandlers = []);
6934
+ for (var i = 0; i < arr.length; ++i) if (indexOf(set, arr[i]) == -1)
6935
+ set.push(arr[i]);
6936
+ }
6937
+
6768
6938
  function hasHandler(emitter, type) {
6769
6939
  var arr = emitter._handlers && emitter._handlers[type];
6770
6940
  return arr && arr.length > 0;
@@ -6869,9 +7039,11 @@
6869
7039
  return inst;
6870
7040
  };
6871
7041
 
6872
- function copyObj(obj, target) {
7042
+ function copyObj(obj, target, overwrite) {
6873
7043
  if (!target) target = {};
6874
- for (var prop in obj) if (obj.hasOwnProperty(prop)) target[prop] = obj[prop];
7044
+ for (var prop in obj)
7045
+ if (obj.hasOwnProperty(prop) && (overwrite !== false || !target.hasOwnProperty(prop)))
7046
+ target[prop] = obj[prop];
6875
7047
  return target;
6876
7048
  }
6877
7049
 
@@ -6951,6 +7123,21 @@
6951
7123
  catch(e) { return document.body; }
6952
7124
  };
6953
7125
 
7126
+ function classTest(cls) { return new RegExp("\\b" + cls + "\\b\\s*"); }
7127
+ function rmClass(node, cls) {
7128
+ var test = classTest(cls);
7129
+ if (test.test(node.className)) node.className = node.className.replace(test, "");
7130
+ }
7131
+ function addClass(node, cls) {
7132
+ if (!classTest(cls).test(node.className)) node.className += " " + cls;
7133
+ }
7134
+ function joinClasses(a, b) {
7135
+ var as = a.split(" ");
7136
+ for (var i = 0; i < as.length; i++)
7137
+ if (as[i] && !classTest(as[i]).test(b)) b += " " + as[i];
7138
+ return b;
7139
+ }
7140
+
6954
7141
  // FEATURE DETECTION
6955
7142
 
6956
7143
  // Detect drag-and-drop
@@ -7333,7 +7520,7 @@
7333
7520
 
7334
7521
  // THE END
7335
7522
 
7336
- CodeMirror.version = "4.0.3";
7523
+ CodeMirror.version = "4.1.0";
7337
7524
 
7338
7525
  return CodeMirror;
7339
7526
  });