Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with
or
.
Download ZIP
Browse files

upgraded codemirror to 3.02

  • Loading branch information...
commit c440d46341d4120132410c4eab6ed22b8645c8b6 1 parent d9ad4e7
@mikz mikz authored committed
Showing with 2,180 additions and 789 deletions.
  1. +385 −152 vendor/assets/javascripts/codemirror.js
  2. +279 −66 vendor/assets/javascripts/codemirror/keymaps/vim.js
  3. +160 −0 vendor/assets/javascripts/codemirror/modes/apl.js
  4. +183 −0 vendor/assets/javascripts/codemirror/modes/asterisk.js
  5. +2 −0  vendor/assets/javascripts/codemirror/modes/clike.js
  6. +3 −3 vendor/assets/javascripts/codemirror/modes/clojure.js
  7. +2 −2 vendor/assets/javascripts/codemirror/modes/css.js
  8. +205 −0 vendor/assets/javascripts/codemirror/modes/d.js
  9. +2 −1  vendor/assets/javascripts/codemirror/modes/gfm.js
  10. +13 −2 vendor/assets/javascripts/codemirror/modes/javascript.js
  11. +8 −7 vendor/assets/javascripts/codemirror/modes/markdown.js
  12. 0  vendor/assets/javascripts/codemirror/modes/properties.js
  13. +349 −0 vendor/assets/javascripts/codemirror/modes/sass.js
  14. +37 −10 vendor/assets/javascripts/codemirror/modes/sieve.js
  15. +268 −0 vendor/assets/javascripts/codemirror/modes/sql.js
  16. +0 −490 vendor/assets/javascripts/codemirror/modes/xmlpure.js
  17. +8 −8 vendor/assets/javascripts/codemirror/modes/xquery.js
  18. +68 −0 vendor/assets/javascripts/codemirror/utils/collapserange.js
  19. +1 −0  vendor/assets/javascripts/codemirror/utils/dialog.js
  20. +2 −1  vendor/assets/javascripts/codemirror/utils/foldcode.js
  21. +9 −3 vendor/assets/javascripts/codemirror/utils/formatting.js
  22. +5 −4 vendor/assets/javascripts/codemirror/utils/javascript-hint.js
  23. +93 −0 vendor/assets/javascripts/codemirror/utils/python-hint.js
  24. +51 −10 vendor/assets/javascripts/codemirror/utils/runmode-standalone.js
  25. +20 −8 vendor/assets/javascripts/codemirror/utils/search.js
  26. +17 −10 vendor/assets/javascripts/codemirror/utils/searchcursor.js
  27. +10 −9 vendor/assets/stylesheets/codemirror.css
  28. +0 −3  vendor/assets/stylesheets/codemirror/modes/diff.css
