|
|
@@ -10,10 +10,11 @@ window.CodeMirror = (function() {
|
|
|
// IE11 currently doesn't count as 'ie', since it has almost none of
|
|
|
// the same bugs as earlier versions. Use ie_gt10 to handle
|
|
|
// incompatibilities in that version.
|
|
|
- var ie = /MSIE \d/.test(navigator.userAgent);
|
|
|
- var ie_lt8 = ie && (document.documentMode == null || document.documentMode < 8);
|
|
|
- var ie_lt9 = ie && (document.documentMode == null || document.documentMode < 9);
|
|
|
+ var old_ie = /MSIE \d/.test(navigator.userAgent);
|
|
|
+ var ie_lt8 = old_ie && (document.documentMode == null || document.documentMode < 8);
|
|
|
+ var ie_lt9 = old_ie && (document.documentMode == null || document.documentMode < 9);
|
|
|
var ie_gt10 = /Trident\/([7-9]|\d{2,})\./.test(navigator.userAgent);
|
|
|
+ var ie = old_ie || ie_gt10;
|
|
|
var webkit = /WebKit\//.test(navigator.userAgent);
|
|
|
var qtwebkit = webkit && /Qt\/\d+\.\d+/.test(navigator.userAgent);
|
|
|
var chrome = /Chrome\//.test(navigator.userAgent);
|
|
|
@@ -35,7 +36,7 @@ window.CodeMirror = (function() {
|
|
|
if (opera_version && opera_version >= 15) { opera = false; webkit = true; }
|
|
|
// Some browsers use the wrong event properties to signal cmd/ctrl on OS X
|
|
|
var flipCtrlCmd = mac && (qtwebkit || opera && (opera_version == null || opera_version < 12.11));
|
|
|
- var captureMiddleClick = gecko || (ie && !ie_lt9);
|
|
|
+ var captureMiddleClick = gecko || (old_ie && !ie_lt9);
|
|
|
|
|
|
// Optimize some code when these features are not used
|
|
|
var sawReadOnlySpans = false, sawCollapsedSpans = false;
|
|
|
@@ -75,7 +76,7 @@ window.CodeMirror = (function() {
|
|
|
|
|
|
// Override magic textarea content restore that IE sometimes does
|
|
|
// on our hidden textarea on reload
|
|
|
- if (ie) setTimeout(bind(resetInput, this, true), 20);
|
|
|
+ if (old_ie) setTimeout(bind(resetInput, this, true), 20);
|
|
|
|
|
|
registerEventHandlers(this);
|
|
|
// IE throws unspecified error in certain cases, when
|
|
|
@@ -195,6 +196,10 @@ window.CodeMirror = (function() {
|
|
|
|
|
|
function loadMode(cm) {
|
|
|
cm.doc.mode = CodeMirror.getMode(cm.options, cm.doc.modeOption);
|
|
|
+ resetModeState(cm);
|
|
|
+ }
|
|
|
+
|
|
|
+ function resetModeState(cm) {
|
|
|
cm.doc.iter(function(line) {
|
|
|
if (line.stateAfter) line.stateAfter = null;
|
|
|
if (line.styles) line.styles = null;
|
|
|
@@ -244,7 +249,6 @@ window.CodeMirror = (function() {
|
|
|
var map = keyMap[cm.options.keyMap], style = map.style;
|
|
|
cm.display.wrapper.className = cm.display.wrapper.className.replace(/\s*cm-keymap-\S+/g, "") +
|
|
|
(style ? " cm-keymap-" + style : "");
|
|
|
- cm.state.disableInput = map.disableInput;
|
|
|
}
|
|
|
|
|
|
function themeChanged(cm) {
|
|
|
@@ -450,7 +454,7 @@ window.CodeMirror = (function() {
|
|
|
// updates.
|
|
|
function updateDisplayInner(cm, changes, visible, forced) {
|
|
|
var display = cm.display, doc = cm.doc;
|
|
|
- if (!display.wrapper.clientWidth) {
|
|
|
+ if (!display.wrapper.offsetWidth) {
|
|
|
display.showingFrom = display.showingTo = doc.first;
|
|
|
display.viewOffset = 0;
|
|
|
return;
|
|
|
@@ -1054,7 +1058,7 @@ window.CodeMirror = (function() {
|
|
|
// doesn't work when wrapping is on, but in that case the
|
|
|
// situation is slightly better, since IE does cache line-wrapping
|
|
|
// information and only recomputes per-line.
|
|
|
- if (ie && !ie_lt8 && !cm.options.lineWrapping && pre.childNodes.length > 100) {
|
|
|
+ if (old_ie && !ie_lt8 && !cm.options.lineWrapping && pre.childNodes.length > 100) {
|
|
|
var fragment = document.createDocumentFragment();
|
|
|
var chunk = 10, n = pre.childNodes.length;
|
|
|
for (var i = 0, chunks = Math.ceil(n / chunk); i < chunks; ++i) {
|
|
|
@@ -1290,7 +1294,7 @@ window.CodeMirror = (function() {
|
|
|
if (bidi ? to == from || to == moveVisually(lineObj, from, 1) : to - from <= 1) {
|
|
|
var ch = x < fromX || x - fromX <= toX - x ? from : to;
|
|
|
var xDiff = x - (ch == from ? fromX : toX);
|
|
|
- while (isExtendingChar.test(lineObj.text.charAt(ch))) ++ch;
|
|
|
+ while (isExtendingChar(lineObj.text.charAt(ch))) ++ch;
|
|
|
var pos = PosWithInfo(lineNo, ch, ch == from ? fromOutside : toOutside,
|
|
|
xDiff < 0 ? -1 : xDiff ? 1 : 0);
|
|
|
return pos;
|
|
|
@@ -1482,7 +1486,7 @@ window.CodeMirror = (function() {
|
|
|
// supported or compatible enough yet to rely on.)
|
|
|
function readInput(cm) {
|
|
|
var input = cm.display.input, prevInput = cm.display.prevInput, doc = cm.doc, sel = doc.sel;
|
|
|
- if (!cm.state.focused || hasSelection(input) || isReadOnly(cm) || cm.state.disableInput) return false;
|
|
|
+ if (!cm.state.focused || hasSelection(input) || isReadOnly(cm) || cm.options.disableInput) return false;
|
|
|
if (cm.state.pasteIncoming && cm.state.fakedLastChar) {
|
|
|
input.value = input.value.substring(0, input.value.length - 1);
|
|
|
cm.state.fakedLastChar = false;
|
|
|
@@ -1500,17 +1504,27 @@ window.CodeMirror = (function() {
|
|
|
var same = 0, l = Math.min(prevInput.length, text.length);
|
|
|
while (same < l && prevInput.charCodeAt(same) == text.charCodeAt(same)) ++same;
|
|
|
var from = sel.from, to = sel.to;
|
|
|
+ var inserted = text.slice(same);
|
|
|
if (same < prevInput.length)
|
|
|
from = Pos(from.line, from.ch - (prevInput.length - same));
|
|
|
else if (cm.state.overwrite && posEq(from, to) && !cm.state.pasteIncoming)
|
|
|
- to = Pos(to.line, Math.min(getLine(doc, to.line).text.length, to.ch + (text.length - same)));
|
|
|
+ to = Pos(to.line, Math.min(getLine(doc, to.line).text.length, to.ch + inserted.length));
|
|
|
|
|
|
var updateInput = cm.curOp.updateInput;
|
|
|
- var changeEvent = {from: from, to: to, text: splitLines(text.slice(same)),
|
|
|
+ var changeEvent = {from: from, to: to, text: splitLines(inserted),
|
|
|
origin: cm.state.pasteIncoming ? "paste" : "+input"};
|
|
|
makeChange(cm.doc, changeEvent, "end");
|
|
|
cm.curOp.updateInput = updateInput;
|
|
|
signalLater(cm, "inputRead", cm, changeEvent);
|
|
|
+ if (!cm.state.pasteIncoming && cm.options.electricChars &&
|
|
|
+ cm.options.smartIndent && sel.head.ch < 100) {
|
|
|
+ var electric = cm.getModeAt(sel.head).electricChars;
|
|
|
+ if (electric) for (var i = 0; i < electric.length; i++)
|
|
|
+ if (inserted.indexOf(electric.charAt(i)) > -1) {
|
|
|
+ indentLine(cm, sel.head.line, "smart");
|
|
|
+ break;
|
|
|
+ }
|
|
|
+ }
|
|
|
|
|
|
if (text.length > 1000 || text.indexOf("\n") > -1) input.value = cm.display.prevInput = "";
|
|
|
else cm.display.prevInput = text;
|
|
|
@@ -1550,7 +1564,7 @@ window.CodeMirror = (function() {
|
|
|
function registerEventHandlers(cm) {
|
|
|
var d = cm.display;
|
|
|
on(d.scroller, "mousedown", operation(cm, onMouseDown));
|
|
|
- if (ie)
|
|
|
+ if (old_ie)
|
|
|
on(d.scroller, "dblclick", operation(cm, function(e) {
|
|
|
if (signalDOMEvent(cm, e)) return;
|
|
|
var pos = posFromMouse(cm, e);
|
|
|
@@ -1669,8 +1683,8 @@ window.CodeMirror = (function() {
|
|
|
|
|
|
// Needed to handle Tab key in KHTML
|
|
|
if (khtml) on(d.sizer, "mouseup", function() {
|
|
|
- if (document.activeElement == d.input) d.input.blur();
|
|
|
- focusInput(cm);
|
|
|
+ if (document.activeElement == d.input) d.input.blur();
|
|
|
+ focusInput(cm);
|
|
|
});
|
|
|
}
|
|
|
|
|
|
@@ -1828,7 +1842,7 @@ window.CodeMirror = (function() {
|
|
|
}
|
|
|
|
|
|
var move = operation(cm, function(e) {
|
|
|
- if (!ie && !e_button(e)) done(e);
|
|
|
+ if (!old_ie && !e_button(e)) done(e);
|
|
|
else extend(e);
|
|
|
});
|
|
|
var up = operation(cm, done);
|
|
|
@@ -1973,7 +1987,7 @@ window.CodeMirror = (function() {
|
|
|
// know one. These don't have to be accurate -- the result of them
|
|
|
// being wrong would just be a slight flicker on the first wheel
|
|
|
// scroll (if it is large enough).
|
|
|
- if (ie) wheelPixelsPerUnit = -.53;
|
|
|
+ if (old_ie) wheelPixelsPerUnit = -.53;
|
|
|
else if (gecko) wheelPixelsPerUnit = 15;
|
|
|
else if (chrome) wheelPixelsPerUnit = -.7;
|
|
|
else if (safari) wheelPixelsPerUnit = -1/3;
|
|
|
@@ -2127,7 +2141,7 @@ window.CodeMirror = (function() {
|
|
|
var cm = this;
|
|
|
if (!cm.state.focused) onFocus(cm);
|
|
|
if (signalDOMEvent(cm, e) || cm.options.onKeyEvent && cm.options.onKeyEvent(cm, addStop(e))) return;
|
|
|
- if (ie && e.keyCode == 27) e.returnValue = false;
|
|
|
+ if (old_ie && e.keyCode == 27) e.returnValue = false;
|
|
|
var code = e.keyCode;
|
|
|
// IE does strange things with escape.
|
|
|
cm.doc.sel.shift = code == 16 || e.shiftKey;
|
|
|
@@ -2148,10 +2162,6 @@ window.CodeMirror = (function() {
|
|
|
if (opera && keyCode == lastStoppedKey) {lastStoppedKey = null; e_preventDefault(e); return;}
|
|
|
if (((opera && (!e.which || e.which < 10)) || khtml) && handleKeyBinding(cm, e)) return;
|
|
|
var ch = String.fromCharCode(charCode == null ? keyCode : charCode);
|
|
|
- if (this.options.electricChars && this.doc.mode.electricChars &&
|
|
|
- this.options.smartIndent && !isReadOnly(this) &&
|
|
|
- this.doc.mode.electricChars.indexOf(ch) > -1)
|
|
|
- setTimeout(operation(cm, function() {indentLine(cm, cm.doc.sel.to.line, "smart");}), 75);
|
|
|
if (handleCharBinding(cm, e, ch)) return;
|
|
|
if (ie && !ie_lt9) cm.display.inputHasSelection = null;
|
|
|
fastPoll(cm);
|
|
|
@@ -2222,7 +2232,7 @@ window.CodeMirror = (function() {
|
|
|
|
|
|
// Try to detect the user choosing select-all
|
|
|
if (display.input.selectionStart != null) {
|
|
|
- if (!ie || ie_lt9) prepareSelectAllHack();
|
|
|
+ if (!old_ie || ie_lt9) prepareSelectAllHack();
|
|
|
clearTimeout(detectingSelectAll);
|
|
|
var i = 0, poll = function(){
|
|
|
if (display.prevInput == "\u200b" && display.input.selectionStart == 0)
|
|
|
@@ -2234,7 +2244,7 @@ window.CodeMirror = (function() {
|
|
|
}
|
|
|
}
|
|
|
|
|
|
- if (ie && !ie_lt9) prepareSelectAllHack();
|
|
|
+ if (old_ie && !ie_lt9) prepareSelectAllHack();
|
|
|
if (captureMiddleClick) {
|
|
|
e_stop(e);
|
|
|
var mouseup = function() {
|
|
|
@@ -2507,6 +2517,7 @@ window.CodeMirror = (function() {
|
|
|
|
|
|
function posEq(a, b) {return a.line == b.line && a.ch == b.ch;}
|
|
|
function posLess(a, b) {return a.line < b.line || (a.line == b.line && a.ch < b.ch);}
|
|
|
+ function cmp(a, b) {return a.line - b.line || a.ch - b.ch;}
|
|
|
function copyPos(x) {return Pos(x.line, x.ch);}
|
|
|
|
|
|
// SELECTION
|
|
|
@@ -2651,14 +2662,13 @@ window.CodeMirror = (function() {
|
|
|
if (coords.top + box.top < 0) doScroll = true;
|
|
|
else if (coords.bottom + box.top > (window.innerHeight || document.documentElement.clientHeight)) doScroll = false;
|
|
|
if (doScroll != null && !phantom) {
|
|
|
- var hidden = display.cursor.style.display == "none";
|
|
|
- if (hidden) {
|
|
|
- display.cursor.style.display = "";
|
|
|
- display.cursor.style.left = coords.left + "px";
|
|
|
- display.cursor.style.top = (coords.top - display.viewOffset) + "px";
|
|
|
- }
|
|
|
- display.cursor.scrollIntoView(doScroll);
|
|
|
- if (hidden) display.cursor.style.display = "none";
|
|
|
+ var scrollNode = elt("div", "\u200b", null, "position: absolute; top: " +
|
|
|
+ (coords.top - display.viewOffset) + "px; height: " +
|
|
|
+ (coords.bottom - coords.top + scrollerCutOff) + "px; left: " +
|
|
|
+ coords.left + "px; width: 2px;");
|
|
|
+ cm.display.lineSpace.appendChild(scrollNode);
|
|
|
+ scrollNode.scrollIntoView(doScroll);
|
|
|
+ cm.display.lineSpace.removeChild(scrollNode);
|
|
|
}
|
|
|
}
|
|
|
|
|
|
@@ -2741,7 +2751,10 @@ window.CodeMirror = (function() {
|
|
|
var tabSize = cm.options.tabSize;
|
|
|
var line = getLine(doc, n), curSpace = countColumn(line.text, null, tabSize);
|
|
|
var curSpaceString = line.text.match(/^\s*/)[0], indentation;
|
|
|
- if (how == "smart") {
|
|
|
+ if (!aggressive && !/\S/.test(line.text)) {
|
|
|
+ indentation = 0;
|
|
|
+ how = "not";
|
|
|
+ } else if (how == "smart") {
|
|
|
indentation = cm.doc.mode.indent(state, line.text.slice(curSpaceString.length), line.text);
|
|
|
if (indentation == Pass) {
|
|
|
if (!aggressive) return;
|
|
|
@@ -2923,7 +2936,7 @@ window.CodeMirror = (function() {
|
|
|
}),
|
|
|
indentSelection: operation(null, function(how) {
|
|
|
var sel = this.doc.sel;
|
|
|
- if (posEq(sel.from, sel.to)) return indentLine(this, sel.from.line, how);
|
|
|
+ if (posEq(sel.from, sel.to)) return indentLine(this, sel.from.line, how, true);
|
|
|
var e = sel.to.line - (sel.to.ch ? 0 : 1);
|
|
|
for (var i = sel.from.line; i <= e; ++i) indentLine(this, i, how);
|
|
|
}),
|
|
|
@@ -2968,11 +2981,31 @@ window.CodeMirror = (function() {
|
|
|
},
|
|
|
|
|
|
getHelper: function(pos, type) {
|
|
|
- if (!helpers.hasOwnProperty(type)) return;
|
|
|
+ return this.getHelpers(pos, type)[0];
|
|
|
+ },
|
|
|
+
|
|
|
+ getHelpers: function(pos, type) {
|
|
|
+ var found = [];
|
|
|
+ if (!helpers.hasOwnProperty(type)) return helpers;
|
|
|
var help = helpers[type], mode = this.getModeAt(pos);
|
|
|
- return mode[type] && help[mode[type]] ||
|
|
|
- mode.helperType && help[mode.helperType] ||
|
|
|
- help[mode.name];
|
|
|
+ if (typeof mode[type] == "string") {
|
|
|
+ if (help[mode[type]]) found.push(help[mode[type]]);
|
|
|
+ } else if (mode[type]) {
|
|
|
+ for (var i = 0; i < mode[type].length; i++) {
|
|
|
+ var val = help[mode[type][i]];
|
|
|
+ if (val) found.push(val);
|
|
|
+ }
|
|
|
+ } else if (mode.helperType && help[mode.helperType]) {
|
|
|
+ found.push(help[mode.helperType]);
|
|
|
+ } else if (help[mode.name]) {
|
|
|
+ found.push(help[mode.name]);
|
|
|
+ }
|
|
|
+ for (var i = 0; i < help._global.length; i++) {
|
|
|
+ var cur = help._global[i];
|
|
|
+ if (cur.pred(mode, this) && indexOf(found, cur.val) == -1)
|
|
|
+ found.push(cur.val);
|
|
|
+ }
|
|
|
+ return found;
|
|
|
},
|
|
|
|
|
|
getStateAfter: function(line, precise) {
|
|
|
@@ -3161,14 +3194,18 @@ window.CodeMirror = (function() {
|
|
|
},
|
|
|
|
|
|
moveV: operation(null, function(dir, unit) {
|
|
|
- var sel = this.doc.sel;
|
|
|
- var pos = cursorCoords(this, sel.head, "div");
|
|
|
- if (sel.goalColumn != null) pos.left = sel.goalColumn;
|
|
|
- var target = findPosV(this, pos, dir, unit);
|
|
|
-
|
|
|
- if (unit == "page") addToScrollPos(this, 0, charCoords(this, target, "div").top - pos.top);
|
|
|
+ var sel = this.doc.sel, target, goal;
|
|
|
+ if (sel.shift || sel.extend || posEq(sel.from, sel.to)) {
|
|
|
+ var pos = cursorCoords(this, sel.head, "div");
|
|
|
+ if (sel.goalColumn != null) pos.left = sel.goalColumn;
|
|
|
+ target = findPosV(this, pos, dir, unit);
|
|
|
+ if (unit == "page") addToScrollPos(this, 0, charCoords(this, target, "div").top - pos.top);
|
|
|
+ goal = pos.left;
|
|
|
+ } else {
|
|
|
+ target = dir < 0 ? sel.from : sel.to;
|
|
|
+ }
|
|
|
extendSelection(this.doc, target, target, dir);
|
|
|
- sel.goalColumn = pos.left;
|
|
|
+ if (goal != null) sel.goalColumn = goal;
|
|
|
}),
|
|
|
|
|
|
toggleOverwrite: function(value) {
|
|
|
@@ -3278,7 +3315,7 @@ window.CodeMirror = (function() {
|
|
|
option("indentWithTabs", false);
|
|
|
option("smartIndent", true);
|
|
|
option("tabSize", 4, function(cm) {
|
|
|
- loadMode(cm);
|
|
|
+ resetModeState(cm);
|
|
|
clearCaches(cm);
|
|
|
regChange(cm);
|
|
|
}, true);
|
|
|
@@ -3331,6 +3368,7 @@ window.CodeMirror = (function() {
|
|
|
if (!val) resetInput(cm, true);
|
|
|
}
|
|
|
});
|
|
|
+ option("disableInput", false, function(cm, val) {if (!val) resetInput(cm, true);}, true);
|
|
|
option("dragDrop", true);
|
|
|
|
|
|
option("cursorBlinkRate", 530);
|
|
|
@@ -3338,12 +3376,13 @@ window.CodeMirror = (function() {
|
|
|
option("cursorHeight", 1);
|
|
|
option("workTime", 100);
|
|
|
option("workDelay", 100);
|
|
|
- option("flattenSpans", true);
|
|
|
+ option("flattenSpans", true, resetModeState, true);
|
|
|
+ option("addModeClass", false, resetModeState, true);
|
|
|
option("pollInterval", 100);
|
|
|
option("undoDepth", 40, function(cm, val){cm.doc.history.undoDepth = val;});
|
|
|
option("historyEventDelay", 500);
|
|
|
option("viewportMargin", 10, function(cm){cm.refresh();}, true);
|
|
|
- option("maxHighlightLength", 10000, function(cm){loadMode(cm); cm.refresh();}, true);
|
|
|
+ option("maxHighlightLength", 10000, resetModeState, true);
|
|
|
option("crudeMeasuringFrom", 10000);
|
|
|
option("moveInputWithCursor", true, function(cm, val) {
|
|
|
if (!val) cm.display.inputDiv.style.top = cm.display.inputDiv.style.left = 0;
|
|
|
@@ -3400,6 +3439,9 @@ window.CodeMirror = (function() {
|
|
|
}
|
|
|
}
|
|
|
modeObj.name = spec.name;
|
|
|
+ if (spec.helperType) modeObj.helperType = spec.helperType;
|
|
|
+ if (spec.modeProps) for (var prop in spec.modeProps)
|
|
|
+ modeObj[prop] = spec.modeProps[prop];
|
|
|
|
|
|
return modeObj;
|
|
|
};
|
|
|
@@ -3430,9 +3472,13 @@ window.CodeMirror = (function() {
|
|
|
|
|
|
var helpers = CodeMirror.helpers = {};
|
|
|
CodeMirror.registerHelper = function(type, name, value) {
|
|
|
- if (!helpers.hasOwnProperty(type)) helpers[type] = CodeMirror[type] = {};
|
|
|
+ if (!helpers.hasOwnProperty(type)) helpers[type] = CodeMirror[type] = {_global: []};
|
|
|
helpers[type][name] = value;
|
|
|
};
|
|
|
+ CodeMirror.registerGlobalHelper = function(type, name, predicate, value) {
|
|
|
+ CodeMirror.registerHelper(type, name, value);
|
|
|
+ helpers[type]._global.push({pred: predicate, val: value});
|
|
|
+ };
|
|
|
|
|
|
// UTILITIES
|
|
|
|
|
|
@@ -3537,7 +3583,9 @@ window.CodeMirror = (function() {
|
|
|
indentAuto: function(cm) {cm.indentSelection("smart");},
|
|
|
indentMore: function(cm) {cm.indentSelection("add");},
|
|
|
indentLess: function(cm) {cm.indentSelection("subtract");},
|
|
|
- insertTab: function(cm) {cm.replaceSelection("\t", "end", "+input");},
|
|
|
+ insertTab: function(cm) {
|
|
|
+ cm.replaceSelection("\t", "end", "+input");
|
|
|
+ },
|
|
|
defaultTab: function(cm) {
|
|
|
if (cm.somethingSelected()) cm.indentSelection("add");
|
|
|
else cm.replaceSelection("\t", "end", "+input");
|
|
|
@@ -3826,7 +3874,7 @@ window.CodeMirror = (function() {
|
|
|
if (withOp) endOperation(cm);
|
|
|
};
|
|
|
|
|
|
- TextMarker.prototype.find = function() {
|
|
|
+ TextMarker.prototype.find = function(bothSides) {
|
|
|
var from, to;
|
|
|
for (var i = 0; i < this.lines.length; ++i) {
|
|
|
var line = this.lines[i];
|
|
|
@@ -3837,7 +3885,7 @@ window.CodeMirror = (function() {
|
|
|
if (span.to != null) to = Pos(found, span.to);
|
|
|
}
|
|
|
}
|
|
|
- if (this.type == "bookmark") return from;
|
|
|
+ if (this.type == "bookmark" && !bothSides) return from;
|
|
|
return from && {from: from, to: to};
|
|
|
};
|
|
|
|
|
|
@@ -3874,6 +3922,8 @@ window.CodeMirror = (function() {
|
|
|
}
|
|
|
};
|
|
|
|
|
|
+ var nextMarkerId = 0;
|
|
|
+
|
|
|
function markText(doc, from, to, options, type) {
|
|
|
if (options && options.shared) return markTextShared(doc, from, to, options, type);
|
|
|
if (doc.cm && !doc.cm.curOp) return operation(doc.cm, markText)(doc, from, to, options, type);
|
|
|
@@ -3887,25 +3937,25 @@ window.CodeMirror = (function() {
|
|
|
marker.replacedWith = elt("span", [marker.replacedWith], "CodeMirror-widget");
|
|
|
if (!options.handleMouseEvents) marker.replacedWith.ignoreEvents = true;
|
|
|
}
|
|
|
- if (marker.collapsed) sawCollapsedSpans = true;
|
|
|
+ if (marker.collapsed) {
|
|
|
+ if (conflictingCollapsedRange(doc, from.line, from, to, marker) ||
|
|
|
+ from.line != to.line && conflictingCollapsedRange(doc, to.line, from, to, marker))
|
|
|
+ throw new Error("Inserting collapsed marker partially overlapping an existing one");
|
|
|
+ sawCollapsedSpans = true;
|
|
|
+ }
|
|
|
|
|
|
if (marker.addToHistory)
|
|
|
addToHistory(doc, {from: from, to: to, origin: "markText"},
|
|
|
{head: doc.sel.head, anchor: doc.sel.anchor}, NaN);
|
|
|
|
|
|
- var curLine = from.line, size = 0, collapsedAtStart, collapsedAtEnd, cm = doc.cm, updateMaxLine;
|
|
|
+ var curLine = from.line, cm = doc.cm, updateMaxLine;
|
|
|
doc.iter(curLine, to.line + 1, function(line) {
|
|
|
if (cm && marker.collapsed && !cm.options.lineWrapping && visualLine(doc, line) == cm.display.maxLine)
|
|
|
updateMaxLine = true;
|
|
|
var span = {from: null, to: null, marker: marker};
|
|
|
- size += line.text.length;
|
|
|
- if (curLine == from.line) {span.from = from.ch; size -= from.ch;}
|
|
|
- if (curLine == to.line) {span.to = to.ch; size -= line.text.length - to.ch;}
|
|
|
- if (marker.collapsed) {
|
|
|
- if (curLine == to.line) collapsedAtEnd = collapsedSpanAt(line, to.ch);
|
|
|
- if (curLine == from.line) collapsedAtStart = collapsedSpanAt(line, from.ch);
|
|
|
- else updateLineHeight(line, 0);
|
|
|
- }
|
|
|
+ if (curLine == from.line) span.from = from.ch;
|
|
|
+ if (curLine == to.line) span.to = to.ch;
|
|
|
+ if (marker.collapsed && curLine != from.line) updateLineHeight(line, 0);
|
|
|
addMarkedSpan(line, span);
|
|
|
++curLine;
|
|
|
});
|
|
|
@@ -3921,9 +3971,7 @@ window.CodeMirror = (function() {
|
|
|
doc.clearHistory();
|
|
|
}
|
|
|
if (marker.collapsed) {
|
|
|
- if (collapsedAtStart != collapsedAtEnd)
|
|
|
- throw new Error("Inserting collapsed marker overlapping an existing one");
|
|
|
- marker.size = size;
|
|
|
+ marker.id = ++nextMarkerId;
|
|
|
marker.atomic = true;
|
|
|
}
|
|
|
if (cm) {
|
|
|
@@ -4139,20 +4187,48 @@ window.CodeMirror = (function() {
|
|
|
return parts;
|
|
|
}
|
|
|
|
|
|
- function collapsedSpanAt(line, ch) {
|
|
|
+ function extraLeft(marker) { return marker.inclusiveLeft ? -1 : 0; }
|
|
|
+ function extraRight(marker) { return marker.inclusiveRight ? 1 : 0; }
|
|
|
+
|
|
|
+ function compareCollapsedMarkers(a, b) {
|
|
|
+ var lenDiff = a.lines.length - b.lines.length;
|
|
|
+ if (lenDiff != 0) return lenDiff;
|
|
|
+ var aPos = a.find(), bPos = b.find();
|
|
|
+ var fromCmp = cmp(aPos.from, bPos.from) || extraLeft(a) - extraLeft(b);
|
|
|
+ if (fromCmp) return -fromCmp;
|
|
|
+ var toCmp = cmp(aPos.to, bPos.to) || extraRight(a) - extraRight(b);
|
|
|
+ if (toCmp) return toCmp;
|
|
|
+ return b.id - a.id;
|
|
|
+ }
|
|
|
+
|
|
|
+ function collapsedSpanAtSide(line, start) {
|
|
|
var sps = sawCollapsedSpans && line.markedSpans, found;
|
|
|
if (sps) for (var sp, i = 0; i < sps.length; ++i) {
|
|
|
sp = sps[i];
|
|
|
- if (!sp.marker.collapsed) continue;
|
|
|
- if ((sp.from == null || sp.from < ch) &&
|
|
|
- (sp.to == null || sp.to > ch) &&
|
|
|
- (!found || found.width < sp.marker.width))
|
|
|
+ if (sp.marker.collapsed && (start ? sp.from : sp.to) == null &&
|
|
|
+ (!found || compareCollapsedMarkers(found, sp.marker) < 0))
|
|
|
found = sp.marker;
|
|
|
}
|
|
|
return found;
|
|
|
}
|
|
|
- function collapsedSpanAtStart(line) { return collapsedSpanAt(line, -1); }
|
|
|
- function collapsedSpanAtEnd(line) { return collapsedSpanAt(line, line.text.length + 1); }
|
|
|
+ function collapsedSpanAtStart(line) { return collapsedSpanAtSide(line, true); }
|
|
|
+ function collapsedSpanAtEnd(line) { return collapsedSpanAtSide(line, false); }
|
|
|
+
|
|
|
+ function conflictingCollapsedRange(doc, lineNo, from, to, marker) {
|
|
|
+ var line = getLine(doc, lineNo);
|
|
|
+ var sps = sawCollapsedSpans && line.markedSpans;
|
|
|
+ if (sps) for (var i = 0; i < sps.length; ++i) {
|
|
|
+ var sp = sps[i];
|
|
|
+ if (!sp.marker.collapsed) continue;
|
|
|
+ var found = sp.marker.find(true);
|
|
|
+ var fromCmp = cmp(found.from, from) || extraLeft(sp.marker) - extraLeft(marker);
|
|
|
+ var toCmp = cmp(found.to, to) || extraRight(sp.marker) - extraRight(marker);
|
|
|
+ if (fromCmp >= 0 && toCmp <= 0 || fromCmp <= 0 && toCmp >= 0) continue;
|
|
|
+ if (fromCmp <= 0 && (cmp(found.to, from) || extraRight(sp.marker) - extraLeft(marker)) > 0 ||
|
|
|
+ fromCmp >= 0 && (cmp(found.from, to) || extraLeft(sp.marker) - extraRight(marker)) < 0)
|
|
|
+ return true;
|
|
|
+ }
|
|
|
+ }
|
|
|
|
|
|
function visualLine(doc, line) {
|
|
|
var merged;
|
|
|
@@ -4312,6 +4388,10 @@ window.CodeMirror = (function() {
|
|
|
} else {
|
|
|
style = mode.token(stream, state);
|
|
|
}
|
|
|
+ if (cm.options.addModeClass) {
|
|
|
+ var mName = CodeMirror.innerMode(mode, state).mode.name;
|
|
|
+ if (mName) style = "m-" + (style ? mName + " " + style : mName);
|
|
|
+ }
|
|
|
if (!flattenSpans || curStyle != style) {
|
|
|
if (curStart < stream.start) f(stream.start, curStyle);
|
|
|
curStart = stream.start; curStyle = style;
|
|
|
@@ -4383,7 +4463,7 @@ window.CodeMirror = (function() {
|
|
|
}
|
|
|
}
|
|
|
|
|
|
- var styleToClassCache = {};
|
|
|
+ var styleToClassCache = {}, styleToClassCacheWithMode = {};
|
|
|
function interpretTokenStyle(style, builder) {
|
|
|
if (!style) return null;
|
|
|
for (;;) {
|
|
|
@@ -4396,8 +4476,9 @@ window.CodeMirror = (function() {
|
|
|
else if (!(new RegExp("(?:^|\s)" + lineClass[2] + "(?:$|\s)")).test(builder[prop]))
|
|
|
builder[prop] += " " + lineClass[2];
|
|
|
}
|
|
|
- return styleToClassCache[style] ||
|
|
|
- (styleToClassCache[style] = "cm-" + style.replace(/ +/g, " cm-"));
|
|
|
+ var cache = builder.cm.options.addModeClass ? styleToClassCacheWithMode : styleToClassCache;
|
|
|
+ return cache[style] ||
|
|
|
+ (cache[style] = "cm-" + style.replace(/ +/g, " cm-"));
|
|
|
}
|
|
|
|
|
|
function buildLineContent(cm, realLine, measure, copyWidgets) {
|
|
|
@@ -4414,7 +4495,7 @@ window.CodeMirror = (function() {
|
|
|
builder.measure = line == realLine && measure;
|
|
|
builder.pos = 0;
|
|
|
builder.addToken = builder.measure ? buildTokenMeasure : buildToken;
|
|
|
- if ((ie || webkit) && cm.getOption("lineWrapping"))
|
|
|
+ if ((old_ie || webkit) && cm.getOption("lineWrapping"))
|
|
|
builder.addToken = buildTokenSplitSpaces(builder.addToken);
|
|
|
var next = insertLineContent(line, builder, getLineStyles(cm, line));
|
|
|
if (measure && line == realLine && !builder.measuredSomething) {
|
|
|
@@ -4433,7 +4514,7 @@ window.CodeMirror = (function() {
|
|
|
// Work around problem with the reported dimensions of single-char
|
|
|
// direction spans on IE (issue #1129). See also the comment in
|
|
|
// cursorCoords.
|
|
|
- if (measure && (ie || ie_gt10) && (order = getOrder(line))) {
|
|
|
+ if (measure && ie && (order = getOrder(line))) {
|
|
|
var l = order.length - 1;
|
|
|
if (order[l].from == order[l].to) --l;
|
|
|
var last = order[l], prev = order[l - 1];
|
|
|
@@ -4500,13 +4581,12 @@ window.CodeMirror = (function() {
|
|
|
function buildTokenMeasure(builder, text, style, startStyle, endStyle) {
|
|
|
var wrapping = builder.cm.options.lineWrapping;
|
|
|
for (var i = 0; i < text.length; ++i) {
|
|
|
- var ch = text.charAt(i), start = i == 0;
|
|
|
- if (ch >= "\ud800" && ch < "\udbff" && i < text.length - 1) {
|
|
|
- ch = text.slice(i, i + 2);
|
|
|
- ++i;
|
|
|
- } else if (i && wrapping && spanAffectsWrapping(text, i)) {
|
|
|
+ var start = i == 0, to = i + 1;
|
|
|
+ while (to < text.length && isExtendingChar(text.charAt(to))) ++to;
|
|
|
+ var ch = text.slice(i, to);
|
|
|
+ i = to - 1;
|
|
|
+ if (i && wrapping && spanAffectsWrapping(text, i))
|
|
|
builder.pre.appendChild(elt("wbr"));
|
|
|
- }
|
|
|
var old = builder.measure[builder.pos];
|
|
|
var span = builder.measure[builder.pos] =
|
|
|
buildToken(builder, ch, style,
|
|
|
@@ -4515,7 +4595,7 @@ window.CodeMirror = (function() {
|
|
|
// In IE single-space nodes wrap differently than spaces
|
|
|
// embedded in larger text nodes, except when set to
|
|
|
// white-space: normal (issue #1268).
|
|
|
- if (ie && wrapping && ch == " " && i && !/\s/.test(text.charAt(i - 1)) &&
|
|
|
+ if (old_ie && wrapping && ch == " " && i && !/\s/.test(text.charAt(i - 1)) &&
|
|
|
i < text.length - 1 && !/\s/.test(text.charAt(i + 1)))
|
|
|
span.style.whiteSpace = "normal";
|
|
|
builder.pos += ch.length;
|
|
|
@@ -4583,7 +4663,7 @@ window.CodeMirror = (function() {
|
|
|
if (m.startStyle && sp.from == pos) spanStartStyle += " " + m.startStyle;
|
|
|
if (m.endStyle && sp.to == nextChange) spanEndStyle += " " + m.endStyle;
|
|
|
if (m.title && !title) title = m.title;
|
|
|
- if (m.collapsed && (!collapsed || collapsed.marker.size < m.size))
|
|
|
+ if (m.collapsed && (!collapsed || compareCollapsedMarkers(collapsed.marker, m) < 0))
|
|
|
collapsed = sp;
|
|
|
} else if (sp.from > pos && nextChange > sp.from) {
|
|
|
nextChange = sp.from;
|
|
|
@@ -4916,10 +4996,11 @@ window.CodeMirror = (function() {
|
|
|
clearHistory: function() {this.history = makeHistory(this.history.maxGeneration);},
|
|
|
|
|
|
markClean: function() {
|
|
|
- this.cleanGeneration = this.changeGeneration();
|
|
|
+ this.cleanGeneration = this.changeGeneration(true);
|
|
|
},
|
|
|
- changeGeneration: function() {
|
|
|
- this.history.lastOp = this.history.lastOrigin = null;
|
|
|
+ changeGeneration: function(forceSplit) {
|
|
|
+ if (forceSplit)
|
|
|
+ this.history.lastOp = this.history.lastOrigin = null;
|
|
|
return this.history.generation;
|
|
|
},
|
|
|
isClean: function (gen) {
|
|
|
@@ -5223,10 +5304,10 @@ window.CodeMirror = (function() {
|
|
|
anchorBefore: doc.sel.anchor, headBefore: doc.sel.head,
|
|
|
anchorAfter: selAfter.anchor, headAfter: selAfter.head};
|
|
|
hist.done.push(cur);
|
|
|
- hist.generation = ++hist.maxGeneration;
|
|
|
while (hist.done.length > hist.undoDepth)
|
|
|
hist.done.shift();
|
|
|
}
|
|
|
+ hist.generation = ++hist.maxGeneration;
|
|
|
hist.lastTime = time;
|
|
|
hist.lastOp = opId;
|
|
|
hist.lastOrigin = change.origin;
|
|
|
@@ -5522,7 +5603,8 @@ window.CodeMirror = (function() {
|
|
|
return true;
|
|
|
}
|
|
|
|
|
|
- var isExtendingChar = /[\u0300-\u036F\u0483-\u0487\u0488-\u0489\u0591-\u05BD\u05BF\u05C1-\u05C2\u05C4-\u05C5\u05C7\u0610-\u061A\u064B-\u065F\u0670\u06D6-\u06DC\u06DF-\u06E4\u06E7-\u06E8\u06EA-\u06ED\uA66F\u1DC0-\u1DFF\u20D0-\u20FF\uA670-\uA672\uA674-\uA67D\uA69F\udc00-\udfff\uFE20-\uFE2F]/;
|
|
|
+ var extendingChars = /[\u0300-\u036f\u0483-\u0489\u0591-\u05bd\u05bf\u05c1\u05c2\u05c4\u05c5\u05c7\u0610-\u061a\u064b-\u065e\u0670\u06d6-\u06dc\u06de-\u06e4\u06e7\u06e8\u06ea-\u06ed\u0711\u0730-\u074a\u07a6-\u07b0\u07eb-\u07f3\u0816-\u0819\u081b-\u0823\u0825-\u0827\u0829-\u082d\u0900-\u0902\u093c\u0941-\u0948\u094d\u0951-\u0955\u0962\u0963\u0981\u09bc\u09be\u09c1-\u09c4\u09cd\u09d7\u09e2\u09e3\u0a01\u0a02\u0a3c\u0a41\u0a42\u0a47\u0a48\u0a4b-\u0a4d\u0a51\u0a70\u0a71\u0a75\u0a81\u0a82\u0abc\u0ac1-\u0ac5\u0ac7\u0ac8\u0acd\u0ae2\u0ae3\u0b01\u0b3c\u0b3e\u0b3f\u0b41-\u0b44\u0b4d\u0b56\u0b57\u0b62\u0b63\u0b82\u0bbe\u0bc0\u0bcd\u0bd7\u0c3e-\u0c40\u0c46-\u0c48\u0c4a-\u0c4d\u0c55\u0c56\u0c62\u0c63\u0cbc\u0cbf\u0cc2\u0cc6\u0ccc\u0ccd\u0cd5\u0cd6\u0ce2\u0ce3\u0d3e\u0d41-\u0d44\u0d4d\u0d57\u0d62\u0d63\u0dca\u0dcf\u0dd2-\u0dd4\u0dd6\u0ddf\u0e31\u0e34-\u0e3a\u0e47-\u0e4e\u0eb1\u0eb4-\u0eb9\u0ebb\u0ebc\u0ec8-\u0ecd\u0f18\u0f19\u0f35\u0f37\u0f39\u0f71-\u0f7e\u0f80-\u0f84\u0f86\u0f87\u0f90-\u0f97\u0f99-\u0fbc\u0fc6\u102d-\u1030\u1032-\u1037\u1039\u103a\u103d\u103e\u1058\u1059\u105e-\u1060\u1071-\u1074\u1082\u1085\u1086\u108d\u109d\u135f\u1712-\u1714\u1732-\u1734\u1752\u1753\u1772\u1773\u17b7-\u17bd\u17c6\u17c9-\u17d3\u17dd\u180b-\u180d\u18a9\u1920-\u1922\u1927\u1928\u1932\u1939-\u193b\u1a17\u1a18\u1a56\u1a58-\u1a5e\u1a60\u1a62\u1a65-\u1a6c\u1a73-\u1a7c\u1a7f\u1b00-\u1b03\u1b34\u1b36-\u1b3a\u1b3c\u1b42\u1b6b-\u1b73\u1b80\u1b81\u1ba2-\u1ba5\u1ba8\u1ba9\u1c2c-\u1c33\u1c36\u1c37\u1cd0-\u1cd2\u1cd4-\u1ce0\u1ce2-\u1ce8\u1ced\u1dc0-\u1de6\u1dfd-\u1dff\u200c\u200d\u20d0-\u20f0\u2cef-\u2cf1\u2de0-\u2dff\u302a-\u302f\u3099\u309a\ua66f-\ua672\ua67c\ua67d\ua6f0\ua6f1\ua802\ua806\ua80b\ua825\ua826\ua8c4\ua8e0-\ua8f1\ua926-\ua92d\ua947-\ua951\ua980-\ua982\ua9b3\ua9b6-\ua9b9\ua9bc\uaa29-\uaa2e\uaa31\uaa32\uaa35\uaa36\uaa43\uaa4c\uaab0\uaab2-\uaab4\uaab7\uaab8\uaabe\uaabf\uaac1\uabe5\uabe8\uabed\udc00-\udfff\ufb1e\ufe00-\ufe0f\ufe20-\ufe26\uff9e\uff9f]/;
|
|
|
+ function isExtendingChar(ch) { return ch.charCodeAt(0) >= 768 && extendingChars.test(ch); }
|
|
|
|
|
|
// DOM UTILITIES
|
|
|
|
|
|
@@ -5663,14 +5745,14 @@ window.CodeMirror = (function() {
|
|
|
var keyNames = {3: "Enter", 8: "Backspace", 9: "Tab", 13: "Enter", 16: "Shift", 17: "Ctrl", 18: "Alt",
|
|
|
19: "Pause", 20: "CapsLock", 27: "Esc", 32: "Space", 33: "PageUp", 34: "PageDown", 35: "End",
|
|
|
36: "Home", 37: "Left", 38: "Up", 39: "Right", 40: "Down", 44: "PrintScrn", 45: "Insert",
|
|
|
- 46: "Delete", 59: ";", 91: "Mod", 92: "Mod", 93: "Mod", 109: "-", 107: "=", 127: "Delete",
|
|
|
- 186: ";", 187: "=", 188: ",", 189: "-", 190: ".", 191: "/", 192: "`", 219: "[", 220: "\\",
|
|
|
- 221: "]", 222: "'", 63276: "PageUp", 63277: "PageDown", 63275: "End", 63273: "Home",
|
|
|
- 63234: "Left", 63232: "Up", 63235: "Right", 63233: "Down", 63302: "Insert", 63272: "Delete"};
|
|
|
+ 46: "Delete", 59: ";", 61: "=", 91: "Mod", 92: "Mod", 93: "Mod", 107: "=", 109: "-", 127: "Delete",
|
|
|
+ 173: "-", 186: ";", 187: "=", 188: ",", 189: "-", 190: ".", 191: "/", 192: "`", 219: "[", 220: "\\",
|
|
|
+ 221: "]", 222: "'", 63232: "Up", 63233: "Down", 63234: "Left", 63235: "Right", 63272: "Delete",
|
|
|
+ 63273: "Home", 63275: "End", 63276: "PageUp", 63277: "PageDown", 63302: "Insert"};
|
|
|
CodeMirror.keyNames = keyNames;
|
|
|
(function() {
|
|
|
// Number keys
|
|
|
- for (var i = 0; i < 10; i++) keyNames[i + 48] = String(i);
|
|
|
+ for (var i = 0; i < 10; i++) keyNames[i + 48] = keyNames[i + 96] = String(i);
|
|
|
// Alphabetic keys
|
|
|
for (var i = 65; i <= 90; i++) keyNames[i] = String.fromCharCode(i);
|
|
|
// Function keys
|
|
|
@@ -5749,7 +5831,7 @@ window.CodeMirror = (function() {
|
|
|
function moveInLine(line, pos, dir, byUnit) {
|
|
|
if (!byUnit) return pos + dir;
|
|
|
do pos += dir;
|
|
|
- while (pos > 0 && isExtendingChar.test(line.text.charAt(pos)));
|
|
|
+ while (pos > 0 && isExtendingChar(line.text.charAt(pos)));
|
|
|
return pos;
|
|
|
}
|
|
|
|
|
|
@@ -5784,7 +5866,7 @@ window.CodeMirror = (function() {
|
|
|
|
|
|
function moveLogically(line, start, dir, byUnit) {
|
|
|
var target = start + dir;
|
|
|
- if (byUnit) while (target > 0 && isExtendingChar.test(line.text.charAt(target))) target += dir;
|
|
|
+ if (byUnit) while (target > 0 && isExtendingChar(line.text.charAt(target))) target += dir;
|
|
|
return target < 0 || target > line.text.length ? null : target;
|
|
|
}
|
|
|
|