Implement CSS `display: flow-root` (modern clearfix)
[WebKit-https.git] / Source / WebInspectorUI / UserInterface / External / CodeMirror / codemirror.js
1 // CodeMirror, copyright (c) by Marijn Haverbeke and others
2 // Distributed under an MIT license: http://codemirror.net/LICENSE
3
4 // This is CodeMirror (http://codemirror.net), a code editor
5 // implemented in JavaScript on top of the browser's DOM.
6 //
7 // You can find some technical background for some of the code below
8 // at http://marijnhaverbeke.nl/blog/#cm-internals .
9
10 (function (global, factory) {
11   typeof exports === 'object' && typeof module !== 'undefined' ? module.exports = factory() :
12   typeof define === 'function' && define.amd ? define(factory) :
13   (global.CodeMirror = factory());
14 }(this, (function () { 'use strict';
15
16 // Kludges for bugs and behavior differences that can't be feature
17 // detected are enabled based on userAgent etc sniffing.
18 var userAgent = navigator.userAgent
19 var platform = navigator.platform
20
21 var gecko = /gecko\/\d/i.test(userAgent)
22 var ie_upto10 = /MSIE \d/.test(userAgent)
23 var ie_11up = /Trident\/(?:[7-9]|\d{2,})\..*rv:(\d+)/.exec(userAgent)
24 var ie = ie_upto10 || ie_11up
25 var ie_version = ie && (ie_upto10 ? document.documentMode || 6 : ie_11up[1])
26 var webkit = /WebKit\//.test(userAgent)
27 var qtwebkit = webkit && /Qt\/\d+\.\d+/.test(userAgent)
28 var chrome = /Chrome\//.test(userAgent)
29 var presto = /Opera\//.test(userAgent)
30 var safari = /Apple Computer/.test(navigator.vendor)
31 var mac_geMountainLion = /Mac OS X 1\d\D([8-9]|\d\d)\D/.test(userAgent)
32 var phantom = /PhantomJS/.test(userAgent)
33
34 var ios = /AppleWebKit/.test(userAgent) && /Mobile\/\w+/.test(userAgent)
35 // This is woefully incomplete. Suggestions for alternative methods welcome.
36 var mobile = ios || /Android|webOS|BlackBerry|Opera Mini|Opera Mobi|IEMobile/i.test(userAgent)
37 var mac = ios || /Mac/.test(platform)
38 var chromeOS = /\bCrOS\b/.test(userAgent)
39 var windows = /win/i.test(platform)
40
41 var presto_version = presto && userAgent.match(/Version\/(\d*\.\d*)/)
42 if (presto_version) { presto_version = Number(presto_version[1]) }
43 if (presto_version && presto_version >= 15) { presto = false; webkit = true }
44 // Some browsers use the wrong event properties to signal cmd/ctrl on OS X
45 var flipCtrlCmd = mac && (qtwebkit || presto && (presto_version == null || presto_version < 12.11))
46 var captureRightClick = gecko || (ie && ie_version >= 9)
47
48 function classTest(cls) { return new RegExp("(^|\\s)" + cls + "(?:$|\\s)\\s*") }
49
50 var rmClass = function(node, cls) {
51   var current = node.className
52   var match = classTest(cls).exec(current)
53   if (match) {
54     var after = current.slice(match.index + match[0].length)
55     node.className = current.slice(0, match.index) + (after ? match[1] + after : "")
56   }
57 }
58
59 function removeChildren(e) {
60   for (var count = e.childNodes.length; count > 0; --count)
61     { e.removeChild(e.firstChild) }
62   return e
63 }
64
65 function removeChildrenAndAdd(parent, e) {
66   return removeChildren(parent).appendChild(e)
67 }
68
69 function elt(tag, content, className, style) {
70   var e = document.createElement(tag)
71   if (className) { e.className = className }
72   if (style) { e.style.cssText = style }
73   if (typeof content == "string") { e.appendChild(document.createTextNode(content)) }
74   else if (content) { for (var i = 0; i < content.length; ++i) { e.appendChild(content[i]) } }
75   return e
76 }
77
78 var range
79 if (document.createRange) { range = function(node, start, end, endNode) {
80   var r = document.createRange()
81   r.setEnd(endNode || node, end)
82   r.setStart(node, start)
83   return r
84 } }
85 else { range = function(node, start, end) {
86   var r = document.body.createTextRange()
87   try { r.moveToElementText(node.parentNode) }
88   catch(e) { return r }
89   r.collapse(true)
90   r.moveEnd("character", end)
91   r.moveStart("character", start)
92   return r
93 } }
94
95 function contains(parent, child) {
96   if (child.nodeType == 3) // Android browser always returns false when child is a textnode
97     { child = child.parentNode }
98   if (parent.contains)
99     { return parent.contains(child) }
100   do {
101     if (child.nodeType == 11) { child = child.host }
102     if (child == parent) { return true }
103   } while (child = child.parentNode)
104 }
105
106 function activeElt() {
107   // IE and Edge may throw an "Unspecified Error" when accessing document.activeElement.
108   // IE < 10 will throw when accessed while the page is loading or in an iframe.
109   // IE > 9 and Edge will throw when accessed in an iframe if document.body is unavailable.
110   var activeElement
111   try {
112     activeElement = document.activeElement
113   } catch(e) {
114     activeElement = document.body || null
115   }
116   while (activeElement && activeElement.root && activeElement.root.activeElement)
117     { activeElement = activeElement.root.activeElement }
118   return activeElement
119 }
120
121 function addClass(node, cls) {
122   var current = node.className
123   if (!classTest(cls).test(current)) { node.className += (current ? " " : "") + cls }
124 }
125 function joinClasses(a, b) {
126   var as = a.split(" ")
127   for (var i = 0; i < as.length; i++)
128     { if (as[i] && !classTest(as[i]).test(b)) { b += " " + as[i] } }
129   return b
130 }
131
132 var selectInput = function(node) { node.select() }
133 if (ios) // Mobile Safari apparently has a bug where select() is broken.
134   { selectInput = function(node) { node.selectionStart = 0; node.selectionEnd = node.value.length } }
135 else if (ie) // Suppress mysterious IE10 errors
136   { selectInput = function(node) { try { node.select() } catch(_e) {} } }
137
138 function bind(f) {
139   var args = Array.prototype.slice.call(arguments, 1)
140   return function(){return f.apply(null, args)}
141 }
142
143 function copyObj(obj, target, overwrite) {
144   if (!target) { target = {} }
145   for (var prop in obj)
146     { if (obj.hasOwnProperty(prop) && (overwrite !== false || !target.hasOwnProperty(prop)))
147       { target[prop] = obj[prop] } }
148   return target
149 }
150
151 // Counts the column offset in a string, taking tabs into account.
152 // Used mostly to find indentation.
153 function countColumn(string, end, tabSize, startIndex, startValue) {
154   if (end == null) {
155     end = string.search(/[^\s\u00a0]/)
156     if (end == -1) { end = string.length }
157   }
158   for (var i = startIndex || 0, n = startValue || 0;;) {
159     var nextTab = string.indexOf("\t", i)
160     if (nextTab < 0 || nextTab >= end)
161       { return n + (end - i) }
162     n += nextTab - i
163     n += tabSize - (n % tabSize)
164     i = nextTab + 1
165   }
166 }
167
168 function Delayed() {this.id = null}
169 Delayed.prototype.set = function(ms, f) {
170   clearTimeout(this.id)
171   this.id = setTimeout(f, ms)
172 }
173
174 function indexOf(array, elt) {
175   for (var i = 0; i < array.length; ++i)
176     { if (array[i] == elt) { return i } }
177   return -1
178 }
179
180 // Number of pixels added to scroller and sizer to hide scrollbar
181 var scrollerGap = 30
182
183 // Returned or thrown by various protocols to signal 'I'm not
184 // handling this'.
185 var Pass = {toString: function(){return "CodeMirror.Pass"}}
186
187 // Reused option objects for setSelection & friends
188 var sel_dontScroll = {scroll: false};
189 var sel_mouse = {origin: "*mouse"};
190 var sel_move = {origin: "+move"};
191 // The inverse of countColumn -- find the offset that corresponds to
192 // a particular column.
193 function findColumn(string, goal, tabSize) {
194   for (var pos = 0, col = 0;;) {
195     var nextTab = string.indexOf("\t", pos)
196     if (nextTab == -1) { nextTab = string.length }
197     var skipped = nextTab - pos
198     if (nextTab == string.length || col + skipped >= goal)
199       { return pos + Math.min(skipped, goal - col) }
200     col += nextTab - pos
201     col += tabSize - (col % tabSize)
202     pos = nextTab + 1
203     if (col >= goal) { return pos }
204   }
205 }
206
207 var spaceStrs = [""]
208 function spaceStr(n) {
209   while (spaceStrs.length <= n)
210     { spaceStrs.push(lst(spaceStrs) + " ") }
211   return spaceStrs[n]
212 }
213
214 function lst(arr) { return arr[arr.length-1] }
215
216 function map(array, f) {
217   var out = []
218   for (var i = 0; i < array.length; i++) { out[i] = f(array[i], i) }
219   return out
220 }
221
222 function insertSorted(array, value, score) {
223   var pos = 0, priority = score(value)
224   while (pos < array.length && score(array[pos]) <= priority) { pos++ }
225   array.splice(pos, 0, value)
226 }
227
228 function nothing() {}
229
230 function createObj(base, props) {
231   var inst
232   if (Object.create) {
233     inst = Object.create(base)
234   } else {
235     nothing.prototype = base
236     inst = new nothing()
237   }
238   if (props) { copyObj(props, inst) }
239   return inst
240 }
241
242 var nonASCIISingleCaseWordChar = /[\u00df\u0587\u0590-\u05f4\u0600-\u06ff\u3040-\u309f\u30a0-\u30ff\u3400-\u4db5\u4e00-\u9fcc\uac00-\ud7af]/;
243 function isWordCharBasic(ch) {
244   return /\w/.test(ch) || ch > "\x80" &&
245     (ch.toUpperCase() != ch.toLowerCase() || nonASCIISingleCaseWordChar.test(ch))
246 }
247 function isWordChar(ch, helper) {
248   if (!helper) { return isWordCharBasic(ch) }
249   if (helper.source.indexOf("\\w") > -1 && isWordCharBasic(ch)) { return true }
250   return helper.test(ch)
251 }
252
253 function isEmpty(obj) {
254   for (var n in obj) { if (obj.hasOwnProperty(n) && obj[n]) { return false } }
255   return true
256 }
257
258 // Extending unicode characters. A series of a non-extending char +
259 // any number of extending chars is treated as a single unit as far
260 // as editing and measuring is concerned. This is not fully correct,
261 // since some scripts/fonts/browsers also treat other configurations
262 // of code points as a group.
263 var extendingChars = /[\u0300-\u036f\u0483-\u0489\u0591-\u05bd\u05bf\u05c1\u05c2\u05c4\u05c5\u05c7\u0610-\u061a\u064b-\u065e\u0670\u06d6-\u06dc\u06de-\u06e4\u06e7\u06e8\u06ea-\u06ed\u0711\u0730-\u074a\u07a6-\u07b0\u07eb-\u07f3\u0816-\u0819\u081b-\u0823\u0825-\u0827\u0829-\u082d\u0900-\u0902\u093c\u0941-\u0948\u094d\u0951-\u0955\u0962\u0963\u0981\u09bc\u09be\u09c1-\u09c4\u09cd\u09d7\u09e2\u09e3\u0a01\u0a02\u0a3c\u0a41\u0a42\u0a47\u0a48\u0a4b-\u0a4d\u0a51\u0a70\u0a71\u0a75\u0a81\u0a82\u0abc\u0ac1-\u0ac5\u0ac7\u0ac8\u0acd\u0ae2\u0ae3\u0b01\u0b3c\u0b3e\u0b3f\u0b41-\u0b44\u0b4d\u0b56\u0b57\u0b62\u0b63\u0b82\u0bbe\u0bc0\u0bcd\u0bd7\u0c3e-\u0c40\u0c46-\u0c48\u0c4a-\u0c4d\u0c55\u0c56\u0c62\u0c63\u0cbc\u0cbf\u0cc2\u0cc6\u0ccc\u0ccd\u0cd5\u0cd6\u0ce2\u0ce3\u0d3e\u0d41-\u0d44\u0d4d\u0d57\u0d62\u0d63\u0dca\u0dcf\u0dd2-\u0dd4\u0dd6\u0ddf\u0e31\u0e34-\u0e3a\u0e47-\u0e4e\u0eb1\u0eb4-\u0eb9\u0ebb\u0ebc\u0ec8-\u0ecd\u0f18\u0f19\u0f35\u0f37\u0f39\u0f71-\u0f7e\u0f80-\u0f84\u0f86\u0f87\u0f90-\u0f97\u0f99-\u0fbc\u0fc6\u102d-\u1030\u1032-\u1037\u1039\u103a\u103d\u103e\u1058\u1059\u105e-\u1060\u1071-\u1074\u1082\u1085\u1086\u108d\u109d\u135f\u1712-\u1714\u1732-\u1734\u1752\u1753\u1772\u1773\u17b7-\u17bd\u17c6\u17c9-\u17d3\u17dd\u180b-\u180d\u18a9\u1920-\u1922\u1927\u1928\u1932\u1939-\u193b\u1a17\u1a18\u1a56\u1a58-\u1a5e\u1a60\u1a62\u1a65-\u1a6c\u1a73-\u1a7c\u1a7f\u1b00-\u1b03\u1b34\u1b36-\u1b3a\u1b3c\u1b42\u1b6b-\u1b73\u1b80\u1b81\u1ba2-\u1ba5\u1ba8\u1ba9\u1c2c-\u1c33\u1c36\u1c37\u1cd0-\u1cd2\u1cd4-\u1ce0\u1ce2-\u1ce8\u1ced\u1dc0-\u1de6\u1dfd-\u1dff\u200c\u200d\u20d0-\u20f0\u2cef-\u2cf1\u2de0-\u2dff\u302a-\u302f\u3099\u309a\ua66f-\ua672\ua67c\ua67d\ua6f0\ua6f1\ua802\ua806\ua80b\ua825\ua826\ua8c4\ua8e0-\ua8f1\ua926-\ua92d\ua947-\ua951\ua980-\ua982\ua9b3\ua9b6-\ua9b9\ua9bc\uaa29-\uaa2e\uaa31\uaa32\uaa35\uaa36\uaa43\uaa4c\uaab0\uaab2-\uaab4\uaab7\uaab8\uaabe\uaabf\uaac1\uabe5\uabe8\uabed\udc00-\udfff\ufb1e\ufe00-\ufe0f\ufe20-\ufe26\uff9e\uff9f]/;
264 function isExtendingChar(ch) { return ch.charCodeAt(0) >= 768 && extendingChars.test(ch) }
265
266 // The display handles the DOM integration, both for input reading
267 // and content drawing. It holds references to DOM nodes and
268 // display-related state.
269
270 function Display(place, doc, input) {
271   var d = this
272   this.input = input
273
274   // Covers bottom-right square when both scrollbars are present.
275   d.scrollbarFiller = elt("div", null, "CodeMirror-scrollbar-filler")
276   d.scrollbarFiller.setAttribute("cm-not-content", "true")
277   // Covers bottom of gutter when coverGutterNextToScrollbar is on
278   // and h scrollbar is present.
279   d.gutterFiller = elt("div", null, "CodeMirror-gutter-filler")
280   d.gutterFiller.setAttribute("cm-not-content", "true")
281   // Will contain the actual code, positioned to cover the viewport.
282   d.lineDiv = elt("div", null, "CodeMirror-code")
283   // Elements are added to these to represent selection and cursors.
284   d.selectionDiv = elt("div", null, null, "position: relative; z-index: 1")
285   d.cursorDiv = elt("div", null, "CodeMirror-cursors")
286   // A visibility: hidden element used to find the size of things.
287   d.measure = elt("div", null, "CodeMirror-measure")
288   // When lines outside of the viewport are measured, they are drawn in this.
289   d.lineMeasure = elt("div", null, "CodeMirror-measure")
290   // Wraps everything that needs to exist inside the vertically-padded coordinate system
291   d.lineSpace = elt("div", [d.measure, d.lineMeasure, d.selectionDiv, d.cursorDiv, d.lineDiv],
292                     null, "position: relative; outline: none")
293   // Moved around its parent to cover visible view.
294   d.mover = elt("div", [elt("div", [d.lineSpace], "CodeMirror-lines")], null, "position: relative")
295   // Set to the height of the document, allowing scrolling.
296   d.sizer = elt("div", [d.mover], "CodeMirror-sizer")
297   d.sizerWidth = null
298   // Behavior of elts with overflow: auto and padding is
299   // inconsistent across browsers. This is used to ensure the
300   // scrollable area is big enough.
301   d.heightForcer = elt("div", null, null, "position: absolute; height: " + scrollerGap + "px; width: 1px;")
302   // Will contain the gutters, if any.
303   d.gutters = elt("div", null, "CodeMirror-gutters")
304   d.lineGutter = null
305   // Actual scrollable element.
306   d.scroller = elt("div", [d.sizer, d.heightForcer, d.gutters], "CodeMirror-scroll")
307   d.scroller.setAttribute("tabIndex", "-1")
308   // The element in which the editor lives.
309   d.wrapper = elt("div", [d.scrollbarFiller, d.gutterFiller, d.scroller], "CodeMirror")
310
311   // Work around IE7 z-index bug (not perfect, hence IE7 not really being supported)
312   if (ie && ie_version < 8) { d.gutters.style.zIndex = -1; d.scroller.style.paddingRight = 0 }
313   if (!webkit && !(gecko && mobile)) { d.scroller.draggable = true }
314
315   if (place) {
316     if (place.appendChild) { place.appendChild(d.wrapper) }
317     else { place(d.wrapper) }
318   }
319
320   // Current rendered range (may be bigger than the view window).
321   d.viewFrom = d.viewTo = doc.first
322   d.reportedViewFrom = d.reportedViewTo = doc.first
323   // Information about the rendered lines.
324   d.view = []
325   d.renderedView = null
326   // Holds info about a single rendered line when it was rendered
327   // for measurement, while not in view.
328   d.externalMeasured = null
329   // Empty space (in pixels) above the view
330   d.viewOffset = 0
331   d.lastWrapHeight = d.lastWrapWidth = 0
332   d.updateLineNumbers = null
333
334   d.nativeBarWidth = d.barHeight = d.barWidth = 0
335   d.scrollbarsClipped = false
336
337   // Used to only resize the line number gutter when necessary (when
338   // the amount of lines crosses a boundary that makes its width change)
339   d.lineNumWidth = d.lineNumInnerWidth = d.lineNumChars = null
340   // Set to true when a non-horizontal-scrolling line widget is
341   // added. As an optimization, line widget aligning is skipped when
342   // this is false.
343   d.alignWidgets = false
344
345   d.cachedCharWidth = d.cachedTextHeight = d.cachedPaddingH = null
346
347   // Tracks the maximum line length so that the horizontal scrollbar
348   // can be kept static when scrolling.
349   d.maxLine = null
350   d.maxLineLength = 0
351   d.maxLineChanged = false
352
353   // Used for measuring wheel scrolling granularity
354   d.wheelDX = d.wheelDY = d.wheelStartX = d.wheelStartY = null
355
356   // True when shift is held down.
357   d.shift = false
358
359   // Used to track whether anything happened since the context menu
360   // was opened.
361   d.selForContextMenu = null
362
363   d.activeTouch = null
364
365   input.init(d)
366 }
367
368 // Find the line object corresponding to the given line number.
369 function getLine(doc, n) {
370   n -= doc.first
371   if (n < 0 || n >= doc.size) { throw new Error("There is no line " + (n + doc.first) + " in the document.") }
372   var chunk = doc
373   while (!chunk.lines) {
374     for (var i = 0;; ++i) {
375       var child = chunk.children[i], sz = child.chunkSize()
376       if (n < sz) { chunk = child; break }
377       n -= sz
378     }
379   }
380   return chunk.lines[n]
381 }
382
383 // Get the part of a document between two positions, as an array of
384 // strings.
385 function getBetween(doc, start, end) {
386   var out = [], n = start.line
387   doc.iter(start.line, end.line + 1, function (line) {
388     var text = line.text
389     if (n == end.line) { text = text.slice(0, end.ch) }
390     if (n == start.line) { text = text.slice(start.ch) }
391     out.push(text)
392     ++n
393   })
394   return out
395 }
396 // Get the lines between from and to, as array of strings.
397 function getLines(doc, from, to) {
398   var out = []
399   doc.iter(from, to, function (line) { out.push(line.text) }) // iter aborts when callback returns truthy value
400   return out
401 }
402
403 // Update the height of a line, propagating the height change
404 // upwards to parent nodes.
405 function updateLineHeight(line, height) {
406   var diff = height - line.height
407   if (diff) { for (var n = line; n; n = n.parent) { n.height += diff } }
408 }
409
410 // Given a line object, find its line number by walking up through
411 // its parent links.
412 function lineNo(line) {
413   if (line.parent == null) { return null }
414   var cur = line.parent, no = indexOf(cur.lines, line)
415   for (var chunk = cur.parent; chunk; cur = chunk, chunk = chunk.parent) {
416     for (var i = 0;; ++i) {
417       if (chunk.children[i] == cur) { break }
418       no += chunk.children[i].chunkSize()
419     }
420   }
421   return no + cur.first
422 }
423
424 // Find the line at the given vertical position, using the height
425 // information in the document tree.
426 function lineAtHeight(chunk, h) {
427   var n = chunk.first
428   outer: do {
429     for (var i$1 = 0; i$1 < chunk.children.length; ++i$1) {
430       var child = chunk.children[i$1], ch = child.height
431       if (h < ch) { chunk = child; continue outer }
432       h -= ch
433       n += child.chunkSize()
434     }
435     return n
436   } while (!chunk.lines)
437   var i = 0
438   for (; i < chunk.lines.length; ++i) {
439     var line = chunk.lines[i], lh = line.height
440     if (h < lh) { break }
441     h -= lh
442   }
443   return n + i
444 }
445
446 function isLine(doc, l) {return l >= doc.first && l < doc.first + doc.size}
447
448 function lineNumberFor(options, i) {
449   return String(options.lineNumberFormatter(i + options.firstLineNumber))
450 }
451
452 // A Pos instance represents a position within the text.
453 function Pos (line, ch) {
454   if (!(this instanceof Pos)) { return new Pos(line, ch) }
455   this.line = line; this.ch = ch
456 }
457
458 // Compare two positions, return 0 if they are the same, a negative
459 // number when a is less, and a positive number otherwise.
460 function cmp(a, b) { return a.line - b.line || a.ch - b.ch }
461
462 function copyPos(x) {return Pos(x.line, x.ch)}
463 function maxPos(a, b) { return cmp(a, b) < 0 ? b : a }
464 function minPos(a, b) { return cmp(a, b) < 0 ? a : b }
465
466 // Most of the external API clips given positions to make sure they
467 // actually exist within the document.
468 function clipLine(doc, n) {return Math.max(doc.first, Math.min(n, doc.first + doc.size - 1))}
469 function clipPos(doc, pos) {
470   if (pos.line < doc.first) { return Pos(doc.first, 0) }
471   var last = doc.first + doc.size - 1
472   if (pos.line > last) { return Pos(last, getLine(doc, last).text.length) }
473   return clipToLen(pos, getLine(doc, pos.line).text.length)
474 }
475 function clipToLen(pos, linelen) {
476   var ch = pos.ch
477   if (ch == null || ch > linelen) { return Pos(pos.line, linelen) }
478   else if (ch < 0) { return Pos(pos.line, 0) }
479   else { return pos }
480 }
481 function clipPosArray(doc, array) {
482   var out = []
483   for (var i = 0; i < array.length; i++) { out[i] = clipPos(doc, array[i]) }
484   return out
485 }
486
487 // Optimize some code when these features are not used.
488 var sawReadOnlySpans = false;
489 var sawCollapsedSpans = false;
490 function seeReadOnlySpans() {
491   sawReadOnlySpans = true
492 }
493
494 function seeCollapsedSpans() {
495   sawCollapsedSpans = true
496 }
497
498 // TEXTMARKER SPANS
499
500 function MarkedSpan(marker, from, to) {
501   this.marker = marker
502   this.from = from; this.to = to
503 }
504
505 // Search an array of spans for a span matching the given marker.
506 function getMarkedSpanFor(spans, marker) {
507   if (spans) { for (var i = 0; i < spans.length; ++i) {
508     var span = spans[i]
509     if (span.marker == marker) { return span }
510   } }
511 }
512 // Remove a span from an array, returning undefined if no spans are
513 // left (we don't store arrays for lines without spans).
514 function removeMarkedSpan(spans, span) {
515   var r
516   for (var i = 0; i < spans.length; ++i)
517     { if (spans[i] != span) { (r || (r = [])).push(spans[i]) } }
518   return r
519 }
520 // Add a span to a line.
521 function addMarkedSpan(line, span) {
522   line.markedSpans = line.markedSpans ? line.markedSpans.concat([span]) : [span]
523   span.marker.attachLine(line)
524 }
525
526 // Used for the algorithm that adjusts markers for a change in the
527 // document. These functions cut an array of spans at a given
528 // character position, returning an array of remaining chunks (or
529 // undefined if nothing remains).
530 function markedSpansBefore(old, startCh, isInsert) {
531   var nw
532   if (old) { for (var i = 0; i < old.length; ++i) {
533     var span = old[i], marker = span.marker
534     var startsBefore = span.from == null || (marker.inclusiveLeft ? span.from <= startCh : span.from < startCh)
535     if (startsBefore || span.from == startCh && marker.type == "bookmark" && (!isInsert || !span.marker.insertLeft)) {
536       var endsAfter = span.to == null || (marker.inclusiveRight ? span.to >= startCh : span.to > startCh)
537       ;(nw || (nw = [])).push(new MarkedSpan(marker, span.from, endsAfter ? null : span.to))
538     }
539   } }
540   return nw
541 }
542 function markedSpansAfter(old, endCh, isInsert) {
543   var nw
544   if (old) { for (var i = 0; i < old.length; ++i) {
545     var span = old[i], marker = span.marker
546     var endsAfter = span.to == null || (marker.inclusiveRight ? span.to >= endCh : span.to > endCh)
547     if (endsAfter || span.from == endCh && marker.type == "bookmark" && (!isInsert || span.marker.insertLeft)) {
548       var startsBefore = span.from == null || (marker.inclusiveLeft ? span.from <= endCh : span.from < endCh)
549       ;(nw || (nw = [])).push(new MarkedSpan(marker, startsBefore ? null : span.from - endCh,
550                                             span.to == null ? null : span.to - endCh))
551     }
552   } }
553   return nw
554 }
555
556 // Given a change object, compute the new set of marker spans that
557 // cover the line in which the change took place. Removes spans
558 // entirely within the change, reconnects spans belonging to the
559 // same marker that appear on both sides of the change, and cuts off
560 // spans partially within the change. Returns an array of span
561 // arrays with one element for each line in (after) the change.
562 function stretchSpansOverChange(doc, change) {
563   if (change.full) { return null }
564   var oldFirst = isLine(doc, change.from.line) && getLine(doc, change.from.line).markedSpans
565   var oldLast = isLine(doc, change.to.line) && getLine(doc, change.to.line).markedSpans
566   if (!oldFirst && !oldLast) { return null }
567
568   var startCh = change.from.ch, endCh = change.to.ch, isInsert = cmp(change.from, change.to) == 0
569   // Get the spans that 'stick out' on both sides
570   var first = markedSpansBefore(oldFirst, startCh, isInsert)
571   var last = markedSpansAfter(oldLast, endCh, isInsert)
572
573   // Next, merge those two ends
574   var sameLine = change.text.length == 1, offset = lst(change.text).length + (sameLine ? startCh : 0)
575   if (first) {
576     // Fix up .to properties of first
577     for (var i = 0; i < first.length; ++i) {
578       var span = first[i]
579       if (span.to == null) {
580         var found = getMarkedSpanFor(last, span.marker)
581         if (!found) { span.to = startCh }
582         else if (sameLine) { span.to = found.to == null ? null : found.to + offset }
583       }
584     }
585   }
586   if (last) {
587     // Fix up .from in last (or move them into first in case of sameLine)
588     for (var i$1 = 0; i$1 < last.length; ++i$1) {
589       var span$1 = last[i$1]
590       if (span$1.to != null) { span$1.to += offset }
591       if (span$1.from == null) {
592         var found$1 = getMarkedSpanFor(first, span$1.marker)
593         if (!found$1) {
594           span$1.from = offset
595           if (sameLine) { (first || (first = [])).push(span$1) }
596         }
597       } else {
598         span$1.from += offset
599         if (sameLine) { (first || (first = [])).push(span$1) }
600       }
601     }
602   }
603   // Make sure we didn't create any zero-length spans
604   if (first) { first = clearEmptySpans(first) }
605   if (last && last != first) { last = clearEmptySpans(last) }
606
607   var newMarkers = [first]
608   if (!sameLine) {
609     // Fill gap with whole-line-spans
610     var gap = change.text.length - 2, gapMarkers
611     if (gap > 0 && first)
612       { for (var i$2 = 0; i$2 < first.length; ++i$2)
613         { if (first[i$2].to == null)
614           { (gapMarkers || (gapMarkers = [])).push(new MarkedSpan(first[i$2].marker, null, null)) } } }
615     for (var i$3 = 0; i$3 < gap; ++i$3)
616       { newMarkers.push(gapMarkers) }
617     newMarkers.push(last)
618   }
619   return newMarkers
620 }
621
622 // Remove spans that are empty and don't have a clearWhenEmpty
623 // option of false.
624 function clearEmptySpans(spans) {
625   for (var i = 0; i < spans.length; ++i) {
626     var span = spans[i]
627     if (span.from != null && span.from == span.to && span.marker.clearWhenEmpty !== false)
628       { spans.splice(i--, 1) }
629   }
630   if (!spans.length) { return null }
631   return spans
632 }
633
634 // Used to 'clip' out readOnly ranges when making a change.
635 function removeReadOnlyRanges(doc, from, to) {
636   var markers = null
637   doc.iter(from.line, to.line + 1, function (line) {
638     if (line.markedSpans) { for (var i = 0; i < line.markedSpans.length; ++i) {
639       var mark = line.markedSpans[i].marker
640       if (mark.readOnly && (!markers || indexOf(markers, mark) == -1))
641         { (markers || (markers = [])).push(mark) }
642     } }
643   })
644   if (!markers) { return null }
645   var parts = [{from: from, to: to}]
646   for (var i = 0; i < markers.length; ++i) {
647     var mk = markers[i], m = mk.find(0)
648     for (var j = 0; j < parts.length; ++j) {
649       var p = parts[j]
650       if (cmp(p.to, m.from) < 0 || cmp(p.from, m.to) > 0) { continue }
651       var newParts = [j, 1], dfrom = cmp(p.from, m.from), dto = cmp(p.to, m.to)
652       if (dfrom < 0 || !mk.inclusiveLeft && !dfrom)
653         { newParts.push({from: p.from, to: m.from}) }
654       if (dto > 0 || !mk.inclusiveRight && !dto)
655         { newParts.push({from: m.to, to: p.to}) }
656       parts.splice.apply(parts, newParts)
657       j += newParts.length - 1
658     }
659   }
660   return parts
661 }
662
663 // Connect or disconnect spans from a line.
664 function detachMarkedSpans(line) {
665   var spans = line.markedSpans
666   if (!spans) { return }
667   for (var i = 0; i < spans.length; ++i)
668     { spans[i].marker.detachLine(line) }
669   line.markedSpans = null
670 }
671 function attachMarkedSpans(line, spans) {
672   if (!spans) { return }
673   for (var i = 0; i < spans.length; ++i)
674     { spans[i].marker.attachLine(line) }
675   line.markedSpans = spans
676 }
677
678 // Helpers used when computing which overlapping collapsed span
679 // counts as the larger one.
680 function extraLeft(marker) { return marker.inclusiveLeft ? -1 : 0 }
681 function extraRight(marker) { return marker.inclusiveRight ? 1 : 0 }
682
683 // Returns a number indicating which of two overlapping collapsed
684 // spans is larger (and thus includes the other). Falls back to
685 // comparing ids when the spans cover exactly the same range.
686 function compareCollapsedMarkers(a, b) {
687   var lenDiff = a.lines.length - b.lines.length
688   if (lenDiff != 0) { return lenDiff }
689   var aPos = a.find(), bPos = b.find()
690   var fromCmp = cmp(aPos.from, bPos.from) || extraLeft(a) - extraLeft(b)
691   if (fromCmp) { return -fromCmp }
692   var toCmp = cmp(aPos.to, bPos.to) || extraRight(a) - extraRight(b)
693   if (toCmp) { return toCmp }
694   return b.id - a.id
695 }
696
697 // Find out whether a line ends or starts in a collapsed span. If
698 // so, return the marker for that span.
699 function collapsedSpanAtSide(line, start) {
700   var sps = sawCollapsedSpans && line.markedSpans, found
701   if (sps) { for (var sp = (void 0), i = 0; i < sps.length; ++i) {
702     sp = sps[i]
703     if (sp.marker.collapsed && (start ? sp.from : sp.to) == null &&
704         (!found || compareCollapsedMarkers(found, sp.marker) < 0))
705       { found = sp.marker }
706   } }
707   return found
708 }
709 function collapsedSpanAtStart(line) { return collapsedSpanAtSide(line, true) }
710 function collapsedSpanAtEnd(line) { return collapsedSpanAtSide(line, false) }
711
712 // Test whether there exists a collapsed span that partially
713 // overlaps (covers the start or end, but not both) of a new span.
714 // Such overlap is not allowed.
715 function conflictingCollapsedRange(doc, lineNo, from, to, marker) {
716   var line = getLine(doc, lineNo)
717   var sps = sawCollapsedSpans && line.markedSpans
718   if (sps) { for (var i = 0; i < sps.length; ++i) {
719     var sp = sps[i]
720     if (!sp.marker.collapsed) { continue }
721     var found = sp.marker.find(0)
722     var fromCmp = cmp(found.from, from) || extraLeft(sp.marker) - extraLeft(marker)
723     var toCmp = cmp(found.to, to) || extraRight(sp.marker) - extraRight(marker)
724     if (fromCmp >= 0 && toCmp <= 0 || fromCmp <= 0 && toCmp >= 0) { continue }
725     if (fromCmp <= 0 && (sp.marker.inclusiveRight && marker.inclusiveLeft ? cmp(found.to, from) >= 0 : cmp(found.to, from) > 0) ||
726         fromCmp >= 0 && (sp.marker.inclusiveRight && marker.inclusiveLeft ? cmp(found.from, to) <= 0 : cmp(found.from, to) < 0))
727       { return true }
728   } }
729 }
730
731 // A visual line is a line as drawn on the screen. Folding, for
732 // example, can cause multiple logical lines to appear on the same
733 // visual line. This finds the start of the visual line that the
734 // given line is part of (usually that is the line itself).
735 function visualLine(line) {
736   var merged
737   while (merged = collapsedSpanAtStart(line))
738     { line = merged.find(-1, true).line }
739   return line
740 }
741
742 // Returns an array of logical lines that continue the visual line
743 // started by the argument, or undefined if there are no such lines.
744 function visualLineContinued(line) {
745   var merged, lines
746   while (merged = collapsedSpanAtEnd(line)) {
747     line = merged.find(1, true).line
748     ;(lines || (lines = [])).push(line)
749   }
750   return lines
751 }
752
753 // Get the line number of the start of the visual line that the
754 // given line number is part of.
755 function visualLineNo(doc, lineN) {
756   var line = getLine(doc, lineN), vis = visualLine(line)
757   if (line == vis) { return lineN }
758   return lineNo(vis)
759 }
760
761 // Get the line number of the start of the next visual line after
762 // the given line.
763 function visualLineEndNo(doc, lineN) {
764   if (lineN > doc.lastLine()) { return lineN }
765   var line = getLine(doc, lineN), merged
766   if (!lineIsHidden(doc, line)) { return lineN }
767   while (merged = collapsedSpanAtEnd(line))
768     { line = merged.find(1, true).line }
769   return lineNo(line) + 1
770 }
771
772 // Compute whether a line is hidden. Lines count as hidden when they
773 // are part of a visual line that starts with another line, or when
774 // they are entirely covered by collapsed, non-widget span.
775 function lineIsHidden(doc, line) {
776   var sps = sawCollapsedSpans && line.markedSpans
777   if (sps) { for (var sp = (void 0), i = 0; i < sps.length; ++i) {
778     sp = sps[i]
779     if (!sp.marker.collapsed) { continue }
780     if (sp.from == null) { return true }
781     if (sp.marker.widgetNode) { continue }
782     if (sp.from == 0 && sp.marker.inclusiveLeft && lineIsHiddenInner(doc, line, sp))
783       { return true }
784   } }
785 }
786 function lineIsHiddenInner(doc, line, span) {
787   if (span.to == null) {
788     var end = span.marker.find(1, true)
789     return lineIsHiddenInner(doc, end.line, getMarkedSpanFor(end.line.markedSpans, span.marker))
790   }
791   if (span.marker.inclusiveRight && span.to == line.text.length)
792     { return true }
793   for (var sp = (void 0), i = 0; i < line.markedSpans.length; ++i) {
794     sp = line.markedSpans[i]
795     if (sp.marker.collapsed && !sp.marker.widgetNode && sp.from == span.to &&
796         (sp.to == null || sp.to != span.from) &&
797         (sp.marker.inclusiveLeft || span.marker.inclusiveRight) &&
798         lineIsHiddenInner(doc, line, sp)) { return true }
799   }
800 }
801
802 // Find the height above the given line.
803 function heightAtLine(lineObj) {
804   lineObj = visualLine(lineObj)
805
806   var h = 0, chunk = lineObj.parent
807   for (var i = 0; i < chunk.lines.length; ++i) {
808     var line = chunk.lines[i]
809     if (line == lineObj) { break }
810     else { h += line.height }
811   }
812   for (var p = chunk.parent; p; chunk = p, p = chunk.parent) {
813     for (var i$1 = 0; i$1 < p.children.length; ++i$1) {
814       var cur = p.children[i$1]
815       if (cur == chunk) { break }
816       else { h += cur.height }
817     }
818   }
819   return h
820 }
821
822 // Compute the character length of a line, taking into account
823 // collapsed ranges (see markText) that might hide parts, and join
824 // other lines onto it.
825 function lineLength(line) {
826   if (line.height == 0) { return 0 }
827   var len = line.text.length, merged, cur = line
828   while (merged = collapsedSpanAtStart(cur)) {
829     var found = merged.find(0, true)
830     cur = found.from.line
831     len += found.from.ch - found.to.ch
832   }
833   cur = line
834   while (merged = collapsedSpanAtEnd(cur)) {
835     var found$1 = merged.find(0, true)
836     len -= cur.text.length - found$1.from.ch
837     cur = found$1.to.line
838     len += cur.text.length - found$1.to.ch
839   }
840   return len
841 }
842
843 // Find the longest line in the document.
844 function findMaxLine(cm) {
845   var d = cm.display, doc = cm.doc
846   d.maxLine = getLine(doc, doc.first)
847   d.maxLineLength = lineLength(d.maxLine)
848   d.maxLineChanged = true
849   doc.iter(function (line) {
850     var len = lineLength(line)
851     if (len > d.maxLineLength) {
852       d.maxLineLength = len
853       d.maxLine = line
854     }
855   })
856 }
857
858 // BIDI HELPERS
859
860 function iterateBidiSections(order, from, to, f) {
861   if (!order) { return f(from, to, "ltr") }
862   var found = false
863   for (var i = 0; i < order.length; ++i) {
864     var part = order[i]
865     if (part.from < to && part.to > from || from == to && part.to == from) {
866       f(Math.max(part.from, from), Math.min(part.to, to), part.level == 1 ? "rtl" : "ltr")
867       found = true
868     }
869   }
870   if (!found) { f(from, to, "ltr") }
871 }
872
873 function bidiLeft(part) { return part.level % 2 ? part.to : part.from }
874 function bidiRight(part) { return part.level % 2 ? part.from : part.to }
875
876 function lineLeft(line) { var order = getOrder(line); return order ? bidiLeft(order[0]) : 0 }
877 function lineRight(line) {
878   var order = getOrder(line)
879   if (!order) { return line.text.length }
880   return bidiRight(lst(order))
881 }
882
883 function compareBidiLevel(order, a, b) {
884   var linedir = order[0].level
885   if (a == linedir) { return true }
886   if (b == linedir) { return false }
887   return a < b
888 }
889
890 var bidiOther = null
891 function getBidiPartAt(order, pos) {
892   var found
893   bidiOther = null
894   for (var i = 0; i < order.length; ++i) {
895     var cur = order[i]
896     if (cur.from < pos && cur.to > pos) { return i }
897     if ((cur.from == pos || cur.to == pos)) {
898       if (found == null) {
899         found = i
900       } else if (compareBidiLevel(order, cur.level, order[found].level)) {
901         if (cur.from != cur.to) { bidiOther = found }
902         return i
903       } else {
904         if (cur.from != cur.to) { bidiOther = i }
905         return found
906       }
907     }
908   }
909   return found
910 }
911
912 function moveInLine(line, pos, dir, byUnit) {
913   if (!byUnit) { return pos + dir }
914   do { pos += dir }
915   while (pos > 0 && isExtendingChar(line.text.charAt(pos)))
916   return pos
917 }
918
919 // This is needed in order to move 'visually' through bi-directional
920 // text -- i.e., pressing left should make the cursor go left, even
921 // when in RTL text. The tricky part is the 'jumps', where RTL and
922 // LTR text touch each other. This often requires the cursor offset
923 // to move more than one unit, in order to visually move one unit.
924 function moveVisually(line, start, dir, byUnit) {
925   var bidi = getOrder(line)
926   if (!bidi) { return moveLogically(line, start, dir, byUnit) }
927   var pos = getBidiPartAt(bidi, start), part = bidi[pos]
928   var target = moveInLine(line, start, part.level % 2 ? -dir : dir, byUnit)
929
930   for (;;) {
931     if (target > part.from && target < part.to) { return target }
932     if (target == part.from || target == part.to) {
933       if (getBidiPartAt(bidi, target) == pos) { return target }
934       part = bidi[pos += dir]
935       return (dir > 0) == part.level % 2 ? part.to : part.from
936     } else {
937       part = bidi[pos += dir]
938       if (!part) { return null }
939       if ((dir > 0) == part.level % 2)
940         { target = moveInLine(line, part.to, -1, byUnit) }
941       else
942         { target = moveInLine(line, part.from, 1, byUnit) }
943     }
944   }
945 }
946
947 function moveLogically(line, start, dir, byUnit) {
948   var target = start + dir
949   if (byUnit) { while (target > 0 && isExtendingChar(line.text.charAt(target))) { target += dir } }
950   return target < 0 || target > line.text.length ? null : target
951 }
952
953 // Bidirectional ordering algorithm
954 // See http://unicode.org/reports/tr9/tr9-13.html for the algorithm
955 // that this (partially) implements.
956
957 // One-char codes used for character types:
958 // L (L):   Left-to-Right
959 // R (R):   Right-to-Left
960 // r (AL):  Right-to-Left Arabic
961 // 1 (EN):  European Number
962 // + (ES):  European Number Separator
963 // % (ET):  European Number Terminator
964 // n (AN):  Arabic Number
965 // , (CS):  Common Number Separator
966 // m (NSM): Non-Spacing Mark
967 // b (BN):  Boundary Neutral
968 // s (B):   Paragraph Separator
969 // t (S):   Segment Separator
970 // w (WS):  Whitespace
971 // N (ON):  Other Neutrals
972
973 // Returns null if characters are ordered as they appear
974 // (left-to-right), or an array of sections ({from, to, level}
975 // objects) in the order in which they occur visually.
976 var bidiOrdering = (function() {
977   // Character types for codepoints 0 to 0xff
978   var lowTypes = "bbbbbbbbbtstwsbbbbbbbbbbbbbbssstwNN%%%NNNNNN,N,N1111111111NNNNNNNLLLLLLLLLLLLLLLLLLLLLLLLLLNNNNNNLLLLLLLLLLLLLLLLLLLLLLLLLLNNNNbbbbbbsbbbbbbbbbbbbbbbbbbbbbbbbbb,N%%%%NNNNLNNNNN%%11NLNNN1LNNNNNLLLLLLLLLLLLLLLLLLLLLLLNLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLN"
979   // Character types for codepoints 0x600 to 0x6f9
980   var arabicTypes = "nnnnnnNNr%%r,rNNmmmmmmmmmmmrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrmmmmmmmmmmmmmmmmmmmmmnnnnnnnnnn%nnrrrmrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrmmmmmmmnNmmmmmmrrmmNmmmmrr1111111111"
981   function charType(code) {
982     if (code <= 0xf7) { return lowTypes.charAt(code) }
983     else if (0x590 <= code && code <= 0x5f4) { return "R" }
984     else if (0x600 <= code && code <= 0x6f9) { return arabicTypes.charAt(code - 0x600) }
985     else if (0x6ee <= code && code <= 0x8ac) { return "r" }
986     else if (0x2000 <= code && code <= 0x200b) { return "w" }
987     else if (code == 0x200c) { return "b" }
988     else { return "L" }
989   }
990
991   var bidiRE = /[\u0590-\u05f4\u0600-\u06ff\u0700-\u08ac]/;
992   var isNeutral = /[stwN]/, isStrong = /[LRr]/, countsAsLeft = /[Lb1n]/, countsAsNum = /[1n]/;
993   // Browsers seem to always treat the boundaries of block elements as being L.
994   var outerType = "L"
995
996   function BidiSpan(level, from, to) {
997     this.level = level
998     this.from = from; this.to = to
999   }
1000
1001   return function(str) {
1002     if (!bidiRE.test(str)) { return false }
1003     var len = str.length, types = []
1004     for (var i = 0; i < len; ++i)
1005       { types.push(charType(str.charCodeAt(i))) }
1006
1007     // W1. Examine each non-spacing mark (NSM) in the level run, and
1008     // change the type of the NSM to the type of the previous
1009     // character. If the NSM is at the start of the level run, it will
1010     // get the type of sor.
1011     for (var i$1 = 0, prev = outerType; i$1 < len; ++i$1) {
1012       var type = types[i$1]
1013       if (type == "m") { types[i$1] = prev }
1014       else { prev = type }
1015     }
1016
1017     // W2. Search backwards from each instance of a European number
1018     // until the first strong type (R, L, AL, or sor) is found. If an
1019     // AL is found, change the type of the European number to Arabic
1020     // number.
1021     // W3. Change all ALs to R.
1022     for (var i$2 = 0, cur = outerType; i$2 < len; ++i$2) {
1023       var type$1 = types[i$2]
1024       if (type$1 == "1" && cur == "r") { types[i$2] = "n" }
1025       else if (isStrong.test(type$1)) { cur = type$1; if (type$1 == "r") { types[i$2] = "R" } }
1026     }
1027
1028     // W4. A single European separator between two European numbers
1029     // changes to a European number. A single common separator between
1030     // two numbers of the same type changes to that type.
1031     for (var i$3 = 1, prev$1 = types[0]; i$3 < len - 1; ++i$3) {
1032       var type$2 = types[i$3]
1033       if (type$2 == "+" && prev$1 == "1" && types[i$3+1] == "1") { types[i$3] = "1" }
1034       else if (type$2 == "," && prev$1 == types[i$3+1] &&
1035                (prev$1 == "1" || prev$1 == "n")) { types[i$3] = prev$1 }
1036       prev$1 = type$2
1037     }
1038
1039     // W5. A sequence of European terminators adjacent to European
1040     // numbers changes to all European numbers.
1041     // W6. Otherwise, separators and terminators change to Other
1042     // Neutral.
1043     for (var i$4 = 0; i$4 < len; ++i$4) {
1044       var type$3 = types[i$4]
1045       if (type$3 == ",") { types[i$4] = "N" }
1046       else if (type$3 == "%") {
1047         var end = (void 0)
1048         for (end = i$4 + 1; end < len && types[end] == "%"; ++end) {}
1049         var replace = (i$4 && types[i$4-1] == "!") || (end < len && types[end] == "1") ? "1" : "N"
1050         for (var j = i$4; j < end; ++j) { types[j] = replace }
1051         i$4 = end - 1
1052       }
1053     }
1054
1055     // W7. Search backwards from each instance of a European number
1056     // until the first strong type (R, L, or sor) is found. If an L is
1057     // found, then change the type of the European number to L.
1058     for (var i$5 = 0, cur$1 = outerType; i$5 < len; ++i$5) {
1059       var type$4 = types[i$5]
1060       if (cur$1 == "L" && type$4 == "1") { types[i$5] = "L" }
1061       else if (isStrong.test(type$4)) { cur$1 = type$4 }
1062     }
1063
1064     // N1. A sequence of neutrals takes the direction of the
1065     // surrounding strong text if the text on both sides has the same
1066     // direction. European and Arabic numbers act as if they were R in
1067     // terms of their influence on neutrals. Start-of-level-run (sor)
1068     // and end-of-level-run (eor) are used at level run boundaries.
1069     // N2. Any remaining neutrals take the embedding direction.
1070     for (var i$6 = 0; i$6 < len; ++i$6) {
1071       if (isNeutral.test(types[i$6])) {
1072         var end$1 = (void 0)
1073         for (end$1 = i$6 + 1; end$1 < len && isNeutral.test(types[end$1]); ++end$1) {}
1074         var before = (i$6 ? types[i$6-1] : outerType) == "L"
1075         var after = (end$1 < len ? types[end$1] : outerType) == "L"
1076         var replace$1 = before || after ? "L" : "R"
1077         for (var j$1 = i$6; j$1 < end$1; ++j$1) { types[j$1] = replace$1 }
1078         i$6 = end$1 - 1
1079       }
1080     }
1081
1082     // Here we depart from the documented algorithm, in order to avoid
1083     // building up an actual levels array. Since there are only three
1084     // levels (0, 1, 2) in an implementation that doesn't take
1085     // explicit embedding into account, we can build up the order on
1086     // the fly, without following the level-based algorithm.
1087     var order = [], m
1088     for (var i$7 = 0; i$7 < len;) {
1089       if (countsAsLeft.test(types[i$7])) {
1090         var start = i$7
1091         for (++i$7; i$7 < len && countsAsLeft.test(types[i$7]); ++i$7) {}
1092         order.push(new BidiSpan(0, start, i$7))
1093       } else {
1094         var pos = i$7, at = order.length
1095         for (++i$7; i$7 < len && types[i$7] != "L"; ++i$7) {}
1096         for (var j$2 = pos; j$2 < i$7;) {
1097           if (countsAsNum.test(types[j$2])) {
1098             if (pos < j$2) { order.splice(at, 0, new BidiSpan(1, pos, j$2)) }
1099             var nstart = j$2
1100             for (++j$2; j$2 < i$7 && countsAsNum.test(types[j$2]); ++j$2) {}
1101             order.splice(at, 0, new BidiSpan(2, nstart, j$2))
1102             pos = j$2
1103           } else { ++j$2 }
1104         }
1105         if (pos < i$7) { order.splice(at, 0, new BidiSpan(1, pos, i$7)) }
1106       }
1107     }
1108     if (order[0].level == 1 && (m = str.match(/^\s+/))) {
1109       order[0].from = m[0].length
1110       order.unshift(new BidiSpan(0, 0, m[0].length))
1111     }
1112     if (lst(order).level == 1 && (m = str.match(/\s+$/))) {
1113       lst(order).to -= m[0].length
1114       order.push(new BidiSpan(0, len - m[0].length, len))
1115     }
1116     if (order[0].level == 2)
1117       { order.unshift(new BidiSpan(1, order[0].to, order[0].to)) }
1118     if (order[0].level != lst(order).level)
1119       { order.push(new BidiSpan(order[0].level, len, len)) }
1120
1121     return order
1122   }
1123 })()
1124
1125 // Get the bidi ordering for the given line (and cache it). Returns
1126 // false for lines that are fully left-to-right, and an array of
1127 // BidiSpan objects otherwise.
1128 function getOrder(line) {
1129   var order = line.order
1130   if (order == null) { order = line.order = bidiOrdering(line.text) }
1131   return order
1132 }
1133
1134 // EVENT HANDLING
1135
1136 // Lightweight event framework. on/off also work on DOM nodes,
1137 // registering native DOM handlers.
1138
1139 var noHandlers = []
1140
1141 var on = function(emitter, type, f) {
1142   if (emitter.addEventListener) {
1143     emitter.addEventListener(type, f, false)
1144   } else if (emitter.attachEvent) {
1145     emitter.attachEvent("on" + type, f)
1146   } else {
1147     var map = emitter._handlers || (emitter._handlers = {})
1148     map[type] = (map[type] || noHandlers).concat(f)
1149   }
1150 }
1151
1152 function getHandlers(emitter, type) {
1153   return emitter._handlers && emitter._handlers[type] || noHandlers
1154 }
1155
1156 function off(emitter, type, f) {
1157   if (emitter.removeEventListener) {
1158     emitter.removeEventListener(type, f, false)
1159   } else if (emitter.detachEvent) {
1160     emitter.detachEvent("on" + type, f)
1161   } else {
1162     var map = emitter._handlers, arr = map && map[type]
1163     if (arr) {
1164       var index = indexOf(arr, f)
1165       if (index > -1)
1166         { map[type] = arr.slice(0, index).concat(arr.slice(index + 1)) }
1167     }
1168   }
1169 }
1170
1171 function signal(emitter, type /*, values...*/) {
1172   var handlers = getHandlers(emitter, type)
1173   if (!handlers.length) { return }
1174   var args = Array.prototype.slice.call(arguments, 2)
1175   for (var i = 0; i < handlers.length; ++i) { handlers[i].apply(null, args) }
1176 }
1177
1178 // The DOM events that CodeMirror handles can be overridden by
1179 // registering a (non-DOM) handler on the editor for the event name,
1180 // and preventDefault-ing the event in that handler.
1181 function signalDOMEvent(cm, e, override) {
1182   if (typeof e == "string")
1183     { e = {type: e, preventDefault: function() { this.defaultPrevented = true }} }
1184   signal(cm, override || e.type, cm, e)
1185   return e_defaultPrevented(e) || e.codemirrorIgnore
1186 }
1187
1188 function signalCursorActivity(cm) {
1189   var arr = cm._handlers && cm._handlers.cursorActivity
1190   if (!arr) { return }
1191   var set = cm.curOp.cursorActivityHandlers || (cm.curOp.cursorActivityHandlers = [])
1192   for (var i = 0; i < arr.length; ++i) { if (indexOf(set, arr[i]) == -1)
1193     { set.push(arr[i]) } }
1194 }
1195
1196 function hasHandler(emitter, type) {
1197   return getHandlers(emitter, type).length > 0
1198 }
1199
1200 // Add on and off methods to a constructor's prototype, to make
1201 // registering events on such objects more convenient.
1202 function eventMixin(ctor) {
1203   ctor.prototype.on = function(type, f) {on(this, type, f)}
1204   ctor.prototype.off = function(type, f) {off(this, type, f)}
1205 }
1206
1207 // Due to the fact that we still support jurassic IE versions, some
1208 // compatibility wrappers are needed.
1209
1210 function e_preventDefault(e) {
1211   if (e.preventDefault) { e.preventDefault() }
1212   else { e.returnValue = false }
1213 }
1214 function e_stopPropagation(e) {
1215   if (e.stopPropagation) { e.stopPropagation() }
1216   else { e.cancelBubble = true }
1217 }
1218 function e_defaultPrevented(e) {
1219   return e.defaultPrevented != null ? e.defaultPrevented : e.returnValue == false
1220 }
1221 function e_stop(e) {e_preventDefault(e); e_stopPropagation(e)}
1222
1223 function e_target(e) {return e.target || e.srcElement}
1224 function e_button(e) {
1225   var b = e.which
1226   if (b == null) {
1227     if (e.button & 1) { b = 1 }
1228     else if (e.button & 2) { b = 3 }
1229     else if (e.button & 4) { b = 2 }
1230   }
1231   if (mac && e.ctrlKey && b == 1) { b = 3 }
1232   return b
1233 }
1234
1235 // Detect drag-and-drop
1236 var dragAndDrop = function() {
1237   // There is *some* kind of drag-and-drop support in IE6-8, but I
1238   // couldn't get it to work yet.
1239   if (ie && ie_version < 9) { return false }
1240   var div = elt('div')
1241   return "draggable" in div || "dragDrop" in div
1242 }()
1243
1244 var zwspSupported
1245 function zeroWidthElement(measure) {
1246   if (zwspSupported == null) {
1247     var test = elt("span", "\u200b")
1248     removeChildrenAndAdd(measure, elt("span", [test, document.createTextNode("x")]))
1249     if (measure.firstChild.offsetHeight != 0)
1250       { zwspSupported = test.offsetWidth <= 1 && test.offsetHeight > 2 && !(ie && ie_version < 8) }
1251   }
1252   var node = zwspSupported ? elt("span", "\u200b") :
1253     elt("span", "\u00a0", null, "display: inline-block; width: 1px; margin-right: -1px")
1254   node.setAttribute("cm-text", "")
1255   return node
1256 }
1257
1258 // Feature-detect IE's crummy client rect reporting for bidi text
1259 var badBidiRects
1260 function hasBadBidiRects(measure) {
1261   if (badBidiRects != null) { return badBidiRects }
1262   var txt = removeChildrenAndAdd(measure, document.createTextNode("A\u062eA"))
1263   var r0 = range(txt, 0, 1).getBoundingClientRect()
1264   var r1 = range(txt, 1, 2).getBoundingClientRect()
1265   removeChildren(measure)
1266   if (!r0 || r0.left == r0.right) { return false } // Safari returns null in some cases (#2780)
1267   return badBidiRects = (r1.right - r0.right < 3)
1268 }
1269
1270 // See if "".split is the broken IE version, if so, provide an
1271 // alternative way to split lines.
1272 var splitLinesAuto = "\n\nb".split(/\n/).length != 3 ? function (string) {
1273   var pos = 0, result = [], l = string.length
1274   while (pos <= l) {
1275     var nl = string.indexOf("\n", pos)
1276     if (nl == -1) { nl = string.length }
1277     var line = string.slice(pos, string.charAt(nl - 1) == "\r" ? nl - 1 : nl)
1278     var rt = line.indexOf("\r")
1279     if (rt != -1) {
1280       result.push(line.slice(0, rt))
1281       pos += rt + 1
1282     } else {
1283       result.push(line)
1284       pos = nl + 1
1285     }
1286   }
1287   return result
1288 } : function (string) { return string.split(/\r\n?|\n/); }
1289
1290 var hasSelection = window.getSelection ? function (te) {
1291   try { return te.selectionStart != te.selectionEnd }
1292   catch(e) { return false }
1293 } : function (te) {
1294   var range
1295   try {range = te.ownerDocument.selection.createRange()}
1296   catch(e) {}
1297   if (!range || range.parentElement() != te) { return false }
1298   return range.compareEndPoints("StartToEnd", range) != 0
1299 }
1300
1301 var hasCopyEvent = (function () {
1302   var e = elt("div")
1303   if ("oncopy" in e) { return true }
1304   e.setAttribute("oncopy", "return;")
1305   return typeof e.oncopy == "function"
1306 })()
1307
1308 var badZoomedRects = null
1309 function hasBadZoomedRects(measure) {
1310   if (badZoomedRects != null) { return badZoomedRects }
1311   var node = removeChildrenAndAdd(measure, elt("span", "x"))
1312   var normal = node.getBoundingClientRect()
1313   var fromRange = range(node, 0, 1).getBoundingClientRect()
1314   return badZoomedRects = Math.abs(normal.left - fromRange.left) > 1
1315 }
1316
1317 var modes = {};
1318 var mimeModes = {};
1319 // Extra arguments are stored as the mode's dependencies, which is
1320 // used by (legacy) mechanisms like loadmode.js to automatically
1321 // load a mode. (Preferred mechanism is the require/define calls.)
1322 function defineMode(name, mode) {
1323   if (arguments.length > 2)
1324     { mode.dependencies = Array.prototype.slice.call(arguments, 2) }
1325   modes[name] = mode
1326 }
1327
1328 function defineMIME(mime, spec) {
1329   mimeModes[mime] = spec
1330 }
1331
1332 // Given a MIME type, a {name, ...options} config object, or a name
1333 // string, return a mode config object.
1334 function resolveMode(spec) {
1335   if (typeof spec == "string" && mimeModes.hasOwnProperty(spec)) {
1336     spec = mimeModes[spec]
1337   } else if (spec && typeof spec.name == "string" && mimeModes.hasOwnProperty(spec.name)) {
1338     var found = mimeModes[spec.name]
1339     if (typeof found == "string") { found = {name: found} }
1340     spec = createObj(found, spec)
1341     spec.name = found.name
1342   } else if (typeof spec == "string" && /^[\w\-]+\/[\w\-]+\+xml$/.test(spec)) {
1343     return resolveMode("application/xml")
1344   } else if (typeof spec == "string" && /^[\w\-]+\/[\w\-]+\+json$/.test(spec)) {
1345     return resolveMode("application/json")
1346   }
1347   if (typeof spec == "string") { return {name: spec} }
1348   else { return spec || {name: "null"} }
1349 }
1350
1351 // Given a mode spec (anything that resolveMode accepts), find and
1352 // initialize an actual mode object.
1353 function getMode(options, spec) {
1354   spec = resolveMode(spec)
1355   var mfactory = modes[spec.name]
1356   if (!mfactory) { return getMode(options, "text/plain") }
1357   var modeObj = mfactory(options, spec)
1358   if (modeExtensions.hasOwnProperty(spec.name)) {
1359     var exts = modeExtensions[spec.name]
1360     for (var prop in exts) {
1361       if (!exts.hasOwnProperty(prop)) { continue }
1362       if (modeObj.hasOwnProperty(prop)) { modeObj["_" + prop] = modeObj[prop] }
1363       modeObj[prop] = exts[prop]
1364     }
1365   }
1366   modeObj.name = spec.name
1367   if (spec.helperType) { modeObj.helperType = spec.helperType }
1368   if (spec.modeProps) { for (var prop$1 in spec.modeProps)
1369     { modeObj[prop$1] = spec.modeProps[prop$1] } }
1370
1371   return modeObj
1372 }
1373
1374 // This can be used to attach properties to mode objects from
1375 // outside the actual mode definition.
1376 var modeExtensions = {}
1377 function extendMode(mode, properties) {
1378   var exts = modeExtensions.hasOwnProperty(mode) ? modeExtensions[mode] : (modeExtensions[mode] = {})
1379   copyObj(properties, exts)
1380 }
1381
1382 function copyState(mode, state) {
1383   if (state === true) { return state }
1384   if (mode.copyState) { return mode.copyState(state) }
1385   var nstate = {}
1386   for (var n in state) {
1387     var val = state[n]
1388     if (val instanceof Array) { val = val.concat([]) }
1389     nstate[n] = val
1390   }
1391   return nstate
1392 }
1393
1394 // Given a mode and a state (for that mode), find the inner mode and
1395 // state at the position that the state refers to.
1396 function innerMode(mode, state) {
1397   var info
1398   while (mode.innerMode) {
1399     info = mode.innerMode(state)
1400     if (!info || info.mode == mode) { break }
1401     state = info.state
1402     mode = info.mode
1403   }
1404   return info || {mode: mode, state: state}
1405 }
1406
1407 function startState(mode, a1, a2) {
1408   return mode.startState ? mode.startState(a1, a2) : true
1409 }
1410
1411 // STRING STREAM
1412
1413 // Fed to the mode parsers, provides helper functions to make
1414 // parsers more succinct.
1415
1416 var StringStream = function(string, tabSize) {
1417   this.pos = this.start = 0
1418   this.string = string
1419   this.tabSize = tabSize || 8
1420   this.lastColumnPos = this.lastColumnValue = 0
1421   this.lineStart = 0
1422 }
1423
1424 StringStream.prototype = {
1425   eol: function() {return this.pos >= this.string.length},
1426   sol: function() {return this.pos == this.lineStart},
1427   peek: function() {return this.string.charAt(this.pos) || undefined},
1428   next: function() {
1429     if (this.pos < this.string.length)
1430       { return this.string.charAt(this.pos++) }
1431   },
1432   eat: function(match) {
1433     var ch = this.string.charAt(this.pos)
1434     var ok
1435     if (typeof match == "string") { ok = ch == match }
1436     else { ok = ch && (match.test ? match.test(ch) : match(ch)) }
1437     if (ok) {++this.pos; return ch}
1438   },
1439   eatWhile: function(match) {
1440     var start = this.pos
1441     while (this.eat(match)){}
1442     return this.pos > start
1443   },
1444   eatSpace: function() {
1445     var this$1 = this;
1446
1447     var start = this.pos
1448     while (/[\s\u00a0]/.test(this.string.charAt(this.pos))) { ++this$1.pos }
1449     return this.pos > start
1450   },
1451   skipToEnd: function() {this.pos = this.string.length},
1452   skipTo: function(ch) {
1453     var found = this.string.indexOf(ch, this.pos)
1454     if (found > -1) {this.pos = found; return true}
1455   },
1456   backUp: function(n) {this.pos -= n},
1457   column: function() {
1458     if (this.lastColumnPos < this.start) {
1459       this.lastColumnValue = countColumn(this.string, this.start, this.tabSize, this.lastColumnPos, this.lastColumnValue)
1460       this.lastColumnPos = this.start
1461     }
1462     return this.lastColumnValue - (this.lineStart ? countColumn(this.string, this.lineStart, this.tabSize) : 0)
1463   },
1464   indentation: function() {
1465     return countColumn(this.string, null, this.tabSize) -
1466       (this.lineStart ? countColumn(this.string, this.lineStart, this.tabSize) : 0)
1467   },
1468   match: function(pattern, consume, caseInsensitive) {
1469     if (typeof pattern == "string") {
1470       var cased = function (str) { return caseInsensitive ? str.toLowerCase() : str; }
1471       var substr = this.string.substr(this.pos, pattern.length)
1472       if (cased(substr) == cased(pattern)) {
1473         if (consume !== false) { this.pos += pattern.length }
1474         return true
1475       }
1476     } else {
1477       var match = this.string.slice(this.pos).match(pattern)
1478       if (match && match.index > 0) { return null }
1479       if (match && consume !== false) { this.pos += match[0].length }
1480       return match
1481     }
1482   },
1483   current: function(){return this.string.slice(this.start, this.pos)},
1484   hideFirstChars: function(n, inner) {
1485     this.lineStart += n
1486     try { return inner() }
1487     finally { this.lineStart -= n }
1488   }
1489 }
1490
1491 // Compute a style array (an array starting with a mode generation
1492 // -- for invalidation -- followed by pairs of end positions and
1493 // style strings), which is used to highlight the tokens on the
1494 // line.
1495 function highlightLine(cm, line, state, forceToEnd) {
1496   // A styles array always starts with a number identifying the
1497   // mode/overlays that it is based on (for easy invalidation).
1498   var st = [cm.state.modeGen], lineClasses = {}
1499   // Compute the base array of styles
1500   runMode(cm, line.text, cm.doc.mode, state, function (end, style) { return st.push(end, style); },
1501     lineClasses, forceToEnd)
1502
1503   // Run overlays, adjust style array.
1504   var loop = function ( o ) {
1505     var overlay = cm.state.overlays[o], i = 1, at = 0
1506     runMode(cm, line.text, overlay.mode, true, function (end, style) {
1507       var start = i
1508       // Ensure there's a token end at the current position, and that i points at it
1509       while (at < end) {
1510         var i_end = st[i]
1511         if (i_end > end)
1512           { st.splice(i, 1, end, st[i+1], i_end) }
1513         i += 2
1514         at = Math.min(end, i_end)
1515       }
1516       if (!style) { return }
1517       if (overlay.opaque) {
1518         st.splice(start, i - start, end, "overlay " + style)
1519         i = start + 2
1520       } else {
1521         for (; start < i; start += 2) {
1522           var cur = st[start+1]
1523           st[start+1] = (cur ? cur + " " : "") + "overlay " + style
1524         }
1525       }
1526     }, lineClasses)
1527   };
1528
1529   for (var o = 0; o < cm.state.overlays.length; ++o) loop( o );
1530
1531   return {styles: st, classes: lineClasses.bgClass || lineClasses.textClass ? lineClasses : null}
1532 }
1533
1534 function getLineStyles(cm, line, updateFrontier) {
1535   if (!line.styles || line.styles[0] != cm.state.modeGen) {
1536     var state = getStateBefore(cm, lineNo(line))
1537     var result = highlightLine(cm, line, line.text.length > cm.options.maxHighlightLength ? copyState(cm.doc.mode, state) : state)
1538     line.stateAfter = state
1539     line.styles = result.styles
1540     if (result.classes) { line.styleClasses = result.classes }
1541     else if (line.styleClasses) { line.styleClasses = null }
1542     if (updateFrontier === cm.doc.frontier) { cm.doc.frontier++ }
1543   }
1544   return line.styles
1545 }
1546
1547 function getStateBefore(cm, n, precise) {
1548   var doc = cm.doc, display = cm.display
1549   if (!doc.mode.startState) { return true }
1550   var pos = findStartLine(cm, n, precise), state = pos > doc.first && getLine(doc, pos-1).stateAfter
1551   if (!state) { state = startState(doc.mode) }
1552   else { state = copyState(doc.mode, state) }
1553   doc.iter(pos, n, function (line) {
1554     processLine(cm, line.text, state)
1555     var save = pos == n - 1 || pos % 5 == 0 || pos >= display.viewFrom && pos < display.viewTo
1556     line.stateAfter = save ? copyState(doc.mode, state) : null
1557     ++pos
1558   })
1559   if (precise) { doc.frontier = pos }
1560   return state
1561 }
1562
1563 // Lightweight form of highlight -- proceed over this line and
1564 // update state, but don't save a style array. Used for lines that
1565 // aren't currently visible.
1566 function processLine(cm, text, state, startAt) {
1567   var mode = cm.doc.mode
1568   var stream = new StringStream(text, cm.options.tabSize)
1569   stream.start = stream.pos = startAt || 0
1570   if (text == "") { callBlankLine(mode, state) }
1571   while (!stream.eol()) {
1572     readToken(mode, stream, state)
1573     stream.start = stream.pos
1574   }
1575 }
1576
1577 function callBlankLine(mode, state) {
1578   if (mode.blankLine) { return mode.blankLine(state) }
1579   if (!mode.innerMode) { return }
1580   var inner = innerMode(mode, state)
1581   if (inner.mode.blankLine) { return inner.mode.blankLine(inner.state) }
1582 }
1583
1584 function readToken(mode, stream, state, inner) {
1585   for (var i = 0; i < 10; i++) {
1586     if (inner) { inner[0] = innerMode(mode, state).mode }
1587     var style = mode.token(stream, state)
1588     if (stream.pos > stream.start) { return style }
1589   }
1590   throw new Error("Mode " + mode.name + " failed to advance stream.")
1591 }
1592
1593 // Utility for getTokenAt and getLineTokens
1594 function takeToken(cm, pos, precise, asArray) {
1595   var getObj = function (copy) { return ({
1596     start: stream.start, end: stream.pos,
1597     string: stream.current(),
1598     type: style || null,
1599     state: copy ? copyState(doc.mode, state) : state
1600   }); }
1601
1602   var doc = cm.doc, mode = doc.mode, style
1603   pos = clipPos(doc, pos)
1604   var line = getLine(doc, pos.line), state = getStateBefore(cm, pos.line, precise)
1605   var stream = new StringStream(line.text, cm.options.tabSize), tokens
1606   if (asArray) { tokens = [] }
1607   while ((asArray || stream.pos < pos.ch) && !stream.eol()) {
1608     stream.start = stream.pos
1609     style = readToken(mode, stream, state)
1610     if (asArray) { tokens.push(getObj(true)) }
1611   }
1612   return asArray ? tokens : getObj()
1613 }
1614
1615 function extractLineClasses(type, output) {
1616   if (type) { for (;;) {
1617     var lineClass = type.match(/(?:^|\s+)line-(background-)?(\S+)/)
1618     if (!lineClass) { break }
1619     type = type.slice(0, lineClass.index) + type.slice(lineClass.index + lineClass[0].length)
1620     var prop = lineClass[1] ? "bgClass" : "textClass"
1621     if (output[prop] == null)
1622       { output[prop] = lineClass[2] }
1623     else if (!(new RegExp("(?:^|\s)" + lineClass[2] + "(?:$|\s)")).test(output[prop]))
1624       { output[prop] += " " + lineClass[2] }
1625   } }
1626   return type
1627 }
1628
1629 // Run the given mode's parser over a line, calling f for each token.
1630 function runMode(cm, text, mode, state, f, lineClasses, forceToEnd) {
1631   var flattenSpans = mode.flattenSpans
1632   if (flattenSpans == null) { flattenSpans = cm.options.flattenSpans }
1633   var curStart = 0, curStyle = null
1634   var stream = new StringStream(text, cm.options.tabSize), style
1635   var inner = cm.options.addModeClass && [null]
1636   if (text == "") { extractLineClasses(callBlankLine(mode, state), lineClasses) }
1637   while (!stream.eol()) {
1638     if (stream.pos > cm.options.maxHighlightLength) {
1639       flattenSpans = false
1640       if (forceToEnd) { processLine(cm, text, state, stream.pos) }
1641       stream.pos = text.length
1642       style = null
1643     } else {
1644       style = extractLineClasses(readToken(mode, stream, state, inner), lineClasses)
1645     }
1646     if (inner) {
1647       var mName = inner[0].name
1648       if (mName) { style = "m-" + (style ? mName + " " + style : mName) }
1649     }
1650     if (!flattenSpans || curStyle != style) {
1651       while (curStart < stream.start) {
1652         curStart = Math.min(stream.start, curStart + 5000)
1653         f(curStart, curStyle)
1654       }
1655       curStyle = style
1656     }
1657     stream.start = stream.pos
1658   }
1659   while (curStart < stream.pos) {
1660     // Webkit seems to refuse to render text nodes longer than 57444
1661     // characters, and returns inaccurate measurements in nodes
1662     // starting around 5000 chars.
1663     var pos = Math.min(stream.pos, curStart + 5000)
1664     f(pos, curStyle)
1665     curStart = pos
1666   }
1667 }
1668
1669 // Finds the line to start with when starting a parse. Tries to
1670 // find a line with a stateAfter, so that it can start with a
1671 // valid state. If that fails, it returns the line with the
1672 // smallest indentation, which tends to need the least context to
1673 // parse correctly.
1674 function findStartLine(cm, n, precise) {
1675   var minindent, minline, doc = cm.doc
1676   var lim = precise ? -1 : n - (cm.doc.mode.innerMode ? 1000 : 100)
1677   for (var search = n; search > lim; --search) {
1678     if (search <= doc.first) { return doc.first }
1679     var line = getLine(doc, search - 1)
1680     if (line.stateAfter && (!precise || search <= doc.frontier)) { return search }
1681     var indented = countColumn(line.text, null, cm.options.tabSize)
1682     if (minline == null || minindent > indented) {
1683       minline = search - 1
1684       minindent = indented
1685     }
1686   }
1687   return minline
1688 }
1689
1690 // LINE DATA STRUCTURE
1691
1692 // Line objects. These hold state related to a line, including
1693 // highlighting info (the styles array).
1694 function Line(text, markedSpans, estimateHeight) {
1695   this.text = text
1696   attachMarkedSpans(this, markedSpans)
1697   this.height = estimateHeight ? estimateHeight(this) : 1
1698 }
1699 eventMixin(Line)
1700 Line.prototype.lineNo = function() { return lineNo(this) }
1701
1702 // Change the content (text, markers) of a line. Automatically
1703 // invalidates cached information and tries to re-estimate the
1704 // line's height.
1705 function updateLine(line, text, markedSpans, estimateHeight) {
1706   line.text = text
1707   if (line.stateAfter) { line.stateAfter = null }
1708   if (line.styles) { line.styles = null }
1709   if (line.order != null) { line.order = null }
1710   detachMarkedSpans(line)
1711   attachMarkedSpans(line, markedSpans)
1712   var estHeight = estimateHeight ? estimateHeight(line) : 1
1713   if (estHeight != line.height) { updateLineHeight(line, estHeight) }
1714 }
1715
1716 // Detach a line from the document tree and its markers.
1717 function cleanUpLine(line) {
1718   line.parent = null
1719   detachMarkedSpans(line)
1720 }
1721
1722 // Convert a style as returned by a mode (either null, or a string
1723 // containing one or more styles) to a CSS style. This is cached,
1724 // and also looks for line-wide styles.
1725 var styleToClassCache = {};
1726 var styleToClassCacheWithMode = {};
1727 function interpretTokenStyle(style, options) {
1728   if (!style || /^\s*$/.test(style)) { return null }
1729   var cache = options.addModeClass ? styleToClassCacheWithMode : styleToClassCache
1730   return cache[style] ||
1731     (cache[style] = style.replace(/\S+/g, "cm-$&"))
1732 }
1733
1734 // Render the DOM representation of the text of a line. Also builds
1735 // up a 'line map', which points at the DOM nodes that represent
1736 // specific stretches of text, and is used by the measuring code.
1737 // The returned object contains the DOM node, this map, and
1738 // information about line-wide styles that were set by the mode.
1739 function buildLineContent(cm, lineView) {
1740   // The padding-right forces the element to have a 'border', which
1741   // is needed on Webkit to be able to get line-level bounding
1742   // rectangles for it (in measureChar).
1743   var content = elt("span", null, null, webkit ? "padding-right: .1px" : null)
1744   var builder = {pre: elt("pre", [content], "CodeMirror-line"), content: content,
1745                  col: 0, pos: 0, cm: cm,
1746                  trailingSpace: false,
1747                  splitSpaces: (ie || webkit) && cm.getOption("lineWrapping")}
1748   lineView.measure = {}
1749
1750   // Iterate over the logical lines that make up this visual line.
1751   for (var i = 0; i <= (lineView.rest ? lineView.rest.length : 0); i++) {
1752     var line = i ? lineView.rest[i - 1] : lineView.line, order = (void 0)
1753     builder.pos = 0
1754     builder.addToken = buildToken
1755     // Optionally wire in some hacks into the token-rendering
1756     // algorithm, to deal with browser quirks.
1757     if (hasBadBidiRects(cm.display.measure) && (order = getOrder(line)))
1758       { builder.addToken = buildTokenBadBidi(builder.addToken, order) }
1759     builder.map = []
1760     var allowFrontierUpdate = lineView != cm.display.externalMeasured && lineNo(line)
1761     insertLineContent(line, builder, getLineStyles(cm, line, allowFrontierUpdate))
1762     if (line.styleClasses) {
1763       if (line.styleClasses.bgClass)
1764         { builder.bgClass = joinClasses(line.styleClasses.bgClass, builder.bgClass || "") }
1765       if (line.styleClasses.textClass)
1766         { builder.textClass = joinClasses(line.styleClasses.textClass, builder.textClass || "") }
1767     }
1768
1769     // Ensure at least a single node is present, for measuring.
1770     if (builder.map.length == 0)
1771       { builder.map.push(0, 0, builder.content.appendChild(zeroWidthElement(cm.display.measure))) }
1772
1773     // Store the map and a cache object for the current logical line
1774     if (i == 0) {
1775       lineView.measure.map = builder.map
1776       lineView.measure.cache = {}
1777     } else {
1778       ;(lineView.measure.maps || (lineView.measure.maps = [])).push(builder.map)
1779       ;(lineView.measure.caches || (lineView.measure.caches = [])).push({})
1780     }
1781   }
1782
1783   // See issue #2901
1784   if (webkit) {
1785     var last = builder.content.lastChild
1786     if (/\bcm-tab\b/.test(last.className) || (last.querySelector && last.querySelector(".cm-tab")))
1787       { builder.content.className = "cm-tab-wrap-hack" }
1788   }
1789
1790   signal(cm, "renderLine", cm, lineView.line, builder.pre)
1791   if (builder.pre.className)
1792     { builder.textClass = joinClasses(builder.pre.className, builder.textClass || "") }
1793
1794   return builder
1795 }
1796
1797 function defaultSpecialCharPlaceholder(ch) {
1798   var token = elt("span", "\u2022", "cm-invalidchar")
1799   token.title = "\\u" + ch.charCodeAt(0).toString(16)
1800   token.setAttribute("aria-label", token.title)
1801   return token
1802 }
1803
1804 // Build up the DOM representation for a single token, and add it to
1805 // the line map. Takes care to render special characters separately.
1806 function buildToken(builder, text, style, startStyle, endStyle, title, css) {
1807   if (!text) { return }
1808   var displayText = builder.splitSpaces ? splitSpaces(text, builder.trailingSpace) : text
1809   var special = builder.cm.state.specialChars, mustWrap = false
1810   var content
1811   if (!special.test(text)) {
1812     builder.col += text.length
1813     content = document.createTextNode(displayText)
1814     builder.map.push(builder.pos, builder.pos + text.length, content)
1815     if (ie && ie_version < 9) { mustWrap = true }
1816     builder.pos += text.length
1817   } else {
1818     content = document.createDocumentFragment()
1819     var pos = 0
1820     while (true) {
1821       special.lastIndex = pos
1822       var m = special.exec(text)
1823       var skipped = m ? m.index - pos : text.length - pos
1824       if (skipped) {
1825         var txt = document.createTextNode(displayText.slice(pos, pos + skipped))
1826         if (ie && ie_version < 9) { content.appendChild(elt("span", [txt])) }
1827         else { content.appendChild(txt) }
1828         builder.map.push(builder.pos, builder.pos + skipped, txt)
1829         builder.col += skipped
1830         builder.pos += skipped
1831       }
1832       if (!m) { break }
1833       pos += skipped + 1
1834       var txt$1 = (void 0)
1835       if (m[0] == "\t") {
1836         var tabSize = builder.cm.options.tabSize, tabWidth = tabSize - builder.col % tabSize
1837         txt$1 = content.appendChild(elt("span", spaceStr(tabWidth), "cm-tab"))
1838         txt$1.setAttribute("role", "presentation")
1839         txt$1.setAttribute("cm-text", "\t")
1840         builder.col += tabWidth
1841       } else if (m[0] == "\r" || m[0] == "\n") {
1842         txt$1 = content.appendChild(elt("span", m[0] == "\r" ? "\u240d" : "\u2424", "cm-invalidchar"))
1843         txt$1.setAttribute("cm-text", m[0])
1844         builder.col += 1
1845       } else {
1846         txt$1 = builder.cm.options.specialCharPlaceholder(m[0])
1847         txt$1.setAttribute("cm-text", m[0])
1848         if (ie && ie_version < 9) { content.appendChild(elt("span", [txt$1])) }
1849         else { content.appendChild(txt$1) }
1850         builder.col += 1
1851       }
1852       builder.map.push(builder.pos, builder.pos + 1, txt$1)
1853       builder.pos++
1854     }
1855   }
1856   builder.trailingSpace = displayText.charCodeAt(text.length - 1) == 32
1857   if (style || startStyle || endStyle || mustWrap || css) {
1858     var fullStyle = style || ""
1859     if (startStyle) { fullStyle += startStyle }
1860     if (endStyle) { fullStyle += endStyle }
1861     var token = elt("span", [content], fullStyle, css)
1862     if (title) { token.title = title }
1863     return builder.content.appendChild(token)
1864   }
1865   builder.content.appendChild(content)
1866 }
1867
1868 function splitSpaces(text, trailingBefore) {
1869   if (text.length > 1 && !/  /.test(text)) { return text }
1870   var spaceBefore = trailingBefore, result = ""
1871   for (var i = 0; i < text.length; i++) {
1872     var ch = text.charAt(i)
1873     if (ch == " " && spaceBefore && (i == text.length - 1 || text.charCodeAt(i + 1) == 32))
1874       { ch = "\u00a0" }
1875     result += ch
1876     spaceBefore = ch == " "
1877   }
1878   return result
1879 }
1880
1881 // Work around nonsense dimensions being reported for stretches of
1882 // right-to-left text.
1883 function buildTokenBadBidi(inner, order) {
1884   return function (builder, text, style, startStyle, endStyle, title, css) {
1885     style = style ? style + " cm-force-border" : "cm-force-border"
1886     var start = builder.pos, end = start + text.length
1887     for (;;) {
1888       // Find the part that overlaps with the start of this text
1889       var part = (void 0)
1890       for (var i = 0; i < order.length; i++) {
1891         part = order[i]
1892         if (part.to > start && part.from <= start) { break }
1893       }
1894       if (part.to >= end) { return inner(builder, text, style, startStyle, endStyle, title, css) }
1895       inner(builder, text.slice(0, part.to - start), style, startStyle, null, title, css)
1896       startStyle = null
1897       text = text.slice(part.to - start)
1898       start = part.to
1899     }
1900   }
1901 }
1902
1903 function buildCollapsedSpan(builder, size, marker, ignoreWidget) {
1904   var widget = !ignoreWidget && marker.widgetNode
1905   if (widget) { builder.map.push(builder.pos, builder.pos + size, widget) }
1906   if (!ignoreWidget && builder.cm.display.input.needsContentAttribute) {
1907     if (!widget)
1908       { widget = builder.content.appendChild(document.createElement("span")) }
1909     widget.setAttribute("cm-marker", marker.id)
1910   }
1911   if (widget) {
1912     builder.cm.display.input.setUneditable(widget)
1913     builder.content.appendChild(widget)
1914   }
1915   builder.pos += size
1916   builder.trailingSpace = false
1917 }
1918
1919 // Outputs a number of spans to make up a line, taking highlighting
1920 // and marked text into account.
1921 function insertLineContent(line, builder, styles) {
1922   var spans = line.markedSpans, allText = line.text, at = 0
1923   if (!spans) {
1924     for (var i$1 = 1; i$1 < styles.length; i$1+=2)
1925       { builder.addToken(builder, allText.slice(at, at = styles[i$1]), interpretTokenStyle(styles[i$1+1], builder.cm.options)) }
1926     return
1927   }
1928
1929   var len = allText.length, pos = 0, i = 1, text = "", style, css
1930   var nextChange = 0, spanStyle, spanEndStyle, spanStartStyle, title, collapsed
1931   for (;;) {
1932     if (nextChange == pos) { // Update current marker set
1933       spanStyle = spanEndStyle = spanStartStyle = title = css = ""
1934       collapsed = null; nextChange = Infinity
1935       var foundBookmarks = [], endStyles = (void 0)
1936       for (var j = 0; j < spans.length; ++j) {
1937         var sp = spans[j], m = sp.marker
1938         if (m.type == "bookmark" && sp.from == pos && m.widgetNode) {
1939           foundBookmarks.push(m)
1940         } else if (sp.from <= pos && (sp.to == null || sp.to > pos || m.collapsed && sp.to == pos && sp.from == pos)) {
1941           if (sp.to != null && sp.to != pos && nextChange > sp.to) {
1942             nextChange = sp.to
1943             spanEndStyle = ""
1944           }
1945           if (m.className) { spanStyle += " " + m.className }
1946           if (m.css) { css = (css ? css + ";" : "") + m.css }
1947           if (m.startStyle && sp.from == pos) { spanStartStyle += " " + m.startStyle }
1948           if (m.endStyle && sp.to == nextChange) { (endStyles || (endStyles = [])).push(m.endStyle, sp.to) }
1949           if (m.title && !title) { title = m.title }
1950           if (m.collapsed && (!collapsed || compareCollapsedMarkers(collapsed.marker, m) < 0))
1951             { collapsed = sp }
1952         } else if (sp.from > pos && nextChange > sp.from) {
1953           nextChange = sp.from
1954         }
1955       }
1956       if (endStyles) { for (var j$1 = 0; j$1 < endStyles.length; j$1 += 2)
1957         { if (endStyles[j$1 + 1] == nextChange) { spanEndStyle += " " + endStyles[j$1] } } }
1958
1959       if (!collapsed || collapsed.from == pos) { for (var j$2 = 0; j$2 < foundBookmarks.length; ++j$2)
1960         { buildCollapsedSpan(builder, 0, foundBookmarks[j$2]) } }
1961       if (collapsed && (collapsed.from || 0) == pos) {
1962         buildCollapsedSpan(builder, (collapsed.to == null ? len + 1 : collapsed.to) - pos,
1963                            collapsed.marker, collapsed.from == null)
1964         if (collapsed.to == null) { return }
1965         if (collapsed.to == pos) { collapsed = false }
1966       }
1967     }
1968     if (pos >= len) { break }
1969
1970     var upto = Math.min(len, nextChange)
1971     while (true) {
1972       if (text) {
1973         var end = pos + text.length
1974         if (!collapsed) {
1975           var tokenText = end > upto ? text.slice(0, upto - pos) : text
1976           builder.addToken(builder, tokenText, style ? style + spanStyle : spanStyle,
1977                            spanStartStyle, pos + tokenText.length == nextChange ? spanEndStyle : "", title, css)
1978         }
1979         if (end >= upto) {text = text.slice(upto - pos); pos = upto; break}
1980         pos = end
1981         spanStartStyle = ""
1982       }
1983       text = allText.slice(at, at = styles[i++])
1984       style = interpretTokenStyle(styles[i++], builder.cm.options)
1985     }
1986   }
1987 }
1988
1989
1990 // These objects are used to represent the visible (currently drawn)
1991 // part of the document. A LineView may correspond to multiple
1992 // logical lines, if those are connected by collapsed ranges.
1993 function LineView(doc, line, lineN) {
1994   // The starting line
1995   this.line = line
1996   // Continuing lines, if any
1997   this.rest = visualLineContinued(line)
1998   // Number of logical lines in this visual line
1999   this.size = this.rest ? lineNo(lst(this.rest)) - lineN + 1 : 1
2000   this.node = this.text = null
2001   this.hidden = lineIsHidden(doc, line)
2002 }
2003
2004 // Create a range of LineView objects for the given lines.
2005 function buildViewArray(cm, from, to) {
2006   var array = [], nextPos
2007   for (var pos = from; pos < to; pos = nextPos) {
2008     var view = new LineView(cm.doc, getLine(cm.doc, pos), pos)
2009     nextPos = pos + view.size
2010     array.push(view)
2011   }
2012   return array
2013 }
2014
2015 var operationGroup = null
2016
2017 function pushOperation(op) {
2018   if (operationGroup) {
2019     operationGroup.ops.push(op)
2020   } else {
2021     op.ownsGroup = operationGroup = {
2022       ops: [op],
2023       delayedCallbacks: []
2024     }
2025   }
2026 }
2027
2028 function fireCallbacksForOps(group) {
2029   // Calls delayed callbacks and cursorActivity handlers until no
2030   // new ones appear
2031   var callbacks = group.delayedCallbacks, i = 0
2032   do {
2033     for (; i < callbacks.length; i++)
2034       { callbacks[i].call(null) }
2035     for (var j = 0; j < group.ops.length; j++) {
2036       var op = group.ops[j]
2037       if (op.cursorActivityHandlers)
2038         { while (op.cursorActivityCalled < op.cursorActivityHandlers.length)
2039           { op.cursorActivityHandlers[op.cursorActivityCalled++].call(null, op.cm) } }
2040     }
2041   } while (i < callbacks.length)
2042 }
2043
2044 function finishOperation(op, endCb) {
2045   var group = op.ownsGroup
2046   if (!group) { return }
2047
2048   try { fireCallbacksForOps(group) }
2049   finally {
2050     operationGroup = null
2051     endCb(group)
2052   }
2053 }
2054
2055 var orphanDelayedCallbacks = null
2056
2057 // Often, we want to signal events at a point where we are in the
2058 // middle of some work, but don't want the handler to start calling
2059 // other methods on the editor, which might be in an inconsistent
2060 // state or simply not expect any other events to happen.
2061 // signalLater looks whether there are any handlers, and schedules
2062 // them to be executed when the last operation ends, or, if no
2063 // operation is active, when a timeout fires.
2064 function signalLater(emitter, type /*, values...*/) {
2065   var arr = getHandlers(emitter, type)
2066   if (!arr.length) { return }
2067   var args = Array.prototype.slice.call(arguments, 2), list
2068   if (operationGroup) {
2069     list = operationGroup.delayedCallbacks
2070   } else if (orphanDelayedCallbacks) {
2071     list = orphanDelayedCallbacks
2072   } else {
2073     list = orphanDelayedCallbacks = []
2074     setTimeout(fireOrphanDelayed, 0)
2075   }
2076   var loop = function ( i ) {
2077     list.push(function () { return arr[i].apply(null, args); })
2078   };
2079
2080   for (var i = 0; i < arr.length; ++i)
2081     loop( i );
2082 }
2083
2084 function fireOrphanDelayed() {
2085   var delayed = orphanDelayedCallbacks
2086   orphanDelayedCallbacks = null
2087   for (var i = 0; i < delayed.length; ++i) { delayed[i]() }
2088 }
2089
2090 // When an aspect of a line changes, a string is added to
2091 // lineView.changes. This updates the relevant part of the line's
2092 // DOM structure.
2093 function updateLineForChanges(cm, lineView, lineN, dims) {
2094   for (var j = 0; j < lineView.changes.length; j++) {
2095     var type = lineView.changes[j]
2096     if (type == "text") { updateLineText(cm, lineView) }
2097     else if (type == "gutter") { updateLineGutter(cm, lineView, lineN, dims) }
2098     else if (type == "class") { updateLineClasses(lineView) }
2099     else if (type == "widget") { updateLineWidgets(cm, lineView, dims) }
2100   }
2101   lineView.changes = null
2102 }
2103
2104 // Lines with gutter elements, widgets or a background class need to
2105 // be wrapped, and have the extra elements added to the wrapper div
2106 function ensureLineWrapped(lineView) {
2107   if (lineView.node == lineView.text) {
2108     lineView.node = elt("div", null, null, "position: relative")
2109     if (lineView.text.parentNode)
2110       { lineView.text.parentNode.replaceChild(lineView.node, lineView.text) }
2111     lineView.node.appendChild(lineView.text)
2112     if (ie && ie_version < 8) { lineView.node.style.zIndex = 2 }
2113   }
2114   return lineView.node
2115 }
2116
2117 function updateLineBackground(lineView) {
2118   var cls = lineView.bgClass ? lineView.bgClass + " " + (lineView.line.bgClass || "") : lineView.line.bgClass
2119   if (cls) { cls += " CodeMirror-linebackground" }
2120   if (lineView.background) {
2121     if (cls) { lineView.background.className = cls }
2122     else { lineView.background.parentNode.removeChild(lineView.background); lineView.background = null }
2123   } else if (cls) {
2124     var wrap = ensureLineWrapped(lineView)
2125     lineView.background = wrap.insertBefore(elt("div", null, cls), wrap.firstChild)
2126   }
2127 }
2128
2129 // Wrapper around buildLineContent which will reuse the structure
2130 // in display.externalMeasured when possible.
2131 function getLineContent(cm, lineView) {
2132   var ext = cm.display.externalMeasured
2133   if (ext && ext.line == lineView.line) {
2134     cm.display.externalMeasured = null
2135     lineView.measure = ext.measure
2136     return ext.built
2137   }
2138   return buildLineContent(cm, lineView)
2139 }
2140
2141 // Redraw the line's text. Interacts with the background and text
2142 // classes because the mode may output tokens that influence these
2143 // classes.
2144 function updateLineText(cm, lineView) {
2145   var cls = lineView.text.className
2146   var built = getLineContent(cm, lineView)
2147   if (lineView.text == lineView.node) { lineView.node = built.pre }
2148   lineView.text.parentNode.replaceChild(built.pre, lineView.text)
2149   lineView.text = built.pre
2150   if (built.bgClass != lineView.bgClass || built.textClass != lineView.textClass) {
2151     lineView.bgClass = built.bgClass
2152     lineView.textClass = built.textClass
2153     updateLineClasses(lineView)
2154   } else if (cls) {
2155     lineView.text.className = cls
2156   }
2157 }
2158
2159 function updateLineClasses(lineView) {
2160   updateLineBackground(lineView)
2161   if (lineView.line.wrapClass)
2162     { ensureLineWrapped(lineView).className = lineView.line.wrapClass }
2163   else if (lineView.node != lineView.text)
2164     { lineView.node.className = "" }
2165   var textClass = lineView.textClass ? lineView.textClass + " " + (lineView.line.textClass || "") : lineView.line.textClass
2166   lineView.text.className = textClass || ""
2167 }
2168
2169 function updateLineGutter(cm, lineView, lineN, dims) {
2170   if (lineView.gutter) {
2171     lineView.node.removeChild(lineView.gutter)
2172     lineView.gutter = null
2173   }
2174   if (lineView.gutterBackground) {
2175     lineView.node.removeChild(lineView.gutterBackground)
2176     lineView.gutterBackground = null
2177   }
2178   if (lineView.line.gutterClass) {
2179     var wrap = ensureLineWrapped(lineView)
2180     lineView.gutterBackground = elt("div", null, "CodeMirror-gutter-background " + lineView.line.gutterClass,
2181                                     ("left: " + (cm.options.fixedGutter ? dims.fixedPos : -dims.gutterTotalWidth) + "px; width: " + (dims.gutterTotalWidth) + "px"))
2182     wrap.insertBefore(lineView.gutterBackground, lineView.text)
2183   }
2184   var markers = lineView.line.gutterMarkers
2185   if (cm.options.lineNumbers || markers) {
2186     var wrap$1 = ensureLineWrapped(lineView)
2187     var gutterWrap = lineView.gutter = elt("div", null, "CodeMirror-gutter-wrapper", ("left: " + (cm.options.fixedGutter ? dims.fixedPos : -dims.gutterTotalWidth) + "px"))
2188     cm.display.input.setUneditable(gutterWrap)
2189     wrap$1.insertBefore(gutterWrap, lineView.text)
2190     if (lineView.line.gutterClass)
2191       { gutterWrap.className += " " + lineView.line.gutterClass }
2192     if (cm.options.lineNumbers && (!markers || !markers["CodeMirror-linenumbers"]))
2193       { lineView.lineNumber = gutterWrap.appendChild(
2194         elt("div", lineNumberFor(cm.options, lineN),
2195             "CodeMirror-linenumber CodeMirror-gutter-elt",
2196             ("left: " + (dims.gutterLeft["CodeMirror-linenumbers"]) + "px; width: " + (cm.display.lineNumInnerWidth) + "px"))) }
2197     if (markers) { for (var k = 0; k < cm.options.gutters.length; ++k) {
2198       var id = cm.options.gutters[k], found = markers.hasOwnProperty(id) && markers[id]
2199       if (found)
2200         { gutterWrap.appendChild(elt("div", [found], "CodeMirror-gutter-elt",
2201                                    ("left: " + (dims.gutterLeft[id]) + "px; width: " + (dims.gutterWidth[id]) + "px"))) }
2202     } }
2203   }
2204 }
2205
2206 function updateLineWidgets(cm, lineView, dims) {
2207   if (lineView.alignable) { lineView.alignable = null }
2208   for (var node = lineView.node.firstChild, next = (void 0); node; node = next) {
2209     next = node.nextSibling
2210     if (node.className == "CodeMirror-linewidget")
2211       { lineView.node.removeChild(node) }
2212   }
2213   insertLineWidgets(cm, lineView, dims)
2214 }
2215
2216 // Build a line's DOM representation from scratch
2217 function buildLineElement(cm, lineView, lineN, dims) {
2218   var built = getLineContent(cm, lineView)
2219   lineView.text = lineView.node = built.pre
2220   if (built.bgClass) { lineView.bgClass = built.bgClass }
2221   if (built.textClass) { lineView.textClass = built.textClass }
2222
2223   updateLineClasses(lineView)
2224   updateLineGutter(cm, lineView, lineN, dims)
2225   insertLineWidgets(cm, lineView, dims)
2226   return lineView.node
2227 }
2228
2229 // A lineView may contain multiple logical lines (when merged by
2230 // collapsed spans). The widgets for all of them need to be drawn.
2231 function insertLineWidgets(cm, lineView, dims) {
2232   insertLineWidgetsFor(cm, lineView.line, lineView, dims, true)
2233   if (lineView.rest) { for (var i = 0; i < lineView.rest.length; i++)
2234     { insertLineWidgetsFor(cm, lineView.rest[i], lineView, dims, false) } }
2235 }
2236
2237 function insertLineWidgetsFor(cm, line, lineView, dims, allowAbove) {
2238   if (!line.widgets) { return }
2239   var wrap = ensureLineWrapped(lineView)
2240   for (var i = 0, ws = line.widgets; i < ws.length; ++i) {
2241     var widget = ws[i], node = elt("div", [widget.node], "CodeMirror-linewidget")
2242     if (!widget.handleMouseEvents) { node.setAttribute("cm-ignore-events", "true") }
2243     positionLineWidget(widget, node, lineView, dims)
2244     cm.display.input.setUneditable(node)
2245     if (allowAbove && widget.above)
2246       { wrap.insertBefore(node, lineView.gutter || lineView.text) }
2247     else
2248       { wrap.appendChild(node) }
2249     signalLater(widget, "redraw")
2250   }
2251 }
2252
2253 function positionLineWidget(widget, node, lineView, dims) {
2254   if (widget.noHScroll) {
2255     ;(lineView.alignable || (lineView.alignable = [])).push(node)
2256     var width = dims.wrapperWidth
2257     node.style.left = dims.fixedPos + "px"
2258     if (!widget.coverGutter) {
2259       width -= dims.gutterTotalWidth
2260       node.style.paddingLeft = dims.gutterTotalWidth + "px"
2261     }
2262     node.style.width = width + "px"
2263   }
2264   if (widget.coverGutter) {
2265     node.style.zIndex = 5
2266     node.style.position = "relative"
2267     if (!widget.noHScroll) { node.style.marginLeft = -dims.gutterTotalWidth + "px" }
2268   }
2269 }
2270
2271 function widgetHeight(widget) {
2272   if (widget.height != null) { return widget.height }
2273   var cm = widget.doc.cm
2274   if (!cm) { return 0 }
2275   if (!contains(document.body, widget.node)) {
2276     var parentStyle = "position: relative;"
2277     if (widget.coverGutter)
2278       { parentStyle += "margin-left: -" + cm.display.gutters.offsetWidth + "px;" }
2279     if (widget.noHScroll)
2280       { parentStyle += "width: " + cm.display.wrapper.clientWidth + "px;" }
2281     removeChildrenAndAdd(cm.display.measure, elt("div", [widget.node], null, parentStyle))
2282   }
2283   return widget.height = widget.node.parentNode.offsetHeight
2284 }
2285
2286 // Return true when the given mouse event happened in a widget
2287 function eventInWidget(display, e) {
2288   for (var n = e_target(e); n != display.wrapper; n = n.parentNode) {
2289     if (!n || (n.nodeType == 1 && n.getAttribute("cm-ignore-events") == "true") ||
2290         (n.parentNode == display.sizer && n != display.mover))
2291       { return true }
2292   }
2293 }
2294
2295 // POSITION MEASUREMENT
2296
2297 function paddingTop(display) {return display.lineSpace.offsetTop}
2298 function paddingVert(display) {return display.mover.offsetHeight - display.lineSpace.offsetHeight}
2299 function paddingH(display) {
2300   if (display.cachedPaddingH) { return display.cachedPaddingH }
2301   var e = removeChildrenAndAdd(display.measure, elt("pre", "x"))
2302   var style = window.getComputedStyle ? window.getComputedStyle(e) : e.currentStyle
2303   var data = {left: parseInt(style.paddingLeft), right: parseInt(style.paddingRight)}
2304   if (!isNaN(data.left) && !isNaN(data.right)) { display.cachedPaddingH = data }
2305   return data
2306 }
2307
2308 function scrollGap(cm) { return scrollerGap - cm.display.nativeBarWidth }
2309 function displayWidth(cm) {
2310   return cm.display.scroller.clientWidth - scrollGap(cm) - cm.display.barWidth
2311 }
2312 function displayHeight(cm) {
2313   return cm.display.scroller.clientHeight - scrollGap(cm) - cm.display.barHeight
2314 }
2315
2316 // Ensure the lineView.wrapping.heights array is populated. This is
2317 // an array of bottom offsets for the lines that make up a drawn
2318 // line. When lineWrapping is on, there might be more than one
2319 // height.
2320 function ensureLineHeights(cm, lineView, rect) {
2321   var wrapping = cm.options.lineWrapping
2322   var curWidth = wrapping && displayWidth(cm)
2323   if (!lineView.measure.heights || wrapping && lineView.measure.width != curWidth) {
2324     var heights = lineView.measure.heights = []
2325     if (wrapping) {
2326       lineView.measure.width = curWidth
2327       var rects = lineView.text.firstChild.getClientRects()
2328       for (var i = 0; i < rects.length - 1; i++) {
2329         var cur = rects[i], next = rects[i + 1]
2330         if (Math.abs(cur.bottom - next.bottom) > 2)
2331           { heights.push((cur.bottom + next.top) / 2 - rect.top) }
2332       }
2333     }
2334     heights.push(rect.bottom - rect.top)
2335   }
2336 }
2337
2338 // Find a line map (mapping character offsets to text nodes) and a
2339 // measurement cache for the given line number. (A line view might
2340 // contain multiple lines when collapsed ranges are present.)
2341 function mapFromLineView(lineView, line, lineN) {
2342   if (lineView.line == line)
2343     { return {map: lineView.measure.map, cache: lineView.measure.cache} }
2344   for (var i = 0; i < lineView.rest.length; i++)
2345     { if (lineView.rest[i] == line)
2346       { return {map: lineView.measure.maps[i], cache: lineView.measure.caches[i]} } }
2347   for (var i$1 = 0; i$1 < lineView.rest.length; i$1++)
2348     { if (lineNo(lineView.rest[i$1]) > lineN)
2349       { return {map: lineView.measure.maps[i$1], cache: lineView.measure.caches[i$1], before: true} } }
2350 }
2351
2352 // Render a line into the hidden node display.externalMeasured. Used
2353 // when measurement is needed for a line that's not in the viewport.
2354 function updateExternalMeasurement(cm, line) {
2355   line = visualLine(line)
2356   var lineN = lineNo(line)
2357   var view = cm.display.externalMeasured = new LineView(cm.doc, line, lineN)
2358   view.lineN = lineN
2359   var built = view.built = buildLineContent(cm, view)
2360   view.text = built.pre
2361   removeChildrenAndAdd(cm.display.lineMeasure, built.pre)
2362   return view
2363 }
2364
2365 // Get a {top, bottom, left, right} box (in line-local coordinates)
2366 // for a given character.
2367 function measureChar(cm, line, ch, bias) {
2368   return measureCharPrepared(cm, prepareMeasureForLine(cm, line), ch, bias)
2369 }
2370
2371 // Find a line view that corresponds to the given line number.
2372 function findViewForLine(cm, lineN) {
2373   if (lineN >= cm.display.viewFrom && lineN < cm.display.viewTo)
2374     { return cm.display.view[findViewIndex(cm, lineN)] }
2375   var ext = cm.display.externalMeasured
2376   if (ext && lineN >= ext.lineN && lineN < ext.lineN + ext.size)
2377     { return ext }
2378 }
2379
2380 // Measurement can be split in two steps, the set-up work that
2381 // applies to the whole line, and the measurement of the actual
2382 // character. Functions like coordsChar, that need to do a lot of
2383 // measurements in a row, can thus ensure that the set-up work is
2384 // only done once.
2385 function prepareMeasureForLine(cm, line) {
2386   var lineN = lineNo(line)
2387   var view = findViewForLine(cm, lineN)
2388   if (view && !view.text) {
2389     view = null
2390   } else if (view && view.changes) {
2391     updateLineForChanges(cm, view, lineN, getDimensions(cm))
2392     cm.curOp.forceUpdate = true
2393   }
2394   if (!view)
2395     { view = updateExternalMeasurement(cm, line) }
2396
2397   var info = mapFromLineView(view, line, lineN)
2398   return {
2399     line: line, view: view, rect: null,
2400     map: info.map, cache: info.cache, before: info.before,
2401     hasHeights: false
2402   }
2403 }
2404
2405 // Given a prepared measurement object, measures the position of an
2406 // actual character (or fetches it from the cache).
2407 function measureCharPrepared(cm, prepared, ch, bias, varHeight) {
2408   if (prepared.before) { ch = -1 }
2409   var key = ch + (bias || ""), found
2410   if (prepared.cache.hasOwnProperty(key)) {
2411     found = prepared.cache[key]
2412   } else {
2413     if (!prepared.rect)
2414       { prepared.rect = prepared.view.text.getBoundingClientRect() }
2415     if (!prepared.hasHeights) {
2416       ensureLineHeights(cm, prepared.view, prepared.rect)
2417       prepared.hasHeights = true
2418     }
2419     found = measureCharInner(cm, prepared, ch, bias)
2420     if (!found.bogus) { prepared.cache[key] = found }
2421   }
2422   return {left: found.left, right: found.right,
2423           top: varHeight ? found.rtop : found.top,
2424           bottom: varHeight ? found.rbottom : found.bottom}
2425 }
2426
2427 var nullRect = {left: 0, right: 0, top: 0, bottom: 0}
2428
2429 function nodeAndOffsetInLineMap(map, ch, bias) {
2430   var node, start, end, collapse, mStart, mEnd
2431   // First, search the line map for the text node corresponding to,
2432   // or closest to, the target character.
2433   for (var i = 0; i < map.length; i += 3) {
2434     mStart = map[i]
2435     mEnd = map[i + 1]
2436     if (ch < mStart) {
2437       start = 0; end = 1
2438       collapse = "left"
2439     } else if (ch < mEnd) {
2440       start = ch - mStart
2441       end = start + 1
2442     } else if (i == map.length - 3 || ch == mEnd && map[i + 3] > ch) {
2443       end = mEnd - mStart
2444       start = end - 1
2445       if (ch >= mEnd) { collapse = "right" }
2446     }
2447     if (start != null) {
2448       node = map[i + 2]
2449       if (mStart == mEnd && bias == (node.insertLeft ? "left" : "right"))
2450         { collapse = bias }
2451       if (bias == "left" && start == 0)
2452         { while (i && map[i - 2] == map[i - 3] && map[i - 1].insertLeft) {
2453           node = map[(i -= 3) + 2]
2454           collapse = "left"
2455         } }
2456       if (bias == "right" && start == mEnd - mStart)
2457         { while (i < map.length - 3 && map[i + 3] == map[i + 4] && !map[i + 5].insertLeft) {
2458           node = map[(i += 3) + 2]
2459           collapse = "right"
2460         } }
2461       break
2462     }
2463   }
2464   return {node: node, start: start, end: end, collapse: collapse, coverStart: mStart, coverEnd: mEnd}
2465 }
2466
2467 function getUsefulRect(rects, bias) {
2468   var rect = nullRect
2469   if (bias == "left") { for (var i = 0; i < rects.length; i++) {
2470     if ((rect = rects[i]).left != rect.right) { break }
2471   } } else { for (var i$1 = rects.length - 1; i$1 >= 0; i$1--) {
2472     if ((rect = rects[i$1]).left != rect.right) { break }
2473   } }
2474   return rect
2475 }
2476
2477 function measureCharInner(cm, prepared, ch, bias) {
2478   var place = nodeAndOffsetInLineMap(prepared.map, ch, bias)
2479   var node = place.node, start = place.start, end = place.end, collapse = place.collapse
2480
2481   var rect
2482   if (node.nodeType == 3) { // If it is a text node, use a range to retrieve the coordinates.
2483     for (var i$1 = 0; i$1 < 4; i$1++) { // Retry a maximum of 4 times when nonsense rectangles are returned
2484       while (start && isExtendingChar(prepared.line.text.charAt(place.coverStart + start))) { --start }
2485       while (place.coverStart + end < place.coverEnd && isExtendingChar(prepared.line.text.charAt(place.coverStart + end))) { ++end }
2486       if (ie && ie_version < 9 && start == 0 && end == place.coverEnd - place.coverStart)
2487         { rect = node.parentNode.getBoundingClientRect() }
2488       else
2489         { rect = getUsefulRect(range(node, start, end).getClientRects(), bias) }
2490       if (rect.left || rect.right || start == 0) { break }
2491       end = start
2492       start = start - 1
2493       collapse = "right"
2494     }
2495     if (ie && ie_version < 11) { rect = maybeUpdateRectForZooming(cm.display.measure, rect) }
2496   } else { // If it is a widget, simply get the box for the whole widget.
2497     if (start > 0) { collapse = bias = "right" }
2498     var rects
2499     if (cm.options.lineWrapping && (rects = node.getClientRects()).length > 1)
2500       { rect = rects[bias == "right" ? rects.length - 1 : 0] }
2501     else
2502       { rect = node.getBoundingClientRect() }
2503   }
2504   if (ie && ie_version < 9 && !start && (!rect || !rect.left && !rect.right)) {
2505     var rSpan = node.parentNode.getClientRects()[0]
2506     if (rSpan)
2507       { rect = {left: rSpan.left, right: rSpan.left + charWidth(cm.display), top: rSpan.top, bottom: rSpan.bottom} }
2508     else
2509       { rect = nullRect }
2510   }
2511
2512   var rtop = rect.top - prepared.rect.top, rbot = rect.bottom - prepared.rect.top
2513   var mid = (rtop + rbot) / 2
2514   var heights = prepared.view.measure.heights
2515   var i = 0
2516   for (; i < heights.length - 1; i++)
2517     { if (mid < heights[i]) { break } }
2518   var top = i ? heights[i - 1] : 0, bot = heights[i]
2519   var result = {left: (collapse == "right" ? rect.right : rect.left) - prepared.rect.left,
2520                 right: (collapse == "left" ? rect.left : rect.right) - prepared.rect.left,
2521                 top: top, bottom: bot}
2522   if (!rect.left && !rect.right) { result.bogus = true }
2523   if (!cm.options.singleCursorHeightPerLine) { result.rtop = rtop; result.rbottom = rbot }
2524
2525   return result
2526 }
2527
2528 // Work around problem with bounding client rects on ranges being
2529 // returned incorrectly when zoomed on IE10 and below.
2530 function maybeUpdateRectForZooming(measure, rect) {
2531   if (!window.screen || screen.logicalXDPI == null ||
2532       screen.logicalXDPI == screen.deviceXDPI || !hasBadZoomedRects(measure))
2533     { return rect }
2534   var scaleX = screen.logicalXDPI / screen.deviceXDPI
2535   var scaleY = screen.logicalYDPI / screen.deviceYDPI
2536   return {left: rect.left * scaleX, right: rect.right * scaleX,
2537           top: rect.top * scaleY, bottom: rect.bottom * scaleY}
2538 }
2539
2540 function clearLineMeasurementCacheFor(lineView) {
2541   if (lineView.measure) {
2542     lineView.measure.cache = {}
2543     lineView.measure.heights = null
2544     if (lineView.rest) { for (var i = 0; i < lineView.rest.length; i++)
2545       { lineView.measure.caches[i] = {} } }
2546   }
2547 }
2548
2549 function clearLineMeasurementCache(cm) {
2550   cm.display.externalMeasure = null
2551   removeChildren(cm.display.lineMeasure)
2552   for (var i = 0; i < cm.display.view.length; i++)
2553     { clearLineMeasurementCacheFor(cm.display.view[i]) }
2554 }
2555
2556 function clearCaches(cm) {
2557   clearLineMeasurementCache(cm)
2558   cm.display.cachedCharWidth = cm.display.cachedTextHeight = cm.display.cachedPaddingH = null
2559   if (!cm.options.lineWrapping) { cm.display.maxLineChanged = true }
2560   cm.display.lineNumChars = null
2561 }
2562
2563 function pageScrollX() { return window.pageXOffset || (document.documentElement || document.body).scrollLeft }
2564 function pageScrollY() { return window.pageYOffset || (document.documentElement || document.body).scrollTop }
2565
2566 // Converts a {top, bottom, left, right} box from line-local
2567 // coordinates into another coordinate system. Context may be one of
2568 // "line", "div" (display.lineDiv), "local"./null (editor), "window",
2569 // or "page".
2570 function intoCoordSystem(cm, lineObj, rect, context, includeWidgets) {
2571   if (!includeWidgets && lineObj.widgets) { for (var i = 0; i < lineObj.widgets.length; ++i) { if (lineObj.widgets[i].above) {
2572     var size = widgetHeight(lineObj.widgets[i])
2573     rect.top += size; rect.bottom += size
2574   } } }
2575   if (context == "line") { return rect }
2576   if (!context) { context = "local" }
2577   var yOff = heightAtLine(lineObj)
2578   if (context == "local") { yOff += paddingTop(cm.display) }
2579   else { yOff -= cm.display.viewOffset }
2580   if (context == "page" || context == "window") {
2581     var lOff = cm.display.lineSpace.getBoundingClientRect()
2582     yOff += lOff.top + (context == "window" ? 0 : pageScrollY())
2583     var xOff = lOff.left + (context == "window" ? 0 : pageScrollX())
2584     rect.left += xOff; rect.right += xOff
2585   }
2586   rect.top += yOff; rect.bottom += yOff
2587   return rect
2588 }
2589
2590 // Coverts a box from "div" coords to another coordinate system.
2591 // Context may be "window", "page", "div", or "local"./null.
2592 function fromCoordSystem(cm, coords, context) {
2593   if (context == "div") { return coords }
2594   var left = coords.left, top = coords.top
2595   // First move into "page" coordinate system
2596   if (context == "page") {
2597     left -= pageScrollX()
2598     top -= pageScrollY()
2599   } else if (context == "local" || !context) {
2600     var localBox = cm.display.sizer.getBoundingClientRect()
2601     left += localBox.left
2602     top += localBox.top
2603   }
2604
2605   var lineSpaceBox = cm.display.lineSpace.getBoundingClientRect()
2606   return {left: left - lineSpaceBox.left, top: top - lineSpaceBox.top}
2607 }
2608
2609 function charCoords(cm, pos, context, lineObj, bias) {
2610   if (!lineObj) { lineObj = getLine(cm.doc, pos.line) }
2611   return intoCoordSystem(cm, lineObj, measureChar(cm, lineObj, pos.ch, bias), context)
2612 }
2613
2614 // Returns a box for a given cursor position, which may have an
2615 // 'other' property containing the position of the secondary cursor
2616 // on a bidi boundary.
2617 function cursorCoords(cm, pos, context, lineObj, preparedMeasure, varHeight) {
2618   lineObj = lineObj || getLine(cm.doc, pos.line)
2619   if (!preparedMeasure) { preparedMeasure = prepareMeasureForLine(cm, lineObj) }
2620   function get(ch, right) {
2621     var m = measureCharPrepared(cm, preparedMeasure, ch, right ? "right" : "left", varHeight)
2622     if (right) { m.left = m.right; } else { m.right = m.left }
2623     return intoCoordSystem(cm, lineObj, m, context)
2624   }
2625   function getBidi(ch, partPos) {
2626     var part = order[partPos], right = part.level % 2
2627     if (ch == bidiLeft(part) && partPos && part.level < order[partPos - 1].level) {
2628       part = order[--partPos]
2629       ch = bidiRight(part) - (part.level % 2 ? 0 : 1)
2630       right = true
2631     } else if (ch == bidiRight(part) && partPos < order.length - 1 && part.level < order[partPos + 1].level) {
2632       part = order[++partPos]
2633       ch = bidiLeft(part) - part.level % 2
2634       right = false
2635     }
2636     if (right && ch == part.to && ch > part.from) { return get(ch - 1) }
2637     return get(ch, right)
2638   }
2639   var order = getOrder(lineObj), ch = pos.ch
2640   if (!order) { return get(ch) }
2641   var partPos = getBidiPartAt(order, ch)
2642   var val = getBidi(ch, partPos)
2643   if (bidiOther != null) { val.other = getBidi(ch, bidiOther) }
2644   return val
2645 }
2646
2647 // Used to cheaply estimate the coordinates for a position. Used for
2648 // intermediate scroll updates.
2649 function estimateCoords(cm, pos) {
2650   var left = 0
2651   pos = clipPos(cm.doc, pos)
2652   if (!cm.options.lineWrapping) { left = charWidth(cm.display) * pos.ch }
2653   var lineObj = getLine(cm.doc, pos.line)
2654   var top = heightAtLine(lineObj) + paddingTop(cm.display)
2655   return {left: left, right: left, top: top, bottom: top + lineObj.height}
2656 }
2657
2658 // Positions returned by coordsChar contain some extra information.
2659 // xRel is the relative x position of the input coordinates compared
2660 // to the found position (so xRel > 0 means the coordinates are to
2661 // the right of the character position, for example). When outside
2662 // is true, that means the coordinates lie outside the line's
2663 // vertical range.
2664 function PosWithInfo(line, ch, outside, xRel) {
2665   var pos = Pos(line, ch)
2666   pos.xRel = xRel
2667   if (outside) { pos.outside = true }
2668   return pos
2669 }
2670
2671 // Compute the character position closest to the given coordinates.
2672 // Input must be lineSpace-local ("div" coordinate system).
2673 function coordsChar(cm, x, y) {
2674   var doc = cm.doc
2675   y += cm.display.viewOffset
2676   if (y < 0) { return PosWithInfo(doc.first, 0, true, -1) }
2677   var lineN = lineAtHeight(doc, y), last = doc.first + doc.size - 1
2678   if (lineN > last)
2679     { return PosWithInfo(doc.first + doc.size - 1, getLine(doc, last).text.length, true, 1) }
2680   if (x < 0) { x = 0 }
2681
2682   var lineObj = getLine(doc, lineN)
2683   for (;;) {
2684     var found = coordsCharInner(cm, lineObj, lineN, x, y)
2685     var merged = collapsedSpanAtEnd(lineObj)
2686     var mergedPos = merged && merged.find(0, true)
2687     if (merged && (found.ch > mergedPos.from.ch || found.ch == mergedPos.from.ch && found.xRel > 0))
2688       { lineN = lineNo(lineObj = mergedPos.to.line) }
2689     else
2690       { return found }
2691   }
2692 }
2693
2694 function coordsCharInner(cm, lineObj, lineNo, x, y) {
2695   var innerOff = y - heightAtLine(lineObj)
2696   var wrongLine = false, adjust = 2 * cm.display.wrapper.clientWidth
2697   var preparedMeasure = prepareMeasureForLine(cm, lineObj)
2698
2699   function getX(ch) {
2700     var sp = cursorCoords(cm, Pos(lineNo, ch), "line", lineObj, preparedMeasure)
2701     wrongLine = true
2702     if (innerOff > sp.bottom) { return sp.left - adjust }
2703     else if (innerOff < sp.top) { return sp.left + adjust }
2704     else { wrongLine = false }
2705     return sp.left
2706   }
2707
2708   var bidi = getOrder(lineObj), dist = lineObj.text.length
2709   var from = lineLeft(lineObj), to = lineRight(lineObj)
2710   var fromX = getX(from), fromOutside = wrongLine, toX = getX(to), toOutside = wrongLine
2711
2712   if (x > toX) { return PosWithInfo(lineNo, to, toOutside, 1) }
2713   // Do a binary search between these bounds.
2714   for (;;) {
2715     if (bidi ? to == from || to == moveVisually(lineObj, from, 1) : to - from <= 1) {
2716       var ch = x < fromX || x - fromX <= toX - x ? from : to
2717       var outside = ch == from ? fromOutside : toOutside
2718       var xDiff = x - (ch == from ? fromX : toX)
2719       // This is a kludge to handle the case where the coordinates
2720       // are after a line-wrapped line. We should replace it with a
2721       // more general handling of cursor positions around line
2722       // breaks. (Issue #4078)
2723       if (toOutside && !bidi && !/\s/.test(lineObj.text.charAt(ch)) && xDiff > 0 &&
2724           ch < lineObj.text.length && preparedMeasure.view.measure.heights.length > 1) {
2725         var charSize = measureCharPrepared(cm, preparedMeasure, ch, "right")
2726         if (innerOff <= charSize.bottom && innerOff >= charSize.top && Math.abs(x - charSize.right) < xDiff) {
2727           outside = false
2728           ch++
2729           xDiff = x - charSize.right
2730         }
2731       }
2732       while (isExtendingChar(lineObj.text.charAt(ch))) { ++ch }
2733       var pos = PosWithInfo(lineNo, ch, outside, xDiff < -1 ? -1 : xDiff > 1 ? 1 : 0)
2734       return pos
2735     }
2736     var step = Math.ceil(dist / 2), middle = from + step
2737     if (bidi) {
2738       middle = from
2739       for (var i = 0; i < step; ++i) { middle = moveVisually(lineObj, middle, 1) }
2740     }
2741     var middleX = getX(middle)
2742     if (middleX > x) {to = middle; toX = middleX; if (toOutside = wrongLine) { toX += 1000; } dist = step}
2743     else {from = middle; fromX = middleX; fromOutside = wrongLine; dist -= step}
2744   }
2745 }
2746
2747 var measureText
2748 // Compute the default text height.
2749 function textHeight(display) {
2750   if (display.cachedTextHeight != null) { return display.cachedTextHeight }
2751   if (measureText == null) {
2752     measureText = elt("pre")
2753     // Measure a bunch of lines, for browsers that compute
2754     // fractional heights.
2755     for (var i = 0; i < 49; ++i) {
2756       measureText.appendChild(document.createTextNode("x"))
2757       measureText.appendChild(elt("br"))
2758     }
2759     measureText.appendChild(document.createTextNode("x"))
2760   }
2761   removeChildrenAndAdd(display.measure, measureText)
2762   var height = measureText.offsetHeight / 50
2763   if (height > 3) { display.cachedTextHeight = height }
2764   removeChildren(display.measure)
2765   return height || 1
2766 }
2767
2768 // Compute the default character width.
2769 function charWidth(display) {
2770   if (display.cachedCharWidth != null) { return display.cachedCharWidth }
2771   var anchor = elt("span", "xxxxxxxxxx")
2772   var pre = elt("pre", [anchor])
2773   removeChildrenAndAdd(display.measure, pre)
2774   var rect = anchor.getBoundingClientRect(), width = (rect.right - rect.left) / 10
2775   if (width > 2) { display.cachedCharWidth = width }
2776   return width || 10
2777 }
2778
2779 // Do a bulk-read of the DOM positions and sizes needed to draw the
2780 // view, so that we don't interleave reading and writing to the DOM.
2781 function getDimensions(cm) {
2782   var d = cm.display, left = {}, width = {}
2783   var gutterLeft = d.gutters.clientLeft
2784   for (var n = d.gutters.firstChild, i = 0; n; n = n.nextSibling, ++i) {
2785     left[cm.options.gutters[i]] = n.offsetLeft + n.clientLeft + gutterLeft
2786     width[cm.options.gutters[i]] = n.clientWidth
2787   }
2788   return {fixedPos: compensateForHScroll(d),
2789           gutterTotalWidth: d.gutters.offsetWidth,
2790           gutterLeft: left,
2791           gutterWidth: width,
2792           wrapperWidth: d.wrapper.clientWidth}
2793 }
2794
2795 // Computes display.scroller.scrollLeft + display.gutters.offsetWidth,
2796 // but using getBoundingClientRect to get a sub-pixel-accurate
2797 // result.
2798 function compensateForHScroll(display) {
2799   return display.scroller.getBoundingClientRect().left - display.sizer.getBoundingClientRect().left
2800 }
2801
2802 // Returns a function that estimates the height of a line, to use as
2803 // first approximation until the line becomes visible (and is thus
2804 // properly measurable).
2805 function estimateHeight(cm) {
2806   var th = textHeight(cm.display), wrapping = cm.options.lineWrapping
2807   var perLine = wrapping && Math.max(5, cm.display.scroller.clientWidth / charWidth(cm.display) - 3)
2808   return function (line) {
2809     if (lineIsHidden(cm.doc, line)) { return 0 }
2810
2811     var widgetsHeight = 0
2812     if (line.widgets) { for (var i = 0; i < line.widgets.length; i++) {
2813       if (line.widgets[i].height) { widgetsHeight += line.widgets[i].height }
2814     } }
2815
2816     if (wrapping)
2817       { return widgetsHeight + (Math.ceil(line.text.length / perLine) || 1) * th }
2818     else
2819       { return widgetsHeight + th }
2820   }
2821 }
2822
2823 function estimateLineHeights(cm) {
2824   var doc = cm.doc, est = estimateHeight(cm)
2825   doc.iter(function (line) {
2826     var estHeight = est(line)
2827     if (estHeight != line.height) { updateLineHeight(line, estHeight) }
2828   })
2829 }
2830
2831 // Given a mouse event, find the corresponding position. If liberal
2832 // is false, it checks whether a gutter or scrollbar was clicked,
2833 // and returns null if it was. forRect is used by rectangular
2834 // selections, and tries to estimate a character position even for
2835 // coordinates beyond the right of the text.
2836 function posFromMouse(cm, e, liberal, forRect) {
2837   var display = cm.display
2838   if (!liberal && e_target(e).getAttribute("cm-not-content") == "true") { return null }
2839
2840   var x, y, space = display.lineSpace.getBoundingClientRect()
2841   // Fails unpredictably on IE[67] when mouse is dragged around quickly.
2842   try { x = e.clientX - space.left; y = e.clientY - space.top }
2843   catch (e) { return null }
2844   var coords = coordsChar(cm, x, y), line
2845   if (forRect && coords.xRel == 1 && (line = getLine(cm.doc, coords.line).text).length == coords.ch) {
2846     var colDiff = countColumn(line, line.length, cm.options.tabSize) - line.length
2847     coords = Pos(coords.line, Math.max(0, Math.round((x - paddingH(cm.display).left) / charWidth(cm.display)) - colDiff))
2848   }
2849   return coords
2850 }
2851
2852 // Find the view element corresponding to a given line. Return null
2853 // when the line isn't visible.
2854 function findViewIndex(cm, n) {
2855   if (n >= cm.display.viewTo) { return null }
2856   n -= cm.display.viewFrom
2857   if (n < 0) { return null }
2858   var view = cm.display.view
2859   for (var i = 0; i < view.length; i++) {
2860     n -= view[i].size
2861     if (n < 0) { return i }
2862   }
2863 }
2864
2865 function updateSelection(cm) {
2866   cm.display.input.showSelection(cm.display.input.prepareSelection())
2867 }
2868
2869 function prepareSelection(cm, primary) {
2870   var doc = cm.doc, result = {}
2871   var curFragment = result.cursors = document.createDocumentFragment()
2872   var selFragment = result.selection = document.createDocumentFragment()
2873
2874   for (var i = 0; i < doc.sel.ranges.length; i++) {
2875     if (primary === false && i == doc.sel.primIndex) { continue }
2876     var range = doc.sel.ranges[i]
2877     if (range.from().line >= cm.display.viewTo || range.to().line < cm.display.viewFrom) { continue }
2878     var collapsed = range.empty()
2879     if (collapsed || cm.options.showCursorWhenSelecting)
2880       { drawSelectionCursor(cm, range.head, curFragment) }
2881     if (!collapsed)
2882       { drawSelectionRange(cm, range, selFragment) }
2883   }
2884   return result
2885 }
2886
2887 // Draws a cursor for the given range
2888 function drawSelectionCursor(cm, head, output) {
2889   var pos = cursorCoords(cm, head, "div", null, null, !cm.options.singleCursorHeightPerLine)
2890
2891   var cursor = output.appendChild(elt("div", "\u00a0", "CodeMirror-cursor"))
2892   cursor.style.left = pos.left + "px"
2893   cursor.style.top = pos.top + "px"
2894   cursor.style.height = Math.max(0, pos.bottom - pos.top) * cm.options.cursorHeight + "px"
2895
2896   if (pos.other) {
2897     // Secondary cursor, shown when on a 'jump' in bi-directional text
2898     var otherCursor = output.appendChild(elt("div", "\u00a0", "CodeMirror-cursor CodeMirror-secondarycursor"))
2899     otherCursor.style.display = ""
2900     otherCursor.style.left = pos.other.left + "px"
2901     otherCursor.style.top = pos.other.top + "px"
2902     otherCursor.style.height = (pos.other.bottom - pos.other.top) * .85 + "px"
2903   }
2904 }
2905
2906 // Draws the given range as a highlighted selection
2907 function drawSelectionRange(cm, range, output) {
2908   var display = cm.display, doc = cm.doc
2909   var fragment = document.createDocumentFragment()
2910   var padding = paddingH(cm.display), leftSide = padding.left
2911   var rightSide = Math.max(display.sizerWidth, displayWidth(cm) - display.sizer.offsetLeft) - padding.right
2912
2913   function add(left, top, width, bottom) {
2914     if (top < 0) { top = 0 }
2915     top = Math.round(top)
2916     bottom = Math.round(bottom)
2917     fragment.appendChild(elt("div", null, "CodeMirror-selected", ("position: absolute; left: " + left + "px;\n                             top: " + top + "px; width: " + (width == null ? rightSide - left : width) + "px;\n                             height: " + (bottom - top) + "px")))
2918   }
2919
2920   function drawForLine(line, fromArg, toArg) {
2921     var lineObj = getLine(doc, line)
2922     var lineLen = lineObj.text.length
2923     var start, end
2924     function coords(ch, bias) {
2925       return charCoords(cm, Pos(line, ch), "div", lineObj, bias)
2926     }
2927
2928     iterateBidiSections(getOrder(lineObj), fromArg || 0, toArg == null ? lineLen : toArg, function (from, to, dir) {
2929       var leftPos = coords(from, "left"), rightPos, left, right
2930       if (from == to) {
2931         rightPos = leftPos
2932         left = right = leftPos.left
2933       } else {
2934         rightPos = coords(to - 1, "right")
2935         if (dir == "rtl") { var tmp = leftPos; leftPos = rightPos; rightPos = tmp }
2936         left = leftPos.left
2937         right = rightPos.right
2938       }
2939       if (fromArg == null && from == 0) { left = leftSide }
2940       if (rightPos.top - leftPos.top > 3) { // Different lines, draw top part
2941         add(left, leftPos.top, null, leftPos.bottom)
2942         left = leftSide
2943         if (leftPos.bottom < rightPos.top) { add(left, leftPos.bottom, null, rightPos.top) }
2944       }
2945       if (toArg == null && to == lineLen) { right = rightSide }
2946       if (!start || leftPos.top < start.top || leftPos.top == start.top && leftPos.left < start.left)
2947         { start = leftPos }
2948       if (!end || rightPos.bottom > end.bottom || rightPos.bottom == end.bottom && rightPos.right > end.right)
2949         { end = rightPos }
2950       if (left < leftSide + 1) { left = leftSide }
2951       add(left, rightPos.top, right - left, rightPos.bottom)
2952     })
2953     return {start: start, end: end}
2954   }
2955
2956   var sFrom = range.from(), sTo = range.to()
2957   if (sFrom.line == sTo.line) {
2958     drawForLine(sFrom.line, sFrom.ch, sTo.ch)
2959   } else {
2960     var fromLine = getLine(doc, sFrom.line), toLine = getLine(doc, sTo.line)
2961     var singleVLine = visualLine(fromLine) == visualLine(toLine)
2962     var leftEnd = drawForLine(sFrom.line, sFrom.ch, singleVLine ? fromLine.text.length + 1 : null).end
2963     var rightStart = drawForLine(sTo.line, singleVLine ? 0 : null, sTo.ch).start
2964     if (singleVLine) {
2965       if (leftEnd.top < rightStart.top - 2) {
2966         add(leftEnd.right, leftEnd.top, null, leftEnd.bottom)
2967         add(leftSide, rightStart.top, rightStart.left, rightStart.bottom)
2968       } else {
2969         add(leftEnd.right, leftEnd.top, rightStart.left - leftEnd.right, leftEnd.bottom)
2970       }
2971     }
2972     if (leftEnd.bottom < rightStart.top)
2973       { add(leftSide, leftEnd.bottom, null, rightStart.top) }
2974   }
2975
2976   output.appendChild(fragment)
2977 }
2978
2979 // Cursor-blinking
2980 function restartBlink(cm) {
2981   if (!cm.state.focused) { return }
2982   var display = cm.display
2983   clearInterval(display.blinker)
2984   var on = true
2985   display.cursorDiv.style.visibility = ""
2986   if (cm.options.cursorBlinkRate > 0)
2987     { display.blinker = setInterval(function () { return display.cursorDiv.style.visibility = (on = !on) ? "" : "hidden"; },
2988       cm.options.cursorBlinkRate) }
2989   else if (cm.options.cursorBlinkRate < 0)
2990     { display.cursorDiv.style.visibility = "hidden" }
2991 }
2992
2993 function ensureFocus(cm) {
2994   if (!cm.state.focused) { cm.display.input.focus(); onFocus(cm) }
2995 }
2996
2997 function delayBlurEvent(cm) {
2998   cm.state.delayingBlurEvent = true
2999   setTimeout(function () { if (cm.state.delayingBlurEvent) {
3000     cm.state.delayingBlurEvent = false
3001     onBlur(cm)
3002   } }, 100)
3003 }
3004
3005 function onFocus(cm, e) {
3006   if (cm.state.delayingBlurEvent) { cm.state.delayingBlurEvent = false }
3007
3008   if (cm.options.readOnly == "nocursor") { return }
3009   if (!cm.state.focused) {
3010     signal(cm, "focus", cm, e)
3011     cm.state.focused = true
3012     addClass(cm.display.wrapper, "CodeMirror-focused")
3013     // This test prevents this from firing when a context
3014     // menu is closed (since the input reset would kill the
3015     // select-all detection hack)
3016     if (!cm.curOp && cm.display.selForContextMenu != cm.doc.sel) {
3017       cm.display.input.reset()
3018       if (webkit) { setTimeout(function () { return cm.display.input.reset(true); }, 20) } // Issue #1730
3019     }
3020     cm.display.input.receivedFocus()
3021   }
3022   restartBlink(cm)
3023 }
3024 function onBlur(cm, e) {
3025   if (cm.state.delayingBlurEvent) { return }
3026
3027   if (cm.state.focused) {
3028     signal(cm, "blur", cm, e)
3029     cm.state.focused = false
3030     rmClass(cm.display.wrapper, "CodeMirror-focused")
3031   }
3032   clearInterval(cm.display.blinker)
3033   setTimeout(function () { if (!cm.state.focused) { cm.display.shift = false } }, 150)
3034 }
3035
3036 // Re-align line numbers and gutter marks to compensate for
3037 // horizontal scrolling.
3038 function alignHorizontally(cm) {
3039   var display = cm.display, view = display.view
3040   if (!display.alignWidgets && (!display.gutters.firstChild || !cm.options.fixedGutter)) { return }
3041   var comp = compensateForHScroll(display) - display.scroller.scrollLeft + cm.doc.scrollLeft
3042   var gutterW = display.gutters.offsetWidth, left = comp + "px"
3043   for (var i = 0; i < view.length; i++) { if (!view[i].hidden) {
3044     if (cm.options.fixedGutter) {
3045       if (view[i].gutter)
3046         { view[i].gutter.style.left = left }
3047       if (view[i].gutterBackground)
3048         { view[i].gutterBackground.style.left = left }
3049     }
3050     var align = view[i].alignable
3051     if (align) { for (var j = 0; j < align.length; j++)
3052       { align[j].style.left = left } }
3053   } }
3054   if (cm.options.fixedGutter)
3055     { display.gutters.style.left = (comp + gutterW) + "px" }
3056 }
3057
3058 // Used to ensure that the line number gutter is still the right
3059 // size for the current document size. Returns true when an update
3060 // is needed.
3061 function maybeUpdateLineNumberWidth(cm) {
3062   if (!cm.options.lineNumbers) { return false }
3063   var doc = cm.doc, last = lineNumberFor(cm.options, doc.first + doc.size - 1), display = cm.display
3064   if (last.length != display.lineNumChars) {
3065     var test = display.measure.appendChild(elt("div", [elt("div", last)],
3066                                                "CodeMirror-linenumber CodeMirror-gutter-elt"))
3067     var innerW = test.firstChild.offsetWidth, padding = test.offsetWidth - innerW
3068     display.lineGutter.style.width = ""
3069     display.lineNumInnerWidth = Math.max(innerW, display.lineGutter.offsetWidth - padding) + 1
3070     display.lineNumWidth = display.lineNumInnerWidth + padding
3071     display.lineNumChars = display.lineNumInnerWidth ? last.length : -1
3072     display.lineGutter.style.width = display.lineNumWidth + "px"
3073     updateGutterSpace(cm)
3074     return true
3075   }
3076   return false
3077 }
3078
3079 // Read the actual heights of the rendered lines, and update their
3080 // stored heights to match.
3081 function updateHeightsInViewport(cm) {
3082   var display = cm.display
3083   var prevBottom = display.lineDiv.offsetTop
3084   for (var i = 0; i < display.view.length; i++) {
3085     var cur = display.view[i], height = (void 0)
3086     if (cur.hidden) { continue }
3087     if (ie && ie_version < 8) {
3088       var bot = cur.node.offsetTop + cur.node.offsetHeight
3089       height = bot - prevBottom
3090       prevBottom = bot
3091     } else {
3092       var box = cur.node.getBoundingClientRect()
3093       height = box.bottom - box.top
3094     }
3095     var diff = cur.line.height - height
3096     if (height < 2) { height = textHeight(display) }
3097     if (diff > .001 || diff < -.001) {
3098       updateLineHeight(cur.line, height)
3099       updateWidgetHeight(cur.line)
3100       if (cur.rest) { for (var j = 0; j < cur.rest.length; j++)
3101         { updateWidgetHeight(cur.rest[j]) } }
3102     }
3103   }