acorn
Version:
ECMAScript parser
1,071 lines • 172 kB
JavaScript
codemirror30 = "// All functions that need access to the editor's state live inside\n\
// the CodeMirror function. Below that, at the bottom of the file,\n\
// some utilities are defined.\n\
\n\
// CodeMirror is the only global var we claim\n\
window.CodeMirror = (function() {\n\
\"use strict\";\n\
\n\
// BROWSER SNIFFING\n\
\n\
// Crude, but necessary to handle a number of hard-to-feature-detect\n\
// bugs and behavior differences.\n\
var gecko = /gecko\\/\\d{7}/i.test(navigator.userAgent);\n\
var ie = /MSIE \\d/.test(navigator.userAgent);\n\
var ie_lt8 = /MSIE [1-7]\\b/.test(navigator.userAgent);\n\
var ie_lt9 = /MSIE [1-8]\\b/.test(navigator.userAgent);\n\
var webkit = /WebKit\\//.test(navigator.userAgent);\n\
var chrome = /Chrome\\//.test(navigator.userAgent);\n\
var opera = /Opera\\//.test(navigator.userAgent);\n\
var safari = /Apple Computer/.test(navigator.vendor);\n\
var khtml = /KHTML\\//.test(navigator.userAgent);\n\
var mac_geLion = /Mac OS X 10\\D([7-9]|\\d\\d)\\D/.test(navigator.userAgent);\n\
\n\
var ios = /AppleWebKit/.test(navigator.userAgent) && /Mobile\\/\\w+/.test(navigator.userAgent);\n\
var mac = ios || /Mac/.test(navigator.platform);\n\
var win = /Win/.test(navigator.platform);\n\
\n\
// CONSTRUCTOR\n\
\n\
function CodeMirror(place, options) {\n\
if (!(this instanceof CodeMirror)) return new CodeMirror(place, options, true);\n\
\n\
this.options = options = options || {};\n\
// Determine effective options based on given values and defaults.\n\
for (var opt in defaults) if (!options.hasOwnProperty(opt) && defaults.hasOwnProperty(opt))\n\
options[opt] = defaults[opt];\n\
setGuttersForLineNumbers(options);\n\
\n\
var display = this.display = makeDisplay(place);\n\
display.wrapper.CodeMirror = this;\n\
updateGutters(this);\n\
themeChanged(this);\n\
keyMapChanged(this);\n\
if (options.tabindex != null) display.input.tabIndex = options.tabindex;\n\
if (options.autofocus) focusInput(this);\n\
if (options.lineWrapping) display.wrapper.className += \" CodeMirror-wrap\";\n\
\n\
var doc = new BranchChunk([new LeafChunk([new Line(\"\", null, textHeight(display))])]);\n\
// frontier is the point up to which the content has been parsed,\n\
doc.frontier = 0;\n\
doc.highlight = new Delayed();\n\
doc.tabSize = options.tabSize;\n\
// The selection. These are always maintained to point at valid\n\
// positions. Inverted is used to remember that the user is\n\
// selecting bottom-to-top.\n\
this.view = {\n\
doc: doc,\n\
sel: {from: {line: 0, ch: 0}, to: {line: 0, ch: 0}, inverted: false, shift: false},\n\
scrollTop: 0, scrollLeft: 0,\n\
overwrite: false, focused: false,\n\
// Tracks the maximum line length so that\n\
// the horizontal scrollbar can be kept\n\
// static when scrolling.\n\
maxLine: getLine(doc, 0),\n\
maxLineChanged: false,\n\
suppressEdits: false,\n\
goalColumn: null\n\
};\n\
loadMode(this);\n\
\n\
// Initialize the content.\n\
this.setValue(options.value || \"\");\n\
doc.history = new History();\n\
\n\
registerEventHandlers(this);\n\
// IE throws unspecified error in certain cases, when\n\
// trying to access activeElement before onload\n\
var hasFocus; try { hasFocus = (document.activeElement == display.input); } catch(e) { }\n\
if (hasFocus || options.autofocus) setTimeout(bind(onFocus, this), 20);\n\
else onBlur(this);\n\
\n\
for (var opt in optionHandlers)\n\
if (optionHandlers.propertyIsEnumerable(opt))\n\
optionHandlers[opt](this, options[opt]);\n\
}\n\
\n\
// DISPLAY CONSTRUCTOR\n\
\n\
function makeDisplay(place) {\n\
var d = {};\n\
var input = d.input = elt(\"textarea\", null, null, \"position: absolute; padding: 0; width: 1px; height: 1em; outline: none;\");\n\
input.setAttribute(\"wrap\", \"off\"); input.setAttribute(\"autocorrect\", \"off\"); input.setAttribute(\"autocapitalize\", \"off\");\n\
// Wraps and hides input textarea\n\
d.inputDiv = elt(\"div\", [input], null, \"overflow: hidden; position: relative; width: 3px; height: 0px;\");\n\
// The actual fake scrollbars.\n\
d.scrollbarH = elt(\"div\", [elt(\"div\", null, null, \"height: 1px\")], \"CodeMirror-hscrollbar\");\n\
d.scrollbarV = elt(\"div\", [elt(\"div\", null, null, \"width: 1px\")], \"CodeMirror-vscrollbar\");\n\
d.scrollbarFiller = elt(\"div\", null, \"CodeMirror-scrollbar-filler\");\n\
// DIVs containing the selection and the actual code\n\
d.lineDiv = elt(\"div\");\n\
d.selectionDiv = elt(\"div\", null, null, \"position: relative; z-index: 1\");\n\
// Blinky cursor, and element used to ensure cursor fits at the end of a line\n\
d.cursor = elt(\"pre\", \"\\u00a0\", \"CodeMirror-cursor\");\n\
// Secondary cursor, shown when on a 'jump' in bi-directional text\n\
d.otherCursor = elt(\"pre\", \"\\u00a0\", \"CodeMirror-cursor CodeMirror-secondarycursor\");\n\
// Used to measure text size\n\
d.measure = elt(\"div\", null, \"CodeMirror-measure\");\n\
// Wraps everything that needs to exist inside the vertically-padded coordinate system\n\
d.lineSpace = elt(\"div\", [d.measure, d.cursor, d.otherCursor, d.selectionDiv, d.lineDiv],\n\
null, \"position: relative; outline: none\");\n\
// Moved around its parent to cover visible view\n\
d.mover = elt(\"div\", [elt(\"div\", [d.lineSpace], \"CodeMirror-lines\")], null, \"position: relative\");\n\
d.gutters = elt(\"div\", null, \"CodeMirror-gutters\");\n\
d.lineGutter = null;\n\
// Set to the height of the text, causes scrolling\n\
d.sizer = elt(\"div\", [d.mover], \"CodeMirror-sizer\");\n\
// D is needed because behavior of elts with overflow: auto and padding is inconsistent across browsers\n\
d.heightForcer = elt(\"div\", \"\\u00a0\", null, \"position: absolute; height: \" + scrollerCutOff + \"px\");\n\
// Provides scrolling\n\
d.scroller = elt(\"div\", [d.sizer, d.heightForcer], \"CodeMirror-scroll\");\n\
d.scroller.setAttribute(\"tabIndex\", \"-1\");\n\
// The element in which the editor lives.\n\
d.wrapper = elt(\"div\", [d.gutters, d.inputDiv, d.scrollbarH, d.scrollbarV,\n\
d.scrollbarFiller, d.scroller], \"CodeMirror\");\n\
// Work around IE7 z-index bug\n\
if (ie_lt8) { d.gutters.style.zIndex = -1; d.scroller.style.paddingRight = 0; }\n\
if (place.appendChild) place.appendChild(d.wrapper); else place(d.wrapper);\n\
\n\
// Needed to hide big blue blinking cursor on Mobile Safari\n\
if (ios) input.style.width = \"0px\";\n\
if (!webkit) d.scroller.draggable = true;\n\
// Needed to handle Tab key in KHTML\n\
if (khtml) { d.inputDiv.style.height = \"1px\"; d.inputDiv.style.position = \"absolute\"; }\n\
// Need to set a minimum width to see the scrollbar on IE7 (but must not set it on IE8).\n\
else if (ie_lt8) d.scrollbarH.style.minWidth = d.scrollbarV.style.minWidth = \"18px\";\n\
\n\
// Current visible range (may be bigger than the view window).\n\
d.viewOffset = d.showingFrom = d.showingTo = d.lastSizeC = 0;\n\
\n\
// Used to only resize the line number gutter when necessary (when\n\
// the amount of lines crosses a boundary that makes its width change)\n\
d.lineNumWidth = d.lineNumChars = null;\n\
// See readInput and resetInput\n\
d.prevInput = \"\";\n\
// Set to true when a non-horizontal-scrolling widget is added. As\n\
// an optimization, widget aligning is skipped when d is false.\n\
d.alignWidgets = false;\n\
// Flag that indicates whether we currently expect input to appear\n\
// (after some event like 'keypress' or 'input') and are polling\n\
// intensively.\n\
d.pollingFast = false;\n\
// Self-resetting timeout for the poller\n\
d.poll = new Delayed();\n\
// True when a drag from the editor is active\n\
d.draggingText = false;\n\
\n\
d.cachedCharWidth = d.cachedTextHeight = null;\n\
d.measureLineCache = [];\n\
d.measureLineCache.pos = 0;\n\
\n\
// Tracks when resetInput has punted to just putting a short\n\
// string instead of the (large) selection.\n\
d.inaccurateSelection = false;\n\
\n\
return d;\n\
}\n\
\n\
// STATE UPDATES\n\
\n\
// Used to get the editor into a consistent state again when options change.\n\
\n\
function loadMode(cm) {\n\
var doc = cm.view.doc;\n\
doc.mode = CodeMirror.getMode(cm.options, cm.options.mode);\n\
doc.iter(0, doc.size, function(line) { line.stateAfter = null; });\n\
doc.frontier = 0;\n\
startWorker(cm, 100);\n\
}\n\
\n\
function wrappingChanged(cm) {\n\
var doc = cm.view.doc;\n\
if (cm.options.lineWrapping) {\n\
cm.display.wrapper.className += \" CodeMirror-wrap\";\n\
var perLine = cm.display.wrapper.clientWidth / charWidth(cm.display) - 3;\n\
doc.iter(0, doc.size, function(line) {\n\
if (line.hidden) return;\n\
var guess = Math.ceil(line.text.length / perLine) || 1;\n\
if (guess != 1) updateLineHeight(line, guess);\n\
});\n\
cm.display.sizer.style.minWidth = \"\";\n\
} else {\n\
cm.display.wrapper.className = cm.display.wrapper.className.replace(\" CodeMirror-wrap\", \"\");\n\
computeMaxLength(cm.view);\n\
doc.iter(0, doc.size, function(line) {\n\
if (line.height != 1 && !line.hidden) updateLineHeight(line, 1);\n\
});\n\
}\n\
regChange(cm, 0, doc.size);\n\
}\n\
\n\
function keyMapChanged(cm) {\n\
var style = keyMap[cm.options.keyMap].style;\n\
cm.display.wrapper.className = cm.display.wrapper.className.replace(/\\s*cm-keymap-\\S+/g, \"\") +\n\
(style ? \" cm-keymap-\" + style : \"\");\n\
}\n\
\n\
function themeChanged(cm) {\n\
cm.display.wrapper.className = cm.display.wrapper.className.replace(/\\s*cm-s-\\S+/g, \"\") +\n\
cm.options.theme.replace(/(^|\\s)\\s*/g, \" cm-s-\");\n\
}\n\
\n\
function guttersChanged(cm) {\n\
updateGutters(cm);\n\
updateDisplay(cm, true);\n\
}\n\
\n\
function updateGutters(cm) {\n\
var gutters = cm.display.gutters, specs = cm.options.gutters;\n\
removeChildren(gutters);\n\
for (var i = 0; i < specs.length; ++i) {\n\
var gutterClass = specs[i];\n\
var gElt = gutters.appendChild(elt(\"div\", null, \"CodeMirror-gutter \" + gutterClass));\n\
if (gutterClass == \"CodeMirror-linenumbers\") {\n\
cm.display.lineGutter = gElt;\n\
gElt.style.width = (cm.display.lineNumWidth || 1) + \"px\";\n\
}\n\
}\n\
gutters.style.display = i ? \"\" : \"none\";\n\
}\n\
\n\
function computeMaxLength(view) {\n\
view.maxLine = getLine(view.doc, 0); view.maxLineChanged = true;\n\
var maxLineLength = view.maxLine.text.length;\n\
view.doc.iter(1, view.doc.size, function(line) {\n\
var l = line.text;\n\
if (!line.hidden && l.length > maxLineLength) {\n\
maxLineLength = l.length; view.maxLine = line;\n\
}\n\
});\n\
}\n\
\n\
// Make sure the gutters options contains the element\n\
// \"CodeMirror-linenumbers\" when the lineNumbers option is true.\n\
function setGuttersForLineNumbers(options) {\n\
var found = false;\n\
for (var i = 0; i < options.gutters.length; ++i) {\n\
if (options.gutters[i] == \"CodeMirror-linenumbers\") {\n\
if (options.lineNumbers) found = true;\n\
else options.gutters.splice(i--, 1);\n\
}\n\
}\n\
if (!found && options.lineNumbers)\n\
options.gutters.push(\"CodeMirror-linenumbers\");\n\
}\n\
\n\
// SCROLLBARS\n\
\n\
// Re-synchronize the fake scrollbars with the actual size of the\n\
// content. Optionally force a scrollTop.\n\
function updateScrollbars(d /* display */, docHeight, scrollTop) {\n\
d.sizer.style.minHeight = d.heightForcer.style.top = (docHeight + 2 * paddingTop(d)) + \"px\";\n\
var needsH = d.scroller.scrollWidth > d.scroller.clientWidth;\n\
var needsV = d.scroller.scrollHeight > d.scroller.clientHeight;\n\
if (needsV) {\n\
d.scrollbarV.style.display = \"block\";\n\
d.scrollbarV.style.bottom = needsH ? scrollbarWidth(d.measure) + \"px\" : \"0\";\n\
d.scrollbarV.firstChild.style.height = \n\
(d.scroller.scrollHeight - d.scroller.clientHeight + d.scrollbarV.clientHeight) + \"px\";\n\
if (scrollTop != null) {\n\
d.scrollbarV.scrollTop = d.scroller.scrollTop = scrollTop;\n\
// 'Nudge' the scrollbar to work around a Webkit bug where,\n\
// in some situations, we'd end up with a scrollbar that\n\
// reported its scrollTop (and looked) as expected, but\n\
// *behaved* as if it was still in a previous state (i.e.\n\
// couldn't scroll up, even though it appeared to be at the\n\
// bottom).\n\
if (webkit) setTimeout(function() {\n\
if (d.scrollbarV.scrollTop != scrollTop) return;\n\
d.scrollbarV.scrollTop = scrollTop + (scrollTop ? -1 : 1);\n\
d.scrollbarV.scrollTop = scrollTop;\n\
}, 0);\n\
}\n\
} else d.scrollbarV.style.display = \"\";\n\
if (needsH) {\n\
d.scrollbarH.style.display = \"block\";\n\
d.scrollbarH.style.right = needsV ? scrollbarWidth(d.measure) + \"px\" : \"0\";\n\
d.scrollbarH.firstChild.style.width =\n\
(d.scroller.scrollWidth - d.scroller.clientWidth + d.scrollbarH.clientWidth) + \"px\";\n\
} else d.scrollbarH.style.display = \"\";\n\
if (needsH && needsV) {\n\
d.scrollbarFiller.style.display = \"block\";\n\
d.scrollbarFiller.style.height = d.scrollbarFiller.style.width = scrollbarWidth(d.measure) + \"px\";\n\
} else d.scrollbarFiller.style.display = \"\";\n\
\n\
if (mac_geLion && scrollbarWidth(d.measure) === 0)\n\
d.scrollbarV.style.minWidth = d.scrollbarH.style.minHeight = \"12px\";\n\
}\n\
\n\
function visibleLines(display, doc, scrollTop) {\n\
var top = (scrollTop != null ? scrollTop : display.scroller.scrollTop) - paddingTop(display);\n\
var fromHeight = Math.max(0, Math.floor(top));\n\
var toHeight = Math.ceil(top + display.wrapper.clientHeight);\n\
return {from: lineAtHeight(doc, fromHeight),\n\
to: lineAtHeight(doc, toHeight)};\n\
}\n\
\n\
// LINE NUMBERS\n\
\n\
function alignLineNumbers(display) {\n\
if (display.alignWidgets) {\n\
var margin = compensateForHScroll(display);\n\
for (var n = display.lineDiv.firstChild; n; n = n.nextSibling)\n\
for (var c = n.lastChild; c && c.widget; c = c.prevSibling)\n\
if (c.widget.noHScroll)\n\
c.style.marginLeft = (c.widget.coverGutter ? margin : margin + display.gutters.offsetWidth) + \"px\";\n\
}\n\
if (!display.lineGutter) return;\n\
var l = lineNumberLeftPos(display) + \"px\";\n\
for (var n = display.lineDiv.firstChild; n; n = n.nextSibling)\n\
n.firstChild.style.left = l;\n\
}\n\
\n\
function maybeUpdateLineNumberWidth(cm) {\n\
if (!cm.options.lineNumbers) return false;\n\
var doc = cm.view.doc, last = lineNumberFor(cm.options, doc.size - 1), display = cm.display;\n\
if (last.length != display.lineNumChars) {\n\
var test = display.measure.appendChild(elt(\"div\", [elt(\"div\", last)],\n\
\"CodeMirror-linenumber CodeMirror-gutter-elt\"));\n\
display.lineNumWidth = test.firstChild.offsetWidth;\n\
display.lineNumChars = display.lineNumWidth ? last.length : -1;\n\
display.lineGutter.style.width = display.lineNumWidth + \"px\";\n\
return true;\n\
}\n\
return false;\n\
}\n\
\n\
function lineNumberFor(options, i) {\n\
return String(options.lineNumberFormatter(i + options.firstLineNumber));\n\
}\n\
function compensateForHScroll(display) {\n\
return display.scroller.getBoundingClientRect().left - display.sizer.getBoundingClientRect().left;\n\
}\n\
function lineNumberLeftPos(display) {\n\
return compensateForHScroll(display) + display.lineGutter.offsetLeft;\n\
}\n\
\n\
// DISPLAY DRAWING\n\
\n\
function updateDisplay(cm, changes, scrollTop) {\n\
var oldFrom = cm.display.showingFrom, oldTo = cm.display.showingTo;\n\
var updated = updateDisplayInner(cm, changes, scrollTop);\n\
if (updated) {\n\
signalLater(cm, cm, \"update\", cm);\n\
if (cm.display.showingFrom != oldFrom || cm.display.showingTo != oldTo)\n\
signalLater(cm, cm, \"update\", cm, cm.display.showingFrom, cm.display.showingTo);\n\
}\n\
updateSelection(cm);\n\
updateScrollbars(cm.display, cm.view.doc.height, scrollTop);\n\
return updated;\n\
}\n\
\n\
// Uses a set of changes plus the current scroll position to\n\
// determine which DOM updates have to be made, and makes the\n\
// updates.\n\
function updateDisplayInner(cm, changes, scrollTop) {\n\
var display = cm.display, doc = cm.view.doc;\n\
if (!display.wrapper.clientWidth) {\n\
display.showingFrom = display.showingTo = display.viewOffset = 0;\n\
return;\n\
}\n\
\n\
// Compute the new visible window\n\
// If scrollTop is specified, use that to determine which lines\n\
// to render instead of the current scrollbar position.\n\
var visible = visibleLines(display, doc, scrollTop);\n\
// Bail out if the visible area is already rendered and nothing changed.\n\
if (changes !== true && changes.length == 0 &&\n\
visible.from > display.showingFrom && visible.to < display.showingTo)\n\
return;\n\
\n\
if (changes && changes !== true && maybeUpdateLineNumberWidth(cm))\n\
changes = true;\n\
display.sizer.style.marginLeft = display.scrollbarH.style.left = display.gutters.offsetWidth + \"px\";\n\
// Used to determine which lines need their line numbers updated\n\
var positionsChangedFrom = changes === true ? 0 : Infinity;\n\
if (cm.options.lineNumbers && changes && changes !== true)\n\
for (var i = 0; i < changes.length; ++i)\n\
if (changes[i].diff) { positionsChangedFrom = changes[i].from; break; }\n\
\n\
var from = Math.max(visible.from - 100, 0), to = Math.min(doc.size, visible.to + 100);\n\
if (display.showingFrom < from && from - display.showingFrom < 20) from = display.showingFrom;\n\
if (display.showingTo > to && display.showingTo - to < 20) to = Math.min(doc.size, display.showingTo);\n\
\n\
// Create a range of theoretically intact lines, and punch holes\n\
// in that using the change info.\n\
var intact = changes === true ? [] :\n\
computeIntact([{from: display.showingFrom, to: display.showingTo, domStart: 0}], changes);\n\
// Clip off the parts that won't be visible\n\
var intactLines = 0;\n\
for (var i = 0; i < intact.length; ++i) {\n\
var range = intact[i];\n\
if (range.from < from) {range.domStart += (from - range.from); range.from = from;}\n\
if (range.to > to) range.to = to;\n\
if (range.from >= range.to) intact.splice(i--, 1);\n\
else intactLines += range.to - range.from;\n\
}\n\
if (intactLines == to - from && from == display.showingFrom && to == display.showingTo)\n\
return;\n\
intact.sort(function(a, b) {return a.domStart - b.domStart;});\n\
\n\
display.lineDiv.style.display = \"none\";\n\
patchDisplay(cm, from, to, intact, positionsChangedFrom);\n\
display.lineDiv.style.display = \"\";\n\
\n\
var different = from != display.showingFrom || to != display.showingTo ||\n\
display.lastSizeC != display.wrapper.clientHeight;\n\
// This is just a bogus formula that detects when the editor is\n\
// resized or the font size changes.\n\
if (different) display.lastSizeC = display.wrapper.clientHeight;\n\
display.showingFrom = from; display.showingTo = to;\n\
display.viewOffset = heightAtLine(doc, from);\n\
startWorker(cm, 100);\n\
\n\
// Since this is all rather error prone, it is honoured with the\n\
// only assertion in the whole file.\n\
if (display.lineDiv.childNodes.length != display.showingTo - display.showingFrom)\n\
throw new Error(\"BAD PATCH! \" + JSON.stringify(intact) + \" size=\" + (display.showingTo - display.showingFrom) +\n\
\" nodes=\" + display.lineDiv.childNodes.length);\n\
\n\
// Update line heights for visible lines based on actual DOM\n\
// sizes\n\
var curNode = display.lineDiv.firstChild, heightChanged = false;\n\
var relativeTo = curNode.offsetTop;\n\
doc.iter(display.showingFrom, display.showingTo, function(line) {\n\
// Work around bizarro IE7 bug where, sometimes, our curNode\n\
// is magically replaced with a new node in the DOM, leaving\n\
// us with a reference to an orphan (nextSibling-less) node.\n\
if (!curNode) return;\n\
if (!line.hidden) {\n\
var end = curNode.offsetHeight + curNode.offsetTop;\n\
var height = end - relativeTo, diff = line.height - height;\n\
if (height < 2) height = textHeight(display);\n\
relativeTo = end;\n\
if (diff > .001 || diff < -.001) {\n\
updateLineHeight(line, height);\n\
heightChanged = true;\n\
}\n\
}\n\
curNode = curNode.nextSibling;\n\
});\n\
\n\
// Position the mover div to align with the current virtual scroll position\n\
display.mover.style.top = display.viewOffset + \"px\";\n\
return true;\n\
}\n\
\n\
function computeIntact(intact, changes) {\n\
for (var i = 0, l = changes.length || 0; i < l; ++i) {\n\
var change = changes[i], intact2 = [], diff = change.diff || 0;\n\
for (var j = 0, l2 = intact.length; j < l2; ++j) {\n\
var range = intact[j];\n\
if (change.to <= range.from && change.diff)\n\
intact2.push({from: range.from + diff, to: range.to + diff,\n\
domStart: range.domStart});\n\
else if (change.to <= range.from || change.from >= range.to)\n\
intact2.push(range);\n\
else {\n\
if (change.from > range.from)\n\
intact2.push({from: range.from, to: change.from, domStart: range.domStart});\n\
if (change.to < range.to)\n\
intact2.push({from: change.to + diff, to: range.to + diff,\n\
domStart: range.domStart + (change.to - range.from)});\n\
}\n\
}\n\
intact = intact2;\n\
}\n\
return intact;\n\
}\n\
\n\
function patchDisplay(cm, from, to, intact, updateNumbersFrom) {\n\
function killNode(node) {\n\
var tmp = node.nextSibling;\n\
node.parentNode.removeChild(node);\n\
return tmp;\n\
}\n\
var display = cm.display, lineNumbers = cm.options.lineNumbers;\n\
var lineNumberPos = lineNumbers && lineNumberLeftPos(display);\n\
// The first pass removes the DOM nodes that aren't intact.\n\
if (!intact.length) removeChildren(display.lineDiv);\n\
else {\n\
var domPos = 0, curNode = display.lineDiv.firstChild, n;\n\
for (var i = 0; i < intact.length; ++i) {\n\
var cur = intact[i];\n\
while (cur.domStart > domPos) {curNode = killNode(curNode); domPos++;}\n\
for (var j = cur.from, e = cur.to; j < e; ++j) {\n\
if (lineNumbers && updateNumbersFrom <= j && curNode.firstChild)\n\
setTextContent(curNode.firstChild, lineNumberFor(cm.options, j));\n\
curNode = curNode.nextSibling; domPos++;\n\
}\n\
}\n\
while (curNode) curNode = killNode(curNode);\n\
}\n\
// This pass fills in the lines that actually changed.\n\
var nextIntact = intact.shift(), curNode = display.lineDiv.firstChild;\n\
var j = from, gutterSpecs = cm.options.gutters;\n\
cm.view.doc.iter(from, to, function(line) {\n\
if (nextIntact && nextIntact.to == j) nextIntact = intact.shift();\n\
if (!nextIntact || nextIntact.from > j) {\n\
if (line.hidden) var lineElement = elt(\"div\");\n\
else {\n\
var lineElement = lineContent(cm, line), markers = line.gutterMarkers;\n\
if (line.className) lineElement.className = line.className;\n\
// Lines with gutter elements or a background class need\n\
// to be wrapped again, and have the extra elements added\n\
// to the wrapper div\n\
if (lineNumbers || markers || line.bgClassName || (line.widgets && line.widgets.length)) {\n\
var inside = [];\n\
if (lineNumbers)\n\
inside.push(elt(\"div\", lineNumberFor(cm.options, j),\n\
\"CodeMirror-linenumber CodeMirror-gutter-elt\",\n\
\"left: \" + lineNumberPos + \"px; width: \"\n\
+ display.lineNumWidth + \"px\"));\n\
if (markers)\n\
for (var k = 0; k < gutterSpecs.length; ++k) {\n\
var id = gutterSpecs[k], found = markers.hasOwnProperty(id) && markers[id];\n\
if (found) {\n\
var gutterElt = display.gutters.childNodes[k];\n\
inside.push(elt(\"div\", [found], \"CodeMirror-gutter-elt\", \"left: \" +\n\
(gutterElt.offsetLeft - display.gutters.offsetWidth) +\n\
\"px; width: \" + gutterElt.clientWidth + \"px\"));\n\
}\n\
}\n\
// Kludge to make sure the styled element lies behind the selection (by z-index)\n\
if (line.bgClassName)\n\
inside.push(elt(\"div\", \"\\u00a0\", line.bgClassName + \" CodeMirror-linebackground\"));\n\
inside.push(lineElement);\n\
if (line.widgets)\n\
for (var i = 0, ws = line.widgets; i < ws.length; ++i) {\n\
var widget = ws[i], node = elt(\"div\", [widget.node], \"CodeMirror-linewidget\");\n\
node.widget = widget;\n\
if (widget.noHScroll)\n\
node.style.width = display.wrapper.clientWidth + \"px\";\n\
if (widget.coverGutter) {\n\
node.style.zIndex = 5;\n\
node.style.position = \"relative\";\n\
node.style.marginLeft =\n\
(widget.noHScroll ? compensateForHScroll(display) : -display.gutters.offsetWidth) + \"px\";\n\
}\n\
inside.push(node);\n\
}\n\
lineElement = elt(\"div\", inside, null, \"position: relative\");\n\
if (ie_lt8) lineElement.style.zIndex = 2;\n\
}\n\
}\n\
display.lineDiv.insertBefore(lineElement, curNode);\n\
} else {\n\
curNode = curNode.nextSibling;\n\
}\n\
++j;\n\
});\n\
}\n\
\n\
// SELECTION / CURSOR\n\
\n\
function selHead(view) {\n\
return view.sel.inverted ? view.sel.from : view.sel.to;\n\
}\n\
\n\
function updateSelection(cm) {\n\
var headPos, display = cm.display, doc = cm.view.doc, sel = cm.view.sel;\n\
if (posEq(sel.from, sel.to)) { // No selection, single cursor\n\
var pos = headPos = cursorCoords(cm, sel.from, \"div\");\n\
display.cursor.style.left = pos.left + \"px\";\n\
display.cursor.style.top = pos.top + \"px\";\n\
display.cursor.style.height = (pos.bottom - pos.top) * .85 + \"px\";\n\
display.cursor.style.display = \"\";\n\
display.selectionDiv.style.display = \"none\";\n\
\n\
if (pos.other) {\n\
display.otherCursor.style.display = \"\";\n\
display.otherCursor.style.left = pos.other.left + \"px\";\n\
display.otherCursor.style.top = pos.other.top + \"px\";\n\
display.otherCursor.style.height = (pos.other.bottom - pos.other.top) * .85 + \"px\";\n\
} else { display.otherCursor.style.display = \"none\"; }\n\
} else {\n\
headPos = cursorCoords(cm, selHead(cm.view), \"div\");\n\
var fragment = document.createDocumentFragment();\n\
var clientWidth = display.lineSpace.clientWidth;\n\
var add = function(left, top, width, bottom) {\n\
if (top < 0) top = 0;\n\
fragment.appendChild(elt(\"div\", null, \"CodeMirror-selected\", \"position: absolute; left: \" + left +\n\
\"px; top: \" + top + \"px; width: \" + (width == null ? clientWidth : width) +\n\
\"px; height: \" + (bottom - top) + \"px\"));\n\
};\n\
\n\
var middleFrom = sel.from.line + 1, middleTo = sel.to.line - 1, sameLine = sel.from.line == sel.to.line;\n\
var drawForLine = function(line, from, toArg, retTop) {\n\
var lineObj = getLine(doc, line), lineLen = lineObj.text.length;\n\
var coords = function(ch) { return charCoords(cm, {line: line, ch: ch}, \"div\", lineObj); };\n\
var rVal = retTop ? Infinity : -Infinity;\n\
iterateBidiSections(getOrder(lineObj), from, toArg == null ? lineLen : toArg, function(from, to, dir) {\n\
var leftPos = coords(dir == \"rtl\" ? to - 1 : from);\n\
var rightPos = coords(dir == \"rtl\" ? from : to - 1);\n\
var left = leftPos.left, right = rightPos.right;\n\
if (rightPos.top - leftPos.top > 3) { // Different lines, draw top part\n\
add(left, leftPos.top, null, leftPos.bottom);\n\
left = paddingLeft(display);\n\
if (leftPos.bottom < rightPos.top) add(left, leftPos.bottom, null, rightPos.top);\n\
}\n\
if (toArg == null && to == lineLen) right = clientWidth;\n\
rVal = retTop ? Math.min(rightPos.top, rVal) : Math.max(rightPos.bottom, rVal);\n\
add(left, rightPos.top, right - left, rightPos.bottom);\n\
});\n\
return rVal;\n\
};\n\
\n\
var middleTop = Infinity, middleBot = -Infinity;\n\
if (sel.from.ch || sameLine)\n\
// Draw the first line of selection.\n\
middleTop = drawForLine(sel.from.line, sel.from.ch, sameLine ? sel.to.ch : null);\n\
else\n\
// Simply include it in the middle block.\n\
middleFrom = sel.from.line;\n\
\n\
if (!sameLine && sel.to.ch)\n\
middleBot = drawForLine(sel.to.line, 0, sel.to.ch, true);\n\
\n\
if (middleFrom <= middleTo) {\n\
// Draw the middle\n\
var botLine = getLine(doc, middleTo),\n\
bottom = charCoords(cm, {line: middleTo, ch: botLine.text.length}, \"div\", botLine);\n\
// Kludge to try and prevent fetching coordinates twice if\n\
// start end end are on same line.\n\
var top = (middleFrom != middleTo || botLine.height > bottom.bottom - bottom.top) ?\n\
charCoords(cm, {line: middleFrom, ch: 0}, \"div\") : bottom;\n\
middleTop = Math.min(middleTop, top.top);\n\
middleBot = Math.max(middleBot, bottom.bottom);\n\
}\n\
if (middleTop < middleBot) add(paddingLeft(display), middleTop, null, middleBot);\n\
\n\
removeChildrenAndAdd(display.selectionDiv, fragment);\n\
display.cursor.style.display = display.otherCursor.style.display = \"none\";\n\
display.selectionDiv.style.display = \"\";\n\
}\n\
\n\
// Move the hidden textarea near the cursor to prevent scrolling artifacts\n\
var wrapOff = display.wrapper.getBoundingClientRect(), lineOff = display.lineDiv.getBoundingClientRect();\n\
display.inputDiv.style.top = Math.max(0, Math.min(display.wrapper.clientHeight - 10,\n\
headPos.top + lineOff.top - wrapOff.top)) + \"px\";\n\
display.inputDiv.style.left = Math.max(0, Math.min(display.wrapper.clientWidth - 10,\n\
headPos.left + lineOff.left - wrapOff.left)) + \"px\";\n\
}\n\
\n\
// Cursor-blinking\n\
function restartBlink(cm) {\n\
var display = cm.display;\n\
clearInterval(display.blinker);\n\
var on = true;\n\
display.cursor.style.visibility = display.otherCursor.style.visibility = \"\";\n\
display.blinker = setInterval(function() {\n\
display.cursor.style.visibility = display.otherCursor.style.visibility = (on = !on) ? \"\" : \"hidden\";\n\
}, cm.options.cursorBlinkRate);\n\
}\n\
\n\
// HIGHLIGHT WORKER\n\
\n\
function startWorker(cm, time) {\n\
if (cm.view.doc.frontier < cm.display.showingTo)\n\
cm.view.doc.highlight.set(time, bind(highlightWorker, cm));\n\
}\n\
\n\
function highlightWorker(cm) {\n\
var doc = cm.view.doc;\n\
if (doc.frontier >= cm.display.showingTo) return;\n\
var end = +new Date + cm.options.workTime;\n\
var state = copyState(doc.mode, getStateBefore(doc, doc.frontier));\n\
var startFrontier = doc.frontier;\n\
doc.iter(doc.frontier, cm.display.showingTo, function(line) {\n\
if (doc.frontier >= cm.display.showingFrom) { // Visible\n\
line.highlight(doc.mode, state, cm.options.tabSize);\n\
line.stateAfter = copyState(doc.mode, state);\n\
} else {\n\
line.process(doc.mode, state, cm.options.tabSize);\n\
line.stateAfter = doc.frontier % 5 == 0 ? copyState(doc.mode, state) : null;\n\
}\n\
++doc.frontier;\n\
if (+new Date > end) {\n\
startWorker(cm, cm.options.workDelay);\n\
return true;\n\
}\n\
});\n\
if (cm.display.showingTo > startFrontier && doc.frontier >= cm.display.showingFrom)\n\
operation(cm, function() {regChange(this, startFrontier, doc.frontier);})();\n\
}\n\
\n\
// Finds the line to start with when starting a parse. Tries to\n\
// find a line with a stateAfter, so that it can start with a\n\
// valid state. If that fails, it returns the line with the\n\
// smallest indentation, which tends to need the least context to\n\
// parse correctly.\n\
function findStartLine(doc, n) {\n\
var minindent, minline;\n\
for (var search = n, lim = n - 100; search > lim; --search) {\n\
if (search == 0) return 0;\n\
var line = getLine(doc, search-1);\n\
if (line.stateAfter) return search;\n\
var indented = line.indentation(doc.tabSize);\n\
if (minline == null || minindent > indented) {\n\
minline = search - 1;\n\
minindent = indented;\n\
}\n\
}\n\
return minline;\n\
}\n\
\n\
function getStateBefore(doc, n) {\n\
var pos = findStartLine(doc, n), state = pos && getLine(doc, pos-1).stateAfter;\n\
if (!state) state = startState(doc.mode);\n\
else state = copyState(doc.mode, state);\n\
doc.iter(pos, n, function(line) {\n\
line.process(doc.mode, state, doc.tabSize);\n\
line.stateAfter = (pos == n - 1 || pos % 5 == 0) ? copyState(doc.mode, state) : null;\n\
});\n\
return state;\n\
}\n\
\n\
// POSITION MEASUREMENT\n\
\n\
function paddingTop(display) {return display.lineSpace.offsetTop;}\n\
function paddingLeft(display) {\n\
var e = removeChildrenAndAdd(display.measure, elt(\"pre\")).appendChild(elt(\"span\", \"x\"));\n\
return e.offsetLeft;\n\
}\n\
\n\
function measureLine(cm, line, ch) {\n\
var wrapping = cm.options.lineWrapping, display = cm.display;\n\
// First look in the cache\n\
var cache = cm.display.measureLineCache;\n\
for (var i = 0; i < cache.length; ++i) {\n\
var memo = cache[i];\n\
if (memo.ch == ch && memo.text == line.text &&\n\
(!wrapping || display.scroller.clientWidth == memo.width))\n\
return {top: memo.top, bottom: memo.bottom, left: memo.left, right: memo.right};\n\
}\n\
\n\
var atEnd = ch && ch == line.text.length;\n\
var pre = lineContent(cm, line, atEnd ? ch - 1 : ch);\n\
removeChildrenAndAdd(display.measure, pre);\n\
var anchor = pre.anchor, outer = display.lineDiv.getBoundingClientRect();\n\
// We'll sample once at the top, once at the bottom of the line,\n\
// to get the real line height (in case there tokens on the line\n\
// with bigger fonts)\n\
anchor.style.verticalAlign = \"top\";\n\
var box1 = anchor.getBoundingClientRect(), left = box1.left - outer.left, right = box1.right - outer.left;\n\
if (ie) {\n\
var left1 = anchor.offsetLeft;\n\
// In IE, verticalAlign does not influence offsetTop, unless\n\
// the element is an inline-block. Unfortunately, inline\n\
// blocks have different wrapping behaviour, so we have to do\n\
// some icky thing with inserting \"Zero-Width No-Break Spaces\"\n\
// to compensate for wrapping artifacts.\n\
anchor.style.display = \"inline-block\";\n\
if (wrapping && anchor.offsetLeft != left1) {\n\
anchor.parentNode.insertBefore(document.createTextNode(\"\\ufeff\"), anchor);\n\
if (anchor.offsetLeft != left1)\n\
anchor.parentNode.insertBefore(document.createTextNode(\"\\ufeff\"), anchor.nextSibling);\n\
if (anchor.offsetLeft != left1)\n\
anchor.parentNode.removeChild(anchor.previousSibling);\n\
}\n\
}\n\
var top = Math.max(0, box1.top - outer.top);\n\
anchor.style.verticalAlign = \"bottom\";\n\
var bottom = Math.min(anchor.getBoundingClientRect().bottom - outer.top, pre.offsetHeight);\n\
if (atEnd) left = right;\n\
\n\
// Store result in the cache\n\
var memo = {ch: ch, text: line.text, width: display.wrapper.clientWidth,\n\
top: top, bottom: bottom, left: left, right: right};\n\
if (cache.length == 8) cache[++cache.pos % 8] = memo;\n\
else cache.push(memo);\n\
\n\
return {top: top, bottom: bottom, left: left, right: right};\n\
}\n\
\n\
// Context is one of \"line\", \"div\" (display.lineDiv), \"local\"/null (editor), or \"page\"\n\
function intoCoordSystem(cm, pos, rect, context) {\n\
if (context == \"line\") return rect;\n\
if (!context) context = \"local\";\n\
var yOff = heightAtLine(cm.view.doc, pos.line);\n\
if (context != \"local\") yOff -= cm.display.viewOffset;\n\
if (context == \"page\") {\n\
var lOff = cm.display.lineSpace.getBoundingClientRect();\n\
yOff += lOff.top; rect.left += lOff.left; rect.right += lOff.right;\n\
}\n\
rect.top += yOff; rect.bottom += yOff;\n\
return rect;\n\
}\n\
\n\
function charCoords(cm, pos, context, lineObj) {\n\
if (!lineObj) lineObj = getLine(cm.view.doc, pos.line);\n\
return intoCoordSystem(cm, pos, measureLine(cm, lineObj, pos.ch), context);\n\
}\n\
\n\
function cursorCoords(cm, pos, context, lineObj) {\n\
lineObj = lineObj || getLine(cm.view.doc, pos.line);\n\
function get(ch, right) {\n\
var m = measureLine(cm, lineObj, ch);\n\
if (right) m.left = m.right; else m.right = m.left;\n\
return intoCoordSystem(cm, pos, m, context);\n\
}\n\
var order = getOrder(lineObj), ch = pos.ch;\n\
if (!order) return get(ch);\n\
var main, other, linedir = order[0].level;\n\
for (var i = 0; i < order.length; ++i) {\n\
var part = order[i], rtl = part.level % 2, nb, here;\n\
if (part.from < ch && part.to > ch) return get(ch, rtl);\n\
var left = rtl ? part.to : part.from, right = rtl ? part.from : part.to;\n\
if (left == ch) {\n\
// Opera and IE return bogus offsets and widths for edges\n\
// where the direction flips, but only for the side with the\n\
// lower level. So we try to use the side with the higher\n\
// level.\n\
if (i && part.level < (nb = order[i-1]).level) here = get(nb.level % 2 ? nb.from : nb.to - 1, true);\n\
else here = get(rtl && part.from != part.to ? ch - 1 : ch);\n\
if (rtl == linedir) main = here; else other = here;\n\
} else if (right == ch) {\n\
var nb = i < order.length - 1 && order[i+1];\n\
if (!rtl && nb && nb.from == nb.to) continue;\n\
if (nb && part.level < nb.level) here = get(nb.level % 2 ? nb.to - 1 : nb.from);\n\
else here = get(rtl ? ch : ch - 1, true);\n\
if (rtl == linedir) main = here; else other = here;\n\
}\n\
}\n\
if (linedir && !ch) other = get(order[0].to - 1);\n\
if (!main) return other;\n\
if (other) main.other = other;\n\
return main;\n\
}\n\
\n\
// Coords must be lineSpace-local\n\
function coordsChar(cm, x, y) {\n\
var display = cm.display, doc = cm.view.doc;\n\
var cw = charWidth(display), heightPos = display.viewOffset + y;\n\
if (heightPos < 0) return {line: 0, ch: 0};\n\
var lineNo = lineAtHeight(doc, heightPos);\n\
if (lineNo >= doc.size) return {line: doc.size - 1, ch: getLine(doc, doc.size - 1).text.length};\n\
var lineObj = getLine(doc, lineNo);\n\
if (!lineObj.text.length) return {line: lineNo, ch: 0};\n\
var tw = cm.options.lineWrapping, innerOff = tw ? heightPos - heightAtLine(doc, lineNo) : 0;\n\
if (x < 0) x = 0;\n\
var wrongLine = false;\n\
function getX(ch) {\n\
var sp = cursorCoords(cm, {line: lineNo, ch: ch}, \"line\", lineObj);\n\
if (tw) {\n\
wrongLine = true;\n\
if (innerOff > sp.bottom) return Math.max(0, sp.left - display.wrapper.clientWidth);\n\
else if (innerOff < sp.top) return sp.left + display.wrapper.clientWidth;\n\
else wrongLine = false;\n\
}\n\
return sp.left;\n\
}\n\
var bidi = getOrder(lineObj), dist = lineObj.text.length;\n\
var from = lineLeft(lineObj), fromX = 0, to = lineRight(lineObj), toX;\n\
if (!bidi) {\n\
// Guess a suitable upper bound for our search.\n\
var estimated = Math.min(to, Math.ceil((x + Math.floor(innerOff / textHeight(display)) *\n\
display.wrapper.clientWidth * .9) / cw));\n\
for (;;) {\n\
var estX = getX(estimated);\n\
if (estX <= x && estimated < to) estimated = Math.min(to, Math.ceil(estimated * 1.2));\n\
else {toX = estX; to = estimated; break;}\n\
}\n\
// Try to guess a suitable lower bound as well.\n\
estimated = Math.floor(to * 0.8); estX = getX(estimated);\n\
if (estX < x) {from = estimated; fromX = estX;}\n\
dist = to - from;\n\
} else toX = getX(to);\n\
if (x > toX) return {line: lineNo, ch: to};\n\
// Do a binary search between these bounds.\n\
for (;;) {\n\
if (bidi ? to == from || to == moveVisually(lineObj, from, 1) : to - from <= 1) {\n\
var after = x - fromX < toX - x, ch = after ? from : to;\n\
while (isExtendingChar.test(lineObj.text.charAt(ch))) ++ch;\n\
return {line: lineNo, ch: ch, after: after};\n\
}\n\
var step = Math.ceil(dist / 2), middle = from + step;\n\
if (bidi) {\n\
middle = from;\n\
for (var i = 0; i < step; ++i) middle = moveVisually(lineObj, middle, 1);\n\
}\n\
var middleX = getX(middle);\n\
if (middleX > x) {to = middle; toX = middleX; if (wrongLine) toX += 1000; dist -= step;}\n\
else {from = middle; fromX = middleX; dist = step;}\n\
}\n\
}\n\
\n\
var measureText;\n\
function textHeight(display) {\n\
if (display.cachedTextHeight != null) return display.cachedTextHeight;\n\
if (measureText == null) {\n\
measureText = elt(\"pre\");\n\
// Measure a bunch of lines, for browsers that compute\n\
// fractional heights.\n\
for (var i = 0; i < 49; ++i) {\n\
measureText.appendChild(document.createTextNode(\"x\"));\n\
measureText.appendChild(elt(\"br\"));\n\
}\n\
measureText.appendChild(document.createTextNode(\"x\"));\n\
}\n\
removeChildrenAndAdd(display.measure, measureText);\n\
var height = measureText.offsetHeight / 50;\n\
if (height > 3) display.cachedTextHeight = height;\n\
removeChildren(display.measure);\n\
return height || 1;\n\
}\n\
\n\
function charWidth(display) {\n\
if (display.cachedCharWidth != null) return display.cachedCharWidth;\n\
var anchor = elt(\"span\", \"x\");\n\
var pre = elt(\"pre\", [anchor]);\n\
removeChildrenAndAdd(display.measure, pre);\n\
var width = anchor.offsetWidth;\n\
if (width > 2) display.cachedCharWidth = width;\n\
return width || 10;\n\
}\n\
\n\
// OPERATIONS\n\
\n\
// Operations are used to wrap changes in such a way that each\n\
// change won't have to update the cursor and display (which would\n\
// be awkward, slow, and error-prone), but instead updates are\n\
// batched and then all combined and executed at once.\n\
\n\
function startOperation(cm) {\n\
if (cm.curOp) ++cm.curOp.depth;\n\
else cm.curOp = {\n\
// Nested operations delay update until the outermost one\n\
// finishes.\n\
depth: 1,\n\
// An array of ranges of lines that have to be updated. See\n\
// updateDisplay.\n\
changes: [],\n\
delayedCallbacks: [],\n\
updateInput: null,\n\
userSelChange: null,\n\
textChanged: null,\n\
selectionChanged: false,\n\
updateMaxLine: false\n\
};\n\
}\n\
\n\
function endOperation(cm) {\n\
var op = cm.curOp;\n\
if (--op.depth) return;\n\
cm.curOp = null;\n\
var view = cm.view, display = cm.display;\n\
if (op.updateMaxLine) computeMaxLength(view);\n\
if (view.maxLineChanged && !cm.options.lineWrapping) {\n\
var width = measureLine(cm, view.maxLine, view.maxLine.text.length).left;\n\
display.sizer.style.minWidth = (width + 3 + scrollerCutOff) + \"px\";\n\
view.maxLineChanged = false;\n\
}\n\
var newScrollPos, updated;\n\
if (op.selectionChanged) {\n\
var coords = cursorCoords(cm, selHead(view));\n\
newScrollPos = calculateScrollPos(display, coords.left, coords.top, coords.left, coords.bottom);\n\
}\n\
if (op.changes.length || newScrollPos && newScrollPos.scrollTop != null)\n\
updated = updateDisplay(cm, op.changes, newScrollPos && newScrollPos.scrollTop);\n\
if (!updated && op.selectionChanged) updateSelection(cm);\n\
if (newScrollPos) scrollCursorIntoView(cm);\n\
if (op.selectionChanged) restartBlink(cm);\n\
\n\
if (view.focused && op.updateInput)\n\
resetInput(cm, op.userSelChange);\n\
\n\
if (op.textChanged)\n\
signal(cm, \"change\", cm, op.textChanged);\n\
if (op.selectionChanged) signal(cm, \"cursorActivity\", cm);\n\
for (var i = 0; i < op.delayedCallbacks.length; ++i) op.delayedCallbacks[i](cm);\n\
}\n\
\n\
// Wraps a function in an operation. Returns the wrapped function.\n\
function operation(cm1, f) {\n\
return function() {\n\
var cm = cm1 || this;\n\
startOperation(cm);\n\
try {var result = f.apply(cm, arguments);}\n\
finally {endOperation(cm);}\n\
return result;\n\
};\n\
}\n\
\n\
function regChange(cm, from, to, lendiff) {\n\
cm.curOp.changes.push({from: from, to: to, diff: lendiff});\n\
}\n\
\n\
function compoundChange(cm, f) {\n\
var hist = cm.view.doc.history;\n\
hist.startCompound();\n\
try { return f(); } finally { hist.endCompound(); }\n\
}\n\
\n\
// INPUT HANDLING\n\
\n\
function slowPoll(cm) {\n\
if (cm.view.pollingFast) return;\n\
cm.display.poll.set(cm.options.pollInterval, function() {\n\
readInput(cm);\n\
if (cm.view.focused) slowPoll(cm);\n\
});\n\
}\n\
\n\
function fastPoll(cm) {\n\
var missed = false;\n\
cm.display.pollingFast = true;\n\
function p() {\n\
var changed = readInput(cm);\n\
if (!changed && !missed) {missed = true; cm.display.poll.set(60, p);}\n\
else {cm.display.pollingFast = false; slowPoll(cm);}\n\
}\n\
cm.display.poll.set(20, p);\n\
}\n\
\n\
// prevInput is a hack to work with IME. If we reset the textarea\n\
// on every change, that breaks IME. So we look for changes\n\
// compared to the previous content instead. (Modern browsers have\n\
// events that indicate IME taking place, but these are not widely\n\
// supported or compatible enough yet to rely on.)\n\
function readInput(cm) {\n\
var input = cm.display.input, prevInput = cm.display.prevInput, view = cm.view, sel = view.sel;\n\
if (!view.focused || hasSelection(input) || cm.options.readOnly) return false;\n\
var text = input.value;\n\
if (text == prevInput && posEq(sel.from, sel.to)) return false;\n\
startOperation(cm);\n\
view.sel.shift = null;\n\
var same = 0, l = Math.min(prevInput.length, text.length);\n\
while (same < l && prevInput[same] == text[same]) ++same;\n\
if (same < prevInput.length)\n\
sel.from = {line: sel.from.line, ch: sel.from.ch - (prevInput.length - same)};\n\
else if (view.overwrite && posEq(sel.from, sel.to))\n\
sel.to = {line: sel.to.line, ch: Math.min(getLine(cm.view.doc, sel.to.line).text.length, sel.to.ch + (text.length - same))};\n\
var updateInput = cm.curOp.updateInput;\n\
cm.replaceSelection(text.slice(same), \"end\");\n\
cm.curOp.updateInput = updateInput;\n\
if (text.length > 1000) { input.value = cm.display.prevInput = \"\"; }\n\
else cm.display.prevInput = text;\n\
endOperation(cm);\n\
return true;\n\
}\n\
\n\
function resetInput(cm, user) {\n\
var view = cm.view, minimal, selected;\n\
if (!posEq(view.sel.from, view.sel.to)) {\n\
cm.display.prevInput = \"\";\n\
minimal = hasCopyEvent &&\n\
(view.sel.to.line - view.sel.from.line > 100 || (selected = cm.getSelection()).length > 1000);\n\
if (minimal) cm.display.input.value = \"-\";\n\
else cm.display.input.value = selected || cm.getSelection();\n\
if (view.focused) selectInput(cm.display.input);\n\
} else if (user) cm.display.prevInput = cm.display.input.value = \"\";\n\
cm.display.inaccurateSelection = minimal;\n\
}\n\
\n\
function focusInput(cm) {\n\
if (cm.options.readOnly != \"nocursor\") cm.display.input.focus();\n\
}\n\
\n\
// EVENT HANDLERS\n\
\n\
function registerEventHandl