Changeset - af3c746b3f1f
[Not reviewed]
default
0 5 0
Marcin Kuzminski - 12 years ago 2013-06-26 14:29:49
marcin@python-works.com
update codemirror to latest version
5 files changed with 511 insertions and 605 deletions:
0 comments (0 inline, 0 general)
rhodecode/public/css/codemirror.css
Show inline comments
 
@@ -10,33 +10,34 @@
 
  overflow: auto;
 
}
 

	
 
/* PADDING */
 

	
 
.CodeMirror-lines {
 
  padding: 4px 0; /* Vertical padding around content */
 
}
 
.CodeMirror pre {
 
  padding: 0 4px; /* Horizontal padding of content */
 
}
 

	
 
.CodeMirror-scrollbar-filler {
 
.CodeMirror-scrollbar-filler, .CodeMirror-gutter-filler {
 
  background-color: white; /* The little square between H and V scrollbars */
 
}
 

	
 
/* GUTTER */
 

	
 
.CodeMirror-gutters {
 
  border-right: 1px solid #ddd;
 
  background-color: #f7f7f7;
 
  white-space: nowrap;
 
}
 
.CodeMirror-linenumbers {}
 
.CodeMirror-linenumber {
 
  padding: 0 3px 0 5px;
 
  min-width: 20px;
 
  text-align: right;
 
  color: #999;
 
}
 

	
 
/* CURSOR */
 

	
 
.CodeMirror div.CodeMirror-cursor {
 
@@ -115,51 +116,53 @@ div.CodeMirror span.CodeMirror-nonmatchi
 
  padding-bottom: 30px; padding-right: 30px;
 
  height: 100%;
 
  outline: none; /* Prevent dragging from highlighting the element */
 
  position: relative;
 
}
 
.CodeMirror-sizer {
 
  position: relative;
 
}
 

	
 
/* The fake, visible scrollbars. Used to force redraw during scrolling
 
   before actuall scrolling happens, thus preventing shaking and
 
   flickering artifacts. */
 
.CodeMirror-vscrollbar, .CodeMirror-hscrollbar, .CodeMirror-scrollbar-filler {
 
.CodeMirror-vscrollbar, .CodeMirror-hscrollbar, .CodeMirror-scrollbar-filler, .CodeMirror-gutter-filler {
 
  position: absolute;
 
  z-index: 6;
 
  display: none;
 
}
 
.CodeMirror-vscrollbar {
 
  right: 0; top: 0;
 
  overflow-x: hidden;
 
  overflow-y: scroll;
 
}
 
.CodeMirror-hscrollbar {
 
  bottom: 0; left: 0;
 
  overflow-y: hidden;
 
  overflow-x: scroll;
 
}
 
.CodeMirror-scrollbar-filler {
 
  right: 0; bottom: 0;
 
  z-index: 6;
 
}
 
.CodeMirror-gutter-filler {
 
  left: 0; bottom: 0;
 
}
 

	
 
.CodeMirror-gutters {
 
  position: absolute; left: 0; top: 0;
 
  height: 100%;
 
  padding-bottom: 30px;
 
  z-index: 3;
 
}
 
.CodeMirror-gutter {
 
  white-space: normal;
 
  height: 100%;
 
  padding-bottom: 30px;
 
  margin-bottom: -32px;
 
  display: inline-block;
 
  /* Hack to make IE7 behave */
 
  *zoom:1;
 
  *display:inline;
 
}
 
.CodeMirror-gutter-elt {
 
  position: absolute;
 
  cursor: default;
 
  z-index: 4;
 
@@ -193,25 +196,24 @@ div.CodeMirror span.CodeMirror-nonmatchi
 
  position: absolute;
 
  left: 0; right: 0; top: 0; bottom: 0;
 
  z-index: 0;
 
}
 

	
 
.CodeMirror-linewidget {
 
  position: relative;
 
  z-index: 2;
 
  overflow: auto;
 
}
 

	
 
.CodeMirror-widget {
 
  display: inline-block;
 
}
 

	
 
.CodeMirror-wrap .CodeMirror-scroll {
 
  overflow-x: hidden;
 
}
 

	
 
.CodeMirror-measure {
 
  position: absolute;
 
  width: 100%; height: 0px;
 
  overflow: hidden;
 
  visibility: hidden;
 
}
rhodecode/public/js/codemirror.js
Show inline comments
 
// CodeMirror version 3.14
 
//
 
// CodeMirror is the only global var we claim
 
window.CodeMirror = (function() {
 
  "use strict";
 

	
 
  // BROWSER SNIFFING
 

	
 
  // Crude, but necessary to handle a number of hard-to-feature-detect
 
  // bugs and behavior differences.
 
  var gecko = /gecko\/\d/i.test(navigator.userAgent);
 
  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);
 
@@ -88,61 +90,60 @@ window.CodeMirror = (function() {
 
  }
 

	
 
  // DISPLAY CONSTRUCTOR
 

	
 
  function makeDisplay(place, docStart) {
 
    var d = {};
 

	
 
    var input = d.input = elt("textarea", null, null, "position: absolute; padding: 0; width: 1px; height: 1em; outline: none; font-size: 4px;");
 
    if (webkit) input.style.width = "1000px";
 
    else input.setAttribute("wrap", "off");
 
    // if border: 0; -- iOS fails to open keyboard (issue #1287)
 
    if (ios) input.style.border = "1px solid black";
 
    input.setAttribute("autocorrect", "off"); input.setAttribute("autocapitalize", "off");
 
    input.setAttribute("autocorrect", "off"); input.setAttribute("autocapitalize", "off"); input.setAttribute("spellcheck", "false");
 

	
 
    // Wraps and hides input textarea
 
    d.inputDiv = elt("div", [input], null, "overflow: hidden; position: relative; width: 3px; height: 0px;");
 
    // The actual fake scrollbars.
 
    d.scrollbarH = elt("div", [elt("div", null, null, "height: 1px")], "CodeMirror-hscrollbar");
 
    d.scrollbarV = elt("div", [elt("div", null, null, "width: 1px")], "CodeMirror-vscrollbar");
 
    d.scrollbarFiller = elt("div", null, "CodeMirror-scrollbar-filler");
 
    d.gutterFiller = elt("div", null, "CodeMirror-gutter-filler");
 
    // DIVs containing the selection and the actual code
 
    d.lineDiv = elt("div");
 
    d.lineDiv = elt("div", null, "CodeMirror-code");
 
    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("div", "\u00a0", "CodeMirror-cursor");
 
    // Secondary cursor, shown when on a 'jump' in bi-directional text
 
    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
 
    d.lineSpace = elt("div", [d.measure, d.selectionDiv, d.lineDiv, d.cursor, d.otherCursor],
 
                         null, "position: relative; outline: none");
 
    // Moved around its parent to cover visible view
 
    d.mover = elt("div", [elt("div", [d.lineSpace], "CodeMirror-lines")], null, "position: relative");
 
    // Set to the height of the text, causes scrolling
 
    d.sizer = elt("div", [d.mover], "CodeMirror-sizer");
 
    // D is needed because behavior of elts with overflow: auto and padding is inconsistent across browsers
 
    d.heightForcer = elt("div", null, null, "position: absolute; height: " + scrollerCutOff + "px; width: 1px;");
 
    // Will contain the gutters, if any
 
    d.gutters = elt("div", null, "CodeMirror-gutters");
 
    d.lineGutter = null;
 
    // Helper element to properly size the gutter backgrounds
 
    var scrollerInner = elt("div", [d.sizer, d.heightForcer, d.gutters], null, "position: relative; min-height: 100%");
 
    // Provides scrolling
 
    d.scroller = elt("div", [scrollerInner], "CodeMirror-scroll");
 
    d.scroller = elt("div", [d.sizer, d.heightForcer, d.gutters], "CodeMirror-scroll");
 
    d.scroller.setAttribute("tabIndex", "-1");
 
    // The element in which the editor lives.
 
    d.wrapper = elt("div", [d.inputDiv, d.scrollbarH, d.scrollbarV,
 
                            d.scrollbarFiller, d.scroller], "CodeMirror");
 
                            d.scrollbarFiller, d.gutterFiller, d.scroller], "CodeMirror");
 
    // Work around IE7 z-index bug
 
    if (ie_lt8) { d.gutters.style.zIndex = -1; d.scroller.style.paddingRight = 0; }
 
    if (place.appendChild) place.appendChild(d.wrapper); else place(d.wrapper);
 

	
 
    // Needed to hide big blue blinking cursor on Mobile Safari
 
    if (ios) input.style.width = "0px";
 
    if (!webkit) d.scroller.draggable = true;
 
    // Needed to handle Tab key in KHTML
 
    if (khtml) { d.inputDiv.style.height = "1px"; d.inputDiv.style.position = "absolute"; }
 
    // Need to set a minimum width to see the scrollbar on IE7 (but must not set it on IE8).
 
    else if (ie_lt8) d.scrollbarH.style.minWidth = d.scrollbarV.style.minWidth = "18px";
 

	
 
@@ -203,63 +204,65 @@ window.CodeMirror = (function() {
 

	
 
  function wrappingChanged(cm) {
 
    if (cm.options.lineWrapping) {
 
      cm.display.wrapper.className += " CodeMirror-wrap";
 
      cm.display.sizer.style.minWidth = "";
 
    } else {
 
      cm.display.wrapper.className = cm.display.wrapper.className.replace(" CodeMirror-wrap", "");
 
      computeMaxLength(cm);
 
    }
 
    estimateLineHeights(cm);
 
    regChange(cm);
 
    clearCaches(cm);
 
    setTimeout(function(){updateScrollbars(cm.display, cm.doc.height);}, 100);
 
    setTimeout(function(){updateScrollbars(cm);}, 100);
 
  }
 

	
 
  function estimateHeight(cm) {
 
    var th = textHeight(cm.display), wrapping = cm.options.lineWrapping;
 
    var perLine = wrapping && Math.max(5, cm.display.scroller.clientWidth / charWidth(cm.display) - 3);
 
    return function(line) {
 
      if (lineIsHidden(cm.doc, line))
 
        return 0;
 
      else if (wrapping)
 
        return (Math.ceil(line.text.length / perLine) || 1) * th;
 
      else
 
        return th;
 
    };
 
  }
 

	
 
  function estimateLineHeights(cm) {
 
    var doc = cm.doc, est = estimateHeight(cm);
 
    doc.iter(function(line) {
 
      var estHeight = est(line);
 
      if (estHeight != line.height) updateLineHeight(line, estHeight);
 
    });
 
  }
 

	
 
  function keyMapChanged(cm) {
 
    var style = keyMap[cm.options.keyMap].style;
 
    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) {
 
    cm.display.wrapper.className = cm.display.wrapper.className.replace(/\s*cm-s-\S+/g, "") +
 
      cm.options.theme.replace(/(^|\s)\s*/g, " cm-s-");
 
    clearCaches(cm);
 
  }
 

	
 
  function guttersChanged(cm) {
 
    updateGutters(cm);
 
    regChange(cm);
 
    setTimeout(function(){alignHorizontally(cm);}, 20);
 
  }
 

	
 
  function updateGutters(cm) {
 
    var gutters = cm.display.gutters, specs = cm.options.gutters;
 
    removeChildren(gutters);
 
    for (var i = 0; i < specs.length; ++i) {
 
      var gutterClass = specs[i];
 
      var gElt = gutters.appendChild(elt("div", null, "CodeMirror-gutter " + gutterClass));
 
      if (gutterClass == "CodeMirror-linenumbers") {
 
        cm.display.lineGutter = gElt;
 
        gElt.style.width = (cm.display.lineNumWidth || 1) + "px";
 
      }
 
@@ -308,46 +311,53 @@ window.CodeMirror = (function() {
 
        if (options.lineNumbers) found = true;
 
        else options.gutters.splice(i--, 1);
 
      }
 
    }
 
    if (!found && options.lineNumbers)
 
      options.gutters.push("CodeMirror-linenumbers");
 
  }
 

	
 
  // SCROLLBARS
 

	
 
  // Re-synchronize the fake scrollbars with the actual size of the
 
  // content. Optionally force a scrollTop.
 
  function updateScrollbars(d /* display */, docHeight) {
 
  function updateScrollbars(cm) {
 
    var d = cm.display, docHeight = cm.doc.height;
 
    var totalHeight = docHeight + paddingVert(d);
 
    d.sizer.style.minHeight = d.heightForcer.style.top = totalHeight + "px";
 
    d.gutters.style.height = Math.max(totalHeight, d.scroller.clientHeight - scrollerCutOff) + "px";
 
    var scrollHeight = Math.max(totalHeight, d.scroller.scrollHeight);
 
    var needsH = d.scroller.scrollWidth > d.scroller.clientWidth;
 
    var needsV = scrollHeight > d.scroller.clientHeight;
 
    var needsH = d.scroller.scrollWidth > (d.scroller.clientWidth + 1);
 
    var needsV = scrollHeight > (d.scroller.clientHeight + 1);
 
    if (needsV) {
 
      d.scrollbarV.style.display = "block";
 
      d.scrollbarV.style.bottom = needsH ? scrollbarWidth(d.measure) + "px" : "0";
 
      d.scrollbarV.firstChild.style.height =
 
        (scrollHeight - d.scroller.clientHeight + d.scrollbarV.clientHeight) + "px";
 
    } else d.scrollbarV.style.display = "";
 
    if (needsH) {
 
      d.scrollbarH.style.display = "block";
 
      d.scrollbarH.style.right = needsV ? scrollbarWidth(d.measure) + "px" : "0";
 
      d.scrollbarH.firstChild.style.width =
 
        (d.scroller.scrollWidth - d.scroller.clientWidth + d.scrollbarH.clientWidth) + "px";
 
    } else d.scrollbarH.style.display = "";
 
    if (needsH && needsV) {
 
      d.scrollbarFiller.style.display = "block";
 
      d.scrollbarFiller.style.height = d.scrollbarFiller.style.width = scrollbarWidth(d.measure) + "px";
 
    } else d.scrollbarFiller.style.display = "";
 
    if (needsH && cm.options.coverGutterNextToScrollbar && cm.options.fixedGutter) {
 
      d.gutterFiller.style.display = "block";
 
      d.gutterFiller.style.height = scrollbarWidth(d.measure) + "px";
 
      d.gutterFiller.style.width = d.gutters.offsetWidth + "px";
 
    } else d.gutterFiller.style.display = "";
 

	
 
    if (mac_geLion && scrollbarWidth(d.measure) === 0)
 
      d.scrollbarV.style.minWidth = d.scrollbarH.style.minHeight = mac_geMountainLion ? "18px" : "12px";
 
  }
 

	
 
  function visibleLines(display, doc, viewPort) {
 
    var top = display.scroller.scrollTop, height = display.wrapper.clientHeight;
 
    if (typeof viewPort == "number") top = viewPort;
 
    else if (viewPort) {top = viewPort.top; height = viewPort.bottom - viewPort.top;}
 
    top = Math.floor(top - paddingTop(display));
 
    var bottom = Math.ceil(top + height);
 
    return {from: lineAtHeight(doc, top), to: lineAtHeight(doc, bottom)};
 
@@ -388,43 +398,44 @@ window.CodeMirror = (function() {
 
    return String(options.lineNumberFormatter(i + options.firstLineNumber));
 
  }
 
  function compensateForHScroll(display) {
 
    return getRect(display.scroller).left - getRect(display.sizer).left;
 
  }
 

	
 
  // DISPLAY DRAWING
 

	
 
  function updateDisplay(cm, changes, viewPort) {
 
    var oldFrom = cm.display.showingFrom, oldTo = cm.display.showingTo, updated;
 
    var visible = visibleLines(cm.display, cm.doc, viewPort);
 
    for (;;) {
 
      if (updateDisplayInner(cm, changes, visible)) {
 
        updated = true;
 
        signalLater(cm, "update", cm);
 
        if (cm.display.showingFrom != oldFrom || cm.display.showingTo != oldTo)
 
          signalLater(cm, "viewportChange", cm, cm.display.showingFrom, cm.display.showingTo);
 
      } else break;
 
      if (!updateDisplayInner(cm, changes, visible)) break;
 
      updated = true;
 
      updateSelection(cm);
 
      updateScrollbars(cm.display, cm.doc.height);
 
      updateScrollbars(cm);
 

	
 
      // Clip forced viewport to actual scrollable area
 
      if (viewPort)
 
        viewPort = Math.min(cm.display.scroller.scrollHeight - cm.display.scroller.clientHeight,
 
                            typeof viewPort == "number" ? viewPort : viewPort.top);
 
      visible = visibleLines(cm.display, cm.doc, viewPort);
 
      if (visible.from >= cm.display.showingFrom && visible.to <= cm.display.showingTo)
 
        break;
 
      changes = [];
 
    }
 

	
 
    if (updated) {
 
      signalLater(cm, "update", cm);
 
      if (cm.display.showingFrom != oldFrom || cm.display.showingTo != oldTo)
 
        signalLater(cm, "viewportChange", cm, cm.display.showingFrom, cm.display.showingTo);
 
    }
 
    return updated;
 
  }
 

	
 
  // Uses a set of changes plus the current scroll position to
 
  // determine which DOM updates have to be made, and makes the
 
  // updates.
 
  function updateDisplayInner(cm, changes, visible) {
 
    var display = cm.display, doc = cm.doc;
 
    if (!display.wrapper.clientWidth) {
 
      display.showingFrom = display.showingTo = doc.first;
 
      display.viewOffset = 0;
 
      return;
 
@@ -494,27 +505,29 @@ window.CodeMirror = (function() {
 
    try {
 
      var focused = document.activeElement;
 
    } catch(e) {}
 
    if (intactLines < (to - from) * .7) display.lineDiv.style.display = "none";
 
    patchDisplay(cm, from, to, intact, positionsChangedFrom);
 
    display.lineDiv.style.display = "";
 
    if (focused && document.activeElement != focused && focused.offsetHeight) focused.focus();
 

	
 
    var different = from != display.showingFrom || to != display.showingTo ||
 
      display.lastSizeC != display.wrapper.clientHeight;
 
    // This is just a bogus formula that detects when the editor is
 
    // resized or the font size changes.
 
    if (different) display.lastSizeC = display.wrapper.clientHeight;
 
    if (different) {
 
      display.lastSizeC = display.wrapper.clientHeight;
 
      startWorker(cm, 400);
 
    }
 
    display.showingFrom = from; display.showingTo = to;
 
    startWorker(cm, 100);
 

	
 
    var prevBottom = display.lineDiv.offsetTop;
 
    for (var node = display.lineDiv.firstChild, height; node; node = node.nextSibling) if (node.lineObj) {
 
      if (ie_lt8) {
 
        var bot = node.offsetTop + node.offsetHeight;
 
        height = bot - prevBottom;
 
        prevBottom = bot;
 
      } else {
 
        var box = getRect(node);
 
        height = box.bottom - box.top;
 
      }
 
      var diff = node.lineObj.height - height;
 
@@ -585,36 +598,39 @@ window.CodeMirror = (function() {
 
        node.lineObj = null;
 
      } else {
 
        node.parentNode.removeChild(node);
 
      }
 
      return next;
 
    }
 

	
 
    var nextIntact = intact.shift(), lineN = from;
 
    cm.doc.iter(from, to, function(line) {
 
      if (nextIntact && nextIntact.to == lineN) nextIntact = intact.shift();
 
      if (lineIsHidden(cm.doc, 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) {
 
        if (line.widgets && cur.previousSibling) for (var i = 0; i < line.widgets.length; ++i) {
 
          var w = line.widgets[i];
 
          if (w.showIfHidden) {
 
            var prev = cur.previousSibling;
 
            if (/pre/i.test(prev.nodeName)) {
 
              var wrap = elt("div", null, null, "position: relative");
 
              prev.parentNode.replaceChild(wrap, prev);
 
              wrap.appendChild(prev);
 
              prev = wrap;
 
            }
 
            var wnode = prev.appendChild(elt("div", [line.widgets[i].node], "CodeMirror-linewidget"));
 
            positionLineWidget(line.widgets[i], wnode, prev, dims);
 
            var wnode = prev.appendChild(elt("div", [w.node], "CodeMirror-linewidget"));
 
            if (!w.handleMouseEvents) wnode.ignoreEvents = true;
 
            positionLineWidget(w, wnode, prev, dims);
 
          }
 
        }
 
      } else if (nextIntact && nextIntact.from <= lineN && nextIntact.to > lineN) {
 
        // This line is intact. Skip to the actual node. Update its
 
        // line number if needed.
 
        while (cur.lineObj != line) cur = rm(cur);
 
        if (lineNumbers && updateNumbersFrom <= lineN && cur.lineNumber)
 
          setTextContent(cur.lineNumber, lineNumberFor(cm.options, lineN));
 
        cur = cur.nextSibling;
 
      } else {
 
        // For lines with widgets, make an attempt to find and reuse
 
        // the existing element, so that widgets aren't needlessly
 
        // removed and re-inserted into the dom
 
        if (line.widgets) for (var j = 0, search = cur, reuse; search && j < 20; ++j, search = search.nextSibling)
 
@@ -639,43 +655,43 @@ window.CodeMirror = (function() {
 
    var lineElement = lineContent(cm, line);
 
    var markers = line.gutterMarkers, display = cm.display, wrap;
 

	
 
    if (!cm.options.lineNumbers && !markers && !line.bgClass && !line.wrapClass && !line.widgets)
 
      return lineElement;
 

	
 
    // Lines with gutter elements, widgets or a background class need
 
    // to be wrapped again, and have the extra elements added to the
 
    // wrapper div
 

	
 
    if (reuse) {
 
      reuse.alignable = null;
 
      var isOk = true, widgetsSeen = 0;
 
      var isOk = true, widgetsSeen = 0, insertBefore = null;
 
      for (var n = reuse.firstChild, next; n; n = next) {
 
        next = n.nextSibling;
 
        if (!/\bCodeMirror-linewidget\b/.test(n.className)) {
 
          reuse.removeChild(n);
 
        } else {
 
          for (var i = 0, first = true; i < line.widgets.length; ++i) {
 
            var widget = line.widgets[i], isFirst = false;
 
            if (!widget.above) { isFirst = first; first = false; }
 
            var widget = line.widgets[i];
 
            if (!widget.above) { insertBefore = n; first = false; }
 
            if (widget.node == n.firstChild) {
 
              positionLineWidget(widget, n, reuse, dims);
 
              ++widgetsSeen;
 
              if (isFirst) reuse.insertBefore(lineElement, n);
 
              break;
 
            }
 
          }
 
          if (i == line.widgets.length) { isOk = false; break; }
 
        }
 
      }
 
      reuse.insertBefore(lineElement, insertBefore);
 
      if (isOk && widgetsSeen == line.widgets.length) {
 
        wrap = reuse;
 
        reuse.className = line.wrapClass || "";
 
      }
 
    }
 
    if (!wrap) {
 
      wrap = elt("div", null, line.wrapClass, "position: relative");
 
      wrap.appendChild(lineElement);
 
    }
 
    // Kludge to make sure the styled element lies behind the selection (by z-index)
 
    if (line.bgClass)
 
      wrap.insertBefore(elt("div", null, line.bgClass + " CodeMirror-linebackground"), wrap.firstChild);
 
@@ -692,24 +708,25 @@ window.CodeMirror = (function() {
 
              + display.lineNumInnerWidth + "px"));
 
      if (markers)
 
        for (var k = 0; k < cm.options.gutters.length; ++k) {
 
          var id = cm.options.gutters[k], found = markers.hasOwnProperty(id) && markers[id];
 
          if (found)
 
            gutterWrap.appendChild(elt("div", [found], "CodeMirror-gutter-elt", "left: " +
 
                                       dims.gutterLeft[id] + "px; width: " + dims.gutterWidth[id] + "px"));
 
        }
 
    }
 
    if (ie_lt8) wrap.style.zIndex = 2;
 
    if (line.widgets && wrap != reuse) for (var i = 0, ws = line.widgets; i < ws.length; ++i) {
 
      var widget = ws[i], node = elt("div", [widget.node], "CodeMirror-linewidget");
 
      if (!widget.handleMouseEvents) node.ignoreEvents = true;
 
      positionLineWidget(widget, node, wrap, dims);
 
      if (widget.above)
 
        wrap.insertBefore(node, cm.options.lineNumbers && line.height != 0 ? gutterWrap : lineElement);
 
      else
 
        wrap.appendChild(node);
 
      signalLater(widget, "redraw");
 
    }
 
    return wrap;
 
  }
 

	
 
  function positionLineWidget(widget, node, wrap, dims) {
 
    if (widget.noHScroll) {
 
@@ -774,92 +791,77 @@ window.CodeMirror = (function() {
 
  function updateSelectionRange(cm) {
 
    var display = cm.display, doc = cm.doc, sel = cm.doc.sel;
 
    var fragment = document.createDocumentFragment();
 
    var clientWidth = display.lineSpace.offsetWidth, pl = paddingLeft(cm.display);
 

	
 
    function add(left, top, width, bottom) {
 
      if (top < 0) top = 0;
 
      fragment.appendChild(elt("div", null, "CodeMirror-selected", "position: absolute; left: " + left +
 
                               "px; top: " + top + "px; width: " + (width == null ? clientWidth - left : width) +
 
                               "px; height: " + (bottom - top) + "px"));
 
    }
 

	
 
    function drawForLine(line, fromArg, toArg, retTop) {
 
    function drawForLine(line, fromArg, toArg) {
 
      var lineObj = getLine(doc, line);
 
      var lineLen = lineObj.text.length, rVal = retTop ? Infinity : -Infinity;
 
      function coords(ch) {
 
        return charCoords(cm, Pos(line, ch), "div", lineObj);
 
      var lineLen = lineObj.text.length;
 
      var start, end;
 
      function coords(ch, bias) {
 
        return charCoords(cm, Pos(line, ch), "div", lineObj, bias);
 
      }
 

	
 
      iterateBidiSections(getOrder(lineObj), fromArg || 0, toArg == null ? lineLen : toArg, function(from, to, dir) {
 
        var leftPos = coords(from), rightPos, left, right;
 
        var leftPos = coords(from, "left"), rightPos, left, right;
 
        if (from == to) {
 
          rightPos = leftPos;
 
          left = right = leftPos.left;
 
        } else {
 
          rightPos = coords(to - 1);
 
          rightPos = coords(to - 1, "right");
 
          if (dir == "rtl") { var tmp = leftPos; leftPos = rightPos; rightPos = tmp; }
 
          left = leftPos.left;
 
          right = rightPos.right;
 
        }
 
        if (fromArg == null && from == 0) left = pl;
 
        if (rightPos.top - leftPos.top > 3) { // Different lines, draw top part
 
          add(left, leftPos.top, null, leftPos.bottom);
 
          left = pl;
 
          if (leftPos.bottom < rightPos.top) add(left, leftPos.bottom, null, rightPos.top);
 
        }
 
        if (toArg == null && to == lineLen) right = clientWidth;
 
        if (fromArg == null && from == 0) left = pl;
 
        rVal = retTop ? Math.min(rightPos.top, rVal) : Math.max(rightPos.bottom, rVal);
 
        if (!start || leftPos.top < start.top || leftPos.top == start.top && leftPos.left < start.left)
 
          start = leftPos;
 
        if (!end || rightPos.bottom > end.bottom || rightPos.bottom == end.bottom && rightPos.right > end.right)
 
          end = rightPos;
 
        if (left < pl + 1) left = pl;
 
        add(left, rightPos.top, right - left, rightPos.bottom);
 
      });
 
      return rVal;
 
      return {start: start, end: end};
 
    }
 

	
 
    if (sel.from.line == sel.to.line) {
 
      drawForLine(sel.from.line, sel.from.ch, sel.to.ch);
 
    } else {
 
      var fromObj = getLine(doc, sel.from.line);
 
      var cur = fromObj, merged, path = [sel.from.line, sel.from.ch], singleLine;
 
      while (merged = collapsedSpanAtEnd(cur)) {
 
        var found = merged.find();
 
        path.push(found.from.ch, found.to.line, found.to.ch);
 
        if (found.to.line == sel.to.line) {
 
          path.push(sel.to.ch);
 
          singleLine = true;
 
          break;
 
      var fromLine = getLine(doc, sel.from.line), toLine = getLine(doc, sel.to.line);
 
      var singleVLine = visualLine(doc, fromLine) == visualLine(doc, toLine);
 
      var leftEnd = drawForLine(sel.from.line, sel.from.ch, singleVLine ? fromLine.text.length : null).end;
 
      var rightStart = drawForLine(sel.to.line, singleVLine ? 0 : null, sel.to.ch).start;
 
      if (singleVLine) {
 
        if (leftEnd.top < rightStart.top - 2) {
 
          add(leftEnd.right, leftEnd.top, null, leftEnd.bottom);
 
          add(pl, rightStart.top, rightStart.left, rightStart.bottom);
 
        } else {
 
          add(leftEnd.right, leftEnd.top, rightStart.left - leftEnd.right, leftEnd.bottom);
 
        }
 
        cur = getLine(doc, found.to.line);
 
      }
 

	
 
      // This is a single, merged line
 
      if (singleLine) {
 
        for (var i = 0; i < path.length; i += 3)
 
          drawForLine(path[i], path[i+1], path[i+2]);
 
      } else {
 
        var middleTop, middleBot, toObj = getLine(doc, sel.to.line);
 
        if (sel.from.ch)
 
          // Draw the first line of selection.
 
          middleTop = drawForLine(sel.from.line, sel.from.ch, null, false);
 
        else
 
          // Simply include it in the middle block.
 
          middleTop = heightAtLine(cm, fromObj) - display.viewOffset;
 

	
 
        if (!sel.to.ch)
 
          middleBot = heightAtLine(cm, toObj) - display.viewOffset;
 
        else
 
          middleBot = drawForLine(sel.to.line, collapsedSpanAtStart(toObj) ? null : 0, sel.to.ch, true);
 

	
 
        if (middleTop < middleBot) add(pl, middleTop, null, middleBot);
 
      }
 
      if (leftEnd.bottom < rightStart.top)
 
        add(pl, leftEnd.bottom, null, rightStart.top);
 
    }
 

	
 
    removeChildrenAndAdd(display.selectionDiv, fragment);
 
    display.selectionDiv.style.display = "";
 
  }
 

	
 
  // Cursor-blinking
 
  function restartBlink(cm) {
 
    if (!cm.state.focused) return;
 
    var display = cm.display;
 
    clearInterval(display.blinker);
 
    var on = true;
 
@@ -907,101 +909,108 @@ window.CodeMirror = (function() {
 
    if (changed.length)
 
      operation(cm, function() {
 
        for (var i = 0; i < changed.length; ++i)
 
          regChange(this, changed[i].start, changed[i].end);
 
      })();
 
  }
 

	
 
  // Finds the line to start with when starting a parse. Tries to
 
  // find a line with a stateAfter, so that it can start with a
 
  // valid state. If that fails, it returns the line with the
 
  // smallest indentation, which tends to need the least context to
 
  // parse correctly.
 
  function findStartLine(cm, n) {
 
  function findStartLine(cm, n, precise) {
 
    var minindent, minline, doc = cm.doc;
 
    for (var search = n, lim = n - 100; search > lim; --search) {
 
      if (search <= doc.first) return doc.first;
 
      var line = getLine(doc, search - 1);
 
      if (line.stateAfter) return search;
 
      if (line.stateAfter && (!precise || search <= doc.frontier)) return search;
 
      var indented = countColumn(line.text, null, cm.options.tabSize);
 
      if (minline == null || minindent > indented) {
 
        minline = search - 1;
 
        minindent = indented;
 
      }
 
    }
 
    return minline;
 
  }
 

	
 
  function getStateBefore(cm, n) {
 
  function getStateBefore(cm, n, precise) {
 
    var doc = cm.doc, display = cm.display;
 
      if (!doc.mode.startState) return true;
 
    var pos = findStartLine(cm, n), state = pos > doc.first && getLine(doc, pos-1).stateAfter;
 
    var pos = findStartLine(cm, n, precise), state = pos > doc.first && getLine(doc, pos-1).stateAfter;
 
    if (!state) state = startState(doc.mode);
 
    else state = copyState(doc.mode, state);
 
    doc.iter(pos, n, function(line) {
 
      processLine(cm, line, state);
 
      var save = pos == n - 1 || pos % 5 == 0 || pos >= display.showingFrom && pos < display.showingTo;
 
      line.stateAfter = save ? copyState(doc.mode, state) : null;
 
      ++pos;
 
    });
 
    return state;
 
  }
 

	
 
  // POSITION MEASUREMENT
 

	
 
  function paddingTop(display) {return display.lineSpace.offsetTop;}
 
  function paddingVert(display) {return display.mover.offsetHeight - display.lineSpace.offsetHeight;}
 
  function paddingLeft(display) {
 
    var e = removeChildrenAndAdd(display.measure, elt("pre", null, null, "text-align: left")).appendChild(elt("span", "x"));
 
    return e.offsetLeft;
 
  }
 

	
 
  function measureChar(cm, line, ch, data) {
 
  function measureChar(cm, line, ch, data, bias) {
 
    var dir = -1;
 
    data = data || measureLine(cm, line);
 

	
 
    for (var pos = ch;; pos += dir) {
 
      var r = data[pos];
 
      if (r) break;
 
      if (dir < 0 && pos == 0) dir = 1;
 
    }
 
    var rightV = (pos < ch || bias == "right") && r.topRight != null;
 
    return {left: pos < ch ? r.right : r.left,
 
            right: pos > ch ? r.left : r.right,
 
            top: r.top, bottom: r.bottom};
 
            top: rightV ? r.topRight : r.top,
 
            bottom: rightV ? r.bottomRight : r.bottom};
 
  }
 

	
 
  function findCachedMeasurement(cm, line) {
 
    var cache = cm.display.measureLineCache;
 
    for (var i = 0; i < cache.length; ++i) {
 
      var memo = cache[i];
 
      if (memo.text == line.text && memo.markedSpans == line.markedSpans &&
 
          cm.display.scroller.clientWidth == memo.width &&
 
          memo.classes == line.textClass + "|" + line.bgClass + "|" + line.wrapClass)
 
        return memo.measure;
 
    }
 
        return memo;
 
    }
 
  }
 

	
 
  function clearCachedMeasurement(cm, line) {
 
    var exists = findCachedMeasurement(cm, line);
 
    if (exists) exists.text = exists.measure = exists.markedSpans = null;
 
  }
 

	
 
  function measureLine(cm, line) {
 
    // First look in the cache
 
    var measure = findCachedMeasurement(cm, line);
 
    if (!measure) {
 
      // Failing that, recompute and store result in cache
 
      measure = measureLineInner(cm, line);
 
      var cache = cm.display.measureLineCache;
 
      var memo = {text: line.text, width: cm.display.scroller.clientWidth,
 
                  markedSpans: line.markedSpans, measure: measure,
 
                  classes: line.textClass + "|" + line.bgClass + "|" + line.wrapClass};
 
      if (cache.length == 16) cache[++cm.display.measureLineCachePos % 16] = memo;
 
      else cache.push(memo);
 
    }
 
    var cached = findCachedMeasurement(cm, line);
 
    if (cached) return cached.measure;
 

	
 
    // Failing that, recompute and store result in cache
 
    var measure = measureLineInner(cm, line);
 
    var cache = cm.display.measureLineCache;
 
    var memo = {text: line.text, width: cm.display.scroller.clientWidth,
 
                markedSpans: line.markedSpans, measure: measure,
 
                classes: line.textClass + "|" + line.bgClass + "|" + line.wrapClass};
 
    if (cache.length == 16) cache[++cm.display.measureLineCachePos % 16] = memo;
 
    else cache.push(memo);
 
    return measure;
 
  }
 

	
 
  function measureLineInner(cm, line) {
 
    var display = cm.display, measure = emptyArray(line.text.length);
 
    var pre = lineContent(cm, line, measure);
 

	
 
    // IE does not cache element positions of inline elements between
 
    // calls to getBoundingClientRect. This makes the loop below,
 
    // which gathers the positions of all the characters on the line,
 
    // do an amount of layout work quadratic to the number of
 
    // characters. When line wrapping is off, we try to improve things
 
@@ -1025,176 +1034,193 @@ window.CodeMirror = (function() {
 
      pre.appendChild(fragment);
 
    }
 

	
 
    removeChildrenAndAdd(display.measure, pre);
 

	
 
    var outer = getRect(display.lineDiv);
 
    var vranges = [], data = emptyArray(line.text.length), maxBot = pre.offsetHeight;
 
    // Work around an IE7/8 bug where it will sometimes have randomly
 
    // replaced our pre with a clone at this point.
 
    if (ie_lt9 && display.measure.first != pre)
 
      removeChildrenAndAdd(display.measure, pre);
 

	
 
    for (var i = 0, cur; i < measure.length; ++i) if (cur = measure[i]) {
 
      var size = getRect(cur);
 
      var top = Math.max(0, size.top - outer.top), bot = Math.min(size.bottom - outer.top, maxBot);
 
    function categorizeVSpan(top, bot) {
 
      if (bot > maxBot) bot = maxBot;
 
      if (top < 0) top = 0;
 
      for (var j = 0; j < vranges.length; j += 2) {
 
        var rtop = vranges[j], rbot = vranges[j+1];
 
        if (rtop > bot || rbot < top) continue;
 
        if (rtop <= top && rbot >= bot ||
 
            top <= rtop && bot >= rbot ||
 
            Math.min(bot, rbot) - Math.max(top, rtop) >= (bot - top) >> 1) {
 
          vranges[j] = Math.min(top, rtop);
 
          vranges[j+1] = Math.max(bot, rbot);
 
          break;
 
          return j;
 
        }
 
      }
 
      if (j == vranges.length) vranges.push(top, bot);
 
      vranges.push(top, bot);
 
      return j;
 
    }
 

	
 
    for (var i = 0, cur; i < measure.length; ++i) if (cur = measure[i]) {
 
      var size, node = cur;
 
      // A widget might wrap, needs special care
 
      if (/\bCodeMirror-widget\b/.test(cur.className) && cur.getClientRects) {
 
        if (cur.firstChild.nodeType == 1) node = cur.firstChild;
 
        var rects = node.getClientRects(), rLeft = rects[0], rRight = rects[rects.length - 1];
 
        if (rects.length > 1) {
 
          var vCatLeft = categorizeVSpan(rLeft.top - outer.top, rLeft.bottom - outer.top);
 
          var vCatRight = categorizeVSpan(rRight.top - outer.top, rRight.bottom - outer.top);
 
          data[i] = {left: rLeft.left - outer.left, right: rRight.right - outer.left,
 
                     top: vCatLeft, topRight: vCatRight};
 
          continue;
 
        }
 
      }
 
      size = getRect(node);
 
      var vCat = categorizeVSpan(size.top - outer.top, size.bottom - outer.top);
 
      var right = size.right;
 
      if (cur.measureRight) right = getRect(cur.measureRight).left;
 
      data[i] = {left: size.left - outer.left, right: right - outer.left, top: j};
 
      data[i] = {left: size.left - outer.left, right: right - outer.left, top: vCat};
 
    }
 
    for (var i = 0, cur; i < data.length; ++i) if (cur = data[i]) {
 
      var vr = cur.top;
 
      var vr = cur.top, vrRight = cur.topRight;
 
      cur.top = vranges[vr]; cur.bottom = vranges[vr+1];
 
    }
 

	
 
      if (vrRight != null) { cur.topRight = vranges[vrRight]; cur.bottomRight = vranges[vrRight+1]; }
 
    }
 
    return data;
 
  }
 

	
 
  function measureLineWidth(cm, line) {
 
    var hasBadSpan = false;
 
    if (line.markedSpans) for (var i = 0; i < line.markedSpans; ++i) {
 
      var sp = line.markedSpans[i];
 
      if (sp.collapsed && (sp.to == null || sp.to == line.text.length)) hasBadSpan = true;
 
    }
 
    var cached = !hasBadSpan && findCachedMeasurement(cm, line);
 
    if (cached) return measureChar(cm, line, line.text.length, cached).right;
 
    if (cached) return measureChar(cm, line, line.text.length, cached.measure, "right").right;
 

	
 
    var pre = lineContent(cm, line);
 
    var end = pre.appendChild(zeroWidthElement(cm.display.measure));
 
    removeChildrenAndAdd(cm.display.measure, pre);
 
    return getRect(end).right - getRect(cm.display.lineDiv).left;
 
  }
 

	
 
  function clearCaches(cm) {
 
    cm.display.measureLineCache.length = cm.display.measureLineCachePos = 0;
 
    cm.display.cachedCharWidth = cm.display.cachedTextHeight = null;
 
    if (!cm.options.lineWrapping) cm.display.maxLineChanged = true;
 
    cm.display.lineNumChars = null;
 
  }
 

	
 
  function pageScrollX() { return window.pageXOffset || (document.documentElement || document.body).scrollLeft; }
 
  function pageScrollY() { return window.pageYOffset || (document.documentElement || document.body).scrollTop; }
 

	
 
  // 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 = widgetHeight(lineObj.widgets[i]);
 
      rect.top += size; rect.bottom += size;
 
    }
 
    if (context == "line") return rect;
 
    if (!context) context = "local";
 
    var yOff = heightAtLine(cm, lineObj);
 
    if (context != "local") yOff -= cm.display.viewOffset;
 
    if (context == "page") {
 
    if (context == "local") yOff += paddingTop(cm.display);
 
    else yOff -= cm.display.viewOffset;
 
    if (context == "page" || context == "window") {
 
      var lOff = getRect(cm.display.lineSpace);
 
      yOff += lOff.top + (window.pageYOffset || (document.documentElement || document.body).scrollTop);
 
      var xOff = lOff.left + (window.pageXOffset || (document.documentElement || document.body).scrollLeft);
 
      yOff += lOff.top + (context == "window" ? 0 : pageScrollY());
 
      var xOff = lOff.left + (context == "window" ? 0 : pageScrollX());
 
      rect.left += xOff; rect.right += xOff;
 
    }
 
    rect.top += yOff; rect.bottom += yOff;
 
    return rect;
 
  }
 

	
 
  // Context may be "window", "page", "div", or "local"/null
 
  // Result is in "div" coords
 
  function fromCoordSystem(cm, coords, context) {
 
    if (context == "div") return coords;
 
    var left = coords.left, top = coords.top;
 
    // First move into "page" coordinate system
 
    if (context == "page") {
 
      left -= window.pageXOffset || (document.documentElement || document.body).scrollLeft;
 
      top -= window.pageYOffset || (document.documentElement || document.body).scrollTop;
 
    }
 
      left -= pageScrollX();
 
      top -= pageScrollY();
 
    } else if (context == "local" || !context) {
 
      var localBox = getRect(cm.display.sizer);
 
      left += localBox.left;
 
      top += localBox.top;
 
    }
 

	
 
    var lineSpaceBox = getRect(cm.display.lineSpace);
 
    left -= lineSpaceBox.left;
 
    top -= lineSpaceBox.top;
 
    if (context == "local" || !context) {
 
      var editorBox = getRect(cm.display.wrapper);
 
      left += editorBox.left;
 
      top += editorBox.top;
 
    }
 
    return {left: left, top: top};
 
  }
 

	
 
  function charCoords(cm, pos, context, lineObj) {
 
    return {left: left - lineSpaceBox.left, top: top - lineSpaceBox.top};
 
  }
 

	
 
  function charCoords(cm, pos, context, lineObj, bias) {
 
    if (!lineObj) lineObj = getLine(cm.doc, pos.line);
 
    return intoCoordSystem(cm, lineObj, measureChar(cm, lineObj, pos.ch), context);
 
    return intoCoordSystem(cm, lineObj, measureChar(cm, lineObj, pos.ch, null, bias), context);
 
  }
 

	
 
  function cursorCoords(cm, pos, context, lineObj, measurement) {
 
    lineObj = lineObj || getLine(cm.doc, pos.line);
 
    if (!measurement) measurement = measureLine(cm, lineObj);
 
    function get(ch, right) {
 
      var m = measureChar(cm, lineObj, ch, measurement);
 
      var m = measureChar(cm, lineObj, ch, measurement, right ? "right" : "left");
 
      if (right) m.left = m.right; else m.right = m.left;
 
      return intoCoordSystem(cm, lineObj, m, context);
 
    }
 
    function getBidi(ch, partPos) {
 
      var part = order[partPos], right = part.level % 2;
 
      if (ch == bidiLeft(part) && partPos && part.level < order[partPos - 1].level) {
 
        part = order[--partPos];
 
        ch = bidiRight(part) - (part.level % 2 ? 0 : 1);
 
        right = true;
 
      } else if (ch == bidiRight(part) && partPos < order.length - 1 && part.level < order[partPos + 1].level) {
 
        part = order[++partPos];
 
        ch = bidiLeft(part) - part.level % 2;
 
        right = false;
 
      }
 
      if (right && ch == part.to && ch > part.from) return get(ch - 1);
 
      return get(ch, right);
 
    }
 
    var order = getOrder(lineObj), ch = pos.ch;
 
    if (!order) return get(ch);
 
    var main, other, linedir = order[0].level;
 
    for (var i = 0; i < order.length; ++i) {
 
      var part = order[i], rtl = part.level % 2, nb, here;
 
      if (part.from < ch && part.to > ch) return get(ch, rtl);
 
      var left = rtl ? part.to : part.from, right = rtl ? part.from : part.to;
 
      if (left == ch) {
 
        // IE returns bogus offsets and widths for edges where the
 
        // direction flips, but only for the side with the lower
 
        // level. So we try to use the side with the higher level.
 
        if (i && part.level < (nb = order[i-1]).level) here = get(nb.level % 2 ? nb.from : nb.to - 1, true);
 
        else here = get(rtl && part.from != part.to ? ch - 1 : ch);
 
        if (rtl == linedir) main = here; else other = here;
 
      } else if (right == ch) {
 
        var nb = i < order.length - 1 && order[i+1];
 
        if (!rtl && nb && nb.from == nb.to) continue;
 
        if (nb && part.level < nb.level) here = get(nb.level % 2 ? nb.to - 1 : nb.from);
 
        else here = get(rtl ? ch : ch - 1, true);
 
        if (rtl == linedir) main = here; else other = here;
 
      }
 
    }
 
    if (linedir && !ch) other = get(order[0].to - 1);
 
    if (!main) return other;
 
    if (other) main.other = other;
 
    return main;
 
  }
 

	
 
  function PosMaybeOutside(line, ch, outside) {
 
    var partPos = getBidiPartAt(order, ch);
 
    var val = getBidi(ch, partPos);
 
    if (bidiOther != null) val.other = getBidi(ch, bidiOther);
 
    return val;
 
  }
 

	
 
  function PosWithInfo(line, ch, outside, xRel) {
 
    var pos = new Pos(line, ch);
 
    pos.xRel = xRel;
 
    if (outside) pos.outside = true;
 
    return pos;
 
  }
 

	
 
  // Coords must be lineSpace-local
 
  function coordsChar(cm, x, y) {
 
    var doc = cm.doc;
 
    y += cm.display.viewOffset;
 
    if (y < 0) return PosMaybeOutside(doc.first, 0, true);
 
    if (y < 0) return PosWithInfo(doc.first, 0, true, -1);
 
    var lineNo = lineAtHeight(doc, y), last = doc.first + doc.size - 1;
 
    if (lineNo > last)
 
      return PosMaybeOutside(doc.first + doc.size - 1, getLine(doc, last).text.length, true);
 
      return PosWithInfo(doc.first + doc.size - 1, getLine(doc, last).text.length, true, 1);
 
    if (x < 0) x = 0;
 

	
 
    for (;;) {
 
      var lineObj = getLine(doc, lineNo);
 
      var found = coordsCharInner(cm, lineObj, lineNo, x, y);
 
      var merged = collapsedSpanAtEnd(lineObj);
 
      var mergedPos = merged && merged.find();
 
      if (merged && found.ch >= mergedPos.from.ch)
 
      if (merged && (found.ch > mergedPos.from.ch || found.ch == mergedPos.from.ch && found.xRel > 0))
 
        lineNo = mergedPos.to.line;
 
      else
 
        return found;
 
    }
 
  }
 

	
 
  function coordsCharInner(cm, lineObj, lineNo, x, y) {
 
    var innerOff = y - heightAtLine(cm, lineObj);
 
    var wrongLine = false, adjust = 2 * cm.display.wrapper.clientWidth;
 
    var measurement = measureLine(cm, lineObj);
 

	
 
    function getX(ch) {
 
@@ -1202,32 +1228,33 @@ window.CodeMirror = (function() {
 
                            lineObj, measurement);
 
      wrongLine = true;
 
      if (innerOff > sp.bottom) return sp.left - adjust;
 
      else if (innerOff < sp.top) return sp.left + adjust;
 
      else wrongLine = false;
 
      return sp.left;
 
    }
 

	
 
    var bidi = getOrder(lineObj), dist = lineObj.text.length;
 
    var from = lineLeft(lineObj), to = lineRight(lineObj);
 
    var fromX = getX(from), fromOutside = wrongLine, toX = getX(to), toOutside = wrongLine;
 

	
 
    if (x > toX) return PosMaybeOutside(lineNo, to, toOutside);
 
    if (x > toX) return PosWithInfo(lineNo, to, toOutside, 1);
 
    // Do a binary search between these bounds.
 
    for (;;) {
 
      if (bidi ? to == from || to == moveVisually(lineObj, from, 1) : to - from <= 1) {
 
        var after = x - fromX < toX - x, ch = after ? from : to;
 
        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;
 
        var pos = PosMaybeOutside(lineNo, ch, after ? fromOutside : toOutside);
 
        pos.after = after;
 
        var pos = PosWithInfo(lineNo, ch, ch == from ? fromOutside : toOutside,
 
                              xDiff < 0 ? -1 : xDiff ? 1 : 0);
 
        return pos;
 
      }
 
      var step = Math.ceil(dist / 2), middle = from + step;
 
      if (bidi) {
 
        middle = from;
 
        for (var i = 0; i < step; ++i) middle = moveVisually(lineObj, middle, 1);
 
      }
 
      var middleX = getX(middle);
 
      if (middleX > x) {to = middle; toX = middleX; if (toOutside = wrongLine) toX += 1000; dist = step;}
 
      else {from = middle; fromX = middleX; fromOutside = wrongLine; dist -= step;}
 
    }
 
  }
 
@@ -1395,47 +1422,50 @@ window.CodeMirror = (function() {
 
      else {cm.display.pollingFast = false; slowPoll(cm);}
 
    }
 
    cm.display.poll.set(20, p);
 
  }
 

	
 
  // prevInput is a hack to work with IME. If we reset the textarea
 
  // on every change, that breaks IME. So we look for changes
 
  // compared to the previous content instead. (Modern browsers have
 
  // events that indicate IME taking place, but these are not widely
 
  // 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)) return false;
 
    if (!cm.state.focused || hasSelection(input) || isReadOnly(cm) || cm.state.disableInput) return false;
 
    var text = input.value;
 
    if (text == prevInput && posEq(sel.from, sel.to)) return false;
 
    if (ie && !ie_lt9 && cm.display.inputHasSelection === text) {
 
      resetInput(cm, true);
 
      return false;
 
    }
 

	
 
    var withOp = !cm.curOp;
 
    if (withOp) startOperation(cm);
 
    sel.shift = false;
 
    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;
 
    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)));
 

	
 
    var updateInput = cm.curOp.updateInput;
 
    makeChange(cm.doc, {from: from, to: to, text: splitLines(text.slice(same)),
 
                        origin: cm.state.pasteIncoming ? "paste" : "+input"}, "end");
 

	
 
    var changeEvent = {from: from, to: to, text: splitLines(text.slice(same)),
 
                       origin: cm.state.pasteIncoming ? "paste" : "+input"};
 
    makeChange(cm.doc, changeEvent, "end");
 
    cm.curOp.updateInput = updateInput;
 
    signalLater(cm, "inputRead", cm, changeEvent);
 

	
 
    if (text.length > 1000 || text.indexOf("\n") > -1) input.value = cm.display.prevInput = "";
 
    else cm.display.prevInput = text;
 
    if (withOp) endOperation(cm);
 
    cm.state.pasteIncoming = false;
 
    return true;
 
  }
 

	
 
  function resetInput(cm, user) {
 
    var minimal, selected, doc = cm.doc;
 
    if (!posEq(doc.sel.from, doc.sel.to)) {
 
      cm.display.prevInput = "";
 
      minimal = hasCopyEvent &&
 
@@ -1458,32 +1488,33 @@ window.CodeMirror = (function() {
 

	
 
  function isReadOnly(cm) {
 
    return cm.options.readOnly || cm.doc.cantEdit;
 
  }
 

	
 
  // EVENT HANDLERS
 

	
 
  function registerEventHandlers(cm) {
 
    var d = cm.display;
 
    on(d.scroller, "mousedown", operation(cm, onMouseDown));
 
    if (ie)
 
      on(d.scroller, "dblclick", operation(cm, function(e) {
 
        if (signalDOMEvent(cm, e)) return;
 
        var pos = posFromMouse(cm, e);
 
        if (!pos || clickInGutter(cm, e) || eventInWidget(cm.display, e)) return;
 
        e_preventDefault(e);
 
        var word = findWordAt(getLine(cm.doc, pos.line).text, pos);
 
        extendSelection(cm.doc, word.from, word.to);
 
      }));
 
    else
 
      on(d.scroller, "dblclick", e_preventDefault);
 
      on(d.scroller, "dblclick", function(e) { signalDOMEvent(cm, e) || e_preventDefault(e); });
 
    on(d.lineSpace, "selectstart", function(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
 
    // handled in onMouseDown for Gecko.
 
    if (!captureMiddleClick) on(d.scroller, "contextmenu", function(e) {onContextMenu(cm, e);});
 

	
 
    on(d.scroller, "scroll", function() {
 
      if (d.scroller.clientHeight) {
 
        setScrollTop(cm, d.scroller.scrollTop);
 
        setScrollLeft(cm, d.scroller.scrollLeft, true);
 
@@ -1497,53 +1528,57 @@ window.CodeMirror = (function() {
 
      if (d.scroller.clientHeight) setScrollLeft(cm, d.scrollbarH.scrollLeft);
 
    });
 

	
 
    on(d.scroller, "mousewheel", function(e){onScrollWheel(cm, e);});
 
    on(d.scroller, "DOMMouseScroll", function(e){onScrollWheel(cm, e);});
 

	
 
    function reFocus() { if (cm.state.focused) setTimeout(bind(focusInput, cm), 0); }
 
    on(d.scrollbarH, "mousedown", reFocus);
 
    on(d.scrollbarV, "mousedown", reFocus);
 
    // Prevent wrapper from ever scrolling
 
    on(d.wrapper, "scroll", function() { d.wrapper.scrollTop = d.wrapper.scrollLeft = 0; });
 

	
 
    var resizeTimer;
 
    function onResize() {
 
      // Might be a text scaling operation, clear size caches.
 
      d.cachedCharWidth = d.cachedTextHeight = null;
 
      clearCaches(cm);
 
      runInOp(cm, bind(regChange, cm));
 
      if (resizeTimer == null) resizeTimer = setTimeout(function() {
 
        resizeTimer = null;
 
        // Might be a text scaling operation, clear size caches.
 
        d.cachedCharWidth = d.cachedTextHeight = knownScrollbarWidth = null;
 
        clearCaches(cm);
 
        runInOp(cm, bind(regChange, cm));
 
      }, 100);
 
    }
 
    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.
 
    function unregister() {
 
      for (var p = d.wrapper.parentNode; p && p != document.body; p = p.parentNode) {}
 
      if (p) setTimeout(unregister, 5000);
 
      else off(window, "resize", onResize);
 
    }
 
    setTimeout(unregister, 5000);
 

	
 
    on(d.input, "keyup", operation(cm, function(e) {
 
      if (cm.options.onKeyEvent && cm.options.onKeyEvent(cm, addStop(e))) return;
 
      if (signalDOMEvent(cm, e) || cm.options.onKeyEvent && cm.options.onKeyEvent(cm, addStop(e))) return;
 
      if (e.keyCode == 16) cm.doc.sel.shift = false;
 
    }));
 
    on(d.input, "input", bind(fastPoll, cm));
 
    on(d.input, "keydown", operation(cm, onKeyDown));
 
    on(d.input, "keypress", operation(cm, onKeyPress));
 
    on(d.input, "focus", bind(onFocus, cm));
 
    on(d.input, "blur", bind(onBlur, cm));
 

	
 
    function drag_(e) {
 
      if (cm.options.onDragEvent && cm.options.onDragEvent(cm, addStop(e))) return;
 
      if (signalDOMEvent(cm, e) || cm.options.onDragEvent && cm.options.onDragEvent(cm, addStop(e))) return;
 
      e_stop(e);
 
    }
 
    if (cm.options.dragDrop) {
 
      on(d.scroller, "dragstart", function(e){onDragStart(cm, e);});
 
      on(d.scroller, "dragenter", drag_);
 
      on(d.scroller, "dragover", drag_);
 
      on(d.scroller, "drop", operation(cm, onDrop));
 
    }
 
    on(d.scroller, "paste", function(e){
 
      if (eventInWidget(d, e)) return;
 
      focusInput(cm);
 
      fastPoll(cm);
 
@@ -1564,46 +1599,45 @@ window.CodeMirror = (function() {
 
    on(d.input, "cut", prepareCopy);
 
    on(d.input, "copy", prepareCopy);
 

	
 
    // Needed to handle Tab key in KHTML
 
    if (khtml) on(d.sizer, "mouseup", function() {
 
        if (document.activeElement == d.input) d.input.blur();
 
        focusInput(cm);
 
    });
 
  }
 

	
 
  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;
 
      if (!n || n.ignoreEvents || n.parentNode == display.sizer && n != display.mover) return true;
 
    }
 
  }
 

	
 
  function posFromMouse(cm, e, liberal) {
 
    var display = cm.display;
 
    if (!liberal) {
 
      var target = e_target(e);
 
      if (target == display.scrollbarH || target == display.scrollbarH.firstChild ||
 
          target == display.scrollbarV || target == display.scrollbarV.firstChild ||
 
          target == display.scrollbarFiller) return null;
 
          target == display.scrollbarFiller || target == display.gutterFiller) return null;
 
    }
 
    var x, y, space = getRect(display.lineSpace);
 
    // Fails unpredictably on IE[67] when mouse is dragged around quickly.
 
    try { x = e.clientX; y = e.clientY; } catch (e) { return null; }
 
    return coordsChar(cm, x - space.left, y - space.top);
 
  }
 

	
 
  var lastClick, lastDoubleClick;
 
  function onMouseDown(e) {
 
    if (signalDOMEvent(this, e)) return;
 
    var cm = this, display = cm.display, doc = cm.doc, sel = doc.sel;
 
    sel.shift = e.shiftKey;
 

	
 
    if (eventInWidget(display, e)) {
 
      if (!webkit) {
 
        display.scroller.draggable = false;
 
        setTimeout(function(){display.scroller.draggable = true;}, 100);
 
      }
 
      return;
 
    }
 
    if (clickInGutter(cm, e)) return;
 
    var start = posFromMouse(cm, e);
 
@@ -1709,46 +1743,74 @@ window.CodeMirror = (function() {
 
      } else {
 
        var outside = e.clientY < editorSize.top ? -20 : e.clientY > editorSize.bottom ? 20 : 0;
 
        if (outside) setTimeout(operation(cm, function() {
 
          if (counter != curCount) return;
 
          display.scroller.scrollTop += outside;
 
          extend(e);
 
        }), 50);
 
      }
 
    }
 

	
 
    function done(e) {
 
      counter = Infinity;
 
      var cur = posFromMouse(cm, e);
 
      if (cur) doSelect(cur);
 
      e_preventDefault(e);
 
      focusInput(cm);
 
      off(document, "mousemove", move);
 
      off(document, "mouseup", up);
 
    }
 

	
 
    var move = operation(cm, function(e) {
 
      if (!ie && !e_button(e)) done(e);
 
      else extend(e);
 
    });
 
    var up = operation(cm, done);
 
    on(document, "mousemove", move);
 
    on(document, "mouseup", up);
 
  }
 

	
 
  function clickInGutter(cm, e) {
 
    var display = cm.display;
 
    try { var mX = e.clientX, mY = e.clientY; }
 
    catch(e) { return false; }
 

	
 
    if (mX >= Math.floor(getRect(display.gutters).right)) return false;
 
    e_preventDefault(e);
 
    if (!hasHandler(cm, "gutterClick")) return true;
 

	
 
    var lineBox = getRect(display.lineDiv);
 
    if (mY > lineBox.bottom) return true;
 
    mY -= lineBox.top - display.viewOffset;
 

	
 
    for (var i = 0; i < cm.options.gutters.length; ++i) {
 
      var g = display.gutters.childNodes[i];
 
      if (g && getRect(g).right >= mX) {
 
        var line = lineAtHeight(cm.doc, mY);
 
        var gutter = cm.options.gutters[i];
 
        signalLater(cm, "gutterClick", cm, line, gutter, e);
 
        break;
 
      }
 
    }
 
    return true;
 
  }
 

	
 
  // Kludge to work around strange IE behavior where it'll sometimes
 
  // re-fire a series of drag-related events right after the drop (#1551)
 
  var lastDrop = 0;
 

	
 
  function onDrop(e) {
 
    var cm = this;
 
    if (eventInWidget(cm.display, e) || (cm.options.onDragEvent && cm.options.onDragEvent(cm, addStop(e))))
 
    if (signalDOMEvent(cm, e) || eventInWidget(cm.display, e) || (cm.options.onDragEvent && cm.options.onDragEvent(cm, addStop(e))))
 
      return;
 
    e_preventDefault(e);
 
    if (ie) lastDrop = +new Date;
 
    var pos = posFromMouse(cm, e, true), files = e.dataTransfer.files;
 
    if (!pos || isReadOnly(cm)) return;
 
    if (files && files.length && window.FileReader && window.File) {
 
      var n = files.length, text = Array(n), read = 0;
 
      var loadFile = function(file, i) {
 
        var reader = new FileReader;
 
        reader.onload = function() {
 
          text[i] = reader.result;
 
          if (++read == n) {
 
            pos = clipPos(cm.doc, pos);
 
            makeChange(cm.doc, {from: pos, to: pos, text: splitLines(text.join("\n")), origin: "paste"}, "around");
 
          }
 
@@ -1770,87 +1832,54 @@ window.CodeMirror = (function() {
 
          var curFrom = cm.doc.sel.from, curTo = cm.doc.sel.to;
 
          setSelection(cm.doc, pos, pos);
 
          if (cm.state.draggingText) replaceRange(cm.doc, "", curFrom, curTo, "paste");
 
          cm.replaceSelection(text, null, "paste");
 
          focusInput(cm);
 
          onFocus(cm);
 
        }
 
      }
 
      catch(e){}
 
    }
 
  }
 

	
 
  function clickInGutter(cm, e) {
 
    var display = cm.display;
 
    try { var mX = e.clientX, mY = e.clientY; }
 
    catch(e) { return false; }
 

	
 
    if (mX >= Math.floor(getRect(display.gutters).right)) return false;
 
    e_preventDefault(e);
 
    if (!hasHandler(cm, "gutterClick")) return true;
 

	
 
    var lineBox = getRect(display.lineDiv);
 
    if (mY > lineBox.bottom) return true;
 
    mY -= lineBox.top - display.viewOffset;
 

	
 
    for (var i = 0; i < cm.options.gutters.length; ++i) {
 
      var g = display.gutters.childNodes[i];
 
      if (g && getRect(g).right >= mX) {
 
        var line = lineAtHeight(cm.doc, mY);
 
        var gutter = cm.options.gutters[i];
 
        signalLater(cm, "gutterClick", cm, line, gutter, e);
 
        break;
 
      }
 
    }
 
    return true;
 
  }
 

	
 
  function onDragStart(cm, e) {
 
    if (ie && !cm.state.draggingText) { e_stop(e); return; }
 
    if (eventInWidget(cm.display, e)) return;
 
    if (ie && (!cm.state.draggingText || +new Date - lastDrop < 100)) { e_stop(e); return; }
 
    if (signalDOMEvent(cm, e) || 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) {
 
    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;
 
      }
 
      if (safari) {
 
        if (cm.display.dragImg) {
 
          img = cm.display.dragImg;
 
        } else {
 
          cm.display.dragImg = img;
 
          img.src = "data:image/gif;base64,R0lGODlhAQABAAAAACH5BAEKAAEALAAAAAABAAEAAAICTAEAOw==";
 
          cm.display.wrapper.appendChild(img);
 
        }
 
      }
 
      e.dataTransfer.setDragImage(img, 0, 0);
 
      if (opera) img.parentNode.removeChild(img);
 
    }
 
  }
 

	
 
  function setScrollTop(cm, val) {
 
    if (Math.abs(cm.doc.scrollTop - val) < 2) return;
 
    cm.doc.scrollTop = val;
 
    if (!gecko) updateDisplay(cm, [], val);
 
    if (cm.display.scroller.scrollTop != val) cm.display.scroller.scrollTop = val;
 
    if (cm.display.scrollbarV.scrollTop != val) cm.display.scrollbarV.scrollTop = val;
 
    if (gecko) updateDisplay(cm, []);
 
    startWorker(cm, 100);
 
  }
 
  function setScrollLeft(cm, val, isScroller) {
 
    if (isScroller ? val == cm.doc.scrollLeft : Math.abs(cm.doc.scrollLeft - val) < 2) return;
 
    val = Math.min(val, cm.display.scroller.scrollWidth - cm.display.scroller.clientWidth);
 
    cm.doc.scrollLeft = val;
 
    alignHorizontally(cm);
 
    if (cm.display.scroller.scrollLeft != val) cm.display.scroller.scrollLeft = val;
 
    if (cm.display.scrollbarH.scrollLeft != val) cm.display.scrollbarH.scrollLeft = val;
 
  }
 

	
 
  // Since the delta values reported on mouse wheel events are
 
  // unstandardized between browsers and even browser versions, and
 
@@ -1965,85 +1994,89 @@ window.CodeMirror = (function() {
 
    var maps = cm.state.keyMaps.slice(0);
 
    if (cm.options.extraKeys) maps.push(cm.options.extraKeys);
 
    maps.push(cm.options.keyMap);
 
    return maps;
 
  }
 

	
 
  var maybeTransition;
 
  function handleKeyBinding(cm, e) {
 
    // Handle auto keymap transitions
 
    var startMap = getKeyMap(cm.options.keyMap), next = startMap.auto;
 
    clearTimeout(maybeTransition);
 
    if (next && !isModifierKey(e)) maybeTransition = setTimeout(function() {
 
      if (getKeyMap(cm.options.keyMap) == startMap)
 
      if (getKeyMap(cm.options.keyMap) == startMap) {
 
        cm.options.keyMap = (next.call ? next.call(null, cm) : next);
 
        keyMapChanged(cm);
 
      }
 
    }, 50);
 

	
 
    var name = keyName(e, true), handled = false;
 
    if (!name) return false;
 
    var keymaps = allKeyMaps(cm);
 

	
 
    if (e.shiftKey) {
 
      // First try to resolve full name (including 'Shift-'). Failing
 
      // that, see if there is a cursor-motion command (starting with
 
      // 'go') bound to the keyname without 'Shift-'.
 
      handled = lookupKey("Shift-" + name, keymaps, function(b) {return doHandleBinding(cm, b, true);})
 
             || lookupKey(name, keymaps, function(b) {
 
                  if (typeof b == "string" && /^go[A-Z]/.test(b)) return doHandleBinding(cm, b);
 
                  if (typeof b == "string" ? /^go[A-Z]/.test(b) : b.motion)
 
                    return doHandleBinding(cm, b);
 
                });
 
    } else {
 
      handled = lookupKey(name, keymaps, function(b) { return doHandleBinding(cm, b); });
 
    }
 
    if (handled == "stop") handled = false;
 

	
 
    if (handled) {
 
      e_preventDefault(e);
 
      restartBlink(cm);
 
      if (ie_lt9) { e.oldKeyCode = e.keyCode; e.keyCode = 0; }
 
      signalLater(cm, "keyHandled", cm, name, e);
 
    }
 
    return handled;
 
  }
 

	
 
  function handleCharBinding(cm, e, ch) {
 
    var handled = lookupKey("'" + ch + "'", allKeyMaps(cm),
 
                            function(b) { return doHandleBinding(cm, b, true); });
 
    if (handled) {
 
      e_preventDefault(e);
 
      restartBlink(cm);
 
      signalLater(cm, "keyHandled", cm, "'" + ch + "'", e);
 
    }
 
    return handled;
 
  }
 

	
 
  var lastStoppedKey = null;
 
  function onKeyDown(e) {
 
    var cm = this;
 
    if (!cm.state.focused) onFocus(cm);
 
    if (ie && e.keyCode == 27) { e.returnValue = false; }
 
    if (cm.options.onKeyEvent && cm.options.onKeyEvent(cm, addStop(e))) return;
 
    if (signalDOMEvent(cm, e) || cm.options.onKeyEvent && cm.options.onKeyEvent(cm, addStop(e))) return;
 
    var code = e.keyCode;
 
    // IE does strange things with escape.
 
    cm.doc.sel.shift = code == 16 || e.shiftKey;
 
    // First give onKeyEvent option a chance to handle this.
 
    var handled = handleKeyBinding(cm, e);
 
    if (opera) {
 
      lastStoppedKey = handled ? code : null;
 
      // Opera has no cut event... we try to at least catch the key combo
 
      if (!handled && code == 88 && !hasCopyEvent && (mac ? e.metaKey : e.ctrlKey))
 
        cm.replaceSelection("");
 
    }
 
  }
 

	
 
  function onKeyPress(e) {
 
    var cm = this;
 
    if (cm.options.onKeyEvent && cm.options.onKeyEvent(cm, addStop(e))) return;
 
    if (signalDOMEvent(cm, e) || cm.options.onKeyEvent && cm.options.onKeyEvent(cm, addStop(e))) return;
 
    var keyCode = e.keyCode, charCode = e.charCode;
 
    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);
 
  }
 
@@ -2081,65 +2114,71 @@ window.CodeMirror = (function() {
 
      operation(cm, setSelection)(cm.doc, pos, pos);
 

	
 
    var oldCSS = display.input.style.cssText;
 
    display.inputDiv.style.position = "absolute";
 
    display.input.style.cssText = "position: fixed; width: 30px; height: 30px; top: " + (e.clientY - 5) +
 
      "px; left: " + (e.clientX - 5) + "px; z-index: 1000; background: white; outline: none;" +
 
      "border-width: 0; outline: none; overflow: hidden; opacity: .05; -ms-opacity: .05; filter: alpha(opacity=5);";
 
    focusInput(cm);
 
    resetInput(cm, true);
 
    // Adds "Select all" to context menu in FF
 
    if (posEq(sel.from, sel.to)) display.input.value = display.prevInput = " ";
 

	
 
    function prepareSelectAllHack() {
 
      if (display.input.selectionStart != null) {
 
        var extval = display.input.value = " " + (posEq(sel.from, sel.to) ? "" : display.input.value);
 
        display.prevInput = " ";
 
        display.input.selectionStart = 1; display.input.selectionEnd = extval.length;
 
      }
 
    }
 
    function rehide() {
 
      display.inputDiv.style.position = "relative";
 
      display.input.style.cssText = oldCSS;
 
      if (ie_lt9) display.scrollbarV.scrollTop = display.scroller.scrollTop = scrollPos;
 
      slowPoll(cm);
 

	
 
      // Try to detect the user choosing select-all
 
      if (display.input.selectionStart != null && (!ie || ie_lt9)) {
 
      if (display.input.selectionStart != null) {
 
        if (!ie || ie_lt9) prepareSelectAllHack();
 
        clearTimeout(detectingSelectAll);
 
        var extval = display.input.value = " " + (posEq(sel.from, sel.to) ? "" : display.input.value), i = 0;
 
        display.prevInput = " ";
 
        display.input.selectionStart = 1; display.input.selectionEnd = extval.length;
 
        var poll = function(){
 
        var i = 0, poll = function(){
 
          if (display.prevInput == " " && display.input.selectionStart == 0)
 
            operation(cm, commands.selectAll)(cm);
 
          else if (i++ < 10) detectingSelectAll = setTimeout(poll, 500);
 
          else resetInput(cm);
 
        };
 
        detectingSelectAll = setTimeout(poll, 200);
 
      }
 
    }
 

	
 
    if (ie && !ie_lt9) prepareSelectAllHack();
 
    if (captureMiddleClick) {
 
      e_stop(e);
 
      var mouseup = function() {
 
        off(window, "mouseup", mouseup);
 
        setTimeout(rehide, 20);
 
      };
 
      on(window, "mouseup", mouseup);
 
    } else {
 
      setTimeout(rehide, 50);
 
    }
 
  }
 

	
 
  // UPDATING
 

	
 
  function changeEnd(change) {
 
  var changeEnd = CodeMirror.changeEnd = function(change) {
 
    if (!change.text) return change.to;
 
    return Pos(change.from.line + change.text.length - 1,
 
               lst(change.text).length + (change.text.length == 1 ? change.from.ch : 0));
 
  }
 
  };
 

	
 
  // Make sure a position will be valid after the given change.
 
  function clipPostChange(doc, change, pos) {
 
    if (!posLess(change.from, pos)) return clipPos(doc, pos);
 
    var diff = (change.text.length - 1) - (change.to.line - change.from.line);
 
    if (pos.line > change.to.line + diff) {
 
      var preLine = pos.line - diff, lastLine = doc.first + doc.size - 1;
 
      if (preLine > lastLine) return Pos(lastLine, getLine(doc, lastLine).text.length);
 
      return clipToLen(pos, getLine(doc, preLine).text.length);
 
    }
 
    if (pos.line == change.to.line + diff)
 
      return clipToLen(pos, lst(change.text).length + (change.text.length == 1 ? change.from.ch : 0) +
 
@@ -2163,56 +2202,56 @@ window.CodeMirror = (function() {
 
    // hint is null, leave the selection alone as much as possible
 
    var adjustPos = function(pos) {
 
      if (posLess(pos, change.from)) return pos;
 
      if (!posLess(change.to, pos)) return end;
 

	
 
      var line = pos.line + change.text.length - (change.to.line - change.from.line) - 1, ch = pos.ch;
 
      if (pos.line == change.to.line) ch += end.ch - change.to.ch;
 
      return Pos(line, ch);
 
    };
 
    return {anchor: adjustPos(doc.sel.anchor), head: adjustPos(doc.sel.head)};
 
  }
 

	
 
  function filterChange(doc, change) {
 
  function filterChange(doc, change, update) {
 
    var obj = {
 
      canceled: false,
 
      from: change.from,
 
      to: change.to,
 
      text: change.text,
 
      origin: change.origin,
 
      update: function(from, to, text, origin) {
 
        if (from) this.from = clipPos(doc, from);
 
        if (to) this.to = clipPos(doc, to);
 
        if (text) this.text = text;
 
        if (origin !== undefined) this.origin = origin;
 
      },
 
      cancel: function() { this.canceled = true; }
 
    };
 
    if (update) obj.update = function(from, to, text, origin) {
 
      if (from) this.from = clipPos(doc, from);
 
      if (to) this.to = clipPos(doc, to);
 
      if (text) this.text = text;
 
      if (origin !== undefined) this.origin = origin;
 
    };
 
    signal(doc, "beforeChange", doc, obj);
 
    if (doc.cm) signal(doc.cm, "beforeChange", doc.cm, obj);
 

	
 
    if (obj.canceled) return null;
 
    return {from: obj.from, to: obj.to, text: obj.text, origin: obj.origin};
 
  }
 

	
 
  // Replace the range from from to to by the strings in replacement.
 
  // change is a {from, to, text [, origin]} object
 
  function makeChange(doc, change, selUpdate, ignoreReadOnly) {
 
    if (doc.cm) {
 
      if (!doc.cm.curOp) return operation(doc.cm, makeChange)(doc, change, selUpdate, ignoreReadOnly);
 
      if (doc.cm.state.suppressEdits) return;
 
    }
 

	
 
    if (hasHandler(doc, "beforeChange") || doc.cm && hasHandler(doc.cm, "beforeChange")) {
 
      change = filterChange(doc, change);
 
      change = filterChange(doc, change, true);
 
      if (!change) return;
 
    }
 

	
 
    // Possibly split or suppress the update based on the presence
 
    // of read-only spans in its range.
 
    var split = sawReadOnlySpans && !ignoreReadOnly && removeReadOnlyRanges(doc, change.from, change.to);
 
    if (split) {
 
      for (var i = split.length - 1; i >= 1; --i)
 
        makeChangeNoReadonly(doc, {from: split[i].from, to: split[i].to, text: [""]});
 
      if (split.length)
 
        makeChangeNoReadonly(doc, {from: split[0].from, to: split[0].to, text: change.text}, selUpdate);
 
    } else {
 
@@ -2233,33 +2272,41 @@ window.CodeMirror = (function() {
 
        rebased.push(doc.history);
 
      }
 
      makeChangeSingleDoc(doc, change, null, stretchSpansOverChange(doc, change));
 
    });
 
  }
 

	
 
  function makeChangeFromHistory(doc, type) {
 
    if (doc.cm && doc.cm.state.suppressEdits) return;
 

	
 
    var hist = doc.history;
 
    var event = (type == "undo" ? hist.done : hist.undone).pop();
 
    if (!event) return;
 
    hist.dirtyCounter += type == "undo" ? -1 : 1;
 

	
 
    var anti = {changes: [], anchorBefore: event.anchorAfter, headBefore: event.headAfter,
 
                anchorAfter: event.anchorBefore, headAfter: event.headBefore};
 
                anchorAfter: event.anchorBefore, headAfter: event.headBefore,
 
                generation: hist.generation};
 
    (type == "undo" ? hist.undone : hist.done).push(anti);
 
    hist.generation = event.generation || ++hist.maxGeneration;
 

	
 
    var filter = hasHandler(doc, "beforeChange") || doc.cm && hasHandler(doc.cm, "beforeChange");
 

	
 
    for (var i = event.changes.length - 1; i >= 0; --i) {
 
      var change = event.changes[i];
 
      change.origin = type;
 
      if (filter && !filterChange(doc, change, false)) {
 
        (type == "undo" ? hist.done : hist.undone).length = 0;
 
        return;
 
      }
 

	
 
      anti.changes.push(historyChangeFromChange(doc, change));
 

	
 
      var after = i ? computeSelAfterChange(doc, change, null)
 
                    : {anchor: event.anchorBefore, head: event.headBefore};
 
      makeChangeSingleDoc(doc, change, after, mergeOldSpans(doc, change));
 
      var rebased = [];
 

	
 
      linkedDocs(doc, function(doc, sharedHist) {
 
        if (!sharedHist && indexOf(rebased, doc.history) == -1) {
 
          rebaseHist(doc.history, change);
 
          rebased.push(doc.history);
 
        }
 
@@ -2503,29 +2550,29 @@ window.CodeMirror = (function() {
 
            curPos = newPos;
 
            continue search;
 
          }
 
        }
 
      }
 
      return curPos;
 
    }
 
  }
 

	
 
  // SCROLLING
 

	
 
  function scrollCursorIntoView(cm) {
 
    var coords = scrollPosIntoView(cm, cm.doc.sel.head);
 
    var coords = scrollPosIntoView(cm, cm.doc.sel.head, cm.options.cursorScrollMargin);
 
    if (!cm.state.focused) return;
 
    var display = cm.display, box = getRect(display.sizer), doScroll = null, pTop = paddingTop(cm.display);
 
    if (coords.top + pTop + box.top < 0) doScroll = true;
 
    else if (coords.bottom + pTop + box.top > (window.innerHeight || document.documentElement.clientHeight)) doScroll = false;
 
    var display = cm.display, box = getRect(display.sizer), doScroll = null;
 
    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";
 
    }
 
  }
 

	
 
@@ -2545,30 +2592,29 @@ window.CodeMirror = (function() {
 
      }
 
      if (!changed) return coords;
 
    }
 
  }
 

	
 
  function scrollIntoView(cm, x1, y1, x2, y2) {
 
    var scrollPos = calculateScrollPos(cm, x1, y1, x2, y2);
 
    if (scrollPos.scrollTop != null) setScrollTop(cm, scrollPos.scrollTop);
 
    if (scrollPos.scrollLeft != null) setScrollLeft(cm, scrollPos.scrollLeft);
 
  }
 

	
 
  function calculateScrollPos(cm, x1, y1, x2, y2) {
 
    var display = cm.display, pt = paddingTop(display);
 
    y1 += pt; y2 += pt;
 
    var display = cm.display, snapMargin = textHeight(cm.display);
 
    if (y1 < 0) y1 = 0;
 
    var screen = display.scroller.clientHeight - scrollerCutOff, screentop = display.scroller.scrollTop, result = {};
 
    var docBottom = cm.doc.height + paddingVert(display);
 
    var atTop = y1 < pt + 10, atBottom = y2 + pt > docBottom - 10;
 
    var atTop = y1 < snapMargin, atBottom = y2 > docBottom - snapMargin;
 
    if (y1 < screentop) {
 
      result.scrollTop = atTop ? 0 : y1;
 
    } else if (y2 > screentop + screen) {
 
      var newTop = Math.min(y1, (atBottom ? docBottom : y2) - screen);
 
      if (newTop != screentop) result.scrollTop = newTop;
 
    }
 

	
 
    var screenw = display.scroller.clientWidth - scrollerCutOff, screenleft = display.scroller.scrollLeft;
 
    x1 += display.gutters.offsetWidth; x2 += display.gutters.offsetWidth;
 
    var gutterw = display.gutters.offsetWidth;
 
    var atLeft = x1 < gutterw + 10;
 
    if (x1 < screenleft + gutterw || atLeft) {
 
@@ -2587,72 +2633,74 @@ window.CodeMirror = (function() {
 

	
 
  function addToScrollPos(cm, left, top) {
 
    var pos = cm.curOp.updateScrollPos || (cm.curOp.updateScrollPos = {scrollLeft: cm.doc.scrollLeft, scrollTop: cm.doc.scrollTop});
 
    var scroll = cm.display.scroller;
 
    pos.scrollTop = Math.max(0, Math.min(scroll.scrollHeight - scroll.clientHeight, pos.scrollTop + top));
 
    pos.scrollLeft = Math.max(0, Math.min(scroll.scrollWidth - scroll.clientWidth, pos.scrollLeft + left));
 
  }
 

	
 
  // API UTILITIES
 

	
 
  function indentLine(cm, n, how, aggressive) {
 
    var doc = cm.doc;
 
    if (!how) how = "add";
 
    if (how == null) how = "add";
 
    if (how == "smart") {
 
      if (!cm.doc.mode.indent) how = "prev";
 
      else var state = getStateBefore(cm, n);
 
    }
 

	
 
    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") {
 
      indentation = cm.doc.mode.indent(state, line.text.slice(curSpaceString.length), line.text);
 
      if (indentation == Pass) {
 
        if (!aggressive) return;
 
        how = "prev";
 
      }
 
    }
 
    if (how == "prev") {
 
      if (n > doc.first) indentation = countColumn(getLine(doc, n-1).text, null, tabSize);
 
      else indentation = 0;
 
    } else if (how == "add") {
 
      indentation = curSpace + cm.options.indentUnit;
 
    } else if (how == "subtract") {
 
      indentation = curSpace - cm.options.indentUnit;
 
    } else if (typeof how == "number") {
 
      indentation = curSpace + how;
 
    }
 
    indentation = Math.max(0, indentation);
 

	
 
    var indentString = "", pos = 0;
 
    if (cm.options.indentWithTabs)
 
      for (var i = Math.floor(indentation / tabSize); i; --i) {pos += tabSize; indentString += "\t";}
 
    if (pos < indentation) indentString += spaceStr(indentation - pos);
 

	
 
    if (indentString != curSpaceString)
 
      replaceRange(cm.doc, indentString, Pos(n, 0), Pos(n, curSpaceString.length), "+input");
 
    line.stateAfter = null;
 
  }
 

	
 
  function changeLine(cm, handle, op) {
 
    var no = handle, line = handle, doc = cm.doc;
 
    if (typeof handle == "number") line = getLine(doc, clipLine(doc, handle));
 
    else no = lineNo(handle);
 
    if (no == null) return null;
 
    if (op(line, no)) regChange(cm, no, no + 1);
 
    else return null;
 
    return line;
 
  }
 

	
 
  function findPosH(doc, pos, dir, unit, visually) {
 
    var line = pos.line, ch = pos.ch;
 
    var line = pos.line, ch = pos.ch, origDir = dir;
 
    var lineObj = getLine(doc, line);
 
    var possible = true;
 
    function findNextLine() {
 
      var l = line + dir;
 
      if (l < doc.first || l >= doc.first + doc.size) return (possible = false);
 
      line = l;
 
      return lineObj = getLine(doc, l);
 
    }
 
    function moveOnce(boundToLine) {
 
      var next = (visually ? moveVisually : moveLogically)(lineObj, ch, dir, true);
 
      if (next == null) {
 
        if (!boundToLine && findNextLine()) {
 
@@ -2673,70 +2721,71 @@ window.CodeMirror = (function() {
 
        var type = isWordChar(cur) ? "w"
 
          : !group ? null
 
          : /\s/.test(cur) ? null
 
          : "p";
 
        if (sawType && sawType != type) {
 
          if (dir < 0) {dir = 1; moveOnce();}
 
          break;
 
        }
 
        if (type) sawType = type;
 
        if (dir > 0 && !moveOnce(!first)) break;
 
      }
 
    }
 
    var result = skipAtomic(doc, Pos(line, ch), dir, true);
 
    var result = skipAtomic(doc, Pos(line, ch), origDir, true);
 
    if (!possible) result.hitSide = true;
 
    return result;
 
  }
 

	
 
  function findPosV(cm, pos, dir, unit) {
 
    var doc = cm.doc, x = pos.left, y;
 
    if (unit == "page") {
 
      var pageSize = Math.min(cm.display.wrapper.clientHeight, window.innerHeight || document.documentElement.clientHeight);
 
      y = pos.top + dir * (pageSize - (dir < 0 ? 1.5 : .5) * textHeight(cm.display));
 
    } else if (unit == "line") {
 
      y = dir > 0 ? pos.bottom + 3 : pos.top - 3;
 
    }
 
    for (;;) {
 
      var target = coordsChar(cm, x, y);
 
      if (!target.outside) break;
 
      if (dir < 0 ? y <= 0 : y >= doc.height) { target.hitSide = true; break; }
 
      y += dir * 5;
 
    }
 
    return target;
 
  }
 

	
 
  function findWordAt(line, pos) {
 
    var start = pos.ch, end = pos.ch;
 
    if (line) {
 
      if (pos.after === false || end == line.length) --start; else ++end;
 
      if (pos.xRel < 0 || end == line.length) --start; else ++end;
 
      var startChar = line.charAt(start);
 
      var check = isWordChar(startChar) ? isWordChar
 
        : /\s/.test(startChar) ? function(ch) {return /\s/.test(ch);}
 
        : function(ch) {return !/\s/.test(ch) && !isWordChar(ch);};
 
      while (start > 0 && check(line.charAt(start - 1))) --start;
 
      while (end < line.length && check(line.charAt(end))) ++end;
 
    }
 
    return {from: Pos(pos.line, start), to: Pos(pos.line, end)};
 
  }
 

	
 
  function selectLine(cm, line) {
 
    extendSelection(cm.doc, Pos(line, 0), clipPos(cm.doc, Pos(line + 1, 0)));
 
  }
 

	
 
  // PROTOTYPE
 

	
 
  // The publicly visible API. Note that operation(null, f) means
 
  // 'wrap f in an operation, performed on its `this` parameter'
 

	
 
  CodeMirror.prototype = {
 
    constructor: CodeMirror,
 
    focus: function(){window.focus(); focusInput(this); onFocus(this); fastPoll(this);},
 

	
 
    setOption: function(option, value) {
 
      var options = this.options, old = options[option];
 
      if (options[option] == value && option != "mode") return;
 
      options[option] = value;
 
      if (optionHandlers.hasOwnProperty(option))
 
        operation(this, optionHandlers[option])(this, value, old);
 
    },
 

	
 
    getOption: function(option) {return this.options[option];},
 
    getDoc: function() {return this.doc;},
 
@@ -2754,90 +2803,116 @@ 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.state.overlays.push({mode: mode, modeSpec: spec, opaque: options && options.opaque});
 
      this.state.modeGen++;
 
      regChange(this);
 
    }),
 
    removeOverlay: operation(null, function(spec) {
 
      var overlays = this.state.overlays;
 
      for (var i = 0; i < overlays.length; ++i) {
 
        if (overlays[i].modeSpec == spec) {
 
        var cur = overlays[i].modeSpec;
 
        if (cur == spec || typeof spec == "string" && cur.name == spec) {
 
          overlays.splice(i, 1);
 
          this.state.modeGen++;
 
          regChange(this);
 
          return;
 
        }
 
      }
 
    }),
 

	
 
    indentLine: operation(null, function(n, dir, aggressive) {
 
      if (typeof dir != "string") {
 
      if (typeof dir != "string" && typeof dir != "number") {
 
        if (dir == null) dir = this.options.smartIndent ? "smart" : "prev";
 
        else dir = dir ? "add" : "subtract";
 
      }
 
      if (isLine(this.doc, n)) indentLine(this, n, dir, aggressive);
 
    }),
 
    indentSelection: operation(null, function(how) {
 
      var sel = this.doc.sel;
 
      if (posEq(sel.from, sel.to)) return indentLine(this, sel.from.line, how);
 
      var e = sel.to.line - (sel.to.ch ? 0 : 1);
 
      for (var i = sel.from.line; i <= e; ++i) indentLine(this, i, how);
 
    }),
 

	
 
    // Fetch the parser token for a given character. Useful for hacks
 
    // that want to inspect the mode state (say, for completion).
 
    getTokenAt: function(pos) {
 
    getTokenAt: function(pos, precise) {
 
      var doc = this.doc;
 
      pos = clipPos(doc, pos);
 
      var state = getStateBefore(this, pos.line), mode = this.doc.mode;
 
      var state = getStateBefore(this, pos.line, precise), mode = this.doc.mode;
 
      var line = getLine(doc, pos.line);
 
      var stream = new StringStream(line.text, this.options.tabSize);
 
      while (stream.pos < pos.ch && !stream.eol()) {
 
        stream.start = stream.pos;
 
        var style = mode.token(stream, state);
 
      }
 
      return {start: stream.start,
 
              end: stream.pos,
 
              string: stream.current(),
 
              className: style || null, // Deprecated, use 'type' instead
 
              type: style || null,
 
              state: state};
 
    },
 

	
 
    getStateAfter: function(line) {
 
    getTokenTypeAt: function(pos) {
 
      pos = clipPos(this.doc, pos);
 
      var styles = getLineStyles(this, getLine(this.doc, pos.line));
 
      var before = 0, after = (styles.length - 1) / 2, ch = pos.ch;
 
      for (;;) {
 
        var mid = (before + after) >> 1;
 
        if ((mid ? styles[mid * 2 - 1] : 0) >= ch) after = mid;
 
        else if (styles[mid * 2 + 1] < ch) before = mid + 1;
 
        else return styles[mid * 2 + 2];
 
      }
 
    },
 

	
 
    getStateAfter: function(line, precise) {
 
      var doc = this.doc;
 
      line = clipLine(doc, line == null ? doc.first + doc.size - 1: line);
 
      return getStateBefore(this, line + 1);
 
      return getStateBefore(this, line + 1, precise);
 
    },
 

	
 
    cursorCoords: function(start, mode) {
 
      var pos, sel = this.doc.sel;
 
      if (start == null) pos = sel.head;
 
      else if (typeof start == "object") pos = clipPos(this.doc, start);
 
      else pos = start ? sel.from : sel.to;
 
      return cursorCoords(this, pos, mode || "page");
 
    },
 

	
 
    charCoords: function(pos, mode) {
 
      return charCoords(this, clipPos(this.doc, pos), mode || "page");
 
    },
 

	
 
    coordsChar: function(coords, mode) {
 
      coords = fromCoordSystem(this, coords, mode || "page");
 
      return coordsChar(this, coords.left, coords.top);
 
    },
 

	
 
    lineAtHeight: function(height, mode) {
 
      height = fromCoordSystem(this, {top: height, left: 0}, mode || "page").top;
 
      return lineAtHeight(this.doc, height + this.display.viewOffset);
 
    },
 
    heightAtLine: function(line, mode) {
 
      var end = false, last = this.doc.first + this.doc.size - 1;
 
      if (line < this.doc.first) line = this.doc.first;
 
      else if (line > last) { line = last; end = true; }
 
      var lineObj = getLine(this.doc, line);
 
      return intoCoordSystem(this, getLine(this.doc, line), {top: 0, left: 0}, mode || "page").top +
 
        (end ? lineObj.height : 0);
 
    },
 

	
 
    defaultTextHeight: function() { return textHeight(this.display); },
 
    defaultCharWidth: function() { return charWidth(this.display); },
 

	
 
    setGutterMarker: operation(null, function(line, gutterID, value) {
 
      return changeLine(this, line, function(line) {
 
        var markers = line.gutterMarkers || (line.gutterMarkers = {});
 
        markers[gutterID] = value;
 
        if (!value && isEmpty(markers)) line.gutterMarkers = null;
 
        return true;
 
      });
 
    }),
 

	
 
@@ -2848,40 +2923,41 @@ window.CodeMirror = (function() {
 
          line.gutterMarkers[gutterID] = null;
 
          regChange(cm, i, i + 1);
 
          if (isEmpty(line.gutterMarkers)) line.gutterMarkers = null;
 
        }
 
        ++i;
 
      });
 
    }),
 

	
 
    addLineClass: operation(null, function(handle, where, cls) {
 
      return changeLine(this, handle, function(line) {
 
        var prop = where == "text" ? "textClass" : where == "background" ? "bgClass" : "wrapClass";
 
        if (!line[prop]) line[prop] = cls;
 
        else if (new RegExp("\\b" + cls + "\\b").test(line[prop])) return false;
 
        else if (new RegExp("(?:^|\\s)" + cls + "(?:$|\\s)").test(line[prop])) return false;
 
        else line[prop] += " " + cls;
 
        return true;
 
      });
 
    }),
 

	
 
    removeLineClass: operation(null, function(handle, where, cls) {
 
      return changeLine(this, handle, function(line) {
 
        var prop = where == "text" ? "textClass" : where == "background" ? "bgClass" : "wrapClass";
 
        var cur = line[prop];
 
        if (!cur) return false;
 
        else if (cls == null) line[prop] = null;
 
        else {
 
          var upd = cur.replace(new RegExp("^" + cls + "\\b\\s*|\\s*\\b" + cls + "\\b"), "");
 
          if (upd == cur) return false;
 
          line[prop] = upd || null;
 
          var found = cur.match(new RegExp("(?:^|\\s+)" + cls + "(?:$|\\s+)"));
 
          if (!found) return false;
 
          var end = found.index + found[0].length;
 
          line[prop] = cur.slice(0, found.index) + (!found.index || end == cur.length ? "" : " ") + cur.slice(end) || null;
 
        }
 
        return true;
 
      });
 
    }),
 

	
 
    addLineWidget: operation(null, function(handle, node, options) {
 
      return addLineWidget(this, handle, node, options);
 
    }),
 

	
 
    removeLineWidget: function(widget) { widget.clear(); },
 

	
 
    lineInfo: function(line) {
 
@@ -2911,25 +2987,25 @@ window.CodeMirror = (function() {
 
        top = pos.top;
 
      } else if (vert == "above" || vert == "near") {
 
        var vspace = Math.max(display.wrapper.clientHeight, this.doc.height),
 
        hspace = Math.max(display.sizer.clientWidth, display.lineSpace.clientWidth);
 
        // Default to positioning above (if specified and possible); otherwise default to positioning below
 
        if ((vert == 'above' || pos.bottom + node.offsetHeight > vspace) && pos.top > node.offsetHeight)
 
          top = pos.top - node.offsetHeight;
 
        else if (pos.bottom + node.offsetHeight <= vspace)
 
          top = pos.bottom;
 
        if (left + node.offsetWidth > hspace)
 
          left = hspace - node.offsetWidth;
 
      }
 
      node.style.top = (top + paddingTop(display)) + "px";
 
      node.style.top = top + "px";
 
      node.style.left = node.style.right = "";
 
      if (horiz == "right") {
 
        left = display.sizer.clientWidth - node.offsetWidth;
 
        node.style.right = "0px";
 
      } else {
 
        if (horiz == "left") left = 0;
 
        else if (horiz == "middle") left = (display.sizer.clientWidth - node.offsetWidth) / 2;
 
        node.style.left = left + "px";
 
      }
 
      if (scroll)
 
        scrollIntoView(this, left, top, left + node.offsetWidth, top + node.offsetHeight);
 
    },
 
@@ -2979,25 +3055,26 @@ 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);
 
      extendSelection(this.doc, target, target, dir);
 
      sel.goalColumn = pos.left;
 
    }),
 

	
 
    toggleOverwrite: function() {
 
    toggleOverwrite: function(value) {
 
      if (value != null && value == this.state.overwrite) return;
 
      if (this.state.overwrite = !this.state.overwrite)
 
        this.display.cursor.className += " CodeMirror-overwrite";
 
      else
 
        this.display.cursor.className = this.display.cursor.className.replace(" CodeMirror-overwrite", "");
 
    },
 
    hasFocus: function() { return this.state.focused; },
 

	
 
    scrollTo: operation(null, function(x, y) {
 
      updateScrollPos(this, x, y);
 
    }),
 
    getScrollInfo: function() {
 
      var scroller = this.display.scroller, co = scrollerCutOff;
 
@@ -3102,39 +3179,41 @@ window.CodeMirror = (function() {
 
  option("onKeyEvent", null);
 
  option("onDragEvent", null);
 

	
 
  option("lineWrapping", false, wrappingChanged, true);
 
  option("gutters", [], function(cm) {
 
    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("coverGutterNextToScrollbar", false, updateScrollbars, true);
 
  option("lineNumbers", false, function(cm) {
 
    setGuttersForLineNumbers(cm.options);
 
    guttersChanged(cm);
 
  }, true);
 
  option("firstLineNumber", 1, guttersChanged, true);
 
  option("lineNumberFormatter", function(integer) {return integer;}, guttersChanged, true);
 
  option("showCursorWhenSelecting", false, updateSelection, true);
 

	
 
  option("readOnly", false, function(cm, val) {
 
    if (val == "nocursor") {onBlur(cm); cm.display.input.blur();}
 
    else if (!val) resetInput(cm, true);
 
  });
 
  option("dragDrop", true);
 

	
 
  option("cursorBlinkRate", 530);
 
  option("cursorScrollMargin", 0);
 
  option("cursorHeight", 1);
 
  option("workTime", 100);
 
  option("workDelay", 100);
 
  option("flattenSpans", 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("moveInputWithCursor", true, function(cm, val) {
 
    if (!val) cm.display.inputDiv.style.top = cm.display.inputDiv.style.left = 0;
 
  });
 
@@ -3154,28 +3233,33 @@ window.CodeMirror = (function() {
 
    if (arguments.length > 2) {
 
      mode.dependencies = [];
 
      for (var i = 2; i < arguments.length; ++i) mode.dependencies.push(arguments[i]);
 
    }
 
    modes[name] = mode;
 
  };
 

	
 
  CodeMirror.defineMIME = function(mime, spec) {
 
    mimeModes[mime] = spec;
 
  };
 

	
 
  CodeMirror.resolveMode = function(spec) {
 
    if (typeof spec == "string" && mimeModes.hasOwnProperty(spec))
 
    if (typeof spec == "string" && mimeModes.hasOwnProperty(spec)) {
 
      spec = mimeModes[spec];
 
    else if (typeof spec == "string" && /^[\w\-]+\/[\w\-]+\+xml$/.test(spec))
 
    } else if (spec && typeof spec.name == "string" && mimeModes.hasOwnProperty(spec.name)) {
 
      var found = mimeModes[spec.name];
 
      spec = createObj(found, spec);
 
      spec.name = found.name;
 
    } else if (typeof spec == "string" && /^[\w\-]+\/[\w\-]+\+xml$/.test(spec)) {
 
      return CodeMirror.resolveMode("application/xml");
 
    }
 
    if (typeof spec == "string") return {name: spec};
 
    else return spec || {name: "null"};
 
  };
 

	
 
  CodeMirror.getMode = function(options, spec) {
 
    spec = CodeMirror.resolveMode(spec);
 
    var mfactory = modes[spec.name];
 
    if (!mfactory) return CodeMirror.getMode(options, "text/plain");
 
    var modeObj = mfactory(options, spec);
 
    if (modeExtensions.hasOwnProperty(spec.name)) {
 
      var exts = modeExtensions[spec.name];
 
      for (var prop in exts) {
 
@@ -3248,24 +3332,28 @@ window.CodeMirror = (function() {
 
  var commands = CodeMirror.commands = {
 
    selectAll: function(cm) {cm.setSelection(Pos(cm.firstLine(), 0), Pos(cm.lastLine()));},
 
    killLine: function(cm) {
 
      var from = cm.getCursor(true), to = cm.getCursor(false), sel = !posEq(from, to);
 
      if (!sel && cm.getLine(from.line).length == from.ch)
 
        cm.replaceRange("", from, Pos(from.line + 1, 0), "+delete");
 
      else cm.replaceRange("", from, sel ? to : Pos(from.line), "+delete");
 
    },
 
    deleteLine: function(cm) {
 
      var l = cm.getCursor().line;
 
      cm.replaceRange("", Pos(l, 0), Pos(l), "+delete");
 
    },
 
    delLineLeft: function(cm) {
 
      var cur = cm.getCursor();
 
      cm.replaceRange("", Pos(cur.line, 0), cur, "+delete");
 
    },
 
    undo: function(cm) {cm.undo();},
 
    redo: function(cm) {cm.redo();},
 
    goDocStart: function(cm) {cm.extendSelection(Pos(cm.firstLine(), 0));},
 
    goDocEnd: function(cm) {cm.extendSelection(Pos(cm.lastLine()));},
 
    goLineStart: function(cm) {
 
      cm.extendSelection(lineStart(cm, cm.getCursor().line));
 
    },
 
    goLineStartSmart: function(cm) {
 
      var cur = cm.getCursor(), start = lineStart(cm, cur.line);
 
      var line = cm.getLineHandle(start.line);
 
      var order = getOrder(line);
 
      if (!order || order[0].level == 0) {
 
@@ -3343,25 +3431,25 @@ window.CodeMirror = (function() {
 
    "Ctrl-Left": "goGroupLeft", "Ctrl-Right": "goGroupRight", "Alt-Left": "goLineStart", "Alt-Right": "goLineEnd",
 
    "Ctrl-Backspace": "delGroupBefore", "Ctrl-Delete": "delGroupAfter", "Ctrl-S": "save", "Ctrl-F": "find",
 
    "Ctrl-G": "findNext", "Shift-Ctrl-G": "findPrev", "Shift-Ctrl-F": "replace", "Shift-Ctrl-R": "replaceAll",
 
    "Ctrl-[": "indentLess", "Ctrl-]": "indentMore",
 
    fallthrough: "basic"
 
  };
 
  keyMap.macDefault = {
 
    "Cmd-A": "selectAll", "Cmd-D": "deleteLine", "Cmd-Z": "undo", "Shift-Cmd-Z": "redo", "Cmd-Y": "redo",
 
    "Cmd-Up": "goDocStart", "Cmd-End": "goDocEnd", "Cmd-Down": "goDocEnd", "Alt-Left": "goGroupLeft",
 
    "Alt-Right": "goGroupRight", "Cmd-Left": "goLineStart", "Cmd-Right": "goLineEnd", "Alt-Backspace": "delGroupBefore",
 
    "Ctrl-Alt-Backspace": "delGroupAfter", "Alt-Delete": "delGroupAfter", "Cmd-S": "save", "Cmd-F": "find",
 
    "Cmd-G": "findNext", "Shift-Cmd-G": "findPrev", "Cmd-Alt-F": "replace", "Shift-Cmd-Alt-F": "replaceAll",
 
    "Cmd-[": "indentLess", "Cmd-]": "indentMore",
 
    "Cmd-[": "indentLess", "Cmd-]": "indentMore", "Cmd-Backspace": "delLineLeft",
 
    fallthrough: ["basic", "emacsy"]
 
  };
 
  keyMap["default"] = mac ? keyMap.macDefault : keyMap.pcDefault;
 
  keyMap.emacsy = {
 
    "Ctrl-F": "goCharRight", "Ctrl-B": "goCharLeft", "Ctrl-P": "goLineUp", "Ctrl-N": "goLineDown",
 
    "Alt-F": "goWordRight", "Alt-B": "goWordLeft", "Ctrl-A": "goLineStart", "Ctrl-E": "goLineEnd",
 
    "Ctrl-V": "goPageDown", "Shift-Ctrl-V": "goPageUp", "Ctrl-D": "delCharAfter", "Ctrl-H": "delCharBefore",
 
    "Alt-D": "delWordAfter", "Alt-Backspace": "delWordBefore", "Ctrl-K": "killLine", "Ctrl-T": "transposeChars"
 
  };
 

	
 
  // KEYMAP DISPATCH
 

	
 
@@ -3382,25 +3470,25 @@ window.CodeMirror = (function() {
 
      if (fallthrough == null) return false;
 
      if (Object.prototype.toString.call(fallthrough) != "[object Array]")
 
        return lookup(fallthrough);
 
      for (var i = 0, e = fallthrough.length; i < e; ++i) {
 
        var done = lookup(fallthrough[i]);
 
        if (done) return done;
 
      }
 
      return false;
 
    }
 

	
 
    for (var i = 0; i < maps.length; ++i) {
 
      var done = lookup(maps[i]);
 
      if (done) return done;
 
      if (done) return done != "stop";
 
    }
 
  }
 
  function isModifierKey(event) {
 
    var name = keyNames[event.keyCode];
 
    return name == "Ctrl" || name == "Alt" || name == "Shift" || name == "Mod";
 
  }
 
  function keyName(event, noShift) {
 
    if (opera && event.keyCode == 34 && event["char"]) return false;
 
    var name = keyNames[event.keyCode];
 
    if (name == null || event.altGraphKey) return false;
 
    if (event.altKey) name = "Alt-" + name;
 
    if (flipCtrlCmd ? event.metaKey : event.ctrlKey) name = "Ctrl-" + name;
 
@@ -3564,56 +3652,59 @@ window.CodeMirror = (function() {
 
    if (cm && this.collapsed && !cm.options.lineWrapping) for (var i = 0; i < this.lines.length; ++i) {
 
      var visual = visualLine(cm.doc, this.lines[i]), len = lineLength(cm.doc, visual);
 
      if (len > cm.display.maxLineLength) {
 
        cm.display.maxLine = visual;
 
        cm.display.maxLineLength = len;
 
        cm.display.maxLineChanged = true;
 
      }
 
    }
 

	
 
    if (min != null && cm) regChange(cm, min, max + 1);
 
    this.lines.length = 0;
 
    this.explicitlyCleared = true;
 
    if (this.collapsed && this.doc.cantEdit) {
 
    if (this.atomic && this.doc.cantEdit) {
 
      this.doc.cantEdit = false;
 
      if (cm) reCheckSelection(cm);
 
    }
 
    if (withOp) endOperation(cm);
 
    signalLater(this, "clear");
 
  };
 

	
 
  TextMarker.prototype.find = function() {
 
    var from, to;
 
    for (var i = 0; i < this.lines.length; ++i) {
 
      var line = this.lines[i];
 
      var span = getMarkedSpanFor(line.markedSpans, this);
 
      if (span.from != null || span.to != null) {
 
        var found = lineNo(line);
 
        if (span.from != null) from = Pos(found, span.from);
 
        if (span.to != null) to = Pos(found, span.to);
 
      }
 
    }
 
    if (this.type == "bookmark") return from;
 
    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,
 
            replacedWith: copyWidget ? repl && repl.cloneNode(true) : repl,
 
            readOnly: this.readOnly,
 
            startStyle: this.startStyle, endStyle: this.endStyle};
 
  TextMarker.prototype.changed = function() {
 
    var pos = this.find(), cm = this.doc.cm;
 
    if (!pos || !cm) return;
 
    var line = getLine(this.doc, pos.from.line);
 
    clearCachedMeasurement(cm, line);
 
    if (pos.from.line >= cm.display.showingFrom && pos.from.line < cm.display.showingTo) {
 
      for (var node = cm.display.lineDiv.firstChild; node; node = node.nextSibling) if (node.lineObj == line) {
 
        if (node.offsetHeight != line.height) updateLineHeight(line, node.offsetHeight);
 
        break;
 
      }
 
      runInOp(cm, function() { cm.curOp.selectionChanged = true; });
 
    }
 
  };
 

	
 
  TextMarker.prototype.attachLine = function(line) {
 
    if (!this.lines.length && this.doc.cm) {
 
      var op = this.doc.cm.curOp;
 
      if (!op.maybeHiddenMarkers || indexOf(op.maybeHiddenMarkers, this) == -1)
 
        (op.maybeUnhiddenMarkers || (op.maybeUnhiddenMarkers = [])).push(this);
 
    }
 
    this.lines.push(line);
 
  };
 
  TextMarker.prototype.detachLine = function(line) {
 
    this.lines.splice(indexOf(this.lines, line), 1);
 
@@ -3624,24 +3715,25 @@ window.CodeMirror = (function() {
 
  };
 

	
 
  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);
 

	
 
    var marker = new TextMarker(doc, type);
 
    if (type == "range" && !posLess(from, to)) return marker;
 
    if (options) copyObj(options, marker);
 
    if (marker.replacedWith) {
 
      marker.collapsed = true;
 
      marker.replacedWith = elt("span", [marker.replacedWith], "CodeMirror-widget");
 
      if (!options.handleMouseEvents) marker.replacedWith.ignoreEvents = true;
 
    }
 
    if (marker.collapsed) 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;
 
    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};
 
@@ -3695,29 +3787,24 @@ window.CodeMirror = (function() {
 
  CodeMirror.SharedTextMarker = SharedTextMarker;
 

	
 
  SharedTextMarker.prototype.clear = function() {
 
    if (this.explicitlyCleared) return;
 
    this.explicitlyCleared = true;
 
    for (var i = 0; i < this.markers.length; ++i)
 
      this.markers[i].clear();
 
    signalLater(this, "clear");
 
  };
 
  SharedTextMarker.prototype.find = function() {
 
    return this.primary.find();
 
  };
 
  SharedTextMarker.prototype.getOptions = function(copyWidget) {
 
    var inner = this.primary.getOptions(copyWidget);
 
    inner.shared = true;
 
    return inner;
 
  };
 

	
 
  function markTextShared(doc, from, to, options, type) {
 
    options = copyObj(options);
 
    options.shared = false;
 
    var markers = [markText(doc, from, to, options, type)], primary = markers[0];
 
    var widget = options.replacedWith;
 
    linkedDocs(doc, function(doc) {
 
      if (widget) options.replacedWith = widget.cloneNode(true);
 
      markers.push(markText(doc, clipPos(doc, from), clipPos(doc, to), options, type));
 
      for (var i = 0; i < doc.linked.length; ++i)
 
        if (doc.linked[i].isParent) return;
 
      primary = lst(markers);
 
@@ -3802,24 +3889,31 @@ window.CodeMirror = (function() {
 
        if (span.from == null) {
 
          var found = getMarkedSpanFor(first, span.marker);
 
          if (!found) {
 
            span.from = offset;
 
            if (sameLine) (first || (first = [])).push(span);
 
          }
 
        } else {
 
          span.from += offset;
 
          if (sameLine) (first || (first = [])).push(span);
 
        }
 
      }
 
    }
 
    if (sameLine && first) {
 
      // Make sure we didn't create any zero-length spans
 
      for (var i = 0; i < first.length; ++i)
 
        if (first[i].from != null && first[i].from == first[i].to && first[i].marker.type != "bookmark")
 
          first.splice(i--, 1);
 
      if (!first.length) first = null;
 
    }
 

	
 
    var newMarkers = [first];
 
    if (!sameLine) {
 
      // Fill gap with whole-line-spans
 
      var gap = change.text.length - 2, gapMarkers;
 
      if (gap > 0 && first)
 
        for (var i = 0; i < first.length; ++i)
 
          if (first[i].to == null)
 
            (gapMarkers || (gapMarkers = [])).push({from: null, to: null, marker: first[i].marker});
 
      for (var i = 0; i < gap; ++i)
 
        newMarkers.push(gapMarkers);
 
      newMarkers.push(last);
 
@@ -3896,38 +3990,39 @@ window.CodeMirror = (function() {
 
    var merged;
 
    while (merged = collapsedSpanAtStart(line))
 
      line = getLine(doc, merged.find().from.line);
 
    return line;
 
  }
 

	
 
  function lineIsHidden(doc, line) {
 
    var sps = sawCollapsedSpans && line.markedSpans;
 
    if (sps) for (var sp, i = 0; i < sps.length; ++i) {
 
      sp = sps[i];
 
      if (!sp.marker.collapsed) continue;
 
      if (sp.from == null) return true;
 
      if (sp.marker.replacedWith) continue;
 
      if (sp.from == 0 && sp.marker.inclusiveLeft && lineIsHiddenInner(doc, line, sp))
 
        return true;
 
    }
 
  }
 
  function lineIsHiddenInner(doc, line, span) {
 
    if (span.to == null) {
 
      var end = span.marker.find().to, endLine = getLine(doc, end.line);
 
      return lineIsHiddenInner(doc, 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];
 
      if (sp.marker.collapsed && sp.from == span.to &&
 
      if (sp.marker.collapsed && !sp.marker.replacedWith && sp.from == span.to &&
 
          (sp.marker.inclusiveLeft || span.marker.inclusiveRight) &&
 
          lineIsHiddenInner(doc, line, sp)) return true;
 
    }
 
  }
 

	
 
  function detachMarkedSpans(line) {
 
    var spans = line.markedSpans;
 
    if (!spans) return;
 
    for (var i = 0; i < spans.length; ++i)
 
      spans[i].marker.detachLine(line);
 
    line.markedSpans = null;
 
  }
 
@@ -4021,72 +4116,68 @@ window.CodeMirror = (function() {
 

	
 
  function cleanUpLine(line) {
 
    line.parent = null;
 
    detachMarkedSpans(line);
 
  }
 

	
 
  // Run the given mode's parser over a line, update the styles
 
  // array, which contains alternating fragments of text and CSS
 
  // classes.
 
  function runMode(cm, text, mode, state, f) {
 
    var flattenSpans = mode.flattenSpans;
 
    if (flattenSpans == null) flattenSpans = cm.options.flattenSpans;
 
    var curText = "", curStyle = null;
 
    var curStart = 0, curStyle = null;
 
    var stream = new StringStream(text, cm.options.tabSize), style;
 
    if (text == "" && mode.blankLine) mode.blankLine(state);
 
    while (!stream.eol()) {
 
      if (stream.pos > cm.options.maxHighlightLength) {
 
        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;
 
      } else {
 
        style = mode.token(stream, state);
 
      }
 
      var substr = stream.current();
 
      if (!flattenSpans || curStyle != style) {
 
        if (curStart < stream.start) f(stream.start, curStyle);
 
        curStart = stream.start; curStyle = style;
 
      }
 
      stream.start = stream.pos;
 
      if (!flattenSpans || curStyle != style) {
 
        if (curText) f(curText, curStyle);
 
        curText = substr; curStyle = style;
 
      } else curText = curText + substr;
 
    }
 
    if (curText) f(curText, curStyle);
 
    }
 
    if (curStart < stream.pos) f(stream.pos, 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.state.modeGen];
 
    // Compute the base array of styles
 
    runMode(cm, line.text, cm.doc.mode, state, function(txt, style) {st.push(txt, style);});
 
    runMode(cm, line.text, cm.doc.mode, state, function(end, style) {st.push(end, style);});
 

	
 
    // Run overlays, adjust style array.
 
    for (var o = 0; o < cm.state.overlays.length; ++o) {
 
      var overlay = cm.state.overlays[o], i = 1;
 
      runMode(cm, line.text, overlay.mode, true, function(txt, style) {
 
        var start = i, len = txt.length;
 
      var overlay = cm.state.overlays[o], i = 1, at = 0;
 
      runMode(cm, line.text, overlay.mode, true, function(end, style) {
 
        var start = i;
 
        // 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;
 
          }
 
        while (at < end) {
 
          var i_end = st[i];
 
          if (i_end > end)
 
            st.splice(i, 1, end, st[i+1], i_end);
 
          i += 2;
 
          at = Math.min(end, i_end);
 
        }
 
        if (!style) return;
 
        if (overlay.opaque) {
 
          st.splice(start, i - start, txt, style);
 
          st.splice(start, i - start, end, style);
 
          i = start + 2;
 
        } else {
 
          for (; start < i; start += 2) {
 
            var cur = st[start+1];
 
            st[start+1] = cur ? cur + " " + style : style;
 
          }
 
        }
 
      });
 
    }
 

	
 
    return st;
 
  }
 
@@ -4108,55 +4199,49 @@ window.CodeMirror = (function() {
 
      stream.start = stream.pos;
 
    }
 
  }
 

	
 
  var styleToClassCache = {};
 
  function styleToClass(style) {
 
    if (!style) return null;
 
    return styleToClassCache[style] ||
 
      (styleToClassCache[style] = "cm-" + style.replace(/ +/g, " cm-"));
 
  }
 

	
 
  function lineContent(cm, realLine, measure) {
 
    var merged, line = realLine, lineBefore, sawBefore, simple = true;
 
    while (merged = collapsedSpanAtStart(line)) {
 
      simple = false;
 
    var merged, line = realLine, empty = true;
 
    while (merged = collapsedSpanAtStart(line))
 
      line = getLine(cm.doc, merged.find().from.line);
 
      if (!lineBefore) lineBefore = line;
 
    }
 

	
 
    var builder = {pre: elt("pre"), col: 0, pos: 0, display: !measure,
 
                   measure: null, addedOne: false, cm: cm};
 
                   measure: null, measuredSomething: false, cm: cm};
 
    if (line.textClass) builder.pre.className = line.textClass;
 

	
 
    do {
 
      if (line.text) empty = false;
 
      builder.measure = line == realLine && measure;
 
      builder.pos = 0;
 
      builder.addToken = builder.measure ? buildTokenMeasure : buildToken;
 
      if ((ie || webkit) && cm.getOption("lineWrapping"))
 
        builder.addToken = buildTokenSplitSpaces(builder.addToken);
 
      if (measure && sawBefore && line != realLine && !builder.addedOne) {
 
      var next = insertLineContent(line, builder, getLineStyles(cm, line));
 
      if (measure && line == realLine && !builder.measuredSomething) {
 
        measure[0] = builder.pre.appendChild(zeroWidthElement(cm.display.measure));
 
        builder.addedOne = true;
 
        builder.measuredSomething = true;
 
      }
 
      var next = insertLineContent(line, builder, getLineStyles(cm, line));
 
      sawBefore = line == lineBefore;
 
      if (next) {
 
        line = getLine(cm.doc, next.to.line);
 
        simple = false;
 
      }
 
      if (next) line = getLine(cm.doc, next.to.line);
 
    } while (next);
 

	
 
    if (measure && !builder.addedOne)
 
      measure[0] = builder.pre.appendChild(simple ? elt("span", "\u00a0") : zeroWidthElement(cm.display.measure));
 
    if (measure && !builder.measuredSomething && !measure[0])
 
      measure[0] = builder.pre.appendChild(empty ? elt("span", "\u00a0") : zeroWidthElement(cm.display.measure));
 
    if (!builder.pre.firstChild && !lineIsHidden(cm.doc, realLine))
 
      builder.pre.appendChild(document.createTextNode("\u00a0"));
 

	
 
    var order;
 
    // 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 && (order = getOrder(line))) {
 
      var l = order.length - 1;
 
      if (order[l].from == order[l].to) --l;
 
      var last = order[l], prev = order[l - 1];
 
      if (last.from + 1 == last.to && prev && last.level < prev.level) {
 
@@ -4207,92 +4292,91 @@ window.CodeMirror = (function() {
 
      return builder.pre.appendChild(elt("span", [content], fullStyle));
 
    }
 
    builder.pre.appendChild(content);
 
  }
 

	
 
  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.test(text.slice(i - 1, i + 1))) {
 
      } else if (i && wrapping && spanAffectsWrapping(text, i)) {
 
        builder.pre.appendChild(elt("wbr"));
 
      }
 
      var span = builder.measure[builder.pos] =
 
        buildToken(builder, ch, style,
 
                   start && startStyle, i == text.length - 1 && endStyle);
 
      // 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)) &&
 
          i < text.length - 1 && !/\s/.test(text.charAt(i + 1)))
 
        span.style.whiteSpace = "normal";
 
      builder.pos += ch.length;
 
    }
 
    if (text.length) builder.addedOne = true;
 
    if (text.length) builder.measuredSomething = true;
 
  }
 

	
 
  function buildTokenSplitSpaces(inner) {
 
    function split(old) {
 
      var out = " ";
 
      for (var i = 0; i < old.length - 2; ++i) out += i % 2 ? " " : "\u00a0";
 
      out += " ";
 
      return out;
 
    }
 
    return function(builder, text, style, startStyle, endStyle) {
 
      return inner(builder, text.replace(/ {3,}/, split), style, startStyle, endStyle);
 
    };
 
  }
 

	
 
  function buildCollapsedSpan(builder, size, widget) {
 
    if (widget) {
 
      if (!builder.display) widget = widget.cloneNode(true);
 
      if (builder.measure) {
 
        builder.measure[builder.pos] = size ? widget
 
          : builder.pre.appendChild(zeroWidthElement(builder.cm.display.measure));
 
        builder.measuredSomething = true;
 
      }
 
      builder.pre.appendChild(widget);
 
      if (builder.measure && size) {
 
        builder.measure[builder.pos] = widget;
 
        builder.addedOne = true;
 
      }
 
    }
 
    builder.pos += size;
 
  }
 

	
 
  // Outputs a number of spans to make up a line, taking highlighting
 
  // and marked text into account.
 
  function insertLineContent(line, builder, styles) {
 
    var spans = line.markedSpans;
 
    var spans = line.markedSpans, allText = line.text, at = 0;
 
    if (!spans) {
 
      for (var i = 1; i < styles.length; i+=2)
 
        builder.addToken(builder, styles[i], styleToClass(styles[i+1]));
 
        builder.addToken(builder, allText.slice(at, at = styles[i]), styleToClass(styles[i+1]));
 
      return;
 
    }
 

	
 
    var allText = line.text, len = allText.length;
 
    var pos = 0, i = 1, text = "", style;
 
    var len = allText.length, pos = 0, i = 1, text = "", style;
 
    var nextChange = 0, spanStyle, spanEndStyle, spanStartStyle, collapsed;
 
    for (;;) {
 
      if (nextChange == pos) { // Update current marker set
 
        spanStyle = spanEndStyle = spanStartStyle = "";
 
        collapsed = null; nextChange = Infinity;
 
        var foundBookmark = null;
 
        for (var j = 0; j < spans.length; ++j) {
 
          var sp = spans[j], m = sp.marker;
 
          if (sp.from <= pos && (sp.to == null || sp.to > pos)) {
 
            if (sp.to != null && nextChange > sp.to) { nextChange = sp.to; spanEndStyle = ""; }
 
            if (m.className) spanStyle += " " + m.className;
 
            if (m.startStyle && sp.from == pos) spanStartStyle += " " + m.startStyle;
 
            if (m.endStyle && sp.to == nextChange) spanEndStyle += " " + m.endStyle;
 
            if (m.collapsed && (!collapsed || collapsed.marker.width < m.width))
 
            if (m.collapsed && (!collapsed || collapsed.marker.size < m.size))
 
              collapsed = sp;
 
          } else if (sp.from > pos && nextChange > sp.from) {
 
            nextChange = sp.from;
 
          }
 
          if (m.type == "bookmark" && sp.from == pos && m.replacedWith)
 
            foundBookmark = m.replacedWith;
 
        }
 
        if (collapsed && (collapsed.from || 0) == pos) {
 
          buildCollapsedSpan(builder, (collapsed.to == null ? len : collapsed.to) - pos,
 
                             collapsed.from != null && collapsed.marker.replacedWith);
 
          if (collapsed.to == null) return collapsed.marker.find();
 
        }
 
@@ -4304,25 +4388,26 @@ window.CodeMirror = (function() {
 
      while (true) {
 
        if (text) {
 
          var end = pos + text.length;
 
          if (!collapsed) {
 
            var tokenText = end > upto ? text.slice(0, upto - pos) : text;
 
            builder.addToken(builder, tokenText, style ? style + spanStyle : spanStyle,
 
                             spanStartStyle, pos + tokenText.length == nextChange ? spanEndStyle : "");
 
          }
 
          if (end >= upto) {text = text.slice(upto - pos); pos = upto; break;}
 
          pos = end;
 
          spanStartStyle = "";
 
        }
 
        text = styles[i++]; style = styleToClass(styles[i++]);
 
        text = allText.slice(at, at = styles[i++]);
 
        style = styleToClass(styles[i++]);
 
      }
 
    }
 
  }
 

	
 
  // DOCUMENT DATA STRUCTURE
 

	
 
  function updateDoc(doc, change, markedSpans, selAfter, estimateHeight) {
 
    function spansFor(n) {return markedSpans ? markedSpans[n] : null;}
 
    function update(line, text, spans) {
 
      updateLine(line, text, spans, estimateHeight);
 
      signalLater(line, "change", line, change);
 
    }
 
@@ -4496,35 +4581,37 @@ window.CodeMirror = (function() {
 
  };
 

	
 
  var nextDocId = 0;
 
  var Doc = CodeMirror.Doc = function(text, mode, firstLine) {
 
    if (!(this instanceof Doc)) return new Doc(text, mode, firstLine);
 
    if (firstLine == null) firstLine = 0;
 

	
 
    BranchChunk.call(this, [new LeafChunk([makeLine("", null)])]);
 
    this.first = firstLine;
 
    this.scrollTop = this.scrollLeft = 0;
 
    this.cantEdit = false;
 
    this.history = makeHistory();
 
    this.cleanGeneration = 1;
 
    this.frontier = firstLine;
 
    var start = Pos(firstLine, 0);
 
    this.sel = {from: start, to: start, head: start, anchor: start, shift: false, extend: false, goalColumn: null};
 
    this.id = ++nextDocId;
 
    this.modeOption = mode;
 

	
 
    if (typeof text == "string") text = splitLines(text);
 
    updateDoc(this, {from: start, to: start, text: text}, null, {head: start, anchor: start});
 
  };
 

	
 
  Doc.prototype = createObj(BranchChunk.prototype, {
 
    constructor: Doc,
 
    iter: function(from, to, op) {
 
      if (op) this.iterN(from - this.first, to - from, op);
 
      else this.iterN(this.first, this.first + this.size, from);
 
    },
 

	
 
    insert: function(at, lines) {
 
      var height = 0;
 
      for (var i = 0, e = lines.length; i < e; ++i) height += lines[i].height;
 
      this.insertInner(at - this.first, lines, height);
 
    },
 
    remove: function(at, n) { this.removeInner(at - this.first, n); },
 

	
 
@@ -4595,38 +4682,43 @@ window.CodeMirror = (function() {
 
    replaceSelection: function(code, collapse, origin) {
 
      makeChange(this, {from: this.sel.from, to: this.sel.to, text: splitLines(code), origin: origin}, collapse || "around");
 
    },
 
    undo: docOperation(function() {makeChangeFromHistory(this, "undo");}),
 
    redo: docOperation(function() {makeChangeFromHistory(this, "redo");}),
 

	
 
    setExtending: function(val) {this.sel.extend = val;},
 

	
 
    historySize: function() {
 
      var hist = this.history;
 
      return {undo: hist.done.length, redo: hist.undone.length};
 
    },
 
    clearHistory: function() {this.history = makeHistory();},
 
    clearHistory: function() {this.history = makeHistory(this.history.maxGeneration);},
 

	
 
    markClean: function() {
 
      this.history.dirtyCounter = 0;
 
      this.cleanGeneration = this.changeGeneration();
 
    },
 
    changeGeneration: function() {
 
      this.history.lastOp = this.history.lastOrigin = null;
 
      return this.history.generation;
 
    },
 
    isClean: function () {return this.history.dirtyCounter == 0;},
 
    isClean: function (gen) {
 
      return this.history.generation == (gen || this.cleanGeneration);
 
    },
 

	
 
    getHistory: function() {
 
      return {done: copyHistoryArray(this.history.done),
 
              undone: copyHistoryArray(this.history.undone)};
 
    },
 
    setHistory: function(histData) {
 
      var hist = this.history = makeHistory();
 
      var hist = this.history = makeHistory(this.history.maxGeneration);
 
      hist.done = histData.done.slice(0);
 
      hist.undone = histData.undone.slice(0);
 
    },
 

	
 
    markText: function(from, to, options) {
 
      return markText(this, clipPos(this, from), clipPos(this, to), options, "range");
 
    },
 
    setBookmark: function(pos, options) {
 
      var realOpts = {replacedWith: options && (options.nodeType == null ? options.widget : options),
 
                      insertLeft: options && options.insertLeft};
 
      pos = clipPos(this, pos);
 
      return markText(this, pos, pos, realOpts, "bookmark");
 
@@ -4838,35 +4930,35 @@ window.CodeMirror = (function() {
 
    }
 
    return h;
 
  }
 

	
 
  function getOrder(line) {
 
    var order = line.order;
 
    if (order == null) order = line.order = bidiOrdering(line.text);
 
    return order;
 
  }
 

	
 
  // HISTORY
 

	
 
  function makeHistory() {
 
  function makeHistory(startGen) {
 
    return {
 
      // Arrays of history events. Doing something adds an event to
 
      // done and clears undo. Undoing moves events from done to
 
      // undone, redoing moves them in the other direction.
 
      done: [], undone: [], undoDepth: Infinity,
 
      // Used to track when changes can be merged into a single undo
 
      // event
 
      lastTime: 0, lastOp: null, lastOrigin: null,
 
      // Used by the isClean() method
 
      dirtyCounter: 0
 
      generation: startGen || 1, maxGeneration: startGen || 1
 
    };
 
  }
 

	
 
  function attachLocalSpans(doc, change, from, to) {
 
    var existing = change["spans_" + doc.id], n = 0;
 
    doc.iter(Math.max(doc.first, from), Math.min(doc.first + doc.size, to), function(line) {
 
      if (line.markedSpans)
 
        (existing || (existing = change["spans_" + doc.id] = {}))[n] = line.markedSpans;
 
      ++n;
 
    });
 
  }
 

	
 
@@ -4892,35 +4984,31 @@ window.CodeMirror = (function() {
 
      if (posEq(change.from, change.to) && posEq(change.from, last.to)) {
 
        // Optimized case for simple insertion -- don't want to add
 
        // new changesets for every character typed
 
        last.to = changeEnd(change);
 
      } else {
 
        // Add new sub-event
 
        cur.changes.push(historyChangeFromChange(doc, change));
 
      }
 
      cur.anchorAfter = selAfter.anchor; cur.headAfter = selAfter.head;
 
    } else {
 
      // Can not be merged, start a new event.
 
      cur = {changes: [historyChangeFromChange(doc, change)],
 
             generation: hist.generation,
 
             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();
 
      if (hist.dirtyCounter < 0)
 
        // The user has made a change after undoing past the last clean state.
 
        // We can never get back to a clean state now until markClean() is called.
 
        hist.dirtyCounter = NaN;
 
      else
 
        hist.dirtyCounter++;
 
    }
 
    hist.lastTime = time;
 
    hist.lastOp = opId;
 
    hist.lastOrigin = change.origin;
 
  }
 

	
 
  function removeClearedSpans(spans) {
 
    if (!spans) return null;
 
    for (var i = 0, out; i < spans.length; ++i) {
 
      if (spans[i].marker.explicitlyCleared) { if (!out) out = spans.slice(0, i); }
 
      else if (out) out.push(spans[i]);
 
    }
 
@@ -5017,24 +5105,27 @@ window.CodeMirror = (function() {
 
    if (!event.stop) event.stop = stopMethod;
 
    return event;
 
  }
 

	
 
  function e_preventDefault(e) {
 
    if (e.preventDefault) e.preventDefault();
 
    else e.returnValue = false;
 
  }
 
  function e_stopPropagation(e) {
 
    if (e.stopPropagation) e.stopPropagation();
 
    else e.cancelBubble = true;
 
  }
 
  function e_defaultPrevented(e) {
 
    return e.defaultPrevented != null ? e.defaultPrevented : e.returnValue == false;
 
  }
 
  function e_stop(e) {e_preventDefault(e); e_stopPropagation(e);}
 
  CodeMirror.e_stop = e_stop;
 
  CodeMirror.e_preventDefault = e_preventDefault;
 
  CodeMirror.e_stopPropagation = e_stopPropagation;
 

	
 
  function e_target(e) {return e.target || e.srcElement;}
 
  function e_button(e) {
 
    var b = e.which;
 
    if (b == null) {
 
      if (e.button & 1) b = 1;
 
      else if (e.button & 2) b = 3;
 
      else if (e.button & 4) b = 2;
 
@@ -5083,24 +5174,29 @@ window.CodeMirror = (function() {
 
    if (!arr) return;
 
    var args = Array.prototype.slice.call(arguments, 2);
 
    if (!delayedCallbacks) {
 
      ++delayedCallbackDepth;
 
      delayedCallbacks = [];
 
      setTimeout(fireDelayed, 0);
 
    }
 
    function bnd(f) {return function(){f.apply(null, args);};};
 
    for (var i = 0; i < arr.length; ++i)
 
      delayedCallbacks.push(bnd(arr[i]));
 
  }
 

	
 
  function signalDOMEvent(cm, e) {
 
    signal(cm, e.type, cm, e);
 
    return e_defaultPrevented(e);
 
  }
 

	
 
  function fireDelayed() {
 
    --delayedCallbackDepth;
 
    var delayed = delayedCallbacks;
 
    delayedCallbacks = null;
 
    for (var i = 0; i < delayed.length; ++i) delayed[i]();
 
  }
 

	
 
  function hasHandler(emitter, type) {
 
    var arr = emitter._handlers && emitter._handlers[type];
 
    return arr && arr.length > 0;
 
  }
 

	
 
@@ -5137,25 +5233,29 @@ window.CodeMirror = (function() {
 
  function spaceStr(n) {
 
    while (spaceStrs.length <= n)
 
      spaceStrs.push(lst(spaceStrs) + " ");
 
    return spaceStrs[n];
 
  }
 

	
 
  function lst(arr) { return arr[arr.length-1]; }
 

	
 
  function selectInput(node) {
 
    if (ios) { // Mobile Safari apparently has a bug where select() is broken.
 
      node.selectionStart = 0;
 
      node.selectionEnd = node.value.length;
 
    } else node.select();
 
    } else {
 
      // Suppress mysterious IE10 errors
 
      try { node.select(); }
 
      catch(_e) {}
 
    }
 
  }
 

	
 
  function indexOf(collection, elt) {
 
    if (collection.indexOf) return collection.indexOf(elt);
 
    for (var i = 0, e = collection.length; i < e; ++i)
 
      if (collection[i] == elt) return i;
 
    return -1;
 
  }
 

	
 
  function createObj(base, props) {
 
    function Obj() {}
 
    Obj.prototype = base;
 
@@ -5171,25 +5271,25 @@ window.CodeMirror = (function() {
 
  }
 

	
 
  function emptyArray(size) {
 
    for (var a = [], i = 0; i < size; ++i) a.push(undefined);
 
    return a;
 
  }
 

	
 
  function bind(f) {
 
    var args = Array.prototype.slice.call(arguments, 1);
 
    return function(){return f.apply(null, args);};
 
  }
 

	
 
  var nonASCIISingleCaseWordChar = /[\u3040-\u309f\u30a0-\u30ff\u3400-\u4db5\u4e00-\u9fcc]/;
 
  var nonASCIISingleCaseWordChar = /[\u3040-\u309f\u30a0-\u30ff\u3400-\u4db5\u4e00-\u9fcc\uac00-\ud7af]/;
 
  function isWordChar(ch) {
 
    return /\w/.test(ch) || ch > "\x80" &&
 
      (ch.toUpperCase() != ch.toLowerCase() || nonASCIISingleCaseWordChar.test(ch));
 
  }
 

	
 
  function isEmpty(obj) {
 
    for (var n in obj) if (obj.hasOwnProperty(n) && obj[n]) return false;
 
    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\uA670-\uA672\uA674-\uA67D\uA69F\udc00-\udfff]/;
 

	
 
@@ -5232,31 +5332,42 @@ window.CodeMirror = (function() {
 
  var dragAndDrop = function() {
 
    // There is *some* kind of drag-and-drop support in IE6-8, but I
 
    // couldn't get it to work yet.
 
    if (ie_lt9) return false;
 
    var div = elt('div');
 
    return "draggable" in div || "dragDrop" in div;
 
  }();
 

	
 
  // For a reason I have yet to figure out, some browsers disallow
 
  // word wrapping between certain characters *only* if a new inline
 
  // element is started between them. This makes it hard to reliably
 
  // measure the position of things, since that requires inserting an
 
  // extra span. This terribly fragile set of regexps matches the
 
  // extra span. This terribly fragile set of tests matches the
 
  // character combinations that suffer from this phenomenon on the
 
  // various browsers.
 
  var spanAffectsWrapping = /^$/; // Won't match any two-character string
 
  if (gecko) spanAffectsWrapping = /$'/;
 
  else if (safari && !/Version\/([6-9]|\d\d)\b/.test(navigator.userAgent)) spanAffectsWrapping = /\-[^ \-?]|\?[^ !'\"\),.\-\/:;\?\]\}]/;
 
  else if (webkit) spanAffectsWrapping = /[~!#%&*)=+}\]|\"\.>,:;][({[<]|-[^\-?\.]|\?[\w~`@#$%\^&*(_=+{[|><]/;
 
  function spanAffectsWrapping() { return false; }
 
  if (gecko) // Only for "$'"
 
    spanAffectsWrapping = function(str, i) {
 
      return str.charCodeAt(i - 1) == 36 && str.charCodeAt(i) == 39;
 
    };
 
  else if (safari && !/Version\/([6-9]|\d\d)\b/.test(navigator.userAgent))
 
    spanAffectsWrapping = function(str, i) {
 
      return /\-[^ \-?]|\?[^ !\'\"\),.\-\/:;\?\]\}]/.test(str.slice(i - 1, i + 1));
 
    };
 
  else if (webkit)
 
    spanAffectsWrapping = function(str, i) {
 
      if (i > 1 && str.charCodeAt(i - 1) == 45 && /\w/.test(str.charAt(i - 2)) && /[^\-?\.]/.test(str.charAt(i)))
 
        return true;
 
      return /[~!#%&*)=+}\]|\"\.>,:;][({[<]|-[^\-?\.\u2010-\u201f\u2026]|\?[\w~`@#$%\^&*(_=+{[|><]|…[\w~`@#$%\^&*(_=+{[><]/.test(str.slice(i - 1, i + 1));
 
    };
 

	
 
  var knownScrollbarWidth;
 
  function scrollbarWidth(measure) {
 
    if (knownScrollbarWidth != null) return knownScrollbarWidth;
 
    var test = elt("div", null, null, "width: 50px; height: 50px; overflow-x: scroll");
 
    removeChildrenAndAdd(measure, test);
 
    if (test.offsetWidth)
 
      knownScrollbarWidth = test.offsetHeight - test.clientHeight;
 
    return knownScrollbarWidth || 0;
 
  }
 

	
 
  var zwspSupported;
 
@@ -5357,64 +5468,85 @@ window.CodeMirror = (function() {
 
    var ch = !order ? 0 : order[0].level % 2 ? lineRight(visual) : lineLeft(visual);
 
    return Pos(lineN, ch);
 
  }
 
  function lineEnd(cm, lineN) {
 
    var merged, line;
 
    while (merged = collapsedSpanAtEnd(line = getLine(cm.doc, lineN)))
 
      lineN = merged.find().to.line;
 
    var order = getOrder(line);
 
    var ch = !order ? line.text.length : order[0].level % 2 ? lineLeft(line) : lineRight(line);
 
    return Pos(lineN, ch);
 
  }
 

	
 
  function compareBidiLevel(order, a, b) {
 
    var linedir = order[0].level;
 
    if (a == linedir) return true;
 
    if (b == linedir) return false;
 
    return a < b;
 
  }
 
  var bidiOther;
 
  function getBidiPartAt(order, pos) {
 
    for (var i = 0, found; i < order.length; ++i) {
 
      var cur = order[i];
 
      if (cur.from < pos && cur.to > pos) { bidiOther = null; return i; }
 
      if (cur.from == pos || cur.to == pos) {
 
        if (found == null) {
 
          found = i;
 
        } else if (compareBidiLevel(order, cur.level, order[found].level)) {
 
          bidiOther = found;
 
          return i;
 
        } else {
 
          bidiOther = i;
 
          return found;
 
        }
 
      }
 
    }
 
    bidiOther = null;
 
    return found;
 
  }
 

	
 
  function moveInLine(line, pos, dir, byUnit) {
 
    if (!byUnit) return pos + dir;
 
    do pos += dir;
 
    while (pos > 0 && isExtendingChar.test(line.text.charAt(pos)));
 
    return pos;
 
  }
 

	
 
  // This is somewhat involved. It is needed in order to move
 
  // 'visually' through bi-directional text -- i.e., pressing left
 
  // should make the cursor go left, even when in RTL text. The
 
  // tricky part is the 'jumps', where RTL and LTR text touch each
 
  // other. This often requires the cursor offset to move more than
 
  // one unit, in order to visually move one unit.
 
  function moveVisually(line, start, dir, byUnit) {
 
    var bidi = getOrder(line);
 
    if (!bidi) return moveLogically(line, start, dir, byUnit);
 
    var moveOneUnit = byUnit ? function(pos, dir) {
 
      do pos += dir;
 
      while (pos > 0 && isExtendingChar.test(line.text.charAt(pos)));
 
      return pos;
 
    } : function(pos, dir) { return pos + dir; };
 
    var linedir = bidi[0].level;
 
    for (var i = 0; i < bidi.length; ++i) {
 
      var part = bidi[i], sticky = part.level % 2 == linedir;
 
      if ((part.from < start && part.to > start) ||
 
          (sticky && (part.from == start || part.to == start))) break;
 
    }
 
    var target = moveOneUnit(start, part.level % 2 ? -dir : dir);
 

	
 
    while (target != null) {
 
      if (part.level % 2 == linedir) {
 
        if (target < part.from || target > part.to) {
 
          part = bidi[i += dir];
 
          target = part && (dir > 0 == part.level % 2 ? moveOneUnit(part.to, -1) : moveOneUnit(part.from, 1));
 
        } else break;
 
    var pos = getBidiPartAt(bidi, start), part = bidi[pos];
 
    var target = moveInLine(line, start, part.level % 2 ? -dir : dir, byUnit);
 

	
 
    for (;;) {
 
      if (target > part.from && target < part.to) return target;
 
      if (target == part.from || target == part.to) {
 
        if (getBidiPartAt(bidi, target) == pos) return target;
 
        part = bidi[pos += dir];
 
        return (dir > 0) == part.level % 2 ? part.to : part.from;
 
      } else {
 
        if (target == bidiLeft(part)) {
 
          part = bidi[--i];
 
          target = part && bidiRight(part);
 
        } else if (target == bidiRight(part)) {
 
          part = bidi[++i];
 
          target = part && bidiLeft(part);
 
        } else break;
 
        part = bidi[pos += dir];
 
        if (!part) return null;
 
        if ((dir > 0) == part.level % 2)
 
          target = moveInLine(line, part.to, -1, byUnit);
 
        else
 
          target = moveInLine(line, part.from, 1, byUnit);
 
      }
 
    }
 

	
 
    return target < 0 || target > line.text.length ? null : target;
 
  }
 

	
 
  function moveLogically(line, start, dir, byUnit) {
 
    var target = start + dir;
 
    if (byUnit) while (target > 0 && isExtendingChar.test(line.text.charAt(target))) target += dir;
 
    return target < 0 || target > line.text.length ? null : target;
 
  }
 

	
 
  // Bidirectional ordering algorithm
 
  // See http://unicode.org/reports/tr9/tr9-13.html for the algorithm
 
  // that this (partially) implements.
 

	
 
@@ -5568,16 +5700,16 @@ window.CodeMirror = (function() {
 
        lst(order).to -= m[0].length;
 
        order.push({from: len - m[0].length, to: len, level: 0});
 
      }
 
      if (order[0].level != lst(order).level)
 
        order.push({from: len, to: len, level: order[0].level});
 

	
 
      return order;
 
    };
 
  })();
 

	
 
  // THE END
 

	
 
  CodeMirror.version = "3.12";
 
  CodeMirror.version = "3.14.0";
 

	
 
  return CodeMirror;
 
})();
rhodecode/public/js/mode/apl/index.html
Show inline comments
 
<!doctype html>
 
<html>
 
  <head>
 
    <meta charset="utf-8">
 
    <title>CodeMirror: APL mode</title>
 
    <link rel="stylesheet" href="../../doc/docs.css">
 
    <link rel="stylesheet" href="../../lib/codemirror.css">
 
    <script src="../../lib/codemirror.js"></script>
 
    <script src="../../addon/edit/matchbrackets.js"></script>
 
    <script src="apl.js"></script>
 
    <script src="./apl.js"></script>
 
    <style>
 
    .CodeMirror { border: 2px inset #dee; }
 
    </style>
 
  </head>
 
  <body>
 
    <h1>CodeMirror: APL mode</h1>
 

	
 
<form><textarea id="code" name="code">
 
⍝ Conway's game of life
 

	
 
⍝ This example was inspired by the impressive demo at
 
⍝ http://www.youtube.com/watch?v=a9xAKttWgP4
rhodecode/public/js/mode/meta.js
Show inline comments
 
@@ -7,24 +7,25 @@ CodeMirror.modeInfo = [
 
  {name: 'Java', mime: 'text/x-java', mode: 'clike'},
 
  {name: 'C#', mime: 'text/x-csharp', mode: 'clike'},
 
  {name: 'Scala', mime: 'text/x-scala', mode: 'clike'},
 
  {name: 'Clojure', mime: 'text/x-clojure', mode: 'clojure'},
 
  {name: 'CoffeeScript', mime: 'text/x-coffeescript', mode: 'coffeescript'},
 
  {name: 'Common Lisp', mime: 'text/x-common-lisp', mode: 'commonlisp'},
 
  {name: 'CSS', mime: 'text/css', mode: 'css'},
 
  {name: 'D', mime: 'text/x-d', mode: 'd'},
 
  {name: 'diff', mime: 'text/x-diff', mode: 'diff'},
 
  {name: 'ECL', mime: 'text/x-ecl', mode: 'ecl'},
 
  {name: 'Erlang', mime: 'text/x-erlang', mode: 'erlang'},
 
  {name: 'Gas', mime: 'text/x-gas', mode: 'gas'},
 
  {name: 'GitHub Flavored Markdown', mode: 'gfm'},
 
  {name: 'GO', mime: 'text/x-go', mode: 'go'},
 
  {name: 'Groovy', mime: 'text/x-groovy', mode: 'groovy'},
 
  {name: 'Haskell', mime: 'text/x-haskell', mode: 'haskell'},
 
  {name: 'Haxe', mime: 'text/x-haxe', mode: 'haxe'},
 
  {name: 'ASP.NET', mime: 'application/x-aspx', mode: 'htmlembedded'},
 
  {name: 'Embedded Javascript', mime: 'application/x-ejs', mode: 'htmlembedded'},
 
  {name: 'JavaServer Pages', mime: 'application/x-jsp', mode: 'htmlembedded'},
 
  {name: 'HTML', mime: 'text/html', mode: 'htmlmixed'},
 
  {name: 'HTTP', mime: 'message/http', mode: 'http'},
 
  {name: 'JavaScript', mime: 'text/javascript', mode: 'javascript'},
 
  {name: 'JSON', mime: 'application/x-json', mode: 'javascript'},
 
  {name: 'JSON', mime: 'application/json', mode: 'javascript'},
 
@@ -65,241 +66,12 @@ CodeMirror.modeInfo = [
 
  {name: 'TiddlyWiki ', mime: 'text/x-tiddlywiki', mode: 'tiddlywiki'},
 
  {name: 'Tiki wiki', mime: 'text/tiki', mode: 'tiki'},
 
  {name: 'VB.NET', mime: 'text/x-vb', mode: 'vb'},
 
  {name: 'VBScript', mime: 'text/vbscript', mode: 'vbscript'},
 
  {name: 'Velocity', mime: 'text/velocity', mode: 'velocity'},
 
  {name: 'Verilog', mime: 'text/x-verilog', mode: 'verilog'},
 
  {name: 'XML', mime: 'application/xml', mode: 'xml'},
 
  {name: 'HTML', mime: 'text/html', mode: 'xml'},
 
  {name: 'XQuery', mime: 'application/xquery', mode: 'xquery'},
 
  {name: 'YAML', mime: 'text/x-yaml', mode: 'yaml'},
 
  {name: 'Z80', mime: 'text/x-z80', mode: 'z80'}
 
];
 

	
 

	
 
MIME_TO_EXT = {
 
    'application/javascript': ['*.js'],
 
    'text/javascript': ['*.js'],
 
    'application/json': ['*.json'],
 
    'application/postscript': ['*.ps', '*.eps'],
 
    'application/x-actionscript': ['*.as'],
 
    'application/x-actionscript3': ['*.as'],
 
    'application/x-awk': ['*.awk'],
 
    'application/x-befunge': ['*.befunge'],
 
    'application/x-brainfuck': ['*.bf', '*.b'],
 
    'application/x-cheetah': ['*.tmpl', '*.spt'],
 
    'application/x-coldfusion': ['*.cfm', '*.cfml', '*.cfc'],
 
    'application/x-csh': ['*.tcsh', '*.csh'],
 
    'application/x-dos-batch': ['*.bat', '*.cmd'],
 
    'application/x-ecl': ['*.ecl'],
 
    'application/x-evoque': ['*.evoque'],
 
    'application/x-fantom': ['*.fan'],
 
    'application/x-genshi': ['*.kid'],
 
    'application/x-gettext': ['*.pot', '*.po'],
 
    'application/x-jsp': ['*.jsp'],
 
    'application/x-mako': ['*.mao'],
 
    'application/x-mason': ['*.m', '*.mhtml', '*.mc', '*.mi', 'autohandler', 'dhandler'],
 
    'application/x-myghty': ['*.myt', 'autodelegate'],
 
    'application/x-php': ['*.phtml'],
 
    'application/x-pypylog': ['*.pypylog'],
 
    'application/x-qml': ['*.qml'],
 
    'application/x-sh': ['*.sh', '*.ksh', '*.bash', '*.ebuild', '*.eclass', '.bashrc', 'bashrc', '.bash_*', 'bash_*'],
 
    'application/x-sh-session': ['*.shell-session'],
 
    'application/x-shell-session': ['*.sh-session'],
 
    'application/x-smarty': ['*.tpl'],
 
    'application/x-ssp': ['*.ssp'],
 
    'application/x-troff': ['*.[1234567]', '*.man'],
 
    'application/x-urbiscript': ['*.u'],
 
    'application/xml+evoque': ['*.xml'],
 
    'application/xml-dtd': ['*.dtd'],
 
    'application/xsl+xml': ['*.xsl', '*.xslt', '*.xpl'],
 
    'text/S-plus': ['*.S', '*.R', '.Rhistory', '.Rprofile'],
 
    'text/coffeescript': ['*.coffee'],
 
    'text/css': ['*.css'],
 
    'text/haxe': ['*.hx'],
 
    'text/html': ['*.html', '*.htm', '*.xhtml', '*.xslt'],
 
    'text/html+evoque': ['*.html'],
 
    'text/html+ruby': ['*.rhtml'],
 
    'text/idl': ['*.pro'],
 
    'text/livescript': ['*.ls'],
 
    'text/matlab': ['*.m'],
 
    'text/octave': ['*.m'],
 
    'text/plain': ['*.txt'],
 
    'text/scilab': ['*.sci', '*.sce', '*.tst'],
 
    'text/smali': ['*.smali'],
 
    'text/x-abap': ['*.abap'],
 
    'text/x-ada': ['*.adb', '*.ads', '*.ada'],
 
    'text/x-apacheconf': ['.htaccess', 'apache.conf', 'apache2.conf'],
 
    'text/x-aspectj': ['*.aj'],
 
    'text/x-asymptote': ['*.asy'],
 
    'text/x-autohotkey': ['*.ahk', '*.ahkl'],
 
    'text/x-autoit': ['*.au3'],
 
    'text/x-bmx': ['*.bmx'],
 
    'text/x-boo': ['*.boo'],
 
    'text/x-c++hdr': ['*.cpp', '*.hpp', '*.c++', '*.h++', '*.cc', '*.hh', '*.cxx', '*.hxx', '*.C', '*.H', '*.cp','*.CPP'],
 
    'text/x-c-objdump': ['*.c-objdump'],
 
    'text/x-ceylon': ['*.ceylon'],
 
    'text/x-chdr': ['*.c', '*.h', '*.idc'],
 
    'text/x-clojure': ['*.clj'],
 
    'text/x-cmake': ['*.cmake', 'CMakeLists.txt'],
 
    'text/x-cobol': ['*.cob', '*.COB', '*.cpy', '*.CPY'],
 
    'text/x-common-lisp': ['*.cl', '*.lisp', '*.el'],
 
    'text/x-coq': ['*.v'],
 
    'text/x-cpp-objdump': ['*.cpp-objdump', '*.c++-objdump', '*.cxx-objdump'],
 
    'text/x-crocsrc': ['*.croc'],
 
    'text/x-csharp': ['*.cs'],
 
    'text/x-cuda': ['*.cu', '*.cuh'],
 
    'text/x-cython': ['*.pyx', '*.pxd', '*.pxi'],
 
    'text/x-d-objdump': ['*.d-objdump'],
 
    'text/x-dart': ['*.dart'],
 
    'text/x-dg': ['*.dg'],
 
    'text/x-diff': ['*.diff', '*.patch'],
 
    'text/x-dsrc': ['*.d', '*.di'],
 
    'text/x-duel': ['*.duel', '*.jbst'],
 
    'text/x-dylan': ['*.dylan', '*.dyl', '*.intr'],
 
    'text/x-dylan-console': ['*.dylan-console'],
 
    'text/x-dylan-lid': ['*.lid', '*.hdp'],
 
    'text/x-echdr': ['*.ec', '*.eh'],
 
    'text/x-elixir': ['*.ex', '*.exs'],
 
    'text/x-erl-shellsession': ['*.erl-sh'],
 
    'text/x-erlang': ['*.erl', '*.hrl', '*.es', '*.escript'],
 
    'text/x-factor': ['*.factor'],
 
    'text/x-fancysrc': ['*.fy', '*.fancypack'],
 
    'text/x-felix': ['*.flx', '*.flxh'],
 
    'text/x-fortran': ['*.f', '*.f90', '*.F', '*.F90'],
 
    'text/x-fsharp': ['*.fs', '*.fsi'],
 
    'text/x-gas': ['*.s', '*.S'],
 
    'text/x-gherkin': ['*.feature'],
 
    'text/x-glslsrc': ['*.vert', '*.frag', '*.geo'],
 
    'text/x-gnuplot': ['*.plot', '*.plt'],
 
    'text/x-gooddata-cl': ['*.gdc'],
 
    'text/x-gooddata-maql': ['*.maql'],
 
    'text/x-gosrc': ['*.go'],
 
    'text/x-gosu': ['*.gs', '*.gsx', '*.gsp', '*.vark'],
 
    'text/x-gosu-template': ['*.gst'],
 
    'text/x-groovy': ['*.groovy'],
 
    'text/x-haml': ['*.haml'],
 
    'text/x-haskell': ['*.hs'],
 
    'text/x-hybris': ['*.hy', '*.hyb'],
 
    'text/x-ini': ['*.ini', '*.cfg'],
 
    'text/x-iokesrc': ['*.ik'],
 
    'text/x-iosrc': ['*.io'],
 
    'text/x-irclog': ['*.weechatlog'],
 
    'text/x-jade': ['*.jade'],
 
    'text/x-java': ['*.java'],
 
    'text/x-java-properties': ['*.properties'],
 
    'text/x-julia': ['*.jl'],
 
    'text/x-kconfig': ['Kconfig', '*Config.in*', 'external.in*', 'standard-modules.in'],
 
    'text/x-koka': ['*.kk', '*.kki'],
 
    'text/x-kotlin': ['*.kt'],
 
    'text/x-lasso': ['*.lasso', '*.lasso[89]'],
 
    'text/x-literate-haskell': ['*.lhs'],
 
    'text/x-llvm': ['*.ll'],
 
    'text/x-logos': ['*.x', '*.xi', '*.xm', '*.xmi'],
 
    'text/x-logtalk': ['*.lgt'],
 
    'text/x-lua': ['*.lua', '*.wlua'],
 
    'text/x-makefile': ['*.mak', 'Makefile', 'makefile', 'Makefile.*', 'GNUmakefile'],
 
    'text/x-minidsrc': ['*.md'],
 
    'text/x-markdown': ['*.md'],
 
    'text/x-modelica': ['*.mo'],
 
    'text/x-modula2': ['*.def', '*.mod'],
 
    'text/x-monkey': ['*.monkey'],
 
    'text/x-moocode': ['*.moo'],
 
    'text/x-moonscript': ['*.moon'],
 
    'text/x-nasm': ['*.asm', '*.ASM'],
 
    'text/x-nemerle': ['*.n'],
 
    'text/x-newlisp': ['*.lsp', '*.nl'],
 
    'text/x-newspeak': ['*.ns2'],
 
    'text/x-nimrod': ['*.nim', '*.nimrod'],
 
    'text/x-nsis': ['*.nsi', '*.nsh'],
 
    'text/x-objdump': ['*.objdump'],
 
    'text/x-objective-c': ['*.m', '*.h'],
 
    'text/x-objective-c++': ['*.mm', '*.hh'],
 
    'text/x-objective-j': ['*.j'],
 
    'text/x-ocaml': ['*.ml', '*.mli', '*.mll', '*.mly'],
 
    'text/x-ooc': ['*.ooc'],
 
    'text/x-opa': ['*.opa'],
 
    'text/x-openedge': ['*.p', '*.cls'],
 
    'text/x-pascal': ['*.pas'],
 
    'text/x-perl': ['*.pl', '*.pm'],
 
    'text/x-php': ['*.php', '*.php[345]', '*.inc'],
 
    'text/x-povray': ['*.pov', '*.inc'],
 
    'text/x-powershell': ['*.ps1'],
 
    'text/x-prolog': ['*.prolog', '*.pro', '*.pl'],
 
    'text/x-python': ['*.py', '*.pyw', '*.sc', 'SConstruct', 'SConscript', '*.tac', '*.sage'],
 
    'text/x-python-traceback': ['*.pytb'],
 
    'text/x-python3-traceback': ['*.py3tb'],
 
    'text/x-r-doc': ['*.Rd'],
 
    'text/x-racket': ['*.rkt', '*.rktl'],
 
    'text/x-rebol': ['*.r', '*.r3'],
 
    'text/x-robotframework': ['*.txt', '*.robot'],
 
    'text/x-rpm-spec': ['*.spec'],
 
    'text/x-rst': ['*.rst', '*.rest'],
 
    'text/x-ruby': ['*.rb', '*.rbw', 'Rakefile', '*.rake', '*.gemspec', '*.rbx', '*.duby'],
 
    'text/x-rustsrc': ['*.rs', '*.rc'],
 
    'text/x-sass': ['*.sass'],
 
    'text/x-scala': ['*.scala'],
 
    'text/x-scaml': ['*.scaml'],
 
    'text/x-scheme': ['*.scm', '*.ss'],
 
    'text/x-scss': ['*.scss'],
 
    'text/x-smalltalk': ['*.st'],
 
    'text/x-snobol': ['*.snobol'],
 
    'text/x-sourcepawn': ['*.sp'],
 
    'text/x-sql': ['*.sql'],
 
    'text/x-sqlite3-console': ['*.sqlite3-console'],
 
    'text/x-squidconf': ['squid.conf'],
 
    'text/x-standardml': ['*.sml', '*.sig', '*.fun'],
 
    'text/x-systemverilog': ['*.sv', '*.svh'],
 
    'text/x-tcl': ['*.tcl'],
 
    'text/x-tea': ['*.tea'],
 
    'text/x-tex': ['*.tex', '*.aux', '*.toc'],
 
    'text/x-typescript': ['*.ts'],
 
    'text/x-vala': ['*.vala', '*.vapi'],
 
    'text/x-vbnet': ['*.vb', '*.bas'],
 
    'text/x-verilog': ['*.v'],
 
    'text/x-vhdl': ['*.vhdl', '*.vhd'],
 
    'text/x-vim': ['*.vim', '.vimrc', '.exrc', '.gvimrc', '_vimrc', '_exrc', '_gvimrc', 'vimrc', 'gvimrc'],
 
    'text/x-windows-registry': ['*.reg'],
 
    'text/x-xtend': ['*.xtend'],
 
    'text/x-yaml': ['*.yaml', '*.yml'],
 
    'text/xml': ['*.xml', '*.xsl', '*.rss', '*.xslt', '*.xsd', '*.wsdl'],
 
    'text/xquery': ['*.xqy', '*.xquery', '*.xq', '*.xql', '*.xqm'],
 
    'text/apl': [],
 
    'text/x-asterisk': [],
 
    'text/x-csrc': [],
 
    'text/x-c++src': ['*.cpp'],
 
    'text/x-coffeescript': ['*.coffee'],
 
    'text/x-d': ["*.d"],
 
    'text/x-ecl': ['*.ecl'],
 
    'text/x-go': ['*.go'],
 
    'text/x-haxe': ['*.hx'],
 
    'application/x-aspx': ['*.aspx'],
 
    'application/x-ejs': [],
 
    'message/http': [],
 
    'application/x-json': ['*.json'],
 
    'application/typescript': ['*.ts'],
 
    'jinja2': ['.jinja2'],
 
    'text/x-less': ['*.less'],
 
    'text/x-livescript': ['*.ls'],
 
    'text/mirc': [],
 
    'text/n-triples': [],
 
    'application/x-httpd-php': ['*.php'],
 
    'text/x-pig': [],
 
    'text/x-properties': ['*.properties'],
 
    'text/x-rsrc': [],
 
    'text/x-sh': ['*.sh', '*.ksh', '*.bash', '*.ebuild', '*.eclass', '.bashrc', 'bashrc', '.bash_*', 'bash_*'],
 
    'application/sieve': [],
 
    'text/x-stsrc': ['*.rs', '*.rc'],
 
    'text/x-smarty': ['*.tpl'],
 
    'application/x-sparql-query': [],
 
    'text/x-mariadb': ['*.sql'],
 
    'text/x-stex': [],
 
    'text/x-latex': ["*.ltx"],
 
    'text/x-tiddlywiki': [],
 
    'text/tiki': [],
 
    'text/x-vb': ['*.vb'],
 
    'text/vbscript': ['*.vb'],
 
    'text/velocity': [],
 
    'application/xml': ['*.xml', '*.xsl', '*.rss', '*.xslt', '*.xsd', '*.wsdl'],
 
    'application/xquery': ['*.xqy', '*.xquery', '*.xq', '*.xql', '*.xqm'],
 
    'text/x-z80': [],
 
}
rhodecode/public/js/mode/php/index.html
Show inline comments
 
@@ -34,18 +34,18 @@ function hello($who) {
 
      var editor = CodeMirror.fromTextArea(document.getElementById("code"), {
 
        lineNumbers: true,
 
        matchBrackets: true,
 
        mode: "application/x-httpd-php",
 
        indentUnit: 4,
 
        indentWithTabs: true,
 
        enterMode: "keep",
 
        tabMode: "shift"
 
      });
 
    </script>
 

	
 
    <p>Simple HTML/PHP mode based on
 
    the <a href="../clike">C-like</a> mode. Depends on XML,
 
    the <a href="../clike/">C-like</a> mode. Depends on XML,
 
    JavaScript, CSS, HTMLMixed, and C-like modes.</p>
 

	
 
    <p><strong>MIME types defined:</strong> <code>application/x-httpd-php</code> (HTML with PHP code), <code>text/x-php</code> (plain, non-wrapped PHP code).</p>
 
  </body>
 
</html>
0 comments (0 inline, 0 general)