Changeset - bb9ef0638069
[Not reviewed]
Bradley M. Kuhn - 12 years ago 2014-05-16 21:54:24
bkuhn@sfconservancy.org
Update CodeMirror CSS and Javascript files to version 3.15, under MIT-permissive license.

These files are exactly as they appear the upstream release 3.15 of
Codemirror, which was released under an MIT-permissive license. To extract
these files, I did the following:

I downloaded the following file:
http://codemirror.net/codemirror-3.15.zip
with sha256sum of:
$ sha256sum codemirror-3.15.zip
8cf3a512899852fd4e3833423ea98d34918cbf7ee0e4e0b13f8b5e7b083f21b9 codemirror-3.15.zip

And extracted from it the Javascript and CSS files herein committed, which
are licensed under the MIT-permissive license, placing them into their
locations in: rhodecode/public/{css,js}/

Using the procedure above, the only difference found between these files in
RhodeCode 2.2.5 release and herein were a few comments and whitespace.

Note that the file .../public/js/mode/meta_ext.js does *not* appear to be
part of CodeMirror and therefore is not included in this commit.
31 files changed with 1561 insertions and 215 deletions:
0 comments (0 inline, 0 general)
rhodecode/public/css/codemirror.css
Show inline comments
 
@@ -99,150 +99,160 @@ div.CodeMirror span.CodeMirror-nonmatchi
 
/* STOP */
 

	
 
/* The rest of this file contains styles related to the mechanics of
 
   the editor. You probably shouldn't touch them. */
 

	
 
.CodeMirror {
 
  line-height: 1;
 
  position: relative;
 
  overflow: hidden;
 
  background: white;
 
  color: black;
 
}
 

	
 
.CodeMirror-scroll {
 
  /* 30px is the magic margin used to hide the element's real scrollbars */
 
  /* See overflow: hidden in .CodeMirror */
 
  margin-bottom: -30px; margin-right: -30px;
 
  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-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;
 
}
 
.CodeMirror-gutter-filler {
 
  left: 0; bottom: 0;
 
}
 

	
 
.CodeMirror-gutters {
 
  position: absolute; left: 0; top: 0;
 
  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;
 
}
 

	
 
.CodeMirror-lines {
 
  cursor: text;
 
}
 
.CodeMirror pre {
 
  /* Reset some styles that the rest of the page might have set */
 
  -moz-border-radius: 0; -webkit-border-radius: 0; border-radius: 0;
 
  border-width: 0;
 
  background: transparent;
 
  font-family: inherit;
 
  font-size: inherit;
 
  margin: 0;
 
  white-space: pre;
 
  word-wrap: normal;
 
  line-height: inherit;
 
  color: inherit;
 
  z-index: 2;
 
  position: relative;
 
  overflow: visible;
 
}
 
.CodeMirror-wrap pre {
 
  word-wrap: break-word;
 
  white-space: pre-wrap;
 
  word-break: normal;
 
}
 
.CodeMirror-code pre {
 
  border-right: 30px solid transparent;
 
  width: -webkit-fit-content;
 
  width: -moz-fit-content;
 
  width: fit-content;
 
}
 
.CodeMirror-wrap .CodeMirror-code pre {
 
  border-right: none;
 
  width: auto;
 
}
 
.CodeMirror-linebackground {
 
  position: absolute;
 
  left: 0; right: 0; top: 0; bottom: 0;
 
  z-index: 0;
 
}
 

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

	
 
.CodeMirror-widget {
 
}
 

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

	
 
.CodeMirror-measure {
 
  position: absolute;
 
  width: 100%; height: 0px;
 
  overflow: hidden;
 
  visibility: hidden;
 
}
 
.CodeMirror-measure pre { position: static; }
 

	
 
.CodeMirror div.CodeMirror-cursor {
 
  position: absolute;
 
  visibility: hidden;
 
  border-right: none;
 
  width: 0;
 
}
 
.CodeMirror-focused div.CodeMirror-cursor {
 
  visibility: visible;
 
}
 

	
 
.CodeMirror-selected { background: #d9d9d9; }
 
.CodeMirror-focused .CodeMirror-selected { background: #d7d4f0; }
 

	
 
.cm-searching {
 
  background: #ffa;
 
  background: rgba(255, 255, 0, .4);
 
}
 

	
 
/* IE7 hack to prevent it from returning funny offsetTops on the spans */
 
.CodeMirror span { *vertical-align: text-bottom; }
 

	
 
@media print {
 
  /* Hide the cursor when printing */
 
  .CodeMirror div.CodeMirror-cursor {
 
    visibility: hidden;
 
  }
 
}
rhodecode/public/js/codemirror.js
Show inline comments
 
// CodeMirror version 3.14
 
// CodeMirror version 3.15
 
//
 
// 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);
 
  var webkit = /WebKit\//.test(navigator.userAgent);
 
  var qtwebkit = webkit && /Qt\/\d+\.\d+/.test(navigator.userAgent);
 
  var chrome = /Chrome\//.test(navigator.userAgent);
 
  var opera = /Opera\//.test(navigator.userAgent);
 
  var safari = /Apple Computer/.test(navigator.vendor);
 
  var khtml = /KHTML\//.test(navigator.userAgent);
 
  var mac_geLion = /Mac OS X 1\d\D([7-9]|\d\d)\D/.test(navigator.userAgent);
 
  var mac_geMountainLion = /Mac OS X 1\d\D([8-9]|\d\d)\D/.test(navigator.userAgent);
 
  var phantom = /PhantomJS/.test(navigator.userAgent);
 

	
 
  var ios = /AppleWebKit/.test(navigator.userAgent) && /Mobile\/\w+/.test(navigator.userAgent);
 
  // This is woefully incomplete. Suggestions for alternative methods welcome.
 
  var mobile = ios || /Android|webOS|BlackBerry|Opera Mini|Opera Mobi|IEMobile/i.test(navigator.userAgent);
 
  var mac = ios || /Mac/.test(navigator.platform);
 
  var windows = /windows/i.test(navigator.platform);
 

	
 
  var opera_version = opera && navigator.userAgent.match(/Version\/(\d*\.\d*)/);
 
  if (opera_version) opera_version = Number(opera_version[1]);
 
  if (opera_version && opera_version >= 15) { opera = false; webkit = true; }
 
  // Some browsers use the wrong event properties to signal cmd/ctrl on OS X
 
  var flipCtrlCmd = mac && (qtwebkit || opera && (opera_version == null || opera_version < 12.11));
 
  var captureMiddleClick = gecko || (ie && !ie_lt9);
 

	
 
  // Optimize some code when these features are not used
 
  var sawReadOnlySpans = false, sawCollapsedSpans = false;
 

	
 
  // CONSTRUCTOR
 

	
 
  function CodeMirror(place, options) {
 
    if (!(this instanceof CodeMirror)) return new CodeMirror(place, options);
 

	
 
    this.options = options = options || {};
 
    // Determine effective options based on given values and defaults.
 
    for (var opt in defaults) if (!options.hasOwnProperty(opt) && defaults.hasOwnProperty(opt))
 
      options[opt] = defaults[opt];
 
    setGuttersForLineNumbers(options);
 

	
 
    var docStart = typeof options.value == "string" ? 0 : options.value.first;
 
    var display = this.display = makeDisplay(place, docStart);
 
    display.wrapper.CodeMirror = this;
 
    updateGutters(this);
 
    if (options.autofocus && !mobile) focusInput(this);
 

	
 
    this.state = {keyMaps: [],
 
                  overlays: [],
 
                  modeGen: 0,
 
                  overwrite: false, focused: false,
 
                  suppressEdits: false, pasteIncoming: false,
 
                  draggingText: false,
 
                  highlight: new Delayed()};
 

	
 
    themeChanged(this);
 
    if (options.lineWrapping)
 
      this.display.wrapper.className += " CodeMirror-wrap";
 

	
 
    var doc = options.value;
 
    if (typeof doc == "string") doc = new Doc(options.value, options.mode);
 
    operation(this, attachDoc)(this, doc);
 

	
 
    // Override magic textarea content restore that IE sometimes does
 
    // on our hidden textarea on reload
 
    if (ie) setTimeout(bind(resetInput, this, true), 20);
 

	
 
    registerEventHandlers(this);
 
    // IE throws unspecified error in certain cases, when
 
    // trying to access activeElement before onload
 
    var hasFocus; try { hasFocus = (document.activeElement == display.input); } catch(e) { }
 
    if (hasFocus || (options.autofocus && !mobile)) setTimeout(bind(onFocus, this), 20);
 
    else onBlur(this);
 

	
 
    operation(this, function() {
 
      for (var opt in optionHandlers)
 
        if (optionHandlers.propertyIsEnumerable(opt))
 
          optionHandlers[opt](this, options[opt], Init);
 
      for (var i = 0; i < initHooks.length; ++i) initHooks[i](this);
 
    })();
 
  }
 

	
 
  // 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("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", 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;");
 
@@ -310,463 +311,469 @@ window.CodeMirror = (function() {
 
      if (options.gutters[i] == "CodeMirror-linenumbers") {
 
        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(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 + 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)};
 
  }
 

	
 
  // LINE NUMBERS
 

	
 
  function alignHorizontally(cm) {
 
    var display = cm.display;
 
    if (!display.alignWidgets && (!display.gutters.firstChild || !cm.options.fixedGutter)) return;
 
    var comp = compensateForHScroll(display) - display.scroller.scrollLeft + cm.doc.scrollLeft;
 
    var gutterW = display.gutters.offsetWidth, l = comp + "px";
 
    for (var n = display.lineDiv.firstChild; n; n = n.nextSibling) if (n.alignable) {
 
      for (var i = 0, a = n.alignable; i < a.length; ++i) a[i].style.left = l;
 
    }
 
    if (cm.options.fixedGutter)
 
      display.gutters.style.left = (comp + gutterW) + "px";
 
  }
 

	
 
  function maybeUpdateLineNumberWidth(cm) {
 
    if (!cm.options.lineNumbers) return false;
 
    var doc = cm.doc, last = lineNumberFor(cm.options, doc.first + doc.size - 1), display = cm.display;
 
    if (last.length != display.lineNumChars) {
 
      var test = display.measure.appendChild(elt("div", [elt("div", last)],
 
                                                 "CodeMirror-linenumber CodeMirror-gutter-elt"));
 
      var innerW = test.firstChild.offsetWidth, padding = test.offsetWidth - innerW;
 
      display.lineGutter.style.width = "";
 
      display.lineNumInnerWidth = Math.max(innerW, display.lineGutter.offsetWidth - padding);
 
      display.lineNumWidth = display.lineNumInnerWidth + padding;
 
      display.lineNumChars = display.lineNumInnerWidth ? last.length : -1;
 
      display.lineGutter.style.width = display.lineNumWidth + "px";
 
      return true;
 
    }
 
    return false;
 
  }
 

	
 
  function lineNumberFor(options, i) {
 
    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) {
 
  function updateDisplay(cm, changes, viewPort, forced) {
 
    var oldFrom = cm.display.showingFrom, oldTo = cm.display.showingTo, updated;
 
    var visible = visibleLines(cm.display, cm.doc, viewPort);
 
    for (;;) {
 
      if (!updateDisplayInner(cm, changes, visible)) break;
 
      if (!updateDisplayInner(cm, changes, visible, forced)) break;
 
      forced = false;
 
      updated = true;
 
      updateSelection(cm);
 
      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) {
 
  function updateDisplayInner(cm, changes, visible, forced) {
 
    var display = cm.display, doc = cm.doc;
 
    if (!display.wrapper.clientWidth) {
 
      display.showingFrom = display.showingTo = doc.first;
 
      display.viewOffset = 0;
 
      return;
 
    }
 

	
 
    // Bail out if the visible area is already rendered and nothing changed.
 
    if (changes.length == 0 &&
 
    if (!forced && changes.length == 0 &&
 
        visible.from > display.showingFrom && visible.to < display.showingTo)
 
      return;
 

	
 
    if (maybeUpdateLineNumberWidth(cm))
 
      changes = [{from: doc.first, to: doc.first + doc.size}];
 
    var gutterW = display.sizer.style.marginLeft = display.gutters.offsetWidth + "px";
 
    display.scrollbarH.style.left = cm.options.fixedGutter ? gutterW : "0";
 

	
 
    // Used to determine which lines need their line numbers updated
 
    var positionsChangedFrom = Infinity;
 
    if (cm.options.lineNumbers)
 
      for (var i = 0; i < changes.length; ++i)
 
        if (changes[i].diff) { positionsChangedFrom = changes[i].from; break; }
 

	
 
    var end = doc.first + doc.size;
 
    var from = Math.max(visible.from - cm.options.viewportMargin, doc.first);
 
    var to = Math.min(end, visible.to + cm.options.viewportMargin);
 
    if (display.showingFrom < from && from - display.showingFrom < 20) from = Math.max(doc.first, display.showingFrom);
 
    if (display.showingTo > to && display.showingTo - to < 20) to = Math.min(end, display.showingTo);
 
    if (sawCollapsedSpans) {
 
      from = lineNo(visualLine(doc, getLine(doc, from)));
 
      while (to < end && lineIsHidden(doc, getLine(doc, to))) ++to;
 
    }
 

	
 
    // Create a range of theoretically intact lines, and punch holes
 
    // in that using the change info.
 
    var intact = [{from: Math.max(display.showingFrom, doc.first),
 
                   to: Math.min(display.showingTo, end)}];
 
    if (intact[0].from >= intact[0].to) intact = [];
 
    else intact = computeIntact(intact, changes);
 
    // When merged lines are present, we might have to reduce the
 
    // intact ranges because changes in continued fragments of the
 
    // intact lines do require the lines to be redrawn.
 
    if (sawCollapsedSpans)
 
      for (var i = 0; i < intact.length; ++i) {
 
        var range = intact[i], merged;
 
        while (merged = collapsedSpanAtEnd(getLine(doc, range.to - 1))) {
 
          var newTo = merged.find().from.line;
 
          if (newTo > range.from) range.to = newTo;
 
          else { intact.splice(i--, 1); break; }
 
        }
 
      }
 

	
 
    // Clip off the parts that won't be visible
 
    var intactLines = 0;
 
    for (var i = 0; i < intact.length; ++i) {
 
      var range = intact[i];
 
      if (range.from < from) range.from = from;
 
      if (range.to > to) range.to = to;
 
      if (range.from >= range.to) intact.splice(i--, 1);
 
      else intactLines += range.to - range.from;
 
    }
 
    if (intactLines == to - from && from == display.showingFrom && to == display.showingTo) {
 
    if (!forced && intactLines == to - from && from == display.showingFrom && to == display.showingTo) {
 
      updateViewOffset(cm);
 
      return;
 
    }
 
    intact.sort(function(a, b) {return a.from - b.from;});
 

	
 
    // Avoid crashing on IE's "unspecified error" when in iframes
 
    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;
 
      startWorker(cm, 400);
 
    }
 
    display.showingFrom = from; display.showingTo = to;
 

	
 
    updateHeightsInViewport(cm);
 
    updateViewOffset(cm);
 

	
 
    return true;
 
  }
 

	
 
  function updateHeightsInViewport(cm) {
 
    var display = cm.display;
 
    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;
 
      if (height < 2) height = textHeight(display);
 
      if (diff > .001 || diff < -.001) {
 
        updateLineHeight(node.lineObj, height);
 
        var widgets = node.lineObj.widgets;
 
        if (widgets) for (var i = 0; i < widgets.length; ++i)
 
          widgets[i].height = widgets[i].node.offsetHeight;
 
      }
 
    }
 
    updateViewOffset(cm);
 

	
 
    return true;
 
  }
 

	
 
  function updateViewOffset(cm) {
 
    var off = cm.display.viewOffset = heightAtLine(cm, getLine(cm.doc, cm.display.showingFrom));
 
    // Position the mover div to align with the current virtual scroll position
 
    cm.display.mover.style.top = off + "px";
 
  }
 

	
 
  function computeIntact(intact, changes) {
 
    for (var i = 0, l = changes.length || 0; i < l; ++i) {
 
      var change = changes[i], intact2 = [], diff = change.diff || 0;
 
      for (var j = 0, l2 = intact.length; j < l2; ++j) {
 
        var range = intact[j];
 
        if (change.to <= range.from && change.diff) {
 
          intact2.push({from: range.from + diff, to: range.to + diff});
 
        } else if (change.to <= range.from || change.from >= range.to) {
 
          intact2.push(range);
 
        } else {
 
          if (change.from > range.from)
 
            intact2.push({from: range.from, to: change.from});
 
          if (change.to < range.to)
 
            intact2.push({from: change.to + diff, to: range.to + diff});
 
        }
 
      }
 
      intact = intact2;
 
    }
 
    return intact;
 
  }
 

	
 
  function getDimensions(cm) {
 
    var d = cm.display, left = {}, width = {};
 
    for (var n = d.gutters.firstChild, i = 0; n; n = n.nextSibling, ++i) {
 
      left[cm.options.gutters[i]] = n.offsetLeft;
 
      width[cm.options.gutters[i]] = n.offsetWidth;
 
    }
 
    return {fixedPos: compensateForHScroll(d),
 
            gutterTotalWidth: d.gutters.offsetWidth,
 
            gutterLeft: left,
 
            gutterWidth: width,
 
            wrapperWidth: d.wrapper.clientWidth};
 
  }
 

	
 
  function patchDisplay(cm, from, to, intact, updateNumbersFrom) {
 
    var dims = getDimensions(cm);
 
    var display = cm.display, lineNumbers = cm.options.lineNumbers;
 
    if (!intact.length && (!webkit || !cm.display.currentWheelTarget))
 
      removeChildren(display.lineDiv);
 
    var container = display.lineDiv, cur = container.firstChild;
 

	
 
    function rm(node) {
 
      var next = node.nextSibling;
 
      if (webkit && mac && cm.display.currentWheelTarget == node) {
 
        node.style.display = "none";
 
        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) {
 
          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", [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)
 
          if (search.lineObj == line && /div/i.test(search.nodeName)) { reuse = search; break; }
 
        // This line needs to be generated.
 
        var lineNode = buildLineElement(cm, line, lineN, dims, reuse);
 
        if (lineNode != reuse) {
 
          container.insertBefore(lineNode, cur);
 
        } else {
 
          while (cur != reuse) cur = rm(cur);
 
          cur = cur.nextSibling;
 
        }
 

	
 
        lineNode.lineObj = line;
 
      }
 
      ++lineN;
 
    });
 
    while (cur) cur = rm(cur);
 
  }
 

	
 
  function buildLineElement(cm, line, lineNo, dims, reuse) {
 
    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, 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) {
 
          for (var i = 0; i < line.widgets.length; ++i) {
 
            var widget = line.widgets[i];
 
            if (!widget.above) { insertBefore = n; first = false; }
 
            if (widget.node == n.firstChild) {
 
              if (!widget.above && !insertBefore) insertBefore = n;
 
              positionLineWidget(widget, n, reuse, dims);
 
              ++widgetsSeen;
 
              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);
 
    if (cm.options.lineNumbers || markers) {
 
      var gutterWrap = wrap.insertBefore(elt("div", null, null, "position: absolute; left: " +
 
                                             (cm.options.fixedGutter ? dims.fixedPos : -dims.gutterTotalWidth) + "px"),
 
                                         wrap.firstChild);
 
      if (cm.options.fixedGutter) (wrap.alignable || (wrap.alignable = [])).push(gutterWrap);
 
      if (cm.options.lineNumbers && (!markers || !markers["CodeMirror-linenumbers"]))
 
        wrap.lineNumber = gutterWrap.appendChild(
 
          elt("div", lineNumberFor(cm.options, lineNo),
 
              "CodeMirror-linenumber CodeMirror-gutter-elt",
 
              "left: " + dims.gutterLeft["CodeMirror-linenumbers"] + "px; width: "
 
              + 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) {
 
      (wrap.alignable || (wrap.alignable = [])).push(node);
 
      var width = dims.wrapperWidth;
 
      node.style.left = dims.fixedPos + "px";
 
      if (!widget.coverGutter) {
 
        width -= dims.gutterTotalWidth;
 
        node.style.paddingLeft = dims.gutterTotalWidth + "px";
 
      }
 
      node.style.width = width + "px";
 
    }
 
    if (widget.coverGutter) {
 
      node.style.zIndex = 5;
 
      node.style.position = "relative";
 
      if (!widget.noHScroll) node.style.marginLeft = -dims.gutterTotalWidth + "px";
 
    }
 
  }
 

	
 
  // SELECTION / CURSOR
 

	
 
  function updateSelection(cm) {
 
    var display = cm.display;
 
    var collapsed = posEq(cm.doc.sel.from, cm.doc.sel.to);
 
    if (collapsed || cm.options.showCursorWhenSelecting)
 
      updateSelectionCursor(cm);
 
    else
 
      display.cursor.style.display = display.otherCursor.style.display = "none";
 
    if (!collapsed)
 
      updateSelectionRange(cm);
 
    else
 
      display.selectionDiv.style.display = "none";
 

	
 
    // Move the hidden textarea near the cursor to prevent scrolling artifacts
 
    if (cm.options.moveInputWithCursor) {
 
      var headPos = cursorCoords(cm, cm.doc.sel.head, "div");
 
      var wrapOff = getRect(display.wrapper), lineOff = getRect(display.lineDiv);
 
      display.inputDiv.style.top = Math.max(0, Math.min(display.wrapper.clientHeight - 10,
 
                                                        headPos.top + lineOff.top - wrapOff.top)) + "px";
 
      display.inputDiv.style.left = Math.max(0, Math.min(display.wrapper.clientWidth - 10,
 
                                                         headPos.left + lineOff.left - wrapOff.left)) + "px";
 
    }
 
  }
 
@@ -873,325 +880,329 @@ window.CodeMirror = (function() {
 

	
 
  // HIGHLIGHT WORKER
 

	
 
  function startWorker(cm, time) {
 
    if (cm.doc.mode.startState && cm.doc.frontier < cm.display.showingTo)
 
      cm.state.highlight.set(time, bind(highlightWorker, cm));
 
  }
 

	
 
  function highlightWorker(cm) {
 
    var doc = cm.doc;
 
    if (doc.frontier < doc.first) doc.frontier = doc.first;
 
    if (doc.frontier >= cm.display.showingTo) return;
 
    var end = +new Date + cm.options.workTime;
 
    var state = copyState(doc.mode, getStateBefore(cm, doc.frontier));
 
    var changed = [], prevChange;
 
    doc.iter(doc.frontier, Math.min(doc.first + doc.size, cm.display.showingTo + 500), function(line) {
 
      if (doc.frontier >= cm.display.showingFrom) { // Visible
 
        var oldStyles = line.styles;
 
        line.styles = highlightLine(cm, line, state);
 
        var ischange = !oldStyles || oldStyles.length != line.styles.length;
 
        for (var i = 0; !ischange && i < oldStyles.length; ++i) ischange = oldStyles[i] != line.styles[i];
 
        if (ischange) {
 
          if (prevChange && prevChange.end == doc.frontier) prevChange.end++;
 
          else changed.push(prevChange = {start: doc.frontier, end: doc.frontier + 1});
 
        }
 
        line.stateAfter = copyState(doc.mode, state);
 
      } else {
 
        processLine(cm, line, state);
 
        line.stateAfter = doc.frontier % 5 == 0 ? copyState(doc.mode, state) : null;
 
      }
 
      ++doc.frontier;
 
      if (+new Date > end) {
 
        startWorker(cm, cm.options.workDelay);
 
        return true;
 
      }
 
    });
 
    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, 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 && (!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, precise) {
 
    var doc = cm.doc, display = cm.display;
 
      if (!doc.mode.startState) return true;
 
    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, 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;
 
    bias = pos > ch ? "left" : pos < ch ? "right" : bias;
 
    if (bias == "left" && r.leftSide) r = r.leftSide;
 
    else if (bias == "right" && r.rightSide) r = r.rightSide;
 
    return {left: pos < ch ? r.right : r.left,
 
            right: pos > ch ? r.left : r.right,
 
            top: rightV ? r.topRight : r.top,
 
            bottom: rightV ? r.bottomRight : r.bottom};
 
            top: r.top,
 
            bottom: 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;
 
    }
 
  }
 

	
 
  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 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);
 
    var pre = lineContent(cm, line, measure, true);
 

	
 
    // 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
 
    // by first subdividing the line into a bunch of inline blocks, so
 
    // that IE can reuse most of the layout information from caches
 
    // for those blocks. This does interfere with line wrapping, so it
 
    // doesn't work when wrapping is on, but in that case the
 
    // situation is slightly better, since IE does cache line-wrapping
 
    // information and only recomputes per-line.
 
    if (ie && !ie_lt8 && !cm.options.lineWrapping && pre.childNodes.length > 100) {
 
      var fragment = document.createDocumentFragment();
 
      var chunk = 10, n = pre.childNodes.length;
 
      for (var i = 0, chunks = Math.ceil(n / chunk); i < chunks; ++i) {
 
        var wrap = elt("div", null, null, "display: inline-block");
 
        for (var j = 0; j < chunk && n; ++j) {
 
          wrap.appendChild(pre.firstChild);
 
          --n;
 
        }
 
        fragment.appendChild(wrap);
 
      }
 
      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);
 

	
 
    function categorizeVSpan(top, bot) {
 
    function measureRect(rect) {
 
      var top = rect.top - outer.top, bot = rect.bottom - outer.top;
 
      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];
 
      for (var i = vranges.length - 2; i >= 0; i -= 2) {
 
        var rtop = vranges[i], rbot = vranges[i+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);
 
          return j;
 
          vranges[i] = Math.min(top, rtop);
 
          vranges[i+1] = Math.max(bot, rbot);
 
          break;
 
        }
 
      }
 
      vranges.push(top, bot);
 
      return j;
 
      if (i < 0) { i = vranges.length; vranges.push(top, bot); }
 
      return {left: rect.left - outer.left,
 
              right: rect.right - outer.left,
 
              top: i, bottom: null};
 
    }
 
    function finishRect(rect) {
 
      rect.bottom = vranges[rect.top+1];
 
      rect.top = vranges[rect.top];
 
    }
 

	
 
    for (var i = 0, cur; i < measure.length; ++i) if (cur = measure[i]) {
 
      var size, node = cur;
 
      var node = cur, rect = null;
 
      // 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];
 
        var rects = node.getClientRects();
 
        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;
 
          rect = data[i] = measureRect(rects[0]);
 
          rect.rightSide = measureRect(rects[rects.length - 1]);
 
        }
 
      }
 
      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: vCat};
 
      if (!rect) rect = data[i] = measureRect(getRect(node));
 
      if (cur.measureRight) rect.right = getRect(cur.measureRight).left;
 
      if (cur.leftSide) rect.leftSide = measureRect(getRect(cur.leftSide));
 
    }
 
    for (var i = 0, cur; i < data.length; ++i) if (cur = data[i]) {
 
      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]; }
 
      finishRect(cur);
 
      if (cur.leftSide) finishRect(cur.leftSide);
 
      if (cur.rightSide) finishRect(cur.rightSide);
 
    }
 
    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.measure, "right").right;
 

	
 
    var pre = lineContent(cm, line);
 
    var pre = lineContent(cm, line, null, true);
 
    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 += paddingTop(cm.display);
 
    else yOff -= cm.display.viewOffset;
 
    if (context == "page" || context == "window") {
 
      var lOff = getRect(cm.display.lineSpace);
 
      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 -= 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);
 
    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, 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, 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 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;
 
  }
 
@@ -1209,226 +1220,227 @@ window.CodeMirror = (function() {
 
    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 || 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) {
 
      var sp = cursorCoords(cm, Pos(lineNo, ch), "line",
 
                            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 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 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 = 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;}
 
    }
 
  }
 

	
 
  var measureText;
 
  function textHeight(display) {
 
    if (display.cachedTextHeight != null) return display.cachedTextHeight;
 
    if (measureText == null) {
 
      measureText = elt("pre");
 
      // Measure a bunch of lines, for browsers that compute
 
      // fractional heights.
 
      for (var i = 0; i < 49; ++i) {
 
        measureText.appendChild(document.createTextNode("x"));
 
        measureText.appendChild(elt("br"));
 
      }
 
      measureText.appendChild(document.createTextNode("x"));
 
    }
 
    removeChildrenAndAdd(display.measure, measureText);
 
    var height = measureText.offsetHeight / 50;
 
    if (height > 3) display.cachedTextHeight = height;
 
    removeChildren(display.measure);
 
    return height || 1;
 
  }
 

	
 
  function charWidth(display) {
 
    if (display.cachedCharWidth != null) return display.cachedCharWidth;
 
    var anchor = elt("span", "x");
 
    var pre = elt("pre", [anchor]);
 
    removeChildrenAndAdd(display.measure, pre);
 
    var width = anchor.offsetWidth;
 
    if (width > 2) display.cachedCharWidth = width;
 
    return width || 10;
 
  }
 

	
 
  // OPERATIONS
 

	
 
  // Operations are used to wrap changes in such a way that each
 
  // change won't have to update the cursor and display (which would
 
  // be awkward, slow, and error-prone), but instead updates are
 
  // batched and then all combined and executed at once.
 

	
 
  var nextOpId = 0;
 
  function startOperation(cm) {
 
    cm.curOp = {
 
      // An array of ranges of lines that have to be updated. See
 
      // updateDisplay.
 
      changes: [],
 
      forceUpdate: false,
 
      updateInput: null,
 
      userSelChange: null,
 
      textChanged: null,
 
      selectionChanged: false,
 
      cursorActivity: false,
 
      updateMaxLine: false,
 
      updateScrollPos: false,
 
      id: ++nextOpId
 
    };
 
    if (!delayedCallbackDepth++) delayedCallbacks = [];
 
  }
 

	
 
  function endOperation(cm) {
 
    var op = cm.curOp, doc = cm.doc, display = cm.display;
 
    cm.curOp = null;
 

	
 
    if (op.updateMaxLine) computeMaxLength(cm);
 
    if (display.maxLineChanged && !cm.options.lineWrapping && display.maxLine) {
 
      var width = measureLineWidth(cm, display.maxLine);
 
      display.sizer.style.minWidth = Math.max(0, width + 3 + scrollerCutOff) + "px";
 
      display.maxLineChanged = false;
 
      var maxScrollLeft = Math.max(0, display.sizer.offsetLeft + display.sizer.offsetWidth - display.scroller.clientWidth);
 
      if (maxScrollLeft < doc.scrollLeft && !op.updateScrollPos)
 
        setScrollLeft(cm, Math.min(display.scroller.scrollLeft, maxScrollLeft), true);
 
    }
 
    var newScrollPos, updated;
 
    if (op.updateScrollPos) {
 
      newScrollPos = op.updateScrollPos;
 
    } else if (op.selectionChanged && display.scroller.clientHeight) { // don't rescroll if not visible
 
      var coords = cursorCoords(cm, doc.sel.head);
 
      newScrollPos = calculateScrollPos(cm, coords.left, coords.top, coords.left, coords.bottom);
 
    }
 
    if (op.changes.length || newScrollPos && newScrollPos.scrollTop != null) {
 
      updated = updateDisplay(cm, op.changes, newScrollPos && newScrollPos.scrollTop);
 
    if (op.changes.length || op.forceUpdate || newScrollPos && newScrollPos.scrollTop != null) {
 
      updated = updateDisplay(cm, op.changes, newScrollPos && newScrollPos.scrollTop, op.forceUpdate);
 
      if (cm.display.scroller.offsetHeight) cm.doc.scrollTop = cm.display.scroller.scrollTop;
 
    }
 
    if (!updated && op.selectionChanged) updateSelection(cm);
 
    if (op.updateScrollPos) {
 
      display.scroller.scrollTop = display.scrollbarV.scrollTop = doc.scrollTop = newScrollPos.scrollTop;
 
      display.scroller.scrollLeft = display.scrollbarH.scrollLeft = doc.scrollLeft = newScrollPos.scrollLeft;
 
      alignHorizontally(cm);
 
      if (op.scrollToPos)
 
        scrollPosIntoView(cm, clipPos(cm.doc, op.scrollToPos), op.scrollToPosMargin);
 
    } else if (newScrollPos) {
 
      scrollCursorIntoView(cm);
 
    }
 
    if (op.selectionChanged) restartBlink(cm);
 

	
 
    if (cm.state.focused && op.updateInput)
 
      resetInput(cm, op.userSelChange);
 

	
 
    var hidden = op.maybeHiddenMarkers, unhidden = op.maybeUnhiddenMarkers;
 
    if (hidden) for (var i = 0; i < hidden.length; ++i)
 
      if (!hidden[i].lines.length) signal(hidden[i], "hide");
 
    if (unhidden) for (var i = 0; i < unhidden.length; ++i)
 
      if (unhidden[i].lines.length) signal(unhidden[i], "unhide");
 

	
 
    var delayed;
 
    if (!--delayedCallbackDepth) {
 
      delayed = delayedCallbacks;
 
      delayedCallbacks = null;
 
    }
 
    if (op.textChanged)
 
      signal(cm, "change", cm, op.textChanged);
 
    if (op.cursorActivity) signal(cm, "cursorActivity", cm);
 
    if (delayed) for (var i = 0; i < delayed.length; ++i) delayed[i]();
 
  }
 

	
 
  // Wraps a function in an operation. Returns the wrapped function.
 
  function operation(cm1, f) {
 
    return function() {
 
      var cm = cm1 || this, withOp = !cm.curOp;
 
      if (withOp) startOperation(cm);
 
      try { var result = f.apply(cm, arguments); }
 
      finally { if (withOp) endOperation(cm); }
 
      return result;
 
    };
 
  }
 
  function docOperation(f) {
 
    return function() {
 
      var withOp = this.cm && !this.cm.curOp, result;
 
      if (withOp) startOperation(this.cm);
 
      try { result = f.apply(this, arguments); }
 
      finally { if (withOp) endOperation(this.cm); }
 
      return result;
 
    };
 
  }
 
  function runInOp(cm, f) {
 
    var withOp = !cm.curOp, result;
 
    if (withOp) startOperation(cm);
 
    try { result = f(); }
 
    finally { if (withOp) endOperation(cm); }
 
    return result;
 
  }
 

	
 
  function regChange(cm, from, to, lendiff) {
 
    if (from == null) from = cm.doc.first;
 
    if (to == null) to = cm.doc.first + cm.doc.size;
 
    cm.curOp.changes.push({from: from, to: to, diff: lendiff});
 
  }
 

	
 
  // INPUT HANDLING
 

	
 
  function slowPoll(cm) {
 
    if (cm.display.pollingFast) return;
 
    cm.display.poll.set(cm.options.pollInterval, function() {
 
      readInput(cm);
 
      if (cm.state.focused) slowPoll(cm);
 
    });
 
  }
 

	
 
  function fastPoll(cm) {
 
    var missed = false;
 
    cm.display.pollingFast = true;
 
    function p() {
 
      var changed = readInput(cm);
 
      if (!changed && !missed) {missed = true; cm.display.poll.set(60, p);}
 
      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) || cm.state.disableInput) return false;
 
@@ -2012,192 +2024,193 @@ window.CodeMirror = (function() {
 
    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) : b.motion)
 
                    return doHandleBinding(cm, b);
 
                });
 
    } else {
 
      handled = lookupKey(name, keymaps, function(b) { return doHandleBinding(cm, b); });
 
    }
 

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

	
 
  function onFocus(cm) {
 
    if (cm.options.readOnly == "nocursor") return;
 
    if (!cm.state.focused) {
 
      signal(cm, "focus", cm);
 
      cm.state.focused = true;
 
      if (cm.display.wrapper.className.search(/\bCodeMirror-focused\b/) == -1)
 
        cm.display.wrapper.className += " CodeMirror-focused";
 
      resetInput(cm, true);
 
    }
 
    slowPoll(cm);
 
    restartBlink(cm);
 
  }
 
  function onBlur(cm) {
 
    if (cm.state.focused) {
 
      signal(cm, "blur", cm);
 
      cm.state.focused = false;
 
      cm.display.wrapper.className = cm.display.wrapper.className.replace(" CodeMirror-focused", "");
 
    }
 
    clearInterval(cm.display.blinker);
 
    setTimeout(function() {if (!cm.state.focused) cm.doc.sel.shift = false;}, 150);
 
  }
 

	
 
  var detectingSelectAll;
 
  function onContextMenu(cm, e) {
 
    if (signalDOMEvent(cm, e, "contextmenu")) return;
 
    var display = cm.display, sel = cm.doc.sel;
 
    if (eventInWidget(display, e)) return;
 

	
 
    var pos = posFromMouse(cm, e), scrollPos = display.scroller.scrollTop;
 
    if (!pos || opera) return; // Opera is difficult.
 
    if (posEq(sel.from, sel.to) || posLess(pos, sel.from) || !posLess(pos, sel.to))
 
      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) {
 
        if (!ie || ie_lt9) prepareSelectAllHack();
 
        clearTimeout(detectingSelectAll);
 
        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
 

	
 
  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) +
 
                       getLine(doc, change.to.line).text.length - change.to.ch);
 
    var inside = pos.line - change.from.line;
 
    return clipToLen(pos, change.text[inside].length + (inside ? 0 : change.from.ch));
 
  }
 

	
 
  // Hint can be null|"end"|"start"|"around"|{anchor,head}
 
  function computeSelAfterChange(doc, change, hint) {
 
    if (hint && typeof hint == "object") // Assumed to be {anchor, head} object
 
      return {anchor: clipPostChange(doc, change, hint.anchor),
 
              head: clipPostChange(doc, change, hint.head)};
 

	
 
    if (hint == "start") return {anchor: change.from, head: change.from};
 

	
 
    var end = changeEnd(change);
 
    if (hint == "around") return {anchor: change.from, head: end};
 
    if (hint == "end") return {anchor: end, head: end};
 

	
 
    // hint is null, leave the selection alone as much as possible
 
    var adjustPos = function(pos) {
 
@@ -2662,305 +2675,320 @@ window.CodeMirror = (function() {
 
      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, 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()) {
 
          if (visually) ch = (dir < 0 ? lineRight : lineLeft)(lineObj);
 
          else ch = dir < 0 ? lineObj.text.length : 0;
 
        } else return (possible = false);
 
      } else ch = next;
 
      return true;
 
    }
 

	
 
    if (unit == "char") moveOnce();
 
    else if (unit == "column") moveOnce(true);
 
    else if (unit == "word" || unit == "group") {
 
      var sawType = null, group = unit == "group";
 
      for (var first = true;; first = false) {
 
        if (dir < 0 && !moveOnce(!first)) break;
 
        var cur = lineObj.text.charAt(ch) || "\n";
 
        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), 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.xRel < 0 || end == line.length) --start; else ++end;
 
      if ((pos.xRel < 0 || end == line.length) && start) --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;},
 

	
 
    addKeyMap: function(map, bottom) {
 
      this.state.keyMaps[bottom ? "push" : "unshift"](map);
 
    },
 
    removeKeyMap: function(map) {
 
      var maps = this.state.keyMaps;
 
      for (var i = 0; i < maps.length; ++i)
 
        if ((typeof map == "string" ? maps[i].name : maps[i]) == map) {
 
        if (maps[i] == map || (typeof maps[i] != "string" && maps[i].name == map)) {
 
          maps.splice(i, 1);
 
          return true;
 
        }
 
    },
 

	
 
    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) {
 
        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" && 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, precise) {
 
      var doc = this.doc;
 
      pos = clipPos(doc, pos);
 
      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};
 
    },
 

	
 
    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;
 
      if (ch == 0) return styles[2];
 
      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];
 
      }
 
    },
 

	
 
    getModeAt: function(pos) {
 
      var mode = this.doc.mode;
 
      if (!mode.innerMode) return mode;
 
      return CodeMirror.innerMode(mode, this.getTokenAt(pos).state).mode;
 
    },
 

	
 
    getHelper: function(pos, type) {
 
      if (!helpers.hasOwnProperty(type)) return;
 
      var help = helpers[type], mode = this.getModeAt(pos);
 
      return mode[type] && help[mode[type]] ||
 
        mode.helperType && help[mode.helperType] ||
 
        help[mode.name];
 
    },
 

	
 
    getStateAfter: function(line, precise) {
 
      var doc = this.doc;
 
      line = clipLine(doc, line == null ? doc.first + doc.size - 1: line);
 
      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;
 
      });
 
    }),
 

	
 
    clearGutter: operation(null, function(gutterID) {
 
      var cm = this, doc = cm.doc, i = doc.first;
 
      doc.iter(function(line) {
 
        if (line.gutterMarkers && line.gutterMarkers[gutterID]) {
 
          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("(?:^|\\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 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) {
 
      if (typeof line == "number") {
 
        if (!isLine(this.doc, line)) return null;
 
        var n = line;
 
@@ -3004,416 +3032,428 @@ window.CodeMirror = (function() {
 
      } 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);
 
    },
 

	
 
    triggerOnKeyDown: operation(null, onKeyDown),
 

	
 
    execCommand: function(cmd) {return commands[cmd](this);},
 

	
 
    findPosH: function(from, amount, unit, visually) {
 
      var dir = 1;
 
      if (amount < 0) { dir = -1; amount = -amount; }
 
      for (var i = 0, cur = clipPos(this.doc, from); i < amount; ++i) {
 
        cur = findPosH(this.doc, cur, dir, unit, visually);
 
        if (cur.hitSide) break;
 
      }
 
      return cur;
 
    },
 

	
 
    moveH: operation(null, function(dir, unit) {
 
      var sel = this.doc.sel, pos;
 
      if (sel.shift || sel.extend || posEq(sel.from, sel.to))
 
        pos = findPosH(this.doc, sel.head, dir, unit, this.options.rtlMoveVisually);
 
      else
 
        pos = dir < 0 ? sel.from : sel.to;
 
      extendSelection(this.doc, pos, pos, dir);
 
    }),
 

	
 
    deleteH: operation(null, function(dir, unit) {
 
      var sel = this.doc.sel;
 
      if (!posEq(sel.from, sel.to)) replaceRange(this.doc, "", sel.from, sel.to, "+delete");
 
      else replaceRange(this.doc, "", sel.from, findPosH(this.doc, sel.head, dir, unit, false), "+delete");
 
      this.curOp.userSelChange = true;
 
    }),
 

	
 
    findPosV: function(from, amount, unit, goalColumn) {
 
      var dir = 1, x = goalColumn;
 
      if (amount < 0) { dir = -1; amount = -amount; }
 
      for (var i = 0, cur = clipPos(this.doc, from); i < amount; ++i) {
 
        var coords = cursorCoords(this, cur, "div");
 
        if (x == null) x = coords.left;
 
        else coords.left = x;
 
        cur = findPosV(this, coords, dir, unit);
 
        if (cur.hitSide) break;
 
      }
 
      return cur;
 
    },
 

	
 
    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(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;
 
      return {left: scroller.scrollLeft, top: scroller.scrollTop,
 
              height: scroller.scrollHeight - co, width: scroller.scrollWidth - co,
 
              clientHeight: scroller.clientHeight - co, clientWidth: scroller.clientWidth - co};
 
    },
 

	
 
    scrollIntoView: operation(null, function(pos, margin) {
 
      if (typeof pos == "number") pos = Pos(pos, 0);
 
      if (!margin) margin = 0;
 
      var coords = pos;
 

	
 
      if (!pos || pos.line != null) {
 
        this.curOp.scrollToPos = pos ? clipPos(this.doc, pos) : this.doc.sel.head;
 
        this.curOp.scrollToPosMargin = margin;
 
        coords = cursorCoords(this, this.curOp.scrollToPos);
 
      }
 
      var sPos = calculateScrollPos(this, coords.left, coords.top - margin, coords.right, coords.bottom + margin);
 
      updateScrollPos(this, sPos.scrollLeft, sPos.scrollTop);
 
    }),
 

	
 
    setSize: function(width, height) {
 
    setSize: operation(null, function(width, height) {
 
      function interpret(val) {
 
        return typeof val == "number" || /^\d+$/.test(String(val)) ? val + "px" : val;
 
      }
 
      if (width != null) this.display.wrapper.style.width = interpret(width);
 
      if (height != null) this.display.wrapper.style.height = interpret(height);
 
      this.refresh();
 
    },
 

	
 
    on: function(type, f) {on(this, type, f);},
 
    off: function(type, f) {off(this, type, f);},
 
      if (this.options.lineWrapping)
 
        this.display.measureLineCache.length = this.display.measureLineCachePos = 0;
 
      this.curOp.forceUpdate = true;
 
    }),
 

	
 
    operation: function(f){return runInOp(this, f);},
 

	
 
    refresh: operation(null, function() {
 
      clearCaches(this);
 
      updateScrollPos(this, this.doc.scrollLeft, this.doc.scrollTop);
 
      regChange(this);
 
    }),
 

	
 
    swapDoc: operation(null, function(doc) {
 
      var old = this.doc;
 
      old.cm = null;
 
      attachDoc(this, doc);
 
      clearCaches(this);
 
      resetInput(this, true);
 
      updateScrollPos(this, doc.scrollLeft, doc.scrollTop);
 
      return old;
 
    }),
 

	
 
    getInputField: function(){return this.display.input;},
 
    getWrapperElement: function(){return this.display.wrapper;},
 
    getScrollerElement: function(){return this.display.scroller;},
 
    getGutterElement: function(){return this.display.gutters;}
 
  };
 
  eventMixin(CodeMirror);
 

	
 
  // OPTION DEFAULTS
 

	
 
  var optionHandlers = CodeMirror.optionHandlers = {};
 

	
 
  // The default configuration options.
 
  var defaults = CodeMirror.defaults = {};
 

	
 
  function option(name, deflt, handle, notOnInit) {
 
    CodeMirror.defaults[name] = deflt;
 
    if (handle) optionHandlers[name] =
 
      notOnInit ? function(cm, val, old) {if (old != Init) handle(cm, val, old);} : handle;
 
  }
 

	
 
  var Init = CodeMirror.Init = {toString: function(){return "CodeMirror.Init";}};
 

	
 
  // These two are, on init, called from the constructor because they
 
  // have to be initialized before the editor can start at all.
 
  option("value", "", function(cm, val) {
 
    cm.setValue(val);
 
  }, true);
 
  option("mode", null, function(cm, val) {
 
    cm.doc.modeOption = val;
 
    loadMode(cm);
 
  }, true);
 

	
 
  option("indentUnit", 2, loadMode, true);
 
  option("indentWithTabs", false);
 
  option("smartIndent", true);
 
  option("tabSize", 4, function(cm) {
 
    loadMode(cm);
 
    clearCaches(cm);
 
    regChange(cm);
 
  }, true);
 
  option("electricChars", true);
 
  option("rtlMoveVisually", !windows);
 

	
 
  option("theme", "default", function(cm) {
 
    themeChanged(cm);
 
    guttersChanged(cm);
 
  }, true);
 
  option("keyMap", "default", keyMapChanged);
 
  option("extraKeys", null);
 

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

	
 
  option("tabindex", null, function(cm, val) {
 
    cm.display.input.tabIndex = val || "";
 
  });
 
  option("autofocus", null);
 

	
 
  // MODE DEFINITION AND QUERYING
 

	
 
  // Known modes, by name and by MIME
 
  var modes = CodeMirror.modes = {}, mimeModes = CodeMirror.mimeModes = {};
 

	
 
  CodeMirror.defineMode = function(name, mode) {
 
    if (!CodeMirror.defaults.mode && name != "null") CodeMirror.defaults.mode = name;
 
    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)) {
 
      spec = mimeModes[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 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) {
 
        if (!exts.hasOwnProperty(prop)) continue;
 
        if (modeObj.hasOwnProperty(prop)) modeObj["_" + prop] = modeObj[prop];
 
        modeObj[prop] = exts[prop];
 
      }
 
    }
 
    modeObj.name = spec.name;
 

	
 
    return modeObj;
 
  };
 

	
 
  CodeMirror.defineMode("null", function() {
 
    return {token: function(stream) {stream.skipToEnd();}};
 
  });
 
  CodeMirror.defineMIME("text/plain", "null");
 

	
 
  var modeExtensions = CodeMirror.modeExtensions = {};
 
  CodeMirror.extendMode = function(mode, properties) {
 
    var exts = modeExtensions.hasOwnProperty(mode) ? modeExtensions[mode] : (modeExtensions[mode] = {});
 
    copyObj(properties, exts);
 
  };
 

	
 
  // EXTENSIONS
 

	
 
  CodeMirror.defineExtension = function(name, func) {
 
    CodeMirror.prototype[name] = func;
 
  };
 
  CodeMirror.defineDocExtension = function(name, func) {
 
    Doc.prototype[name] = func;
 
  };
 
  CodeMirror.defineOption = option;
 

	
 
  var initHooks = [];
 
  CodeMirror.defineInitHook = function(f) {initHooks.push(f);};
 

	
 
  var helpers = CodeMirror.helpers = {};
 
  CodeMirror.registerHelper = function(type, name, value) {
 
    if (!helpers.hasOwnProperty(type)) helpers[type] = CodeMirror[type] = {};
 
    helpers[type][name] = value;
 
  };
 

	
 
  // UTILITIES
 

	
 
  CodeMirror.isWordChar = isWordChar;
 

	
 
  // MODE STATE HANDLING
 

	
 
  // Utility functions for working with state. Exported because modes
 
  // sometimes need to do this.
 
  function copyState(mode, state) {
 
    if (state === true) return state;
 
    if (mode.copyState) return mode.copyState(state);
 
    var nstate = {};
 
    for (var n in state) {
 
      var val = state[n];
 
      if (val instanceof Array) val = val.concat([]);
 
      nstate[n] = val;
 
    }
 
    return nstate;
 
  }
 
  CodeMirror.copyState = copyState;
 

	
 
  function startState(mode, a1, a2) {
 
    return mode.startState ? mode.startState(a1, a2) : true;
 
  }
 
  CodeMirror.startState = startState;
 

	
 
  CodeMirror.innerMode = function(mode, state) {
 
    while (mode.innerMode) {
 
      var info = mode.innerMode(state);
 
      if (!info || info.mode == mode) break;
 
      state = info.state;
 
      mode = info.mode;
 
    }
 
    return info || {mode: mode, state: state};
 
  };
 

	
 
  // STANDARD COMMANDS
 

	
 
  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) {
 
        var firstNonWS = Math.max(0, line.text.search(/\S/));
 
        var inWS = cur.line == start.line && cur.ch <= firstNonWS && cur.ch;
 
        cm.extendSelection(Pos(start.line, inWS ? 0 : firstNonWS));
 
      } else cm.extendSelection(start);
 
    },
 
    goLineEnd: function(cm) {
 
      cm.extendSelection(lineEnd(cm, cm.getCursor().line));
 
    },
 
    goLineRight: function(cm) {
 
      var top = cm.charCoords(cm.getCursor(), "div").top + 5;
 
      cm.extendSelection(cm.coordsChar({left: cm.display.lineDiv.offsetWidth + 100, top: top}, "div"));
 
    },
 
    goLineLeft: function(cm) {
 
      var top = cm.charCoords(cm.getCursor(), "div").top + 5;
 
      cm.extendSelection(cm.coordsChar({left: 0, top: top}, "div"));
 
    },
 
    goLineUp: function(cm) {cm.moveV(-1, "line");},
 
    goLineDown: function(cm) {cm.moveV(1, "line");},
 
    goPageUp: function(cm) {cm.moveV(-1, "page");},
 
    goPageDown: function(cm) {cm.moveV(1, "page");},
 
    goCharLeft: function(cm) {cm.moveH(-1, "char");},
 
    goCharRight: function(cm) {cm.moveH(1, "char");},
 
    goColumnLeft: function(cm) {cm.moveH(-1, "column");},
 
    goColumnRight: function(cm) {cm.moveH(1, "column");},
 
    goWordLeft: function(cm) {cm.moveH(-1, "word");},
 
    goGroupRight: function(cm) {cm.moveH(1, "group");},
 
    goGroupLeft: function(cm) {cm.moveH(-1, "group");},
 
    goWordRight: function(cm) {cm.moveH(1, "word");},
 
    delCharBefore: function(cm) {cm.deleteH(-1, "char");},
 
    delCharAfter: function(cm) {cm.deleteH(1, "char");},
 
    delWordBefore: function(cm) {cm.deleteH(-1, "word");},
 
    delWordAfter: function(cm) {cm.deleteH(1, "word");},
 
    delGroupBefore: function(cm) {cm.deleteH(-1, "group");},
 
    delGroupAfter: function(cm) {cm.deleteH(1, "group");},
 
    indentAuto: function(cm) {cm.indentSelection("smart");},
 
    indentMore: function(cm) {cm.indentSelection("add");},
 
    indentLess: function(cm) {cm.indentSelection("subtract");},
 
    insertTab: function(cm) {cm.replaceSelection("\t", "end", "+input");},
 
    defaultTab: function(cm) {
 
      if (cm.somethingSelected()) cm.indentSelection("add");
 
      else cm.replaceSelection("\t", "end", "+input");
 
    },
 
    transposeChars: function(cm) {
 
      var cur = cm.getCursor(), line = cm.getLine(cur.line);
 
      if (cur.ch > 0 && cur.ch < line.length - 1)
 
        cm.replaceRange(line.charAt(cur.ch) + line.charAt(cur.ch - 1),
 
                        Pos(cur.line, cur.ch - 1), Pos(cur.line, cur.ch + 1));
 
    },
 
    newlineAndIndent: function(cm) {
 
      operation(cm, function() {
 
        cm.replaceSelection("\n", "end", "+input");
 
        cm.indentLine(cm.getCursor().line, null, true);
 
      })();
 
    },
 
    toggleOverwrite: function(cm) {cm.toggleOverwrite();}
 
  };
 

	
 
  // STANDARD KEYMAPS
 

	
 
  var keyMap = CodeMirror.keyMap = {};
 
@@ -3540,344 +3580,351 @@ window.CodeMirror = (function() {
 
    var cm = CodeMirror(function(node) {
 
      textarea.parentNode.insertBefore(node, textarea.nextSibling);
 
    }, options);
 
    cm.save = save;
 
    cm.getTextArea = function() { return textarea; };
 
    cm.toTextArea = function() {
 
      save();
 
      textarea.parentNode.removeChild(cm.getWrapperElement());
 
      textarea.style.display = "";
 
      if (textarea.form) {
 
        off(textarea.form, "submit", save);
 
        if (typeof textarea.form.submit == "function")
 
          textarea.form.submit = realSubmit;
 
      }
 
    };
 
    return cm;
 
  };
 

	
 
  // STRING STREAM
 

	
 
  // Fed to the mode parsers, provides helper functions to make
 
  // parsers more succinct.
 

	
 
  // The character stream used by a mode's parser.
 
  function StringStream(string, tabSize) {
 
    this.pos = this.start = 0;
 
    this.string = string;
 
    this.tabSize = tabSize || 8;
 
    this.lastColumnPos = this.lastColumnValue = 0;
 
  }
 

	
 
  StringStream.prototype = {
 
    eol: function() {return this.pos >= this.string.length;},
 
    sol: function() {return this.pos == 0;},
 
    peek: function() {return this.string.charAt(this.pos) || undefined;},
 
    next: function() {
 
      if (this.pos < this.string.length)
 
        return this.string.charAt(this.pos++);
 
    },
 
    eat: function(match) {
 
      var ch = this.string.charAt(this.pos);
 
      if (typeof match == "string") var ok = ch == match;
 
      else var ok = ch && (match.test ? match.test(ch) : match(ch));
 
      if (ok) {++this.pos; return ch;}
 
    },
 
    eatWhile: function(match) {
 
      var start = this.pos;
 
      while (this.eat(match)){}
 
      return this.pos > start;
 
    },
 
    eatSpace: function() {
 
      var start = this.pos;
 
      while (/[\s\u00a0]/.test(this.string.charAt(this.pos))) ++this.pos;
 
      return this.pos > start;
 
    },
 
    skipToEnd: function() {this.pos = this.string.length;},
 
    skipTo: function(ch) {
 
      var found = this.string.indexOf(ch, this.pos);
 
      if (found > -1) {this.pos = found; return true;}
 
    },
 
    backUp: function(n) {this.pos -= n;},
 
    column: function() {
 
      if (this.lastColumnPos < this.start) {
 
        this.lastColumnValue = countColumn(this.string, this.start, this.tabSize, this.lastColumnPos, this.lastColumnValue);
 
        this.lastColumnPos = this.start;
 
      }
 
      return this.lastColumnValue;
 
    },
 
    indentation: function() {return countColumn(this.string, null, this.tabSize);},
 
    match: function(pattern, consume, caseInsensitive) {
 
      if (typeof pattern == "string") {
 
        var cased = function(str) {return caseInsensitive ? str.toLowerCase() : str;};
 
        var substr = this.string.substr(this.pos, pattern.length);
 
        if (cased(substr) == cased(pattern)) {
 
          if (consume !== false) this.pos += pattern.length;
 
          return true;
 
        }
 
      } else {
 
        var match = this.string.slice(this.pos).match(pattern);
 
        if (match && match.index > 0) return null;
 
        if (match && consume !== false) this.pos += match[0].length;
 
        return match;
 
      }
 
    },
 
    current: function(){return this.string.slice(this.start, this.pos);}
 
  };
 
  CodeMirror.StringStream = StringStream;
 

	
 
  // TEXTMARKERS
 

	
 
  function TextMarker(doc, type) {
 
    this.lines = [];
 
    this.type = type;
 
    this.doc = doc;
 
  }
 
  CodeMirror.TextMarker = TextMarker;
 
  eventMixin(TextMarker);
 

	
 
  TextMarker.prototype.clear = function() {
 
    if (this.explicitlyCleared) return;
 
    var cm = this.doc.cm, withOp = cm && !cm.curOp;
 
    if (withOp) startOperation(cm);
 
    if (hasHandler(this, "clear")) {
 
      var found = this.find();
 
      if (found) signalLater(this, "clear", found.from, found.to);
 
    }
 
    var min = null, max = null;
 
    for (var i = 0; i < this.lines.length; ++i) {
 
      var line = this.lines[i];
 
      var span = getMarkedSpanFor(line.markedSpans, this);
 
      if (span.to != null) max = lineNo(line);
 
      line.markedSpans = removeMarkedSpan(line.markedSpans, span);
 
      if (span.from != null)
 
        min = lineNo(line);
 
      else if (this.collapsed && !lineIsHidden(this.doc, line) && cm)
 
        updateLineHeight(line, textHeight(cm.display));
 
    }
 
    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.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.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; });
 
      runInOp(cm, function() {
 
        cm.curOp.selectionChanged = cm.curOp.forceUpdate = cm.curOp.updateMaxLine = 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);
 
    if (!this.lines.length && this.doc.cm) {
 
      var op = this.doc.cm.curOp;
 
      (op.maybeHiddenMarkers || (op.maybeHiddenMarkers = [])).push(this);
 
    }
 
  };
 

	
 
  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};
 
      size += line.text.length;
 
      if (curLine == from.line) {span.from = from.ch; size -= from.ch;}
 
      if (curLine == to.line) {span.to = to.ch; size -= line.text.length - to.ch;}
 
      if (marker.collapsed) {
 
        if (curLine == to.line) collapsedAtEnd = collapsedSpanAt(line, to.ch);
 
        if (curLine == from.line) collapsedAtStart = collapsedSpanAt(line, from.ch);
 
        else updateLineHeight(line, 0);
 
      }
 
      addMarkedSpan(line, span);
 
      ++curLine;
 
    });
 
    if (marker.collapsed) doc.iter(from.line, to.line + 1, function(line) {
 
      if (lineIsHidden(doc, line)) updateLineHeight(line, 0);
 
    });
 

	
 
    if (marker.clearOnEnter) on(marker, "beforeCursorEnter", function() { marker.clear(); });
 

	
 
    if (marker.readOnly) {
 
      sawReadOnlySpans = true;
 
      if (doc.history.done.length || doc.history.undone.length)
 
        doc.clearHistory();
 
    }
 
    if (marker.collapsed) {
 
      if (collapsedAtStart != collapsedAtEnd)
 
        throw new Error("Inserting collapsed marker overlapping an existing one");
 
      marker.size = size;
 
      marker.atomic = true;
 
    }
 
    if (cm) {
 
      if (updateMaxLine) cm.curOp.updateMaxLine = true;
 
      if (marker.className || marker.startStyle || marker.endStyle || marker.collapsed)
 
      if (marker.className || marker.title || marker.startStyle || marker.endStyle || marker.collapsed)
 
        regChange(cm, from.line, to.line + 1);
 
      if (marker.atomic) reCheckSelection(cm);
 
    }
 
    return marker;
 
  }
 

	
 
  // SHARED TEXTMARKERS
 

	
 
  function SharedTextMarker(markers, primary) {
 
    this.markers = markers;
 
    this.primary = primary;
 
    for (var i = 0, me = this; i < markers.length; ++i) {
 
      markers[i].parent = this;
 
      on(markers[i], "clear", function(){me.clear();});
 
    }
 
  }
 
  CodeMirror.SharedTextMarker = SharedTextMarker;
 
  eventMixin(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();
 
  };
 

	
 
  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);
 
    });
 
    return new SharedTextMarker(markers, primary);
 
  }
 

	
 
  // TEXTMARKER SPANS
 

	
 
  function getMarkedSpanFor(spans, marker) {
 
    if (spans) for (var i = 0; i < spans.length; ++i) {
 
      var span = spans[i];
 
      if (span.marker == marker) return span;
 
    }
 
  }
 
  function removeMarkedSpan(spans, span) {
 
    for (var r, i = 0; i < spans.length; ++i)
 
      if (spans[i] != span) (r || (r = [])).push(spans[i]);
 
    return r;
 
  }
 
  function addMarkedSpan(line, span) {
 
    line.markedSpans = line.markedSpans ? line.markedSpans.concat([span]) : [span];
 
    span.marker.attachLine(line);
 
  }
 

	
 
  function markedSpansBefore(old, startCh, isInsert) {
 
    if (old) for (var i = 0, nw; i < old.length; ++i) {
 
      var span = old[i], marker = span.marker;
 
      var startsBefore = span.from == null || (marker.inclusiveLeft ? span.from <= startCh : span.from < startCh);
 
      if (startsBefore || marker.type == "bookmark" && span.from == startCh && (!isInsert || !span.marker.insertLeft)) {
 
        var endsAfter = span.to == null || (marker.inclusiveRight ? span.to >= startCh : span.to > startCh);
 
        (nw || (nw = [])).push({from: span.from,
 
                                to: endsAfter ? null : span.to,
 
                                marker: marker});
 
      }
 
    }
 
    return nw;
 
  }
 

	
 
  function markedSpansAfter(old, endCh, isInsert) {
 
    if (old) for (var i = 0, nw; i < old.length; ++i) {
 
      var span = old[i], marker = span.marker;
 
      var endsAfter = span.to == null || (marker.inclusiveRight ? span.to >= endCh : span.to > endCh);
 
      if (endsAfter || marker.type == "bookmark" && span.from == endCh && (!isInsert || span.marker.insertLeft)) {
 
        var startsBefore = span.from == null || (marker.inclusiveLeft ? span.from <= endCh : span.from < endCh);
 
        (nw || (nw = [])).push({from: startsBefore ? null : span.from - endCh,
 
                                to: span.to == null ? null : span.to - endCh,
 
                                marker: marker});
 
      }
 
    }
 
    return nw;
 
  }
 

	
 
  function stretchSpansOverChange(doc, change) {
 
    var oldFirst = isLine(doc, change.from.line) && getLine(doc, change.from.line).markedSpans;
 
    var oldLast = isLine(doc, change.to.line) && getLine(doc, change.to.line).markedSpans;
 
    if (!oldFirst && !oldLast) return null;
 

	
 
    var startCh = change.from.ch, endCh = change.to.ch, isInsert = posEq(change.from, change.to);
 
    // Get the spans that 'stick out' on both sides
 
    var first = markedSpansBefore(oldFirst, startCh, isInsert);
 
    var last = markedSpansAfter(oldLast, endCh, isInsert);
 

	
 
    // Next, merge those two ends
 
    var sameLine = change.text.length == 1, offset = lst(change.text).length + (sameLine ? startCh : 0);
 
    if (first) {
 
      // Fix up .to properties of first
 
      for (var i = 0; i < first.length; ++i) {
 
        var span = first[i];
 
        if (span.to == null) {
 
          var found = getMarkedSpanFor(last, span.marker);
 
          if (!found) span.to = startCh;
 
          else if (sameLine) span.to = found.to == null ? null : found.to + offset;
 
        }
 
      }
 
    }
 
@@ -3944,1119 +3991,1145 @@ window.CodeMirror = (function() {
 
  }
 

	
 
  function removeReadOnlyRanges(doc, from, to) {
 
    var markers = null;
 
    doc.iter(from.line, to.line + 1, function(line) {
 
      if (line.markedSpans) for (var i = 0; i < line.markedSpans.length; ++i) {
 
        var mark = line.markedSpans[i].marker;
 
        if (mark.readOnly && (!markers || indexOf(markers, mark) == -1))
 
          (markers || (markers = [])).push(mark);
 
      }
 
    });
 
    if (!markers) return null;
 
    var parts = [{from: from, to: to}];
 
    for (var i = 0; i < markers.length; ++i) {
 
      var mk = markers[i], m = mk.find();
 
      for (var j = 0; j < parts.length; ++j) {
 
        var p = parts[j];
 
        if (posLess(p.to, m.from) || posLess(m.to, p.from)) continue;
 
        var newParts = [j, 1];
 
        if (posLess(p.from, m.from) || !mk.inclusiveLeft && posEq(p.from, m.from))
 
          newParts.push({from: p.from, to: m.from});
 
        if (posLess(m.to, p.to) || !mk.inclusiveRight && posEq(p.to, m.to))
 
          newParts.push({from: m.to, to: p.to});
 
        parts.splice.apply(parts, newParts);
 
        j += newParts.length - 1;
 
      }
 
    }
 
    return parts;
 
  }
 

	
 
  function collapsedSpanAt(line, ch) {
 
    var sps = sawCollapsedSpans && line.markedSpans, found;
 
    if (sps) for (var sp, i = 0; i < sps.length; ++i) {
 
      sp = sps[i];
 
      if (!sp.marker.collapsed) continue;
 
      if ((sp.from == null || sp.from < ch) &&
 
          (sp.to == null || sp.to > ch) &&
 
          (!found || found.width < sp.marker.width))
 
        found = sp.marker;
 
    }
 
    return found;
 
  }
 
  function collapsedSpanAtStart(line) { return collapsedSpanAt(line, -1); }
 
  function collapsedSpanAtEnd(line) { return collapsedSpanAt(line, line.text.length + 1); }
 

	
 
  function visualLine(doc, line) {
 
    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.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;
 
  }
 

	
 
  function attachMarkedSpans(line, spans) {
 
    if (!spans) return;
 
    for (var i = 0; i < spans.length; ++i)
 
      spans[i].marker.attachLine(line);
 
    line.markedSpans = spans;
 
  }
 

	
 
  // LINE WIDGETS
 

	
 
  var LineWidget = CodeMirror.LineWidget = function(cm, node, options) {
 
    for (var opt in options) if (options.hasOwnProperty(opt))
 
    if (options) for (var opt in options) if (options.hasOwnProperty(opt))
 
      this[opt] = options[opt];
 
    this.cm = cm;
 
    this.node = node;
 
  };
 
  eventMixin(LineWidget);
 
  function widgetOperation(f) {
 
    return function() {
 
      var withOp = !this.cm.curOp;
 
      if (withOp) startOperation(this.cm);
 
      try {var result = f.apply(this, arguments);}
 
      finally {if (withOp) endOperation(this.cm);}
 
      return result;
 
    };
 
  }
 
  LineWidget.prototype.clear = widgetOperation(function() {
 
    var ws = this.line.widgets, no = lineNo(this.line);
 
    if (no == null || !ws) return;
 
    for (var i = 0; i < ws.length; ++i) if (ws[i] == this) ws.splice(i--, 1);
 
    if (!ws.length) this.line.widgets = null;
 
    var aboveVisible = heightAtLine(this.cm, this.line) < this.cm.doc.scrollTop;
 
    updateLineHeight(this.line, Math.max(0, this.line.height - widgetHeight(this)));
 
    if (aboveVisible) addToScrollPos(this.cm, 0, -this.height);
 
    regChange(this.cm, no, no + 1);
 
  });
 
  LineWidget.prototype.changed = widgetOperation(function() {
 
    var oldH = this.height;
 
    this.height = null;
 
    var diff = widgetHeight(this) - oldH;
 
    if (!diff) return;
 
    updateLineHeight(this.line, this.line.height + diff);
 
    var no = lineNo(this.line);
 
    regChange(this.cm, no, no + 1);
 
  });
 

	
 
  function widgetHeight(widget) {
 
    if (widget.height != null) return widget.height;
 
    if (!widget.node.parentNode || widget.node.parentNode.nodeType != 1)
 
      removeChildrenAndAdd(widget.cm.display.measure, elt("div", [widget.node], null, "position: relative"));
 
    return widget.height = widget.node.offsetHeight;
 
  }
 

	
 
  function addLineWidget(cm, handle, node, options) {
 
    var widget = new LineWidget(cm, node, options);
 
    if (widget.noHScroll) cm.display.alignWidgets = true;
 
    changeLine(cm, handle, function(line) {
 
      (line.widgets || (line.widgets = [])).push(widget);
 
      var widgets = line.widgets || (line.widgets = []);
 
      if (widget.insertAt == null) widgets.push(widget);
 
      else widgets.splice(Math.min(widgets.length - 1, Math.max(0, widget.insertAt)), 0, widget);
 
      widget.line = line;
 
      if (!lineIsHidden(cm.doc, line) || widget.showIfHidden) {
 
        var aboveVisible = heightAtLine(cm, line) < cm.display.scroller.scrollTop;
 
        var aboveVisible = heightAtLine(cm, line) < cm.doc.scrollTop;
 
        updateLineHeight(line, line.height + widgetHeight(widget));
 
        if (aboveVisible) addToScrollPos(cm, 0, widget.height);
 
      }
 
      return true;
 
    });
 
    return widget;
 
  }
 

	
 
  // LINE DATA STRUCTURE
 

	
 
  // Line objects. These hold state related to a line, including
 
  // highlighting info (the styles array).
 
  function makeLine(text, markedSpans, estimateHeight) {
 
    var line = {text: text};
 
    attachMarkedSpans(line, markedSpans);
 
    line.height = estimateHeight ? estimateHeight(line) : 1;
 
    return line;
 
  }
 
  var Line = CodeMirror.Line = function(text, markedSpans, estimateHeight) {
 
    this.text = text;
 
    attachMarkedSpans(this, markedSpans);
 
    this.height = estimateHeight ? estimateHeight(this) : 1;
 
  };
 
  eventMixin(Line);
 

	
 
  function updateLine(line, text, markedSpans, estimateHeight) {
 
    line.text = text;
 
    if (line.stateAfter) line.stateAfter = null;
 
    if (line.styles) line.styles = null;
 
    if (line.order != null) line.order = null;
 
    detachMarkedSpans(line);
 
    attachMarkedSpans(line, markedSpans);
 
    var estHeight = estimateHeight ? estimateHeight(line) : 1;
 
    if (estHeight != line.height) updateLineHeight(line, estHeight);
 
  }
 

	
 
  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 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);
 
      }
 
      if (!flattenSpans || curStyle != style) {
 
        if (curStart < stream.start) f(stream.start, curStyle);
 
        curStart = stream.start; curStyle = style;
 
      }
 
      stream.start = stream.pos;
 
    }
 
    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(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, 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 (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, 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;
 
  }
 

	
 
  function getLineStyles(cm, line) {
 
    if (!line.styles || line.styles[0] != cm.state.modeGen)
 
      line.styles = highlightLine(cm, line, line.stateAfter = getStateBefore(cm, lineNo(line)));
 
    return line.styles;
 
  }
 

	
 
  // Lightweight form of highlight -- proceed over this line and
 
  // update state, but don't save a style array.
 
  function processLine(cm, line, state) {
 
    var mode = cm.doc.mode;
 
    var stream = new StringStream(line.text, cm.options.tabSize);
 
    if (line.text == "" && mode.blankLine) mode.blankLine(state);
 
    while (!stream.eol() && stream.pos <= cm.options.maxHighlightLength) {
 
      mode.token(stream, state);
 
      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) {
 
  function lineContent(cm, realLine, measure, copyWidgets) {
 
    var merged, line = realLine, empty = true;
 
    while (merged = collapsedSpanAtStart(line))
 
      line = getLine(cm.doc, merged.find().from.line);
 

	
 
    var builder = {pre: elt("pre"), col: 0, pos: 0, display: !measure,
 
                   measure: null, measuredSomething: false, cm: cm};
 
    var builder = {pre: elt("pre"), col: 0, pos: 0,
 
                   measure: null, measuredSomething: false, cm: cm,
 
                   copyWidgets: copyWidgets};
 
    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);
 
      var next = insertLineContent(line, builder, getLineStyles(cm, line));
 
      if (measure && line == realLine && !builder.measuredSomething) {
 
        measure[0] = builder.pre.appendChild(zeroWidthElement(cm.display.measure));
 
        builder.measuredSomething = true;
 
      }
 
      if (next) line = getLine(cm.doc, next.to.line);
 
    } while (next);
 

	
 
    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) {
 
        var span = measure[builder.pos - 1];
 
        if (span) span.parentNode.insertBefore(span.measureRight = zeroWidthElement(cm.display.measure),
 
                                               span.nextSibling);
 
      }
 
    }
 

	
 
    signal(cm, "renderLine", cm, realLine, builder.pre);
 
    return builder.pre;
 
  }
 

	
 
  var tokenSpecialChars = /[\t\u0000-\u0019\u00ad\u200b\u2028\u2029\uFEFF]/g;
 
  function buildToken(builder, text, style, startStyle, endStyle) {
 
  function buildToken(builder, text, style, startStyle, endStyle, title) {
 
    if (!text) return;
 
    if (!tokenSpecialChars.test(text)) {
 
      builder.col += text.length;
 
      var content = document.createTextNode(text);
 
    } else {
 
      var content = document.createDocumentFragment(), pos = 0;
 
      while (true) {
 
        tokenSpecialChars.lastIndex = pos;
 
        var m = tokenSpecialChars.exec(text);
 
        var skipped = m ? m.index - pos : text.length - pos;
 
        if (skipped) {
 
          content.appendChild(document.createTextNode(text.slice(pos, pos + skipped)));
 
          builder.col += skipped;
 
        }
 
        if (!m) break;
 
        pos += skipped + 1;
 
        if (m[0] == "\t") {
 
          var tabSize = builder.cm.options.tabSize, tabWidth = tabSize - builder.col % tabSize;
 
          content.appendChild(elt("span", spaceStr(tabWidth), "cm-tab"));
 
          builder.col += tabWidth;
 
        } else {
 
          var token = elt("span", "\u2022", "cm-invalidchar");
 
          token.title = "\\u" + m[0].charCodeAt(0).toString(16);
 
          content.appendChild(token);
 
          builder.col += 1;
 
        }
 
      }
 
    }
 
    if (style || startStyle || endStyle || builder.measure) {
 
      var fullStyle = style || "";
 
      if (startStyle) fullStyle += startStyle;
 
      if (endStyle) fullStyle += endStyle;
 
      return builder.pre.appendChild(elt("span", [content], fullStyle));
 
      var token = elt("span", [content], fullStyle);
 
      if (title) token.title = title;
 
      return builder.pre.appendChild(token);
 
    }
 
    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(text, i)) {
 
        builder.pre.appendChild(elt("wbr"));
 
      }
 
      var old = builder.measure[builder.pos];
 
      var span = builder.measure[builder.pos] =
 
        buildToken(builder, ch, style,
 
                   start && startStyle, i == text.length - 1 && endStyle);
 
      if (old) span.leftSide = old.leftSide || old;
 
      // 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.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);
 
    return function(builder, text, style, startStyle, endStyle, title) {
 
      return inner(builder, text.replace(/ {3,}/, split), style, startStyle, endStyle, title);
 
    };
 
  }
 

	
 
  function buildCollapsedSpan(builder, size, widget) {
 
  function buildCollapsedSpan(builder, size, marker, ignoreWidget) {
 
    var widget = !ignoreWidget && marker.replacedWith;
 
    if (widget) {
 
      if (!builder.display) widget = widget.cloneNode(true);
 
      if (builder.copyWidgets) widget = widget.cloneNode(true);
 
      builder.pre.appendChild(widget);
 
      if (builder.measure) {
 
        builder.measure[builder.pos] = size ? widget
 
          : builder.pre.appendChild(zeroWidthElement(builder.cm.display.measure));
 
        if (size) {
 
          builder.measure[builder.pos] = widget;
 
        } else {
 
          var elt = builder.measure[builder.pos] = zeroWidthElement(builder.cm.display.measure);
 
          if (marker.type != "bookmark" || marker.insertLeft)
 
            builder.pre.insertBefore(elt, widget);
 
          else
 
            builder.pre.appendChild(elt);
 
        }
 
        builder.measuredSomething = true;
 
      }
 
      builder.pre.appendChild(widget);
 
    }
 
    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, allText = line.text, at = 0;
 
    if (!spans) {
 
      for (var i = 1; i < styles.length; i+=2)
 
        builder.addToken(builder, allText.slice(at, at = styles[i]), styleToClass(styles[i+1]));
 
      return;
 
    }
 

	
 
    var len = allText.length, pos = 0, i = 1, text = "", style;
 
    var nextChange = 0, spanStyle, spanEndStyle, spanStartStyle, collapsed;
 
    var nextChange = 0, spanStyle, spanEndStyle, spanStartStyle, title, collapsed;
 
    for (;;) {
 
      if (nextChange == pos) { // Update current marker set
 
        spanStyle = spanEndStyle = spanStartStyle = "";
 
        spanStyle = spanEndStyle = spanStartStyle = title = "";
 
        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.title && !title) title = m.title;
 
            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 (m.type == "bookmark" && sp.from == pos && m.replacedWith) foundBookmark = m;
 
        }
 
        if (collapsed && (collapsed.from || 0) == pos) {
 
          buildCollapsedSpan(builder, (collapsed.to == null ? len : collapsed.to) - pos,
 
                             collapsed.from != null && collapsed.marker.replacedWith);
 
                             collapsed.marker, collapsed.from == null);
 
          if (collapsed.to == null) return collapsed.marker.find();
 
        }
 
        if (foundBookmark && !collapsed) buildCollapsedSpan(builder, 0, foundBookmark);
 
      }
 
      if (pos >= len) break;
 

	
 
      var upto = Math.min(len, nextChange);
 
      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 : "");
 
                             spanStartStyle, pos + tokenText.length == nextChange ? spanEndStyle : "", title);
 
          }
 
          if (end >= upto) {text = text.slice(upto - pos); pos = upto; break;}
 
          pos = end;
 
          spanStartStyle = "";
 
        }
 
        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);
 
    }
 

	
 
    var from = change.from, to = change.to, text = change.text;
 
    var firstLine = getLine(doc, from.line), lastLine = getLine(doc, to.line);
 
    var lastText = lst(text), lastSpans = spansFor(text.length - 1), nlines = to.line - from.line;
 

	
 
    // First adjust the line structure
 
    if (from.ch == 0 && to.ch == 0 && lastText == "") {
 
      // This is a whole-line replace. Treated specially to make
 
      // sure line objects move the way they are supposed to.
 
      for (var i = 0, e = text.length - 1, added = []; i < e; ++i)
 
        added.push(makeLine(text[i], spansFor(i), estimateHeight));
 
        added.push(new Line(text[i], spansFor(i), estimateHeight));
 
      update(lastLine, lastLine.text, lastSpans);
 
      if (nlines) doc.remove(from.line, nlines);
 
      if (added.length) doc.insert(from.line, added);
 
    } else if (firstLine == lastLine) {
 
      if (text.length == 1) {
 
        update(firstLine, firstLine.text.slice(0, from.ch) + lastText + firstLine.text.slice(to.ch), lastSpans);
 
      } else {
 
        for (var added = [], i = 1, e = text.length - 1; i < e; ++i)
 
          added.push(makeLine(text[i], spansFor(i), estimateHeight));
 
        added.push(makeLine(lastText + firstLine.text.slice(to.ch), lastSpans, estimateHeight));
 
          added.push(new Line(text[i], spansFor(i), estimateHeight));
 
        added.push(new Line(lastText + firstLine.text.slice(to.ch), lastSpans, estimateHeight));
 
        update(firstLine, firstLine.text.slice(0, from.ch) + text[0], spansFor(0));
 
        doc.insert(from.line + 1, added);
 
      }
 
    } else if (text.length == 1) {
 
      update(firstLine, firstLine.text.slice(0, from.ch) + text[0] + lastLine.text.slice(to.ch), spansFor(0));
 
      doc.remove(from.line + 1, nlines);
 
    } else {
 
      update(firstLine, firstLine.text.slice(0, from.ch) + text[0], spansFor(0));
 
      update(lastLine, lastText + lastLine.text.slice(to.ch), lastSpans);
 
      for (var i = 1, e = text.length - 1, added = []; i < e; ++i)
 
        added.push(makeLine(text[i], spansFor(i), estimateHeight));
 
        added.push(new Line(text[i], spansFor(i), estimateHeight));
 
      if (nlines > 1) doc.remove(from.line + 1, nlines - 1);
 
      doc.insert(from.line + 1, added);
 
    }
 

	
 
    signalLater(doc, "change", doc, change);
 
    setSelection(doc, selAfter.anchor, selAfter.head, null, true);
 
  }
 

	
 
  function LeafChunk(lines) {
 
    this.lines = lines;
 
    this.parent = null;
 
    for (var i = 0, e = lines.length, height = 0; i < e; ++i) {
 
      lines[i].parent = this;
 
      height += lines[i].height;
 
    }
 
    this.height = height;
 
  }
 

	
 
  LeafChunk.prototype = {
 
    chunkSize: function() { return this.lines.length; },
 
    removeInner: function(at, n) {
 
      for (var i = at, e = at + n; i < e; ++i) {
 
        var line = this.lines[i];
 
        this.height -= line.height;
 
        cleanUpLine(line);
 
        signalLater(line, "delete");
 
      }
 
      this.lines.splice(at, n);
 
    },
 
    collapse: function(lines) {
 
      lines.splice.apply(lines, [lines.length, 0].concat(this.lines));
 
    },
 
    insertInner: function(at, lines, height) {
 
      this.height += height;
 
      this.lines = this.lines.slice(0, at).concat(lines).concat(this.lines.slice(at));
 
      for (var i = 0, e = lines.length; i < e; ++i) lines[i].parent = this;
 
    },
 
    iterN: function(at, n, op) {
 
      for (var e = at + n; at < e; ++at)
 
        if (op(this.lines[at])) return true;
 
    }
 
  };
 

	
 
  function BranchChunk(children) {
 
    this.children = children;
 
    var size = 0, height = 0;
 
    for (var i = 0, e = children.length; i < e; ++i) {
 
      var ch = children[i];
 
      size += ch.chunkSize(); height += ch.height;
 
      ch.parent = this;
 
    }
 
    this.size = size;
 
    this.height = height;
 
    this.parent = null;
 
  }
 

	
 
  BranchChunk.prototype = {
 
    chunkSize: function() { return this.size; },
 
    removeInner: function(at, n) {
 
      this.size -= n;
 
      for (var i = 0; i < this.children.length; ++i) {
 
        var child = this.children[i], sz = child.chunkSize();
 
        if (at < sz) {
 
          var rm = Math.min(n, sz - at), oldHeight = child.height;
 
          child.removeInner(at, rm);
 
          this.height -= oldHeight - child.height;
 
          if (sz == rm) { this.children.splice(i--, 1); child.parent = null; }
 
          if ((n -= rm) == 0) break;
 
          at = 0;
 
        } else at -= sz;
 
      }
 
      if (this.size - n < 25) {
 
        var lines = [];
 
        this.collapse(lines);
 
        this.children = [new LeafChunk(lines)];
 
        this.children[0].parent = this;
 
      }
 
    },
 
    collapse: function(lines) {
 
      for (var i = 0, e = this.children.length; i < e; ++i) this.children[i].collapse(lines);
 
    },
 
    insertInner: function(at, lines, height) {
 
      this.size += lines.length;
 
      this.height += height;
 
      for (var i = 0, e = this.children.length; i < e; ++i) {
 
        var child = this.children[i], sz = child.chunkSize();
 
        if (at <= sz) {
 
          child.insertInner(at, lines, height);
 
          if (child.lines && child.lines.length > 50) {
 
            while (child.lines.length > 50) {
 
              var spilled = child.lines.splice(child.lines.length - 25, 25);
 
              var newleaf = new LeafChunk(spilled);
 
              child.height -= newleaf.height;
 
              this.children.splice(i + 1, 0, newleaf);
 
              newleaf.parent = this;
 
            }
 
            this.maybeSpill();
 
          }
 
          break;
 
        }
 
        at -= sz;
 
      }
 
    },
 
    maybeSpill: function() {
 
      if (this.children.length <= 10) return;
 
      var me = this;
 
      do {
 
        var spilled = me.children.splice(me.children.length - 5, 5);
 
        var sibling = new BranchChunk(spilled);
 
        if (!me.parent) { // Become the parent node
 
          var copy = new BranchChunk(me.children);
 
          copy.parent = me;
 
          me.children = [copy, sibling];
 
          me = copy;
 
        } else {
 
          me.size -= sibling.size;
 
          me.height -= sibling.height;
 
          var myIndex = indexOf(me.parent.children, me);
 
          me.parent.children.splice(myIndex + 1, 0, sibling);
 
        }
 
        sibling.parent = me.parent;
 
      } while (me.children.length > 10);
 
      me.parent.maybeSpill();
 
    },
 
    iterN: function(at, n, op) {
 
      for (var i = 0, e = this.children.length; i < e; ++i) {
 
        var child = this.children[i], sz = child.chunkSize();
 
        if (at < sz) {
 
          var used = Math.min(n, sz - at);
 
          if (child.iterN(at, used, op)) return true;
 
          if ((n -= used) == 0) break;
 
          at = 0;
 
        } else at -= sz;
 
      }
 
    }
 
  };
 

	
 
  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)])]);
 
    BranchChunk.call(this, [new LeafChunk([new Line("", 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); },
 

	
 
    getValue: function(lineSep) {
 
      var lines = getLines(this, this.first, this.first + this.size);
 
      if (lineSep === false) return lines;
 
      return lines.join(lineSep || "\n");
 
    },
 
    setValue: function(code) {
 
      var top = Pos(this.first, 0), last = this.first + this.size - 1;
 
      makeChange(this, {from: top, to: Pos(last, getLine(this, last).text.length),
 
                        text: splitLines(code), origin: "setValue"},
 
                 {head: top, anchor: top}, true);
 
    },
 
    replaceRange: function(code, from, to, origin) {
 
      from = clipPos(this, from);
 
      to = to ? clipPos(this, to) : from;
 
      replaceRange(this, code, from, to, origin);
 
    },
 
    getRange: function(from, to, lineSep) {
 
      var lines = getBetween(this, clipPos(this, from), clipPos(this, to));
 
      if (lineSep === false) return lines;
 
      return lines.join(lineSep || "\n");
 
    },
 

	
 
    getLine: function(line) {var l = this.getLineHandle(line); return l && l.text;},
 
    setLine: function(line, text) {
 
      if (isLine(this, line))
 
        replaceRange(this, text, Pos(line, 0), clipPos(this, Pos(line)));
 
    },
 
    removeLine: function(line) {
 
      if (line) replaceRange(this, "", clipPos(this, Pos(line - 1)), clipPos(this, Pos(line)));
 
      else replaceRange(this, "", Pos(0, 0), clipPos(this, Pos(1, 0)));
 
    },
 

	
 
    getLineHandle: function(line) {if (isLine(this, line)) return getLine(this, line);},
 
    getLineNumber: function(line) {return lineNo(line);},
 

	
 
    getLineHandleVisualStart: function(line) {
 
      if (typeof line == "number") line = getLine(this, line);
 
      return visualLine(this, line);
 
    },
 

	
 
    lineCount: function() {return this.size;},
 
    firstLine: function() {return this.first;},
 
    lastLine: function() {return this.first + this.size - 1;},
 

	
 
    clipPos: function(pos) {return clipPos(this, pos);},
 

	
 
    getCursor: function(start) {
 
      var sel = this.sel, pos;
 
      if (start == null || start == "head") pos = sel.head;
 
      else if (start == "anchor") pos = sel.anchor;
 
      else if (start == "end" || start === false) pos = sel.to;
 
      else pos = sel.from;
 
      return copyPos(pos);
 
    },
 
    somethingSelected: function() {return !posEq(this.sel.head, this.sel.anchor);},
 

	
 
    setCursor: docOperation(function(line, ch, extend) {
 
      var pos = clipPos(this, typeof line == "number" ? Pos(line, ch || 0) : line);
 
      if (extend) extendSelection(this, pos);
 
      else setSelection(this, pos, pos);
 
    }),
 
    setSelection: docOperation(function(anchor, head) {
 
      setSelection(this, clipPos(this, anchor), clipPos(this, head || anchor));
 
    }),
 
    extendSelection: docOperation(function(from, to) {
 
      extendSelection(this, clipPos(this, from), to && clipPos(this, to));
 
    }),
 

	
 
    getSelection: function(lineSep) {return this.getRange(this.sel.from, this.sel.to, lineSep);},
 
    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(this.history.maxGeneration);},
 

	
 
    markClean: function() {
 
      this.cleanGeneration = this.changeGeneration();
 
    },
 
    changeGeneration: function() {
 
      this.history.lastOp = this.history.lastOrigin = null;
 
      return this.history.generation;
 
    },
 
    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(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");
 
    },
 
    findMarksAt: function(pos) {
 
      pos = clipPos(this, pos);
 
      var markers = [], spans = getLine(this, pos.line).markedSpans;
 
      if (spans) for (var i = 0; i < spans.length; ++i) {
 
        var span = spans[i];
 
        if ((span.from == null || span.from <= pos.ch) &&
 
            (span.to == null || span.to >= pos.ch))
 
          markers.push(span.marker.parent || span.marker);
 
      }
 
      return markers;
 
    },
 
    getAllMarks: function() {
 
      var markers = [];
 
      this.iter(function(line) {
 
        var sps = line.markedSpans;
 
        if (sps) for (var i = 0; i < sps.length; ++i)
 
          if (sps[i].from != null) markers.push(sps[i].marker);
 
      });
 
      return markers;
 
    },
 

	
 
    posFromIndex: function(off) {
 
      var ch, lineNo = this.first;
 
      this.iter(function(line) {
 
        var sz = line.text.length + 1;
 
        if (sz > off) { ch = off; return true; }
 
        off -= sz;
 
        ++lineNo;
 
      });
 
      return clipPos(this, Pos(lineNo, ch));
 
    },
 
    indexFromPos: function (coords) {
 
      coords = clipPos(this, coords);
 
      var index = coords.ch;
 
      if (coords.line < this.first || coords.ch < 0) return 0;
 
      this.iter(this.first, coords.line, function (line) {
 
        index += line.text.length + 1;
 
      });
 
      return index;
 
    },
 

	
 
    copy: function(copyHistory) {
 
      var doc = new Doc(getLines(this, this.first, this.first + this.size), this.modeOption, this.first);
 
      doc.scrollTop = this.scrollTop; doc.scrollLeft = this.scrollLeft;
 
      doc.sel = {from: this.sel.from, to: this.sel.to, head: this.sel.head, anchor: this.sel.anchor,
 
                 shift: this.sel.shift, extend: false, goalColumn: this.sel.goalColumn};
 
      if (copyHistory) {
 
        doc.history.undoDepth = this.history.undoDepth;
 
        doc.setHistory(this.getHistory());
 
      }
 
      return doc;
 
    },
 

	
 
    linkedDoc: function(options) {
 
      if (!options) options = {};
 
      var from = this.first, to = this.first + this.size;
 
      if (options.from != null && options.from > from) from = options.from;
 
      if (options.to != null && options.to < to) to = options.to;
 
      var copy = new Doc(getLines(this, from, to), options.mode || this.modeOption, from);
 
      if (options.sharedHist) copy.history = this.history;
 
      (this.linked || (this.linked = [])).push({doc: copy, sharedHist: options.sharedHist});
 
      copy.linked = [{doc: this, isParent: true, sharedHist: options.sharedHist}];
 
      return copy;
 
    },
 
    unlinkDoc: function(other) {
 
      if (other instanceof CodeMirror) other = other.doc;
 
      if (this.linked) for (var i = 0; i < this.linked.length; ++i) {
 
        var link = this.linked[i];
 
        if (link.doc != other) continue;
 
        this.linked.splice(i, 1);
 
        other.unlinkDoc(this);
 
        break;
 
      }
 
      // If the histories were shared, split them again
 
      if (other.history == this.history) {
 
        var splitIds = [other.id];
 
        linkedDocs(other, function(doc) {splitIds.push(doc.id);}, true);
 
        other.history = makeHistory();
 
        other.history.done = copyHistoryArray(this.history.done, splitIds);
 
        other.history.undone = copyHistoryArray(this.history.undone, splitIds);
 
      }
 
    },
 
    iterLinkedDocs: function(f) {linkedDocs(this, f);},
 

	
 
    getMode: function() {return this.mode;},
 
    getEditor: function() {return this.cm;}
 
  });
 

	
 
  Doc.prototype.eachLine = Doc.prototype.iter;
 

	
 
  // The Doc methods that should be available on CodeMirror instances
 
  var dontDelegate = "iter insert remove copy getEditor".split(" ");
 
  for (var prop in Doc.prototype) if (Doc.prototype.hasOwnProperty(prop) && indexOf(dontDelegate, prop) < 0)
 
    CodeMirror.prototype[prop] = (function(method) {
 
      return function() {return method.apply(this.doc, arguments);};
 
    })(Doc.prototype[prop]);
 

	
 
  eventMixin(Doc);
 

	
 
  function linkedDocs(doc, f, sharedHistOnly) {
 
    function propagate(doc, skip, sharedHist) {
 
      if (doc.linked) for (var i = 0; i < doc.linked.length; ++i) {
 
        var rel = doc.linked[i];
 
        if (rel.doc == skip) continue;
 
        var shared = sharedHist && rel.sharedHist;
 
        if (sharedHistOnly && !shared) continue;
 
        f(rel.doc, shared);
 
        propagate(rel.doc, doc, shared);
 
      }
 
    }
 
    propagate(doc, null, true);
 
  }
 

	
 
  function attachDoc(cm, doc) {
 
    if (doc.cm) throw new Error("This document is already in use.");
 
    cm.doc = doc;
 
    doc.cm = cm;
 
    estimateLineHeights(cm);
 
    loadMode(cm);
 
    if (!cm.options.lineWrapping) computeMaxLength(cm);
 
    cm.options.mode = doc.modeOption;
 
    regChange(cm);
 
  }
 

	
 
  // LINE UTILITIES
 

	
 
  function getLine(chunk, n) {
 
    n -= chunk.first;
 
    while (!chunk.lines) {
 
      for (var i = 0;; ++i) {
 
        var child = chunk.children[i], sz = child.chunkSize();
 
        if (n < sz) { chunk = child; break; }
 
        n -= sz;
 
      }
 
    }
 
    return chunk.lines[n];
 
  }
 

	
 
  function getBetween(doc, start, end) {
 
    var out = [], n = start.line;
 
    doc.iter(start.line, end.line + 1, function(line) {
 
      var text = line.text;
 
      if (n == end.line) text = text.slice(0, end.ch);
 
      if (n == start.line) text = text.slice(start.ch);
 
      out.push(text);
 
      ++n;
 
    });
 
    return out;
 
  }
 
  function getLines(doc, from, to) {
 
    var out = [];
 
    doc.iter(from, to, function(line) { out.push(line.text); });
 
    return out;
 
  }
 

	
 
  function updateLineHeight(line, height) {
 
    var diff = height - line.height;
 
    for (var n = line; n; n = n.parent) n.height += diff;
 
  }
 

	
 
  function lineNo(line) {
 
    if (line.parent == null) return null;
 
    var cur = line.parent, no = indexOf(cur.lines, line);
 
    for (var chunk = cur.parent; chunk; cur = chunk, chunk = chunk.parent) {
 
      for (var i = 0;; ++i) {
 
        if (chunk.children[i] == cur) break;
 
        no += chunk.children[i].chunkSize();
 
      }
 
    }
 
    return no + cur.first;
 
  }
 

	
 
  function lineAtHeight(chunk, h) {
 
    var n = chunk.first;
 
    outer: do {
 
      for (var i = 0, e = chunk.children.length; i < e; ++i) {
 
        var child = chunk.children[i], ch = child.height;
 
        if (h < ch) { chunk = child; continue outer; }
 
        h -= ch;
 
        n += child.chunkSize();
 
      }
 
      return n;
 
    } while (!chunk.lines);
 
    for (var i = 0, e = chunk.lines.length; i < e; ++i) {
 
      var line = chunk.lines[i], lh = line.height;
 
      if (h < lh) break;
 
      h -= lh;
 
    }
 
    return n + i;
 
  }
 

	
 
  function heightAtLine(cm, lineObj) {
 
    lineObj = visualLine(cm.doc, lineObj);
 

	
 
    var h = 0, chunk = lineObj.parent;
 
    for (var i = 0; i < chunk.lines.length; ++i) {
 
      var line = chunk.lines[i];
 
      if (line == lineObj) break;
 
      else h += line.height;
 
    }
 
    for (var p = chunk.parent; p; chunk = p, p = chunk.parent) {
 
      for (var i = 0; i < p.children.length; ++i) {
 
        var cur = p.children[i];
 
        if (cur == chunk) break;
 
        else h += cur.height;
 
      }
 
    }
 
    return h;
 
  }
 

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

	
 
  // HISTORY
 

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

	
 
  function historyChangeFromChange(doc, change) {
 
    var histChange = {from: change.from, to: changeEnd(change), text: getBetween(doc, change.from, change.to)};
 
    var from = { line: change.from.line, ch: change.from.ch };
 
    var histChange = {from: from, to: changeEnd(change), text: getBetween(doc, change.from, change.to)};
 
    attachLocalSpans(doc, histChange, change.from.line, change.to.line + 1);
 
    linkedDocs(doc, function(doc) {attachLocalSpans(doc, histChange, change.from.line, change.to.line + 1);}, true);
 
    return histChange;
 
  }
 

	
 
  function addToHistory(doc, change, selAfter, opId) {
 
    var hist = doc.history;
 
    hist.undone.length = 0;
 
    var time = +new Date, cur = lst(hist.done);
 

	
 
    if (cur &&
 
        (hist.lastOp == opId ||
 
         hist.lastOrigin == change.origin && change.origin &&
 
         ((change.origin.charAt(0) == "+" && doc.cm && hist.lastTime > time - doc.cm.options.historyEventDelay) ||
 
          change.origin.charAt(0) == "*"))) {
 
      // Merge this change into the last event
 
      var last = lst(cur.changes);
 
      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();
 
    }
 
    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]);
 
    }
 
    return !out ? spans : out.length ? out : null;
 
  }
 

	
 
  function getOldSpans(doc, change) {
 
    var found = change["spans_" + doc.id];
 
    if (!found) return null;
 
    for (var i = 0, nw = []; i < change.text.length; ++i)
 
      nw.push(removeClearedSpans(found[i]));
 
    return nw;
 
  }
 

	
 
  // Used both to provide a JSON-safe object in .getHistory, and, when
 
  // detaching a document, to split the history in two
 
  function copyHistoryArray(events, newGroup) {
 
    for (var i = 0, copy = []; i < events.length; ++i) {
 
      var event = events[i], changes = event.changes, newChanges = [];
 
      copy.push({changes: newChanges, anchorBefore: event.anchorBefore, headBefore: event.headBefore,
 
                 anchorAfter: event.anchorAfter, headAfter: event.headAfter});
 
      for (var j = 0; j < changes.length; ++j) {
 
        var change = changes[j], m;
 
        newChanges.push({from: change.from, to: change.to, text: change.text});
 
        if (newGroup) for (var prop in change) if (m = prop.match(/^spans_(\d+)$/)) {
 
          if (indexOf(newGroup, Number(m[1])) > -1) {
 
            lst(newChanges)[prop] = change[prop];
 
            delete change[prop];
 
          }
 
        }
 
      }
 
    }
 
    return copy;
 
  }
 

	
 
  // Rebasing/resetting history to deal with externally-sourced changes
 

	
 
  function rebaseHistSel(pos, from, to, diff) {
 
    if (to < pos.line) {
 
      pos.line += diff;
 
    } else if (from < pos.line) {
 
      pos.line = from;
 
      pos.ch = 0;
 
    }
 
  }
 

	
 
  // Tries to rebase an array of history events given a change in the
 
  // document. If the change touches the same lines as the event, the
 
  // event, and everything 'behind' it, is discarded. If the change is
 
  // before the event, the event's positions are updated. Uses a
 
  // copy-on-write scheme for the positions, to avoid having to
 
@@ -5090,457 +5163,468 @@ window.CodeMirror = (function() {
 
      }
 
    }
 
  }
 

	
 
  function rebaseHist(hist, change) {
 
    var from = change.from.line, to = change.to.line, diff = change.text.length - (to - from) - 1;
 
    rebaseHistArray(hist.done, from, to, diff);
 
    rebaseHistArray(hist.undone, from, to, diff);
 
  }
 

	
 
  // EVENT OPERATORS
 

	
 
  function stopMethod() {e_stop(this);}
 
  // Ensure an event has a stop method.
 
  function addStop(event) {
 
    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;
 
    }
 
    if (mac && e.ctrlKey && b == 1) b = 3;
 
    return b;
 
  }
 

	
 
  // EVENT HANDLING
 

	
 
  function on(emitter, type, f) {
 
    if (emitter.addEventListener)
 
      emitter.addEventListener(type, f, false);
 
    else if (emitter.attachEvent)
 
      emitter.attachEvent("on" + type, f);
 
    else {
 
      var map = emitter._handlers || (emitter._handlers = {});
 
      var arr = map[type] || (map[type] = []);
 
      arr.push(f);
 
    }
 
  }
 

	
 
  function off(emitter, type, f) {
 
    if (emitter.removeEventListener)
 
      emitter.removeEventListener(type, f, false);
 
    else if (emitter.detachEvent)
 
      emitter.detachEvent("on" + type, f);
 
    else {
 
      var arr = emitter._handlers && emitter._handlers[type];
 
      if (!arr) return;
 
      for (var i = 0; i < arr.length; ++i)
 
        if (arr[i] == f) { arr.splice(i, 1); break; }
 
    }
 
  }
 

	
 
  function signal(emitter, type /*, values...*/) {
 
    var arr = emitter._handlers && emitter._handlers[type];
 
    if (!arr) return;
 
    var args = Array.prototype.slice.call(arguments, 2);
 
    for (var i = 0; i < arr.length; ++i) arr[i].apply(null, args);
 
  }
 

	
 
  var delayedCallbacks, delayedCallbackDepth = 0;
 
  function signalLater(emitter, type /*, values...*/) {
 
    var arr = emitter._handlers && emitter._handlers[type];
 
    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 signalDOMEvent(cm, e, override) {
 
    signal(cm, override || e.type, cm, e);
 
    return e_defaultPrevented(e) || e.codemirrorIgnore;
 
  }
 

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

	
 
  CodeMirror.on = on; CodeMirror.off = off; CodeMirror.signal = signal;
 

	
 
  function eventMixin(ctor) {
 
    ctor.prototype.on = function(type, f) {on(this, type, f);};
 
    ctor.prototype.off = function(type, f) {off(this, type, f);};
 
  }
 

	
 
  // MISC UTILITIES
 

	
 
  // Number of pixels added to scroller and sizer to hide scrollbar
 
  var scrollerCutOff = 30;
 

	
 
  // Returned or thrown by various protocols to signal 'I'm not
 
  // handling this'.
 
  var Pass = CodeMirror.Pass = {toString: function(){return "CodeMirror.Pass";}};
 

	
 
  function Delayed() {this.id = null;}
 
  Delayed.prototype = {set: function(ms, f) {clearTimeout(this.id); this.id = setTimeout(f, ms);}};
 

	
 
  // Counts the column offset in a string, taking tabs into account.
 
  // Used mostly to find indentation.
 
  function countColumn(string, end, tabSize, startIndex, startValue) {
 
    if (end == null) {
 
      end = string.search(/[^\s\u00a0]/);
 
      if (end == -1) end = string.length;
 
    }
 
    for (var i = startIndex || 0, n = startValue || 0; i < end; ++i) {
 
      if (string.charAt(i) == "\t") n += tabSize - (n % tabSize);
 
      else ++n;
 
    }
 
    return n;
 
  }
 
  CodeMirror.countColumn = countColumn;
 

	
 
  var spaceStrs = [""];
 
  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 {
 
      // 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;
 
    var inst = new Obj();
 
    if (props) copyObj(props, inst);
 
    return inst;
 
  }
 

	
 
  function copyObj(obj, target) {
 
    if (!target) target = {};
 
    for (var prop in obj) if (obj.hasOwnProperty(prop)) target[prop] = obj[prop];
 
    return target;
 
  }
 

	
 
  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\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]/;
 

	
 
  // DOM UTILITIES
 

	
 
  function elt(tag, content, className, style) {
 
    var e = document.createElement(tag);
 
    if (className) e.className = className;
 
    if (style) e.style.cssText = style;
 
    if (typeof content == "string") setTextContent(e, content);
 
    else if (content) for (var i = 0; i < content.length; ++i) e.appendChild(content[i]);
 
    return e;
 
  }
 

	
 
  function removeChildren(e) {
 
    for (var count = e.childNodes.length; count > 0; --count)
 
      e.removeChild(e.firstChild);
 
    return e;
 
  }
 

	
 
  function removeChildrenAndAdd(parent, e) {
 
    return removeChildren(parent).appendChild(e);
 
  }
 

	
 
  function setTextContent(e, str) {
 
    if (ie_lt9) {
 
      e.innerHTML = "";
 
      e.appendChild(document.createTextNode(str));
 
    } else e.textContent = str;
 
  }
 

	
 
  function getRect(node) {
 
    return node.getBoundingClientRect();
 
  }
 
  CodeMirror.replaceGetRect = function(f) { getRect = f; };
 

	
 
  // FEATURE DETECTION
 

	
 
  // Detect drag-and-drop
 
  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 tests matches the
 
  // character combinations that suffer from this phenomenon on the
 
  // various browsers.
 
  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)
 
  else if (webkit && !/Chrome\/(?:29|[3-9]\d|\d\d\d)\./.test(navigator.userAgent))
 
    spanAffectsWrapping = function(str, i) {
 
      if (i > 1 && str.charCodeAt(i - 1) == 45 && /\w/.test(str.charAt(i - 2)) && /[^\-?\.]/.test(str.charAt(i)))
 
        return true;
 
      if (i > 1 && str.charCodeAt(i - 1) == 45) {
 
        if (/\w/.test(str.charAt(i - 2)) && /[^\-?\.]/.test(str.charAt(i))) return true;
 
        if (i > 2 && /[\d\.,]/.test(str.charAt(i - 2)) && /[\d\.,]/.test(str.charAt(i))) return false;
 
      }
 
      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;
 
  function zeroWidthElement(measure) {
 
    if (zwspSupported == null) {
 
      var test = elt("span", "\u200b");
 
      removeChildrenAndAdd(measure, elt("span", [test, document.createTextNode("x")]));
 
      if (measure.firstChild.offsetHeight != 0)
 
        zwspSupported = test.offsetWidth <= 1 && test.offsetHeight > 2 && !ie_lt8;
 
    }
 
    if (zwspSupported) return elt("span", "\u200b");
 
    else return elt("span", "\u00a0", null, "display: inline-block; width: 1px; margin-right: -1px");
 
  }
 

	
 
  // See if "".split is the broken IE version, if so, provide an
 
  // alternative way to split lines.
 
  var splitLines = "\n\nb".split(/\n/).length != 3 ? function(string) {
 
    var pos = 0, result = [], l = string.length;
 
    while (pos <= l) {
 
      var nl = string.indexOf("\n", pos);
 
      if (nl == -1) nl = string.length;
 
      var line = string.slice(pos, string.charAt(nl - 1) == "\r" ? nl - 1 : nl);
 
      var rt = line.indexOf("\r");
 
      if (rt != -1) {
 
        result.push(line.slice(0, rt));
 
        pos += rt + 1;
 
      } else {
 
        result.push(line);
 
        pos = nl + 1;
 
      }
 
    }
 
    return result;
 
  } : function(string){return string.split(/\r\n?|\n/);};
 
  CodeMirror.splitLines = splitLines;
 

	
 
  var hasSelection = window.getSelection ? function(te) {
 
    try { return te.selectionStart != te.selectionEnd; }
 
    catch(e) { return false; }
 
  } : function(te) {
 
    try {var range = te.ownerDocument.selection.createRange();}
 
    catch(e) {}
 
    if (!range || range.parentElement() != te) return false;
 
    return range.compareEndPoints("StartToEnd", range) != 0;
 
  };
 

	
 
  var hasCopyEvent = (function() {
 
    var e = elt("div");
 
    if ("oncopy" in e) return true;
 
    e.setAttribute("oncopy", "return;");
 
    return typeof e.oncopy == 'function';
 
  })();
 

	
 
  // KEY NAMING
 

	
 
  var keyNames = {3: "Enter", 8: "Backspace", 9: "Tab", 13: "Enter", 16: "Shift", 17: "Ctrl", 18: "Alt",
 
                  19: "Pause", 20: "CapsLock", 27: "Esc", 32: "Space", 33: "PageUp", 34: "PageDown", 35: "End",
 
                  36: "Home", 37: "Left", 38: "Up", 39: "Right", 40: "Down", 44: "PrintScrn", 45: "Insert",
 
                  46: "Delete", 59: ";", 91: "Mod", 92: "Mod", 93: "Mod", 109: "-", 107: "=", 127: "Delete",
 
                  186: ";", 187: "=", 188: ",", 189: "-", 190: ".", 191: "/", 192: "`", 219: "[", 220: "\\",
 
                  221: "]", 222: "'", 63276: "PageUp", 63277: "PageDown", 63275: "End", 63273: "Home",
 
                  63234: "Left", 63232: "Up", 63235: "Right", 63233: "Down", 63302: "Insert", 63272: "Delete"};
 
  CodeMirror.keyNames = keyNames;
 
  (function() {
 
    // Number keys
 
    for (var i = 0; i < 10; i++) keyNames[i + 48] = String(i);
 
    // Alphabetic keys
 
    for (var i = 65; i <= 90; i++) keyNames[i] = String.fromCharCode(i);
 
    // Function keys
 
    for (var i = 1; i <= 12; i++) keyNames[i + 111] = keyNames[i + 63235] = "F" + i;
 
  })();
 

	
 
  // BIDI HELPERS
 

	
 
  function iterateBidiSections(order, from, to, f) {
 
    if (!order) return f(from, to, "ltr");
 
    var found = false;
 
    for (var i = 0; i < order.length; ++i) {
 
      var part = order[i];
 
      if (part.from < to && part.to > from || from == to && part.to == from)
 
      if (part.from < to && part.to > from || from == to && part.to == from) {
 
        f(Math.max(part.from, from), Math.min(part.to, to), part.level == 1 ? "rtl" : "ltr");
 
    }
 
        found = true;
 
      }
 
    }
 
    if (!found) f(from, to, "ltr");
 
  }
 

	
 
  function bidiLeft(part) { return part.level % 2 ? part.to : part.from; }
 
  function bidiRight(part) { return part.level % 2 ? part.from : part.to; }
 

	
 
  function lineLeft(line) { var order = getOrder(line); return order ? bidiLeft(order[0]) : 0; }
 
  function lineRight(line) {
 
    var order = getOrder(line);
 
    if (!order) return line.text.length;
 
    return bidiRight(lst(order));
 
  }
 

	
 
  function lineStart(cm, lineN) {
 
    var line = getLine(cm.doc, lineN);
 
    var visual = visualLine(cm.doc, line);
 
    if (visual != line) lineN = lineNo(visual);
 
    var order = getOrder(visual);
 
    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 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 {
 
        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);
 
      }
 
    }
 
  }
 

	
 
  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;
 
@@ -5616,100 +5700,100 @@ window.CodeMirror = (function() {
 

	
 
      // W4. A single European separator between two European numbers
 
      // changes to a European number. A single common separator between
 
      // two numbers of the same type changes to that type.
 
      for (var i = 1, prev = types[0]; i < len - 1; ++i) {
 
        var type = types[i];
 
        if (type == "+" && prev == "1" && types[i+1] == "1") types[i] = "1";
 
        else if (type == "," && prev == types[i+1] &&
 
                 (prev == "1" || prev == "n")) types[i] = prev;
 
        prev = type;
 
      }
 

	
 
      // W5. A sequence of European terminators adjacent to European
 
      // numbers changes to all European numbers.
 
      // W6. Otherwise, separators and terminators change to Other
 
      // Neutral.
 
      for (var i = 0; i < len; ++i) {
 
        var type = types[i];
 
        if (type == ",") types[i] = "N";
 
        else if (type == "%") {
 
          for (var end = i + 1; end < len && types[end] == "%"; ++end) {}
 
          var replace = (i && types[i-1] == "!") || (end < len - 1 && types[end] == "1") ? "1" : "N";
 
          for (var j = i; j < end; ++j) types[j] = replace;
 
          i = end - 1;
 
        }
 
      }
 

	
 
      // W7. Search backwards from each instance of a European number
 
      // until the first strong type (R, L, or sor) is found. If an L is
 
      // found, then change the type of the European number to L.
 
      for (var i = 0, cur = outerType; i < len; ++i) {
 
        var type = types[i];
 
        if (cur == "L" && type == "1") types[i] = "L";
 
        else if (isStrong.test(type)) cur = type;
 
      }
 

	
 
      // N1. A sequence of neutrals takes the direction of the
 
      // surrounding strong text if the text on both sides has the same
 
      // direction. European and Arabic numbers act as if they were R in
 
      // terms of their influence on neutrals. Start-of-level-run (sor)
 
      // and end-of-level-run (eor) are used at level run boundaries.
 
      // N2. Any remaining neutrals take the embedding direction.
 
      for (var i = 0; i < len; ++i) {
 
        if (isNeutral.test(types[i])) {
 
          for (var end = i + 1; end < len && isNeutral.test(types[end]); ++end) {}
 
          var before = (i ? types[i-1] : outerType) == "L";
 
          var after = (end < len - 1 ? types[end] : outerType) == "L";
 
          var replace = before || after ? "L" : "R";
 
          for (var j = i; j < end; ++j) types[j] = replace;
 
          i = end - 1;
 
        }
 
      }
 

	
 
      // Here we depart from the documented algorithm, in order to avoid
 
      // building up an actual levels array. Since there are only three
 
      // levels (0, 1, 2) in an implementation that doesn't take
 
      // explicit embedding into account, we can build up the order on
 
      // the fly, without following the level-based algorithm.
 
      var order = [], m;
 
      for (var i = 0; i < len;) {
 
        if (countsAsLeft.test(types[i])) {
 
          var start = i;
 
          for (++i; i < len && countsAsLeft.test(types[i]); ++i) {}
 
          order.push({from: start, to: i, level: 0});
 
        } else {
 
          var pos = i, at = order.length;
 
          for (++i; i < len && types[i] != "L"; ++i) {}
 
          for (var j = pos; j < i;) {
 
            if (countsAsNum.test(types[j])) {
 
              if (pos < j) order.splice(at, 0, {from: pos, to: j, level: 1});
 
              var nstart = j;
 
              for (++j; j < i && countsAsNum.test(types[j]); ++j) {}
 
              order.splice(at, 0, {from: nstart, to: j, level: 2});
 
              pos = j;
 
            } else ++j;
 
          }
 
          if (pos < i) order.splice(at, 0, {from: pos, to: i, level: 1});
 
        }
 
      }
 
      if (order[0].level == 1 && (m = str.match(/^\s+/))) {
 
        order[0].from = m[0].length;
 
        order.unshift({from: 0, to: m[0].length, level: 0});
 
      }
 
      if (lst(order).level == 1 && (m = str.match(/\s+$/))) {
 
        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.14.0";
 
  CodeMirror.version = "3.15.0";
 

	
 
  return CodeMirror;
 
})();
rhodecode/public/js/mode/clike/clike.js
Show inline comments
 
@@ -65,193 +65,194 @@ CodeMirror.defineMode("clike", function(
 
        if (next == quote && !escaped) {end = true; break;}
 
        escaped = !escaped && next == "\\";
 
      }
 
      if (end || !(escaped || multiLineStrings))
 
        state.tokenize = null;
 
      return "string";
 
    };
 
  }
 

	
 
  function tokenComment(stream, state) {
 
    var maybeEnd = false, ch;
 
    while (ch = stream.next()) {
 
      if (ch == "/" && maybeEnd) {
 
        state.tokenize = null;
 
        break;
 
      }
 
      maybeEnd = (ch == "*");
 
    }
 
    return "comment";
 
  }
 

	
 
  function Context(indented, column, type, align, prev) {
 
    this.indented = indented;
 
    this.column = column;
 
    this.type = type;
 
    this.align = align;
 
    this.prev = prev;
 
  }
 
  function pushContext(state, col, type) {
 
    var indent = state.indented;
 
    if (state.context && state.context.type == "statement")
 
      indent = state.context.indented;
 
    return state.context = new Context(indent, col, type, null, state.context);
 
  }
 
  function popContext(state) {
 
    var t = state.context.type;
 
    if (t == ")" || t == "]" || t == "}")
 
      state.indented = state.context.indented;
 
    return state.context = state.context.prev;
 
  }
 

	
 
  // Interface
 

	
 
  return {
 
    startState: function(basecolumn) {
 
      return {
 
        tokenize: null,
 
        context: new Context((basecolumn || 0) - indentUnit, 0, "top", false),
 
        indented: 0,
 
        startOfLine: true
 
      };
 
    },
 

	
 
    token: function(stream, state) {
 
      var ctx = state.context;
 
      if (stream.sol()) {
 
        if (ctx.align == null) ctx.align = false;
 
        state.indented = stream.indentation();
 
        state.startOfLine = true;
 
      }
 
      if (stream.eatSpace()) return null;
 
      curPunc = null;
 
      var style = (state.tokenize || tokenBase)(stream, state);
 
      if (style == "comment" || style == "meta") return style;
 
      if (ctx.align == null) ctx.align = true;
 

	
 
      if ((curPunc == ";" || curPunc == ":" || curPunc == ",") && ctx.type == "statement") popContext(state);
 
      else if (curPunc == "{") pushContext(state, stream.column(), "}");
 
      else if (curPunc == "[") pushContext(state, stream.column(), "]");
 
      else if (curPunc == "(") pushContext(state, stream.column(), ")");
 
      else if (curPunc == "}") {
 
        while (ctx.type == "statement") ctx = popContext(state);
 
        if (ctx.type == "}") ctx = popContext(state);
 
        while (ctx.type == "statement") ctx = popContext(state);
 
      }
 
      else if (curPunc == ctx.type) popContext(state);
 
      else if (((ctx.type == "}" || ctx.type == "top") && curPunc != ';') || (ctx.type == "statement" && curPunc == "newstatement"))
 
        pushContext(state, stream.column(), "statement");
 
      state.startOfLine = false;
 
      return style;
 
    },
 

	
 
    indent: function(state, textAfter) {
 
      if (state.tokenize != tokenBase && state.tokenize != null) return CodeMirror.Pass;
 
      var ctx = state.context, firstChar = textAfter && textAfter.charAt(0);
 
      if (ctx.type == "statement" && firstChar == "}") ctx = ctx.prev;
 
      var closing = firstChar == ctx.type;
 
      if (ctx.type == "statement") return ctx.indented + (firstChar == "{" ? 0 : statementIndentUnit);
 
      else if (ctx.align && (!dontAlignCalls || ctx.type != ")")) return ctx.column + (closing ? 0 : 1);
 
      else if (ctx.type == ")" && !closing) return ctx.indented + statementIndentUnit;
 
      else return ctx.indented + (closing ? 0 : indentUnit);
 
    },
 

	
 
    electricChars: "{}",
 
    blockCommentStart: "/*",
 
    blockCommentEnd: "*/",
 
    lineComment: "//"
 
    lineComment: "//",
 
    fold: "brace"
 
  };
 
});
 

	
 
(function() {
 
  function words(str) {
 
    var obj = {}, words = str.split(" ");
 
    for (var i = 0; i < words.length; ++i) obj[words[i]] = true;
 
    return obj;
 
  }
 
  var cKeywords = "auto if break int case long char register continue return default short do sizeof " +
 
    "double static else struct entry switch extern typedef float union for unsigned " +
 
    "goto while enum void const signed volatile";
 

	
 
  function cppHook(stream, state) {
 
    if (!state.startOfLine) return false;
 
    for (;;) {
 
      if (stream.skipTo("\\")) {
 
        stream.next();
 
        if (stream.eol()) {
 
          state.tokenize = cppHook;
 
          break;
 
        }
 
      } else {
 
        stream.skipToEnd();
 
        state.tokenize = null;
 
        break;
 
      }
 
    }
 
    return "meta";
 
  }
 

	
 
  // C#-style strings where "" escapes a quote.
 
  function tokenAtString(stream, state) {
 
    var next;
 
    while ((next = stream.next()) != null) {
 
      if (next == '"' && !stream.eat('"')) {
 
        state.tokenize = null;
 
        break;
 
      }
 
    }
 
    return "string";
 
  }
 

	
 
  function mimes(ms, mode) {
 
    for (var i = 0; i < ms.length; ++i) CodeMirror.defineMIME(ms[i], mode);
 
  }
 

	
 
  mimes(["text/x-csrc", "text/x-c", "text/x-chdr"], {
 
    name: "clike",
 
    keywords: words(cKeywords),
 
    blockKeywords: words("case do else for if switch while struct"),
 
    atoms: words("null"),
 
    hooks: {"#": cppHook}
 
  });
 
  mimes(["text/x-c++src", "text/x-c++hdr"], {
 
    name: "clike",
 
    keywords: words(cKeywords + " asm dynamic_cast namespace reinterpret_cast try bool explicit new " +
 
                    "static_cast typeid catch operator template typename class friend private " +
 
                    "this using const_cast inline public throw virtual delete mutable protected " +
 
                    "wchar_t"),
 
    blockKeywords: words("catch class do else finally for if struct switch try while"),
 
    atoms: words("true false null"),
 
    hooks: {"#": cppHook}
 
  });
 
  CodeMirror.defineMIME("text/x-java", {
 
    name: "clike",
 
    keywords: words("abstract assert boolean break byte case catch char class const continue default " +
 
                    "do double else enum extends final finally float for goto if implements import " +
 
                    "instanceof int interface long native new package private protected public " +
 
                    "return short static strictfp super switch synchronized this throw throws transient " +
 
                    "try void volatile while"),
 
    blockKeywords: words("catch class do else finally for if switch try while"),
 
    atoms: words("true false null"),
 
    hooks: {
 
      "@": function(stream) {
 
        stream.eatWhile(/[\w\$_]/);
 
        return "meta";
 
      }
 
    }
 
  });
 
  CodeMirror.defineMIME("text/x-csharp", {
 
    name: "clike",
 
    keywords: words("abstract as base break case catch checked class const continue" +
 
                    " default delegate do else enum event explicit extern finally fixed for" +
 
                    " foreach goto if implicit in interface internal is lock namespace new" +
 
                    " operator out override params private protected public readonly ref return sealed" +
 
                    " sizeof stackalloc static struct switch this throw try typeof unchecked" +
 
                    " unsafe using virtual void volatile while add alias ascending descending dynamic from get" +
 
                    " global group into join let orderby partial remove select set value var yield"),
 
    blockKeywords: words("catch class do else finally for foreach if struct switch try while"),
 
    builtin: words("Boolean Byte Char DateTime DateTimeOffset Decimal Double" +
 
                    " Guid Int16 Int32 Int64 Object SByte Single String TimeSpan UInt16 UInt32" +
 
                    " UInt64 bool byte char decimal double short int long object"  +
 
                    " sbyte float string ushort uint ulong"),
 
    atoms: words("true false null"),
 
    hooks: {
rhodecode/public/js/mode/coffeescript/coffeescript.js
Show inline comments
 
@@ -246,102 +246,103 @@ CodeMirror.defineMode('coffeescript', fu
 
            }
 
            return false;
 
        } else {
 
            state.scopes.shift();
 
            return false;
 
        }
 
    }
 

	
 
    function tokenLexer(stream, state) {
 
        var style = state.tokenize(stream, state);
 
        var current = stream.current();
 

	
 
        // Handle '.' connected identifiers
 
        if (current === '.') {
 
            style = state.tokenize(stream, state);
 
            current = stream.current();
 
            if (style === 'variable') {
 
                return 'variable';
 
            } else {
 
                return ERRORCLASS;
 
            }
 
        }
 

	
 
        // Handle scope changes.
 
        if (current === 'return') {
 
            state.dedent += 1;
 
        }
 
        if (((current === '->' || current === '=>') &&
 
                  !state.lambda &&
 
                  state.scopes[0].type == 'coffee' &&
 
                  stream.peek() === '')
 
               || style === 'indent') {
 
            indent(stream, state);
 
        }
 
        var delimiter_index = '[({'.indexOf(current);
 
        if (delimiter_index !== -1) {
 
            indent(stream, state, '])}'.slice(delimiter_index, delimiter_index+1));
 
        }
 
        if (indentKeywords.exec(current)){
 
            indent(stream, state);
 
        }
 
        if (current == 'then'){
 
            dedent(stream, state);
 
        }
 

	
 

	
 
        if (style === 'dedent') {
 
            if (dedent(stream, state)) {
 
                return ERRORCLASS;
 
            }
 
        }
 
        delimiter_index = '])}'.indexOf(current);
 
        if (delimiter_index !== -1) {
 
            if (dedent(stream, state)) {
 
                return ERRORCLASS;
 
            }
 
        }
 
        if (state.dedent > 0 && stream.eol() && state.scopes[0].type == 'coffee') {
 
            if (state.scopes.length > 1) state.scopes.shift();
 
            state.dedent -= 1;
 
        }
 

	
 
        return style;
 
    }
 

	
 
    var external = {
 
        startState: function(basecolumn) {
 
            return {
 
              tokenize: tokenBase,
 
              scopes: [{offset:basecolumn || 0, type:'coffee'}],
 
              lastToken: null,
 
              lambda: false,
 
              dedent: 0
 
          };
 
        },
 

	
 
        token: function(stream, state) {
 
            var style = tokenLexer(stream, state);
 

	
 
            state.lastToken = {style:style, content: stream.current()};
 

	
 
            if (stream.eol() && stream.lambda) {
 
                state.lambda = false;
 
            }
 

	
 
            return style;
 
        },
 

	
 
        indent: function(state) {
 
            if (state.tokenize != tokenBase) {
 
                return 0;
 
            }
 

	
 
            return state.scopes[0].offset;
 
        },
 

	
 
        lineComment: "#"
 
        lineComment: "#",
 
        fold: "indent"
 
    };
 
    return external;
 
});
 

	
 
CodeMirror.defineMIME('text/x-coffeescript', 'coffeescript');
rhodecode/public/js/mode/css/css.js
Show inline comments
 
@@ -10,482 +10,499 @@ CodeMirror.defineMode("css-base", functi
 
      atMediaTypes = parserConfig.atMediaTypes || {},
 
      atMediaFeatures = parserConfig.atMediaFeatures || {},
 
      propertyKeywords = parserConfig.propertyKeywords || {},
 
      colorKeywords = parserConfig.colorKeywords || {},
 
      valueKeywords = parserConfig.valueKeywords || {},
 
      allowNested = !!parserConfig.allowNested,
 
      type = null;
 

	
 
  function ret(style, tp) { type = tp; return style; }
 

	
 
  function tokenBase(stream, state) {
 
    var ch = stream.next();
 
    if (hooks[ch]) {
 
      // result[0] is style and result[1] is type
 
      var result = hooks[ch](stream, state);
 
      if (result !== false) return result;
 
    }
 
    if (ch == "@") {stream.eatWhile(/[\w\\\-]/); return ret("def", stream.current());}
 
    else if (ch == "=") ret(null, "compare");
 
    else if ((ch == "~" || ch == "|") && stream.eat("=")) return ret(null, "compare");
 
    else if (ch == "\"" || ch == "'") {
 
      state.tokenize = tokenString(ch);
 
      return state.tokenize(stream, state);
 
    }
 
    else if (ch == "#") {
 
      stream.eatWhile(/[\w\\\-]/);
 
      return ret("atom", "hash");
 
    }
 
    else if (ch == "!") {
 
      stream.match(/^\s*\w*/);
 
      return ret("keyword", "important");
 
    }
 
    else if (/\d/.test(ch)) {
 
      stream.eatWhile(/[\w.%]/);
 
      return ret("number", "unit");
 
    }
 
    else if (ch === "-") {
 
      if (/\d/.test(stream.peek())) {
 
        stream.eatWhile(/[\w.%]/);
 
        return ret("number", "unit");
 
      } else if (stream.match(/^[^-]+-/)) {
 
        return ret("meta", "meta");
 
      }
 
    }
 
    else if (/[,+>*\/]/.test(ch)) {
 
      return ret(null, "select-op");
 
    }
 
    else if (ch == "." && stream.match(/^-?[_a-z][_a-z0-9-]*/i)) {
 
      return ret("qualifier", "qualifier");
 
    }
 
    else if (ch == ":") {
 
      return ret("operator", ch);
 
    }
 
    else if (/[;{}\[\]\(\)]/.test(ch)) {
 
      return ret(null, ch);
 
    }
 
    else if (ch == "u" && stream.match("rl(")) {
 
      stream.backUp(1);
 
      state.tokenize = tokenParenthesized;
 
      return ret("property", "variable");
 
    }
 
    else {
 
      stream.eatWhile(/[\w\\\-]/);
 
      return ret("property", "variable");
 
    }
 
  }
 

	
 
  function tokenString(quote, nonInclusive) {
 
    return function(stream, state) {
 
      var escaped = false, ch;
 
      while ((ch = stream.next()) != null) {
 
        if (ch == quote && !escaped)
 
          break;
 
        escaped = !escaped && ch == "\\";
 
      }
 
      if (!escaped) {
 
        if (nonInclusive) stream.backUp(1);
 
        state.tokenize = tokenBase;
 
      }
 
      return ret("string", "string");
 
    };
 
  }
 

	
 
  function tokenParenthesized(stream, state) {
 
    stream.next(); // Must be '('
 
    if (!stream.match(/\s*[\"\']/, false))
 
      state.tokenize = tokenString(")", true);
 
    else
 
      state.tokenize = tokenBase;
 
    return ret(null, "(");
 
  }
 

	
 
  return {
 
    startState: function(base) {
 
      return {tokenize: tokenBase,
 
              baseIndent: base || 0,
 
              stack: []};
 
              stack: [],
 
              lastToken: null};
 
    },
 

	
 
    token: function(stream, state) {
 

	
 
      // Use these terms when applicable (see http://www.xanthir.com/blog/b4E50)
 
      //
 
      // rule** or **ruleset:
 
      // A selector + braces combo, or an at-rule.
 
      //
 
      // declaration block:
 
      // A sequence of declarations.
 
      //
 
      // declaration:
 
      // A property + colon + value combo.
 
      //
 
      // property value:
 
      // The entire value of a property.
 
      //
 
      // component value:
 
      // A single piece of a property value. Like the 5px in
 
      // text-shadow: 0 0 5px blue;. Can also refer to things that are
 
      // multiple terms, like the 1-4 terms that make up the background-size
 
      // portion of the background shorthand.
 
      //
 
      // term:
 
      // The basic unit of author-facing CSS, like a single number (5),
 
      // dimension (5px), string ("foo"), or function. Officially defined
 
      //  by the CSS 2.1 grammar (look for the 'term' production)
 
      //
 
      //
 
      // simple selector:
 
      // A single atomic selector, like a type selector, an attr selector, a
 
      // class selector, etc.
 
      //
 
      // compound selector:
 
      // One or more simple selectors without a combinator. div.example is
 
      // compound, div > .example is not.
 
      //
 
      // complex selector:
 
      // One or more compound selectors chained with combinators.
 
      //
 
      // combinator:
 
      // The parts of selectors that express relationships. There are four
 
      // currently - the space (descendant combinator), the greater-than
 
      // bracket (child combinator), the plus sign (next sibling combinator),
 
      // and the tilda (following sibling combinator).
 
      //
 
      // sequence of selectors:
 
      // One or more of the named type of selector chained with commas.
 

	
 
      state.tokenize = state.tokenize || tokenBase;
 
      if (state.tokenize == tokenBase && stream.eatSpace()) return null;
 
      var style = state.tokenize(stream, state);
 
      if (style && typeof style != "string") style = ret(style[0], style[1]);
 

	
 
      // Changing style returned based on context
 
      var context = state.stack[state.stack.length-1];
 
      if (style == "variable") {
 
        if (type == "variable-definition") state.stack.push("propertyValue");
 
        return "variable-2";
 
        return state.lastToken = "variable-2";
 
      } else if (style == "property") {
 
        var word = stream.current().toLowerCase();
 
        if (context == "propertyValue") {
 
          if (valueKeywords.hasOwnProperty(word)) {
 
            style = "string-2";
 
          } else if (colorKeywords.hasOwnProperty(word)) {
 
            style = "keyword";
 
          } else {
 
            style = "variable-2";
 
          }
 
        } else if (context == "rule") {
 
          if (!propertyKeywords.hasOwnProperty(word)) {
 
            style += " error";
 
          }
 
        } else if (context == "block") {
 
          // if a value is present in both property, value, or color, the order
 
          // of preference is property -> color -> value
 
          if (propertyKeywords.hasOwnProperty(word)) {
 
            style = "property";
 
          } else if (colorKeywords.hasOwnProperty(word)) {
 
            style = "keyword";
 
          } else if (valueKeywords.hasOwnProperty(word)) {
 
            style = "string-2";
 
          } else {
 
            style = "tag";
 
          }
 
        } else if (!context || context == "@media{") {
 
          style = "tag";
 
        } else if (context == "@media") {
 
          if (atMediaTypes[stream.current()]) {
 
            style = "attribute"; // Known attribute
 
          } else if (/^(only|not)$/.test(word)) {
 
            style = "keyword";
 
          } else if (word == "and") {
 
            style = "error"; // "and" is only allowed in @mediaType
 
          } else if (atMediaFeatures.hasOwnProperty(word)) {
 
            style = "error"; // Known property, should be in @mediaType(
 
          } else {
 
            // Unknown, expecting keyword or attribute, assuming attribute
 
            style = "attribute error";
 
          }
 
        } else if (context == "@mediaType") {
 
          if (atMediaTypes.hasOwnProperty(word)) {
 
            style = "attribute";
 
          } else if (word == "and") {
 
            style = "operator";
 
          } else if (/^(only|not)$/.test(word)) {
 
            style = "error"; // Only allowed in @media
 
          } else {
 
            // Unknown attribute or property, but expecting property (preceded
 
            // by "and"). Should be in parentheses
 
            style = "error";
 
          }
 
        } else if (context == "@mediaType(") {
 
          if (propertyKeywords.hasOwnProperty(word)) {
 
            // do nothing, remains "property"
 
          } else if (atMediaTypes.hasOwnProperty(word)) {
 
            style = "error"; // Known property, should be in parentheses
 
          } else if (word == "and") {
 
            style = "operator";
 
          } else if (/^(only|not)$/.test(word)) {
 
            style = "error"; // Only allowed in @media
 
          } else {
 
            style += " error";
 
          }
 
        } else if (context == "@import") {
 
          style = "tag";
 
        } else {
 
          style = "error";
 
        }
 
      } else if (style == "atom") {
 
        if(!context || context == "@media{" || context == "block") {
 
          style = "builtin";
 
        } else if (context == "propertyValue") {
 
          if (!/^#([0-9a-fA-f]{3}|[0-9a-fA-f]{6})$/.test(stream.current())) {
 
            style += " error";
 
          }
 
        } else {
 
          style = "error";
 
        }
 
      } else if (context == "@media" && type == "{") {
 
        style = "error";
 
      }
 

	
 
      // Push/pop context stack
 
      if (type == "{") {
 
        if (context == "@media" || context == "@mediaType") {
 
          state.stack.pop();
 
          state.stack[state.stack.length-1] = "@media{";
 
        }
 
        else {
 
          var newContext = allowNested ? "block" : "rule";
 
          state.stack.push(newContext);
 
        }
 
      }
 
      else if (type == "}") {
 
        var lastState = state.stack[state.stack.length - 1];
 
        if (lastState == "interpolation") style = "operator";
 
        if (context == "interpolation") style = "operator";
 
        state.stack.pop();
 
        if (context == "propertyValue") state.stack.pop();
 
      }
 
      else if (type == "interpolation") state.stack.push("interpolation");
 
      else if (type == "@media") state.stack.push("@media");
 
      else if (type == "@import") state.stack.push("@import");
 
      else if (context == "@media" && /\b(keyword|attribute)\b/.test(style))
 
        state.stack.push("@mediaType");
 
      else if (context == "@mediaType" && stream.current() == ",") state.stack.pop();
 
      else if (context == "@mediaType" && type == "(") state.stack.push("@mediaType(");
 
      else if (context == "@mediaType(" && type == ")") state.stack.pop();
 
      else if ((context == "rule" || context == "block") && type == ":") state.stack.push("propertyValue");
 
        state.stack[state.stack.length-1] = "@mediaType";
 
      else if (context == "@mediaType" && stream.current() == ",")
 
        state.stack[state.stack.length-1] = "@media";
 
      else if (type == "(") {
 
        if (context == "@media" || context == "@mediaType") {
 
          // Make sure @mediaType is used to avoid error on {
 
          state.stack[state.stack.length-1] = "@mediaType";
 
          state.stack.push("@mediaType(");
 
        }
 
      }
 
      else if (type == ")") {
 
        if (context == "propertyValue" && state.stack[state.stack.length-2] == "@mediaType(") {
 
          // In @mediaType( without closing ; after propertyValue
 
          state.stack.pop();
 
          state.stack.pop();
 
        }
 
        else if (context == "@mediaType(") {
 
          state.stack.pop();
 
        }
 
      }
 
      else if (type == ":" && state.lastToken == "property") state.stack.push("propertyValue");
 
      else if (context == "propertyValue" && type == ";") state.stack.pop();
 
      else if (context == "@import" && type == ";") state.stack.pop();
 
      return style;
 

	
 
      return state.lastToken = style;
 
    },
 

	
 
    indent: function(state, textAfter) {
 
      var n = state.stack.length;
 
      if (/^\}/.test(textAfter))
 
        n -= state.stack[state.stack.length-1] == "propertyValue" ? 2 : 1;
 
        n -= state.stack[n-1] == "propertyValue" ? 2 : 1;
 
      return state.baseIndent + n * indentUnit;
 
    },
 

	
 
    electricChars: "}",
 
    blockCommentStart: "/*",
 
    blockCommentEnd: "*/"
 
    blockCommentEnd: "*/",
 
    fold: "brace"
 
  };
 
});
 

	
 
(function() {
 
  function keySet(array) {
 
    var keys = {};
 
    for (var i = 0; i < array.length; ++i) {
 
      keys[array[i]] = true;
 
    }
 
    return keys;
 
  }
 

	
 
  var atMediaTypes = keySet([
 
    "all", "aural", "braille", "handheld", "print", "projection", "screen",
 
    "tty", "tv", "embossed"
 
  ]);
 

	
 
  var atMediaFeatures = keySet([
 
    "width", "min-width", "max-width", "height", "min-height", "max-height",
 
    "device-width", "min-device-width", "max-device-width", "device-height",
 
    "min-device-height", "max-device-height", "aspect-ratio",
 
    "min-aspect-ratio", "max-aspect-ratio", "device-aspect-ratio",
 
    "min-device-aspect-ratio", "max-device-aspect-ratio", "color", "min-color",
 
    "max-color", "color-index", "min-color-index", "max-color-index",
 
    "monochrome", "min-monochrome", "max-monochrome", "resolution",
 
    "min-resolution", "max-resolution", "scan", "grid"
 
  ]);
 

	
 
  var propertyKeywords = keySet([
 
    "align-content", "align-items", "align-self", "alignment-adjust",
 
    "alignment-baseline", "anchor-point", "animation", "animation-delay",
 
    "animation-direction", "animation-duration", "animation-iteration-count",
 
    "animation-name", "animation-play-state", "animation-timing-function",
 
    "appearance", "azimuth", "backface-visibility", "background",
 
    "background-attachment", "background-clip", "background-color",
 
    "background-image", "background-origin", "background-position",
 
    "background-repeat", "background-size", "baseline-shift", "binding",
 
    "bleed", "bookmark-label", "bookmark-level", "bookmark-state",
 
    "bookmark-target", "border", "border-bottom", "border-bottom-color",
 
    "border-bottom-left-radius", "border-bottom-right-radius",
 
    "border-bottom-style", "border-bottom-width", "border-collapse",
 
    "border-color", "border-image", "border-image-outset",
 
    "border-image-repeat", "border-image-slice", "border-image-source",
 
    "border-image-width", "border-left", "border-left-color",
 
    "border-left-style", "border-left-width", "border-radius", "border-right",
 
    "border-right-color", "border-right-style", "border-right-width",
 
    "border-spacing", "border-style", "border-top", "border-top-color",
 
    "border-top-left-radius", "border-top-right-radius", "border-top-style",
 
    "border-top-width", "border-width", "bottom", "box-decoration-break",
 
    "box-shadow", "box-sizing", "break-after", "break-before", "break-inside",
 
    "caption-side", "clear", "clip", "color", "color-profile", "column-count",
 
    "column-fill", "column-gap", "column-rule", "column-rule-color",
 
    "column-rule-style", "column-rule-width", "column-span", "column-width",
 
    "columns", "content", "counter-increment", "counter-reset", "crop", "cue",
 
    "cue-after", "cue-before", "cursor", "direction", "display",
 
    "dominant-baseline", "drop-initial-after-adjust",
 
    "drop-initial-after-align", "drop-initial-before-adjust",
 
    "drop-initial-before-align", "drop-initial-size", "drop-initial-value",
 
    "elevation", "empty-cells", "fit", "fit-position", "flex", "flex-basis",
 
    "flex-direction", "flex-flow", "flex-grow", "flex-shrink", "flex-wrap",
 
    "float", "float-offset", "font", "font-feature-settings", "font-family",
 
    "font-kerning", "font-language-override", "font-size", "font-size-adjust",
 
    "font-stretch", "font-style", "font-synthesis", "font-variant",
 
    "font-variant-alternates", "font-variant-caps", "font-variant-east-asian",
 
    "font-variant-ligatures", "font-variant-numeric", "font-variant-position",
 
    "font-weight", "grid-cell", "grid-column", "grid-column-align",
 
    "grid-column-sizing", "grid-column-span", "grid-columns", "grid-flow",
 
    "grid-row", "grid-row-align", "grid-row-sizing", "grid-row-span",
 
    "grid-rows", "grid-template", "hanging-punctuation", "height", "hyphens",
 
    "icon", "image-orientation", "image-rendering", "image-resolution",
 
    "inline-box-align", "justify-content", "left", "letter-spacing",
 
    "line-break", "line-height", "line-stacking", "line-stacking-ruby",
 
    "line-stacking-shift", "line-stacking-strategy", "list-style",
 
    "list-style-image", "list-style-position", "list-style-type", "margin",
 
    "margin-bottom", "margin-left", "margin-right", "margin-top",
 
    "marker-offset", "marks", "marquee-direction", "marquee-loop",
 
    "marquee-play-count", "marquee-speed", "marquee-style", "max-height",
 
    "max-width", "min-height", "min-width", "move-to", "nav-down", "nav-index",
 
    "nav-left", "nav-right", "nav-up", "opacity", "order", "orphans", "outline",
 
    "outline-color", "outline-offset", "outline-style", "outline-width",
 
    "overflow", "overflow-style", "overflow-wrap", "overflow-x", "overflow-y",
 
    "padding", "padding-bottom", "padding-left", "padding-right", "padding-top",
 
    "page", "page-break-after", "page-break-before", "page-break-inside",
 
    "page-policy", "pause", "pause-after", "pause-before", "perspective",
 
    "perspective-origin", "pitch", "pitch-range", "play-during", "position",
 
    "presentation-level", "punctuation-trim", "quotes", "rendering-intent",
 
    "resize", "rest", "rest-after", "rest-before", "richness", "right",
 
    "rotation", "rotation-point", "ruby-align", "ruby-overhang",
 
    "ruby-position", "ruby-span", "size", "speak", "speak-as", "speak-header",
 
    "speak-numeral", "speak-punctuation", "speech-rate", "stress", "string-set",
 
    "tab-size", "table-layout", "target", "target-name", "target-new",
 
    "target-position", "text-align", "text-align-last", "text-decoration",
 
    "text-decoration-color", "text-decoration-line", "text-decoration-skip",
 
    "text-decoration-style", "text-emphasis", "text-emphasis-color",
 
    "text-emphasis-position", "text-emphasis-style", "text-height",
 
    "text-indent", "text-justify", "text-outline", "text-shadow",
 
    "text-space-collapse", "text-transform", "text-underline-position",
 
    "text-indent", "text-justify", "text-outline", "text-overflow", "text-shadow",
 
    "text-size-adjust", "text-space-collapse", "text-transform", "text-underline-position",
 
    "text-wrap", "top", "transform", "transform-origin", "transform-style",
 
    "transition", "transition-delay", "transition-duration",
 
    "transition-property", "transition-timing-function", "unicode-bidi",
 
    "vertical-align", "visibility", "voice-balance", "voice-duration",
 
    "voice-family", "voice-pitch", "voice-range", "voice-rate", "voice-stress",
 
    "voice-volume", "volume", "white-space", "widows", "width", "word-break",
 
    "word-spacing", "word-wrap", "z-index",
 
    "word-spacing", "word-wrap", "z-index", "zoom",
 
    // SVG-specific
 
    "clip-path", "clip-rule", "mask", "enable-background", "filter", "flood-color",
 
    "flood-opacity", "lighting-color", "stop-color", "stop-opacity", "pointer-events",
 
    "color-interpolation", "color-interpolation-filters", "color-profile",
 
    "color-rendering", "fill", "fill-opacity", "fill-rule", "image-rendering",
 
    "marker", "marker-end", "marker-mid", "marker-start", "shape-rendering", "stroke",
 
    "stroke-dasharray", "stroke-dashoffset", "stroke-linecap", "stroke-linejoin",
 
    "stroke-miterlimit", "stroke-opacity", "stroke-width", "text-rendering",
 
    "baseline-shift", "dominant-baseline", "glyph-orientation-horizontal",
 
    "glyph-orientation-vertical", "kerning", "text-anchor", "writing-mode"
 
  ]);
 

	
 
  var colorKeywords = keySet([
 
    "aliceblue", "antiquewhite", "aqua", "aquamarine", "azure", "beige",
 
    "bisque", "black", "blanchedalmond", "blue", "blueviolet", "brown",
 
    "burlywood", "cadetblue", "chartreuse", "chocolate", "coral", "cornflowerblue",
 
    "cornsilk", "crimson", "cyan", "darkblue", "darkcyan", "darkgoldenrod",
 
    "darkgray", "darkgreen", "darkkhaki", "darkmagenta", "darkolivegreen",
 
    "darkorange", "darkorchid", "darkred", "darksalmon", "darkseagreen",
 
    "darkslateblue", "darkslategray", "darkturquoise", "darkviolet",
 
    "deeppink", "deepskyblue", "dimgray", "dodgerblue", "firebrick",
 
    "floralwhite", "forestgreen", "fuchsia", "gainsboro", "ghostwhite",
 
    "gold", "goldenrod", "gray", "green", "greenyellow", "honeydew",
 
    "hotpink", "indianred", "indigo", "ivory", "khaki", "lavender",
 
    "lavenderblush", "lawngreen", "lemonchiffon", "lightblue", "lightcoral",
 
    "lightcyan", "lightgoldenrodyellow", "lightgray", "lightgreen", "lightpink",
 
    "lightsalmon", "lightseagreen", "lightskyblue", "lightslategray",
 
    "lightsteelblue", "lightyellow", "lime", "limegreen", "linen", "magenta",
 
    "maroon", "mediumaquamarine", "mediumblue", "mediumorchid", "mediumpurple",
 
    "mediumseagreen", "mediumslateblue", "mediumspringgreen", "mediumturquoise",
 
    "mediumvioletred", "midnightblue", "mintcream", "mistyrose", "moccasin",
 
    "navajowhite", "navy", "oldlace", "olive", "olivedrab", "orange", "orangered",
 
    "orchid", "palegoldenrod", "palegreen", "paleturquoise", "palevioletred",
 
    "papayawhip", "peachpuff", "peru", "pink", "plum", "powderblue",
 
    "purple", "red", "rosybrown", "royalblue", "saddlebrown", "salmon",
 
    "sandybrown", "seagreen", "seashell", "sienna", "silver", "skyblue",
 
    "slateblue", "slategray", "snow", "springgreen", "steelblue", "tan",
 
    "teal", "thistle", "tomato", "turquoise", "violet", "wheat", "white",
 
    "whitesmoke", "yellow", "yellowgreen"
 
  ]);
 

	
 
  var valueKeywords = keySet([
 
    "above", "absolute", "activeborder", "activecaption", "afar",
 
    "after-white-space", "ahead", "alias", "all", "all-scroll", "alternate",
 
    "always", "amharic", "amharic-abegede", "antialiased", "appworkspace",
 
    "arabic-indic", "armenian", "asterisks", "auto", "avoid", "background",
 
    "backwards", "baseline", "below", "bidi-override", "binary", "bengali",
 
    "blink", "block", "block-axis", "bold", "bolder", "border", "border-box",
 
    "both", "bottom", "break-all", "break-word", "button", "button-bevel",
 
    "buttonface", "buttonhighlight", "buttonshadow", "buttontext", "cambodian",
 
    "capitalize", "caps-lock-indicator", "caption", "captiontext", "caret",
 
    "cell", "center", "checkbox", "circle", "cjk-earthly-branch",
 
    "cjk-heavenly-stem", "cjk-ideographic", "clear", "clip", "close-quote",
 
    "col-resize", "collapse", "compact", "condensed", "contain", "content",
 
    "content-box", "context-menu", "continuous", "copy", "cover", "crop",
 
    "cross", "crosshair", "currentcolor", "cursive", "dashed", "decimal",
 
    "decimal-leading-zero", "default", "default-button", "destination-atop",
 
    "destination-in", "destination-out", "destination-over", "devanagari",
 
    "disc", "discard", "document", "dot-dash", "dot-dot-dash", "dotted",
 
    "double", "down", "e-resize", "ease", "ease-in", "ease-in-out", "ease-out",
 
    "element", "ellipsis", "embed", "end", "ethiopic", "ethiopic-abegede",
 
    "ethiopic-abegede-am-et", "ethiopic-abegede-gez", "ethiopic-abegede-ti-er",
 
    "ethiopic-abegede-ti-et", "ethiopic-halehame-aa-er",
 
    "ethiopic-halehame-aa-et", "ethiopic-halehame-am-et",
 
    "ethiopic-halehame-gez", "ethiopic-halehame-om-et",
 
    "ethiopic-halehame-sid-et", "ethiopic-halehame-so-et",
 
    "ethiopic-halehame-ti-er", "ethiopic-halehame-ti-et",
 
    "ethiopic-halehame-tig", "ew-resize", "expanded", "extra-condensed",
 
    "extra-expanded", "fantasy", "fast", "fill", "fixed", "flat", "footnotes",
 
    "forwards", "from", "geometricPrecision", "georgian", "graytext", "groove",
 
    "gujarati", "gurmukhi", "hand", "hangul", "hangul-consonant", "hebrew",
 
    "help", "hidden", "hide", "higher", "highlight", "highlighttext",
 
    "hiragana", "hiragana-iroha", "horizontal", "hsl", "hsla", "icon", "ignore",
 
    "inactiveborder", "inactivecaption", "inactivecaptiontext", "infinite",
 
    "infobackground", "infotext", "inherit", "initial", "inline", "inline-axis",
 
    "inline-block", "inline-table", "inset", "inside", "intrinsic", "invert",
 
    "italic", "justify", "kannada", "katakana", "katakana-iroha", "khmer",
 
    "landscape", "lao", "large", "larger", "left", "level", "lighter",
 
    "line-through", "linear", "lines", "list-item", "listbox", "listitem",
 
    "local", "logical", "loud", "lower", "lower-alpha", "lower-armenian",
 
    "lower-greek", "lower-hexadecimal", "lower-latin", "lower-norwegian",
 
    "lower-roman", "lowercase", "ltr", "malayalam", "match",
 
    "media-controls-background", "media-current-time-display",
 
    "media-fullscreen-button", "media-mute-button", "media-play-button",
 
    "media-return-to-realtime-button", "media-rewind-button",
 
    "media-seek-back-button", "media-seek-forward-button", "media-slider",
 
    "media-sliderthumb", "media-time-remaining-display", "media-volume-slider",
 
    "media-volume-slider-container", "media-volume-sliderthumb", "medium",
 
    "menu", "menulist", "menulist-button", "menulist-text",
 
    "menulist-textfield", "menutext", "message-box", "middle", "min-intrinsic",
 
    "mix", "mongolian", "monospace", "move", "multiple", "myanmar", "n-resize",
 
    "narrower", "ne-resize", "nesw-resize", "no-close-quote", "no-drop",
 
    "no-open-quote", "no-repeat", "none", "normal", "not-allowed", "nowrap",
 
    "ns-resize", "nw-resize", "nwse-resize", "oblique", "octal", "open-quote",
 
    "optimizeLegibility", "optimizeSpeed", "oriya", "oromo", "outset",
 
    "outside", "overlay", "overline", "padding", "padding-box", "painted",
rhodecode/public/js/mode/css/scss_test.js
Show inline comments
 
(function() {
 
  var mode = CodeMirror.getMode({tabSize: 4}, "text/x-scss");
 
  function MT(name) { test.mode(name, mode, Array.prototype.slice.call(arguments, 1), "scss"); }
 

	
 
  MT('url_with_quotation',
 
    "[tag foo] { [property background][operator :][string-2 url]([string test.jpg]) }");
 

	
 
  MT('url_with_double_quotes',
 
    "[tag foo] { [property background][operator :][string-2 url]([string \"test.jpg\"]) }");
 

	
 
  MT('url_with_single_quotes',
 
    "[tag foo] { [property background][operator :][string-2 url]([string \'test.jpg\']) }");
 

	
 
  MT('string',
 
    "[def @import] [string \"compass/css3\"]");
 

	
 
  MT('important_keyword',
 
    "[tag foo] { [property background][operator :][string-2 url]([string \'test.jpg\']) [keyword !important] }");
 

	
 
  MT('variable',
 
    "[variable-2 $blue][operator :][atom #333]");
 

	
 
  MT('variable_as_attribute',
 
    "[tag foo] { [property color][operator :][variable-2 $blue] }");
 

	
 
  MT('numbers',
 
    "[tag foo] { [property padding][operator :][number 10px] [number 10] [number 10em] [number 8in] }");
 

	
 
  MT('number_percentage',
 
    "[tag foo] { [property width][operator :][number 80%] }");
 

	
 
  MT('selector',
 
    "[builtin #hello][qualifier .world]{}");
 

	
 
  MT('singleline_comment',
 
    "[comment // this is a comment]");
 

	
 
  MT('multiline_comment',
 
    "[comment /*foobar*/]");
 

	
 
  MT('attribute_with_hyphen',
 
    "[tag foo] { [property font-size][operator :][number 10px] }");
 

	
 
  MT('string_after_attribute',
 
    "[tag foo] { [property content][operator :][string \"::\"] }");
 

	
 
  MT('directives',
 
    "[def @include] [qualifier .mixin]");
 

	
 
  MT('basic_structure',
 
    "[tag p] { [property background][operator :][keyword red]; }");
 

	
 
  MT('nested_structure',
 
    "[tag p] { [tag a] { [property color][operator :][keyword red]; } }");
 

	
 
  MT('mixin',
 
    "[def @mixin] [tag table-base] {}");
 

	
 
  MT('number_without_semicolon',
 
    "[tag p] {[property width][operator :][number 12]}",
 
    "[tag a] {[property color][operator :][keyword red];}");
 

	
 
  MT('atom_in_nested_block',
 
    "[tag p] { [tag a] { [property color][operator :][atom #000]; } }");
 

	
 
  MT('interpolation_in_property',
 
    "[tag foo] { [operator #{][variable-2 $hello][operator }:][atom #000]; }");
 
    "[tag foo] { [operator #{][variable-2 $hello][operator }:][number 2]; }");
 

	
 
  MT('interpolation_in_selector',
 
    "[tag foo][operator #{][variable-2 $hello][operator }] { [property color][operator :][atom #000]; }");
 

	
 
  MT('interpolation_error',
 
    "[tag foo][operator #{][error foo][operator }] { [property color][operator :][atom #000]; }");
 

	
 
  MT("divide_operator",
 
    "[tag foo] { [property width][operator :][number 4] [operator /] [number 2] }");
 

	
 
  MT('nested_structure_with_id_selector',
 
    "[tag p] { [builtin #hello] { [property color][operator :][keyword red]; } }");
 
})();
rhodecode/public/js/mode/css/test.js
Show inline comments
 
(function() {
 
  var mode = CodeMirror.getMode({tabSize: 4}, "css");
 
  function MT(name) { test.mode(name, mode, Array.prototype.slice.call(arguments, 1)); }
 

	
 
  // Requires at least one media query
 
  MT("atMediaEmpty",
 
     "[def @media] [error {] }");
 

	
 
  MT("atMediaMultiple",
 
     "[def @media] [keyword not] [attribute screen] [operator and] ([property color]), [keyword not] [attribute print] [operator and] ([property color]) { }");
 

	
 
  MT("atMediaCheckStack",
 
     "[def @media] [attribute screen] { } [tag foo] { }");
 

	
 
  MT("atMediaCheckStack",
 
     "[def @media] [attribute screen] ([property color]) { } [tag foo] { }");
 

	
 
  MT("atMediaPropertyOnly",
 
     "[def @media] ([property color]) { } [tag foo] { }");
 

	
 
  MT("atMediaCheckStackInvalidAttribute",
 
     "[def @media] [attribute&error foobarhello] { [tag foo] { } }");
 

	
 
  MT("atMediaCheckStackInvalidAttribute",
 
     "[def @media] [attribute&error foobarhello] { } [tag foo] { }");
 

	
 
  // Error, because "and" is only allowed immediately preceding a media expression
 
  MT("atMediaInvalidAttribute",
 
     "[def @media] [attribute&error foobarhello] { }");
 

	
 
  // Error, because "and" is only allowed immediately preceding a media expression
 
  MT("atMediaInvalidAnd",
 
     "[def @media] [error and] [attribute screen] { }");
 

	
 
  // Error, because "not" is only allowed as the first item in each media query
 
  MT("atMediaInvalidNot",
 
     "[def @media] [attribute screen] [error not] ([error not]) { }");
 

	
 
  // Error, because "only" is only allowed as the first item in each media query
 
  MT("atMediaInvalidOnly",
 
     "[def @media] [attribute screen] [error only] ([error only]) { }");
 

	
 
  // Error, because "foobarhello" is neither a known type or property, but
 
  // property was expected (after "and"), and it should be in parenthese.
 
  MT("atMediaUnknownType",
 
     "[def @media] [attribute screen] [operator and] [error foobarhello] { }");
 

	
 
  // Error, because "color" is not a known type, but is a known property, and
 
  // should be in parentheses.
 
  MT("atMediaInvalidType",
 
     "[def @media] [attribute screen] [operator and] [error color] { }");
 

	
 
  // Error, because "print" is not a known property, but is a known type,
 
  // and should not be in parenthese.
 
  MT("atMediaInvalidProperty",
 
     "[def @media] [attribute screen] [operator and] ([error print]) { }");
 

	
 
  // Soft error, because "foobarhello" is not a known property or type.
 
  MT("atMediaUnknownProperty",
 
     "[def @media] [attribute screen] [operator and] ([property&error foobarhello]) { }");
 

	
 
  // Make sure nesting works with media queries
 
  MT("atMediaMaxWidthNested",
 
     "[def @media] [attribute screen] [operator and] ([property max-width][operator :] [number 25px]) { [tag foo] { } }");
 

	
 
  MT("tagSelector",
 
     "[tag foo] { }");
 

	
 
  MT("classSelector",
 
     "[qualifier .foo-bar_hello] { }");
 

	
 
  MT("idSelector",
 
     "[builtin #foo] { [error #foo] }");
 

	
 
  MT("tagSelectorUnclosed",
 
     "[tag foo] { [property margin][operator :] [number 0] } [tag bar] { }");
 

	
 
  MT("tagStringNoQuotes",
 
     "[tag foo] { [property font-family][operator :] [variable-2 hello] [variable-2 world]; }");
 

	
 
  MT("tagStringDouble",
 
     "[tag foo] { [property font-family][operator :] [string \"hello world\"]; }");
 

	
 
  MT("tagStringSingle",
 
     "[tag foo] { [property font-family][operator :] [string 'hello world']; }");
 

	
 
  MT("tagColorKeyword",
 
     "[tag foo] {" +
 
       "[property color][operator :] [keyword black];" +
 
       "[property color][operator :] [keyword navy];" +
 
       "[property color][operator :] [keyword yellow];" +
 
       "}");
 

	
 
  MT("tagColorHex3",
 
     "[tag foo] { [property background][operator :] [atom #fff]; }");
 

	
 
  MT("tagColorHex6",
 
     "[tag foo] { [property background][operator :] [atom #ffffff]; }");
 

	
 
  MT("tagColorHex4",
 
     "[tag foo] { [property background][operator :] [atom&error #ffff]; }");
 

	
 
  MT("tagColorHexInvalid",
 
     "[tag foo] { [property background][operator :] [atom&error #ffg]; }");
 

	
 
  MT("tagNegativeNumber",
 
     "[tag foo] { [property margin][operator :] [number -5px]; }");
 

	
 
  MT("tagPositiveNumber",
 
     "[tag foo] { [property padding][operator :] [number 5px]; }");
 

	
 
  MT("tagVendor",
 
     "[tag foo] { [meta -foo-][property box-sizing][operator :] [meta -foo-][string-2 border-box]; }");
 

	
 
  MT("tagBogusProperty",
 
     "[tag foo] { [property&error barhelloworld][operator :] [number 0]; }");
 

	
 
  MT("tagTwoProperties",
 
     "[tag foo] { [property margin][operator :] [number 0]; [property padding][operator :] [number 0]; }");
 

	
 
  MT("tagTwoPropertiesURL",
 
     "[tag foo] { [property background][operator :] [string-2 url]([string //example.com/foo.png]); [property padding][operator :] [number 0]; }");
 

	
 
  MT("commentSGML",
 
     "[comment <!--comment-->]");
 
})();
rhodecode/public/js/mode/groovy/groovy.js
Show inline comments
 
@@ -110,101 +110,102 @@ CodeMirror.defineMode("groovy", function
 
  function tokenComment(stream, state) {
 
    var maybeEnd = false, ch;
 
    while (ch = stream.next()) {
 
      if (ch == "/" && maybeEnd) {
 
        state.tokenize.pop();
 
        break;
 
      }
 
      maybeEnd = (ch == "*");
 
    }
 
    return "comment";
 
  }
 

	
 
  function expectExpression(last) {
 
    return !last || last == "operator" || last == "->" || /[\.\[\{\(,;:]/.test(last) ||
 
      last == "newstatement" || last == "keyword" || last == "proplabel";
 
  }
 

	
 
  function Context(indented, column, type, align, prev) {
 
    this.indented = indented;
 
    this.column = column;
 
    this.type = type;
 
    this.align = align;
 
    this.prev = prev;
 
  }
 
  function pushContext(state, col, type) {
 
    return state.context = new Context(state.indented, col, type, null, state.context);
 
  }
 
  function popContext(state) {
 
    var t = state.context.type;
 
    if (t == ")" || t == "]" || t == "}")
 
      state.indented = state.context.indented;
 
    return state.context = state.context.prev;
 
  }
 

	
 
  // Interface
 

	
 
  return {
 
    startState: function(basecolumn) {
 
      return {
 
        tokenize: [tokenBase],
 
        context: new Context((basecolumn || 0) - config.indentUnit, 0, "top", false),
 
        indented: 0,
 
        startOfLine: true,
 
        lastToken: null
 
      };
 
    },
 

	
 
    token: function(stream, state) {
 
      var ctx = state.context;
 
      if (stream.sol()) {
 
        if (ctx.align == null) ctx.align = false;
 
        state.indented = stream.indentation();
 
        state.startOfLine = true;
 
        // Automatic semicolon insertion
 
        if (ctx.type == "statement" && !expectExpression(state.lastToken)) {
 
          popContext(state); ctx = state.context;
 
        }
 
      }
 
      if (stream.eatSpace()) return null;
 
      curPunc = null;
 
      var style = state.tokenize[state.tokenize.length-1](stream, state);
 
      if (style == "comment") return style;
 
      if (ctx.align == null) ctx.align = true;
 

	
 
      if ((curPunc == ";" || curPunc == ":") && ctx.type == "statement") popContext(state);
 
      // Handle indentation for {x -> \n ... }
 
      else if (curPunc == "->" && ctx.type == "statement" && ctx.prev.type == "}") {
 
        popContext(state);
 
        state.context.align = false;
 
      }
 
      else if (curPunc == "{") pushContext(state, stream.column(), "}");
 
      else if (curPunc == "[") pushContext(state, stream.column(), "]");
 
      else if (curPunc == "(") pushContext(state, stream.column(), ")");
 
      else if (curPunc == "}") {
 
        while (ctx.type == "statement") ctx = popContext(state);
 
        if (ctx.type == "}") ctx = popContext(state);
 
        while (ctx.type == "statement") ctx = popContext(state);
 
      }
 
      else if (curPunc == ctx.type) popContext(state);
 
      else if (ctx.type == "}" || ctx.type == "top" || (ctx.type == "statement" && curPunc == "newstatement"))
 
        pushContext(state, stream.column(), "statement");
 
      state.startOfLine = false;
 
      state.lastToken = curPunc || style;
 
      return style;
 
    },
 

	
 
    indent: function(state, textAfter) {
 
      if (!state.tokenize[state.tokenize.length-1].isBase) return 0;
 
      var firstChar = textAfter && textAfter.charAt(0), ctx = state.context;
 
      if (ctx.type == "statement" && !expectExpression(state.lastToken)) ctx = ctx.prev;
 
      var closing = firstChar == ctx.type;
 
      if (ctx.type == "statement") return ctx.indented + (firstChar == "{" ? 0 : config.indentUnit);
 
      else if (ctx.align) return ctx.column + (closing ? 0 : 1);
 
      else return ctx.indented + (closing ? 0 : config.indentUnit);
 
    },
 

	
 
    electricChars: "{}"
 
    electricChars: "{}",
 
    fold: "brace"
 
  };
 
});
 

	
 
CodeMirror.defineMIME("text/x-groovy", "groovy");
rhodecode/public/js/mode/jade/index.html
Show inline comments
 
new file 100644
 
<!doctype html>
 
<html>
 
  <head>
 
    <meta charset="utf-8">
 
    <title>CodeMirror: Jade Templating Mode</title>
 
    <link rel="stylesheet" href="../../lib/codemirror.css">
 
    <script src="../../lib/codemirror.js"></script>
 
    <script src="jade.js"></script>
 
    <style type="text/css">.CodeMirror {border-top: 1px solid black; border-bottom: 1px solid black;}</style>
 
    <link rel="stylesheet" href="../../doc/docs.css">
 
  </head>
 
  <body>
 
    <h1>CodeMirror: Jade Templating Mode</h1>
 
    <form><textarea id="code" name="code">
 
doctype 5
 
  html
 
    head
 
      title= "Jade Templating CodeMirror Mode Example"
 
      link(rel='stylesheet', href='/css/bootstrap.min.css')
 
      link(rel='stylesheet', href='/css/index.css')
 
      script(type='text/javascript', src='/js/jquery-1.9.1.min.js')
 
      script(type='text/javascript', src='/js/bootstrap.min.js')
 
    body
 
      div.header
 
        h1 Welcome to this Example
 
      div.spots
 
        if locals.spots
 
          each spot in spots
 
            div.spot.well
 
         div
 
           if spot.logo
 
             img.img-rounded.logo(src=spot.logo)
 
           else
 
             img.img-rounded.logo(src="img/placeholder.png")
 
         h3
 
           a(href=spot.hash) ##{spot.hash}
 
           if spot.title
 
             span.title #{spot.title}
 
           if spot.desc
 
             div #{spot.desc}
 
        else
 
          h3 There are no spots currently available.
 
</textarea></form>
 
    <script>
 
      var editor = CodeMirror.fromTextArea(document.getElementById("code"), {
 
        mode: {name: "jade", alignCDATA: true},
 
        lineNumbers: true
 
      });
 
    </script>
 
    <h3>The Jade Templating Mode</h3>
 
      <p> Created by Drew Bratcher. Managed as part of an Adobe Brackets extension at <a href="https://github.com/dbratcher/brackets-jade">https://github.com/dbratcher/brackets-jade</a>.</p>
 
    <p><strong>MIME type defined:</strong> <code>text/x-jade</code>.</p>
 
  </body>
 
</html>
rhodecode/public/js/mode/jade/jade.js
Show inline comments
 
new file 100644
 
CodeMirror.defineMode("jade", function () {
 
  var symbol_regex1 = /^(?:~|!|%|\^|\*|\+|=|\\|:|;|,|\/|\?|&|<|>|\|)/;
 
  var open_paren_regex = /^(\(|\[)/;
 
  var close_paren_regex = /^(\)|\])/;
 
  var keyword_regex1 = /^(if|else|return|var|function|include|doctype|each)/;
 
  var keyword_regex2 = /^(#|{|}|\.)/;
 
  var keyword_regex3 = /^(in)/;
 
  var html_regex1 = /^(html|head|title|meta|link|script|body|br|div|input|span|a|img)/;
 
  var html_regex2 = /^(h1|h2|h3|h4|h5|p|strong|em)/;
 
  return {
 
    startState: function () {
 
      return {
 
        inString: false,
 
        stringType: "",
 
        beforeTag: true,
 
        justMatchedKeyword: false,
 
        afterParen: false
 
      };
 
    },
 
    token: function (stream, state) {
 
      //check for state changes
 
      if (!state.inString && ((stream.peek() == '"') || (stream.peek() == "'"))) {
 
        state.stringType = stream.peek();
 
        stream.next(); // Skip quote
 
        state.inString = true; // Update state
 
      }
 

	
 
      //return state
 
      if (state.inString) {
 
        if (stream.skipTo(state.stringType)) { // Quote found on this line
 
          stream.next(); // Skip quote
 
          state.inString = false; // Clear flag
 
        } else {
 
          stream.skipToEnd(); // Rest of line is string
 
        }
 
        state.justMatchedKeyword = false;
 
        return "string"; // Token style
 
      } else if (stream.sol() && stream.eatSpace()) {
 
        if (stream.match(keyword_regex1)) {
 
          state.justMatchedKeyword = true;
 
          stream.eatSpace();
 
          return "keyword";
 
        }
 
        if (stream.match(html_regex1) || stream.match(html_regex2)) {
 
          state.justMatchedKeyword = true;
 
          return "variable";
 
        }
 
      } else if (stream.sol() && stream.match(keyword_regex1)) {
 
        state.justMatchedKeyword = true;
 
        stream.eatSpace();
 
        return "keyword";
 
      } else if (stream.sol() && (stream.match(html_regex1) || stream.match(html_regex2))) {
 
        state.justMatchedKeyword = true;
 
        return "variable";
 
      } else if (stream.eatSpace()) {
 
        state.justMatchedKeyword = false;
 
        if (stream.match(keyword_regex3) && stream.eatSpace()) {
 
          state.justMatchedKeyword = true;
 
          return "keyword";
 
        }
 
      } else if (stream.match(symbol_regex1)) {
 
        state.justMatchedKeyword = false;
 
        return "atom";
 
      } else if (stream.match(open_paren_regex)) {
 
        state.afterParen = true;
 
        state.justMatchedKeyword = true;
 
        return "def";
 
      } else if (stream.match(close_paren_regex)) {
 
        state.afterParen = false;
 
        state.justMatchedKeyword = true;
 
        return "def";
 
      } else if (stream.match(keyword_regex2)) {
 
        state.justMatchedKeyword = true;
 
        return "keyword";
 
      } else if (stream.eatSpace()) {
 
        state.justMatchedKeyword = false;
 
      } else {
 
        stream.next();
 
        if (state.justMatchedKeyword) {
 
          return "property";
 
        } else if (state.afterParen) {
 
          return "property";
 
        }
 
      }
 
      return null;
 
    }
 
  };
 
});
 

	
 
CodeMirror.defineMIME('text/x-jade', 'jade');
rhodecode/public/js/mode/javascript/javascript.js
Show inline comments
 
@@ -165,312 +165,315 @@ CodeMirror.defineMode("javascript", func
 
    for (var v = state.localVars; v; v = v.next)
 
      if (v.name == varname) return true;
 
  }
 

	
 
  function parseJS(state, style, type, content, stream) {
 
    var cc = state.cc;
 
    // Communicate our context to the combinators.
 
    // (Less wasteful than consing up a hundred closures on every call.)
 
    cx.state = state; cx.stream = stream; cx.marked = null, cx.cc = cc;
 

	
 
    if (!state.lexical.hasOwnProperty("align"))
 
      state.lexical.align = true;
 

	
 
    while(true) {
 
      var combinator = cc.length ? cc.pop() : jsonMode ? expression : statement;
 
      if (combinator(type, content)) {
 
        while(cc.length && cc[cc.length - 1].lex)
 
          cc.pop()();
 
        if (cx.marked) return cx.marked;
 
        if (type == "variable" && inScope(state, content)) return "variable-2";
 
        return style;
 
      }
 
    }
 
  }
 

	
 
  // Combinator utils
 

	
 
  var cx = {state: null, column: null, marked: null, cc: null};
 
  function pass() {
 
    for (var i = arguments.length - 1; i >= 0; i--) cx.cc.push(arguments[i]);
 
  }
 
  function cont() {
 
    pass.apply(null, arguments);
 
    return true;
 
  }
 
  function register(varname) {
 
    function inList(list) {
 
      for (var v = list; v; v = v.next)
 
        if (v.name == varname) return true;
 
      return false;
 
    }
 
    var state = cx.state;
 
    if (state.context) {
 
      cx.marked = "def";
 
      if (inList(state.localVars)) return;
 
      state.localVars = {name: varname, next: state.localVars};
 
    } else {
 
      if (inList(state.globalVars)) return;
 
      state.globalVars = {name: varname, next: state.globalVars};
 
    }
 
  }
 

	
 
  // Combinators
 

	
 
  var defaultVars = {name: "this", next: {name: "arguments"}};
 
  function pushcontext() {
 
    cx.state.context = {prev: cx.state.context, vars: cx.state.localVars};
 
    cx.state.localVars = defaultVars;
 
  }
 
  function popcontext() {
 
    cx.state.localVars = cx.state.context.vars;
 
    cx.state.context = cx.state.context.prev;
 
  }
 
  function pushlex(type, info) {
 
    var result = function() {
 
      var state = cx.state, indent = state.indented;
 
      if (state.lexical.type == "stat") indent = state.lexical.indented;
 
      state.lexical = new JSLexical(indent, cx.stream.column(), type, null, state.lexical, info);
 
    };
 
    result.lex = true;
 
    return result;
 
  }
 
  function poplex() {
 
    var state = cx.state;
 
    if (state.lexical.prev) {
 
      if (state.lexical.type == ")")
 
        state.indented = state.lexical.indented;
 
      state.lexical = state.lexical.prev;
 
    }
 
  }
 
  poplex.lex = true;
 

	
 
  function expect(wanted) {
 
    return function(type) {
 
      if (type == wanted) return cont();
 
      else if (wanted == ";") return pass();
 
      else return cont(arguments.callee);
 
    };
 
  }
 

	
 
  function statement(type) {
 
    if (type == "var") return cont(pushlex("vardef"), vardef1, expect(";"), poplex);
 
    if (type == "keyword a") return cont(pushlex("form"), expression, statement, poplex);
 
    if (type == "keyword b") return cont(pushlex("form"), statement, poplex);
 
    if (type == "{") return cont(pushlex("}"), block, poplex);
 
    if (type == ";") return cont();
 
    if (type == "if") return cont(pushlex("form"), expression, statement, poplex, maybeelse(cx.state.indented));
 
    if (type == "if") return cont(pushlex("form"), expression, statement, poplex, maybeelse);
 
    if (type == "function") return cont(functiondef);
 
    if (type == "for") return cont(pushlex("form"), expect("("), pushlex(")"), forspec1, expect(")"),
 
                                      poplex, statement, poplex);
 
                                   poplex, statement, poplex);
 
    if (type == "variable") return cont(pushlex("stat"), maybelabel);
 
    if (type == "switch") return cont(pushlex("form"), expression, pushlex("}", "switch"), expect("{"),
 
                                         block, poplex, poplex);
 
                                      block, poplex, poplex);
 
    if (type == "case") return cont(expression, expect(":"));
 
    if (type == "default") return cont(expect(":"));
 
    if (type == "catch") return cont(pushlex("form"), pushcontext, expect("("), funarg, expect(")"),
 
                                        statement, poplex, popcontext);
 
                                     statement, poplex, popcontext);
 
    return pass(pushlex("stat"), expression, expect(";"), poplex);
 
  }
 
  function expression(type) {
 
    return expressionInner(type, false);
 
  }
 
  function expressionNoComma(type) {
 
    return expressionInner(type, true);
 
  }
 
  function expressionInner(type, noComma) {
 
    var maybeop = noComma ? maybeoperatorNoComma : maybeoperatorComma;
 
    if (atomicTypes.hasOwnProperty(type)) return cont(maybeop);
 
    if (type == "function") return cont(functiondef);
 
    if (type == "keyword c") return cont(noComma ? maybeexpressionNoComma : maybeexpression);
 
    if (type == "(") return cont(pushlex(")"), maybeexpression, expect(")"), poplex, maybeop);
 
    if (type == "operator") return cont(noComma ? expressionNoComma : expression);
 
    if (type == "[") return cont(pushlex("]"), commasep(expressionNoComma, "]"), poplex, maybeop);
 
    if (type == "{") return cont(pushlex("}"), commasep(objprop, "}"), poplex, maybeop);
 
    return cont();
 
  }
 
  function maybeexpression(type) {
 
    if (type.match(/[;\}\)\],]/)) return pass();
 
    return pass(expression);
 
  }
 
  function maybeexpressionNoComma(type) {
 
    if (type.match(/[;\}\)\],]/)) return pass();
 
    return pass(expressionNoComma);
 
  }
 

	
 
  function maybeoperatorComma(type, value) {
 
    if (type == ",") return cont(expression);
 
    return maybeoperatorNoComma(type, value, maybeoperatorComma);
 
    return maybeoperatorNoComma(type, value, false);
 
  }
 
  function maybeoperatorNoComma(type, value, me) {
 
    if (!me) me = maybeoperatorNoComma;
 
  function maybeoperatorNoComma(type, value, noComma) {
 
    var me = noComma == false ? maybeoperatorComma : maybeoperatorNoComma;
 
    var expr = noComma == false ? expression : expressionNoComma;
 
    if (type == "operator") {
 
      if (/\+\+|--/.test(value)) return cont(me);
 
      if (value == "?") return cont(expression, expect(":"), expression);
 
      return cont(expression);
 
      if (value == "?") return cont(expression, expect(":"), expr);
 
      return cont(expr);
 
    }
 
    if (type == ";") return;
 
    if (type == "(") return cont(pushlex(")", "call"), commasep(expressionNoComma, ")"), poplex, me);
 
    if (type == ".") return cont(property, me);
 
    if (type == "[") return cont(pushlex("]"), expression, expect("]"), poplex, me);
 
    if (type == "[") return cont(pushlex("]"), maybeexpression, expect("]"), poplex, me);
 
  }
 
  function maybelabel(type) {
 
    if (type == ":") return cont(poplex, statement);
 
    return pass(maybeoperatorComma, expect(";"), poplex);
 
  }
 
  function property(type) {
 
    if (type == "variable") {cx.marked = "property"; return cont();}
 
  }
 
  function objprop(type, value) {
 
    if (type == "variable") {
 
      cx.marked = "property";
 
      if (value == "get" || value == "set") return cont(getterSetter);
 
    } else if (type == "number" || type == "string") {
 
      cx.marked = type + " property";
 
    }
 
    if (atomicTypes.hasOwnProperty(type)) return cont(expect(":"), expressionNoComma);
 
  }
 
  function getterSetter(type) {
 
    if (type == ":") return cont(expression);
 
    if (type != "variable") return cont(expect(":"), expression);
 
    cx.marked = "property";
 
    return cont(functiondef);
 
  }
 
  function commasep(what, end) {
 
    function proceed(type) {
 
      if (type == ",") {
 
        var lex = cx.state.lexical;
 
        if (lex.info == "call") lex.pos = (lex.pos || 0) + 1;
 
        return cont(what, proceed);
 
      }
 
      if (type == end) return cont();
 
      return cont(expect(end));
 
    }
 
    return function(type) {
 
      if (type == end) return cont();
 
      else return pass(what, proceed);
 
    };
 
  }
 
  function block(type) {
 
    if (type == "}") return cont();
 
    return pass(statement, block);
 
  }
 
  function maybetype(type) {
 
    if (type == ":") return cont(typedef);
 
    return pass();
 
  }
 
  function typedef(type) {
 
    if (type == "variable"){cx.marked = "variable-3"; return cont();}
 
    return pass();
 
  }
 
  function vardef1(type, value) {
 
    if (type == "variable") {
 
      register(value);
 
      return isTS ? cont(maybetype, vardef2) : cont(vardef2);
 
    }
 
    return pass();
 
  }
 
  function vardef2(type, value) {
 
    if (value == "=") return cont(expressionNoComma, vardef2);
 
    if (type == ",") return cont(vardef1);
 
  }
 
  function maybeelse(indent) {
 
    return function(type, value) {
 
      if (type == "keyword b" && value == "else") {
 
        cx.state.lexical = new JSLexical(indent, 0, "form", null, cx.state.lexical);
 
        return cont(statement, poplex);
 
      }
 
      return pass();
 
    };
 
  function maybeelse(type, value) {
 
    if (type == "keyword b" && value == "else") return cont(pushlex("form"), statement, poplex);
 
  }
 
  function forspec1(type) {
 
    if (type == "var") return cont(vardef1, expect(";"), forspec2);
 
    if (type == ";") return cont(forspec2);
 
    if (type == "variable") return cont(formaybein);
 
    return pass(expression, expect(";"), forspec2);
 
  }
 
  function formaybein(_type, value) {
 
    if (value == "in") return cont(expression);
 
    return cont(maybeoperatorComma, forspec2);
 
  }
 
  function forspec2(type, value) {
 
    if (type == ";") return cont(forspec3);
 
    if (value == "in") return cont(expression);
 
    return pass(expression, expect(";"), forspec3);
 
  }
 
  function forspec3(type) {
 
    if (type != ")") cont(expression);
 
  }
 
  function functiondef(type, value) {
 
    if (type == "variable") {register(value); return cont(functiondef);}
 
    if (type == "(") return cont(pushlex(")"), pushcontext, commasep(funarg, ")"), poplex, statement, popcontext);
 
  }
 
  function funarg(type, value) {
 
    if (type == "variable") {register(value); return isTS ? cont(maybetype) : cont();}
 
  }
 

	
 
  // Interface
 

	
 
  return {
 
    startState: function(basecolumn) {
 
      return {
 
        tokenize: jsTokenBase,
 
        lastType: null,
 
        cc: [],
 
        lexical: new JSLexical((basecolumn || 0) - indentUnit, 0, "block", false),
 
        localVars: parserConfig.localVars,
 
        globalVars: parserConfig.globalVars,
 
        context: parserConfig.localVars && {vars: parserConfig.localVars},
 
        indented: 0
 
      };
 
    },
 

	
 
    token: function(stream, state) {
 
      if (stream.sol()) {
 
        if (!state.lexical.hasOwnProperty("align"))
 
          state.lexical.align = false;
 
        state.indented = stream.indentation();
 
      }
 
      if (state.tokenize != jsTokenComment && stream.eatSpace()) return null;
 
      var style = state.tokenize(stream, state);
 
      if (type == "comment") return style;
 
      state.lastType = type == "operator" && (content == "++" || content == "--") ? "incdec" : type;
 
      return parseJS(state, style, type, content, stream);
 
    },
 

	
 
    indent: function(state, textAfter) {
 
      if (state.tokenize == jsTokenComment) return CodeMirror.Pass;
 
      if (state.tokenize != jsTokenBase) return 0;
 
      var firstChar = textAfter && textAfter.charAt(0), lexical = state.lexical;
 
      // Kludge to prevent 'maybelse' from blocking lexical scope pops
 
      for (var i = state.cc.length - 1; i >= 0; --i) {
 
        var c = state.cc[i];
 
        if (c == poplex) lexical = lexical.prev;
 
        else if (c != maybeelse || /^else\b/.test(textAfter)) break;
 
      }
 
      if (lexical.type == "stat" && firstChar == "}") lexical = lexical.prev;
 
      if (statementIndent && lexical.type == ")" && lexical.prev.type == "stat")
 
        lexical = lexical.prev;
 
      var type = lexical.type, closing = firstChar == type;
 

	
 
      if (type == "vardef") return lexical.indented + (state.lastType == "operator" || state.lastType == "," ? 4 : 0);
 
      else if (type == "form" && firstChar == "{") return lexical.indented;
 
      else if (type == "form") return lexical.indented + indentUnit;
 
      else if (type == "stat")
 
        return lexical.indented + (state.lastType == "operator" || state.lastType == "," ? statementIndent || indentUnit : 0);
 
      else if (lexical.info == "switch" && !closing && parserConfig.doubleIndentSwitch != false)
 
        return lexical.indented + (/^(?:case|default)\b/.test(textAfter) ? indentUnit : 2 * indentUnit);
 
      else if (lexical.align) return lexical.column + (closing ? 0 : 1);
 
      else return lexical.indented + (closing ? 0 : indentUnit);
 
    },
 

	
 
    electricChars: ":{}",
 
    blockCommentStart: jsonMode ? null : "/*",
 
    blockCommentEnd: jsonMode ? null : "*/",
 
    lineComment: jsonMode ? null : "//",
 
    fold: "brace",
 

	
 
    helperType: jsonMode ? "json" : "javascript",
 
    jsonMode: jsonMode
 
  };
 
});
 

	
 
CodeMirror.defineMIME("text/javascript", "javascript");
 
CodeMirror.defineMIME("text/ecmascript", "javascript");
 
CodeMirror.defineMIME("application/javascript", "javascript");
 
CodeMirror.defineMIME("application/ecmascript", "javascript");
 
CodeMirror.defineMIME("application/json", {name: "javascript", json: true});
 
CodeMirror.defineMIME("application/x-json", {name: "javascript", json: true});
 
CodeMirror.defineMIME("text/typescript", { name: "javascript", typescript: true });
 
CodeMirror.defineMIME("application/typescript", { name: "javascript", typescript: true });
rhodecode/public/js/mode/javascript/test.js
Show inline comments
 
new file 100644
 
(function() {
 
  var mode = CodeMirror.getMode({indentUnit: 2}, "javascript");
 
  function MT(name) { test.mode(name, mode, Array.prototype.slice.call(arguments, 1)); }
 

	
 
  MT("locals",
 
     "[keyword function] [variable foo]([def a], [def b]) { [keyword var] [def c] = [number 10]; [keyword return] [variable-2 a] + [variable-2 c] + [variable d]; }");
 

	
 
  MT("comma-and-binop",
 
     "[keyword function](){ [keyword var] [def x] = [number 1] + [number 2], [def y]; }");
 
})();
rhodecode/public/js/mode/markdown/index.html
Show inline comments
 
<!doctype html>
 
<html>
 
  <head>
 
    <meta charset="utf-8">
 
    <title>CodeMirror: Markdown mode</title>
 
    <link rel="stylesheet" href="../../lib/codemirror.css">
 
    <script src="../../lib/codemirror.js"></script>
 
    <script src="../../addon/edit/continuelist.js"></script>
 
    <script src="../xml/xml.js"></script>
 
    <script src="markdown.js"></script>
 
    <style type="text/css">.CodeMirror {border-top: 1px solid black; border-bottom: 1px solid black;}</style>
 
    <style type="text/css">
 
      .CodeMirror {border-top: 1px solid black; border-bottom: 1px solid black;}
 
      .cm-s-default .cm-trailing-space-a:before,
 
      .cm-s-default .cm-trailing-space-b:before {position: absolute; content: "\00B7"; color: #777;}
 
      .cm-s-default .cm-trailing-space-new-line:before {position: absolute; content: "\21B5"; color: #777;}
 
    </style>
 
    <link rel="stylesheet" href="../../doc/docs.css">
 
  </head>
 
  <body>
 
    <h1>CodeMirror: Markdown mode</h1>
 

	
 
<!-- source: http://daringfireball.net/projects/markdown/basics.text -->
 
<form><textarea id="code" name="code">
 
Markdown: Basics
 
================
 

	
 
&lt;ul id="ProjectSubmenu"&gt;
 
    &lt;li&gt;&lt;a href="/projects/markdown/" title="Markdown Project Page"&gt;Main&lt;/a&gt;&lt;/li&gt;
 
    &lt;li&gt;&lt;a class="selected" title="Markdown Basics"&gt;Basics&lt;/a&gt;&lt;/li&gt;
 
    &lt;li&gt;&lt;a href="/projects/markdown/syntax" title="Markdown Syntax Documentation"&gt;Syntax&lt;/a&gt;&lt;/li&gt;
 
    &lt;li&gt;&lt;a href="/projects/markdown/license" title="Pricing and License Information"&gt;License&lt;/a&gt;&lt;/li&gt;
 
    &lt;li&gt;&lt;a href="/projects/markdown/dingus" title="Online Markdown Web Form"&gt;Dingus&lt;/a&gt;&lt;/li&gt;
 
&lt;/ul&gt;
 

	
 

	
 
Getting the Gist of Markdown's Formatting Syntax
 
------------------------------------------------
 

	
 
This page offers a brief overview of what it's like to use Markdown.
 
The [syntax page] [s] provides complete, detailed documentation for
 
every feature, but Markdown should be very easy to pick up simply by
 
looking at a few examples of it in action. The examples on this page
 
are written in a before/after style, showing example syntax and the
 
HTML output produced by Markdown.
 

	
 
It's also helpful to simply try Markdown out; the [Dingus] [d] is a
 
web application that allows you type your own Markdown-formatted text
 
and translate it to XHTML.
 

	
 
**Note:** This document is itself written using Markdown; you
 
can [see the source for it by adding '.text' to the URL] [src].
 

	
 
  [s]: /projects/markdown/syntax  "Markdown Syntax"
 
  [d]: /projects/markdown/dingus  "Markdown Dingus"
 
  [src]: /projects/markdown/basics.text
 

	
 

	
 
## Paragraphs, Headers, Blockquotes ##
 

	
 
A paragraph is simply one or more consecutive lines of text, separated
 
by one or more blank lines. (A blank line is any line that looks like
 
a blank line -- a line containing nothing but spaces or tabs is
 
considered blank.) Normal paragraphs should not be indented with
 
spaces or tabs.
 

	
 
Markdown offers two styles of headers: *Setext* and *atx*.
 
Setext-style headers for `&lt;h1&gt;` and `&lt;h2&gt;` are created by
 
"underlining" with equal signs (`=`) and hyphens (`-`), respectively.
 
To create an atx-style header, you put 1-6 hash marks (`#`) at the
 
beginning of the line -- the number of hashes equals the resulting
 
HTML header level.
 

	
 
Blockquotes are indicated using email-style '`&gt;`' angle brackets.
 

	
 
Markdown:
 

	
 
    A First Level Header
 
    ====================
 

	
 
    
 
    A Second Level Header
 
    ---------------------
 

	
 
    Now is the time for all good men to come to
 
    the aid of their country. This is just a
 
    regular paragraph.
 

	
 
    The quick brown fox jumped over the lazy
 
    dog's back.
 

	
 
    
 
    ### Header 3
 

	
 
    &gt; This is a blockquote.
 
    &gt;
 
    &gt; 
 
    &gt; This is the second paragraph in the blockquote.
 
    &gt;
 
    &gt; ## This is an H2 in a blockquote
 

	
 

	
 
Output:
 

	
 
    &lt;h1&gt;A First Level Header&lt;/h1&gt;
 

	
 
    
 
    &lt;h2&gt;A Second Level Header&lt;/h2&gt;
 

	
 
    
 
    &lt;p&gt;Now is the time for all good men to come to
 
    the aid of their country. This is just a
 
    regular paragraph.&lt;/p&gt;
 

	
 
    
 
    &lt;p&gt;The quick brown fox jumped over the lazy
 
    dog's back.&lt;/p&gt;
 

	
 
    
 
    &lt;h3&gt;Header 3&lt;/h3&gt;
 

	
 
    
 
    &lt;blockquote&gt;
 
        &lt;p&gt;This is a blockquote.&lt;/p&gt;
 

	
 
        
 
        &lt;p&gt;This is the second paragraph in the blockquote.&lt;/p&gt;
 

	
 
        
 
        &lt;h2&gt;This is an H2 in a blockquote&lt;/h2&gt;
 
    &lt;/blockquote&gt;
 

	
 

	
 

	
 
### Phrase Emphasis ###
 

	
 
Markdown uses asterisks and underscores to indicate spans of emphasis.
 

	
 
Markdown:
 

	
 
    Some of these words *are emphasized*.
 
    Some of these words _are emphasized also_.
 

	
 
    
 
    Use two asterisks for **strong emphasis**.
 
    Or, if you prefer, __use two underscores instead__.
 

	
 
Output:
 

	
 
    &lt;p&gt;Some of these words &lt;em&gt;are emphasized&lt;/em&gt;.
 
    Some of these words &lt;em&gt;are emphasized also&lt;/em&gt;.&lt;/p&gt;
 

	
 
    
 
    &lt;p&gt;Use two asterisks for &lt;strong&gt;strong emphasis&lt;/strong&gt;.
 
    Or, if you prefer, &lt;strong&gt;use two underscores instead&lt;/strong&gt;.&lt;/p&gt;
 

	
 
   
 

	
 

	
 
## Lists ##
 

	
 
Unordered (bulleted) lists use asterisks, pluses, and hyphens (`*`,
 
`+`, and `-`) as list markers. These three markers are
 
interchangable; this:
 

	
 
    *   Candy.
 
    *   Gum.
 
    *   Booze.
 

	
 
this:
 

	
 
    +   Candy.
 
    +   Gum.
 
    +   Booze.
 

	
 
and this:
 

	
 
    -   Candy.
 
    -   Gum.
 
    -   Booze.
 

	
 
all produce the same output:
 

	
 
    &lt;ul&gt;
 
    &lt;li&gt;Candy.&lt;/li&gt;
 
    &lt;li&gt;Gum.&lt;/li&gt;
 
    &lt;li&gt;Booze.&lt;/li&gt;
 
    &lt;/ul&gt;
 

	
 
Ordered (numbered) lists use regular numbers, followed by periods, as
 
list markers:
 

	
 
    1.  Red
 
    2.  Green
 
    3.  Blue
 

	
 
Output:
 

	
 
    &lt;ol&gt;
 
    &lt;li&gt;Red&lt;/li&gt;
 
    &lt;li&gt;Green&lt;/li&gt;
 
    &lt;li&gt;Blue&lt;/li&gt;
 
    &lt;/ol&gt;
 

	
 
If you put blank lines between items, you'll get `&lt;p&gt;` tags for the
 
list item text. You can create multi-paragraph list items by indenting
 
the paragraphs by 4 spaces or 1 tab:
 

	
 
    *   A list item.
 

	
 
    
 
        With multiple paragraphs.
 

	
 
    *   Another item in the list.
 

	
 
Output:
 

	
 
    &lt;ul&gt;
 
    &lt;li&gt;&lt;p&gt;A list item.&lt;/p&gt;
 
    &lt;p&gt;With multiple paragraphs.&lt;/p&gt;&lt;/li&gt;
 
    &lt;li&gt;&lt;p&gt;Another item in the list.&lt;/p&gt;&lt;/li&gt;
 
    &lt;/ul&gt;
 

	
 
    
 

	
 

	
 
### Links ###
 

	
 
Markdown supports two styles for creating links: *inline* and
 
*reference*. With both styles, you use square brackets to delimit the
 
text you want to turn into a link.
 

	
 
Inline-style links use parentheses immediately after the link text.
 
For example:
 

	
 
    This is an [example link](http://example.com/).
 

	
 
Output:
 

	
 
    &lt;p&gt;This is an &lt;a href="http://example.com/"&gt;
 
    example link&lt;/a&gt;.&lt;/p&gt;
 

	
 
Optionally, you may include a title attribute in the parentheses:
 

	
 
    This is an [example link](http://example.com/ "With a Title").
 

	
 
Output:
 

	
 
    &lt;p&gt;This is an &lt;a href="http://example.com/" title="With a Title"&gt;
 
    example link&lt;/a&gt;.&lt;/p&gt;
 

	
 
Reference-style links allow you to refer to your links by names, which
 
you define elsewhere in your document:
 

	
 
    I get 10 times more traffic from [Google][1] than from
 
    [Yahoo][2] or [MSN][3].
 

	
 
    [1]: http://google.com/        "Google"
 
    [2]: http://search.yahoo.com/  "Yahoo Search"
 
    [3]: http://search.msn.com/    "MSN Search"
 

	
 
Output:
 

	
 
    &lt;p&gt;I get 10 times more traffic from &lt;a href="http://google.com/"
 
    title="Google"&gt;Google&lt;/a&gt; than from &lt;a href="http://search.yahoo.com/"
 
    title="Yahoo Search"&gt;Yahoo&lt;/a&gt; or &lt;a href="http://search.msn.com/"
 
    title="MSN Search"&gt;MSN&lt;/a&gt;.&lt;/p&gt;
 

	
 
The title attribute is optional. Link names may contain letters,
 
numbers and spaces, but are *not* case sensitive:
 

	
 
    I start my morning with a cup of coffee and
 
    [The New York Times][NY Times].
 

	
 
    [ny times]: http://www.nytimes.com/
 

	
 
Output:
 

	
 
    &lt;p&gt;I start my morning with a cup of coffee and
 
    &lt;a href="http://www.nytimes.com/"&gt;The New York Times&lt;/a&gt;.&lt;/p&gt;
 

	
 

	
 
### Images ###
 

	
 
Image syntax is very much like link syntax.
 

	
 
Inline (titles are optional):
 

	
 
    ![alt text](/path/to/img.jpg "Title")
 

	
 
Reference-style:
 

	
 
    ![alt text][id]
 

	
 
    [id]: /path/to/img.jpg "Title"
 

	
 
Both of the above examples produce the same output:
 

	
 
    &lt;img src="/path/to/img.jpg" alt="alt text" title="Title" /&gt;
 

	
 

	
 

	
 
### Code ###
 

	
 
In a regular paragraph, you can create code span by wrapping text in
 
backtick quotes. Any ampersands (`&amp;`) and angle brackets (`&lt;` or
 
`&gt;`) will automatically be translated into HTML entities. This makes
 
it easy to use Markdown to write about HTML example code:
 

	
 
    I strongly recommend against using any `&lt;blink&gt;` tags.
 

	
 
    I wish SmartyPants used named entities like `&amp;mdash;`
 
    instead of decimal-encoded entites like `&amp;#8212;`.
 

	
 
Output:
 

	
 
    &lt;p&gt;I strongly recommend against using any
 
    &lt;code&gt;&amp;lt;blink&amp;gt;&lt;/code&gt; tags.&lt;/p&gt;
 

	
 
    
 
    &lt;p&gt;I wish SmartyPants used named entities like
 
    &lt;code&gt;&amp;amp;mdash;&lt;/code&gt; instead of decimal-encoded
 
    entites like &lt;code&gt;&amp;amp;#8212;&lt;/code&gt;.&lt;/p&gt;
 

	
 

	
 
To specify an entire block of pre-formatted code, indent every line of
 
the block by 4 spaces or 1 tab. Just like with code spans, `&amp;`, `&lt;`,
 
and `&gt;` characters will be escaped automatically.
 

	
 
Markdown:
 

	
 
    If you want your page to validate under XHTML 1.0 Strict,
 
    you've got to put paragraph tags in your blockquotes:
 

	
 
        &lt;blockquote&gt;
 
            &lt;p&gt;For example.&lt;/p&gt;
 
        &lt;/blockquote&gt;
 

	
 
Output:
 

	
 
    &lt;p&gt;If you want your page to validate under XHTML 1.0 Strict,
 
    you've got to put paragraph tags in your blockquotes:&lt;/p&gt;
 

	
 
    
 
    &lt;pre&gt;&lt;code&gt;&amp;lt;blockquote&amp;gt;
 
        &amp;lt;p&amp;gt;For example.&amp;lt;/p&amp;gt;
 
    &amp;lt;/blockquote&amp;gt;
 
    &lt;/code&gt;&lt;/pre&gt;
 
</textarea></form>
 

	
 
    <script>
 
      var editor = CodeMirror.fromTextArea(document.getElementById("code"), {
 
        mode: 'markdown',
 
        lineNumbers: true,
 
        theme: "default",
 
        extraKeys: {"Enter": "newlineAndIndentContinueMarkdownList"}
 
      });
 
    </script>
 

	
 
    <p>Optionally depends on the XML mode for properly highlighted inline XML blocks.</p>
 

	
 
    <p><strong>MIME types defined:</strong> <code>text/x-markdown</code>.</p>
 

	
 
    <p><strong>Parsing/Highlighting Tests:</strong> <a href="../../test/index.html#markdown_*">normal</a>,  <a href="../../test/index.html#verbose,markdown_*">verbose</a>.</p>
 

	
 
  </body>
 
</html>
rhodecode/public/js/mode/markdown/markdown.js
Show inline comments
 
@@ -10,517 +10,542 @@ CodeMirror.defineMode("markdown", functi
 
    "c++": "text/x-c++src",
 
    java: "text/x-java",
 
    csharp: "text/x-csharp",
 
    "c#": "text/x-csharp",
 
    scala: "text/x-scala"
 
  };
 

	
 
  var getMode = (function () {
 
    var i, modes = {}, mimes = {}, mime;
 

	
 
    var list = [];
 
    for (var m in CodeMirror.modes)
 
      if (CodeMirror.modes.propertyIsEnumerable(m)) list.push(m);
 
    for (i = 0; i < list.length; i++) {
 
      modes[list[i]] = list[i];
 
    }
 
    var mimesList = [];
 
    for (var m in CodeMirror.mimeModes)
 
      if (CodeMirror.mimeModes.propertyIsEnumerable(m))
 
        mimesList.push({mime: m, mode: CodeMirror.mimeModes[m]});
 
    for (i = 0; i < mimesList.length; i++) {
 
      mime = mimesList[i].mime;
 
      mimes[mime] = mimesList[i].mime;
 
    }
 

	
 
    for (var a in aliases) {
 
      if (aliases[a] in modes || aliases[a] in mimes)
 
        modes[a] = aliases[a];
 
    }
 

	
 
    return function (lang) {
 
      return modes[lang] ? CodeMirror.getMode(cmCfg, modes[lang]) : null;
 
    };
 
  }());
 

	
 
  // Should underscores in words open/close em/strong?
 
  if (modeCfg.underscoresBreakWords === undefined)
 
    modeCfg.underscoresBreakWords = true;
 

	
 
  // Turn on fenced code blocks? ("```" to start/end)
 
  if (modeCfg.fencedCodeBlocks === undefined) modeCfg.fencedCodeBlocks = false;
 

	
 
  // Turn on task lists? ("- [ ] " and "- [x] ")
 
  if (modeCfg.taskLists === undefined) modeCfg.taskLists = false;
 

	
 
  var codeDepth = 0;
 

	
 
  var header   = 'header'
 
  ,   code     = 'comment'
 
  ,   quote1   = 'atom'
 
  ,   quote2   = 'number'
 
  ,   list1    = 'variable-2'
 
  ,   list2    = 'variable-3'
 
  ,   list3    = 'keyword'
 
  ,   hr       = 'hr'
 
  ,   image    = 'tag'
 
  ,   linkinline = 'link'
 
  ,   linkemail = 'link'
 
  ,   linktext = 'link'
 
  ,   linkhref = 'string'
 
  ,   em       = 'em'
 
  ,   strong   = 'strong';
 

	
 
  var hrRE = /^([*\-=_])(?:\s*\1){2,}\s*$/
 
  ,   ulRE = /^[*\-+]\s+/
 
  ,   olRE = /^[0-9]+\.\s+/
 
  ,   taskListRE = /^\[(x| )\](?=\s)/ // Must follow ulRE or olRE
 
  ,   headerRE = /^(?:\={1,}|-{1,})$/
 
  ,   textRE = /^[^!\[\]*_\\<>` "'(]+/;
 

	
 
  function switchInline(stream, state, f) {
 
    state.f = state.inline = f;
 
    return f(stream, state);
 
  }
 

	
 
  function switchBlock(stream, state, f) {
 
    state.f = state.block = f;
 
    return f(stream, state);
 
  }
 

	
 

	
 
  // Blocks
 

	
 
  function blankLine(state) {
 
    // Reset linkTitle state
 
    state.linkTitle = false;
 
    // Reset EM state
 
    state.em = false;
 
    // Reset STRONG state
 
    state.strong = false;
 
    // Reset state.quote
 
    state.quote = 0;
 
    if (!htmlFound && state.f == htmlBlock) {
 
      state.f = inlineNormal;
 
      state.block = blockNormal;
 
    }
 
    // Reset state.trailingSpace
 
    state.trailingSpace = 0;
 
    state.trailingSpaceNewLine = false;
 
    // Mark this line as blank
 
    state.thisLineHasContent = false;
 
    return null;
 
  }
 

	
 
  function blockNormal(stream, state) {
 

	
 
    var prevLineIsList = (state.list !== false);
 
    if (state.list !== false && state.indentationDiff >= 0) { // Continued list
 
      if (state.indentationDiff < 4) { // Only adjust indentation if *not* a code block
 
        state.indentation -= state.indentationDiff;
 
      }
 
      state.list = null;
 
    } else if (state.list !== false && state.indentation > 0) {
 
      state.list = null;
 
      state.listDepth = Math.floor(state.indentation / 4);
 
    } else if (state.list !== false) { // No longer a list
 
      state.list = false;
 
      state.listDepth = 0;
 
    }
 

	
 
    if (state.indentationDiff >= 4) {
 
      state.indentation -= 4;
 
      stream.skipToEnd();
 
      return code;
 
    } else if (stream.eatSpace()) {
 
      return null;
 
    } else if (stream.peek() === '#' || (state.prevLineHasContent && stream.match(headerRE)) ) {
 
      state.header = true;
 
    } else if (stream.eat('>')) {
 
      state.indentation++;
 
      state.quote = 1;
 
      stream.eatSpace();
 
      while (stream.eat('>')) {
 
        stream.eatSpace();
 
        state.quote++;
 
      }
 
    } else if (stream.peek() === '[') {
 
      return switchInline(stream, state, footnoteLink);
 
    } else if (stream.match(hrRE, true)) {
 
      return hr;
 
    } else if ((!state.prevLineHasContent || prevLineIsList) && (stream.match(ulRE, true) || stream.match(olRE, true))) {
 
      state.indentation += 4;
 
      state.list = true;
 
      state.listDepth++;
 
      if (modeCfg.taskLists && stream.match(taskListRE, false)) {
 
        state.taskList = true;
 
      }
 
    } else if (modeCfg.fencedCodeBlocks && stream.match(/^```([\w+#]*)/, true)) {
 
      // try switching mode
 
      state.localMode = getMode(RegExp.$1);
 
      if (state.localMode) state.localState = state.localMode.startState();
 
      switchBlock(stream, state, local);
 
      return code;
 
    }
 

	
 
    return switchInline(stream, state, state.inline);
 
  }
 

	
 
  function htmlBlock(stream, state) {
 
    var style = htmlMode.token(stream, state.htmlState);
 
    if (htmlFound && style === 'tag' && state.htmlState.type !== 'openTag' && !state.htmlState.context) {
 
      state.f = inlineNormal;
 
      state.block = blockNormal;
 
    }
 
    if (state.md_inside && stream.current().indexOf(">")!=-1) {
 
      state.f = inlineNormal;
 
      state.block = blockNormal;
 
      state.htmlState.context = undefined;
 
    }
 
    return style;
 
  }
 

	
 
  function local(stream, state) {
 
    if (stream.sol() && stream.match(/^```/, true)) {
 
      state.localMode = state.localState = null;
 
      state.f = inlineNormal;
 
      state.block = blockNormal;
 
      return code;
 
    } else if (state.localMode) {
 
      return state.localMode.token(stream, state.localState);
 
    } else {
 
      stream.skipToEnd();
 
      return code;
 
    }
 
  }
 

	
 
  // Inline
 
  function getType(state) {
 
    var styles = [];
 

	
 
    if (state.taskOpen) { return "meta"; }
 
    if (state.taskClosed) { return "property"; }
 

	
 
    if (state.strong) { styles.push(strong); }
 
    if (state.em) { styles.push(em); }
 

	
 
    if (state.linkText) { styles.push(linktext); }
 

	
 
    if (state.code) { styles.push(code); }
 

	
 
    if (state.header) { styles.push(header); }
 
    if (state.quote) { styles.push(state.quote % 2 ? quote1 : quote2); }
 
    if (state.list !== false) {
 
      var listMod = (state.listDepth - 1) % 3;
 
      if (!listMod) {
 
        styles.push(list1);
 
      } else if (listMod === 1) {
 
        styles.push(list2);
 
      } else {
 
        styles.push(list3);
 
      }
 
    }
 

	
 
    if (state.trailingSpaceNewLine) {
 
      styles.push("trailing-space-new-line");
 
    } else if (state.trailingSpace) {
 
      styles.push("trailing-space-" + (state.trailingSpace % 2 ? "a" : "b"));
 
    }
 

	
 
    return styles.length ? styles.join(' ') : null;
 
  }
 

	
 
  function handleText(stream, state) {
 
    if (stream.match(textRE, true)) {
 
      return getType(state);
 
    }
 
    return undefined;
 
  }
 

	
 
  function inlineNormal(stream, state) {
 
    var style = state.text(stream, state);
 
    if (typeof style !== 'undefined')
 
      return style;
 

	
 
    if (state.list) { // List marker (*, +, -, 1., etc)
 
      state.list = null;
 
      return getType(state);
 
    }
 

	
 
    if (state.taskList) {
 
      var taskOpen = stream.match(taskListRE, true)[1] !== "x";
 
      if (taskOpen) state.taskOpen = true;
 
      else state.taskClosed = true;
 
      state.taskList = false;
 
      return getType(state);
 
    }
 

	
 
    state.taskOpen = false;
 
    state.taskClosed = false;
 

	
 
    var ch = stream.next();
 

	
 
    if (ch === '\\') {
 
      stream.next();
 
      return getType(state);
 
    }
 

	
 
    // Matches link titles present on next line
 
    if (state.linkTitle) {
 
      state.linkTitle = false;
 
      var matchCh = ch;
 
      if (ch === '(') {
 
        matchCh = ')';
 
      }
 
      matchCh = (matchCh+'').replace(/([.?*+^$[\]\\(){}|-])/g, "\\$1");
 
      var regex = '^\\s*(?:[^' + matchCh + '\\\\]+|\\\\\\\\|\\\\.)' + matchCh;
 
      if (stream.match(new RegExp(regex), true)) {
 
        return linkhref;
 
      }
 
    }
 

	
 
    // If this block is changed, it may need to be updated in GFM mode
 
    if (ch === '`') {
 
      var t = getType(state);
 
      var before = stream.pos;
 
      stream.eatWhile('`');
 
      var difference = 1 + stream.pos - before;
 
      if (!state.code) {
 
        codeDepth = difference;
 
        state.code = true;
 
        return getType(state);
 
      } else {
 
        if (difference === codeDepth) { // Must be exact
 
          state.code = false;
 
          return t;
 
        }
 
        return getType(state);
 
      }
 
    } else if (state.code) {
 
      return getType(state);
 
    }
 

	
 
    if (ch === '!' && stream.match(/\[[^\]]*\] ?(?:\(|\[)/, false)) {
 
      stream.match(/\[[^\]]*\]/);
 
      state.inline = state.f = linkHref;
 
      return image;
 
    }
 

	
 
    if (ch === '[' && stream.match(/.*\](\(| ?\[)/, false)) {
 
      state.linkText = true;
 
      return getType(state);
 
    }
 

	
 
    if (ch === ']' && state.linkText) {
 
      var type = getType(state);
 
      state.linkText = false;
 
      state.inline = state.f = linkHref;
 
      return type;
 
    }
 

	
 
    if (ch === '<' && stream.match(/^(https?|ftps?):\/\/(?:[^\\>]|\\.)+>/, false)) {
 
      return switchInline(stream, state, inlineElement(linkinline, '>'));
 
    }
 

	
 
    if (ch === '<' && stream.match(/^[^> \\]+@(?:[^\\>]|\\.)+>/, false)) {
 
      return switchInline(stream, state, inlineElement(linkemail, '>'));
 
    }
 

	
 
    if (ch === '<' && stream.match(/^\w/, false)) {
 
      if (stream.string.indexOf(">")!=-1) {
 
        var atts = stream.string.substring(1,stream.string.indexOf(">"));
 
        if (/markdown\s*=\s*('|"){0,1}1('|"){0,1}/.test(atts)) {
 
          state.md_inside = true;
 
        }
 
      }
 
      stream.backUp(1);
 
      return switchBlock(stream, state, htmlBlock);
 
    }
 

	
 
    if (ch === '<' && stream.match(/^\/\w*?>/)) {
 
      state.md_inside = false;
 
      return "tag";
 
    }
 

	
 
    var ignoreUnderscore = false;
 
    if (!modeCfg.underscoresBreakWords) {
 
      if (ch === '_' && stream.peek() !== '_' && stream.match(/(\w)/, false)) {
 
        var prevPos = stream.pos - 2;
 
        if (prevPos >= 0) {
 
          var prevCh = stream.string.charAt(prevPos);
 
          if (prevCh !== '_' && prevCh.match(/(\w)/, false)) {
 
            ignoreUnderscore = true;
 
          }
 
        }
 
      }
 
    }
 
    var t = getType(state);
 
    if (ch === '*' || (ch === '_' && !ignoreUnderscore)) {
 
      if (state.strong === ch && stream.eat(ch)) { // Remove STRONG
 
        state.strong = false;
 
        return t;
 
      } else if (!state.strong && stream.eat(ch)) { // Add STRONG
 
        state.strong = ch;
 
        return getType(state);
 
      } else if (state.em === ch) { // Remove EM
 
        state.em = false;
 
        return t;
 
      } else if (!state.em) { // Add EM
 
        state.em = ch;
 
        return getType(state);
 
      }
 
    } else if (ch === ' ') {
 
      if (stream.eat('*') || stream.eat('_')) { // Probably surrounded by spaces
 
        if (stream.peek() === ' ') { // Surrounded by spaces, ignore
 
          return getType(state);
 
        } else { // Not surrounded by spaces, back up pointer
 
          stream.backUp(1);
 
        }
 
      }
 
    }
 

	
 
    if (ch === ' ') {
 
      if (stream.match(/ +$/, false)) {
 
        state.trailingSpace++;
 
      } else if (state.trailingSpace) {
 
        state.trailingSpaceNewLine = true;
 
      }
 
    }
 

	
 
    return getType(state);
 
  }
 

	
 
  function linkHref(stream, state) {
 
    // Check if space, and return NULL if so (to avoid marking the space)
 
    if(stream.eatSpace()){
 
      return null;
 
    }
 
    var ch = stream.next();
 
    if (ch === '(' || ch === '[') {
 
      return switchInline(stream, state, inlineElement(linkhref, ch === '(' ? ')' : ']'));
 
    }
 
    return 'error';
 
  }
 

	
 
  function footnoteLink(stream, state) {
 
    if (stream.match(/^[^\]]*\]:/, true)) {
 
      state.f = footnoteUrl;
 
      return linktext;
 
    }
 
    return switchInline(stream, state, inlineNormal);
 
  }
 

	
 
  function footnoteUrl(stream, state) {
 
    // Check if space, and return NULL if so (to avoid marking the space)
 
    if(stream.eatSpace()){
 
      return null;
 
    }
 
    // Match URL
 
    stream.match(/^[^\s]+/, true);
 
    // Check for link title
 
    if (stream.peek() === undefined) { // End of line, set flag to check next line
 
      state.linkTitle = true;
 
    } else { // More content on line, check if link title
 
      stream.match(/^(?:\s+(?:"(?:[^"\\]|\\\\|\\.)+"|'(?:[^'\\]|\\\\|\\.)+'|\((?:[^)\\]|\\\\|\\.)+\)))?/, true);
 
    }
 
    state.f = state.inline = inlineNormal;
 
    return linkhref;
 
  }
 

	
 
  var savedInlineRE = [];
 
  function inlineRE(endChar) {
 
    if (!savedInlineRE[endChar]) {
 
      // Escape endChar for RegExp (taken from http://stackoverflow.com/a/494122/526741)
 
      endChar = (endChar+'').replace(/([.?*+^$[\]\\(){}|-])/g, "\\$1");
 
      // Match any non-endChar, escaped character, as well as the closing
 
      // endChar.
 
      savedInlineRE[endChar] = new RegExp('^(?:[^\\\\]|\\\\.)*?(' + endChar + ')');
 
    }
 
    return savedInlineRE[endChar];
 
  }
 

	
 
  function inlineElement(type, endChar, next) {
 
    next = next || inlineNormal;
 
    return function(stream, state) {
 
      stream.match(inlineRE(endChar));
 
      state.inline = state.f = next;
 
      return type;
 
    };
 
  }
 

	
 
  return {
 
    startState: function() {
 
      return {
 
        f: blockNormal,
 

	
 
        prevLineHasContent: false,
 
        thisLineHasContent: false,
 

	
 
        block: blockNormal,
 
        htmlState: CodeMirror.startState(htmlMode),
 
        indentation: 0,
 

	
 
        inline: inlineNormal,
 
        text: handleText,
 

	
 
        linkText: false,
 
        linkTitle: false,
 
        em: false,
 
        strong: false,
 
        header: false,
 
        taskList: false,
 
        list: false,
 
        listDepth: 0,
 
        quote: 0
 
        quote: 0,
 
        trailingSpace: 0,
 
        trailingSpaceNewLine: false
 
      };
 
    },
 

	
 
    copyState: function(s) {
 
      return {
 
        f: s.f,
 

	
 
        prevLineHasContent: s.prevLineHasContent,
 
        thisLineHasContent: s.thisLineHasContent,
 

	
 
        block: s.block,
 
        htmlState: CodeMirror.copyState(htmlMode, s.htmlState),
 
        indentation: s.indentation,
 

	
 
        localMode: s.localMode,
 
        localState: s.localMode ? CodeMirror.copyState(s.localMode, s.localState) : null,
 

	
 
        inline: s.inline,
 
        text: s.text,
 
        linkTitle: s.linkTitle,
 
        em: s.em,
 
        strong: s.strong,
 
        header: s.header,
 
        taskList: s.taskList,
 
        list: s.list,
 
        listDepth: s.listDepth,
 
        quote: s.quote,
 
        trailingSpace: s.trailingSpace,
 
        trailingSpaceNewLine: s.trailingSpaceNewLine,
 
        md_inside: s.md_inside
 
      };
 
    },
 

	
 
    token: function(stream, state) {
 
      if (stream.sol()) {
 
        if (stream.match(/^\s*$/, true)) {
 
          state.prevLineHasContent = false;
 
          return blankLine(state);
 
        } else {
 
          state.prevLineHasContent = state.thisLineHasContent;
 
          state.thisLineHasContent = true;
 
        }
 

	
 
        // Reset state.header
 
        state.header = false;
 

	
 
        // Reset state.taskList
 
        state.taskList = false;
 

	
 
        // Reset state.code
 
        state.code = false;
 

	
 
        // Reset state.trailingSpace
 
        state.trailingSpace = 0;
 
        state.trailingSpaceNewLine = false;
 

	
 
        state.f = state.block;
 
        var indentation = stream.match(/^\s*/, true)[0].replace(/\t/g, '    ').length;
 
        var difference = Math.floor((indentation - state.indentation) / 4) * 4;
 
        if (difference > 4) difference = 4;
 
        var adjustedIndentation = state.indentation + difference;
 
        state.indentationDiff = adjustedIndentation - state.indentation;
 
        state.indentation = adjustedIndentation;
 
        if (indentation > 0) return null;
 
      }
 
      return state.f(stream, state);
 
    },
 

	
 
    blankLine: blankLine,
 

	
 
    getType: getType
 
  };
 

	
 
}, "xml");
 

	
 
CodeMirror.defineMIME("text/x-markdown", "markdown");
rhodecode/public/js/mode/markdown/test.js
Show inline comments
 
(function() {
 
  var mode = CodeMirror.getMode({tabSize: 4}, "markdown");
 
  function MT(name) { test.mode(name, mode, Array.prototype.slice.call(arguments, 1)); }
 

	
 
  MT("plainText",
 
     "foo");
 

	
 
  // Don't style single trailing space
 
  MT("trailingSpace1",
 
     "foo ");
 

	
 
  // Two or more trailing spaces should be styled with line break character
 
  MT("trailingSpace2",
 
     "foo[trailing-space-a  ][trailing-space-new-line  ]");
 

	
 
  MT("trailingSpace3",
 
     "foo[trailing-space-a  ][trailing-space-b  ][trailing-space-new-line  ]");
 

	
 
  MT("trailingSpace4",
 
     "foo[trailing-space-a  ][trailing-space-b  ][trailing-space-a  ][trailing-space-new-line  ]");
 

	
 
  // Code blocks using 4 spaces (regardless of CodeMirror.tabSize value)
 
  MT("codeBlocksUsing4Spaces",
 
     "    [comment foo]");
 

	
 
  // Code blocks using 4 spaces with internal indentation
 
  MT("codeBlocksUsing4SpacesIndentation",
 
     "    [comment bar]",
 
     "        [comment hello]",
 
     "            [comment world]",
 
     "    [comment foo]",
 
     "bar");
 

	
 
  // Code blocks using 4 spaces with internal indentation
 
  MT("codeBlocksUsing4SpacesIndentation",
 
     " foo",
 
     "    [comment bar]",
 
     "        [comment hello]",
 
     "    [comment world]");
 

	
 
  // Code blocks using 1 tab (regardless of CodeMirror.indentWithTabs value)
 
  MT("codeBlocksUsing1Tab",
 
     "\t[comment foo]");
 

	
 
  // Inline code using backticks
 
  MT("inlineCodeUsingBackticks",
 
     "foo [comment `bar`]");
 

	
 
  // Block code using single backtick (shouldn't work)
 
  MT("blockCodeSingleBacktick",
 
     "[comment `]",
 
     "foo",
 
     "[comment `]");
 

	
 
  // Unclosed backticks
 
  // Instead of simply marking as CODE, it would be nice to have an
 
  // incomplete flag for CODE, that is styled slightly different.
 
  MT("unclosedBackticks",
 
     "foo [comment `bar]");
 

	
 
  // Per documentation: "To include a literal backtick character within a
 
  // code span, you can use multiple backticks as the opening and closing
 
  // delimiters"
 
  MT("doubleBackticks",
 
     "[comment ``foo ` bar``]");
 

	
 
  // Tests based on Dingus
 
  // http://daringfireball.net/projects/markdown/dingus
 
  //
 
  // Multiple backticks within an inline code block
 
  MT("consecutiveBackticks",
 
     "[comment `foo```bar`]");
 

	
 
  // Multiple backticks within an inline code block with a second code block
 
  MT("consecutiveBackticks",
 
     "[comment `foo```bar`] hello [comment `world`]");
 

	
 
  // Unclosed with several different groups of backticks
 
  MT("unclosedBackticks",
 
     "[comment ``foo ``` bar` hello]");
 

	
 
  // Closed with several different groups of backticks
 
  MT("closedBackticks",
 
     "[comment ``foo ``` bar` hello``] world");
 

	
 
  // atx headers
 
  // http://daringfireball.net/projects/markdown/syntax#header
 

	
 
  MT("atxH1",
 
     "[header # foo]");
 

	
 
  MT("atxH2",
 
     "[header ## foo]");
 

	
 
  MT("atxH3",
 
     "[header ### foo]");
 

	
 
  MT("atxH4",
 
     "[header #### foo]");
 

	
 
  MT("atxH5",
 
     "[header ##### foo]");
 

	
 
  MT("atxH6",
 
     "[header ###### foo]");
 

	
 
  // H6 - 7x '#' should still be H6, per Dingus
 
  // http://daringfireball.net/projects/markdown/dingus
 
  MT("atxH6NotH7",
 
     "[header ####### foo]");
 

	
 
  // Setext headers - H1, H2
 
  // Per documentation, "Any number of underlining =’s or -’s will work."
 
  // http://daringfireball.net/projects/markdown/syntax#header
 
  // Ideally, the text would be marked as `header` as well, but this is
 
  // not really feasible at the moment. So, instead, we're testing against
 
  // what works today, to avoid any regressions.
rhodecode/public/js/mode/meta.js
Show inline comments
 
CodeMirror.modeInfo = [
 
  {name: 'APL', mime: 'text/apl', mode: 'apl'},
 
  {name: 'Asterisk', mime: 'text/x-asterisk', mode: 'asterisk'},
 
  {name: 'C', mime: 'text/x-csrc', mode: 'clike'},
 
  {name: 'C++', mime: 'text/x-c++src', mode: 'clike'},
 
  {name: 'Cobol', mime: 'text/x-cobol', mode: 'cobol'},
 
  {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: 'GitHub Flavored Markdown', mime: 'text/x-gfm', 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: 'Jade', mime: 'text/x-jade', mode: 'jade'},
 
  {name: 'JavaScript', mime: 'text/javascript', mode: 'javascript'},
 
  {name: 'JSON', mime: 'application/x-json', mode: 'javascript'},
 
  {name: 'JSON', mime: 'application/json', mode: 'javascript'},
 
  {name: 'TypeScript', mime: 'application/typescript', mode: 'javascript'},
 
  {name: 'Jinja2', mime: 'jinja2', mode: 'jinja2'},
 
  {name: 'LESS', mime: 'text/x-less', mode: 'less'},
 
  {name: 'LiveScript', mime: 'text/x-livescript', mode: 'livescript'},
 
  {name: 'Lua', mime: 'text/x-lua', mode: 'lua'},
 
  {name: 'Markdown (GitHub-flavour)', mime: 'text/x-markdown', mode: 'markdown'},
 
  {name: 'mIRC', mime: 'text/mirc', mode: 'mirc'},
 
  {name: 'Nginx', mime: 'text/x-nginx-conf', mode: 'nginx'},
 
  {name: 'NTriples', mime: 'text/n-triples', mode: 'ntriples'},
 
  {name: 'OCaml', mime: 'text/x-ocaml', mode: 'ocaml'},
 
  {name: 'Pascal', mime: 'text/x-pascal', mode: 'pascal'},
 
  {name: 'Perl', mime: 'text/x-perl', mode: 'perl'},
 
  {name: 'PHP', mime: 'text/x-php', mode: 'php'},
 
  {name: 'PHP(HTML)', mime: 'application/x-httpd-php', mode: 'php'},
 
  {name: 'Pig', mime: 'text/x-pig', mode: 'pig'},
 
  {name: 'Plain Text', mime: 'text/plain', mode: 'null'},
 
  {name: 'Properties files', mime: 'text/x-properties', mode: 'clike'},
 
  {name: 'Python', mime: 'text/x-python', mode: 'python'},
 
  {name: 'Cython', mime: 'text/x-cython', mode: 'python'},
 
  {name: 'R', mime: 'text/x-rsrc', mode: 'r'},
 
  {name: 'reStructuredText', mime: 'text/x-rst', mode: 'rst'},
 
  {name: 'Ruby', mime: 'text/x-ruby', mode: 'ruby'},
 
  {name: 'Rust', mime: 'text/x-rustsrc', mode: 'rust'},
 
  {name: 'Sass', mime: 'text/x-sass', mode: 'sass'},
 
  {name: 'Scheme', mime: 'text/x-scheme', mode: 'scheme'},
 
  {name: 'SCSS', mime: 'text/x-scss', mode: 'css'},
 
  {name: 'Shell', mime: 'text/x-sh', mode: 'shell'},
 
  {name: 'Sieve', mime: 'application/sieve', mode: 'sieve'},
 
  {name: 'Smalltalk', mime: 'text/x-stsrc', mode: 'smalltalk'},
 
  {name: 'Smarty', mime: 'text/x-smarty', mode: 'smarty'},
 
  {name: 'SmartyMixed', mime: 'text/x-smarty', mode: 'smartymixed'},
 
  {name: 'SPARQL', mime: 'application/x-sparql-query', mode: 'sparql'},
 
  {name: 'SQL', mime: 'text/x-sql', mode: 'sql'},
 
  {name: 'MariaDB', mime: 'text/x-mariadb', mode: 'sql'},
 
  {name: 'sTeX', mime: 'text/x-stex', mode: 'stex'},
 
  {name: 'LaTeX', mime: 'text/x-latex', mode: 'stex'},
 
  {name: 'Tcl', mime: 'text/x-tcl', mode: 'tcl'},
 
  {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'}
 
];
rhodecode/public/js/mode/nginx/index.html
Show inline comments
 
new file 100644
 
<!doctype html>
 
<html>
 
  <head>
 
    <title>CodeMirror: NGINX mode</title>
 
    <link rel="stylesheet" href="../../lib/codemirror.css">
 
    <script src="../../lib/codemirror.js"></script>
 
    <script src="nginx.js"></script>
 
    <style>.CodeMirror {background: #f8f8f8;}</style>
 
    <link rel="stylesheet" href="../../doc/docs.css">
 
  </head>
 

	
 
  <style>
 
    body {
 
      margin: 0em auto;
 
    }
 

	
 
    .CodeMirror, .CodeMirror-scroll {
 
      height: 600px;
 
    }
 
  </style>
 

	
 
  <body>
 
    <h1>CodeMirror: NGINX mode</h1>
 
    <form><textarea id="code" name="code" style="height: 800px;">
 
server {
 
  listen 173.255.219.235:80;
 
  server_name website.com.au;
 
  rewrite / $scheme://www.$host$request_uri permanent; ## Forcibly prepend a www
 
}
 

	
 
server {
 
  listen 173.255.219.235:443;
 
  server_name website.com.au;
 
  rewrite / $scheme://www.$host$request_uri permanent; ## Forcibly prepend a www
 
}
 

	
 
server {
 

	
 
  listen      173.255.219.235:80;
 
  server_name www.website.com.au;
 

	
 

	
 

	
 
  root        /data/www;
 
  index       index.html index.php;
 

	
 
  location / {
 
    index index.html index.php;     ## Allow a static html file to be shown first
 
    try_files $uri $uri/ @handler;  ## If missing pass the URI to Magento's front handler
 
    expires 30d;                    ## Assume all files are cachable
 
  }
 

	
 
  ## These locations would be hidden by .htaccess normally
 
  location /app/                { deny all; }
 
  location /includes/           { deny all; }
 
  location /lib/                { deny all; }
 
  location /media/downloadable/ { deny all; }
 
  location /pkginfo/            { deny all; }
 
  location /report/config.xml   { deny all; }
 
  location /var/                { deny all; }
 

	
 
  location /var/export/ { ## Allow admins only to view export folder
 
    auth_basic           "Restricted"; ## Message shown in login window
 
    auth_basic_user_file /rs/passwords/testfile; ## See /etc/nginx/htpassword
 
    autoindex            on;
 
  }
 

	
 
  location  /. { ## Disable .htaccess and other hidden files
 
    return 404;
 
  }
 

	
 
  location @handler { ## Magento uses a common front handler
 
    rewrite / /index.php;
 
  }
 

	
 
  location ~ .php/ { ## Forward paths like /js/index.php/x.js to relevant handler
 
    rewrite ^/(.*.php)/ /$1 last;
 
  }
 

	
 
  location ~ \.php$ {
 
    if (!-e $request_filename) { rewrite / /index.php last; } ## Catch 404s that try_files miss
 

	
 
    fastcgi_pass   127.0.0.1:9000;
 
    fastcgi_index  index.php;
 
    fastcgi_param PATH_INFO $fastcgi_script_name;
 
    fastcgi_param  SCRIPT_FILENAME $document_root$fastcgi_script_name;
 
    include        /rs/confs/nginx/fastcgi_params;
 
  }
 

	
 
}
 

	
 

	
 
server {
 

	
 
  listen              173.255.219.235:443;
 
  server_name         website.com.au www.website.com.au;
 

	
 
  root   /data/www;
 
  index index.html index.php;
 

	
 
  ssl                 on;
 
  ssl_certificate     /rs/ssl/ssl.crt;
 
  ssl_certificate_key /rs/ssl/ssl.key;
 

	
 
  ssl_session_timeout  5m;
 

	
 
  ssl_protocols  SSLv2 SSLv3 TLSv1;
 
  ssl_ciphers  ALL:!ADH:!EXPORT56:RC4+RSA:+HIGH:+MEDIUM:+LOW:+SSLv2:+EXP;
 
  ssl_prefer_server_ciphers   on;
 

	
 

	
 

	
 
  location / {
 
    index index.html index.php; ## Allow a static html file to be shown first
 
    try_files $uri $uri/ @handler; ## If missing pass the URI to Magento's front handler
 
    expires 30d; ## Assume all files are cachable
 
  }
 

	
 
  ## These locations would be hidden by .htaccess normally
 
  location /app/                { deny all; }
 
  location /includes/           { deny all; }
 
  location /lib/                { deny all; }
 
  location /media/downloadable/ { deny all; }
 
  location /pkginfo/            { deny all; }
 
  location /report/config.xml   { deny all; }
 
  location /var/                { deny all; }
 

	
 
  location /var/export/ { ## Allow admins only to view export folder
 
    auth_basic           "Restricted"; ## Message shown in login window
 
    auth_basic_user_file htpasswd; ## See /etc/nginx/htpassword
 
    autoindex            on;
 
  }
 

	
 
  location  /. { ## Disable .htaccess and other hidden files
 
    return 404;
 
  }
 

	
 
  location @handler { ## Magento uses a common front handler
 
    rewrite / /index.php;
 
  }
 

	
 
  location ~ .php/ { ## Forward paths like /js/index.php/x.js to relevant handler
 
    rewrite ^/(.*.php)/ /$1 last;
 
  }
 

	
 
  location ~ .php$ { ## Execute PHP scripts
 
    if (!-e $request_filename) { rewrite  /index.php last; } ## Catch 404s that try_files miss
 

	
 
    fastcgi_pass 127.0.0.1:9000;
 
    fastcgi_index  index.php;
 
    fastcgi_param PATH_INFO $fastcgi_script_name;
 
    fastcgi_param  SCRIPT_FILENAME $document_root$fastcgi_script_name;
 
    include        /rs/confs/nginx/fastcgi_params;
 

	
 
    fastcgi_param HTTPS on;
 
  }
 

	
 
}
 
</textarea></form>
 
    <script>
 
      var editor = CodeMirror.fromTextArea(document.getElementById("code"), {});
 
    </script>
 

	
 
    <p><strong>MIME types defined:</strong> <code>text/nginx</code>.</p>
 

	
 
  </body>
 
</html>
rhodecode/public/js/mode/nginx/nginx.js
Show inline comments
 
new file 100644
 
CodeMirror.defineMode("nginx", function(config) {
 

	
 
  function words(str) {
 
    var obj = {}, words = str.split(" ");
 
    for (var i = 0; i < words.length; ++i) obj[words[i]] = true;
 
    return obj;
 
  }
 

	
 
  var keywords = words(
 
    /* ngxDirectiveControl */ "break return rewrite set" +
 
    /* ngxDirective */ " accept_mutex accept_mutex_delay access_log add_after_body add_before_body add_header addition_types aio alias allow ancient_browser ancient_browser_value auth_basic auth_basic_user_file auth_http auth_http_header auth_http_timeout autoindex autoindex_exact_size autoindex_localtime charset charset_types client_body_buffer_size client_body_in_file_only client_body_in_single_buffer client_body_temp_path client_body_timeout client_header_buffer_size client_header_timeout client_max_body_size connection_pool_size create_full_put_path daemon dav_access dav_methods debug_connection debug_points default_type degradation degrade deny devpoll_changes devpoll_events directio directio_alignment empty_gif env epoll_events error_log eventport_events expires fastcgi_bind fastcgi_buffer_size fastcgi_buffers fastcgi_busy_buffers_size fastcgi_cache fastcgi_cache_key fastcgi_cache_methods fastcgi_cache_min_uses fastcgi_cache_path fastcgi_cache_use_stale fastcgi_cache_valid fastcgi_catch_stderr fastcgi_connect_timeout fastcgi_hide_header fastcgi_ignore_client_abort fastcgi_ignore_headers fastcgi_index fastcgi_intercept_errors fastcgi_max_temp_file_size fastcgi_next_upstream fastcgi_param fastcgi_pass_header fastcgi_pass_request_body fastcgi_pass_request_headers fastcgi_read_timeout fastcgi_send_lowat fastcgi_send_timeout fastcgi_split_path_info fastcgi_store fastcgi_store_access fastcgi_temp_file_write_size fastcgi_temp_path fastcgi_upstream_fail_timeout fastcgi_upstream_max_fails flv geoip_city geoip_country google_perftools_profiles gzip gzip_buffers gzip_comp_level gzip_disable gzip_hash gzip_http_version gzip_min_length gzip_no_buffer gzip_proxied gzip_static gzip_types gzip_vary gzip_window if_modified_since ignore_invalid_headers image_filter image_filter_buffer image_filter_jpeg_quality image_filter_transparency imap_auth imap_capabilities imap_client_buffer index ip_hash keepalive_requests keepalive_timeout kqueue_changes kqueue_events large_client_header_buffers limit_conn limit_conn_log_level limit_rate limit_rate_after limit_req limit_req_log_level limit_req_zone limit_zone lingering_time lingering_timeout lock_file log_format log_not_found log_subrequest map_hash_bucket_size map_hash_max_size master_process memcached_bind memcached_buffer_size memcached_connect_timeout memcached_next_upstream memcached_read_timeout memcached_send_timeout memcached_upstream_fail_timeout memcached_upstream_max_fails merge_slashes min_delete_depth modern_browser modern_browser_value msie_padding msie_refresh multi_accept open_file_cache open_file_cache_errors open_file_cache_events open_file_cache_min_uses open_file_cache_valid open_log_file_cache output_buffers override_charset perl perl_modules perl_require perl_set pid pop3_auth pop3_capabilities port_in_redirect postpone_gzipping postpone_output protocol proxy proxy_bind proxy_buffer proxy_buffer_size proxy_buffering proxy_buffers proxy_busy_buffers_size proxy_cache proxy_cache_key proxy_cache_methods proxy_cache_min_uses proxy_cache_path proxy_cache_use_stale proxy_cache_valid proxy_connect_timeout proxy_headers_hash_bucket_size proxy_headers_hash_max_size proxy_hide_header proxy_ignore_client_abort proxy_ignore_headers proxy_intercept_errors proxy_max_temp_file_size proxy_method proxy_next_upstream proxy_pass_error_message proxy_pass_header proxy_pass_request_body proxy_pass_request_headers proxy_read_timeout proxy_redirect proxy_send_lowat proxy_send_timeout proxy_set_body proxy_set_header proxy_ssl_session_reuse proxy_store proxy_store_access proxy_temp_file_write_size proxy_temp_path proxy_timeout proxy_upstream_fail_timeout proxy_upstream_max_fails random_index read_ahead real_ip_header recursive_error_pages request_pool_size reset_timedout_connection resolver resolver_timeout rewrite_log rtsig_overflow_events rtsig_overflow_test rtsig_overflow_threshold rtsig_signo satisfy secure_link_secret send_lowat send_timeout sendfile sendfile_max_chunk server_name_in_redirect server_names_hash_bucket_size server_names_hash_max_size server_tokens set_real_ip_from smtp_auth smtp_capabilities smtp_client_buffer smtp_greeting_delay so_keepalive source_charset ssi ssi_ignore_recycled_buffers ssi_min_file_chunk ssi_silent_errors ssi_types ssi_value_length ssl ssl_certificate ssl_certificate_key ssl_ciphers ssl_client_certificate ssl_crl ssl_dhparam ssl_engine ssl_prefer_server_ciphers ssl_protocols ssl_session_cache ssl_session_timeout ssl_verify_client ssl_verify_depth starttls stub_status sub_filter sub_filter_once sub_filter_types tcp_nodelay tcp_nopush thread_stack_size timeout timer_resolution types_hash_bucket_size types_hash_max_size underscores_in_headers uninitialized_variable_warn use user userid userid_domain userid_expires userid_mark userid_name userid_p3p userid_path userid_service valid_referers variables_hash_bucket_size variables_hash_max_size worker_connections worker_cpu_affinity worker_priority worker_processes worker_rlimit_core worker_rlimit_nofile worker_rlimit_sigpending worker_threads working_directory xclient xml_entities xslt_stylesheet xslt_typesdrew@li229-23"
 
    );
 

	
 
  var keywords_block = words(
 
    /* ngxDirectiveBlock */ "http mail events server types location upstream charset_map limit_except if geo map"
 
    );
 

	
 
  var keywords_important = words(
 
    /* ngxDirectiveImportant */ "include root server server_name listen internal proxy_pass memcached_pass fastcgi_pass try_files"
 
    );
 

	
 
  var indentUnit = config.indentUnit, type;
 
  function ret(style, tp) {type = tp; return style;}
 

	
 
  function tokenBase(stream, state) {
 

	
 

	
 
    stream.eatWhile(/[\w\$_]/);
 

	
 
    var cur = stream.current();
 

	
 

	
 
    if (keywords.propertyIsEnumerable(cur)) {
 
      return "keyword";
 
    }
 
    else if (keywords_block.propertyIsEnumerable(cur)) {
 
      return "variable-2";
 
    }
 
    else if (keywords_important.propertyIsEnumerable(cur)) {
 
      return "string-2";
 
    }
 
    /**/
 

	
 
    var ch = stream.next();
 
    if (ch == "@") {stream.eatWhile(/[\w\\\-]/); return ret("meta", stream.current());}
 
    else if (ch == "/" && stream.eat("*")) {
 
      state.tokenize = tokenCComment;
 
      return tokenCComment(stream, state);
 
    }
 
    else if (ch == "<" && stream.eat("!")) {
 
      state.tokenize = tokenSGMLComment;
 
      return tokenSGMLComment(stream, state);
 
    }
 
    else if (ch == "=") ret(null, "compare");
 
    else if ((ch == "~" || ch == "|") && stream.eat("=")) return ret(null, "compare");
 
    else if (ch == "\"" || ch == "'") {
 
      state.tokenize = tokenString(ch);
 
      return state.tokenize(stream, state);
 
    }
 
    else if (ch == "#") {
 
      stream.skipToEnd();
 
      return ret("comment", "comment");
 
    }
 
    else if (ch == "!") {
 
      stream.match(/^\s*\w*/);
 
      return ret("keyword", "important");
 
    }
 
    else if (/\d/.test(ch)) {
 
      stream.eatWhile(/[\w.%]/);
 
      return ret("number", "unit");
 
    }
 
    else if (/[,.+>*\/]/.test(ch)) {
 
      return ret(null, "select-op");
 
    }
 
    else if (/[;{}:\[\]]/.test(ch)) {
 
      return ret(null, ch);
 
    }
 
    else {
 
      stream.eatWhile(/[\w\\\-]/);
 
      return ret("variable", "variable");
 
    }
 
  }
 

	
 
  function tokenCComment(stream, state) {
 
    var maybeEnd = false, ch;
 
    while ((ch = stream.next()) != null) {
 
      if (maybeEnd && ch == "/") {
 
        state.tokenize = tokenBase;
 
        break;
 
      }
 
      maybeEnd = (ch == "*");
 
    }
 
    return ret("comment", "comment");
 
  }
 

	
 
  function tokenSGMLComment(stream, state) {
 
    var dashes = 0, ch;
 
    while ((ch = stream.next()) != null) {
 
      if (dashes >= 2 && ch == ">") {
 
        state.tokenize = tokenBase;
 
        break;
 
      }
 
      dashes = (ch == "-") ? dashes + 1 : 0;
 
    }
 
    return ret("comment", "comment");
 
  }
 

	
 
  function tokenString(quote) {
 
    return function(stream, state) {
 
      var escaped = false, ch;
 
      while ((ch = stream.next()) != null) {
 
        if (ch == quote && !escaped)
 
          break;
 
        escaped = !escaped && ch == "\\";
 
      }
 
      if (!escaped) state.tokenize = tokenBase;
 
      return ret("string", "string");
 
    };
 
  }
 

	
 
  return {
 
    startState: function(base) {
 
      return {tokenize: tokenBase,
 
              baseIndent: base || 0,
 
              stack: []};
 
    },
 

	
 
    token: function(stream, state) {
 
      if (stream.eatSpace()) return null;
 
      type = null;
 
      var style = state.tokenize(stream, state);
 

	
 
      var context = state.stack[state.stack.length-1];
 
      if (type == "hash" && context == "rule") style = "atom";
 
      else if (style == "variable") {
 
        if (context == "rule") style = "number";
 
        else if (!context || context == "@media{") style = "tag";
 
      }
 

	
 
      if (context == "rule" && /^[\{\};]$/.test(type))
 
        state.stack.pop();
 
      if (type == "{") {
 
        if (context == "@media") state.stack[state.stack.length-1] = "@media{";
 
        else state.stack.push("{");
 
      }
 
      else if (type == "}") state.stack.pop();
 
      else if (type == "@media") state.stack.push("@media");
 
      else if (context == "{" && type != "comment") state.stack.push("rule");
 
      return style;
 
    },
 

	
 
    indent: function(state, textAfter) {
 
      var n = state.stack.length;
 
      if (/^\}/.test(textAfter))
 
        n -= state.stack[state.stack.length-1] == "rule" ? 2 : 1;
 
      return state.baseIndent + n * indentUnit;
 
    },
 

	
 
    electricChars: "}"
 
  };
 
});
 

	
 
CodeMirror.defineMIME("text/nginx", "text/x-nginx-conf");
rhodecode/public/js/mode/python/index.html
Show inline comments
 
<!doctype html>
 
<html>
 
  <head>
 
    <meta charset="utf-8">
 
    <title>CodeMirror: Python mode</title>
 
    <link rel="stylesheet" href="../../lib/codemirror.css">
 
    <script src="../../lib/codemirror.js"></script>
 
    <script src="../../addon/edit/matchbrackets.js"></script>
 
    <script src="python.js"></script>
 
    <link rel="stylesheet" href="../../doc/docs.css">
 
    <style type="text/css">.CodeMirror {border-top: 1px solid black; border-bottom: 1px solid black;}</style>
 
  </head>
 
  <body>
 
    <h1>CodeMirror: Python mode</h1>
 

	
 
    <h2>Python mode</h2>
 
    <div><textarea id="code" name="code">
 
# Literals
 
1234
 
0.0e101
 
.123
 
0b01010011100
 
0o01234567
 
0x0987654321abcdef
 
7
 
2147483647
 
3L
 
79228162514264337593543950336L
 
0x100000000L
 
79228162514264337593543950336
 
0xdeadbeef
 
3.14j
 
10.j
 
10j
 
.001j
 
1e100j
 
3.14e-10j
 

	
 

	
 
# String Literals
 
'For\''
 
"God\""
 
"""so loved
 
the world"""
 
'''that he gave
 
his only begotten\' '''
 
'that whosoever believeth \
 
in him'
 
''
 

	
 
# Identifiers
 
__a__
 
a.b
 
a.b.c
 

	
 
# Operators
 
+ - * / % & | ^ ~ < >
 
== != <= >= <> << >> // **
 
and or not in is
 

	
 
# Delimiters
 
() [] {} , : ` = ; @ .  # Note that @ and . require the proper context.
 
+= -= *= /= %= &= |= ^=
 
//= >>= <<= **=
 

	
 
# Keywords
 
as assert break class continue def del elif else except
 
finally for from global if import lambda pass raise
 
return try while with yield
 

	
 
# Python 2 Keywords (otherwise Identifiers)
 
exec print
 

	
 
# Python 3 Keywords (otherwise Identifiers)
 
nonlocal
 

	
 
# Types
 
bool classmethod complex dict enumerate float frozenset int list object
 
property reversed set slice staticmethod str super tuple type
 

	
 
# Python 2 Types (otherwise Identifiers)
 
basestring buffer file long unicode xrange
 

	
 
# Python 3 Types (otherwise Identifiers)
 
bytearray bytes filter map memoryview open range zip
 

	
 
# Some Example code
 
import os
 
from package import ParentClass
 

	
 
@nonsenseDecorator
 
def doesNothing():
 
    pass
 

	
 
class ExampleClass(ParentClass):
 
    @staticmethod
 
    def example(inputStr):
 
        a = list(inputStr)
 
        a.reverse()
 
        return ''.join(a)
 

	
 
    def __init__(self, mixin = 'Hello'):
 
        self.mixin = mixin
 

	
 
</textarea></div>
 

	
 

	
 
<h2>Cython mode</h2>
 

	
 
<div><textarea id="code-cython" name="code-cython">
 

	
 
import numpy as np
 
cimport cython
 
from libc.math cimport sqrt
 

	
 
@cython.boundscheck(False)
 
@cython.wraparound(False)
 
def pairwise_cython(double[:, ::1] X):
 
    cdef int M = X.shape[0]
 
    cdef int N = X.shape[1]
 
    cdef double tmp, d
 
    cdef double[:, ::1] D = np.empty((M, M), dtype=np.float64)
 
    for i in range(M):
 
        for j in range(M):
 
            d = 0.0
 
            for k in range(N):
 
                tmp = X[i, k] - X[j, k]
 
                d += tmp * tmp
 
            D[i, j] = sqrt(d)
 
    return np.asarray(D)
 

	
 
</textarea></div>
 

	
 
    <script>
 
      var editor = CodeMirror.fromTextArea(document.getElementById("code"), {
 
        mode: {name: "python",
 
               version: 2,
 
               singleLineStringErrors: false},
 
        lineNumbers: true,
 
        indentUnit: 4,
 
        tabMode: "shift",
 
        matchBrackets: true
 
    });
 

	
 
    CodeMirror.fromTextArea(document.getElementById("code-cython"), {
 
        mode: {name: "text/x-cython",
 
               version: 2,
 
               singleLineStringErrors: false},
 
        lineNumbers: true,
 
        indentUnit: 4,
 
        tabMode: "shift",
 
        matchBrackets: true
 
      });
 
    </script>
 
    <h2>Configuration Options:</h2>
 
    <h2>Configuration Options for Python mode:</h2>
 
    <ul>
 
      <li>version - 2/3 - The version of Python to recognize.  Default is 2.</li>
 
      <li>singleLineStringErrors - true/false - If you have a single-line string that is not terminated at the end of the line, this will show subsequent lines as errors if true, otherwise it will consider the newline as the end of the string. Default is false.</li>
 
    </ul>
 
    <h2>Advanced Configuration Options:</h2>
 
    <p>Usefull for superset of python syntax like Enthought enaml, IPython magics and  questionmark help</p>
 
    <ul>
 
      <li>singleOperators - RegEx - Regular Expression for single operator matching,  default : <pre>^[\\+\\-\\*/%&amp;|\\^~&lt;&gt;!]</pre></li>
 
      <li>singleDelimiters - RegEx - Regular Expression for single delimiter matching, default :  <pre>^[\\(\\)\\[\\]\\{\\}@,:`=;\\.]</pre></li>
 
      <li>doubleOperators - RegEx - Regular Expression for double operators matching, default : <pre>^((==)|(!=)|(&lt;=)|(&gt;=)|(&lt;&gt;)|(&lt;&lt;)|(&gt;&gt;)|(//)|(\\*\\*))</pre></li>
 
      <li>doubleDelimiters - RegEx - Regular Expressoin for double delimiters matching, default : <pre>^((\\+=)|(\\-=)|(\\*=)|(%=)|(/=)|(&amp;=)|(\\|=)|(\\^=))</pre></li>
 
      <li>tripleDelimiters - RegEx - Regular Expression for triple delimiters matching, default : <pre>^((//=)|(&gt;&gt;=)|(&lt;&lt;=)|(\\*\\*=))</pre></li>
 
      <li>identifiers - RegEx - Regular Expression for identifier, default : <pre>^[_A-Za-z][_A-Za-z0-9]*</pre></li>
 
      <li>extra_keywords - list of string - List of extra words ton consider as keywords</li>
 
      <li>extra_builtins - list of string - List of extra words ton consider as builtins</li>
 
    </ul>
 

	
 

	
 
    <p><strong>MIME types defined:</strong> <code>text/x-python</code>.</p>
 
    <p><strong>MIME types defined:</strong> <code>text/x-python</code> and <code>text/x-cython</code>.</p>
 
  </body>
 
</html>
rhodecode/public/js/mode/python/python.js
Show inline comments
 
CodeMirror.defineMode("python", function(conf, parserConf) {
 
    var ERRORCLASS = 'error';
 

	
 
    function wordRegexp(words) {
 
        return new RegExp("^((" + words.join(")|(") + "))\\b");
 
    }
 

	
 
    var singleOperators = parserConf.singleOperators || new RegExp("^[\\+\\-\\*/%&|\\^~<>!]");
 
    var singleDelimiters = parserConf.singleDelimiters || new RegExp('^[\\(\\)\\[\\]\\{\\}@,:`=;\\.]');
 
    var doubleOperators = parserConf.doubleOperators || new RegExp("^((==)|(!=)|(<=)|(>=)|(<>)|(<<)|(>>)|(//)|(\\*\\*))");
 
    var doubleDelimiters = parserConf.doubleDelimiters || new RegExp("^((\\+=)|(\\-=)|(\\*=)|(%=)|(/=)|(&=)|(\\|=)|(\\^=))");
 
    var tripleDelimiters = parserConf.tripleDelimiters || new RegExp("^((//=)|(>>=)|(<<=)|(\\*\\*=))");
 
    var identifiers = parserConf.identifiers|| new RegExp("^[_A-Za-z][_A-Za-z0-9]*");
 

	
 
    var wordOperators = wordRegexp(['and', 'or', 'not', 'is', 'in']);
 
    var commonkeywords = ['as', 'assert', 'break', 'class', 'continue',
 
                          'def', 'del', 'elif', 'else', 'except', 'finally',
 
                          'for', 'from', 'global', 'if', 'import',
 
                          'lambda', 'pass', 'raise', 'return',
 
                          'try', 'while', 'with', 'yield'];
 
    var commonBuiltins = ['abs', 'all', 'any', 'bin', 'bool', 'bytearray', 'callable', 'chr',
 
                          'classmethod', 'compile', 'complex', 'delattr', 'dict', 'dir', 'divmod',
 
                          'enumerate', 'eval', 'filter', 'float', 'format', 'frozenset',
 
                          'getattr', 'globals', 'hasattr', 'hash', 'help', 'hex', 'id',
 
                          'input', 'int', 'isinstance', 'issubclass', 'iter', 'len',
 
                          'list', 'locals', 'map', 'max', 'memoryview', 'min', 'next',
 
                          'object', 'oct', 'open', 'ord', 'pow', 'property', 'range',
 
                          'repr', 'reversed', 'round', 'set', 'setattr', 'slice',
 
                          'sorted', 'staticmethod', 'str', 'sum', 'super', 'tuple',
 
                          'type', 'vars', 'zip', '__import__', 'NotImplemented',
 
                          'Ellipsis', '__debug__'];
 
    var py2 = {'builtins': ['apply', 'basestring', 'buffer', 'cmp', 'coerce', 'execfile',
 
                            'file', 'intern', 'long', 'raw_input', 'reduce', 'reload',
 
                            'unichr', 'unicode', 'xrange', 'False', 'True', 'None'],
 
               'keywords': ['exec', 'print']};
 
    var py3 = {'builtins': ['ascii', 'bytes', 'exec', 'print'],
 
               'keywords': ['nonlocal', 'False', 'True', 'None']};
 

	
 
    if(parserConf.extra_keywords != undefined){
 
        commonkeywords = commonkeywords.concat(parserConf.extra_keywords);
 
    }
 
    if(parserConf.extra_builtins != undefined){
 
        commonBuiltins = commonBuiltins.concat(parserConf.extra_builtins);
 
    }
 
    if (!!parserConf.version && parseInt(parserConf.version, 10) === 3) {
 
        commonkeywords = commonkeywords.concat(py3.keywords);
 
        commonBuiltins = commonBuiltins.concat(py3.builtins);
 
        var stringPrefixes = new RegExp("^(([rb]|(br))?('{3}|\"{3}|['\"]))", "i");
 
    } else {
 
        commonkeywords = commonkeywords.concat(py2.keywords);
 
        commonBuiltins = commonBuiltins.concat(py2.builtins);
 
        var stringPrefixes = new RegExp("^(([rub]|(ur)|(br))?('{3}|\"{3}|['\"]))", "i");
 
    }
 
    var keywords = wordRegexp(commonkeywords);
 
    var builtins = wordRegexp(commonBuiltins);
 

	
 
    var indentInfo = null;
 

	
 
    // tokenizers
 
    function tokenBase(stream, state) {
 
        // Handle scope changes
 
        if (stream.sol()) {
 
            var scopeOffset = state.scopes[0].offset;
 
            if (stream.eatSpace()) {
 
                var lineOffset = stream.indentation();
 
                if (lineOffset > scopeOffset) {
 
                    indentInfo = 'indent';
 
                } else if (lineOffset < scopeOffset) {
 
                    indentInfo = 'dedent';
 
                }
 
                return null;
 
            } else {
 
                if (scopeOffset > 0) {
 
                    dedent(stream, state);
 
                }
 
            }
 
        }
 
        if (stream.eatSpace()) {
 
            return null;
 
        }
 

	
 
        var ch = stream.peek();
 

	
 
        // Handle Comments
 
        if (ch === '#') {
 
            stream.skipToEnd();
 
            return 'comment';
 
        }
 

	
 
        // Handle Number Literals
 
        if (stream.match(/^[0-9\.]/, false)) {
 
            var floatLiteral = false;
 
            // Floats
 
            if (stream.match(/^\d*\.\d+(e[\+\-]?\d+)?/i)) { floatLiteral = true; }
 
            if (stream.match(/^\d+\.\d*/)) { floatLiteral = true; }
 
            if (stream.match(/^\.\d+/)) { floatLiteral = true; }
 
            if (floatLiteral) {
 
                // Float literals may be "imaginary"
 
                stream.eat(/J/i);
 
                return 'number';
 
            }
 
            // Integers
 
            var intLiteral = false;
 
            // Hex
 
            if (stream.match(/^0x[0-9a-f]+/i)) { intLiteral = true; }
 
            // Binary
 
            if (stream.match(/^0b[01]+/i)) { intLiteral = true; }
 
            // Octal
 
            if (stream.match(/^0o[0-7]+/i)) { intLiteral = true; }
 
            // Decimal
 
            if (stream.match(/^[1-9]\d*(e[\+\-]?\d+)?/)) {
 
                // Decimal literals may be "imaginary"
 
                stream.eat(/J/i);
 
                // TODO - Can you have imaginary longs?
 
                intLiteral = true;
 
            }
 
            // Zero by itself with no other piece of number.
 
            if (stream.match(/^0(?![\dx])/i)) { intLiteral = true; }
 
            if (intLiteral) {
 
                // Integer literals may be "long"
 
                stream.eat(/L/i);
 
                return 'number';
 
            }
 
        }
 

	
 
        // Handle Strings
 
        if (stream.match(stringPrefixes)) {
 
            state.tokenize = tokenStringFactory(stream.current());
 
            return state.tokenize(stream, state);
 
        }
 

	
 
        // Handle operators and Delimiters
 
        if (stream.match(tripleDelimiters) || stream.match(doubleDelimiters)) {
 
            return null;
 
        }
 
        if (stream.match(doubleOperators)
 
            || stream.match(singleOperators)
 
            || stream.match(wordOperators)) {
 
            return 'operator';
 
        }
 
@@ -225,117 +231,128 @@ CodeMirror.defineMode("python", function
 
            }
 
            if (_indent_index === -1) {
 
                return true;
 
            }
 
            while (state.scopes[0].offset !== _indent) {
 
                state.scopes.shift();
 
            }
 
            return false;
 
        } else {
 
            if (type === 'py') {
 
                state.scopes[0].offset = stream.indentation();
 
                return false;
 
            } else {
 
                if (state.scopes[0].type != type) {
 
                    return true;
 
                }
 
                state.scopes.shift();
 
                return false;
 
            }
 
        }
 
    }
 

	
 
    function tokenLexer(stream, state) {
 
        indentInfo = null;
 
        var style = state.tokenize(stream, state);
 
        var current = stream.current();
 

	
 
        // Handle '.' connected identifiers
 
        if (current === '.') {
 
            style = stream.match(identifiers, false) ? null : ERRORCLASS;
 
            if (style === null && state.lastToken === 'meta') {
 
                // Apply 'meta' style to '.' connected identifiers when
 
                // appropriate.
 
                style = 'meta';
 
            }
 
            return style;
 
        }
 

	
 
        // Handle decorators
 
        if (current === '@') {
 
            return stream.match(identifiers, false) ? 'meta' : ERRORCLASS;
 
        }
 

	
 
        if ((style === 'variable' || style === 'builtin')
 
            && state.lastToken === 'meta') {
 
            style = 'meta';
 
        }
 

	
 
        // Handle scope changes.
 
        if (current === 'pass' || current === 'return') {
 
            state.dedent += 1;
 
        }
 
        if (current === 'lambda') state.lambda = true;
 
        if ((current === ':' && !state.lambda && state.scopes[0].type == 'py')
 
            || indentInfo === 'indent') {
 
            indent(stream, state);
 
        }
 
        var delimiter_index = '[({'.indexOf(current);
 
        if (delimiter_index !== -1) {
 
            indent(stream, state, '])}'.slice(delimiter_index, delimiter_index+1));
 
        }
 
        if (indentInfo === 'dedent') {
 
            if (dedent(stream, state)) {
 
                return ERRORCLASS;
 
            }
 
        }
 
        delimiter_index = '])}'.indexOf(current);
 
        if (delimiter_index !== -1) {
 
            if (dedent(stream, state, current)) {
 
                return ERRORCLASS;
 
            }
 
        }
 
        if (state.dedent > 0 && stream.eol() && state.scopes[0].type == 'py') {
 
            if (state.scopes.length > 1) state.scopes.shift();
 
            state.dedent -= 1;
 
        }
 

	
 
        return style;
 
    }
 

	
 
    var external = {
 
        startState: function(basecolumn) {
 
            return {
 
              tokenize: tokenBase,
 
              scopes: [{offset:basecolumn || 0, type:'py'}],
 
              lastToken: null,
 
              lambda: false,
 
              dedent: 0
 
          };
 
        },
 

	
 
        token: function(stream, state) {
 
            var style = tokenLexer(stream, state);
 

	
 
            state.lastToken = style;
 

	
 
            if (stream.eol() && stream.lambda) {
 
            if (stream.eol() && state.lambda) {
 
                state.lambda = false;
 
            }
 

	
 
            return style;
 
        },
 

	
 
        indent: function(state) {
 
            if (state.tokenize != tokenBase) {
 
                return state.tokenize.isString ? CodeMirror.Pass : 0;
 
            }
 

	
 
            return state.scopes[0].offset;
 
        },
 

	
 
        lineComment: "#"
 
        lineComment: "#",
 
        fold: "indent"
 
    };
 
    return external;
 
});
 

	
 
CodeMirror.defineMIME("text/x-python", "python");
 

	
 
var words = function(str){return str.split(' ');};
 

	
 

	
 
CodeMirror.defineMIME("text/x-cython", {
 
  name: "python",
 
  extra_keywords: words("by cdef cimport cpdef ctypedef enum except"+
 
                        "extern gil include nogil property public"+
 
                        "readonly struct union DEF IF ELIF ELSE")
 
});
rhodecode/public/js/mode/rst/LICENSE.txt
Show inline comments
 
The MIT License
 

	
 
Copyright (c) 2013 Hasan Karahan
 
Copyright (c) 2013 Hasan Karahan <hasan.karahan81@gmail.com>
 

	
 
Permission is hereby granted, free of charge, to any person obtaining a copy
 
of this software and associated documentation files (the "Software"), to deal
 
in the Software without restriction, including without limitation the rights
 
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 
copies of the Software, and to permit persons to whom the Software is
 
furnished to do so, subject to the following conditions:
 

	
 
The above copyright notice and this permission notice shall be included in
 
all copies or substantial portions of the Software.
 

	
 
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
 
THE SOFTWARE.
 
THE SOFTWARE.
 
\ No newline at end of file
rhodecode/public/js/mode/rst/rst.js
Show inline comments
 
CodeMirror.defineMode('rst-base', function (config) {
 

	
 
    ///////////////////////////////////////////////////////////////////////////
 
    ///////////////////////////////////////////////////////////////////////////
 

	
 
    function format(string) {
 
        var args = Array.prototype.slice.call(arguments, 1);
 
        return string.replace(/{(\d+)}/g, function (match, n) {
 
            return typeof args[n] != 'undefined' ? args[n] : match;
 
        });
 
    }
 

	
 
    function AssertException(message) {
 
        this.message = message;
 
    }
 

	
 
    AssertException.prototype.toString = function () {
 
        return 'AssertException: ' + this.message;
 
    };
 

	
 
    function assert(expression, message) {
 
        if (!expression) throw new AssertException(message);
 
        return expression;
 
    }
 

	
 
    ///////////////////////////////////////////////////////////////////////////
 
    ///////////////////////////////////////////////////////////////////////////
 

	
 
    var mode_python = CodeMirror.getMode(config, 'python');
 
    var mode_stex = CodeMirror.getMode(config, 'stex');
 

	
 
    ///////////////////////////////////////////////////////////////////////////
 
    ///////////////////////////////////////////////////////////////////////////
 

	
 
    var SEPA = "\\s+";
 
    var TAIL = "(?:\\s*|\\W|$)",
 
        rx_TAIL = new RegExp(format('^{0}', TAIL));
 

	
 
    var NAME = "(?:[^\\W\\d_](?:[\\w\\+\\.\\-:]*[^\\W_])?)",
 
    var NAME =
 
        "(?:[^\\W\\d_](?:[\\w!\"#$%&'()\\*\\+,\\-\\.\/:;<=>\\?]*[^\\W_])?)",
 
        rx_NAME = new RegExp(format('^{0}', NAME));
 
    var NAME_WWS = "(?:[^\\W\\d_](?:[\\w\\s\\+\\.\\-:]*[^\\W_])?)";
 
    var NAME_WWS =
 
        "(?:[^\\W\\d_](?:[\\w\\s!\"#$%&'()\\*\\+,\\-\\.\/:;<=>\\?]*[^\\W_])?)";
 
    var REF_NAME = format('(?:{0}|`{1}`)', NAME, NAME_WWS);
 

	
 
    var TEXT1 = "(?:[^\\s\\|](?:[^\\|]*[^\\s\\|])?)";
 
    var TEXT2 = "(?:[^\\`]+)",
 
        rx_TEXT2 = new RegExp(format('^{0}', TEXT2));
 

	
 
    var rx_section = new RegExp(
 
        "^([!'#$%&\"()*+,-./:;<=>?@\\[\\\\\\]^_`{|}~])\\1{3,}\\s*$");
 
    var rx_explicit = new RegExp(
 
        format('^\\.\\.{0}', SEPA));
 
    var rx_link = new RegExp(
 
        format('^_{0}:{1}|^__:{1}', REF_NAME, TAIL));
 
    var rx_directive = new RegExp(
 
        format('^{0}::{1}', REF_NAME, TAIL));
 
    var rx_substitution = new RegExp(
 
        format('^\\|{0}\\|{1}{2}::{3}', TEXT1, SEPA, REF_NAME, TAIL));
 
    var rx_footnote = new RegExp(
 
        format('^\\[(?:\\d+|#{0}?|\\*)]{1}', REF_NAME, TAIL));
 
    var rx_citation = new RegExp(
 
        format('^\\[{0}\\]{1}', REF_NAME, TAIL));
 

	
 
    var rx_substitution_ref = new RegExp(
 
        format('^\\|{0}\\|', TEXT1));
 
    var rx_footnote_ref = new RegExp(
 
        format('^\\[(?:\\d+|#{0}?|\\*)]_', REF_NAME));
 
    var rx_citation_ref = new RegExp(
 
        format('^\\[{0}\\]_', REF_NAME));
 
    var rx_link_ref1 = new RegExp(
 
        format('^{0}__?', REF_NAME));
 
    var rx_link_ref2 = new RegExp(
 
        format('^`{0}`_', TEXT2));
 

	
 
    var rx_role_pre = new RegExp(
 
        format('^:{0}:`{1}`{2}', NAME, TEXT2, TAIL));
 
    var rx_role_suf = new RegExp(
 
        format('^`{1}`:{0}:{2}', NAME, TEXT2, TAIL));
 
    var rx_role = new RegExp(
 
        format('^:{0}:{1}', NAME, TAIL));
 

	
 
    var rx_directive_name = new RegExp(format('^{0}', REF_NAME));
 
    var rx_directive_tail = new RegExp(format('^::{0}', TAIL));
 
    var rx_substitution_text = new RegExp(format('^\\|{0}\\|', TEXT1));
 
    var rx_substitution_sepa = new RegExp(format('^{0}', SEPA));
 
    var rx_substitution_name = new RegExp(format('^{0}', REF_NAME));
 
    var rx_substitution_tail = new RegExp(format('^::{0}', TAIL));
 
    var rx_link_head = new RegExp("^_");
 
    var rx_link_name = new RegExp(format('^{0}|_', REF_NAME));
 
    var rx_link_tail = new RegExp(format('^:{0}', TAIL));
 

	
 
    var rx_verbatim = new RegExp('^::\\s*$');
 
    var rx_examples = new RegExp('^\\s+(?:>>>|In \\[\\d+\\]:)\\s');
 

	
 
    ///////////////////////////////////////////////////////////////////////////
 
    ///////////////////////////////////////////////////////////////////////////
 

	
 
    function to_normal(stream, state) {
 
        var token = null;
 

	
 
        if (stream.sol() && stream.match(rx_examples, false)) {
 
            change(state, to_mode, {
 
                mode: mode_python, local: mode_python.startState()
 
            });
 
        } else if (stream.sol() && stream.match(rx_explicit)) {
 
            change(state, to_explicit);
 
            token = 'meta';
 
        } else if (stream.sol() && stream.match(rx_section)) {
 
            change(state, to_normal);
 
            token = 'header';
 
        } else if (phase(state) == rx_role_pre ||
 
            stream.match(rx_role_pre, false)) {
 

	
 
            switch (stage(state)) {
 
                case 0:
 
                    change(state, to_normal, context(rx_role_pre, 1));
 
                    assert(stream.match(/^:/));
 
                    token = 'meta';
 
                    break;
 
                case 1:
 
                    change(state, to_normal, context(rx_role_pre, 2));
 
                    assert(stream.match(rx_NAME));
 
                    token = 'keyword';
 

	
 
                    if (stream.current().match(/^(?:math|latex)/)) {
 
                        state.tmp = {
 
                            mode: mode_stex, local: mode_stex.startState()
 
                        };
 
                    }
 
                    break;
 
                case 2:
 
                    change(state, to_normal, context(rx_role_pre, 3));
 
                    assert(stream.match(/^:`/));
 
                    token = 'meta';
 
                    break;
 
                case 3:
 
                    if (state.tmp) {
 
                        if (stream.peek() == '`') {
 
@@ -387,164 +389,173 @@ CodeMirror.defineMode('rst-base', functi
 
            change(state, to_normal);
 
            token = 'quote';
 
        }
 

	
 
        else {
 
            stream.eatSpace();
 
            if (stream.eol()) {
 
                change(state, to_normal);
 
            } else {
 
                stream.skipToEnd();
 
                change(state, to_comment);
 
                token = 'comment';
 
            }
 
        }
 

	
 
        return token;
 
    }
 

	
 
    ///////////////////////////////////////////////////////////////////////////
 
    ///////////////////////////////////////////////////////////////////////////
 

	
 
    function to_comment(stream, state) {
 
        return as_block(stream, state, 'comment');
 
    }
 

	
 
    function to_verbatim(stream, state) {
 
        return as_block(stream, state, 'meta');
 
    }
 

	
 
    function as_block(stream, state, token) {
 
        if (stream.eol() || stream.eatSpace()) {
 
            stream.skipToEnd();
 
            return token;
 
        } else {
 
            change(state, to_normal);
 
            return null;
 
        }
 
    }
 

	
 
    ///////////////////////////////////////////////////////////////////////////
 
    ///////////////////////////////////////////////////////////////////////////
 

	
 
    function to_mode(stream, state) {
 

	
 
        if (state.ctx.mode && state.ctx.local) {
 

	
 
            if (stream.sol()) {
 
                if (!stream.eatSpace()) change(state, to_normal);
 
                return null;
 
            }
 

	
 
            try {
 
                return state.ctx.mode.token(stream, state.ctx.local);
 
            } catch (ex) {
 
                change(state, to_normal);
 
                return null;
 
            }
 
        }
 

	
 
        change(state, to_normal);
 
        return null;
 
    }
 

	
 
    ///////////////////////////////////////////////////////////////////////////
 
    ///////////////////////////////////////////////////////////////////////////
 

	
 
    function context(phase, stage, mode, local) {
 
        return {phase: phase, stage: stage, mode: mode, local: local};
 
    }
 

	
 
    function change(state, tok, ctx) {
 
        state.tok = tok;
 
        state.ctx = ctx || {};
 
    }
 

	
 
    function stage(state) {
 
        return state.ctx.stage || 0;
 
    }
 

	
 
    function phase(state) {
 
        return state.ctx.phase;
 
    }
 

	
 
    ///////////////////////////////////////////////////////////////////////////
 
    ///////////////////////////////////////////////////////////////////////////
 

	
 
    return {
 
        startState: function () {
 
            return {tok: to_normal, ctx: context(undefined, 0)};
 
        },
 

	
 
        copyState: function (state) {
 
            return {tok: state.tok, ctx: state.ctx};
 
        },
 

	
 
        innerMode: function (state) {
 
            return {state: state.ctx.local, mode: state.ctx.mode};
 
            return state.tmp ? {state: state.tmp.local, mode: state.tmp.mode}
 
                 : state.ctx ? {state: state.ctx.local, mode: state.ctx.mode}
 
                             : null;
 
        },
 

	
 
        token: function (stream, state) {
 
            return state.tok(stream, state);
 
        }
 
    };
 
}, 'python', 'stex');
 

	
 
///////////////////////////////////////////////////////////////////////////////
 
///////////////////////////////////////////////////////////////////////////////
 

	
 
CodeMirror.defineMode('rst', function (config, options) {
 

	
 
    var rx_strong = /^\*\*[^\*\s](?:[^\*]*[^\*\s])?\*\*/;
 
    var rx_emphasis = /^\*[^\*\s](?:[^\*]*[^\*\s])?\*/;
 
    var rx_literal = /^``[^`\s](?:[^`]*[^`\s])``/;
 

	
 
    var rx_number = /^(?:[\d]+(?:[\.,]\d+)*)/;
 
    var rx_positive = /^(?:\s\+[\d]+(?:[\.,]\d+)*)/;
 
    var rx_negative = /^(?:\s\-[\d]+(?:[\.,]\d+)*)/;
 

	
 
    var rx_uri_protocol = "[Hh][Tt][Tt][Pp][Ss]?://";
 
    var rx_uri_domain = "(?:[\\d\\w.-]+)\\.(?:\\w{2,6})";
 
    var rx_uri_path = "(?:/[\\d\\w\\#\\%\\&\\-\\.\\,\\/\\:\\=\\?\\~]+)*";
 
    var rx_uri = new RegExp("^" +
 
        rx_uri_protocol + rx_uri_domain + rx_uri_path
 
    );
 

	
 
    var rx_strong = /^\*\*[^\*\s](?:[^\*]*[^\*\s])?\*\*(\s+|$)/;
 
    var rx_emphasis = /^[^\*]\*[^\*\s](?:[^\*]*[^\*\s])?\*(\s+|$)/;
 
    var rx_literal = /^``[^`\s](?:[^`]*[^`\s])``(\s+|$)/;
 

	
 
    var rx_number = /^(?:[\d]+(?:[\.,]\d+)*)/;
 
    var rx_positive = /^(?:\s\+[\d]+(?:[\.,]\d+)*)/;
 
    var rx_negative = /^(?:\s\-[\d]+(?:[\.,]\d+)*)/;
 

	
 
    var overlay = {
 
        token: function (stream) {
 

	
 
            if (stream.match(rx_uri)) return 'link';
 
            if (stream.match(rx_strong)) return 'strong';
 
            if (stream.match(rx_emphasis)) return 'em';
 
            if (stream.match(rx_literal)) return 'string-2';
 
            if (stream.match(rx_number)) return 'number';
 
            if (stream.match(rx_positive)) return 'positive';
 
            if (stream.match(rx_negative)) return 'negative';
 
            if (stream.match(rx_strong) && stream.match (/\W+|$/, false))
 
                return 'strong';
 
            if (stream.match(rx_emphasis) && stream.match (/\W+|$/, false))
 
                return 'em';
 
            if (stream.match(rx_literal) && stream.match (/\W+|$/, false))
 
                return 'string-2';
 
            if (stream.match(rx_number))
 
                return 'number';
 
            if (stream.match(rx_positive))
 
                return 'positive';
 
            if (stream.match(rx_negative))
 
                return 'negative';
 
            if (stream.match(rx_uri))
 
                return 'link';
 

	
 
            while (stream.next() != null) {
 
                if (stream.match(rx_uri, false)) break;
 
                if (stream.match(rx_strong, false)) break;
 
                if (stream.match(rx_emphasis, false)) break;
 
                if (stream.match(rx_literal, false)) break;
 
                if (stream.match(rx_number, false)) break;
 
                if (stream.match(rx_positive, false)) break;
 
                if (stream.match(rx_negative, false)) break;
 
                if (stream.match(rx_uri, false)) break;
 
            }
 

	
 
            return null;
 
        }
 
    };
 

	
 
    var mode = CodeMirror.getMode(
 
        config, options.backdrop || 'rst-base'
 
    );
 

	
 
    return CodeMirror.overlayMode(mode, overlay, true); // combine
 
}, 'python', 'stex');
 

	
 
///////////////////////////////////////////////////////////////////////////////
 
///////////////////////////////////////////////////////////////////////////////
 

	
 
CodeMirror.defineMIME('text/x-rst', 'rst');
 

	
 
///////////////////////////////////////////////////////////////////////////////
 
///////////////////////////////////////////////////////////////////////////////
rhodecode/public/js/mode/ruby/ruby.js
Show inline comments
 
CodeMirror.defineMode("ruby", function(config) {
 
  function wordObj(words) {
 
    var o = {};
 
    for (var i = 0, e = words.length; i < e; ++i) o[words[i]] = true;
 
    return o;
 
  }
 
  var keywords = wordObj([
 
    "alias", "and", "BEGIN", "begin", "break", "case", "class", "def", "defined?", "do", "else",
 
    "elsif", "END", "end", "ensure", "false", "for", "if", "in", "module", "next", "not", "or",
 
    "redo", "rescue", "retry", "return", "self", "super", "then", "true", "undef", "unless",
 
    "until", "when", "while", "yield", "nil", "raise", "throw", "catch", "fail", "loop", "callcc",
 
    "caller", "lambda", "proc", "public", "protected", "private", "require", "load",
 
    "require_relative", "extend", "autoload", "__END__", "__FILE__", "__LINE__", "__dir__"
 
  ]);
 
  var indentWords = wordObj(["def", "class", "case", "for", "while", "do", "module", "then",
 
                             "catch", "loop", "proc", "begin"]);
 
  var dedentWords = wordObj(["end", "until"]);
 
  var matching = {"[": "]", "{": "}", "(": ")"};
 
  var curPunc;
 

	
 
  function chain(newtok, stream, state) {
 
    state.tokenize.push(newtok);
 
    return newtok(stream, state);
 
  }
 

	
 
  function tokenBase(stream, state) {
 
    curPunc = null;
 
    if (stream.sol() && stream.match("=begin") && stream.eol()) {
 
      state.tokenize.push(readBlockComment);
 
      return "comment";
 
    }
 
    if (stream.eatSpace()) return null;
 
    var ch = stream.next(), m;
 
    if (ch == "`" || ch == "'" || ch == '"') {
 
      return chain(readQuoted(ch, "string", ch == '"' || ch == "`"), stream, state);
 
    } else if (ch == "/" && !stream.eol() && stream.peek() != " ") {
 
      return chain(readQuoted(ch, "string-2", true), stream, state);
 
    } else if (ch == "%") {
 
      var style = "string", embed = false;
 
      var style = "string", embed = true;
 
      if (stream.eat("s")) style = "atom";
 
      else if (stream.eat(/[WQ]/)) { style = "string"; embed = true; }
 
      else if (stream.eat(/[r]/)) { style = "string-2"; embed = true; }
 
      else if (stream.eat(/[wxq]/)) style = "string";
 
      else if (stream.eat(/[WQ]/)) style = "string";
 
      else if (stream.eat(/[r]/)) style = "string-2";
 
      else if (stream.eat(/[wxq]/)) { style = "string"; embed = false; }
 
      var delim = stream.eat(/[^\w\s]/);
 
      if (!delim) return "operator";
 
      if (matching.propertyIsEnumerable(delim)) delim = matching[delim];
 
      return chain(readQuoted(delim, style, embed, true), stream, state);
 
    } else if (ch == "#") {
 
      stream.skipToEnd();
 
      return "comment";
 
    } else if (ch == "<" && (m = stream.match(/^<-?[\`\"\']?([a-zA-Z_?]\w*)[\`\"\']?(?:;|$)/))) {
 
      return chain(readHereDoc(m[1]), stream, state);
 
    } else if (ch == "0") {
 
      if (stream.eat("x")) stream.eatWhile(/[\da-fA-F]/);
 
      else if (stream.eat("b")) stream.eatWhile(/[01]/);
 
      else stream.eatWhile(/[0-7]/);
 
      return "number";
 
    } else if (/\d/.test(ch)) {
 
      stream.match(/^[\d_]*(?:\.[\d_]+)?(?:[eE][+\-]?[\d_]+)?/);
 
      return "number";
 
    } else if (ch == "?") {
 
      while (stream.match(/^\\[CM]-/)) {}
 
      if (stream.eat("\\")) stream.eatWhile(/\w/);
 
      else stream.next();
 
      return "string";
 
    } else if (ch == ":") {
 
      if (stream.eat("'")) return chain(readQuoted("'", "atom", false), stream, state);
 
      if (stream.eat('"')) return chain(readQuoted('"', "atom", true), stream, state);
 

	
 
      // :> :>> :< :<< are valid symbols
 
      if (stream.eat(/[\<\>]/)) {
 
        stream.eat(/[\<\>]/);
 
        return "atom";
 
      }
 

	
 
      // :+ :- :/ :* :| :& :! are valid symbols
 
      if (stream.eat(/[\+\-\*\/\&\|\:\!]/)) {
 
        return "atom";
 
      }
 

	
 
      // Symbols can't start by a digit
 
      if (stream.eat(/[a-zA-Z$@_]/)) {
 
        stream.eatWhile(/[\w]/);
 
        // Only one ? ! = is allowed and only as the last character
 
        stream.eat(/[\?\!\=]/);
 
        return "atom";
 
      }
 
      return "operator";
 
    } else if (ch == "@" && stream.match(/^@?[a-zA-Z_]/)) {
 
      stream.eat("@");
 
      stream.eatWhile(/[\w]/);
 
      return "variable-2";
 
    } else if (ch == "$") {
 
      if (stream.eat(/[a-zA-Z_]/)) {
 
        stream.eatWhile(/[\w]/);
 
      } else if (stream.eat(/\d/)) {
 
        stream.eat(/\d/);
 
      } else {
 
        stream.next(); // Must be a special global like $: or $!
 
      }
 
      return "variable-3";
 
    } else if (/[a-zA-Z_]/.test(ch)) {
 
      stream.eatWhile(/[\w]/);
 
      stream.eat(/[\?\!]/);
 
      if (stream.eat(":")) return "atom";
 
      return "ident";
 
    } else if (ch == "|" && (state.varList || state.lastTok == "{" || state.lastTok == "do")) {
 
      curPunc = "|";
 
      return null;
 
    } else if (/[\(\)\[\]{}\\;]/.test(ch)) {
 
      curPunc = ch;
 
      return null;
 
    } else if (ch == "-" && stream.eat(">")) {
 
      return "arrow";
 
    } else if (/[=+\-\/*:\.^%<>~|]/.test(ch)) {
 
      stream.eatWhile(/[=+\-\/*:\.^%<>~|]/);
 
      return "operator";
 
    } else {
 
      return null;
 
    }
 
  }
 

	
 
  function tokenBaseUntilBrace() {
 
    var depth = 1;
 
    return function(stream, state) {
 
      if (stream.peek() == "}") {
 
        depth--;
 
        if (depth == 0) {
 
          state.tokenize.pop();
 
          return state.tokenize[state.tokenize.length-1](stream, state);
 
        }
 
      } else if (stream.peek() == "{") {
 
        depth++;
 
      }
 
      return tokenBase(stream, state);
 
    };
 
  }
 
  function tokenBaseOnce() {
 
    var alreadyCalled = false;
rhodecode/public/js/mode/rust/rust.js
Show inline comments
 
@@ -335,101 +335,102 @@ CodeMirror.defineMode("rust", function()
 
  }
 
  function pattern(type) {
 
    if (type == "name") {cx.marked = "def"; return cont(patternmaybeop);}
 
    if (type == "atom") return cont(patternmaybeop);
 
    if (type == "op") return cont(pattern);
 
    if (type.match(/[\]\)\};,]/)) return pass();
 
    return matchBrackets(type, pattern);
 
  }
 
  function patternmaybeop(type) {
 
    if (type == "op" && content == ".") return cont();
 
    if (content == "to") {cx.marked = "keyword"; return cont(pattern);}
 
    else return pass();
 
  }
 
  function altbody(type) {
 
    if (type == "{") return cont(pushlex("}", "alt"), altblock1, poplex);
 
    return pass();
 
  }
 
  function altblock1(type) {
 
    if (type == "}") return cont();
 
    if (type == "|") return cont(altblock1);
 
    if (content == "when") {cx.marked = "keyword"; return cont(expression, altblock2);}
 
    if (type.match(/[\]\);,]/)) return cont(altblock1);
 
    return pass(pattern, altblock2);
 
  }
 
  function altblock2(type) {
 
    if (type == "{") return cont(pushlex("}", "alt"), block, poplex, altblock1);
 
    else return pass(altblock1);
 
  }
 

	
 
  function macro(type) {
 
    if (type.match(/[\[\(\{]/)) return matchBrackets(type, expression);
 
    return pass();
 
  }
 
  function matchBrackets(type, comb) {
 
    if (type == "[") return cont(pushlex("]"), commasep(comb, "]"), poplex);
 
    if (type == "(") return cont(pushlex(")"), commasep(comb, ")"), poplex);
 
    if (type == "{") return cont(pushlex("}"), commasep(comb, "}"), poplex);
 
    return cont();
 
  }
 

	
 
  function parse(state, stream, style) {
 
    var cc = state.cc;
 
    // Communicate our context to the combinators.
 
    // (Less wasteful than consing up a hundred closures on every call.)
 
    cx.state = state; cx.stream = stream; cx.marked = null, cx.cc = cc;
 

	
 
    while (true) {
 
      var combinator = cc.length ? cc.pop() : block;
 
      if (combinator(tcat)) {
 
        while(cc.length && cc[cc.length - 1].lex)
 
          cc.pop()();
 
        return cx.marked || style;
 
      }
 
    }
 
  }
 

	
 
  return {
 
    startState: function() {
 
      return {
 
        tokenize: tokenBase,
 
        cc: [],
 
        lexical: {indented: -indentUnit, column: 0, type: "top", align: false},
 
        keywords: valKeywords,
 
        indented: 0
 
      };
 
    },
 

	
 
    token: function(stream, state) {
 
      if (stream.sol()) {
 
        if (!state.lexical.hasOwnProperty("align"))
 
          state.lexical.align = false;
 
        state.indented = stream.indentation();
 
      }
 
      if (stream.eatSpace()) return null;
 
      tcat = content = null;
 
      var style = state.tokenize(stream, state);
 
      if (style == "comment") return style;
 
      if (!state.lexical.hasOwnProperty("align"))
 
        state.lexical.align = true;
 
      if (tcat == "prefix") return style;
 
      if (!content) content = stream.current();
 
      return parse(state, stream, style);
 
    },
 

	
 
    indent: function(state, textAfter) {
 
      if (state.tokenize != tokenBase) return 0;
 
      var firstChar = textAfter && textAfter.charAt(0), lexical = state.lexical,
 
          type = lexical.type, closing = firstChar == type;
 
      if (type == "stat") return lexical.indented + indentUnit;
 
      if (lexical.align) return lexical.column + (closing ? 0 : 1);
 
      return lexical.indented + (closing ? 0 : (lexical.info == "alt" ? altIndentUnit : indentUnit));
 
    },
 

	
 
    electricChars: "{}",
 
    blockCommentStart: "/*",
 
    blockCommentEnd: "*/",
 
    lineComment: "//"
 
    lineComment: "//",
 
    fold: "brace"
 
  };
 
});
 

	
 
CodeMirror.defineMIME("text/x-rustsrc", "rust");
rhodecode/public/js/mode/smalltalk/smalltalk.js
Show inline comments
 
CodeMirror.defineMode('smalltalk', function(config) {
 

	
 
  var specialChars = /[+\-\/\\*~<>=@%|&?!.,:;^]/;
 
  var keywords = /true|false|nil|self|super|thisContext/;
 

	
 
  var Context = function(tokenizer, parent) {
 
    this.next = tokenizer;
 
    this.parent = parent;
 
  };
 

	
 
  var Token = function(name, context, eos) {
 
    this.name = name;
 
    this.context = context;
 
    this.eos = eos;
 
  };
 

	
 
  var State = function() {
 
    this.context = new Context(next, null);
 
    this.expectVariable = true;
 
    this.indentation = 0;
 
    this.userIndentationDelta = 0;
 
  };
 

	
 
  State.prototype.userIndent = function(indentation) {
 
    this.userIndentationDelta = indentation > 0 ? (indentation / config.indentUnit - this.indentation) : 0;
 
  };
 

	
 
  var next = function(stream, context, state) {
 
    var token = new Token(null, context, false);
 
    var aChar = stream.next();
 

	
 
    if (aChar === '"') {
 
      token = nextComment(stream, new Context(nextComment, context));
 

	
 
    } else if (aChar === '\'') {
 
      token = nextString(stream, new Context(nextString, context));
 

	
 
    } else if (aChar === '#') {
 
      stream.eatWhile(/[^ .\[\]()]/);
 
      token.name = 'string-2';
 
      if (stream.peek() === '\'') {
 
        stream.next();
 
        token = nextSymbol(stream, new Context(nextSymbol, context));
 
      } else {
 
        stream.eatWhile(/[^ .\[\]()]/);
 
        token.name = 'string-2';
 
      }
 

	
 
    } else if (aChar === '$') {
 
      if (stream.next() === '<') {
 
        stream.eatWhile(/[^ >]/);
 
        stream.next();
 
      }
 
      token.name = 'string-2';
 

	
 
    } else if (aChar === '|' && state.expectVariable) {
 
      token.context = new Context(nextTemporaries, context);
 

	
 
    } else if (/[\[\]{}()]/.test(aChar)) {
 
      token.name = 'bracket';
 
      token.eos = /[\[{(]/.test(aChar);
 

	
 
      if (aChar === '[') {
 
        state.indentation++;
 
      } else if (aChar === ']') {
 
        state.indentation = Math.max(0, state.indentation - 1);
 
      }
 

	
 
    } else if (specialChars.test(aChar)) {
 
      stream.eatWhile(specialChars);
 
      token.name = 'operator';
 
      token.eos = aChar !== ';'; // ; cascaded message expression
 

	
 
    } else if (/\d/.test(aChar)) {
 
      stream.eatWhile(/[\w\d]/);
 
      token.name = 'number';
 

	
 
    } else if (/[\w_]/.test(aChar)) {
 
      stream.eatWhile(/[\w\d_]/);
 
      token.name = state.expectVariable ? (keywords.test(stream.current()) ? 'keyword' : 'variable') : null;
 

	
 
    } else {
 
      token.eos = state.expectVariable;
 
    }
 

	
 
    return token;
 
  };
 

	
 
  var nextComment = function(stream, context) {
 
    stream.eatWhile(/[^"]/);
 
    return new Token('comment', stream.eat('"') ? context.parent : context, true);
 
  };
 

	
 
  var nextString = function(stream, context) {
 
    stream.eatWhile(/[^']/);
 
    return new Token('string', stream.eat('\'') ? context.parent : context, false);
 
  };
 

	
 
  var nextSymbol = function(stream, context) {
 
    stream.eatWhile(/[^']/);
 
    return new Token('string-2', stream.eat('\'') ? context.parent : context, false);
 
  };
 

	
 
  var nextTemporaries = function(stream, context) {
 
    var token = new Token(null, context, false);
 
    var aChar = stream.next();
 

	
 
    if (aChar === '|') {
 
      token.context = context.parent;
 
      token.eos = true;
 

	
 
    } else {
 
      stream.eatWhile(/[^|]/);
 
      token.name = 'variable';
 
    }
 

	
 
    return token;
 
  };
 

	
 
  return {
 
    startState: function() {
 
      return new State;
 
    },
 

	
 
    token: function(stream, state) {
 
      state.userIndent(stream.indentation());
 

	
 
      if (stream.eatSpace()) {
 
        return null;
 
      }
 

	
 
      var token = state.context.next(stream, state.context, state);
 
      state.context = token.context;
 
      state.expectVariable = token.eos;
 

	
 
      return token.name;
 
    },
 

	
 
    blankLine: function(state) {
 
      state.userIndent(0);
 
    },
 

	
 
    indent: function(state, textAfter) {
 
      var i = state.context.next === next && textAfter && textAfter.charAt(0) === ']' ? -1 : state.userIndentationDelta;
 
      return (state.indentation + i) * config.indentUnit;
 
    },
 

	
 
    electricChars: ']'
 
  };
 

	
 
});
 

	
 
CodeMirror.defineMIME('text/x-stsrc', {name: 'smalltalk'});
rhodecode/public/js/mode/smartymixed/index.html
Show inline comments
 
new file 100644
 
<!doctype html>
 
<html>
 
  <head>
 
    <meta charset="utf-8">
 
    <title>CodeMirror: Smarty mixed mode</title>
 
    <link rel="stylesheet" href="../../lib/codemirror.css">
 
    <script src="../../lib/codemirror.js"></script>
 
    <link rel="stylesheet" href="../../doc/docs.css">
 

	
 
    <!-- smartymixed dependencies -->
 
    <script src="../../mode/xml/xml.js"></script>
 
    <script src="../../mode/javascript/javascript.js"></script>
 
    <script src="../../mode/css/css.js"></script>
 
    <script src="../../mode/htmlmixed/htmlmixed.js"></script>
 
    <script src="../../mode/smarty/smarty.js"></script>
 

	
 
    <!-- smartymixed -->
 
    <script src="../../mode/smartymixed/smartymixed.js"></script>
 
  </head>
 
  <body>
 
    <h1>CodeMirror: Smarty mixed mode</h1>
 
    <form><textarea id="code" name="code">
 
{**
 
* @brief Smarty mixed mode
 
* @author Ruslan Osmanov
 
* @date 29.06.2013
 
*}
 
<html>
 
<head>
 
  <title>{$title|htmlspecialchars|truncate:30}</title>
 
</head>
 
<body>
 
  {* Multiline smarty
 
  * comment, no {$variables} here
 
  *}
 
  {literal}
 
  {literal} is just an HTML text.
 
  <script type="text/javascript">//<![CDATA[
 
    var a = {$just_a_normal_js_object : "value"};
 
    var myCodeMirror = CodeMirror.fromTextArea(document.getElementById("code"), {
 
      mode           : "smartymixed",
 
      tabSize        : 2,
 
      indentUnit     : 2,
 
      indentWithTabs : false,
 
      lineNumbers    : true,
 
      smartyVersion  : 3
 
    });
 
    // ]]>
 
  </script>
 
  <style>
 
    /* CSS content 
 
    {$no_smarty} */
 
    .some-class { font-weight: bolder; color: "orange"; }
 
  </style>
 
  {/literal}
 

	
 
  {extends file="parent.tpl"}
 
  {include file="template.tpl"}
 

	
 
  {* some example Smarty content *}
 
  {if isset($name) && $name == 'Blog'}
 
    This is a {$var}.
 
    {$integer = 4511}, {$array[] = "a"}, {$stringvar = "string"}
 
    {$integer = 4512} {$array[] = "a"} {$stringvar = "string"}
 
    {assign var='bob' value=$var.prop}
 
  {elseif $name == $foo}
 
    {function name=menu level=0}
 
    {foreach $data as $entry}
 
      {if is_array($entry)}
 
      - {$entry@key}
 
      {menu data=$entry level=$level+1}
 
      {else}
 
      {$entry}
 
      {* One
 
      * Two
 
      * Three
 
      *}
 
      {/if}
 
    {/foreach}
 
    {/function}
 
  {/if}
 
  </body>
 
  <!-- R.O. -->
 
</html>
 
</textarea></form>
 

	
 
    <script type="text/javascript">
 
      var myCodeMirror = CodeMirror.fromTextArea(document.getElementById("code"), {
 
        mode           : "smartymixed",
 
        tabSize        : 2,
 
        indentUnit     : 2,
 
        indentWithTabs : false,
 
        lineNumbers    : true,
 
        smartyVersion  : 3,
 
        matchBrackets  : true,
 
      });
 
    </script>
 

	
 
    <p>The Smarty mixed mode depends on the Smarty and HTML mixed modes. HTML
 
    mixed mode itself depends on XML, JavaScript, and CSS modes.</p>
 

	
 
    <p>It takes the same options, as Smarty and HTML mixed modes.</p>
 

	
 
    <p><strong>MIME types defined:</strong> <code>text/x-smarty</code>.</p>
 
  </body>
 
</html>
 
<!-- vim: set ft=html ts=2 sts=2 sw=2 et: -->
rhodecode/public/js/mode/smartymixed/smartymixed.js
Show inline comments
 
new file 100644
 
/**
 
* @file smartymixed.js
 
* @brief Smarty Mixed Codemirror mode (Smarty + Mixed HTML)
 
* @author Ruslan Osmanov <rrosmanov at gmail dot com>
 
* @version 3.0
 
* @date 05.07.2013
 
*/
 
CodeMirror.defineMode("smartymixed", function(config) {
 
  var settings, regs, helpers, parsers,
 
  htmlMixedMode = CodeMirror.getMode(config, "htmlmixed"),
 
  smartyMode = CodeMirror.getMode(config, "smarty"),
 

	
 
  settings = {
 
    rightDelimiter: '}',
 
    leftDelimiter: '{'
 
  };
 

	
 
  if (config.hasOwnProperty("leftDelimiter")) {
 
    settings.leftDelimiter = config.leftDelimiter;
 
  }
 
  if (config.hasOwnProperty("rightDelimiter")) {
 
    settings.rightDelimiter = config.rightDelimiter;
 
  }
 

	
 
  regs = {
 
    smartyComment: new RegExp("^" + settings.leftDelimiter + "\\*"),
 
    literalOpen: new RegExp(settings.leftDelimiter + "literal" + settings.rightDelimiter),
 
    literalClose: new RegExp(settings.leftDelimiter + "\/literal" + settings.rightDelimiter),
 
    hasLeftDelimeter: new RegExp(".*" + settings.leftDelimiter),
 
    htmlHasLeftDelimeter: new RegExp("[^<>]*" + settings.leftDelimiter)
 
  };
 

	
 
  helpers = {
 
    chain: function(stream, state, parser) {
 
      state.tokenize = parser;
 
      return parser(stream, state);
 
    },
 

	
 
    cleanChain: function(stream, state, parser) {
 
      state.tokenize = null;
 
      state.localState = null;
 
      state.localMode = null;
 
      return (typeof parser == "string") ? (parser ? parser : null) : parser(stream, state);
 
    },
 

	
 
    maybeBackup: function(stream, pat, style) {
 
      var cur = stream.current();
 
      var close = cur.search(pat),
 
      m;
 
      if (close > - 1) stream.backUp(cur.length - close);
 
      else if (m = cur.match(/<\/?$/)) {
 
        stream.backUp(cur.length);
 
        if (!stream.match(pat, false)) stream.match(cur[0]);
 
      }
 
      return style;
 
    }
 
  };
 

	
 
  parsers = {
 
    html: function(stream, state) {
 
      if (!state.inLiteral && stream.match(regs.htmlHasLeftDelimeter, false)) {
 
        state.tokenize = parsers.smarty;
 
        state.localMode = smartyMode;
 
        state.localState = smartyMode.startState(htmlMixedMode.indent(state.htmlMixedState, ""));
 
        return helpers.maybeBackup(stream, settings.leftDelimiter, smartyMode.token(stream, state.localState));
 
      }
 
      return htmlMixedMode.token(stream, state.htmlMixedState);
 
    },
 

	
 
    smarty: function(stream, state) {
 
      if (stream.match(settings.leftDelimiter, false)) {
 
        if (stream.match(regs.smartyComment, false)) {
 
          return helpers.chain(stream, state, parsers.inBlock("comment", "*" + settings.rightDelimiter));
 
        }
 
      } else if (stream.match(settings.rightDelimiter, false)) {
 
        stream.eat(settings.rightDelimiter);
 
        state.tokenize = parsers.html;
 
        state.localMode = htmlMixedMode;
 
        state.localState = state.htmlMixedState;
 
        return "tag";
 
      }
 

	
 
      return helpers.maybeBackup(stream, settings.rightDelimiter, smartyMode.token(stream, state.localState));
 
    },
 

	
 
    inBlock: function(style, terminator) {
 
      return function(stream, state) {
 
        while (!stream.eol()) {
 
          if (stream.match(terminator)) {
 
            helpers.cleanChain(stream, state, "");
 
            break;
 
          }
 
          stream.next();
 
        }
 
        return style;
 
      };
 
    }
 
  };
 

	
 
  return {
 
    startState: function() {
 
      var state = htmlMixedMode.startState();
 
      return {
 
        token: parsers.html,
 
        localMode: null,
 
        localState: null,
 
        htmlMixedState: state,
 
        tokenize: null,
 
        inLiteral: false
 
      };
 
    },
 

	
 
    copyState: function(state) {
 
      var local = null, tok = (state.tokenize || state.token);
 
      if (state.localState) {
 
        local = CodeMirror.copyState((tok != parsers.html ? smartyMode : htmlMixedMode), state.localState);
 
      }
 
      return {
 
        token: state.token,
 
        tokenize: state.tokenize,
 
        localMode: state.localMode,
 
        localState: local,
 
        htmlMixedState: CodeMirror.copyState(htmlMixedMode, state.htmlMixedState),
 
        inLiteral: state.inLiteral
 
      };
 
    },
 

	
 
    token: function(stream, state) {
 
      if (stream.match(settings.leftDelimiter, false)) {
 
        if (!state.inLiteral && stream.match(regs.literalOpen, true)) {
 
          state.inLiteral = true;
 
          return "keyword";
 
        } else if (state.inLiteral && stream.match(regs.literalClose, true)) {
 
          state.inLiteral = false;
 
          return "keyword";
 
        }
 
      }
 
      if (state.inLiteral && state.localState != state.htmlMixedState) {
 
        state.tokenize = parsers.html;
 
        state.localMode = htmlMixedMode;
 
        state.localState = state.htmlMixedState;
 
      }
 

	
 
      var style = (state.tokenize || state.token)(stream, state);
 
      return style;
 
    },
 

	
 
    indent: function(state, textAfter) {
 
      if (state.localMode == smartyMode
 
          || (state.inLiteral && !state.localMode)
 
         || regs.hasLeftDelimeter.test(textAfter)) {
 
        return CodeMirror.Pass;
 
      }
 
      return htmlMixedMode.indent(state.htmlMixedState, textAfter);
 
    },
 

	
 
    electricChars: "/{}:",
 

	
 
    innerMode: function(state) {
 
      return {
 
        state: state.localState || state.htmlMixedState,
 
        mode: state.localMode || htmlMixedMode
 
      };
 
    }
 
  };
 
},
 
"htmlmixed");
 

	
 
CodeMirror.defineMIME("text/x-smarty", "smartymixed");
 
// vim: et ts=2 sts=2 sw=2
rhodecode/public/js/mode/sparql/sparql.js
Show inline comments
 
CodeMirror.defineMode("sparql", function(config) {
 
  var indentUnit = config.indentUnit;
 
  var curPunc;
 

	
 
  function wordRegexp(words) {
 
    return new RegExp("^(?:" + words.join("|") + ")$", "i");
 
  }
 
  var ops = wordRegexp(["str", "lang", "langmatches", "datatype", "bound", "sameterm", "isiri", "isuri",
 
                        "isblank", "isliteral", "union", "a"]);
 
                        "isblank", "isliteral", "a"]);
 
  var keywords = wordRegexp(["base", "prefix", "select", "distinct", "reduced", "construct", "describe",
 
                             "ask", "from", "named", "where", "order", "limit", "offset", "filter", "optional",
 
                             "graph", "by", "asc", "desc"]);
 
                             "graph", "by", "asc", "desc", "as", "having", "undef", "values", "group",
 
                             "minus", "in", "not", "service", "silent", "using", "insert", "delete", "union",
 
                             "data", "copy", "to", "move", "add", "create", "drop", "clear", "load"]);
 
  var operatorChars = /[*+\-<>=&|]/;
 

	
 
  function tokenBase(stream, state) {
 
    var ch = stream.next();
 
    curPunc = null;
 
    if (ch == "$" || ch == "?") {
 
      stream.match(/^[\w\d]*/);
 
      return "variable-2";
 
    }
 
    else if (ch == "<" && !stream.match(/^[\s\u00a0=]/, false)) {
 
      stream.match(/^[^\s\u00a0>]*>?/);
 
      return "atom";
 
    }
 
    else if (ch == "\"" || ch == "'") {
 
      state.tokenize = tokenLiteral(ch);
 
      return state.tokenize(stream, state);
 
    }
 
    else if (/[{}\(\),\.;\[\]]/.test(ch)) {
 
      curPunc = ch;
 
      return null;
 
    }
 
    else if (ch == "#") {
 
      stream.skipToEnd();
 
      return "comment";
 
    }
 
    else if (operatorChars.test(ch)) {
 
      stream.eatWhile(operatorChars);
 
      return null;
 
    }
 
    else if (ch == ":") {
 
      stream.eatWhile(/[\w\d\._\-]/);
 
      return "atom";
 
    }
 
    else {
 
      stream.eatWhile(/[_\w\d]/);
 
      if (stream.eat(":")) {
 
        stream.eatWhile(/[\w\d_\-]/);
 
        return "atom";
 
      }
 
      var word = stream.current();
 
      if (ops.test(word))
 
        return null;
 
      else if (keywords.test(word))
 
        return "keyword";
 
      else
 
        return "variable";
 
    }
 
  }
 

	
 
  function tokenLiteral(quote) {
 
    return function(stream, state) {
 
      var escaped = false, ch;
 
      while ((ch = stream.next()) != null) {
 
        if (ch == quote && !escaped) {
 
          state.tokenize = tokenBase;
 
          break;
 
        }
 
        escaped = !escaped && ch == "\\";
 
      }
 
      return "string";
 
    };
 
  }
 

	
 
  function pushContext(state, type, col) {
 
    state.context = {prev: state.context, indent: state.indent, col: col, type: type};
 
  }
 
  function popContext(state) {
 
    state.indent = state.context.indent;
 
    state.context = state.context.prev;
 
  }
 

	
 
  return {
 
    startState: function() {
 
      return {tokenize: tokenBase,
 
              context: null,
 
              indent: 0,
 
              col: 0};
 
    },
 

	
 
    token: function(stream, state) {
 
      if (stream.sol()) {
 
        if (state.context && state.context.align == null) state.context.align = false;
 
        state.indent = stream.indentation();
 
      }
 
      if (stream.eatSpace()) return null;
 
      var style = state.tokenize(stream, state);
 

	
 
      if (style != "comment" && state.context && state.context.align == null && state.context.type != "pattern") {
 
        state.context.align = true;
 
      }
 

	
 
      if (curPunc == "(") pushContext(state, ")", stream.column());
 
      else if (curPunc == "[") pushContext(state, "]", stream.column());
 
      else if (curPunc == "{") pushContext(state, "}", stream.column());
 
      else if (/[\]\}\)]/.test(curPunc)) {
 
        while (state.context && state.context.type == "pattern") popContext(state);
rhodecode/public/js/mode/vbscript/index.html
Show inline comments
 
<!doctype html>
 
<html>
 
  <head>
 
    <meta charset="utf-8">
 
    <title>CodeMirror: VBScript mode</title>
 
    <link rel="stylesheet" href="../../lib/codemirror.css">
 
    <script src="../../lib/codemirror.js"></script>
 
    <script src="vbscript.js"></script>
 
    <link rel="stylesheet" href="../../doc/docs.css">
 
    <style type="text/css">.CodeMirror {border-top: 1px solid black; border-bottom: 1px solid black;}</style>
 
  </head>
 
  <body>
 
    <h1>CodeMirror: VBScript mode</h1>
 

	
 
<div><textarea id="code" name="code">
 
' Pete Guhl
 
' 03-04-2012
 
'
 
' Basic VBScript support for codemirror2
 

	
 
Const ForReading = 1, ForWriting = 2, ForAppending = 8
 

	
 
Call Sub020_PostBroadcastToUrbanAirship(strUserName, strPassword, intTransmitID, strResponse)
 

	
 
If Not IsNull(strResponse) AND Len(strResponse) = 0 Then
 
    boolTransmitOkYN = False
 
	boolTransmitOkYN = False
 
Else
 
    ' WScript.Echo "Oh Happy Day! Oh Happy DAY!"
 
    boolTransmitOkYN = True
 
	' WScript.Echo "Oh Happy Day! Oh Happy DAY!"
 
	boolTransmitOkYN = True
 
End If
 
</textarea></div>
 

	
 
    <script>
 
      var editor = CodeMirror.fromTextArea(document.getElementById("code"), {
 
        lineNumbers: true
 
        lineNumbers: true,
 
        indentUnit: 4
 
      });
 
    </script>
 

	
 
    <p><strong>MIME types defined:</strong> <code>text/vbscript</code>.</p>
 
  </body>
 
</html>
 

	
rhodecode/public/js/mode/vbscript/vbscript.js
Show inline comments
 
CodeMirror.defineMode("vbscript", function() {
 
  var regexVBScriptKeyword = /^(?:Call|Case|CDate|Clear|CInt|CLng|Const|CStr|Description|Dim|Do|Each|Else|ElseIf|End|Err|Error|Exit|False|For|Function|If|LCase|Loop|LTrim|Next|Nothing|Now|Number|On|Preserve|Quit|ReDim|Resume|RTrim|Select|Set|Sub|Then|To|Trim|True|UBound|UCase|Until|VbCr|VbCrLf|VbLf|VbTab)$/im;
 
/*
 
For extra ASP classic objects, initialize CodeMirror instance with this option:
 
    isASP: true
 

	
 
E.G.:
 
    var editor = CodeMirror.fromTextArea(document.getElementById("code"), {
 
        lineNumbers: true,
 
        isASP: true
 
      });
 
*/
 
CodeMirror.defineMode("vbscript", function(conf, parserConf) {
 
    var ERRORCLASS = 'error';
 

	
 
    function wordRegexp(words) {
 
        return new RegExp("^((" + words.join(")|(") + "))\\b", "i");
 
    }
 

	
 
    var singleOperators = new RegExp("^[\\+\\-\\*/&\\\\\\^<>=]");
 
    var doubleOperators = new RegExp("^((<>)|(<=)|(>=))");
 
    var singleDelimiters = new RegExp('^[\\.,]');
 
    var brakets = new RegExp('^[\\(\\)]');
 
    var identifiers = new RegExp("^[A-Za-z][_A-Za-z0-9]*");
 

	
 
    var openingKeywords = ['class','sub','select','while','if','function', 'property', 'with', 'for'];
 
    var middleKeywords = ['else','elseif','case'];
 
    var endKeywords = ['next','loop','wend'];
 

	
 
    var wordOperators = wordRegexp(['and', 'or', 'not', 'xor', 'is', 'mod', 'eqv', 'imp']);
 
    var commonkeywords = ['dim', 'redim', 'then',  'until', 'randomize',
 
                          'byval','byref','new','property', 'exit', 'in',
 
                          'const','private', 'public',
 
                          'get','set','let', 'stop', 'on error resume next', 'on error goto 0', 'option explicit', 'call', 'me'];
 

	
 
    //This list was from: http://msdn.microsoft.com/en-us/library/f8tbc79x(v=vs.84).aspx
 
    var atomWords = ['true', 'false', 'nothing', 'empty', 'null'];
 
    //This list was from: http://msdn.microsoft.com/en-us/library/3ca8tfek(v=vs.84).aspx
 
    var builtinFuncsWords = ['abs', 'array', 'asc', 'atn', 'cbool', 'cbyte', 'ccur', 'cdate', 'cdbl', 'chr', 'cint', 'clng', 'cos', 'csng', 'cstr', 'date', 'dateadd', 'datediff', 'datepart',
 
                        'dateserial', 'datevalue', 'day', 'escape', 'eval', 'execute', 'exp', 'filter', 'formatcurrency', 'formatdatetime', 'formatnumber', 'formatpercent', 'getlocale', 'getobject',
 
                        'getref', 'hex', 'hour', 'inputbox', 'instr', 'instrrev', 'int', 'fix', 'isarray', 'isdate', 'isempty', 'isnull', 'isnumeric', 'isobject', 'join', 'lbound', 'lcase', 'left',
 
                        'len', 'loadpicture', 'log', 'ltrim', 'rtrim', 'trim', 'maths', 'mid', 'minute', 'month', 'monthname', 'msgbox', 'now', 'oct', 'replace', 'rgb', 'right', 'rnd', 'round',
 
                        'scriptengine', 'scriptenginebuildversion', 'scriptenginemajorversion', 'scriptengineminorversion', 'second', 'setlocale', 'sgn', 'sin', 'space', 'split', 'sqr', 'strcomp',
 
                        'string', 'strreverse', 'tan', 'time', 'timer', 'timeserial', 'timevalue', 'typename', 'ubound', 'ucase', 'unescape', 'vartype', 'weekday', 'weekdayname', 'year'];
 

	
 
    //This list was from: http://msdn.microsoft.com/en-us/library/ydz4cfk3(v=vs.84).aspx
 
    var builtinConsts = ['vbBlack', 'vbRed', 'vbGreen', 'vbYellow', 'vbBlue', 'vbMagenta', 'vbCyan', 'vbWhite', 'vbBinaryCompare', 'vbTextCompare',
 
                         'vbSunday', 'vbMonday', 'vbTuesday', 'vbWednesday', 'vbThursday', 'vbFriday', 'vbSaturday', 'vbUseSystemDayOfWeek', 'vbFirstJan1', 'vbFirstFourDays', 'vbFirstFullWeek',
 
                         'vbGeneralDate', 'vbLongDate', 'vbShortDate', 'vbLongTime', 'vbShortTime', 'vbObjectError',
 
                         'vbOKOnly', 'vbOKCancel', 'vbAbortRetryIgnore', 'vbYesNoCancel', 'vbYesNo', 'vbRetryCancel', 'vbCritical', 'vbQuestion', 'vbExclamation', 'vbInformation', 'vbDefaultButton1', 'vbDefaultButton2',
 
                         'vbDefaultButton3', 'vbDefaultButton4', 'vbApplicationModal', 'vbSystemModal', 'vbOK', 'vbCancel', 'vbAbort', 'vbRetry', 'vbIgnore', 'vbYes', 'vbNo',
 
                         'vbCr', 'VbCrLf', 'vbFormFeed', 'vbLf', 'vbNewLine', 'vbNullChar', 'vbNullString', 'vbTab', 'vbVerticalTab', 'vbUseDefault', 'vbTrue', 'vbFalse',
 
                         'vbEmpty', 'vbNull', 'vbInteger', 'vbLong', 'vbSingle', 'vbDouble', 'vbCurrency', 'vbDate', 'vbString', 'vbObject', 'vbError', 'vbBoolean', 'vbVariant', 'vbDataObject', 'vbDecimal', 'vbByte', 'vbArray'];
 
    //This list was from: http://msdn.microsoft.com/en-us/library/hkc375ea(v=vs.84).aspx
 
    var builtinObjsWords = ['WScript', 'err', 'debug', 'RegExp'];
 
    var knownProperties = ['description', 'firstindex', 'global', 'helpcontext', 'helpfile', 'ignorecase', 'length', 'number', 'pattern', 'source', 'value', 'count'];
 
    var knownMethods = ['clear', 'execute', 'raise', 'replace', 'test', 'write', 'writeline', 'close', 'open', 'state', 'eof', 'update', 'addnew', 'end', 'createobject', 'quit'];
 

	
 
    var aspBuiltinObjsWords = ['server', 'response', 'request', 'session', 'application'];
 
    var aspKnownProperties = ['buffer', 'cachecontrol', 'charset', 'contenttype', 'expires', 'expiresabsolute', 'isclientconnected', 'pics', 'status', //response
 
                              'clientcertificate', 'cookies', 'form', 'querystring', 'servervariables', 'totalbytes', //request
 
                              'contents', 'staticobjects', //application
 
                              'codepage', 'lcid', 'sessionid', 'timeout', //session
 
                              'scripttimeout']; //server
 
    var aspKnownMethods = ['addheader', 'appendtolog', 'binarywrite', 'end', 'flush', 'redirect', //response
 
                           'binaryread', //request
 
                           'remove', 'removeall', 'lock', 'unlock', //application
 
                           'abandon', //session
 
                           'getlasterror', 'htmlencode', 'mappath', 'transfer', 'urlencode']; //server
 

	
 
    var knownWords = knownMethods.concat(knownProperties);
 

	
 
    builtinObjsWords = builtinObjsWords.concat(builtinConsts);
 

	
 
    if (conf.isASP){
 
        builtinObjsWords = builtinObjsWords.concat(aspBuiltinObjsWords);
 
        knownWords = knownWords.concat(aspKnownMethods, aspKnownProperties);
 
    };
 

	
 
    var keywords = wordRegexp(commonkeywords);
 
    var atoms = wordRegexp(atomWords);
 
    var builtinFuncs = wordRegexp(builtinFuncsWords);
 
    var builtinObjs = wordRegexp(builtinObjsWords);
 
    var known = wordRegexp(knownWords);
 
    var stringPrefixes = '"';
 

	
 
    var opening = wordRegexp(openingKeywords);
 
    var middle = wordRegexp(middleKeywords);
 
    var closing = wordRegexp(endKeywords);
 
    var doubleClosing = wordRegexp(['end']);
 
    var doOpening = wordRegexp(['do']);
 
    var noIndentWords = wordRegexp(['on error resume next', 'exit']);
 
    var comment = wordRegexp(['rem']);
 

	
 

	
 
    function indent(_stream, state) {
 
      state.currentIndent++;
 
    }
 

	
 
    function dedent(_stream, state) {
 
      state.currentIndent--;
 
    }
 
    // tokenizers
 
    function tokenBase(stream, state) {
 
        if (stream.eatSpace()) {
 
            return 'space';
 
            //return null;
 
        }
 

	
 
        var ch = stream.peek();
 

	
 
        // Handle Comments
 
        if (ch === "'") {
 
            stream.skipToEnd();
 
            return 'comment';
 
        }
 
        if (stream.match(comment)){
 
            stream.skipToEnd();
 
            return 'comment';
 
        }
 

	
 

	
 
        // Handle Number Literals
 
        if (stream.match(/^((&H)|(&O))?[0-9\.]/i, false) && !stream.match(/^((&H)|(&O))?[0-9\.]+[a-z_]/i, false)) {
 
            var floatLiteral = false;
 
            // Floats
 
            if (stream.match(/^\d*\.\d+/i)) { floatLiteral = true; }
 
            else if (stream.match(/^\d+\.\d*/)) { floatLiteral = true; }
 
            else if (stream.match(/^\.\d+/)) { floatLiteral = true; }
 

	
 
            if (floatLiteral) {
 
                // Float literals may be "imaginary"
 
                stream.eat(/J/i);
 
                return 'number';
 
            }
 
            // Integers
 
            var intLiteral = false;
 
            // Hex
 
            if (stream.match(/^&H[0-9a-f]+/i)) { intLiteral = true; }
 
            // Octal
 
            else if (stream.match(/^&O[0-7]+/i)) { intLiteral = true; }
 
            // Decimal
 
            else if (stream.match(/^[1-9]\d*F?/)) {
 
                // Decimal literals may be "imaginary"
 
                stream.eat(/J/i);
 
                // TODO - Can you have imaginary longs?
 
                intLiteral = true;
 
            }
 
            // Zero by itself with no other piece of number.
 
            else if (stream.match(/^0(?![\dx])/i)) { intLiteral = true; }
 
            if (intLiteral) {
 
                // Integer literals may be "long"
 
                stream.eat(/L/i);
 
                return 'number';
 
            }
 
        }
 

	
 
        // Handle Strings
 
        if (stream.match(stringPrefixes)) {
 
            state.tokenize = tokenStringFactory(stream.current());
 
            return state.tokenize(stream, state);
 
        }
 

	
 
  return {
 
    token: function(stream) {
 
      if (stream.eatSpace()) return null;
 
      var ch = stream.next();
 
      if (ch == "'") {
 
        stream.skipToEnd();
 
        return "comment";
 
      }
 
      if (ch == '"') {
 
        stream.skipTo('"');
 
        return "string";
 
      }
 
        // Handle operators and Delimiters
 
        if (stream.match(doubleOperators)
 
            || stream.match(singleOperators)
 
            || stream.match(wordOperators)) {
 
            return 'operator';
 
        }
 
        if (stream.match(singleDelimiters)) {
 
            return null;
 
        }
 

	
 
        if (stream.match(brakets)) {
 
            return "bracket";
 
        }
 

	
 
        if (stream.match(noIndentWords)) {
 
            state.doInCurrentLine = true;
 

	
 
            return 'keyword';
 
        }
 

	
 
        if (stream.match(doOpening)) {
 
            indent(stream,state);
 
            state.doInCurrentLine = true;
 

	
 
            return 'keyword';
 
        }
 
        if (stream.match(opening)) {
 
            if (! state.doInCurrentLine)
 
              indent(stream,state);
 
            else
 
              state.doInCurrentLine = false;
 

	
 
            return 'keyword';
 
        }
 
        if (stream.match(middle)) {
 
            return 'keyword';
 
        }
 

	
 

	
 
        if (stream.match(doubleClosing)) {
 
            dedent(stream,state);
 
            dedent(stream,state);
 

	
 
            return 'keyword';
 
        }
 
        if (stream.match(closing)) {
 
            if (! state.doInCurrentLine)
 
              dedent(stream,state);
 
            else
 
              state.doInCurrentLine = false;
 

	
 
            return 'keyword';
 
        }
 

	
 
        if (stream.match(keywords)) {
 
            return 'keyword';
 
        }
 

	
 
        if (stream.match(atoms)) {
 
            return 'atom';
 
        }
 

	
 
        if (stream.match(known)) {
 
            return 'variable-2';
 
        }
 

	
 
        if (stream.match(builtinFuncs)) {
 
            return 'builtin';
 
        }
 

	
 
        if (stream.match(builtinObjs)){
 
            return 'variable-2';
 
        }
 

	
 
        if (stream.match(identifiers)) {
 
            return 'variable';
 
        }
 

	
 
        // Handle non-detected items
 
        stream.next();
 
        return ERRORCLASS;
 
    }
 

	
 
      if (/\w/.test(ch)) {
 
        stream.eatWhile(/\w/);
 
        if (regexVBScriptKeyword.test(stream.current())) return "keyword";
 
      }
 
      return null;
 
    function tokenStringFactory(delimiter) {
 
        var singleline = delimiter.length == 1;
 
        var OUTCLASS = 'string';
 

	
 
        return function(stream, state) {
 
            while (!stream.eol()) {
 
                stream.eatWhile(/[^'"]/);
 
                if (stream.match(delimiter)) {
 
                    state.tokenize = tokenBase;
 
                    return OUTCLASS;
 
                } else {
 
                    stream.eat(/['"]/);
 
                }
 
            }
 
            if (singleline) {
 
                if (parserConf.singleLineStringErrors) {
 
                    return ERRORCLASS;
 
                } else {
 
                    state.tokenize = tokenBase;
 
                }
 
            }
 
            return OUTCLASS;
 
        };
 
    }
 
  };
 

	
 

	
 
    function tokenLexer(stream, state) {
 
        var style = state.tokenize(stream, state);
 
        var current = stream.current();
 

	
 
        // Handle '.' connected identifiers
 
        if (current === '.') {
 
            style = state.tokenize(stream, state);
 

	
 
            current = stream.current();
 
            if (style.substr(0, 8) === 'variable' || style==='builtin' || style==='keyword'){//|| knownWords.indexOf(current.substring(1)) > -1) {
 
                if (style === 'builtin' || style === 'keyword') style='variable';
 
                if (knownWords.indexOf(current.substr(1)) > -1) style='variable-2';
 

	
 
                return style;
 
            } else {
 
                return ERRORCLASS;
 
            }
 
        }
 

	
 
        return style;
 
    }
 

	
 
    var external = {
 
        electricChars:"dDpPtTfFeE ",
 
        startState: function() {
 
            return {
 
              tokenize: tokenBase,
 
              lastToken: null,
 
              currentIndent: 0,
 
              nextLineIndent: 0,
 
              doInCurrentLine: false,
 
              ignoreKeyword: false
 

	
 

	
 
          };
 
        },
 

	
 
        token: function(stream, state) {
 
            if (stream.sol()) {
 
              state.currentIndent += state.nextLineIndent;
 
              state.nextLineIndent = 0;
 
              state.doInCurrentLine = 0;
 
            }
 
            var style = tokenLexer(stream, state);
 

	
 
            state.lastToken = {style:style, content: stream.current()};
 

	
 
            if (style==='space') style=null;
 

	
 
            return style;
 
        },
 

	
 
        indent: function(state, textAfter) {
 
            var trueText = textAfter.replace(/^\s+|\s+$/g, '') ;
 
            if (trueText.match(closing) || trueText.match(doubleClosing) || trueText.match(middle)) return conf.indentUnit*(state.currentIndent-1);
 
            if(state.currentIndent < 0) return 0;
 
            return state.currentIndent * conf.indentUnit;
 
        }
 

	
 
    };
 
    return external;
 
});
 

	
 
CodeMirror.defineMIME("text/vbscript", "vbscript");
rhodecode/public/js/mode/xml/xml.js
Show inline comments
 
CodeMirror.defineMode("xml", function(config, parserConfig) {
 
  var indentUnit = config.indentUnit;
 
  var multilineTagIndentFactor = parserConfig.multilineTagIndentFactor || 1;
 
  var multilineTagIndentPastTag = parserConfig.multilineTagIndentPastTag || true;
 

	
 
  var Kludges = parserConfig.htmlMode ? {
 
    autoSelfClosers: {'area': true, 'base': true, 'br': true, 'col': true, 'command': true,
 
                      'embed': true, 'frame': true, 'hr': true, 'img': true, 'input': true,
 
                      'keygen': true, 'link': true, 'meta': true, 'param': true, 'source': true,
 
                      'track': true, 'wbr': true},
 
    implicitlyClosed: {'dd': true, 'li': true, 'optgroup': true, 'option': true, 'p': true,
 
                       'rp': true, 'rt': true, 'tbody': true, 'td': true, 'tfoot': true,
 
                       'th': true, 'tr': true},
 
    contextGrabbers: {
 
      'dd': {'dd': true, 'dt': true},
 
      'dt': {'dd': true, 'dt': true},
 
      'li': {'li': true},
 
      'option': {'option': true, 'optgroup': true},
 
      'optgroup': {'optgroup': true},
 
      'p': {'address': true, 'article': true, 'aside': true, 'blockquote': true, 'dir': true,
 
            'div': true, 'dl': true, 'fieldset': true, 'footer': true, 'form': true,
 
            'h1': true, 'h2': true, 'h3': true, 'h4': true, 'h5': true, 'h6': true,
 
            'header': true, 'hgroup': true, 'hr': true, 'menu': true, 'nav': true, 'ol': true,
 
            'p': true, 'pre': true, 'section': true, 'table': true, 'ul': true},
 
      'rp': {'rp': true, 'rt': true},
 
      'rt': {'rp': true, 'rt': true},
 
      'tbody': {'tbody': true, 'tfoot': true},
 
      'td': {'td': true, 'th': true},
 
      'tfoot': {'tbody': true},
 
      'th': {'td': true, 'th': true},
 
      'thead': {'tbody': true, 'tfoot': true},
 
      'tr': {'tr': true}
 
    },
 
    doNotIndent: {"pre": true},
 
    allowUnquoted: true,
 
    allowMissing: true
 
  } : {
 
    autoSelfClosers: {},
 
    implicitlyClosed: {},
 
    contextGrabbers: {},
 
    doNotIndent: {},
 
    allowUnquoted: false,
 
    allowMissing: false
 
  };
 
  var alignCDATA = parserConfig.alignCDATA;
 

	
 
  // Return variables for tokenizers
 
  var tagName, type;
 

	
 
  function inText(stream, state) {
 
    function chain(parser) {
 
      state.tokenize = parser;
 
      return parser(stream, state);
 
    }
 

	
 
    var ch = stream.next();
 
    if (ch == "<") {
 
      if (stream.eat("!")) {
 
        if (stream.eat("[")) {
 
          if (stream.match("CDATA[")) return chain(inBlock("atom", "]]>"));
 
          else return null;
 
        } else if (stream.match("--")) {
 
          return chain(inBlock("comment", "-->"));
 
        } else if (stream.match("DOCTYPE", true, true)) {
 
          stream.eatWhile(/[\w\._\-]/);
 
          return chain(doctype(1));
 
        } else {
 
          return null;
 
        }
 
      } else if (stream.eat("?")) {
 
        stream.eatWhile(/[\w\._\-]/);
 
        state.tokenize = inBlock("meta", "?>");
 
        return "meta";
 
      } else {
 
        var isClose = stream.eat("/");
 
        tagName = "";
 
        var c;
 
        while ((c = stream.eat(/[^\s\u00a0=<>\"\'\/?]/))) tagName += c;
 
        if (!tagName) return "error";
 
        type = isClose ? "closeTag" : "openTag";
 
        state.tokenize = inTag;
 
        return "tag";
 
      }
 
    } else if (ch == "&") {
 
      var ok;
 
      if (stream.eat("#")) {
 
        if (stream.eat("x")) {
 
          ok = stream.eatWhile(/[a-fA-F\d]/) && stream.eat(";");
 
        } else {
 
          ok = stream.eatWhile(/[\d]/) && stream.eat(";");
 
        }
 
      } else {
 
        ok = stream.eatWhile(/[\w\.\-:]/) && stream.eat(";");
 
      }
 
      return ok ? "atom" : "error";
 
    } else {
 
      stream.eatWhile(/[^&<]/);
 
      return null;
 
    }
 
  }
 

	
 
  function inTag(stream, state) {
 
    var ch = stream.next();
 
    if (ch == ">" || (ch == "/" && stream.eat(">"))) {
 
      state.tokenize = inText;
 
      type = ch == ">" ? "endTag" : "selfcloseTag";
 
      return "tag";
 
    } else if (ch == "=") {
 
      type = "equals";
 
      return null;
 
    } else if (ch == "<") {
 
      return "error";
 
    } else if (/[\'\"]/.test(ch)) {
 
      state.tokenize = inAttribute(ch);
 
      state.stringStartCol = stream.column();
 
      return state.tokenize(stream, state);
 
    } else {
 
      stream.eatWhile(/[^\s\u00a0=<>\"\']/);
 
      return "word";
 
    }
 
  }
 

	
 
  function inAttribute(quote) {
 
    return function(stream, state) {
 
    var closure = function(stream, state) {
 
      while (!stream.eol()) {
 
        if (stream.next() == quote) {
 
          state.tokenize = inTag;
 
          break;
 
        }
 
      }
 
      return "string";
 
    };
 
    closure.isInAttribute = true;
 
    return closure;
 
  }
 

	
 
  function inBlock(style, terminator) {
 
    return function(stream, state) {
 
      while (!stream.eol()) {
 
        if (stream.match(terminator)) {
 
          state.tokenize = inText;
 
          break;
 
        }
 
        stream.next();
 
      }
 
      return style;
 
    };
 
  }
 
  function doctype(depth) {
 
    return function(stream, state) {
 
      var ch;
 
      while ((ch = stream.next()) != null) {
 
        if (ch == "<") {
 
          state.tokenize = doctype(depth + 1);
 
          return state.tokenize(stream, state);
 
        } else if (ch == ">") {
 
          if (depth == 1) {
 
            state.tokenize = inText;
 
            break;
 
          } else {
 
            state.tokenize = doctype(depth - 1);
 
            return state.tokenize(stream, state);
 
          }
 
        }
 
      }
 
      return "meta";
 
    };
 
  }
 

	
 
  var curState, curStream, setStyle;
 
  function pass() {
 
    for (var i = arguments.length - 1; i >= 0; i--) curState.cc.push(arguments[i]);
 
  }
 
  function cont() {
 
    pass.apply(null, arguments);
 
    return true;
 
  }
 

	
 
  function pushContext(tagName, startOfLine) {
 
    var noIndent = Kludges.doNotIndent.hasOwnProperty(tagName) || (curState.context && curState.context.noIndent);
 
    curState.context = {
 
      prev: curState.context,
 
      tagName: tagName,
 
      indent: curState.indented,
 
      startOfLine: startOfLine,
 
      noIndent: noIndent
 
    };
 
  }
 
  function popContext() {
 
    if (curState.context) curState.context = curState.context.prev;
 
  }
 

	
 
  function element(type) {
 
    if (type == "openTag") {
 
      curState.tagName = tagName;
 
      curState.tagStart = curStream.column();
 
      return cont(attributes, endtag(curState.startOfLine));
 
    } else if (type == "closeTag") {
 
      var err = false;
 
      if (curState.context) {
 
        if (curState.context.tagName != tagName) {
 
          if (Kludges.implicitlyClosed.hasOwnProperty(curState.context.tagName.toLowerCase())) {
 
            popContext();
 
          }
 
          err = !curState.context || curState.context.tagName != tagName;
 
        }
 
      } else {
 
        err = true;
 
      }
 
      if (err) setStyle = "error";
 
      return cont(endclosetag(err));
 
    }
 
    return cont();
 
  }
 
  function endtag(startOfLine) {
 
    return function(type) {
 
      var tagName = curState.tagName;
 
      curState.tagName = curState.tagStart = null;
 
      if (type == "selfcloseTag" ||
 
          (type == "endTag" && Kludges.autoSelfClosers.hasOwnProperty(tagName.toLowerCase()))) {
 
        maybePopContext(tagName.toLowerCase());
 
        return cont();
 
      }
 
      if (type == "endTag") {
 
        maybePopContext(tagName.toLowerCase());
 
        pushContext(tagName, startOfLine);
 
        return cont();
 
      }
 
      return cont();
 
    };
 
  }
 
  function endclosetag(err) {
 
    return function(type) {
 
      if (err) setStyle = "error";
 
      if (type == "endTag") { popContext(); return cont(); }
 
      setStyle = "error";
 
      return cont(arguments.callee);
 
    };
 
  }
 
  function maybePopContext(nextTagName) {
 
    var parentTagName;
 
    while (true) {
 
      if (!curState.context) {
 
        return;
 
      }
 
      parentTagName = curState.context.tagName.toLowerCase();
 
      if (!Kludges.contextGrabbers.hasOwnProperty(parentTagName) ||
 
          !Kludges.contextGrabbers[parentTagName].hasOwnProperty(nextTagName)) {
 
        return;
 
      }
 
      popContext();
 
    }
 
  }
 

	
 
  function attributes(type) {
 
    if (type == "word") {setStyle = "attribute"; return cont(attribute, attributes);}
 
    if (type == "endTag" || type == "selfcloseTag") return pass();
 
    setStyle = "error";
 
    return cont(attributes);
 
  }
 
  function attribute(type) {
 
    if (type == "equals") return cont(attvalue, attributes);
 
    if (!Kludges.allowMissing) setStyle = "error";
 
    else if (type == "word") setStyle = "attribute";
 
    return (type == "endTag" || type == "selfcloseTag") ? pass() : cont();
 
  }
 
  function attvalue(type) {
 
    if (type == "string") return cont(attvaluemaybe);
 
    if (type == "word" && Kludges.allowUnquoted) {setStyle = "string"; return cont();}
 
    setStyle = "error";
 
    return (type == "endTag" || type == "selfCloseTag") ? pass() : cont();
 
  }
 
  function attvaluemaybe(type) {
 
    if (type == "string") return cont(attvaluemaybe);
 
    else return pass();
 
  }
 

	
 
  return {
 
    startState: function() {
 
      return {tokenize: inText, cc: [], indented: 0, startOfLine: true, tagName: null, tagStart: null, context: null};
 
    },
 

	
 
    token: function(stream, state) {
 
      if (!state.tagName && stream.sol()) {
 
        state.startOfLine = true;
 
        state.indented = stream.indentation();
 
      }
 
      if (stream.eatSpace()) return null;
 

	
 
      setStyle = type = tagName = null;
 
      var style = state.tokenize(stream, state);
 
      state.type = type;
 
      if ((style || type) && style != "comment") {
 
        curState = state; curStream = stream;
 
        while (true) {
 
          var comb = state.cc.pop() || element;
 
          if (comb(type || style)) break;
 
        }
 
      }
 
      state.startOfLine = false;
 
      return setStyle || style;
 
    },
 

	
 
    indent: function(state, textAfter, fullLine) {
 
      var context = state.context;
 
      // Indent multi-line strings (e.g. css).
 
      if (state.tokenize.isInAttribute) {
 
        return state.stringStartCol + 1;
 
      }
 
      if ((state.tokenize != inTag && state.tokenize != inText) ||
 
          context && context.noIndent)
 
        return fullLine ? fullLine.match(/^(\s*)/)[0].length : 0;
 
      if (state.tagName) return state.tagStart + indentUnit * multilineTagIndentFactor;
 
      // Indent the starts of attribute names.
 
      if (state.tagName) {
 
        if (multilineTagIndentPastTag)
 
          return state.tagStart + state.tagName.length + 2;
 
        else
 
          return state.tagStart + indentUnit * multilineTagIndentFactor;
 
      }
 
      if (alignCDATA && /<!\[CDATA\[/.test(textAfter)) return 0;
 
      if (context && /^<\//.test(textAfter))
 
        context = context.prev;
 
      while (context && !context.startOfLine)
 
        context = context.prev;
 
      if (context) return context.indent + indentUnit;
 
      else return 0;
 
    },
 

	
 
    electricChars: "/",
 
    blockCommentStart: "<!--",
 
    blockCommentEnd: "-->",
 

	
 
    configuration: parserConfig.htmlMode ? "html" : "xml"
 
    configuration: parserConfig.htmlMode ? "html" : "xml",
 
    helperType: parserConfig.htmlMode ? "html" : "xml"
 
  };
 
});
 

	
 
CodeMirror.defineMIME("text/xml", "xml");
 
CodeMirror.defineMIME("application/xml", "xml");
 
if (!CodeMirror.mimeModes.hasOwnProperty("text/html"))
 
  CodeMirror.defineMIME("text/html", {name: "xml", htmlMode: true});
0 comments (0 inline, 0 general)