codemirror-rails 2.33 → 2.34

Sign up to get free protection for your applications and to get access to all the features.
Files changed (25) hide show
  1. data/lib/codemirror/rails/version.rb +2 -2
  2. data/vendor/assets/javascripts/codemirror.js +359 -453
  3. data/vendor/assets/javascripts/codemirror/keymaps/vim.js +4 -1
  4. data/vendor/assets/javascripts/codemirror/modes/clojure.js +7 -8
  5. data/vendor/assets/javascripts/codemirror/modes/commonlisp.js +101 -0
  6. data/vendor/assets/javascripts/codemirror/modes/css.js +336 -62
  7. data/vendor/assets/javascripts/codemirror/modes/gfm.js +6 -1
  8. data/vendor/assets/javascripts/codemirror/modes/haxe.js +0 -3
  9. data/vendor/assets/javascripts/codemirror/modes/htmlembedded.js +5 -1
  10. data/vendor/assets/javascripts/codemirror/modes/htmlmixed.js +11 -12
  11. data/vendor/assets/javascripts/codemirror/modes/javascript.js +1 -1
  12. data/vendor/assets/javascripts/codemirror/modes/markdown.js +131 -17
  13. data/vendor/assets/javascripts/codemirror/modes/php.js +4 -6
  14. data/vendor/assets/javascripts/codemirror/modes/shell.js +1 -1
  15. data/vendor/assets/javascripts/codemirror/modes/tiki.js +0 -7
  16. data/vendor/assets/javascripts/codemirror/modes/vb.js +2 -2
  17. data/vendor/assets/javascripts/codemirror/modes/xml.js +0 -8
  18. data/vendor/assets/javascripts/codemirror/utils/closetag.js +35 -35
  19. data/vendor/assets/javascripts/codemirror/utils/formatting.js +147 -253
  20. data/vendor/assets/javascripts/codemirror/utils/multiplex.js +4 -8
  21. data/vendor/assets/javascripts/codemirror/utils/overlay.js +3 -1
  22. data/vendor/assets/javascripts/codemirror/utils/runmode-standalone.js +90 -0
  23. data/vendor/assets/javascripts/codemirror/utils/simple-hint.js +1 -1
  24. data/vendor/assets/stylesheets/codemirror.css +2 -2
  25. metadata +14 -12
@@ -1,6 +1,6 @@
1
1
  module Codemirror
2
2
  module Rails
3
- VERSION = '2.33'
4
- CODEMIRROR_VERSION = '2.33'
3
+ VERSION = '2.34'
4
+ CODEMIRROR_VERSION = '2.34'
5
5
  end
6
6
  end
@@ -1,5 +1,5 @@
1
- // CodeMirror version 2.33
2
- //
1
+ // CodeMirror version 2.34
2
+
3
3
  // All functions that need access to the editor's state live inside
4
4
  // the CodeMirror function. Below that, at the bottom of the file,
5
5
  // some utilities are defined.