View
537 vendor/assets/javascripts/codemirror.js
@@ -1,4 +1,4 @@
-// CodeMirror version 3.0
+// CodeMirror version 3.02
//
// CodeMirror is the only global var we claim
window.CodeMirror = (function() {
@@ -10,8 +10,8 @@ window.CodeMirror = (function() {
// bugs and behavior differences.
var gecko = /gecko\/\d/i.test(navigator.userAgent);
var ie = /MSIE \d/.test(navigator.userAgent);
- var ie_lt8 = /MSIE [1-7]\b/.test(navigator.userAgent);
- var ie_lt9 = /MSIE [1-8]\b/.test(navigator.userAgent);
+ var ie_lt8 = ie && (document.documentMode == null || document.documentMode < 8);
+ var ie_lt9 = ie && (document.documentMode == null || document.documentMode < 9);
var webkit = /WebKit\//.test(navigator.userAgent);
var qtwebkit = webkit && /Qt\/\d+\.\d+/.test(navigator.userAgent);
var chrome = /Chrome\//.test(navigator.userAgent);
@@ -24,8 +24,14 @@ window.CodeMirror = (function() {
var ios = /AppleWebKit/.test(navigator.userAgent) && /Mobile\/\w+/.test(navigator.userAgent);
// This is woefully incomplete. Suggestions for alternative methods welcome.
- var mobile = ios || /Android|webOS|BlackBerry|Opera Mini|IEMobile/i.test(navigator.userAgent);
+ var mobile = ios || /Android|webOS|BlackBerry|Opera Mini|Opera Mobi|IEMobile/i.test(navigator.userAgent);
var mac = ios || /Mac/.test(navigator.platform);
+ var windows = /windows/i.test(navigator.platform);
+
+ var opera_version = opera && navigator.userAgent.match(/Version\/(\d*\.\d*)/);
+ if (opera_version) opera_version = Number(opera_version[1]);
+ // 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));
// Optimize some code when these features are not used
var sawReadOnlySpans = false, sawCollapsedSpans = false;
@@ -80,7 +86,9 @@ window.CodeMirror = (function() {
function makeDisplay(place) {
var d = {};
var input = d.input = elt("textarea", null, null, "position: absolute; padding: 0; width: 1px; height: 1em; outline: none;");
- input.setAttribute("wrap", "off"); input.setAttribute("autocorrect", "off"); input.setAttribute("autocapitalize", "off");
+ if (webkit) input.style.width = "1000px";
+ else input.setAttribute("wrap", "off");
+ input.setAttribute("autocorrect", "off"); input.setAttribute("autocapitalize", "off");
// Wraps and hides input textarea
d.inputDiv = elt("div", [input], null, "overflow: hidden; position: relative; width: 3px; height: 0px;");
// The actual fake scrollbars.
@@ -91,9 +99,9 @@ window.CodeMirror = (function() {
d.lineDiv = elt("div");
d.selectionDiv = elt("div", null, null, "position: relative; z-index: 1");
// Blinky cursor, and element used to ensure cursor fits at the end of a line
- d.cursor = elt("pre", "\u00a0", "CodeMirror-cursor");
+ d.cursor = elt("div", "\u00a0", "CodeMirror-cursor");
// Secondary cursor, shown when on a 'jump' in bi-directional text
- d.otherCursor = elt("pre", "\u00a0", "CodeMirror-cursor CodeMirror-secondarycursor");
+ d.otherCursor = elt("div", "\u00a0", "CodeMirror-cursor CodeMirror-secondarycursor");
// Used to measure text size
d.measure = elt("div", null, "CodeMirror-measure");
// Wraps everything that needs to exist inside the vertically-padded coordinate system
@@ -160,6 +168,9 @@ window.CodeMirror = (function() {
// detected
d.pasteIncoming = false;
+ // Used for measuring wheel scrolling granularity
+ d.wheelDX = d.wheelDY = d.wheelStartX = d.wheelStartY = null;
+
return d;
}
@@ -183,7 +194,9 @@ window.CodeMirror = (function() {
suppressEdits: false,
goalColumn: null,
cantEdit: false,
- keyMaps: []
+ keyMaps: [],
+ overlays: [],
+ modeGen: 0
};
}
@@ -194,9 +207,14 @@ window.CodeMirror = (function() {
function loadMode(cm) {
var doc = cm.view.doc;
cm.view.mode = CodeMirror.getMode(cm.options, cm.options.mode);
- doc.iter(0, doc.size, function(line) { line.stateAfter = null; });
+ doc.iter(0, doc.size, function(line) {
+ if (line.stateAfter) line.stateAfter = null;
+ if (line.styles) line.styles = null;
+ });
cm.view.frontier = 0;
startWorker(cm, 100);
+ cm.view.modeGen++;
+ if (cm.curOp) regChange(cm, 0, doc.size);
}
function wrappingChanged(cm) {
@@ -342,13 +360,14 @@ window.CodeMirror = (function() {
function alignHorizontally(cm) {
var display = cm.display;
- if (!display.alignWidgets && !display.gutters.firstChild) return;
+ if (!display.alignWidgets && (!display.gutters.firstChild || !cm.options.fixedGutter)) return;
var comp = compensateForHScroll(display) - display.scroller.scrollLeft + cm.view.scrollLeft;
var gutterW = display.gutters.offsetWidth, l = comp + "px";
for (var n = display.lineDiv.firstChild; n; n = n.nextSibling) if (n.alignable) {
for (var i = 0, a = n.alignable; i < a.length; ++i) a[i].style.left = l;
}
- display.gutters.style.left = (comp + gutterW) + "px";
+ if (cm.options.fixedGutter)
+ display.gutters.style.left = (comp + gutterW) + "px";
}
function maybeUpdateLineNumberWidth(cm) {
@@ -412,7 +431,8 @@ window.CodeMirror = (function() {
if (changes && maybeUpdateLineNumberWidth(cm))
changes = true;
- display.sizer.style.marginLeft = display.scrollbarH.style.left = display.gutters.offsetWidth + "px";
+ var gutterW = display.sizer.style.marginLeft = display.gutters.offsetWidth + "px";
+ display.scrollbarH.style.left = cm.options.fixedGutter ? gutterW : "0";
// When merged lines are present, the line that needs to be
// redrawn might not be the one that was changed.
@@ -458,9 +478,11 @@ window.CodeMirror = (function() {
return;
intact.sort(function(a, b) {return a.from - b.from;});
+ var focused = document.activeElement;
if (intactLines < (to - from) * .7) display.lineDiv.style.display = "none";
patchDisplay(cm, from, to, intact, positionsChangedFrom);
display.lineDiv.style.display = "";
+ if (document.activeElement != focused && focused.offsetHeight) focused.focus();
var different = from != display.showingFrom || to != display.showingTo ||
display.lastSizeC != display.wrapper.clientHeight;
@@ -482,12 +504,19 @@ window.CodeMirror = (function() {
}
var diff = node.lineObj.height - height;
if (height < 2) height = textHeight(display);
- if (diff > .001 || diff < -.001)
+ if (diff > .001 || diff < -.001) {
updateLineHeight(node.lineObj, height);
+ var widgets = node.lineObj.widgets;
+ if (widgets) for (var i = 0; i < widgets.length; ++i)
+ widgets[i].height = widgets[i].node.offsetHeight;
+ }
}
display.viewOffset = heightAtLine(cm, getLine(doc, from));
// Position the mover div to align with the current virtual scroll position
display.mover.style.top = display.viewOffset + "px";
+
+ if (visibleLines(display, doc, viewPort).to >= to)
+ updateDisplayInner(cm, [], viewPort);
return true;
}
@@ -528,9 +557,7 @@ window.CodeMirror = (function() {
function patchDisplay(cm, from, to, intact, updateNumbersFrom) {
var dims = getDimensions(cm);
var display = cm.display, lineNumbers = cm.options.lineNumbers;
- // IE does bad things to nodes when .innerHTML = "" is used on a parent
- // we still need widgets and markers intact to add back to the new content later
- if (!intact.length && !ie && (!webkit || !cm.display.currentWheelTarget))
+ if (!intact.length && (!webkit || !cm.display.currentWheelTarget))
removeChildren(display.lineDiv);
var container = display.lineDiv, cur = container.firstChild;
@@ -540,7 +567,7 @@ window.CodeMirror = (function() {
node.style.display = "none";
node.lineObj = null;
} else {
- container.removeChild(node);
+ node.parentNode.removeChild(node);
}
return next;
}
@@ -550,6 +577,17 @@ window.CodeMirror = (function() {
if (nextIntact && nextIntact.to == lineNo) nextIntact = intact.shift();
if (lineIsHidden(line)) {
if (line.height != 0) updateLineHeight(line, 0);
+ if (line.widgets && cur.previousSibling) for (var i = 0; i < line.widgets.length; ++i)
+ if (line.widgets[i].showIfHidden) {
+ var prev = cur.previousSibling;
+ if (prev.nodeType == "pre") {
+ var wrap = elt("div", null, null, "position: relative");
+ prev.parentNode.replaceChild(wrap, prev);
+ wrap.appendChild(prev);
+ prev = wrap;
+ }
+ prev.appendChild(buildLineWidget(line.widgets[i], prev, dims));
+ }
} else if (nextIntact && nextIntact.from <= lineNo && nextIntact.to > lineNo) {
// This line is intact. Skip to the actual node. Update its
// line number if needed.
@@ -582,8 +620,8 @@ window.CodeMirror = (function() {
var wrap = elt("div", null, line.wrapClass, "position: relative");
if (cm.options.lineNumbers || markers) {
var gutterWrap = wrap.appendChild(elt("div", null, null, "position: absolute; left: " +
- dims.fixedPos + "px"));
- wrap.alignable = [gutterWrap];
+ (cm.options.fixedGutter ? dims.fixedPos : -dims.gutterTotalWidth) + "px"));
+ if (cm.options.fixedGutter) wrap.alignable = [gutterWrap];
if (cm.options.lineNumbers && (!markers || !markers["CodeMirror-linenumbers"]))
wrap.lineNumber = gutterWrap.appendChild(
elt("div", lineNumberFor(cm.options, lineNo),
@@ -602,35 +640,38 @@ window.CodeMirror = (function() {
if (line.bgClass)
wrap.appendChild(elt("div", "\u00a0", line.bgClass + " CodeMirror-linebackground"));
wrap.appendChild(lineElement);
- if (line.widgets)
- for (var i = 0, ws = line.widgets; i < ws.length; ++i) {
- var widget = ws[i], node = elt("div", [widget.node], "CodeMirror-linewidget");
- node.widget = widget;
- if (widget.noHScroll) {
- (wrap.alignable || (wrap.alignable = [])).push(node);
- var width = dims.wrapperWidth;
- node.style.left = dims.fixedPos + "px";
- if (!widget.coverGutter) {
- width -= dims.gutterTotalWidth;
- node.style.paddingLeft = dims.gutterTotalWidth + "px";
- }
- node.style.width = width + "px";
- }
- if (widget.coverGutter) {
- node.style.zIndex = 5;
- node.style.position = "relative";
- if (!widget.noHScroll) node.style.marginLeft = -dims.gutterTotalWidth + "px";
- }
- if (widget.above)
- wrap.insertBefore(node, cm.options.lineNumbers && line.height != 0 ? gutterWrap : lineElement);
- else
- wrap.appendChild(node);
- }
-
+ if (line.widgets) for (var i = 0, ws = line.widgets; i < ws.length; ++i) {
+ var widget = ws[i], node = buildLineWidget(widget, wrap, dims);
+ if (widget.above)
+ wrap.insertBefore(node, cm.options.lineNumbers && line.height != 0 ? gutterWrap : lineElement);
+ else
+ wrap.appendChild(node);
+ }
if (ie_lt8) wrap.style.zIndex = 2;
return wrap;
}
+ function buildLineWidget(widget, wrap, dims) {
+ var node = elt("div", [widget.node], "CodeMirror-linewidget");
+ node.widget = widget;
+ if (widget.noHScroll) {
+ (wrap.alignable || (wrap.alignable = [])).push(node);
+ var width = dims.wrapperWidth;
+ node.style.left = dims.fixedPos + "px";
+ if (!widget.coverGutter) {
+ width -= dims.gutterTotalWidth;
+ node.style.paddingLeft = dims.gutterTotalWidth + "px";
+ }
+ node.style.width = width + "px";
+ }
+ if (widget.coverGutter) {
+ node.style.zIndex = 5;
+ node.style.position = "relative";
+ if (!widget.noHScroll) node.style.marginLeft = -dims.gutterTotalWidth + "px";
+ }
+ return node;
+ }
+
// SELECTION / CURSOR
function updateSelection(cm) {
@@ -765,7 +806,7 @@ window.CodeMirror = (function() {
// HIGHLIGHT WORKER
function startWorker(cm, time) {
- if (cm.view.frontier < cm.display.showingTo)
+ if (cm.view.mode.startState && cm.view.frontier < cm.display.showingTo)
cm.view.highlight.set(time, bind(highlightWorker, cm));
}
@@ -777,7 +818,12 @@ window.CodeMirror = (function() {
var changed = [], prevChange;
doc.iter(view.frontier, Math.min(doc.size, cm.display.showingTo + 500), function(line) {
if (view.frontier >= cm.display.showingFrom) { // Visible
- if (highlightLine(cm, line, state) && view.frontier >= cm.display.showingFrom) {
+ var oldStyles = line.styles;
+ line.styles = highlightLine(cm, line, state);
+ var ischange = !oldStyles || oldStyles.length != line.styles.length;
+ for (var i = 0; !ischange && i < oldStyles.length; ++i)
+ ischange = oldStyles[i] != line.styles[i];
+ if (ischange) {
if (prevChange && prevChange.end == view.frontier) prevChange.end++;
else changed.push(prevChange = {start: view.frontier, end: view.frontier + 1});
}
@@ -821,6 +867,7 @@ window.CodeMirror = (function() {
function getStateBefore(cm, n) {
var view = cm.view;
+ if (!view.mode.startState) return true;
var pos = findStartLine(cm, n), state = pos && getLine(view.doc, pos-1).stateAfter;
if (!state) state = startState(view.mode);
else state = copyState(view.mode, state);
@@ -842,7 +889,9 @@ window.CodeMirror = (function() {
}
function measureChar(cm, line, ch, data) {
- var data = data || measureLine(cm, line), dir = -1;
+ var dir = -1;
+ data = data || measureLine(cm, line);
+
for (var pos = ch;; pos += dir) {
var r = data[pos];
if (r) break;
@@ -938,7 +987,7 @@ window.CodeMirror = (function() {
// Context is one of "line", "div" (display.lineDiv), "local"/null (editor), or "page"
function intoCoordSystem(cm, lineObj, rect, context) {
if (lineObj.widgets) for (var i = 0; i < lineObj.widgets.length; ++i) if (lineObj.widgets[i].above) {
- var size = lineObj.widgets[i].node.offsetHeight;
+ var size = widgetHeight(lineObj.widgets[i]);
rect.top += size; rect.bottom += size;
}
if (context == "line") return rect;
@@ -1010,8 +1059,9 @@ window.CodeMirror = (function() {
var lineObj = getLine(doc, lineNo);
var found = coordsCharInner(cm, lineObj, lineNo, x, y);
var merged = collapsedSpanAtEnd(lineObj);
- if (merged && found.ch == lineRight(lineObj))
- lineNo = merged.find().to.line;
+ var mergedPos = merged && merged.find();
+ if (merged && found.ch >= mergedPos.from.ch)
+ lineNo = mergedPos.to.line;
else
return found;
}
@@ -1121,6 +1171,9 @@ window.CodeMirror = (function() {
var width = measureChar(cm, view.maxLine, view.maxLine.text.length).right;
display.sizer.style.minWidth = (width + 3 + scrollerCutOff) + "px";
view.maxLineChanged = false;
+ var maxScrollLeft = Math.max(0, display.sizer.offsetLeft + display.sizer.offsetWidth - display.scroller.clientWidth);
+ if (maxScrollLeft < view.scrollLeft)
+ setScrollLeft(cm, Math.min(display.scroller.scrollLeft, maxScrollLeft), true);
}
var newScrollPos, updated;
if (op.selectionChanged) {
@@ -1237,7 +1290,7 @@ window.CodeMirror = (function() {
on(d.scroller, "mousedown", operation(cm, onMouseDown));
on(d.scroller, "dblclick", operation(cm, e_preventDefault));
on(d.lineSpace, "selectstart", function(e) {
- if (!mouseEventInWidget(d, e)) e_preventDefault(e);
+ if (!eventInWidget(d, e)) e_preventDefault(e);
});
// Gecko browsers fire contextmenu *after* opening the menu, at
// which point we can't mess with it anymore. Context menu is
@@ -1264,13 +1317,24 @@ window.CodeMirror = (function() {
on(d.scrollbarV, "mousedown", reFocus);
// Prevent wrapper from ever scrolling
on(d.wrapper, "scroll", function() { d.wrapper.scrollTop = d.wrapper.scrollLeft = 0; });
- on(window, "resize", function resizeHandler() {
+
+ if (!window.registered) window.registered = 0;
+ ++window.registered;
+ function onResize() {
// Might be a text scaling operation, clear size caches.
d.cachedCharWidth = d.cachedTextHeight = null;
clearCaches(cm);
- if (d.wrapper.parentNode) updateDisplay(cm, true);
- else off(window, "resize", resizeHandler);
- });
+ updateDisplay(cm, true);
+ }
+ on(window, "resize", onResize);
+ // Above handler holds on to the editor and its data structures.
+ // Here we poll to unregister it when the editor is no longer in
+ // the document, so that it can be garbage-collected.
+ setTimeout(function unregister() {
+ for (var p = d.wrapper.parentNode; p && p != document.body; p = p.parentNode) {}
+ if (p) setTimeout(unregister, 5000);
+ else {--window.registered; off(window, "resize", onResize);}
+ }, 5000);
on(d.input, "keyup", operation(cm, function(e) {
if (cm.options.onKeyEvent && cm.options.onKeyEvent(cm, addStop(e))) return;
@@ -1292,7 +1356,11 @@ window.CodeMirror = (function() {
on(d.scroller, "dragover", drag_);
on(d.scroller, "drop", operation(cm, onDrop));
}
- on(d.scroller, "paste", function(){focusInput(cm); fastPoll(cm);});
+ on(d.scroller, "paste", function(e){
+ if (eventInWidget(d, e)) return;
+ focusInput(cm);
+ fastPoll(cm);
+ });
on(d.input, "paste", function() {
d.pasteIncoming = true;
fastPoll(cm);
@@ -1316,10 +1384,12 @@ window.CodeMirror = (function() {
});
}
- function mouseEventInWidget(display, e) {
- for (var n = e_target(e); n != display.wrapper; n = n.parentNode)
+ function eventInWidget(display, e) {
+ for (var n = e_target(e); n != display.wrapper; n = n.parentNode) {
+ if (!n) return true;
if (/\bCodeMirror-(?:line)?widget\b/.test(n.className) ||
n.parentNode == display.sizer && n != display.mover) return true;
+ }
}
function posFromMouse(cm, e, liberal) {
@@ -1341,7 +1411,7 @@ window.CodeMirror = (function() {
var cm = this, display = cm.display, view = cm.view, sel = view.sel, doc = view.doc;
sel.shift = e_prop(e, "shiftKey");
- if (mouseEventInWidget(display, e)) {
+ if (eventInWidget(display, e)) {
if (!webkit) {
display.scroller.draggable = false;
setTimeout(function(){display.scroller.draggable = true;}, 100);
@@ -1477,7 +1547,8 @@ window.CodeMirror = (function() {
function onDrop(e) {
var cm = this;
- if (cm.options.onDragEvent && cm.options.onDragEvent(cm, addStop(e))) return;
+ if (eventInWidget(cm.display, e) || (cm.options.onDragEvent && cm.options.onDragEvent(cm, addStop(e))))
+ return;
e_preventDefault(e);
var pos = posFromMouse(cm, e, true), files = e.dataTransfer.files;
if (!pos || isReadOnly(cm)) return;
@@ -1502,7 +1573,8 @@ window.CodeMirror = (function() {
// Don't do a replace if the drop happened inside of the selected text.
if (cm.view.draggingText && !(posLess(pos, cm.view.sel.from) || posLess(cm.view.sel.to, pos))) {
cm.view.draggingText(e);
- if (ie) setTimeout(bind(focusInput, cm), 50);
+ // Ensure the editor is re-focused
+ setTimeout(bind(focusInput, cm), 20);
return;
}
try {
@@ -1546,13 +1618,24 @@ window.CodeMirror = (function() {
}
function onDragStart(cm, e) {
+ if (eventInWidget(cm.display, e)) return;
+
var txt = cm.getSelection();
e.dataTransfer.setData("Text", txt);
// Use dummy image instead of default browsers image.
// Recent Safari (~6.0.2) have a tendency to segfault when this happens, so we don't do it there.
- if (e.dataTransfer.setDragImage && !safari)
- e.dataTransfer.setDragImage(elt('img'), 0, 0);
+ if (e.dataTransfer.setDragImage && !safari) {
+ var img = elt("img", null, null, "position: fixed; left: 0; top: 0;");
+ if (opera) {
+ img.width = img.height = 1;
+ cm.display.wrapper.appendChild(img);
+ // Force a relayout, or Opera won't use our image for some obscure reason
+ img._top = img.offsetTop;
+ }
+ e.dataTransfer.setDragImage(img, 0, 0);
+ if (opera) img.parentNode.removeChild(img);
+ }
}
function setScrollTop(cm, val) {
@@ -1565,6 +1648,7 @@ window.CodeMirror = (function() {
}
function setScrollLeft(cm, val, isScroller) {
if (isScroller ? val == cm.view.scrollLeft : Math.abs(cm.view.scrollLeft - val) < 2) return;
+ val = Math.min(val, cm.display.scroller.scrollWidth - cm.display.scroller.clientWidth);
cm.view.scrollLeft = val;
alignHorizontally(cm);
if (cm.display.scroller.scrollLeft != val) cm.display.scroller.scrollLeft = val;
@@ -1582,7 +1666,7 @@ window.CodeMirror = (function() {
// is that it gives us a chance to update the display before the
// actual scrolling happens, reducing flickering.
- var wheelSamples = 0, wheelDX, wheelDY, wheelStartX, wheelStartY, wheelPixelsPerUnit = null;
+ var wheelSamples = 0, wheelPixelsPerUnit = null;
// Fill in a browser-detected starting value on browsers where we
// 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
@@ -1611,7 +1695,7 @@ window.CodeMirror = (function() {
}
}
- var scroll = cm.display.scroller;
+ var display = cm.display, scroll = display.scroller;
// On some browsers, horizontal scrolling will cause redraws to
// happen before the gutter has been realigned, causing it to
// wriggle around in a most unseemly way. When we have an
@@ -1623,35 +1707,35 @@ window.CodeMirror = (function() {
setScrollTop(cm, Math.max(0, Math.min(scroll.scrollTop + dy * wheelPixelsPerUnit, scroll.scrollHeight - scroll.clientHeight)));
setScrollLeft(cm, Math.max(0, Math.min(scroll.scrollLeft + dx * wheelPixelsPerUnit, scroll.scrollWidth - scroll.clientWidth)));
e_preventDefault(e);
- wheelStartX = null; // Abort measurement, if in progress
+ display.wheelStartX = null; // Abort measurement, if in progress
return;
}
if (dy && wheelPixelsPerUnit != null) {
var pixels = dy * wheelPixelsPerUnit;
- var top = cm.view.scrollTop, bot = top + cm.display.wrapper.clientHeight;
+ var top = cm.view.scrollTop, bot = top + display.wrapper.clientHeight;
if (pixels < 0) top = Math.max(0, top + pixels - 50);
else bot = Math.min(cm.view.doc.height, bot + pixels + 50);
updateDisplay(cm, [], {top: top, bottom: bot});
}
if (wheelSamples < 20) {
- if (wheelStartX == null) {
- wheelStartX = scroll.scrollLeft; wheelStartY = scroll.scrollTop;
- wheelDX = dx; wheelDY = dy;
+ if (display.wheelStartX == null) {
+ display.wheelStartX = scroll.scrollLeft; display.wheelStartY = scroll.scrollTop;
+ display.wheelDX = dx; display.wheelDY = dy;
setTimeout(function() {
- if (wheelStartX == null) return;
- var movedX = scroll.scrollLeft - wheelStartX;
- var movedY = scroll.scrollTop - wheelStartY;
- var sample = (movedY && wheelDY && movedY / wheelDY) ||
- (movedX && wheelDX && movedX / wheelDX);
- wheelStartX = wheelStartY = null;
+ if (display.wheelStartX == null) return;
+ var movedX = scroll.scrollLeft - display.wheelStartX;
+ var movedY = scroll.scrollTop - display.wheelStartY;
+ var sample = (movedY && display.wheelDY && movedY / display.wheelDY) ||
+ (movedX && display.wheelDX && movedX / display.wheelDX);
+ display.wheelStartX = display.wheelStartY = null;
if (!sample) return;
wheelPixelsPerUnit = (wheelPixelsPerUnit * wheelSamples + sample) / (wheelSamples + 1);
++wheelSamples;
}, 200);
} else {
- wheelDX += dx; wheelDY += dy;
+ display.wheelDX += dx; display.wheelDY += dy;
}
}
}
@@ -1697,7 +1781,6 @@ window.CodeMirror = (function() {
}, 50);
var name = keyNames[e_prop(e, "keyCode")], handled = false;
- var flipCtrlCmd = mac && (opera || qtwebkit);
if (name == null || e.altGraphKey) return false;
if (e_prop(e, "altKey")) name = "Alt-" + name;
if (e_prop(e, flipCtrlCmd ? "metaKey" : "ctrlKey")) name = "Ctrl-" + name;
@@ -1794,7 +1877,10 @@ window.CodeMirror = (function() {
var detectingSelectAll;
function onContextMenu(cm, e) {
- var display = cm.display, sel = cm.view.sel;
+ var display = cm.display;
+ if (eventInWidget(display, e)) return;
+
+ var sel = cm.view.sel;
var pos = posFromMouse(cm, e), scrollPos = display.scroller.scrollTop;
if (!pos || opera) return; // Opera is difficult.
if (posEq(sel.from, sel.to) || posLess(pos, sel.from) || !posLess(pos, sel.to))
@@ -1904,7 +1990,7 @@ window.CodeMirror = (function() {
if (!cm.options.lineWrapping) {
checkWidthStart = lineNo(visualLine(doc, firstLine));
doc.iter(checkWidthStart, to.line + 1, function(line) {
- if (lineLength(doc, line) == view.maxLineLength) {
+ if (line == view.maxLine) {
recomputeMaxLength = true;
return true;
}
@@ -2351,6 +2437,25 @@ window.CodeMirror = (function() {
}
},
+ addOverlay: operation(null, function(spec, options) {
+ var mode = spec.token ? spec : CodeMirror.getMode(this.options, spec);
+ if (mode.startState) throw new Error("Overlays may not be stateful.");
+ this.view.overlays.push({mode: mode, modeSpec: spec, opaque: options && options.opaque});
+ this.view.modeGen++;
+ regChange(this, 0, this.view.doc.size);
+ }),
+ removeOverlay: operation(null, function(spec) {
+ var overlays = this.view.overlays;
+ for (var i = 0; i < overlays.length; ++i) {
+ if (overlays[i].modeSpec == spec) {
+ overlays.splice(i, 1);
+ this.view.modeGen++;
+ regChange(this, 0, this.view.doc.size);
+ return;
+ }
+ }
+ }),
+
undo: operation(null, function() {unredoHelper(this, "undo");}),
redo: operation(null, function() {unredoHelper(this, "redo");}),
@@ -2522,23 +2627,10 @@ window.CodeMirror = (function() {
}),
addLineWidget: operation(null, function(handle, node, options) {
- var widget = options || {};
- widget.node = node;
- if (widget.noHScroll) this.display.alignWidgets = true;
- changeLine(this, handle, function(line) {
- (line.widgets || (line.widgets = [])).push(widget);
- widget.line = line;
- return true;
- });
- return widget;
+ return addLineWidget(this, handle, node, options);
}),
- removeLineWidget: operation(null, function(widget) {
- var ws = widget.line.widgets, no = lineNo(widget.line);
- if (no == null) return;
- for (var i = 0; i < ws.length; ++i) if (ws[i] == widget) ws.splice(i--, 1);
- regChange(this, no, no + 1);
- }),
+ removeLineWidget: function(widget) { widget.clear(); },
lineInfo: function(line) {
if (typeof line == "number") {
@@ -2663,7 +2755,8 @@ window.CodeMirror = (function() {
// Stuff used by commands, probably not much use to outside code.
moveH: operation(null, function(dir, unit) {
var sel = this.view.sel, pos = dir < 0 ? sel.from : sel.to;
- if (sel.shift || sel.extend || posEq(sel.from, sel.to)) pos = findPosH(this, dir, unit, true);
+ if (sel.shift || sel.extend || posEq(sel.from, sel.to))
+ pos = findPosH(this, dir, unit, this.options.rtlMoveVisually);
extendSelection(this, pos, pos, dir);
}),
@@ -2713,7 +2806,7 @@ window.CodeMirror = (function() {
return clipPos(doc, {line: lineNo, ch: ch});
},
indexFromPos: function (coords) {
- if (coords.line < 0 || coords.ch < 0) return 0;
+ coords = clipPos(this.view.doc, coords);
var index = coords.ch;
this.view.doc.iter(0, coords.line, function (line) {
index += line.text.length + 1;
@@ -2735,8 +2828,12 @@ window.CodeMirror = (function() {
scrollIntoView: function(pos) {
if (typeof pos == "number") pos = {line: pos, ch: 0};
- pos = pos ? clipPos(this.view.doc, pos) : this.view.sel.head;
- scrollPosIntoView(this, pos);
+ if (!pos || pos.line != null) {
+ pos = pos ? clipPos(this.view.doc, pos) : this.view.sel.head;
+ scrollPosIntoView(this, pos);
+ } else {
+ scrollIntoView(this, pos.left, pos.top, pos.right, pos.bottom);
+ }
},
setSize: function(width, height) {
@@ -2755,8 +2852,11 @@ window.CodeMirror = (function() {
refresh: function() {
clearCaches(this);
- if (this.display.scroller.scrollHeight > this.view.scrollTop)
- this.display.scrollbarV.scrollTop = this.display.scroller.scrollTop = this.view.scrollTop;
+ var sTop = this.view.scrollTop, sLeft = this.view.scrollLeft;
+ if (this.display.scroller.scrollHeight > sTop)
+ this.display.scrollbarV.scrollTop = this.display.scroller.scrollTop = sTop;
+ if (this.display.scroller.scrollWidth > sLeft)
+ this.display.scrollbarH.scrollLeft = this.display.scroller.scrollLeft = sLeft;
updateDisplay(this, true);
},
@@ -2795,6 +2895,7 @@ window.CodeMirror = (function() {
updateDisplay(cm, true);
}, true);
option("electricChars", true);
+ option("rtlMoveVisually", !windows);
option("theme", "default", function(cm) {
themeChanged(cm);
@@ -2811,6 +2912,10 @@ window.CodeMirror = (function() {
setGuttersForLineNumbers(cm.options);
guttersChanged(cm);
}, true);
+ option("fixedGutter", true, function(cm, val) {
+ cm.display.gutters.style.left = val ? compensateForHScroll(cm.display) + "px" : "0";
+ cm.refresh();
+ }, true);
option("lineNumbers", false, function(cm) {
setGuttersForLineNumbers(cm.options);
guttersChanged(cm);
@@ -2867,7 +2972,7 @@ window.CodeMirror = (function() {
};
CodeMirror.getMode = function(options, spec) {
- var spec = CodeMirror.resolveMode(spec);
+ spec = CodeMirror.resolveMode(spec);
var mfactory = modes[spec.name];
if (!mfactory) return CodeMirror.getMode(options, "text/plain");
var modeObj = mfactory(options, spec);
@@ -3204,11 +3309,12 @@ window.CodeMirror = (function() {
this.type = type;
this.cm = cm;
}
+ CodeMirror.TextMarker = TextMarker;
TextMarker.prototype.clear = function() {
if (this.explicitlyCleared) return;
startOperation(this.cm);
- var min = null, max = null;
+ var view = this.cm.view, min = null, max = null;
for (var i = 0; i < this.lines.length; ++i) {
var line = this.lines[i];
var span = getMarkedSpanFor(line.markedSpans, this);
@@ -3219,6 +3325,15 @@ window.CodeMirror = (function() {
else if (this.collapsed && !lineIsHidden(line))
updateLineHeight(line, textHeight(this.cm.display));
}
+ if (this.collapsed && !this.cm.options.lineWrapping) for (var i = 0; i < this.lines.length; ++i) {
+ var visual = visualLine(view.doc, this.lines[i]), len = lineLength(view.doc, visual);
+ if (len > view.maxLineLength) {
+ view.maxLine = visual;
+ view.maxLineLength = len;
+ view.maxLineChanged = true;
+ }
+ }
+
if (min != null) regChange(this.cm, min, max + 1);
this.lines.length = 0;
this.explicitlyCleared = true;
@@ -3245,6 +3360,18 @@ window.CodeMirror = (function() {
return from && {from: from, to: to};
};
+ TextMarker.prototype.getOptions = function(copyWidget) {
+ var repl = this.replacedWith;
+ return {className: this.className,
+ inclusiveLeft: this.inclusiveLeft, inclusiveRight: this.inclusiveRight,
+ atomic: this.atomic,
+ collapsed: this.collapsed,
+ clearOnEnter: this.clearOnEnter,
+ replacedWith: copyWidget ? repl && repl.cloneNode(true) : repl,
+ readOnly: this.readOnly,
+ startStyle: this.startStyle, endStyle: this.endStyle};
+ };
+
function markText(cm, from, to, options, type) {
var doc = cm.view.doc;
var marker = new TextMarker(cm, type);
@@ -3259,6 +3386,8 @@ window.CodeMirror = (function() {
var curLine = from.line, size = 0, collapsedAtStart, collapsedAtEnd;
doc.iter(curLine, to.line + 1, function(line) {
+ if (marker.collapsed && !cm.options.lineWrapping && visualLine(doc, line) == cm.view.maxLine)
+ cm.curOp.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;}
@@ -3269,10 +3398,11 @@ window.CodeMirror = (function() {
else updateLineHeight(line, 0);
}
addMarkedSpan(line, span);
- if (marker.collapsed && curLine == from.line && lineIsHidden(line))
- updateLineHeight(line, 0);
++curLine;
});
+ if (marker.collapsed) doc.iter(from.line, to.line + 1, function(line) {
+ if (lineIsHidden(line)) updateLineHeight(line, 0);
+ });
if (marker.readOnly) {
sawReadOnlySpans = true;
@@ -3447,9 +3577,12 @@ window.CodeMirror = (function() {
return true;
}
}
- window.lineIsHidden = lineIsHidden;
function lineIsHiddenInner(line, span) {
- if (span.to == null || span.marker.inclusiveRight && span.to == line.text.length)
+ if (span.to == null) {
+ var end = span.marker.find().to, endLine = getLine(lineDoc(line), end.line);
+ return lineIsHiddenInner(endLine, getMarkedSpanFor(endLine.markedSpans, span.marker));
+ }
+ if (span.marker.inclusiveRight && span.to == line.text.length)
return true;
for (var sp, i = 0; i < line.markedSpans.length; ++i) {
sp = line.markedSpans[i];
@@ -3491,6 +3624,63 @@ window.CodeMirror = (function() {
line.markedSpans = spans;
}
+ // LINE WIDGETS
+
+ var LineWidget = CodeMirror.LineWidget = function(cm, node, options) {
+ for (var opt in options) if (options.hasOwnProperty(opt))
+ this[opt] = options[opt];
+ this.cm = cm;
+ this.node = node;
+ };
+ function widgetOperation(f) {
+ return function() {
+ startOperation(this.cm);
+ try {var result = f.apply(this, arguments);}
+ finally {endOperation(this.cm);}
+ return result;
+ };
+ }
+ LineWidget.prototype.clear = widgetOperation(function() {
+ var ws = this.line.widgets, no = lineNo(this.line);
+ if (no == null || !ws) return;
+ for (var i = 0; i < ws.length; ++i) if (ws[i] == this) ws.splice(i--, 1);
+ updateLineHeight(this.line, Math.max(0, this.line.height - widgetHeight(this)));
+ regChange(this.cm, no, no + 1);
+ });
+ LineWidget.prototype.changed = widgetOperation(function() {
+ var oldH = this.height;
+ this.height = null;
+ var diff = widgetHeight(this) - oldH;
+ if (!diff) return;
+ updateLineHeight(this.line, this.line.height + diff);
+ var no = lineNo(this.line);
+ regChange(this.cm, no, no + 1);
+ });
+
+ function widgetHeight(widget) {
+ if (widget.height != null) return widget.height;
+ if (!widget.node.parentNode || widget.node.parentNode.nodeType != 1)
+ removeChildrenAndAdd(widget.cm.display.measure, elt("div", [widget.node], null, "position: relative"));
+ return widget.height = widget.node.offsetHeight;
+ }
+
+ function addLineWidget(cm, handle, node, options) {
+ var widget = new LineWidget(cm, node, options);
+ if (widget.noHScroll) cm.display.alignWidgets = true;
+ changeLine(cm, handle, function(line) {
+ (line.widgets || (line.widgets = [])).push(widget);
+ widget.line = line;
+ if (!lineIsHidden(line) || widget.showIfHidden) {
+ var aboveVisible = heightAtLine(cm, line) < cm.display.scroller.scrollTop;
+ updateLineHeight(line, line.height + widgetHeight(widget));
+ if (aboveVisible)
+ setTimeout(function() {cm.display.scroller.scrollTop += widget.height;});
+ }
+ return true;
+ });
+ return widget;
+ }
+
// LINE DATA STRUCTURE
// Line objects. These hold state related to a line, including
@@ -3504,7 +3694,8 @@ window.CodeMirror = (function() {
function updateLine(cm, line, text, markedSpans) {
line.text = text;
- line.stateAfter = line.styles = null;
+ if (line.stateAfter) line.stateAfter = null;
+ if (line.styles) line.styles = null;
if (line.order != null) line.order = null;
detachMarkedSpans(line);
attachMarkedSpans(line, markedSpans);
@@ -3521,31 +3712,72 @@ window.CodeMirror = (function() {
// Run the given mode's parser over a line, update the styles
// array, which contains alternating fragments of text and CSS
// classes.
- function highlightLine(cm, line, state) {
- var mode = cm.view.mode, flattenSpans = cm.options.flattenSpans;
- var changed = !line.styles, pos = 0, curText = "", curStyle = null;
- var stream = new StringStream(line.text, cm.options.tabSize), st = line.styles || (line.styles = []);
- if (line.text == "" && mode.blankLine) mode.blankLine(state);
+ function runMode(cm, text, mode, state, f) {
+ var flattenSpans = cm.options.flattenSpans;
+ var curText = "", curStyle = null;
+ var stream = new StringStream(text, cm.options.tabSize);
+ if (text == "" && mode.blankLine) mode.blankLine(state);
while (!stream.eol()) {
- var style = mode.token(stream, state), substr = stream.current();
+ var style = mode.token(stream, state);
+ if (stream.pos > 5000) {
+ flattenSpans = false;
+ // Webkit seems to refuse to render text nodes longer than 57444 characters
+ stream.pos = Math.min(text.length, stream.start + 50000);
+ style = null;
+ }
+ var substr = stream.current();
stream.start = stream.pos;
if (!flattenSpans || curStyle != style) {
- if (curText) {
- changed = changed || pos >= st.length || curText != st[pos] || curStyle != st[pos+1];
- st[pos++] = curText; st[pos++] = curStyle;
- }
+ if (curText) f(curText, curStyle);
curText = substr; curStyle = style;
} else curText = curText + substr;
- // Give up when line is ridiculously long
- if (stream.pos > 5000) break;
}
- if (curText) {
- changed = changed || pos >= st.length || curText != st[pos] || curStyle != st[pos+1];
- st[pos++] = curText; st[pos++] = curStyle;
+ if (curText) f(curText, curStyle);
+ }
+
+ function highlightLine(cm, line, state) {
+ // A styles array always starts with a number identifying the
+ // mode/overlays that it is based on (for easy invalidation).
+ var st = [cm.view.modeGen];
+ // Compute the base array of styles
+ runMode(cm, line.text, cm.view.mode, state, function(txt, style) {st.push(txt, style);});
+
+ // Run overlays, adjust style array.
+ for (var o = 0; o < cm.view.overlays.length; ++o) {
+ var overlay = cm.view.overlays[o], i = 1;
+ runMode(cm, line.text, overlay.mode, true, function(txt, style) {
+ var start = i, len = txt.length;
+ // Ensure there's a token end at the current position, and that i points at it
+ while (len) {
+ var cur = st[i], len_ = cur.length;
+ if (len_ <= len) {
+ len -= len_;
+ } else {
+ st.splice(i, 1, cur.slice(0, len), st[i+1], cur.slice(len));
+ len = 0;
+ }
+ i += 2;
+ }
+ if (!style) return;
+ if (overlay.opaque) {
+ st.splice(start, i - start, txt, style);
+ i = start + 2;
+ } else {
+ for (; start < i; start += 2) {
+ var cur = st[start+1];
+ st[start+1] = cur ? cur + " " + style : style;
+ }
+ }
+ });
}
- if (stream.pos > 5000) { st[pos++] = line.text.slice(stream.pos); st[pos++] = null; }
- if (pos != st.length) { st.length = pos; changed = true; }
- return changed;
+
+ return st;
+ }
+
+ function getLineStyles(cm, line) {
+ if (!line.styles || line.styles[0] != cm.view.modeGen)
+ line.styles = highlightLine(cm, line, line.stateAfter = getStateBefore(cm, lineNo(line)));
+ return line.styles;
}
// Lightweight form of highlight -- proceed over this line and
@@ -3580,8 +3812,6 @@ window.CodeMirror = (function() {
if (line.textClass) builder.pre.className = line.textClass;
do {
- if (!line.styles)
- highlightLine(cm, line, line.stateAfter = getStateBefore(cm, lineNo(line)));
builder.measure = line == realLine && measure;
builder.pos = 0;
builder.addToken = builder.measure ? buildTokenMeasure : buildToken;
@@ -3589,7 +3819,7 @@ window.CodeMirror = (function() {
measure[0] = builder.pre.appendChild(zeroWidthElement(cm.display.measure));
builder.addedOne = true;
}
- var next = insertLineContent(line, builder);
+ var next = insertLineContent(line, builder, getLineStyles(cm, line));
sawBefore = line == lineBefore;
if (next) {
line = getLine(cm.view.doc, next.to.line);
@@ -3646,7 +3876,7 @@ window.CodeMirror = (function() {
function buildTokenMeasure(builder, text, style, startStyle, endStyle) {
for (var i = 0; i < text.length; ++i) {
- if (i && i < text.length - 1 &&
+ if (i && i < text.length &&
builder.cm.options.lineWrapping &&
spanAffectsWrapping.test(text.slice(i - 1, i + 1)))
builder.pre.appendChild(elt("wbr"));
@@ -3671,16 +3901,16 @@ window.CodeMirror = (function() {
// Outputs a number of spans to make up a line, taking highlighting
// and marked text into account.
- function insertLineContent(line, builder) {
- var st = line.styles, spans = line.markedSpans;
+ function insertLineContent(line, builder, styles) {
+ var spans = line.markedSpans;
if (!spans) {
- for (var i = 0; i < st.length; i+=2)
- builder.addToken(builder, st[i], styleToClass(st[i+1]));
+ for (var i = 1; i < styles.length; i+=2)
+ builder.addToken(builder, styles[i], styleToClass(styles[i+1]));
return;
}
var allText = line.text, len = allText.length;
- var pos = 0, i = 0, text = "", style;
+ var pos = 0, i = 1, text = "", style;
var nextChange = 0, spanStyle, spanEndStyle, spanStartStyle, collapsed;
for (;;) {
if (nextChange == pos) { // Update current marker set
@@ -3724,7 +3954,7 @@ window.CodeMirror = (function() {
pos = end;
spanStartStyle = "";
}
- text = st[i++]; style = styleToClass(st[i++]);
+ text = styles[i++]; style = styleToClass(styles[i++]);
}
}
}
@@ -3896,6 +4126,11 @@ window.CodeMirror = (function() {
return no;
}
+ function lineDoc(line) {
+ for (var d = line.parent; d.parent; d = d.parent) {}
+ return d;
+ }
+
function lineAtHeight(chunk, h) {
var n = 0;
outer: do {
@@ -4177,7 +4412,9 @@ window.CodeMirror = (function() {
}
function removeChildren(e) {
- e.innerHTML = "";
+ // IE will break all parent-child relations in subnodes when setting innerHTML
+ if (!ie) e.innerHTML = "";
+ else while (e.firstChild) e.removeChild(e.firstChild);
return e;
}
@@ -4300,7 +4537,7 @@ window.CodeMirror = (function() {
if (!order) return f(from, to, "ltr");
for (var i = 0; i < order.length; ++i) {
var part = order[i];
- if (part.from < to && part.to > from)
+ if (part.from < to && part.to > from || from == to && part.to == from)
f(Math.max(part.from, from), Math.min(part.to, to), part.level == 1 ? "rtl" : "ltr");
}
}
@@ -4418,24 +4655,20 @@ window.CodeMirror = (function() {
var bidiRE = /[\u0590-\u05f4\u0600-\u06ff\u0700-\u08ac]/;
var isNeutral = /[stwN]/, isStrong = /[LRr]/, countsAsLeft = /[Lb1n]/, countsAsNum = /[1n]/;
+ // Browsers seem to always treat the boundaries of block elements as being L.
+ var outerType = "L";
return function charOrdering(str) {
if (!bidiRE.test(str)) return false;
- var len = str.length, types = [], startType = null;
- for (var i = 0, type; i < len; ++i) {
+ var len = str.length, types = [];
+ for (var i = 0, type; i < len; ++i)
types.push(type = charType(str.charCodeAt(i)));
- if (startType == null) {
- if (type == "L") startType = "L";
- else if (type == "R" || type == "r") startType = "R";
- }
- }
- if (startType == null) startType = "L";
// W1. Examine each non-spacing mark (NSM) in the level run, and
// change the type of the NSM to the type of the previous
// character. If the NSM is at the start of the level run, it will
// get the type of sor.
- for (var i = 0, prev = startType; i < len; ++i) {
+ for (var i = 0, prev = outerType; i < len; ++i) {
var type = types[i];
if (type == "m") types[i] = prev;
else prev = type;
@@ -4446,7 +4679,7 @@ window.CodeMirror = (function() {
// AL is found, change the type of the European number to Arabic
// number.
// W3. Change all ALs to R.
- for (var i = 0, cur = startType; i < len; ++i) {
+ for (var i = 0, cur = outerType; i < len; ++i) {
var type = types[i];
if (type == "1" && cur == "r") types[i] = "n";
else if (isStrong.test(type)) { cur = type; if (type == "r") types[i] = "R"; }
@@ -4481,7 +4714,7 @@ window.CodeMirror = (function() {
// W7. Search backwards from each instance of a European number
// until the first strong type (R, L, or sor) is found. If an L is
// found, then change the type of the European number to L.
- for (var i = 0, cur = startType; i < len; ++i) {
+ for (var i = 0, cur = outerType; i < len; ++i) {
var type = types[i];
if (cur == "L" && type == "1") types[i] = "L";
else if (isStrong.test(type)) cur = type;
@@ -4496,8 +4729,8 @@ window.CodeMirror = (function() {
for (var i = 0; i < len; ++i) {
if (isNeutral.test(types[i])) {
for (var end = i + 1; end < len && isNeutral.test(types[end]); ++end) {}
- var before = (i ? types[i-1] : startType) == "L";
- var after = (end < len - 1 ? types[end] : startType) == "L";
+ var before = (i ? types[i-1] : outerType) == "L";
+ var after = (end < len - 1 ? types[end] : outerType) == "L";
var replace = before || after ? "L" : "R";
for (var j = i; j < end; ++j) types[j] = replace;
i = end - 1;
@@ -4547,7 +4780,7 @@ window.CodeMirror = (function() {
// THE END
- CodeMirror.version = "3.0";
+ CodeMirror.version = "3.02";
return CodeMirror;
})();
View
345 vendor/assets/javascripts/codemirror/keymaps/vim.js
@@ -115,6 +115,10 @@
motion: 'moveByWords',
motionArgs: { forward: false, wordEnd: true, bigWord: true,
inclusive: true }},
+ { keys: ['{'], type: 'motion', motion: 'moveByParagraph',
+ motionArgs: { forward: false }},
+ { keys: ['}'], type: 'motion', motion: 'moveByParagraph',
+ motionArgs: { forward: true }},
{ keys: ['Ctrl-f'], type: 'motion',
motion: 'moveByPage', motionArgs: { forward: true }},
{ keys: ['Ctrl-b'], type: 'motion',
@@ -247,7 +251,7 @@
var specialKeys = ['Left', 'Right', 'Up', 'Down', 'Space', 'Backspace',
'Esc', 'Home', 'End', 'PageUp', 'PageDown'];
var validMarks = upperCaseAlphabet.concat(lowerCaseAlphabet).concat(
- numbers);
+ numbers).concat(['<', '>']);
var validRegisters = upperCaseAlphabet.concat(lowerCaseAlphabet).concat(
numbers).concat('-\"'.split(''));
@@ -720,7 +724,11 @@
// Handle user defined Ex to Ex mappings
exCommandDispatcher.processCommand(cm, command.exArgs.input);
} else {
- showPrompt(cm, onPromptClose, ':');
+ if (vim.visualMode) {
+ showPrompt(cm, onPromptClose, ':', undefined, '\'<,\'>');
+ } else {
+ showPrompt(cm, onPromptClose, ':');
+ }
}
},
evalInput: function(cm, vim) {
@@ -806,6 +814,12 @@
// CodeMirror can't figure out that we changed directions...
cm.setCursor(selectionStart);
cm.setSelection(selectionStart, selectionEnd);
+ updateMark(cm, vim, '<',
+ cursorIsBefore(selectionStart, selectionEnd) ? selectionStart
+ : selectionEnd);
+ updateMark(cm, vim, '>',
+ cursorIsBefore(selectionStart, selectionEnd) ? selectionEnd
+ : selectionStart);
} else if (!operator) {
curEnd = clipCursorToContent(cm, curEnd);
cm.setCursor(curEnd.line, curEnd.ch);
@@ -923,6 +937,22 @@
cm.setCursor(curStart);
return curEnd;
},
+ moveByParagraph: function(cm, motionArgs) {
+ var line = cm.getCursor().line;
+ var repeat = motionArgs.repeat;
+ var inc = motionArgs.forward ? 1 : -1;
+ for (var i = 0; i < repeat; i++) {
+ if ((!motionArgs.forward && line === 0) ||
+ (motionArgs.forward && line == cm.lineCount() - 1)) {
+ break;
+ }
+ line += inc;
+ while (line !== 0 && line != cm.lineCount - 1 && cm.getLine(line)) {
+ line += inc;
+ }
+ }
+ return { line: line, ch: 0 };
+ },
moveByWords: function(cm, motionArgs) {
return moveToWord(cm, motionArgs.repeat, !!motionArgs.forward,
!!motionArgs.wordEnd, !!motionArgs.bigWord);
@@ -1119,21 +1149,29 @@
cm.setSelection(curStart, curEnd);
}
} else {
+ curStart = cm.getCursor('anchor');
+ curEnd = cm.getCursor('head');
if (!vim.visualLine && actionArgs.linewise) {
// Shift-V pressed in characterwise visual mode. Switch to linewise
// visual mode instead of exiting visual mode.
vim.visualLine = true;
- curStart = cm.getCursor('anchor');
- curEnd = cm.getCursor('head');
curStart.ch = cursorIsBefore(curStart, curEnd) ? 0 :
lineLength(cm, curStart.line);
curEnd.ch = cursorIsBefore(curStart, curEnd) ?
lineLength(cm, curEnd.line) : 0;
cm.setSelection(curStart, curEnd);
+ } else if (vim.visualLine && !actionArgs.linewise) {
+ // v pressed in linewise visual mode. Switch to characterwise visual
+ // mode instead of exiting visual mode.
+ vim.visualLine = false;
} else {
exitVisualMode(cm, vim);
}
}
+ updateMark(cm, vim, '<', cursorIsBefore(curStart, curEnd) ? curStart
+ : curEnd);
+ updateMark(cm, vim, '>', cursorIsBefore(curStart, curEnd) ? curEnd
+ : curStart);
},
joinLines: function(cm, actionArgs, vim) {
var curStart, curEnd;
@@ -1232,13 +1270,7 @@
},
setMark: function(cm, actionArgs, vim) {
var markName = actionArgs.selectedCharacter;
- if (!inArray(markName, validMarks)) {
- return;
- }
- if (vim.marks[markName]) {
- vim.marks[markName].clear();
- }
- vim.marks[markName] = cm.setBookmark(cm.getCursor());
+ updateMark(cm, vim, markName, cm.getCursor());
},
replace: function(cm, actionArgs) {
var replaceWith = actionArgs.selectedCharacter;
@@ -1636,6 +1668,16 @@
return clipCursorToContent(cm, { line: line, ch: repeat - 1 });
}
+ function updateMark(cm, vim, markName, pos) {
+ if (!inArray(markName, validMarks)) {
+ return;
+ }
+ if (vim.marks[markName]) {
+ vim.marks[markName].clear();
+ }
+ vim.marks[markName] = cm.setBookmark(pos);
+ }
+
function charIdxInLine(start, line, character, forward, includeChar) {
// Search for char in line.
// motion_options: {forward, includeChar}
@@ -1804,6 +1846,12 @@
setMarked: function(marked) {
this.marked = marked;
},
+ getOverlay: function() {
+ return this.searchOverlay;
+ },
+ setOverlay: function(overlay) {
+ this.searchOverlay = overlay;
+ },
isReversed: function() {
return getVimGlobalState().isReversed;
},
@@ -1815,9 +1863,9 @@
var vim = getVimState(cm);
return vim.searchState_ || (vim.searchState_ = new SearchState());
}
- function dialog(cm, text, shortText, callback) {
+ function dialog(cm, text, shortText, callback, initialValue) {
if (cm.openDialog) {
- cm.openDialog(text, callback, {bottom: true});
+ cm.openDialog(text, callback, { bottom: true, value: initialValue });
}
else {
callback(prompt(shortText, ""));
@@ -1899,9 +1947,10 @@
return raw;
}
var searchPromptDesc = '(Javascript regexp)';
- function showPrompt(cm, onPromptClose, prefix, desc) {
+ function showPrompt(cm, onPromptClose, prefix, desc, initialValue) {
var shortText = (prefix || '') + ' ' + (desc || '');
- dialog(cm, makePrompt(prefix, desc), shortText, onPromptClose);
+ dialog(cm, makePrompt(prefix, desc), shortText, onPromptClose,
+ initialValue);
}
function regexEqual(r1, r2) {
if (r1 instanceof RegExp && r2 instanceof RegExp) {
@@ -1934,17 +1983,53 @@
state.setQuery(query);
});
}
+ function searchOverlay(query) {
+ return {
+ token: function(stream) {
+ var match = stream.match(query, false);
+ if (match) {
+ if (!stream.sol()) {
+ // Backtrack 1 to match \b
+ stream.backUp(1);
+ if (!query.exec(stream.next() + match[0])) {
+ stream.next();
+ return null;
+ }
+ }
+ stream.match(query);
+ return "searching";
+ }
+ while (!stream.eol()) {
+ stream.next();
+ if (stream.match(query, false)) break;
+ }
+ },
+ query: query
+ };
+ }
function highlightSearchMatches(cm, query) {
- // TODO: Highlight only text inside the viewport. Highlighting everything
- // is inefficient and expensive.
- if (cm.lineCount() < 2000) { // This is too expensive on big documents.
- var marked = [];
- for (var cursor = cm.getSearchCursor(query);
- cursor.findNext();) {
- marked.push(cm.markText(cursor.from(), cursor.to(),
- { className: 'CodeMirror-searching' }));
+ if (cm.addOverlay) {
+ var overlay = getSearchState(cm).getOverlay();
+ if (!overlay || query != overlay.query) {
+ if (overlay) {
+ cm.removeOverlay(overlay);
+ }
+ overlay = searchOverlay(query);
+ cm.addOverlay(overlay);
+ getSearchState(cm).setOverlay(overlay);
+ }
+ } else {
+ // TODO: Highlight only text inside the viewport. Highlighting everything
+ // is inefficient and expensive.
+ if (cm.lineCount() < 2000) { // This is too expensive on big documents.
+ var marked = [];
+ for (var cursor = cm.getSearchCursor(query);
+ cursor.findNext();) {
+ marked.push(cm.markText(cursor.from(), cursor.to(),
+ { className: 'cm-searching' }));
+ }
+ getSearchState(cm).setMarked(marked);
}
- getSearchState(cm).setMarked(marked);
}
}
function findNext(cm, prev, repeat) {
@@ -1978,20 +2063,52 @@
return cursor.from();
});}
function clearSearchHighlight(cm) {
- cm.operation(function() {
- var state = getSearchState(cm);
- if (!state.getQuery()) {
- return;
- }
- var marked = state.getMarked();
- if (!marked) {
- return;
- }
- for (var i = 0; i < marked.length; ++i) {
- marked[i].clear();
+ if (cm.addOverlay) {
+ cm.removeOverlay(getSearchState(cm).getOverlay());
+ getSearchState(cm).setOverlay(null);
+ } else {
+ cm.operation(function() {
+ var state = getSearchState(cm);
+ if (!state.getQuery()) {
+ return;
+ }
+ var marked = state.getMarked();
+ if (!marked) {
+ return;
+ }
+ for (var i = 0; i < marked.length; ++i) {
+ marked[i].clear();
+ }
+ state.setMarked(null);
+ });
+ }
+ }
+ /**
+ * Check if pos is in the specified range, INCLUSIVE.
+ * Range can be specified with 1 or 2 arguments.
+ * If the first range argument is an array, treat it as an array of line
+ * numbers. Match pos against any of the lines.
+ * If the first range argument is a number,
+ * if there is only 1 range argument, check if pos has the same line
+ * number
+ * if there are 2 range arguments, then check if pos is in between the two
+ * range arguments.
+ */
+ function isInRange(pos, start, end) {
+ if (typeof pos != 'number') {
+ // Assume it is a cursor position. Get the line number.
+ pos = pos.line;
+ }
+ if (start instanceof Array) {
+ return inArray(pos, start);
+ } else {
+ if (end) {
+ return (pos >= start && pos <= end);
+ } else {
+ return pos == start;
}
- state.setMarked(null);
- });}
+ }
+ }
// Ex command handling
// Care must be taken when adding to the default Ex command map. For any
@@ -2001,14 +2118,23 @@
{ name: 'map', type: 'builtIn' },
{ name: 'write', shortName: 'w', type: 'builtIn' },
{ name: 'undo', shortName: 'u', type: 'builtIn' },
- { name: 'redo', shortName: 'red', type: 'builtIn' }
+ { name: 'redo', shortName: 'red', type: 'builtIn' },
+ { name: 'substitute', shortName: 's', type: 'builtIn'}
];
- var ExCommandDispatcher = function() {
+ Vim.ExCommandDispatcher = function() {
this.buildCommandMap_();
};
- ExCommandDispatcher.prototype = {
+ Vim.ExCommandDispatcher.prototype = {
processCommand: function(cm, input) {
- var params = this.parseInput_(input);
+ var inputStream = new CodeMirror.StringStream(input);
+ var params = {};
+ params.input = input;
+ try {
+ this.parseInput_(cm, inputStream, params);
+ } catch(e) {
+ showConfirm(cm, e);
+ return;
+ }
var commandName;
if (!params.commandName) {
// If only a line range is defined, move to the line.
@@ -2019,6 +2145,7 @@
var command = this.matchCommand_(params.commandName);
if (command) {
commandName = command.name;
+ this.parseCommandArgs_(inputStream, params, command);
if (command.type == 'exToKey') {
// Handle Ex to Key mapping.
for (var i = 0; i < command.toKeys.length; i++) {
@@ -2038,37 +2165,63 @@
}
exCommands[commandName](cm, params);
},
- parseInput_: function(input) {
- var result = {};
- result.input = input;
- var idx = 0;
- // Trim preceding ':'.
- var colons = (/^:+/).exec(input);
- if (colons) {
- idx += colons[0].length;
- }
-
+ parseInput_: function(cm, inputStream, result) {
+ inputStream.eatWhile(':');
// Parse range.
- var numberMatch = (/^(\d+)/).exec(input.substring(idx));
- if (numberMatch) {
- result.line = parseInt(numberMatch[1], 10);
- idx += numberMatch[0].length;
+ if (inputStream.eat('%')) {
+ result.line = 0;
+ result.lineEnd = cm.lineCount() - 1;
+ } else {
+ result.line = this.parseLineSpec_(cm, inputStream);
+ if (result.line !== undefined && inputStream.eat(',')) {
+ result.lineEnd = this.parseLineSpec_(cm, inputStream);
+ }
}
// Parse command name.
- var commandMatch = (/^(\w+)/).exec(input.substring(idx));
+ var commandMatch = inputStream.match(/^(\w+)/);
if (commandMatch) {
result.commandName = commandMatch[1];
- idx += commandMatch[1].length;
+ } else {
+ result.commandName = inputStream.match(/.*/)[0];
}
+ return result;
+ },
+ parseLineSpec_: function(cm, inputStream) {
+ var numberMatch = inputStream.match(/^(\d+)/);
+ if (numberMatch) {
+ return parseInt(numberMatch[1], 10) - 1;
+ }
+ switch (inputStream.next()) {
+ case '.':
+ return cm.getCursor().line;
+ case '$':
+ return cm.lineCount() - 1;
+ case '\'':
+ var mark = getVimState(cm).marks[inputStream.next()];
+ if (mark && mark.find()) {
+ return mark.find().line;
+ } else {
+ throw "Mark not set";
+ }
+ break;
+ default:
+ inputStream.backUp(1);
+ return cm.getCursor().line;
+ }
+ },
+ parseCommandArgs_: function(inputStream, params, command) {
+ if (inputStream.eol()) {
+ return;
+ }
+ params.argString = inputStream.match(/.*/)[0];
// Parse command-line arguments
- var args = trim(input.substring(idx)).split(/\s+/);
+ var delim = command.argDelimiter || /\s+/;
+ var args = trim(params.argString).split(delim);
if (args.length && args[0]) {
- result.commandArgs = args;
+ params.args = args;
}
-
- return result;
},
matchCommand_: function(commandName) {
// Return the command in the command map that matches the shortest
@@ -2095,9 +2248,9 @@
}
},
map: function(lhs, rhs) {
- if (lhs.charAt(0) == ':') {
+ if (lhs != ':' && lhs.charAt(0) == ':') {
var commandName = lhs.substring(1);
- if (rhs.charAt(0) == ':') {
+ if (rhs != ':' && rhs.charAt(0) == ':') {
// Ex to Ex mapping
this.commandMap_[commandName] = {
name: commandName,
@@ -2113,7 +2266,7 @@
};
}
} else {
- if (rhs.charAt(0) == ':') {
+ if (rhs != ':' && rhs.charAt(0) == ':') {
// Key to Ex mapping.
defaultKeymap.unshift({
keys: parseKeyString(lhs),
@@ -2172,7 +2325,7 @@
var exCommands = {
map: function(cm, params) {
- var mapArgs = params.commandArgs;
+ var mapArgs = params.args;
if (!mapArgs || mapArgs.length < 2) {
if (cm) {
showConfirm(cm, 'Invalid mapping: ' + params.input);
@@ -2187,6 +2340,66 @@
motionArgs: { forward: false, explicitRepeat: true,
linewise: true, repeat: params.line }});
},
+ substitute: function(cm, params) {
+ var argString = params.argString;
+ var slashes = findUnescapedSlashes(argString);
+ if (slashes[0] !== 0) {
+ showConfirm(cm, 'Substitutions should be of the form ' +
+ ':s/pattern/replace/');
+ return;
+ }
+ var regexPart = argString.substring(slashes[0] + 1, slashes[1]);
+ var replacePart = '';
+ var flagsPart;
+ var count;
+ if (slashes[1]) {
+ replacePart = argString.substring(slashes[1] + 1, slashes[2]);
+ }
+ if (slashes[2]) {
+ // After the 3rd slash, we can have flags followed by a space followed
+ // by count.
+ var trailing = argString.substring(slashes[2] + 1).split(' ');
+ flagsPart = trailing[0];
+ count = parseInt(trailing[1]);
+ }
+ if (flagsPart) {
+ regexPart = regexPart + '/' + flagsPart;
+ }
+ if (regexPart) {
+ // If regex part is empty, then use the previous query. Otherwise use
+ // the regex part as the new query.
+ updateSearchQuery(cm, regexPart, true /** ignoreCase */,
+ true /** smartCase */);
+ }
+ var state = getSearchState(cm);
+ var query = state.getQuery();
+ var lineStart = params.line || 0;
+ var lineEnd = params.lineEnd || lineStart;
+ if (count) {
+ lineStart = lineEnd;
+ lineEnd = lineStart + count - 1;
+ }
+ var startPos = clipCursorToContent(cm, { line: lineStart, ch: 0 });
+ function doReplace() {
+ for (var cursor = cm.getSearchCursor(query, startPos);
+ cursor.findNext() &&
+ isInRange(cursor.from(), lineStart, lineEnd);) {
+ var text = cm.getRange(cursor.from(), cursor.to());
+ var newText = text.replace(query, replacePart);
+ cursor.replace(newText);
+ }
+ var vim = getVimState(cm);
+ if (vim.visualMode) {
+ exitVisualMode(cm, vim);
+ }
+ }
+ if (cm.compoundChange) {
+ // Only exists in v2
+ cm.compoundChange(doReplace);
+ } else {
+ cm.operation(doReplace);
+ }
+ },
redo: CodeMirror.commands.redo,
undo: CodeMirror.commands.undo,
write: function(cm) {
@@ -2200,7 +2413,7 @@
}
};
- var exCommandDispatcher = new ExCommandDispatcher();
+ var exCommandDispatcher = new Vim.ExCommandDispatcher();
// Register Vim with CodeMirror
function buildVimKeyMap() {
View
160 vendor/assets/javascripts/codemirror/modes/apl.js
@@ -0,0 +1,160 @@
+CodeMirror.defineMode("apl", function() {
+ var builtInOps = {
+ ".": "innerProduct",
+ "\\": "scan",
+ "/": "reduce",
+ "": "reduce1Axis",
+ "": "scan1Axis",
+ "¨": "each",
+ "": "power"
+ };
+ var builtInFuncs = {
+ "+": ["conjugate", "add"],
+ "": ["negate", "subtract"],
+ "×": ["signOf", "multiply"],
+ "÷": ["reciprocal", "divide"],
+ "": ["ceiling", "greaterOf"],
+ "": ["floor", "lesserOf"],
+ "": ["absolute", "residue"],
+ "": ["indexGenerate", "indexOf"],
+ "?": ["roll", "deal"],
+ "": ["exponentiate", "toThePowerOf"],
+ "": ["naturalLog", "logToTheBase"],
+ "": ["piTimes", "circularFuncs"],
+ "!": ["factorial", "binomial"],
+ "": ["matrixInverse", "matrixDivide"],
+ "<": [null, "lessThan"],
+ "": [null, "lessThanOrEqual"],
+ "=": [null, "equals"],
+ ">": [null, "greaterThan"],
+ "": [null, "greaterThanOrEqual"],
+ "": [null, "notEqual"],
+ "": ["depth", "match"],
+ "": [null, "notMatch"],
+ "": ["enlist", "membership"],
+ "": [null, "find"],
+ "": ["unique", "union"],
+ "": [null, "intersection"],
+ "": ["not", "without"],
+ "": [null, "or"],
+ "": [null, "and"],
+ "": [null, "nor"],
+ "": [null, "nand"],
+ "": ["shapeOf", "reshape"],
+ ",": ["ravel", "catenate"],
+ "": [null, "firstAxisCatenate"],
+ "": ["reverse", "rotate"],
+ "": ["axis1Reverse", "axis1Rotate"],
+ "": ["transpose", null],
+ "": ["first", "take"],
+ "": [null, "drop"],
+ "": ["enclose", "partitionWithAxis"],
+ "": ["diclose", "pick"],
+ "": [null, "index"],
+ "": ["gradeUp", null],
+ "": ["gradeDown", null],
+ "": ["encode", null],
+ "": ["decode", null],
+ "": ["format", "formatByExample"],
+ "": ["execute", null],
+ "": ["stop", "left"],
+ "": ["pass", "right"]
+ };
+
+ var isOperator = /[\.\/⌿⍀¨⍣]/;
+ var isNiladic = //;
+ var isFunction = /[\+−×÷⌈⌊∣⍳\?⋆⍟○!⌹<≤=>≥≠≡≢∈⍷∪∩∼∨∧⍱⍲⍴,⍪⌽⊖⍉↑↓⊂⊃⌷⍋⍒⊤⊥⍕⍎⊣⊢]/;
+ var isArrow = //;
+ var isComment = /[⍝#].*$/;
+
+ var stringEater = function(type) {
+ var prev;
+ prev = false;
+ return function(c) {
+ prev = c;
+ if (c === type) {
+ return prev === "\\";
+ }
+ return true;
+ };
+ };
+ return {
+ startState: function() {
+ return {
+ prev: false,
+ func: false,
+ op: false,
+ string: false,
+ escape: false
+ };
+ },
+ token: function(stream, state) {
+ var ch, funcName, word;
+ if (stream.eatSpace()) {
+ return null;
+ }
+ ch = stream.next();
+ if (ch === '"' || ch === "'") {
+ stream.eatWhile(stringEater(ch));
+ stream.next();
+ state.prev = true;
+ return "string";
+ }
+ if (/[\[{\(]/.test(ch)) {
+ state.prev = false;
+ return null;
+ }
+ if (/[\]}\)]/.test(ch)) {
+ state.prev = true;
+ return null;
+ }
+ if (isNiladic.test(ch)) {
+ state.prev = false;
+ return "niladic";
+ }
+ if (/\d]/.test(ch)) {
+ if (state.func) {
+ state.func = false;
+ state.prev = false;
+ } else {
+ state.prev = true;
+ }
+ stream.eatWhile(/[\w\.]/);
+ return "number";
+ }
+ if (isOperator.test(ch)) {
+ return "operator apl-" + builtInOps[ch];
+ }
+ if (isArrow.test(ch)) {
+ return "apl-arrow";
+ }
+ if (isFunction.test(ch)) {
+ funcName = "apl-";
+ if (builtInFuncs[ch] != null) {
+ if (state.prev) {
+ funcName += builtInFuncs[ch][1];
+ } else {
+ funcName += builtInFuncs[ch][0];
+ }
+ }
+ state.func = true;
+ state.prev = false;
+ return "function " + funcName;
+ }
+ if (isComment.test(ch)) {
+ stream.skipToEnd();
+ return "comment";
+ }
+ if (ch === "" && stream.peek() === ".") {
+ stream.next();
+ return "function jot-dot";
+ }
+ stream.eatWhile(/[\w\$_]/);
+ word = stream.current();
+ state.prev = true;
+ return "keyword";
+ }
+ };
+});
+
+CodeMirror.defineMIME("text/apl", "apl");
View
183 vendor/assets/javascripts/codemirror/modes/asterisk.js
@@ -0,0 +1,183 @@
+/*
+ * =====================================================================================
+ *
+ * Filename: mode/asterisk/asterisk.js
+ *
+ * Description: CodeMirror mode for Asterisk dialplan
+ *
+ * Created: 05/17/2012 09:20:25 PM
+ * Revision: none
+ *
+ * Author: Stas Kobzar (stas@modulis.ca),
+ * Company: Modulis.ca Inc.
+ *
+ * =====================================================================================
+ */
+
+CodeMirror.defineMode("asterisk", function() {
+ var atoms = ["exten", "same", "include","ignorepat","switch"],
+ dpcmd = ["#include","#exec"],
+ apps = [
+ "addqueuemember","adsiprog","aelsub","agentlogin","agentmonitoroutgoing","agi",
+ "alarmreceiver","amd","answer","authenticate","background","backgrounddetect",
+ "bridge","busy","callcompletioncancel","callcompletionrequest","celgenuserevent",
+ "changemonitor","chanisavail","channelredirect","chanspy","clearhash","confbridge",
+ "congestion","continuewhile","controlplayback","dahdiacceptr2call","dahdibarge",
+ "dahdiras","dahdiscan","dahdisendcallreroutingfacility","dahdisendkeypadfacility",
+ "datetime","dbdel","dbdeltree","deadagi","dial","dictate","directory","disa",
+ "dumpchan","eagi","echo","endwhile","exec","execif","execiftime","exitwhile","extenspy",
+ "externalivr","festival","flash","followme","forkcdr","getcpeid","gosub","gosubif",
+ "goto","gotoif","gotoiftime","hangup","iax2provision","ices","importvar","incomplete",
+ "ivrdemo","jabberjoin","jabberleave","jabbersend","jabbersendgroup","jabberstatus",
+ "jack","log","macro","macroexclusive","macroexit","macroif","mailboxexists","meetme",
+ "meetmeadmin","meetmechanneladmin","meetmecount","milliwatt","minivmaccmess","minivmdelete",
+ "minivmgreet","minivmmwi","minivmnotify","minivmrecord","mixmonitor","monitor","morsecode",
+ "mp3player","mset","musiconhold","nbscat","nocdr","noop","odbc","odbc","odbcfinish",
+ "originate","ospauth","ospfinish","osplookup","ospnext","page","park","parkandannounce",
+ "parkedcall","pausemonitor","pausequeuemember","pickup","pickupchan","playback","playtones",
+ "privacymanager","proceeding","progress","queue","queuelog","raiseexception","read","readexten",
+ "readfile","receivefax","receivefax","receivefax","record","removequeuemember",
+ "resetcdr","retrydial","return","ringing","sayalpha","saycountedadj","saycountednoun",
+ "saycountpl","saydigits","saynumber","sayphonetic","sayunixtime","senddtmf","sendfax",
+ "sendfax","sendfax","sendimage","sendtext","sendurl","set","setamaflags",
+ "setcallerpres","setmusiconhold","sipaddheader","sipdtmfmode","sipremoveheader","skel",
+ "slastation","slatrunk","sms","softhangup","speechactivategrammar","speechbackground",
+ "speechcreate","speechdeactivategrammar","speechdestroy","speechloadgrammar","speechprocessingsound",
+ "speechstart","speechunloadgrammar","stackpop","startmusiconhold","stopmixmonitor","stopmonitor",
+ "stopmusiconhold","stopplaytones","system","testclient","testserver","transfer","tryexec",
+ "trysystem","unpausemonitor","unpausequeuemember","userevent","verbose","vmauthenticate",
+ "vmsayname","voicemail","voicemailmain","wait","waitexten","waitfornoise","waitforring",
+ "waitforsilence","waitmusiconhold","waituntil","while","zapateller"
+ ];
+
+ function basicToken(stream,state){
+ var cur = '';
+ var ch = '';
+ ch = stream.next();
+ // comment
+ if(ch == ";") {
+ stream.skipToEnd();
+ return "comment";
+ }
+ // context
+ if(ch == '[') {
+ stream.skipTo(']');
+ stream.eat(']');
+ return "header";
+ }
+ // string
+ if(ch == '"') {
+ stream.skipTo('"');
+ return "string";
+ }
+ if(ch == "'") {
+ stream.skipTo("'");
+ return "string-2";
+ }
+ // dialplan commands
+ if(ch == '#') {
+ stream.eatWhile(/\w/);
+ cur = stream.current();
+ if(dpcmd.indexOf(cur) !== -1) {
+ stream.skipToEnd();
+ return "strong";
+ }
+ }
+ // application args
+ if(ch == '$'){
+ var ch1 = stream.peek();
+ if(ch1 == '{'){
+ stream.skipTo('}');
+ stream.eat('}');
+ return "variable-3";
+ }
+ }
+ // extension
+ stream.eatWhile(/\w/);
+ cur = stream.current();
+ if(atoms.indexOf(cur) !== -1) {
+ state.extenStart = true;
+ switch(cur) {
+ case 'same': state.extenSame = true; break;
+ case 'include':
+ case 'switch':
+ case 'ignorepat':
+ state.extenInclude = true;break;
+ default:break;
+ }
+ return "atom";
+ }
+ }
+
+ return {
+ startState: function() {
+ return {
+ extenStart: false,
+ extenSame: false,
+ extenInclude: false,
+ extenExten: false,
+ extenPriority: false,
+ extenApplication: false
+ };
+ },
+ token: function(stream, state) {
+
+ var cur = '';
+ var ch = '';
+ if(stream.eatSpace()) return null;
+ // extension started
+ if(state.extenStart){
+ stream.eatWhile(/[^\s]/);
+ cur = stream.current();
+ if(/^=>?$/.test(cur)){
+ state.extenExten = true;
+ state.extenStart = false;
+ return "strong";
+ } else {
+ state.extenStart = false;
+ stream.skipToEnd();
+ return "error";
+ }
+ } else if(state.extenExten) {
+ // set exten and priority
+ state.extenExten = false;
+ state.extenPriority = true;
+ stream.eatWhile(/[^,]/);
+ if(state.extenInclude) {
+ stream.skipToEnd();
+ state.extenPriority = false;
+ state.extenInclude = false;
+ }
+ if(state.extenSame) {
+ state.extenPriority = false;
+ state.extenSame = false;
+ state.extenApplication = true;
+ }
+ return "tag";
+ } else if(state.extenPriority) {
+ state.extenPriority = false;
+ state.extenApplication = true;
+ ch = stream.next(); // get comma
+ if(state.extenSame) return null;
+ stream.eatWhile(/[^,]/);
+ return "number";
+ } else if(state.extenApplication) {
+ stream.eatWhile(/,/);
+ cur = stream.current();
+ if(cur === ',') return null; </