<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN"
"http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head><meta http-equiv="content-type" content="text/html; charset=utf-8" />
<title>[188325] trunk/Source/WebInspectorUI</title>
</head>
<body>

<style type="text/css"><!--
#msg dl.meta { border: 1px #006 solid; background: #369; padding: 6px; color: #fff; }
#msg dl.meta dt { float: left; width: 6em; font-weight: bold; }
#msg dt:after { content:':';}
#msg dl, #msg dt, #msg ul, #msg li, #header, #footer, #logmsg { font-family: verdana,arial,helvetica,sans-serif; font-size: 10pt;  }
#msg dl a { font-weight: bold}
#msg dl a:link    { color:#fc3; }
#msg dl a:active  { color:#ff0; }
#msg dl a:visited { color:#cc6; }
h3 { font-family: verdana,arial,helvetica,sans-serif; font-size: 10pt; font-weight: bold; }
#msg pre { overflow: auto; background: #ffc; border: 1px #fa0 solid; padding: 6px; }
#logmsg { background: #ffc; border: 1px #fa0 solid; padding: 1em 1em 0 1em; }
#logmsg p, #logmsg pre, #logmsg blockquote { margin: 0 0 1em 0; }
#logmsg p, #logmsg li, #logmsg dt, #logmsg dd { line-height: 14pt; }
#logmsg h1, #logmsg h2, #logmsg h3, #logmsg h4, #logmsg h5, #logmsg h6 { margin: .5em 0; }
#logmsg h1:first-child, #logmsg h2:first-child, #logmsg h3:first-child, #logmsg h4:first-child, #logmsg h5:first-child, #logmsg h6:first-child { margin-top: 0; }
#logmsg ul, #logmsg ol { padding: 0; list-style-position: inside; margin: 0 0 0 1em; }
#logmsg ul { text-indent: -1em; padding-left: 1em; }#logmsg ol { text-indent: -1.5em; padding-left: 1.5em; }
#logmsg > ul, #logmsg > ol { margin: 0 0 1em 0; }
#logmsg pre { background: #eee; padding: 1em; }
#logmsg blockquote { border: 1px solid #fa0; border-left-width: 10px; padding: 1em 1em 0 1em; background: white;}
#logmsg dl { margin: 0; }
#logmsg dt { font-weight: bold; }
#logmsg dd { margin: 0; padding: 0 0 0.5em 0; }
#logmsg dd:before { content:'\00bb';}
#logmsg table { border-spacing: 0px; border-collapse: collapse; border-top: 4px solid #fa0; border-bottom: 1px solid #fa0; background: #fff; }
#logmsg table th { text-align: left; font-weight: normal; padding: 0.2em 0.5em; border-top: 1px dotted #fa0; }
#logmsg table td { text-align: right; border-top: 1px dotted #fa0; padding: 0.2em 0.5em; }
#logmsg table thead th { text-align: center; border-bottom: 1px solid #fa0; }
#logmsg table th.Corner { text-align: left; }
#logmsg hr { border: none 0; border-top: 2px dashed #fa0; height: 1px; }
#header, #footer { color: #fff; background: #636; border: 1px #300 solid; padding: 6px; }
#patch { width: 100%; }
#patch h4 {font-family: verdana,arial,helvetica,sans-serif;font-size:10pt;padding:8px;background:#369;color:#fff;margin:0;}
#patch .propset h4, #patch .binary h4 {margin:0;}
#patch pre {padding:0;line-height:1.2em;margin:0;}
#patch .diff {width:100%;background:#eee;padding: 0 0 10px 0;overflow:auto;}
#patch .propset .diff, #patch .binary .diff  {padding:10px 0;}
#patch span {display:block;padding:0 10px;}
#patch .modfile, #patch .addfile, #patch .delfile, #patch .propset, #patch .binary, #patch .copfile {border:1px solid #ccc;margin:10px 0;}
#patch ins {background:#dfd;text-decoration:none;display:block;padding:0 10px;}
#patch del {background:#fdd;text-decoration:none;display:block;padding:0 10px;}
#patch .lines, .info {color:#888;background:#fff;}
--></style>
<div id="msg">
<dl class="meta">
<dt>Revision</dt> <dd><a href="http://trac.webkit.org/projects/webkit/changeset/188325">188325</a></dd>
<dt>Author</dt> <dd>drousso@apple.com</dd>
<dt>Date</dt> <dd>2015-08-11 22:40:27 -0700 (Tue, 11 Aug 2015)</dd>
</dl>

<h3>Log Message</h3>
<pre>Web Inspector: Update to CodeMirror 5.5 or later
https://bugs.webkit.org/show_bug.cgi?id=147109

Reviewed by Timothy Hatcher.

Updated CodeMirror to version 5.5, as well as the extension files for CodeMirror
that are currently used in WebInspector.

* Localizations/en.lproj/localizedStrings.js:
* Tools/PrettyPrinting/FormatterDebug.js:
Added WebInspector namespace for formatters.

* Tools/PrettyPrinting/index.html:
Added WebInspector namespace for formatters.

* UserInterface/External/CodeMirror/LICENSE:
* UserInterface/External/CodeMirror/clojure.js:
* UserInterface/External/CodeMirror/closebrackets.js:
* UserInterface/External/CodeMirror/codemirror.css:
* UserInterface/External/CodeMirror/codemirror.js:
* UserInterface/External/CodeMirror/coffeescript.js:
* UserInterface/External/CodeMirror/comment.js:
* UserInterface/External/CodeMirror/css.js:
* UserInterface/External/CodeMirror/htmlmixed.js:
* UserInterface/External/CodeMirror/javascript.js:
* UserInterface/External/CodeMirror/livescript.js:
* UserInterface/External/CodeMirror/matchbrackets.js:
* UserInterface/External/CodeMirror/overlay.js:
* UserInterface/External/CodeMirror/sass.js:
* UserInterface/External/CodeMirror/searchcursor.js:
* UserInterface/External/CodeMirror/sql.js:
* UserInterface/External/CodeMirror/xml.js:
* UserInterface/Views/CodeMirrorFormatters.js:
Now uses the new token in CodeMirror for media query parenthesis.

* UserInterface/Views/CSSStyleDeclarationTextEditor.css:
(.css-style-text-editor &gt; .CodeMirror pre):
Removed the additional vertical padding.

* UserInterface/Views/CSSStyleDeclarationTextEditor.js:
(WebInspector.CSSStyleDeclarationTextEditor.prototype._handleMouseDown):
(WebInspector.CSSStyleDeclarationTextEditor.prototype._handleMouseUp):
Clicking on the end of a line in a style will now correctly insert a new line.

* UserInterface/Views/ComputedStyleDetailsPanel.css:
(.details-section &gt; .content &gt; .group &gt; .row .CodeMirror-code pre .go-to-arrow):
The go-to arrow now has the proper dimensions.

* UserInterface/Views/HoverMenu.css:
(.hover-menu &gt; img):
* UserInterface/Views/SourceCodeTextEditor.css:
(.hover-menu.color &gt; img):</pre>

<h3>Modified Paths</h3>
<ul>
<li><a href="#trunkSourceWebInspectorUIChangeLog">trunk/Source/WebInspectorUI/ChangeLog</a></li>
<li><a href="#trunkSourceWebInspectorUILocalizationsenlprojlocalizedStringsjs">trunk/Source/WebInspectorUI/Localizations/en.lproj/localizedStrings.js</a></li>
<li><a href="#trunkSourceWebInspectorUIToolsPrettyPrintingFormatterDebugjs">trunk/Source/WebInspectorUI/Tools/PrettyPrinting/FormatterDebug.js</a></li>
<li><a href="#trunkSourceWebInspectorUIToolsPrettyPrintingindexhtml">trunk/Source/WebInspectorUI/Tools/PrettyPrinting/index.html</a></li>
<li><a href="#trunkSourceWebInspectorUIUserInterfaceExternalCodeMirrorLICENSE">trunk/Source/WebInspectorUI/UserInterface/External/CodeMirror/LICENSE</a></li>
<li><a href="#trunkSourceWebInspectorUIUserInterfaceExternalCodeMirrorclojurejs">trunk/Source/WebInspectorUI/UserInterface/External/CodeMirror/clojure.js</a></li>
<li><a href="#trunkSourceWebInspectorUIUserInterfaceExternalCodeMirrorclosebracketsjs">trunk/Source/WebInspectorUI/UserInterface/External/CodeMirror/closebrackets.js</a></li>
<li><a href="#trunkSourceWebInspectorUIUserInterfaceExternalCodeMirrorcodemirrorcss">trunk/Source/WebInspectorUI/UserInterface/External/CodeMirror/codemirror.css</a></li>
<li><a href="#trunkSourceWebInspectorUIUserInterfaceExternalCodeMirrorcodemirrorjs">trunk/Source/WebInspectorUI/UserInterface/External/CodeMirror/codemirror.js</a></li>
<li><a href="#trunkSourceWebInspectorUIUserInterfaceExternalCodeMirrorcoffeescriptjs">trunk/Source/WebInspectorUI/UserInterface/External/CodeMirror/coffeescript.js</a></li>
<li><a href="#trunkSourceWebInspectorUIUserInterfaceExternalCodeMirrorcommentjs">trunk/Source/WebInspectorUI/UserInterface/External/CodeMirror/comment.js</a></li>
<li><a href="#trunkSourceWebInspectorUIUserInterfaceExternalCodeMirrorcssjs">trunk/Source/WebInspectorUI/UserInterface/External/CodeMirror/css.js</a></li>
<li><a href="#trunkSourceWebInspectorUIUserInterfaceExternalCodeMirrorhtmlmixedjs">trunk/Source/WebInspectorUI/UserInterface/External/CodeMirror/htmlmixed.js</a></li>
<li><a href="#trunkSourceWebInspectorUIUserInterfaceExternalCodeMirrorjavascriptjs">trunk/Source/WebInspectorUI/UserInterface/External/CodeMirror/javascript.js</a></li>
<li><a href="#trunkSourceWebInspectorUIUserInterfaceExternalCodeMirrorlivescriptjs">trunk/Source/WebInspectorUI/UserInterface/External/CodeMirror/livescript.js</a></li>
<li><a href="#trunkSourceWebInspectorUIUserInterfaceExternalCodeMirrormatchbracketsjs">trunk/Source/WebInspectorUI/UserInterface/External/CodeMirror/matchbrackets.js</a></li>
<li><a href="#trunkSourceWebInspectorUIUserInterfaceExternalCodeMirroroverlayjs">trunk/Source/WebInspectorUI/UserInterface/External/CodeMirror/overlay.js</a></li>
<li><a href="#trunkSourceWebInspectorUIUserInterfaceExternalCodeMirrorplaceholderjs">trunk/Source/WebInspectorUI/UserInterface/External/CodeMirror/placeholder.js</a></li>
<li><a href="#trunkSourceWebInspectorUIUserInterfaceExternalCodeMirrorrunmodejs">trunk/Source/WebInspectorUI/UserInterface/External/CodeMirror/runmode.js</a></li>
<li><a href="#trunkSourceWebInspectorUIUserInterfaceExternalCodeMirrorsassjs">trunk/Source/WebInspectorUI/UserInterface/External/CodeMirror/sass.js</a></li>
<li><a href="#trunkSourceWebInspectorUIUserInterfaceExternalCodeMirrorsearchcursorjs">trunk/Source/WebInspectorUI/UserInterface/External/CodeMirror/searchcursor.js</a></li>
<li><a href="#trunkSourceWebInspectorUIUserInterfaceExternalCodeMirrorsqljs">trunk/Source/WebInspectorUI/UserInterface/External/CodeMirror/sql.js</a></li>
<li><a href="#trunkSourceWebInspectorUIUserInterfaceExternalCodeMirrorxmljs">trunk/Source/WebInspectorUI/UserInterface/External/CodeMirror/xml.js</a></li>
<li><a href="#trunkSourceWebInspectorUIUserInterfaceViewsCSSStyleDeclarationTextEditorcss">trunk/Source/WebInspectorUI/UserInterface/Views/CSSStyleDeclarationTextEditor.css</a></li>
<li><a href="#trunkSourceWebInspectorUIUserInterfaceViewsCSSStyleDeclarationTextEditorjs">trunk/Source/WebInspectorUI/UserInterface/Views/CSSStyleDeclarationTextEditor.js</a></li>
<li><a href="#trunkSourceWebInspectorUIUserInterfaceViewsCodeMirrorFormattersjs">trunk/Source/WebInspectorUI/UserInterface/Views/CodeMirrorFormatters.js</a></li>
<li><a href="#trunkSourceWebInspectorUIUserInterfaceViewsComputedStyleDetailsPanelcss">trunk/Source/WebInspectorUI/UserInterface/Views/ComputedStyleDetailsPanel.css</a></li>
<li><a href="#trunkSourceWebInspectorUIUserInterfaceViewsHoverMenucss">trunk/Source/WebInspectorUI/UserInterface/Views/HoverMenu.css</a></li>
<li><a href="#trunkSourceWebInspectorUIUserInterfaceViewsSourceCodeTextEditorcss">trunk/Source/WebInspectorUI/UserInterface/Views/SourceCodeTextEditor.css</a></li>
</ul>

<h3>Property Changed</h3>
<ul>
<li><a href="#trunkSourceWebInspectorUIUserInterfaceExternalCodeMirrorLICENSE">trunk/Source/WebInspectorUI/UserInterface/External/CodeMirror/LICENSE</a></li>
<li><a href="#trunkSourceWebInspectorUIUserInterfaceExternalCodeMirrorclojurejs">trunk/Source/WebInspectorUI/UserInterface/External/CodeMirror/clojure.js</a></li>
<li><a href="#trunkSourceWebInspectorUIUserInterfaceExternalCodeMirrorclosebracketsjs">trunk/Source/WebInspectorUI/UserInterface/External/CodeMirror/closebrackets.js</a></li>
<li><a href="#trunkSourceWebInspectorUIUserInterfaceExternalCodeMirrorcodemirrorcss">trunk/Source/WebInspectorUI/UserInterface/External/CodeMirror/codemirror.css</a></li>
<li><a href="#trunkSourceWebInspectorUIUserInterfaceExternalCodeMirrorcodemirrorjs">trunk/Source/WebInspectorUI/UserInterface/External/CodeMirror/codemirror.js</a></li>
<li><a href="#trunkSourceWebInspectorUIUserInterfaceExternalCodeMirrorcoffeescriptjs">trunk/Source/WebInspectorUI/UserInterface/External/CodeMirror/coffeescript.js</a></li>
<li><a href="#trunkSourceWebInspectorUIUserInterfaceExternalCodeMirrorcommentjs">trunk/Source/WebInspectorUI/UserInterface/External/CodeMirror/comment.js</a></li>
<li><a href="#trunkSourceWebInspectorUIUserInterfaceExternalCodeMirrorcssjs">trunk/Source/WebInspectorUI/UserInterface/External/CodeMirror/css.js</a></li>
<li><a href="#trunkSourceWebInspectorUIUserInterfaceExternalCodeMirrorhtmlmixedjs">trunk/Source/WebInspectorUI/UserInterface/External/CodeMirror/htmlmixed.js</a></li>
<li><a href="#trunkSourceWebInspectorUIUserInterfaceExternalCodeMirrorjavascriptjs">trunk/Source/WebInspectorUI/UserInterface/External/CodeMirror/javascript.js</a></li>
<li><a href="#trunkSourceWebInspectorUIUserInterfaceExternalCodeMirrorlivescriptjs">trunk/Source/WebInspectorUI/UserInterface/External/CodeMirror/livescript.js</a></li>
<li><a href="#trunkSourceWebInspectorUIUserInterfaceExternalCodeMirrormatchbracketsjs">trunk/Source/WebInspectorUI/UserInterface/External/CodeMirror/matchbrackets.js</a></li>
<li><a href="#trunkSourceWebInspectorUIUserInterfaceExternalCodeMirroroverlayjs">trunk/Source/WebInspectorUI/UserInterface/External/CodeMirror/overlay.js</a></li>
<li><a href="#trunkSourceWebInspectorUIUserInterfaceExternalCodeMirrorplaceholderjs">trunk/Source/WebInspectorUI/UserInterface/External/CodeMirror/placeholder.js</a></li>
<li><a href="#trunkSourceWebInspectorUIUserInterfaceExternalCodeMirrorrunmodejs">trunk/Source/WebInspectorUI/UserInterface/External/CodeMirror/runmode.js</a></li>
<li><a href="#trunkSourceWebInspectorUIUserInterfaceExternalCodeMirrorsassjs">trunk/Source/WebInspectorUI/UserInterface/External/CodeMirror/sass.js</a></li>
<li><a href="#trunkSourceWebInspectorUIUserInterfaceExternalCodeMirrorsearchcursorjs">trunk/Source/WebInspectorUI/UserInterface/External/CodeMirror/searchcursor.js</a></li>
<li><a href="#trunkSourceWebInspectorUIUserInterfaceExternalCodeMirrorsqljs">trunk/Source/WebInspectorUI/UserInterface/External/CodeMirror/sql.js</a></li>
<li><a href="#trunkSourceWebInspectorUIUserInterfaceExternalCodeMirrorxmljs">trunk/Source/WebInspectorUI/UserInterface/External/CodeMirror/xml.js</a></li>
</ul>

</div>
<div id="patch">
<h3>Diff</h3>
<a id="trunkSourceWebInspectorUIChangeLog"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebInspectorUI/ChangeLog (188324 => 188325)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebInspectorUI/ChangeLog        2015-08-12 04:58:37 UTC (rev 188324)
+++ trunk/Source/WebInspectorUI/ChangeLog        2015-08-12 05:40:27 UTC (rev 188325)
</span><span class="lines">@@ -1,3 +1,58 @@
</span><ins>+2015-08-11  Devin Rousso  &lt;drousso@apple.com&gt;
+
+        Web Inspector: Update to CodeMirror 5.5 or later
+        https://bugs.webkit.org/show_bug.cgi?id=147109
+
+        Reviewed by Timothy Hatcher.
+
+        Updated CodeMirror to version 5.5, as well as the extension files for CodeMirror
+        that are currently used in WebInspector.
+
+        * Localizations/en.lproj/localizedStrings.js:
+        * Tools/PrettyPrinting/FormatterDebug.js:
+        Added WebInspector namespace for formatters.
+
+        * Tools/PrettyPrinting/index.html:
+        Added WebInspector namespace for formatters.
+
+        * UserInterface/External/CodeMirror/LICENSE:
+        * UserInterface/External/CodeMirror/clojure.js:
+        * UserInterface/External/CodeMirror/closebrackets.js:
+        * UserInterface/External/CodeMirror/codemirror.css:
+        * UserInterface/External/CodeMirror/codemirror.js:
+        * UserInterface/External/CodeMirror/coffeescript.js:
+        * UserInterface/External/CodeMirror/comment.js:
+        * UserInterface/External/CodeMirror/css.js:
+        * UserInterface/External/CodeMirror/htmlmixed.js:
+        * UserInterface/External/CodeMirror/javascript.js:
+        * UserInterface/External/CodeMirror/livescript.js:
+        * UserInterface/External/CodeMirror/matchbrackets.js:
+        * UserInterface/External/CodeMirror/overlay.js:
+        * UserInterface/External/CodeMirror/sass.js:
+        * UserInterface/External/CodeMirror/searchcursor.js:
+        * UserInterface/External/CodeMirror/sql.js:
+        * UserInterface/External/CodeMirror/xml.js:
+        * UserInterface/Views/CodeMirrorFormatters.js:
+        Now uses the new token in CodeMirror for media query parenthesis.
+
+        * UserInterface/Views/CSSStyleDeclarationTextEditor.css:
+        (.css-style-text-editor &gt; .CodeMirror pre):
+        Removed the additional vertical padding.
+
+        * UserInterface/Views/CSSStyleDeclarationTextEditor.js:
+        (WebInspector.CSSStyleDeclarationTextEditor.prototype._handleMouseDown):
+        (WebInspector.CSSStyleDeclarationTextEditor.prototype._handleMouseUp):
+        Clicking on the end of a line in a style will now correctly insert a new line.
+
+        * UserInterface/Views/ComputedStyleDetailsPanel.css:
+        (.details-section &gt; .content &gt; .group &gt; .row .CodeMirror-code pre .go-to-arrow):
+        The go-to arrow now has the proper dimensions.
+
+        * UserInterface/Views/HoverMenu.css:
+        (.hover-menu &gt; img):
+        * UserInterface/Views/SourceCodeTextEditor.css:
+        (.hover-menu.color &gt; img):
+
</ins><span class="cx"> 2015-08-11  Matt Baker  &lt;mattbaker@apple.com&gt;
</span><span class="cx"> 
</span><span class="cx">         Web Inspector: Add the ability to filter out tasks in the Rendering Frames timeline
</span></span></pre></div>
<a id="trunkSourceWebInspectorUILocalizationsenlprojlocalizedStringsjs"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebInspectorUI/Localizations/en.lproj/localizedStrings.js (188324 => 188325)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebInspectorUI/Localizations/en.lproj/localizedStrings.js        2015-08-12 04:58:37 UTC (rev 188324)
+++ trunk/Source/WebInspectorUI/Localizations/en.lproj/localizedStrings.js        2015-08-12 05:40:27 UTC (rev 188325)
</span><span class="lines">@@ -98,10 +98,15 @@
</span><span class="cx"> localizedStrings[&quot;Click Listener&quot;] = &quot;Click Listener&quot;;
</span><span class="cx"> localizedStrings[&quot;Click or press the spacebar to record.&quot;] = &quot;Click or press the spacebar to record.&quot;;
</span><span class="cx"> localizedStrings[&quot;Click or press the spacebar to stop recording.&quot;] = &quot;Click or press the spacebar to stop recording.&quot;;
</span><ins>+localizedStrings[&quot;Click to add a new rule.&quot;] = &quot;Click to add a new rule.&quot;;
</ins><span class="cx"> localizedStrings[&quot;Click to close this tab&quot;] = &quot;Click to close this tab&quot;;
</span><del>-localizedStrings[&quot;Click to open a colorpicker. Shift-click to change color format.&quot;] = &quot;Click to open a colorpicker. Shift-click to change color format.&quot;;
</del><ins>+localizedStrings[&quot;Click to disable the selected rule&quot;] = &quot;Click to disable the selected rule&quot;;
+localizedStrings[&quot;Click to enable the selected rule&quot;] = &quot;Click to enable the selected rule&quot;;
+localizedStrings[&quot;Click to link property values&quot;] = &quot;Click to link property values&quot;;
</ins><span class="cx"> localizedStrings[&quot;Click to open a cubic-bezier editor&quot;] = &quot;Click to open a cubic-bezier editor&quot;;
</span><ins>+localizedStrings[&quot;Click to remove link&quot;] = &quot;Click to remove link&quot;;
</ins><span class="cx"> localizedStrings[&quot;Click to restart the animation&quot;] = &quot;Click to restart the animation&quot;;
</span><ins>+localizedStrings[&quot;Click to select a color. Shift-click to switch color formats.&quot;] = &quot;Click to select a color. Shift-click to switch color formats.&quot;;
</ins><span class="cx"> localizedStrings[&quot;Clickable&quot;] = &quot;Clickable&quot;;
</span><span class="cx"> localizedStrings[&quot;Close&quot;] = &quot;Close&quot;;
</span><span class="cx"> localizedStrings[&quot;Close %s timeline view&quot;] = &quot;Close %s timeline view&quot;;
</span><span class="lines">@@ -215,6 +220,8 @@
</span><span class="cx"> localizedStrings[&quot;Encoded&quot;] = &quot;Encoded&quot;;
</span><span class="cx"> localizedStrings[&quot;Encoding&quot;] = &quot;Encoding&quot;;
</span><span class="cx"> localizedStrings[&quot;End Capturing&quot;] = &quot;End Capturing&quot;;
</span><ins>+localizedStrings[&quot;Enter a URL&quot;] = &quot;Enter a URL&quot;;
+localizedStrings[&quot;Enter a name.&quot;] = &quot;Enter a name.&quot;;
</ins><span class="cx"> localizedStrings[&quot;Error: &quot;] = &quot;Error: &quot;;
</span><span class="cx"> localizedStrings[&quot;Errors&quot;] = &quot;Errors&quot;;
</span><span class="cx"> localizedStrings[&quot;Evaluate JavaScript&quot;] = &quot;Evaluate JavaScript&quot;;
</span><span class="lines">@@ -281,6 +288,7 @@
</span><span class="cx"> localizedStrings[&quot;Indexed Databases&quot;] = &quot;Indexed Databases&quot;;
</span><span class="cx"> localizedStrings[&quot;Info: &quot;] = &quot;Info: &quot;;
</span><span class="cx"> localizedStrings[&quot;Inherited From: &quot;] = &quot;Inherited From: &quot;;
</span><ins>+localizedStrings[&quot;Inherited from %s&quot;] = &quot;Inherited from %s&quot;;
</ins><span class="cx"> localizedStrings[&quot;Initiator&quot;] = &quot;Initiator&quot;;
</span><span class="cx"> localizedStrings[&quot;Input: &quot;] = &quot;Input: &quot;;
</span><span class="cx"> localizedStrings[&quot;Invalid&quot;] = &quot;Invalid&quot;;
</span><span class="lines">@@ -350,12 +358,15 @@
</span><span class="cx"> localizedStrings[&quot;No Response Headers&quot;] = &quot;No Response Headers&quot;;
</span><span class="cx"> localizedStrings[&quot;No Results Found&quot;] = &quot;No Results Found&quot;;
</span><span class="cx"> localizedStrings[&quot;No Search Results&quot;] = &quot;No Search Results&quot;;
</span><ins>+localizedStrings[&quot;No Units&quot;] = &quot;No Units&quot;;
</ins><span class="cx"> localizedStrings[&quot;No exact ARIA role match.&quot;] = &quot;No exact ARIA role match.&quot;;
</span><span class="cx"> localizedStrings[&quot;No message&quot;] = &quot;No message&quot;;
</span><span class="cx"> localizedStrings[&quot;No properties.&quot;] = &quot;No properties.&quot;;
</span><span class="cx"> localizedStrings[&quot;Node&quot;] = &quot;Node&quot;;
</span><span class="cx"> localizedStrings[&quot;Not found&quot;] = &quot;Not found&quot;;
</span><span class="cx"> localizedStrings[&quot;Online&quot;] = &quot;Online&quot;;
</span><ins>+localizedStrings[&quot;Option-click to show all units&quot;] = &quot;Option-click to show all units&quot;;
+localizedStrings[&quot;Option-click to show all values&quot;] = &quot;Option-click to show all values&quot;;
</ins><span class="cx"> localizedStrings[&quot;Options&quot;] = &quot;Options&quot;;
</span><span class="cx"> localizedStrings[&quot;Original&quot;] = &quot;Original&quot;;
</span><span class="cx"> localizedStrings[&quot;Original formatting&quot;] = &quot;Original formatting&quot;;
</span><span class="lines">@@ -410,6 +421,7 @@
</span><span class="cx"> localizedStrings[&quot;Request Data&quot;] = &quot;Request Data&quot;;
</span><span class="cx"> localizedStrings[&quot;Request Headers&quot;] = &quot;Request Headers&quot;;
</span><span class="cx"> localizedStrings[&quot;Required&quot;] = &quot;Required&quot;;
</span><ins>+localizedStrings[&quot;Reset&quot;] = &quot;Reset&quot;;
</ins><span class="cx"> localizedStrings[&quot;Resource&quot;] = &quot;Resource&quot;;
</span><span class="cx"> localizedStrings[&quot;Resource Type&quot;] = &quot;Resource Type&quot;;
</span><span class="cx"> localizedStrings[&quot;Resources&quot;] = &quot;Resources&quot;;
</span><span class="lines">@@ -478,11 +490,11 @@
</span><span class="cx"> localizedStrings[&quot;Storage&quot;] = &quot;Storage&quot;;
</span><span class="cx"> localizedStrings[&quot;Style&quot;] = &quot;Style&quot;;
</span><span class="cx"> localizedStrings[&quot;Style Attribute&quot;] = &quot;Style Attribute&quot;;
</span><ins>+localizedStrings[&quot;Style Rules&quot;] = &quot;Style Rules&quot;;
</ins><span class="cx"> localizedStrings[&quot;Styles&quot;] = &quot;Styles&quot;;
</span><span class="cx"> localizedStrings[&quot;Styles Invalidated&quot;] = &quot;Styles Invalidated&quot;;
</span><span class="cx"> localizedStrings[&quot;Styles Recalculated&quot;] = &quot;Styles Recalculated&quot;;
</span><span class="cx"> localizedStrings[&quot;Styles \u2014 Computed&quot;] = &quot;Styles \u2014 Computed&quot;;
</span><del>-localizedStrings[&quot;Styles \u2014 Metrics&quot;] = &quot;Styles \u2014 Metrics&quot;;
</del><span class="cx"> localizedStrings[&quot;Styles \u2014 Rules&quot;] = &quot;Styles \u2014 Rules&quot;;
</span><span class="cx"> localizedStrings[&quot;Stylesheet&quot;] = &quot;Stylesheet&quot;;
</span><span class="cx"> localizedStrings[&quot;Stylesheets&quot;] = &quot;Stylesheets&quot;;
</span><span class="lines">@@ -496,6 +508,7 @@
</span><span class="cx"> localizedStrings[&quot;The value '%s' is not supported for this property.\nClick to delete and open autocomplete.&quot;] = &quot;The value '%s' is not supported for this property.\nClick to delete and open autocomplete.&quot;;
</span><span class="cx"> localizedStrings[&quot;The value '%s' needs units.\nClick to add 'px' to the value.&quot;] = &quot;The value '%s' needs units.\nClick to add 'px' to the value.&quot;;
</span><span class="cx"> localizedStrings[&quot;The  %s \ntable is empty.&quot;] = &quot;The  %s \ntable is empty.&quot;;
</span><ins>+localizedStrings[&quot;This Element&quot;] = &quot;This Element&quot;;
</ins><span class="cx"> localizedStrings[&quot;This property needs a value.\nClick to open autocomplete.&quot;] = &quot;This property needs a value.\nClick to open autocomplete.&quot;;
</span><span class="cx"> localizedStrings[&quot;Time until the load event fired, click to show the Network Requests timeline&quot;] = &quot;Time until the load event fired, click to show the Network Requests timeline&quot;;
</span><span class="cx"> localizedStrings[&quot;Timeline Events&quot;] = &quot;Timeline Events&quot;;
</span><span class="lines">@@ -516,6 +529,7 @@
</span><span class="cx"> localizedStrings[&quot;Type Issue&quot;] = &quot;Type Issue&quot;;
</span><span class="cx"> localizedStrings[&quot;Type information for variable: %s&quot;] = &quot;Type information for variable: %s&quot;;
</span><span class="cx"> localizedStrings[&quot;Unable to determine path to property from root&quot;] = &quot;Unable to determine path to property from root&quot;;
</span><ins>+localizedStrings[&quot;Unchanged&quot;] = &quot;Unchanged&quot;;
</ins><span class="cx"> localizedStrings[&quot;Uncomment All Properties&quot;] = &quot;Uncomment All Properties&quot;;
</span><span class="cx"> localizedStrings[&quot;Unknown node&quot;] = &quot;Unknown node&quot;;
</span><span class="cx"> localizedStrings[&quot;Untitled&quot;] = &quot;Untitled&quot;;
</span></span></pre></div>
<a id="trunkSourceWebInspectorUIToolsPrettyPrintingFormatterDebugjs"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebInspectorUI/Tools/PrettyPrinting/FormatterDebug.js (188324 => 188325)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebInspectorUI/Tools/PrettyPrinting/FormatterDebug.js        2015-08-12 04:58:37 UTC (rev 188324)
+++ trunk/Source/WebInspectorUI/Tools/PrettyPrinting/FormatterDebug.js        2015-08-12 05:40:27 UTC (rev 188325)
</span><span class="lines">@@ -1,4 +1,4 @@
</span><del>-Formatter.prototype.debug = function(from, to)
</del><ins>+WebInspector.Formatter.prototype.debug = function(from, to)
</ins><span class="cx"> {
</span><span class="cx">     var debug = &quot;&quot;;
</span><span class="cx">     var outerMode = this._codeMirror.getMode();
</span></span></pre></div>
<a id="trunkSourceWebInspectorUIToolsPrettyPrintingindexhtml"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebInspectorUI/Tools/PrettyPrinting/index.html (188324 => 188325)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebInspectorUI/Tools/PrettyPrinting/index.html        2015-08-12 04:58:37 UTC (rev 188324)
+++ trunk/Source/WebInspectorUI/Tools/PrettyPrinting/index.html        2015-08-12 05:40:27 UTC (rev 188325)
</span><span class="lines">@@ -210,8 +210,8 @@
</span><span class="cx">         var originalLineEndings = [];
</span><span class="cx">         var formattedLineEndings = [];
</span><span class="cx">         var mapping = {original: [0], formatted: [0]};
</span><del>-        var builder = new FormatterContentBuilder(mapping, originalLineEndings, formattedLineEndings, 0, 0, indentString);
-        var formatter = new Formatter(cm, builder);
</del><ins>+        var builder = new WebInspector.FormatterContentBuilder(mapping, originalLineEndings, formattedLineEndings, 0, 0, indentString);
+        var formatter = new WebInspector.Formatter(cm, builder);
</ins><span class="cx"> 
</span><span class="cx">         // Time the formatter.
</span><span class="cx">         var startTime = Date.now();
</span><span class="lines">@@ -332,8 +332,8 @@
</span><span class="cx">             var originalLineEndings = [];
</span><span class="cx">             var formattedLineEndings = [];
</span><span class="cx">             var mapping = {original: [0], formatted: [0]};
</span><del>-            var builder = new FormatterContentBuilder(mapping, originalLineEndings, formattedLineEndings, 0, 0, indentString);
-            var formatter = new Formatter(editor, builder);
</del><ins>+            var builder = new WebInspector.FormatterContentBuilder(mapping, originalLineEndings, formattedLineEndings, 0, 0, indentString);
+            var formatter = new WebInspector.Formatter(editor, builder);
</ins><span class="cx">             formatter.format(start, end);
</span><span class="cx"> 
</span><span class="cx">             // Compare results.
</span></span></pre></div>
<a id="trunkSourceWebInspectorUIUserInterfaceExternalCodeMirrorLICENSE"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebInspectorUI/UserInterface/External/CodeMirror/LICENSE (188324 => 188325)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebInspectorUI/UserInterface/External/CodeMirror/LICENSE        2015-08-12 04:58:37 UTC (rev 188324)
+++ trunk/Source/WebInspectorUI/UserInterface/External/CodeMirror/LICENSE        2015-08-12 05:40:27 UTC (rev 188325)
</span><span class="lines">@@ -1,4 +1,4 @@
</span><del>-Copyright (C) 2013 by Marijn Haverbeke &lt;marijnh@gmail.com&gt;
</del><ins>+Copyright (C) 2015 by Marijn Haverbeke &lt;marijnh@gmail.com&gt; and others
</ins><span class="cx"> 
</span><span class="cx"> Permission is hereby granted, free of charge, to any person obtaining a copy
</span><span class="cx"> of this software and associated documentation files (the &quot;Software&quot;), to deal
</span><span class="lines">@@ -17,7 +17,3 @@
</span><span class="cx"> LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
</span><span class="cx"> OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
</span><span class="cx"> THE SOFTWARE.
</span><del>-
-Please note that some subdirectories of the CodeMirror distribution
-include their own LICENSE files, and are released under different
-licences.
</del><span class="cx">Property changes on: trunk/Source/WebInspectorUI/UserInterface/External/CodeMirror/LICENSE
</span><span class="cx">___________________________________________________________________
</span></span></pre></div>
<a id="svnexecutable"></a>
<div class="addfile"><h4>Added: svn:executable</h4></div>
<a id="trunkSourceWebInspectorUIUserInterfaceExternalCodeMirrorclojurejs"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebInspectorUI/UserInterface/External/CodeMirror/clojure.js (188324 => 188325)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebInspectorUI/UserInterface/External/CodeMirror/clojure.js        2015-08-12 04:58:37 UTC (rev 188324)
+++ trunk/Source/WebInspectorUI/UserInterface/External/CodeMirror/clojure.js        2015-08-12 05:40:27 UTC (rev 188325)
</span><span class="lines">@@ -18,7 +18,7 @@
</span><span class="cx"> 
</span><span class="cx"> CodeMirror.defineMode(&quot;clojure&quot;, function (options) {
</span><span class="cx">     var BUILTIN = &quot;builtin&quot;, COMMENT = &quot;comment&quot;, STRING = &quot;string&quot;, CHARACTER = &quot;string-2&quot;,
</span><del>-        ATOM = &quot;atom&quot;, NUMBER = &quot;number&quot;, BRACKET = &quot;bracket&quot;, KEYWORD = &quot;keyword&quot;;
</del><ins>+        ATOM = &quot;atom&quot;, NUMBER = &quot;number&quot;, BRACKET = &quot;bracket&quot;, KEYWORD = &quot;keyword&quot;, VAR = &quot;variable&quot;;
</ins><span class="cx">     var INDENT_WORD_SKIP = options.indentUnit || 2;
</span><span class="cx">     var NORMAL_INDENT_UNIT = options.indentUnit || 2;
</span><span class="cx"> 
</span><span class="lines">@@ -59,7 +59,7 @@
</span><span class="cx">         sign: /[+-]/,
</span><span class="cx">         exponent: /e/i,
</span><span class="cx">         keyword_char: /[^\s\(\[\;\)\]]/,
</span><del>-        symbol: /[\w*+!\-\._?:&lt;&gt;\/]/
</del><ins>+        symbol: /[\w*+!\-\._?:&lt;&gt;\/\xa1-\uffff]/
</ins><span class="cx">     };
</span><span class="cx"> 
</span><span class="cx">     function stateStack(indent, type, prev) { // represents a state stack object
</span><span class="lines">@@ -114,7 +114,7 @@
</span><span class="cx">         var first = stream.next();
</span><span class="cx">         // Read special literals: backspace, newline, space, return.
</span><span class="cx">         // Just read all lowercase letters.
</span><del>-        if (first.match(/[a-z]/) &amp;&amp; stream.match(/[a-z]+/, true)) {
</del><ins>+        if (first &amp;&amp; first.match(/[a-z]/) &amp;&amp; stream.match(/[a-z]+/, true)) {
</ins><span class="cx">             return;
</span><span class="cx">         }
</span><span class="cx">         // Read unicode character: \u1000 \uA0a1
</span><span class="lines">@@ -220,7 +220,9 @@
</span><span class="cx">                             returnType = BUILTIN;
</span><span class="cx">                         } else if (atoms &amp;&amp; atoms.propertyIsEnumerable(stream.current())) {
</span><span class="cx">                             returnType = ATOM;
</span><del>-                        } else returnType = null;
</del><ins>+                        } else {
+                          returnType = VAR;
+                        }
</ins><span class="cx">                     }
</span><span class="cx">             }
</span><span class="cx"> 
</span><span class="lines">@@ -232,6 +234,7 @@
</span><span class="cx">             return state.indentStack.indent;
</span><span class="cx">         },
</span><span class="cx"> 
</span><ins>+        closeBrackets: {pairs: &quot;()[]{}\&quot;\&quot;&quot;},
</ins><span class="cx">         lineComment: &quot;;;&quot;
</span><span class="cx">     };
</span><span class="cx"> });
</span><span class="cx">Property changes on: trunk/Source/WebInspectorUI/UserInterface/External/CodeMirror/clojure.js
</span><span class="cx">___________________________________________________________________
</span></span></pre></div>
<a id="svnexecutable"></a>
<div class="addfile"><h4>Added: svn:executable</h4></div>
<a id="trunkSourceWebInspectorUIUserInterfaceExternalCodeMirrorclosebracketsjs"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebInspectorUI/UserInterface/External/CodeMirror/closebrackets.js (188324 => 188325)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebInspectorUI/UserInterface/External/CodeMirror/closebrackets.js        2015-08-12 04:58:37 UTC (rev 188324)
+++ trunk/Source/WebInspectorUI/UserInterface/External/CodeMirror/closebrackets.js        2015-08-12 05:40:27 UTC (rev 188325)
</span><span class="lines">@@ -9,135 +9,177 @@
</span><span class="cx">   else // Plain browser env
</span><span class="cx">     mod(CodeMirror);
</span><span class="cx"> })(function(CodeMirror) {
</span><del>-  var DEFAULT_BRACKETS = &quot;()[]{}''\&quot;\&quot;&quot;;
-  var DEFAULT_EXPLODE_ON_ENTER = &quot;[]{}&quot;;
-  var SPACE_CHAR_REGEX = /\s/;
</del><ins>+  var defaults = {
+    pairs: &quot;()[]{}''\&quot;\&quot;&quot;,
+    triples: &quot;&quot;,
+    explode: &quot;[]{}&quot;
+  };
</ins><span class="cx"> 
</span><span class="cx">   var Pos = CodeMirror.Pos;
</span><span class="cx"> 
</span><span class="cx">   CodeMirror.defineOption(&quot;autoCloseBrackets&quot;, false, function(cm, val, old) {
</span><del>-    if (old != CodeMirror.Init &amp;&amp; old)
-      cm.removeKeyMap(&quot;autoCloseBrackets&quot;);
-    if (!val) return;
-    var pairs = DEFAULT_BRACKETS, explode = DEFAULT_EXPLODE_ON_ENTER;
-    if (typeof val == &quot;string&quot;) pairs = val;
-    else if (typeof val == &quot;object&quot;) {
-      if (val.pairs != null) pairs = val.pairs;
-      if (val.explode != null) explode = val.explode;
</del><ins>+    if (old &amp;&amp; old != CodeMirror.Init) {
+      cm.removeKeyMap(keyMap);
+      cm.state.closeBrackets = null;
</ins><span class="cx">     }
</span><del>-    var map = buildKeymap(pairs);
-    if (explode) map.Enter = buildExplodeHandler(explode);
-    cm.addKeyMap(map);
</del><ins>+    if (val) {
+      cm.state.closeBrackets = val;
+      cm.addKeyMap(keyMap);
+    }
</ins><span class="cx">   });
</span><span class="cx"> 
</span><del>-  function charsAround(cm, pos) {
-    var str = cm.getRange(Pos(pos.line, pos.ch - 1),
-                          Pos(pos.line, pos.ch + 1));
-    return str.length == 2 ? str : null;
</del><ins>+  function getOption(conf, name) {
+    if (name == &quot;pairs&quot; &amp;&amp; typeof conf == &quot;string&quot;) return conf;
+    if (typeof conf == &quot;object&quot; &amp;&amp; conf[name] != null) return conf[name];
+    return defaults[name];
</ins><span class="cx">   }
</span><span class="cx"> 
</span><del>-  function buildKeymap(pairs) {
-    var map = {
-      name : &quot;autoCloseBrackets&quot;,
-      Backspace: function(cm) {
-        if (cm.getOption(&quot;disableInput&quot;)) return CodeMirror.Pass;
-        var ranges = cm.listSelections();
-        for (var i = 0; i &lt; ranges.length; i++) {
-          if (!ranges[i].empty()) return CodeMirror.Pass;
-          var around = charsAround(cm, ranges[i].head);
-          if (!around || pairs.indexOf(around) % 2 != 0) return CodeMirror.Pass;
-        }
-        for (var i = ranges.length - 1; i &gt;= 0; i--) {
-          var cur = ranges[i].head;
-          cm.replaceRange(&quot;&quot;, Pos(cur.line, cur.ch - 1), Pos(cur.line, cur.ch + 1));
-        }
-      }
-    };
-    var closingBrackets = &quot;&quot;;
-    for (var i = 0; i &lt; pairs.length; i += 2) (function(left, right) {
-      if (left != right) closingBrackets += right;
-      map[&quot;'&quot; + left + &quot;'&quot;] = function(cm) {
-        if (cm.getOption(&quot;disableInput&quot;)) return CodeMirror.Pass;
-        var ranges = cm.listSelections(), type, next;
-        for (var i = 0; i &lt; ranges.length; i++) {
-          var range = ranges[i], cur = range.head, curType;
-          if (left == &quot;'&quot; &amp;&amp; cm.getTokenTypeAt(cur) == &quot;comment&quot;)
-            return CodeMirror.Pass;
-          var next = cm.getRange(cur, Pos(cur.line, cur.ch + 1));
-          if (!range.empty())
-            curType = &quot;surround&quot;;
-          else if (left == right &amp;&amp; next == right) {
-            if (cm.getRange(cur, Pos(cur.line, cur.ch + 3)) == left + left + left)
-              curType = &quot;skipThree&quot;;
-            else
-              curType = &quot;skip&quot;;
-          } else if (left == right &amp;&amp; cur.ch &gt; 1 &amp;&amp;
-                     cm.getRange(Pos(cur.line, cur.ch - 2), cur) == left + left &amp;&amp;
-                     (cur.ch &lt;= 2 || cm.getRange(Pos(cur.line, cur.ch - 3), Pos(cur.line, cur.ch - 2)) != left))
-            curType = &quot;addFour&quot;;
-          else if (left == right &amp;&amp; CodeMirror.isWordChar(next))
-            return CodeMirror.Pass;
-          else if (cm.getLine(cur.line).length == cur.ch || closingBrackets.indexOf(next) &gt;= 0 || SPACE_CHAR_REGEX.test(next))
-            curType = &quot;both&quot;;
-          else
-            return CodeMirror.Pass;
-          if (!type) type = curType;
-          else if (type != curType) return CodeMirror.Pass;
-        }
</del><ins>+  var bind = defaults.pairs + &quot;`&quot;;
+  var keyMap = {Backspace: handleBackspace, Enter: handleEnter};
+  for (var i = 0; i &lt; bind.length; i++)
+    keyMap[&quot;'&quot; + bind.charAt(i) + &quot;'&quot;] = handler(bind.charAt(i));
</ins><span class="cx"> 
</span><del>-        cm.operation(function() {
-          if (type == &quot;skip&quot;) {
-            cm.execCommand(&quot;goCharRight&quot;);
-          } else if (type == &quot;skipThree&quot;) {
-            for (var i = 0; i &lt; 3; i++)
-              cm.execCommand(&quot;goCharRight&quot;);
-          } else if (type == &quot;surround&quot;) {
-            var sels = cm.getSelections();
-            for (var i = 0; i &lt; sels.length; i++)
-              sels[i] = left + sels[i] + right;
-            cm.replaceSelections(sels, &quot;around&quot;);
-          } else if (type == &quot;both&quot;) {
-            cm.replaceSelection(left + right, null);
-            cm.execCommand(&quot;goCharLeft&quot;);
-          } else if (type == &quot;addFour&quot;) {
-            cm.replaceSelection(left + left + left + left, &quot;before&quot;);
-            cm.execCommand(&quot;goCharRight&quot;);
-          }
-        });
-      };
-      if (left != right) map[&quot;'&quot; + right + &quot;'&quot;] = function(cm) {
-        var ranges = cm.listSelections();
-        for (var i = 0; i &lt; ranges.length; i++) {
-          var range = ranges[i];
-          if (!range.empty() ||
-              cm.getRange(range.head, Pos(range.head.line, range.head.ch + 1)) != right)
-            return CodeMirror.Pass;
-        }
-        cm.execCommand(&quot;goCharRight&quot;);
-      };
-    })(pairs.charAt(i), pairs.charAt(i + 1));
-    return map;
</del><ins>+  function handler(ch) {
+    return function(cm) { return handleChar(cm, ch); };
</ins><span class="cx">   }
</span><span class="cx"> 
</span><del>-  function buildExplodeHandler(pairs) {
-    return function(cm) {
-      if (cm.getOption(&quot;disableInput&quot;)) return CodeMirror.Pass;
-      var ranges = cm.listSelections();
</del><ins>+  function getConfig(cm) {
+    var deflt = cm.state.closeBrackets;
+    if (!deflt) return null;
+    var mode = cm.getModeAt(cm.getCursor());
+    return mode.closeBrackets || deflt;
+  }
+
+  function handleBackspace(cm) {
+    var conf = getConfig(cm);
+    if (!conf || cm.getOption(&quot;disableInput&quot;)) return CodeMirror.Pass;
+
+    var pairs = getOption(conf, &quot;pairs&quot;);
+    var ranges = cm.listSelections();
+    for (var i = 0; i &lt; ranges.length; i++) {
+      if (!ranges[i].empty()) return CodeMirror.Pass;
+      var around = charsAround(cm, ranges[i].head);
+      if (!around || pairs.indexOf(around) % 2 != 0) return CodeMirror.Pass;
+    }
+    for (var i = ranges.length - 1; i &gt;= 0; i--) {
+      var cur = ranges[i].head;
+      cm.replaceRange(&quot;&quot;, Pos(cur.line, cur.ch - 1), Pos(cur.line, cur.ch + 1));
+    }
+  }
+
+  function handleEnter(cm) {
+    var conf = getConfig(cm);
+    var explode = conf &amp;&amp; getOption(conf, &quot;explode&quot;);
+    if (!explode || cm.getOption(&quot;disableInput&quot;)) return CodeMirror.Pass;
+
+    var ranges = cm.listSelections();
+    for (var i = 0; i &lt; ranges.length; i++) {
+      if (!ranges[i].empty()) return CodeMirror.Pass;
+      var around = charsAround(cm, ranges[i].head);
+      if (!around || explode.indexOf(around) % 2 != 0) return CodeMirror.Pass;
+    }
+    cm.operation(function() {
+      cm.replaceSelection(&quot;\n\n&quot;, null);
+      cm.execCommand(&quot;goCharLeft&quot;);
+      ranges = cm.listSelections();
</ins><span class="cx">       for (var i = 0; i &lt; ranges.length; i++) {
</span><del>-        if (!ranges[i].empty()) return CodeMirror.Pass;
-        var around = charsAround(cm, ranges[i].head);
-        if (!around || pairs.indexOf(around) % 2 != 0) return CodeMirror.Pass;
</del><ins>+        var line = ranges[i].head.line;
+        cm.indentLine(line, null, true);
+        cm.indentLine(line + 1, null, true);
</ins><span class="cx">       }
</span><del>-      cm.operation(function() {
-        cm.replaceSelection(&quot;\n\n&quot;, null);
</del><ins>+    });
+  }
+
+  function handleChar(cm, ch) {
+    var conf = getConfig(cm);
+    if (!conf || cm.getOption(&quot;disableInput&quot;)) return CodeMirror.Pass;
+
+    var pairs = getOption(conf, &quot;pairs&quot;);
+    var pos = pairs.indexOf(ch);
+    if (pos == -1) return CodeMirror.Pass;
+    var triples = getOption(conf, &quot;triples&quot;);
+
+    var identical = pairs.charAt(pos + 1) == ch;
+    var ranges = cm.listSelections();
+    var opening = pos % 2 == 0;
+
+    var type, next;
+    for (var i = 0; i &lt; ranges.length; i++) {
+      var range = ranges[i], cur = range.head, curType;
+      var next = cm.getRange(cur, Pos(cur.line, cur.ch + 1));
+      if (opening &amp;&amp; !range.empty()) {
+        curType = &quot;surround&quot;;
+      } else if ((identical || !opening) &amp;&amp; next == ch) {
+        if (triples.indexOf(ch) &gt;= 0 &amp;&amp; cm.getRange(cur, Pos(cur.line, cur.ch + 3)) == ch + ch + ch)
+          curType = &quot;skipThree&quot;;
+        else
+          curType = &quot;skip&quot;;
+      } else if (identical &amp;&amp; cur.ch &gt; 1 &amp;&amp; triples.indexOf(ch) &gt;= 0 &amp;&amp;
+                 cm.getRange(Pos(cur.line, cur.ch - 2), cur) == ch + ch &amp;&amp;
+                 (cur.ch &lt;= 2 || cm.getRange(Pos(cur.line, cur.ch - 3), Pos(cur.line, cur.ch - 2)) != ch)) {
+        curType = &quot;addFour&quot;;
+      } else if (identical) {
+        if (!CodeMirror.isWordChar(next) &amp;&amp; enteringString(cm, cur, ch)) curType = &quot;both&quot;;
+        else return CodeMirror.Pass;
+      } else if (opening &amp;&amp; (cm.getLine(cur.line).length == cur.ch ||
+                             isClosingBracket(next, pairs) ||
+                             /\s/.test(next))) {
+        curType = &quot;both&quot;;
+      } else {
+        return CodeMirror.Pass;
+      }
+      if (!type) type = curType;
+      else if (type != curType) return CodeMirror.Pass;
+    }
+
+    var left = pos % 2 ? pairs.charAt(pos - 1) : ch;
+    var right = pos % 2 ? ch : pairs.charAt(pos + 1);
+    cm.operation(function() {
+      if (type == &quot;skip&quot;) {
+        cm.execCommand(&quot;goCharRight&quot;);
+      } else if (type == &quot;skipThree&quot;) {
+        for (var i = 0; i &lt; 3; i++)
+          cm.execCommand(&quot;goCharRight&quot;);
+      } else if (type == &quot;surround&quot;) {
+        var sels = cm.getSelections();
+        for (var i = 0; i &lt; sels.length; i++)
+          sels[i] = left + sels[i] + right;
+        cm.replaceSelections(sels, &quot;around&quot;);
+      } else if (type == &quot;both&quot;) {
+        cm.replaceSelection(left + right, null);
+        cm.triggerElectric(left + right);
</ins><span class="cx">         cm.execCommand(&quot;goCharLeft&quot;);
</span><del>-        ranges = cm.listSelections();
-        for (var i = 0; i &lt; ranges.length; i++) {
-          var line = ranges[i].head.line;
-          cm.indentLine(line, null, true);
-          cm.indentLine(line + 1, null, true);
-        }
-      });
-    };
</del><ins>+      } else if (type == &quot;addFour&quot;) {
+        cm.replaceSelection(left + left + left + left, &quot;before&quot;);
+        cm.execCommand(&quot;goCharRight&quot;);
+      }
+    });
</ins><span class="cx">   }
</span><ins>+
+  function isClosingBracket(ch, pairs) {
+    var pos = pairs.lastIndexOf(ch);
+    return pos &gt; -1 &amp;&amp; pos % 2 == 1;
+  }
+
+  function charsAround(cm, pos) {
+    var str = cm.getRange(Pos(pos.line, pos.ch - 1),
+                          Pos(pos.line, pos.ch + 1));
+    return str.length == 2 ? str : null;
+  }
+
+  // Project the token type that will exists after the given char is
+  // typed, and use it to determine whether it would cause the start
+  // of a string token.
+  function enteringString(cm, pos, ch) {
+    var line = cm.getLine(pos.line);
+    var token = cm.getTokenAt(pos);
+    if (/\bstring2?\b/.test(token.type)) return false;
+    var stream = new CodeMirror.StringStream(line.slice(0, pos.ch) + ch + line.slice(pos.ch), 4);
+    stream.pos = stream.start = token.start;
+    for (;;) {
+      var type1 = cm.getMode().token(stream, token.state);
+      if (stream.pos &gt;= pos.ch + 1) return /\bstring2?\b/.test(type1);
+      stream.start = stream.pos;
+    }
+  }
</ins><span class="cx"> });
</span><span class="cx">Property changes on: trunk/Source/WebInspectorUI/UserInterface/External/CodeMirror/closebrackets.js
</span><span class="cx">___________________________________________________________________
</span></span></pre></div>
<a id="svnexecutable"></a>
<div class="addfile"><h4>Added: svn:executable</h4></div>
<a id="trunkSourceWebInspectorUIUserInterfaceExternalCodeMirrorcodemirrorcss"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebInspectorUI/UserInterface/External/CodeMirror/codemirror.css (188324 => 188325)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebInspectorUI/UserInterface/External/CodeMirror/codemirror.css        2015-08-12 04:58:37 UTC (rev 188324)
+++ trunk/Source/WebInspectorUI/UserInterface/External/CodeMirror/codemirror.css        2015-08-12 05:40:27 UTC (rev 188325)
</span><span class="lines">@@ -4,11 +4,8 @@
</span><span class="cx">   /* Set height, width, borders, and global font properties here */
</span><span class="cx">   font-family: monospace;
</span><span class="cx">   height: 300px;
</span><ins>+  color: black;
</ins><span class="cx"> }
</span><del>-.CodeMirror-scroll {
-  /* Set scrolling behaviour here */
-  overflow: auto;
-}
</del><span class="cx"> 
</span><span class="cx"> /* PADDING */
</span><span class="cx"> 
</span><span class="lines">@@ -36,28 +33,60 @@
</span><span class="cx">   min-width: 20px;
</span><span class="cx">   text-align: right;
</span><span class="cx">   color: #999;
</span><del>-  -moz-box-sizing: content-box;
-  box-sizing: content-box;
</del><ins>+  white-space: nowrap;
</ins><span class="cx"> }
</span><span class="cx"> 
</span><ins>+.CodeMirror-guttermarker { color: black; }
+.CodeMirror-guttermarker-subtle { color: #999; }
+
</ins><span class="cx"> /* CURSOR */
</span><span class="cx"> 
</span><del>-.CodeMirror div.CodeMirror-cursor {
</del><ins>+.CodeMirror-cursor {
</ins><span class="cx">   border-left: 1px solid black;
</span><ins>+  border-right: none;
+  width: 0;
</ins><span class="cx"> }
</span><span class="cx"> /* Shown when moving in bi-directional text */
</span><span class="cx"> .CodeMirror div.CodeMirror-secondarycursor {
</span><span class="cx">   border-left: 1px solid silver;
</span><span class="cx"> }
</span><del>-.CodeMirror.cm-keymap-fat-cursor div.CodeMirror-cursor {
</del><ins>+.cm-fat-cursor .CodeMirror-cursor {
</ins><span class="cx">   width: auto;
</span><span class="cx">   border: 0;
</span><span class="cx">   background: #7e7;
</span><span class="cx"> }
</span><ins>+.cm-fat-cursor div.CodeMirror-cursors {
+  z-index: 1;
+}
+
+.cm-animate-fat-cursor {
+  width: auto;
+  border: 0;
+  -webkit-animation: blink 1.06s steps(1) infinite;
+  -moz-animation: blink 1.06s steps(1) infinite;
+  animation: blink 1.06s steps(1) infinite;
+  background-color: #7e7;
+}
+@-moz-keyframes blink {
+  0% {}
+  50% { background-color: transparent; }
+  100% {}
+}
+@-webkit-keyframes blink {
+  0% {}
+  50% { background-color: transparent; }
+  100% {}
+}
+@keyframes blink {
+  0% {}
+  50% { background-color: transparent; }
+  100% {}
+}
+
</ins><span class="cx"> /* Can style cursor different in overwrite (non-insert) mode */
</span><del>-div.CodeMirror-overwrite div.CodeMirror-cursor {}
</del><ins>+.CodeMirror-overwrite .CodeMirror-cursor {}
</ins><span class="cx"> 
</span><del>-.cm-tab { display: inline-block; }
</del><ins>+.cm-tab { display: inline-block; text-decoration: inherit; }
</ins><span class="cx"> 
</span><span class="cx"> .CodeMirror-ruler {
</span><span class="cx">   border-left: 1px solid #ccc;
</span><span class="lines">@@ -66,6 +95,15 @@
</span><span class="cx"> 
</span><span class="cx"> /* DEFAULT THEME */
</span><span class="cx"> 
</span><ins>+.cm-s-default .cm-header {color: blue;}
+.cm-s-default .cm-quote {color: #090;}
+.cm-negative {color: #d44;}
+.cm-positive {color: #292;}
+.cm-header, .cm-strong {font-weight: bold;}
+.cm-em {font-style: italic;}
+.cm-link {text-decoration: underline;}
+.cm-strikethrough {text-decoration: line-through;}
+
</ins><span class="cx"> .cm-s-default .cm-keyword {color: #708;}
</span><span class="cx"> .cm-s-default .cm-atom {color: #219;}
</span><span class="cx"> .cm-s-default .cm-number {color: #164;}
</span><span class="lines">@@ -85,22 +123,19 @@
</span><span class="cx"> .cm-s-default .cm-bracket {color: #997;}
</span><span class="cx"> .cm-s-default .cm-tag {color: #170;}
</span><span class="cx"> .cm-s-default .cm-attribute {color: #00c;}
</span><del>-.cm-s-default .cm-header {color: blue;}
-.cm-s-default .cm-quote {color: #090;}
</del><span class="cx"> .cm-s-default .cm-hr {color: #999;}
</span><span class="cx"> .cm-s-default .cm-link {color: #00c;}
</span><span class="cx"> 
</span><del>-.cm-negative {color: #d44;}
-.cm-positive {color: #292;}
-.cm-header, .cm-strong {font-weight: bold;}
-.cm-em {font-style: italic;}
-.cm-link {text-decoration: underline;}
-
</del><span class="cx"> .cm-s-default .cm-error {color: #f00;}
</span><span class="cx"> .cm-invalidchar {color: #f00;}
</span><span class="cx"> 
</span><ins>+.CodeMirror-composing { border-bottom: 2px solid; }
+
+/* Default styles for common addons */
+
</ins><span class="cx"> div.CodeMirror span.CodeMirror-matchingbracket {color: #0f0;}
</span><span class="cx"> div.CodeMirror span.CodeMirror-nonmatchingbracket {color: #f22;}
</span><ins>+.CodeMirror-matchingtag { background: rgba(255, 150, 0, .3); }
</ins><span class="cx"> .CodeMirror-activeline-background {background: #e8f2ff;}
</span><span class="cx"> 
</span><span class="cx"> /* STOP */
</span><span class="lines">@@ -109,14 +144,13 @@
</span><span class="cx">    the editor. You probably shouldn't touch them. */
</span><span class="cx"> 
</span><span class="cx"> .CodeMirror {
</span><del>-  line-height: 1;
</del><span class="cx">   position: relative;
</span><span class="cx">   overflow: hidden;
</span><span class="cx">   background: white;
</span><del>-  color: black;
</del><span class="cx"> }
</span><span class="cx"> 
</span><span class="cx"> .CodeMirror-scroll {
</span><ins>+  overflow: scroll !important; /* Things will break if this is overridden */
</ins><span class="cx">   /* 30px is the magic margin used to hide the element's real scrollbars */
</span><span class="cx">   /* See overflow: hidden in .CodeMirror */
</span><span class="cx">   margin-bottom: -30px; margin-right: -30px;
</span><span class="lines">@@ -124,14 +158,10 @@
</span><span class="cx">   height: 100%;
</span><span class="cx">   outline: none; /* Prevent dragging from highlighting the element */
</span><span class="cx">   position: relative;
</span><del>-  -moz-box-sizing: content-box;
-  box-sizing: content-box;
</del><span class="cx"> }
</span><span class="cx"> .CodeMirror-sizer {
</span><span class="cx">   position: relative;
</span><span class="cx">   border-right: 30px solid transparent;
</span><del>-  -moz-box-sizing: content-box;
-  box-sizing: content-box;
</del><span class="cx"> }
</span><span class="cx"> 
</span><span class="cx"> /* The fake, visible scrollbars. Used to force redraw during scrolling
</span><span class="lines">@@ -161,29 +191,42 @@
</span><span class="cx"> 
</span><span class="cx"> .CodeMirror-gutters {
</span><span class="cx">   position: absolute; left: 0; top: 0;
</span><del>-  padding-bottom: 30px;
</del><span class="cx">   z-index: 3;
</span><span class="cx"> }
</span><span class="cx"> .CodeMirror-gutter {
</span><span class="cx">   white-space: normal;
</span><span class="cx">   height: 100%;
</span><del>-  -moz-box-sizing: content-box;
-  box-sizing: content-box;
-  padding-bottom: 30px;
-  margin-bottom: -32px;
</del><span class="cx">   display: inline-block;
</span><ins>+  margin-bottom: -30px;
</ins><span class="cx">   /* Hack to make IE7 behave */
</span><span class="cx">   *zoom:1;
</span><span class="cx">   *display:inline;
</span><span class="cx"> }
</span><ins>+.CodeMirror-gutter-wrapper {
+  position: absolute;
+  z-index: 4;
+  background: none !important;
+  border: none !important;
+}
+.CodeMirror-gutter-background {
+  position: absolute;
+  top: 0; bottom: 0;
+  z-index: 4;
+}
</ins><span class="cx"> .CodeMirror-gutter-elt {
</span><span class="cx">   position: absolute;
</span><span class="cx">   cursor: default;
</span><span class="cx">   z-index: 4;
</span><span class="cx"> }
</span><ins>+.CodeMirror-gutter-wrapper {
+  -webkit-user-select: none;
+  -moz-user-select: none;
+  user-select: none;
+}
</ins><span class="cx"> 
</span><span class="cx"> .CodeMirror-lines {
</span><span class="cx">   cursor: text;
</span><ins>+  min-height: 1px; /* prevents collapsing before first draw */
</ins><span class="cx"> }
</span><span class="cx"> .CodeMirror pre {
</span><span class="cx">   /* Reset some styles that the rest of the page might have set */
</span><span class="lines">@@ -200,6 +243,7 @@
</span><span class="cx">   z-index: 2;
</span><span class="cx">   position: relative;
</span><span class="cx">   overflow: visible;
</span><ins>+  -webkit-tap-highlight-color: transparent;
</ins><span class="cx"> }
</span><span class="cx"> .CodeMirror-wrap pre {
</span><span class="cx">   word-wrap: break-word;
</span><span class="lines">@@ -221,10 +265,20 @@
</span><span class="cx"> 
</span><span class="cx"> .CodeMirror-widget {}
</span><span class="cx"> 
</span><del>-.CodeMirror-wrap .CodeMirror-scroll {
-  overflow-x: hidden;
</del><ins>+.CodeMirror-code {
+  outline: none;
</ins><span class="cx"> }
</span><span class="cx"> 
</span><ins>+/* Force content-box sizing for the elements where we expect it */
+.CodeMirror-scroll,
+.CodeMirror-sizer,
+.CodeMirror-gutter,
+.CodeMirror-gutters,
+.CodeMirror-linenumber {
+  -moz-box-sizing: content-box;
+  box-sizing: content-box;
+}
+
</ins><span class="cx"> .CodeMirror-measure {
</span><span class="cx">   position: absolute;
</span><span class="cx">   width: 100%;
</span><span class="lines">@@ -232,19 +286,19 @@
</span><span class="cx">   overflow: hidden;
</span><span class="cx">   visibility: hidden;
</span><span class="cx"> }
</span><ins>+
+.CodeMirror-cursor { position: absolute; }
</ins><span class="cx"> .CodeMirror-measure pre { position: static; }
</span><span class="cx"> 
</span><del>-.CodeMirror div.CodeMirror-cursor {
-  position: absolute;
-  border-right: none;
-  width: 0;
-}
-
</del><span class="cx"> div.CodeMirror-cursors {
</span><span class="cx">   visibility: hidden;
</span><span class="cx">   position: relative;
</span><del>-  z-index: 1;
</del><ins>+  z-index: 3;
</ins><span class="cx"> }
</span><ins>+div.CodeMirror-dragcursors {
+  visibility: visible;
+}
+
</ins><span class="cx"> .CodeMirror-focused div.CodeMirror-cursors {
</span><span class="cx">   visibility: visible;
</span><span class="cx"> }
</span><span class="lines">@@ -252,6 +306,8 @@
</span><span class="cx"> .CodeMirror-selected { background: #d9d9d9; }
</span><span class="cx"> .CodeMirror-focused .CodeMirror-selected { background: #d7d4f0; }
</span><span class="cx"> .CodeMirror-crosshair { cursor: crosshair; }
</span><ins>+.CodeMirror-line::selection, .CodeMirror-line &gt; span::selection, .CodeMirror-line &gt; span &gt; span::selection { background: #d7d4f0; }
+.CodeMirror-line::-moz-selection, .CodeMirror-line &gt; span::-moz-selection, .CodeMirror-line &gt; span &gt; span::-moz-selection { background: #d7d4f0; }
</ins><span class="cx"> 
</span><span class="cx"> .cm-searching {
</span><span class="cx">   background: #ffa;
</span><span class="lines">@@ -270,3 +326,9 @@
</span><span class="cx">     visibility: hidden;
</span><span class="cx">   }
</span><span class="cx"> }
</span><ins>+
+/* See issue #2901 */
+.cm-tab-wrap-hack:after { content: ''; }
+
+/* Help users use markselection to safely style text background */
+span.CodeMirror-selectedtext { background: none; }
</ins><span class="cx">Property changes on: trunk/Source/WebInspectorUI/UserInterface/External/CodeMirror/codemirror.css
</span><span class="cx">___________________________________________________________________
</span></span></pre></div>
<a id="svnexecutable"></a>
<div class="addfile"><h4>Added: svn:executable</h4></div>
<a id="trunkSourceWebInspectorUIUserInterfaceExternalCodeMirrorcodemirrorjs"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebInspectorUI/UserInterface/External/CodeMirror/codemirror.js (188324 => 188325)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebInspectorUI/UserInterface/External/CodeMirror/codemirror.js        2015-08-12 04:58:37 UTC (rev 188324)
+++ trunk/Source/WebInspectorUI/UserInterface/External/CodeMirror/codemirror.js        2015-08-12 05:40:27 UTC (rev 188325)
</span><span class="lines">@@ -23,19 +23,15 @@
</span><span class="cx">   // detected are enabled based on userAgent etc sniffing.
</span><span class="cx"> 
</span><span class="cx">   var gecko = /gecko\/\d/i.test(navigator.userAgent);
</span><del>-  // ie_uptoN means Internet Explorer version N or lower
</del><span class="cx">   var ie_upto10 = /MSIE \d/.test(navigator.userAgent);
</span><del>-  var ie_upto7 = ie_upto10 &amp;&amp; (document.documentMode == null || document.documentMode &lt; 8);
-  var ie_upto8 = ie_upto10 &amp;&amp; (document.documentMode == null || document.documentMode &lt; 9);
-  var ie_upto9 = ie_upto10 &amp;&amp; (document.documentMode == null || document.documentMode &lt; 10);
-  var ie_11up = /Trident\/([7-9]|\d{2,})\./.test(navigator.userAgent);
</del><ins>+  var ie_11up = /Trident\/(?:[7-9]|\d{2,})\..*rv:(\d+)/.exec(navigator.userAgent);
</ins><span class="cx">   var ie = ie_upto10 || ie_11up;
</span><ins>+  var ie_version = ie &amp;&amp; (ie_upto10 ? document.documentMode || 6 : ie_11up[1]);
</ins><span class="cx">   var webkit = /WebKit\//.test(navigator.userAgent);
</span><span class="cx">   var qtwebkit = webkit &amp;&amp; /Qt\/\d+\.\d+/.test(navigator.userAgent);
</span><span class="cx">   var chrome = /Chrome\//.test(navigator.userAgent);
</span><span class="cx">   var presto = /Opera\//.test(navigator.userAgent);
</span><span class="cx">   var safari = /Apple Computer/.test(navigator.vendor);
</span><del>-  var khtml = /KHTML\//.test(navigator.userAgent);
</del><span class="cx">   var mac_geMountainLion = /Mac OS X 1\d\D([8-9]|\d\d)\D/.test(navigator.userAgent);
</span><span class="cx">   var phantom = /PhantomJS/.test(navigator.userAgent);
</span><span class="cx"> 
</span><span class="lines">@@ -50,7 +46,7 @@
</span><span class="cx">   if (presto_version &amp;&amp; presto_version &gt;= 15) { presto = false; webkit = true; }
</span><span class="cx">   // Some browsers use the wrong event properties to signal cmd/ctrl on OS X
</span><span class="cx">   var flipCtrlCmd = mac &amp;&amp; (qtwebkit || presto &amp;&amp; (presto_version == null || presto_version &lt; 12.11));
</span><del>-  var captureRightClick = gecko || (ie &amp;&amp; !ie_upto8);
</del><ins>+  var captureRightClick = gecko || (ie &amp;&amp; ie_version &gt;= 9);
</ins><span class="cx"> 
</span><span class="cx">   // Optimize some code when these features are not used.
</span><span class="cx">   var sawReadOnlySpans = false, sawCollapsedSpans = false;
</span><span class="lines">@@ -63,55 +59,70 @@
</span><span class="cx">   function CodeMirror(place, options) {
</span><span class="cx">     if (!(this instanceof CodeMirror)) return new CodeMirror(place, options);
</span><span class="cx"> 
</span><del>-    this.options = options = options || {};
</del><ins>+    this.options = options = options ? copyObj(options) : {};
</ins><span class="cx">     // Determine effective options based on given values and defaults.
</span><span class="cx">     copyObj(defaults, options, false);
</span><span class="cx">     setGuttersForLineNumbers(options);
</span><span class="cx"> 
</span><span class="cx">     var doc = options.value;
</span><del>-    if (typeof doc == &quot;string&quot;) doc = new Doc(doc, options.mode);
</del><ins>+    if (typeof doc == &quot;string&quot;) doc = new Doc(doc, options.mode, null, options.lineSeparator);
</ins><span class="cx">     this.doc = doc;
</span><span class="cx"> 
</span><del>-    var display = this.display = new Display(place, doc);
</del><ins>+    var input = new CodeMirror.inputStyles[options.inputStyle](this);
+    var display = this.display = new Display(place, doc, input);
</ins><span class="cx">     display.wrapper.CodeMirror = this;
</span><span class="cx">     updateGutters(this);
</span><span class="cx">     themeChanged(this);
</span><span class="cx">     if (options.lineWrapping)
</span><span class="cx">       this.display.wrapper.className += &quot; CodeMirror-wrap&quot;;
</span><del>-    if (options.autofocus &amp;&amp; !mobile) focusInput(this);
</del><ins>+    if (options.autofocus &amp;&amp; !mobile) display.input.focus();
+    initScrollbars(this);
</ins><span class="cx"> 
</span><span class="cx">     this.state = {
</span><span class="cx">       keyMaps: [],  // stores maps added by addKeyMap
</span><span class="cx">       overlays: [], // highlighting overlays, as added by addOverlay
</span><span class="cx">       modeGen: 0,   // bumped when mode/overlay changes, used to invalidate highlighting info
</span><del>-      overwrite: false, focused: false,
</del><ins>+      overwrite: false,
+      delayingBlurEvent: false,
+      focused: false,
</ins><span class="cx">       suppressEdits: false, // used to disable editing during key handlers when in readOnly mode
</span><del>-      pasteIncoming: false, cutIncoming: false, // help recognize paste/cut edits in readInput
</del><ins>+      pasteIncoming: false, cutIncoming: false, // help recognize paste/cut edits in input.poll
+      selectingText: false,
</ins><span class="cx">       draggingText: false,
</span><del>-      highlight: new Delayed() // stores highlight worker timeout
</del><ins>+      highlight: new Delayed(), // stores highlight worker timeout
+      keySeq: null,  // Unfinished key sequence
+      specialChars: null
</ins><span class="cx">     };
</span><span class="cx"> 
</span><ins>+    var cm = this;
+
</ins><span class="cx">     // Override magic textarea content restore that IE sometimes does
</span><span class="cx">     // on our hidden textarea on reload
</span><del>-    if (ie_upto10) setTimeout(bind(resetInput, this, true), 20);
</del><ins>+    if (ie &amp;&amp; ie_version &lt; 11) setTimeout(function() { cm.display.input.reset(true); }, 20);
</ins><span class="cx"> 
</span><span class="cx">     registerEventHandlers(this);
</span><span class="cx">     ensureGlobalHandlers();
</span><span class="cx"> 
</span><del>-    var cm = this;
-    runInOp(this, function() {
-      cm.curOp.forceUpdate = true;
-      attachDoc(cm, doc);
</del><ins>+    startOperation(this);
+    this.curOp.forceUpdate = true;
+    attachDoc(this, doc);
</ins><span class="cx"> 
</span><del>-      if ((options.autofocus &amp;&amp; !mobile) || activeElt() == display.input)
-        setTimeout(bind(onFocus, cm), 20);
-      else
-        onBlur(cm);
</del><ins>+    if ((options.autofocus &amp;&amp; !mobile) || cm.hasFocus())
+      setTimeout(bind(onFocus, this), 20);
+    else
+      onBlur(this);
</ins><span class="cx"> 
</span><del>-      for (var opt in optionHandlers) if (optionHandlers.hasOwnProperty(opt))
-        optionHandlers[opt](cm, options[opt], Init);
-      for (var i = 0; i &lt; initHooks.length; ++i) initHooks[i](cm);
-    });
</del><ins>+    for (var opt in optionHandlers) if (optionHandlers.hasOwnProperty(opt))
+      optionHandlers[opt](this, options[opt], Init);
+    maybeUpdateLineNumberWidth(this);
+    if (options.finishInit) options.finishInit(this);
+    for (var i = 0; i &lt; initHooks.length; ++i) initHooks[i](this);
+    endOperation(this);
+    // Suppress optimizelegibility in Webkit, since it breaks text
+    // measuring on line wrapping boundaries.
+    if (webkit &amp;&amp; options.lineWrapping &amp;&amp;
+        getComputedStyle(display.lineDiv).textRendering == &quot;optimizelegibility&quot;)
+      display.lineDiv.style.textRendering = &quot;auto&quot;;
</ins><span class="cx">   }
</span><span class="cx"> 
</span><span class="cx">   // DISPLAY CONSTRUCTOR
</span><span class="lines">@@ -120,32 +131,17 @@
</span><span class="cx">   // and content drawing. It holds references to DOM nodes and
</span><span class="cx">   // display-related state.
</span><span class="cx"> 
</span><del>-  function Display(place, doc) {
</del><ins>+  function Display(place, doc, input) {
</ins><span class="cx">     var d = this;
</span><ins>+    this.input = input;
</ins><span class="cx"> 
</span><del>-    // The semihidden textarea that is focused when the editor is
-    // focused, and receives input.
-    var input = d.input = elt(&quot;textarea&quot;, null, null, &quot;position: absolute; padding: 0; width: 1px; height: 1em; outline: none&quot;);
-    // The textarea is kept positioned near the cursor to prevent the
-    // fact that it'll be scrolled into view on input from scrolling
-    // our fake cursor out of view. On webkit, when wrap=off, paste is
-    // very slow. So make the area wide instead.
-    if (webkit) input.style.width = &quot;1000px&quot;;
-    else input.setAttribute(&quot;wrap&quot;, &quot;off&quot;);
-    // If border: 0; -- iOS fails to open keyboard (issue #1287)
-    if (ios) input.style.border = &quot;1px solid black&quot;;
-    input.setAttribute(&quot;autocorrect&quot;, &quot;off&quot;); input.setAttribute(&quot;autocapitalize&quot;, &quot;off&quot;); input.setAttribute(&quot;spellcheck&quot;, &quot;false&quot;);
-
-    // Wraps and hides input textarea
-    d.inputDiv = elt(&quot;div&quot;, [input], null, &quot;overflow: hidden; position: relative; width: 3px; height: 0px;&quot;);
-    // The fake scrollbar elements.
-    d.scrollbarH = elt(&quot;div&quot;, [elt(&quot;div&quot;, null, null, &quot;height: 100%; min-height: 1px&quot;)], &quot;CodeMirror-hscrollbar&quot;);
-    d.scrollbarV = elt(&quot;div&quot;, [elt(&quot;div&quot;, null, null, &quot;min-width: 1px&quot;)], &quot;CodeMirror-vscrollbar&quot;);
</del><span class="cx">     // Covers bottom-right square when both scrollbars are present.
</span><span class="cx">     d.scrollbarFiller = elt(&quot;div&quot;, null, &quot;CodeMirror-scrollbar-filler&quot;);
</span><ins>+    d.scrollbarFiller.setAttribute(&quot;cm-not-content&quot;, &quot;true&quot;);
</ins><span class="cx">     // Covers bottom of gutter when coverGutterNextToScrollbar is on
</span><span class="cx">     // and h scrollbar is present.
</span><span class="cx">     d.gutterFiller = elt(&quot;div&quot;, null, &quot;CodeMirror-gutter-filler&quot;);
</span><ins>+    d.gutterFiller.setAttribute(&quot;cm-not-content&quot;, &quot;true&quot;);
</ins><span class="cx">     // Will contain the actual code, positioned to cover the viewport.
</span><span class="cx">     d.lineDiv = elt(&quot;div&quot;, null, &quot;CodeMirror-code&quot;);
</span><span class="cx">     // Elements are added to these to represent selection and cursors.
</span><span class="lines">@@ -162,10 +158,11 @@
</span><span class="cx">     d.mover = elt(&quot;div&quot;, [elt(&quot;div&quot;, [d.lineSpace], &quot;CodeMirror-lines&quot;)], null, &quot;position: relative&quot;);
</span><span class="cx">     // Set to the height of the document, allowing scrolling.
</span><span class="cx">     d.sizer = elt(&quot;div&quot;, [d.mover], &quot;CodeMirror-sizer&quot;);
</span><ins>+    d.sizerWidth = null;
</ins><span class="cx">     // Behavior of elts with overflow: auto and padding is
</span><span class="cx">     // inconsistent across browsers. This is used to ensure the
</span><span class="cx">     // scrollable area is big enough.
</span><del>-    d.heightForcer = elt(&quot;div&quot;, null, null, &quot;position: absolute; height: &quot; + scrollerCutOff + &quot;px; width: 1px;&quot;);
</del><ins>+    d.heightForcer = elt(&quot;div&quot;, null, null, &quot;position: absolute; height: &quot; + scrollerGap + &quot;px; width: 1px;&quot;);
</ins><span class="cx">     // Will contain the gutters, if any.
</span><span class="cx">     d.gutters = elt(&quot;div&quot;, null, &quot;CodeMirror-gutters&quot;);
</span><span class="cx">     d.lineGutter = null;
</span><span class="lines">@@ -173,56 +170,44 @@
</span><span class="cx">     d.scroller = elt(&quot;div&quot;, [d.sizer, d.heightForcer, d.gutters], &quot;CodeMirror-scroll&quot;);
</span><span class="cx">     d.scroller.setAttribute(&quot;tabIndex&quot;, &quot;-1&quot;);
</span><span class="cx">     // The element in which the editor lives.
</span><del>-    d.wrapper = elt(&quot;div&quot;, [d.inputDiv, d.scrollbarH, d.scrollbarV,
-                            d.scrollbarFiller, d.gutterFiller, d.scroller], &quot;CodeMirror&quot;);
</del><ins>+    d.wrapper = elt(&quot;div&quot;, [d.scrollbarFiller, d.gutterFiller, d.scroller], &quot;CodeMirror&quot;);
</ins><span class="cx"> 
</span><span class="cx">     // Work around IE7 z-index bug (not perfect, hence IE7 not really being supported)
</span><del>-    if (ie_upto7) { d.gutters.style.zIndex = -1; d.scroller.style.paddingRight = 0; }
-    // Needed to hide big blue blinking cursor on Mobile Safari
-    if (ios) input.style.width = &quot;0px&quot;;
-    if (!webkit) d.scroller.draggable = true;
-    // Needed to handle Tab key in KHTML
-    if (khtml) { d.inputDiv.style.height = &quot;1px&quot;; d.inputDiv.style.position = &quot;absolute&quot;; }
-    // Need to set a minimum width to see the scrollbar on IE7 (but must not set it on IE8).
-    if (ie_upto7) d.scrollbarH.style.minHeight = d.scrollbarV.style.minWidth = &quot;18px&quot;;
</del><ins>+    if (ie &amp;&amp; ie_version &lt; 8) { d.gutters.style.zIndex = -1; d.scroller.style.paddingRight = 0; }
+    if (!webkit &amp;&amp; !(gecko &amp;&amp; mobile)) d.scroller.draggable = true;
</ins><span class="cx"> 
</span><del>-    if (place.appendChild) place.appendChild(d.wrapper);
-    else place(d.wrapper);
</del><ins>+    if (place) {
+      if (place.appendChild) place.appendChild(d.wrapper);
+      else place(d.wrapper);
+    }
</ins><span class="cx"> 
</span><span class="cx">     // Current rendered range (may be bigger than the view window).
</span><span class="cx">     d.viewFrom = d.viewTo = doc.first;
</span><ins>+    d.reportedViewFrom = d.reportedViewTo = doc.first;
</ins><span class="cx">     // Information about the rendered lines.
</span><span class="cx">     d.view = [];
</span><ins>+    d.renderedView = null;
</ins><span class="cx">     // Holds info about a single rendered line when it was rendered
</span><span class="cx">     // for measurement, while not in view.
</span><span class="cx">     d.externalMeasured = null;
</span><span class="cx">     // Empty space (in pixels) above the view
</span><span class="cx">     d.viewOffset = 0;
</span><del>-    d.lastSizeC = 0;
</del><ins>+    d.lastWrapHeight = d.lastWrapWidth = 0;
</ins><span class="cx">     d.updateLineNumbers = null;
</span><span class="cx"> 
</span><ins>+    d.nativeBarWidth = d.barHeight = d.barWidth = 0;
+    d.scrollbarsClipped = false;
+
</ins><span class="cx">     // Used to only resize the line number gutter when necessary (when
</span><span class="cx">     // the amount of lines crosses a boundary that makes its width change)
</span><span class="cx">     d.lineNumWidth = d.lineNumInnerWidth = d.lineNumChars = null;
</span><del>-    // See readInput and resetInput
-    d.prevInput = &quot;&quot;;
</del><span class="cx">     // Set to true when a non-horizontal-scrolling line widget is
</span><span class="cx">     // added. As an optimization, line widget aligning is skipped when
</span><span class="cx">     // this is false.
</span><span class="cx">     d.alignWidgets = false;
</span><del>-    // Flag that indicates whether we expect input to appear real soon
-    // now (after some event like 'keypress' or 'input') and are
-    // polling intensively.
-    d.pollingFast = false;
-    // Self-resetting timeout for the poller
-    d.poll = new Delayed();
</del><span class="cx"> 
</span><span class="cx">     d.cachedCharWidth = d.cachedTextHeight = d.cachedPaddingH = null;
</span><span class="cx"> 
</span><del>-    // Tracks when resetInput has punted to just putting a short
-    // string into the textarea instead of the full selection.
-    d.inaccurateSelection = false;
-
</del><span class="cx">     // Tracks the maximum line length so that the horizontal scrollbar
</span><span class="cx">     // can be kept static when scrolling.
</span><span class="cx">     d.maxLine = null;
</span><span class="lines">@@ -238,6 +223,10 @@
</span><span class="cx">     // Used to track whether anything happened since the context menu
</span><span class="cx">     // was opened.
</span><span class="cx">     d.selForContextMenu = null;
</span><ins>+
+    d.activeTouch = null;
+
+    input.init(d);
</ins><span class="cx">   }
</span><span class="cx"> 
</span><span class="cx">   // STATE UPDATES
</span><span class="lines">@@ -264,6 +253,7 @@
</span><span class="cx">     if (cm.options.lineWrapping) {
</span><span class="cx">       addClass(cm.display.wrapper, &quot;CodeMirror-wrap&quot;);
</span><span class="cx">       cm.display.sizer.style.minWidth = &quot;&quot;;
</span><ins>+      cm.display.sizerWidth = null;
</ins><span class="cx">     } else {
</span><span class="cx">       rmClass(cm.display.wrapper, &quot;CodeMirror-wrap&quot;);
</span><span class="cx">       findMaxLine(cm);
</span><span class="lines">@@ -303,12 +293,6 @@
</span><span class="cx">     });
</span><span class="cx">   }
</span><span class="cx"> 
</span><del>-  function keyMapChanged(cm) {
-    var map = keyMap[cm.options.keyMap], style = map.style;
-    cm.display.wrapper.className = cm.display.wrapper.className.replace(/\s*cm-keymap-\S+/g, &quot;&quot;) +
-      (style ? &quot; cm-keymap-&quot; + style : &quot;&quot;);
-  }
-
</del><span class="cx">   function themeChanged(cm) {
</span><span class="cx">     cm.display.wrapper.className = cm.display.wrapper.className.replace(/\s*cm-s-\S+/g, &quot;&quot;) +
</span><span class="cx">       cm.options.theme.replace(/(^|\s)\s*/g, &quot; cm-s-&quot;);
</span><span class="lines">@@ -341,7 +325,6 @@
</span><span class="cx">   function updateGutterSpace(cm) {
</span><span class="cx">     var width = cm.display.gutters.offsetWidth;
</span><span class="cx">     cm.display.sizer.style.marginLeft = width + &quot;px&quot;;
</span><del>-    cm.display.scrollbarH.style.left = cm.options.fixedGutter ? width + &quot;px&quot; : 0;
</del><span class="cx">   }
</span><span class="cx"> 
</span><span class="cx">   // Compute the character length of a line, taking into account
</span><span class="lines">@@ -397,87 +380,186 @@
</span><span class="cx">   // Prepare DOM reads needed to update the scrollbars. Done in one
</span><span class="cx">   // shot to minimize update/measure roundtrips.
</span><span class="cx">   function measureForScrollbars(cm) {
</span><del>-    var scroll = cm.display.scroller;
</del><ins>+    var d = cm.display, gutterW = d.gutters.offsetWidth;
+    var docH = Math.round(cm.doc.height + paddingVert(cm.display));
</ins><span class="cx">     return {
</span><del>-      clientHeight: scroll.clientHeight,
-      barHeight: cm.display.scrollbarV.clientHeight,
-      scrollWidth: scroll.scrollWidth, clientWidth: scroll.clientWidth,
-      barWidth: cm.display.scrollbarH.clientWidth,
-      docHeight: Math.round(cm.doc.height + paddingVert(cm.display))
</del><ins>+      clientHeight: d.scroller.clientHeight,
+      viewHeight: d.wrapper.clientHeight,
+      scrollWidth: d.scroller.scrollWidth, clientWidth: d.scroller.clientWidth,
+      viewWidth: d.wrapper.clientWidth,
+      barLeft: cm.options.fixedGutter ? gutterW : 0,
+      docHeight: docH,
+      scrollHeight: docH + scrollGap(cm) + d.barHeight,
+      nativeBarWidth: d.nativeBarWidth,
+      gutterWidth: gutterW
</ins><span class="cx">     };
</span><span class="cx">   }
</span><span class="cx"> 
</span><ins>+  function NativeScrollbars(place, scroll, cm) {
+    this.cm = cm;
+    var vert = this.vert = elt(&quot;div&quot;, [elt(&quot;div&quot;, null, null, &quot;min-width: 1px&quot;)], &quot;CodeMirror-vscrollbar&quot;);
+    var horiz = this.horiz = elt(&quot;div&quot;, [elt(&quot;div&quot;, null, null, &quot;height: 100%; min-height: 1px&quot;)], &quot;CodeMirror-hscrollbar&quot;);
+    place(vert); place(horiz);
+
+    on(vert, &quot;scroll&quot;, function() {
+      if (vert.clientHeight) scroll(vert.scrollTop, &quot;vertical&quot;);
+    });
+    on(horiz, &quot;scroll&quot;, function() {
+      if (horiz.clientWidth) scroll(horiz.scrollLeft, &quot;horizontal&quot;);
+    });
+
+    this.checkedOverlay = false;
+    // Need to set a minimum width to see the scrollbar on IE7 (but must not set it on IE8).
+    if (ie &amp;&amp; ie_version &lt; 8) this.horiz.style.minHeight = this.vert.style.minWidth = &quot;18px&quot;;
+  }
+
+  NativeScrollbars.prototype = copyObj({
+    update: function(measure) {
+      var needsH = measure.scrollWidth &gt; measure.clientWidth + 1;
+      var needsV = measure.scrollHeight &gt; measure.clientHeight + 1;
+      var sWidth = measure.nativeBarWidth;
+
+      if (needsV) {
+        this.vert.style.display = &quot;block&quot;;
+        this.vert.style.bottom = needsH ? sWidth + &quot;px&quot; : &quot;0&quot;;
+        var totalHeight = measure.viewHeight - (needsH ? sWidth : 0);
+        // A bug in IE8 can cause this value to be negative, so guard it.
+        this.vert.firstChild.style.height =
+          Math.max(0, measure.scrollHeight - measure.clientHeight + totalHeight) + &quot;px&quot;;
+      } else {
+        this.vert.style.display = &quot;&quot;;
+        this.vert.firstChild.style.height = &quot;0&quot;;
+      }
+
+      if (needsH) {
+        this.horiz.style.display = &quot;block&quot;;
+        this.horiz.style.right = needsV ? sWidth + &quot;px&quot; : &quot;0&quot;;
+        this.horiz.style.left = measure.barLeft + &quot;px&quot;;
+        var totalWidth = measure.viewWidth - measure.barLeft - (needsV ? sWidth : 0);
+        this.horiz.firstChild.style.width =
+          (measure.scrollWidth - measure.clientWidth + totalWidth) + &quot;px&quot;;
+      } else {
+        this.horiz.style.display = &quot;&quot;;
+        this.horiz.firstChild.style.width = &quot;0&quot;;
+      }
+
+      if (!this.checkedOverlay &amp;&amp; measure.clientHeight &gt; 0) {
+        if (sWidth == 0) this.overlayHack();
+        this.checkedOverlay = true;
+      }
+
+      return {right: needsV ? sWidth : 0, bottom: needsH ? sWidth : 0};
+    },
+    setScrollLeft: function(pos) {
+      if (this.horiz.scrollLeft != pos) this.horiz.scrollLeft = pos;
+    },
+    setScrollTop: function(pos) {
+      if (this.vert.scrollTop != pos) this.vert.scrollTop = pos;
+    },
+    overlayHack: function() {
+      var w = mac &amp;&amp; !mac_geMountainLion ? &quot;12px&quot; : &quot;18px&quot;;
+      this.horiz.style.minHeight = this.vert.style.minWidth = w;
+      var self = this;
+      var barMouseDown = function(e) {
+        if (e_target(e) != self.vert &amp;&amp; e_target(e) != self.horiz)
+          operation(self.cm, onMouseDown)(e);
+      };
+      on(this.vert, &quot;mousedown&quot;, barMouseDown);
+      on(this.horiz, &quot;mousedown&quot;, barMouseDown);
+    },
+    clear: function() {
+      var parent = this.horiz.parentNode;
+      parent.removeChild(this.horiz);
+      parent.removeChild(this.vert);
+    }
+  }, NativeScrollbars.prototype);
+
+  function NullScrollbars() {}
+
+  NullScrollbars.prototype = copyObj({
+    update: function() { return {bottom: 0, right: 0}; },
+    setScrollLeft: function() {},
+    setScrollTop: function() {},
+    clear: function() {}
+  }, NullScrollbars.prototype);
+
+  CodeMirror.scrollbarModel = {&quot;native&quot;: NativeScrollbars, &quot;null&quot;: NullScrollbars};
+
+  function initScrollbars(cm) {
+    if (cm.display.scrollbars) {
+      cm.display.scrollbars.clear();
+      if (cm.display.scrollbars.addClass)
+        rmClass(cm.display.wrapper, cm.display.scrollbars.addClass);
+    }
+
+    cm.display.scrollbars = new CodeMirror.scrollbarModel[cm.options.scrollbarStyle](function(node) {
+      cm.display.wrapper.insertBefore(node, cm.display.scrollbarFiller);
+      // Prevent clicks in the scrollbars from killing focus
+      on(node, &quot;mousedown&quot;, function() {
+        if (cm.state.focused) setTimeout(function() { cm.display.input.focus(); }, 0);
+      });
+      node.setAttribute(&quot;cm-not-content&quot;, &quot;true&quot;);
+    }, function(pos, axis) {
+      if (axis == &quot;horizontal&quot;) setScrollLeft(cm, pos);
+      else setScrollTop(cm, pos);
+    }, cm);
+    if (cm.display.scrollbars.addClass)
+      addClass(cm.display.wrapper, cm.display.scrollbars.addClass);
+  }
+
+  function updateScrollbars(cm, measure) {
+    if (!measure) measure = measureForScrollbars(cm);
+    var startWidth = cm.display.barWidth, startHeight = cm.display.barHeight;
+    updateScrollbarsInner(cm, measure);
+    for (var i = 0; i &lt; 4 &amp;&amp; startWidth != cm.display.barWidth || startHeight != cm.display.barHeight; i++) {
+      if (startWidth != cm.display.barWidth &amp;&amp; cm.options.lineWrapping)
+        updateHeightsInViewport(cm);
+      updateScrollbarsInner(cm, measureForScrollbars(cm));
+      startWidth = cm.display.barWidth; startHeight = cm.display.barHeight;
+    }
+  }
+
</ins><span class="cx">   // Re-synchronize the fake scrollbars with the actual size of the
</span><span class="cx">   // content.
</span><del>-  function updateScrollbars(cm, measure) {
-    if (!measure) measure = measureForScrollbars(cm);
</del><ins>+  function updateScrollbarsInner(cm, measure) {
</ins><span class="cx">     var d = cm.display;
</span><del>-    var scrollHeight = measure.docHeight + scrollerCutOff;
-    var needsH = measure.scrollWidth &gt; measure.clientWidth;
-    var needsV = scrollHeight &gt; measure.clientHeight;
-    if (needsV) {
-      d.scrollbarV.style.display = &quot;block&quot;;
-      d.scrollbarV.style.bottom = needsH ? scrollbarWidth(d.measure) + &quot;px&quot; : &quot;0&quot;;
-      // A bug in IE8 can cause this value to be negative, so guard it.
-      d.scrollbarV.firstChild.style.height =
-        Math.max(0, scrollHeight - measure.clientHeight + (measure.barHeight || d.scrollbarV.clientHeight)) + &quot;px&quot;;
-    } else {
-      d.scrollbarV.style.display = &quot;&quot;;
-      d.scrollbarV.firstChild.style.height = &quot;0&quot;;
-    }
-    if (needsH) {
-      d.scrollbarH.style.display = &quot;block&quot;;
-      d.scrollbarH.style.right = needsV ? scrollbarWidth(d.measure) + &quot;px&quot; : &quot;0&quot;;
-      d.scrollbarH.firstChild.style.width =
-        (measure.scrollWidth - measure.clientWidth + (measure.barWidth || d.scrollbarH.clientWidth)) + &quot;px&quot;;
-    } else {
-      d.scrollbarH.style.display = &quot;&quot;;
-      d.scrollbarH.firstChild.style.width = &quot;0&quot;;
-    }
-    if (needsH &amp;&amp; needsV) {
</del><ins>+    var sizes = d.scrollbars.update(measure);
+
+    d.sizer.style.paddingRight = (d.barWidth = sizes.right) + &quot;px&quot;;
+    d.sizer.style.paddingBottom = (d.barHeight = sizes.bottom) + &quot;px&quot;;
+
+    if (sizes.right &amp;&amp; sizes.bottom) {
</ins><span class="cx">       d.scrollbarFiller.style.display = &quot;block&quot;;
</span><del>-      d.scrollbarFiller.style.height = d.scrollbarFiller.style.width = scrollbarWidth(d.measure) + &quot;px&quot;;
</del><ins>+      d.scrollbarFiller.style.height = sizes.bottom + &quot;px&quot;;
+      d.scrollbarFiller.style.width = sizes.right + &quot;px&quot;;
</ins><span class="cx">     } else d.scrollbarFiller.style.display = &quot;&quot;;
</span><del>-    if (needsH &amp;&amp; cm.options.coverGutterNextToScrollbar &amp;&amp; cm.options.fixedGutter) {
</del><ins>+    if (sizes.bottom &amp;&amp; cm.options.coverGutterNextToScrollbar &amp;&amp; cm.options.fixedGutter) {
</ins><span class="cx">       d.gutterFiller.style.display = &quot;block&quot;;
</span><del>-      d.gutterFiller.style.height = scrollbarWidth(d.measure) + &quot;px&quot;;
-      d.gutterFiller.style.width = d.gutters.offsetWidth + &quot;px&quot;;
</del><ins>+      d.gutterFiller.style.height = sizes.bottom + &quot;px&quot;;
+      d.gutterFiller.style.width = measure.gutterWidth + &quot;px&quot;;
</ins><span class="cx">     } else d.gutterFiller.style.display = &quot;&quot;;
</span><del>-
-    if (!cm.state.checkedOverlayScrollbar &amp;&amp; measure.clientHeight &gt; 0) {
-      if (scrollbarWidth(d.measure) === 0) {
-        var w = mac &amp;&amp; !mac_geMountainLion ? &quot;12px&quot; : &quot;18px&quot;;
-        d.scrollbarV.style.minWidth = d.scrollbarH.style.minHeight = w;
-        var barMouseDown = function(e) {
-          if (e_target(e) != d.scrollbarV &amp;&amp; e_target(e) != d.scrollbarH)
-            operation(cm, onMouseDown)(e);
-        };
-        on(d.scrollbarV, &quot;mousedown&quot;, barMouseDown);
-        on(d.scrollbarH, &quot;mousedown&quot;, barMouseDown);
-      }
-      cm.state.checkedOverlayScrollbar = true;
-    }
</del><span class="cx">   }
</span><span class="cx"> 
</span><span class="cx">   // Compute the lines that are visible in a given viewport (defaults
</span><del>-  // the the current scroll position). viewPort may contain top,
</del><ins>+  // the the current scroll position). viewport may contain top,
</ins><span class="cx">   // height, and ensure (see op.scrollToPos) properties.
</span><del>-  function visibleLines(display, doc, viewPort) {
-    var top = viewPort &amp;&amp; viewPort.top != null ? Math.max(0, viewPort.top) : display.scroller.scrollTop;
</del><ins>+  function visibleLines(display, doc, viewport) {
+    var top = viewport &amp;&amp; viewport.top != null ? Math.max(0, viewport.top) : display.scroller.scrollTop;
</ins><span class="cx">     top = Math.floor(top - paddingTop(display));
</span><del>-    var bottom = viewPort &amp;&amp; viewPort.bottom != null ? viewPort.bottom : top + display.wrapper.clientHeight;
</del><ins>+    var bottom = viewport &amp;&amp; viewport.bottom != null ? viewport.bottom : top + display.wrapper.clientHeight;
</ins><span class="cx"> 
</span><span class="cx">     var from = lineAtHeight(doc, top), to = lineAtHeight(doc, bottom);
</span><span class="cx">     // Ensure is a {from: {line, ch}, to: {line, ch}} object, and
</span><span class="cx">     // forces those lines into the viewport (if possible).
</span><del>-    if (viewPort &amp;&amp; viewPort.ensure) {
-      var ensureFrom = viewPort.ensure.from.line, ensureTo = viewPort.ensure.to.line;
-      if (ensureFrom &lt; from)
-        return {from: ensureFrom,
-                to: lineAtHeight(doc, heightAtLine(getLine(doc, ensureFrom)) + display.wrapper.clientHeight)};
-      if (Math.min(ensureTo, doc.lastLine()) &gt;= to)
-        return {from: lineAtHeight(doc, heightAtLine(getLine(doc, ensureTo)) - display.wrapper.clientHeight),
-                to: ensureTo};
</del><ins>+    if (viewport &amp;&amp; viewport.ensure) {
+      var ensureFrom = viewport.ensure.from.line, ensureTo = viewport.ensure.to.line;
+      if (ensureFrom &lt; from) {
+        from = ensureFrom;
+        to = lineAtHeight(doc, heightAtLine(getLine(doc, ensureFrom)) + display.wrapper.clientHeight);
+      } else if (Math.min(ensureTo, doc.lastLine()) &gt;= to) {
+        from = lineAtHeight(doc, heightAtLine(getLine(doc, ensureTo)) - display.wrapper.clientHeight);
+        to = ensureTo;
+      }
</ins><span class="cx">     }
</span><span class="cx">     return {from: from, to: Math.max(to, from + 1)};
</span><span class="cx">   }
</span><span class="lines">@@ -513,7 +595,7 @@
</span><span class="cx">                                                  &quot;CodeMirror-linenumber CodeMirror-gutter-elt&quot;));
</span><span class="cx">       var innerW = test.firstChild.offsetWidth, padding = test.offsetWidth - innerW;
</span><span class="cx">       display.lineGutter.style.width = &quot;&quot;;
</span><del>-      display.lineNumInnerWidth = Math.max(innerW, display.lineGutter.offsetWidth - padding);
</del><ins>+      display.lineNumInnerWidth = Math.max(innerW, display.lineGutter.offsetWidth - padding) + 1;
</ins><span class="cx">       display.lineNumWidth = display.lineNumInnerWidth + padding;
</span><span class="cx">       display.lineNumChars = display.lineNumInnerWidth ? last.length : -1;
</span><span class="cx">       display.lineGutter.style.width = display.lineNumWidth + &quot;px&quot;;
</span><span class="lines">@@ -536,78 +618,68 @@
</span><span class="cx"> 
</span><span class="cx">   // DISPLAY DRAWING
</span><span class="cx"> 
</span><del>-  // Updates the display, selection, and scrollbars, using the
-  // information in display.view to find out which nodes are no longer
-  // up-to-date. Tries to bail out early when no changes are needed,
-  // unless forced is true.
-  // Returns true if an actual update happened, false otherwise.
-  function updateDisplay(cm, viewPort, forced) {
-    var oldFrom = cm.display.viewFrom, oldTo = cm.display.viewTo, updated;
-    var visible = visibleLines(cm.display, cm.doc, viewPort);
-    for (var first = true;; first = false) {
-      var oldWidth = cm.display.scroller.clientWidth;
-      if (!updateDisplayInner(cm, visible, forced)) break;
-      updated = true;
</del><ins>+  function DisplayUpdate(cm, viewport, force) {
+    var display = cm.display;
</ins><span class="cx"> 
</span><del>-      // If the max line changed since it was last measured, measure it,
-      // and ensure the document's width matches it.
-      if (cm.display.maxLineChanged &amp;&amp; !cm.options.lineWrapping)
-        adjustContentWidth(cm);
</del><ins>+    this.viewport = viewport;
+    // Store some values that we'll need later (but don't want to force a relayout for)
+    this.visible = visibleLines(display, cm.doc, viewport);
+    this.editorIsHidden = !display.wrapper.offsetWidth;
+    this.wrapperHeight = display.wrapper.clientHeight;
+    this.wrapperWidth = display.wrapper.clientWidth;
+    this.oldDisplayWidth = displayWidth(cm);
+    this.force = force;
+    this.dims = getDimensions(cm);
+    this.events = [];
+  }
</ins><span class="cx"> 
</span><del>-      var barMeasure = measureForScrollbars(cm);
-      updateSelection(cm);
-      setDocumentHeight(cm, barMeasure);
-      updateScrollbars(cm, barMeasure);
-      if (webkit &amp;&amp; cm.options.lineWrapping)
-        checkForWebkitWidthBug(cm, barMeasure); // (Issue #2420)
-      if (first &amp;&amp; cm.options.lineWrapping &amp;&amp; oldWidth != cm.display.scroller.clientWidth) {
-        forced = true;
-        continue;
-      }
-      forced = false;
</del><ins>+  DisplayUpdate.prototype.signal = function(emitter, type) {
+    if (hasHandler(emitter, type))
+      this.events.push(arguments);
+  };
+  DisplayUpdate.prototype.finish = function() {
+    for (var i = 0; i &lt; this.events.length; i++)
+      signal.apply(null, this.events[i]);
+  };
</ins><span class="cx"> 
</span><del>-      // Clip forced viewport to actual scrollable area.
-      if (viewPort &amp;&amp; viewPort.top != null)
-        viewPort = {top: Math.min(barMeasure.docHeight - scrollerCutOff - barMeasure.clientHeight, viewPort.top)};
-      // Updated line heights might result in the drawn area not
-      // actually covering the viewport. Keep looping until it does.
-      visible = visibleLines(cm.display, cm.doc, viewPort);
-      if (visible.from &gt;= cm.display.viewFrom &amp;&amp; visible.to &lt;= cm.display.viewTo)
-        break;
</del><ins>+  function maybeClipScrollbars(cm) {
+    var display = cm.display;
+    if (!display.scrollbarsClipped &amp;&amp; display.scroller.offsetWidth) {
+      display.nativeBarWidth = display.scroller.offsetWidth - display.scroller.clientWidth;
+      display.heightForcer.style.height = scrollGap(cm) + &quot;px&quot;;
+      display.sizer.style.marginBottom = -display.nativeBarWidth + &quot;px&quot;;
+      display.sizer.style.borderRightWidth = scrollGap(cm) + &quot;px&quot;;
+      display.scrollbarsClipped = true;
</ins><span class="cx">     }
</span><del>-
-    cm.display.updateLineNumbers = null;
-    if (updated) {
-      signalLater(cm, &quot;update&quot;, cm);
-      if (cm.display.viewFrom != oldFrom || cm.display.viewTo != oldTo)
-        signalLater(cm, &quot;viewportChange&quot;, cm, cm.display.viewFrom, cm.display.viewTo);
-    }
-    return updated;
</del><span class="cx">   }
</span><span class="cx"> 
</span><span class="cx">   // Does the actual updating of the line display. Bails out
</span><span class="cx">   // (returning false) when there is nothing to be done and forced is
</span><span class="cx">   // false.
</span><del>-  function updateDisplayInner(cm, visible, forced) {
</del><ins>+  function updateDisplayIfNeeded(cm, update) {
</ins><span class="cx">     var display = cm.display, doc = cm.doc;
</span><del>-    if (!display.wrapper.offsetWidth) {
</del><ins>+
+    if (update.editorIsHidden) {
</ins><span class="cx">       resetView(cm);
</span><del>-      return;
</del><ins>+      return false;
</ins><span class="cx">     }
</span><span class="cx"> 
</span><span class="cx">     // Bail out if the visible area is already rendered and nothing changed.
</span><del>-    if (!forced &amp;&amp; visible.from &gt;= display.viewFrom &amp;&amp; visible.to &lt;= display.viewTo &amp;&amp;
-        countDirtyView(cm) == 0)
-      return;
</del><ins>+    if (!update.force &amp;&amp;
+        update.visible.from &gt;= display.viewFrom &amp;&amp; update.visible.to &lt;= display.viewTo &amp;&amp;
+        (display.updateLineNumbers == null || display.updateLineNumbers &gt;= display.viewTo) &amp;&amp;
+        display.renderedView == display.view &amp;&amp; countDirtyView(cm) == 0)
+      return false;
</ins><span class="cx"> 
</span><del>-    if (maybeUpdateLineNumberWidth(cm))
</del><ins>+    if (maybeUpdateLineNumberWidth(cm)) {
</ins><span class="cx">       resetView(cm);
</span><del>-    var dims = getDimensions(cm);
</del><ins>+      update.dims = getDimensions(cm);
+    }
</ins><span class="cx"> 
</span><span class="cx">     // Compute a suitable new viewport (from &amp; to)
</span><span class="cx">     var end = doc.first + doc.size;
</span><del>-    var from = Math.max(visible.from - cm.options.viewportMargin, doc.first);
-    var to = Math.min(end, visible.to + cm.options.viewportMargin);
</del><ins>+    var from = Math.max(update.visible.from - cm.options.viewportMargin, doc.first);
+    var to = Math.min(end, update.visible.to + cm.options.viewportMargin);
</ins><span class="cx">     if (display.viewFrom &lt; from &amp;&amp; from - display.viewFrom &lt; 20) from = Math.max(doc.first, display.viewFrom);
</span><span class="cx">     if (display.viewTo &gt; to &amp;&amp; display.viewTo - to &lt; 20) to = Math.min(end, display.viewTo);
</span><span class="cx">     if (sawCollapsedSpans) {
</span><span class="lines">@@ -616,7 +688,7 @@
</span><span class="cx">     }
</span><span class="cx"> 
</span><span class="cx">     var different = from != display.viewFrom || to != display.viewTo ||
</span><del>-      display.lastSizeC != display.wrapper.clientHeight;
</del><ins>+      display.lastWrapHeight != update.wrapperHeight || display.lastWrapWidth != update.wrapperWidth;
</ins><span class="cx">     adjustView(cm, from, to);
</span><span class="cx"> 
</span><span class="cx">     display.viewOffset = heightAtLine(getLine(cm.doc, display.viewFrom));
</span><span class="lines">@@ -624,58 +696,86 @@
</span><span class="cx">     cm.display.mover.style.top = display.viewOffset + &quot;px&quot;;
</span><span class="cx"> 
</span><span class="cx">     var toUpdate = countDirtyView(cm);
</span><del>-    if (!different &amp;&amp; toUpdate == 0 &amp;&amp; !forced) return;
</del><ins>+    if (!different &amp;&amp; toUpdate == 0 &amp;&amp; !update.force &amp;&amp; display.renderedView == display.view &amp;&amp;
+        (display.updateLineNumbers == null || display.updateLineNumbers &gt;= display.viewTo))
+      return false;
</ins><span class="cx"> 
</span><span class="cx">     // For big changes, we hide the enclosing element during the
</span><span class="cx">     // update, since that speeds up the operations on most browsers.
</span><span class="cx">     var focused = activeElt();
</span><span class="cx">     if (toUpdate &gt; 4) display.lineDiv.style.display = &quot;none&quot;;
</span><del>-    patchDisplay(cm, display.updateLineNumbers, dims);
</del><ins>+    patchDisplay(cm, display.updateLineNumbers, update.dims);
</ins><span class="cx">     if (toUpdate &gt; 4) display.lineDiv.style.display = &quot;&quot;;
</span><ins>+    display.renderedView = display.view;
</ins><span class="cx">     // There might have been a widget with a focused element that got
</span><span class="cx">     // hidden or updated, if so re-focus it.
</span><span class="cx">     if (focused &amp;&amp; activeElt() != focused &amp;&amp; focused.offsetHeight) focused.focus();
</span><span class="cx"> 
</span><span class="cx">     // Prevent selection and cursors from interfering with the scroll
</span><del>-    // width.
</del><ins>+    // width and height.
</ins><span class="cx">     removeChildren(display.cursorDiv);
</span><span class="cx">     removeChildren(display.selectionDiv);
</span><ins>+    display.gutters.style.height = display.sizer.style.minHeight = 0;
</ins><span class="cx"> 
</span><span class="cx">     if (different) {
</span><del>-      display.lastSizeC = display.wrapper.clientHeight;
</del><ins>+      display.lastWrapHeight = update.wrapperHeight;
+      display.lastWrapWidth = update.wrapperWidth;
</ins><span class="cx">       startWorker(cm, 400);
</span><span class="cx">     }
</span><span class="cx"> 
</span><del>-    updateHeightsInViewport(cm);
</del><ins>+    display.updateLineNumbers = null;
</ins><span class="cx"> 
</span><span class="cx">     return true;
</span><span class="cx">   }
</span><span class="cx"> 
</span><del>-  function adjustContentWidth(cm) {
-    var display = cm.display;
-    var width = measureChar(cm, display.maxLine, display.maxLine.text.length).left;
-    display.maxLineChanged = false;
-    var minWidth = Math.max(0, width + 3);
-    var maxScrollLeft = Math.max(0, display.sizer.offsetLeft + minWidth + scrollerCutOff - display.scroller.clientWidth);
-    display.sizer.style.minWidth = minWidth + &quot;px&quot;;
-    if (maxScrollLeft &lt; cm.doc.scrollLeft)
-      setScrollLeft(cm, Math.min(display.scroller.scrollLeft, maxScrollLeft), true);
-  }
</del><ins>+  function postUpdateDisplay(cm, update) {
+    var viewport = update.viewport;
+    for (var first = true;; first = false) {
+      if (!first || !cm.options.lineWrapping || update.oldDisplayWidth == displayWidth(cm)) {
+        // Clip forced viewport to actual scrollable area.
+        if (viewport &amp;&amp; viewport.top != null)
+          viewport = {top: Math.min(cm.doc.height + paddingVert(cm.display) - displayHeight(cm), viewport.top)};
+        // Updated line heights might result in the drawn area not
+        // actually covering the viewport. Keep looping until it does.
+        update.visible = visibleLines(cm.display, cm.doc, viewport);
+        if (update.visible.from &gt;= cm.display.viewFrom &amp;&amp; update.visible.to &lt;= cm.display.viewTo)
+          break;
+      }
+      if (!updateDisplayIfNeeded(cm, update)) break;
+      updateHeightsInViewport(cm);
+      var barMeasure = measureForScrollbars(cm);
+      updateSelection(cm);
+      setDocumentHeight(cm, barMeasure);
+      updateScrollbars(cm, barMeasure);
+    }
</ins><span class="cx"> 
</span><del>-  function setDocumentHeight(cm, measure) {
-    cm.display.sizer.style.minHeight = cm.display.heightForcer.style.top = measure.docHeight + &quot;px&quot;;
-    cm.display.gutters.style.height = Math.max(measure.docHeight, measure.clientHeight - scrollerCutOff) + &quot;px&quot;;
</del><ins>+    update.signal(cm, &quot;update&quot;, cm);
+    if (cm.display.viewFrom != cm.display.reportedViewFrom || cm.display.viewTo != cm.display.reportedViewTo) {
+      update.signal(cm, &quot;viewportChange&quot;, cm, cm.display.viewFrom, cm.display.viewTo);
+      cm.display.reportedViewFrom = cm.display.viewFrom; cm.display.reportedViewTo = cm.display.viewTo;
+    }
</ins><span class="cx">   }
</span><span class="cx"> 
</span><del>-  function checkForWebkitWidthBug(cm, measure) {
-    // Work around Webkit bug where it sometimes reserves space for a
-    // non-existing phantom scrollbar in the scroller (Issue #2420)
-    if (cm.display.sizer.offsetWidth + cm.display.gutters.offsetWidth &lt; cm.display.scroller.clientWidth - 1) {
-      cm.display.sizer.style.minHeight = cm.display.heightForcer.style.top = &quot;0px&quot;;
-      cm.display.gutters.style.height = measure.docHeight + &quot;px&quot;;
</del><ins>+  function updateDisplaySimple(cm, viewport) {
+    var update = new DisplayUpdate(cm, viewport);
+    if (updateDisplayIfNeeded(cm, update)) {
+      updateHeightsInViewport(cm);
+      postUpdateDisplay(cm, update);
+      var barMeasure = measureForScrollbars(cm);
+      updateSelection(cm);
+      setDocumentHeight(cm, barMeasure);
+      updateScrollbars(cm, barMeasure);
+      update.finish();
</ins><span class="cx">     }
</span><span class="cx">   }
</span><span class="cx"> 
</span><ins>+  function setDocumentHeight(cm, measure) {
+    cm.display.sizer.style.minHeight = measure.docHeight + &quot;px&quot;;
+    var total = measure.docHeight + cm.display.barHeight;
+    cm.display.heightForcer.style.top = total + &quot;px&quot;;
+    cm.display.gutters.style.height = Math.max(total + scrollGap(cm), measure.clientHeight) + &quot;px&quot;;
+  }
+
</ins><span class="cx">   // Read the actual heights of the rendered lines, and update their
</span><span class="cx">   // stored heights to match.
</span><span class="cx">   function updateHeightsInViewport(cm) {
</span><span class="lines">@@ -684,7 +784,7 @@
</span><span class="cx">     for (var i = 0; i &lt; display.view.length; i++) {
</span><span class="cx">       var cur = display.view[i], height;
</span><span class="cx">       if (cur.hidden) continue;
</span><del>-      if (ie_upto7) {
</del><ins>+      if (ie &amp;&amp; ie_version &lt; 8) {
</ins><span class="cx">         var bot = cur.node.offsetTop + cur.node.offsetHeight;
</span><span class="cx">         height = bot - prevBottom;
</span><span class="cx">         prevBottom = bot;
</span><span class="lines">@@ -714,9 +814,10 @@
</span><span class="cx">   // view, so that we don't interleave reading and writing to the DOM.
</span><span class="cx">   function getDimensions(cm) {
</span><span class="cx">     var d = cm.display, left = {}, width = {};
</span><ins>+    var gutterLeft = d.gutters.clientLeft;
</ins><span class="cx">     for (var n = d.gutters.firstChild, i = 0; n; n = n.nextSibling, ++i) {
</span><del>-      left[cm.options.gutters[i]] = n.offsetLeft;
-      width[cm.options.gutters[i]] = n.offsetWidth;
</del><ins>+      left[cm.options.gutters[i]] = n.offsetLeft + n.clientLeft + gutterLeft;
+      width[cm.options.gutters[i]] = n.clientWidth;
</ins><span class="cx">     }
</span><span class="cx">     return {fixedPos: compensateForHScroll(d),
</span><span class="cx">             gutterTotalWidth: d.gutters.offsetWidth,
</span><span class="lines">@@ -749,7 +850,7 @@
</span><span class="cx">     for (var i = 0; i &lt; view.length; i++) {
</span><span class="cx">       var lineView = view[i];
</span><span class="cx">       if (lineView.hidden) {
</span><del>-      } else if (!lineView.node) { // Not drawn yet
</del><ins>+      } else if (!lineView.node || lineView.node.parentNode != container) { // Not drawn yet
</ins><span class="cx">         var node = buildLineElement(cm, lineView, lineN, dims);
</span><span class="cx">         container.insertBefore(node, cur);
</span><span class="cx">       } else { // Already drawn
</span><span class="lines">@@ -780,7 +881,7 @@
</span><span class="cx">       if (type == &quot;text&quot;) updateLineText(cm, lineView);
</span><span class="cx">       else if (type == &quot;gutter&quot;) updateLineGutter(cm, lineView, lineN, dims);
</span><span class="cx">       else if (type == &quot;class&quot;) updateLineClasses(lineView);
</span><del>-      else if (type == &quot;widget&quot;) updateLineWidgets(lineView, dims);
</del><ins>+      else if (type == &quot;widget&quot;) updateLineWidgets(cm, lineView, dims);
</ins><span class="cx">     }
</span><span class="cx">     lineView.changes = null;
</span><span class="cx">   }
</span><span class="lines">@@ -793,7 +894,7 @@
</span><span class="cx">       if (lineView.text.parentNode)
</span><span class="cx">         lineView.text.parentNode.replaceChild(lineView.node, lineView.text);
</span><span class="cx">       lineView.node.appendChild(lineView.text);
</span><del>-      if (ie_upto7) lineView.node.style.zIndex = 2;
</del><ins>+      if (ie &amp;&amp; ie_version &lt; 8) lineView.node.style.zIndex = 2;
</ins><span class="cx">     }
</span><span class="cx">     return lineView.node;
</span><span class="cx">   }
</span><span class="lines">@@ -855,13 +956,26 @@
</span><span class="cx">       lineView.node.removeChild(lineView.gutter);
</span><span class="cx">       lineView.gutter = null;
</span><span class="cx">     }
</span><ins>+    if (lineView.gutterBackground) {
+      lineView.node.removeChild(lineView.gutterBackground);
+      lineView.gutterBackground = null;
+    }
+    if (lineView.line.gutterClass) {
+      var wrap = ensureLineWrapped(lineView);
+      lineView.gutterBackground = elt(&quot;div&quot;, null, &quot;CodeMirror-gutter-background &quot; + lineView.line.gutterClass,
+                                      &quot;left: &quot; + (cm.options.fixedGutter ? dims.fixedPos : -dims.gutterTotalWidth) +
+                                      &quot;px; width: &quot; + dims.gutterTotalWidth + &quot;px&quot;);
+      wrap.insertBefore(lineView.gutterBackground, lineView.text);
+    }
</ins><span class="cx">     var markers = lineView.line.gutterMarkers;
</span><span class="cx">     if (cm.options.lineNumbers || markers) {
</span><span class="cx">       var wrap = ensureLineWrapped(lineView);
</span><del>-      var gutterWrap = lineView.gutter =
-        wrap.insertBefore(elt(&quot;div&quot;, null, &quot;CodeMirror-gutter-wrapper&quot;, &quot;position: absolute; left: &quot; +
-                              (cm.options.fixedGutter ? dims.fixedPos : -dims.gutterTotalWidth) + &quot;px&quot;),
-                          lineView.text);
</del><ins>+      var gutterWrap = lineView.gutter = elt(&quot;div&quot;, null, &quot;CodeMirror-gutter-wrapper&quot;, &quot;left: &quot; +
+                                             (cm.options.fixedGutter ? dims.fixedPos : -dims.gutterTotalWidth) + &quot;px&quot;);
+      cm.display.input.setUneditable(gutterWrap);
+      wrap.insertBefore(gutterWrap, lineView.text);
+      if (lineView.line.gutterClass)
+        gutterWrap.className += &quot; &quot; + lineView.line.gutterClass;
</ins><span class="cx">       if (cm.options.lineNumbers &amp;&amp; (!markers || !markers[&quot;CodeMirror-linenumbers&quot;]))
</span><span class="cx">         lineView.lineNumber = gutterWrap.appendChild(
</span><span class="cx">           elt(&quot;div&quot;, lineNumberFor(cm.options, lineN),
</span><span class="lines">@@ -877,14 +991,14 @@
</span><span class="cx">     }
</span><span class="cx">   }
</span><span class="cx"> 
</span><del>-  function updateLineWidgets(lineView, dims) {
</del><ins>+  function updateLineWidgets(cm, lineView, dims) {
</ins><span class="cx">     if (lineView.alignable) lineView.alignable = null;
</span><span class="cx">     for (var node = lineView.node.firstChild, next; node; node = next) {
</span><span class="cx">       var next = node.nextSibling;
</span><span class="cx">       if (node.className == &quot;CodeMirror-linewidget&quot;)
</span><span class="cx">         lineView.node.removeChild(node);
</span><span class="cx">     }
</span><del>-    insertLineWidgets(lineView, dims);
</del><ins>+    insertLineWidgets(cm, lineView, dims);
</ins><span class="cx">   }
</span><span class="cx"> 
</span><span class="cx">   // Build a line's DOM representation from scratch
</span><span class="lines">@@ -896,25 +1010,26 @@
</span><span class="cx"> 
</span><span class="cx">     updateLineClasses(lineView);
</span><span class="cx">     updateLineGutter(cm, lineView, lineN, dims);
</span><del>-    insertLineWidgets(lineView, dims);
</del><ins>+    insertLineWidgets(cm, lineView, dims);
</ins><span class="cx">     return lineView.node;
</span><span class="cx">   }
</span><span class="cx"> 
</span><span class="cx">   // A lineView may contain multiple logical lines (when merged by
</span><span class="cx">   // collapsed spans). The widgets for all of them need to be drawn.
</span><del>-  function insertLineWidgets(lineView, dims) {
-    insertLineWidgetsFor(lineView.line, lineView, dims, true);
</del><ins>+  function insertLineWidgets(cm, lineView, dims) {
+    insertLineWidgetsFor(cm, lineView.line, lineView, dims, true);
</ins><span class="cx">     if (lineView.rest) for (var i = 0; i &lt; lineView.rest.length; i++)
</span><del>-      insertLineWidgetsFor(lineView.rest[i], lineView, dims, false);
</del><ins>+      insertLineWidgetsFor(cm, lineView.rest[i], lineView, dims, false);
</ins><span class="cx">   }
</span><span class="cx"> 
</span><del>-  function insertLineWidgetsFor(line, lineView, dims, allowAbove) {
</del><ins>+  function insertLineWidgetsFor(cm, line, lineView, dims, allowAbove) {
</ins><span class="cx">     if (!line.widgets) return;
</span><span class="cx">     var wrap = ensureLineWrapped(lineView);
</span><span class="cx">     for (var i = 0, ws = line.widgets; i &lt; ws.length; ++i) {
</span><span class="cx">       var widget = ws[i], node = elt(&quot;div&quot;, [widget.node], &quot;CodeMirror-linewidget&quot;);
</span><del>-      if (!widget.handleMouseEvents) node.ignoreEvents = true;
</del><ins>+      if (!widget.handleMouseEvents) node.setAttribute(&quot;cm-ignore-events&quot;, &quot;true&quot;);
</ins><span class="cx">       positionLineWidget(widget, node, lineView, dims);
</span><ins>+      cm.display.input.setUneditable(node);
</ins><span class="cx">       if (allowAbove &amp;&amp; widget.above)
</span><span class="cx">         wrap.insertBefore(node, lineView.gutter || lineView.text);
</span><span class="cx">       else
</span><span class="lines">@@ -957,6 +1072,905 @@
</span><span class="cx">   function maxPos(a, b) { return cmp(a, b) &lt; 0 ? b : a; }
</span><span class="cx">   function minPos(a, b) { return cmp(a, b) &lt; 0 ? a : b; }
</span><span class="cx"> 
</span><ins>+  // INPUT HANDLING
+
+  function ensureFocus(cm) {
+    if (!cm.state.focused) { cm.display.input.focus(); onFocus(cm); }
+  }
+
+  function isReadOnly(cm) {
+    return cm.options.readOnly || cm.doc.cantEdit;
+  }
+
+  // This will be set to an array of strings when copying, so that,
+  // when pasting, we know what kind of selections the copied text
+  // was made out of.
+  var lastCopied = null;
+
+  function applyTextInput(cm, inserted, deleted, sel, origin) {
+    var doc = cm.doc;
+    cm.display.shift = false;
+    if (!sel) sel = doc.sel;
+
+    var paste = cm.state.pasteIncoming || origin == &quot;paste&quot;;
+    var textLines = doc.splitLines(inserted), multiPaste = null;
+    // When pasing N lines into N selections, insert one line per selection
+    if (paste &amp;&amp; sel.ranges.length &gt; 1) {
+      if (lastCopied &amp;&amp; lastCopied.join(&quot;\n&quot;) == inserted) {
+        if (sel.ranges.length % lastCopied.length == 0) {
+          multiPaste = [];
+          for (var i = 0; i &lt; lastCopied.length; i++)
+            multiPaste.push(doc.splitLines(lastCopied[i]));
+        }
+      } else if (textLines.length == sel.ranges.length) {
+        multiPaste = map(textLines, function(l) { return [l]; });
+      }
+    }
+
+    // Normal behavior is to insert the new text into every selection
+    for (var i = sel.ranges.length - 1; i &gt;= 0; i--) {
+      var range = sel.ranges[i];
+      var from = range.from(), to = range.to();
+      if (range.empty()) {
+        if (deleted &amp;&amp; deleted &gt; 0) // Handle deletion
+          from = Pos(from.line, from.ch - deleted);
+        else if (cm.state.overwrite &amp;&amp; !paste) // Handle overwrite
+          to = Pos(to.line, Math.min(getLine(doc, to.line).text.length, to.ch + lst(textLines).length));
+      }
+      var updateInput = cm.curOp.updateInput;
+      var changeEvent = {from: from, to: to, text: multiPaste ? multiPaste[i % multiPaste.length] : textLines,
+                         origin: origin || (paste ? &quot;paste&quot; : cm.state.cutIncoming ? &quot;cut&quot; : &quot;+input&quot;)};
+      makeChange(cm.doc, changeEvent);
+      signalLater(cm, &quot;inputRead&quot;, cm, changeEvent);
+    }
+    if (inserted &amp;&amp; !paste)
+      triggerElectric(cm, inserted);
+
+    ensureCursorVisible(cm);
+    cm.curOp.updateInput = updateInput;
+    cm.curOp.typing = true;
+    cm.state.pasteIncoming = cm.state.cutIncoming = false;
+  }
+
+  function handlePaste(e, cm) {
+    var pasted = e.clipboardData &amp;&amp; e.clipboardData.getData(&quot;text/plain&quot;);
+    if (pasted) {
+      e.preventDefault();
+      if (!isReadOnly(cm) &amp;&amp; !cm.options.disableInput)
+        runInOp(cm, function() { applyTextInput(cm, pasted, 0, null, &quot;paste&quot;); });
+      return true;
+    }
+  }
+
+  function triggerElectric(cm, inserted) {
+    // When an 'electric' character is inserted, immediately trigger a reindent
+    if (!cm.options.electricChars || !cm.options.smartIndent) return;
+    var sel = cm.doc.sel;
+
+    for (var i = sel.ranges.length - 1; i &gt;= 0; i--) {
+      var range = sel.ranges[i];
+      if (range.head.ch &gt; 100 || (i &amp;&amp; sel.ranges[i - 1].head.line == range.head.line)) continue;
+      var mode = cm.getModeAt(range.head);
+      var indented = false;
+      if (mode.electricChars) {
+        for (var j = 0; j &lt; mode.electricChars.length; j++)
+          if (inserted.indexOf(mode.electricChars.charAt(j)) &gt; -1) {
+            indented = indentLine(cm, range.head.line, &quot;smart&quot;);
+            break;
+          }
+      } else if (mode.electricInput) {
+        if (mode.electricInput.test(getLine(cm.doc, range.head.line).text.slice(0, range.head.ch)))
+          indented = indentLine(cm, range.head.line, &quot;smart&quot;);
+      }
+      if (indented) signalLater(cm, &quot;electricInput&quot;, cm, range.head.line);
+    }
+  }
+
+  function copyableRanges(cm) {
+    var text = [], ranges = [];
+    for (var i = 0; i &lt; cm.doc.sel.ranges.length; i++) {
+      var line = cm.doc.sel.ranges[i].head.line;
+      var lineRange = {anchor: Pos(line, 0), head: Pos(line + 1, 0)};
+      ranges.push(lineRange);
+      text.push(cm.getRange(lineRange.anchor, lineRange.head));
+    }
+    return {text: text, ranges: ranges};
+  }
+
+  function disableBrowserMagic(field) {
+    field.setAttribute(&quot;autocorrect&quot;, &quot;off&quot;);
+    field.setAttribute(&quot;autocapitalize&quot;, &quot;off&quot;);
+    field.setAttribute(&quot;spellcheck&quot;, &quot;false&quot;);
+  }
+
+  // TEXTAREA INPUT STYLE
+
+  function TextareaInput(cm) {
+    this.cm = cm;
+    // See input.poll and input.reset
+    this.prevInput = &quot;&quot;;
+
+    // Flag that indicates whether we expect input to appear real soon
+    // now (after some event like 'keypress' or 'input') and are
+    // polling intensively.
+    this.pollingFast = false;
+    // Self-resetting timeout for the poller
+    this.polling = new Delayed();
+    // Tracks when input.reset has punted to just putting a short
+    // string into the textarea instead of the full selection.
+    this.inaccurateSelection = false;
+    // Used to work around IE issue with selection being forgotten when focus moves away from textarea
+    this.hasSelection = false;
+    this.composing = null;
+  };
+
+  function hiddenTextarea() {
+    var te = elt(&quot;textarea&quot;, null, null, &quot;position: absolute; padding: 0; width: 1px; height: 1em; outline: none&quot;);
+    var div = elt(&quot;div&quot;, [te], null, &quot;overflow: hidden; position: relative; width: 3px; height: 0px;&quot;);
+    // The textarea is kept positioned near the cursor to prevent the
+    // fact that it'll be scrolled into view on input from scrolling
+    // our fake cursor out of view. On webkit, when wrap=off, paste is
+    // very slow. So make the area wide instead.
+    if (webkit) te.style.width = &quot;1000px&quot;;
+    else te.setAttribute(&quot;wrap&quot;, &quot;off&quot;);
+    // If border: 0; -- iOS fails to open keyboard (issue #1287)
+    if (ios) te.style.border = &quot;1px solid black&quot;;
+    disableBrowserMagic(te);
+    return div;
+  }
+
+  TextareaInput.prototype = copyObj({
+    init: function(display) {
+      var input = this, cm = this.cm;
+
+      // Wraps and hides input textarea
+      var div = this.wrapper = hiddenTextarea();
+      // The semihidden textarea that is focused when the editor is
+      // focused, and receives input.
+      var te = this.textarea = div.firstChild;
+      display.wrapper.insertBefore(div, display.wrapper.firstChild);
+
+      // Needed to hide big blue blinking cursor on Mobile Safari (doesn't seem to work in iOS 8 anymore)
+      if (ios) te.style.width = &quot;0px&quot;;
+
+      on(te, &quot;input&quot;, function() {
+        if (ie &amp;&amp; ie_version &gt;= 9 &amp;&amp; input.hasSelection) input.hasSelection = null;
+        input.poll();
+      });
+
+      on(te, &quot;paste&quot;, function(e) {
+        if (handlePaste(e, cm)) return true;
+
+        cm.state.pasteIncoming = true;
+        input.fastPoll();
+      });
+
+      function prepareCopyCut(e) {
+        if (cm.somethingSelected()) {
+          lastCopied = cm.getSelections();
+          if (input.inaccurateSelection) {
+            input.prevInput = &quot;&quot;;
+            input.inaccurateSelection = false;
+            te.value = lastCopied.join(&quot;\n&quot;);
+            selectInput(te);
+          }
+        } else if (!cm.options.lineWiseCopyCut) {
+          return;
+        } else {
+          var ranges = copyableRanges(cm);
+          lastCopied = ranges.text;
+          if (e.type == &quot;cut&quot;) {
+            cm.setSelections(ranges.ranges, null, sel_dontScroll);
+          } else {
+            input.prevInput = &quot;&quot;;
+            te.value = ranges.text.join(&quot;\n&quot;);
+            selectInput(te);
+          }
+        }
+        if (e.type == &quot;cut&quot;) cm.state.cutIncoming = true;
+      }
+      on(te, &quot;cut&quot;, prepareCopyCut);
+      on(te, &quot;copy&quot;, prepareCopyCut);
+
+      on(display.scroller, &quot;paste&quot;, function(e) {
+        if (eventInWidget(display, e)) return;
+        cm.state.pasteIncoming = true;
+        input.focus();
+      });
+
+      // Prevent normal selection in the editor (we handle our own)
+      on(display.lineSpace, &quot;selectstart&quot;, function(e) {
+        if (!eventInWidget(display, e)) e_preventDefault(e);
+      });
+
+      on(te, &quot;compositionstart&quot;, function() {
+        var start = cm.getCursor(&quot;from&quot;);
+        input.composing = {
+          start: start,
+          range: cm.markText(start, cm.getCursor(&quot;to&quot;), {className: &quot;CodeMirror-composing&quot;})
+        };
+      });
+      on(te, &quot;compositionend&quot;, function() {
+        if (input.composing) {
+          input.poll();
+          input.composing.range.clear();
+          input.composing = null;
+        }
+      });
+    },
+
+    prepareSelection: function() {
+      // Redraw the selection and/or cursor
+      var cm = this.cm, display = cm.display, doc = cm.doc;
+      var result = prepareSelection(cm);
+
+      // Move the hidden textarea near the cursor to prevent scrolling artifacts
+      if (cm.options.moveInputWithCursor) {
+        var headPos = cursorCoords(cm, doc.sel.primary().head, &quot;div&quot;);
+        var wrapOff = display.wrapper.getBoundingClientRect(), lineOff = display.lineDiv.getBoundingClientRect();
+        result.teTop = Math.max(0, Math.min(display.wrapper.clientHeight - 10,
+                                            headPos.top + lineOff.top - wrapOff.top));
+        result.teLeft = Math.max(0, Math.min(display.wrapper.clientWidth - 10,
+                                             headPos.left + lineOff.left - wrapOff.left));
+      }
+
+      return result;
+    },
+
+    showSelection: function(drawn) {
+      var cm = this.cm, display = cm.display;
+      removeChildrenAndAdd(display.cursorDiv, drawn.cursors);
+      removeChildrenAndAdd(display.selectionDiv, drawn.selection);
+      if (drawn.teTop != null) {
+        this.wrapper.style.top = drawn.teTop + &quot;px&quot;;
+        this.wrapper.style.left = drawn.teLeft + &quot;px&quot;;
+      }
+    },
+
+    // Reset the input to correspond to the selection (or to be empty,
+    // when not typing and nothing is selected)
+    reset: function(typing) {
+      if (this.contextMenuPending) return;
+      var minimal, selected, cm = this.cm, doc = cm.doc;
+      if (cm.somethingSelected()) {
+        this.prevInput = &quot;&quot;;
+        var range = doc.sel.primary();
+        minimal = hasCopyEvent &amp;&amp;
+          (range.to().line - range.from().line &gt; 100 || (selected = cm.getSelection()).length &gt; 1000);
+        var content = minimal ? &quot;-&quot; : selected || cm.getSelection();
+        this.textarea.value = content;
+        if (cm.state.focused) selectInput(this.textarea);
+        if (ie &amp;&amp; ie_version &gt;= 9) this.hasSelection = content;
+      } else if (!typing) {
+        this.prevInput = this.textarea.value = &quot;&quot;;
+        if (ie &amp;&amp; ie_version &gt;= 9) this.hasSelection = null;
+      }
+      this.inaccurateSelection = minimal;
+    },
+
+    getField: function() { return this.textarea; },
+
+    supportsTouch: function() { return false; },
+
+    focus: function() {
+      if (this.cm.options.readOnly != &quot;nocursor&quot; &amp;&amp; (!mobile || activeElt() != this.textarea)) {
+        try { this.textarea.focus(); }
+        catch (e) {} // IE8 will throw if the textarea is display: none or not in DOM
+      }
+    },
+
+    blur: function() { this.textarea.blur(); },
+
+    resetPosition: function() {
+      this.wrapper.style.top = this.wrapper.style.left = 0;
+    },
+
+    receivedFocus: function() { this.slowPoll(); },
+
+    // Poll for input changes, using the normal rate of polling. This
+    // runs as long as the editor is focused.
+    slowPoll: function() {
+      var input = this;
+      if (input.pollingFast) return;
+      input.polling.set(this.cm.options.pollInterval, function() {
+        input.poll();
+        if (input.cm.state.focused) input.slowPoll();
+      });
+    },
+
+    // When an event has just come in that is likely to add or change
+    // something in the input textarea, we poll faster, to ensure that
+    // the change appears on the screen quickly.
+    fastPoll: function() {
+      var missed = false, input = this;
+      input.pollingFast = true;
+      function p() {
+        var changed = input.poll();
+        if (!changed &amp;&amp; !missed) {missed = true; input.polling.set(60, p);}
+        else {input.pollingFast = false; input.slowPoll();}
+      }
+      input.polling.set(20, p);
+    },
+
+    // Read input from the textarea, and update the document to match.
+    // When something is selected, it is present in the textarea, and
+    // selected (unless it is huge, in which case a placeholder is
+    // used). When nothing is selected, the cursor sits after previously
+    // seen text (can be empty), which is stored in prevInput (we must
+    // not reset the textarea when typing, because that breaks IME).
+    poll: function() {
+      var cm = this.cm, input = this.textarea, prevInput = this.prevInput;
+      // Since this is called a *lot*, try to bail out as cheaply as
+      // possible when it is clear that nothing happened. hasSelection
+      // will be the case when there is a lot of text in the textarea,
+      // in which case reading its value would be expensive.
+      if (this.contextMenuPending || !cm.state.focused ||
+          (hasSelection(input) &amp;&amp; !prevInput &amp;&amp; !this.composing) ||
+          isReadOnly(cm) || cm.options.disableInput || cm.state.keySeq)
+        return false;
+
+      var text = input.value;
+      // If nothing changed, bail.
+      if (text == prevInput &amp;&amp; !cm.somethingSelected()) return false;
+      // Work around nonsensical selection resetting in IE9/10, and
+      // inexplicable appearance of private area unicode characters on
+      // some key combos in Mac (#2689).
+      if (ie &amp;&amp; ie_version &gt;= 9 &amp;&amp; this.hasSelection === text ||
+          mac &amp;&amp; /[\uf700-\uf7ff]/.test(text)) {
+        cm.display.input.reset();
+        return false;
+      }
+
+      if (cm.doc.sel == cm.display.selForContextMenu) {
+        var first = text.charCodeAt(0);
+        if (first == 0x200b &amp;&amp; !prevInput) prevInput = &quot;\u200b&quot;;
+        if (first == 0x21da) { this.reset(); return this.cm.execCommand(&quot;undo&quot;); }
+      }
+      // Find the part of the input that is actually new
+      var same = 0, l = Math.min(prevInput.length, text.length);
+      while (same &lt; l &amp;&amp; prevInput.charCodeAt(same) == text.charCodeAt(same)) ++same;
+
+      var self = this;
+      runInOp(cm, function() {
+        applyTextInput(cm, text.slice(same), prevInput.length - same,
+                       null, self.composing ? &quot;*compose&quot; : null);
+
+        // Don't leave long text in the textarea, since it makes further polling slow
+        if (text.length &gt; 1000 || text.indexOf(&quot;\n&quot;) &gt; -1) input.value = self.prevInput = &quot;&quot;;
+        else self.prevInput = text;
+
+        if (self.composing) {
+          self.composing.range.clear();
+          self.composing.range = cm.markText(self.composing.start, cm.getCursor(&quot;to&quot;),
+                                             {className: &quot;CodeMirror-composing&quot;});
+        }
+      });
+      return true;
+    },
+
+    ensurePolled: function() {
+      if (this.pollingFast &amp;&amp; this.poll()) this.pollingFast = false;
+    },
+
+    onKeyPress: function() {
+      if (ie &amp;&amp; ie_version &gt;= 9) this.hasSelection = null;
+      this.fastPoll();
+    },
+
+    onContextMenu: function(e) {
+      var input = this, cm = input.cm, display = cm.display, te = input.textarea;
+      var pos = posFromMouse(cm, e), scrollPos = display.scroller.scrollTop;
+      if (!pos || presto) return; // Opera is difficult.
+
+      // Reset the current text selection only if the click is done outside of the selection
+      // and 'resetSelectionOnContextMenu' option is true.
+      var reset = cm.options.resetSelectionOnContextMenu;
+      if (reset &amp;&amp; cm.doc.sel.contains(pos) == -1)
+        operation(cm, setSelection)(cm.doc, simpleSelection(pos), sel_dontScroll);
+
+      var oldCSS = te.style.cssText;
+      input.wrapper.style.position = &quot;absolute&quot;;
+      te.style.cssText = &quot;position: fixed; width: 30px; height: 30px; top: &quot; + (e.clientY - 5) +
+        &quot;px; left: &quot; + (e.clientX - 5) + &quot;px; z-index: 1000; background: &quot; +
+        (ie ? &quot;rgba(255, 255, 255, .05)&quot; : &quot;transparent&quot;) +
+        &quot;; outline: none; border-width: 0; outline: none; overflow: hidden; opacity: .05; filter: alpha(opacity=5);&quot;;
+      if (webkit) var oldScrollY = window.scrollY; // Work around Chrome issue (#2712)
+      display.input.focus();
+      if (webkit) window.scrollTo(null, oldScrollY);
+      display.input.reset();
+      // Adds &quot;Select all&quot; to context menu in FF
+      if (!cm.somethingSelected()) te.value = input.prevInput = &quot; &quot;;
+      input.contextMenuPending = true;
+      display.selForContextMenu = cm.doc.sel;
+      clearTimeout(display.detectingSelectAll);
+
+      // Select-all will be greyed out if there's nothing to select, so
+      // this adds a zero-width space so that we can later check whether
+      // it got selected.
+      function prepareSelectAllHack() {
+        if (te.selectionStart != null) {
+          var selected = cm.somethingSelected();
+          var extval = &quot;\u200b&quot; + (selected ? te.value : &quot;&quot;);
+          te.value = &quot;\u21da&quot;; // Used to catch context-menu undo
+          te.value = extval;
+          input.prevInput = selected ? &quot;&quot; : &quot;\u200b&quot;;
+          te.selectionStart = 1; te.selectionEnd = extval.length;
+          // Re-set this, in case some other handler touched the
+          // selection in the meantime.
+          display.selForContextMenu = cm.doc.sel;
+        }
+      }
+      function rehide() {
+        input.contextMenuPending = false;
+        input.wrapper.style.position = &quot;relative&quot;;
+        te.style.cssText = oldCSS;
+        if (ie &amp;&amp; ie_version &lt; 9) display.scrollbars.setScrollTop(display.scroller.scrollTop = scrollPos);
+
+        // Try to detect the user choosing select-all
+        if (te.selectionStart != null) {
+          if (!ie || (ie &amp;&amp; ie_version &lt; 9)) prepareSelectAllHack();
+          var i = 0, poll = function() {
+            if (display.selForContextMenu == cm.doc.sel &amp;&amp; te.selectionStart == 0 &amp;&amp;
+                te.selectionEnd &gt; 0 &amp;&amp; input.prevInput == &quot;\u200b&quot;)
+              operation(cm, commands.selectAll)(cm);
+            else if (i++ &lt; 10) display.detectingSelectAll = setTimeout(poll, 500);
+            else display.input.reset();
+          };
+          display.detectingSelectAll = setTimeout(poll, 200);
+        }
+      }
+
+      if (ie &amp;&amp; ie_version &gt;= 9) prepareSelectAllHack();
+      if (captureRightClick) {
+        e_stop(e);
+        var mouseup = function() {
+          off(window, &quot;mouseup&quot;, mouseup);
+          setTimeout(rehide, 20);
+        };
+        on(window, &quot;mouseup&quot;, mouseup);
+      } else {
+        setTimeout(rehide, 50);
+      }
+    },
+
+    setUneditable: nothing,
+
+    needsContentAttribute: false
+  }, TextareaInput.prototype);
+
+  // CONTENTEDITABLE INPUT STYLE
+
+  function ContentEditableInput(cm) {
+    this.cm = cm;
+    this.lastAnchorNode = this.lastAnchorOffset = this.lastFocusNode = this.lastFocusOffset = null;
+    this.polling = new Delayed();
+    this.gracePeriod = false;
+  }
+
+  ContentEditableInput.prototype = copyObj({
+    init: function(display) {
+      var input = this, cm = input.cm;
+      var div = input.div = display.lineDiv;
+      div.contentEditable = &quot;true&quot;;
+      disableBrowserMagic(div);
+
+      on(div, &quot;paste&quot;, function(e) { handlePaste(e, cm); })
+
+      on(div, &quot;compositionstart&quot;, function(e) {
+        var data = e.data;
+        input.composing = {sel: cm.doc.sel, data: data, startData: data};
+        if (!data) return;
+        var prim = cm.doc.sel.primary();
+        var line = cm.getLine(prim.head.line);
+        var found = line.indexOf(data, Math.max(0, prim.head.ch - data.length));
+        if (found &gt; -1 &amp;&amp; found &lt;= prim.head.ch)
+          input.composing.sel = simpleSelection(Pos(prim.head.line, found),
+                                                Pos(prim.head.line, found + data.length));
+      });
+      on(div, &quot;compositionupdate&quot;, function(e) {
+        input.composing.data = e.data;
+      });
+      on(div, &quot;compositionend&quot;, function(e) {
+        var ours = input.composing;
+        if (!ours) return;
+        if (e.data != ours.startData &amp;&amp; !/\u200b/.test(e.data))
+          ours.data = e.data;
+        // Need a small delay to prevent other code (input event,
+        // selection polling) from doing damage when fired right after
+        // compositionend.
+        setTimeout(function() {
+          if (!ours.handled)
+            input.applyComposition(ours);
+          if (input.composing == ours)
+            input.composing = null;
+        }, 50);
+      });
+
+      on(div, &quot;touchstart&quot;, function() {
+        input.forceCompositionEnd();
+      });
+
+      on(div, &quot;input&quot;, function() {
+        if (input.composing) return;
+        if (!input.pollContent())
+          runInOp(input.cm, function() {regChange(cm);});
+      });
+
+      function onCopyCut(e) {
+        if (cm.somethingSelected()) {
+          lastCopied = cm.getSelections();
+          if (e.type == &quot;cut&quot;) cm.replaceSelection(&quot;&quot;, null, &quot;cut&quot;);
+        } else if (!cm.options.lineWiseCopyCut) {
+          return;
+        } else {
+          var ranges = copyableRanges(cm);
+          lastCopied = ranges.text;
+          if (e.type == &quot;cut&quot;) {
+            cm.operation(function() {
+              cm.setSelections(ranges.ranges, 0, sel_dontScroll);
+              cm.replaceSelection(&quot;&quot;, null, &quot;cut&quot;);
+            });
+          }
+        }
+        // iOS exposes the clipboard API, but seems to discard content inserted into it
+        if (e.clipboardData &amp;&amp; !ios) {
+          e.preventDefault();
+          e.clipboardData.clearData();
+          e.clipboardData.setData(&quot;text/plain&quot;, lastCopied.join(&quot;\n&quot;));
+        } else {
+          // Old-fashioned briefly-focus-a-textarea hack
+          var kludge = hiddenTextarea(), te = kludge.firstChild;
+          cm.display.lineSpace.insertBefore(kludge, cm.display.lineSpace.firstChild);
+          te.value = lastCopied.join(&quot;\n&quot;);
+          var hadFocus = document.activeElement;
+          selectInput(te);
+          setTimeout(function() {
+            cm.display.lineSpace.removeChild(kludge);
+            hadFocus.focus();
+          }, 50);
+        }
+      }
+      on(div, &quot;copy&quot;, onCopyCut);
+      on(div, &quot;cut&quot;, onCopyCut);
+    },
+
+    prepareSelection: function() {
+      var result = prepareSelection(this.cm, false);
+      result.focus = this.cm.state.focused;
+      return result;
+    },
+
+    showSelection: function(info) {
+      if (!info || !this.cm.display.view.length) return;
+      if (info.focus) this.showPrimarySelection();
+      this.showMultipleSelections(info);
+    },
+
+    showPrimarySelection: function() {
+      var sel = window.getSelection(), prim = this.cm.doc.sel.primary();
+      var curAnchor = domToPos(this.cm, sel.anchorNode, sel.anchorOffset);
+      var curFocus = domToPos(this.cm, sel.focusNode, sel.focusOffset);
+      if (curAnchor &amp;&amp; !curAnchor.bad &amp;&amp; curFocus &amp;&amp; !curFocus.bad &amp;&amp;
+          cmp(minPos(curAnchor, curFocus), prim.from()) == 0 &amp;&amp;
+          cmp(maxPos(curAnchor, curFocus), prim.to()) == 0)
+        return;
+
+      var start = posToDOM(this.cm, prim.from());
+      var end = posToDOM(this.cm, prim.to());
+      if (!start &amp;&amp; !end) return;
+
+      var view = this.cm.display.view;
+      var old = sel.rangeCount &amp;&amp; sel.getRangeAt(0);
+      if (!start) {
+        start = {node: view[0].measure.map[2], offset: 0};
+      } else if (!end) { // FIXME dangerously hacky
+        var measure = view[view.length - 1].measure;
+        var map = measure.maps ? measure.maps[measure.maps.length - 1] : measure.map;
+        end = {node: map[map.length - 1], offset: map[map.length - 2] - map[map.length - 3]};
+      }
+
+      try { var rng = range(start.node, start.offset, end.offset, end.node); }
+      catch(e) {} // Our model of the DOM might be outdated, in which case the range we try to set can be impossible
+      if (rng) {
+        sel.removeAllRanges();
+        sel.addRange(rng);
+        if (old &amp;&amp; sel.anchorNode == null) sel.addRange(old);
+        else if (gecko) this.startGracePeriod();
+      }
+      this.rememberSelection();
+    },
+
+    startGracePeriod: function() {
+      var input = this;
+      clearTimeout(this.gracePeriod);
+      this.gracePeriod = setTimeout(function() {
+        input.gracePeriod = false;
+        if (input.selectionChanged())
+          input.cm.operation(function() { input.cm.curOp.selectionChanged = true; });
+      }, 20);
+    },
+
+    showMultipleSelections: function(info) {
+      removeChildrenAndAdd(this.cm.display.cursorDiv, info.cursors);
+      removeChildrenAndAdd(this.cm.display.selectionDiv, info.selection);
+    },
+
+    rememberSelection: function() {
+      var sel = window.getSelection();
+      this.lastAnchorNode = sel.anchorNode; this.lastAnchorOffset = sel.anchorOffset;
+      this.lastFocusNode = sel.focusNode; this.lastFocusOffset = sel.focusOffset;
+    },
+
+    selectionInEditor: function() {
+      var sel = window.getSelection();
+      if (!sel.rangeCount) return false;
+      var node = sel.getRangeAt(0).commonAncestorContainer;
+      return contains(this.div, node);
+    },
+
+    focus: function() {
+      if (this.cm.options.readOnly != &quot;nocursor&quot;) this.div.focus();
+    },
+    blur: function() { this.div.blur(); },
+    getField: function() { return this.div; },
+
+    supportsTouch: function() { return true; },
+
+    receivedFocus: function() {
+      var input = this;
+      if (this.selectionInEditor())
+        this.pollSelection();
+      else
+        runInOp(this.cm, function() { input.cm.curOp.selectionChanged = true; });
+
+      function poll() {
+        if (input.cm.state.focused) {
+          input.pollSelection();
+          input.polling.set(input.cm.options.pollInterval, poll);
+        }
+      }
+      this.polling.set(this.cm.options.pollInterval, poll);
+    },
+
+    selectionChanged: function() {
+      var sel = window.getSelection();
+      return sel.anchorNode != this.lastAnchorNode || sel.anchorOffset != this.lastAnchorOffset ||
+        sel.focusNode != this.lastFocusNode || sel.focusOffset != this.lastFocusOffset;
+    },
+
+    pollSelection: function() {
+      if (!this.composing &amp;&amp; !this.gracePeriod &amp;&amp; this.selectionChanged()) {
+        var sel = window.getSelection(), cm = this.cm;
+        this.rememberSelection();
+        var anchor = domToPos(cm, sel.anchorNode, sel.anchorOffset);
+        var head = domToPos(cm, sel.focusNode, sel.focusOffset);
+        if (anchor &amp;&amp; head) runInOp(cm, function() {
+          setSelection(cm.doc, simpleSelection(anchor, head), sel_dontScroll);
+          if (anchor.bad || head.bad) cm.curOp.selectionChanged = true;
+        });
+      }
+    },
+
+    pollContent: function() {
+      var cm = this.cm, display = cm.display, sel = cm.doc.sel.primary();
+      var from = sel.from(), to = sel.to();
+      if (from.line &lt; display.viewFrom || to.line &gt; display.viewTo - 1) return false;
+
+      var fromIndex;
+      if (from.line == display.viewFrom || (fromIndex = findViewIndex(cm, from.line)) == 0) {
+        var fromLine = lineNo(display.view[0].line);
+        var fromNode = display.view[0].node;
+      } else {
+        var fromLine = lineNo(display.view[fromIndex].line);
+        var fromNode = display.view[fromIndex - 1].node.nextSibling;
+      }
+      var toIndex = findViewIndex(cm, to.line);
+      if (toIndex == display.view.length - 1) {
+        var toLine = display.viewTo - 1;
+        var toNode = display.lineDiv.lastChild;
+      } else {
+        var toLine = lineNo(display.view[toIndex + 1].line) - 1;
+        var toNode = display.view[toIndex + 1].node.previousSibling;
+      }
+
+      var newText = cm.doc.splitLines(domTextBetween(cm, fromNode, toNode, fromLine, toLine));
+      var oldText = getBetween(cm.doc, Pos(fromLine, 0), Pos(toLine, getLine(cm.doc, toLine).text.length));
+      while (newText.length &gt; 1 &amp;&amp; oldText.length &gt; 1) {
+        if (lst(newText) == lst(oldText)) { newText.pop(); oldText.pop(); toLine--; }
+        else if (newText[0] == oldText[0]) { newText.shift(); oldText.shift(); fromLine++; }
+        else break;
+      }
+
+      var cutFront = 0, cutEnd = 0;
+      var newTop = newText[0], oldTop = oldText[0], maxCutFront = Math.min(newTop.length, oldTop.length);
+      while (cutFront &lt; maxCutFront &amp;&amp; newTop.charCodeAt(cutFront) == oldTop.charCodeAt(cutFront))
+        ++cutFront;
+      var newBot = lst(newText), oldBot = lst(oldText);
+      var maxCutEnd = Math.min(newBot.length - (newText.length == 1 ? cutFront : 0),
+                               oldBot.length - (oldText.length == 1 ? cutFront : 0));
+      while (cutEnd &lt; maxCutEnd &amp;&amp;
+             newBot.charCodeAt(newBot.length - cutEnd - 1) == oldBot.charCodeAt(oldBot.length - cutEnd - 1))
+        ++cutEnd;
+
+      newText[newText.length - 1] = newBot.slice(0, newBot.length - cutEnd);
+      newText[0] = newText[0].slice(cutFront);
+
+      var chFrom = Pos(fromLine, cutFront);
+      var chTo = Pos(toLine, oldText.length ? lst(oldText).length - cutEnd : 0);
+      if (newText.length &gt; 1 || newText[0] || cmp(chFrom, chTo)) {
+        replaceRange(cm.doc, newText, chFrom, chTo, &quot;+input&quot;);
+        return true;
+      }
+    },
+
+    ensurePolled: function() {
+      this.forceCompositionEnd();
+    },
+    reset: function() {
+      this.forceCompositionEnd();
+    },
+    forceCompositionEnd: function() {
+      if (!this.composing || this.composing.handled) return;
+      this.applyComposition(this.composing);
+      this.composing.handled = true;
+      this.div.blur();
+      this.div.focus();
+    },
+    applyComposition: function(composing) {
+      if (composing.data &amp;&amp; composing.data != composing.startData)
+        operation(this.cm, applyTextInput)(this.cm, composing.data, 0, composing.sel);
+    },
+
+    setUneditable: function(node) {
+      node.setAttribute(&quot;contenteditable&quot;, &quot;false&quot;);
+    },
+
+    onKeyPress: function(e) {
+      e.preventDefault();
+      operation(this.cm, applyTextInput)(this.cm, String.fromCharCode(e.charCode == null ? e.keyCode : e.charCode), 0);
+    },
+
+    onContextMenu: nothing,
+    resetPosition: nothing,
+
+    needsContentAttribute: true
+  }, ContentEditableInput.prototype);
+
+  function posToDOM(cm, pos) {
+    var view = findViewForLine(cm, pos.line);
+    if (!view || view.hidden) return null;
+    var line = getLine(cm.doc, pos.line);
+    var info = mapFromLineView(view, line, pos.line);
+
+    var order = getOrder(line), side = &quot;left&quot;;
+    if (order) {
+      var partPos = getBidiPartAt(order, pos.ch);
+      side = partPos % 2 ? &quot;right&quot; : &quot;left&quot;;
+    }
+    var result = nodeAndOffsetInLineMap(info.map, pos.ch, side);
+    result.offset = result.collapse == &quot;right&quot; ? result.end : result.start;
+    return result;
+  }
+
+  function badPos(pos, bad) { if (bad) pos.bad = true; return pos; }
+
+  function domToPos(cm, node, offset) {
+    var lineNode;
+    if (node == cm.display.lineDiv) {
+      lineNode = cm.display.lineDiv.childNodes[offset];
+      if (!lineNode) return badPos(cm.clipPos(Pos(cm.display.viewTo - 1)), true);
+      node = null; offset = 0;
+    } else {
+      for (lineNode = node;; lineNode = lineNode.parentNode) {
+        if (!lineNode || lineNode == cm.display.lineDiv) return null;
+        if (lineNode.parentNode &amp;&amp; lineNode.parentNode == cm.display.lineDiv) break;
+      }
+    }
+    for (var i = 0; i &lt; cm.display.view.length; i++) {
+      var lineView = cm.display.view[i];
+      if (lineView.node == lineNode)
+        return locateNodeInLineView(lineView, node, offset);
+    }
+  }
+
+  function locateNodeInLineView(lineView, node, offset) {
+    var wrapper = lineView.text.firstChild, bad = false;
+    if (!node || !contains(wrapper, node)) return badPos(Pos(lineNo(lineView.line), 0), true);
+    if (node == wrapper) {
+      bad = true;
+      node = wrapper.childNodes[offset];
+      offset = 0;
+      if (!node) {
+        var line = lineView.rest ? lst(lineView.rest) : lineView.line;
+        return badPos(Pos(lineNo(line), line.text.length), bad);
+      }
+    }
+
+    var textNode = node.nodeType == 3 ? node : null, topNode = node;
+    if (!textNode &amp;&amp; node.childNodes.length == 1 &amp;&amp; node.firstChild.nodeType == 3) {
+      textNode = node.firstChild;
+      if (offset) offset = textNode.nodeValue.length;
+    }
+    while (topNode.parentNode != wrapper) topNode = topNode.parentNode;
+    var measure = lineView.measure, maps = measure.maps;
+
+    function find(textNode, topNode, offset) {
+      for (var i = -1; i &lt; (maps ? maps.length : 0); i++) {
+        var map = i &lt; 0 ? measure.map : maps[i];
+        for (var j = 0; j &lt; map.length; j += 3) {
+          var curNode = map[j + 2];
+          if (curNode == textNode || curNode == topNode) {
+            var line = lineNo(i &lt; 0 ? lineView.line : lineView.rest[i]);
+            var ch = map[j] + offset;
+            if (offset &lt; 0 || curNode != textNode) ch = map[j + (offset ? 1 : 0)];
+            return Pos(line, ch);
+          }
+        }
+      }
+    }
+    var found = find(textNode, topNode, offset);
+    if (found) return badPos(found, bad);
+
+    // FIXME this is all really shaky. might handle the few cases it needs to handle, but likely to cause problems
+    for (var after = topNode.nextSibling, dist = textNode ? textNode.nodeValue.length - offset : 0; after; after = after.nextSibling) {
+      found = find(after, after.firstChild, 0);
+      if (found)
+        return badPos(Pos(found.line, found.ch - dist), bad);
+      else
+        dist += after.textContent.length;
+    }
+    for (var before = topNode.previousSibling, dist = offset; before; before = before.previousSibling) {
+      found = find(before, before.firstChild, -1);
+      if (found)
+        return badPos(Pos(found.line, found.ch + dist), bad);
+      else
+        dist += after.textContent.length;
+    }
+  }
+
+  function domTextBetween(cm, from, to, fromLine, toLine) {
+    var text = &quot;&quot;, closing = false, lineSep = cm.doc.lineSeparator();
+    function recognizeMarker(id) { return function(marker) { return marker.id == id; }; }
+    function walk(node) {
+      if (node.nodeType == 1) {
+        var cmText = node.getAttribute(&quot;cm-text&quot;);
+        if (cmText != null) {
+          if (cmText == &quot;&quot;) cmText = node.textContent.replace(/\u200b/g, &quot;&quot;);
+          text += cmText;
+          return;
+        }
+        var markerID = node.getAttribute(&quot;cm-marker&quot;), range;
+        if (markerID) {
+          var found = cm.findMarks(Pos(fromLine, 0), Pos(toLine + 1, 0), recognizeMarker(+markerID));
+          if (found.length &amp;&amp; (range = found[0].find()))
+            text += getBetween(cm.doc, range.from, range.to).join(lineSep);
+          return;
+        }
+        if (node.getAttribute(&quot;contenteditable&quot;) == &quot;false&quot;) return;
+        for (var i = 0; i &lt; node.childNodes.length; i++)
+          walk(node.childNodes[i]);
+        if (/^(pre|div|p)$/i.test(node.nodeName))
+          closing = true;
+      } else if (node.nodeType == 3) {
+        var val = node.nodeValue;
+        if (!val) return;
+        if (closing) {
+          text += lineSep;
+          closing = false;
+        }
+        text += val;
+      }
+    }
+    for (;;) {
+      walk(from);
+      if (from == to) break;
+      from = from.nextSibling;
+    }
+    return text;
+  }
+
+  CodeMirror.inputStyles = {&quot;textarea&quot;: TextareaInput, &quot;contenteditable&quot;: ContentEditableInput};
+
</ins><span class="cx">   // SELECTION / CURSOR
</span><span class="cx"> 
</span><span class="cx">   // Selection objects are immutable. A new one is created every time
</span><span class="lines">@@ -1244,40 +2258,30 @@
</span><span class="cx"> 
</span><span class="cx">   // SELECTION DRAWING
</span><span class="cx"> 
</span><del>-  // Redraw the selection and/or cursor
</del><span class="cx">   function updateSelection(cm) {
</span><del>-    var display = cm.display, doc = cm.doc;
-    var curFragment = document.createDocumentFragment();
-    var selFragment = document.createDocumentFragment();
</del><ins>+    cm.display.input.showSelection(cm.display.input.prepareSelection());
+  }
</ins><span class="cx"> 
</span><ins>+  function prepareSelection(cm, primary) {
+    var doc = cm.doc, result = {};
+    var curFragment = result.cursors = document.createDocumentFragment();
+    var selFragment = result.selection = document.createDocumentFragment();
+
</ins><span class="cx">     for (var i = 0; i &lt; doc.sel.ranges.length; i++) {
</span><ins>+      if (primary === false &amp;&amp; i == doc.sel.primIndex) continue;
</ins><span class="cx">       var range = doc.sel.ranges[i];
</span><span class="cx">       var collapsed = range.empty();
</span><span class="cx">       if (collapsed || cm.options.showCursorWhenSelecting)
</span><del>-        drawSelectionCursor(cm, range, curFragment);
</del><ins>+        drawSelectionCursor(cm, range.head, curFragment);
</ins><span class="cx">       if (!collapsed)
</span><span class="cx">         drawSelectionRange(cm, range, selFragment);
</span><span class="cx">     }
</span><del>-
-    // Move the hidden textarea near the cursor to prevent scrolling artifacts
-    if (cm.options.moveInputWithCursor) {
-      var headPos = cursorCoords(cm, doc.sel.primary().head, &quot;div&quot;);
-      var wrapOff = display.wrapper.getBoundingClientRect(), lineOff = display.lineDiv.getBoundingClientRect();
-      var top = Math.max(0, Math.min(display.wrapper.clientHeight - 10,
-                                     headPos.top + lineOff.top - wrapOff.top));
-      var left = Math.max(0, Math.min(display.wrapper.clientWidth - 10,
-                                      headPos.left + lineOff.left - wrapOff.left));
-      display.inputDiv.style.top = top + &quot;px&quot;;
-      display.inputDiv.style.left = left + &quot;px&quot;;
-    }
-
-    removeChildrenAndAdd(display.cursorDiv, curFragment);
-    removeChildrenAndAdd(display.selectionDiv, selFragment);
</del><ins>+    return result;
</ins><span class="cx">   }
</span><span class="cx"> 
</span><span class="cx">   // Draws a cursor for the given range
</span><del>-  function drawSelectionCursor(cm, range, output) {
-    var pos = cursorCoords(cm, range.head, &quot;div&quot;);
</del><ins>+  function drawSelectionCursor(cm, head, output) {
+    var pos = cursorCoords(cm, head, &quot;div&quot;, null, null, !cm.options.singleCursorHeightPerLine);
</ins><span class="cx"> 
</span><span class="cx">     var cursor = output.appendChild(elt(&quot;div&quot;, &quot;\u00a0&quot;, &quot;CodeMirror-cursor&quot;));
</span><span class="cx">     cursor.style.left = pos.left + &quot;px&quot;;
</span><span class="lines">@@ -1298,7 +2302,8 @@
</span><span class="cx">   function drawSelectionRange(cm, range, output) {
</span><span class="cx">     var display = cm.display, doc = cm.doc;
</span><span class="cx">     var fragment = document.createDocumentFragment();
</span><del>-    var padding = paddingH(cm.display), leftSide = padding.left, rightSide = display.lineSpace.offsetWidth - padding.right;
</del><ins>+    var padding = paddingH(cm.display), leftSide = padding.left;
+    var rightSide = Math.max(display.sizerWidth, displayWidth(cm) - display.sizer.offsetLeft) - padding.right;
</ins><span class="cx"> 
</span><span class="cx">     function add(left, top, width, bottom) {
</span><span class="cx">       if (top &lt; 0) top = 0;
</span><span class="lines">@@ -1379,6 +2384,8 @@
</span><span class="cx">       display.blinker = setInterval(function() {
</span><span class="cx">         display.cursorDiv.style.visibility = (on = !on) ? &quot;&quot; : &quot;hidden&quot;;
</span><span class="cx">       }, cm.options.cursorBlinkRate);
</span><ins>+    else if (cm.options.cursorBlinkRate &lt; 0)
+      display.cursorDiv.style.visibility = &quot;hidden&quot;;
</ins><span class="cx">   }
</span><span class="cx"> 
</span><span class="cx">   // HIGHLIGHT WORKER
</span><span class="lines">@@ -1394,18 +2401,20 @@
</span><span class="cx">     if (doc.frontier &gt;= cm.display.viewTo) return;
</span><span class="cx">     var end = +new Date + cm.options.workTime;
</span><span class="cx">     var state = copyState(doc.mode, getStateBefore(cm, doc.frontier));
</span><ins>+    var changedLines = [];
</ins><span class="cx"> 
</span><del>-    runInOp(cm, function() {
</del><span class="cx">     doc.iter(doc.frontier, Math.min(doc.first + doc.size, cm.display.viewTo + 500), function(line) {
</span><span class="cx">       if (doc.frontier &gt;= cm.display.viewFrom) { // Visible
</span><span class="cx">         var oldStyles = line.styles;
</span><span class="cx">         var highlighted = highlightLine(cm, line, state, true);
</span><span class="cx">         line.styles = highlighted.styles;
</span><del>-        if (highlighted.classes) line.styleClasses = highlighted.classes;
-        else if (line.styleClasses) line.styleClasses = null;
-        var ischange = !oldStyles || oldStyles.length != line.styles.length;
</del><ins>+        var oldCls = line.styleClasses, newCls = highlighted.classes;
+        if (newCls) line.styleClasses = newCls;
+        else if (oldCls) line.styleClasses = null;
+        var ischange = !oldStyles || oldStyles.length != line.styles.length ||
+          oldCls != newCls &amp;&amp; (!oldCls || !newCls || oldCls.bgClass != newCls.bgClass || oldCls.textClass != newCls.textClass);
</ins><span class="cx">         for (var i = 0; !ischange &amp;&amp; i &lt; oldStyles.length; ++i) ischange = oldStyles[i] != line.styles[i];
</span><del>-        if (ischange) regLineChange(cm, doc.frontier, &quot;text&quot;);
</del><ins>+        if (ischange) changedLines.push(doc.frontier);
</ins><span class="cx">         line.stateAfter = copyState(doc.mode, state);
</span><span class="cx">       } else {
</span><span class="cx">         processLine(cm, line.text, state);
</span><span class="lines">@@ -1417,6 +2426,9 @@
</span><span class="cx">         return true;
</span><span class="cx">       }
</span><span class="cx">     });
</span><ins>+    if (changedLines.length) runInOp(cm, function() {
+      for (var i = 0; i &lt; changedLines.length; i++)
+        regLineChange(cm, changedLines[i], &quot;text&quot;);
</ins><span class="cx">     });
</span><span class="cx">   }
</span><span class="cx"> 
</span><span class="lines">@@ -1470,13 +2482,21 @@
</span><span class="cx">     return data;
</span><span class="cx">   }
</span><span class="cx"> 
</span><ins>+  function scrollGap(cm) { return scrollerGap - cm.display.nativeBarWidth; }
+  function displayWidth(cm) {
+    return cm.display.scroller.clientWidth - scrollGap(cm) - cm.display.barWidth;
+  }
+  function displayHeight(cm) {
+    return cm.display.scroller.clientHeight - scrollGap(cm) - cm.display.barHeight;
+  }
+
</ins><span class="cx">   // Ensure the lineView.wrapping.heights array is populated. This is
</span><span class="cx">   // an array of bottom offsets for the lines that make up a drawn
</span><span class="cx">   // line. When lineWrapping is on, there might be more than one
</span><span class="cx">   // height.
</span><span class="cx">   function ensureLineHeights(cm, lineView, rect) {
</span><span class="cx">     var wrapping = cm.options.lineWrapping;
</span><del>-    var curWidth = wrapping &amp;&amp; cm.display.scroller.clientWidth;
</del><ins>+    var curWidth = wrapping &amp;&amp; displayWidth(cm);
</ins><span class="cx">     if (!lineView.measure.heights || wrapping &amp;&amp; lineView.measure.width != curWidth) {
</span><span class="cx">       var heights = lineView.measure.heights = [];
</span><span class="cx">       if (wrapping) {
</span><span class="lines">@@ -1542,10 +2562,12 @@
</span><span class="cx">   function prepareMeasureForLine(cm, line) {
</span><span class="cx">     var lineN = lineNo(line);
</span><span class="cx">     var view = findViewForLine(cm, lineN);
</span><del>-    if (view &amp;&amp; !view.text)
</del><ins>+    if (view &amp;&amp; !view.text) {
</ins><span class="cx">       view = null;
</span><del>-    else if (view &amp;&amp; view.changes)
</del><ins>+    } else if (view &amp;&amp; view.changes) {
</ins><span class="cx">       updateLineForChanges(cm, view, lineN, getDimensions(cm));
</span><ins>+      cm.curOp.forceUpdate = true;
+    }
</ins><span class="cx">     if (!view)
</span><span class="cx">       view = updateExternalMeasurement(cm, line);
</span><span class="cx"> 
</span><span class="lines">@@ -1559,7 +2581,7 @@
</span><span class="cx"> 
</span><span class="cx">   // Given a prepared measurement object, measures the position of an
</span><span class="cx">   // actual character (or fetches it from the cache).
</span><del>-  function measureCharPrepared(cm, prepared, ch, bias) {
</del><ins>+  function measureCharPrepared(cm, prepared, ch, bias, varHeight) {
</ins><span class="cx">     if (prepared.before) ch = -1;
</span><span class="cx">     var key = ch + (bias || &quot;&quot;), found;
</span><span class="cx">     if (prepared.cache.hasOwnProperty(key)) {
</span><span class="lines">@@ -1574,14 +2596,14 @@
</span><span class="cx">       found = measureCharInner(cm, prepared, ch, bias);
</span><span class="cx">       if (!found.bogus) prepared.cache[key] = found;
</span><span class="cx">     }
</span><del>-    return {left: found.left, right: found.right, top: found.top, bottom: found.bottom};
</del><ins>+    return {left: found.left, right: found.right,
+            top: varHeight ? found.rtop : found.top,
+            bottom: varHeight ? found.rbottom : found.bottom};
</ins><span class="cx">   }
</span><span class="cx"> 
</span><span class="cx">   var nullRect = {left: 0, right: 0, top: 0, bottom: 0};
</span><span class="cx"> 
</span><del>-  function measureCharInner(cm, prepared, ch, bias) {
-    var map = prepared.map;
-
</del><ins>+  function nodeAndOffsetInLineMap(map, ch, bias) {
</ins><span class="cx">     var node, start, end, collapse;
</span><span class="cx">     // First, search the line map for the text node corresponding to,
</span><span class="cx">     // or closest to, the target character.
</span><span class="lines">@@ -1615,22 +2637,35 @@
</span><span class="cx">         break;
</span><span class="cx">       }
</span><span class="cx">     }
</span><ins>+    return {node: node, start: start, end: end, collapse: collapse, coverStart: mStart, coverEnd: mEnd};
+  }
</ins><span class="cx"> 
</span><ins>+  function measureCharInner(cm, prepared, ch, bias) {
+    var place = nodeAndOffsetInLineMap(prepared.map, ch, bias);
+    var node = place.node, start = place.start, end = place.end, collapse = place.collapse;
+
</ins><span class="cx">     var rect;
</span><span class="cx">     if (node.nodeType == 3) { // If it is a text node, use a range to retrieve the coordinates.
</span><del>-      while (start &amp;&amp; isExtendingChar(prepared.line.text.charAt(mStart + start))) --start;
-      while (mStart + end &lt; mEnd &amp;&amp; isExtendingChar(prepared.line.text.charAt(mStart + end))) ++end;
-      if (ie_upto8 &amp;&amp; start == 0 &amp;&amp; end == mEnd - mStart) {
-        rect = node.parentNode.getBoundingClientRect();
-      } else if (ie &amp;&amp; cm.options.lineWrapping) {
-        var rects = range(node, start, end).getClientRects();
-        if (rects.length)
-          rect = rects[bias == &quot;right&quot; ? rects.length - 1 : 0];
-        else
-          rect = nullRect;
-      } else {
-        rect = range(node, start, end).getBoundingClientRect() || nullRect;
</del><ins>+      for (var i = 0; i &lt; 4; i++) { // Retry a maximum of 4 times when nonsense rectangles are returned
+        while (start &amp;&amp; isExtendingChar(prepared.line.text.charAt(place.coverStart + start))) --start;
+        while (place.coverStart + end &lt; place.coverEnd &amp;&amp; isExtendingChar(prepared.line.text.charAt(place.coverStart + end))) ++end;
+        if (ie &amp;&amp; ie_version &lt; 9 &amp;&amp; start == 0 &amp;&amp; end == place.coverEnd - place.coverStart) {
+          rect = node.parentNode.getBoundingClientRect();
+        } else if (ie &amp;&amp; cm.options.lineWrapping) {
+          var rects = range(node, start, end).getClientRects();
+          if (rects.length)
+            rect = rects[bias == &quot;right&quot; ? rects.length - 1 : 0];
+          else
+            rect = nullRect;
+        } else {
+          rect = range(node, start, end).getBoundingClientRect() || nullRect;
+        }
+        if (rect.left || rect.right || start == 0) break;
+        end = start;
+        start = start - 1;
+        collapse = &quot;right&quot;;
</ins><span class="cx">       }
</span><ins>+      if (ie &amp;&amp; ie_version &lt; 11) rect = maybeUpdateRectForZooming(cm.display.measure, rect);
</ins><span class="cx">     } else { // If it is a widget, simply get the box for the whole widget.
</span><span class="cx">       if (start &gt; 0) collapse = bias = &quot;right&quot;;
</span><span class="cx">       var rects;
</span><span class="lines">@@ -1639,7 +2674,7 @@
</span><span class="cx">       else
</span><span class="cx">         rect = node.getBoundingClientRect();
</span><span class="cx">     }
</span><del>-    if (ie_upto8 &amp;&amp; !start &amp;&amp; (!rect || !rect.left &amp;&amp; !rect.right)) {
</del><ins>+    if (ie &amp;&amp; ie_version &lt; 9 &amp;&amp; !start &amp;&amp; (!rect || !rect.left &amp;&amp; !rect.right)) {
</ins><span class="cx">       var rSpan = node.parentNode.getClientRects()[0];
</span><span class="cx">       if (rSpan)
</span><span class="cx">         rect = {left: rSpan.left, right: rSpan.left + charWidth(cm.display), top: rSpan.top, bottom: rSpan.bottom};
</span><span class="lines">@@ -1647,18 +2682,33 @@
</span><span class="cx">         rect = nullRect;
</span><span class="cx">     }
</span><span class="cx"> 
</span><del>-    var top, bot = (rect.bottom + rect.top) / 2 - prepared.rect.top;
</del><ins>+    var rtop = rect.top - prepared.rect.top, rbot = rect.bottom - prepared.rect.top;
+    var mid = (rtop + rbot) / 2;
</ins><span class="cx">     var heights = prepared.view.measure.heights;
</span><span class="cx">     for (var i = 0; i &lt; heights.length - 1; i++)
</span><del>-      if (bot &lt; heights[i]) break;
-    top = i ? heights[i - 1] : 0; bot = heights[i];
</del><ins>+      if (mid &lt; heights[i]) break;
+    var top = i ? heights[i - 1] : 0, bot = heights[i];
</ins><span class="cx">     var result = {left: (collapse == &quot;right&quot; ? rect.right : rect.left) - prepared.rect.left,
</span><span class="cx">                   right: (collapse == &quot;left&quot; ? rect.left : rect.right) - prepared.rect.left,
</span><span class="cx">                   top: top, bottom: bot};
</span><span class="cx">     if (!rect.left &amp;&amp; !rect.right) result.bogus = true;
</span><ins>+    if (!cm.options.singleCursorHeightPerLine) { result.rtop = rtop; result.rbottom = rbot; }
+
</ins><span class="cx">     return result;
</span><span class="cx">   }
</span><span class="cx"> 
</span><ins>+  // Work around problem with bounding client rects on ranges being
+  // returned incorrectly when zoomed on IE10 and below.
+  function maybeUpdateRectForZooming(measure, rect) {
+    if (!window.screen || screen.logicalXDPI == null ||
+        screen.logicalXDPI == screen.deviceXDPI || !hasBadZoomedRects(measure))
+      return rect;
+    var scaleX = screen.logicalXDPI / screen.deviceXDPI;
+    var scaleY = screen.logicalYDPI / screen.deviceYDPI;
+    return {left: rect.left * scaleX, right: rect.right * scaleX,
+            top: rect.top * scaleY, bottom: rect.bottom * scaleY};
+  }
+
</ins><span class="cx">   function clearLineMeasurementCacheFor(lineView) {
</span><span class="cx">     if (lineView.measure) {
</span><span class="cx">       lineView.measure.cache = {};
</span><span class="lines">@@ -1687,7 +2737,8 @@
</span><span class="cx"> 
</span><span class="cx">   // Converts a {top, bottom, left, right} box from line-local
</span><span class="cx">   // coordinates into another coordinate system. Context may be one of
</span><del>-  // &quot;line&quot;, &quot;div&quot; (display.lineDiv), &quot;local&quot;/null (editor), or &quot;page&quot;.
</del><ins>+  // &quot;line&quot;, &quot;div&quot; (display.lineDiv), &quot;local&quot;/null (editor), &quot;window&quot;,
+  // or &quot;page&quot;.
</ins><span class="cx">   function intoCoordSystem(cm, lineObj, rect, context) {
</span><span class="cx">     if (lineObj.widgets) for (var i = 0; i &lt; lineObj.widgets.length; ++i) if (lineObj.widgets[i].above) {
</span><span class="cx">       var size = widgetHeight(lineObj.widgets[i]);
</span><span class="lines">@@ -1735,11 +2786,11 @@
</span><span class="cx">   // Returns a box for a given cursor position, which may have an
</span><span class="cx">   // 'other' property containing the position of the secondary cursor
</span><span class="cx">   // on a bidi boundary.
</span><del>-  function cursorCoords(cm, pos, context, lineObj, preparedMeasure) {
</del><ins>+  function cursorCoords(cm, pos, context, lineObj, preparedMeasure, varHeight) {
</ins><span class="cx">     lineObj = lineObj || getLine(cm.doc, pos.line);
</span><span class="cx">     if (!preparedMeasure) preparedMeasure = prepareMeasureForLine(cm, lineObj);
</span><span class="cx">     function get(ch, right) {
</span><del>-      var m = measureCharPrepared(cm, preparedMeasure, ch, right ? &quot;right&quot; : &quot;left&quot;);
</del><ins>+      var m = measureCharPrepared(cm, preparedMeasure, ch, right ? &quot;right&quot; : &quot;left&quot;, varHeight);
</ins><span class="cx">       if (right) m.left = m.right; else m.right = m.left;
</span><span class="cx">       return intoCoordSystem(cm, lineObj, m, context);
</span><span class="cx">     }
</span><span class="lines">@@ -1891,10 +2942,13 @@
</span><span class="cx">   // error-prone). Instead, display updates are batched and then all
</span><span class="cx">   // combined and executed at once.
</span><span class="cx"> 
</span><ins>+  var operationGroup = null;
+
</ins><span class="cx">   var nextOpId = 0;
</span><span class="cx">   // Start a new operation.
</span><span class="cx">   function startOperation(cm) {
</span><span class="cx">     cm.curOp = {
</span><ins>+      cm: cm,
</ins><span class="cx">       viewChanged: false,      // Flag that indicates that lines might need to be redrawn
</span><span class="cx">       startHeight: cm.doc.height, // Used to detect need to update scrollbar
</span><span class="cx">       forceUpdate: false,      // Used to force a redraw
</span><span class="lines">@@ -1902,60 +2956,160 @@
</span><span class="cx">       typing: false,           // Whether this reset should be careful to leave existing text (for compositing)
</span><span class="cx">       changeObjs: null,        // Accumulated changes, for firing change events
</span><span class="cx">       cursorActivityHandlers: null, // Set of handlers to fire cursorActivity on
</span><ins>+      cursorActivityCalled: 0, // Tracks which cursorActivity handlers have been called already
</ins><span class="cx">       selectionChanged: false, // Whether the selection needs to be redrawn
</span><span class="cx">       updateMaxLine: false,    // Set when the widest line needs to be determined anew
</span><span class="cx">       scrollLeft: null, scrollTop: null, // Intermediate scroll position, not pushed to DOM yet
</span><span class="cx">       scrollToPos: null,       // Used to scroll to a specific position
</span><ins>+      focus: false,
</ins><span class="cx">       id: ++nextOpId           // Unique ID
</span><span class="cx">     };
</span><del>-    if (!delayedCallbackDepth++) delayedCallbacks = [];
</del><ins>+    if (operationGroup) {
+      operationGroup.ops.push(cm.curOp);
+    } else {
+      cm.curOp.ownsGroup = operationGroup = {
+        ops: [cm.curOp],
+        delayedCallbacks: []
+      };
+    }
</ins><span class="cx">   }
</span><span class="cx"> 
</span><ins>+  function fireCallbacksForOps(group) {
+    // Calls delayed callbacks and cursorActivity handlers until no
+    // new ones appear
+    var callbacks = group.delayedCallbacks, i = 0;
+    do {
+      for (; i &lt; callbacks.length; i++)
+        callbacks[i].call(null);
+      for (var j = 0; j &lt; group.ops.length; j++) {
+        var op = group.ops[j];
+        if (op.cursorActivityHandlers)
+          while (op.cursorActivityCalled &lt; op.cursorActivityHandlers.length)
+            op.cursorActivityHandlers[op.cursorActivityCalled++].call(null, op.cm);
+      }
+    } while (i &lt; callbacks.length);
+  }
+
</ins><span class="cx">   // Finish an operation, updating the display and signalling delayed events
</span><span class="cx">   function endOperation(cm) {
</span><del>-    var op = cm.curOp, doc = cm.doc, display = cm.display;
-    cm.curOp = null;
</del><ins>+    var op = cm.curOp, group = op.ownsGroup;
+    if (!group) return;
</ins><span class="cx"> 
</span><ins>+    try { fireCallbacksForOps(group); }
+    finally {
+      operationGroup = null;
+      for (var i = 0; i &lt; group.ops.length; i++)
+        group.ops[i].cm.curOp = null;
+      endOperations(group);
+    }
+  }
+
+  // The DOM updates done when an operation finishes are batched so
+  // that the minimum number of relayouts are required.
+  function endOperations(group) {
+    var ops = group.ops;
+    for (var i = 0; i &lt; ops.length; i++) // Read DOM
+      endOperation_R1(ops[i]);
+    for (var i = 0; i &lt; ops.length; i++) // Write DOM (maybe)
+      endOperation_W1(ops[i]);
+    for (var i = 0; i &lt; ops.length; i++) // Read DOM
+      endOperation_R2(ops[i]);
+    for (var i = 0; i &lt; ops.length; i++) // Write DOM (maybe)
+      endOperation_W2(ops[i]);
+    for (var i = 0; i &lt; ops.length; i++) // Read DOM
+      endOperation_finish(ops[i]);
+  }
+
+  function endOperation_R1(op) {
+    var cm = op.cm, display = cm.display;
+    maybeClipScrollbars(cm);
</ins><span class="cx">     if (op.updateMaxLine) findMaxLine(cm);
</span><span class="cx"> 
</span><del>-    // If it looks like an update might be needed, call updateDisplay
-    if (op.viewChanged || op.forceUpdate || op.scrollTop != null ||
-        op.scrollToPos &amp;&amp; (op.scrollToPos.from.line &lt; display.viewFrom ||
-                           op.scrollToPos.to.line &gt;= display.viewTo) ||
-        display.maxLineChanged &amp;&amp; cm.options.lineWrapping) {
-      var updated = updateDisplay(cm, {top: op.scrollTop, ensure: op.scrollToPos}, op.forceUpdate);
-      if (cm.display.scroller.offsetHeight) cm.doc.scrollTop = cm.display.scroller.scrollTop;
</del><ins>+    op.mustUpdate = op.viewChanged || op.forceUpdate || op.scrollTop != null ||
+      op.scrollToPos &amp;&amp; (op.scrollToPos.from.line &lt; display.viewFrom ||
+                         op.scrollToPos.to.line &gt;= display.viewTo) ||
+      display.maxLineChanged &amp;&amp; cm.options.lineWrapping;
+    op.update = op.mustUpdate &amp;&amp;
+      new DisplayUpdate(cm, op.mustUpdate &amp;&amp; {top: op.scrollTop, ensure: op.scrollToPos}, op.forceUpdate);
+  }
+
+  function endOperation_W1(op) {
+    op.updatedDisplay = op.mustUpdate &amp;&amp; updateDisplayIfNeeded(op.cm, op.update);
+  }
+
+  function endOperation_R2(op) {
+    var cm = op.cm, display = cm.display;
+    if (op.updatedDisplay) updateHeightsInViewport(cm);
+
+    op.barMeasure = measureForScrollbars(cm);
+
+    // If the max line changed since it was last measured, measure it,
+    // and ensure the document's width matches it.
+    // updateDisplay_W2 will use these properties to do the actual resizing
+    if (display.maxLineChanged &amp;&amp; !cm.options.lineWrapping) {
+      op.adjustWidthTo = measureChar(cm, display.maxLine, display.maxLine.text.length).left + 3;
+      cm.display.sizerWidth = op.adjustWidthTo;
+      op.barMeasure.scrollWidth =
+        Math.max(display.scroller.clientWidth, display.sizer.offsetLeft + op.adjustWidthTo + scrollGap(cm) + cm.display.barWidth);
+      op.maxScrollLeft = Math.max(0, display.sizer.offsetLeft + op.adjustWidthTo - displayWidth(cm));
</ins><span class="cx">     }
</span><del>-    // If no update was run, but the selection changed, redraw that.
-    if (!updated &amp;&amp; op.selectionChanged) updateSelection(cm);
-    if (!updated &amp;&amp; op.startHeight != cm.doc.height) updateScrollbars(cm);
</del><span class="cx"> 
</span><ins>+    if (op.updatedDisplay || op.selectionChanged)
+      op.preparedSelection = display.input.prepareSelection();
+  }
+
+  function endOperation_W2(op) {
+    var cm = op.cm;
+
+    if (op.adjustWidthTo != null) {
+      cm.display.sizer.style.minWidth = op.adjustWidthTo + &quot;px&quot;;
+      if (op.maxScrollLeft &lt; cm.doc.scrollLeft)
+        setScrollLeft(cm, Math.min(cm.display.scroller.scrollLeft, op.maxScrollLeft), true);
+      cm.display.maxLineChanged = false;
+    }
+
+    if (op.preparedSelection)
+      cm.display.input.showSelection(op.preparedSelection);
+    if (op.updatedDisplay)
+      setDocumentHeight(cm, op.barMeasure);
+    if (op.updatedDisplay || op.startHeight != cm.doc.height)
+      updateScrollbars(cm, op.barMeasure);
+
+    if (op.selectionChanged) restartBlink(cm);
+
+    if (cm.state.focused &amp;&amp; op.updateInput)
+      cm.display.input.reset(op.typing);
+    if (op.focus &amp;&amp; op.focus == activeElt()) ensureFocus(op.cm);
+  }
+
+  function endOperation_finish(op) {
+    var cm = op.cm, display = cm.display, doc = cm.doc;
+
+    if (op.updatedDisplay) postUpdateDisplay(cm, op.update);
+
</ins><span class="cx">     // Abort mouse wheel delta measurement, when scrolling explicitly
</span><span class="cx">     if (display.wheelStartX != null &amp;&amp; (op.scrollTop != null || op.scrollLeft != null || op.scrollToPos))
</span><span class="cx">       display.wheelStartX = display.wheelStartY = null;
</span><span class="cx"> 
</span><span class="cx">     // Propagate the scroll position to the actual DOM scroller
</span><del>-    if (op.scrollTop != null &amp;&amp; display.scroller.scrollTop != op.scrollTop) {
-      var top = Math.max(0, Math.min(display.scroller.scrollHeight - display.scroller.clientHeight, op.scrollTop));
-      display.scroller.scrollTop = display.scrollbarV.scrollTop = doc.scrollTop = top;
</del><ins>+    if (op.scrollTop != null &amp;&amp; (display.scroller.scrollTop != op.scrollTop || op.forceScroll)) {
+      doc.scrollTop = Math.max(0, Math.min(display.scroller.scrollHeight - display.scroller.clientHeight, op.scrollTop));
+      display.scrollbars.setScrollTop(doc.scrollTop);
+      display.scroller.scrollTop = doc.scrollTop;
</ins><span class="cx">     }
</span><del>-    if (op.scrollLeft != null &amp;&amp; display.scroller.scrollLeft != op.scrollLeft) {
-      var left = Math.max(0, Math.min(display.scroller.scrollWidth - display.scroller.clientWidth, op.scrollLeft));
-      display.scroller.scrollLeft = display.scrollbarH.scrollLeft = doc.scrollLeft = left;
</del><ins>+    if (op.scrollLeft != null &amp;&amp; (display.scroller.scrollLeft != op.scrollLeft || op.forceScroll)) {
+      doc.scrollLeft = Math.max(0, Math.min(display.scroller.scrollWidth - displayWidth(cm), op.scrollLeft));
+      display.scrollbars.setScrollLeft(doc.scrollLeft);
+      display.scroller.scrollLeft = doc.scrollLeft;
</ins><span class="cx">       alignHorizontally(cm);
</span><span class="cx">     }
</span><span class="cx">     // If we need to scroll a specific position into view, do so.
</span><span class="cx">     if (op.scrollToPos) {
</span><del>-      var coords = scrollPosIntoView(cm, clipPos(cm.doc, op.scrollToPos.from),
-                                     clipPos(cm.doc, op.scrollToPos.to), op.scrollToPos.margin);
</del><ins>+      var coords = scrollPosIntoView(cm, clipPos(doc, op.scrollToPos.from),
+                                     clipPos(doc, op.scrollToPos.to), op.scrollToPos.margin);
</ins><span class="cx">       if (op.scrollToPos.isCursor &amp;&amp; cm.state.focused) maybeScrollWindow(cm, coords);
</span><span class="cx">     }
</span><span class="cx"> 
</span><del>-    if (op.selectionChanged) restartBlink(cm);
-
-    if (cm.state.focused &amp;&amp; op.updateInput)
-      resetInput(cm, op.typing);
-
</del><span class="cx">     // Fire events for markers that are hidden/unidden by editing or
</span><span class="cx">     // undoing
</span><span class="cx">     var hidden = op.maybeHiddenMarkers, unhidden = op.maybeUnhiddenMarkers;
</span><span class="lines">@@ -1964,18 +3118,14 @@
</span><span class="cx">     if (unhidden) for (var i = 0; i &lt; unhidden.length; ++i)
</span><span class="cx">       if (unhidden[i].lines.length) signal(unhidden[i], &quot;unhide&quot;);
</span><span class="cx"> 
</span><del>-    var delayed;
-    if (!--delayedCallbackDepth) {
-      delayed = delayedCallbacks;
-      delayedCallbacks = null;
-    }
</del><ins>+    if (display.wrapper.offsetHeight)
+      doc.scrollTop = cm.display.scroller.scrollTop;
+
</ins><span class="cx">     // Fire change events, and delayed event handlers
</span><span class="cx">     if (op.changeObjs)
</span><span class="cx">       signal(cm, &quot;changes&quot;, cm, op.changeObjs);
</span><del>-    if (delayed) for (var i = 0; i &lt; delayed.length; ++i) delayed[i]();
-    if (op.cursorActivityHandlers)
-      for (var i = 0; i &lt; op.cursorActivityHandlers.length; i++)
-        op.cursorActivityHandlers[i](cm);
</del><ins>+    if (op.update)
+      op.update.finish();
</ins><span class="cx">   }
</span><span class="cx"> 
</span><span class="cx">   // Run the given function in an operation
</span><span class="lines">@@ -2201,152 +3351,6 @@
</span><span class="cx">     return dirty;
</span><span class="cx">   }
</span><span class="cx"> 
</span><del>-  // INPUT HANDLING
-
-  // Poll for input changes, using the normal rate of polling. This
-  // runs as long as the editor is focused.
-  function slowPoll(cm) {
-    if (cm.display.pollingFast) return;
-    cm.display.poll.set(cm.options.pollInterval, function() {
-      readInput(cm);
-      if (cm.state.focused) slowPoll(cm);
-    });
-  }
-
-  // When an event has just come in that is likely to add or change
-  // something in the input textarea, we poll faster, to ensure that
-  // the change appears on the screen quickly.
-  function fastPoll(cm) {
-    var missed = false;
-    cm.display.pollingFast = true;
-    function p() {
-      var changed = readInput(cm);
-      if (!changed &amp;&amp; !missed) {missed = true; cm.display.poll.set(60, p);}
-      else {cm.display.pollingFast = false; slowPoll(cm);}
-    }
-    cm.display.poll.set(20, p);
-  }
-
-  // Read input from the textarea, and update the document to match.
-  // When something is selected, it is present in the textarea, and
-  // selected (unless it is huge, in which case a placeholder is
-  // used). When nothing is selected, the cursor sits after previously
-  // seen text (can be empty), which is stored in prevInput (we must
-  // not reset the textarea when typing, because that breaks IME).
-  function readInput(cm) {
-    var input = cm.display.input, prevInput = cm.display.prevInput, doc = cm.doc;
-    // Since this is called a *lot*, try to bail out as cheaply as
-    // possible when it is clear that nothing happened. hasSelection
-    // will be the case when there is a lot of text in the textarea,
-    // in which case reading its value would be expensive.
-    if (!cm.state.focused || (hasSelection(input) &amp;&amp; !prevInput) || isReadOnly(cm) || cm.options.disableInput)
-      return false;
-    // See paste handler for more on the fakedLastChar kludge
-    if (cm.state.pasteIncoming &amp;&amp; cm.state.fakedLastChar) {
-      input.value = input.value.substring(0, input.value.length - 1);
-      cm.state.fakedLastChar = false;
-    }
-    var text = input.value;
-    // If nothing changed, bail.
-    if (text == prevInput &amp;&amp; !cm.somethingSelected()) return false;
-    // Work around nonsensical selection resetting in IE9/10
-    if (ie &amp;&amp; !ie_upto8 &amp;&amp; cm.display.inputHasSelection === text) {
-      resetInput(cm);
-      return false;
-    }
-
-    var withOp = !cm.curOp;
-    if (withOp) startOperation(cm);
-    cm.display.shift = false;
-
-    if (text.charCodeAt(0) == 0x200b &amp;&amp; doc.sel == cm.display.selForContextMenu &amp;&amp; !prevInput)
-      prevInput = &quot;\u200b&quot;;
-    // Find the part of the input that is actually new
-    var same = 0, l = Math.min(prevInput.length, text.length);
-    while (same &lt; l &amp;&amp; prevInput.charCodeAt(same) == text.charCodeAt(same)) ++same;
-    var inserted = text.slice(same), textLines = splitLines(inserted);
-
-    // When pasing N lines into N selections, insert one line per selection
-    var multiPaste = cm.state.pasteIncoming &amp;&amp; textLines.length &gt; 1 &amp;&amp; doc.sel.ranges.length == textLines.length;
-
-    // Normal behavior is to insert the new text into every selection
-    for (var i = doc.sel.ranges.length - 1; i &gt;= 0; i--) {
-      var range = doc.sel.ranges[i];
-      var from = range.from(), to = range.to();
-      // Handle deletion
-      if (same &lt; prevInput.length)
-        from = Pos(from.line, from.ch - (prevInput.length - same));
-      // Handle overwrite
-      else if (cm.state.overwrite &amp;&amp; range.empty() &amp;&amp; !cm.state.pasteIncoming)
-        to = Pos(to.line, Math.min(getLine(doc, to.line).text.length, to.ch + lst(textLines).length));
-      var updateInput = cm.curOp.updateInput;
-      var changeEvent = {from: from, to: to, text: multiPaste ? [textLines[i]] : textLines,
-                         origin: cm.state.pasteIncoming ? &quot;paste&quot; : cm.state.cutIncoming ? &quot;cut&quot; : &quot;+input&quot;};
-      makeChange(cm.doc, changeEvent);
-      signalLater(cm, &quot;inputRead&quot;, cm, changeEvent);
-      // When an 'electric' character is inserted, immediately trigger a reindent
-      if (inserted &amp;&amp; !cm.state.pasteIncoming &amp;&amp; cm.options.electricChars &amp;&amp;
-          cm.options.smartIndent &amp;&amp; range.head.ch &lt; 100 &amp;&amp;
-          (!i || doc.sel.ranges[i - 1].head.line != range.head.line)) {
-        var mode = cm.getModeAt(range.head);
-        if (mode.electricChars) {
-          for (var j = 0; j &lt; mode.electricChars.length; j++)
-            if (inserted.indexOf(mode.electricChars.charAt(j)) &gt; -1) {
-              indentLine(cm, range.head.line, &quot;smart&quot;);
-              break;
-            }
-        } else if (mode.electricInput) {
-          var end = changeEnd(changeEvent);
-          if (mode.electricInput.test(getLine(doc, end.line).text.slice(0, end.ch)))
-            indentLine(cm, range.head.line, &quot;smart&quot;);
-        }
-      }
-    }
-    ensureCursorVisible(cm);
-    cm.curOp.updateInput = updateInput;
-    cm.curOp.typing = true;
-
-    // Don't leave long text in the textarea, since it makes further polling slow
-    if (text.length &gt; 1000 || text.indexOf(&quot;\n&quot;) &gt; -1) input.value = cm.display.prevInput = &quot;&quot;;
-    else cm.display.prevInput = text;
-    if (withOp) endOperation(cm);
-    cm.state.pasteIncoming = cm.state.cutIncoming = false;
-    return true;
-  }
-
-  // Reset the input to correspond to the selection (or to be empty,
-  // when not typing and nothing is selected)
-  function resetInput(cm, typing) {
-    var minimal, selected, doc = cm.doc;
-    if (cm.somethingSelected()) {
-      cm.display.prevInput = &quot;&quot;;
-      var range = doc.sel.primary();
-      minimal = hasCopyEvent &amp;&amp;
-        (range.to().line - range.from().line &gt; 100 || (selected = cm.getSelection()).length &gt; 1000);
-      var content = minimal ? &quot;-&quot; : selected || cm.getSelection();
-      cm.display.input.value = content;
-      if (cm.state.focused) selectInput(cm.display.input);
-      if (ie &amp;&amp; !ie_upto8) cm.display.inputHasSelection = content;
-    } else if (!typing) {
-      cm.display.prevInput = cm.display.input.value = &quot;&quot;;
-      if (ie &amp;&amp; !ie_upto8) cm.display.inputHasSelection = null;
-    }
-    cm.display.inaccurateSelection = minimal;
-  }
-
-  function focusInput(cm) {
-    if (cm.options.readOnly != &quot;nocursor&quot; &amp;&amp; (!mobile || activeElt() != cm.display.input))
-      cm.display.input.focus();
-  }
-
-  function ensureFocus(cm) {
-    if (!cm.state.focused) { focusInput(cm); onFocus(cm); }
-  }
-
-  function isReadOnly(cm) {
-    return cm.options.readOnly || cm.doc.cantEdit;
-  }
-
</del><span class="cx">   // EVENT HANDLERS
</span><span class="cx"> 
</span><span class="cx">   // Attach the necessary event handlers when initializing the editor
</span><span class="lines">@@ -2354,26 +3358,75 @@
</span><span class="cx">     var d = cm.display;
</span><span class="cx">     on(d.scroller, &quot;mousedown&quot;, operation(cm, onMouseDown));
</span><span class="cx">     // Older IE's will not fire a second mousedown for a double click
</span><del>-    if (ie_upto10)
</del><ins>+    if (ie &amp;&amp; ie_version &lt; 11)
</ins><span class="cx">       on(d.scroller, &quot;dblclick&quot;, operation(cm, function(e) {
</span><span class="cx">         if (signalDOMEvent(cm, e)) return;
</span><span class="cx">         var pos = posFromMouse(cm, e);
</span><span class="cx">         if (!pos || clickInGutter(cm, e) || eventInWidget(cm.display, e)) return;
</span><span class="cx">         e_preventDefault(e);
</span><del>-        var word = findWordAt(cm, pos);
</del><ins>+        var word = cm.findWordAt(pos);
</ins><span class="cx">         extendSelection(cm.doc, word.anchor, word.head);
</span><span class="cx">       }));
</span><span class="cx">     else
</span><span class="cx">       on(d.scroller, &quot;dblclick&quot;, function(e) { signalDOMEvent(cm, e) || e_preventDefault(e); });
</span><del>-    // Prevent normal selection in the editor (we handle our own)
-    on(d.lineSpace, &quot;selectstart&quot;, function(e) {
-      if (!eventInWidget(d, e)) e_preventDefault(e);
-    });
</del><span class="cx">     // Some browsers fire contextmenu *after* opening the menu, at
</span><span class="cx">     // which point we can't mess with it anymore. Context menu is
</span><span class="cx">     // handled in onMouseDown for these browsers.
</span><span class="cx">     if (!captureRightClick) on(d.scroller, &quot;contextmenu&quot;, function(e) {onContextMenu(cm, e);});
</span><span class="cx"> 
</span><ins>+    // Used to suppress mouse event handling when a touch happens
+    var touchFinished, prevTouch = {end: 0};
+    function finishTouch() {
+      if (d.activeTouch) {
+        touchFinished = setTimeout(function() {d.activeTouch = null;}, 1000);
+        prevTouch = d.activeTouch;
+        prevTouch.end = +new Date;
+      }
+    };
+    function isMouseLikeTouchEvent(e) {
+      if (e.touches.length != 1) return false;
+      var touch = e.touches[0];
+      return touch.radiusX &lt;= 1 &amp;&amp; touch.radiusY &lt;= 1;
+    }
+    function farAway(touch, other) {
+      if (other.left == null) return true;
+      var dx = other.left - touch.left, dy = other.top - touch.top;
+      return dx * dx + dy * dy &gt; 20 * 20;
+    }
+    on(d.scroller, &quot;touchstart&quot;, function(e) {
+      if (!isMouseLikeTouchEvent(e)) {
+        clearTimeout(touchFinished);
+        var now = +new Date;
+        d.activeTouch = {start: now, moved: false,
+                         prev: now - prevTouch.end &lt;= 300 ? prevTouch : null};
+        if (e.touches.length == 1) {
+          d.activeTouch.left = e.touches[0].pageX;
+          d.activeTouch.top = e.touches[0].pageY;
+        }
+      }
+    });
+    on(d.scroller, &quot;touchmove&quot;, function() {
+      if (d.activeTouch) d.activeTouch.moved = true;
+    });
+    on(d.scroller, &quot;touchend&quot;, function(e) {
+      var touch = d.activeTouch;
+      if (touch &amp;&amp; !eventInWidget(d, e) &amp;&amp; touch.left != null &amp;&amp;
+          !touch.moved &amp;&amp; new Date - touch.start &lt; 300) {
+        var pos = cm.coordsChar(d.activeTouch, &quot;page&quot;), range;
+        if (!touch.prev || farAway(touch, touch.prev)) // Single tap
+          range = new Range(pos, pos);
+        else if (!touch.prev.prev || farAway(touch, touch.prev.prev)) // Double tap
+          range = cm.findWordAt(pos);
+        else // Triple tap
+          range = new Range(Pos(pos.line, 0), clipPos(cm.doc, Pos(pos.line + 1, 0)));
+        cm.setSelection(range.anchor, range.head);
+        cm.focus();
+        e_preventDefault(e);
+      }
+      finishTouch();
+    });
+    on(d.scroller, &quot;touchcancel&quot;, finishTouch);
+
</ins><span class="cx">     // Sync scrolling between fake scrollbars and real scrollable
</span><span class="cx">     // area, ensure viewport is updated when scrolling.
</span><span class="cx">     on(d.scroller, &quot;scroll&quot;, function() {
</span><span class="lines">@@ -2383,105 +3436,51 @@
</span><span class="cx">         signal(cm, &quot;scroll&quot;, cm);
</span><span class="cx">       }
</span><span class="cx">     });
</span><del>-    on(d.scrollbarV, &quot;scroll&quot;, function() {
-      if (d.scroller.clientHeight) setScrollTop(cm, d.scrollbarV.scrollTop);
-    });
-    on(d.scrollbarH, &quot;scroll&quot;, function() {
-      if (d.scroller.clientHeight) setScrollLeft(cm, d.scrollbarH.scrollLeft);
-    });
</del><span class="cx"> 
</span><span class="cx">     // Listen to wheel events in order to try and update the viewport on time.
</span><span class="cx">     on(d.scroller, &quot;mousewheel&quot;, function(e){onScrollWheel(cm, e);});
</span><span class="cx">     on(d.scroller, &quot;DOMMouseScroll&quot;, function(e){onScrollWheel(cm, e);});
</span><span class="cx"> 
</span><del>-    // Prevent clicks in the scrollbars from killing focus
-    function reFocus() { if (cm.state.focused) setTimeout(bind(focusInput, cm), 0); }
-    on(d.scrollbarH, &quot;mousedown&quot;, reFocus);
-    on(d.scrollbarV, &quot;mousedown&quot;, reFocus);
</del><span class="cx">     // Prevent wrapper from ever scrolling
</span><span class="cx">     on(d.wrapper, &quot;scroll&quot;, function() { d.wrapper.scrollTop = d.wrapper.scrollLeft = 0; });
</span><span class="cx"> 
</span><del>-    on(d.input, &quot;keyup&quot;, operation(cm, onKeyUp));
-    on(d.input, &quot;input&quot;, function() {
-      if (ie &amp;&amp; !ie_upto8 &amp;&amp; cm.display.inputHasSelection) cm.display.inputHasSelection = null;
-      fastPoll(cm);
-    });
-    on(d.input, &quot;keydown&quot;, operation(cm, onKeyDown));
-    on(d.input, &quot;keypress&quot;, operation(cm, onKeyPress));
-    on(d.input, &quot;focus&quot;, bind(onFocus, cm));
-    on(d.input, &quot;blur&quot;, bind(onBlur, cm));
</del><ins>+    d.dragFunctions = {
+      enter: function(e) {if (!signalDOMEvent(cm, e)) e_stop(e);},
+      over: function(e) {if (!signalDOMEvent(cm, e)) { onDragOver(cm, e); e_stop(e); }},
+      start: function(e){onDragStart(cm, e);},
+      drop: operation(cm, onDrop),
+      leave: function() {clearDragCursor(cm);}
+    };
</ins><span class="cx"> 
</span><del>-    function drag_(e) {
-      if (!signalDOMEvent(cm, e)) e_stop(e);
-    }
-    if (cm.options.dragDrop) {
-      on(d.scroller, &quot;dragstart&quot;, function(e){onDragStart(cm, e);});
-      on(d.scroller, &quot;dragenter&quot;, drag_);
-      on(d.scroller, &quot;dragover&quot;, drag_);
-      on(d.scroller, &quot;drop&quot;, operation(cm, onDrop));
-    }
-    on(d.scroller, &quot;paste&quot;, function(e) {
-      if (eventInWidget(d, e)) return;
-      cm.state.pasteIncoming = true;
-      focusInput(cm);
-      fastPoll(cm);
-    });
-    on(d.input, &quot;paste&quot;, function() {
-      // Workaround for webkit bug https://bugs.webkit.org/show_bug.cgi?id=90206
-      // Add a char to the end of textarea before paste occur so that
-      // selection doesn't span to the end of textarea.
-      if (webkit &amp;&amp; !cm.state.fakedLastChar &amp;&amp; !(new Date - cm.state.lastMiddleDown &lt; 200)) {
-        var start = d.input.selectionStart, end = d.input.selectionEnd;
-        d.input.value += &quot;$&quot;;
-        d.input.selectionStart = start;
-        d.input.selectionEnd = end;
-        cm.state.fakedLastChar = true;
-      }
-      cm.state.pasteIncoming = true;
-      fastPoll(cm);
-    });
</del><ins>+    var inp = d.input.getField();
+    on(inp, &quot;keyup&quot;, function(e) { onKeyUp.call(cm, e); });
+    on(inp, &quot;keydown&quot;, operation(cm, onKeyDown));
+    on(inp, &quot;keypress&quot;, operation(cm, onKeyPress));
+    on(inp, &quot;focus&quot;, bind(onFocus, cm));
+    on(inp, &quot;blur&quot;, bind(onBlur, cm));
+  }
</ins><span class="cx"> 
</span><del>-    function prepareCopyCut(e) {
-      if (cm.somethingSelected()) {
-        if (d.inaccurateSelection) {
-          d.prevInput = &quot;&quot;;
-          d.inaccurateSelection = false;
-          d.input.value = cm.getSelection();
-          selectInput(d.input);
-        }
-      } else {
-        var text = &quot;&quot;, ranges = [];
-        for (var i = 0; i &lt; cm.doc.sel.ranges.length; i++) {
-          var line = cm.doc.sel.ranges[i].head.line;
-          var lineRange = {anchor: Pos(line, 0), head: Pos(line + 1, 0)};
-          ranges.push(lineRange);
-          text += cm.getRange(lineRange.anchor, lineRange.head);
-        }
-        if (e.type == &quot;cut&quot;) {
-          cm.setSelections(ranges, null, sel_dontScroll);
-        } else {
-          d.prevInput = &quot;&quot;;
-          d.input.value = text;
-          selectInput(d.input);
-        }
-      }
-      if (e.type == &quot;cut&quot;) cm.state.cutIncoming = true;
</del><ins>+  function dragDropChanged(cm, value, old) {
+    var wasOn = old &amp;&amp; old != CodeMirror.Init;
+    if (!value != !wasOn) {
+      var funcs = cm.display.dragFunctions;
+      var toggle = value ? on : off;
+      toggle(cm.display.scroller, &quot;dragstart&quot;, funcs.start);
+      toggle(cm.display.scroller, &quot;dragenter&quot;, funcs.enter);
+      toggle(cm.display.scroller, &quot;dragover&quot;, funcs.over);
+      toggle(cm.display.scroller, &quot;dragleave&quot;, funcs.leave);
+      toggle(cm.display.scroller, &quot;drop&quot;, funcs.drop);
</ins><span class="cx">     }
</span><del>-    on(d.input, &quot;cut&quot;, prepareCopyCut);
-    on(d.input, &quot;copy&quot;, prepareCopyCut);
-
-    // Needed to handle Tab key in KHTML
-    if (khtml) on(d.sizer, &quot;mouseup&quot;, function() {
-      if (activeElt() == d.input) d.input.blur();
-      focusInput(cm);
-    });
</del><span class="cx">   }
</span><span class="cx"> 
</span><span class="cx">   // Called when the window resizes
</span><span class="cx">   function onResize(cm) {
</span><ins>+    var d = cm.display;
+    if (d.lastWrapHeight == d.wrapper.clientHeight &amp;&amp; d.lastWrapWidth == d.wrapper.clientWidth)
+      return;
</ins><span class="cx">     // Might be a text scaling operation, clear size caches.
</span><del>-    var d = cm.display;
</del><span class="cx">     d.cachedCharWidth = d.cachedTextHeight = d.cachedPaddingH = null;
</span><ins>+    d.scrollbarsClipped = false;
</ins><span class="cx">     cm.setSize();
</span><span class="cx">   }
</span><span class="cx"> 
</span><span class="lines">@@ -2490,7 +3489,9 @@
</span><span class="cx">   // Return true when the given mouse event happened in a widget
</span><span class="cx">   function eventInWidget(display, e) {
</span><span class="cx">     for (var n = e_target(e); n != display.wrapper; n = n.parentNode) {
</span><del>-      if (!n || n.ignoreEvents || n.parentNode == display.sizer &amp;&amp; n != display.mover) return true;
</del><ins>+      if (!n || (n.nodeType == 1 &amp;&amp; n.getAttribute(&quot;cm-ignore-events&quot;) == &quot;true&quot;) ||
+          (n.parentNode == display.sizer &amp;&amp; n != display.mover))
+        return true;
</ins><span class="cx">     }
</span><span class="cx">   }
</span><span class="cx"> 
</span><span class="lines">@@ -2501,11 +3502,8 @@
</span><span class="cx">   // coordinates beyond the right of the text.
</span><span class="cx">   function posFromMouse(cm, e, liberal, forRect) {
</span><span class="cx">     var display = cm.display;
</span><del>-    if (!liberal) {
-      var target = e_target(e);
-      if (target == display.scrollbarH || target == display.scrollbarV ||
-          target == display.scrollbarFiller || target == display.gutterFiller) return null;
-    }
</del><ins>+    if (!liberal &amp;&amp; e_target(e).getAttribute(&quot;cm-not-content&quot;) == &quot;true&quot;) return null;
+
</ins><span class="cx">     var x, y, space = display.lineSpace.getBoundingClientRect();
</span><span class="cx">     // Fails unpredictably on IE[67] when mouse is dragged around quickly.
</span><span class="cx">     try { x = e.clientX - space.left; y = e.clientY - space.top; }
</span><span class="lines">@@ -2524,8 +3522,8 @@
</span><span class="cx">   // middle-click-paste. Or it might be a click on something we should
</span><span class="cx">   // not interfere with, such as a scrollbar or widget.
</span><span class="cx">   function onMouseDown(e) {
</span><del>-    if (signalDOMEvent(this, e)) return;
</del><span class="cx">     var cm = this, display = cm.display;
</span><ins>+    if (display.activeTouch &amp;&amp; display.input.supportsTouch() || signalDOMEvent(cm, e)) return;
</ins><span class="cx">     display.shift = e.shiftKey;
</span><span class="cx"> 
</span><span class="cx">     if (eventInWidget(display, e)) {
</span><span class="lines">@@ -2543,7 +3541,10 @@
</span><span class="cx"> 
</span><span class="cx">     switch (e_button(e)) {
</span><span class="cx">     case 1:
</span><del>-      if (start)
</del><ins>+      // #3261: make sure, that we're not starting a second selection
+      if (cm.state.selectingText)
+        cm.state.selectingText(e);
+      else if (start)
</ins><span class="cx">         leftButtonDown(cm, e, start);
</span><span class="cx">       else if (e_target(e) == display.scroller)
</span><span class="cx">         e_preventDefault(e);
</span><span class="lines">@@ -2551,18 +3552,20 @@
</span><span class="cx">     case 2:
</span><span class="cx">       if (webkit) cm.state.lastMiddleDown = +new Date;
</span><span class="cx">       if (start) extendSelection(cm.doc, start);
</span><del>-      setTimeout(bind(focusInput, cm), 20);
</del><ins>+      setTimeout(function() {display.input.focus();}, 20);
</ins><span class="cx">       e_preventDefault(e);
</span><span class="cx">       break;
</span><span class="cx">     case 3:
</span><span class="cx">       if (captureRightClick) onContextMenu(cm, e);
</span><ins>+      else delayBlurEvent(cm);
</ins><span class="cx">       break;
</span><span class="cx">     }
</span><span class="cx">   }
</span><span class="cx"> 
</span><span class="cx">   var lastClick, lastDoubleClick;
</span><span class="cx">   function leftButtonDown(cm, e, start) {
</span><del>-    setTimeout(bind(ensureFocus, cm), 0);
</del><ins>+    if (ie) setTimeout(bind(ensureFocus, cm), 0);
+    else cm.curOp.focus = activeElt();
</ins><span class="cx"> 
</span><span class="cx">     var now = +new Date, type;
</span><span class="cx">     if (lastDoubleClick &amp;&amp; lastDoubleClick.time &gt; now - 400 &amp;&amp; cmp(lastDoubleClick.pos, start) == 0) {
</span><span class="lines">@@ -2575,9 +3578,11 @@
</span><span class="cx">       lastClick = {time: now, pos: start};
</span><span class="cx">     }
</span><span class="cx"> 
</span><del>-    var sel = cm.doc.sel, modifier = mac ? e.metaKey : e.ctrlKey;
</del><ins>+    var sel = cm.doc.sel, modifier = mac ? e.metaKey : e.ctrlKey, contained;
</ins><span class="cx">     if (cm.options.dragDrop &amp;&amp; dragAndDrop &amp;&amp; !isReadOnly(cm) &amp;&amp;
</span><del>-        type == &quot;single&quot; &amp;&amp; sel.contains(start) &gt; -1 &amp;&amp; sel.somethingSelected())
</del><ins>+        type == &quot;single&quot; &amp;&amp; (contained = sel.contains(start)) &gt; -1 &amp;&amp;
+        (cmp((contained = sel.ranges[contained]).from(), start) &lt; 0 || start.xRel &gt; 0) &amp;&amp;
+        (cmp(contained.to(), start) &gt; 0 || start.xRel &lt; 0))
</ins><span class="cx">       leftButtonStartDrag(cm, e, start, modifier);
</span><span class="cx">     else
</span><span class="cx">       leftButtonSelect(cm, e, start, type, modifier);
</span><span class="lines">@@ -2586,7 +3591,7 @@
</span><span class="cx">   // Start a text drag. When it ends, see if any dragging actually
</span><span class="cx">   // happen, and treat as a click if it didn't.
</span><span class="cx">   function leftButtonStartDrag(cm, e, start, modifier) {
</span><del>-    var display = cm.display;
</del><ins>+    var display = cm.display, startTime = +new Date;
</ins><span class="cx">     var dragEnd = operation(cm, function(e2) {
</span><span class="cx">       if (webkit) display.scroller.draggable = false;
</span><span class="cx">       cm.state.draggingText = false;
</span><span class="lines">@@ -2594,12 +3599,13 @@
</span><span class="cx">       off(display.scroller, &quot;drop&quot;, dragEnd);
</span><span class="cx">       if (Math.abs(e.clientX - e2.clientX) + Math.abs(e.clientY - e2.clientY) &lt; 10) {
</span><span class="cx">         e_preventDefault(e2);
</span><del>-        if (!modifier)
</del><ins>+        if (!modifier &amp;&amp; +new Date - 200 &lt; startTime)
</ins><span class="cx">           extendSelection(cm.doc, start);
</span><del>-        focusInput(cm);
-        // Work around unexplainable focus problem in IE9 (#2127)
-        if (ie_upto10 &amp;&amp; !ie_upto8)
-          setTimeout(function() {document.body.focus(); focusInput(cm);}, 20);
</del><ins>+        // Work around unexplainable focus problem in IE9 (#2127) and Chrome (#3081)
+        if (webkit || ie &amp;&amp; ie_version == 9)
+          setTimeout(function() {document.body.focus(); display.input.focus();}, 20);
+        else
+          display.input.focus();
</ins><span class="cx">       }
</span><span class="cx">     });
</span><span class="cx">     // Let the drag handler handle this.
</span><span class="lines">@@ -2616,15 +3622,16 @@
</span><span class="cx">     var display = cm.display, doc = cm.doc;
</span><span class="cx">     e_preventDefault(e);
</span><span class="cx"> 
</span><del>-    var ourRange, ourIndex, startSel = doc.sel;
</del><ins>+    var ourRange, ourIndex, startSel = doc.sel, ranges = startSel.ranges;
</ins><span class="cx">     if (addNew &amp;&amp; !e.shiftKey) {
</span><span class="cx">       ourIndex = doc.sel.contains(start);
</span><span class="cx">       if (ourIndex &gt; -1)
</span><del>-        ourRange = doc.sel.ranges[ourIndex];
</del><ins>+        ourRange = ranges[ourIndex];
</ins><span class="cx">       else
</span><span class="cx">         ourRange = new Range(start, start);
</span><span class="cx">     } else {
</span><span class="cx">       ourRange = doc.sel.primary();
</span><ins>+      ourIndex = doc.sel.primIndex;
</ins><span class="cx">     }
</span><span class="cx"> 
</span><span class="cx">     if (e.altKey) {
</span><span class="lines">@@ -2633,7 +3640,7 @@
</span><span class="cx">       start = posFromMouse(cm, e, true, true);
</span><span class="cx">       ourIndex = -1;
</span><span class="cx">     } else if (type == &quot;double&quot;) {
</span><del>-      var word = findWordAt(cm, start);
</del><ins>+      var word = cm.findWordAt(start);
</ins><span class="cx">       if (cm.display.shift || doc.extend)
</span><span class="cx">         ourRange = extendRange(doc, ourRange, word.anchor, word.head);
</span><span class="cx">       else
</span><span class="lines">@@ -2652,12 +3659,15 @@
</span><span class="cx">       ourIndex = 0;
</span><span class="cx">       setSelection(doc, new Selection([ourRange], 0), sel_mouse);
</span><span class="cx">       startSel = doc.sel;
</span><del>-    } else if (ourIndex &gt; -1) {
</del><ins>+    } else if (ourIndex == -1) {
+      ourIndex = ranges.length;
+      setSelection(doc, normalizeSelection(ranges.concat([ourRange]), ourIndex),
+                   {scroll: false, origin: &quot;*mouse&quot;});
+    } else if (ranges.length &gt; 1 &amp;&amp; ranges[ourIndex].empty() &amp;&amp; type == &quot;single&quot; &amp;&amp; !e.shiftKey) {
+      setSelection(doc, normalizeSelection(ranges.slice(0, ourIndex).concat(ranges.slice(ourIndex + 1)), 0));
+      startSel = doc.sel;
+    } else {
</ins><span class="cx">       replaceOneSelection(doc, ourIndex, ourRange, sel_mouse);
</span><del>-    } else {
-      ourIndex = doc.sel.ranges.length;
-      setSelection(doc, normalizeSelection(doc.sel.ranges.concat([ourRange]), ourIndex),
-                   {scroll: false, origin: &quot;*mouse&quot;});
</del><span class="cx">     }
</span><span class="cx"> 
</span><span class="cx">     var lastPos = start;
</span><span class="lines">@@ -2687,7 +3697,7 @@
</span><span class="cx">         var anchor = oldRange.anchor, head = pos;
</span><span class="cx">         if (type != &quot;single&quot;) {
</span><span class="cx">           if (type == &quot;double&quot;)
</span><del>-            var range = findWordAt(cm, pos);
</del><ins>+            var range = cm.findWordAt(pos);
</ins><span class="cx">           else
</span><span class="cx">             var range = new Range(Pos(pos.line, 0), clipPos(doc, Pos(pos.line + 1, 0)));
</span><span class="cx">           if (cmp(range.anchor, anchor) &gt; 0) {
</span><span class="lines">@@ -2716,7 +3726,7 @@
</span><span class="cx">       var cur = posFromMouse(cm, e, true, type == &quot;rect&quot;);
</span><span class="cx">       if (!cur) return;
</span><span class="cx">       if (cmp(cur, lastPos) != 0) {
</span><del>-        ensureFocus(cm);
</del><ins>+        cm.curOp.focus = activeElt();
</ins><span class="cx">         extendTo(cur);
</span><span class="cx">         var visible = visibleLines(display, doc);
</span><span class="cx">         if (cur.line &gt;= visible.to || cur.line &lt; visible.from)
</span><span class="lines">@@ -2732,19 +3742,21 @@
</span><span class="cx">     }
</span><span class="cx"> 
</span><span class="cx">     function done(e) {
</span><ins>+      cm.state.selectingText = false;
</ins><span class="cx">       counter = Infinity;
</span><span class="cx">       e_preventDefault(e);
</span><del>-      focusInput(cm);
</del><ins>+      display.input.focus();
</ins><span class="cx">       off(document, &quot;mousemove&quot;, move);
</span><span class="cx">       off(document, &quot;mouseup&quot;, up);
</span><span class="cx">       doc.history.lastSelOrigin = null;
</span><span class="cx">     }
</span><span class="cx"> 
</span><span class="cx">     var move = operation(cm, function(e) {
</span><del>-      if ((ie &amp;&amp; !ie_upto9) ?  !e.buttons : !e_button(e)) done(e);
</del><ins>+      if (!e_button(e)) done(e);
</ins><span class="cx">       else extend(e);
</span><span class="cx">     });
</span><span class="cx">     var up = operation(cm, done);
</span><ins>+    cm.state.selectingText = up;
</ins><span class="cx">     on(document, &quot;mousemove&quot;, move);
</span><span class="cx">     on(document, &quot;mouseup&quot;, up);
</span><span class="cx">   }
</span><span class="lines">@@ -2784,6 +3796,7 @@
</span><span class="cx"> 
</span><span class="cx">   function onDrop(e) {
</span><span class="cx">     var cm = this;
</span><ins>+    clearDragCursor(cm);
</ins><span class="cx">     if (signalDOMEvent(cm, e) || eventInWidget(cm.display, e))
</span><span class="cx">       return;
</span><span class="cx">     e_preventDefault(e);
</span><span class="lines">@@ -2800,7 +3813,9 @@
</span><span class="cx">           text[i] = reader.result;
</span><span class="cx">           if (++read == n) {
</span><span class="cx">             pos = clipPos(cm.doc, pos);
</span><del>-            var change = {from: pos, to: pos, text: splitLines(text.join(&quot;\n&quot;)), origin: &quot;paste&quot;};
</del><ins>+            var change = {from: pos, to: pos,
+                          text: cm.doc.splitLines(text.join(cm.doc.lineSeparator())),
+                          origin: &quot;paste&quot;};
</ins><span class="cx">             makeChange(cm.doc, change);
</span><span class="cx">             setSelectionReplaceHistory(cm.doc, simpleSelection(pos, changeEnd(change)));
</span><span class="cx">           }
</span><span class="lines">@@ -2813,19 +3828,19 @@
</span><span class="cx">       if (cm.state.draggingText &amp;&amp; cm.doc.sel.contains(pos) &gt; -1) {
</span><span class="cx">         cm.state.draggingText(e);
</span><span class="cx">         // Ensure the editor is re-focused
</span><del>-        setTimeout(bind(focusInput, cm), 20);
</del><ins>+        setTimeout(function() {cm.display.input.focus();}, 20);
</ins><span class="cx">         return;
</span><span class="cx">       }
</span><span class="cx">       try {
</span><span class="cx">         var text = e.dataTransfer.getData(&quot;Text&quot;);
</span><span class="cx">         if (text) {
</span><del>-          if (cm.state.draggingText &amp;&amp; !(mac ? e.metaKey : e.ctrlKey))
</del><ins>+          if (cm.state.draggingText &amp;&amp; !(mac ? e.altKey : e.ctrlKey))
</ins><span class="cx">             var selected = cm.listSelections();
</span><span class="cx">           setSelectionNoUndo(cm.doc, simpleSelection(pos, pos));
</span><span class="cx">           if (selected) for (var i = 0; i &lt; selected.length; ++i)
</span><span class="cx">             replaceRange(cm.doc, &quot;&quot;, selected[i].anchor, selected[i].head, &quot;drag&quot;);
</span><span class="cx">           cm.replaceSelection(text, &quot;around&quot;, &quot;paste&quot;);
</span><del>-          focusInput(cm);
</del><ins>+          cm.display.input.focus();
</ins><span class="cx">         }
</span><span class="cx">       }
</span><span class="cx">       catch(e){}
</span><span class="lines">@@ -2854,6 +3869,25 @@
</span><span class="cx">     }
</span><span class="cx">   }
</span><span class="cx"> 
</span><ins>+  function onDragOver(cm, e) {
+    var pos = posFromMouse(cm, e);
+    if (!pos) return;
+    var frag = document.createDocumentFragment();
+    drawSelectionCursor(cm, pos, frag);
+    if (!cm.display.dragCursor) {
+      cm.display.dragCursor = elt(&quot;div&quot;, null, &quot;CodeMirror-cursors CodeMirror-dragcursors&quot;);
+      cm.display.lineSpace.insertBefore(cm.display.dragCursor, cm.display.cursorDiv);
+    }
+    removeChildrenAndAdd(cm.display.dragCursor, frag);
+  }
+
+  function clearDragCursor(cm) {
+    if (cm.display.dragCursor) {
+      cm.display.lineSpace.removeChild(cm.display.dragCursor);
+      cm.display.dragCursor = null;
+    }
+  }
+
</ins><span class="cx">   // SCROLL EVENTS
</span><span class="cx"> 
</span><span class="cx">   // Sync the scrollable area and scrollbars, ensure the viewport
</span><span class="lines">@@ -2861,10 +3895,10 @@
</span><span class="cx">   function setScrollTop(cm, val) {
</span><span class="cx">     if (Math.abs(cm.doc.scrollTop - val) &lt; 2) return;
</span><span class="cx">     cm.doc.scrollTop = val;
</span><del>-    if (!gecko) updateDisplay(cm, {top: val});
</del><ins>+    if (!gecko) updateDisplaySimple(cm, {top: val});
</ins><span class="cx">     if (cm.display.scroller.scrollTop != val) cm.display.scroller.scrollTop = val;
</span><del>-    if (cm.display.scrollbarV.scrollTop != val) cm.display.scrollbarV.scrollTop = val;
-    if (gecko) updateDisplay(cm);
</del><ins>+    cm.display.scrollbars.setScrollTop(val);
+    if (gecko) updateDisplaySimple(cm);
</ins><span class="cx">     startWorker(cm, 100);
</span><span class="cx">   }
</span><span class="cx">   // Sync scroller and scrollbar, ensure the gutter elements are
</span><span class="lines">@@ -2875,7 +3909,7 @@
</span><span class="cx">     cm.doc.scrollLeft = val;
</span><span class="cx">     alignHorizontally(cm);
</span><span class="cx">     if (cm.display.scroller.scrollLeft != val) cm.display.scroller.scrollLeft = val;
</span><del>-    if (cm.display.scrollbarH.scrollLeft != val) cm.display.scrollbarH.scrollLeft = val;
</del><ins>+    cm.display.scrollbars.setScrollLeft(val);
</ins><span class="cx">   }
</span><span class="cx"> 
</span><span class="cx">   // Since the delta values reported on mouse wheel events are
</span><span class="lines">@@ -2899,12 +3933,23 @@
</span><span class="cx">   else if (chrome) wheelPixelsPerUnit = -.7;
</span><span class="cx">   else if (safari) wheelPixelsPerUnit = -1/3;
</span><span class="cx"> 
</span><del>-  function onScrollWheel(cm, e) {
</del><ins>+  var wheelEventDelta = function(e) {
</ins><span class="cx">     var dx = e.wheelDeltaX, dy = e.wheelDeltaY;
</span><span class="cx">     if (dx == null &amp;&amp; e.detail &amp;&amp; e.axis == e.HORIZONTAL_AXIS) dx = e.detail;
</span><span class="cx">     if (dy == null &amp;&amp; e.detail &amp;&amp; e.axis == e.VERTICAL_AXIS) dy = e.detail;
</span><span class="cx">     else if (dy == null) dy = e.wheelDelta;
</span><ins>+    return {x: dx, y: dy};
+  };
+  CodeMirror.wheelEventPixels = function(e) {
+    var delta = wheelEventDelta(e);
+    delta.x *= wheelPixelsPerUnit;
+    delta.y *= wheelPixelsPerUnit;
+    return delta;
+  };
</ins><span class="cx"> 
</span><ins>+  function onScrollWheel(cm, e) {
+    var delta = wheelEventDelta(e), dx = delta.x, dy = delta.y;
+
</ins><span class="cx">     var display = cm.display, scroll = display.scroller;
</span><span class="cx">     // Quit if there's nothing to scroll here
</span><span class="cx">     if (!(dx &amp;&amp; scroll.scrollWidth &gt; scroll.clientWidth ||
</span><span class="lines">@@ -2947,7 +3992,7 @@
</span><span class="cx">       var top = cm.doc.scrollTop, bot = top + display.wrapper.clientHeight;
</span><span class="cx">       if (pixels &lt; 0) top = Math.max(0, top + pixels - 50);
</span><span class="cx">       else bot = Math.min(cm.doc.height, bot + pixels + 50);
</span><del>-      updateDisplay(cm, {top: top, bottom: bot});
</del><ins>+      updateDisplaySimple(cm, {top: top, bottom: bot});
</ins><span class="cx">     }
</span><span class="cx"> 
</span><span class="cx">     if (wheelSamples &lt; 20) {
</span><span class="lines">@@ -2981,7 +4026,7 @@
</span><span class="cx">     }
</span><span class="cx">     // Ensure previous input has been read, so that the handler sees a
</span><span class="cx">     // consistent view of the document
</span><del>-    if (cm.display.pollingFast &amp;&amp; readInput(cm)) cm.display.pollingFast = false;
</del><ins>+    cm.display.input.ensurePolled();
</ins><span class="cx">     var prevShift = cm.display.shift, done = false;
</span><span class="cx">     try {
</span><span class="cx">       if (isReadOnly(cm)) cm.state.suppressEdits = true;
</span><span class="lines">@@ -2994,71 +4039,79 @@
</span><span class="cx">     return done;
</span><span class="cx">   }
</span><span class="cx"> 
</span><del>-  // Collect the currently active keymaps.
-  function allKeyMaps(cm) {
-    var maps = cm.state.keyMaps.slice(0);
-    if (cm.options.extraKeys) maps.push(cm.options.extraKeys);
-    maps.push(cm.options.keyMap);
-    return maps;
</del><ins>+  function lookupKeyForEditor(cm, name, handle) {
+    for (var i = 0; i &lt; cm.state.keyMaps.length; i++) {
+      var result = lookupKey(name, cm.state.keyMaps[i], handle, cm);
+      if (result) return result;
+    }
+    return (cm.options.extraKeys &amp;&amp; lookupKey(name, cm.options.extraKeys, handle, cm))
+      || lookupKey(name, cm.options.keyMap, handle, cm);
</ins><span class="cx">   }
</span><span class="cx"> 
</span><del>-  var maybeTransition;
</del><ins>+  var stopSeq = new Delayed;
+  function dispatchKey(cm, name, e, handle) {
+    var seq = cm.state.keySeq;
+    if (seq) {
+      if (isModifierKey(name)) return &quot;handled&quot;;
+      stopSeq.set(50, function() {
+        if (cm.state.keySeq == seq) {
+          cm.state.keySeq = null;
+          cm.display.input.reset();
+        }
+      });
+      name = seq + &quot; &quot; + name;
+    }
+    var result = lookupKeyForEditor(cm, name, handle);
+
+    if (result == &quot;multi&quot;)
+      cm.state.keySeq = name;
+    if (result == &quot;handled&quot;)
+      signalLater(cm, &quot;keyHandled&quot;, cm, name, e);
+
+    if (result == &quot;handled&quot; || result == &quot;multi&quot;) {
+      e_preventDefault(e);
+      restartBlink(cm);
+    }
+
+    if (seq &amp;&amp; !result &amp;&amp; /\'$/.test(name)) {
+      e_preventDefault(e);
+      return true;
+    }
+    return !!result;
+  }
+
</ins><span class="cx">   // Handle a key from the keydown event.
</span><span class="cx">   function handleKeyBinding(cm, e) {
</span><del>-    // Handle automatic keymap transitions
-    var startMap = getKeyMap(cm.options.keyMap), next = startMap.auto;
-    clearTimeout(maybeTransition);
-    if (next &amp;&amp; !isModifierKey(e)) maybeTransition = setTimeout(function() {
-      if (getKeyMap(cm.options.keyMap) == startMap) {
-        cm.options.keyMap = (next.call ? next.call(null, cm) : next);
-        keyMapChanged(cm);
-      }
-    }, 50);
-
-    var name = keyName(e, true), handled = false;
</del><ins>+    var name = keyName(e, true);
</ins><span class="cx">     if (!name) return false;
</span><del>-    var keymaps = allKeyMaps(cm);
</del><span class="cx"> 
</span><del>-    if (e.shiftKey) {
</del><ins>+    if (e.shiftKey &amp;&amp; !cm.state.keySeq) {
</ins><span class="cx">       // First try to resolve full name (including 'Shift-'). Failing
</span><span class="cx">       // that, see if there is a cursor-motion command (starting with
</span><span class="cx">       // 'go') bound to the keyname without 'Shift-'.
</span><del>-      handled = lookupKey(&quot;Shift-&quot; + name, keymaps, function(b) {return doHandleBinding(cm, b, true);})
-             || lookupKey(name, keymaps, function(b) {
-                  if (typeof b == &quot;string&quot; ? /^go[A-Z]/.test(b) : b.motion)
-                    return doHandleBinding(cm, b);
-                });
</del><ins>+      return dispatchKey(cm, &quot;Shift-&quot; + name, e, function(b) {return doHandleBinding(cm, b, true);})
+          || dispatchKey(cm, name, e, function(b) {
+               if (typeof b == &quot;string&quot; ? /^go[A-Z]/.test(b) : b.motion)
+                 return doHandleBinding(cm, b);
+             });
</ins><span class="cx">     } else {
</span><del>-      handled = lookupKey(name, keymaps, function(b) { return doHandleBinding(cm, b); });
</del><ins>+      return dispatchKey(cm, name, e, function(b) { return doHandleBinding(cm, b); });
</ins><span class="cx">     }
</span><del>-
-    if (handled) {
-      e_preventDefault(e);
-      restartBlink(cm);
-      signalLater(cm, &quot;keyHandled&quot;, cm, name, e);
-    }
-    return handled;
</del><span class="cx">   }
</span><span class="cx"> 
</span><span class="cx">   // Handle a key from the keypress event
</span><span class="cx">   function handleCharBinding(cm, e, ch) {
</span><del>-    var handled = lookupKey(&quot;'&quot; + ch + &quot;'&quot;, allKeyMaps(cm),
-                            function(b) { return doHandleBinding(cm, b, true); });
-    if (handled) {
-      e_preventDefault(e);
-      restartBlink(cm);
-      signalLater(cm, &quot;keyHandled&quot;, cm, &quot;'&quot; + ch + &quot;'&quot;, e);
-    }
-    return handled;
</del><ins>+    return dispatchKey(cm, &quot;'&quot; + ch + &quot;'&quot;, e,
+                       function(b) { return doHandleBinding(cm, b, true); });
</ins><span class="cx">   }
</span><span class="cx"> 
</span><span class="cx">   var lastStoppedKey = null;
</span><span class="cx">   function onKeyDown(e) {
</span><span class="cx">     var cm = this;
</span><del>-    ensureFocus(cm);
</del><ins>+    cm.curOp.focus = activeElt();
</ins><span class="cx">     if (signalDOMEvent(cm, e)) return;
</span><span class="cx">     // IE does strange things with escape.
</span><del>-    if (ie_upto10 &amp;&amp; e.keyCode == 27) e.returnValue = false;
</del><ins>+    if (ie &amp;&amp; ie_version &lt; 11 &amp;&amp; e.keyCode == 27) e.returnValue = false;
</ins><span class="cx">     var code = e.keyCode;
</span><span class="cx">     cm.display.shift = code == 16 || e.shiftKey;
</span><span class="cx">     var handled = handleKeyBinding(cm, e);
</span><span class="lines">@@ -3090,42 +4143,55 @@
</span><span class="cx">   }
</span><span class="cx"> 
</span><span class="cx">   function onKeyUp(e) {
</span><del>-    if (signalDOMEvent(this, e)) return;
</del><span class="cx">     if (e.keyCode == 16) this.doc.sel.shift = false;
</span><ins>+    signalDOMEvent(this, e);
</ins><span class="cx">   }
</span><span class="cx"> 
</span><span class="cx">   function onKeyPress(e) {
</span><span class="cx">     var cm = this;
</span><del>-    if (signalDOMEvent(cm, e)) return;
</del><ins>+    if (eventInWidget(cm.display, e) || signalDOMEvent(cm, e) || e.ctrlKey &amp;&amp; !e.altKey || mac &amp;&amp; e.metaKey) return;
</ins><span class="cx">     var keyCode = e.keyCode, charCode = e.charCode;
</span><span class="cx">     if (presto &amp;&amp; keyCode == lastStoppedKey) {lastStoppedKey = null; e_preventDefault(e); return;}
</span><del>-    if (((presto &amp;&amp; (!e.which || e.which &lt; 10)) || khtml) &amp;&amp; handleKeyBinding(cm, e)) return;
</del><ins>+    if ((presto &amp;&amp; (!e.which || e.which &lt; 10)) &amp;&amp; handleKeyBinding(cm, e)) return;
</ins><span class="cx">     var ch = String.fromCharCode(charCode == null ? keyCode : charCode);
</span><span class="cx">     if (handleCharBinding(cm, e, ch)) return;
</span><del>-    if (ie &amp;&amp; !ie_upto8) cm.display.inputHasSelection = null;
-    fastPoll(cm);
</del><ins>+    cm.display.input.onKeyPress(e);
</ins><span class="cx">   }
</span><span class="cx"> 
</span><span class="cx">   // FOCUS/BLUR EVENTS
</span><span class="cx"> 
</span><ins>+  function delayBlurEvent(cm) {
+    cm.state.delayingBlurEvent = true;
+    setTimeout(function() {
+      if (cm.state.delayingBlurEvent) {
+        cm.state.delayingBlurEvent = false;
+        onBlur(cm);
+      }
+    }, 100);
+  }
+
</ins><span class="cx">   function onFocus(cm) {
</span><ins>+    if (cm.state.delayingBlurEvent) cm.state.delayingBlurEvent = false;
+
</ins><span class="cx">     if (cm.options.readOnly == &quot;nocursor&quot;) return;
</span><span class="cx">     if (!cm.state.focused) {
</span><span class="cx">       signal(cm, &quot;focus&quot;, cm);
</span><span class="cx">       cm.state.focused = true;
</span><span class="cx">       addClass(cm.display.wrapper, &quot;CodeMirror-focused&quot;);
</span><del>-      // The prevInput test prevents this from firing when a context
-      // menu is closed (since the resetInput would kill the
</del><ins>+      // This test prevents this from firing when a context
+      // menu is closed (since the input reset would kill the
</ins><span class="cx">       // select-all detection hack)
</span><span class="cx">       if (!cm.curOp &amp;&amp; cm.display.selForContextMenu != cm.doc.sel) {
</span><del>-        resetInput(cm);
-        if (webkit) setTimeout(bind(resetInput, cm, true), 0); // Issue #1730
</del><ins>+        cm.display.input.reset();
+        if (webkit) setTimeout(function() { cm.display.input.reset(true); }, 20); // Issue #1730
</ins><span class="cx">       }
</span><ins>+      cm.display.input.receivedFocus();
</ins><span class="cx">     }
</span><del>-    slowPoll(cm);
</del><span class="cx">     restartBlink(cm);
</span><span class="cx">   }
</span><span class="cx">   function onBlur(cm) {
</span><ins>+    if (cm.state.delayingBlurEvent) return;
+
</ins><span class="cx">     if (cm.state.focused) {
</span><span class="cx">       signal(cm, &quot;blur&quot;, cm);
</span><span class="cx">       cm.state.focused = false;
</span><span class="lines">@@ -3141,76 +4207,8 @@
</span><span class="cx">   // textarea (making it as unobtrusive as possible) to let the
</span><span class="cx">   // right-click take effect on it.
</span><span class="cx">   function onContextMenu(cm, e) {
</span><del>-    if (signalDOMEvent(cm, e, &quot;contextmenu&quot;)) return;
-    var display = cm.display;
-    if (eventInWidget(display, e) || contextMenuInGutter(cm, e)) return;
-
-    var pos = posFromMouse(cm, e), scrollPos = display.scroller.scrollTop;
-    if (!pos || presto) return; // Opera is difficult.
-
-    // Reset the current text selection only if the click is done outside of the selection
-    // and 'resetSelectionOnContextMenu' option is true.
-    var reset = cm.options.resetSelectionOnContextMenu;
-    if (reset &amp;&amp; cm.doc.sel.contains(pos) == -1)
-      operation(cm, setSelection)(cm.doc, simpleSelection(pos), sel_dontScroll);
-
-    var oldCSS = display.input.style.cssText;
-    display.inputDiv.style.position = &quot;absolute&quot;;
-    display.input.style.cssText = &quot;position: fixed; width: 30px; height: 30px; top: &quot; + (e.clientY - 5) +
-      &quot;px; left: &quot; + (e.clientX - 5) + &quot;px; z-index: 1000; background: &quot; +
-      (ie ? &quot;rgba(255, 255, 255, .05)&quot; : &quot;transparent&quot;) +
-      &quot;; outline: none; border-width: 0; outline: none; overflow: hidden; opacity: .05; filter: alpha(opacity=5);&quot;;
-    focusInput(cm);
-    resetInput(cm);
-    // Adds &quot;Select all&quot; to context menu in FF
-    if (!cm.somethingSelected()) display.input.value = display.prevInput = &quot; &quot;;
-    display.selForContextMenu = cm.doc.sel;
-    clearTimeout(display.detectingSelectAll);
-
-    // Select-all will be greyed out if there's nothing to select, so
-    // this adds a zero-width space so that we can later check whether
-    // it got selected.
-    function prepareSelectAllHack() {
-      if (display.input.selectionStart != null) {
-        var selected = cm.somethingSelected();
-        var extval = display.input.value = &quot;\u200b&quot; + (selected ? display.input.value : &quot;&quot;);
-        display.prevInput = selected ? &quot;&quot; : &quot;\u200b&quot;;
-        display.input.selectionStart = 1; display.input.selectionEnd = extval.length;
-        // Re-set this, in case some other handler touched the
-        // selection in the meantime.
-        display.selForContextMenu = cm.doc.sel;
-      }
-    }
-    function rehide() {
-      display.inputDiv.style.position = &quot;relative&quot;;
-      display.input.style.cssText = oldCSS;
-      if (ie_upto8) display.scrollbarV.scrollTop = display.scroller.scrollTop = scrollPos;
-      slowPoll(cm);
-
-      // Try to detect the user choosing select-all
-      if (display.input.selectionStart != null) {
-        if (!ie || ie_upto8) prepareSelectAllHack();
-        var i = 0, poll = function() {
-          if (display.selForContextMenu == cm.doc.sel &amp;&amp; display.input.selectionStart == 0)
-            operation(cm, commands.selectAll)(cm);
-          else if (i++ &lt; 10) display.detectingSelectAll = setTimeout(poll, 500);
-          else resetInput(cm);
-        };
-        display.detectingSelectAll = setTimeout(poll, 200);
-      }
-    }
-
-    if (ie &amp;&amp; !ie_upto8) prepareSelectAllHack();
-    if (captureRightClick) {
-      e_stop(e);
-      var mouseup = function() {
-        off(window, &quot;mouseup&quot;, mouseup);
-        setTimeout(rehide, 20);
-      };
-      on(window, &quot;mouseup&quot;, mouseup);
-    } else {
-      setTimeout(rehide, 50);
-    }
</del><ins>+    if (eventInWidget(cm.display, e) || contextMenuInGutter(cm, e)) return;
+    cm.display.input.onContextMenu(e);
</ins><span class="cx">   }
</span><span class="cx"> 
</span><span class="cx">   function contextMenuInGutter(cm, e) {
</span><span class="lines">@@ -3390,9 +4388,9 @@
</span><span class="cx"> 
</span><span class="cx">       antiChanges.push(historyChangeFromChange(doc, change));
</span><span class="cx"> 
</span><del>-      var after = i ? computeSelAfterChange(doc, change, null) : lst(source);
</del><ins>+      var after = i ? computeSelAfterChange(doc, change) : lst(source);
</ins><span class="cx">       makeChangeSingleDoc(doc, change, after, mergeOldSpans(doc, change));
</span><del>-      if (!i &amp;&amp; doc.cm) doc.cm.scrollIntoView(change);
</del><ins>+      if (!i &amp;&amp; doc.cm) doc.cm.scrollIntoView({from: change.from, to: changeEnd(change)});
</ins><span class="cx">       var rebased = [];
</span><span class="cx"> 
</span><span class="cx">       // Propagate to the linked documents
</span><span class="lines">@@ -3449,7 +4447,7 @@
</span><span class="cx"> 
</span><span class="cx">     change.removed = getBetween(doc, change.from, change.to);
</span><span class="cx"> 
</span><del>-    if (!selAfter) selAfter = computeSelAfterChange(doc, change, null);
</del><ins>+    if (!selAfter) selAfter = computeSelAfterChange(doc, change);
</ins><span class="cx">     if (doc.cm) makeChangeSingleDocInEditor(doc.cm, change, spans);
</span><span class="cx">     else updateDoc(doc, change, spans);
</span><span class="cx">     setSelectionNoUndo(doc, selAfter, sel_dontScroll);
</span><span class="lines">@@ -3495,7 +4493,9 @@
</span><span class="cx"> 
</span><span class="cx">     var lendiff = change.text.length - (to.line - from.line) - 1;
</span><span class="cx">     // Remember that these lines changed, for updating the display
</span><del>-    if (from.line == to.line &amp;&amp; change.text.length == 1 &amp;&amp; !isWholeLineUpdate(cm.doc, change))
</del><ins>+    if (change.full)
+      regChange(cm);
+    else if (from.line == to.line &amp;&amp; change.text.length == 1 &amp;&amp; !isWholeLineUpdate(cm.doc, change))
</ins><span class="cx">       regLineChange(cm, from.line, &quot;text&quot;);
</span><span class="cx">     else
</span><span class="cx">       regChange(cm, from.line, to.line + 1, lendiff);
</span><span class="lines">@@ -3517,7 +4517,7 @@
</span><span class="cx">   function replaceRange(doc, code, from, to, origin) {
</span><span class="cx">     if (!to) to = from;
</span><span class="cx">     if (cmp(to, from) &lt; 0) { var tmp = to; to = from; from = tmp; }
</span><del>-    if (typeof code == &quot;string&quot;) code = splitLines(code);
</del><ins>+    if (typeof code == &quot;string&quot;) code = doc.splitLines(code);
</ins><span class="cx">     makeChange(doc, {from: from, to: to, text: code, origin: origin});
</span><span class="cx">   }
</span><span class="cx"> 
</span><span class="lines">@@ -3534,7 +4534,7 @@
</span><span class="cx">     if (doScroll != null &amp;&amp; !phantom) {
</span><span class="cx">       var scrollNode = elt(&quot;div&quot;, &quot;\u200b&quot;, null, &quot;position: absolute; top: &quot; +
</span><span class="cx">                            (coords.top - display.viewOffset - paddingTop(cm.display)) + &quot;px; height: &quot; +
</span><del>-                           (coords.bottom - coords.top + scrollerCutOff) + &quot;px; left: &quot; +
</del><ins>+                           (coords.bottom - coords.top + scrollGap(cm) + display.barHeight) + &quot;px; left: &quot; +
</ins><span class="cx">                            coords.left + &quot;px; width: 2px;&quot;);
</span><span class="cx">       cm.display.lineSpace.appendChild(scrollNode);
</span><span class="cx">       scrollNode.scrollIntoView(doScroll);
</span><span class="lines">@@ -3547,7 +4547,7 @@
</span><span class="cx">   // measured, the position of something may 'drift' during drawing).
</span><span class="cx">   function scrollPosIntoView(cm, pos, end, margin) {
</span><span class="cx">     if (margin == null) margin = 0;
</span><del>-    for (;;) {
</del><ins>+    for (var limit = 0; limit &lt; 5; limit++) {
</ins><span class="cx">       var changed = false, coords = cursorCoords(cm, pos);
</span><span class="cx">       var endCoords = !end || end == pos ? coords : cursorCoords(cm, end);
</span><span class="cx">       var scrollPos = calculateScrollPos(cm, Math.min(coords.left, endCoords.left),
</span><span class="lines">@@ -3563,8 +4563,9 @@
</span><span class="cx">         setScrollLeft(cm, scrollPos.scrollLeft);
</span><span class="cx">         if (Math.abs(cm.doc.scrollLeft - startLeft) &gt; 1) changed = true;
</span><span class="cx">       }
</span><del>-      if (!changed) return coords;
</del><ins>+      if (!changed) break;
</ins><span class="cx">     }
</span><ins>+    return coords;
</ins><span class="cx">   }
</span><span class="cx"> 
</span><span class="cx">   // Scroll a given set of coordinates into view (immediately).
</span><span class="lines">@@ -3582,7 +4583,8 @@
</span><span class="cx">     var display = cm.display, snapMargin = textHeight(cm.display);
</span><span class="cx">     if (y1 &lt; 0) y1 = 0;
</span><span class="cx">     var screentop = cm.curOp &amp;&amp; cm.curOp.scrollTop != null ? cm.curOp.scrollTop : display.scroller.scrollTop;
</span><del>-    var screen = display.scroller.clientHeight - scrollerCutOff, result = {};
</del><ins>+    var screen = displayHeight(cm), result = {};
+    if (y2 - y1 &gt; screen) y2 = y1 + screen;
</ins><span class="cx">     var docBottom = cm.doc.height + paddingVert(display);
</span><span class="cx">     var atTop = y1 &lt; snapMargin, atBottom = y2 &gt; docBottom - snapMargin;
</span><span class="cx">     if (y1 &lt; screentop) {
</span><span class="lines">@@ -3593,16 +4595,15 @@
</span><span class="cx">     }
</span><span class="cx"> 
</span><span class="cx">     var screenleft = cm.curOp &amp;&amp; cm.curOp.scrollLeft != null ? cm.curOp.scrollLeft : display.scroller.scrollLeft;
</span><del>-    var screenw = display.scroller.clientWidth - scrollerCutOff;
-    x1 += display.gutters.offsetWidth; x2 += display.gutters.offsetWidth;
-    var gutterw = display.gutters.offsetWidth;
-    var atLeft = x1 &lt; gutterw + 10;
-    if (x1 &lt; screenleft + gutterw || atLeft) {
-      if (atLeft) x1 = 0;
-      result.scrollLeft = Math.max(0, x1 - 10 - gutterw);
-    } else if (x2 &gt; screenw + screenleft - 3) {
-      result.scrollLeft = x2 + 10 - screenw;
-    }
</del><ins>+    var screenw = displayWidth(cm) - (cm.options.fixedGutter ? display.gutters.offsetWidth : 0);
+    var tooWide = x2 - x1 &gt; screenw;
+    if (tooWide) x2 = x1 + screenw;
+    if (x1 &lt; 10)
+      result.scrollLeft = 0;
+    else if (x1 &lt; screenleft)
+      result.scrollLeft = Math.max(0, x1 - (tooWide ? 0 : 10));
+    else if (x2 &gt; screenw + screenleft - 3)
+      result.scrollLeft = x2 + (tooWide ? 0 : 10) - screenw;
</ins><span class="cx">     return result;
</span><span class="cx">   }
</span><span class="cx"> 
</span><span class="lines">@@ -3658,7 +4659,7 @@
</span><span class="cx">     if (how == &quot;smart&quot;) {
</span><span class="cx">       // Fall back to &quot;prev&quot; when the mode doesn't have an indentation
</span><span class="cx">       // method.
</span><del>-      if (!cm.doc.mode.indent) how = &quot;prev&quot;;
</del><ins>+      if (!doc.mode.indent) how = &quot;prev&quot;;
</ins><span class="cx">       else state = getStateBefore(cm, n);
</span><span class="cx">     }
</span><span class="cx"> 
</span><span class="lines">@@ -3670,8 +4671,8 @@
</span><span class="cx">       indentation = 0;
</span><span class="cx">       how = &quot;not&quot;;
</span><span class="cx">     } else if (how == &quot;smart&quot;) {
</span><del>-      indentation = cm.doc.mode.indent(state, line.text.slice(curSpaceString.length), line.text);
-      if (indentation == Pass) {
</del><ins>+      indentation = doc.mode.indent(state, line.text.slice(curSpaceString.length), line.text);
+      if (indentation == Pass || indentation &gt; 150) {
</ins><span class="cx">         if (!aggressive) return;
</span><span class="cx">         how = &quot;prev&quot;;
</span><span class="cx">       }
</span><span class="lines">@@ -3694,7 +4695,9 @@
</span><span class="cx">     if (pos &lt; indentation) indentString += spaceStr(indentation - pos);
</span><span class="cx"> 
</span><span class="cx">     if (indentString != curSpaceString) {
</span><del>-      replaceRange(cm.doc, indentString, Pos(n, 0), Pos(n, curSpaceString.length), &quot;+input&quot;);
</del><ins>+      replaceRange(doc, indentString, Pos(n, 0), Pos(n, curSpaceString.length), &quot;+input&quot;);
+      line.stateAfter = null;
+      return true;
</ins><span class="cx">     } else {
</span><span class="cx">       // Ensure that, if the cursor was in the whitespace at the start
</span><span class="cx">       // of the line, it is moved to the end of that space.
</span><span class="lines">@@ -3707,18 +4710,17 @@
</span><span class="cx">         }
</span><span class="cx">       }
</span><span class="cx">     }
</span><del>-    line.stateAfter = null;
</del><span class="cx">   }
</span><span class="cx"> 
</span><span class="cx">   // Utility for applying a change to a line by handle or number,
</span><span class="cx">   // returning the number and optionally registering the line as
</span><span class="cx">   // changed.
</span><del>-  function changeLine(cm, handle, changeType, op) {
-    var no = handle, line = handle, doc = cm.doc;
</del><ins>+  function changeLine(doc, handle, changeType, op) {
+    var no = handle, line = handle;
</ins><span class="cx">     if (typeof handle == &quot;number&quot;) line = getLine(doc, clipLine(doc, handle));
</span><span class="cx">     else no = lineNo(handle);
</span><span class="cx">     if (no == null) return null;
</span><del>-    if (op(line, no)) regLineChange(cm, no, changeType);
</del><ins>+    if (op(line, no) &amp;&amp; doc.cm) regLineChange(doc.cm, no, changeType);
</ins><span class="cx">     return line;
</span><span class="cx">   }
</span><span class="cx"> 
</span><span class="lines">@@ -3824,24 +4826,6 @@
</span><span class="cx">     return target;
</span><span class="cx">   }
</span><span class="cx"> 
</span><del>-  // Find the word at the given position (as returned by coordsChar).
-  function findWordAt(cm, pos) {
-    var doc = cm.doc, line = getLine(doc, pos.line).text;
-    var start = pos.ch, end = pos.ch;
-    if (line) {
-      var helper = cm.getHelper(pos, &quot;wordChars&quot;);
-      if ((pos.xRel &lt; 0 || end == line.length) &amp;&amp; start) --start; else ++end;
-      var startChar = line.charAt(start);
-      var check = isWordChar(startChar, helper)
-        ? function(ch) { return isWordChar(ch, helper); }
-        : /\s/.test(startChar) ? function(ch) {return /\s/.test(ch);}
-        : function(ch) {return !/\s/.test(ch) &amp;&amp; !isWordChar(ch);};
-      while (start &gt; 0 &amp;&amp; check(line.charAt(start - 1))) --start;
-      while (end &lt; line.length &amp;&amp; check(line.charAt(end))) ++end;
-    }
-    return new Range(Pos(pos.line, start), Pos(pos.line, end));
-  }
-
</del><span class="cx">   // EDITOR METHODS
</span><span class="cx"> 
</span><span class="cx">   // The publicly visible API. Note that methodOp(f) means
</span><span class="lines">@@ -3854,7 +4838,7 @@
</span><span class="cx"> 
</span><span class="cx">   CodeMirror.prototype = {
</span><span class="cx">     constructor: CodeMirror,
</span><del>-    focus: function(){window.focus(); focusInput(this); fastPoll(this);},
</del><ins>+    focus: function(){window.focus(); this.display.input.focus();},
</ins><span class="cx"> 
</span><span class="cx">     setOption: function(option, value) {
</span><span class="cx">       var options = this.options, old = options[option];
</span><span class="lines">@@ -3868,12 +4852,12 @@
</span><span class="cx">     getDoc: function() {return this.doc;},
</span><span class="cx"> 
</span><span class="cx">     addKeyMap: function(map, bottom) {
</span><del>-      this.state.keyMaps[bottom ? &quot;push&quot; : &quot;unshift&quot;](map);
</del><ins>+      this.state.keyMaps[bottom ? &quot;push&quot; : &quot;unshift&quot;](getKeyMap(map));
</ins><span class="cx">     },
</span><span class="cx">     removeKeyMap: function(map) {
</span><span class="cx">       var maps = this.state.keyMaps;
</span><span class="cx">       for (var i = 0; i &lt; maps.length; ++i)
</span><del>-        if (maps[i] == map || (typeof maps[i] != &quot;string&quot; &amp;&amp; maps[i].name == map)) {
</del><ins>+        if (maps[i] == map || maps[i].name == map) {
</ins><span class="cx">           maps.splice(i, 1);
</span><span class="cx">           return true;
</span><span class="cx">         }
</span><span class="lines">@@ -3911,11 +4895,14 @@
</span><span class="cx">       for (var i = 0; i &lt; ranges.length; i++) {
</span><span class="cx">         var range = ranges[i];
</span><span class="cx">         if (!range.empty()) {
</span><del>-          var start = Math.max(end, range.from().line);
-          var to = range.to();
</del><ins>+          var from = range.from(), to = range.to();
+          var start = Math.max(end, from.line);
</ins><span class="cx">           end = Math.min(this.lastLine(), to.line - (to.ch ? 0 : 1)) + 1;
</span><span class="cx">           for (var j = start; j &lt; end; ++j)
</span><span class="cx">             indentLine(this, j, how);
</span><ins>+          var newRanges = this.doc.sel.ranges;
+          if (from.ch == 0 &amp;&amp; ranges.length == newRanges.length &amp;&amp; newRanges[i].from().ch &gt; 0)
+            replaceOneSelection(this.doc, i, new Range(from, newRanges[i].to()), sel_dontScroll);
</ins><span class="cx">         } else if (range.head.line &gt; end) {
</span><span class="cx">           indentLine(this, range.head.line, how, true);
</span><span class="cx">           end = range.head.line;
</span><span class="lines">@@ -3927,22 +4914,13 @@
</span><span class="cx">     // Fetch the parser token for a given character. Useful for hacks
</span><span class="cx">     // that want to inspect the mode state (say, for completion).
</span><span class="cx">     getTokenAt: function(pos, precise) {
</span><del>-      var doc = this.doc;
-      pos = clipPos(doc, pos);
-      var state = getStateBefore(this, pos.line, precise), mode = this.doc.mode;
-      var line = getLine(doc, pos.line);
-      var stream = new StringStream(line.text, this.options.tabSize);
-      while (stream.pos &lt; pos.ch &amp;&amp; !stream.eol()) {
-        stream.start = stream.pos;
-        var style = readToken(mode, stream, state);
-      }
-      return {start: stream.start,
-              end: stream.pos,
-              string: stream.current(),
-              type: style || null,
-              state: state};
</del><ins>+      return takeToken(this, pos, precise);
</ins><span class="cx">     },
</span><span class="cx"> 
</span><ins>+    getLineTokens: function(line, precise) {
+      return takeToken(this, Pos(line), precise, true);
+    },
+
</ins><span class="cx">     getTokenTypeAt: function(pos) {
</span><span class="cx">       pos = clipPos(this.doc, pos);
</span><span class="cx">       var styles = getLineStyles(this, getLine(this.doc, pos.line));
</span><span class="lines">@@ -3971,7 +4949,7 @@
</span><span class="cx"> 
</span><span class="cx">     getHelpers: function(pos, type) {
</span><span class="cx">       var found = [];
</span><del>-      if (!helpers.hasOwnProperty(type)) return helpers;
</del><ins>+      if (!helpers.hasOwnProperty(type)) return found;
</ins><span class="cx">       var help = helpers[type], mode = this.getModeAt(pos);
</span><span class="cx">       if (typeof mode[type] == &quot;string&quot;) {
</span><span class="cx">         if (help[mode[type]]) found.push(help[mode[type]]);
</span><span class="lines">@@ -4021,10 +4999,15 @@
</span><span class="cx">       return lineAtHeight(this.doc, height + this.display.viewOffset);
</span><span class="cx">     },
</span><span class="cx">     heightAtLine: function(line, mode) {
</span><del>-      var end = false, last = this.doc.first + this.doc.size - 1;
-      if (line &lt; this.doc.first) line = this.doc.first;
-      else if (line &gt; last) { line = last; end = true; }
-      var lineObj = getLine(this.doc, line);
</del><ins>+      var end = false, lineObj;
+      if (typeof line == &quot;number&quot;) {
+        var last = this.doc.first + this.doc.size - 1;
+        if (line &lt; this.doc.first) line = this.doc.first;
+        else if (line &gt; last) { line = last; end = true; }
+        lineObj = getLine(this.doc, line);
+      } else {
+        lineObj = line;
+      }
</ins><span class="cx">       return intoCoordSystem(this, lineObj, {top: 0, left: 0}, mode || &quot;page&quot;).top +
</span><span class="cx">         (end ? this.doc.height - heightAtLine(lineObj) : 0);
</span><span class="cx">     },
</span><span class="lines">@@ -4033,7 +5016,7 @@
</span><span class="cx">     defaultCharWidth: function() { return charWidth(this.display); },
</span><span class="cx"> 
</span><span class="cx">     setGutterMarker: methodOp(function(line, gutterID, value) {
</span><del>-      return changeLine(this, line, &quot;gutter&quot;, function(line) {
</del><ins>+      return changeLine(this.doc, line, &quot;gutter&quot;, function(line) {
</ins><span class="cx">         var markers = line.gutterMarkers || (line.gutterMarkers = {});
</span><span class="cx">         markers[gutterID] = value;
</span><span class="cx">         if (!value &amp;&amp; isEmpty(markers)) line.gutterMarkers = null;
</span><span class="lines">@@ -4053,38 +5036,6 @@
</span><span class="cx">       });
</span><span class="cx">     }),
</span><span class="cx"> 
</span><del>-    addLineClass: methodOp(function(handle, where, cls) {
-      return changeLine(this, handle, &quot;class&quot;, function(line) {
-        var prop = where == &quot;text&quot; ? &quot;textClass&quot; : where == &quot;background&quot; ? &quot;bgClass&quot; : &quot;wrapClass&quot;;
-        if (!line[prop]) line[prop] = cls;
-        else if (new RegExp(&quot;(?:^|\\s)&quot; + cls + &quot;(?:$|\\s)&quot;).test(line[prop])) return false;
-        else line[prop] += &quot; &quot; + cls;
-        return true;
-      });
-    }),
-
-    removeLineClass: methodOp(function(handle, where, cls) {
-      return changeLine(this, handle, &quot;class&quot;, function(line) {
-        var prop = where == &quot;text&quot; ? &quot;textClass&quot; : where == &quot;background&quot; ? &quot;bgClass&quot; : &quot;wrapClass&quot;;
-        var cur = line[prop];
-        if (!cur) return false;
-        else if (cls == null) line[prop] = null;
-        else {
-          var found = cur.match(new RegExp(&quot;(?:^|\\s+)&quot; + cls + &quot;(?:$|\\s+)&quot;));
-          if (!found) return false;
-          var end = found.index + found[0].length;
-          line[prop] = cur.slice(0, found.index) + (!found.index || end == cur.length ? &quot;&quot; : &quot; &quot;) + cur.slice(end) || null;
-        }
-        return true;
-      });
-    }),
-
-    addLineWidget: methodOp(function(handle, node, options) {
-      return addLineWidget(this, handle, node, options);
-    }),
-
-    removeLineWidget: function(widget) { widget.clear(); },
-
</del><span class="cx">     lineInfo: function(line) {
</span><span class="cx">       if (typeof line == &quot;number&quot;) {
</span><span class="cx">         if (!isLine(this.doc, line)) return null;
</span><span class="lines">@@ -4107,6 +5058,8 @@
</span><span class="cx">       pos = cursorCoords(this, clipPos(this.doc, pos));
</span><span class="cx">       var top = pos.bottom, left = pos.left;
</span><span class="cx">       node.style.position = &quot;absolute&quot;;
</span><ins>+      node.setAttribute(&quot;cm-ignore-events&quot;, &quot;true&quot;);
+      this.display.input.setUneditable(node);
</ins><span class="cx">       display.sizer.appendChild(node);
</span><span class="cx">       if (vert == &quot;over&quot;) {
</span><span class="cx">         top = pos.top;
</span><span class="lines">@@ -4137,13 +5090,15 @@
</span><span class="cx"> 
</span><span class="cx">     triggerOnKeyDown: methodOp(onKeyDown),
</span><span class="cx">     triggerOnKeyPress: methodOp(onKeyPress),
</span><del>-    triggerOnKeyUp: methodOp(onKeyUp),
</del><ins>+    triggerOnKeyUp: onKeyUp,
</ins><span class="cx"> 
</span><span class="cx">     execCommand: function(cmd) {
</span><span class="cx">       if (commands.hasOwnProperty(cmd))
</span><del>-        return commands[cmd](this);
</del><ins>+        return commands[cmd].call(null, this);
</ins><span class="cx">     },
</span><span class="cx"> 
</span><ins>+    triggerElectric: methodOp(function(text) { triggerElectric(this, text); }),
+
</ins><span class="cx">     findPosH: function(from, amount, unit, visually) {
</span><span class="cx">       var dir = 1;
</span><span class="cx">       if (amount &lt; 0) { dir = -1; amount = -amount; }
</span><span class="lines">@@ -4206,6 +5161,24 @@
</span><span class="cx">         doc.sel.ranges[i].goalColumn = goals[i];
</span><span class="cx">     }),
</span><span class="cx"> 
</span><ins>+    // Find the word at the given position (as returned by coordsChar).
+    findWordAt: function(pos) {
+      var doc = this.doc, line = getLine(doc, pos.line).text;
+      var start = pos.ch, end = pos.ch;
+      if (line) {
+        var helper = this.getHelper(pos, &quot;wordChars&quot;);
+        if ((pos.xRel &lt; 0 || end == line.length) &amp;&amp; start) --start; else ++end;
+        var startChar = line.charAt(start);
+        var check = isWordChar(startChar, helper)
+          ? function(ch) { return isWordChar(ch, helper); }
+          : /\s/.test(startChar) ? function(ch) {return /\s/.test(ch);}
+          : function(ch) {return !/\s/.test(ch) &amp;&amp; !isWordChar(ch);};
+        while (start &gt; 0 &amp;&amp; check(line.charAt(start - 1))) --start;
+        while (end &lt; line.length &amp;&amp; check(line.charAt(end))) ++end;
+      }
+      return new Range(Pos(pos.line, start), Pos(pos.line, end));
+    },
+
</ins><span class="cx">     toggleOverwrite: function(value) {
</span><span class="cx">       if (value != null &amp;&amp; value == this.state.overwrite) return;
</span><span class="cx">       if (this.state.overwrite = !this.state.overwrite)
</span><span class="lines">@@ -4215,7 +5188,7 @@
</span><span class="cx"> 
</span><span class="cx">       signal(this, &quot;overwriteToggle&quot;, this, this.state.overwrite);
</span><span class="cx">     },
</span><del>-    hasFocus: function() { return activeElt() == this.display.input; },
</del><ins>+    hasFocus: function() { return this.display.input.getField() == activeElt(); },
</ins><span class="cx"> 
</span><span class="cx">     scrollTo: methodOp(function(x, y) {
</span><span class="cx">       if (x != null || y != null) resolveScrollToPos(this);
</span><span class="lines">@@ -4223,10 +5196,11 @@
</span><span class="cx">       if (y != null) this.curOp.scrollTop = y;
</span><span class="cx">     }),
</span><span class="cx">     getScrollInfo: function() {
</span><del>-      var scroller = this.display.scroller, co = scrollerCutOff;
</del><ins>+      var scroller = this.display.scroller;
</ins><span class="cx">       return {left: scroller.scrollLeft, top: scroller.scrollTop,
</span><del>-              height: scroller.scrollHeight - co, width: scroller.scrollWidth - co,
-              clientHeight: scroller.clientHeight - co, clientWidth: scroller.clientWidth - co};
</del><ins>+              height: scroller.scrollHeight - scrollGap(this) - this.display.barHeight,
+              width: scroller.scrollWidth - scrollGap(this) - this.display.barWidth,
+              clientHeight: displayHeight(this), clientWidth: displayWidth(this)};
</ins><span class="cx">     },
</span><span class="cx"> 
</span><span class="cx">     scrollIntoView: methodOp(function(range, margin) {
</span><span class="lines">@@ -4254,14 +5228,21 @@
</span><span class="cx">     }),
</span><span class="cx"> 
</span><span class="cx">     setSize: methodOp(function(width, height) {
</span><ins>+      var cm = this;
</ins><span class="cx">       function interpret(val) {
</span><span class="cx">         return typeof val == &quot;number&quot; || /^\d+$/.test(String(val)) ? val + &quot;px&quot; : val;
</span><span class="cx">       }
</span><del>-      if (width != null) this.display.wrapper.style.width = interpret(width);
-      if (height != null) this.display.wrapper.style.height = interpret(height);
-      if (this.options.lineWrapping) clearLineMeasurementCache(this);
-      this.curOp.forceUpdate = true;
-      signal(this, &quot;refresh&quot;, this);
</del><ins>+      if (width != null) cm.display.wrapper.style.width = interpret(width);
+      if (height != null) cm.display.wrapper.style.height = interpret(height);
+      if (cm.options.lineWrapping) clearLineMeasurementCache(this);
+      var lineNo = cm.display.viewFrom;
+      cm.doc.iter(lineNo, cm.display.viewTo, function(line) {
+        if (line.widgets) for (var i = 0; i &lt; line.widgets.length; i++)
+          if (line.widgets[i].noHScroll) { regLineChange(cm, lineNo, &quot;widget&quot;); break; }
+        ++lineNo;
+      });
+      cm.curOp.forceUpdate = true;
+      signal(cm, &quot;refresh&quot;, this);
</ins><span class="cx">     }),
</span><span class="cx"> 
</span><span class="cx">     operation: function(f){return runInOp(this, f);},
</span><span class="lines">@@ -4283,13 +5264,14 @@
</span><span class="cx">       old.cm = null;
</span><span class="cx">       attachDoc(this, doc);
</span><span class="cx">       clearCaches(this);
</span><del>-      resetInput(this);
</del><ins>+      this.display.input.reset();
</ins><span class="cx">       this.scrollTo(doc.scrollLeft, doc.scrollTop);
</span><ins>+      this.curOp.forceScroll = true;
</ins><span class="cx">       signalLater(this, &quot;swapDoc&quot;, this, old);
</span><span class="cx">       return old;
</span><span class="cx">     }),
</span><span class="cx"> 
</span><del>-    getInputField: function(){return this.display.input;},
</del><ins>+    getInputField: function(){return this.display.input.getField();},
</ins><span class="cx">     getWrapperElement: function(){return this.display.wrapper;},
</span><span class="cx">     getScrollerElement: function(){return this.display.scroller;},
</span><span class="cx">     getGutterElement: function(){return this.display.gutters;}
</span><span class="lines">@@ -4330,12 +5312,31 @@
</span><span class="cx">     clearCaches(cm);
</span><span class="cx">     regChange(cm);
</span><span class="cx">   }, true);
</span><del>-  option(&quot;specialChars&quot;, /[\t\u0000-\u0019\u00ad\u200b\u2028\u2029\ufeff]/g, function(cm, val) {
-    cm.options.specialChars = new RegExp(val.source + (val.test(&quot;\t&quot;) ? &quot;&quot; : &quot;|\t&quot;), &quot;g&quot;);
-    cm.refresh();
-  }, true);
</del><ins>+  option(&quot;lineSeparator&quot;, null, function(cm, val) {
+    cm.doc.lineSep = val;
+    if (!val) return;
+    var newBreaks = [], lineNo = cm.doc.first;
+    cm.doc.iter(function(line) {
+      for (var pos = 0;;) {
+        var found = line.text.indexOf(val, pos);
+        if (found == -1) break;
+        pos = found + val.length;
+        newBreaks.push(Pos(lineNo, found));
+      }
+      lineNo++;
+    });
+    for (var i = newBreaks.length - 1; i &gt;= 0; i--)
+      replaceRange(cm.doc, val, newBreaks[i], Pos(newBreaks[i].line, newBreaks[i].ch + val.length))
+  });
+  option(&quot;specialChars&quot;, /[\t\u0000-\u0019\u00ad\u200b-\u200f\u2028\u2029\ufeff]/g, function(cm, val, old) {
+    cm.state.specialChars = new RegExp(val.source + (val.test(&quot;\t&quot;) ? &quot;&quot; : &quot;|\t&quot;), &quot;g&quot;);
+    if (old != CodeMirror.Init) cm.refresh();
+  });
</ins><span class="cx">   option(&quot;specialCharPlaceholder&quot;, defaultSpecialCharPlaceholder, function(cm) {cm.refresh();}, true);
</span><span class="cx">   option(&quot;electricChars&quot;, true);
</span><ins>+  option(&quot;inputStyle&quot;, mobile ? &quot;contenteditable&quot; : &quot;textarea&quot;, function() {
+    throw new Error(&quot;inputStyle can not (yet) be changed in a running editor&quot;); // FIXME
+  }, true);
</ins><span class="cx">   option(&quot;rtlMoveVisually&quot;, !windows);
</span><span class="cx">   option(&quot;wholeLineUpdateBefore&quot;, true);
</span><span class="cx"> 
</span><span class="lines">@@ -4343,7 +5344,12 @@
</span><span class="cx">     themeChanged(cm);
</span><span class="cx">     guttersChanged(cm);
</span><span class="cx">   }, true);
</span><del>-  option(&quot;keyMap&quot;, &quot;default&quot;, keyMapChanged);
</del><ins>+  option(&quot;keyMap&quot;, &quot;default&quot;, function(cm, val, old) {
+    var next = getKeyMap(val);
+    var prev = old != CodeMirror.Init &amp;&amp; getKeyMap(old);
+    if (prev &amp;&amp; prev.detach) prev.detach(cm, next);
+    if (next.attach) next.attach(cm, prev || null);
+  });
</ins><span class="cx">   option(&quot;extraKeys&quot;, null);
</span><span class="cx"> 
</span><span class="cx">   option(&quot;lineWrapping&quot;, false, wrappingChanged, true);
</span><span class="lines">@@ -4355,7 +5361,13 @@
</span><span class="cx">     cm.display.gutters.style.left = val ? compensateForHScroll(cm.display) + &quot;px&quot; : &quot;0&quot;;
</span><span class="cx">     cm.refresh();
</span><span class="cx">   }, true);
</span><del>-  option(&quot;coverGutterNextToScrollbar&quot;, false, updateScrollbars, true);
</del><ins>+  option(&quot;coverGutterNextToScrollbar&quot;, false, function(cm) {updateScrollbars(cm);}, true);
+  option(&quot;scrollbarStyle&quot;, &quot;native&quot;, function(cm) {
+    initScrollbars(cm);
+    updateScrollbars(cm);
+    cm.display.scrollbars.setScrollTop(cm.doc.scrollTop);
+    cm.display.scrollbars.setScrollLeft(cm.doc.scrollLeft);
+  }, true);
</ins><span class="cx">   option(&quot;lineNumbers&quot;, false, function(cm) {
</span><span class="cx">     setGuttersForLineNumbers(cm.options);
</span><span class="cx">     guttersChanged(cm);
</span><span class="lines">@@ -4365,6 +5377,7 @@
</span><span class="cx">   option(&quot;showCursorWhenSelecting&quot;, false, updateSelection, true);
</span><span class="cx"> 
</span><span class="cx">   option(&quot;resetSelectionOnContextMenu&quot;, true);
</span><ins>+  option(&quot;lineWiseCopyCut&quot;, true);
</ins><span class="cx"> 
</span><span class="cx">   option(&quot;readOnly&quot;, false, function(cm, val) {
</span><span class="cx">     if (val == &quot;nocursor&quot;) {
</span><span class="lines">@@ -4373,15 +5386,16 @@
</span><span class="cx">       cm.display.disabled = true;
</span><span class="cx">     } else {
</span><span class="cx">       cm.display.disabled = false;
</span><del>-      if (!val) resetInput(cm);
</del><ins>+      if (!val) cm.display.input.reset();
</ins><span class="cx">     }
</span><span class="cx">   });
</span><del>-  option(&quot;disableInput&quot;, false, function(cm, val) {if (!val) resetInput(cm);}, true);
-  option(&quot;dragDrop&quot;, true);
</del><ins>+  option(&quot;disableInput&quot;, false, function(cm, val) {if (!val) cm.display.input.reset();}, true);
+  option(&quot;dragDrop&quot;, true, dragDropChanged);
</ins><span class="cx"> 
</span><span class="cx">   option(&quot;cursorBlinkRate&quot;, 530);
</span><span class="cx">   option(&quot;cursorScrollMargin&quot;, 0);
</span><del>-  option(&quot;cursorHeight&quot;, 1);
</del><ins>+  option(&quot;cursorHeight&quot;, 1, updateSelection, true);
+  option(&quot;singleCursorHeightPerLine&quot;, true, updateSelection, true);
</ins><span class="cx">   option(&quot;workTime&quot;, 100);
</span><span class="cx">   option(&quot;workDelay&quot;, 100);
</span><span class="cx">   option(&quot;flattenSpans&quot;, true, resetModeState, true);
</span><span class="lines">@@ -4392,11 +5406,11 @@
</span><span class="cx">   option(&quot;viewportMargin&quot;, 10, function(cm){cm.refresh();}, true);
</span><span class="cx">   option(&quot;maxHighlightLength&quot;, 10000, resetModeState, true);
</span><span class="cx">   option(&quot;moveInputWithCursor&quot;, true, function(cm, val) {
</span><del>-    if (!val) cm.display.inputDiv.style.top = cm.display.inputDiv.style.left = 0;
</del><ins>+    if (!val) cm.display.input.resetPosition();
</ins><span class="cx">   });
</span><span class="cx"> 
</span><span class="cx">   option(&quot;tabindex&quot;, null, function(cm, val) {
</span><del>-    cm.display.input.tabIndex = val || &quot;&quot;;
</del><ins>+    cm.display.input.getField().tabIndex = val || &quot;&quot;;
</ins><span class="cx">   });
</span><span class="cx">   option(&quot;autofocus&quot;, null);
</span><span class="cx"> 
</span><span class="lines">@@ -4410,10 +5424,8 @@
</span><span class="cx">   // load a mode. (Preferred mechanism is the require/define calls.)
</span><span class="cx">   CodeMirror.defineMode = function(name, mode) {
</span><span class="cx">     if (!CodeMirror.defaults.mode &amp;&amp; name != &quot;null&quot;) CodeMirror.defaults.mode = name;
</span><del>-    if (arguments.length &gt; 2) {
-      mode.dependencies = [];
-      for (var i = 2; i &lt; arguments.length; ++i) mode.dependencies.push(arguments[i]);
-    }
</del><ins>+    if (arguments.length &gt; 2)
+      mode.dependencies = Array.prototype.slice.call(arguments, 2);
</ins><span class="cx">     modes[name] = mode;
</span><span class="cx">   };
</span><span class="cx"> 
</span><span class="lines">@@ -4564,6 +5576,20 @@
</span><span class="cx">         return {from: Pos(range.from().line, 0), to: range.from()};
</span><span class="cx">       });
</span><span class="cx">     },
</span><ins>+    delWrappedLineLeft: function(cm) {
+      deleteNearSelection(cm, function(range) {
+        var top = cm.charCoords(range.head, &quot;div&quot;).top + 5;
+        var leftPos = cm.coordsChar({left: 0, top: top}, &quot;div&quot;);
+        return {from: leftPos, to: range.from()};
+      });
+    },
+    delWrappedLineRight: function(cm) {
+      deleteNearSelection(cm, function(range) {
+        var top = cm.charCoords(range.head, &quot;div&quot;).top + 5;
+        var rightPos = cm.coordsChar({left: cm.display.lineDiv.offsetWidth + 100, top: top}, &quot;div&quot;);
+        return {from: range.from(), to: rightPos };
+      });
+    },
</ins><span class="cx">     undo: function(cm) {cm.undo();},
</span><span class="cx">     redo: function(cm) {cm.redo();},
</span><span class="cx">     undoSelection: function(cm) {cm.undoSelection();},
</span><span class="lines">@@ -4571,23 +5597,17 @@
</span><span class="cx">     goDocStart: function(cm) {cm.extendSelection(Pos(cm.firstLine(), 0));},
</span><span class="cx">     goDocEnd: function(cm) {cm.extendSelection(Pos(cm.lastLine()));},
</span><span class="cx">     goLineStart: function(cm) {
</span><del>-      cm.extendSelectionsBy(function(range) { return lineStart(cm, range.head.line); }, sel_move);
</del><ins>+      cm.extendSelectionsBy(function(range) { return lineStart(cm, range.head.line); },
+                            {origin: &quot;+move&quot;, bias: 1});
</ins><span class="cx">     },
</span><span class="cx">     goLineStartSmart: function(cm) {
</span><span class="cx">       cm.extendSelectionsBy(function(range) {
</span><del>-        var start = lineStart(cm, range.head.line);
-        var line = cm.getLineHandle(start.line);
-        var order = getOrder(line);
-        if (!order || order[0].level == 0) {
-          var firstNonWS = Math.max(0, line.text.search(/\S/));
-          var inWS = range.head.line == start.line &amp;&amp; range.head.ch &lt;= firstNonWS &amp;&amp; range.head.ch;
-          return Pos(start.line, inWS ? 0 : firstNonWS);
-        }
-        return start;
-      }, sel_move);
</del><ins>+        return lineStartSmart(cm, range.head);
+      }, {origin: &quot;+move&quot;, bias: 1});
</ins><span class="cx">     },
</span><span class="cx">     goLineEnd: function(cm) {
</span><del>-      cm.extendSelectionsBy(function(range) { return lineEnd(cm, range.head.line); }, sel_move);
</del><ins>+      cm.extendSelectionsBy(function(range) { return lineEnd(cm, range.head.line); },
+                            {origin: &quot;+move&quot;, bias: -1});
</ins><span class="cx">     },
</span><span class="cx">     goLineRight: function(cm) {
</span><span class="cx">       cm.extendSelectionsBy(function(range) {
</span><span class="lines">@@ -4601,6 +5621,14 @@
</span><span class="cx">         return cm.coordsChar({left: 0, top: top}, &quot;div&quot;);
</span><span class="cx">       }, sel_move);
</span><span class="cx">     },
</span><ins>+    goLineLeftSmart: function(cm) {
+      cm.extendSelectionsBy(function(range) {
+        var top = cm.charCoords(range.head, &quot;div&quot;).top + 5;
+        var pos = cm.coordsChar({left: 0, top: top}, &quot;div&quot;);
+        if (pos.ch &lt; cm.getLine(pos.line).search(/\S/)) return lineStartSmart(cm, range.head);
+        return pos;
+      }, sel_move);
+    },
</ins><span class="cx">     goLineUp: function(cm) {cm.moveV(-1, &quot;line&quot;);},
</span><span class="cx">     goLineDown: function(cm) {cm.moveV(1, &quot;line&quot;);},
</span><span class="cx">     goPageUp: function(cm) {cm.moveV(-1, &quot;page&quot;);},
</span><span class="lines">@@ -4650,7 +5678,8 @@
</span><span class="cx">             } else if (cur.line &gt; cm.doc.first) {
</span><span class="cx">               var prev = getLine(cm.doc, cur.line - 1).text;
</span><span class="cx">               if (prev)
</span><del>-                cm.replaceRange(line.charAt(0) + &quot;\n&quot; + prev.charAt(prev.length - 1),
</del><ins>+                cm.replaceRange(line.charAt(0) + cm.doc.lineSeparator() +
+                                prev.charAt(prev.length - 1),
</ins><span class="cx">                                 Pos(cur.line - 1, prev.length - 1), Pos(cur.line, 1), &quot;+transpose&quot;);
</span><span class="cx">             }
</span><span class="cx">           }
</span><span class="lines">@@ -4664,7 +5693,7 @@
</span><span class="cx">         var len = cm.listSelections().length;
</span><span class="cx">         for (var i = 0; i &lt; len; i++) {
</span><span class="cx">           var range = cm.listSelections()[i];
</span><del>-          cm.replaceRange(&quot;\n&quot;, range.anchor, range.head, &quot;+input&quot;);
</del><ins>+          cm.replaceRange(cm.doc.lineSeparator(), range.anchor, range.head, &quot;+input&quot;);
</ins><span class="cx">           cm.indentLine(range.from().line + 1, null, true);
</span><span class="cx">           ensureCursorVisible(cm);
</span><span class="cx">         }
</span><span class="lines">@@ -4673,9 +5702,11 @@
</span><span class="cx">     toggleOverwrite: function(cm) {cm.toggleOverwrite();}
</span><span class="cx">   };
</span><span class="cx"> 
</span><ins>+
</ins><span class="cx">   // STANDARD KEYMAPS
</span><span class="cx"> 
</span><span class="cx">   var keyMap = CodeMirror.keyMap = {};
</span><ins>+
</ins><span class="cx">   keyMap.basic = {
</span><span class="cx">     &quot;Left&quot;: &quot;goCharLeft&quot;, &quot;Right&quot;: &quot;goCharRight&quot;, &quot;Up&quot;: &quot;goLineUp&quot;, &quot;Down&quot;: &quot;goLineDown&quot;,
</span><span class="cx">     &quot;End&quot;: &quot;goLineEnd&quot;, &quot;Home&quot;: &quot;goLineStartSmart&quot;, &quot;PageUp&quot;: &quot;goPageUp&quot;, &quot;PageDown&quot;: &quot;goPageDown&quot;,
</span><span class="lines">@@ -4689,7 +5720,7 @@
</span><span class="cx">   // are simply ignored.
</span><span class="cx">   keyMap.pcDefault = {
</span><span class="cx">     &quot;Ctrl-A&quot;: &quot;selectAll&quot;, &quot;Ctrl-D&quot;: &quot;deleteLine&quot;, &quot;Ctrl-Z&quot;: &quot;undo&quot;, &quot;Shift-Ctrl-Z&quot;: &quot;redo&quot;, &quot;Ctrl-Y&quot;: &quot;redo&quot;,
</span><del>-    &quot;Ctrl-Home&quot;: &quot;goDocStart&quot;, &quot;Ctrl-Up&quot;: &quot;goDocStart&quot;, &quot;Ctrl-End&quot;: &quot;goDocEnd&quot;, &quot;Ctrl-Down&quot;: &quot;goDocEnd&quot;,
</del><ins>+    &quot;Ctrl-Home&quot;: &quot;goDocStart&quot;, &quot;Ctrl-End&quot;: &quot;goDocEnd&quot;, &quot;Ctrl-Up&quot;: &quot;goLineUp&quot;, &quot;Ctrl-Down&quot;: &quot;goLineDown&quot;,
</ins><span class="cx">     &quot;Ctrl-Left&quot;: &quot;goGroupLeft&quot;, &quot;Ctrl-Right&quot;: &quot;goGroupRight&quot;, &quot;Alt-Left&quot;: &quot;goLineStart&quot;, &quot;Alt-Right&quot;: &quot;goLineEnd&quot;,
</span><span class="cx">     &quot;Ctrl-Backspace&quot;: &quot;delGroupBefore&quot;, &quot;Ctrl-Delete&quot;: &quot;delGroupAfter&quot;, &quot;Ctrl-S&quot;: &quot;save&quot;, &quot;Ctrl-F&quot;: &quot;find&quot;,
</span><span class="cx">     &quot;Ctrl-G&quot;: &quot;findNext&quot;, &quot;Shift-Ctrl-G&quot;: &quot;findPrev&quot;, &quot;Shift-Ctrl-F&quot;: &quot;replace&quot;, &quot;Shift-Ctrl-R&quot;: &quot;replaceAll&quot;,
</span><span class="lines">@@ -4697,16 +5728,6 @@
</span><span class="cx">     &quot;Ctrl-U&quot;: &quot;undoSelection&quot;, &quot;Shift-Ctrl-U&quot;: &quot;redoSelection&quot;, &quot;Alt-U&quot;: &quot;redoSelection&quot;,
</span><span class="cx">     fallthrough: &quot;basic&quot;
</span><span class="cx">   };
</span><del>-  keyMap.macDefault = {
-    &quot;Cmd-A&quot;: &quot;selectAll&quot;, &quot;Cmd-D&quot;: &quot;deleteLine&quot;, &quot;Cmd-Z&quot;: &quot;undo&quot;, &quot;Shift-Cmd-Z&quot;: &quot;redo&quot;, &quot;Cmd-Y&quot;: &quot;redo&quot;,
-    &quot;Cmd-Up&quot;: &quot;goDocStart&quot;, &quot;Cmd-End&quot;: &quot;goDocEnd&quot;, &quot;Cmd-Down&quot;: &quot;goDocEnd&quot;, &quot;Alt-Left&quot;: &quot;goGroupLeft&quot;,
-    &quot;Alt-Right&quot;: &quot;goGroupRight&quot;, &quot;Cmd-Left&quot;: &quot;goLineStart&quot;, &quot;Cmd-Right&quot;: &quot;goLineEnd&quot;, &quot;Alt-Backspace&quot;: &quot;delGroupBefore&quot;,
-    &quot;Ctrl-Alt-Backspace&quot;: &quot;delGroupAfter&quot;, &quot;Alt-Delete&quot;: &quot;delGroupAfter&quot;, &quot;Cmd-S&quot;: &quot;save&quot;, &quot;Cmd-F&quot;: &quot;find&quot;,
-    &quot;Cmd-G&quot;: &quot;findNext&quot;, &quot;Shift-Cmd-G&quot;: &quot;findPrev&quot;, &quot;Cmd-Alt-F&quot;: &quot;replace&quot;, &quot;Shift-Cmd-Alt-F&quot;: &quot;replaceAll&quot;,
-    &quot;Cmd-[&quot;: &quot;indentLess&quot;, &quot;Cmd-]&quot;: &quot;indentMore&quot;, &quot;Cmd-Backspace&quot;: &quot;delLineLeft&quot;,
-    &quot;Cmd-U&quot;: &quot;undoSelection&quot;, &quot;Shift-Cmd-U&quot;: &quot;redoSelection&quot;,
-    fallthrough: [&quot;basic&quot;, &quot;emacsy&quot;]
-  };
</del><span class="cx">   // Very basic readline/emacs-style bindings, which are standard on Mac.
</span><span class="cx">   keyMap.emacsy = {
</span><span class="cx">     &quot;Ctrl-F&quot;: &quot;goCharRight&quot;, &quot;Ctrl-B&quot;: &quot;goCharLeft&quot;, &quot;Ctrl-P&quot;: &quot;goLineUp&quot;, &quot;Ctrl-N&quot;: &quot;goLineDown&quot;,
</span><span class="lines">@@ -4714,70 +5735,117 @@
</span><span class="cx">     &quot;Ctrl-V&quot;: &quot;goPageDown&quot;, &quot;Shift-Ctrl-V&quot;: &quot;goPageUp&quot;, &quot;Ctrl-D&quot;: &quot;delCharAfter&quot;, &quot;Ctrl-H&quot;: &quot;delCharBefore&quot;,
</span><span class="cx">     &quot;Alt-D&quot;: &quot;delWordAfter&quot;, &quot;Alt-Backspace&quot;: &quot;delWordBefore&quot;, &quot;Ctrl-K&quot;: &quot;killLine&quot;, &quot;Ctrl-T&quot;: &quot;transposeChars&quot;
</span><span class="cx">   };
</span><ins>+  keyMap.macDefault = {
+    &quot;Cmd-A&quot;: &quot;selectAll&quot;, &quot;Cmd-D&quot;: &quot;deleteLine&quot;, &quot;Cmd-Z&quot;: &quot;undo&quot;, &quot;Shift-Cmd-Z&quot;: &quot;redo&quot;, &quot;Cmd-Y&quot;: &quot;redo&quot;,
+    &quot;Cmd-Home&quot;: &quot;goDocStart&quot;, &quot;Cmd-Up&quot;: &quot;goDocStart&quot;, &quot;Cmd-End&quot;: &quot;goDocEnd&quot;, &quot;Cmd-Down&quot;: &quot;goDocEnd&quot;, &quot;Alt-Left&quot;: &quot;goGroupLeft&quot;,
+    &quot;Alt-Right&quot;: &quot;goGroupRight&quot;, &quot;Cmd-Left&quot;: &quot;goLineLeft&quot;, &quot;Cmd-Right&quot;: &quot;goLineRight&quot;, &quot;Alt-Backspace&quot;: &quot;delGroupBefore&quot;,
+    &quot;Ctrl-Alt-Backspace&quot;: &quot;delGroupAfter&quot;, &quot;Alt-Delete&quot;: &quot;delGroupAfter&quot;, &quot;Cmd-S&quot;: &quot;save&quot;, &quot;Cmd-F&quot;: &quot;find&quot;,
+    &quot;Cmd-G&quot;: &quot;findNext&quot;, &quot;Shift-Cmd-G&quot;: &quot;findPrev&quot;, &quot;Cmd-Alt-F&quot;: &quot;replace&quot;, &quot;Shift-Cmd-Alt-F&quot;: &quot;replaceAll&quot;,
+    &quot;Cmd-[&quot;: &quot;indentLess&quot;, &quot;Cmd-]&quot;: &quot;indentMore&quot;, &quot;Cmd-Backspace&quot;: &quot;delWrappedLineLeft&quot;, &quot;Cmd-Delete&quot;: &quot;delWrappedLineRight&quot;,
+    &quot;Cmd-U&quot;: &quot;undoSelection&quot;, &quot;Shift-Cmd-U&quot;: &quot;redoSelection&quot;, &quot;Ctrl-Up&quot;: &quot;goDocStart&quot;, &quot;Ctrl-Down&quot;: &quot;goDocEnd&quot;,
+    fallthrough: [&quot;basic&quot;, &quot;emacsy&quot;]
+  };
</ins><span class="cx">   keyMap[&quot;default&quot;] = mac ? keyMap.macDefault : keyMap.pcDefault;
</span><span class="cx"> 
</span><span class="cx">   // KEYMAP DISPATCH
</span><span class="cx"> 
</span><del>-  function getKeyMap(val) {
-    if (typeof val == &quot;string&quot;) return keyMap[val];
-    else return val;
</del><ins>+  function normalizeKeyName(name) {
+    var parts = name.split(/-(?!$)/), name = parts[parts.length - 1];
+    var alt, ctrl, shift, cmd;
+    for (var i = 0; i &lt; parts.length - 1; i++) {
+      var mod = parts[i];
+      if (/^(cmd|meta|m)$/i.test(mod)) cmd = true;
+      else if (/^a(lt)?$/i.test(mod)) alt = true;
+      else if (/^(c|ctrl|control)$/i.test(mod)) ctrl = true;
+      else if (/^s(hift)$/i.test(mod)) shift = true;
+      else throw new Error(&quot;Unrecognized modifier name: &quot; + mod);
+    }
+    if (alt) name = &quot;Alt-&quot; + name;
+    if (ctrl) name = &quot;Ctrl-&quot; + name;
+    if (cmd) name = &quot;Cmd-&quot; + name;
+    if (shift) name = &quot;Shift-&quot; + name;
+    return name;
</ins><span class="cx">   }
</span><span class="cx"> 
</span><del>-  // Given an array of keymaps and a key name, call handle on any
-  // bindings found, until that returns a truthy value, at which point
-  // we consider the key handled. Implements things like binding a key
-  // to false stopping further handling and keymap fallthrough.
-  var lookupKey = CodeMirror.lookupKey = function(name, maps, handle) {
-    function lookup(map) {
-      map = getKeyMap(map);
-      var found = map[name];
-      if (found === false) return &quot;stop&quot;;
-      if (found != null &amp;&amp; handle(found)) return true;
-      if (map.nofallthrough) return &quot;stop&quot;;
</del><ins>+  // This is a kludge to keep keymaps mostly working as raw objects
+  // (backwards compatibility) while at the same time support features
+  // like normalization and multi-stroke key bindings. It compiles a
+  // new normalized keymap, and then updates the old object to reflect
+  // this.
+  CodeMirror.normalizeKeyMap = function(keymap) {
+    var copy = {};
+    for (var keyname in keymap) if (keymap.hasOwnProperty(keyname)) {
+      var value = keymap[keyname];
+      if (/^(name|fallthrough|(de|at)tach)$/.test(keyname)) continue;
+      if (value == &quot;...&quot;) { delete keymap[keyname]; continue; }
</ins><span class="cx"> 
</span><del>-      var fallthrough = map.fallthrough;
-      if (fallthrough == null) return false;
-      if (Object.prototype.toString.call(fallthrough) != &quot;[object Array]&quot;)
-        return lookup(fallthrough);
-      for (var i = 0; i &lt; fallthrough.length; ++i) {
-        var done = lookup(fallthrough[i]);
-        if (done) return done;
</del><ins>+      var keys = map(keyname.split(&quot; &quot;), normalizeKeyName);
+      for (var i = 0; i &lt; keys.length; i++) {
+        var val, name;
+        if (i == keys.length - 1) {
+          name = keys.join(&quot; &quot;);
+          val = value;
+        } else {
+          name = keys.slice(0, i + 1).join(&quot; &quot;);
+          val = &quot;...&quot;;
+        }
+        var prev = copy[name];
+        if (!prev) copy[name] = val;
+        else if (prev != val) throw new Error(&quot;Inconsistent bindings for &quot; + name);
</ins><span class="cx">       }
</span><del>-      return false;
</del><ins>+      delete keymap[keyname];
</ins><span class="cx">     }
</span><ins>+    for (var prop in copy) keymap[prop] = copy[prop];
+    return keymap;
+  };
</ins><span class="cx"> 
</span><del>-    for (var i = 0; i &lt; maps.length; ++i) {
-      var done = lookup(maps[i]);
-      if (done) return done != &quot;stop&quot;;
</del><ins>+  var lookupKey = CodeMirror.lookupKey = function(key, map, handle, context) {
+    map = getKeyMap(map);
+    var found = map.call ? map.call(key, context) : map[key];
+    if (found === false) return &quot;nothing&quot;;
+    if (found === &quot;...&quot;) return &quot;multi&quot;;
+    if (found != null &amp;&amp; handle(found)) return &quot;handled&quot;;
+
+    if (map.fallthrough) {
+      if (Object.prototype.toString.call(map.fallthrough) != &quot;[object Array]&quot;)
+        return lookupKey(key, map.fallthrough, handle, context);
+      for (var i = 0; i &lt; map.fallthrough.length; i++) {
+        var result = lookupKey(key, map.fallthrough[i], handle, context);
+        if (result) return result;
+      }
</ins><span class="cx">     }
</span><span class="cx">   };
</span><span class="cx"> 
</span><span class="cx">   // Modifier key presses don't count as 'real' key presses for the
</span><span class="cx">   // purpose of keymap fallthrough.
</span><del>-  var isModifierKey = CodeMirror.isModifierKey = function(event) {
-    var name = keyNames[event.keyCode];
</del><ins>+  var isModifierKey = CodeMirror.isModifierKey = function(value) {
+    var name = typeof value == &quot;string&quot; ? value : keyNames[value.keyCode];
</ins><span class="cx">     return name == &quot;Ctrl&quot; || name == &quot;Alt&quot; || name == &quot;Shift&quot; || name == &quot;Mod&quot;;
</span><span class="cx">   };
</span><span class="cx"> 
</span><span class="cx">   // Look up the name of a key as indicated by an event object.
</span><span class="cx">   var keyName = CodeMirror.keyName = function(event, noShift) {
</span><span class="cx">     if (presto &amp;&amp; event.keyCode == 34 &amp;&amp; event[&quot;char&quot;]) return false;
</span><del>-    var name = keyNames[event.keyCode];
</del><ins>+    var base = keyNames[event.keyCode], name = base;
</ins><span class="cx">     if (name == null || event.altGraphKey) return false;
</span><del>-    if (event.altKey) name = &quot;Alt-&quot; + name;
-    if (flipCtrlCmd ? event.metaKey : event.ctrlKey) name = &quot;Ctrl-&quot; + name;
-    if (flipCtrlCmd ? event.ctrlKey : event.metaKey) name = &quot;Cmd-&quot; + name;
-    if (!noShift &amp;&amp; event.shiftKey) name = &quot;Shift-&quot; + name;
</del><ins>+    if (event.altKey &amp;&amp; base != &quot;Alt&quot;) name = &quot;Alt-&quot; + name;
+    if ((flipCtrlCmd ? event.metaKey : event.ctrlKey) &amp;&amp; base != &quot;Ctrl&quot;) name = &quot;Ctrl-&quot; + name;
+    if ((flipCtrlCmd ? event.ctrlKey : event.metaKey) &amp;&amp; base != &quot;Cmd&quot;) name = &quot;Cmd-&quot; + name;
+    if (!noShift &amp;&amp; event.shiftKey &amp;&amp; base != &quot;Shift&quot;) name = &quot;Shift-&quot; + name;
</ins><span class="cx">     return name;
</span><span class="cx">   };
</span><span class="cx"> 
</span><ins>+  function getKeyMap(val) {
+    return typeof val == &quot;string&quot; ? keyMap[val] : val;
+  }
+
</ins><span class="cx">   // FROMTEXTAREA
</span><span class="cx"> 
</span><span class="cx">   CodeMirror.fromTextArea = function(textarea, options) {
</span><del>-    if (!options) options = {};
</del><ins>+    options = options ? copyObj(options) : {};
</ins><span class="cx">     options.value = textarea.value;
</span><del>-    if (!options.tabindex &amp;&amp; textarea.tabindex)
-      options.tabindex = textarea.tabindex;
</del><ins>+    if (!options.tabindex &amp;&amp; textarea.tabIndex)
+      options.tabindex = textarea.tabIndex;
</ins><span class="cx">     if (!options.placeholder &amp;&amp; textarea.placeholder)
</span><span class="cx">       options.placeholder = textarea.placeholder;
</span><span class="cx">     // Set autofocus to true if this textarea is focused, or if it has
</span><span class="lines">@@ -4805,22 +5873,26 @@
</span><span class="cx">       }
</span><span class="cx">     }
</span><span class="cx"> 
</span><ins>+    options.finishInit = function(cm) {
+      cm.save = save;
+      cm.getTextArea = function() { return textarea; };
+      cm.toTextArea = function() {
+        cm.toTextArea = isNaN; // Prevent this from being ran twice
+        save();
+        textarea.parentNode.removeChild(cm.getWrapperElement());
+        textarea.style.display = &quot;&quot;;
+        if (textarea.form) {
+          off(textarea.form, &quot;submit&quot;, save);
+          if (typeof textarea.form.submit == &quot;function&quot;)
+            textarea.form.submit = realSubmit;
+        }
+      };
+    };
+
</ins><span class="cx">     textarea.style.display = &quot;none&quot;;
</span><span class="cx">     var cm = CodeMirror(function(node) {
</span><span class="cx">       textarea.parentNode.insertBefore(node, textarea.nextSibling);
</span><span class="cx">     }, options);
</span><del>-    cm.save = save;
-    cm.getTextArea = function() { return textarea; };
-    cm.toTextArea = function() {
-      save();
-      textarea.parentNode.removeChild(cm.getWrapperElement());
-      textarea.style.display = &quot;&quot;;
-      if (textarea.form) {
-        off(textarea.form, &quot;submit&quot;, save);
-        if (typeof textarea.form.submit == &quot;function&quot;)
-          textarea.form.submit = realSubmit;
-      }
-    };
</del><span class="cx">     return cm;
</span><span class="cx">   };
</span><span class="cx"> 
</span><span class="lines">@@ -4913,10 +5985,13 @@
</span><span class="cx">   // marker continues beyond the start/end of the line. Markers have
</span><span class="cx">   // links back to the lines they currently touch.
</span><span class="cx"> 
</span><ins>+  var nextMarkerId = 0;
+
</ins><span class="cx">   var TextMarker = CodeMirror.TextMarker = function(doc, type) {
</span><span class="cx">     this.lines = [];
</span><span class="cx">     this.type = type;
</span><span class="cx">     this.doc = doc;
</span><ins>+    this.id = ++nextMarkerId;
</ins><span class="cx">   };
</span><span class="cx">   eventMixin(TextMarker);
</span><span class="cx"> 
</span><span class="lines">@@ -5048,7 +6123,7 @@
</span><span class="cx">       // Showing up as a widget implies collapsed (widget replaces text)
</span><span class="cx">       marker.collapsed = true;
</span><span class="cx">       marker.widgetNode = elt(&quot;span&quot;, [marker.replacedWith], &quot;CodeMirror-widget&quot;);
</span><del>-      if (!options.handleMouseEvents) marker.widgetNode.ignoreEvents = true;
</del><ins>+      if (!options.handleMouseEvents) marker.widgetNode.setAttribute(&quot;cm-ignore-events&quot;, &quot;true&quot;);
</ins><span class="cx">       if (options.insertLeft) marker.widgetNode.insertLeft = true;
</span><span class="cx">     }
</span><span class="cx">     if (marker.collapsed) {
</span><span class="lines">@@ -5092,7 +6167,7 @@
</span><span class="cx">       if (updateMaxLine) cm.curOp.updateMaxLine = true;
</span><span class="cx">       if (marker.collapsed)
</span><span class="cx">         regChange(cm, from.line, to.line + 1);
</span><del>-      else if (marker.className || marker.title || marker.startStyle || marker.endStyle)
</del><ins>+      else if (marker.className || marker.title || marker.startStyle || marker.endStyle || marker.css)
</ins><span class="cx">         for (var i = from.line; i &lt;= to.line; i++) regLineChange(cm, i, &quot;text&quot;);
</span><span class="cx">       if (marker.atomic) reCheckSelection(cm.doc);
</span><span class="cx">       signalLater(cm, &quot;markerAdded&quot;, cm, marker);
</span><span class="lines">@@ -5232,6 +6307,7 @@
</span><span class="cx">   // spans partially within the change. Returns an array of span
</span><span class="cx">   // arrays with one element for each line in (after) the change.
</span><span class="cx">   function stretchSpansOverChange(doc, change) {
</span><ins>+    if (change.full) return null;
</ins><span class="cx">     var oldFirst = isLine(doc, change.from.line) &amp;&amp; getLine(doc, change.from.line).markedSpans;
</span><span class="cx">     var oldLast = isLine(doc, change.to.line) &amp;&amp; getLine(doc, change.to.line).markedSpans;
</span><span class="cx">     if (!oldFirst &amp;&amp; !oldLast) return null;
</span><span class="lines">@@ -5419,8 +6495,8 @@
</span><span class="cx">       var fromCmp = cmp(found.from, from) || extraLeft(sp.marker) - extraLeft(marker);
</span><span class="cx">       var toCmp = cmp(found.to, to) || extraRight(sp.marker) - extraRight(marker);
</span><span class="cx">       if (fromCmp &gt;= 0 &amp;&amp; toCmp &lt;= 0 || fromCmp &lt;= 0 &amp;&amp; toCmp &gt;= 0) continue;
</span><del>-      if (fromCmp &lt;= 0 &amp;&amp; (cmp(found.to, from) || extraRight(sp.marker) - extraLeft(marker)) &gt; 0 ||
-          fromCmp &gt;= 0 &amp;&amp; (cmp(found.from, to) || extraLeft(sp.marker) - extraRight(marker)) &lt; 0)
</del><ins>+      if (fromCmp &lt;= 0 &amp;&amp; (cmp(found.to, from) &gt; 0 || (sp.marker.inclusiveRight &amp;&amp; marker.inclusiveLeft)) ||
+          fromCmp &gt;= 0 &amp;&amp; (cmp(found.from, to) &lt; 0 || (sp.marker.inclusiveLeft &amp;&amp; marker.inclusiveRight)))
</ins><span class="cx">         return true;
</span><span class="cx">     }
</span><span class="cx">   }
</span><span class="lines">@@ -5499,10 +6575,10 @@
</span><span class="cx"> 
</span><span class="cx">   // Line widgets are block elements displayed above or below a line.
</span><span class="cx"> 
</span><del>-  var LineWidget = CodeMirror.LineWidget = function(cm, node, options) {
</del><ins>+  var LineWidget = CodeMirror.LineWidget = function(doc, node, options) {
</ins><span class="cx">     if (options) for (var opt in options) if (options.hasOwnProperty(opt))
</span><span class="cx">       this[opt] = options[opt];
</span><del>-    this.cm = cm;
</del><ins>+    this.doc = doc;
</ins><span class="cx">     this.node = node;
</span><span class="cx">   };
</span><span class="cx">   eventMixin(LineWidget);
</span><span class="lines">@@ -5513,46 +6589,55 @@
</span><span class="cx">   }
</span><span class="cx"> 
</span><span class="cx">   LineWidget.prototype.clear = function() {
</span><del>-    var cm = this.cm, ws = this.line.widgets, line = this.line, no = lineNo(line);
</del><ins>+    var cm = this.doc.cm, ws = this.line.widgets, line = this.line, no = lineNo(line);
</ins><span class="cx">     if (no == null || !ws) return;
</span><span class="cx">     for (var i = 0; i &lt; ws.length; ++i) if (ws[i] == this) ws.splice(i--, 1);
</span><span class="cx">     if (!ws.length) line.widgets = null;
</span><span class="cx">     var height = widgetHeight(this);
</span><del>-    runInOp(cm, function() {
</del><ins>+    updateLineHeight(line, Math.max(0, line.height - height));
+    if (cm) runInOp(cm, function() {
</ins><span class="cx">       adjustScrollWhenAboveVisible(cm, line, -height);
</span><span class="cx">       regLineChange(cm, no, &quot;widget&quot;);
</span><del>-      updateLineHeight(line, Math.max(0, line.height - height));
</del><span class="cx">     });
</span><span class="cx">   };
</span><span class="cx">   LineWidget.prototype.changed = function() {
</span><del>-    var oldH = this.height, cm = this.cm, line = this.line;
</del><ins>+    var oldH = this.height, cm = this.doc.cm, line = this.line;
</ins><span class="cx">     this.height = null;
</span><span class="cx">     var diff = widgetHeight(this) - oldH;
</span><span class="cx">     if (!diff) return;
</span><del>-    runInOp(cm, function() {
</del><ins>+    updateLineHeight(line, line.height + diff);
+    if (cm) runInOp(cm, function() {
</ins><span class="cx">       cm.curOp.forceUpdate = true;
</span><span class="cx">       adjustScrollWhenAboveVisible(cm, line, diff);
</span><del>-      updateLineHeight(line, line.height + diff);
</del><span class="cx">     });
</span><span class="cx">   };
</span><span class="cx"> 
</span><span class="cx">   function widgetHeight(widget) {
</span><span class="cx">     if (widget.height != null) return widget.height;
</span><del>-    if (!contains(document.body, widget.node))
-      removeChildrenAndAdd(widget.cm.display.measure, elt(&quot;div&quot;, [widget.node], null, &quot;position: relative&quot;));
</del><ins>+    var cm = widget.doc.cm;
+    if (!cm) return 0;
+    if (!contains(document.body, widget.node)) {
+      var parentStyle = &quot;position: relative;&quot;;
+      if (widget.coverGutter)
+        parentStyle += &quot;margin-left: -&quot; + cm.display.gutters.offsetWidth + &quot;px;&quot;;
+      if (widget.noHScroll)
+        parentStyle += &quot;width: &quot; + cm.display.wrapper.clientWidth + &quot;px;&quot;;
+      removeChildrenAndAdd(cm.display.measure, elt(&quot;div&quot;, [widget.node], null, parentStyle));
+    }
</ins><span class="cx">     return widget.height = widget.node.offsetHeight;
</span><span class="cx">   }
</span><span class="cx"> 
</span><del>-  function addLineWidget(cm, handle, node, options) {
-    var widget = new LineWidget(cm, node, options);
-    if (widget.noHScroll) cm.display.alignWidgets = true;
-    changeLine(cm, handle, &quot;widget&quot;, function(line) {
</del><ins>+  function addLineWidget(doc, handle, node, options) {
+    var widget = new LineWidget(doc, node, options);
+    var cm = doc.cm;
+    if (cm &amp;&amp; widget.noHScroll) cm.display.alignWidgets = true;
+    changeLine(doc, handle, &quot;widget&quot;, function(line) {
</ins><span class="cx">       var widgets = line.widgets || (line.widgets = []);
</span><span class="cx">       if (widget.insertAt == null) widgets.push(widget);
</span><span class="cx">       else widgets.splice(Math.min(widgets.length - 1, Math.max(0, widget.insertAt)), 0, widget);
</span><span class="cx">       widget.line = line;
</span><del>-      if (!lineIsHidden(cm.doc, line)) {
-        var aboveVisible = heightAtLine(line) &lt; cm.doc.scrollTop;
</del><ins>+      if (cm &amp;&amp; !lineIsHidden(doc, line)) {
+        var aboveVisible = heightAtLine(line) &lt; doc.scrollTop;
</ins><span class="cx">         updateLineHeight(line, line.height + widgetHeight(widget));
</span><span class="cx">         if (aboveVisible) addToScrollPos(cm, null, widget.height);
</span><span class="cx">         cm.curOp.forceUpdate = true;
</span><span class="lines">@@ -5615,20 +6700,44 @@
</span><span class="cx">     if (inner.mode.blankLine) return inner.mode.blankLine(inner.state);
</span><span class="cx">   }
</span><span class="cx"> 
</span><del>-  function readToken(mode, stream, state) {
</del><ins>+  function readToken(mode, stream, state, inner) {
</ins><span class="cx">     for (var i = 0; i &lt; 10; i++) {
</span><ins>+      if (inner) inner[0] = CodeMirror.innerMode(mode, state).mode;
</ins><span class="cx">       var style = mode.token(stream, state);
</span><span class="cx">       if (stream.pos &gt; stream.start) return style;
</span><span class="cx">     }
</span><span class="cx">     throw new Error(&quot;Mode &quot; + mode.name + &quot; failed to advance stream.&quot;);
</span><span class="cx">   }
</span><span class="cx"> 
</span><ins>+  // Utility for getTokenAt and getLineTokens
+  function takeToken(cm, pos, precise, asArray) {
+    function getObj(copy) {
+      return {start: stream.start, end: stream.pos,
+              string: stream.current(),
+              type: style || null,
+              state: copy ? copyState(doc.mode, state) : state};
+    }
+
+    var doc = cm.doc, mode = doc.mode, style;
+    pos = clipPos(doc, pos);
+    var line = getLine(doc, pos.line), state = getStateBefore(cm, pos.line, precise);
+    var stream = new StringStream(line.text, cm.options.tabSize), tokens;
+    if (asArray) tokens = [];
+    while ((asArray || stream.pos &lt; pos.ch) &amp;&amp; !stream.eol()) {
+      stream.start = stream.pos;
+      style = readToken(mode, stream, state);
+      if (asArray) tokens.push(getObj(true));
+    }
+    return asArray ? tokens : getObj();
+  }
+
</ins><span class="cx">   // Run the given mode's parser over a line, calling f for each token.
</span><span class="cx">   function runMode(cm, text, mode, state, f, lineClasses, forceToEnd) {
</span><span class="cx">     var flattenSpans = mode.flattenSpans;
</span><span class="cx">     if (flattenSpans == null) flattenSpans = cm.options.flattenSpans;
</span><span class="cx">     var curStart = 0, curStyle = null;
</span><span class="cx">     var stream = new StringStream(text, cm.options.tabSize), style;
</span><ins>+    var inner = cm.options.addModeClass &amp;&amp; [null];
</ins><span class="cx">     if (text == &quot;&quot;) extractLineClasses(callBlankLine(mode, state), lineClasses);
</span><span class="cx">     while (!stream.eol()) {
</span><span class="cx">       if (stream.pos &gt; cm.options.maxHighlightLength) {
</span><span class="lines">@@ -5637,15 +6746,18 @@
</span><span class="cx">         stream.pos = text.length;
</span><span class="cx">         style = null;
</span><span class="cx">       } else {
</span><del>-        style = extractLineClasses(readToken(mode, stream, state), lineClasses);
</del><ins>+        style = extractLineClasses(readToken(mode, stream, state, inner), lineClasses);
</ins><span class="cx">       }
</span><del>-      if (cm.options.addModeClass) {
-        var mName = CodeMirror.innerMode(mode, state).mode.name;
</del><ins>+      if (inner) {
+        var mName = inner[0].name;
</ins><span class="cx">         if (mName) style = &quot;m-&quot; + (style ? mName + &quot; &quot; + style : mName);
</span><span class="cx">       }
</span><span class="cx">       if (!flattenSpans || curStyle != style) {
</span><del>-        if (curStart &lt; stream.start) f(stream.start, curStyle);
-        curStart = stream.start; curStyle = style;
</del><ins>+        while (curStart &lt; stream.start) {
+          curStart = Math.min(stream.start, curStart + 50000);
+          f(curStart, curStyle);
+        }
+        curStyle = style;
</ins><span class="cx">       }
</span><span class="cx">       stream.start = stream.pos;
</span><span class="cx">     }
</span><span class="lines">@@ -5699,12 +6811,13 @@
</span><span class="cx">     return {styles: st, classes: lineClasses.bgClass || lineClasses.textClass ? lineClasses : null};
</span><span class="cx">   }
</span><span class="cx"> 
</span><del>-  function getLineStyles(cm, line) {
</del><ins>+  function getLineStyles(cm, line, updateFrontier) {
</ins><span class="cx">     if (!line.styles || line.styles[0] != cm.state.modeGen) {
</span><span class="cx">       var result = highlightLine(cm, line, line.stateAfter = getStateBefore(cm, lineNo(line)));
</span><span class="cx">       line.styles = result.styles;
</span><span class="cx">       if (result.classes) line.styleClasses = result.classes;
</span><span class="cx">       else if (line.styleClasses) line.styleClasses = null;
</span><ins>+      if (updateFrontier === cm.doc.frontier) cm.doc.frontier++;
</ins><span class="cx">     }
</span><span class="cx">     return line.styles;
</span><span class="cx">   }
</span><span class="lines">@@ -5744,7 +6857,9 @@
</span><span class="cx">     // is needed on Webkit to be able to get line-level bounding
</span><span class="cx">     // rectangles for it (in measureChar).
</span><span class="cx">     var content = elt(&quot;span&quot;, null, null, webkit ? &quot;padding-right: .1px&quot; : null);
</span><del>-    var builder = {pre: elt(&quot;pre&quot;, [content]), content: content, col: 0, pos: 0, cm: cm};
</del><ins>+    var builder = {pre: elt(&quot;pre&quot;, [content], &quot;CodeMirror-line&quot;), content: content,
+                   col: 0, pos: 0, cm: cm,
+                   splitSpaces: (ie || webkit) &amp;&amp; cm.getOption(&quot;lineWrapping&quot;)};
</ins><span class="cx">     lineView.measure = {};
</span><span class="cx"> 
</span><span class="cx">     // Iterate over the logical lines that make up this visual line.
</span><span class="lines">@@ -5754,12 +6869,11 @@
</span><span class="cx">       builder.addToken = buildToken;
</span><span class="cx">       // Optionally wire in some hacks into the token-rendering
</span><span class="cx">       // algorithm, to deal with browser quirks.
</span><del>-      if ((ie || webkit) &amp;&amp; cm.getOption(&quot;lineWrapping&quot;))
-        builder.addToken = buildTokenSplitSpaces(builder.addToken);
</del><span class="cx">       if (hasBadBidiRects(cm.display.measure) &amp;&amp; (order = getOrder(line)))
</span><span class="cx">         builder.addToken = buildTokenBadBidi(builder.addToken, order);
</span><span class="cx">       builder.map = [];
</span><del>-      insertLineContent(line, builder, getLineStyles(cm, line));
</del><ins>+      var allowFrontierUpdate = lineView != cm.display.externalMeasured &amp;&amp; lineNo(line);
+      insertLineContent(line, builder, getLineStyles(cm, line, allowFrontierUpdate));
</ins><span class="cx">       if (line.styleClasses) {
</span><span class="cx">         if (line.styleClasses.bgClass)
</span><span class="cx">           builder.bgClass = joinClasses(line.styleClasses.bgClass, builder.bgClass || &quot;&quot;);
</span><span class="lines">@@ -5781,28 +6895,35 @@
</span><span class="cx">       }
</span><span class="cx">     }
</span><span class="cx"> 
</span><ins>+    // See issue #2901
+    if (webkit &amp;&amp; /\bcm-tab\b/.test(builder.content.lastChild.className))
+      builder.content.className = &quot;cm-tab-wrap-hack&quot;;
+
</ins><span class="cx">     signal(cm, &quot;renderLine&quot;, cm, lineView.line, builder.pre);
</span><span class="cx">     if (builder.pre.className)
</span><span class="cx">       builder.textClass = joinClasses(builder.pre.className, builder.textClass || &quot;&quot;);
</span><ins>+
</ins><span class="cx">     return builder;
</span><span class="cx">   }
</span><span class="cx"> 
</span><span class="cx">   function defaultSpecialCharPlaceholder(ch) {
</span><span class="cx">     var token = elt(&quot;span&quot;, &quot;\u2022&quot;, &quot;cm-invalidchar&quot;);
</span><span class="cx">     token.title = &quot;\\u&quot; + ch.charCodeAt(0).toString(16);
</span><ins>+    token.setAttribute(&quot;aria-label&quot;, token.title);
</ins><span class="cx">     return token;
</span><span class="cx">   }
</span><span class="cx"> 
</span><span class="cx">   // Build up the DOM representation for a single token, and add it to
</span><span class="cx">   // the line map. Takes care to render special characters separately.
</span><del>-  function buildToken(builder, text, style, startStyle, endStyle, title) {
</del><ins>+  function buildToken(builder, text, style, startStyle, endStyle, title, css) {
</ins><span class="cx">     if (!text) return;
</span><del>-    var special = builder.cm.options.specialChars, mustWrap = false;
</del><ins>+    var displayText = builder.splitSpaces ? text.replace(/ {3,}/g, splitSpaces) : text;
+    var special = builder.cm.state.specialChars, mustWrap = false;
</ins><span class="cx">     if (!special.test(text)) {
</span><span class="cx">       builder.col += text.length;
</span><del>-      var content = document.createTextNode(text);
</del><ins>+      var content = document.createTextNode(displayText);
</ins><span class="cx">       builder.map.push(builder.pos, builder.pos + text.length, content);
</span><del>-      if (ie_upto8) mustWrap = true;
</del><ins>+      if (ie &amp;&amp; ie_version &lt; 9) mustWrap = true;
</ins><span class="cx">       builder.pos += text.length;
</span><span class="cx">     } else {
</span><span class="cx">       var content = document.createDocumentFragment(), pos = 0;
</span><span class="lines">@@ -5811,8 +6932,8 @@
</span><span class="cx">         var m = special.exec(text);
</span><span class="cx">         var skipped = m ? m.index - pos : text.length - pos;
</span><span class="cx">         if (skipped) {
</span><del>-          var txt = document.createTextNode(text.slice(pos, pos + skipped));
-          if (ie_upto8) content.appendChild(elt(&quot;span&quot;, [txt]));
</del><ins>+          var txt = document.createTextNode(displayText.slice(pos, pos + skipped));
+          if (ie &amp;&amp; ie_version &lt; 9) content.appendChild(elt(&quot;span&quot;, [txt]));
</ins><span class="cx">           else content.appendChild(txt);
</span><span class="cx">           builder.map.push(builder.pos, builder.pos + skipped, txt);
</span><span class="cx">           builder.col += skipped;
</span><span class="lines">@@ -5823,10 +6944,17 @@
</span><span class="cx">         if (m[0] == &quot;\t&quot;) {
</span><span class="cx">           var tabSize = builder.cm.options.tabSize, tabWidth = tabSize - builder.col % tabSize;
</span><span class="cx">           var txt = content.appendChild(elt(&quot;span&quot;, spaceStr(tabWidth), &quot;cm-tab&quot;));
</span><ins>+          txt.setAttribute(&quot;role&quot;, &quot;presentation&quot;);
+          txt.setAttribute(&quot;cm-text&quot;, &quot;\t&quot;);
</ins><span class="cx">           builder.col += tabWidth;
</span><ins>+        } else if (m[0] == &quot;\r&quot; || m[0] == &quot;\n&quot;) {
+          var txt = content.appendChild(elt(&quot;span&quot;, m[0] == &quot;\r&quot; ? &quot;␍&quot; : &quot;␤&quot;, &quot;cm-invalidchar&quot;));
+          txt.setAttribute(&quot;cm-text&quot;, m[0]);
+          builder.col += 1;
</ins><span class="cx">         } else {
</span><span class="cx">           var txt = builder.cm.options.specialCharPlaceholder(m[0]);
</span><del>-          if (ie_upto8) content.appendChild(elt(&quot;span&quot;, [txt]));
</del><ins>+          txt.setAttribute(&quot;cm-text&quot;, m[0]);
+          if (ie &amp;&amp; ie_version &lt; 9) content.appendChild(elt(&quot;span&quot;, [txt]));
</ins><span class="cx">           else content.appendChild(txt);
</span><span class="cx">           builder.col += 1;
</span><span class="cx">         }
</span><span class="lines">@@ -5834,33 +6962,28 @@
</span><span class="cx">         builder.pos++;
</span><span class="cx">       }
</span><span class="cx">     }
</span><del>-    if (style || startStyle || endStyle || mustWrap) {
</del><ins>+    if (style || startStyle || endStyle || mustWrap || css) {
</ins><span class="cx">       var fullStyle = style || &quot;&quot;;
</span><span class="cx">       if (startStyle) fullStyle += startStyle;
</span><span class="cx">       if (endStyle) fullStyle += endStyle;
</span><del>-      var token = elt(&quot;span&quot;, [content], fullStyle);
</del><ins>+      var token = elt(&quot;span&quot;, [content], fullStyle, css);
</ins><span class="cx">       if (title) token.title = title;
</span><span class="cx">       return builder.content.appendChild(token);
</span><span class="cx">     }
</span><span class="cx">     builder.content.appendChild(content);
</span><span class="cx">   }
</span><span class="cx"> 
</span><del>-  function buildTokenSplitSpaces(inner) {
-    function split(old) {
-      var out = &quot; &quot;;
-      for (var i = 0; i &lt; old.length - 2; ++i) out += i % 2 ? &quot; &quot; : &quot;\u00a0&quot;;
-      out += &quot; &quot;;
-      return out;
-    }
-    return function(builder, text, style, startStyle, endStyle, title) {
-      inner(builder, text.replace(/ {3,}/g, split), style, startStyle, endStyle, title);
-    };
</del><ins>+  function splitSpaces(old) {
+    var out = &quot; &quot;;
+    for (var i = 0; i &lt; old.length - 2; ++i) out += i % 2 ? &quot; &quot; : &quot;\u00a0&quot;;
+    out += &quot; &quot;;
+    return out;
</ins><span class="cx">   }
</span><span class="cx"> 
</span><span class="cx">   // Work around nonsense dimensions being reported for stretches of
</span><span class="cx">   // right-to-left text.
</span><span class="cx">   function buildTokenBadBidi(inner, order) {
</span><del>-    return function(builder, text, style, startStyle, endStyle, title) {
</del><ins>+    return function(builder, text, style, startStyle, endStyle, title, css) {
</ins><span class="cx">       style = style ? style + &quot; cm-force-border&quot; : &quot;cm-force-border&quot;;
</span><span class="cx">       var start = builder.pos, end = start + text.length;
</span><span class="cx">       for (;;) {
</span><span class="lines">@@ -5869,8 +6992,8 @@
</span><span class="cx">           var part = order[i];
</span><span class="cx">           if (part.to &gt; start &amp;&amp; part.from &lt;= start) break;
</span><span class="cx">         }
</span><del>-        if (part.to &gt;= end) return inner(builder, text, style, startStyle, endStyle, title);
-        inner(builder, text.slice(0, part.to - start), style, startStyle, null, title);
</del><ins>+        if (part.to &gt;= end) return inner(builder, text, style, startStyle, endStyle, title, css);
+        inner(builder, text.slice(0, part.to - start), style, startStyle, null, title, css);
</ins><span class="cx">         startStyle = null;
</span><span class="cx">         text = text.slice(part.to - start);
</span><span class="cx">         start = part.to;
</span><span class="lines">@@ -5880,8 +7003,14 @@
</span><span class="cx"> 
</span><span class="cx">   function buildCollapsedSpan(builder, size, marker, ignoreWidget) {
</span><span class="cx">     var widget = !ignoreWidget &amp;&amp; marker.widgetNode;
</span><ins>+    if (widget) builder.map.push(builder.pos, builder.pos + size, widget);
+    if (!ignoreWidget &amp;&amp; builder.cm.display.input.needsContentAttribute) {
+      if (!widget)
+        widget = builder.content.appendChild(document.createElement(&quot;span&quot;));
+      widget.setAttribute(&quot;cm-marker&quot;, marker.id);
+    }
</ins><span class="cx">     if (widget) {
</span><del>-      builder.map.push(builder.pos, builder.pos + size, widget);
</del><ins>+      builder.cm.display.input.setUneditable(widget);
</ins><span class="cx">       builder.content.appendChild(widget);
</span><span class="cx">     }
</span><span class="cx">     builder.pos += size;
</span><span class="lines">@@ -5897,18 +7026,24 @@
</span><span class="cx">       return;
</span><span class="cx">     }
</span><span class="cx"> 
</span><del>-    var len = allText.length, pos = 0, i = 1, text = &quot;&quot;, style;
</del><ins>+    var len = allText.length, pos = 0, i = 1, text = &quot;&quot;, style, css;
</ins><span class="cx">     var nextChange = 0, spanStyle, spanEndStyle, spanStartStyle, title, collapsed;
</span><span class="cx">     for (;;) {
</span><span class="cx">       if (nextChange == pos) { // Update current marker set
</span><del>-        spanStyle = spanEndStyle = spanStartStyle = title = &quot;&quot;;
</del><ins>+        spanStyle = spanEndStyle = spanStartStyle = title = css = &quot;&quot;;
</ins><span class="cx">         collapsed = null; nextChange = Infinity;
</span><span class="cx">         var foundBookmarks = [];
</span><span class="cx">         for (var j = 0; j &lt; spans.length; ++j) {
</span><span class="cx">           var sp = spans[j], m = sp.marker;
</span><del>-          if (sp.from &lt;= pos &amp;&amp; (sp.to == null || sp.to &gt; pos)) {
-            if (sp.to != null &amp;&amp; nextChange &gt; sp.to) { nextChange = sp.to; spanEndStyle = &quot;&quot;; }
</del><ins>+          if (m.type == &quot;bookmark&quot; &amp;&amp; sp.from == pos &amp;&amp; m.widgetNode) {
+            foundBookmarks.push(m);
+          } else if (sp.from &lt;= pos &amp;&amp; (sp.to == null || sp.to &gt; pos || m.collapsed &amp;&amp; sp.to == pos &amp;&amp; sp.from == pos)) {
+            if (sp.to != null &amp;&amp; sp.to != pos &amp;&amp; nextChange &gt; sp.to) {
+              nextChange = sp.to;
+              spanEndStyle = &quot;&quot;;
+            }
</ins><span class="cx">             if (m.className) spanStyle += &quot; &quot; + m.className;
</span><ins>+            if (m.css) css = m.css;
</ins><span class="cx">             if (m.startStyle &amp;&amp; sp.from == pos) spanStartStyle += &quot; &quot; + m.startStyle;
</span><span class="cx">             if (m.endStyle &amp;&amp; sp.to == nextChange) spanEndStyle += &quot; &quot; + m.endStyle;
</span><span class="cx">             if (m.title &amp;&amp; !title) title = m.title;
</span><span class="lines">@@ -5917,12 +7052,12 @@
</span><span class="cx">           } else if (sp.from &gt; pos &amp;&amp; nextChange &gt; sp.from) {
</span><span class="cx">             nextChange = sp.from;
</span><span class="cx">           }
</span><del>-          if (m.type == &quot;bookmark&quot; &amp;&amp; sp.from == pos &amp;&amp; m.widgetNode) foundBookmarks.push(m);
</del><span class="cx">         }
</span><span class="cx">         if (collapsed &amp;&amp; (collapsed.from || 0) == pos) {
</span><span class="cx">           buildCollapsedSpan(builder, (collapsed.to == null ? len + 1 : collapsed.to) - pos,
</span><span class="cx">                              collapsed.marker, collapsed.from == null);
</span><span class="cx">           if (collapsed.to == null) return;
</span><ins>+          if (collapsed.to == pos) collapsed = false;
</ins><span class="cx">         }
</span><span class="cx">         if (!collapsed &amp;&amp; foundBookmarks.length) for (var j = 0; j &lt; foundBookmarks.length; ++j)
</span><span class="cx">           buildCollapsedSpan(builder, 0, foundBookmarks[j]);
</span><span class="lines">@@ -5936,7 +7071,7 @@
</span><span class="cx">           if (!collapsed) {
</span><span class="cx">             var tokenText = end &gt; upto ? text.slice(0, upto - pos) : text;
</span><span class="cx">             builder.addToken(builder, tokenText, style ? style + spanStyle : spanStyle,
</span><del>-                             spanStartStyle, pos + tokenText.length == nextChange ? spanEndStyle : &quot;&quot;, title);
</del><ins>+                             spanStartStyle, pos + tokenText.length == nextChange ? spanEndStyle : &quot;&quot;, title, css);
</ins><span class="cx">           }
</span><span class="cx">           if (end &gt;= upto) {text = text.slice(upto - pos); pos = upto; break;}
</span><span class="cx">           pos = end;
</span><span class="lines">@@ -5965,17 +7100,24 @@
</span><span class="cx">       updateLine(line, text, spans, estimateHeight);
</span><span class="cx">       signalLater(line, &quot;change&quot;, line, change);
</span><span class="cx">     }
</span><ins>+    function linesFor(start, end) {
+      for (var i = start, result = []; i &lt; end; ++i)
+        result.push(new Line(text[i], spansFor(i), estimateHeight));
+      return result;
+    }
</ins><span class="cx"> 
</span><span class="cx">     var from = change.from, to = change.to, text = change.text;
</span><span class="cx">     var firstLine = getLine(doc, from.line), lastLine = getLine(doc, to.line);
</span><span class="cx">     var lastText = lst(text), lastSpans = spansFor(text.length - 1), nlines = to.line - from.line;
</span><span class="cx"> 
</span><span class="cx">     // Adjust the line structure
</span><del>-    if (isWholeLineUpdate(doc, change)) {
</del><ins>+    if (change.full) {
+      doc.insert(0, linesFor(0, text.length));
+      doc.remove(text.length, doc.size - text.length);
+    } else if (isWholeLineUpdate(doc, change)) {
</ins><span class="cx">       // This is a whole-line replace. Treated specially to make
</span><span class="cx">       // sure line objects move the way they are supposed to.
</span><del>-      for (var i = 0, added = []; i &lt; text.length - 1; ++i)
-        added.push(new Line(text[i], spansFor(i), estimateHeight));
</del><ins>+      var added = linesFor(0, text.length - 1);
</ins><span class="cx">       update(lastLine, lastLine.text, lastSpans);
</span><span class="cx">       if (nlines) doc.remove(from.line, nlines);
</span><span class="cx">       if (added.length) doc.insert(from.line, added);
</span><span class="lines">@@ -5983,8 +7125,7 @@
</span><span class="cx">       if (text.length == 1) {
</span><span class="cx">         update(firstLine, firstLine.text.slice(0, from.ch) + lastText + firstLine.text.slice(to.ch), lastSpans);
</span><span class="cx">       } else {
</span><del>-        for (var added = [], i = 1; i &lt; text.length - 1; ++i)
-          added.push(new Line(text[i], spansFor(i), estimateHeight));
</del><ins>+        var added = linesFor(1, text.length - 1);
</ins><span class="cx">         added.push(new Line(lastText + firstLine.text.slice(to.ch), lastSpans, estimateHeight));
</span><span class="cx">         update(firstLine, firstLine.text.slice(0, from.ch) + text[0], spansFor(0));
</span><span class="cx">         doc.insert(from.line + 1, added);
</span><span class="lines">@@ -5995,8 +7136,7 @@
</span><span class="cx">     } else {
</span><span class="cx">       update(firstLine, firstLine.text.slice(0, from.ch) + text[0], spansFor(0));
</span><span class="cx">       update(lastLine, lastText + lastLine.text.slice(to.ch), lastSpans);
</span><del>-      for (var i = 1, added = []; i &lt; text.length - 1; ++i)
-        added.push(new Line(text[i], spansFor(i), estimateHeight));
</del><ins>+      var added = linesFor(1, text.length - 1);
</ins><span class="cx">       if (nlines &gt; 1) doc.remove(from.line + 1, nlines - 1);
</span><span class="cx">       doc.insert(from.line + 1, added);
</span><span class="cx">     }
</span><span class="lines">@@ -6156,8 +7296,8 @@
</span><span class="cx">   };
</span><span class="cx"> 
</span><span class="cx">   var nextDocId = 0;
</span><del>-  var Doc = CodeMirror.Doc = function(text, mode, firstLine) {
-    if (!(this instanceof Doc)) return new Doc(text, mode, firstLine);
</del><ins>+  var Doc = CodeMirror.Doc = function(text, mode, firstLine, lineSep) {
+    if (!(this instanceof Doc)) return new Doc(text, mode, firstLine, lineSep);
</ins><span class="cx">     if (firstLine == null) firstLine = 0;
</span><span class="cx"> 
</span><span class="cx">     BranchChunk.call(this, [new LeafChunk([new Line(&quot;&quot;, null)])]);
</span><span class="lines">@@ -6171,8 +7311,9 @@
</span><span class="cx">     this.history = new History(null);
</span><span class="cx">     this.id = ++nextDocId;
</span><span class="cx">     this.modeOption = mode;
</span><ins>+    this.lineSep = lineSep;
</ins><span class="cx"> 
</span><del>-    if (typeof text == &quot;string&quot;) text = splitLines(text);
</del><ins>+    if (typeof text == &quot;string&quot;) text = this.splitLines(text);
</ins><span class="cx">     updateDoc(this, {from: start, to: start, text: text});
</span><span class="cx">     setSelection(this, simpleSelection(start), sel_dontScroll);
</span><span class="cx">   };
</span><span class="lines">@@ -6202,12 +7343,12 @@
</span><span class="cx">     getValue: function(lineSep) {
</span><span class="cx">       var lines = getLines(this, this.first, this.first + this.size);
</span><span class="cx">       if (lineSep === false) return lines;
</span><del>-      return lines.join(lineSep || &quot;\n&quot;);
</del><ins>+      return lines.join(lineSep || this.lineSeparator());
</ins><span class="cx">     },
</span><span class="cx">     setValue: docMethodOp(function(code) {
</span><span class="cx">       var top = Pos(this.first, 0), last = this.first + this.size - 1;
</span><span class="cx">       makeChange(this, {from: top, to: Pos(last, getLine(this, last).text.length),
</span><del>-                        text: splitLines(code), origin: &quot;setValue&quot;}, true);
</del><ins>+                        text: this.splitLines(code), origin: &quot;setValue&quot;, full: true}, true);
</ins><span class="cx">       setSelection(this, simpleSelection(top));
</span><span class="cx">     }),
</span><span class="cx">     replaceRange: function(code, from, to, origin) {
</span><span class="lines">@@ -6218,7 +7359,7 @@
</span><span class="cx">     getRange: function(from, to, lineSep) {
</span><span class="cx">       var lines = getBetween(this, clipPos(this, from), clipPos(this, to));
</span><span class="cx">       if (lineSep === false) return lines;
</span><del>-      return lines.join(lineSep || &quot;\n&quot;);
</del><ins>+      return lines.join(lineSep || this.lineSeparator());
</ins><span class="cx">     },
</span><span class="cx"> 
</span><span class="cx">     getLine: function(line) {var l = this.getLineHandle(line); return l &amp;&amp; l.text;},
</span><span class="lines">@@ -6284,13 +7425,13 @@
</span><span class="cx">         lines = lines ? lines.concat(sel) : sel;
</span><span class="cx">       }
</span><span class="cx">       if (lineSep === false) return lines;
</span><del>-      else return lines.join(lineSep || &quot;\n&quot;);
</del><ins>+      else return lines.join(lineSep || this.lineSeparator());
</ins><span class="cx">     },
</span><span class="cx">     getSelections: function(lineSep) {
</span><span class="cx">       var parts = [], ranges = this.sel.ranges;
</span><span class="cx">       for (var i = 0; i &lt; ranges.length; i++) {
</span><span class="cx">         var sel = getBetween(this, ranges[i].from(), ranges[i].to());
</span><del>-        if (lineSep !== false) sel = sel.join(lineSep || &quot;\n&quot;);
</del><ins>+        if (lineSep !== false) sel = sel.join(lineSep || this.lineSeparator());
</ins><span class="cx">         parts[i] = sel;
</span><span class="cx">       }
</span><span class="cx">       return parts;
</span><span class="lines">@@ -6305,7 +7446,7 @@
</span><span class="cx">       var changes = [], sel = this.sel;
</span><span class="cx">       for (var i = 0; i &lt; sel.ranges.length; i++) {
</span><span class="cx">         var range = sel.ranges[i];
</span><del>-        changes[i] = {from: range.from(), to: range.to(), text: splitLines(code[i]), origin: origin};
</del><ins>+        changes[i] = {from: range.from(), to: range.to(), text: this.splitLines(code[i]), origin: origin};
</ins><span class="cx">       }
</span><span class="cx">       var newSel = collapse &amp;&amp; collapse != &quot;end&quot; &amp;&amp; computeReplacedSel(this, changes, collapse);
</span><span class="cx">       for (var i = changes.length - 1; i &gt;= 0; i--)
</span><span class="lines">@@ -6334,7 +7475,7 @@
</span><span class="cx">     },
</span><span class="cx">     changeGeneration: function(forceSplit) {
</span><span class="cx">       if (forceSplit)
</span><del>-        this.history.lastOp = this.history.lastOrigin = null;
</del><ins>+        this.history.lastOp = this.history.lastSelOp = this.history.lastOrigin = null;
</ins><span class="cx">       return this.history.generation;
</span><span class="cx">     },
</span><span class="cx">     isClean: function (gen) {
</span><span class="lines">@@ -6351,13 +7492,48 @@
</span><span class="cx">       hist.undone = copyHistoryArray(histData.undone.slice(0), null, true);
</span><span class="cx">     },
</span><span class="cx"> 
</span><ins>+    addLineClass: docMethodOp(function(handle, where, cls) {
+      return changeLine(this, handle, where == &quot;gutter&quot; ? &quot;gutter&quot; : &quot;class&quot;, function(line) {
+        var prop = where == &quot;text&quot; ? &quot;textClass&quot;
+                 : where == &quot;background&quot; ? &quot;bgClass&quot;
+                 : where == &quot;gutter&quot; ? &quot;gutterClass&quot; : &quot;wrapClass&quot;;
+        if (!line[prop]) line[prop] = cls;
+        else if (classTest(cls).test(line[prop])) return false;
+        else line[prop] += &quot; &quot; + cls;
+        return true;
+      });
+    }),
+    removeLineClass: docMethodOp(function(handle, where, cls) {
+      return changeLine(this, handle, where == &quot;gutter&quot; ? &quot;gutter&quot; : &quot;class&quot;, function(line) {
+        var prop = where == &quot;text&quot; ? &quot;textClass&quot;
+                 : where == &quot;background&quot; ? &quot;bgClass&quot;
+                 : where == &quot;gutter&quot; ? &quot;gutterClass&quot; : &quot;wrapClass&quot;;
+        var cur = line[prop];
+        if (!cur) return false;
+        else if (cls == null) line[prop] = null;
+        else {
+          var found = cur.match(classTest(cls));
+          if (!found) return false;
+          var end = found.index + found[0].length;
+          line[prop] = cur.slice(0, found.index) + (!found.index || end == cur.length ? &quot;&quot; : &quot; &quot;) + cur.slice(end) || null;
+        }
+        return true;
+      });
+    }),
+
+    addLineWidget: docMethodOp(function(handle, node, options) {
+      return addLineWidget(this, handle, node, options);
+    }),
+    removeLineWidget: function(widget) { widget.clear(); },
+
</ins><span class="cx">     markText: function(from, to, options) {
</span><span class="cx">       return markText(this, clipPos(this, from), clipPos(this, to), options, &quot;range&quot;);
</span><span class="cx">     },
</span><span class="cx">     setBookmark: function(pos, options) {
</span><span class="cx">       var realOpts = {replacedWith: options &amp;&amp; (options.nodeType == null ? options.widget : options),
</span><span class="cx">                       insertLeft: options &amp;&amp; options.insertLeft,
</span><del>-                      clearWhenEmpty: false, shared: options &amp;&amp; options.shared};
</del><ins>+                      clearWhenEmpty: false, shared: options &amp;&amp; options.shared,
+                      handleMouseEvents: options &amp;&amp; options.handleMouseEvents};
</ins><span class="cx">       pos = clipPos(this, pos);
</span><span class="cx">       return markText(this, pos, pos, realOpts, &quot;bookmark&quot;);
</span><span class="cx">     },
</span><span class="lines">@@ -6420,7 +7596,8 @@
</span><span class="cx">     },
</span><span class="cx"> 
</span><span class="cx">     copy: function(copyHistory) {
</span><del>-      var doc = new Doc(getLines(this, this.first, this.first + this.size), this.modeOption, this.first);
</del><ins>+      var doc = new Doc(getLines(this, this.first, this.first + this.size),
+                        this.modeOption, this.first, this.lineSep);
</ins><span class="cx">       doc.scrollTop = this.scrollTop; doc.scrollLeft = this.scrollLeft;
</span><span class="cx">       doc.sel = this.sel;
</span><span class="cx">       doc.extend = false;
</span><span class="lines">@@ -6436,7 +7613,7 @@
</span><span class="cx">       var from = this.first, to = this.first + this.size;
</span><span class="cx">       if (options.from != null &amp;&amp; options.from &gt; from) from = options.from;
</span><span class="cx">       if (options.to != null &amp;&amp; options.to &lt; to) to = options.to;
</span><del>-      var copy = new Doc(getLines(this, from, to), options.mode || this.modeOption, from);
</del><ins>+      var copy = new Doc(getLines(this, from, to), options.mode || this.modeOption, from, this.lineSep);
</ins><span class="cx">       if (options.sharedHist) copy.history = this.history;
</span><span class="cx">       (this.linked || (this.linked = [])).push({doc: copy, sharedHist: options.sharedHist});
</span><span class="cx">       copy.linked = [{doc: this, isParent: true, sharedHist: options.sharedHist}];
</span><span class="lines">@@ -6465,14 +7642,20 @@
</span><span class="cx">     iterLinkedDocs: function(f) {linkedDocs(this, f);},
</span><span class="cx"> 
</span><span class="cx">     getMode: function() {return this.mode;},
</span><del>-    getEditor: function() {return this.cm;}
</del><ins>+    getEditor: function() {return this.cm;},
+
+    splitLines: function(str) {
+      if (this.lineSep) return str.split(this.lineSep);
+      return splitLinesAuto(str);
+    },
+    lineSeparator: function() { return this.lineSep || &quot;\n&quot;; }
</ins><span class="cx">   });
</span><span class="cx"> 
</span><span class="cx">   // Public alias.
</span><span class="cx">   Doc.prototype.eachLine = Doc.prototype.iter;
</span><span class="cx"> 
</span><span class="cx">   // Set up methods on CodeMirror's prototype to redirect to the editor's document.
</span><del>-  var dontDelegate = &quot;iter insert remove copy getEditor&quot;.split(&quot; &quot;);
</del><ins>+  var dontDelegate = &quot;iter insert remove copy getEditor constructor&quot;.split(&quot; &quot;);
</ins><span class="cx">   for (var prop in Doc.prototype) if (Doc.prototype.hasOwnProperty(prop) &amp;&amp; indexOf(dontDelegate, prop) &lt; 0)
</span><span class="cx">     CodeMirror.prototype[prop] = (function(method) {
</span><span class="cx">       return function() {return method.apply(this.doc, arguments);};
</span><span class="lines">@@ -6626,7 +7809,7 @@
</span><span class="cx">     // Used to track when changes can be merged into a single undo
</span><span class="cx">     // event
</span><span class="cx">     this.lastModTime = this.lastSelTime = 0;
</span><del>-    this.lastOp = null;
</del><ins>+    this.lastOp = this.lastSelOp = null;
</ins><span class="cx">     this.lastOrigin = this.lastSelOrigin = null;
</span><span class="cx">     // Used by the isClean() method
</span><span class="cx">     this.generation = this.maxGeneration = startGen || 1;
</span><span class="lines">@@ -6704,7 +7887,7 @@
</span><span class="cx">     hist.done.push(selAfter);
</span><span class="cx">     hist.generation = ++hist.maxGeneration;
</span><span class="cx">     hist.lastModTime = hist.lastSelTime = time;
</span><del>-    hist.lastOp = opId;
</del><ins>+    hist.lastOp = hist.lastSelOp = opId;
</ins><span class="cx">     hist.lastOrigin = hist.lastSelOrigin = change.origin;
</span><span class="cx"> 
</span><span class="cx">     if (!last) signal(doc, &quot;historyAdded&quot;);
</span><span class="lines">@@ -6730,7 +7913,7 @@
</span><span class="cx">     // the current, or the origins don't allow matching. Origins
</span><span class="cx">     // starting with * are always merged, those starting with + are
</span><span class="cx">     // merged when similar and close together in time.
</span><del>-    if (opId == hist.lastOp ||
</del><ins>+    if (opId == hist.lastSelOp ||
</ins><span class="cx">         (origin &amp;&amp; hist.lastSelOrigin == origin &amp;&amp;
</span><span class="cx">          (hist.lastModTime == hist.lastSelTime &amp;&amp; hist.lastOrigin == origin ||
</span><span class="cx">           selectionEventCanBeMerged(doc, origin, lst(hist.done), sel))))
</span><span class="lines">@@ -6740,7 +7923,7 @@
</span><span class="cx"> 
</span><span class="cx">     hist.lastSelTime = +new Date;
</span><span class="cx">     hist.lastSelOrigin = origin;
</span><del>-    hist.lastOp = opId;
</del><ins>+    hist.lastSelOp = opId;
</ins><span class="cx">     if (options &amp;&amp; options.clearRedo !== false)
</span><span class="cx">       clearSelectionEvents(hist.undone);
</span><span class="cx">   }
</span><span class="lines">@@ -6925,6 +8108,8 @@
</span><span class="cx">     for (var i = 0; i &lt; arr.length; ++i) arr[i].apply(null, args);
</span><span class="cx">   };
</span><span class="cx"> 
</span><ins>+  var orphanDelayedCallbacks = null;
+
</ins><span class="cx">   // Often, we want to signal events at a point where we are in the
</span><span class="cx">   // middle of some work, but don't want the handler to start calling
</span><span class="cx">   // other methods on the editor, which might be in an inconsistent
</span><span class="lines">@@ -6932,25 +8117,26 @@
</span><span class="cx">   // signalLater looks whether there are any handlers, and schedules
</span><span class="cx">   // them to be executed when the last operation ends, or, if no
</span><span class="cx">   // operation is active, when a timeout fires.
</span><del>-  var delayedCallbacks, delayedCallbackDepth = 0;
</del><span class="cx">   function signalLater(emitter, type /*, values...*/) {
</span><span class="cx">     var arr = emitter._handlers &amp;&amp; emitter._handlers[type];
</span><span class="cx">     if (!arr) return;
</span><del>-    var args = Array.prototype.slice.call(arguments, 2);
-    if (!delayedCallbacks) {
-      ++delayedCallbackDepth;
-      delayedCallbacks = [];
-      setTimeout(fireDelayed, 0);
</del><ins>+    var args = Array.prototype.slice.call(arguments, 2), list;
+    if (operationGroup) {
+      list = operationGroup.delayedCallbacks;
+    } else if (orphanDelayedCallbacks) {
+      list = orphanDelayedCallbacks;
+    } else {
+      list = orphanDelayedCallbacks = [];
+      setTimeout(fireOrphanDelayed, 0);
</ins><span class="cx">     }
</span><span class="cx">     function bnd(f) {return function(){f.apply(null, args);};};
</span><span class="cx">     for (var i = 0; i &lt; arr.length; ++i)
</span><del>-      delayedCallbacks.push(bnd(arr[i]));
</del><ins>+      list.push(bnd(arr[i]));
</ins><span class="cx">   }
</span><span class="cx"> 
</span><del>-  function fireDelayed() {
-    --delayedCallbackDepth;
-    var delayed = delayedCallbacks;
-    delayedCallbacks = null;
</del><ins>+  function fireOrphanDelayed() {
+    var delayed = orphanDelayedCallbacks;
+    orphanDelayedCallbacks = null;
</ins><span class="cx">     for (var i = 0; i &lt; delayed.length; ++i) delayed[i]();
</span><span class="cx">   }
</span><span class="cx"> 
</span><span class="lines">@@ -6987,7 +8173,7 @@
</span><span class="cx">   // MISC UTILITIES
</span><span class="cx"> 
</span><span class="cx">   // Number of pixels added to scroller and sizer to hide scrollbar
</span><del>-  var scrollerCutOff = 30;
</del><ins>+  var scrollerGap = 30;
</ins><span class="cx"> 
</span><span class="cx">   // Returned or thrown by various protocols to signal 'I'm not
</span><span class="cx">   // handling this'.
</span><span class="lines">@@ -7055,22 +8241,21 @@
</span><span class="cx">       if (array[i] == elt) return i;
</span><span class="cx">     return -1;
</span><span class="cx">   }
</span><del>-  if ([].indexOf) indexOf = function(array, elt) { return array.indexOf(elt); };
</del><span class="cx">   function map(array, f) {
</span><span class="cx">     var out = [];
</span><span class="cx">     for (var i = 0; i &lt; array.length; i++) out[i] = f(array[i], i);
</span><span class="cx">     return out;
</span><span class="cx">   }
</span><del>-  if ([].map) map = function(array, f) { return array.map(f); };
</del><span class="cx"> 
</span><ins>+  function nothing() {}
+
</ins><span class="cx">   function createObj(base, props) {
</span><span class="cx">     var inst;
</span><span class="cx">     if (Object.create) {
</span><span class="cx">       inst = Object.create(base);
</span><span class="cx">     } else {
</span><del>-      var ctor = function() {};
-      ctor.prototype = base;
-      inst = new ctor();
</del><ins>+      nothing.prototype = base;
+      inst = new nothing();
</ins><span class="cx">     }
</span><span class="cx">     if (props) copyObj(props, inst);
</span><span class="cx">     return inst;
</span><span class="lines">@@ -7089,7 +8274,7 @@
</span><span class="cx">     return function(){return f.apply(null, args);};
</span><span class="cx">   }
</span><span class="cx"> 
</span><del>-  var nonASCIISingleCaseWordChar = /[\u00df\u3040-\u309f\u30a0-\u30ff\u3400-\u4db5\u4e00-\u9fcc\uac00-\ud7af]/;
</del><ins>+  var nonASCIISingleCaseWordChar = /[\u00df\u0587\u0590-\u05f4\u0600-\u06ff\u3040-\u309f\u30a0-\u30ff\u3400-\u4db5\u4e00-\u9fcc\uac00-\ud7af]/;
</ins><span class="cx">   var isWordCharBasic = CodeMirror.isWordChar = function(ch) {
</span><span class="cx">     return /\w/.test(ch) || ch &gt; &quot;\x80&quot; &amp;&amp;
</span><span class="cx">       (ch.toUpperCase() != ch.toLowerCase() || nonASCIISingleCaseWordChar.test(ch));
</span><span class="lines">@@ -7125,15 +8310,16 @@
</span><span class="cx">   }
</span><span class="cx"> 
</span><span class="cx">   var range;
</span><del>-  if (document.createRange) range = function(node, start, end) {
</del><ins>+  if (document.createRange) range = function(node, start, end, endNode) {
</ins><span class="cx">     var r = document.createRange();
</span><del>-    r.setEnd(node, end);
</del><ins>+    r.setEnd(endNode || node, end);
</ins><span class="cx">     r.setStart(node, start);
</span><span class="cx">     return r;
</span><span class="cx">   };
</span><span class="cx">   else range = function(node, start, end) {
</span><span class="cx">     var r = document.body.createTextRange();
</span><del>-    r.moveToElementText(node.parentNode);
</del><ins>+    try { r.moveToElementText(node.parentNode); }
+    catch(e) { return r; }
</ins><span class="cx">     r.collapse(true);
</span><span class="cx">     r.moveEnd(&quot;character&quot;, end);
</span><span class="cx">     r.moveStart(&quot;character&quot;, start);
</span><span class="lines">@@ -7150,29 +8336,43 @@
</span><span class="cx">     return removeChildren(parent).appendChild(e);
</span><span class="cx">   }
</span><span class="cx"> 
</span><del>-  function contains(parent, child) {
</del><ins>+  var contains = CodeMirror.contains = function(parent, child) {
+    if (child.nodeType == 3) // Android browser always returns false when child is a textnode
+      child = child.parentNode;
</ins><span class="cx">     if (parent.contains)
</span><span class="cx">       return parent.contains(child);
</span><del>-    while (child = child.parentNode)
</del><ins>+    do {
+      if (child.nodeType == 11) child = child.host;
</ins><span class="cx">       if (child == parent) return true;
</span><ins>+    } while (child = child.parentNode);
+  };
+
+  function activeElt() {
+    var activeElement = document.activeElement;
+    while (activeElement &amp;&amp; activeElement.root &amp;&amp; activeElement.root.activeElement)
+      activeElement = activeElement.root.activeElement;
+    return activeElement;
</ins><span class="cx">   }
</span><del>-
-  function activeElt() { return document.activeElement; }
</del><span class="cx">   // Older versions of IE throws unspecified error when touching
</span><span class="cx">   // document.activeElement in some cases (during loading, in iframe)
</span><del>-  if (ie_upto10) activeElt = function() {
</del><ins>+  if (ie &amp;&amp; ie_version &lt; 11) activeElt = function() {
</ins><span class="cx">     try { return document.activeElement; }
</span><span class="cx">     catch(e) { return document.body; }
</span><span class="cx">   };
</span><span class="cx"> 
</span><del>-  function classTest(cls) { return new RegExp(&quot;\\b&quot; + cls + &quot;\\b\\s*&quot;); }
-  function rmClass(node, cls) {
-    var test = classTest(cls);
-    if (test.test(node.className)) node.className = node.className.replace(test, &quot;&quot;);
-  }
-  function addClass(node, cls) {
-    if (!classTest(cls).test(node.className)) node.className += &quot; &quot; + cls;
-  }
</del><ins>+  function classTest(cls) { return new RegExp(&quot;(^|\\s)&quot; + cls + &quot;(?:$|\\s)\\s*&quot;); }
+  var rmClass = CodeMirror.rmClass = function(node, cls) {
+    var current = node.className;
+    var match = classTest(cls).exec(current);
+    if (match) {
+      var after = current.slice(match.index + match[0].length);
+      node.className = current.slice(0, match.index) + (after ? match[1] + after : &quot;&quot;);
+    }
+  };
+  var addClass = CodeMirror.addClass = function(node, cls) {
+    var current = node.className;
+    if (!classTest(cls).test(current)) node.className += (current ? &quot; &quot; : &quot;&quot;) + cls;
+  };
</ins><span class="cx">   function joinClasses(a, b) {
</span><span class="cx">     var as = a.split(&quot; &quot;);
</span><span class="cx">     for (var i = 0; i &lt; as.length; i++)
</span><span class="lines">@@ -7207,7 +8407,6 @@
</span><span class="cx">     on(window, &quot;resize&quot;, function() {
</span><span class="cx">       if (resizeTimer == null) resizeTimer = setTimeout(function() {
</span><span class="cx">         resizeTimer = null;
</span><del>-        knownScrollbarWidth = null;
</del><span class="cx">         forEachCodeMirror(onResize);
</span><span class="cx">       }, 100);
</span><span class="cx">     });
</span><span class="lines">@@ -7223,31 +8422,23 @@
</span><span class="cx">   var dragAndDrop = function() {
</span><span class="cx">     // There is *some* kind of drag-and-drop support in IE6-8, but I
</span><span class="cx">     // couldn't get it to work yet.
</span><del>-    if (ie_upto8) return false;
</del><ins>+    if (ie &amp;&amp; ie_version &lt; 9) return false;
</ins><span class="cx">     var div = elt('div');
</span><span class="cx">     return &quot;draggable&quot; in div || &quot;dragDrop&quot; in div;
</span><span class="cx">   }();
</span><span class="cx"> 
</span><del>-  var knownScrollbarWidth;
-  function scrollbarWidth(measure) {
-    if (knownScrollbarWidth != null) return knownScrollbarWidth;
-    var test = elt(&quot;div&quot;, null, null, &quot;width: 50px; height: 50px; overflow-x: scroll&quot;);
-    removeChildrenAndAdd(measure, test);
-    if (test.offsetWidth)
-      knownScrollbarWidth = test.offsetHeight - test.clientHeight;
-    return knownScrollbarWidth || 0;
-  }
-
</del><span class="cx">   var zwspSupported;
</span><span class="cx">   function zeroWidthElement(measure) {
</span><span class="cx">     if (zwspSupported == null) {
</span><span class="cx">       var test = elt(&quot;span&quot;, &quot;\u200b&quot;);
</span><span class="cx">       removeChildrenAndAdd(measure, elt(&quot;span&quot;, [test, document.createTextNode(&quot;x&quot;)]));
</span><span class="cx">       if (measure.firstChild.offsetHeight != 0)
</span><del>-        zwspSupported = test.offsetWidth &lt;= 1 &amp;&amp; test.offsetHeight &gt; 2 &amp;&amp; !ie_upto7;
</del><ins>+        zwspSupported = test.offsetWidth &lt;= 1 &amp;&amp; test.offsetHeight &gt; 2 &amp;&amp; !(ie &amp;&amp; ie_version &lt; 8);
</ins><span class="cx">     }
</span><del>-    if (zwspSupported) return elt(&quot;span&quot;, &quot;\u200b&quot;);
-    else return elt(&quot;span&quot;, &quot;\u00a0&quot;, null, &quot;display: inline-block; width: 1px; margin-right: -1px&quot;);
</del><ins>+    var node = zwspSupported ? elt(&quot;span&quot;, &quot;\u200b&quot;) :
+      elt(&quot;span&quot;, &quot;\u00a0&quot;, null, &quot;display: inline-block; width: 1px; margin-right: -1px&quot;);
+    node.setAttribute(&quot;cm-text&quot;, &quot;&quot;);
+    return node;
</ins><span class="cx">   }
</span><span class="cx"> 
</span><span class="cx">   // Feature-detect IE's crummy client rect reporting for bidi text
</span><span class="lines">@@ -7256,14 +8447,14 @@
</span><span class="cx">     if (badBidiRects != null) return badBidiRects;
</span><span class="cx">     var txt = removeChildrenAndAdd(measure, document.createTextNode(&quot;A\u062eA&quot;));
</span><span class="cx">     var r0 = range(txt, 0, 1).getBoundingClientRect();
</span><del>-    if (r0.left == r0.right) return false;
</del><ins>+    if (!r0 || r0.left == r0.right) return false; // Safari returns null in some cases (#2780)
</ins><span class="cx">     var r1 = range(txt, 1, 2).getBoundingClientRect();
</span><span class="cx">     return badBidiRects = (r1.right - r0.right &lt; 3);
</span><span class="cx">   }
</span><span class="cx"> 
</span><span class="cx">   // See if &quot;&quot;.split is the broken IE version, if so, provide an
</span><span class="cx">   // alternative way to split lines.
</span><del>-  var splitLines = CodeMirror.splitLines = &quot;\n\nb&quot;.split(/\n/).length != 3 ? function(string) {
</del><ins>+  var splitLinesAuto = CodeMirror.splitLines = &quot;\n\nb&quot;.split(/\n/).length != 3 ? function(string) {
</ins><span class="cx">     var pos = 0, result = [], l = string.length;
</span><span class="cx">     while (pos &lt;= l) {
</span><span class="cx">       var nl = string.indexOf(&quot;\n&quot;, pos);
</span><span class="lines">@@ -7298,6 +8489,15 @@
</span><span class="cx">     return typeof e.oncopy == &quot;function&quot;;
</span><span class="cx">   })();
</span><span class="cx"> 
</span><ins>+  var badZoomedRects = null;
+  function hasBadZoomedRects(measure) {
+    if (badZoomedRects != null) return badZoomedRects;
+    var node = removeChildrenAndAdd(measure, elt(&quot;span&quot;, &quot;x&quot;));
+    var normal = node.getBoundingClientRect();
+    var fromRange = range(node, 0, 1).getBoundingClientRect();
+    return badZoomedRects = Math.abs(normal.left - fromRange.left) &gt; 1;
+  }
+
</ins><span class="cx">   // KEY NAMES
</span><span class="cx"> 
</span><span class="cx">   var keyNames = {3: &quot;Enter&quot;, 8: &quot;Backspace&quot;, 9: &quot;Tab&quot;, 13: &quot;Enter&quot;, 16: &quot;Shift&quot;, 17: &quot;Ctrl&quot;, 18: &quot;Alt&quot;,
</span><span class="lines">@@ -7360,6 +8560,17 @@
</span><span class="cx">     var ch = !order ? line.text.length : order[0].level % 2 ? lineLeft(line) : lineRight(line);
</span><span class="cx">     return Pos(lineN == null ? lineNo(line) : lineN, ch);
</span><span class="cx">   }
</span><ins>+  function lineStartSmart(cm, pos) {
+    var start = lineStart(cm, pos.line);
+    var line = getLine(cm.doc, start.line);
+    var order = getOrder(line);
+    if (!order || order[0].level == 0) {
+      var firstNonWS = Math.max(0, line.text.search(/\S/));
+      var inWS = pos.line == start.line &amp;&amp; pos.ch &lt;= firstNonWS &amp;&amp; pos.ch;
+      return Pos(start.line, inWS ? 0 : firstNonWS);
+    }
+    return start;
+  }
</ins><span class="cx"> 
</span><span class="cx">   function compareBidiLevel(order, a, b) {
</span><span class="cx">     var linedir = order[0].level;
</span><span class="lines">@@ -7590,6 +8801,8 @@
</span><span class="cx">         lst(order).to -= m[0].length;
</span><span class="cx">         order.push(new BidiSpan(0, len - m[0].length, len));
</span><span class="cx">       }
</span><ins>+      if (order[0].level == 2)
+        order.unshift(new BidiSpan(1, order[0].to, order[0].to));
</ins><span class="cx">       if (order[0].level != lst(order).level)
</span><span class="cx">         order.push(new BidiSpan(order[0].level, len, len));
</span><span class="cx"> 
</span><span class="lines">@@ -7599,7 +8812,7 @@
</span><span class="cx"> 
</span><span class="cx">   // THE END
</span><span class="cx"> 
</span><del>-  CodeMirror.version = &quot;4.2.0&quot;;
</del><ins>+  CodeMirror.version = &quot;5.5.1&quot;;
</ins><span class="cx"> 
</span><span class="cx">   return CodeMirror;
</span><span class="cx"> });
</span><span class="cx">Property changes on: trunk/Source/WebInspectorUI/UserInterface/External/CodeMirror/codemirror.js
</span><span class="cx">___________________________________________________________________
</span></span></pre></div>
<a id="svnexecutable"></a>
<div class="addfile"><h4>Added: svn:executable</h4></div>
<a id="trunkSourceWebInspectorUIUserInterfaceExternalCodeMirrorcoffeescriptjs"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebInspectorUI/UserInterface/External/CodeMirror/coffeescript.js (188324 => 188325)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebInspectorUI/UserInterface/External/CodeMirror/coffeescript.js        2015-08-12 04:58:37 UTC (rev 188324)
+++ trunk/Source/WebInspectorUI/UserInterface/External/CodeMirror/coffeescript.js        2015-08-12 05:40:27 UTC (rev 188325)
</span><span class="lines">@@ -15,14 +15,14 @@
</span><span class="cx"> })(function(CodeMirror) {
</span><span class="cx"> &quot;use strict&quot;;
</span><span class="cx"> 
</span><del>-CodeMirror.defineMode(&quot;coffeescript&quot;, function(conf) {
</del><ins>+CodeMirror.defineMode(&quot;coffeescript&quot;, function(conf, parserConf) {
</ins><span class="cx">   var ERRORCLASS = &quot;error&quot;;
</span><span class="cx"> 
</span><span class="cx">   function wordRegexp(words) {
</span><span class="cx">     return new RegExp(&quot;^((&quot; + words.join(&quot;)|(&quot;) + &quot;))\\b&quot;);
</span><span class="cx">   }
</span><span class="cx"> 
</span><del>-  var operators = /^(?:-&gt;|=&gt;|\+[+=]?|-[\-=]?|\*[\*=]?|\/[\/=]?|[=!]=|&lt;[&gt;&lt;]?=?|&gt;&gt;?=?|%=?|&amp;=?|\|=?|\^=?|\~|!|\?)/;
</del><ins>+  var operators = /^(?:-&gt;|=&gt;|\+[+=]?|-[\-=]?|\*[\*=]?|\/[\/=]?|[=!]=|&lt;[&gt;&lt;]?=?|&gt;&gt;?=?|%=?|&amp;=?|\|=?|\^=?|\~|!|\?|(or|and|\|\||&amp;&amp;|\?)=)/;
</ins><span class="cx">   var delimiters = /^(?:[()\[\]{},:`=;]|\.\.?\.?)/;
</span><span class="cx">   var identifiers = /^[_A-Za-z$][_A-Za-z$0-9]*/;
</span><span class="cx">   var properties = /^(@|this\.)[_A-Za-z$][_A-Za-z$0-9]*/;
</span><span class="lines">@@ -34,7 +34,7 @@
</span><span class="cx">                         &quot;switch&quot;, &quot;try&quot;, &quot;catch&quot;, &quot;finally&quot;, &quot;class&quot;];
</span><span class="cx">   var commonKeywords = [&quot;break&quot;, &quot;by&quot;, &quot;continue&quot;, &quot;debugger&quot;, &quot;delete&quot;,
</span><span class="cx">                         &quot;do&quot;, &quot;in&quot;, &quot;of&quot;, &quot;new&quot;, &quot;return&quot;, &quot;then&quot;,
</span><del>-                        &quot;this&quot;, &quot;throw&quot;, &quot;when&quot;, &quot;until&quot;];
</del><ins>+                        &quot;this&quot;, &quot;@&quot;, &quot;throw&quot;, &quot;when&quot;, &quot;until&quot;, &quot;extends&quot;];
</ins><span class="cx"> 
</span><span class="cx">   var keywords = wordRegexp(indentKeywords.concat(commonKeywords));
</span><span class="cx"> 
</span><span class="lines">@@ -191,7 +191,7 @@
</span><span class="cx">         }
</span><span class="cx">       }
</span><span class="cx">       if (singleline) {
</span><del>-        if (conf.mode.singleLineStringErrors) {
</del><ins>+        if (parserConf.singleLineStringErrors) {
</ins><span class="cx">           outclass = ERRORCLASS;
</span><span class="cx">         } else {
</span><span class="cx">           state.tokenize = tokenBase;
</span><span class="lines">@@ -217,7 +217,7 @@
</span><span class="cx">     type = type || &quot;coffee&quot;;
</span><span class="cx">     var offset = 0, align = false, alignOffset = null;
</span><span class="cx">     for (var scope = state.scope; scope; scope = scope.prev) {
</span><del>-      if (scope.type === &quot;coffee&quot;) {
</del><ins>+      if (scope.type === &quot;coffee&quot; || scope.type == &quot;}&quot;) {
</ins><span class="cx">         offset = scope.offset + conf.indentUnit;
</span><span class="cx">         break;
</span><span class="cx">       }
</span><span class="lines">@@ -278,7 +278,7 @@
</span><span class="cx"> 
</span><span class="cx">     // Handle scope changes.
</span><span class="cx">     if (current === &quot;return&quot;) {
</span><del>-      state.dedent += 1;
</del><ins>+      state.dedent = true;
</ins><span class="cx">     }
</span><span class="cx">     if (((current === &quot;-&gt;&quot; || current === &quot;=&gt;&quot;) &amp;&amp;
</span><span class="cx">          !state.lambda &amp;&amp;
</span><span class="lines">@@ -310,9 +310,10 @@
</span><span class="cx">       if (state.scope.type == current)
</span><span class="cx">         state.scope = state.scope.prev;
</span><span class="cx">     }
</span><del>-    if (state.dedent &gt; 0 &amp;&amp; stream.eol() &amp;&amp; state.scope.type == &quot;coffee&quot;) {
-      if (state.scope.prev) state.scope = state.scope.prev;
-      state.dedent -= 1;
</del><ins>+    if (state.dedent &amp;&amp; stream.eol()) {
+      if (state.scope.type == &quot;coffee&quot; &amp;&amp; state.scope.prev)
+        state.scope = state.scope.prev;
+      state.dedent = false;
</ins><span class="cx">     }
</span><span class="cx"> 
</span><span class="cx">     return style;
</span><span class="cx">Property changes on: trunk/Source/WebInspectorUI/UserInterface/External/CodeMirror/coffeescript.js
</span><span class="cx">___________________________________________________________________
</span></span></pre></div>
<a id="svnexecutable"></a>
<div class="addfile"><h4>Added: svn:executable</h4></div>
<a id="trunkSourceWebInspectorUIUserInterfaceExternalCodeMirrorcommentjs"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebInspectorUI/UserInterface/External/CodeMirror/comment.js (188324 => 188325)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebInspectorUI/UserInterface/External/CodeMirror/comment.js        2015-08-12 04:58:37 UTC (rev 188324)
+++ trunk/Source/WebInspectorUI/UserInterface/External/CodeMirror/comment.js        2015-08-12 05:40:27 UTC (rev 188325)
</span><span class="lines">@@ -109,7 +109,7 @@
</span><span class="cx">   CodeMirror.defineExtension(&quot;uncomment&quot;, function(from, to, options) {
</span><span class="cx">     if (!options) options = noOptions;
</span><span class="cx">     var self = this, mode = self.getModeAt(from);
</span><del>-    var end = Math.min(to.line, self.lastLine()), start = Math.min(from.line, end);
</del><ins>+    var end = Math.min(to.ch != 0 || to.line == from.line ? to.line : to.line - 1, self.lastLine()), start = Math.min(from.line, end);
</ins><span class="cx"> 
</span><span class="cx">     // Try finding line comments
</span><span class="cx">     var lineString = options.lineComment || mode.lineComment, lines = [];
</span><span class="lines">@@ -153,6 +153,17 @@
</span><span class="cx">         !/comment/.test(self.getTokenTypeAt(Pos(end, close + 1))))
</span><span class="cx">       return false;
</span><span class="cx"> 
</span><ins>+    // Avoid killing block comments completely outside the selection.
+    // Positions of the last startString before the start of the selection, and the first endString after it.
+    var lastStart = startLine.lastIndexOf(startString, from.ch);
+    var firstEnd = lastStart == -1 ? -1 : startLine.slice(0, from.ch).indexOf(endString, lastStart + startString.length);
+    if (lastStart != -1 &amp;&amp; firstEnd != -1 &amp;&amp; firstEnd + endString.length != from.ch) return false;
+    // Positions of the first endString after the end of the selection, and the last startString before it.
+    firstEnd = endLine.indexOf(endString, to.ch);
+    var almostLastStart = endLine.slice(to.ch).lastIndexOf(startString, firstEnd - to.ch);
+    lastStart = (firstEnd == -1 || almostLastStart == -1) ? -1 : to.ch + almostLastStart;
+    if (firstEnd != -1 &amp;&amp; lastStart != -1 &amp;&amp; lastStart != to.ch) return false;
+
</ins><span class="cx">     self.operation(function() {
</span><span class="cx">       self.replaceRange(&quot;&quot;, Pos(end, close - (pad &amp;&amp; endLine.slice(close - pad.length, close) == pad ? pad.length : 0)),
</span><span class="cx">                         Pos(end, close + endString.length));
</span><span class="cx">Property changes on: trunk/Source/WebInspectorUI/UserInterface/External/CodeMirror/comment.js
</span><span class="cx">___________________________________________________________________
</span></span></pre></div>
<a id="svnexecutable"></a>
<div class="addfile"><h4>Added: svn:executable</h4></div>
<a id="trunkSourceWebInspectorUIUserInterfaceExternalCodeMirrorcssjs"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebInspectorUI/UserInterface/External/CodeMirror/css.js (188324 => 188325)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebInspectorUI/UserInterface/External/CodeMirror/css.js        2015-08-12 04:58:37 UTC (rev 188324)
+++ trunk/Source/WebInspectorUI/UserInterface/External/CodeMirror/css.js        2015-08-12 05:40:27 UTC (rev 188325)
</span><span class="lines">@@ -12,17 +12,22 @@
</span><span class="cx"> &quot;use strict&quot;;
</span><span class="cx"> 
</span><span class="cx"> CodeMirror.defineMode(&quot;css&quot;, function(config, parserConfig) {
</span><ins>+  var provided = parserConfig;
</ins><span class="cx">   if (!parserConfig.propertyKeywords) parserConfig = CodeMirror.resolveMode(&quot;text/css&quot;);
</span><ins>+  parserConfig.inline = provided.inline;
</ins><span class="cx"> 
</span><span class="cx">   var indentUnit = config.indentUnit,
</span><span class="cx">       tokenHooks = parserConfig.tokenHooks,
</span><ins>+      documentTypes = parserConfig.documentTypes || {},
</ins><span class="cx">       mediaTypes = parserConfig.mediaTypes || {},
</span><span class="cx">       mediaFeatures = parserConfig.mediaFeatures || {},
</span><ins>+      mediaValueKeywords = parserConfig.mediaValueKeywords || {},
</ins><span class="cx">       propertyKeywords = parserConfig.propertyKeywords || {},
</span><span class="cx">       nonStandardPropertyKeywords = parserConfig.nonStandardPropertyKeywords || {},
</span><ins>+      fontProperties = parserConfig.fontProperties || {},
+      counterDescriptors = parserConfig.counterDescriptors || {},
</ins><span class="cx">       colorKeywords = parserConfig.colorKeywords || {},
</span><span class="cx">       valueKeywords = parserConfig.valueKeywords || {},
</span><del>-      fontProperties = parserConfig.fontProperties || {},
</del><span class="cx">       allowNested = parserConfig.allowNested;
</span><span class="cx"> 
</span><span class="cx">   var type, override;
</span><span class="lines">@@ -57,6 +62,11 @@
</span><span class="cx">       if (/[\d.]/.test(stream.peek())) {
</span><span class="cx">         stream.eatWhile(/[\w.%]/);
</span><span class="cx">         return ret(&quot;number&quot;, &quot;unit&quot;);
</span><ins>+      } else if (stream.match(/^-[\w\\\-]+/)) {
+        stream.eatWhile(/[\w\\\-]/);
+        if (stream.match(/^\s*:/, false))
+          return ret(&quot;variable-2&quot;, &quot;variable-definition&quot;);
+        return ret(&quot;variable-2&quot;, &quot;variable&quot;);
</ins><span class="cx">       } else if (stream.match(/^\w+-/)) {
</span><span class="cx">         return ret(&quot;meta&quot;, &quot;meta&quot;);
</span><span class="cx">       }
</span><span class="lines">@@ -66,7 +76,9 @@
</span><span class="cx">       return ret(&quot;qualifier&quot;, &quot;qualifier&quot;);
</span><span class="cx">     } else if (/[:;{}\[\]\(\)]/.test(ch)) {
</span><span class="cx">       return ret(null, ch);
</span><del>-    } else if (ch == &quot;u&quot; &amp;&amp; stream.match(&quot;rl(&quot;)) {
</del><ins>+    } else if ((ch == &quot;u&quot; &amp;&amp; stream.match(/rl(-prefix)?\(/)) ||
+               (ch == &quot;d&quot; &amp;&amp; stream.match(&quot;omain(&quot;)) ||
+               (ch == &quot;r&quot; &amp;&amp; stream.match(&quot;egexp(&quot;))) {
</ins><span class="cx">       stream.backUp(1);
</span><span class="cx">       state.tokenize = tokenParenthesized;
</span><span class="cx">       return ret(&quot;property&quot;, &quot;word&quot;);
</span><span class="lines">@@ -148,10 +160,11 @@
</span><span class="cx">       return pushContext(state, stream, &quot;block&quot;);
</span><span class="cx">     } else if (type == &quot;}&quot; &amp;&amp; state.context.prev) {
</span><span class="cx">       return popContext(state);
</span><del>-    } else if (type == &quot;@media&quot;) {
-      return pushContext(state, stream, &quot;media&quot;);
-    } else if (type == &quot;@font-face&quot;) {
-      return &quot;font_face_before&quot;;
</del><ins>+    } else if (/@(media|supports|(-moz-)?document)/.test(type)) {
+      return pushContext(state, stream, &quot;atBlock&quot;);
+    } else if (/@(font-face|counter-style)/.test(type)) {
+      state.stateArg = type;
+      return &quot;restricted_atBlock_before&quot;;
</ins><span class="cx">     } else if (/^@(-(moz|ms|o|webkit)-)?keyframes$/.test(type)) {
</span><span class="cx">       return &quot;keyframes&quot;;
</span><span class="cx">     } else if (type &amp;&amp; type.charAt(0) == &quot;@&quot;) {
</span><span class="lines">@@ -182,7 +195,7 @@
</span><span class="cx">         override = &quot;string-2&quot;;
</span><span class="cx">         return &quot;maybeprop&quot;;
</span><span class="cx">       } else if (allowNested) {
</span><del>-        override = stream.match(/^\s*:/, false) ? &quot;property&quot; : &quot;tag&quot;;
</del><ins>+        override = stream.match(/^\s*:(?:\s|$)/, false) ? &quot;property&quot; : &quot;tag&quot;;
</ins><span class="cx">         return &quot;block&quot;;
</span><span class="cx">       } else {
</span><span class="cx">         override += &quot; error&quot;;
</span><span class="lines">@@ -229,6 +242,7 @@
</span><span class="cx">     if (type == &quot;{&quot; || type == &quot;}&quot;) return popAndPass(type, stream, state);
</span><span class="cx">     if (type == &quot;)&quot;) return popContext(state);
</span><span class="cx">     if (type == &quot;(&quot;) return pushContext(state, stream, &quot;parens&quot;);
</span><ins>+    if (type == &quot;interpolation&quot;) return pushContext(state, stream, &quot;interpolation&quot;);
</ins><span class="cx">     if (type == &quot;word&quot;) wordAsValue(stream);
</span><span class="cx">     return &quot;parens&quot;;
</span><span class="cx">   };
</span><span class="lines">@@ -241,47 +255,67 @@
</span><span class="cx">     return pass(type, stream, state);
</span><span class="cx">   };
</span><span class="cx"> 
</span><del>-  states.media = function(type, stream, state) {
-    if (type == &quot;(&quot;) return pushContext(state, stream, &quot;media_parens&quot;);
</del><ins>+  states.atBlock = function(type, stream, state) {
+    if (type == &quot;(&quot;) return pushContext(state, stream, &quot;atBlock_parens&quot;);
</ins><span class="cx">     if (type == &quot;}&quot;) return popAndPass(type, stream, state);
</span><span class="cx">     if (type == &quot;{&quot;) return popContext(state) &amp;&amp; pushContext(state, stream, allowNested ? &quot;block&quot; : &quot;top&quot;);
</span><span class="cx"> 
</span><span class="cx">     if (type == &quot;word&quot;) {
</span><span class="cx">       var word = stream.current().toLowerCase();
</span><del>-      if (word == &quot;only&quot; || word == &quot;not&quot; || word == &quot;and&quot;)
</del><ins>+      if (word == &quot;only&quot; || word == &quot;not&quot; || word == &quot;and&quot; || word == &quot;or&quot;)
</ins><span class="cx">         override = &quot;keyword&quot;;
</span><ins>+      else if (documentTypes.hasOwnProperty(word))
+        override = &quot;tag&quot;;
</ins><span class="cx">       else if (mediaTypes.hasOwnProperty(word))
</span><span class="cx">         override = &quot;attribute&quot;;
</span><span class="cx">       else if (mediaFeatures.hasOwnProperty(word))
</span><span class="cx">         override = &quot;property&quot;;
</span><ins>+      else if (mediaValueKeywords.hasOwnProperty(word))
+        override = &quot;keyword&quot;;
+      else if (propertyKeywords.hasOwnProperty(word))
+        override = &quot;property&quot;;
+      else if (nonStandardPropertyKeywords.hasOwnProperty(word))
+        override = &quot;string-2&quot;;
+      else if (valueKeywords.hasOwnProperty(word))
+        override = &quot;atom&quot;;
+      else if (colorKeywords.hasOwnProperty(word))
+        override = &quot;keyword&quot;;
</ins><span class="cx">       else
</span><span class="cx">         override = &quot;error&quot;;
</span><span class="cx">     }
</span><span class="cx">     return state.context.type;
</span><span class="cx">   };
</span><span class="cx"> 
</span><del>-  states.media_parens = function(type, stream, state) {
</del><ins>+  states.atBlock_parens = function(type, stream, state) {
</ins><span class="cx">     if (type == &quot;)&quot;) return popContext(state);
</span><span class="cx">     if (type == &quot;{&quot; || type == &quot;}&quot;) return popAndPass(type, stream, state, 2);
</span><del>-    return states.media(type, stream, state);
</del><ins>+    return states.atBlock(type, stream, state);
</ins><span class="cx">   };
</span><span class="cx"> 
</span><del>-  states.font_face_before = function(type, stream, state) {
</del><ins>+  states.restricted_atBlock_before = function(type, stream, state) {
</ins><span class="cx">     if (type == &quot;{&quot;)
</span><del>-      return pushContext(state, stream, &quot;font_face&quot;);
</del><ins>+      return pushContext(state, stream, &quot;restricted_atBlock&quot;);
+    if (type == &quot;word&quot; &amp;&amp; state.stateArg == &quot;@counter-style&quot;) {
+      override = &quot;variable&quot;;
+      return &quot;restricted_atBlock_before&quot;;
+    }
</ins><span class="cx">     return pass(type, stream, state);
</span><span class="cx">   };
</span><span class="cx"> 
</span><del>-  states.font_face = function(type, stream, state) {
-    if (type == &quot;}&quot;) return popContext(state);
</del><ins>+  states.restricted_atBlock = function(type, stream, state) {
+    if (type == &quot;}&quot;) {
+      state.stateArg = null;
+      return popContext(state);
+    }
</ins><span class="cx">     if (type == &quot;word&quot;) {
</span><del>-      if (!fontProperties.hasOwnProperty(stream.current().toLowerCase()))
</del><ins>+      if ((state.stateArg == &quot;@font-face&quot; &amp;&amp; !fontProperties.hasOwnProperty(stream.current().toLowerCase())) ||
+          (state.stateArg == &quot;@counter-style&quot; &amp;&amp; !counterDescriptors.hasOwnProperty(stream.current().toLowerCase())))
</ins><span class="cx">         override = &quot;error&quot;;
</span><span class="cx">       else
</span><span class="cx">         override = &quot;property&quot;;
</span><span class="cx">       return &quot;maybeprop&quot;;
</span><span class="cx">     }
</span><del>-    return &quot;font_face&quot;;
</del><ins>+    return &quot;restricted_atBlock&quot;;
</ins><span class="cx">   };
</span><span class="cx"> 
</span><span class="cx">   states.keyframes = function(type, stream, state) {
</span><span class="lines">@@ -301,15 +335,17 @@
</span><span class="cx">   states.interpolation = function(type, stream, state) {
</span><span class="cx">     if (type == &quot;}&quot;) return popContext(state);
</span><span class="cx">     if (type == &quot;{&quot; || type == &quot;;&quot;) return popAndPass(type, stream, state);
</span><del>-    if (type != &quot;variable&quot;) override = &quot;error&quot;;
</del><ins>+    if (type == &quot;word&quot;) override = &quot;variable&quot;;
+    else if (type != &quot;variable&quot; &amp;&amp; type != &quot;(&quot; &amp;&amp; type != &quot;)&quot;) override = &quot;error&quot;;
</ins><span class="cx">     return &quot;interpolation&quot;;
</span><span class="cx">   };
</span><span class="cx"> 
</span><span class="cx">   return {
</span><span class="cx">     startState: function(base) {
</span><span class="cx">       return {tokenize: null,
</span><del>-              state: &quot;top&quot;,
-              context: new Context(&quot;top&quot;, base || 0, null)};
</del><ins>+              state: parserConfig.inline ? &quot;block&quot; : &quot;top&quot;,
+              stateArg: null,
+              context: new Context(parserConfig.inline ? &quot;block&quot; : &quot;top&quot;, base || 0, null)};
</ins><span class="cx">     },
</span><span class="cx"> 
</span><span class="cx">     token: function(stream, state) {
</span><span class="lines">@@ -329,9 +365,9 @@
</span><span class="cx">       var indent = cx.indent;
</span><span class="cx">       if (cx.type == &quot;prop&quot; &amp;&amp; (ch == &quot;}&quot; || ch == &quot;)&quot;)) cx = cx.prev;
</span><span class="cx">       if (cx.prev &amp;&amp;
</span><del>-          (ch == &quot;}&quot; &amp;&amp; (cx.type == &quot;block&quot; || cx.type == &quot;top&quot; || cx.type == &quot;interpolation&quot; || cx.type == &quot;font_face&quot;) ||
-           ch == &quot;)&quot; &amp;&amp; (cx.type == &quot;parens&quot; || cx.type == &quot;media_parens&quot;) ||
-           ch == &quot;{&quot; &amp;&amp; (cx.type == &quot;at&quot; || cx.type == &quot;media&quot;))) {
</del><ins>+          (ch == &quot;}&quot; &amp;&amp; (cx.type == &quot;block&quot; || cx.type == &quot;top&quot; || cx.type == &quot;interpolation&quot; || cx.type == &quot;restricted_atBlock&quot;) ||
+           ch == &quot;)&quot; &amp;&amp; (cx.type == &quot;parens&quot; || cx.type == &quot;atBlock_parens&quot;) ||
+           ch == &quot;{&quot; &amp;&amp; (cx.type == &quot;at&quot; || cx.type == &quot;atBlock&quot;))) {
</ins><span class="cx">         indent = cx.indent - indentUnit;
</span><span class="cx">         cx = cx.prev;
</span><span class="cx">       }
</span><span class="lines">@@ -353,6 +389,10 @@
</span><span class="cx">     return keys;
</span><span class="cx">   }
</span><span class="cx"> 
</span><ins>+  var documentTypes_ = [
+    &quot;domain&quot;, &quot;regexp&quot;, &quot;url&quot;, &quot;url-prefix&quot;
+  ], documentTypes = keySet(documentTypes_);
+
</ins><span class="cx">   var mediaTypes_ = [
</span><span class="cx">     &quot;all&quot;, &quot;aural&quot;, &quot;braille&quot;, &quot;handheld&quot;, &quot;print&quot;, &quot;projection&quot;, &quot;screen&quot;,
</span><span class="cx">     &quot;tty&quot;, &quot;tv&quot;, &quot;embossed&quot;
</span><span class="lines">@@ -366,9 +406,16 @@
</span><span class="cx">     &quot;min-device-aspect-ratio&quot;, &quot;max-device-aspect-ratio&quot;, &quot;color&quot;, &quot;min-color&quot;,
</span><span class="cx">     &quot;max-color&quot;, &quot;color-index&quot;, &quot;min-color-index&quot;, &quot;max-color-index&quot;,
</span><span class="cx">     &quot;monochrome&quot;, &quot;min-monochrome&quot;, &quot;max-monochrome&quot;, &quot;resolution&quot;,
</span><del>-    &quot;min-resolution&quot;, &quot;max-resolution&quot;, &quot;scan&quot;, &quot;grid&quot;
</del><ins>+    &quot;min-resolution&quot;, &quot;max-resolution&quot;, &quot;scan&quot;, &quot;grid&quot;, &quot;orientation&quot;,
+    &quot;device-pixel-ratio&quot;, &quot;min-device-pixel-ratio&quot;, &quot;max-device-pixel-ratio&quot;,
+    &quot;pointer&quot;, &quot;any-pointer&quot;, &quot;hover&quot;, &quot;any-hover&quot;
</ins><span class="cx">   ], mediaFeatures = keySet(mediaFeatures_);
</span><span class="cx"> 
</span><ins>+  var mediaValueKeywords_ = [
+    &quot;landscape&quot;, &quot;portrait&quot;, &quot;none&quot;, &quot;coarse&quot;, &quot;fine&quot;, &quot;on-demand&quot;, &quot;hover&quot;,
+    &quot;interlace&quot;, &quot;progressive&quot;
+  ], mediaValueKeywords = keySet(mediaValueKeywords_);
+
</ins><span class="cx">   var propertyKeywords_ = [
</span><span class="cx">     &quot;align-content&quot;, &quot;align-items&quot;, &quot;align-self&quot;, &quot;alignment-adjust&quot;,
</span><span class="cx">     &quot;alignment-baseline&quot;, &quot;anchor-point&quot;, &quot;animation&quot;, &quot;animation-delay&quot;,
</span><span class="lines">@@ -461,14 +508,24 @@
</span><span class="cx">     &quot;glyph-orientation-vertical&quot;, &quot;text-anchor&quot;, &quot;writing-mode&quot;
</span><span class="cx">   ], propertyKeywords = keySet(propertyKeywords_);
</span><span class="cx"> 
</span><del>-  var nonStandardPropertyKeywords = [
</del><ins>+  var nonStandardPropertyKeywords_ = [
</ins><span class="cx">     &quot;scrollbar-arrow-color&quot;, &quot;scrollbar-base-color&quot;, &quot;scrollbar-dark-shadow-color&quot;,
</span><span class="cx">     &quot;scrollbar-face-color&quot;, &quot;scrollbar-highlight-color&quot;, &quot;scrollbar-shadow-color&quot;,
</span><span class="cx">     &quot;scrollbar-3d-light-color&quot;, &quot;scrollbar-track-color&quot;, &quot;shape-inside&quot;,
</span><span class="cx">     &quot;searchfield-cancel-button&quot;, &quot;searchfield-decoration&quot;, &quot;searchfield-results-button&quot;,
</span><span class="cx">     &quot;searchfield-results-decoration&quot;, &quot;zoom&quot;
</span><del>-  ], nonStandardPropertyKeywords = keySet(nonStandardPropertyKeywords);
</del><ins>+  ], nonStandardPropertyKeywords = keySet(nonStandardPropertyKeywords_);
</ins><span class="cx"> 
</span><ins>+  var fontProperties_ = [
+    &quot;font-family&quot;, &quot;src&quot;, &quot;unicode-range&quot;, &quot;font-variant&quot;, &quot;font-feature-settings&quot;,
+    &quot;font-stretch&quot;, &quot;font-weight&quot;, &quot;font-style&quot;
+  ], fontProperties = keySet(fontProperties_);
+
+  var counterDescriptors_ = [
+    &quot;additive-symbols&quot;, &quot;fallback&quot;, &quot;negative&quot;, &quot;pad&quot;, &quot;prefix&quot;, &quot;range&quot;,
+    &quot;speak-as&quot;, &quot;suffix&quot;, &quot;symbols&quot;, &quot;system&quot;
+  ], counterDescriptors = keySet(counterDescriptors_);
+
</ins><span class="cx">   var colorKeywords_ = [
</span><span class="cx">     &quot;aliceblue&quot;, &quot;antiquewhite&quot;, &quot;aqua&quot;, &quot;aquamarine&quot;, &quot;azure&quot;, &quot;beige&quot;,
</span><span class="cx">     &quot;bisque&quot;, &quot;black&quot;, &quot;blanchedalmond&quot;, &quot;blue&quot;, &quot;blueviolet&quot;, &quot;brown&quot;,
</span><span class="lines">@@ -491,54 +548,57 @@
</span><span class="cx">     &quot;navajowhite&quot;, &quot;navy&quot;, &quot;oldlace&quot;, &quot;olive&quot;, &quot;olivedrab&quot;, &quot;orange&quot;, &quot;orangered&quot;,
</span><span class="cx">     &quot;orchid&quot;, &quot;palegoldenrod&quot;, &quot;palegreen&quot;, &quot;paleturquoise&quot;, &quot;palevioletred&quot;,
</span><span class="cx">     &quot;papayawhip&quot;, &quot;peachpuff&quot;, &quot;peru&quot;, &quot;pink&quot;, &quot;plum&quot;, &quot;powderblue&quot;,
</span><del>-    &quot;purple&quot;, &quot;rebeccapurple&quot;, &quot;red&quot;, &quot;rosybrown&quot;, &quot;royalblue&quot;, &quot;saddlebrown&quot;, &quot;salmon&quot;,
-    &quot;sandybrown&quot;, &quot;seagreen&quot;, &quot;seashell&quot;, &quot;sienna&quot;, &quot;silver&quot;, &quot;skyblue&quot;,
</del><ins>+    &quot;purple&quot;, &quot;rebeccapurple&quot;, &quot;red&quot;, &quot;rosybrown&quot;, &quot;royalblue&quot;, &quot;saddlebrown&quot;,
+    &quot;salmon&quot;, &quot;sandybrown&quot;, &quot;seagreen&quot;, &quot;seashell&quot;, &quot;sienna&quot;, &quot;silver&quot;, &quot;skyblue&quot;,
</ins><span class="cx">     &quot;slateblue&quot;, &quot;slategray&quot;, &quot;snow&quot;, &quot;springgreen&quot;, &quot;steelblue&quot;, &quot;tan&quot;,
</span><span class="cx">     &quot;teal&quot;, &quot;thistle&quot;, &quot;tomato&quot;, &quot;turquoise&quot;, &quot;violet&quot;, &quot;wheat&quot;, &quot;white&quot;,
</span><span class="cx">     &quot;whitesmoke&quot;, &quot;yellow&quot;, &quot;yellowgreen&quot;
</span><span class="cx">   ], colorKeywords = keySet(colorKeywords_);
</span><span class="cx"> 
</span><span class="cx">   var valueKeywords_ = [
</span><del>-    &quot;above&quot;, &quot;absolute&quot;, &quot;activeborder&quot;, &quot;activecaption&quot;, &quot;afar&quot;,
-    &quot;after-white-space&quot;, &quot;ahead&quot;, &quot;alias&quot;, &quot;all&quot;, &quot;all-scroll&quot;, &quot;alternate&quot;,
</del><ins>+    &quot;above&quot;, &quot;absolute&quot;, &quot;activeborder&quot;, &quot;additive&quot;, &quot;activecaption&quot;, &quot;afar&quot;,
+    &quot;after-white-space&quot;, &quot;ahead&quot;, &quot;alias&quot;, &quot;all&quot;, &quot;all-scroll&quot;, &quot;alphabetic&quot;, &quot;alternate&quot;,
</ins><span class="cx">     &quot;always&quot;, &quot;amharic&quot;, &quot;amharic-abegede&quot;, &quot;antialiased&quot;, &quot;appworkspace&quot;,
</span><del>-    &quot;arabic-indic&quot;, &quot;armenian&quot;, &quot;asterisks&quot;, &quot;auto&quot;, &quot;avoid&quot;, &quot;avoid-column&quot;, &quot;avoid-page&quot;,
</del><ins>+    &quot;arabic-indic&quot;, &quot;armenian&quot;, &quot;asterisks&quot;, &quot;attr&quot;, &quot;auto&quot;, &quot;avoid&quot;, &quot;avoid-column&quot;, &quot;avoid-page&quot;,
</ins><span class="cx">     &quot;avoid-region&quot;, &quot;background&quot;, &quot;backwards&quot;, &quot;baseline&quot;, &quot;below&quot;, &quot;bidi-override&quot;, &quot;binary&quot;,
</span><span class="cx">     &quot;bengali&quot;, &quot;blink&quot;, &quot;block&quot;, &quot;block-axis&quot;, &quot;bold&quot;, &quot;bolder&quot;, &quot;border&quot;, &quot;border-box&quot;,
</span><del>-    &quot;both&quot;, &quot;bottom&quot;, &quot;break&quot;, &quot;break-all&quot;, &quot;break-word&quot;, &quot;button&quot;, &quot;button-bevel&quot;,
-    &quot;buttonface&quot;, &quot;buttonhighlight&quot;, &quot;buttonshadow&quot;, &quot;buttontext&quot;, &quot;cambodian&quot;,
</del><ins>+    &quot;both&quot;, &quot;bottom&quot;, &quot;break&quot;, &quot;break-all&quot;, &quot;break-word&quot;, &quot;bullets&quot;, &quot;button&quot;, &quot;button-bevel&quot;,
+    &quot;buttonface&quot;, &quot;buttonhighlight&quot;, &quot;buttonshadow&quot;, &quot;buttontext&quot;, &quot;calc&quot;, &quot;cambodian&quot;,
</ins><span class="cx">     &quot;capitalize&quot;, &quot;caps-lock-indicator&quot;, &quot;caption&quot;, &quot;captiontext&quot;, &quot;caret&quot;,
</span><del>-    &quot;cell&quot;, &quot;center&quot;, &quot;checkbox&quot;, &quot;circle&quot;, &quot;cjk-earthly-branch&quot;,
</del><ins>+    &quot;cell&quot;, &quot;center&quot;, &quot;checkbox&quot;, &quot;circle&quot;, &quot;cjk-decimal&quot;, &quot;cjk-earthly-branch&quot;,
</ins><span class="cx">     &quot;cjk-heavenly-stem&quot;, &quot;cjk-ideographic&quot;, &quot;clear&quot;, &quot;clip&quot;, &quot;close-quote&quot;,
</span><del>-    &quot;col-resize&quot;, &quot;collapse&quot;, &quot;column&quot;, &quot;compact&quot;, &quot;condensed&quot;, &quot;contain&quot;, &quot;content&quot;,
-    &quot;content-box&quot;, &quot;context-menu&quot;, &quot;continuous&quot;, &quot;copy&quot;, &quot;cover&quot;, &quot;crop&quot;,
-    &quot;cross&quot;, &quot;crosshair&quot;, &quot;currentcolor&quot;, &quot;cursive&quot;, &quot;dashed&quot;, &quot;decimal&quot;,
</del><ins>+    &quot;col-resize&quot;, &quot;collapse&quot;, &quot;column&quot;, &quot;column-reverse&quot;, &quot;compact&quot;, &quot;condensed&quot;, &quot;contain&quot;, &quot;content&quot;,
+    &quot;content-box&quot;, &quot;context-menu&quot;, &quot;continuous&quot;, &quot;copy&quot;, &quot;counter&quot;, &quot;counters&quot;, &quot;cover&quot;, &quot;crop&quot;,
+    &quot;cross&quot;, &quot;crosshair&quot;, &quot;currentcolor&quot;, &quot;cursive&quot;, &quot;cyclic&quot;, &quot;dashed&quot;, &quot;decimal&quot;,
</ins><span class="cx">     &quot;decimal-leading-zero&quot;, &quot;default&quot;, &quot;default-button&quot;, &quot;destination-atop&quot;,
</span><span class="cx">     &quot;destination-in&quot;, &quot;destination-out&quot;, &quot;destination-over&quot;, &quot;devanagari&quot;,
</span><del>-    &quot;disc&quot;, &quot;discard&quot;, &quot;document&quot;, &quot;dot-dash&quot;, &quot;dot-dot-dash&quot;, &quot;dotted&quot;,
-    &quot;double&quot;, &quot;down&quot;, &quot;e-resize&quot;, &quot;ease&quot;, &quot;ease-in&quot;, &quot;ease-in-out&quot;, &quot;ease-out&quot;,
</del><ins>+    &quot;disc&quot;, &quot;discard&quot;, &quot;disclosure-closed&quot;, &quot;disclosure-open&quot;, &quot;document&quot;,
+    &quot;dot-dash&quot;, &quot;dot-dot-dash&quot;,
+    &quot;dotted&quot;, &quot;double&quot;, &quot;down&quot;, &quot;e-resize&quot;, &quot;ease&quot;, &quot;ease-in&quot;, &quot;ease-in-out&quot;, &quot;ease-out&quot;,
</ins><span class="cx">     &quot;element&quot;, &quot;ellipse&quot;, &quot;ellipsis&quot;, &quot;embed&quot;, &quot;end&quot;, &quot;ethiopic&quot;, &quot;ethiopic-abegede&quot;,
</span><span class="cx">     &quot;ethiopic-abegede-am-et&quot;, &quot;ethiopic-abegede-gez&quot;, &quot;ethiopic-abegede-ti-er&quot;,
</span><span class="cx">     &quot;ethiopic-abegede-ti-et&quot;, &quot;ethiopic-halehame-aa-er&quot;,
</span><span class="cx">     &quot;ethiopic-halehame-aa-et&quot;, &quot;ethiopic-halehame-am-et&quot;,
</span><span class="cx">     &quot;ethiopic-halehame-gez&quot;, &quot;ethiopic-halehame-om-et&quot;,
</span><span class="cx">     &quot;ethiopic-halehame-sid-et&quot;, &quot;ethiopic-halehame-so-et&quot;,
</span><del>-    &quot;ethiopic-halehame-ti-er&quot;, &quot;ethiopic-halehame-ti-et&quot;,
-    &quot;ethiopic-halehame-tig&quot;, &quot;ew-resize&quot;, &quot;expanded&quot;, &quot;extra-condensed&quot;,
-    &quot;extra-expanded&quot;, &quot;fantasy&quot;, &quot;fast&quot;, &quot;fill&quot;, &quot;fixed&quot;, &quot;flat&quot;, &quot;footnotes&quot;,
</del><ins>+    &quot;ethiopic-halehame-ti-er&quot;, &quot;ethiopic-halehame-ti-et&quot;, &quot;ethiopic-halehame-tig&quot;,
+    &quot;ethiopic-numeric&quot;, &quot;ew-resize&quot;, &quot;expanded&quot;, &quot;extends&quot;, &quot;extra-condensed&quot;,
+    &quot;extra-expanded&quot;, &quot;fantasy&quot;, &quot;fast&quot;, &quot;fill&quot;, &quot;fixed&quot;, &quot;flat&quot;, &quot;flex&quot;, &quot;footnotes&quot;,
</ins><span class="cx">     &quot;forwards&quot;, &quot;from&quot;, &quot;geometricPrecision&quot;, &quot;georgian&quot;, &quot;graytext&quot;, &quot;groove&quot;,
</span><span class="cx">     &quot;gujarati&quot;, &quot;gurmukhi&quot;, &quot;hand&quot;, &quot;hangul&quot;, &quot;hangul-consonant&quot;, &quot;hebrew&quot;,
</span><span class="cx">     &quot;help&quot;, &quot;hidden&quot;, &quot;hide&quot;, &quot;higher&quot;, &quot;highlight&quot;, &quot;highlighttext&quot;,
</span><span class="cx">     &quot;hiragana&quot;, &quot;hiragana-iroha&quot;, &quot;horizontal&quot;, &quot;hsl&quot;, &quot;hsla&quot;, &quot;icon&quot;, &quot;ignore&quot;,
</span><span class="cx">     &quot;inactiveborder&quot;, &quot;inactivecaption&quot;, &quot;inactivecaptiontext&quot;, &quot;infinite&quot;,
</span><span class="cx">     &quot;infobackground&quot;, &quot;infotext&quot;, &quot;inherit&quot;, &quot;initial&quot;, &quot;inline&quot;, &quot;inline-axis&quot;,
</span><del>-    &quot;inline-block&quot;, &quot;inline-table&quot;, &quot;inset&quot;, &quot;inside&quot;, &quot;intrinsic&quot;, &quot;invert&quot;,
-    &quot;italic&quot;, &quot;justify&quot;, &quot;kannada&quot;, &quot;katakana&quot;, &quot;katakana-iroha&quot;, &quot;keep-all&quot;, &quot;khmer&quot;,
</del><ins>+    &quot;inline-block&quot;, &quot;inline-flex&quot;, &quot;inline-table&quot;, &quot;inset&quot;, &quot;inside&quot;, &quot;intrinsic&quot;, &quot;invert&quot;,
+    &quot;italic&quot;, &quot;japanese-formal&quot;, &quot;japanese-informal&quot;, &quot;justify&quot;, &quot;kannada&quot;,
+    &quot;katakana&quot;, &quot;katakana-iroha&quot;, &quot;keep-all&quot;, &quot;khmer&quot;,
+    &quot;korean-hangul-formal&quot;, &quot;korean-hanja-formal&quot;, &quot;korean-hanja-informal&quot;,
</ins><span class="cx">     &quot;landscape&quot;, &quot;lao&quot;, &quot;large&quot;, &quot;larger&quot;, &quot;left&quot;, &quot;level&quot;, &quot;lighter&quot;,
</span><del>-    &quot;line-through&quot;, &quot;linear&quot;, &quot;lines&quot;, &quot;list-item&quot;, &quot;listbox&quot;, &quot;listitem&quot;,
</del><ins>+    &quot;line-through&quot;, &quot;linear&quot;, &quot;linear-gradient&quot;, &quot;lines&quot;, &quot;list-item&quot;, &quot;listbox&quot;, &quot;listitem&quot;,
</ins><span class="cx">     &quot;local&quot;, &quot;logical&quot;, &quot;loud&quot;, &quot;lower&quot;, &quot;lower-alpha&quot;, &quot;lower-armenian&quot;,
</span><span class="cx">     &quot;lower-greek&quot;, &quot;lower-hexadecimal&quot;, &quot;lower-latin&quot;, &quot;lower-norwegian&quot;,
</span><del>-    &quot;lower-roman&quot;, &quot;lowercase&quot;, &quot;ltr&quot;, &quot;malayalam&quot;, &quot;match&quot;,
</del><ins>+    &quot;lower-roman&quot;, &quot;lowercase&quot;, &quot;ltr&quot;, &quot;malayalam&quot;, &quot;match&quot;, &quot;matrix&quot;, &quot;matrix3d&quot;,
</ins><span class="cx">     &quot;media-controls-background&quot;, &quot;media-current-time-display&quot;,
</span><span class="cx">     &quot;media-fullscreen-button&quot;, &quot;media-mute-button&quot;, &quot;media-play-button&quot;,
</span><span class="cx">     &quot;media-return-to-realtime-button&quot;, &quot;media-rewind-button&quot;,
</span><span class="lines">@@ -550,46 +610,50 @@
</span><span class="cx">     &quot;mix&quot;, &quot;mongolian&quot;, &quot;monospace&quot;, &quot;move&quot;, &quot;multiple&quot;, &quot;myanmar&quot;, &quot;n-resize&quot;,
</span><span class="cx">     &quot;narrower&quot;, &quot;ne-resize&quot;, &quot;nesw-resize&quot;, &quot;no-close-quote&quot;, &quot;no-drop&quot;,
</span><span class="cx">     &quot;no-open-quote&quot;, &quot;no-repeat&quot;, &quot;none&quot;, &quot;normal&quot;, &quot;not-allowed&quot;, &quot;nowrap&quot;,
</span><del>-    &quot;ns-resize&quot;, &quot;nw-resize&quot;, &quot;nwse-resize&quot;, &quot;oblique&quot;, &quot;octal&quot;, &quot;open-quote&quot;,
</del><ins>+    &quot;ns-resize&quot;, &quot;numbers&quot;, &quot;numeric&quot;, &quot;nw-resize&quot;, &quot;nwse-resize&quot;, &quot;oblique&quot;, &quot;octal&quot;, &quot;open-quote&quot;,
</ins><span class="cx">     &quot;optimizeLegibility&quot;, &quot;optimizeSpeed&quot;, &quot;oriya&quot;, &quot;oromo&quot;, &quot;outset&quot;,
</span><span class="cx">     &quot;outside&quot;, &quot;outside-shape&quot;, &quot;overlay&quot;, &quot;overline&quot;, &quot;padding&quot;, &quot;padding-box&quot;,
</span><del>-    &quot;painted&quot;, &quot;page&quot;, &quot;paused&quot;, &quot;persian&quot;, &quot;plus-darker&quot;, &quot;plus-lighter&quot;, &quot;pointer&quot;,
-    &quot;polygon&quot;, &quot;portrait&quot;, &quot;pre&quot;, &quot;pre-line&quot;, &quot;pre-wrap&quot;, &quot;preserve-3d&quot;, &quot;progress&quot;, &quot;push-button&quot;,
-    &quot;radio&quot;, &quot;read-only&quot;, &quot;read-write&quot;, &quot;read-write-plaintext-only&quot;, &quot;rectangle&quot;, &quot;region&quot;,
-    &quot;relative&quot;, &quot;repeat&quot;, &quot;repeat-x&quot;, &quot;repeat-y&quot;, &quot;reset&quot;, &quot;reverse&quot;, &quot;rgb&quot;, &quot;rgba&quot;,
-    &quot;ridge&quot;, &quot;right&quot;, &quot;round&quot;, &quot;row-resize&quot;, &quot;rtl&quot;, &quot;run-in&quot;, &quot;running&quot;,
-    &quot;s-resize&quot;, &quot;sans-serif&quot;, &quot;scroll&quot;, &quot;scrollbar&quot;, &quot;se-resize&quot;, &quot;searchfield&quot;,
</del><ins>+    &quot;painted&quot;, &quot;page&quot;, &quot;paused&quot;, &quot;persian&quot;, &quot;perspective&quot;, &quot;plus-darker&quot;, &quot;plus-lighter&quot;,
+    &quot;pointer&quot;, &quot;polygon&quot;, &quot;portrait&quot;, &quot;pre&quot;, &quot;pre-line&quot;, &quot;pre-wrap&quot;, &quot;preserve-3d&quot;,
+    &quot;progress&quot;, &quot;push-button&quot;, &quot;radial-gradient&quot;, &quot;radio&quot;, &quot;read-only&quot;,
+    &quot;read-write&quot;, &quot;read-write-plaintext-only&quot;, &quot;rectangle&quot;, &quot;region&quot;,
+    &quot;relative&quot;, &quot;repeat&quot;, &quot;repeating-linear-gradient&quot;,
+    &quot;repeating-radial-gradient&quot;, &quot;repeat-x&quot;, &quot;repeat-y&quot;, &quot;reset&quot;, &quot;reverse&quot;,
+    &quot;rgb&quot;, &quot;rgba&quot;, &quot;ridge&quot;, &quot;right&quot;, &quot;rotate&quot;, &quot;rotate3d&quot;, &quot;rotateX&quot;, &quot;rotateY&quot;,
+    &quot;rotateZ&quot;, &quot;round&quot;, &quot;row&quot;, &quot;row-resize&quot;, &quot;row-reverse&quot;, &quot;rtl&quot;, &quot;run-in&quot;, &quot;running&quot;,
+    &quot;s-resize&quot;, &quot;sans-serif&quot;, &quot;scale&quot;, &quot;scale3d&quot;, &quot;scaleX&quot;, &quot;scaleY&quot;, &quot;scaleZ&quot;,
+    &quot;scroll&quot;, &quot;scrollbar&quot;, &quot;se-resize&quot;, &quot;searchfield&quot;,
</ins><span class="cx">     &quot;searchfield-cancel-button&quot;, &quot;searchfield-decoration&quot;,
</span><span class="cx">     &quot;searchfield-results-button&quot;, &quot;searchfield-results-decoration&quot;,
</span><span class="cx">     &quot;semi-condensed&quot;, &quot;semi-expanded&quot;, &quot;separate&quot;, &quot;serif&quot;, &quot;show&quot;, &quot;sidama&quot;,
</span><del>-    &quot;single&quot;, &quot;skip-white-space&quot;, &quot;slide&quot;, &quot;slider-horizontal&quot;,
</del><ins>+    &quot;simp-chinese-formal&quot;, &quot;simp-chinese-informal&quot;, &quot;single&quot;,
+    &quot;skew&quot;, &quot;skewX&quot;, &quot;skewY&quot;, &quot;skip-white-space&quot;, &quot;slide&quot;, &quot;slider-horizontal&quot;,
</ins><span class="cx">     &quot;slider-vertical&quot;, &quot;sliderthumb-horizontal&quot;, &quot;sliderthumb-vertical&quot;, &quot;slow&quot;,
</span><span class="cx">     &quot;small&quot;, &quot;small-caps&quot;, &quot;small-caption&quot;, &quot;smaller&quot;, &quot;solid&quot;, &quot;somali&quot;,
</span><del>-    &quot;source-atop&quot;, &quot;source-in&quot;, &quot;source-out&quot;, &quot;source-over&quot;, &quot;space&quot;, &quot;square&quot;,
-    &quot;square-button&quot;, &quot;start&quot;, &quot;static&quot;, &quot;status-bar&quot;, &quot;stretch&quot;, &quot;stroke&quot;,
-    &quot;sub&quot;, &quot;subpixel-antialiased&quot;, &quot;super&quot;, &quot;sw-resize&quot;, &quot;table&quot;,
</del><ins>+    &quot;source-atop&quot;, &quot;source-in&quot;, &quot;source-out&quot;, &quot;source-over&quot;, &quot;space&quot;, &quot;spell-out&quot;, &quot;square&quot;,
+    &quot;square-button&quot;, &quot;start&quot;, &quot;static&quot;, &quot;status-bar&quot;, &quot;stretch&quot;, &quot;stroke&quot;, &quot;sub&quot;,
+    &quot;subpixel-antialiased&quot;, &quot;super&quot;, &quot;sw-resize&quot;, &quot;symbolic&quot;, &quot;symbols&quot;, &quot;table&quot;,
</ins><span class="cx">     &quot;table-caption&quot;, &quot;table-cell&quot;, &quot;table-column&quot;, &quot;table-column-group&quot;,
</span><span class="cx">     &quot;table-footer-group&quot;, &quot;table-header-group&quot;, &quot;table-row&quot;, &quot;table-row-group&quot;,
</span><ins>+    &quot;tamil&quot;,
</ins><span class="cx">     &quot;telugu&quot;, &quot;text&quot;, &quot;text-bottom&quot;, &quot;text-top&quot;, &quot;textarea&quot;, &quot;textfield&quot;, &quot;thai&quot;,
</span><span class="cx">     &quot;thick&quot;, &quot;thin&quot;, &quot;threeddarkshadow&quot;, &quot;threedface&quot;, &quot;threedhighlight&quot;,
</span><span class="cx">     &quot;threedlightshadow&quot;, &quot;threedshadow&quot;, &quot;tibetan&quot;, &quot;tigre&quot;, &quot;tigrinya-er&quot;,
</span><span class="cx">     &quot;tigrinya-er-abegede&quot;, &quot;tigrinya-et&quot;, &quot;tigrinya-et-abegede&quot;, &quot;to&quot;, &quot;top&quot;,
</span><ins>+    &quot;trad-chinese-formal&quot;, &quot;trad-chinese-informal&quot;,
+    &quot;translate&quot;, &quot;translate3d&quot;, &quot;translateX&quot;, &quot;translateY&quot;, &quot;translateZ&quot;,
</ins><span class="cx">     &quot;transparent&quot;, &quot;ultra-condensed&quot;, &quot;ultra-expanded&quot;, &quot;underline&quot;, &quot;up&quot;,
</span><span class="cx">     &quot;upper-alpha&quot;, &quot;upper-armenian&quot;, &quot;upper-greek&quot;, &quot;upper-hexadecimal&quot;,
</span><span class="cx">     &quot;upper-latin&quot;, &quot;upper-norwegian&quot;, &quot;upper-roman&quot;, &quot;uppercase&quot;, &quot;urdu&quot;, &quot;url&quot;,
</span><del>-    &quot;vertical&quot;, &quot;vertical-text&quot;, &quot;visible&quot;, &quot;visibleFill&quot;, &quot;visiblePainted&quot;,
</del><ins>+    &quot;var&quot;, &quot;vertical&quot;, &quot;vertical-text&quot;, &quot;visible&quot;, &quot;visibleFill&quot;, &quot;visiblePainted&quot;,
</ins><span class="cx">     &quot;visibleStroke&quot;, &quot;visual&quot;, &quot;w-resize&quot;, &quot;wait&quot;, &quot;wave&quot;, &quot;wider&quot;,
</span><del>-    &quot;window&quot;, &quot;windowframe&quot;, &quot;windowtext&quot;, &quot;x-large&quot;, &quot;x-small&quot;, &quot;xor&quot;,
</del><ins>+    &quot;window&quot;, &quot;windowframe&quot;, &quot;windowtext&quot;, &quot;words&quot;, &quot;x-large&quot;, &quot;x-small&quot;, &quot;xor&quot;,
</ins><span class="cx">     &quot;xx-large&quot;, &quot;xx-small&quot;
</span><span class="cx">   ], valueKeywords = keySet(valueKeywords_);
</span><span class="cx"> 
</span><del>-  var fontProperties_ = [
-    &quot;font-family&quot;, &quot;src&quot;, &quot;unicode-range&quot;, &quot;font-variant&quot;, &quot;font-feature-settings&quot;,
-    &quot;font-stretch&quot;, &quot;font-weight&quot;, &quot;font-style&quot;
-  ], fontProperties = keySet(fontProperties_);
-
-  var allWords = mediaTypes_.concat(mediaFeatures_).concat(propertyKeywords_)
-    .concat(nonStandardPropertyKeywords).concat(colorKeywords_).concat(valueKeywords_);
</del><ins>+  var allWords = documentTypes_.concat(mediaTypes_).concat(mediaFeatures_).concat(mediaValueKeywords_)
+    .concat(propertyKeywords_).concat(nonStandardPropertyKeywords_).concat(colorKeywords_)
+    .concat(valueKeywords_);
</ins><span class="cx">   CodeMirror.registerHelper(&quot;hintWords&quot;, &quot;css&quot;, allWords);
</span><span class="cx"> 
</span><span class="cx">   function tokenCComment(stream, state) {
</span><span class="lines">@@ -604,30 +668,18 @@
</span><span class="cx">     return [&quot;comment&quot;, &quot;comment&quot;];
</span><span class="cx">   }
</span><span class="cx"> 
</span><del>-  function tokenSGMLComment(stream, state) {
-    if (stream.skipTo(&quot;--&gt;&quot;)) {
-      stream.match(&quot;--&gt;&quot;);
-      state.tokenize = null;
-    } else {
-      stream.skipToEnd();
-    }
-    return [&quot;comment&quot;, &quot;comment&quot;];
-  }
-
</del><span class="cx">   CodeMirror.defineMIME(&quot;text/css&quot;, {
</span><ins>+    documentTypes: documentTypes,
</ins><span class="cx">     mediaTypes: mediaTypes,
</span><span class="cx">     mediaFeatures: mediaFeatures,
</span><ins>+    mediaValueKeywords: mediaValueKeywords,
</ins><span class="cx">     propertyKeywords: propertyKeywords,
</span><span class="cx">     nonStandardPropertyKeywords: nonStandardPropertyKeywords,
</span><ins>+    fontProperties: fontProperties,
+    counterDescriptors: counterDescriptors,
</ins><span class="cx">     colorKeywords: colorKeywords,
</span><span class="cx">     valueKeywords: valueKeywords,
</span><del>-    fontProperties: fontProperties,
</del><span class="cx">     tokenHooks: {
</span><del>-      &quot;&lt;&quot;: function(stream, state) {
-        if (!stream.match(&quot;!--&quot;)) return false;
-        state.tokenize = tokenSGMLComment;
-        return tokenSGMLComment(stream, state);
-      },
</del><span class="cx">       &quot;/&quot;: function(stream, state) {
</span><span class="cx">         if (!stream.eat(&quot;*&quot;)) return false;
</span><span class="cx">         state.tokenize = tokenCComment;
</span><span class="lines">@@ -640,6 +692,7 @@
</span><span class="cx">   CodeMirror.defineMIME(&quot;text/x-scss&quot;, {
</span><span class="cx">     mediaTypes: mediaTypes,
</span><span class="cx">     mediaFeatures: mediaFeatures,
</span><ins>+    mediaValueKeywords: mediaValueKeywords,
</ins><span class="cx">     propertyKeywords: propertyKeywords,
</span><span class="cx">     nonStandardPropertyKeywords: nonStandardPropertyKeywords,
</span><span class="cx">     colorKeywords: colorKeywords,
</span><span class="lines">@@ -659,7 +712,7 @@
</span><span class="cx">         }
</span><span class="cx">       },
</span><span class="cx">       &quot;:&quot;: function(stream) {
</span><del>-        if (stream.match(/\s*{/))
</del><ins>+        if (stream.match(/\s*\{/))
</ins><span class="cx">           return [null, &quot;{&quot;];
</span><span class="cx">         return false;
</span><span class="cx">       },
</span><span class="lines">@@ -681,6 +734,7 @@
</span><span class="cx">   CodeMirror.defineMIME(&quot;text/x-less&quot;, {
</span><span class="cx">     mediaTypes: mediaTypes,
</span><span class="cx">     mediaFeatures: mediaFeatures,
</span><ins>+    mediaValueKeywords: mediaValueKeywords,
</ins><span class="cx">     propertyKeywords: propertyKeywords,
</span><span class="cx">     nonStandardPropertyKeywords: nonStandardPropertyKeywords,
</span><span class="cx">     colorKeywords: colorKeywords,
</span><span class="lines">@@ -700,6 +754,7 @@
</span><span class="cx">         }
</span><span class="cx">       },
</span><span class="cx">       &quot;@&quot;: function(stream) {
</span><ins>+        if (stream.eat(&quot;{&quot;)) return [null, &quot;interpolation&quot;];
</ins><span class="cx">         if (stream.match(/^(charset|document|font-face|import|(-(moz|ms|o|webkit)-)?keyframes|media|namespace|page|supports)\b/, false)) return false;
</span><span class="cx">         stream.eatWhile(/[\w\\\-]/);
</span><span class="cx">         if (stream.match(/^\s*:/, false))
</span><span class="cx">Property changes on: trunk/Source/WebInspectorUI/UserInterface/External/CodeMirror/css.js
</span><span class="cx">___________________________________________________________________
</span></span></pre></div>
<a id="svnexecutable"></a>
<div class="addfile"><h4>Added: svn:executable</h4></div>
<a id="trunkSourceWebInspectorUIUserInterfaceExternalCodeMirrorhtmlmixedjs"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebInspectorUI/UserInterface/External/CodeMirror/htmlmixed.js (188324 => 188325)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebInspectorUI/UserInterface/External/CodeMirror/htmlmixed.js        2015-08-12 04:58:37 UTC (rev 188324)
+++ trunk/Source/WebInspectorUI/UserInterface/External/CodeMirror/htmlmixed.js        2015-08-12 05:40:27 UTC (rev 188325)
</span><span class="lines">@@ -30,6 +30,7 @@
</span><span class="cx"> 
</span><span class="cx">   function html(stream, state) {
</span><span class="cx">     var tagName = state.htmlState.tagName;
</span><ins>+    if (tagName) tagName = tagName.toLowerCase();
</ins><span class="cx">     var style = htmlMode.token(stream, state.htmlState);
</span><span class="cx">     if (tagName == &quot;script&quot; &amp;&amp; /\btag\b/.test(style) &amp;&amp; stream.current() == &quot;&gt;&quot;) {
</span><span class="cx">       // Script block: mode to change to depends on type attribute
</span><span class="lines">@@ -56,9 +57,9 @@
</span><span class="cx">   }
</span><span class="cx">   function maybeBackup(stream, pat, style) {
</span><span class="cx">     var cur = stream.current();
</span><del>-    var close = cur.search(pat), m;
</del><ins>+    var close = cur.search(pat);
</ins><span class="cx">     if (close &gt; -1) stream.backUp(cur.length - close);
</span><del>-    else if (m = cur.match(/&lt;\/?$/)) {
</del><ins>+    else if (cur.match(/&lt;\/?$/)) {
</ins><span class="cx">       stream.backUp(cur.length);
</span><span class="cx">       if (!stream.match(pat, false)) stream.match(cur);
</span><span class="cx">     }
</span><span class="lines">@@ -68,7 +69,7 @@
</span><span class="cx">     if (stream.match(/^&lt;\/\s*script\s*&gt;/i, false)) {
</span><span class="cx">       state.token = html;
</span><span class="cx">       state.localState = state.localMode = null;
</span><del>-      return html(stream, state);
</del><ins>+      return null;
</ins><span class="cx">     }
</span><span class="cx">     return maybeBackup(stream, /&lt;\/\s*script\s*&gt;/,
</span><span class="cx">                        state.localMode.token(stream, state.localState));
</span><span class="lines">@@ -77,7 +78,7 @@
</span><span class="cx">     if (stream.match(/^&lt;\/\s*style\s*&gt;/i, false)) {
</span><span class="cx">       state.token = html;
</span><span class="cx">       state.localState = state.localMode = null;
</span><del>-      return html(stream, state);
</del><ins>+      return null;
</ins><span class="cx">     }
</span><span class="cx">     return maybeBackup(stream, /&lt;\/\s*style\s*&gt;/,
</span><span class="cx">                        cssMode.token(stream, state.localState));
</span><span class="cx">Property changes on: trunk/Source/WebInspectorUI/UserInterface/External/CodeMirror/htmlmixed.js
</span><span class="cx">___________________________________________________________________
</span></span></pre></div>
<a id="svnexecutable"></a>
<div class="addfile"><h4>Added: svn:executable</h4></div>
<a id="trunkSourceWebInspectorUIUserInterfaceExternalCodeMirrorjavascriptjs"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebInspectorUI/UserInterface/External/CodeMirror/javascript.js (188324 => 188325)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebInspectorUI/UserInterface/External/CodeMirror/javascript.js        2015-08-12 04:58:37 UTC (rev 188324)
+++ trunk/Source/WebInspectorUI/UserInterface/External/CodeMirror/javascript.js        2015-08-12 05:40:27 UTC (rev 188325)
</span><span class="lines">@@ -19,6 +19,7 @@
</span><span class="cx">   var jsonldMode = parserConfig.jsonld;
</span><span class="cx">   var jsonMode = parserConfig.json || jsonldMode;
</span><span class="cx">   var isTS = parserConfig.typescript;
</span><ins>+  var wordRE = parserConfig.wordCharacters || /[\w$\xa1-\uffff]/;
</ins><span class="cx"> 
</span><span class="cx">   // Tokenizer
</span><span class="cx"> 
</span><span class="lines">@@ -117,7 +118,7 @@
</span><span class="cx">       } else if (state.lastType == &quot;operator&quot; || state.lastType == &quot;keyword c&quot; ||
</span><span class="cx">                state.lastType == &quot;sof&quot; || /^[\[{}\(,;:]$/.test(state.lastType)) {
</span><span class="cx">         readRegexp(stream);
</span><del>-        stream.eatWhile(/[gimy]/); // 'y' is &quot;sticky&quot; option in Mozilla
</del><ins>+        stream.match(/^\b(([gimyu])(?![gimyu]*\2))+\b/);
</ins><span class="cx">         return ret(&quot;regexp&quot;, &quot;string-2&quot;);
</span><span class="cx">       } else {
</span><span class="cx">         stream.eatWhile(isOperatorChar);
</span><span class="lines">@@ -132,8 +133,8 @@
</span><span class="cx">     } else if (isOperatorChar.test(ch)) {
</span><span class="cx">       stream.eatWhile(isOperatorChar);
</span><span class="cx">       return ret(&quot;operator&quot;, &quot;operator&quot;, stream.current());
</span><del>-    } else {
-      stream.eatWhile(/[\w\$_]/);
</del><ins>+    } else if (wordRE.test(ch)) {
+      stream.eatWhile(wordRE);
</ins><span class="cx">       var word = stream.current(), known = keywords.propertyIsEnumerable(word) &amp;&amp; keywords[word];
</span><span class="cx">       return (known &amp;&amp; state.lastType != &quot;.&quot;) ? ret(known.type, known.style, word) :
</span><span class="cx">                      ret(&quot;variable&quot;, &quot;variable&quot;, word);
</span><span class="lines">@@ -202,8 +203,10 @@
</span><span class="cx">         if (--depth == 0) break;
</span><span class="cx">       } else if (bracket &gt;= 3 &amp;&amp; bracket &lt; 6) {
</span><span class="cx">         ++depth;
</span><del>-      } else if (/[$\w]/.test(ch)) {
</del><ins>+      } else if (wordRE.test(ch)) {
</ins><span class="cx">         sawSomething = true;
</span><ins>+      } else if (/[&quot;'\/]/.test(ch)) {
+        return;
</ins><span class="cx">       } else if (sawSomething &amp;&amp; !depth) {
</span><span class="cx">         ++pos;
</span><span class="cx">         break;
</span><span class="lines">@@ -238,7 +241,7 @@
</span><span class="cx">     var cc = state.cc;
</span><span class="cx">     // Communicate our context to the combinators.
</span><span class="cx">     // (Less wasteful than consing up a hundred closures on every call.)
</span><del>-    cx.state = state; cx.stream = stream; cx.marked = null, cx.cc = cc;
</del><ins>+    cx.state = state; cx.stream = stream; cx.marked = null, cx.cc = cc; cx.style = style;
</ins><span class="cx"> 
</span><span class="cx">     if (!state.lexical.hasOwnProperty(&quot;align&quot;))
</span><span class="cx">       state.lexical.align = true;
</span><span class="lines">@@ -298,6 +301,8 @@
</span><span class="cx">     var result = function() {
</span><span class="cx">       var state = cx.state, indent = state.indented;
</span><span class="cx">       if (state.lexical.type == &quot;stat&quot;) indent = state.lexical.indented;
</span><ins>+      else for (var outer = state.lexical; outer &amp;&amp; outer.type == &quot;)&quot; &amp;&amp; outer.align; outer = outer.prev)
+        indent = outer.indented;
</ins><span class="cx">       state.lexical = new JSLexical(indent, cx.stream.column(), type, null, state.lexical, info);
</span><span class="cx">     };
</span><span class="cx">     result.lex = true;
</span><span class="lines">@@ -343,7 +348,7 @@
</span><span class="cx">     if (type == &quot;catch&quot;) return cont(pushlex(&quot;form&quot;), pushcontext, expect(&quot;(&quot;), funarg, expect(&quot;)&quot;),
</span><span class="cx">                                      statement, poplex, popcontext);
</span><span class="cx">     if (type == &quot;module&quot;) return cont(pushlex(&quot;form&quot;), pushcontext, afterModule, popcontext, poplex);
</span><del>-    if (type == &quot;class&quot;) return cont(pushlex(&quot;form&quot;), className, objlit, poplex);
</del><ins>+    if (type == &quot;class&quot;) return cont(pushlex(&quot;form&quot;), className, poplex);
</ins><span class="cx">     if (type == &quot;export&quot;) return cont(pushlex(&quot;form&quot;), afterExport, poplex);
</span><span class="cx">     if (type == &quot;import&quot;) return cont(pushlex(&quot;form&quot;), afterImport, poplex);
</span><span class="cx">     return pass(pushlex(&quot;stat&quot;), expression, expect(&quot;;&quot;), poplex);
</span><span class="lines">@@ -388,7 +393,7 @@
</span><span class="cx">   function maybeoperatorNoComma(type, value, noComma) {
</span><span class="cx">     var me = noComma == false ? maybeoperatorComma : maybeoperatorNoComma;
</span><span class="cx">     var expr = noComma == false ? expression : expressionNoComma;
</span><del>-    if (value == &quot;=&gt;&quot;) return cont(pushcontext, noComma ? arrowBodyNoComma : arrowBody, popcontext);
</del><ins>+    if (type == &quot;=&gt;&quot;) return cont(pushcontext, noComma ? arrowBodyNoComma : arrowBody, popcontext);
</ins><span class="cx">     if (type == &quot;operator&quot;) {
</span><span class="cx">       if (/\+\+|--/.test(value)) return cont(me);
</span><span class="cx">       if (value == &quot;?&quot;) return cont(expression, expect(&quot;:&quot;), expr);
</span><span class="lines">@@ -414,13 +419,11 @@
</span><span class="cx">   }
</span><span class="cx">   function arrowBody(type) {
</span><span class="cx">     findFatArrow(cx.stream, cx.state);
</span><del>-    if (type == &quot;{&quot;) return pass(statement);
-    return pass(expression);
</del><ins>+    return pass(type == &quot;{&quot; ? statement : expression);
</ins><span class="cx">   }
</span><span class="cx">   function arrowBodyNoComma(type) {
</span><span class="cx">     findFatArrow(cx.stream, cx.state);
</span><del>-    if (type == &quot;{&quot;) return pass(statement);
-    return pass(expressionNoComma);
</del><ins>+    return pass(type == &quot;{&quot; ? statement : expressionNoComma);
</ins><span class="cx">   }
</span><span class="cx">   function maybelabel(type) {
</span><span class="cx">     if (type == &quot;:&quot;) return cont(poplex, statement);
</span><span class="lines">@@ -430,15 +433,18 @@
</span><span class="cx">     if (type == &quot;variable&quot;) {cx.marked = &quot;property&quot;; return cont();}
</span><span class="cx">   }
</span><span class="cx">   function objprop(type, value) {
</span><del>-    if (type == &quot;variable&quot;) {
</del><ins>+    if (type == &quot;variable&quot; || cx.style == &quot;keyword&quot;) {
</ins><span class="cx">       cx.marked = &quot;property&quot;;
</span><span class="cx">       if (value == &quot;get&quot; || value == &quot;set&quot;) return cont(getterSetter);
</span><ins>+      return cont(afterprop);
</ins><span class="cx">     } else if (type == &quot;number&quot; || type == &quot;string&quot;) {
</span><del>-      cx.marked = jsonldMode ? &quot;property&quot; : (type + &quot; property&quot;);
</del><ins>+      cx.marked = jsonldMode ? &quot;property&quot; : (cx.style + &quot; property&quot;);
+      return cont(afterprop);
+    } else if (type == &quot;jsonld-keyword&quot;) {
+      return cont(afterprop);
</ins><span class="cx">     } else if (type == &quot;[&quot;) {
</span><span class="cx">       return cont(expression, expect(&quot;]&quot;), afterprop);
</span><span class="cx">     }
</span><del>-    if (atomicTypes.hasOwnProperty(type)) return cont(afterprop);
</del><span class="cx">   }
</span><span class="cx">   function getterSetter(type) {
</span><span class="cx">     if (type != &quot;variable&quot;) return pass(afterprop);
</span><span class="lines">@@ -476,8 +482,11 @@
</span><span class="cx">   function maybetype(type) {
</span><span class="cx">     if (isTS &amp;&amp; type == &quot;:&quot;) return cont(typedef);
</span><span class="cx">   }
</span><ins>+  function maybedefault(_, value) {
+    if (value == &quot;=&quot;) return cont(expressionNoComma);
+  }
</ins><span class="cx">   function typedef(type) {
</span><del>-    if (type == &quot;variable&quot;){cx.marked = &quot;variable-3&quot;; return cont();}
</del><ins>+    if (type == &quot;variable&quot;) {cx.marked = &quot;variable-3&quot;; return cont();}
</ins><span class="cx">   }
</span><span class="cx">   function vardef() {
</span><span class="cx">     return pass(pattern, maybetype, maybeAssign, vardefCont);
</span><span class="lines">@@ -532,17 +541,37 @@
</span><span class="cx">   }
</span><span class="cx">   function funarg(type) {
</span><span class="cx">     if (type == &quot;spread&quot;) return cont(funarg);
</span><del>-    return pass(pattern, maybetype);
</del><ins>+    return pass(pattern, maybetype, maybedefault);
</ins><span class="cx">   }
</span><span class="cx">   function className(type, value) {
</span><span class="cx">     if (type == &quot;variable&quot;) {register(value); return cont(classNameAfter);}
</span><span class="cx">   }
</span><del>-  function classNameAfter(_type, value) {
-    if (value == &quot;extends&quot;) return cont(expression);
</del><ins>+  function classNameAfter(type, value) {
+    if (value == &quot;extends&quot;) return cont(expression, classNameAfter);
+    if (type == &quot;{&quot;) return cont(pushlex(&quot;}&quot;), classBody, poplex);
</ins><span class="cx">   }
</span><del>-  function objlit(type) {
-    if (type == &quot;{&quot;) return contCommasep(objprop, &quot;}&quot;);
</del><ins>+  function classBody(type, value) {
+    if (type == &quot;variable&quot; || cx.style == &quot;keyword&quot;) {
+      if (value == &quot;static&quot;) {
+        cx.marked = &quot;keyword&quot;;
+        return cont(classBody);
+      }
+      cx.marked = &quot;property&quot;;
+      if (value == &quot;get&quot; || value == &quot;set&quot;) return cont(classGetterSetter, functiondef, classBody);
+      return cont(functiondef, classBody);
+    }
+    if (value == &quot;*&quot;) {
+      cx.marked = &quot;keyword&quot;;
+      return cont(classBody);
+    }
+    if (type == &quot;;&quot;) return cont(classBody);
+    if (type == &quot;}&quot;) return cont();
</ins><span class="cx">   }
</span><ins>+  function classGetterSetter(type) {
+    if (type != &quot;variable&quot;) return pass();
+    cx.marked = &quot;property&quot;;
+    return cont();
+  }
</ins><span class="cx">   function afterModule(type, value) {
</span><span class="cx">     if (type == &quot;string&quot;) return cont(statement);
</span><span class="cx">     if (type == &quot;variable&quot;) { register(value); return cont(maybeFrom); }
</span><span class="lines">@@ -559,8 +588,12 @@
</span><span class="cx">   function importSpec(type, value) {
</span><span class="cx">     if (type == &quot;{&quot;) return contCommasep(importSpec, &quot;}&quot;);
</span><span class="cx">     if (type == &quot;variable&quot;) register(value);
</span><del>-    return cont();
</del><ins>+    if (value == &quot;*&quot;) cx.marked = &quot;keyword&quot;;
+    return cont(maybeAs);
</ins><span class="cx">   }
</span><ins>+  function maybeAs(_type, value) {
+    if (value == &quot;as&quot;) { cx.marked = &quot;keyword&quot;; return cont(importSpec); }
+  }
</ins><span class="cx">   function maybeFrom(_type, value) {
</span><span class="cx">     if (value == &quot;from&quot;) { cx.marked = &quot;keyword&quot;; return cont(expression); }
</span><span class="cx">   }
</span><span class="lines">@@ -570,7 +603,7 @@
</span><span class="cx">   }
</span><span class="cx">   function maybeArrayComprehension(type) {
</span><span class="cx">     if (type == &quot;for&quot;) return pass(comprehension, expect(&quot;]&quot;));
</span><del>-    if (type == &quot;,&quot;) return cont(commasep(expressionNoComma, &quot;]&quot;));
</del><ins>+    if (type == &quot;,&quot;) return cont(commasep(maybeexpressionNoComma, &quot;]&quot;));
</ins><span class="cx">     return pass(commasep(expressionNoComma, &quot;]&quot;));
</span><span class="cx">   }
</span><span class="cx">   function comprehension(type) {
</span><span class="lines">@@ -578,6 +611,12 @@
</span><span class="cx">     if (type == &quot;if&quot;) return cont(expression, comprehension);
</span><span class="cx">   }
</span><span class="cx"> 
</span><ins>+  function isContinuedStatement(state, textAfter) {
+    return state.lastType == &quot;operator&quot; || state.lastType == &quot;,&quot; ||
+      isOperatorChar.test(textAfter.charAt(0)) ||
+      /[,.]/.test(textAfter.charAt(0));
+  }
+
</ins><span class="cx">   // Interface
</span><span class="cx"> 
</span><span class="cx">   return {
</span><span class="lines">@@ -629,18 +668,19 @@
</span><span class="cx">       else if (type == &quot;form&quot; &amp;&amp; firstChar == &quot;{&quot;) return lexical.indented;
</span><span class="cx">       else if (type == &quot;form&quot;) return lexical.indented + indentUnit;
</span><span class="cx">       else if (type == &quot;stat&quot;)
</span><del>-        return lexical.indented + (state.lastType == &quot;operator&quot; || state.lastType == &quot;,&quot; ? statementIndent || indentUnit : 0);
</del><ins>+        return lexical.indented + (isContinuedStatement(state, textAfter) ? statementIndent || indentUnit : 0);
</ins><span class="cx">       else if (lexical.info == &quot;switch&quot; &amp;&amp; !closing &amp;&amp; parserConfig.doubleIndentSwitch != false)
</span><span class="cx">         return lexical.indented + (/^(?:case|default)\b/.test(textAfter) ? indentUnit : 2 * indentUnit);
</span><span class="cx">       else if (lexical.align) return lexical.column + (closing ? 0 : 1);
</span><span class="cx">       else return lexical.indented + (closing ? 0 : indentUnit);
</span><span class="cx">     },
</span><span class="cx"> 
</span><del>-    electricChars: &quot;:{}&quot;,
</del><ins>+    electricInput: /^\s*(?:case .*?:|default:|\{|\})$/,
</ins><span class="cx">     blockCommentStart: jsonMode ? null : &quot;/*&quot;,
</span><span class="cx">     blockCommentEnd: jsonMode ? null : &quot;*/&quot;,
</span><span class="cx">     lineComment: jsonMode ? null : &quot;//&quot;,
</span><span class="cx">     fold: &quot;brace&quot;,
</span><ins>+    closeBrackets: &quot;()[]{}''\&quot;\&quot;``&quot;,
</ins><span class="cx"> 
</span><span class="cx">     helperType: jsonMode ? &quot;json&quot; : &quot;javascript&quot;,
</span><span class="cx">     jsonldMode: jsonldMode,
</span><span class="lines">@@ -648,11 +688,12 @@
</span><span class="cx">   };
</span><span class="cx"> });
</span><span class="cx"> 
</span><del>-CodeMirror.registerHelper(&quot;wordChars&quot;, &quot;javascript&quot;, /[\\w$]/);
</del><ins>+CodeMirror.registerHelper(&quot;wordChars&quot;, &quot;javascript&quot;, /[\w$]/);
</ins><span class="cx"> 
</span><span class="cx"> CodeMirror.defineMIME(&quot;text/javascript&quot;, &quot;javascript&quot;);
</span><span class="cx"> CodeMirror.defineMIME(&quot;text/ecmascript&quot;, &quot;javascript&quot;);
</span><span class="cx"> CodeMirror.defineMIME(&quot;application/javascript&quot;, &quot;javascript&quot;);
</span><ins>+CodeMirror.defineMIME(&quot;application/x-javascript&quot;, &quot;javascript&quot;);
</ins><span class="cx"> CodeMirror.defineMIME(&quot;application/ecmascript&quot;, &quot;javascript&quot;);
</span><span class="cx"> CodeMirror.defineMIME(&quot;application/json&quot;, {name: &quot;javascript&quot;, json: true});
</span><span class="cx"> CodeMirror.defineMIME(&quot;application/x-json&quot;, {name: &quot;javascript&quot;, json: true});
</span><span class="cx">Property changes on: trunk/Source/WebInspectorUI/UserInterface/External/CodeMirror/javascript.js
</span><span class="cx">___________________________________________________________________
</span></span></pre></div>
<a id="svnexecutable"></a>
<div class="addfile"><h4>Added: svn:executable</h4></div>
<a id="trunkSourceWebInspectorUIUserInterfaceExternalCodeMirrorlivescriptjs"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebInspectorUI/UserInterface/External/CodeMirror/livescript.js (188324 => 188325)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebInspectorUI/UserInterface/External/CodeMirror/livescript.js        2015-08-12 04:58:37 UTC (rev 188324)
+++ trunk/Source/WebInspectorUI/UserInterface/External/CodeMirror/livescript.js        2015-08-12 05:40:27 UTC (rev 188325)
</span><span class="lines">@@ -24,8 +24,8 @@
</span><span class="cx">         var nr = Rules[next_rule];
</span><span class="cx">         if (nr.splice) {
</span><span class="cx">           for (var i$ = 0; i$ &lt; nr.length; ++i$) {
</span><del>-            var r = nr[i$], m;
-            if (r.regex &amp;&amp; (m = stream.match(r.regex))) {
</del><ins>+            var r = nr[i$];
+            if (r.regex &amp;&amp; stream.match(r.regex)) {
</ins><span class="cx">               state.next = r.next || state.next;
</span><span class="cx">               return r.token;
</span><span class="cx">             }
</span><span class="cx">Property changes on: trunk/Source/WebInspectorUI/UserInterface/External/CodeMirror/livescript.js
</span><span class="cx">___________________________________________________________________
</span></span></pre></div>
<a id="svnexecutable"></a>
<div class="addfile"><h4>Added: svn:executable</h4></div>
<a id="trunkSourceWebInspectorUIUserInterfaceExternalCodeMirrormatchbracketsjs"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebInspectorUI/UserInterface/External/CodeMirror/matchbrackets.js (188324 => 188325)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebInspectorUI/UserInterface/External/CodeMirror/matchbrackets.js        2015-08-12 04:58:37 UTC (rev 188324)
+++ trunk/Source/WebInspectorUI/UserInterface/External/CodeMirror/matchbrackets.js        2015-08-12 05:40:27 UTC (rev 188325)
</span><span class="lines">@@ -81,7 +81,7 @@
</span><span class="cx">     if (marks.length) {
</span><span class="cx">       // Kludge to work around the IE bug from issue #1193, where text
</span><span class="cx">       // input stops going to the textare whever this fires.
</span><del>-      if (ie_lt8 &amp;&amp; cm.state.focused) cm.display.input.focus();
</del><ins>+      if (ie_lt8 &amp;&amp; cm.state.focused) cm.focus();
</ins><span class="cx"> 
</span><span class="cx">       var clear = function() {
</span><span class="cx">         cm.operation(function() {
</span><span class="cx">Property changes on: trunk/Source/WebInspectorUI/UserInterface/External/CodeMirror/matchbrackets.js
</span><span class="cx">___________________________________________________________________
</span></span></pre></div>
<a id="svnexecutable"></a>
<div class="addfile"><h4>Added: svn:executable</h4></div>
<a id="trunkSourceWebInspectorUIUserInterfaceExternalCodeMirroroverlayjs"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebInspectorUI/UserInterface/External/CodeMirror/overlay.js (188324 => 188325)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebInspectorUI/UserInterface/External/CodeMirror/overlay.js        2015-08-12 04:58:37 UTC (rev 188324)
+++ trunk/Source/WebInspectorUI/UserInterface/External/CodeMirror/overlay.js        2015-08-12 05:40:27 UTC (rev 188325)
</span><span class="lines">@@ -28,7 +28,7 @@
</span><span class="cx">         overlay: CodeMirror.startState(overlay),
</span><span class="cx">         basePos: 0, baseCur: null,
</span><span class="cx">         overlayPos: 0, overlayCur: null,
</span><del>-        lineSeen: null
</del><ins>+        streamSeen: null
</ins><span class="cx">       };
</span><span class="cx">     },
</span><span class="cx">     copyState: function(state) {
</span><span class="lines">@@ -41,9 +41,9 @@
</span><span class="cx">     },
</span><span class="cx"> 
</span><span class="cx">     token: function(stream, state) {
</span><del>-      if (stream.sol() || stream.string != state.lineSeen ||
</del><ins>+      if (stream != state.streamSeen ||
</ins><span class="cx">           Math.min(state.basePos, state.overlayPos) &lt; stream.start) {
</span><del>-        state.lineSeen = stream.string;
</del><ins>+        state.streamSeen = stream;
</ins><span class="cx">         state.basePos = state.overlayPos = stream.start;
</span><span class="cx">       }
</span><span class="cx"> 
</span><span class="cx">Property changes on: trunk/Source/WebInspectorUI/UserInterface/External/CodeMirror/overlay.js
</span><span class="cx">___________________________________________________________________
</span></span></pre></div>
<a id="svnexecutable"></a>
<div class="addfile"><h4>Added: svn:executable</h4></div>
<a id="trunkSourceWebInspectorUIUserInterfaceExternalCodeMirrorplaceholderjs"></a>
<div class="propset"><h4>Property changes: trunk/Source/WebInspectorUI/UserInterface/External/CodeMirror/placeholder.js</h4>
<pre class="diff"><span>
</span></pre></div>
<a id="svnexecutable"></a>
<div class="addfile"><h4>Added: svn:executable</h4></div>
<a id="trunkSourceWebInspectorUIUserInterfaceExternalCodeMirrorrunmodejs"></a>
<div class="propset"><h4>Property changes: trunk/Source/WebInspectorUI/UserInterface/External/CodeMirror/runmode.js</h4>
<pre class="diff"><span>
</span></pre></div>
<a id="svnexecutable"></a>
<div class="addfile"><h4>Added: svn:executable</h4></div>
<a id="trunkSourceWebInspectorUIUserInterfaceExternalCodeMirrorsassjs"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebInspectorUI/UserInterface/External/CodeMirror/sass.js (188324 => 188325)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebInspectorUI/UserInterface/External/CodeMirror/sass.js        2015-08-12 04:58:37 UTC (rev 188324)
+++ trunk/Source/WebInspectorUI/UserInterface/External/CodeMirror/sass.js        2015-08-12 05:40:27 UTC (rev 188325)
</span><span class="lines">@@ -12,302 +12,368 @@
</span><span class="cx"> &quot;use strict&quot;;
</span><span class="cx"> 
</span><span class="cx"> CodeMirror.defineMode(&quot;sass&quot;, function(config) {
</span><del>-  var tokenRegexp = function(words){
</del><ins>+  function tokenRegexp(words) {
</ins><span class="cx">     return new RegExp(&quot;^&quot; + words.join(&quot;|&quot;));
</span><del>-  };
</del><ins>+  }
</ins><span class="cx"> 
</span><span class="cx">   var keywords = [&quot;true&quot;, &quot;false&quot;, &quot;null&quot;, &quot;auto&quot;];
</span><span class="cx">   var keywordsRegexp = new RegExp(&quot;^&quot; + keywords.join(&quot;|&quot;));
</span><span class="cx"> 
</span><del>-  var operators = [&quot;\\(&quot;, &quot;\\)&quot;, &quot;=&quot;, &quot;&gt;&quot;, &quot;&lt;&quot;, &quot;==&quot;, &quot;&gt;=&quot;, &quot;&lt;=&quot;, &quot;\\+&quot;, &quot;-&quot;, &quot;\\!=&quot;, &quot;/&quot;, &quot;\\*&quot;, &quot;%&quot;, &quot;and&quot;, &quot;or&quot;, &quot;not&quot;];
</del><ins>+  var operators = [&quot;\\(&quot;, &quot;\\)&quot;, &quot;=&quot;, &quot;&gt;&quot;, &quot;&lt;&quot;, &quot;==&quot;, &quot;&gt;=&quot;, &quot;&lt;=&quot;, &quot;\\+&quot;, &quot;-&quot;,
+                   &quot;\\!=&quot;, &quot;/&quot;, &quot;\\*&quot;, &quot;%&quot;, &quot;and&quot;, &quot;or&quot;, &quot;not&quot;, &quot;;&quot;,&quot;\\{&quot;,&quot;\\}&quot;,&quot;:&quot;];
</ins><span class="cx">   var opRegexp = tokenRegexp(operators);
</span><span class="cx"> 
</span><del>-  var pseudoElementsRegexp = /^::?[\w\-]+/;
</del><ins>+  var pseudoElementsRegexp = /^::?[a-zA-Z_][\w\-]*/;
</ins><span class="cx"> 
</span><del>-  var urlTokens = function(stream, state){
</del><ins>+  function urlTokens(stream, state) {
</ins><span class="cx">     var ch = stream.peek();
</span><span class="cx"> 
</span><del>-    if (ch === &quot;)&quot;){
</del><ins>+    if (ch === &quot;)&quot;) {
</ins><span class="cx">       stream.next();
</span><span class="cx">       state.tokenizer = tokenBase;
</span><span class="cx">       return &quot;operator&quot;;
</span><del>-    }else if (ch === &quot;(&quot;){
</del><ins>+    } else if (ch === &quot;(&quot;) {
</ins><span class="cx">       stream.next();
</span><span class="cx">       stream.eatSpace();
</span><span class="cx"> 
</span><span class="cx">       return &quot;operator&quot;;
</span><del>-    }else if (ch === &quot;'&quot; || ch === '&quot;'){
</del><ins>+    } else if (ch === &quot;'&quot; || ch === '&quot;') {
</ins><span class="cx">       state.tokenizer = buildStringTokenizer(stream.next());
</span><span class="cx">       return &quot;string&quot;;
</span><del>-    }else{
</del><ins>+    } else {
</ins><span class="cx">       state.tokenizer = buildStringTokenizer(&quot;)&quot;, false);
</span><span class="cx">       return &quot;string&quot;;
</span><span class="cx">     }
</span><del>-  };
-  var multilineComment = function(stream, state) {
-    if (stream.skipTo(&quot;*/&quot;)){
-      stream.next();
-      stream.next();
-      state.tokenizer = tokenBase;
-    }else {
-      stream.next();
-    }
</del><ins>+  }
+  function comment(indentation, multiLine) {
+    return function(stream, state) {
+      if (stream.sol() &amp;&amp; stream.indentation() &lt;= indentation) {
+        state.tokenizer = tokenBase;
+        return tokenBase(stream, state);
+      }
</ins><span class="cx"> 
</span><del>-    return &quot;comment&quot;;
-  };
</del><ins>+      if (multiLine &amp;&amp; stream.skipTo(&quot;*/&quot;)) {
+        stream.next();
+        stream.next();
+        state.tokenizer = tokenBase;
+      } else {
+        stream.skipToEnd();
+      }
</ins><span class="cx"> 
</span><del>-  var buildStringTokenizer = function(quote, greedy){
-    if(greedy == null){ greedy = true; }
</del><ins>+      return &quot;comment&quot;;
+    };
+  }
</ins><span class="cx"> 
</span><del>-    function stringTokenizer(stream, state){
</del><ins>+  function buildStringTokenizer(quote, greedy) {
+    if (greedy == null) { greedy = true; }
+
+    function stringTokenizer(stream, state) {
</ins><span class="cx">       var nextChar = stream.next();
</span><span class="cx">       var peekChar = stream.peek();
</span><span class="cx">       var previousChar = stream.string.charAt(stream.pos-2);
</span><span class="cx"> 
</span><span class="cx">       var endingString = ((nextChar !== &quot;\\&quot; &amp;&amp; peekChar === quote) || (nextChar === quote &amp;&amp; previousChar !== &quot;\\&quot;));
</span><span class="cx"> 
</span><del>-      /*
-      console.log(&quot;previousChar: &quot; + previousChar);
-      console.log(&quot;nextChar: &quot; + nextChar);
-      console.log(&quot;peekChar: &quot; + peekChar);
-      console.log(&quot;ending: &quot; + endingString);
-      */
-
-      if (endingString){
</del><ins>+      if (endingString) {
</ins><span class="cx">         if (nextChar !== quote &amp;&amp; greedy) { stream.next(); }
</span><span class="cx">         state.tokenizer = tokenBase;
</span><span class="cx">         return &quot;string&quot;;
</span><del>-      }else if (nextChar === &quot;#&quot; &amp;&amp; peekChar === &quot;{&quot;){
</del><ins>+      } else if (nextChar === &quot;#&quot; &amp;&amp; peekChar === &quot;{&quot;) {
</ins><span class="cx">         state.tokenizer = buildInterpolationTokenizer(stringTokenizer);
</span><span class="cx">         stream.next();
</span><span class="cx">         return &quot;operator&quot;;
</span><del>-      }else {
</del><ins>+      } else {
</ins><span class="cx">         return &quot;string&quot;;
</span><span class="cx">       }
</span><span class="cx">     }
</span><span class="cx"> 
</span><span class="cx">     return stringTokenizer;
</span><del>-  };
</del><ins>+  }
</ins><span class="cx"> 
</span><del>-  var buildInterpolationTokenizer = function(currentTokenizer){
-    return function(stream, state){
-      if (stream.peek() === &quot;}&quot;){
</del><ins>+  function buildInterpolationTokenizer(currentTokenizer) {
+    return function(stream, state) {
+      if (stream.peek() === &quot;}&quot;) {
</ins><span class="cx">         stream.next();
</span><span class="cx">         state.tokenizer = currentTokenizer;
</span><span class="cx">         return &quot;operator&quot;;
</span><del>-      }else{
</del><ins>+      } else {
</ins><span class="cx">         return tokenBase(stream, state);
</span><span class="cx">       }
</span><span class="cx">     };
</span><del>-  };
</del><ins>+  }
</ins><span class="cx"> 
</span><del>-  var indent = function(state){
-    if (state.indentCount == 0){
</del><ins>+  function indent(state) {
+    if (state.indentCount == 0) {
</ins><span class="cx">       state.indentCount++;
</span><span class="cx">       var lastScopeOffset = state.scopes[0].offset;
</span><span class="cx">       var currentOffset = lastScopeOffset + config.indentUnit;
</span><span class="cx">       state.scopes.unshift({ offset:currentOffset });
</span><span class="cx">     }
</span><del>-  };
</del><ins>+  }
</ins><span class="cx"> 
</span><del>-  var dedent = function(state){
-    if (state.scopes.length == 1) { return; }
</del><ins>+  function dedent(state) {
+    if (state.scopes.length == 1) return;
</ins><span class="cx"> 
</span><span class="cx">     state.scopes.shift();
</span><del>-  };
</del><ins>+  }
</ins><span class="cx"> 
</span><del>-  var tokenBase = function(stream, state) {
</del><ins>+  function tokenBase(stream, state) {
</ins><span class="cx">     var ch = stream.peek();
</span><span class="cx"> 
</span><del>-    // Single line Comment
-    if (stream.match('//')) {
-      stream.skipToEnd();
-      return &quot;comment&quot;;
</del><ins>+    // Comment
+    if (stream.match(&quot;/*&quot;)) {
+      state.tokenizer = comment(stream.indentation(), true);
+      return state.tokenizer(stream, state);
</ins><span class="cx">     }
</span><del>-
-    // Multiline Comment
-    if (stream.match('/*')){
-      state.tokenizer = multilineComment;
</del><ins>+    if (stream.match(&quot;//&quot;)) {
+      state.tokenizer = comment(stream.indentation(), false);
</ins><span class="cx">       return state.tokenizer(stream, state);
</span><span class="cx">     }
</span><span class="cx"> 
</span><span class="cx">     // Interpolation
</span><del>-    if (stream.match('#{')){
-    state.tokenizer = buildInterpolationTokenizer(tokenBase);
</del><ins>+    if (stream.match(&quot;#{&quot;)) {
+      state.tokenizer = buildInterpolationTokenizer(tokenBase);
</ins><span class="cx">       return &quot;operator&quot;;
</span><span class="cx">     }
</span><span class="cx"> 
</span><del>-    if (ch === &quot;.&quot;){
</del><ins>+    // Strings
+    if (ch === '&quot;' || ch === &quot;'&quot;) {
</ins><span class="cx">       stream.next();
</span><ins>+      state.tokenizer = buildStringTokenizer(ch);
+      return &quot;string&quot;;
+    }
</ins><span class="cx"> 
</span><del>-      // Match class selectors
-      if (stream.match(/^[\w-]+/)){
-        indent(state);
-        return &quot;atom&quot;;
-      }else if (stream.peek() === &quot;#&quot;){
-        indent(state);
-        return &quot;atom&quot;;
-      }else{
-        return &quot;operator&quot;;
</del><ins>+    if(!state.cursorHalf){// state.cursorHalf === 0
+    // first half i.e. before : for key-value pairs
+    // including selectors
+
+      if (ch === &quot;.&quot;) {
+        stream.next();
+        if (stream.match(/^[\w-]+/)) {
+          indent(state);
+          return &quot;atom&quot;;
+        } else if (stream.peek() === &quot;#&quot;) {
+          indent(state);
+          return &quot;atom&quot;;
+        }
</ins><span class="cx">       }
</span><del>-    }
</del><span class="cx"> 
</span><del>-    if (ch === &quot;#&quot;){
-      stream.next();
</del><ins>+      if (ch === &quot;#&quot;) {
+        stream.next();
+        // ID selectors
+        if (stream.match(/^[\w-]+/)) {
+          indent(state);
+          return &quot;atom&quot;;
+        }
+        if (stream.peek() === &quot;#&quot;) {
+          indent(state);
+          return &quot;atom&quot;;
+        }
+      }
</ins><span class="cx"> 
</span><del>-      // Hex numbers
-      if (stream.match(/[0-9a-fA-F]{6}|[0-9a-fA-F]{3}/)){
-        return &quot;number&quot;;
</del><ins>+      // Variables
+      if (ch === &quot;$&quot;) {
+        stream.next();
+        stream.eatWhile(/[\w-]/);
+        return &quot;variable-2&quot;;
</ins><span class="cx">       }
</span><span class="cx"> 
</span><del>-      // ID selectors
-      if (stream.match(/^[\w-]+/)){
-        indent(state);
</del><ins>+      // Numbers
+      if (stream.match(/^-?[0-9\.]+/))
+        return &quot;number&quot;;
+
+      // Units
+      if (stream.match(/^(px|em|in)\b/))
+        return &quot;unit&quot;;
+
+      if (stream.match(keywordsRegexp))
+        return &quot;keyword&quot;;
+
+      if (stream.match(/^url/) &amp;&amp; stream.peek() === &quot;(&quot;) {
+        state.tokenizer = urlTokens;
</ins><span class="cx">         return &quot;atom&quot;;
</span><span class="cx">       }
</span><span class="cx"> 
</span><del>-      if (stream.peek() === &quot;#&quot;){
-        indent(state);
-        return &quot;atom&quot;;
</del><ins>+      if (ch === &quot;=&quot;) {
+        // Match shortcut mixin definition
+        if (stream.match(/^=[\w-]+/)) {
+          indent(state);
+          return &quot;meta&quot;;
+        }
</ins><span class="cx">       }
</span><del>-    }
</del><span class="cx"> 
</span><del>-    // Numbers
-    if (stream.match(/^-?[0-9\.]+/)){
-      return &quot;number&quot;;
-    }
</del><ins>+      if (ch === &quot;+&quot;) {
+        // Match shortcut mixin definition
+        if (stream.match(/^\+[\w-]+/)){
+          return &quot;variable-3&quot;;
+        }
+      }
</ins><span class="cx"> 
</span><del>-    // Units
-    if (stream.match(/^(px|em|in)\b/)){
-      return &quot;unit&quot;;
-    }
</del><ins>+      if(ch === &quot;@&quot;){
+        if(stream.match(/@extend/)){
+          if(!stream.match(/\s*[\w]/))
+            dedent(state);
+        }
+      }
</ins><span class="cx"> 
</span><del>-    if (stream.match(keywordsRegexp)){
-      return &quot;keyword&quot;;
-    }
</del><span class="cx"> 
</span><del>-    if (stream.match(/^url/) &amp;&amp; stream.peek() === &quot;(&quot;){
-      state.tokenizer = urlTokens;
-      return &quot;atom&quot;;
-    }
</del><ins>+      // Indent Directives
+      if (stream.match(/^@(else if|if|media|else|for|each|while|mixin|function)/)) {
+        indent(state);
+        return &quot;meta&quot;;
+      }
</ins><span class="cx"> 
</span><del>-    // Variables
-    if (ch === &quot;$&quot;){
-      stream.next();
-      stream.eatWhile(/[\w-]/);
</del><ins>+      // Other Directives
+      if (ch === &quot;@&quot;) {
+        stream.next();
+        stream.eatWhile(/[\w-]/);
+        return &quot;meta&quot;;
+      }
</ins><span class="cx"> 
</span><del>-      if (stream.peek() === &quot;:&quot;){
</del><ins>+      if (stream.eatWhile(/[\w-]/)){
+        if(stream.match(/ *: *[\w-\+\$#!\(&quot;']/,false)){
+          return &quot;property&quot;;
+        }
+        else if(stream.match(/ *:/,false)){
+          indent(state);
+          state.cursorHalf = 1;
+          return &quot;atom&quot;;
+        }
+        else if(stream.match(/ *,/,false)){
+          return &quot;atom&quot;;
+        }
+        else{
+          indent(state);
+          return &quot;atom&quot;;
+        }
+      }
+
+      if(ch === &quot;:&quot;){
+        if (stream.match(pseudoElementsRegexp)){ // could be a pseudo-element
+          return &quot;keyword&quot;;
+        }
</ins><span class="cx">         stream.next();
</span><del>-        return &quot;variable-2&quot;;
-      }else{
-        return &quot;variable-3&quot;;
</del><ins>+        state.cursorHalf=1;
+        return &quot;operator&quot;;
</ins><span class="cx">       }
</span><del>-    }
</del><span class="cx"> 
</span><del>-    if (ch === &quot;!&quot;){
-      stream.next();
</del><ins>+    } // cursorHalf===0 ends here
+    else{
</ins><span class="cx"> 
</span><del>-      if (stream.match(/^[\w]+/)){
-        return &quot;keyword&quot;;
</del><ins>+      if (ch === &quot;#&quot;) {
+        stream.next();
+        // Hex numbers
+        if (stream.match(/[0-9a-fA-F]{6}|[0-9a-fA-F]{3}/)){
+          if(!stream.peek()){
+            state.cursorHalf = 0;
+          }
+          return &quot;number&quot;;
+        }
</ins><span class="cx">       }
</span><span class="cx"> 
</span><del>-      return &quot;operator&quot;;
-    }
</del><ins>+      // Numbers
+      if (stream.match(/^-?[0-9\.]+/)){
+        if(!stream.peek()){
+          state.cursorHalf = 0;
+        }
+        return &quot;number&quot;;
+      }
</ins><span class="cx"> 
</span><del>-    if (ch === &quot;=&quot;){
-      stream.next();
</del><ins>+      // Units
+      if (stream.match(/^(px|em|in)\b/)){
+        if(!stream.peek()){
+          state.cursorHalf = 0;
+        }
+        return &quot;unit&quot;;
+      }
</ins><span class="cx"> 
</span><del>-      // Match shortcut mixin definition
-      if (stream.match(/^[\w-]+/)){
-        indent(state);
-        return &quot;meta&quot;;
-      }else {
-        return &quot;operator&quot;;
</del><ins>+      if (stream.match(keywordsRegexp)){
+        if(!stream.peek()){
+          state.cursorHalf = 0;
+        }
+        return &quot;keyword&quot;;
</ins><span class="cx">       }
</span><del>-    }
</del><span class="cx"> 
</span><del>-    if (ch === &quot;+&quot;){
-      stream.next();
</del><ins>+      if (stream.match(/^url/) &amp;&amp; stream.peek() === &quot;(&quot;) {
+        state.tokenizer = urlTokens;
+        if(!stream.peek()){
+          state.cursorHalf = 0;
+        }
+        return &quot;atom&quot;;
+      }
</ins><span class="cx"> 
</span><del>-      // Match shortcut mixin definition
-      if (stream.match(/^[\w-]+/)){
</del><ins>+      // Variables
+      if (ch === &quot;$&quot;) {
+        stream.next();
+        stream.eatWhile(/[\w-]/);
+        if(!stream.peek()){
+          state.cursorHalf = 0;
+        }
</ins><span class="cx">         return &quot;variable-3&quot;;
</span><del>-      }else {
-        return &quot;operator&quot;;
</del><span class="cx">       }
</span><del>-    }
</del><span class="cx"> 
</span><del>-    // Indent Directives
-    if (stream.match(/^@(else if|if|media|else|for|each|while|mixin|function)/)){
-      indent(state);
-      return &quot;meta&quot;;
-    }
</del><ins>+      // bang character for !important, !default, etc.
+      if (ch === &quot;!&quot;) {
+        stream.next();
+        if(!stream.peek()){
+          state.cursorHalf = 0;
+        }
+        return stream.match(/^[\w]+/) ? &quot;keyword&quot;: &quot;operator&quot;;
+      }
</ins><span class="cx"> 
</span><del>-    // Other Directives
-    if (ch === &quot;@&quot;){
-      stream.next();
-      stream.eatWhile(/[\w-]/);
-      return &quot;meta&quot;;
-    }
</del><ins>+      if (stream.match(opRegexp)){
+        if(!stream.peek()){
+          state.cursorHalf = 0;
+        }
+        return &quot;operator&quot;;
+      }
</ins><span class="cx"> 
</span><del>-    // Strings
-    if (ch === '&quot;' || ch === &quot;'&quot;){
-      stream.next();
-      state.tokenizer = buildStringTokenizer(ch);
-      return &quot;string&quot;;
-    }
</del><ins>+      // attributes
+      if (stream.eatWhile(/[\w-]/)) {
+        if(!stream.peek()){
+          state.cursorHalf = 0;
+        }
+        return &quot;attribute&quot;;
+      }
</ins><span class="cx"> 
</span><del>-    // Pseudo element selectors
-    if (ch == ':' &amp;&amp; stream.match(pseudoElementsRegexp)){
-      return &quot;keyword&quot;;
-    }
</del><ins>+      //stream.eatSpace();
+      if(!stream.peek()){
+        state.cursorHalf = 0;
+        return null;
+      }
</ins><span class="cx"> 
</span><del>-    // atoms
-    if (stream.eatWhile(/[\w-&amp;]/)){
-      // matches a property definition
-      if (stream.peek() === &quot;:&quot; &amp;&amp; !stream.match(pseudoElementsRegexp, false))
-        return &quot;property&quot;;
-      else
-        return &quot;atom&quot;;
-    }
</del><ins>+    } // else ends here
</ins><span class="cx"> 
</span><del>-    if (stream.match(opRegexp)){
</del><ins>+    if (stream.match(opRegexp))
</ins><span class="cx">       return &quot;operator&quot;;
</span><del>-    }
</del><span class="cx"> 
</span><span class="cx">     // If we haven't returned by now, we move 1 character
</span><span class="cx">     // and return an error
</span><span class="cx">     stream.next();
</span><span class="cx">     return null;
</span><del>-  };
</del><ins>+  }
</ins><span class="cx"> 
</span><del>-  var tokenLexer = function(stream, state) {
-    if (stream.sol()){
-      state.indentCount = 0;
-    }
</del><ins>+  function tokenLexer(stream, state) {
+    if (stream.sol()) state.indentCount = 0;
</ins><span class="cx">     var style = state.tokenizer(stream, state);
</span><span class="cx">     var current = stream.current();
</span><span class="cx"> 
</span><del>-    if (current === &quot;@return&quot;){
</del><ins>+    if (current === &quot;@return&quot; || current === &quot;}&quot;){
</ins><span class="cx">       dedent(state);
</span><span class="cx">     }
</span><span class="cx"> 
</span><del>-    if (style === &quot;atom&quot;){
-      indent(state);
-    }
</del><ins>+    if (style !== null) {
+      var startOfToken = stream.pos - current.length;
</ins><span class="cx"> 
</span><del>-    if (style !== null){
-      var startOfToken = stream.pos - current.length;
</del><span class="cx">       var withCurrentIndent = startOfToken + (config.indentUnit * state.indentCount);
</span><span class="cx"> 
</span><span class="cx">       var newScopes = [];
</span><span class="cx"> 
</span><del>-      for (var i = 0; i &lt; state.scopes.length; i++){
</del><ins>+      for (var i = 0; i &lt; state.scopes.length; i++) {
</ins><span class="cx">         var scope = state.scopes[i];
</span><span class="cx"> 
</span><del>-        if (scope.offset &lt;= withCurrentIndent){
</del><ins>+        if (scope.offset &lt;= withCurrentIndent)
</ins><span class="cx">           newScopes.push(scope);
</span><del>-        }
</del><span class="cx">       }
</span><span class="cx"> 
</span><span class="cx">       state.scopes = newScopes;
</span><span class="lines">@@ -315,13 +381,16 @@
</span><span class="cx"> 
</span><span class="cx"> 
</span><span class="cx">     return style;
</span><del>-  };
</del><ins>+  }
</ins><span class="cx"> 
</span><span class="cx">   return {
</span><span class="cx">     startState: function() {
</span><span class="cx">       return {
</span><span class="cx">         tokenizer: tokenBase,
</span><del>-        scopes: [{offset: 0, type: 'sass'}],
</del><ins>+        scopes: [{offset: 0, type: &quot;sass&quot;}],
+        indentCount: 0,
+        cursorHalf: 0,  // cursor half tells us if cursor lies after (1)
+                        // or before (0) colon (well... more or less)
</ins><span class="cx">         definedVars: [],
</span><span class="cx">         definedMixins: []
</span><span class="cx">       };
</span><span class="cx">Property changes on: trunk/Source/WebInspectorUI/UserInterface/External/CodeMirror/sass.js
</span><span class="cx">___________________________________________________________________
</span></span></pre></div>
<a id="svnexecutable"></a>
<div class="addfile"><h4>Added: svn:executable</h4></div>
<a id="trunkSourceWebInspectorUIUserInterfaceExternalCodeMirrorsearchcursorjs"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebInspectorUI/UserInterface/External/CodeMirror/searchcursor.js (188324 => 188325)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebInspectorUI/UserInterface/External/CodeMirror/searchcursor.js        2015-08-12 04:58:37 UTC (rev 188324)
+++ trunk/Source/WebInspectorUI/UserInterface/External/CodeMirror/searchcursor.js        2015-08-12 05:40:27 UTC (rev 188325)
</span><span class="lines">@@ -107,7 +107,7 @@
</span><span class="cx">             var from = Pos(pos.line, cut);
</span><span class="cx">             for (var ln = pos.line + 1, i = 1; i &lt; last; ++i, ++ln)
</span><span class="cx">               if (target[i] != fold(doc.getLine(ln))) return;
</span><del>-            if (doc.getLine(ln).slice(0, origTarget[last].length) != target[last]) return;
</del><ins>+            if (fold(doc.getLine(ln).slice(0, origTarget[last].length)) != target[last]) return;
</ins><span class="cx">             return {from: from, to: Pos(ln, origTarget[last].length)};
</span><span class="cx">           }
</span><span class="cx">         };
</span><span class="lines">@@ -148,10 +148,10 @@
</span><span class="cx">     from: function() {if (this.atOccurrence) return this.pos.from;},
</span><span class="cx">     to: function() {if (this.atOccurrence) return this.pos.to;},
</span><span class="cx"> 
</span><del>-    replace: function(newText) {
</del><ins>+    replace: function(newText, origin) {
</ins><span class="cx">       if (!this.atOccurrence) return;
</span><span class="cx">       var lines = CodeMirror.splitLines(newText);
</span><del>-      this.doc.replaceRange(lines, this.pos.from, this.pos.to);
</del><ins>+      this.doc.replaceRange(lines, this.pos.from, this.pos.to, origin);
</ins><span class="cx">       this.pos.to = Pos(this.pos.from.line + lines.length - 1,
</span><span class="cx">                         lines[lines.length - 1].length + (lines.length == 1 ? this.pos.from.ch : 0));
</span><span class="cx">     }
</span><span class="lines">@@ -177,9 +177,9 @@
</span><span class="cx">   });
</span><span class="cx"> 
</span><span class="cx">   CodeMirror.defineExtension(&quot;selectMatches&quot;, function(query, caseFold) {
</span><del>-    var ranges = [], next;
</del><ins>+    var ranges = [];
</ins><span class="cx">     var cur = this.getSearchCursor(query, this.getCursor(&quot;from&quot;), caseFold);
</span><del>-    while (next = cur.findNext()) {
</del><ins>+    while (cur.findNext()) {
</ins><span class="cx">       if (CodeMirror.cmpPos(cur.to(), this.getCursor(&quot;to&quot;)) &gt; 0) break;
</span><span class="cx">       ranges.push({anchor: cur.from(), head: cur.to()});
</span><span class="cx">     }
</span><span class="cx">Property changes on: trunk/Source/WebInspectorUI/UserInterface/External/CodeMirror/searchcursor.js
</span><span class="cx">___________________________________________________________________
</span></span></pre></div>
<a id="svnexecutable"></a>
<div class="addfile"><h4>Added: svn:executable</h4></div>
<a id="trunkSourceWebInspectorUIUserInterfaceExternalCodeMirrorsqljs"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebInspectorUI/UserInterface/External/CodeMirror/sql.js (188324 => 188325)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebInspectorUI/UserInterface/External/CodeMirror/sql.js        2015-08-12 04:58:37 UTC (rev 188324)
+++ trunk/Source/WebInspectorUI/UserInterface/External/CodeMirror/sql.js        2015-08-12 05:40:27 UTC (rev 188325)
</span><span class="lines">@@ -190,7 +190,7 @@
</span><span class="cx"> 
</span><span class="cx">     indent: function(state, textAfter) {
</span><span class="cx">       var cx = state.context;
</span><del>-      if (!cx) return 0;
</del><ins>+      if (!cx) return CodeMirror.Pass;
</ins><span class="cx">       var closing = textAfter.charAt(0) == cx.type;
</span><span class="cx">       if (cx.align) return cx.col + (closing ? 0 : 1);
</span><span class="cx">       else return cx.indent + (closing ? 0 : config.indentUnit);
</span><span class="lines">@@ -213,7 +213,8 @@
</span><span class="cx">     while ((ch = stream.next()) != null) {
</span><span class="cx">       if (ch == &quot;`&quot; &amp;&amp; !stream.eat(&quot;`&quot;)) return &quot;variable-2&quot;;
</span><span class="cx">     }
</span><del>-    return null;
</del><ins>+    stream.backUp(stream.current().length - 1);
+    return stream.eatWhile(/\w/) ? &quot;variable-2&quot; : null;
</ins><span class="cx">   }
</span><span class="cx"> 
</span><span class="cx">   // variable token
</span><span class="lines">@@ -256,7 +257,7 @@
</span><span class="cx">   }
</span><span class="cx"> 
</span><span class="cx">   // these keywords are used by all SQL dialects (however, a mode can still overwrite it)
</span><del>-  var sqlKeywords = &quot;alter and as asc between by count create delete desc distinct drop from having in insert into is join like not on or order select set table union update values where &quot;;
</del><ins>+  var sqlKeywords = &quot;alter and as asc between by count create delete desc distinct drop from group having in insert into is join like not on or order select set table union update values where &quot;;
</ins><span class="cx"> 
</span><span class="cx">   // turn a space-separated list into an array
</span><span class="cx">   function set(str) {
</span><span class="lines">@@ -279,7 +280,7 @@
</span><span class="cx">   CodeMirror.defineMIME(&quot;text/x-mssql&quot;, {
</span><span class="cx">     name: &quot;sql&quot;,
</span><span class="cx">     client: set(&quot;charset clear connect edit ego exit go help nopager notee nowarning pager print prompt quit rehash source status system tee&quot;),
</span><del>-    keywords: set(sqlKeywords + &quot;begin trigger proc view index for add constraint key primary foreign collate clustered nonclustered&quot;),
</del><ins>+    keywords: set(sqlKeywords + &quot;begin trigger proc view index for add constraint key primary foreign collate clustered nonclustered declare&quot;),
</ins><span class="cx">     builtin: set(&quot;bigint numeric bit smallint decimal smallmoney int tinyint money float real char varchar text nchar nvarchar ntext binary varbinary image cursor timestamp hierarchyid uniqueidentifier sql_variant xml table &quot;),
</span><span class="cx">     atoms: set(&quot;false true null unknown&quot;),
</span><span class="cx">     operatorChars: /^[*+\-%&lt;&gt;!=]/,
</span><span class="lines">@@ -292,7 +293,7 @@
</span><span class="cx">   CodeMirror.defineMIME(&quot;text/x-mysql&quot;, {
</span><span class="cx">     name: &quot;sql&quot;,
</span><span class="cx">     client: set(&quot;charset clear connect edit ego exit go help nopager notee nowarning pager print prompt quit rehash source status system tee&quot;),
</span><del>-    keywords: set(sqlKeywords + &quot;accessible action add after algorithm all analyze asensitive at authors auto_increment autocommit avg avg_row_length before binary binlog both btree cache call cascade cascaded case catalog_name chain change changed character check checkpoint checksum class_origin client_statistics close coalesce code collate collation collations column columns comment commit committed completion concurrent condition connection consistent constraint contains continue contributors convert cross current current_date current_time current_timestamp current_user cursor data database databases day_hour day_microsecond day_minute day_second deallocate dec declare default delay_key_write delayed delimiter des_key_file describe deterministic dev_pop dev_samp deviance diagnostics directory disable discard distinctrow div dual dumpfile each elseif enable enclosed end ends engine engines enum errors escape escaped even event events every execute exists e
 xit explain extended fast fetch field fields first flush for force foreign found_rows full fulltext function general get global grant grants group groupby_concat handler hash help high_priority hosts hour_microsecond hour_minute hour_second if ignore ignore_server_ids import index index_statistics infile inner innodb inout insensitive insert_method install interval invoker isolation iterate key keys kill language last leading leave left level limit linear lines list load local localtime localtimestamp lock logs low_priority master master_heartbeat_period master_ssl_verify_server_cert masters match max max_rows maxvalue message_text middleint migrate min min_rows minute_microsecond minute_second mod mode modifies modify mutex mysql_errno natural next no no_write_to_binlog offline offset one online open optimize option optionally out outer outfile pack_keys parser partition partitions password phase plugin plugins prepare preserve prev primary privileges procedure processlist 
 profile profiles purge query quick range read read_write reads real rebuild recover references regexp relaylog release remove rename reorganize repair repeatable replace require resignal restrict resume return returns revoke right rlike rollback rollup row row_format rtree savepoint schedule schema schema_name schemas second_microsecond security sensitive separator serializable server session share show signal slave slow smallint snapshot soname spatial specific sql sql_big_result sql_buffer_result sql_cache sql_calc_found_rows sql_no_cache sql_small_result sqlexception sqlstate sqlwarning ssl start starting starts status std stddev stddev_pop stddev_samp storage straight_join subclass_origin sum suspend table_name table_statistics tables tablespace temporary terminated to trailing transaction trigger triggers truncate uncommitted undo uninstall unique unlock upgrade usage use use_frm user user_resources user_statistics using utc_date utc_time utc_timestamp value variables v
 arying view views warnings when while with work write xa xor year_month zerofill begin do then else loop repeat&quot;),
</del><ins>+    keywords: set(sqlKeywords + &quot;accessible action add after algorithm all analyze asensitive at authors auto_increment autocommit avg avg_row_length before binary binlog both btree cache call cascade cascaded case catalog_name chain change changed character check checkpoint checksum class_origin client_statistics close coalesce code collate collation collations column columns comment commit committed completion concurrent condition connection consistent constraint contains continue contributors convert cross current current_date current_time current_timestamp current_user cursor data database databases day_hour day_microsecond day_minute day_second deallocate dec declare default delay_key_write delayed delimiter des_key_file describe deterministic dev_pop dev_samp deviance diagnostics directory disable discard distinctrow div dual dumpfile each elseif enable enclosed end ends engine engines enum errors escape escaped even event events every execute exists ex
 it explain extended fast fetch field fields first flush for force foreign found_rows full fulltext function general get global grant grants group group_concat handler hash help high_priority hosts hour_microsecond hour_minute hour_second if ignore ignore_server_ids import index index_statistics infile inner innodb inout insensitive insert_method install interval invoker isolation iterate key keys kill language last leading leave left level limit linear lines list load local localtime localtimestamp lock logs low_priority master master_heartbeat_period master_ssl_verify_server_cert masters match max max_rows maxvalue message_text middleint migrate min min_rows minute_microsecond minute_second mod mode modifies modify mutex mysql_errno natural next no no_write_to_binlog offline offset one online open optimize option optionally out outer outfile pack_keys parser partition partitions password phase plugin plugins prepare preserve prev primary privileges procedure processlist pro
 file profiles purge query quick range read read_write reads real rebuild recover references regexp relaylog release remove rename reorganize repair repeatable replace require resignal restrict resume return returns revoke right rlike rollback rollup row row_format rtree savepoint schedule schema schema_name schemas second_microsecond security sensitive separator serializable server session share show signal slave slow smallint snapshot soname spatial specific sql sql_big_result sql_buffer_result sql_cache sql_calc_found_rows sql_no_cache sql_small_result sqlexception sqlstate sqlwarning ssl start starting starts status std stddev stddev_pop stddev_samp storage straight_join subclass_origin sum suspend table_name table_statistics tables tablespace temporary terminated to trailing transaction trigger triggers truncate uncommitted undo uninstall unique unlock upgrade usage use use_frm user user_resources user_statistics using utc_date utc_time utc_timestamp value variables vary
 ing view views warnings when while with work write xa xor year_month zerofill begin do then else loop repeat&quot;),
</ins><span class="cx">     builtin: set(&quot;bool boolean bit blob decimal double float long longblob longtext medium mediumblob mediumint mediumtext time timestamp tinyblob tinyint tinytext text bigint int int1 int2 int3 int4 int8 integer float float4 float8 double char varbinary varchar varcharacter precision date datetime year unsigned signed numeric&quot;),
</span><span class="cx">     atoms: set(&quot;false true null unknown&quot;),
</span><span class="cx">     operatorChars: /^[*+\-%&lt;&gt;!=&amp;|^]/,
</span><span class="lines">@@ -326,9 +327,9 @@
</span><span class="cx">   CodeMirror.defineMIME(&quot;text/x-cassandra&quot;, {
</span><span class="cx">     name: &quot;sql&quot;,
</span><span class="cx">     client: { },
</span><del>-    keywords: set(&quot;use select from using consistency where limit first reversed first and in insert into values using consistency ttl update set delete truncate begin batch apply create keyspace with columnfamily primary key index on drop alter type add any one quorum all local_quorum each_quorum&quot;),
-    builtin: set(&quot;ascii bigint blob boolean counter decimal double float int text timestamp uuid varchar varint&quot;),
-    atoms: set(&quot;false true&quot;),
</del><ins>+    keywords: set(&quot;add all allow alter and any apply as asc authorize batch begin by clustering columnfamily compact consistency count create custom delete desc distinct drop each_quorum exists filtering from grant if in index insert into key keyspace keyspaces level limit local_one local_quorum modify nan norecursive nosuperuser not of on one order password permission permissions primary quorum rename revoke schema select set storage superuser table three to token truncate ttl two type unlogged update use user users using values where with writetime&quot;),
+    builtin: set(&quot;ascii bigint blob boolean counter decimal double float frozen inet int list map static text timestamp timeuuid tuple uuid varchar varint&quot;),
+    atoms: set(&quot;false true infinity NaN&quot;),
</ins><span class="cx">     operatorChars: /^[&lt;&gt;=]/,
</span><span class="cx">     dateSQL: { },
</span><span class="cx">     support: set(&quot;commentSlashSlash decimallessFloat&quot;),
</span><span class="lines">@@ -366,8 +367,6 @@
</span><span class="cx"> 
</span><span class="cx">   keywords:
</span><span class="cx">     A list of keywords you want to be highlighted.
</span><del>-  functions:
-    A list of function names you want to be highlighted.
</del><span class="cx">   builtin:
</span><span class="cx">     A list of builtin types you want to be highlighted (if you want types to be of class &quot;builtin&quot; instead of &quot;keyword&quot;).
</span><span class="cx">   operatorChars:
</span><span class="cx">Property changes on: trunk/Source/WebInspectorUI/UserInterface/External/CodeMirror/sql.js
</span><span class="cx">___________________________________________________________________
</span></span></pre></div>
<a id="svnexecutable"></a>
<div class="addfile"><h4>Added: svn:executable</h4></div>
<a id="trunkSourceWebInspectorUIUserInterfaceExternalCodeMirrorxmljs"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebInspectorUI/UserInterface/External/CodeMirror/xml.js (188324 => 188325)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebInspectorUI/UserInterface/External/CodeMirror/xml.js        2015-08-12 04:58:37 UTC (rev 188324)
+++ trunk/Source/WebInspectorUI/UserInterface/External/CodeMirror/xml.js        2015-08-12 05:40:27 UTC (rev 188325)
</span><span class="lines">@@ -21,7 +21,7 @@
</span><span class="cx">     autoSelfClosers: {'area': true, 'base': true, 'br': true, 'col': true, 'command': true,
</span><span class="cx">                       'embed': true, 'frame': true, 'hr': true, 'img': true, 'input': true,
</span><span class="cx">                       'keygen': true, 'link': true, 'meta': true, 'param': true, 'source': true,
</span><del>-                      'track': true, 'wbr': true},
</del><ins>+                      'track': true, 'wbr': true, 'menuitem': true},
</ins><span class="cx">     implicitlyClosed: {'dd': true, 'li': true, 'optgroup': true, 'option': true, 'p': true,
</span><span class="cx">                        'rp': true, 'rt': true, 'tbody': true, 'td': true, 'tfoot': true,
</span><span class="cx">                        'th': true, 'tr': true},
</span><span class="lines">@@ -109,6 +109,7 @@
</span><span class="cx">       return null;
</span><span class="cx">     }
</span><span class="cx">   }
</span><ins>+  inText.isInText = true;
</ins><span class="cx"> 
</span><span class="cx">   function inTag(stream, state) {
</span><span class="cx">     var ch = stream.next();
</span><span class="cx">Property changes on: trunk/Source/WebInspectorUI/UserInterface/External/CodeMirror/xml.js
</span><span class="cx">___________________________________________________________________
</span></span></pre></div>
<a id="svnexecutable"></a>
<div class="addfile"><h4>Added: svn:executable</h4></div>
<a id="trunkSourceWebInspectorUIUserInterfaceViewsCSSStyleDeclarationTextEditorcss"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebInspectorUI/UserInterface/Views/CSSStyleDeclarationTextEditor.css (188324 => 188325)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebInspectorUI/UserInterface/Views/CSSStyleDeclarationTextEditor.css        2015-08-12 04:58:37 UTC (rev 188324)
+++ trunk/Source/WebInspectorUI/UserInterface/Views/CSSStyleDeclarationTextEditor.css        2015-08-12 05:40:27 UTC (rev 188325)
</span><span class="lines">@@ -45,7 +45,7 @@
</span><span class="cx"> 
</span><span class="cx"> .css-style-text-editor &gt; .CodeMirror pre {
</span><span class="cx">     /* Compensate for the checkboxes so properties line up with readonly styles that do not have checkboxes. */
</span><del>-    padding: 1px 5px 1px 25px;
</del><ins>+    padding: 0 5px 0 25px;
</ins><span class="cx">     text-indent: -21px;
</span><span class="cx"> }
</span><span class="cx"> 
</span></span></pre></div>
<a id="trunkSourceWebInspectorUIUserInterfaceViewsCSSStyleDeclarationTextEditorjs"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebInspectorUI/UserInterface/Views/CSSStyleDeclarationTextEditor.js (188324 => 188325)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebInspectorUI/UserInterface/Views/CSSStyleDeclarationTextEditor.js        2015-08-12 04:58:37 UTC (rev 188324)
+++ trunk/Source/WebInspectorUI/UserInterface/Views/CSSStyleDeclarationTextEditor.js        2015-08-12 05:40:27 UTC (rev 188325)
</span><span class="lines">@@ -441,13 +441,12 @@
</span><span class="cx"> 
</span><span class="cx">     _handleMouseDown(event)
</span><span class="cx">     {
</span><del>-        if (this._codeMirror.options.readOnly || this._codeMirror.state.focused)
</del><ins>+        if (this._codeMirror.options.readOnly)
</ins><span class="cx">             return;
</span><span class="cx"> 
</span><del>-        var cursor = this._codeMirror.coordsChar({left: event.x, top: event.y});
-        var line = this._codeMirror.getLine(cursor.line);
-        var trimmedLine = line.trimRight();
-
</del><ins>+        let cursor = this._codeMirror.coordsChar({left: event.x, top: event.y});
+        let line = this._codeMirror.getLine(cursor.line);
+        let trimmedLine = line.trimRight();
</ins><span class="cx">         if (!trimmedLine.trimLeft().length || cursor.ch !== trimmedLine.length)
</span><span class="cx">             return;
</span><span class="cx"> 
</span><span class="lines">@@ -459,16 +458,19 @@
</span><span class="cx">         if (this._codeMirror.options.readOnly || !this._mouseDownCursorPosition)
</span><span class="cx">             return;
</span><span class="cx"> 
</span><del>-        var cursor = this._codeMirror.coordsChar({left: event.x, top: event.y});
-        var line = this._codeMirror.getLine(cursor.line);
-
</del><ins>+        let cursor = this._codeMirror.coordsChar({left: event.x, top: event.y});
</ins><span class="cx">         if (this._mouseDownCursorPosition.line === cursor.line &amp;&amp; this._mouseDownCursorPosition.ch === cursor.ch) {
</span><del>-            var replacement = &quot;\n&quot;;
</del><ins>+            let nextLine = this._codeMirror.getLine(cursor.line + 1);
+            if (cursor.line &lt; this._codeMirror.lineCount() - 1 &amp;&amp; (!nextLine || !nextLine.trim().length)) {
+                this._codeMirror.setCursor({line: cursor.line + 1, ch: 0});
+            } else {
+                let line = this._codeMirror.getLine(cursor.line);
+                let replacement = &quot;\n&quot;;
+                if (!line.trimRight().endsWith(&quot;;&quot;) &amp;&amp; !this._textAtCursorIsComment(this._codeMirror, cursor))
+                    replacement = &quot;;&quot; + replacement;
</ins><span class="cx"> 
</span><del>-            if (!line.trimRight().endsWith(&quot;;&quot;) &amp;&amp; !this._textAtCursorIsComment(this._codeMirror, cursor))
-                replacement = &quot;;&quot; + replacement;
-
-            this._codeMirror.replaceRange(replacement, cursor);
</del><ins>+                this._codeMirror.replaceRange(replacement, cursor);
+            }
</ins><span class="cx">         }
</span><span class="cx"> 
</span><span class="cx">         this._mouseDownCursorPosition = null;
</span></span></pre></div>
<a id="trunkSourceWebInspectorUIUserInterfaceViewsCodeMirrorFormattersjs"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebInspectorUI/UserInterface/Views/CodeMirrorFormatters.js (188324 => 188325)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebInspectorUI/UserInterface/Views/CodeMirrorFormatters.js        2015-08-12 04:58:37 UTC (rev 188324)
+++ trunk/Source/WebInspectorUI/UserInterface/Views/CodeMirrorFormatters.js        2015-08-12 05:40:27 UTC (rev 188325)
</span><span class="lines">@@ -339,7 +339,7 @@
</span><span class="cx">                     return true;
</span><span class="cx">                 if (state.state === &quot;prop&quot;) // -webkit-transform:rotate(...)translate(...);
</span><span class="cx">                     return true;
</span><del>-                if (state.state === &quot;media&quot; || state.state === &quot;media_parens&quot;) // Space in &quot;not(foo)and&quot; but not at the end of &quot;not(not(foo))&quot;
</del><ins>+                if (state.state === &quot;media&quot; || state.state === &quot;atBlock_parens&quot;) // Space in &quot;not(foo)and&quot; but not at the end of &quot;not(not(foo))&quot;
</ins><span class="cx">                     return true;
</span><span class="cx">                 return false; // color: rgb(...);
</span><span class="cx">             }
</span><span class="lines">@@ -350,7 +350,7 @@
</span><span class="cx">             return true;
</span><span class="cx"> 
</span><span class="cx">         if (/\bkeyword\b/.test(lastToken)) // media-query keywords
</span><del>-            return state.state === &quot;media&quot; || state.state === &quot;media_parens&quot;;
</del><ins>+            return state.state === &quot;media&quot; || (state.state === &quot;atBlock_parens&quot; &amp;&amp; content !== &quot;)&quot;);
</ins><span class="cx"> 
</span><span class="cx">         return false;
</span><span class="cx">     },
</span></span></pre></div>
<a id="trunkSourceWebInspectorUIUserInterfaceViewsComputedStyleDetailsPanelcss"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebInspectorUI/UserInterface/Views/ComputedStyleDetailsPanel.css (188324 => 188325)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebInspectorUI/UserInterface/Views/ComputedStyleDetailsPanel.css        2015-08-12 04:58:37 UTC (rev 188324)
+++ trunk/Source/WebInspectorUI/UserInterface/Views/ComputedStyleDetailsPanel.css        2015-08-12 05:40:27 UTC (rev 188325)
</span><span class="lines">@@ -44,7 +44,7 @@
</span><span class="cx">     display: none;
</span><span class="cx">     position: absolute;
</span><span class="cx">     width: 12px;
</span><del>-    height: 10px;
</del><ins>+    height: 12px;
</ins><span class="cx">     vertical-align: text-bottom;
</span><span class="cx"> }
</span><span class="cx"> 
</span></span></pre></div>
<a id="trunkSourceWebInspectorUIUserInterfaceViewsHoverMenucss"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebInspectorUI/UserInterface/Views/HoverMenu.css (188324 => 188325)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebInspectorUI/UserInterface/Views/HoverMenu.css        2015-08-12 04:58:37 UTC (rev 188324)
+++ trunk/Source/WebInspectorUI/UserInterface/Views/HoverMenu.css        2015-08-12 05:40:27 UTC (rev 188325)
</span><span class="lines">@@ -59,6 +59,7 @@
</span><span class="cx">     height: 13px;
</span><span class="cx"> 
</span><span class="cx">     content: -webkit-image-set(url(../Images/HoverMenuButton.png) 1x, url(../Images/HoverMenuButton@2x.png) 2x);
</span><ins>+    transform: translateY(-1px);
</ins><span class="cx"> }
</span><span class="cx"> 
</span><span class="cx"> .hover-menu.visible &gt; img {
</span></span></pre></div>
<a id="trunkSourceWebInspectorUIUserInterfaceViewsSourceCodeTextEditorcss"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebInspectorUI/UserInterface/Views/SourceCodeTextEditor.css (188324 => 188325)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebInspectorUI/UserInterface/Views/SourceCodeTextEditor.css        2015-08-12 04:58:37 UTC (rev 188324)
+++ trunk/Source/WebInspectorUI/UserInterface/Views/SourceCodeTextEditor.css        2015-08-12 05:40:27 UTC (rev 188325)
</span><span class="lines">@@ -180,8 +180,7 @@
</span><span class="cx">     width: 16px;
</span><span class="cx">     height: 16px;
</span><span class="cx">     content: -webkit-image-set(url(../Images/ColorIcon.png) 1x, url(../Images/ColorIcon@2x.png) 2x);
</span><del>-
-    -webkit-transform: translateY(1px);
</del><ins>+    transform: translateY(0.5px);
</ins><span class="cx"> }
</span><span class="cx"> 
</span><span class="cx"> @media (-webkit-min-device-pixel-ratio: 2) {
</span></span></pre>
</div>
</div>

</body>
</html>