@@ -62,22 +62,13 @@ window.CodeMirror = (function() {
62
62
  // Need to set a minimum width to see the scrollbar on IE7 (but must not set it on IE8).
63
63
  else if (ie_lt8) scrollbar.style.minWidth = "18px";
64
64
 
65
- // Check for problem with IE innerHTML not working when we have a
66
- // P (or similar) parent node.
67
- try { charWidth(); }
68
- catch (e) {
69
- if (e.message.match(/runtime/i))
70
- e = new Error("A CodeMirror inside a P-style element does not work in Internet Explorer. (innerHTML bug)");
71
- throw e;
72
- }
73
-
74
65
  // Delayed object wrap timeouts, making sure only one is active. blinker holds an interval.
75
66
  var poll = new Delayed(), highlight = new Delayed(), blinker;
76
67
 
77
68
  // mode holds a mode API object. doc is the tree of Line objects,
78
- // work an array of lines that should be parsed, and history the
79
- // undo history (instance of History constructor).
80
- var mode, doc = new BranchChunk([new LeafChunk([new Line("")])]), work, focused;
69
+ // frontier is the point up to which the content has been parsed,
70
+ // and history the undo history (instance of History constructor).
71
+ var mode, doc = new BranchChunk([new LeafChunk([new Line("")])]), frontier = 0, focused;
81
72
  loadMode();
82
73
  // The selection. These are always maintained to point at valid
83
74
  // positions. Inverted is used to remember that the user is
@@ -89,7 +80,7 @@ window.CodeMirror = (function() {
89
80
  overwrite = false, suppressEdits = false;
90
81
  // Variables used by startOperation/endOperation to track what
91
82
  // happened during the operation.
92
- var updateInput, userSelChange, changes, textChanged, selectionChanged, leaveInputAlone,
83
+ var updateInput, userSelChange, changes, textChanged, selectionChanged,
93
84
  gutterDirty, callbacks;
94
85
  // Current visible range (may be bigger than the view window).
95
86
  var displayOffset = 0, showingFrom = 0, showingTo = 0, lastSizeC = 0;
@@ -99,7 +90,6 @@ window.CodeMirror = (function() {
99
90
  // Tracks the maximum line length so that the horizontal scrollbar
100
91
  // can be kept static when scrolling.
101
92
  var maxLine = getLine(0), updateMaxLine = false, maxLineChanged = true;
102
- var tabCache = {};
103
93
  var pollingFast = false; // Ensures slowPoll doesn't cancel fastPoll
104
94
  var goalColumn = null;
105
95
 
@@ -186,6 +176,7 @@ window.CodeMirror = (function() {
186
176
  }
187
177
  },
188
178
  getOption: function(option) {return options[option];},
179
+ getMode: function() {return mode;},
189
180
  undo: operation(undo),
190
181
  redo: operation(redo),
191
182
  indentLine: operation(function(n, dir) {
@@ -204,8 +195,18 @@ window.CodeMirror = (function() {
204
195
  history.undone = histData.undone;
205
196
  },
206
197
  getHistory: function() {
207
- history.time = 0;
208
- return {done: history.done.concat([]), undone: history.undone.concat([])};
198
+ function cp(arr) {
199
+ for (var i = 0, nw = [], nwelt; i < arr.length; ++i) {
200
+ nw.push(nwelt = []);
201
+ for (var j = 0, elt = arr[i]; j < elt.length; ++j) {
202
+ var old = [], cur = elt[j];
203
+ nwelt.push({start: cur.start, added: cur.added, old: old});
204
+ for (var k = 0; k < cur.old.length; ++k) old.push(hlText(cur.old[k]));
205
+ }
206
+ }
207
+ return nw;
208
+ }
209
+ return {done: cp(history.done), undone: cp(history.undone)};
209
210
  },
210
211
  matchBrackets: operation(function(){matchBrackets(true);}),
211
212
  getTokenAt: operation(function(pos) {
@@ -374,6 +375,12 @@ window.CodeMirror = (function() {
374
375
  for (var n = line; n; n = n.parent) n.height += diff;
375
376
  }
376
377
 
378
+ function lineContent(line, wrapAt) {
379
+ if (!line.styles)
380
+ line.highlight(mode, line.stateAfter = getStateBefore(lineNo(line)), options.tabSize);
381
+ return line.getContent(options.tabSize, wrapAt, options.lineWrapping);
382
+ }
383
+
377
384
  function setValue(code) {
378
385
  var top = {line: 0, ch: 0};
379
386
  updateLines(top, {line: doc.size - 1, ch: getLine(doc.size-1).text.length},
@@ -572,11 +579,8 @@ window.CodeMirror = (function() {
572
579
  e.dataTransfer.setData("Text", txt);
573
580
 
574
581
  // Use dummy image instead of default browsers image.
575
- if (gecko || chrome || opera) {
576
- var img = elt('img');
577
- img.scr = 'data:image/gif;base64,R0lGODdhAgACAIAAAAAAAP///ywAAAAAAgACAAACAoRRADs='; //1x1 image
578
- e.dataTransfer.setDragImage(img, 0, 0);
579
- }
582
+ if (e.dataTransfer.setDragImage)
583
+ e.dataTransfer.setDragImage(elt('img'), 0, 0);
580
584
  }
581
585
 
582
586
  function doHandleBinding(bound, dropShift) {
@@ -610,10 +614,11 @@ window.CodeMirror = (function() {
610
614
  }, 50);
611
615
 
612
616
  var name = keyNames[e_prop(e, "keyCode")], handled = false;
617
+ var flipCtrlCmd = opera && mac;
613
618
  if (name == null || e.altGraphKey) return false;
614
619
  if (e_prop(e, "altKey")) name = "Alt-" + name;
615
- if (e_prop(e, "ctrlKey")) name = "Ctrl-" + name;
616
- if (e_prop(e, "metaKey")) name = "Cmd-" + name;
620
+ if (e_prop(e, flipCtrlCmd ? "metaKey" : "ctrlKey")) name = "Ctrl-" + name;
621
+ if (e_prop(e, flipCtrlCmd ? "ctrlKey" : "metaKey")) name = "Cmd-" + name;
617
622
 
618
623
  var stopped = false;
619
624
  function stop() { stopped = true; }
@@ -689,7 +694,6 @@ window.CodeMirror = (function() {
689
694
  focused = true;
690
695
  if (scroller.className.search(/\bCodeMirror-focused\b/) == -1)
691
696
  scroller.className += " CodeMirror-focused";
692
- if (!leaveInputAlone) resetInput(true);
693
697
  }
694
698
  slowPoll();
695
699
  restartBlink();
@@ -712,13 +716,16 @@ window.CodeMirror = (function() {
712
716
  // Afterwards, set the selection to selFrom, selTo.
713
717
  function updateLines(from, to, newText, selFrom, selTo) {
714
718
  if (suppressEdits) return;
719
+ var old = [];
720
+ doc.iter(from.line, to.line + 1, function(line) {
721
+ old.push(newHL(line.text, line.markedSpans));
722
+ });
715
723
  if (history) {
716
- var old = [];
717
- doc.iter(from.line, to.line + 1, function(line) { old.push(line.text); });
718
724
  history.addChange(from.line, newText.length, old);
719
725
  while (history.done.length > options.undoDepth) history.done.shift();
720
726
  }
721
- updateLinesNoUndo(from, to, newText, selFrom, selTo);
727
+ var lines = updateMarkedSpans(hlSpans(old[0]), hlSpans(lst(old)), from.ch, to.ch, newText);
728
+ updateLinesNoUndo(from, to, lines, selFrom, selTo);
722
729
  }
723
730
  function unredoHelper(from, to) {
724
731
  if (!from.length) return;
@@ -726,11 +733,12 @@ window.CodeMirror = (function() {
726
733
  for (var i = set.length - 1; i >= 0; i -= 1) {
727
734
  var change = set[i];
728
735
  var replaced = [], end = change.start + change.added;
729
- doc.iter(change.start, end, function(line) { replaced.push(line.text); });
736
+ doc.iter(change.start, end, function(line) { replaced.push(newHL(line.text, line.markedSpans)); });
730
737
  out.push({start: change.start, added: change.old.length, old: replaced});
731
738
  var pos = {line: change.start + change.old.length - 1,
732
- ch: editEnd(replaced[replaced.length-1], change.old[change.old.length-1])};
733
- updateLinesNoUndo({line: change.start, ch: 0}, {line: end - 1, ch: getLine(end-1).text.length}, change.old, pos, pos);
739
+ ch: editEnd(hlText(lst(replaced)), hlText(lst(change.old)))};
740
+ updateLinesNoUndo({line: change.start, ch: 0}, {line: end - 1, ch: getLine(end-1).text.length},
741
+ change.old, pos, pos);
734
742
  }
735
743
  updateInput = true;
736
744
  to.push(out);
@@ -738,66 +746,59 @@ window.CodeMirror = (function() {
738
746
  function undo() {unredoHelper(history.done, history.undone);}
739
747
  function redo() {unredoHelper(history.undone, history.done);}
740
748
 
741
- function updateLinesNoUndo(from, to, newText, selFrom, selTo) {
749
+ function updateLinesNoUndo(from, to, lines, selFrom, selTo) {
742
750
  if (suppressEdits) return;
743
751
  var recomputeMaxLength = false, maxLineLength = maxLine.text.length;
744
752
  if (!options.lineWrapping)
745
753
  doc.iter(from.line, to.line + 1, function(line) {
746
754
  if (!line.hidden && line.text.length == maxLineLength) {recomputeMaxLength = true; return true;}
747
755
  });
748
- if (from.line != to.line || newText.length > 1) gutterDirty = true;
756
+ if (from.line != to.line || lines.length > 1) gutterDirty = true;
749
757
 
750
758
  var nlines = to.line - from.line, firstLine = getLine(from.line), lastLine = getLine(to.line);
751
- // First adjust the line structure, taking some care to leave highlighting intact.
752
- if (from.ch == 0 && to.ch == 0 && newText[newText.length - 1] == "") {
759
+ var lastHL = lst(lines);
760
+
761
+ // First adjust the line structure
762
+ if (from.ch == 0 && to.ch == 0 && hlText(lastHL) == "") {
753
763
  // This is a whole-line replace. Treated specially to make
754
764
  // sure line objects move the way they are supposed to.
755
765
  var added = [], prevLine = null;
756
- if (from.line) {
757
- prevLine = getLine(from.line - 1);
758
- prevLine.fixMarkEnds(lastLine);
759
- } else lastLine.fixMarkStarts();
760
- for (var i = 0, e = newText.length - 1; i < e; ++i)
761
- added.push(Line.inheritMarks(newText[i], prevLine));
766
+ for (var i = 0, e = lines.length - 1; i < e; ++i)
767
+ added.push(new Line(hlText(lines[i]), hlSpans(lines[i])));
768
+ lastLine.update(lastLine.text, hlSpans(lastHL));
762
769
  if (nlines) doc.remove(from.line, nlines, callbacks);
763
770
  if (added.length) doc.insert(from.line, added);
764
771
  } else if (firstLine == lastLine) {
765
- if (newText.length == 1)
766
- firstLine.replace(from.ch, to.ch, newText[0]);
767
- else {
768
- lastLine = firstLine.split(to.ch, newText[newText.length-1]);
769
- firstLine.replace(from.ch, null, newText[0]);
770
- firstLine.fixMarkEnds(lastLine);
771
- var added = [];
772
- for (var i = 1, e = newText.length - 1; i < e; ++i)
773
- added.push(Line.inheritMarks(newText[i], firstLine));
774
- added.push(lastLine);
772
+ if (lines.length == 1) {
773
+ firstLine.update(firstLine.text.slice(0, from.ch) + hlText(lines[0]) + firstLine.text.slice(to.ch), hlSpans(lines[0]));
774
+ } else {
775
+ for (var added = [], i = 1, e = lines.length - 1; i < e; ++i)
776
+ added.push(new Line(hlText(lines[i]), hlSpans(lines[i])));
777
+ added.push(new Line(hlText(lastHL) + firstLine.text.slice(to.ch), hlSpans(lastHL)));
778
+ firstLine.update(firstLine.text.slice(0, from.ch) + hlText(lines[0]), hlSpans(lines[0]));
775
779
  doc.insert(from.line + 1, added);
776
780
  }
777
- } else if (newText.length == 1) {
778
- firstLine.replace(from.ch, null, newText[0]);
779
- lastLine.replace(null, to.ch, "");
780
- firstLine.append(lastLine);
781
+ } else if (lines.length == 1) {
782
+ firstLine.update(firstLine.text.slice(0, from.ch) + hlText(lines[0]) + lastLine.text.slice(to.ch), hlSpans(lines[0]));
781
783
  doc.remove(from.line + 1, nlines, callbacks);
782
784
  } else {
783
785
  var added = [];
784
- firstLine.replace(from.ch, null, newText[0]);
785
- lastLine.replace(null, to.ch, newText[newText.length-1]);
786
- firstLine.fixMarkEnds(lastLine);
787
- for (var i = 1, e = newText.length - 1; i < e; ++i)
788
- added.push(Line.inheritMarks(newText[i], firstLine));
786
+ firstLine.update(firstLine.text.slice(0, from.ch) + hlText(lines[0]), hlSpans(lines[0]));
787
+ lastLine.update(hlText(lastHL) + lastLine.text.slice(to.ch), hlSpans(lastHL));
788
+ for (var i = 1, e = lines.length - 1; i < e; ++i)
789
+ added.push(new Line(hlText(lines[i]), hlSpans(lines[i])));
789
790
  if (nlines > 1) doc.remove(from.line + 1, nlines - 1, callbacks);
790
791
  doc.insert(from.line + 1, added);
791
792
  }
792
793
  if (options.lineWrapping) {
793
794
  var perLine = Math.max(5, scroller.clientWidth / charWidth() - 3);
794
- doc.iter(from.line, from.line + newText.length, function(line) {
795
+ doc.iter(from.line, from.line + lines.length, function(line) {
795
796
  if (line.hidden) return;
796
797
  var guess = Math.ceil(line.text.length / perLine) || 1;
797
798
  if (guess != line.height) updateLineHeight(line, guess);
798
799
  });
799
800
  } else {
800
- doc.iter(from.line, from.line + newText.length, function(line) {
801
+ doc.iter(from.line, from.line + lines.length, function(line) {
801
802
  var l = line.text;
802
803
  if (!line.hidden && l.length > maxLineLength) {
803
804
  maxLine = line; maxLineLength = l.length; maxLineChanged = true;
@@ -807,26 +808,24 @@ window.CodeMirror = (function() {
807
808
  if (recomputeMaxLength) updateMaxLine = true;
808
809
  }
809
810
 
810
- // Add these lines to the work array, so that they will be
811
- // highlighted. Adjust work lines if lines were added/removed.
812
- var newWork = [], lendiff = newText.length - nlines - 1;
813
- for (var i = 0, l = work.length; i < l; ++i) {
814
- var task = work[i];
815
- if (task < from.line) newWork.push(task);
816
- else if (task > to.line) newWork.push(task + lendiff);
817
- }
818
- var hlEnd = from.line + Math.min(newText.length, 500);
819
- highlightLines(from.line, hlEnd);
820
- newWork.push(hlEnd);
821
- work = newWork;
822
- startWorker(100);
811
+ // Adjust frontier, schedule worker
812
+ frontier = Math.min(frontier, from.line);
813
+ startWorker(400);
814
+
815
+ var lendiff = lines.length - nlines - 1;
823
816
  // Remember that these lines changed, for updating the display
824
817
  changes.push({from: from.line, to: to.line + 1, diff: lendiff});
825
- var changeObj = {from: from, to: to, text: newText};
826
- if (textChanged) {
827
- for (var cur = textChanged; cur.next; cur = cur.next) {}
828
- cur.next = changeObj;
829
- } else textChanged = changeObj;
818
+ if (options.onChange) {
819
+ // Normalize lines to contain only strings, since that's what
820
+ // the change event handler expects
821
+ for (var i = 0; i < lines.length; ++i)
822
+ if (typeof lines[i] != "string") lines[i] = lines[i].text;
823
+ var changeObj = {from: from, to: to, text: lines};
824
+ if (textChanged) {
825
+ for (var cur = textChanged; cur.next; cur = cur.next) {}
826
+ cur.next = changeObj;
827
+ } else textChanged = changeObj;
828
+ }
830
829
 
831
830
  // Update the selection
832
831
  function updateLine(n) {return n <= Math.min(to.line, to.line + lendiff) ? n : n + lendiff;}
@@ -888,7 +887,7 @@ window.CodeMirror = (function() {
888
887
  var line = pos.line + code.length - (to.line - from.line) - 1;
889
888
  var ch = pos.ch;
890
889
  if (pos.line == to.line)
891
- ch += code[code.length-1].length - (to.ch - (to.line == from.line ? from.ch : 0));
890
+ ch += lst(code).length - (to.ch - (to.line == from.line ? from.ch : 0));
892
891
  return {line: line, ch: ch};
893
892
  }
894
893
  var end;
@@ -906,7 +905,7 @@ window.CodeMirror = (function() {
906
905
  });
907
906
  }
908
907
  function replaceRange1(code, from, to, computeSel) {
909
- var endch = code.length == 1 ? code[0].length + from.ch : code[code.length-1].length;
908
+ var endch = code.length == 1 ? code[0].length + from.ch : lst(code).length;
910
909
  var newSel = computeSel({line: from.line + code.length - 1, ch: endch});
911
910
  updateLines(from, to, code, newSel.from, newSel.to);
912
911
  }
@@ -926,21 +925,17 @@ window.CodeMirror = (function() {
926
925
  function slowPoll() {
927
926
  if (pollingFast) return;
928
927
  poll.set(options.pollInterval, function() {
929
- startOperation();
930
928
  readInput();
931
929
  if (focused) slowPoll();
932
- endOperation();
933
930
  });
934
931
  }
935
932
  function fastPoll() {
936
933
  var missed = false;
937
934
  pollingFast = true;
938
935
  function p() {
939
- startOperation();
940
936
  var changed = readInput();
941
937
  if (!changed && !missed) {missed = true; poll.set(60, p);}
942
938
  else {pollingFast = false; slowPoll();}
943
- endOperation();
944
939
  }
945
940
  poll.set(20, p);
946
941
  }
@@ -952,9 +947,10 @@ window.CodeMirror = (function() {
952
947
  // supported or compatible enough yet to rely on.)
953
948
  var prevInput = "";
954
949
  function readInput() {
955
- if (leaveInputAlone || !focused || hasSelection(input) || options.readOnly) return false;
950
+ if (!focused || hasSelection(input) || options.readOnly) return false;
956
951
  var text = input.value;
957
952
  if (text == prevInput) return false;
953
+ if (!nestedOperation) startOperation();
958
954
  shiftSelecting = null;
959
955
  var same = 0, l = Math.min(prevInput.length, text.length);
960
956
  while (same < l && prevInput[same] == text[same]) ++same;
@@ -965,6 +961,7 @@ window.CodeMirror = (function() {
965
961
  replaceSelection(text.slice(same), "end");
966
962
  if (text.length > 1000) { input.value = prevInput = ""; }
967
963
  else prevInput = text;
964
+ if (!nestedOperation) endOperation();
968
965
  return true;
969
966
  }
970
967
  function resetInput(user) {
@@ -1090,6 +1087,7 @@ window.CodeMirror = (function() {
1090
1087
  });
1091
1088
  showingFrom = from; showingTo = to;
1092
1089
  displayOffset = heightAtLine(doc, from);
1090
+ startWorker(100);
1093
1091
 
1094
1092
  // Since this is all rather error prone, it is honoured with the
1095
1093
  // only assertion in the whole file.
@@ -1176,7 +1174,7 @@ window.CodeMirror = (function() {
1176
1174
  if (!nextIntact || nextIntact.from > j) {
1177
1175
  if (line.hidden) var lineElement = elt("pre");
1178
1176
  else {
1179
- var lineElement = line.getElement(makeTab);
1177
+ var lineElement = lineContent(line);
1180
1178
  if (line.className) lineElement.className = line.className;
1181
1179
  // Kludge to make sure the styled element lies behind the selection (by z-index)
1182
1180
  if (line.bgClassName) {
@@ -1460,7 +1458,7 @@ window.CodeMirror = (function() {
1460
1458
  var indentString = "", pos = 0;
1461
1459
  if (options.indentWithTabs)
1462
1460
  for (var i = Math.floor(indentation / options.tabSize); i; --i) {pos += options.tabSize; indentString += "\t";}
1463
- while (pos < indentation) {++pos; indentString += " ";}
1461
+ if (pos < indentation) indentString += spaceStr(indentation - pos);
1464
1462
 
1465
1463
  if (indentString != curSpaceString)
1466
1464
  replaceRange(indentString, {line: n, ch: 0}, {line: n, ch: curSpaceString.length});
@@ -1469,8 +1467,8 @@ window.CodeMirror = (function() {
1469
1467
  function loadMode() {
1470
1468
  mode = CodeMirror.getMode(options, options.mode);
1471
1469
  doc.iter(0, doc.size, function(line) { line.stateAfter = null; });
1472
- work = [0];
1473
- startWorker();
1470
+ frontier = 0;
1471
+ startWorker(100);
1474
1472
  }
1475
1473
  function gutterChanged() {
1476
1474
  var visible = options.gutter || options.lineNumbers;
@@ -1497,13 +1495,6 @@ window.CodeMirror = (function() {
1497
1495
  }
1498
1496
  changes.push({from: 0, to: doc.size});
1499
1497
  }
1500
- function makeTab(col) {
1501
- var w = options.tabSize - col % options.tabSize, cached = tabCache[w];
1502
- if (cached) return cached;
1503
- for (var str = "", i = 0; i < w; ++i) str += " ";
1504
- var span = elt("span", str, "cm-tab");
1505
- return (tabCache[w] = {element: span, width: w});
1506
- }
1507
1498
  function themeChanged() {
1508
1499
  scroller.className = scroller.className.replace(/\s*cm-s-\S+/g, "") +
1509
1500
  options.theme.replace(/(^|\s)\s*/g, " cm-s-");
@@ -1514,74 +1505,71 @@ window.CodeMirror = (function() {
1514
1505
  (style ? " cm-keymap-" + style : "");
1515
1506
  }
1516
1507
 
1517
- function TextMarker() { this.set = []; }
1508
+ function TextMarker(type, style) { this.lines = []; this.type = type; if (style) this.style = style; }
1518
1509
  TextMarker.prototype.clear = operation(function() {
1519
1510
  var min = Infinity, max = -Infinity;
1520
- for (var i = 0, e = this.set.length; i < e; ++i) {
1521
- var line = this.set[i], mk = line.marked;
1522
- if (!mk || !line.parent) continue;
1523
- var lineN = lineNo(line);
1524
- min = Math.min(min, lineN); max = Math.max(max, lineN);
1525
- for (var j = 0; j < mk.length; ++j)
1526
- if (mk[j].marker == this) mk.splice(j--, 1);
1511
+ for (var i = 0; i < this.lines.length; ++i) {
1512
+ var line = this.lines[i];
1513
+ var span = getMarkedSpanFor(line.markedSpans, this, true);
1514
+ if (span.from != null || span.to != null) {
1515
+ var lineN = lineNo(line);
1516
+ min = Math.min(min, lineN); max = Math.max(max, lineN);
1517
+ }
1527
1518
  }
1528
1519
  if (min != Infinity)
1529
1520
  changes.push({from: min, to: max + 1});
1521
+ this.lines.length = 0;
1530
1522
  });
1531
1523
  TextMarker.prototype.find = function() {
1532
1524
  var from, to;
1533
- for (var i = 0, e = this.set.length; i < e; ++i) {
1534
- var line = this.set[i], mk = line.marked;
1535
- for (var j = 0; j < mk.length; ++j) {
1536
- var mark = mk[j];
1537
- if (mark.marker == this) {
1538
- if (mark.from != null || mark.to != null) {
1539
- var found = lineNo(line);
1540
- if (found != null) {
1541
- if (mark.from != null) from = {line: found, ch: mark.from};
1542
- if (mark.to != null) to = {line: found, ch: mark.to};
1543
- }
1544
- }
1545
- }
1525
+ for (var i = 0; i < this.lines.length; ++i) {
1526
+ var line = this.lines[i];
1527
+ var span = getMarkedSpanFor(line.markedSpans, this);
1528
+ if (span.from != null || span.to != null) {
1529
+ var found = lineNo(line);
1530
+ if (span.from != null) from = {line: found, ch: span.from};
1531
+ if (span.to != null) to = {line: found, ch: span.to};
1546
1532
  }
1547
1533
  }
1548
- return {from: from, to: to};
1534
+ if (this.type == "bookmark") return from;
1535
+ return from && {from: from, to: to};
1549
1536
  };
1550
1537
 
1551
- function markText(from, to, className) {
1538
+ function markText(from, to, className, options) {
1552
1539
  from = clipPos(from); to = clipPos(to);
1553
- var tm = new TextMarker();
1554
- if (!posLess(from, to)) return tm;
1555
- function add(line, from, to, className) {
1556
- getLine(line).addMark(new MarkedText(from, to, className, tm));
1557
- }
1558
- if (from.line == to.line) add(from.line, from.ch, to.ch, className);
1559
- else {
1560
- add(from.line, from.ch, null, className);
1561
- for (var i = from.line + 1, e = to.line; i < e; ++i)
1562
- add(i, null, null, className);
1563
- add(to.line, null, to.ch, className);
1564
- }
1540
+ var marker = new TextMarker("range", className);
1541
+ if (options) for (var opt in options) if (options.hasOwnProperty(opt))
1542
+ marker[opt] = options[opt];
1543
+ var curLine = from.line;
1544
+ doc.iter(curLine, to.line + 1, function(line) {
1545
+ var span = {from: curLine == from.line ? from.ch : null,
1546
+ to: curLine == to.line ? to.ch : null,
1547
+ marker: marker};
1548
+ (line.markedSpans || (line.markedSpans = [])).push(span);
1549
+ marker.lines.push(line);
1550
+ ++curLine;
1551
+ });
1565
1552
  changes.push({from: from.line, to: to.line + 1});
1566
- return tm;
1553
+ return marker;
1567
1554
  }
1568
1555
 
1569
1556
  function setBookmark(pos) {
1570
1557
  pos = clipPos(pos);
1571
- var bm = new Bookmark(pos.ch);
1572
- getLine(pos.line).addMark(bm);
1573
- return bm;
1558
+ var marker = new TextMarker("bookmark"), line = getLine(pos.line);
1559
+ var span = {from: pos.ch, to: pos.ch, marker: marker};
1560
+ (line.markedSpans || (line.markedSpans = [])).push(span);
1561
+ marker.lines.push(line);
1562
+ return marker;
1574
1563
  }
1575
1564
 
1576
1565
  function findMarksAt(pos) {
1577
1566
  pos = clipPos(pos);
1578
- var markers = [], marked = getLine(pos.line).marked;
1579
- if (!marked) return markers;
1580
- for (var i = 0, e = marked.length; i < e; ++i) {
1581
- var m = marked[i];
1582
- if ((m.from == null || m.from <= pos.ch) &&
1583
- (m.to == null || m.to >= pos.ch))
1584
- markers.push(m.marker || m);
1567
+ var markers = [], spans = getLine(pos.line).markedSpans;
1568
+ if (spans) for (var i = 0; i < spans.length; ++i) {
1569
+ var span = spans[i];
1570
+ if ((span.from == null || span.from <= pos.ch) &&
1571
+ (span.to == null || span.to >= pos.ch))
1572
+ markers.push(span.marker);
1585
1573
  }
1586
1574
  return markers;
1587
1575
  }
@@ -1656,40 +1644,11 @@ window.CodeMirror = (function() {
1656
1644
  markerClass: marker && marker.style, lineClass: line.className, bgClass: line.bgClassName};
1657
1645
  }
1658
1646
 
1659
- // These are used to go from pixel positions to character
1660
- // positions, taking varying character widths into account.
1661
- function charFromX(line, x) {
1662
- if (x <= 0) return 0;
1663
- var lineObj = getLine(line), text = lineObj.text;
1664
- function getX(len) {
1665
- return measureLine(lineObj, len).left;
1666
- }
1667
- var from = 0, fromX = 0, to = text.length, toX;
1668
- // Guess a suitable upper bound for our search.
1669
- var estimated = Math.min(to, Math.ceil(x / charWidth()));
1670
- for (;;) {
1671
- var estX = getX(estimated);
1672
- if (estX <= x && estimated < to) estimated = Math.min(to, Math.ceil(estimated * 1.2));
1673
- else {toX = estX; to = estimated; break;}
1674
- }
1675
- if (x > toX) return to;
1676
- // Try to guess a suitable lower bound as well.
1677
- estimated = Math.floor(to * 0.8); estX = getX(estimated);
1678
- if (estX < x) {from = estimated; fromX = estX;}
1679
- // Do a binary search between these bounds.
1680
- for (;;) {
1681
- if (to - from <= 1) return (toX - x > x - fromX) ? from : to;
1682
- var middle = Math.ceil((from + to) / 2), middleX = getX(middle);
1683
- if (middleX > x) {to = middle; toX = middleX;}
1684
- else {from = middle; fromX = middleX;}
1685
- }
1686
- }
1687
-
1688
1647
  function measureLine(line, ch) {
1689
1648
  if (ch == 0) return {top: 0, left: 0};
1690
1649
  var wbr = options.lineWrapping && ch < line.text.length &&
1691
1650
  spanAffectsWrapping.test(line.text.slice(ch - 1, ch + 1));
1692
- var pre = line.getElement(makeTab, ch, wbr);
1651
+ var pre = lineContent(line, ch);
1693
1652
  removeChildrenAndAdd(measure, pre);
1694
1653
  var anchor = pre.anchor;
1695
1654
  var top = anchor.offsetTop, left = anchor.offsetLeft;
@@ -1800,6 +1759,7 @@ window.CodeMirror = (function() {
1800
1759
  var offL = eltOffset(lineSpace, true);
1801
1760
  return coordsChar(x - offL.left, y - offL.top);
1802
1761
  }
1762
+ var detectingSelectAll;
1803
1763
  function onContextMenu(e) {
1804
1764
  var pos = posFromMouse(e), scrollPos = scrollbar.scrollTop;
1805
1765
  if (!pos || opera) return; // Opera is difficult.
@@ -1811,19 +1771,30 @@ window.CodeMirror = (function() {
1811
1771
  input.style.cssText = "position: fixed; width: 30px; height: 30px; top: " + (e.clientY - 5) +
1812
1772
  "px; left: " + (e.clientX - 5) + "px; z-index: 1000; background: white; " +
1813
1773
  "border-width: 0; outline: none; overflow: hidden; opacity: .05; filter: alpha(opacity=5);";
1814
- leaveInputAlone = true;
1815
- var val = input.value = getSelection();
1816
1774
  focusInput();
1817
- selectInput(input);
1775
+ resetInput(true);
1776
+ // Adds "Select all" to context menu in FF
1777
+ if (posEq(sel.from, sel.to)) input.value = prevInput = " ";
1778
+
1818
1779
  function rehide() {
1819
- var newVal = splitLines(input.value).join("\n");
1820
- if (newVal != val && !options.readOnly) operation(replaceSelection)(newVal, "end");
1821
1780
  inputDiv.style.position = "relative";
1822
1781
  input.style.cssText = oldCSS;
1823
1782
  if (ie_lt9) scrollbar.scrollTop = scrollPos;
1824
- leaveInputAlone = false;
1825
- resetInput(true);
1826
1783
  slowPoll();
1784
+
1785
+ // Try to detect the user choosing select-all
1786
+ if (input.selectionStart != null) {
1787
+ clearTimeout(detectingSelectAll);
1788
+ var extval = input.value = " " + (posEq(sel.from, sel.to) ? "" : input.value), i = 0;
1789
+ prevInput = " ";
1790
+ input.selectionStart = 1; input.selectionEnd = extval.length;
1791
+ detectingSelectAll = setTimeout(function poll(){
1792
+ if (prevInput == " " && input.selectionStart == 0)
1793
+ operation(commands.selectAll)(instance);
1794
+ else if (i++ < 10) detectingSelectAll = setTimeout(poll, 500);
1795
+ else resetInput();
1796
+ }, 200);
1797
+ }
1827
1798
  }
1828
1799
 
1829
1800
  if (gecko) {
@@ -1907,70 +1878,39 @@ window.CodeMirror = (function() {
1907
1878
  return minline;
1908
1879
  }
1909
1880
  function getStateBefore(n) {
1910
- var start = findStartLine(n), state = start && getLine(start-1).stateAfter;
1881
+ var pos = findStartLine(n), state = pos && getLine(pos-1).stateAfter;
1911
1882
  if (!state) state = startState(mode);
1912
1883
  else state = copyState(mode, state);
1913
- doc.iter(start, n, function(line) {
1914
- line.highlight(mode, state, options.tabSize);
1915
- line.stateAfter = copyState(mode, state);
1884
+ doc.iter(pos, n, function(line) {
1885
+ line.process(mode, state, options.tabSize);
1886
+ line.stateAfter = (pos == n - 1 || pos % 5 == 0) ? copyState(mode, state) : null;
1916
1887
  });
1917
- if (start < n) changes.push({from: start, to: n});
1918
- if (n < doc.size && !getLine(n).stateAfter) work.push(n);
1919
1888
  return state;
1920
1889
  }
1921
- function highlightLines(start, end) {
1922
- var state = getStateBefore(start);
1923
- doc.iter(start, end, function(line) {
1924
- line.highlight(mode, state, options.tabSize);
1925
- line.stateAfter = copyState(mode, state);
1926
- });
1927
- }
1928
1890
  function highlightWorker() {
1929
- var end = +new Date + options.workTime;
1930
- var foundWork = work.length;
1931
- while (work.length) {
1932
- if (!getLine(showingFrom).stateAfter) var task = showingFrom;
1933
- else var task = work.pop();
1934
- if (task >= doc.size) continue;
1935
- var start = findStartLine(task), state = start && getLine(start-1).stateAfter;
1936
- if (state) state = copyState(mode, state);
1937
- else state = startState(mode);
1938
-
1939
- var unchanged = 0, compare = mode.compareStates, realChange = false,
1940
- i = start, bail = false;
1941
- doc.iter(i, doc.size, function(line) {
1942
- var hadState = line.stateAfter;
1943
- if (+new Date > end) {
1944
- work.push(i);
1945
- startWorker(options.workDelay);
1946
- if (realChange) changes.push({from: task, to: i + 1});
1947
- return (bail = true);
1948
- }
1949
- var changed = line.highlight(mode, state, options.tabSize);
1950
- if (changed) realChange = true;
1891
+ if (frontier >= showingTo) return;
1892
+ var end = +new Date + options.workTime, state = copyState(mode, getStateBefore(frontier));
1893
+ var startFrontier = frontier;
1894
+ doc.iter(frontier, showingTo, function(line) {
1895
+ if (frontier >= showingFrom) { // Visible
1896
+ line.highlight(mode, state, options.tabSize);
1951
1897
  line.stateAfter = copyState(mode, state);
1952
- var done = null;
1953
- if (compare) {
1954
- var same = hadState && compare(hadState, state);
1955
- if (same != Pass) done = !!same;
1956
- }
1957
- if (done == null) {
1958
- if (changed !== false || !hadState) unchanged = 0;
1959
- else if (++unchanged > 3 && (!mode.indent || mode.indent(hadState, "") == mode.indent(state, "")))
1960
- done = true;
1961
- }
1962
- if (done) return true;
1963
- ++i;
1964
- });
1965
- if (bail) return;
1966
- if (realChange) changes.push({from: task, to: i + 1});
1967
- }
1968
- if (foundWork && options.onHighlightComplete)
1969
- options.onHighlightComplete(instance);
1898
+ } else {
1899
+ line.process(mode, state, options.tabSize);
1900
+ line.stateAfter = frontier % 5 == 0 ? copyState(mode, state) : null;
1901
+ }
1902
+ ++frontier;
1903
+ if (+new Date > end) {
1904
+ startWorker(options.workDelay);
1905
+ return true;
1906
+ }
1907
+ });
1908
+ if (showingTo > startFrontier && frontier >= showingFrom)
1909
+ operation(function() {changes.push({from: startFrontier, to: frontier});})();
1970
1910
  }
1971
1911
  function startWorker(time) {
1972
- if (!work.length) return;
1973
- highlight.set(time, operation(highlightWorker));
1912
+ if (frontier < showingTo)
1913
+ highlight.set(time, highlightWorker);
1974
1914
  }
1975
1915
 
1976
1916
  // Operations are used to wrap changes in such a way that each
@@ -2005,8 +1945,7 @@ window.CodeMirror = (function() {
2005
1945
  if (newScrollPos) scrollCursorIntoView();
2006
1946
  if (selectionChanged) restartBlink();
2007
1947
 
2008
- if (focused && !leaveInputAlone &&
2009
- (updateInput === true || (updateInput !== false && selectionChanged)))
1948
+ if (focused && (updateInput === true || (updateInput !== false && selectionChanged)))
2010
1949
  resetInput(userSelChange);
2011
1950
 
2012
1951
  if (selectionChanged && options.matchBrackets)
@@ -2070,7 +2009,6 @@ window.CodeMirror = (function() {
2070
2009
  onCursorActivity: null,
2071
2010
  onViewportChange: null,
2072
2011
  onGutterClick: null,
2073
- onHighlightComplete: null,
2074
2012
  onUpdate: null,
2075
2013
  onFocus: null, onBlur: null, onScroll: null,
2076
2014
  matchBrackets: false,
@@ -2113,7 +2051,13 @@ window.CodeMirror = (function() {
2113
2051
  var spec = CodeMirror.resolveMode(spec);
2114
2052
  var mfactory = modes[spec.name];
2115
2053
  if (!mfactory) return CodeMirror.getMode(options, "text/plain");
2116
- return mfactory(options, spec);
2054
+ var modeObj = mfactory(options, spec);
2055
+ if (modeExtensions.hasOwnProperty(spec.name)) {
2056
+ var exts = modeExtensions[spec.name];
2057
+ for (var prop in exts) if (exts.hasOwnProperty(prop)) modeObj[prop] = exts[prop];
2058
+ }
2059
+ modeObj.name = spec.name;
2060
+ return modeObj;
2117
2061
  };
2118
2062
  CodeMirror.listModes = function() {
2119
2063
  var list = [];
@@ -2133,6 +2077,13 @@ window.CodeMirror = (function() {
2133
2077
  extensions[name] = func;
2134
2078
  };
2135
2079
 
2080
+ var modeExtensions = CodeMirror.modeExtensions = {};
2081
+ CodeMirror.extendMode = function(mode, properties) {
2082
+ var exts = modeExtensions.hasOwnProperty(mode) ? modeExtensions[mode] : (modeExtensions[mode] = {});
2083
+ for (var prop in properties) if (properties.hasOwnProperty(prop))
2084
+ exts[prop] = properties[prop];
2085
+ };
2086
+
2136
2087
  var commands = CodeMirror.commands = {
2137
2088
  selectAll: function(cm) {cm.setSelection({line: 0, ch: 0}, {line: cm.lineCount() - 1});},
2138
2089
  killLine: function(cm) {
@@ -2335,6 +2286,14 @@ window.CodeMirror = (function() {
2335
2286
  return mode.startState ? mode.startState(a1, a2) : true;
2336
2287
  }
2337
2288
  CodeMirror.startState = startState;
2289
+ CodeMirror.innerMode = function(mode, state) {
2290
+ while (mode.innerMode) {
2291
+ var info = mode.innerMode(state);
2292
+ state = info.state;
2293
+ mode = info.mode;
2294
+ }
2295
+ return info || {mode: mode, state: state};
2296
+ };
2338
2297
 
2339
2298
  // The character stream used by a mode's parser.
2340
2299
  function StringStream(string, tabSize) {
@@ -2383,6 +2342,7 @@ window.CodeMirror = (function() {
2383
2342
  }
2384
2343
  } else {
2385
2344
  var match = this.string.slice(this.pos).match(pattern);
2345
+ if (match && match.index > 0) return null;
2386
2346
  if (match && consume !== false) this.pos += match[0].length;
2387
2347
  return match;
2388
2348
  }
@@ -2391,69 +2351,123 @@ window.CodeMirror = (function() {
2391
2351
  };
2392
2352
  CodeMirror.StringStream = StringStream;
2393
2353
 
2394
- function MarkedText(from, to, className, marker) {
2395
- this.from = from; this.to = to; this.style = className; this.marker = marker;
2354
+ function MarkedSpan(from, to, marker) {
2355
+ this.from = from; this.to = to; this.marker = marker;
2396
2356
  }
2397
- MarkedText.prototype = {
2398
- attach: function(line) { this.marker.set.push(line); },
2399
- detach: function(line) {
2400
- var ix = indexOf(this.marker.set, line);
2401
- if (ix > -1) this.marker.set.splice(ix, 1);
2402
- },
2403
- split: function(pos, lenBefore) {
2404
- if (this.to <= pos && this.to != null) return null;
2405
- var from = this.from < pos || this.from == null ? null : this.from - pos + lenBefore;
2406
- var to = this.to == null ? null : this.to - pos + lenBefore;
2407
- return new MarkedText(from, to, this.style, this.marker);
2408
- },
2409
- dup: function() { return new MarkedText(null, null, this.style, this.marker); },
2410
- clipTo: function(fromOpen, from, toOpen, to, diff) {
2411
- if (fromOpen && to > this.from && (to < this.to || this.to == null))
2412
- this.from = null;
2413
- else if (this.from != null && this.from >= from)
2414
- this.from = Math.max(to, this.from) + diff;
2415
- if (toOpen && (from < this.to || this.to == null) && (from > this.from || this.from == null))
2416
- this.to = null;
2417
- else if (this.to != null && this.to > from)
2418
- this.to = to < this.to ? this.to + diff : from;
2419
- },
2420
- isDead: function() { return this.from != null && this.to != null && this.from >= this.to; },
2421
- sameSet: function(x) { return this.marker == x.marker; }
2422
- };
2423
2357
 
2424
- function Bookmark(pos) {
2425
- this.from = pos; this.to = pos; this.line = null;
2358
+ function getMarkedSpanFor(spans, marker, del) {
2359
+ if (spans) for (var i = 0; i < spans.length; ++i) {
2360
+ var span = spans[i];
2361
+ if (span.marker == marker) {
2362
+ if (del) spans.splice(i, 1);
2363
+ return span;
2364
+ }
2365
+ }
2426
2366
  }
2427
- Bookmark.prototype = {
2428
- attach: function(line) { this.line = line; },
2429
- detach: function(line) { if (this.line == line) this.line = null; },
2430
- split: function(pos, lenBefore) {
2431
- if (pos < this.from) {
2432
- this.from = this.to = (this.from - pos) + lenBefore;
2433
- return this;
2367
+
2368
+ function markedSpansBefore(old, startCh, endCh) {
2369
+ if (old) for (var i = 0, nw; i < old.length; ++i) {
2370
+ var span = old[i], marker = span.marker;
2371
+ var startsBefore = span.from == null || (marker.inclusiveLeft ? span.from <= startCh : span.from < startCh);
2372
+ if (startsBefore || marker.type == "bookmark" && span.from == startCh && span.from != endCh) {
2373
+ var endsAfter = span.to == null || (marker.inclusiveRight ? span.to >= startCh : span.to > startCh);
2374
+ (nw || (nw = [])).push({from: span.from,
2375
+ to: endsAfter ? null : span.to,
2376
+ marker: marker});
2434
2377
  }
2435
- },
2436
- isDead: function() { return this.from > this.to; },
2437
- clipTo: function(fromOpen, from, toOpen, to, diff) {
2438
- if ((fromOpen || from < this.from) && (toOpen || to > this.to)) {
2439
- this.from = 0; this.to = -1;
2440
- } else if (this.from > from) {
2441
- this.from = this.to = Math.max(to, this.from) + diff;
2378
+ }
2379
+ return nw;
2380
+ }
2381
+
2382
+ function markedSpansAfter(old, endCh) {
2383
+ if (old) for (var i = 0, nw; i < old.length; ++i) {
2384
+ var span = old[i], marker = span.marker;
2385
+ var endsAfter = span.to == null || (marker.inclusiveRight ? span.to >= endCh : span.to > endCh);
2386
+ if (endsAfter || marker.type == "bookmark" && span.from == endCh) {
2387
+ var startsBefore = span.from == null || (marker.inclusiveLeft ? span.from <= endCh : span.from < endCh);
2388
+ (nw || (nw = [])).push({from: startsBefore ? null : span.from - endCh,
2389
+ to: span.to == null ? null : span.to - endCh,
2390
+ marker: marker});
2442
2391
  }
2443
- },
2444
- sameSet: function(x) { return false; },
2445
- find: function() {
2446
- if (!this.line || !this.line.parent) return null;
2447
- return {line: lineNo(this.line), ch: this.from};
2448
- },
2449
- clear: function() {
2450
- if (this.line) {
2451
- var found = indexOf(this.line.marked, this);
2452
- if (found != -1) this.line.marked.splice(found, 1);
2453
- this.line = null;
2392
+ }
2393
+ return nw;
2394
+ }
2395
+
2396
+ function updateMarkedSpans(oldFirst, oldLast, startCh, endCh, newText) {
2397
+ if (!oldFirst && !oldLast) return newText;
2398
+ // Get the spans that 'stick out' on both sides
2399
+ var first = markedSpansBefore(oldFirst, startCh);
2400
+ var last = markedSpansAfter(oldLast, endCh);
2401
+
2402
+ // Next, merge those two ends
2403
+ var sameLine = newText.length == 1, offset = lst(newText).length + (sameLine ? startCh : 0);
2404
+ if (first) {
2405
+ // Fix up .to properties of first
2406
+ for (var i = 0; i < first.length; ++i) {
2407
+ var span = first[i];
2408
+ if (span.to == null) {
2409
+ var found = getMarkedSpanFor(last, span.marker);
2410
+ if (!found) span.to = startCh;
2411
+ else if (sameLine) span.to = found.to == null ? null : found.to + offset;
2412
+ }
2454
2413
  }
2455
2414
  }
2456
- };
2415
+ if (last) {
2416
+ // Fix up .from in last (or move them into first in case of sameLine)
2417
+ for (var i = 0; i < last.length; ++i) {
2418
+ var span = last[i];
2419
+ if (span.to != null) span.to += offset;
2420
+ if (span.from == null) {
2421
+ var found = getMarkedSpanFor(first, span.marker);
2422
+ if (!found) {
2423
+ span.from = offset;
2424
+ if (sameLine) (first || (first = [])).push(span);
2425
+ }
2426
+ } else {
2427
+ span.from += offset;
2428
+ if (sameLine) (first || (first = [])).push(span);
2429
+ }
2430
+ }
2431
+ }
2432
+
2433
+ var newMarkers = [newHL(newText[0], first)];
2434
+ if (!sameLine) {
2435
+ // Fill gap with whole-line-spans
2436
+ var gap = newText.length - 2, gapMarkers;
2437
+ if (gap > 0 && first)
2438
+ for (var i = 0; i < first.length; ++i)
2439
+ if (first[i].to == null)
2440
+ (gapMarkers || (gapMarkers = [])).push({from: null, to: null, marker: first[i].marker});
2441
+ for (var i = 0; i < gap; ++i)
2442
+ newMarkers.push(newHL(newText[i+1], gapMarkers));
2443
+ newMarkers.push(newHL(lst(newText), last));
2444
+ }
2445
+ return newMarkers;
2446
+ }
2447
+
2448
+ // hl stands for history-line, a data structure that can be either a
2449
+ // string (line without markers) or a {text, markedSpans} object.
2450
+ function hlText(val) { return typeof val == "string" ? val : val.text; }
2451
+ function hlSpans(val) { return typeof val == "string" ? null : val.markedSpans; }
2452
+ function newHL(text, spans) { return spans ? {text: text, markedSpans: spans} : text; }
2453
+
2454
+ function detachMarkedSpans(line) {
2455
+ var spans = line.markedSpans;
2456
+ if (!spans) return;
2457
+ for (var i = 0; i < spans.length; ++i) {
2458
+ var lines = spans[i].marker.lines;
2459
+ var ix = indexOf(lines, line);
2460
+ lines.splice(ix, 1);
2461
+ }
2462
+ line.markedSpans = null;
2463
+ }
2464
+
2465
+ function attachMarkedSpans(line, spans) {
2466
+ if (!spans) return;
2467
+ for (var i = 0; i < spans.length; ++i)
2468
+ var marker = spans[i].marker.lines.push(line);
2469
+ line.markedSpans = spans;
2470
+ }
2457
2471
 
2458
2472
  // When measuring the position of the end of a line, different
2459
2473
  // browsers require different approaches. If an empty span is added,
@@ -2467,142 +2481,32 @@ window.CodeMirror = (function() {
2467
2481
 
2468
2482
  // Line objects. These hold state related to a line, including
2469
2483
  // highlighting info (the styles array).
2470
- function Line(text, styles) {
2471
- this.styles = styles || [text, null];
2484
+ function Line(text, markedSpans) {
2472
2485
  this.text = text;
2473
2486
  this.height = 1;
2487
+ attachMarkedSpans(this, markedSpans);
2474
2488
  }
2475
- Line.inheritMarks = function(text, orig) {
2476
- var ln = new Line(text), mk = orig && orig.marked;
2477
- if (mk) {
2478
- for (var i = 0; i < mk.length; ++i) {
2479
- if (mk[i].to == null && mk[i].style) {
2480
- var newmk = ln.marked || (ln.marked = []), mark = mk[i];
2481
- var nmark = mark.dup(); newmk.push(nmark); nmark.attach(ln);
2482
- }
2483
- }
2484
- }
2485
- return ln;
2486
- };
2487
2489
  Line.prototype = {
2488
- // Replace a piece of a line, keeping the styles around it intact.
2489
- replace: function(from, to_, text) {
2490
- var st = [], mk = this.marked, to = to_ == null ? this.text.length : to_;
2491
- copyStyles(0, from, this.styles, st);
2492
- if (text) st.push(text, null);
2493
- copyStyles(to, this.text.length, this.styles, st);
2494
- this.styles = st;
2495
- this.text = this.text.slice(0, from) + text + this.text.slice(to);
2496
- this.stateAfter = null;
2497
- if (mk) {
2498
- var diff = text.length - (to - from);
2499
- for (var i = 0; i < mk.length; ++i) {
2500
- var mark = mk[i];
2501
- mark.clipTo(from == null, from || 0, to_ == null, to, diff);
2502
- if (mark.isDead()) {mark.detach(this); mk.splice(i--, 1);}
2503
- }
2504
- }
2505
- },
2506
- // Split a part off a line, keeping styles and markers intact.
2507
- split: function(pos, textBefore) {
2508
- var st = [textBefore, null], mk = this.marked;
2509
- copyStyles(pos, this.text.length, this.styles, st);
2510
- var taken = new Line(textBefore + this.text.slice(pos), st);
2511
- if (mk) {
2512
- for (var i = 0; i < mk.length; ++i) {
2513
- var mark = mk[i];
2514
- var newmark = mark.split(pos, textBefore.length);
2515
- if (newmark) {
2516
- if (!taken.marked) taken.marked = [];
2517
- taken.marked.push(newmark); newmark.attach(taken);
2518
- if (newmark == mark) mk.splice(i--, 1);
2519
- }
2520
- }
2521
- }
2522
- return taken;
2523
- },
2524
- append: function(line) {
2525
- var mylen = this.text.length, mk = line.marked, mymk = this.marked;
2526
- this.text += line.text;
2527
- copyStyles(0, line.text.length, line.styles, this.styles);
2528
- if (mymk) {
2529
- for (var i = 0; i < mymk.length; ++i)
2530
- if (mymk[i].to == null) mymk[i].to = mylen;
2531
- }
2532
- if (mk && mk.length) {
2533
- if (!mymk) this.marked = mymk = [];
2534
- outer: for (var i = 0; i < mk.length; ++i) {
2535
- var mark = mk[i];
2536
- if (!mark.from) {
2537
- for (var j = 0; j < mymk.length; ++j) {
2538
- var mymark = mymk[j];
2539
- if (mymark.to == mylen && mymark.sameSet(mark)) {
2540
- mymark.to = mark.to == null ? null : mark.to + mylen;
2541
- if (mymark.isDead()) {
2542
- mymark.detach(this);
2543
- mk.splice(i--, 1);
2544
- }
2545
- continue outer;
2546
- }
2547
- }
2548
- }
2549
- mymk.push(mark);
2550
- mark.attach(this);
2551
- mark.from += mylen;
2552
- if (mark.to != null) mark.to += mylen;
2553
- }
2554
- }
2555
- },
2556
- fixMarkEnds: function(other) {
2557
- var mk = this.marked, omk = other.marked;
2558
- if (!mk) return;
2559
- outer: for (var i = 0; i < mk.length; ++i) {
2560
- var mark = mk[i], close = mark.to == null;
2561
- if (close && omk) {
2562
- for (var j = 0; j < omk.length; ++j) {
2563
- var om = omk[j];
2564
- if (!om.sameSet(mark) || om.from != null) continue;
2565
- if (mark.from == this.text.length && om.to == 0) {
2566
- omk.splice(j, 1);
2567
- mk.splice(i--, 1);
2568
- continue outer;
2569
- } else {
2570
- close = false; break;
2571
- }
2572
- }
2573
- }
2574
- if (close) mark.to = this.text.length;
2575
- }
2576
- },
2577
- fixMarkStarts: function() {
2578
- var mk = this.marked;
2579
- if (!mk) return;
2580
- for (var i = 0; i < mk.length; ++i)
2581
- if (mk[i].from == null) mk[i].from = 0;
2582
- },
2583
- addMark: function(mark) {
2584
- mark.attach(this);
2585
- if (this.marked == null) this.marked = [];
2586
- this.marked.push(mark);
2587
- this.marked.sort(function(a, b){return (a.from || 0) - (b.from || 0);});
2490
+ update: function(text, markedSpans) {
2491
+ this.text = text;
2492
+ this.stateAfter = this.styles = null;
2493
+ detachMarkedSpans(this);
2494
+ attachMarkedSpans(this, markedSpans);
2588
2495
  },
2589
2496
  // Run the given mode's parser over a line, update the styles
2590
2497
  // array, which contains alternating fragments of text and CSS
2591
2498
  // classes.
2592
2499
  highlight: function(mode, state, tabSize) {
2593
- var stream = new StringStream(this.text, tabSize), st = this.styles, pos = 0;
2594
- var changed = false, curWord = st[0], prevWord;
2500
+ var stream = new StringStream(this.text, tabSize), st = this.styles || (this.styles = []);
2501
+ var pos = st.length = 0;
2595
2502
  if (this.text == "" && mode.blankLine) mode.blankLine(state);
2596
2503
  while (!stream.eol()) {
2597
- var style = mode.token(stream, state);
2598
- var substr = this.text.slice(stream.start, stream.pos);
2504
+ var style = mode.token(stream, state), substr = stream.current();
2599
2505
  stream.start = stream.pos;
2600
- if (pos && st[pos-1] == style)
2506
+ if (pos && st[pos-1] == style) {
2601
2507
  st[pos-2] += substr;
2602
- else if (substr) {
2603
- if (!changed && (st[pos+1] != style || (pos && st[pos-2] != prevWord))) changed = true;
2508
+ } else if (substr) {
2604
2509
  st[pos++] = substr; st[pos++] = style;
2605
- prevWord = curWord; curWord = st[pos];
2606
2510
  }
2607
2511
  // Give up when line is ridiculously long
2608
2512
  if (stream.pos > 5000) {
@@ -2610,12 +2514,14 @@ window.CodeMirror = (function() {
2610
2514
  break;
2611
2515
  }
2612
2516
  }
2613
- if (st.length != pos) {st.length = pos; changed = true;}
2614
- if (pos && st[pos-2] != prevWord) changed = true;
2615
- // Short lines with simple highlights return null, and are
2616
- // counted as changed by the driver because they are likely to
2617
- // highlight the same way in various contexts.
2618
- return changed || (st.length < 5 && this.text.length < 10 ? null : false);
2517
+ },
2518
+ process: function(mode, state, tabSize) {
2519
+ var stream = new StringStream(this.text, tabSize);
2520
+ if (this.text == "" && mode.blankLine) mode.blankLine(state);
2521
+ while (!stream.eol() && stream.pos <= 5000) {
2522
+ mode.token(stream, state);
2523
+ stream.start = stream.pos;
2524
+ }
2619
2525
  },
2620
2526
  // Fetch the parser token for a given character. Useful for hacks
2621
2527
  // that want to inspect the mode state (say, for completion).
@@ -2634,7 +2540,7 @@ window.CodeMirror = (function() {
2634
2540
  indentation: function(tabSize) {return countColumn(this.text, null, tabSize);},
2635
2541
  // Produces an HTML fragment for the line, taking selection,
2636
2542
  // marking, and highlighting into account.
2637
- getElement: function(makeTab, wrapAt, wrapWBR) {
2543
+ getContent: function(tabSize, wrapAt, compensateForWrapping) {
2638
2544
  var first = true, col = 0, specials = /[\t\u0000-\u0019\u200b\u2028\u2029\uFEFF]/g;
2639
2545
  var pre = elt("pre");
2640
2546
  function span_(html, text, style) {
@@ -2658,9 +2564,9 @@ window.CodeMirror = (function() {
2658
2564
  if (!m) break;
2659
2565
  pos += skipped + 1;
2660
2566
  if (m[0] == "\t") {
2661
- var tab = makeTab(col);
2662
- content.appendChild(tab.element.cloneNode(true));
2663
- col += tab.width;
2567
+ var tabWidth = tabSize - col % tabSize;
2568
+ content.appendChild(elt("span", spaceStr(tabWidth), "cm-tab"));
2569
+ col += tabWidth;
2664
2570
  } else {
2665
2571
  var token = elt("span", "\u2022", "cm-invalidchar");
2666
2572
  token.title = "\\u" + m[0].charCodeAt(0).toString(16);
@@ -2681,7 +2587,7 @@ window.CodeMirror = (function() {
2681
2587
  if (wrapAt > outPos) {
2682
2588
  span_(html, text.slice(0, wrapAt - outPos), style);
2683
2589
  // See comment at the definition of spanAffectsWrapping
2684
- if (wrapWBR) html.appendChild(elt("wbr"));
2590
+ if (compensateForWrapping) html.appendChild(elt("wbr"));
2685
2591
  }
2686
2592
  html.appendChild(anchor);
2687
2593
  var cut = wrapAt - outPos;
@@ -2702,7 +2608,7 @@ window.CodeMirror = (function() {
2702
2608
  };
2703
2609
  }
2704
2610
 
2705
- var st = this.styles, allText = this.text, marked = this.marked;
2611
+ var st = this.styles, allText = this.text, marked = this.markedSpans;
2706
2612
  var len = allText.length;
2707
2613
  function styleToClass(style) {
2708
2614
  if (!style) return null;
@@ -2718,13 +2624,14 @@ window.CodeMirror = (function() {
2718
2624
  span(pre, str, styleToClass(style));
2719
2625
  }
2720
2626
  } else {
2627
+ marked.sort(function(a, b) { return a.from - b.from; });
2721
2628
  var pos = 0, i = 0, text = "", style, sg = 0;
2722
2629
  var nextChange = marked[0].from || 0, marks = [], markpos = 0;
2723
2630
  var advanceMarks = function() {
2724
2631
  var m;
2725
2632
  while (markpos < marked.length &&
2726
2633
  ((m = marked[markpos]).from == pos || m.from == null)) {
2727
- if (m.style != null) marks.push(m);
2634
+ if (m.marker.type == "range") marks.push(m);
2728
2635
  ++markpos;
2729
2636
  }
2730
2637
  nextChange = markpos < marked.length ? marked[markpos].from : Infinity;
@@ -2743,8 +2650,12 @@ window.CodeMirror = (function() {
2743
2650
  if (text) {
2744
2651
  var end = pos + text.length;
2745
2652
  var appliedStyle = style;
2746
- for (var j = 0; j < marks.length; ++j)
2747
- appliedStyle = (appliedStyle ? appliedStyle + " " : "") + marks[j].style;
2653
+ for (var j = 0; j < marks.length; ++j) {
2654
+ var mark = marks[j];
2655
+ appliedStyle = (appliedStyle ? appliedStyle + " " : "") + mark.marker.style;
2656
+ if (mark.marker.endStyle && mark.to === Math.min(end, upto)) appliedStyle += " " + mark.marker.endStyle;
2657
+ if (mark.marker.startStyle && mark.from === pos) appliedStyle += " " + mark.marker.startStyle;
2658
+ }
2748
2659
  span(pre, end > upto ? text.slice(0, upto - pos) : text, appliedStyle);
2749
2660
  if (end >= upto) {text = text.slice(upto - pos); pos = upto; break;}
2750
2661
  pos = end;
@@ -2757,24 +2668,9 @@ window.CodeMirror = (function() {
2757
2668
  },
2758
2669
  cleanUp: function() {
2759
2670
  this.parent = null;
2760
- if (this.marked)
2761
- for (var i = 0, e = this.marked.length; i < e; ++i) this.marked[i].detach(this);
2671
+ detachMarkedSpans(this);
2762
2672
  }
2763
2673
  };
2764
- // Utility used by replace and split above
2765
- function copyStyles(from, to, source, dest) {
2766
- for (var i = 0, pos = 0, state = 0; pos < to; i+=2) {
2767
- var part = source[i], end = pos + part.length;
2768
- if (state == 0) {
2769
- if (end > from) dest.push(part.slice(from - pos, Math.min(part.length, to - pos)), source[i+1]);
2770
- if (end >= from) state = 1;
2771
- } else if (state == 1) {
2772
- if (end > to) dest.push(part.slice(0, to - pos), source[i+1]);
2773
- else dest.push(part, source[i+1]);
2774
- }
2775
- pos = end;
2776
- }
2777
- }
2778
2674
 
2779
2675
  // Data structure that holds the sequence of lines.
2780
2676
  function LeafChunk(lines) {
@@ -2975,7 +2871,7 @@ window.CodeMirror = (function() {
2975
2871
  History.prototype = {
2976
2872
  addChange: function(start, added, old) {
2977
2873
  this.undone.length = 0;
2978
- var time = +new Date, cur = this.done[this.done.length - 1], last = cur && cur[cur.length - 1];
2874
+ var time = +new Date, cur = lst(this.done), last = cur && lst(cur);
2979
2875
  var dtime = time - this.time;
2980
2876
 
2981
2877
  if (this.compound && cur && !this.closed) {
@@ -3121,10 +3017,19 @@ window.CodeMirror = (function() {
3121
3017
  return box;
3122
3018
  }
3123
3019
 
3124
- // Get a node's text content.
3125
3020
  function eltText(node) {
3126
3021
  return node.textContent || node.innerText || node.nodeValue || "";
3127
3022
  }
3023
+
3024
+ var spaceStrs = [""];
3025
+ function spaceStr(n) {
3026
+ while (spaceStrs.length <= n)
3027
+ spaceStrs.push(lst(spaceStrs) + " ");
3028
+ return spaceStrs[n];
3029
+ }
3030
+
3031
+ function lst(arr) { return arr[arr.length-1]; }
3032
+
3128
3033
  function selectInput(node) {
3129
3034
  if (ios) { // Mobile Safari apparently has a bug where select() is broken.
3130
3035
  node.selectionStart = 0;
@@ -3158,7 +3063,6 @@ window.CodeMirror = (function() {
3158
3063
  e.appendChild(document.createTextNode(str));
3159
3064
  } else e.textContent = str;
3160
3065
  }
3161
- CodeMirror.setTextContent = setTextContent;
3162
3066
 
3163
3067
  // Used to position the cursor after an undo/redo by finding the
3164
3068
  // last edited character.
@@ -3233,5 +3137,7 @@ window.CodeMirror = (function() {
3233
3137
  for (var i = 1; i <= 12; i++) keyNames[i + 111] = keyNames[i + 63235] = "F" + i;
3234
3138
  })();
3235
3139
 
3140
+ CodeMirror.version = "2.34";
3141
+
3236
3142
  return CodeMirror;
3237
3143
  })();