http://git-wip-us.apache.org/repos/asf/brooklyn-ui/blob/d19e3156/src/main/webapp/assets/js/lib/codemirror.js
----------------------------------------------------------------------
diff --git a/src/main/webapp/assets/js/lib/codemirror.js 
b/src/main/webapp/assets/js/lib/codemirror.js
deleted file mode 100644
index c6f9af8..0000000
--- a/src/main/webapp/assets/js/lib/codemirror.js
+++ /dev/null
@@ -1,8835 +0,0 @@
-// CodeMirror, copyright (c) by Marijn Haverbeke and others
-// Distributed under an MIT license: http://codemirror.net/LICENSE
-
-// This is CodeMirror (http://codemirror.net), a code editor
-// implemented in JavaScript on top of the browser's DOM.
-//
-// You can find some technical background for some of the code below
-// at http://marijnhaverbeke.nl/blog/#cm-internals .
-
-(function(mod) {
-  if (typeof exports == "object" && typeof module == "object") // CommonJS
-    module.exports = mod();
-  else if (typeof define == "function" && define.amd) // AMD
-    return define([], mod);
-  else // Plain browser env
-    this.CodeMirror = mod();
-})(function() {
-  "use strict";
-
-  // BROWSER SNIFFING
-
-  // Kludges for bugs and behavior differences that can't be feature
-  // detected are enabled based on userAgent etc sniffing.
-
-  var gecko = /gecko\/\d/i.test(navigator.userAgent);
-  var ie_upto10 = /MSIE \d/.test(navigator.userAgent);
-  var ie_11up = 
/Trident\/(?:[7-9]|\d{2,})\..*rv:(\d+)/.exec(navigator.userAgent);
-  var ie = ie_upto10 || ie_11up;
-  var ie_version = ie && (ie_upto10 ? document.documentMode || 6 : ie_11up[1]);
-  var webkit = /WebKit\//.test(navigator.userAgent);
-  var qtwebkit = webkit && /Qt\/\d+\.\d+/.test(navigator.userAgent);
-  var chrome = /Chrome\//.test(navigator.userAgent);
-  var presto = /Opera\//.test(navigator.userAgent);
-  var safari = /Apple Computer/.test(navigator.vendor);
-  var mac_geMountainLion = /Mac OS X 
1\d\D([8-9]|\d\d)\D/.test(navigator.userAgent);
-  var phantom = /PhantomJS/.test(navigator.userAgent);
-
-  var ios = /AppleWebKit/.test(navigator.userAgent) && 
/Mobile\/\w+/.test(navigator.userAgent);
-  // This is woefully incomplete. Suggestions for alternative methods welcome.
-  var mobile = ios || /Android|webOS|BlackBerry|Opera Mini|Opera 
Mobi|IEMobile/i.test(navigator.userAgent);
-  var mac = ios || /Mac/.test(navigator.platform);
-  var windows = /win/i.test(navigator.platform);
-
-  var presto_version = presto && 
navigator.userAgent.match(/Version\/(\d*\.\d*)/);
-  if (presto_version) presto_version = Number(presto_version[1]);
-  if (presto_version && presto_version >= 15) { presto = false; webkit = true; 
}
-  // Some browsers use the wrong event properties to signal cmd/ctrl on OS X
-  var flipCtrlCmd = mac && (qtwebkit || presto && (presto_version == null || 
presto_version < 12.11));
-  var captureRightClick = gecko || (ie && ie_version >= 9);
-
-  // Optimize some code when these features are not used.
-  var sawReadOnlySpans = false, sawCollapsedSpans = false;
-
-  // EDITOR CONSTRUCTOR
-
-  // A CodeMirror instance represents an editor. This is the object
-  // that user code is usually dealing with.
-
-  function CodeMirror(place, options) {
-    if (!(this instanceof CodeMirror)) return new CodeMirror(place, options);
-
-    this.options = options = options ? copyObj(options) : {};
-    // Determine effective options based on given values and defaults.
-    copyObj(defaults, options, false);
-    setGuttersForLineNumbers(options);
-
-    var doc = options.value;
-    if (typeof doc == "string") doc = new Doc(doc, options.mode, null, 
options.lineSeparator);
-    this.doc = doc;
-
-    var input = new CodeMirror.inputStyles[options.inputStyle](this);
-    var display = this.display = new Display(place, doc, input);
-    display.wrapper.CodeMirror = this;
-    updateGutters(this);
-    themeChanged(this);
-    if (options.lineWrapping)
-      this.display.wrapper.className += " CodeMirror-wrap";
-    if (options.autofocus && !mobile) display.input.focus();
-    initScrollbars(this);
-
-    this.state = {
-      keyMaps: [],  // stores maps added by addKeyMap
-      overlays: [], // highlighting overlays, as added by addOverlay
-      modeGen: 0,   // bumped when mode/overlay changes, used to invalidate 
highlighting info
-      overwrite: false,
-      delayingBlurEvent: false,
-      focused: false,
-      suppressEdits: false, // used to disable editing during key handlers 
when in readOnly mode
-      pasteIncoming: false, cutIncoming: false, // help recognize paste/cut 
edits in input.poll
-      selectingText: false,
-      draggingText: false,
-      highlight: new Delayed(), // stores highlight worker timeout
-      keySeq: null,  // Unfinished key sequence
-      specialChars: null
-    };
-
-    var cm = this;
-
-    // Override magic textarea content restore that IE sometimes does
-    // on our hidden textarea on reload
-    if (ie && ie_version < 11) setTimeout(function() { 
cm.display.input.reset(true); }, 20);
-
-    registerEventHandlers(this);
-    ensureGlobalHandlers();
-
-    startOperation(this);
-    this.curOp.forceUpdate = true;
-    attachDoc(this, doc);
-
-    if ((options.autofocus && !mobile) || cm.hasFocus())
-      setTimeout(bind(onFocus, this), 20);
-    else
-      onBlur(this);
-
-    for (var opt in optionHandlers) if (optionHandlers.hasOwnProperty(opt))
-      optionHandlers[opt](this, options[opt], Init);
-    maybeUpdateLineNumberWidth(this);
-    if (options.finishInit) options.finishInit(this);
-    for (var i = 0; i < initHooks.length; ++i) initHooks[i](this);
-    endOperation(this);
-    // Suppress optimizelegibility in Webkit, since it breaks text
-    // measuring on line wrapping boundaries.
-    if (webkit && options.lineWrapping &&
-        getComputedStyle(display.lineDiv).textRendering == 
"optimizelegibility")
-      display.lineDiv.style.textRendering = "auto";
-  }
-
-  // DISPLAY CONSTRUCTOR
-
-  // The display handles the DOM integration, both for input reading
-  // and content drawing. It holds references to DOM nodes and
-  // display-related state.
-
-  function Display(place, doc, input) {
-    var d = this;
-    this.input = input;
-
-    // Covers bottom-right square when both scrollbars are present.
-    d.scrollbarFiller = elt("div", null, "CodeMirror-scrollbar-filler");
-    d.scrollbarFiller.setAttribute("cm-not-content", "true");
-    // Covers bottom of gutter when coverGutterNextToScrollbar is on
-    // and h scrollbar is present.
-    d.gutterFiller = elt("div", null, "CodeMirror-gutter-filler");
-    d.gutterFiller.setAttribute("cm-not-content", "true");
-    // Will contain the actual code, positioned to cover the viewport.
-    d.lineDiv = elt("div", null, "CodeMirror-code");
-    // Elements are added to these to represent selection and cursors.
-    d.selectionDiv = elt("div", null, null, "position: relative; z-index: 1");
-    d.cursorDiv = elt("div", null, "CodeMirror-cursors");
-    // A visibility: hidden element used to find the size of things.
-    d.measure = elt("div", null, "CodeMirror-measure");
-    // When lines outside of the viewport are measured, they are drawn in this.
-    d.lineMeasure = elt("div", null, "CodeMirror-measure");
-    // Wraps everything that needs to exist inside the vertically-padded 
coordinate system
-    d.lineSpace = elt("div", [d.measure, d.lineMeasure, d.selectionDiv, 
d.cursorDiv, d.lineDiv],
-                      null, "position: relative; outline: none");
-    // Moved around its parent to cover visible view.
-    d.mover = elt("div", [elt("div", [d.lineSpace], "CodeMirror-lines")], 
null, "position: relative");
-    // Set to the height of the document, allowing scrolling.
-    d.sizer = elt("div", [d.mover], "CodeMirror-sizer");
-    d.sizerWidth = null;
-    // Behavior of elts with overflow: auto and padding is
-    // inconsistent across browsers. This is used to ensure the
-    // scrollable area is big enough.
-    d.heightForcer = elt("div", null, null, "position: absolute; height: " + 
scrollerGap + "px; width: 1px;");
-    // Will contain the gutters, if any.
-    d.gutters = elt("div", null, "CodeMirror-gutters");
-    d.lineGutter = null;
-    // Actual scrollable element.
-    d.scroller = elt("div", [d.sizer, d.heightForcer, d.gutters], 
"CodeMirror-scroll");
-    d.scroller.setAttribute("tabIndex", "-1");
-    // The element in which the editor lives.
-    d.wrapper = elt("div", [d.scrollbarFiller, d.gutterFiller, d.scroller], 
"CodeMirror");
-
-    // Work around IE7 z-index bug (not perfect, hence IE7 not really being 
supported)
-    if (ie && ie_version < 8) { d.gutters.style.zIndex = -1; 
d.scroller.style.paddingRight = 0; }
-    if (!webkit && !(gecko && mobile)) d.scroller.draggable = true;
-
-    if (place) {
-      if (place.appendChild) place.appendChild(d.wrapper);
-      else place(d.wrapper);
-    }
-
-    // Current rendered range (may be bigger than the view window).
-    d.viewFrom = d.viewTo = doc.first;
-    d.reportedViewFrom = d.reportedViewTo = doc.first;
-    // Information about the rendered lines.
-    d.view = [];
-    d.renderedView = null;
-    // Holds info about a single rendered line when it was rendered
-    // for measurement, while not in view.
-    d.externalMeasured = null;
-    // Empty space (in pixels) above the view
-    d.viewOffset = 0;
-    d.lastWrapHeight = d.lastWrapWidth = 0;
-    d.updateLineNumbers = null;
-
-    d.nativeBarWidth = d.barHeight = d.barWidth = 0;
-    d.scrollbarsClipped = false;
-
-    // Used to only resize the line number gutter when necessary (when
-    // the amount of lines crosses a boundary that makes its width change)
-    d.lineNumWidth = d.lineNumInnerWidth = d.lineNumChars = null;
-    // Set to true when a non-horizontal-scrolling line widget is
-    // added. As an optimization, line widget aligning is skipped when
-    // this is false.
-    d.alignWidgets = false;
-
-    d.cachedCharWidth = d.cachedTextHeight = d.cachedPaddingH = null;
-
-    // Tracks the maximum line length so that the horizontal scrollbar
-    // can be kept static when scrolling.
-    d.maxLine = null;
-    d.maxLineLength = 0;
-    d.maxLineChanged = false;
-
-    // Used for measuring wheel scrolling granularity
-    d.wheelDX = d.wheelDY = d.wheelStartX = d.wheelStartY = null;
-
-    // True when shift is held down.
-    d.shift = false;
-
-    // Used to track whether anything happened since the context menu
-    // was opened.
-    d.selForContextMenu = null;
-
-    d.activeTouch = null;
-
-    input.init(d);
-  }
-
-  // STATE UPDATES
-
-  // Used to get the editor into a consistent state again when options change.
-
-  function loadMode(cm) {
-    cm.doc.mode = CodeMirror.getMode(cm.options, cm.doc.modeOption);
-    resetModeState(cm);
-  }
-
-  function resetModeState(cm) {
-    cm.doc.iter(function(line) {
-      if (line.stateAfter) line.stateAfter = null;
-      if (line.styles) line.styles = null;
-    });
-    cm.doc.frontier = cm.doc.first;
-    startWorker(cm, 100);
-    cm.state.modeGen++;
-    if (cm.curOp) regChange(cm);
-  }
-
-  function wrappingChanged(cm) {
-    if (cm.options.lineWrapping) {
-      addClass(cm.display.wrapper, "CodeMirror-wrap");
-      cm.display.sizer.style.minWidth = "";
-      cm.display.sizerWidth = null;
-    } else {
-      rmClass(cm.display.wrapper, "CodeMirror-wrap");
-      findMaxLine(cm);
-    }
-    estimateLineHeights(cm);
-    regChange(cm);
-    clearCaches(cm);
-    setTimeout(function(){updateScrollbars(cm);}, 100);
-  }
-
-  // Returns a function that estimates the height of a line, to use as
-  // first approximation until the line becomes visible (and is thus
-  // properly measurable).
-  function estimateHeight(cm) {
-    var th = textHeight(cm.display), wrapping = cm.options.lineWrapping;
-    var perLine = wrapping && Math.max(5, cm.display.scroller.clientWidth / 
charWidth(cm.display) - 3);
-    return function(line) {
-      if (lineIsHidden(cm.doc, line)) return 0;
-
-      var widgetsHeight = 0;
-      if (line.widgets) for (var i = 0; i < line.widgets.length; i++) {
-        if (line.widgets[i].height) widgetsHeight += line.widgets[i].height;
-      }
-
-      if (wrapping)
-        return widgetsHeight + (Math.ceil(line.text.length / perLine) || 1) * 
th;
-      else
-        return widgetsHeight + th;
-    };
-  }
-
-  function estimateLineHeights(cm) {
-    var doc = cm.doc, est = estimateHeight(cm);
-    doc.iter(function(line) {
-      var estHeight = est(line);
-      if (estHeight != line.height) updateLineHeight(line, estHeight);
-    });
-  }
-
-  function themeChanged(cm) {
-    cm.display.wrapper.className = 
cm.display.wrapper.className.replace(/\s*cm-s-\S+/g, "") +
-      cm.options.theme.replace(/(^|\s)\s*/g, " cm-s-");
-    clearCaches(cm);
-  }
-
-  function guttersChanged(cm) {
-    updateGutters(cm);
-    regChange(cm);
-    setTimeout(function(){alignHorizontally(cm);}, 20);
-  }
-
-  // Rebuild the gutter elements, ensure the margin to the left of the
-  // code matches their width.
-  function updateGutters(cm) {
-    var gutters = cm.display.gutters, specs = cm.options.gutters;
-    removeChildren(gutters);
-    for (var i = 0; i < specs.length; ++i) {
-      var gutterClass = specs[i];
-      var gElt = gutters.appendChild(elt("div", null, "CodeMirror-gutter " + 
gutterClass));
-      if (gutterClass == "CodeMirror-linenumbers") {
-        cm.display.lineGutter = gElt;
-        gElt.style.width = (cm.display.lineNumWidth || 1) + "px";
-      }
-    }
-    gutters.style.display = i ? "" : "none";
-    updateGutterSpace(cm);
-  }
-
-  function updateGutterSpace(cm) {
-    var width = cm.display.gutters.offsetWidth;
-    cm.display.sizer.style.marginLeft = width + "px";
-  }
-
-  // Compute the character length of a line, taking into account
-  // collapsed ranges (see markText) that might hide parts, and join
-  // other lines onto it.
-  function lineLength(line) {
-    if (line.height == 0) return 0;
-    var len = line.text.length, merged, cur = line;
-    while (merged = collapsedSpanAtStart(cur)) {
-      var found = merged.find(0, true);
-      cur = found.from.line;
-      len += found.from.ch - found.to.ch;
-    }
-    cur = line;
-    while (merged = collapsedSpanAtEnd(cur)) {
-      var found = merged.find(0, true);
-      len -= cur.text.length - found.from.ch;
-      cur = found.to.line;
-      len += cur.text.length - found.to.ch;
-    }
-    return len;
-  }
-
-  // Find the longest line in the document.
-  function findMaxLine(cm) {
-    var d = cm.display, doc = cm.doc;
-    d.maxLine = getLine(doc, doc.first);
-    d.maxLineLength = lineLength(d.maxLine);
-    d.maxLineChanged = true;
-    doc.iter(function(line) {
-      var len = lineLength(line);
-      if (len > d.maxLineLength) {
-        d.maxLineLength = len;
-        d.maxLine = line;
-      }
-    });
-  }
-
-  // Make sure the gutters options contains the element
-  // "CodeMirror-linenumbers" when the lineNumbers option is true.
-  function setGuttersForLineNumbers(options) {
-    var found = indexOf(options.gutters, "CodeMirror-linenumbers");
-    if (found == -1 && options.lineNumbers) {
-      options.gutters = options.gutters.concat(["CodeMirror-linenumbers"]);
-    } else if (found > -1 && !options.lineNumbers) {
-      options.gutters = options.gutters.slice(0);
-      options.gutters.splice(found, 1);
-    }
-  }
-
-  // SCROLLBARS
-
-  // Prepare DOM reads needed to update the scrollbars. Done in one
-  // shot to minimize update/measure roundtrips.
-  function measureForScrollbars(cm) {
-    var d = cm.display, gutterW = d.gutters.offsetWidth;
-    var docH = Math.round(cm.doc.height + paddingVert(cm.display));
-    return {
-      clientHeight: d.scroller.clientHeight,
-      viewHeight: d.wrapper.clientHeight,
-      scrollWidth: d.scroller.scrollWidth, clientWidth: d.scroller.clientWidth,
-      viewWidth: d.wrapper.clientWidth,
-      barLeft: cm.options.fixedGutter ? gutterW : 0,
-      docHeight: docH,
-      scrollHeight: docH + scrollGap(cm) + d.barHeight,
-      nativeBarWidth: d.nativeBarWidth,
-      gutterWidth: gutterW
-    };
-  }
-
-  function NativeScrollbars(place, scroll, cm) {
-    this.cm = cm;
-    var vert = this.vert = elt("div", [elt("div", null, null, "min-width: 
1px")], "CodeMirror-vscrollbar");
-    var horiz = this.horiz = elt("div", [elt("div", null, null, "height: 100%; 
min-height: 1px")], "CodeMirror-hscrollbar");
-    place(vert); place(horiz);
-
-    on(vert, "scroll", function() {
-      if (vert.clientHeight) scroll(vert.scrollTop, "vertical");
-    });
-    on(horiz, "scroll", function() {
-      if (horiz.clientWidth) scroll(horiz.scrollLeft, "horizontal");
-    });
-
-    this.checkedOverlay = false;
-    // Need to set a minimum width to see the scrollbar on IE7 (but must not 
set it on IE8).
-    if (ie && ie_version < 8) this.horiz.style.minHeight = 
this.vert.style.minWidth = "18px";
-  }
-
-  NativeScrollbars.prototype = copyObj({
-    update: function(measure) {
-      var needsH = measure.scrollWidth > measure.clientWidth + 1;
-      var needsV = measure.scrollHeight > measure.clientHeight + 1;
-      var sWidth = measure.nativeBarWidth;
-
-      if (needsV) {
-        this.vert.style.display = "block";
-        this.vert.style.bottom = needsH ? sWidth + "px" : "0";
-        var totalHeight = measure.viewHeight - (needsH ? sWidth : 0);
-        // A bug in IE8 can cause this value to be negative, so guard it.
-        this.vert.firstChild.style.height =
-          Math.max(0, measure.scrollHeight - measure.clientHeight + 
totalHeight) + "px";
-      } else {
-        this.vert.style.display = "";
-        this.vert.firstChild.style.height = "0";
-      }
-
-      if (needsH) {
-        this.horiz.style.display = "block";
-        this.horiz.style.right = needsV ? sWidth + "px" : "0";
-        this.horiz.style.left = measure.barLeft + "px";
-        var totalWidth = measure.viewWidth - measure.barLeft - (needsV ? 
sWidth : 0);
-        this.horiz.firstChild.style.width =
-          (measure.scrollWidth - measure.clientWidth + totalWidth) + "px";
-      } else {
-        this.horiz.style.display = "";
-        this.horiz.firstChild.style.width = "0";
-      }
-
-      if (!this.checkedOverlay && measure.clientHeight > 0) {
-        if (sWidth == 0) this.overlayHack();
-        this.checkedOverlay = true;
-      }
-
-      return {right: needsV ? sWidth : 0, bottom: needsH ? sWidth : 0};
-    },
-    setScrollLeft: function(pos) {
-      if (this.horiz.scrollLeft != pos) this.horiz.scrollLeft = pos;
-    },
-    setScrollTop: function(pos) {
-      if (this.vert.scrollTop != pos) this.vert.scrollTop = pos;
-    },
-    overlayHack: function() {
-      var w = mac && !mac_geMountainLion ? "12px" : "18px";
-      this.horiz.style.minHeight = this.vert.style.minWidth = w;
-      var self = this;
-      var barMouseDown = function(e) {
-        if (e_target(e) != self.vert && e_target(e) != self.horiz)
-          operation(self.cm, onMouseDown)(e);
-      };
-      on(this.vert, "mousedown", barMouseDown);
-      on(this.horiz, "mousedown", barMouseDown);
-    },
-    clear: function() {
-      var parent = this.horiz.parentNode;
-      parent.removeChild(this.horiz);
-      parent.removeChild(this.vert);
-    }
-  }, NativeScrollbars.prototype);
-
-  function NullScrollbars() {}
-
-  NullScrollbars.prototype = copyObj({
-    update: function() { return {bottom: 0, right: 0}; },
-    setScrollLeft: function() {},
-    setScrollTop: function() {},
-    clear: function() {}
-  }, NullScrollbars.prototype);
-
-  CodeMirror.scrollbarModel = {"native": NativeScrollbars, "null": 
NullScrollbars};
-
-  function initScrollbars(cm) {
-    if (cm.display.scrollbars) {
-      cm.display.scrollbars.clear();
-      if (cm.display.scrollbars.addClass)
-        rmClass(cm.display.wrapper, cm.display.scrollbars.addClass);
-    }
-
-    cm.display.scrollbars = new 
CodeMirror.scrollbarModel[cm.options.scrollbarStyle](function(node) {
-      cm.display.wrapper.insertBefore(node, cm.display.scrollbarFiller);
-      // Prevent clicks in the scrollbars from killing focus
-      on(node, "mousedown", function() {
-        if (cm.state.focused) setTimeout(function() { 
cm.display.input.focus(); }, 0);
-      });
-      node.setAttribute("cm-not-content", "true");
-    }, function(pos, axis) {
-      if (axis == "horizontal") setScrollLeft(cm, pos);
-      else setScrollTop(cm, pos);
-    }, cm);
-    if (cm.display.scrollbars.addClass)
-      addClass(cm.display.wrapper, cm.display.scrollbars.addClass);
-  }
-
-  function updateScrollbars(cm, measure) {
-    if (!measure) measure = measureForScrollbars(cm);
-    var startWidth = cm.display.barWidth, startHeight = cm.display.barHeight;
-    updateScrollbarsInner(cm, measure);
-    for (var i = 0; i < 4 && startWidth != cm.display.barWidth || startHeight 
!= cm.display.barHeight; i++) {
-      if (startWidth != cm.display.barWidth && cm.options.lineWrapping)
-        updateHeightsInViewport(cm);
-      updateScrollbarsInner(cm, measureForScrollbars(cm));
-      startWidth = cm.display.barWidth; startHeight = cm.display.barHeight;
-    }
-  }
-
-  // Re-synchronize the fake scrollbars with the actual size of the
-  // content.
-  function updateScrollbarsInner(cm, measure) {
-    var d = cm.display;
-    var sizes = d.scrollbars.update(measure);
-
-    d.sizer.style.paddingRight = (d.barWidth = sizes.right) + "px";
-    d.sizer.style.paddingBottom = (d.barHeight = sizes.bottom) + "px";
-
-    if (sizes.right && sizes.bottom) {
-      d.scrollbarFiller.style.display = "block";
-      d.scrollbarFiller.style.height = sizes.bottom + "px";
-      d.scrollbarFiller.style.width = sizes.right + "px";
-    } else d.scrollbarFiller.style.display = "";
-    if (sizes.bottom && cm.options.coverGutterNextToScrollbar && 
cm.options.fixedGutter) {
-      d.gutterFiller.style.display = "block";
-      d.gutterFiller.style.height = sizes.bottom + "px";
-      d.gutterFiller.style.width = measure.gutterWidth + "px";
-    } else d.gutterFiller.style.display = "";
-  }
-
-  // Compute the lines that are visible in a given viewport (defaults
-  // the the current scroll position). viewport may contain top,
-  // height, and ensure (see op.scrollToPos) properties.
-  function visibleLines(display, doc, viewport) {
-    var top = viewport && viewport.top != null ? Math.max(0, viewport.top) : 
display.scroller.scrollTop;
-    top = Math.floor(top - paddingTop(display));
-    var bottom = viewport && viewport.bottom != null ? viewport.bottom : top + 
display.wrapper.clientHeight;
-
-    var from = lineAtHeight(doc, top), to = lineAtHeight(doc, bottom);
-    // Ensure is a {from: {line, ch}, to: {line, ch}} object, and
-    // forces those lines into the viewport (if possible).
-    if (viewport && viewport.ensure) {
-      var ensureFrom = viewport.ensure.from.line, ensureTo = 
viewport.ensure.to.line;
-      if (ensureFrom < from) {
-        from = ensureFrom;
-        to = lineAtHeight(doc, heightAtLine(getLine(doc, ensureFrom)) + 
display.wrapper.clientHeight);
-      } else if (Math.min(ensureTo, doc.lastLine()) >= to) {
-        from = lineAtHeight(doc, heightAtLine(getLine(doc, ensureTo)) - 
display.wrapper.clientHeight);
-        to = ensureTo;
-      }
-    }
-    return {from: from, to: Math.max(to, from + 1)};
-  }
-
-  // LINE NUMBERS
-
-  // Re-align line numbers and gutter marks to compensate for
-  // horizontal scrolling.
-  function alignHorizontally(cm) {
-    var display = cm.display, view = display.view;
-    if (!display.alignWidgets && (!display.gutters.firstChild || 
!cm.options.fixedGutter)) return;
-    var comp = compensateForHScroll(display) - display.scroller.scrollLeft + 
cm.doc.scrollLeft;
-    var gutterW = display.gutters.offsetWidth, left = comp + "px";
-    for (var i = 0; i < view.length; i++) if (!view[i].hidden) {
-      if (cm.options.fixedGutter && view[i].gutter)
-        view[i].gutter.style.left = left;
-      var align = view[i].alignable;
-      if (align) for (var j = 0; j < align.length; j++)
-        align[j].style.left = left;
-    }
-    if (cm.options.fixedGutter)
-      display.gutters.style.left = (comp + gutterW) + "px";
-  }
-
-  // Used to ensure that the line number gutter is still the right
-  // size for the current document size. Returns true when an update
-  // is needed.
-  function maybeUpdateLineNumberWidth(cm) {
-    if (!cm.options.lineNumbers) return false;
-    var doc = cm.doc, last = lineNumberFor(cm.options, doc.first + doc.size - 
1), display = cm.display;
-    if (last.length != display.lineNumChars) {
-      var test = display.measure.appendChild(elt("div", [elt("div", last)],
-                                                 "CodeMirror-linenumber 
CodeMirror-gutter-elt"));
-      var innerW = test.firstChild.offsetWidth, padding = test.offsetWidth - 
innerW;
-      display.lineGutter.style.width = "";
-      display.lineNumInnerWidth = Math.max(innerW, 
display.lineGutter.offsetWidth - padding) + 1;
-      display.lineNumWidth = display.lineNumInnerWidth + padding;
-      display.lineNumChars = display.lineNumInnerWidth ? last.length : -1;
-      display.lineGutter.style.width = display.lineNumWidth + "px";
-      updateGutterSpace(cm);
-      return true;
-    }
-    return false;
-  }
-
-  function lineNumberFor(options, i) {
-    return String(options.lineNumberFormatter(i + options.firstLineNumber));
-  }
-
-  // Computes display.scroller.scrollLeft + display.gutters.offsetWidth,
-  // but using getBoundingClientRect to get a sub-pixel-accurate
-  // result.
-  function compensateForHScroll(display) {
-    return display.scroller.getBoundingClientRect().left - 
display.sizer.getBoundingClientRect().left;
-  }
-
-  // DISPLAY DRAWING
-
-  function DisplayUpdate(cm, viewport, force) {
-    var display = cm.display;
-
-    this.viewport = viewport;
-    // Store some values that we'll need later (but don't want to force a 
relayout for)
-    this.visible = visibleLines(display, cm.doc, viewport);
-    this.editorIsHidden = !display.wrapper.offsetWidth;
-    this.wrapperHeight = display.wrapper.clientHeight;
-    this.wrapperWidth = display.wrapper.clientWidth;
-    this.oldDisplayWidth = displayWidth(cm);
-    this.force = force;
-    this.dims = getDimensions(cm);
-    this.events = [];
-  }
-
-  DisplayUpdate.prototype.signal = function(emitter, type) {
-    if (hasHandler(emitter, type))
-      this.events.push(arguments);
-  };
-  DisplayUpdate.prototype.finish = function() {
-    for (var i = 0; i < this.events.length; i++)
-      signal.apply(null, this.events[i]);
-  };
-
-  function maybeClipScrollbars(cm) {
-    var display = cm.display;
-    if (!display.scrollbarsClipped && display.scroller.offsetWidth) {
-      display.nativeBarWidth = display.scroller.offsetWidth - 
display.scroller.clientWidth;
-      display.heightForcer.style.height = scrollGap(cm) + "px";
-      display.sizer.style.marginBottom = -display.nativeBarWidth + "px";
-      display.sizer.style.borderRightWidth = scrollGap(cm) + "px";
-      display.scrollbarsClipped = true;
-    }
-  }
-
-  // Does the actual updating of the line display. Bails out
-  // (returning false) when there is nothing to be done and forced is
-  // false.
-  function updateDisplayIfNeeded(cm, update) {
-    var display = cm.display, doc = cm.doc;
-
-    if (update.editorIsHidden) {
-      resetView(cm);
-      return false;
-    }
-
-    // Bail out if the visible area is already rendered and nothing changed.
-    if (!update.force &&
-        update.visible.from >= display.viewFrom && update.visible.to <= 
display.viewTo &&
-        (display.updateLineNumbers == null || display.updateLineNumbers >= 
display.viewTo) &&
-        display.renderedView == display.view && countDirtyView(cm) == 0)
-      return false;
-
-    if (maybeUpdateLineNumberWidth(cm)) {
-      resetView(cm);
-      update.dims = getDimensions(cm);
-    }
-
-    // Compute a suitable new viewport (from & to)
-    var end = doc.first + doc.size;
-    var from = Math.max(update.visible.from - cm.options.viewportMargin, 
doc.first);
-    var to = Math.min(end, update.visible.to + cm.options.viewportMargin);
-    if (display.viewFrom < from && from - display.viewFrom < 20) from = 
Math.max(doc.first, display.viewFrom);
-    if (display.viewTo > to && display.viewTo - to < 20) to = Math.min(end, 
display.viewTo);
-    if (sawCollapsedSpans) {
-      from = visualLineNo(cm.doc, from);
-      to = visualLineEndNo(cm.doc, to);
-    }
-
-    var different = from != display.viewFrom || to != display.viewTo ||
-      display.lastWrapHeight != update.wrapperHeight || display.lastWrapWidth 
!= update.wrapperWidth;
-    adjustView(cm, from, to);
-
-    display.viewOffset = heightAtLine(getLine(cm.doc, display.viewFrom));
-    // Position the mover div to align with the current scroll position
-    cm.display.mover.style.top = display.viewOffset + "px";
-
-    var toUpdate = countDirtyView(cm);
-    if (!different && toUpdate == 0 && !update.force && display.renderedView 
== display.view &&
-        (display.updateLineNumbers == null || display.updateLineNumbers >= 
display.viewTo))
-      return false;
-
-    // For big changes, we hide the enclosing element during the
-    // update, since that speeds up the operations on most browsers.
-    var focused = activeElt();
-    if (toUpdate > 4) display.lineDiv.style.display = "none";
-    patchDisplay(cm, display.updateLineNumbers, update.dims);
-    if (toUpdate > 4) display.lineDiv.style.display = "";
-    display.renderedView = display.view;
-    // There might have been a widget with a focused element that got
-    // hidden or updated, if so re-focus it.
-    if (focused && activeElt() != focused && focused.offsetHeight) 
focused.focus();
-
-    // Prevent selection and cursors from interfering with the scroll
-    // width and height.
-    removeChildren(display.cursorDiv);
-    removeChildren(display.selectionDiv);
-    display.gutters.style.height = display.sizer.style.minHeight = 0;
-
-    if (different) {
-      display.lastWrapHeight = update.wrapperHeight;
-      display.lastWrapWidth = update.wrapperWidth;
-      startWorker(cm, 400);
-    }
-
-    display.updateLineNumbers = null;
-
-    return true;
-  }
-
-  function postUpdateDisplay(cm, update) {
-    var viewport = update.viewport;
-    for (var first = true;; first = false) {
-      if (!first || !cm.options.lineWrapping || update.oldDisplayWidth == 
displayWidth(cm)) {
-        // Clip forced viewport to actual scrollable area.
-        if (viewport && viewport.top != null)
-          viewport = {top: Math.min(cm.doc.height + paddingVert(cm.display) - 
displayHeight(cm), viewport.top)};
-        // Updated line heights might result in the drawn area not
-        // actually covering the viewport. Keep looping until it does.
-        update.visible = visibleLines(cm.display, cm.doc, viewport);
-        if (update.visible.from >= cm.display.viewFrom && update.visible.to <= 
cm.display.viewTo)
-          break;
-      }
-      if (!updateDisplayIfNeeded(cm, update)) break;
-      updateHeightsInViewport(cm);
-      var barMeasure = measureForScrollbars(cm);
-      updateSelection(cm);
-      setDocumentHeight(cm, barMeasure);
-      updateScrollbars(cm, barMeasure);
-    }
-
-    update.signal(cm, "update", cm);
-    if (cm.display.viewFrom != cm.display.reportedViewFrom || 
cm.display.viewTo != cm.display.reportedViewTo) {
-      update.signal(cm, "viewportChange", cm, cm.display.viewFrom, 
cm.display.viewTo);
-      cm.display.reportedViewFrom = cm.display.viewFrom; 
cm.display.reportedViewTo = cm.display.viewTo;
-    }
-  }
-
-  function updateDisplaySimple(cm, viewport) {
-    var update = new DisplayUpdate(cm, viewport);
-    if (updateDisplayIfNeeded(cm, update)) {
-      updateHeightsInViewport(cm);
-      postUpdateDisplay(cm, update);
-      var barMeasure = measureForScrollbars(cm);
-      updateSelection(cm);
-      setDocumentHeight(cm, barMeasure);
-      updateScrollbars(cm, barMeasure);
-      update.finish();
-    }
-  }
-
-  function setDocumentHeight(cm, measure) {
-    cm.display.sizer.style.minHeight = measure.docHeight + "px";
-    var total = measure.docHeight + cm.display.barHeight;
-    cm.display.heightForcer.style.top = total + "px";
-    cm.display.gutters.style.height = Math.max(total + scrollGap(cm), 
measure.clientHeight) + "px";
-  }
-
-  // Read the actual heights of the rendered lines, and update their
-  // stored heights to match.
-  function updateHeightsInViewport(cm) {
-    var display = cm.display;
-    var prevBottom = display.lineDiv.offsetTop;
-    for (var i = 0; i < display.view.length; i++) {
-      var cur = display.view[i], height;
-      if (cur.hidden) continue;
-      if (ie && ie_version < 8) {
-        var bot = cur.node.offsetTop + cur.node.offsetHeight;
-        height = bot - prevBottom;
-        prevBottom = bot;
-      } else {
-        var box = cur.node.getBoundingClientRect();
-        height = box.bottom - box.top;
-      }
-      var diff = cur.line.height - height;
-      if (height < 2) height = textHeight(display);
-      if (diff > .001 || diff < -.001) {
-        updateLineHeight(cur.line, height);
-        updateWidgetHeight(cur.line);
-        if (cur.rest) for (var j = 0; j < cur.rest.length; j++)
-          updateWidgetHeight(cur.rest[j]);
-      }
-    }
-  }
-
-  // Read and store the height of line widgets associated with the
-  // given line.
-  function updateWidgetHeight(line) {
-    if (line.widgets) for (var i = 0; i < line.widgets.length; ++i)
-      line.widgets[i].height = line.widgets[i].node.offsetHeight;
-  }
-
-  // Do a bulk-read of the DOM positions and sizes needed to draw the
-  // view, so that we don't interleave reading and writing to the DOM.
-  function getDimensions(cm) {
-    var d = cm.display, left = {}, width = {};
-    var gutterLeft = d.gutters.clientLeft;
-    for (var n = d.gutters.firstChild, i = 0; n; n = n.nextSibling, ++i) {
-      left[cm.options.gutters[i]] = n.offsetLeft + n.clientLeft + gutterLeft;
-      width[cm.options.gutters[i]] = n.clientWidth;
-    }
-    return {fixedPos: compensateForHScroll(d),
-            gutterTotalWidth: d.gutters.offsetWidth,
-            gutterLeft: left,
-            gutterWidth: width,
-            wrapperWidth: d.wrapper.clientWidth};
-  }
-
-  // Sync the actual display DOM structure with display.view, removing
-  // nodes for lines that are no longer in view, and creating the ones
-  // that are not there yet, and updating the ones that are out of
-  // date.
-  function patchDisplay(cm, updateNumbersFrom, dims) {
-    var display = cm.display, lineNumbers = cm.options.lineNumbers;
-    var container = display.lineDiv, cur = container.firstChild;
-
-    function rm(node) {
-      var next = node.nextSibling;
-      // Works around a throw-scroll bug in OS X Webkit
-      if (webkit && mac && cm.display.currentWheelTarget == node)
-        node.style.display = "none";
-      else
-        node.parentNode.removeChild(node);
-      return next;
-    }
-
-    var view = display.view, lineN = display.viewFrom;
-    // Loop over the elements in the view, syncing cur (the DOM nodes
-    // in display.lineDiv) with the view as we go.
-    for (var i = 0; i < view.length; i++) {
-      var lineView = view[i];
-      if (lineView.hidden) {
-      } else if (!lineView.node || lineView.node.parentNode != container) { // 
Not drawn yet
-        var node = buildLineElement(cm, lineView, lineN, dims);
-        container.insertBefore(node, cur);
-      } else { // Already drawn
-        while (cur != lineView.node) cur = rm(cur);
-        var updateNumber = lineNumbers && updateNumbersFrom != null &&
-          updateNumbersFrom <= lineN && lineView.lineNumber;
-        if (lineView.changes) {
-          if (indexOf(lineView.changes, "gutter") > -1) updateNumber = false;
-          updateLineForChanges(cm, lineView, lineN, dims);
-        }
-        if (updateNumber) {
-          removeChildren(lineView.lineNumber);
-          
lineView.lineNumber.appendChild(document.createTextNode(lineNumberFor(cm.options,
 lineN)));
-        }
-        cur = lineView.node.nextSibling;
-      }
-      lineN += lineView.size;
-    }
-    while (cur) cur = rm(cur);
-  }
-
-  // When an aspect of a line changes, a string is added to
-  // lineView.changes. This updates the relevant part of the line's
-  // DOM structure.
-  function updateLineForChanges(cm, lineView, lineN, dims) {
-    for (var j = 0; j < lineView.changes.length; j++) {
-      var type = lineView.changes[j];
-      if (type == "text") updateLineText(cm, lineView);
-      else if (type == "gutter") updateLineGutter(cm, lineView, lineN, dims);
-      else if (type == "class") updateLineClasses(lineView);
-      else if (type == "widget") updateLineWidgets(cm, lineView, dims);
-    }
-    lineView.changes = null;
-  }
-
-  // Lines with gutter elements, widgets or a background class need to
-  // be wrapped, and have the extra elements added to the wrapper div
-  function ensureLineWrapped(lineView) {
-    if (lineView.node == lineView.text) {
-      lineView.node = elt("div", null, null, "position: relative");
-      if (lineView.text.parentNode)
-        lineView.text.parentNode.replaceChild(lineView.node, lineView.text);
-      lineView.node.appendChild(lineView.text);
-      if (ie && ie_version < 8) lineView.node.style.zIndex = 2;
-    }
-    return lineView.node;
-  }
-
-  function updateLineBackground(lineView) {
-    var cls = lineView.bgClass ? lineView.bgClass + " " + 
(lineView.line.bgClass || "") : lineView.line.bgClass;
-    if (cls) cls += " CodeMirror-linebackground";
-    if (lineView.background) {
-      if (cls) lineView.background.className = cls;
-      else { lineView.background.parentNode.removeChild(lineView.background); 
lineView.background = null; }
-    } else if (cls) {
-      var wrap = ensureLineWrapped(lineView);
-      lineView.background = wrap.insertBefore(elt("div", null, cls), 
wrap.firstChild);
-    }
-  }
-
-  // Wrapper around buildLineContent which will reuse the structure
-  // in display.externalMeasured when possible.
-  function getLineContent(cm, lineView) {
-    var ext = cm.display.externalMeasured;
-    if (ext && ext.line == lineView.line) {
-      cm.display.externalMeasured = null;
-      lineView.measure = ext.measure;
-      return ext.built;
-    }
-    return buildLineContent(cm, lineView);
-  }
-
-  // Redraw the line's text. Interacts with the background and text
-  // classes because the mode may output tokens that influence these
-  // classes.
-  function updateLineText(cm, lineView) {
-    var cls = lineView.text.className;
-    var built = getLineContent(cm, lineView);
-    if (lineView.text == lineView.node) lineView.node = built.pre;
-    lineView.text.parentNode.replaceChild(built.pre, lineView.text);
-    lineView.text = built.pre;
-    if (built.bgClass != lineView.bgClass || built.textClass != 
lineView.textClass) {
-      lineView.bgClass = built.bgClass;
-      lineView.textClass = built.textClass;
-      updateLineClasses(lineView);
-    } else if (cls) {
-      lineView.text.className = cls;
-    }
-  }
-
-  function updateLineClasses(lineView) {
-    updateLineBackground(lineView);
-    if (lineView.line.wrapClass)
-      ensureLineWrapped(lineView).className = lineView.line.wrapClass;
-    else if (lineView.node != lineView.text)
-      lineView.node.className = "";
-    var textClass = lineView.textClass ? lineView.textClass + " " + 
(lineView.line.textClass || "") : lineView.line.textClass;
-    lineView.text.className = textClass || "";
-  }
-
-  function updateLineGutter(cm, lineView, lineN, dims) {
-    if (lineView.gutter) {
-      lineView.node.removeChild(lineView.gutter);
-      lineView.gutter = null;
-    }
-    if (lineView.gutterBackground) {
-      lineView.node.removeChild(lineView.gutterBackground);
-      lineView.gutterBackground = null;
-    }
-    if (lineView.line.gutterClass) {
-      var wrap = ensureLineWrapped(lineView);
-      lineView.gutterBackground = elt("div", null, 
"CodeMirror-gutter-background " + lineView.line.gutterClass,
-                                      "left: " + (cm.options.fixedGutter ? 
dims.fixedPos : -dims.gutterTotalWidth) +
-                                      "px; width: " + dims.gutterTotalWidth + 
"px");
-      wrap.insertBefore(lineView.gutterBackground, lineView.text);
-    }
-    var markers = lineView.line.gutterMarkers;
-    if (cm.options.lineNumbers || markers) {
-      var wrap = ensureLineWrapped(lineView);
-      var gutterWrap = lineView.gutter = elt("div", null, 
"CodeMirror-gutter-wrapper", "left: " +
-                                             (cm.options.fixedGutter ? 
dims.fixedPos : -dims.gutterTotalWidth) + "px");
-      cm.display.input.setUneditable(gutterWrap);
-      wrap.insertBefore(gutterWrap, lineView.text);
-      if (lineView.line.gutterClass)
-        gutterWrap.className += " " + lineView.line.gutterClass;
-      if (cm.options.lineNumbers && (!markers || 
!markers["CodeMirror-linenumbers"]))
-        lineView.lineNumber = gutterWrap.appendChild(
-          elt("div", lineNumberFor(cm.options, lineN),
-              "CodeMirror-linenumber CodeMirror-gutter-elt",
-              "left: " + dims.gutterLeft["CodeMirror-linenumbers"] + "px; 
width: "
-              + cm.display.lineNumInnerWidth + "px"));
-      if (markers) for (var k = 0; k < cm.options.gutters.length; ++k) {
-        var id = cm.options.gutters[k], found = markers.hasOwnProperty(id) && 
markers[id];
-        if (found)
-          gutterWrap.appendChild(elt("div", [found], "CodeMirror-gutter-elt", 
"left: " +
-                                     dims.gutterLeft[id] + "px; width: " + 
dims.gutterWidth[id] + "px"));
-      }
-    }
-  }
-
-  function updateLineWidgets(cm, lineView, dims) {
-    if (lineView.alignable) lineView.alignable = null;
-    for (var node = lineView.node.firstChild, next; node; node = next) {
-      var next = node.nextSibling;
-      if (node.className == "CodeMirror-linewidget")
-        lineView.node.removeChild(node);
-    }
-    insertLineWidgets(cm, lineView, dims);
-  }
-
-  // Build a line's DOM representation from scratch
-  function buildLineElement(cm, lineView, lineN, dims) {
-    var built = getLineContent(cm, lineView);
-    lineView.text = lineView.node = built.pre;
-    if (built.bgClass) lineView.bgClass = built.bgClass;
-    if (built.textClass) lineView.textClass = built.textClass;
-
-    updateLineClasses(lineView);
-    updateLineGutter(cm, lineView, lineN, dims);
-    insertLineWidgets(cm, lineView, dims);
-    return lineView.node;
-  }
-
-  // A lineView may contain multiple logical lines (when merged by
-  // collapsed spans). The widgets for all of them need to be drawn.
-  function insertLineWidgets(cm, lineView, dims) {
-    insertLineWidgetsFor(cm, lineView.line, lineView, dims, true);
-    if (lineView.rest) for (var i = 0; i < lineView.rest.length; i++)
-      insertLineWidgetsFor(cm, lineView.rest[i], lineView, dims, false);
-  }
-
-  function insertLineWidgetsFor(cm, line, lineView, dims, allowAbove) {
-    if (!line.widgets) return;
-    var wrap = ensureLineWrapped(lineView);
-    for (var i = 0, ws = line.widgets; i < ws.length; ++i) {
-      var widget = ws[i], node = elt("div", [widget.node], 
"CodeMirror-linewidget");
-      if (!widget.handleMouseEvents) node.setAttribute("cm-ignore-events", 
"true");
-      positionLineWidget(widget, node, lineView, dims);
-      cm.display.input.setUneditable(node);
-      if (allowAbove && widget.above)
-        wrap.insertBefore(node, lineView.gutter || lineView.text);
-      else
-        wrap.appendChild(node);
-      signalLater(widget, "redraw");
-    }
-  }
-
-  function positionLineWidget(widget, node, lineView, dims) {
-    if (widget.noHScroll) {
-      (lineView.alignable || (lineView.alignable = [])).push(node);
-      var width = dims.wrapperWidth;
-      node.style.left = dims.fixedPos + "px";
-      if (!widget.coverGutter) {
-        width -= dims.gutterTotalWidth;
-        node.style.paddingLeft = dims.gutterTotalWidth + "px";
-      }
-      node.style.width = width + "px";
-    }
-    if (widget.coverGutter) {
-      node.style.zIndex = 5;
-      node.style.position = "relative";
-      if (!widget.noHScroll) node.style.marginLeft = -dims.gutterTotalWidth + 
"px";
-    }
-  }
-
-  // POSITION OBJECT
-
-  // A Pos instance represents a position within the text.
-  var Pos = CodeMirror.Pos = function(line, ch) {
-    if (!(this instanceof Pos)) return new Pos(line, ch);
-    this.line = line; this.ch = ch;
-  };
-
-  // Compare two positions, return 0 if they are the same, a negative
-  // number when a is less, and a positive number otherwise.
-  var cmp = CodeMirror.cmpPos = function(a, b) { return a.line - b.line || 
a.ch - b.ch; };
-
-  function copyPos(x) {return Pos(x.line, x.ch);}
-  function maxPos(a, b) { return cmp(a, b) < 0 ? b : a; }
-  function minPos(a, b) { return cmp(a, b) < 0 ? a : b; }
-
-  // INPUT HANDLING
-
-  function ensureFocus(cm) {
-    if (!cm.state.focused) { cm.display.input.focus(); onFocus(cm); }
-  }
-
-  function isReadOnly(cm) {
-    return cm.options.readOnly || cm.doc.cantEdit;
-  }
-
-  // This will be set to an array of strings when copying, so that,
-  // when pasting, we know what kind of selections the copied text
-  // was made out of.
-  var lastCopied = null;
-
-  function applyTextInput(cm, inserted, deleted, sel, origin) {
-    var doc = cm.doc;
-    cm.display.shift = false;
-    if (!sel) sel = doc.sel;
-
-    var paste = cm.state.pasteIncoming || origin == "paste";
-    var textLines = doc.splitLines(inserted), multiPaste = null;
-    // When pasing N lines into N selections, insert one line per selection
-    if (paste && sel.ranges.length > 1) {
-      if (lastCopied && lastCopied.join("\n") == inserted) {
-        if (sel.ranges.length % lastCopied.length == 0) {
-          multiPaste = [];
-          for (var i = 0; i < lastCopied.length; i++)
-            multiPaste.push(doc.splitLines(lastCopied[i]));
-        }
-      } else if (textLines.length == sel.ranges.length) {
-        multiPaste = map(textLines, function(l) { return [l]; });
-      }
-    }
-
-    // Normal behavior is to insert the new text into every selection
-    for (var i = sel.ranges.length - 1; i >= 0; i--) {
-      var range = sel.ranges[i];
-      var from = range.from(), to = range.to();
-      if (range.empty()) {
-        if (deleted && deleted > 0) // Handle deletion
-          from = Pos(from.line, from.ch - deleted);
-        else if (cm.state.overwrite && !paste) // Handle overwrite
-          to = Pos(to.line, Math.min(getLine(doc, to.line).text.length, to.ch 
+ lst(textLines).length));
-      }
-      var updateInput = cm.curOp.updateInput;
-      var changeEvent = {from: from, to: to, text: multiPaste ? multiPaste[i % 
multiPaste.length] : textLines,
-                         origin: origin || (paste ? "paste" : 
cm.state.cutIncoming ? "cut" : "+input")};
-      makeChange(cm.doc, changeEvent);
-      signalLater(cm, "inputRead", cm, changeEvent);
-    }
-    if (inserted && !paste)
-      triggerElectric(cm, inserted);
-
-    ensureCursorVisible(cm);
-    cm.curOp.updateInput = updateInput;
-    cm.curOp.typing = true;
-    cm.state.pasteIncoming = cm.state.cutIncoming = false;
-  }
-
-  function handlePaste(e, cm) {
-    var pasted = e.clipboardData && e.clipboardData.getData("text/plain");
-    if (pasted) {
-      e.preventDefault();
-      if (!isReadOnly(cm) && !cm.options.disableInput)
-        runInOp(cm, function() { applyTextInput(cm, pasted, 0, null, "paste"); 
});
-      return true;
-    }
-  }
-
-  function triggerElectric(cm, inserted) {
-    // When an 'electric' character is inserted, immediately trigger a reindent
-    if (!cm.options.electricChars || !cm.options.smartIndent) return;
-    var sel = cm.doc.sel;
-
-    for (var i = sel.ranges.length - 1; i >= 0; i--) {
-      var range = sel.ranges[i];
-      if (range.head.ch > 100 || (i && sel.ranges[i - 1].head.line == 
range.head.line)) continue;
-      var mode = cm.getModeAt(range.head);
-      var indented = false;
-      if (mode.electricChars) {
-        for (var j = 0; j < mode.electricChars.length; j++)
-          if (inserted.indexOf(mode.electricChars.charAt(j)) > -1) {
-            indented = indentLine(cm, range.head.line, "smart");
-            break;
-          }
-      } else if (mode.electricInput) {
-        if (mode.electricInput.test(getLine(cm.doc, 
range.head.line).text.slice(0, range.head.ch)))
-          indented = indentLine(cm, range.head.line, "smart");
-      }
-      if (indented) signalLater(cm, "electricInput", cm, range.head.line);
-    }
-  }
-
-  function copyableRanges(cm) {
-    var text = [], ranges = [];
-    for (var i = 0; i < cm.doc.sel.ranges.length; i++) {
-      var line = cm.doc.sel.ranges[i].head.line;
-      var lineRange = {anchor: Pos(line, 0), head: Pos(line + 1, 0)};
-      ranges.push(lineRange);
-      text.push(cm.getRange(lineRange.anchor, lineRange.head));
-    }
-    return {text: text, ranges: ranges};
-  }
-
-  function disableBrowserMagic(field) {
-    field.setAttribute("autocorrect", "off");
-    field.setAttribute("autocapitalize", "off");
-    field.setAttribute("spellcheck", "false");
-  }
-
-  // TEXTAREA INPUT STYLE
-
-  function TextareaInput(cm) {
-    this.cm = cm;
-    // See input.poll and input.reset
-    this.prevInput = "";
-
-    // Flag that indicates whether we expect input to appear real soon
-    // now (after some event like 'keypress' or 'input') and are
-    // polling intensively.
-    this.pollingFast = false;
-    // Self-resetting timeout for the poller
-    this.polling = new Delayed();
-    // Tracks when input.reset has punted to just putting a short
-    // string into the textarea instead of the full selection.
-    this.inaccurateSelection = false;
-    // Used to work around IE issue with selection being forgotten when focus 
moves away from textarea
-    this.hasSelection = false;
-    this.composing = null;
-  };
-
-  function hiddenTextarea() {
-    var te = elt("textarea", null, null, "position: absolute; padding: 0; 
width: 1px; height: 1em; outline: none");
-    var div = elt("div", [te], null, "overflow: hidden; position: relative; 
width: 3px; height: 0px;");
-    // The textarea is kept positioned near the cursor to prevent the
-    // fact that it'll be scrolled into view on input from scrolling
-    // our fake cursor out of view. On webkit, when wrap=off, paste is
-    // very slow. So make the area wide instead.
-    if (webkit) te.style.width = "1000px";
-    else te.setAttribute("wrap", "off");
-    // If border: 0; -- iOS fails to open keyboard (issue #1287)
-    if (ios) te.style.border = "1px solid black";
-    disableBrowserMagic(te);
-    return div;
-  }
-
-  TextareaInput.prototype = copyObj({
-    init: function(display) {
-      var input = this, cm = this.cm;
-
-      // Wraps and hides input textarea
-      var div = this.wrapper = hiddenTextarea();
-      // The semihidden textarea that is focused when the editor is
-      // focused, and receives input.
-      var te = this.textarea = div.firstChild;
-      display.wrapper.insertBefore(div, display.wrapper.firstChild);
-
-      // Needed to hide big blue blinking cursor on Mobile Safari (doesn't 
seem to work in iOS 8 anymore)
-      if (ios) te.style.width = "0px";
-
-      on(te, "input", function() {
-        if (ie && ie_version >= 9 && input.hasSelection) input.hasSelection = 
null;
-        input.poll();
-      });
-
-      on(te, "paste", function(e) {
-        if (handlePaste(e, cm)) return true;
-
-        cm.state.pasteIncoming = true;
-        input.fastPoll();
-      });
-
-      function prepareCopyCut(e) {
-        if (cm.somethingSelected()) {
-          lastCopied = cm.getSelections();
-          if (input.inaccurateSelection) {
-            input.prevInput = "";
-            input.inaccurateSelection = false;
-            te.value = lastCopied.join("\n");
-            selectInput(te);
-          }
-        } else if (!cm.options.lineWiseCopyCut) {
-          return;
-        } else {
-          var ranges = copyableRanges(cm);
-          lastCopied = ranges.text;
-          if (e.type == "cut") {
-            cm.setSelections(ranges.ranges, null, sel_dontScroll);
-          } else {
-            input.prevInput = "";
-            te.value = ranges.text.join("\n");
-            selectInput(te);
-          }
-        }
-        if (e.type == "cut") cm.state.cutIncoming = true;
-      }
-      on(te, "cut", prepareCopyCut);
-      on(te, "copy", prepareCopyCut);
-
-      on(display.scroller, "paste", function(e) {
-        if (eventInWidget(display, e)) return;
-        cm.state.pasteIncoming = true;
-        input.focus();
-      });
-
-      // Prevent normal selection in the editor (we handle our own)
-      on(display.lineSpace, "selectstart", function(e) {
-        if (!eventInWidget(display, e)) e_preventDefault(e);
-      });
-
-      on(te, "compositionstart", function() {
-        var start = cm.getCursor("from");
-        if (input.composing) input.composing.range.clear()
-        input.composing = {
-          start: start,
-          range: cm.markText(start, cm.getCursor("to"), {className: 
"CodeMirror-composing"})
-        };
-      });
-      on(te, "compositionend", function() {
-        if (input.composing) {
-          input.poll();
-          input.composing.range.clear();
-          input.composing = null;
-        }
-      });
-    },
-
-    prepareSelection: function() {
-      // Redraw the selection and/or cursor
-      var cm = this.cm, display = cm.display, doc = cm.doc;
-      var result = prepareSelection(cm);
-
-      // Move the hidden textarea near the cursor to prevent scrolling 
artifacts
-      if (cm.options.moveInputWithCursor) {
-        var headPos = cursorCoords(cm, doc.sel.primary().head, "div");
-        var wrapOff = display.wrapper.getBoundingClientRect(), lineOff = 
display.lineDiv.getBoundingClientRect();
-        result.teTop = Math.max(0, Math.min(display.wrapper.clientHeight - 10,
-                                            headPos.top + lineOff.top - 
wrapOff.top));
-        result.teLeft = Math.max(0, Math.min(display.wrapper.clientWidth - 10,
-                                             headPos.left + lineOff.left - 
wrapOff.left));
-      }
-
-      return result;
-    },
-
-    showSelection: function(drawn) {
-      var cm = this.cm, display = cm.display;
-      removeChildrenAndAdd(display.cursorDiv, drawn.cursors);
-      removeChildrenAndAdd(display.selectionDiv, drawn.selection);
-      if (drawn.teTop != null) {
-        this.wrapper.style.top = drawn.teTop + "px";
-        this.wrapper.style.left = drawn.teLeft + "px";
-      }
-    },
-
-    // Reset the input to correspond to the selection (or to be empty,
-    // when not typing and nothing is selected)
-    reset: function(typing) {
-      if (this.contextMenuPending) return;
-      var minimal, selected, cm = this.cm, doc = cm.doc;
-      if (cm.somethingSelected()) {
-        this.prevInput = "";
-        var range = doc.sel.primary();
-        minimal = hasCopyEvent &&
-          (range.to().line - range.from().line > 100 || (selected = 
cm.getSelection()).length > 1000);
-        var content = minimal ? "-" : selected || cm.getSelection();
-        this.textarea.value = content;
-        if (cm.state.focused) selectInput(this.textarea);
-        if (ie && ie_version >= 9) this.hasSelection = content;
-      } else if (!typing) {
-        this.prevInput = this.textarea.value = "";
-        if (ie && ie_version >= 9) this.hasSelection = null;
-      }
-      this.inaccurateSelection = minimal;
-    },
-
-    getField: function() { return this.textarea; },
-
-    supportsTouch: function() { return false; },
-
-    focus: function() {
-      if (this.cm.options.readOnly != "nocursor" && (!mobile || activeElt() != 
this.textarea)) {
-        try { this.textarea.focus(); }
-        catch (e) {} // IE8 will throw if the textarea is display: none or not 
in DOM
-      }
-    },
-
-    blur: function() { this.textarea.blur(); },
-
-    resetPosition: function() {
-      this.wrapper.style.top = this.wrapper.style.left = 0;
-    },
-
-    receivedFocus: function() { this.slowPoll(); },
-
-    // Poll for input changes, using the normal rate of polling. This
-    // runs as long as the editor is focused.
-    slowPoll: function() {
-      var input = this;
-      if (input.pollingFast) return;
-      input.polling.set(this.cm.options.pollInterval, function() {
-        input.poll();
-        if (input.cm.state.focused) input.slowPoll();
-      });
-    },
-
-    // When an event has just come in that is likely to add or change
-    // something in the input textarea, we poll faster, to ensure that
-    // the change appears on the screen quickly.
-    fastPoll: function() {
-      var missed = false, input = this;
-      input.pollingFast = true;
-      function p() {
-        var changed = input.poll();
-        if (!changed && !missed) {missed = true; input.polling.set(60, p);}
-        else {input.pollingFast = false; input.slowPoll();}
-      }
-      input.polling.set(20, p);
-    },
-
-    // Read input from the textarea, and update the document to match.
-    // When something is selected, it is present in the textarea, and
-    // selected (unless it is huge, in which case a placeholder is
-    // used). When nothing is selected, the cursor sits after previously
-    // seen text (can be empty), which is stored in prevInput (we must
-    // not reset the textarea when typing, because that breaks IME).
-    poll: function() {
-      var cm = this.cm, input = this.textarea, prevInput = this.prevInput;
-      // Since this is called a *lot*, try to bail out as cheaply as
-      // possible when it is clear that nothing happened. hasSelection
-      // will be the case when there is a lot of text in the textarea,
-      // in which case reading its value would be expensive.
-      if (this.contextMenuPending || !cm.state.focused ||
-          (hasSelection(input) && !prevInput && !this.composing) ||
-          isReadOnly(cm) || cm.options.disableInput || cm.state.keySeq)
-        return false;
-
-      var text = input.value;
-      // If nothing changed, bail.
-      if (text == prevInput && !cm.somethingSelected()) return false;
-      // Work around nonsensical selection resetting in IE9/10, and
-      // inexplicable appearance of private area unicode characters on
-      // some key combos in Mac (#2689).
-      if (ie && ie_version >= 9 && this.hasSelection === text ||
-          mac && /[\uf700-\uf7ff]/.test(text)) {
-        cm.display.input.reset();
-        return false;
-      }
-
-      if (cm.doc.sel == cm.display.selForContextMenu) {
-        var first = text.charCodeAt(0);
-        if (first == 0x200b && !prevInput) prevInput = "\u200b";
-        if (first == 0x21da) { this.reset(); return 
this.cm.execCommand("undo"); }
-      }
-      // Find the part of the input that is actually new
-      var same = 0, l = Math.min(prevInput.length, text.length);
-      while (same < l && prevInput.charCodeAt(same) == text.charCodeAt(same)) 
++same;
-
-      var self = this;
-      runInOp(cm, function() {
-        applyTextInput(cm, text.slice(same), prevInput.length - same,
-                       null, self.composing ? "*compose" : null);
-
-        // Don't leave long text in the textarea, since it makes further 
polling slow
-        if (text.length > 1000 || text.indexOf("\n") > -1) input.value = 
self.prevInput = "";
-        else self.prevInput = text;
-
-        if (self.composing) {
-          self.composing.range.clear();
-          self.composing.range = cm.markText(self.composing.start, 
cm.getCursor("to"),
-                                             {className: 
"CodeMirror-composing"});
-        }
-      });
-      return true;
-    },
-
-    ensurePolled: function() {
-      if (this.pollingFast && this.poll()) this.pollingFast = false;
-    },
-
-    onKeyPress: function() {
-      if (ie && ie_version >= 9) this.hasSelection = null;
-      this.fastPoll();
-    },
-
-    onContextMenu: function(e) {
-      var input = this, cm = input.cm, display = cm.display, te = 
input.textarea;
-      var pos = posFromMouse(cm, e), scrollPos = display.scroller.scrollTop;
-      if (!pos || presto) return; // Opera is difficult.
-
-      // Reset the current text selection only if the click is done outside of 
the selection
-      // and 'resetSelectionOnContextMenu' option is true.
-      var reset = cm.options.resetSelectionOnContextMenu;
-      if (reset && cm.doc.sel.contains(pos) == -1)
-        operation(cm, setSelection)(cm.doc, simpleSelection(pos), 
sel_dontScroll);
-
-      var oldCSS = te.style.cssText;
-      input.wrapper.style.position = "absolute";
-      te.style.cssText = "position: fixed; width: 30px; height: 30px; top: " + 
(e.clientY - 5) +
-        "px; left: " + (e.clientX - 5) + "px; z-index: 1000; background: " +
-        (ie ? "rgba(255, 255, 255, .05)" : "transparent") +
-        "; outline: none; border-width: 0; outline: none; overflow: hidden; 
opacity: .05; filter: alpha(opacity=5);";
-      if (webkit) var oldScrollY = window.scrollY; // Work around Chrome issue 
(#2712)
-      display.input.focus();
-      if (webkit) window.scrollTo(null, oldScrollY);
-      display.input.reset();
-      // Adds "Select all" to context menu in FF
-      if (!cm.somethingSelected()) te.value = input.prevInput = " ";
-      input.contextMenuPending = true;
-      display.selForContextMenu = cm.doc.sel;
-      clearTimeout(display.detectingSelectAll);
-
-      // Select-all will be greyed out if there's nothing to select, so
-      // this adds a zero-width space so that we can later check whether
-      // it got selected.
-      function prepareSelectAllHack() {
-        if (te.selectionStart != null) {
-          var selected = cm.somethingSelected();
-          var extval = "\u200b" + (selected ? te.value : "");
-          te.value = "\u21da"; // Used to catch context-menu undo
-          te.value = extval;
-          input.prevInput = selected ? "" : "\u200b";
-          te.selectionStart = 1; te.selectionEnd = extval.length;
-          // Re-set this, in case some other handler touched the
-          // selection in the meantime.
-          display.selForContextMenu = cm.doc.sel;
-        }
-      }
-      function rehide() {
-        input.contextMenuPending = false;
-        input.wrapper.style.position = "relative";
-        te.style.cssText = oldCSS;
-        if (ie && ie_version < 9) 
display.scrollbars.setScrollTop(display.scroller.scrollTop = scrollPos);
-
-        // Try to detect the user choosing select-all
-        if (te.selectionStart != null) {
-          if (!ie || (ie && ie_version < 9)) prepareSelectAllHack();
-          var i = 0, poll = function() {
-            if (display.selForContextMenu == cm.doc.sel && te.selectionStart 
== 0 &&
-                te.selectionEnd > 0 && input.prevInput == "\u200b")
-              operation(cm, commands.selectAll)(cm);
-            else if (i++ < 10) display.detectingSelectAll = setTimeout(poll, 
500);
-            else display.input.reset();
-          };
-          display.detectingSelectAll = setTimeout(poll, 200);
-        }
-      }
-
-      if (ie && ie_version >= 9) prepareSelectAllHack();
-      if (captureRightClick) {
-        e_stop(e);
-        var mouseup = function() {
-          off(window, "mouseup", mouseup);
-          setTimeout(rehide, 20);
-        };
-        on(window, "mouseup", mouseup);
-      } else {
-        setTimeout(rehide, 50);
-      }
-    },
-
-    readOnlyChanged: function(val) {
-      if (!val) this.reset();
-    },
-
-    setUneditable: nothing,
-
-    needsContentAttribute: false
-  }, TextareaInput.prototype);
-
-  // CONTENTEDITABLE INPUT STYLE
-
-  function ContentEditableInput(cm) {
-    this.cm = cm;
-    this.lastAnchorNode = this.lastAnchorOffset = this.lastFocusNode = 
this.lastFocusOffset = null;
-    this.polling = new Delayed();
-    this.gracePeriod = false;
-  }
-
-  ContentEditableInput.prototype = copyObj({
-    init: function(display) {
-      var input = this, cm = input.cm;
-      var div = input.div = display.lineDiv;
-      disableBrowserMagic(div);
-
-      on(div, "paste", function(e) { handlePaste(e, cm); })
-
-      on(div, "compositionstart", function(e) {
-        var data = e.data;
-        input.composing = {sel: cm.doc.sel, data: data, startData: data};
-        if (!data) return;
-        var prim = cm.doc.sel.primary();
-        var line = cm.getLine(prim.head.line);
-        var found = line.indexOf(data, Math.max(0, prim.head.ch - 
data.length));
-        if (found > -1 && found <= prim.head.ch)
-          input.composing.sel = simpleSelection(Pos(prim.head.line, found),
-                                                Pos(prim.head.line, found + 
data.length));
-      });
-      on(div, "compositionupdate", function(e) {
-        input.composing.data = e.data;
-      });
-      on(div, "compositionend", function(e) {
-        var ours = input.composing;
-        if (!ours) return;
-        if (e.data != ours.startData && !/\u200b/.test(e.data))
-          ours.data = e.data;
-        // Need a small delay to prevent other code (input event,
-        // selection polling) from doing damage when fired right after
-        // compositionend.
-        setTimeout(function() {
-          if (!ours.handled)
-            input.applyComposition(ours);
-          if (input.composing == ours)
-            input.composing = null;
-        }, 50);
-      });
-
-      on(div, "touchstart", function() {
-        input.forceCompositionEnd();
-      });
-
-      on(div, "input", function() {
-        if (input.composing) return;
-        if (isReadOnly(cm) || !input.pollContent())
-          runInOp(input.cm, function() {regChange(cm);});
-      });
-
-      function onCopyCut(e) {
-        if (cm.somethingSelected()) {
-          lastCopied = cm.getSelections();
-          if (e.type == "cut") cm.replaceSelection("", null, "cut");
-        } else if (!cm.options.lineWiseCopyCut) {
-          return;
-        } else {
-          var ranges = copyableRanges(cm);
-          lastCopied = ranges.text;
-          if (e.type == "cut") {
-            cm.operation(function() {
-              cm.setSelections(ranges.ranges, 0, sel_dontScroll);
-              cm.replaceSelection("", null, "cut");
-            });
-          }
-        }
-        // iOS exposes the clipboard API, but seems to discard content 
inserted into it
-        if (e.clipboardData && !ios) {
-          e.preventDefault();
-          e.clipboardData.clearData();
-          e.clipboardData.setData("text/plain", lastCopied.join("\n"));
-        } else {
-          // Old-fashioned briefly-focus-a-textarea hack
-          var kludge = hiddenTextarea(), te = kludge.firstChild;
-          cm.display.lineSpace.insertBefore(kludge, 
cm.display.lineSpace.firstChild);
-          te.value = lastCopied.join("\n");
-          var hadFocus = document.activeElement;
-          selectInput(te);
-          setTimeout(function() {
-            cm.display.lineSpace.removeChild(kludge);
-            hadFocus.focus();
-          }, 50);
-        }
-      }
-      on(div, "copy", onCopyCut);
-      on(div, "cut", onCopyCut);
-    },
-
-    prepareSelection: function() {
-      var result = prepareSelection(this.cm, false);
-      result.focus = this.cm.state.focused;
-      return result;
-    },
-
-    showSelection: function(info) {
-      if (!info || !this.cm.display.view.length) return;
-      if (info.focus) this.showPrimarySelection();
-      this.showMultipleSelections(info);
-    },
-
-    showPrimarySelection: function() {
-      var sel = window.getSelection(), prim = this.cm.doc.sel.primary();
-      var curAnchor = domToPos(this.cm, sel.anchorNode, sel.anchorOffset);
-      var curFocus = domToPos(this.cm, sel.focusNode, sel.focusOffset);
-      if (curAnchor && !curAnchor.bad && curFocus && !curFocus.bad &&
-          cmp(minPos(curAnchor, curFocus), prim.from()) == 0 &&
-          cmp(maxPos(curAnchor, curFocus), prim.to()) == 0)
-        return;
-
-      var start = posToDOM(this.cm, prim.from());
-      var end = posToDOM(this.cm, prim.to());
-      if (!start && !end) return;
-
-      var view = this.cm.display.view;
-      var old = sel.rangeCount && sel.getRangeAt(0);
-      if (!start) {
-        start = {node: view[0].measure.map[2], offset: 0};
-      } else if (!end) { // FIXME dangerously hacky
-        var measure = view[view.length - 1].measure;
-        var map = measure.maps ? measure.maps[measure.maps.length - 1] : 
measure.map;
-        end = {node: map[map.length - 1], offset: map[map.length - 2] - 
map[map.length - 3]};
-      }
-
-      try { var rng = range(start.node, start.offset, end.offset, end.node); }
-      catch(e) {} // Our model of the DOM might be outdated, in which case the 
range we try to set can be impossible
-      if (rng) {
-        sel.removeAllRanges();
-        sel.addRange(rng);
-        if (old && sel.anchorNode == null) sel.addRange(old);
-        else if (gecko) this.startGracePeriod();
-      }
-      this.rememberSelection();
-    },
-
-    startGracePeriod: function() {
-      var input = this;
-      clearTimeout(this.gracePeriod);
-      this.gracePeriod = setTimeout(function() {
-        input.gracePeriod = false;
-        if (input.selectionChanged())
-          input.cm.operation(function() { input.cm.curOp.selectionChanged = 
true; });
-      }, 20);
-    },
-
-    showMultipleSelections: function(info) {
-      removeChildrenAndAdd(this.cm.display.cursorDiv, info.cursors);
-      removeChildrenAndAdd(this.cm.display.selectionDiv, info.selection);
-    },
-
-    rememberSelection: function() {
-      var sel = window.getSelection();
-      this.lastAnchorNode = sel.anchorNode; this.lastAnchorOffset = 
sel.anchorOffset;
-      this.lastFocusNode = sel.focusNode; this.lastFocusOffset = 
sel.focusOffset;
-    },
-
-    selectionInEditor: function() {
-      var sel = window.getSelection();
-      if (!sel.rangeCount) return false;
-      var node = sel.getRangeAt(0).commonAncestorContainer;
-      return contains(this.div, node);
-    },
-
-    focus: function() {
-      if (this.cm.options.readOnly != "nocursor") this.div.focus();
-    },
-    blur: function() { this.div.blur(); },
-    getField: function() { return this.div; },
-
-    supportsTouch: function() { return true; },
-
-    receivedFocus: function() {
-      var input = this;
-      if (this.selectionInEditor())
-        this.pollSelection();
-      else
-        runInOp(this.cm, function() { input.cm.curOp.selectionChanged = true; 
});
-
-      function poll() {
-        if (input.cm.state.focused) {
-          input.pollSelection();
-          input.polling.set(input.cm.options.pollInterval, poll);
-        }
-      }
-      this.polling.set(this.cm.options.pollInterval, poll);
-    },
-
-    selectionChanged: function() {
-      var sel = window.getSelection();
-      return sel.anchorNode != this.lastAnchorNode || sel.anchorOffset != 
this.lastAnchorOffset ||
-        sel.focusNode != this.lastFocusNode || sel.focusOffset != 
this.lastFocusOffset;
-    },
-
-    pollSelection: function() {
-      if (!this.composing && !this.gracePeriod && this.selectionChanged()) {
-        var sel = window.getSelection(), cm = this.cm;
-        this.rememberSelection();
-        var anchor = domToPos(cm, sel.anchorNode, sel.anchorOffset);
-        var head = domToPos(cm, sel.focusNode, sel.focusOffset);
-        if (anchor && head) runInOp(cm, function() {
-          setSelection(cm.doc, simpleSelection(anchor, head), sel_dontScroll);
-          if (anchor.bad || head.bad) cm.curOp.selectionChanged = true;
-        });
-      }
-    },
-
-    pollContent: function() {
-      var cm = this.cm, display = cm.display, sel = cm.doc.sel.primary();
-      var from = sel.from(), to = sel.to();
-      if (from.line < display.viewFrom || to.line > display.viewTo - 1) return 
false;
-
-      var fromIndex;
-      if (from.line == display.viewFrom || (fromIndex = findViewIndex(cm, 
from.line)) == 0) {
-        var fromLine = lineNo(display.view[0].line);
-        var fromNode = display.view[0].node;
-      } else {
-        var fromLine = lineNo(display.view[fromIndex].line);
-        var fromNode = display.view[fromIndex - 1].node.nextSibling;
-      }
-      var toIndex = findViewIndex(cm, to.line);
-      if (toIndex == display.view.length - 1) {
-        var toLine = display.viewTo - 1;
-        var toNode = display.lineDiv.lastChild;
-      } else {
-        var toLine = lineNo(display.view[toIndex + 1].line) - 1;
-        var toNode = display.view[toIndex + 1].node.previousSibling;
-      }
-
-      var newText = cm.doc.splitLines(domTextBetween(cm, fromNode, toNode, 
fromLine, toLine));
-      var oldText = getBetween(cm.doc, Pos(fromLine, 0), Pos(toLine, 
getLine(cm.doc, toLine).text.length));
-      while (newText.length > 1 && oldText.length > 1) {
-        if (lst(newText) == lst(oldText)) { newText.pop(); oldText.pop(); 
toLine--; }
-        else if (newText[0] == oldText[0]) { newText.shift(); oldText.shift(); 
fromLine++; }
-        else break;
-      }
-
-      var cutFront = 0, cutEnd = 0;
-      var newTop = newText[0], oldTop = oldText[0], maxCutFront = 
Math.min(newTop.length, oldTop.length);
-      while (cutFront < maxCutFront && newTop.charCodeAt(cutFront) == 
oldTop.charCodeAt(cutFront))
-        ++cutFront;
-      var newBot = lst(newText), oldBot = lst(oldText);
-      var maxCutEnd = Math.min(newBot.length - (newText.length == 1 ? cutFront 
: 0),
-                               oldBot.length - (oldText.length == 1 ? cutFront 
: 0));
-      while (cutEnd < maxCutEnd &&
-             newBot.charCodeAt(newBot.length - cutEnd - 1) == 
oldBot.charCodeAt(oldBot.length - cutEnd - 1))
-        ++cutEnd;
-
-      newText[newText.length - 1] = newBot.slice(0, newBot.length - cutEnd);
-      newText[0] = newText[0].slice(cutFront);
-
-      var chFrom = Pos(fromLine, cutFront);
-      var chTo = Pos(toLine, oldText.length ? lst(oldText).length - cutEnd : 
0);
-      if (newText.length > 1 || newText[0] || cmp(chFrom, chTo)) {
-        replaceRange(cm.doc, newText, chFrom, chTo, "+input");
-        return true;
-      }
-    },
-
-    ensurePolled: function() {
-      this.forceCompositionEnd();
-    },
-    reset: function() {
-      this.forceCompositionEnd();
-    },
-    forceCompositionEnd: function() {
-      if (!this.composing || this.composing.handled) return;
-      this.applyComposition(this.composing);
-      this.composing.handled = true;
-      this.div.blur();
-      this.div.focus();
-    },
-    applyComposition: function(composing) {
-      if (isReadOnly(this.cm))
-        operation(this.cm, regChange)(this.cm)
-      else if (composing.data && composing.data != composing.startData)
-        operation(this.cm, applyTextInput)(this.cm, composing.data, 0, 
composing.sel);
-    },
-
-    setUneditable: function(node) {
-      node.contentEditable = "false"
-    },
-
-    onKeyPress: function(e) {
-      e.preventDefault();
-      if (!isReadOnly(this.cm))
-        operation(this.cm, applyTextInput)(this.cm, 
String.fromCharCode(e.charCode == null ? e.keyCode : e.charCode), 0);
-    },
-
-    readOnlyChanged: function(val) {
-      this.div.contentEditable = String(val != "nocursor")
-    },
-
-    onContextMenu: nothing,
-    resetPosition: nothing,
-
-    needsContentAttribute: true
-  }, ContentEditableInput.prototype);
-
-  function posToDOM(cm, pos) {
-    var view = findViewForLine(cm, pos.line);
-    if (!view || view.hidden) return null;
-    var line = getLine(cm.doc, pos.line);
-    var info = mapFromLineView(view, line, pos.line);
-
-    var order = getOrder(line), side = "left";
-    if (order) {
-      var partPos = getBidiPartAt(order, pos.ch);
-      side = partPos % 2 ? "right" : "left";
-    }
-    var result = nodeAndOffsetInLineMap(info.map, pos.ch, side);
-    result.offset = result.collapse == "right" ? result.end : result.start;
-    return result;
-  }
-
-  function badPos(pos, bad) { if (bad) pos.bad = true; return pos; }
-
-  function domToPos(cm, node, offset) {
-    var lineNode;
-    if (node == cm.display.lineDiv) {
-      lineNode = cm.display.lineDiv.childNodes[offset];
-      if (!lineNode) return badPos(cm.clipPos(Pos(cm.display.viewTo - 1)), 
true);
-      node = null; offset = 0;
-    } else {
-      for (lineNode = node;; lineNode = lineNode.parentNode) {
-        if (!lineNode || lineNode == cm.display.lineDiv) return null;
-        if (lineNode.parentNode && lineNode.parentNode == cm.display.lineDiv) 
break;
-      }
-    }
-    for (var i = 0; i < cm.display.view.length; i++) {
-      var lineView = cm.display.view[i];
-      if (lineView.node == lineNode)
-        return locateNodeInLineView(lineView, node, offset);
-    }
-  }
-
-  function locateNodeInLineView(lineView, node, offset) {
-    var wrapper = lineView.text.firstChild, bad = false;
-    if (!node || !contains(wrapper, node)) return 
badPos(Pos(lineNo(lineView.line), 0), true);
-    if (node == wrapper) {
-      bad = true;
-      node = wrapper.childNodes[offset];
-      offset = 0;
-      if (!node) {
-        var line = lineView.rest ? lst(lineView.rest) : lineView.line;
-        return badPos(Pos(lineNo(line), line.text.length), bad);
-      }
-    }
-
-    var textNode = node.nodeType == 3 ? node : null, topNode = node;
-    if (!textNode && node.childNodes.length == 1 && node.firstChild.nodeType 
== 3) {
-      textNode = node.firstChild;
-      if (offset) offset = textNode.nodeValue.length;
-    }
-    while (topNode.parentNode != wrapper) topNode = topNode.parentNode;
-    var measure = lineView.measure, maps = measure.maps;
-
-    function find(textNode, topNode, offset) {
-      for (var i = -1; i < (maps ? maps.length : 0); i++) {
-        var map = i < 0 ? measure.map : maps[i];
-        for (var j = 0; j < map.length; j += 3) {
-          var curNode = map[j + 2];
-          if (curNode == textNode || curNode == topNode) {
-            var line = lineNo(i < 0 ? lineView.line : lineView.rest[i]);
-            var ch = map[j] + offset;
-            if (offset < 0 || curNode != textNode) ch = map[j + (offset ? 1 : 
0)];
-            return Pos(line, ch);
-          }
-        }
-      }
-    }
-    var found = find(textNode, topNode, offset);
-    if (found) return badPos(found, bad);
-
-    // FIXME this is all really shaky. might handle the few cases it needs to 
handle, but likely to cause problems
-    for (var after = topNode.nextSibling, dist = textNode ? 
textNode.nodeValue.length - offset : 0; after; after = after.nextSibling) {
-      found = find(after, after.firstChild, 0);
-      if (found)
-        return badPos(Pos(found.line, found.ch - dist), bad);
-      else
-        dist += after.textContent.length;
-    }
-    for (var before = topNode.previousSibling, dist = offset; before; before = 
before.previousSibling) {
-      found = find(before, before.firstChild, -1);
-      if (found)
-        return badPos(Pos(found.line, found.ch + dist), bad);
-      else
-        dist += after.textContent.length;
-    }
-  }
-
-  function domTextBetween(cm, from, to, fromLine, toLine) {
-    var text = "", closing = false, lineSep = cm.doc.lineSeparator();
-    function recognizeMarker(id) { return function(marker) { return marker.id 
== id; }; }
-    function walk(node) {
-      if (node.nodeType == 1) {
-        var cmText = node.getAttribute("cm-text");
-        if (cmText != null) {
-          if (cmText == "") cmText = node.textContent.replace(/\u200b/g, "");
-          text += cmText;
-          return;
-        }
-        var markerID = node.getAttribute("cm-marker"), range;
-        if (markerID) {
-          var found = cm.findMarks(Pos(fromLine, 0), Pos(toLine + 1, 0), 
recognizeMarker(+markerID));
-          if (found.length && (range = found[0].find()))
-            text += getBetween(cm.doc, range.from, range.to).join(lineSep);
-          return;
-        }
-        if (node.getAttribute("contenteditable") == "false") return;
-        for (var i = 0; i < node.childNodes.length; i++)
-          walk(node.childNodes[i]);
-        if (/^(pre|div|p)$/i.test(node.nodeName))
-          closing = true;
-      } else if (node.nodeType == 3) {
-        var val = node.nodeValue;
-        if (!val) return;
-        if (closing) {
-          text += lineSep;
-          closing = false;
-        }
-        text += val;
-      }
-    }
-    for (;;) {
-      walk(from);
-      if (from == to) break;
-      from = from.nextSibling;
-    }
-    return text;
-  }
-
-  CodeMirror.inputStyles = {"textarea": TextareaInput, "contenteditable": 
ContentEditableInput};
-
-  // SELECTION / CURSOR
-
-  // Selection objects are immutable. A new one is created every time
-  // the selection changes. A selection is one or more non-overlapping
-  // (and non-touching) ranges, sorted, and an integer that indicates
-  // which one is the primary selection (the one that's scrolled into
-  // view, that getCursor returns, etc).
-  function Selection(ranges, primIndex) {
-    this.ranges = ranges;
-    this.primIndex = primIndex;
-  }
-
-  Selection.prototype = {
-    primary: function() { return this.ranges[this.primIndex]; },
-    equals: function(other) {
-      if (other == this) return true;
-      if (other.primIndex != this.primIndex || other.ranges.length != 
this.ranges.length) return false;
-      for (var i = 0; i < this.ranges.length; i++) {
-        var here = this.ranges[i], there = other.ranges[i];
-        if (cmp(here.anchor, there.anchor) != 0 || cmp(here.head, there.head) 
!= 0) return false;
-      }
-      return true;
-    },
-    deepCopy: function() {
-      for (var out = [], i = 0; i < this.ranges.length; i++)
-        out[i] = new Range(copyPos(this.ranges[i].anchor), 
copyPos(this.ranges[i].head));
-      return new Selection(out, this.primIndex);
-    },
-    somethingSelected: function() {
-      for (var i = 0; i < this.ranges.length; i++)
-        if (!this.ranges[i].empty()) return true;
-      return false;
-    },
-    contains: function(pos, end) {
-      if (!end) end = pos;
-      for (var i = 0; i < this.ranges.length; i++) {
-        var range = this.ranges[i];
-        if (cmp(end, range.from()) >= 0 && cmp(pos, range.to()) <= 0)
-          return i;
-      }
-      return -1;
-    }
-  };
-
-  function Range(anchor, head) {
-    this.anchor = anchor; this.head = head;
-  }
-
-  Range.prototype = {
-    from: function() { return minPos(this.anchor, this.head); },
-    to: function() { return maxPos(this.anchor, this.head); },
-    empty: function() {
-      return this.head.line == this.anchor.line && this.head.ch == 
this.anchor.ch;
-    }
-  };
-
-  // Take an unsorted, potentially overlapping set of ranges, and
-  // build a selection out of it. 'Consumes' ranges array (modifying
-  // it).
-  function normalizeSelection(ranges, primIndex) {
-    var prim = ranges[primIndex];
-    ranges.sort(function(a, b) { return cmp(a.from(), b.from()); });
-    primIndex = indexOf(ranges, prim);
-    for (var i = 1; i < ranges.length; i++) {
-      var cur = ranges[i], prev = ranges[i - 1];
-      if (cmp(prev.to(), cur.from()) >= 0) {
-        var from = minPos(prev.from(), cur.from()), to = maxPos(prev.to(), 
cur.to());
-        var inv = prev.empty() ? cur.from() == cur.head : prev.from() == 
prev.head;
-        if (i <= primIndex) --primIndex;
-        ranges.splice(--i, 2, new Range(inv ? to : from, inv ? from : to));
-      }
-    }
-    return new Selection(ranges, primIndex);
-  }
-
-  function simpleSelection(anchor, head) {
-    return new Selection([new Range(anchor, head || anchor)], 0);
-  }
-
-  // Most of the external API clips given positions to make sure they
-  // actually exist within the document.
-  function clipLine(doc, n) {return Math.max(doc.first, Math.min(n, doc.first 
+ doc.size - 1));}
-  function clipPos(doc, pos) {
-    if (pos.line < doc.first) return Pos(doc.first, 0);
-    var last = doc.first + doc.size - 1;
-    if (pos.line > last) return Pos(last, getLine(doc, last).text.length);
-    return clipToLen(pos, getLine(doc, pos.line).text.length);
-  }
-  function clipToLen(pos, linelen) {
-    var ch = pos.ch;
-    if (ch == null || ch > linelen) return Pos(pos.line, linelen);
-    else if (ch < 0) return Pos(pos.line, 0);
-    else return pos;
-  }
-  function isLine(doc, l) {return l >= doc.first && l < doc.first + doc.size;}
-  function clipPosArray(doc, array) {
-    for (var out = [], i = 0; i < array.length; i++) out[i] = clipPos(doc, 
array[i]);
-    return out;
-  }
-
-  // SELECTION UPDATES
-
-  // The 'scroll' parameter given to many of these indicated whether
-  // the new cursor position should be scrolled into view after
-  // modifying the selection.
-
-  // If shift is held or the extend flag is set, extends a range to
-  // include a given position (and optionally a second position).
-  // Otherwise, simply returns the range between the given positions.
-  // Used for cursor motion and such.
-  function extendRange(doc, range, head, other) {
-    if (doc.cm && doc.cm.display.shift || doc.extend) {
-      var anchor = range.anchor;
-      if (other) {
-        var posBefore = cmp(head, anchor) < 0;
-        if (posBefore != (cmp(other, anchor) < 0)) {
-          anchor = head;
-          head = other;
-        } else if (posBefore != (cmp(head, other) < 0)) {
-          head = other;
-        }
-      }
-      return new Range(anchor, head);
-    } else {
-      return new Range(other || head, head);
-    }
-  }
-
-  // Extend the primary selection range, discard the rest.
-  function extendSelection(doc, head, other, options) {
-    setSelection(doc, new Selection([extendRange(doc, doc.sel.primary(), head, 
other)], 0), options);
-  }
-
-  // Extend all selections (pos is an array of selections with length
-  // equal the number of selections)
-  function extendSelections(doc, heads, options) {
-    for (var out = [], i = 0; i < doc.sel.ranges.length; i++)
-      out[i] = extendRange(doc, doc.sel.ranges[i], heads[i], null);
-    var newSel = normalizeSelection(out, doc.sel.primIndex);
-    setSelection(doc, newSel, options);
-  }
-
-  // Updates a single range in the selection.
-  function replaceOneSelection(doc, i, range, options) {
-    var ranges = doc.sel.ranges.slice(0);
-    ranges[i] = range;
-    setSelection(doc, normalizeSelection(ranges, doc.sel.primIndex), options);
-  }
-
-  // Reset the selection to a single range.
-  function setSimpleSelection(doc, anchor, head, options) {
-    setSelection(doc, simpleSelection(anchor, head), options);
-  }
-
-  // Give beforeSelectionChange handlers a change to influence a
-  // selection update.
-  function filterSelectionChange(doc, sel) {
-    var obj = {
-      ranges: sel.ranges,
-      update: function(ranges) {
-        this.ranges = [];
-        for (var i = 0; i < ranges.length; i++)
-          this.ranges[i] = new Range(clipPos(doc, ranges[i].anchor),
-                                     clipPos(doc, ranges[i].head));
-      }
-    };
-    signal(doc, "beforeSelectionChange", doc, obj);
-    if (doc.cm) signal(doc.cm, "beforeSelectionChange", doc.cm, obj);
-    if (obj.ranges != sel.ranges) return normalizeSelection(obj.ranges, 
obj.ranges.length - 1);
-    else return sel;
-  }
-
-  function setSelectionReplaceHistory(doc, sel, options) {
-    var done = doc.history.done, last = lst(done);
-    if (last && last.ranges) {
-      done[done.length - 1] = sel;
-      setSelectionNoUndo(doc, sel, options);
-    } else {
-      setSelection(doc, sel, options);
-    }
-  }
-
-  // Set a new selection.
-  function setSelection(doc, sel, options) {
-    setSelectionNoUndo(doc, sel, options);
-    addSelectionToHistory(doc, doc.sel, doc.cm ? doc.cm.curOp.id : NaN, 
options);
-  }
-
-  function setSelectionNoUndo(doc, sel, options) {
-    if (hasHandler(doc, "beforeSelectionChange") || doc.cm && 
hasHandler(doc.cm, "beforeSelectionChange"))
-      sel = filterSelectionChange(doc, sel);
-
-    var bias = options && options.bias ||
-      (cmp(sel.primary().head, doc.sel.primary().head) < 0 ? -1 : 1);
-    setSelectionInner(doc, skipAtomicInSelection(doc, sel, bias, true));
-
-    if (!(options && options.scroll === false) && doc.cm)
-      ensureCursorVisible(doc.cm);
-  }
-
-  function setSelectionInner(doc, sel) {
-    if (sel.equals(doc.sel)) return;
-
-    doc.sel = sel;
-
-    if (doc.cm) {
-      doc.cm.curOp.updateInput = doc.cm.curOp.selectionChanged = true;
-      signalCursorActivity(doc.cm);
-    }
-    signalLater(doc, "cursorActivity", doc);
-  }
-
-  // Verify that the selection does not partially select any atomic
-  // marked ranges.
-  function reCheckSelection(doc) {
-    setSelectionInner(doc, skipAtomicInSelection(doc, doc.sel, null, false), 
sel_dontScroll);
-  }
-
-  // Return a selection that does not partially select any atomic
-  // ranges.
-  function skipA

<TRUNCATED>

Reply via email to