Changeset 111861 in spip-zone


Ignore:
Timestamp:
Oct 5, 2018, 9:39:38 AM (10 months ago)
Author:
arnaud.berard@…
Message:

Maj des composants de la lib CodeMirror? en version 5 https://codemirror.net/

Location:
_plugins_/skeleditor/trunk/codemirror
Files:
45 edited

Legend:

Unmodified
Added
Removed
  • _plugins_/skeleditor/trunk/codemirror/demo/activeline.html

    r48687 r111861  
    11<!doctype html>
    2 <html>
    3   <head>
    4     <title>CodeMirror 2: Active Line Demo</title>
    5     <link rel="stylesheet" href="../lib/codemirror.css">
    6     <script src="../lib/codemirror.js"></script>
    7     <link rel="stylesheet" href="../theme/default.css">
    8     <script src="../mode/xml/xml.js"></script>
    9     <link rel="stylesheet" href="../css/docs.css">
    102
    11     <style type="text/css">
     3<title>CodeMirror: Active Line Demo</title>
     4<meta charset="utf-8"/>
     5<link rel=stylesheet href="../doc/docs.css">
     6
     7<link rel="stylesheet" href="../lib/codemirror.css">
     8<script src="../lib/codemirror.js"></script>
     9<script src="../mode/xml/xml.js"></script>
     10<script src="../addon/selection/active-line.js"></script>
     11<style type="text/css">
    1212      .CodeMirror {border-top: 1px solid black; border-bottom: 1px solid black;}
    13       .activeline {background: #f0fcff !important;}
    1413    </style>
    15   </head>
    16   <body>
    17     <h1>CodeMirror 2: Active Line Demo</h1>
     14<div id=nav>
     15  <a href="https://codemirror.net"><h1>CodeMirror</h1><img id=logo src="../doc/logo.png"></a>
    1816
    19     <form><textarea id="code" name="code">
     17  <ul>
     18    <li><a href="../index.html">Home</a>
     19    <li><a href="../doc/manual.html">Manual</a>
     20    <li><a href="https://github.com/codemirror/codemirror">Code</a>
     21  </ul>
     22  <ul>
     23    <li><a class=active href="#">Active Line</a>
     24  </ul>
     25</div>
     26
     27<article>
     28<h2>Active Line Demo</h2>
     29<form><textarea id="code" name="code">
    2030<?xml version="1.0" encoding="UTF-8"?>
    2131<rss xmlns:atom="http://www.w3.org/2005/Atom" version="2.0"
     
    4353  <item>
    4454    <title>codemirror: Posted a description of the CodeMirror 2 internals at
    45       http://codemirror.net/2/internals.html</title>
     55      https://codemirror.net/2/internals.html</title>
    4656    <description>codemirror: Posted a description of the CodeMirror 2 internals at
    47       http://codemirror.net/2/internals.html</description>
     57      https://codemirror.net/2/internals.html</description>
    4858    <pubDate>Wed, 02 Mar 2011 12:15:09 +0000</pubDate>
    4959    <guid>http://twitter.com/codemirror/statuses/42920879788789760</guid>
     
    5262    <twitter:place/>
    5363  </item>
    54 </feed></textarea></form>
     64  </channel>
     65</rss></textarea></form>
    5566
    5667    <script>
     68var nonEmpty = false;
    5769var editor = CodeMirror.fromTextArea(document.getElementById("code"), {
    5870  mode: "application/xml",
     71  styleActiveLine: true,
    5972  lineNumbers: true,
    60   onCursorActivity: function() {
    61     editor.setLineClass(hlLine, null);
    62     hlLine = editor.setLineClass(editor.getCursor().line, "activeline");
    63   }
     73  lineWrapping: true
    6474});
    65 var hlLine = editor.setLineClass(0, "activeline");
     75
     76function toggleSelProp() {
     77  nonEmpty = !nonEmpty;
     78  editor.setOption("styleActiveLine", {nonEmpty: nonEmpty});
     79  var label = nonEmpty ? 'Disable nonEmpty option' : 'Enable nonEmpty option';
     80  document.getElementById('toggleButton').innerText = label;
     81}
    6682</script>
    6783
    6884    <p>Styling the current cursor line.</p>
    6985
    70   </body>
    71 </html>
     86    <button onclick="toggleSelProp()" id="toggleButton">Enable <code>nonEmpty</code> option</button>
     87
     88  </article>
  • _plugins_/skeleditor/trunk/codemirror/demo/changemode.html

    r49339 r111861  
    11<!doctype html>
    2 <html>
    3   <head>
    4     <title>CodeMirror 2: Mode-Changing Demo</title>
    5     <link rel="stylesheet" href="../lib/codemirror.css">
    6     <script src="../lib/codemirror.js"></script>
    7     <link rel="stylesheet" href="../theme/default.css">
    8     <script src="../mode/javascript/javascript.js"></script>
    9     <script src="../mode/scheme/scheme.js"></script>
    10     <link rel="stylesheet" href="../css/docs.css">
    112
    12     <style type="text/css">
     3<title>CodeMirror: Mode-Changing Demo</title>
     4<meta charset="utf-8"/>
     5<link rel=stylesheet href="../doc/docs.css">
     6
     7<link rel="stylesheet" href="../lib/codemirror.css">
     8<script src="../lib/codemirror.js"></script>
     9<script src="../mode/javascript/javascript.js"></script>
     10<script src="../mode/scheme/scheme.js"></script>
     11<style type="text/css">
    1312      .CodeMirror {border: 1px solid black;}
    1413    </style>
    15   </head>
    16   <body>
    17     <h1>CodeMirror 2: Mode-Changing demo</h1>
     14<div id=nav>
     15  <a href="https://codemirror.net"><h1>CodeMirror</h1><img id=logo src="../doc/logo.png"></a>
    1816
    19     <form><textarea id="code" name="code">
     17  <ul>
     18    <li><a href="../index.html">Home</a>
     19    <li><a href="../doc/manual.html">Manual</a>
     20    <li><a href="https://github.com/codemirror/codemirror">Code</a>
     21  </ul>
     22  <ul>
     23    <li><a class=active href="#">Mode-Changing</a>
     24  </ul>
     25</div>
     26
     27<article>
     28<h2>Mode-Changing Demo</h2>
     29<form><textarea id="code" name="code">
    2030;; If there is Scheme code in here, the editor will be in Scheme mode.
    2131;; If you put in JS instead, it'll switch to JS mode.
     
    3242  var editor = CodeMirror.fromTextArea(document.getElementById("code"), {
    3343    mode: "scheme",
    34     lineNumbers: true,
    35     matchBrackets: true,
    36     tabMode: "indent",
    37     onChange: function() {
    38       clearTimeout(pending);
    39       setTimeout(update, 400);
    40     }
     44    lineNumbers: true
    4145  });
    4246  var pending;
     47  editor.on("change", function() {
     48    clearTimeout(pending);
     49    pending = setTimeout(update, 400);
     50  });
     51  function looksLikeScheme(code) {
     52    return !/^\s*\(\s*function\b/.test(code) && /^\s*[;\(]/.test(code);
     53  }
    4354  function update() {
    44     editor.setOption("mode", /^\s*[;\(]/.test(editor.getValue()) ? "scheme" : "javascript");
     55    editor.setOption("mode", looksLikeScheme(editor.getValue()) ? "scheme" : "javascript");
    4556  }
    4657</script>
    47   </body>
    48 </html>
     58  </article>
  • _plugins_/skeleditor/trunk/codemirror/demo/complete.html

    r48687 r111861  
    11<!doctype html>
    2 <html>
    3   <head>
    4     <title>CodeMirror 2: Autocomplete Demo</title>
    5     <link rel="stylesheet" href="../lib/codemirror.css">
    6     <script src="../lib/codemirror.js"></script>
    7     <link rel="stylesheet" href="../theme/night.css">
    8     <script src="../mode/javascript/javascript.js"></script>
    9     <link rel="stylesheet" href="../css/docs.css">
    102
    11     <style type="text/css">
    12       .completions {
    13         position: absolute;
    14         z-index: 10;
    15         overflow: hidden;
    16         -webkit-box-shadow: 2px 3px 5px rgba(0,0,0,.2);
    17         -moz-box-shadow: 2px 3px 5px rgba(0,0,0,.2);
    18         box-shadow: 2px 3px 5px rgba(0,0,0,.2);
    19       }
    20       .completions select {
    21         background: #fafafa;
    22         outline: none;
    23         border: none;
    24         padding: 0;
    25         margin: 0;
    26         font-family: monospace;
    27       }
    28       .CodeMirror {
    29         border: 1px solid #eee;
    30       }
    31     </style>
    32   </head>
    33   <body>
    34     <h1>CodeMirror 2: Autocomplete demo</h1>
     3<title>CodeMirror: Autocomplete Demo</title>
     4<meta charset="utf-8"/>
     5<link rel=stylesheet href="../doc/docs.css">
    356
    36     <form><textarea id="code" name="code">
     7<link rel="stylesheet" href="../lib/codemirror.css">
     8<link rel="stylesheet" href="../addon/hint/show-hint.css">
     9<script src="../lib/codemirror.js"></script>
     10<script src="../addon/hint/show-hint.js"></script>
     11<script src="../addon/hint/javascript-hint.js"></script>
     12<script src="../mode/javascript/javascript.js"></script>
     13<script src="../mode/markdown/markdown.js"></script>
     14
     15<div id=nav>
     16  <a href="https://codemirror.net"><h1>CodeMirror</h1><img id=logo src="../doc/logo.png"></a>
     17
     18  <ul>
     19    <li><a href="../index.html">Home</a>
     20    <li><a href="../doc/manual.html">Manual</a>
     21    <li><a href="https://github.com/codemirror/codemirror">Code</a>
     22  </ul>
     23  <ul>
     24    <li><a class=active href="#">Autocomplete</a>
     25  </ul>
     26</div>
     27
     28<article>
     29<h2>Autocomplete Demo</h2>
     30<form><textarea id="code" name="code">
    3731function getCompletions(token, context) {
    3832  var found = [], start = token.string;
     
    7266</textarea></form>
    7367
    74 <p>Press <strong>ctrl-space</strong> to activate autocompletion. See
    75 the <a href="complete.js">code</a> to figure out how it works.</p>
     68<p>Press <strong>ctrl-space</strong> to activate autocompletion. Built
     69on top of the <a href="../doc/manual.html#addon_show-hint"><code>show-hint</code></a>
     70and <a href="../doc/manual.html#addon_javascript-hint"><code>javascript-hint</code></a>
     71addons.</p>
    7672
    77     <script src="complete.js"></script>
    78   </body>
    79 </html>
     73<form><textarea style="display: none" id="synonyms" name="synonyms">
     74Here, the completion use an asynchronous hinting functions to provide
     75synonyms for each words. If your browser support `Promises`, the
     76hinting function can also return one.
     77</textarea></form>
     78
     79<script>
     80var editor = CodeMirror.fromTextArea(document.getElementById("code"), {
     81  lineNumbers: true,
     82  extraKeys: {"Ctrl-Space": "autocomplete"},
     83  mode: {name: "javascript", globalVars: true}
     84});
     85
     86if (typeof Promise !== "undefined") {
     87  var comp = [
     88    ["here", "hither"],
     89    ["asynchronous", "nonsynchronous"],
     90    ["completion", "achievement", "conclusion", "culmination", "expirations"],
     91    ["hinting", "advive", "broach", "imply"],
     92    ["function","action"],
     93    ["provide", "add", "bring", "give"],
     94    ["synonyms", "equivalents"],
     95    ["words", "token"],
     96    ["each", "every"],
     97  ]
     98
     99  function synonyms(cm, option) {
     100    return new Promise(function(accept) {
     101      setTimeout(function() {
     102        var cursor = cm.getCursor(), line = cm.getLine(cursor.line)
     103        var start = cursor.ch, end = cursor.ch
     104        while (start && /\w/.test(line.charAt(start - 1))) --start
     105        while (end < line.length && /\w/.test(line.charAt(end))) ++end
     106        var word = line.slice(start, end).toLowerCase()
     107        for (var i = 0; i < comp.length; i++) if (comp[i].indexOf(word) != -1)
     108          return accept({list: comp[i],
     109                         from: CodeMirror.Pos(cursor.line, start),
     110                         to: CodeMirror.Pos(cursor.line, end)})
     111        return accept(null)
     112      }, 100)
     113    })
     114  }
     115
     116  var editor2 = CodeMirror.fromTextArea(document.getElementById("synonyms"), {
     117    extraKeys: {"Ctrl-Space": "autocomplete"},
     118    lineNumbers: true,
     119    lineWrapping: true,
     120    mode: "text/x-markdown",
     121    hintOptions: {hint: synonyms}
     122  })
     123}
     124</script>
     125
     126</article>
  • _plugins_/skeleditor/trunk/codemirror/demo/fullscreen.html

    r49339 r111861  
    11<!doctype html>
    2 <html>
    3   <head>
    4     <title>CodeMirror 2: Full Screen Editing</title>
    5     <link rel="stylesheet" href="../lib/codemirror.css">
    6     <script src="../lib/codemirror.js"></script>
    7     <link rel="stylesheet" href="../theme/default.css">
    8     <link rel="stylesheet" href="../theme/night.css">
    9     <script src="../mode/xml/xml.js"></script>
    10     <link rel="stylesheet" href="../css/docs.css">
    11     <script src="http://ajax.googleapis.com/ajax/libs/jquery/1.6.1/jquery.min.js"></script>
    122
    13     <style type="text/css">
    14         .CodeMirror {border-top: 1px solid black; border-bottom: 1px solid black;}
    15         .fullscreen {
    16             display: block;
    17             position: absolute;
    18             top: 0;
    19             left: 0;
    20             width: 100%;
    21             height: 100%;
    22             z-index: 9999;
    23             margin: 0;
    24             padding: 0;
    25             border: 0px solid #BBBBBB;
    26             opacity: 1;
     3<title>CodeMirror: Full Screen Editing</title>
     4<meta charset="utf-8"/>
     5<link rel=stylesheet href="../doc/docs.css">
     6
     7<link rel="stylesheet" href="../lib/codemirror.css">
     8<link rel="stylesheet" href="../addon/display/fullscreen.css">
     9<link rel="stylesheet" href="../theme/night.css">
     10<script src="../lib/codemirror.js"></script>
     11<script src="../mode/xml/xml.js"></script>
     12<script src="../addon/display/fullscreen.js"></script>
     13
     14<div id=nav>
     15  <a href="https://codemirror.net"><h1>CodeMirror</h1><img id=logo src="../doc/logo.png"></a>
     16
     17  <ul>
     18    <li><a href="../index.html">Home</a>
     19    <li><a href="../doc/manual.html">Manual</a>
     20    <li><a href="https://github.com/codemirror/codemirror">Code</a>
     21  </ul>
     22  <ul>
     23    <li><a class=active href="#">Full Screen Editing</a>
     24  </ul>
     25</div>
     26
     27<article>
     28<h2>Full Screen Editing</h2>
     29<form><textarea id="code" name="code" rows="5">
     30<dl>
     31  <dt id="option_indentWithTabs"><code><strong>indentWithTabs</strong>: boolean</code></dt>
     32  <dd>Whether, when indenting, the first N*<code>tabSize</code>
     33  spaces should be replaced by N tabs. Default is false.</dd>
     34
     35  <dt id="option_electricChars"><code><strong>electricChars</strong>: boolean</code></dt>
     36  <dd>Configures whether the editor should re-indent the current
     37  line when a character is typed that might change its proper
     38  indentation (only works if the mode supports indentation).
     39  Default is true.</dd>
     40
     41  <dt id="option_specialChars"><code><strong>specialChars</strong>: RegExp</code></dt>
     42  <dd>A regular expression used to determine which characters
     43  should be replaced by a
     44  special <a href="#option_specialCharPlaceholder">placeholder</a>.
     45  Mostly useful for non-printing special characters. The default
     46  is <code>/[\u0000-\u0019\u00ad\u200b\u2028\u2029\ufeff]/</code>.</dd>
     47  <dt id="option_specialCharPlaceholder"><code><strong>specialCharPlaceholder</strong>: function(char) → Element</code></dt>
     48  <dd>A function that, given a special character identified by
     49  the <a href="#option_specialChars"><code>specialChars</code></a>
     50  option, produces a DOM node that is used to represent the
     51  character. By default, a red dot (<span style="color: red">•</span>)
     52  is shown, with a title tooltip to indicate the character code.</dd>
     53
     54  <dt id="option_rtlMoveVisually"><code><strong>rtlMoveVisually</strong>: boolean</code></dt>
     55  <dd>Determines whether horizontal cursor movement through
     56  right-to-left (Arabic, Hebrew) text is visual (pressing the left
     57  arrow moves the cursor left) or logical (pressing the left arrow
     58  moves to the next lower index in the string, which is visually
     59  right in right-to-left text). The default is <code>false</code>
     60  on Windows, and <code>true</code> on other platforms.</dd>
     61</dl>
     62</textarea></form>
     63  <script>
     64    var editor = CodeMirror.fromTextArea(document.getElementById("code"), {
     65      lineNumbers: true,
     66      theme: "night",
     67      extraKeys: {
     68        "F11": function(cm) {
     69          cm.setOption("fullScreen", !cm.getOption("fullScreen"));
     70        },
     71        "Esc": function(cm) {
     72          if (cm.getOption("fullScreen")) cm.setOption("fullScreen", false);
    2773        }
    28     </style>
    29   </head>
    30   <body>
    31     <h1>CodeMirror 2: Full Screen Editing</h1>
     74      }
     75    });
     76  </script>
    3277
    33     <form><textarea id="code" name="code" rows="5">
    34   <dt id="option_indentWithTabs"><code>indentWithTabs (boolean)</code></dt>
    35   <dd>Whether, when indenting, the first N*8 spaces should be
    36   replaced by N tabs. Default is false.</dd>
    37 
    38   <dt id="option_tabMode"><code>tabMode (string)</code></dt>
    39   <dd>Determines what happens when the user presses the tab key.
    40   Must be one of the following:
    41     <dl>
    42       <dt><code>"classic" (the default)</code></dt>
    43       <dd>When nothing is selected, insert a tab. Otherwise,
    44       behave like the <code>"shift"</code> mode. (When shift is
    45       held, this behaves like the <code>"indent"</code> mode.)</dd>
    46       <dt><code>"shift"</code></dt>
    47       <dd>Indent all selected lines by
    48       one <a href="#option_indentUnit"><code>indentUnit</code></a>.
    49       If shift was held while pressing tab, un-indent all selected
    50       lines one unit.</dd>
    51       <dt><code>"indent"</code></dt>
    52       <dd>Indent the line the 'correctly', based on its syntactic
    53       context. Only works if the
    54       mode <a href="#indent">supports</a> it.</dd>
    55       <dt><code>"default"</code></dt>
    56       <dd>Do not capture tab presses, let the browser apply its
    57       default behaviour (which usually means it skips to the next
    58       control).</dd>
    59     </dl></dd>
    60 
    61   <dt id="option_enterMode"><code>enterMode (string)</code></dt>
    62   <dd>Determines whether and how new lines are indented when the
    63   enter key is pressed. The following modes are supported:
    64     <dl>
    65       <dt><code>"indent" (the default)</code></dt>
    66       <dd>Use the mode's indentation rules to give the new line
    67       the correct indentation.</dd>
    68       <dt><code>"keep"</code></dt>
    69       <dd>Indent the line the same as the previous line.</dd>
    70       <dt><code>"flat"</code></dt>
    71       <dd>Do not indent the new line.</dd>
    72     </dl></dd>
    73 
    74   <dt id="option_enterMode"><code>enterMode (string)</code></dt>
    75   <dd>Determines whether and how new lines are indented when the
    76   enter key is pressed. The following modes are supported:
    77     <dl>
    78       <dt><code>"indent" (the default)</code></dt>
    79       <dd>Use the mode's indentation rules to give the new line
    80       the correct indentation.</dd>
    81       <dt><code>"keep"</code></dt>
    82       <dd>Indent the line the same as the previous line.</dd>
    83       <dt><code>"flat"</code></dt>
    84       <dd>Do not indent the new line.</dd>
    85     </dl></dd>
    86 
    87   <dt id="option_enterMode"><code>enterMode (string)</code></dt>
    88   <dd>Determines whether and how new lines are indented when the
    89   enter key is pressed. The following modes are supported:
    90     <dl>
    91       <dt><code>"indent" (the default)</code></dt>
    92       <dd>Use the mode's indentation rules to give the new line
    93       the correct indentation.</dd>
    94       <dt><code>"keep"</code></dt>
    95       <dd>Indent the line the same as the previous line.</dd>
    96       <dt><code>"flat"</code></dt>
    97       <dd>Do not indent the new line.</dd>
    98     </dl></dd>
    99 
    100   <dt id="option_enterMode"><code>enterMode (string)</code></dt>
    101   <dd>Determines whether and how new lines are indented when the
    102   enter key is pressed. The following modes are supported:
    103     <dl>
    104       <dt><code>"indent" (the default)</code></dt>
    105       <dd>Use the mode's indentation rules to give the new line
    106       the correct indentation.</dd>
    107       <dt><code>"keep"</code></dt>
    108       <dd>Indent the line the same as the previous line.</dd>
    109       <dt><code>"flat"</code></dt>
    110       <dd>Do not indent the new line.</dd>
    111     </dl></dd>
    112 
    113 </textarea></form>
    114  <script>
    115 
    116 (function () {
    117 
    118     var editor = CodeMirror.fromTextArea(document.getElementById("code"), {
    119         lineNumbers: true,
    120         theme: "night",
    121         onKeyEvent: function(i, e) {
    122           // Hook into F11
    123           if ((e.keyCode == 122 || e.keyCode == 27) && e.type == 'keydown') {
    124             e.stop();
    125             return toggleFullscreenEditing();
    126           }
    127         }
    128     });
    129 
    130     function toggleFullscreenEditing()
    131     {
    132         var editorDiv = $('.CodeMirror-scroll');
    133         if (!editorDiv.hasClass('fullscreen')) {
    134             toggleFullscreenEditing.beforeFullscreen = { height: editorDiv.height(), width: editorDiv.width() }
    135             editorDiv.addClass('fullscreen');
    136             editorDiv.height('100%');
    137             editorDiv.width('100%');
    138             editor.refresh();
    139         }
    140         else {
    141             editorDiv.removeClass('fullscreen');
    142             editorDiv.height(toggleFullscreenEditing.beforeFullscreen.height);
    143             editorDiv.width(toggleFullscreenEditing.beforeFullscreen.width);
    144             editor.refresh();
    145         }
    146     }
    147 
    148 })();
    149 </script>
    150 
    151     <p>Press <strong>F11</strong> (or <strong>ESC</strong> in Safari on Mac OS X) when cursor is in the editor to toggle full screen editing.</p>
    152 
    153     <p><strong>Note:</strong> Does not currently work correctly in IE
    154     6 and 7, where setting the height of something
    155     to <code>100%</code> doesn't make it full-screen.</p>
    156 
    157   </body>
    158 </html>
     78    <p>Demonstration of
     79    the <a href="../doc/manual.html#addon_fullscreen">fullscreen</a>
     80    addon. Press <strong>F11</strong> when cursor is in the editor to
     81    toggle full screen editing. <strong>Esc</strong> can also be used
     82    to <i>exit</i> full screen editing.</p>
     83  </article>
  • _plugins_/skeleditor/trunk/codemirror/demo/marker.html

    r48687 r111861  
    11<!doctype html>
    2 <html>
    3   <head>
    4     <title>CodeMirror 2: Breakpoint Demo</title>
    5     <link rel="stylesheet" href="../lib/codemirror.css">
    6     <script src="../lib/codemirror.js"></script>
    7     <link rel="stylesheet" href="../theme/default.css">
    8     <script src="../mode/javascript/javascript.js"></script>
    9     <link rel="stylesheet" href="../css/docs.css">
    102
    11     <style type="text/css">
    12       .CodeMirror-gutter {
    13         width: 3em;
    14         background: white;
    15       }
    16       .CodeMirror {
    17         border: 1px solid #aaa;
    18       }
     3<title>CodeMirror: Breakpoint Demo</title>
     4<meta charset="utf-8"/>
     5<link rel=stylesheet href="../doc/docs.css">
     6
     7<link rel="stylesheet" href="../lib/codemirror.css">
     8<script src="../lib/codemirror.js"></script>
     9<script src="../mode/javascript/javascript.js"></script>
     10<style type="text/css">
     11      .breakpoints {width: .8em;}
     12      .breakpoint { color: #822; }
     13      .CodeMirror {border: 1px solid #aaa;}
    1914    </style>
    20   </head>
    21   <body>
    22     <h1>CodeMirror 2: Breakpoint demo</h1>
     15<div id=nav>
     16  <a href="https://codemirror.net"><h1>CodeMirror</h1><img id=logo src="../doc/logo.png"></a>
    2317
    24     <form><textarea id="code" name="code">
    25 CodeMirror.fromTextArea(document.getElementById("code"), {
     18  <ul>
     19    <li><a href="../index.html">Home</a>
     20    <li><a href="../doc/manual.html">Manual</a>
     21    <li><a href="https://github.com/codemirror/codemirror">Code</a>
     22  </ul>
     23  <ul>
     24    <li><a class=active href="#">Breakpoint</a>
     25  </ul>
     26</div>
     27
     28<article>
     29<h2>Breakpoint Demo</h2>
     30<form><textarea id="code" name="code">
     31var editor = CodeMirror.fromTextArea(document.getElementById("code"), {
    2632  lineNumbers: true,
    27   onGutterClick: function(cm, n) {
    28     var info = cm.lineInfo(n);
    29     if (info.markerText)
    30       cm.clearMarker(n);
    31     else
    32       cm.setMarker(n, "<span style=\"color: #900\">●</span> %N%");
    33   }
     33  gutters: ["CodeMirror-linenumbers", "breakpoints"]
    3434});
     35editor.on("gutterClick", function(cm, n) {
     36  var info = cm.lineInfo(n);
     37  cm.setGutterMarker(n, "breakpoints", info.gutterMarkers ? null : makeMarker());
     38});
     39
     40function makeMarker() {
     41  var marker = document.createElement("div");
     42  marker.style.color = "#822";
     43  marker.innerHTML = "●";
     44  return marker;
     45}
    3546</textarea></form>
    3647
    3748<p>Click the line-number gutter to add or remove 'breakpoints'.</p>
    3849
    39     <script>
    40       CodeMirror.fromTextArea(document.getElementById("code"), {
    41         lineNumbers: true,
    42         onGutterClick: function(cm, n) {
    43           var info = cm.lineInfo(n);
    44           if (info.markerText)
    45             cm.clearMarker(n);
    46           else
    47             cm.setMarker(n, "<span style=\"color: #900\">●</span> %N%");
    48         }
    49       });
    50     </script>
     50    <script>eval(document.getElementById("code").value);</script>
    5151
    52   </body>
    53 </html>
     52  </article>
  • _plugins_/skeleditor/trunk/codemirror/demo/mustache.html

    r48687 r111861  
    11<!doctype html>
    2 <html>
    3   <head>
    4     <title>CodeMirror 2: Overlay Parser Demo</title>
    5     <link rel="stylesheet" href="../lib/codemirror.css">
    6     <script src="../lib/codemirror.js"></script>
    7     <script src="../lib/overlay.js"></script>
    8     <link rel="stylesheet" href="../theme/default.css">
    9     <script src="../mode/xml/xml.js"></script>
    10     <link rel="stylesheet" href="../css/docs.css">
    112
    12     <style type="text/css">
     3<title>CodeMirror: Overlay Parser Demo</title>
     4<meta charset="utf-8"/>
     5<link rel=stylesheet href="../doc/docs.css">
     6
     7<link rel="stylesheet" href="../lib/codemirror.css">
     8<script src="../lib/codemirror.js"></script>
     9<script src="../addon/mode/overlay.js"></script>
     10<script src="../mode/xml/xml.js"></script>
     11<style type="text/css">
    1312      .CodeMirror {border: 1px solid black;}
    14       .mustache {color: #0ca;}
    15     </style>
    16   </head>
    17   <body>
    18     <h1>CodeMirror 2: Overlay Parser Demo</h1>
     13      .cm-mustache {color: #0ca;}
     14</style>
     15<div id=nav>
     16  <a href="https://codemirror.net"><h1>CodeMirror</h1><img id=logo src="../doc/logo.png"></a>
    1917
    20     <form><textarea id="code" name="code">
     18  <ul>
     19    <li><a href="../index.html">Home</a>
     20    <li><a href="../doc/manual.html">Manual</a>
     21    <li><a href="https://github.com/codemirror/codemirror">Code</a>
     22  </ul>
     23  <ul>
     24    <li><a class=active href="#">Overlay Parser</a>
     25  </ul>
     26</div>
     27
     28<article>
     29<h2>Overlay Parser Demo</h2>
     30<form><textarea id="code" name="code">
    2131<html>
    2232  <body>
     
    3444  var mustacheOverlay = {
    3545    token: function(stream, state) {
     46      var ch;
    3647      if (stream.match("{{")) {
    3748        while ((ch = stream.next()) != null)
    38           if (ch == "}" && stream.next() == "}") break;
    39         return "mustache";
     49          if (ch == "}" && stream.next() == "}") {
     50            stream.eat("}");
     51            return "mustache";
     52          }
    4053      }
    4154      while (stream.next() != null && !stream.match("{{", false)) {}
     
    4356    }
    4457  };
    45   return CodeMirror.overlayParser(CodeMirror.getMode(config, parserConfig.backdrop || "text/html"), mustacheOverlay);
     58  return CodeMirror.overlayMode(CodeMirror.getMode(config, parserConfig.backdrop || "text/html"), mustacheOverlay);
    4659});
    4760var editor = CodeMirror.fromTextArea(document.getElementById("code"), {mode: "mustache"});
     
    5164    the <a href="http://mustache.github.com/">Mustache</a> templating
    5265    directives inside of it by using the code
    53     in <a href="../lib/overlay.js"><code>overlay.js</code></a>. View
     66    in <a href="../addon/mode/overlay.js"><code>overlay.js</code></a>. View
    5467    source to see the 15 lines of code needed to accomplish this.</p>
    5568
    56   </body>
    57 </html>
     69  </article>
  • _plugins_/skeleditor/trunk/codemirror/demo/resize.html

    r48687 r111861  
    11<!doctype html>
    2 <html>
    3   <head>
    4     <title>CodeMirror 2: Autoresize Demo</title>
    5     <link rel="stylesheet" href="../lib/codemirror.css">
    6     <script src="../lib/codemirror.js"></script>
    7     <link rel="stylesheet" href="../theme/default.css">
    8     <script src="../mode/css/css.js"></script>
    9     <link rel="stylesheet" href="../css/docs.css">
    102
    11     <style type="text/css">
     3<title>CodeMirror: Autoresize Demo</title>
     4<meta charset="utf-8"/>
     5<link rel=stylesheet href="../doc/docs.css">
     6
     7<link rel="stylesheet" href="../lib/codemirror.css">
     8<script src="../lib/codemirror.js"></script>
     9<script src="../mode/css/css.js"></script>
     10<style type="text/css">
    1211      .CodeMirror {
    1312        border: 1px solid #eee;
    14       }
    15       .CodeMirror-scroll {
    1613        height: auto;
    17         overflow-y: hidden;
    18         overflow-x: auto;
    1914      }
    2015    </style>
    21   </head>
    22   <body>
    23     <h1>CodeMirror 2: Autoresize demo</h1>
     16<div id=nav>
     17  <a href="https://codemirror.net"><h1>CodeMirror</h1><img id=logo src="../doc/logo.png"></a>
    2418
    25     <form><textarea id="code" name="code">
    26 .CodeMirror-scroll {
     19  <ul>
     20    <li><a href="../index.html">Home</a>
     21    <li><a href="../doc/manual.html">Manual</a>
     22    <li><a href="https://github.com/codemirror/codemirror">Code</a>
     23  </ul>
     24  <ul>
     25    <li><a class=active href="#">Autoresize</a>
     26  </ul>
     27</div>
     28
     29<article>
     30<h2>Autoresize Demo</h2>
     31<form><textarea id="code" name="code">
     32.CodeMirror {
     33  border: 1px solid #eee;
    2734  height: auto;
    28   overflow-y: hidden;
    29   overflow-x: auto;
    30 }</textarea></form>
     35}
     36</textarea></form>
    3137
    32 <p>By setting a single CSS property, CodeMirror can be made to
    33 automatically resize to fit the content. Use <code>max-height</code>
    34 to prevent it from growing past a given point (on halfway modern
    35 browsers).</p>
     38<p>By setting an editor's <code>height</code> style
     39to <code>auto</code> and giving
     40the <a href="../doc/manual.html#option_viewportMargin"><code>viewportMargin</code></a>
     41a value of <code>Infinity</code>, CodeMirror can be made to
     42automatically resize to fit its content.</p>
    3643
    3744    <script>
    38       CodeMirror.fromTextArea(document.getElementById("code"), {
    39         lineNumbers: true
     45      var editor = CodeMirror.fromTextArea(document.getElementById("code"), {
     46        lineNumbers: true,
     47        viewportMargin: Infinity
    4048      });
    4149    </script>
    4250
    43   </body>
    44 </html>
     51  </article>
  • _plugins_/skeleditor/trunk/codemirror/demo/runmode.html

    r48687 r111861  
    11<!doctype html>
    2 <html>
    3   <head>
    4     <title>CodeMirror 2: Mode Runner Demo</title>
    5     <link rel="stylesheet" href="../lib/codemirror.css">
    6     <script src="../lib/codemirror.js"></script>
    7     <script src="../lib/runmode.js"></script>
    8     <link rel="stylesheet" href="../theme/default.css">
    9     <script src="../mode/xml/xml.js"></script>
    10     <link rel="stylesheet" href="../css/docs.css">
    11   </head>
    12   <body>
    13     <h1>CodeMirror 2: Mode Runner Demo</h1>
     2
     3<title>CodeMirror: Mode Runner Demo</title>
     4<meta charset="utf-8"/>
     5<link rel=stylesheet href="../doc/docs.css">
     6
     7<link rel="stylesheet" href="../lib/codemirror.css">
     8<script src="../lib/codemirror.js"></script>
     9<script src="../addon/runmode/runmode.js"></script>
     10<script src="../mode/xml/xml.js"></script>
     11<div id=nav>
     12  <a href="https://codemirror.net"><h1>CodeMirror</h1><img id=logo src="../doc/logo.png"></a>
     13
     14  <ul>
     15    <li><a href="../index.html">Home</a>
     16    <li><a href="../doc/manual.html">Manual</a>
     17    <li><a href="https://github.com/codemirror/codemirror">Code</a>
     18  </ul>
     19  <ul>
     20    <li><a class=active href="#">Mode Runner</a>
     21  </ul>
     22</div>
     23
     24<article>
     25<h2>Mode Runner Demo</h2>
     26
    1427
    1528    <textarea id="code" style="width: 90%; height: 7em; border: 1px solid black; padding: .2em .4em;">
    1629<foobar>
    1730  <blah>Enter your xml here and press the button below to display
    18     it as highlighted by the CodeMirror XLM mode</blah>
     31    it as highlighted by the CodeMirror XML mode</blah>
    1932  <tag2 foo="2" bar="&amp;quot;bar&amp;quot;"/>
    2033</foobar></textarea><br>
     
    3144    <p>Running a CodeMirror mode outside of the editor.
    3245    The <code>CodeMirror.runMode</code> function, defined
    33     in <code><a href="../lib/runmode.js">lib/runmode.js</a></code> takes the following arguments:</p>
     46    in <code><a href="../addon/runmode/runmode.js">addon/runmode/runmode.js</a></code> takes the following arguments:</p>
    3447
    3548    <dl>
    3649      <dt><code>text (string)</code></dt>
    3750      <dd>The document to run through the highlighter.</dd>
    38       <dt><code>mode (<a href="../manual.html#option_mode">mode spec</a>)</code></dt>
     51      <dt><code>mode (<a href="../doc/manual.html#option_mode">mode spec</a>)</code></dt>
    3952      <dd>The mode to use (must be loaded as normal).</dd>
    4053      <dt><code>output (function or DOM node)</code></dt>
     
    4760    </dl>
    4861
    49   </body>
    50 </html>
     62  </article>
  • _plugins_/skeleditor/trunk/codemirror/demo/search.html

    r49339 r111861  
    11<!doctype html>
    2 <html>
    3   <head>
    4     <title>CodeMirror 2: Search/Replace Demo</title>
    5     <link rel="stylesheet" href="../lib/codemirror.css">
    6     <script src="../lib/codemirror.js"></script>
    7     <link rel="stylesheet" href="../theme/default.css">
    8     <script src="../mode/xml/xml.js"></script>
    9     <link rel="stylesheet" href="../css/docs.css">
    102
    11     <style type="text/css">
     3<title>CodeMirror: Search/Replace Demo</title>
     4<meta charset="utf-8"/>
     5<link rel=stylesheet href="../doc/docs.css">
     6
     7<link rel="stylesheet" href="../lib/codemirror.css">
     8<link rel="stylesheet" href="../addon/dialog/dialog.css">
     9<link rel="stylesheet" href="../addon/search/matchesonscrollbar.css">
     10<script src="../lib/codemirror.js"></script>
     11<script src="../mode/xml/xml.js"></script>
     12<script src="../addon/dialog/dialog.js"></script>
     13<script src="../addon/search/searchcursor.js"></script>
     14<script src="../addon/search/search.js"></script>
     15<script src="../addon/scroll/annotatescrollbar.js"></script>
     16<script src="../addon/search/matchesonscrollbar.js"></script>
     17<script src="../addon/search/jump-to-line.js"></script>
     18<style type="text/css">
    1219      .CodeMirror {border-top: 1px solid black; border-bottom: 1px solid black;}
    13       .searched {background: yellow;}
     20      dt {font-family: monospace; color: #666;}
    1421    </style>
    15   </head>
    16   <body>
    17     <h1>CodeMirror 2: Search/Replace Demo</h1>
     22<div id=nav>
     23  <a href="https://codemirror.net"><h1>CodeMirror</h1><img id=logo src="../doc/logo.png"></a>
    1824
    19     <form><textarea id="code" name="code">
    20   <dt id="option_indentWithTabs"><code>indentWithTabs (boolean)</code></dt>
    21   <dd>Whether, when indenting, the first N*8 spaces should be
    22   replaced by N tabs. Default is false.</dd>
     25  <ul>
     26    <li><a href="../index.html">Home</a>
     27    <li><a href="../doc/manual.html">Manual</a>
     28    <li><a href="https://github.com/codemirror/codemirror">Code</a>
     29  </ul>
     30  <ul>
     31    <li><a class=active href="#">Search/Replace</a>
     32  </ul>
     33</div>
    2334
    24   <dt id="option_tabMode"><code>tabMode (string)</code></dt>
    25   <dd>Determines what happens when the user presses the tab key.
    26   Must be one of the following:
    27     <dl>
    28       <dt><code>"classic" (the default)</code></dt>
    29       <dd>When nothing is selected, insert a tab. Otherwise,
    30       behave like the <code>"shift"</code> mode. (When shift is
    31       held, this behaves like the <code>"indent"</code> mode.)</dd>
    32       <dt><code>"shift"</code></dt>
    33       <dd>Indent all selected lines by
    34       one <a href="#option_indentUnit"><code>indentUnit</code></a>.
    35       If shift was held while pressing tab, un-indent all selected
    36       lines one unit.</dd>
    37       <dt><code>"indent"</code></dt>
    38       <dd>Indent the line the 'correctly', based on its syntactic
    39       context. Only works if the
    40       mode <a href="#indent">supports</a> it.</dd>
    41       <dt><code>"default"</code></dt>
    42       <dd>Do not capture tab presses, let the browser apply its
    43       default behaviour (which usually means it skips to the next
    44       control).</dd>
    45     </dl></dd>
     35<article>
     36<h2>Search/Replace Demo</h2>
     37<form><textarea id="code" name="code">
     38<dl>
     39  <dt id="option_indentWithTabs"><code><strong>indentWithTabs</strong>: boolean</code></dt>
     40  <dd>Whether, when indenting, the first N*<code>tabSize</code>
     41  spaces should be replaced by N tabs. Default is false.</dd>
    4642
    47   <dt id="option_enterMode"><code>enterMode (string)</code></dt>
    48   <dd>Determines whether and how new lines are indented when the
    49   enter key is pressed. The following modes are supported:
    50     <dl>
    51       <dt><code>"indent" (the default)</code></dt>
    52       <dd>Use the mode's indentation rules to give the new line
    53       the correct indentation.</dd>
    54       <dt><code>"keep"</code></dt>
    55       <dd>Indent the line the same as the previous line.</dd>
    56       <dt><code>"flat"</code></dt>
    57       <dd>Do not indent the new line.</dd>
    58     </dl></dd>
     43  <dt id="option_electricChars"><code><strong>electricChars</strong>: boolean</code></dt>
     44  <dd>Configures whether the editor should re-indent the current
     45  line when a character is typed that might change its proper
     46  indentation (only works if the mode supports indentation).
     47  Default is true.</dd>
     48
     49  <dt id="option_specialChars"><code><strong>specialChars</strong>: RegExp</code></dt>
     50  <dd>A regular expression used to determine which characters
     51  should be replaced by a
     52  special <a href="#option_specialCharPlaceholder">placeholder</a>.
     53  Mostly useful for non-printing special characters. The default
     54  is <code>/[\u0000-\u0019\u00ad\u200b\u2028\u2029\ufeff]/</code>.</dd>
     55  <dt id="option_specialCharPlaceholder"><code><strong>specialCharPlaceholder</strong>: function(char) → Element</code></dt>
     56  <dd>A function that, given a special character identified by
     57  the <a href="#option_specialChars"><code>specialChars</code></a>
     58  option, produces a DOM node that is used to represent the
     59  character. By default, a red dot (<span style="color: red">•</span>)
     60  is shown, with a title tooltip to indicate the character code.</dd>
     61
     62  <dt id="option_rtlMoveVisually"><code><strong>rtlMoveVisually</strong>: boolean</code></dt>
     63  <dd>Determines whether horizontal cursor movement through
     64  right-to-left (Arabic, Hebrew) text is visual (pressing the left
     65  arrow moves the cursor left) or logical (pressing the left arrow
     66  moves to the next lower index in the string, which is visually
     67  right in right-to-left text). The default is <code>false</code>
     68  on Windows, and <code>true</code> on other platforms.</dd>
     69</dl>
    5970</textarea></form>
    60 <button type=button onclick="search()">Search</button>
    61 <input type=text style="width: 5em" id=query value=indent> or
    62 <button type=button onclick="replace()">replace</button> it by
    63 <input type=text style="width: 5em" id=replace>
    6471
    6572    <script>
    66 var editor = CodeMirror.fromTextArea(document.getElementById("code"), {mode: "text/html", lineNumbers: true});
    67 
    68 var lastPos = null, lastQuery = null, marked = [];
    69 
    70 function unmark() {
    71   for (var i = 0; i < marked.length; ++i) marked[i]();
    72   marked.length = 0;
    73 }
    74 
    75 function search() {
    76   unmark();                     
    77   var text = document.getElementById("query").value;
    78   if (!text) return;
    79   for (var cursor = editor.getSearchCursor(text); cursor.findNext();)
    80     marked.push(editor.markText(cursor.from(), cursor.to(), "searched"));
    81 
    82   if (lastQuery != text) lastPos = null;
    83   var cursor = editor.getSearchCursor(text, lastPos || editor.getCursor());
    84   if (!cursor.findNext()) {
    85     cursor = editor.getSearchCursor(text);
    86     if (!cursor.findNext()) return;
    87   }
    88   editor.setSelection(cursor.from(), cursor.to());
    89   lastQuery = text; lastPos = cursor.to();
    90 }
    91 
    92 function replace() {
    93   unmark();
    94   var text = document.getElementById("query").value,
    95       replace = document.getElementById("replace").value;
    96   if (!text) return;
    97   for (var cursor = editor.getSearchCursor(text); cursor.findNext();)
    98     cursor.replace(replace);
    99 }
     73var editor = CodeMirror.fromTextArea(document.getElementById("code"), {
     74  mode: "text/html",
     75  lineNumbers: true,
     76  extraKeys: {"Alt-F": "findPersistent"}
     77});
    10078</script>
    10179
    102     <p>Demonstration of search/replace functionality and marking
    103     text.</p>
    104 
    105   </body>
    106 </html>
     80    <p>Demonstration of primitive search/replace functionality. The
     81    keybindings (which can be configured with custom keymaps) are:</p>
     82    <dl>
     83      <dt>Ctrl-F / Cmd-F</dt><dd>Start searching</dd>
     84      <dt>Ctrl-G / Cmd-G</dt><dd>Find next</dd>
     85      <dt>Shift-Ctrl-G / Shift-Cmd-G</dt><dd>Find previous</dd>
     86      <dt>Shift-Ctrl-F / Cmd-Option-F</dt><dd>Replace</dd>
     87      <dt>Shift-Ctrl-R / Shift-Cmd-Option-F</dt><dd>Replace all</dd>
     88      <dt>Alt-F</dt><dd>Persistent search (dialog doesn't autoclose,
     89      enter to find next, Shift-Enter to find previous)</dd>
     90      <dt>Alt-G</dt><dd>Jump to line</dd>
     91    </dl>
     92    <p>Searching is enabled by
     93    including <a href="../addon/search/search.js">addon/search/search.js</a>
     94    and <a href="../addon/search/searchcursor.js">addon/search/searchcursor.js</a>.
     95    Jump to line - including <a href="../addon/search/jump-to-line.js">addon/search/jump-to-line.js</a>.</p>
     96    <p>For good-looking input dialogs, you also want to include
     97    <a href="../addon/dialog/dialog.js">addon/dialog/dialog.js</a>
     98    and <a href="../addon/dialog/dialog.css">addon/dialog/dialog.css</a>.</p>
     99  </article>
  • _plugins_/skeleditor/trunk/codemirror/demo/theme.html

    r49339 r111861  
    11<!doctype html>
    2 <html>
    3   <head>
    4     <title>CodeMirror 2: Theme Demo</title>
    5     <link rel="stylesheet" href="../lib/codemirror.css">
    6     <script src="../lib/codemirror.js"></script>
    7     <link rel="stylesheet" href="../theme/default.css">
    8     <link rel="stylesheet" href="../theme/neat.css">
    9     <link rel="stylesheet" href="../theme/elegant.css">
    10     <link rel="stylesheet" href="../theme/night.css">
    11     <script src="../mode/javascript/javascript.js"></script>
    12     <link rel="stylesheet" href="../css/docs.css">
    132
    14     <style type="text/css">
    15       .CodeMirror {border: 1px solid black;}
     3<title>CodeMirror: Theme Demo</title>
     4<meta charset="utf-8"/>
     5<link rel=stylesheet href="../doc/docs.css">
     6
     7<link rel="stylesheet" href="../lib/codemirror.css">
     8<link rel="stylesheet" href="../theme/3024-day.css">
     9<link rel="stylesheet" href="../theme/3024-night.css">
     10<link rel="stylesheet" href="../theme/abcdef.css">
     11<link rel="stylesheet" href="../theme/ambiance.css">
     12<link rel="stylesheet" href="../theme/base16-dark.css">
     13<link rel="stylesheet" href="../theme/bespin.css">
     14<link rel="stylesheet" href="../theme/base16-light.css">
     15<link rel="stylesheet" href="../theme/blackboard.css">
     16<link rel="stylesheet" href="../theme/cobalt.css">
     17<link rel="stylesheet" href="../theme/colorforth.css">
     18<link rel="stylesheet" href="../theme/dracula.css">
     19<link rel="stylesheet" href="../theme/duotone-dark.css">
     20<link rel="stylesheet" href="../theme/duotone-light.css">
     21<link rel="stylesheet" href="../theme/eclipse.css">
     22<link rel="stylesheet" href="../theme/elegant.css">
     23<link rel="stylesheet" href="../theme/erlang-dark.css">
     24<link rel="stylesheet" href="../theme/gruvbox-dark.css">
     25<link rel="stylesheet" href="../theme/hopscotch.css">
     26<link rel="stylesheet" href="../theme/icecoder.css">
     27<link rel="stylesheet" href="../theme/isotope.css">
     28<link rel="stylesheet" href="../theme/lesser-dark.css">
     29<link rel="stylesheet" href="../theme/liquibyte.css">
     30<link rel="stylesheet" href="../theme/lucario.css">
     31<link rel="stylesheet" href="../theme/material.css">
     32<link rel="stylesheet" href="../theme/mbo.css">
     33<link rel="stylesheet" href="../theme/mdn-like.css">
     34<link rel="stylesheet" href="../theme/midnight.css">
     35<link rel="stylesheet" href="../theme/monokai.css">
     36<link rel="stylesheet" href="../theme/neat.css">
     37<link rel="stylesheet" href="../theme/neo.css">
     38<link rel="stylesheet" href="../theme/night.css">
     39<link rel="stylesheet" href="../theme/oceanic-next.css">
     40<link rel="stylesheet" href="../theme/panda-syntax.css">
     41<link rel="stylesheet" href="../theme/paraiso-dark.css">
     42<link rel="stylesheet" href="../theme/paraiso-light.css">
     43<link rel="stylesheet" href="../theme/pastel-on-dark.css">
     44<link rel="stylesheet" href="../theme/railscasts.css">
     45<link rel="stylesheet" href="../theme/rubyblue.css">
     46<link rel="stylesheet" href="../theme/seti.css">
     47<link rel="stylesheet" href="../theme/shadowfox.css">
     48<link rel="stylesheet" href="../theme/solarized.css">
     49<link rel="stylesheet" href="../theme/the-matrix.css">
     50<link rel="stylesheet" href="../theme/tomorrow-night-bright.css">
     51<link rel="stylesheet" href="../theme/tomorrow-night-eighties.css">
     52<link rel="stylesheet" href="../theme/ttcn.css">
     53<link rel="stylesheet" href="../theme/twilight.css">
     54<link rel="stylesheet" href="../theme/vibrant-ink.css">
     55<link rel="stylesheet" href="../theme/xq-dark.css">
     56<link rel="stylesheet" href="../theme/xq-light.css">
     57<link rel="stylesheet" href="../theme/yeti.css">
     58<link rel="stylesheet" href="../theme/idea.css">
     59<link rel="stylesheet" href="../theme/darcula.css">
     60<link rel="stylesheet" href="../theme/zenburn.css">
     61<script src="../lib/codemirror.js"></script>
     62<script src="../mode/javascript/javascript.js"></script>
     63<script src="../addon/selection/active-line.js"></script>
     64<script src="../addon/edit/matchbrackets.js"></script>
     65<style type="text/css">
     66      .CodeMirror {border: 1px solid black; font-size:13px}
    1667    </style>
    17   </head>
    18   <body>
    19     <h1>CodeMirror 2: Theme demo</h1>
     68<div id=nav>
     69  <a href="https://codemirror.net"><h1>CodeMirror</h1><img id=logo src="../doc/logo.png"></a>
    2070
    21     <form><textarea id="code" name="code">
     71  <ul>
     72    <li><a href="../index.html">Home</a>
     73    <li><a href="../doc/manual.html">Manual</a>
     74    <li><a href="https://github.com/codemirror/codemirror">Code</a>
     75  </ul>
     76  <ul>
     77    <li><a class=active href="#">Theme</a>
     78  </ul>
     79</div>
     80
     81<article>
     82<h2>Theme Demo</h2>
     83<form><textarea id="code" name="code">
    2284function findSequence(goal) {
    2385  function find(start, history) {
     
    3395}</textarea></form>
    3496
    35 <p>Select a theme: <select onchange="selectTheme(this)">
     97<p>Select a theme: <select onchange="selectTheme()" id=select>
    3698    <option selected>default</option>
     99    <option>3024-day</option>
     100    <option>3024-night</option>
     101    <option>abcdef</option>
     102    <option>ambiance</option>
     103    <option>base16-dark</option>
     104    <option>base16-light</option>
     105    <option>bespin</option>
     106    <option>blackboard</option>
     107    <option>cobalt</option>
     108    <option>colorforth</option>
     109    <option>darcula</option>
     110    <option>dracula</option>
     111    <option>duotone-dark</option>
     112    <option>duotone-light</option>
     113    <option>eclipse</option>
     114    <option>elegant</option>
     115    <option>erlang-dark</option>
     116    <option>gruvbox-dark</option>
     117    <option>hopscotch</option>
     118    <option>icecoder</option>
     119    <option>idea</option>
     120    <option>isotope</option>
     121    <option>lesser-dark</option>
     122    <option>liquibyte</option>
     123    <option>lucario</option>
     124    <option>material</option>
     125    <option>mbo</option>
     126    <option>mdn-like</option>
     127    <option>midnight</option>
     128    <option>monokai</option>
     129    <option>neat</option>
     130    <option>neo</option>
    37131    <option>night</option>
    38     <option>neat</option>
    39     <option>elegant</option>
     132    <option>oceanic-next</option>
     133    <option>panda-syntax</option>
     134    <option>paraiso-dark</option>
     135    <option>paraiso-light</option>
     136    <option>pastel-on-dark</option>
     137    <option>railscasts</option>
     138    <option>rubyblue</option>
     139    <option>seti</option>
     140    <option>shadowfox</option>
     141    <option>solarized dark</option>
     142    <option>solarized light</option>
     143    <option>the-matrix</option>
     144    <option>tomorrow-night-bright</option>
     145    <option>tomorrow-night-eighties</option>
     146    <option>ttcn</option>
     147    <option>twilight</option>
     148    <option>vibrant-ink</option>
     149    <option>xq-dark</option>
     150    <option>xq-light</option>
     151    <option>yeti</option>
     152    <option>zenburn</option>
    40153</select>
    41154</p>
     
    43156<script>
    44157  var editor = CodeMirror.fromTextArea(document.getElementById("code"), {
    45     lineNumbers: true
     158    lineNumbers: true,
     159    styleActiveLine: true,
     160    matchBrackets: true
    46161  });
    47   function selectTheme(node) {
    48     var theme = node.options[node.selectedIndex].innerHTML;
     162  var input = document.getElementById("select");
     163  function selectTheme() {
     164    var theme = input.options[input.selectedIndex].textContent;
    49165    editor.setOption("theme", theme);
     166    location.hash = "#" + theme;
    50167  }
     168  var choice = (location.hash && location.hash.slice(1)) ||
     169               (document.location.search &&
     170                decodeURIComponent(document.location.search.slice(1)));
     171  if (choice) {
     172    input.value = choice;
     173    editor.setOption("theme", choice);
     174  }
     175  CodeMirror.on(window, "hashchange", function() {
     176    var theme = location.hash.slice(1);
     177    if (theme) { input.value = theme; selectTheme(); }
     178  });
    51179</script>
    52   </body>
    53 </html>
     180  </article>
  • _plugins_/skeleditor/trunk/codemirror/lib/codemirror.css

    r49339 r111861  
     1/* BASICS */
     2
    13.CodeMirror {
    2   line-height: 1em;
     4  /* Set height, width, borders, and global font properties here */
    35  font-family: monospace;
     6  height: 300px;
     7  color: black;
     8  direction: ltr;
     9}
     10
     11/* PADDING */
     12
     13.CodeMirror-lines {
     14  padding: 4px 0; /* Vertical padding around content */
     15}
     16.CodeMirror pre {
     17  padding: 0 4px; /* Horizontal padding of content */
     18}
     19
     20.CodeMirror-scrollbar-filler, .CodeMirror-gutter-filler {
     21  background-color: white; /* The little square between H and V scrollbars */
     22}
     23
     24/* GUTTER */
     25
     26.CodeMirror-gutters {
     27  border-right: 1px solid #ddd;
     28  background-color: #f7f7f7;
     29  white-space: nowrap;
     30}
     31.CodeMirror-linenumbers {}
     32.CodeMirror-linenumber {
     33  padding: 0 3px 0 5px;
     34  min-width: 20px;
     35  text-align: right;
     36  color: #999;
     37  white-space: nowrap;
     38}
     39
     40.CodeMirror-guttermarker { color: black; }
     41.CodeMirror-guttermarker-subtle { color: #999; }
     42
     43/* CURSOR */
     44
     45.CodeMirror-cursor {
     46  border-left: 1px solid black;
     47  border-right: none;
     48  width: 0;
     49}
     50/* Shown when moving in bi-directional text */
     51.CodeMirror div.CodeMirror-secondarycursor {
     52  border-left: 1px solid silver;
     53}
     54.cm-fat-cursor .CodeMirror-cursor {
     55  width: auto;
     56  border: 0 !important;
     57  background: #7e7;
     58}
     59.cm-fat-cursor div.CodeMirror-cursors {
     60  z-index: 1;
     61}
     62.cm-fat-cursor-mark {
     63  background-color: rgba(20, 255, 20, 0.5);
     64  -webkit-animation: blink 1.06s steps(1) infinite;
     65  -moz-animation: blink 1.06s steps(1) infinite;
     66  animation: blink 1.06s steps(1) infinite;
     67}
     68.cm-animate-fat-cursor {
     69  width: auto;
     70  border: 0;
     71  -webkit-animation: blink 1.06s steps(1) infinite;
     72  -moz-animation: blink 1.06s steps(1) infinite;
     73  animation: blink 1.06s steps(1) infinite;
     74  background-color: #7e7;
     75}
     76@-moz-keyframes blink {
     77  0% {}
     78  50% { background-color: transparent; }
     79  100% {}
     80}
     81@-webkit-keyframes blink {
     82  0% {}
     83  50% { background-color: transparent; }
     84  100% {}
     85}
     86@keyframes blink {
     87  0% {}
     88  50% { background-color: transparent; }
     89  100% {}
     90}
     91
     92/* Can style cursor different in overwrite (non-insert) mode */
     93.CodeMirror-overwrite .CodeMirror-cursor {}
     94
     95.cm-tab { display: inline-block; text-decoration: inherit; }
     96
     97.CodeMirror-rulers {
     98  position: absolute;
     99  left: 0; right: 0; top: -50px; bottom: -20px;
     100  overflow: hidden;
     101}
     102.CodeMirror-ruler {
     103  border-left: 1px solid #ccc;
     104  top: 0; bottom: 0;
     105  position: absolute;
     106}
     107
     108/* DEFAULT THEME */
     109
     110.cm-s-default .cm-header {color: blue;}
     111.cm-s-default .cm-quote {color: #090;}
     112.cm-negative {color: #d44;}
     113.cm-positive {color: #292;}
     114.cm-header, .cm-strong {font-weight: bold;}
     115.cm-em {font-style: italic;}
     116.cm-link {text-decoration: underline;}
     117.cm-strikethrough {text-decoration: line-through;}
     118
     119.cm-s-default .cm-keyword {color: #708;}
     120.cm-s-default .cm-atom {color: #219;}
     121.cm-s-default .cm-number {color: #164;}
     122.cm-s-default .cm-def {color: #00f;}
     123.cm-s-default .cm-variable,
     124.cm-s-default .cm-punctuation,
     125.cm-s-default .cm-property,
     126.cm-s-default .cm-operator {}
     127.cm-s-default .cm-variable-2 {color: #05a;}
     128.cm-s-default .cm-variable-3, .cm-s-default .cm-type {color: #085;}
     129.cm-s-default .cm-comment {color: #a50;}
     130.cm-s-default .cm-string {color: #a11;}
     131.cm-s-default .cm-string-2 {color: #f50;}
     132.cm-s-default .cm-meta {color: #555;}
     133.cm-s-default .cm-qualifier {color: #555;}
     134.cm-s-default .cm-builtin {color: #30a;}
     135.cm-s-default .cm-bracket {color: #997;}
     136.cm-s-default .cm-tag {color: #170;}
     137.cm-s-default .cm-attribute {color: #00c;}
     138.cm-s-default .cm-hr {color: #999;}
     139.cm-s-default .cm-link {color: #00c;}
     140
     141.cm-s-default .cm-error {color: #f00;}
     142.cm-invalidchar {color: #f00;}
     143
     144.CodeMirror-composing { border-bottom: 2px solid; }
     145
     146/* Default styles for common addons */
     147
     148div.CodeMirror span.CodeMirror-matchingbracket {color: #0b0;}
     149div.CodeMirror span.CodeMirror-nonmatchingbracket {color: #a22;}
     150.CodeMirror-matchingtag { background: rgba(255, 150, 0, .3); }
     151.CodeMirror-activeline-background {background: #e8f2ff;}
     152
     153/* STOP */
     154
     155/* The rest of this file contains styles related to the mechanics of
     156   the editor. You probably shouldn't touch them. */
     157
     158.CodeMirror {
     159  position: relative;
     160  overflow: hidden;
     161  background: white;
    4162}
    5163
    6164.CodeMirror-scroll {
    7   overflow: auto;
    8   height: 300px;
    9   /* This is needed to prevent an IE[67] bug where the scrolled content
    10      is visible outside of the scrolling box. */
    11   position: relative;
    12 }
    13 
     165  overflow: scroll !important; /* Things will break if this is overridden */
     166  /* 30px is the magic margin used to hide the element's real scrollbars */
     167  /* See overflow: hidden in .CodeMirror */
     168  margin-bottom: -30px; margin-right: -30px;
     169  padding-bottom: 30px;
     170  height: 100%;
     171  outline: none; /* Prevent dragging from highlighting the element */
     172  position: relative;
     173}
     174.CodeMirror-sizer {
     175  position: relative;
     176  border-right: 30px solid transparent;
     177}
     178
     179/* The fake, visible scrollbars. Used to force redraw during scrolling
     180   before actual scrolling happens, thus preventing shaking and
     181   flickering artifacts. */
     182.CodeMirror-vscrollbar, .CodeMirror-hscrollbar, .CodeMirror-scrollbar-filler, .CodeMirror-gutter-filler {
     183  position: absolute;
     184  z-index: 6;
     185  display: none;
     186}
     187.CodeMirror-vscrollbar {
     188  right: 0; top: 0;
     189  overflow-x: hidden;
     190  overflow-y: scroll;
     191}
     192.CodeMirror-hscrollbar {
     193  bottom: 0; left: 0;
     194  overflow-y: hidden;
     195  overflow-x: scroll;
     196}
     197.CodeMirror-scrollbar-filler {
     198  right: 0; bottom: 0;
     199}
     200.CodeMirror-gutter-filler {
     201  left: 0; bottom: 0;
     202}
     203
     204.CodeMirror-gutters {
     205  position: absolute; left: 0; top: 0;
     206  min-height: 100%;
     207  z-index: 3;
     208}
    14209.CodeMirror-gutter {
    15   position: absolute; left: 0; top: 0;
    16   background-color: #f7f7f7;
    17   border-right: 1px solid #eee;
    18   min-width: 2em;
     210  white-space: normal;
    19211  height: 100%;
    20 }
    21 .CodeMirror-gutter-text {
    22   color: #aaa;
    23   text-align: right;
    24   padding: .4em .2em .4em .4em;
    25 }
     212  display: inline-block;
     213  vertical-align: top;
     214  margin-bottom: -30px;
     215}
     216.CodeMirror-gutter-wrapper {
     217  position: absolute;
     218  z-index: 4;
     219  background: none !important;
     220  border: none !important;
     221}
     222.CodeMirror-gutter-background {
     223  position: absolute;
     224  top: 0; bottom: 0;
     225  z-index: 4;
     226}
     227.CodeMirror-gutter-elt {
     228  position: absolute;
     229  cursor: default;
     230  z-index: 4;
     231}
     232.CodeMirror-gutter-wrapper ::selection { background-color: transparent }
     233.CodeMirror-gutter-wrapper ::-moz-selection { background-color: transparent }
     234
    26235.CodeMirror-lines {
    27   padding: .4em;
    28 }
    29 
     236  cursor: text;
     237  min-height: 1px; /* prevents collapsing before first draw */
     238}
    30239.CodeMirror pre {
    31   -moz-border-radius: 0;
    32   -webkit-border-radius: 0;
    33   -o-border-radius: 0;
    34   border-radius: 0;
    35   border-width: 0; margin: 0; padding: 0; background: transparent;
     240  /* Reset some styles that the rest of the page might have set */
     241  -moz-border-radius: 0; -webkit-border-radius: 0; border-radius: 0;
     242  border-width: 0;
     243  background: transparent;
    36244  font-family: inherit;
    37245  font-size: inherit;
    38   padding: 0; margin: 0;
     246  margin: 0;
    39247  white-space: pre;
    40248  word-wrap: normal;
    41 }
    42 
    43 .CodeMirror textarea {
    44   font-family: inherit !important;
    45   font-size: inherit !important;
     249  line-height: inherit;
     250  color: inherit;
     251  z-index: 2;
     252  position: relative;
     253  overflow: visible;
     254  -webkit-tap-highlight-color: transparent;
     255  -webkit-font-variant-ligatures: contextual;
     256  font-variant-ligatures: contextual;
     257}
     258.CodeMirror-wrap pre {
     259  word-wrap: break-word;
     260  white-space: pre-wrap;
     261  word-break: normal;
     262}
     263
     264.CodeMirror-linebackground {
     265  position: absolute;
     266  left: 0; right: 0; top: 0; bottom: 0;
     267  z-index: 0;
     268}
     269
     270.CodeMirror-linewidget {
     271  position: relative;
     272  z-index: 2;
     273  padding: 0.1px; /* Force widget margins to stay inside of the container */
     274}
     275
     276.CodeMirror-widget {}
     277
     278.CodeMirror-rtl pre { direction: rtl; }
     279
     280.CodeMirror-code {
     281  outline: none;
     282}
     283
     284/* Force content-box sizing for the elements where we expect it */
     285.CodeMirror-scroll,
     286.CodeMirror-sizer,
     287.CodeMirror-gutter,
     288.CodeMirror-gutters,
     289.CodeMirror-linenumber {
     290  -moz-box-sizing: content-box;
     291  box-sizing: content-box;
     292}
     293
     294.CodeMirror-measure {
     295  position: absolute;
     296  width: 100%;
     297  height: 0;
     298  overflow: hidden;
     299  visibility: hidden;
    46300}
    47301
    48302.CodeMirror-cursor {
    49   z-index: 10;
    50   position: absolute;
     303  position: absolute;
     304  pointer-events: none;
     305}
     306.CodeMirror-measure pre { position: static; }
     307
     308div.CodeMirror-cursors {
    51309  visibility: hidden;
    52   border-left: 1px solid black !important;
    53 }
    54 .CodeMirror-focused .CodeMirror-cursor {
     310  position: relative;
     311  z-index: 3;
     312}
     313div.CodeMirror-dragcursors {
    55314  visibility: visible;
    56315}
    57316
    58 span.CodeMirror-selected {
    59   background: #ccc !important;
    60   color: HighlightText !important;
    61 }
    62 .CodeMirror-focused span.CodeMirror-selected {
    63   background: Highlight !important;
    64 }
    65 
    66 .CodeMirror-matchingbracket {color: #0f0 !important;}
    67 .CodeMirror-nonmatchingbracket {color: #f22 !important;}
     317.CodeMirror-focused div.CodeMirror-cursors {
     318  visibility: visible;
     319}
     320
     321.CodeMirror-selected { background: #d9d9d9; }
     322.CodeMirror-focused .CodeMirror-selected { background: #d7d4f0; }
     323.CodeMirror-crosshair { cursor: crosshair; }
     324.CodeMirror-line::selection, .CodeMirror-line > span::selection, .CodeMirror-line > span > span::selection { background: #d7d4f0; }
     325.CodeMirror-line::-moz-selection, .CodeMirror-line > span::-moz-selection, .CodeMirror-line > span > span::-moz-selection { background: #d7d4f0; }
     326
     327.cm-searching {
     328  background-color: #ffa;
     329  background-color: rgba(255, 255, 0, .4);
     330}
     331
     332/* Used to force a border model for a node */
     333.cm-force-border { padding-right: .1px; }
     334
     335@media print {
     336  /* Hide the cursor when printing */
     337  .CodeMirror div.CodeMirror-cursors {
     338    visibility: hidden;
     339  }
     340}
     341
     342/* See issue #2901 */
     343.cm-tab-wrap-hack:after { content: ''; }
     344
     345/* Help users use markselection to safely style text background */
     346span.CodeMirror-selectedtext { background: none; }
  • _plugins_/skeleditor/trunk/codemirror/lib/codemirror.js

    r49339 r111861  
    1 // All functions that need access to the editor's state live inside
    2 // the CodeMirror function. Below that, at the bottom of the file,
    3 // some utilities are defined.
    4 
    5 // CodeMirror is the only global var we claim
    6 var CodeMirror = (function() {
    7   // This is the function that produces an editor instance. It's
    8   // closure is used to store the editor state.
    9   function CodeMirror(place, givenOptions) {
    10     // Determine effective options based on given values and defaults.
    11     var options = {}, defaults = CodeMirror.defaults;
    12     for (var opt in defaults)
    13       if (defaults.hasOwnProperty(opt))
    14         options[opt] = (givenOptions && givenOptions.hasOwnProperty(opt) ? givenOptions : defaults)[opt];
    15 
    16     var targetDocument = options["document"];
    17     // The element in which the editor lives.
    18     var wrapper = targetDocument.createElement("div");
    19     wrapper.className = "CodeMirror";
    20     // This mess creates the base DOM structure for the editor.
    21     wrapper.innerHTML =
    22       '<div style="overflow: hidden; position: relative; width: 1px; height: 0px;">' + // Wraps and hides input textarea
    23         '<textarea style="position: absolute; width: 2px;" wrap="off"></textarea></div>' +
    24       '<div class="CodeMirror-scroll cm-s-' + options.theme + '">' +
    25         '<div style="position: relative">' + // Set to the height of the text, causes scrolling
    26           '<div style="position: absolute; height: 0; width: 0; overflow: hidden;"></div>' +
    27           '<div style="position: relative">' + // Moved around its parent to cover visible view
    28             '<div class="CodeMirror-gutter"><div class="CodeMirror-gutter-text"></div></div>' +
    29             // Provides positioning relative to (visible) text origin
    30             '<div class="CodeMirror-lines"><div style="position: relative">' +
    31               '<pre class="CodeMirror-cursor">&#160;</pre>' + // Absolutely positioned blinky cursor
    32               '<div></div>' + // This DIV contains the actual code
    33             '</div></div></div></div></div>';
    34     if (place.appendChild) place.appendChild(wrapper); else place(wrapper);
    35     // I've never seen more elegant code in my life.
    36     var inputDiv = wrapper.firstChild, input = inputDiv.firstChild,
    37         scroller = wrapper.lastChild, code = scroller.firstChild,
    38         measure = code.firstChild, mover = measure.nextSibling,
    39         gutter = mover.firstChild, gutterText = gutter.firstChild,
    40         lineSpace = gutter.nextSibling.firstChild,
    41         cursor = lineSpace.firstChild, lineDiv = cursor.nextSibling;
    42     if (options.tabindex != null) input.tabindex = options.tabindex;
    43     if (!options.gutter && !options.lineNumbers) gutter.style.display = "none";
    44 
    45     // Delayed object wrap timeouts, making sure only one is active. blinker holds an interval.
    46     var poll = new Delayed(), highlight = new Delayed(), blinker;
    47 
    48     // mode holds a mode API object. lines an array of Line objects
    49     // (see Line constructor), work an array of lines that should be
    50     // parsed, and history the undo history (instance of History
    51     // constructor).
    52     var mode, lines = [new Line("")], work, history = new History(), focused;
    53     loadMode();
    54     // The selection. These are always maintained to point at valid
    55     // positions. Inverted is used to remember that the user is
    56     // selecting bottom-to-top.
    57     var sel = {from: {line: 0, ch: 0}, to: {line: 0, ch: 0}, inverted: false};
    58     // Selection-related flags. shiftSelecting obviously tracks
    59     // whether the user is holding shift. reducedSelection is a hack
    60     // to get around the fact that we can't create inverted
    61     // selections. See below.
    62     var shiftSelecting, reducedSelection, lastDoubleClick;
    63     // Variables used by startOperation/endOperation to track what
    64     // happened during the operation.
    65     var updateInput, changes, textChanged, selectionChanged, leaveInputAlone;
    66     // Current visible range (may be bigger than the view window).
    67     var showingFrom = 0, showingTo = 0, lastHeight = 0, curKeyId = null;
    68     // editing will hold an object describing the things we put in the
    69     // textarea, to help figure out whether something changed.
    70     // bracketHighlighted is used to remember that a backet has been
    71     // marked.
    72     var editing, bracketHighlighted;
    73     // Tracks the maximum line length so that the horizontal scrollbar
    74     // can be kept static when scrolling.
    75     var maxLine = "";
    76 
    77     // Initialize the content.
    78     operation(function(){setValue(options.value || ""); updateInput = false;})();
    79 
    80     // Register our event handlers.
    81     connect(scroller, "mousedown", operation(onMouseDown));
    82     // Gecko browsers fire contextmenu *after* opening the menu, at
    83     // which point we can't mess with it anymore. Context menu is
    84     // handled in onMouseDown for Gecko.
    85     if (!gecko) connect(scroller, "contextmenu", onContextMenu);
    86     connect(code, "dblclick", operation(onDblClick));
    87     connect(scroller, "scroll", function() {updateDisplay([]); if (options.onScroll) options.onScroll(instance);});
    88     connect(window, "resize", function() {updateDisplay(true);});
    89     connect(input, "keyup", operation(onKeyUp));
    90     connect(input, "keydown", operation(onKeyDown));
    91     connect(input, "keypress", operation(onKeyPress));
    92     connect(input, "focus", onFocus);
    93     connect(input, "blur", onBlur);
    94 
    95     connect(scroller, "dragenter", function(e){e.stop();});
    96     connect(scroller, "dragover", function(e){e.stop();});
    97     connect(scroller, "drop", operation(onDrop));
    98     connect(scroller, "paste", function(){focusInput(); fastPoll();});
    99     connect(input, "paste", function(){fastPoll();});
    100     connect(input, "cut", function(){fastPoll();});
    101    
    102     // IE throws unspecified error in certain cases, when
    103     // trying to access activeElement before onload
    104     var hasFocus; try { hasFocus = (targetDocument.activeElement == input); } catch(e) { }
    105     if (hasFocus) setTimeout(onFocus, 20);
    106     else onBlur();
    107 
    108     function isLine(l) {return l >= 0 && l < lines.length;}
    109     // The instance object that we'll return. Mostly calls out to
    110     // local functions in the CodeMirror function. Some do some extra
    111     // range checking and/or clipping. operation is used to wrap the
    112     // call so that changes it makes are tracked, and the display is
    113     // updated afterwards.
    114     var instance = {
    115       getValue: getValue,
    116       setValue: operation(setValue),
    117       getSelection: getSelection,
    118       replaceSelection: operation(replaceSelection),
    119       focus: function(){focusInput(); onFocus(); fastPoll();},
    120       setOption: function(option, value) {
    121         options[option] = value;
    122         if (option == "lineNumbers" || option == "gutter") gutterChanged();
    123         else if (option == "mode" || option == "indentUnit") loadMode();
    124         else if (option == "readOnly" && value == "nocursor") input.blur();
    125         else if (option == "theme") scroller.className = scroller.className.replace(/cm-s-\w+/, "cm-s-" + value);
    126       },
    127       getOption: function(option) {return options[option];},
    128       undo: operation(undo),
    129       redo: operation(redo),
    130       indentLine: operation(function(n) {if (isLine(n)) indentLine(n, "smart");}),
    131       historySize: function() {return {undo: history.done.length, redo: history.undone.length};},
    132       matchBrackets: operation(function(){matchBrackets(true);}),
    133       getTokenAt: function(pos) {
    134         pos = clipPos(pos);
    135         return lines[pos.line].getTokenAt(mode, getStateBefore(pos.line), pos.ch);
    136       },
    137       getStateAfter: function(line) {
    138         line = clipLine(line == null ? lines.length - 1: line);
    139         return getStateBefore(line + 1);
    140       },
    141       cursorCoords: function(start){
    142         if (start == null) start = sel.inverted;
    143         return pageCoords(start ? sel.from : sel.to);
    144       },
    145       charCoords: function(pos){return pageCoords(clipPos(pos));},
    146       coordsChar: function(coords) {
    147         var off = eltOffset(lineSpace);
    148         var line = clipLine(Math.min(lines.length - 1, showingFrom + Math.floor((coords.y - off.top) / lineHeight())));
    149         return clipPos({line: line, ch: charFromX(clipLine(line), coords.x - off.left)});
    150       },
    151       getSearchCursor: function(query, pos, caseFold) {return new SearchCursor(query, pos, caseFold);},
    152       markText: operation(function(a, b, c){return operation(markText(a, b, c));}),
    153       setMarker: addGutterMarker,
    154       clearMarker: removeGutterMarker,
    155       setLineClass: operation(setLineClass),
    156       lineInfo: lineInfo,
    157       addWidget: function(pos, node, scroll, where) {
    158         pos = localCoords(clipPos(pos));
    159         var top = pos.yBot, left = pos.x;
    160         node.style.position = "absolute";
    161         code.appendChild(node);
    162         node.style.left = left + "px";
    163         if (where == "over") top = pos.y;
    164         else if (where == "fit") {
    165           var vspace = lines.length * lineHeight(), hspace = code.clientWidth - paddingLeft();
    166           top = pos.y + node.offsetHeight > vspace ? vspace - node.offsetHeight : pos.y;
    167           if (left + node.offsetWidth > hspace) left = hspace - node.offsetWidth;
     1// CodeMirror, copyright (c) by Marijn Haverbeke and others
     2// Distributed under an MIT license: https://codemirror.net/LICENSE
     3
     4// This is CodeMirror (https://codemirror.net), a code editor
     5// implemented in JavaScript on top of the browser's DOM.
     6//
     7// You can find some technical background for some of the code below
     8// at http://marijnhaverbeke.nl/blog/#cm-internals .
     9
     10(function (global, factory) {
     11  typeof exports === 'object' && typeof module !== 'undefined' ? module.exports = factory() :
     12  typeof define === 'function' && define.amd ? define(factory) :
     13  (global.CodeMirror = factory());
     14}(this, (function () { 'use strict';
     15
     16// Kludges for bugs and behavior differences that can't be feature
     17// detected are enabled based on userAgent etc sniffing.
     18var userAgent = navigator.userAgent
     19var platform = navigator.platform
     20
     21var gecko = /gecko\/\d/i.test(userAgent)
     22var ie_upto10 = /MSIE \d/.test(userAgent)
     23var ie_11up = /Trident\/(?:[7-9]|\d{2,})\..*rv:(\d+)/.exec(userAgent)
     24var edge = /Edge\/(\d+)/.exec(userAgent)
     25var ie = ie_upto10 || ie_11up || edge
     26var ie_version = ie && (ie_upto10 ? document.documentMode || 6 : +(edge || ie_11up)[1])
     27var webkit = !edge && /WebKit\//.test(userAgent)
     28var qtwebkit = webkit && /Qt\/\d+\.\d+/.test(userAgent)
     29var chrome = !edge && /Chrome\//.test(userAgent)
     30var presto = /Opera\//.test(userAgent)
     31var safari = /Apple Computer/.test(navigator.vendor)
     32var mac_geMountainLion = /Mac OS X 1\d\D([8-9]|\d\d)\D/.test(userAgent)
     33var phantom = /PhantomJS/.test(userAgent)
     34
     35var ios = !edge && /AppleWebKit/.test(userAgent) && /Mobile\/\w+/.test(userAgent)
     36var android = /Android/.test(userAgent)
     37// This is woefully incomplete. Suggestions for alternative methods welcome.
     38var mobile = ios || android || /webOS|BlackBerry|Opera Mini|Opera Mobi|IEMobile/i.test(userAgent)
     39var mac = ios || /Mac/.test(platform)
     40var chromeOS = /\bCrOS\b/.test(userAgent)
     41var windows = /win/i.test(platform)
     42
     43var presto_version = presto && userAgent.match(/Version\/(\d*\.\d*)/)
     44if (presto_version) { presto_version = Number(presto_version[1]) }
     45if (presto_version && presto_version >= 15) { presto = false; webkit = true }
     46// Some browsers use the wrong event properties to signal cmd/ctrl on OS X
     47var flipCtrlCmd = mac && (qtwebkit || presto && (presto_version == null || presto_version < 12.11))
     48var captureRightClick = gecko || (ie && ie_version >= 9)
     49
     50function classTest(cls) { return new RegExp("(^|\\s)" + cls + "(?:$|\\s)\\s*") }
     51
     52var rmClass = function(node, cls) {
     53  var current = node.className
     54  var match = classTest(cls).exec(current)
     55  if (match) {
     56    var after = current.slice(match.index + match[0].length)
     57    node.className = current.slice(0, match.index) + (after ? match[1] + after : "")
     58  }
     59}
     60
     61function removeChildren(e) {
     62  for (var count = e.childNodes.length; count > 0; --count)
     63    { e.removeChild(e.firstChild) }
     64  return e
     65}
     66
     67function removeChildrenAndAdd(parent, e) {
     68  return removeChildren(parent).appendChild(e)
     69}
     70
     71function elt(tag, content, className, style) {
     72  var e = document.createElement(tag)
     73  if (className) { e.className = className }
     74  if (style) { e.style.cssText = style }
     75  if (typeof content == "string") { e.appendChild(document.createTextNode(content)) }
     76  else if (content) { for (var i = 0; i < content.length; ++i) { e.appendChild(content[i]) } }
     77  return e
     78}
     79// wrapper for elt, which removes the elt from the accessibility tree
     80function eltP(tag, content, className, style) {
     81  var e = elt(tag, content, className, style)
     82  e.setAttribute("role", "presentation")
     83  return e
     84}
     85
     86var range
     87if (document.createRange) { range = function(node, start, end, endNode) {
     88  var r = document.createRange()
     89  r.setEnd(endNode || node, end)
     90  r.setStart(node, start)
     91  return r
     92} }
     93else { range = function(node, start, end) {
     94  var r = document.body.createTextRange()
     95  try { r.moveToElementText(node.parentNode) }
     96  catch(e) { return r }
     97  r.collapse(true)
     98  r.moveEnd("character", end)
     99  r.moveStart("character", start)
     100  return r
     101} }
     102
     103function contains(parent, child) {
     104  if (child.nodeType == 3) // Android browser always returns false when child is a textnode
     105    { child = child.parentNode }
     106  if (parent.contains)
     107    { return parent.contains(child) }
     108  do {
     109    if (child.nodeType == 11) { child = child.host }
     110    if (child == parent) { return true }
     111  } while (child = child.parentNode)
     112}
     113
     114function activeElt() {
     115  // IE and Edge may throw an "Unspecified Error" when accessing document.activeElement.
     116  // IE < 10 will throw when accessed while the page is loading or in an iframe.
     117  // IE > 9 and Edge will throw when accessed in an iframe if document.body is unavailable.
     118  var activeElement
     119  try {
     120    activeElement = document.activeElement
     121  } catch(e) {
     122    activeElement = document.body || null
     123  }
     124  while (activeElement && activeElement.shadowRoot && activeElement.shadowRoot.activeElement)
     125    { activeElement = activeElement.shadowRoot.activeElement }
     126  return activeElement
     127}
     128
     129function addClass(node, cls) {
     130  var current = node.className
     131  if (!classTest(cls).test(current)) { node.className += (current ? " " : "") + cls }
     132}
     133function joinClasses(a, b) {
     134  var as = a.split(" ")
     135  for (var i = 0; i < as.length; i++)
     136    { if (as[i] && !classTest(as[i]).test(b)) { b += " " + as[i] } }
     137  return b
     138}
     139
     140var selectInput = function(node) { node.select() }
     141if (ios) // Mobile Safari apparently has a bug where select() is broken.
     142  { selectInput = function(node) { node.selectionStart = 0; node.selectionEnd = node.value.length } }
     143else if (ie) // Suppress mysterious IE10 errors
     144  { selectInput = function(node) { try { node.select() } catch(_e) {} } }
     145
     146function bind(f) {
     147  var args = Array.prototype.slice.call(arguments, 1)
     148  return function(){return f.apply(null, args)}
     149}
     150
     151function copyObj(obj, target, overwrite) {
     152  if (!target) { target = {} }
     153  for (var prop in obj)
     154    { if (obj.hasOwnProperty(prop) && (overwrite !== false || !target.hasOwnProperty(prop)))
     155      { target[prop] = obj[prop] } }
     156  return target
     157}
     158
     159// Counts the column offset in a string, taking tabs into account.
     160// Used mostly to find indentation.
     161function countColumn(string, end, tabSize, startIndex, startValue) {
     162  if (end == null) {
     163    end = string.search(/[^\s\u00a0]/)
     164    if (end == -1) { end = string.length }
     165  }
     166  for (var i = startIndex || 0, n = startValue || 0;;) {
     167    var nextTab = string.indexOf("\t", i)
     168    if (nextTab < 0 || nextTab >= end)
     169      { return n + (end - i) }
     170    n += nextTab - i
     171    n += tabSize - (n % tabSize)
     172    i = nextTab + 1
     173  }
     174}
     175
     176var Delayed = function() {this.id = null};
     177Delayed.prototype.set = function (ms, f) {
     178  clearTimeout(this.id)
     179  this.id = setTimeout(f, ms)
     180};
     181
     182function indexOf(array, elt) {
     183  for (var i = 0; i < array.length; ++i)
     184    { if (array[i] == elt) { return i } }
     185  return -1
     186}
     187
     188// Number of pixels added to scroller and sizer to hide scrollbar
     189var scrollerGap = 30
     190
     191// Returned or thrown by various protocols to signal 'I'm not
     192// handling this'.
     193var Pass = {toString: function(){return "CodeMirror.Pass"}}
     194
     195// Reused option objects for setSelection & friends
     196var sel_dontScroll = {scroll: false};
     197var sel_mouse = {origin: "*mouse"};
     198var sel_move = {origin: "+move"};
     199// The inverse of countColumn -- find the offset that corresponds to
     200// a particular column.
     201function findColumn(string, goal, tabSize) {
     202  for (var pos = 0, col = 0;;) {
     203    var nextTab = string.indexOf("\t", pos)
     204    if (nextTab == -1) { nextTab = string.length }
     205    var skipped = nextTab - pos
     206    if (nextTab == string.length || col + skipped >= goal)
     207      { return pos + Math.min(skipped, goal - col) }
     208    col += nextTab - pos
     209    col += tabSize - (col % tabSize)
     210    pos = nextTab + 1
     211    if (col >= goal) { return pos }
     212  }
     213}
     214
     215var spaceStrs = [""]
     216function spaceStr(n) {
     217  while (spaceStrs.length <= n)
     218    { spaceStrs.push(lst(spaceStrs) + " ") }
     219  return spaceStrs[n]
     220}
     221
     222function lst(arr) { return arr[arr.length-1] }
     223
     224function map(array, f) {
     225  var out = []
     226  for (var i = 0; i < array.length; i++) { out[i] = f(array[i], i) }
     227  return out
     228}
     229
     230function insertSorted(array, value, score) {
     231  var pos = 0, priority = score(value)
     232  while (pos < array.length && score(array[pos]) <= priority) { pos++ }
     233  array.splice(pos, 0, value)
     234}
     235
     236function nothing() {}
     237
     238function createObj(base, props) {
     239  var inst
     240  if (Object.create) {
     241    inst = Object.create(base)
     242  } else {
     243    nothing.prototype = base
     244    inst = new nothing()
     245  }
     246  if (props) { copyObj(props, inst) }
     247  return inst
     248}
     249
     250var nonASCIISingleCaseWordChar = /[\u00df\u0587\u0590-\u05f4\u0600-\u06ff\u3040-\u309f\u30a0-\u30ff\u3400-\u4db5\u4e00-\u9fcc\uac00-\ud7af]/
     251function isWordCharBasic(ch) {
     252  return /\w/.test(ch) || ch > "\x80" &&
     253    (ch.toUpperCase() != ch.toLowerCase() || nonASCIISingleCaseWordChar.test(ch))
     254}
     255function isWordChar(ch, helper) {
     256  if (!helper) { return isWordCharBasic(ch) }
     257  if (helper.source.indexOf("\\w") > -1 && isWordCharBasic(ch)) { return true }
     258  return helper.test(ch)
     259}
     260
     261function isEmpty(obj) {
     262  for (var n in obj) { if (obj.hasOwnProperty(n) && obj[n]) { return false } }
     263  return true
     264}
     265
     266// Extending unicode characters. A series of a non-extending char +
     267// any number of extending chars is treated as a single unit as far
     268// as editing and measuring is concerned. This is not fully correct,
     269// since some scripts/fonts/browsers also treat other configurations
     270// of code points as a group.
     271var extendingChars = /[\u0300-\u036f\u0483-\u0489\u0591-\u05bd\u05bf\u05c1\u05c2\u05c4\u05c5\u05c7\u0610-\u061a\u064b-\u065e\u0670\u06d6-\u06dc\u06de-\u06e4\u06e7\u06e8\u06ea-\u06ed\u0711\u0730-\u074a\u07a6-\u07b0\u07eb-\u07f3\u0816-\u0819\u081b-\u0823\u0825-\u0827\u0829-\u082d\u0900-\u0902\u093c\u0941-\u0948\u094d\u0951-\u0955\u0962\u0963\u0981\u09bc\u09be\u09c1-\u09c4\u09cd\u09d7\u09e2\u09e3\u0a01\u0a02\u0a3c\u0a41\u0a42\u0a47\u0a48\u0a4b-\u0a4d\u0a51\u0a70\u0a71\u0a75\u0a81\u0a82\u0abc\u0ac1-\u0ac5\u0ac7\u0ac8\u0acd\u0ae2\u0ae3\u0b01\u0b3c\u0b3e\u0b3f\u0b41-\u0b44\u0b4d\u0b56\u0b57\u0b62\u0b63\u0b82\u0bbe\u0bc0\u0bcd\u0bd7\u0c3e-\u0c40\u0c46-\u0c48\u0c4a-\u0c4d\u0c55\u0c56\u0c62\u0c63\u0cbc\u0cbf\u0cc2\u0cc6\u0ccc\u0ccd\u0cd5\u0cd6\u0ce2\u0ce3\u0d3e\u0d41-\u0d44\u0d4d\u0d57\u0d62\u0d63\u0dca\u0dcf\u0dd2-\u0dd4\u0dd6\u0ddf\u0e31\u0e34-\u0e3a\u0e47-\u0e4e\u0eb1\u0eb4-\u0eb9\u0ebb\u0ebc\u0ec8-\u0ecd\u0f18\u0f19\u0f35\u0f37\u0f39\u0f71-\u0f7e\u0f80-\u0f84\u0f86\u0f87\u0f90-\u0f97\u0f99-\u0fbc\u0fc6\u102d-\u1030\u1032-\u1037\u1039\u103a\u103d\u103e\u1058\u1059\u105e-\u1060\u1071-\u1074\u1082\u1085\u1086\u108d\u109d\u135f\u1712-\u1714\u1732-\u1734\u1752\u1753\u1772\u1773\u17b7-\u17bd\u17c6\u17c9-\u17d3\u17dd\u180b-\u180d\u18a9\u1920-\u1922\u1927\u1928\u1932\u1939-\u193b\u1a17\u1a18\u1a56\u1a58-\u1a5e\u1a60\u1a62\u1a65-\u1a6c\u1a73-\u1a7c\u1a7f\u1b00-\u1b03\u1b34\u1b36-\u1b3a\u1b3c\u1b42\u1b6b-\u1b73\u1b80\u1b81\u1ba2-\u1ba5\u1ba8\u1ba9\u1c2c-\u1c33\u1c36\u1c37\u1cd0-\u1cd2\u1cd4-\u1ce0\u1ce2-\u1ce8\u1ced\u1dc0-\u1de6\u1dfd-\u1dff\u200c\u200d\u20d0-\u20f0\u2cef-\u2cf1\u2de0-\u2dff\u302a-\u302f\u3099\u309a\ua66f-\ua672\ua67c\ua67d\ua6f0\ua6f1\ua802\ua806\ua80b\ua825\ua826\ua8c4\ua8e0-\ua8f1\ua926-\ua92d\ua947-\ua951\ua980-\ua982\ua9b3\ua9b6-\ua9b9\ua9bc\uaa29-\uaa2e\uaa31\uaa32\uaa35\uaa36\uaa43\uaa4c\uaab0\uaab2-\uaab4\uaab7\uaab8\uaabe\uaabf\uaac1\uabe5\uabe8\uabed\udc00-\udfff\ufb1e\ufe00-\ufe0f\ufe20-\ufe26\uff9e\uff9f]/
     272function isExtendingChar(ch) { return ch.charCodeAt(0) >= 768 && extendingChars.test(ch) }
     273
     274// Returns a number from the range [`0`; `str.length`] unless `pos` is outside that range.
     275function skipExtendingChars(str, pos, dir) {
     276  while ((dir < 0 ? pos > 0 : pos < str.length) && isExtendingChar(str.charAt(pos))) { pos += dir }
     277  return pos
     278}
     279
     280// Returns the value from the range [`from`; `to`] that satisfies
     281// `pred` and is closest to `from`. Assumes that at least `to`
     282// satisfies `pred`. Supports `from` being greater than `to`.
     283function findFirst(pred, from, to) {
     284  // At any point we are certain `to` satisfies `pred`, don't know
     285  // whether `from` does.
     286  var dir = from > to ? -1 : 1
     287  for (;;) {
     288    if (from == to) { return from }
     289    var midF = (from + to) / 2, mid = dir < 0 ? Math.ceil(midF) : Math.floor(midF)
     290    if (mid == from) { return pred(mid) ? from : to }
     291    if (pred(mid)) { to = mid }
     292    else { from = mid + dir }
     293  }
     294}
     295
     296// The display handles the DOM integration, both for input reading
     297// and content drawing. It holds references to DOM nodes and
     298// display-related state.
     299
     300function Display(place, doc, input) {
     301  var d = this
     302  this.input = input
     303
     304  // Covers bottom-right square when both scrollbars are present.
     305  d.scrollbarFiller = elt("div", null, "CodeMirror-scrollbar-filler")
     306  d.scrollbarFiller.setAttribute("cm-not-content", "true")
     307  // Covers bottom of gutter when coverGutterNextToScrollbar is on
     308  // and h scrollbar is present.
     309  d.gutterFiller = elt("div", null, "CodeMirror-gutter-filler")
     310  d.gutterFiller.setAttribute("cm-not-content", "true")
     311  // Will contain the actual code, positioned to cover the viewport.
     312  d.lineDiv = eltP("div", null, "CodeMirror-code")
     313  // Elements are added to these to represent selection and cursors.
     314  d.selectionDiv = elt("div", null, null, "position: relative; z-index: 1")
     315  d.cursorDiv = elt("div", null, "CodeMirror-cursors")
     316  // A visibility: hidden element used to find the size of things.
     317  d.measure = elt("div", null, "CodeMirror-measure")
     318  // When lines outside of the viewport are measured, they are drawn in this.
     319  d.lineMeasure = elt("div", null, "CodeMirror-measure")
     320  // Wraps everything that needs to exist inside the vertically-padded coordinate system
     321  d.lineSpace = eltP("div", [d.measure, d.lineMeasure, d.selectionDiv, d.cursorDiv, d.lineDiv],
     322                    null, "position: relative; outline: none")
     323  var lines = eltP("div", [d.lineSpace], "CodeMirror-lines")
     324  // Moved around its parent to cover visible view.
     325  d.mover = elt("div", [lines], null, "position: relative")
     326  // Set to the height of the document, allowing scrolling.
     327  d.sizer = elt("div", [d.mover], "CodeMirror-sizer")
     328  d.sizerWidth = null
     329  // Behavior of elts with overflow: auto and padding is
     330  // inconsistent across browsers. This is used to ensure the
     331  // scrollable area is big enough.
     332  d.heightForcer = elt("div", null, null, "position: absolute; height: " + scrollerGap + "px; width: 1px;")
     333  // Will contain the gutters, if any.
     334  d.gutters = elt("div", null, "CodeMirror-gutters")
     335  d.lineGutter = null
     336  // Actual scrollable element.
     337  d.scroller = elt("div", [d.sizer, d.heightForcer, d.gutters], "CodeMirror-scroll")
     338  d.scroller.setAttribute("tabIndex", "-1")
     339  // The element in which the editor lives.
     340  d.wrapper = elt("div", [d.scrollbarFiller, d.gutterFiller, d.scroller], "CodeMirror")
     341
     342  // Work around IE7 z-index bug (not perfect, hence IE7 not really being supported)
     343  if (ie && ie_version < 8) { d.gutters.style.zIndex = -1; d.scroller.style.paddingRight = 0 }
     344  if (!webkit && !(gecko && mobile)) { d.scroller.draggable = true }
     345
     346  if (place) {
     347    if (place.appendChild) { place.appendChild(d.wrapper) }
     348    else { place(d.wrapper) }
     349  }
     350
     351  // Current rendered range (may be bigger than the view window).
     352  d.viewFrom = d.viewTo = doc.first
     353  d.reportedViewFrom = d.reportedViewTo = doc.first
     354  // Information about the rendered lines.
     355  d.view = []
     356  d.renderedView = null
     357  // Holds info about a single rendered line when it was rendered
     358  // for measurement, while not in view.
     359  d.externalMeasured = null
     360  // Empty space (in pixels) above the view
     361  d.viewOffset = 0
     362  d.lastWrapHeight = d.lastWrapWidth = 0
     363  d.updateLineNumbers = null
     364
     365  d.nativeBarWidth = d.barHeight = d.barWidth = 0
     366  d.scrollbarsClipped = false
     367
     368  // Used to only resize the line number gutter when necessary (when
     369  // the amount of lines crosses a boundary that makes its width change)
     370  d.lineNumWidth = d.lineNumInnerWidth = d.lineNumChars = null
     371  // Set to true when a non-horizontal-scrolling line widget is
     372  // added. As an optimization, line widget aligning is skipped when
     373  // this is false.
     374  d.alignWidgets = false
     375
     376  d.cachedCharWidth = d.cachedTextHeight = d.cachedPaddingH = null
     377
     378  // Tracks the maximum line length so that the horizontal scrollbar
     379  // can be kept static when scrolling.
     380  d.maxLine = null
     381  d.maxLineLength = 0
     382  d.maxLineChanged = false
     383
     384  // Used for measuring wheel scrolling granularity
     385  d.wheelDX = d.wheelDY = d.wheelStartX = d.wheelStartY = null
     386
     387  // True when shift is held down.
     388  d.shift = false
     389
     390  // Used to track whether anything happened since the context menu
     391  // was opened.
     392  d.selForContextMenu = null
     393
     394  d.activeTouch = null
     395
     396  input.init(d)
     397}
     398
     399// Find the line object corresponding to the given line number.
     400function getLine(doc, n) {
     401  n -= doc.first
     402  if (n < 0 || n >= doc.size) { throw new Error("There is no line " + (n + doc.first) + " in the document.") }
     403  var chunk = doc
     404  while (!chunk.lines) {
     405    for (var i = 0;; ++i) {
     406      var child = chunk.children[i], sz = child.chunkSize()
     407      if (n < sz) { chunk = child; break }
     408      n -= sz
     409    }
     410  }
     411  return chunk.lines[n]
     412}
     413
     414// Get the part of a document between two positions, as an array of
     415// strings.
     416function getBetween(doc, start, end) {
     417  var out = [], n = start.line
     418  doc.iter(start.line, end.line + 1, function (line) {
     419    var text = line.text
     420    if (n == end.line) { text = text.slice(0, end.ch) }
     421    if (n == start.line) { text = text.slice(start.ch) }
     422    out.push(text)
     423    ++n
     424  })
     425  return out
     426}
     427// Get the lines between from and to, as array of strings.
     428function getLines(doc, from, to) {
     429  var out = []
     430  doc.iter(from, to, function (line) { out.push(line.text) }) // iter aborts when callback returns truthy value
     431  return out
     432}
     433
     434// Update the height of a line, propagating the height change
     435// upwards to parent nodes.
     436function updateLineHeight(line, height) {
     437  var diff = height - line.height
     438  if (diff) { for (var n = line; n; n = n.parent) { n.height += diff } }
     439}
     440
     441// Given a line object, find its line number by walking up through
     442// its parent links.
     443function lineNo(line) {
     444  if (line.parent == null) { return null }
     445  var cur = line.parent, no = indexOf(cur.lines, line)
     446  for (var chunk = cur.parent; chunk; cur = chunk, chunk = chunk.parent) {
     447    for (var i = 0;; ++i) {
     448      if (chunk.children[i] == cur) { break }
     449      no += chunk.children[i].chunkSize()
     450    }
     451  }
     452  return no + cur.first
     453}
     454
     455// Find the line at the given vertical position, using the height
     456// information in the document tree.
     457function lineAtHeight(chunk, h) {
     458  var n = chunk.first
     459  outer: do {
     460    for (var i$1 = 0; i$1 < chunk.children.length; ++i$1) {
     461      var child = chunk.children[i$1], ch = child.height
     462      if (h < ch) { chunk = child; continue outer }
     463      h -= ch
     464      n += child.chunkSize()
     465    }
     466    return n
     467  } while (!chunk.lines)
     468  var i = 0
     469  for (; i < chunk.lines.length; ++i) {
     470    var line = chunk.lines[i], lh = line.height
     471    if (h < lh) { break }
     472    h -= lh
     473  }
     474  return n + i
     475}
     476
     477function isLine(doc, l) {return l >= doc.first && l < doc.first + doc.size}
     478
     479function lineNumberFor(options, i) {
     480  return String(options.lineNumberFormatter(i + options.firstLineNumber))
     481}
     482
     483// A Pos instance represents a position within the text.
     484function Pos(line, ch, sticky) {
     485  if ( sticky === void 0 ) sticky = null;
     486
     487  if (!(this instanceof Pos)) { return new Pos(line, ch, sticky) }
     488  this.line = line
     489  this.ch = ch
     490  this.sticky = sticky
     491}
     492
     493// Compare two positions, return 0 if they are the same, a negative
     494// number when a is less, and a positive number otherwise.
     495function cmp(a, b) { return a.line - b.line || a.ch - b.ch }
     496
     497function equalCursorPos(a, b) { return a.sticky == b.sticky && cmp(a, b) == 0 }
     498
     499function copyPos(x) {return Pos(x.line, x.ch)}
     500function maxPos(a, b) { return cmp(a, b) < 0 ? b : a }
     501function minPos(a, b) { return cmp(a, b) < 0 ? a : b }
     502
     503// Most of the external API clips given positions to make sure they
     504// actually exist within the document.
     505function clipLine(doc, n) {return Math.max(doc.first, Math.min(n, doc.first + doc.size - 1))}
     506function clipPos(doc, pos) {
     507  if (pos.line < doc.first) { return Pos(doc.first, 0) }
     508  var last = doc.first + doc.size - 1
     509  if (pos.line > last) { return Pos(last, getLine(doc, last).text.length) }
     510  return clipToLen(pos, getLine(doc, pos.line).text.length)
     511}
     512function clipToLen(pos, linelen) {
     513  var ch = pos.ch
     514  if (ch == null || ch > linelen) { return Pos(pos.line, linelen) }
     515  else if (ch < 0) { return Pos(pos.line, 0) }
     516  else { return pos }
     517}
     518function clipPosArray(doc, array) {
     519  var out = []
     520  for (var i = 0; i < array.length; i++) { out[i] = clipPos(doc, array[i]) }
     521  return out
     522}
     523
     524// Optimize some code when these features are not used.
     525var sawReadOnlySpans = false;
     526var sawCollapsedSpans = false;
     527function seeReadOnlySpans() {
     528  sawReadOnlySpans = true
     529}
     530
     531function seeCollapsedSpans() {
     532  sawCollapsedSpans = true
     533}
     534
     535// TEXTMARKER SPANS
     536
     537function MarkedSpan(marker, from, to) {
     538  this.marker = marker
     539  this.from = from; this.to = to
     540}
     541
     542// Search an array of spans for a span matching the given marker.
     543function getMarkedSpanFor(spans, marker) {
     544  if (spans) { for (var i = 0; i < spans.length; ++i) {
     545    var span = spans[i]
     546    if (span.marker == marker) { return span }
     547  } }
     548}
     549// Remove a span from an array, returning undefined if no spans are
     550// left (we don't store arrays for lines without spans).
     551function removeMarkedSpan(spans, span) {
     552  var r
     553  for (var i = 0; i < spans.length; ++i)
     554    { if (spans[i] != span) { (r || (r = [])).push(spans[i]) } }
     555  return r
     556}
     557// Add a span to a line.
     558function addMarkedSpan(line, span) {
     559  line.markedSpans = line.markedSpans ? line.markedSpans.concat([span]) : [span]
     560  span.marker.attachLine(line)
     561}
     562
     563// Used for the algorithm that adjusts markers for a change in the
     564// document. These functions cut an array of spans at a given
     565// character position, returning an array of remaining chunks (or
     566// undefined if nothing remains).
     567function markedSpansBefore(old, startCh, isInsert) {
     568  var nw
     569  if (old) { for (var i = 0; i < old.length; ++i) {
     570    var span = old[i], marker = span.marker
     571    var startsBefore = span.from == null || (marker.inclusiveLeft ? span.from <= startCh : span.from < startCh)
     572    if (startsBefore || span.from == startCh && marker.type == "bookmark" && (!isInsert || !span.marker.insertLeft)) {
     573      var endsAfter = span.to == null || (marker.inclusiveRight ? span.to >= startCh : span.to > startCh)
     574      ;(nw || (nw = [])).push(new MarkedSpan(marker, span.from, endsAfter ? null : span.to))
     575    }
     576  } }
     577  return nw
     578}
     579function markedSpansAfter(old, endCh, isInsert) {
     580  var nw
     581  if (old) { for (var i = 0; i < old.length; ++i) {
     582    var span = old[i], marker = span.marker
     583    var endsAfter = span.to == null || (marker.inclusiveRight ? span.to >= endCh : span.to > endCh)
     584    if (endsAfter || span.from == endCh && marker.type == "bookmark" && (!isInsert || span.marker.insertLeft)) {
     585      var startsBefore = span.from == null || (marker.inclusiveLeft ? span.from <= endCh : span.from < endCh)
     586      ;(nw || (nw = [])).push(new MarkedSpan(marker, startsBefore ? null : span.from - endCh,
     587                                            span.to == null ? null : span.to - endCh))
     588    }
     589  } }
     590  return nw
     591}
     592
     593// Given a change object, compute the new set of marker spans that
     594// cover the line in which the change took place. Removes spans
     595// entirely within the change, reconnects spans belonging to the
     596// same marker that appear on both sides of the change, and cuts off
     597// spans partially within the change. Returns an array of span
     598// arrays with one element for each line in (after) the change.
     599function stretchSpansOverChange(doc, change) {
     600  if (change.full) { return null }
     601  var oldFirst = isLine(doc, change.from.line) && getLine(doc, change.from.line).markedSpans
     602  var oldLast = isLine(doc, change.to.line) && getLine(doc, change.to.line).markedSpans
     603  if (!oldFirst && !oldLast) { return null }
     604
     605  var startCh = change.from.ch, endCh = change.to.ch, isInsert = cmp(change.from, change.to) == 0
     606  // Get the spans that 'stick out' on both sides
     607  var first = markedSpansBefore(oldFirst, startCh, isInsert)
     608  var last = markedSpansAfter(oldLast, endCh, isInsert)
     609
     610  // Next, merge those two ends
     611  var sameLine = change.text.length == 1, offset = lst(change.text).length + (sameLine ? startCh : 0)
     612  if (first) {
     613    // Fix up .to properties of first
     614    for (var i = 0; i < first.length; ++i) {
     615      var span = first[i]
     616      if (span.to == null) {
     617        var found = getMarkedSpanFor(last, span.marker)
     618        if (!found) { span.to = startCh }
     619        else if (sameLine) { span.to = found.to == null ? null : found.to + offset }
     620      }
     621    }
     622  }
     623  if (last) {
     624    // Fix up .from in last (or move them into first in case of sameLine)
     625    for (var i$1 = 0; i$1 < last.length; ++i$1) {
     626      var span$1 = last[i$1]
     627      if (span$1.to != null) { span$1.to += offset }
     628      if (span$1.from == null) {
     629        var found$1 = getMarkedSpanFor(first, span$1.marker)
     630        if (!found$1) {
     631          span$1.from = offset
     632          if (sameLine) { (first || (first = [])).push(span$1) }
    168633        }
    169         node.style.top = (top + paddingTop()) + "px";
    170         node.style.left = (left + paddingLeft()) + "px";
    171         if (scroll)
    172           scrollIntoView(left, top, left + node.offsetWidth, top + node.offsetHeight);
    173       },
    174 
    175       lineCount: function() {return lines.length;},
    176       getCursor: function(start) {
    177         if (start == null) start = sel.inverted;
    178         return copyPos(start ? sel.from : sel.to);
    179       },
    180       somethingSelected: function() {return !posEq(sel.from, sel.to);},
    181       setCursor: operation(function(line, ch) {
    182         if (ch == null && typeof line.line == "number") setCursor(line.line, line.ch);
    183         else setCursor(line, ch);
    184       }),
    185       setSelection: operation(function(from, to) {setSelection(clipPos(from), clipPos(to || from));}),
    186       getLine: function(line) {if (isLine(line)) return lines[line].text;},
    187       setLine: operation(function(line, text) {
    188         if (isLine(line)) replaceRange(text, {line: line, ch: 0}, {line: line, ch: lines[line].text.length});
    189       }),
    190       removeLine: operation(function(line) {
    191         if (isLine(line)) replaceRange("", {line: line, ch: 0}, clipPos({line: line+1, ch: 0}));
    192       }),
    193       replaceRange: operation(replaceRange),
    194       getRange: function(from, to) {return getRange(clipPos(from), clipPos(to));},
    195 
    196       operation: function(f){return operation(f)();},
    197       refresh: function(){updateDisplay(true);},
    198       getInputField: function(){return input;},
    199       getWrapperElement: function(){return wrapper;},
    200       getScrollerElement: function(){return scroller;}
    201     };
    202 
    203     function setValue(code) {
    204       history = null;
    205       var top = {line: 0, ch: 0};
    206       updateLines(top, {line: lines.length - 1, ch: lines[lines.length-1].text.length},
    207                   splitLines(code), top, top);
    208       history = new History();
    209     }
    210     function getValue(code) {
    211       var text = [];
    212       for (var i = 0, l = lines.length; i < l; ++i)
    213         text.push(lines[i].text);
    214       return text.join("\n");
    215     }
    216 
    217     function onMouseDown(e) {
    218       var ld = lastDoubleClick; lastDoubleClick = null;
    219       // First, see if this is a click in the gutter
    220       for (var n = e.target(); n != wrapper; n = n.parentNode)
    221         if (n.parentNode == gutterText) {
    222           if (options.onGutterClick)
    223             options.onGutterClick(instance, indexOf(gutterText.childNodes, n) + showingFrom);
    224           return e.stop();
     634      } else {
     635        span$1.from += offset
     636        if (sameLine) { (first || (first = [])).push(span$1) }
     637      }
     638    }
     639  }
     640  // Make sure we didn't create any zero-length spans
     641  if (first) { first = clearEmptySpans(first) }
     642  if (last && last != first) { last = clearEmptySpans(last) }
     643
     644  var newMarkers = [first]
     645  if (!sameLine) {
     646    // Fill gap with whole-line-spans
     647    var gap = change.text.length - 2, gapMarkers
     648    if (gap > 0 && first)
     649      { for (var i$2 = 0; i$2 < first.length; ++i$2)
     650        { if (first[i$2].to == null)
     651          { (gapMarkers || (gapMarkers = [])).push(new MarkedSpan(first[i$2].marker, null, null)) } } }
     652    for (var i$3 = 0; i$3 < gap; ++i$3)
     653      { newMarkers.push(gapMarkers) }
     654    newMarkers.push(last)
     655  }
     656  return newMarkers
     657}
     658
     659// Remove spans that are empty and don't have a clearWhenEmpty
     660// option of false.
     661function clearEmptySpans(spans) {
     662  for (var i = 0; i < spans.length; ++i) {
     663    var span = spans[i]
     664    if (span.from != null && span.from == span.to && span.marker.clearWhenEmpty !== false)
     665      { spans.splice(i--, 1) }
     666  }
     667  if (!spans.length) { return null }
     668  return spans
     669}
     670
     671// Used to 'clip' out readOnly ranges when making a change.
     672function removeReadOnlyRanges(doc, from, to) {
     673  var markers = null
     674  doc.iter(from.line, to.line + 1, function (line) {
     675    if (line.markedSpans) { for (var i = 0; i < line.markedSpans.length; ++i) {
     676      var mark = line.markedSpans[i].marker
     677      if (mark.readOnly && (!markers || indexOf(markers, mark) == -1))
     678        { (markers || (markers = [])).push(mark) }
     679    } }
     680  })
     681  if (!markers) { return null }
     682  var parts = [{from: from, to: to}]
     683  for (var i = 0; i < markers.length; ++i) {
     684    var mk = markers[i], m = mk.find(0)
     685    for (var j = 0; j < parts.length; ++j) {
     686      var p = parts[j]
     687      if (cmp(p.to, m.from) < 0 || cmp(p.from, m.to) > 0) { continue }
     688      var newParts = [j, 1], dfrom = cmp(p.from, m.from), dto = cmp(p.to, m.to)
     689      if (dfrom < 0 || !mk.inclusiveLeft && !dfrom)
     690        { newParts.push({from: p.from, to: m.from}) }
     691      if (dto > 0 || !mk.inclusiveRight && !dto)
     692        { newParts.push({from: m.to, to: p.to}) }
     693      parts.splice.apply(parts, newParts)
     694      j += newParts.length - 3
     695    }
     696  }
     697  return parts
     698}
     699
     700// Connect or disconnect spans from a line.
     701function detachMarkedSpans(line) {
     702  var spans = line.markedSpans
     703  if (!spans) { return }
     704  for (var i = 0; i < spans.length; ++i)
     705    { spans[i].marker.detachLine(line) }
     706  line.markedSpans = null
     707}
     708function attachMarkedSpans(line, spans) {
     709  if (!spans) { return }
     710  for (var i = 0; i < spans.length; ++i)
     711    { spans[i].marker.attachLine(line) }
     712  line.markedSpans = spans
     713}
     714
     715// Helpers used when computing which overlapping collapsed span
     716// counts as the larger one.
     717function extraLeft(marker) { return marker.inclusiveLeft ? -1 : 0 }
     718function extraRight(marker) { return marker.inclusiveRight ? 1 : 0 }
     719
     720// Returns a number indicating which of two overlapping collapsed
     721// spans is larger (and thus includes the other). Falls back to
     722// comparing ids when the spans cover exactly the same range.
     723function compareCollapsedMarkers(a, b) {
     724  var lenDiff = a.lines.length - b.lines.length
     725  if (lenDiff != 0) { return lenDiff }
     726  var aPos = a.find(), bPos = b.find()
     727  var fromCmp = cmp(aPos.from, bPos.from) || extraLeft(a) - extraLeft(b)
     728  if (fromCmp) { return -fromCmp }
     729  var toCmp = cmp(aPos.to, bPos.to) || extraRight(a) - extraRight(b)
     730  if (toCmp) { return toCmp }
     731  return b.id - a.id
     732}
     733
     734// Find out whether a line ends or starts in a collapsed span. If
     735// so, return the marker for that span.
     736function collapsedSpanAtSide(line, start) {
     737  var sps = sawCollapsedSpans && line.markedSpans, found
     738  if (sps) { for (var sp = (void 0), i = 0; i < sps.length; ++i) {
     739    sp = sps[i]
     740    if (sp.marker.collapsed && (start ? sp.from : sp.to) == null &&
     741        (!found || compareCollapsedMarkers(found, sp.marker) < 0))
     742      { found = sp.marker }
     743  } }
     744  return found
     745}
     746function collapsedSpanAtStart(line) { return collapsedSpanAtSide(line, true) }
     747function collapsedSpanAtEnd(line) { return collapsedSpanAtSide(line, false) }
     748
     749function collapsedSpanAround(line, ch) {
     750  var sps = sawCollapsedSpans && line.markedSpans, found
     751  if (sps) { for (var i = 0; i < sps.length; ++i) {
     752    var sp = sps[i]
     753    if (sp.marker.collapsed && (sp.from == null || sp.from < ch) && (sp.to == null || sp.to > ch) &&
     754        (!found || compareCollapsedMarkers(found, sp.marker) < 0)) { found = sp.marker }
     755  } }
     756  return found
     757}
     758
     759// Test whether there exists a collapsed span that partially
     760// overlaps (covers the start or end, but not both) of a new span.
     761// Such overlap is not allowed.
     762function conflictingCollapsedRange(doc, lineNo, from, to, marker) {
     763  var line = getLine(doc, lineNo)
     764  var sps = sawCollapsedSpans && line.markedSpans
     765  if (sps) { for (var i = 0; i < sps.length; ++i) {
     766    var sp = sps[i]
     767    if (!sp.marker.collapsed) { continue }
     768    var found = sp.marker.find(0)
     769    var fromCmp = cmp(found.from, from) || extraLeft(sp.marker) - extraLeft(marker)
     770    var toCmp = cmp(found.to, to) || extraRight(sp.marker) - extraRight(marker)
     771    if (fromCmp >= 0 && toCmp <= 0 || fromCmp <= 0 && toCmp >= 0) { continue }
     772    if (fromCmp <= 0 && (sp.marker.inclusiveRight && marker.inclusiveLeft ? cmp(found.to, from) >= 0 : cmp(found.to, from) > 0) ||
     773        fromCmp >= 0 && (sp.marker.inclusiveRight && marker.inclusiveLeft ? cmp(found.from, to) <= 0 : cmp(found.from, to) < 0))
     774      { return true }
     775  } }
     776}
     777
     778// A visual line is a line as drawn on the screen. Folding, for
     779// example, can cause multiple logical lines to appear on the same
     780// visual line. This finds the start of the visual line that the
     781// given line is part of (usually that is the line itself).
     782function visualLine(line) {
     783  var merged
     784  while (merged = collapsedSpanAtStart(line))
     785    { line = merged.find(-1, true).line }
     786  return line
     787}
     788
     789function visualLineEnd(line) {
     790  var merged
     791  while (merged = collapsedSpanAtEnd(line))
     792    { line = merged.find(1, true).line }
     793  return line
     794}
     795
     796// Returns an array of logical lines that continue the visual line
     797// started by the argument, or undefined if there are no such lines.
     798function visualLineContinued(line) {
     799  var merged, lines
     800  while (merged = collapsedSpanAtEnd(line)) {
     801    line = merged.find(1, true).line
     802    ;(lines || (lines = [])).push(line)
     803  }
     804  return lines
     805}
     806
     807// Get the line number of the start of the visual line that the
     808// given line number is part of.
     809function visualLineNo(doc, lineN) {
     810  var line = getLine(doc, lineN), vis = visualLine(line)
     811  if (line == vis) { return lineN }
     812  return lineNo(vis)
     813}
     814
     815// Get the line number of the start of the next visual line after
     816// the given line.
     817function visualLineEndNo(doc, lineN) {
     818  if (lineN > doc.lastLine()) { return lineN }
     819  var line = getLine(doc, lineN), merged
     820  if (!lineIsHidden(doc, line)) { return lineN }
     821  while (merged = collapsedSpanAtEnd(line))
     822    { line = merged.find(1, true).line }
     823  return lineNo(line) + 1
     824}
     825
     826// Compute whether a line is hidden. Lines count as hidden when they
     827// are part of a visual line that starts with another line, or when
     828// they are entirely covered by collapsed, non-widget span.
     829function lineIsHidden(doc, line) {
     830  var sps = sawCollapsedSpans && line.markedSpans
     831  if (sps) { for (var sp = (void 0), i = 0; i < sps.length; ++i) {
     832    sp = sps[i]
     833    if (!sp.marker.collapsed) { continue }
     834    if (sp.from == null) { return true }
     835    if (sp.marker.widgetNode) { continue }
     836    if (sp.from == 0 && sp.marker.inclusiveLeft && lineIsHiddenInner(doc, line, sp))
     837      { return true }
     838  } }
     839}
     840function lineIsHiddenInner(doc, line, span) {
     841  if (span.to == null) {
     842    var end = span.marker.find(1, true)
     843    return lineIsHiddenInner(doc, end.line, getMarkedSpanFor(end.line.markedSpans, span.marker))
     844  }
     845  if (span.marker.inclusiveRight && span.to == line.text.length)
     846    { return true }
     847  for (var sp = (void 0), i = 0; i < line.markedSpans.length; ++i) {
     848    sp = line.markedSpans[i]
     849    if (sp.marker.collapsed && !sp.marker.widgetNode && sp.from == span.to &&
     850        (sp.to == null || sp.to != span.from) &&
     851        (sp.marker.inclusiveLeft || span.marker.inclusiveRight) &&
     852        lineIsHiddenInner(doc, line, sp)) { return true }
     853  }
     854}
     855
     856// Find the height above the given line.
     857function heightAtLine(lineObj) {
     858  lineObj = visualLine(lineObj)
     859
     860  var h = 0, chunk = lineObj.parent
     861  for (var i = 0; i < chunk.lines.length; ++i) {
     862    var line = chunk.lines[i]
     863    if (line == lineObj) { break }
     864    else { h += line.height }
     865  }
     866  for (var p = chunk.parent; p; chunk = p, p = chunk.parent) {
     867    for (var i$1 = 0; i$1 < p.children.length; ++i$1) {
     868      var cur = p.children[i$1]
     869      if (cur == chunk) { break }
     870      else { h += cur.height }
     871    }
     872  }
     873  return h
     874}
     875
     876// Compute the character length of a line, taking into account
     877// collapsed ranges (see markText) that might hide parts, and join
     878// other lines onto it.
     879function lineLength(line) {
     880  if (line.height == 0) { return 0 }
     881  var len = line.text.length, merged, cur = line
     882  while (merged = collapsedSpanAtStart(cur)) {
     883    var found = merged.find(0, true)
     884    cur = found.from.line
     885    len += found.from.ch - found.to.ch
     886  }
     887  cur = line
     888  while (merged = collapsedSpanAtEnd(cur)) {
     889    var found$1 = merged.find(0, true)
     890    len -= cur.text.length - found$1.from.ch
     891    cur = found$1.to.line
     892    len += cur.text.length - found$1.to.ch
     893  }
     894  return len
     895}
     896
     897// Find the longest line in the document.
     898function findMaxLine(cm) {
     899  var d = cm.display, doc = cm.doc
     900  d.maxLine = getLine(doc, doc.first)
     901  d.maxLineLength = lineLength(d.maxLine)
     902  d.maxLineChanged = true
     903  doc.iter(function (line) {
     904    var len = lineLength(line)
     905    if (len > d.maxLineLength) {
     906      d.maxLineLength = len
     907      d.maxLine = line
     908    }
     909  })
     910}
     911
     912// BIDI HELPERS
     913
     914function iterateBidiSections(order, from, to, f) {
     915  if (!order) { return f(from, to, "ltr", 0) }
     916  var found = false
     917  for (var i = 0; i < order.length; ++i) {
     918    var part = order[i]
     919    if (part.from < to && part.to > from || from == to && part.to == from) {
     920      f(Math.max(part.from, from), Math.min(part.to, to), part.level == 1 ? "rtl" : "ltr", i)
     921      found = true
     922    }
     923  }
     924  if (!found) { f(from, to, "ltr") }
     925}
     926
     927var bidiOther = null
     928function getBidiPartAt(order, ch, sticky) {
     929  var found
     930  bidiOther = null
     931  for (var i = 0; i < order.length; ++i) {
     932    var cur = order[i]
     933    if (cur.from < ch && cur.to > ch) { return i }
     934    if (cur.to == ch) {
     935      if (cur.from != cur.to && sticky == "before") { found = i }
     936      else { bidiOther = i }
     937    }
     938    if (cur.from == ch) {
     939      if (cur.from != cur.to && sticky != "before") { found = i }
     940      else { bidiOther = i }
     941    }
     942  }
     943  return found != null ? found : bidiOther
     944}
     945
     946// Bidirectional ordering algorithm
     947// See http://unicode.org/reports/tr9/tr9-13.html for the algorithm
     948// that this (partially) implements.
     949
     950// One-char codes used for character types:
     951// L (L):   Left-to-Right
     952// R (R):   Right-to-Left
     953// r (AL):  Right-to-Left Arabic
     954// 1 (EN):  European Number
     955// + (ES):  European Number Separator
     956// % (ET):  European Number Terminator
     957// n (AN):  Arabic Number
     958// , (CS):  Common Number Separator
     959// m (NSM): Non-Spacing Mark
     960// b (BN):  Boundary Neutral
     961// s (B):   Paragraph Separator
     962// t (S):   Segment Separator
     963// w (WS):  Whitespace
     964// N (ON):  Other Neutrals
     965
     966// Returns null if characters are ordered as they appear
     967// (left-to-right), or an array of sections ({from, to, level}
     968// objects) in the order in which they occur visually.
     969var bidiOrdering = (function() {
     970  // Character types for codepoints 0 to 0xff
     971  var lowTypes = "bbbbbbbbbtstwsbbbbbbbbbbbbbbssstwNN%%%NNNNNN,N,N1111111111NNNNNNNLLLLLLLLLLLLLLLLLLLLLLLLLLNNNNNNLLLLLLLLLLLLLLLLLLLLLLLLLLNNNNbbbbbbsbbbbbbbbbbbbbbbbbbbbbbbbbb,N%%%%NNNNLNNNNN%%11NLNNN1LNNNNNLLLLLLLLLLLLLLLLLLLLLLLNLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLN"
     972  // Character types for codepoints 0x600 to 0x6f9
     973  var arabicTypes = "nnnnnnNNr%%r,rNNmmmmmmmmmmmrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrmmmmmmmmmmmmmmmmmmmmmnnnnnnnnnn%nnrrrmrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrmmmmmmmnNmmmmmmrrmmNmmmmrr1111111111"
     974  function charType(code) {
     975    if (code <= 0xf7) { return lowTypes.charAt(code) }
     976    else if (0x590 <= code && code <= 0x5f4) { return "R" }
     977    else if (0x600 <= code && code <= 0x6f9) { return arabicTypes.charAt(code - 0x600) }
     978    else if (0x6ee <= code && code <= 0x8ac) { return "r" }
     979    else if (0x2000 <= code && code <= 0x200b) { return "w" }
     980    else if (code == 0x200c) { return "b" }
     981    else { return "L" }
     982  }
     983
     984  var bidiRE = /[\u0590-\u05f4\u0600-\u06ff\u0700-\u08ac]/
     985  var isNeutral = /[stwN]/, isStrong = /[LRr]/, countsAsLeft = /[Lb1n]/, countsAsNum = /[1n]/
     986
     987  function BidiSpan(level, from, to) {
     988    this.level = level
     989    this.from = from; this.to = to
     990  }
     991
     992  return function(str, direction) {
     993    var outerType = direction == "ltr" ? "L" : "R"
     994
     995    if (str.length == 0 || direction == "ltr" && !bidiRE.test(str)) { return false }
     996    var len = str.length, types = []
     997    for (var i = 0; i < len; ++i)
     998      { types.push(charType(str.charCodeAt(i))) }
     999
     1000    // W1. Examine each non-spacing mark (NSM) in the level run, and
     1001    // change the type of the NSM to the type of the previous
     1002    // character. If the NSM is at the start of the level run, it will
     1003    // get the type of sor.
     1004    for (var i$1 = 0, prev = outerType; i$1 < len; ++i$1) {
     1005      var type = types[i$1]
     1006      if (type == "m") { types[i$1] = prev }
     1007      else { prev = type }
     1008    }
     1009
     1010    // W2. Search backwards from each instance of a European number
     1011    // until the first strong type (R, L, AL, or sor) is found. If an
     1012    // AL is found, change the type of the European number to Arabic
     1013    // number.
     1014    // W3. Change all ALs to R.
     1015    for (var i$2 = 0, cur = outerType; i$2 < len; ++i$2) {
     1016      var type$1 = types[i$2]
     1017      if (type$1 == "1" && cur == "r") { types[i$2] = "n" }
     1018      else if (isStrong.test(type$1)) { cur = type$1; if (type$1 == "r") { types[i$2] = "R" } }
     1019    }
     1020
     1021    // W4. A single European separator between two European numbers
     1022    // changes to a European number. A single common separator between
     1023    // two numbers of the same type changes to that type.
     1024    for (var i$3 = 1, prev$1 = types[0]; i$3 < len - 1; ++i$3) {
     1025      var type$2 = types[i$3]
     1026      if (type$2 == "+" && prev$1 == "1" && types[i$3+1] == "1") { types[i$3] = "1" }
     1027      else if (type$2 == "," && prev$1 == types[i$3+1] &&
     1028               (prev$1 == "1" || prev$1 == "n")) { types[i$3] = prev$1 }
     1029      prev$1 = type$2
     1030    }
     1031
     1032    // W5. A sequence of European terminators adjacent to European
     1033    // numbers changes to all European numbers.
     1034    // W6. Otherwise, separators and terminators change to Other
     1035    // Neutral.
     1036    for (var i$4 = 0; i$4 < len; ++i$4) {
     1037      var type$3 = types[i$4]
     1038      if (type$3 == ",") { types[i$4] = "N" }
     1039      else if (type$3 == "%") {
     1040        var end = (void 0)
     1041        for (end = i$4 + 1; end < len && types[end] == "%"; ++end) {}
     1042        var replace = (i$4 && types[i$4-1] == "!") || (end < len && types[end] == "1") ? "1" : "N"
     1043        for (var j = i$4; j < end; ++j) { types[j] = replace }
     1044        i$4 = end - 1
     1045      }
     1046    }
     1047
     1048    // W7. Search backwards from each instance of a European number
     1049    // until the first strong type (R, L, or sor) is found. If an L is
     1050    // found, then change the type of the European number to L.
     1051    for (var i$5 = 0, cur$1 = outerType; i$5 < len; ++i$5) {
     1052      var type$4 = types[i$5]
     1053      if (cur$1 == "L" && type$4 == "1") { types[i$5] = "L" }
     1054      else if (isStrong.test(type$4)) { cur$1 = type$4 }
     1055    }
     1056
     1057    // N1. A sequence of neutrals takes the direction of the
     1058    // surrounding strong text if the text on both sides has the same
     1059    // direction. European and Arabic numbers act as if they were R in
     1060    // terms of their influence on neutrals. Start-of-level-run (sor)
     1061    // and end-of-level-run (eor) are used at level run boundaries.
     1062    // N2. Any remaining neutrals take the embedding direction.
     1063    for (var i$6 = 0; i$6 < len; ++i$6) {
     1064      if (isNeutral.test(types[i$6])) {
     1065        var end$1 = (void 0)
     1066        for (end$1 = i$6 + 1; end$1 < len && isNeutral.test(types[end$1]); ++end$1) {}
     1067        var before = (i$6 ? types[i$6-1] : outerType) == "L"
     1068        var after = (end$1 < len ? types[end$1] : outerType) == "L"
     1069        var replace$1 = before == after ? (before ? "L" : "R") : outerType
     1070        for (var j$1 = i$6; j$1 < end$1; ++j$1) { types[j$1] = replace$1 }
     1071        i$6 = end$1 - 1
     1072      }
     1073    }
     1074
     1075    // Here we depart from the documented algorithm, in order to avoid
     1076    // building up an actual levels array. Since there are only three
     1077    // levels (0, 1, 2) in an implementation that doesn't take
     1078    // explicit embedding into account, we can build up the order on
     1079    // the fly, without following the level-based algorithm.
     1080    var order = [], m
     1081    for (var i$7 = 0; i$7 < len;) {
     1082      if (countsAsLeft.test(types[i$7])) {
     1083        var start = i$7
     1084        for (++i$7; i$7 < len && countsAsLeft.test(types[i$7]); ++i$7) {}
     1085        order.push(new BidiSpan(0, start, i$7))
     1086      } else {
     1087        var pos = i$7, at = order.length
     1088        for (++i$7; i$7 < len && types[i$7] != "L"; ++i$7) {}
     1089        for (var j$2 = pos; j$2 < i$7;) {
     1090          if (countsAsNum.test(types[j$2])) {
     1091            if (pos < j$2) { order.splice(at, 0, new BidiSpan(1, pos, j$2)) }
     1092            var nstart = j$2
     1093            for (++j$2; j$2 < i$7 && countsAsNum.test(types[j$2]); ++j$2) {}
     1094            order.splice(at, 0, new BidiSpan(2, nstart, j$2))
     1095            pos = j$2
     1096          } else { ++j$2 }
    2251097        }
    226 
    227       var start = posFromMouse(e);
    228       switch (e.button()) {
    229       case 3:
    230         if (gecko && !mac) onContextMenu(e);
    231         return;
    232       case 2:
    233         if (start) setCursor(start.line, start.ch, true);
    234         return;
     1098        if (pos < i$7) { order.splice(at, 0, new BidiSpan(1, pos, i$7)) }
    2351099      }
    236       // For button 1, if it was clicked inside the editor
    237       // (posFromMouse returning non-null), we have to adjust the
    238       // selection.
    239       if (!start) {if (e.target() == scroller) e.stop(); return;}
    240 
    241       if (!focused) onFocus();
    242       e.stop();
    243       if (ld && +new Date - ld < 400) return selectLine(start.line);
    244 
    245       setCursor(start.line, start.ch, true);
    246       var last = start, going;
    247       // And then we have to see if it's a drag event, in which case
    248       // the dragged-over text must be selected.
    249       function end() {
    250         focusInput();
    251         updateInput = true;
    252         move(); up();
     1100    }
     1101    if (direction == "ltr") {
     1102      if (order[0].level == 1 && (m = str.match(/^\s+/))) {
     1103        order[0].from = m[0].length
     1104        order.unshift(new BidiSpan(0, 0, m[0].length))
    2531105      }
    254       function extend(e) {
    255         var cur = posFromMouse(e, true);
    256         if (cur && !posEq(cur, last)) {
    257           if (!focused) onFocus();
    258           last = cur;
    259           setSelectionUser(start, cur);
    260           updateInput = false;
    261           var visible = visibleLines();
    262           if (cur.line >= visible.to || cur.line < visible.from)
    263             going = setTimeout(operation(function(){extend(e);}), 150);
     1106      if (lst(order).level == 1 && (m = str.match(/\s+$/))) {
     1107        lst(order).to -= m[0].length
     1108        order.push(new BidiSpan(0, len - m[0].length, len))
     1109      }
     1110    }
     1111
     1112    return direction == "rtl" ? order.reverse() : order
     1113  }
     1114})()
     1115
     1116// Get the bidi ordering for the given line (and cache it). Returns
     1117// false for lines that are fully left-to-right, and an array of
     1118// BidiSpan objects otherwise.
     1119function getOrder(line, direction) {
     1120  var order = line.order
     1121  if (order == null) { order = line.order = bidiOrdering(line.text, direction) }
     1122  return order
     1123}
     1124
     1125// EVENT HANDLING
     1126
     1127// Lightweight event framework. on/off also work on DOM nodes,
     1128// registering native DOM handlers.
     1129
     1130var noHandlers = []
     1131
     1132var on = function(emitter, type, f) {
     1133  if (emitter.addEventListener) {
     1134    emitter.addEventListener(type, f, false)
     1135  } else if (emitter.attachEvent) {
     1136    emitter.attachEvent("on" + type, f)
     1137  } else {
     1138    var map = emitter._handlers || (emitter._handlers = {})
     1139    map[type] = (map[type] || noHandlers).concat(f)
     1140  }
     1141}
     1142
     1143function getHandlers(emitter, type) {
     1144  return emitter._handlers && emitter._handlers[type] || noHandlers
     1145}
     1146
     1147function off(emitter, type, f) {
     1148  if (emitter.removeEventListener) {
     1149    emitter.removeEventListener(type, f, false)
     1150  } else if (emitter.detachEvent) {
     1151    emitter.detachEvent("on" + type, f)
     1152  } else {
     1153    var map = emitter._handlers, arr = map && map[type]
     1154    if (arr) {
     1155      var index = indexOf(arr, f)
     1156      if (index > -1)
     1157        { map[type] = arr.slice(0, index).concat(arr.slice(index + 1)) }
     1158    }
     1159  }
     1160}
     1161
     1162function signal(emitter, type /*, values...*/) {
     1163  var handlers = getHandlers(emitter, type)
     1164  if (!handlers.length) { return }
     1165  var args = Array.prototype.slice.call(arguments, 2)
     1166  for (var i = 0; i < handlers.length; ++i) { handlers[i].apply(null, args) }
     1167}
     1168
     1169// The DOM events that CodeMirror handles can be overridden by
     1170// registering a (non-DOM) handler on the editor for the event name,
     1171// and preventDefault-ing the event in that handler.
     1172function signalDOMEvent(cm, e, override) {
     1173  if (typeof e == "string")
     1174    { e = {type: e, preventDefault: function() { this.defaultPrevented = true }} }
     1175  signal(cm, override || e.type, cm, e)
     1176  return e_defaultPrevented(e) || e.codemirrorIgnore
     1177}
     1178
     1179function signalCursorActivity(cm) {
     1180  var arr = cm._handlers && cm._handlers.cursorActivity
     1181  if (!arr) { return }
     1182  var set = cm.curOp.cursorActivityHandlers || (cm.curOp.cursorActivityHandlers = [])
     1183  for (var i = 0; i < arr.length; ++i) { if (indexOf(set, arr[i]) == -1)
     1184    { set.push(arr[i]) } }
     1185}
     1186
     1187function hasHandler(emitter, type) {
     1188  return getHandlers(emitter, type).length > 0
     1189}
     1190
     1191// Add on and off methods to a constructor's prototype, to make
     1192// registering events on such objects more convenient.
     1193function eventMixin(ctor) {
     1194  ctor.prototype.on = function(type, f) {on(this, type, f)}
     1195  ctor.prototype.off = function(type, f) {off(this, type, f)}
     1196}
     1197
     1198// Due to the fact that we still support jurassic IE versions, some
     1199// compatibility wrappers are needed.
     1200
     1201function e_preventDefault(e) {
     1202  if (e.preventDefault) { e.preventDefault() }
     1203  else { e.returnValue = false }
     1204}
     1205function e_stopPropagation(e) {
     1206  if (e.stopPropagation) { e.stopPropagation() }
     1207  else { e.cancelBubble = true }
     1208}
     1209function e_defaultPrevented(e) {
     1210  return e.defaultPrevented != null ? e.defaultPrevented : e.returnValue == false
     1211}
     1212function e_stop(e) {e_preventDefault(e); e_stopPropagation(e)}
     1213
     1214function e_target(e) {return e.target || e.srcElement}
     1215function e_button(e) {
     1216  var b = e.which
     1217  if (b == null) {
     1218    if (e.button & 1) { b = 1 }
     1219    else if (e.button & 2) { b = 3 }
     1220    else if (e.button & 4) { b = 2 }
     1221  }
     1222  if (mac && e.ctrlKey && b == 1) { b = 3 }
     1223  return b
     1224}
     1225
     1226// Detect drag-and-drop
     1227var dragAndDrop = function() {
     1228  // There is *some* kind of drag-and-drop support in IE6-8, but I
     1229  // couldn't get it to work yet.
     1230  if (ie && ie_version < 9) { return false }
     1231  var div = elt('div')
     1232  return "draggable" in div || "dragDrop" in div
     1233}()
     1234
     1235var zwspSupported
     1236function zeroWidthElement(measure) {
     1237  if (zwspSupported == null) {
     1238    var test = elt("span", "\u200b")
     1239    removeChildrenAndAdd(measure, elt("span", [test, document.createTextNode("x")]))
     1240    if (measure.firstChild.offsetHeight != 0)
     1241      { zwspSupported = test.offsetWidth <= 1 && test.offsetHeight > 2 && !(ie && ie_version < 8) }
     1242  }
     1243  var node = zwspSupported ? elt("span", "\u200b") :
     1244    elt("span", "\u00a0", null, "display: inline-block; width: 1px; margin-right: -1px")
     1245  node.setAttribute("cm-text", "")
     1246  return node
     1247}
     1248
     1249// Feature-detect IE's crummy client rect reporting for bidi text
     1250var badBidiRects
     1251function hasBadBidiRects(measure) {
     1252  if (badBidiRects != null) { return badBidiRects }
     1253  var txt = removeChildrenAndAdd(measure, document.createTextNode("A\u062eA"))
     1254  var r0 = range(txt, 0, 1).getBoundingClientRect()
     1255  var r1 = range(txt, 1, 2).getBoundingClientRect()
     1256  removeChildren(measure)
     1257  if (!r0 || r0.left == r0.right) { return false } // Safari returns null in some cases (#2780)
     1258  return badBidiRects = (r1.right - r0.right < 3)
     1259}
     1260
     1261// See if "".split is the broken IE version, if so, provide an
     1262// alternative way to split lines.
     1263var splitLinesAuto = "\n\nb".split(/\n/).length != 3 ? function (string) {
     1264  var pos = 0, result = [], l = string.length
     1265  while (pos <= l) {
     1266    var nl = string.indexOf("\n", pos)
     1267    if (nl == -1) { nl = string.length }
     1268    var line = string.slice(pos, string.charAt(nl - 1) == "\r" ? nl - 1 : nl)
     1269    var rt = line.indexOf("\r")
     1270    if (rt != -1) {
     1271      result.push(line.slice(0, rt))
     1272      pos += rt + 1
     1273    } else {
     1274      result.push(line)
     1275      pos = nl + 1
     1276    }
     1277  }
     1278  return result
     1279} : function (string) { return string.split(/\r\n?|\n/); }
     1280
     1281var hasSelection = window.getSelection ? function (te) {
     1282  try { return te.selectionStart != te.selectionEnd }
     1283  catch(e) { return false }
     1284} : function (te) {
     1285  var range
     1286  try {range = te.ownerDocument.selection.createRange()}
     1287  catch(e) {}
     1288  if (!range || range.parentElement() != te) { return false }
     1289  return range.compareEndPoints("StartToEnd", range) != 0
     1290}
     1291
     1292var hasCopyEvent = (function () {
     1293  var e = elt("div")
     1294  if ("oncopy" in e) { return true }
     1295  e.setAttribute("oncopy", "return;")
     1296  return typeof e.oncopy == "function"
     1297})()
     1298
     1299var badZoomedRects = null
     1300function hasBadZoomedRects(measure) {
     1301  if (badZoomedRects != null) { return badZoomedRects }
     1302  var node = removeChildrenAndAdd(measure, elt("span", "x"))
     1303  var normal = node.getBoundingClientRect()
     1304  var fromRange = range(node, 0, 1).getBoundingClientRect()
     1305  return badZoomedRects = Math.abs(normal.left - fromRange.left) > 1
     1306}
     1307
     1308var modes = {};
     1309var mimeModes = {};
     1310// Extra arguments are stored as the mode's dependencies, which is
     1311// used by (legacy) mechanisms like loadmode.js to automatically
     1312// load a mode. (Preferred mechanism is the require/define calls.)
     1313function defineMode(name, mode) {
     1314  if (arguments.length > 2)
     1315    { mode.dependencies = Array.prototype.slice.call(arguments, 2) }
     1316  modes[name] = mode
     1317}
     1318
     1319function defineMIME(mime, spec) {
     1320  mimeModes[mime] = spec
     1321}
     1322
     1323// Given a MIME type, a {name, ...options} config object, or a name
     1324// string, return a mode config object.
     1325function resolveMode(spec) {
     1326  if (typeof spec == "string" && mimeModes.hasOwnProperty(spec)) {
     1327    spec = mimeModes[spec]
     1328  } else if (spec && typeof spec.name == "string" && mimeModes.hasOwnProperty(spec.name)) {
     1329    var found = mimeModes[spec.name]
     1330    if (typeof found == "string") { found = {name: found} }
     1331    spec = createObj(found, spec)
     1332    spec.name = found.name
     1333  } else if (typeof spec == "string" && /^[\w\-]+\/[\w\-]+\+xml$/.test(spec)) {
     1334    return resolveMode("application/xml")
     1335  } else if (typeof spec == "string" && /^[\w\-]+\/[\w\-]+\+json$/.test(spec)) {
     1336    return resolveMode("application/json")
     1337  }
     1338  if (typeof spec == "string") { return {name: spec} }
     1339  else { return spec || {name: "null"} }
     1340}
     1341
     1342// Given a mode spec (anything that resolveMode accepts), find and
     1343// initialize an actual mode object.
     1344function getMode(options, spec) {
     1345  spec = resolveMode(spec)
     1346  var mfactory = modes[spec.name]
     1347  if (!mfactory) { return getMode(options, "text/plain") }
     1348  var modeObj = mfactory(options, spec)
     1349  if (modeExtensions.hasOwnProperty(spec.name)) {
     1350    var exts = modeExtensions[spec.name]
     1351    for (var prop in exts) {
     1352      if (!exts.hasOwnProperty(prop)) { continue }
     1353      if (modeObj.hasOwnProperty(prop)) { modeObj["_" + prop] = modeObj[prop] }
     1354      modeObj[prop] = exts[prop]
     1355    }
     1356  }
     1357  modeObj.name = spec.name
     1358  if (spec.helperType) { modeObj.helperType = spec.helperType }
     1359  if (spec.modeProps) { for (var prop$1 in spec.modeProps)
     1360    { modeObj[prop$1] = spec.modeProps[prop$1] } }
     1361
     1362  return modeObj
     1363}
     1364
     1365// This can be used to attach properties to mode objects from
     1366// outside the actual mode definition.
     1367var modeExtensions = {}
     1368function extendMode(mode, properties) {
     1369  var exts = modeExtensions.hasOwnProperty(mode) ? modeExtensions[mode] : (modeExtensions[mode] = {})
     1370  copyObj(properties, exts)
     1371}
     1372
     1373function copyState(mode, state) {
     1374  if (state === true) { return state }
     1375  if (mode.copyState) { return mode.copyState(state) }
     1376  var nstate = {}
     1377  for (var n in state) {
     1378    var val = state[n]
     1379    if (val instanceof Array) { val = val.concat([]) }
     1380    nstate[n] = val
     1381  }
     1382  return nstate
     1383}
     1384
     1385// Given a mode and a state (for that mode), find the inner mode and
     1386// state at the position that the state refers to.
     1387function innerMode(mode, state) {
     1388  var info
     1389  while (mode.innerMode) {
     1390    info = mode.innerMode(state)
     1391    if (!info || info.mode == mode) { break }
     1392    state = info.state
     1393    mode = info.mode
     1394  }
     1395  return info || {mode: mode, state: state}
     1396}
     1397
     1398function startState(mode, a1, a2) {
     1399  return mode.startState ? mode.startState(a1, a2) : true
     1400}
     1401
     1402// STRING STREAM
     1403
     1404// Fed to the mode parsers, provides helper functions to make
     1405// parsers more succinct.
     1406
     1407var StringStream = function(string, tabSize, lineOracle) {
     1408  this.pos = this.start = 0
     1409  this.string = string
     1410  this.tabSize = tabSize || 8
     1411  this.lastColumnPos = this.lastColumnValue = 0
     1412  this.lineStart = 0
     1413  this.lineOracle = lineOracle
     1414};
     1415
     1416StringStream.prototype.eol = function () {return this.pos >= this.string.length};
     1417StringStream.prototype.sol = function () {return this.pos == this.lineStart};
     1418StringStream.prototype.peek = function () {return this.string.charAt(this.pos) || undefined};
     1419StringStream.prototype.next = function () {
     1420  if (this.pos < this.string.length)
     1421    { return this.string.charAt(this.pos++) }
     1422};
     1423StringStream.prototype.eat = function (match) {
     1424  var ch = this.string.charAt(this.pos)
     1425  var ok
     1426  if (typeof match == "string") { ok = ch == match }
     1427  else { ok = ch && (match.test ? match.test(ch) : match(ch)) }
     1428  if (ok) {++this.pos; return ch}
     1429};
     1430StringStream.prototype.eatWhile = function (match) {
     1431  var start = this.pos
     1432  while (this.eat(match)){}
     1433  return this.pos > start
     1434};
     1435StringStream.prototype.eatSpace = function () {
     1436    var this$1 = this;
     1437
     1438  var start = this.pos
     1439  while (/[\s\u00a0]/.test(this.string.charAt(this.pos))) { ++this$1.pos }
     1440  return this.pos > start
     1441};
     1442StringStream.prototype.skipToEnd = function () {this.pos = this.string.length};
     1443StringStream.prototype.skipTo = function (ch) {
     1444  var found = this.string.indexOf(ch, this.pos)
     1445  if (found > -1) {this.pos = found; return true}
     1446};
     1447StringStream.prototype.backUp = function (n) {this.pos -= n};
     1448StringStream.prototype.column = function () {
     1449  if (this.lastColumnPos < this.start) {
     1450    this.lastColumnValue = countColumn(this.string, this.start, this.tabSize, this.lastColumnPos, this.lastColumnValue)
     1451    this.lastColumnPos = this.start
     1452  }
     1453  return this.lastColumnValue - (this.lineStart ? countColumn(this.string, this.lineStart, this.tabSize) : 0)
     1454};
     1455StringStream.prototype.indentation = function () {
     1456  return countColumn(this.string, null, this.tabSize) -
     1457    (this.lineStart ? countColumn(this.string, this.lineStart, this.tabSize) : 0)
     1458};
     1459StringStream.prototype.match = function (pattern, consume, caseInsensitive) {
     1460  if (typeof pattern == "string") {
     1461    var cased = function (str) { return caseInsensitive ? str.toLowerCase() : str; }
     1462    var substr = this.string.substr(this.pos, pattern.length)
     1463    if (cased(substr) == cased(pattern)) {
     1464      if (consume !== false) { this.pos += pattern.length }
     1465      return true
     1466    }
     1467  } else {
     1468    var match = this.string.slice(this.pos).match(pattern)
     1469    if (match && match.index > 0) { return null }
     1470    if (match && consume !== false) { this.pos += match[0].length }
     1471    return match
     1472  }
     1473};
     1474StringStream.prototype.current = function (){return this.string.slice(this.start, this.pos)};
     1475StringStream.prototype.hideFirstChars = function (n, inner) {
     1476  this.lineStart += n
     1477  try { return inner() }
     1478  finally { this.lineStart -= n }
     1479};
     1480StringStream.prototype.lookAhead = function (n) {
     1481  var oracle = this.lineOracle
     1482  return oracle && oracle.lookAhead(n)
     1483};
     1484StringStream.prototype.baseToken = function () {
     1485  var oracle = this.lineOracle
     1486  return oracle && oracle.baseToken(this.pos)
     1487};
     1488
     1489var SavedContext = function(state, lookAhead) {
     1490  this.state = state
     1491  this.lookAhead = lookAhead
     1492};
     1493
     1494var Context = function(doc, state, line, lookAhead) {
     1495  this.state = state
     1496  this.doc = doc
     1497  this.line = line
     1498  this.maxLookAhead = lookAhead || 0
     1499  this.baseTokens = null
     1500  this.baseTokenPos = 1
     1501};
     1502
     1503Context.prototype.lookAhead = function (n) {
     1504  var line = this.doc.getLine(this.line + n)
     1505  if (line != null && n > this.maxLookAhead) { this.maxLookAhead = n }
     1506  return line
     1507};
     1508
     1509Context.prototype.baseToken = function (n) {
     1510    var this$1 = this;
     1511
     1512  if (!this.baseTokens) { return null }
     1513  while (this.baseTokens[this.baseTokenPos] <= n)
     1514    { this$1.baseTokenPos += 2 }
     1515  var type = this.baseTokens[this.baseTokenPos + 1]
     1516  return {type: type && type.replace(/( |^)overlay .*/, ""),
     1517          size: this.baseTokens[this.baseTokenPos] - n}
     1518};
     1519
     1520Context.prototype.nextLine = function () {
     1521  this.line++
     1522  if (this.maxLookAhead > 0) { this.maxLookAhead-- }
     1523};
     1524
     1525Context.fromSaved = function (doc, saved, line) {
     1526  if (saved instanceof SavedContext)
     1527    { return new Context(doc, copyState(doc.mode, saved.state), line, saved.lookAhead) }
     1528  else
     1529    { return new Context(doc, copyState(doc.mode, saved), line) }
     1530};
     1531
     1532Context.prototype.save = function (copy) {
     1533  var state = copy !== false ? copyState(this.doc.mode, this.state) : this.state
     1534  return this.maxLookAhead > 0 ? new SavedContext(state, this.maxLookAhead) : state
     1535};
     1536
     1537
     1538// Compute a style array (an array starting with a mode generation
     1539// -- for invalidation -- followed by pairs of end positions and
     1540// style strings), which is used to highlight the tokens on the
     1541// line.
     1542function highlightLine(cm, line, context, forceToEnd) {
     1543  // A styles array always starts with a number identifying the
     1544  // mode/overlays that it is based on (for easy invalidation).
     1545  var st = [cm.state.modeGen], lineClasses = {}
     1546  // Compute the base array of styles
     1547  runMode(cm, line.text, cm.doc.mode, context, function (end, style) { return st.push(end, style); },
     1548          lineClasses, forceToEnd)
     1549  var state = context.state
     1550
     1551  // Run overlays, adjust style array.
     1552  var loop = function ( o ) {
     1553    context.baseTokens = st
     1554    var overlay = cm.state.overlays[o], i = 1, at = 0
     1555    context.state = true
     1556    runMode(cm, line.text, overlay.mode, context, function (end, style) {
     1557      var start = i
     1558      // Ensure there's a token end at the current position, and that i points at it
     1559      while (at < end) {
     1560        var i_end = st[i]
     1561        if (i_end > end)
     1562          { st.splice(i, 1, end, st[i+1], i_end) }
     1563        i += 2
     1564        at = Math.min(end, i_end)
     1565      }
     1566      if (!style) { return }
     1567      if (overlay.opaque) {
     1568        st.splice(start, i - start, end, "overlay " + style)
     1569        i = start + 2
     1570      } else {
     1571        for (; start < i; start += 2) {
     1572          var cur = st[start+1]
     1573          st[start+1] = (cur ? cur + " " : "") + "overlay " + style
    2641574        }
    2651575      }
    266 
    267       var move = connect(targetDocument, "mousemove", operation(function(e) {
    268         clearTimeout(going);
    269         e.stop();
    270         extend(e);
    271       }), true);
    272       var up = connect(targetDocument, "mouseup", operation(function(e) {
    273         clearTimeout(going);
    274         var cur = posFromMouse(e);
    275         if (cur) setSelectionUser(start, cur);
    276         e.stop();
    277         end();
    278       }), true);
    279     }
    280     function onDblClick(e) {
    281       var pos = posFromMouse(e);
    282       if (!pos) return;
    283       selectWordAt(pos);
    284       e.stop();
    285       lastDoubleClick = +new Date;
    286     }
    287     function onDrop(e) {
    288       e.e.preventDefault();
    289       var pos = posFromMouse(e, true), files = e.e.dataTransfer.files;
    290       if (!pos || options.readOnly) return;
    291       if (files && files.length && window.FileReader && window.File) {
    292         function loadFile(file, i) {
    293           var reader = new FileReader;
    294           reader.onload = function() {
    295             text[i] = reader.result;
    296             if (++read == n) replaceRange(text.join(""), clipPos(pos), clipPos(pos));
    297           };
    298           reader.readAsText(file);
    299         }
    300         var n = files.length, text = Array(n), read = 0;
    301         for (var i = 0; i < n; ++i) loadFile(files[i], i);
     1576    }, lineClasses)
     1577    context.state = state
     1578    context.baseTokens = null
     1579    context.baseTokenPos = 1
     1580  };
     1581
     1582  for (var o = 0; o < cm.state.overlays.length; ++o) loop( o );
     1583
     1584  return {styles: st, classes: lineClasses.bgClass || lineClasses.textClass ? lineClasses : null}
     1585}
     1586
     1587function getLineStyles(cm, line, updateFrontier) {
     1588  if (!line.styles || line.styles[0] != cm.state.modeGen) {
     1589    var context = getContextBefore(cm, lineNo(line))
     1590    var resetState = line.text.length > cm.options.maxHighlightLength && copyState(cm.doc.mode, context.state)
     1591    var result = highlightLine(cm, line, context)
     1592    if (resetState) { context.state = resetState }
     1593    line.stateAfter = context.save(!resetState)
     1594    line.styles = result.styles
     1595    if (result.classes) { line.styleClasses = result.classes }
     1596    else if (line.styleClasses) { line.styleClasses = null }
     1597    if (updateFrontier === cm.doc.highlightFrontier)
     1598      { cm.doc.modeFrontier = Math.max(cm.doc.modeFrontier, ++cm.doc.highlightFrontier) }
     1599  }
     1600  return line.styles
     1601}
     1602
     1603function getContextBefore(cm, n, precise) {
     1604  var doc = cm.doc, display = cm.display
     1605  if (!doc.mode.startState) { return new Context(doc, true, n) }
     1606  var start = findStartLine(cm, n, precise)
     1607  var saved = start > doc.first && getLine(doc, start - 1).stateAfter
     1608  var context = saved ? Context.fromSaved(doc, saved, start) : new Context(doc, startState(doc.mode), start)
     1609
     1610  doc.iter(start, n, function (line) {
     1611    processLine(cm, line.text, context)
     1612    var pos = context.line
     1613    line.stateAfter = pos == n - 1 || pos % 5 == 0 || pos >= display.viewFrom && pos < display.viewTo ? context.save() : null
     1614    context.nextLine()
     1615  })
     1616  if (precise) { doc.modeFrontier = context.line }
     1617  return context
     1618}
     1619
     1620// Lightweight form of highlight -- proceed over this line and
     1621// update state, but don't save a style array. Used for lines that
     1622// aren't currently visible.
     1623function processLine(cm, text, context, startAt) {
     1624  var mode = cm.doc.mode
     1625  var stream = new StringStream(text, cm.options.tabSize, context)
     1626  stream.start = stream.pos = startAt || 0
     1627  if (text == "") { callBlankLine(mode, context.state) }
     1628  while (!stream.eol()) {
     1629    readToken(mode, stream, context.state)
     1630    stream.start = stream.pos
     1631  }
     1632}
     1633
     1634function callBlankLine(mode, state) {
     1635  if (mode.blankLine) { return mode.blankLine(state) }
     1636  if (!mode.innerMode) { return }
     1637  var inner = innerMode(mode, state)
     1638  if (inner.mode.blankLine) { return inner.mode.blankLine(inner.state) }
     1639}
     1640
     1641function readToken(mode, stream, state, inner) {
     1642  for (var i = 0; i < 10; i++) {
     1643    if (inner) { inner[0] = innerMode(mode, state).mode }
     1644    var style = mode.token(stream, state)
     1645    if (stream.pos > stream.start) { return style }
     1646  }
     1647  throw new Error("Mode " + mode.name + " failed to advance stream.")
     1648}
     1649
     1650var Token = function(stream, type, state) {
     1651  this.start = stream.start; this.end = stream.pos
     1652  this.string = stream.current()
     1653  this.type = type || null
     1654  this.state = state
     1655};
     1656
     1657// Utility for getTokenAt and getLineTokens
     1658function takeToken(cm, pos, precise, asArray) {
     1659  var doc = cm.doc, mode = doc.mode, style
     1660  pos = clipPos(doc, pos)
     1661  var line = getLine(doc, pos.line), context = getContextBefore(cm, pos.line, precise)
     1662  var stream = new StringStream(line.text, cm.options.tabSize, context), tokens
     1663  if (asArray) { tokens = [] }
     1664  while ((asArray || stream.pos < pos.ch) && !stream.eol()) {
     1665    stream.start = stream.pos
     1666    style = readToken(mode, stream, context.state)
     1667    if (asArray) { tokens.push(new Token(stream, style, copyState(doc.mode, context.state))) }
     1668  }
     1669  return asArray ? tokens : new Token(stream, style, context.state)
     1670}
     1671
     1672function extractLineClasses(type, output) {
     1673  if (type) { for (;;) {
     1674    var lineClass = type.match(/(?:^|\s+)line-(background-)?(\S+)/)
     1675    if (!lineClass) { break }
     1676    type = type.slice(0, lineClass.index) + type.slice(lineClass.index + lineClass[0].length)
     1677    var prop = lineClass[1] ? "bgClass" : "textClass"
     1678    if (output[prop] == null)
     1679      { output[prop] = lineClass[2] }
     1680    else if (!(new RegExp("(?:^|\s)" + lineClass[2] + "(?:$|\s)")).test(output[prop]))
     1681      { output[prop] += " " + lineClass[2] }
     1682  } }
     1683  return type
     1684}
     1685
     1686// Run the given mode's parser over a line, calling f for each token.
     1687function runMode(cm, text, mode, context, f, lineClasses, forceToEnd) {
     1688  var flattenSpans = mode.flattenSpans
     1689  if (flattenSpans == null) { flattenSpans = cm.options.flattenSpans }
     1690  var curStart = 0, curStyle = null
     1691  var stream = new StringStream(text, cm.options.tabSize, context), style
     1692  var inner = cm.options.addModeClass && [null]
     1693  if (text == "") { extractLineClasses(callBlankLine(mode, context.state), lineClasses) }
     1694  while (!stream.eol()) {
     1695    if (stream.pos > cm.options.maxHighlightLength) {
     1696      flattenSpans = false
     1697      if (forceToEnd) { processLine(cm, text, context, stream.pos) }
     1698      stream.pos = text.length
     1699      style = null
     1700    } else {
     1701      style = extractLineClasses(readToken(mode, stream, context.state, inner), lineClasses)
     1702    }
     1703    if (inner) {
     1704      var mName = inner[0].name
     1705      if (mName) { style = "m-" + (style ? mName + " " + style : mName) }
     1706    }
     1707    if (!flattenSpans || curStyle != style) {
     1708      while (curStart < stream.start) {
     1709        curStart = Math.min(stream.start, curStart + 5000)
     1710        f(curStart, curStyle)
    3021711      }
    303       else {
    304         try {
    305           var text = e.e.dataTransfer.getData("Text");
    306           if (text) replaceRange(text, pos, pos);
    307         }
    308         catch(e){}
     1712      curStyle = style
     1713    }
     1714    stream.start = stream.pos
     1715  }
     1716  while (curStart < stream.pos) {
     1717    // Webkit seems to refuse to render text nodes longer than 57444
     1718    // characters, and returns inaccurate measurements in nodes
     1719    // starting around 5000 chars.
     1720    var pos = Math.min(stream.pos, curStart + 5000)
     1721    f(pos, curStyle)
     1722    curStart = pos
     1723  }
     1724}
     1725
     1726// Finds the line to start with when starting a parse. Tries to
     1727// find a line with a stateAfter, so that it can start with a
     1728// valid state. If that fails, it returns the line with the
     1729// smallest indentation, which tends to need the least context to
     1730// parse correctly.
     1731function findStartLine(cm, n, precise) {
     1732  var minindent, minline, doc = cm.doc
     1733  var lim = precise ? -1 : n - (cm.doc.mode.innerMode ? 1000 : 100)
     1734  for (var search = n; search > lim; --search) {
     1735    if (search <= doc.first) { return doc.first }
     1736    var line = getLine(doc, search - 1), after = line.stateAfter
     1737    if (after && (!precise || search + (after instanceof SavedContext ? after.lookAhead : 0) <= doc.modeFrontier))
     1738      { return search }
     1739    var indented = countColumn(line.text, null, cm.options.tabSize)
     1740    if (minline == null || minindent > indented) {
     1741      minline = search - 1
     1742      minindent = indented
     1743    }
     1744  }
     1745  return minline
     1746}
     1747
     1748function retreatFrontier(doc, n) {
     1749  doc.modeFrontier = Math.min(doc.modeFrontier, n)
     1750  if (doc.highlightFrontier < n - 10) { return }
     1751  var start = doc.first
     1752  for (var line = n - 1; line > start; line--) {
     1753    var saved = getLine(doc, line).stateAfter
     1754    // change is on 3
     1755    // state on line 1 looked ahead 2 -- so saw 3
     1756    // test 1 + 2 < 3 should cover this
     1757    if (saved && (!(saved instanceof SavedContext) || line + saved.lookAhead < n)) {
     1758      start = line + 1
     1759      break
     1760    }
     1761  }
     1762  doc.highlightFrontier = Math.min(doc.highlightFrontier, start)
     1763}
     1764
     1765// LINE DATA STRUCTURE
     1766
     1767// Line objects. These hold state related to a line, including
     1768// highlighting info (the styles array).
     1769var Line = function(text, markedSpans, estimateHeight) {
     1770  this.text = text
     1771  attachMarkedSpans(this, markedSpans)
     1772  this.height = estimateHeight ? estimateHeight(this) : 1
     1773};
     1774
     1775Line.prototype.lineNo = function () { return lineNo(this) };
     1776eventMixin(Line)
     1777
     1778// Change the content (text, markers) of a line. Automatically
     1779// invalidates cached information and tries to re-estimate the
     1780// line's height.
     1781function updateLine(line, text, markedSpans, estimateHeight) {
     1782  line.text = text
     1783  if (line.stateAfter) { line.stateAfter = null }
     1784  if (line.styles) { line.styles = null }
     1785  if (line.order != null) { line.order = null }
     1786  detachMarkedSpans(line)
     1787  attachMarkedSpans(line, markedSpans)
     1788  var estHeight = estimateHeight ? estimateHeight(line) : 1
     1789  if (estHeight != line.height) { updateLineHeight(line, estHeight) }
     1790}
     1791
     1792// Detach a line from the document tree and its markers.
     1793function cleanUpLine(line) {
     1794  line.parent = null
     1795  detachMarkedSpans(line)
     1796}
     1797
     1798// Convert a style as returned by a mode (either null, or a string
     1799// containing one or more styles) to a CSS style. This is cached,
     1800// and also looks for line-wide styles.
     1801var styleToClassCache = {};
     1802var styleToClassCacheWithMode = {};
     1803function interpretTokenStyle(style, options) {
     1804  if (!style || /^\s*$/.test(style)) { return null }
     1805  var cache = options.addModeClass ? styleToClassCacheWithMode : styleToClassCache
     1806  return cache[style] ||
     1807    (cache[style] = style.replace(/\S+/g, "cm-$&"))
     1808}
     1809
     1810// Render the DOM representation of the text of a line. Also builds
     1811// up a 'line map', which points at the DOM nodes that represent
     1812// specific stretches of text, and is used by the measuring code.
     1813// The returned object contains the DOM node, this map, and
     1814// information about line-wide styles that were set by the mode.
     1815function buildLineContent(cm, lineView) {
     1816  // The padding-right forces the element to have a 'border', which
     1817  // is needed on Webkit to be able to get line-level bounding
     1818  // rectangles for it (in measureChar).
     1819  var content = eltP("span", null, null, webkit ? "padding-right: .1px" : null)
     1820  var builder = {pre: eltP("pre", [content], "CodeMirror-line"), content: content,
     1821                 col: 0, pos: 0, cm: cm,
     1822                 trailingSpace: false,
     1823                 splitSpaces: cm.getOption("lineWrapping")}
     1824  lineView.measure = {}
     1825
     1826  // Iterate over the logical lines that make up this visual line.
     1827  for (var i = 0; i <= (lineView.rest ? lineView.rest.length : 0); i++) {
     1828    var line = i ? lineView.rest[i - 1] : lineView.line, order = (void 0)
     1829    builder.pos = 0
     1830    builder.addToken = buildToken
     1831    // Optionally wire in some hacks into the token-rendering
     1832    // algorithm, to deal with browser quirks.
     1833    if (hasBadBidiRects(cm.display.measure) && (order = getOrder(line, cm.doc.direction)))
     1834      { builder.addToken = buildTokenBadBidi(builder.addToken, order) }
     1835    builder.map = []
     1836    var allowFrontierUpdate = lineView != cm.display.externalMeasured && lineNo(line)
     1837    insertLineContent(line, builder, getLineStyles(cm, line, allowFrontierUpdate))
     1838    if (line.styleClasses) {
     1839      if (line.styleClasses.bgClass)
     1840        { builder.bgClass = joinClasses(line.styleClasses.bgClass, builder.bgClass || "") }
     1841      if (line.styleClasses.textClass)
     1842        { builder.textClass = joinClasses(line.styleClasses.textClass, builder.textClass || "") }
     1843    }
     1844
     1845    // Ensure at least a single node is present, for measuring.
     1846    if (builder.map.length == 0)
     1847      { builder.map.push(0, 0, builder.content.appendChild(zeroWidthElement(cm.display.measure))) }
     1848
     1849    // Store the map and a cache object for the current logical line
     1850    if (i == 0) {
     1851      lineView.measure.map = builder.map
     1852      lineView.measure.cache = {}
     1853    } else {
     1854      ;(lineView.measure.maps || (lineView.measure.maps = [])).push(builder.map)
     1855      ;(lineView.measure.caches || (lineView.measure.caches = [])).push({})
     1856    }
     1857  }
     1858
     1859  // See issue #2901
     1860  if (webkit) {
     1861    var last = builder.content.lastChild
     1862    if (/\bcm-tab\b/.test(last.className) || (last.querySelector && last.querySelector(".cm-tab")))
     1863      { builder.content.className = "cm-tab-wrap-hack" }
     1864  }
     1865
     1866  signal(cm, "renderLine", cm, lineView.line, builder.pre)
     1867  if (builder.pre.className)
     1868    { builder.textClass = joinClasses(builder.pre.className, builder.textClass || "") }
     1869
     1870  return builder
     1871}
     1872
     1873function defaultSpecialCharPlaceholder(ch) {
     1874  var token = elt("span", "\u2022", "cm-invalidchar")
     1875  token.title = "\\u" + ch.charCodeAt(0).toString(16)
     1876  token.setAttribute("aria-label", token.title)
     1877  return token
     1878}
     1879
     1880// Build up the DOM representation for a single token, and add it to
     1881// the line map. Takes care to render special characters separately.
     1882function buildToken(builder, text, style, startStyle, endStyle, title, css) {
     1883  if (!text) { return }
     1884  var displayText = builder.splitSpaces ? splitSpaces(text, builder.trailingSpace) : text
     1885  var special = builder.cm.state.specialChars, mustWrap = false
     1886  var content
     1887  if (!special.test(text)) {
     1888    builder.col += text.length
     1889    content = document.createTextNode(displayText)
     1890    builder.map.push(builder.pos, builder.pos + text.length, content)
     1891    if (ie && ie_version < 9) { mustWrap = true }
     1892    builder.pos += text.length
     1893  } else {
     1894    content = document.createDocumentFragment()
     1895    var pos = 0
     1896    while (true) {
     1897      special.lastIndex = pos
     1898      var m = special.exec(text)
     1899      var skipped = m ? m.index - pos : text.length - pos
     1900      if (skipped) {
     1901        var txt = document.createTextNode(displayText.slice(pos, pos + skipped))
     1902        if (ie && ie_version < 9) { content.appendChild(elt("span", [txt])) }
     1903        else { content.appendChild(txt) }
     1904        builder.map.push(builder.pos, builder.pos + skipped, txt)
     1905        builder.col += skipped
     1906        builder.pos += skipped
    3091907      }
    310     }
    311     function onKeyDown(e) {
    312       if (!focused) onFocus();
    313 
    314       var code = e.e.keyCode;
    315       // IE does strange things with escape.
    316       if (ie && code == 27) { e.e.returnValue = false; }
    317       // Tries to detect ctrl on non-mac, cmd on mac.
    318       var mod = (mac ? e.e.metaKey : e.e.ctrlKey) && !e.e.altKey, anyMod = e.e.ctrlKey || e.e.altKey || e.e.metaKey;
    319       if (code == 16 || e.e.shiftKey) shiftSelecting = shiftSelecting || (sel.inverted ? sel.to : sel.from);
    320       else shiftSelecting = null;
    321       // First give onKeyEvent option a chance to handle this.
    322       if (options.onKeyEvent && options.onKeyEvent(instance, addStop(e.e))) return;
    323 
    324       if (code == 33 || code == 34) {scrollPage(code == 34); return e.stop();} // page up/down
    325       if (mod && ((code == 36 || code == 35) || // ctrl-home/end
    326                   mac && (code == 38 || code == 40))) { // cmd-up/down
    327         scrollEnd(code == 36 || code == 38); return e.stop();
     1908      if (!m) { break }
     1909      pos += skipped + 1
     1910      var txt$1 = (void 0)
     1911      if (m[0] == "\t") {
     1912        var tabSize = builder.cm.options.tabSize, tabWidth = tabSize - builder.col % tabSize
     1913        txt$1 = content.appendChild(elt("span", spaceStr(tabWidth), "cm-tab"))
     1914        txt$1.setAttribute("role", "presentation")
     1915        txt$1.setAttribute("cm-text", "\t")
     1916        builder.col += tabWidth
     1917      } else if (m[0] == "\r" || m[0] == "\n") {
     1918        txt$1 = content.appendChild(elt("span", m[0] == "\r" ? "\u240d" : "\u2424", "cm-invalidchar"))
     1919        txt$1.setAttribute("cm-text", m[0])
     1920        builder.col += 1
     1921      } else {
     1922        txt$1 = builder.cm.options.specialCharPlaceholder(m[0])
     1923        txt$1.setAttribute("cm-text", m[0])
     1924        if (ie && ie_version < 9) { content.appendChild(elt("span", [txt$1])) }
     1925        else { content.appendChild(txt$1) }
     1926        builder.col += 1
    3281927      }
    329       if (mod && code == 65) {selectAll(); return e.stop();} // ctrl-a
    330       if (!options.readOnly) {
    331         if (!anyMod && code == 13) {return;} // enter
    332         if (!anyMod && code == 9 && handleTab(e.e.shiftKey)) return e.stop(); // tab
    333         if (mod && code == 90) {undo(); return e.stop();} // ctrl-z
    334         if (mod && ((e.e.shiftKey && code == 90) || code == 89)) {redo(); return e.stop();} // ctrl-shift-z, ctrl-y
     1928      builder.map.push(builder.pos, builder.pos + 1, txt$1)
     1929      builder.pos++
     1930    }
     1931  }
     1932  builder.trailingSpace = displayText.charCodeAt(text.length - 1) == 32
     1933  if (style || startStyle || endStyle || mustWrap || css) {
     1934    var fullStyle = style || ""
     1935    if (startStyle) { fullStyle += startStyle }
     1936    if (endStyle) { fullStyle += endStyle }
     1937    var token = elt("span", [content], fullStyle, css)
     1938    if (title) { token.title = title }
     1939    return builder.content.appendChild(token)
     1940  }
     1941  builder.content.appendChild(content)
     1942}
     1943
     1944// Change some spaces to NBSP to prevent the browser from collapsing
     1945// trailing spaces at the end of a line when rendering text (issue #1362).
     1946function splitSpaces(text, trailingBefore) {
     1947  if (text.length > 1 && !/  /.test(text)) { return text }
     1948  var spaceBefore = trailingBefore, result = ""
     1949  for (var i = 0; i < text.length; i++) {
     1950    var ch = text.charAt(i)
     1951    if (ch == " " && spaceBefore && (i == text.length - 1 || text.charCodeAt(i + 1) == 32))
     1952      { ch = "\u00a0" }
     1953    result += ch
     1954    spaceBefore = ch == " "
     1955  }
     1956  return result
     1957}
     1958
     1959// Work around nonsense dimensions being reported for stretches of
     1960// right-to-left text.
     1961function buildTokenBadBidi(inner, order) {
     1962  return function (builder, text, style, startStyle, endStyle, title, css) {
     1963    style = style ? style + " cm-force-border" : "cm-force-border"
     1964    var start = builder.pos, end = start + text.length
     1965    for (;;) {
     1966      // Find the part that overlaps with the start of this text
     1967      var part = (void 0)
     1968      for (var i = 0; i < order.length; i++) {
     1969        part = order[i]
     1970        if (part.to > start && part.from <= start) { break }
    3351971      }
    336 
    337       // Key id to use in the movementKeys map. We also pass it to
    338       // fastPoll in order to 'self learn'. We need this because
    339       // reducedSelection, the hack where we collapse the selection to
    340       // its start when it is inverted and a movement key is pressed
    341       // (and later restore it again), shouldn't be used for
    342       // non-movement keys.
    343       curKeyId = (mod ? "c" : "") + code;
    344       if (sel.inverted && movementKeys.hasOwnProperty(curKeyId)) {
    345         var range = selRange(input);
    346         if (range) {
    347           reducedSelection = {anchor: range.start};
    348           setSelRange(input, range.start, range.start);
     1972      if (part.to >= end) { return inner(builder, text, style, startStyle, endStyle, title, css) }
     1973      inner(builder, text.slice(0, part.to - start), style, startStyle, null, title, css)
     1974      startStyle = null
     1975      text = text.slice(part.to - start)
     1976      start = part.to
     1977    }
     1978  }
     1979}
     1980
     1981function buildCollapsedSpan(builder, size, marker, ignoreWidget) {
     1982  var widget = !ignoreWidget && marker.widgetNode
     1983  if (widget) { builder.map.push(builder.pos, builder.pos + size, widget) }
     1984  if (!ignoreWidget && builder.cm.display.input.needsContentAttribute) {
     1985    if (!widget)
     1986      { widget = builder.content.appendChild(document.createElement("span")) }
     1987    widget.setAttribute("cm-marker", marker.id)
     1988  }
     1989  if (widget) {
     1990    builder.cm.display.input.setUneditable(widget)
     1991    builder.content.appendChild(widget)
     1992  }
     1993  builder.pos += size
     1994  builder.trailingSpace = false
     1995}
     1996
     1997// Outputs a number of spans to make up a line, taking highlighting
     1998// and marked text into account.
     1999function insertLineContent(line, builder, styles) {
     2000  var spans = line.markedSpans, allText = line.text, at = 0
     2001  if (!spans) {
     2002    for (var i$1 = 1; i$1 < styles.length; i$1+=2)
     2003      { builder.addToken(builder, allText.slice(at, at = styles[i$1]), interpretTokenStyle(styles[i$1+1], builder.cm.options)) }
     2004    return
     2005  }
     2006
     2007  var len = allText.length, pos = 0, i = 1, text = "", style, css
     2008  var nextChange = 0, spanStyle, spanEndStyle, spanStartStyle, title, collapsed
     2009  for (;;) {
     2010    if (nextChange == pos) { // Update current marker set
     2011      spanStyle = spanEndStyle = spanStartStyle = title = css = ""
     2012      collapsed = null; nextChange = Infinity
     2013      var foundBookmarks = [], endStyles = (void 0)
     2014      for (var j = 0; j < spans.length; ++j) {
     2015        var sp = spans[j], m = sp.marker
     2016        if (m.type == "bookmark" && sp.from == pos && m.widgetNode) {
     2017          foundBookmarks.push(m)
     2018        } else if (sp.from <= pos && (sp.to == null || sp.to > pos || m.collapsed && sp.to == pos && sp.from == pos)) {
     2019          if (sp.to != null && sp.to != pos && nextChange > sp.to) {
     2020            nextChange = sp.to
     2021            spanEndStyle = ""
     2022          }
     2023          if (m.className) { spanStyle += " " + m.className }
     2024          if (m.css) { css = (css ? css + ";" : "") + m.css }
     2025          if (m.startStyle && sp.from == pos) { spanStartStyle += " " + m.startStyle }
     2026          if (m.endStyle && sp.to == nextChange) { (endStyles || (endStyles = [])).push(m.endStyle, sp.to) }
     2027          if (m.title && !title) { title = m.title }
     2028          if (m.collapsed && (!collapsed || compareCollapsedMarkers(collapsed.marker, m) < 0))
     2029            { collapsed = sp }
     2030        } else if (sp.from > pos && nextChange > sp.from) {
     2031          nextChange = sp.from
    3492032        }
    3502033      }
    351       fastPoll(curKeyId);
    352     }
    353     function onKeyUp(e) {
    354       if (options.onKeyEvent && options.onKeyEvent(instance, addStop(e.e))) return;
    355       if (reducedSelection) {
    356         reducedSelection = null;
    357         updateInput = true;
     2034      if (endStyles) { for (var j$1 = 0; j$1 < endStyles.length; j$1 += 2)
     2035        { if (endStyles[j$1 + 1] == nextChange) { spanEndStyle += " " + endStyles[j$1] } } }
     2036
     2037      if (!collapsed || collapsed.from == pos) { for (var j$2 = 0; j$2 < foundBookmarks.length; ++j$2)
     2038        { buildCollapsedSpan(builder, 0, foundBookmarks[j$2]) } }
     2039      if (collapsed && (collapsed.from || 0) == pos) {
     2040        buildCollapsedSpan(builder, (collapsed.to == null ? len + 1 : collapsed.to) - pos,
     2041                           collapsed.marker, collapsed.from == null)
     2042        if (collapsed.to == null) { return }
     2043        if (collapsed.to == pos) { collapsed = false }
    3582044      }
    359       if (e.e.keyCode == 16) shiftSelecting = null;
    360     }
    361     function onKeyPress(e) {
    362       if (options.onKeyEvent && options.onKeyEvent(instance, addStop(e.e))) return;
    363       if (options.electricChars && mode.electricChars) {
    364         var ch = String.fromCharCode(e.e.charCode == null ? e.e.keyCode : e.e.charCode);
    365         if (mode.electricChars.indexOf(ch) > -1)
    366           setTimeout(operation(function() {indentLine(sel.to.line, "smart");}), 50);
     2045    }
     2046    if (pos >= len) { break }
     2047
     2048    var upto = Math.min(len, nextChange)
     2049    while (true) {
     2050      if (text) {
     2051        var end = pos + text.length
     2052        if (!collapsed) {
     2053          var tokenText = end > upto ? text.slice(0, upto - pos) : text
     2054          builder.addToken(builder, tokenText, style ? style + spanStyle : spanStyle,
     2055                           spanStartStyle, pos + tokenText.length == nextChange ? spanEndStyle : "", title, css)
     2056        }
     2057        if (end >= upto) {text = text.slice(upto - pos); pos = upto; break}
     2058        pos = end
     2059        spanStartStyle = ""
    3672060      }
    368       var code = e.e.keyCode;
    369       // Re-stop tab and enter. Necessary on some browsers.
    370       if (code == 13) {if (!options.readOnly) handleEnter(); e.stop();}
    371       else if (!e.e.ctrlKey && !e.e.altKey && !e.e.metaKey && code == 9 && options.tabMode != "default") e.stop();
    372       else fastPoll(curKeyId);
    373     }
    374 
    375     function onFocus() {
    376       if (options.readOnly == "nocursor") return;
    377       if (!focused) {
    378         if (options.onFocus) options.onFocus(instance);
    379         focused = true;
    380         if (wrapper.className.search(/\bCodeMirror-focused\b/) == -1)
    381           wrapper.className += " CodeMirror-focused";
    382         if (!leaveInputAlone) prepareInput();
     2061      text = allText.slice(at, at = styles[i++])
     2062      style = interpretTokenStyle(styles[i++], builder.cm.options)
     2063    }
     2064  }
     2065}
     2066
     2067
     2068// These objects are used to represent the visible (currently drawn)
     2069// part of the document. A LineView may correspond to multiple
     2070// logical lines, if those are connected by collapsed ranges.
     2071function LineView(doc, line, lineN) {
     2072  // The starting line
     2073  this.line = line
     2074  // Continuing lines, if any
     2075  this.rest = visualLineContinued(line)
     2076  // Number of logical lines in this visual line
     2077  this.size = this.rest ? lineNo(lst(this.rest)) - lineN + 1 : 1
     2078  this.node = this.text = null
     2079  this.hidden = lineIsHidden(doc, line)
     2080}
     2081
     2082// Create a range of LineView objects for the given lines.
     2083function buildViewArray(cm, from, to) {
     2084  var array = [], nextPos
     2085  for (var pos = from; pos < to; pos = nextPos) {
     2086    var view = new LineView(cm.doc, getLine(cm.doc, pos), pos)
     2087    nextPos = pos + view.size
     2088    array.push(view)
     2089  }
     2090  return array
     2091}
     2092
     2093var operationGroup = null
     2094
     2095function pushOperation(op) {
     2096  if (operationGroup) {
     2097    operationGroup.ops.push(op)
     2098  } else {
     2099    op.ownsGroup = operationGroup = {
     2100      ops: [op],
     2101      delayedCallbacks: []
     2102    }
     2103  }
     2104}
     2105
     2106function fireCallbacksForOps(group) {
     2107  // Calls delayed callbacks and cursorActivity handlers until no
     2108  // new ones appear
     2109  var callbacks = group.delayedCallbacks, i = 0
     2110  do {
     2111    for (; i < callbacks.length; i++)
     2112      { callbacks[i].call(null) }
     2113    for (var j = 0; j < group.ops.length; j++) {
     2114      var op = group.ops[j]
     2115      if (op.cursorActivityHandlers)
     2116        { while (op.cursorActivityCalled < op.cursorActivityHandlers.length)
     2117          { op.cursorActivityHandlers[op.cursorActivityCalled++].call(null, op.cm) } }
     2118    }
     2119  } while (i < callbacks.length)
     2120}
     2121
     2122function finishOperation(op, endCb) {
     2123  var group = op.ownsGroup
     2124  if (!group) { return }
     2125
     2126  try { fireCallbacksForOps(group) }
     2127  finally {
     2128    operationGroup = null
     2129    endCb(group)
     2130  }
     2131}
     2132
     2133var orphanDelayedCallbacks = null
     2134
     2135// Often, we want to signal events at a point where we are in the
     2136// middle of some work, but don't want the handler to start calling
     2137// other methods on the editor, which might be in an inconsistent
     2138// state or simply not expect any other events to happen.
     2139// signalLater looks whether there are any handlers, and schedules
     2140// them to be executed when the last operation ends, or, if no
     2141// operation is active, when a timeout fires.
     2142function signalLater(emitter, type /*, values...*/) {
     2143  var arr = getHandlers(emitter, type)
     2144  if (!arr.length) { return }
     2145  var args = Array.prototype.slice.call(arguments, 2), list
     2146  if (operationGroup) {
     2147    list = operationGroup.delayedCallbacks
     2148  } else if (orphanDelayedCallbacks) {
     2149    list = orphanDelayedCallbacks
     2150  } else {
     2151    list = orphanDelayedCallbacks = []
     2152    setTimeout(fireOrphanDelayed, 0)
     2153  }
     2154  var loop = function ( i ) {
     2155    list.push(function () { return arr[i].apply(null, args); })
     2156  };
     2157
     2158  for (var i = 0; i < arr.length; ++i)
     2159    loop( i );
     2160}
     2161
     2162function fireOrphanDelayed() {
     2163  var delayed = orphanDelayedCallbacks
     2164  orphanDelayedCallbacks = null
     2165  for (var i = 0; i < delayed.length; ++i) { delayed[i]() }
     2166}
     2167
     2168// When an aspect of a line changes, a string is added to
     2169// lineView.changes. This updates the relevant part of the line's
     2170// DOM structure.
     2171function updateLineForChanges(cm, lineView, lineN, dims) {
     2172  for (var j = 0; j < lineView.changes.length; j++) {
     2173    var type = lineView.changes[j]
     2174    if (type == "text") { updateLineText(cm, lineView) }
     2175    else if (type == "gutter") { updateLineGutter(cm, lineView, lineN, dims) }
     2176    else if (type == "class") { updateLineClasses(cm, lineView) }
     2177    else if (type == "widget") { updateLineWidgets(cm, lineView, dims) }
     2178  }
     2179  lineView.changes = null
     2180}
     2181
     2182// Lines with gutter elements, widgets or a background class need to
     2183// be wrapped, and have the extra elements added to the wrapper div
     2184function ensureLineWrapped(lineView) {
     2185  if (lineView.node == lineView.text) {
     2186    lineView.node = elt("div", null, null, "position: relative")
     2187    if (lineView.text.parentNode)
     2188      { lineView.text.parentNode.replaceChild(lineView.node, lineView.text) }
     2189    lineView.node.appendChild(lineView.text)
     2190    if (ie && ie_version < 8) { lineView.node.style.zIndex = 2 }
     2191  }
     2192  return lineView.node
     2193}
     2194
     2195function updateLineBackground(cm, lineView) {
     2196  var cls = lineView.bgClass ? lineView.bgClass + " " + (lineView.line.bgClass || "") : lineView.line.bgClass
     2197  if (cls) { cls += " CodeMirror-linebackground" }
     2198  if (lineView.background) {
     2199    if (cls) { lineView.background.className = cls }
     2200    else { lineView.background.parentNode.removeChild(lineView.background); lineView.background = null }
     2201  } else if (cls) {
     2202    var wrap = ensureLineWrapped(lineView)
     2203    lineView.background = wrap.insertBefore(elt("div", null, cls), wrap.firstChild)
     2204    cm.display.input.setUneditable(lineView.background)
     2205  }
     2206}
     2207
     2208// Wrapper around buildLineContent which will reuse the structure
     2209// in display.externalMeasured when possible.
     2210function getLineContent(cm, lineView) {
     2211  var ext = cm.display.externalMeasured
     2212  if (ext && ext.line == lineView.line) {
     2213    cm.display.externalMeasured = null
     2214    lineView.measure = ext.measure
     2215    return ext.built
     2216  }
     2217  return buildLineContent(cm, lineView)
     2218}
     2219
     2220// Redraw the line's text. Interacts with the background and text
     2221// classes because the mode may output tokens that influence these
     2222// classes.
     2223function updateLineText(cm, lineView) {
     2224  var cls = lineView.text.className
     2225  var built = getLineContent(cm, lineView)
     2226  if (lineView.text == lineView.node) { lineView.node = built.pre }
     2227  lineView.text.parentNode.replaceChild(built.pre, lineView.text)
     2228  lineView.text = built.pre
     2229  if (built.bgClass != lineView.bgClass || built.textClass != lineView.textClass) {
     2230    lineView.bgClass = built.bgClass
     2231    lineView.textClass = built.textClass
     2232    updateLineClasses(cm, lineView)
     2233  } else if (cls) {
     2234    lineView.text.className = cls
     2235  }
     2236}
     2237
     2238function updateLineClasses(cm, lineView) {
     2239  updateLineBackground(cm, lineView)
     2240  if (lineView.line.wrapClass)
     2241    { ensureLineWrapped(lineView).className = lineView.line.wrapClass }
     2242  else if (lineView.node != lineView.text)
     2243    { lineView.node.className = "" }
     2244  var textClass = lineView.textClass ? lineView.textClass + " " + (lineView.line.textClass || "") : lineView.line.textClass
     2245  lineView.text.className = textClass || ""
     2246}
     2247
     2248function updateLineGutter(cm, lineView, lineN, dims) {
     2249  if (lineView.gutter) {
     2250    lineView.node.removeChild(lineView.gutter)
     2251    lineView.gutter = null
     2252  }
     2253  if (lineView.gutterBackground) {
     2254    lineView.node.removeChild(lineView.gutterBackground)
     2255    lineView.gutterBackground = null
     2256  }
     2257  if (lineView.line.gutterClass) {
     2258    var wrap = ensureLineWrapped(lineView)
     2259    lineView.gutterBackground = elt("div", null, "CodeMirror-gutter-background " + lineView.line.gutterClass,
     2260                                    ("left: " + (cm.options.fixedGutter ? dims.fixedPos : -dims.gutterTotalWidth) + "px; width: " + (dims.gutterTotalWidth) + "px"))
     2261    cm.display.input.setUneditable(lineView.gutterBackground)
     2262    wrap.insertBefore(lineView.gutterBackground, lineView.text)
     2263  }
     2264  var markers = lineView.line.gutterMarkers
     2265  if (cm.options.lineNumbers || markers) {
     2266    var wrap$1 = ensureLineWrapped(lineView)
     2267    var gutterWrap = lineView.gutter = elt("div", null, "CodeMirror-gutter-wrapper", ("left: " + (cm.options.fixedGutter ? dims.fixedPos : -dims.gutterTotalWidth) + "px"))
     2268    cm.display.input.setUneditable(gutterWrap)
     2269    wrap$1.insertBefore(gutterWrap, lineView.text)
     2270    if (lineView.line.gutterClass)
     2271      { gutterWrap.className += " " + lineView.line.gutterClass }
     2272    if (cm.options.lineNumbers && (!markers || !markers["CodeMirror-linenumbers"]))
     2273      { lineView.lineNumber = gutterWrap.appendChild(
     2274        elt("div", lineNumberFor(cm.options, lineN),
     2275            "CodeMirror-linenumber CodeMirror-gutter-elt",
     2276            ("left: " + (dims.gutterLeft["CodeMirror-linenumbers"]) + "px; width: " + (cm.display.lineNumInnerWidth) + "px"))) }
     2277    if (markers) { for (var k = 0; k < cm.options.gutters.length; ++k) {
     2278      var id = cm.options.gutters[k], found = markers.hasOwnProperty(id) && markers[id]
     2279      if (found)
     2280        { gutterWrap.appendChild(elt("div", [found], "CodeMirror-gutter-elt",
     2281                                   ("left: " + (dims.gutterLeft[id]) + "px; width: " + (dims.gutterWidth[id]) + "px"))) }
     2282    } }
     2283  }
     2284}
     2285
     2286function updateLineWidgets(cm, lineView, dims) {
     2287  if (lineView.alignable) { lineView.alignable = null }
     2288  for (var node = lineView.node.firstChild, next = (void 0); node; node = next) {
     2289    next = node.nextSibling
     2290    if (node.className == "CodeMirror-linewidget")
     2291      { lineView.node.removeChild(node) }
     2292  }
     2293  insertLineWidgets(cm, lineView, dims)
     2294}
     2295
     2296// Build a line's DOM representation from scratch
     2297function buildLineElement(cm, lineView, lineN, dims) {
     2298  var built = getLineContent(cm, lineView)
     2299  lineView.text = lineView.node = built.pre
     2300  if (built.bgClass) { lineView.bgClass = built.bgClass }
     2301  if (built.textClass) { lineView.textClass = built.textClass }
     2302
     2303  updateLineClasses(cm, lineView)
     2304  updateLineGutter(cm, lineView, lineN, dims)
     2305  insertLineWidgets(cm, lineView, dims)
     2306  return lineView.node
     2307}
     2308
     2309// A lineView may contain multiple logical lines (when merged by
     2310// collapsed spans). The widgets for all of them need to be drawn.
     2311function insertLineWidgets(cm, lineView, dims) {
     2312  insertLineWidgetsFor(cm, lineView.line, lineView, dims, true)
     2313  if (lineView.rest) { for (var i = 0; i < lineView.rest.length; i++)
     2314    { insertLineWidgetsFor(cm, lineView.rest[i], lineView, dims, false) } }
     2315}
     2316
     2317function insertLineWidgetsFor(cm, line, lineView, dims, allowAbove) {
     2318  if (!line.widgets) { return }
     2319  var wrap = ensureLineWrapped(lineView)
     2320  for (var i = 0, ws = line.widgets; i < ws.length; ++i) {
     2321    var widget = ws[i], node = elt("div", [widget.node], "CodeMirror-linewidget")
     2322    if (!widget.handleMouseEvents) { node.setAttribute("cm-ignore-events", "true") }
     2323    positionLineWidget(widget, node, lineView, dims)
     2324    cm.display.input.setUneditable(node)
     2325    if (allowAbove && widget.above)
     2326      { wrap.insertBefore(node, lineView.gutter || lineView.text) }
     2327    else
     2328      { wrap.appendChild(node) }
     2329    signalLater(widget, "redraw")
     2330  }
     2331}
     2332
     2333function positionLineWidget(widget, node, lineView, dims) {
     2334  if (widget.noHScroll) {
     2335    ;(lineView.alignable || (lineView.alignable = [])).push(node)
     2336    var width = dims.wrapperWidth
     2337    node.style.left = dims.fixedPos + "px"
     2338    if (!widget.coverGutter) {
     2339      width -= dims.gutterTotalWidth
     2340      node.style.paddingLeft = dims.gutterTotalWidth + "px"
     2341    }
     2342    node.style.width = width + "px"
     2343  }
     2344  if (widget.coverGutter) {
     2345    node.style.zIndex = 5
     2346    node.style.position = "relative"
     2347    if (!widget.noHScroll) { node.style.marginLeft = -dims.gutterTotalWidth + "px" }
     2348  }
     2349}
     2350
     2351function widgetHeight(widget) {
     2352  if (widget.height != null) { return widget.height }
     2353  var cm = widget.doc.cm
     2354  if (!cm) { return 0 }
     2355  if (!contains(document.body, widget.node)) {
     2356    var parentStyle = "position: relative;"
     2357    if (widget.coverGutter)
     2358      { parentStyle += "margin-left: -" + cm.display.gutters.offsetWidth + "px;" }
     2359    if (widget.noHScroll)
     2360      { parentStyle += "width: " + cm.display.wrapper.clientWidth + "px;" }
     2361    removeChildrenAndAdd(cm.display.measure, elt("div", [widget.node], null, parentStyle))
     2362  }
     2363  return widget.height = widget.node.parentNode.offsetHeight
     2364}
     2365
     2366// Return true when the given mouse event happened in a widget
     2367function eventInWidget(display, e) {
     2368  for (var n = e_target(e); n != display.wrapper; n = n.parentNode) {
     2369    if (!n || (n.nodeType == 1 && n.getAttribute("cm-ignore-events") == "true") ||
     2370        (n.parentNode == display.sizer && n != display.mover))
     2371      { return true }
     2372  }
     2373}
     2374
     2375// POSITION MEASUREMENT
     2376
     2377function paddingTop(display) {return display.lineSpace.offsetTop}
     2378function paddingVert(display) {return display.mover.offsetHeight - display.lineSpace.offsetHeight}
     2379function paddingH(display) {
     2380  if (display.cachedPaddingH) { return display.cachedPaddingH }
     2381  var e = removeChildrenAndAdd(display.measure, elt("pre", "x"))
     2382  var style = window.getComputedStyle ? window.getComputedStyle(e) : e.currentStyle
     2383  var data = {left: parseInt(style.paddingLeft), right: parseInt(style.paddingRight)}
     2384  if (!isNaN(data.left) && !isNaN(data.right)) { display.cachedPaddingH = data }
     2385  return data
     2386}
     2387
     2388function scrollGap(cm) { return scrollerGap - cm.display.nativeBarWidth }
     2389function displayWidth(cm) {
     2390  return cm.display.scroller.clientWidth - scrollGap(cm) - cm.display.barWidth
     2391}
     2392function displayHeight(cm) {
     2393  return cm.display.scroller.clientHeight - scrollGap(cm) - cm.display.barHeight
     2394}
     2395
     2396// Ensure the lineView.wrapping.heights array is populated. This is
     2397// an array of bottom offsets for the lines that make up a drawn
     2398// line. When lineWrapping is on, there might be more than one
     2399// height.
     2400function ensureLineHeights(cm, lineView, rect) {
     2401  var wrapping = cm.options.lineWrapping
     2402  var curWidth = wrapping && displayWidth(cm)
     2403  if (!lineView.measure.heights || wrapping && lineView.measure.width != curWidth) {
     2404    var heights = lineView.measure.heights = []
     2405    if (wrapping) {
     2406      lineView.measure.width = curWidth
     2407      var rects = lineView.text.firstChild.getClientRects()
     2408      for (var i = 0; i < rects.length - 1; i++) {
     2409        var cur = rects[i], next = rects[i + 1]
     2410        if (Math.abs(cur.bottom - next.bottom) > 2)
     2411          { heights.push((cur.bottom + next.top) / 2 - rect.top) }
    3832412      }
    384       slowPoll();
    385       restartBlink();
    386     }
    387     function onBlur() {
    388       if (focused) {
    389         if (options.onBlur) options.onBlur(instance);
    390         focused = false;
    391         wrapper.className = wrapper.className.replace(" CodeMirror-focused", "");
     2413    }
     2414    heights.push(rect.bottom - rect.top)
     2415  }
     2416}
     2417
     2418// Find a line map (mapping character offsets to text nodes) and a
     2419// measurement cache for the given line number. (A line view might
     2420// contain multiple lines when collapsed ranges are present.)
     2421function mapFromLineView(lineView, line, lineN) {
     2422  if (lineView.line == line)
     2423    { return {map: lineView.measure.map, cache: lineView.measure.cache} }
     2424  for (var i = 0; i < lineView.rest.length; i++)
     2425    { if (lineView.rest[i] == line)
     2426      { return {map: lineView.measure.maps[i], cache: lineView.measure.caches[i]} } }
     2427  for (var i$1 = 0; i$1 < lineView.rest.length; i$1++)
     2428    { if (lineNo(lineView.rest[i$1]) > lineN)
     2429      { return {map: lineView.measure.maps[i$1], cache: lineView.measure.caches[i$1], before: true} } }
     2430}
     2431
     2432// Render a line into the hidden node display.externalMeasured. Used
     2433// when measurement is needed for a line that's not in the viewport.
     2434function updateExternalMeasurement(cm, line) {
     2435  line = visualLine(line)
     2436  var lineN = lineNo(line)
     2437  var view = cm.display.externalMeasured = new LineView(cm.doc, line, lineN)
     2438  view.lineN = lineN
     2439  var built = view.built = buildLineContent(cm, view)
     2440  view.text = built.pre
     2441  removeChildrenAndAdd(cm.display.lineMeasure, built.pre)
     2442  return view
     2443}
     2444
     2445// Get a {top, bottom, left, right} box (in line-local coordinates)
     2446// for a given character.
     2447function measureChar(cm, line, ch, bias) {
     2448  return measureCharPrepared(cm, prepareMeasureForLine(cm, line), ch, bias)
     2449}
     2450
     2451// Find a line view that corresponds to the given line number.
     2452function findViewForLine(cm, lineN) {
     2453  if (lineN >= cm.display.viewFrom && lineN < cm.display.viewTo)
     2454    { return cm.display.view[findViewIndex(cm, lineN)] }
     2455  var ext = cm.display.externalMeasured
     2456  if (ext && lineN >= ext.lineN && lineN < ext.lineN + ext.size)
     2457    { return ext }
     2458}
     2459
     2460// Measurement can be split in two steps, the set-up work that
     2461// applies to the whole line, and the measurement of the actual
     2462// character. Functions like coordsChar, that need to do a lot of
     2463// measurements in a row, can thus ensure that the set-up work is
     2464// only done once.
     2465function prepareMeasureForLine(cm, line) {
     2466  var lineN = lineNo(line)
     2467  var view = findViewForLine(cm, lineN)
     2468  if (view && !view.text) {
     2469    view = null
     2470  } else if (view && view.changes) {
     2471    updateLineForChanges(cm, view, lineN, getDimensions(cm))
     2472    cm.curOp.forceUpdate = true
     2473  }
     2474  if (!view)
     2475    { view = updateExternalMeasurement(cm, line) }
     2476
     2477  var info = mapFromLineView(view, line, lineN)
     2478  return {
     2479    line: line, view: view, rect: null,
     2480    map: info.map, cache: info.cache, before: info.before,
     2481    hasHeights: false
     2482  }
     2483}
     2484
     2485// Given a prepared measurement object, measures the position of an
     2486// actual character (or fetches it from the cache).
     2487function measureCharPrepared(cm, prepared, ch, bias, varHeight) {
     2488  if (prepared.before) { ch = -1 }
     2489  var key = ch + (bias || ""), found
     2490  if (prepared.cache.hasOwnProperty(key)) {
     2491    found = prepared.cache[key]
     2492  } else {
     2493    if (!prepared.rect)
     2494      { prepared.rect = prepared.view.text.getBoundingClientRect() }
     2495    if (!prepared.hasHeights) {
     2496      ensureLineHeights(cm, prepared.view, prepared.rect)
     2497      prepared.hasHeights = true
     2498    }
     2499    found = measureCharInner(cm, prepared, ch, bias)
     2500    if (!found.bogus) { prepared.cache[key] = found }
     2501  }
     2502  return {left: found.left, right: found.right,
     2503          top: varHeight ? found.rtop : found.top,
     2504          bottom: varHeight ? found.rbottom : found.bottom}
     2505}
     2506
     2507var nullRect = {left: 0, right: 0, top: 0, bottom: 0}
     2508
     2509function nodeAndOffsetInLineMap(map, ch, bias) {
     2510  var node, start, end, collapse, mStart, mEnd
     2511  // First, search the line map for the text node corresponding to,
     2512  // or closest to, the target character.
     2513  for (var i = 0; i < map.length; i += 3) {
     2514    mStart = map[i]
     2515    mEnd = map[i + 1]
     2516    if (ch < mStart) {
     2517      start = 0; end = 1
     2518      collapse = "left"
     2519    } else if (ch < mEnd) {
     2520      start = ch - mStart
     2521      end = start + 1
     2522    } else if (i == map.length - 3 || ch == mEnd && map[i + 3] > ch) {
     2523      end = mEnd - mStart
     2524      start = end - 1
     2525      if (ch >= mEnd) { collapse = "right" }
     2526    }
     2527    if (start != null) {
     2528      node = map[i + 2]
     2529      if (mStart == mEnd && bias == (node.insertLeft ? "left" : "right"))
     2530        { collapse = bias }
     2531      if (bias == "left" && start == 0)
     2532        { while (i && map[i - 2] == map[i - 3] && map[i - 1].insertLeft) {
     2533          node = map[(i -= 3) + 2]
     2534          collapse = "left"
     2535        } }
     2536      if (bias == "right" && start == mEnd - mStart)
     2537        { while (i < map.length - 3 && map[i + 3] == map[i + 4] && !map[i + 5].insertLeft) {
     2538          node = map[(i += 3) + 2]
     2539          collapse = "right"
     2540        } }
     2541      break
     2542    }
     2543  }
     2544  return {node: node, start: start, end: end, collapse: collapse, coverStart: mStart, coverEnd: mEnd}
     2545}
     2546
     2547function getUsefulRect(rects, bias) {
     2548  var rect = nullRect
     2549  if (bias == "left") { for (var i = 0; i < rects.length; i++) {
     2550    if ((rect = rects[i]).left != rect.right) { break }
     2551  } } else { for (var i$1 = rects.length - 1; i$1 >= 0; i$1--) {
     2552    if ((rect = rects[i$1]).left != rect.right) { break }
     2553  } }
     2554  return rect
     2555}
     2556
     2557function measureCharInner(cm, prepared, ch, bias) {
     2558  var place = nodeAndOffsetInLineMap(prepared.map, ch, bias)
     2559  var node = place.node, start = place.start, end = place.end, collapse = place.collapse
     2560
     2561  var rect
     2562  if (node.nodeType == 3) { // If it is a text node, use a range to retrieve the coordinates.
     2563    for (var i$1 = 0; i$1 < 4; i$1++) { // Retry a maximum of 4 times when nonsense rectangles are returned
     2564      while (start && isExtendingChar(prepared.line.text.charAt(place.coverStart + start))) { --start }
     2565      while (place.coverStart + end < place.coverEnd && isExtendingChar(prepared.line.text.charAt(place.coverStart + end))) { ++end }
     2566      if (ie && ie_version < 9 && start == 0 && end == place.coverEnd - place.coverStart)
     2567        { rect = node.parentNode.getBoundingClientRect() }
     2568      else
     2569        { rect = getUsefulRect(range(node, start, end).getClientRects(), bias) }
     2570      if (rect.left || rect.right || start == 0) { break }
     2571      end = start
     2572      start = start - 1
     2573      collapse = "right"
     2574    }
     2575    if (ie && ie_version < 11) { rect = maybeUpdateRectForZooming(cm.display.measure, rect) }
     2576  } else { // If it is a widget, simply get the box for the whole widget.
     2577    if (start > 0) { collapse = bias = "right" }
     2578    var rects
     2579    if (cm.options.lineWrapping && (rects = node.getClientRects()).length > 1)
     2580      { rect = rects[bias == "right" ? rects.length - 1 : 0] }
     2581    else
     2582      { rect = node.getBoundingClientRect() }
     2583  }
     2584  if (ie && ie_version < 9 && !start && (!rect || !rect.left && !rect.right)) {
     2585    var rSpan = node.parentNode.getClientRects()[0]
     2586    if (rSpan)
     2587      { rect = {left: rSpan.left, right: rSpan.left + charWidth(cm.display), top: rSpan.top, bottom: rSpan.bottom} }
     2588    else
     2589      { rect = nullRect }
     2590  }
     2591
     2592  var rtop = rect.top - prepared.rect.top, rbot = rect.bottom - prepared.rect.top
     2593  var mid = (rtop + rbot) / 2
     2594  var heights = prepared.view.measure.heights
     2595  var i = 0
     2596  for (; i < heights.length - 1; i++)
     2597    { if (mid < heights[i]) { break } }
     2598  var top = i ? heights[i - 1] : 0, bot = heights[i]
     2599  var result = {left: (collapse == "right" ? rect.right : rect.left) - prepared.rect.left,
     2600                right: (collapse == "left" ? rect.left : rect.right) - prepared.rect.left,
     2601                top: top, bottom: bot}
     2602  if (!rect.left && !rect.right) { result.bogus = true }
     2603  if (!cm.options.singleCursorHeightPerLine) { result.rtop = rtop; result.rbottom = rbot }
     2604
     2605  return result
     2606}
     2607
     2608// Work around problem with bounding client rects on ranges being
     2609// returned incorrectly when zoomed on IE10 and below.
     2610function maybeUpdateRectForZooming(measure, rect) {
     2611  if (!window.screen || screen.logicalXDPI == null ||
     2612      screen.logicalXDPI == screen.deviceXDPI || !hasBadZoomedRects(measure))
     2613    { return rect }
     2614  var scaleX = screen.logicalXDPI / screen.deviceXDPI
     2615  var scaleY = screen.logicalYDPI / screen.deviceYDPI
     2616  return {left: rect.left * scaleX, right: rect.right * scaleX,
     2617          top: rect.top * scaleY, bottom: rect.bottom * scaleY}
     2618}
     2619
     2620function clearLineMeasurementCacheFor(lineView) {
     2621  if (lineView.measure) {
     2622    lineView.measure.cache = {}
     2623    lineView.measure.heights = null
     2624    if (lineView.rest) { for (var i = 0; i < lineView.rest.length; i++)
     2625      { lineView.measure.caches[i] = {} } }
     2626  }
     2627}
     2628
     2629function clearLineMeasurementCache(cm) {
     2630  cm.display.externalMeasure = null
     2631  removeChildren(cm.display.lineMeasure)
     2632  for (var i = 0; i < cm.display.view.length; i++)
     2633    { clearLineMeasurementCacheFor(cm.display.view[i]) }
     2634}
     2635
     2636function clearCaches(cm) {
     2637  clearLineMeasurementCache(cm)
     2638  cm.display.cachedCharWidth = cm.display.cachedTextHeight = cm.display.cachedPaddingH = null
     2639  if (!cm.options.lineWrapping) { cm.display.maxLineChanged = true }
     2640  cm.display.lineNumChars = null
     2641}
     2642
     2643function pageScrollX() {
     2644  // Work around https://bugs.chromium.org/p/chromium/issues/detail?id=489206
     2645  // which causes page_Offset and bounding client rects to use
     2646  // different reference viewports and invalidate our calculations.
     2647  if (chrome && android) { return -(document.body.getBoundingClientRect().left - parseInt(getComputedStyle(document.body).marginLeft)) }
     2648  return window.pageXOffset || (document.documentElement || document.body).scrollLeft
     2649}
     2650function pageScrollY() {
     2651  if (chrome && android) { return -(document.body.getBoundingClientRect().top - parseInt(getComputedStyle(document.body).marginTop)) }
     2652  return window.pageYOffset || (document.documentElement || document.body).scrollTop
     2653}
     2654
     2655function widgetTopHeight(lineObj) {
     2656  var height = 0
     2657  if (lineObj.widgets) { for (var i = 0; i < lineObj.widgets.length; ++i) { if (lineObj.widgets[i].above)
     2658    { height += widgetHeight(lineObj.widgets[i]) } } }
     2659  return height
     2660}
     2661
     2662// Converts a {top, bottom, left, right} box from line-local
     2663// coordinates into another coordinate system. Context may be one of
     2664// "line", "div" (display.lineDiv), "local"./null (editor), "window",
     2665// or "page".
     2666function intoCoordSystem(cm, lineObj, rect, context, includeWidgets) {
     2667  if (!includeWidgets) {
     2668    var height = widgetTopHeight(lineObj)
     2669    rect.top += height; rect.bottom += height
     2670  }
     2671  if (context == "line") { return rect }
     2672  if (!context) { context = "local" }
     2673  var yOff = heightAtLine(lineObj)
     2674  if (context == "local") { yOff += paddingTop(cm.display) }
     2675  else { yOff -= cm.display.viewOffset }
     2676  if (context == "page" || context == "window") {
     2677    var lOff = cm.display.lineSpace.getBoundingClientRect()
     2678    yOff += lOff.top + (context == "window" ? 0 : pageScrollY())
     2679    var xOff = lOff.left + (context == "window" ? 0 : pageScrollX())
     2680    rect.left += xOff; rect.right += xOff
     2681  }
     2682  rect.top += yOff; rect.bottom += yOff
     2683  return rect
     2684}
     2685
     2686// Coverts a box from "div" coords to another coordinate system.
     2687// Context may be "window", "page", "div", or "local"./null.
     2688function fromCoordSystem(cm, coords, context) {
     2689  if (context == "div") { return coords }
     2690  var left = coords.left, top = coords.top
     2691  // First move into "page" coordinate system
     2692  if (context == "page") {
     2693    left -= pageScrollX()
     2694    top -= pageScrollY()
     2695  } else if (context == "local" || !context) {
     2696    var localBox = cm.display.sizer.getBoundingClientRect()
     2697    left += localBox.left
     2698    top += localBox.top
     2699  }
     2700
     2701  var lineSpaceBox = cm.display.lineSpace.getBoundingClientRect()
     2702  return {left: left - lineSpaceBox.left, top: top - lineSpaceBox.top}
     2703}
     2704
     2705function charCoords(cm, pos, context, lineObj, bias) {
     2706  if (!lineObj) { lineObj = getLine(cm.doc, pos.line) }
     2707  return intoCoordSystem(cm, lineObj, measureChar(cm, lineObj, pos.ch, bias), context)
     2708}
     2709
     2710// Returns a box for a given cursor position, which may have an
     2711// 'other' property containing the position of the secondary cursor
     2712// on a bidi boundary.
     2713// A cursor Pos(line, char, "before") is on the same visual line as `char - 1`
     2714// and after `char - 1` in writing order of `char - 1`
     2715// A cursor Pos(line, char, "after") is on the same visual line as `char`
     2716// and before `char` in writing order of `char`
     2717// Examples (upper-case letters are RTL, lower-case are LTR):
     2718//     Pos(0, 1, ...)
     2719//     before   after
     2720// ab     a|b     a|b
     2721// aB     a|B     aB|
     2722// Ab     |Ab     A|b
     2723// AB     B|A     B|A
     2724// Every position after the last character on a line is considered to stick
     2725// to the last character on the line.
     2726function cursorCoords(cm, pos, context, lineObj, preparedMeasure, varHeight) {
     2727  lineObj = lineObj || getLine(cm.doc, pos.line)
     2728  if (!preparedMeasure) { preparedMeasure = prepareMeasureForLine(cm, lineObj) }
     2729  function get(ch, right) {
     2730    var m = measureCharPrepared(cm, preparedMeasure, ch, right ? "right" : "left", varHeight)
     2731    if (right) { m.left = m.right; } else { m.right = m.left }
     2732    return intoCoordSystem(cm, lineObj, m, context)
     2733  }
     2734  var order = getOrder(lineObj, cm.doc.direction), ch = pos.ch, sticky = pos.sticky
     2735  if (ch >= lineObj.text.length) {
     2736    ch = lineObj.text.length
     2737    sticky = "before"
     2738  } else if (ch <= 0) {
     2739    ch = 0
     2740    sticky = "after"
     2741  }
     2742  if (!order) { return get(sticky == "before" ? ch - 1 : ch, sticky == "before") }
     2743
     2744  function getBidi(ch, partPos, invert) {
     2745    var part = order[partPos], right = part.level == 1
     2746    return get(invert ? ch - 1 : ch, right != invert)
     2747  }
     2748  var partPos = getBidiPartAt(order, ch, sticky)
     2749  var other = bidiOther
     2750  var val = getBidi(ch, partPos, sticky == "before")
     2751  if (other != null) { val.other = getBidi(ch, other, sticky != "before") }
     2752  return val
     2753}
     2754
     2755// Used to cheaply estimate the coordinates for a position. Used for
     2756// intermediate scroll updates.
     2757function estimateCoords(cm, pos) {
     2758  var left = 0
     2759  pos = clipPos(cm.doc, pos)
     2760  if (!cm.options.lineWrapping) { left = charWidth(cm.display) * pos.ch }
     2761  var lineObj = getLine(cm.doc, pos.line)
     2762  var top = heightAtLine(lineObj) + paddingTop(cm.display)
     2763  return {left: left, right: left, top: top, bottom: top + lineObj.height}
     2764}
     2765
     2766// Positions returned by coordsChar contain some extra information.
     2767// xRel is the relative x position of the input coordinates compared
     2768// to the found position (so xRel > 0 means the coordinates are to
     2769// the right of the character position, for example). When outside
     2770// is true, that means the coordinates lie outside the line's
     2771// vertical range.
     2772function PosWithInfo(line, ch, sticky, outside, xRel) {
     2773  var pos = Pos(line, ch, sticky)
     2774  pos.xRel = xRel
     2775  if (outside) { pos.outside = true }
     2776  return pos
     2777}
     2778
     2779// Compute the character position closest to the given coordinates.
     2780// Input must be lineSpace-local ("div" coordinate system).
     2781function coordsChar(cm, x, y) {
     2782  var doc = cm.doc
     2783  y += cm.display.viewOffset
     2784  if (y < 0) { return PosWithInfo(doc.first, 0, null, true, -1) }
     2785  var lineN = lineAtHeight(doc, y), last = doc.first + doc.size - 1
     2786  if (lineN > last)
     2787    { return PosWithInfo(doc.first + doc.size - 1, getLine(doc, last).text.length, null, true, 1) }
     2788  if (x < 0) { x = 0 }
     2789
     2790  var lineObj = getLine(doc, lineN)
     2791  for (;;) {
     2792    var found = coordsCharInner(cm, lineObj, lineN, x, y)
     2793    var collapsed = collapsedSpanAround(lineObj, found.ch + (found.xRel > 0 ? 1 : 0))
     2794    if (!collapsed) { return found }
     2795    var rangeEnd = collapsed.find(1)
     2796    if (rangeEnd.line == lineN) { return rangeEnd }
     2797    lineObj = getLine(doc, lineN = rangeEnd.line)
     2798  }
     2799}
     2800
     2801function wrappedLineExtent(cm, lineObj, preparedMeasure, y) {
     2802  y -= widgetTopHeight(lineObj)
     2803  var end = lineObj.text.length
     2804  var begin = findFirst(function (ch) { return measureCharPrepared(cm, preparedMeasure, ch - 1).bottom <= y; }, end, 0)
     2805  end = findFirst(function (ch) { return measureCharPrepared(cm, preparedMeasure, ch).top > y; }, begin, end)
     2806  return {begin: begin, end: end}
     2807}
     2808
     2809function wrappedLineExtentChar(cm, lineObj, preparedMeasure, target) {
     2810  if (!preparedMeasure) { preparedMeasure = prepareMeasureForLine(cm, lineObj) }
     2811  var targetTop = intoCoordSystem(cm, lineObj, measureCharPrepared(cm, preparedMeasure, target), "line").top
     2812  return wrappedLineExtent(cm, lineObj, preparedMeasure, targetTop)
     2813}
     2814
     2815// Returns true if the given side of a box is after the given
     2816// coordinates, in top-to-bottom, left-to-right order.
     2817function boxIsAfter(box, x, y, left) {
     2818  return box.bottom <= y ? false : box.top > y ? true : (left ? box.left : box.right) > x
     2819}
     2820
     2821function coordsCharInner(cm, lineObj, lineNo, x, y) {
     2822  // Move y into line-local coordinate space
     2823  y -= heightAtLine(lineObj)
     2824  var preparedMeasure = prepareMeasureForLine(cm, lineObj)
     2825  // When directly calling `measureCharPrepared`, we have to adjust
     2826  // for the widgets at this line.
     2827  var widgetHeight = widgetTopHeight(lineObj)
     2828  var begin = 0, end = lineObj.text.length, ltr = true
     2829
     2830  var order = getOrder(lineObj, cm.doc.direction)
     2831  // If the line isn't plain left-to-right text, first figure out
     2832  // which bidi section the coordinates fall into.
     2833  if (order) {
     2834    var part = (cm.options.lineWrapping ? coordsBidiPartWrapped : coordsBidiPart)
     2835                 (cm, lineObj, lineNo, preparedMeasure, order, x, y)
     2836    ltr = part.level != 1
     2837    // The awkward -1 offsets are needed because findFirst (called
     2838    // on these below) will treat its first bound as inclusive,
     2839    // second as exclusive, but we want to actually address the
     2840    // characters in the part's range
     2841    begin = ltr ? part.from : part.to - 1
     2842    end = ltr ? part.to : part.from - 1
     2843  }
     2844
     2845  // A binary search to find the first character whose bounding box
     2846  // starts after the coordinates. If we run across any whose box wrap
     2847  // the coordinates, store that.
     2848  var chAround = null, boxAround = null
     2849  var ch = findFirst(function (ch) {
     2850    var box = measureCharPrepared(cm, preparedMeasure, ch)
     2851    box.top += widgetHeight; box.bottom += widgetHeight
     2852    if (!boxIsAfter(box, x, y, false)) { return false }
     2853    if (box.top <= y && box.left <= x) {
     2854      chAround = ch
     2855      boxAround = box
     2856    }
     2857    return true
     2858  }, begin, end)
     2859
     2860  var baseX, sticky, outside = false
     2861  // If a box around the coordinates was found, use that
     2862  if (boxAround) {
     2863    // Distinguish coordinates nearer to the left or right side of the box
     2864    var atLeft = x - boxAround.left < boxAround.right - x, atStart = atLeft == ltr
     2865    ch = chAround + (atStart ? 0 : 1)
     2866    sticky = atStart ? "after" : "before"
     2867    baseX = atLeft ? boxAround.left : boxAround.right
     2868  } else {
     2869    // (Adjust for extended bound, if necessary.)
     2870    if (!ltr && (ch == end || ch == begin)) { ch++ }
     2871    // To determine which side to associate with, get the box to the
     2872    // left of the character and compare it's vertical position to the
     2873    // coordinates
     2874    sticky = ch == 0 ? "after" : ch == lineObj.text.length ? "before" :
     2875      (measureCharPrepared(cm, preparedMeasure, ch - (ltr ? 1 : 0)).bottom + widgetHeight <= y) == ltr ?
     2876      "after" : "before"
     2877    // Now get accurate coordinates for this place, in order to get a
     2878    // base X position
     2879    var coords = cursorCoords(cm, Pos(lineNo, ch, sticky), "line", lineObj, preparedMeasure)
     2880    baseX = coords.left
     2881    outside = y < coords.top || y >= coords.bottom
     2882  }
     2883
     2884  ch = skipExtendingChars(lineObj.text, ch, 1)
     2885  return PosWithInfo(lineNo, ch, sticky, outside, x - baseX)
     2886}
     2887
     2888function coordsBidiPart(cm, lineObj, lineNo, preparedMeasure, order, x, y) {
     2889  // Bidi parts are sorted left-to-right, and in a non-line-wrapping
     2890  // situation, we can take this ordering to correspond to the visual
     2891  // ordering. This finds the first part whose end is after the given
     2892  // coordinates.
     2893  var index = findFirst(function (i) {
     2894    var part = order[i], ltr = part.level != 1
     2895    return boxIsAfter(cursorCoords(cm, Pos(lineNo, ltr ? part.to : part.from, ltr ? "before" : "after"),
     2896                                   "line", lineObj, preparedMeasure), x, y, true)
     2897  }, 0, order.length - 1)
     2898  var part = order[index]
     2899  // If this isn't the first part, the part's start is also after
     2900  // the coordinates, and the coordinates aren't on the same line as
     2901  // that start, move one part back.
     2902  if (index > 0) {
     2903    var ltr = part.level != 1
     2904    var start = cursorCoords(cm, Pos(lineNo, ltr ? part.from : part.to, ltr ? "after" : "before"),
     2905                             "line", lineObj, preparedMeasure)
     2906    if (boxIsAfter(start, x, y, true) && start.top > y)
     2907      { part = order[index - 1] }
     2908  }
     2909  return part
     2910}
     2911
     2912function coordsBidiPartWrapped(cm, lineObj, _lineNo, preparedMeasure, order, x, y) {
     2913  // In a wrapped line, rtl text on wrapping boundaries can do things
     2914  // that don't correspond to the ordering in our `order` array at
     2915  // all, so a binary search doesn't work, and we want to return a
     2916  // part that only spans one line so that the binary search in
     2917  // coordsCharInner is safe. As such, we first find the extent of the
     2918  // wrapped line, and then do a flat search in which we discard any
     2919  // spans that aren't on the line.
     2920  var ref = wrappedLineExtent(cm, lineObj, preparedMeasure, y);
     2921  var begin = ref.begin;
     2922  var end = ref.end;
     2923  if (/\s/.test(lineObj.text.charAt(end - 1))) { end-- }
     2924  var part = null, closestDist = null
     2925  for (var i = 0; i < order.length; i++) {
     2926    var p = order[i]
     2927    if (p.from >= end || p.to <= begin) { continue }
     2928    var ltr = p.level != 1
     2929    var endX = measureCharPrepared(cm, preparedMeasure, ltr ? Math.min(end, p.to) - 1 : Math.max(begin, p.from)).right
     2930    // Weigh against spans ending before this, so that they are only
     2931    // picked if nothing ends after
     2932    var dist = endX < x ? x - endX + 1e9 : endX - x
     2933    if (!part || closestDist > dist) {
     2934      part = p
     2935      closestDist = dist
     2936    }
     2937  }
     2938  if (!part) { part = order[order.length - 1] }
     2939  // Clip the part to the wrapped line.
     2940  if (part.from < begin) { part = {from: begin, to: part.to, level: part.level} }
     2941  if (part.to > end) { part = {from: part.from, to: end, level: part.level} }
     2942  return part
     2943}
     2944
     2945var measureText
     2946// Compute the default text height.
     2947function textHeight(display) {
     2948  if (display.cachedTextHeight != null) { return display.cachedTextHeight }
     2949  if (measureText == null) {
     2950    measureText = elt("pre")
     2951    // Measure a bunch of lines, for browsers that compute
     2952    // fractional heights.
     2953    for (var i = 0; i < 49; ++i) {
     2954      measureText.appendChild(document.createTextNode("x"))
     2955      measureText.appendChild(elt("br"))
     2956    }
     2957    measureText.appendChild(document.createTextNode("x"))
     2958  }
     2959  removeChildrenAndAdd(display.measure, measureText)
     2960  var height = measureText.offsetHeight / 50
     2961  if (height > 3) { display.cachedTextHeight = height }
     2962  removeChildren(display.measure)
     2963  return height || 1
     2964}
     2965
     2966// Compute the default character width.
     2967function charWidth(display) {
     2968  if (display.cachedCharWidth != null) { return display.cachedCharWidth }
     2969  var anchor = elt("span", "xxxxxxxxxx")
     2970  var pre = elt("pre", [anchor])
     2971  removeChildrenAndAdd(display.measure, pre)
     2972  var rect = anchor.getBoundingClientRect(), width = (rect.right - rect.left) / 10
     2973  if (width > 2) { display.cachedCharWidth = width }
     2974  return width || 10
     2975}
     2976
     2977// Do a bulk-read of the DOM positions and sizes needed to draw the
     2978// view, so that we don't interleave reading and writing to the DOM.
     2979function getDimensions(cm) {
     2980  var d = cm.display, left = {}, width = {}
     2981  var gutterLeft = d.gutters.clientLeft
     2982  for (var n = d.gutters.firstChild, i = 0; n; n = n.nextSibling, ++i) {
     2983    left[cm.options.gutters[i]] = n.offsetLeft + n.clientLeft + gutterLeft
     2984    width[cm.options.gutters[i]] = n.clientWidth
     2985  }
     2986  return {fixedPos: compensateForHScroll(d),
     2987          gutterTotalWidth: d.gutters.offsetWidth,
     2988          gutterLeft: left,
     2989          gutterWidth: width,
     2990          wrapperWidth: d.wrapper.clientWidth}
     2991}
     2992
     2993// Computes display.scroller.scrollLeft + display.gutters.offsetWidth,
     2994// but using getBoundingClientRect to get a sub-pixel-accurate
     2995// result.
     2996function compensateForHScroll(display) {
     2997  return display.scroller.getBoundingClientRect().left - display.sizer.getBoundingClientRect().left
     2998}
     2999
     3000// Returns a function that estimates the height of a line, to use as
     3001// first approximation until the line becomes visible (and is thus
     3002// properly measurable).
     3003function estimateHeight(cm) {
     3004  var th = textHeight(cm.display), wrapping = cm.options.lineWrapping
     3005  var perLine = wrapping && Math.max(5, cm.display.scroller.clientWidth / charWidth(cm.display) - 3)
     3006  return function (line) {
     3007    if (lineIsHidden(cm.doc, line)) { return 0 }
     3008
     3009    var widgetsHeight = 0
     3010    if (line.widgets) { for (var i = 0; i < line.widgets.length; i++) {
     3011      if (line.widgets[i].height) { widgetsHeight += line.widgets[i].height }
     3012    } }
     3013
     3014    if (wrapping)
     3015      { return widgetsHeight + (Math.ceil(line.text.length / perLine) || 1) * th }
     3016    else
     3017      { return widgetsHeight + th }
     3018  }
     3019}
     3020
     3021function estimateLineHeights(cm) {
     3022  var doc = cm.doc, est = estimateHeight(cm)
     3023  doc.iter(function (line) {
     3024    var estHeight = est(line)
     3025    if (estHeight != line.height) { updateLineHeight(line, estHeight) }
     3026  })
     3027}
     3028
     3029// Given a mouse event, find the corresponding position. If liberal
     3030// is false, it checks whether a gutter or scrollbar was clicked,
     3031// and returns null if it was. forRect is used by rectangular
     3032// selections, and tries to estimate a character position even for
     3033// coordinates beyond the right of the text.
     3034function posFromMouse(cm, e, liberal, forRect) {
     3035  var display = cm.display
     3036  if (!liberal && e_target(e).getAttribute("cm-not-content") == "true") { return null }
     3037
     3038  var x, y, space = display.lineSpace.getBoundingClientRect()
     3039  // Fails unpredictably on IE[67] when mouse is dragged around quickly.
     3040  try { x = e.clientX - space.left; y = e.clientY - space.top }
     3041  catch (e) { return null }
     3042  var coords = coordsChar(cm, x, y), line
     3043  if (forRect && coords.xRel == 1 && (line = getLine(cm.doc, coords.line).text).length == coords.ch) {
     3044    var colDiff = countColumn(line, line.length, cm.options.tabSize) - line.length
     3045    coords = Pos(coords.line, Math.max(0, Math.round((x - paddingH(cm.display).left) / charWidth(cm.display)) - colDiff))
     3046  }
     3047  return coords
     3048}
     3049
     3050// Find the view element corresponding to a given line. Return null
     3051// when the line isn't visible.
     3052function findViewIndex(cm, n) {
     3053  if (n >= cm.display.viewTo) { return null }
     3054  n -= cm.display.viewFrom
     3055  if (n < 0) { return null }
     3056  var view = cm.display.view
     3057  for (var i = 0; i < view.length; i++) {
     3058    n -= view[i].size
     3059    if (n < 0) { return i }
     3060  }
     3061}
     3062
     3063function updateSelection(cm) {
     3064  cm.display.input.showSelection(cm.display.input.prepareSelection())
     3065}
     3066
     3067function prepareSelection(cm, primary) {
     3068  if ( primary === void 0 ) primary = true;
     3069
     3070  var doc = cm.doc, result = {}
     3071  var curFragment = result.cursors = document.createDocumentFragment()
     3072  var selFragment = result.selection = document.createDocumentFragment()
     3073
     3074  for (var i = 0; i < doc.sel.ranges.length; i++) {
     3075    if (!primary && i == doc.sel.primIndex) { continue }
     3076    var range = doc.sel.ranges[i]
     3077    if (range.from().line >= cm.display.viewTo || range.to().line < cm.display.viewFrom) { continue }
     3078    var collapsed = range.empty()
     3079    if (collapsed || cm.options.showCursorWhenSelecting)
     3080      { drawSelectionCursor(cm, range.head, curFragment) }
     3081    if (!collapsed)
     3082      { drawSelectionRange(cm, range, selFragment) }
     3083  }
     3084  return result
     3085}
     3086
     3087// Draws a cursor for the given range
     3088function drawSelectionCursor(cm, head, output) {
     3089  var pos = cursorCoords(cm, head, "div", null, null, !cm.options.singleCursorHeightPerLine)
     3090
     3091  var cursor = output.appendChild(elt("div", "\u00a0", "CodeMirror-cursor"))
     3092  cursor.style.left = pos.left + "px"
     3093  cursor.style.top = pos.top + "px"
     3094  cursor.style.height = Math.max(0, pos.bottom - pos.top) * cm.options.cursorHeight + "px"
     3095
     3096  if (pos.other) {
     3097    // Secondary cursor, shown when on a 'jump' in bi-directional text
     3098    var otherCursor = output.appendChild(elt("div", "\u00a0", "CodeMirror-cursor CodeMirror-secondarycursor"))
     3099    otherCursor.style.display = ""
     3100    otherCursor.style.left = pos.other.left + "px"
     3101    otherCursor.style.top = pos.other.top + "px"
     3102    otherCursor.style.height = (pos.other.bottom - pos.other.top) * .85 + "px"
     3103  }
     3104}
     3105
     3106function cmpCoords(a, b) { return a.top - b.top || a.left - b.left }
     3107
     3108// Draws the given range as a highlighted selection
     3109function drawSelectionRange(cm, range, output) {
     3110  var display = cm.display, doc = cm.doc
     3111  var fragment = document.createDocumentFragment()
     3112  var padding = paddingH(cm.display), leftSide = padding.left
     3113  var rightSide = Math.max(display.sizerWidth, displayWidth(cm) - display.sizer.offsetLeft) - padding.right
     3114  var docLTR = doc.direction == "ltr"
     3115
     3116  function add(left, top, width, bottom) {
     3117    if (top < 0) { top = 0 }
     3118    top = Math.round(top)
     3119    bottom = Math.round(bottom)
     3120    fragment.appendChild(elt("div", null, "CodeMirror-selected", ("position: absolute; left: " + left + "px;\n                             top: " + top + "px; width: " + (width == null ? rightSide - left : width) + "px;\n                             height: " + (bottom - top) + "px")))
     3121  }
     3122
     3123  function drawForLine(line, fromArg, toArg) {
     3124    var lineObj = getLine(doc, line)
     3125    var lineLen = lineObj.text.length
     3126    var start, end
     3127    function coords(ch, bias) {
     3128      return charCoords(cm, Pos(line, ch), "div", lineObj, bias)
     3129    }
     3130
     3131    function wrapX(pos, dir, side) {
     3132      var extent = wrappedLineExtentChar(cm, lineObj, null, pos)
     3133      var prop = (dir == "ltr") == (side == "after") ? "left" : "right"
     3134      var ch = side == "after" ? extent.begin : extent.end - (/\s/.test(lineObj.text.charAt(extent.end - 1)) ? 2 : 1)
     3135      return coords(ch, prop)[prop]
     3136    }
     3137
     3138    var order = getOrder(lineObj, doc.direction)
     3139    iterateBidiSections(order, fromArg || 0, toArg == null ? lineLen : toArg, function (from, to, dir, i) {
     3140      var ltr = dir == "ltr"
     3141      var fromPos = coords(from, ltr ? "left" : "right")
     3142      var toPos = coords(to - 1, ltr ? "right" : "left")
     3143
     3144      var openStart = fromArg == null && from == 0, openEnd = toArg == null && to == lineLen
     3145      var first = i == 0, last = !order || i == order.length - 1
     3146      if (toPos.top - fromPos.top <= 3) { // Single line
     3147        var openLeft = (docLTR ? openStart : openEnd) && first
     3148        var openRight = (docLTR ? openEnd : openStart) && last
     3149        var left = openLeft ? leftSide : (ltr ? fromPos : toPos).left
     3150        var right = openRight ? rightSide : (ltr ? toPos : fromPos).right
     3151        add(left, fromPos.top, right - left, fromPos.bottom)
     3152      } else { // Multiple lines
     3153        var topLeft, topRight, botLeft, botRight
     3154        if (ltr) {
     3155          topLeft = docLTR && openStart && first ? leftSide : fromPos.left
     3156          topRight = docLTR ? rightSide : wrapX(from, dir, "before")
     3157          botLeft = docLTR ? leftSide : wrapX(to, dir, "after")
     3158          botRight = docLTR && openEnd && last ? rightSide : toPos.right
     3159        } else {
     3160          topLeft = !docLTR ? leftSide : wrapX(from, dir, "before")
     3161          topRight = !docLTR && openStart && first ? rightSide : fromPos.right
     3162          botLeft = !docLTR && openEnd && last ? leftSide : toPos.left
     3163          botRight = !docLTR ? rightSide : wrapX(to, dir, "after")
     3164        }
     3165        add(topLeft, fromPos.top, topRight - topLeft, fromPos.bottom)
     3166        if (fromPos.bottom < toPos.top) { add(leftSide, fromPos.bottom, null, toPos.top) }
     3167        add(botLeft, toPos.top, botRight - botLeft, toPos.bottom)
    3923168      }
    393       clearInterval(blinker);
    394       setTimeout(function() {if (!focused) shiftSelecting = null;}, 150);
    395     }
    396 
    397     // Replace the range from from to to by the strings in newText.
    398     // Afterwards, set the selection to selFrom, selTo.
    399     function updateLines(from, to, newText, selFrom, selTo) {
    400       if (history) {
    401         var old = [];
    402         for (var i = from.line, e = to.line + 1; i < e; ++i) old.push(lines[i].text);
    403         history.addChange(from.line, newText.length, old);
    404         while (history.done.length > options.undoDepth) history.done.shift();
     3169
     3170      if (!start || cmpCoords(fromPos, start) < 0) { start = fromPos }
     3171      if (cmpCoords(toPos, start) < 0) { start = toPos }
     3172      if (!end || cmpCoords(fromPos, end) < 0) { end = fromPos }
     3173      if (cmpCoords(toPos, end) < 0) { end = toPos }
     3174    })
     3175    return {start: start, end: end}
     3176  }
     3177
     3178  var sFrom = range.from(), sTo = range.to()
     3179  if (sFrom.line == sTo.line) {
     3180    drawForLine(sFrom.line, sFrom.ch, sTo.ch)
     3181  } else {
     3182    var fromLine = getLine(doc, sFrom.line), toLine = getLine(doc, sTo.line)
     3183    var singleVLine = visualLine(fromLine) == visualLine(toLine)
     3184    var leftEnd = drawForLine(sFrom.line, sFrom.ch, singleVLine ? fromLine.text.length + 1 : null).end
     3185    var rightStart = drawForLine(sTo.line, singleVLine ? 0 : null, sTo.ch).start
     3186    if (singleVLine) {
     3187      if (leftEnd.top < rightStart.top - 2) {
     3188        add(leftEnd.right, leftEnd.top, null, leftEnd.bottom)
     3189        add(leftSide, rightStart.top, rightStart.left, rightStart.bottom)
     3190      } else {
     3191        add(leftEnd.right, leftEnd.top, rightStart.left - leftEnd.right, leftEnd.bottom)
    4053192      }
    406       updateLinesNoUndo(from, to, newText, selFrom, selTo);
    407     }
    408     function unredoHelper(from, to) {
    409       var change = from.pop();
    410       if (change) {
    411         var replaced = [], end = change.start + change.added;
    412         for (var i = change.start; i < end; ++i) replaced.push(lines[i].text);
    413         to.push({start: change.start, added: change.old.length, old: replaced});
    414         var pos = clipPos({line: change.start + change.old.length - 1,
    415                            ch: editEnd(replaced[replaced.length-1], change.old[change.old.length-1])});
    416         updateLinesNoUndo({line: change.start, ch: 0}, {line: end - 1, ch: lines[end-1].text.length}, change.old, pos, pos);
     3193    }
     3194    if (leftEnd.bottom < rightStart.top)
     3195      { add(leftSide, leftEnd.bottom, null, rightStart.top) }
     3196  }
     3197
     3198  output.appendChild(fragment)
     3199}
     3200
     3201// Cursor-blinking
     3202function restartBlink(cm) {
     3203  if (!cm.state.focused) { return }
     3204  var display = cm.display
     3205  clearInterval(display.blinker)
     3206  var on = true
     3207  display.cursorDiv.style.visibility = ""
     3208  if (cm.options.cursorBlinkRate > 0)
     3209    { display.blinker = setInterval(function () { return display.cursorDiv.style.visibility = (on = !on) ? "" : "hidden"; },
     3210      cm.options.cursorBlinkRate) }
     3211  else if (cm.options.cursorBlinkRate < 0)
     3212    { display.cursorDiv.style.visibility = "hidden" }
     3213}
     3214
     3215function ensureFocus(cm) {
     3216  if (!cm.state.focused) { cm.display.input.focus(); onFocus(cm) }
     3217}
     3218
     3219function delayBlurEvent(cm) {
     3220  cm.state.delayingBlurEvent = true
     3221  setTimeout(function () { if (cm.state.delayingBlurEvent) {
     3222    cm.state.delayingBlurEvent = false
     3223    onBlur(cm)
     3224  } }, 100)
     3225}
     3226
     3227function onFocus(cm, e) {
     3228  if (cm.state.delayingBlurEvent) { cm.state.delayingBlurEvent = false }
     3229
     3230  if (cm.options.readOnly == "nocursor") { return }
     3231  if (!cm.state.focused) {
     3232    signal(cm, "focus", cm, e)
     3233    cm.state.focused = true
     3234    addClass(cm.display.wrapper, "CodeMirror-focused")
     3235    // This test prevents this from firing when a context
     3236    // menu is closed (since the input reset would kill the
     3237    // select-all detection hack)
     3238    if (!cm.curOp && cm.display.selForContextMenu != cm.doc.sel) {
     3239      cm.display.input.reset()
     3240      if (webkit) { setTimeout(function () { return cm.display.input.reset(true); }, 20) } // Issue #1730
     3241    }
     3242    cm.display.input.receivedFocus()
     3243  }
     3244  restartBlink(cm)
     3245}
     3246function onBlur(cm, e) {
     3247  if (cm.state.delayingBlurEvent) { return }
     3248
     3249  if (cm.state.focused) {
     3250    signal(cm, "blur", cm, e)
     3251    cm.state.focused = false
     3252    rmClass(cm.display.wrapper, "CodeMirror-focused")
     3253  }
     3254  clearInterval(cm.display.blinker)
     3255  setTimeout(function () { if (!cm.state.focused) { cm.display.shift = false } }, 150)
     3256}
     3257
     3258// Read the actual heights of the rendered lines, and update their
     3259// stored heights to match.
     3260function updateHeightsInViewport(cm) {
     3261  var display = cm.display
     3262  var prevBottom = display.lineDiv.offsetTop
     3263  for (var i = 0; i < display.view.length; i++) {
     3264    var cur = display.view[i], height = (void 0)
     3265    if (cur.hidden) { continue }
     3266    if (ie && ie_version < 8) {
     3267      var bot = cur.node.offsetTop + cur.node.offsetHeight
     3268      height = bot - prevBottom
     3269      prevBottom = bot
     3270    } else {
     3271      var box = cur.node.getBoundingClientRect()
     3272      height = box.bottom - box.top
     3273    }
     3274    var diff = cur.line.height - height
     3275    if (height < 2) { height = textHeight(display) }
     3276    if (diff > .005 || diff < -.005) {
     3277      updateLineHeight(cur.line, height)
     3278      updateWidgetHeight(cur.line)
     3279      if (cur.rest) { for (var j = 0; j < cur.rest.length; j++)
     3280        { updateWidgetHeight(cur.rest[j]) } }
     3281    }
     3282  }
     3283}
     3284
     3285// Read and store the height of line widgets associated with the
     3286// given line.
     3287function updateWidgetHeight(line) {
     3288  if (line.widgets) { for (var i = 0; i < line.widgets.length; ++i) {
     3289    var w = line.widgets[i], parent = w.node.parentNode
     3290    if (parent) { w.height = parent.offsetHeight }
     3291  } }
     3292}
     3293
     3294// Compute the lines that are visible in a given viewport (defaults
     3295// the the current scroll position). viewport may contain top,
     3296// height, and ensure (see op.scrollToPos) properties.
     3297function visibleLines(display, doc, viewport) {
     3298  var top = viewport && viewport.top != null ? Math.max(0, viewport.top) : display.scroller.scrollTop
     3299  top = Math.floor(top - paddingTop(display))
     3300  var bottom = viewport && viewport.bottom != null ? viewport.bottom : top + display.wrapper.clientHeight
     3301
     3302  var from = lineAtHeight(doc, top), to = lineAtHeight(doc, bottom)
     3303  // Ensure is a {from: {line, ch}, to: {line, ch}} object, and
     3304  // forces those lines into the viewport (if possible).
     3305  if (viewport && viewport.ensure) {
     3306    var ensureFrom = viewport.ensure.from.line, ensureTo = viewport.ensure.to.line
     3307    if (ensureFrom < from) {
     3308      from = ensureFrom
     3309      to = lineAtHeight(doc, heightAtLine(getLine(doc, ensureFrom)) + display.wrapper.clientHeight)
     3310    } else if (Math.min(ensureTo, doc.lastLine()) >= to) {
     3311      from = lineAtHeight(doc, heightAtLine(getLine(doc, ensureTo)) - display.wrapper.clientHeight)
     3312      to = ensureTo
     3313    }
     3314  }
     3315  return {from: from, to: Math.max(to, from + 1)}
     3316}
     3317
     3318// Re-align line numbers and gutter marks to compensate for
     3319// horizontal scrolling.
     3320function alignHorizontally(cm) {
     3321  var display = cm.display, view = display.view
     3322  if (!display.alignWidgets && (!display.gutters.firstChild || !cm.options.fixedGutter)) { return }
     3323  var comp = compensateForHScroll(display) - display.scroller.scrollLeft + cm.doc.scrollLeft
     3324  var gutterW = display.gutters.offsetWidth, left = comp + "px"
     3325  for (var i = 0; i < view.length; i++) { if (!view[i].hidden) {
     3326    if (cm.options.fixedGutter) {
     3327      if (view[i].gutter)
     3328        { view[i].gutter.style.left = left }
     3329      if (view[i].gutterBackground)
     3330        { view[i].gutterBackground.style.left = left }
     3331    }
     3332    var align = view[i].alignable
     3333    if (align) { for (var j = 0; j < align.length; j++)
     3334      { align[j].style.left = left } }
     3335  } }
     3336  if (cm.options.fixedGutter)
     3337    { display.gutters.style.left = (comp + gutterW) + "px" }
     3338}
     3339
     3340// Used to ensure that the line number gutter is still the right
     3341// size for the current document size. Returns true when an update
     3342// is needed.
     3343function maybeUpdateLineNumberWidth(cm) {
     3344  if (!cm.options.lineNumbers) { return false }
     3345  var doc = cm.doc, last = lineNumberFor(cm.options, doc.first + doc.size - 1), display = cm.display
     3346  if (last.length != display.lineNumChars) {
     3347    var test = display.measure.appendChild(elt("div", [elt("div", last)],
     3348                                               "CodeMirror-linenumber CodeMirror-gutter-elt"))
     3349    var innerW = test.firstChild.offsetWidth, padding = test.offsetWidth - innerW
     3350    display.lineGutter.style.width = ""
     3351    display.lineNumInnerWidth = Math.max(innerW, display.lineGutter.offsetWidth - padding) + 1
     3352    display.lineNumWidth = display.lineNumInnerWidth + padding
     3353    display.lineNumChars = display.lineNumInnerWidth ? last.length : -1
     3354    display.lineGutter.style.width = display.lineNumWidth + "px"
     3355    updateGutterSpace(cm)
     3356    return true
     3357  }
     3358  return false
     3359}
     3360
     3361// SCROLLING THINGS INTO VIEW
     3362
     3363// If an editor sits on the top or bottom of the window, partially
     3364// scrolled out of view, this ensures that the cursor is visible.
     3365function maybeScrollWindow(cm, rect) {
     3366  if (signalDOMEvent(cm, "scrollCursorIntoView")) { return }
     3367
     3368  var display = cm.display, box = display.sizer.getBoundingClientRect(), doScroll = null
     3369  if (rect.top + box.top < 0) { doScroll = true }
     3370  else if (rect.bottom + box.top > (window.innerHeight || document.documentElement.clientHeight)) { doScroll = false }
     3371  if (doScroll != null && !phantom) {
     3372    var scrollNode = elt("div", "\u200b", null, ("position: absolute;\n                         top: " + (rect.top - display.viewOffset - paddingTop(cm.display)) + "px;\n                         height: " + (rect.bottom - rect.top + scrollGap(cm) + display.barHeight) + "px;\n                         left: " + (rect.left) + "px; width: " + (Math.max(2, rect.right - rect.left)) + "px;"))
     3373    cm.display.lineSpace.appendChild(scrollNode)
     3374    scrollNode.scrollIntoView(doScroll)
     3375    cm.display.lineSpace.removeChild(scrollNode)
     3376  }
     3377}
     3378
     3379// Scroll a given position into view (immediately), verifying that
     3380// it actually became visible (as line heights are accurately
     3381// measured, the position of something may 'drift' during drawing).
     3382function scrollPosIntoView(cm, pos, end, margin) {
     3383  if (margin == null) { margin = 0 }
     3384  var rect
     3385  if (!cm.options.lineWrapping && pos == end) {
     3386    // Set pos and end to the cursor positions around the character pos sticks to
     3387    // If pos.sticky == "before", that is around pos.ch - 1, otherwise around pos.ch
     3388    // If pos == Pos(_, 0, "before"), pos and end are unchanged
     3389    pos = pos.ch ? Pos(pos.line, pos.sticky == "before" ? pos.ch - 1 : pos.ch, "after") : pos
     3390    end = pos.sticky == "before" ? Pos(pos.line, pos.ch + 1, "before") : pos
     3391  }
     3392  for (var limit = 0; limit < 5; limit++) {
     3393    var changed = false
     3394    var coords = cursorCoords(cm, pos)
     3395    var endCoords = !end || end == pos ? coords : cursorCoords(cm, end)
     3396    rect = {left: Math.min(coords.left, endCoords.left),
     3397            top: Math.min(coords.top, endCoords.top) - margin,
     3398            right: Math.max(coords.left, endCoords.left),
     3399            bottom: Math.max(coords.bottom, endCoords.bottom) + margin}
     3400    var scrollPos = calculateScrollPos(cm, rect)
     3401    var startTop = cm.doc.scrollTop, startLeft = cm.doc.scrollLeft
     3402    if (scrollPos.scrollTop != null) {
     3403      updateScrollTop(cm, scrollPos.scrollTop)
     3404      if (Math.abs(cm.doc.scrollTop - startTop) > 1) { changed = true }
     3405    }
     3406    if (scrollPos.scrollLeft != null) {
     3407      setScrollLeft(cm, scrollPos.scrollLeft)
     3408      if (Math.abs(cm.doc.scrollLeft - startLeft) > 1) { changed = true }
     3409    }
     3410    if (!changed) { break }
     3411  }
     3412  return rect
     3413}
     3414
     3415// Scroll a given set of coordinates into view (immediately).
     3416function scrollIntoView(cm, rect) {
     3417  var scrollPos = calculateScrollPos(cm, rect)
     3418  if (scrollPos.scrollTop != null) { updateScrollTop(cm, scrollPos.scrollTop) }
     3419  if (scrollPos.scrollLeft != null) { setScrollLeft(cm, scrollPos.scrollLeft) }
     3420}
     3421
     3422// Calculate a new scroll position needed to scroll the given
     3423// rectangle into view. Returns an object with scrollTop and
     3424// scrollLeft properties. When these are undefined, the
     3425// vertical/horizontal position does not need to be adjusted.
     3426function calculateScrollPos(cm, rect) {
     3427  var display = cm.display, snapMargin = textHeight(cm.display)
     3428  if (rect.top < 0) { rect.top = 0 }
     3429  var screentop = cm.curOp && cm.curOp.scrollTop != null ? cm.curOp.scrollTop : display.scroller.scrollTop
     3430  var screen = displayHeight(cm), result = {}
     3431  if (rect.bottom - rect.top > screen) { rect.bottom = rect.top + screen }
     3432  var docBottom = cm.doc.height + paddingVert(display)
     3433  var atTop = rect.top < snapMargin, atBottom = rect.bottom > docBottom - snapMargin
     3434  if (rect.top < screentop) {
     3435    result.scrollTop = atTop ? 0 : rect.top
     3436  } else if (rect.bottom > screentop + screen) {
     3437    var newTop = Math.min(rect.top, (atBottom ? docBottom : rect.bottom) - screen)
     3438    if (newTop != screentop) { result.scrollTop = newTop }
     3439  }
     3440
     3441  var screenleft = cm.curOp && cm.curOp.scrollLeft != null ? cm.curOp.scrollLeft : display.scroller.scrollLeft
     3442  var screenw = displayWidth(cm) - (cm.options.fixedGutter ? display.gutters.offsetWidth : 0)
     3443  var tooWide = rect.right - rect.left > screenw
     3444  if (tooWide) { rect.right = rect.left + screenw }
     3445  if (rect.left < 10)
     3446    { result.scrollLeft = 0 }
     3447  else if (rect.left < screenleft)
     3448    { result.scrollLeft = Math.max(0, rect.left - (tooWide ? 0 : 10)) }
     3449  else if (rect.right > screenw + screenleft - 3)
     3450    { result.scrollLeft = rect.right + (tooWide ? 0 : 10) - screenw }
     3451  return result
     3452}
     3453
     3454// Store a relative adjustment to the scroll position in the current
     3455// operation (to be applied when the operation finishes).
     3456function addToScrollTop(cm, top) {
     3457  if (top == null) { return }
     3458  resolveScrollToPos(cm)
     3459  cm.curOp.scrollTop = (cm.curOp.scrollTop == null ? cm.doc.scrollTop : cm.curOp.scrollTop) + top
     3460}
     3461
     3462// Make sure that at the end of the operation the current cursor is
     3463// shown.
     3464function ensureCursorVisible(cm) {
     3465  resolveScrollToPos(cm)
     3466  var cur = cm.getCursor()
     3467  cm.curOp.scrollToPos = {from: cur, to: cur, margin: cm.options.cursorScrollMargin}
     3468}
     3469
     3470function scrollToCoords(cm, x, y) {
     3471  if (x != null || y != null) { resolveScrollToPos(cm) }
     3472  if (x != null) { cm.curOp.scrollLeft = x }
     3473  if (y != null) { cm.curOp.scrollTop = y }
     3474}
     3475
     3476function scrollToRange(cm, range) {
     3477  resolveScrollToPos(cm)
     3478  cm.curOp.scrollToPos = range
     3479}
     3480
     3481// When an operation has its scrollToPos property set, and another
     3482// scroll action is applied before the end of the operation, this
     3483// 'simulates' scrolling that position into view in a cheap way, so
     3484// that the effect of intermediate scroll commands is not ignored.
     3485function resolveScrollToPos(cm) {
     3486  var range = cm.curOp.scrollToPos
     3487  if (range) {
     3488    cm.curOp.scrollToPos = null
     3489    var from = estimateCoords(cm, range.from), to = estimateCoords(cm, range.to)
     3490    scrollToCoordsRange(cm, from, to, range.margin)
     3491  }
     3492}
     3493
     3494function scrollToCoordsRange(cm, from, to, margin) {
     3495  var sPos = calculateScrollPos(cm, {
     3496    left: Math.min(from.left, to.left),
     3497    top: Math.min(from.top, to.top) - margin,
     3498    right: Math.max(from.right, to.right),
     3499    bottom: Math.max(from.bottom, to.bottom) + margin
     3500  })
     3501  scrollToCoords(cm, sPos.scrollLeft, sPos.scrollTop)
     3502}
     3503
     3504// Sync the scrollable area and scrollbars, ensure the viewport
     3505// covers the visible area.
     3506function updateScrollTop(cm, val) {
     3507  if (Math.abs(cm.doc.scrollTop - val) < 2) { return }
     3508  if (!gecko) { updateDisplaySimple(cm, {top: val}) }
     3509  setScrollTop(cm, val, true)
     3510  if (gecko) { updateDisplaySimple(cm) }
     3511  startWorker(cm, 100)
     3512}
     3513
     3514function setScrollTop(cm, val, forceScroll) {
     3515  val = Math.min(cm.display.scroller.scrollHeight - cm.display.scroller.clientHeight, val)
     3516  if (cm.display.scroller.scrollTop == val && !forceScroll) { return }
     3517  cm.doc.scrollTop = val
     3518  cm.display.scrollbars.setScrollTop(val)
     3519  if (cm.display.scroller.scrollTop != val) { cm.display.scroller.scrollTop = val }
     3520}
     3521
     3522// Sync scroller and scrollbar, ensure the gutter elements are
     3523// aligned.
     3524function setScrollLeft(cm, val, isScroller, forceScroll) {
     3525  val = Math.min(val, cm.display.scroller.scrollWidth - cm.display.scroller.clientWidth)
     3526  if ((isScroller ? val == cm.doc.scrollLeft : Math.abs(cm.doc.scrollLeft - val) < 2) && !forceScroll) { return }
     3527  cm.doc.scrollLeft = val
     3528  alignHorizontally(cm)
     3529  if (cm.display.scroller.scrollLeft != val) { cm.display.scroller.scrollLeft = val }
     3530  cm.display.scrollbars.setScrollLeft(val)
     3531}
     3532
     3533// SCROLLBARS
     3534
     3535// Prepare DOM reads needed to update the scrollbars. Done in one
     3536// shot to minimize update/measure roundtrips.
     3537function measureForScrollbars(cm) {
     3538  var d = cm.display, gutterW = d.gutters.offsetWidth
     3539  var docH = Math.round(cm.doc.height + paddingVert(cm.display))
     3540  return {
     3541    clientHeight: d.scroller.clientHeight,
     3542    viewHeight: d.wrapper.clientHeight,
     3543    scrollWidth: d.scroller.scrollWidth, clientWidth: d.scroller.clientWidth,
     3544    viewWidth: d.wrapper.clientWidth,
     3545    barLeft: cm.options.fixedGutter ? gutterW : 0,
     3546    docHeight: docH,
     3547    scrollHeight: docH + scrollGap(cm) + d.barHeight,
     3548    nativeBarWidth: d.nativeBarWidth,
     3549    gutterWidth: gutterW
     3550  }
     3551}
     3552
     3553var NativeScrollbars = function(place, scroll, cm) {
     3554  this.cm = cm
     3555  var vert = this.vert = elt("div", [elt("div", null, null, "min-width: 1px")], "CodeMirror-vscrollbar")
     3556  var horiz = this.horiz = elt("div", [elt("div", null, null, "height: 100%; min-height: 1px")], "CodeMirror-hscrollbar")
     3557  vert.tabIndex = horiz.tabIndex = -1
     3558  place(vert); place(horiz)
     3559
     3560  on(vert, "scroll", function () {
     3561    if (vert.clientHeight) { scroll(vert.scrollTop, "vertical") }
     3562  })
     3563  on(horiz, "scroll", function () {
     3564    if (horiz.clientWidth) { scroll(horiz.scrollLeft, "horizontal") }
     3565  })
     3566
     3567  this.checkedZeroWidth = false
     3568  // Need to set a minimum width to see the scrollbar on IE7 (but must not set it on IE8).
     3569  if (ie && ie_version < 8) { this.horiz.style.minHeight = this.vert.style.minWidth = "18px" }
     3570};
     3571
     3572NativeScrollbars.prototype.update = function (measure) {
     3573  var needsH = measure.scrollWidth > measure.clientWidth + 1
     3574  var needsV = measure.scrollHeight > measure.clientHeight + 1
     3575  var sWidth = measure.nativeBarWidth
     3576
     3577  if (needsV) {
     3578    this.vert.style.display = "block"
     3579    this.vert.style.bottom = needsH ? sWidth + "px" : "0"
     3580    var totalHeight = measure.viewHeight - (needsH ? sWidth : 0)
     3581    // A bug in IE8 can cause this value to be negative, so guard it.
     3582    this.vert.firstChild.style.height =
     3583      Math.max(0, measure.scrollHeight - measure.clientHeight + totalHeight) + "px"
     3584  } else {
     3585    this.vert.style.display = ""
     3586    this.vert.firstChild.style.height = "0"
     3587  }
     3588
     3589  if (needsH) {
     3590    this.horiz.style.display = "block"
     3591    this.horiz.style.right = needsV ? sWidth + "px" : "0"
     3592    this.horiz.style.left = measure.barLeft + "px"
     3593    var totalWidth = measure.viewWidth - measure.barLeft - (needsV ? sWidth : 0)
     3594    this.horiz.firstChild.style.width =
     3595      Math.max(0, measure.scrollWidth - measure.clientWidth + totalWidth) + "px"
     3596  } else {
     3597    this.horiz.style.display = ""
     3598    this.horiz.firstChild.style.width = "0"
     3599  }
     3600
     3601  if (!this.checkedZeroWidth && measure.clientHeight > 0) {
     3602    if (sWidth == 0) { this.zeroWidthHack() }
     3603    this.checkedZeroWidth = true
     3604  }
     3605
     3606  return {right: needsV ? sWidth : 0, bottom: needsH ? sWidth : 0}
     3607};
     3608
     3609NativeScrollbars.prototype.setScrollLeft = function (pos) {
     3610  if (this.horiz.scrollLeft != pos) { this.horiz.scrollLeft = pos }
     3611  if (this.disableHoriz) { this.enableZeroWidthBar(this.horiz, this.disableHoriz, "horiz") }
     3612};
     3613
     3614NativeScrollbars.prototype.setScrollTop = function (pos) {
     3615  if (this.vert.scrollTop != pos) { this.vert.scrollTop = pos }
     3616  if (this.disableVert) { this.enableZeroWidthBar(this.vert, this.disableVert, "vert") }
     3617};
     3618
     3619NativeScrollbars.prototype.zeroWidthHack = function () {
     3620  var w = mac && !mac_geMountainLion ? "12px" : "18px"
     3621  this.horiz.style.height = this.vert.style.width = w
     3622  this.horiz.style.pointerEvents = this.vert.style.pointerEvents = "none"
     3623  this.disableHoriz = new Delayed
     3624  this.disableVert = new Delayed
     3625};
     3626
     3627NativeScrollbars.prototype.enableZeroWidthBar = function (bar, delay, type) {
     3628  bar.style.pointerEvents = "auto"
     3629  function maybeDisable() {
     3630    // To find out whether the scrollbar is still visible, we
     3631    // check whether the element under the pixel in the bottom
     3632    // right corner of the scrollbar box is the scrollbar box
     3633    // itself (when the bar is still visible) or its filler child
     3634    // (when the bar is hidden). If it is still visible, we keep
     3635    // it enabled, if it's hidden, we disable pointer events.
     3636    var box = bar.getBoundingClientRect()
     3637    var elt = type == "vert" ? document.elementFromPoint(box.right - 1, (box.top + box.bottom) / 2)
     3638        : document.elementFromPoint((box.right + box.left) / 2, box.bottom - 1)
     3639    if (elt != bar) { bar.style.pointerEvents = "none" }
     3640    else { delay.set(1000, maybeDisable) }
     3641  }
     3642  delay.set(1000, maybeDisable)
     3643};
     3644
     3645NativeScrollbars.prototype.clear = function () {
     3646  var parent = this.horiz.parentNode
     3647  parent.removeChild(this.horiz)
     3648  parent.removeChild(this.vert)
     3649};
     3650
     3651var NullScrollbars = function () {};
     3652
     3653NullScrollbars.prototype.update = function () { return {bottom: 0, right: 0} };
     3654NullScrollbars.prototype.setScrollLeft = function () {};
     3655NullScrollbars.prototype.setScrollTop = function () {};
     3656NullScrollbars.prototype.clear = function () {};
     3657
     3658function updateScrollbars(cm, measure) {
     3659  if (!measure) { measure = measureForScrollbars(cm) }
     3660  var startWidth = cm.display.barWidth, startHeight = cm.display.barHeight
     3661  updateScrollbarsInner(cm, measure)
     3662  for (var i = 0; i < 4 && startWidth != cm.display.barWidth || startHeight != cm.display.barHeight; i++) {
     3663    if (startWidth != cm.display.barWidth && cm.options.lineWrapping)
     3664      { updateHeightsInViewport(cm) }
     3665    updateScrollbarsInner(cm, measureForScrollbars(cm))
     3666    startWidth = cm.display.barWidth; startHeight = cm.display.barHeight
     3667  }
     3668}
     3669
     3670// Re-synchronize the fake scrollbars with the actual size of the
     3671// content.
     3672function updateScrollbarsInner(cm, measure) {
     3673  var d = cm.display
     3674  var sizes = d.scrollbars.update(measure)
     3675
     3676  d.sizer.style.paddingRight = (d.barWidth = sizes.right) + "px"
     3677  d.sizer.style.paddingBottom = (d.barHeight = sizes.bottom) + "px"
     3678  d.heightForcer.style.borderBottom = sizes.bottom + "px solid transparent"
     3679
     3680  if (sizes.right && sizes.bottom) {
     3681    d.scrollbarFiller.style.display = "block"
     3682    d.scrollbarFiller.style.height = sizes.bottom + "px"
     3683    d.scrollbarFiller.style.width = sizes.right + "px"
     3684  } else { d.scrollbarFiller.style.display = "" }
     3685  if (sizes.bottom && cm.options.coverGutterNextToScrollbar && cm.options.fixedGutter) {
     3686    d.gutterFiller.style.display = "block"
     3687    d.gutterFiller.style.height = sizes.bottom + "px"
     3688    d.gutterFiller.style.width = measure.gutterWidth + "px"
     3689  } else { d.gutterFiller.style.display = "" }
     3690}
     3691
     3692var scrollbarModel = {"native": NativeScrollbars, "null": NullScrollbars}
     3693
     3694function initScrollbars(cm) {
     3695  if (cm.display.scrollbars) {
     3696    cm.display.scrollbars.clear()
     3697    if (cm.display.scrollbars.addClass)
     3698      { rmClass(cm.display.wrapper, cm.display.scrollbars.addClass) }
     3699  }
     3700
     3701  cm.display.scrollbars = new scrollbarModel[cm.options.scrollbarStyle](function (node) {
     3702    cm.display.wrapper.insertBefore(node, cm.display.scrollbarFiller)
     3703    // Prevent clicks in the scrollbars from killing focus
     3704    on(node, "mousedown", function () {
     3705      if (cm.state.focused) { setTimeout(function () { return cm.display.input.focus(); }, 0) }
     3706    })
     3707    node.setAttribute("cm-not-content", "true")
     3708  }, function (pos, axis) {
     3709    if (axis == "horizontal") { setScrollLeft(cm, pos) }
     3710    else { updateScrollTop(cm, pos) }
     3711  }, cm)
     3712  if (cm.display.scrollbars.addClass)
     3713    { addClass(cm.display.wrapper, cm.display.scrollbars.addClass) }
     3714}
     3715
     3716// Operations are used to wrap a series of changes to the editor
     3717// state in such a way that each change won't have to update the
     3718// cursor and display (which would be awkward, slow, and
     3719// error-prone). Instead, display updates are batched and then all
     3720// combined and executed at once.
     3721
     3722var nextOpId = 0
     3723// Start a new operation.
     3724function startOperation(cm) {
     3725  cm.curOp = {
     3726    cm: cm,
     3727    viewChanged: false,      // Flag that indicates that lines might need to be redrawn
     3728    startHeight: cm.doc.height, // Used to detect need to update scrollbar
     3729    forceUpdate: false,      // Used to force a redraw
     3730    updateInput: null,       // Whether to reset the input textarea
     3731    typing: false,           // Whether this reset should be careful to leave existing text (for compositing)
     3732    changeObjs: null,        // Accumulated changes, for firing change events
     3733    cursorActivityHandlers: null, // Set of handlers to fire cursorActivity on
     3734    cursorActivityCalled: 0, // Tracks which cursorActivity handlers have been called already
     3735    selectionChanged: false, // Whether the selection needs to be redrawn
     3736    updateMaxLine: false,    // Set when the widest line needs to be determined anew
     3737    scrollLeft: null, scrollTop: null, // Intermediate scroll position, not pushed to DOM yet
     3738    scrollToPos: null,       // Used to scroll to a specific position
     3739    focus: false,
     3740    id: ++nextOpId           // Unique ID
     3741  }
     3742  pushOperation(cm.curOp)
     3743}
     3744
     3745// Finish an operation, updating the display and signalling delayed events
     3746function endOperation(cm) {
     3747  var op = cm.curOp
     3748  finishOperation(op, function (group) {
     3749    for (var i = 0; i < group.ops.length; i++)
     3750      { group.ops[i].cm.curOp = null }
     3751    endOperations(group)
     3752  })
     3753}
     3754
     3755// The DOM updates done when an operation finishes are batched so
     3756// that the minimum number of relayouts are required.
     3757function endOperations(group) {
     3758  var ops = group.ops
     3759  for (var i = 0; i < ops.length; i++) // Read DOM
     3760    { endOperation_R1(ops[i]) }
     3761  for (var i$1 = 0; i$1 < ops.length; i$1++) // Write DOM (maybe)
     3762    { endOperation_W1(ops[i$1]) }
     3763  for (var i$2 = 0; i$2 < ops.length; i$2++) // Read DOM
     3764    { endOperation_R2(ops[i$2]) }
     3765  for (var i$3 = 0; i$3 < ops.length; i$3++) // Write DOM (maybe)
     3766    { endOperation_W2(ops[i$3]) }
     3767  for (var i$4 = 0; i$4 < ops.length; i$4++) // Read DOM
     3768    { endOperation_finish(ops[i$4]) }
     3769}
     3770
     3771function endOperation_R1(op) {
     3772  var cm = op.cm, display = cm.display
     3773  maybeClipScrollbars(cm)
     3774  if (op.updateMaxLine) { findMaxLine(cm) }
     3775
     3776  op.mustUpdate = op.viewChanged || op.forceUpdate || op.scrollTop != null ||
     3777    op.scrollToPos && (op.scrollToPos.from.line < display.viewFrom ||
     3778                       op.scrollToPos.to.line >= display.viewTo) ||
     3779    display.maxLineChanged && cm.options.lineWrapping
     3780  op.update = op.mustUpdate &&
     3781    new DisplayUpdate(cm, op.mustUpdate && {top: op.scrollTop, ensure: op.scrollToPos}, op.forceUpdate)
     3782}
     3783
     3784function endOperation_W1(op) {
     3785  op.updatedDisplay = op.mustUpdate && updateDisplayIfNeeded(op.cm, op.update)
     3786}
     3787
     3788function endOperation_R2(op) {
     3789  var cm = op.cm, display = cm.display
     3790  if (op.updatedDisplay) { updateHeightsInViewport(cm) }
     3791
     3792  op.barMeasure = measureForScrollbars(cm)
     3793
     3794  // If the max line changed since it was last measured, measure it,
     3795  // and ensure the document's width matches it.
     3796  // updateDisplay_W2 will use these properties to do the actual resizing
     3797  if (display.maxLineChanged && !cm.options.lineWrapping) {
     3798    op.adjustWidthTo = measureChar(cm, display.maxLine, display.maxLine.text.length).left + 3
     3799    cm.display.sizerWidth = op.adjustWidthTo
     3800    op.barMeasure.scrollWidth =
     3801      Math.max(display.scroller.clientWidth, display.sizer.offsetLeft + op.adjustWidthTo + scrollGap(cm) + cm.display.barWidth)
     3802    op.maxScrollLeft = Math.max(0, display.sizer.offsetLeft + op.adjustWidthTo - displayWidth(cm))
     3803  }
     3804
     3805  if (op.updatedDisplay || op.selectionChanged)
     3806    { op.preparedSelection = display.input.prepareSelection() }
     3807}
     3808
     3809function endOperation_W2(op) {
     3810  var cm = op.cm
     3811
     3812  if (op.adjustWidthTo != null) {
     3813    cm.display.sizer.style.minWidth = op.adjustWidthTo + "px"
     3814    if (op.maxScrollLeft < cm.doc.scrollLeft)
     3815      { setScrollLeft(cm, Math.min(cm.display.scroller.scrollLeft, op.maxScrollLeft), true) }
     3816    cm.display.maxLineChanged = false
     3817  }
     3818
     3819  var takeFocus = op.focus && op.focus == activeElt()
     3820  if (op.preparedSelection)
     3821    { cm.display.input.showSelection(op.preparedSelection, takeFocus) }
     3822  if (op.updatedDisplay || op.startHeight != cm.doc.height)
     3823    { updateScrollbars(cm, op.barMeasure) }
     3824  if (op.updatedDisplay)
     3825    { setDocumentHeight(cm, op.barMeasure) }
     3826
     3827  if (op.selectionChanged) { restartBlink(cm) }
     3828
     3829  if (cm.state.focused && op.updateInput)
     3830    { cm.display.input.reset(op.typing) }
     3831  if (takeFocus) { ensureFocus(op.cm) }
     3832}
     3833
     3834function endOperation_finish(op) {
     3835  var cm = op.cm, display = cm.display, doc = cm.doc
     3836
     3837  if (op.updatedDisplay) { postUpdateDisplay(cm, op.update) }
     3838
     3839  // Abort mouse wheel delta measurement, when scrolling explicitly
     3840  if (display.wheelStartX != null && (op.scrollTop != null || op.scrollLeft != null || op.scrollToPos))
     3841    { display.wheelStartX = display.wheelStartY = null }
     3842
     3843  // Propagate the scroll position to the actual DOM scroller
     3844  if (op.scrollTop != null) { setScrollTop(cm, op.scrollTop, op.forceScroll) }
     3845
     3846  if (op.scrollLeft != null) { setScrollLeft(cm, op.scrollLeft, true, true) }
     3847  // If we need to scroll a specific position into view, do so.
     3848  if (op.scrollToPos) {
     3849    var rect = scrollPosIntoView(cm, clipPos(doc, op.scrollToPos.from),
     3850                                 clipPos(doc, op.scrollToPos.to), op.scrollToPos.margin)
     3851    maybeScrollWindow(cm, rect)
     3852  }
     3853
     3854  // Fire events for markers that are hidden/unidden by editing or
     3855  // undoing
     3856  var hidden = op.maybeHiddenMarkers, unhidden = op.maybeUnhiddenMarkers
     3857  if (hidden) { for (var i = 0; i < hidden.length; ++i)
     3858    { if (!hidden[i].lines.length) { signal(hidden[i], "hide") } } }
     3859  if (unhidden) { for (var i$1 = 0; i$1 < unhidden.length; ++i$1)
     3860    { if (unhidden[i$1].lines.length) { signal(unhidden[i$1], "unhide") } } }
     3861
     3862  if (display.wrapper.offsetHeight)
     3863    { doc.scrollTop = cm.display.scroller.scrollTop }
     3864
     3865  // Fire change events, and delayed event handlers
     3866  if (op.changeObjs)
     3867    { signal(cm, "changes", cm, op.changeObjs) }
     3868  if (op.update)
     3869    { op.update.finish() }
     3870}
     3871
     3872// Run the given function in an operation
     3873function runInOp(cm, f) {
     3874  if (cm.curOp) { return f() }
     3875  startOperation(cm)
     3876  try { return f() }
     3877  finally { endOperation(cm) }
     3878}
     3879// Wraps a function in an operation. Returns the wrapped function.
     3880function operation(cm, f) {
     3881  return function() {
     3882    if (cm.curOp) { return f.apply(cm, arguments) }
     3883    startOperation(cm)
     3884    try { return f.apply(cm, arguments) }
     3885    finally { endOperation(cm) }
     3886  }
     3887}
     3888// Used to add methods to editor and doc instances, wrapping them in
     3889// operations.
     3890function methodOp(f) {
     3891  return function() {
     3892    if (this.curOp) { return f.apply(this, arguments) }
     3893    startOperation(this)
     3894    try { return f.apply(this, arguments) }
     3895    finally { endOperation(this) }
     3896  }
     3897}
     3898function docMethodOp(f) {
     3899  return function() {
     3900    var cm = this.cm
     3901    if (!cm || cm.curOp) { return f.apply(this, arguments) }
     3902    startOperation(cm)
     3903    try { return f.apply(this, arguments) }
     3904    finally { endOperation(cm) }
     3905  }
     3906}
     3907
     3908// Updates the display.view data structure for a given change to the
     3909// document. From and to are in pre-change coordinates. Lendiff is
     3910// the amount of lines added or subtracted by the change. This is
     3911// used for changes that span multiple lines, or change the way
     3912// lines are divided into visual lines. regLineChange (below)
     3913// registers single-line changes.
     3914function regChange(cm, from, to, lendiff) {
     3915  if (from == null) { from = cm.doc.first }
     3916  if (to == null) { to = cm.doc.first + cm.doc.size }
     3917  if (!lendiff) { lendiff = 0 }
     3918
     3919  var display = cm.display
     3920  if (lendiff && to < display.viewTo &&
     3921      (display.updateLineNumbers == null || display.updateLineNumbers > from))
     3922    { display.updateLineNumbers = from }
     3923
     3924  cm.curOp.viewChanged = true
     3925
     3926  if (from >= display.viewTo) { // Change after
     3927    if (sawCollapsedSpans && visualLineNo(cm.doc, from) < display.viewTo)
     3928      { resetView(cm) }
     3929  } else if (to <= display.viewFrom) { // Change before
     3930    if (sawCollapsedSpans && visualLineEndNo(cm.doc, to + lendiff) > display.viewFrom) {
     3931      resetView(cm)
     3932    } else {
     3933      display.viewFrom += lendiff
     3934      display.viewTo += lendiff
     3935    }
     3936  } else if (from <= display.viewFrom && to >= display.viewTo) { // Full overlap
     3937    resetView(cm)
     3938  } else if (from <= display.viewFrom) { // Top overlap
     3939    var cut = viewCuttingPoint(cm, to, to + lendiff, 1)
     3940    if (cut) {
     3941      display.view = display.view.slice(cut.index)
     3942      display.viewFrom = cut.lineN
     3943      display.viewTo += lendiff
     3944    } else {
     3945      resetView(cm)
     3946    }
     3947  } else if (to >= display.viewTo) { // Bottom overlap
     3948    var cut$1 = viewCuttingPoint(cm, from, from, -1)
     3949    if (cut$1) {
     3950      display.view = display.view.slice(0, cut$1.index)
     3951      display.viewTo = cut$1.lineN
     3952    } else {
     3953      resetView(cm)
     3954    }
     3955  } else { // Gap in the middle
     3956    var cutTop = viewCuttingPoint(cm, from, from, -1)
     3957    var cutBot = viewCuttingPoint(cm, to, to + lendiff, 1)
     3958    if (cutTop && cutBot) {
     3959      display.view = display.view.slice(0, cutTop.index)
     3960        .concat(buildViewArray(cm, cutTop.lineN, cutBot.lineN))
     3961        .concat(display.view.slice(cutBot.index))
     3962      display.viewTo += lendiff
     3963    } else {
     3964      resetView(cm)
     3965    }
     3966  }
     3967
     3968  var ext = display.externalMeasured
     3969  if (ext) {
     3970    if (to < ext.lineN)
     3971      { ext.lineN += lendiff }
     3972    else if (from < ext.lineN + ext.size)
     3973      { display.externalMeasured = null }
     3974  }
     3975}
     3976
     3977// Register a change to a single line. Type must be one of "text",
     3978// "gutter", "class", "widget"
     3979function regLineChange(cm, line, type) {
     3980  cm.curOp.viewChanged = true
     3981  var display = cm.display, ext = cm.display.externalMeasured
     3982  if (ext && line >= ext.lineN && line < ext.lineN + ext.size)
     3983    { display.externalMeasured = null }
     3984
     3985  if (line < display.viewFrom || line >= display.viewTo) { return }
     3986  var lineView = display.view[findViewIndex(cm, line)]
     3987  if (lineView.node == null) { return }
     3988  var arr = lineView.changes || (lineView.changes = [])
     3989  if (indexOf(arr, type) == -1) { arr.push(type) }
     3990}
     3991
     3992// Clear the view.
     3993function resetView(cm) {
     3994  cm.display.viewFrom = cm.display.viewTo = cm.doc.first
     3995  cm.display.view = []
     3996  cm.display.viewOffset = 0
     3997}
     3998
     3999function viewCuttingPoint(cm, oldN, newN, dir) {
     4000  var index = findViewIndex(cm, oldN), diff, view = cm.display.view
     4001  if (!sawCollapsedSpans || newN == cm.doc.first + cm.doc.size)
     4002    { return {index: index, lineN: newN} }
     4003  var n = cm.display.viewFrom
     4004  for (var i = 0; i < index; i++)
     4005    { n += view[i].size }
     4006  if (n != oldN) {
     4007    if (dir > 0) {
     4008      if (index == view.length - 1) { return null }
     4009      diff = (n + view[index].size) - oldN
     4010      index++
     4011    } else {
     4012      diff = n - oldN
     4013    }
     4014    oldN += diff; newN += diff
     4015  }
     4016  while (visualLineNo(cm.doc, newN) != newN) {
     4017    if (index == (dir < 0 ? 0 : view.length - 1)) { return null }
     4018    newN += dir * view[index - (dir < 0 ? 1 : 0)].size
     4019    index += dir
     4020  }
     4021  return {index: index, lineN: newN}
     4022}
     4023
     4024// Force the view to cover a given range, adding empty view element
     4025// or clipping off existing ones as needed.
     4026function adjustView(cm, from, to) {
     4027  var display = cm.display, view = display.view
     4028  if (view.length == 0 || from >= display.viewTo || to <= display.viewFrom) {
     4029    display.view = buildViewArray(cm, from, to)
     4030    display.viewFrom = from
     4031  } else {
     4032    if (display.viewFrom > from)
     4033      { display.view = buildViewArray(cm, from, display.viewFrom).concat(display.view) }
     4034    else if (display.viewFrom < from)
     4035      { display.view = display.view.slice(findViewIndex(cm, from)) }
     4036    display.viewFrom = from
     4037    if (display.viewTo < to)
     4038      { display.view = display.view.concat(buildViewArray(cm, display.viewTo, to)) }
     4039    else if (display.viewTo > to)
     4040      { display.view = display.view.slice(0, findViewIndex(cm, to)) }
     4041  }
     4042  display.viewTo = to
     4043}
     4044
     4045// Count the number of lines in the view whose DOM representation is
     4046// out of date (or nonexistent).
     4047function countDirtyView(cm) {
     4048  var view = cm.display.view, dirty = 0
     4049  for (var i = 0; i < view.length; i++) {
     4050    var lineView = view[i]
     4051    if (!lineView.hidden && (!lineView.node || lineView.changes)) { ++dirty }
     4052  }
     4053  return dirty
     4054}
     4055
     4056// HIGHLIGHT WORKER
     4057
     4058function startWorker(cm, time) {
     4059  if (cm.doc.highlightFrontier < cm.display.viewTo)
     4060    { cm.state.highlight.set(time, bind(highlightWorker, cm)) }
     4061}
     4062
     4063function highlightWorker(cm) {
     4064  var doc = cm.doc
     4065  if (doc.highlightFrontier >= cm.display.viewTo) { return }
     4066  var end = +new Date + cm.options.workTime
     4067  var context = getContextBefore(cm, doc.highlightFrontier)
     4068  var changedLines = []
     4069
     4070  doc.iter(context.line, Math.min(doc.first + doc.size, cm.display.viewTo + 500), function (line) {
     4071    if (context.line >= cm.display.viewFrom) { // Visible
     4072      var oldStyles = line.styles
     4073      var resetState = line.text.length > cm.options.maxHighlightLength ? copyState(doc.mode, context.state) : null
     4074      var highlighted = highlightLine(cm, line, context, true)
     4075      if (resetState) { context.state = resetState }
     4076      line.styles = highlighted.styles
     4077      var oldCls = line.styleClasses, newCls = highlighted.classes
     4078      if (newCls) { line.styleClasses = newCls }
     4079      else if (oldCls) { line.styleClasses = null }
     4080      var ischange = !oldStyles || oldStyles.length != line.styles.length ||
     4081        oldCls != newCls && (!oldCls || !newCls || oldCls.bgClass != newCls.bgClass || oldCls.textClass != newCls.textClass)
     4082      for (var i = 0; !ischange && i < oldStyles.length; ++i) { ischange = oldStyles[i] != line.styles[i] }
     4083      if (ischange) { changedLines.push(context.line) }
     4084      line.stateAfter = context.save()
     4085      context.nextLine()
     4086    } else {
     4087      if (line.text.length <= cm.options.maxHighlightLength)
     4088        { processLine(cm, line.text, context) }
     4089      line.stateAfter = context.line % 5 == 0 ? context.save() : null
     4090      context.nextLine()
     4091    }
     4092    if (+new Date > end) {
     4093      startWorker(cm, cm.options.workDelay)
     4094      return true
     4095    }
     4096  })
     4097  doc.highlightFrontier = context.line
     4098  doc.modeFrontier = Math.max(doc.modeFrontier, context.line)
     4099  if (changedLines.length) { runInOp(cm, function () {
     4100    for (var i = 0; i < changedLines.length; i++)
     4101      { regLineChange(cm, changedLines[i], "text") }
     4102  }) }
     4103}
     4104
     4105// DISPLAY DRAWING
     4106
     4107var DisplayUpdate = function(cm, viewport, force) {
     4108  var display = cm.display
     4109
     4110  this.viewport = viewport
     4111  // Store some values that we'll need later (but don't want to force a relayout for)
     4112  this.visible = visibleLines(display, cm.doc, viewport)
     4113  this.editorIsHidden = !display.wrapper.offsetWidth
     4114  this.wrapperHeight = display.wrapper.clientHeight
     4115  this.wrapperWidth = display.wrapper.clientWidth
     4116  this.oldDisplayWidth = displayWidth(cm)
     4117  this.force = force
     4118  this.dims = getDimensions(cm)
     4119  this.events = []
     4120};
     4121
     4122DisplayUpdate.prototype.signal = function (emitter, type) {
     4123  if (hasHandler(emitter, type))
     4124    { this.events.push(arguments) }
     4125};
     4126DisplayUpdate.prototype.finish = function () {
     4127    var this$1 = this;
     4128
     4129  for (var i = 0; i < this.events.length; i++)
     4130    { signal.apply(null, this$1.events[i]) }
     4131};
     4132
     4133function maybeClipScrollbars(cm) {
     4134  var display = cm.display
     4135  if (!display.scrollbarsClipped && display.scroller.offsetWidth) {
     4136    display.nativeBarWidth = display.scroller.offsetWidth - display.scroller.clientWidth
     4137    display.heightForcer.style.height = scrollGap(cm) + "px"
     4138    display.sizer.style.marginBottom = -display.nativeBarWidth + "px"
     4139    display.sizer.style.borderRightWidth = scrollGap(cm) + "px"
     4140    display.scrollbarsClipped = true
     4141  }
     4142}
     4143
     4144function selectionSnapshot(cm) {
     4145  if (cm.hasFocus()) { return null }
     4146  var active = activeElt()
     4147  if (!active || !contains(cm.display.lineDiv, active)) { return null }
     4148  var result = {activeElt: active}
     4149  if (window.getSelection) {
     4150    var sel = window.getSelection()
     4151    if (sel.anchorNode && sel.extend && contains(cm.display.lineDiv, sel.anchorNode)) {
     4152      result.anchorNode = sel.anchorNode
     4153      result.anchorOffset = sel.anchorOffset
     4154      result.focusNode = sel.focusNode
     4155      result.focusOffset = sel.focusOffset
     4156    }
     4157  }
     4158  return result
     4159}
     4160
     4161function restoreSelection(snapshot) {
     4162  if (!snapshot || !snapshot.activeElt || snapshot.activeElt == activeElt()) { return }
     4163  snapshot.activeElt.focus()
     4164  if (snapshot.anchorNode && contains(document.body, snapshot.anchorNode) && contains(document.body, snapshot.focusNode)) {
     4165    var sel = window.getSelection(), range = document.createRange()
     4166    range.setEnd(snapshot.anchorNode, snapshot.anchorOffset)
     4167    range.collapse(false)
     4168    sel.removeAllRanges()
     4169    sel.addRange(range)
     4170    sel.extend(snapshot.focusNode, snapshot.focusOffset)
     4171  }
     4172}
     4173
     4174// Does the actual updating of the line display. Bails out
     4175// (returning false) when there is nothing to be done and forced is
     4176// false.
     4177function updateDisplayIfNeeded(cm, update) {
     4178  var display = cm.display, doc = cm.doc
     4179
     4180  if (update.editorIsHidden) {
     4181    resetView(cm)
     4182    return false
     4183  }
     4184
     4185  // Bail out if the visible area is already rendered and nothing changed.
     4186  if (!update.force &&
     4187      update.visible.from >= display.viewFrom && update.visible.to <= display.viewTo &&
     4188      (display.updateLineNumbers == null || display.updateLineNumbers >= display.viewTo) &&
     4189      display.renderedView == display.view && countDirtyView(cm) == 0)
     4190    { return false }
     4191
     4192  if (maybeUpdateLineNumberWidth(cm)) {
     4193    resetView(cm)
     4194    update.dims = getDimensions(cm)
     4195  }
     4196
     4197  // Compute a suitable new viewport (from & to)
     4198  var end = doc.first + doc.size
     4199  var from = Math.