Newsletter - Version 7.0.3

Version Description

  • New media selector for blocks
  • Minor fixes
  • Updated codemirror
  • Updated default theme
  • Fixed tag filter on posts block (when tags have parathesis or like)
Download this release

Release Info

Developer satollo
Plugin Icon 128x128 Newsletter
Version 7.0.3
Comparing to
See all releases

Code changes from version 7.0.2 to 7.0.3

Files changed (40) hide show
  1. admin.js +77 -43
  2. emails/blocks/html/options.php +1 -1
  3. emails/blocks/posts/block.php +3 -1
  4. emails/emails.php +11 -1
  5. emails/themes/default/theme-options.php +1 -1
  6. emails/themes/default/theme.php +9 -1
  7. emails/tnp-composer/_scripts/newsletter-builder-v2.js +2 -1
  8. includes/fields.php +34 -12
  9. includes/module.php +34 -8
  10. plugin.php +8 -7
  11. readme.txt +9 -1
  12. subscription/subscription.php +11 -8
  13. users/import.php +4 -0
  14. vendor/codemirror/addon/hint/css-hint.js +9 -3
  15. vendor/codemirror/addon/hint/html-hint.js +3 -0
  16. vendor/codemirror/addon/hint/javascript-hint.js +6 -1
  17. vendor/codemirror/addon/hint/show-hint.js +102 -29
  18. vendor/codemirror/addon/hint/sql-hint.js +304 -0
  19. vendor/codemirror/addon/hint/xml-hint.js +39 -17
  20. vendor/codemirror/codemirror.css +14 -10
  21. vendor/codemirror/codemirror.js +2024 -1922
  22. vendor/codemirror/mode/css/css.js +132 -100
  23. vendor/codemirror/mode/css/gss.html +1 -1
  24. vendor/codemirror/mode/css/index.html +7 -1
  25. vendor/codemirror/mode/css/less.html +1 -1
  26. vendor/codemirror/mode/css/less_test.js +4 -4
  27. vendor/codemirror/mode/css/scss.html +1 -1
  28. vendor/codemirror/mode/css/scss_test.js +5 -5
  29. vendor/codemirror/mode/css/test.js +29 -21
  30. vendor/codemirror/mode/htmlmixed/htmlmixed.js +4 -3
  31. vendor/codemirror/mode/htmlmixed/index.html +1 -1
  32. vendor/codemirror/mode/javascript/index.html +2 -2
  33. vendor/codemirror/mode/javascript/javascript.js +88 -45
  34. vendor/codemirror/mode/javascript/test.js +39 -0
  35. vendor/codemirror/mode/javascript/typescript.html +1 -1
  36. vendor/codemirror/mode/meta.js +13 -9
  37. vendor/codemirror/mode/php/index.html +1 -1
  38. vendor/codemirror/mode/php/php.js +4 -4
  39. vendor/codemirror/mode/xml/index.html +1 -1
  40. vendor/codemirror/mode/xml/xml.js +12 -1
admin.js CHANGED
@@ -1,53 +1,53 @@
1
- jQuery.cookie = function(name, value, options) {
2
- if (typeof value != 'undefined') { // name and value given, set cookie
3
- options = options || {};
4
- if (value === null) {
5
- value = '';
6
- options.expires = -1;
7
- }
8
- var expires = '';
9
- if (options.expires && (typeof options.expires == 'number' || options.expires.toUTCString)) {
10
- var date;
11
- if (typeof options.expires == 'number') {
12
- date = new Date();
13
- date.setTime(date.getTime() + (options.expires * 24 * 60 * 60 * 1000));
14
- } else {
15
- date = options.expires;
16
- }
17
- expires = '; expires=' + date.toUTCString(); // use expires attribute, max-age is not supported by IE
18
- }
19
- // CAUTION: Needed to parenthesize options.path and options.domain
20
- // in the following expressions, otherwise they evaluate to undefined
21
- // in the packed version for some reason...
22
- var path = options.path ? '; path=' + (options.path) : '';
23
- var domain = options.domain ? '; domain=' + (options.domain) : '';
24
- var secure = options.secure ? '; secure' : '';
25
- document.cookie = [name, '=', encodeURIComponent(value), expires, path, domain, secure].join('');
26
- } else { // only name given, get cookie
27
- var cookieValue = null;
28
- if (document.cookie && document.cookie != '') {
29
- var cookies = document.cookie.split(';');
30
- for (var i = 0; i < cookies.length; i++) {
31
- var cookie = jQuery.trim(cookies[i]);
32
- // Does this cookie string begin with the name we want?
33
- if (cookie.substring(0, name.length + 1) == (name + '=')) {
34
- cookieValue = decodeURIComponent(cookie.substring(name.length + 1));
35
- break;
36
  }
37
- }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
38
  }
39
- return cookieValue;
40
- }
41
  };
42
 
43
  function tnp_toggle_schedule() {
44
- jQuery("#tnp-schedule-button").toggle();
45
- jQuery("#tnp-schedule").toggle();
46
  }
47
 
48
  function tnp_select_toggle(s, t) {
49
  if (s.value == 1) {
50
- jQuery("#options-" + t).show();
51
  } else {
52
  jQuery("#options-" + t).hide();
53
  }
@@ -65,7 +65,7 @@ function tnp_date_onchange(field) {
65
  if (year.value === '' || month.value === '' || day.value === '') {
66
  base_field.value = 0;
67
  } else {
68
- base_field.value = new Date(year.value, month.value, day.value, 12, 0, 0).getTime()/1000;
69
  }
70
  //this.form.elements['options[" . esc_attr($name) . "]'].value = new Date(document.getElementById('" . esc_attr($name) . "_year').value, document.getElementById('" . esc_attr($name) . "_month').value, document.getElementById('" . esc_attr($name) . "_day').value, 12, 0, 0).getTime()/1000";
71
  }
@@ -130,7 +130,7 @@ window.onload = function () {
130
 
131
  function isNewsletterOptionsPage() {
132
  return jQuery("#tnp-nl-status").length
133
- && jQuery("#newsletter-form").length;
134
  }
135
 
136
  })();
@@ -142,6 +142,7 @@ window.onload = function () {
142
  * https://seballot.github.io/spectrum/
143
  */
144
  function tnp_controls_init() {
 
145
  jQuery(".tnpf-color").spectrum({
146
  type: 'color',
147
  allowEmpty: true,
@@ -149,4 +150,37 @@ function tnp_controls_init() {
149
  showInput: true,
150
  preferredFormat: 'hex'
151
  });
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
152
  }
1
+ jQuery.cookie = function (name, value, options) {
2
+ if (typeof value != 'undefined') { // name and value given, set cookie
3
+ options = options || {};
4
+ if (value === null) {
5
+ value = '';
6
+ options.expires = -1;
7
+ }
8
+ var expires = '';
9
+ if (options.expires && (typeof options.expires == 'number' || options.expires.toUTCString)) {
10
+ var date;
11
+ if (typeof options.expires == 'number') {
12
+ date = new Date();
13
+ date.setTime(date.getTime() + (options.expires * 24 * 60 * 60 * 1000));
14
+ } else {
15
+ date = options.expires;
16
+ }
17
+ expires = '; expires=' + date.toUTCString(); // use expires attribute, max-age is not supported by IE
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
18
  }
19
+ // CAUTION: Needed to parenthesize options.path and options.domain
20
+ // in the following expressions, otherwise they evaluate to undefined
21
+ // in the packed version for some reason...
22
+ var path = options.path ? '; path=' + (options.path) : '';
23
+ var domain = options.domain ? '; domain=' + (options.domain) : '';
24
+ var secure = options.secure ? '; secure' : '';
25
+ document.cookie = [name, '=', encodeURIComponent(value), expires, path, domain, secure].join('');
26
+ } else { // only name given, get cookie
27
+ var cookieValue = null;
28
+ if (document.cookie && document.cookie != '') {
29
+ var cookies = document.cookie.split(';');
30
+ for (var i = 0; i < cookies.length; i++) {
31
+ var cookie = jQuery.trim(cookies[i]);
32
+ // Does this cookie string begin with the name we want?
33
+ if (cookie.substring(0, name.length + 1) == (name + '=')) {
34
+ cookieValue = decodeURIComponent(cookie.substring(name.length + 1));
35
+ break;
36
+ }
37
+ }
38
+ }
39
+ return cookieValue;
40
  }
 
 
41
  };
42
 
43
  function tnp_toggle_schedule() {
44
+ jQuery("#tnp-schedule-button").toggle();
45
+ jQuery("#tnp-schedule").toggle();
46
  }
47
 
48
  function tnp_select_toggle(s, t) {
49
  if (s.value == 1) {
50
+ jQuery("#options-" + t).show();
51
  } else {
52
  jQuery("#options-" + t).hide();
53
  }
65
  if (year.value === '' || month.value === '' || day.value === '') {
66
  base_field.value = 0;
67
  } else {
68
+ base_field.value = new Date(year.value, month.value, day.value, 12, 0, 0).getTime() / 1000;
69
  }
70
  //this.form.elements['options[" . esc_attr($name) . "]'].value = new Date(document.getElementById('" . esc_attr($name) . "_year').value, document.getElementById('" . esc_attr($name) . "_month').value, document.getElementById('" . esc_attr($name) . "_day').value, 12, 0, 0).getTime()/1000";
71
  }
130
 
131
  function isNewsletterOptionsPage() {
132
  return jQuery("#tnp-nl-status").length
133
+ && jQuery("#newsletter-form").length;
134
  }
135
 
136
  })();
142
  * https://seballot.github.io/spectrum/
143
  */
144
  function tnp_controls_init() {
145
+ console.log('Controls init');
146
  jQuery(".tnpf-color").spectrum({
147
  type: 'color',
148
  allowEmpty: true,
150
  showInput: true,
151
  preferredFormat: 'hex'
152
  });
153
+ }
154
+
155
+ function tnp_fields_media_mini_select(el) {
156
+ event.preventDefault();
157
+
158
+ let name = jQuery(el).data("name");
159
+
160
+ let tnp_uploader = wp.media({
161
+ title: "Select an image",
162
+ button: {
163
+ text: "Select"
164
+ },
165
+ multiple: false
166
+ }).on("select", function () {
167
+ let media = tnp_uploader.state().get("selection").first();
168
+ let $field = jQuery("#" + name + "_id");
169
+ $field.val(media.id);
170
+ $field.trigger("change");
171
+
172
+ var img_url = media.attributes.url;
173
+ if (typeof media.attributes.sizes.thumbnail !== "undefined")
174
+ img_url = media.attributes.sizes.thumbnail.url;
175
+ document.getElementById(name + "_img").src = img_url;
176
+ }).open();
177
+ }
178
+
179
+ function tnp_fields_media_mini_remove(name) {
180
+ event.preventDefault();
181
+ event.stopPropagation();
182
+ let $field = jQuery("#" + name + "_id");
183
+ $field.val("");
184
+ $field.trigger("change");
185
+ document.getElementById(name + "_img").src = "";
186
  }
emails/blocks/html/options.php CHANGED
@@ -25,7 +25,7 @@ $options = array_merge($default_options, $options);
25
  lineNumbers: true,
26
  mode: 'htmlmixed',
27
  lineWrapping: true,
28
- extraKeys: {"Ctrl-Space": "autocomplete"}
29
  });
30
  });
31
  </script>
25
  lineNumbers: true,
26
  mode: 'htmlmixed',
27
  lineWrapping: true,
28
+ //extraKeys: {"Ctrl-Space": "autocomplete"}
29
  });
30
  });
31
  </script>
emails/blocks/posts/block.php CHANGED
@@ -75,7 +75,9 @@ if (!empty($options['categories'])) {
75
  }
76
 
77
  if (!empty($options['tags'])) {
78
- $filters['tag'] = $options['tags'];
 
 
79
  }
80
 
81
  if ($context['type'] != 'automated') {
75
  }
76
 
77
  if (!empty($options['tags'])) {
78
+ $tags = explode(',', $options['tags']);
79
+ $tags = array_unique(array_map('sanitize_title', $tags));
80
+ $filters['tag'] = $tags;
81
  }
82
 
83
  if ($context['type'] != 'automated') {
emails/emails.php CHANGED
@@ -276,6 +276,11 @@ class NewsletterEmails extends NewsletterModule {
276
  static function get_outlook_wrapper_close() {
277
  echo "<!--[if mso | IE]></td></tr></table><![endif]-->";
278
  }
 
 
 
 
 
279
 
280
  /**
281
  * Renders a block identified by its id, using the block options and adding a wrapper
@@ -285,6 +290,8 @@ class NewsletterEmails extends NewsletterModule {
285
  * @param type $options
286
  */
287
  function render_block($block_id = null, $wrapper = false, $options = array(), $context = array()) {
 
 
288
  include_once NEWSLETTER_INCLUDES_DIR . '/helper.php';
289
 
290
  $width = 600;
@@ -296,8 +303,11 @@ class NewsletterEmails extends NewsletterModule {
296
  if (!is_array($options)) {
297
  $options = array();
298
  }
299
-
 
 
300
  $options = wp_kses_post_deep($options);
 
301
 
302
  $block_options = get_option('newsletter_main');
303
 
276
  static function get_outlook_wrapper_close() {
277
  echo "<!--[if mso | IE]></td></tr></table><![endif]-->";
278
  }
279
+
280
+ function hook_safe_style_css($rules) {
281
+ $rules[] = 'display';
282
+ return $rules;
283
+ }
284
 
285
  /**
286
  * Renders a block identified by its id, using the block options and adding a wrapper
290
  * @param type $options
291
  */
292
  function render_block($block_id = null, $wrapper = false, $options = array(), $context = array()) {
293
+ static $kses_style_filter = false;
294
+
295
  include_once NEWSLETTER_INCLUDES_DIR . '/helper.php';
296
 
297
  $width = 600;
303
  if (!is_array($options)) {
304
  $options = array();
305
  }
306
+
307
+
308
+ add_filter('safe_style_css', [$this, 'hook_safe_style_css']);
309
  $options = wp_kses_post_deep($options);
310
+ remove_filter('safe_style_css', [$this, 'hook_safe_style_css']);
311
 
312
  $block_options = get_option('newsletter_main');
313
 
emails/themes/default/theme-options.php CHANGED
@@ -3,7 +3,7 @@ defined('ABSPATH') || exit;
3
  ?>
4
 
5
  <table class="form-table">
6
- <tr><td colspan="2">General options for header, social links and footer sections could also be set in <a href="?page=newsletter_main_main">Blog Info panel</a>.</td></tr>
7
  <tr>
8
  <th><?php _e('Primary color', 'newsletter') ?></th>
9
  <td>
3
  ?>
4
 
5
  <table class="form-table">
6
+ <tr><td colspan="2">General options for header, social links and footer sections could also be set in <a href="?page=newsletter_main_info">Blog Info panel</a>.</td></tr>
7
  <tr>
8
  <th><?php _e('Primary color', 'newsletter') ?></th>
9
  <td>
emails/themes/default/theme.php CHANGED
@@ -37,7 +37,9 @@ if (isset($theme_options['theme_posts'])) {
37
  }
38
 
39
  if (!empty($theme_options['theme_tags'])) {
40
- $filters['tag'] = $theme_options['theme_tags'];
 
 
41
  }
42
 
43
  if (!empty($theme_options['theme_post_types'])) {
@@ -60,6 +62,12 @@ if (isset($theme_options['theme_posts'])) {
60
  <meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
61
  <meta name="viewport" content="width=device-width, initial-scale=1">
62
  <style type="text/css">
 
 
 
 
 
 
63
  a {
64
  text-decoration: none;
65
  color: <?php echo $color; ?>;
37
  }
38
 
39
  if (!empty($theme_options['theme_tags'])) {
40
+ $tags = explode(',', $theme_options['theme_tags']);
41
+ $tags = array_unique(array_map('sanitize_title', $tags));
42
+ $filters['tag'] = $tags;
43
  }
44
 
45
  if (!empty($theme_options['theme_post_types'])) {
62
  <meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
63
  <meta name="viewport" content="width=device-width, initial-scale=1">
64
  <style type="text/css">
65
+ * {
66
+ line-height: normal;
67
+ }
68
+ h1, h2, h3, h4 {
69
+ line-height: normal;
70
+ }
71
  a {
72
  text-decoration: none;
73
  color: <?php echo $color; ?>;
emails/tnp-composer/_scripts/newsletter-builder-v2.js CHANGED
@@ -63,8 +63,9 @@ jQuery.fn.perform_block_edit = function () {
63
  context_type: tnp_context_type,
64
  options: options
65
  }, function () {
 
66
  start_options = jQuery("#tnpc-block-options-form").serialize();
67
- tnp_controls_init();
68
  });
69
 
70
  } else {
63
  context_type: tnp_context_type,
64
  options: options
65
  }, function () {
66
+ console.log('Block form options loaded');
67
  start_options = jQuery("#tnpc-block-options-form").serialize();
68
+ //tnp_controls_init();
69
  });
70
 
71
  } else {
includes/fields.php CHANGED
@@ -1,8 +1,8 @@
1
  <?php
2
 
3
  class NewsletterFields {
4
-
5
  /* @var NewsletterControls */
 
6
  var $controls;
7
 
8
  public function __construct(NewsletterControls $controls) {
@@ -257,7 +257,7 @@ class NewsletterFields {
257
  $this->_close();
258
  }
259
 
260
- /**
261
  * General field to collect an element dimension in pixels
262
  *
263
  * Attributes:
@@ -277,7 +277,7 @@ class NewsletterFields {
277
  $this->_close();
278
  }
279
 
280
- /**
281
  * Collects a color in HEX format with a picker.
282
  */
283
  public function color($name, $label, $attrs = []) {
@@ -288,7 +288,7 @@ class NewsletterFields {
288
  $this->_close();
289
  }
290
 
291
- /**
292
  * Configuration for a simple button with label and color
293
  *
294
  * Attributes:
@@ -431,21 +431,43 @@ class NewsletterFields {
431
  *
432
  * Attributes:
433
  * - alt: if true shows the alternate text field for the "alt" attribute
 
434
  *
435
  * @param string $name
436
  * @param string $label
437
  * @param array $attrs
438
  */
439
  public function media($name, $label = '', $attrs = []) {
440
- $attrs = $this->_merge_attrs($attrs, ['alt' => false]);
441
- $this->_open('tnp-media');
442
- $this->_label($label);
443
- $this->controls->media($name);
444
- if ($attrs['alt']) {
445
- $this->controls->text($name . '_alt', 20, 'Alternative text');
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
446
  }
447
- $this->_description($attrs);
448
- $this->_close();
449
  }
450
 
451
  public function categories($name = 'categories', $label = '', $attrs = []) {
1
  <?php
2
 
3
  class NewsletterFields {
 
4
  /* @var NewsletterControls */
5
+
6
  var $controls;
7
 
8
  public function __construct(NewsletterControls $controls) {
257
  $this->_close();
258
  }
259
 
260
+ /**
261
  * General field to collect an element dimension in pixels
262
  *
263
  * Attributes:
277
  $this->_close();
278
  }
279
 
280
+ /**
281
  * Collects a color in HEX format with a picker.
282
  */
283
  public function color($name, $label, $attrs = []) {
288
  $this->_close();
289
  }
290
 
291
+ /**
292
  * Configuration for a simple button with label and color
293
  *
294
  * Attributes:
431
  *
432
  * Attributes:
433
  * - alt: if true shows the alternate text field for the "alt" attribute
434
+ * - layout: if set to "mini" the controls is shown as a mini selector, no labels
435
  *
436
  * @param string $name
437
  * @param string $label
438
  * @param array $attrs
439
  */
440
  public function media($name, $label = '', $attrs = []) {
441
+ $attrs = $this->_merge_attrs($attrs, ['alt' => false, 'layout' => '']);
442
+
443
+ if (empty($attrs['layout'])) {
444
+ $this->_open('tnp-media');
445
+ $this->_label($label);
446
+ $this->controls->media($name);
447
+ if ($attrs['alt']) {
448
+ $this->controls->text($name . '_alt', 20, 'Alternative text');
449
+ }
450
+ $this->_description($attrs);
451
+ $this->_close();
452
+ } else {
453
+ if (isset($this->controls->data[$name]['id'])) {
454
+ $media_id = (int) $this->controls->data[$name]['id'];
455
+ $media = wp_get_attachment_image_src($media_id, 'thumbnail');
456
+ } else {
457
+ $media = false;
458
+ $media_id = 0;
459
+ }
460
+ echo '<div class="tnpf-media-mini-select" data-name="' . esc_attr($name) . '" style="width: 100px; height: 100px; overflow: hidden; border: 1px dashed #999; position: relative" onclick="tnp_fields_media_mini_select(this)">';
461
+ echo '<a style="position: absolute; top: 5px; right: 5px; background-color: #000; color: #fff; padding: 0px 5px 6px 5px; font-size: 24px; display: block; text-decoration: none" href="#" onclick="tnp_fields_media_mini_remove(\'' . esc_attr($name) . '\'); return false;">&times;</a>';
462
+ if ($media) {
463
+ echo '<img style="max-width: 100%; height: auto; display: block" id="' . esc_attr($name) . '_img" src="' . esc_attr($media[0]) . '">';
464
+ } else {
465
+ echo '<img style="max-width: 100%; height: auto; display: block" id="' . esc_attr($name) . '_img" src="">';
466
+ }
467
+
468
+ echo '</div>';
469
+ echo '<input type="hidden" id="' . esc_attr($name) . '_id" name="options[' . esc_attr($name) . '][id]" value="' . esc_attr($media_id) . '">';
470
  }
 
 
471
  }
472
 
473
  public function categories($name = 'categories', $label = '', $attrs = []) {
includes/module.php CHANGED
@@ -305,13 +305,17 @@ class TNP_User {
305
  }
306
 
307
  /**
308
- * @property int $id The subscriber unique identifier
309
- * @property string $subject The subscriber email
310
- * @property string $message The subscriber name or first name
311
- * @property string $track The subscriber last name
312
- * @property array $options The subscriber status
 
 
 
 
313
  * */
314
- abstract class TNP_Email {
315
 
316
  const STATUS_DRAFT = 'new';
317
  const STATUS_SENT = 'sent';
@@ -844,7 +848,7 @@ class NewsletterModule {
844
  }
845
 
846
  function admin_menu() {
847
-
848
  }
849
 
850
  function add_menu_page($page, $title, $capability = '') {
@@ -990,7 +994,7 @@ class NewsletterModule {
990
 
991
  /**
992
  * Delete one or more emails identified by ID (single value or array of ID)
993
- *
994
  * @global wpdb $wpdb
995
  * @param int|array $id Single numeric ID or an array of IDs to be deleted
996
  * @return boolean
@@ -2389,6 +2393,28 @@ class NewsletterModule {
2389
  return $posts;
2390
  }
2391
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
2392
  protected function generate_admin_notification_message($user) {
2393
 
2394
  $message = file_get_contents(__DIR__ . '/notification.html');
305
  }
306
 
307
  /**
308
+ * @property int $id The email unique identifier
309
+ * @property string $subject The email subject
310
+ * @property string $message The email html message
311
+ * @property int $track Check if the email stats should be active
312
+ * @property array $options Email options
313
+ * @property int $total Total emails to send
314
+ * @property int $sent Total sent emails by now
315
+ * @property int $open_count Total opened emails
316
+ * @property int $click_count Total clicked emails
317
  * */
318
+ class TNP_Email {
319
 
320
  const STATUS_DRAFT = 'new';
321
  const STATUS_SENT = 'sent';
848
  }
849
 
850
  function admin_menu() {
851
+
852
  }
853
 
854
  function add_menu_page($page, $title, $capability = '') {
994
 
995
  /**
996
  * Delete one or more emails identified by ID (single value or array of ID)
997
+ *
998
  * @global wpdb $wpdb
999
  * @param int|array $id Single numeric ID or an array of IDs to be deleted
1000
  * @return boolean
2393
  return $posts;
2394
  }
2395
 
2396
+ function get_wp_query($filters, $langiage = '') {
2397
+ if ($language) {
2398
+ if (class_exists('SitePress')) {
2399
+ $this->switch_language($language);
2400
+ $filters['suppress_filters'] = false;
2401
+ }
2402
+ if (class_exists('Polylang')) {
2403
+ $filters['lang'] = $language;
2404
+ }
2405
+ }
2406
+
2407
+ $posts = new WP_Query($filters);
2408
+
2409
+ if ($language) {
2410
+ if (class_exists('SitePress')) {
2411
+ $this->switch_language($current_language);
2412
+ }
2413
+ }
2414
+
2415
+ return $posts;
2416
+ }
2417
+
2418
  protected function generate_admin_notification_message($user) {
2419
 
2420
  $message = file_get_contents(__DIR__ . '/notification.html');
plugin.php CHANGED
@@ -4,7 +4,7 @@
4
  Plugin Name: Newsletter
5
  Plugin URI: https://www.thenewsletterplugin.com/plugins/newsletter
6
  Description: Newsletter is a cool plugin to create your own subscriber list, to send newsletters, to build your business. <strong>Before update give a look to <a href="https://www.thenewsletterplugin.com/category/release">this page</a> to know what's changed.</strong>
7
- Version: 7.0.2
8
  Author: Stefano Lissa & The Newsletter Team
9
  Author URI: https://www.thenewsletterplugin.com
10
  Disclaimer: Use at your own risk. No warranty expressed or implied is provided.
@@ -35,7 +35,7 @@ if (version_compare(phpversion(), '5.6', '<')) {
35
  return;
36
  }
37
 
38
- define('NEWSLETTER_VERSION', '7.0.2');
39
 
40
  global $newsletter, $wpdb;
41
 
@@ -314,7 +314,7 @@ class Newsletter extends NewsletterModule {
314
  if (!$install_time) {
315
  update_option('newsletter_install_time', time(), false);
316
  }
317
-
318
  touch(NEWSLETTER_LOG_DIR . '/index.html');
319
 
320
  Newsletter::instance()->upgrade();
@@ -436,7 +436,7 @@ class Newsletter extends NewsletterModule {
436
  delete_transient("tnp_extensions_json");
437
 
438
  touch(NEWSLETTER_LOG_DIR . '/index.html');
439
-
440
  return true;
441
  }
442
 
@@ -606,7 +606,7 @@ class Newsletter extends NewsletterModule {
606
  $emails = $this->get_results("select * from " . NEWSLETTER_EMAILS_TABLE . " where status='sending' and send_on<" . time() . " order by id asc");
607
  $this->logger->debug(__METHOD__ . '> Emails found in sending status: ' . count($emails));
608
 
609
- foreach ($emails as $email) {
610
  $this->logger->info(__METHOD__ . '> Start newsletter ' . $email->id);
611
  $r = $this->send($email);
612
  if ($this->limits_exceeded()) {
@@ -690,6 +690,7 @@ class Newsletter extends NewsletterModule {
690
  if (empty($users)) {
691
  $this->logger->info(__METHOD__ . '> No more users, set as sent');
692
  $wpdb->query("update " . NEWSLETTER_EMAILS_TABLE . " set status='sent', total=sent where id=" . $email->id . " limit 1");
 
693
  return true;
694
  }
695
  } else {
@@ -975,9 +976,9 @@ class Newsletter extends NewsletterModule {
975
  $mailer->from_name = $this->options['sender_name'];
976
  return $mailer->send($message);
977
  }
978
-
979
  /**
980
- *
981
  * @param type $to
982
  * @param type $subject
983
  * @param string|array $message If string is considered HTML, is array should contains the keys "html" and "text"
4
  Plugin Name: Newsletter
5
  Plugin URI: https://www.thenewsletterplugin.com/plugins/newsletter
6
  Description: Newsletter is a cool plugin to create your own subscriber list, to send newsletters, to build your business. <strong>Before update give a look to <a href="https://www.thenewsletterplugin.com/category/release">this page</a> to know what's changed.</strong>
7
+ Version: 7.0.3
8
  Author: Stefano Lissa & The Newsletter Team
9
  Author URI: https://www.thenewsletterplugin.com
10
  Disclaimer: Use at your own risk. No warranty expressed or implied is provided.
35
  return;
36
  }
37
 
38
+ define('NEWSLETTER_VERSION', '7.0.3');
39
 
40
  global $newsletter, $wpdb;
41
 
314
  if (!$install_time) {
315
  update_option('newsletter_install_time', time(), false);
316
  }
317
+
318
  touch(NEWSLETTER_LOG_DIR . '/index.html');
319
 
320
  Newsletter::instance()->upgrade();
436
  delete_transient("tnp_extensions_json");
437
 
438
  touch(NEWSLETTER_LOG_DIR . '/index.html');
439
+
440
  return true;
441
  }
442
 
606
  $emails = $this->get_results("select * from " . NEWSLETTER_EMAILS_TABLE . " where status='sending' and send_on<" . time() . " order by id asc");
607
  $this->logger->debug(__METHOD__ . '> Emails found in sending status: ' . count($emails));
608
 
609
+ foreach ($emails as $email) {
610
  $this->logger->info(__METHOD__ . '> Start newsletter ' . $email->id);
611
  $r = $this->send($email);
612
  if ($this->limits_exceeded()) {
690
  if (empty($users)) {
691
  $this->logger->info(__METHOD__ . '> No more users, set as sent');
692
  $wpdb->query("update " . NEWSLETTER_EMAILS_TABLE . " set status='sent', total=sent where id=" . $email->id . " limit 1");
693
+ do_action('newsletter_ended_sending_newsletter', $email);
694
  return true;
695
  }
696
  } else {
976
  $mailer->from_name = $this->options['sender_name'];
977
  return $mailer->send($message);
978
  }
979
+
980
  /**
981
+ *
982
  * @param type $to
983
  * @param type $subject
984
  * @param string|array $message If string is considered HTML, is array should contains the keys "html" and "text"
readme.txt CHANGED
@@ -2,7 +2,7 @@
2
  Tags: email, email marketing, newsletter, newsletter subscribers, welcome email, signup forms, contact, lead generation, popup, marketing automation
3
  Requires at least: 3.4.0
4
  Tested up to: 5.6
5
- Stable tag: 7.0.2
6
  Requires PHP: 5.6
7
  Contributors: satollo,webagile,michael-travan
8
  License: GPLv2 or later
@@ -118,6 +118,14 @@ Thank you, The Newsletter Team
118
 
119
  == Changelog ==
120
 
 
 
 
 
 
 
 
 
121
  = 7.0.2 =
122
 
123
  * Fixed media 2x resize
2
  Tags: email, email marketing, newsletter, newsletter subscribers, welcome email, signup forms, contact, lead generation, popup, marketing automation
3
  Requires at least: 3.4.0
4
  Tested up to: 5.6
5
+ Stable tag: 7.0.3
6
  Requires PHP: 5.6
7
  Contributors: satollo,webagile,michael-travan
8
  License: GPLv2 or later
118
 
119
  == Changelog ==
120
 
121
+ = 7.0.3 =
122
+
123
+ * New media selector for blocks
124
+ * Minor fixes
125
+ * Updated codemirror
126
+ * Updated default theme
127
+ * Fixed tag filter on posts block (when tags have parathesis or like)
128
+
129
  = 7.0.2 =
130
 
131
  * Fixed media 2x resize
subscription/subscription.php CHANGED
@@ -461,9 +461,12 @@ class NewsletterSubscription extends NewsletterModule {
461
  *
462
  * @return \TNP_Subscription
463
  */
464
- function get_default_subscription($language = '') {
465
  $subscription = new TNP_Subscription();
466
- $subscription->data->language = $language;
 
 
 
467
  $subscription->optin = $this->is_double_optin() ? 'double' : 'single';
468
  $subscription->if_exists = empty($this->options['multiple']) ? TNP_Subscription::EXISTING_ERROR : TNP_Subscription::EXISTING_MERGE;
469
 
@@ -723,14 +726,14 @@ class NewsletterSubscription extends NewsletterModule {
723
  * @return TNP_Subscription
724
  */
725
  function build_subscription() {
726
-
727
  $language = '';
728
  if (!empty($_REQUEST['nlang'])) {
729
  $language = $_REQUEST['nlang'];
730
  } else {
731
  $language = $this->get_current_language();
732
  }
733
-
734
  $subscription = $this->get_default_subscription($language);
735
  $data = $subscription->data;
736
 
@@ -784,7 +787,7 @@ class NewsletterSubscription extends NewsletterModule {
784
  continue;
785
  }
786
  $data->lists['' . $list_id] = 1;
787
-
788
  }
789
  } else {
790
  $this->logger->debug('No lists received');
@@ -929,7 +932,7 @@ class NewsletterSubscription extends NewsletterModule {
929
  if (empty($template) || strpos($template, '{message}') === false) {
930
  $template = '{message}';
931
  }
932
-
933
  if (is_array($message)) {
934
  $message['html'] = str_replace('{message}', $message['html'], $template);
935
  $message['html'] = $this->replace($message['html'], $user);
@@ -943,7 +946,7 @@ class NewsletterSubscription extends NewsletterModule {
943
  $headers = [];
944
 
945
  // Replaces tags from the template
946
-
947
  $subject = $this->replace($subject, $user);
948
 
949
  return Newsletter::instance()->mail($user->email, $subject, $message, $headers);
@@ -1038,7 +1041,7 @@ class NewsletterSubscription extends NewsletterModule {
1038
 
1039
  return $this->mail($user, $subject, $message);
1040
  }
1041
-
1042
  function get_text_message($type) {
1043
  switch ($type) {
1044
  case 'confirmation':
461
  *
462
  * @return \TNP_Subscription
463
  */
464
+ function get_default_subscription($language = null) {
465
  $subscription = new TNP_Subscription();
466
+
467
+ $language = is_null( $language ) ? $this->get_current_language() : $language;
468
+
469
+ $subscription->data->language = $language ;
470
  $subscription->optin = $this->is_double_optin() ? 'double' : 'single';
471
  $subscription->if_exists = empty($this->options['multiple']) ? TNP_Subscription::EXISTING_ERROR : TNP_Subscription::EXISTING_MERGE;
472
 
726
  * @return TNP_Subscription
727
  */
728
  function build_subscription() {
729
+
730
  $language = '';
731
  if (!empty($_REQUEST['nlang'])) {
732
  $language = $_REQUEST['nlang'];
733
  } else {
734
  $language = $this->get_current_language();
735
  }
736
+
737
  $subscription = $this->get_default_subscription($language);
738
  $data = $subscription->data;
739
 
787
  continue;
788
  }
789
  $data->lists['' . $list_id] = 1;
790
+
791
  }
792
  } else {
793
  $this->logger->debug('No lists received');
932
  if (empty($template) || strpos($template, '{message}') === false) {
933
  $template = '{message}';
934
  }
935
+
936
  if (is_array($message)) {
937
  $message['html'] = str_replace('{message}', $message['html'], $template);
938
  $message['html'] = $this->replace($message['html'], $user);
946
  $headers = [];
947
 
948
  // Replaces tags from the template
949
+
950
  $subject = $this->replace($subject, $user);
951
 
952
  return Newsletter::instance()->mail($user->email, $subject, $message, $headers);
1041
 
1042
  return $this->mail($user, $subject, $message);
1043
  }
1044
+
1045
  function get_text_message($type) {
1046
  switch ($type) {
1047
  case 'confirmation':
users/import.php CHANGED
@@ -149,6 +149,10 @@ if ($controls->is_action('import')) {
149
  <div id="tnp-heading">
150
 
151
  <h2><?php _e('Import', 'newsletter') ?></h2>
 
 
 
 
152
  <p>
153
  The import and export functions <strong>ARE NOT for backup</strong>. If you want to backup you should consider to backup the
154
  wp_newsletter* tables. Please, read on bottom of this page the data format to use and other important notes.</p>
149
  <div id="tnp-heading">
150
 
151
  <h2><?php _e('Import', 'newsletter') ?></h2>
152
+ <p>
153
+ <strong>Please,consider to use the free <a href="?page=newsletter_main_extensions">Advanced import addon</a>
154
+ to manage more fields and different file formats.</strong>
155
+ </p>
156
  <p>
157
  The import and export functions <strong>ARE NOT for backup</strong>. If you want to backup you should consider to backup the
158
  wp_newsletter* tables. Please, read on bottom of this page the data format to use and other important notes.</p>
vendor/codemirror/addon/hint/css-hint.js CHANGED
@@ -11,9 +11,15 @@
11
  })(function(CodeMirror) {
12
  "use strict";
13
 
14
- var pseudoClasses = {link: 1, visited: 1, active: 1, hover: 1, focus: 1,
15
- "first-letter": 1, "first-line": 1, "first-child": 1,
16
- before: 1, after: 1, lang: 1};
 
 
 
 
 
 
17
 
18
  CodeMirror.registerHelper("hint", "css", function(cm) {
19
  var cur = cm.getCursor(), token = cm.getTokenAt(cur);
11
  })(function(CodeMirror) {
12
  "use strict";
13
 
14
+ var pseudoClasses = {"active":1, "after":1, "before":1, "checked":1, "default":1,
15
+ "disabled":1, "empty":1, "enabled":1, "first-child":1, "first-letter":1,
16
+ "first-line":1, "first-of-type":1, "focus":1, "hover":1, "in-range":1,
17
+ "indeterminate":1, "invalid":1, "lang":1, "last-child":1, "last-of-type":1,
18
+ "link":1, "not":1, "nth-child":1, "nth-last-child":1, "nth-last-of-type":1,
19
+ "nth-of-type":1, "only-of-type":1, "only-child":1, "optional":1, "out-of-range":1,
20
+ "placeholder":1, "read-only":1, "read-write":1, "required":1, "root":1,
21
+ "selection":1, "target":1, "valid":1, "visited":1
22
+ };
23
 
24
  CodeMirror.registerHelper("hint", "css", function(cm) {
25
  var cur = cm.getCursor(), token = cm.getTokenAt(cur);
vendor/codemirror/addon/hint/html-hint.js CHANGED
@@ -98,6 +98,7 @@
98
  dfn: s,
99
  dir: s,
100
  div: s,
 
101
  dl: s,
102
  dt: s,
103
  em: s,
@@ -322,6 +323,8 @@
322
  itemtype: null,
323
  lang: ["en", "es"],
324
  spellcheck: ["true", "false"],
 
 
325
  style: null,
326
  tabindex: ["1", "2", "3", "4", "5", "6", "7", "8", "9"],
327
  title: null,
98
  dfn: s,
99
  dir: s,
100
  div: s,
101
+ dialog: { attrs: { open: null } },
102
  dl: s,
103
  dt: s,
104
  em: s,
323
  itemtype: null,
324
  lang: ["en", "es"],
325
  spellcheck: ["true", "false"],
326
+ autocorrect: ["true", "false"],
327
+ autocapitalize: ["true", "false"],
328
  style: null,
329
  tabindex: ["1", "2", "3", "4", "5", "6", "7", "8", "9"],
330
  title: null,
vendor/codemirror/addon/hint/javascript-hint.js CHANGED
@@ -144,10 +144,15 @@
144
  base = base[context.pop().string];
145
  if (base != null) gatherCompletions(base);
146
  } else {
147
- // If not, just look in the global object and any local scope
148
  // (reading into JS mode internals to get at the local and global variables)
149
  for (var v = token.state.localVars; v; v = v.next) maybeAdd(v.name);
 
 
150
  for (var v = token.state.globalVars; v; v = v.next) maybeAdd(v.name);
 
 
 
151
  if (!options || options.useGlobalScope !== false)
152
  gatherCompletions(global);
153
  forEach(keywords, maybeAdd);
144
  base = base[context.pop().string];
145
  if (base != null) gatherCompletions(base);
146
  } else {
147
+ // If not, just look in the global object, any local scope, and optional additional-context
148
  // (reading into JS mode internals to get at the local and global variables)
149
  for (var v = token.state.localVars; v; v = v.next) maybeAdd(v.name);
150
+ for (var c = token.state.context; c; c = c.prev)
151
+ for (var v = c.vars; v; v = v.next) maybeAdd(v.name)
152
  for (var v = token.state.globalVars; v; v = v.next) maybeAdd(v.name);
153
+ if (options && options.additionalContext != null)
154
+ for (var key in options.additionalContext)
155
+ maybeAdd(key);
156
  if (!options || options.useGlobalScope !== false)
157
  gatherCompletions(global);
158
  forEach(keywords, maybeAdd);
vendor/codemirror/addon/hint/show-hint.js CHANGED
@@ -1,6 +1,8 @@
1
  // CodeMirror, copyright (c) by Marijn Haverbeke and others
2
  // Distributed under an MIT license: https://codemirror.net/LICENSE
3
 
 
 
4
  (function(mod) {
5
  if (typeof exports == "object" && typeof module == "object") // CommonJS
6
  mod(require("../../lib/codemirror"));
@@ -46,6 +48,10 @@
46
  completion.update(true);
47
  });
48
 
 
 
 
 
49
  function Completion(cm, options) {
50
  this.cm = cm;
51
  this.options = options;
@@ -81,12 +87,19 @@
81
  },
82
 
83
  pick: function(data, i) {
84
- var completion = data.list[i];
85
- if (completion.hint) completion.hint(this.cm, data, completion);
86
- else this.cm.replaceRange(getText(completion), completion.from || data.from,
87
- completion.to || data.to, "complete");
88
- CodeMirror.signal(data, "pick", completion);
89
- this.close();
 
 
 
 
 
 
 
90
  },
91
 
92
  cursorActivity: function() {
@@ -95,11 +108,18 @@
95
  this.debounce = 0;
96
  }
97
 
 
 
 
 
 
98
  var pos = this.cm.getCursor(), line = this.cm.getLine(pos.line);
99
  if (pos.line != this.startPos.line || line.length - pos.ch != this.startLen - this.startPos.ch ||
100
- pos.ch < this.startPos.ch || this.cm.somethingSelected() ||
101
  (!pos.ch || this.options.closeCharacters.test(line.charAt(pos.ch - 1)))) {
102
- this.close();
 
 
103
  } else {
104
  var self = this;
105
  this.debounce = requestAnimationFrame(function() {self.update();});
@@ -163,6 +183,14 @@
163
  Tab: handle.pick,
164
  Esc: handle.close
165
  };
 
 
 
 
 
 
 
 
166
  var custom = completion.options.customKeys;
167
  var ourMap = custom ? {} : baseMap;
168
  function addBinding(key, val) {
@@ -198,47 +226,66 @@
198
  this.data = data;
199
  this.picked = false;
200
  var widget = this, cm = completion.cm;
 
 
201
 
202
- var hints = this.hints = document.createElement("ul");
203
  var theme = completion.cm.options.theme;
204
  hints.className = "CodeMirror-hints " + theme;
205
  this.selectedHint = data.selectedHint || 0;
206
 
207
  var completions = data.list;
208
  for (var i = 0; i < completions.length; ++i) {
209
- var elt = hints.appendChild(document.createElement("li")), cur = completions[i];
210
  var className = HINT_ELEMENT_CLASS + (i != this.selectedHint ? "" : " " + ACTIVE_HINT_ELEMENT_CLASS);
211
  if (cur.className != null) className = cur.className + " " + className;
212
  elt.className = className;
213
  if (cur.render) cur.render(elt, data, cur);
214
- else elt.appendChild(document.createTextNode(cur.displayText || getText(cur)));
215
  elt.hintId = i;
216
  }
217
 
 
218
  var pos = cm.cursorCoords(completion.options.alignWithWord ? data.from : null);
219
  var left = pos.left, top = pos.bottom, below = true;
220
- hints.style.left = left + "px";
221
- hints.style.top = top + "px";
 
 
 
 
 
 
 
 
 
 
 
222
  // If we're at the edge of the screen, then we want the menu to appear on the left of the cursor.
223
- var winW = window.innerWidth || Math.max(document.body.offsetWidth, document.documentElement.offsetWidth);
224
- var winH = window.innerHeight || Math.max(document.body.offsetHeight, document.documentElement.offsetHeight);
225
- (completion.options.container || document.body).appendChild(hints);
226
- var box = hints.getBoundingClientRect(), overlapY = box.bottom - winH;
227
- var scrolls = hints.scrollHeight > hints.clientHeight + 1
228
- var startScroll = cm.getScrollInfo();
229
 
 
 
 
 
 
 
 
 
230
  if (overlapY > 0) {
231
  var height = box.bottom - box.top, curTop = pos.top - (pos.bottom - box.top);
232
  if (curTop - height > 0) { // Fits above cursor
233
- hints.style.top = (top = pos.top - height) + "px";
234
  below = false;
235
  } else if (height > winH) {
236
  hints.style.height = (winH - 5) + "px";
237
- hints.style.top = (top = pos.bottom - box.top) + "px";
238
  var cursor = cm.getCursor();
239
  if (data.from.ch != cursor.ch) {
240
  pos = cm.cursorCoords(cursor);
241
- hints.style.left = (left = pos.left) + "px";
242
  box = hints.getBoundingClientRect();
243
  }
244
  }
@@ -249,7 +296,7 @@
249
  hints.style.width = (winW - 5) + "px";
250
  overlapX -= (box.right - box.left) - winW;
251
  }
252
- hints.style.left = (left = pos.left - overlapX) + "px";
253
  }
254
  if (scrolls) for (var node = hints.firstChild; node; node = node.nextSibling)
255
  node.style.paddingRight = cm.display.nativeBarWidth + "px"
@@ -273,7 +320,7 @@
273
  cm.on("scroll", this.onScroll = function() {
274
  var curScroll = cm.getScrollInfo(), editor = cm.getWrapperElement().getBoundingClientRect();
275
  var newTop = top + startScroll.top - curScroll.top;
276
- var point = newTop - (window.pageYOffset || (document.documentElement || document.body).scrollTop);
277
  if (!below) point += hints.offsetHeight;
278
  if (point <= editor.top || point >= editor.bottom) return completion.close();
279
  hints.style.top = newTop + "px";
@@ -297,6 +344,12 @@
297
  setTimeout(function(){cm.focus();}, 20);
298
  });
299
 
 
 
 
 
 
 
300
  CodeMirror.signal(data, "select", completions[this.selectedHint], hints.childNodes[this.selectedHint]);
301
  return true;
302
  }
@@ -337,15 +390,31 @@
337
  if (node) node.className = node.className.replace(" " + ACTIVE_HINT_ELEMENT_CLASS, "");
338
  node = this.hints.childNodes[this.selectedHint = i];
339
  node.className += " " + ACTIVE_HINT_ELEMENT_CLASS;
340
- if (node.offsetTop < this.hints.scrollTop)
341
- this.hints.scrollTop = node.offsetTop - 3;
342
- else if (node.offsetTop + node.offsetHeight > this.hints.scrollTop + this.hints.clientHeight)
343
- this.hints.scrollTop = node.offsetTop + node.offsetHeight - this.hints.clientHeight + 3;
344
  CodeMirror.signal(this.data, "select", this.data.list[this.selectedHint], node);
345
  },
346
 
 
 
 
 
 
 
 
 
 
 
 
347
  screenAmount: function() {
348
  return Math.floor(this.hints.clientHeight / this.hints.firstChild.offsetHeight) || 1;
 
 
 
 
 
 
 
 
349
  }
350
  };
351
 
@@ -423,11 +492,15 @@
423
  completeSingle: true,
424
  alignWithWord: true,
425
  closeCharacters: /[\s()\[\]{};:>,]/,
 
 
426
  closeOnUnfocus: true,
427
  completeOnSingleClick: true,
428
  container: null,
429
  customKeys: null,
430
- extraKeys: null
 
 
431
  };
432
 
433
  CodeMirror.defineOption("hintOptions", null);
1
  // CodeMirror, copyright (c) by Marijn Haverbeke and others
2
  // Distributed under an MIT license: https://codemirror.net/LICENSE
3
 
4
+ // declare global: DOMRect
5
+
6
  (function(mod) {
7
  if (typeof exports == "object" && typeof module == "object") // CommonJS
8
  mod(require("../../lib/codemirror"));
48
  completion.update(true);
49
  });
50
 
51
+ CodeMirror.defineExtension("closeHint", function() {
52
+ if (this.state.completionActive) this.state.completionActive.close()
53
+ })
54
+
55
  function Completion(cm, options) {
56
  this.cm = cm;
57
  this.options = options;
87
  },
88
 
89
  pick: function(data, i) {
90
+ var completion = data.list[i], self = this;
91
+ this.cm.operation(function() {
92
+ if (completion.hint)
93
+ completion.hint(self.cm, data, completion);
94
+ else
95
+ self.cm.replaceRange(getText(completion), completion.from || data.from,
96
+ completion.to || data.to, "complete");
97
+ CodeMirror.signal(data, "pick", completion);
98
+ self.cm.scrollIntoView();
99
+ });
100
+ if (this.options.closeOnPick) {
101
+ this.close();
102
+ }
103
  },
104
 
105
  cursorActivity: function() {
108
  this.debounce = 0;
109
  }
110
 
111
+ var identStart = this.startPos;
112
+ if(this.data) {
113
+ identStart = this.data.from;
114
+ }
115
+
116
  var pos = this.cm.getCursor(), line = this.cm.getLine(pos.line);
117
  if (pos.line != this.startPos.line || line.length - pos.ch != this.startLen - this.startPos.ch ||
118
+ pos.ch < identStart.ch || this.cm.somethingSelected() ||
119
  (!pos.ch || this.options.closeCharacters.test(line.charAt(pos.ch - 1)))) {
120
+ if (this.options.closeOnCursorActivity) {
121
+ this.close();
122
+ }
123
  } else {
124
  var self = this;
125
  this.debounce = requestAnimationFrame(function() {self.update();});
183
  Tab: handle.pick,
184
  Esc: handle.close
185
  };
186
+
187
+ var mac = /Mac/.test(navigator.platform);
188
+
189
+ if (mac) {
190
+ baseMap["Ctrl-P"] = function() {handle.moveFocus(-1);};
191
+ baseMap["Ctrl-N"] = function() {handle.moveFocus(1);};
192
+ }
193
+
194
  var custom = completion.options.customKeys;
195
  var ourMap = custom ? {} : baseMap;
196
  function addBinding(key, val) {
226
  this.data = data;
227
  this.picked = false;
228
  var widget = this, cm = completion.cm;
229
+ var ownerDocument = cm.getInputField().ownerDocument;
230
+ var parentWindow = ownerDocument.defaultView || ownerDocument.parentWindow;
231
 
232
+ var hints = this.hints = ownerDocument.createElement("ul");
233
  var theme = completion.cm.options.theme;
234
  hints.className = "CodeMirror-hints " + theme;
235
  this.selectedHint = data.selectedHint || 0;
236
 
237
  var completions = data.list;
238
  for (var i = 0; i < completions.length; ++i) {
239
+ var elt = hints.appendChild(ownerDocument.createElement("li")), cur = completions[i];
240
  var className = HINT_ELEMENT_CLASS + (i != this.selectedHint ? "" : " " + ACTIVE_HINT_ELEMENT_CLASS);
241
  if (cur.className != null) className = cur.className + " " + className;
242
  elt.className = className;
243
  if (cur.render) cur.render(elt, data, cur);
244
+ else elt.appendChild(ownerDocument.createTextNode(cur.displayText || getText(cur)));
245
  elt.hintId = i;
246
  }
247
 
248
+ var container = completion.options.container || ownerDocument.body;
249
  var pos = cm.cursorCoords(completion.options.alignWithWord ? data.from : null);
250
  var left = pos.left, top = pos.bottom, below = true;
251
+ var offsetLeft = 0, offsetTop = 0;
252
+ if (container !== ownerDocument.body) {
253
+ // We offset the cursor position because left and top are relative to the offsetParent's top left corner.
254
+ var isContainerPositioned = ['absolute', 'relative', 'fixed'].indexOf(parentWindow.getComputedStyle(container).position) !== -1;
255
+ var offsetParent = isContainerPositioned ? container : container.offsetParent;
256
+ var offsetParentPosition = offsetParent.getBoundingClientRect();
257
+ var bodyPosition = ownerDocument.body.getBoundingClientRect();
258
+ offsetLeft = (offsetParentPosition.left - bodyPosition.left - offsetParent.scrollLeft);
259
+ offsetTop = (offsetParentPosition.top - bodyPosition.top - offsetParent.scrollTop);
260
+ }
261
+ hints.style.left = (left - offsetLeft) + "px";
262
+ hints.style.top = (top - offsetTop) + "px";
263
+
264
  // If we're at the edge of the screen, then we want the menu to appear on the left of the cursor.
265
+ var winW = parentWindow.innerWidth || Math.max(ownerDocument.body.offsetWidth, ownerDocument.documentElement.offsetWidth);
266
+ var winH = parentWindow.innerHeight || Math.max(ownerDocument.body.offsetHeight, ownerDocument.documentElement.offsetHeight);
267
+ container.appendChild(hints);
 
 
 
268
 
269
+ var box = completion.options.moveOnOverlap ? hints.getBoundingClientRect() : new DOMRect();
270
+ var scrolls = completion.options.paddingForScrollbar ? hints.scrollHeight > hints.clientHeight + 1 : false;
271
+
272
+ // Compute in the timeout to avoid reflow on init
273
+ var startScroll;
274
+ setTimeout(function() { startScroll = cm.getScrollInfo(); });
275
+
276
+ var overlapY = box.bottom - winH;
277
  if (overlapY > 0) {
278
  var height = box.bottom - box.top, curTop = pos.top - (pos.bottom - box.top);
279
  if (curTop - height > 0) { // Fits above cursor
280
+ hints.style.top = (top = pos.top - height - offsetTop) + "px";
281
  below = false;
282
  } else if (height > winH) {
283
  hints.style.height = (winH - 5) + "px";
284
+ hints.style.top = (top = pos.bottom - box.top - offsetTop) + "px";
285
  var cursor = cm.getCursor();
286
  if (data.from.ch != cursor.ch) {
287
  pos = cm.cursorCoords(cursor);
288
+ hints.style.left = (left = pos.left - offsetLeft) + "px";
289
  box = hints.getBoundingClientRect();
290
  }
291
  }
296
  hints.style.width = (winW - 5) + "px";
297
  overlapX -= (box.right - box.left) - winW;
298
  }
299
+ hints.style.left = (left = pos.left - overlapX - offsetLeft) + "px";
300
  }
301
  if (scrolls) for (var node = hints.firstChild; node; node = node.nextSibling)
302
  node.style.paddingRight = cm.display.nativeBarWidth + "px"
320
  cm.on("scroll", this.onScroll = function() {
321
  var curScroll = cm.getScrollInfo(), editor = cm.getWrapperElement().getBoundingClientRect();
322
  var newTop = top + startScroll.top - curScroll.top;
323
+ var point = newTop - (parentWindow.pageYOffset || (ownerDocument.documentElement || ownerDocument.body).scrollTop);
324
  if (!below) point += hints.offsetHeight;
325
  if (point <= editor.top || point >= editor.bottom) return completion.close();
326
  hints.style.top = newTop + "px";
344
  setTimeout(function(){cm.focus();}, 20);
345
  });
346
 
347
+ // The first hint doesn't need to be scrolled to on init
348
+ var selectedHintRange = this.getSelectedHintRange();
349
+ if (selectedHintRange.from !== 0 || selectedHintRange.to !== 0) {
350
+ this.scrollToActive();
351
+ }
352
+
353
  CodeMirror.signal(data, "select", completions[this.selectedHint], hints.childNodes[this.selectedHint]);
354
  return true;
355
  }
390
  if (node) node.className = node.className.replace(" " + ACTIVE_HINT_ELEMENT_CLASS, "");
391
  node = this.hints.childNodes[this.selectedHint = i];
392
  node.className += " " + ACTIVE_HINT_ELEMENT_CLASS;
393
+ this.scrollToActive()
 
 
 
394
  CodeMirror.signal(this.data, "select", this.data.list[this.selectedHint], node);
395
  },
396
 
397
+ scrollToActive: function() {
398
+ var selectedHintRange = this.getSelectedHintRange();
399
+ var node1 = this.hints.childNodes[selectedHintRange.from];
400
+ var node2 = this.hints.childNodes[selectedHintRange.to];
401
+ var firstNode = this.hints.firstChild;
402
+ if (node1.offsetTop < this.hints.scrollTop)
403
+ this.hints.scrollTop = node1.offsetTop - firstNode.offsetTop;
404
+ else if (node2.offsetTop + node2.offsetHeight > this.hints.scrollTop + this.hints.clientHeight)
405
+ this.hints.scrollTop = node2.offsetTop + node2.offsetHeight - this.hints.clientHeight + firstNode.offsetTop;
406
+ },
407
+
408
  screenAmount: function() {
409
  return Math.floor(this.hints.clientHeight / this.hints.firstChild.offsetHeight) || 1;
410
+ },
411
+
412
+ getSelectedHintRange: function() {
413
+ var margin = this.completion.options.scrollMargin || 0;
414
+ return {
415
+ from: Math.max(0, this.selectedHint - margin),
416
+ to: Math.min(this.data.list.length - 1, this.selectedHint + margin),
417
+ };
418
  }
419
  };
420
 
492
  completeSingle: true,
493
  alignWithWord: true,
494
  closeCharacters: /[\s()\[\]{};:>,]/,
495
+ closeOnCursorActivity: true,
496
+ closeOnPick: true,
497
  closeOnUnfocus: true,
498
  completeOnSingleClick: true,
499
  container: null,
500
  customKeys: null,
501
+ extraKeys: null,
502
+ paddingForScrollbar: true,
503
+ moveOnOverlap: true,
504
  };
505
 
506
  CodeMirror.defineOption("hintOptions", null);
vendor/codemirror/addon/hint/sql-hint.js ADDED
@@ -0,0 +1,304 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ // CodeMirror, copyright (c) by Marijn Haverbeke and others
2
+ // Distributed under an MIT license: https://codemirror.net/LICENSE
3
+
4
+ (function(mod) {
5
+ if (typeof exports == "object" && typeof module == "object") // CommonJS
6
+ mod(require("../../lib/codemirror"), require("../../mode/sql/sql"));
7
+ else if (typeof define == "function" && define.amd) // AMD
8
+ define(["../../lib/codemirror", "../../mode/sql/sql"], mod);
9
+ else // Plain browser env
10
+ mod(CodeMirror);
11
+ })(function(CodeMirror) {
12
+ "use strict";
13
+
14
+ var tables;
15
+ var defaultTable;
16
+ var keywords;
17
+ var identifierQuote;
18
+ var CONS = {
19
+ QUERY_DIV: ";",
20
+ ALIAS_KEYWORD: "AS"
21
+ };
22
+ var Pos = CodeMirror.Pos, cmpPos = CodeMirror.cmpPos;
23
+
24
+ function isArray(val) { return Object.prototype.toString.call(val) == "[object Array]" }
25
+
26
+ function getKeywords(editor) {
27
+ var mode = editor.doc.modeOption;
28
+ if (mode === "sql") mode = "text/x-sql";
29
+ return CodeMirror.resolveMode(mode).keywords;
30
+ }
31
+
32
+ function getIdentifierQuote(editor) {
33
+ var mode = editor.doc.modeOption;
34
+ if (mode === "sql") mode = "text/x-sql";
35
+ return CodeMirror.resolveMode(mode).identifierQuote || "`";
36
+ }
37
+
38
+ function getText(item) {
39
+ return typeof item == "string" ? item : item.text;
40
+ }
41
+
42
+ function wrapTable(name, value) {
43
+ if (isArray(value)) value = {columns: value}
44
+ if (!value.text) value.text = name
45
+ return value
46
+ }
47
+
48
+ function parseTables(input) {
49
+ var result = {}
50
+ if (isArray(input)) {
51
+ for (var i = input.length - 1; i >= 0; i--) {
52
+ var item = input[i]
53
+ result[getText(item).toUpperCase()] = wrapTable(getText(item), item)
54
+ }
55
+ } else if (input) {
56
+ for (var name in input)
57
+ result[name.toUpperCase()] = wrapTable(name, input[name])
58
+ }
59
+ return result
60
+ }
61
+
62
+ function getTable(name) {
63
+ return tables[name.toUpperCase()]
64
+ }
65
+
66
+ function shallowClone(object) {
67
+ var result = {};
68
+ for (var key in object) if (object.hasOwnProperty(key))
69
+ result[key] = object[key];
70
+ return result;
71
+ }
72
+
73
+ function match(string, word) {
74
+ var len = string.length;
75
+ var sub = getText(word).substr(0, len);
76
+ return string.toUpperCase() === sub.toUpperCase();
77
+ }
78
+
79
+ function addMatches(result, search, wordlist, formatter) {
80
+ if (isArray(wordlist)) {
81
+ for (var i = 0; i < wordlist.length; i++)
82
+ if (match(search, wordlist[i])) result.push(formatter(wordlist[i]))
83
+ } else {
84
+ for (var word in wordlist) if (wordlist.hasOwnProperty(word)) {
85
+ var val = wordlist[word]
86
+ if (!val || val === true)
87
+ val = word
88
+ else
89
+ val = val.displayText ? {text: val.text, displayText: val.displayText} : val.text
90
+ if (match(search, val)) result.push(formatter(val))
91
+ }
92
+ }
93
+ }
94
+
95
+ function cleanName(name) {
96
+ // Get rid name from identifierQuote and preceding dot(.)
97
+ if (name.charAt(0) == ".") {
98
+ name = name.substr(1);
99
+ }
100
+ // replace doublicated identifierQuotes with single identifierQuotes
101
+ // and remove single identifierQuotes
102
+ var nameParts = name.split(identifierQuote+identifierQuote);
103
+ for (var i = 0; i < nameParts.length; i++)
104
+ nameParts[i] = nameParts[i].replace(new RegExp(identifierQuote,"g"), "");
105
+ return nameParts.join(identifierQuote);
106
+ }
107
+
108
+ function insertIdentifierQuotes(name) {
109
+ var nameParts = getText(name).split(".");
110
+ for (var i = 0; i < nameParts.length; i++)
111
+ nameParts[i] = identifierQuote +
112
+ // doublicate identifierQuotes
113
+ nameParts[i].replace(new RegExp(identifierQuote,"g"), identifierQuote+identifierQuote) +
114
+ identifierQuote;
115
+ var escaped = nameParts.join(".");
116
+ if (typeof name == "string") return escaped;
117
+ name = shallowClone(name);
118
+ name.text = escaped;
119
+ return name;
120
+ }
121
+
122
+ function nameCompletion(cur, token, result, editor) {
123
+ // Try to complete table, column names and return start position of completion
124
+ var useIdentifierQuotes = false;
125
+ var nameParts = [];
126
+ var start = token.start;
127
+ var cont = true;
128
+ while (cont) {
129
+ cont = (token.string.charAt(0) == ".");
130
+ useIdentifierQuotes = useIdentifierQuotes || (token.string.charAt(0) == identifierQuote);
131
+
132
+ start = token.start;
133
+ nameParts.unshift(cleanName(token.string));
134
+
135
+ token = editor.getTokenAt(Pos(cur.line, token.start));
136
+ if (token.string == ".") {
137
+ cont = true;
138
+ token = editor.getTokenAt(Pos(cur.line, token.start));
139
+ }
140
+ }
141
+
142
+ // Try to complete table names
143
+ var string = nameParts.join(".");
144
+ addMatches(result, string, tables, function(w) {
145
+ return useIdentifierQuotes ? insertIdentifierQuotes(w) : w;
146
+ });
147
+
148
+ // Try to complete columns from defaultTable
149
+ addMatches(result, string, defaultTable, function(w) {
150
+ return useIdentifierQuotes ? insertIdentifierQuotes(w) : w;
151
+ });
152
+
153
+ // Try to complete columns
154
+ string = nameParts.pop();
155
+ var table = nameParts.join(".");
156
+
157
+ var alias = false;
158
+ var aliasTable = table;
159
+ // Check if table is available. If not, find table by Alias
160
+ if (!getTable(table)) {
161
+ var oldTable = table;
162
+ table = findTableByAlias(table, editor);
163
+ if (table !== oldTable) alias = true;
164
+ }
165
+
166
+ var columns = getTable(table);
167
+ if (columns && columns.columns)
168
+ columns = columns.columns;
169
+
170
+ if (columns) {
171
+ addMatches(result, string, columns, function(w) {
172
+ var tableInsert = table;
173
+ if (alias == true) tableInsert = aliasTable;
174
+ if (typeof w == "string") {
175
+ w = tableInsert + "." + w;
176
+ } else {
177
+ w = shallowClone(w);
178
+ w.text = tableInsert + "." + w.text;
179
+ }
180
+ return useIdentifierQuotes ? insertIdentifierQuotes(w) : w;
181
+ });
182
+ }
183
+
184
+ return start;
185
+ }
186
+
187
+ function eachWord(lineText, f) {
188
+ var words = lineText.split(/\s+/)
189
+ for (var i = 0; i < words.length; i++)
190
+ if (words[i]) f(words[i].replace(/[`,;]/g, ''))
191
+ }
192
+
193
+ function findTableByAlias(alias, editor) {
194
+ var doc = editor.doc;
195
+ var fullQuery = doc.getValue();
196
+ var aliasUpperCase = alias.toUpperCase();
197
+ var previousWord = "";
198
+ var table = "";
199
+ var separator = [];
200
+ var validRange = {
201
+ start: Pos(0, 0),
202
+ end: Pos(editor.lastLine(), editor.getLineHandle(editor.lastLine()).length)
203
+ };
204
+
205
+ //add separator
206
+ var indexOfSeparator = fullQuery.indexOf(CONS.QUERY_DIV);
207
+ while(indexOfSeparator != -1) {
208
+ separator.push(doc.posFromIndex(indexOfSeparator));
209
+ indexOfSeparator = fullQuery.indexOf(CONS.QUERY_DIV, indexOfSeparator+1);
210
+ }
211
+ separator.unshift(Pos(0, 0));
212
+ separator.push(Pos(editor.lastLine(), editor.getLineHandle(editor.lastLine()).text.length));
213
+
214
+ //find valid range
215
+ var prevItem = null;
216
+ var current = editor.getCursor()
217
+ for (var i = 0; i < separator.length; i++) {
218
+ if ((prevItem == null || cmpPos(current, prevItem) > 0) && cmpPos(current, separator[i]) <= 0) {
219
+ validRange = {start: prevItem, end: separator[i]};
220
+ break;
221
+ }
222
+ prevItem = separator[i];
223
+ }
224
+
225
+ if (validRange.start) {
226
+ var query = doc.getRange(validRange.start, validRange.end, false);
227
+
228
+ for (var i = 0; i < query.length; i++) {
229
+ var lineText = query[i];
230
+ eachWord(lineText, function(word) {
231
+ var wordUpperCase = word.toUpperCase();
232
+ if (wordUpperCase === aliasUpperCase && getTable(previousWord))
233
+ table = previousWord;
234
+ if (wordUpperCase !== CONS.ALIAS_KEYWORD)
235
+ previousWord = word;
236
+ });
237
+ if (table) break;
238
+ }
239
+ }
240
+ return table;
241
+ }
242
+
243
+ CodeMirror.registerHelper("hint", "sql", function(editor, options) {
244
+ tables = parseTables(options && options.tables)
245
+ var defaultTableName = options && options.defaultTable;
246
+ var disableKeywords = options && options.disableKeywords;
247
+ defaultTable = defaultTableName && getTable(defaultTableName);
248
+ keywords = getKeywords(editor);
249
+ identifierQuote = getIdentifierQuote(editor);
250
+
251
+ if (defaultTableName && !defaultTable)
252
+ defaultTable = findTableByAlias(defaultTableName, editor);
253
+
254
+ defaultTable = defaultTable || [];
255
+
256
+ if (defaultTable.columns)
257
+ defaultTable = defaultTable.columns;
258
+
259
+ var cur = editor.getCursor();
260
+ var result = [];
261
+ var token = editor.getTokenAt(cur), start, end, search;
262
+ if (token.end > cur.ch) {
263
+ token.end = cur.ch;
264
+ token.string = token.string.slice(0, cur.ch - token.start);
265
+ }
266
+
267
+ if (token.string.match(/^[.`"'\w@][\w$#]*$/g)) {
268
+ search = token.string;
269
+ start = token.start;
270
+ end = token.end;
271
+ } else {
272
+ start = end = cur.ch;
273
+ search = "";
274
+ }
275
+ if (search.charAt(0) == "." || search.charAt(0) == identifierQuote) {
276
+ start = nameCompletion(cur, token, result, editor);
277
+ } else {
278
+ var objectOrClass = function(w, className) {
279
+ if (typeof w === "object") {
280
+ w.className = className;
281
+ } else {
282
+ w = { text: w, className: className };
283
+ }
284
+ return w;
285
+ };
286
+ addMatches(result, search, defaultTable, function(w) {
287
+ return objectOrClass(w, "CodeMirror-hint-table CodeMirror-hint-default-table");
288
+ });
289
+ addMatches(
290
+ result,
291
+ search,
292
+ tables, function(w) {
293
+ return objectOrClass(w, "CodeMirror-hint-table");
294
+ }
295
+ );
296
+ if (!disableKeywords)
297
+ addMatches(result, search, keywords, function(w) {
298
+ return objectOrClass(w.toUpperCase(), "CodeMirror-hint-keyword");
299
+ });
300
+ }
301
+
302
+ return {list: result, from: Pos(cur.line, start), to: Pos(cur.line, end)};
303
+ });
304
+ });
vendor/codemirror/addon/hint/xml-hint.js CHANGED
@@ -13,9 +13,15 @@
13
 
14
  var Pos = CodeMirror.Pos;
15
 
 
 
 
 
 
16
  function getHints(cm, options) {
17
  var tags = options && options.schemaInfo;
18
  var quote = (options && options.quoteChar) || '"';
 
19
  if (!tags) return;
20
  var cur = cm.getCursor(), token = cm.getTokenAt(cur);
21
  if (token.end > cur.ch) {
@@ -23,7 +29,7 @@
23
  token.string = token.string.slice(0, cur.ch - token.start);
24
  }
25
  var inner = CodeMirror.innerMode(cm.getMode(), token.state);
26
- if (inner.mode.name != "xml") return;
27
  var result = [], replaceToken = false, prefix;
28
  var tag = /\btag\b/.test(token.type) && !/>$/.test(token.string);
29
  var tagName = tag && /^\w/.test(token.string), tagStart;
@@ -38,25 +44,28 @@
38
  tagType = "close";
39
  }
40
 
41
- if (!tag && !inner.state.tagName || tagType) {
 
42
  if (tagName)
43
  prefix = token.string;
44
  replaceToken = tagType;
45
- var cx = inner.state.context, curTag = cx && tags[cx.tagName];
46
- var childList = cx ? curTag && curTag.children : tags["!top"];
 
 
47
  if (childList && tagType != "close") {
48
- for (var i = 0; i < childList.length; ++i) if (!prefix || childList[i].lastIndexOf(prefix, 0) == 0)
49
  result.push("<" + childList[i]);
50
  } else if (tagType != "close") {
51
  for (var name in tags)
52
- if (tags.hasOwnProperty(name) && name != "!top" && name != "!attrs" && (!prefix || name.lastIndexOf(prefix, 0) == 0))
53
  result.push("<" + name);
54
  }
55
- if (cx && (!prefix || tagType == "close" && cx.tagName.lastIndexOf(prefix, 0) == 0))
56
- result.push("</" + cx.tagName + ">");
57
  } else {
58
  // Attribute completion
59
- var curTag = tags[inner.state.tagName], attrs = curTag && curTag.attrs;
60
  var globalAttrs = tags["!attrs"];
61
  if (!attrs && !globalAttrs) return;
62
  if (!attrs) {
@@ -86,24 +95,37 @@
86
  quote = token.string.charAt(len - 1);
87
  prefix = token.string.substr(n, len - 2);
88
  }
 
 
 
 
89
  replaceToken = true;
90
  }
91
- for (var i = 0; i < atValues.length; ++i) if (!prefix || atValues[i].lastIndexOf(prefix, 0) == 0)
92
- result.push(quote + atValues[i] + quote);
 
 
 
 
 
 
93
  } else { // An attribute name
94
  if (token.type == "attribute") {
95
  prefix = token.string;
96
  replaceToken = true;
97
  }
98
- for (var attr in attrs) if (attrs.hasOwnProperty(attr) && (!prefix || attr.lastIndexOf(prefix, 0) == 0))
99
  result.push(attr);
100
  }
101
  }
102
- return {
103
- list: result,
104
- from: replaceToken ? Pos(cur.line, tagStart == null ? token.start : tagStart) : cur,
105
- to: replaceToken ? Pos(cur.line, token.end) : cur
106
- };
 
 
 
107
  }
108
 
109
  CodeMirror.registerHelper("hint", "xml", getHints);
13
 
14
  var Pos = CodeMirror.Pos;
15
 
16
+ function matches(hint, typed, matchInMiddle) {
17
+ if (matchInMiddle) return hint.indexOf(typed) >= 0;
18
+ else return hint.lastIndexOf(typed, 0) == 0;
19
+ }
20
+
21
  function getHints(cm, options) {
22
  var tags = options && options.schemaInfo;
23
  var quote = (options && options.quoteChar) || '"';
24
+ var matchInMiddle = options && options.matchInMiddle;
25
  if (!tags) return;
26
  var cur = cm.getCursor(), token = cm.getTokenAt(cur);
27
  if (token.end > cur.ch) {
29
  token.string = token.string.slice(0, cur.ch - token.start);
30
  }
31
  var inner = CodeMirror.innerMode(cm.getMode(), token.state);
32
+ if (!inner.mode.xmlCurrentTag) return
33
  var result = [], replaceToken = false, prefix;
34
  var tag = /\btag\b/.test(token.type) && !/>$/.test(token.string);
35
  var tagName = tag && /^\w/.test(token.string), tagStart;
44
  tagType = "close";
45
  }
46
 
47
+ var tagInfo = inner.mode.xmlCurrentTag(inner.state)
48
+ if (!tag && !tagInfo || tagType) {
49
  if (tagName)
50
  prefix = token.string;
51
  replaceToken = tagType;
52
+ var context = inner.mode.xmlCurrentContext ? inner.mode.xmlCurrentContext(inner.state) : []
53
+ var inner = context.length && context[context.length - 1]
54
+ var curTag = inner && tags[inner]
55
+ var childList = inner ? curTag && curTag.children : tags["!top"];
56
  if (childList && tagType != "close") {
57
+ for (var i = 0; i < childList.length; ++i) if (!prefix || matches(childList[i], prefix, matchInMiddle))
58
  result.push("<" + childList[i]);
59
  } else if (tagType != "close") {
60
  for (var name in tags)
61
+ if (tags.hasOwnProperty(name) && name != "!top" && name != "!attrs" && (!prefix || matches(name, prefix, matchInMiddle)))
62
  result.push("<" + name);
63
  }
64
+ if (inner && (!prefix || tagType == "close" && matches(inner, prefix, matchInMiddle)))
65
+ result.push("</" + inner + ">");
66
  } else {
67
  // Attribute completion
68
+ var curTag = tagInfo && tags[tagInfo.name], attrs = curTag && curTag.attrs;
69
  var globalAttrs = tags["!attrs"];
70
  if (!attrs && !globalAttrs) return;
71
  if (!attrs) {
95
  quote = token.string.charAt(len - 1);
96
  prefix = token.string.substr(n, len - 2);
97
  }
98
+ if (n) { // an opening quote
99
+ var line = cm.getLine(cur.line);
100
+ if (line.length > token.end && line.charAt(token.end) == quote) token.end++; // include a closing quote
101
+ }
102
  replaceToken = true;
103
  }
104
+ var returnHintsFromAtValues = function(atValues) {
105
+ if (atValues)
106
+ for (var i = 0; i < atValues.length; ++i) if (!prefix || matches(atValues[i], prefix, matchInMiddle))
107
+ result.push(quote + atValues[i] + quote);
108
+ return returnHints();
109
+ };
110
+ if (atValues && atValues.then) return atValues.then(returnHintsFromAtValues);
111
+ return returnHintsFromAtValues(atValues);
112
  } else { // An attribute name
113
  if (token.type == "attribute") {
114
  prefix = token.string;
115
  replaceToken = true;
116
  }
117
+ for (var attr in attrs) if (attrs.hasOwnProperty(attr) && (!prefix || matches(attr, prefix, matchInMiddle)))
118
  result.push(attr);
119
  }
120
  }
121
+ function returnHints() {
122
+ return {
123
+ list: result,
124
+ from: replaceToken ? Pos(cur.line, tagStart == null ? token.start : tagStart) : cur,
125
+ to: replaceToken ? Pos(cur.line, token.end) : cur
126
+ };
127
+ }
128
+ return returnHints();
129
  }
130
 
131
  CodeMirror.registerHelper("hint", "xml", getHints);
vendor/codemirror/codemirror.css CHANGED
@@ -13,12 +13,13 @@
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 */
@@ -96,7 +97,7 @@
96
 
97
  .CodeMirror-rulers {
98
  position: absolute;
99
- left: 0; right: 0; top: -50px; bottom: -20px;
100
  overflow: hidden;
101
  }
102
  .CodeMirror-ruler {
@@ -163,17 +164,17 @@ div.CodeMirror span.CodeMirror-nonmatchingbracket {color: #a22;}
163
 
164
  .CodeMirror-scroll {
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
@@ -183,6 +184,7 @@ div.CodeMirror span.CodeMirror-nonmatchingbracket {color: #a22;}
183
  position: absolute;
184
  z-index: 6;
185
  display: none;
 
186
  }
187
  .CodeMirror-vscrollbar {
188
  right: 0; top: 0;
@@ -211,7 +213,7 @@ div.CodeMirror span.CodeMirror-nonmatchingbracket {color: #a22;}
211
  height: 100%;
212
  display: inline-block;
213
  vertical-align: top;
214
- margin-bottom: -30px;
215
  }
216
  .CodeMirror-gutter-wrapper {
217
  position: absolute;
@@ -236,7 +238,8 @@ div.CodeMirror span.CodeMirror-nonmatchingbracket {color: #a22;}
236
  cursor: text;
237
  min-height: 1px; /* prevents collapsing before first draw */
238
  }
239
- .CodeMirror pre {
 
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;
@@ -255,7 +258,8 @@ div.CodeMirror span.CodeMirror-nonmatchingbracket {color: #a22;}
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;
13
  .CodeMirror-lines {
14
  padding: 4px 0; /* Vertical padding around content */
15
  }
16
+ .CodeMirror pre.CodeMirror-line,
17
+ .CodeMirror pre.CodeMirror-line-like {
18
  padding: 0 4px; /* Horizontal padding of content */
19
  }
20
 
21
  .CodeMirror-scrollbar-filler, .CodeMirror-gutter-filler {
22
+ background-color: transparent; /* The little square between H and V scrollbars */
23
  }
24
 
25
  /* GUTTER */
97
 
98
  .CodeMirror-rulers {
99
  position: absolute;
100
+ left: 0; right: 0; top: -50px; bottom: 0;
101
  overflow: hidden;
102
  }
103
  .CodeMirror-ruler {
164
 
165
  .CodeMirror-scroll {
166
  overflow: scroll !important; /* Things will break if this is overridden */
167
+ /* 50px is the magic margin used to hide the element's real scrollbars */
168
  /* See overflow: hidden in .CodeMirror */
169
+ margin-bottom: -50px; margin-right: -50px;
170
+ padding-bottom: 50px;
171
  height: 100%;
172
  outline: none; /* Prevent dragging from highlighting the element */
173
  position: relative;
174
  }
175
  .CodeMirror-sizer {
176
  position: relative;
177
+ border-right: 50px solid transparent;
178
  }
179
 
180
  /* The fake, visible scrollbars. Used to force redraw during scrolling
184
  position: absolute;
185
  z-index: 6;
186
  display: none;
187
+ outline: none;
188
  }
189
  .CodeMirror-vscrollbar {
190
  right: 0; top: 0;
213
  height: 100%;
214
  display: inline-block;
215
  vertical-align: top;
216
+ margin-bottom: -50px;
217
  }
218
  .CodeMirror-gutter-wrapper {
219
  position: absolute;
238
  cursor: text;
239
  min-height: 1px; /* prevents collapsing before first draw */
240
  }
241
+ .CodeMirror pre.CodeMirror-line,
242
+ .CodeMirror pre.CodeMirror-line-like {
243
  /* Reset some styles that the rest of the page might have set */
244
  -moz-border-radius: 0; -webkit-border-radius: 0; border-radius: 0;
245
  border-width: 0;
258
  -webkit-font-variant-ligatures: contextual;
259
  font-variant-ligatures: contextual;
260
  }
261
+ .CodeMirror-wrap pre.CodeMirror-line,
262
+ .CodeMirror-wrap pre.CodeMirror-line-like {
263
  word-wrap: break-word;
264
  white-space: pre-wrap;
265
  word-break: normal;
vendor/codemirror/codemirror.js CHANGED
@@ -10,7 +10,7 @@
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
@@ -32,7 +32,7 @@
32
  var mac_geMountainLion = /Mac OS X 1\d\D([8-9]|\d\d)\D/.test(userAgent);
33
  var phantom = /PhantomJS/.test(userAgent);
34
 
35
- var ios = !edge && /AppleWebKit/.test(userAgent) && /Mobile\/\w+/.test(userAgent);
36
  var android = /Android/.test(userAgent);
37
  // This is woefully incomplete. Suggestions for alternative methods welcome.
38
  var mobile = ios || android || /webOS|BlackBerry|Opera Mini|Opera Mobi|IEMobile/i.test(userAgent);
@@ -173,10 +173,28 @@
173
  }
174
  }
175
 
176
- var Delayed = function() {this.id = null;};
 
 
 
 
 
 
 
 
 
 
 
 
 
177
  Delayed.prototype.set = function (ms, f) {
178
- clearTimeout(this.id);
179
- this.id = setTimeout(f, ms);
 
 
 
 
 
180
  };
181
 
182
  function indexOf(array, elt) {
@@ -186,7 +204,7 @@
186
  }
187
 
188
  // Number of pixels added to scroller and sizer to hide scrollbar
189
- var scrollerGap = 30;
190
 
191
  // Returned or thrown by various protocols to signal 'I'm not
192
  // handling this'.
@@ -292,1474 +310,1368 @@
292
  }
293
  }
294
 
295
- // The display handles the DOM integration, both for input reading
296
- // and content drawing. It holds references to DOM nodes and
297
- // display-related state.
298
-
299
- function Display(place, doc, input) {
300
- var d = this;
301
- this.input = input;
302
-
303
- // Covers bottom-right square when both scrollbars are present.
304
- d.scrollbarFiller = elt("div", null, "CodeMirror-scrollbar-filler");
305
- d.scrollbarFiller.setAttribute("cm-not-content", "true");
306
- // Covers bottom of gutter when coverGutterNextToScrollbar is on
307
- // and h scrollbar is present.
308
- d.gutterFiller = elt("div", null, "CodeMirror-gutter-filler");
309
- d.gutterFiller.setAttribute("cm-not-content", "true");
310
- // Will contain the actual code, positioned to cover the viewport.
311
- d.lineDiv = eltP("div", null, "CodeMirror-code");
312
- // Elements are added to these to represent selection and cursors.
313
- d.selectionDiv = elt("div", null, null, "position: relative; z-index: 1");
314
- d.cursorDiv = elt("div", null, "CodeMirror-cursors");
315
- // A visibility: hidden element used to find the size of things.
316
- d.measure = elt("div", null, "CodeMirror-measure");
317
- // When lines outside of the viewport are measured, they are drawn in this.
318
- d.lineMeasure = elt("div", null, "CodeMirror-measure");
319
- // Wraps everything that needs to exist inside the vertically-padded coordinate system
320
- d.lineSpace = eltP("div", [d.measure, d.lineMeasure, d.selectionDiv, d.cursorDiv, d.lineDiv],
321
- null, "position: relative; outline: none");
322
- var lines = eltP("div", [d.lineSpace], "CodeMirror-lines");
323
- // Moved around its parent to cover visible view.
324
- d.mover = elt("div", [lines], null, "position: relative");
325
- // Set to the height of the document, allowing scrolling.
326
- d.sizer = elt("div", [d.mover], "CodeMirror-sizer");
327
- d.sizerWidth = null;
328
- // Behavior of elts with overflow: auto and padding is
329
- // inconsistent across browsers. This is used to ensure the
330
- // scrollable area is big enough.
331
- d.heightForcer = elt("div", null, null, "position: absolute; height: " + scrollerGap + "px; width: 1px;");
332
- // Will contain the gutters, if any.
333
- d.gutters = elt("div", null, "CodeMirror-gutters");
334
- d.lineGutter = null;
335
- // Actual scrollable element.
336
- d.scroller = elt("div", [d.sizer, d.heightForcer, d.gutters], "CodeMirror-scroll");
337
- d.scroller.setAttribute("tabIndex", "-1");
338
- // The element in which the editor lives.
339
- d.wrapper = elt("div", [d.scrollbarFiller, d.gutterFiller, d.scroller], "CodeMirror");
340
 
341
- // Work around IE7 z-index bug (not perfect, hence IE7 not really being supported)
342
- if (ie && ie_version < 8) { d.gutters.style.zIndex = -1; d.scroller.style.paddingRight = 0; }
343
- if (!webkit && !(gecko && mobile)) { d.scroller.draggable = true; }
 
 
 
 
 
 
 
 
 
344
 
345
- if (place) {
346
- if (place.appendChild) { place.appendChild(d.wrapper); }
347
- else { place(d.wrapper); }
 
 
 
 
 
 
 
 
 
 
 
 
348
  }
 
 
349
 
350
- // Current rendered range (may be bigger than the view window).
351
- d.viewFrom = d.viewTo = doc.first;
352
- d.reportedViewFrom = d.reportedViewTo = doc.first;
353
- // Information about the rendered lines.
354
- d.view = [];
355
- d.renderedView = null;
356
- // Holds info about a single rendered line when it was rendered
357
- // for measurement, while not in view.
358
- d.externalMeasured = null;
359
- // Empty space (in pixels) above the view
360
- d.viewOffset = 0;
361
- d.lastWrapHeight = d.lastWrapWidth = 0;
362
- d.updateLineNumbers = null;
363
 
364
- d.nativeBarWidth = d.barHeight = d.barWidth = 0;
365
- d.scrollbarsClipped = false;
 
 
 
 
 
 
 
 
 
 
 
 
 
366
 
367
- // Used to only resize the line number gutter when necessary (when
368
- // the amount of lines crosses a boundary that makes its width change)
369
- d.lineNumWidth = d.lineNumInnerWidth = d.lineNumChars = null;
370
- // Set to true when a non-horizontal-scrolling line widget is
371
- // added. As an optimization, line widget aligning is skipped when
372
- // this is false.
373
- d.alignWidgets = false;
 
 
 
 
 
 
 
 
 
 
374
 
375
- d.cachedCharWidth = d.cachedTextHeight = d.cachedPaddingH = null;
 
376
 
377
- // Tracks the maximum line length so that the horizontal scrollbar
378
- // can be kept static when scrolling.
379
- d.maxLine = null;
380
- d.maxLineLength = 0;
381
- d.maxLineChanged = false;
382
 
383
- // Used for measuring wheel scrolling granularity
384
- d.wheelDX = d.wheelDY = d.wheelStartX = d.wheelStartY = null;
385
 
386
- // True when shift is held down.
387
- d.shift = false;
 
 
388
 
389
- // Used to track whether anything happened since the context menu
390
- // was opened.
391
- d.selForContextMenu = null;
 
 
 
 
 
 
392
 
393
- d.activeTouch = null;
 
 
 
 
 
 
 
 
 
394
 
395
- input.init(d);
396
- }
 
 
 
 
 
 
 
 
397
 
398
- // Find the line object corresponding to the given line number.
399
- function getLine(doc, n) {
400
- n -= doc.first;
401
- if (n < 0 || n >= doc.size) { throw new Error("There is no line " + (n + doc.first) + " in the document.") }
402
- var chunk = doc;
403
- while (!chunk.lines) {
404
- for (var i = 0;; ++i) {
405
- var child = chunk.children[i], sz = child.chunkSize();
406
- if (n < sz) { chunk = child; break }
407
- n -= sz;
 
 
 
 
408
  }
409
- }
410
- return chunk.lines[n]
411
- }
412
 
413
- // Get the part of a document between two positions, as an array of
414
- // strings.
415
- function getBetween(doc, start, end) {
416
- var out = [], n = start.line;
417
- doc.iter(start.line, end.line + 1, function (line) {
418
- var text = line.text;
419
- if (n == end.line) { text = text.slice(0, end.ch); }
420
- if (n == start.line) { text = text.slice(start.ch); }
421
- out.push(text);
422
- ++n;
423
- });
424
- return out
425
- }
426
- // Get the lines between from and to, as array of strings.
427
- function getLines(doc, from, to) {
428
- var out = [];
429
- doc.iter(from, to, function (line) { out.push(line.text); }); // iter aborts when callback returns truthy value
430
- return out
431
- }
432
 
433
- // Update the height of a line, propagating the height change
434
- // upwards to parent nodes.
435
- function updateLineHeight(line, height) {
436
- var diff = height - line.height;
437
- if (diff) { for (var n = line; n; n = n.parent) { n.height += diff; } }
438
- }
439
-
440
- // Given a line object, find its line number by walking up through
441
- // its parent links.
442
- function lineNo(line) {
443
- if (line.parent == null) { return null }
444
- var cur = line.parent, no = indexOf(cur.lines, line);
445
- for (var chunk = cur.parent; chunk; cur = chunk, chunk = chunk.parent) {
446
- for (var i = 0;; ++i) {
447
- if (chunk.children[i] == cur) { break }
448
- no += chunk.children[i].chunkSize();
449
  }
450
- }
451
- return no + cur.first
452
- }
453
 
454
- // Find the line at the given vertical position, using the height
455
- // information in the document tree.
456
- function lineAtHeight(chunk, h) {
457
- var n = chunk.first;
458
- outer: do {
459
- for (var i$1 = 0; i$1 < chunk.children.length; ++i$1) {
460
- var child = chunk.children[i$1], ch = child.height;
461
- if (h < ch) { chunk = child; continue outer }
462
- h -= ch;
463
- n += child.chunkSize();
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
464
  }
465
- return n
466
- } while (!chunk.lines)
467
- var i = 0;
468
- for (; i < chunk.lines.length; ++i) {
469
- var line = chunk.lines[i], lh = line.height;
470
- if (h < lh) { break }
471
- h -= lh;
472
- }
473
- return n + i
474
- }
475
 
476
- function isLine(doc, l) {return l >= doc.first && l < doc.first + doc.size}
 
 
477
 
478
- function lineNumberFor(options, i) {
479
- return String(options.lineNumberFormatter(i + options.firstLineNumber))
 
 
 
 
 
480
  }
481
 
482
- // A Pos instance represents a position within the text.
483
- function Pos(line, ch, sticky) {
484
- if ( sticky === void 0 ) sticky = null;
485
-
486
- if (!(this instanceof Pos)) { return new Pos(line, ch, sticky) }
487
- this.line = line;
488
- this.ch = ch;
489
- this.sticky = sticky;
490
- }
491
 
492
- // Compare two positions, return 0 if they are the same, a negative
493
- // number when a is less, and a positive number otherwise.
494
- function cmp(a, b) { return a.line - b.line || a.ch - b.ch }
495
 
496
- function equalCursorPos(a, b) { return a.sticky == b.sticky && cmp(a, b) == 0 }
497
 
498
- function copyPos(x) {return Pos(x.line, x.ch)}
499
- function maxPos(a, b) { return cmp(a, b) < 0 ? b : a }
500
- function minPos(a, b) { return cmp(a, b) < 0 ? a : b }
 
 
 
 
 
 
 
501
 
502
- // Most of the external API clips given positions to make sure they
503
- // actually exist within the document.
504
- function clipLine(doc, n) {return Math.max(doc.first, Math.min(n, doc.first + doc.size - 1))}
505
- function clipPos(doc, pos) {
506
- if (pos.line < doc.first) { return Pos(doc.first, 0) }
507
- var last = doc.first + doc.size - 1;
508
- if (pos.line > last) { return Pos(last, getLine(doc, last).text.length) }
509
- return clipToLen(pos, getLine(doc, pos.line).text.length)
510
- }
511
- function clipToLen(pos, linelen) {
512
- var ch = pos.ch;
513
- if (ch == null || ch > linelen) { return Pos(pos.line, linelen) }
514
- else if (ch < 0) { return Pos(pos.line, 0) }
515
- else { return pos }
516
  }
517
- function clipPosArray(doc, array) {
518
- var out = [];
519
- for (var i = 0; i < array.length; i++) { out[i] = clipPos(doc, array[i]); }
520
- return out
 
 
 
 
 
 
 
 
 
 
521
  }
522
 
523
- // Optimize some code when these features are not used.
524
- var sawReadOnlySpans = false, sawCollapsedSpans = false;
 
 
 
 
525
 
526
- function seeReadOnlySpans() {
527
- sawReadOnlySpans = true;
 
 
 
 
 
 
528
  }
529
 
530
- function seeCollapsedSpans() {
531
- sawCollapsedSpans = true;
 
 
 
 
532
  }
533
 
534
- // TEXTMARKER SPANS
 
 
535
 
536
- function MarkedSpan(marker, from, to) {
537
- this.marker = marker;
538
- this.from = from; this.to = to;
 
 
539
  }
540
 
541
- // Search an array of spans for a span matching the given marker.
542
- function getMarkedSpanFor(spans, marker) {
543
- if (spans) { for (var i = 0; i < spans.length; ++i) {
544
- var span = spans[i];
545
- if (span.marker == marker) { return span }
546
- } }
547
  }
548
- // Remove a span from an array, returning undefined if no spans are
549
- // left (we don't store arrays for lines without spans).
550
- function removeMarkedSpan(spans, span) {
551
- var r;
552
- for (var i = 0; i < spans.length; ++i)
553
- { if (spans[i] != span) { (r || (r = [])).push(spans[i]); } }
554
- return r
555
  }
556
- // Add a span to a line.
557
- function addMarkedSpan(line, span) {
558
- line.markedSpans = line.markedSpans ? line.markedSpans.concat([span]) : [span];
559
- span.marker.attachLine(line);
560
  }
 
561
 
562
- // Used for the algorithm that adjusts markers for a change in the
563
- // document. These functions cut an array of spans at a given
564
- // character position, returning an array of remaining chunks (or
565
- // undefined if nothing remains).
566
- function markedSpansBefore(old, startCh, isInsert) {
567
- var nw;
568
- if (old) { for (var i = 0; i < old.length; ++i) {
569
- var span = old[i], marker = span.marker;
570
- var startsBefore = span.from == null || (marker.inclusiveLeft ? span.from <= startCh : span.from < startCh);
571
- if (startsBefore || span.from == startCh && marker.type == "bookmark" && (!isInsert || !span.marker.insertLeft)) {
572
- var endsAfter = span.to == null || (marker.inclusiveRight ? span.to >= startCh : span.to > startCh)
573
- ;(nw || (nw = [])).push(new MarkedSpan(marker, span.from, endsAfter ? null : span.to));
574
- }
575
- } }
576
- return nw
577
  }
578
- function markedSpansAfter(old, endCh, isInsert) {
579
- var nw;
580
- if (old) { for (var i = 0; i < old.length; ++i) {
581
- var span = old[i], marker = span.marker;
582
- var endsAfter = span.to == null || (marker.inclusiveRight ? span.to >= endCh : span.to > endCh);
583
- if (endsAfter || span.from == endCh && marker.type == "bookmark" && (!isInsert || span.marker.insertLeft)) {
584
- var startsBefore = span.from == null || (marker.inclusiveLeft ? span.from <= endCh : span.from < endCh)
585
- ;(nw || (nw = [])).push(new MarkedSpan(marker, startsBefore ? null : span.from - endCh,
586
- span.to == null ? null : span.to - endCh));
587
- }
588
- } }
589
- return nw
590
- }
591
-
592
- // Given a change object, compute the new set of marker spans that
593
- // cover the line in which the change took place. Removes spans
594
- // entirely within the change, reconnects spans belonging to the
595
- // same marker that appear on both sides of the change, and cuts off
596
- // spans partially within the change. Returns an array of span
597
- // arrays with one element for each line in (after) the change.
598
- function stretchSpansOverChange(doc, change) {
599
- if (change.full) { return null }
600
- var oldFirst = isLine(doc, change.from.line) && getLine(doc, change.from.line).markedSpans;
601
- var oldLast = isLine(doc, change.to.line) && getLine(doc, change.to.line).markedSpans;
602
- if (!oldFirst && !oldLast) { return null }
603
-
604
- var startCh = change.from.ch, endCh = change.to.ch, isInsert = cmp(change.from, change.to) == 0;
605
- // Get the spans that 'stick out' on both sides
606
- var first = markedSpansBefore(oldFirst, startCh, isInsert);
607
- var last = markedSpansAfter(oldLast, endCh, isInsert);
608
 
609
- // Next, merge those two ends
610
- var sameLine = change.text.length == 1, offset = lst(change.text).length + (sameLine ? startCh : 0);
611
- if (first) {
612
- // Fix up .to properties of first
613
- for (var i = 0; i < first.length; ++i) {
614
- var span = first[i];
615
- if (span.to == null) {
616
- var found = getMarkedSpanFor(last, span.marker);
617
- if (!found) { span.to = startCh; }
618
- else if (sameLine) { span.to = found.to == null ? null : found.to + offset; }
619
- }
620
- }
621
- }
622
- if (last) {
623
- // Fix up .from in last (or move them into first in case of sameLine)
624
- for (var i$1 = 0; i$1 < last.length; ++i$1) {
625
- var span$1 = last[i$1];
626
- if (span$1.to != null) { span$1.to += offset; }
627
- if (span$1.from == null) {
628
- var found$1 = getMarkedSpanFor(first, span$1.marker);
629
- if (!found$1) {
630
- span$1.from = offset;
631
- if (sameLine) { (first || (first = [])).push(span$1); }
632
- }
633
- } else {
634
- span$1.from += offset;
635
- if (sameLine) { (first || (first = [])).push(span$1); }
636
- }
637
- }
638
- }
639
- // Make sure we didn't create any zero-length spans
640
- if (first) { first = clearEmptySpans(first); }
641
- if (last && last != first) { last = clearEmptySpans(last); }
642
 
643
- var newMarkers = [first];
644
- if (!sameLine) {
645
- // Fill gap with whole-line-spans
646
- var gap = change.text.length - 2, gapMarkers;
647
- if (gap > 0 && first)
648
- { for (var i$2 = 0; i$2 < first.length; ++i$2)
649
- { if (first[i$2].to == null)
650
- { (gapMarkers || (gapMarkers = [])).push(new MarkedSpan(first[i$2].marker, null, null)); } } }
651
- for (var i$3 = 0; i$3 < gap; ++i$3)
652
- { newMarkers.push(gapMarkers); }
653
- newMarkers.push(last);
654
  }
655
- return newMarkers
 
 
 
656
  }
657
 
658
- // Remove spans that are empty and don't have a clearWhenEmpty
659
- // option of false.
660
- function clearEmptySpans(spans) {
661
- for (var i = 0; i < spans.length; ++i) {
662
- var span = spans[i];
663
- if (span.from != null && span.from == span.to && span.marker.clearWhenEmpty !== false)
664
- { spans.splice(i--, 1); }
665
- }
666
- if (!spans.length) { return null }
667
- return spans
668
  }
669
 
670
- // Used to 'clip' out readOnly ranges when making a change.
671
- function removeReadOnlyRanges(doc, from, to) {
672
- var markers = null;
673
- doc.iter(from.line, to.line + 1, function (line) {
674
- if (line.markedSpans) { for (var i = 0; i < line.markedSpans.length; ++i) {
675
- var mark = line.markedSpans[i].marker;
676
- if (mark.readOnly && (!markers || indexOf(markers, mark) == -1))
677
- { (markers || (markers = [])).push(mark); }
678
- } }
679
- });
680
- if (!markers) { return null }
681
- var parts = [{from: from, to: to}];
682
- for (var i = 0; i < markers.length; ++i) {
683
- var mk = markers[i], m = mk.find(0);
684
- for (var j = 0; j < parts.length; ++j) {
685
- var p = parts[j];
686
- if (cmp(p.to, m.from) < 0 || cmp(p.from, m.to) > 0) { continue }
687
- var newParts = [j, 1], dfrom = cmp(p.from, m.from), dto = cmp(p.to, m.to);
688
- if (dfrom < 0 || !mk.inclusiveLeft && !dfrom)
689
- { newParts.push({from: p.from, to: m.from}); }
690
- if (dto > 0 || !mk.inclusiveRight && !dto)
691
- { newParts.push({from: m.to, to: p.to}); }
692
- parts.splice.apply(parts, newParts);
693
- j += newParts.length - 3;
694
  }
695
  }
696
- return parts
697
- }
698
 
699
- // Connect or disconnect spans from a line.
700
- function detachMarkedSpans(line) {
701
- var spans = line.markedSpans;
702
- if (!spans) { return }
703
- for (var i = 0; i < spans.length; ++i)
704
- { spans[i].marker.detachLine(line); }
705
- line.markedSpans = null;
706
- }
707
- function attachMarkedSpans(line, spans) {
708
- if (!spans) { return }
709
- for (var i = 0; i < spans.length; ++i)
710
- { spans[i].marker.attachLine(line); }
711
- line.markedSpans = spans;
712
- }
713
 
714
- // Helpers used when computing which overlapping collapsed span
715
- // counts as the larger one.
716
- function extraLeft(marker) { return marker.inclusiveLeft ? -1 : 0 }
717
- function extraRight(marker) { return marker.inclusiveRight ? 1 : 0 }
 
 
718
 
719
- // Returns a number indicating which of two overlapping collapsed
720
- // spans is larger (and thus includes the other). Falls back to
721
- // comparing ids when the spans cover exactly the same range.
722
- function compareCollapsedMarkers(a, b) {
723
- var lenDiff = a.lines.length - b.lines.length;
724
- if (lenDiff != 0) { return lenDiff }
725
- var aPos = a.find(), bPos = b.find();
726
- var fromCmp = cmp(aPos.from, bPos.from) || extraLeft(a) - extraLeft(b);
727
- if (fromCmp) { return -fromCmp }
728
- var toCmp = cmp(aPos.to, bPos.to) || extraRight(a) - extraRight(b);
729
- if (toCmp) { return toCmp }
730
- return b.id - a.id
731
  }
732
 
733
- // Find out whether a line ends or starts in a collapsed span. If
734
- // so, return the marker for that span.
735
- function collapsedSpanAtSide(line, start) {
736
- var sps = sawCollapsedSpans && line.markedSpans, found;
737
- if (sps) { for (var sp = (void 0), i = 0; i < sps.length; ++i) {
738
- sp = sps[i];
739
- if (sp.marker.collapsed && (start ? sp.from : sp.to) == null &&
740
- (!found || compareCollapsedMarkers(found, sp.marker) < 0))
741
- { found = sp.marker; }
742
- } }
743
- return found
744
- }
745
- function collapsedSpanAtStart(line) { return collapsedSpanAtSide(line, true) }
746
- function collapsedSpanAtEnd(line) { return collapsedSpanAtSide(line, false) }
747
 
748
- function collapsedSpanAround(line, ch) {
749
- var sps = sawCollapsedSpans && line.markedSpans, found;
750
- if (sps) { for (var i = 0; i < sps.length; ++i) {
751
- var sp = sps[i];
752
- if (sp.marker.collapsed && (sp.from == null || sp.from < ch) && (sp.to == null || sp.to > ch) &&
753
- (!found || compareCollapsedMarkers(found, sp.marker) < 0)) { found = sp.marker; }
754
- } }
755
- return found
756
  }
757
 
758
- // Test whether there exists a collapsed span that partially
759
- // overlaps (covers the start or end, but not both) of a new span.
760
- // Such overlap is not allowed.
761
- function conflictingCollapsedRange(doc, lineNo$$1, from, to, marker) {
762
- var line = getLine(doc, lineNo$$1);
763
- var sps = sawCollapsedSpans && line.markedSpans;
764
- if (sps) { for (var i = 0; i < sps.length; ++i) {
765
- var sp = sps[i];
766
- if (!sp.marker.collapsed) { continue }
767
- var found = sp.marker.find(0);
768
- var fromCmp = cmp(found.from, from) || extraLeft(sp.marker) - extraLeft(marker);
769
- var toCmp = cmp(found.to, to) || extraRight(sp.marker) - extraRight(marker);
770
- if (fromCmp >= 0 && toCmp <= 0 || fromCmp <= 0 && toCmp >= 0) { continue }
771
- if (fromCmp <= 0 && (sp.marker.inclusiveRight && marker.inclusiveLeft ? cmp(found.to, from) >= 0 : cmp(found.to, from) > 0) ||
772
- fromCmp >= 0 && (sp.marker.inclusiveRight && marker.inclusiveLeft ? cmp(found.from, to) <= 0 : cmp(found.from, to) < 0))
773
- { return true }
774
- } }
775
  }
776
 
777
- // A visual line is a line as drawn on the screen. Folding, for
778
- // example, can cause multiple logical lines to appear on the same
779
- // visual line. This finds the start of the visual line that the
780
- // given line is part of (usually that is the line itself).
781
- function visualLine(line) {
782
- var merged;
783
- while (merged = collapsedSpanAtStart(line))
784
- { line = merged.find(-1, true).line; }
785
- return line
786
- }
787
-
788
- function visualLineEnd(line) {
789
- var merged;
790
- while (merged = collapsedSpanAtEnd(line))
791
- { line = merged.find(1, true).line; }
792
- return line
793
- }
794
-
795
- // Returns an array of logical lines that continue the visual line
796
- // started by the argument, or undefined if there are no such lines.
797
- function visualLineContinued(line) {
798
- var merged, lines;
799
- while (merged = collapsedSpanAtEnd(line)) {
800
- line = merged.find(1, true).line
801
- ;(lines || (lines = [])).push(line);
802
- }
803
- return lines
804
- }
805
-
806
- // Get the line number of the start of the visual line that the
807
- // given line number is part of.
808
- function visualLineNo(doc, lineN) {
809
- var line = getLine(doc, lineN), vis = visualLine(line);
810
- if (line == vis) { return lineN }
811
- return lineNo(vis)
812
- }
813
-
814
- // Get the line number of the start of the next visual line after
815
- // the given line.
816
- function visualLineEndNo(doc, lineN) {
817
- if (lineN > doc.lastLine()) { return lineN }
818
- var line = getLine(doc, lineN), merged;
819
- if (!lineIsHidden(doc, line)) { return lineN }
820
- while (merged = collapsedSpanAtEnd(line))
821
- { line = merged.find(1, true).line; }
822
- return lineNo(line) + 1
823
- }
824
-
825
- // Compute whether a line is hidden. Lines count as hidden when they
826
- // are part of a visual line that starts with another line, or when
827
- // they are entirely covered by collapsed, non-widget span.
828
- function lineIsHidden(doc, line) {
829
- var sps = sawCollapsedSpans && line.markedSpans;
830
- if (sps) { for (var sp = (void 0), i = 0; i < sps.length; ++i) {
831
- sp = sps[i];
832
- if (!sp.marker.collapsed) { continue }
833
- if (sp.from == null) { return true }
834
- if (sp.marker.widgetNode) { continue }
835
- if (sp.from == 0 && sp.marker.inclusiveLeft && lineIsHiddenInner(doc, line, sp))
836
- { return true }
837
- } }
838
- }
839
- function lineIsHiddenInner(doc, line, span) {
840
- if (span.to == null) {
841
- var end = span.marker.find(1, true);
842
- return lineIsHiddenInner(doc, end.line, getMarkedSpanFor(end.line.markedSpans, span.marker))
843
- }
844
- if (span.marker.inclusiveRight && span.to == line.text.length)
845
- { return true }
846
- for (var sp = (void 0), i = 0; i < line.markedSpans.length; ++i) {
847
- sp = line.markedSpans[i];
848
- if (sp.marker.collapsed && !sp.marker.widgetNode && sp.from == span.to &&
849
- (sp.to == null || sp.to != span.from) &&
850
- (sp.marker.inclusiveLeft || span.marker.inclusiveRight) &&
851
- lineIsHiddenInner(doc, line, sp)) { return true }
852
  }
 
 
853
  }
854
 
855
- // Find the height above the given line.
856
- function heightAtLine(lineObj) {
857
- lineObj = visualLine(lineObj);
858
-
859
- var h = 0, chunk = lineObj.parent;
860
- for (var i = 0; i < chunk.lines.length; ++i) {
861
- var line = chunk.lines[i];
862
- if (line == lineObj) { break }
863
- else { h += line.height; }
864
- }
865
- for (var p = chunk.parent; p; chunk = p, p = chunk.parent) {
866
- for (var i$1 = 0; i$1 < p.children.length; ++i$1) {
867
- var cur = p.children[i$1];
868
- if (cur == chunk) { break }
869
- else { h += cur.height; }
870
  }
871
  }
872
- return h
873
- }
 
 
874
 
875
- // Compute the character length of a line, taking into account
876
- // collapsed ranges (see markText) that might hide parts, and join
877
- // other lines onto it.
878
- function lineLength(line) {
879
- if (line.height == 0) { return 0 }
880
- var len = line.text.length, merged, cur = line;
881
- while (merged = collapsedSpanAtStart(cur)) {
882
- var found = merged.find(0, true);
883
- cur = found.from.line;
884
- len += found.from.ch - found.to.ch;
885
- }
886
- cur = line;
887
- while (merged = collapsedSpanAtEnd(cur)) {
888
- var found$1 = merged.find(0, true);
889
- len -= cur.text.length - found$1.from.ch;
890
- cur = found$1.to.line;
891
- len += cur.text.length - found$1.to.ch;
892
- }
893
- return len
894
  }
895
 
896
- // Find the longest line in the document.
897
- function findMaxLine(cm) {
898
- var d = cm.display, doc = cm.doc;
899
- d.maxLine = getLine(doc, doc.first);
900
- d.maxLineLength = lineLength(d.maxLine);
901
- d.maxLineChanged = true;
902
- doc.iter(function (line) {
903
- var len = lineLength(line);
904
- if (len > d.maxLineLength) {
905
- d.maxLineLength = len;
906
- d.maxLine = line;
907
- }
908
- });
909
  }
910
 
911
- // BIDI HELPERS
912
-
913
- function iterateBidiSections(order, from, to, f) {
914
- if (!order) { return f(from, to, "ltr", 0) }
915
- var found = false;
916
- for (var i = 0; i < order.length; ++i) {
917
- var part = order[i];
918
- if (part.from < to && part.to > from || from == to && part.to == from) {
919
- f(Math.max(part.from, from), Math.min(part.to, to), part.level == 1 ? "rtl" : "ltr", i);
920
- found = true;
921
- }
922
  }
923
- if (!found) { f(from, to, "ltr"); }
924
  }
925
 
926
- var bidiOther = null;
927
- function getBidiPartAt(order, ch, sticky) {
928
- var found;
929
- bidiOther = null;
930
- for (var i = 0; i < order.length; ++i) {
931
- var cur = order[i];
932
- if (cur.from < ch && cur.to > ch) { return i }
933
- if (cur.to == ch) {
934
- if (cur.from != cur.to && sticky == "before") { found = i; }
935
- else { bidiOther = i; }
936
- }
937
- if (cur.from == ch) {
938
- if (cur.from != cur.to && sticky != "before") { found = i; }
939
- else { bidiOther = i; }
940
- }
941
  }
942
- return found != null ? found : bidiOther
943
  }
944
 
945
- // Bidirectional ordering algorithm
946
- // See http://unicode.org/reports/tr9/tr9-13.html for the algorithm
947
- // that this (partially) implements.
948
 
949
- // One-char codes used for character types:
950
- // L (L): Left-to-Right
951
- // R (R): Right-to-Left
952
- // r (AL): Right-to-Left Arabic
953
- // 1 (EN): European Number
954
- // + (ES): European Number Separator
955
- // % (ET): European Number Terminator
956
- // n (AN): Arabic Number
957
- // , (CS): Common Number Separator
958
- // m (NSM): Non-Spacing Mark
959
- // b (BN): Boundary Neutral
960
- // s (B): Paragraph Separator
961
- // t (S): Segment Separator
962
- // w (WS): Whitespace
963
- // N (ON): Other Neutrals
964
 
965
- // Returns null if characters are ordered as they appear
966
- // (left-to-right), or an array of sections ({from, to, level}
967
- // objects) in the order in which they occur visually.
968
- var bidiOrdering = (function() {
969
- // Character types for codepoints 0 to 0xff
970
- var lowTypes = "bbbbbbbbbtstwsbbbbbbbbbbbbbbssstwNN%%%NNNNNN,N,N1111111111NNNNNNNLLLLLLLLLLLLLLLLLLLLLLLLLLNNNNNNLLLLLLLLLLLLLLLLLLLLLLLLLLNNNNbbbbbbsbbbbbbbbbbbbbbbbbbbbbbbbbb,N%%%%NNNNLNNNNN%%11NLNNN1LNNNNNLLLLLLLLLLLLLLLLLLLLLLLNLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLN";
971
- // Character types for codepoints 0x600 to 0x6f9
972
- var arabicTypes = "nnnnnnNNr%%r,rNNmmmmmmmmmmmrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrmmmmmmmmmmmmmmmmmmmmmnnnnnnnnnn%nnrrrmrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrmmmmmmmnNmmmmmmrrmmNmmmmrr1111111111";
973
- function charType(code) {
974
- if (code <= 0xf7) { return lowTypes.charAt(code) }
975
- else if (0x590 <= code && code <= 0x5f4) { return "R" }
976
- else if (0x600 <= code && code <= 0x6f9) { return arabicTypes.charAt(code - 0x600) }
977
- else if (0x6ee <= code && code <= 0x8ac) { return "r" }
978
- else if (0x2000 <= code && code <= 0x200b) { return "w" }
979
- else if (code == 0x200c) { return "b" }
980
- else { return "L" }
981
- }
982
 
983
- var bidiRE = /[\u0590-\u05f4\u0600-\u06ff\u0700-\u08ac]/;
984
- var isNeutral = /[stwN]/, isStrong = /[LRr]/, countsAsLeft = /[Lb1n]/, countsAsNum = /[1n]/;
 
 
 
 
 
 
985
 
986
- function BidiSpan(level, from, to) {
987
- this.level = level;
988
- this.from = from; this.to = to;
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
989
  }
990
-
991
- return function(str, direction) {
992
- var outerType = direction == "ltr" ? "L" : "R";
993
-
994
- if (str.length == 0 || direction == "ltr" && !bidiRE.test(str)) { return false }
995
- var len = str.length, types = [];
996
- for (var i = 0; i < len; ++i)
997
- { types.push(charType(str.charCodeAt(i))); }
998
-
999
- // W1. Examine each non-spacing mark (NSM) in the level run, and
1000
- // change the type of the NSM to the type of the previous
1001
- // character. If the NSM is at the start of the level run, it will
1002
- // get the type of sor.
1003
- for (var i$1 = 0, prev = outerType; i$1 < len; ++i$1) {
1004
- var type = types[i$1];
1005
- if (type == "m") { types[i$1] = prev; }
1006
- else { prev = type; }
1007
- }
1008
-
1009
- // W2. Search backwards from each instance of a European number
1010
- // until the first strong type (R, L, AL, or sor) is found. If an
1011
- // AL is found, change the type of the European number to Arabic
1012
- // number.
1013
- // W3. Change all ALs to R.
1014
- for (var i$2 = 0, cur = outerType; i$2 < len; ++i$2) {
1015
- var type$1 = types[i$2];
1016
- if (type$1 == "1" && cur == "r") { types[i$2] = "n"; }
1017
- else if (isStrong.test(type$1)) { cur = type$1; if (type$1 == "r") { types[i$2] = "R"; } }
1018
- }
1019
-
1020
- // W4. A single European separator between two European numbers
1021
- // changes to a European number. A single common separator between
1022
- // two numbers of the same type changes to that type.
1023
- for (var i$3 = 1, prev$1 = types[0]; i$3 < len - 1; ++i$3) {
1024
- var type$2 = types[i$3];
1025
- if (type$2 == "+" && prev$1 == "1" && types[i$3+1] == "1") { types[i$3] = "1"; }
1026
- else if (type$2 == "," && prev$1 == types[i$3+1] &&
1027
- (prev$1 == "1" || prev$1 == "n")) { types[i$3] = prev$1; }
1028
- prev$1 = type$2;
1029
- }
1030
-
1031
- // W5. A sequence of European terminators adjacent to European
1032
- // numbers changes to all European numbers.
1033
- // W6. Otherwise, separators and terminators change to Other
1034
- // Neutral.
1035
- for (var i$4 = 0; i$4 < len; ++i$4) {
1036
- var type$3 = types[i$4];
1037
- if (type$3 == ",") { types[i$4] = "N"; }
1038
- else if (type$3 == "%") {
1039
- var end = (void 0);
1040
- for (end = i$4 + 1; end < len && types[end] == "%"; ++end) {}
1041
- var replace = (i$4 && types[i$4-1] == "!") || (end < len && types[end] == "1") ? "1" : "N";
1042
- for (var j = i$4; j < end; ++j) { types[j] = replace; }
1043
- i$4 = end - 1;
1044
- }
1045
- }
1046
-
1047
- // W7. Search backwards from each instance of a European number
1048
- // until the first strong type (R, L, or sor) is found. If an L is
1049
- // found, then change the type of the European number to L.
1050
- for (var i$5 = 0, cur$1 = outerType; i$5 < len; ++i$5) {
1051
- var type$4 = types[i$5];
1052
- if (cur$1 == "L" && type$4 == "1") { types[i$5] = "L"; }
1053
- else if (isStrong.test(type$4)) { cur$1 = type$4; }
1054
- }
1055
-
1056
- // N1. A sequence of neutrals takes the direction of the
1057
- // surrounding strong text if the text on both sides has the same
1058
- // direction. European and Arabic numbers act as if they were R in
1059
- // terms of their influence on neutrals. Start-of-level-run (sor)
1060
- // and end-of-level-run (eor) are used at level run boundaries.
1061
- // N2. Any remaining neutrals take the embedding direction.
1062
- for (var i$6 = 0; i$6 < len; ++i$6) {
1063
- if (isNeutral.test(types[i$6])) {
1064
- var end$1 = (void 0);
1065
- for (end$1 = i$6 + 1; end$1 < len && isNeutral.test(types[end$1]); ++end$1) {}
1066
- var before = (i$6 ? types[i$6-1] : outerType) == "L";
1067
- var after = (end$1 < len ? types[end$1] : outerType) == "L";
1068
- var replace$1 = before == after ? (before ? "L" : "R") : outerType;
1069
- for (var j$1 = i$6; j$1 < end$1; ++j$1) { types[j$1] = replace$1; }
1070
- i$6 = end$1 - 1;
1071
- }
1072
  }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1073
 
1074
- // Here we depart from the documented algorithm, in order to avoid
1075
- // building up an actual levels array. Since there are only three
1076
- // levels (0, 1, 2) in an implementation that doesn't take
1077
- // explicit embedding into account, we can build up the order on
1078
- // the fly, without following the level-based algorithm.
1079
- var order = [], m;
1080
- for (var i$7 = 0; i$7 < len;) {
1081
- if (countsAsLeft.test(types[i$7])) {
1082
- var start = i$7;
1083
- for (++i$7; i$7 < len && countsAsLeft.test(types[i$7]); ++i$7) {}
1084
- order.push(new BidiSpan(0, start, i$7));
1085
- } else {
1086
- var pos = i$7, at = order.length;
1087
- for (++i$7; i$7 < len && types[i$7] != "L"; ++i$7) {}
1088
- for (var j$2 = pos; j$2 < i$7;) {
1089
- if (countsAsNum.test(types[j$2])) {
1090
- if (pos < j$2) { order.splice(at, 0, new BidiSpan(1, pos, j$2)); }
1091
- var nstart = j$2;
1092
- for (++j$2; j$2 < i$7 && countsAsNum.test(types[j$2]); ++j$2) {}
1093
- order.splice(at, 0, new BidiSpan(2, nstart, j$2));
1094
- pos = j$2;
1095
- } else { ++j$2; }
1096
- }
1097
- if (pos < i$7) { order.splice(at, 0, new BidiSpan(1, pos, i$7)); }
1098
- }
1099
- }
1100
- if (direction == "ltr") {
1101
- if (order[0].level == 1 && (m = str.match(/^\s+/))) {
1102
- order[0].from = m[0].length;
1103
- order.unshift(new BidiSpan(0, 0, m[0].length));
1104
- }
1105
- if (lst(order).level == 1 && (m = str.match(/\s+$/))) {
1106
- lst(order).to -= m[0].length;
1107
- order.push(new BidiSpan(0, len - m[0].length, len));
1108
- }
1109
  }
1110
-
1111
- return direction == "rtl" ? order.reverse() : order
1112
  }
1113
- })();
1114
-
1115
- // Get the bidi ordering for the given line (and cache it). Returns
1116
- // false for lines that are fully left-to-right, and an array of
1117
- // BidiSpan objects otherwise.
1118
- function getOrder(line, direction) {
1119
- var order = line.order;
1120
- if (order == null) { order = line.order = bidiOrdering(line.text, direction); }
1121
- return order
1122
  }
1123
 
1124
- // EVENT HANDLING
1125
-
1126
- // Lightweight event framework. on/off also work on DOM nodes,
1127
- // registering native DOM handlers.
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1128
 
1129
- var noHandlers = [];
 
 
 
 
 
1130
 
1131
- var on = function(emitter, type, f) {
1132
- if (emitter.addEventListener) {
1133
- emitter.addEventListener(type, f, false);
1134
- } else if (emitter.attachEvent) {
1135
- emitter.attachEvent("on" + type, f);
1136
- } else {
1137
- var map$$1 = emitter._handlers || (emitter._handlers = {});
1138
- map$$1[type] = (map$$1[type] || noHandlers).concat(f);
 
 
1139
  }
1140
- };
1141
-
1142
- function getHandlers(emitter, type) {
1143
- return emitter._handlers && emitter._handlers[type] || noHandlers
1144
  }
1145
 
1146
- function off(emitter, type, f) {
1147
- if (emitter.removeEventListener) {
1148
- emitter.removeEventListener(type, f, false);
1149
- } else if (emitter.detachEvent) {
1150
- emitter.detachEvent("on" + type, f);
1151
- } else {
1152
- var map$$1 = emitter._handlers, arr = map$$1 && map$$1[type];
1153
- if (arr) {
1154
- var index = indexOf(arr, f);
1155
- if (index > -1)
1156
- { map$$1[type] = arr.slice(0, index).concat(arr.slice(index + 1)); }
1157
  }
 
 
 
 
 
 
 
1158
  }
 
1159
  }
1160
 
1161
- function signal(emitter, type /*, values...*/) {
1162
- var handlers = getHandlers(emitter, type);
1163
- if (!handlers.length) { return }
1164
- var args = Array.prototype.slice.call(arguments, 2);
1165
- for (var i = 0; i < handlers.length; ++i) { handlers[i].apply(null, args); }
1166
- }
1167
 
1168
- // The DOM events that CodeMirror handles can be overridden by
1169
- // registering a (non-DOM) handler on the editor for the event name,
1170
- // and preventDefault-ing the event in that handler.
1171
- function signalDOMEvent(cm, e, override) {
1172
- if (typeof e == "string")
1173
- { e = {type: e, preventDefault: function() { this.defaultPrevented = true; }}; }
1174
- signal(cm, override || e.type, cm, e);
1175
- return e_defaultPrevented(e) || e.codemirrorIgnore
1176
  }
1177
 
1178
- function signalCursorActivity(cm) {
1179
- var arr = cm._handlers && cm._handlers.cursorActivity;
1180
- if (!arr) { return }
1181
- var set = cm.curOp.cursorActivityHandlers || (cm.curOp.cursorActivityHandlers = []);
1182
- for (var i = 0; i < arr.length; ++i) { if (indexOf(set, arr[i]) == -1)
1183
- { set.push(arr[i]); } }
1184
- }
1185
 
1186
- function hasHandler(emitter, type) {
1187
- return getHandlers(emitter, type).length > 0
 
 
1188
  }
1189
 
1190
- // Add on and off methods to a constructor's prototype, to make
1191
- // registering events on such objects more convenient.
1192
- function eventMixin(ctor) {
1193
- ctor.prototype.on = function(type, f) {on(this, type, f);};
1194
- ctor.prototype.off = function(type, f) {off(this, type, f);};
1195
- }
1196
 
1197
- // Due to the fact that we still support jurassic IE versions, some
1198
- // compatibility wrappers are needed.
1199
 
1200
- function e_preventDefault(e) {
1201
- if (e.preventDefault) { e.preventDefault(); }
1202
- else { e.returnValue = false; }
 
 
 
 
 
 
 
 
 
1203
  }
1204
- function e_stopPropagation(e) {
1205
- if (e.stopPropagation) { e.stopPropagation(); }
1206
- else { e.cancelBubble = true; }
 
 
1207
  }
1208
- function e_defaultPrevented(e) {
1209
- return e.defaultPrevented != null ? e.defaultPrevented : e.returnValue == false
 
 
1210
  }
1211
- function e_stop(e) {e_preventDefault(e); e_stopPropagation(e);}
1212
 
1213
- function e_target(e) {return e.target || e.srcElement}
1214
- function e_button(e) {
1215
- var b = e.which;
1216
- if (b == null) {
1217
- if (e.button & 1) { b = 1; }
1218
- else if (e.button & 2) { b = 3; }
1219
- else if (e.button & 4) { b = 2; }
1220
- }
1221
- if (mac && e.ctrlKey && b == 1) { b = 3; }
1222
- return b
1223
- }
1224
 
1225
- // Detect drag-and-drop
1226
- var dragAndDrop = function() {
1227
- // There is *some* kind of drag-and-drop support in IE6-8, but I
1228
- // couldn't get it to work yet.
1229
- if (ie && ie_version < 9) { return false }
1230
- var div = elt('div');
1231
- return "draggable" in div || "dragDrop" in div
1232
- }();
1233
 
1234
- var zwspSupported;
1235
- function zeroWidthElement(measure) {
1236
- if (zwspSupported == null) {
1237
- var test = elt("span", "\u200b");
1238
- removeChildrenAndAdd(measure, elt("span", [test, document.createTextNode("x")]));
1239
- if (measure.firstChild.offsetHeight != 0)
1240
- { zwspSupported = test.offsetWidth <= 1 && test.offsetHeight > 2 && !(ie && ie_version < 8); }
1241
- }
1242
- var node = zwspSupported ? elt("span", "\u200b") :
1243
- elt("span", "\u00a0", null, "display: inline-block; width: 1px; margin-right: -1px");
1244
- node.setAttribute("cm-text", "");
1245
- return node
1246
- }
1247
 
1248
- // Feature-detect IE's crummy client rect reporting for bidi text
1249
- var badBidiRects;
1250
- function hasBadBidiRects(measure) {
1251
- if (badBidiRects != null) { return badBidiRects }
1252
- var txt = removeChildrenAndAdd(measure, document.createTextNode("A\u062eA"));
1253
- var r0 = range(txt, 0, 1).getBoundingClientRect();
1254
- var r1 = range(txt, 1, 2).getBoundingClientRect();
1255
- removeChildren(measure);
1256
- if (!r0 || r0.left == r0.right) { return false } // Safari returns null in some cases (#2780)
1257
- return badBidiRects = (r1.right - r0.right < 3)
1258
- }
1259
 
1260
- // See if "".split is the broken IE version, if so, provide an
1261
- // alternative way to split lines.
1262
- var splitLinesAuto = "\n\nb".split(/\n/).length != 3 ? function (string) {
1263
- var pos = 0, result = [], l = string.length;
1264
- while (pos <= l) {
1265
- var nl = string.indexOf("\n", pos);
1266
- if (nl == -1) { nl = string.length; }
1267
- var line = string.slice(pos, string.charAt(nl - 1) == "\r" ? nl - 1 : nl);
1268
- var rt = line.indexOf("\r");
1269
- if (rt != -1) {
1270
- result.push(line.slice(0, rt));
1271
- pos += rt + 1;
1272
- } else {
1273
- result.push(line);
1274
- pos = nl + 1;
1275
- }
1276
- }
1277
- return result
1278
- } : function (string) { return string.split(/\r\n?|\n/); };
1279
 
1280
- var hasSelection = window.getSelection ? function (te) {
1281
- try { return te.selectionStart != te.selectionEnd }
1282
- catch(e) { return false }
1283
- } : function (te) {
1284
- var range$$1;
1285
- try {range$$1 = te.ownerDocument.selection.createRange();}
1286
- catch(e) {}
1287
- if (!range$$1 || range$$1.parentElement() != te) { return false }
1288
- return range$$1.compareEndPoints("StartToEnd", range$$1) != 0
1289
  };
1290
 
1291
- var hasCopyEvent = (function () {
1292
- var e = elt("div");
1293
- if ("oncopy" in e) { return true }
1294
- e.setAttribute("oncopy", "return;");
1295
- return typeof e.oncopy == "function"
1296
- })();
1297
 
1298
- var badZoomedRects = null;
1299
- function hasBadZoomedRects(measure) {
1300
- if (badZoomedRects != null) { return badZoomedRects }
1301
- var node = removeChildrenAndAdd(measure, elt("span", "x"));
1302
- var normal = node.getBoundingClientRect();
1303
- var fromRange = range(node, 0, 1).getBoundingClientRect();
1304
- return badZoomedRects = Math.abs(normal.left - fromRange.left) > 1
1305
- }
1306
 
1307
- // Known modes, by name and by MIME
1308
- var modes = {}, mimeModes = {};
 
 
 
 
 
 
 
 
 
 
1309
 
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.)
1313
- function defineMode(name, mode) {
1314
- if (arguments.length > 2)
1315
- { mode.dependencies = Array.prototype.slice.call(arguments, 2); }
1316
- modes[name] = mode;
1317
- }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1318
 
1319
- function 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.
1325
- function 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.
1344
- function 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.
1367
- var modeExtensions = {};
1368
- function extendMode(mode, properties) {
1369
- var exts = modeExtensions.hasOwnProperty(mode) ? modeExtensions[mode] : (modeExtensions[mode] = {});
1370
- copyObj(properties, exts);
 
 
 
 
 
 
 
 
 
1371
  }
1372
 
1373
- function 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.
1387
- function 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
 
1398
- function 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
 
1407
- var 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
 
1416
- StringStream.prototype.eol = function () {return this.pos >= this.string.length};
1417
- StringStream.prototype.sol = function () {return this.pos == this.lineStart};
1418
- StringStream.prototype.peek = function () {return this.string.charAt(this.pos) || undefined};
1419
- StringStream.prototype.next = function () {
1420
- if (this.pos < this.string.length)
1421
- { return this.string.charAt(this.pos++) }
1422
- };
1423
- StringStream.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
- };
1430
- StringStream.prototype.eatWhile = function (match) {
1431
- var start = this.pos;
1432
- while (this.eat(match)){}
1433
- return this.pos > start
1434
- };
1435
- StringStream.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
- };
1442
- StringStream.prototype.skipToEnd = function () {this.pos = this.string.length;};
1443
- StringStream.prototype.skipTo = function (ch) {
1444
- var found = this.string.indexOf(ch, this.pos);
1445
- if (found > -1) {this.pos = found; return true}
1446
- };
1447
- StringStream.prototype.backUp = function (n) {this.pos -= n;};
1448
- StringStream.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
- };
1455
- StringStream.prototype.indentation = function () {
1456
- return countColumn(this.string, null, this.tabSize) -
1457
- (this.lineStart ? countColumn(this.string, this.lineStart, this.tabSize) : 0)
1458
- };
1459
- StringStream.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
- };
1474
- StringStream.prototype.current = function (){return this.string.slice(this.start, this.pos)};
1475
- StringStream.prototype.hideFirstChars = function (n, inner) {
1476
- this.lineStart += n;
1477
- try { return inner() }
1478
- finally { this.lineStart -= n; }
1479
- };
1480
- StringStream.prototype.lookAhead = function (n) {
1481
- var oracle = this.lineOracle;
1482
- return oracle && oracle.lookAhead(n)
1483
- };
1484
- StringStream.prototype.baseToken = function () {
1485
- var oracle = this.lineOracle;
1486
- return oracle && oracle.baseToken(this.pos)
1487
- };
1488
 
1489
- var SavedContext = function(state, lookAhead) {
1490
- this.state = state;
1491
- this.lookAhead = lookAhead;
1492
- };
1493
 
1494
- var 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
 
1503
- Context.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
 
1509
- Context.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
 
1520
- Context.prototype.nextLine = function () {
1521
- this.line++;
1522
- if (this.maxLookAhead > 0) { this.maxLookAhead--; }
1523
- };
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1524
 
1525
- Context.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
 
1532
- Context.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.
1542
- function 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;
1574
- }
1575
- }
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
 
1587
- function 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
 
1603
- function 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.
1623
- function 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
 
1634
- function 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
 
1641
- function 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
 
1650
- var 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
1658
- function 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
 
1672
- function 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.
1687
- function 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);
1711
- }
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.
1731
- function 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
 
1748
- function 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
@@ -1878,7 +1790,7 @@
1878
 
1879
  // Build up the DOM representation for a single token, and add it to
1880
  // the line map. Takes care to render special characters separately.
1881
- function buildToken(builder, text, style, startStyle, endStyle, title, css) {
1882
  if (!text) { return }
1883
  var displayText = builder.splitSpaces ? splitSpaces(text, builder.trailingSpace) : text;
1884
  var special = builder.cm.state.specialChars, mustWrap = false;
@@ -1929,12 +1841,15 @@
1929
  }
1930
  }
1931
  builder.trailingSpace = displayText.charCodeAt(text.length - 1) == 32;
1932
- if (style || startStyle || endStyle || mustWrap || css) {
1933
  var fullStyle = style || "";
1934
  if (startStyle) { fullStyle += startStyle; }
1935
  if (endStyle) { fullStyle += endStyle; }
1936
  var token = elt("span", [content], fullStyle, css);
1937
- if (title) { token.title = title; }
 
 
 
1938
  return builder.content.appendChild(token)
1939
  }
1940
  builder.content.appendChild(content);
@@ -1958,7 +1873,7 @@
1958
  // Work around nonsense dimensions being reported for stretches of
1959
  // right-to-left text.
1960
  function buildTokenBadBidi(inner, order) {
1961
- return function (builder, text, style, startStyle, endStyle, title, css) {
1962
  style = style ? style + " cm-force-border" : "cm-force-border";
1963
  var start = builder.pos, end = start + text.length;
1964
  for (;;) {
@@ -1968,8 +1883,8 @@
1968
  part = order[i];
1969
  if (part.to > start && part.from <= start) { break }
1970
  }
1971
- if (part.to >= end) { return inner(builder, text, style, startStyle, endStyle, title, css) }
1972
- inner(builder, text.slice(0, part.to - start), style, startStyle, null, title, css);
1973
  startStyle = null;
1974
  text = text.slice(part.to - start);
1975
  start = part.to;
@@ -2004,10 +1919,11 @@
2004
  }
2005
 
2006
  var len = allText.length, pos = 0, i = 1, text = "", style, css;
2007
- var nextChange = 0, spanStyle, spanEndStyle, spanStartStyle, title, collapsed;
2008
  for (;;) {
2009
  if (nextChange == pos) { // Update current marker set
2010
- spanStyle = spanEndStyle = spanStartStyle = title = css = "";
 
2011
  collapsed = null; nextChange = Infinity;
2012
  var foundBookmarks = [], endStyles = (void 0);
2013
  for (var j = 0; j < spans.length; ++j) {
@@ -2023,7 +1939,13 @@
2023
  if (m.css) { css = (css ? css + ";" : "") + m.css; }
2024
  if (m.startStyle && sp.from == pos) { spanStartStyle += " " + m.startStyle; }
2025
  if (m.endStyle && sp.to == nextChange) { (endStyles || (endStyles = [])).push(m.endStyle, sp.to); }
2026
- if (m.title && !title) { title = m.title; }
 
 
 
 
 
 
2027
  if (m.collapsed && (!collapsed || compareCollapsedMarkers(collapsed.marker, m) < 0))
2028
  { collapsed = sp; }
2029
  } else if (sp.from > pos && nextChange > sp.from) {
@@ -2051,7 +1973,7 @@
2051
  if (!collapsed) {
2052
  var tokenText = end > upto ? text.slice(0, upto - pos) : text;
2053
  builder.addToken(builder, tokenText, style ? style + spanStyle : spanStyle,
2054
- spanStartStyle, pos + tokenText.length == nextChange ? spanEndStyle : "", title, css);
2055
  }
2056
  if (end >= upto) {text = text.slice(upto - pos); pos = upto; break}
2057
  pos = end;
@@ -2273,8 +2195,8 @@
2273
  elt("div", lineNumberFor(cm.options, lineN),
2274
  "CodeMirror-linenumber CodeMirror-gutter-elt",
2275
  ("left: " + (dims.gutterLeft["CodeMirror-linenumbers"]) + "px; width: " + (cm.display.lineNumInnerWidth) + "px"))); }
2276
- if (markers) { for (var k = 0; k < cm.options.gutters.length; ++k) {
2277
- var id = cm.options.gutters[k], found = markers.hasOwnProperty(id) && markers[id];
2278
  if (found)
2279
  { gutterWrap.appendChild(elt("div", [found], "CodeMirror-gutter-elt",
2280
  ("left: " + (dims.gutterLeft[id]) + "px; width: " + (dims.gutterWidth[id]) + "px"))); }
@@ -2284,10 +2206,10 @@
2284
 
2285
  function updateLineWidgets(cm, lineView, dims) {
2286
  if (lineView.alignable) { lineView.alignable = null; }
 
2287
  for (var node = lineView.node.firstChild, next = (void 0); node; node = next) {
2288
  next = node.nextSibling;
2289
- if (node.className == "CodeMirror-linewidget")
2290
- { lineView.node.removeChild(node); }
2291
  }
2292
  insertLineWidgets(cm, lineView, dims);
2293
  }
@@ -2317,7 +2239,7 @@
2317
  if (!line.widgets) { return }
2318
  var wrap = ensureLineWrapped(lineView);
2319
  for (var i = 0, ws = line.widgets; i < ws.length; ++i) {
2320
- var widget = ws[i], node = elt("div", [widget.node], "CodeMirror-linewidget");
2321
  if (!widget.handleMouseEvents) { node.setAttribute("cm-ignore-events", "true"); }
2322
  positionLineWidget(widget, node, lineView, dims);
2323
  cm.display.input.setUneditable(node);
@@ -2377,7 +2299,7 @@
2377
  function paddingVert(display) {return display.mover.offsetHeight - display.lineSpace.offsetHeight}
2378
  function paddingH(display) {
2379
  if (display.cachedPaddingH) { return display.cachedPaddingH }
2380
- var e = removeChildrenAndAdd(display.measure, elt("pre", "x"));
2381
  var style = window.getComputedStyle ? window.getComputedStyle(e) : e.currentStyle;
2382
  var data = {left: parseInt(style.paddingLeft), right: parseInt(style.paddingRight)};
2383
  if (!isNaN(data.left) && !isNaN(data.right)) { display.cachedPaddingH = data; }
@@ -2505,36 +2427,36 @@
2505
 
2506
  var nullRect = {left: 0, right: 0, top: 0, bottom: 0};
2507
 
2508
- function nodeAndOffsetInLineMap(map$$1, ch, bias) {
2509
  var node, start, end, collapse, mStart, mEnd;
2510
  // First, search the line map for the text node corresponding to,
2511
  // or closest to, the target character.
2512
- for (var i = 0; i < map$$1.length; i += 3) {
2513
- mStart = map$$1[i];
2514
- mEnd = map$$1[i + 1];
2515
  if (ch < mStart) {
2516
  start = 0; end = 1;
2517
  collapse = "left";
2518
  } else if (ch < mEnd) {
2519
  start = ch - mStart;
2520
  end = start + 1;
2521
- } else if (i == map$$1.length - 3 || ch == mEnd && map$$1[i + 3] > ch) {
2522
  end = mEnd - mStart;
2523
  start = end - 1;
2524
  if (ch >= mEnd) { collapse = "right"; }
2525
  }
2526
  if (start != null) {
2527
- node = map$$1[i + 2];
2528
  if (mStart == mEnd && bias == (node.insertLeft ? "left" : "right"))
2529
  { collapse = bias; }
2530
  if (bias == "left" && start == 0)
2531
- { while (i && map$$1[i - 2] == map$$1[i - 3] && map$$1[i - 1].insertLeft) {
2532
- node = map$$1[(i -= 3) + 2];
2533
  collapse = "left";
2534
  } }
2535
  if (bias == "right" && start == mEnd - mStart)
2536
- { while (i < map$$1.length - 3 && map$$1[i + 3] == map$$1[i + 4] && !map$$1[i + 5].insertLeft) {
2537
- node = map$$1[(i += 3) + 2];
2538
  collapse = "right";
2539
  } }
2540
  break
@@ -2771,7 +2693,7 @@
2771
  function PosWithInfo(line, ch, sticky, outside, xRel) {
2772
  var pos = Pos(line, ch, sticky);
2773
  pos.xRel = xRel;
2774
- if (outside) { pos.outside = true; }
2775
  return pos
2776
  }
2777
 
@@ -2780,16 +2702,16 @@
2780
  function coordsChar(cm, x, y) {
2781
  var doc = cm.doc;
2782
  y += cm.display.viewOffset;
2783
- if (y < 0) { return PosWithInfo(doc.first, 0, null, true, -1) }
2784
  var lineN = lineAtHeight(doc, y), last = doc.first + doc.size - 1;
2785
  if (lineN > last)
2786
- { return PosWithInfo(doc.first + doc.size - 1, getLine(doc, last).text.length, null, true, 1) }
2787
  if (x < 0) { x = 0; }
2788
 
2789
  var lineObj = getLine(doc, lineN);
2790
  for (;;) {
2791
  var found = coordsCharInner(cm, lineObj, lineN, x, y);
2792
- var collapsed = collapsedSpanAround(lineObj, found.ch + (found.xRel > 0 ? 1 : 0));
2793
  if (!collapsed) { return found }
2794
  var rangeEnd = collapsed.find(1);
2795
  if (rangeEnd.line == lineN) { return rangeEnd }
@@ -2817,13 +2739,13 @@
2817
  return box.bottom <= y ? false : box.top > y ? true : (left ? box.left : box.right) > x
2818
  }
2819
 
2820
- function coordsCharInner(cm, lineObj, lineNo$$1, x, y) {
2821
  // Move y into line-local coordinate space
2822
  y -= heightAtLine(lineObj);
2823
  var preparedMeasure = prepareMeasureForLine(cm, lineObj);
2824
  // When directly calling `measureCharPrepared`, we have to adjust
2825
  // for the widgets at this line.
2826
- var widgetHeight$$1 = widgetTopHeight(lineObj);
2827
  var begin = 0, end = lineObj.text.length, ltr = true;
2828
 
2829
  var order = getOrder(lineObj, cm.doc.direction);
@@ -2831,7 +2753,7 @@
2831
  // which bidi section the coordinates fall into.
2832
  if (order) {
2833
  var part = (cm.options.lineWrapping ? coordsBidiPartWrapped : coordsBidiPart)
2834
- (cm, lineObj, lineNo$$1, preparedMeasure, order, x, y);
2835
  ltr = part.level != 1;
2836
  // The awkward -1 offsets are needed because findFirst (called
2837
  // on these below) will treat its first bound as inclusive,
@@ -2847,7 +2769,7 @@
2847
  var chAround = null, boxAround = null;
2848
  var ch = findFirst(function (ch) {
2849
  var box = measureCharPrepared(cm, preparedMeasure, ch);
2850
- box.top += widgetHeight$$1; box.bottom += widgetHeight$$1;
2851
  if (!boxIsAfter(box, x, y, false)) { return false }
2852
  if (box.top <= y && box.left <= x) {
2853
  chAround = ch;
@@ -2871,27 +2793,27 @@
2871
  // left of the character and compare it's vertical position to the
2872
  // coordinates
2873
  sticky = ch == 0 ? "after" : ch == lineObj.text.length ? "before" :
2874
- (measureCharPrepared(cm, preparedMeasure, ch - (ltr ? 1 : 0)).bottom + widgetHeight$$1 <= y) == ltr ?
2875
  "after" : "before";
2876
  // Now get accurate coordinates for this place, in order to get a
2877
  // base X position
2878
- var coords = cursorCoords(cm, Pos(lineNo$$1, ch, sticky), "line", lineObj, preparedMeasure);
2879
  baseX = coords.left;
2880
- outside = y < coords.top || y >= coords.bottom;
2881
  }
2882
 
2883
  ch = skipExtendingChars(lineObj.text, ch, 1);
2884
- return PosWithInfo(lineNo$$1, ch, sticky, outside, x - baseX)
2885
  }
2886
 
2887
- function coordsBidiPart(cm, lineObj, lineNo$$1, preparedMeasure, order, x, y) {
2888
  // Bidi parts are sorted left-to-right, and in a non-line-wrapping
2889
  // situation, we can take this ordering to correspond to the visual
2890
  // ordering. This finds the first part whose end is after the given
2891
  // coordinates.
2892
  var index = findFirst(function (i) {
2893
  var part = order[i], ltr = part.level != 1;
2894
- return boxIsAfter(cursorCoords(cm, Pos(lineNo$$1, ltr ? part.to : part.from, ltr ? "before" : "after"),
2895
  "line", lineObj, preparedMeasure), x, y, true)
2896
  }, 0, order.length - 1);
2897
  var part = order[index];
@@ -2900,7 +2822,7 @@
2900
  // that start, move one part back.
2901
  if (index > 0) {
2902
  var ltr = part.level != 1;
2903
- var start = cursorCoords(cm, Pos(lineNo$$1, ltr ? part.from : part.to, ltr ? "after" : "before"),
2904
  "line", lineObj, preparedMeasure);
2905
  if (boxIsAfter(start, x, y, true) && start.top > y)
2906
  { part = order[index - 1]; }
@@ -2946,7 +2868,7 @@
2946
  function textHeight(display) {
2947
  if (display.cachedTextHeight != null) { return display.cachedTextHeight }
2948
  if (measureText == null) {
2949
- measureText = elt("pre");
2950
  // Measure a bunch of lines, for browsers that compute
2951
  // fractional heights.
2952
  for (var i = 0; i < 49; ++i) {
@@ -2966,7 +2888,7 @@
2966
  function charWidth(display) {
2967
  if (display.cachedCharWidth != null) { return display.cachedCharWidth }
2968
  var anchor = elt("span", "xxxxxxxxxx");
2969
- var pre = elt("pre", [anchor]);
2970
  removeChildrenAndAdd(display.measure, pre);
2971
  var rect = anchor.getBoundingClientRect(), width = (rect.right - rect.left) / 10;
2972
  if (width > 2) { display.cachedCharWidth = width; }
@@ -2979,8 +2901,9 @@
2979
  var d = cm.display, left = {}, width = {};
2980
  var gutterLeft = d.gutters.clientLeft;
2981
  for (var n = d.gutters.firstChild, i = 0; n; n = n.nextSibling, ++i) {
2982
- left[cm.options.gutters[i]] = n.offsetLeft + n.clientLeft + gutterLeft;
2983
- width[cm.options.gutters[i]] = n.clientWidth;
 
2984
  }
2985
  return {fixedPos: compensateForHScroll(d),
2986
  gutterTotalWidth: d.gutters.offsetWidth,
@@ -3037,26 +2960,174 @@
3037
  var x, y, space = display.lineSpace.getBoundingClientRect();
3038
  // Fails unpredictably on IE[67] when mouse is dragged around quickly.
3039
  try { x = e.clientX - space.left; y = e.clientY - space.top; }
3040
- catch (e) { return null }
3041
  var coords = coordsChar(cm, x, y), line;
3042
- if (forRect && coords.xRel == 1 && (line = getLine(cm.doc, coords.line).text).length == coords.ch) {
3043
  var colDiff = countColumn(line, line.length, cm.options.tabSize) - line.length;
3044
  coords = Pos(coords.line, Math.max(0, Math.round((x - paddingH(cm.display).left) / charWidth(cm.display)) - colDiff));
3045
  }
3046
- return coords
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
3047
  }
3048
 
3049
- // Find the view element corresponding to a given line. Return null
3050
- // when the line isn't visible.
3051
- function findViewIndex(cm, n) {
3052
- if (n >= cm.display.viewTo) { return null }
3053
- n -= cm.display.viewFrom;
3054
- if (n < 0) { return null }
3055
- var view = cm.display.view;
3056
  for (var i = 0; i < view.length; i++) {
3057
- n -= view[i].size;
3058
- if (n < 0) { return i }
3059
  }
 
3060
  }
3061
 
3062
  function updateSelection(cm) {
@@ -3072,13 +3143,13 @@
3072
 
3073
  for (var i = 0; i < doc.sel.ranges.length; i++) {
3074
  if (!primary && i == doc.sel.primIndex) { continue }
3075
- var range$$1 = doc.sel.ranges[i];
3076
- if (range$$1.from().line >= cm.display.viewTo || range$$1.to().line < cm.display.viewFrom) { continue }
3077
- var collapsed = range$$1.empty();
3078
  if (collapsed || cm.options.showCursorWhenSelecting)
3079
- { drawSelectionCursor(cm, range$$1.head, curFragment); }
3080
  if (!collapsed)
3081
- { drawSelectionRange(cm, range$$1, selFragment); }
3082
  }
3083
  return result
3084
  }
@@ -3105,7 +3176,7 @@
3105
  function cmpCoords(a, b) { return a.top - b.top || a.left - b.left }
3106
 
3107
  // Draws the given range as a highlighted selection
3108
- function drawSelectionRange(cm, range$$1, output) {
3109
  var display = cm.display, doc = cm.doc;
3110
  var fragment = document.createDocumentFragment();
3111
  var padding = paddingH(cm.display), leftSide = padding.left;
@@ -3174,7 +3245,7 @@
3174
  return {start: start, end: end}
3175
  }
3176
 
3177
- var sFrom = range$$1.from(), sTo = range$$1.to();
3178
  if (sFrom.line == sTo.line) {
3179
  drawForLine(sFrom.line, sFrom.ch, sTo.ch);
3180
  } else {
@@ -3205,26 +3276,31 @@
3205
  var on = true;
3206
  display.cursorDiv.style.visibility = "";
3207
  if (cm.options.cursorBlinkRate > 0)
3208
- { display.blinker = setInterval(function () { return display.cursorDiv.style.visibility = (on = !on) ? "" : "hidden"; },
3209
- cm.options.cursorBlinkRate); }
 
 
3210
  else if (cm.options.cursorBlinkRate < 0)
3211
  { display.cursorDiv.style.visibility = "hidden"; }
3212
  }
3213
 
3214
  function ensureFocus(cm) {
3215
- if (!cm.state.focused) { cm.display.input.focus(); onFocus(cm); }
 
 
 
3216
  }
3217
 
3218
  function delayBlurEvent(cm) {
3219
  cm.state.delayingBlurEvent = true;
3220
  setTimeout(function () { if (cm.state.delayingBlurEvent) {
3221
  cm.state.delayingBlurEvent = false;
3222
- onBlur(cm);
3223
  } }, 100);
3224
  }
3225
 
3226
  function onFocus(cm, e) {
3227
- if (cm.state.delayingBlurEvent) { cm.state.delayingBlurEvent = false; }
3228
 
3229
  if (cm.options.readOnly == "nocursor") { return }
3230
  if (!cm.state.focused) {
@@ -3260,7 +3336,8 @@
3260
  var display = cm.display;
3261
  var prevBottom = display.lineDiv.offsetTop;
3262
  for (var i = 0; i < display.view.length; i++) {
3263
- var cur = display.view[i], height = (void 0);
 
3264
  if (cur.hidden) { continue }
3265
  if (ie && ie_version < 8) {
3266
  var bot = cur.node.offsetTop + cur.node.offsetHeight;
@@ -3269,15 +3346,26 @@
3269
  } else {
3270
  var box = cur.node.getBoundingClientRect();
3271
  height = box.bottom - box.top;
 
 
 
 
3272
  }
3273
  var diff = cur.line.height - height;
3274
- if (height < 2) { height = textHeight(display); }
3275
  if (diff > .005 || diff < -.005) {
3276
  updateLineHeight(cur.line, height);
3277
  updateWidgetHeight(cur.line);
3278
  if (cur.rest) { for (var j = 0; j < cur.rest.length; j++)
3279
  { updateWidgetHeight(cur.rest[j]); } }
3280
  }
 
 
 
 
 
 
 
 
3281
  }
3282
  }
3283
 
@@ -3314,49 +3402,6 @@
3314
  return {from: from, to: Math.max(to, from + 1)}
3315
  }
3316
 
3317
- // Re-align line numbers and gutter marks to compensate for
3318
- // horizontal scrolling.
3319
- function alignHorizontally(cm) {
3320
- var display = cm.display, view = display.view;
3321
- if (!display.alignWidgets && (!display.gutters.firstChild || !cm.options.fixedGutter)) { return }
3322
- var comp = compensateForHScroll(display) - display.scroller.scrollLeft + cm.doc.scrollLeft;
3323
- var gutterW = display.gutters.offsetWidth, left = comp + "px";
3324
- for (var i = 0; i < view.length; i++) { if (!view[i].hidden) {
3325
- if (cm.options.fixedGutter) {
3326
- if (view[i].gutter)
3327
- { view[i].gutter.style.left = left; }
3328
- if (view[i].gutterBackground)
3329
- { view[i].gutterBackground.style.left = left; }
3330
- }
3331
- var align = view[i].alignable;
3332
- if (align) { for (var j = 0; j < align.length; j++)
3333
- { align[j].style.left = left; } }
3334
- } }
3335
- if (cm.options.fixedGutter)
3336
- { display.gutters.style.left = (comp + gutterW) + "px"; }
3337
- }
3338
-
3339
- // Used to ensure that the line number gutter is still the right
3340
- // size for the current document size. Returns true when an update
3341
- // is needed.
3342
- function maybeUpdateLineNumberWidth(cm) {
3343
- if (!cm.options.lineNumbers) { return false }
3344
- var doc = cm.doc, last = lineNumberFor(cm.options, doc.first + doc.size - 1), display = cm.display;
3345
- if (last.length != display.lineNumChars) {
3346
- var test = display.measure.appendChild(elt("div", [elt("div", last)],
3347
- "CodeMirror-linenumber CodeMirror-gutter-elt"));
3348
- var innerW = test.firstChild.offsetWidth, padding = test.offsetWidth - innerW;
3349
- display.lineGutter.style.width = "";
3350
- display.lineNumInnerWidth = Math.max(innerW, display.lineGutter.offsetWidth - padding) + 1;
3351
- display.lineNumWidth = display.lineNumInnerWidth + padding;
3352
- display.lineNumChars = display.lineNumInnerWidth ? last.length : -1;
3353
- display.lineGutter.style.width = display.lineNumWidth + "px";
3354
- updateGutterSpace(cm);
3355
- return true
3356
- }
3357
- return false
3358
- }
3359
-
3360
  // SCROLLING THINGS INTO VIEW
3361
 
3362
  // If an editor sits on the top or bottom of the window, partially
@@ -3437,14 +3482,15 @@
3437
  if (newTop != screentop) { result.scrollTop = newTop; }
3438
  }
3439
 
3440
- var screenleft = cm.curOp && cm.curOp.scrollLeft != null ? cm.curOp.scrollLeft : display.scroller.scrollLeft;
3441
- var screenw = displayWidth(cm) - (cm.options.fixedGutter ? display.gutters.offsetWidth : 0);
 
3442
  var tooWide = rect.right - rect.left > screenw;
3443
  if (tooWide) { rect.right = rect.left + screenw; }
3444
  if (rect.left < 10)
3445
  { result.scrollLeft = 0; }
3446
  else if (rect.left < screenleft)
3447
- { result.scrollLeft = Math.max(0, rect.left - (tooWide ? 0 : 10)); }
3448
  else if (rect.right > screenw + screenleft - 3)
3449
  { result.scrollLeft = rect.right + (tooWide ? 0 : 10) - screenw; }
3450
  return result
@@ -3472,9 +3518,9 @@
3472
  if (y != null) { cm.curOp.scrollTop = y; }
3473
  }
3474
 
3475
- function scrollToRange(cm, range$$1) {
3476
  resolveScrollToPos(cm);
3477
- cm.curOp.scrollToPos = range$$1;
3478
  }
3479
 
3480
  // When an operation has its scrollToPos property set, and another
@@ -3482,11 +3528,11 @@
3482
  // 'simulates' scrolling that position into view in a cheap way, so
3483
  // that the effect of intermediate scroll commands is not ignored.
3484
  function resolveScrollToPos(cm) {
3485
- var range$$1 = cm.curOp.scrollToPos;
3486
- if (range$$1) {
3487
  cm.curOp.scrollToPos = null;
3488
- var from = estimateCoords(cm, range$$1.from), to = estimateCoords(cm, range$$1.to);
3489
- scrollToCoordsRange(cm, from, to, range$$1.margin);
3490
  }
3491
  }
3492
 
@@ -3511,7 +3557,7 @@
3511
  }
3512
 
3513
  function setScrollTop(cm, val, forceScroll) {
3514
- val = Math.min(cm.display.scroller.scrollHeight - cm.display.scroller.clientHeight, val);
3515
  if (cm.display.scroller.scrollTop == val && !forceScroll) { return }
3516
  cm.doc.scrollTop = val;
3517
  cm.display.scrollbars.setScrollTop(val);
@@ -3521,7 +3567,7 @@
3521
  // Sync scroller and scrollbar, ensure the gutter elements are
3522
  // aligned.
3523
  function setScrollLeft(cm, val, isScroller, forceScroll) {
3524
- val = Math.min(val, cm.display.scroller.scrollWidth - cm.display.scroller.clientWidth);
3525
  if ((isScroller ? val == cm.doc.scrollLeft : Math.abs(cm.doc.scrollLeft - val) < 2) && !forceScroll) { return }
3526
  cm.doc.scrollLeft = val;
3527
  alignHorizontally(cm);
@@ -3633,9 +3679,9 @@
3633
  // (when the bar is hidden). If it is still visible, we keep
3634
  // it enabled, if it's hidden, we disable pointer events.
3635
  var box = bar.getBoundingClientRect();
3636
- var elt$$1 = type == "vert" ? document.elementFromPoint(box.right - 1, (box.top + box.bottom) / 2)
3637
  : document.elementFromPoint((box.right + box.left) / 2, box.bottom - 1);
3638
- if (elt$$1 != bar) { bar.style.pointerEvents = "none"; }
3639
  else { delay.set(1000, maybeDisable); }
3640
  }
3641
  delay.set(1000, maybeDisable);
@@ -3726,7 +3772,7 @@
3726
  viewChanged: false, // Flag that indicates that lines might need to be redrawn
3727
  startHeight: cm.doc.height, // Used to detect need to update scrollbar
3728
  forceUpdate: false, // Used to force a redraw
3729
- updateInput: null, // Whether to reset the input textarea
3730
  typing: false, // Whether this reset should be careful to leave existing text (for compositing)
3731
  changeObjs: null, // Accumulated changes, for firing change events
3732
  cursorActivityHandlers: null, // Set of handlers to fire cursorActivity on
@@ -3904,154 +3950,6 @@
3904
  }
3905
  }
3906
 
3907
- // Updates the display.view data structure for a given change to the
3908
- // document. From and to are in pre-change coordinates. Lendiff is
3909
- // the amount of lines added or subtracted by the change. This is
3910
- // used for changes that span multiple lines, or change the way
3911
- // lines are divided into visual lines. regLineChange (below)
3912
- // registers single-line changes.
3913
- function regChange(cm, from, to, lendiff) {
3914
- if (from == null) { from = cm.doc.first; }
3915
- if (to == null) { to = cm.doc.first + cm.doc.size; }
3916
- if (!lendiff) { lendiff = 0; }
3917
-
3918
- var display = cm.display;
3919
- if (lendiff && to < display.viewTo &&
3920
- (display.updateLineNumbers == null || display.updateLineNumbers > from))
3921
- { display.updateLineNumbers = from; }
3922
-
3923
- cm.curOp.viewChanged = true;
3924
-
3925
- if (from >= display.viewTo) { // Change after
3926
- if (sawCollapsedSpans && visualLineNo(cm.doc, from) < display.viewTo)
3927
- { resetView(cm); }
3928
- } else if (to <= display.viewFrom) { // Change before
3929
- if (sawCollapsedSpans && visualLineEndNo(cm.doc, to + lendiff) > display.viewFrom) {
3930
- resetView(cm);
3931
- } else {
3932
- display.viewFrom += lendiff;
3933
- display.viewTo += lendiff;
3934
- }
3935
- } else if (from <= display.viewFrom && to >= display.viewTo) { // Full overlap
3936
- resetView(cm);
3937
- } else if (from <= display.viewFrom) { // Top overlap
3938
- var cut = viewCuttingPoint(cm, to, to + lendiff, 1);
3939
- if (cut) {
3940
- display.view = display.view.slice(cut.index);
3941
- display.viewFrom = cut.lineN;
3942
- display.viewTo += lendiff;
3943
- } else {
3944
- resetView(cm);
3945
- }
3946
- } else if (to >= display.viewTo) { // Bottom overlap
3947
- var cut$1 = viewCuttingPoint(cm, from, from, -1);
3948
- if (cut$1) {
3949
- display.view = display.view.slice(0, cut$1.index);
3950
- display.viewTo = cut$1.lineN;
3951
- } else {
3952
- resetView(cm);
3953
- }
3954
- } else { // Gap in the middle
3955
- var cutTop = viewCuttingPoint(cm, from, from, -1);
3956
- var cutBot = viewCuttingPoint(cm, to, to + lendiff, 1);
3957
- if (cutTop && cutBot) {
3958
- display.view = display.view.slice(0, cutTop.index)
3959
- .concat(buildViewArray(cm, cutTop.lineN, cutBot.lineN))
3960
- .concat(display.view.slice(cutBot.index));
3961
- display.viewTo += lendiff;
3962
- } else {
3963
- resetView(cm);
3964
- }
3965
- }
3966
-
3967
- var ext = display.externalMeasured;
3968
- if (ext) {
3969
- if (to < ext.lineN)
3970
- { ext.lineN += lendiff; }
3971
- else if (from < ext.lineN + ext.size)
3972
- { display.externalMeasured = null; }
3973
- }
3974
- }
3975
-
3976
- // Register a change to a single line. Type must be one of "text",
3977
- // "gutter", "class", "widget"
3978
- function regLineChange(cm, line, type) {
3979
- cm.curOp.viewChanged = true;
3980
- var display = cm.display, ext = cm.display.externalMeasured;
3981
- if (ext && line >= ext.lineN && line < ext.lineN + ext.size)
3982
- { display.externalMeasured = null; }
3983
-
3984
- if (line < display.viewFrom || line >= display.viewTo) { return }
3985
- var lineView = display.view[findViewIndex(cm, line)];
3986
- if (lineView.node == null) { return }
3987
- var arr = lineView.changes || (lineView.changes = []);
3988
- if (indexOf(arr, type) == -1) { arr.push(type); }
3989
- }
3990
-
3991
- // Clear the view.
3992
- function resetView(cm) {
3993
- cm.display.viewFrom = cm.display.viewTo = cm.doc.first;
3994
- cm.display.view = [];
3995
- cm.display.viewOffset = 0;
3996
- }
3997
-
3998
- function viewCuttingPoint(cm, oldN, newN, dir) {
3999
- var index = findViewIndex(cm, oldN), diff, view = cm.display.view;
4000
- if (!sawCollapsedSpans || newN == cm.doc.first + cm.doc.size)
4001
- { return {index: index, lineN: newN} }
4002
- var n = cm.display.viewFrom;
4003
- for (var i = 0; i < index; i++)
4004
- { n += view[i].size; }
4005
- if (n != oldN) {
4006
- if (dir > 0) {
4007
- if (index == view.length - 1) { return null }
4008
- diff = (n + view[index].size) - oldN;
4009
- index++;
4010
- } else {
4011
- diff = n - oldN;
4012
- }
4013
- oldN += diff; newN += diff;
4014
- }
4015
- while (visualLineNo(cm.doc, newN) != newN) {
4016
- if (index == (dir < 0 ? 0 : view.length - 1)) { return null }
4017
- newN += dir * view[index - (dir < 0 ? 1 : 0)].size;
4018
- index += dir;
4019
- }
4020
- return {index: index, lineN: newN}
4021
- }
4022
-
4023
- // Force the view to cover a given range, adding empty view element
4024
- // or clipping off existing ones as needed.
4025
- function adjustView(cm, from, to) {
4026
- var display = cm.display, view = display.view;
4027
- if (view.length == 0 || from >= display.viewTo || to <= display.viewFrom) {
4028
- display.view = buildViewArray(cm, from, to);
4029
- display.viewFrom = from;
4030
- } else {
4031
- if (display.viewFrom > from)
4032
- { display.view = buildViewArray(cm, from, display.viewFrom).concat(display.view); }
4033
- else if (display.viewFrom < from)
4034
- { display.view = display.view.slice(findViewIndex(cm, from)); }
4035
- display.viewFrom = from;
4036
- if (display.viewTo < to)
4037
- { display.view = display.view.concat(buildViewArray(cm, display.viewTo, to)); }
4038
- else if (display.viewTo > to)
4039
- { display.view = display.view.slice(0, findViewIndex(cm, to)); }
4040
- }
4041
- display.viewTo = to;
4042
- }
4043
-
4044
- // Count the number of lines in the view whose DOM representation is
4045
- // out of date (or nonexistent).
4046
- function countDirtyView(cm) {
4047
- var view = cm.display.view, dirty = 0;
4048
- for (var i = 0; i < view.length; i++) {
4049
- var lineView = view[i];
4050
- if (!lineView.hidden && (!lineView.node || lineView.changes)) { ++dirty; }
4051
- }
4052
- return dirty
4053
- }
4054
-
4055
  // HIGHLIGHT WORKER
4056
 
4057
  function startWorker(cm, time) {
@@ -4123,10 +4021,8 @@
4123
  { this.events.push(arguments); }
4124
  };
4125
  DisplayUpdate.prototype.finish = function () {
4126
- var this$1 = this;
4127
-
4128
  for (var i = 0; i < this.events.length; i++)
4129
- { signal.apply(null, this$1.events[i]); }
4130
  };
4131
 
4132
  function maybeClipScrollbars(cm) {
@@ -4160,12 +4056,13 @@
4160
  function restoreSelection(snapshot) {
4161
  if (!snapshot || !snapshot.activeElt || snapshot.activeElt == activeElt()) { return }
4162
  snapshot.activeElt.focus();
4163
- if (snapshot.anchorNode && contains(document.body, snapshot.anchorNode) && contains(document.body, snapshot.focusNode)) {
4164
- var sel = window.getSelection(), range$$1 = document.createRange();
4165
- range$$1.setEnd(snapshot.anchorNode, snapshot.anchorOffset);
4166
- range$$1.collapse(false);
 
4167
  sel.removeAllRanges();
4168
- sel.addRange(range$$1);
4169
  sel.extend(snapshot.focusNode, snapshot.focusOffset);
4170
  }
4171
  }
@@ -4258,6 +4155,8 @@
4258
  update.visible = visibleLines(cm.display, cm.doc, viewport);
4259
  if (update.visible.from >= cm.display.viewFrom && update.visible.to <= cm.display.viewTo)
4260
  { break }
 
 
4261
  }
4262
  if (!updateDisplayIfNeeded(cm, update)) { break }
4263
  updateHeightsInViewport(cm);
@@ -4333,45 +4232,206 @@
4333
  while (cur) { cur = rm(cur); }
4334
  }
4335
 
4336
- function updateGutterSpace(cm) {
4337
- var width = cm.display.gutters.offsetWidth;
4338
- cm.display.sizer.style.marginLeft = width + "px";
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
4339
  }
4340
 
4341
- function setDocumentHeight(cm, measure) {
4342
- cm.display.sizer.style.minHeight = measure.docHeight + "px";
4343
- cm.display.heightForcer.style.top = measure.docHeight + "px";
4344
- cm.display.gutters.style.height = (measure.docHeight + cm.display.barHeight + scrollGap(cm)) + "px";
 
 
 
 
 
 
 
 
 
4345
  }
4346
 
4347
  // Rebuild the gutter elements, ensure the margin to the left of the
4348
  // code matches their width.
4349
- function updateGutters(cm) {
4350
- var gutters = cm.display.gutters, specs = cm.options.gutters;
4351
  removeChildren(gutters);
4352
- var i = 0;
4353
- for (; i < specs.length; ++i) {
4354
- var gutterClass = specs[i];
4355
- var gElt = gutters.appendChild(elt("div", null, "CodeMirror-gutter " + gutterClass));
4356
- if (gutterClass == "CodeMirror-linenumbers") {
4357
- cm.display.lineGutter = gElt;
4358
- gElt.style.width = (cm.display.lineNumWidth || 1) + "px";
 
 
 
4359
  }
4360
  }
4361
- gutters.style.display = i ? "" : "none";
4362
- updateGutterSpace(cm);
 
 
 
 
 
 
4363
  }
4364
 
4365
- // Make sure the gutters options contains the element
4366
- // "CodeMirror-linenumbers" when the lineNumbers option is true.
4367
- function setGuttersForLineNumbers(options) {
4368
- var found = indexOf(options.gutters, "CodeMirror-linenumbers");
4369
- if (found == -1 && options.lineNumbers) {
4370
- options.gutters = options.gutters.concat(["CodeMirror-linenumbers"]);
4371
- } else if (found > -1 && !options.lineNumbers) {
4372
- options.gutters = options.gutters.slice(0);
4373
- options.gutters.splice(found, 1);
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
4374
  }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
4375
  }
4376
 
4377
  // Since the delta values reported on mouse wheel events are
@@ -4497,40 +4557,32 @@
4497
  Selection.prototype.primary = function () { return this.ranges[this.primIndex] };
4498
 
4499
  Selection.prototype.equals = function (other) {
4500
- var this$1 = this;
4501
-
4502
  if (other == this) { return true }
4503
  if (other.primIndex != this.primIndex || other.ranges.length != this.ranges.length) { return false }
4504
  for (var i = 0; i < this.ranges.length; i++) {
4505
- var here = this$1.ranges[i], there = other.ranges[i];
4506
  if (!equalCursorPos(here.anchor, there.anchor) || !equalCursorPos(here.head, there.head)) { return false }
4507
  }
4508
  return true
4509
  };
4510
 
4511
  Selection.prototype.deepCopy = function () {
4512
- var this$1 = this;
4513
-
4514
  var out = [];
4515
  for (var i = 0; i < this.ranges.length; i++)
4516
- { out[i] = new Range(copyPos(this$1.ranges[i].anchor), copyPos(this$1.ranges[i].head)); }
4517
  return new Selection(out, this.primIndex)
4518
  };
4519
 
4520
  Selection.prototype.somethingSelected = function () {
4521
- var this$1 = this;
4522
-
4523
  for (var i = 0; i < this.ranges.length; i++)
4524
- { if (!this$1.ranges[i].empty()) { return true } }
4525
  return false
4526
  };
4527
 
4528
  Selection.prototype.contains = function (pos, end) {
4529
- var this$1 = this;
4530
-
4531
  if (!end) { end = pos; }
4532
  for (var i = 0; i < this.ranges.length; i++) {
4533
- var range = this$1.ranges[i];
4534
  if (cmp(end, range.from()) >= 0 && cmp(pos, range.to()) <= 0)
4535
  { return i }
4536
  }
@@ -4656,16 +4708,16 @@
4656
  }
4657
 
4658
  // Perform a change on the document data structure.
4659
- function updateDoc(doc, change, markedSpans, estimateHeight$$1) {
4660
  function spansFor(n) {return markedSpans ? markedSpans[n] : null}
4661
  function update(line, text, spans) {
4662
- updateLine(line, text, spans, estimateHeight$$1);
4663
  signalLater(line, "change", line, change);
4664
  }
4665
  function linesFor(start, end) {
4666
  var result = [];
4667
  for (var i = start; i < end; ++i)
4668
- { result.push(new Line(text[i], spansFor(i), estimateHeight$$1)); }
4669
  return result
4670
  }
4671
 
@@ -4689,7 +4741,7 @@
4689
  update(firstLine, firstLine.text.slice(0, from.ch) + lastText + firstLine.text.slice(to.ch), lastSpans);
4690
  } else {
4691
  var added$1 = linesFor(1, text.length - 1);
4692
- added$1.push(new Line(lastText + firstLine.text.slice(to.ch), lastSpans, estimateHeight$$1));
4693
  update(firstLine, firstLine.text.slice(0, from.ch) + text[0], spansFor(0));
4694
  doc.insert(from.line + 1, added$1);
4695
  }
@@ -5026,11 +5078,9 @@
5026
  var obj = {
5027
  ranges: sel.ranges,
5028
  update: function(ranges) {
5029
- var this$1 = this;
5030
-
5031
  this.ranges = [];
5032
  for (var i = 0; i < ranges.length; i++)
5033
- { this$1.ranges[i] = new Range(clipPos(doc, ranges[i].anchor),
5034
  clipPos(doc, ranges[i].head)); }
5035
  },
5036
  origin: options && options.origin
@@ -5075,7 +5125,8 @@
5075
  doc.sel = sel;
5076
 
5077
  if (doc.cm) {
5078
- doc.cm.curOp.updateInput = doc.cm.curOp.selectionChanged = true;
 
5079
  signalCursorActivity(doc.cm);
5080
  }
5081
  signalLater(doc, "cursorActivity", doc);
@@ -5108,8 +5159,15 @@
5108
  var line = getLine(doc, pos.line);
5109
  if (line.markedSpans) { for (var i = 0; i < line.markedSpans.length; ++i) {
5110
  var sp = line.markedSpans[i], m = sp.marker;
5111
- if ((sp.from == null || (m.inclusiveLeft ? sp.from <= pos.ch : sp.from < pos.ch)) &&
5112
- (sp.to == null || (m.inclusiveRight ? sp.to >= pos.ch : sp.to > pos.ch))) {
 
 
 
 
 
 
 
5113
  if (mayClear) {
5114
  signal(m, "beforeCursorEnter");
5115
  if (m.explicitlyCleared) {
@@ -5121,14 +5179,14 @@
5121
 
5122
  if (oldPos) {
5123
  var near = m.find(dir < 0 ? 1 : -1), diff = (void 0);
5124
- if (dir < 0 ? m.inclusiveRight : m.inclusiveLeft)
5125
  { near = movePos(doc, near, -dir, near && near.line == pos.line ? line : null); }
5126
  if (near && near.line == pos.line && (diff = cmp(near, oldPos)) && (dir < 0 ? diff < 0 : diff > 0))
5127
  { return skipAtomicInner(doc, near, pos, dir, mayClear) }
5128
  }
5129
 
5130
  var far = m.find(dir < 0 ? -1 : 1);
5131
- if (dir < 0 ? m.inclusiveLeft : m.inclusiveRight)
5132
  { far = movePos(doc, far, dir, far.line == pos.line ? line : null); }
5133
  return far ? skipAtomicInner(doc, far, pos, dir, mayClear) : null
5134
  }
@@ -5187,7 +5245,10 @@
5187
  signal(doc, "beforeChange", doc, obj);
5188
  if (doc.cm) { signal(doc.cm, "beforeChange", doc.cm, obj); }
5189
 
5190
- if (obj.canceled) { return null }
 
 
 
5191
  return {from: obj.from, to: obj.to, text: obj.text, origin: obj.origin}
5192
  }
5193
 
@@ -5354,6 +5415,9 @@
5354
  if (doc.cm) { makeChangeSingleDocInEditor(doc.cm, change, spans); }
5355
  else { updateDoc(doc, change, spans); }
5356
  setSelectionNoUndo(doc, selAfter, sel_dontScroll);
 
 
 
5357
  }
5358
 
5359
  // Handle the interaction of a change to a document with the editor
@@ -5503,13 +5567,11 @@
5503
  // See also http://marijnhaverbeke.nl/blog/codemirror-line-tree.html
5504
 
5505
  function LeafChunk(lines) {
5506
- var this$1 = this;
5507
-
5508
  this.lines = lines;
5509
  this.parent = null;
5510
  var height = 0;
5511
  for (var i = 0; i < lines.length; ++i) {
5512
- lines[i].parent = this$1;
5513
  height += lines[i].height;
5514
  }
5515
  this.height = height;
@@ -5520,11 +5582,9 @@
5520
 
5521
  // Remove the n lines at offset 'at'.
5522
  removeInner: function(at, n) {
5523
- var this$1 = this;
5524
-
5525
  for (var i = at, e = at + n; i < e; ++i) {
5526
- var line = this$1.lines[i];
5527
- this$1.height -= line.height;
5528
  cleanUpLine(line);
5529
  signalLater(line, "delete");
5530
  }
@@ -5539,31 +5599,25 @@
5539
  // Insert the given array of lines at offset 'at', count them as
5540
  // having the given height.
5541
  insertInner: function(at, lines, height) {
5542
- var this$1 = this;
5543
-
5544
  this.height += height;
5545
  this.lines = this.lines.slice(0, at).concat(lines).concat(this.lines.slice(at));
5546
- for (var i = 0; i < lines.length; ++i) { lines[i].parent = this$1; }
5547
  },
5548
 
5549
  // Used to iterate over a part of the tree.
5550
  iterN: function(at, n, op) {
5551
- var this$1 = this;
5552
-
5553
  for (var e = at + n; at < e; ++at)
5554
- { if (op(this$1.lines[at])) { return true } }
5555
  }
5556
  };
5557
 
5558
  function BranchChunk(children) {
5559
- var this$1 = this;
5560
-
5561
  this.children = children;
5562
  var size = 0, height = 0;
5563
  for (var i = 0; i < children.length; ++i) {
5564
  var ch = children[i];
5565
  size += ch.chunkSize(); height += ch.height;
5566
- ch.parent = this$1;
5567
  }
5568
  this.size = size;
5569
  this.height = height;
@@ -5574,16 +5628,14 @@
5574
  chunkSize: function() { return this.size },
5575
 
5576
  removeInner: function(at, n) {
5577
- var this$1 = this;
5578
-
5579
  this.size -= n;
5580
  for (var i = 0; i < this.children.length; ++i) {
5581
- var child = this$1.children[i], sz = child.chunkSize();
5582
  if (at < sz) {
5583
  var rm = Math.min(n, sz - at), oldHeight = child.height;
5584
  child.removeInner(at, rm);
5585
- this$1.height -= oldHeight - child.height;
5586
- if (sz == rm) { this$1.children.splice(i--, 1); child.parent = null; }
5587
  if ((n -= rm) == 0) { break }
5588
  at = 0;
5589
  } else { at -= sz; }
@@ -5600,18 +5652,14 @@
5600
  },
5601
 
5602
  collapse: function(lines) {
5603
- var this$1 = this;
5604
-
5605
- for (var i = 0; i < this.children.length; ++i) { this$1.children[i].collapse(lines); }
5606
  },
5607
 
5608
  insertInner: function(at, lines, height) {
5609
- var this$1 = this;
5610
-
5611
  this.size += lines.length;
5612
  this.height += height;
5613
  for (var i = 0; i < this.children.length; ++i) {
5614
- var child = this$1.children[i], sz = child.chunkSize();
5615
  if (at <= sz) {
5616
  child.insertInner(at, lines, height);
5617
  if (child.lines && child.lines.length > 50) {
@@ -5621,11 +5669,11 @@
5621
  for (var pos = remaining; pos < child.lines.length;) {
5622
  var leaf = new LeafChunk(child.lines.slice(pos, pos += 25));
5623
  child.height -= leaf.height;
5624
- this$1.children.splice(++i, 0, leaf);
5625
- leaf.parent = this$1;
5626
  }
5627
  child.lines = child.lines.slice(0, remaining);
5628
- this$1.maybeSpill();
5629
  }
5630
  break
5631
  }
@@ -5657,10 +5705,8 @@
5657
  },
5658
 
5659
  iterN: function(at, n, op) {
5660
- var this$1 = this;
5661
-
5662
  for (var i = 0; i < this.children.length; ++i) {
5663
- var child = this$1.children[i], sz = child.chunkSize();
5664
  if (at < sz) {
5665
  var used = Math.min(n, sz - at);
5666
  if (child.iterN(at, used, op)) { return true }
@@ -5674,20 +5720,16 @@
5674
  // Line widgets are block elements displayed above or below a line.
5675
 
5676
  var LineWidget = function(doc, node, options) {
5677
- var this$1 = this;
5678
-
5679
  if (options) { for (var opt in options) { if (options.hasOwnProperty(opt))
5680
- { this$1[opt] = options[opt]; } } }
5681
  this.doc = doc;
5682
  this.node = node;
5683
  };
5684
 
5685
  LineWidget.prototype.clear = function () {
5686
- var this$1 = this;
5687
-
5688
  var cm = this.doc.cm, ws = this.line.widgets, line = this.line, no = lineNo(line);
5689
  if (no == null || !ws) { return }
5690
- for (var i = 0; i < ws.length; ++i) { if (ws[i] == this$1) { ws.splice(i--, 1); } }
5691
  if (!ws.length) { line.widgets = null; }
5692
  var height = widgetHeight(this);
5693
  updateLineHeight(line, Math.max(0, line.height - height));
@@ -5730,7 +5772,7 @@
5730
  changeLine(doc, handle, "widget", function (line) {
5731
  var widgets = line.widgets || (line.widgets = []);
5732
  if (widget.insertAt == null) { widgets.push(widget); }
5733
- else { widgets.splice(Math.min(widgets.length - 1, Math.max(0, widget.insertAt)), 0, widget); }
5734
  widget.line = line;
5735
  if (cm && !lineIsHidden(doc, line)) {
5736
  var aboveVisible = heightAtLine(line) < doc.scrollTop;
@@ -5770,8 +5812,6 @@
5770
 
5771
  // Clear the marker.
5772
  TextMarker.prototype.clear = function () {
5773
- var this$1 = this;
5774
-
5775
  if (this.explicitlyCleared) { return }
5776
  var cm = this.doc.cm, withOp = cm && !cm.curOp;
5777
  if (withOp) { startOperation(cm); }
@@ -5781,19 +5821,19 @@
5781
  }
5782
  var min = null, max = null;
5783
  for (var i = 0; i < this.lines.length; ++i) {
5784
- var line = this$1.lines[i];
5785
- var span = getMarkedSpanFor(line.markedSpans, this$1);
5786
- if (cm && !this$1.collapsed) { regLineChange(cm, lineNo(line), "text"); }
5787
  else if (cm) {
5788
  if (span.to != null) { max = lineNo(line); }
5789
  if (span.from != null) { min = lineNo(line); }
5790
  }
5791
  line.markedSpans = removeMarkedSpan(line.markedSpans, span);
5792
- if (span.from == null && this$1.collapsed && !lineIsHidden(this$1.doc, line) && cm)
5793
  { updateLineHeight(line, textHeight(cm.display)); }
5794
  }
5795
  if (cm && this.collapsed && !cm.options.lineWrapping) { for (var i$1 = 0; i$1 < this.lines.length; ++i$1) {
5796
- var visual = visualLine(this$1.lines[i$1]), len = lineLength(visual);
5797
  if (len > cm.display.maxLineLength) {
5798
  cm.display.maxLine = visual;
5799
  cm.display.maxLineLength = len;
@@ -5819,13 +5859,11 @@
5819
  // Pos objects returned contain a line object, rather than a line
5820
  // number (used to prevent looking up the same line twice).
5821
  TextMarker.prototype.find = function (side, lineObj) {
5822
- var this$1 = this;
5823
-
5824
  if (side == null && this.type == "bookmark") { side = 1; }
5825
  var from, to;
5826
  for (var i = 0; i < this.lines.length; ++i) {
5827
- var line = this$1.lines[i];
5828
- var span = getMarkedSpanFor(line.markedSpans, this$1);
5829
  if (span.from != null) {
5830
  from = Pos(lineObj ? line : lineNo(line), span.from);
5831
  if (side == -1) { return from }
@@ -5944,7 +5982,8 @@
5944
  if (updateMaxLine) { cm.curOp.updateMaxLine = true; }
5945
  if (marker.collapsed)
5946
  { regChange(cm, from.line, to.line + 1); }
5947
- else if (marker.className || marker.title || marker.startStyle || marker.endStyle || marker.css)
 
5948
  { for (var i = from.line; i <= to.line; i++) { regLineChange(cm, i, "text"); } }
5949
  if (marker.atomic) { reCheckSelection(cm.doc); }
5950
  signalLater(cm, "markerAdded", cm, marker);
@@ -5958,21 +5997,17 @@
5958
  // implemented as a meta-marker-object controlling multiple normal
5959
  // markers.
5960
  var SharedTextMarker = function(markers, primary) {
5961
- var this$1 = this;
5962
-
5963
  this.markers = markers;
5964
  this.primary = primary;
5965
  for (var i = 0; i < markers.length; ++i)
5966
- { markers[i].parent = this$1; }
5967
  };
5968
 
5969
  SharedTextMarker.prototype.clear = function () {
5970
- var this$1 = this;
5971
-
5972
  if (this.explicitlyCleared) { return }
5973
  this.explicitlyCleared = true;
5974
  for (var i = 0; i < this.markers.length; ++i)
5975
- { this$1.markers[i].clear(); }
5976
  signalLater(this, "clear");
5977
  };
5978
 
@@ -6115,11 +6150,11 @@
6115
  clipPos: function(pos) {return clipPos(this, pos)},
6116
 
6117
  getCursor: function(start) {
6118
- var range$$1 = this.sel.primary(), pos;
6119
- if (start == null || start == "head") { pos = range$$1.head; }
6120
- else if (start == "anchor") { pos = range$$1.anchor; }
6121
- else if (start == "end" || start == "to" || start === false) { pos = range$$1.to(); }
6122
- else { pos = range$$1.from(); }
6123
  return pos
6124
  },
6125
  listSelections: function() { return this.sel.ranges },
@@ -6142,13 +6177,11 @@
6142
  extendSelections(this, clipPosArray(this, heads), options);
6143
  }),
6144
  setSelections: docMethodOp(function(ranges, primary, options) {
6145
- var this$1 = this;
6146
-
6147
  if (!ranges.length) { return }
6148
  var out = [];
6149
  for (var i = 0; i < ranges.length; i++)
6150
- { out[i] = new Range(clipPos(this$1, ranges[i].anchor),
6151
- clipPos(this$1, ranges[i].head)); }
6152
  if (primary == null) { primary = Math.min(ranges.length - 1, this.sel.primIndex); }
6153
  setSelection(this, normalizeSelection(this.cm, out, primary), options);
6154
  }),
@@ -6159,23 +6192,19 @@
6159
  }),
6160
 
6161
  getSelection: function(lineSep) {
6162
- var this$1 = this;
6163
-
6164
  var ranges = this.sel.ranges, lines;
6165
  for (var i = 0; i < ranges.length; i++) {
6166
- var sel = getBetween(this$1, ranges[i].from(), ranges[i].to());
6167
  lines = lines ? lines.concat(sel) : sel;
6168
  }
6169
  if (lineSep === false) { return lines }
6170
  else { return lines.join(lineSep || this.lineSeparator()) }
6171
  },
6172
  getSelections: function(lineSep) {
6173
- var this$1 = this;
6174
-
6175
  var parts = [], ranges = this.sel.ranges;
6176
  for (var i = 0; i < ranges.length; i++) {
6177
- var sel = getBetween(this$1, ranges[i].from(), ranges[i].to());
6178
- if (lineSep !== false) { sel = sel.join(lineSep || this$1.lineSeparator()); }
6179
  parts[i] = sel;
6180
  }
6181
  return parts
@@ -6187,16 +6216,14 @@
6187
  this.replaceSelections(dup, collapse, origin || "+input");
6188
  },
6189
  replaceSelections: docMethodOp(function(code, collapse, origin) {
6190
- var this$1 = this;
6191
-
6192
  var changes = [], sel = this.sel;
6193
  for (var i = 0; i < sel.ranges.length; i++) {
6194
- var range$$1 = sel.ranges[i];
6195
- changes[i] = {from: range$$1.from(), to: range$$1.to(), text: this$1.splitLines(code[i]), origin: origin};
6196
  }
6197
  var newSel = collapse && collapse != "end" && computeReplacedSel(this, changes, collapse);
6198
  for (var i$1 = changes.length - 1; i$1 >= 0; i$1--)
6199
- { makeChange(this$1, changes[i$1]); }
6200
  if (newSel) { setSelectionReplaceHistory(this, newSel); }
6201
  else if (this.cm) { ensureCursorVisible(this.cm); }
6202
  }),
@@ -6214,7 +6241,12 @@
6214
  for (var i$1 = 0; i$1 < hist.undone.length; i$1++) { if (!hist.undone[i$1].ranges) { ++undone; } }
6215
  return {undo: done, redo: undone}
6216
  },
6217
- clearHistory: function() {this.history = new History(this.history.maxGeneration);},
 
 
 
 
 
6218
 
6219
  markClean: function() {
6220
  this.cleanGeneration = this.changeGeneration(true);
@@ -6335,18 +6367,18 @@
6335
  },
6336
  findMarks: function(from, to, filter) {
6337
  from = clipPos(this, from); to = clipPos(this, to);
6338
- var found = [], lineNo$$1 = from.line;
6339
  this.iter(from.line, to.line + 1, function (line) {
6340
  var spans = line.markedSpans;
6341
  if (spans) { for (var i = 0; i < spans.length; i++) {
6342
  var span = spans[i];
6343
- if (!(span.to != null && lineNo$$1 == from.line && from.ch >= span.to ||
6344
- span.from == null && lineNo$$1 != from.line ||
6345
- span.from != null && lineNo$$1 == to.line && span.from >= to.ch) &&
6346
  (!filter || filter(span.marker)))
6347
  { found.push(span.marker.parent || span.marker); }
6348
  } }
6349
- ++lineNo$$1;
6350
  });
6351
  return found
6352
  },
@@ -6361,14 +6393,14 @@
6361
  },
6362
 
6363
  posFromIndex: function(off) {
6364
- var ch, lineNo$$1 = this.first, sepSize = this.lineSeparator().length;
6365
  this.iter(function (line) {
6366
  var sz = line.text.length + sepSize;
6367
  if (sz > off) { ch = off; return true }
6368
  off -= sz;
6369
- ++lineNo$$1;
6370
  });
6371
- return clipPos(this, Pos(lineNo$$1, ch))
6372
  },
6373
  indexFromPos: function (coords) {
6374
  coords = clipPos(this, coords);
@@ -6407,15 +6439,13 @@
6407
  return copy
6408
  },
6409
  unlinkDoc: function(other) {
6410
- var this$1 = this;
6411
-
6412
  if (other instanceof CodeMirror) { other = other.doc; }
6413
  if (this.linked) { for (var i = 0; i < this.linked.length; ++i) {
6414
- var link = this$1.linked[i];
6415
  if (link.doc != other) { continue }
6416
- this$1.linked.splice(i, 1);
6417
- other.unlinkDoc(this$1);
6418
- detachSharedMarkers(findSharedMarkers(this$1));
6419
  break
6420
  } }
6421
  // If the histories were shared, split them again
@@ -6467,28 +6497,39 @@
6467
  // and insert it.
6468
  if (files && files.length && window.FileReader && window.File) {
6469
  var n = files.length, text = Array(n), read = 0;
6470
- var loadFile = function (file, i) {
6471
- if (cm.options.allowDropFileTypes &&
6472
- indexOf(cm.options.allowDropFileTypes, file.type) == -1)
6473
- { return }
6474
-
6475
- var reader = new FileReader;
6476
- reader.onload = operation(cm, function () {
6477
- var content = reader.result;
6478
- if (/[\x00-\x08\x0e-\x1f]{2}/.test(content)) { content = ""; }
6479
- text[i] = content;
6480
- if (++read == n) {
6481
  pos = clipPos(cm.doc, pos);
6482
  var change = {from: pos, to: pos,
6483
- text: cm.doc.splitLines(text.join(cm.doc.lineSeparator())),
 
6484
  origin: "paste"};
6485
  makeChange(cm.doc, change);
6486
- setSelectionReplaceHistory(cm.doc, simpleSelection(pos, changeEnd(change)));
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
6487
  }
6488
- });
 
 
6489
  reader.readAsText(file);
6490
  };
6491
- for (var i = 0; i < n; ++i) { loadFile(files[i], i); }
6492
  } else { // Normal drop
6493
  // Don't do a replace if the drop happened inside of the selected text.
6494
  if (cm.state.draggingText && cm.doc.sel.contains(pos) > -1) {
@@ -6510,7 +6551,7 @@
6510
  cm.display.input.focus();
6511
  }
6512
  }
6513
- catch(e){}
6514
  }
6515
  }
6516
 
@@ -6562,11 +6603,14 @@
6562
 
6563
  function forEachCodeMirror(f) {
6564
  if (!document.getElementsByClassName) { return }
6565
- var byClass = document.getElementsByClassName("CodeMirror");
6566
  for (var i = 0; i < byClass.length; i++) {
6567
  var cm = byClass[i].CodeMirror;
6568
- if (cm) { f(cm); }
6569
  }
 
 
 
6570
  }
6571
 
6572
  var globalsRegistered = false;
@@ -6601,9 +6645,9 @@
6601
  19: "Pause", 20: "CapsLock", 27: "Esc", 32: "Space", 33: "PageUp", 34: "PageDown", 35: "End",
6602
  36: "Home", 37: "Left", 38: "Up", 39: "Right", 40: "Down", 44: "PrintScrn", 45: "Insert",
6603
  46: "Delete", 59: ";", 61: "=", 91: "Mod", 92: "Mod", 93: "Mod",
6604
- 106: "*", 107: "=", 109: "-", 110: ".", 111: "/", 127: "Delete", 145: "ScrollLock",
6605
  173: "-", 186: ";", 187: "=", 188: ",", 189: "-", 190: ".", 191: "/", 192: "`", 219: "[", 220: "\\",
6606
- 221: "]", 222: "'", 63232: "Up", 63233: "Down", 63234: "Left", 63235: "Right", 63272: "Delete",
6607
  63273: "Home", 63275: "End", 63276: "PageUp", 63277: "PageDown", 63302: "Insert"
6608
  };
6609
 
@@ -6710,18 +6754,18 @@
6710
  return keymap
6711
  }
6712
 
6713
- function lookupKey(key, map$$1, handle, context) {
6714
- map$$1 = getKeyMap(map$$1);
6715
- var found = map$$1.call ? map$$1.call(key, context) : map$$1[key];
6716
  if (found === false) { return "nothing" }
6717
  if (found === "...") { return "multi" }
6718
  if (found != null && handle(found)) { return "handled" }
6719
 
6720
- if (map$$1.fallthrough) {
6721
- if (Object.prototype.toString.call(map$$1.fallthrough) != "[object Array]")
6722
- { return lookupKey(key, map$$1.fallthrough, handle, context) }
6723
- for (var i = 0; i < map$$1.fallthrough.length; i++) {
6724
- var result = lookupKey(key, map$$1.fallthrough[i], handle, context);
6725
  if (result) { return result }
6726
  }
6727
  }
@@ -6738,7 +6782,7 @@
6738
  var base = name;
6739
  if (event.altKey && base != "Alt") { name = "Alt-" + name; }
6740
  if ((flipCtrlCmd ? event.metaKey : event.ctrlKey) && base != "Ctrl") { name = "Ctrl-" + name; }
6741
- if ((flipCtrlCmd ? event.ctrlKey : event.metaKey) && base != "Cmd") { name = "Cmd-" + name; }
6742
  if (!noShift && event.shiftKey && base != "Shift") { name = "Shift-" + name; }
6743
  return name
6744
  }
@@ -6795,6 +6839,7 @@
6795
 
6796
  function endOfLine(visually, cm, lineObj, lineNo, dir) {
6797
  if (visually) {
 
6798
  var order = getOrder(lineObj, cm.doc.direction);
6799
  if (order) {
6800
  var part = dir < 0 ? lst(order) : order[0];
@@ -6963,7 +7008,7 @@
6963
  goGroupRight: function (cm) { return cm.moveH(1, "group"); },
6964
  goGroupLeft: function (cm) { return cm.moveH(-1, "group"); },
6965
  goWordRight: function (cm) { return cm.moveH(1, "word"); },
6966
- delCharBefore: function (cm) { return cm.deleteH(-1, "char"); },
6967
  delCharAfter: function (cm) { return cm.deleteH(1, "char"); },
6968
  delWordBefore: function (cm) { return cm.deleteH(-1, "word"); },
6969
  delWordAfter: function (cm) { return cm.deleteH(1, "word"); },
@@ -7049,7 +7094,7 @@
7049
  var line = getLine(cm.doc, start.line);
7050
  var order = getOrder(line, cm.doc.direction);
7051
  if (!order || order[0].level == 0) {
7052
- var firstNonWS = Math.max(0, line.text.search(/\S/));
7053
  var inWS = pos.line == start.line && pos.ch <= firstNonWS && pos.ch;
7054
  return Pos(start.line, inWS ? 0 : firstNonWS, start.sticky)
7055
  }
@@ -7152,6 +7197,7 @@
7152
  var lastStoppedKey = null;
7153
  function onKeyDown(e) {
7154
  var cm = this;
 
7155
  cm.curOp.focus = activeElt();
7156
  if (signalDOMEvent(cm, e)) { return }
7157
  // IE does strange things with escape.
@@ -7165,6 +7211,8 @@
7165
  if (!handled && code == 88 && !hasCopyEvent && (mac ? e.metaKey : e.ctrlKey))
7166
  { cm.replaceSelection("", null, "cut"); }
7167
  }
 
 
7168
 
7169
  // Turn mouse into crosshair when Alt is held on Mac.
7170
  if (code == 18 && !/\bCodeMirror-crosshair\b/.test(cm.display.lineDiv.className))
@@ -7193,6 +7241,7 @@
7193
 
7194
  function onKeyPress(e) {
7195
  var cm = this;
 
7196
  if (eventInWidget(cm.display, e) || signalDOMEvent(cm, e) || e.ctrlKey && !e.altKey || mac && e.metaKey) { return }
7197
  var keyCode = e.keyCode, charCode = e.charCode;
7198
  if (presto && keyCode == lastStoppedKey) {lastStoppedKey = null; e_preventDefault(e); return}
@@ -7332,6 +7381,10 @@
7332
  var dragEnd = operation(cm, function (e) {
7333
  if (webkit) { display.scroller.draggable = false; }
7334
  cm.state.draggingText = false;
 
 
 
 
7335
  off(display.wrapper.ownerDocument, "mouseup", dragEnd);
7336
  off(display.wrapper.ownerDocument, "mousemove", mouseMove);
7337
  off(display.scroller, "dragstart", dragStart);
@@ -7341,8 +7394,8 @@
7341
  if (!behavior.addNew)
7342
  { extendSelection(cm.doc, pos, null, null, behavior.extend); }
7343
  // Work around unexplainable focus problem in IE9 (#2127) and Chrome (#3081)
7344
- if (webkit || ie && ie_version == 9)
7345
- { setTimeout(function () {display.wrapper.ownerDocument.body.focus(); display.input.focus();}, 20); }
7346
  else
7347
  { display.input.focus(); }
7348
  }
@@ -7355,15 +7408,15 @@
7355
  if (webkit) { display.scroller.draggable = true; }
7356
  cm.state.draggingText = dragEnd;
7357
  dragEnd.copy = !behavior.moveOnDrag;
7358
- // IE's approach to draggable
7359
- if (display.scroller.dragDrop) { display.scroller.dragDrop(); }
7360
  on(display.wrapper.ownerDocument, "mouseup", dragEnd);
7361
  on(display.wrapper.ownerDocument, "mousemove", mouseMove);
7362
  on(display.scroller, "dragstart", dragStart);
7363
  on(display.scroller, "drop", dragEnd);
7364
 
7365
- delayBlurEvent(cm);
7366
  setTimeout(function () { return display.input.focus(); }, 20);
 
 
7367
  }
7368
 
7369
  function rangeForUnit(cm, pos, unit) {
@@ -7376,6 +7429,7 @@
7376
 
7377
  // Normal selection, as opposed to text dragging.
7378
  function leftButtonSelect(cm, event, start, behavior) {
 
7379
  var display = cm.display, doc = cm.doc;
7380
  e_preventDefault(event);
7381
 
@@ -7396,11 +7450,11 @@
7396
  start = posFromMouse(cm, event, true, true);
7397
  ourIndex = -1;
7398
  } else {
7399
- var range$$1 = rangeForUnit(cm, start, behavior.unit);
7400
  if (behavior.extend)
7401
- { ourRange = extendRange(ourRange, range$$1.anchor, range$$1.head, behavior.extend); }
7402
  else
7403
- { ourRange = range$$1; }
7404
  }
7405
 
7406
  if (!behavior.addNew) {
@@ -7443,14 +7497,14 @@
7443
  cm.scrollIntoView(pos);
7444
  } else {
7445
  var oldRange = ourRange;
7446
- var range$$1 = rangeForUnit(cm, pos, behavior.unit);
7447
  var anchor = oldRange.anchor, head;
7448
- if (cmp(range$$1.anchor, anchor) > 0) {
7449
- head = range$$1.head;
7450
- anchor = minPos(oldRange.from(), range$$1.anchor);
7451
  } else {
7452
- head = range$$1.anchor;
7453
- anchor = maxPos(oldRange.to(), range$$1.head);
7454
  }
7455
  var ranges$1 = startSel.ranges.slice(0);
7456
  ranges$1[ourIndex] = bidiSimplify(cm, new Range(clipPos(doc, anchor), head));
@@ -7488,8 +7542,13 @@
7488
  function done(e) {
7489
  cm.state.selectingText = false;
7490
  counter = Infinity;
7491
- e_preventDefault(e);
7492
- display.input.focus();
 
 
 
 
 
7493
  off(display.wrapper.ownerDocument, "mousemove", move);
7494
  off(display.wrapper.ownerDocument, "mouseup", up);
7495
  doc.history.lastSelOrigin = null;
@@ -7507,17 +7566,17 @@
7507
 
7508
  // Used when mouse-selecting to adjust the anchor to the proper side
7509
  // of a bidi jump depending on the visual position of the head.
7510
- function bidiSimplify(cm, range$$1) {
7511
- var anchor = range$$1.anchor;
7512
- var head = range$$1.head;
7513
  var anchorLine = getLine(cm.doc, anchor.line);
7514
- if (cmp(anchor, head) == 0 && anchor.sticky == head.sticky) { return range$$1 }
7515
  var order = getOrder(anchorLine);
7516
- if (!order) { return range$$1 }
7517
  var index = getBidiPartAt(order, anchor.ch, anchor.sticky), part = order[index];
7518
- if (part.from != anchor.ch && part.to != anchor.ch) { return range$$1 }
7519
  var boundary = index + ((part.from == anchor.ch) == (part.level != 1) ? 0 : 1);
7520
- if (boundary == 0 || boundary == order.length) { return range$$1 }
7521
 
7522
  // Compute the relative visual position of the head compared to the
7523
  // anchor (<0 is to the left, >0 to the right)
@@ -7536,7 +7595,7 @@
7536
  var usePart = order[boundary + (leftSide ? -1 : 0)];
7537
  var from = leftSide == (usePart.level == 1);
7538
  var ch = from ? usePart.from : usePart.to, sticky = from ? "after" : "before";
7539
- return anchor.ch == ch && anchor.sticky == sticky ? range$$1 : new Range(new Pos(anchor.line, ch, sticky), head)
7540
  }
7541
 
7542
 
@@ -7549,7 +7608,7 @@
7549
  mY = e.touches[0].clientY;
7550
  } else {
7551
  try { mX = e.clientX; mY = e.clientY; }
7552
- catch(e) { return false }
7553
  }
7554
  if (mX >= Math.floor(cm.display.gutters.getBoundingClientRect().right)) { return false }
7555
  if (prevent) { e_preventDefault(e); }
@@ -7560,12 +7619,12 @@
7560
  if (mY > lineBox.bottom || !hasHandler(cm, type)) { return e_defaultPrevented(e) }
7561
  mY -= lineBox.top - display.viewOffset;
7562
 
7563
- for (var i = 0; i < cm.options.gutters.length; ++i) {
7564
  var g = display.gutters.childNodes[i];
7565
  if (g && g.getBoundingClientRect().right >= mX) {
7566
  var line = lineAtHeight(cm.doc, mY);
7567
- var gutter = cm.options.gutters[i];
7568
- signal(cm, type, cm, line, gutter, e);
7569
  return e_defaultPrevented(e)
7570
  }
7571
  }
@@ -7649,7 +7708,7 @@
7649
  for (var i = newBreaks.length - 1; i >= 0; i--)
7650
  { replaceRange(cm.doc, val, newBreaks[i], Pos(newBreaks[i].line, newBreaks[i].ch + val.length)); }
7651
  });
7652
- option("specialChars", /[\u0000-\u001f\u007f-\u009f\u00ad\u061c\u200b-\u200f\u2028\u2029\ufeff]/g, function (cm, val, old) {
7653
  cm.state.specialChars = new RegExp(val.source + (val.test("\t") ? "" : "|\t"), "g");
7654
  if (old != Init) { cm.refresh(); }
7655
  });
@@ -7659,12 +7718,14 @@
7659
  throw new Error("inputStyle can not (yet) be changed in a running editor") // FIXME
7660
  }, true);
7661
  option("spellcheck", false, function (cm, val) { return cm.getInputField().spellcheck = val; }, true);
 
 
7662
  option("rtlMoveVisually", !windows);
7663
  option("wholeLineUpdateBefore", true);
7664
 
7665
  option("theme", "default", function (cm) {
7666
  themeChanged(cm);
7667
- guttersChanged(cm);
7668
  }, true);
7669
  option("keyMap", "default", function (cm, val, old) {
7670
  var next = getKeyMap(val);
@@ -7676,9 +7737,9 @@
7676
  option("configureMouse", null);
7677
 
7678
  option("lineWrapping", false, wrappingChanged, true);
7679
- option("gutters", [], function (cm) {
7680
- setGuttersForLineNumbers(cm.options);
7681
- guttersChanged(cm);
7682
  }, true);
7683
  option("fixedGutter", true, function (cm, val) {
7684
  cm.display.gutters.style.left = val ? compensateForHScroll(cm.display) + "px" : "0";
@@ -7691,12 +7752,12 @@
7691
  cm.display.scrollbars.setScrollTop(cm.doc.scrollTop);
7692
  cm.display.scrollbars.setScrollLeft(cm.doc.scrollLeft);
7693
  }, true);
7694
- option("lineNumbers", false, function (cm) {
7695
- setGuttersForLineNumbers(cm.options);
7696
- guttersChanged(cm);
7697
  }, true);
7698
- option("firstLineNumber", 1, guttersChanged, true);
7699
- option("lineNumberFormatter", function (integer) { return integer; }, guttersChanged, true);
7700
  option("showCursorWhenSelecting", false, updateSelection, true);
7701
 
7702
  option("resetSelectionOnContextMenu", true);
@@ -7711,6 +7772,12 @@
7711
  }
7712
  cm.display.input.readOnlyChanged(val);
7713
  });
 
 
 
 
 
 
7714
  option("disableInput", false, function (cm, val) {if (!val) { cm.display.input.reset(); }}, true);
7715
  option("dragDrop", true, dragDropChanged);
7716
  option("allowDropFileTypes", null);
@@ -7738,12 +7805,6 @@
7738
  option("phrases", null);
7739
  }
7740
 
7741
- function guttersChanged(cm) {
7742
- updateGutters(cm);
7743
- regChange(cm);
7744
- alignHorizontally(cm);
7745
- }
7746
-
7747
  function dragDropChanged(cm, value, old) {
7748
  var wasOn = old && old != Init;
7749
  if (!value != !wasOn) {
@@ -7783,7 +7844,6 @@
7783
  this.options = options = options ? copyObj(options) : {};
7784
  // Determine effective options based on given values and defaults.
7785
  copyObj(defaults, options, false);
7786
- setGuttersForLineNumbers(options);
7787
 
7788
  var doc = options.value;
7789
  if (typeof doc == "string") { doc = new Doc(doc, options.mode, null, options.lineSeparator, options.direction); }
@@ -7791,9 +7851,8 @@
7791
  this.doc = doc;
7792
 
7793
  var input = new CodeMirror.inputStyles[options.inputStyle](this);
7794
- var display = this.display = new Display(place, doc, input);
7795
  display.wrapper.CodeMirror = this;
7796
- updateGutters(this);
7797
  themeChanged(this);
7798
  if (options.lineWrapping)
7799
  { this.display.wrapper.className += " CodeMirror-wrap"; }
@@ -7807,7 +7866,7 @@
7807
  delayingBlurEvent: false,
7808
  focused: false,
7809
  suppressEdits: false, // used to disable editing during key handlers when in readOnly mode
7810
- pasteIncoming: false, cutIncoming: false, // help recognize paste/cut edits in input.poll
7811
  selectingText: false,
7812
  draggingText: false,
7813
  highlight: new Delayed(), // stores highlight worker timeout
@@ -7829,15 +7888,17 @@
7829
  attachDoc(this, doc);
7830
 
7831
  if ((options.autofocus && !mobile) || this.hasFocus())
7832
- { setTimeout(bind(onFocus, this), 20); }
 
 
7833
  else
7834
  { onBlur(this); }
7835
 
7836
  for (var opt in optionHandlers) { if (optionHandlers.hasOwnProperty(opt))
7837
- { optionHandlers[opt](this$1, options[opt], Init); } }
7838
  maybeUpdateLineNumberWidth(this);
7839
  if (options.finishInit) { options.finishInit(this); }
7840
- for (var i = 0; i < initHooks.length; ++i) { initHooks[i](this$1); }
7841
  endOperation(this);
7842
  // Suppress optimizelegibility in Webkit, since it breaks text
7843
  // measuring on line wrapping boundaries.
@@ -7871,6 +7932,9 @@
7871
  // which point we can't mess with it anymore. Context menu is
7872
  // handled in onMouseDown for these browsers.
7873
  on(d.scroller, "contextmenu", function (e) { return onContextMenu(cm, e); });
 
 
 
7874
 
7875
  // Used to suppress mouse event handling when a touch happens
7876
  var touchFinished, prevTouch = {end: 0};
@@ -8040,7 +8104,8 @@
8040
  cm.display.shift = false;
8041
  if (!sel) { sel = doc.sel; }
8042
 
8043
- var paste = cm.state.pasteIncoming || origin == "paste";
 
8044
  var textLines = splitLinesAuto(inserted), multiPaste = null;
8045
  // When pasting N lines into N selections, insert one line per selection
8046
  if (paste && sel.ranges.length > 1) {
@@ -8055,22 +8120,21 @@
8055
  }
8056
  }
8057
 
8058
- var updateInput;
8059
  // Normal behavior is to insert the new text into every selection
8060
  for (var i$1 = sel.ranges.length - 1; i$1 >= 0; i$1--) {
8061
- var range$$1 = sel.ranges[i$1];
8062
- var from = range$$1.from(), to = range$$1.to();
8063
- if (range$$1.empty()) {
8064
  if (deleted && deleted > 0) // Handle deletion
8065
  { from = Pos(from.line, from.ch - deleted); }
8066
  else if (cm.state.overwrite && !paste) // Handle overwrite
8067
  { to = Pos(to.line, Math.min(getLine(doc, to.line).text.length, to.ch + lst(textLines).length)); }
8068
- else if (paste && lastCopied && lastCopied.lineWise && lastCopied.text.join("\n") == inserted)
8069
  { from = to = Pos(from.line, 0); }
8070
  }
8071
- updateInput = cm.curOp.updateInput;
8072
  var changeEvent = {from: from, to: to, text: multiPaste ? multiPaste[i$1 % multiPaste.length] : textLines,
8073
- origin: origin || (paste ? "paste" : cm.state.cutIncoming ? "cut" : "+input")};
8074
  makeChange(cm.doc, changeEvent);
8075
  signalLater(cm, "inputRead", cm, changeEvent);
8076
  }
@@ -8078,9 +8142,9 @@
8078
  { triggerElectric(cm, inserted); }
8079
 
8080
  ensureCursorVisible(cm);
8081
- cm.curOp.updateInput = updateInput;
8082
  cm.curOp.typing = true;
8083
- cm.state.pasteIncoming = cm.state.cutIncoming = false;
8084
  }
8085
 
8086
  function handlePaste(e, cm) {
@@ -8099,21 +8163,21 @@
8099
  var sel = cm.doc.sel;
8100
 
8101
  for (var i = sel.ranges.length - 1; i >= 0; i--) {
8102
- var range$$1 = sel.ranges[i];
8103
- if (range$$1.head.ch > 100 || (i && sel.ranges[i - 1].head.line == range$$1.head.line)) { continue }
8104
- var mode = cm.getModeAt(range$$1.head);
8105
  var indented = false;
8106
  if (mode.electricChars) {
8107
  for (var j = 0; j < mode.electricChars.length; j++)
8108
  { if (inserted.indexOf(mode.electricChars.charAt(j)) > -1) {
8109
- indented = indentLine(cm, range$$1.head.line, "smart");
8110
  break
8111
  } }
8112
  } else if (mode.electricInput) {
8113
- if (mode.electricInput.test(getLine(cm.doc, range$$1.head.line).text.slice(0, range$$1.head.ch)))
8114
- { indented = indentLine(cm, range$$1.head.line, "smart"); }
8115
  }
8116
- if (indented) { signalLater(cm, "electricInput", cm, range$$1.head.line); }
8117
  }
8118
  }
8119
 
@@ -8128,9 +8192,9 @@
8128
  return {text: text, ranges: ranges}
8129
  }
8130
 
8131
- function disableBrowserMagic(field, spellcheck) {
8132
- field.setAttribute("autocorrect", "off");
8133
- field.setAttribute("autocapitalize", "off");
8134
  field.setAttribute("spellcheck", !!spellcheck);
8135
  }
8136
 
@@ -8178,13 +8242,13 @@
8178
  getOption: function(option) {return this.options[option]},
8179
  getDoc: function() {return this.doc},
8180
 
8181
- addKeyMap: function(map$$1, bottom) {
8182
- this.state.keyMaps[bottom ? "push" : "unshift"](getKeyMap(map$$1));
8183
  },
8184
- removeKeyMap: function(map$$1) {
8185
  var maps = this.state.keyMaps;
8186
  for (var i = 0; i < maps.length; ++i)
8187
- { if (maps[i] == map$$1 || maps[i].name == map$$1) {
8188
  maps.splice(i, 1);
8189
  return true
8190
  } }
@@ -8201,15 +8265,13 @@
8201
  regChange(this);
8202
  }),
8203
  removeOverlay: methodOp(function(spec) {
8204
- var this$1 = this;
8205
-
8206
  var overlays = this.state.overlays;
8207
  for (var i = 0; i < overlays.length; ++i) {
8208
  var cur = overlays[i].modeSpec;
8209
  if (cur == spec || typeof spec == "string" && cur.name == spec) {
8210
  overlays.splice(i, 1);
8211
- this$1.state.modeGen++;
8212
- regChange(this$1);
8213
  return
8214
  }
8215
  }
@@ -8223,24 +8285,22 @@
8223
  if (isLine(this.doc, n)) { indentLine(this, n, dir, aggressive); }
8224
  }),
8225
  indentSelection: methodOp(function(how) {
8226
- var this$1 = this;
8227
-
8228
  var ranges = this.doc.sel.ranges, end = -1;
8229
  for (var i = 0; i < ranges.length; i++) {
8230
- var range$$1 = ranges[i];
8231
- if (!range$$1.empty()) {
8232
- var from = range$$1.from(), to = range$$1.to();
8233
  var start = Math.max(end, from.line);
8234
- end = Math.min(this$1.lastLine(), to.line - (to.ch ? 0 : 1)) + 1;
8235
  for (var j = start; j < end; ++j)
8236
- { indentLine(this$1, j, how); }
8237
- var newRanges = this$1.doc.sel.ranges;
8238
  if (from.ch == 0 && ranges.length == newRanges.length && newRanges[i].from().ch > 0)
8239
- { replaceOneSelection(this$1.doc, i, new Range(from, newRanges[i].to()), sel_dontScroll); }
8240
- } else if (range$$1.head.line > end) {
8241
- indentLine(this$1, range$$1.head.line, how, true);
8242
- end = range$$1.head.line;
8243
- if (i == this$1.doc.sel.primIndex) { ensureCursorVisible(this$1); }
8244
  }
8245
  }
8246
  }),
@@ -8282,8 +8342,6 @@
8282
  },
8283
 
8284
  getHelpers: function(pos, type) {
8285
- var this$1 = this;
8286
-
8287
  var found = [];
8288
  if (!helpers.hasOwnProperty(type)) { return found }
8289
  var help = helpers[type], mode = this.getModeAt(pos);
@@ -8301,7 +8359,7 @@
8301
  }
8302
  for (var i$1 = 0; i$1 < help._global.length; i$1++) {
8303
  var cur = help._global[i$1];
8304
- if (cur.pred(mode, this$1) && indexOf(found, cur.val) == -1)
8305
  { found.push(cur.val); }
8306
  }
8307
  return found
@@ -8314,10 +8372,10 @@
8314
  },
8315
 
8316
  cursorCoords: function(start, mode) {
8317
- var pos, range$$1 = this.doc.sel.primary();
8318
- if (start == null) { pos = range$$1.head; }
8319
  else if (typeof start == "object") { pos = clipPos(this.doc, start); }
8320
- else { pos = start ? range$$1.from() : range$$1.to(); }
8321
  return cursorCoords(this, pos, mode || "page")
8322
  },
8323
 
@@ -8401,13 +8459,11 @@
8401
  triggerElectric: methodOp(function(text) { triggerElectric(this, text); }),
8402
 
8403
  findPosH: function(from, amount, unit, visually) {
8404
- var this$1 = this;
8405
-
8406
  var dir = 1;
8407
  if (amount < 0) { dir = -1; amount = -amount; }
8408
  var cur = clipPos(this.doc, from);
8409
  for (var i = 0; i < amount; ++i) {
8410
- cur = findPosH(this$1.doc, cur, dir, unit, visually);
8411
  if (cur.hitSide) { break }
8412
  }
8413
  return cur
@@ -8416,11 +8472,11 @@
8416
  moveH: methodOp(function(dir, unit) {
8417
  var this$1 = this;
8418
 
8419
- this.extendSelectionsBy(function (range$$1) {
8420
- if (this$1.display.shift || this$1.doc.extend || range$$1.empty())
8421
- { return findPosH(this$1.doc, range$$1.head, dir, unit, this$1.options.rtlMoveVisually) }
8422
  else
8423
- { return dir < 0 ? range$$1.from() : range$$1.to() }
8424
  }, sel_move);
8425
  }),
8426
 
@@ -8429,23 +8485,21 @@
8429
  if (sel.somethingSelected())
8430
  { doc.replaceSelection("", null, "+delete"); }
8431
  else
8432
- { deleteNearSelection(this, function (range$$1) {
8433
- var other = findPosH(doc, range$$1.head, dir, unit, false);
8434
- return dir < 0 ? {from: other, to: range$$1.head} : {from: range$$1.head, to: other}
8435
  }); }
8436
  }),
8437
 
8438
  findPosV: function(from, amount, unit, goalColumn) {
8439
- var this$1 = this;
8440
-
8441
  var dir = 1, x = goalColumn;
8442
  if (amount < 0) { dir = -1; amount = -amount; }
8443
  var cur = clipPos(this.doc, from);
8444
  for (var i = 0; i < amount; ++i) {
8445
- var coords = cursorCoords(this$1, cur, "div");
8446
  if (x == null) { x = coords.left; }
8447
  else { coords.left = x; }
8448
- cur = findPosV(this$1, coords, dir, unit);
8449
  if (cur.hitSide) { break }
8450
  }
8451
  return cur
@@ -8456,14 +8510,14 @@
8456
 
8457
  var doc = this.doc, goals = [];
8458
  var collapse = !this.display.shift && !doc.extend && doc.sel.somethingSelected();
8459
- doc.extendSelectionsBy(function (range$$1) {
8460
  if (collapse)
8461
- { return dir < 0 ? range$$1.from() : range$$1.to() }
8462
- var headPos = cursorCoords(this$1, range$$1.head, "div");
8463
- if (range$$1.goalColumn != null) { headPos.left = range$$1.goalColumn; }
8464
  goals.push(headPos.left);
8465
  var pos = findPosV(this$1, headPos, dir, unit);
8466
- if (unit == "page" && range$$1 == doc.sel.primary())
8467
  { addToScrollTop(this$1, charCoords(this$1, pos, "div").top - headPos.top); }
8468
  return pos
8469
  }, sel_move);
@@ -8510,22 +8564,22 @@
8510
  clientHeight: displayHeight(this), clientWidth: displayWidth(this)}
8511
  },
8512
 
8513
- scrollIntoView: methodOp(function(range$$1, margin) {
8514
- if (range$$1 == null) {
8515
- range$$1 = {from: this.doc.sel.primary().head, to: null};
8516
  if (margin == null) { margin = this.options.cursorScrollMargin; }
8517
- } else if (typeof range$$1 == "number") {
8518
- range$$1 = {from: Pos(range$$1, 0), to: null};
8519
- } else if (range$$1.from == null) {
8520
- range$$1 = {from: range$$1, to: null};
8521
  }
8522
- if (!range$$1.to) { range$$1.to = range$$1.from; }
8523
- range$$1.margin = margin || 0;
8524
 
8525
- if (range$$1.from.line != null) {
8526
- scrollToRange(this, range$$1);
8527
  } else {
8528
- scrollToCoordsRange(this, range$$1.from, range$$1.to, range$$1.margin);
8529
  }
8530
  }),
8531
 
@@ -8536,11 +8590,11 @@
8536
  if (width != null) { this.display.wrapper.style.width = interpret(width); }
8537
  if (height != null) { this.display.wrapper.style.height = interpret(height); }
8538
  if (this.options.lineWrapping) { clearLineMeasurementCache(this); }
8539
- var lineNo$$1 = this.display.viewFrom;
8540
- this.doc.iter(lineNo$$1, this.display.viewTo, function (line) {
8541
  if (line.widgets) { for (var i = 0; i < line.widgets.length; i++)
8542
- { if (line.widgets[i].noHScroll) { regLineChange(this$1, lineNo$$1, "widget"); break } } }
8543
- ++lineNo$$1;
8544
  });
8545
  this.curOp.forceUpdate = true;
8546
  signal(this, "refresh", this);
@@ -8556,8 +8610,8 @@
8556
  this.curOp.forceUpdate = true;
8557
  clearCaches(this);
8558
  scrollToCoords(this, this.doc.scrollLeft, this.doc.scrollTop);
8559
- updateGutterSpace(this);
8560
- if (oldHeight == null || Math.abs(oldHeight - textHeight(this.display)) > .5)
8561
  { estimateLineHeights(this); }
8562
  signal(this, "refresh", this);
8563
  }),
@@ -8565,6 +8619,8 @@
8565
  swapDoc: methodOp(function(doc) {
8566
  var old = this.doc;
8567
  old.cm = null;
 
 
8568
  attachDoc(this, doc);
8569
  clearCaches(this);
8570
  this.display.input.reset();
@@ -8597,34 +8653,43 @@
8597
  }
8598
 
8599
  // Used for horizontal relative motion. Dir is -1 or 1 (left or
8600
- // right), unit can be "char", "column" (like char, but doesn't
8601
- // cross line boundaries), "word" (across next word), or "group" (to
8602
- // the start of next group of word or non-word-non-whitespace
8603
- // chars). The visually param controls whether, in right-to-left
8604
- // text, direction 1 means to move towards the next index in the
8605
- // string, or towards the character to the right of the current
8606
- // position. The resulting position will have a hitSide=true
8607
- // property if it reached the end of the document.
8608
  function findPosH(doc, pos, dir, unit, visually) {
8609
  var oldPos = pos;
8610
  var origDir = dir;
8611
  var lineObj = getLine(doc, pos.line);
 
8612
  function findNextLine() {
8613
- var l = pos.line + dir;
8614
  if (l < doc.first || l >= doc.first + doc.size) { return false }
8615
  pos = new Pos(l, pos.ch, pos.sticky);
8616
  return lineObj = getLine(doc, l)
8617
  }
8618
  function moveOnce(boundToLine) {
8619
  var next;
8620
- if (visually) {
 
 
 
 
 
 
 
 
8621
  next = moveVisually(doc.cm, lineObj, pos, dir);
8622
  } else {
8623
  next = moveLogically(lineObj, pos, dir);
8624
  }
8625
  if (next == null) {
8626
  if (!boundToLine && findNextLine())
8627
- { pos = endOfLine(visually, doc.cm, lineObj, pos.line, dir); }
8628
  else
8629
  { return false }
8630
  } else {
@@ -8633,7 +8698,7 @@
8633
  return true
8634
  }
8635
 
8636
- if (unit == "char") {
8637
  moveOnce();
8638
  } else if (unit == "column") {
8639
  moveOnce(true);
@@ -8701,10 +8766,18 @@
8701
 
8702
  var input = this, cm = input.cm;
8703
  var div = input.div = display.lineDiv;
8704
- disableBrowserMagic(div, cm.options.spellcheck);
 
 
 
 
 
 
 
 
8705
 
8706
  on(div, "paste", function (e) {
8707
- if (signalDOMEvent(cm, e) || handlePaste(e, cm)) { return }
8708
  // IE doesn't fire input events, so we schedule a read for the pasted content in this way
8709
  if (ie_version <= 11) { setTimeout(operation(cm, function () { return this$1.updateFromDOM(); }), 20); }
8710
  });
@@ -8729,7 +8802,7 @@
8729
  });
8730
 
8731
  function onCopyCut(e) {
8732
- if (signalDOMEvent(cm, e)) { return }
8733
  if (cm.somethingSelected()) {
8734
  setLastCopied({lineWise: false, text: cm.getSelections()});
8735
  if (e.type == "cut") { cm.replaceSelection("", null, "cut"); }
@@ -8771,9 +8844,18 @@
8771
  on(div, "cut", onCopyCut);
8772
  };
8773
 
 
 
 
 
 
 
 
 
 
8774
  ContentEditableInput.prototype.prepareSelection = function () {
8775
  var result = prepareSelection(this.cm, false);
8776
- result.focus = this.cm.state.focused;
8777
  return result
8778
  };
8779
 
@@ -8809,8 +8891,8 @@
8809
  var end = to.line < cm.display.viewTo && posToDOM(cm, to);
8810
  if (!end) {
8811
  var measure = view[view.length - 1].measure;
8812
- var map$$1 = measure.maps ? measure.maps[measure.maps.length - 1] : measure.map;
8813
- end = {node: map$$1[map$$1.length - 1], offset: map$$1[map$$1.length - 2] - map$$1[map$$1.length - 3]};
8814
  }
8815
 
8816
  if (!start || !end) {
@@ -8869,7 +8951,7 @@
8869
 
8870
  ContentEditableInput.prototype.focus = function () {
8871
  if (this.cm.options.readOnly != "nocursor") {
8872
- if (!this.selectionInEditor())
8873
  { this.showSelection(this.prepareSelection(), true); }
8874
  this.div.focus();
8875
  }
@@ -8910,7 +8992,7 @@
8910
  // Because Android doesn't allow us to actually detect backspace
8911
  // presses in a sane way, this code checks for when that happens
8912
  // and simulates a backspace press in this case.
8913
- if (android && chrome && this.cm.options.gutters.length && isInGutter(sel.anchorNode)) {
8914
  this.cm.triggerOnKeyDown({type: "keydown", keyCode: 8, preventDefault: Math.abs});
8915
  this.blur();
8916
  this.focus();
@@ -9099,11 +9181,11 @@
9099
  addText(cmText);
9100
  return
9101
  }
9102
- var markerID = node.getAttribute("cm-marker"), range$$1;
9103
  if (markerID) {
9104
  var found = cm.findMarks(Pos(fromLine, 0), Pos(toLine + 1, 0), recognizeMarker(+markerID));
9105
- if (found.length && (range$$1 = found[0].find(0)))
9106
- { addText(getBetween(cm.doc, range$$1.from, range$$1.to).join(lineSep)); }
9107
  return
9108
  }
9109
  if (node.getAttribute("contenteditable") == "false") { return }
@@ -9171,13 +9253,13 @@
9171
 
9172
  function find(textNode, topNode, offset) {
9173
  for (var i = -1; i < (maps ? maps.length : 0); i++) {
9174
- var map$$1 = i < 0 ? measure.map : maps[i];
9175
- for (var j = 0; j < map$$1.length; j += 3) {
9176
- var curNode = map$$1[j + 2];
9177
  if (curNode == textNode || curNode == topNode) {
9178
  var line = lineNo(i < 0 ? lineView.line : lineView.rest[i]);
9179
- var ch = map$$1[j] + offset;
9180
- if (offset < 0 || curNode != textNode) { ch = map$$1[j + (offset ? 1 : 0)]; }
9181
  return Pos(line, ch)
9182
  }
9183
  }
@@ -9241,7 +9323,7 @@
9241
  on(te, "paste", function (e) {
9242
  if (signalDOMEvent(cm, e) || handlePaste(e, cm)) { return }
9243
 
9244
- cm.state.pasteIncoming = true;
9245
  input.fastPoll();
9246
  });
9247
 
@@ -9262,15 +9344,23 @@
9262
  selectInput(te);
9263
  }
9264
  }
9265
- if (e.type == "cut") { cm.state.cutIncoming = true; }
9266
  }
9267
  on(te, "cut", prepareCopyCut);
9268
  on(te, "copy", prepareCopyCut);
9269
 
9270
  on(display.scroller, "paste", function (e) {
9271
  if (eventInWidget(display, e) || signalDOMEvent(cm, e)) { return }
9272
- cm.state.pasteIncoming = true;
9273
- input.focus();
 
 
 
 
 
 
 
 
9274
  });
9275
 
9276
  // Prevent normal selection in the editor (we handle our own)
@@ -9303,6 +9393,15 @@
9303
  this.textarea = this.wrapper.firstChild;
9304
  };
9305
 
 
 
 
 
 
 
 
 
 
9306
  TextareaInput.prototype.prepareSelection = function () {
9307
  // Redraw the selection and/or cursor
9308
  var cm = this.cm, display = cm.display, doc = cm.doc;
@@ -9461,6 +9560,7 @@
9461
 
9462
  TextareaInput.prototype.onContextMenu = function (e) {
9463
  var input = this, cm = input.cm, display = cm.display, te = input.textarea;
 
9464
  var pos = posFromMouse(cm, e), scrollPos = display.scroller.scrollTop;
9465
  if (!pos || presto) { return } // Opera is difficult.
9466
 
@@ -9471,8 +9571,8 @@
9471
  { operation(cm, setSelection)(cm.doc, simpleSelection(pos), sel_dontScroll); }
9472
 
9473
  var oldCSS = te.style.cssText, oldWrapperCSS = input.wrapper.style.cssText;
9474
- input.wrapper.style.cssText = "position: absolute";
9475
- var wrapperBox = input.wrapper.getBoundingClientRect();
9476
  te.style.cssText = "position: absolute; width: 30px; height: 30px;\n top: " + (e.clientY - wrapperBox.top - 5) + "px; left: " + (e.clientX - wrapperBox.left - 5) + "px;\n z-index: 1000; background: " + (ie ? "rgba(255, 255, 255, .05)" : "transparent") + ";\n outline: none; border-width: 0; outline: none; overflow: hidden; opacity: .05; filter: alpha(opacity=5);";
9477
  var oldScrollY;
9478
  if (webkit) { oldScrollY = window.scrollY; } // Work around Chrome issue (#2712)
@@ -9481,7 +9581,7 @@
9481
  display.input.reset();
9482
  // Adds "Select all" to context menu in FF
9483
  if (!cm.somethingSelected()) { te.value = input.prevInput = " "; }
9484
- input.contextMenuPending = true;
9485
  display.selForContextMenu = cm.doc.sel;
9486
  clearTimeout(display.detectingSelectAll);
9487
 
@@ -9502,6 +9602,7 @@
9502
  }
9503
  }
9504
  function rehide() {
 
9505
  input.contextMenuPending = false;
9506
  input.wrapper.style.cssText = oldWrapperCSS;
9507
  te.style.cssText = oldCSS;
@@ -9541,6 +9642,7 @@
9541
  TextareaInput.prototype.readOnlyChanged = function (val) {
9542
  if (!val) { this.reset(); }
9543
  this.textarea.disabled = val == "nocursor";
 
9544
  };
9545
 
9546
  TextareaInput.prototype.setUneditable = function () {};
@@ -9592,7 +9694,7 @@
9592
  textarea.style.display = "";
9593
  if (textarea.form) {
9594
  off(textarea.form, "submit", save);
9595
- if (typeof textarea.form.submit == "function")
9596
  { textarea.form.submit = realSubmit; }
9597
  }
9598
  };
@@ -9691,7 +9793,7 @@
9691
 
9692
  addLegacyProps(CodeMirror);
9693
 
9694
- CodeMirror.version = "5.41.0";
9695
 
9696
  return CodeMirror;
9697
 
10
  (function (global, factory) {
11
  typeof exports === 'object' && typeof module !== 'undefined' ? module.exports = factory() :
12
  typeof define === 'function' && define.amd ? define(factory) :
13
+ (global = global || self, global.CodeMirror = factory());
14
  }(this, (function () { 'use strict';
15
 
16
  // Kludges for bugs and behavior differences that can't be feature
32
  var mac_geMountainLion = /Mac OS X 1\d\D([8-9]|\d\d)\D/.test(userAgent);
33
  var phantom = /PhantomJS/.test(userAgent);
34
 
35
+ var ios = safari && (/Mobile\/\w+/.test(userAgent) || navigator.maxTouchPoints > 2);
36
  var android = /Android/.test(userAgent);
37
  // This is woefully incomplete. Suggestions for alternative methods welcome.
38
  var mobile = ios || android || /webOS|BlackBerry|Opera Mini|Opera Mobi|IEMobile/i.test(userAgent);
173
  }
174
  }
175
 
176
+ var Delayed = function() {
177
+ this.id = null;
178
+ this.f = null;
179
+ this.time = 0;
180
+ this.handler = bind(this.onTimeout, this);
181
+ };
182
+ Delayed.prototype.onTimeout = function (self) {
183
+ self.id = 0;
184
+ if (self.time <= +new Date) {
185
+ self.f();
186
+ } else {
187
+ setTimeout(self.handler, self.time - +new Date);
188
+ }
189
+ };
190
  Delayed.prototype.set = function (ms, f) {
191
+ this.f = f;
192
+ var time = +new Date + ms;
193
+ if (!this.id || time < this.time) {
194
+ clearTimeout(this.id);
195
+ this.id = setTimeout(this.handler, ms);
196
+ this.time = time;
197
+ }
198
  };
199
 
200
  function indexOf(array, elt) {
204
  }
205
 
206
  // Number of pixels added to scroller and sizer to hide scrollbar
207
+ var scrollerGap = 50;
208
 
209
  // Returned or thrown by various protocols to signal 'I'm not
210
  // handling this'.
310
  }
311
  }
312
 
313
+ // BIDI HELPERS
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
314
 
315
+ function iterateBidiSections(order, from, to, f) {
316
+ if (!order) { return f(from, to, "ltr", 0) }
317
+ var found = false;
318
+ for (var i = 0; i < order.length; ++i) {
319
+ var part = order[i];
320
+ if (part.from < to && part.to > from || from == to && part.to == from) {
321
+ f(Math.max(part.from, from), Math.min(part.to, to), part.level == 1 ? "rtl" : "ltr", i);
322
+ found = true;
323
+ }
324
+ }
325
+ if (!found) { f(from, to, "ltr"); }
326
+ }
327
 
328
+ var bidiOther = null;
329
+ function getBidiPartAt(order, ch, sticky) {
330
+ var found;
331
+ bidiOther = null;
332
+ for (var i = 0; i < order.length; ++i) {
333
+ var cur = order[i];
334
+ if (cur.from < ch && cur.to > ch) { return i }
335
+ if (cur.to == ch) {
336
+ if (cur.from != cur.to && sticky == "before") { found = i; }
337
+ else { bidiOther = i; }
338
+ }
339
+ if (cur.from == ch) {
340
+ if (cur.from != cur.to && sticky != "before") { found = i; }
341
+ else { bidiOther = i; }
342
+ }
343
  }
344
+ return found != null ? found : bidiOther
345
+ }
346
 
347
+ // Bidirectional ordering algorithm
348
+ // See http://unicode.org/reports/tr9/tr9-13.html for the algorithm
349
+ // that this (partially) implements.
 
 
 
 
 
 
 
 
 
 
350
 
351
+ // One-char codes used for character types:
352
+ // L (L): Left-to-Right
353
+ // R (R): Right-to-Left
354
+ // r (AL): Right-to-Left Arabic
355
+ // 1 (EN): European Number
356
+ // + (ES): European Number Separator
357
+ // % (ET): European Number Terminator
358
+ // n (AN): Arabic Number
359
+ // , (CS): Common Number Separator
360
+ // m (NSM): Non-Spacing Mark
361
+ // b (BN): Boundary Neutral
362
+ // s (B): Paragraph Separator
363
+ // t (S): Segment Separator
364
+ // w (WS): Whitespace
365
+ // N (ON): Other Neutrals
366
 
367
+ // Returns null if characters are ordered as they appear
368
+ // (left-to-right), or an array of sections ({from, to, level}
369
+ // objects) in the order in which they occur visually.
370
+ var bidiOrdering = (function() {
371
+ // Character types for codepoints 0 to 0xff
372
+ var lowTypes = "bbbbbbbbbtstwsbbbbbbbbbbbbbbssstwNN%%%NNNNNN,N,N1111111111NNNNNNNLLLLLLLLLLLLLLLLLLLLLLLLLLNNNNNNLLLLLLLLLLLLLLLLLLLLLLLLLLNNNNbbbbbbsbbbbbbbbbbbbbbbbbbbbbbbbbb,N%%%%NNNNLNNNNN%%11NLNNN1LNNNNNLLLLLLLLLLLLLLLLLLLLLLLNLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLN";
373
+ // Character types for codepoints 0x600 to 0x6f9
374
+ var arabicTypes = "nnnnnnNNr%%r,rNNmmmmmmmmmmmrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrmmmmmmmmmmmmmmmmmmmmmnnnnnnnnnn%nnrrrmrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrmmmmmmmnNmmmmmmrrmmNmmmmrr1111111111";
375
+ function charType(code) {
376
+ if (code <= 0xf7) { return lowTypes.charAt(code) }
377
+ else if (0x590 <= code && code <= 0x5f4) { return "R" }
378
+ else if (0x600 <= code && code <= 0x6f9) { return arabicTypes.charAt(code - 0x600) }
379
+ else if (0x6ee <= code && code <= 0x8ac) { return "r" }
380
+ else if (0x2000 <= code && code <= 0x200b) { return "w" }
381
+ else if (code == 0x200c) { return "b" }
382
+ else { return "L" }
383
+ }
384
 
385
+ var bidiRE = /[\u0590-\u05f4\u0600-\u06ff\u0700-\u08ac]/;
386
+ var isNeutral = /[stwN]/, isStrong = /[LRr]/, countsAsLeft = /[Lb1n]/, countsAsNum = /[1n]/;
387
 
388
+ function BidiSpan(level, from, to) {
389
+ this.level = level;
390
+ this.from = from; this.to = to;
391
+ }
 
392
 
393
+ return function(str, direction) {
394
+ var outerType = direction == "ltr" ? "L" : "R";
395
 
396
+ if (str.length == 0 || direction == "ltr" && !bidiRE.test(str)) { return false }
397
+ var len = str.length, types = [];
398
+ for (var i = 0; i < len; ++i)
399
+ { types.push(charType(str.charCodeAt(i))); }
400
 
401
+ // W1. Examine each non-spacing mark (NSM) in the level run, and
402
+ // change the type of the NSM to the type of the previous
403
+ // character. If the NSM is at the start of the level run, it will
404
+ // get the type of sor.
405
+ for (var i$1 = 0, prev = outerType; i$1 < len; ++i$1) {
406
+ var type = types[i$1];
407
+ if (type == "m") { types[i$1] = prev; }
408
+ else { prev = type; }
409
+ }
410
 
411
+ // W2. Search backwards from each instance of a European number
412
+ // until the first strong type (R, L, AL, or sor) is found. If an
413
+ // AL is found, change the type of the European number to Arabic
414
+ // number.
415
+ // W3. Change all ALs to R.
416
+ for (var i$2 = 0, cur = outerType; i$2 < len; ++i$2) {
417
+ var type$1 = types[i$2];
418
+ if (type$1 == "1" && cur == "r") { types[i$2] = "n"; }
419
+ else if (isStrong.test(type$1)) { cur = type$1; if (type$1 == "r") { types[i$2] = "R"; } }
420
+ }
421
 
422
+ // W4. A single European separator between two European numbers
423
+ // changes to a European number. A single common separator between
424
+ // two numbers of the same type changes to that type.
425
+ for (var i$3 = 1, prev$1 = types[0]; i$3 < len - 1; ++i$3) {
426
+ var type$2 = types[i$3];
427
+ if (type$2 == "+" && prev$1 == "1" && types[i$3+1] == "1") { types[i$3] = "1"; }
428
+ else if (type$2 == "," && prev$1 == types[i$3+1] &&
429
+ (prev$1 == "1" || prev$1 == "n")) { types[i$3] = prev$1; }
430
+ prev$1 = type$2;
431
+ }
432
 
433
+ // W5. A sequence of European terminators adjacent to European
434
+ // numbers changes to all European numbers.
435
+ // W6. Otherwise, separators and terminators change to Other
436
+ // Neutral.
437
+ for (var i$4 = 0; i$4 < len; ++i$4) {
438
+ var type$3 = types[i$4];
439
+ if (type$3 == ",") { types[i$4] = "N"; }
440
+ else if (type$3 == "%") {
441
+ var end = (void 0);
442
+ for (end = i$4 + 1; end < len && types[end] == "%"; ++end) {}
443
+ var replace = (i$4 && types[i$4-1] == "!") || (end < len && types[end] == "1") ? "1" : "N";
444
+ for (var j = i$4; j < end; ++j) { types[j] = replace; }
445
+ i$4 = end - 1;
446
+ }
447
  }
 
 
 
448
 
449
+ // W7. Search backwards from each instance of a European number
450
+ // until the first strong type (R, L, or sor) is found. If an L is
451
+ // found, then change the type of the European number to L.
452
+ for (var i$5 = 0, cur$1 = outerType; i$5 < len; ++i$5) {
453
+ var type$4 = types[i$5];
454
+ if (cur$1 == "L" && type$4 == "1") { types[i$5] = "L"; }
455
+ else if (isStrong.test(type$4)) { cur$1 = type$4; }
456
+ }
 
 
 
 
 
 
 
 
 
 
 
457
 
458
+ // N1. A sequence of neutrals takes the direction of the
459
+ // surrounding strong text if the text on both sides has the same
460
+ // direction. European and Arabic numbers act as if they were R in
461
+ // terms of their influence on neutrals. Start-of-level-run (sor)
462
+ // and end-of-level-run (eor) are used at level run boundaries.
463
+ // N2. Any remaining neutrals take the embedding direction.
464
+ for (var i$6 = 0; i$6 < len; ++i$6) {
465
+ if (isNeutral.test(types[i$6])) {
466
+ var end$1 = (void 0);
467
+ for (end$1 = i$6 + 1; end$1 < len && isNeutral.test(types[end$1]); ++end$1) {}
468
+ var before = (i$6 ? types[i$6-1] : outerType) == "L";
469
+ var after = (end$1 < len ? types[end$1] : outerType) == "L";
470
+ var replace$1 = before == after ? (before ? "L" : "R") : outerType;
471
+ for (var j$1 = i$6; j$1 < end$1; ++j$1) { types[j$1] = replace$1; }
472
+ i$6 = end$1 - 1;
473
+ }
474
  }
 
 
 
475
 
476
+ // Here we depart from the documented algorithm, in order to avoid
477
+ // building up an actual levels array. Since there are only three
478
+ // levels (0, 1, 2) in an implementation that doesn't take
479
+ // explicit embedding into account, we can build up the order on
480
+ // the fly, without following the level-based algorithm.
481
+ var order = [], m;
482
+ for (var i$7 = 0; i$7 < len;) {
483
+ if (countsAsLeft.test(types[i$7])) {
484
+ var start = i$7;
485
+ for (++i$7; i$7 < len && countsAsLeft.test(types[i$7]); ++i$7) {}
486
+ order.push(new BidiSpan(0, start, i$7));
487
+ } else {
488
+ var pos = i$7, at = order.length, isRTL = direction == "rtl" ? 1 : 0;
489
+ for (++i$7; i$7 < len && types[i$7] != "L"; ++i$7) {}
490
+ for (var j$2 = pos; j$2 < i$7;) {
491
+ if (countsAsNum.test(types[j$2])) {
492
+ if (pos < j$2) { order.splice(at, 0, new BidiSpan(1, pos, j$2)); at += isRTL; }
493
+ var nstart = j$2;
494
+ for (++j$2; j$2 < i$7 && countsAsNum.test(types[j$2]); ++j$2) {}
495
+ order.splice(at, 0, new BidiSpan(2, nstart, j$2));
496
+ at += isRTL;
497
+ pos = j$2;
498
+ } else { ++j$2; }
499
+ }
500
+ if (pos < i$7) { order.splice(at, 0, new BidiSpan(1, pos, i$7)); }
501
+ }
502
+ }
503
+ if (direction == "ltr") {
504
+ if (order[0].level == 1 && (m = str.match(/^\s+/))) {
505
+ order[0].from = m[0].length;
506
+ order.unshift(new BidiSpan(0, 0, m[0].length));
507
+ }
508
+ if (lst(order).level == 1 && (m = str.match(/\s+$/))) {
509
+ lst(order).to -= m[0].length;
510
+ order.push(new BidiSpan(0, len - m[0].length, len));
511
+ }
512
  }
 
 
 
 
 
 
 
 
 
 
513
 
514
+ return direction == "rtl" ? order.reverse() : order
515
+ }
516
+ })();
517
 
518
+ // Get the bidi ordering for the given line (and cache it). Returns
519
+ // false for lines that are fully left-to-right, and an array of
520
+ // BidiSpan objects otherwise.
521
+ function getOrder(line, direction) {
522
+ var order = line.order;
523
+ if (order == null) { order = line.order = bidiOrdering(line.text, direction); }
524
+ return order
525
  }
526
 
527
+ // EVENT HANDLING
 
 
 
 
 
 
 
 
528
 
529
+ // Lightweight event framework. on/off also work on DOM nodes,
530
+ // registering native DOM handlers.
 
531
 
532
+ var noHandlers = [];
533
 
534
+ var on = function(emitter, type, f) {
535
+ if (emitter.addEventListener) {
536
+ emitter.addEventListener(type, f, false);
537
+ } else if (emitter.attachEvent) {
538
+ emitter.attachEvent("on" + type, f);
539
+ } else {
540
+ var map = emitter._handlers || (emitter._handlers = {});
541
+ map[type] = (map[type] || noHandlers).concat(f);
542
+ }
543
+ };
544
 
545
+ function getHandlers(emitter, type) {
546
+ return emitter._handlers && emitter._handlers[type] || noHandlers
 
 
 
 
 
 
 
 
 
 
 
 
547
  }
548
+
549
+ function off(emitter, type, f) {
550
+ if (emitter.removeEventListener) {
551
+ emitter.removeEventListener(type, f, false);
552
+ } else if (emitter.detachEvent) {
553
+ emitter.detachEvent("on" + type, f);
554
+ } else {
555
+ var map = emitter._handlers, arr = map && map[type];
556
+ if (arr) {
557
+ var index = indexOf(arr, f);
558
+ if (index > -1)
559
+ { map[type] = arr.slice(0, index).concat(arr.slice(index + 1)); }
560
+ }
561
+ }
562
  }
563
 
564
+ function signal(emitter, type /*, values...*/) {
565
+ var handlers = getHandlers(emitter, type);
566
+ if (!handlers.length) { return }
567
+ var args = Array.prototype.slice.call(arguments, 2);
568
+ for (var i = 0; i < handlers.length; ++i) { handlers[i].apply(null, args); }
569
+ }
570
 
571
+ // The DOM events that CodeMirror handles can be overridden by
572
+ // registering a (non-DOM) handler on the editor for the event name,
573
+ // and preventDefault-ing the event in that handler.
574
+ function signalDOMEvent(cm, e, override) {
575
+ if (typeof e == "string")
576
+ { e = {type: e, preventDefault: function() { this.defaultPrevented = true; }}; }
577
+ signal(cm, override || e.type, cm, e);
578
+ return e_defaultPrevented(e) || e.codemirrorIgnore
579
  }
580
 
581
+ function signalCursorActivity(cm) {
582
+ var arr = cm._handlers && cm._handlers.cursorActivity;
583
+ if (!arr) { return }
584
+ var set = cm.curOp.cursorActivityHandlers || (cm.curOp.cursorActivityHandlers = []);
585
+ for (var i = 0; i < arr.length; ++i) { if (indexOf(set, arr[i]) == -1)
586
+ { set.push(arr[i]); } }
587
  }
588
 
589
+ function hasHandler(emitter, type) {
590
+ return getHandlers(emitter, type).length > 0
591
+ }
592
 
593
+ // Add on and off methods to a constructor's prototype, to make
594
+ // registering events on such objects more convenient.
595
+ function eventMixin(ctor) {
596
+ ctor.prototype.on = function(type, f) {on(this, type, f);};
597
+ ctor.prototype.off = function(type, f) {off(this, type, f);};
598
  }
599
 
600
+ // Due to the fact that we still support jurassic IE versions, some
601
+ // compatibility wrappers are needed.
602
+
603
+ function e_preventDefault(e) {
604
+ if (e.preventDefault) { e.preventDefault(); }
605
+ else { e.returnValue = false; }
606
  }
607
+ function e_stopPropagation(e) {
608
+ if (e.stopPropagation) { e.stopPropagation(); }
609
+ else { e.cancelBubble = true; }
 
 
 
 
610
  }
611
+ function e_defaultPrevented(e) {
612
+ return e.defaultPrevented != null ? e.defaultPrevented : e.returnValue == false
 
 
613
  }
614
+ function e_stop(e) {e_preventDefault(e); e_stopPropagation(e);}
615
 
616
+ function e_target(e) {return e.target || e.srcElement}
617
+ function e_button(e) {
618
+ var b = e.which;
619
+ if (b == null) {
620
+ if (e.button & 1) { b = 1; }
621
+ else if (e.button & 2) { b = 3; }
622
+ else if (e.button & 4) { b = 2; }
623
+ }
624
+ if (mac && e.ctrlKey && b == 1) { b = 3; }
625
+ return b
 
 
 
 
 
626
  }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
627
 
628
+ // Detect drag-and-drop
629
+ var dragAndDrop = function() {
630
+ // There is *some* kind of drag-and-drop support in IE6-8, but I
631
+ // couldn't get it to work yet.
632
+ if (ie && ie_version < 9) { return false }
633
+ var div = elt('div');
634
+ return "draggable" in div || "dragDrop" in div
635
+ }();
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
636
 
637
+ var zwspSupported;
638
+ function zeroWidthElement(measure) {
639
+ if (zwspSupported == null) {
640
+ var test = elt("span", "\u200b");
641
+ removeChildrenAndAdd(measure, elt("span", [test, document.createTextNode("x")]));
642
+ if (measure.firstChild.offsetHeight != 0)
643
+ { zwspSupported = test.offsetWidth <= 1 && test.offsetHeight > 2 && !(ie && ie_version < 8); }
 
 
 
 
644
  }
645
+ var node = zwspSupported ? elt("span", "\u200b") :
646
+ elt("span", "\u00a0", null, "display: inline-block; width: 1px; margin-right: -1px");
647
+ node.setAttribute("cm-text", "");
648
+ return node
649
  }
650
 
651
+ // Feature-detect IE's crummy client rect reporting for bidi text
652
+ var badBidiRects;
653
+ function hasBadBidiRects(measure) {
654
+ if (badBidiRects != null) { return badBidiRects }
655
+ var txt = removeChildrenAndAdd(measure, document.createTextNode("A\u062eA"));
656
+ var r0 = range(txt, 0, 1).getBoundingClientRect();
657
+ var r1 = range(txt, 1, 2).getBoundingClientRect();
658
+ removeChildren(measure);
659
+ if (!r0 || r0.left == r0.right) { return false } // Safari returns null in some cases (#2780)
660
+ return badBidiRects = (r1.right - r0.right < 3)
661
  }
662
 
663
+ // See if "".split is the broken IE version, if so, provide an
664
+ // alternative way to split lines.
665
+ var splitLinesAuto = "\n\nb".split(/\n/).length != 3 ? function (string) {
666
+ var pos = 0, result = [], l = string.length;
667
+ while (pos <= l) {
668
+ var nl = string.indexOf("\n", pos);
669
+ if (nl == -1) { nl = string.length; }
670
+ var line = string.slice(pos, string.charAt(nl - 1) == "\r" ? nl - 1 : nl);
671
+ var rt = line.indexOf("\r");
672
+ if (rt != -1) {
673
+ result.push(line.slice(0, rt));
674
+ pos += rt + 1;
675
+ } else {
676
+ result.push(line);
677
+ pos = nl + 1;
 
 
 
 
 
 
 
 
 
678
  }
679
  }
680
+ return result
681
+ } : function (string) { return string.split(/\r\n?|\n/); };
682
 
683
+ var hasSelection = window.getSelection ? function (te) {
684
+ try { return te.selectionStart != te.selectionEnd }
685
+ catch(e) { return false }
686
+ } : function (te) {
687
+ var range;
688
+ try {range = te.ownerDocument.selection.createRange();}
689
+ catch(e) {}
690
+ if (!range || range.parentElement() != te) { return false }
691
+ return range.compareEndPoints("StartToEnd", range) != 0
692
+ };
 
 
 
 
693
 
694
+ var hasCopyEvent = (function () {
695
+ var e = elt("div");
696
+ if ("oncopy" in e) { return true }
697
+ e.setAttribute("oncopy", "return;");
698
+ return typeof e.oncopy == "function"
699
+ })();
700
 
701
+ var badZoomedRects = null;
702
+ function hasBadZoomedRects(measure) {
703
+ if (badZoomedRects != null) { return badZoomedRects }
704
+ var node = removeChildrenAndAdd(measure, elt("span", "x"));
705
+ var normal = node.getBoundingClientRect();
706
+ var fromRange = range(node, 0, 1).getBoundingClientRect();
707
+ return badZoomedRects = Math.abs(normal.left - fromRange.left) > 1
 
 
 
 
 
708
  }
709
 
710
+ // Known modes, by name and by MIME
711
+ var modes = {}, mimeModes = {};
 
 
 
 
 
 
 
 
 
 
 
 
712
 
713
+ // Extra arguments are stored as the mode's dependencies, which is
714
+ // used by (legacy) mechanisms like loadmode.js to automatically
715
+ // load a mode. (Preferred mechanism is the require/define calls.)
716
+ function defineMode(name, mode) {
717
+ if (arguments.length > 2)
718
+ { mode.dependencies = Array.prototype.slice.call(arguments, 2); }
719
+ modes[name] = mode;
 
720
  }
721
 
722
+ function defineMIME(mime, spec) {
723
+ mimeModes[mime] = spec;
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
724
  }
725
 
726
+ // Given a MIME type, a {name, ...options} config object, or a name
727
+ // string, return a mode config object.
728
+ function resolveMode(spec) {
729
+ if (typeof spec == "string" && mimeModes.hasOwnProperty(spec)) {
730
+ spec = mimeModes[spec];
731
+ } else if (spec && typeof spec.name == "string" && mimeModes.hasOwnProperty(spec.name)) {
732
+ var found = mimeModes[spec.name];
733
+ if (typeof found == "string") { found = {name: found}; }
734
+ spec = createObj(found, spec);
735
+ spec.name = found.name;
736
+ } else if (typeof spec == "string" && /^[\w\-]+\/[\w\-]+\+xml$/.test(spec)) {
737
+ return resolveMode("application/xml")
738
+ } else if (typeof spec == "string" && /^[\w\-]+\/[\w\-]+\+json$/.test(spec)) {
739
+ return resolveMode("application/json")
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
740
  }
741
+ if (typeof spec == "string") { return {name: spec} }
742
+ else { return spec || {name: "null"} }
743
  }
744
 
745
+ // Given a mode spec (anything that resolveMode accepts), find and
746
+ // initialize an actual mode object.
747
+ function getMode(options, spec) {
748
+ spec = resolveMode(spec);
749
+ var mfactory = modes[spec.name];
750
+ if (!mfactory) { return getMode(options, "text/plain") }
751
+ var modeObj = mfactory(options, spec);
752
+ if (modeExtensions.hasOwnProperty(spec.name)) {
753
+ var exts = modeExtensions[spec.name];
754
+ for (var prop in exts) {
755
+ if (!exts.hasOwnProperty(prop)) { continue }
756
+ if (modeObj.hasOwnProperty(prop)) { modeObj["_" + prop] = modeObj[prop]; }
757
+ modeObj[prop] = exts[prop];
 
 
758
  }
759
  }
760
+ modeObj.name = spec.name;
761
+ if (spec.helperType) { modeObj.helperType = spec.helperType; }
762
+ if (spec.modeProps) { for (var prop$1 in spec.modeProps)
763
+ { modeObj[prop$1] = spec.modeProps[prop$1]; } }
764
 
765
+ return modeObj
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
766
  }
767
 
768
+ // This can be used to attach properties to mode objects from
769
+ // outside the actual mode definition.
770
+ var modeExtensions = {};
771
+ function extendMode(mode, properties) {
772
+ var exts = modeExtensions.hasOwnProperty(mode) ? modeExtensions[mode] : (modeExtensions[mode] = {});
773
+ copyObj(properties, exts);
 
 
 
 
 
 
 
774
  }
775
 
776
+ function copyState(mode, state) {
777
+ if (state === true) { return state }
778
+ if (mode.copyState) { return mode.copyState(state) }
779
+ var nstate = {};
780
+ for (var n in state) {
781
+ var val = state[n];
782
+ if (val instanceof Array) { val = val.concat([]); }
783
+ nstate[n] = val;
 
 
 
784
  }
785
+ return nstate
786
  }
787
 
788
+ // Given a mode and a state (for that mode), find the inner mode and
789
+ // state at the position that the state refers to.
790
+ function innerMode(mode, state) {
791
+ var info;
792
+ while (mode.innerMode) {
793
+ info = mode.innerMode(state);
794
+ if (!info || info.mode == mode) { break }
795
+ state = info.state;
796
+ mode = info.mode;
 
 
 
 
 
 
797
  }
798
+ return info || {mode: mode, state: state}
799
  }
800
 
801
+ function startState(mode, a1, a2) {
802
+ return mode.startState ? mode.startState(a1, a2) : true
803
+ }
804
 
805
+ // STRING STREAM
 
 
 
 
 
 
 
 
 
 
 
 
 
 
806
 
807
+ // Fed to the mode parsers, provides helper functions to make
808
+ // parsers more succinct.
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
809
 
810
+ var StringStream = function(string, tabSize, lineOracle) {
811
+ this.pos = this.start = 0;
812
+ this.string = string;
813
+ this.tabSize = tabSize || 8;
814
+ this.lastColumnPos = this.lastColumnValue = 0;
815
+ this.lineStart = 0;
816
+ this.lineOracle = lineOracle;
817
+ };
818
 
819
+ StringStream.prototype.eol = function () {return this.pos >= this.string.length};
820
+ StringStream.prototype.sol = function () {return this.pos == this.lineStart};
821
+ StringStream.prototype.peek = function () {return this.string.charAt(this.pos) || undefined};
822
+ StringStream.prototype.next = function () {
823
+ if (this.pos < this.string.length)
824
+ { return this.string.charAt(this.pos++) }
825
+ };
826
+ StringStream.prototype.eat = function (match) {
827
+ var ch = this.string.charAt(this.pos);
828
+ var ok;
829
+ if (typeof match == "string") { ok = ch == match; }
830
+ else { ok = ch && (match.test ? match.test(ch) : match(ch)); }
831
+ if (ok) {++this.pos; return ch}
832
+ };
833
+ StringStream.prototype.eatWhile = function (match) {
834
+ var start = this.pos;
835
+ while (this.eat(match)){}
836
+ return this.pos > start
837
+ };
838
+ StringStream.prototype.eatSpace = function () {
839
+ var start = this.pos;
840
+ while (/[\s\u00a0]/.test(this.string.charAt(this.pos))) { ++this.pos; }
841
+ return this.pos > start
842
+ };
843
+ StringStream.prototype.skipToEnd = function () {this.pos = this.string.length;};
844
+ StringStream.prototype.skipTo = function (ch) {
845
+ var found = this.string.indexOf(ch, this.pos);
846
+ if (found > -1) {this.pos = found; return true}
847
+ };
848
+ StringStream.prototype.backUp = function (n) {this.pos -= n;};
849
+ StringStream.prototype.column = function () {
850
+ if (this.lastColumnPos < this.start) {
851
+ this.lastColumnValue = countColumn(this.string, this.start, this.tabSize, this.lastColumnPos, this.lastColumnValue);
852
+ this.lastColumnPos = this.start;
853
  }
854
+ return this.lastColumnValue - (this.lineStart ? countColumn(this.string, this.lineStart, this.tabSize) : 0)
855
+ };
856
+ StringStream.prototype.indentation = function () {
857
+ return countColumn(this.string, null, this.tabSize) -
858
+ (this.lineStart ? countColumn(this.string, this.lineStart, this.tabSize) : 0)
859
+ };
860
+ StringStream.prototype.match = function (pattern, consume, caseInsensitive) {
861
+ if (typeof pattern == "string") {
862
+ var cased = function (str) { return caseInsensitive ? str.toLowerCase() : str; };
863
+ var substr = this.string.substr(this.pos, pattern.length);
864
+ if (cased(substr) == cased(pattern)) {
865
+ if (consume !== false) { this.pos += pattern.length; }
866
+ return true
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
867
  }
868
+ } else {
869
+ var match = this.string.slice(this.pos).match(pattern);
870
+ if (match && match.index > 0) { return null }
871
+ if (match && consume !== false) { this.pos += match[0].length; }
872
+ return match
873
+ }
874
+ };
875
+ StringStream.prototype.current = function (){return this.string.slice(this.start, this.pos)};
876
+ StringStream.prototype.hideFirstChars = function (n, inner) {
877
+ this.lineStart += n;
878
+ try { return inner() }
879
+ finally { this.lineStart -= n; }
880
+ };
881
+ StringStream.prototype.lookAhead = function (n) {
882
+ var oracle = this.lineOracle;
883
+ return oracle && oracle.lookAhead(n)
884
+ };
885
+ StringStream.prototype.baseToken = function () {
886
+ var oracle = this.lineOracle;
887
+ return oracle && oracle.baseToken(this.pos)
888
+ };
889
 
890
+ // Find the line object corresponding to the given line number.
891
+ function getLine(doc, n) {
892
+ n -= doc.first;
893
+ if (n < 0 || n >= doc.size) { throw new Error("There is no line " + (n + doc.first) + " in the document.") }
894
+ var chunk = doc;
895
+ while (!chunk.lines) {
896
+ for (var i = 0;; ++i) {
897
+ var child = chunk.children[i], sz = child.chunkSize();
898
+ if (n < sz) { chunk = child; break }
899
+ n -= sz;
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
900
  }
 
 
901
  }
902
+ return chunk.lines[n]
 
 
 
 
 
 
 
 
903
  }
904
 
905
+ // Get the part of a document between two positions, as an array of
906
+ // strings.
907
+ function getBetween(doc, start, end) {
908
+ var out = [], n = start.line;
909
+ doc.iter(start.line, end.line + 1, function (line) {
910
+ var text = line.text;
911
+ if (n == end.line) { text = text.slice(0, end.ch); }
912
+ if (n == start.line) { text = text.slice(start.ch); }
913
+ out.push(text);
914
+ ++n;
915
+ });
916
+ return out
917
+ }
918
+ // Get the lines between from and to, as array of strings.
919
+ function getLines(doc, from, to) {
920
+ var out = [];
921
+ doc.iter(from, to, function (line) { out.push(line.text); }); // iter aborts when callback returns truthy value
922
+ return out
923
+ }
924
 
925
+ // Update the height of a line, propagating the height change
926
+ // upwards to parent nodes.
927
+ function updateLineHeight(line, height) {
928
+ var diff = height - line.height;
929
+ if (diff) { for (var n = line; n; n = n.parent) { n.height += diff; } }
930
+ }
931
 
932
+ // Given a line object, find its line number by walking up through
933
+ // its parent links.
934
+ function lineNo(line) {
935
+ if (line.parent == null) { return null }
936
+ var cur = line.parent, no = indexOf(cur.lines, line);
937
+ for (var chunk = cur.parent; chunk; cur = chunk, chunk = chunk.parent) {
938
+ for (var i = 0;; ++i) {
939
+ if (chunk.children[i] == cur) { break }
940
+ no += chunk.children[i].chunkSize();
941
+ }
942
  }
943
+ return no + cur.first
 
 
 
944
  }
945
 
946
+ // Find the line at the given vertical position, using the height
947
+ // information in the document tree.
948
+ function lineAtHeight(chunk, h) {
949
+ var n = chunk.first;
950
+ outer: do {
951
+ for (var i$1 = 0; i$1 < chunk.children.length; ++i$1) {
952
+ var child = chunk.children[i$1], ch = child.height;
953
+ if (h < ch) { chunk = child; continue outer }
954
+ h -= ch;
955
+ n += child.chunkSize();
 
956
  }
957
+ return n
958
+ } while (!chunk.lines)
959
+ var i = 0;
960
+ for (; i < chunk.lines.length; ++i) {
961
+ var line = chunk.lines[i], lh = line.height;
962
+ if (h < lh) { break }
963
+ h -= lh;
964
  }
965
+ return n + i
966
  }
967
 
968
+ function isLine(doc, l) {return l >= doc.first && l < doc.first + doc.size}
 
 
 
 
 
969
 
970
+ function lineNumberFor(options, i) {
971
+ return String(options.lineNumberFormatter(i + options.firstLineNumber))
 
 
 
 
 
 
972
  }
973
 
974
+ // A Pos instance represents a position within the text.
975
+ function Pos(line, ch, sticky) {
976
+ if ( sticky === void 0 ) sticky = null;
 
 
 
 
977
 
978
+ if (!(this instanceof Pos)) { return new Pos(line, ch, sticky) }
979
+ this.line = line;
980
+ this.ch = ch;
981
+ this.sticky = sticky;
982
  }
983
 
984
+ // Compare two positions, return 0 if they are the same, a negative
985
+ // number when a is less, and a positive number otherwise.
986
+ function cmp(a, b) { return a.line - b.line || a.ch - b.ch }
 
 
 
987
 
988
+ function equalCursorPos(a, b) { return a.sticky == b.sticky && cmp(a, b) == 0 }
 
989
 
990
+ function copyPos(x) {return Pos(x.line, x.ch)}
991
+ function maxPos(a, b) { return cmp(a, b) < 0 ? b : a }
992
+ function minPos(a, b) { return cmp(a, b) < 0 ? a : b }
993
+
994
+ // Most of the external API clips given positions to make sure they
995
+ // actually exist within the document.
996
+ function clipLine(doc, n) {return Math.max(doc.first, Math.min(n, doc.first + doc.size - 1))}
997
+ function clipPos(doc, pos) {
998
+ if (pos.line < doc.first) { return Pos(doc.first, 0) }
999
+ var last = doc.first + doc.size - 1;
1000
+ if (pos.line > last) { return Pos(last, getLine(doc, last).text.length) }
1001
+ return clipToLen(pos, getLine(doc, pos.line).text.length)
1002
  }
1003
+ function clipToLen(pos, linelen) {
1004
+ var ch = pos.ch;
1005
+ if (ch == null || ch > linelen) { return Pos(pos.line, linelen) }
1006
+ else if (ch < 0) { return Pos(pos.line, 0) }
1007
+ else { return pos }
1008
  }
1009
+ function clipPosArray(doc, array) {
1010
+ var out = [];
1011
+ for (var i = 0; i < array.length; i++) { out[i] = clipPos(doc, array[i]); }
1012
+ return out
1013
  }
 
1014
 
1015
+ var SavedContext = function(state, lookAhead) {
1016
+ this.state = state;
1017
+ this.lookAhead = lookAhead;
1018
+ };
 
 
 
 
 
 
 
1019
 
1020
+ var Context = function(doc, state, line, lookAhead) {
1021
+ this.state = state;
1022
+ this.doc = doc;
1023
+ this.line = line;
1024
+ this.maxLookAhead = lookAhead || 0;
1025
+ this.baseTokens = null;
1026
+ this.baseTokenPos = 1;
1027
+ };
1028
 
1029
+ Context.prototype.lookAhead = function (n) {
1030
+ var line = this.doc.getLine(this.line + n);
1031
+ if (line != null && n > this.maxLookAhead) { this.maxLookAhead = n; }
1032
+ return line
1033
+ };
 
 
 
 
 
 
 
 
1034
 
1035
+ Context.prototype.baseToken = function (n) {
1036
+ if (!this.baseTokens) { return null }
1037
+ while (this.baseTokens[this.baseTokenPos] <= n)
1038
+ { this.baseTokenPos += 2; }
1039
+ var type = this.baseTokens[this.baseTokenPos + 1];
1040
+ return {type: type && type.replace(/( |^)overlay .*/, ""),
1041
+ size: this.baseTokens[this.baseTokenPos] - n}
1042
+ };
 
 
 
1043
 
1044
+ Context.prototype.nextLine = function () {
1045
+ this.line++;
1046
+ if (this.maxLookAhead > 0) { this.maxLookAhead--; }
1047
+ };
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1048
 
1049
+ Context.fromSaved = function (doc, saved, line) {
1050
+ if (saved instanceof SavedContext)
1051
+ { return new Context(doc, copyState(doc.mode, saved.state), line, saved.lookAhead) }
1052
+ else
1053
+ { return new Context(doc, copyState(doc.mode, saved), line) }
 
 
 
 
1054
  };
1055
 
1056
+ Context.prototype.save = function (copy) {
1057
+ var state = copy !== false ? copyState(this.doc.mode, this.state) : this.state;
1058
+ return this.maxLookAhead > 0 ? new SavedContext(state, this.maxLookAhead) : state
1059
+ };
 
 
1060
 
 
 
 
 
 
 
 
 
1061
 
1062
+ // Compute a style array (an array starting with a mode generation
1063
+ // -- for invalidation -- followed by pairs of end positions and
1064
+ // style strings), which is used to highlight the tokens on the
1065
+ // line.
1066
+ function highlightLine(cm, line, context, forceToEnd) {
1067
+ // A styles array always starts with a number identifying the
1068
+ // mode/overlays that it is based on (for easy invalidation).
1069
+ var st = [cm.state.modeGen], lineClasses = {};
1070
+ // Compute the base array of styles
1071
+ runMode(cm, line.text, cm.doc.mode, context, function (end, style) { return st.push(end, style); },
1072
+ lineClasses, forceToEnd);
1073
+ var state = context.state;
1074
 
1075
+ // Run overlays, adjust style array.
1076
+ var loop = function ( o ) {
1077
+ context.baseTokens = st;
1078
+ var overlay = cm.state.overlays[o], i = 1, at = 0;
1079
+ context.state = true;
1080
+ runMode(cm, line.text, overlay.mode, context, function (end, style) {
1081
+ var start = i;
1082
+ // Ensure there's a token end at the current position, and that i points at it
1083
+ while (at < end) {
1084
+ var i_end = st[i];
1085
+ if (i_end > end)
1086
+ { st.splice(i, 1, end, st[i+1], i_end); }
1087
+ i += 2;
1088
+ at = Math.min(end, i_end);
1089
+ }
1090
+ if (!style) { return }
1091
+ if (overlay.opaque) {
1092
+ st.splice(start, i - start, end, "overlay " + style);
1093
+ i = start + 2;
1094
+ } else {
1095
+ for (; start < i; start += 2) {
1096
+ var cur = st[start+1];
1097
+ st[start+1] = (cur ? cur + " " : "") + "overlay " + style;
1098
+ }
1099
+ }
1100
+ }, lineClasses);
1101
+ context.state = state;
1102
+ context.baseTokens = null;
1103
+ context.baseTokenPos = 1;
1104
+ };
1105
 
1106
+ for (var o = 0; o < cm.state.overlays.length; ++o) loop( o );
 
 
1107
 
1108
+ return {styles: st, classes: lineClasses.bgClass || lineClasses.textClass ? lineClasses : null}
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1109
  }
1110
 
1111
+ function getLineStyles(cm, line, updateFrontier) {
1112
+ if (!line.styles || line.styles[0] != cm.state.modeGen) {
1113
+ var context = getContextBefore(cm, lineNo(line));
1114
+ var resetState = line.text.length > cm.options.maxHighlightLength && copyState(cm.doc.mode, context.state);
1115
+ var result = highlightLine(cm, line, context);
1116
+ if (resetState) { context.state = resetState; }
1117
+ line.stateAfter = context.save(!resetState);
1118
+ line.styles = result.styles;
1119
+ if (result.classes) { line.styleClasses = result.classes; }
1120
+ else if (line.styleClasses) { line.styleClasses = null; }
1121
+ if (updateFrontier === cm.doc.highlightFrontier)
1122
+ { cm.doc.modeFrontier = Math.max(cm.doc.modeFrontier, ++cm.doc.highlightFrontier); }
 
 
1123
  }
1124
+ return line.styles
 
 
 
 
 
1125
  }
1126
 
1127
+ function getContextBefore(cm, n, precise) {
1128
+ var doc = cm.doc, display = cm.display;
1129
+ if (!doc.mode.startState) { return new Context(doc, true, n) }
1130
+ var start = findStartLine(cm, n, precise);
1131
+ var saved = start > doc.first && getLine(doc, start - 1).stateAfter;
1132
+ var context = saved ? Context.fromSaved(doc, saved, start) : new Context(doc, startState(doc.mode), start);
1133
+
1134
+ doc.iter(start, n, function (line) {
1135
+ processLine(cm, line.text, context);
1136
+ var pos = context.line;
1137
+ line.stateAfter = pos == n - 1 || pos % 5 == 0 || pos >= display.viewFrom && pos < display.viewTo ? context.save() : null;
1138
+ context.nextLine();
1139
+ });
1140
+ if (precise) { doc.modeFrontier = context.line; }
1141
+ return context
1142
  }
1143
 
1144
+ // Lightweight form of highlight -- proceed over this line and
1145
+ // update state, but don't save a style array. Used for lines that
1146
+ // aren't currently visible.
1147
+ function processLine(cm, text, context, startAt) {
1148
+ var mode = cm.doc.mode;
1149
+ var stream = new StringStream(text, cm.options.tabSize, context);
1150
+ stream.start = stream.pos = startAt || 0;
1151
+ if (text == "") { callBlankLine(mode, context.state); }
1152
+ while (!stream.eol()) {
1153
+ readToken(mode, stream, context.state);
1154
+ stream.start = stream.pos;
1155
  }
 
1156
  }
1157
 
1158
+ function callBlankLine(mode, state) {
1159
+ if (mode.blankLine) { return mode.blankLine(state) }
1160
+ if (!mode.innerMode) { return }
1161
+ var inner = innerMode(mode, state);
1162
+ if (inner.mode.blankLine) { return inner.mode.blankLine(inner.state) }
 
 
 
 
 
 
1163
  }
1164
 
1165
+ function readToken(mode, stream, state, inner) {
1166
+ for (var i = 0; i < 10; i++) {
1167
+ if (inner) { inner[0] = innerMode(mode, state).mode; }
1168
+ var style = mode.token(stream, state);
1169
+ if (stream.pos > stream.start) { return style }
1170
+ }
1171
+ throw new Error("Mode " + mode.name + " failed to advance stream.")
1172
  }
1173
 
1174
+ var Token = function(stream, type, state) {
1175
+ this.start = stream.start; this.end = stream.pos;
1176
+ this.string = stream.current();
1177
+ this.type = type || null;
1178
+ this.state = state;
1179
+ };
1180
 
1181
+ // Utility for getTokenAt and getLineTokens
1182
+ function takeToken(cm, pos, precise, asArray) {
1183
+ var doc = cm.doc, mode = doc.mode, style;
1184
+ pos = clipPos(doc, pos);
1185
+ var line = getLine(doc, pos.line), context = getContextBefore(cm, pos.line, precise);
1186
+ var stream = new StringStream(line.text, cm.options.tabSize, context), tokens;
1187
+ if (asArray) { tokens = []; }
1188
+ while ((asArray || stream.pos < pos.ch) && !stream.eol()) {
1189
+ stream.start = stream.pos;
1190
+ style = readToken(mode, stream, context.state);
1191
+ if (asArray) { tokens.push(new Token(stream, style, copyState(doc.mode, context.state))); }
1192
+ }
1193
+ return asArray ? tokens : new Token(stream, style, context.state)
1194
+ }
1195
 
1196
+ function extractLineClasses(type, output) {
1197
+ if (type) { for (;;) {
1198
+ var lineClass = type.match(/(?:^|\s+)line-(background-)?(\S+)/);
1199
+ if (!lineClass) { break }
1200
+ type = type.slice(0, lineClass.index) + type.slice(lineClass.index + lineClass[0].length);
1201
+ var prop = lineClass[1] ? "bgClass" : "textClass";
1202
+ if (output[prop] == null)
1203
+ { output[prop] = lineClass[2]; }
1204
+ else if (!(new RegExp("(?:^|\\s)" + lineClass[2] + "(?:$|\\s)")).test(output[prop]))
1205
+ { output[prop] += " " + lineClass[2]; }
1206
+ } }
1207
+ return type
1208
+ }
1209
 
1210
+ // Run the given mode's parser over a line, calling f for each token.
1211
+ function runMode(cm, text, mode, context, f, lineClasses, forceToEnd) {
1212
+ var flattenSpans = mode.flattenSpans;
1213
+ if (flattenSpans == null) { flattenSpans = cm.options.flattenSpans; }
1214
+ var curStart = 0, curStyle = null;
1215
+ var stream = new StringStream(text, cm.options.tabSize, context), style;
1216
+ var inner = cm.options.addModeClass && [null];
1217
+ if (text == "") { extractLineClasses(callBlankLine(mode, context.state), lineClasses); }
1218
+ while (!stream.eol()) {
1219
+ if (stream.pos > cm.options.maxHighlightLength) {
1220
+ flattenSpans = false;
1221
+ if (forceToEnd) { processLine(cm, text, context, stream.pos); }
1222
+ stream.pos = text.length;
1223
+ style = null;
1224
+ } else {
1225
+ style = extractLineClasses(readToken(mode, stream, context.state, inner), lineClasses);
1226
+ }
1227
+ if (inner) {
1228
+ var mName = inner[0].name;
1229
+ if (mName) { style = "m-" + (style ? mName + " " + style : mName); }
1230
+ }
1231
+ if (!flattenSpans || curStyle != style) {
1232
+ while (curStart < stream.start) {
1233
+ curStart = Math.min(stream.start, curStart + 5000);
1234
+ f(curStart, curStyle);
1235
+ }
1236
+ curStyle = style;
1237
+ }
1238
+ stream.start = stream.pos;
1239
+ }
1240
+ while (curStart < stream.pos) {
1241
+ // Webkit seems to refuse to render text nodes longer than 57444
1242
+ // characters, and returns inaccurate measurements in nodes
1243
+ // starting around 5000 chars.
1244
+ var pos = Math.min(stream.pos, curStart + 5000);
1245
+ f(pos, curStyle);
1246
+ curStart = pos;
1247
+ }
1248
+ }
1249
 
1250
+ // Finds the line to start with when starting a parse. Tries to
1251
+ // find a line with a stateAfter, so that it can start with a
1252
+ // valid state. If that fails, it returns the line with the
1253
+ // smallest indentation, which tends to need the least context to
1254
+ // parse correctly.
1255
+ function findStartLine(cm, n, precise) {
1256
+ var minindent, minline, doc = cm.doc;
1257
+ var lim = precise ? -1 : n - (cm.doc.mode.innerMode ? 1000 : 100);
1258
+ for (var search = n; search > lim; --search) {
1259
+ if (search <= doc.first) { return doc.first }
1260
+ var line = getLine(doc, search - 1), after = line.stateAfter;
1261
+ if (after && (!precise || search + (after instanceof SavedContext ? after.lookAhead : 0) <= doc.modeFrontier))
1262
+ { return search }
1263
+ var indented = countColumn(line.text, null, cm.options.tabSize);
1264
+ if (minline == null || minindent > indented) {
1265
+ minline = search - 1;
1266
+ minindent = indented;
1267
+ }
1268
  }
1269
+ return minline
1270
+ }
1271
+
1272
+ function retreatFrontier(doc, n) {
1273
+ doc.modeFrontier = Math.min(doc.modeFrontier, n);
1274
+ if (doc.highlightFrontier < n - 10) { return }
1275
+ var start = doc.first;
1276
+ for (var line = n - 1; line > start; line--) {
1277
+ var saved = getLine(doc, line).stateAfter;
1278
+ // change is on 3
1279
+ // state on line 1 looked ahead 2 -- so saw 3
1280
+ // test 1 + 2 < 3 should cover this
1281
+ if (saved && (!(saved instanceof SavedContext) || line + saved.lookAhead < n)) {
1282
+ start = line + 1;
1283
+ break
1284
  }
 
 
 
 
 
1285
  }
1286
+ doc.highlightFrontier = Math.min(doc.highlightFrontier, start);
1287
+ }
 
 
 
 
 
 
 
 
 
 
 
 
 
1288
 
1289
+ // Optimize some code when these features are not used.
1290
+ var sawReadOnlySpans = false, sawCollapsedSpans = false;
 
 
1291
 
1292
+ function seeReadOnlySpans() {
1293
+ sawReadOnlySpans = true;
1294
+ }
 
 
 
 
 
1295
 
1296
+ function seeCollapsedSpans() {
1297
+ sawCollapsedSpans = true;
1298
+ }
 
 
1299
 
1300
+ // TEXTMARKER SPANS
 
1301
 
1302
+ function MarkedSpan(marker, from, to) {
1303
+ this.marker = marker;
1304
+ this.from = from; this.to = to;
1305
+ }
 
 
 
1306
 
1307
+ // Search an array of spans for a span matching the given marker.
1308
+ function getMarkedSpanFor(spans, marker) {
1309
+ if (spans) { for (var i = 0; i < spans.length; ++i) {
1310
+ var span = spans[i];
1311
+ if (span.marker == marker) { return span }
1312
+ } }
1313
+ }
1314
+ // Remove a span from an array, returning undefined if no spans are
1315
+ // left (we don't store arrays for lines without spans).
1316
+ function removeMarkedSpan(spans, span) {
1317
+ var r;
1318
+ for (var i = 0; i < spans.length; ++i)
1319
+ { if (spans[i] != span) { (r || (r = [])).push(spans[i]); } }
1320
+ return r
1321
+ }
1322
+ // Add a span to a line.
1323
+ function addMarkedSpan(line, span) {
1324
+ line.markedSpans = line.markedSpans ? line.markedSpans.concat([span]) : [span];
1325
+ span.marker.attachLine(line);
1326
+ }
1327
 
1328
+ // Used for the algorithm that adjusts markers for a change in the
1329
+ // document. These functions cut an array of spans at a given
1330
+ // character position, returning an array of remaining chunks (or
1331
+ // undefined if nothing remains).
1332
+ function markedSpansBefore(old, startCh, isInsert) {
1333
+ var nw;
1334
+ if (old) { for (var i = 0; i < old.length; ++i) {
1335
+ var span = old[i], marker = span.marker;
1336
+ var startsBefore = span.from == null || (marker.inclusiveLeft ? span.from <= startCh : span.from < startCh);
1337
+ if (startsBefore || span.from == startCh && marker.type == "bookmark" && (!isInsert || !span.marker.insertLeft)) {
1338
+ var endsAfter = span.to == null || (marker.inclusiveRight ? span.to >= startCh : span.to > startCh)
1339
+ ;(nw || (nw = [])).push(new MarkedSpan(marker, span.from, endsAfter ? null : span.to));
1340
+ }
1341
+ } }
1342
+ return nw
1343
+ }
1344
+ function markedSpansAfter(old, endCh, isInsert) {
1345
+ var nw;
1346
+ if (old) { for (var i = 0; i < old.length; ++i) {
1347
+ var span = old[i], marker = span.marker;
1348
+ var endsAfter = span.to == null || (marker.inclusiveRight ? span.to >= endCh : span.to > endCh);
1349
+ if (endsAfter || span.from == endCh && marker.type == "bookmark" && (!isInsert || span.marker.insertLeft)) {
1350
+ var startsBefore = span.from == null || (marker.inclusiveLeft ? span.from <= endCh : span.from < endCh)
1351
+ ;(nw || (nw = [])).push(new MarkedSpan(marker, startsBefore ? null : span.from - endCh,
1352
+ span.to == null ? null : span.to - endCh));
1353
+ }
1354
+ } }
1355
+ return nw
1356
+ }
1357
 
1358
+ // Given a change object, compute the new set of marker spans that
1359
+ // cover the line in which the change took place. Removes spans
1360
+ // entirely within the change, reconnects spans belonging to the
1361
+ // same marker that appear on both sides of the change, and cuts off
1362
+ // spans partially within the change. Returns an array of span
1363
+ // arrays with one element for each line in (after) the change.
1364
+ function stretchSpansOverChange(doc, change) {
1365
+ if (change.full) { return null }
1366
+ var oldFirst = isLine(doc, change.from.line) && getLine(doc, change.from.line).markedSpans;
1367
+ var oldLast = isLine(doc, change.to.line) && getLine(doc, change.to.line).markedSpans;
1368
+ if (!oldFirst && !oldLast) { return null }
1369
 
1370
+ var startCh = change.from.ch, endCh = change.to.ch, isInsert = cmp(change.from, change.to) == 0;
1371
+ // Get the spans that 'stick out' on both sides
1372
+ var first = markedSpansBefore(oldFirst, startCh, isInsert);
1373
+ var last = markedSpansAfter(oldLast, endCh, isInsert);
1374
 
1375
+ // Next, merge those two ends
1376
+ var sameLine = change.text.length == 1, offset = lst(change.text).length + (sameLine ? startCh : 0);
1377
+ if (first) {
1378
+ // Fix up .to properties of first
1379
+ for (var i = 0; i < first.length; ++i) {
1380
+ var span = first[i];
1381
+ if (span.to == null) {
1382
+ var found = getMarkedSpanFor(last, span.marker);
1383
+ if (!found) { span.to = startCh; }
1384
+ else if (sameLine) { span.to = found.to == null ? null : found.to + offset; }
1385
+ }
1386
+ }
1387
+ }
1388
+ if (last) {
1389
+ // Fix up .from in last (or move them into first in case of sameLine)
1390
+ for (var i$1 = 0; i$1 < last.length; ++i$1) {
1391
+ var span$1 = last[i$1];
1392
+ if (span$1.to != null) { span$1.to += offset; }
1393
+ if (span$1.from == null) {
1394
+ var found$1 = getMarkedSpanFor(first, span$1.marker);
1395
+ if (!found$1) {
1396
+ span$1.from = offset;
1397
+ if (sameLine) { (first || (first = [])).push(span$1); }
1398
+ }
1399
+ } else {
1400
+ span$1.from += offset;
1401
+ if (sameLine) { (first || (first = [])).push(span$1); }
1402
+ }
1403
+ }
1404
+ }
1405
+ // Make sure we didn't create any zero-length spans
1406
+ if (first) { first = clearEmptySpans(first); }
1407
+ if (last && last != first) { last = clearEmptySpans(last); }
1408
+
1409
+ var newMarkers = [first];
1410
+ if (!sameLine) {
1411
+ // Fill gap with whole-line-spans
1412
+ var gap = change.text.length - 2, gapMarkers;
1413
+ if (gap > 0 && first)
1414
+ { for (var i$2 = 0; i$2 < first.length; ++i$2)
1415
+ { if (first[i$2].to == null)
1416
+ { (gapMarkers || (gapMarkers = [])).push(new MarkedSpan(first[i$2].marker, null, null)); } } }
1417
+ for (var i$3 = 0; i$3 < gap; ++i$3)
1418
+ { newMarkers.push(gapMarkers); }
1419
+ newMarkers.push(last);
1420
+ }
1421
+ return newMarkers
1422
+ }
1423
+
1424
+ // Remove spans that are empty and don't have a clearWhenEmpty
1425
+ // option of false.
1426
+ function clearEmptySpans(spans) {
1427
+ for (var i = 0; i < spans.length; ++i) {
1428
+ var span = spans[i];
1429
+ if (span.from != null && span.from == span.to && span.marker.clearWhenEmpty !== false)
1430
+ { spans.splice(i--, 1); }
1431
+ }
1432
+ if (!spans.length) { return null }
1433
+ return spans
1434
+ }
1435
+
1436
+ // Used to 'clip' out readOnly ranges when making a change.
1437
+ function removeReadOnlyRanges(doc, from, to) {
1438
+ var markers = null;
1439
+ doc.iter(from.line, to.line + 1, function (line) {
1440
+ if (line.markedSpans) { for (var i = 0; i < line.markedSpans.length; ++i) {
1441
+ var mark = line.markedSpans[i].marker;
1442
+ if (mark.readOnly && (!markers || indexOf(markers, mark) == -1))
1443
+ { (markers || (markers = [])).push(mark); }
1444
+ } }
1445
+ });
1446
+ if (!markers) { return null }
1447
+ var parts = [{from: from, to: to}];
1448
+ for (var i = 0; i < markers.length; ++i) {
1449
+ var mk = markers[i], m = mk.find(0);
1450
+ for (var j = 0; j < parts.length; ++j) {
1451
+ var p = parts[j];
1452
+ if (cmp(p.to, m.from) < 0 || cmp(p.from, m.to) > 0) { continue }
1453
+ var newParts = [j, 1], dfrom = cmp(p.from, m.from), dto = cmp(p.to, m.to);
1454
+ if (dfrom < 0 || !mk.inclusiveLeft && !dfrom)
1455
+ { newParts.push({from: p.from, to: m.from}); }
1456
+ if (dto > 0 || !mk.inclusiveRight && !dto)
1457
+ { newParts.push({from: m.to, to: p.to}); }
1458
+ parts.splice.apply(parts, newParts);
1459
+ j += newParts.length - 3;
1460
+ }
1461
+ }
1462
+ return parts
1463
+ }
1464
 
1465
+ // Connect or disconnect spans from a line.
1466
+ function detachMarkedSpans(line) {
1467
+ var spans = line.markedSpans;
1468
+ if (!spans) { return }
1469
+ for (var i = 0; i < spans.length; ++i)
1470
+ { spans[i].marker.detachLine(line); }
1471
+ line.markedSpans = null;
1472
+ }
1473
+ function attachMarkedSpans(line, spans) {
1474
+ if (!spans) { return }
1475
+ for (var i = 0; i < spans.length; ++i)
1476
+ { spans[i].marker.attachLine(line); }
1477
+ line.markedSpans = spans;
1478
+ }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1479
 
1480
+ // Helpers used when computing which overlapping collapsed span
1481
+ // counts as the larger one.
1482
+ function extraLeft(marker) { return marker.inclusiveLeft ? -1 : 0 }
1483
+ function extraRight(marker) { return marker.inclusiveRight ? 1 : 0 }
1484
 
1485
+ // Returns a number indicating which of two overlapping collapsed
1486
+ // spans is larger (and thus includes the other). Falls back to
1487
+ // comparing ids when the spans cover exactly the same range.
1488
+ function compareCollapsedMarkers(a, b) {
1489
+ var lenDiff = a.lines.length - b.lines.length;
1490
+ if (lenDiff != 0) { return lenDiff }
1491
+ var aPos = a.find(), bPos = b.find();
1492
+ var fromCmp = cmp(aPos.from, bPos.from) || extraLeft(a) - extraLeft(b);
1493
+ if (fromCmp) { return -fromCmp }
1494
+ var toCmp = cmp(aPos.to, bPos.to) || extraRight(a) - extraRight(b);
1495
+ if (toCmp) { return toCmp }
1496
+ return b.id - a.id
1497
  }
1498
 
1499
+ // Find out whether a line ends or starts in a collapsed span. If
1500
+ // so, return the marker for that span.
1501
+ function collapsedSpanAtSide(line, start) {
1502
+ var sps = sawCollapsedSpans && line.markedSpans, found;
1503
+ if (sps) { for (var sp = (void 0), i = 0; i < sps.length; ++i) {
1504
+ sp = sps[i];
1505
+ if (sp.marker.collapsed && (start ? sp.from : sp.to) == null &&
1506
+ (!found || compareCollapsedMarkers(found, sp.marker) < 0))
1507
+ { found = sp.marker; }
1508
+ } }
1509
+ return found
 
 
 
1510
  }
1511
+ function collapsedSpanAtStart(line) { return collapsedSpanAtSide(line, true) }
1512
+ function collapsedSpanAtEnd(line) { return collapsedSpanAtSide(line, false) }
1513
 
1514
+ function collapsedSpanAround(line, ch) {
1515
+ var sps = sawCollapsedSpans && line.markedSpans, found;
1516
+ if (sps) { for (var i = 0; i < sps.length; ++i) {
1517
+ var sp = sps[i];
1518
+ if (sp.marker.collapsed && (sp.from == null || sp.from < ch) && (sp.to == null || sp.to > ch) &&
1519
+ (!found || compareCollapsedMarkers(found, sp.marker) < 0)) { found = sp.marker; }
1520
+ } }
1521
+ return found
1522
+ }
1523
 
1524
+ // Test whether there exists a collapsed span that partially
1525
+ // overlaps (covers the start or end, but not both) of a new span.
1526
+ // Such overlap is not allowed.
1527
+ function conflictingCollapsedRange(doc, lineNo, from, to, marker) {
1528
+ var line = getLine(doc, lineNo);
1529
+ var sps = sawCollapsedSpans && line.markedSpans;
1530
+ if (sps) { for (var i = 0; i < sps.length; ++i) {
1531
+ var sp = sps[i];
1532
+ if (!sp.marker.collapsed) { continue }
1533
+ var found = sp.marker.find(0);
1534
+ var fromCmp = cmp(found.from, from) || extraLeft(sp.marker) - extraLeft(marker);
1535
+ var toCmp = cmp(found.to, to) || extraRight(sp.marker) - extraRight(marker);
1536
+ if (fromCmp >= 0 && toCmp <= 0 || fromCmp <= 0 && toCmp >= 0) { continue }
1537
+ if (fromCmp <= 0 && (sp.marker.inclusiveRight && marker.inclusiveLeft ? cmp(found.to, from) >= 0 : cmp(found.to, from) > 0) ||
1538
+ fromCmp >= 0 && (sp.marker.inclusiveRight && marker.inclusiveLeft ? cmp(found.from, to) <= 0 : cmp(found.from, to) < 0))
1539
+ { return true }
1540
+ } }
1541
  }
1542
 
1543
+ // A visual line is a line as drawn on the screen. Folding, for
1544
+ // example, can cause multiple logical lines to appear on the same
1545
+ // visual line. This finds the start of the visual line that the
1546
+ // given line is part of (usually that is the line itself).
1547
+ function visualLine(line) {
1548
+ var merged;
1549
+ while (merged = collapsedSpanAtStart(line))
1550
+ { line = merged.find(-1, true).line; }
1551
+ return line
 
 
 
1552
  }
1553
 
1554
+ function visualLineEnd(line) {
1555
+ var merged;
1556
+ while (merged = collapsedSpanAtEnd(line))
1557
+ { line = merged.find(1, true).line; }
1558
+ return line
1559
  }
1560
 
1561
+ // Returns an array of logical lines that continue the visual line
1562
+ // started by the argument, or undefined if there are no such lines.
1563
+ function visualLineContinued(line) {
1564
+ var merged, lines;
1565
+ while (merged = collapsedSpanAtEnd(line)) {
1566
+ line = merged.find(1, true).line
1567
+ ;(lines || (lines = [])).push(line);
1568
  }
1569
+ return lines
1570
  }
1571
 
1572
+ // Get the line number of the start of the visual line that the
1573
+ // given line number is part of.
1574
+ function visualLineNo(doc, lineN) {
1575
+ var line = getLine(doc, lineN), vis = visualLine(line);
1576
+ if (line == vis) { return lineN }
1577
+ return lineNo(vis)
1578
+ }
1579
 
1580
+ // Get the line number of the start of the next visual line after
1581
+ // the given line.
1582
+ function visualLineEndNo(doc, lineN) {
1583
+ if (lineN > doc.lastLine()) { return lineN }
1584
+ var line = getLine(doc, lineN), merged;
1585
+ if (!lineIsHidden(doc, line)) { return lineN }
1586
+ while (merged = collapsedSpanAtEnd(line))
1587
+ { line = merged.find(1, true).line; }
1588
+ return lineNo(line) + 1
 
 
 
 
1589
  }
1590
 
1591
+ // Compute whether a line is hidden. Lines count as hidden when they
1592
+ // are part of a visual line that starts with another line, or when
1593
+ // they are entirely covered by collapsed, non-widget span.
1594
+ function lineIsHidden(doc, line) {
1595
+ var sps = sawCollapsedSpans && line.markedSpans;
1596
+ if (sps) { for (var sp = (void 0), i = 0; i < sps.length; ++i) {
1597
+ sp = sps[i];
1598
+ if (!sp.marker.collapsed) { continue }
1599
+ if (sp.from == null) { return true }
1600
+ if (sp.marker.widgetNode) { continue }
1601
+ if (sp.from == 0 && sp.marker.inclusiveLeft && lineIsHiddenInner(doc, line, sp))
1602
+ { return true }
1603
  } }
1604
+ }
1605
+ function lineIsHiddenInner(doc, line, span) {
1606
+ if (span.to == null) {
1607
+ var end = span.marker.find(1, true);
1608
+ return lineIsHiddenInner(doc, end.line, getMarkedSpanFor(end.line.markedSpans, span.marker))
1609
+ }
1610
+ if (span.marker.inclusiveRight && span.to == line.text.length)
1611
+ { return true }
1612
+ for (var sp = (void 0), i = 0; i < line.markedSpans.length; ++i) {
1613
+ sp = line.markedSpans[i];
1614
+ if (sp.marker.collapsed && !sp.marker.widgetNode && sp.from == span.to &&
1615
+ (sp.to == null || sp.to != span.from) &&
1616
+ (sp.marker.inclusiveLeft || span.marker.inclusiveRight) &&
1617
+ lineIsHiddenInner(doc, line, sp)) { return true }
1618
+ }
1619
  }
1620
 
1621
+ // Find the height above the given line.
1622
+ function heightAtLine(lineObj) {
1623
+ lineObj = visualLine(lineObj);
1624
+
1625
+ var h = 0, chunk = lineObj.parent;
1626
+ for (var i = 0; i < chunk.lines.length; ++i) {
1627
+ var line = chunk.lines[i];
1628
+ if (line == lineObj) { break }
1629
+ else { h += line.height; }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1630
  }
1631
+ for (var p = chunk.parent; p; chunk = p, p = chunk.parent) {
1632
+ for (var i$1 = 0; i$1 < p.children.length; ++i$1) {
1633
+ var cur = p.children[i$1];
1634
+ if (cur == chunk) { break }
1635
+ else { h += cur.height; }
1636
+ }
 
1637
  }
1638
+ return h
1639
  }
1640
 
1641
+ // Compute the character length of a line, taking into account
1642
+ // collapsed ranges (see markText) that might hide parts, and join
1643
+ // other lines onto it.
1644
+ function lineLength(line) {
1645
+ if (line.height == 0) { return 0 }
1646
+ var len = line.text.length, merged, cur = line;
1647
+ while (merged = collapsedSpanAtStart(cur)) {
1648
+ var found = merged.find(0, true);
1649
+ cur = found.from.line;
1650
+ len += found.from.ch - found.to.ch;
 
 
 
 
 
 
 
 
1651
  }
1652
+ cur = line;
1653
+ while (merged = collapsedSpanAtEnd(cur)) {
1654
+ var found$1 = merged.find(0, true);
1655
+ len -= cur.text.length - found$1.from.ch;
1656
+ cur = found$1.to.line;
1657
+ len += cur.text.length - found$1.to.ch;
1658
+ }
1659
+ return len
1660
  }
1661
 
1662
+ // Find the longest line in the document.
1663
+ function findMaxLine(cm) {
1664
+ var d = cm.display, doc = cm.doc;
1665
+ d.maxLine = getLine(doc, doc.first);
1666
+ d.maxLineLength = lineLength(d.maxLine);
1667
+ d.maxLineChanged = true;
1668
+ doc.iter(function (line) {
1669
+ var len = lineLength(line);
1670
+ if (len > d.maxLineLength) {
1671
+ d.maxLineLength = len;
1672
+ d.maxLine = line;
 
1673
  }
1674
+ });
 
1675
  }
1676
 
1677
  // LINE DATA STRUCTURE
1790
 
1791
  // Build up the DOM representation for a single token, and add it to
1792
  // the line map. Takes care to render special characters separately.
1793
+ function buildToken(builder, text, style, startStyle, endStyle, css, attributes) {
1794
  if (!text) { return }
1795
  var displayText = builder.splitSpaces ? splitSpaces(text, builder.trailingSpace) : text;
1796
  var special = builder.cm.state.specialChars, mustWrap = false;
1841
  }
1842
  }
1843
  builder.trailingSpace = displayText.charCodeAt(text.length - 1) == 32;
1844
+ if (style || startStyle || endStyle || mustWrap || css || attributes) {
1845
  var fullStyle = style || "";
1846
  if (startStyle) { fullStyle += startStyle; }
1847
  if (endStyle) { fullStyle += endStyle; }
1848
  var token = elt("span", [content], fullStyle, css);
1849
+ if (attributes) {
1850
+ for (var attr in attributes) { if (attributes.hasOwnProperty(attr) && attr != "style" && attr != "class")
1851
+ { token.setAttribute(attr, attributes[attr]); } }
1852
+ }
1853
  return builder.content.appendChild(token)
1854
  }
1855
  builder.content.appendChild(content);
1873
  // Work around nonsense dimensions being reported for stretches of
1874
  // right-to-left text.
1875
  function buildTokenBadBidi(inner, order) {
1876
+ return function (builder, text, style, startStyle, endStyle, css, attributes) {
1877
  style = style ? style + " cm-force-border" : "cm-force-border";
1878
  var start = builder.pos, end = start + text.length;
1879
  for (;;) {
1883
  part = order[i];
1884
  if (part.to > start && part.from <= start) { break }
1885
  }
1886
+ if (part.to >= end) { return inner(builder, text, style, startStyle, endStyle, css, attributes) }
1887
+ inner(builder, text.slice(0, part.to - start), style, startStyle, null, css, attributes);
1888
  startStyle = null;
1889
  text = text.slice(part.to - start);
1890
  start = part.to;
1919
  }
1920
 
1921
  var len = allText.length, pos = 0, i = 1, text = "", style, css;
1922
+ var nextChange = 0, spanStyle, spanEndStyle, spanStartStyle, collapsed, attributes;
1923
  for (;;) {
1924
  if (nextChange == pos) { // Update current marker set
1925
+ spanStyle = spanEndStyle = spanStartStyle = css = "";
1926
+ attributes = null;
1927
  collapsed = null; nextChange = Infinity;
1928
  var foundBookmarks = [], endStyles = (void 0);
1929
  for (var j = 0; j < spans.length; ++j) {
1939
  if (m.css) { css = (css ? css + ";" : "") + m.css; }
1940
  if (m.startStyle && sp.from == pos) { spanStartStyle += " " + m.startStyle; }
1941
  if (m.endStyle && sp.to == nextChange) { (endStyles || (endStyles = [])).push(m.endStyle, sp.to); }
1942
+ // support for the old title property
1943
+ // https://github.com/codemirror/CodeMirror/pull/5673
1944
+ if (m.title) { (attributes || (attributes = {})).title = m.title; }
1945
+ if (m.attributes) {
1946
+ for (var attr in m.attributes)
1947
+ { (attributes || (attributes = {}))[attr] = m.attributes[attr]; }
1948
+ }
1949
  if (m.collapsed && (!collapsed || compareCollapsedMarkers(collapsed.marker, m) < 0))
1950
  { collapsed = sp; }
1951
  } else if (sp.from > pos && nextChange > sp.from) {
1973
  if (!collapsed) {
1974
  var tokenText = end > upto ? text.slice(0, upto - pos) : text;
1975
  builder.addToken(builder, tokenText, style ? style + spanStyle : spanStyle,
1976
+ spanStartStyle, pos + tokenText.length == nextChange ? spanEndStyle : "", css, attributes);
1977
  }
1978
  if (end >= upto) {text = text.slice(upto - pos); pos = upto; break}
1979
  pos = end;
2195
  elt("div", lineNumberFor(cm.options, lineN),
2196
  "CodeMirror-linenumber CodeMirror-gutter-elt",
2197
  ("left: " + (dims.gutterLeft["CodeMirror-linenumbers"]) + "px; width: " + (cm.display.lineNumInnerWidth) + "px"))); }
2198
+ if (markers) { for (var k = 0; k < cm.display.gutterSpecs.length; ++k) {
2199
+ var id = cm.display.gutterSpecs[k].className, found = markers.hasOwnProperty(id) && markers[id];
2200
  if (found)
2201
  { gutterWrap.appendChild(elt("div", [found], "CodeMirror-gutter-elt",
2202
  ("left: " + (dims.gutterLeft[id]) + "px; width: " + (dims.gutterWidth[id]) + "px"))); }
2206
 
2207
  function updateLineWidgets(cm, lineView, dims) {
2208
  if (lineView.alignable) { lineView.alignable = null; }
2209
+ var isWidget = classTest("CodeMirror-linewidget");
2210
  for (var node = lineView.node.firstChild, next = (void 0); node; node = next) {
2211
  next = node.nextSibling;
2212
+ if (isWidget.test(node.className)) { lineView.node.removeChild(node); }
 
2213
  }
2214
  insertLineWidgets(cm, lineView, dims);
2215
  }
2239
  if (!line.widgets) { return }
2240
  var wrap = ensureLineWrapped(lineView);
2241
  for (var i = 0, ws = line.widgets; i < ws.length; ++i) {
2242
+ var widget = ws[i], node = elt("div", [widget.node], "CodeMirror-linewidget" + (widget.className ? " " + widget.className : ""));
2243
  if (!widget.handleMouseEvents) { node.setAttribute("cm-ignore-events", "true"); }
2244
  positionLineWidget(widget, node, lineView, dims);
2245
  cm.display.input.setUneditable(node);
2299
  function paddingVert(display) {return display.mover.offsetHeight - display.lineSpace.offsetHeight}
2300
  function paddingH(display) {
2301
  if (display.cachedPaddingH) { return display.cachedPaddingH }
2302
+ var e = removeChildrenAndAdd(display.measure, elt("pre", "x", "CodeMirror-line-like"));
2303
  var style = window.getComputedStyle ? window.getComputedStyle(e) : e.currentStyle;
2304
  var data = {left: parseInt(style.paddingLeft), right: parseInt(style.paddingRight)};
2305
  if (!isNaN(data.left) && !isNaN(data.right)) { display.cachedPaddingH = data; }
2427
 
2428
  var nullRect = {left: 0, right: 0, top: 0, bottom: 0};
2429
 
2430
+ function nodeAndOffsetInLineMap(map, ch, bias) {
2431
  var node, start, end, collapse, mStart, mEnd;
2432
  // First, search the line map for the text node corresponding to,
2433
  // or closest to, the target character.
2434
+ for (var i = 0; i < map.length; i += 3) {
2435
+ mStart = map[i];
2436
+ mEnd = map[i + 1];
2437
  if (ch < mStart) {
2438
  start = 0; end = 1;
2439
  collapse = "left";
2440
  } else if (ch < mEnd) {
2441
  start = ch - mStart;
2442
  end = start + 1;
2443
+ } else if (i == map.length - 3 || ch == mEnd && map[i + 3] > ch) {
2444
  end = mEnd - mStart;
2445
  start = end - 1;
2446
  if (ch >= mEnd) { collapse = "right"; }
2447
  }
2448
  if (start != null) {
2449
+ node = map[i + 2];
2450
  if (mStart == mEnd && bias == (node.insertLeft ? "left" : "right"))
2451
  { collapse = bias; }
2452
  if (bias == "left" && start == 0)
2453
+ { while (i && map[i - 2] == map[i - 3] && map[i - 1].insertLeft) {
2454
+ node = map[(i -= 3) + 2];
2455
  collapse = "left";
2456
  } }
2457
  if (bias == "right" && start == mEnd - mStart)
2458
+ { while (i < map.length - 3 && map[i + 3] == map[i + 4] && !map[i + 5].insertLeft) {
2459
+ node = map[(i += 3) + 2];
2460
  collapse = "right";
2461
  } }
2462
  break
2693
  function PosWithInfo(line, ch, sticky, outside, xRel) {
2694
  var pos = Pos(line, ch, sticky);
2695
  pos.xRel = xRel;
2696
+ if (outside) { pos.outside = outside; }
2697
  return pos
2698
  }
2699
 
2702
  function coordsChar(cm, x, y) {
2703
  var doc = cm.doc;
2704
  y += cm.display.viewOffset;
2705
+ if (y < 0) { return PosWithInfo(doc.first, 0, null, -1, -1) }
2706
  var lineN = lineAtHeight(doc, y), last = doc.first + doc.size - 1;
2707
  if (lineN > last)
2708
+ { return PosWithInfo(doc.first + doc.size - 1, getLine(doc, last).text.length, null, 1, 1) }
2709
  if (x < 0) { x = 0; }
2710
 
2711
  var lineObj = getLine(doc, lineN);
2712
  for (;;) {
2713
  var found = coordsCharInner(cm, lineObj, lineN, x, y);
2714
+ var collapsed = collapsedSpanAround(lineObj, found.ch + (found.xRel > 0 || found.outside > 0 ? 1 : 0));
2715
  if (!collapsed) { return found }
2716
  var rangeEnd = collapsed.find(1);
2717
  if (rangeEnd.line == lineN) { return rangeEnd }
2739
  return box.bottom <= y ? false : box.top > y ? true : (left ? box.left : box.right) > x
2740
  }
2741
 
2742
+ function coordsCharInner(cm, lineObj, lineNo, x, y) {
2743
  // Move y into line-local coordinate space
2744
  y -= heightAtLine(lineObj);
2745
  var preparedMeasure = prepareMeasureForLine(cm, lineObj);
2746
  // When directly calling `measureCharPrepared`, we have to adjust
2747
  // for the widgets at this line.
2748
+ var widgetHeight = widgetTopHeight(lineObj);
2749
  var begin = 0, end = lineObj.text.length, ltr = true;
2750
 
2751
  var order = getOrder(lineObj, cm.doc.direction);
2753
  // which bidi section the coordinates fall into.
2754
  if (order) {
2755
  var part = (cm.options.lineWrapping ? coordsBidiPartWrapped : coordsBidiPart)
2756
+ (cm, lineObj, lineNo, preparedMeasure, order, x, y);
2757
  ltr = part.level != 1;
2758
  // The awkward -1 offsets are needed because findFirst (called
2759
  // on these below) will treat its first bound as inclusive,
2769
  var chAround = null, boxAround = null;
2770
  var ch = findFirst(function (ch) {
2771
  var box = measureCharPrepared(cm, preparedMeasure, ch);
2772
+ box.top += widgetHeight; box.bottom += widgetHeight;
2773
  if (!boxIsAfter(box, x, y, false)) { return false }
2774
  if (box.top <= y && box.left <= x) {
2775
  chAround = ch;
2793
  // left of the character and compare it's vertical position to the
2794
  // coordinates
2795
  sticky = ch == 0 ? "after" : ch == lineObj.text.length ? "before" :
2796
+ (measureCharPrepared(cm, preparedMeasure, ch - (ltr ? 1 : 0)).bottom + widgetHeight <= y) == ltr ?
2797
  "after" : "before";
2798
  // Now get accurate coordinates for this place, in order to get a
2799
  // base X position
2800
+ var coords = cursorCoords(cm, Pos(lineNo, ch, sticky), "line", lineObj, preparedMeasure);
2801
  baseX = coords.left;
2802
+ outside = y < coords.top ? -1 : y >= coords.bottom ? 1 : 0;
2803
  }
2804
 
2805
  ch = skipExtendingChars(lineObj.text, ch, 1);
2806
+ return PosWithInfo(lineNo, ch, sticky, outside, x - baseX)
2807
  }
2808
 
2809
+ function coordsBidiPart(cm, lineObj, lineNo, preparedMeasure, order, x, y) {
2810
  // Bidi parts are sorted left-to-right, and in a non-line-wrapping
2811
  // situation, we can take this ordering to correspond to the visual
2812
  // ordering. This finds the first part whose end is after the given
2813
  // coordinates.
2814
  var index = findFirst(function (i) {
2815
  var part = order[i], ltr = part.level != 1;
2816
+ return boxIsAfter(cursorCoords(cm, Pos(lineNo, ltr ? part.to : part.from, ltr ? "before" : "after"),
2817
  "line", lineObj, preparedMeasure), x, y, true)
2818
  }, 0, order.length - 1);
2819
  var part = order[index];
2822
  // that start, move one part back.
2823
  if (index > 0) {
2824
  var ltr = part.level != 1;
2825
+ var start = cursorCoords(cm, Pos(lineNo, ltr ? part.from : part.to, ltr ? "after" : "before"),
2826
  "line", lineObj, preparedMeasure);
2827
  if (boxIsAfter(start, x, y, true) && start.top > y)
2828
  { part = order[index - 1]; }
2868
  function textHeight(display) {
2869
  if (display.cachedTextHeight != null) { return display.cachedTextHeight }
2870
  if (measureText == null) {
2871
+ measureText = elt("pre", null, "CodeMirror-line-like");
2872
  // Measure a bunch of lines, for browsers that compute
2873
  // fractional heights.
2874
  for (var i = 0; i < 49; ++i) {
2888
  function charWidth(display) {
2889
  if (display.cachedCharWidth != null) { return display.cachedCharWidth }
2890
  var anchor = elt("span", "xxxxxxxxxx");
2891
+ var pre = elt("pre", [anchor], "CodeMirror-line-like");
2892
  removeChildrenAndAdd(display.measure, pre);
2893
  var rect = anchor.getBoundingClientRect(), width = (rect.right - rect.left) / 10;
2894
  if (width > 2) { display.cachedCharWidth = width; }
2901
  var d = cm.display, left = {}, width = {};
2902
  var gutterLeft = d.gutters.clientLeft;
2903
  for (var n = d.gutters.firstChild, i = 0; n; n = n.nextSibling, ++i) {
2904
+ var id = cm.display.gutterSpecs[i].className;
2905
+ left[id] = n.offsetLeft + n.clientLeft + gutterLeft;
2906
+ width[id] = n.clientWidth;
2907
  }
2908
  return {fixedPos: compensateForHScroll(d),
2909
  gutterTotalWidth: d.gutters.offsetWidth,
2960
  var x, y, space = display.lineSpace.getBoundingClientRect();
2961
  // Fails unpredictably on IE[67] when mouse is dragged around quickly.
2962
  try { x = e.clientX - space.left; y = e.clientY - space.top; }
2963
+ catch (e$1) { return null }
2964
  var coords = coordsChar(cm, x, y), line;
2965
+ if (forRect && coords.xRel > 0 && (line = getLine(cm.doc, coords.line).text).length == coords.ch) {
2966
  var colDiff = countColumn(line, line.length, cm.options.tabSize) - line.length;
2967
  coords = Pos(coords.line, Math.max(0, Math.round((x - paddingH(cm.display).left) / charWidth(cm.display)) - colDiff));
2968
  }
2969
+ return coords
2970
+ }
2971
+
2972
+ // Find the view element corresponding to a given line. Return null
2973
+ // when the line isn't visible.
2974
+ function findViewIndex(cm, n) {
2975
+ if (n >= cm.display.viewTo) { return null }
2976
+ n -= cm.display.viewFrom;
2977
+ if (n < 0) { return null }
2978
+ var view = cm.display.view;
2979
+ for (var i = 0; i < view.length; i++) {
2980
+ n -= view[i].size;
2981
+ if (n < 0) { return i }
2982
+ }
2983
+ }
2984
+
2985
+ // Updates the display.view data structure for a given change to the
2986
+ // document. From and to are in pre-change coordinates. Lendiff is
2987
+ // the amount of lines added or subtracted by the change. This is
2988
+ // used for changes that span multiple lines, or change the way
2989
+ // lines are divided into visual lines. regLineChange (below)
2990
+ // registers single-line changes.
2991
+ function regChange(cm, from, to, lendiff) {
2992
+ if (from == null) { from = cm.doc.first; }
2993
+ if (to == null) { to = cm.doc.first + cm.doc.size; }
2994
+ if (!lendiff) { lendiff = 0; }
2995
+
2996
+ var display = cm.display;
2997
+ if (lendiff && to < display.viewTo &&
2998
+ (display.updateLineNumbers == null || display.updateLineNumbers > from))
2999
+ { display.updateLineNumbers = from; }
3000
+
3001
+ cm.curOp.viewChanged = true;
3002
+
3003
+ if (from >= display.viewTo) { // Change after
3004
+ if (sawCollapsedSpans && visualLineNo(cm.doc, from) < display.viewTo)
3005
+ { resetView(cm); }
3006
+ } else if (to <= display.viewFrom) { // Change before
3007
+ if (sawCollapsedSpans && visualLineEndNo(cm.doc, to + lendiff) > display.viewFrom) {
3008
+ resetView(cm);
3009
+ } else {
3010
+ display.viewFrom += lendiff;
3011
+ display.viewTo += lendiff;
3012
+ }
3013
+ } else if (from <= display.viewFrom && to >= display.viewTo) { // Full overlap
3014
+ resetView(cm);
3015
+ } else if (from <= display.viewFrom) { // Top overlap
3016
+ var cut = viewCuttingPoint(cm, to, to + lendiff, 1);
3017
+ if (cut) {
3018
+ display.view = display.view.slice(cut.index);
3019
+ display.viewFrom = cut.lineN;
3020
+ display.viewTo += lendiff;
3021
+ } else {
3022
+ resetView(cm);
3023
+ }
3024
+ } else if (to >= display.viewTo) { // Bottom overlap
3025
+ var cut$1 = viewCuttingPoint(cm, from, from, -1);
3026
+ if (cut$1) {
3027
+ display.view = display.view.slice(0, cut$1.index);
3028
+ display.viewTo = cut$1.lineN;
3029
+ } else {
3030
+ resetView(cm);
3031
+ }
3032
+ } else { // Gap in the middle
3033
+ var cutTop = viewCuttingPoint(cm, from, from, -1);
3034
+ var cutBot = viewCuttingPoint(cm, to, to + lendiff, 1);
3035
+ if (cutTop && cutBot) {
3036
+ display.view = display.view.slice(0, cutTop.index)
3037
+ .concat(buildViewArray(cm, cutTop.lineN, cutBot.lineN))
3038
+ .concat(display.view.slice(cutBot.index));
3039
+ display.viewTo += lendiff;
3040
+ } else {
3041
+ resetView(cm);
3042
+ }
3043
+ }
3044
+
3045
+ var ext = display.externalMeasured;
3046
+ if (ext) {
3047
+ if (to < ext.lineN)
3048
+ { ext.lineN += lendiff; }
3049
+ else if (from < ext.lineN + ext.size)
3050
+ { display.externalMeasured = null; }
3051
+ }
3052
+ }
3053
+
3054
+ // Register a change to a single line. Type must be one of "text",
3055
+ // "gutter", "class", "widget"
3056
+ function regLineChange(cm, line, type) {
3057
+ cm.curOp.viewChanged = true;
3058
+ var display = cm.display, ext = cm.display.externalMeasured;
3059
+ if (ext && line >= ext.lineN && line < ext.lineN + ext.size)
3060
+ { display.externalMeasured = null; }
3061
+
3062
+ if (line < display.viewFrom || line >= display.viewTo) { return }
3063
+ var lineView = display.view[findViewIndex(cm, line)];
3064
+ if (lineView.node == null) { return }
3065
+ var arr = lineView.changes || (lineView.changes = []);
3066
+ if (indexOf(arr, type) == -1) { arr.push(type); }
3067
+ }
3068
+
3069
+ // Clear the view.
3070
+ function resetView(cm) {
3071
+ cm.display.viewFrom = cm.display.viewTo = cm.doc.first;
3072
+ cm.display.view = [];
3073
+ cm.display.viewOffset = 0;
3074
+ }
3075
+
3076
+ function viewCuttingPoint(cm, oldN, newN, dir) {
3077
+ var index = findViewIndex(cm, oldN), diff, view = cm.display.view;
3078
+ if (!sawCollapsedSpans || newN == cm.doc.first + cm.doc.size)
3079
+ { return {index: index, lineN: newN} }
3080
+ var n = cm.display.viewFrom;
3081
+ for (var i = 0; i < index; i++)
3082
+ { n += view[i].size; }
3083
+ if (n != oldN) {
3084
+ if (dir > 0) {
3085
+ if (index == view.length - 1) { return null }
3086
+ diff = (n + view[index].size) - oldN;
3087
+ index++;
3088
+ } else {
3089
+ diff = n - oldN;
3090
+ }
3091
+ oldN += diff; newN += diff;
3092
+ }
3093
+ while (visualLineNo(cm.doc, newN) != newN) {
3094
+ if (index == (dir < 0 ? 0 : view.length - 1)) { return null }
3095
+ newN += dir * view[index - (dir < 0 ? 1 : 0)].size;
3096
+ index += dir;
3097
+ }
3098
+ return {index: index, lineN: newN}
3099
+ }
3100
+
3101
+ // Force the view to cover a given range, adding empty view element
3102
+ // or clipping off existing ones as needed.
3103
+ function adjustView(cm, from, to) {
3104
+ var display = cm.display, view = display.view;
3105
+ if (view.length == 0 || from >= display.viewTo || to <= display.viewFrom) {
3106
+ display.view = buildViewArray(cm, from, to);
3107
+ display.viewFrom = from;
3108
+ } else {
3109
+ if (display.viewFrom > from)
3110
+ { display.view = buildViewArray(cm, from, display.viewFrom).concat(display.view); }
3111
+ else if (display.viewFrom < from)
3112
+ { display.view = display.view.slice(findViewIndex(cm, from)); }
3113
+ display.viewFrom = from;
3114
+ if (display.viewTo < to)
3115
+ { display.view = display.view.concat(buildViewArray(cm, display.viewTo, to)); }
3116
+ else if (display.viewTo > to)
3117
+ { display.view = display.view.slice(0, findViewIndex(cm, to)); }
3118
+ }
3119
+ display.viewTo = to;
3120
  }
3121
 
3122
+ // Count the number of lines in the view whose DOM representation is
3123
+ // out of date (or nonexistent).
3124
+ function countDirtyView(cm) {
3125
+ var view = cm.display.view, dirty = 0;
 
 
 
3126
  for (var i = 0; i < view.length; i++) {
3127
+ var lineView = view[i];
3128
+ if (!lineView.hidden && (!lineView.node || lineView.changes)) { ++dirty; }
3129
  }
3130
+ return dirty
3131
  }
3132
 
3133
  function updateSelection(cm) {
3143
 
3144
  for (var i = 0; i < doc.sel.ranges.length; i++) {
3145
  if (!primary && i == doc.sel.primIndex) { continue }
3146
+ var range = doc.sel.ranges[i];
3147
+ if (range.from().line >= cm.display.viewTo || range.to().line < cm.display.viewFrom) { continue }
3148
+ var collapsed = range.empty();
3149
  if (collapsed || cm.options.showCursorWhenSelecting)
3150
+ { drawSelectionCursor(cm, range.head, curFragment); }
3151
  if (!collapsed)
3152
+ { drawSelectionRange(cm, range, selFragment); }
3153
  }
3154
  return result
3155
  }
3176
  function cmpCoords(a, b) { return a.top - b.top || a.left - b.left }
3177
 
3178
  // Draws the given range as a highlighted selection
3179
+ function drawSelectionRange(cm, range, output) {
3180
  var display = cm.display, doc = cm.doc;
3181
  var fragment = document.createDocumentFragment();
3182
  var padding = paddingH(cm.display), leftSide = padding.left;
3245
  return {start: start, end: end}
3246
  }
3247
 
3248
+ var sFrom = range.from(), sTo = range.to();
3249
  if (sFrom.line == sTo.line) {
3250
  drawForLine(sFrom.line, sFrom.ch, sTo.ch);
3251
  } else {
3276
  var on = true;
3277
  display.cursorDiv.style.visibility = "";
3278
  if (cm.options.cursorBlinkRate > 0)
3279
+ { display.blinker = setInterval(function () {
3280
+ if (!cm.hasFocus()) { onBlur(cm); }
3281
+ display.cursorDiv.style.visibility = (on = !on) ? "" : "hidden";
3282
+ }, cm.options.cursorBlinkRate); }
3283
  else if (cm.options.cursorBlinkRate < 0)
3284
  { display.cursorDiv.style.visibility = "hidden"; }
3285
  }
3286
 
3287
  function ensureFocus(cm) {
3288
+ if (!cm.hasFocus()) {
3289
+ cm.display.input.focus();
3290
+ if (!cm.state.focused) { onFocus(cm); }
3291
+ }
3292
  }
3293
 
3294
  function delayBlurEvent(cm) {
3295
  cm.state.delayingBlurEvent = true;
3296
  setTimeout(function () { if (cm.state.delayingBlurEvent) {
3297
  cm.state.delayingBlurEvent = false;
3298
+ if (cm.state.focused) { onBlur(cm); }
3299
  } }, 100);
3300
  }
3301
 
3302
  function onFocus(cm, e) {
3303
+ if (cm.state.delayingBlurEvent && !cm.state.draggingText) { cm.state.delayingBlurEvent = false; }
3304
 
3305
  if (cm.options.readOnly == "nocursor") { return }
3306
  if (!cm.state.focused) {
3336
  var display = cm.display;
3337
  var prevBottom = display.lineDiv.offsetTop;
3338
  for (var i = 0; i < display.view.length; i++) {
3339
+ var cur = display.view[i], wrapping = cm.options.lineWrapping;
3340
+ var height = (void 0), width = 0;
3341
  if (cur.hidden) { continue }
3342
  if (ie && ie_version < 8) {
3343
  var bot = cur.node.offsetTop + cur.node.offsetHeight;
3346
  } else {
3347
  var box = cur.node.getBoundingClientRect();
3348
  height = box.bottom - box.top;
3349
+ // Check that lines don't extend past the right of the current
3350
+ // editor width
3351
+ if (!wrapping && cur.text.firstChild)
3352
+ { width = cur.text.firstChild.getBoundingClientRect().right - box.left - 1; }
3353
  }
3354
  var diff = cur.line.height - height;
 
3355
  if (diff > .005 || diff < -.005) {
3356
  updateLineHeight(cur.line, height);
3357
  updateWidgetHeight(cur.line);
3358
  if (cur.rest) { for (var j = 0; j < cur.rest.length; j++)
3359
  { updateWidgetHeight(cur.rest[j]); } }
3360
  }
3361
+ if (width > cm.display.sizerWidth) {
3362
+ var chWidth = Math.ceil(width / charWidth(cm.display));
3363
+ if (chWidth > cm.display.maxLineLength) {
3364
+ cm.display.maxLineLength = chWidth;
3365
+ cm.display.maxLine = cur.line;
3366
+ cm.display.maxLineChanged = true;
3367
+ }
3368
+ }
3369
  }
3370
  }
3371
 
3402
  return {from: from, to: Math.max(to, from + 1)}
3403
  }
3404
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
3405
  // SCROLLING THINGS INTO VIEW
3406
 
3407
  // If an editor sits on the top or bottom of the window, partially
3482
  if (newTop != screentop) { result.scrollTop = newTop; }
3483
  }
3484
 
3485
+ var gutterSpace = cm.options.fixedGutter ? 0 : display.gutters.offsetWidth;
3486
+ var screenleft = cm.curOp && cm.curOp.scrollLeft != null ? cm.curOp.scrollLeft : display.scroller.scrollLeft - gutterSpace;
3487
+ var screenw = displayWidth(cm) - display.gutters.offsetWidth;
3488
  var tooWide = rect.right - rect.left > screenw;
3489
  if (tooWide) { rect.right = rect.left + screenw; }
3490
  if (rect.left < 10)
3491
  { result.scrollLeft = 0; }
3492
  else if (rect.left < screenleft)
3493
+ { result.scrollLeft = Math.max(0, rect.left + gutterSpace - (tooWide ? 0 : 10)); }
3494
  else if (rect.right > screenw + screenleft - 3)
3495
  { result.scrollLeft = rect.right + (tooWide ? 0 : 10) - screenw; }
3496
  return result
3518
  if (y != null) { cm.curOp.scrollTop = y; }
3519
  }
3520
 
3521
+ function scrollToRange(cm, range) {
3522
  resolveScrollToPos(cm);
3523
+ cm.curOp.scrollToPos = range;
3524
  }
3525
 
3526
  // When an operation has its scrollToPos property set, and another
3528
  // 'simulates' scrolling that position into view in a cheap way, so
3529
  // that the effect of intermediate scroll commands is not ignored.
3530
  function resolveScrollToPos(cm) {
3531
+ var range = cm.curOp.scrollToPos;
3532
+ if (range) {
3533
  cm.curOp.scrollToPos = null;
3534
+ var from = estimateCoords(cm, range.from), to = estimateCoords(cm, range.to);
3535
+ scrollToCoordsRange(cm, from, to, range.margin);
3536
  }
3537
  }
3538
 
3557
  }
3558
 
3559
  function setScrollTop(cm, val, forceScroll) {
3560
+ val = Math.max(0, Math.min(cm.display.scroller.scrollHeight - cm.display.scroller.clientHeight, val));
3561
  if (cm.display.scroller.scrollTop == val && !forceScroll) { return }
3562
  cm.doc.scrollTop = val;
3563
  cm.display.scrollbars.setScrollTop(val);
3567
  // Sync scroller and scrollbar, ensure the gutter elements are
3568
  // aligned.
3569
  function setScrollLeft(cm, val, isScroller, forceScroll) {
3570
+ val = Math.max(0, Math.min(val, cm.display.scroller.scrollWidth - cm.display.scroller.clientWidth));
3571
  if ((isScroller ? val == cm.doc.scrollLeft : Math.abs(cm.doc.scrollLeft - val) < 2) && !forceScroll) { return }
3572
  cm.doc.scrollLeft = val;
3573
  alignHorizontally(cm);
3679
  // (when the bar is hidden). If it is still visible, we keep
3680
  // it enabled, if it's hidden, we disable pointer events.
3681
  var box = bar.getBoundingClientRect();
3682
+ var elt = type == "vert" ? document.elementFromPoint(box.right - 1, (box.top + box.bottom) / 2)
3683
  : document.elementFromPoint((box.right + box.left) / 2, box.bottom - 1);
3684
+ if (elt != bar) { bar.style.pointerEvents = "none"; }
3685
  else { delay.set(1000, maybeDisable); }
3686
  }
3687
  delay.set(1000, maybeDisable);
3772
  viewChanged: false, // Flag that indicates that lines might need to be redrawn
3773
  startHeight: cm.doc.height, // Used to detect need to update scrollbar
3774
  forceUpdate: false, // Used to force a redraw
3775
+ updateInput: 0, // Whether to reset the input textarea
3776
  typing: false, // Whether this reset should be careful to leave existing text (for compositing)
3777
  changeObjs: null, // Accumulated changes, for firing change events
3778
  cursorActivityHandlers: null, // Set of handlers to fire cursorActivity on
3950
  }
3951
  }
3952
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
3953
  // HIGHLIGHT WORKER
3954
 
3955
  function startWorker(cm, time) {
4021
  { this.events.push(arguments); }
4022
  };
4023
  DisplayUpdate.prototype.finish = function () {
 
 
4024
  for (var i = 0; i < this.events.length; i++)
4025
+ { signal.apply(null, this.events[i]); }
4026
  };
4027
 
4028
  function maybeClipScrollbars(cm) {
4056
  function restoreSelection(snapshot) {
4057
  if (!snapshot || !snapshot.activeElt || snapshot.activeElt == activeElt()) { return }
4058
  snapshot.activeElt.focus();
4059
+ if (!/^(INPUT|TEXTAREA)$/.test(snapshot.activeElt.nodeName) &&
4060
+ snapshot.anchorNode && contains(document.body, snapshot.anchorNode) && contains(document.body, snapshot.focusNode)) {
4061
+ var sel = window.getSelection(), range = document.createRange();
4062
+ range.setEnd(snapshot.anchorNode, snapshot.anchorOffset);
4063
+ range.collapse(false);
4064
  sel.removeAllRanges();
4065
+ sel.addRange(range);
4066
  sel.extend(snapshot.focusNode, snapshot.focusOffset);
4067
  }
4068
  }
4155
  update.visible = visibleLines(cm.display, cm.doc, viewport);
4156
  if (update.visible.from >= cm.display.viewFrom && update.visible.to <= cm.display.viewTo)
4157
  { break }
4158
+ } else if (first) {
4159
+ update.visible = visibleLines(cm.display, cm.doc, viewport);
4160
  }
4161
  if (!updateDisplayIfNeeded(cm, update)) { break }
4162
  updateHeightsInViewport(cm);
4232
  while (cur) { cur = rm(cur); }
4233
  }
4234
 
4235
+ function updateGutterSpace(display) {
4236
+ var width = display.gutters.offsetWidth;
4237
+ display.sizer.style.marginLeft = width + "px";
4238
+ }
4239
+
4240
+ function setDocumentHeight(cm, measure) {
4241
+ cm.display.sizer.style.minHeight = measure.docHeight + "px";
4242
+ cm.display.heightForcer.style.top = measure.docHeight + "px";
4243
+ cm.display.gutters.style.height = (measure.docHeight + cm.display.barHeight + scrollGap(cm)) + "px";
4244
+ }
4245
+
4246
+ // Re-align line numbers and gutter marks to compensate for
4247
+ // horizontal scrolling.
4248
+ function alignHorizontally(cm) {
4249
+ var display = cm.display, view = display.view;
4250
+ if (!display.alignWidgets && (!display.gutters.firstChild || !cm.options.fixedGutter)) { return }
4251
+ var comp = compensateForHScroll(display) - display.scroller.scrollLeft + cm.doc.scrollLeft;
4252
+ var gutterW = display.gutters.offsetWidth, left = comp + "px";
4253
+ for (var i = 0; i < view.length; i++) { if (!view[i].hidden) {
4254
+ if (cm.options.fixedGutter) {
4255
+ if (view[i].gutter)
4256
+ { view[i].gutter.style.left = left; }
4257
+ if (view[i].gutterBackground)
4258
+ { view[i].gutterBackground.style.left = left; }
4259
+ }
4260
+ var align = view[i].alignable;
4261
+ if (align) { for (var j = 0; j < align.length; j++)
4262
+ { align[j].style.left = left; } }
4263
+ } }
4264
+ if (cm.options.fixedGutter)
4265
+ { display.gutters.style.left = (comp + gutterW) + "px"; }
4266
+ }
4267
+
4268
+ // Used to ensure that the line number gutter is still the right
4269
+ // size for the current document size. Returns true when an update
4270
+ // is needed.
4271
+ function maybeUpdateLineNumberWidth(cm) {
4272
+ if (!cm.options.lineNumbers) { return false }
4273
+ var doc = cm.doc, last = lineNumberFor(cm.options, doc.first + doc.size - 1), display = cm.display;
4274
+ if (last.length != display.lineNumChars) {
4275
+ var test = display.measure.appendChild(elt("div", [elt("div", last)],
4276
+ "CodeMirror-linenumber CodeMirror-gutter-elt"));
4277
+ var innerW = test.firstChild.offsetWidth, padding = test.offsetWidth - innerW;
4278
+ display.lineGutter.style.width = "";
4279
+ display.lineNumInnerWidth = Math.max(innerW, display.lineGutter.offsetWidth - padding) + 1;
4280
+ display.lineNumWidth = display.lineNumInnerWidth + padding;
4281
+ display.lineNumChars = display.lineNumInnerWidth ? last.length : -1;
4282
+ display.lineGutter.style.width = display.lineNumWidth + "px";
4283
+ updateGutterSpace(cm.display);
4284
+ return true
4285
+ }
4286
+ return false
4287
  }
4288
 
4289
+ function getGutters(gutters, lineNumbers) {
4290
+ var result = [], sawLineNumbers = false;
4291
+ for (var i = 0; i < gutters.length; i++) {
4292
+ var name = gutters[i], style = null;
4293
+ if (typeof name != "string") { style = name.style; name = name.className; }
4294
+ if (name == "CodeMirror-linenumbers") {
4295
+ if (!lineNumbers) { continue }
4296
+ else { sawLineNumbers = true; }
4297
+ }
4298
+ result.push({className: name, style: style});
4299
+ }
4300
+ if (lineNumbers && !sawLineNumbers) { result.push({className: "CodeMirror-linenumbers", style: null}); }
4301
+ return result
4302
  }
4303
 
4304
  // Rebuild the gutter elements, ensure the margin to the left of the
4305
  // code matches their width.
4306
+ function renderGutters(display) {
4307
+ var gutters = display.gutters, specs = display.gutterSpecs;
4308
  removeChildren(gutters);
4309
+ display.lineGutter = null;
4310
+ for (var i = 0; i < specs.length; ++i) {
4311
+ var ref = specs[i];
4312
+ var className = ref.className;
4313
+ var style = ref.style;
4314
+ var gElt = gutters.appendChild(elt("div", null, "CodeMirror-gutter " + className));
4315
+ if (style) { gElt.style.cssText = style; }
4316
+ if (className == "CodeMirror-linenumbers") {
4317
+ display.lineGutter = gElt;
4318
+ gElt.style.width = (display.lineNumWidth || 1) + "px";
4319
  }
4320
  }
4321
+ gutters.style.display = specs.length ? "" : "none";
4322
+ updateGutterSpace(display);
4323
+ }
4324
+
4325
+ function updateGutters(cm) {
4326
+ renderGutters(cm.display);
4327
+ regChange(cm);
4328
+ alignHorizontally(cm);
4329
  }
4330
 
4331
+ // The display handles the DOM integration, both for input reading
4332
+ // and content drawing. It holds references to DOM nodes and
4333
+ // display-related state.
4334
+
4335
+ function Display(place, doc, input, options) {
4336
+ var d = this;
4337
+ this.input = input;
4338
+
4339
+ // Covers bottom-right square when both scrollbars are present.
4340
+ d.scrollbarFiller = elt("div", null, "CodeMirror-scrollbar-filler");
4341
+ d.scrollbarFiller.setAttribute("cm-not-content", "true");
4342
+ // Covers bottom of gutter when coverGutterNextToScrollbar is on
4343
+ // and h scrollbar is present.
4344
+ d.gutterFiller = elt("div", null, "CodeMirror-gutter-filler");
4345
+ d.gutterFiller.setAttribute("cm-not-content", "true");
4346
+ // Will contain the actual code, positioned to cover the viewport.
4347
+ d.lineDiv = eltP("div", null, "CodeMirror-code");
4348
+ // Elements are added to these to represent selection and cursors.
4349
+ d.selectionDiv = elt("div", null, null, "position: relative; z-index: 1");
4350
+ d.cursorDiv = elt("div", null, "CodeMirror-cursors");
4351
+ // A visibility: hidden element used to find the size of things.
4352
+ d.measure = elt("div", null, "CodeMirror-measure");
4353
+ // When lines outside of the viewport are measured, they are drawn in this.
4354
+ d.lineMeasure = elt("div", null, "CodeMirror-measure");
4355
+ // Wraps everything that needs to exist inside the vertically-padded coordinate system
4356
+ d.lineSpace = eltP("div", [d.measure, d.lineMeasure, d.selectionDiv, d.cursorDiv, d.lineDiv],
4357
+ null, "position: relative; outline: none");
4358
+ var lines = eltP("div", [d.lineSpace], "CodeMirror-lines");
4359
+ // Moved around its parent to cover visible view.
4360
+ d.mover = elt("div", [lines], null, "position: relative");
4361
+ // Set to the height of the document, allowing scrolling.
4362
+ d.sizer = elt("div", [d.mover], "CodeMirror-sizer");
4363
+ d.sizerWidth = null;
4364
+ // Behavior of elts with overflow: auto and padding is
4365
+ // inconsistent across browsers. This is used to ensure the
4366
+ // scrollable area is big enough.
4367
+ d.heightForcer = elt("div", null, null, "position: absolute; height: " + scrollerGap + "px; width: 1px;");
4368
+ // Will contain the gutters, if any.
4369
+ d.gutters = elt("div", null, "CodeMirror-gutters");
4370
+ d.lineGutter = null;
4371
+ // Actual scrollable element.
4372
+ d.scroller = elt("div", [d.sizer, d.heightForcer, d.gutters], "CodeMirror-scroll");
4373
+ d.scroller.setAttribute("tabIndex", "-1");
4374
+ // The element in which the editor lives.
4375
+ d.wrapper = elt("div", [d.scrollbarFiller, d.gutterFiller, d.scroller], "CodeMirror");
4376
+
4377
+ // Work around IE7 z-index bug (not perfect, hence IE7 not really being supported)
4378
+ if (ie && ie_version < 8) { d.gutters.style.zIndex = -1; d.scroller.style.paddingRight = 0; }
4379
+ if (!webkit && !(gecko && mobile)) { d.scroller.draggable = true; }
4380
+
4381
+ if (place) {
4382
+ if (place.appendChild) { place.appendChild(d.wrapper); }
4383
+ else { place(d.wrapper); }
4384
  }
4385
+
4386
+ // Current rendered range (may be bigger than the view window).
4387
+ d.viewFrom = d.viewTo = doc.first;
4388
+ d.reportedViewFrom = d.reportedViewTo = doc.first;
4389
+ // Information about the rendered lines.
4390
+ d.view = [];
4391
+ d.renderedView = null;
4392
+ // Holds info about a single rendered line when it was rendered
4393
+ // for measurement, while not in view.
4394
+ d.externalMeasured = null;
4395
+ // Empty space (in pixels) above the view
4396
+ d.viewOffset = 0;
4397
+ d.lastWrapHeight = d.lastWrapWidth = 0;
4398
+ d.updateLineNumbers = null;
4399
+
4400
+ d.nativeBarWidth = d.barHeight = d.barWidth = 0;
4401
+ d.scrollbarsClipped = false;
4402
+
4403
+ // Used to only resize the line number gutter when necessary (when
4404
+ // the amount of lines crosses a boundary that makes its width change)
4405
+ d.lineNumWidth = d.lineNumInnerWidth = d.lineNumChars = null;
4406
+ // Set to true when a non-horizontal-scrolling line widget is
4407
+ // added. As an optimization, line widget aligning is skipped when
4408
+ // this is false.
4409
+ d.alignWidgets = false;
4410
+
4411
+ d.cachedCharWidth = d.cachedTextHeight = d.cachedPaddingH = null;
4412
+
4413
+ // Tracks the maximum line length so that the horizontal scrollbar
4414
+ // can be kept static when scrolling.
4415
+ d.maxLine = null;
4416
+ d.maxLineLength = 0;
4417
+ d.maxLineChanged = false;
4418
+
4419
+ // Used for measuring wheel scrolling granularity
4420
+ d.wheelDX = d.wheelDY = d.wheelStartX = d.wheelStartY = null;
4421
+
4422
+ // True when shift is held down.
4423
+ d.shift = false;
4424
+
4425
+ // Used to track whether anything happened since the context menu
4426
+ // was opened.
4427
+ d.selForContextMenu = null;
4428
+
4429
+ d.activeTouch = null;
4430
+
4431
+ d.gutterSpecs = getGutters(options.gutters, options.lineNumbers);
4432
+ renderGutters(d);
4433
+
4434
+ input.init(d);
4435
  }
4436
 
4437
  // Since the delta values reported on mouse wheel events are
4557
  Selection.prototype.primary = function () { return this.ranges[this.primIndex] };
4558
 
4559
  Selection.prototype.equals = function (other) {
 
 
4560
  if (other == this) { return true }
4561
  if (other.primIndex != this.primIndex || other.ranges.length != this.ranges.length) { return false }
4562
  for (var i = 0; i < this.ranges.length; i++) {
4563
+ var here = this.ranges[i], there = other.ranges[i];
4564
  if (!equalCursorPos(here.anchor, there.anchor) || !equalCursorPos(here.head, there.head)) { return false }
4565
  }
4566
  return true
4567
  };
4568
 
4569
  Selection.prototype.deepCopy = function () {
 
 
4570
  var out = [];
4571
  for (var i = 0; i < this.ranges.length; i++)
4572
+ { out[i] = new Range(copyPos(this.ranges[i].anchor), copyPos(this.ranges[i].head)); }
4573
  return new Selection(out, this.primIndex)
4574
  };
4575
 
4576
  Selection.prototype.somethingSelected = function () {
 
 
4577
  for (var i = 0; i < this.ranges.length; i++)
4578
+ { if (!this.ranges[i].empty()) { return true } }
4579
  return false
4580
  };
4581
 
4582
  Selection.prototype.contains = function (pos, end) {
 
 
4583
  if (!end) { end = pos; }
4584
  for (var i = 0; i < this.ranges.length; i++) {
4585
+ var range = this.ranges[i];
4586
  if (cmp(end, range.from()) >= 0 && cmp(pos, range.to()) <= 0)
4587
  { return i }
4588
  }
4708
  }
4709
 
4710
  // Perform a change on the document data structure.
4711
+ function updateDoc(doc, change, markedSpans, estimateHeight) {
4712
  function spansFor(n) {return markedSpans ? markedSpans[n] : null}
4713
  function update(line, text, spans) {
4714
+ updateLine(line, text, spans, estimateHeight);
4715
  signalLater(line, "change", line, change);
4716
  }
4717
  function linesFor(start, end) {
4718
  var result = [];
4719
  for (var i = start; i < end; ++i)
4720
+ { result.push(new Line(text[i], spansFor(i), estimateHeight)); }
4721
  return result
4722
  }
4723
 
4741
  update(firstLine, firstLine.text.slice(0, from.ch) + lastText + firstLine.text.slice(to.ch), lastSpans);
4742
  } else {
4743
  var added$1 = linesFor(1, text.length - 1);
4744
+ added$1.push(new Line(lastText + firstLine.text.slice(to.ch), lastSpans, estimateHeight));
4745
  update(firstLine, firstLine.text.slice(0, from.ch) + text[0], spansFor(0));
4746
  doc.insert(from.line + 1, added$1);
4747
  }
5078
  var obj = {
5079
  ranges: sel.ranges,
5080
  update: function(ranges) {
 
 
5081
  this.ranges = [];
5082
  for (var i = 0; i < ranges.length; i++)
5083
+ { this.ranges[i] = new Range(clipPos(doc, ranges[i].anchor),
5084
  clipPos(doc, ranges[i].head)); }
5085
  },
5086
  origin: options && options.origin
5125
  doc.sel = sel;
5126
 
5127
  if (doc.cm) {
5128
+ doc.cm.curOp.updateInput = 1;
5129
+ doc.cm.curOp.selectionChanged = true;
5130
  signalCursorActivity(doc.cm);
5131
  }
5132
  signalLater(doc, "cursorActivity", doc);
5159
  var line = getLine(doc, pos.line);
5160
  if (line.markedSpans) { for (var i = 0; i < line.markedSpans.length; ++i) {
5161
  var sp = line.markedSpans[i], m = sp.marker;
5162
+
5163
+ // Determine if we should prevent the cursor being placed to the left/right of an atomic marker
5164
+ // Historically this was determined using the inclusiveLeft/Right option, but the new way to control it
5165
+ // is with selectLeft/Right
5166
+ var preventCursorLeft = ("selectLeft" in m) ? !m.selectLeft : m.inclusiveLeft;
5167
+ var preventCursorRight = ("selectRight" in m) ? !m.selectRight : m.inclusiveRight;
5168
+
5169
+ if ((sp.from == null || (preventCursorLeft ? sp.from <= pos.ch : sp.from < pos.ch)) &&
5170
+ (sp.to == null || (preventCursorRight ? sp.to >= pos.ch : sp.to > pos.ch))) {
5171
  if (mayClear) {
5172
  signal(m, "beforeCursorEnter");
5173
  if (m.explicitlyCleared) {
5179
 
5180
  if (oldPos) {
5181
  var near = m.find(dir < 0 ? 1 : -1), diff = (void 0);
5182
+ if (dir < 0 ? preventCursorRight : preventCursorLeft)
5183
  { near = movePos(doc, near, -dir, near && near.line == pos.line ? line : null); }
5184
  if (near && near.line == pos.line && (diff = cmp(near, oldPos)) && (dir < 0 ? diff < 0 : diff > 0))
5185
  { return skipAtomicInner(doc, near, pos, dir, mayClear) }
5186
  }
5187
 
5188
  var far = m.find(dir < 0 ? -1 : 1);
5189
+ if (dir < 0 ? preventCursorLeft : preventCursorRight)
5190
  { far = movePos(doc, far, dir, far.line == pos.line ? line : null); }
5191
  return far ? skipAtomicInner(doc, far, pos, dir, mayClear) : null
5192
  }
5245
  signal(doc, "beforeChange", doc, obj);
5246
  if (doc.cm) { signal(doc.cm, "beforeChange", doc.cm, obj); }
5247
 
5248
+ if (obj.canceled) {
5249
+ if (doc.cm) { doc.cm.curOp.updateInput = 2; }
5250
+ return null
5251
+ }
5252
  return {from: obj.from, to: obj.to, text: obj.text, origin: obj.origin}
5253
  }
5254
 
5415
  if (doc.cm) { makeChangeSingleDocInEditor(doc.cm, change, spans); }
5416
  else { updateDoc(doc, change, spans); }
5417
  setSelectionNoUndo(doc, selAfter, sel_dontScroll);
5418
+
5419
+ if (doc.cantEdit && skipAtomic(doc, Pos(doc.firstLine(), 0)))
5420
+ { doc.cantEdit = false; }
5421
  }
5422
 
5423
  // Handle the interaction of a change to a document with the editor
5567
  // See also http://marijnhaverbeke.nl/blog/codemirror-line-tree.html
5568
 
5569
  function LeafChunk(lines) {
 
 
5570
  this.lines = lines;
5571
  this.parent = null;
5572
  var height = 0;
5573
  for (var i = 0; i < lines.length; ++i) {
5574
+ lines[i].parent = this;
5575
  height += lines[i].height;
5576
  }
5577
  this.height = height;
5582
 
5583
  // Remove the n lines at offset 'at'.
5584
  removeInner: function(at, n) {
 
 
5585
  for (var i = at, e = at + n; i < e; ++i) {
5586
+ var line = this.lines[i];
5587
+ this.height -= line.height;
5588
  cleanUpLine(line);
5589
  signalLater(line, "delete");
5590
  }
5599
  // Insert the given array of lines at offset 'at', count them as
5600
  // having the given height.
5601
  insertInner: function(at, lines, height) {
 
 
5602
  this.height += height;
5603
  this.lines = this.lines.slice(0, at).concat(lines).concat(this.lines.slice(at));
5604
+ for (var i = 0; i < lines.length; ++i) { lines[i].parent = this; }
5605
  },
5606
 
5607
  // Used to iterate over a part of the tree.
5608
  iterN: function(at, n, op) {
 
 
5609
  for (var e = at + n; at < e; ++at)
5610
+ { if (op(this.lines[at])) { return true } }
5611
  }
5612
  };
5613
 
5614
  function BranchChunk(children) {
 
 
5615
  this.children = children;
5616
  var size = 0, height = 0;
5617
  for (var i = 0; i < children.length; ++i) {
5618
  var ch = children[i];
5619
  size += ch.chunkSize(); height += ch.height;
5620
+ ch.parent = this;
5621
  }
5622
  this.size = size;
5623
  this.height = height;
5628
  chunkSize: function() { return this.size },
5629
 
5630
  removeInner: function(at, n) {
 
 
5631
  this.size -= n;
5632
  for (var i = 0; i < this.children.length; ++i) {
5633
+ var child = this.children[i], sz = child.chunkSize();
5634
  if (at < sz) {
5635
  var rm = Math.min(n, sz - at), oldHeight = child.height;
5636
  child.removeInner(at, rm);
5637
+ this.height -= oldHeight - child.height;
5638
+ if (sz == rm) { this.children.splice(i--, 1); child.parent = null; }
5639
  if ((n -= rm) == 0) { break }
5640
  at = 0;
5641
  } else { at -= sz; }
5652
  },
5653
 
5654
  collapse: function(lines) {
5655
+ for (var i = 0; i < this.children.length; ++i) { this.children[i].collapse(lines); }
 
 
5656
  },
5657
 
5658
  insertInner: function(at, lines, height) {
 
 
5659
  this.size += lines.length;
5660
  this.height += height;
5661
  for (var i = 0; i < this.children.length; ++i) {
5662
+ var child = this.children[i], sz = child.chunkSize();
5663
  if (at <= sz) {
5664
  child.insertInner(at, lines, height);
5665
  if (child.lines && child.lines.length > 50) {
5669
  for (var pos = remaining; pos < child.lines.length;) {
5670
  var leaf = new LeafChunk(child.lines.slice(pos, pos += 25));
5671
  child.height -= leaf.height;
5672
+ this.children.splice(++i, 0, leaf);
5673
+ leaf.parent = this;
5674
  }
5675
  child.lines = child.lines.slice(0, remaining);
5676
+ this.maybeSpill();
5677
  }
5678
  break
5679
  }
5705
  },
5706
 
5707
  iterN: function(at, n, op) {
 
 
5708
  for (var i = 0; i < this.children.length; ++i) {
5709
+ var child = this.children[i], sz = child.chunkSize();
5710
  if (at < sz) {
5711
  var used = Math.min(n, sz - at);
5712
  if (child.iterN(at, used, op)) { return true }
5720
  // Line widgets are block elements displayed above or below a line.
5721
 
5722
  var LineWidget = function(doc, node, options) {
 
 
5723
  if (options) { for (var opt in options) { if (options.hasOwnProperty(opt))
5724
+ { this[opt] = options[opt]; } } }
5725
  this.doc = doc;
5726
  this.node = node;
5727
  };
5728
 
5729
  LineWidget.prototype.clear = function () {
 
 
5730
  var cm = this.doc.cm, ws = this.line.widgets, line = this.line, no = lineNo(line);
5731
  if (no == null || !ws) { return }
5732
+ for (var i = 0; i < ws.length; ++i) { if (ws[i] == this) { ws.splice(i--, 1); } }
5733
  if (!ws.length) { line.widgets = null; }
5734
  var height = widgetHeight(this);
5735
  updateLineHeight(line, Math.max(0, line.height - height));
5772
  changeLine(doc, handle, "widget", function (line) {
5773
  var widgets = line.widgets || (line.widgets = []);
5774
  if (widget.insertAt == null) { widgets.push(widget); }
5775
+ else { widgets.splice(Math.min(widgets.length, Math.max(0, widget.insertAt)), 0, widget); }
5776
  widget.line = line;
5777
  if (cm && !lineIsHidden(doc, line)) {
5778
  var aboveVisible = heightAtLine(line) < doc.scrollTop;
5812
 
5813
  // Clear the marker.
5814
  TextMarker.prototype.clear = function () {
 
 
5815
  if (this.explicitlyCleared) { return }
5816
  var cm = this.doc.cm, withOp = cm && !cm.curOp;
5817
  if (withOp) { startOperation(cm); }
5821
  }
5822
  var min = null, max = null;
5823
  for (var i = 0; i < this.lines.length; ++i) {
5824
+ var line = this.lines[i];
5825
+ var span = getMarkedSpanFor(line.markedSpans, this);
5826
+ if (cm && !this.collapsed) { regLineChange(cm, lineNo(line), "text"); }
5827
  else if (cm) {
5828
  if (span.to != null) { max = lineNo(line); }
5829
  if (span.from != null) { min = lineNo(line); }
5830
  }
5831
  line.markedSpans = removeMarkedSpan(line.markedSpans, span);
5832
+ if (span.from == null && this.collapsed && !lineIsHidden(this.doc, line) && cm)
5833
  { updateLineHeight(line, textHeight(cm.display)); }
5834
  }
5835
  if (cm && this.collapsed && !cm.options.lineWrapping) { for (var i$1 = 0; i$1 < this.lines.length; ++i$1) {
5836
+ var visual = visualLine(this.lines[i$1]), len = lineLength(visual);
5837
  if (len > cm.display.maxLineLength) {
5838
  cm.display.maxLine = visual;
5839
  cm.display.maxLineLength = len;
5859
  // Pos objects returned contain a line object, rather than a line
5860
  // number (used to prevent looking up the same line twice).
5861
  TextMarker.prototype.find = function (side, lineObj) {
 
 
5862
  if (side == null && this.type == "bookmark") { side = 1; }
5863
  var from, to;
5864
  for (var i = 0; i < this.lines.length; ++i) {
5865
+ var line = this.lines[i];
5866
+ var span = getMarkedSpanFor(line.markedSpans, this);
5867
  if (span.from != null) {
5868
  from = Pos(lineObj ? line : lineNo(line), span.from);
5869
  if (side == -1) { return from }
5982
  if (updateMaxLine) { cm.curOp.updateMaxLine = true; }
5983
  if (marker.collapsed)
5984
  { regChange(cm, from.line, to.line + 1); }
5985
+ else if (marker.className || marker.startStyle || marker.endStyle || marker.css ||
5986
+ marker.attributes || marker.title)
5987
  { for (var i = from.line; i <= to.line; i++) { regLineChange(cm, i, "text"); } }
5988
  if (marker.atomic) { reCheckSelection(cm.doc); }
5989
  signalLater(cm, "markerAdded", cm, marker);
5997
  // implemented as a meta-marker-object controlling multiple normal
5998
  // markers.
5999
  var SharedTextMarker = function(markers, primary) {
 
 
6000
  this.markers = markers;
6001
  this.primary = primary;
6002
  for (var i = 0; i < markers.length; ++i)
6003
+ { markers[i].parent = this; }
6004
  };
6005
 
6006
  SharedTextMarker.prototype.clear = function () {
 
 
6007
  if (this.explicitlyCleared) { return }
6008
  this.explicitlyCleared = true;
6009
  for (var i = 0; i < this.markers.length; ++i)
6010
+ { this.markers[i].clear(); }
6011
  signalLater(this, "clear");
6012
  };
6013
 
6150
  clipPos: function(pos) {return clipPos(this, pos)},
6151
 
6152
  getCursor: function(start) {
6153
+ var range = this.sel.primary(), pos;
6154
+ if (start == null || start == "head") { pos = range.head; }
6155
+ else if (start == "anchor") { pos = range.anchor; }
6156
+ else if (start == "end" || start == "to" || start === false) { pos = range.to(); }
6157
+ else { pos = range.from(); }
6158
  return pos
6159
  },
6160
  listSelections: function() { return this.sel.ranges },
6177
  extendSelections(this, clipPosArray(this, heads), options);
6178
  }),
6179
  setSelections: docMethodOp(function(ranges, primary, options) {
 
 
6180
  if (!ranges.length) { return }
6181
  var out = [];
6182
  for (var i = 0; i < ranges.length; i++)
6183
+ { out[i] = new Range(clipPos(this, ranges[i].anchor),
6184
+ clipPos(this, ranges[i].head)); }
6185
  if (primary == null) { primary = Math.min(ranges.length - 1, this.sel.primIndex); }
6186
  setSelection(this, normalizeSelection(this.cm, out, primary), options);
6187
  }),
6192
  }),
6193
 
6194
  getSelection: function(lineSep) {
 
 
6195
  var ranges = this.sel.ranges, lines;
6196
  for (var i = 0; i < ranges.length; i++) {
6197
+ var sel = getBetween(this, ranges[i].from(), ranges[i].to());
6198
  lines = lines ? lines.concat(sel) : sel;
6199
  }
6200
  if (lineSep === false) { return lines }
6201
  else { return lines.join(lineSep || this.lineSeparator()) }
6202
  },
6203
  getSelections: function(lineSep) {
 
 
6204
  var parts = [], ranges = this.sel.ranges;
6205
  for (var i = 0; i < ranges.length; i++) {
6206
+ var sel = getBetween(this, ranges[i].from(), ranges[i].to());
6207
+ if (lineSep !== false) { sel = sel.join(lineSep || this.lineSeparator()); }
6208
  parts[i] = sel;
6209
  }
6210
  return parts
6216
  this.replaceSelections(dup, collapse, origin || "+input");
6217
  },
6218
  replaceSelections: docMethodOp(function(code, collapse, origin) {
 
 
6219
  var changes = [], sel = this.sel;
6220
  for (var i = 0; i < sel.ranges.length; i++) {
6221
+ var range = sel.ranges[i];
6222
+ changes[i] = {from: range.from(), to: range.to(), text: this.splitLines(code[i]), origin: origin};
6223
  }
6224
  var newSel = collapse && collapse != "end" && computeReplacedSel(this, changes, collapse);
6225
  for (var i$1 = changes.length - 1; i$1 >= 0; i$1--)
6226
+ { makeChange(this, changes[i$1]); }
6227
  if (newSel) { setSelectionReplaceHistory(this, newSel); }
6228
  else if (this.cm) { ensureCursorVisible(this.cm); }
6229
  }),
6241
  for (var i$1 = 0; i$1 < hist.undone.length; i$1++) { if (!hist.undone[i$1].ranges) { ++undone; } }
6242
  return {undo: done, redo: undone}
6243
  },
6244
+ clearHistory: function() {
6245
+ var this$1 = this;
6246
+
6247
+ this.history = new History(this.history.maxGeneration);
6248
+ linkedDocs(this, function (doc) { return doc.history = this$1.history; }, true);
6249
+ },
6250
 
6251
  markClean: function() {
6252
  this.cleanGeneration = this.changeGeneration(true);
6367
  },
6368
  findMarks: function(from, to, filter) {
6369
  from = clipPos(this, from); to = clipPos(this, to);
6370
+ var found = [], lineNo = from.line;
6371
  this.iter(from.line, to.line + 1, function (line) {
6372
  var spans = line.markedSpans;
6373
  if (spans) { for (var i = 0; i < spans.length; i++) {
6374
  var span = spans[i];
6375
+ if (!(span.to != null && lineNo == from.line && from.ch >= span.to ||
6376
+ span.from == null && lineNo != from.line ||
6377
+ span.from != null && lineNo == to.line && span.from >= to.ch) &&
6378
  (!filter || filter(span.marker)))
6379
  { found.push(span.marker.parent || span.marker); }
6380
  } }
6381
+ ++lineNo;
6382
  });
6383
  return found
6384
  },
6393
  },
6394
 
6395
  posFromIndex: function(off) {
6396
+ var ch, lineNo = this.first, sepSize = this.lineSeparator().length;
6397
  this.iter(function (line) {
6398
  var sz = line.text.length + sepSize;
6399
  if (sz > off) { ch = off; return true }
6400
  off -= sz;
6401
+ ++lineNo;
6402
  });
6403
+ return clipPos(this, Pos(lineNo, ch))
6404
  },
6405
  indexFromPos: function (coords) {
6406
  coords = clipPos(this, coords);
6439
  return copy
6440
  },
6441
  unlinkDoc: function(other) {
 
 
6442
  if (other instanceof CodeMirror) { other = other.doc; }
6443
  if (this.linked) { for (var i = 0; i < this.linked.length; ++i) {
6444
+ var link = this.linked[i];
6445
  if (link.doc != other) { continue }
6446
+ this.linked.splice(i, 1);
6447
+ other.unlinkDoc(this);
6448
+ detachSharedMarkers(findSharedMarkers(this));
6449
  break
6450
  } }
6451
  // If the histories were shared, split them again
6497
  // and insert it.
6498
  if (files && files.length && window.FileReader && window.File) {
6499
  var n = files.length, text = Array(n), read = 0;
6500
+ var markAsReadAndPasteIfAllFilesAreRead = function () {
6501
+ if (++read == n) {
6502
+ operation(cm, function () {
 
 
 
 
 
 
 
 
6503
  pos = clipPos(cm.doc, pos);
6504
  var change = {from: pos, to: pos,
6505
+ text: cm.doc.splitLines(
6506
+ text.filter(function (t) { return t != null; }).join(cm.doc.lineSeparator())),
6507
  origin: "paste"};
6508
  makeChange(cm.doc, change);
6509
+ setSelectionReplaceHistory(cm.doc, simpleSelection(clipPos(cm.doc, pos), clipPos(cm.doc, changeEnd(change))));
6510
+ })();
6511
+ }
6512
+ };
6513
+ var readTextFromFile = function (file, i) {
6514
+ if (cm.options.allowDropFileTypes &&
6515
+ indexOf(cm.options.allowDropFileTypes, file.type) == -1) {
6516
+ markAsReadAndPasteIfAllFilesAreRead();
6517
+ return
6518
+ }
6519
+ var reader = new FileReader;
6520
+ reader.onerror = function () { return markAsReadAndPasteIfAllFilesAreRead(); };
6521
+ reader.onload = function () {
6522
+ var content = reader.result;
6523
+ if (/[\x00-\x08\x0e-\x1f]{2}/.test(content)) {
6524
+ markAsReadAndPasteIfAllFilesAreRead();
6525
+ return
6526
  }
6527
+ text[i] = content;
6528
+ markAsReadAndPasteIfAllFilesAreRead();
6529
+ };
6530
  reader.readAsText(file);
6531
  };
6532
+ for (var i = 0; i < files.length; i++) { readTextFromFile(files[i], i); }
6533
  } else { // Normal drop
6534
  // Don't do a replace if the drop happened inside of the selected text.
6535
  if (cm.state.draggingText && cm.doc.sel.contains(pos) > -1) {
6551
  cm.display.input.focus();
6552
  }
6553
  }
6554
+ catch(e$1){}
6555
  }
6556
  }
6557
 
6603
 
6604
  function forEachCodeMirror(f) {
6605
  if (!document.getElementsByClassName) { return }
6606
+ var byClass = document.getElementsByClassName("CodeMirror"), editors = [];
6607
  for (var i = 0; i < byClass.length; i++) {
6608
  var cm = byClass[i].CodeMirror;
6609
+ if (cm) { editors.push(cm); }
6610
  }
6611
+ if (editors.length) { editors[0].operation(function () {
6612
+ for (var i = 0; i < editors.length; i++) { f(editors[i]); }
6613
+ }); }
6614
  }
6615
 
6616
  var globalsRegistered = false;
6645
  19: "Pause", 20: "CapsLock", 27: "Esc", 32: "Space", 33: "PageUp", 34: "PageDown", 35: "End",
6646
  36: "Home", 37: "Left", 38: "Up", 39: "Right", 40: "Down", 44: "PrintScrn", 45: "Insert",
6647
  46: "Delete", 59: ";", 61: "=", 91: "Mod", 92: "Mod", 93: "Mod",
6648
+ 106: "*", 107: "=", 109: "-", 110: ".", 111: "/", 145: "ScrollLock",
6649
  173: "-", 186: ";", 187: "=", 188: ",", 189: "-", 190: ".", 191: "/", 192: "`", 219: "[", 220: "\\",
6650
+ 221: "]", 222: "'", 224: "Mod", 63232: "Up", 63233: "Down", 63234: "Left", 63235: "Right", 63272: "Delete",
6651
  63273: "Home", 63275: "End", 63276: "PageUp", 63277: "PageDown", 63302: "Insert"
6652
  };
6653
 
6754
  return keymap
6755
  }
6756
 
6757
+ function lookupKey(key, map, handle, context) {
6758
+ map = getKeyMap(map);
6759
+ var found = map.call ? map.call(key, context) : map[key];
6760
  if (found === false) { return "nothing" }
6761
  if (found === "...") { return "multi" }
6762
  if (found != null && handle(found)) { return "handled" }
6763
 
6764
+ if (map.fallthrough) {
6765
+ if (Object.prototype.toString.call(map.fallthrough) != "[object Array]")
6766
+ { return lookupKey(key, map.fallthrough, handle, context) }
6767
+ for (var i = 0; i < map.fallthrough.length; i++) {
6768
+ var result = lookupKey(key, map.fallthrough[i], handle, context);
6769
  if (result) { return result }
6770
  }
6771
  }
6782
  var base = name;
6783
  if (event.altKey && base != "Alt") { name = "Alt-" + name; }
6784
  if ((flipCtrlCmd ? event.metaKey : event.ctrlKey) && base != "Ctrl") { name = "Ctrl-" + name; }
6785
+ if ((flipCtrlCmd ? event.ctrlKey : event.metaKey) && base != "Mod") { name = "Cmd-" + name; }
6786
  if (!noShift && event.shiftKey && base != "Shift") { name = "Shift-" + name; }
6787
  return name
6788
  }
6839
 
6840
  function endOfLine(visually, cm, lineObj, lineNo, dir) {
6841
  if (visually) {
6842
+ if (cm.doc.direction == "rtl") { dir = -dir; }
6843
  var order = getOrder(lineObj, cm.doc.direction);
6844
  if (order) {
6845
  var part = dir < 0 ? lst(order) : order[0];
7008
  goGroupRight: function (cm) { return cm.moveH(1, "group"); },
7009
  goGroupLeft: function (cm) { return cm.moveH(-1, "group"); },
7010
  goWordRight: function (cm) { return cm.moveH(1, "word"); },
7011
+ delCharBefore: function (cm) { return cm.deleteH(-1, "codepoint"); },
7012
  delCharAfter: function (cm) { return cm.deleteH(1, "char"); },
7013
  delWordBefore: function (cm) { return cm.deleteH(-1, "word"); },
7014
  delWordAfter: function (cm) { return cm.deleteH(1, "word"); },
7094
  var line = getLine(cm.doc, start.line);
7095
  var order = getOrder(line, cm.doc.direction);
7096
  if (!order || order[0].level == 0) {
7097
+ var firstNonWS = Math.max(start.ch, line.text.search(/\S/));
7098
  var inWS = pos.line == start.line && pos.ch <= firstNonWS && pos.ch;
7099
  return Pos(start.line, inWS ? 0 : firstNonWS, start.sticky)
7100
  }
7197
  var lastStoppedKey = null;
7198
  function onKeyDown(e) {
7199
  var cm = this;
7200
+ if (e.target && e.target != cm.display.input.getField()) { return }
7201
  cm.curOp.focus = activeElt();
7202
  if (signalDOMEvent(cm, e)) { return }
7203
  // IE does strange things with escape.
7211
  if (!handled && code == 88 && !hasCopyEvent && (mac ? e.metaKey : e.ctrlKey))
7212
  { cm.replaceSelection("", null, "cut"); }
7213
  }
7214
+ if (gecko && !mac && !handled && code == 46 && e.shiftKey && !e.ctrlKey && document.execCommand)
7215
+ { document.execCommand("cut"); }
7216
 
7217
  // Turn mouse into crosshair when Alt is held on Mac.
7218
  if (code == 18 && !/\bCodeMirror-crosshair\b/.test(cm.display.lineDiv.className))
7241
 
7242
  function onKeyPress(e) {
7243
  var cm = this;
7244
+ if (e.target && e.target != cm.display.input.getField()) { return }
7245
  if (eventInWidget(cm.display, e) || signalDOMEvent(cm, e) || e.ctrlKey && !e.altKey || mac && e.metaKey) { return }
7246
  var keyCode = e.keyCode, charCode = e.charCode;
7247
  if (presto && keyCode == lastStoppedKey) {lastStoppedKey = null; e_preventDefault(e); return}
7381
  var dragEnd = operation(cm, function (e) {
7382
  if (webkit) { display.scroller.draggable = false; }
7383
  cm.state.draggingText = false;
7384
+ if (cm.state.delayingBlurEvent) {
7385
+ if (cm.hasFocus()) { cm.state.delayingBlurEvent = false; }
7386
+ else { delayBlurEvent(cm); }
7387
+ }
7388
  off(display.wrapper.ownerDocument, "mouseup", dragEnd);
7389
  off(display.wrapper.ownerDocument, "mousemove", mouseMove);
7390
  off(display.scroller, "dragstart", dragStart);
7394
  if (!behavior.addNew)
7395
  { extendSelection(cm.doc, pos, null, null, behavior.extend); }
7396
  // Work around unexplainable focus problem in IE9 (#2127) and Chrome (#3081)
7397
+ if ((webkit && !safari) || ie && ie_version == 9)
7398
+ { setTimeout(function () {display.wrapper.ownerDocument.body.focus({preventScroll: true}); display.input.focus();}, 20); }
7399
  else
7400
  { display.input.focus(); }
7401
  }
7408
  if (webkit) { display.scroller.draggable = true; }
7409
  cm.state.draggingText = dragEnd;
7410
  dragEnd.copy = !behavior.moveOnDrag;
 
 
7411
  on(display.wrapper.ownerDocument, "mouseup", dragEnd);
7412
  on(display.wrapper.ownerDocument, "mousemove", mouseMove);
7413
  on(display.scroller, "dragstart", dragStart);
7414
  on(display.scroller, "drop", dragEnd);
7415
 
7416
+ cm.state.delayingBlurEvent = true;
7417
  setTimeout(function () { return display.input.focus(); }, 20);
7418
+ // IE's approach to draggable
7419
+ if (display.scroller.dragDrop) { display.scroller.dragDrop(); }
7420
  }
7421
 
7422
  function rangeForUnit(cm, pos, unit) {
7429
 
7430
  // Normal selection, as opposed to text dragging.
7431
  function leftButtonSelect(cm, event, start, behavior) {
7432
+ if (ie) { delayBlurEvent(cm); }
7433
  var display = cm.display, doc = cm.doc;
7434
  e_preventDefault(event);
7435
 
7450
  start = posFromMouse(cm, event, true, true);
7451
  ourIndex = -1;
7452
  } else {
7453
+ var range = rangeForUnit(cm, start, behavior.unit);
7454
  if (behavior.extend)
7455
+ { ourRange = extendRange(ourRange, range.anchor, range.head, behavior.extend); }
7456
  else
7457
+ { ourRange = range; }
7458
  }
7459
 
7460
  if (!behavior.addNew) {
7497
  cm.scrollIntoView(pos);
7498
  } else {
7499
  var oldRange = ourRange;
7500
+ var range = rangeForUnit(cm, pos, behavior.unit);
7501
  var anchor = oldRange.anchor, head;
7502
+ if (cmp(range.anchor, anchor) > 0) {
7503
+ head = range.head;
7504
+ anchor = minPos(oldRange.from(), range.anchor);
7505
  } else {
7506
+ head = range.anchor;
7507
+ anchor = maxPos(oldRange.to(), range.head);
7508
  }
7509
  var ranges$1 = startSel.ranges.slice(0);
7510
  ranges$1[ourIndex] = bidiSimplify(cm, new Range(clipPos(doc, anchor), head));
7542
  function done(e) {
7543
  cm.state.selectingText = false;
7544
  counter = Infinity;
7545
+ // If e is null or undefined we interpret this as someone trying
7546
+ // to explicitly cancel the selection rather than the user
7547
+ // letting go of the mouse button.
7548
+ if (e) {
7549
+ e_preventDefault(e);
7550
+ display.input.focus();
7551
+ }
7552
  off(display.wrapper.ownerDocument, "mousemove", move);
7553
  off(display.wrapper.ownerDocument, "mouseup", up);
7554
  doc.history.lastSelOrigin = null;
7566
 
7567
  // Used when mouse-selecting to adjust the anchor to the proper side
7568
  // of a bidi jump depending on the visual position of the head.
7569
+ function bidiSimplify(cm, range) {
7570
+ var anchor = range.anchor;
7571
+ var head = range.head;
7572
  var anchorLine = getLine(cm.doc, anchor.line);
7573
+ if (cmp(anchor, head) == 0 && anchor.sticky == head.sticky) { return range }
7574
  var order = getOrder(anchorLine);
7575
+ if (!order) { return range }
7576
  var index = getBidiPartAt(order, anchor.ch, anchor.sticky), part = order[index];
7577
+ if (part.from != anchor.ch && part.to != anchor.ch) { return range }
7578
  var boundary = index + ((part.from == anchor.ch) == (part.level != 1) ? 0 : 1);
7579
+ if (boundary == 0 || boundary == order.length) { return range }
7580
 
7581
  // Compute the relative visual position of the head compared to the
7582
  // anchor (<0 is to the left, >0 to the right)
7595
  var usePart = order[boundary + (leftSide ? -1 : 0)];
7596
  var from = leftSide == (usePart.level == 1);
7597
  var ch = from ? usePart.from : usePart.to, sticky = from ? "after" : "before";
7598
+ return anchor.ch == ch && anchor.sticky == sticky ? range : new Range(new Pos(anchor.line, ch, sticky), head)
7599
  }
7600
 
7601
 
7608
  mY = e.touches[0].clientY;
7609
  } else {
7610
  try { mX = e.clientX; mY = e.clientY; }
7611
+ catch(e$1) { return false }
7612
  }
7613
  if (mX >= Math.floor(cm.display.gutters.getBoundingClientRect().right)) { return false }
7614
  if (prevent) { e_preventDefault(e); }
7619
  if (mY > lineBox.bottom || !hasHandler(cm, type)) { return e_defaultPrevented(e) }
7620
  mY -= lineBox.top - display.viewOffset;
7621
 
7622
+ for (var i = 0; i < cm.display.gutterSpecs.length; ++i) {
7623
  var g = display.gutters.childNodes[i];
7624
  if (g && g.getBoundingClientRect().right >= mX) {
7625
  var line = lineAtHeight(cm.doc, mY);
7626
+ var gutter = cm.display.gutterSpecs[i];
7627
+ signal(cm, type, cm, line, gutter.className, e);
7628
  return e_defaultPrevented(e)
7629
  }
7630
  }
7708
  for (var i = newBreaks.length - 1; i >= 0; i--)
7709
  { replaceRange(cm.doc, val, newBreaks[i], Pos(newBreaks[i].line, newBreaks[i].ch + val.length)); }
7710
  });
7711
+ option("specialChars", /[\u0000-\u001f\u007f-\u009f\u00ad\u061c\u200b-\u200c\u200e\u200f\u2028\u2029\ufeff\ufff9-\ufffc]/g, function (cm, val, old) {
7712
  cm.state.specialChars = new RegExp(val.source + (val.test("\t") ? "" : "|\t"), "g");
7713
  if (old != Init) { cm.refresh(); }
7714
  });
7718
  throw new Error("inputStyle can not (yet) be changed in a running editor") // FIXME
7719
  }, true);
7720
  option("spellcheck", false, function (cm, val) { return cm.getInputField().spellcheck = val; }, true);
7721
+ option("autocorrect", false, function (cm, val) { return cm.getInputField().autocorrect = val; }, true);
7722
+ option("autocapitalize", false, function (cm, val) { return cm.getInputField().autocapitalize = val; }, true);
7723
  option("rtlMoveVisually", !windows);
7724
  option("wholeLineUpdateBefore", true);
7725
 
7726
  option("theme", "default", function (cm) {
7727
  themeChanged(cm);
7728
+ updateGutters(cm);
7729
  }, true);
7730
  option("keyMap", "default", function (cm, val, old) {
7731
  var next = getKeyMap(val);
7737
  option("configureMouse", null);
7738
 
7739
  option("lineWrapping", false, wrappingChanged, true);
7740
+ option("gutters", [], function (cm, val) {
7741
+ cm.display.gutterSpecs = getGutters(val, cm.options.lineNumbers);
7742
+ updateGutters(cm);
7743
  }, true);
7744
  option("fixedGutter", true, function (cm, val) {
7745
  cm.display.gutters.style.left = val ? compensateForHScroll(cm.display) + "px" : "0";
7752
  cm.display.scrollbars.setScrollTop(cm.doc.scrollTop);
7753
  cm.display.scrollbars.setScrollLeft(cm.doc.scrollLeft);
7754
  }, true);
7755
+ option("lineNumbers", false, function (cm, val) {
7756
+ cm.display.gutterSpecs = getGutters(cm.options.gutters, val);
7757
+ updateGutters(cm);
7758
  }, true);
7759
+ option("firstLineNumber", 1, updateGutters, true);
7760
+ option("lineNumberFormatter", function (integer) { return integer; }, updateGutters, true);
7761
  option("showCursorWhenSelecting", false, updateSelection, true);
7762
 
7763
  option("resetSelectionOnContextMenu", true);
7772
  }
7773
  cm.display.input.readOnlyChanged(val);
7774
  });
7775
+
7776
+ option("screenReaderLabel", null, function (cm, val) {
7777
+ val = (val === '') ? null : val;
7778
+ cm.display.input.screenReaderLabelChanged(val);
7779
+ });
7780
+
7781
  option("disableInput", false, function (cm, val) {if (!val) { cm.display.input.reset(); }}, true);
7782
  option("dragDrop", true, dragDropChanged);
7783
  option("allowDropFileTypes", null);
7805
  option("phrases", null);
7806
  }
7807
 
 
 
 
 
 
 
7808
  function dragDropChanged(cm, value, old) {
7809
  var wasOn = old && old != Init;
7810
  if (!value != !wasOn) {
7844
  this.options = options = options ? copyObj(options) : {};
7845
  // Determine effective options based on given values and defaults.
7846
  copyObj(defaults, options, false);
 
7847
 
7848
  var doc = options.value;
7849
  if (typeof doc == "string") { doc = new Doc(doc, options.mode, null, options.lineSeparator, options.direction); }
7851
  this.doc = doc;
7852
 
7853
  var input = new CodeMirror.inputStyles[options.inputStyle](this);
7854
+ var display = this.display = new Display(place, doc, input, options);
7855
  display.wrapper.CodeMirror = this;
 
7856
  themeChanged(this);
7857
  if (options.lineWrapping)
7858
  { this.display.wrapper.className += " CodeMirror-wrap"; }
7866
  delayingBlurEvent: false,
7867
  focused: false,
7868
  suppressEdits: false, // used to disable editing during key handlers when in readOnly mode
7869
+ pasteIncoming: -1, cutIncoming: -1, // help recognize paste/cut edits in input.poll
7870
  selectingText: false,
7871
  draggingText: false,
7872
  highlight: new Delayed(), // stores highlight worker timeout
7888
  attachDoc(this, doc);
7889
 
7890
  if ((options.autofocus && !mobile) || this.hasFocus())
7891
+ { setTimeout(function () {
7892
+ if (this$1.hasFocus() && !this$1.state.focused) { onFocus(this$1); }
7893
+ }, 20); }
7894
  else
7895
  { onBlur(this); }
7896
 
7897
  for (var opt in optionHandlers) { if (optionHandlers.hasOwnProperty(opt))
7898
+ { optionHandlers[opt](this, options[opt], Init); } }
7899
  maybeUpdateLineNumberWidth(this);
7900
  if (options.finishInit) { options.finishInit(this); }
7901
+ for (var i = 0; i < initHooks.length; ++i) { initHooks[i](this); }
7902
  endOperation(this);
7903
  // Suppress optimizelegibility in Webkit, since it breaks text
7904
  // measuring on line wrapping boundaries.
7932
  // which point we can't mess with it anymore. Context menu is
7933
  // handled in onMouseDown for these browsers.
7934
  on(d.scroller, "contextmenu", function (e) { return onContextMenu(cm, e); });
7935
+ on(d.input.getField(), "contextmenu", function (e) {
7936
+ if (!d.scroller.contains(e.target)) { onContextMenu(cm, e); }
7937
+ });
7938
 
7939
  // Used to suppress mouse event handling when a touch happens
7940
  var touchFinished, prevTouch = {end: 0};
8104
  cm.display.shift = false;
8105
  if (!sel) { sel = doc.sel; }
8106
 
8107
+ var recent = +new Date - 200;
8108
+ var paste = origin == "paste" || cm.state.pasteIncoming > recent;
8109
  var textLines = splitLinesAuto(inserted), multiPaste = null;
8110
  // When pasting N lines into N selections, insert one line per selection
8111
  if (paste && sel.ranges.length > 1) {
8120
  }
8121
  }
8122
 
8123
+ var updateInput = cm.curOp.updateInput;
8124
  // Normal behavior is to insert the new text into every selection
8125
  for (var i$1 = sel.ranges.length - 1; i$1 >= 0; i$1--) {
8126
+ var range = sel.ranges[i$1];
8127
+ var from = range.from(), to = range.to();
8128
+ if (range.empty()) {
8129
  if (deleted && deleted > 0) // Handle deletion
8130
  { from = Pos(from.line, from.ch - deleted); }
8131
  else if (cm.state.overwrite && !paste) // Handle overwrite
8132
  { to = Pos(to.line, Math.min(getLine(doc, to.line).text.length, to.ch + lst(textLines).length)); }
8133
+ else if (paste && lastCopied && lastCopied.lineWise && lastCopied.text.join("\n") == textLines.join("\n"))
8134
  { from = to = Pos(from.line, 0); }
8135
  }
 
8136
  var changeEvent = {from: from, to: to, text: multiPaste ? multiPaste[i$1 % multiPaste.length] : textLines,
8137
+ origin: origin || (paste ? "paste" : cm.state.cutIncoming > recent ? "cut" : "+input")};
8138
  makeChange(cm.doc, changeEvent);
8139
  signalLater(cm, "inputRead", cm, changeEvent);
8140
  }
8142
  { triggerElectric(cm, inserted); }
8143
 
8144
  ensureCursorVisible(cm);
8145
+ if (cm.curOp.updateInput < 2) { cm.curOp.updateInput = updateInput; }
8146
  cm.curOp.typing = true;
8147
+ cm.state.pasteIncoming = cm.state.cutIncoming = -1;
8148
  }
8149
 
8150
  function handlePaste(e, cm) {
8163
  var sel = cm.doc.sel;
8164
 
8165
  for (var i = sel.ranges.length - 1; i >= 0; i--) {
8166
+ var range = sel.ranges[i];
8167
+ if (range.head.ch > 100 || (i && sel.ranges[i - 1].head.line == range.head.line)) { continue }
8168
+ var mode = cm.getModeAt(range.head);
8169
  var indented = false;
8170
  if (mode.electricChars) {
8171
  for (var j = 0; j < mode.electricChars.length; j++)
8172
  { if (inserted.indexOf(mode.electricChars.charAt(j)) > -1) {
8173
+ indented = indentLine(cm, range.head.line, "smart");
8174
  break
8175
  } }
8176
  } else if (mode.electricInput) {
8177
+ if (mode.electricInput.test(getLine(cm.doc, range.head.line).text.slice(0, range.head.ch)))
8178
+ { indented = indentLine(cm, range.head.line, "smart"); }
8179
  }
8180
+ if (indented) { signalLater(cm, "electricInput", cm, range.head.line); }
8181
  }
8182
  }
8183
 
8192
  return {text: text, ranges: ranges}
8193
  }
8194
 
8195
+ function disableBrowserMagic(field, spellcheck, autocorrect, autocapitalize) {
8196
+ field.setAttribute("autocorrect", autocorrect ? "" : "off");
8197
+ field.setAttribute("autocapitalize", autocapitalize ? "" : "off");
8198
  field.setAttribute("spellcheck", !!spellcheck);
8199
  }
8200
 
8242
  getOption: function(option) {return this.options[option]},
8243
  getDoc: function() {return this.doc},
8244
 
8245
+ addKeyMap: function(map, bottom) {
8246
+ this.state.keyMaps[bottom ? "push" : "unshift"](getKeyMap(map));
8247
  },
8248
+ removeKeyMap: function(map) {
8249
  var maps = this.state.keyMaps;
8250
  for (var i = 0; i < maps.length; ++i)
8251
+ { if (maps[i] == map || maps[i].name == map) {
8252
  maps.splice(i, 1);
8253
  return true
8254
  } }
8265
  regChange(this);
8266
  }),
8267
  removeOverlay: methodOp(function(spec) {
 
 
8268
  var overlays = this.state.overlays;
8269
  for (var i = 0; i < overlays.length; ++i) {
8270
  var cur = overlays[i].modeSpec;
8271
  if (cur == spec || typeof spec == "string" && cur.name == spec) {
8272
  overlays.splice(i, 1);
8273
+ this.state.modeGen++;
8274
+ regChange(this);
8275
  return
8276
  }
8277
  }
8285
  if (isLine(this.doc, n)) { indentLine(this, n, dir, aggressive); }
8286
  }),
8287
  indentSelection: methodOp(function(how) {
 
 
8288
  var ranges = this.doc.sel.ranges, end = -1;
8289
  for (var i = 0; i < ranges.length; i++) {
8290
+ var range = ranges[i];
8291
+ if (!range.empty()) {
8292
+ var from = range.from(), to = range.to();
8293
  var start = Math.max(end, from.line);
8294
+ end = Math.min(this.lastLine(), to.line - (to.ch ? 0 : 1)) + 1;
8295
  for (var j = start; j < end; ++j)
8296
+ { indentLine(this, j, how); }
8297
+ var newRanges = this.doc.sel.ranges;
8298
  if (from.ch == 0 && ranges.length == newRanges.length && newRanges[i].from().ch > 0)
8299
+ { replaceOneSelection(this.doc, i, new Range(from, newRanges[i].to()), sel_dontScroll); }
8300
+ } else if (range.head.line > end) {
8301
+ indentLine(this, range.head.line, how, true);
8302
+ end = range.head.line;
8303
+ if (i == this.doc.sel.primIndex) { ensureCursorVisible(this); }
8304
  }
8305
  }
8306
  }),
8342
  },
8343
 
8344
  getHelpers: function(pos, type) {
 
 
8345
  var found = [];
8346
  if (!helpers.hasOwnProperty(type)) { return found }
8347
  var help = helpers[type], mode = this.getModeAt(pos);
8359
  }
8360
  for (var i$1 = 0; i$1 < help._global.length; i$1++) {
8361
  var cur = help._global[i$1];
8362
+ if (cur.pred(mode, this) && indexOf(found, cur.val) == -1)
8363
  { found.push(cur.val); }
8364
  }
8365
  return found
8372
  },
8373
 
8374
  cursorCoords: function(start, mode) {
8375
+ var pos, range = this.doc.sel.primary();
8376
+ if (start == null) { pos = range.head; }
8377
  else if (typeof start == "object") { pos = clipPos(this.doc, start); }
8378
+ else { pos = start ? range.from() : range.to(); }
8379
  return cursorCoords(this, pos, mode || "page")
8380
  },
8381
 
8459
  triggerElectric: methodOp(function(text) { triggerElectric(this, text); }),
8460
 
8461
  findPosH: function(from, amount, unit, visually) {
 
 
8462
  var dir = 1;
8463
  if (amount < 0) { dir = -1; amount = -amount; }
8464
  var cur = clipPos(this.doc, from);
8465
  for (var i = 0; i < amount; ++i) {
8466
+ cur = findPosH(this.doc, cur, dir, unit, visually);
8467
  if (cur.hitSide) { break }
8468
  }
8469
  return cur
8472
  moveH: methodOp(function(dir, unit) {
8473
  var this$1 = this;
8474
 
8475
+ this.extendSelectionsBy(function (range) {
8476
+ if (this$1.display.shift || this$1.doc.extend || range.empty())
8477
+ { return findPosH(this$1.doc, range.head, dir, unit, this$1.options.rtlMoveVisually) }
8478
  else
8479
+ { return dir < 0 ? range.from() : range.to() }
8480
  }, sel_move);
8481
  }),
8482
 
8485
  if (sel.somethingSelected())
8486
  { doc.replaceSelection("", null, "+delete"); }
8487
  else
8488
+ { deleteNearSelection(this, function (range) {
8489
+ var other = findPosH(doc, range.head, dir, unit, false);
8490
+ return dir < 0 ? {from: other, to: range.head} : {from: range.head, to: other}
8491
  }); }
8492
  }),
8493
 
8494
  findPosV: function(from, amount, unit, goalColumn) {
 
 
8495
  var dir = 1, x = goalColumn;
8496
  if (amount < 0) { dir = -1; amount = -amount; }
8497
  var cur = clipPos(this.doc, from);
8498
  for (var i = 0; i < amount; ++i) {
8499
+ var coords = cursorCoords(this, cur, "div");
8500
  if (x == null) { x = coords.left; }
8501
  else { coords.left = x; }
8502
+ cur = findPosV(this, coords, dir, unit);
8503
  if (cur.hitSide) { break }
8504
  }
8505
  return cur
8510
 
8511
  var doc = this.doc, goals = [];
8512
  var collapse = !this.display.shift && !doc.extend && doc.sel.somethingSelected();
8513
+ doc.extendSelectionsBy(function (range) {
8514
  if (collapse)
8515
+ { return dir < 0 ? range.from() : range.to() }
8516
+ var headPos = cursorCoords(this$1, range.head, "div");
8517
+ if (range.goalColumn != null) { headPos.left = range.goalColumn; }
8518
  goals.push(headPos.left);
8519
  var pos = findPosV(this$1, headPos, dir, unit);
8520
+ if (unit == "page" && range == doc.sel.primary())
8521
  { addToScrollTop(this$1, charCoords(this$1, pos, "div").top - headPos.top); }
8522
  return pos
8523
  }, sel_move);
8564
  clientHeight: displayHeight(this), clientWidth: displayWidth(this)}
8565
  },
8566
 
8567
+ scrollIntoView: methodOp(function(range, margin) {
8568
+ if (range == null) {
8569
+ range = {from: this.doc.sel.primary().head, to: null};
8570
  if (margin == null) { margin = this.options.cursorScrollMargin; }
8571
+ } else if (typeof range == "number") {
8572
+ range = {from: Pos(range, 0), to: null};
8573
+ } else if (range.from == null) {
8574
+ range = {from: range, to: null};
8575
  }
8576
+ if (!range.to) { range.to = range.from; }
8577
+ range.margin = margin || 0;
8578
 
8579
+ if (range.from.line != null) {
8580
+ scrollToRange(this, range);
8581
  } else {
8582
+ scrollToCoordsRange(this, range.from, range.to, range.margin);
8583
  }
8584
  }),
8585
 
8590
  if (width != null) { this.display.wrapper.style.width = interpret(width); }
8591
  if (height != null) { this.display.wrapper.style.height = interpret(height); }
8592
  if (this.options.lineWrapping) { clearLineMeasurementCache(this); }
8593
+ var lineNo = this.display.viewFrom;
8594
+ this.doc.iter(lineNo, this.display.viewTo, function (line) {
8595
  if (line.widgets) { for (var i = 0; i < line.widgets.length; i++)
8596
+ { if (line.widgets[i].noHScroll) { regLineChange(this$1, lineNo, "widget"); break } } }
8597
+ ++lineNo;
8598
  });
8599
  this.curOp.forceUpdate = true;
8600
  signal(this, "refresh", this);
8610
  this.curOp.forceUpdate = true;
8611
  clearCaches(this);
8612
  scrollToCoords(this, this.doc.scrollLeft, this.doc.scrollTop);
8613
+ updateGutterSpace(this.display);
8614
+ if (oldHeight == null || Math.abs(oldHeight - textHeight(this.display)) > .5 || this.options.lineWrapping)
8615
  { estimateLineHeights(this); }
8616
  signal(this, "refresh", this);
8617
  }),
8619
  swapDoc: methodOp(function(doc) {
8620
  var old = this.doc;
8621
  old.cm = null;
8622
+ // Cancel the current text selection if any (#5821)
8623
+ if (this.state.selectingText) { this.state.selectingText(); }
8624
  attachDoc(this, doc);
8625
  clearCaches(this);
8626
  this.display.input.reset();
8653
  }
8654
 
8655
  // Used for horizontal relative motion. Dir is -1 or 1 (left or
8656
+ // right), unit can be "codepoint", "char", "column" (like char, but
8657
+ // doesn't cross line boundaries), "word" (across next word), or
8658
+ // "group" (to the start of next group of word or
8659
+ // non-word-non-whitespace chars). The visually param controls
8660
+ // whether, in right-to-left text, direction 1 means to move towards
8661
+ // the next index in the string, or towards the character to the right
8662
+ // of the current position. The resulting position will have a
8663
+ // hitSide=true property if it reached the end of the document.
8664
  function findPosH(doc, pos, dir, unit, visually) {
8665
  var oldPos = pos;
8666
  var origDir = dir;
8667
  var lineObj = getLine(doc, pos.line);
8668
+ var lineDir = visually && doc.direction == "rtl" ? -dir : dir;
8669
  function findNextLine() {
8670
+ var l = pos.line + lineDir;
8671
  if (l < doc.first || l >= doc.first + doc.size) { return false }
8672
  pos = new Pos(l, pos.ch, pos.sticky);
8673
  return lineObj = getLine(doc, l)
8674
  }
8675
  function moveOnce(boundToLine) {
8676
  var next;
8677
+ if (unit == "codepoint") {
8678
+ var ch = lineObj.text.charCodeAt(pos.ch + (unit > 0 ? 0 : -1));
8679
+ if (isNaN(ch)) {
8680
+ next = null;
8681
+ } else {
8682
+ var astral = dir > 0 ? ch >= 0xD800 && ch < 0xDC00 : ch >= 0xDC00 && ch < 0xDFFF;
8683
+ next = new Pos(pos.line, Math.max(0, Math.min(lineObj.text.length, pos.ch + dir * (astral ? 2 : 1))), -dir);
8684
+ }
8685
+ } else if (visually) {
8686
  next = moveVisually(doc.cm, lineObj, pos, dir);
8687
  } else {
8688
  next = moveLogically(lineObj, pos, dir);
8689
  }
8690
  if (next == null) {
8691
  if (!boundToLine && findNextLine())
8692
+ { pos = endOfLine(visually, doc.cm, lineObj, pos.line, lineDir); }
8693
  else
8694
  { return false }
8695
  } else {
8698
  return true
8699
  }
8700
 
8701
+ if (unit == "char" || unit == "codepoint") {
8702
  moveOnce();
8703
  } else if (unit == "column") {
8704
  moveOnce(true);
8766
 
8767
  var input = this, cm = input.cm;
8768
  var div = input.div = display.lineDiv;
8769
+ disableBrowserMagic(div, cm.options.spellcheck, cm.options.autocorrect, cm.options.autocapitalize);
8770
+
8771
+ function belongsToInput(e) {
8772
+ for (var t = e.target; t; t = t.parentNode) {
8773
+ if (t == div) { return true }
8774
+ if (/\bCodeMirror-(?:line)?widget\b/.test(t.className)) { break }
8775
+ }
8776
+ return false
8777
+ }
8778
 
8779
  on(div, "paste", function (e) {
8780
+ if (!belongsToInput(e) || signalDOMEvent(cm, e) || handlePaste(e, cm)) { return }
8781
  // IE doesn't fire input events, so we schedule a read for the pasted content in this way
8782
  if (ie_version <= 11) { setTimeout(operation(cm, function () { return this$1.updateFromDOM(); }), 20); }
8783
  });
8802
  });
8803
 
8804
  function onCopyCut(e) {
8805
+ if (!belongsToInput(e) || signalDOMEvent(cm, e)) { return }
8806
  if (cm.somethingSelected()) {
8807
  setLastCopied({lineWise: false, text: cm.getSelections()});
8808
  if (e.type == "cut") { cm.replaceSelection("", null, "cut"); }
8844
  on(div, "cut", onCopyCut);
8845
  };
8846
 
8847
+ ContentEditableInput.prototype.screenReaderLabelChanged = function (label) {
8848
+ // Label for screenreaders, accessibility
8849
+ if(label) {
8850
+ this.div.setAttribute('aria-label', label);
8851
+ } else {
8852
+ this.div.removeAttribute('aria-label');
8853
+ }
8854
+ };
8855
+
8856
  ContentEditableInput.prototype.prepareSelection = function () {
8857
  var result = prepareSelection(this.cm, false);
8858
+ result.focus = document.activeElement == this.div;
8859
  return result
8860
  };
8861
 
8891
  var end = to.line < cm.display.viewTo && posToDOM(cm, to);
8892
  if (!end) {
8893
  var measure = view[view.length - 1].measure;
8894
+ var map = measure.maps ? measure.maps[measure.maps.length - 1] : measure.map;
8895
+ end = {node: map[map.length - 1], offset: map[map.length - 2] - map[map.length - 3]};
8896
  }
8897
 
8898
  if (!start || !end) {
8951
 
8952
  ContentEditableInput.prototype.focus = function () {
8953
  if (this.cm.options.readOnly != "nocursor") {
8954
+ if (!this.selectionInEditor() || document.activeElement != this.div)
8955
  { this.showSelection(this.prepareSelection(), true); }
8956
  this.div.focus();
8957
  }
8992
  // Because Android doesn't allow us to actually detect backspace
8993
  // presses in a sane way, this code checks for when that happens
8994
  // and simulates a backspace press in this case.
8995
+ if (android && chrome && this.cm.display.gutterSpecs.length && isInGutter(sel.anchorNode)) {
8996
  this.cm.triggerOnKeyDown({type: "keydown", keyCode: 8, preventDefault: Math.abs});
8997
  this.blur();
8998
  this.focus();
9181
  addText(cmText);
9182
  return
9183
  }
9184
+ var markerID = node.getAttribute("cm-marker"), range;
9185
  if (markerID) {
9186
  var found = cm.findMarks(Pos(fromLine, 0), Pos(toLine + 1, 0), recognizeMarker(+markerID));
9187
+ if (found.length && (range = found[0].find(0)))
9188
+ { addText(getBetween(cm.doc, range.from, range.to).join(lineSep)); }
9189
  return
9190
  }
9191
  if (node.getAttribute("contenteditable") == "false") { return }
9253
 
9254
  function find(textNode, topNode, offset) {
9255
  for (var i = -1; i < (maps ? maps.length : 0); i++) {
9256
+ var map = i < 0 ? measure.map : maps[i];
9257
+ for (var j = 0; j < map.length; j += 3) {
9258
+ var curNode = map[j + 2];
9259
  if (curNode == textNode || curNode == topNode) {
9260
  var line = lineNo(i < 0 ? lineView.line : lineView.rest[i]);
9261
+ var ch = map[j] + offset;
9262
+ if (offset < 0 || curNode != textNode) { ch = map[j + (offset ? 1 : 0)]; }
9263
  return Pos(line, ch)
9264
  }
9265
  }
9323
  on(te, "paste", function (e) {
9324
  if (signalDOMEvent(cm, e) || handlePaste(e, cm)) { return }
9325
 
9326
+ cm.state.pasteIncoming = +new Date;
9327
  input.fastPoll();
9328
  });
9329
 
9344
  selectInput(te);
9345
  }
9346
  }
9347
+ if (e.type == "cut") { cm.state.cutIncoming = +new Date; }
9348
  }
9349
  on(te, "cut", prepareCopyCut);
9350
  on(te, "copy", prepareCopyCut);
9351
 
9352
  on(display.scroller, "paste", function (e) {
9353
  if (eventInWidget(display, e) || signalDOMEvent(cm, e)) { return }
9354
+ if (!te.dispatchEvent) {
9355
+ cm.state.pasteIncoming = +new Date;
9356
+ input.focus();
9357
+ return
9358
+ }
9359
+
9360
+ // Pass the `paste` event to the textarea so it's handled by its event listener.
9361
+ var event = new Event("paste");
9362
+ event.clipboardData = e.clipboardData;
9363
+ te.dispatchEvent(event);
9364
  });
9365
 
9366
  // Prevent normal selection in the editor (we handle our own)
9393
  this.textarea = this.wrapper.firstChild;
9394
  };
9395
 
9396
+ TextareaInput.prototype.screenReaderLabelChanged = function (label) {
9397
+ // Label for screenreaders, accessibility
9398
+ if(label) {
9399
+ this.textarea.setAttribute('aria-label', label);
9400
+ } else {
9401
+ this.textarea.removeAttribute('aria-label');
9402
+ }
9403
+ };
9404
+
9405
  TextareaInput.prototype.prepareSelection = function () {
9406
  // Redraw the selection and/or cursor
9407
  var cm = this.cm, display = cm.display, doc = cm.doc;
9560
 
9561
  TextareaInput.prototype.onContextMenu = function (e) {
9562
  var input = this, cm = input.cm, display = cm.display, te = input.textarea;
9563
+ if (input.contextMenuPending) { input.contextMenuPending(); }
9564
  var pos = posFromMouse(cm, e), scrollPos = display.scroller.scrollTop;
9565
  if (!pos || presto) { return } // Opera is difficult.
9566
 
9571
  { operation(cm, setSelection)(cm.doc, simpleSelection(pos), sel_dontScroll); }
9572
 
9573
  var oldCSS = te.style.cssText, oldWrapperCSS = input.wrapper.style.cssText;
9574
+ var wrapperBox = input.wrapper.offsetParent.getBoundingClientRect();
9575
+ input.wrapper.style.cssText = "position: static";
9576
  te.style.cssText = "position: absolute; width: 30px; height: 30px;\n top: " + (e.clientY - wrapperBox.top - 5) + "px; left: " + (e.clientX - wrapperBox.left - 5) + "px;\n z-index: 1000; background: " + (ie ? "rgba(255, 255, 255, .05)" : "transparent") + ";\n outline: none; border-width: 0; outline: none; overflow: hidden; opacity: .05; filter: alpha(opacity=5);";
9577
  var oldScrollY;
9578
  if (webkit) { oldScrollY = window.scrollY; } // Work around Chrome issue (#2712)
9581
  display.input.reset();
9582
  // Adds "Select all" to context menu in FF
9583
  if (!cm.somethingSelected()) { te.value = input.prevInput = " "; }
9584
+ input.contextMenuPending = rehide;
9585
  display.selForContextMenu = cm.doc.sel;
9586
  clearTimeout(display.detectingSelectAll);
9587
 
9602
  }
9603
  }
9604
  function rehide() {
9605
+ if (input.contextMenuPending != rehide) { return }
9606
  input.contextMenuPending = false;
9607
  input.wrapper.style.cssText = oldWrapperCSS;
9608
  te.style.cssText = oldCSS;
9642
  TextareaInput.prototype.readOnlyChanged = function (val) {
9643
  if (!val) { this.reset(); }
9644
  this.textarea.disabled = val == "nocursor";
9645
+ this.textarea.readOnly = !!val;
9646
  };
9647
 
9648
  TextareaInput.prototype.setUneditable = function () {};
9694
  textarea.style.display = "";
9695
  if (textarea.form) {
9696
  off(textarea.form, "submit", save);
9697
+ if (!options.leaveSubmitMethodAlone && typeof textarea.form.submit == "function")
9698
  { textarea.form.submit = realSubmit; }
9699
  }
9700
  };
9793
 
9794
  addLegacyProps(CodeMirror);
9795
 
9796
+ CodeMirror.version = "5.59.1";
9797
 
9798
  return CodeMirror;
9799
 
vendor/codemirror/mode/css/css.js CHANGED
@@ -29,7 +29,8 @@ CodeMirror.defineMode("css", function(config, parserConfig) {
29
  valueKeywords = parserConfig.valueKeywords || {},
30
  allowNested = parserConfig.allowNested,
31
  lineComment = parserConfig.lineComment,
32
- supportsAtComponent = parserConfig.supportsAtComponent === true;
 
33
 
34
  var type, override;
35
  function ret(style, tp) { type = tp; return style; }
@@ -63,7 +64,7 @@ CodeMirror.defineMode("css", function(config, parserConfig) {
63
  if (/[\d.]/.test(stream.peek())) {
64
  stream.eatWhile(/[\w.%]/);
65
  return ret("number", "unit");
66
- } else if (stream.match(/^-[\w\\\-]+/)) {
67
  stream.eatWhile(/[\w\\\-]/);
68
  if (stream.match(/^\s*:/, false))
69
  return ret("variable-2", "variable-definition");
@@ -77,12 +78,11 @@ CodeMirror.defineMode("css", function(config, parserConfig) {
77
  return ret("qualifier", "qualifier");
78
  } else if (/[:;{}\[\]\(\)]/.test(ch)) {
79
  return ret(null, ch);
80
- } else if (((ch == "u" || ch == "U") && stream.match(/rl(-prefix)?\(/i)) ||
81
- ((ch == "d" || ch == "D") && stream.match("omain(", true, true)) ||
82
- ((ch == "r" || ch == "R") && stream.match("egexp(", true, true))) {
83
- stream.backUp(1);
84
- state.tokenize = tokenParenthesized;
85
- return ret("property", "word");
86
  } else if (/[\w\\\-]/.test(ch)) {
87
  stream.eatWhile(/[\w\\\-]/);
88
  return ret("property", "word");
@@ -198,7 +198,7 @@ CodeMirror.defineMode("css", function(config, parserConfig) {
198
  override = "property";
199
  return "maybeprop";
200
  } else if (nonStandardPropertyKeywords.hasOwnProperty(word)) {
201
- override = "string-2";
202
  return "maybeprop";
203
  } else if (allowNested) {
204
  override = stream.match(/^\s*:(?:\s|$)/, false) ? "property" : "tag";
@@ -292,7 +292,7 @@ CodeMirror.defineMode("css", function(config, parserConfig) {
292
  else if (propertyKeywords.hasOwnProperty(word))
293
  override = "property";
294
  else if (nonStandardPropertyKeywords.hasOwnProperty(word))
295
- override = "string-2";
296
  else if (valueKeywords.hasOwnProperty(word))
297
  override = "atom";
298
  else if (colorKeywords.hasOwnProperty(word))
@@ -443,117 +443,149 @@ CodeMirror.defineMode("css", function(config, parserConfig) {
443
  "monochrome", "min-monochrome", "max-monochrome", "resolution",
444
  "min-resolution", "max-resolution", "scan", "grid", "orientation",
445
  "device-pixel-ratio", "min-device-pixel-ratio", "max-device-pixel-ratio",
446
- "pointer", "any-pointer", "hover", "any-hover"
447
  ], mediaFeatures = keySet(mediaFeatures_);
448
 
449
  var mediaValueKeywords_ = [
450
  "landscape", "portrait", "none", "coarse", "fine", "on-demand", "hover",
451
- "interlace", "progressive"
 
452
  ], mediaValueKeywords = keySet(mediaValueKeywords_);
453
 
454
  var propertyKeywords_ = [
455
  "align-content", "align-items", "align-self", "alignment-adjust",
456
- "alignment-baseline", "anchor-point", "animation", "animation-delay",
457
  "animation-direction", "animation-duration", "animation-fill-mode",
458
  "animation-iteration-count", "animation-name", "animation-play-state",
459
- "animation-timing-function", "appearance", "azimuth", "backface-visibility",
460
- "background", "background-attachment", "background-blend-mode", "background-clip",
461
- "background-color", "background-image", "background-origin", "background-position",
462
- "background-repeat", "background-size", "baseline-shift", "binding",
463
- "bleed", "bookmark-label", "bookmark-level", "bookmark-state",
464
- "bookmark-target", "border", "border-bottom", "border-bottom-color",
465
- "border-bottom-left-radius", "border-bottom-right-radius",
466
- "border-bottom-style", "border-bottom-width", "border-collapse",
467
- "border-color", "border-image", "border-image-outset",
 
468
  "border-image-repeat", "border-image-slice", "border-image-source",
469
- "border-image-width", "border-left", "border-left-color",
470
- "border-left-style", "border-left-width", "border-radius", "border-right",
471
- "border-right-color", "border-right-style", "border-right-width",
472
- "border-spacing", "border-style", "border-top", "border-top-color",
473
- "border-top-left-radius", "border-top-right-radius", "border-top-style",
474
- "border-top-width", "border-width", "bottom", "box-decoration-break",
475
- "box-shadow", "box-sizing", "break-after", "break-before", "break-inside",
476
- "caption-side", "caret-color", "clear", "clip", "color", "color-profile", "column-count",
477
- "column-fill", "column-gap", "column-rule", "column-rule-color",
478
- "column-rule-style", "column-rule-width", "column-span", "column-width",
479
- "columns", "content", "counter-increment", "counter-reset", "crop", "cue",
480
- "cue-after", "cue-before", "cursor", "direction", "display",
481
- "dominant-baseline", "drop-initial-after-adjust",
482
- "drop-initial-after-align", "drop-initial-before-adjust",
483
- "drop-initial-before-align", "drop-initial-size", "drop-initial-value",
484
- "elevation", "empty-cells", "fit", "fit-position", "flex", "flex-basis",
485
- "flex-direction", "flex-flow", "flex-grow", "flex-shrink", "flex-wrap",
486
- "float", "float-offset", "flow-from", "flow-into", "font", "font-feature-settings",
487
- "font-family", "font-kerning", "font-language-override", "font-size", "font-size-adjust",
488
- "font-stretch", "font-style", "font-synthesis", "font-variant",
489
- "font-variant-alternates", "font-variant-caps", "font-variant-east-asian",
490
- "font-variant-ligatures", "font-variant-numeric", "font-variant-position",
491
- "font-weight", "grid", "grid-area", "grid-auto-columns", "grid-auto-flow",
492
- "grid-auto-rows", "grid-column", "grid-column-end", "grid-column-gap",
493
- "grid-column-start", "grid-gap", "grid-row", "grid-row-end", "grid-row-gap",
494
- "grid-row-start", "grid-template", "grid-template-areas", "grid-template-columns",
495
- "grid-template-rows", "hanging-punctuation", "height", "hyphens",
496
- "icon", "image-orientation", "image-rendering", "image-resolution",
497
- "inline-box-align", "justify-content", "justify-items", "justify-self", "left", "letter-spacing",
498
- "line-break", "line-height", "line-stacking", "line-stacking-ruby",
 
 
 
499
  "line-stacking-shift", "line-stacking-strategy", "list-style",
500
  "list-style-image", "list-style-position", "list-style-type", "margin",
501
- "margin-bottom", "margin-left", "margin-right", "margin-top",
502
- "marks", "marquee-direction", "marquee-loop",
503
- "marquee-play-count", "marquee-speed", "marquee-style", "max-height",
504
- "max-width", "min-height", "min-width", "mix-blend-mode", "move-to", "nav-down", "nav-index",
505
- "nav-left", "nav-right", "nav-up", "object-fit", "object-position",
506
- "opacity", "order", "orphans", "outline",
507
- "outline-color", "outline-offset", "outline-style", "outline-width",
508
- "overflow", "overflow-style", "overflow-wrap", "overflow-x", "overflow-y",
509
- "padding", "padding-bottom", "padding-left", "padding-right", "padding-top",
510
- "page", "page-break-after", "page-break-before", "page-break-inside",
511
- "page-policy", "pause", "pause-after", "pause-before", "perspective",
512
- "perspective-origin", "pitch", "pitch-range", "place-content", "place-items", "place-self", "play-during", "position",
513
- "presentation-level", "punctuation-trim", "quotes", "region-break-after",
514
- "region-break-before", "region-break-inside", "region-fragment",
515
- "rendering-intent", "resize", "rest", "rest-after", "rest-before", "richness",
516
- "right", "rotation", "rotation-point", "ruby-align", "ruby-overhang",
517
- "ruby-position", "ruby-span", "shape-image-threshold", "shape-inside", "shape-margin",
518
- "shape-outside", "size", "speak", "speak-as", "speak-header",
519
- "speak-numeral", "speak-punctuation", "speech-rate", "stress", "string-set",
520
- "tab-size", "table-layout", "target", "target-name", "target-new",
521
- "target-position", "text-align", "text-align-last", "text-decoration",
 
 
 
 
 
 
 
 
 
 
 
 
 
 
522
  "text-decoration-color", "text-decoration-line", "text-decoration-skip",
523
- "text-decoration-style", "text-emphasis", "text-emphasis-color",
524
- "text-emphasis-position", "text-emphasis-style", "text-height",
525
- "text-indent", "text-justify", "text-outline", "text-overflow", "text-shadow",
526
- "text-size-adjust", "text-space-collapse", "text-transform", "text-underline-position",
527
- "text-wrap", "top", "transform", "transform-origin", "transform-style",
528
- "transition", "transition-delay", "transition-duration",
529
- "transition-property", "transition-timing-function", "unicode-bidi",
530
- "user-select", "vertical-align", "visibility", "voice-balance", "voice-duration",
531
- "voice-family", "voice-pitch", "voice-range", "voice-rate", "voice-stress",
532
- "voice-volume", "volume", "white-space", "widows", "width", "will-change", "word-break",
533
- "word-spacing", "word-wrap", "z-index",
 
534
  // SVG-specific
535
  "clip-path", "clip-rule", "mask", "enable-background", "filter", "flood-color",
536
  "flood-opacity", "lighting-color", "stop-color", "stop-opacity", "pointer-events",
537
  "color-interpolation", "color-interpolation-filters",
538
  "color-rendering", "fill", "fill-opacity", "fill-rule", "image-rendering",
539
- "marker", "marker-end", "marker-mid", "marker-start", "shape-rendering", "stroke",
540
  "stroke-dasharray", "stroke-dashoffset", "stroke-linecap", "stroke-linejoin",
541
  "stroke-miterlimit", "stroke-opacity", "stroke-width", "text-rendering",
542
  "baseline-shift", "dominant-baseline", "glyph-orientation-horizontal",
543
- "glyph-orientation-vertical", "text-anchor", "writing-mode"
544
  ], propertyKeywords = keySet(propertyKeywords_);
545
 
546
  var nonStandardPropertyKeywords_ = [
 
 
 
 
 
 
 
 
 
 
 
 
 
547
  "scrollbar-arrow-color", "scrollbar-base-color", "scrollbar-dark-shadow-color",
548
  "scrollbar-face-color", "scrollbar-highlight-color", "scrollbar-shadow-color",
549
- "scrollbar-3d-light-color", "scrollbar-track-color", "shape-inside",
550
- "searchfield-cancel-button", "searchfield-decoration", "searchfield-results-button",
551
- "searchfield-results-decoration", "zoom"
552
  ], nonStandardPropertyKeywords = keySet(nonStandardPropertyKeywords_);
553
 
554
  var fontProperties_ = [
555
- "font-family", "src", "unicode-range", "font-variant", "font-feature-settings",
556
- "font-stretch", "font-weight", "font-style"
557
  ], fontProperties = keySet(fontProperties_);
558
 
559
  var counterDescriptors_ = [
@@ -595,7 +627,7 @@ CodeMirror.defineMode("css", function(config, parserConfig) {
595
  "after-white-space", "ahead", "alias", "all", "all-scroll", "alphabetic", "alternate",
596
  "always", "amharic", "amharic-abegede", "antialiased", "appworkspace",
597
  "arabic-indic", "armenian", "asterisks", "attr", "auto", "auto-flow", "avoid", "avoid-column", "avoid-page",
598
- "avoid-region", "background", "backwards", "baseline", "below", "bidi-override", "binary",
599
  "bengali", "blink", "block", "block-axis", "bold", "bolder", "border", "border-box",
600
  "both", "bottom", "break", "break-all", "break-word", "bullets", "button", "button-bevel",
601
  "buttonface", "buttonhighlight", "buttonshadow", "buttontext", "calc", "cambodian",
@@ -619,7 +651,7 @@ CodeMirror.defineMode("css", function(config, parserConfig) {
619
  "ethiopic-halehame-sid-et", "ethiopic-halehame-so-et",
620
  "ethiopic-halehame-ti-er", "ethiopic-halehame-ti-et", "ethiopic-halehame-tig",
621
  "ethiopic-numeric", "ew-resize", "exclusion", "expanded", "extends", "extra-condensed",
622
- "extra-expanded", "fantasy", "fast", "fill", "fixed", "flat", "flex", "flex-end", "flex-start", "footnotes",
623
  "forwards", "from", "geometricPrecision", "georgian", "graytext", "grid", "groove",
624
  "gujarati", "gurmukhi", "hand", "hangul", "hangul-consonant", "hard-light", "hebrew",
625
  "help", "hidden", "hide", "higher", "highlight", "highlighttext",
@@ -634,7 +666,7 @@ CodeMirror.defineMode("css", function(config, parserConfig) {
634
  "line-through", "linear", "linear-gradient", "lines", "list-item", "listbox", "listitem",
635
  "local", "logical", "loud", "lower", "lower-alpha", "lower-armenian",
636
  "lower-greek", "lower-hexadecimal", "lower-latin", "lower-norwegian",
637
- "lower-roman", "lowercase", "ltr", "luminosity", "malayalam", "match", "matrix", "matrix3d",
638
  "media-controls-background", "media-current-time-display",
639
  "media-fullscreen-button", "media-mute-button", "media-play-button",
640
  "media-return-to-realtime-button", "media-rewind-button",
@@ -643,13 +675,13 @@ CodeMirror.defineMode("css", function(config, parserConfig) {
643
  "media-volume-slider-container", "media-volume-sliderthumb", "medium",
644
  "menu", "menulist", "menulist-button", "menulist-text",
645
  "menulist-textfield", "menutext", "message-box", "middle", "min-intrinsic",
646
- "mix", "mongolian", "monospace", "move", "multiple", "multiply", "myanmar", "n-resize",
647
  "narrower", "ne-resize", "nesw-resize", "no-close-quote", "no-drop",
648
  "no-open-quote", "no-repeat", "none", "normal", "not-allowed", "nowrap",
649
  "ns-resize", "numbers", "numeric", "nw-resize", "nwse-resize", "oblique", "octal", "opacity", "open-quote",
650
  "optimizeLegibility", "optimizeSpeed", "oriya", "oromo", "outset",
651
  "outside", "outside-shape", "overlay", "overline", "padding", "padding-box",
652
- "painted", "page", "paused", "persian", "perspective", "plus-darker", "plus-lighter",
653
  "pointer", "polygon", "portrait", "pre", "pre-line", "pre-wrap", "preserve-3d",
654
  "progress", "push-button", "radial-gradient", "radio", "read-only",
655
  "read-write", "read-write-plaintext-only", "rectangle", "region",
@@ -667,8 +699,8 @@ CodeMirror.defineMode("css", function(config, parserConfig) {
667
  "slider-vertical", "sliderthumb-horizontal", "sliderthumb-vertical", "slow",
668
  "small", "small-caps", "small-caption", "smaller", "soft-light", "solid", "somali",
669
  "source-atop", "source-in", "source-out", "source-over", "space", "space-around", "space-between", "space-evenly", "spell-out", "square",
670
- "square-button", "start", "static", "status-bar", "stretch", "stroke", "sub",
671
- "subpixel-antialiased", "super", "sw-resize", "symbolic", "symbols", "system-ui", "table",
672
  "table-caption", "table-cell", "table-column", "table-column-group",
673
  "table-footer-group", "table-header-group", "table-row", "table-row-group",
674
  "tamil",
@@ -678,10 +710,10 @@ CodeMirror.defineMode("css", function(config, parserConfig) {
678
  "tigrinya-er-abegede", "tigrinya-et", "tigrinya-et-abegede", "to", "top",
679
  "trad-chinese-formal", "trad-chinese-informal", "transform",
680
  "translate", "translate3d", "translateX", "translateY", "translateZ",
681
- "transparent", "ultra-condensed", "ultra-expanded", "underline", "unset", "up",
682
  "upper-alpha", "upper-armenian", "upper-greek", "upper-hexadecimal",
683
  "upper-latin", "upper-norwegian", "upper-roman", "uppercase", "urdu", "url",
684
- "var", "vertical", "vertical-text", "visible", "visibleFill", "visiblePainted",
685
  "visibleStroke", "visual", "w-resize", "wait", "wave", "wider",
686
  "window", "windowframe", "windowtext", "words", "wrap", "wrap-reverse", "x-large", "x-small", "xor",
687
  "xx-large", "xx-small"
29
  valueKeywords = parserConfig.valueKeywords || {},
30
  allowNested = parserConfig.allowNested,
31
  lineComment = parserConfig.lineComment,
32
+ supportsAtComponent = parserConfig.supportsAtComponent === true,
33
+ highlightNonStandardPropertyKeywords = config.highlightNonStandardPropertyKeywords !== false;
34
 
35
  var type, override;
36
  function ret(style, tp) { type = tp; return style; }
64
  if (/[\d.]/.test(stream.peek())) {
65
  stream.eatWhile(/[\w.%]/);
66
  return ret("number", "unit");
67
+ } else if (stream.match(/^-[\w\\\-]*/)) {
68
  stream.eatWhile(/[\w\\\-]/);
69
  if (stream.match(/^\s*:/, false))
70
  return ret("variable-2", "variable-definition");
78
  return ret("qualifier", "qualifier");
79
  } else if (/[:;{}\[\]\(\)]/.test(ch)) {
80
  return ret(null, ch);
81
+ } else if (stream.match(/[\w-.]+(?=\()/)) {
82
+ if (/^(url(-prefix)?|domain|regexp)$/.test(stream.current().toLowerCase())) {
83
+ state.tokenize = tokenParenthesized;
84
+ }
85
+ return ret("variable callee", "variable");
 
86
  } else if (/[\w\\\-]/.test(ch)) {
87
  stream.eatWhile(/[\w\\\-]/);
88
  return ret("property", "word");
198
  override = "property";
199
  return "maybeprop";
200
  } else if (nonStandardPropertyKeywords.hasOwnProperty(word)) {
201
+ override = highlightNonStandardPropertyKeywords ? "string-2" : "property";
202
  return "maybeprop";
203
  } else if (allowNested) {
204
  override = stream.match(/^\s*:(?:\s|$)/, false) ? "property" : "tag";
292
  else if (propertyKeywords.hasOwnProperty(word))
293
  override = "property";
294
  else if (nonStandardPropertyKeywords.hasOwnProperty(word))
295
+ override = highlightNonStandardPropertyKeywords ? "string-2" : "property";
296
  else if (valueKeywords.hasOwnProperty(word))
297
  override = "atom";
298
  else if (colorKeywords.hasOwnProperty(word))
443
  "monochrome", "min-monochrome", "max-monochrome", "resolution",
444
  "min-resolution", "max-resolution", "scan", "grid", "orientation",
445
  "device-pixel-ratio", "min-device-pixel-ratio", "max-device-pixel-ratio",
446
+ "pointer", "any-pointer", "hover", "any-hover", "prefers-color-scheme"
447
  ], mediaFeatures = keySet(mediaFeatures_);
448
 
449
  var mediaValueKeywords_ = [
450
  "landscape", "portrait", "none", "coarse", "fine", "on-demand", "hover",
451
+ "interlace", "progressive",
452
+ "dark", "light"
453
  ], mediaValueKeywords = keySet(mediaValueKeywords_);
454
 
455
  var propertyKeywords_ = [
456
  "align-content", "align-items", "align-self", "alignment-adjust",
457
+ "alignment-baseline", "all", "anchor-point", "animation", "animation-delay",
458
  "animation-direction", "animation-duration", "animation-fill-mode",
459
  "animation-iteration-count", "animation-name", "animation-play-state",
460
+ "animation-timing-function", "appearance", "azimuth", "backdrop-filter",
461
+ "backface-visibility", "background", "background-attachment",
462
+ "background-blend-mode", "background-clip", "background-color",
463
+ "background-image", "background-origin", "background-position",
464
+ "background-position-x", "background-position-y", "background-repeat",
465
+ "background-size", "baseline-shift", "binding", "bleed", "block-size",
466
+ "bookmark-label", "bookmark-level", "bookmark-state", "bookmark-target",
467
+ "border", "border-bottom", "border-bottom-color", "border-bottom-left-radius",
468
+ "border-bottom-right-radius", "border-bottom-style", "border-bottom-width",
469
+ "border-collapse", "border-color", "border-image", "border-image-outset",
470
  "border-image-repeat", "border-image-slice", "border-image-source",
471
+ "border-image-width", "border-left", "border-left-color", "border-left-style",
472
+ "border-left-width", "border-radius", "border-right", "border-right-color",
473
+ "border-right-style", "border-right-width", "border-spacing", "border-style",
474
+ "border-top", "border-top-color", "border-top-left-radius",
475
+ "border-top-right-radius", "border-top-style", "border-top-width",
476
+ "border-width", "bottom", "box-decoration-break", "box-shadow", "box-sizing",
477
+ "break-after", "break-before", "break-inside", "caption-side", "caret-color",
478
+ "clear", "clip", "color", "color-profile", "column-count", "column-fill",
479
+ "column-gap", "column-rule", "column-rule-color", "column-rule-style",
480
+ "column-rule-width", "column-span", "column-width", "columns", "contain",
481
+ "content", "counter-increment", "counter-reset", "crop", "cue", "cue-after",
482
+ "cue-before", "cursor", "direction", "display", "dominant-baseline",
483
+ "drop-initial-after-adjust", "drop-initial-after-align",
484
+ "drop-initial-before-adjust", "drop-initial-before-align", "drop-initial-size",
485
+ "drop-initial-value", "elevation", "empty-cells", "fit", "fit-position",
486
+ "flex", "flex-basis", "flex-direction", "flex-flow", "flex-grow",
487
+ "flex-shrink", "flex-wrap", "float", "float-offset", "flow-from", "flow-into",
488
+ "font", "font-family", "font-feature-settings", "font-kerning",
489
+ "font-language-override", "font-optical-sizing", "font-size",
490
+ "font-size-adjust", "font-stretch", "font-style", "font-synthesis",
491
+ "font-variant", "font-variant-alternates", "font-variant-caps",
492
+ "font-variant-east-asian", "font-variant-ligatures", "font-variant-numeric",
493
+ "font-variant-position", "font-variation-settings", "font-weight", "gap",
494
+ "grid", "grid-area", "grid-auto-columns", "grid-auto-flow", "grid-auto-rows",
495
+ "grid-column", "grid-column-end", "grid-column-gap", "grid-column-start",
496
+ "grid-gap", "grid-row", "grid-row-end", "grid-row-gap", "grid-row-start",
497
+ "grid-template", "grid-template-areas", "grid-template-columns",
498
+ "grid-template-rows", "hanging-punctuation", "height", "hyphens", "icon",
499
+ "image-orientation", "image-rendering", "image-resolution", "inline-box-align",
500
+ "inset", "inset-block", "inset-block-end", "inset-block-start", "inset-inline",
501
+ "inset-inline-end", "inset-inline-start", "isolation", "justify-content",
502
+ "justify-items", "justify-self", "left", "letter-spacing", "line-break",
503
+ "line-height", "line-height-step", "line-stacking", "line-stacking-ruby",
504
  "line-stacking-shift", "line-stacking-strategy", "list-style",
505
  "list-style-image", "list-style-position", "list-style-type", "margin",
506
+ "margin-bottom", "margin-left", "margin-right", "margin-top", "marks",
507
+ "marquee-direction", "marquee-loop", "marquee-play-count", "marquee-speed",
508
+ "marquee-style", "mask-clip", "mask-composite", "mask-image", "mask-mode",
509
+ "mask-origin", "mask-position", "mask-repeat", "mask-size","mask-type",
510
+ "max-block-size", "max-height", "max-inline-size",
511
+ "max-width", "min-block-size", "min-height", "min-inline-size", "min-width",
512
+ "mix-blend-mode", "move-to", "nav-down", "nav-index", "nav-left", "nav-right",
513
+ "nav-up", "object-fit", "object-position", "offset", "offset-anchor",
514
+ "offset-distance", "offset-path", "offset-position", "offset-rotate",
515
+ "opacity", "order", "orphans", "outline", "outline-color", "outline-offset",
516
+ "outline-style", "outline-width", "overflow", "overflow-style",
517
+ "overflow-wrap", "overflow-x", "overflow-y", "padding", "padding-bottom",
518
+ "padding-left", "padding-right", "padding-top", "page", "page-break-after",
519
+ "page-break-before", "page-break-inside", "page-policy", "pause",
520
+ "pause-after", "pause-before", "perspective", "perspective-origin", "pitch",
521
+ "pitch-range", "place-content", "place-items", "place-self", "play-during",
522
+ "position", "presentation-level", "punctuation-trim", "quotes",
523
+ "region-break-after", "region-break-before", "region-break-inside",
524
+ "region-fragment", "rendering-intent", "resize", "rest", "rest-after",
525
+ "rest-before", "richness", "right", "rotate", "rotation", "rotation-point",
526
+ "row-gap", "ruby-align", "ruby-overhang", "ruby-position", "ruby-span",
527
+ "scale", "scroll-behavior", "scroll-margin", "scroll-margin-block",
528
+ "scroll-margin-block-end", "scroll-margin-block-start", "scroll-margin-bottom",
529
+ "scroll-margin-inline", "scroll-margin-inline-end",
530
+ "scroll-margin-inline-start", "scroll-margin-left", "scroll-margin-right",
531
+ "scroll-margin-top", "scroll-padding", "scroll-padding-block",
532
+ "scroll-padding-block-end", "scroll-padding-block-start",
533
+ "scroll-padding-bottom", "scroll-padding-inline", "scroll-padding-inline-end",
534
+ "scroll-padding-inline-start", "scroll-padding-left", "scroll-padding-right",
535
+ "scroll-padding-top", "scroll-snap-align", "scroll-snap-type",
536
+ "shape-image-threshold", "shape-inside", "shape-margin", "shape-outside",
537
+ "size", "speak", "speak-as", "speak-header", "speak-numeral",
538
+ "speak-punctuation", "speech-rate", "stress", "string-set", "tab-size",
539
+ "table-layout", "target", "target-name", "target-new", "target-position",
540
+ "text-align", "text-align-last", "text-combine-upright", "text-decoration",
541
  "text-decoration-color", "text-decoration-line", "text-decoration-skip",
542
+ "text-decoration-skip-ink", "text-decoration-style", "text-emphasis",
543
+ "text-emphasis-color", "text-emphasis-position", "text-emphasis-style",
544
+ "text-height", "text-indent", "text-justify", "text-orientation",
545
+ "text-outline", "text-overflow", "text-rendering", "text-shadow",
546
+ "text-size-adjust", "text-space-collapse", "text-transform",
547
+ "text-underline-position", "text-wrap", "top", "touch-action", "transform", "transform-origin",
548
+ "transform-style", "transition", "transition-delay", "transition-duration",
549
+ "transition-property", "transition-timing-function", "translate",
550
+ "unicode-bidi", "user-select", "vertical-align", "visibility", "voice-balance",
551
+ "voice-duration", "voice-family", "voice-pitch", "voice-range", "voice-rate",
552
+ "voice-stress", "voice-volume", "volume", "white-space", "widows", "width",
553
+ "will-change", "word-break", "word-spacing", "word-wrap", "writing-mode", "z-index",
554
  // SVG-specific
555
  "clip-path", "clip-rule", "mask", "enable-background", "filter", "flood-color",
556
  "flood-opacity", "lighting-color", "stop-color", "stop-opacity", "pointer-events",
557
  "color-interpolation", "color-interpolation-filters",
558
  "color-rendering", "fill", "fill-opacity", "fill-rule", "image-rendering",
559
+ "marker", "marker-end", "marker-mid", "marker-start", "paint-order", "shape-rendering", "stroke",
560
  "stroke-dasharray", "stroke-dashoffset", "stroke-linecap", "stroke-linejoin",
561
  "stroke-miterlimit", "stroke-opacity", "stroke-width", "text-rendering",
562
  "baseline-shift", "dominant-baseline", "glyph-orientation-horizontal",
563
+ "glyph-orientation-vertical", "text-anchor", "writing-mode",
564
  ], propertyKeywords = keySet(propertyKeywords_);
565
 
566
  var nonStandardPropertyKeywords_ = [
567
+ "border-block", "border-block-color", "border-block-end",
568
+ "border-block-end-color", "border-block-end-style", "border-block-end-width",
569
+ "border-block-start", "border-block-start-color", "border-block-start-style",
570
+ "border-block-start-width", "border-block-style", "border-block-width",
571
+ "border-inline", "border-inline-color", "border-inline-end",
572
+ "border-inline-end-color", "border-inline-end-style",
573
+ "border-inline-end-width", "border-inline-start", "border-inline-start-color",
574
+ "border-inline-start-style", "border-inline-start-width",
575
+ "border-inline-style", "border-inline-width", "margin-block",
576
+ "margin-block-end", "margin-block-start", "margin-inline", "margin-inline-end",
577
+ "margin-inline-start", "padding-block", "padding-block-end",
578
+ "padding-block-start", "padding-inline", "padding-inline-end",
579
+ "padding-inline-start", "scroll-snap-stop", "scrollbar-3d-light-color",
580
  "scrollbar-arrow-color", "scrollbar-base-color", "scrollbar-dark-shadow-color",
581
  "scrollbar-face-color", "scrollbar-highlight-color", "scrollbar-shadow-color",
582
+ "scrollbar-track-color", "searchfield-cancel-button", "searchfield-decoration",
583
+ "searchfield-results-button", "searchfield-results-decoration", "shape-inside", "zoom"
 
584
  ], nonStandardPropertyKeywords = keySet(nonStandardPropertyKeywords_);
585
 
586
  var fontProperties_ = [
587
+ "font-display", "font-family", "src", "unicode-range", "font-variant",
588
+ "font-feature-settings", "font-stretch", "font-weight", "font-style"
589
  ], fontProperties = keySet(fontProperties_);
590
 
591
  var counterDescriptors_ = [
627
  "after-white-space", "ahead", "alias", "all", "all-scroll", "alphabetic", "alternate",
628
  "always", "amharic", "amharic-abegede", "antialiased", "appworkspace",
629
  "arabic-indic", "armenian", "asterisks", "attr", "auto", "auto-flow", "avoid", "avoid-column", "avoid-page",
630
+ "avoid-region", "axis-pan", "background", "backwards", "baseline", "below", "bidi-override", "binary",
631
  "bengali", "blink", "block", "block-axis", "bold", "bolder", "border", "border-box",
632
  "both", "bottom", "break", "break-all", "break-word", "bullets", "button", "button-bevel",
633
  "buttonface", "buttonhighlight", "buttonshadow", "buttontext", "calc", "cambodian",
651
  "ethiopic-halehame-sid-et", "ethiopic-halehame-so-et",
652
  "ethiopic-halehame-ti-er", "ethiopic-halehame-ti-et", "ethiopic-halehame-tig",
653
  "ethiopic-numeric", "ew-resize", "exclusion", "expanded", "extends", "extra-condensed",
654
+ "extra-expanded", "fantasy", "fast", "fill", "fill-box", "fixed", "flat", "flex", "flex-end", "flex-start", "footnotes",
655
  "forwards", "from", "geometricPrecision", "georgian", "graytext", "grid", "groove",
656
  "gujarati", "gurmukhi", "hand", "hangul", "hangul-consonant", "hard-light", "hebrew",
657
  "help", "hidden", "hide", "higher", "highlight", "highlighttext",
666
  "line-through", "linear", "linear-gradient", "lines", "list-item", "listbox", "listitem",
667
  "local", "logical", "loud", "lower", "lower-alpha", "lower-armenian",
668
  "lower-greek", "lower-hexadecimal", "lower-latin", "lower-norwegian",
669
+ "lower-roman", "lowercase", "ltr", "luminosity", "malayalam", "manipulation", "match", "matrix", "matrix3d",
670
  "media-controls-background", "media-current-time-display",
671
  "media-fullscreen-button", "media-mute-button", "media-play-button",
672
  "media-return-to-realtime-button", "media-rewind-button",
675
  "media-volume-slider-container", "media-volume-sliderthumb", "medium",
676
  "menu", "menulist", "menulist-button", "menulist-text",
677
  "menulist-textfield", "menutext", "message-box", "middle", "min-intrinsic",
678
+ "mix", "mongolian", "monospace", "move", "multiple", "multiple_mask_images", "multiply", "myanmar", "n-resize",
679
  "narrower", "ne-resize", "nesw-resize", "no-close-quote", "no-drop",
680
  "no-open-quote", "no-repeat", "none", "normal", "not-allowed", "nowrap",
681
  "ns-resize", "numbers", "numeric", "nw-resize", "nwse-resize", "oblique", "octal", "opacity", "open-quote",
682
  "optimizeLegibility", "optimizeSpeed", "oriya", "oromo", "outset",
683
  "outside", "outside-shape", "overlay", "overline", "padding", "padding-box",
684
+ "painted", "page", "paused", "persian", "perspective", "pinch-zoom", "plus-darker", "plus-lighter",
685
  "pointer", "polygon", "portrait", "pre", "pre-line", "pre-wrap", "preserve-3d",
686
  "progress", "push-button", "radial-gradient", "radio", "read-only",
687
  "read-write", "read-write-plaintext-only", "rectangle", "region",
699
  "slider-vertical", "sliderthumb-horizontal", "sliderthumb-vertical", "slow",
700
  "small", "small-caps", "small-caption", "smaller", "soft-light", "solid", "somali",
701
  "source-atop", "source-in", "source-out", "source-over", "space", "space-around", "space-between", "space-evenly", "spell-out", "square",
702
+ "square-button", "start", "static", "status-bar", "stretch", "stroke", "stroke-box", "sub",
703
+ "subpixel-antialiased", "svg_masks", "super", "sw-resize", "symbolic", "symbols", "system-ui", "table",
704
  "table-caption", "table-cell", "table-column", "table-column-group",
705
  "table-footer-group", "table-header-group", "table-row", "table-row-group",
706
  "tamil",
710
  "tigrinya-er-abegede", "tigrinya-et", "tigrinya-et-abegede", "to", "top",
711
  "trad-chinese-formal", "trad-chinese-informal", "transform",
712
  "translate", "translate3d", "translateX", "translateY", "translateZ",
713
+ "transparent", "ultra-condensed", "ultra-expanded", "underline", "unidirectional-pan", "unset", "up",
714
  "upper-alpha", "upper-armenian", "upper-greek", "upper-hexadecimal",
715
  "upper-latin", "upper-norwegian", "upper-roman", "uppercase", "urdu", "url",
716
+ "var", "vertical", "vertical-text", "view-box", "visible", "visibleFill", "visiblePainted",
717
  "visibleStroke", "visual", "w-resize", "wait", "wave", "wider",
718
  "window", "windowframe", "windowtext", "words", "wrap", "wrap-reverse", "x-large", "x-small", "xor",
719
  "xx-large", "xx-small"
vendor/codemirror/mode/css/gss.html CHANGED
@@ -13,7 +13,7 @@
13
  <script src="../../addon/hint/css-hint.js"></script>
14
  <style>.CodeMirror {background: #f8f8f8;}</style>
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>
13
  <script src="../../addon/hint/css-hint.js"></script>
14
  <style>.CodeMirror {background: #f8f8f8;}</style>
15
  <div id=nav>
16
+ <a href="https://codemirror.net"><h1>CodeMirror</h1><img id=logo src="../../doc/logo.png" alt=""></a>
17
 
18
  <ul>
19
  <li><a href="../../index.html">Home</a>
vendor/codemirror/mode/css/index.html CHANGED
@@ -12,7 +12,7 @@
12
  <script src="../../addon/hint/css-hint.js"></script>
13
  <style>.CodeMirror {background: #f8f8f8;}</style>
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>
@@ -68,6 +68,12 @@ code {
68
  });
69
  </script>
70
 
 
 
 
 
 
 
71
  <p><strong>MIME types defined:</strong> <code>text/css</code>, <code>text/x-scss</code> (<a href="scss.html">demo</a>), <code>text/x-less</code> (<a href="less.html">demo</a>).</p>
72
 
73
  <p><strong>Parsing/Highlighting Tests:</strong> <a href="../../test/index.html#css_*">normal</a>, <a href="../../test/index.html#verbose,css_*">verbose</a>.</p>
12
  <script src="../../addon/hint/css-hint.js"></script>
13
  <style>.CodeMirror {background: #f8f8f8;}</style>
14
  <div id=nav>
15
+ <a href="https://codemirror.net"><h1>CodeMirror</h1><img id=logo src="../../doc/logo.png" alt=""></a>
16
 
17
  <ul>
18
  <li><a href="../../index.html">Home</a>
68
  });
69
  </script>
70
 
71
+ <p>CSS mode supports this option:</p>
72
+ <d1>
73
+ <dt><code><strong>highlightNonStandardPropertyKeywords</strong>: boolean</code></dt>
74
+ <dd>Whether to highlight non-standard CSS property keywords such as <code>margin-inline</code> or <code>zoom</code> (default: <code>true</code>).</dd>
75
+ </d1>
76
+
77
  <p><strong>MIME types defined:</strong> <code>text/css</code>, <code>text/x-scss</code> (<a href="scss.html">demo</a>), <code>text/x-less</code> (<a href="less.html">demo</a>).</p>
78
 
79
  <p><strong>Parsing/Highlighting Tests:</strong> <a href="../../test/index.html#css_*">normal</a>, <a href="../../test/index.html#verbose,css_*">verbose</a>.</p>
vendor/codemirror/mode/css/less.html CHANGED
@@ -10,7 +10,7 @@
10
  <script src="css.js"></script>
11
  <style>.CodeMirror {border: 1px solid #ddd; line-height: 1.2;}</style>
12
  <div id=nav>
13
- <a href="https://codemirror.net"><h1>CodeMirror</h1><img id=logo src="../../doc/logo.png"></a>
14
 
15
  <ul>
16
  <li><a href="../../index.html">Home</a>
10
  <script src="css.js"></script>
11
  <style>.CodeMirror {border: 1px solid #ddd; line-height: 1.2;}</style>
12
  <div id=nav>
13
+ <a href="https://codemirror.net"><h1>CodeMirror</h1><img id=logo src="../../doc/logo.png" alt=""></a>
14
 
15
  <ul>
16
  <li><a href="../../index.html">Home</a>
vendor/codemirror/mode/css/less_test.js CHANGED
@@ -10,8 +10,8 @@
10
  MT("variable",
11
  "[variable-2 @base]: [atom #f04615];",
12
  "[qualifier .class] {",
13
- " [property width]: [variable percentage]([number 0.5]); [comment // returns `50%`]",
14
- " [property color]: [variable saturate]([variable-2 @base], [number 5%]);",
15
  "}");
16
 
17
  MT("amp",
@@ -26,10 +26,10 @@
26
 
27
  MT("mixin",
28
  "[qualifier .mixin] ([variable dark]; [variable-2 @color]) {",
29
- " [property color]: [atom darken]([variable-2 @color], [number 10%]);",
30
  "}",
31
  "[qualifier .mixin] ([variable light]; [variable-2 @color]) {",
32
- " [property color]: [atom lighten]([variable-2 @color], [number 10%]);",
33
  "}",
34
  "[qualifier .mixin] ([variable-2 @_]; [variable-2 @color]) {",
35
  " [property display]: [atom block];",
10
  MT("variable",
11
  "[variable-2 @base]: [atom #f04615];",
12
  "[qualifier .class] {",
13
+ " [property width]: [variable&callee percentage]([number 0.5]); [comment // returns `50%`]",
14
+ " [property color]: [variable&callee saturate]([variable-2 @base], [number 5%]);",
15
  "}");
16
 
17
  MT("amp",
26
 
27
  MT("mixin",
28
  "[qualifier .mixin] ([variable dark]; [variable-2 @color]) {",
29
+ " [property color]: [variable&callee darken]([variable-2 @color], [number 10%]);",
30
  "}",
31
  "[qualifier .mixin] ([variable light]; [variable-2 @color]) {",
32
+ " [property color]: [variable&callee lighten]([variable-2 @color], [number 10%]);",
33
  "}",
34
  "[qualifier .mixin] ([variable-2 @_]; [variable-2 @color]) {",
35
  " [property display]: [atom block];",
vendor/codemirror/mode/css/scss.html CHANGED
@@ -10,7 +10,7 @@
10
  <script src="css.js"></script>
11
  <style>.CodeMirror {background: #f8f8f8;}</style>
12
  <div id=nav>
13
- <a href="https://codemirror.net"><h1>CodeMirror</h1><img id=logo src="../../doc/logo.png"></a>
14
 
15
  <ul>
16
  <li><a href="../../index.html">Home</a>
10
  <script src="css.js"></script>
11
  <style>.CodeMirror {background: #f8f8f8;}</style>
12
  <div id=nav>
13
+ <a href="https://codemirror.net"><h1>CodeMirror</h1><img id=logo src="../../doc/logo.png" alt=""></a>
14
 
15
  <ul>
16
  <li><a href="../../index.html">Home</a>
vendor/codemirror/mode/css/scss_test.js CHANGED
@@ -6,19 +6,19 @@
6
  function MT(name) { test.mode(name, mode, Array.prototype.slice.call(arguments, 1), "scss"); }
7
 
8
  MT('url_with_quotation',
9
- "[tag foo] { [property background]:[atom url]([string test.jpg]) }");
10
 
11
  MT('url_with_double_quotes',
12
- "[tag foo] { [property background]:[atom url]([string \"test.jpg\"]) }");
13
 
14
  MT('url_with_single_quotes',
15
- "[tag foo] { [property background]:[atom url]([string \'test.jpg\']) }");
16
 
17
  MT('string',
18
  "[def @import] [string \"compass/css3\"]");
19
 
20
  MT('important_keyword',
21
- "[tag foo] { [property background]:[atom url]([string \'test.jpg\']) [keyword !important] }");
22
 
23
  MT('variable',
24
  "[variable-2 $blue]:[atom #333]");
@@ -95,7 +95,7 @@
95
 
96
  MT('indent_parentheses',
97
  "[tag foo] {",
98
- " [property color]: [atom darken]([variable-2 $blue],",
99
  " [number 9%]);",
100
  "}");
101
 
6
  function MT(name) { test.mode(name, mode, Array.prototype.slice.call(arguments, 1), "scss"); }
7
 
8
  MT('url_with_quotation',
9
+ "[tag foo] { [property background]:[variable&callee url]([string test.jpg]) }");
10
 
11
  MT('url_with_double_quotes',
12
+ "[tag foo] { [property background]:[variable&callee url]([string \"test.jpg\"]) }");
13
 
14
  MT('url_with_single_quotes',
15
+ "[tag foo] { [property background]:[variable&callee url]([string \'test.jpg\']) }");
16
 
17
  MT('string',
18
  "[def @import] [string \"compass/css3\"]");
19
 
20
  MT('important_keyword',
21
+ "[tag foo] { [property background]:[variable&callee url]([string \'test.jpg\']) [keyword !important] }");
22
 
23
  MT('variable',
24
  "[variable-2 $blue]:[atom #333]");
95
 
96
  MT('indent_parentheses',
97
  "[tag foo] {",
98
+ " [property color]: [variable&callee darken]([variable-2 $blue],",
99
  " [number 9%]);",
100
  "}");
101
 
vendor/codemirror/mode/css/test.js CHANGED
@@ -89,11 +89,11 @@
89
  "[tag foo] { [property margin]: [number 0]; [property padding]: [number 0]; }");
90
 
91
  MT("tagTwoPropertiesURL",
92
- "[tag foo] { [property background]: [atom url]([string //example.com/foo.png]); [property padding]: [number 0]; }");
93
 
94
  MT("indent_tagSelector",
95
  "[tag strong], [tag em] {",
96
- " [property background]: [atom rgba](",
97
  " [number 255], [number 255], [number 0], [number .2]",
98
  " );",
99
  "}");
@@ -114,7 +114,7 @@
114
 
115
  MT("indent_parentheses",
116
  "[tag foo]:[variable-3 before] {",
117
- " [property background]: [atom url](",
118
  "[string blahblah]",
119
  "[string etc]",
120
  "[string ]) [keyword !important];",
@@ -124,20 +124,20 @@
124
  "[def @font-face] {",
125
  " [property font-family]: [string 'myfont'];",
126
  " [error nonsense]: [string 'abc'];",
127
- " [property src]: [atom url]([string http://blah]),",
128
- " [atom url]([string http://foo]);",
129
  "}");
130
 
131
  MT("empty_url",
132
- "[def @import] [atom url]() [attribute screen];");
133
 
134
  MT("parens",
135
  "[qualifier .foo] {",
136
- " [property background-image]: [variable fade]([atom #000], [number 20%]);",
137
- " [property border-image]: [atom linear-gradient](",
138
  " [atom to] [atom bottom],",
139
- " [variable fade]([atom #000], [number 20%]) [number 0%],",
140
- " [variable fade]([atom #000], [number 20%]) [number 100%]",
141
  " );",
142
  "}");
143
 
@@ -146,7 +146,15 @@
146
  " [variable-2 --main-color]: [atom #06c];",
147
  "}",
148
  "[tag h1][builtin #foo] {",
149
- " [property color]: [atom var]([variable-2 --main-color]);",
 
 
 
 
 
 
 
 
150
  "}");
151
 
152
  MT("supports",
@@ -155,10 +163,10 @@
155
  "}");
156
 
157
  MT("document",
158
- "[def @document] [tag url]([string http://blah]),",
159
- " [tag url-prefix]([string https://]),",
160
- " [tag domain]([string blah.com]),",
161
- " [tag regexp]([string \".*blah.+\"]) {",
162
  " [builtin #id] {",
163
  " [property background-color]: [keyword white];",
164
  " }",
@@ -168,16 +176,16 @@
168
  "}");
169
 
170
  MT("document_url",
171
- "[def @document] [tag url]([string http://blah]) { [qualifier .class] { } }");
172
 
173
  MT("document_urlPrefix",
174
- "[def @document] [tag url-prefix]([string https://]) { [builtin #id] { } }");
175
 
176
  MT("document_domain",
177
- "[def @document] [tag domain]([string blah.com]) { [tag foo] { } }");
178
 
179
  MT("document_regexp",
180
- "[def @document] [tag regexp]([string \".*blah.+\"]) { [builtin #id] { } }");
181
 
182
  MT("counter-style",
183
  "[def @counter-style] [variable binary] {",
@@ -199,11 +207,11 @@
199
  "[tag ol][qualifier .roman] { [property list-style]: [variable simple-roman]; }");
200
 
201
  MT("counter-style-symbols",
202
- "[tag ol] { [property list-style]: [atom symbols]([atom cyclic] [string \"*\"] [string \"\\2020\"] [string \"\\2021\"] [string \"\\A7\"]); }");
203
 
204
  MT("comment-does-not-disrupt",
205
  "[def @font-face] [comment /* foo */] {",
206
- " [property src]: [atom url]([string x]);",
207
  " [property font-family]: [variable One];",
208
  "}")
209
  })();
89
  "[tag foo] { [property margin]: [number 0]; [property padding]: [number 0]; }");
90
 
91
  MT("tagTwoPropertiesURL",
92
+ "[tag foo] { [property background]: [variable&callee url]([string //example.com/foo.png]); [property padding]: [number 0]; }");
93
 
94
  MT("indent_tagSelector",
95
  "[tag strong], [tag em] {",
96
+ " [property background]: [variable&callee rgba](",
97
  " [number 255], [number 255], [number 0], [number .2]",
98
  " );",
99
  "}");
114
 
115
  MT("indent_parentheses",
116
  "[tag foo]:[variable-3 before] {",
117
+ " [property background]: [variable&callee url](",
118
  "[string blahblah]",
119
  "[string etc]",
120
  "[string ]) [keyword !important];",
124
  "[def @font-face] {",
125
  " [property font-family]: [string 'myfont'];",
126
  " [error nonsense]: [string 'abc'];",
127
+ " [property src]: [variable&callee url]([string http://blah]),",
128
+ " [variable&callee url]([string http://foo]);",
129
  "}");
130
 
131
  MT("empty_url",
132
+ "[def @import] [variable&callee url]() [attribute screen];");
133
 
134
  MT("parens",
135
  "[qualifier .foo] {",
136
+ " [property background-image]: [variable&callee fade]([atom #000], [number 20%]);",
137
+ " [property border-image]: [variable&callee linear-gradient](",
138
  " [atom to] [atom bottom],",
139
+ " [variable&callee fade]([atom #000], [number 20%]) [number 0%],",
140
+ " [variable&callee fade]([atom #000], [number 20%]) [number 100%]",
141
  " );",
142
  "}");
143
 
146
  " [variable-2 --main-color]: [atom #06c];",
147
  "}",
148
  "[tag h1][builtin #foo] {",
149
+ " [property color]: [variable&callee var]([variable-2 --main-color]);",
150
+ "}");
151
+
152
+ MT("blank_css_variable",
153
+ ":[variable-3 root] {",
154
+ " [variable-2 --]: [atom #06c];",
155
+ "}",
156
+ "[tag h1][builtin #foo] {",
157
+ " [property color]: [variable&callee var]([variable-2 --]);",
158
  "}");
159
 
160
  MT("supports",
163
  "}");
164
 
165
  MT("document",
166
+ "[def @document] [variable&callee url]([string http://blah]),",
167
+ " [variable&callee url-prefix]([string https://]),",
168
+ " [variable&callee domain]([string blah.com]),",
169
+ " [variable&callee regexp]([string \".*blah.+\"]) {",
170
  " [builtin #id] {",
171
  " [property background-color]: [keyword white];",
172
  " }",
176
  "}");
177
 
178
  MT("document_url",
179
+ "[def @document] [variable&callee url]([string http://blah]) { [qualifier .class] { } }");
180
 
181
  MT("document_urlPrefix",
182
+ "[def @document] [variable&callee url-prefix]([string https://]) { [builtin #id] { } }");
183
 
184
  MT("document_domain",
185
+ "[def @document] [variable&callee domain]([string blah.com]) { [tag foo] { } }");
186
 
187
  MT("document_regexp",
188
+ "[def @document] [variable&callee regexp]([string \".*blah.+\"]) { [builtin #id] { } }");
189
 
190
  MT("counter-style",
191
  "[def @counter-style] [variable binary] {",
207
  "[tag ol][qualifier .roman] { [property list-style]: [variable simple-roman]; }");
208
 
209
  MT("counter-style-symbols",
210
+ "[tag ol] { [property list-style]: [variable&callee symbols]([atom cyclic] [string \"*\"] [string \"\\2020\"] [string \"\\2021\"] [string \"\\A7\"]); }");
211
 
212
  MT("comment-does-not-disrupt",
213
  "[def @font-face] [comment /* foo */] {",
214
+ " [property src]: [variable&callee url]([string x]);",
215
  " [property font-family]: [variable One];",
216
  "}")
217
  })();
vendor/codemirror/mode/htmlmixed/htmlmixed.js CHANGED
@@ -74,7 +74,8 @@
74
  name: "xml",
75
  htmlMode: true,
76
  multilineTagIndentFactor: parserConfig.multilineTagIndentFactor,
77
- multilineTagIndentPastTag: parserConfig.multilineTagIndentPastTag
 
78
  });
79
 
80
  var tags = {};
@@ -105,7 +106,7 @@
105
  return maybeBackup(stream, endTag, state.localMode.token(stream, state.localState));
106
  };
107
  state.localMode = mode;
108
- state.localState = CodeMirror.startState(mode, htmlMode.indent(state.htmlState, ""));
109
  } else if (state.inTag) {
110
  state.inTag += stream.current()
111
  if (stream.eol()) state.inTag += " "
@@ -135,7 +136,7 @@
135
 
136
  indent: function (state, textAfter, line) {
137
  if (!state.localMode || /^\s*<\//.test(textAfter))
138
- return htmlMode.indent(state.htmlState, textAfter);
139
  else if (state.localMode.indent)
140
  return state.localMode.indent(state.localState, textAfter, line);
141
  else
74
  name: "xml",
75
  htmlMode: true,
76
  multilineTagIndentFactor: parserConfig.multilineTagIndentFactor,
77
+ multilineTagIndentPastTag: parserConfig.multilineTagIndentPastTag,
78
+ allowMissingTagName: parserConfig.allowMissingTagName,
79
  });
80
 
81
  var tags = {};
106
  return maybeBackup(stream, endTag, state.localMode.token(stream, state.localState));
107
  };
108
  state.localMode = mode;
109
+ state.localState = CodeMirror.startState(mode, htmlMode.indent(state.htmlState, "", ""));
110
  } else if (state.inTag) {
111
  state.inTag += stream.current()
112
  if (stream.eol()) state.inTag += " "
136
 
137
  indent: function (state, textAfter, line) {
138
  if (!state.localMode || /^\s*<\//.test(textAfter))
139
+ return htmlMode.indent(state.htmlState, textAfter, line);
140
  else if (state.localMode.indent)
141
  return state.localMode.indent(state.localState, textAfter, line);
142
  else
vendor/codemirror/mode/htmlmixed/index.html CHANGED
@@ -14,7 +14,7 @@
14
  <script src="htmlmixed.js"></script>
15
  <style>.CodeMirror {border-top: 1px solid black; border-bottom: 1px solid black;}</style>
16
  <div id=nav>
17
- <a href="https://codemirror.net"><h1>CodeMirror</h1><img id=logo src="../../doc/logo.png"></a>
18
 
19
  <ul>
20
  <li><a href="../../index.html">Home</a>
14
  <script src="htmlmixed.js"></script>
15
  <style>.CodeMirror {border-top: 1px solid black; border-bottom: 1px solid black;}</style>
16
  <div id=nav>
17
+ <a href="https://codemirror.net"><h1>CodeMirror</h1><img id=logo src="../../doc/logo.png" alt=""></a>
18
 
19
  <ul>
20
  <li><a href="../../index.html">Home</a>
vendor/codemirror/mode/javascript/index.html CHANGED
@@ -12,7 +12,7 @@
12
  <script src="javascript.js"></script>
13
  <style>.CodeMirror {border-top: 1px solid black; border-bottom: 1px solid black;}</style>
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>
@@ -110,5 +110,5 @@ StringStream.prototype = {
110
  </ul>
111
  </p>
112
 
113
- <p><strong>MIME types defined:</strong> <code>text/javascript</code>, <code>application/json</code>, <code>application/ld+json</code>, <code>text/typescript</code>, <code>application/typescript</code>.</p>
114
  </article>
12
  <script src="javascript.js"></script>
13
  <style>.CodeMirror {border-top: 1px solid black; border-bottom: 1px solid black;}</style>
14
  <div id=nav>
15
+ <a href="https://codemirror.net"><h1>CodeMirror</h1><img id=logo src="../../doc/logo.png" alt=""></a>
16
 
17
  <ul>
18
  <li><a href="../../index.html">Home</a>
110
  </ul>
111
  </p>
112
 
113
+ <p><strong>MIME types defined:</strong> <code>text/javascript</code>, <code>application/javascript</code>, <code>application/x-javascript</code>, <code>text/ecmascript</code>, <code>application/ecmascript</code>, <code>application/json</code>, <code>application/x-json</code>, <code>application/manifest+json</code>, <code>application/ld+json</code>, <code>text/typescript</code>, <code>application/typescript</code>.</p>
114
  </article>
vendor/codemirror/mode/javascript/javascript.js CHANGED
@@ -67,7 +67,7 @@ CodeMirror.defineMode("javascript", function(config, parserConfig) {
67
  if (ch == '"' || ch == "'") {
68
  state.tokenize = tokenString(ch);
69
  return state.tokenize(stream, state);
70
- } else if (ch == "." && stream.match(/^\d+(?:[eE][+\-]?\d+)?/)) {
71
  return ret("number", "number");
72
  } else if (ch == "." && stream.match("..")) {
73
  return ret("spread", "meta");
@@ -75,10 +75,10 @@ CodeMirror.defineMode("javascript", function(config, parserConfig) {
75
  return ret(ch);
76
  } else if (ch == "=" && stream.eat(">")) {
77
  return ret("=>", "operator");
78
- } else if (ch == "0" && stream.match(/^(?:x[\da-f]+|o[0-7]+|b[01]+)n?/i)) {
79
  return ret("number", "number");
80
  } else if (/\d/.test(ch)) {
81
- stream.match(/^\d*(?:n|(?:\.\d*)?(?:[eE][+\-]?\d+)?)?/);
82
  return ret("number", "number");
83
  } else if (ch == "/") {
84
  if (stream.eat("*")) {
@@ -98,18 +98,25 @@ CodeMirror.defineMode("javascript", function(config, parserConfig) {
98
  } else if (ch == "`") {
99
  state.tokenize = tokenQuasi;
100
  return tokenQuasi(stream, state);
101
- } else if (ch == "#") {
102
  stream.skipToEnd();
103
- return ret("error", "error");
 
 
 
 
 
 
104
  } else if (isOperatorChar.test(ch)) {
105
  if (ch != ">" || !state.lexical || state.lexical.type != ">") {
106
  if (stream.eat("=")) {
107
  if (ch == "!" || ch == "=") stream.eat("=")
108
- } else if (/[<>*+\-]/.test(ch)) {
109
  stream.eat(ch)
110
  if (ch == ">") stream.eat(ch)
111
  }
112
  }
 
113
  return ret("operator", "operator", stream.current());
114
  } else if (wordRE.test(ch)) {
115
  stream.eatWhile(wordRE);
@@ -119,7 +126,7 @@ CodeMirror.defineMode("javascript", function(config, parserConfig) {
119
  var kw = keywords[word]
120
  return ret(kw.type, kw.style, word)
121
  }
122
- if (word == "async" && stream.match(/^(\s|\/\*.*?\*\/)*[\[\(\w]/, false))
123
  return ret("async", "keyword", word)
124
  }
125
  return ret("variable", "variable", word)
@@ -195,8 +202,12 @@ CodeMirror.defineMode("javascript", function(config, parserConfig) {
195
  ++depth;
196
  } else if (wordRE.test(ch)) {
197
  sawSomething = true;
198
- } else if (/["'\/]/.test(ch)) {
199
- return;
 
 
 
 
200
  } else if (sawSomething && !depth) {
201
  ++pos;
202
  break;
@@ -365,7 +376,10 @@ CodeMirror.defineMode("javascript", function(config, parserConfig) {
365
  }
366
  if (type == "function") return cont(functiondef);
367
  if (type == "for") return cont(pushlex("form"), forspec, statement, poplex);
368
- if (type == "class" || (isTS && value == "interface")) { cx.marked = "keyword"; return cont(pushlex("form"), className, poplex); }
 
 
 
369
  if (type == "variable") {
370
  if (isTS && value == "declare") {
371
  cx.marked = "keyword"
@@ -373,11 +387,11 @@ CodeMirror.defineMode("javascript", function(config, parserConfig) {
373
  } else if (isTS && (value == "module" || value == "enum" || value == "type") && cx.stream.match(/^\s*\w/, false)) {
374
  cx.marked = "keyword"
375
  if (value == "enum") return cont(enumdef);
376
- else if (value == "type") return cont(typeexpr, expect("operator"), typeexpr, expect(";"));
377
  else return cont(pushlex("form"), pattern, expect("{"), pushlex("}"), block, poplex, poplex)
378
  } else if (isTS && value == "namespace") {
379
  cx.marked = "keyword"
380
- return cont(pushlex("form"), expression, block, poplex)
381
  } else if (isTS && value == "abstract") {
382
  cx.marked = "keyword"
383
  return cont(statement)
@@ -407,7 +421,7 @@ CodeMirror.defineMode("javascript", function(config, parserConfig) {
407
  }
408
  function parenExpr(type) {
409
  if (type != "(") return pass()
410
- return cont(pushlex(")"), expression, expect(")"), poplex)
411
  }
412
  function expressionInner(type, value, noComma) {
413
  if (cx.state.fatArrowAt == cx.stream.start) {
@@ -436,7 +450,7 @@ CodeMirror.defineMode("javascript", function(config, parserConfig) {
436
  }
437
 
438
  function maybeoperatorComma(type, value) {
439
- if (type == ",") return cont(expression);
440
  return maybeoperatorNoComma(type, value, false);
441
  }
442
  function maybeoperatorNoComma(type, value, noComma) {
@@ -445,7 +459,7 @@ CodeMirror.defineMode("javascript", function(config, parserConfig) {
445
  if (type == "=>") return cont(pushcontext, noComma ? arrowBodyNoComma : arrowBody, popcontext);
446
  if (type == "operator") {
447
  if (/\+\+|--/.test(value) || isTS && value == "!") return cont(me);
448
- if (isTS && value == "<" && cx.stream.match(/^([^>]|<.*?>)*>\s*\(/, false))
449
  return cont(pushlex(">"), commasep(typeexpr, ">"), poplex, me);
450
  if (value == "?") return cont(expression, expect(":"), expr);
451
  return cont(expr);
@@ -552,6 +566,7 @@ CodeMirror.defineMode("javascript", function(config, parserConfig) {
552
  }, proceed);
553
  }
554
  if (type == end || value == end) return cont();
 
555
  return cont(expect(end));
556
  }
557
  return function(type, value) {
@@ -574,6 +589,9 @@ CodeMirror.defineMode("javascript", function(config, parserConfig) {
574
  if (value == "?") return cont(maybetype);
575
  }
576
  }
 
 
 
577
  function mayberettype(type) {
578
  if (isTS && type == ":") {
579
  if (cx.stream.match(/^\s*\w+\s+is\b/, false)) return cont(expression, isKW, typeexpr)
@@ -587,45 +605,57 @@ CodeMirror.defineMode("javascript", function(config, parserConfig) {
587
  }
588
  }
589
  function typeexpr(type, value) {
590
- if (value == "keyof" || value == "typeof") {
591
  cx.marked = "keyword"
592
- return cont(value == "keyof" ? typeexpr : expressionNoComma)
593
  }
594
  if (type == "variable" || value == "void") {
595
  cx.marked = "type"
596
  return cont(afterType)
597
  }
 
598
  if (type == "string" || type == "number" || type == "atom") return cont(afterType);
599
  if (type == "[") return cont(pushlex("]"), commasep(typeexpr, "]", ","), poplex, afterType)
600
- if (type == "{") return cont(pushlex("}"), commasep(typeprop, "}", ",;"), poplex, afterType)
601
- if (type == "(") return cont(commasep(typearg, ")"), maybeReturnType)
602
  if (type == "<") return cont(commasep(typeexpr, ">"), typeexpr)
603
  }
604
  function maybeReturnType(type) {
605
  if (type == "=>") return cont(typeexpr)
606
  }
 
 
 
 
 
607
  function typeprop(type, value) {
608
  if (type == "variable" || cx.style == "keyword") {
609
  cx.marked = "property"
610
  return cont(typeprop)
611
- } else if (value == "?") {
612
  return cont(typeprop)
613
  } else if (type == ":") {
614
  return cont(typeexpr)
615
  } else if (type == "[") {
616
- return cont(expression, maybetype, expect("]"), typeprop)
 
 
 
 
617
  }
618
  }
619
  function typearg(type, value) {
620
  if (type == "variable" && cx.stream.match(/^\s*[?:]/, false) || value == "?") return cont(typearg)
621
  if (type == ":") return cont(typeexpr)
 
622
  return pass(typeexpr)
623
  }
624
  function afterType(type, value) {
625
  if (value == "<") return cont(pushlex(">"), commasep(typeexpr, ">"), poplex, afterType)
626
  if (value == "|" || type == "." || value == "&") return cont(typeexpr)
627
- if (type == "[") return cont(expect("]"), afterType)
628
  if (value == "extends" || value == "implements") { cx.marked = "keyword"; return cont(typeexpr) }
 
629
  }
630
  function maybeTypeArgs(_, value) {
631
  if (value == "<") return cont(pushlex(">"), commasep(typeexpr, ">"), poplex, afterType)
@@ -655,6 +685,7 @@ CodeMirror.defineMode("javascript", function(config, parserConfig) {
655
  if (type == "variable") cx.marked = "property";
656
  if (type == "spread") return cont(pattern);
657
  if (type == "}") return pass();
 
658
  return cont(expect(":"), pattern, maybeAssign);
659
  }
660
  function eltpattern() {
@@ -671,25 +702,18 @@ CodeMirror.defineMode("javascript", function(config, parserConfig) {
671
  }
672
  function forspec(type, value) {
673
  if (value == "await") return cont(forspec);
674
- if (type == "(") return cont(pushlex(")"), forspec1, expect(")"), poplex);
675
  }
676
  function forspec1(type) {
677
- if (type == "var") return cont(vardef, expect(";"), forspec2);
678
- if (type == ";") return cont(forspec2);
679
- if (type == "variable") return cont(formaybeinof);
680
- return pass(expression, expect(";"), forspec2);
681
- }
682
- function formaybeinof(_type, value) {
683
- if (value == "in" || value == "of") { cx.marked = "keyword"; return cont(expression); }
684
- return cont(maybeoperatorComma, forspec2);
685
  }
686
  function forspec2(type, value) {
687
- if (type == ";") return cont(forspec3);
688
- if (value == "in" || value == "of") { cx.marked = "keyword"; return cont(expression); }
689
- return pass(expression, expect(";"), forspec3);
690
- }
691
- function forspec3(type) {
692
- if (type != ")") cont(expression);
693
  }
694
  function functiondef(type, value) {
695
  if (value == "*") {cx.marked = "keyword"; return cont(functiondef);}
@@ -697,10 +721,25 @@ CodeMirror.defineMode("javascript", function(config, parserConfig) {
697
  if (type == "(") return cont(pushcontext, pushlex(")"), commasep(funarg, ")"), poplex, mayberettype, statement, popcontext);
698
  if (isTS && value == "<") return cont(pushlex(">"), commasep(typeparam, ">"), poplex, functiondef)
699
  }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
700
  function funarg(type, value) {
701
  if (value == "@") cont(expression, funarg)
702
  if (type == "spread") return cont(funarg);
703
  if (isTS && isModifier(value)) { cx.marked = "keyword"; return cont(funarg); }
 
704
  return pass(pattern, maybetype, maybeAssign);
705
  }
706
  function classExpression(type, value) {
@@ -729,15 +768,17 @@ CodeMirror.defineMode("javascript", function(config, parserConfig) {
729
  }
730
  if (type == "variable" || cx.style == "keyword") {
731
  cx.marked = "property";
732
- return cont(isTS ? classfield : functiondef, classBody);
733
  }
 
734
  if (type == "[")
735
- return cont(expression, maybetype, expect("]"), isTS ? classfield : functiondef, classBody)
736
  if (value == "*") {
737
  cx.marked = "keyword";
738
  return cont(classBody);
739
  }
740
- if (type == ";") return cont(classBody);
 
741
  if (type == "}") return cont();
742
  if (value == "@") return cont(expression, classBody)
743
  }
@@ -745,7 +786,8 @@ CodeMirror.defineMode("javascript", function(config, parserConfig) {
745
  if (value == "?") return cont(classfield)
746
  if (type == ":") return cont(typeexpr, maybeAssign)
747
  if (value == "=") return cont(expressionNoComma)
748
- return pass(functiondef)
 
749
  }
750
  function afterExport(type, value) {
751
  if (value == "*") { cx.marked = "keyword"; return cont(maybeFrom, expect(";")); }
@@ -833,7 +875,7 @@ CodeMirror.defineMode("javascript", function(config, parserConfig) {
833
  },
834
 
835
  indent: function(state, textAfter) {
836
- if (state.tokenize == tokenComment) return CodeMirror.Pass;
837
  if (state.tokenize != tokenBase) return 0;
838
  var firstChar = textAfter && textAfter.charAt(0), lexical = state.lexical, top
839
  // Kludge to prevent 'maybelse' from blocking lexical scope pops
@@ -890,9 +932,10 @@ CodeMirror.defineMIME("text/ecmascript", "javascript");
890
  CodeMirror.defineMIME("application/javascript", "javascript");
891
  CodeMirror.defineMIME("application/x-javascript", "javascript");
892
  CodeMirror.defineMIME("application/ecmascript", "javascript");
893
- CodeMirror.defineMIME("application/json", {name: "javascript", json: true});
894
- CodeMirror.defineMIME("application/x-json", {name: "javascript", json: true});
895
- CodeMirror.defineMIME("application/ld+json", {name: "javascript", jsonld: true});
 
896
  CodeMirror.defineMIME("text/typescript", { name: "javascript", typescript: true });
897
  CodeMirror.defineMIME("application/typescript", { name: "javascript", typescript: true });
898
 
67
  if (ch == '"' || ch == "'") {
68
  state.tokenize = tokenString(ch);
69
  return state.tokenize(stream, state);
70
+ } else if (ch == "." && stream.match(/^\d[\d_]*(?:[eE][+\-]?[\d_]+)?/)) {
71
  return ret("number", "number");
72
  } else if (ch == "." && stream.match("..")) {
73
  return ret("spread", "meta");
75
  return ret(ch);
76
  } else if (ch == "=" && stream.eat(">")) {
77
  return ret("=>", "operator");
78
+ } else if (ch == "0" && stream.match(/^(?:x[\dA-Fa-f_]+|o[0-7_]+|b[01_]+)n?/)) {
79
  return ret("number", "number");
80
  } else if (/\d/.test(ch)) {
81
+ stream.match(/^[\d_]*(?:n|(?:\.[\d_]*)?(?:[eE][+\-]?[\d_]+)?)?/);
82
  return ret("number", "number");
83
  } else if (ch == "/") {
84
  if (stream.eat("*")) {
98
  } else if (ch == "`") {
99
  state.tokenize = tokenQuasi;
100
  return tokenQuasi(stream, state);
101
+ } else if (ch == "#" && stream.peek() == "!") {
102
  stream.skipToEnd();
103
+ return ret("meta", "meta");
104
+ } else if (ch == "#" && stream.eatWhile(wordRE)) {
105
+ return ret("variable", "property")
106
+ } else if (ch == "<" && stream.match("!--") ||
107
+ (ch == "-" && stream.match("->") && !/\S/.test(stream.string.slice(0, stream.start)))) {
108
+ stream.skipToEnd()
109
+ return ret("comment", "comment")
110
  } else if (isOperatorChar.test(ch)) {
111
  if (ch != ">" || !state.lexical || state.lexical.type != ">") {
112
  if (stream.eat("=")) {
113
  if (ch == "!" || ch == "=") stream.eat("=")
114
+ } else if (/[<>*+\-|&?]/.test(ch)) {
115
  stream.eat(ch)
116
  if (ch == ">") stream.eat(ch)
117
  }
118
  }
119
+ if (ch == "?" && stream.eat(".")) return ret(".")
120
  return ret("operator", "operator", stream.current());
121
  } else if (wordRE.test(ch)) {
122
  stream.eatWhile(wordRE);
126
  var kw = keywords[word]
127
  return ret(kw.type, kw.style, word)
128
  }
129
+ if (word == "async" && stream.match(/^(\s|\/\*([^*]|\*(?!\/))*?\*\/)*[\[\(\w]/, false))
130
  return ret("async", "keyword", word)
131
  }
132
  return ret("variable", "variable", word)
202
  ++depth;
203
  } else if (wordRE.test(ch)) {
204
  sawSomething = true;
205
+ } else if (/["'\/`]/.test(ch)) {
206
+ for (;; --pos) {
207
+ if (pos == 0) return
208
+ var next = stream.string.charAt(pos - 1)
209
+ if (next == ch && stream.string.charAt(pos - 2) != "\\") { pos--; break }
210
+ }
211
  } else if (sawSomething && !depth) {
212
  ++pos;
213
  break;
376
  }
377
  if (type == "function") return cont(functiondef);
378
  if (type == "for") return cont(pushlex("form"), forspec, statement, poplex);
379
+ if (type == "class" || (isTS && value == "interface")) {
380
+ cx.marked = "keyword"
381
+ return cont(pushlex("form", type == "class" ? type : value), className, poplex)
382
+ }
383
  if (type == "variable") {
384
  if (isTS && value == "declare") {
385
  cx.marked = "keyword"
387
  } else if (isTS && (value == "module" || value == "enum" || value == "type") && cx.stream.match(/^\s*\w/, false)) {
388
  cx.marked = "keyword"
389
  if (value == "enum") return cont(enumdef);
390
+ else if (value == "type") return cont(typename, expect("operator"), typeexpr, expect(";"));
391
  else return cont(pushlex("form"), pattern, expect("{"), pushlex("}"), block, poplex, poplex)
392
  } else if (isTS && value == "namespace") {
393
  cx.marked = "keyword"
394
+ return cont(pushlex("form"), expression, statement, poplex)
395
  } else if (isTS && value == "abstract") {
396
  cx.marked = "keyword"
397
  return cont(statement)
421
  }
422
  function parenExpr(type) {
423
  if (type != "(") return pass()
424
+ return cont(pushlex(")"), maybeexpression, expect(")"), poplex)
425
  }
426
  function expressionInner(type, value, noComma) {
427
  if (cx.state.fatArrowAt == cx.stream.start) {
450
  }
451
 
452
  function maybeoperatorComma(type, value) {
453
+ if (type == ",") return cont(maybeexpression);
454
  return maybeoperatorNoComma(type, value, false);
455
  }
456
  function maybeoperatorNoComma(type, value, noComma) {
459
  if (type == "=>") return cont(pushcontext, noComma ? arrowBodyNoComma : arrowBody, popcontext);
460
  if (type == "operator") {
461
  if (/\+\+|--/.test(value) || isTS && value == "!") return cont(me);
462
+ if (isTS && value == "<" && cx.stream.match(/^([^<>]|<[^<>]*>)*>\s*\(/, false))
463
  return cont(pushlex(">"), commasep(typeexpr, ">"), poplex, me);
464
  if (value == "?") return cont(expression, expect(":"), expr);
465
  return cont(expr);
566
  }, proceed);
567
  }
568
  if (type == end || value == end) return cont();
569
+ if (sep && sep.indexOf(";") > -1) return pass(what)
570
  return cont(expect(end));
571
  }
572
  return function(type, value) {
589
  if (value == "?") return cont(maybetype);
590
  }
591
  }
592
+ function maybetypeOrIn(type, value) {
593
+ if (isTS && (type == ":" || value == "in")) return cont(typeexpr)
594
+ }
595
  function mayberettype(type) {
596
  if (isTS && type == ":") {
597
  if (cx.stream.match(/^\s*\w+\s+is\b/, false)) return cont(expression, isKW, typeexpr)
605
  }
606
  }
607
  function typeexpr(type, value) {
608
+ if (value == "keyof" || value == "typeof" || value == "infer") {
609
  cx.marked = "keyword"
610
+ return cont(value == "typeof" ? expressionNoComma : typeexpr)
611
  }
612
  if (type == "variable" || value == "void") {
613
  cx.marked = "type"
614
  return cont(afterType)
615
  }
616
+ if (value == "|" || value == "&") return cont(typeexpr)
617
  if (type == "string" || type == "number" || type == "atom") return cont(afterType);
618
  if (type == "[") return cont(pushlex("]"), commasep(typeexpr, "]", ","), poplex, afterType)
619
+ if (type == "{") return cont(pushlex("}"), typeprops, poplex, afterType)
620
+ if (type == "(") return cont(commasep(typearg, ")"), maybeReturnType, afterType)
621
  if (type == "<") return cont(commasep(typeexpr, ">"), typeexpr)
622
  }
623
  function maybeReturnType(type) {
624
  if (type == "=>") return cont(typeexpr)
625
  }
626
+ function typeprops(type) {
627
+ if (type == "}") return cont()
628
+ if (type == "," || type == ";") return cont(typeprops)
629
+ return pass(typeprop, typeprops)
630
+ }
631
  function typeprop(type, value) {
632
  if (type == "variable" || cx.style == "keyword") {
633
  cx.marked = "property"
634
  return cont(typeprop)
635
+ } else if (value == "?" || type == "number" || type == "string") {
636
  return cont(typeprop)
637
  } else if (type == ":") {
638
  return cont(typeexpr)
639
  } else if (type == "[") {
640
+ return cont(expect("variable"), maybetypeOrIn, expect("]"), typeprop)
641
+ } else if (type == "(") {
642
+ return pass(functiondecl, typeprop)
643
+ } else if (!type.match(/[;\}\)\],]/)) {
644
+ return cont()
645
  }
646
  }
647
  function typearg(type, value) {
648
  if (type == "variable" && cx.stream.match(/^\s*[?:]/, false) || value == "?") return cont(typearg)
649
  if (type == ":") return cont(typeexpr)
650
+ if (type == "spread") return cont(typearg)
651
  return pass(typeexpr)
652
  }
653
  function afterType(type, value) {
654
  if (value == "<") return cont(pushlex(">"), commasep(typeexpr, ">"), poplex, afterType)
655
  if (value == "|" || type == "." || value == "&") return cont(typeexpr)
656
+ if (type == "[") return cont(typeexpr, expect("]"), afterType)
657
  if (value == "extends" || value == "implements") { cx.marked = "keyword"; return cont(typeexpr) }
658
+ if (value == "?") return cont(typeexpr, expect(":"), typeexpr)
659
  }
660
  function maybeTypeArgs(_, value) {
661
  if (value == "<") return cont(pushlex(">"), commasep(typeexpr, ">"), poplex, afterType)
685
  if (type == "variable") cx.marked = "property";
686
  if (type == "spread") return cont(pattern);
687
  if (type == "}") return pass();
688
+ if (type == "[") return cont(expression, expect(']'), expect(':'), proppattern);
689
  return cont(expect(":"), pattern, maybeAssign);
690
  }
691
  function eltpattern() {
702
  }
703
  function forspec(type, value) {
704
  if (value == "await") return cont(forspec);
705
+ if (type == "(") return cont(pushlex(")"), forspec1, poplex);
706
  }
707
  function forspec1(type) {
708
+ if (type == "var") return cont(vardef, forspec2);
709
+ if (type == "variable") return cont(forspec2);
710
+ return pass(forspec2)
 
 
 
 
 
711
  }
712
  function forspec2(type, value) {
713
+ if (type == ")") return cont()
714
+ if (type == ";") return cont(forspec2)
715
+ if (value == "in" || value == "of") { cx.marked = "keyword"; return cont(expression, forspec2) }
716
+ return pass(expression, forspec2)
 
 
717
  }
718
  function functiondef(type, value) {
719
  if (value == "*") {cx.marked = "keyword"; return cont(functiondef);}
721
  if (type == "(") return cont(pushcontext, pushlex(")"), commasep(funarg, ")"), poplex, mayberettype, statement, popcontext);
722
  if (isTS && value == "<") return cont(pushlex(">"), commasep(typeparam, ">"), poplex, functiondef)
723
  }
724
+ function functiondecl(type, value) {
725
+ if (value == "*") {cx.marked = "keyword"; return cont(functiondecl);}
726
+ if (type == "variable") {register(value); return cont(functiondecl);}
727
+ if (type == "(") return cont(pushcontext, pushlex(")"), commasep(funarg, ")"), poplex, mayberettype, popcontext);
728
+ if (isTS && value == "<") return cont(pushlex(">"), commasep(typeparam, ">"), poplex, functiondecl)
729
+ }
730
+ function typename(type, value) {
731
+ if (type == "keyword" || type == "variable") {
732
+ cx.marked = "type"
733
+ return cont(typename)
734
+ } else if (value == "<") {
735
+ return cont(pushlex(">"), commasep(typeparam, ">"), poplex)
736
+ }
737
+ }
738
  function funarg(type, value) {
739
  if (value == "@") cont(expression, funarg)
740
  if (type == "spread") return cont(funarg);
741
  if (isTS && isModifier(value)) { cx.marked = "keyword"; return cont(funarg); }
742
+ if (isTS && type == "this") return cont(maybetype, maybeAssign)
743
  return pass(pattern, maybetype, maybeAssign);
744
  }
745
  function classExpression(type, value) {
768
  }
769
  if (type == "variable" || cx.style == "keyword") {
770
  cx.marked = "property";
771
+ return cont(classfield, classBody);
772
  }
773
+ if (type == "number" || type == "string") return cont(classfield, classBody);
774
  if (type == "[")
775
+ return cont(expression, maybetype, expect("]"), classfield, classBody)
776
  if (value == "*") {
777
  cx.marked = "keyword";
778
  return cont(classBody);
779
  }
780
+ if (isTS && type == "(") return pass(functiondecl, classBody)
781
+ if (type == ";" || type == ",") return cont(classBody);
782
  if (type == "}") return cont();
783
  if (value == "@") return cont(expression, classBody)
784
  }
786
  if (value == "?") return cont(classfield)
787
  if (type == ":") return cont(typeexpr, maybeAssign)
788
  if (value == "=") return cont(expressionNoComma)
789
+ var context = cx.state.lexical.prev, isInterface = context && context.info == "interface"
790
+ return pass(isInterface ? functiondecl : functiondef)
791
  }
792
  function afterExport(type, value) {
793
  if (value == "*") { cx.marked = "keyword"; return cont(maybeFrom, expect(";")); }
875
  },
876
 
877
  indent: function(state, textAfter) {
878
+ if (state.tokenize == tokenComment || state.tokenize == tokenQuasi) return CodeMirror.Pass;
879
  if (state.tokenize != tokenBase) return 0;
880
  var firstChar = textAfter && textAfter.charAt(0), lexical = state.lexical, top
881
  // Kludge to prevent 'maybelse' from blocking lexical scope pops
932
  CodeMirror.defineMIME("application/javascript", "javascript");
933
  CodeMirror.defineMIME("application/x-javascript", "javascript");
934
  CodeMirror.defineMIME("application/ecmascript", "javascript");
935
+ CodeMirror.defineMIME("application/json", { name: "javascript", json: true });
936
+ CodeMirror.defineMIME("application/x-json", { name: "javascript", json: true });
937
+ CodeMirror.defineMIME("application/manifest+json", { name: "javascript", json: true })
938
+ CodeMirror.defineMIME("application/ld+json", { name: "javascript", jsonld: true });
939
  CodeMirror.defineMIME("text/typescript", { name: "javascript", typescript: true });
940
  CodeMirror.defineMIME("application/typescript", { name: "javascript", typescript: true });
941
 
vendor/codemirror/mode/javascript/test.js CHANGED
@@ -127,6 +127,9 @@
127
  "[keyword let] [def f] [operator =] ([[ [def a], [def b] ]], [def c]) [operator =>] [variable-2 a] [operator +] [variable-2 c];",
128
  "[variable c];");
129
 
 
 
 
130
  MT("spread",
131
  "[keyword function] [def f]([def a], [meta ...][def b]) {",
132
  " [variable something]([variable-2 a], [meta ...][variable-2 b]);",
@@ -226,6 +229,12 @@
226
  " [keyword return] [variable-2 x];",
227
  "}");
228
 
 
 
 
 
 
 
229
  MT("new_target",
230
  "[keyword function] [def F]([def target]) {",
231
  " [keyword if] ([variable-2 target] [operator &&] [keyword new].[keyword target].[property name]) {",
@@ -292,6 +301,30 @@
292
  "[keyword return]",
293
  "{} [string-2 /5/]")
294
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
295
  var ts_mode = CodeMirror.getMode({indentUnit: 2}, "application/typescript")
296
  function TS(name) {
297
  test.mode(name, ts_mode, Array.prototype.slice.call(arguments, 1))
@@ -442,6 +475,12 @@
442
  TS("abstract class",
443
  "[keyword export] [keyword abstract] [keyword class] [def Foo] {}")
444
 
 
 
 
 
 
 
445
  var jsonld_mode = CodeMirror.getMode(
446
  {indentUnit: 2},
447
  {name: "javascript", jsonld: true}
127
  "[keyword let] [def f] [operator =] ([[ [def a], [def b] ]], [def c]) [operator =>] [variable-2 a] [operator +] [variable-2 c];",
128
  "[variable c];");
129
 
130
+ MT("fatArrow_stringDefault",
131
+ "([def a], [def b] [operator =] [string 'x\\'y']) [operator =>] [variable-2 a] [operator +] [variable-2 b]")
132
+
133
  MT("spread",
134
  "[keyword function] [def f]([def a], [meta ...][def b]) {",
135
  " [variable something]([variable-2 a], [meta ...][variable-2 b]);",
229
  " [keyword return] [variable-2 x];",
230
  "}");
231
 
232
+ MT(
233
+ "param_destructuring",
234
+ "[keyword function] [def foo]([def x] [operator =] [string-2 `foo${][number 10][string-2 }bar`]) {",
235
+ " [keyword return] [variable-2 x];",
236
+ "}");
237
+
238
  MT("new_target",
239
  "[keyword function] [def F]([def target]) {",
240
  " [keyword if] ([variable-2 target] [operator &&] [keyword new].[keyword target].[property name]) {",
301
  "[keyword return]",
302
  "{} [string-2 /5/]")
303
 
304
+ MT("numeric separator",
305
+ "[number 123_456];",
306
+ "[number 0xdead_c0de];",
307
+ "[number 0o123_456];",
308
+ "[number 0b1101_1101];",
309
+ "[number .123_456e0_1];",
310
+ "[number 1E+123_456];",
311
+ "[number 12_34_56n];")
312
+
313
+ MT("underscore property",
314
+ "[variable something].[property _property];",
315
+ "[variable something].[property _123];",
316
+ "[variable something].[property _for];",
317
+ "[variable _for];",
318
+ "[variable _123];")
319
+
320
+ MT("private properties",
321
+ "[keyword class] [def C] {",
322
+ " [property #x] [operator =] [number 2];",
323
+ " [property #read]() {",
324
+ " [keyword return] [keyword this].[property #x]",
325
+ " }",
326
+ "}")
327
+
328
  var ts_mode = CodeMirror.getMode({indentUnit: 2}, "application/typescript")
329
  function TS(name) {
330
  test.mode(name, ts_mode, Array.prototype.slice.call(arguments, 1))
475
  TS("abstract class",
476
  "[keyword export] [keyword abstract] [keyword class] [def Foo] {}")
477
 
478
+ TS("interface without semicolons",
479
+ "[keyword interface] [def Foo] {",
480
+ " [property greet]([def x]: [type int]): [type blah]",
481
+ " [property bar]: [type void]",
482
+ "}")
483
+
484
  var jsonld_mode = CodeMirror.getMode(
485
  {indentUnit: 2},
486
  {name: "javascript", jsonld: true}
vendor/codemirror/mode/javascript/typescript.html CHANGED
@@ -10,7 +10,7 @@
10
  <script src="javascript.js"></script>
11
  <style>.CodeMirror {border-top: 1px solid black; border-bottom: 1px solid black;}</style>
12
  <div id=nav>
13
- <a href="https://codemirror.net"><h1>CodeMirror</h1><img id=logo src="../../doc/logo.png"></a>
14
 
15
  <ul>
16
  <li><a href="../../index.html">Home</a>
10
  <script src="javascript.js"></script>
11
  <style>.CodeMirror {border-top: 1px solid black; border-bottom: 1px solid black;}</style>
12
  <div id=nav>
13
+ <a href="https://codemirror.net"><h1>CodeMirror</h1><img id=logo src="../../doc/logo.png" alt=""></a>
14
 
15
  <ul>
16
  <li><a href="../../index.html">Home</a>
vendor/codemirror/mode/meta.js CHANGED
@@ -20,11 +20,11 @@
20
  {name: "C", mime: "text/x-csrc", mode: "clike", ext: ["c", "h", "ino"]},
21
  {name: "C++", mime: "text/x-c++src", mode: "clike", ext: ["cpp", "c++", "cc", "cxx", "hpp", "h++", "hh", "hxx"], alias: ["cpp"]},
22
  {name: "Cobol", mime: "text/x-cobol", mode: "cobol", ext: ["cob", "cpy"]},
23
- {name: "C#", mime: "text/x-csharp", mode: "clike", ext: ["cs"], alias: ["csharp"]},
24
  {name: "Clojure", mime: "text/x-clojure", mode: "clojure", ext: ["clj", "cljc", "cljx"]},
25
  {name: "ClojureScript", mime: "text/x-clojurescript", mode: "clojure", ext: ["cljs"]},
26
  {name: "Closure Stylesheets (GSS)", mime: "text/x-gss", mode: "css", ext: ["gss"]},
27
- {name: "CMake", mime: "text/x-cmake", mode: "cmake", ext: ["cmake", "cmake.in"], file: /^CMakeLists.txt$/},
28
  {name: "CoffeeScript", mimes: ["application/vnd.coffeescript", "text/coffeescript", "text/x-coffeescript"], mode: "coffeescript", ext: ["coffee"], alias: ["coffee", "coffee-script"]},
29
  {name: "Common Lisp", mime: "text/x-common-lisp", mode: "commonlisp", ext: ["cl", "lisp", "el"], alias: ["lisp"]},
30
  {name: "Cypher", mime: "application/x-cypher-query", mode: "cypher", ext: ["cyp", "cypher"]},
@@ -51,11 +51,11 @@
51
  {name: "Factor", mime: "text/x-factor", mode: "factor", ext: ["factor"]},
52
  {name: "FCL", mime: "text/x-fcl", mode: "fcl"},
53
  {name: "Forth", mime: "text/x-forth", mode: "forth", ext: ["forth", "fth", "4th"]},
54
- {name: "Fortran", mime: "text/x-fortran", mode: "fortran", ext: ["f", "for", "f77", "f90"]},
55
  {name: "F#", mime: "text/x-fsharp", mode: "mllike", ext: ["fs"], alias: ["fsharp"]},
56
  {name: "Gas", mime: "text/x-gas", mode: "gas", ext: ["s"]},
57
  {name: "Gherkin", mime: "text/x-feature", mode: "gherkin", ext: ["feature"]},
58
- {name: "GitHub Flavored Markdown", mime: "text/x-gfm", mode: "gfm", file: /^(readme|contributing|history).md$/i},
59
  {name: "Go", mime: "text/x-go", mode: "go", ext: ["go"]},
60
  {name: "Groovy", mime: "text/x-groovy", mode: "groovy", ext: ["groovy", "gradle"], file: /^Jenkinsfile$/},
61
  {name: "HAML", mime: "text/x-haml", mode: "haml", ext: ["haml"]},
@@ -75,7 +75,7 @@
75
  {name: "JSON", mimes: ["application/json", "application/x-json"], mode: "javascript", ext: ["json", "map"], alias: ["json5"]},
76
  {name: "JSON-LD", mime: "application/ld+json", mode: "javascript", ext: ["jsonld"], alias: ["jsonld"]},
77
  {name: "JSX", mime: "text/jsx", mode: "jsx", ext: ["jsx"]},
78
- {name: "Jinja2", mime: "null", mode: "jinja2", ext: ["j2", "jinja", "jinja2"]},
79
  {name: "Julia", mime: "text/x-julia", mode: "julia", ext: ["jl"]},
80
  {name: "Kotlin", mime: "text/x-kotlin", mode: "clike", ext: ["kt"]},
81
  {name: "LESS", mime: "text/x-less", mode: "css", ext: ["less"]},
@@ -84,7 +84,7 @@
84
  {name: "Markdown", mime: "text/x-markdown", mode: "markdown", ext: ["markdown", "md", "mkd"]},
85
  {name: "mIRC", mime: "text/mirc", mode: "mirc"},
86
  {name: "MariaDB SQL", mime: "text/x-mariadb", mode: "sql"},
87
- {name: "Mathematica", mime: "text/x-mathematica", mode: "mathematica", ext: ["m", "nb"]},
88
  {name: "Modelica", mime: "text/x-modelica", mode: "modelica", ext: ["mo"]},
89
  {name: "MUMPS", mime: "text/x-mumps", mode: "mumps", ext: ["mps"]},
90
  {name: "MS SQL", mime: "text/x-mssql", mode: "sql"},
@@ -94,7 +94,8 @@
94
  {name: "NSIS", mime: "text/x-nsis", mode: "nsis", ext: ["nsh", "nsi"]},
95
  {name: "NTriples", mimes: ["application/n-triples", "application/n-quads", "text/n-triples"],
96
  mode: "ntriples", ext: ["nt", "nq"]},
97
- {name: "Objective-C", mime: "text/x-objectivec", mode: "clike", ext: ["m", "mm"], alias: ["objective-c", "objc"]},
 
98
  {name: "OCaml", mime: "text/x-ocaml", mode: "mllike", ext: ["ml", "mli", "mll", "mly"]},
99
  {name: "Octave", mime: "text/x-octave", mode: "octave", ext: ["m"]},
100
  {name: "Oz", mime: "text/x-oz", mode: "oz", ext: ["oz"]},
@@ -105,6 +106,7 @@
105
  {name: "Pig", mime: "text/x-pig", mode: "pig", ext: ["pig"]},
106
  {name: "Plain Text", mime: "text/plain", mode: "null", ext: ["txt", "text", "conf", "def", "list", "log"]},
107
  {name: "PLSQL", mime: "text/x-plsql", mode: "sql", ext: ["pls"]},
 
108
  {name: "PowerShell", mime: "application/x-powershell", mode: "powershell", ext: ["ps1", "psd1", "psm1"]},
109
  {name: "Properties files", mime: "text/x-properties", mode: "properties", ext: ["properties", "ini", "in"], alias: ["ini", "properties"]},
110
  {name: "ProtoBuf", mime: "text/x-protobuf", mode: "protobuf", ext: ["proto"]},
@@ -142,7 +144,7 @@
142
  {name: "SystemVerilog", mime: "text/x-systemverilog", mode: "verilog", ext: ["v", "sv", "svh"]},
143
  {name: "Tcl", mime: "text/x-tcl", mode: "tcl", ext: ["tcl"]},
144
  {name: "Textile", mime: "text/x-textile", mode: "textile", ext: ["textile"]},
145
- {name: "TiddlyWiki ", mime: "text/x-tiddlywiki", mode: "tiddlywiki"},
146
  {name: "Tiki wiki", mime: "text/tiki", mode: "tiki"},
147
  {name: "TOML", mime: "text/x-toml", mode: "toml", ext: ["toml"]},
148
  {name: "Tornado", mime: "text/x-tornado", mode: "tornado"},
@@ -167,7 +169,8 @@
167
  {name: "Z80", mime: "text/x-z80", mode: "z80", ext: ["z80"]},
168
  {name: "mscgen", mime: "text/x-mscgen", mode: "mscgen", ext: ["mscgen", "mscin", "msc"]},
169
  {name: "xu", mime: "text/x-xu", mode: "mscgen", ext: ["xu"]},
170
- {name: "msgenny", mime: "text/x-msgenny", mode: "mscgen", ext: ["msgenny"]}
 
171
  ];
172
  // Ensure all modes have a mime property for backwards compatibility
173
  for (var i = 0; i < CodeMirror.modeInfo.length; i++) {
@@ -188,6 +191,7 @@
188
  };
189
 
190
  CodeMirror.findModeByExtension = function(ext) {
 
191
  for (var i = 0; i < CodeMirror.modeInfo.length; i++) {
192
  var info = CodeMirror.modeInfo[i];
193
  if (info.ext) for (var j = 0; j < info.ext.length; j++)
20
  {name: "C", mime: "text/x-csrc", mode: "clike", ext: ["c", "h", "ino"]},
21
  {name: "C++", mime: "text/x-c++src", mode: "clike", ext: ["cpp", "c++", "cc", "cxx", "hpp", "h++", "hh", "hxx"], alias: ["cpp"]},
22
  {name: "Cobol", mime: "text/x-cobol", mode: "cobol", ext: ["cob", "cpy"]},
23
+ {name: "C#", mime: "text/x-csharp", mode: "clike", ext: ["cs"], alias: ["csharp", "cs"]},
24
  {name: "Clojure", mime: "text/x-clojure", mode: "clojure", ext: ["clj", "cljc", "cljx"]},
25
  {name: "ClojureScript", mime: "text/x-clojurescript", mode: "clojure", ext: ["cljs"]},
26
  {name: "Closure Stylesheets (GSS)", mime: "text/x-gss", mode: "css", ext: ["gss"]},
27
+ {name: "CMake", mime: "text/x-cmake", mode: "cmake", ext: ["cmake", "cmake.in"], file: /^CMakeLists\.txt$/},
28
  {name: "CoffeeScript", mimes: ["application/vnd.coffeescript", "text/coffeescript", "text/x-coffeescript"], mode: "coffeescript", ext: ["coffee"], alias: ["coffee", "coffee-script"]},
29
  {name: "Common Lisp", mime: "text/x-common-lisp", mode: "commonlisp", ext: ["cl", "lisp", "el"], alias: ["lisp"]},
30
  {name: "Cypher", mime: "application/x-cypher-query", mode: "cypher", ext: ["cyp", "cypher"]},
51
  {name: "Factor", mime: "text/x-factor", mode: "factor", ext: ["factor"]},
52
  {name: "FCL", mime: "text/x-fcl", mode: "fcl"},
53
  {name: "Forth", mime: "text/x-forth", mode: "forth", ext: ["forth", "fth", "4th"]},
54
+ {name: "Fortran", mime: "text/x-fortran", mode: "fortran", ext: ["f", "for", "f77", "f90", "f95"]},
55
  {name: "F#", mime: "text/x-fsharp", mode: "mllike", ext: ["fs"], alias: ["fsharp"]},
56
  {name: "Gas", mime: "text/x-gas", mode: "gas", ext: ["s"]},
57
  {name: "Gherkin", mime: "text/x-feature", mode: "gherkin", ext: ["feature"]},
58
+ {name: "GitHub Flavored Markdown", mime: "text/x-gfm", mode: "gfm", file: /^(readme|contributing|history)\.md$/i},
59
  {name: "Go", mime: "text/x-go", mode: "go", ext: ["go"]},
60
  {name: "Groovy", mime: "text/x-groovy", mode: "groovy", ext: ["groovy", "gradle"], file: /^Jenkinsfile$/},
61
  {name: "HAML", mime: "text/x-haml", mode: "haml", ext: ["haml"]},
75
  {name: "JSON", mimes: ["application/json", "application/x-json"], mode: "javascript", ext: ["json", "map"], alias: ["json5"]},
76
  {name: "JSON-LD", mime: "application/ld+json", mode: "javascript", ext: ["jsonld"], alias: ["jsonld"]},
77
  {name: "JSX", mime: "text/jsx", mode: "jsx", ext: ["jsx"]},
78
+ {name: "Jinja2", mime: "text/jinja2", mode: "jinja2", ext: ["j2", "jinja", "jinja2"]},
79
  {name: "Julia", mime: "text/x-julia", mode: "julia", ext: ["jl"]},
80
  {name: "Kotlin", mime: "text/x-kotlin", mode: "clike", ext: ["kt"]},
81
  {name: "LESS", mime: "text/x-less", mode: "css", ext: ["less"]},
84
  {name: "Markdown", mime: "text/x-markdown", mode: "markdown", ext: ["markdown", "md", "mkd"]},
85
  {name: "mIRC", mime: "text/mirc", mode: "mirc"},
86
  {name: "MariaDB SQL", mime: "text/x-mariadb", mode: "sql"},
87
+ {name: "Mathematica", mime: "text/x-mathematica", mode: "mathematica", ext: ["m", "nb", "wl", "wls"]},
88
  {name: "Modelica", mime: "text/x-modelica", mode: "modelica", ext: ["mo"]},
89
  {name: "MUMPS", mime: "text/x-mumps", mode: "mumps", ext: ["mps"]},
90
  {name: "MS SQL", mime: "text/x-mssql", mode: "sql"},
94
  {name: "NSIS", mime: "text/x-nsis", mode: "nsis", ext: ["nsh", "nsi"]},
95
  {name: "NTriples", mimes: ["application/n-triples", "application/n-quads", "text/n-triples"],
96
  mode: "ntriples", ext: ["nt", "nq"]},
97
+ {name: "Objective-C", mime: "text/x-objectivec", mode: "clike", ext: ["m"], alias: ["objective-c", "objc"]},
98
+ {name: "Objective-C++", mime: "text/x-objectivec++", mode: "clike", ext: ["mm"], alias: ["objective-c++", "objc++"]},
99
  {name: "OCaml", mime: "text/x-ocaml", mode: "mllike", ext: ["ml", "mli", "mll", "mly"]},
100
  {name: "Octave", mime: "text/x-octave", mode: "octave", ext: ["m"]},
101
  {name: "Oz", mime: "text/x-oz", mode: "oz", ext: ["oz"]},
106
  {name: "Pig", mime: "text/x-pig", mode: "pig", ext: ["pig"]},
107
  {name: "Plain Text", mime: "text/plain", mode: "null", ext: ["txt", "text", "conf", "def", "list", "log"]},
108
  {name: "PLSQL", mime: "text/x-plsql", mode: "sql", ext: ["pls"]},
109
+ {name: "PostgreSQL", mime: "text/x-pgsql", mode: "sql"},
110
  {name: "PowerShell", mime: "application/x-powershell", mode: "powershell", ext: ["ps1", "psd1", "psm1"]},
111
  {name: "Properties files", mime: "text/x-properties", mode: "properties", ext: ["properties", "ini", "in"], alias: ["ini", "properties"]},
112
  {name: "ProtoBuf", mime: "text/x-protobuf", mode: "protobuf", ext: ["proto"]},
144
  {name: "SystemVerilog", mime: "text/x-systemverilog", mode: "verilog", ext: ["v", "sv", "svh"]},
145
  {name: "Tcl", mime: "text/x-tcl", mode: "tcl", ext: ["tcl"]},
146
  {name: "Textile", mime: "text/x-textile", mode: "textile", ext: ["textile"]},
147
+ {name: "TiddlyWiki", mime: "text/x-tiddlywiki", mode: "tiddlywiki"},
148
  {name: "Tiki wiki", mime: "text/tiki", mode: "tiki"},
149
  {name: "TOML", mime: "text/x-toml", mode: "toml", ext: ["toml"]},
150
  {name: "Tornado", mime: "text/x-tornado", mode: "tornado"},
169
  {name: "Z80", mime: "text/x-z80", mode: "z80", ext: ["z80"]},
170
  {name: "mscgen", mime: "text/x-mscgen", mode: "mscgen", ext: ["mscgen", "mscin", "msc"]},
171
  {name: "xu", mime: "text/x-xu", mode: "mscgen", ext: ["xu"]},
172
+ {name: "msgenny", mime: "text/x-msgenny", mode: "mscgen", ext: ["msgenny"]},
173
+ {name: "WebAssembly", mime: "text/webassembly", mode: "wast", ext: ["wat", "wast"]},
174
  ];
175
  // Ensure all modes have a mime property for backwards compatibility
176
  for (var i = 0; i < CodeMirror.modeInfo.length; i++) {
191
  };
192
 
193
  CodeMirror.findModeByExtension = function(ext) {
194
+ ext = ext.toLowerCase();
195
  for (var i = 0; i < CodeMirror.modeInfo.length; i++) {
196
  var info = CodeMirror.modeInfo[i];
197
  if (info.ext) for (var j = 0; j < info.ext.length; j++)
vendor/codemirror/mode/php/index.html CHANGED
@@ -15,7 +15,7 @@
15
  <script src="php.js"></script>
16
  <style>.CodeMirror {border-top: 1px solid black; border-bottom: 1px solid black;}</style>
17
  <div id=nav>
18
- <a href="https://codemirror.net"><h1>CodeMirror</h1><img id=logo src="../../doc/logo.png"></a>
19
 
20
  <ul>
21
  <li><a href="../../index.html">Home</a>
15
  <script src="php.js"></script>
16
  <style>.CodeMirror {border-top: 1px solid black; border-bottom: 1px solid black;}</style>
17
  <div id=nav>
18
+ <a href="https://codemirror.net"><h1>CodeMirror</h1><img id=logo src="../../doc/logo.png" alt=""></a>
19
 
20
  <ul>
21
  <li><a href="../../index.html">Home</a>
vendor/codemirror/mode/php/php.js CHANGED
@@ -160,7 +160,7 @@
160
  if (!isPHP) {
161
  if (stream.match(/^<\?\w*/)) {
162
  state.curMode = phpMode;
163
- if (!state.php) state.php = CodeMirror.startState(phpMode, htmlMode.indent(state.html, ""))
164
  state.curState = state.php;
165
  return "meta";
166
  }
@@ -213,11 +213,11 @@
213
 
214
  token: dispatch,
215
 
216
- indent: function(state, textAfter) {
217
  if ((state.curMode != phpMode && /^\s*<\//.test(textAfter)) ||
218
  (state.curMode == phpMode && /^\?>/.test(textAfter)))
219
- return htmlMode.indent(state.html, textAfter);
220
- return state.curMode.indent(state.curState, textAfter);
221
  },
222
 
223
  blockCommentStart: "/*",
160
  if (!isPHP) {
161
  if (stream.match(/^<\?\w*/)) {
162
  state.curMode = phpMode;
163
+ if (!state.php) state.php = CodeMirror.startState(phpMode, htmlMode.indent(state.html, "", ""))
164
  state.curState = state.php;
165
  return "meta";
166
  }
213
 
214
  token: dispatch,
215
 
216
+ indent: function(state, textAfter, line) {
217
  if ((state.curMode != phpMode && /^\s*<\//.test(textAfter)) ||
218
  (state.curMode == phpMode && /^\?>/.test(textAfter)))
219
+ return htmlMode.indent(state.html, textAfter, line);
220
+ return state.curMode.indent(state.curState, textAfter, line);
221
  },
222
 
223
  blockCommentStart: "/*",
vendor/codemirror/mode/xml/index.html CHANGED
@@ -9,7 +9,7 @@
9
  <script src="xml.js"></script>
10
  <style>.CodeMirror {border-top: 1px solid black; border-bottom: 1px solid black;}</style>
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>
9
  <script src="xml.js"></script>
10
  <style>.CodeMirror {border-top: 1px solid black; border-bottom: 1px solid black;}</style>
11
  <div id=nav>
12
+ <a href="https://codemirror.net"><h1>CodeMirror</h1><img id=logo src="../../doc/logo.png" alt=""></a>
13
 
14
  <ul>
15
  <li><a href="../../index.html">Home</a>
vendor/codemirror/mode/xml/xml.js CHANGED
@@ -189,7 +189,7 @@ CodeMirror.defineMode("xml", function(editorConf, config_) {
189
 
190
  function Context(state, tagName, startOfLine) {
191
  this.prev = state.context;
192
- this.tagName = tagName;
193
  this.indent = state.indented;
194
  this.startOfLine = startOfLine;
195
  if (config.doNotIndent.hasOwnProperty(tagName) || (state.context && state.context.noIndent))
@@ -390,6 +390,17 @@ CodeMirror.defineMode("xml", function(editorConf, config_) {
390
  skipAttribute: function(state) {
391
  if (state.state == attrValueState)
392
  state.state = attrState
 
 
 
 
 
 
 
 
 
 
 
393
  }
394
  };
395
  });
189
 
190
  function Context(state, tagName, startOfLine) {
191
  this.prev = state.context;
192
+ this.tagName = tagName || "";
193
  this.indent = state.indented;
194
  this.startOfLine = startOfLine;
195
  if (config.doNotIndent.hasOwnProperty(tagName) || (state.context && state.context.noIndent))
390
  skipAttribute: function(state) {
391
  if (state.state == attrValueState)
392
  state.state = attrState
393
+ },
394
+
395
+ xmlCurrentTag: function(state) {
396
+ return state.tagName ? {name: state.tagName, close: state.type == "closeTag"} : null
397
+ },
398
+
399
+ xmlCurrentContext: function(state) {
400
+ var context = []
401
+ for (var cx = state.context; cx; cx = cx.prev)
402
+ context.push(cx.tagName)
403
+ return context.reverse()
404
  }
405
  };
406
  });