browser/devtools/sourceeditor/codemirror/codemirror.js

changeset 0
6474c204b198
     1.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     1.2 +++ b/browser/devtools/sourceeditor/codemirror/codemirror.js	Wed Dec 31 06:09:35 2014 +0100
     1.3 @@ -0,0 +1,7339 @@
     1.4 +// This is CodeMirror (http://codemirror.net), a code editor
     1.5 +// implemented in JavaScript on top of the browser's DOM.
     1.6 +//
     1.7 +// You can find some technical background for some of the code below
     1.8 +// at http://marijnhaverbeke.nl/blog/#cm-internals .
     1.9 +
    1.10 +(function(mod) {
    1.11 +  if (typeof exports == "object" && typeof module == "object") // CommonJS
    1.12 +    module.exports = mod();
    1.13 +  else if (typeof define == "function" && define.amd) // AMD
    1.14 +    return define([], mod);
    1.15 +  else // Plain browser env
    1.16 +    this.CodeMirror = mod();
    1.17 +})(function() {
    1.18 +  "use strict";
    1.19 +
    1.20 +  // BROWSER SNIFFING
    1.21 +
    1.22 +  // Kludges for bugs and behavior differences that can't be feature
    1.23 +  // detected are enabled based on userAgent etc sniffing.
    1.24 +
    1.25 +  var gecko = /gecko\/\d/i.test(navigator.userAgent);
    1.26 +  // ie_uptoN means Internet Explorer version N or lower
    1.27 +  var ie_upto10 = /MSIE \d/.test(navigator.userAgent);
    1.28 +  var ie_upto7 = ie_upto10 && (document.documentMode == null || document.documentMode < 8);
    1.29 +  var ie_upto8 = ie_upto10 && (document.documentMode == null || document.documentMode < 9);
    1.30 +  var ie_upto9 = ie_upto10 && (document.documentMode == null || document.documentMode < 10);
    1.31 +  var ie_11up = /Trident\/([7-9]|\d{2,})\./.test(navigator.userAgent);
    1.32 +  var ie = ie_upto10 || ie_11up;
    1.33 +  var webkit = /WebKit\//.test(navigator.userAgent);
    1.34 +  var qtwebkit = webkit && /Qt\/\d+\.\d+/.test(navigator.userAgent);
    1.35 +  var chrome = /Chrome\//.test(navigator.userAgent);
    1.36 +  var presto = /Opera\//.test(navigator.userAgent);
    1.37 +  var safari = /Apple Computer/.test(navigator.vendor);
    1.38 +  var khtml = /KHTML\//.test(navigator.userAgent);
    1.39 +  var mac_geLion = /Mac OS X 1\d\D([7-9]|\d\d)\D/.test(navigator.userAgent);
    1.40 +  var mac_geMountainLion = /Mac OS X 1\d\D([8-9]|\d\d)\D/.test(navigator.userAgent);
    1.41 +  var phantom = /PhantomJS/.test(navigator.userAgent);
    1.42 +
    1.43 +  var ios = /AppleWebKit/.test(navigator.userAgent) && /Mobile\/\w+/.test(navigator.userAgent);
    1.44 +  // This is woefully incomplete. Suggestions for alternative methods welcome.
    1.45 +  var mobile = ios || /Android|webOS|BlackBerry|Opera Mini|Opera Mobi|IEMobile/i.test(navigator.userAgent);
    1.46 +  var mac = ios || /Mac/.test(navigator.platform);
    1.47 +  var windows = /win/i.test(navigator.platform);
    1.48 +
    1.49 +  var presto_version = presto && navigator.userAgent.match(/Version\/(\d*\.\d*)/);
    1.50 +  if (presto_version) presto_version = Number(presto_version[1]);
    1.51 +  if (presto_version && presto_version >= 15) { presto = false; webkit = true; }
    1.52 +  // Some browsers use the wrong event properties to signal cmd/ctrl on OS X
    1.53 +  var flipCtrlCmd = mac && (qtwebkit || presto && (presto_version == null || presto_version < 12.11));
    1.54 +  var captureRightClick = gecko || (ie && !ie_upto8);
    1.55 +
    1.56 +  // Optimize some code when these features are not used.
    1.57 +  var sawReadOnlySpans = false, sawCollapsedSpans = false;
    1.58 +
    1.59 +  // EDITOR CONSTRUCTOR
    1.60 +
    1.61 +  // A CodeMirror instance represents an editor. This is the object
    1.62 +  // that user code is usually dealing with.
    1.63 +
    1.64 +  function CodeMirror(place, options) {
    1.65 +    if (!(this instanceof CodeMirror)) return new CodeMirror(place, options);
    1.66 +
    1.67 +    this.options = options = options || {};
    1.68 +    // Determine effective options based on given values and defaults.
    1.69 +    for (var opt in defaults) if (!options.hasOwnProperty(opt))
    1.70 +      options[opt] = defaults[opt];
    1.71 +    setGuttersForLineNumbers(options);
    1.72 +
    1.73 +    var doc = options.value;
    1.74 +    if (typeof doc == "string") doc = new Doc(doc, options.mode);
    1.75 +    this.doc = doc;
    1.76 +
    1.77 +    var display = this.display = new Display(place, doc);
    1.78 +    display.wrapper.CodeMirror = this;
    1.79 +    updateGutters(this);
    1.80 +    themeChanged(this);
    1.81 +    if (options.lineWrapping)
    1.82 +      this.display.wrapper.className += " CodeMirror-wrap";
    1.83 +    if (options.autofocus && !mobile) focusInput(this);
    1.84 +
    1.85 +    this.state = {
    1.86 +      keyMaps: [],  // stores maps added by addKeyMap
    1.87 +      overlays: [], // highlighting overlays, as added by addOverlay
    1.88 +      modeGen: 0,   // bumped when mode/overlay changes, used to invalidate highlighting info
    1.89 +      overwrite: false, focused: false,
    1.90 +      suppressEdits: false, // used to disable editing during key handlers when in readOnly mode
    1.91 +      pasteIncoming: false, cutIncoming: false, // help recognize paste/cut edits in readInput
    1.92 +      draggingText: false,
    1.93 +      highlight: new Delayed() // stores highlight worker timeout
    1.94 +    };
    1.95 +
    1.96 +    // Override magic textarea content restore that IE sometimes does
    1.97 +    // on our hidden textarea on reload
    1.98 +    if (ie_upto10) setTimeout(bind(resetInput, this, true), 20);
    1.99 +
   1.100 +    registerEventHandlers(this);
   1.101 +
   1.102 +    var cm = this;
   1.103 +    runInOp(this, function() {
   1.104 +      cm.curOp.forceUpdate = true;
   1.105 +      attachDoc(cm, doc);
   1.106 +
   1.107 +      if ((options.autofocus && !mobile) || activeElt() == display.input)
   1.108 +        setTimeout(bind(onFocus, cm), 20);
   1.109 +      else
   1.110 +        onBlur(cm);
   1.111 +
   1.112 +      for (var opt in optionHandlers) if (optionHandlers.hasOwnProperty(opt))
   1.113 +        optionHandlers[opt](cm, options[opt], Init);
   1.114 +      for (var i = 0; i < initHooks.length; ++i) initHooks[i](cm);
   1.115 +    });
   1.116 +  }
   1.117 +
   1.118 +  // DISPLAY CONSTRUCTOR
   1.119 +
   1.120 +  // The display handles the DOM integration, both for input reading
   1.121 +  // and content drawing. It holds references to DOM nodes and
   1.122 +  // display-related state.
   1.123 +
   1.124 +  function Display(place, doc) {
   1.125 +    var d = this;
   1.126 +
   1.127 +    // The semihidden textarea that is focused when the editor is
   1.128 +    // focused, and receives input.
   1.129 +    var input = d.input = elt("textarea", null, null, "position: absolute; padding: 0; width: 1px; height: 1em; outline: none");
   1.130 +    // The textarea is kept positioned near the cursor to prevent the
   1.131 +    // fact that it'll be scrolled into view on input from scrolling
   1.132 +    // our fake cursor out of view. On webkit, when wrap=off, paste is
   1.133 +    // very slow. So make the area wide instead.
   1.134 +    if (webkit) input.style.width = "1000px";
   1.135 +    else input.setAttribute("wrap", "off");
   1.136 +    // If border: 0; -- iOS fails to open keyboard (issue #1287)
   1.137 +    if (ios) input.style.border = "1px solid black";
   1.138 +    input.setAttribute("autocorrect", "off"); input.setAttribute("autocapitalize", "off"); input.setAttribute("spellcheck", "false");
   1.139 +
   1.140 +    // Wraps and hides input textarea
   1.141 +    d.inputDiv = elt("div", [input], null, "overflow: hidden; position: relative; width: 3px; height: 0px;");
   1.142 +    // The fake scrollbar elements.
   1.143 +    d.scrollbarH = elt("div", [elt("div", null, null, "height: 100%; min-height: 1px")], "CodeMirror-hscrollbar");
   1.144 +    d.scrollbarV = elt("div", [elt("div", null, null, "min-width: 1px")], "CodeMirror-vscrollbar");
   1.145 +    // Covers bottom-right square when both scrollbars are present.
   1.146 +    d.scrollbarFiller = elt("div", null, "CodeMirror-scrollbar-filler");
   1.147 +    // Covers bottom of gutter when coverGutterNextToScrollbar is on
   1.148 +    // and h scrollbar is present.
   1.149 +    d.gutterFiller = elt("div", null, "CodeMirror-gutter-filler");
   1.150 +    // Will contain the actual code, positioned to cover the viewport.
   1.151 +    d.lineDiv = elt("div", null, "CodeMirror-code");
   1.152 +    // Elements are added to these to represent selection and cursors.
   1.153 +    d.selectionDiv = elt("div", null, null, "position: relative; z-index: 1");
   1.154 +    d.cursorDiv = elt("div", null, "CodeMirror-cursors");
   1.155 +    // A visibility: hidden element used to find the size of things.
   1.156 +    d.measure = elt("div", null, "CodeMirror-measure");
   1.157 +    // When lines outside of the viewport are measured, they are drawn in this.
   1.158 +    d.lineMeasure = elt("div", null, "CodeMirror-measure");
   1.159 +    // Wraps everything that needs to exist inside the vertically-padded coordinate system
   1.160 +    d.lineSpace = elt("div", [d.measure, d.lineMeasure, d.selectionDiv, d.cursorDiv, d.lineDiv],
   1.161 +                      null, "position: relative; outline: none");
   1.162 +    // Moved around its parent to cover visible view.
   1.163 +    d.mover = elt("div", [elt("div", [d.lineSpace], "CodeMirror-lines")], null, "position: relative");
   1.164 +    // Set to the height of the document, allowing scrolling.
   1.165 +    d.sizer = elt("div", [d.mover], "CodeMirror-sizer");
   1.166 +    // Behavior of elts with overflow: auto and padding is
   1.167 +    // inconsistent across browsers. This is used to ensure the
   1.168 +    // scrollable area is big enough.
   1.169 +    d.heightForcer = elt("div", null, null, "position: absolute; height: " + scrollerCutOff + "px; width: 1px;");
   1.170 +    // Will contain the gutters, if any.
   1.171 +    d.gutters = elt("div", null, "CodeMirror-gutters");
   1.172 +    d.lineGutter = null;
   1.173 +    // Actual scrollable element.
   1.174 +    d.scroller = elt("div", [d.sizer, d.heightForcer, d.gutters], "CodeMirror-scroll");
   1.175 +    d.scroller.setAttribute("tabIndex", "-1");
   1.176 +    // The element in which the editor lives.
   1.177 +    d.wrapper = elt("div", [d.inputDiv, d.scrollbarH, d.scrollbarV,
   1.178 +                            d.scrollbarFiller, d.gutterFiller, d.scroller], "CodeMirror");
   1.179 +
   1.180 +    // Work around IE7 z-index bug (not perfect, hence IE7 not really being supported)
   1.181 +    if (ie_upto7) { d.gutters.style.zIndex = -1; d.scroller.style.paddingRight = 0; }
   1.182 +    // Needed to hide big blue blinking cursor on Mobile Safari
   1.183 +    if (ios) input.style.width = "0px";
   1.184 +    if (!webkit) d.scroller.draggable = true;
   1.185 +    // Needed to handle Tab key in KHTML
   1.186 +    if (khtml) { d.inputDiv.style.height = "1px"; d.inputDiv.style.position = "absolute"; }
   1.187 +    // Need to set a minimum width to see the scrollbar on IE7 (but must not set it on IE8).
   1.188 +    if (ie_upto7) d.scrollbarH.style.minHeight = d.scrollbarV.style.minWidth = "18px";
   1.189 +
   1.190 +    if (place.appendChild) place.appendChild(d.wrapper);
   1.191 +    else place(d.wrapper);
   1.192 +
   1.193 +    // Current rendered range (may be bigger than the view window).
   1.194 +    d.viewFrom = d.viewTo = doc.first;
   1.195 +    // Information about the rendered lines.
   1.196 +    d.view = [];
   1.197 +    // Holds info about a single rendered line when it was rendered
   1.198 +    // for measurement, while not in view.
   1.199 +    d.externalMeasured = null;
   1.200 +    // Empty space (in pixels) above the view
   1.201 +    d.viewOffset = 0;
   1.202 +    d.lastSizeC = 0;
   1.203 +    d.updateLineNumbers = null;
   1.204 +
   1.205 +    // Used to only resize the line number gutter when necessary (when
   1.206 +    // the amount of lines crosses a boundary that makes its width change)
   1.207 +    d.lineNumWidth = d.lineNumInnerWidth = d.lineNumChars = null;
   1.208 +    // See readInput and resetInput
   1.209 +    d.prevInput = "";
   1.210 +    // Set to true when a non-horizontal-scrolling line widget is
   1.211 +    // added. As an optimization, line widget aligning is skipped when
   1.212 +    // this is false.
   1.213 +    d.alignWidgets = false;
   1.214 +    // Flag that indicates whether we expect input to appear real soon
   1.215 +    // now (after some event like 'keypress' or 'input') and are
   1.216 +    // polling intensively.
   1.217 +    d.pollingFast = false;
   1.218 +    // Self-resetting timeout for the poller
   1.219 +    d.poll = new Delayed();
   1.220 +
   1.221 +    d.cachedCharWidth = d.cachedTextHeight = d.cachedPaddingH = null;
   1.222 +
   1.223 +    // Tracks when resetInput has punted to just putting a short
   1.224 +    // string into the textarea instead of the full selection.
   1.225 +    d.inaccurateSelection = false;
   1.226 +
   1.227 +    // Tracks the maximum line length so that the horizontal scrollbar
   1.228 +    // can be kept static when scrolling.
   1.229 +    d.maxLine = null;
   1.230 +    d.maxLineLength = 0;
   1.231 +    d.maxLineChanged = false;
   1.232 +
   1.233 +    // Used for measuring wheel scrolling granularity
   1.234 +    d.wheelDX = d.wheelDY = d.wheelStartX = d.wheelStartY = null;
   1.235 +
   1.236 +    // True when shift is held down.
   1.237 +    d.shift = false;
   1.238 +  }
   1.239 +
   1.240 +  // STATE UPDATES
   1.241 +
   1.242 +  // Used to get the editor into a consistent state again when options change.
   1.243 +
   1.244 +  function loadMode(cm) {
   1.245 +    cm.doc.mode = CodeMirror.getMode(cm.options, cm.doc.modeOption);
   1.246 +    resetModeState(cm);
   1.247 +  }
   1.248 +
   1.249 +  function resetModeState(cm) {
   1.250 +    cm.doc.iter(function(line) {
   1.251 +      if (line.stateAfter) line.stateAfter = null;
   1.252 +      if (line.styles) line.styles = null;
   1.253 +    });
   1.254 +    cm.doc.frontier = cm.doc.first;
   1.255 +    startWorker(cm, 100);
   1.256 +    cm.state.modeGen++;
   1.257 +    if (cm.curOp) regChange(cm);
   1.258 +  }
   1.259 +
   1.260 +  function wrappingChanged(cm) {
   1.261 +    if (cm.options.lineWrapping) {
   1.262 +      cm.display.wrapper.className += " CodeMirror-wrap";
   1.263 +      cm.display.sizer.style.minWidth = "";
   1.264 +    } else {
   1.265 +      cm.display.wrapper.className = cm.display.wrapper.className.replace(" CodeMirror-wrap", "");
   1.266 +      findMaxLine(cm);
   1.267 +    }
   1.268 +    estimateLineHeights(cm);
   1.269 +    regChange(cm);
   1.270 +    clearCaches(cm);
   1.271 +    setTimeout(function(){updateScrollbars(cm);}, 100);
   1.272 +  }
   1.273 +
   1.274 +  // Returns a function that estimates the height of a line, to use as
   1.275 +  // first approximation until the line becomes visible (and is thus
   1.276 +  // properly measurable).
   1.277 +  function estimateHeight(cm) {
   1.278 +    var th = textHeight(cm.display), wrapping = cm.options.lineWrapping;
   1.279 +    var perLine = wrapping && Math.max(5, cm.display.scroller.clientWidth / charWidth(cm.display) - 3);
   1.280 +    return function(line) {
   1.281 +      if (lineIsHidden(cm.doc, line)) return 0;
   1.282 +
   1.283 +      var widgetsHeight = 0;
   1.284 +      if (line.widgets) for (var i = 0; i < line.widgets.length; i++) {
   1.285 +        if (line.widgets[i].height) widgetsHeight += line.widgets[i].height;
   1.286 +      }
   1.287 +
   1.288 +      if (wrapping)
   1.289 +        return widgetsHeight + (Math.ceil(line.text.length / perLine) || 1) * th;
   1.290 +      else
   1.291 +        return widgetsHeight + th;
   1.292 +    };
   1.293 +  }
   1.294 +
   1.295 +  function estimateLineHeights(cm) {
   1.296 +    var doc = cm.doc, est = estimateHeight(cm);
   1.297 +    doc.iter(function(line) {
   1.298 +      var estHeight = est(line);
   1.299 +      if (estHeight != line.height) updateLineHeight(line, estHeight);
   1.300 +    });
   1.301 +  }
   1.302 +
   1.303 +  function keyMapChanged(cm) {
   1.304 +    var map = keyMap[cm.options.keyMap], style = map.style;
   1.305 +    cm.display.wrapper.className = cm.display.wrapper.className.replace(/\s*cm-keymap-\S+/g, "") +
   1.306 +      (style ? " cm-keymap-" + style : "");
   1.307 +  }
   1.308 +
   1.309 +  function themeChanged(cm) {
   1.310 +    cm.display.wrapper.className = cm.display.wrapper.className.replace(/\s*cm-s-\S+/g, "") +
   1.311 +      cm.options.theme.replace(/(^|\s)\s*/g, " cm-s-");
   1.312 +    clearCaches(cm);
   1.313 +  }
   1.314 +
   1.315 +  function guttersChanged(cm) {
   1.316 +    updateGutters(cm);
   1.317 +    regChange(cm);
   1.318 +    setTimeout(function(){alignHorizontally(cm);}, 20);
   1.319 +  }
   1.320 +
   1.321 +  // Rebuild the gutter elements, ensure the margin to the left of the
   1.322 +  // code matches their width.
   1.323 +  function updateGutters(cm) {
   1.324 +    var gutters = cm.display.gutters, specs = cm.options.gutters;
   1.325 +    removeChildren(gutters);
   1.326 +    for (var i = 0; i < specs.length; ++i) {
   1.327 +      var gutterClass = specs[i];
   1.328 +      var gElt = gutters.appendChild(elt("div", null, "CodeMirror-gutter " + gutterClass));
   1.329 +      if (gutterClass == "CodeMirror-linenumbers") {
   1.330 +        cm.display.lineGutter = gElt;
   1.331 +        gElt.style.width = (cm.display.lineNumWidth || 1) + "px";
   1.332 +      }
   1.333 +    }
   1.334 +    gutters.style.display = i ? "" : "none";
   1.335 +    var width = gutters.offsetWidth;
   1.336 +    cm.display.sizer.style.marginLeft = width + "px";
   1.337 +    if (i) cm.display.scrollbarH.style.left = cm.options.fixedGutter ? width + "px" : 0;
   1.338 +  }
   1.339 +
   1.340 +  // Compute the character length of a line, taking into account
   1.341 +  // collapsed ranges (see markText) that might hide parts, and join
   1.342 +  // other lines onto it.
   1.343 +  function lineLength(line) {
   1.344 +    if (line.height == 0) return 0;
   1.345 +    var len = line.text.length, merged, cur = line;
   1.346 +    while (merged = collapsedSpanAtStart(cur)) {
   1.347 +      var found = merged.find(0, true);
   1.348 +      cur = found.from.line;
   1.349 +      len += found.from.ch - found.to.ch;
   1.350 +    }
   1.351 +    cur = line;
   1.352 +    while (merged = collapsedSpanAtEnd(cur)) {
   1.353 +      var found = merged.find(0, true);
   1.354 +      len -= cur.text.length - found.from.ch;
   1.355 +      cur = found.to.line;
   1.356 +      len += cur.text.length - found.to.ch;
   1.357 +    }
   1.358 +    return len;
   1.359 +  }
   1.360 +
   1.361 +  // Find the longest line in the document.
   1.362 +  function findMaxLine(cm) {
   1.363 +    var d = cm.display, doc = cm.doc;
   1.364 +    d.maxLine = getLine(doc, doc.first);
   1.365 +    d.maxLineLength = lineLength(d.maxLine);
   1.366 +    d.maxLineChanged = true;
   1.367 +    doc.iter(function(line) {
   1.368 +      var len = lineLength(line);
   1.369 +      if (len > d.maxLineLength) {
   1.370 +        d.maxLineLength = len;
   1.371 +        d.maxLine = line;
   1.372 +      }
   1.373 +    });
   1.374 +  }
   1.375 +
   1.376 +  // Make sure the gutters options contains the element
   1.377 +  // "CodeMirror-linenumbers" when the lineNumbers option is true.
   1.378 +  function setGuttersForLineNumbers(options) {
   1.379 +    var found = indexOf(options.gutters, "CodeMirror-linenumbers");
   1.380 +    if (found == -1 && options.lineNumbers) {
   1.381 +      options.gutters = options.gutters.concat(["CodeMirror-linenumbers"]);
   1.382 +    } else if (found > -1 && !options.lineNumbers) {
   1.383 +      options.gutters = options.gutters.slice(0);
   1.384 +      options.gutters.splice(found, 1);
   1.385 +    }
   1.386 +  }
   1.387 +
   1.388 +  // SCROLLBARS
   1.389 +
   1.390 +  // Prepare DOM reads needed to update the scrollbars. Done in one
   1.391 +  // shot to minimize update/measure roundtrips.
   1.392 +  function measureForScrollbars(cm) {
   1.393 +    var scroll = cm.display.scroller;
   1.394 +    return {
   1.395 +      clientHeight: scroll.clientHeight,
   1.396 +      barHeight: cm.display.scrollbarV.clientHeight,
   1.397 +      scrollWidth: scroll.scrollWidth, clientWidth: scroll.clientWidth,
   1.398 +      barWidth: cm.display.scrollbarH.clientWidth,
   1.399 +      docHeight: Math.round(cm.doc.height + paddingVert(cm.display))
   1.400 +    };
   1.401 +  }
   1.402 +
   1.403 +  // Re-synchronize the fake scrollbars with the actual size of the
   1.404 +  // content.
   1.405 +  function updateScrollbars(cm, measure) {
   1.406 +    if (!measure) measure = measureForScrollbars(cm);
   1.407 +    var d = cm.display;
   1.408 +    var scrollHeight = measure.docHeight + scrollerCutOff;
   1.409 +    var needsH = measure.scrollWidth > measure.clientWidth;
   1.410 +    var needsV = scrollHeight > measure.clientHeight;
   1.411 +    if (needsV) {
   1.412 +      d.scrollbarV.style.display = "block";
   1.413 +      d.scrollbarV.style.bottom = needsH ? scrollbarWidth(d.measure) + "px" : "0";
   1.414 +      // A bug in IE8 can cause this value to be negative, so guard it.
   1.415 +      d.scrollbarV.firstChild.style.height =
   1.416 +        Math.max(0, scrollHeight - measure.clientHeight + (measure.barHeight || d.scrollbarV.clientHeight)) + "px";
   1.417 +    } else {
   1.418 +      d.scrollbarV.style.display = "";
   1.419 +      d.scrollbarV.firstChild.style.height = "0";
   1.420 +    }
   1.421 +    if (needsH) {
   1.422 +      d.scrollbarH.style.display = "block";
   1.423 +      d.scrollbarH.style.right = needsV ? scrollbarWidth(d.measure) + "px" : "0";
   1.424 +      d.scrollbarH.firstChild.style.width =
   1.425 +        (measure.scrollWidth - measure.clientWidth + (measure.barWidth || d.scrollbarH.clientWidth)) + "px";
   1.426 +    } else {
   1.427 +      d.scrollbarH.style.display = "";
   1.428 +      d.scrollbarH.firstChild.style.width = "0";
   1.429 +    }
   1.430 +    if (needsH && needsV) {
   1.431 +      d.scrollbarFiller.style.display = "block";
   1.432 +      d.scrollbarFiller.style.height = d.scrollbarFiller.style.width = scrollbarWidth(d.measure) + "px";
   1.433 +    } else d.scrollbarFiller.style.display = "";
   1.434 +    if (needsH && cm.options.coverGutterNextToScrollbar && cm.options.fixedGutter) {
   1.435 +      d.gutterFiller.style.display = "block";
   1.436 +      d.gutterFiller.style.height = scrollbarWidth(d.measure) + "px";
   1.437 +      d.gutterFiller.style.width = d.gutters.offsetWidth + "px";
   1.438 +    } else d.gutterFiller.style.display = "";
   1.439 +
   1.440 +    if (mac_geLion && scrollbarWidth(d.measure) === 0) {
   1.441 +      d.scrollbarV.style.minWidth = d.scrollbarH.style.minHeight = mac_geMountainLion ? "18px" : "12px";
   1.442 +      var barMouseDown = function(e) {
   1.443 +        if (e_target(e) != d.scrollbarV && e_target(e) != d.scrollbarH)
   1.444 +          operation(cm, onMouseDown)(e);
   1.445 +      };
   1.446 +      on(d.scrollbarV, "mousedown", barMouseDown);
   1.447 +      on(d.scrollbarH, "mousedown", barMouseDown);
   1.448 +    }
   1.449 +  }
   1.450 +
   1.451 +  // Compute the lines that are visible in a given viewport (defaults
   1.452 +  // the the current scroll position). viewPort may contain top,
   1.453 +  // height, and ensure (see op.scrollToPos) properties.
   1.454 +  function visibleLines(display, doc, viewPort) {
   1.455 +    var top = viewPort && viewPort.top != null ? viewPort.top : display.scroller.scrollTop;
   1.456 +    top = Math.floor(top - paddingTop(display));
   1.457 +    var bottom = viewPort && viewPort.bottom != null ? viewPort.bottom : top + display.wrapper.clientHeight;
   1.458 +
   1.459 +    var from = lineAtHeight(doc, top), to = lineAtHeight(doc, bottom);
   1.460 +    // Ensure is a {from: {line, ch}, to: {line, ch}} object, and
   1.461 +    // forces those lines into the viewport (if possible).
   1.462 +    if (viewPort && viewPort.ensure) {
   1.463 +      var ensureFrom = viewPort.ensure.from.line, ensureTo = viewPort.ensure.to.line;
   1.464 +      if (ensureFrom < from)
   1.465 +        return {from: ensureFrom,
   1.466 +                to: lineAtHeight(doc, heightAtLine(getLine(doc, ensureFrom)) + display.wrapper.clientHeight)};
   1.467 +      if (Math.min(ensureTo, doc.lastLine()) >= to)
   1.468 +        return {from: lineAtHeight(doc, heightAtLine(getLine(doc, ensureTo)) - display.wrapper.clientHeight),
   1.469 +                to: ensureTo};
   1.470 +    }
   1.471 +    return {from: from, to: to};
   1.472 +  }
   1.473 +
   1.474 +  // LINE NUMBERS
   1.475 +
   1.476 +  // Re-align line numbers and gutter marks to compensate for
   1.477 +  // horizontal scrolling.
   1.478 +  function alignHorizontally(cm) {
   1.479 +    var display = cm.display, view = display.view;
   1.480 +    if (!display.alignWidgets && (!display.gutters.firstChild || !cm.options.fixedGutter)) return;
   1.481 +    var comp = compensateForHScroll(display) - display.scroller.scrollLeft + cm.doc.scrollLeft;
   1.482 +    var gutterW = display.gutters.offsetWidth, left = comp + "px";
   1.483 +    for (var i = 0; i < view.length; i++) if (!view[i].hidden) {
   1.484 +      if (cm.options.fixedGutter && view[i].gutter)
   1.485 +        view[i].gutter.style.left = left;
   1.486 +      var align = view[i].alignable;
   1.487 +      if (align) for (var j = 0; j < align.length; j++)
   1.488 +        align[j].style.left = left;
   1.489 +    }
   1.490 +    if (cm.options.fixedGutter)
   1.491 +      display.gutters.style.left = (comp + gutterW) + "px";
   1.492 +  }
   1.493 +
   1.494 +  // Used to ensure that the line number gutter is still the right
   1.495 +  // size for the current document size. Returns true when an update
   1.496 +  // is needed.
   1.497 +  function maybeUpdateLineNumberWidth(cm) {
   1.498 +    if (!cm.options.lineNumbers) return false;
   1.499 +    var doc = cm.doc, last = lineNumberFor(cm.options, doc.first + doc.size - 1), display = cm.display;
   1.500 +    if (last.length != display.lineNumChars) {
   1.501 +      var test = display.measure.appendChild(elt("div", [elt("div", last)],
   1.502 +                                                 "CodeMirror-linenumber CodeMirror-gutter-elt"));
   1.503 +      var innerW = test.firstChild.offsetWidth, padding = test.offsetWidth - innerW;
   1.504 +      display.lineGutter.style.width = "";
   1.505 +      display.lineNumInnerWidth = Math.max(innerW, display.lineGutter.offsetWidth - padding);
   1.506 +      display.lineNumWidth = display.lineNumInnerWidth + padding;
   1.507 +      display.lineNumChars = display.lineNumInnerWidth ? last.length : -1;
   1.508 +      display.lineGutter.style.width = display.lineNumWidth + "px";
   1.509 +      var width = display.gutters.offsetWidth;
   1.510 +      display.scrollbarH.style.left = cm.options.fixedGutter ? width + "px" : 0;
   1.511 +      display.sizer.style.marginLeft = width + "px";
   1.512 +      return true;
   1.513 +    }
   1.514 +    return false;
   1.515 +  }
   1.516 +
   1.517 +  function lineNumberFor(options, i) {
   1.518 +    return String(options.lineNumberFormatter(i + options.firstLineNumber));
   1.519 +  }
   1.520 +
   1.521 +  // Computes display.scroller.scrollLeft + display.gutters.offsetWidth,
   1.522 +  // but using getBoundingClientRect to get a sub-pixel-accurate
   1.523 +  // result.
   1.524 +  function compensateForHScroll(display) {
   1.525 +    return display.scroller.getBoundingClientRect().left - display.sizer.getBoundingClientRect().left;
   1.526 +  }
   1.527 +
   1.528 +  // DISPLAY DRAWING
   1.529 +
   1.530 +  // Updates the display, selection, and scrollbars, using the
   1.531 +  // information in display.view to find out which nodes are no longer
   1.532 +  // up-to-date. Tries to bail out early when no changes are needed,
   1.533 +  // unless forced is true.
   1.534 +  // Returns true if an actual update happened, false otherwise.
   1.535 +  function updateDisplay(cm, viewPort, forced) {
   1.536 +    var oldFrom = cm.display.viewFrom, oldTo = cm.display.viewTo, updated;
   1.537 +    var visible = visibleLines(cm.display, cm.doc, viewPort);
   1.538 +    for (var first = true;; first = false) {
   1.539 +      var oldWidth = cm.display.scroller.clientWidth;
   1.540 +      if (!updateDisplayInner(cm, visible, forced)) break;
   1.541 +      updated = true;
   1.542 +
   1.543 +      // If the max line changed since it was last measured, measure it,
   1.544 +      // and ensure the document's width matches it.
   1.545 +      if (cm.display.maxLineChanged && !cm.options.lineWrapping)
   1.546 +        adjustContentWidth(cm);
   1.547 +
   1.548 +      var barMeasure = measureForScrollbars(cm);
   1.549 +      updateSelection(cm);
   1.550 +      setDocumentHeight(cm, barMeasure);
   1.551 +      updateScrollbars(cm, barMeasure);
   1.552 +      if (first && cm.options.lineWrapping && oldWidth != cm.display.scroller.clientWidth) {
   1.553 +        forced = true;
   1.554 +        continue;
   1.555 +      }
   1.556 +      forced = false;
   1.557 +
   1.558 +      // Clip forced viewport to actual scrollable area.
   1.559 +      if (viewPort && viewPort.top != null)
   1.560 +        viewPort = {top: Math.min(barMeasure.docHeight - scrollerCutOff - barMeasure.clientHeight, viewPort.top)};
   1.561 +      // Updated line heights might result in the drawn area not
   1.562 +      // actually covering the viewport. Keep looping until it does.
   1.563 +      visible = visibleLines(cm.display, cm.doc, viewPort);
   1.564 +      if (visible.from >= cm.display.viewFrom && visible.to <= cm.display.viewTo)
   1.565 +        break;
   1.566 +    }
   1.567 +
   1.568 +    cm.display.updateLineNumbers = null;
   1.569 +    if (updated) {
   1.570 +      signalLater(cm, "update", cm);
   1.571 +      if (cm.display.viewFrom != oldFrom || cm.display.viewTo != oldTo)
   1.572 +        signalLater(cm, "viewportChange", cm, cm.display.viewFrom, cm.display.viewTo);
   1.573 +    }
   1.574 +    return updated;
   1.575 +  }
   1.576 +
   1.577 +  // Does the actual updating of the line display. Bails out
   1.578 +  // (returning false) when there is nothing to be done and forced is
   1.579 +  // false.
   1.580 +  function updateDisplayInner(cm, visible, forced) {
   1.581 +    var display = cm.display, doc = cm.doc;
   1.582 +    if (!display.wrapper.offsetWidth) {
   1.583 +      resetView(cm);
   1.584 +      return;
   1.585 +    }
   1.586 +
   1.587 +    // Bail out if the visible area is already rendered and nothing changed.
   1.588 +    if (!forced && visible.from >= display.viewFrom && visible.to <= display.viewTo &&
   1.589 +        countDirtyView(cm) == 0)
   1.590 +      return;
   1.591 +
   1.592 +    if (maybeUpdateLineNumberWidth(cm))
   1.593 +      resetView(cm);
   1.594 +    var dims = getDimensions(cm);
   1.595 +
   1.596 +    // Compute a suitable new viewport (from & to)
   1.597 +    var end = doc.first + doc.size;
   1.598 +    var from = Math.max(visible.from - cm.options.viewportMargin, doc.first);
   1.599 +    var to = Math.min(end, visible.to + cm.options.viewportMargin);
   1.600 +    if (display.viewFrom < from && from - display.viewFrom < 20) from = Math.max(doc.first, display.viewFrom);
   1.601 +    if (display.viewTo > to && display.viewTo - to < 20) to = Math.min(end, display.viewTo);
   1.602 +    if (sawCollapsedSpans) {
   1.603 +      from = visualLineNo(cm.doc, from);
   1.604 +      to = visualLineEndNo(cm.doc, to);
   1.605 +    }
   1.606 +
   1.607 +    var different = from != display.viewFrom || to != display.viewTo ||
   1.608 +      display.lastSizeC != display.wrapper.clientHeight;
   1.609 +    adjustView(cm, from, to);
   1.610 +
   1.611 +    display.viewOffset = heightAtLine(getLine(cm.doc, display.viewFrom));
   1.612 +    // Position the mover div to align with the current scroll position
   1.613 +    cm.display.mover.style.top = display.viewOffset + "px";
   1.614 +
   1.615 +    var toUpdate = countDirtyView(cm);
   1.616 +    if (!different && toUpdate == 0 && !forced) return;
   1.617 +
   1.618 +    // For big changes, we hide the enclosing element during the
   1.619 +    // update, since that speeds up the operations on most browsers.
   1.620 +    var focused = activeElt();
   1.621 +    if (toUpdate > 4) display.lineDiv.style.display = "none";
   1.622 +    patchDisplay(cm, display.updateLineNumbers, dims);
   1.623 +    if (toUpdate > 4) display.lineDiv.style.display = "";
   1.624 +    // There might have been a widget with a focused element that got
   1.625 +    // hidden or updated, if so re-focus it.
   1.626 +    if (focused && activeElt() != focused && focused.offsetHeight) focused.focus();
   1.627 +
   1.628 +    // Prevent selection and cursors from interfering with the scroll
   1.629 +    // width.
   1.630 +    removeChildren(display.cursorDiv);
   1.631 +    removeChildren(display.selectionDiv);
   1.632 +
   1.633 +    if (different) {
   1.634 +      display.lastSizeC = display.wrapper.clientHeight;
   1.635 +      startWorker(cm, 400);
   1.636 +    }
   1.637 +
   1.638 +    updateHeightsInViewport(cm);
   1.639 +
   1.640 +    return true;
   1.641 +  }
   1.642 +
   1.643 +  function adjustContentWidth(cm) {
   1.644 +    var display = cm.display;
   1.645 +    var width = measureChar(cm, display.maxLine, display.maxLine.text.length).left;
   1.646 +    display.maxLineChanged = false;
   1.647 +    var minWidth = Math.max(0, width + 3);
   1.648 +    var maxScrollLeft = Math.max(0, display.sizer.offsetLeft + minWidth + scrollerCutOff - display.scroller.clientWidth);
   1.649 +    display.sizer.style.minWidth = minWidth + "px";
   1.650 +    if (maxScrollLeft < cm.doc.scrollLeft)
   1.651 +      setScrollLeft(cm, Math.min(display.scroller.scrollLeft, maxScrollLeft), true);
   1.652 +  }
   1.653 +
   1.654 +  function setDocumentHeight(cm, measure) {
   1.655 +    cm.display.sizer.style.minHeight = cm.display.heightForcer.style.top = measure.docHeight + "px";
   1.656 +    cm.display.gutters.style.height = Math.max(measure.docHeight, measure.clientHeight - scrollerCutOff) + "px";
   1.657 +  }
   1.658 +
   1.659 +  // Read the actual heights of the rendered lines, and update their
   1.660 +  // stored heights to match.
   1.661 +  function updateHeightsInViewport(cm) {
   1.662 +    var display = cm.display;
   1.663 +    var prevBottom = display.lineDiv.offsetTop;
   1.664 +    for (var i = 0; i < display.view.length; i++) {
   1.665 +      var cur = display.view[i], height;
   1.666 +      if (cur.hidden) continue;
   1.667 +      if (ie_upto7) {
   1.668 +        var bot = cur.node.offsetTop + cur.node.offsetHeight;
   1.669 +        height = bot - prevBottom;
   1.670 +        prevBottom = bot;
   1.671 +      } else {
   1.672 +        var box = cur.node.getBoundingClientRect();
   1.673 +        height = box.bottom - box.top;
   1.674 +      }
   1.675 +      var diff = cur.line.height - height;
   1.676 +      if (height < 2) height = textHeight(display);
   1.677 +      if (diff > .001 || diff < -.001) {
   1.678 +        updateLineHeight(cur.line, height);
   1.679 +        updateWidgetHeight(cur.line);
   1.680 +        if (cur.rest) for (var j = 0; j < cur.rest.length; j++)
   1.681 +          updateWidgetHeight(cur.rest[j]);
   1.682 +      }
   1.683 +    }
   1.684 +  }
   1.685 +
   1.686 +  // Read and store the height of line widgets associated with the
   1.687 +  // given line.
   1.688 +  function updateWidgetHeight(line) {
   1.689 +    if (line.widgets) for (var i = 0; i < line.widgets.length; ++i)
   1.690 +      line.widgets[i].height = line.widgets[i].node.offsetHeight;
   1.691 +  }
   1.692 +
   1.693 +  // Do a bulk-read of the DOM positions and sizes needed to draw the
   1.694 +  // view, so that we don't interleave reading and writing to the DOM.
   1.695 +  function getDimensions(cm) {
   1.696 +    var d = cm.display, left = {}, width = {};
   1.697 +    for (var n = d.gutters.firstChild, i = 0; n; n = n.nextSibling, ++i) {
   1.698 +      left[cm.options.gutters[i]] = n.offsetLeft;
   1.699 +      width[cm.options.gutters[i]] = n.offsetWidth;
   1.700 +    }
   1.701 +    return {fixedPos: compensateForHScroll(d),
   1.702 +            gutterTotalWidth: d.gutters.offsetWidth,
   1.703 +            gutterLeft: left,
   1.704 +            gutterWidth: width,
   1.705 +            wrapperWidth: d.wrapper.clientWidth};
   1.706 +  }
   1.707 +
   1.708 +  // Sync the actual display DOM structure with display.view, removing
   1.709 +  // nodes for lines that are no longer in view, and creating the ones
   1.710 +  // that are not there yet, and updating the ones that are out of
   1.711 +  // date.
   1.712 +  function patchDisplay(cm, updateNumbersFrom, dims) {
   1.713 +    var display = cm.display, lineNumbers = cm.options.lineNumbers;
   1.714 +    var container = display.lineDiv, cur = container.firstChild;
   1.715 +
   1.716 +    function rm(node) {
   1.717 +      var next = node.nextSibling;
   1.718 +      // Works around a throw-scroll bug in OS X Webkit
   1.719 +      if (webkit && mac && cm.display.currentWheelTarget == node)
   1.720 +        node.style.display = "none";
   1.721 +      else
   1.722 +        node.parentNode.removeChild(node);
   1.723 +      return next;
   1.724 +    }
   1.725 +
   1.726 +    var view = display.view, lineN = display.viewFrom;
   1.727 +    // Loop over the elements in the view, syncing cur (the DOM nodes
   1.728 +    // in display.lineDiv) with the view as we go.
   1.729 +    for (var i = 0; i < view.length; i++) {
   1.730 +      var lineView = view[i];
   1.731 +      if (lineView.hidden) {
   1.732 +      } else if (!lineView.node) { // Not drawn yet
   1.733 +        var node = buildLineElement(cm, lineView, lineN, dims);
   1.734 +        container.insertBefore(node, cur);
   1.735 +      } else { // Already drawn
   1.736 +        while (cur != lineView.node) cur = rm(cur);
   1.737 +        var updateNumber = lineNumbers && updateNumbersFrom != null &&
   1.738 +          updateNumbersFrom <= lineN && lineView.lineNumber;
   1.739 +        if (lineView.changes) {
   1.740 +          if (indexOf(lineView.changes, "gutter") > -1) updateNumber = false;
   1.741 +          updateLineForChanges(cm, lineView, lineN, dims);
   1.742 +        }
   1.743 +        if (updateNumber) {
   1.744 +          removeChildren(lineView.lineNumber);
   1.745 +          lineView.lineNumber.appendChild(document.createTextNode(lineNumberFor(cm.options, lineN)));
   1.746 +        }
   1.747 +        cur = lineView.node.nextSibling;
   1.748 +      }
   1.749 +      lineN += lineView.size;
   1.750 +    }
   1.751 +    while (cur) cur = rm(cur);
   1.752 +  }
   1.753 +
   1.754 +  // When an aspect of a line changes, a string is added to
   1.755 +  // lineView.changes. This updates the relevant part of the line's
   1.756 +  // DOM structure.
   1.757 +  function updateLineForChanges(cm, lineView, lineN, dims) {
   1.758 +    for (var j = 0; j < lineView.changes.length; j++) {
   1.759 +      var type = lineView.changes[j];
   1.760 +      if (type == "text") updateLineText(cm, lineView);
   1.761 +      else if (type == "gutter") updateLineGutter(cm, lineView, lineN, dims);
   1.762 +      else if (type == "class") updateLineClasses(lineView);
   1.763 +      else if (type == "widget") updateLineWidgets(lineView, dims);
   1.764 +    }
   1.765 +    lineView.changes = null;
   1.766 +  }
   1.767 +
   1.768 +  // Lines with gutter elements, widgets or a background class need to
   1.769 +  // be wrapped, and have the extra elements added to the wrapper div
   1.770 +  function ensureLineWrapped(lineView) {
   1.771 +    if (lineView.node == lineView.text) {
   1.772 +      lineView.node = elt("div", null, null, "position: relative");
   1.773 +      if (lineView.text.parentNode)
   1.774 +        lineView.text.parentNode.replaceChild(lineView.node, lineView.text);
   1.775 +      lineView.node.appendChild(lineView.text);
   1.776 +      if (ie_upto7) lineView.node.style.zIndex = 2;
   1.777 +    }
   1.778 +    return lineView.node;
   1.779 +  }
   1.780 +
   1.781 +  function updateLineBackground(lineView) {
   1.782 +    var cls = lineView.bgClass ? lineView.bgClass + " " + (lineView.line.bgClass || "") : lineView.line.bgClass;
   1.783 +    if (cls) cls += " CodeMirror-linebackground";
   1.784 +    if (lineView.background) {
   1.785 +      if (cls) lineView.background.className = cls;
   1.786 +      else { lineView.background.parentNode.removeChild(lineView.background); lineView.background = null; }
   1.787 +    } else if (cls) {
   1.788 +      var wrap = ensureLineWrapped(lineView);
   1.789 +      lineView.background = wrap.insertBefore(elt("div", null, cls), wrap.firstChild);
   1.790 +    }
   1.791 +  }
   1.792 +
   1.793 +  // Wrapper around buildLineContent which will reuse the structure
   1.794 +  // in display.externalMeasured when possible.
   1.795 +  function getLineContent(cm, lineView) {
   1.796 +    var ext = cm.display.externalMeasured;
   1.797 +    if (ext && ext.line == lineView.line) {
   1.798 +      cm.display.externalMeasured = null;
   1.799 +      lineView.measure = ext.measure;
   1.800 +      return ext.built;
   1.801 +    }
   1.802 +    return buildLineContent(cm, lineView);
   1.803 +  }
   1.804 +
   1.805 +  // Redraw the line's text. Interacts with the background and text
   1.806 +  // classes because the mode may output tokens that influence these
   1.807 +  // classes.
   1.808 +  function updateLineText(cm, lineView) {
   1.809 +    var cls = lineView.text.className;
   1.810 +    var built = getLineContent(cm, lineView);
   1.811 +    if (lineView.text == lineView.node) lineView.node = built.pre;
   1.812 +    lineView.text.parentNode.replaceChild(built.pre, lineView.text);
   1.813 +    lineView.text = built.pre;
   1.814 +    if (built.bgClass != lineView.bgClass || built.textClass != lineView.textClass) {
   1.815 +      lineView.bgClass = built.bgClass;
   1.816 +      lineView.textClass = built.textClass;
   1.817 +      updateLineClasses(lineView);
   1.818 +    } else if (cls) {
   1.819 +      lineView.text.className = cls;
   1.820 +    }
   1.821 +  }
   1.822 +
   1.823 +  function updateLineClasses(lineView) {
   1.824 +    updateLineBackground(lineView);
   1.825 +    if (lineView.line.wrapClass)
   1.826 +      ensureLineWrapped(lineView).className = lineView.line.wrapClass;
   1.827 +    else if (lineView.node != lineView.text)
   1.828 +      lineView.node.className = "";
   1.829 +    var textClass = lineView.textClass ? lineView.textClass + " " + (lineView.line.textClass || "") : lineView.line.textClass;
   1.830 +    lineView.text.className = textClass || "";
   1.831 +  }
   1.832 +
   1.833 +  function updateLineGutter(cm, lineView, lineN, dims) {
   1.834 +    if (lineView.gutter) {
   1.835 +      lineView.node.removeChild(lineView.gutter);
   1.836 +      lineView.gutter = null;
   1.837 +    }
   1.838 +    var markers = lineView.line.gutterMarkers;
   1.839 +    if (cm.options.lineNumbers || markers) {
   1.840 +      var wrap = ensureLineWrapped(lineView);
   1.841 +      var gutterWrap = lineView.gutter =
   1.842 +        wrap.insertBefore(elt("div", null, "CodeMirror-gutter-wrapper", "position: absolute; left: " +
   1.843 +                              (cm.options.fixedGutter ? dims.fixedPos : -dims.gutterTotalWidth) + "px"),
   1.844 +                          lineView.text);
   1.845 +      if (cm.options.lineNumbers && (!markers || !markers["CodeMirror-linenumbers"]))
   1.846 +        lineView.lineNumber = gutterWrap.appendChild(
   1.847 +          elt("div", lineNumberFor(cm.options, lineN),
   1.848 +              "CodeMirror-linenumber CodeMirror-gutter-elt",
   1.849 +              "left: " + dims.gutterLeft["CodeMirror-linenumbers"] + "px; width: "
   1.850 +              + cm.display.lineNumInnerWidth + "px"));
   1.851 +      if (markers) for (var k = 0; k < cm.options.gutters.length; ++k) {
   1.852 +        var id = cm.options.gutters[k], found = markers.hasOwnProperty(id) && markers[id];
   1.853 +        if (found)
   1.854 +          gutterWrap.appendChild(elt("div", [found], "CodeMirror-gutter-elt", "left: " +
   1.855 +                                     dims.gutterLeft[id] + "px; width: " + dims.gutterWidth[id] + "px"));
   1.856 +      }
   1.857 +    }
   1.858 +  }
   1.859 +
   1.860 +  function updateLineWidgets(lineView, dims) {
   1.861 +    if (lineView.alignable) lineView.alignable = null;
   1.862 +    for (var node = lineView.node.firstChild, next; node; node = next) {
   1.863 +      var next = node.nextSibling;
   1.864 +      if (node.className == "CodeMirror-linewidget")
   1.865 +        lineView.node.removeChild(node);
   1.866 +    }
   1.867 +    insertLineWidgets(lineView, dims);
   1.868 +  }
   1.869 +
   1.870 +  // Build a line's DOM representation from scratch
   1.871 +  function buildLineElement(cm, lineView, lineN, dims) {
   1.872 +    var built = getLineContent(cm, lineView);
   1.873 +    lineView.text = lineView.node = built.pre;
   1.874 +    if (built.bgClass) lineView.bgClass = built.bgClass;
   1.875 +    if (built.textClass) lineView.textClass = built.textClass;
   1.876 +
   1.877 +    updateLineClasses(lineView);
   1.878 +    updateLineGutter(cm, lineView, lineN, dims);
   1.879 +    insertLineWidgets(lineView, dims);
   1.880 +    return lineView.node;
   1.881 +  }
   1.882 +
   1.883 +  // A lineView may contain multiple logical lines (when merged by
   1.884 +  // collapsed spans). The widgets for all of them need to be drawn.
   1.885 +  function insertLineWidgets(lineView, dims) {
   1.886 +    insertLineWidgetsFor(lineView.line, lineView, dims, true);
   1.887 +    if (lineView.rest) for (var i = 0; i < lineView.rest.length; i++)
   1.888 +      insertLineWidgetsFor(lineView.rest[i], lineView, dims, false);
   1.889 +  }
   1.890 +
   1.891 +  function insertLineWidgetsFor(line, lineView, dims, allowAbove) {
   1.892 +    if (!line.widgets) return;
   1.893 +    var wrap = ensureLineWrapped(lineView);
   1.894 +    for (var i = 0, ws = line.widgets; i < ws.length; ++i) {
   1.895 +      var widget = ws[i], node = elt("div", [widget.node], "CodeMirror-linewidget");
   1.896 +      if (!widget.handleMouseEvents) node.ignoreEvents = true;
   1.897 +      positionLineWidget(widget, node, lineView, dims);
   1.898 +      if (allowAbove && widget.above)
   1.899 +        wrap.insertBefore(node, lineView.gutter || lineView.text);
   1.900 +      else
   1.901 +        wrap.appendChild(node);
   1.902 +      signalLater(widget, "redraw");
   1.903 +    }
   1.904 +  }
   1.905 +
   1.906 +  function positionLineWidget(widget, node, lineView, dims) {
   1.907 +    if (widget.noHScroll) {
   1.908 +      (lineView.alignable || (lineView.alignable = [])).push(node);
   1.909 +      var width = dims.wrapperWidth;
   1.910 +      node.style.left = dims.fixedPos + "px";
   1.911 +      if (!widget.coverGutter) {
   1.912 +        width -= dims.gutterTotalWidth;
   1.913 +        node.style.paddingLeft = dims.gutterTotalWidth + "px";
   1.914 +      }
   1.915 +      node.style.width = width + "px";
   1.916 +    }
   1.917 +    if (widget.coverGutter) {
   1.918 +      node.style.zIndex = 5;
   1.919 +      node.style.position = "relative";
   1.920 +      if (!widget.noHScroll) node.style.marginLeft = -dims.gutterTotalWidth + "px";
   1.921 +    }
   1.922 +  }
   1.923 +
   1.924 +  // POSITION OBJECT
   1.925 +
   1.926 +  // A Pos instance represents a position within the text.
   1.927 +  var Pos = CodeMirror.Pos = function(line, ch) {
   1.928 +    if (!(this instanceof Pos)) return new Pos(line, ch);
   1.929 +    this.line = line; this.ch = ch;
   1.930 +  };
   1.931 +
   1.932 +  // Compare two positions, return 0 if they are the same, a negative
   1.933 +  // number when a is less, and a positive number otherwise.
   1.934 +  var cmp = CodeMirror.cmpPos = function(a, b) { return a.line - b.line || a.ch - b.ch; };
   1.935 +
   1.936 +  function copyPos(x) {return Pos(x.line, x.ch);}
   1.937 +  function maxPos(a, b) { return cmp(a, b) < 0 ? b : a; }
   1.938 +  function minPos(a, b) { return cmp(a, b) < 0 ? a : b; }
   1.939 +
   1.940 +  // SELECTION / CURSOR
   1.941 +
   1.942 +  // Selection objects are immutable. A new one is created every time
   1.943 +  // the selection changes. A selection is one or more non-overlapping
   1.944 +  // (and non-touching) ranges, sorted, and an integer that indicates
   1.945 +  // which one is the primary selection (the one that's scrolled into
   1.946 +  // view, that getCursor returns, etc).
   1.947 +  function Selection(ranges, primIndex) {
   1.948 +    this.ranges = ranges;
   1.949 +    this.primIndex = primIndex;
   1.950 +  }
   1.951 +
   1.952 +  Selection.prototype = {
   1.953 +    primary: function() { return this.ranges[this.primIndex]; },
   1.954 +    equals: function(other) {
   1.955 +      if (other == this) return true;
   1.956 +      if (other.primIndex != this.primIndex || other.ranges.length != this.ranges.length) return false;
   1.957 +      for (var i = 0; i < this.ranges.length; i++) {
   1.958 +        var here = this.ranges[i], there = other.ranges[i];
   1.959 +        if (cmp(here.anchor, there.anchor) != 0 || cmp(here.head, there.head) != 0) return false;
   1.960 +      }
   1.961 +      return true;
   1.962 +    },
   1.963 +    deepCopy: function() {
   1.964 +      for (var out = [], i = 0; i < this.ranges.length; i++)
   1.965 +        out[i] = new Range(copyPos(this.ranges[i].anchor), copyPos(this.ranges[i].head));
   1.966 +      return new Selection(out, this.primIndex);
   1.967 +    },
   1.968 +    somethingSelected: function() {
   1.969 +      for (var i = 0; i < this.ranges.length; i++)
   1.970 +        if (!this.ranges[i].empty()) return true;
   1.971 +      return false;
   1.972 +    },
   1.973 +    contains: function(pos, end) {
   1.974 +      if (!end) end = pos;
   1.975 +      for (var i = 0; i < this.ranges.length; i++) {
   1.976 +        var range = this.ranges[i];
   1.977 +        if (cmp(end, range.from()) >= 0 && cmp(pos, range.to()) <= 0)
   1.978 +          return i;
   1.979 +      }
   1.980 +      return -1;
   1.981 +    }
   1.982 +  };
   1.983 +
   1.984 +  function Range(anchor, head) {
   1.985 +    this.anchor = anchor; this.head = head;
   1.986 +  }
   1.987 +
   1.988 +  Range.prototype = {
   1.989 +    from: function() { return minPos(this.anchor, this.head); },
   1.990 +    to: function() { return maxPos(this.anchor, this.head); },
   1.991 +    empty: function() {
   1.992 +      return this.head.line == this.anchor.line && this.head.ch == this.anchor.ch;
   1.993 +    }
   1.994 +  };
   1.995 +
   1.996 +  // Take an unsorted, potentially overlapping set of ranges, and
   1.997 +  // build a selection out of it. 'Consumes' ranges array (modifying
   1.998 +  // it).
   1.999 +  function normalizeSelection(ranges, primIndex) {
  1.1000 +    var prim = ranges[primIndex];
  1.1001 +    ranges.sort(function(a, b) { return cmp(a.from(), b.from()); });
  1.1002 +    primIndex = indexOf(ranges, prim);
  1.1003 +    for (var i = 1; i < ranges.length; i++) {
  1.1004 +      var cur = ranges[i], prev = ranges[i - 1];
  1.1005 +      if (cmp(prev.to(), cur.from()) >= 0) {
  1.1006 +        var from = minPos(prev.from(), cur.from()), to = maxPos(prev.to(), cur.to());
  1.1007 +        var inv = prev.empty() ? cur.from() == cur.head : prev.from() == prev.head;
  1.1008 +        if (i <= primIndex) --primIndex;
  1.1009 +        ranges.splice(--i, 2, new Range(inv ? to : from, inv ? from : to));
  1.1010 +      }
  1.1011 +    }
  1.1012 +    return new Selection(ranges, primIndex);
  1.1013 +  }
  1.1014 +
  1.1015 +  function simpleSelection(anchor, head) {
  1.1016 +    return new Selection([new Range(anchor, head || anchor)], 0);
  1.1017 +  }
  1.1018 +
  1.1019 +  // Most of the external API clips given positions to make sure they
  1.1020 +  // actually exist within the document.
  1.1021 +  function clipLine(doc, n) {return Math.max(doc.first, Math.min(n, doc.first + doc.size - 1));}
  1.1022 +  function clipPos(doc, pos) {
  1.1023 +    if (pos.line < doc.first) return Pos(doc.first, 0);
  1.1024 +    var last = doc.first + doc.size - 1;
  1.1025 +    if (pos.line > last) return Pos(last, getLine(doc, last).text.length);
  1.1026 +    return clipToLen(pos, getLine(doc, pos.line).text.length);
  1.1027 +  }
  1.1028 +  function clipToLen(pos, linelen) {
  1.1029 +    var ch = pos.ch;
  1.1030 +    if (ch == null || ch > linelen) return Pos(pos.line, linelen);
  1.1031 +    else if (ch < 0) return Pos(pos.line, 0);
  1.1032 +    else return pos;
  1.1033 +  }
  1.1034 +  function isLine(doc, l) {return l >= doc.first && l < doc.first + doc.size;}
  1.1035 +  function clipPosArray(doc, array) {
  1.1036 +    for (var out = [], i = 0; i < array.length; i++) out[i] = clipPos(doc, array[i]);
  1.1037 +    return out;
  1.1038 +  }
  1.1039 +
  1.1040 +  // SELECTION UPDATES
  1.1041 +
  1.1042 +  // The 'scroll' parameter given to many of these indicated whether
  1.1043 +  // the new cursor position should be scrolled into view after
  1.1044 +  // modifying the selection.
  1.1045 +
  1.1046 +  // If shift is held or the extend flag is set, extends a range to
  1.1047 +  // include a given position (and optionally a second position).
  1.1048 +  // Otherwise, simply returns the range between the given positions.
  1.1049 +  // Used for cursor motion and such.
  1.1050 +  function extendRange(doc, range, head, other) {
  1.1051 +    if (doc.cm && doc.cm.display.shift || doc.extend) {
  1.1052 +      var anchor = range.anchor;
  1.1053 +      if (other) {
  1.1054 +        var posBefore = cmp(head, anchor) < 0;
  1.1055 +        if (posBefore != (cmp(other, anchor) < 0)) {
  1.1056 +          anchor = head;
  1.1057 +          head = other;
  1.1058 +        } else if (posBefore != (cmp(head, other) < 0)) {
  1.1059 +          head = other;
  1.1060 +        }
  1.1061 +      }
  1.1062 +      return new Range(anchor, head);
  1.1063 +    } else {
  1.1064 +      return new Range(other || head, head);
  1.1065 +    }
  1.1066 +  }
  1.1067 +
  1.1068 +  // Extend the primary selection range, discard the rest.
  1.1069 +  function extendSelection(doc, head, other, options) {
  1.1070 +    setSelection(doc, new Selection([extendRange(doc, doc.sel.primary(), head, other)], 0), options);
  1.1071 +  }
  1.1072 +
  1.1073 +  // Extend all selections (pos is an array of selections with length
  1.1074 +  // equal the number of selections)
  1.1075 +  function extendSelections(doc, heads, options) {
  1.1076 +    for (var out = [], i = 0; i < doc.sel.ranges.length; i++)
  1.1077 +      out[i] = extendRange(doc, doc.sel.ranges[i], heads[i], null);
  1.1078 +    var newSel = normalizeSelection(out, doc.sel.primIndex);
  1.1079 +    setSelection(doc, newSel, options);
  1.1080 +  }
  1.1081 +
  1.1082 +  // Updates a single range in the selection.
  1.1083 +  function replaceOneSelection(doc, i, range, options) {
  1.1084 +    var ranges = doc.sel.ranges.slice(0);
  1.1085 +    ranges[i] = range;
  1.1086 +    setSelection(doc, normalizeSelection(ranges, doc.sel.primIndex), options);
  1.1087 +  }
  1.1088 +
  1.1089 +  // Reset the selection to a single range.
  1.1090 +  function setSimpleSelection(doc, anchor, head, options) {
  1.1091 +    setSelection(doc, simpleSelection(anchor, head), options);
  1.1092 +  }
  1.1093 +
  1.1094 +  // Give beforeSelectionChange handlers a change to influence a
  1.1095 +  // selection update.
  1.1096 +  function filterSelectionChange(doc, sel) {
  1.1097 +    var obj = {
  1.1098 +      ranges: sel.ranges,
  1.1099 +      update: function(ranges) {
  1.1100 +        this.ranges = [];
  1.1101 +        for (var i = 0; i < ranges.length; i++)
  1.1102 +          this.ranges[i] = new Range(clipPos(doc, ranges[i].anchor),
  1.1103 +                                     clipPos(doc, ranges[i].head));
  1.1104 +      }
  1.1105 +    };
  1.1106 +    signal(doc, "beforeSelectionChange", doc, obj);
  1.1107 +    if (doc.cm) signal(doc.cm, "beforeSelectionChange", doc.cm, obj);
  1.1108 +    if (obj.ranges != sel.ranges) return normalizeSelection(obj.ranges, obj.ranges.length - 1);
  1.1109 +    else return sel;
  1.1110 +  }
  1.1111 +
  1.1112 +  function setSelectionReplaceHistory(doc, sel, options) {
  1.1113 +    var done = doc.history.done, last = lst(done);
  1.1114 +    if (last && last.ranges) {
  1.1115 +      done[done.length - 1] = sel;
  1.1116 +      setSelectionNoUndo(doc, sel, options);
  1.1117 +    } else {
  1.1118 +      setSelection(doc, sel, options);
  1.1119 +    }
  1.1120 +  }
  1.1121 +
  1.1122 +  // Set a new selection.
  1.1123 +  function setSelection(doc, sel, options) {
  1.1124 +    setSelectionNoUndo(doc, sel, options);
  1.1125 +    addSelectionToHistory(doc, doc.sel, doc.cm ? doc.cm.curOp.id : NaN, options);
  1.1126 +  }
  1.1127 +
  1.1128 +  function setSelectionNoUndo(doc, sel, options) {
  1.1129 +    if (hasHandler(doc, "beforeSelectionChange") || doc.cm && hasHandler(doc.cm, "beforeSelectionChange"))
  1.1130 +      sel = filterSelectionChange(doc, sel);
  1.1131 +
  1.1132 +    var bias = cmp(sel.primary().head, doc.sel.primary().head) < 0 ? -1 : 1;
  1.1133 +    setSelectionInner(doc, skipAtomicInSelection(doc, sel, bias, true));
  1.1134 +
  1.1135 +    if (!(options && options.scroll === false) && doc.cm)
  1.1136 +      ensureCursorVisible(doc.cm);
  1.1137 +  }
  1.1138 +
  1.1139 +  function setSelectionInner(doc, sel) {
  1.1140 +    if (sel.equals(doc.sel)) return;
  1.1141 +
  1.1142 +    doc.sel = sel;
  1.1143 +
  1.1144 +    if (doc.cm)
  1.1145 +      doc.cm.curOp.updateInput = doc.cm.curOp.selectionChanged =
  1.1146 +        doc.cm.curOp.cursorActivity = true;
  1.1147 +    signalLater(doc, "cursorActivity", doc);
  1.1148 +  }
  1.1149 +
  1.1150 +  // Verify that the selection does not partially select any atomic
  1.1151 +  // marked ranges.
  1.1152 +  function reCheckSelection(doc) {
  1.1153 +    setSelectionInner(doc, skipAtomicInSelection(doc, doc.sel, null, false), sel_dontScroll);
  1.1154 +  }
  1.1155 +
  1.1156 +  // Return a selection that does not partially select any atomic
  1.1157 +  // ranges.
  1.1158 +  function skipAtomicInSelection(doc, sel, bias, mayClear) {
  1.1159 +    var out;
  1.1160 +    for (var i = 0; i < sel.ranges.length; i++) {
  1.1161 +      var range = sel.ranges[i];
  1.1162 +      var newAnchor = skipAtomic(doc, range.anchor, bias, mayClear);
  1.1163 +      var newHead = skipAtomic(doc, range.head, bias, mayClear);
  1.1164 +      if (out || newAnchor != range.anchor || newHead != range.head) {
  1.1165 +        if (!out) out = sel.ranges.slice(0, i);
  1.1166 +        out[i] = new Range(newAnchor, newHead);
  1.1167 +      }
  1.1168 +    }
  1.1169 +    return out ? normalizeSelection(out, sel.primIndex) : sel;
  1.1170 +  }
  1.1171 +
  1.1172 +  // Ensure a given position is not inside an atomic range.
  1.1173 +  function skipAtomic(doc, pos, bias, mayClear) {
  1.1174 +    var flipped = false, curPos = pos;
  1.1175 +    var dir = bias || 1;
  1.1176 +    doc.cantEdit = false;
  1.1177 +    search: for (;;) {
  1.1178 +      var line = getLine(doc, curPos.line);
  1.1179 +      if (line.markedSpans) {
  1.1180 +        for (var i = 0; i < line.markedSpans.length; ++i) {
  1.1181 +          var sp = line.markedSpans[i], m = sp.marker;
  1.1182 +          if ((sp.from == null || (m.inclusiveLeft ? sp.from <= curPos.ch : sp.from < curPos.ch)) &&
  1.1183 +              (sp.to == null || (m.inclusiveRight ? sp.to >= curPos.ch : sp.to > curPos.ch))) {
  1.1184 +            if (mayClear) {
  1.1185 +              signal(m, "beforeCursorEnter");
  1.1186 +              if (m.explicitlyCleared) {
  1.1187 +                if (!line.markedSpans) break;
  1.1188 +                else {--i; continue;}
  1.1189 +              }
  1.1190 +            }
  1.1191 +            if (!m.atomic) continue;
  1.1192 +            var newPos = m.find(dir < 0 ? -1 : 1);
  1.1193 +            if (cmp(newPos, curPos) == 0) {
  1.1194 +              newPos.ch += dir;
  1.1195 +              if (newPos.ch < 0) {
  1.1196 +                if (newPos.line > doc.first) newPos = clipPos(doc, Pos(newPos.line - 1));
  1.1197 +                else newPos = null;
  1.1198 +              } else if (newPos.ch > line.text.length) {
  1.1199 +                if (newPos.line < doc.first + doc.size - 1) newPos = Pos(newPos.line + 1, 0);
  1.1200 +                else newPos = null;
  1.1201 +              }
  1.1202 +              if (!newPos) {
  1.1203 +                if (flipped) {
  1.1204 +                  // Driven in a corner -- no valid cursor position found at all
  1.1205 +                  // -- try again *with* clearing, if we didn't already
  1.1206 +                  if (!mayClear) return skipAtomic(doc, pos, bias, true);
  1.1207 +                  // Otherwise, turn off editing until further notice, and return the start of the doc
  1.1208 +                  doc.cantEdit = true;
  1.1209 +                  return Pos(doc.first, 0);
  1.1210 +                }
  1.1211 +                flipped = true; newPos = pos; dir = -dir;
  1.1212 +              }
  1.1213 +            }
  1.1214 +            curPos = newPos;
  1.1215 +            continue search;
  1.1216 +          }
  1.1217 +        }
  1.1218 +      }
  1.1219 +      return curPos;
  1.1220 +    }
  1.1221 +  }
  1.1222 +
  1.1223 +  // SELECTION DRAWING
  1.1224 +
  1.1225 +  // Redraw the selection and/or cursor
  1.1226 +  function updateSelection(cm) {
  1.1227 +    var display = cm.display, doc = cm.doc;
  1.1228 +    var curFragment = document.createDocumentFragment();
  1.1229 +    var selFragment = document.createDocumentFragment();
  1.1230 +
  1.1231 +    for (var i = 0; i < doc.sel.ranges.length; i++) {
  1.1232 +      var range = doc.sel.ranges[i];
  1.1233 +      var collapsed = range.empty();
  1.1234 +      if (collapsed || cm.options.showCursorWhenSelecting)
  1.1235 +        updateSelectionCursor(cm, range, curFragment);
  1.1236 +      if (!collapsed)
  1.1237 +        updateSelectionRange(cm, range, selFragment);
  1.1238 +    }
  1.1239 +
  1.1240 +    // Move the hidden textarea near the cursor to prevent scrolling artifacts
  1.1241 +    if (cm.options.moveInputWithCursor) {
  1.1242 +      var headPos = cursorCoords(cm, doc.sel.primary().head, "div");
  1.1243 +      var wrapOff = display.wrapper.getBoundingClientRect(), lineOff = display.lineDiv.getBoundingClientRect();
  1.1244 +      var top = Math.max(0, Math.min(display.wrapper.clientHeight - 10,
  1.1245 +                                     headPos.top + lineOff.top - wrapOff.top));
  1.1246 +      var left = Math.max(0, Math.min(display.wrapper.clientWidth - 10,
  1.1247 +                                      headPos.left + lineOff.left - wrapOff.left));
  1.1248 +      display.inputDiv.style.top = top + "px";
  1.1249 +      display.inputDiv.style.left = left + "px";
  1.1250 +    }
  1.1251 +
  1.1252 +    removeChildrenAndAdd(display.cursorDiv, curFragment);
  1.1253 +    removeChildrenAndAdd(display.selectionDiv, selFragment);
  1.1254 +  }
  1.1255 +
  1.1256 +  // Draws a cursor for the given range
  1.1257 +  function updateSelectionCursor(cm, range, output) {
  1.1258 +    var pos = cursorCoords(cm, range.head, "div");
  1.1259 +
  1.1260 +    var cursor = output.appendChild(elt("div", "\u00a0", "CodeMirror-cursor"));
  1.1261 +    cursor.style.left = pos.left + "px";
  1.1262 +    cursor.style.top = pos.top + "px";
  1.1263 +    cursor.style.height = Math.max(0, pos.bottom - pos.top) * cm.options.cursorHeight + "px";
  1.1264 +
  1.1265 +    if (pos.other) {
  1.1266 +      // Secondary cursor, shown when on a 'jump' in bi-directional text
  1.1267 +      var otherCursor = output.appendChild(elt("div", "\u00a0", "CodeMirror-cursor CodeMirror-secondarycursor"));
  1.1268 +      otherCursor.style.display = "";
  1.1269 +      otherCursor.style.left = pos.other.left + "px";
  1.1270 +      otherCursor.style.top = pos.other.top + "px";
  1.1271 +      otherCursor.style.height = (pos.other.bottom - pos.other.top) * .85 + "px";
  1.1272 +    }
  1.1273 +  }
  1.1274 +
  1.1275 +  // Draws the given range as a highlighted selection
  1.1276 +  function updateSelectionRange(cm, range, output) {
  1.1277 +    var display = cm.display, doc = cm.doc;
  1.1278 +    var fragment = document.createDocumentFragment();
  1.1279 +    var padding = paddingH(cm.display), leftSide = padding.left, rightSide = display.lineSpace.offsetWidth - padding.right;
  1.1280 +
  1.1281 +    function add(left, top, width, bottom) {
  1.1282 +      if (top < 0) top = 0;
  1.1283 +      fragment.appendChild(elt("div", null, "CodeMirror-selected", "position: absolute; left: " + left +
  1.1284 +                               "px; top: " + top + "px; width: " + (width == null ? rightSide - left : width) +
  1.1285 +                               "px; height: " + (bottom - top) + "px"));
  1.1286 +    }
  1.1287 +
  1.1288 +    function drawForLine(line, fromArg, toArg) {
  1.1289 +      var lineObj = getLine(doc, line);
  1.1290 +      var lineLen = lineObj.text.length;
  1.1291 +      var start, end;
  1.1292 +      function coords(ch, bias) {
  1.1293 +        return charCoords(cm, Pos(line, ch), "div", lineObj, bias);
  1.1294 +      }
  1.1295 +
  1.1296 +      iterateBidiSections(getOrder(lineObj), fromArg || 0, toArg == null ? lineLen : toArg, function(from, to, dir) {
  1.1297 +        var leftPos = coords(from, "left"), rightPos, left, right;
  1.1298 +        if (from == to) {
  1.1299 +          rightPos = leftPos;
  1.1300 +          left = right = leftPos.left;
  1.1301 +        } else {
  1.1302 +          rightPos = coords(to - 1, "right");
  1.1303 +          if (dir == "rtl") { var tmp = leftPos; leftPos = rightPos; rightPos = tmp; }
  1.1304 +          left = leftPos.left;
  1.1305 +          right = rightPos.right;
  1.1306 +        }
  1.1307 +        if (fromArg == null && from == 0) left = leftSide;
  1.1308 +        if (rightPos.top - leftPos.top > 3) { // Different lines, draw top part
  1.1309 +          add(left, leftPos.top, null, leftPos.bottom);
  1.1310 +          left = leftSide;
  1.1311 +          if (leftPos.bottom < rightPos.top) add(left, leftPos.bottom, null, rightPos.top);
  1.1312 +        }
  1.1313 +        if (toArg == null && to == lineLen) right = rightSide;
  1.1314 +        if (!start || leftPos.top < start.top || leftPos.top == start.top && leftPos.left < start.left)
  1.1315 +          start = leftPos;
  1.1316 +        if (!end || rightPos.bottom > end.bottom || rightPos.bottom == end.bottom && rightPos.right > end.right)
  1.1317 +          end = rightPos;
  1.1318 +        if (left < leftSide + 1) left = leftSide;
  1.1319 +        add(left, rightPos.top, right - left, rightPos.bottom);
  1.1320 +      });
  1.1321 +      return {start: start, end: end};
  1.1322 +    }
  1.1323 +
  1.1324 +    var sFrom = range.from(), sTo = range.to();
  1.1325 +    if (sFrom.line == sTo.line) {
  1.1326 +      drawForLine(sFrom.line, sFrom.ch, sTo.ch);
  1.1327 +    } else {
  1.1328 +      var fromLine = getLine(doc, sFrom.line), toLine = getLine(doc, sTo.line);
  1.1329 +      var singleVLine = visualLine(fromLine) == visualLine(toLine);
  1.1330 +      var leftEnd = drawForLine(sFrom.line, sFrom.ch, singleVLine ? fromLine.text.length + 1 : null).end;
  1.1331 +      var rightStart = drawForLine(sTo.line, singleVLine ? 0 : null, sTo.ch).start;
  1.1332 +      if (singleVLine) {
  1.1333 +        if (leftEnd.top < rightStart.top - 2) {
  1.1334 +          add(leftEnd.right, leftEnd.top, null, leftEnd.bottom);
  1.1335 +          add(leftSide, rightStart.top, rightStart.left, rightStart.bottom);
  1.1336 +        } else {
  1.1337 +          add(leftEnd.right, leftEnd.top, rightStart.left - leftEnd.right, leftEnd.bottom);
  1.1338 +        }
  1.1339 +      }
  1.1340 +      if (leftEnd.bottom < rightStart.top)
  1.1341 +        add(leftSide, leftEnd.bottom, null, rightStart.top);
  1.1342 +    }
  1.1343 +
  1.1344 +    output.appendChild(fragment);
  1.1345 +  }
  1.1346 +
  1.1347 +  // Cursor-blinking
  1.1348 +  function restartBlink(cm) {
  1.1349 +    if (!cm.state.focused) return;
  1.1350 +    var display = cm.display;
  1.1351 +    clearInterval(display.blinker);
  1.1352 +    var on = true;
  1.1353 +    display.cursorDiv.style.visibility = "";
  1.1354 +    if (cm.options.cursorBlinkRate > 0)
  1.1355 +      display.blinker = setInterval(function() {
  1.1356 +        display.cursorDiv.style.visibility = (on = !on) ? "" : "hidden";
  1.1357 +      }, cm.options.cursorBlinkRate);
  1.1358 +  }
  1.1359 +
  1.1360 +  // HIGHLIGHT WORKER
  1.1361 +
  1.1362 +  function startWorker(cm, time) {
  1.1363 +    if (cm.doc.mode.startState && cm.doc.frontier < cm.display.viewTo)
  1.1364 +      cm.state.highlight.set(time, bind(highlightWorker, cm));
  1.1365 +  }
  1.1366 +
  1.1367 +  function highlightWorker(cm) {
  1.1368 +    var doc = cm.doc;
  1.1369 +    if (doc.frontier < doc.first) doc.frontier = doc.first;
  1.1370 +    if (doc.frontier >= cm.display.viewTo) return;
  1.1371 +    var end = +new Date + cm.options.workTime;
  1.1372 +    var state = copyState(doc.mode, getStateBefore(cm, doc.frontier));
  1.1373 +
  1.1374 +    runInOp(cm, function() {
  1.1375 +    doc.iter(doc.frontier, Math.min(doc.first + doc.size, cm.display.viewTo + 500), function(line) {
  1.1376 +      if (doc.frontier >= cm.display.viewFrom) { // Visible
  1.1377 +        var oldStyles = line.styles;
  1.1378 +        line.styles = highlightLine(cm, line, state, true);
  1.1379 +        var ischange = !oldStyles || oldStyles.length != line.styles.length;
  1.1380 +        for (var i = 0; !ischange && i < oldStyles.length; ++i) ischange = oldStyles[i] != line.styles[i];
  1.1381 +        if (ischange) regLineChange(cm, doc.frontier, "text");
  1.1382 +        line.stateAfter = copyState(doc.mode, state);
  1.1383 +      } else {
  1.1384 +        processLine(cm, line.text, state);
  1.1385 +        line.stateAfter = doc.frontier % 5 == 0 ? copyState(doc.mode, state) : null;
  1.1386 +      }
  1.1387 +      ++doc.frontier;
  1.1388 +      if (+new Date > end) {
  1.1389 +        startWorker(cm, cm.options.workDelay);
  1.1390 +        return true;
  1.1391 +      }
  1.1392 +    });
  1.1393 +    });
  1.1394 +  }
  1.1395 +
  1.1396 +  // Finds the line to start with when starting a parse. Tries to
  1.1397 +  // find a line with a stateAfter, so that it can start with a
  1.1398 +  // valid state. If that fails, it returns the line with the
  1.1399 +  // smallest indentation, which tends to need the least context to
  1.1400 +  // parse correctly.
  1.1401 +  function findStartLine(cm, n, precise) {
  1.1402 +    var minindent, minline, doc = cm.doc;
  1.1403 +    var lim = precise ? -1 : n - (cm.doc.mode.innerMode ? 1000 : 100);
  1.1404 +    for (var search = n; search > lim; --search) {
  1.1405 +      if (search <= doc.first) return doc.first;
  1.1406 +      var line = getLine(doc, search - 1);
  1.1407 +      if (line.stateAfter && (!precise || search <= doc.frontier)) return search;
  1.1408 +      var indented = countColumn(line.text, null, cm.options.tabSize);
  1.1409 +      if (minline == null || minindent > indented) {
  1.1410 +        minline = search - 1;
  1.1411 +        minindent = indented;
  1.1412 +      }
  1.1413 +    }
  1.1414 +    return minline;
  1.1415 +  }
  1.1416 +
  1.1417 +  function getStateBefore(cm, n, precise) {
  1.1418 +    var doc = cm.doc, display = cm.display;
  1.1419 +    if (!doc.mode.startState) return true;
  1.1420 +    var pos = findStartLine(cm, n, precise), state = pos > doc.first && getLine(doc, pos-1).stateAfter;
  1.1421 +    if (!state) state = startState(doc.mode);
  1.1422 +    else state = copyState(doc.mode, state);
  1.1423 +    doc.iter(pos, n, function(line) {
  1.1424 +      processLine(cm, line.text, state);
  1.1425 +      var save = pos == n - 1 || pos % 5 == 0 || pos >= display.viewFrom && pos < display.viewTo;
  1.1426 +      line.stateAfter = save ? copyState(doc.mode, state) : null;
  1.1427 +      ++pos;
  1.1428 +    });
  1.1429 +    if (precise) doc.frontier = pos;
  1.1430 +    return state;
  1.1431 +  }
  1.1432 +
  1.1433 +  // POSITION MEASUREMENT
  1.1434 +
  1.1435 +  function paddingTop(display) {return display.lineSpace.offsetTop;}
  1.1436 +  function paddingVert(display) {return display.mover.offsetHeight - display.lineSpace.offsetHeight;}
  1.1437 +  function paddingH(display) {
  1.1438 +    if (display.cachedPaddingH) return display.cachedPaddingH;
  1.1439 +    var e = removeChildrenAndAdd(display.measure, elt("pre", "x"));
  1.1440 +    var style = window.getComputedStyle ? window.getComputedStyle(e) : e.currentStyle;
  1.1441 +    return display.cachedPaddingH = {left: parseInt(style.paddingLeft),
  1.1442 +                                     right: parseInt(style.paddingRight)};
  1.1443 +  }
  1.1444 +
  1.1445 +  // Ensure the lineView.wrapping.heights array is populated. This is
  1.1446 +  // an array of bottom offsets for the lines that make up a drawn
  1.1447 +  // line. When lineWrapping is on, there might be more than one
  1.1448 +  // height.
  1.1449 +  function ensureLineHeights(cm, lineView, rect) {
  1.1450 +    var wrapping = cm.options.lineWrapping;
  1.1451 +    var curWidth = wrapping && cm.display.scroller.clientWidth;
  1.1452 +    if (!lineView.measure.heights || wrapping && lineView.measure.width != curWidth) {
  1.1453 +      var heights = lineView.measure.heights = [];
  1.1454 +      if (wrapping) {
  1.1455 +        lineView.measure.width = curWidth;
  1.1456 +        var rects = lineView.text.firstChild.getClientRects();
  1.1457 +        for (var i = 0; i < rects.length - 1; i++) {
  1.1458 +          var cur = rects[i], next = rects[i + 1];
  1.1459 +          if (Math.abs(cur.bottom - next.bottom) > 2)
  1.1460 +            heights.push((cur.bottom + next.top) / 2 - rect.top);
  1.1461 +        }
  1.1462 +      }
  1.1463 +      heights.push(rect.bottom - rect.top);
  1.1464 +    }
  1.1465 +  }
  1.1466 +
  1.1467 +  // Find a line map (mapping character offsets to text nodes) and a
  1.1468 +  // measurement cache for the given line number. (A line view might
  1.1469 +  // contain multiple lines when collapsed ranges are present.)
  1.1470 +  function mapFromLineView(lineView, line, lineN) {
  1.1471 +    if (lineView.line == line)
  1.1472 +      return {map: lineView.measure.map, cache: lineView.measure.cache};
  1.1473 +    for (var i = 0; i < lineView.rest.length; i++)
  1.1474 +      if (lineView.rest[i] == line)
  1.1475 +        return {map: lineView.measure.maps[i], cache: lineView.measure.caches[i]};
  1.1476 +    for (var i = 0; i < lineView.rest.length; i++)
  1.1477 +      if (lineNo(lineView.rest[i]) > lineN)
  1.1478 +        return {map: lineView.measure.maps[i], cache: lineView.measure.caches[i], before: true};
  1.1479 +  }
  1.1480 +
  1.1481 +  // Render a line into the hidden node display.externalMeasured. Used
  1.1482 +  // when measurement is needed for a line that's not in the viewport.
  1.1483 +  function updateExternalMeasurement(cm, line) {
  1.1484 +    line = visualLine(line);
  1.1485 +    var lineN = lineNo(line);
  1.1486 +    var view = cm.display.externalMeasured = new LineView(cm.doc, line, lineN);
  1.1487 +    view.lineN = lineN;
  1.1488 +    var built = view.built = buildLineContent(cm, view);
  1.1489 +    view.text = built.pre;
  1.1490 +    removeChildrenAndAdd(cm.display.lineMeasure, built.pre);
  1.1491 +    return view;
  1.1492 +  }
  1.1493 +
  1.1494 +  // Get a {top, bottom, left, right} box (in line-local coordinates)
  1.1495 +  // for a given character.
  1.1496 +  function measureChar(cm, line, ch, bias) {
  1.1497 +    return measureCharPrepared(cm, prepareMeasureForLine(cm, line), ch, bias);
  1.1498 +  }
  1.1499 +
  1.1500 +  // Find a line view that corresponds to the given line number.
  1.1501 +  function findViewForLine(cm, lineN) {
  1.1502 +    if (lineN >= cm.display.viewFrom && lineN < cm.display.viewTo)
  1.1503 +      return cm.display.view[findViewIndex(cm, lineN)];
  1.1504 +    var ext = cm.display.externalMeasured;
  1.1505 +    if (ext && lineN >= ext.lineN && lineN < ext.lineN + ext.size)
  1.1506 +      return ext;
  1.1507 +  }
  1.1508 +
  1.1509 +  // Measurement can be split in two steps, the set-up work that
  1.1510 +  // applies to the whole line, and the measurement of the actual
  1.1511 +  // character. Functions like coordsChar, that need to do a lot of
  1.1512 +  // measurements in a row, can thus ensure that the set-up work is
  1.1513 +  // only done once.
  1.1514 +  function prepareMeasureForLine(cm, line) {
  1.1515 +    var lineN = lineNo(line);
  1.1516 +    var view = findViewForLine(cm, lineN);
  1.1517 +    if (view && !view.text)
  1.1518 +      view = null;
  1.1519 +    else if (view && view.changes)
  1.1520 +      updateLineForChanges(cm, view, lineN, getDimensions(cm));
  1.1521 +    if (!view)
  1.1522 +      view = updateExternalMeasurement(cm, line);
  1.1523 +
  1.1524 +    var info = mapFromLineView(view, line, lineN);
  1.1525 +    return {
  1.1526 +      line: line, view: view, rect: null,
  1.1527 +      map: info.map, cache: info.cache, before: info.before,
  1.1528 +      hasHeights: false
  1.1529 +    };
  1.1530 +  }
  1.1531 +
  1.1532 +  // Given a prepared measurement object, measures the position of an
  1.1533 +  // actual character (or fetches it from the cache).
  1.1534 +  function measureCharPrepared(cm, prepared, ch, bias) {
  1.1535 +    if (prepared.before) ch = -1;
  1.1536 +    var key = ch + (bias || ""), found;
  1.1537 +    if (prepared.cache.hasOwnProperty(key)) {
  1.1538 +      found = prepared.cache[key];
  1.1539 +    } else {
  1.1540 +      if (!prepared.rect)
  1.1541 +        prepared.rect = prepared.view.text.getBoundingClientRect();
  1.1542 +      if (!prepared.hasHeights) {
  1.1543 +        ensureLineHeights(cm, prepared.view, prepared.rect);
  1.1544 +        prepared.hasHeights = true;
  1.1545 +      }
  1.1546 +      found = measureCharInner(cm, prepared, ch, bias);
  1.1547 +      if (!found.bogus) prepared.cache[key] = found;
  1.1548 +    }
  1.1549 +    return {left: found.left, right: found.right, top: found.top, bottom: found.bottom};
  1.1550 +  }
  1.1551 +
  1.1552 +  var nullRect = {left: 0, right: 0, top: 0, bottom: 0};
  1.1553 +
  1.1554 +  function measureCharInner(cm, prepared, ch, bias) {
  1.1555 +    var map = prepared.map;
  1.1556 +
  1.1557 +    var node, start, end, collapse;
  1.1558 +    // First, search the line map for the text node corresponding to,
  1.1559 +    // or closest to, the target character.
  1.1560 +    for (var i = 0; i < map.length; i += 3) {
  1.1561 +      var mStart = map[i], mEnd = map[i + 1];
  1.1562 +      if (ch < mStart) {
  1.1563 +        start = 0; end = 1;
  1.1564 +        collapse = "left";
  1.1565 +      } else if (ch < mEnd) {
  1.1566 +        start = ch - mStart;
  1.1567 +        end = start + 1;
  1.1568 +      } else if (i == map.length - 3 || ch == mEnd && map[i + 3] > ch) {
  1.1569 +        end = mEnd - mStart;
  1.1570 +        start = end - 1;
  1.1571 +        if (ch >= mEnd) collapse = "right";
  1.1572 +      }
  1.1573 +      if (start != null) {
  1.1574 +        node = map[i + 2];
  1.1575 +        if (mStart == mEnd && bias == (node.insertLeft ? "left" : "right"))
  1.1576 +          collapse = bias;
  1.1577 +        if (bias == "left" && start == 0)
  1.1578 +          while (i && map[i - 2] == map[i - 3] && map[i - 1].insertLeft) {
  1.1579 +            node = map[(i -= 3) + 2];
  1.1580 +            collapse = "left";
  1.1581 +          }
  1.1582 +        if (bias == "right" && start == mEnd - mStart)
  1.1583 +          while (i < map.length - 3 && map[i + 3] == map[i + 4] && !map[i + 5].insertLeft) {
  1.1584 +            node = map[(i += 3) + 2];
  1.1585 +            collapse = "right";
  1.1586 +          }
  1.1587 +        break;
  1.1588 +      }
  1.1589 +    }
  1.1590 +
  1.1591 +    var rect;
  1.1592 +    if (node.nodeType == 3) { // If it is a text node, use a range to retrieve the coordinates.
  1.1593 +      while (start && isExtendingChar(prepared.line.text.charAt(mStart + start))) --start;
  1.1594 +      while (mStart + end < mEnd && isExtendingChar(prepared.line.text.charAt(mStart + end))) ++end;
  1.1595 +      if (ie_upto8 && start == 0 && end == mEnd - mStart) {
  1.1596 +        rect = node.parentNode.getBoundingClientRect();
  1.1597 +      } else if (ie && cm.options.lineWrapping) {
  1.1598 +        var rects = range(node, start, end).getClientRects();
  1.1599 +        if (rects.length)
  1.1600 +          rect = rects[bias == "right" ? rects.length - 1 : 0];
  1.1601 +        else
  1.1602 +          rect = nullRect;
  1.1603 +      } else {
  1.1604 +        rect = range(node, start, end).getBoundingClientRect();
  1.1605 +      }
  1.1606 +    } else { // If it is a widget, simply get the box for the whole widget.
  1.1607 +      if (start > 0) collapse = bias = "right";
  1.1608 +      var rects;
  1.1609 +      if (cm.options.lineWrapping && (rects = node.getClientRects()).length > 1)
  1.1610 +        rect = rects[bias == "right" ? rects.length - 1 : 0];
  1.1611 +      else
  1.1612 +        rect = node.getBoundingClientRect();
  1.1613 +    }
  1.1614 +    if (ie_upto8 && !start && (!rect || !rect.left && !rect.right)) {
  1.1615 +      var rSpan = node.parentNode.getClientRects()[0];
  1.1616 +      if (rSpan)
  1.1617 +        rect = {left: rSpan.left, right: rSpan.left + charWidth(cm.display), top: rSpan.top, bottom: rSpan.bottom};
  1.1618 +      else
  1.1619 +        rect = nullRect;
  1.1620 +    }
  1.1621 +
  1.1622 +    var top, bot = (rect.bottom + rect.top) / 2 - prepared.rect.top;
  1.1623 +    var heights = prepared.view.measure.heights;
  1.1624 +    for (var i = 0; i < heights.length - 1; i++)
  1.1625 +      if (bot < heights[i]) break;
  1.1626 +    top = i ? heights[i - 1] : 0; bot = heights[i];
  1.1627 +    var result = {left: (collapse == "right" ? rect.right : rect.left) - prepared.rect.left,
  1.1628 +                  right: (collapse == "left" ? rect.left : rect.right) - prepared.rect.left,
  1.1629 +                  top: top, bottom: bot};
  1.1630 +    if (!rect.left && !rect.right) result.bogus = true;
  1.1631 +    return result;
  1.1632 +  }
  1.1633 +
  1.1634 +  function clearLineMeasurementCacheFor(lineView) {
  1.1635 +    if (lineView.measure) {
  1.1636 +      lineView.measure.cache = {};
  1.1637 +      lineView.measure.heights = null;
  1.1638 +      if (lineView.rest) for (var i = 0; i < lineView.rest.length; i++)
  1.1639 +        lineView.measure.caches[i] = {};
  1.1640 +    }
  1.1641 +  }
  1.1642 +
  1.1643 +  function clearLineMeasurementCache(cm) {
  1.1644 +    cm.display.externalMeasure = null;
  1.1645 +    removeChildren(cm.display.lineMeasure);
  1.1646 +    for (var i = 0; i < cm.display.view.length; i++)
  1.1647 +      clearLineMeasurementCacheFor(cm.display.view[i]);
  1.1648 +  }
  1.1649 +
  1.1650 +  function clearCaches(cm) {
  1.1651 +    clearLineMeasurementCache(cm);
  1.1652 +    cm.display.cachedCharWidth = cm.display.cachedTextHeight = cm.display.cachedPaddingH = null;
  1.1653 +    if (!cm.options.lineWrapping) cm.display.maxLineChanged = true;
  1.1654 +    cm.display.lineNumChars = null;
  1.1655 +  }
  1.1656 +
  1.1657 +  function pageScrollX() { return window.pageXOffset || (document.documentElement || document.body).scrollLeft; }
  1.1658 +  function pageScrollY() { return window.pageYOffset || (document.documentElement || document.body).scrollTop; }
  1.1659 +
  1.1660 +  // Converts a {top, bottom, left, right} box from line-local
  1.1661 +  // coordinates into another coordinate system. Context may be one of
  1.1662 +  // "line", "div" (display.lineDiv), "local"/null (editor), or "page".
  1.1663 +  function intoCoordSystem(cm, lineObj, rect, context) {
  1.1664 +    if (lineObj.widgets) for (var i = 0; i < lineObj.widgets.length; ++i) if (lineObj.widgets[i].above) {
  1.1665 +      var size = widgetHeight(lineObj.widgets[i]);
  1.1666 +      rect.top += size; rect.bottom += size;
  1.1667 +    }
  1.1668 +    if (context == "line") return rect;
  1.1669 +    if (!context) context = "local";
  1.1670 +    var yOff = heightAtLine(lineObj);
  1.1671 +    if (context == "local") yOff += paddingTop(cm.display);
  1.1672 +    else yOff -= cm.display.viewOffset;
  1.1673 +    if (context == "page" || context == "window") {
  1.1674 +      var lOff = cm.display.lineSpace.getBoundingClientRect();
  1.1675 +      yOff += lOff.top + (context == "window" ? 0 : pageScrollY());
  1.1676 +      var xOff = lOff.left + (context == "window" ? 0 : pageScrollX());
  1.1677 +      rect.left += xOff; rect.right += xOff;
  1.1678 +    }
  1.1679 +    rect.top += yOff; rect.bottom += yOff;
  1.1680 +    return rect;
  1.1681 +  }
  1.1682 +
  1.1683 +  // Coverts a box from "div" coords to another coordinate system.
  1.1684 +  // Context may be "window", "page", "div", or "local"/null.
  1.1685 +  function fromCoordSystem(cm, coords, context) {
  1.1686 +    if (context == "div") return coords;
  1.1687 +    var left = coords.left, top = coords.top;
  1.1688 +    // First move into "page" coordinate system
  1.1689 +    if (context == "page") {
  1.1690 +      left -= pageScrollX();
  1.1691 +      top -= pageScrollY();
  1.1692 +    } else if (context == "local" || !context) {
  1.1693 +      var localBox = cm.display.sizer.getBoundingClientRect();
  1.1694 +      left += localBox.left;
  1.1695 +      top += localBox.top;
  1.1696 +    }
  1.1697 +
  1.1698 +    var lineSpaceBox = cm.display.lineSpace.getBoundingClientRect();
  1.1699 +    return {left: left - lineSpaceBox.left, top: top - lineSpaceBox.top};
  1.1700 +  }
  1.1701 +
  1.1702 +  function charCoords(cm, pos, context, lineObj, bias) {
  1.1703 +    if (!lineObj) lineObj = getLine(cm.doc, pos.line);
  1.1704 +    return intoCoordSystem(cm, lineObj, measureChar(cm, lineObj, pos.ch, bias), context);
  1.1705 +  }
  1.1706 +
  1.1707 +  // Returns a box for a given cursor position, which may have an
  1.1708 +  // 'other' property containing the position of the secondary cursor
  1.1709 +  // on a bidi boundary.
  1.1710 +  function cursorCoords(cm, pos, context, lineObj, preparedMeasure) {
  1.1711 +    lineObj = lineObj || getLine(cm.doc, pos.line);
  1.1712 +    if (!preparedMeasure) preparedMeasure = prepareMeasureForLine(cm, lineObj);
  1.1713 +    function get(ch, right) {
  1.1714 +      var m = measureCharPrepared(cm, preparedMeasure, ch, right ? "right" : "left");
  1.1715 +      if (right) m.left = m.right; else m.right = m.left;
  1.1716 +      return intoCoordSystem(cm, lineObj, m, context);
  1.1717 +    }
  1.1718 +    function getBidi(ch, partPos) {
  1.1719 +      var part = order[partPos], right = part.level % 2;
  1.1720 +      if (ch == bidiLeft(part) && partPos && part.level < order[partPos - 1].level) {
  1.1721 +        part = order[--partPos];
  1.1722 +        ch = bidiRight(part) - (part.level % 2 ? 0 : 1);
  1.1723 +        right = true;
  1.1724 +      } else if (ch == bidiRight(part) && partPos < order.length - 1 && part.level < order[partPos + 1].level) {
  1.1725 +        part = order[++partPos];
  1.1726 +        ch = bidiLeft(part) - part.level % 2;
  1.1727 +        right = false;
  1.1728 +      }
  1.1729 +      if (right && ch == part.to && ch > part.from) return get(ch - 1);
  1.1730 +      return get(ch, right);
  1.1731 +    }
  1.1732 +    var order = getOrder(lineObj), ch = pos.ch;
  1.1733 +    if (!order) return get(ch);
  1.1734 +    var partPos = getBidiPartAt(order, ch);
  1.1735 +    var val = getBidi(ch, partPos);
  1.1736 +    if (bidiOther != null) val.other = getBidi(ch, bidiOther);
  1.1737 +    return val;
  1.1738 +  }
  1.1739 +
  1.1740 +  // Used to cheaply estimate the coordinates for a position. Used for
  1.1741 +  // intermediate scroll updates.
  1.1742 +  function estimateCoords(cm, pos) {
  1.1743 +    var left = 0, pos = clipPos(cm.doc, pos);
  1.1744 +    if (!cm.options.lineWrapping) left = charWidth(cm.display) * pos.ch;
  1.1745 +    var lineObj = getLine(cm.doc, pos.line);
  1.1746 +    var top = heightAtLine(lineObj) + paddingTop(cm.display);
  1.1747 +    return {left: left, right: left, top: top, bottom: top + lineObj.height};
  1.1748 +  }
  1.1749 +
  1.1750 +  // Positions returned by coordsChar contain some extra information.
  1.1751 +  // xRel is the relative x position of the input coordinates compared
  1.1752 +  // to the found position (so xRel > 0 means the coordinates are to
  1.1753 +  // the right of the character position, for example). When outside
  1.1754 +  // is true, that means the coordinates lie outside the line's
  1.1755 +  // vertical range.
  1.1756 +  function PosWithInfo(line, ch, outside, xRel) {
  1.1757 +    var pos = Pos(line, ch);
  1.1758 +    pos.xRel = xRel;
  1.1759 +    if (outside) pos.outside = true;
  1.1760 +    return pos;
  1.1761 +  }
  1.1762 +
  1.1763 +  // Compute the character position closest to the given coordinates.
  1.1764 +  // Input must be lineSpace-local ("div" coordinate system).
  1.1765 +  function coordsChar(cm, x, y) {
  1.1766 +    var doc = cm.doc;
  1.1767 +    y += cm.display.viewOffset;
  1.1768 +    if (y < 0) return PosWithInfo(doc.first, 0, true, -1);
  1.1769 +    var lineN = lineAtHeight(doc, y), last = doc.first + doc.size - 1;
  1.1770 +    if (lineN > last)
  1.1771 +      return PosWithInfo(doc.first + doc.size - 1, getLine(doc, last).text.length, true, 1);
  1.1772 +    if (x < 0) x = 0;
  1.1773 +
  1.1774 +    var lineObj = getLine(doc, lineN);
  1.1775 +    for (;;) {
  1.1776 +      var found = coordsCharInner(cm, lineObj, lineN, x, y);
  1.1777 +      var merged = collapsedSpanAtEnd(lineObj);
  1.1778 +      var mergedPos = merged && merged.find(0, true);
  1.1779 +      if (merged && (found.ch > mergedPos.from.ch || found.ch == mergedPos.from.ch && found.xRel > 0))
  1.1780 +        lineN = lineNo(lineObj = mergedPos.to.line);
  1.1781 +      else
  1.1782 +        return found;
  1.1783 +    }
  1.1784 +  }
  1.1785 +
  1.1786 +  function coordsCharInner(cm, lineObj, lineNo, x, y) {
  1.1787 +    var innerOff = y - heightAtLine(lineObj);
  1.1788 +    var wrongLine = false, adjust = 2 * cm.display.wrapper.clientWidth;
  1.1789 +    var preparedMeasure = prepareMeasureForLine(cm, lineObj);
  1.1790 +
  1.1791 +    function getX(ch) {
  1.1792 +      var sp = cursorCoords(cm, Pos(lineNo, ch), "line", lineObj, preparedMeasure);
  1.1793 +      wrongLine = true;
  1.1794 +      if (innerOff > sp.bottom) return sp.left - adjust;
  1.1795 +      else if (innerOff < sp.top) return sp.left + adjust;
  1.1796 +      else wrongLine = false;
  1.1797 +      return sp.left;
  1.1798 +    }
  1.1799 +
  1.1800 +    var bidi = getOrder(lineObj), dist = lineObj.text.length;
  1.1801 +    var from = lineLeft(lineObj), to = lineRight(lineObj);
  1.1802 +    var fromX = getX(from), fromOutside = wrongLine, toX = getX(to), toOutside = wrongLine;
  1.1803 +
  1.1804 +    if (x > toX) return PosWithInfo(lineNo, to, toOutside, 1);
  1.1805 +    // Do a binary search between these bounds.
  1.1806 +    for (;;) {
  1.1807 +      if (bidi ? to == from || to == moveVisually(lineObj, from, 1) : to - from <= 1) {
  1.1808 +        var ch = x < fromX || x - fromX <= toX - x ? from : to;
  1.1809 +        var xDiff = x - (ch == from ? fromX : toX);
  1.1810 +        while (isExtendingChar(lineObj.text.charAt(ch))) ++ch;
  1.1811 +        var pos = PosWithInfo(lineNo, ch, ch == from ? fromOutside : toOutside,
  1.1812 +                              xDiff < -1 ? -1 : xDiff > 1 ? 1 : 0);
  1.1813 +        return pos;
  1.1814 +      }
  1.1815 +      var step = Math.ceil(dist / 2), middle = from + step;
  1.1816 +      if (bidi) {
  1.1817 +        middle = from;
  1.1818 +        for (var i = 0; i < step; ++i) middle = moveVisually(lineObj, middle, 1);
  1.1819 +      }
  1.1820 +      var middleX = getX(middle);
  1.1821 +      if (middleX > x) {to = middle; toX = middleX; if (toOutside = wrongLine) toX += 1000; dist = step;}
  1.1822 +      else {from = middle; fromX = middleX; fromOutside = wrongLine; dist -= step;}
  1.1823 +    }
  1.1824 +  }
  1.1825 +
  1.1826 +  var measureText;
  1.1827 +  // Compute the default text height.
  1.1828 +  function textHeight(display) {
  1.1829 +    if (display.cachedTextHeight != null) return display.cachedTextHeight;
  1.1830 +    if (measureText == null) {
  1.1831 +      measureText = elt("pre");
  1.1832 +      // Measure a bunch of lines, for browsers that compute
  1.1833 +      // fractional heights.
  1.1834 +      for (var i = 0; i < 49; ++i) {
  1.1835 +        measureText.appendChild(document.createTextNode("x"));
  1.1836 +        measureText.appendChild(elt("br"));
  1.1837 +      }
  1.1838 +      measureText.appendChild(document.createTextNode("x"));
  1.1839 +    }
  1.1840 +    removeChildrenAndAdd(display.measure, measureText);
  1.1841 +    var height = measureText.offsetHeight / 50;
  1.1842 +    if (height > 3) display.cachedTextHeight = height;
  1.1843 +    removeChildren(display.measure);
  1.1844 +    return height || 1;
  1.1845 +  }
  1.1846 +
  1.1847 +  // Compute the default character width.
  1.1848 +  function charWidth(display) {
  1.1849 +    if (display.cachedCharWidth != null) return display.cachedCharWidth;
  1.1850 +    var anchor = elt("span", "xxxxxxxxxx");
  1.1851 +    var pre = elt("pre", [anchor]);
  1.1852 +    removeChildrenAndAdd(display.measure, pre);
  1.1853 +    var rect = anchor.getBoundingClientRect(), width = (rect.right - rect.left) / 10;
  1.1854 +    if (width > 2) display.cachedCharWidth = width;
  1.1855 +    return width || 10;
  1.1856 +  }
  1.1857 +
  1.1858 +  // OPERATIONS
  1.1859 +
  1.1860 +  // Operations are used to wrap a series of changes to the editor
  1.1861 +  // state in such a way that each change won't have to update the
  1.1862 +  // cursor and display (which would be awkward, slow, and
  1.1863 +  // error-prone). Instead, display updates are batched and then all
  1.1864 +  // combined and executed at once.
  1.1865 +
  1.1866 +  var nextOpId = 0;
  1.1867 +  // Start a new operation.
  1.1868 +  function startOperation(cm) {
  1.1869 +    cm.curOp = {
  1.1870 +      viewChanged: false,      // Flag that indicates that lines might need to be redrawn
  1.1871 +      startHeight: cm.doc.height, // Used to detect need to update scrollbar
  1.1872 +      forceUpdate: false,      // Used to force a redraw
  1.1873 +      updateInput: null,       // Whether to reset the input textarea
  1.1874 +      typing: false,           // Whether this reset should be careful to leave existing text (for compositing)
  1.1875 +      changeObjs: null,        // Accumulated changes, for firing change events
  1.1876 +      cursorActivity: false,   // Whether to fire a cursorActivity event
  1.1877 +      selectionChanged: false, // Whether the selection needs to be redrawn
  1.1878 +      updateMaxLine: false,    // Set when the widest line needs to be determined anew
  1.1879 +      scrollLeft: null, scrollTop: null, // Intermediate scroll position, not pushed to DOM yet
  1.1880 +      scrollToPos: null,       // Used to scroll to a specific position
  1.1881 +      id: ++nextOpId           // Unique ID
  1.1882 +    };
  1.1883 +    if (!delayedCallbackDepth++) delayedCallbacks = [];
  1.1884 +  }
  1.1885 +
  1.1886 +  // Finish an operation, updating the display and signalling delayed events
  1.1887 +  function endOperation(cm) {
  1.1888 +    var op = cm.curOp, doc = cm.doc, display = cm.display;
  1.1889 +    cm.curOp = null;
  1.1890 +
  1.1891 +    if (op.updateMaxLine) findMaxLine(cm);
  1.1892 +
  1.1893 +    // If it looks like an update might be needed, call updateDisplay
  1.1894 +    if (op.viewChanged || op.forceUpdate || op.scrollTop != null ||
  1.1895 +        op.scrollToPos && (op.scrollToPos.from.line < display.viewFrom ||
  1.1896 +                           op.scrollToPos.to.line >= display.viewTo) ||
  1.1897 +        display.maxLineChanged && cm.options.lineWrapping) {
  1.1898 +      var updated = updateDisplay(cm, {top: op.scrollTop, ensure: op.scrollToPos}, op.forceUpdate);
  1.1899 +      if (cm.display.scroller.offsetHeight) cm.doc.scrollTop = cm.display.scroller.scrollTop;
  1.1900 +    }
  1.1901 +    // If no update was run, but the selection changed, redraw that.
  1.1902 +    if (!updated && op.selectionChanged) updateSelection(cm);
  1.1903 +    if (!updated && op.startHeight != cm.doc.height) updateScrollbars(cm);
  1.1904 +
  1.1905 +    // Propagate the scroll position to the actual DOM scroller
  1.1906 +    if (op.scrollTop != null && display.scroller.scrollTop != op.scrollTop) {
  1.1907 +      var top = Math.max(0, Math.min(display.scroller.scrollHeight - display.scroller.clientHeight, op.scrollTop));
  1.1908 +      display.scroller.scrollTop = display.scrollbarV.scrollTop = doc.scrollTop = top;
  1.1909 +    }
  1.1910 +    if (op.scrollLeft != null && display.scroller.scrollLeft != op.scrollLeft) {
  1.1911 +      var left = Math.max(0, Math.min(display.scroller.scrollWidth - display.scroller.clientWidth, op.scrollLeft));
  1.1912 +      display.scroller.scrollLeft = display.scrollbarH.scrollLeft = doc.scrollLeft = left;
  1.1913 +      alignHorizontally(cm);
  1.1914 +    }
  1.1915 +    // If we need to scroll a specific position into view, do so.
  1.1916 +    if (op.scrollToPos) {
  1.1917 +      var coords = scrollPosIntoView(cm, clipPos(cm.doc, op.scrollToPos.from),
  1.1918 +                                     clipPos(cm.doc, op.scrollToPos.to), op.scrollToPos.margin);
  1.1919 +      if (op.scrollToPos.isCursor && cm.state.focused) maybeScrollWindow(cm, coords);
  1.1920 +    }
  1.1921 +
  1.1922 +    if (op.selectionChanged) restartBlink(cm);
  1.1923 +
  1.1924 +    if (cm.state.focused && op.updateInput)
  1.1925 +      resetInput(cm, op.typing);
  1.1926 +
  1.1927 +    // Fire events for markers that are hidden/unidden by editing or
  1.1928 +    // undoing
  1.1929 +    var hidden = op.maybeHiddenMarkers, unhidden = op.maybeUnhiddenMarkers;
  1.1930 +    if (hidden) for (var i = 0; i < hidden.length; ++i)
  1.1931 +      if (!hidden[i].lines.length) signal(hidden[i], "hide");
  1.1932 +    if (unhidden) for (var i = 0; i < unhidden.length; ++i)
  1.1933 +      if (unhidden[i].lines.length) signal(unhidden[i], "unhide");
  1.1934 +
  1.1935 +    var delayed;
  1.1936 +    if (!--delayedCallbackDepth) {
  1.1937 +      delayed = delayedCallbacks;
  1.1938 +      delayedCallbacks = null;
  1.1939 +    }
  1.1940 +    // Fire change events, and delayed event handlers
  1.1941 +    if (op.changeObjs) {
  1.1942 +      for (var i = 0; i < op.changeObjs.length; i++)
  1.1943 +        signal(cm, "change", cm, op.changeObjs[i]);
  1.1944 +      signal(cm, "changes", cm, op.changeObjs);
  1.1945 +    }
  1.1946 +    if (op.cursorActivity) signal(cm, "cursorActivity", cm);
  1.1947 +    if (delayed) for (var i = 0; i < delayed.length; ++i) delayed[i]();
  1.1948 +  }
  1.1949 +
  1.1950 +  // Run the given function in an operation
  1.1951 +  function runInOp(cm, f) {
  1.1952 +    if (cm.curOp) return f();
  1.1953 +    startOperation(cm);
  1.1954 +    try { return f(); }
  1.1955 +    finally { endOperation(cm); }
  1.1956 +  }
  1.1957 +  // Wraps a function in an operation. Returns the wrapped function.
  1.1958 +  function operation(cm, f) {
  1.1959 +    return function() {
  1.1960 +      if (cm.curOp) return f.apply(cm, arguments);
  1.1961 +      startOperation(cm);
  1.1962 +      try { return f.apply(cm, arguments); }
  1.1963 +      finally { endOperation(cm); }
  1.1964 +    };
  1.1965 +  }
  1.1966 +  // Used to add methods to editor and doc instances, wrapping them in
  1.1967 +  // operations.
  1.1968 +  function methodOp(f) {
  1.1969 +    return function() {
  1.1970 +      if (this.curOp) return f.apply(this, arguments);
  1.1971 +      startOperation(this);
  1.1972 +      try { return f.apply(this, arguments); }
  1.1973 +      finally { endOperation(this); }
  1.1974 +    };
  1.1975 +  }
  1.1976 +  function docMethodOp(f) {
  1.1977 +    return function() {
  1.1978 +      var cm = this.cm;
  1.1979 +      if (!cm || cm.curOp) return f.apply(this, arguments);
  1.1980 +      startOperation(cm);
  1.1981 +      try { return f.apply(this, arguments); }
  1.1982 +      finally { endOperation(cm); }
  1.1983 +    };
  1.1984 +  }
  1.1985 +
  1.1986 +  // VIEW TRACKING
  1.1987 +
  1.1988 +  // These objects are used to represent the visible (currently drawn)
  1.1989 +  // part of the document. A LineView may correspond to multiple
  1.1990 +  // logical lines, if those are connected by collapsed ranges.
  1.1991 +  function LineView(doc, line, lineN) {
  1.1992 +    // The starting line
  1.1993 +    this.line = line;
  1.1994 +    // Continuing lines, if any
  1.1995 +    this.rest = visualLineContinued(line);
  1.1996 +    // Number of logical lines in this visual line
  1.1997 +    this.size = this.rest ? lineNo(lst(this.rest)) - lineN + 1 : 1;
  1.1998 +    this.node = this.text = null;
  1.1999 +    this.hidden = lineIsHidden(doc, line);
  1.2000 +  }
  1.2001 +
  1.2002 +  // Create a range of LineView objects for the given lines.
  1.2003 +  function buildViewArray(cm, from, to) {
  1.2004 +    var array = [], nextPos;
  1.2005 +    for (var pos = from; pos < to; pos = nextPos) {
  1.2006 +      var view = new LineView(cm.doc, getLine(cm.doc, pos), pos);
  1.2007 +      nextPos = pos + view.size;
  1.2008 +      array.push(view);
  1.2009 +    }
  1.2010 +    return array;
  1.2011 +  }
  1.2012 +
  1.2013 +  // Updates the display.view data structure for a given change to the
  1.2014 +  // document. From and to are in pre-change coordinates. Lendiff is
  1.2015 +  // the amount of lines added or subtracted by the change. This is
  1.2016 +  // used for changes that span multiple lines, or change the way
  1.2017 +  // lines are divided into visual lines. regLineChange (below)
  1.2018 +  // registers single-line changes.
  1.2019 +  function regChange(cm, from, to, lendiff) {
  1.2020 +    if (from == null) from = cm.doc.first;
  1.2021 +    if (to == null) to = cm.doc.first + cm.doc.size;
  1.2022 +    if (!lendiff) lendiff = 0;
  1.2023 +
  1.2024 +    var display = cm.display;
  1.2025 +    if (lendiff && to < display.viewTo &&
  1.2026 +        (display.updateLineNumbers == null || display.updateLineNumbers > from))
  1.2027 +      display.updateLineNumbers = from;
  1.2028 +
  1.2029 +    cm.curOp.viewChanged = true;
  1.2030 +
  1.2031 +    if (from >= display.viewTo) { // Change after
  1.2032 +      if (sawCollapsedSpans && visualLineNo(cm.doc, from) < display.viewTo)
  1.2033 +        resetView(cm);
  1.2034 +    } else if (to <= display.viewFrom) { // Change before
  1.2035 +      if (sawCollapsedSpans && visualLineEndNo(cm.doc, to + lendiff) > display.viewFrom) {
  1.2036 +        resetView(cm);
  1.2037 +      } else {
  1.2038 +        display.viewFrom += lendiff;
  1.2039 +        display.viewTo += lendiff;
  1.2040 +      }
  1.2041 +    } else if (from <= display.viewFrom && to >= display.viewTo) { // Full overlap
  1.2042 +      resetView(cm);
  1.2043 +    } else if (from <= display.viewFrom) { // Top overlap
  1.2044 +      var cut = viewCuttingPoint(cm, to, to + lendiff, 1);
  1.2045 +      if (cut) {
  1.2046 +        display.view = display.view.slice(cut.index);
  1.2047 +        display.viewFrom = cut.lineN;
  1.2048 +        display.viewTo += lendiff;
  1.2049 +      } else {
  1.2050 +        resetView(cm);
  1.2051 +      }
  1.2052 +    } else if (to >= display.viewTo) { // Bottom overlap
  1.2053 +      var cut = viewCuttingPoint(cm, from, from, -1);
  1.2054 +      if (cut) {
  1.2055 +        display.view = display.view.slice(0, cut.index);
  1.2056 +        display.viewTo = cut.lineN;
  1.2057 +      } else {
  1.2058 +        resetView(cm);
  1.2059 +      }
  1.2060 +    } else { // Gap in the middle
  1.2061 +      var cutTop = viewCuttingPoint(cm, from, from, -1);
  1.2062 +      var cutBot = viewCuttingPoint(cm, to, to + lendiff, 1);
  1.2063 +      if (cutTop && cutBot) {
  1.2064 +        display.view = display.view.slice(0, cutTop.index)
  1.2065 +          .concat(buildViewArray(cm, cutTop.lineN, cutBot.lineN))
  1.2066 +          .concat(display.view.slice(cutBot.index));
  1.2067 +        display.viewTo += lendiff;
  1.2068 +      } else {
  1.2069 +        resetView(cm);
  1.2070 +      }
  1.2071 +    }
  1.2072 +
  1.2073 +    var ext = display.externalMeasured;
  1.2074 +    if (ext) {
  1.2075 +      if (to < ext.lineN)
  1.2076 +        ext.lineN += lendiff;
  1.2077 +      else if (from < ext.lineN + ext.size)
  1.2078 +        display.externalMeasured = null;
  1.2079 +    }
  1.2080 +  }
  1.2081 +
  1.2082 +  // Register a change to a single line. Type must be one of "text",
  1.2083 +  // "gutter", "class", "widget"
  1.2084 +  function regLineChange(cm, line, type) {
  1.2085 +    cm.curOp.viewChanged = true;
  1.2086 +    var display = cm.display, ext = cm.display.externalMeasured;
  1.2087 +    if (ext && line >= ext.lineN && line < ext.lineN + ext.size)
  1.2088 +      display.externalMeasured = null;
  1.2089 +
  1.2090 +    if (line < display.viewFrom || line >= display.viewTo) return;
  1.2091 +    var lineView = display.view[findViewIndex(cm, line)];
  1.2092 +    if (lineView.node == null) return;
  1.2093 +    var arr = lineView.changes || (lineView.changes = []);
  1.2094 +    if (indexOf(arr, type) == -1) arr.push(type);
  1.2095 +  }
  1.2096 +
  1.2097 +  // Clear the view.
  1.2098 +  function resetView(cm) {
  1.2099 +    cm.display.viewFrom = cm.display.viewTo = cm.doc.first;
  1.2100 +    cm.display.view = [];
  1.2101 +    cm.display.viewOffset = 0;
  1.2102 +  }
  1.2103 +
  1.2104 +  // Find the view element corresponding to a given line. Return null
  1.2105 +  // when the line isn't visible.
  1.2106 +  function findViewIndex(cm, n) {
  1.2107 +    if (n >= cm.display.viewTo) return null;
  1.2108 +    n -= cm.display.viewFrom;
  1.2109 +    if (n < 0) return null;
  1.2110 +    var view = cm.display.view;
  1.2111 +    for (var i = 0; i < view.length; i++) {
  1.2112 +      n -= view[i].size;
  1.2113 +      if (n < 0) return i;
  1.2114 +    }
  1.2115 +  }
  1.2116 +
  1.2117 +  function viewCuttingPoint(cm, oldN, newN, dir) {
  1.2118 +    var index = findViewIndex(cm, oldN), diff, view = cm.display.view;
  1.2119 +    if (!sawCollapsedSpans) return {index: index, lineN: newN};
  1.2120 +    for (var i = 0, n = cm.display.viewFrom; i < index; i++)
  1.2121 +      n += view[i].size;
  1.2122 +    if (n != oldN) {
  1.2123 +      if (dir > 0) {
  1.2124 +        if (index == view.length - 1) return null;
  1.2125 +        diff = (n + view[index].size) - oldN;
  1.2126 +        index++;
  1.2127 +      } else {
  1.2128 +        diff = n - oldN;
  1.2129 +      }
  1.2130 +      oldN += diff; newN += diff;
  1.2131 +    }
  1.2132 +    while (visualLineNo(cm.doc, newN) != newN) {
  1.2133 +      if (index == (dir < 0 ? 0 : view.length - 1)) return null;
  1.2134 +      newN += dir * view[index - (dir < 0 ? 1 : 0)].size;
  1.2135 +      index += dir;
  1.2136 +    }
  1.2137 +    return {index: index, lineN: newN};
  1.2138 +  }
  1.2139 +
  1.2140 +  // Force the view to cover a given range, adding empty view element
  1.2141 +  // or clipping off existing ones as needed.
  1.2142 +  function adjustView(cm, from, to) {
  1.2143 +    var display = cm.display, view = display.view;
  1.2144 +    if (view.length == 0 || from >= display.viewTo || to <= display.viewFrom) {
  1.2145 +      display.view = buildViewArray(cm, from, to);
  1.2146 +      display.viewFrom = from;
  1.2147 +    } else {
  1.2148 +      if (display.viewFrom > from)
  1.2149 +        display.view = buildViewArray(cm, from, display.viewFrom).concat(display.view);
  1.2150 +      else if (display.viewFrom < from)
  1.2151 +        display.view = display.view.slice(findViewIndex(cm, from));
  1.2152 +      display.viewFrom = from;
  1.2153 +      if (display.viewTo < to)
  1.2154 +        display.view = display.view.concat(buildViewArray(cm, display.viewTo, to));
  1.2155 +      else if (display.viewTo > to)
  1.2156 +        display.view = display.view.slice(0, findViewIndex(cm, to));
  1.2157 +    }
  1.2158 +    display.viewTo = to;
  1.2159 +  }
  1.2160 +
  1.2161 +  // Count the number of lines in the view whose DOM representation is
  1.2162 +  // out of date (or nonexistent).
  1.2163 +  function countDirtyView(cm) {
  1.2164 +    var view = cm.display.view, dirty = 0;
  1.2165 +    for (var i = 0; i < view.length; i++) {
  1.2166 +      var lineView = view[i];
  1.2167 +      if (!lineView.hidden && (!lineView.node || lineView.changes)) ++dirty;
  1.2168 +    }
  1.2169 +    return dirty;
  1.2170 +  }
  1.2171 +
  1.2172 +  // INPUT HANDLING
  1.2173 +
  1.2174 +  // Poll for input changes, using the normal rate of polling. This
  1.2175 +  // runs as long as the editor is focused.
  1.2176 +  function slowPoll(cm) {
  1.2177 +    if (cm.display.pollingFast) return;
  1.2178 +    cm.display.poll.set(cm.options.pollInterval, function() {
  1.2179 +      readInput(cm);
  1.2180 +      if (cm.state.focused) slowPoll(cm);
  1.2181 +    });
  1.2182 +  }
  1.2183 +
  1.2184 +  // When an event has just come in that is likely to add or change
  1.2185 +  // something in the input textarea, we poll faster, to ensure that
  1.2186 +  // the change appears on the screen quickly.
  1.2187 +  function fastPoll(cm) {
  1.2188 +    var missed = false;
  1.2189 +    cm.display.pollingFast = true;
  1.2190 +    function p() {
  1.2191 +      var changed = readInput(cm);
  1.2192 +      if (!changed && !missed) {missed = true; cm.display.poll.set(60, p);}
  1.2193 +      else {cm.display.pollingFast = false; slowPoll(cm);}
  1.2194 +    }
  1.2195 +    cm.display.poll.set(20, p);
  1.2196 +  }
  1.2197 +
  1.2198 +  // Read input from the textarea, and update the document to match.
  1.2199 +  // When something is selected, it is present in the textarea, and
  1.2200 +  // selected (unless it is huge, in which case a placeholder is
  1.2201 +  // used). When nothing is selected, the cursor sits after previously
  1.2202 +  // seen text (can be empty), which is stored in prevInput (we must
  1.2203 +  // not reset the textarea when typing, because that breaks IME).
  1.2204 +  function readInput(cm) {
  1.2205 +    var input = cm.display.input, prevInput = cm.display.prevInput, doc = cm.doc;
  1.2206 +    // Since this is called a *lot*, try to bail out as cheaply as
  1.2207 +    // possible when it is clear that nothing happened. hasSelection
  1.2208 +    // will be the case when there is a lot of text in the textarea,
  1.2209 +    // in which case reading its value would be expensive.
  1.2210 +    if (!cm.state.focused || hasSelection(input) || isReadOnly(cm) || cm.options.disableInput) return false;
  1.2211 +    var text = input.value;
  1.2212 +    // If nothing changed, bail.
  1.2213 +    if (text == prevInput && !cm.somethingSelected()) return false;
  1.2214 +    // Work around nonsensical selection resetting in IE9/10
  1.2215 +    if (ie && !ie_upto8 && cm.display.inputHasSelection === text) {
  1.2216 +      resetInput(cm);
  1.2217 +      return false;
  1.2218 +    }
  1.2219 +
  1.2220 +    var withOp = !cm.curOp;
  1.2221 +    if (withOp) startOperation(cm);
  1.2222 +    cm.display.shift = false;
  1.2223 +
  1.2224 +    // Find the part of the input that is actually new
  1.2225 +    var same = 0, l = Math.min(prevInput.length, text.length);
  1.2226 +    while (same < l && prevInput.charCodeAt(same) == text.charCodeAt(same)) ++same;
  1.2227 +    var inserted = text.slice(same), textLines = splitLines(inserted);
  1.2228 +
  1.2229 +    // When pasing N lines into N selections, insert one line per selection
  1.2230 +    var multiPaste = cm.state.pasteIncoming && textLines.length > 1 && doc.sel.ranges.length == textLines.length;
  1.2231 +
  1.2232 +    // Normal behavior is to insert the new text into every selection
  1.2233 +    for (var i = doc.sel.ranges.length - 1; i >= 0; i--) {
  1.2234 +      var range = doc.sel.ranges[i];
  1.2235 +      var from = range.from(), to = range.to();
  1.2236 +      // Handle deletion
  1.2237 +      if (same < prevInput.length)
  1.2238 +        from = Pos(from.line, from.ch - (prevInput.length - same));
  1.2239 +      // Handle overwrite
  1.2240 +      else if (cm.state.overwrite && range.empty() && !cm.state.pasteIncoming)
  1.2241 +        to = Pos(to.line, Math.min(getLine(doc, to.line).text.length, to.ch + lst(textLines).length));
  1.2242 +      var updateInput = cm.curOp.updateInput;
  1.2243 +      var changeEvent = {from: from, to: to, text: multiPaste ? [textLines[i]] : textLines,
  1.2244 +                         origin: cm.state.pasteIncoming ? "paste" : cm.state.cutIncoming ? "cut" : "+input"};
  1.2245 +      makeChange(cm.doc, changeEvent);
  1.2246 +      signalLater(cm, "inputRead", cm, changeEvent);
  1.2247 +      // When an 'electric' character is inserted, immediately trigger a reindent
  1.2248 +      if (inserted && !cm.state.pasteIncoming && cm.options.electricChars &&
  1.2249 +          cm.options.smartIndent && range.head.ch < 100 &&
  1.2250 +          (!i || doc.sel.ranges[i - 1].head.line != range.head.line)) {
  1.2251 +        var electric = cm.getModeAt(range.head).electricChars;
  1.2252 +        if (electric) for (var j = 0; j < electric.length; j++)
  1.2253 +          if (inserted.indexOf(electric.charAt(j)) > -1) {
  1.2254 +            indentLine(cm, range.head.line, "smart");
  1.2255 +            break;
  1.2256 +          }
  1.2257 +      }
  1.2258 +    }
  1.2259 +    ensureCursorVisible(cm);
  1.2260 +    cm.curOp.updateInput = updateInput;
  1.2261 +    cm.curOp.typing = true;
  1.2262 +
  1.2263 +    // Don't leave long text in the textarea, since it makes further polling slow
  1.2264 +    if (text.length > 1000 || text.indexOf("\n") > -1) input.value = cm.display.prevInput = "";
  1.2265 +    else cm.display.prevInput = text;
  1.2266 +    if (withOp) endOperation(cm);
  1.2267 +    cm.state.pasteIncoming = cm.state.cutIncoming = false;
  1.2268 +    return true;
  1.2269 +  }
  1.2270 +
  1.2271 +  // Reset the input to correspond to the selection (or to be empty,
  1.2272 +  // when not typing and nothing is selected)
  1.2273 +  function resetInput(cm, typing) {
  1.2274 +    var minimal, selected, doc = cm.doc;
  1.2275 +    if (cm.somethingSelected()) {
  1.2276 +      cm.display.prevInput = "";
  1.2277 +      var range = doc.sel.primary();
  1.2278 +      minimal = hasCopyEvent &&
  1.2279 +        (range.to().line - range.from().line > 100 || (selected = cm.getSelection()).length > 1000);
  1.2280 +      var content = minimal ? "-" : selected || cm.getSelection();
  1.2281 +      cm.display.input.value = content;
  1.2282 +      if (cm.state.focused) selectInput(cm.display.input);
  1.2283 +      if (ie && !ie_upto8) cm.display.inputHasSelection = content;
  1.2284 +    } else if (!typing) {
  1.2285 +      cm.display.prevInput = cm.display.input.value = "";
  1.2286 +      if (ie && !ie_upto8) cm.display.inputHasSelection = null;
  1.2287 +    }
  1.2288 +    cm.display.inaccurateSelection = minimal;
  1.2289 +  }
  1.2290 +
  1.2291 +  function focusInput(cm) {
  1.2292 +    if (cm.options.readOnly != "nocursor" && (!mobile || activeElt() != cm.display.input))
  1.2293 +      cm.display.input.focus();
  1.2294 +  }
  1.2295 +
  1.2296 +  function ensureFocus(cm) {
  1.2297 +    if (!cm.state.focused) { focusInput(cm); onFocus(cm); }
  1.2298 +  }
  1.2299 +
  1.2300 +  function isReadOnly(cm) {
  1.2301 +    return cm.options.readOnly || cm.doc.cantEdit;
  1.2302 +  }
  1.2303 +
  1.2304 +  // EVENT HANDLERS
  1.2305 +
  1.2306 +  // Attach the necessary event handlers when initializing the editor
  1.2307 +  function registerEventHandlers(cm) {
  1.2308 +    var d = cm.display;
  1.2309 +    on(d.scroller, "mousedown", operation(cm, onMouseDown));
  1.2310 +    // Older IE's will not fire a second mousedown for a double click
  1.2311 +    if (ie_upto10)
  1.2312 +      on(d.scroller, "dblclick", operation(cm, function(e) {
  1.2313 +        if (signalDOMEvent(cm, e)) return;
  1.2314 +        var pos = posFromMouse(cm, e);
  1.2315 +        if (!pos || clickInGutter(cm, e) || eventInWidget(cm.display, e)) return;
  1.2316 +        e_preventDefault(e);
  1.2317 +        var word = findWordAt(cm.doc, pos);
  1.2318 +        extendSelection(cm.doc, word.anchor, word.head);
  1.2319 +      }));
  1.2320 +    else
  1.2321 +      on(d.scroller, "dblclick", function(e) { signalDOMEvent(cm, e) || e_preventDefault(e); });
  1.2322 +    // Prevent normal selection in the editor (we handle our own)
  1.2323 +    on(d.lineSpace, "selectstart", function(e) {
  1.2324 +      if (!eventInWidget(d, e)) e_preventDefault(e);
  1.2325 +    });
  1.2326 +    // Some browsers fire contextmenu *after* opening the menu, at
  1.2327 +    // which point we can't mess with it anymore. Context menu is
  1.2328 +    // handled in onMouseDown for these browsers.
  1.2329 +    if (!captureRightClick) on(d.scroller, "contextmenu", function(e) {onContextMenu(cm, e);});
  1.2330 +
  1.2331 +    // Sync scrolling between fake scrollbars and real scrollable
  1.2332 +    // area, ensure viewport is updated when scrolling.
  1.2333 +    on(d.scroller, "scroll", function() {
  1.2334 +      if (d.scroller.clientHeight) {
  1.2335 +        setScrollTop(cm, d.scroller.scrollTop);
  1.2336 +        setScrollLeft(cm, d.scroller.scrollLeft, true);
  1.2337 +        signal(cm, "scroll", cm);
  1.2338 +      }
  1.2339 +    });
  1.2340 +    on(d.scrollbarV, "scroll", function() {
  1.2341 +      if (d.scroller.clientHeight) setScrollTop(cm, d.scrollbarV.scrollTop);
  1.2342 +    });
  1.2343 +    on(d.scrollbarH, "scroll", function() {
  1.2344 +      if (d.scroller.clientHeight) setScrollLeft(cm, d.scrollbarH.scrollLeft);
  1.2345 +    });
  1.2346 +
  1.2347 +    // Listen to wheel events in order to try and update the viewport on time.
  1.2348 +    on(d.scroller, "mousewheel", function(e){onScrollWheel(cm, e);});
  1.2349 +    on(d.scroller, "DOMMouseScroll", function(e){onScrollWheel(cm, e);});
  1.2350 +
  1.2351 +    // Prevent clicks in the scrollbars from killing focus
  1.2352 +    function reFocus() { if (cm.state.focused) setTimeout(bind(focusInput, cm), 0); }
  1.2353 +    on(d.scrollbarH, "mousedown", reFocus);
  1.2354 +    on(d.scrollbarV, "mousedown", reFocus);
  1.2355 +    // Prevent wrapper from ever scrolling
  1.2356 +    on(d.wrapper, "scroll", function() { d.wrapper.scrollTop = d.wrapper.scrollLeft = 0; });
  1.2357 +
  1.2358 +    // When the window resizes, we need to refresh active editors.
  1.2359 +    var resizeTimer;
  1.2360 +    function onResize() {
  1.2361 +      if (resizeTimer == null) resizeTimer = setTimeout(function() {
  1.2362 +        resizeTimer = null;
  1.2363 +        // Might be a text scaling operation, clear size caches.
  1.2364 +        d.cachedCharWidth = d.cachedTextHeight = d.cachedPaddingH = knownScrollbarWidth = null;
  1.2365 +        cm.setSize();
  1.2366 +      }, 100);
  1.2367 +    }
  1.2368 +    on(window, "resize", onResize);
  1.2369 +    // The above handler holds on to the editor and its data
  1.2370 +    // structures. Here we poll to unregister it when the editor is no
  1.2371 +    // longer in the document, so that it can be garbage-collected.
  1.2372 +    function unregister() {
  1.2373 +      if (contains(document.body, d.wrapper)) setTimeout(unregister, 5000);
  1.2374 +      else off(window, "resize", onResize);
  1.2375 +    }
  1.2376 +    setTimeout(unregister, 5000);
  1.2377 +
  1.2378 +    on(d.input, "keyup", operation(cm, onKeyUp));
  1.2379 +    on(d.input, "input", function() {
  1.2380 +      if (ie && !ie_upto8 && cm.display.inputHasSelection) cm.display.inputHasSelection = null;
  1.2381 +      fastPoll(cm);
  1.2382 +    });
  1.2383 +    on(d.input, "keydown", operation(cm, onKeyDown));
  1.2384 +    on(d.input, "keypress", operation(cm, onKeyPress));
  1.2385 +    on(d.input, "focus", bind(onFocus, cm));
  1.2386 +    on(d.input, "blur", bind(onBlur, cm));
  1.2387 +
  1.2388 +    function drag_(e) {
  1.2389 +      if (!signalDOMEvent(cm, e)) e_stop(e);
  1.2390 +    }
  1.2391 +    if (cm.options.dragDrop) {
  1.2392 +      on(d.scroller, "dragstart", function(e){onDragStart(cm, e);});
  1.2393 +      on(d.scroller, "dragenter", drag_);
  1.2394 +      on(d.scroller, "dragover", drag_);
  1.2395 +      on(d.scroller, "drop", operation(cm, onDrop));
  1.2396 +    }
  1.2397 +    on(d.scroller, "paste", function(e) {
  1.2398 +      if (eventInWidget(d, e)) return;
  1.2399 +      cm.state.pasteIncoming = true;
  1.2400 +      focusInput(cm);
  1.2401 +      fastPoll(cm);
  1.2402 +    });
  1.2403 +    on(d.input, "paste", function() {
  1.2404 +      cm.state.pasteIncoming = true;
  1.2405 +      fastPoll(cm);
  1.2406 +    });
  1.2407 +
  1.2408 +    function prepareCopy(e) {
  1.2409 +      if (d.inaccurateSelection) {
  1.2410 +        d.prevInput = "";
  1.2411 +        d.inaccurateSelection = false;
  1.2412 +        d.input.value = cm.getSelection();
  1.2413 +        selectInput(d.input);
  1.2414 +      }
  1.2415 +      if (e.type == "cut") cm.state.cutIncoming = true;
  1.2416 +    }
  1.2417 +    on(d.input, "cut", prepareCopy);
  1.2418 +    on(d.input, "copy", prepareCopy);
  1.2419 +
  1.2420 +    // Needed to handle Tab key in KHTML
  1.2421 +    if (khtml) on(d.sizer, "mouseup", function() {
  1.2422 +      if (activeElt() == d.input) d.input.blur();
  1.2423 +      focusInput(cm);
  1.2424 +    });
  1.2425 +  }
  1.2426 +
  1.2427 +  // MOUSE EVENTS
  1.2428 +
  1.2429 +  // Return true when the given mouse event happened in a widget
  1.2430 +  function eventInWidget(display, e) {
  1.2431 +    for (var n = e_target(e); n != display.wrapper; n = n.parentNode) {
  1.2432 +      if (!n || n.ignoreEvents || n.parentNode == display.sizer && n != display.mover) return true;
  1.2433 +    }
  1.2434 +  }
  1.2435 +
  1.2436 +  // Given a mouse event, find the corresponding position. If liberal
  1.2437 +  // is false, it checks whether a gutter or scrollbar was clicked,
  1.2438 +  // and returns null if it was. forRect is used by rectangular
  1.2439 +  // selections, and tries to estimate a character position even for
  1.2440 +  // coordinates beyond the right of the text.
  1.2441 +  function posFromMouse(cm, e, liberal, forRect) {
  1.2442 +    var display = cm.display;
  1.2443 +    if (!liberal) {
  1.2444 +      var target = e_target(e);
  1.2445 +      if (target == display.scrollbarH || target == display.scrollbarV ||
  1.2446 +          target == display.scrollbarFiller || target == display.gutterFiller) return null;
  1.2447 +    }
  1.2448 +    var x, y, space = display.lineSpace.getBoundingClientRect();
  1.2449 +    // Fails unpredictably on IE[67] when mouse is dragged around quickly.
  1.2450 +    try { x = e.clientX - space.left; y = e.clientY - space.top; }
  1.2451 +    catch (e) { return null; }
  1.2452 +    var coords = coordsChar(cm, x, y), line;
  1.2453 +    if (forRect && coords.xRel == 1 && (line = getLine(cm.doc, coords.line).text).length == coords.ch) {
  1.2454 +      var colDiff = countColumn(line, line.length, cm.options.tabSize) - line.length;
  1.2455 +      coords = Pos(coords.line, Math.round((x - paddingH(cm.display).left) / charWidth(cm.display)) - colDiff);
  1.2456 +    }
  1.2457 +    return coords;
  1.2458 +  }
  1.2459 +
  1.2460 +  // A mouse down can be a single click, double click, triple click,
  1.2461 +  // start of selection drag, start of text drag, new cursor
  1.2462 +  // (ctrl-click), rectangle drag (alt-drag), or xwin
  1.2463 +  // middle-click-paste. Or it might be a click on something we should
  1.2464 +  // not interfere with, such as a scrollbar or widget.
  1.2465 +  function onMouseDown(e) {
  1.2466 +    if (signalDOMEvent(this, e)) return;
  1.2467 +    var cm = this, display = cm.display;
  1.2468 +    display.shift = e.shiftKey;
  1.2469 +
  1.2470 +    if (eventInWidget(display, e)) {
  1.2471 +      if (!webkit) {
  1.2472 +        // Briefly turn off draggability, to allow widgets to do
  1.2473 +        // normal dragging things.
  1.2474 +        display.scroller.draggable = false;
  1.2475 +        setTimeout(function(){display.scroller.draggable = true;}, 100);
  1.2476 +      }
  1.2477 +      return;
  1.2478 +    }
  1.2479 +    if (clickInGutter(cm, e)) return;
  1.2480 +    var start = posFromMouse(cm, e);
  1.2481 +    window.focus();
  1.2482 +
  1.2483 +    switch (e_button(e)) {
  1.2484 +    case 1:
  1.2485 +      if (start)
  1.2486 +        leftButtonDown(cm, e, start);
  1.2487 +      else if (e_target(e) == display.scroller)
  1.2488 +        e_preventDefault(e);
  1.2489 +      break;
  1.2490 +    case 2:
  1.2491 +      if (webkit) cm.state.lastMiddleDown = +new Date;
  1.2492 +      if (start) extendSelection(cm.doc, start);
  1.2493 +      setTimeout(bind(focusInput, cm), 20);
  1.2494 +      e_preventDefault(e);
  1.2495 +      break;
  1.2496 +    case 3:
  1.2497 +      if (captureRightClick) onContextMenu(cm, e);
  1.2498 +      break;
  1.2499 +    }
  1.2500 +  }
  1.2501 +
  1.2502 +  var lastClick, lastDoubleClick;
  1.2503 +  function leftButtonDown(cm, e, start) {
  1.2504 +    setTimeout(bind(ensureFocus, cm), 0);
  1.2505 +
  1.2506 +    var now = +new Date, type;
  1.2507 +    if (lastDoubleClick && lastDoubleClick.time > now - 400 && cmp(lastDoubleClick.pos, start) == 0) {
  1.2508 +      type = "triple";
  1.2509 +    } else if (lastClick && lastClick.time > now - 400 && cmp(lastClick.pos, start) == 0) {
  1.2510 +      type = "double";
  1.2511 +      lastDoubleClick = {time: now, pos: start};
  1.2512 +    } else {
  1.2513 +      type = "single";
  1.2514 +      lastClick = {time: now, pos: start};
  1.2515 +    }
  1.2516 +
  1.2517 +    var sel = cm.doc.sel, addNew = mac ? e.metaKey : e.ctrlKey;
  1.2518 +    if (cm.options.dragDrop && dragAndDrop && !addNew && !isReadOnly(cm) &&
  1.2519 +        type == "single" && sel.contains(start) > -1 && sel.somethingSelected())
  1.2520 +      leftButtonStartDrag(cm, e, start);
  1.2521 +    else
  1.2522 +      leftButtonSelect(cm, e, start, type, addNew);
  1.2523 +  }
  1.2524 +
  1.2525 +  // Start a text drag. When it ends, see if any dragging actually
  1.2526 +  // happen, and treat as a click if it didn't.
  1.2527 +  function leftButtonStartDrag(cm, e, start) {
  1.2528 +    var display = cm.display;
  1.2529 +    var dragEnd = operation(cm, function(e2) {
  1.2530 +      if (webkit) display.scroller.draggable = false;
  1.2531 +      cm.state.draggingText = false;
  1.2532 +      off(document, "mouseup", dragEnd);
  1.2533 +      off(display.scroller, "drop", dragEnd);
  1.2534 +      if (Math.abs(e.clientX - e2.clientX) + Math.abs(e.clientY - e2.clientY) < 10) {
  1.2535 +        e_preventDefault(e2);
  1.2536 +        extendSelection(cm.doc, start);
  1.2537 +        focusInput(cm);
  1.2538 +        // Work around unexplainable focus problem in IE9 (#2127)
  1.2539 +        if (ie_upto10 && !ie_upto8)
  1.2540 +          setTimeout(function() {document.body.focus(); focusInput(cm);}, 20);
  1.2541 +      }
  1.2542 +    });
  1.2543 +    // Let the drag handler handle this.
  1.2544 +    if (webkit) display.scroller.draggable = true;
  1.2545 +    cm.state.draggingText = dragEnd;
  1.2546 +    // IE's approach to draggable
  1.2547 +    if (display.scroller.dragDrop) display.scroller.dragDrop();
  1.2548 +    on(document, "mouseup", dragEnd);
  1.2549 +    on(display.scroller, "drop", dragEnd);
  1.2550 +  }
  1.2551 +
  1.2552 +  // Normal selection, as opposed to text dragging.
  1.2553 +  function leftButtonSelect(cm, e, start, type, addNew) {
  1.2554 +    var display = cm.display, doc = cm.doc;
  1.2555 +    e_preventDefault(e);
  1.2556 +
  1.2557 +    var ourRange, ourIndex, startSel = doc.sel;
  1.2558 +    if (addNew) {
  1.2559 +      ourIndex = doc.sel.contains(start);
  1.2560 +      if (ourIndex > -1)
  1.2561 +        ourRange = doc.sel.ranges[ourIndex];
  1.2562 +      else
  1.2563 +        ourRange = new Range(start, start);
  1.2564 +    } else {
  1.2565 +      ourRange = doc.sel.primary();
  1.2566 +    }
  1.2567 +
  1.2568 +    if (e.altKey) {
  1.2569 +      type = "rect";
  1.2570 +      if (!addNew) ourRange = new Range(start, start);
  1.2571 +      start = posFromMouse(cm, e, true, true);
  1.2572 +      ourIndex = -1;
  1.2573 +    } else if (type == "double") {
  1.2574 +      var word = findWordAt(doc, start);
  1.2575 +      if (cm.display.shift || doc.extend)
  1.2576 +        ourRange = extendRange(doc, ourRange, word.anchor, word.head);
  1.2577 +      else
  1.2578 +        ourRange = word;
  1.2579 +    } else if (type == "triple") {
  1.2580 +      var line = new Range(Pos(start.line, 0), clipPos(doc, Pos(start.line + 1, 0)));
  1.2581 +      if (cm.display.shift || doc.extend)
  1.2582 +        ourRange = extendRange(doc, ourRange, line.anchor, line.head);
  1.2583 +      else
  1.2584 +        ourRange = line;
  1.2585 +    } else {
  1.2586 +      ourRange = extendRange(doc, ourRange, start);
  1.2587 +    }
  1.2588 +
  1.2589 +    if (!addNew) {
  1.2590 +      ourIndex = 0;
  1.2591 +      setSelection(doc, new Selection([ourRange], 0), sel_mouse);
  1.2592 +    } else if (ourIndex > -1) {
  1.2593 +      replaceOneSelection(doc, ourIndex, ourRange, sel_mouse);
  1.2594 +    } else {
  1.2595 +      ourIndex = doc.sel.ranges.length;
  1.2596 +      setSelection(doc, normalizeSelection(doc.sel.ranges.concat([ourRange]), ourIndex),
  1.2597 +                   {scroll: false, origin: "*mouse"});
  1.2598 +    }
  1.2599 +
  1.2600 +    var lastPos = start;
  1.2601 +    function extendTo(pos) {
  1.2602 +      if (cmp(lastPos, pos) == 0) return;
  1.2603 +      lastPos = pos;
  1.2604 +
  1.2605 +      if (type == "rect") {
  1.2606 +        var ranges = [], tabSize = cm.options.tabSize;
  1.2607 +        var startCol = countColumn(getLine(doc, start.line).text, start.ch, tabSize);
  1.2608 +        var posCol = countColumn(getLine(doc, pos.line).text, pos.ch, tabSize);
  1.2609 +        var left = Math.min(startCol, posCol), right = Math.max(startCol, posCol);
  1.2610 +        for (var line = Math.min(start.line, pos.line), end = Math.min(cm.lastLine(), Math.max(start.line, pos.line));
  1.2611 +             line <= end; line++) {
  1.2612 +          var text = getLine(doc, line).text, leftPos = findColumn(text, left, tabSize);
  1.2613 +          if (left == right)
  1.2614 +            ranges.push(new Range(Pos(line, leftPos), Pos(line, leftPos)));
  1.2615 +          else if (text.length > leftPos)
  1.2616 +            ranges.push(new Range(Pos(line, leftPos), Pos(line, findColumn(text, right, tabSize))));
  1.2617 +        }
  1.2618 +        if (!ranges.length) ranges.push(new Range(start, start));
  1.2619 +        setSelection(doc, normalizeSelection(startSel.ranges.slice(0, ourIndex).concat(ranges), ourIndex), sel_mouse);
  1.2620 +      } else {
  1.2621 +        var oldRange = ourRange;
  1.2622 +        var anchor = oldRange.anchor, head = pos;
  1.2623 +        if (type != "single") {
  1.2624 +          if (type == "double")
  1.2625 +            var range = findWordAt(doc, pos);
  1.2626 +          else
  1.2627 +            var range = new Range(Pos(pos.line, 0), clipPos(doc, Pos(pos.line + 1, 0)));
  1.2628 +          if (cmp(range.anchor, anchor) > 0) {
  1.2629 +            head = range.head;
  1.2630 +            anchor = minPos(oldRange.from(), range.anchor);
  1.2631 +          } else {
  1.2632 +            head = range.anchor;
  1.2633 +            anchor = maxPos(oldRange.to(), range.head);
  1.2634 +          }
  1.2635 +        }
  1.2636 +        var ranges = startSel.ranges.slice(0);
  1.2637 +        ranges[ourIndex] = new Range(clipPos(doc, anchor), head);
  1.2638 +        setSelection(doc, normalizeSelection(ranges, ourIndex), sel_mouse);
  1.2639 +      }
  1.2640 +    }
  1.2641 +
  1.2642 +    var editorSize = display.wrapper.getBoundingClientRect();
  1.2643 +    // Used to ensure timeout re-tries don't fire when another extend
  1.2644 +    // happened in the meantime (clearTimeout isn't reliable -- at
  1.2645 +    // least on Chrome, the timeouts still happen even when cleared,
  1.2646 +    // if the clear happens after their scheduled firing time).
  1.2647 +    var counter = 0;
  1.2648 +
  1.2649 +    function extend(e) {
  1.2650 +      var curCount = ++counter;
  1.2651 +      var cur = posFromMouse(cm, e, true, type == "rect");
  1.2652 +      if (!cur) return;
  1.2653 +      if (cmp(cur, lastPos) != 0) {
  1.2654 +        ensureFocus(cm);
  1.2655 +        extendTo(cur);
  1.2656 +        var visible = visibleLines(display, doc);
  1.2657 +        if (cur.line >= visible.to || cur.line < visible.from)
  1.2658 +          setTimeout(operation(cm, function(){if (counter == curCount) extend(e);}), 150);
  1.2659 +      } else {
  1.2660 +        var outside = e.clientY < editorSize.top ? -20 : e.clientY > editorSize.bottom ? 20 : 0;
  1.2661 +        if (outside) setTimeout(operation(cm, function() {
  1.2662 +          if (counter != curCount) return;
  1.2663 +          display.scroller.scrollTop += outside;
  1.2664 +          extend(e);
  1.2665 +        }), 50);
  1.2666 +      }
  1.2667 +    }
  1.2668 +
  1.2669 +    function done(e) {
  1.2670 +      counter = Infinity;
  1.2671 +      e_preventDefault(e);
  1.2672 +      focusInput(cm);
  1.2673 +      off(document, "mousemove", move);
  1.2674 +      off(document, "mouseup", up);
  1.2675 +      doc.history.lastSelOrigin = null;
  1.2676 +    }
  1.2677 +
  1.2678 +    var move = operation(cm, function(e) {
  1.2679 +      if ((ie && !ie_upto9) ?  !e.buttons : !e_button(e)) done(e);
  1.2680 +      else extend(e);
  1.2681 +    });
  1.2682 +    var up = operation(cm, done);
  1.2683 +    on(document, "mousemove", move);
  1.2684 +    on(document, "mouseup", up);
  1.2685 +  }
  1.2686 +
  1.2687 +  // Determines whether an event happened in the gutter, and fires the
  1.2688 +  // handlers for the corresponding event.
  1.2689 +  function gutterEvent(cm, e, type, prevent, signalfn) {
  1.2690 +    try { var mX = e.clientX, mY = e.clientY; }
  1.2691 +    catch(e) { return false; }
  1.2692 +    if (mX >= Math.floor(cm.display.gutters.getBoundingClientRect().right)) return false;
  1.2693 +    if (prevent) e_preventDefault(e);
  1.2694 +
  1.2695 +    var display = cm.display;
  1.2696 +    var lineBox = display.lineDiv.getBoundingClientRect();
  1.2697 +
  1.2698 +    if (mY > lineBox.bottom || !hasHandler(cm, type)) return e_defaultPrevented(e);
  1.2699 +    mY -= lineBox.top - display.viewOffset;
  1.2700 +
  1.2701 +    for (var i = 0; i < cm.options.gutters.length; ++i) {
  1.2702 +      var g = display.gutters.childNodes[i];
  1.2703 +      if (g && g.getBoundingClientRect().right >= mX) {
  1.2704 +        var line = lineAtHeight(cm.doc, mY);
  1.2705 +        var gutter = cm.options.gutters[i];
  1.2706 +        signalfn(cm, type, cm, line, gutter, e);
  1.2707 +        return e_defaultPrevented(e);
  1.2708 +      }
  1.2709 +    }
  1.2710 +  }
  1.2711 +
  1.2712 +  function clickInGutter(cm, e) {
  1.2713 +    return gutterEvent(cm, e, "gutterClick", true, signalLater);
  1.2714 +  }
  1.2715 +
  1.2716 +  // Kludge to work around strange IE behavior where it'll sometimes
  1.2717 +  // re-fire a series of drag-related events right after the drop (#1551)
  1.2718 +  var lastDrop = 0;
  1.2719 +
  1.2720 +  function onDrop(e) {
  1.2721 +    var cm = this;
  1.2722 +    if (signalDOMEvent(cm, e) || eventInWidget(cm.display, e))
  1.2723 +      return;
  1.2724 +    e_preventDefault(e);
  1.2725 +    if (ie_upto10) lastDrop = +new Date;
  1.2726 +    var pos = posFromMouse(cm, e, true), files = e.dataTransfer.files;
  1.2727 +    if (!pos || isReadOnly(cm)) return;
  1.2728 +    // Might be a file drop, in which case we simply extract the text
  1.2729 +    // and insert it.
  1.2730 +    if (files && files.length && window.FileReader && window.File) {
  1.2731 +      var n = files.length, text = Array(n), read = 0;
  1.2732 +      var loadFile = function(file, i) {
  1.2733 +        var reader = new FileReader;
  1.2734 +        reader.onload = function() {
  1.2735 +          text[i] = reader.result;
  1.2736 +          if (++read == n) {
  1.2737 +            pos = clipPos(cm.doc, pos);
  1.2738 +            var change = {from: pos, to: pos, text: splitLines(text.join("\n")), origin: "paste"};
  1.2739 +            makeChange(cm.doc, change);
  1.2740 +            setSelectionReplaceHistory(cm.doc, simpleSelection(pos, changeEnd(change)));
  1.2741 +          }
  1.2742 +        };
  1.2743 +        reader.readAsText(file);
  1.2744 +      };
  1.2745 +      for (var i = 0; i < n; ++i) loadFile(files[i], i);
  1.2746 +    } else { // Normal drop
  1.2747 +      // Don't do a replace if the drop happened inside of the selected text.
  1.2748 +      if (cm.state.draggingText && cm.doc.sel.contains(pos) > -1) {
  1.2749 +        cm.state.draggingText(e);
  1.2750 +        // Ensure the editor is re-focused
  1.2751 +        setTimeout(bind(focusInput, cm), 20);
  1.2752 +        return;
  1.2753 +      }
  1.2754 +      try {
  1.2755 +        var text = e.dataTransfer.getData("Text");
  1.2756 +        if (text) {
  1.2757 +          var selected = cm.state.draggingText && cm.listSelections();
  1.2758 +          setSelectionNoUndo(cm.doc, simpleSelection(pos, pos));
  1.2759 +          if (selected) for (var i = 0; i < selected.length; ++i)
  1.2760 +            replaceRange(cm.doc, "", selected[i].anchor, selected[i].head, "drag");
  1.2761 +          cm.replaceSelection(text, "around", "paste");
  1.2762 +          focusInput(cm);
  1.2763 +        }
  1.2764 +      }
  1.2765 +      catch(e){}
  1.2766 +    }
  1.2767 +  }
  1.2768 +
  1.2769 +  function onDragStart(cm, e) {
  1.2770 +    if (ie_upto10 && (!cm.state.draggingText || +new Date - lastDrop < 100)) { e_stop(e); return; }
  1.2771 +    if (signalDOMEvent(cm, e) || eventInWidget(cm.display, e)) return;
  1.2772 +
  1.2773 +    e.dataTransfer.setData("Text", cm.getSelection());
  1.2774 +
  1.2775 +    // Use dummy image instead of default browsers image.
  1.2776 +    // Recent Safari (~6.0.2) have a tendency to segfault when this happens, so we don't do it there.
  1.2777 +    if (e.dataTransfer.setDragImage && !safari) {
  1.2778 +      var img = elt("img", null, null, "position: fixed; left: 0; top: 0;");
  1.2779 +      img.src = "data:image/gif;base64,R0lGODlhAQABAAAAACH5BAEKAAEALAAAAAABAAEAAAICTAEAOw==";
  1.2780 +      if (presto) {
  1.2781 +        img.width = img.height = 1;
  1.2782 +        cm.display.wrapper.appendChild(img);
  1.2783 +        // Force a relayout, or Opera won't use our image for some obscure reason
  1.2784 +        img._top = img.offsetTop;
  1.2785 +      }
  1.2786 +      e.dataTransfer.setDragImage(img, 0, 0);
  1.2787 +      if (presto) img.parentNode.removeChild(img);
  1.2788 +    }
  1.2789 +  }
  1.2790 +
  1.2791 +  // SCROLL EVENTS
  1.2792 +
  1.2793 +  // Sync the scrollable area and scrollbars, ensure the viewport
  1.2794 +  // covers the visible area.
  1.2795 +  function setScrollTop(cm, val) {
  1.2796 +    if (Math.abs(cm.doc.scrollTop - val) < 2) return;
  1.2797 +    cm.doc.scrollTop = val;
  1.2798 +    if (!gecko) updateDisplay(cm, {top: val});
  1.2799 +    if (cm.display.scroller.scrollTop != val) cm.display.scroller.scrollTop = val;
  1.2800 +    if (cm.display.scrollbarV.scrollTop != val) cm.display.scrollbarV.scrollTop = val;
  1.2801 +    if (gecko) updateDisplay(cm);
  1.2802 +    startWorker(cm, 100);
  1.2803 +  }
  1.2804 +  // Sync scroller and scrollbar, ensure the gutter elements are
  1.2805 +  // aligned.
  1.2806 +  function setScrollLeft(cm, val, isScroller) {
  1.2807 +    if (isScroller ? val == cm.doc.scrollLeft : Math.abs(cm.doc.scrollLeft - val) < 2) return;
  1.2808 +    val = Math.min(val, cm.display.scroller.scrollWidth - cm.display.scroller.clientWidth);
  1.2809 +    cm.doc.scrollLeft = val;
  1.2810 +    alignHorizontally(cm);
  1.2811 +    if (cm.display.scroller.scrollLeft != val) cm.display.scroller.scrollLeft = val;
  1.2812 +    if (cm.display.scrollbarH.scrollLeft != val) cm.display.scrollbarH.scrollLeft = val;
  1.2813 +  }
  1.2814 +
  1.2815 +  // Since the delta values reported on mouse wheel events are
  1.2816 +  // unstandardized between browsers and even browser versions, and
  1.2817 +  // generally horribly unpredictable, this code starts by measuring
  1.2818 +  // the scroll effect that the first few mouse wheel events have,
  1.2819 +  // and, from that, detects the way it can convert deltas to pixel
  1.2820 +  // offsets afterwards.
  1.2821 +  //
  1.2822 +  // The reason we want to know the amount a wheel event will scroll
  1.2823 +  // is that it gives us a chance to update the display before the
  1.2824 +  // actual scrolling happens, reducing flickering.
  1.2825 +
  1.2826 +  var wheelSamples = 0, wheelPixelsPerUnit = null;
  1.2827 +  // Fill in a browser-detected starting value on browsers where we
  1.2828 +  // know one. These don't have to be accurate -- the result of them
  1.2829 +  // being wrong would just be a slight flicker on the first wheel
  1.2830 +  // scroll (if it is large enough).
  1.2831 +  if (ie) wheelPixelsPerUnit = -.53;
  1.2832 +  else if (gecko) wheelPixelsPerUnit = 15;
  1.2833 +  else if (chrome) wheelPixelsPerUnit = -.7;
  1.2834 +  else if (safari) wheelPixelsPerUnit = -1/3;
  1.2835 +
  1.2836 +  function onScrollWheel(cm, e) {
  1.2837 +    var dx = e.wheelDeltaX, dy = e.wheelDeltaY;
  1.2838 +    if (dx == null && e.detail && e.axis == e.HORIZONTAL_AXIS) dx = e.detail;
  1.2839 +    if (dy == null && e.detail && e.axis == e.VERTICAL_AXIS) dy = e.detail;
  1.2840 +    else if (dy == null) dy = e.wheelDelta;
  1.2841 +
  1.2842 +    var display = cm.display, scroll = display.scroller;
  1.2843 +    // Quit if there's nothing to scroll here
  1.2844 +    if (!(dx && scroll.scrollWidth > scroll.clientWidth ||
  1.2845 +          dy && scroll.scrollHeight > scroll.clientHeight)) return;
  1.2846 +
  1.2847 +    // Webkit browsers on OS X abort momentum scrolls when the target
  1.2848 +    // of the scroll event is removed from the scrollable element.
  1.2849 +    // This hack (see related code in patchDisplay) makes sure the
  1.2850 +    // element is kept around.
  1.2851 +    if (dy && mac && webkit) {
  1.2852 +      outer: for (var cur = e.target, view = display.view; cur != scroll; cur = cur.parentNode) {
  1.2853 +        for (var i = 0; i < view.length; i++) {
  1.2854 +          if (view[i].node == cur) {
  1.2855 +            cm.display.currentWheelTarget = cur;
  1.2856 +            break outer;
  1.2857 +          }
  1.2858 +        }
  1.2859 +      }
  1.2860 +    }
  1.2861 +
  1.2862 +    // On some browsers, horizontal scrolling will cause redraws to
  1.2863 +    // happen before the gutter has been realigned, causing it to
  1.2864 +    // wriggle around in a most unseemly way. When we have an
  1.2865 +    // estimated pixels/delta value, we just handle horizontal
  1.2866 +    // scrolling entirely here. It'll be slightly off from native, but
  1.2867 +    // better than glitching out.
  1.2868 +    if (dx && !gecko && !presto && wheelPixelsPerUnit != null) {
  1.2869 +      if (dy)
  1.2870 +        setScrollTop(cm, Math.max(0, Math.min(scroll.scrollTop + dy * wheelPixelsPerUnit, scroll.scrollHeight - scroll.clientHeight)));
  1.2871 +      setScrollLeft(cm, Math.max(0, Math.min(scroll.scrollLeft + dx * wheelPixelsPerUnit, scroll.scrollWidth - scroll.clientWidth)));
  1.2872 +      e_preventDefault(e);
  1.2873 +      display.wheelStartX = null; // Abort measurement, if in progress
  1.2874 +      return;
  1.2875 +    }
  1.2876 +
  1.2877 +    // 'Project' the visible viewport to cover the area that is being
  1.2878 +    // scrolled into view (if we know enough to estimate it).
  1.2879 +    if (dy && wheelPixelsPerUnit != null) {
  1.2880 +      var pixels = dy * wheelPixelsPerUnit;
  1.2881 +      var top = cm.doc.scrollTop, bot = top + display.wrapper.clientHeight;
  1.2882 +      if (pixels < 0) top = Math.max(0, top + pixels - 50);
  1.2883 +      else bot = Math.min(cm.doc.height, bot + pixels + 50);
  1.2884 +      updateDisplay(cm, {top: top, bottom: bot});
  1.2885 +    }
  1.2886 +
  1.2887 +    if (wheelSamples < 20) {
  1.2888 +      if (display.wheelStartX == null) {
  1.2889 +        display.wheelStartX = scroll.scrollLeft; display.wheelStartY = scroll.scrollTop;
  1.2890 +        display.wheelDX = dx; display.wheelDY = dy;
  1.2891 +        setTimeout(function() {
  1.2892 +          if (display.wheelStartX == null) return;
  1.2893 +          var movedX = scroll.scrollLeft - display.wheelStartX;
  1.2894 +          var movedY = scroll.scrollTop - display.wheelStartY;
  1.2895 +          var sample = (movedY && display.wheelDY && movedY / display.wheelDY) ||
  1.2896 +            (movedX && display.wheelDX && movedX / display.wheelDX);
  1.2897 +          display.wheelStartX = display.wheelStartY = null;
  1.2898 +          if (!sample) return;
  1.2899 +          wheelPixelsPerUnit = (wheelPixelsPerUnit * wheelSamples + sample) / (wheelSamples + 1);
  1.2900 +          ++wheelSamples;
  1.2901 +        }, 200);
  1.2902 +      } else {
  1.2903 +        display.wheelDX += dx; display.wheelDY += dy;
  1.2904 +      }
  1.2905 +    }
  1.2906 +  }
  1.2907 +
  1.2908 +  // KEY EVENTS
  1.2909 +
  1.2910 +  // Run a handler that was bound to a key.
  1.2911 +  function doHandleBinding(cm, bound, dropShift) {
  1.2912 +    if (typeof bound == "string") {
  1.2913 +      bound = commands[bound];
  1.2914 +      if (!bound) return false;
  1.2915 +    }
  1.2916 +    // Ensure previous input has been read, so that the handler sees a
  1.2917 +    // consistent view of the document
  1.2918 +    if (cm.display.pollingFast && readInput(cm)) cm.display.pollingFast = false;
  1.2919 +    var prevShift = cm.display.shift, done = false;
  1.2920 +    try {
  1.2921 +      if (isReadOnly(cm)) cm.state.suppressEdits = true;
  1.2922 +      if (dropShift) cm.display.shift = false;
  1.2923 +      done = bound(cm) != Pass;
  1.2924 +    } finally {
  1.2925 +      cm.display.shift = prevShift;
  1.2926 +      cm.state.suppressEdits = false;
  1.2927 +    }
  1.2928 +    return done;
  1.2929 +  }
  1.2930 +
  1.2931 +  // Collect the currently active keymaps.
  1.2932 +  function allKeyMaps(cm) {
  1.2933 +    var maps = cm.state.keyMaps.slice(0);
  1.2934 +    if (cm.options.extraKeys) maps.push(cm.options.extraKeys);
  1.2935 +    maps.push(cm.options.keyMap);
  1.2936 +    return maps;
  1.2937 +  }
  1.2938 +
  1.2939 +  var maybeTransition;
  1.2940 +  // Handle a key from the keydown event.
  1.2941 +  function handleKeyBinding(cm, e) {
  1.2942 +    // Handle automatic keymap transitions
  1.2943 +    var startMap = getKeyMap(cm.options.keyMap), next = startMap.auto;
  1.2944 +    clearTimeout(maybeTransition);
  1.2945 +    if (next && !isModifierKey(e)) maybeTransition = setTimeout(function() {
  1.2946 +      if (getKeyMap(cm.options.keyMap) == startMap) {
  1.2947 +        cm.options.keyMap = (next.call ? next.call(null, cm) : next);
  1.2948 +        keyMapChanged(cm);
  1.2949 +      }
  1.2950 +    }, 50);
  1.2951 +
  1.2952 +    var name = keyName(e, true), handled = false;
  1.2953 +    if (!name) return false;
  1.2954 +    var keymaps = allKeyMaps(cm);
  1.2955 +
  1.2956 +    if (e.shiftKey) {
  1.2957 +      // First try to resolve full name (including 'Shift-'). Failing
  1.2958 +      // that, see if there is a cursor-motion command (starting with
  1.2959 +      // 'go') bound to the keyname without 'Shift-'.
  1.2960 +      handled = lookupKey("Shift-" + name, keymaps, function(b) {return doHandleBinding(cm, b, true);})
  1.2961 +             || lookupKey(name, keymaps, function(b) {
  1.2962 +                  if (typeof b == "string" ? /^go[A-Z]/.test(b) : b.motion)
  1.2963 +                    return doHandleBinding(cm, b);
  1.2964 +                });
  1.2965 +    } else {
  1.2966 +      handled = lookupKey(name, keymaps, function(b) { return doHandleBinding(cm, b); });
  1.2967 +    }
  1.2968 +
  1.2969 +    if (handled) {
  1.2970 +      e_preventDefault(e);
  1.2971 +      restartBlink(cm);
  1.2972 +      signalLater(cm, "keyHandled", cm, name, e);
  1.2973 +    }
  1.2974 +    return handled;
  1.2975 +  }
  1.2976 +
  1.2977 +  // Handle a key from the keypress event
  1.2978 +  function handleCharBinding(cm, e, ch) {
  1.2979 +    var handled = lookupKey("'" + ch + "'", allKeyMaps(cm),
  1.2980 +                            function(b) { return doHandleBinding(cm, b, true); });
  1.2981 +    if (handled) {
  1.2982 +      e_preventDefault(e);
  1.2983 +      restartBlink(cm);
  1.2984 +      signalLater(cm, "keyHandled", cm, "'" + ch + "'", e);
  1.2985 +    }
  1.2986 +    return handled;
  1.2987 +  }
  1.2988 +
  1.2989 +  var lastStoppedKey = null;
  1.2990 +  function onKeyDown(e) {
  1.2991 +    var cm = this;
  1.2992 +    ensureFocus(cm);
  1.2993 +    if (signalDOMEvent(cm, e)) return;
  1.2994 +    // IE does strange things with escape.
  1.2995 +    if (ie_upto10 && e.keyCode == 27) e.returnValue = false;
  1.2996 +    var code = e.keyCode;
  1.2997 +    cm.display.shift = code == 16 || e.shiftKey;
  1.2998 +    var handled = handleKeyBinding(cm, e);
  1.2999 +    if (presto) {
  1.3000 +      lastStoppedKey = handled ? code : null;
  1.3001 +      // Opera has no cut event... we try to at least catch the key combo
  1.3002 +      if (!handled && code == 88 && !hasCopyEvent && (mac ? e.metaKey : e.ctrlKey))
  1.3003 +        cm.replaceSelection("", null, "cut");
  1.3004 +    }
  1.3005 +  }
  1.3006 +
  1.3007 +  function onKeyUp(e) {
  1.3008 +    if (signalDOMEvent(this, e)) return;
  1.3009 +    if (e.keyCode == 16) this.doc.sel.shift = false;
  1.3010 +  }
  1.3011 +
  1.3012 +  function onKeyPress(e) {
  1.3013 +    var cm = this;
  1.3014 +    if (signalDOMEvent(cm, e)) return;
  1.3015 +    var keyCode = e.keyCode, charCode = e.charCode;
  1.3016 +    if (presto && keyCode == lastStoppedKey) {lastStoppedKey = null; e_preventDefault(e); return;}
  1.3017 +    if (((presto && (!e.which || e.which < 10)) || khtml) && handleKeyBinding(cm, e)) return;
  1.3018 +    var ch = String.fromCharCode(charCode == null ? keyCode : charCode);
  1.3019 +    if (handleCharBinding(cm, e, ch)) return;
  1.3020 +    if (ie && !ie_upto8) cm.display.inputHasSelection = null;
  1.3021 +    fastPoll(cm);
  1.3022 +  }
  1.3023 +
  1.3024 +  // FOCUS/BLUR EVENTS
  1.3025 +
  1.3026 +  function onFocus(cm) {
  1.3027 +    if (cm.options.readOnly == "nocursor") return;
  1.3028 +    if (!cm.state.focused) {
  1.3029 +      signal(cm, "focus", cm);
  1.3030 +      cm.state.focused = true;
  1.3031 +      if (cm.display.wrapper.className.search(/\bCodeMirror-focused\b/) == -1)
  1.3032 +        cm.display.wrapper.className += " CodeMirror-focused";
  1.3033 +      if (!cm.curOp) {
  1.3034 +        resetInput(cm);
  1.3035 +        if (webkit) setTimeout(bind(resetInput, cm, true), 0); // Issue #1730
  1.3036 +      }
  1.3037 +    }
  1.3038 +    slowPoll(cm);
  1.3039 +    restartBlink(cm);
  1.3040 +  }
  1.3041 +  function onBlur(cm) {
  1.3042 +    if (cm.state.focused) {
  1.3043 +      signal(cm, "blur", cm);
  1.3044 +      cm.state.focused = false;
  1.3045 +      cm.display.wrapper.className = cm.display.wrapper.className.replace(" CodeMirror-focused", "");
  1.3046 +    }
  1.3047 +    clearInterval(cm.display.blinker);
  1.3048 +    setTimeout(function() {if (!cm.state.focused) cm.display.shift = false;}, 150);
  1.3049 +  }
  1.3050 +
  1.3051 +  // CONTEXT MENU HANDLING
  1.3052 +
  1.3053 +  var detectingSelectAll;
  1.3054 +  // To make the context menu work, we need to briefly unhide the
  1.3055 +  // textarea (making it as unobtrusive as possible) to let the
  1.3056 +  // right-click take effect on it.
  1.3057 +  function onContextMenu(cm, e) {
  1.3058 +    if (signalDOMEvent(cm, e, "contextmenu")) return;
  1.3059 +    var display = cm.display;
  1.3060 +    if (eventInWidget(display, e) || contextMenuInGutter(cm, e)) return;
  1.3061 +
  1.3062 +    var pos = posFromMouse(cm, e), scrollPos = display.scroller.scrollTop;
  1.3063 +    if (!pos || presto) return; // Opera is difficult.
  1.3064 +
  1.3065 +    // Reset the current text selection only if the click is done outside of the selection
  1.3066 +    // and 'resetSelectionOnContextMenu' option is true.
  1.3067 +    var reset = cm.options.resetSelectionOnContextMenu;
  1.3068 +    if (reset && cm.doc.sel.contains(pos) == -1)
  1.3069 +      operation(cm, setSelection)(cm.doc, simpleSelection(pos), sel_dontScroll);
  1.3070 +
  1.3071 +    var oldCSS = display.input.style.cssText;
  1.3072 +    display.inputDiv.style.position = "absolute";
  1.3073 +    display.input.style.cssText = "position: fixed; width: 30px; height: 30px; top: " + (e.clientY - 5) +
  1.3074 +      "px; left: " + (e.clientX - 5) + "px; z-index: 1000; background: " +
  1.3075 +      (ie ? "rgba(255, 255, 255, .05)" : "transparent") +
  1.3076 +      "; outline: none; border-width: 0; outline: none; overflow: hidden; opacity: .05; filter: alpha(opacity=5);";
  1.3077 +    focusInput(cm);
  1.3078 +    resetInput(cm);
  1.3079 +    // Adds "Select all" to context menu in FF
  1.3080 +    if (!cm.somethingSelected()) display.input.value = display.prevInput = " ";
  1.3081 +
  1.3082 +    // Select-all will be greyed out if there's nothing to select, so
  1.3083 +    // this adds a zero-width space so that we can later check whether
  1.3084 +    // it got selected.
  1.3085 +    function prepareSelectAllHack() {
  1.3086 +      if (display.input.selectionStart != null) {
  1.3087 +        var extval = display.input.value = "\u200b" + (cm.somethingSelected() ? display.input.value : "");
  1.3088 +        display.prevInput = "\u200b";
  1.3089 +        display.input.selectionStart = 1; display.input.selectionEnd = extval.length;
  1.3090 +      }
  1.3091 +    }
  1.3092 +    function rehide() {
  1.3093 +      display.inputDiv.style.position = "relative";
  1.3094 +      display.input.style.cssText = oldCSS;
  1.3095 +      if (ie_upto8) display.scrollbarV.scrollTop = display.scroller.scrollTop = scrollPos;
  1.3096 +      slowPoll(cm);
  1.3097 +
  1.3098 +      // Try to detect the user choosing select-all
  1.3099 +      if (display.input.selectionStart != null) {
  1.3100 +        if (!ie || ie_upto8) prepareSelectAllHack();
  1.3101 +        clearTimeout(detectingSelectAll);
  1.3102 +        var i = 0, poll = function(){
  1.3103 +          if (display.prevInput == "\u200b" && display.input.selectionStart == 0)
  1.3104 +            operation(cm, commands.selectAll)(cm);
  1.3105 +          else if (i++ < 10) detectingSelectAll = setTimeout(poll, 500);
  1.3106 +          else resetInput(cm);
  1.3107 +        };
  1.3108 +        detectingSelectAll = setTimeout(poll, 200);
  1.3109 +      }
  1.3110 +    }
  1.3111 +
  1.3112 +    if (ie && !ie_upto8) prepareSelectAllHack();
  1.3113 +    if (captureRightClick) {
  1.3114 +      e_stop(e);
  1.3115 +      var mouseup = function() {
  1.3116 +        off(window, "mouseup", mouseup);
  1.3117 +        setTimeout(rehide, 20);
  1.3118 +      };
  1.3119 +      on(window, "mouseup", mouseup);
  1.3120 +    } else {
  1.3121 +      setTimeout(rehide, 50);
  1.3122 +    }
  1.3123 +  }
  1.3124 +
  1.3125 +  function contextMenuInGutter(cm, e) {
  1.3126 +    if (!hasHandler(cm, "gutterContextMenu")) return false;
  1.3127 +    return gutterEvent(cm, e, "gutterContextMenu", false, signal);
  1.3128 +  }
  1.3129 +
  1.3130 +  // UPDATING
  1.3131 +
  1.3132 +  // Compute the position of the end of a change (its 'to' property
  1.3133 +  // refers to the pre-change end).
  1.3134 +  var changeEnd = CodeMirror.changeEnd = function(change) {
  1.3135 +    if (!change.text) return change.to;
  1.3136 +    return Pos(change.from.line + change.text.length - 1,
  1.3137 +               lst(change.text).length + (change.text.length == 1 ? change.from.ch : 0));
  1.3138 +  };
  1.3139 +
  1.3140 +  // Adjust a position to refer to the post-change position of the
  1.3141 +  // same text, or the end of the change if the change covers it.
  1.3142 +  function adjustForChange(pos, change) {
  1.3143 +    if (cmp(pos, change.from) < 0) return pos;
  1.3144 +    if (cmp(pos, change.to) <= 0) return changeEnd(change);
  1.3145 +
  1.3146 +    var line = pos.line + change.text.length - (change.to.line - change.from.line) - 1, ch = pos.ch;
  1.3147 +    if (pos.line == change.to.line) ch += changeEnd(change).ch - change.to.ch;
  1.3148 +    return Pos(line, ch);
  1.3149 +  }
  1.3150 +
  1.3151 +  function computeSelAfterChange(doc, change) {
  1.3152 +    var out = [];
  1.3153 +    for (var i = 0; i < doc.sel.ranges.length; i++) {
  1.3154 +      var range = doc.sel.ranges[i];
  1.3155 +      out.push(new Range(adjustForChange(range.anchor, change),
  1.3156 +                         adjustForChange(range.head, change)));
  1.3157 +    }
  1.3158 +    return normalizeSelection(out, doc.sel.primIndex);
  1.3159 +  }
  1.3160 +
  1.3161 +  function offsetPos(pos, old, nw) {
  1.3162 +    if (pos.line == old.line)
  1.3163 +      return Pos(nw.line, pos.ch - old.ch + nw.ch);
  1.3164 +    else
  1.3165 +      return Pos(nw.line + (pos.line - old.line), pos.ch);
  1.3166 +  }
  1.3167 +
  1.3168 +  // Used by replaceSelections to allow moving the selection to the
  1.3169 +  // start or around the replaced test. Hint may be "start" or "around".
  1.3170 +  function computeReplacedSel(doc, changes, hint) {
  1.3171 +    var out = [];
  1.3172 +    var oldPrev = Pos(doc.first, 0), newPrev = oldPrev;
  1.3173 +    for (var i = 0; i < changes.length; i++) {
  1.3174 +      var change = changes[i];
  1.3175 +      var from = offsetPos(change.from, oldPrev, newPrev);
  1.3176 +      var to = offsetPos(changeEnd(change), oldPrev, newPrev);
  1.3177 +      oldPrev = change.to;
  1.3178 +      newPrev = to;
  1.3179 +      if (hint == "around") {
  1.3180 +        var range = doc.sel.ranges[i], inv = cmp(range.head, range.anchor) < 0;
  1.3181 +        out[i] = new Range(inv ? to : from, inv ? from : to);
  1.3182 +      } else {
  1.3183 +        out[i] = new Range(from, from);
  1.3184 +      }
  1.3185 +    }
  1.3186 +    return new Selection(out, doc.sel.primIndex);
  1.3187 +  }
  1.3188 +
  1.3189 +  // Allow "beforeChange" event handlers to influence a change
  1.3190 +  function filterChange(doc, change, update) {
  1.3191 +    var obj = {
  1.3192 +      canceled: false,
  1.3193 +      from: change.from,
  1.3194 +      to: change.to,
  1.3195 +      text: change.text,
  1.3196 +      origin: change.origin,
  1.3197 +      cancel: function() { this.canceled = true; }
  1.3198 +    };
  1.3199 +    if (update) obj.update = function(from, to, text, origin) {
  1.3200 +      if (from) this.from = clipPos(doc, from);
  1.3201 +      if (to) this.to = clipPos(doc, to);
  1.3202 +      if (text) this.text = text;
  1.3203 +      if (origin !== undefined) this.origin = origin;
  1.3204 +    };
  1.3205 +    signal(doc, "beforeChange", doc, obj);
  1.3206 +    if (doc.cm) signal(doc.cm, "beforeChange", doc.cm, obj);
  1.3207 +
  1.3208 +    if (obj.canceled) return null;
  1.3209 +    return {from: obj.from, to: obj.to, text: obj.text, origin: obj.origin};
  1.3210 +  }
  1.3211 +
  1.3212 +  // Apply a change to a document, and add it to the document's
  1.3213 +  // history, and propagating it to all linked documents.
  1.3214 +  function makeChange(doc, change, ignoreReadOnly) {
  1.3215 +    if (doc.cm) {
  1.3216 +      if (!doc.cm.curOp) return operation(doc.cm, makeChange)(doc, change, ignoreReadOnly);
  1.3217 +      if (doc.cm.state.suppressEdits) return;
  1.3218 +    }
  1.3219 +
  1.3220 +    if (hasHandler(doc, "beforeChange") || doc.cm && hasHandler(doc.cm, "beforeChange")) {
  1.3221 +      change = filterChange(doc, change, true);
  1.3222 +      if (!change) return;
  1.3223 +    }
  1.3224 +
  1.3225 +    // Possibly split or suppress the update based on the presence
  1.3226 +    // of read-only spans in its range.
  1.3227 +    var split = sawReadOnlySpans && !ignoreReadOnly && removeReadOnlyRanges(doc, change.from, change.to);
  1.3228 +    if (split) {
  1.3229 +      for (var i = split.length - 1; i >= 0; --i)
  1.3230 +        makeChangeInner(doc, {from: split[i].from, to: split[i].to, text: i ? [""] : change.text});
  1.3231 +    } else {
  1.3232 +      makeChangeInner(doc, change);
  1.3233 +    }
  1.3234 +  }
  1.3235 +
  1.3236 +  function makeChangeInner(doc, change) {
  1.3237 +    if (change.text.length == 1 && change.text[0] == "" && cmp(change.from, change.to) == 0) return;
  1.3238 +    var selAfter = computeSelAfterChange(doc, change);
  1.3239 +    addChangeToHistory(doc, change, selAfter, doc.cm ? doc.cm.curOp.id : NaN);
  1.3240 +
  1.3241 +    makeChangeSingleDoc(doc, change, selAfter, stretchSpansOverChange(doc, change));
  1.3242 +    var rebased = [];
  1.3243 +
  1.3244 +    linkedDocs(doc, function(doc, sharedHist) {
  1.3245 +      if (!sharedHist && indexOf(rebased, doc.history) == -1) {
  1.3246 +        rebaseHist(doc.history, change);
  1.3247 +        rebased.push(doc.history);
  1.3248 +      }
  1.3249 +      makeChangeSingleDoc(doc, change, null, stretchSpansOverChange(doc, change));
  1.3250 +    });
  1.3251 +  }
  1.3252 +
  1.3253 +  // Revert a change stored in a document's history.
  1.3254 +  function makeChangeFromHistory(doc, type, allowSelectionOnly) {
  1.3255 +    if (doc.cm && doc.cm.state.suppressEdits) return;
  1.3256 +
  1.3257 +    var hist = doc.history, event, selAfter = doc.sel;
  1.3258 +    var source = type == "undo" ? hist.done : hist.undone, dest = type == "undo" ? hist.undone : hist.done;
  1.3259 +
  1.3260 +    // Verify that there is a useable event (so that ctrl-z won't
  1.3261 +    // needlessly clear selection events)
  1.3262 +    for (var i = 0; i < source.length; i++) {
  1.3263 +      event = source[i];
  1.3264 +      if (allowSelectionOnly ? event.ranges && !event.equals(doc.sel) : !event.ranges)
  1.3265 +        break;
  1.3266 +    }
  1.3267 +    if (i == source.length) return;
  1.3268 +    hist.lastOrigin = hist.lastSelOrigin = null;
  1.3269 +
  1.3270 +    for (;;) {
  1.3271 +      event = source.pop();
  1.3272 +      if (event.ranges) {
  1.3273 +        pushSelectionToHistory(event, dest);
  1.3274 +        if (allowSelectionOnly && !event.equals(doc.sel)) {
  1.3275 +          setSelection(doc, event, {clearRedo: false});
  1.3276 +          return;
  1.3277 +        }
  1.3278 +        selAfter = event;
  1.3279 +      }
  1.3280 +      else break;
  1.3281 +    }
  1.3282 +
  1.3283 +    // Build up a reverse change object to add to the opposite history
  1.3284 +    // stack (redo when undoing, and vice versa).
  1.3285 +    var antiChanges = [];
  1.3286 +    pushSelectionToHistory(selAfter, dest);
  1.3287 +    dest.push({changes: antiChanges, generation: hist.generation});
  1.3288 +    hist.generation = event.generation || ++hist.maxGeneration;
  1.3289 +
  1.3290 +    var filter = hasHandler(doc, "beforeChange") || doc.cm && hasHandler(doc.cm, "beforeChange");
  1.3291 +
  1.3292 +    for (var i = event.changes.length - 1; i >= 0; --i) {
  1.3293 +      var change = event.changes[i];
  1.3294 +      change.origin = type;
  1.3295 +      if (filter && !filterChange(doc, change, false)) {
  1.3296 +        source.length = 0;
  1.3297 +        return;
  1.3298 +      }
  1.3299 +
  1.3300 +      antiChanges.push(historyChangeFromChange(doc, change));
  1.3301 +
  1.3302 +      var after = i ? computeSelAfterChange(doc, change, null) : lst(source);
  1.3303 +      makeChangeSingleDoc(doc, change, after, mergeOldSpans(doc, change));
  1.3304 +      if (doc.cm) ensureCursorVisible(doc.cm);
  1.3305 +      var rebased = [];
  1.3306 +
  1.3307 +      // Propagate to the linked documents
  1.3308 +      linkedDocs(doc, function(doc, sharedHist) {
  1.3309 +        if (!sharedHist && indexOf(rebased, doc.history) == -1) {
  1.3310 +          rebaseHist(doc.history, change);
  1.3311 +          rebased.push(doc.history);
  1.3312 +        }
  1.3313 +        makeChangeSingleDoc(doc, change, null, mergeOldSpans(doc, change));
  1.3314 +      });
  1.3315 +    }
  1.3316 +  }
  1.3317 +
  1.3318 +  // Sub-views need their line numbers shifted when text is added
  1.3319 +  // above or below them in the parent document.
  1.3320 +  function shiftDoc(doc, distance) {
  1.3321 +    doc.first += distance;
  1.3322 +    doc.sel = new Selection(map(doc.sel.ranges, function(range) {
  1.3323 +      return new Range(Pos(range.anchor.line + distance, range.anchor.ch),
  1.3324 +                       Pos(range.head.line + distance, range.head.ch));
  1.3325 +    }), doc.sel.primIndex);
  1.3326 +    if (doc.cm) regChange(doc.cm, doc.first, doc.first - distance, distance);
  1.3327 +  }
  1.3328 +
  1.3329 +  // More lower-level change function, handling only a single document
  1.3330 +  // (not linked ones).
  1.3331 +  function makeChangeSingleDoc(doc, change, selAfter, spans) {
  1.3332 +    if (doc.cm && !doc.cm.curOp)
  1.3333 +      return operation(doc.cm, makeChangeSingleDoc)(doc, change, selAfter, spans);
  1.3334 +
  1.3335 +    if (change.to.line < doc.first) {
  1.3336 +      shiftDoc(doc, change.text.length - 1 - (change.to.line - change.from.line));
  1.3337 +      return;
  1.3338 +    }
  1.3339 +    if (change.from.line > doc.lastLine()) return;
  1.3340 +
  1.3341 +    // Clip the change to the size of this doc
  1.3342 +    if (change.from.line < doc.first) {
  1.3343 +      var shift = change.text.length - 1 - (doc.first - change.from.line);
  1.3344 +      shiftDoc(doc, shift);
  1.3345 +      change = {from: Pos(doc.first, 0), to: Pos(change.to.line + shift, change.to.ch),
  1.3346 +                text: [lst(change.text)], origin: change.origin};
  1.3347 +    }
  1.3348 +    var last = doc.lastLine();
  1.3349 +    if (change.to.line > last) {
  1.3350 +      change = {from: change.from, to: Pos(last, getLine(doc, last).text.length),
  1.3351 +                text: [change.text[0]], origin: change.origin};
  1.3352 +    }
  1.3353 +
  1.3354 +    change.removed = getBetween(doc, change.from, change.to);
  1.3355 +
  1.3356 +    if (!selAfter) selAfter = computeSelAfterChange(doc, change, null);
  1.3357 +    if (doc.cm) makeChangeSingleDocInEditor(doc.cm, change, spans);
  1.3358 +    else updateDoc(doc, change, spans);
  1.3359 +    setSelectionNoUndo(doc, selAfter, sel_dontScroll);
  1.3360 +  }
  1.3361 +
  1.3362 +  // Handle the interaction of a change to a document with the editor
  1.3363 +  // that this document is part of.
  1.3364 +  function makeChangeSingleDocInEditor(cm, change, spans) {
  1.3365 +    var doc = cm.doc, display = cm.display, from = change.from, to = change.to;
  1.3366 +
  1.3367 +    var recomputeMaxLength = false, checkWidthStart = from.line;
  1.3368 +    if (!cm.options.lineWrapping) {
  1.3369 +      checkWidthStart = lineNo(visualLine(getLine(doc, from.line)));
  1.3370 +      doc.iter(checkWidthStart, to.line + 1, function(line) {
  1.3371 +        if (line == display.maxLine) {
  1.3372 +          recomputeMaxLength = true;
  1.3373 +          return true;
  1.3374 +        }
  1.3375 +      });
  1.3376 +    }
  1.3377 +
  1.3378 +    if (doc.sel.contains(change.from, change.to) > -1)
  1.3379 +      cm.curOp.cursorActivity = true;
  1.3380 +
  1.3381 +    updateDoc(doc, change, spans, estimateHeight(cm));
  1.3382 +
  1.3383 +    if (!cm.options.lineWrapping) {
  1.3384 +      doc.iter(checkWidthStart, from.line + change.text.length, function(line) {
  1.3385 +        var len = lineLength(line);
  1.3386 +        if (len > display.maxLineLength) {
  1.3387 +          display.maxLine = line;
  1.3388 +          display.maxLineLength = len;
  1.3389 +          display.maxLineChanged = true;
  1.3390 +          recomputeMaxLength = false;
  1.3391 +        }
  1.3392 +      });
  1.3393 +      if (recomputeMaxLength) cm.curOp.updateMaxLine = true;
  1.3394 +    }
  1.3395 +
  1.3396 +    // Adjust frontier, schedule worker
  1.3397 +    doc.frontier = Math.min(doc.frontier, from.line);
  1.3398 +    startWorker(cm, 400);
  1.3399 +
  1.3400 +    var lendiff = change.text.length - (to.line - from.line) - 1;
  1.3401 +    // Remember that these lines changed, for updating the display
  1.3402 +    if (from.line == to.line && change.text.length == 1 && !isWholeLineUpdate(cm.doc, change))
  1.3403 +      regLineChange(cm, from.line, "text");
  1.3404 +    else
  1.3405 +      regChange(cm, from.line, to.line + 1, lendiff);
  1.3406 +
  1.3407 +    if (hasHandler(cm, "change") || hasHandler(cm, "changes"))
  1.3408 +      (cm.curOp.changeObjs || (cm.curOp.changeObjs = [])).push({
  1.3409 +        from: from, to: to,
  1.3410 +        text: change.text,
  1.3411 +        removed: change.removed,
  1.3412 +        origin: change.origin
  1.3413 +      });
  1.3414 +  }
  1.3415 +
  1.3416 +  function replaceRange(doc, code, from, to, origin) {
  1.3417 +    if (!to) to = from;
  1.3418 +    if (cmp(to, from) < 0) { var tmp = to; to = from; from = tmp; }
  1.3419 +    if (typeof code == "string") code = splitLines(code);
  1.3420 +    makeChange(doc, {from: from, to: to, text: code, origin: origin});
  1.3421 +  }
  1.3422 +
  1.3423 +  // SCROLLING THINGS INTO VIEW
  1.3424 +
  1.3425 +  // If an editor sits on the top or bottom of the window, partially
  1.3426 +  // scrolled out of view, this ensures that the cursor is visible.
  1.3427 +  function maybeScrollWindow(cm, coords) {
  1.3428 +    var display = cm.display, box = display.sizer.getBoundingClientRect(), doScroll = null;
  1.3429 +    if (coords.top + box.top < 0) doScroll = true;
  1.3430 +    else if (coords.bottom + box.top > (window.innerHeight || document.documentElement.clientHeight)) doScroll = false;
  1.3431 +    if (doScroll != null && !phantom) {
  1.3432 +      var scrollNode = elt("div", "\u200b", null, "position: absolute; top: " +
  1.3433 +                           (coords.top - display.viewOffset - paddingTop(cm.display)) + "px; height: " +
  1.3434 +                           (coords.bottom - coords.top + scrollerCutOff) + "px; left: " +
  1.3435 +                           coords.left + "px; width: 2px;");
  1.3436 +      cm.display.lineSpace.appendChild(scrollNode);
  1.3437 +      scrollNode.scrollIntoView(doScroll);
  1.3438 +      cm.display.lineSpace.removeChild(scrollNode);
  1.3439 +    }
  1.3440 +  }
  1.3441 +
  1.3442 +  // Scroll a given position into view (immediately), verifying that
  1.3443 +  // it actually became visible (as line heights are accurately
  1.3444 +  // measured, the position of something may 'drift' during drawing).
  1.3445 +  function scrollPosIntoView(cm, pos, end, margin) {
  1.3446 +    if (margin == null) margin = 0;
  1.3447 +    for (;;) {
  1.3448 +      var changed = false, coords = cursorCoords(cm, pos);
  1.3449 +      var endCoords = !end || end == pos ? coords : cursorCoords(cm, end);
  1.3450 +      var scrollPos = calculateScrollPos(cm, Math.min(coords.left, endCoords.left),
  1.3451 +                                         Math.min(coords.top, endCoords.top) - margin,
  1.3452 +                                         Math.max(coords.left, endCoords.left),
  1.3453 +                                         Math.max(coords.bottom, endCoords.bottom) + margin);
  1.3454 +      var startTop = cm.doc.scrollTop, startLeft = cm.doc.scrollLeft;
  1.3455 +      if (scrollPos.scrollTop != null) {
  1.3456 +        setScrollTop(cm, scrollPos.scrollTop);
  1.3457 +        if (Math.abs(cm.doc.scrollTop - startTop) > 1) changed = true;
  1.3458 +      }
  1.3459 +      if (scrollPos.scrollLeft != null) {
  1.3460 +        setScrollLeft(cm, scrollPos.scrollLeft);
  1.3461 +        if (Math.abs(cm.doc.scrollLeft - startLeft) > 1) changed = true;
  1.3462 +      }
  1.3463 +      if (!changed) return coords;
  1.3464 +    }
  1.3465 +  }
  1.3466 +
  1.3467 +  // Scroll a given set of coordinates into view (immediately).
  1.3468 +  function scrollIntoView(cm, x1, y1, x2, y2) {
  1.3469 +    var scrollPos = calculateScrollPos(cm, x1, y1, x2, y2);
  1.3470 +    if (scrollPos.scrollTop != null) setScrollTop(cm, scrollPos.scrollTop);
  1.3471 +    if (scrollPos.scrollLeft != null) setScrollLeft(cm, scrollPos.scrollLeft);
  1.3472 +  }
  1.3473 +
  1.3474 +  // Calculate a new scroll position needed to scroll the given
  1.3475 +  // rectangle into view. Returns an object with scrollTop and
  1.3476 +  // scrollLeft properties. When these are undefined, the
  1.3477 +  // vertical/horizontal position does not need to be adjusted.
  1.3478 +  function calculateScrollPos(cm, x1, y1, x2, y2) {
  1.3479 +    var display = cm.display, snapMargin = textHeight(cm.display);
  1.3480 +    if (y1 < 0) y1 = 0;
  1.3481 +    var screentop = cm.curOp && cm.curOp.scrollTop != null ? cm.curOp.scrollTop : display.scroller.scrollTop;
  1.3482 +    var screen = display.scroller.clientHeight - scrollerCutOff, result = {};
  1.3483 +    var docBottom = cm.doc.height + paddingVert(display);
  1.3484 +    var atTop = y1 < snapMargin, atBottom = y2 > docBottom - snapMargin;
  1.3485 +    if (y1 < screentop) {
  1.3486 +      result.scrollTop = atTop ? 0 : y1;
  1.3487 +    } else if (y2 > screentop + screen) {
  1.3488 +      var newTop = Math.min(y1, (atBottom ? docBottom : y2) - screen);
  1.3489 +      if (newTop != screentop) result.scrollTop = newTop;
  1.3490 +    }
  1.3491 +
  1.3492 +    var screenleft = cm.curOp && cm.curOp.scrollLeft != null ? cm.curOp.scrollLeft : display.scroller.scrollLeft;
  1.3493 +    var screenw = display.scroller.clientWidth - scrollerCutOff;
  1.3494 +    x1 += display.gutters.offsetWidth; x2 += display.gutters.offsetWidth;
  1.3495 +    var gutterw = display.gutters.offsetWidth;
  1.3496 +    var atLeft = x1 < gutterw + 10;
  1.3497 +    if (x1 < screenleft + gutterw || atLeft) {
  1.3498 +      if (atLeft) x1 = 0;
  1.3499 +      result.scrollLeft = Math.max(0, x1 - 10 - gutterw);
  1.3500 +    } else if (x2 > screenw + screenleft - 3) {
  1.3501 +      result.scrollLeft = x2 + 10 - screenw;
  1.3502 +    }
  1.3503 +    return result;
  1.3504 +  }
  1.3505 +
  1.3506 +  // Store a relative adjustment to the scroll position in the current
  1.3507 +  // operation (to be applied when the operation finishes).
  1.3508 +  function addToScrollPos(cm, left, top) {
  1.3509 +    if (left != null || top != null) resolveScrollToPos(cm);
  1.3510 +    if (left != null)
  1.3511 +      cm.curOp.scrollLeft = (cm.curOp.scrollLeft == null ? cm.doc.scrollLeft : cm.curOp.scrollLeft) + left;
  1.3512 +    if (top != null)
  1.3513 +      cm.curOp.scrollTop = (cm.curOp.scrollTop == null ? cm.doc.scrollTop : cm.curOp.scrollTop) + top;
  1.3514 +  }
  1.3515 +
  1.3516 +  // Make sure that at the end of the operation the current cursor is
  1.3517 +  // shown.
  1.3518 +  function ensureCursorVisible(cm) {
  1.3519 +    resolveScrollToPos(cm);
  1.3520 +    var cur = cm.getCursor(), from = cur, to = cur;
  1.3521 +    if (!cm.options.lineWrapping) {
  1.3522 +      from = cur.ch ? Pos(cur.line, cur.ch - 1) : cur;
  1.3523 +      to = Pos(cur.line, cur.ch + 1);
  1.3524 +    }
  1.3525 +    cm.curOp.scrollToPos = {from: from, to: to, margin: cm.options.cursorScrollMargin, isCursor: true};
  1.3526 +  }
  1.3527 +
  1.3528 +  // When an operation has its scrollToPos property set, and another
  1.3529 +  // scroll action is applied before the end of the operation, this
  1.3530 +  // 'simulates' scrolling that position into view in a cheap way, so
  1.3531 +  // that the effect of intermediate scroll commands is not ignored.
  1.3532 +  function resolveScrollToPos(cm) {
  1.3533 +    var range = cm.curOp.scrollToPos;
  1.3534 +    if (range) {
  1.3535 +      cm.curOp.scrollToPos = null;
  1.3536 +      var from = estimateCoords(cm, range.from), to = estimateCoords(cm, range.to);
  1.3537 +      var sPos = calculateScrollPos(cm, Math.min(from.left, to.left),
  1.3538 +                                    Math.min(from.top, to.top) - range.margin,
  1.3539 +                                    Math.max(from.right, to.right),
  1.3540 +                                    Math.max(from.bottom, to.bottom) + range.margin);
  1.3541 +      cm.scrollTo(sPos.scrollLeft, sPos.scrollTop);
  1.3542 +    }
  1.3543 +  }
  1.3544 +
  1.3545 +  // API UTILITIES
  1.3546 +
  1.3547 +  // Indent the given line. The how parameter can be "smart",
  1.3548 +  // "add"/null, "subtract", or "prev". When aggressive is false
  1.3549 +  // (typically set to true for forced single-line indents), empty
  1.3550 +  // lines are not indented, and places where the mode returns Pass
  1.3551 +  // are left alone.
  1.3552 +  function indentLine(cm, n, how, aggressive) {
  1.3553 +    var doc = cm.doc, state;
  1.3554 +    if (how == null) how = "add";
  1.3555 +    if (how == "smart") {
  1.3556 +      // Fall back to "prev" when the mode doesn't have an indentation
  1.3557 +      // method.
  1.3558 +      if (!cm.doc.mode.indent) how = "prev";
  1.3559 +      else state = getStateBefore(cm, n);
  1.3560 +    }
  1.3561 +
  1.3562 +    var tabSize = cm.options.tabSize;
  1.3563 +    var line = getLine(doc, n), curSpace = countColumn(line.text, null, tabSize);
  1.3564 +    if (line.stateAfter) line.stateAfter = null;
  1.3565 +    var curSpaceString = line.text.match(/^\s*/)[0], indentation;
  1.3566 +    if (!aggressive && !/\S/.test(line.text)) {
  1.3567 +      indentation = 0;
  1.3568 +      how = "not";
  1.3569 +    } else if (how == "smart") {
  1.3570 +      indentation = cm.doc.mode.indent(state, line.text.slice(curSpaceString.length), line.text);
  1.3571 +      if (indentation == Pass) {
  1.3572 +        if (!aggressive) return;
  1.3573 +        how = "prev";
  1.3574 +      }
  1.3575 +    }
  1.3576 +    if (how == "prev") {
  1.3577 +      if (n > doc.first) indentation = countColumn(getLine(doc, n-1).text, null, tabSize);
  1.3578 +      else indentation = 0;
  1.3579 +    } else if (how == "add") {
  1.3580 +      indentation = curSpace + cm.options.indentUnit;
  1.3581 +    } else if (how == "subtract") {
  1.3582 +      indentation = curSpace - cm.options.indentUnit;
  1.3583 +    } else if (typeof how == "number") {
  1.3584 +      indentation = curSpace + how;
  1.3585 +    }
  1.3586 +    indentation = Math.max(0, indentation);
  1.3587 +
  1.3588 +    var indentString = "", pos = 0;
  1.3589 +    if (cm.options.indentWithTabs)
  1.3590 +      for (var i = Math.floor(indentation / tabSize); i; --i) {pos += tabSize; indentString += "\t";}
  1.3591 +    if (pos < indentation) indentString += spaceStr(indentation - pos);
  1.3592 +
  1.3593 +    if (indentString != curSpaceString) {
  1.3594 +      replaceRange(cm.doc, indentString, Pos(n, 0), Pos(n, curSpaceString.length), "+input");
  1.3595 +    } else {
  1.3596 +      // Ensure that, if the cursor was in the whitespace at the start
  1.3597 +      // of the line, it is moved to the end of that space.
  1.3598 +      for (var i = 0; i < doc.sel.ranges.length; i++) {
  1.3599 +        var range = doc.sel.ranges[i];
  1.3600 +        if (range.head.line == n && range.head.ch < curSpaceString.length) {
  1.3601 +          var pos = Pos(n, curSpaceString.length);
  1.3602 +          replaceOneSelection(doc, i, new Range(pos, pos));
  1.3603 +          break;
  1.3604 +        }
  1.3605 +      }
  1.3606 +    }
  1.3607 +    line.stateAfter = null;
  1.3608 +  }
  1.3609 +
  1.3610 +  // Utility for applying a change to a line by handle or number,
  1.3611 +  // returning the number and optionally registering the line as
  1.3612 +  // changed.
  1.3613 +  function changeLine(cm, handle, changeType, op) {
  1.3614 +    var no = handle, line = handle, doc = cm.doc;
  1.3615 +    if (typeof handle == "number") line = getLine(doc, clipLine(doc, handle));
  1.3616 +    else no = lineNo(handle);
  1.3617 +    if (no == null) return null;
  1.3618 +    if (op(line, no)) regLineChange(cm, no, changeType);
  1.3619 +    else return null;
  1.3620 +    return line;
  1.3621 +  }
  1.3622 +
  1.3623 +  // Helper for deleting text near the selection(s), used to implement
  1.3624 +  // backspace, delete, and similar functionality.
  1.3625 +  function deleteNearSelection(cm, compute) {
  1.3626 +    var ranges = cm.doc.sel.ranges, kill = [];
  1.3627 +    // Build up a set of ranges to kill first, merging overlapping
  1.3628 +    // ranges.
  1.3629 +    for (var i = 0; i < ranges.length; i++) {
  1.3630 +      var toKill = compute(ranges[i]);
  1.3631 +      while (kill.length && cmp(toKill.from, lst(kill).to) <= 0) {
  1.3632 +        var replaced = kill.pop();
  1.3633 +        if (cmp(replaced.from, toKill.from) < 0) {
  1.3634 +          toKill.from = replaced.from;
  1.3635 +          break;
  1.3636 +        }
  1.3637 +      }
  1.3638 +      kill.push(toKill);
  1.3639 +    }
  1.3640 +    // Next, remove those actual ranges.
  1.3641 +    runInOp(cm, function() {
  1.3642 +      for (var i = kill.length - 1; i >= 0; i--)
  1.3643 +        replaceRange(cm.doc, "", kill[i].from, kill[i].to, "+delete");
  1.3644 +      ensureCursorVisible(cm);
  1.3645 +    });
  1.3646 +  }
  1.3647 +
  1.3648 +  // Used for horizontal relative motion. Dir is -1 or 1 (left or
  1.3649 +  // right), unit can be "char", "column" (like char, but doesn't
  1.3650 +  // cross line boundaries), "word" (across next word), or "group" (to
  1.3651 +  // the start of next group of word or non-word-non-whitespace
  1.3652 +  // chars). The visually param controls whether, in right-to-left
  1.3653 +  // text, direction 1 means to move towards the next index in the
  1.3654 +  // string, or towards the character to the right of the current
  1.3655 +  // position. The resulting position will have a hitSide=true
  1.3656 +  // property if it reached the end of the document.
  1.3657 +  function findPosH(doc, pos, dir, unit, visually) {
  1.3658 +    var line = pos.line, ch = pos.ch, origDir = dir;
  1.3659 +    var lineObj = getLine(doc, line);
  1.3660 +    var possible = true;
  1.3661 +    function findNextLine() {
  1.3662 +      var l = line + dir;
  1.3663 +      if (l < doc.first || l >= doc.first + doc.size) return (possible = false);
  1.3664 +      line = l;
  1.3665 +      return lineObj = getLine(doc, l);
  1.3666 +    }
  1.3667 +    function moveOnce(boundToLine) {
  1.3668 +      var next = (visually ? moveVisually : moveLogically)(lineObj, ch, dir, true);
  1.3669 +      if (next == null) {
  1.3670 +        if (!boundToLine && findNextLine()) {
  1.3671 +          if (visually) ch = (dir < 0 ? lineRight : lineLeft)(lineObj);
  1.3672 +          else ch = dir < 0 ? lineObj.text.length : 0;
  1.3673 +        } else return (possible = false);
  1.3674 +      } else ch = next;
  1.3675 +      return true;
  1.3676 +    }
  1.3677 +
  1.3678 +    if (unit == "char") moveOnce();
  1.3679 +    else if (unit == "column") moveOnce(true);
  1.3680 +    else if (unit == "word" || unit == "group") {
  1.3681 +      var sawType = null, group = unit == "group";
  1.3682 +      for (var first = true;; first = false) {
  1.3683 +        if (dir < 0 && !moveOnce(!first)) break;
  1.3684 +        var cur = lineObj.text.charAt(ch) || "\n";
  1.3685 +        var type = isWordChar(cur) ? "w"
  1.3686 +          : group && cur == "\n" ? "n"
  1.3687 +          : !group || /\s/.test(cur) ? null
  1.3688 +          : "p";
  1.3689 +        if (group && !first && !type) type = "s";
  1.3690 +        if (sawType && sawType != type) {
  1.3691 +          if (dir < 0) {dir = 1; moveOnce();}
  1.3692 +          break;
  1.3693 +        }
  1.3694 +
  1.3695 +        if (type) sawType = type;
  1.3696 +        if (dir > 0 && !moveOnce(!first)) break;
  1.3697 +      }
  1.3698 +    }
  1.3699 +    var result = skipAtomic(doc, Pos(line, ch), origDir, true);
  1.3700 +    if (!possible) result.hitSide = true;
  1.3701 +    return result;
  1.3702 +  }
  1.3703 +
  1.3704 +  // For relative vertical movement. Dir may be -1 or 1. Unit can be
  1.3705 +  // "page" or "line". The resulting position will have a hitSide=true
  1.3706 +  // property if it reached the end of the document.
  1.3707 +  function findPosV(cm, pos, dir, unit) {
  1.3708 +    var doc = cm.doc, x = pos.left, y;
  1.3709 +    if (unit == "page") {
  1.3710 +      var pageSize = Math.min(cm.display.wrapper.clientHeight, window.innerHeight || document.documentElement.clientHeight);
  1.3711 +      y = pos.top + dir * (pageSize - (dir < 0 ? 1.5 : .5) * textHeight(cm.display));
  1.3712 +    } else if (unit == "line") {
  1.3713 +      y = dir > 0 ? pos.bottom + 3 : pos.top - 3;
  1.3714 +    }
  1.3715 +    for (;;) {
  1.3716 +      var target = coordsChar(cm, x, y);
  1.3717 +      if (!target.outside) break;
  1.3718 +      if (dir < 0 ? y <= 0 : y >= doc.height) { target.hitSide = true; break; }
  1.3719 +      y += dir * 5;
  1.3720 +    }
  1.3721 +    return target;
  1.3722 +  }
  1.3723 +
  1.3724 +  // Find the word at the given position (as returned by coordsChar).
  1.3725 +  function findWordAt(doc, pos) {
  1.3726 +    var line = getLine(doc, pos.line).text;
  1.3727 +    var start = pos.ch, end = pos.ch;
  1.3728 +    if (line) {
  1.3729 +      if ((pos.xRel < 0 || end == line.length) && start) --start; else ++end;
  1.3730 +      var startChar = line.charAt(start);
  1.3731 +      var check = isWordChar(startChar) ? isWordChar
  1.3732 +        : /\s/.test(startChar) ? function(ch) {return /\s/.test(ch);}
  1.3733 +        : function(ch) {return !/\s/.test(ch) && !isWordChar(ch);};
  1.3734 +      while (start > 0 && check(line.charAt(start - 1))) --start;
  1.3735 +      while (end < line.length && check(line.charAt(end))) ++end;
  1.3736 +    }
  1.3737 +    return new Range(Pos(pos.line, start), Pos(pos.line, end));
  1.3738 +  }
  1.3739 +
  1.3740 +  // EDITOR METHODS
  1.3741 +
  1.3742 +  // The publicly visible API. Note that methodOp(f) means
  1.3743 +  // 'wrap f in an operation, performed on its `this` parameter'.
  1.3744 +
  1.3745 +  // This is not the complete set of editor methods. Most of the
  1.3746 +  // methods defined on the Doc type are also injected into
  1.3747 +  // CodeMirror.prototype, for backwards compatibility and
  1.3748 +  // convenience.
  1.3749 +
  1.3750 +  CodeMirror.prototype = {
  1.3751 +    constructor: CodeMirror,
  1.3752 +    focus: function(){window.focus(); focusInput(this); fastPoll(this);},
  1.3753 +
  1.3754 +    setOption: function(option, value) {
  1.3755 +      var options = this.options, old = options[option];
  1.3756 +      if (options[option] == value && option != "mode") return;
  1.3757 +      options[option] = value;
  1.3758 +      if (optionHandlers.hasOwnProperty(option))
  1.3759 +        operation(this, optionHandlers[option])(this, value, old);
  1.3760 +    },
  1.3761 +
  1.3762 +    getOption: function(option) {return this.options[option];},
  1.3763 +    getDoc: function() {return this.doc;},
  1.3764 +
  1.3765 +    addKeyMap: function(map, bottom) {
  1.3766 +      this.state.keyMaps[bottom ? "push" : "unshift"](map);
  1.3767 +    },
  1.3768 +    removeKeyMap: function(map) {
  1.3769 +      var maps = this.state.keyMaps;
  1.3770 +      for (var i = 0; i < maps.length; ++i)
  1.3771 +        if (maps[i] == map || (typeof maps[i] != "string" && maps[i].name == map)) {
  1.3772 +          maps.splice(i, 1);
  1.3773 +          return true;
  1.3774 +        }
  1.3775 +    },
  1.3776 +
  1.3777 +    addOverlay: methodOp(function(spec, options) {
  1.3778 +      var mode = spec.token ? spec : CodeMirror.getMode(this.options, spec);
  1.3779 +      if (mode.startState) throw new Error("Overlays may not be stateful.");
  1.3780 +      this.state.overlays.push({mode: mode, modeSpec: spec, opaque: options && options.opaque});
  1.3781 +      this.state.modeGen++;
  1.3782 +      regChange(this);
  1.3783 +    }),
  1.3784 +    removeOverlay: methodOp(function(spec) {
  1.3785 +      var overlays = this.state.overlays;
  1.3786 +      for (var i = 0; i < overlays.length; ++i) {
  1.3787 +        var cur = overlays[i].modeSpec;
  1.3788 +        if (cur == spec || typeof spec == "string" && cur.name == spec) {
  1.3789 +          overlays.splice(i, 1);
  1.3790 +          this.state.modeGen++;
  1.3791 +          regChange(this);
  1.3792 +          return;
  1.3793 +        }
  1.3794 +      }
  1.3795 +    }),
  1.3796 +
  1.3797 +    indentLine: methodOp(function(n, dir, aggressive) {
  1.3798 +      if (typeof dir != "string" && typeof dir != "number") {
  1.3799 +        if (dir == null) dir = this.options.smartIndent ? "smart" : "prev";
  1.3800 +        else dir = dir ? "add" : "subtract";
  1.3801 +      }
  1.3802 +      if (isLine(this.doc, n)) indentLine(this, n, dir, aggressive);
  1.3803 +    }),
  1.3804 +    indentSelection: methodOp(function(how) {
  1.3805 +      var ranges = this.doc.sel.ranges, end = -1;
  1.3806 +      for (var i = 0; i < ranges.length; i++) {
  1.3807 +        var range = ranges[i];
  1.3808 +        if (!range.empty()) {
  1.3809 +          var start = Math.max(end, range.from().line);
  1.3810 +          var to = range.to();
  1.3811 +          end = Math.min(this.lastLine(), to.line - (to.ch ? 0 : 1)) + 1;
  1.3812 +          for (var j = start; j < end; ++j)
  1.3813 +            indentLine(this, j, how);
  1.3814 +        } else if (range.head.line > end) {
  1.3815 +          indentLine(this, range.head.line, how, true);
  1.3816 +          end = range.head.line;
  1.3817 +          if (i == this.doc.sel.primIndex) ensureCursorVisible(this);
  1.3818 +        }
  1.3819 +      }
  1.3820 +    }),
  1.3821 +
  1.3822 +    // Fetch the parser token for a given character. Useful for hacks
  1.3823 +    // that want to inspect the mode state (say, for completion).
  1.3824 +    getTokenAt: function(pos, precise) {
  1.3825 +      var doc = this.doc;
  1.3826 +      pos = clipPos(doc, pos);
  1.3827 +      var state = getStateBefore(this, pos.line, precise), mode = this.doc.mode;
  1.3828 +      var line = getLine(doc, pos.line);
  1.3829 +      var stream = new StringStream(line.text, this.options.tabSize);
  1.3830 +      while (stream.pos < pos.ch && !stream.eol()) {
  1.3831 +        stream.start = stream.pos;
  1.3832 +        var style = mode.token(stream, state);
  1.3833 +      }
  1.3834 +      return {start: stream.start,
  1.3835 +              end: stream.pos,
  1.3836 +              string: stream.current(),
  1.3837 +              type: style || null,
  1.3838 +              state: state};
  1.3839 +    },
  1.3840 +
  1.3841 +    getTokenTypeAt: function(pos) {
  1.3842 +      pos = clipPos(this.doc, pos);
  1.3843 +      var styles = getLineStyles(this, getLine(this.doc, pos.line));
  1.3844 +      var before = 0, after = (styles.length - 1) / 2, ch = pos.ch;
  1.3845 +      if (ch == 0) return styles[2];
  1.3846 +      for (;;) {
  1.3847 +        var mid = (before + after) >> 1;
  1.3848 +        if ((mid ? styles[mid * 2 - 1] : 0) >= ch) after = mid;
  1.3849 +        else if (styles[mid * 2 + 1] < ch) before = mid + 1;
  1.3850 +        else return styles[mid * 2 + 2];
  1.3851 +      }
  1.3852 +    },
  1.3853 +
  1.3854 +    getModeAt: function(pos) {
  1.3855 +      var mode = this.doc.mode;
  1.3856 +      if (!mode.innerMode) return mode;
  1.3857 +      return CodeMirror.innerMode(mode, this.getTokenAt(pos).state).mode;
  1.3858 +    },
  1.3859 +
  1.3860 +    getHelper: function(pos, type) {
  1.3861 +      return this.getHelpers(pos, type)[0];
  1.3862 +    },
  1.3863 +
  1.3864 +    getHelpers: function(pos, type) {
  1.3865 +      var found = [];
  1.3866 +      if (!helpers.hasOwnProperty(type)) return helpers;
  1.3867 +      var help = helpers[type], mode = this.getModeAt(pos);
  1.3868 +      if (typeof mode[type] == "string") {
  1.3869 +        if (help[mode[type]]) found.push(help[mode[type]]);
  1.3870 +      } else if (mode[type]) {
  1.3871 +        for (var i = 0; i < mode[type].length; i++) {
  1.3872 +          var val = help[mode[type][i]];
  1.3873 +          if (val) found.push(val);
  1.3874 +        }
  1.3875 +      } else if (mode.helperType && help[mode.helperType]) {
  1.3876 +        found.push(help[mode.helperType]);
  1.3877 +      } else if (help[mode.name]) {
  1.3878 +        found.push(help[mode.name]);
  1.3879 +      }
  1.3880 +      for (var i = 0; i < help._global.length; i++) {
  1.3881 +        var cur = help._global[i];
  1.3882 +        if (cur.pred(mode, this) && indexOf(found, cur.val) == -1)
  1.3883 +          found.push(cur.val);
  1.3884 +      }
  1.3885 +      return found;
  1.3886 +    },
  1.3887 +
  1.3888 +    getStateAfter: function(line, precise) {
  1.3889 +      var doc = this.doc;
  1.3890 +      line = clipLine(doc, line == null ? doc.first + doc.size - 1: line);
  1.3891 +      return getStateBefore(this, line + 1, precise);
  1.3892 +    },
  1.3893 +
  1.3894 +    cursorCoords: function(start, mode) {
  1.3895 +      var pos, range = this.doc.sel.primary();
  1.3896 +      if (start == null) pos = range.head;
  1.3897 +      else if (typeof start == "object") pos = clipPos(this.doc, start);
  1.3898 +      else pos = start ? range.from() : range.to();
  1.3899 +      return cursorCoords(this, pos, mode || "page");
  1.3900 +    },
  1.3901 +
  1.3902 +    charCoords: function(pos, mode) {
  1.3903 +      return charCoords(this, clipPos(this.doc, pos), mode || "page");
  1.3904 +    },
  1.3905 +
  1.3906 +    coordsChar: function(coords, mode) {
  1.3907 +      coords = fromCoordSystem(this, coords, mode || "page");
  1.3908 +      return coordsChar(this, coords.left, coords.top);
  1.3909 +    },
  1.3910 +
  1.3911 +    lineAtHeight: function(height, mode) {
  1.3912 +      height = fromCoordSystem(this, {top: height, left: 0}, mode || "page").top;
  1.3913 +      return lineAtHeight(this.doc, height + this.display.viewOffset);
  1.3914 +    },
  1.3915 +    heightAtLine: function(line, mode) {
  1.3916 +      var end = false, last = this.doc.first + this.doc.size - 1;
  1.3917 +      if (line < this.doc.first) line = this.doc.first;
  1.3918 +      else if (line > last) { line = last; end = true; }
  1.3919 +      var lineObj = getLine(this.doc, line);
  1.3920 +      return intoCoordSystem(this, lineObj, {top: 0, left: 0}, mode || "page").top +
  1.3921 +        (end ? this.doc.height - heightAtLine(lineObj) : 0);
  1.3922 +    },
  1.3923 +
  1.3924 +    defaultTextHeight: function() { return textHeight(this.display); },
  1.3925 +    defaultCharWidth: function() { return charWidth(this.display); },
  1.3926 +
  1.3927 +    setGutterMarker: methodOp(function(line, gutterID, value) {
  1.3928 +      return changeLine(this, line, "gutter", function(line) {
  1.3929 +        var markers = line.gutterMarkers || (line.gutterMarkers = {});
  1.3930 +        markers[gutterID] = value;
  1.3931 +        if (!value && isEmpty(markers)) line.gutterMarkers = null;
  1.3932 +        return true;
  1.3933 +      });
  1.3934 +    }),
  1.3935 +
  1.3936 +    clearGutter: methodOp(function(gutterID) {
  1.3937 +      var cm = this, doc = cm.doc, i = doc.first;
  1.3938 +      doc.iter(function(line) {
  1.3939 +        if (line.gutterMarkers && line.gutterMarkers[gutterID]) {
  1.3940 +          line.gutterMarkers[gutterID] = null;
  1.3941 +          regLineChange(cm, i, "gutter");
  1.3942 +          if (isEmpty(line.gutterMarkers)) line.gutterMarkers = null;
  1.3943 +        }
  1.3944 +        ++i;
  1.3945 +      });
  1.3946 +    }),
  1.3947 +
  1.3948 +    addLineClass: methodOp(function(handle, where, cls) {
  1.3949 +      return changeLine(this, handle, "class", function(line) {
  1.3950 +        var prop = where == "text" ? "textClass" : where == "background" ? "bgClass" : "wrapClass";
  1.3951 +        if (!line[prop]) line[prop] = cls;
  1.3952 +        else if (new RegExp("(?:^|\\s)" + cls + "(?:$|\\s)").test(line[prop])) return false;
  1.3953 +        else line[prop] += " " + cls;
  1.3954 +        return true;
  1.3955 +      });
  1.3956 +    }),
  1.3957 +
  1.3958 +    removeLineClass: methodOp(function(handle, where, cls) {
  1.3959 +      return changeLine(this, handle, "class", function(line) {
  1.3960 +        var prop = where == "text" ? "textClass" : where == "background" ? "bgClass" : "wrapClass";
  1.3961 +        var cur = line[prop];
  1.3962 +        if (!cur) return false;
  1.3963 +        else if (cls == null) line[prop] = null;
  1.3964 +        else {
  1.3965 +          var found = cur.match(new RegExp("(?:^|\\s+)" + cls + "(?:$|\\s+)"));
  1.3966 +          if (!found) return false;
  1.3967 +          var end = found.index + found[0].length;
  1.3968 +          line[prop] = cur.slice(0, found.index) + (!found.index || end == cur.length ? "" : " ") + cur.slice(end) || null;
  1.3969 +        }
  1.3970 +        return true;
  1.3971 +      });
  1.3972 +    }),
  1.3973 +
  1.3974 +    addLineWidget: methodOp(function(handle, node, options) {
  1.3975 +      return addLineWidget(this, handle, node, options);
  1.3976 +    }),
  1.3977 +
  1.3978 +    removeLineWidget: function(widget) { widget.clear(); },
  1.3979 +
  1.3980 +    lineInfo: function(line) {
  1.3981 +      if (typeof line == "number") {
  1.3982 +        if (!isLine(this.doc, line)) return null;
  1.3983 +        var n = line;
  1.3984 +        line = getLine(this.doc, line);
  1.3985 +        if (!line) return null;
  1.3986 +      } else {
  1.3987 +        var n = lineNo(line);
  1.3988 +        if (n == null) return null;
  1.3989 +      }
  1.3990 +      return {line: n, handle: line, text: line.text, gutterMarkers: line.gutterMarkers,
  1.3991 +              textClass: line.textClass, bgClass: line.bgClass, wrapClass: line.wrapClass,
  1.3992 +              widgets: line.widgets};
  1.3993 +    },
  1.3994 +
  1.3995 +    getViewport: function() { return {from: this.display.viewFrom, to: this.display.viewTo};},
  1.3996 +
  1.3997 +    addWidget: function(pos, node, scroll, vert, horiz) {
  1.3998 +      var display = this.display;
  1.3999 +      pos = cursorCoords(this, clipPos(this.doc, pos));
  1.4000 +      var top = pos.bottom, left = pos.left;
  1.4001 +      node.style.position = "absolute";
  1.4002 +      display.sizer.appendChild(node);
  1.4003 +      if (vert == "over") {
  1.4004 +        top = pos.top;
  1.4005 +      } else if (vert == "above" || vert == "near") {
  1.4006 +        var vspace = Math.max(display.wrapper.clientHeight, this.doc.height),
  1.4007 +        hspace = Math.max(display.sizer.clientWidth, display.lineSpace.clientWidth);
  1.4008 +        // Default to positioning above (if specified and possible); otherwise default to positioning below
  1.4009 +        if ((vert == 'above' || pos.bottom + node.offsetHeight > vspace) && pos.top > node.offsetHeight)
  1.4010 +          top = pos.top - node.offsetHeight;
  1.4011 +        else if (pos.bottom + node.offsetHeight <= vspace)
  1.4012 +          top = pos.bottom;
  1.4013 +        if (left + node.offsetWidth > hspace)
  1.4014 +          left = hspace - node.offsetWidth;
  1.4015 +      }
  1.4016 +      node.style.top = top + "px";
  1.4017 +      node.style.left = node.style.right = "";
  1.4018 +      if (horiz == "right") {
  1.4019 +        left = display.sizer.clientWidth - node.offsetWidth;
  1.4020 +        node.style.right = "0px";
  1.4021 +      } else {
  1.4022 +        if (horiz == "left") left = 0;
  1.4023 +        else if (horiz == "middle") left = (display.sizer.clientWidth - node.offsetWidth) / 2;
  1.4024 +        node.style.left = left + "px";
  1.4025 +      }
  1.4026 +      if (scroll)
  1.4027 +        scrollIntoView(this, left, top, left + node.offsetWidth, top + node.offsetHeight);
  1.4028 +    },
  1.4029 +
  1.4030 +    triggerOnKeyDown: methodOp(onKeyDown),
  1.4031 +    triggerOnKeyPress: methodOp(onKeyPress),
  1.4032 +    triggerOnKeyUp: methodOp(onKeyUp),
  1.4033 +
  1.4034 +    execCommand: function(cmd) {
  1.4035 +      if (commands.hasOwnProperty(cmd))
  1.4036 +        return commands[cmd](this);
  1.4037 +    },
  1.4038 +
  1.4039 +    findPosH: function(from, amount, unit, visually) {
  1.4040 +      var dir = 1;
  1.4041 +      if (amount < 0) { dir = -1; amount = -amount; }
  1.4042 +      for (var i = 0, cur = clipPos(this.doc, from); i < amount; ++i) {
  1.4043 +        cur = findPosH(this.doc, cur, dir, unit, visually);
  1.4044 +        if (cur.hitSide) break;
  1.4045 +      }
  1.4046 +      return cur;
  1.4047 +    },
  1.4048 +
  1.4049 +    moveH: methodOp(function(dir, unit) {
  1.4050 +      var cm = this;
  1.4051 +      cm.extendSelectionsBy(function(range) {
  1.4052 +        if (cm.display.shift || cm.doc.extend || range.empty())
  1.4053 +          return findPosH(cm.doc, range.head, dir, unit, cm.options.rtlMoveVisually);
  1.4054 +        else
  1.4055 +          return dir < 0 ? range.from() : range.to();
  1.4056 +      }, sel_move);
  1.4057 +    }),
  1.4058 +
  1.4059 +    deleteH: methodOp(function(dir, unit) {
  1.4060 +      var sel = this.doc.sel, doc = this.doc;
  1.4061 +      if (sel.somethingSelected())
  1.4062 +        doc.replaceSelection("", null, "+delete");
  1.4063 +      else
  1.4064 +        deleteNearSelection(this, function(range) {
  1.4065 +          var other = findPosH(doc, range.head, dir, unit, false);
  1.4066 +          return dir < 0 ? {from: other, to: range.head} : {from: range.head, to: other};
  1.4067 +        });
  1.4068 +    }),
  1.4069 +
  1.4070 +    findPosV: function(from, amount, unit, goalColumn) {
  1.4071 +      var dir = 1, x = goalColumn;
  1.4072 +      if (amount < 0) { dir = -1; amount = -amount; }
  1.4073 +      for (var i = 0, cur = clipPos(this.doc, from); i < amount; ++i) {
  1.4074 +        var coords = cursorCoords(this, cur, "div");
  1.4075 +        if (x == null) x = coords.left;
  1.4076 +        else coords.left = x;
  1.4077 +        cur = findPosV(this, coords, dir, unit);
  1.4078 +        if (cur.hitSide) break;
  1.4079 +      }
  1.4080 +      return cur;
  1.4081 +    },
  1.4082 +
  1.4083 +    moveV: methodOp(function(dir, unit) {
  1.4084 +      var cm = this, doc = this.doc, goals = [];
  1.4085 +      var collapse = !cm.display.shift && !doc.extend && doc.sel.somethingSelected();
  1.4086 +      doc.extendSelectionsBy(function(range) {
  1.4087 +        if (collapse)
  1.4088 +          return dir < 0 ? range.from() : range.to();
  1.4089 +        var headPos = cursorCoords(cm, range.head, "div");
  1.4090 +        if (range.goalColumn != null) headPos.left = range.goalColumn;
  1.4091 +        goals.push(headPos.left);
  1.4092 +        var pos = findPosV(cm, headPos, dir, unit);
  1.4093 +        if (unit == "page" && range == doc.sel.primary())
  1.4094 +          addToScrollPos(cm, null, charCoords(cm, pos, "div").top - headPos.top);
  1.4095 +        return pos;
  1.4096 +      }, sel_move);
  1.4097 +      if (goals.length) for (var i = 0; i < doc.sel.ranges.length; i++)
  1.4098 +        doc.sel.ranges[i].goalColumn = goals[i];
  1.4099 +    }),
  1.4100 +
  1.4101 +    toggleOverwrite: function(value) {
  1.4102 +      if (value != null && value == this.state.overwrite) return;
  1.4103 +      if (this.state.overwrite = !this.state.overwrite)
  1.4104 +        this.display.cursorDiv.className += " CodeMirror-overwrite";
  1.4105 +      else
  1.4106 +        this.display.cursorDiv.className = this.display.cursorDiv.className.replace(" CodeMirror-overwrite", "");
  1.4107 +
  1.4108 +      signal(this, "overwriteToggle", this, this.state.overwrite);
  1.4109 +    },
  1.4110 +    hasFocus: function() { return activeElt() == this.display.input; },
  1.4111 +
  1.4112 +    scrollTo: methodOp(function(x, y) {
  1.4113 +      if (x != null || y != null) resolveScrollToPos(this);
  1.4114 +      if (x != null) this.curOp.scrollLeft = x;
  1.4115 +      if (y != null) this.curOp.scrollTop = y;
  1.4116 +    }),
  1.4117 +    getScrollInfo: function() {
  1.4118 +      var scroller = this.display.scroller, co = scrollerCutOff;
  1.4119 +      return {left: scroller.scrollLeft, top: scroller.scrollTop,
  1.4120 +              height: scroller.scrollHeight - co, width: scroller.scrollWidth - co,
  1.4121 +              clientHeight: scroller.clientHeight - co, clientWidth: scroller.clientWidth - co};
  1.4122 +    },
  1.4123 +
  1.4124 +    scrollIntoView: methodOp(function(range, margin) {
  1.4125 +      if (range == null) {
  1.4126 +        range = {from: this.doc.sel.primary().head, to: null};
  1.4127 +        if (margin == null) margin = this.options.cursorScrollMargin;
  1.4128 +      } else if (typeof range == "number") {
  1.4129 +        range = {from: Pos(range, 0), to: null};
  1.4130 +      } else if (range.from == null) {
  1.4131 +        range = {from: range, to: null};
  1.4132 +      }
  1.4133 +      if (!range.to) range.to = range.from;
  1.4134 +      range.margin = margin || 0;
  1.4135 +
  1.4136 +      if (range.from.line != null) {
  1.4137 +        resolveScrollToPos(this);
  1.4138 +        this.curOp.scrollToPos = range;
  1.4139 +      } else {
  1.4140 +        var sPos = calculateScrollPos(this, Math.min(range.from.left, range.to.left),
  1.4141 +                                      Math.min(range.from.top, range.to.top) - range.margin,
  1.4142 +                                      Math.max(range.from.right, range.to.right),
  1.4143 +                                      Math.max(range.from.bottom, range.to.bottom) + range.margin);
  1.4144 +        this.scrollTo(sPos.scrollLeft, sPos.scrollTop);
  1.4145 +      }
  1.4146 +    }),
  1.4147 +
  1.4148 +    setSize: methodOp(function(width, height) {
  1.4149 +      function interpret(val) {
  1.4150 +        return typeof val == "number" || /^\d+$/.test(String(val)) ? val + "px" : val;
  1.4151 +      }
  1.4152 +      if (width != null) this.display.wrapper.style.width = interpret(width);
  1.4153 +      if (height != null) this.display.wrapper.style.height = interpret(height);
  1.4154 +      if (this.options.lineWrapping) clearLineMeasurementCache(this);
  1.4155 +      this.curOp.forceUpdate = true;
  1.4156 +      signal(this, "refresh", this);
  1.4157 +    }),
  1.4158 +
  1.4159 +    operation: function(f){return runInOp(this, f);},
  1.4160 +
  1.4161 +    refresh: methodOp(function() {
  1.4162 +      var oldHeight = this.display.cachedTextHeight;
  1.4163 +      regChange(this);
  1.4164 +      clearCaches(this);
  1.4165 +      this.scrollTo(this.doc.scrollLeft, this.doc.scrollTop);
  1.4166 +      if (oldHeight == null || Math.abs(oldHeight - textHeight(this.display)) > .5)
  1.4167 +        estimateLineHeights(this);
  1.4168 +      signal(this, "refresh", this);
  1.4169 +    }),
  1.4170 +
  1.4171 +    swapDoc: methodOp(function(doc) {
  1.4172 +      var old = this.doc;
  1.4173 +      old.cm = null;
  1.4174 +      attachDoc(this, doc);
  1.4175 +      clearCaches(this);
  1.4176 +      resetInput(this);
  1.4177 +      this.scrollTo(doc.scrollLeft, doc.scrollTop);
  1.4178 +      signalLater(this, "swapDoc", this, old);
  1.4179 +      return old;
  1.4180 +    }),
  1.4181 +
  1.4182 +    getInputField: function(){return this.display.input;},
  1.4183 +    getWrapperElement: function(){return this.display.wrapper;},
  1.4184 +    getScrollerElement: function(){return this.display.scroller;},
  1.4185 +    getGutterElement: function(){return this.display.gutters;}
  1.4186 +  };
  1.4187 +  eventMixin(CodeMirror);
  1.4188 +
  1.4189 +  // OPTION DEFAULTS
  1.4190 +
  1.4191 +  // The default configuration options.
  1.4192 +  var defaults = CodeMirror.defaults = {};
  1.4193 +  // Functions to run when options are changed.
  1.4194 +  var optionHandlers = CodeMirror.optionHandlers = {};
  1.4195 +
  1.4196 +  function option(name, deflt, handle, notOnInit) {
  1.4197 +    CodeMirror.defaults[name] = deflt;
  1.4198 +    if (handle) optionHandlers[name] =
  1.4199 +      notOnInit ? function(cm, val, old) {if (old != Init) handle(cm, val, old);} : handle;
  1.4200 +  }
  1.4201 +
  1.4202 +  // Passed to option handlers when there is no old value.
  1.4203 +  var Init = CodeMirror.Init = {toString: function(){return "CodeMirror.Init";}};
  1.4204 +
  1.4205 +  // These two are, on init, called from the constructor because they
  1.4206 +  // have to be initialized before the editor can start at all.
  1.4207 +  option("value", "", function(cm, val) {
  1.4208 +    cm.setValue(val);
  1.4209 +  }, true);
  1.4210 +  option("mode", null, function(cm, val) {
  1.4211 +    cm.doc.modeOption = val;
  1.4212 +    loadMode(cm);
  1.4213 +  }, true);
  1.4214 +
  1.4215 +  option("indentUnit", 2, loadMode, true);
  1.4216 +  option("indentWithTabs", false);
  1.4217 +  option("smartIndent", true);
  1.4218 +  option("tabSize", 4, function(cm) {
  1.4219 +    resetModeState(cm);
  1.4220 +    clearCaches(cm);
  1.4221 +    regChange(cm);
  1.4222 +  }, true);
  1.4223 +  option("specialChars", /[\t\u0000-\u0019\u00ad\u200b\u2028\u2029\ufeff]/g, function(cm, val) {
  1.4224 +    cm.options.specialChars = new RegExp(val.source + (val.test("\t") ? "" : "|\t"), "g");
  1.4225 +    cm.refresh();
  1.4226 +  }, true);
  1.4227 +  option("specialCharPlaceholder", defaultSpecialCharPlaceholder, function(cm) {cm.refresh();}, true);
  1.4228 +  option("electricChars", true);
  1.4229 +  option("rtlMoveVisually", !windows);
  1.4230 +  option("wholeLineUpdateBefore", true);
  1.4231 +
  1.4232 +  option("theme", "default", function(cm) {
  1.4233 +    themeChanged(cm);
  1.4234 +    guttersChanged(cm);
  1.4235 +  }, true);
  1.4236 +  option("keyMap", "default", keyMapChanged);
  1.4237 +  option("extraKeys", null);
  1.4238 +
  1.4239 +  option("lineWrapping", false, wrappingChanged, true);
  1.4240 +  option("gutters", [], function(cm) {
  1.4241 +    setGuttersForLineNumbers(cm.options);
  1.4242 +    guttersChanged(cm);
  1.4243 +  }, true);
  1.4244 +  option("fixedGutter", true, function(cm, val) {
  1.4245 +    cm.display.gutters.style.left = val ? compensateForHScroll(cm.display) + "px" : "0";
  1.4246 +    cm.refresh();
  1.4247 +  }, true);
  1.4248 +  option("coverGutterNextToScrollbar", false, updateScrollbars, true);
  1.4249 +  option("lineNumbers", false, function(cm) {
  1.4250 +    setGuttersForLineNumbers(cm.options);
  1.4251 +    guttersChanged(cm);
  1.4252 +  }, true);
  1.4253 +  option("firstLineNumber", 1, guttersChanged, true);
  1.4254 +  option("lineNumberFormatter", function(integer) {return integer;}, guttersChanged, true);
  1.4255 +  option("showCursorWhenSelecting", false, updateSelection, true);
  1.4256 +
  1.4257 +  option("resetSelectionOnContextMenu", true);
  1.4258 +
  1.4259 +  option("readOnly", false, function(cm, val) {
  1.4260 +    if (val == "nocursor") {
  1.4261 +      onBlur(cm);
  1.4262 +      cm.display.input.blur();
  1.4263 +      cm.display.disabled = true;
  1.4264 +    } else {
  1.4265 +      cm.display.disabled = false;
  1.4266 +      if (!val) resetInput(cm);
  1.4267 +    }
  1.4268 +  });
  1.4269 +  option("disableInput", false, function(cm, val) {if (!val) resetInput(cm);}, true);
  1.4270 +  option("dragDrop", true);
  1.4271 +
  1.4272 +  option("cursorBlinkRate", 530);
  1.4273 +  option("cursorScrollMargin", 0);
  1.4274 +  option("cursorHeight", 1);
  1.4275 +  option("workTime", 100);
  1.4276 +  option("workDelay", 100);
  1.4277 +  option("flattenSpans", true, resetModeState, true);
  1.4278 +  option("addModeClass", false, resetModeState, true);
  1.4279 +  option("pollInterval", 100);
  1.4280 +  option("undoDepth", 200, function(cm, val){cm.doc.history.undoDepth = val;});
  1.4281 +  option("historyEventDelay", 1250);
  1.4282 +  option("viewportMargin", 10, function(cm){cm.refresh();}, true);
  1.4283 +  option("maxHighlightLength", 10000, resetModeState, true);
  1.4284 +  option("moveInputWithCursor", true, function(cm, val) {
  1.4285 +    if (!val) cm.display.inputDiv.style.top = cm.display.inputDiv.style.left = 0;
  1.4286 +  });
  1.4287 +
  1.4288 +  option("tabindex", null, function(cm, val) {
  1.4289 +    cm.display.input.tabIndex = val || "";
  1.4290 +  });
  1.4291 +  option("autofocus", null);
  1.4292 +
  1.4293 +  // MODE DEFINITION AND QUERYING
  1.4294 +
  1.4295 +  // Known modes, by name and by MIME
  1.4296 +  var modes = CodeMirror.modes = {}, mimeModes = CodeMirror.mimeModes = {};
  1.4297 +
  1.4298 +  // Extra arguments are stored as the mode's dependencies, which is
  1.4299 +  // used by (legacy) mechanisms like loadmode.js to automatically
  1.4300 +  // load a mode. (Preferred mechanism is the require/define calls.)
  1.4301 +  CodeMirror.defineMode = function(name, mode) {
  1.4302 +    if (!CodeMirror.defaults.mode && name != "null") CodeMirror.defaults.mode = name;
  1.4303 +    if (arguments.length > 2) {
  1.4304 +      mode.dependencies = [];
  1.4305 +      for (var i = 2; i < arguments.length; ++i) mode.dependencies.push(arguments[i]);
  1.4306 +    }
  1.4307 +    modes[name] = mode;
  1.4308 +  };
  1.4309 +
  1.4310 +  CodeMirror.defineMIME = function(mime, spec) {
  1.4311 +    mimeModes[mime] = spec;
  1.4312 +  };
  1.4313 +
  1.4314 +  // Given a MIME type, a {name, ...options} config object, or a name
  1.4315 +  // string, return a mode config object.
  1.4316 +  CodeMirror.resolveMode = function(spec) {
  1.4317 +    if (typeof spec == "string" && mimeModes.hasOwnProperty(spec)) {
  1.4318 +      spec = mimeModes[spec];
  1.4319 +    } else if (spec && typeof spec.name == "string" && mimeModes.hasOwnProperty(spec.name)) {
  1.4320 +      var found = mimeModes[spec.name];
  1.4321 +      if (typeof found == "string") found = {name: found};
  1.4322 +      spec = createObj(found, spec);
  1.4323 +      spec.name = found.name;
  1.4324 +    } else if (typeof spec == "string" && /^[\w\-]+\/[\w\-]+\+xml$/.test(spec)) {
  1.4325 +      return CodeMirror.resolveMode("application/xml");
  1.4326 +    }
  1.4327 +    if (typeof spec == "string") return {name: spec};
  1.4328 +    else return spec || {name: "null"};
  1.4329 +  };
  1.4330 +
  1.4331 +  // Given a mode spec (anything that resolveMode accepts), find and
  1.4332 +  // initialize an actual mode object.
  1.4333 +  CodeMirror.getMode = function(options, spec) {
  1.4334 +    var spec = CodeMirror.resolveMode(spec);
  1.4335 +    var mfactory = modes[spec.name];
  1.4336 +    if (!mfactory) return CodeMirror.getMode(options, "text/plain");
  1.4337 +    var modeObj = mfactory(options, spec);
  1.4338 +    if (modeExtensions.hasOwnProperty(spec.name)) {
  1.4339 +      var exts = modeExtensions[spec.name];
  1.4340 +      for (var prop in exts) {
  1.4341 +        if (!exts.hasOwnProperty(prop)) continue;
  1.4342 +        if (modeObj.hasOwnProperty(prop)) modeObj["_" + prop] = modeObj[prop];
  1.4343 +        modeObj[prop] = exts[prop];
  1.4344 +      }
  1.4345 +    }
  1.4346 +    modeObj.name = spec.name;
  1.4347 +    if (spec.helperType) modeObj.helperType = spec.helperType;
  1.4348 +    if (spec.modeProps) for (var prop in spec.modeProps)
  1.4349 +      modeObj[prop] = spec.modeProps[prop];
  1.4350 +
  1.4351 +    return modeObj;
  1.4352 +  };
  1.4353 +
  1.4354 +  // Minimal default mode.
  1.4355 +  CodeMirror.defineMode("null", function() {
  1.4356 +    return {token: function(stream) {stream.skipToEnd();}};
  1.4357 +  });
  1.4358 +  CodeMirror.defineMIME("text/plain", "null");
  1.4359 +
  1.4360 +  // This can be used to attach properties to mode objects from
  1.4361 +  // outside the actual mode definition.
  1.4362 +  var modeExtensions = CodeMirror.modeExtensions = {};
  1.4363 +  CodeMirror.extendMode = function(mode, properties) {
  1.4364 +    var exts = modeExtensions.hasOwnProperty(mode) ? modeExtensions[mode] : (modeExtensions[mode] = {});
  1.4365 +    copyObj(properties, exts);
  1.4366 +  };
  1.4367 +
  1.4368 +  // EXTENSIONS
  1.4369 +
  1.4370 +  CodeMirror.defineExtension = function(name, func) {
  1.4371 +    CodeMirror.prototype[name] = func;
  1.4372 +  };
  1.4373 +  CodeMirror.defineDocExtension = function(name, func) {
  1.4374 +    Doc.prototype[name] = func;
  1.4375 +  };
  1.4376 +  CodeMirror.defineOption = option;
  1.4377 +
  1.4378 +  var initHooks = [];
  1.4379 +  CodeMirror.defineInitHook = function(f) {initHooks.push(f);};
  1.4380 +
  1.4381 +  var helpers = CodeMirror.helpers = {};
  1.4382 +  CodeMirror.registerHelper = function(type, name, value) {
  1.4383 +    if (!helpers.hasOwnProperty(type)) helpers[type] = CodeMirror[type] = {_global: []};
  1.4384 +    helpers[type][name] = value;
  1.4385 +  };
  1.4386 +  CodeMirror.registerGlobalHelper = function(type, name, predicate, value) {
  1.4387 +    CodeMirror.registerHelper(type, name, value);
  1.4388 +    helpers[type]._global.push({pred: predicate, val: value});
  1.4389 +  };
  1.4390 +
  1.4391 +  // MODE STATE HANDLING
  1.4392 +
  1.4393 +  // Utility functions for working with state. Exported because nested
  1.4394 +  // modes need to do this for their inner modes.
  1.4395 +
  1.4396 +  var copyState = CodeMirror.copyState = function(mode, state) {
  1.4397 +    if (state === true) return state;
  1.4398 +    if (mode.copyState) return mode.copyState(state);
  1.4399 +    var nstate = {};
  1.4400 +    for (var n in state) {
  1.4401 +      var val = state[n];
  1.4402 +      if (val instanceof Array) val = val.concat([]);
  1.4403 +      nstate[n] = val;
  1.4404 +    }
  1.4405 +    return nstate;
  1.4406 +  };
  1.4407 +
  1.4408 +  var startState = CodeMirror.startState = function(mode, a1, a2) {
  1.4409 +    return mode.startState ? mode.startState(a1, a2) : true;
  1.4410 +  };
  1.4411 +
  1.4412 +  // Given a mode and a state (for that mode), find the inner mode and
  1.4413 +  // state at the position that the state refers to.
  1.4414 +  CodeMirror.innerMode = function(mode, state) {
  1.4415 +    while (mode.innerMode) {
  1.4416 +      var info = mode.innerMode(state);
  1.4417 +      if (!info || info.mode == mode) break;
  1.4418 +      state = info.state;
  1.4419 +      mode = info.mode;
  1.4420 +    }
  1.4421 +    return info || {mode: mode, state: state};
  1.4422 +  };
  1.4423 +
  1.4424 +  // STANDARD COMMANDS
  1.4425 +
  1.4426 +  // Commands are parameter-less actions that can be performed on an
  1.4427 +  // editor, mostly used for keybindings.
  1.4428 +  var commands = CodeMirror.commands = {
  1.4429 +    selectAll: function(cm) {cm.setSelection(Pos(cm.firstLine(), 0), Pos(cm.lastLine()), sel_dontScroll);},
  1.4430 +    singleSelection: function(cm) {
  1.4431 +      cm.setSelection(cm.getCursor("anchor"), cm.getCursor("head"), sel_dontScroll);
  1.4432 +    },
  1.4433 +    killLine: function(cm) {
  1.4434 +      deleteNearSelection(cm, function(range) {
  1.4435 +        if (range.empty()) {
  1.4436 +          var len = getLine(cm.doc, range.head.line).text.length;
  1.4437 +          if (range.head.ch == len && range.head.line < cm.lastLine())
  1.4438 +            return {from: range.head, to: Pos(range.head.line + 1, 0)};
  1.4439 +          else
  1.4440 +            return {from: range.head, to: Pos(range.head.line, len)};
  1.4441 +        } else {
  1.4442 +          return {from: range.from(), to: range.to()};
  1.4443 +        }
  1.4444 +      });
  1.4445 +    },
  1.4446 +    deleteLine: function(cm) {
  1.4447 +      deleteNearSelection(cm, function(range) {
  1.4448 +        return {from: Pos(range.from().line, 0),
  1.4449 +                to: clipPos(cm.doc, Pos(range.to().line + 1, 0))};
  1.4450 +      });
  1.4451 +    },
  1.4452 +    delLineLeft: function(cm) {
  1.4453 +      deleteNearSelection(cm, function(range) {
  1.4454 +        return {from: Pos(range.from().line, 0), to: range.from()};
  1.4455 +      });
  1.4456 +    },
  1.4457 +    undo: function(cm) {cm.undo();},
  1.4458 +    redo: function(cm) {cm.redo();},
  1.4459 +    undoSelection: function(cm) {cm.undoSelection();},
  1.4460 +    redoSelection: function(cm) {cm.redoSelection();},
  1.4461 +    goDocStart: function(cm) {cm.extendSelection(Pos(cm.firstLine(), 0));},
  1.4462 +    goDocEnd: function(cm) {cm.extendSelection(Pos(cm.lastLine()));},
  1.4463 +    goLineStart: function(cm) {
  1.4464 +      cm.extendSelectionsBy(function(range) { return lineStart(cm, range.head.line); }, sel_move);
  1.4465 +    },
  1.4466 +    goLineStartSmart: function(cm) {
  1.4467 +      cm.extendSelectionsBy(function(range) {
  1.4468 +        var start = lineStart(cm, range.head.line);
  1.4469 +        var line = cm.getLineHandle(start.line);
  1.4470 +        var order = getOrder(line);
  1.4471 +        if (!order || order[0].level == 0) {
  1.4472 +          var firstNonWS = Math.max(0, line.text.search(/\S/));
  1.4473 +          var inWS = range.head.line == start.line && range.head.ch <= firstNonWS && range.head.ch;
  1.4474 +          return Pos(start.line, inWS ? 0 : firstNonWS);
  1.4475 +        }
  1.4476 +        return start;
  1.4477 +      }, sel_move);
  1.4478 +    },
  1.4479 +    goLineEnd: function(cm) {
  1.4480 +      cm.extendSelectionsBy(function(range) { return lineEnd(cm, range.head.line); }, sel_move);
  1.4481 +    },
  1.4482 +    goLineRight: function(cm) {
  1.4483 +      cm.extendSelectionsBy(function(range) {
  1.4484 +        var top = cm.charCoords(range.head, "div").top + 5;
  1.4485 +        return cm.coordsChar({left: cm.display.lineDiv.offsetWidth + 100, top: top}, "div");
  1.4486 +      }, sel_move);
  1.4487 +    },
  1.4488 +    goLineLeft: function(cm) {
  1.4489 +      cm.extendSelectionsBy(function(range) {
  1.4490 +        var top = cm.charCoords(range.head, "div").top + 5;
  1.4491 +        return cm.coordsChar({left: 0, top: top}, "div");
  1.4492 +      }, sel_move);
  1.4493 +    },
  1.4494 +    goLineUp: function(cm) {cm.moveV(-1, "line");},
  1.4495 +    goLineDown: function(cm) {cm.moveV(1, "line");},
  1.4496 +    goPageUp: function(cm) {cm.moveV(-1, "page");},
  1.4497 +    goPageDown: function(cm) {cm.moveV(1, "page");},
  1.4498 +    goCharLeft: function(cm) {cm.moveH(-1, "char");},
  1.4499 +    goCharRight: function(cm) {cm.moveH(1, "char");},
  1.4500 +    goColumnLeft: function(cm) {cm.moveH(-1, "column");},
  1.4501 +    goColumnRight: function(cm) {cm.moveH(1, "column");},
  1.4502 +    goWordLeft: function(cm) {cm.moveH(-1, "word");},
  1.4503 +    goGroupRight: function(cm) {cm.moveH(1, "group");},
  1.4504 +    goGroupLeft: function(cm) {cm.moveH(-1, "group");},
  1.4505 +    goWordRight: function(cm) {cm.moveH(1, "word");},
  1.4506 +    delCharBefore: function(cm) {cm.deleteH(-1, "char");},
  1.4507 +    delCharAfter: function(cm) {cm.deleteH(1, "char");},
  1.4508 +    delWordBefore: function(cm) {cm.deleteH(-1, "word");},
  1.4509 +    delWordAfter: function(cm) {cm.deleteH(1, "word");},
  1.4510 +    delGroupBefore: function(cm) {cm.deleteH(-1, "group");},
  1.4511 +    delGroupAfter: function(cm) {cm.deleteH(1, "group");},
  1.4512 +    indentAuto: function(cm) {cm.indentSelection("smart");},
  1.4513 +    indentMore: function(cm) {cm.indentSelection("add");},
  1.4514 +    indentLess: function(cm) {cm.indentSelection("subtract");},
  1.4515 +    insertTab: function(cm) {cm.replaceSelection("\t");},
  1.4516 +    defaultTab: function(cm) {
  1.4517 +      if (cm.somethingSelected()) cm.indentSelection("add");
  1.4518 +      else cm.execCommand("insertTab");
  1.4519 +    },
  1.4520 +    transposeChars: function(cm) {
  1.4521 +      runInOp(cm, function() {
  1.4522 +        var ranges = cm.listSelections();
  1.4523 +        for (var i = 0; i < ranges.length; i++) {
  1.4524 +          var cur = ranges[i].head, line = getLine(cm.doc, cur.line).text;
  1.4525 +          if (cur.ch > 0 && cur.ch < line.length - 1)
  1.4526 +            cm.replaceRange(line.charAt(cur.ch) + line.charAt(cur.ch - 1),
  1.4527 +                            Pos(cur.line, cur.ch - 1), Pos(cur.line, cur.ch + 1));
  1.4528 +        }
  1.4529 +      });
  1.4530 +    },
  1.4531 +    newlineAndIndent: function(cm) {
  1.4532 +      runInOp(cm, function() {
  1.4533 +        var len = cm.listSelections().length;
  1.4534 +        for (var i = 0; i < len; i++) {
  1.4535 +          var range = cm.listSelections()[i];
  1.4536 +          cm.replaceRange("\n", range.anchor, range.head, "+input");
  1.4537 +          cm.indentLine(range.from().line + 1, null, true);
  1.4538 +          ensureCursorVisible(cm);
  1.4539 +        }
  1.4540 +      });
  1.4541 +    },
  1.4542 +    toggleOverwrite: function(cm) {cm.toggleOverwrite();}
  1.4543 +  };
  1.4544 +
  1.4545 +  // STANDARD KEYMAPS
  1.4546 +
  1.4547 +  var keyMap = CodeMirror.keyMap = {};
  1.4548 +  keyMap.basic = {
  1.4549 +    "Left": "goCharLeft", "Right": "goCharRight", "Up": "goLineUp", "Down": "goLineDown",
  1.4550 +    "End": "goLineEnd", "Home": "goLineStartSmart", "PageUp": "goPageUp", "PageDown": "goPageDown",
  1.4551 +    "Delete": "delCharAfter", "Backspace": "delCharBefore", "Shift-Backspace": "delCharBefore",
  1.4552 +    "Tab": "defaultTab", "Shift-Tab": "indentAuto",
  1.4553 +    "Enter": "newlineAndIndent", "Insert": "toggleOverwrite",
  1.4554 +    "Esc": "singleSelection"
  1.4555 +  };
  1.4556 +  // Note that the save and find-related commands aren't defined by
  1.4557 +  // default. User code or addons can define them. Unknown commands
  1.4558 +  // are simply ignored.
  1.4559 +  keyMap.pcDefault = {
  1.4560 +    "Ctrl-A": "selectAll", "Ctrl-D": "deleteLine", "Ctrl-Z": "undo", "Shift-Ctrl-Z": "redo", "Ctrl-Y": "redo",
  1.4561 +    "Ctrl-Home": "goDocStart", "Ctrl-Up": "goDocStart", "Ctrl-End": "goDocEnd", "Ctrl-Down": "goDocEnd",
  1.4562 +    "Ctrl-Left": "goGroupLeft", "Ctrl-Right": "goGroupRight", "Alt-Left": "goLineStart", "Alt-Right": "goLineEnd",
  1.4563 +    "Ctrl-Backspace": "delGroupBefore", "Ctrl-Delete": "delGroupAfter", "Ctrl-S": "save", "Ctrl-F": "find",
  1.4564 +    "Ctrl-G": "findNext", "Shift-Ctrl-G": "findPrev", "Shift-Ctrl-F": "replace", "Shift-Ctrl-R": "replaceAll",
  1.4565 +    "Ctrl-[": "indentLess", "Ctrl-]": "indentMore",
  1.4566 +    "Ctrl-U": "undoSelection", "Shift-Ctrl-U": "redoSelection", "Alt-U": "redoSelection",
  1.4567 +    fallthrough: "basic"
  1.4568 +  };
  1.4569 +  keyMap.macDefault = {
  1.4570 +    "Cmd-A": "selectAll", "Cmd-D": "deleteLine", "Cmd-Z": "undo", "Shift-Cmd-Z": "redo", "Cmd-Y": "redo",
  1.4571 +    "Cmd-Up": "goDocStart", "Cmd-End": "goDocEnd", "Cmd-Down": "goDocEnd", "Alt-Left": "goGroupLeft",
  1.4572 +    "Alt-Right": "goGroupRight", "Cmd-Left": "goLineStart", "Cmd-Right": "goLineEnd", "Alt-Backspace": "delGroupBefore",
  1.4573 +    "Ctrl-Alt-Backspace": "delGroupAfter", "Alt-Delete": "delGroupAfter", "Cmd-S": "save", "Cmd-F": "find",
  1.4574 +    "Cmd-G": "findNext", "Shift-Cmd-G": "findPrev", "Cmd-Alt-F": "replace", "Shift-Cmd-Alt-F": "replaceAll",
  1.4575 +    "Cmd-[": "indentLess", "Cmd-]": "indentMore", "Cmd-Backspace": "delLineLeft",
  1.4576 +    "Cmd-U": "undoSelection", "Shift-Cmd-U": "redoSelection",
  1.4577 +    fallthrough: ["basic", "emacsy"]
  1.4578 +  };
  1.4579 +  // Very basic readline/emacs-style bindings, which are standard on Mac.
  1.4580 +  keyMap.emacsy = {
  1.4581 +    "Ctrl-F": "goCharRight", "Ctrl-B": "goCharLeft", "Ctrl-P": "goLineUp", "Ctrl-N": "goLineDown",
  1.4582 +    "Alt-F": "goWordRight", "Alt-B": "goWordLeft", "Ctrl-A": "goLineStart", "Ctrl-E": "goLineEnd",
  1.4583 +    "Ctrl-V": "goPageDown", "Shift-Ctrl-V": "goPageUp", "Ctrl-D": "delCharAfter", "Ctrl-H": "delCharBefore",
  1.4584 +    "Alt-D": "delWordAfter", "Alt-Backspace": "delWordBefore", "Ctrl-K": "killLine", "Ctrl-T": "transposeChars"
  1.4585 +  };
  1.4586 +  keyMap["default"] = mac ? keyMap.macDefault : keyMap.pcDefault;
  1.4587 +
  1.4588 +  // KEYMAP DISPATCH
  1.4589 +
  1.4590 +  function getKeyMap(val) {
  1.4591 +    if (typeof val == "string") return keyMap[val];
  1.4592 +    else return val;
  1.4593 +  }
  1.4594 +
  1.4595 +  // Given an array of keymaps and a key name, call handle on any
  1.4596 +  // bindings found, until that returns a truthy value, at which point
  1.4597 +  // we consider the key handled. Implements things like binding a key
  1.4598 +  // to false stopping further handling and keymap fallthrough.
  1.4599 +  var lookupKey = CodeMirror.lookupKey = function(name, maps, handle) {
  1.4600 +    function lookup(map) {
  1.4601 +      map = getKeyMap(map);
  1.4602 +      var found = map[name];
  1.4603 +      if (found === false) return "stop";
  1.4604 +      if (found != null && handle(found)) return true;
  1.4605 +      if (map.nofallthrough) return "stop";
  1.4606 +
  1.4607 +      var fallthrough = map.fallthrough;
  1.4608 +      if (fallthrough == null) return false;
  1.4609 +      if (Object.prototype.toString.call(fallthrough) != "[object Array]")
  1.4610 +        return lookup(fallthrough);
  1.4611 +      for (var i = 0; i < fallthrough.length; ++i) {
  1.4612 +        var done = lookup(fallthrough[i]);
  1.4613 +        if (done) return done;
  1.4614 +      }
  1.4615 +      return false;
  1.4616 +    }
  1.4617 +
  1.4618 +    for (var i = 0; i < maps.length; ++i) {
  1.4619 +      var done = lookup(maps[i]);
  1.4620 +      if (done) return done != "stop";
  1.4621 +    }
  1.4622 +  };
  1.4623 +
  1.4624 +  // Modifier key presses don't count as 'real' key presses for the
  1.4625 +  // purpose of keymap fallthrough.
  1.4626 +  var isModifierKey = CodeMirror.isModifierKey = function(event) {
  1.4627 +    var name = keyNames[event.keyCode];
  1.4628 +    return name == "Ctrl" || name == "Alt" || name == "Shift" || name == "Mod";
  1.4629 +  };
  1.4630 +
  1.4631 +  // Look up the name of a key as indicated by an event object.
  1.4632 +  var keyName = CodeMirror.keyName = function(event, noShift) {
  1.4633 +    if (presto && event.keyCode == 34 && event["char"]) return false;
  1.4634 +    var name = keyNames[event.keyCode];
  1.4635 +    if (name == null || event.altGraphKey) return false;
  1.4636 +    if (event.altKey) name = "Alt-" + name;
  1.4637 +    if (flipCtrlCmd ? event.metaKey : event.ctrlKey) name = "Ctrl-" + name;
  1.4638 +    if (flipCtrlCmd ? event.ctrlKey : event.metaKey) name = "Cmd-" + name;
  1.4639 +    if (!noShift && event.shiftKey) name = "Shift-" + name;
  1.4640 +    return name;
  1.4641 +  };
  1.4642 +
  1.4643 +  // FROMTEXTAREA
  1.4644 +
  1.4645 +  CodeMirror.fromTextArea = function(textarea, options) {
  1.4646 +    if (!options) options = {};
  1.4647 +    options.value = textarea.value;
  1.4648 +    if (!options.tabindex && textarea.tabindex)
  1.4649 +      options.tabindex = textarea.tabindex;
  1.4650 +    if (!options.placeholder && textarea.placeholder)
  1.4651 +      options.placeholder = textarea.placeholder;
  1.4652 +    // Set autofocus to true if this textarea is focused, or if it has
  1.4653 +    // autofocus and no other element is focused.
  1.4654 +    if (options.autofocus == null) {
  1.4655 +      var hasFocus = activeElt();
  1.4656 +      options.autofocus = hasFocus == textarea ||
  1.4657 +        textarea.getAttribute("autofocus") != null && hasFocus == document.body;
  1.4658 +    }
  1.4659 +
  1.4660 +    function save() {textarea.value = cm.getValue();}
  1.4661 +    if (textarea.form) {
  1.4662 +      on(textarea.form, "submit", save);
  1.4663 +      // Deplorable hack to make the submit method do the right thing.
  1.4664 +      if (!options.leaveSubmitMethodAlone) {
  1.4665 +        var form = textarea.form, realSubmit = form.submit;
  1.4666 +        try {
  1.4667 +          var wrappedSubmit = form.submit = function() {
  1.4668 +            save();
  1.4669 +            form.submit = realSubmit;
  1.4670 +            form.submit();
  1.4671 +            form.submit = wrappedSubmit;
  1.4672 +          };
  1.4673 +        } catch(e) {}
  1.4674 +      }
  1.4675 +    }
  1.4676 +
  1.4677 +    textarea.style.display = "none";
  1.4678 +    var cm = CodeMirror(function(node) {
  1.4679 +      textarea.parentNode.insertBefore(node, textarea.nextSibling);
  1.4680 +    }, options);
  1.4681 +    cm.save = save;
  1.4682 +    cm.getTextArea = function() { return textarea; };
  1.4683 +    cm.toTextArea = function() {
  1.4684 +      save();
  1.4685 +      textarea.parentNode.removeChild(cm.getWrapperElement());
  1.4686 +      textarea.style.display = "";
  1.4687 +      if (textarea.form) {
  1.4688 +        off(textarea.form, "submit", save);
  1.4689 +        if (typeof textarea.form.submit == "function")
  1.4690 +          textarea.form.submit = realSubmit;
  1.4691 +      }
  1.4692 +    };
  1.4693 +    return cm;
  1.4694 +  };
  1.4695 +
  1.4696 +  // STRING STREAM
  1.4697 +
  1.4698 +  // Fed to the mode parsers, provides helper functions to make
  1.4699 +  // parsers more succinct.
  1.4700 +
  1.4701 +  var StringStream = CodeMirror.StringStream = function(string, tabSize) {
  1.4702 +    this.pos = this.start = 0;
  1.4703 +    this.string = string;
  1.4704 +    this.tabSize = tabSize || 8;
  1.4705 +    this.lastColumnPos = this.lastColumnValue = 0;
  1.4706 +    this.lineStart = 0;
  1.4707 +  };
  1.4708 +
  1.4709 +  StringStream.prototype = {
  1.4710 +    eol: function() {return this.pos >= this.string.length;},
  1.4711 +    sol: function() {return this.pos == this.lineStart;},
  1.4712 +    peek: function() {return this.string.charAt(this.pos) || undefined;},
  1.4713 +    next: function() {
  1.4714 +      if (this.pos < this.string.length)
  1.4715 +        return this.string.charAt(this.pos++);
  1.4716 +    },
  1.4717 +    eat: function(match) {
  1.4718 +      var ch = this.string.charAt(this.pos);
  1.4719 +      if (typeof match == "string") var ok = ch == match;
  1.4720 +      else var ok = ch && (match.test ? match.test(ch) : match(ch));
  1.4721 +      if (ok) {++this.pos; return ch;}
  1.4722 +    },
  1.4723 +    eatWhile: function(match) {
  1.4724 +      var start = this.pos;
  1.4725 +      while (this.eat(match)){}
  1.4726 +      return this.pos > start;
  1.4727 +    },
  1.4728 +    eatSpace: function() {
  1.4729 +      var start = this.pos;
  1.4730 +      while (/[\s\u00a0]/.test(this.string.charAt(this.pos))) ++this.pos;
  1.4731 +      return this.pos > start;
  1.4732 +    },
  1.4733 +    skipToEnd: function() {this.pos = this.string.length;},
  1.4734 +    skipTo: function(ch) {
  1.4735 +      var found = this.string.indexOf(ch, this.pos);
  1.4736 +      if (found > -1) {this.pos = found; return true;}
  1.4737 +    },
  1.4738 +    backUp: function(n) {this.pos -= n;},
  1.4739 +    column: function() {
  1.4740 +      if (this.lastColumnPos < this.start) {
  1.4741 +        this.lastColumnValue = countColumn(this.string, this.start, this.tabSize, this.lastColumnPos, this.lastColumnValue);
  1.4742 +        this.lastColumnPos = this.start;
  1.4743 +      }
  1.4744 +      return this.lastColumnValue - (this.lineStart ? countColumn(this.string, this.lineStart, this.tabSize) : 0);
  1.4745 +    },
  1.4746 +    indentation: function() {
  1.4747 +      return countColumn(this.string, null, this.tabSize) -
  1.4748 +        (this.lineStart ? countColumn(this.string, this.lineStart, this.tabSize) : 0);
  1.4749 +    },
  1.4750 +    match: function(pattern, consume, caseInsensitive) {
  1.4751 +      if (typeof pattern == "string") {
  1.4752 +        var cased = function(str) {return caseInsensitive ? str.toLowerCase() : str;};
  1.4753 +        var substr = this.string.substr(this.pos, pattern.length);
  1.4754 +        if (cased(substr) == cased(pattern)) {
  1.4755 +          if (consume !== false) this.pos += pattern.length;
  1.4756 +          return true;
  1.4757 +        }
  1.4758 +      } else {
  1.4759 +        var match = this.string.slice(this.pos).match(pattern);
  1.4760 +        if (match && match.index > 0) return null;
  1.4761 +        if (match && consume !== false) this.pos += match[0].length;
  1.4762 +        return match;
  1.4763 +      }
  1.4764 +    },
  1.4765 +    current: function(){return this.string.slice(this.start, this.pos);},
  1.4766 +    hideFirstChars: function(n, inner) {
  1.4767 +      this.lineStart += n;
  1.4768 +      try { return inner(); }
  1.4769 +      finally { this.lineStart -= n; }
  1.4770 +    }
  1.4771 +  };
  1.4772 +
  1.4773 +  // TEXTMARKERS
  1.4774 +
  1.4775 +  // Created with markText and setBookmark methods. A TextMarker is a
  1.4776 +  // handle that can be used to clear or find a marked position in the
  1.4777 +  // document. Line objects hold arrays (markedSpans) containing
  1.4778 +  // {from, to, marker} object pointing to such marker objects, and
  1.4779 +  // indicating that such a marker is present on that line. Multiple
  1.4780 +  // lines may point to the same marker when it spans across lines.
  1.4781 +  // The spans will have null for their from/to properties when the
  1.4782 +  // marker continues beyond the start/end of the line. Markers have
  1.4783 +  // links back to the lines they currently touch.
  1.4784 +
  1.4785 +  var TextMarker = CodeMirror.TextMarker = function(doc, type) {
  1.4786 +    this.lines = [];
  1.4787 +    this.type = type;
  1.4788 +    this.doc = doc;
  1.4789 +  };
  1.4790 +  eventMixin(TextMarker);
  1.4791 +
  1.4792 +  // Clear the marker.
  1.4793 +  TextMarker.prototype.clear = function() {
  1.4794 +    if (this.explicitlyCleared) return;
  1.4795 +    var cm = this.doc.cm, withOp = cm && !cm.curOp;
  1.4796 +    if (withOp) startOperation(cm);
  1.4797 +    if (hasHandler(this, "clear")) {
  1.4798 +      var found = this.find();
  1.4799 +      if (found) signalLater(this, "clear", found.from, found.to);
  1.4800 +    }
  1.4801 +    var min = null, max = null;
  1.4802 +    for (var i = 0; i < this.lines.length; ++i) {
  1.4803 +      var line = this.lines[i];
  1.4804 +      var span = getMarkedSpanFor(line.markedSpans, this);
  1.4805 +      if (cm && !this.collapsed) regLineChange(cm, lineNo(line), "text");
  1.4806 +      else if (cm) {
  1.4807 +        if (span.to != null) max = lineNo(line);
  1.4808 +        if (span.from != null) min = lineNo(line);
  1.4809 +      }
  1.4810 +      line.markedSpans = removeMarkedSpan(line.markedSpans, span);
  1.4811 +      if (span.from == null && this.collapsed && !lineIsHidden(this.doc, line) && cm)
  1.4812 +        updateLineHeight(line, textHeight(cm.display));
  1.4813 +    }
  1.4814 +    if (cm && this.collapsed && !cm.options.lineWrapping) for (var i = 0; i < this.lines.length; ++i) {
  1.4815 +      var visual = visualLine(this.lines[i]), len = lineLength(visual);
  1.4816 +      if (len > cm.display.maxLineLength) {
  1.4817 +        cm.display.maxLine = visual;
  1.4818 +        cm.display.maxLineLength = len;
  1.4819 +        cm.display.maxLineChanged = true;
  1.4820 +      }
  1.4821 +    }
  1.4822 +
  1.4823 +    if (min != null && cm && this.collapsed) regChange(cm, min, max + 1);
  1.4824 +    this.lines.length = 0;
  1.4825 +    this.explicitlyCleared = true;
  1.4826 +    if (this.atomic && this.doc.cantEdit) {
  1.4827 +      this.doc.cantEdit = false;
  1.4828 +      if (cm) reCheckSelection(cm.doc);
  1.4829 +    }
  1.4830 +    if (cm) signalLater(cm, "markerCleared", cm, this);
  1.4831 +    if (withOp) endOperation(cm);
  1.4832 +  };
  1.4833 +
  1.4834 +  // Find the position of the marker in the document. Returns a {from,
  1.4835 +  // to} object by default. Side can be passed to get a specific side
  1.4836 +  // -- 0 (both), -1 (left), or 1 (right). When lineObj is true, the
  1.4837 +  // Pos objects returned contain a line object, rather than a line
  1.4838 +  // number (used to prevent looking up the same line twice).
  1.4839 +  TextMarker.prototype.find = function(side, lineObj) {
  1.4840 +    if (side == null && this.type == "bookmark") side = 1;
  1.4841 +    var from, to;
  1.4842 +    for (var i = 0; i < this.lines.length; ++i) {
  1.4843 +      var line = this.lines[i];
  1.4844 +      var span = getMarkedSpanFor(line.markedSpans, this);
  1.4845 +      if (span.from != null) {
  1.4846 +        from = Pos(lineObj ? line : lineNo(line), span.from);
  1.4847 +        if (side == -1) return from;
  1.4848 +      }
  1.4849 +      if (span.to != null) {
  1.4850 +        to = Pos(lineObj ? line : lineNo(line), span.to);
  1.4851 +        if (side == 1) return to;
  1.4852 +      }
  1.4853 +    }
  1.4854 +    return from && {from: from, to: to};
  1.4855 +  };
  1.4856 +
  1.4857 +  // Signals that the marker's widget changed, and surrounding layout
  1.4858 +  // should be recomputed.
  1.4859 +  TextMarker.prototype.changed = function() {
  1.4860 +    var pos = this.find(-1, true), widget = this, cm = this.doc.cm;
  1.4861 +    if (!pos || !cm) return;
  1.4862 +    runInOp(cm, function() {
  1.4863 +      var line = pos.line, lineN = lineNo(pos.line);
  1.4864 +      var view = findViewForLine(cm, lineN);
  1.4865 +      if (view) {
  1.4866 +        clearLineMeasurementCacheFor(view);
  1.4867 +        cm.curOp.selectionChanged = cm.curOp.forceUpdate = true;
  1.4868 +      }
  1.4869 +      cm.curOp.updateMaxLine = true;
  1.4870 +      if (!lineIsHidden(widget.doc, line) && widget.height != null) {
  1.4871 +        var oldHeight = widget.height;
  1.4872 +        widget.height = null;
  1.4873 +        var dHeight = widgetHeight(widget) - oldHeight;
  1.4874 +        if (dHeight)
  1.4875 +          updateLineHeight(line, line.height + dHeight);
  1.4876 +      }
  1.4877 +    });
  1.4878 +  };
  1.4879 +
  1.4880 +  TextMarker.prototype.attachLine = function(line) {
  1.4881 +    if (!this.lines.length && this.doc.cm) {
  1.4882 +      var op = this.doc.cm.curOp;
  1.4883 +      if (!op.maybeHiddenMarkers || indexOf(op.maybeHiddenMarkers, this) == -1)
  1.4884 +        (op.maybeUnhiddenMarkers || (op.maybeUnhiddenMarkers = [])).push(this);
  1.4885 +    }
  1.4886 +    this.lines.push(line);
  1.4887 +  };
  1.4888 +  TextMarker.prototype.detachLine = function(line) {
  1.4889 +    this.lines.splice(indexOf(this.lines, line), 1);
  1.4890 +    if (!this.lines.length && this.doc.cm) {
  1.4891 +      var op = this.doc.cm.curOp;
  1.4892 +      (op.maybeHiddenMarkers || (op.maybeHiddenMarkers = [])).push(this);
  1.4893 +    }
  1.4894 +  };
  1.4895 +
  1.4896 +  // Collapsed markers have unique ids, in order to be able to order
  1.4897 +  // them, which is needed for uniquely determining an outer marker
  1.4898 +  // when they overlap (they may nest, but not partially overlap).
  1.4899 +  var nextMarkerId = 0;
  1.4900 +
  1.4901 +  // Create a marker, wire it up to the right lines, and
  1.4902 +  function markText(doc, from, to, options, type) {
  1.4903 +    // Shared markers (across linked documents) are handled separately
  1.4904 +    // (markTextShared will call out to this again, once per
  1.4905 +    // document).
  1.4906 +    if (options && options.shared) return markTextShared(doc, from, to, options, type);
  1.4907 +    // Ensure we are in an operation.
  1.4908 +    if (doc.cm && !doc.cm.curOp) return operation(doc.cm, markText)(doc, from, to, options, type);
  1.4909 +
  1.4910 +    var marker = new TextMarker(doc, type), diff = cmp(from, to);
  1.4911 +    if (options) copyObj(options, marker);
  1.4912 +    // Don't connect empty markers unless clearWhenEmpty is false
  1.4913 +    if (diff > 0 || diff == 0 && marker.clearWhenEmpty !== false)
  1.4914 +      return marker;
  1.4915 +    if (marker.replacedWith) {
  1.4916 +      // Showing up as a widget implies collapsed (widget replaces text)
  1.4917 +      marker.collapsed = true;
  1.4918 +      marker.widgetNode = elt("span", [marker.replacedWith], "CodeMirror-widget");
  1.4919 +      if (!options.handleMouseEvents) marker.widgetNode.ignoreEvents = true;
  1.4920 +      if (options.insertLeft) marker.widgetNode.insertLeft = true;
  1.4921 +    }
  1.4922 +    if (marker.collapsed) {
  1.4923 +      if (conflictingCollapsedRange(doc, from.line, from, to, marker) ||
  1.4924 +          from.line != to.line && conflictingCollapsedRange(doc, to.line, from, to, marker))
  1.4925 +        throw new Error("Inserting collapsed marker partially overlapping an existing one");
  1.4926 +      sawCollapsedSpans = true;
  1.4927 +    }
  1.4928 +
  1.4929 +    if (marker.addToHistory)
  1.4930 +      addChangeToHistory(doc, {from: from, to: to, origin: "markText"}, doc.sel, NaN);
  1.4931 +
  1.4932 +    var curLine = from.line, cm = doc.cm, updateMaxLine;
  1.4933 +    doc.iter(curLine, to.line + 1, function(line) {
  1.4934 +      if (cm && marker.collapsed && !cm.options.lineWrapping && visualLine(line) == cm.display.maxLine)
  1.4935 +        updateMaxLine = true;
  1.4936 +      if (marker.collapsed && curLine != from.line) updateLineHeight(line, 0);
  1.4937 +      addMarkedSpan(line, new MarkedSpan(marker,
  1.4938 +                                         curLine == from.line ? from.ch : null,
  1.4939 +                                         curLine == to.line ? to.ch : null));
  1.4940 +      ++curLine;
  1.4941 +    });
  1.4942 +    // lineIsHidden depends on the presence of the spans, so needs a second pass
  1.4943 +    if (marker.collapsed) doc.iter(from.line, to.line + 1, function(line) {
  1.4944 +      if (lineIsHidden(doc, line)) updateLineHeight(line, 0);
  1.4945 +    });
  1.4946 +
  1.4947 +    if (marker.clearOnEnter) on(marker, "beforeCursorEnter", function() { marker.clear(); });
  1.4948 +
  1.4949 +    if (marker.readOnly) {
  1.4950 +      sawReadOnlySpans = true;
  1.4951 +      if (doc.history.done.length || doc.history.undone.length)
  1.4952 +        doc.clearHistory();
  1.4953 +    }
  1.4954 +    if (marker.collapsed) {
  1.4955 +      marker.id = ++nextMarkerId;
  1.4956 +      marker.atomic = true;
  1.4957 +    }
  1.4958 +    if (cm) {
  1.4959 +      // Sync editor state
  1.4960 +      if (updateMaxLine) cm.curOp.updateMaxLine = true;
  1.4961 +      if (marker.collapsed)
  1.4962 +        regChange(cm, from.line, to.line + 1);
  1.4963 +      else if (marker.className || marker.title || marker.startStyle || marker.endStyle)
  1.4964 +        for (var i = from.line; i <= to.line; i++) regLineChange(cm, i, "text");
  1.4965 +      if (marker.atomic) reCheckSelection(cm.doc);
  1.4966 +      signalLater(cm, "markerAdded", cm, marker);
  1.4967 +    }
  1.4968 +    return marker;
  1.4969 +  }
  1.4970 +
  1.4971 +  // SHARED TEXTMARKERS
  1.4972 +
  1.4973 +  // A shared marker spans multiple linked documents. It is
  1.4974 +  // implemented as a meta-marker-object controlling multiple normal
  1.4975 +  // markers.
  1.4976 +  var SharedTextMarker = CodeMirror.SharedTextMarker = function(markers, primary) {
  1.4977 +    this.markers = markers;
  1.4978 +    this.primary = primary;
  1.4979 +    for (var i = 0, me = this; i < markers.length; ++i) {
  1.4980 +      markers[i].parent = this;
  1.4981 +      on(markers[i], "clear", function(){me.clear();});
  1.4982 +    }
  1.4983 +  };
  1.4984 +  eventMixin(SharedTextMarker);
  1.4985 +
  1.4986 +  SharedTextMarker.prototype.clear = function() {
  1.4987 +    if (this.explicitlyCleared) return;
  1.4988 +    this.explicitlyCleared = true;
  1.4989 +    for (var i = 0; i < this.markers.length; ++i)
  1.4990 +      this.markers[i].clear();
  1.4991 +    signalLater(this, "clear");
  1.4992 +  };
  1.4993 +  SharedTextMarker.prototype.find = function(side, lineObj) {
  1.4994 +    return this.primary.find(side, lineObj);
  1.4995 +  };
  1.4996 +
  1.4997 +  function markTextShared(doc, from, to, options, type) {
  1.4998 +    options = copyObj(options);
  1.4999 +    options.shared = false;
  1.5000 +    var markers = [markText(doc, from, to, options, type)], primary = markers[0];
  1.5001 +    var widget = options.widgetNode;
  1.5002 +    linkedDocs(doc, function(doc) {
  1.5003 +      if (widget) options.widgetNode = widget.cloneNode(true);
  1.5004 +      markers.push(markText(doc, clipPos(doc, from), clipPos(doc, to), options, type));
  1.5005 +      for (var i = 0; i < doc.linked.length; ++i)
  1.5006 +        if (doc.linked[i].isParent) return;
  1.5007 +      primary = lst(markers);
  1.5008 +    });
  1.5009 +    return new SharedTextMarker(markers, primary);
  1.5010 +  }
  1.5011 +
  1.5012 +  // TEXTMARKER SPANS
  1.5013 +
  1.5014 +  function MarkedSpan(marker, from, to) {
  1.5015 +    this.marker = marker;
  1.5016 +    this.from = from; this.to = to;
  1.5017 +  }
  1.5018 +
  1.5019 +  // Search an array of spans for a span matching the given marker.
  1.5020 +  function getMarkedSpanFor(spans, marker) {
  1.5021 +    if (spans) for (var i = 0; i < spans.length; ++i) {
  1.5022 +      var span = spans[i];
  1.5023 +      if (span.marker == marker) return span;
  1.5024 +    }
  1.5025 +  }
  1.5026 +  // Remove a span from an array, returning undefined if no spans are
  1.5027 +  // left (we don't store arrays for lines without spans).
  1.5028 +  function removeMarkedSpan(spans, span) {
  1.5029 +    for (var r, i = 0; i < spans.length; ++i)
  1.5030 +      if (spans[i] != span) (r || (r = [])).push(spans[i]);
  1.5031 +    return r;
  1.5032 +  }
  1.5033 +  // Add a span to a line.
  1.5034 +  function addMarkedSpan(line, span) {
  1.5035 +    line.markedSpans = line.markedSpans ? line.markedSpans.concat([span]) : [span];
  1.5036 +    span.marker.attachLine(line);
  1.5037 +  }
  1.5038 +
  1.5039 +  // Used for the algorithm that adjusts markers for a change in the
  1.5040 +  // document. These functions cut an array of spans at a given
  1.5041 +  // character position, returning an array of remaining chunks (or
  1.5042 +  // undefined if nothing remains).
  1.5043 +  function markedSpansBefore(old, startCh, isInsert) {
  1.5044 +    if (old) for (var i = 0, nw; i < old.length; ++i) {
  1.5045 +      var span = old[i], marker = span.marker;
  1.5046 +      var startsBefore = span.from == null || (marker.inclusiveLeft ? span.from <= startCh : span.from < startCh);
  1.5047 +      if (startsBefore || span.from == startCh && marker.type == "bookmark" && (!isInsert || !span.marker.insertLeft)) {
  1.5048 +        var endsAfter = span.to == null || (marker.inclusiveRight ? span.to >= startCh : span.to > startCh);
  1.5049 +        (nw || (nw = [])).push(new MarkedSpan(marker, span.from, endsAfter ? null : span.to));
  1.5050 +      }
  1.5051 +    }
  1.5052 +    return nw;
  1.5053 +  }
  1.5054 +  function markedSpansAfter(old, endCh, isInsert) {
  1.5055 +    if (old) for (var i = 0, nw; i < old.length; ++i) {
  1.5056 +      var span = old[i], marker = span.marker;
  1.5057 +      var endsAfter = span.to == null || (marker.inclusiveRight ? span.to >= endCh : span.to > endCh);
  1.5058 +      if (endsAfter || span.from == endCh && marker.type == "bookmark" && (!isInsert || span.marker.insertLeft)) {
  1.5059 +        var startsBefore = span.from == null || (marker.inclusiveLeft ? span.from <= endCh : span.from < endCh);
  1.5060 +        (nw || (nw = [])).push(new MarkedSpan(marker, startsBefore ? null : span.from - endCh,
  1.5061 +                                              span.to == null ? null : span.to - endCh));
  1.5062 +      }
  1.5063 +    }
  1.5064 +    return nw;
  1.5065 +  }
  1.5066 +
  1.5067 +  // Given a change object, compute the new set of marker spans that
  1.5068 +  // cover the line in which the change took place. Removes spans
  1.5069 +  // entirely within the change, reconnects spans belonging to the
  1.5070 +  // same marker that appear on both sides of the change, and cuts off
  1.5071 +  // spans partially within the change. Returns an array of span
  1.5072 +  // arrays with one element for each line in (after) the change.
  1.5073 +  function stretchSpansOverChange(doc, change) {
  1.5074 +    var oldFirst = isLine(doc, change.from.line) && getLine(doc, change.from.line).markedSpans;
  1.5075 +    var oldLast = isLine(doc, change.to.line) && getLine(doc, change.to.line).markedSpans;
  1.5076 +    if (!oldFirst && !oldLast) return null;
  1.5077 +
  1.5078 +    var startCh = change.from.ch, endCh = change.to.ch, isInsert = cmp(change.from, change.to) == 0;
  1.5079 +    // Get the spans that 'stick out' on both sides
  1.5080 +    var first = markedSpansBefore(oldFirst, startCh, isInsert);
  1.5081 +    var last = markedSpansAfter(oldLast, endCh, isInsert);
  1.5082 +
  1.5083 +    // Next, merge those two ends
  1.5084 +    var sameLine = change.text.length == 1, offset = lst(change.text).length + (sameLine ? startCh : 0);
  1.5085 +    if (first) {
  1.5086 +      // Fix up .to properties of first
  1.5087 +      for (var i = 0; i < first.length; ++i) {
  1.5088 +        var span = first[i];
  1.5089 +        if (span.to == null) {
  1.5090 +          var found = getMarkedSpanFor(last, span.marker);
  1.5091 +          if (!found) span.to = startCh;
  1.5092 +          else if (sameLine) span.to = found.to == null ? null : found.to + offset;
  1.5093 +        }
  1.5094 +      }
  1.5095 +    }
  1.5096 +    if (last) {
  1.5097 +      // Fix up .from in last (or move them into first in case of sameLine)
  1.5098 +      for (var i = 0; i < last.length; ++i) {
  1.5099 +        var span = last[i];
  1.5100 +        if (span.to != null) span.to += offset;
  1.5101 +        if (span.from == null) {
  1.5102 +          var found = getMarkedSpanFor(first, span.marker);
  1.5103 +          if (!found) {
  1.5104 +            span.from = offset;
  1.5105 +            if (sameLine) (first || (first = [])).push(span);
  1.5106 +          }
  1.5107 +        } else {
  1.5108 +          span.from += offset;
  1.5109 +          if (sameLine) (first || (first = [])).push(span);
  1.5110 +        }
  1.5111 +      }
  1.5112 +    }
  1.5113 +    // Make sure we didn't create any zero-length spans
  1.5114 +    if (first) first = clearEmptySpans(first);
  1.5115 +    if (last && last != first) last = clearEmptySpans(last);
  1.5116 +
  1.5117 +    var newMarkers = [first];
  1.5118 +    if (!sameLine) {
  1.5119 +      // Fill gap with whole-line-spans
  1.5120 +      var gap = change.text.length - 2, gapMarkers;
  1.5121 +      if (gap > 0 && first)
  1.5122 +        for (var i = 0; i < first.length; ++i)
  1.5123 +          if (first[i].to == null)
  1.5124 +            (gapMarkers || (gapMarkers = [])).push(new MarkedSpan(first[i].marker, null, null));
  1.5125 +      for (var i = 0; i < gap; ++i)
  1.5126 +        newMarkers.push(gapMarkers);
  1.5127 +      newMarkers.push(last);
  1.5128 +    }
  1.5129 +    return newMarkers;
  1.5130 +  }
  1.5131 +
  1.5132 +  // Remove spans that are empty and don't have a clearWhenEmpty
  1.5133 +  // option of false.
  1.5134 +  function clearEmptySpans(spans) {
  1.5135 +    for (var i = 0; i < spans.length; ++i) {
  1.5136 +      var span = spans[i];
  1.5137 +      if (span.from != null && span.from == span.to && span.marker.clearWhenEmpty !== false)
  1.5138 +        spans.splice(i--, 1);
  1.5139 +    }
  1.5140 +    if (!spans.length) return null;
  1.5141 +    return spans;
  1.5142 +  }
  1.5143 +
  1.5144 +  // Used for un/re-doing changes from the history. Combines the
  1.5145 +  // result of computing the existing spans with the set of spans that
  1.5146 +  // existed in the history (so that deleting around a span and then
  1.5147 +  // undoing brings back the span).
  1.5148 +  function mergeOldSpans(doc, change) {
  1.5149 +    var old = getOldSpans(doc, change);
  1.5150 +    var stretched = stretchSpansOverChange(doc, change);
  1.5151 +    if (!old) return stretched;
  1.5152 +    if (!stretched) return old;
  1.5153 +
  1.5154 +    for (var i = 0; i < old.length; ++i) {
  1.5155 +      var oldCur = old[i], stretchCur = stretched[i];
  1.5156 +      if (oldCur && stretchCur) {
  1.5157 +        spans: for (var j = 0; j < stretchCur.length; ++j) {
  1.5158 +          var span = stretchCur[j];
  1.5159 +          for (var k = 0; k < oldCur.length; ++k)
  1.5160 +            if (oldCur[k].marker == span.marker) continue spans;
  1.5161 +          oldCur.push(span);
  1.5162 +        }
  1.5163 +      } else if (stretchCur) {
  1.5164 +        old[i] = stretchCur;
  1.5165 +      }
  1.5166 +    }
  1.5167 +    return old;
  1.5168 +  }
  1.5169 +
  1.5170 +  // Used to 'clip' out readOnly ranges when making a change.
  1.5171 +  function removeReadOnlyRanges(doc, from, to) {
  1.5172 +    var markers = null;
  1.5173 +    doc.iter(from.line, to.line + 1, function(line) {
  1.5174 +      if (line.markedSpans) for (var i = 0; i < line.markedSpans.length; ++i) {
  1.5175 +        var mark = line.markedSpans[i].marker;
  1.5176 +        if (mark.readOnly && (!markers || indexOf(markers, mark) == -1))
  1.5177 +          (markers || (markers = [])).push(mark);
  1.5178 +      }
  1.5179 +    });
  1.5180 +    if (!markers) return null;
  1.5181 +    var parts = [{from: from, to: to}];
  1.5182 +    for (var i = 0; i < markers.length; ++i) {
  1.5183 +      var mk = markers[i], m = mk.find(0);
  1.5184 +      for (var j = 0; j < parts.length; ++j) {
  1.5185 +        var p = parts[j];
  1.5186 +        if (cmp(p.to, m.from) < 0 || cmp(p.from, m.to) > 0) continue;
  1.5187 +        var newParts = [j, 1], dfrom = cmp(p.from, m.from), dto = cmp(p.to, m.to);
  1.5188 +        if (dfrom < 0 || !mk.inclusiveLeft && !dfrom)
  1.5189 +          newParts.push({from: p.from, to: m.from});
  1.5190 +        if (dto > 0 || !mk.inclusiveRight && !dto)
  1.5191 +          newParts.push({from: m.to, to: p.to});
  1.5192 +        parts.splice.apply(parts, newParts);
  1.5193 +        j += newParts.length - 1;
  1.5194 +      }
  1.5195 +    }
  1.5196 +    return parts;
  1.5197 +  }
  1.5198 +
  1.5199 +  // Connect or disconnect spans from a line.
  1.5200 +  function detachMarkedSpans(line) {
  1.5201 +    var spans = line.markedSpans;
  1.5202 +    if (!spans) return;
  1.5203 +    for (var i = 0; i < spans.length; ++i)
  1.5204 +      spans[i].marker.detachLine(line);
  1.5205 +    line.markedSpans = null;
  1.5206 +  }
  1.5207 +  function attachMarkedSpans(line, spans) {
  1.5208 +    if (!spans) return;
  1.5209 +    for (var i = 0; i < spans.length; ++i)
  1.5210 +      spans[i].marker.attachLine(line);
  1.5211 +    line.markedSpans = spans;
  1.5212 +  }
  1.5213 +
  1.5214 +  // Helpers used when computing which overlapping collapsed span
  1.5215 +  // counts as the larger one.
  1.5216 +  function extraLeft(marker) { return marker.inclusiveLeft ? -1 : 0; }
  1.5217 +  function extraRight(marker) { return marker.inclusiveRight ? 1 : 0; }
  1.5218 +
  1.5219 +  // Returns a number indicating which of two overlapping collapsed
  1.5220 +  // spans is larger (and thus includes the other). Falls back to
  1.5221 +  // comparing ids when the spans cover exactly the same range.
  1.5222 +  function compareCollapsedMarkers(a, b) {
  1.5223 +    var lenDiff = a.lines.length - b.lines.length;
  1.5224 +    if (lenDiff != 0) return lenDiff;
  1.5225 +    var aPos = a.find(), bPos = b.find();
  1.5226 +    var fromCmp = cmp(aPos.from, bPos.from) || extraLeft(a) - extraLeft(b);
  1.5227 +    if (fromCmp) return -fromCmp;
  1.5228 +    var toCmp = cmp(aPos.to, bPos.to) || extraRight(a) - extraRight(b);
  1.5229 +    if (toCmp) return toCmp;
  1.5230 +    return b.id - a.id;
  1.5231 +  }
  1.5232 +
  1.5233 +  // Find out whether a line ends or starts in a collapsed span. If
  1.5234 +  // so, return the marker for that span.
  1.5235 +  function collapsedSpanAtSide(line, start) {
  1.5236 +    var sps = sawCollapsedSpans && line.markedSpans, found;
  1.5237 +    if (sps) for (var sp, i = 0; i < sps.length; ++i) {
  1.5238 +      sp = sps[i];
  1.5239 +      if (sp.marker.collapsed && (start ? sp.from : sp.to) == null &&
  1.5240 +          (!found || compareCollapsedMarkers(found, sp.marker) < 0))
  1.5241 +        found = sp.marker;
  1.5242 +    }
  1.5243 +    return found;
  1.5244 +  }
  1.5245 +  function collapsedSpanAtStart(line) { return collapsedSpanAtSide(line, true); }
  1.5246 +  function collapsedSpanAtEnd(line) { return collapsedSpanAtSide(line, false); }
  1.5247 +
  1.5248 +  // Test whether there exists a collapsed span that partially
  1.5249 +  // overlaps (covers the start or end, but not both) of a new span.
  1.5250 +  // Such overlap is not allowed.
  1.5251 +  function conflictingCollapsedRange(doc, lineNo, from, to, marker) {
  1.5252 +    var line = getLine(doc, lineNo);
  1.5253 +    var sps = sawCollapsedSpans && line.markedSpans;
  1.5254 +    if (sps) for (var i = 0; i < sps.length; ++i) {
  1.5255 +      var sp = sps[i];
  1.5256 +      if (!sp.marker.collapsed) continue;
  1.5257 +      var found = sp.marker.find(0);
  1.5258 +      var fromCmp = cmp(found.from, from) || extraLeft(sp.marker) - extraLeft(marker);
  1.5259 +      var toCmp = cmp(found.to, to) || extraRight(sp.marker) - extraRight(marker);
  1.5260 +      if (fromCmp >= 0 && toCmp <= 0 || fromCmp <= 0 && toCmp >= 0) continue;
  1.5261 +      if (fromCmp <= 0 && (cmp(found.to, from) || extraRight(sp.marker) - extraLeft(marker)) > 0 ||
  1.5262 +          fromCmp >= 0 && (cmp(found.from, to) || extraLeft(sp.marker) - extraRight(marker)) < 0)
  1.5263 +        return true;
  1.5264 +    }
  1.5265 +  }
  1.5266 +
  1.5267 +  // A visual line is a line as drawn on the screen. Folding, for
  1.5268 +  // example, can cause multiple logical lines to appear on the same
  1.5269 +  // visual line. This finds the start of the visual line that the
  1.5270 +  // given line is part of (usually that is the line itself).
  1.5271 +  function visualLine(line) {
  1.5272 +    var merged;
  1.5273 +    while (merged = collapsedSpanAtStart(line))
  1.5274 +      line = merged.find(-1, true).line;
  1.5275 +    return line;
  1.5276 +  }
  1.5277 +
  1.5278 +  // Returns an array of logical lines that continue the visual line
  1.5279 +  // started by the argument, or undefined if there are no such lines.
  1.5280 +  function visualLineContinued(line) {
  1.5281 +    var merged, lines;
  1.5282 +    while (merged = collapsedSpanAtEnd(line)) {
  1.5283 +      line = merged.find(1, true).line;
  1.5284 +      (lines || (lines = [])).push(line);
  1.5285 +    }
  1.5286 +    return lines;
  1.5287 +  }
  1.5288 +
  1.5289 +  // Get the line number of the start of the visual line that the
  1.5290 +  // given line number is part of.
  1.5291 +  function visualLineNo(doc, lineN) {
  1.5292 +    var line = getLine(doc, lineN), vis = visualLine(line);
  1.5293 +    if (line == vis) return lineN;
  1.5294 +    return lineNo(vis);
  1.5295 +  }
  1.5296 +  // Get the line number of the start of the next visual line after
  1.5297 +  // the given line.
  1.5298 +  function visualLineEndNo(doc, lineN) {
  1.5299 +    if (lineN > doc.lastLine()) return lineN;
  1.5300 +    var line = getLine(doc, lineN), merged;
  1.5301 +    if (!lineIsHidden(doc, line)) return lineN;
  1.5302 +    while (merged = collapsedSpanAtEnd(line))
  1.5303 +      line = merged.find(1, true).line;
  1.5304 +    return lineNo(line) + 1;
  1.5305 +  }
  1.5306 +
  1.5307 +  // Compute whether a line is hidden. Lines count as hidden when they
  1.5308 +  // are part of a visual line that starts with another line, or when
  1.5309 +  // they are entirely covered by collapsed, non-widget span.
  1.5310 +  function lineIsHidden(doc, line) {
  1.5311 +    var sps = sawCollapsedSpans && line.markedSpans;
  1.5312 +    if (sps) for (var sp, i = 0; i < sps.length; ++i) {
  1.5313 +      sp = sps[i];
  1.5314 +      if (!sp.marker.collapsed) continue;
  1.5315 +      if (sp.from == null) return true;
  1.5316 +      if (sp.marker.widgetNode) continue;
  1.5317 +      if (sp.from == 0 && sp.marker.inclusiveLeft && lineIsHiddenInner(doc, line, sp))
  1.5318 +        return true;
  1.5319 +    }
  1.5320 +  }
  1.5321 +  function lineIsHiddenInner(doc, line, span) {
  1.5322 +    if (span.to == null) {
  1.5323 +      var end = span.marker.find(1, true);
  1.5324 +      return lineIsHiddenInner(doc, end.line, getMarkedSpanFor(end.line.markedSpans, span.marker));
  1.5325 +    }
  1.5326 +    if (span.marker.inclusiveRight && span.to == line.text.length)
  1.5327 +      return true;
  1.5328 +    for (var sp, i = 0; i < line.markedSpans.length; ++i) {
  1.5329 +      sp = line.markedSpans[i];
  1.5330 +      if (sp.marker.collapsed && !sp.marker.widgetNode && sp.from == span.to &&
  1.5331 +          (sp.to == null || sp.to != span.from) &&
  1.5332 +          (sp.marker.inclusiveLeft || span.marker.inclusiveRight) &&
  1.5333 +          lineIsHiddenInner(doc, line, sp)) return true;
  1.5334 +    }
  1.5335 +  }
  1.5336 +
  1.5337 +  // LINE WIDGETS
  1.5338 +
  1.5339 +  // Line widgets are block elements displayed above or below a line.
  1.5340 +
  1.5341 +  var LineWidget = CodeMirror.LineWidget = function(cm, node, options) {
  1.5342 +    if (options) for (var opt in options) if (options.hasOwnProperty(opt))
  1.5343 +      this[opt] = options[opt];
  1.5344 +    this.cm = cm;
  1.5345 +    this.node = node;
  1.5346 +  };
  1.5347 +  eventMixin(LineWidget);
  1.5348 +
  1.5349 +  function adjustScrollWhenAboveVisible(cm, line, diff) {
  1.5350 +    if (heightAtLine(line) < ((cm.curOp && cm.curOp.scrollTop) || cm.doc.scrollTop))
  1.5351 +      addToScrollPos(cm, null, diff);
  1.5352 +  }
  1.5353 +
  1.5354 +  LineWidget.prototype.clear = function() {
  1.5355 +    var cm = this.cm, ws = this.line.widgets, line = this.line, no = lineNo(line);
  1.5356 +    if (no == null || !ws) return;
  1.5357 +    for (var i = 0; i < ws.length; ++i) if (ws[i] == this) ws.splice(i--, 1);
  1.5358 +    if (!ws.length) line.widgets = null;
  1.5359 +    var height = widgetHeight(this);
  1.5360 +    runInOp(cm, function() {
  1.5361 +      adjustScrollWhenAboveVisible(cm, line, -height);
  1.5362 +      regLineChange(cm, no, "widget");
  1.5363 +      updateLineHeight(line, Math.max(0, line.height - height));
  1.5364 +    });
  1.5365 +  };
  1.5366 +  LineWidget.prototype.changed = function() {
  1.5367 +    var oldH = this.height, cm = this.cm, line = this.line;
  1.5368 +    this.height = null;
  1.5369 +    var diff = widgetHeight(this) - oldH;
  1.5370 +    if (!diff) return;
  1.5371 +    runInOp(cm, function() {
  1.5372 +      cm.curOp.forceUpdate = true;
  1.5373 +      adjustScrollWhenAboveVisible(cm, line, diff);
  1.5374 +      updateLineHeight(line, line.height + diff);
  1.5375 +    });
  1.5376 +  };
  1.5377 +
  1.5378 +  function widgetHeight(widget) {
  1.5379 +    if (widget.height != null) return widget.height;
  1.5380 +    if (!contains(document.body, widget.node))
  1.5381 +      removeChildrenAndAdd(widget.cm.display.measure, elt("div", [widget.node], null, "position: relative"));
  1.5382 +    return widget.height = widget.node.offsetHeight;
  1.5383 +  }
  1.5384 +
  1.5385 +  function addLineWidget(cm, handle, node, options) {
  1.5386 +    var widget = new LineWidget(cm, node, options);
  1.5387 +    if (widget.noHScroll) cm.display.alignWidgets = true;
  1.5388 +    changeLine(cm, handle, "widget", function(line) {
  1.5389 +      var widgets = line.widgets || (line.widgets = []);
  1.5390 +      if (widget.insertAt == null) widgets.push(widget);
  1.5391 +      else widgets.splice(Math.min(widgets.length - 1, Math.max(0, widget.insertAt)), 0, widget);
  1.5392 +      widget.line = line;
  1.5393 +      if (!lineIsHidden(cm.doc, line)) {
  1.5394 +        var aboveVisible = heightAtLine(line) < cm.doc.scrollTop;
  1.5395 +        updateLineHeight(line, line.height + widgetHeight(widget));
  1.5396 +        if (aboveVisible) addToScrollPos(cm, null, widget.height);
  1.5397 +        cm.curOp.forceUpdate = true;
  1.5398 +      }
  1.5399 +      return true;
  1.5400 +    });
  1.5401 +    return widget;
  1.5402 +  }
  1.5403 +
  1.5404 +  // LINE DATA STRUCTURE
  1.5405 +
  1.5406 +  // Line objects. These hold state related to a line, including
  1.5407 +  // highlighting info (the styles array).
  1.5408 +  var Line = CodeMirror.Line = function(text, markedSpans, estimateHeight) {
  1.5409 +    this.text = text;
  1.5410 +    attachMarkedSpans(this, markedSpans);
  1.5411 +    this.height = estimateHeight ? estimateHeight(this) : 1;
  1.5412 +  };
  1.5413 +  eventMixin(Line);
  1.5414 +  Line.prototype.lineNo = function() { return lineNo(this); };
  1.5415 +
  1.5416 +  // Change the content (text, markers) of a line. Automatically
  1.5417 +  // invalidates cached information and tries to re-estimate the
  1.5418 +  // line's height.
  1.5419 +  function updateLine(line, text, markedSpans, estimateHeight) {
  1.5420 +    line.text = text;
  1.5421 +    if (line.stateAfter) line.stateAfter = null;
  1.5422 +    if (line.styles) line.styles = null;
  1.5423 +    if (line.order != null) line.order = null;
  1.5424 +    detachMarkedSpans(line);
  1.5425 +    attachMarkedSpans(line, markedSpans);
  1.5426 +    var estHeight = estimateHeight ? estimateHeight(line) : 1;
  1.5427 +    if (estHeight != line.height) updateLineHeight(line, estHeight);
  1.5428 +  }
  1.5429 +
  1.5430 +  // Detach a line from the document tree and its markers.
  1.5431 +  function cleanUpLine(line) {
  1.5432 +    line.parent = null;
  1.5433 +    detachMarkedSpans(line);
  1.5434 +  }
  1.5435 +
  1.5436 +  // Run the given mode's parser over a line, calling f for each token.
  1.5437 +  function runMode(cm, text, mode, state, f, forceToEnd) {
  1.5438 +    var flattenSpans = mode.flattenSpans;
  1.5439 +    if (flattenSpans == null) flattenSpans = cm.options.flattenSpans;
  1.5440 +    var curStart = 0, curStyle = null;
  1.5441 +    var stream = new StringStream(text, cm.options.tabSize), style;
  1.5442 +    if (text == "" && mode.blankLine) mode.blankLine(state);
  1.5443 +    while (!stream.eol()) {
  1.5444 +      if (stream.pos > cm.options.maxHighlightLength) {
  1.5445 +        flattenSpans = false;
  1.5446 +        if (forceToEnd) processLine(cm, text, state, stream.pos);
  1.5447 +        stream.pos = text.length;
  1.5448 +        style = null;
  1.5449 +      } else {
  1.5450 +        style = mode.token(stream, state);
  1.5451 +      }
  1.5452 +      if (cm.options.addModeClass) {
  1.5453 +        var mName = CodeMirror.innerMode(mode, state).mode.name;
  1.5454 +        if (mName) style = "m-" + (style ? mName + " " + style : mName);
  1.5455 +      }
  1.5456 +      if (!flattenSpans || curStyle != style) {
  1.5457 +        if (curStart < stream.start) f(stream.start, curStyle);
  1.5458 +        curStart = stream.start; curStyle = style;
  1.5459 +      }
  1.5460 +      stream.start = stream.pos;
  1.5461 +    }
  1.5462 +    while (curStart < stream.pos) {
  1.5463 +      // Webkit seems to refuse to render text nodes longer than 57444 characters
  1.5464 +      var pos = Math.min(stream.pos, curStart + 50000);
  1.5465 +      f(pos, curStyle);
  1.5466 +      curStart = pos;
  1.5467 +    }
  1.5468 +  }
  1.5469 +
  1.5470 +  // Compute a style array (an array starting with a mode generation
  1.5471 +  // -- for invalidation -- followed by pairs of end positions and
  1.5472 +  // style strings), which is used to highlight the tokens on the
  1.5473 +  // line.
  1.5474 +  function highlightLine(cm, line, state, forceToEnd) {
  1.5475 +    // A styles array always starts with a number identifying the
  1.5476 +    // mode/overlays that it is based on (for easy invalidation).
  1.5477 +    var st = [cm.state.modeGen];
  1.5478 +    // Compute the base array of styles
  1.5479 +    runMode(cm, line.text, cm.doc.mode, state, function(end, style) {
  1.5480 +      st.push(end, style);
  1.5481 +    }, forceToEnd);
  1.5482 +
  1.5483 +    // Run overlays, adjust style array.
  1.5484 +    for (var o = 0; o < cm.state.overlays.length; ++o) {
  1.5485 +      var overlay = cm.state.overlays[o], i = 1, at = 0;
  1.5486 +      runMode(cm, line.text, overlay.mode, true, function(end, style) {
  1.5487 +        var start = i;
  1.5488 +        // Ensure there's a token end at the current position, and that i points at it
  1.5489 +        while (at < end) {
  1.5490 +          var i_end = st[i];
  1.5491 +          if (i_end > end)
  1.5492 +            st.splice(i, 1, end, st[i+1], i_end);
  1.5493 +          i += 2;
  1.5494 +          at = Math.min(end, i_end);
  1.5495 +        }
  1.5496 +        if (!style) return;
  1.5497 +        if (overlay.opaque) {
  1.5498 +          st.splice(start, i - start, end, style);
  1.5499 +          i = start + 2;
  1.5500 +        } else {
  1.5501 +          for (; start < i; start += 2) {
  1.5502 +            var cur = st[start+1];
  1.5503 +            st[start+1] = cur ? cur + " " + style : style;
  1.5504 +          }
  1.5505 +        }
  1.5506 +      });
  1.5507 +    }
  1.5508 +
  1.5509 +    return st;
  1.5510 +  }
  1.5511 +
  1.5512 +  function getLineStyles(cm, line) {
  1.5513 +    if (!line.styles || line.styles[0] != cm.state.modeGen)
  1.5514 +      line.styles = highlightLine(cm, line, line.stateAfter = getStateBefore(cm, lineNo(line)));
  1.5515 +    return line.styles;
  1.5516 +  }
  1.5517 +
  1.5518 +  // Lightweight form of highlight -- proceed over this line and
  1.5519 +  // update state, but don't save a style array. Used for lines that
  1.5520 +  // aren't currently visible.
  1.5521 +  function processLine(cm, text, state, startAt) {
  1.5522 +    var mode = cm.doc.mode;
  1.5523 +    var stream = new StringStream(text, cm.options.tabSize);
  1.5524 +    stream.start = stream.pos = startAt || 0;
  1.5525 +    if (text == "" && mode.blankLine) mode.blankLine(state);
  1.5526 +    while (!stream.eol() && stream.pos <= cm.options.maxHighlightLength) {
  1.5527 +      mode.token(stream, state);
  1.5528 +      stream.start = stream.pos;
  1.5529 +    }
  1.5530 +  }
  1.5531 +
  1.5532 +  // Convert a style as returned by a mode (either null, or a string
  1.5533 +  // containing one or more styles) to a CSS style. This is cached,
  1.5534 +  // and also looks for line-wide styles.
  1.5535 +  var styleToClassCache = {}, styleToClassCacheWithMode = {};
  1.5536 +  function interpretTokenStyle(style, builder) {
  1.5537 +    if (!style) return null;
  1.5538 +    for (;;) {
  1.5539 +      var lineClass = style.match(/(?:^|\s+)line-(background-)?(\S+)/);
  1.5540 +      if (!lineClass) break;
  1.5541 +      style = style.slice(0, lineClass.index) + style.slice(lineClass.index + lineClass[0].length);
  1.5542 +      var prop = lineClass[1] ? "bgClass" : "textClass";
  1.5543 +      if (builder[prop] == null)
  1.5544 +        builder[prop] = lineClass[2];
  1.5545 +      else if (!(new RegExp("(?:^|\s)" + lineClass[2] + "(?:$|\s)")).test(builder[prop]))
  1.5546 +        builder[prop] += " " + lineClass[2];
  1.5547 +    }
  1.5548 +    if (/^\s*$/.test(style)) return null;
  1.5549 +    var cache = builder.cm.options.addModeClass ? styleToClassCacheWithMode : styleToClassCache;
  1.5550 +    return cache[style] ||
  1.5551 +      (cache[style] = style.replace(/\S+/g, "cm-$&"));
  1.5552 +  }
  1.5553 +
  1.5554 +  // Render the DOM representation of the text of a line. Also builds
  1.5555 +  // up a 'line map', which points at the DOM nodes that represent
  1.5556 +  // specific stretches of text, and is used by the measuring code.
  1.5557 +  // The returned object contains the DOM node, this map, and
  1.5558 +  // information about line-wide styles that were set by the mode.
  1.5559 +  function buildLineContent(cm, lineView) {
  1.5560 +    // The padding-right forces the element to have a 'border', which
  1.5561 +    // is needed on Webkit to be able to get line-level bounding
  1.5562 +    // rectangles for it (in measureChar).
  1.5563 +    var content = elt("span", null, null, webkit ? "padding-right: .1px" : null);
  1.5564 +    var builder = {pre: elt("pre", [content]), content: content, col: 0, pos: 0, cm: cm};
  1.5565 +    lineView.measure = {};
  1.5566 +
  1.5567 +    // Iterate over the logical lines that make up this visual line.
  1.5568 +    for (var i = 0; i <= (lineView.rest ? lineView.rest.length : 0); i++) {
  1.5569 +      var line = i ? lineView.rest[i - 1] : lineView.line, order;
  1.5570 +      builder.pos = 0;
  1.5571 +      builder.addToken = buildToken;
  1.5572 +      // Optionally wire in some hacks into the token-rendering
  1.5573 +      // algorithm, to deal with browser quirks.
  1.5574 +      if ((ie || webkit) && cm.getOption("lineWrapping"))
  1.5575 +        builder.addToken = buildTokenSplitSpaces(builder.addToken);
  1.5576 +      if (hasBadBidiRects(cm.display.measure) && (order = getOrder(line)))
  1.5577 +        builder.addToken = buildTokenBadBidi(builder.addToken, order);
  1.5578 +      builder.map = [];
  1.5579 +      insertLineContent(line, builder, getLineStyles(cm, line));
  1.5580 +
  1.5581 +      // Ensure at least a single node is present, for measuring.
  1.5582 +      if (builder.map.length == 0)
  1.5583 +        builder.map.push(0, 0, builder.content.appendChild(zeroWidthElement(cm.display.measure)));
  1.5584 +
  1.5585 +      // Store the map and a cache object for the current logical line
  1.5586 +      if (i == 0) {
  1.5587 +        lineView.measure.map = builder.map;
  1.5588 +        lineView.measure.cache = {};
  1.5589 +      } else {
  1.5590 +        (lineView.measure.maps || (lineView.measure.maps = [])).push(builder.map);
  1.5591 +        (lineView.measure.caches || (lineView.measure.caches = [])).push({});
  1.5592 +      }
  1.5593 +    }
  1.5594 +
  1.5595 +    signal(cm, "renderLine", cm, lineView.line, builder.pre);
  1.5596 +    return builder;
  1.5597 +  }
  1.5598 +
  1.5599 +  function defaultSpecialCharPlaceholder(ch) {
  1.5600 +    var token = elt("span", "\u2022", "cm-invalidchar");
  1.5601 +    token.title = "\\u" + ch.charCodeAt(0).toString(16);
  1.5602 +    return token;
  1.5603 +  }
  1.5604 +
  1.5605 +  // Build up the DOM representation for a single token, and add it to
  1.5606 +  // the line map. Takes care to render special characters separately.
  1.5607 +  function buildToken(builder, text, style, startStyle, endStyle, title) {
  1.5608 +    if (!text) return;
  1.5609 +    var special = builder.cm.options.specialChars, mustWrap = false;
  1.5610 +    if (!special.test(text)) {
  1.5611 +      builder.col += text.length;
  1.5612 +      var content = document.createTextNode(text);
  1.5613 +      builder.map.push(builder.pos, builder.pos + text.length, content);
  1.5614 +      if (ie_upto8) mustWrap = true;
  1.5615 +      builder.pos += text.length;
  1.5616 +    } else {
  1.5617 +      var content = document.createDocumentFragment(), pos = 0;
  1.5618 +      while (true) {
  1.5619 +        special.lastIndex = pos;
  1.5620 +        var m = special.exec(text);
  1.5621 +        var skipped = m ? m.index - pos : text.length - pos;
  1.5622 +        if (skipped) {
  1.5623 +          var txt = document.createTextNode(text.slice(pos, pos + skipped));
  1.5624 +          if (ie_upto8) content.appendChild(elt("span", [txt]));
  1.5625 +          else content.appendChild(txt);
  1.5626 +          builder.map.push(builder.pos, builder.pos + skipped, txt);
  1.5627 +          builder.col += skipped;
  1.5628 +          builder.pos += skipped;
  1.5629 +        }
  1.5630 +        if (!m) break;
  1.5631 +        pos += skipped + 1;
  1.5632 +        if (m[0] == "\t") {
  1.5633 +          var tabSize = builder.cm.options.tabSize, tabWidth = tabSize - builder.col % tabSize;
  1.5634 +          var txt = content.appendChild(elt("span", spaceStr(tabWidth), "cm-tab"));
  1.5635 +          builder.col += tabWidth;
  1.5636 +        } else {
  1.5637 +          var txt = builder.cm.options.specialCharPlaceholder(m[0]);
  1.5638 +          if (ie_upto8) content.appendChild(elt("span", [txt]));
  1.5639 +          else content.appendChild(txt);
  1.5640 +          builder.col += 1;
  1.5641 +        }
  1.5642 +        builder.map.push(builder.pos, builder.pos + 1, txt);
  1.5643 +        builder.pos++;
  1.5644 +      }
  1.5645 +    }
  1.5646 +    if (style || startStyle || endStyle || mustWrap) {
  1.5647 +      var fullStyle = style || "";
  1.5648 +      if (startStyle) fullStyle += startStyle;
  1.5649 +      if (endStyle) fullStyle += endStyle;
  1.5650 +      var token = elt("span", [content], fullStyle);
  1.5651 +      if (title) token.title = title;
  1.5652 +      return builder.content.appendChild(token);
  1.5653 +    }
  1.5654 +    builder.content.appendChild(content);
  1.5655 +  }
  1.5656 +
  1.5657 +  function buildTokenSplitSpaces(inner) {
  1.5658 +    function split(old) {
  1.5659 +      var out = " ";
  1.5660 +      for (var i = 0; i < old.length - 2; ++i) out += i % 2 ? " " : "\u00a0";
  1.5661 +      out += " ";
  1.5662 +      return out;
  1.5663 +    }
  1.5664 +    return function(builder, text, style, startStyle, endStyle, title) {
  1.5665 +      inner(builder, text.replace(/ {3,}/g, split), style, startStyle, endStyle, title);
  1.5666 +    };
  1.5667 +  }
  1.5668 +
  1.5669 +  // Work around nonsense dimensions being reported for stretches of
  1.5670 +  // right-to-left text.
  1.5671 +  function buildTokenBadBidi(inner, order) {
  1.5672 +    return function(builder, text, style, startStyle, endStyle, title) {
  1.5673 +      style = style ? style + " cm-force-border" : "cm-force-border";
  1.5674 +      var start = builder.pos, end = start + text.length;
  1.5675 +      for (;;) {
  1.5676 +        // Find the part that overlaps with the start of this text
  1.5677 +        for (var i = 0; i < order.length; i++) {
  1.5678 +          var part = order[i];
  1.5679 +          if (part.to > start && part.from <= start) break;
  1.5680 +        }
  1.5681 +        if (part.to >= end) return inner(builder, text, style, startStyle, endStyle, title);
  1.5682 +        inner(builder, text.slice(0, part.to - start), style, startStyle, null, title);
  1.5683 +        startStyle = null;
  1.5684 +        text = text.slice(part.to - start);
  1.5685 +        start = part.to;
  1.5686 +      }
  1.5687 +    };
  1.5688 +  }
  1.5689 +
  1.5690 +  function buildCollapsedSpan(builder, size, marker, ignoreWidget) {
  1.5691 +    var widget = !ignoreWidget && marker.widgetNode;
  1.5692 +    if (widget) {
  1.5693 +      builder.map.push(builder.pos, builder.pos + size, widget);
  1.5694 +      builder.content.appendChild(widget);
  1.5695 +    }
  1.5696 +    builder.pos += size;
  1.5697 +  }
  1.5698 +
  1.5699 +  // Outputs a number of spans to make up a line, taking highlighting
  1.5700 +  // and marked text into account.
  1.5701 +  function insertLineContent(line, builder, styles) {
  1.5702 +    var spans = line.markedSpans, allText = line.text, at = 0;
  1.5703 +    if (!spans) {
  1.5704 +      for (var i = 1; i < styles.length; i+=2)
  1.5705 +        builder.addToken(builder, allText.slice(at, at = styles[i]), interpretTokenStyle(styles[i+1], builder));
  1.5706 +      return;
  1.5707 +    }
  1.5708 +
  1.5709 +    var len = allText.length, pos = 0, i = 1, text = "", style;
  1.5710 +    var nextChange = 0, spanStyle, spanEndStyle, spanStartStyle, title, collapsed;
  1.5711 +    for (;;) {
  1.5712 +      if (nextChange == pos) { // Update current marker set
  1.5713 +        spanStyle = spanEndStyle = spanStartStyle = title = "";
  1.5714 +        collapsed = null; nextChange = Infinity;
  1.5715 +        var foundBookmarks = [];
  1.5716 +        for (var j = 0; j < spans.length; ++j) {
  1.5717 +          var sp = spans[j], m = sp.marker;
  1.5718 +          if (sp.from <= pos && (sp.to == null || sp.to > pos)) {
  1.5719 +            if (sp.to != null && nextChange > sp.to) { nextChange = sp.to; spanEndStyle = ""; }
  1.5720 +            if (m.className) spanStyle += " " + m.className;
  1.5721 +            if (m.startStyle && sp.from == pos) spanStartStyle += " " + m.startStyle;
  1.5722 +            if (m.endStyle && sp.to == nextChange) spanEndStyle += " " + m.endStyle;
  1.5723 +            if (m.title && !title) title = m.title;
  1.5724 +            if (m.collapsed && (!collapsed || compareCollapsedMarkers(collapsed.marker, m) < 0))
  1.5725 +              collapsed = sp;
  1.5726 +          } else if (sp.from > pos && nextChange > sp.from) {
  1.5727 +            nextChange = sp.from;
  1.5728 +          }
  1.5729 +          if (m.type == "bookmark" && sp.from == pos && m.widgetNode) foundBookmarks.push(m);
  1.5730 +        }
  1.5731 +        if (collapsed && (collapsed.from || 0) == pos) {
  1.5732 +          buildCollapsedSpan(builder, (collapsed.to == null ? len + 1 : collapsed.to) - pos,
  1.5733 +                             collapsed.marker, collapsed.from == null);
  1.5734 +          if (collapsed.to == null) return;
  1.5735 +        }
  1.5736 +        if (!collapsed && foundBookmarks.length) for (var j = 0; j < foundBookmarks.length; ++j)
  1.5737 +          buildCollapsedSpan(builder, 0, foundBookmarks[j]);
  1.5738 +      }
  1.5739 +      if (pos >= len) break;
  1.5740 +
  1.5741 +      var upto = Math.min(len, nextChange);
  1.5742 +      while (true) {
  1.5743 +        if (text) {
  1.5744 +          var end = pos + text.length;
  1.5745 +          if (!collapsed) {
  1.5746 +            var tokenText = end > upto ? text.slice(0, upto - pos) : text;
  1.5747 +            builder.addToken(builder, tokenText, style ? style + spanStyle : spanStyle,
  1.5748 +                             spanStartStyle, pos + tokenText.length == nextChange ? spanEndStyle : "", title);
  1.5749 +          }
  1.5750 +          if (end >= upto) {text = text.slice(upto - pos); pos = upto; break;}
  1.5751 +          pos = end;
  1.5752 +          spanStartStyle = "";
  1.5753 +        }
  1.5754 +        text = allText.slice(at, at = styles[i++]);
  1.5755 +        style = interpretTokenStyle(styles[i++], builder);
  1.5756 +      }
  1.5757 +    }
  1.5758 +  }
  1.5759 +
  1.5760 +  // DOCUMENT DATA STRUCTURE
  1.5761 +
  1.5762 +  // By default, updates that start and end at the beginning of a line
  1.5763 +  // are treated specially, in order to make the association of line
  1.5764 +  // widgets and marker elements with the text behave more intuitive.
  1.5765 +  function isWholeLineUpdate(doc, change) {
  1.5766 +    return change.from.ch == 0 && change.to.ch == 0 && lst(change.text) == "" &&
  1.5767 +      (!doc.cm || doc.cm.options.wholeLineUpdateBefore);
  1.5768 +  }
  1.5769 +
  1.5770 +  // Perform a change on the document data structure.
  1.5771 +  function updateDoc(doc, change, markedSpans, estimateHeight) {
  1.5772 +    function spansFor(n) {return markedSpans ? markedSpans[n] : null;}
  1.5773 +    function update(line, text, spans) {
  1.5774 +      updateLine(line, text, spans, estimateHeight);
  1.5775 +      signalLater(line, "change", line, change);
  1.5776 +    }
  1.5777 +
  1.5778 +    var from = change.from, to = change.to, text = change.text;
  1.5779 +    var firstLine = getLine(doc, from.line), lastLine = getLine(doc, to.line);
  1.5780 +    var lastText = lst(text), lastSpans = spansFor(text.length - 1), nlines = to.line - from.line;
  1.5781 +
  1.5782 +    // Adjust the line structure
  1.5783 +    if (isWholeLineUpdate(doc, change)) {
  1.5784 +      // This is a whole-line replace. Treated specially to make
  1.5785 +      // sure line objects move the way they are supposed to.
  1.5786 +      for (var i = 0, added = []; i < text.length - 1; ++i)
  1.5787 +        added.push(new Line(text[i], spansFor(i), estimateHeight));
  1.5788 +      update(lastLine, lastLine.text, lastSpans);
  1.5789 +      if (nlines) doc.remove(from.line, nlines);
  1.5790 +      if (added.length) doc.insert(from.line, added);
  1.5791 +    } else if (firstLine == lastLine) {
  1.5792 +      if (text.length == 1) {
  1.5793 +        update(firstLine, firstLine.text.slice(0, from.ch) + lastText + firstLine.text.slice(to.ch), lastSpans);
  1.5794 +      } else {
  1.5795 +        for (var added = [], i = 1; i < text.length - 1; ++i)
  1.5796 +          added.push(new Line(text[i], spansFor(i), estimateHeight));
  1.5797 +        added.push(new Line(lastText + firstLine.text.slice(to.ch), lastSpans, estimateHeight));
  1.5798 +        update(firstLine, firstLine.text.slice(0, from.ch) + text[0], spansFor(0));
  1.5799 +        doc.insert(from.line + 1, added);
  1.5800 +      }
  1.5801 +    } else if (text.length == 1) {
  1.5802 +      update(firstLine, firstLine.text.slice(0, from.ch) + text[0] + lastLine.text.slice(to.ch), spansFor(0));
  1.5803 +      doc.remove(from.line + 1, nlines);
  1.5804 +    } else {
  1.5805 +      update(firstLine, firstLine.text.slice(0, from.ch) + text[0], spansFor(0));
  1.5806 +      update(lastLine, lastText + lastLine.text.slice(to.ch), lastSpans);
  1.5807 +      for (var i = 1, added = []; i < text.length - 1; ++i)
  1.5808 +        added.push(new Line(text[i], spansFor(i), estimateHeight));
  1.5809 +      if (nlines > 1) doc.remove(from.line + 1, nlines - 1);
  1.5810 +      doc.insert(from.line + 1, added);
  1.5811 +    }
  1.5812 +
  1.5813 +    signalLater(doc, "change", doc, change);
  1.5814 +  }
  1.5815 +
  1.5816 +  // The document is represented as a BTree consisting of leaves, with
  1.5817 +  // chunk of lines in them, and branches, with up to ten leaves or
  1.5818 +  // other branch nodes below them. The top node is always a branch
  1.5819 +  // node, and is the document object itself (meaning it has
  1.5820 +  // additional methods and properties).
  1.5821 +  //
  1.5822 +  // All nodes have parent links. The tree is used both to go from
  1.5823 +  // line numbers to line objects, and to go from objects to numbers.
  1.5824 +  // It also indexes by height, and is used to convert between height
  1.5825 +  // and line object, and to find the total height of the document.
  1.5826 +  //
  1.5827 +  // See also http://marijnhaverbeke.nl/blog/codemirror-line-tree.html
  1.5828 +
  1.5829 +  function LeafChunk(lines) {
  1.5830 +    this.lines = lines;
  1.5831 +    this.parent = null;
  1.5832 +    for (var i = 0, height = 0; i < lines.length; ++i) {
  1.5833 +      lines[i].parent = this;
  1.5834 +      height += lines[i].height;
  1.5835 +    }
  1.5836 +    this.height = height;
  1.5837 +  }
  1.5838 +
  1.5839 +  LeafChunk.prototype = {
  1.5840 +    chunkSize: function() { return this.lines.length; },
  1.5841 +    // Remove the n lines at offset 'at'.
  1.5842 +    removeInner: function(at, n) {
  1.5843 +      for (var i = at, e = at + n; i < e; ++i) {
  1.5844 +        var line = this.lines[i];
  1.5845 +        this.height -= line.height;
  1.5846 +        cleanUpLine(line);
  1.5847 +        signalLater(line, "delete");
  1.5848 +      }
  1.5849 +      this.lines.splice(at, n);
  1.5850 +    },
  1.5851 +    // Helper used to collapse a small branch into a single leaf.
  1.5852 +    collapse: function(lines) {
  1.5853 +      lines.push.apply(lines, this.lines);
  1.5854 +    },
  1.5855 +    // Insert the given array of lines at offset 'at', count them as
  1.5856 +    // having the given height.
  1.5857 +    insertInner: function(at, lines, height) {
  1.5858 +      this.height += height;
  1.5859 +      this.lines = this.lines.slice(0, at).concat(lines).concat(this.lines.slice(at));
  1.5860 +      for (var i = 0; i < lines.length; ++i) lines[i].parent = this;
  1.5861 +    },
  1.5862 +    // Used to iterate over a part of the tree.
  1.5863 +    iterN: function(at, n, op) {
  1.5864 +      for (var e = at + n; at < e; ++at)
  1.5865 +        if (op(this.lines[at])) return true;
  1.5866 +    }
  1.5867 +  };
  1.5868 +
  1.5869 +  function BranchChunk(children) {
  1.5870 +    this.children = children;
  1.5871 +    var size = 0, height = 0;
  1.5872 +    for (var i = 0; i < children.length; ++i) {
  1.5873 +      var ch = children[i];
  1.5874 +      size += ch.chunkSize(); height += ch.height;
  1.5875 +      ch.parent = this;
  1.5876 +    }
  1.5877 +    this.size = size;
  1.5878 +    this.height = height;
  1.5879 +    this.parent = null;
  1.5880 +  }
  1.5881 +
  1.5882 +  BranchChunk.prototype = {
  1.5883 +    chunkSize: function() { return this.size; },
  1.5884 +    removeInner: function(at, n) {
  1.5885 +      this.size -= n;
  1.5886 +      for (var i = 0; i < this.children.length; ++i) {
  1.5887 +        var child = this.children[i], sz = child.chunkSize();
  1.5888 +        if (at < sz) {
  1.5889 +          var rm = Math.min(n, sz - at), oldHeight = child.height;
  1.5890 +          child.removeInner(at, rm);
  1.5891 +          this.height -= oldHeight - child.height;
  1.5892 +          if (sz == rm) { this.children.splice(i--, 1); child.parent = null; }
  1.5893 +          if ((n -= rm) == 0) break;
  1.5894 +          at = 0;
  1.5895 +        } else at -= sz;
  1.5896 +      }
  1.5897 +      // If the result is smaller than 25 lines, ensure that it is a
  1.5898 +      // single leaf node.
  1.5899 +      if (this.size - n < 25 &&
  1.5900 +          (this.children.length > 1 || !(this.children[0] instanceof LeafChunk))) {
  1.5901 +        var lines = [];
  1.5902 +        this.collapse(lines);
  1.5903 +        this.children = [new LeafChunk(lines)];
  1.5904 +        this.children[0].parent = this;
  1.5905 +      }
  1.5906 +    },
  1.5907 +    collapse: function(lines) {
  1.5908 +      for (var i = 0; i < this.children.length; ++i) this.children[i].collapse(lines);
  1.5909 +    },
  1.5910 +    insertInner: function(at, lines, height) {
  1.5911 +      this.size += lines.length;
  1.5912 +      this.height += height;
  1.5913 +      for (var i = 0; i < this.children.length; ++i) {
  1.5914 +        var child = this.children[i], sz = child.chunkSize();
  1.5915 +        if (at <= sz) {
  1.5916 +          child.insertInner(at, lines, height);
  1.5917 +          if (child.lines && child.lines.length > 50) {
  1.5918 +            while (child.lines.length > 50) {
  1.5919 +              var spilled = child.lines.splice(child.lines.length - 25, 25);
  1.5920 +              var newleaf = new LeafChunk(spilled);
  1.5921 +              child.height -= newleaf.height;
  1.5922 +              this.children.splice(i + 1, 0, newleaf);
  1.5923 +              newleaf.parent = this;
  1.5924 +            }
  1.5925 +            this.maybeSpill();
  1.5926 +          }
  1.5927 +          break;
  1.5928 +        }
  1.5929 +        at -= sz;
  1.5930 +      }
  1.5931 +    },
  1.5932 +    // When a node has grown, check whether it should be split.
  1.5933 +    maybeSpill: function() {
  1.5934 +      if (this.children.length <= 10) return;
  1.5935 +      var me = this;
  1.5936 +      do {
  1.5937 +        var spilled = me.children.splice(me.children.length - 5, 5);
  1.5938 +        var sibling = new BranchChunk(spilled);
  1.5939 +        if (!me.parent) { // Become the parent node
  1.5940 +          var copy = new BranchChunk(me.children);
  1.5941 +          copy.parent = me;
  1.5942 +          me.children = [copy, sibling];
  1.5943 +          me = copy;
  1.5944 +        } else {
  1.5945 +          me.size -= sibling.size;
  1.5946 +          me.height -= sibling.height;
  1.5947 +          var myIndex = indexOf(me.parent.children, me);
  1.5948 +          me.parent.children.splice(myIndex + 1, 0, sibling);
  1.5949 +        }
  1.5950 +        sibling.parent = me.parent;
  1.5951 +      } while (me.children.length > 10);
  1.5952 +      me.parent.maybeSpill();
  1.5953 +    },
  1.5954 +    iterN: function(at, n, op) {
  1.5955 +      for (var i = 0; i < this.children.length; ++i) {
  1.5956 +        var child = this.children[i], sz = child.chunkSize();
  1.5957 +        if (at < sz) {
  1.5958 +          var used = Math.min(n, sz - at);
  1.5959 +          if (child.iterN(at, used, op)) return true;
  1.5960 +          if ((n -= used) == 0) break;
  1.5961 +          at = 0;
  1.5962 +        } else at -= sz;
  1.5963 +      }
  1.5964 +    }
  1.5965 +  };
  1.5966 +
  1.5967 +  var nextDocId = 0;
  1.5968 +  var Doc = CodeMirror.Doc = function(text, mode, firstLine) {
  1.5969 +    if (!(this instanceof Doc)) return new Doc(text, mode, firstLine);
  1.5970 +    if (firstLine == null) firstLine = 0;
  1.5971 +
  1.5972 +    BranchChunk.call(this, [new LeafChunk([new Line("", null)])]);
  1.5973 +    this.first = firstLine;
  1.5974 +    this.scrollTop = this.scrollLeft = 0;
  1.5975 +    this.cantEdit = false;
  1.5976 +    this.cleanGeneration = 1;
  1.5977 +    this.frontier = firstLine;
  1.5978 +    var start = Pos(firstLine, 0);
  1.5979 +    this.sel = simpleSelection(start);
  1.5980 +    this.history = new History(null);
  1.5981 +    this.id = ++nextDocId;
  1.5982 +    this.modeOption = mode;
  1.5983 +
  1.5984 +    if (typeof text == "string") text = splitLines(text);
  1.5985 +    updateDoc(this, {from: start, to: start, text: text});
  1.5986 +    setSelection(this, simpleSelection(start), sel_dontScroll);
  1.5987 +  };
  1.5988 +
  1.5989 +  Doc.prototype = createObj(BranchChunk.prototype, {
  1.5990 +    constructor: Doc,
  1.5991 +    // Iterate over the document. Supports two forms -- with only one
  1.5992 +    // argument, it calls that for each line in the document. With
  1.5993 +    // three, it iterates over the range given by the first two (with
  1.5994 +    // the second being non-inclusive).
  1.5995 +    iter: function(from, to, op) {
  1.5996 +      if (op) this.iterN(from - this.first, to - from, op);
  1.5997 +      else this.iterN(this.first, this.first + this.size, from);
  1.5998 +    },
  1.5999 +
  1.6000 +    // Non-public interface for adding and removing lines.
  1.6001 +    insert: function(at, lines) {
  1.6002 +      var height = 0;
  1.6003 +      for (var i = 0; i < lines.length; ++i) height += lines[i].height;
  1.6004 +      this.insertInner(at - this.first, lines, height);
  1.6005 +    },
  1.6006 +    remove: function(at, n) { this.removeInner(at - this.first, n); },
  1.6007 +
  1.6008 +    // From here, the methods are part of the public interface. Most
  1.6009 +    // are also available from CodeMirror (editor) instances.
  1.6010 +
  1.6011 +    getValue: function(lineSep) {
  1.6012 +      var lines = getLines(this, this.first, this.first + this.size);
  1.6013 +      if (lineSep === false) return lines;
  1.6014 +      return lines.join(lineSep || "\n");
  1.6015 +    },
  1.6016 +    setValue: docMethodOp(function(code) {
  1.6017 +      var top = Pos(this.first, 0), last = this.first + this.size - 1;
  1.6018 +      makeChange(this, {from: top, to: Pos(last, getLine(this, last).text.length),
  1.6019 +                        text: splitLines(code), origin: "setValue"}, true);
  1.6020 +      setSelection(this, simpleSelection(top));
  1.6021 +    }),
  1.6022 +    replaceRange: function(code, from, to, origin) {
  1.6023 +      from = clipPos(this, from);
  1.6024 +      to = to ? clipPos(this, to) : from;
  1.6025 +      replaceRange(this, code, from, to, origin);
  1.6026 +    },
  1.6027 +    getRange: function(from, to, lineSep) {
  1.6028 +      var lines = getBetween(this, clipPos(this, from), clipPos(this, to));
  1.6029 +      if (lineSep === false) return lines;
  1.6030 +      return lines.join(lineSep || "\n");
  1.6031 +    },
  1.6032 +
  1.6033 +    getLine: function(line) {var l = this.getLineHandle(line); return l && l.text;},
  1.6034 +
  1.6035 +    getLineHandle: function(line) {if (isLine(this, line)) return getLine(this, line);},
  1.6036 +    getLineNumber: function(line) {return lineNo(line);},
  1.6037 +
  1.6038 +    getLineHandleVisualStart: function(line) {
  1.6039 +      if (typeof line == "number") line = getLine(this, line);
  1.6040 +      return visualLine(line);
  1.6041 +    },
  1.6042 +
  1.6043 +    lineCount: function() {return this.size;},
  1.6044 +    firstLine: function() {return this.first;},
  1.6045 +    lastLine: function() {return this.first + this.size - 1;},
  1.6046 +
  1.6047 +    clipPos: function(pos) {return clipPos(this, pos);},
  1.6048 +
  1.6049 +    getCursor: function(start) {
  1.6050 +      var range = this.sel.primary(), pos;
  1.6051 +      if (start == null || start == "head") pos = range.head;
  1.6052 +      else if (start == "anchor") pos = range.anchor;
  1.6053 +      else if (start == "end" || start == "to" || start === false) pos = range.to();
  1.6054 +      else pos = range.from();
  1.6055 +      return pos;
  1.6056 +    },
  1.6057 +    listSelections: function() { return this.sel.ranges; },
  1.6058 +    somethingSelected: function() {return this.sel.somethingSelected();},
  1.6059 +
  1.6060 +    setCursor: docMethodOp(function(line, ch, options) {
  1.6061 +      setSimpleSelection(this, clipPos(this, typeof line == "number" ? Pos(line, ch || 0) : line), null, options);
  1.6062 +    }),
  1.6063 +    setSelection: docMethodOp(function(anchor, head, options) {
  1.6064 +      setSimpleSelection(this, clipPos(this, anchor), clipPos(this, head || anchor), options);
  1.6065 +    }),
  1.6066 +    extendSelection: docMethodOp(function(head, other, options) {
  1.6067 +      extendSelection(this, clipPos(this, head), other && clipPos(this, other), options);
  1.6068 +    }),
  1.6069 +    extendSelections: docMethodOp(function(heads, options) {
  1.6070 +      extendSelections(this, clipPosArray(this, heads, options));
  1.6071 +    }),
  1.6072 +    extendSelectionsBy: docMethodOp(function(f, options) {
  1.6073 +      extendSelections(this, map(this.sel.ranges, f), options);
  1.6074 +    }),
  1.6075 +    setSelections: docMethodOp(function(ranges, primary, options) {
  1.6076 +      if (!ranges.length) return;
  1.6077 +      for (var i = 0, out = []; i < ranges.length; i++)
  1.6078 +        out[i] = new Range(clipPos(this, ranges[i].anchor),
  1.6079 +                           clipPos(this, ranges[i].head));
  1.6080 +      if (primary == null) primary = Math.min(ranges.length - 1, this.sel.primIndex);
  1.6081 +      setSelection(this, normalizeSelection(out, primary), options);
  1.6082 +    }),
  1.6083 +    addSelection: docMethodOp(function(anchor, head, options) {
  1.6084 +      var ranges = this.sel.ranges.slice(0);
  1.6085 +      ranges.push(new Range(clipPos(this, anchor), clipPos(this, head || anchor)));
  1.6086 +      setSelection(this, normalizeSelection(ranges, ranges.length - 1), options);
  1.6087 +    }),
  1.6088 +
  1.6089 +    getSelection: function(lineSep) {
  1.6090 +      var ranges = this.sel.ranges, lines;
  1.6091 +      for (var i = 0; i < ranges.length; i++) {
  1.6092 +        var sel = getBetween(this, ranges[i].from(), ranges[i].to());
  1.6093 +        lines = lines ? lines.concat(sel) : sel;
  1.6094 +      }
  1.6095 +      if (lineSep === false) return lines;
  1.6096 +      else return lines.join(lineSep || "\n");
  1.6097 +    },
  1.6098 +    getSelections: function(lineSep) {
  1.6099 +      var parts = [], ranges = this.sel.ranges;
  1.6100 +      for (var i = 0; i < ranges.length; i++) {
  1.6101 +        var sel = getBetween(this, ranges[i].from(), ranges[i].to());
  1.6102 +        if (lineSep !== false) sel = sel.join(lineSep || "\n");
  1.6103 +        parts[i] = sel;
  1.6104 +      }
  1.6105 +      return parts;
  1.6106 +    },
  1.6107 +    replaceSelection: docMethodOp(function(code, collapse, origin) {
  1.6108 +      var dup = [];
  1.6109 +      for (var i = 0; i < this.sel.ranges.length; i++)
  1.6110 +        dup[i] = code;
  1.6111 +      this.replaceSelections(dup, collapse, origin || "+input");
  1.6112 +    }),
  1.6113 +    replaceSelections: function(code, collapse, origin) {
  1.6114 +      var changes = [], sel = this.sel;
  1.6115 +      for (var i = 0; i < sel.ranges.length; i++) {
  1.6116 +        var range = sel.ranges[i];
  1.6117 +        changes[i] = {from: range.from(), to: range.to(), text: splitLines(code[i]), origin: origin};
  1.6118 +      }
  1.6119 +      var newSel = collapse && collapse != "end" && computeReplacedSel(this, changes, collapse);
  1.6120 +      for (var i = changes.length - 1; i >= 0; i--)
  1.6121 +        makeChange(this, changes[i]);
  1.6122 +      if (newSel) setSelectionReplaceHistory(this, newSel);
  1.6123 +      else if (this.cm) ensureCursorVisible(this.cm);
  1.6124 +    },
  1.6125 +    undo: docMethodOp(function() {makeChangeFromHistory(this, "undo");}),
  1.6126 +    redo: docMethodOp(function() {makeChangeFromHistory(this, "redo");}),
  1.6127 +    undoSelection: docMethodOp(function() {makeChangeFromHistory(this, "undo", true);}),
  1.6128 +    redoSelection: docMethodOp(function() {makeChangeFromHistory(this, "redo", true);}),
  1.6129 +
  1.6130 +    setExtending: function(val) {this.extend = val;},
  1.6131 +    getExtending: function() {return this.extend;},
  1.6132 +
  1.6133 +    historySize: function() {
  1.6134 +      var hist = this.history, done = 0, undone = 0;
  1.6135 +      for (var i = 0; i < hist.done.length; i++) if (!hist.done[i].ranges) ++done;
  1.6136 +      for (var i = 0; i < hist.undone.length; i++) if (!hist.undone[i].ranges) ++undone;
  1.6137 +      return {undo: done, redo: undone};
  1.6138 +    },
  1.6139 +    clearHistory: function() {this.history = new History(this.history.maxGeneration);},
  1.6140 +
  1.6141 +    markClean: function() {
  1.6142 +      this.cleanGeneration = this.changeGeneration(true);
  1.6143 +    },
  1.6144 +    changeGeneration: function(forceSplit) {
  1.6145 +      if (forceSplit)
  1.6146 +        this.history.lastOp = this.history.lastOrigin = null;
  1.6147 +      return this.history.generation;
  1.6148 +    },
  1.6149 +    isClean: function (gen) {
  1.6150 +      return this.history.generation == (gen || this.cleanGeneration);
  1.6151 +    },
  1.6152 +
  1.6153 +    getHistory: function() {
  1.6154 +      return {done: copyHistoryArray(this.history.done),
  1.6155 +              undone: copyHistoryArray(this.history.undone)};
  1.6156 +    },
  1.6157 +    setHistory: function(histData) {
  1.6158 +      var hist = this.history = new History(this.history.maxGeneration);
  1.6159 +      hist.done = copyHistoryArray(histData.done.slice(0), null, true);
  1.6160 +      hist.undone = copyHistoryArray(histData.undone.slice(0), null, true);
  1.6161 +    },
  1.6162 +
  1.6163 +    markText: function(from, to, options) {
  1.6164 +      return markText(this, clipPos(this, from), clipPos(this, to), options, "range");
  1.6165 +    },
  1.6166 +    setBookmark: function(pos, options) {
  1.6167 +      var realOpts = {replacedWith: options && (options.nodeType == null ? options.widget : options),
  1.6168 +                      insertLeft: options && options.insertLeft,
  1.6169 +                      clearWhenEmpty: false, shared: options && options.shared};
  1.6170 +      pos = clipPos(this, pos);
  1.6171 +      return markText(this, pos, pos, realOpts, "bookmark");
  1.6172 +    },
  1.6173 +    findMarksAt: function(pos) {
  1.6174 +      pos = clipPos(this, pos);
  1.6175 +      var markers = [], spans = getLine(this, pos.line).markedSpans;
  1.6176 +      if (spans) for (var i = 0; i < spans.length; ++i) {
  1.6177 +        var span = spans[i];
  1.6178 +        if ((span.from == null || span.from <= pos.ch) &&
  1.6179 +            (span.to == null || span.to >= pos.ch))
  1.6180 +          markers.push(span.marker.parent || span.marker);
  1.6181 +      }
  1.6182 +      return markers;
  1.6183 +    },
  1.6184 +    findMarks: function(from, to) {
  1.6185 +      from = clipPos(this, from); to = clipPos(this, to);
  1.6186 +      var found = [], lineNo = from.line;
  1.6187 +      this.iter(from.line, to.line + 1, function(line) {
  1.6188 +        var spans = line.markedSpans;
  1.6189 +        if (spans) for (var i = 0; i < spans.length; i++) {
  1.6190 +          var span = spans[i];
  1.6191 +          if (!(lineNo == from.line && from.ch > span.to ||
  1.6192 +                span.from == null && lineNo != from.line||
  1.6193 +                lineNo == to.line && span.from > to.ch))
  1.6194 +            found.push(span.marker.parent || span.marker);
  1.6195 +        }
  1.6196 +        ++lineNo;
  1.6197 +      });
  1.6198 +      return found;
  1.6199 +    },
  1.6200 +    getAllMarks: function() {
  1.6201 +      var markers = [];
  1.6202 +      this.iter(function(line) {
  1.6203 +        var sps = line.markedSpans;
  1.6204 +        if (sps) for (var i = 0; i < sps.length; ++i)
  1.6205 +          if (sps[i].from != null) markers.push(sps[i].marker);
  1.6206 +      });
  1.6207 +      return markers;
  1.6208 +    },
  1.6209 +
  1.6210 +    posFromIndex: function(off) {
  1.6211 +      var ch, lineNo = this.first;
  1.6212 +      this.iter(function(line) {
  1.6213 +        var sz = line.text.length + 1;
  1.6214 +        if (sz > off) { ch = off; return true; }
  1.6215 +        off -= sz;
  1.6216 +        ++lineNo;
  1.6217 +      });
  1.6218 +      return clipPos(this, Pos(lineNo, ch));
  1.6219 +    },
  1.6220 +    indexFromPos: function (coords) {
  1.6221 +      coords = clipPos(this, coords);
  1.6222 +      var index = coords.ch;
  1.6223 +      if (coords.line < this.first || coords.ch < 0) return 0;
  1.6224 +      this.iter(this.first, coords.line, function (line) {
  1.6225 +        index += line.text.length + 1;
  1.6226 +      });
  1.6227 +      return index;
  1.6228 +    },
  1.6229 +
  1.6230 +    copy: function(copyHistory) {
  1.6231 +      var doc = new Doc(getLines(this, this.first, this.first + this.size), this.modeOption, this.first);
  1.6232 +      doc.scrollTop = this.scrollTop; doc.scrollLeft = this.scrollLeft;
  1.6233 +      doc.sel = this.sel;
  1.6234 +      doc.extend = false;
  1.6235 +      if (copyHistory) {
  1.6236 +        doc.history.undoDepth = this.history.undoDepth;
  1.6237 +        doc.setHistory(this.getHistory());
  1.6238 +      }
  1.6239 +      return doc;
  1.6240 +    },
  1.6241 +
  1.6242 +    linkedDoc: function(options) {
  1.6243 +      if (!options) options = {};
  1.6244 +      var from = this.first, to = this.first + this.size;
  1.6245 +      if (options.from != null && options.from > from) from = options.from;
  1.6246 +      if (options.to != null && options.to < to) to = options.to;
  1.6247 +      var copy = new Doc(getLines(this, from, to), options.mode || this.modeOption, from);
  1.6248 +      if (options.sharedHist) copy.history = this.history;
  1.6249 +      (this.linked || (this.linked = [])).push({doc: copy, sharedHist: options.sharedHist});
  1.6250 +      copy.linked = [{doc: this, isParent: true, sharedHist: options.sharedHist}];
  1.6251 +      return copy;
  1.6252 +    },
  1.6253 +    unlinkDoc: function(other) {
  1.6254 +      if (other instanceof CodeMirror) other = other.doc;
  1.6255 +      if (this.linked) for (var i = 0; i < this.linked.length; ++i) {
  1.6256 +        var link = this.linked[i];
  1.6257 +        if (link.doc != other) continue;
  1.6258 +        this.linked.splice(i, 1);
  1.6259 +        other.unlinkDoc(this);
  1.6260 +        break;
  1.6261 +      }
  1.6262 +      // If the histories were shared, split them again
  1.6263 +      if (other.history == this.history) {
  1.6264 +        var splitIds = [other.id];
  1.6265 +        linkedDocs(other, function(doc) {splitIds.push(doc.id);}, true);
  1.6266 +        other.history = new History(null);
  1.6267 +        other.history.done = copyHistoryArray(this.history.done, splitIds);
  1.6268 +        other.history.undone = copyHistoryArray(this.history.undone, splitIds);
  1.6269 +      }
  1.6270 +    },
  1.6271 +    iterLinkedDocs: function(f) {linkedDocs(this, f);},
  1.6272 +
  1.6273 +    getMode: function() {return this.mode;},
  1.6274 +    getEditor: function() {return this.cm;}
  1.6275 +  });
  1.6276 +
  1.6277 +  // Public alias.
  1.6278 +  Doc.prototype.eachLine = Doc.prototype.iter;
  1.6279 +
  1.6280 +  // Set up methods on CodeMirror's prototype to redirect to the editor's document.
  1.6281 +  var dontDelegate = "iter insert remove copy getEditor".split(" ");
  1.6282 +  for (var prop in Doc.prototype) if (Doc.prototype.hasOwnProperty(prop) && indexOf(dontDelegate, prop) < 0)
  1.6283 +    CodeMirror.prototype[prop] = (function(method) {
  1.6284 +      return function() {return method.apply(this.doc, arguments);};
  1.6285 +    })(Doc.prototype[prop]);
  1.6286 +
  1.6287 +  eventMixin(Doc);
  1.6288 +
  1.6289 +  // Call f for all linked documents.
  1.6290 +  function linkedDocs(doc, f, sharedHistOnly) {
  1.6291 +    function propagate(doc, skip, sharedHist) {
  1.6292 +      if (doc.linked) for (var i = 0; i < doc.linked.length; ++i) {
  1.6293 +        var rel = doc.linked[i];
  1.6294 +        if (rel.doc == skip) continue;
  1.6295 +        var shared = sharedHist && rel.sharedHist;
  1.6296 +        if (sharedHistOnly && !shared) continue;
  1.6297 +        f(rel.doc, shared);
  1.6298 +        propagate(rel.doc, doc, shared);
  1.6299 +      }
  1.6300 +    }
  1.6301 +    propagate(doc, null, true);
  1.6302 +  }
  1.6303 +
  1.6304 +  // Attach a document to an editor.
  1.6305 +  function attachDoc(cm, doc) {
  1.6306 +    if (doc.cm) throw new Error("This document is already in use.");
  1.6307 +    cm.doc = doc;
  1.6308 +    doc.cm = cm;
  1.6309 +    estimateLineHeights(cm);
  1.6310 +    loadMode(cm);
  1.6311 +    if (!cm.options.lineWrapping) findMaxLine(cm);
  1.6312 +    cm.options.mode = doc.modeOption;
  1.6313 +    regChange(cm);
  1.6314 +  }
  1.6315 +
  1.6316 +  // LINE UTILITIES
  1.6317 +
  1.6318 +  // Find the line object corresponding to the given line number.
  1.6319 +  function getLine(doc, n) {
  1.6320 +    n -= doc.first;
  1.6321 +    if (n < 0 || n >= doc.size) throw new Error("There is no line " + (n + doc.first) + " in the document.");
  1.6322 +    for (var chunk = doc; !chunk.lines;) {
  1.6323 +      for (var i = 0;; ++i) {
  1.6324 +        var child = chunk.children[i], sz = child.chunkSize();
  1.6325 +        if (n < sz) { chunk = child; break; }
  1.6326 +        n -= sz;
  1.6327 +      }
  1.6328 +    }
  1.6329 +    return chunk.lines[n];
  1.6330 +  }
  1.6331 +
  1.6332 +  // Get the part of a document between two positions, as an array of
  1.6333 +  // strings.
  1.6334 +  function getBetween(doc, start, end) {
  1.6335 +    var out = [], n = start.line;
  1.6336 +    doc.iter(start.line, end.line + 1, function(line) {
  1.6337 +      var text = line.text;
  1.6338 +      if (n == end.line) text = text.slice(0, end.ch);
  1.6339 +      if (n == start.line) text = text.slice(start.ch);
  1.6340 +      out.push(text);
  1.6341 +      ++n;
  1.6342 +    });
  1.6343 +    return out;
  1.6344 +  }
  1.6345 +  // Get the lines between from and to, as array of strings.
  1.6346 +  function getLines(doc, from, to) {
  1.6347 +    var out = [];
  1.6348 +    doc.iter(from, to, function(line) { out.push(line.text); });
  1.6349 +    return out;
  1.6350 +  }
  1.6351 +
  1.6352 +  // Update the height of a line, propagating the height change
  1.6353 +  // upwards to parent nodes.
  1.6354 +  function updateLineHeight(line, height) {
  1.6355 +    var diff = height - line.height;
  1.6356 +    if (diff) for (var n = line; n; n = n.parent) n.height += diff;
  1.6357 +  }
  1.6358 +
  1.6359 +  // Given a line object, find its line number by walking up through
  1.6360 +  // its parent links.
  1.6361 +  function lineNo(line) {
  1.6362 +    if (line.parent == null) return null;
  1.6363 +    var cur = line.parent, no = indexOf(cur.lines, line);
  1.6364 +    for (var chunk = cur.parent; chunk; cur = chunk, chunk = chunk.parent) {
  1.6365 +      for (var i = 0;; ++i) {
  1.6366 +        if (chunk.children[i] == cur) break;
  1.6367 +        no += chunk.children[i].chunkSize();
  1.6368 +      }
  1.6369 +    }
  1.6370 +    return no + cur.first;
  1.6371 +  }
  1.6372 +
  1.6373 +  // Find the line at the given vertical position, using the height
  1.6374 +  // information in the document tree.
  1.6375 +  function lineAtHeight(chunk, h) {
  1.6376 +    var n = chunk.first;
  1.6377 +    outer: do {
  1.6378 +      for (var i = 0; i < chunk.children.length; ++i) {
  1.6379 +        var child = chunk.children[i], ch = child.height;
  1.6380 +        if (h < ch) { chunk = child; continue outer; }
  1.6381 +        h -= ch;
  1.6382 +        n += child.chunkSize();
  1.6383 +      }
  1.6384 +      return n;
  1.6385 +    } while (!chunk.lines);
  1.6386 +    for (var i = 0; i < chunk.lines.length; ++i) {
  1.6387 +      var line = chunk.lines[i], lh = line.height;
  1.6388 +      if (h < lh) break;
  1.6389 +      h -= lh;
  1.6390 +    }
  1.6391 +    return n + i;
  1.6392 +  }
  1.6393 +
  1.6394 +
  1.6395 +  // Find the height above the given line.
  1.6396 +  function heightAtLine(lineObj) {
  1.6397 +    lineObj = visualLine(lineObj);
  1.6398 +
  1.6399 +    var h = 0, chunk = lineObj.parent;
  1.6400 +    for (var i = 0; i < chunk.lines.length; ++i) {
  1.6401 +      var line = chunk.lines[i];
  1.6402 +      if (line == lineObj) break;
  1.6403 +      else h += line.height;
  1.6404 +    }
  1.6405 +    for (var p = chunk.parent; p; chunk = p, p = chunk.parent) {
  1.6406 +      for (var i = 0; i < p.children.length; ++i) {
  1.6407 +        var cur = p.children[i];
  1.6408 +        if (cur == chunk) break;
  1.6409 +        else h += cur.height;
  1.6410 +      }
  1.6411 +    }
  1.6412 +    return h;
  1.6413 +  }
  1.6414 +
  1.6415 +  // Get the bidi ordering for the given line (and cache it). Returns
  1.6416 +  // false for lines that are fully left-to-right, and an array of
  1.6417 +  // BidiSpan objects otherwise.
  1.6418 +  function getOrder(line) {
  1.6419 +    var order = line.order;
  1.6420 +    if (order == null) order = line.order = bidiOrdering(line.text);
  1.6421 +    return order;
  1.6422 +  }
  1.6423 +
  1.6424 +  // HISTORY
  1.6425 +
  1.6426 +  function History(startGen) {
  1.6427 +    // Arrays of change events and selections. Doing something adds an
  1.6428 +    // event to done and clears undo. Undoing moves events from done
  1.6429 +    // to undone, redoing moves them in the other direction.
  1.6430 +    this.done = []; this.undone = [];
  1.6431 +    this.undoDepth = Infinity;
  1.6432 +    // Used to track when changes can be merged into a single undo
  1.6433 +    // event
  1.6434 +    this.lastModTime = this.lastSelTime = 0;
  1.6435 +    this.lastOp = null;
  1.6436 +    this.lastOrigin = this.lastSelOrigin = null;
  1.6437 +    // Used by the isClean() method
  1.6438 +    this.generation = this.maxGeneration = startGen || 1;
  1.6439 +  }
  1.6440 +
  1.6441 +  // Create a history change event from an updateDoc-style change
  1.6442 +  // object.
  1.6443 +  function historyChangeFromChange(doc, change) {
  1.6444 +    var histChange = {from: copyPos(change.from), to: changeEnd(change), text: getBetween(doc, change.from, change.to)};
  1.6445 +    attachLocalSpans(doc, histChange, change.from.line, change.to.line + 1);
  1.6446 +    linkedDocs(doc, function(doc) {attachLocalSpans(doc, histChange, change.from.line, change.to.line + 1);}, true);
  1.6447 +    return histChange;
  1.6448 +  }
  1.6449 +
  1.6450 +  // Pop all selection events off the end of a history array. Stop at
  1.6451 +  // a change event.
  1.6452 +  function clearSelectionEvents(array) {
  1.6453 +    while (array.length) {
  1.6454 +      var last = lst(array);
  1.6455 +      if (last.ranges) array.pop();
  1.6456 +      else break;
  1.6457 +    }
  1.6458 +  }
  1.6459 +
  1.6460 +  // Find the top change event in the history. Pop off selection
  1.6461 +  // events that are in the way.
  1.6462 +  function lastChangeEvent(hist, force) {
  1.6463 +    if (force) {
  1.6464 +      clearSelectionEvents(hist.done);
  1.6465 +      return lst(hist.done);
  1.6466 +    } else if (hist.done.length && !lst(hist.done).ranges) {
  1.6467 +      return lst(hist.done);
  1.6468 +    } else if (hist.done.length > 1 && !hist.done[hist.done.length - 2].ranges) {
  1.6469 +      hist.done.pop();
  1.6470 +      return lst(hist.done);
  1.6471 +    }
  1.6472 +  }
  1.6473 +
  1.6474 +  // Register a change in the history. Merges changes that are within
  1.6475 +  // a single operation, ore are close together with an origin that
  1.6476 +  // allows merging (starting with "+") into a single event.
  1.6477 +  function addChangeToHistory(doc, change, selAfter, opId) {
  1.6478 +    var hist = doc.history;
  1.6479 +    hist.undone.length = 0;
  1.6480 +    var time = +new Date, cur;
  1.6481 +
  1.6482 +    if ((hist.lastOp == opId ||
  1.6483 +         hist.lastOrigin == change.origin && change.origin &&
  1.6484 +         ((change.origin.charAt(0) == "+" && doc.cm && hist.lastModTime > time - doc.cm.options.historyEventDelay) ||
  1.6485 +          change.origin.charAt(0) == "*")) &&
  1.6486 +        (cur = lastChangeEvent(hist, hist.lastOp == opId))) {
  1.6487 +      // Merge this change into the last event
  1.6488 +      var last = lst(cur.changes);
  1.6489 +      if (cmp(change.from, change.to) == 0 && cmp(change.from, last.to) == 0) {
  1.6490 +        // Optimized case for simple insertion -- don't want to add
  1.6491 +        // new changesets for every character typed
  1.6492 +        last.to = changeEnd(change);
  1.6493 +      } else {
  1.6494 +        // Add new sub-event
  1.6495 +        cur.changes.push(historyChangeFromChange(doc, change));
  1.6496 +      }
  1.6497 +    } else {
  1.6498 +      // Can not be merged, start a new event.
  1.6499 +      var before = lst(hist.done);
  1.6500 +      if (!before || !before.ranges)
  1.6501 +        pushSelectionToHistory(doc.sel, hist.done);
  1.6502 +      cur = {changes: [historyChangeFromChange(doc, change)],
  1.6503 +             generation: hist.generation};
  1.6504 +      hist.done.push(cur);
  1.6505 +      while (hist.done.length > hist.undoDepth) {
  1.6506 +        hist.done.shift();
  1.6507 +        if (!hist.done[0].ranges) hist.done.shift();
  1.6508 +      }
  1.6509 +    }
  1.6510 +    hist.done.push(selAfter);
  1.6511 +    hist.generation = ++hist.maxGeneration;
  1.6512 +    hist.lastModTime = hist.lastSelTime = time;
  1.6513 +    hist.lastOp = opId;
  1.6514 +    hist.lastOrigin = hist.lastSelOrigin = change.origin;
  1.6515 +
  1.6516 +    if (!last) signal(doc, "historyAdded");
  1.6517 +  }
  1.6518 +
  1.6519 +  function selectionEventCanBeMerged(doc, origin, prev, sel) {
  1.6520 +    var ch = origin.charAt(0);
  1.6521 +    return ch == "*" ||
  1.6522 +      ch == "+" &&
  1.6523 +      prev.ranges.length == sel.ranges.length &&
  1.6524 +      prev.somethingSelected() == sel.somethingSelected() &&
  1.6525 +      new Date - doc.history.lastSelTime <= (doc.cm ? doc.cm.options.historyEventDelay : 500);
  1.6526 +  }
  1.6527 +
  1.6528 +  // Called whenever the selection changes, sets the new selection as
  1.6529 +  // the pending selection in the history, and pushes the old pending
  1.6530 +  // selection into the 'done' array when it was significantly
  1.6531 +  // different (in number of selected ranges, emptiness, or time).
  1.6532 +  function addSelectionToHistory(doc, sel, opId, options) {
  1.6533 +    var hist = doc.history, origin = options && options.origin;
  1.6534 +
  1.6535 +    // A new event is started when the previous origin does not match
  1.6536 +    // the current, or the origins don't allow matching. Origins
  1.6537 +    // starting with * are always merged, those starting with + are
  1.6538 +    // merged when similar and close together in time.
  1.6539 +    if (opId == hist.lastOp ||
  1.6540 +        (origin && hist.lastSelOrigin == origin &&
  1.6541 +         (hist.lastModTime == hist.lastSelTime && hist.lastOrigin == origin ||
  1.6542 +          selectionEventCanBeMerged(doc, origin, lst(hist.done), sel))))
  1.6543 +      hist.done[hist.done.length - 1] = sel;
  1.6544 +    else
  1.6545 +      pushSelectionToHistory(sel, hist.done);
  1.6546 +
  1.6547 +    hist.lastSelTime = +new Date;
  1.6548 +    hist.lastSelOrigin = origin;
  1.6549 +    hist.lastOp = opId;
  1.6550 +    if (options && options.clearRedo !== false)
  1.6551 +      clearSelectionEvents(hist.undone);
  1.6552 +  }
  1.6553 +
  1.6554 +  function pushSelectionToHistory(sel, dest) {
  1.6555 +    var top = lst(dest);
  1.6556 +    if (!(top && top.ranges && top.equals(sel)))
  1.6557 +      dest.push(sel);
  1.6558 +  }
  1.6559 +
  1.6560 +  // Used to store marked span information in the history.
  1.6561 +  function attachLocalSpans(doc, change, from, to) {
  1.6562 +    var existing = change["spans_" + doc.id], n = 0;
  1.6563 +    doc.iter(Math.max(doc.first, from), Math.min(doc.first + doc.size, to), function(line) {
  1.6564 +      if (line.markedSpans)
  1.6565 +        (existing || (existing = change["spans_" + doc.id] = {}))[n] = line.markedSpans;
  1.6566 +      ++n;
  1.6567 +    });
  1.6568 +  }
  1.6569 +
  1.6570 +  // When un/re-doing restores text containing marked spans, those
  1.6571 +  // that have been explicitly cleared should not be restored.
  1.6572 +  function removeClearedSpans(spans) {
  1.6573 +    if (!spans) return null;
  1.6574 +    for (var i = 0, out; i < spans.length; ++i) {
  1.6575 +      if (spans[i].marker.explicitlyCleared) { if (!out) out = spans.slice(0, i); }
  1.6576 +      else if (out) out.push(spans[i]);
  1.6577 +    }
  1.6578 +    return !out ? spans : out.length ? out : null;
  1.6579 +  }
  1.6580 +
  1.6581 +  // Retrieve and filter the old marked spans stored in a change event.
  1.6582 +  function getOldSpans(doc, change) {
  1.6583 +    var found = change["spans_" + doc.id];
  1.6584 +    if (!found) return null;
  1.6585 +    for (var i = 0, nw = []; i < change.text.length; ++i)
  1.6586 +      nw.push(removeClearedSpans(found[i]));
  1.6587 +    return nw;
  1.6588 +  }
  1.6589 +
  1.6590 +  // Used both to provide a JSON-safe object in .getHistory, and, when
  1.6591 +  // detaching a document, to split the history in two
  1.6592 +  function copyHistoryArray(events, newGroup, instantiateSel) {
  1.6593 +    for (var i = 0, copy = []; i < events.length; ++i) {
  1.6594 +      var event = events[i];
  1.6595 +      if (event.ranges) {
  1.6596 +        copy.push(instantiateSel ? Selection.prototype.deepCopy.call(event) : event);
  1.6597 +        continue;
  1.6598 +      }
  1.6599 +      var changes = event.changes, newChanges = [];
  1.6600 +      copy.push({changes: newChanges});
  1.6601 +      for (var j = 0; j < changes.length; ++j) {
  1.6602 +        var change = changes[j], m;
  1.6603 +        newChanges.push({from: change.from, to: change.to, text: change.text});
  1.6604 +        if (newGroup) for (var prop in change) if (m = prop.match(/^spans_(\d+)$/)) {
  1.6605 +          if (indexOf(newGroup, Number(m[1])) > -1) {
  1.6606 +            lst(newChanges)[prop] = change[prop];
  1.6607 +            delete change[prop];
  1.6608 +          }
  1.6609 +        }
  1.6610 +      }
  1.6611 +    }
  1.6612 +    return copy;
  1.6613 +  }
  1.6614 +
  1.6615 +  // Rebasing/resetting history to deal with externally-sourced changes
  1.6616 +
  1.6617 +  function rebaseHistSelSingle(pos, from, to, diff) {
  1.6618 +    if (to < pos.line) {
  1.6619 +      pos.line += diff;
  1.6620 +    } else if (from < pos.line) {
  1.6621 +      pos.line = from;
  1.6622 +      pos.ch = 0;
  1.6623 +    }
  1.6624 +  }
  1.6625 +
  1.6626 +  // Tries to rebase an array of history events given a change in the
  1.6627 +  // document. If the change touches the same lines as the event, the
  1.6628 +  // event, and everything 'behind' it, is discarded. If the change is
  1.6629 +  // before the event, the event's positions are updated. Uses a
  1.6630 +  // copy-on-write scheme for the positions, to avoid having to
  1.6631 +  // reallocate them all on every rebase, but also avoid problems with
  1.6632 +  // shared position objects being unsafely updated.
  1.6633 +  function rebaseHistArray(array, from, to, diff) {
  1.6634 +    for (var i = 0; i < array.length; ++i) {
  1.6635 +      var sub = array[i], ok = true;
  1.6636 +      if (sub.ranges) {
  1.6637 +        if (!sub.copied) { sub = array[i] = sub.deepCopy(); sub.copied = true; }
  1.6638 +        for (var j = 0; j < sub.ranges.length; j++) {
  1.6639 +          rebaseHistSelSingle(sub.ranges[j].anchor, from, to, diff);
  1.6640 +          rebaseHistSelSingle(sub.ranges[j].head, from, to, diff);
  1.6641 +        }
  1.6642 +        continue;
  1.6643 +      }
  1.6644 +      for (var j = 0; j < sub.changes.length; ++j) {
  1.6645 +        var cur = sub.changes[j];
  1.6646 +        if (to < cur.from.line) {
  1.6647 +          cur.from = Pos(cur.from.line + diff, cur.from.ch);
  1.6648 +          cur.to = Pos(cur.to.line + diff, cur.to.ch);
  1.6649 +        } else if (from <= cur.to.line) {
  1.6650 +          ok = false;
  1.6651 +          break;
  1.6652 +        }
  1.6653 +      }
  1.6654 +      if (!ok) {
  1.6655 +        array.splice(0, i + 1);
  1.6656 +        i = 0;
  1.6657 +      }
  1.6658 +    }
  1.6659 +  }
  1.6660 +
  1.6661 +  function rebaseHist(hist, change) {
  1.6662 +    var from = change.from.line, to = change.to.line, diff = change.text.length - (to - from) - 1;
  1.6663 +    rebaseHistArray(hist.done, from, to, diff);
  1.6664 +    rebaseHistArray(hist.undone, from, to, diff);
  1.6665 +  }
  1.6666 +
  1.6667 +  // EVENT UTILITIES
  1.6668 +
  1.6669 +  // Due to the fact that we still support jurassic IE versions, some
  1.6670 +  // compatibility wrappers are needed.
  1.6671 +
  1.6672 +  var e_preventDefault = CodeMirror.e_preventDefault = function(e) {
  1.6673 +    if (e.preventDefault) e.preventDefault();
  1.6674 +    else e.returnValue = false;
  1.6675 +  };
  1.6676 +  var e_stopPropagation = CodeMirror.e_stopPropagation = function(e) {
  1.6677 +    if (e.stopPropagation) e.stopPropagation();
  1.6678 +    else e.cancelBubble = true;
  1.6679 +  };
  1.6680 +  function e_defaultPrevented(e) {
  1.6681 +    return e.defaultPrevented != null ? e.defaultPrevented : e.returnValue == false;
  1.6682 +  }
  1.6683 +  var e_stop = CodeMirror.e_stop = function(e) {e_preventDefault(e); e_stopPropagation(e);};
  1.6684 +
  1.6685 +  function e_target(e) {return e.target || e.srcElement;}
  1.6686 +  function e_button(e) {
  1.6687 +    var b = e.which;
  1.6688 +    if (b == null) {
  1.6689 +      if (e.button & 1) b = 1;
  1.6690 +      else if (e.button & 2) b = 3;
  1.6691 +      else if (e.button & 4) b = 2;
  1.6692 +    }
  1.6693 +    if (mac && e.ctrlKey && b == 1) b = 3;
  1.6694 +    return b;
  1.6695 +  }
  1.6696 +
  1.6697 +  // EVENT HANDLING
  1.6698 +
  1.6699 +  // Lightweight event framework. on/off also work on DOM nodes,
  1.6700 +  // registering native DOM handlers.
  1.6701 +
  1.6702 +  var on = CodeMirror.on = function(emitter, type, f) {
  1.6703 +    if (emitter.addEventListener)
  1.6704 +      emitter.addEventListener(type, f, false);
  1.6705 +    else if (emitter.attachEvent)
  1.6706 +      emitter.attachEvent("on" + type, f);
  1.6707 +    else {
  1.6708 +      var map = emitter._handlers || (emitter._handlers = {});
  1.6709 +      var arr = map[type] || (map[type] = []);
  1.6710 +      arr.push(f);
  1.6711 +    }
  1.6712 +  };
  1.6713 +
  1.6714 +  var off = CodeMirror.off = function(emitter, type, f) {
  1.6715 +    if (emitter.removeEventListener)
  1.6716 +      emitter.removeEventListener(type, f, false);
  1.6717 +    else if (emitter.detachEvent)
  1.6718 +      emitter.detachEvent("on" + type, f);
  1.6719 +    else {
  1.6720 +      var arr = emitter._handlers && emitter._handlers[type];
  1.6721 +      if (!arr) return;
  1.6722 +      for (var i = 0; i < arr.length; ++i)
  1.6723 +        if (arr[i] == f) { arr.splice(i, 1); break; }
  1.6724 +    }
  1.6725 +  };
  1.6726 +
  1.6727 +  var signal = CodeMirror.signal = function(emitter, type /*, values...*/) {
  1.6728 +    var arr = emitter._handlers && emitter._handlers[type];
  1.6729 +    if (!arr) return;
  1.6730 +    var args = Array.prototype.slice.call(arguments, 2);
  1.6731 +    for (var i = 0; i < arr.length; ++i) arr[i].apply(null, args);
  1.6732 +  };
  1.6733 +
  1.6734 +  // Often, we want to signal events at a point where we are in the
  1.6735 +  // middle of some work, but don't want the handler to start calling
  1.6736 +  // other methods on the editor, which might be in an inconsistent
  1.6737 +  // state or simply not expect any other events to happen.
  1.6738 +  // signalLater looks whether there are any handlers, and schedules
  1.6739 +  // them to be executed when the last operation ends, or, if no
  1.6740 +  // operation is active, when a timeout fires.
  1.6741 +  var delayedCallbacks, delayedCallbackDepth = 0;
  1.6742 +  function signalLater(emitter, type /*, values...*/) {
  1.6743 +    var arr = emitter._handlers && emitter._handlers[type];
  1.6744 +    if (!arr) return;
  1.6745 +    var args = Array.prototype.slice.call(arguments, 2);
  1.6746 +    if (!delayedCallbacks) {
  1.6747 +      ++delayedCallbackDepth;
  1.6748 +      delayedCallbacks = [];
  1.6749 +      setTimeout(fireDelayed, 0);
  1.6750 +    }
  1.6751 +    function bnd(f) {return function(){f.apply(null, args);};};
  1.6752 +    for (var i = 0; i < arr.length; ++i)
  1.6753 +      delayedCallbacks.push(bnd(arr[i]));
  1.6754 +  }
  1.6755 +
  1.6756 +  function fireDelayed() {
  1.6757 +    --delayedCallbackDepth;
  1.6758 +    var delayed = delayedCallbacks;
  1.6759 +    delayedCallbacks = null;
  1.6760 +    for (var i = 0; i < delayed.length; ++i) delayed[i]();
  1.6761 +  }
  1.6762 +
  1.6763 +  // The DOM events that CodeMirror handles can be overridden by
  1.6764 +  // registering a (non-DOM) handler on the editor for the event name,
  1.6765 +  // and preventDefault-ing the event in that handler.
  1.6766 +  function signalDOMEvent(cm, e, override) {
  1.6767 +    signal(cm, override || e.type, cm, e);
  1.6768 +    return e_defaultPrevented(e) || e.codemirrorIgnore;
  1.6769 +  }
  1.6770 +
  1.6771 +  function hasHandler(emitter, type) {
  1.6772 +    var arr = emitter._handlers && emitter._handlers[type];
  1.6773 +    return arr && arr.length > 0;
  1.6774 +  }
  1.6775 +
  1.6776 +  // Add on and off methods to a constructor's prototype, to make
  1.6777 +  // registering events on such objects more convenient.
  1.6778 +  function eventMixin(ctor) {
  1.6779 +    ctor.prototype.on = function(type, f) {on(this, type, f);};
  1.6780 +    ctor.prototype.off = function(type, f) {off(this, type, f);};
  1.6781 +  }
  1.6782 +
  1.6783 +  // MISC UTILITIES
  1.6784 +
  1.6785 +  // Number of pixels added to scroller and sizer to hide scrollbar
  1.6786 +  var scrollerCutOff = 30;
  1.6787 +
  1.6788 +  // Returned or thrown by various protocols to signal 'I'm not
  1.6789 +  // handling this'.
  1.6790 +  var Pass = CodeMirror.Pass = {toString: function(){return "CodeMirror.Pass";}};
  1.6791 +
  1.6792 +  // Reused option objects for setSelection & friends
  1.6793 +  var sel_dontScroll = {scroll: false}, sel_mouse = {origin: "*mouse"}, sel_move = {origin: "+move"};
  1.6794 +
  1.6795 +  function Delayed() {this.id = null;}
  1.6796 +  Delayed.prototype.set = function(ms, f) {
  1.6797 +    clearTimeout(this.id);
  1.6798 +    this.id = setTimeout(f, ms);
  1.6799 +  };
  1.6800 +
  1.6801 +  // Counts the column offset in a string, taking tabs into account.
  1.6802 +  // Used mostly to find indentation.
  1.6803 +  var countColumn = CodeMirror.countColumn = function(string, end, tabSize, startIndex, startValue) {
  1.6804 +    if (end == null) {
  1.6805 +      end = string.search(/[^\s\u00a0]/);
  1.6806 +      if (end == -1) end = string.length;
  1.6807 +    }
  1.6808 +    for (var i = startIndex || 0, n = startValue || 0;;) {
  1.6809 +      var nextTab = string.indexOf("\t", i);
  1.6810 +      if (nextTab < 0 || nextTab >= end)
  1.6811 +        return n + (end - i);
  1.6812 +      n += nextTab - i;
  1.6813 +      n += tabSize - (n % tabSize);
  1.6814 +      i = nextTab + 1;
  1.6815 +    }
  1.6816 +  };
  1.6817 +
  1.6818 +  // The inverse of countColumn -- find the offset that corresponds to
  1.6819 +  // a particular column.
  1.6820 +  function findColumn(string, goal, tabSize) {
  1.6821 +    for (var pos = 0, col = 0;;) {
  1.6822 +      var nextTab = string.indexOf("\t", pos);
  1.6823 +      if (nextTab == -1) nextTab = string.length;
  1.6824 +      var skipped = nextTab - pos;
  1.6825 +      if (nextTab == string.length || col + skipped >= goal)
  1.6826 +        return pos + Math.min(skipped, goal - col);
  1.6827 +      col += nextTab - pos;
  1.6828 +      col += tabSize - (col % tabSize);
  1.6829 +      pos = nextTab + 1;
  1.6830 +      if (col >= goal) return pos;
  1.6831 +    }
  1.6832 +  }
  1.6833 +
  1.6834 +  var spaceStrs = [""];
  1.6835 +  function spaceStr(n) {
  1.6836 +    while (spaceStrs.length <= n)
  1.6837 +      spaceStrs.push(lst(spaceStrs) + " ");
  1.6838 +    return spaceStrs[n];
  1.6839 +  }
  1.6840 +
  1.6841 +  function lst(arr) { return arr[arr.length-1]; }
  1.6842 +
  1.6843 +  var selectInput = function(node) { node.select(); };
  1.6844 +  if (ios) // Mobile Safari apparently has a bug where select() is broken.
  1.6845 +    selectInput = function(node) { node.selectionStart = 0; node.selectionEnd = node.value.length; };
  1.6846 +  else if (ie) // Suppress mysterious IE10 errors
  1.6847 +    selectInput = function(node) { try { node.select(); } catch(_e) {} };
  1.6848 +
  1.6849 +  function indexOf(array, elt) {
  1.6850 +    for (var i = 0; i < array.length; ++i)
  1.6851 +      if (array[i] == elt) return i;
  1.6852 +    return -1;
  1.6853 +  }
  1.6854 +  if ([].indexOf) indexOf = function(array, elt) { return array.indexOf(elt); };
  1.6855 +  function map(array, f) {
  1.6856 +    var out = [];
  1.6857 +    for (var i = 0; i < array.length; i++) out[i] = f(array[i], i);
  1.6858 +    return out;
  1.6859 +  }
  1.6860 +  if ([].map) map = function(array, f) { return array.map(f); };
  1.6861 +
  1.6862 +  function createObj(base, props) {
  1.6863 +    var inst;
  1.6864 +    if (Object.create) {
  1.6865 +      inst = Object.create(base);
  1.6866 +    } else {
  1.6867 +      var ctor = function() {};
  1.6868 +      ctor.prototype = base;
  1.6869 +      inst = new ctor();
  1.6870 +    }
  1.6871 +    if (props) copyObj(props, inst);
  1.6872 +    return inst;
  1.6873 +  };
  1.6874 +
  1.6875 +  function copyObj(obj, target) {
  1.6876 +    if (!target) target = {};
  1.6877 +    for (var prop in obj) if (obj.hasOwnProperty(prop)) target[prop] = obj[prop];
  1.6878 +    return target;
  1.6879 +  }
  1.6880 +
  1.6881 +  function bind(f) {
  1.6882 +    var args = Array.prototype.slice.call(arguments, 1);
  1.6883 +    return function(){return f.apply(null, args);};
  1.6884 +  }
  1.6885 +
  1.6886 +  var nonASCIISingleCaseWordChar = /[\u00df\u3040-\u309f\u30a0-\u30ff\u3400-\u4db5\u4e00-\u9fcc\uac00-\ud7af]/;
  1.6887 +  var isWordChar = CodeMirror.isWordChar = function(ch) {
  1.6888 +    return /\w/.test(ch) || ch > "\x80" &&
  1.6889 +      (ch.toUpperCase() != ch.toLowerCase() || nonASCIISingleCaseWordChar.test(ch));
  1.6890 +  };
  1.6891 +
  1.6892 +  function isEmpty(obj) {
  1.6893 +    for (var n in obj) if (obj.hasOwnProperty(n) && obj[n]) return false;
  1.6894 +    return true;
  1.6895 +  }
  1.6896 +
  1.6897 +  // Extending unicode characters. A series of a non-extending char +
  1.6898 +  // any number of extending chars is treated as a single unit as far
  1.6899 +  // as editing and measuring is concerned. This is not fully correct,
  1.6900 +  // since some scripts/fonts/browsers also treat other configurations
  1.6901 +  // of code points as a group.
  1.6902 +  var extendingChars = /[\u0300-\u036f\u0483-\u0489\u0591-\u05bd\u05bf\u05c1\u05c2\u05c4\u05c5\u05c7\u0610-\u061a\u064b-\u065e\u0670\u06d6-\u06dc\u06de-\u06e4\u06e7\u06e8\u06ea-\u06ed\u0711\u0730-\u074a\u07a6-\u07b0\u07eb-\u07f3\u0816-\u0819\u081b-\u0823\u0825-\u0827\u0829-\u082d\u0900-\u0902\u093c\u0941-\u0948\u094d\u0951-\u0955\u0962\u0963\u0981\u09bc\u09be\u09c1-\u09c4\u09cd\u09d7\u09e2\u09e3\u0a01\u0a02\u0a3c\u0a41\u0a42\u0a47\u0a48\u0a4b-\u0a4d\u0a51\u0a70\u0a71\u0a75\u0a81\u0a82\u0abc\u0ac1-\u0ac5\u0ac7\u0ac8\u0acd\u0ae2\u0ae3\u0b01\u0b3c\u0b3e\u0b3f\u0b41-\u0b44\u0b4d\u0b56\u0b57\u0b62\u0b63\u0b82\u0bbe\u0bc0\u0bcd\u0bd7\u0c3e-\u0c40\u0c46-\u0c48\u0c4a-\u0c4d\u0c55\u0c56\u0c62\u0c63\u0cbc\u0cbf\u0cc2\u0cc6\u0ccc\u0ccd\u0cd5\u0cd6\u0ce2\u0ce3\u0d3e\u0d41-\u0d44\u0d4d\u0d57\u0d62\u0d63\u0dca\u0dcf\u0dd2-\u0dd4\u0dd6\u0ddf\u0e31\u0e34-\u0e3a\u0e47-\u0e4e\u0eb1\u0eb4-\u0eb9\u0ebb\u0ebc\u0ec8-\u0ecd\u0f18\u0f19\u0f35\u0f37\u0f39\u0f71-\u0f7e\u0f80-\u0f84\u0f86\u0f87\u0f90-\u0f97\u0f99-\u0fbc\u0fc6\u102d-\u1030\u1032-\u1037\u1039\u103a\u103d\u103e\u1058\u1059\u105e-\u1060\u1071-\u1074\u1082\u1085\u1086\u108d\u109d\u135f\u1712-\u1714\u1732-\u1734\u1752\u1753\u1772\u1773\u17b7-\u17bd\u17c6\u17c9-\u17d3\u17dd\u180b-\u180d\u18a9\u1920-\u1922\u1927\u1928\u1932\u1939-\u193b\u1a17\u1a18\u1a56\u1a58-\u1a5e\u1a60\u1a62\u1a65-\u1a6c\u1a73-\u1a7c\u1a7f\u1b00-\u1b03\u1b34\u1b36-\u1b3a\u1b3c\u1b42\u1b6b-\u1b73\u1b80\u1b81\u1ba2-\u1ba5\u1ba8\u1ba9\u1c2c-\u1c33\u1c36\u1c37\u1cd0-\u1cd2\u1cd4-\u1ce0\u1ce2-\u1ce8\u1ced\u1dc0-\u1de6\u1dfd-\u1dff\u200c\u200d\u20d0-\u20f0\u2cef-\u2cf1\u2de0-\u2dff\u302a-\u302f\u3099\u309a\ua66f-\ua672\ua67c\ua67d\ua6f0\ua6f1\ua802\ua806\ua80b\ua825\ua826\ua8c4\ua8e0-\ua8f1\ua926-\ua92d\ua947-\ua951\ua980-\ua982\ua9b3\ua9b6-\ua9b9\ua9bc\uaa29-\uaa2e\uaa31\uaa32\uaa35\uaa36\uaa43\uaa4c\uaab0\uaab2-\uaab4\uaab7\uaab8\uaabe\uaabf\uaac1\uabe5\uabe8\uabed\udc00-\udfff\ufb1e\ufe00-\ufe0f\ufe20-\ufe26\uff9e\uff9f]/;
  1.6903 +  function isExtendingChar(ch) { return ch.charCodeAt(0) >= 768 && extendingChars.test(ch); }
  1.6904 +
  1.6905 +  // DOM UTILITIES
  1.6906 +
  1.6907 +  function elt(tag, content, className, style) {
  1.6908 +    var e = document.createElement(tag);
  1.6909 +    if (className) e.className = className;
  1.6910 +    if (style) e.style.cssText = style;
  1.6911 +    if (typeof content == "string") e.appendChild(document.createTextNode(content));
  1.6912 +    else if (content) for (var i = 0; i < content.length; ++i) e.appendChild(content[i]);
  1.6913 +    return e;
  1.6914 +  }
  1.6915 +
  1.6916 +  var range;
  1.6917 +  if (document.createRange) range = function(node, start, end) {
  1.6918 +    var r = document.createRange();
  1.6919 +    r.setEnd(node, end);
  1.6920 +    r.setStart(node, start);
  1.6921 +    return r;
  1.6922 +  };
  1.6923 +  else range = function(node, start, end) {
  1.6924 +    var r = document.body.createTextRange();
  1.6925 +    r.moveToElementText(node.parentNode);
  1.6926 +    r.collapse(true);
  1.6927 +    r.moveEnd("character", end);
  1.6928 +    r.moveStart("character", start);
  1.6929 +    return r;
  1.6930 +  };
  1.6931 +
  1.6932 +  function removeChildren(e) {
  1.6933 +    for (var count = e.childNodes.length; count > 0; --count)
  1.6934 +      e.removeChild(e.firstChild);
  1.6935 +    return e;
  1.6936 +  }
  1.6937 +
  1.6938 +  function removeChildrenAndAdd(parent, e) {
  1.6939 +    return removeChildren(parent).appendChild(e);
  1.6940 +  }
  1.6941 +
  1.6942 +  function contains(parent, child) {
  1.6943 +    if (parent.contains)
  1.6944 +      return parent.contains(child);
  1.6945 +    while (child = child.parentNode)
  1.6946 +      if (child == parent) return true;
  1.6947 +  }
  1.6948 +
  1.6949 +  function activeElt() { return document.activeElement; }
  1.6950 +  // Older versions of IE throws unspecified error when touching
  1.6951 +  // document.activeElement in some cases (during loading, in iframe)
  1.6952 +  if (ie_upto10) activeElt = function() {
  1.6953 +    try { return document.activeElement; }
  1.6954 +    catch(e) { return document.body; }
  1.6955 +  };
  1.6956 +
  1.6957 +  // FEATURE DETECTION
  1.6958 +
  1.6959 +  // Detect drag-and-drop
  1.6960 +  var dragAndDrop = function() {
  1.6961 +    // There is *some* kind of drag-and-drop support in IE6-8, but I
  1.6962 +    // couldn't get it to work yet.
  1.6963 +    if (ie_upto8) return false;
  1.6964 +    var div = elt('div');
  1.6965 +    return "draggable" in div || "dragDrop" in div;
  1.6966 +  }();
  1.6967 +
  1.6968 +  var knownScrollbarWidth;
  1.6969 +  function scrollbarWidth(measure) {
  1.6970 +    if (knownScrollbarWidth != null) return knownScrollbarWidth;
  1.6971 +    var test = elt("div", null, null, "width: 50px; height: 50px; overflow-x: scroll");
  1.6972 +    removeChildrenAndAdd(measure, test);
  1.6973 +    if (test.offsetWidth)
  1.6974 +      knownScrollbarWidth = test.offsetHeight - test.clientHeight;
  1.6975 +    return knownScrollbarWidth || 0;
  1.6976 +  }
  1.6977 +
  1.6978 +  var zwspSupported;
  1.6979 +  function zeroWidthElement(measure) {
  1.6980 +    if (zwspSupported == null) {
  1.6981 +      var test = elt("span", "\u200b");
  1.6982 +      removeChildrenAndAdd(measure, elt("span", [test, document.createTextNode("x")]));
  1.6983 +      if (measure.firstChild.offsetHeight != 0)
  1.6984 +        zwspSupported = test.offsetWidth <= 1 && test.offsetHeight > 2 && !ie_upto7;
  1.6985 +    }
  1.6986 +    if (zwspSupported) return elt("span", "\u200b");
  1.6987 +    else return elt("span", "\u00a0", null, "display: inline-block; width: 1px; margin-right: -1px");
  1.6988 +  }
  1.6989 +
  1.6990 +  // Feature-detect IE's crummy client rect reporting for bidi text
  1.6991 +  var badBidiRects;
  1.6992 +  function hasBadBidiRects(measure) {
  1.6993 +    if (badBidiRects != null) return badBidiRects;
  1.6994 +    var txt = removeChildrenAndAdd(measure, document.createTextNode("A\u062eA"));
  1.6995 +    var r0 = range(txt, 0, 1).getBoundingClientRect();
  1.6996 +    if (r0.left == r0.right) return false;
  1.6997 +    var r1 = range(txt, 1, 2).getBoundingClientRect();
  1.6998 +    return badBidiRects = (r1.right - r0.right < 3);
  1.6999 +  }
  1.7000 +
  1.7001 +  // See if "".split is the broken IE version, if so, provide an
  1.7002 +  // alternative way to split lines.
  1.7003 +  var splitLines = CodeMirror.splitLines = "\n\nb".split(/\n/).length != 3 ? function(string) {
  1.7004 +    var pos = 0, result = [], l = string.length;
  1.7005 +    while (pos <= l) {
  1.7006 +      var nl = string.indexOf("\n", pos);
  1.7007 +      if (nl == -1) nl = string.length;
  1.7008 +      var line = string.slice(pos, string.charAt(nl - 1) == "\r" ? nl - 1 : nl);
  1.7009 +      var rt = line.indexOf("\r");
  1.7010 +      if (rt != -1) {
  1.7011 +        result.push(line.slice(0, rt));
  1.7012 +        pos += rt + 1;
  1.7013 +      } else {
  1.7014 +        result.push(line);
  1.7015 +        pos = nl + 1;
  1.7016 +      }
  1.7017 +    }
  1.7018 +    return result;
  1.7019 +  } : function(string){return string.split(/\r\n?|\n/);};
  1.7020 +
  1.7021 +  var hasSelection = window.getSelection ? function(te) {
  1.7022 +    try { return te.selectionStart != te.selectionEnd; }
  1.7023 +    catch(e) { return false; }
  1.7024 +  } : function(te) {
  1.7025 +    try {var range = te.ownerDocument.selection.createRange();}
  1.7026 +    catch(e) {}
  1.7027 +    if (!range || range.parentElement() != te) return false;
  1.7028 +    return range.compareEndPoints("StartToEnd", range) != 0;
  1.7029 +  };
  1.7030 +
  1.7031 +  var hasCopyEvent = (function() {
  1.7032 +    var e = elt("div");
  1.7033 +    if ("oncopy" in e) return true;
  1.7034 +    e.setAttribute("oncopy", "return;");
  1.7035 +    return typeof e.oncopy == "function";
  1.7036 +  })();
  1.7037 +
  1.7038 +  // KEY NAMES
  1.7039 +
  1.7040 +  var keyNames = {3: "Enter", 8: "Backspace", 9: "Tab", 13: "Enter", 16: "Shift", 17: "Ctrl", 18: "Alt",
  1.7041 +                  19: "Pause", 20: "CapsLock", 27: "Esc", 32: "Space", 33: "PageUp", 34: "PageDown", 35: "End",
  1.7042 +                  36: "Home", 37: "Left", 38: "Up", 39: "Right", 40: "Down", 44: "PrintScrn", 45: "Insert",
  1.7043 +                  46: "Delete", 59: ";", 61: "=", 91: "Mod", 92: "Mod", 93: "Mod", 107: "=", 109: "-", 127: "Delete",
  1.7044 +                  173: "-", 186: ";", 187: "=", 188: ",", 189: "-", 190: ".", 191: "/", 192: "`", 219: "[", 220: "\\",
  1.7045 +                  221: "]", 222: "'", 63232: "Up", 63233: "Down", 63234: "Left", 63235: "Right", 63272: "Delete",
  1.7046 +                  63273: "Home", 63275: "End", 63276: "PageUp", 63277: "PageDown", 63302: "Insert"};
  1.7047 +  CodeMirror.keyNames = keyNames;
  1.7048 +  (function() {
  1.7049 +    // Number keys
  1.7050 +    for (var i = 0; i < 10; i++) keyNames[i + 48] = keyNames[i + 96] = String(i);
  1.7051 +    // Alphabetic keys
  1.7052 +    for (var i = 65; i <= 90; i++) keyNames[i] = String.fromCharCode(i);
  1.7053 +    // Function keys
  1.7054 +    for (var i = 1; i <= 12; i++) keyNames[i + 111] = keyNames[i + 63235] = "F" + i;
  1.7055 +  })();
  1.7056 +
  1.7057 +  // BIDI HELPERS
  1.7058 +
  1.7059 +  function iterateBidiSections(order, from, to, f) {
  1.7060 +    if (!order) return f(from, to, "ltr");
  1.7061 +    var found = false;
  1.7062 +    for (var i = 0; i < order.length; ++i) {
  1.7063 +      var part = order[i];
  1.7064 +      if (part.from < to && part.to > from || from == to && part.to == from) {
  1.7065 +        f(Math.max(part.from, from), Math.min(part.to, to), part.level == 1 ? "rtl" : "ltr");
  1.7066 +        found = true;
  1.7067 +      }
  1.7068 +    }
  1.7069 +    if (!found) f(from, to, "ltr");
  1.7070 +  }
  1.7071 +
  1.7072 +  function bidiLeft(part) { return part.level % 2 ? part.to : part.from; }
  1.7073 +  function bidiRight(part) { return part.level % 2 ? part.from : part.to; }
  1.7074 +
  1.7075 +  function lineLeft(line) { var order = getOrder(line); return order ? bidiLeft(order[0]) : 0; }
  1.7076 +  function lineRight(line) {
  1.7077 +    var order = getOrder(line);
  1.7078 +    if (!order) return line.text.length;
  1.7079 +    return bidiRight(lst(order));
  1.7080 +  }
  1.7081 +
  1.7082 +  function lineStart(cm, lineN) {
  1.7083 +    var line = getLine(cm.doc, lineN);
  1.7084 +    var visual = visualLine(line);
  1.7085 +    if (visual != line) lineN = lineNo(visual);
  1.7086 +    var order = getOrder(visual);
  1.7087 +    var ch = !order ? 0 : order[0].level % 2 ? lineRight(visual) : lineLeft(visual);
  1.7088 +    return Pos(lineN, ch);
  1.7089 +  }
  1.7090 +  function lineEnd(cm, lineN) {
  1.7091 +    var merged, line = getLine(cm.doc, lineN);
  1.7092 +    while (merged = collapsedSpanAtEnd(line)) {
  1.7093 +      line = merged.find(1, true).line;
  1.7094 +      lineN = null;
  1.7095 +    }
  1.7096 +    var order = getOrder(line);
  1.7097 +    var ch = !order ? line.text.length : order[0].level % 2 ? lineLeft(line) : lineRight(line);
  1.7098 +    return Pos(lineN == null ? lineNo(line) : lineN, ch);
  1.7099 +  }
  1.7100 +
  1.7101 +  function compareBidiLevel(order, a, b) {
  1.7102 +    var linedir = order[0].level;
  1.7103 +    if (a == linedir) return true;
  1.7104 +    if (b == linedir) return false;
  1.7105 +    return a < b;
  1.7106 +  }
  1.7107 +  var bidiOther;
  1.7108 +  function getBidiPartAt(order, pos) {
  1.7109 +    bidiOther = null;
  1.7110 +    for (var i = 0, found; i < order.length; ++i) {
  1.7111 +      var cur = order[i];
  1.7112 +      if (cur.from < pos && cur.to > pos) return i;
  1.7113 +      if ((cur.from == pos || cur.to == pos)) {
  1.7114 +        if (found == null) {
  1.7115 +          found = i;
  1.7116 +        } else if (compareBidiLevel(order, cur.level, order[found].level)) {
  1.7117 +          if (cur.from != cur.to) bidiOther = found;
  1.7118 +          return i;
  1.7119 +        } else {
  1.7120 +          if (cur.from != cur.to) bidiOther = i;
  1.7121 +          return found;
  1.7122 +        }
  1.7123 +      }
  1.7124 +    }
  1.7125 +    return found;
  1.7126 +  }
  1.7127 +
  1.7128 +  function moveInLine(line, pos, dir, byUnit) {
  1.7129 +    if (!byUnit) return pos + dir;
  1.7130 +    do pos += dir;
  1.7131 +    while (pos > 0 && isExtendingChar(line.text.charAt(pos)));
  1.7132 +    return pos;
  1.7133 +  }
  1.7134 +
  1.7135 +  // This is needed in order to move 'visually' through bi-directional
  1.7136 +  // text -- i.e., pressing left should make the cursor go left, even
  1.7137 +  // when in RTL text. The tricky part is the 'jumps', where RTL and
  1.7138 +  // LTR text touch each other. This often requires the cursor offset
  1.7139 +  // to move more than one unit, in order to visually move one unit.
  1.7140 +  function moveVisually(line, start, dir, byUnit) {
  1.7141 +    var bidi = getOrder(line);
  1.7142 +    if (!bidi) return moveLogically(line, start, dir, byUnit);
  1.7143 +    var pos = getBidiPartAt(bidi, start), part = bidi[pos];
  1.7144 +    var target = moveInLine(line, start, part.level % 2 ? -dir : dir, byUnit);
  1.7145 +
  1.7146 +    for (;;) {
  1.7147 +      if (target > part.from && target < part.to) return target;
  1.7148 +      if (target == part.from || target == part.to) {
  1.7149 +        if (getBidiPartAt(bidi, target) == pos) return target;
  1.7150 +        part = bidi[pos += dir];
  1.7151 +        return (dir > 0) == part.level % 2 ? part.to : part.from;
  1.7152 +      } else {
  1.7153 +        part = bidi[pos += dir];
  1.7154 +        if (!part) return null;
  1.7155 +        if ((dir > 0) == part.level % 2)
  1.7156 +          target = moveInLine(line, part.to, -1, byUnit);
  1.7157 +        else
  1.7158 +          target = moveInLine(line, part.from, 1, byUnit);
  1.7159 +      }
  1.7160 +    }
  1.7161 +  }
  1.7162 +
  1.7163 +  function moveLogically(line, start, dir, byUnit) {
  1.7164 +    var target = start + dir;
  1.7165 +    if (byUnit) while (target > 0 && isExtendingChar(line.text.charAt(target))) target += dir;
  1.7166 +    return target < 0 || target > line.text.length ? null : target;
  1.7167 +  }
  1.7168 +
  1.7169 +  // Bidirectional ordering algorithm
  1.7170 +  // See http://unicode.org/reports/tr9/tr9-13.html for the algorithm
  1.7171 +  // that this (partially) implements.
  1.7172 +
  1.7173 +  // One-char codes used for character types:
  1.7174 +  // L (L):   Left-to-Right
  1.7175 +  // R (R):   Right-to-Left
  1.7176 +  // r (AL):  Right-to-Left Arabic
  1.7177 +  // 1 (EN):  European Number
  1.7178 +  // + (ES):  European Number Separator
  1.7179 +  // % (ET):  European Number Terminator
  1.7180 +  // n (AN):  Arabic Number
  1.7181 +  // , (CS):  Common Number Separator
  1.7182 +  // m (NSM): Non-Spacing Mark
  1.7183 +  // b (BN):  Boundary Neutral
  1.7184 +  // s (B):   Paragraph Separator
  1.7185 +  // t (S):   Segment Separator
  1.7186 +  // w (WS):  Whitespace
  1.7187 +  // N (ON):  Other Neutrals
  1.7188 +
  1.7189 +  // Returns null if characters are ordered as they appear
  1.7190 +  // (left-to-right), or an array of sections ({from, to, level}
  1.7191 +  // objects) in the order in which they occur visually.
  1.7192 +  var bidiOrdering = (function() {
  1.7193 +    // Character types for codepoints 0 to 0xff
  1.7194 +    var lowTypes = "bbbbbbbbbtstwsbbbbbbbbbbbbbbssstwNN%%%NNNNNN,N,N1111111111NNNNNNNLLLLLLLLLLLLLLLLLLLLLLLLLLNNNNNNLLLLLLLLLLLLLLLLLLLLLLLLLLNNNNbbbbbbsbbbbbbbbbbbbbbbbbbbbbbbbbb,N%%%%NNNNLNNNNN%%11NLNNN1LNNNNNLLLLLLLLLLLLLLLLLLLLLLLNLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLN";
  1.7195 +    // Character types for codepoints 0x600 to 0x6ff
  1.7196 +    var arabicTypes = "rrrrrrrrrrrr,rNNmmmmmmrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrmmmmmmmmmmmmmmrrrrrrrnnnnnnnnnn%nnrrrmrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrmmmmmmmmmmmmmmmmmmmNmmmm";
  1.7197 +    function charType(code) {
  1.7198 +      if (code <= 0xf7) return lowTypes.charAt(code);
  1.7199 +      else if (0x590 <= code && code <= 0x5f4) return "R";
  1.7200 +      else if (0x600 <= code && code <= 0x6ed) return arabicTypes.charAt(code - 0x600);
  1.7201 +      else if (0x6ee <= code && code <= 0x8ac) return "r";
  1.7202 +      else if (0x2000 <= code && code <= 0x200b) return "w";
  1.7203 +      else if (code == 0x200c) return "b";
  1.7204 +      else return "L";
  1.7205 +    }
  1.7206 +
  1.7207 +    var bidiRE = /[\u0590-\u05f4\u0600-\u06ff\u0700-\u08ac]/;
  1.7208 +    var isNeutral = /[stwN]/, isStrong = /[LRr]/, countsAsLeft = /[Lb1n]/, countsAsNum = /[1n]/;
  1.7209 +    // Browsers seem to always treat the boundaries of block elements as being L.
  1.7210 +    var outerType = "L";
  1.7211 +
  1.7212 +    function BidiSpan(level, from, to) {
  1.7213 +      this.level = level;
  1.7214 +      this.from = from; this.to = to;
  1.7215 +    }
  1.7216 +
  1.7217 +    return function(str) {
  1.7218 +      if (!bidiRE.test(str)) return false;
  1.7219 +      var len = str.length, types = [];
  1.7220 +      for (var i = 0, type; i < len; ++i)
  1.7221 +        types.push(type = charType(str.charCodeAt(i)));
  1.7222 +
  1.7223 +      // W1. Examine each non-spacing mark (NSM) in the level run, and
  1.7224 +      // change the type of the NSM to the type of the previous
  1.7225 +      // character. If the NSM is at the start of the level run, it will
  1.7226 +      // get the type of sor.
  1.7227 +      for (var i = 0, prev = outerType; i < len; ++i) {
  1.7228 +        var type = types[i];
  1.7229 +        if (type == "m") types[i] = prev;
  1.7230 +        else prev = type;
  1.7231 +      }
  1.7232 +
  1.7233 +      // W2. Search backwards from each instance of a European number
  1.7234 +      // until the first strong type (R, L, AL, or sor) is found. If an
  1.7235 +      // AL is found, change the type of the European number to Arabic
  1.7236 +      // number.
  1.7237 +      // W3. Change all ALs to R.
  1.7238 +      for (var i = 0, cur = outerType; i < len; ++i) {
  1.7239 +        var type = types[i];
  1.7240 +        if (type == "1" && cur == "r") types[i] = "n";
  1.7241 +        else if (isStrong.test(type)) { cur = type; if (type == "r") types[i] = "R"; }
  1.7242 +      }
  1.7243 +
  1.7244 +      // W4. A single European separator between two European numbers
  1.7245 +      // changes to a European number. A single common separator between
  1.7246 +      // two numbers of the same type changes to that type.
  1.7247 +      for (var i = 1, prev = types[0]; i < len - 1; ++i) {
  1.7248 +        var type = types[i];
  1.7249 +        if (type == "+" && prev == "1" && types[i+1] == "1") types[i] = "1";
  1.7250 +        else if (type == "," && prev == types[i+1] &&
  1.7251 +                 (prev == "1" || prev == "n")) types[i] = prev;
  1.7252 +        prev = type;
  1.7253 +      }
  1.7254 +
  1.7255 +      // W5. A sequence of European terminators adjacent to European
  1.7256 +      // numbers changes to all European numbers.
  1.7257 +      // W6. Otherwise, separators and terminators change to Other
  1.7258 +      // Neutral.
  1.7259 +      for (var i = 0; i < len; ++i) {
  1.7260 +        var type = types[i];
  1.7261 +        if (type == ",") types[i] = "N";
  1.7262 +        else if (type == "%") {
  1.7263 +          for (var end = i + 1; end < len && types[end] == "%"; ++end) {}
  1.7264 +          var replace = (i && types[i-1] == "!") || (end < len && types[end] == "1") ? "1" : "N";
  1.7265 +          for (var j = i; j < end; ++j) types[j] = replace;
  1.7266 +          i = end - 1;
  1.7267 +        }
  1.7268 +      }
  1.7269 +
  1.7270 +      // W7. Search backwards from each instance of a European number
  1.7271 +      // until the first strong type (R, L, or sor) is found. If an L is
  1.7272 +      // found, then change the type of the European number to L.
  1.7273 +      for (var i = 0, cur = outerType; i < len; ++i) {
  1.7274 +        var type = types[i];
  1.7275 +        if (cur == "L" && type == "1") types[i] = "L";
  1.7276 +        else if (isStrong.test(type)) cur = type;
  1.7277 +      }
  1.7278 +
  1.7279 +      // N1. A sequence of neutrals takes the direction of the
  1.7280 +      // surrounding strong text if the text on both sides has the same
  1.7281 +      // direction. European and Arabic numbers act as if they were R in
  1.7282 +      // terms of their influence on neutrals. Start-of-level-run (sor)
  1.7283 +      // and end-of-level-run (eor) are used at level run boundaries.
  1.7284 +      // N2. Any remaining neutrals take the embedding direction.
  1.7285 +      for (var i = 0; i < len; ++i) {
  1.7286 +        if (isNeutral.test(types[i])) {
  1.7287 +          for (var end = i + 1; end < len && isNeutral.test(types[end]); ++end) {}
  1.7288 +          var before = (i ? types[i-1] : outerType) == "L";
  1.7289 +          var after = (end < len ? types[end] : outerType) == "L";
  1.7290 +          var replace = before || after ? "L" : "R";
  1.7291 +          for (var j = i; j < end; ++j) types[j] = replace;
  1.7292 +          i = end - 1;
  1.7293 +        }
  1.7294 +      }
  1.7295 +
  1.7296 +      // Here we depart from the documented algorithm, in order to avoid
  1.7297 +      // building up an actual levels array. Since there are only three
  1.7298 +      // levels (0, 1, 2) in an implementation that doesn't take
  1.7299 +      // explicit embedding into account, we can build up the order on
  1.7300 +      // the fly, without following the level-based algorithm.
  1.7301 +      var order = [], m;
  1.7302 +      for (var i = 0; i < len;) {
  1.7303 +        if (countsAsLeft.test(types[i])) {
  1.7304 +          var start = i;
  1.7305 +          for (++i; i < len && countsAsLeft.test(types[i]); ++i) {}
  1.7306 +          order.push(new BidiSpan(0, start, i));
  1.7307 +        } else {
  1.7308 +          var pos = i, at = order.length;
  1.7309 +          for (++i; i < len && types[i] != "L"; ++i) {}
  1.7310 +          for (var j = pos; j < i;) {
  1.7311 +            if (countsAsNum.test(types[j])) {
  1.7312 +              if (pos < j) order.splice(at, 0, new BidiSpan(1, pos, j));
  1.7313 +              var nstart = j;
  1.7314 +              for (++j; j < i && countsAsNum.test(types[j]); ++j) {}
  1.7315 +              order.splice(at, 0, new BidiSpan(2, nstart, j));
  1.7316 +              pos = j;
  1.7317 +            } else ++j;
  1.7318 +          }
  1.7319 +          if (pos < i) order.splice(at, 0, new BidiSpan(1, pos, i));
  1.7320 +        }
  1.7321 +      }
  1.7322 +      if (order[0].level == 1 && (m = str.match(/^\s+/))) {
  1.7323 +        order[0].from = m[0].length;
  1.7324 +        order.unshift(new BidiSpan(0, 0, m[0].length));
  1.7325 +      }
  1.7326 +      if (lst(order).level == 1 && (m = str.match(/\s+$/))) {
  1.7327 +        lst(order).to -= m[0].length;
  1.7328 +        order.push(new BidiSpan(0, len - m[0].length, len));
  1.7329 +      }
  1.7330 +      if (order[0].level != lst(order).level)
  1.7331 +        order.push(new BidiSpan(order[0].level, len, len));
  1.7332 +
  1.7333 +      return order;
  1.7334 +    };
  1.7335 +  })();
  1.7336 +
  1.7337 +  // THE END
  1.7338 +
  1.7339 +  CodeMirror.version = "4.0.3";
  1.7340 +
  1.7341 +  return CodeMirror;
  1.7342 +});

mercurial