@codemirror/view 0.19.46 → 0.20.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.js CHANGED
@@ -1,8 +1,5 @@
1
- import { MapMode, Text as Text$1, Facet, StateEffect, ChangeSet, EditorSelection, EditorState, CharCategory, Transaction, Prec, combineConfig, StateField } from '@codemirror/state';
1
+ import { Text, RangeSet, MapMode, RangeValue, Facet, StateEffect, ChangeSet, findClusterBreak, EditorSelection, EditorState, findColumn, CharCategory, Prec, Transaction, combineConfig, StateField, RangeSetBuilder, codePointAt, countColumn } from '@codemirror/state';
2
2
  import { StyleModule } from 'style-mod';
3
- import { RangeSet, RangeValue, RangeSetBuilder } from '@codemirror/rangeset';
4
- export { Range } from '@codemirror/rangeset';
5
- import { Text, findClusterBreak, findColumn, codePointAt, countColumn } from '@codemirror/text';
6
3
  import { keyName, base } from 'w3c-keyname';
7
4
 
8
5
  function getSelection(root) {
@@ -315,32 +312,34 @@ class ContentView {
315
312
  sync(track) {
316
313
  if (this.dirty & 2 /* Node */) {
317
314
  let parent = this.dom;
318
- let pos = parent.firstChild;
315
+ let prev = null, next;
319
316
  for (let child of this.children) {
320
317
  if (child.dirty) {
321
- if (!child.dom && pos) {
322
- let contentView = ContentView.get(pos);
318
+ if (!child.dom && (next = prev ? prev.nextSibling : parent.firstChild)) {
319
+ let contentView = ContentView.get(next);
323
320
  if (!contentView || !contentView.parent && contentView.constructor == child.constructor)
324
- child.reuseDOM(pos);
321
+ child.reuseDOM(next);
325
322
  }
326
323
  child.sync(track);
327
324
  child.dirty = 0 /* Not */;
328
325
  }
329
- if (track && !track.written && track.node == parent && pos != child.dom)
326
+ next = prev ? prev.nextSibling : parent.firstChild;
327
+ if (track && !track.written && track.node == parent && next != child.dom)
330
328
  track.written = true;
331
329
  if (child.dom.parentNode == parent) {
332
- while (pos && pos != child.dom)
333
- pos = rm(pos);
334
- pos = child.dom.nextSibling;
330
+ while (next && next != child.dom)
331
+ next = rm$1(next);
335
332
  }
336
333
  else {
337
- parent.insertBefore(child.dom, pos);
334
+ parent.insertBefore(child.dom, next);
338
335
  }
336
+ prev = child.dom;
339
337
  }
340
- if (pos && track && track.node == parent)
338
+ next = prev ? prev.nextSibling : parent.firstChild;
339
+ if (next && track && track.node == parent)
341
340
  track.written = true;
342
- while (pos)
343
- pos = rm(pos);
341
+ while (next)
342
+ next = rm$1(next);
344
343
  }
345
344
  else if (this.dirty & 1 /* Child */) {
346
345
  for (let child of this.children)
@@ -486,7 +485,7 @@ class ContentView {
486
485
  }
487
486
  ContentView.prototype.breakAfter = 0;
488
487
  // Remove a DOM node and return its next sibling.
489
- function rm(dom) {
488
+ function rm$1(dom) {
490
489
  let next = dom.nextSibling;
491
490
  dom.parentNode.removeChild(dom);
492
491
  return next;
@@ -933,6 +932,7 @@ class WidgetBufferView extends ContentView {
933
932
  if (!this.dom) {
934
933
  let dom = document.createElement("img");
935
934
  dom.className = "cm-widgetBuffer";
935
+ dom.setAttribute("aria-hidden", "true");
936
936
  this.setDOM(dom);
937
937
  }
938
938
  }
@@ -1073,7 +1073,7 @@ function updateAttrs(dom, prev, attrs) {
1073
1073
  Widgets added to the content are described by subclasses of this
1074
1074
  class. Using a description object like that makes it possible to
1075
1075
  delay creating of the DOM structure for a widget until it is
1076
- needed, and to avoid redrawing widgets even when the decorations
1076
+ needed, and to avoid redrawing widgets even if the decorations
1077
1077
  that define them are recreated.
1078
1078
  */
1079
1079
  class WidgetType {
@@ -1086,7 +1086,7 @@ class WidgetType {
1086
1086
  returns `false`, which will cause new instances of the widget to
1087
1087
  always be redrawn.
1088
1088
  */
1089
- eq(_widget) { return false; }
1089
+ eq(widget) { return false; }
1090
1090
  /**
1091
1091
  Update a DOM element created by a widget of the same type (but
1092
1092
  different, non-`eq` content) to reflect this widget. May return
@@ -1094,7 +1094,7 @@ class WidgetType {
1094
1094
  couldn't (in which case the widget will be redrawn). The default
1095
1095
  implementation just returns false.
1096
1096
  */
1097
- updateDOM(_dom) { return false; }
1097
+ updateDOM(dom) { return false; }
1098
1098
  /**
1099
1099
  @internal
1100
1100
  */
@@ -1113,7 +1113,7 @@ class WidgetType {
1113
1113
  should be ignored by the editor. The default is to ignore all
1114
1114
  events.
1115
1115
  */
1116
- ignoreEvent(_event) { return true; }
1116
+ ignoreEvent(event) { return true; }
1117
1117
  /**
1118
1118
  @internal
1119
1119
  */
@@ -1122,7 +1122,7 @@ class WidgetType {
1122
1122
  This is called when the an instance of the widget is removed
1123
1123
  from the editor view.
1124
1124
  */
1125
- destroy(_dom) { }
1125
+ destroy(dom) { }
1126
1126
  }
1127
1127
  /**
1128
1128
  The different types of blocks that can occur in an editor view.
@@ -1148,7 +1148,8 @@ return BlockType})(BlockType || (BlockType = {}));
1148
1148
  /**
1149
1149
  A decoration provides information on how to draw or style a piece
1150
1150
  of content. You'll usually use it wrapped in a
1151
- [`Range`](https://codemirror.net/6/docs/ref/#rangeset.Range), which adds a start and end position.
1151
+ [`Range`](https://codemirror.net/6/docs/ref/#state.Range), which adds a start and end position.
1152
+ @nonabstract
1152
1153
  */
1153
1154
  class Decoration extends RangeValue {
1154
1155
  /**
@@ -1187,22 +1188,21 @@ class Decoration extends RangeValue {
1187
1188
  Create a mark decoration, which influences the styling of the
1188
1189
  content in its range. Nested mark decorations will cause nested
1189
1190
  DOM elements to be created. Nesting order is determined by
1190
- precedence of the [facet](https://codemirror.net/6/docs/ref/#view.EditorView^decorations) or
1191
- (below the facet-provided decorations) [view
1192
- plugin](https://codemirror.net/6/docs/ref/#view.PluginSpec.decorations). Such elements are split
1193
- on line boundaries and on the boundaries of higher-precedence
1194
- decorations.
1191
+ precedence of the [facet](https://codemirror.net/6/docs/ref/#view.EditorView^decorations), with
1192
+ the higher-precedence decorations creating the inner DOM nodes.
1193
+ Such elements are split on line boundaries and on the boundaries
1194
+ of lower-precedence decorations.
1195
1195
  */
1196
1196
  static mark(spec) {
1197
1197
  return new MarkDecoration(spec);
1198
1198
  }
1199
1199
  /**
1200
- Create a widget decoration, which adds an element at the given
1201
- position.
1200
+ Create a widget decoration, which displays a DOM element at the
1201
+ given position.
1202
1202
  */
1203
1203
  static widget(spec) {
1204
1204
  let side = spec.side || 0, block = !!spec.block;
1205
- side += block ? (side > 0 ? 400000000 /* BlockAfter */ : -500000000 /* BlockBefore */) : (side > 0 ? 100000000 /* InlineAfter */ : -100000000 /* InlineBefore */);
1205
+ side += block ? (side > 0 ? 300000000 /* BlockAfter */ : -400000000 /* BlockBefore */) : (side > 0 ? 100000000 /* InlineAfter */ : -100000000 /* InlineBefore */);
1206
1206
  return new PointDecoration(spec, side, side, block, spec.widget || null, false);
1207
1207
  }
1208
1208
  /**
@@ -1212,8 +1212,8 @@ class Decoration extends RangeValue {
1212
1212
  static replace(spec) {
1213
1213
  let block = !!spec.block, startSide, endSide;
1214
1214
  if (spec.isBlockGap) {
1215
- startSide = -400000000 /* GapStart */;
1216
- endSide = 300000000 /* GapEnd */;
1215
+ startSide = -500000000 /* GapStart */;
1216
+ endSide = 400000000 /* GapEnd */;
1217
1217
  }
1218
1218
  else {
1219
1219
  let { start, end } = getInclusive(spec, block);
@@ -1430,7 +1430,7 @@ class LineView extends ContentView {
1430
1430
  let last = this.dom.lastChild;
1431
1431
  while (last && ContentView.get(last) instanceof MarkView)
1432
1432
  last = last.lastChild;
1433
- if (!last ||
1433
+ if (!last || !this.length ||
1434
1434
  last.nodeName != "BR" && ((_a = ContentView.get(last)) === null || _a === void 0 ? void 0 : _a.isEditable) == false &&
1435
1435
  (!browser.ios || !this.children.some(ch => ch instanceof TextView))) {
1436
1436
  let hack = document.createElement("BR");
@@ -1509,7 +1509,7 @@ class BlockWidgetView extends ContentView {
1509
1509
  }
1510
1510
  }
1511
1511
  get overrideDOMText() {
1512
- return this.parent ? this.parent.view.state.doc.slice(this.posAtStart, this.posAtEnd) : Text$1.empty;
1512
+ return this.parent ? this.parent.view.state.doc.slice(this.posAtStart, this.posAtEnd) : Text.empty;
1513
1513
  }
1514
1514
  domBoundsAround() { return null; }
1515
1515
  become(other) {
@@ -1536,11 +1536,11 @@ class BlockWidgetView extends ContentView {
1536
1536
  }
1537
1537
 
1538
1538
  class ContentBuilder {
1539
- constructor(doc, pos, end, disallowBlockEffectsBelow) {
1539
+ constructor(doc, pos, end, disallowBlockEffectsFor) {
1540
1540
  this.doc = doc;
1541
1541
  this.pos = pos;
1542
1542
  this.end = end;
1543
- this.disallowBlockEffectsBelow = disallowBlockEffectsBelow;
1543
+ this.disallowBlockEffectsFor = disallowBlockEffectsFor;
1544
1544
  this.content = [];
1545
1545
  this.curLine = null;
1546
1546
  this.breakAtStart = 0;
@@ -1625,7 +1625,13 @@ class ContentBuilder {
1625
1625
  if (this.openStart < 0)
1626
1626
  this.openStart = openStart;
1627
1627
  }
1628
- point(from, to, deco, active, openStart) {
1628
+ point(from, to, deco, active, openStart, index) {
1629
+ if (this.disallowBlockEffectsFor[index] && deco instanceof PointDecoration) {
1630
+ if (deco.block)
1631
+ throw new RangeError("Block decorations may not be specified via plugins");
1632
+ if (to > this.doc.lineAt(this.pos).to)
1633
+ throw new RangeError("Decorations that replace line breaks may not be specified via plugins");
1634
+ }
1629
1635
  let len = to - from;
1630
1636
  if (deco instanceof PointDecoration) {
1631
1637
  if (deco.block) {
@@ -1669,17 +1675,8 @@ class ContentBuilder {
1669
1675
  if (this.openStart < 0)
1670
1676
  this.openStart = openStart;
1671
1677
  }
1672
- filterPoint(from, to, value, index) {
1673
- if (index < this.disallowBlockEffectsBelow && value instanceof PointDecoration) {
1674
- if (value.block)
1675
- throw new RangeError("Block decorations may not be specified via plugins");
1676
- if (to > this.doc.lineAt(this.pos).to)
1677
- throw new RangeError("Decorations that replace line breaks may not be specified via plugins");
1678
- }
1679
- return true;
1680
- }
1681
- static build(text, from, to, decorations, pluginDecorationLength) {
1682
- let builder = new ContentBuilder(text, from, to, pluginDecorationLength);
1678
+ static build(text, from, to, decorations, dynamicDecorationMap) {
1679
+ let builder = new ContentBuilder(text, from, to, dynamicDecorationMap);
1683
1680
  builder.openEnd = RangeSet.spans(decorations, from, to, builder);
1684
1681
  if (builder.openStart < 0)
1685
1682
  builder.openStart = builder.openEnd;
@@ -1709,13 +1706,8 @@ const mouseSelectionStyle = /*@__PURE__*/Facet.define();
1709
1706
  const exceptionSink = /*@__PURE__*/Facet.define();
1710
1707
  const updateListener = /*@__PURE__*/Facet.define();
1711
1708
  const inputHandler = /*@__PURE__*/Facet.define();
1712
- // FIXME remove
1713
- const scrollTo = /*@__PURE__*/StateEffect.define({
1714
- map: (range, changes) => range.map(changes)
1715
- });
1716
- // FIXME remove
1717
- const centerOn = /*@__PURE__*/StateEffect.define({
1718
- map: (range, changes) => range.map(changes)
1709
+ const perLineTextDirection = /*@__PURE__*/Facet.define({
1710
+ combine: values => values.some(x => x)
1719
1711
  });
1720
1712
  class ScrollTarget {
1721
1713
  constructor(range, y = "nearest", x = "nearest", yMargin = 5, xMargin = 5) {
@@ -1754,83 +1746,6 @@ function logException(state, exception, context) {
1754
1746
  console.error(exception);
1755
1747
  }
1756
1748
  const editable = /*@__PURE__*/Facet.define({ combine: values => values.length ? values[0] : true });
1757
- /**
1758
- Used to [declare](https://codemirror.net/6/docs/ref/#view.PluginSpec.provide) which
1759
- [fields](https://codemirror.net/6/docs/ref/#view.PluginValue) a [view plugin](https://codemirror.net/6/docs/ref/#view.ViewPlugin)
1760
- provides.
1761
- */
1762
- class PluginFieldProvider {
1763
- /**
1764
- @internal
1765
- */
1766
- constructor(
1767
- /**
1768
- @internal
1769
- */
1770
- field,
1771
- /**
1772
- @internal
1773
- */
1774
- get) {
1775
- this.field = field;
1776
- this.get = get;
1777
- }
1778
- }
1779
- /**
1780
- Plugin fields are a mechanism for allowing plugins to provide
1781
- values that can be retrieved through the
1782
- [`pluginField`](https://codemirror.net/6/docs/ref/#view.EditorView.pluginField) view method.
1783
- */
1784
- class PluginField {
1785
- /**
1786
- Create a [provider](https://codemirror.net/6/docs/ref/#view.PluginFieldProvider) for this field,
1787
- to use with a plugin's [provide](https://codemirror.net/6/docs/ref/#view.PluginSpec.provide)
1788
- option.
1789
- */
1790
- from(get) {
1791
- return new PluginFieldProvider(this, get);
1792
- }
1793
- /**
1794
- Define a new plugin field.
1795
- */
1796
- static define() { return new PluginField(); }
1797
- }
1798
- /**
1799
- This field can be used by plugins to provide
1800
- [decorations](https://codemirror.net/6/docs/ref/#view.Decoration).
1801
-
1802
- **Note**: For reasons of data flow (plugins are only updated
1803
- after the viewport is computed), decorations produced by plugins
1804
- are _not_ taken into account when predicting the vertical layout
1805
- structure of the editor. They **must not** introduce block
1806
- widgets (that will raise an error) or replacing decorations that
1807
- cover line breaks (these will be ignored if they occur). Such
1808
- decorations, or others that cause a large amount of vertical
1809
- size shift compared to the undecorated content, should be
1810
- provided through the state-level [`decorations`
1811
- facet](https://codemirror.net/6/docs/ref/#view.EditorView^decorations) instead.
1812
- */
1813
- PluginField.decorations = /*@__PURE__*/PluginField.define();
1814
- /**
1815
- Used to provide ranges that should be treated as atoms as far as
1816
- cursor motion is concerned. This causes methods like
1817
- [`moveByChar`](https://codemirror.net/6/docs/ref/#view.EditorView.moveByChar) and
1818
- [`moveVertically`](https://codemirror.net/6/docs/ref/#view.EditorView.moveVertically) (and the
1819
- commands built on top of them) to skip across such regions when
1820
- a selection endpoint would enter them. This does _not_ prevent
1821
- direct programmatic [selection
1822
- updates](https://codemirror.net/6/docs/ref/#state.TransactionSpec.selection) from moving into such
1823
- regions.
1824
- */
1825
- PluginField.atomicRanges = /*@__PURE__*/PluginField.define();
1826
- /**
1827
- Plugins can provide additional scroll margins (space around the
1828
- sides of the scrolling element that should be considered
1829
- invisible) through this field. This can be useful when the
1830
- plugin introduces elements that cover part of that element (for
1831
- example a horizontally fixed gutter).
1832
- */
1833
- PluginField.scrollMargins = /*@__PURE__*/PluginField.define();
1834
1749
  let nextPluginID = 0;
1835
1750
  const viewPlugin = /*@__PURE__*/Facet.define();
1836
1751
  /**
@@ -1851,27 +1766,29 @@ class ViewPlugin {
1851
1766
  /**
1852
1767
  @internal
1853
1768
  */
1854
- fields) {
1769
+ domEventHandlers, buildExtensions) {
1855
1770
  this.id = id;
1856
1771
  this.create = create;
1857
- this.fields = fields;
1858
- this.extension = viewPlugin.of(this);
1772
+ this.domEventHandlers = domEventHandlers;
1773
+ this.extension = buildExtensions(this);
1859
1774
  }
1860
1775
  /**
1861
1776
  Define a plugin from a constructor function that creates the
1862
1777
  plugin's value, given an editor view.
1863
1778
  */
1864
1779
  static define(create, spec) {
1865
- let { eventHandlers, provide, decorations } = spec || {};
1866
- let fields = [];
1867
- if (provide)
1868
- for (let provider of Array.isArray(provide) ? provide : [provide])
1869
- fields.push(provider);
1870
- if (eventHandlers)
1871
- fields.push(domEventHandlers.from((value) => ({ plugin: value, handlers: eventHandlers })));
1872
- if (decorations)
1873
- fields.push(PluginField.decorations.from(decorations));
1874
- return new ViewPlugin(nextPluginID++, create, fields);
1780
+ const { eventHandlers, provide, decorations: deco } = spec || {};
1781
+ return new ViewPlugin(nextPluginID++, create, eventHandlers, plugin => {
1782
+ let ext = [viewPlugin.of(plugin)];
1783
+ if (deco)
1784
+ ext.push(decorations.of(view => {
1785
+ let pluginInst = view.plugin(plugin);
1786
+ return pluginInst ? deco(pluginInst) : Decoration.none;
1787
+ }));
1788
+ if (provide)
1789
+ ext.push(provide(plugin));
1790
+ return ext;
1791
+ });
1875
1792
  }
1876
1793
  /**
1877
1794
  Create a plugin for a class whose constructor takes a single
@@ -1881,7 +1798,6 @@ class ViewPlugin {
1881
1798
  return ViewPlugin.define(view => new cls(view), spec);
1882
1799
  }
1883
1800
  }
1884
- const domEventHandlers = /*@__PURE__*/PluginField.define();
1885
1801
  class PluginInstance {
1886
1802
  constructor(spec) {
1887
1803
  this.spec = spec;
@@ -1894,12 +1810,6 @@ class PluginInstance {
1894
1810
  // initialized on the first update.
1895
1811
  this.value = null;
1896
1812
  }
1897
- takeField(type, target) {
1898
- if (this.spec)
1899
- for (let { field, get } of this.spec.fields)
1900
- if (field == type)
1901
- target.push(get(this.value));
1902
- }
1903
1813
  update(view) {
1904
1814
  if (!this.value) {
1905
1815
  if (this.spec) {
@@ -1951,6 +1861,8 @@ const editorAttributes = /*@__PURE__*/Facet.define();
1951
1861
  const contentAttributes = /*@__PURE__*/Facet.define();
1952
1862
  // Provide decorations
1953
1863
  const decorations = /*@__PURE__*/Facet.define();
1864
+ const atomicRanges = /*@__PURE__*/Facet.define();
1865
+ const scrollMargins = /*@__PURE__*/Facet.define();
1954
1866
  const styleModule = /*@__PURE__*/Facet.define();
1955
1867
  class ChangedRange {
1956
1868
  constructor(fromA, toA, fromB, toB) {
@@ -2051,8 +1963,8 @@ class ViewUpdate {
2051
1963
  return (this.flags & 4 /* Viewport */) > 0;
2052
1964
  }
2053
1965
  /**
2054
- Indicates whether the height of an element in the editor changed
2055
- in this update.
1966
+ Indicates whether the height of a block element in the editor
1967
+ changed in this update.
2056
1968
  */
2057
1969
  get heightChanged() {
2058
1970
  return (this.flags & 2 /* Height */) > 0;
@@ -2511,7 +2423,7 @@ class DocView extends ContentView {
2511
2423
  this.view = view;
2512
2424
  this.compositionDeco = Decoration.none;
2513
2425
  this.decorations = [];
2514
- this.pluginDecorationLength = 0;
2426
+ this.dynamicDecorationMap = [];
2515
2427
  // Track a minimum width for the editor. When measuring sizes in
2516
2428
  // measureVisibleLineHeights, this is updated to point at the width
2517
2429
  // of a given element and its extent in the document. When a change
@@ -2617,7 +2529,7 @@ class DocView extends ContentView {
2617
2529
  if (!next)
2618
2530
  break;
2619
2531
  let { fromA, toA, fromB, toB } = next;
2620
- let { content, breakAtStart, openStart, openEnd } = ContentBuilder.build(this.view.state.doc, fromB, toB, this.decorations, this.pluginDecorationLength);
2532
+ let { content, breakAtStart, openStart, openEnd } = ContentBuilder.build(this.view.state.doc, fromB, toB, this.decorations, this.dynamicDecorationMap);
2621
2533
  let { i: toI, off: toOff } = cursor.findPos(toA, 1);
2622
2534
  let { i: fromI, off: fromOff } = cursor.findPos(fromA, -1);
2623
2535
  replaceRange(this, fromI, fromOff, toI, toOff, content, breakAtStart, openStart, openEnd);
@@ -2758,11 +2670,11 @@ class DocView extends ContentView {
2758
2670
  off = start;
2759
2671
  }
2760
2672
  }
2761
- measureVisibleLineHeights() {
2762
- let result = [], { from, to } = this.view.viewState.viewport;
2673
+ measureVisibleLineHeights(viewport) {
2674
+ let result = [], { from, to } = viewport;
2763
2675
  let contentWidth = this.view.contentDOM.clientWidth;
2764
2676
  let isWider = contentWidth > Math.max(this.view.scrollDOM.clientWidth, this.minWidth) + 1;
2765
- let widest = -1;
2677
+ let widest = -1, ltr = this.view.textDirection == Direction.LTR;
2766
2678
  for (let pos = 0, i = 0; i < this.children.length; i++) {
2767
2679
  let child = this.children[i], end = pos + child.length;
2768
2680
  if (end > to)
@@ -2775,8 +2687,7 @@ class DocView extends ContentView {
2775
2687
  let rects = last ? clientRectsFor(last) : [];
2776
2688
  if (rects.length) {
2777
2689
  let rect = rects[rects.length - 1];
2778
- let width = this.view.textDirection == Direction.LTR ? rect.right - childRect.left
2779
- : childRect.right - rect.left;
2690
+ let width = ltr ? rect.right - childRect.left : childRect.right - rect.left;
2780
2691
  if (width > widest) {
2781
2692
  widest = width;
2782
2693
  this.minWidth = contentWidth;
@@ -2790,6 +2701,10 @@ class DocView extends ContentView {
2790
2701
  }
2791
2702
  return result;
2792
2703
  }
2704
+ textDirectionAt(pos) {
2705
+ let { i } = this.childPos(pos, 1);
2706
+ return getComputedStyle(this.children[i].dom).direction == "rtl" ? Direction.RTL : Direction.LTR;
2707
+ }
2793
2708
  measureTextSize() {
2794
2709
  for (let child of this.children) {
2795
2710
  if (child instanceof LineView) {
@@ -2841,11 +2756,14 @@ class DocView extends ContentView {
2841
2756
  return Decoration.set(deco);
2842
2757
  }
2843
2758
  updateDeco() {
2844
- let pluginDecorations = this.view.pluginField(PluginField.decorations);
2845
- this.pluginDecorationLength = pluginDecorations.length;
2759
+ let allDeco = this.view.state.facet(decorations).map((d, i) => {
2760
+ let dynamic = this.dynamicDecorationMap[i] = typeof d == "function";
2761
+ return dynamic ? d(this.view) : d;
2762
+ });
2763
+ for (let i = allDeco.length; i < allDeco.length + 3; i++)
2764
+ this.dynamicDecorationMap[i] = false;
2846
2765
  return this.decorations = [
2847
- ...pluginDecorations,
2848
- ...this.view.state.facet(decorations),
2766
+ ...allDeco,
2849
2767
  this.compositionDeco,
2850
2768
  this.computeBlockGapDeco(),
2851
2769
  this.view.viewState.lineGapDeco
@@ -2860,7 +2778,7 @@ class DocView extends ContentView {
2860
2778
  rect = { left: Math.min(rect.left, other.left), top: Math.min(rect.top, other.top),
2861
2779
  right: Math.max(rect.right, other.right), bottom: Math.max(rect.bottom, other.bottom) };
2862
2780
  let mLeft = 0, mRight = 0, mTop = 0, mBottom = 0;
2863
- for (let margins of this.view.pluginField(PluginField.scrollMargins))
2781
+ for (let margins of this.view.state.facet(scrollMargins).map(f => f(this.view)))
2864
2782
  if (margins) {
2865
2783
  let { left, right, top, bottom } = margins;
2866
2784
  if (left != null)
@@ -3249,7 +3167,8 @@ function moveToLineBoundary(view, start, forward, includeWrap) {
3249
3167
  : view.coordsAtPos(start.assoc < 0 && start.head > line.from ? start.head - 1 : start.head);
3250
3168
  if (coords) {
3251
3169
  let editorRect = view.dom.getBoundingClientRect();
3252
- let pos = view.posAtCoords({ x: forward == (view.textDirection == Direction.LTR) ? editorRect.right - 1 : editorRect.left + 1,
3170
+ let direction = view.textDirectionAt(line.from);
3171
+ let pos = view.posAtCoords({ x: forward == (direction == Direction.LTR) ? editorRect.right - 1 : editorRect.left + 1,
3253
3172
  y: (coords.top + coords.bottom) / 2 });
3254
3173
  if (pos != null)
3255
3174
  return EditorSelection.cursor(pos, forward ? -1 : 1);
@@ -3260,8 +3179,9 @@ function moveToLineBoundary(view, start, forward, includeWrap) {
3260
3179
  }
3261
3180
  function moveByChar(view, start, forward, by) {
3262
3181
  let line = view.state.doc.lineAt(start.head), spans = view.bidiSpans(line);
3182
+ let direction = view.textDirectionAt(line.from);
3263
3183
  for (let cur = start, check = null;;) {
3264
- let next = moveVisually(line, spans, view.textDirection, cur, forward), char = movedOver;
3184
+ let next = moveVisually(line, spans, direction, cur, forward), char = movedOver;
3265
3185
  if (!next) {
3266
3186
  if (line.number == (forward ? view.state.doc.lines : 1))
3267
3187
  return cur;
@@ -3319,7 +3239,7 @@ function moveVertically(view, start, forward, distance) {
3319
3239
  }
3320
3240
  }
3321
3241
  function skipAtoms(view, oldPos, pos) {
3322
- let atoms = view.pluginField(PluginField.atomicRanges);
3242
+ let atoms = view.state.facet(atomicRanges).map(f => f(view));
3323
3243
  for (;;) {
3324
3244
  let moved = false;
3325
3245
  for (let set of atoms) {
@@ -3367,10 +3287,10 @@ class InputState {
3367
3287
  for (let type in handlers) {
3368
3288
  let handler = handlers[type];
3369
3289
  view.contentDOM.addEventListener(type, (event) => {
3370
- if (type == "keydown" && this.keydown(view, event))
3371
- return;
3372
3290
  if (!eventBelongsToEditor(view, event) || this.ignoreDuringComposition(event))
3373
3291
  return;
3292
+ if (type == "keydown" && this.keydown(view, event))
3293
+ return;
3374
3294
  if (this.mustFlushObserver(event))
3375
3295
  view.observer.forceFlush();
3376
3296
  if (this.runCustomHandlers(type, view, event))
@@ -3381,7 +3301,6 @@ class InputState {
3381
3301
  this.registeredEvents.push(type);
3382
3302
  }
3383
3303
  this.notifiedFocused = view.hasFocus;
3384
- this.ensureHandlers(view);
3385
3304
  // On Safari adding an input event handler somehow prevents an
3386
3305
  // issue where the composition vanishes when you press enter.
3387
3306
  if (browser.safari)
@@ -3391,20 +3310,23 @@ class InputState {
3391
3310
  this.lastSelectionOrigin = origin;
3392
3311
  this.lastSelectionTime = Date.now();
3393
3312
  }
3394
- ensureHandlers(view) {
3395
- let handlers = this.customHandlers = view.pluginField(domEventHandlers);
3396
- for (let set of handlers) {
3397
- for (let type in set.handlers)
3398
- if (this.registeredEvents.indexOf(type) < 0 && type != "scroll") {
3399
- this.registeredEvents.push(type);
3400
- view.contentDOM.addEventListener(type, (event) => {
3401
- if (!eventBelongsToEditor(view, event))
3402
- return;
3403
- if (this.runCustomHandlers(type, view, event))
3404
- event.preventDefault();
3405
- });
3406
- }
3407
- }
3313
+ ensureHandlers(view, plugins) {
3314
+ var _a;
3315
+ let handlers;
3316
+ for (let plugin of plugins)
3317
+ if (handlers = (_a = plugin.update(view).spec) === null || _a === void 0 ? void 0 : _a.domEventHandlers) {
3318
+ this.customHandlers.push({ plugin: plugin.value, handlers });
3319
+ for (let type in handlers)
3320
+ if (this.registeredEvents.indexOf(type) < 0 && type != "scroll") {
3321
+ this.registeredEvents.push(type);
3322
+ view.contentDOM.addEventListener(type, (event) => {
3323
+ if (!eventBelongsToEditor(view, event))
3324
+ return;
3325
+ if (this.runCustomHandlers(type, view, event))
3326
+ event.preventDefault();
3327
+ });
3328
+ }
3329
+ }
3408
3330
  }
3409
3331
  runCustomHandlers(type, view, event) {
3410
3332
  for (let set of this.customHandlers) {
@@ -3438,7 +3360,7 @@ class InputState {
3438
3360
  // Must always run, even if a custom handler handled the event
3439
3361
  this.lastKeyCode = event.keyCode;
3440
3362
  this.lastKeyTime = Date.now();
3441
- if (this.screenKeyEvent(view, event))
3363
+ if (event.keyCode == 9 && Date.now() < this.lastEscPress + 2000)
3442
3364
  return true;
3443
3365
  // Chrome for Android usually doesn't fire proper key events, but
3444
3366
  // occasionally does, usually surrounded by a bunch of complicated
@@ -3482,20 +3404,12 @@ class InputState {
3482
3404
  // compositionend and keydown events are sometimes emitted in the
3483
3405
  // wrong order. The key event should still be ignored, even when
3484
3406
  // it happens after the compositionend event.
3485
- if (browser.safari && Date.now() - this.compositionEndedAt < 500) {
3407
+ if (browser.safari && Date.now() - this.compositionEndedAt < 100) {
3486
3408
  this.compositionEndedAt = 0;
3487
3409
  return true;
3488
3410
  }
3489
3411
  return false;
3490
3412
  }
3491
- screenKeyEvent(view, event) {
3492
- let protectedTab = event.keyCode == 9 && Date.now() < this.lastEscPress + 2000;
3493
- if (event.keyCode == 27)
3494
- this.lastEscPress = Date.now();
3495
- else if (modifierCodes.indexOf(event.keyCode) < 0)
3496
- this.lastEscPress = 0;
3497
- return protectedTab;
3498
- }
3499
3413
  mustFlushObserver(event) {
3500
3414
  return (event.type == "keydown" && event.keyCode != 229) ||
3501
3415
  event.type == "compositionend" && !browser.ios;
@@ -3669,6 +3583,10 @@ function doPaste(view, input) {
3669
3583
  }
3670
3584
  handlers.keydown = (view, event) => {
3671
3585
  view.inputState.setSelectionOrigin("select");
3586
+ if (event.keyCode == 27)
3587
+ view.inputState.lastEscPress = Date.now();
3588
+ else if (modifierCodes.indexOf(event.keyCode) < 0)
3589
+ view.inputState.lastEscPress = 0;
3672
3590
  };
3673
3591
  let lastTouch = 0;
3674
3592
  handlers.touchstart = (view, e) => {
@@ -3926,14 +3844,6 @@ handlers.focus = handlers.blur = view => {
3926
3844
  view.update([]);
3927
3845
  }, 10);
3928
3846
  };
3929
- handlers.beforeprint = view => {
3930
- view.viewState.printing = true;
3931
- view.requestMeasure();
3932
- setTimeout(() => {
3933
- view.viewState.printing = false;
3934
- view.requestMeasure();
3935
- }, 2000);
3936
- };
3937
3847
  function forceClearComposition(view, rapid) {
3938
3848
  if (view.docView.compositionDeco.size) {
3939
3849
  view.inputState.rapidCompositionStart = rapid;
@@ -4002,7 +3912,6 @@ class HeightOracle {
4002
3912
  constructor() {
4003
3913
  this.doc = Text.empty;
4004
3914
  this.lineWrapping = false;
4005
- this.direction = Direction.LTR;
4006
3915
  this.heightSamples = {};
4007
3916
  this.lineHeight = 14;
4008
3917
  this.charWidth = 7;
@@ -4023,8 +3932,8 @@ class HeightOracle {
4023
3932
  return lines * this.lineHeight;
4024
3933
  }
4025
3934
  setDoc(doc) { this.doc = doc; return this; }
4026
- mustRefreshForStyle(whiteSpace, direction) {
4027
- return (wrappingWhiteSpace.indexOf(whiteSpace) > -1) != this.lineWrapping || this.direction != direction;
3935
+ mustRefreshForWrapping(whiteSpace) {
3936
+ return (wrappingWhiteSpace.indexOf(whiteSpace) > -1) != this.lineWrapping;
4028
3937
  }
4029
3938
  mustRefreshForHeights(lineHeights) {
4030
3939
  let newHeight = false;
@@ -4040,13 +3949,10 @@ class HeightOracle {
4040
3949
  }
4041
3950
  return newHeight;
4042
3951
  }
4043
- refresh(whiteSpace, direction, lineHeight, charWidth, lineLength, knownHeights) {
3952
+ refresh(whiteSpace, lineHeight, charWidth, lineLength, knownHeights) {
4044
3953
  let lineWrapping = wrappingWhiteSpace.indexOf(whiteSpace) > -1;
4045
- let changed = Math.round(lineHeight) != Math.round(this.lineHeight) ||
4046
- this.lineWrapping != lineWrapping ||
4047
- this.direction != direction;
3954
+ let changed = Math.round(lineHeight) != Math.round(this.lineHeight) || this.lineWrapping != lineWrapping;
4048
3955
  this.lineWrapping = lineWrapping;
4049
- this.direction = direction;
4050
3956
  this.lineHeight = lineHeight;
4051
3957
  this.charWidth = charWidth;
4052
3958
  this.lineLength = lineLength;
@@ -4127,12 +4033,6 @@ class BlockInfo {
4127
4033
  .concat(Array.isArray(other.type) ? other.type : [other]);
4128
4034
  return new BlockInfo(this.from, this.length + other.length, this.top, this.height + other.height, detail);
4129
4035
  }
4130
- /**
4131
- FIXME remove on next breaking release @internal
4132
- */
4133
- moveY(offset) {
4134
- return !offset ? this : new BlockInfo(this.from, this.length, this.top + offset, this.height, Array.isArray(this.type) ? this.type.map(b => b.moveY(offset)) : this.type);
4135
- }
4136
4036
  }
4137
4037
  var QueryType = /*@__PURE__*/(function (QueryType) {
4138
4038
  QueryType[QueryType["ByPos"] = 0] = "ByPos";
@@ -4256,8 +4156,9 @@ class HeightMapBlock extends HeightMap {
4256
4156
  lineAt(_value, _type, doc, top, offset) {
4257
4157
  return this.blockAt(0, doc, top, offset);
4258
4158
  }
4259
- forEachLine(_from, _to, doc, top, offset, f) {
4260
- f(this.blockAt(0, doc, top, offset));
4159
+ forEachLine(from, to, doc, top, offset, f) {
4160
+ if (from <= offset + this.length && to >= offset)
4161
+ f(this.blockAt(0, doc, top, offset));
4261
4162
  }
4262
4163
  updateHeight(oracle, offset = 0, _force = false, measured) {
4263
4164
  if (measured && measured.from <= offset && measured.more)
@@ -4688,6 +4589,11 @@ function visiblePixelRange(dom, paddingTop) {
4688
4589
  return { left: left - rect.left, right: Math.max(left, right) - rect.left,
4689
4590
  top: top - (rect.top + paddingTop), bottom: Math.max(top, bottom) - (rect.top + paddingTop) };
4690
4591
  }
4592
+ function fullPixelRange(dom, paddingTop) {
4593
+ let rect = dom.getBoundingClientRect();
4594
+ return { left: 0, right: rect.right - rect.left,
4595
+ top: paddingTop, bottom: rect.bottom - (rect.top + paddingTop) };
4596
+ }
4691
4597
  // Line gaps are placeholder widgets used to hide pieces of overlong
4692
4598
  // lines within the viewport, as a kludge to keep the editor
4693
4599
  // responsive when a ridiculously long line is loaded into it.
@@ -4753,6 +4659,7 @@ class ViewState {
4753
4659
  // Flag set when editor content was redrawn, so that the next
4754
4660
  // measure stage knows it must read DOM layout
4755
4661
  this.mustMeasureContent = true;
4662
+ this.defaultTextDirection = Direction.RTL;
4756
4663
  this.visibleRanges = [];
4757
4664
  // Cursor 'assoc' is only significant when the cursor is on a line
4758
4665
  // wrap point, where it must stick to the character that it is
@@ -4763,7 +4670,8 @@ class ViewState {
4763
4670
  // boundary and, if so, reset it to make sure it is positioned in
4764
4671
  // the right place.
4765
4672
  this.mustEnforceCursorAssoc = false;
4766
- this.heightMap = HeightMap.empty().applyChanges(state.facet(decorations), Text.empty, this.heightOracle.setDoc(state.doc), [new ChangedRange(0, 0, 0, state.doc.length)]);
4673
+ this.stateDeco = state.facet(decorations).filter(d => typeof d != "function");
4674
+ this.heightMap = HeightMap.empty().applyChanges(this.stateDeco, Text.empty, this.heightOracle.setDoc(state.doc), [new ChangedRange(0, 0, 0, state.doc.length)]);
4767
4675
  this.viewport = this.getViewport(0, null);
4768
4676
  this.updateViewportLines();
4769
4677
  this.updateForViewport();
@@ -4791,13 +4699,13 @@ class ViewState {
4791
4699
  });
4792
4700
  }
4793
4701
  update(update, scrollTarget = null) {
4794
- let prev = this.state;
4795
4702
  this.state = update.state;
4796
- let newDeco = this.state.facet(decorations);
4703
+ let prevDeco = this.stateDeco;
4704
+ this.stateDeco = this.state.facet(decorations).filter(d => typeof d != "function");
4797
4705
  let contentChanges = update.changedRanges;
4798
- let heightChanges = ChangedRange.extendWithRanges(contentChanges, heightRelevantDecoChanges(update.startState.facet(decorations), newDeco, update ? update.changes : ChangeSet.empty(this.state.doc.length)));
4706
+ let heightChanges = ChangedRange.extendWithRanges(contentChanges, heightRelevantDecoChanges(prevDeco, this.stateDeco, update ? update.changes : ChangeSet.empty(this.state.doc.length)));
4799
4707
  let prevHeight = this.heightMap.height;
4800
- this.heightMap = this.heightMap.applyChanges(newDeco, prev.doc, this.heightOracle.setDoc(this.state.doc), heightChanges);
4708
+ this.heightMap = this.heightMap.applyChanges(this.stateDeco, update.startState.doc, this.heightOracle.setDoc(this.state.doc), heightChanges);
4801
4709
  if (this.heightMap.height != prevHeight)
4802
4710
  update.flags |= 2 /* Height */;
4803
4711
  let viewport = heightChanges.length ? this.mapViewport(this.viewport, update.changes) : this.viewport;
@@ -4822,8 +4730,9 @@ class ViewState {
4822
4730
  measure(view) {
4823
4731
  let dom = view.contentDOM, style = window.getComputedStyle(dom);
4824
4732
  let oracle = this.heightOracle;
4825
- let whiteSpace = style.whiteSpace, direction = style.direction == "rtl" ? Direction.RTL : Direction.LTR;
4826
- let refresh = this.heightOracle.mustRefreshForStyle(whiteSpace, direction);
4733
+ let whiteSpace = style.whiteSpace;
4734
+ this.defaultTextDirection = style.direction == "rtl" ? Direction.RTL : Direction.LTR;
4735
+ let refresh = this.heightOracle.mustRefreshForWrapping(whiteSpace);
4827
4736
  let measureContent = refresh || this.mustMeasureContent || this.contentDOMHeight != dom.clientHeight;
4828
4737
  let result = 0, bias = 0;
4829
4738
  if (this.editorWidth != view.scrollDOM.clientWidth) {
@@ -4844,8 +4753,7 @@ class ViewState {
4844
4753
  }
4845
4754
  }
4846
4755
  // Pixel viewport
4847
- let pixelViewport = this.printing ? { top: -1e8, bottom: 1e8, left: -1e8, right: 1e8 }
4848
- : visiblePixelRange(dom, this.paddingTop);
4756
+ let pixelViewport = (this.printing ? fullPixelRange : visiblePixelRange)(dom, this.paddingTop);
4849
4757
  let dTop = pixelViewport.top - this.pixelViewport.top, dBottom = pixelViewport.bottom - this.pixelViewport.bottom;
4850
4758
  this.pixelViewport = pixelViewport;
4851
4759
  let inView = this.pixelViewport.bottom > this.pixelViewport.top && this.pixelViewport.right > this.pixelViewport.left;
@@ -4863,12 +4771,12 @@ class ViewState {
4863
4771
  result |= 8 /* Geometry */;
4864
4772
  }
4865
4773
  if (measureContent) {
4866
- let lineHeights = view.docView.measureVisibleLineHeights();
4774
+ let lineHeights = view.docView.measureVisibleLineHeights(this.viewport);
4867
4775
  if (oracle.mustRefreshForHeights(lineHeights))
4868
4776
  refresh = true;
4869
4777
  if (refresh || oracle.lineWrapping && Math.abs(contentWidth - this.contentDOMWidth) > oracle.charWidth) {
4870
4778
  let { lineHeight, charWidth } = view.docView.measureTextSize();
4871
- refresh = oracle.refresh(whiteSpace, direction, lineHeight, charWidth, contentWidth / charWidth, lineHeights);
4779
+ refresh = oracle.refresh(whiteSpace, lineHeight, charWidth, contentWidth / charWidth, lineHeights);
4872
4780
  if (refresh) {
4873
4781
  view.docView.minWidth = 0;
4874
4782
  result |= 8 /* Geometry */;
@@ -4879,7 +4787,10 @@ class ViewState {
4879
4787
  else if (dTop < 0 && dBottom < 0)
4880
4788
  bias = Math.min(dTop, dBottom);
4881
4789
  oracle.heightChanged = false;
4882
- this.heightMap = this.heightMap.updateHeight(oracle, 0, refresh, new MeasuredHeights(this.viewport.from, lineHeights));
4790
+ for (let vp of this.viewports) {
4791
+ let heights = vp.from == this.viewport.from ? lineHeights : view.docView.measureVisibleLineHeights(vp);
4792
+ this.heightMap = this.heightMap.updateHeight(oracle, 0, refresh, new MeasuredHeights(vp.from, heights));
4793
+ }
4883
4794
  if (oracle.heightChanged)
4884
4795
  result |= 2 /* Height */;
4885
4796
  }
@@ -4965,12 +4876,12 @@ class ViewState {
4965
4876
  ensureLineGaps(current) {
4966
4877
  let gaps = [];
4967
4878
  // This won't work at all in predominantly right-to-left text.
4968
- if (this.heightOracle.direction != Direction.LTR)
4879
+ if (this.defaultTextDirection != Direction.LTR)
4969
4880
  return gaps;
4970
4881
  for (let line of this.viewportLines) {
4971
4882
  if (line.length < 4000 /* DoubleMargin */)
4972
4883
  continue;
4973
- let structure = lineStructure(line.from, line.to, this.state);
4884
+ let structure = lineStructure(line.from, line.to, this.stateDeco);
4974
4885
  if (structure.total < 4000 /* DoubleMargin */)
4975
4886
  continue;
4976
4887
  let viewFrom, viewTo;
@@ -5021,7 +4932,7 @@ class ViewState {
5021
4932
  }
5022
4933
  }
5023
4934
  computeVisibleRanges() {
5024
- let deco = this.state.facet(decorations);
4935
+ let deco = this.stateDeco;
5025
4936
  if (this.lineGaps.length)
5026
4937
  deco = deco.concat(this.lineGapDeco);
5027
4938
  let ranges = [];
@@ -5057,9 +4968,9 @@ class Viewport {
5057
4968
  this.to = to;
5058
4969
  }
5059
4970
  }
5060
- function lineStructure(from, to, state) {
4971
+ function lineStructure(from, to, stateDeco) {
5061
4972
  let ranges = [], pos = from, total = 0;
5062
- RangeSet.spans(state.facet(decorations), from, to, {
4973
+ RangeSet.spans(stateDeco, from, to, {
5063
4974
  span() { },
5064
4975
  point(from, to) {
5065
4976
  if (from > pos) {
@@ -5192,7 +5103,7 @@ function buildTheme(main, spec, scopes) {
5192
5103
  }
5193
5104
  });
5194
5105
  }
5195
- const baseTheme = /*@__PURE__*/buildTheme("." + baseThemeID, {
5106
+ const baseTheme$1 = /*@__PURE__*/buildTheme("." + baseThemeID, {
5196
5107
  "&.cm-editor": {
5197
5108
  position: "relative !important",
5198
5109
  boxSizing: "border-box",
@@ -5297,6 +5208,65 @@ const baseTheme = /*@__PURE__*/buildTheme("." + baseThemeID, {
5297
5208
  "&dark .cm-activeLine": { backgroundColor: "#223039" },
5298
5209
  "&light .cm-specialChar": { color: "red" },
5299
5210
  "&dark .cm-specialChar": { color: "#f78" },
5211
+ ".cm-gutters": {
5212
+ display: "flex",
5213
+ height: "100%",
5214
+ boxSizing: "border-box",
5215
+ left: 0,
5216
+ zIndex: 200
5217
+ },
5218
+ "&light .cm-gutters": {
5219
+ backgroundColor: "#f5f5f5",
5220
+ color: "#6c6c6c",
5221
+ borderRight: "1px solid #ddd"
5222
+ },
5223
+ "&dark .cm-gutters": {
5224
+ backgroundColor: "#333338",
5225
+ color: "#ccc"
5226
+ },
5227
+ ".cm-gutter": {
5228
+ display: "flex !important",
5229
+ flexDirection: "column",
5230
+ flexShrink: 0,
5231
+ boxSizing: "border-box",
5232
+ minHeight: "100%",
5233
+ overflow: "hidden"
5234
+ },
5235
+ ".cm-gutterElement": {
5236
+ boxSizing: "border-box"
5237
+ },
5238
+ ".cm-lineNumbers .cm-gutterElement": {
5239
+ padding: "0 3px 0 5px",
5240
+ minWidth: "20px",
5241
+ textAlign: "right",
5242
+ whiteSpace: "nowrap"
5243
+ },
5244
+ "&light .cm-activeLineGutter": {
5245
+ backgroundColor: "#e2f2ff"
5246
+ },
5247
+ "&dark .cm-activeLineGutter": {
5248
+ backgroundColor: "#222227"
5249
+ },
5250
+ ".cm-panels": {
5251
+ boxSizing: "border-box",
5252
+ position: "sticky",
5253
+ left: 0,
5254
+ right: 0
5255
+ },
5256
+ "&light .cm-panels": {
5257
+ backgroundColor: "#f5f5f5",
5258
+ color: "black"
5259
+ },
5260
+ "&light .cm-panels-top": {
5261
+ borderBottom: "1px solid #ddd"
5262
+ },
5263
+ "&light .cm-panels-bottom": {
5264
+ borderTop: "1px solid #ddd"
5265
+ },
5266
+ "&dark .cm-panels": {
5267
+ backgroundColor: "#333338",
5268
+ color: "white"
5269
+ },
5300
5270
  ".cm-tab": {
5301
5271
  display: "inline-block",
5302
5272
  overflow: "hidden",
@@ -5422,6 +5392,7 @@ class DOMObserver {
5422
5392
  });
5423
5393
  this.resize.observe(view.scrollDOM);
5424
5394
  }
5395
+ window.addEventListener("beforeprint", this.onPrint = this.onPrint.bind(this));
5425
5396
  this.start();
5426
5397
  window.addEventListener("scroll", this.onScroll = this.onScroll.bind(this));
5427
5398
  if (typeof IntersectionObserver == "function") {
@@ -5456,6 +5427,14 @@ class DOMObserver {
5456
5427
  this.view.requestMeasure();
5457
5428
  }, 50);
5458
5429
  }
5430
+ onPrint() {
5431
+ this.view.viewState.printing = true;
5432
+ this.view.measure();
5433
+ setTimeout(() => {
5434
+ this.view.viewState.printing = false;
5435
+ this.view.requestMeasure();
5436
+ }, 500);
5437
+ }
5459
5438
  updateGaps(gaps) {
5460
5439
  if (this.gapIntersection && (gaps.length != this.gaps.length || this.gaps.some((g, i) => g != gaps[i]))) {
5461
5440
  this.gapIntersection.disconnect();
@@ -5673,6 +5652,7 @@ class DOMObserver {
5673
5652
  dom.removeEventListener("scroll", this.onScroll);
5674
5653
  window.removeEventListener("scroll", this.onScroll);
5675
5654
  window.removeEventListener("resize", this.onResize);
5655
+ window.removeEventListener("beforeprint", this.onPrint);
5676
5656
  this.dom.ownerDocument.removeEventListener("selectionchange", this.onSelectionChange);
5677
5657
  clearTimeout(this.parentCheck);
5678
5658
  clearTimeout(this.resizeTimeout);
@@ -5744,7 +5724,7 @@ function applyDOMChange(view, start, end, typeOver) {
5744
5724
  diff.toB == diff.from + 2 && reader.text.slice(diff.from, diff.toB) == LineBreakPlaceholder + LineBreakPlaceholder)
5745
5725
  diff.toB--;
5746
5726
  change = { from: from + diff.from, to: from + diff.toA,
5747
- insert: Text$1.of(reader.text.slice(diff.from, diff.toB).split(LineBreakPlaceholder)) };
5727
+ insert: Text.of(reader.text.slice(diff.from, diff.toB).split(LineBreakPlaceholder)) };
5748
5728
  }
5749
5729
  newSel = selectionFromPoints(selPoints, from);
5750
5730
  }
@@ -5935,9 +5915,9 @@ transactions for editing actions.
5935
5915
  */
5936
5916
  class EditorView {
5937
5917
  /**
5938
- Construct a new view. You'll usually want to put `view.dom` into
5939
- your document after creating a view, so that the user can see
5940
- it.
5918
+ Construct a new view. You'll want to either provide a `parent`
5919
+ option, or put `view.dom` into your document after creating a
5920
+ view, so that the user can see the editor.
5941
5921
  */
5942
5922
  constructor(
5943
5923
  /**
@@ -5988,6 +5968,7 @@ class EditorView {
5988
5968
  this.measure();
5989
5969
  });
5990
5970
  this.inputState = new InputState(this);
5971
+ this.inputState.ensureHandlers(this, this.plugins);
5991
5972
  this.docView = new DocView(this);
5992
5973
  this.mountStyles();
5993
5974
  this.updateAttrs();
@@ -6075,14 +6056,9 @@ class EditorView {
6075
6056
  let { main } = tr.state.selection;
6076
6057
  scrollTarget = new ScrollTarget(main.empty ? main : EditorSelection.cursor(main.head, main.head > main.anchor ? -1 : 1));
6077
6058
  }
6078
- for (let e of tr.effects) {
6079
- if (e.is(scrollTo))
6080
- scrollTarget = new ScrollTarget(e.value);
6081
- else if (e.is(centerOn))
6082
- scrollTarget = new ScrollTarget(e.value, "center");
6083
- else if (e.is(scrollIntoView))
6059
+ for (let e of tr.effects)
6060
+ if (e.is(scrollIntoView))
6084
6061
  scrollTarget = e.value;
6085
- }
6086
6062
  }
6087
6063
  this.viewState.update(update, scrollTarget);
6088
6064
  this.bidiCache = CachedOrder.update(this.bidiCache, update.changes);
@@ -6133,7 +6109,7 @@ class EditorView {
6133
6109
  for (let plugin of this.plugins)
6134
6110
  plugin.update(this);
6135
6111
  this.docView = new DocView(this);
6136
- this.inputState.ensureHandlers(this);
6112
+ this.inputState.ensureHandlers(this, this.plugins);
6137
6113
  this.mountStyles();
6138
6114
  this.updateAttrs();
6139
6115
  this.bidiCache = [];
@@ -6165,7 +6141,7 @@ class EditorView {
6165
6141
  plugin.destroy(this);
6166
6142
  this.plugins = newPlugins;
6167
6143
  this.pluginMap.clear();
6168
- this.inputState.ensureHandlers(this);
6144
+ this.inputState.ensureHandlers(this, this.plugins);
6169
6145
  }
6170
6146
  else {
6171
6147
  for (let p of this.plugins)
@@ -6303,7 +6279,7 @@ class EditorView {
6303
6279
  }
6304
6280
  mountStyles() {
6305
6281
  this.styleModules = this.state.facet(styleModule);
6306
- StyleModule.mount(this.root, this.styleModules.concat(baseTheme).reverse());
6282
+ StyleModule.mount(this.root, this.styleModules.concat(baseTheme$1).reverse());
6307
6283
  }
6308
6284
  readMeasured() {
6309
6285
  if (this.updateState == 2 /* Updating */)
@@ -6334,16 +6310,6 @@ class EditorView {
6334
6310
  }
6335
6311
  }
6336
6312
  /**
6337
- Collect all values provided by the active plugins for a given
6338
- field.
6339
- */
6340
- pluginField(field) {
6341
- let result = [];
6342
- for (let plugin of this.plugins)
6343
- plugin.update(this).takeField(field, result);
6344
- return result;
6345
- }
6346
- /**
6347
6313
  Get the value of a specific plugin, if present. Note that
6348
6314
  plugins that crash can be dropped from a view, so even when you
6349
6315
  know you registered a given plugin, it is recommended to check
@@ -6370,23 +6336,6 @@ class EditorView {
6370
6336
  return { top: this.viewState.paddingTop, bottom: this.viewState.paddingBottom };
6371
6337
  }
6372
6338
  /**
6373
- Find the line or block widget at the given vertical position.
6374
-
6375
- By default, this position is interpreted as a screen position,
6376
- meaning `docTop` is set to the DOM top position of the editor
6377
- content (forcing a layout). You can pass a different `docTop`
6378
- value—for example 0 to interpret `height` as a document-relative
6379
- position, or a precomputed document top
6380
- (`view.contentDOM.getBoundingClientRect().top`) to limit layout
6381
- queries.
6382
-
6383
- *Deprecated: use `elementAtHeight` instead.*
6384
- */
6385
- blockAtHeight(height, docTop) {
6386
- let top = ensureTop(docTop, this);
6387
- return this.elementAtHeight(height - top).moveY(top);
6388
- }
6389
- /**
6390
6339
  Find the text line or block widget at the given vertical
6391
6340
  position (which is interpreted as relative to the [top of the
6392
6341
  document](https://codemirror.net/6/docs/ref/#view.EditorView.documentTop)
@@ -6396,23 +6345,6 @@ class EditorView {
6396
6345
  return this.viewState.elementAtHeight(height);
6397
6346
  }
6398
6347
  /**
6399
- Find information for the visual line (see
6400
- [`visualLineAt`](https://codemirror.net/6/docs/ref/#view.EditorView.visualLineAt)) at the given
6401
- vertical position. The resulting block info might hold another
6402
- array of block info structs in its `type` field if this line
6403
- consists of more than one block.
6404
-
6405
- Defaults to treating `height` as a screen position. See
6406
- [`blockAtHeight`](https://codemirror.net/6/docs/ref/#view.EditorView.blockAtHeight) for the
6407
- interpretation of the `docTop` parameter.
6408
-
6409
- *Deprecated: use `lineBlockAtHeight` instead.*
6410
- */
6411
- visualLineAtHeight(height, docTop) {
6412
- let top = ensureTop(docTop, this);
6413
- return this.lineBlockAtHeight(height - top).moveY(top);
6414
- }
6415
- /**
6416
6348
  Find the line block (see
6417
6349
  [`lineBlockAt`](https://codemirror.net/6/docs/ref/#view.EditorView.lineBlockAt) at the given
6418
6350
  height.
@@ -6422,19 +6354,6 @@ class EditorView {
6422
6354
  return this.viewState.lineBlockAtHeight(height);
6423
6355
  }
6424
6356
  /**
6425
- Iterate over the height information of the visual lines in the
6426
- viewport. The heights of lines are reported relative to the
6427
- given document top, which defaults to the screen position of the
6428
- document (forcing a layout).
6429
-
6430
- *Deprecated: use `viewportLineBlocks` instead.*
6431
- */
6432
- viewportLines(f, docTop) {
6433
- let top = ensureTop(docTop, this);
6434
- for (let line of this.viewportLineBlocks)
6435
- f(line.moveY(top));
6436
- }
6437
- /**
6438
6357
  Get the extent and vertical position of all [line
6439
6358
  blocks](https://codemirror.net/6/docs/ref/#view.EditorView.lineBlockAt) in the viewport. Positions
6440
6359
  are relative to the [top of the
@@ -6444,24 +6363,9 @@ class EditorView {
6444
6363
  return this.viewState.viewportLines;
6445
6364
  }
6446
6365
  /**
6447
- Find the extent and height of the visual line (a range delimited
6448
- on both sides by either non-[hidden](https://codemirror.net/6/docs/ref/#view.Decoration^range)
6449
- line breaks, or the start/end of the document) at the given position.
6450
-
6451
- Vertical positions are computed relative to the `docTop`
6452
- argument, which defaults to 0 for this method. You can pass
6453
- `view.contentDOM.getBoundingClientRect().top` here to get screen
6454
- coordinates.
6455
-
6456
- *Deprecated: use `lineBlockAt` instead.*
6457
- */
6458
- visualLineAt(pos, docTop = 0) {
6459
- return this.lineBlockAt(pos).moveY(docTop + this.viewState.paddingTop);
6460
- }
6461
- /**
6462
6366
  Find the line block around the given document position. A line
6463
6367
  block is a range delimited on both sides by either a
6464
- non-[hidden](https://codemirror.net/6/docs/ref/#view.Decoration^range) line breaks, or the
6368
+ non-[hidden](https://codemirror.net/6/docs/ref/#view.Decoration^replace) line breaks, or the
6465
6369
  start/end of the document. It will usually just hold a line of
6466
6370
  text, but may be broken into multiple textblocks by block
6467
6371
  widgets.
@@ -6477,13 +6381,13 @@ class EditorView {
6477
6381
  }
6478
6382
  /**
6479
6383
  Move a cursor position by [grapheme
6480
- cluster](https://codemirror.net/6/docs/ref/#text.findClusterBreak). `forward` determines whether
6481
- the motion is away from the line start, or towards it. Motion in
6482
- bidirectional text is in visual order, in the editor's [text
6483
- direction](https://codemirror.net/6/docs/ref/#view.EditorView.textDirection). When the start
6484
- position was the last one on the line, the returned position
6485
- will be across the line break. If there is no further line, the
6486
- original position is returned.
6384
+ cluster](https://codemirror.net/6/docs/ref/#state.findClusterBreak). `forward` determines whether
6385
+ the motion is away from the line start, or towards it. In
6386
+ bidirectional text, the line is traversed in visual order, using
6387
+ the editor's [text direction](https://codemirror.net/6/docs/ref/#view.EditorView.textDirection).
6388
+ When the start position was the last one on the line, the
6389
+ returned position will be across the line break. If there is no
6390
+ further line, the original position is returned.
6487
6391
 
6488
6392
  By default, this method moves over a single cluster. The
6489
6393
  optional `by` argument can be used to move across more. It will
@@ -6528,10 +6432,6 @@ class EditorView {
6528
6432
  moveVertically(start, forward, distance) {
6529
6433
  return skipAtoms(this, start, moveVertically(this, start, forward, distance));
6530
6434
  }
6531
- // FIXME remove on next major version
6532
- scrollPosIntoView(pos) {
6533
- this.dispatch({ effects: scrollTo.of(EditorSelection.cursor(pos)) });
6534
- }
6535
6435
  /**
6536
6436
  Find the DOM parent node and offset (child offset if `node` is
6537
6437
  an element, character offset when it is a text node) at the
@@ -6587,9 +6487,25 @@ class EditorView {
6587
6487
  /**
6588
6488
  The text direction
6589
6489
  ([`direction`](https://developer.mozilla.org/en-US/docs/Web/CSS/direction)
6590
- CSS property) of the editor.
6490
+ CSS property) of the editor's content element.
6491
+ */
6492
+ get textDirection() { return this.viewState.defaultTextDirection; }
6493
+ /**
6494
+ Find the text direction of the block at the given position, as
6495
+ assigned by CSS. If
6496
+ [`perLineTextDirection`](https://codemirror.net/6/docs/ref/#view.EditorView^perLineTextDirection)
6497
+ isn't enabled, or the given position is outside of the viewport,
6498
+ this will always return the same as
6499
+ [`textDirection`](https://codemirror.net/6/docs/ref/#view.EditorView.textDirection). Note that
6500
+ this may trigger a DOM layout.
6591
6501
  */
6592
- get textDirection() { return this.viewState.heightOracle.direction; }
6502
+ textDirectionAt(pos) {
6503
+ let perLine = this.state.facet(perLineTextDirection);
6504
+ if (!perLine || pos < this.viewport.from || pos > this.viewport.to)
6505
+ return this.textDirection;
6506
+ this.readMeasured();
6507
+ return this.docView.textDirectionAt(pos);
6508
+ }
6593
6509
  /**
6594
6510
  Whether this editor [wraps lines](https://codemirror.net/6/docs/ref/#view.EditorView.lineWrapping)
6595
6511
  (as determined by the
@@ -6608,11 +6524,11 @@ class EditorView {
6608
6524
  bidiSpans(line) {
6609
6525
  if (line.length > MaxBidiLine)
6610
6526
  return trivialOrder(line.length);
6611
- let dir = this.textDirection;
6527
+ let dir = this.textDirectionAt(line.from);
6612
6528
  for (let entry of this.bidiCache)
6613
6529
  if (entry.from == line.from && entry.dir == dir)
6614
6530
  return entry.order;
6615
- let order = computeOrder(line.text, this.textDirection);
6531
+ let order = computeOrder(line.text, dir);
6616
6532
  this.bidiCache.push(new CachedOrder(line.from, line.to, dir, order));
6617
6533
  return order;
6618
6534
  }
@@ -6663,16 +6579,16 @@ class EditorView {
6663
6579
  return scrollIntoView.of(new ScrollTarget(typeof pos == "number" ? EditorSelection.cursor(pos) : pos, options.y, options.x, options.yMargin, options.xMargin));
6664
6580
  }
6665
6581
  /**
6666
- Facet that can be used to add DOM event handlers. The value
6667
- should be an object mapping event names to handler functions. The
6668
- first such function to return true will be assumed to have handled
6669
- that event, and no other handlers or built-in behavior will be
6670
- activated for it.
6671
- These are registered on the [content
6672
- element](https://codemirror.net/6/docs/ref/#view.EditorView.contentDOM), except for `scroll`
6673
- handlers, which will be called any time the editor's [scroll
6674
- element](https://codemirror.net/6/docs/ref/#view.EditorView.scrollDOM) or one of its parent nodes
6675
- is scrolled.
6582
+ Returns an extension that can be used to add DOM event handlers.
6583
+ The value should be an object mapping event names to handler
6584
+ functions. For any given event, such functions are ordered by
6585
+ extension precedence, and the first handler to return true will
6586
+ be assumed to have handled that event, and no other handlers or
6587
+ built-in behavior will be activated for it. These are registered
6588
+ on the [content element](https://codemirror.net/6/docs/ref/#view.EditorView.contentDOM), except
6589
+ for `scroll` handlers, which will be called any time the
6590
+ editor's [scroll element](https://codemirror.net/6/docs/ref/#view.EditorView.scrollDOM) or one of
6591
+ its parent nodes is scrolled.
6676
6592
  */
6677
6593
  static domEventHandlers(handlers) {
6678
6594
  return ViewPlugin.define(() => ({}), { eventHandlers: handlers });
@@ -6714,20 +6630,6 @@ class EditorView {
6714
6630
  }
6715
6631
  }
6716
6632
  /**
6717
- Effect that can be [added](https://codemirror.net/6/docs/ref/#state.TransactionSpec.effects) to a
6718
- transaction to make it scroll the given range into view.
6719
-
6720
- *Deprecated*. Use [`scrollIntoView`](https://codemirror.net/6/docs/ref/#view.EditorView^scrollIntoView) instead.
6721
- */
6722
- EditorView.scrollTo = scrollTo;
6723
- /**
6724
- Effect that makes the editor scroll the given range to the
6725
- center of the visible view.
6726
-
6727
- *Deprecated*. Use [`scrollIntoView`](https://codemirror.net/6/docs/ref/#view.EditorView^scrollIntoView) instead.
6728
- */
6729
- EditorView.centerOn = centerOn;
6730
- /**
6731
6633
  Facet to add a [style
6732
6634
  module](https://github.com/marijnh/style-mod#documentation) to
6733
6635
  an editor view. The view will ensure that the module is
@@ -6744,6 +6646,13 @@ called and the default behavior is prevented.
6744
6646
  */
6745
6647
  EditorView.inputHandler = inputHandler;
6746
6648
  /**
6649
+ By default, the editor assumes all its content has the same
6650
+ [text direction](https://codemirror.net/6/docs/ref/#view.Direction). Configure this with a `true`
6651
+ value to make it read and store the text direction of every
6652
+ (rendered) line separately.
6653
+ */
6654
+ EditorView.perLineTextDirection = perLineTextDirection;
6655
+ /**
6747
6656
  Allows you to provide a function that should be called when the
6748
6657
  library catches an exception from an extension (mostly from view
6749
6658
  plugins, but may be used by other extensions to route exceptions
@@ -6759,9 +6668,9 @@ EditorView.updateListener = updateListener;
6759
6668
  /**
6760
6669
  Facet that controls whether the editor content DOM is editable.
6761
6670
  When its highest-precedence value is `false`, the element will
6762
- not longer have its `contenteditable` attribute set. (Note that
6763
- this doesn't affect API calls that change the editor content,
6764
- even when those are bound to keys or buttons. See the
6671
+ not have its `contenteditable` attribute set. (Note that this
6672
+ doesn't affect API calls that change the editor content, even
6673
+ when those are bound to keys or buttons. See the
6765
6674
  [`readOnly`](https://codemirror.net/6/docs/ref/#state.EditorState.readOnly) facet for that.)
6766
6675
  */
6767
6676
  EditorView.editable = editable;
@@ -6780,18 +6689,45 @@ the drag should move the content.
6780
6689
  */
6781
6690
  EditorView.dragMovesSelection = dragMovesSelection$1;
6782
6691
  /**
6783
- Facet used to configure whether a given selecting click adds
6784
- a new range to the existing selection or replaces it entirely.
6692
+ Facet used to configure whether a given selecting click adds a
6693
+ new range to the existing selection or replaces it entirely. The
6694
+ default behavior is to check `event.metaKey` on macOS, and
6695
+ `event.ctrlKey` elsewhere.
6785
6696
  */
6786
6697
  EditorView.clickAddsSelectionRange = clickAddsSelectionRange;
6787
6698
  /**
6788
6699
  A facet that determines which [decorations](https://codemirror.net/6/docs/ref/#view.Decoration)
6789
- are shown in the view. See also [view
6790
- plugins](https://codemirror.net/6/docs/ref/#view.EditorView^decorations), which have a separate
6791
- mechanism for providing decorations.
6700
+ are shown in the view. Decorations can be provided in two
6701
+ ways—directly, or via a function that takes an editor view.
6702
+
6703
+ Only decoration sets provided directly are allowed to influence
6704
+ the editor's vertical layout structure. The ones provided as
6705
+ functions are called _after_ the new viewport has been computed,
6706
+ and thus **must not** introduce block widgets or replacing
6707
+ decorations that cover line breaks.
6792
6708
  */
6793
6709
  EditorView.decorations = decorations;
6794
6710
  /**
6711
+ Used to provide ranges that should be treated as atoms as far as
6712
+ cursor motion is concerned. This causes methods like
6713
+ [`moveByChar`](https://codemirror.net/6/docs/ref/#view.EditorView.moveByChar) and
6714
+ [`moveVertically`](https://codemirror.net/6/docs/ref/#view.EditorView.moveVertically) (and the
6715
+ commands built on top of them) to skip across such regions when
6716
+ a selection endpoint would enter them. This does _not_ prevent
6717
+ direct programmatic [selection
6718
+ updates](https://codemirror.net/6/docs/ref/#state.TransactionSpec.selection) from moving into such
6719
+ regions.
6720
+ */
6721
+ EditorView.atomicRanges = atomicRanges;
6722
+ /**
6723
+ Facet that allows extensions to provide additional scroll
6724
+ margins (space around the sides of the scrolling element that
6725
+ should be considered invisible). This can be useful when the
6726
+ plugin introduces elements that cover part of that element (for
6727
+ example a horizontally fixed gutter).
6728
+ */
6729
+ EditorView.scrollMargins = scrollMargins;
6730
+ /**
6795
6731
  This facet records whether a dark theme is active. The extension
6796
6732
  returned by [`theme`](https://codemirror.net/6/docs/ref/#view.EditorView^theme) automatically
6797
6733
  includes an instance of this when the `dark` option is set to
@@ -6824,10 +6760,6 @@ search match).
6824
6760
  EditorView.announce = /*@__PURE__*/StateEffect.define();
6825
6761
  // Maximum line length for which we compute accurate bidi info
6826
6762
  const MaxBidiLine = 4096;
6827
- // FIXME remove this and its callers on next breaking release
6828
- function ensureTop(given, view) {
6829
- return (given == null ? view.contentDOM.getBoundingClientRect().top : given) + view.viewState.paddingTop;
6830
- }
6831
6763
  const BadMeasure = {};
6832
6764
  class CachedOrder {
6833
6765
  constructor(from, to, dir, order) {
@@ -6930,7 +6862,7 @@ function getKeymap(state) {
6930
6862
  }
6931
6863
  /**
6932
6864
  Run the key handlers registered for a given scope. The event
6933
- object should be `"keydown"` event. Returns true if any of the
6865
+ object should be a `"keydown"` event. Returns true if any of the
6934
6866
  handlers handled it.
6935
6867
  */
6936
6868
  function runScopeHandlers(view, event, scope) {
@@ -7707,9 +7639,1302 @@ function placeholder(content) {
7707
7639
  }, { decorations: v => v.decorations });
7708
7640
  }
7709
7641
 
7642
+ // Don't compute precise column positions for line offsets above this
7643
+ // (since it could get expensive). Assume offset==column for them.
7644
+ const MaxOff = 2000;
7645
+ function rectangleFor(state, a, b) {
7646
+ let startLine = Math.min(a.line, b.line), endLine = Math.max(a.line, b.line);
7647
+ let ranges = [];
7648
+ if (a.off > MaxOff || b.off > MaxOff || a.col < 0 || b.col < 0) {
7649
+ let startOff = Math.min(a.off, b.off), endOff = Math.max(a.off, b.off);
7650
+ for (let i = startLine; i <= endLine; i++) {
7651
+ let line = state.doc.line(i);
7652
+ if (line.length <= endOff)
7653
+ ranges.push(EditorSelection.range(line.from + startOff, line.to + endOff));
7654
+ }
7655
+ }
7656
+ else {
7657
+ let startCol = Math.min(a.col, b.col), endCol = Math.max(a.col, b.col);
7658
+ for (let i = startLine; i <= endLine; i++) {
7659
+ let line = state.doc.line(i);
7660
+ let start = findColumn(line.text, startCol, state.tabSize, true);
7661
+ if (start > -1) {
7662
+ let end = findColumn(line.text, endCol, state.tabSize);
7663
+ ranges.push(EditorSelection.range(line.from + start, line.from + end));
7664
+ }
7665
+ }
7666
+ }
7667
+ return ranges;
7668
+ }
7669
+ function absoluteColumn(view, x) {
7670
+ let ref = view.coordsAtPos(view.viewport.from);
7671
+ return ref ? Math.round(Math.abs((ref.left - x) / view.defaultCharacterWidth)) : -1;
7672
+ }
7673
+ function getPos(view, event) {
7674
+ let offset = view.posAtCoords({ x: event.clientX, y: event.clientY }, false);
7675
+ let line = view.state.doc.lineAt(offset), off = offset - line.from;
7676
+ let col = off > MaxOff ? -1
7677
+ : off == line.length ? absoluteColumn(view, event.clientX)
7678
+ : countColumn(line.text, view.state.tabSize, offset - line.from);
7679
+ return { line: line.number, col, off };
7680
+ }
7681
+ function rectangleSelectionStyle(view, event) {
7682
+ let start = getPos(view, event), startSel = view.state.selection;
7683
+ if (!start)
7684
+ return null;
7685
+ return {
7686
+ update(update) {
7687
+ if (update.docChanged) {
7688
+ let newStart = update.changes.mapPos(update.startState.doc.line(start.line).from);
7689
+ let newLine = update.state.doc.lineAt(newStart);
7690
+ start = { line: newLine.number, col: start.col, off: Math.min(start.off, newLine.length) };
7691
+ startSel = startSel.map(update.changes);
7692
+ }
7693
+ },
7694
+ get(event, _extend, multiple) {
7695
+ let cur = getPos(view, event);
7696
+ if (!cur)
7697
+ return startSel;
7698
+ let ranges = rectangleFor(view.state, start, cur);
7699
+ if (!ranges.length)
7700
+ return startSel;
7701
+ if (multiple)
7702
+ return EditorSelection.create(ranges.concat(startSel.ranges));
7703
+ else
7704
+ return EditorSelection.create(ranges);
7705
+ }
7706
+ };
7707
+ }
7708
+ /**
7709
+ Create an extension that enables rectangular selections. By
7710
+ default, it will react to left mouse drag with the Alt key held
7711
+ down. When such a selection occurs, the text within the rectangle
7712
+ that was dragged over will be selected, as one selection
7713
+ [range](https://codemirror.net/6/docs/ref/#state.SelectionRange) per line.
7714
+ */
7715
+ function rectangularSelection(options) {
7716
+ let filter = (options === null || options === void 0 ? void 0 : options.eventFilter) || (e => e.altKey && e.button == 0);
7717
+ return EditorView.mouseSelectionStyle.of((view, event) => filter(event) ? rectangleSelectionStyle(view, event) : null);
7718
+ }
7719
+ const keys = {
7720
+ Alt: [18, e => e.altKey],
7721
+ Control: [17, e => e.ctrlKey],
7722
+ Shift: [16, e => e.shiftKey],
7723
+ Meta: [91, e => e.metaKey]
7724
+ };
7725
+ const showCrosshair = { style: "cursor: crosshair" };
7726
+ /**
7727
+ Returns an extension that turns the pointer cursor into a
7728
+ crosshair when a given modifier key, defaulting to Alt, is held
7729
+ down. Can serve as a visual hint that rectangular selection is
7730
+ going to happen when paired with
7731
+ [`rectangularSelection`](https://codemirror.net/6/docs/ref/#view.rectangularSelection).
7732
+ */
7733
+ function crosshairCursor(options = {}) {
7734
+ let [code, getter] = keys[options.key || "Alt"];
7735
+ let plugin = ViewPlugin.fromClass(class {
7736
+ constructor(view) {
7737
+ this.view = view;
7738
+ this.isDown = false;
7739
+ }
7740
+ set(isDown) {
7741
+ if (this.isDown != isDown) {
7742
+ this.isDown = isDown;
7743
+ this.view.update([]);
7744
+ }
7745
+ }
7746
+ }, {
7747
+ eventHandlers: {
7748
+ keydown(e) {
7749
+ this.set(e.keyCode == code || getter(e));
7750
+ },
7751
+ keyup(e) {
7752
+ if (e.keyCode == code || !getter(e))
7753
+ this.set(false);
7754
+ }
7755
+ }
7756
+ });
7757
+ return [
7758
+ plugin,
7759
+ EditorView.contentAttributes.of(view => { var _a; return ((_a = view.plugin(plugin)) === null || _a === void 0 ? void 0 : _a.isDown) ? showCrosshair : null; })
7760
+ ];
7761
+ }
7762
+
7763
+ const Outside = "-10000px";
7764
+ class TooltipViewManager {
7765
+ constructor(view, facet, createTooltipView) {
7766
+ this.facet = facet;
7767
+ this.createTooltipView = createTooltipView;
7768
+ this.input = view.state.facet(facet);
7769
+ this.tooltips = this.input.filter(t => t);
7770
+ this.tooltipViews = this.tooltips.map(createTooltipView);
7771
+ }
7772
+ update(update) {
7773
+ let input = update.state.facet(this.facet);
7774
+ let tooltips = input.filter(x => x);
7775
+ if (input === this.input) {
7776
+ for (let t of this.tooltipViews)
7777
+ if (t.update)
7778
+ t.update(update);
7779
+ return false;
7780
+ }
7781
+ let tooltipViews = [];
7782
+ for (let i = 0; i < tooltips.length; i++) {
7783
+ let tip = tooltips[i], known = -1;
7784
+ if (!tip)
7785
+ continue;
7786
+ for (let i = 0; i < this.tooltips.length; i++) {
7787
+ let other = this.tooltips[i];
7788
+ if (other && other.create == tip.create)
7789
+ known = i;
7790
+ }
7791
+ if (known < 0) {
7792
+ tooltipViews[i] = this.createTooltipView(tip);
7793
+ }
7794
+ else {
7795
+ let tooltipView = tooltipViews[i] = this.tooltipViews[known];
7796
+ if (tooltipView.update)
7797
+ tooltipView.update(update);
7798
+ }
7799
+ }
7800
+ for (let t of this.tooltipViews)
7801
+ if (tooltipViews.indexOf(t) < 0)
7802
+ t.dom.remove();
7803
+ this.input = input;
7804
+ this.tooltips = tooltips;
7805
+ this.tooltipViews = tooltipViews;
7806
+ return true;
7807
+ }
7808
+ }
7809
+ /**
7810
+ Creates an extension that configures tooltip behavior.
7811
+ */
7812
+ function tooltips(config = {}) {
7813
+ return tooltipConfig.of(config);
7814
+ }
7815
+ function windowSpace() {
7816
+ return { top: 0, left: 0, bottom: innerHeight, right: innerWidth };
7817
+ }
7818
+ const tooltipConfig = /*@__PURE__*/Facet.define({
7819
+ combine: values => {
7820
+ var _a, _b, _c;
7821
+ return ({
7822
+ position: browser.ios ? "absolute" : ((_a = values.find(conf => conf.position)) === null || _a === void 0 ? void 0 : _a.position) || "fixed",
7823
+ parent: ((_b = values.find(conf => conf.parent)) === null || _b === void 0 ? void 0 : _b.parent) || null,
7824
+ tooltipSpace: ((_c = values.find(conf => conf.tooltipSpace)) === null || _c === void 0 ? void 0 : _c.tooltipSpace) || windowSpace,
7825
+ });
7826
+ }
7827
+ });
7828
+ const tooltipPlugin = /*@__PURE__*/ViewPlugin.fromClass(class {
7829
+ constructor(view) {
7830
+ var _a;
7831
+ this.view = view;
7832
+ this.inView = true;
7833
+ this.lastTransaction = 0;
7834
+ this.measureTimeout = -1;
7835
+ let config = view.state.facet(tooltipConfig);
7836
+ this.position = config.position;
7837
+ this.parent = config.parent;
7838
+ this.classes = view.themeClasses;
7839
+ this.createContainer();
7840
+ this.measureReq = { read: this.readMeasure.bind(this), write: this.writeMeasure.bind(this), key: this };
7841
+ this.manager = new TooltipViewManager(view, showTooltip, t => this.createTooltip(t));
7842
+ this.intersectionObserver = typeof IntersectionObserver == "function" ? new IntersectionObserver(entries => {
7843
+ if (Date.now() > this.lastTransaction - 50 &&
7844
+ entries.length > 0 && entries[entries.length - 1].intersectionRatio < 1)
7845
+ this.measureSoon();
7846
+ }, { threshold: [1] }) : null;
7847
+ this.observeIntersection();
7848
+ (_a = view.dom.ownerDocument.defaultView) === null || _a === void 0 ? void 0 : _a.addEventListener("resize", this.measureSoon = this.measureSoon.bind(this));
7849
+ this.maybeMeasure();
7850
+ }
7851
+ createContainer() {
7852
+ if (this.parent) {
7853
+ this.container = document.createElement("div");
7854
+ this.container.style.position = "relative";
7855
+ this.container.className = this.view.themeClasses;
7856
+ this.parent.appendChild(this.container);
7857
+ }
7858
+ else {
7859
+ this.container = this.view.dom;
7860
+ }
7861
+ }
7862
+ observeIntersection() {
7863
+ if (this.intersectionObserver) {
7864
+ this.intersectionObserver.disconnect();
7865
+ for (let tooltip of this.manager.tooltipViews)
7866
+ this.intersectionObserver.observe(tooltip.dom);
7867
+ }
7868
+ }
7869
+ measureSoon() {
7870
+ if (this.measureTimeout < 0)
7871
+ this.measureTimeout = setTimeout(() => {
7872
+ this.measureTimeout = -1;
7873
+ this.maybeMeasure();
7874
+ }, 50);
7875
+ }
7876
+ update(update) {
7877
+ if (update.transactions.length)
7878
+ this.lastTransaction = Date.now();
7879
+ let updated = this.manager.update(update);
7880
+ if (updated)
7881
+ this.observeIntersection();
7882
+ let shouldMeasure = updated || update.geometryChanged;
7883
+ let newConfig = update.state.facet(tooltipConfig);
7884
+ if (newConfig.position != this.position) {
7885
+ this.position = newConfig.position;
7886
+ for (let t of this.manager.tooltipViews)
7887
+ t.dom.style.position = this.position;
7888
+ shouldMeasure = true;
7889
+ }
7890
+ if (newConfig.parent != this.parent) {
7891
+ if (this.parent)
7892
+ this.container.remove();
7893
+ this.parent = newConfig.parent;
7894
+ this.createContainer();
7895
+ for (let t of this.manager.tooltipViews)
7896
+ this.container.appendChild(t.dom);
7897
+ shouldMeasure = true;
7898
+ }
7899
+ else if (this.parent && this.view.themeClasses != this.classes) {
7900
+ this.classes = this.container.className = this.view.themeClasses;
7901
+ }
7902
+ if (shouldMeasure)
7903
+ this.maybeMeasure();
7904
+ }
7905
+ createTooltip(tooltip) {
7906
+ let tooltipView = tooltip.create(this.view);
7907
+ tooltipView.dom.classList.add("cm-tooltip");
7908
+ if (tooltip.arrow && !tooltipView.dom.querySelector(".cm-tooltip > .cm-tooltip-arrow")) {
7909
+ let arrow = document.createElement("div");
7910
+ arrow.className = "cm-tooltip-arrow";
7911
+ tooltipView.dom.appendChild(arrow);
7912
+ }
7913
+ tooltipView.dom.style.position = this.position;
7914
+ tooltipView.dom.style.top = Outside;
7915
+ this.container.appendChild(tooltipView.dom);
7916
+ if (tooltipView.mount)
7917
+ tooltipView.mount(this.view);
7918
+ return tooltipView;
7919
+ }
7920
+ destroy() {
7921
+ var _a, _b;
7922
+ (_a = this.view.dom.ownerDocument.defaultView) === null || _a === void 0 ? void 0 : _a.removeEventListener("resize", this.measureSoon);
7923
+ for (let { dom } of this.manager.tooltipViews)
7924
+ dom.remove();
7925
+ (_b = this.intersectionObserver) === null || _b === void 0 ? void 0 : _b.disconnect();
7926
+ clearTimeout(this.measureTimeout);
7927
+ }
7928
+ readMeasure() {
7929
+ let editor = this.view.dom.getBoundingClientRect();
7930
+ return {
7931
+ editor,
7932
+ parent: this.parent ? this.container.getBoundingClientRect() : editor,
7933
+ pos: this.manager.tooltips.map((t, i) => {
7934
+ let tv = this.manager.tooltipViews[i];
7935
+ return tv.getCoords ? tv.getCoords(t.pos) : this.view.coordsAtPos(t.pos);
7936
+ }),
7937
+ size: this.manager.tooltipViews.map(({ dom }) => dom.getBoundingClientRect()),
7938
+ space: this.view.state.facet(tooltipConfig).tooltipSpace(this.view),
7939
+ };
7940
+ }
7941
+ writeMeasure(measured) {
7942
+ let { editor, space } = measured;
7943
+ let others = [];
7944
+ for (let i = 0; i < this.manager.tooltips.length; i++) {
7945
+ let tooltip = this.manager.tooltips[i], tView = this.manager.tooltipViews[i], { dom } = tView;
7946
+ let pos = measured.pos[i], size = measured.size[i];
7947
+ // Hide tooltips that are outside of the editor.
7948
+ if (!pos || pos.bottom <= Math.max(editor.top, space.top) ||
7949
+ pos.top >= Math.min(editor.bottom, space.bottom) ||
7950
+ pos.right < Math.max(editor.left, space.left) - .1 ||
7951
+ pos.left > Math.min(editor.right, space.right) + .1) {
7952
+ dom.style.top = Outside;
7953
+ continue;
7954
+ }
7955
+ let arrow = tooltip.arrow ? tView.dom.querySelector(".cm-tooltip-arrow") : null;
7956
+ let arrowHeight = arrow ? 7 /* Size */ : 0;
7957
+ let width = size.right - size.left, height = size.bottom - size.top;
7958
+ let offset = tView.offset || noOffset, ltr = this.view.textDirection == Direction.LTR;
7959
+ let left = size.width > space.right - space.left ? (ltr ? space.left : space.right - size.width)
7960
+ : ltr ? Math.min(pos.left - (arrow ? 14 /* Offset */ : 0) + offset.x, space.right - width)
7961
+ : Math.max(space.left, pos.left - width + (arrow ? 14 /* Offset */ : 0) - offset.x);
7962
+ let above = !!tooltip.above;
7963
+ if (!tooltip.strictSide && (above
7964
+ ? pos.top - (size.bottom - size.top) - offset.y < space.top
7965
+ : pos.bottom + (size.bottom - size.top) + offset.y > space.bottom) &&
7966
+ above == (space.bottom - pos.bottom > pos.top - space.top))
7967
+ above = !above;
7968
+ let top = above ? pos.top - height - arrowHeight - offset.y : pos.bottom + arrowHeight + offset.y;
7969
+ let right = left + width;
7970
+ if (tView.overlap !== true)
7971
+ for (let r of others)
7972
+ if (r.left < right && r.right > left && r.top < top + height && r.bottom > top)
7973
+ top = above ? r.top - height - 2 - arrowHeight : r.bottom + arrowHeight + 2;
7974
+ if (this.position == "absolute") {
7975
+ dom.style.top = (top - measured.parent.top) + "px";
7976
+ dom.style.left = (left - measured.parent.left) + "px";
7977
+ }
7978
+ else {
7979
+ dom.style.top = top + "px";
7980
+ dom.style.left = left + "px";
7981
+ }
7982
+ if (arrow)
7983
+ arrow.style.left = `${pos.left + (ltr ? offset.x : -offset.x) - (left + 14 /* Offset */ - 7 /* Size */)}px`;
7984
+ if (tView.overlap !== true)
7985
+ others.push({ left, top, right, bottom: top + height });
7986
+ dom.classList.toggle("cm-tooltip-above", above);
7987
+ dom.classList.toggle("cm-tooltip-below", !above);
7988
+ if (tView.positioned)
7989
+ tView.positioned();
7990
+ }
7991
+ }
7992
+ maybeMeasure() {
7993
+ if (this.manager.tooltips.length) {
7994
+ if (this.view.inView)
7995
+ this.view.requestMeasure(this.measureReq);
7996
+ if (this.inView != this.view.inView) {
7997
+ this.inView = this.view.inView;
7998
+ if (!this.inView)
7999
+ for (let tv of this.manager.tooltipViews)
8000
+ tv.dom.style.top = Outside;
8001
+ }
8002
+ }
8003
+ }
8004
+ }, {
8005
+ eventHandlers: {
8006
+ scroll() { this.maybeMeasure(); }
8007
+ }
8008
+ });
8009
+ const baseTheme = /*@__PURE__*/EditorView.baseTheme({
8010
+ ".cm-tooltip": {
8011
+ zIndex: 100
8012
+ },
8013
+ "&light .cm-tooltip": {
8014
+ border: "1px solid #bbb",
8015
+ backgroundColor: "#f5f5f5"
8016
+ },
8017
+ "&light .cm-tooltip-section:not(:first-child)": {
8018
+ borderTop: "1px solid #bbb",
8019
+ },
8020
+ "&dark .cm-tooltip": {
8021
+ backgroundColor: "#333338",
8022
+ color: "white"
8023
+ },
8024
+ ".cm-tooltip-arrow": {
8025
+ height: `${7 /* Size */}px`,
8026
+ width: `${7 /* Size */ * 2}px`,
8027
+ position: "absolute",
8028
+ zIndex: -1,
8029
+ overflow: "hidden",
8030
+ "&:before, &:after": {
8031
+ content: "''",
8032
+ position: "absolute",
8033
+ width: 0,
8034
+ height: 0,
8035
+ borderLeft: `${7 /* Size */}px solid transparent`,
8036
+ borderRight: `${7 /* Size */}px solid transparent`,
8037
+ },
8038
+ ".cm-tooltip-above &": {
8039
+ bottom: `-${7 /* Size */}px`,
8040
+ "&:before": {
8041
+ borderTop: `${7 /* Size */}px solid #bbb`,
8042
+ },
8043
+ "&:after": {
8044
+ borderTop: `${7 /* Size */}px solid #f5f5f5`,
8045
+ bottom: "1px"
8046
+ }
8047
+ },
8048
+ ".cm-tooltip-below &": {
8049
+ top: `-${7 /* Size */}px`,
8050
+ "&:before": {
8051
+ borderBottom: `${7 /* Size */}px solid #bbb`,
8052
+ },
8053
+ "&:after": {
8054
+ borderBottom: `${7 /* Size */}px solid #f5f5f5`,
8055
+ top: "1px"
8056
+ }
8057
+ },
8058
+ },
8059
+ "&dark .cm-tooltip .cm-tooltip-arrow": {
8060
+ "&:before": {
8061
+ borderTopColor: "#333338",
8062
+ borderBottomColor: "#333338"
8063
+ },
8064
+ "&:after": {
8065
+ borderTopColor: "transparent",
8066
+ borderBottomColor: "transparent"
8067
+ }
8068
+ }
8069
+ });
8070
+ const noOffset = { x: 0, y: 0 };
8071
+ /**
8072
+ Facet to which an extension can add a value to show a tooltip.
8073
+ */
8074
+ const showTooltip = /*@__PURE__*/Facet.define({
8075
+ enables: [tooltipPlugin, baseTheme]
8076
+ });
8077
+ const showHoverTooltip = /*@__PURE__*/Facet.define({
8078
+ combine(x) { console.log("show", x.map(x => !!x)); return x; }
8079
+ });
8080
+ class HoverTooltipHost {
8081
+ constructor(view) {
8082
+ this.view = view;
8083
+ this.mounted = false;
8084
+ this.dom = document.createElement("div");
8085
+ this.dom.classList.add("cm-tooltip-hover");
8086
+ this.manager = new TooltipViewManager(view, showHoverTooltip, t => this.createHostedView(t));
8087
+ }
8088
+ // Needs to be static so that host tooltip instances always match
8089
+ static create(view) {
8090
+ return new HoverTooltipHost(view);
8091
+ }
8092
+ createHostedView(tooltip) {
8093
+ let hostedView = tooltip.create(this.view);
8094
+ hostedView.dom.classList.add("cm-tooltip-section");
8095
+ this.dom.appendChild(hostedView.dom);
8096
+ if (this.mounted && hostedView.mount)
8097
+ hostedView.mount(this.view);
8098
+ return hostedView;
8099
+ }
8100
+ mount(view) {
8101
+ for (let hostedView of this.manager.tooltipViews) {
8102
+ if (hostedView.mount)
8103
+ hostedView.mount(view);
8104
+ }
8105
+ this.mounted = true;
8106
+ }
8107
+ positioned() {
8108
+ for (let hostedView of this.manager.tooltipViews) {
8109
+ if (hostedView.positioned)
8110
+ hostedView.positioned();
8111
+ }
8112
+ }
8113
+ update(update) {
8114
+ this.manager.update(update);
8115
+ }
8116
+ }
8117
+ const showHoverTooltipHost = /*@__PURE__*/showTooltip.compute([showHoverTooltip], state => {
8118
+ let tooltips = state.facet(showHoverTooltip).filter(t => t);
8119
+ console.log("hover tooltips: ", tooltips.length);
8120
+ if (tooltips.length === 0)
8121
+ return null;
8122
+ return {
8123
+ pos: Math.min(...tooltips.map(t => t.pos)),
8124
+ end: Math.max(...tooltips.filter(t => t.end != null).map(t => t.end)),
8125
+ create: HoverTooltipHost.create,
8126
+ above: tooltips[0].above,
8127
+ arrow: tooltips.some(t => t.arrow),
8128
+ };
8129
+ });
8130
+ class HoverPlugin {
8131
+ constructor(view, source, field, setHover, hoverTime) {
8132
+ this.view = view;
8133
+ this.source = source;
8134
+ this.field = field;
8135
+ this.setHover = setHover;
8136
+ this.hoverTime = hoverTime;
8137
+ this.hoverTimeout = -1;
8138
+ this.restartTimeout = -1;
8139
+ this.pending = null;
8140
+ this.lastMove = { x: 0, y: 0, target: view.dom, time: 0 };
8141
+ this.checkHover = this.checkHover.bind(this);
8142
+ view.dom.addEventListener("mouseleave", this.mouseleave = this.mouseleave.bind(this));
8143
+ view.dom.addEventListener("mousemove", this.mousemove = this.mousemove.bind(this));
8144
+ }
8145
+ update() {
8146
+ if (this.pending) {
8147
+ this.pending = null;
8148
+ clearTimeout(this.restartTimeout);
8149
+ this.restartTimeout = setTimeout(() => this.startHover(), 20);
8150
+ }
8151
+ }
8152
+ get active() {
8153
+ return this.view.state.field(this.field);
8154
+ }
8155
+ checkHover() {
8156
+ this.hoverTimeout = -1;
8157
+ if (this.active)
8158
+ return;
8159
+ let hovered = Date.now() - this.lastMove.time;
8160
+ if (hovered < this.hoverTime)
8161
+ this.hoverTimeout = setTimeout(this.checkHover, this.hoverTime - hovered);
8162
+ else
8163
+ this.startHover();
8164
+ }
8165
+ startHover() {
8166
+ var _a;
8167
+ clearTimeout(this.restartTimeout);
8168
+ let { lastMove } = this;
8169
+ let pos = this.view.contentDOM.contains(lastMove.target) ? this.view.posAtCoords(lastMove) : null;
8170
+ if (pos == null)
8171
+ return;
8172
+ let posCoords = this.view.coordsAtPos(pos);
8173
+ if (posCoords == null || lastMove.y < posCoords.top || lastMove.y > posCoords.bottom ||
8174
+ lastMove.x < posCoords.left - this.view.defaultCharacterWidth ||
8175
+ lastMove.x > posCoords.right + this.view.defaultCharacterWidth)
8176
+ return;
8177
+ let bidi = this.view.bidiSpans(this.view.state.doc.lineAt(pos)).find(s => s.from <= pos && s.to >= pos);
8178
+ let rtl = bidi && bidi.dir == Direction.RTL ? -1 : 1;
8179
+ let open = this.source(this.view, pos, (lastMove.x < posCoords.left ? -rtl : rtl));
8180
+ if ((_a = open) === null || _a === void 0 ? void 0 : _a.then) {
8181
+ let pending = this.pending = { pos };
8182
+ open.then(result => {
8183
+ if (this.pending == pending) {
8184
+ this.pending = null;
8185
+ if (result)
8186
+ this.view.dispatch({ effects: this.setHover.of(result) });
8187
+ }
8188
+ }, e => logException(this.view.state, e, "hover tooltip"));
8189
+ }
8190
+ else if (open) {
8191
+ this.view.dispatch({ effects: this.setHover.of(open) });
8192
+ }
8193
+ }
8194
+ mousemove(event) {
8195
+ var _a;
8196
+ this.lastMove = { x: event.clientX, y: event.clientY, target: event.target, time: Date.now() };
8197
+ if (this.hoverTimeout < 0)
8198
+ this.hoverTimeout = setTimeout(this.checkHover, this.hoverTime);
8199
+ let tooltip = this.active;
8200
+ if (tooltip && !isInTooltip(this.lastMove.target) || this.pending) {
8201
+ let { pos } = tooltip || this.pending, end = (_a = tooltip === null || tooltip === void 0 ? void 0 : tooltip.end) !== null && _a !== void 0 ? _a : pos;
8202
+ if ((pos == end ? this.view.posAtCoords(this.lastMove) != pos
8203
+ : !isOverRange(this.view, pos, end, event.clientX, event.clientY, 6 /* MaxDist */))) {
8204
+ this.view.dispatch({ effects: this.setHover.of(null) });
8205
+ this.pending = null;
8206
+ }
8207
+ }
8208
+ }
8209
+ mouseleave() {
8210
+ clearTimeout(this.hoverTimeout);
8211
+ this.hoverTimeout = -1;
8212
+ if (this.active)
8213
+ this.view.dispatch({ effects: this.setHover.of(null) });
8214
+ }
8215
+ destroy() {
8216
+ clearTimeout(this.hoverTimeout);
8217
+ this.view.dom.removeEventListener("mouseleave", this.mouseleave);
8218
+ this.view.dom.removeEventListener("mousemove", this.mousemove);
8219
+ }
8220
+ }
8221
+ function isInTooltip(elt) {
8222
+ for (let cur = elt; cur; cur = cur.parentNode)
8223
+ if (cur.nodeType == 1 && cur.classList.contains("cm-tooltip"))
8224
+ return true;
8225
+ return false;
8226
+ }
8227
+ function isOverRange(view, from, to, x, y, margin) {
8228
+ let range = document.createRange();
8229
+ let fromDOM = view.domAtPos(from), toDOM = view.domAtPos(to);
8230
+ range.setEnd(toDOM.node, toDOM.offset);
8231
+ range.setStart(fromDOM.node, fromDOM.offset);
8232
+ let rects = range.getClientRects();
8233
+ range.detach();
8234
+ for (let i = 0; i < rects.length; i++) {
8235
+ let rect = rects[i];
8236
+ let dist = Math.max(rect.top - y, y - rect.bottom, rect.left - x, x - rect.right);
8237
+ if (dist <= margin)
8238
+ return true;
8239
+ }
8240
+ return false;
8241
+ }
8242
+ /**
8243
+ Set up a hover tooltip, which shows up when the pointer hovers
8244
+ over ranges of text. The callback is called when the mouse hovers
8245
+ over the document text. It should, if there is a tooltip
8246
+ associated with position `pos`, return the tooltip description
8247
+ (either directly or in a promise). The `side` argument indicates
8248
+ on which side of the position the pointer is—it will be -1 if the
8249
+ pointer is before the position, 1 if after the position.
8250
+
8251
+ Note that all hover tooltips are hosted within a single tooltip
8252
+ container element. This allows multiple tooltips over the same
8253
+ range to be "merged" together without overlapping.
8254
+ */
8255
+ function hoverTooltip(source, options = {}) {
8256
+ let setHover = StateEffect.define();
8257
+ let hoverState = StateField.define({
8258
+ create() { return null; },
8259
+ update(value, tr) {
8260
+ console.log("update tooltip", !!value);
8261
+ if (value && (options.hideOnChange && (tr.docChanged || tr.selection)))
8262
+ return null;
8263
+ if (value && tr.docChanged) {
8264
+ let newPos = tr.changes.mapPos(value.pos, -1, MapMode.TrackDel);
8265
+ if (newPos == null)
8266
+ return null;
8267
+ let copy = Object.assign(Object.create(null), value);
8268
+ copy.pos = newPos;
8269
+ if (value.end != null)
8270
+ copy.end = tr.changes.mapPos(value.end);
8271
+ value = copy;
8272
+ }
8273
+ for (let effect of tr.effects) {
8274
+ if (effect.is(setHover))
8275
+ value = effect.value;
8276
+ if (effect.is(closeHoverTooltipEffect))
8277
+ value = (console.log("CLOSE"), null);
8278
+ }
8279
+ console.log("updated: " + !!value);
8280
+ return value;
8281
+ },
8282
+ provide: f => showHoverTooltip.from(f)
8283
+ });
8284
+ return [
8285
+ hoverState,
8286
+ ViewPlugin.define(view => new HoverPlugin(view, source, hoverState, setHover, options.hoverTime || 300 /* Time */)),
8287
+ showHoverTooltipHost
8288
+ ];
8289
+ }
8290
+ /**
8291
+ Get the active tooltip view for a given tooltip, if available.
8292
+ */
8293
+ function getTooltip(view, tooltip) {
8294
+ let plugin = view.plugin(tooltipPlugin);
8295
+ if (!plugin)
8296
+ return null;
8297
+ let found = plugin.manager.tooltips.indexOf(tooltip);
8298
+ return found < 0 ? null : plugin.manager.tooltipViews[found];
8299
+ }
8300
+ /**
8301
+ Returns true if any hover tooltips are currently active.
8302
+ */
8303
+ function hasHoverTooltips(state) {
8304
+ return state.facet(showHoverTooltip).some(x => x);
8305
+ }
8306
+ const closeHoverTooltipEffect = /*@__PURE__*/StateEffect.define();
8307
+ /**
8308
+ Transaction effect that closes all hover tooltips.
8309
+ */
8310
+ const closeHoverTooltips = /*@__PURE__*/closeHoverTooltipEffect.of(null);
8311
+ /**
8312
+ Tell the tooltip extension to recompute the position of the active
8313
+ tooltips. This can be useful when something happens (such as a
8314
+ re-positioning or CSS change affecting the editor) that could
8315
+ invalidate the existing tooltip positions.
8316
+ */
8317
+ function repositionTooltips(view) {
8318
+ var _a;
8319
+ (_a = view.plugin(tooltipPlugin)) === null || _a === void 0 ? void 0 : _a.maybeMeasure();
8320
+ }
8321
+
8322
+ const panelConfig = /*@__PURE__*/Facet.define({
8323
+ combine(configs) {
8324
+ let topContainer, bottomContainer;
8325
+ for (let c of configs) {
8326
+ topContainer = topContainer || c.topContainer;
8327
+ bottomContainer = bottomContainer || c.bottomContainer;
8328
+ }
8329
+ return { topContainer, bottomContainer };
8330
+ }
8331
+ });
8332
+ /**
8333
+ Configures the panel-managing extension.
8334
+ */
8335
+ function panels(config) {
8336
+ return config ? [panelConfig.of(config)] : [];
8337
+ }
8338
+ /**
8339
+ Get the active panel created by the given constructor, if any.
8340
+ This can be useful when you need access to your panels' DOM
8341
+ structure.
8342
+ */
8343
+ function getPanel(view, panel) {
8344
+ let plugin = view.plugin(panelPlugin);
8345
+ let index = plugin ? plugin.specs.indexOf(panel) : -1;
8346
+ return index > -1 ? plugin.panels[index] : null;
8347
+ }
8348
+ const panelPlugin = /*@__PURE__*/ViewPlugin.fromClass(class {
8349
+ constructor(view) {
8350
+ this.input = view.state.facet(showPanel);
8351
+ this.specs = this.input.filter(s => s);
8352
+ this.panels = this.specs.map(spec => spec(view));
8353
+ let conf = view.state.facet(panelConfig);
8354
+ this.top = new PanelGroup(view, true, conf.topContainer);
8355
+ this.bottom = new PanelGroup(view, false, conf.bottomContainer);
8356
+ this.top.sync(this.panels.filter(p => p.top));
8357
+ this.bottom.sync(this.panels.filter(p => !p.top));
8358
+ for (let p of this.panels) {
8359
+ p.dom.classList.add("cm-panel");
8360
+ if (p.mount)
8361
+ p.mount();
8362
+ }
8363
+ }
8364
+ update(update) {
8365
+ let conf = update.state.facet(panelConfig);
8366
+ if (this.top.container != conf.topContainer) {
8367
+ this.top.sync([]);
8368
+ this.top = new PanelGroup(update.view, true, conf.topContainer);
8369
+ }
8370
+ if (this.bottom.container != conf.bottomContainer) {
8371
+ this.bottom.sync([]);
8372
+ this.bottom = new PanelGroup(update.view, false, conf.bottomContainer);
8373
+ }
8374
+ this.top.syncClasses();
8375
+ this.bottom.syncClasses();
8376
+ let input = update.state.facet(showPanel);
8377
+ if (input != this.input) {
8378
+ let specs = input.filter(x => x);
8379
+ let panels = [], top = [], bottom = [], mount = [];
8380
+ for (let spec of specs) {
8381
+ let known = this.specs.indexOf(spec), panel;
8382
+ if (known < 0) {
8383
+ panel = spec(update.view);
8384
+ mount.push(panel);
8385
+ }
8386
+ else {
8387
+ panel = this.panels[known];
8388
+ if (panel.update)
8389
+ panel.update(update);
8390
+ }
8391
+ panels.push(panel);
8392
+ (panel.top ? top : bottom).push(panel);
8393
+ }
8394
+ this.specs = specs;
8395
+ this.panels = panels;
8396
+ this.top.sync(top);
8397
+ this.bottom.sync(bottom);
8398
+ for (let p of mount) {
8399
+ p.dom.classList.add("cm-panel");
8400
+ if (p.mount)
8401
+ p.mount();
8402
+ }
8403
+ }
8404
+ else {
8405
+ for (let p of this.panels)
8406
+ if (p.update)
8407
+ p.update(update);
8408
+ }
8409
+ }
8410
+ destroy() {
8411
+ this.top.sync([]);
8412
+ this.bottom.sync([]);
8413
+ }
8414
+ }, {
8415
+ provide: plugin => EditorView.scrollMargins.of(view => {
8416
+ let value = view.plugin(plugin);
8417
+ return value && { top: value.top.scrollMargin(), bottom: value.bottom.scrollMargin() };
8418
+ })
8419
+ });
8420
+ class PanelGroup {
8421
+ constructor(view, top, container) {
8422
+ this.view = view;
8423
+ this.top = top;
8424
+ this.container = container;
8425
+ this.dom = undefined;
8426
+ this.classes = "";
8427
+ this.panels = [];
8428
+ this.syncClasses();
8429
+ }
8430
+ sync(panels) {
8431
+ for (let p of this.panels)
8432
+ if (p.destroy && panels.indexOf(p) < 0)
8433
+ p.destroy();
8434
+ this.panels = panels;
8435
+ this.syncDOM();
8436
+ }
8437
+ syncDOM() {
8438
+ if (this.panels.length == 0) {
8439
+ if (this.dom) {
8440
+ this.dom.remove();
8441
+ this.dom = undefined;
8442
+ }
8443
+ return;
8444
+ }
8445
+ if (!this.dom) {
8446
+ this.dom = document.createElement("div");
8447
+ this.dom.className = this.top ? "cm-panels cm-panels-top" : "cm-panels cm-panels-bottom";
8448
+ this.dom.style[this.top ? "top" : "bottom"] = "0";
8449
+ let parent = this.container || this.view.dom;
8450
+ parent.insertBefore(this.dom, this.top ? parent.firstChild : null);
8451
+ }
8452
+ let curDOM = this.dom.firstChild;
8453
+ for (let panel of this.panels) {
8454
+ if (panel.dom.parentNode == this.dom) {
8455
+ while (curDOM != panel.dom)
8456
+ curDOM = rm(curDOM);
8457
+ curDOM = curDOM.nextSibling;
8458
+ }
8459
+ else {
8460
+ this.dom.insertBefore(panel.dom, curDOM);
8461
+ }
8462
+ }
8463
+ while (curDOM)
8464
+ curDOM = rm(curDOM);
8465
+ }
8466
+ scrollMargin() {
8467
+ return !this.dom || this.container ? 0
8468
+ : Math.max(0, this.top ?
8469
+ this.dom.getBoundingClientRect().bottom - Math.max(0, this.view.scrollDOM.getBoundingClientRect().top) :
8470
+ Math.min(innerHeight, this.view.scrollDOM.getBoundingClientRect().bottom) - this.dom.getBoundingClientRect().top);
8471
+ }
8472
+ syncClasses() {
8473
+ if (!this.container || this.classes == this.view.themeClasses)
8474
+ return;
8475
+ for (let cls of this.classes.split(" "))
8476
+ if (cls)
8477
+ this.container.classList.remove(cls);
8478
+ for (let cls of (this.classes = this.view.themeClasses).split(" "))
8479
+ if (cls)
8480
+ this.container.classList.add(cls);
8481
+ }
8482
+ }
8483
+ function rm(node) {
8484
+ let next = node.nextSibling;
8485
+ node.remove();
8486
+ return next;
8487
+ }
8488
+ /**
8489
+ Opening a panel is done by providing a constructor function for
8490
+ the panel through this facet. (The panel is closed again when its
8491
+ constructor is no longer provided.) Values of `null` are ignored.
8492
+ */
8493
+ const showPanel = /*@__PURE__*/Facet.define({
8494
+ enables: panelPlugin
8495
+ });
8496
+
8497
+ /**
8498
+ A gutter marker represents a bit of information attached to a line
8499
+ in a specific gutter. Your own custom markers have to extend this
8500
+ class.
8501
+ */
8502
+ class GutterMarker extends RangeValue {
8503
+ /**
8504
+ @internal
8505
+ */
8506
+ compare(other) {
8507
+ return this == other || this.constructor == other.constructor && this.eq(other);
8508
+ }
8509
+ /**
8510
+ Compare this marker to another marker of the same type.
8511
+ */
8512
+ eq(other) { return false; }
8513
+ /**
8514
+ Called if the marker has a `toDOM` method and its representation
8515
+ was removed from a gutter.
8516
+ */
8517
+ destroy(dom) { }
8518
+ }
8519
+ GutterMarker.prototype.elementClass = "";
8520
+ GutterMarker.prototype.toDOM = undefined;
8521
+ GutterMarker.prototype.mapMode = MapMode.TrackBefore;
8522
+ GutterMarker.prototype.startSide = GutterMarker.prototype.endSide = -1;
8523
+ GutterMarker.prototype.point = true;
8524
+ /**
8525
+ Facet used to add a class to all gutter elements for a given line.
8526
+ Markers given to this facet should _only_ define an
8527
+ [`elementclass`](https://codemirror.net/6/docs/ref/#view.GutterMarker.elementClass), not a
8528
+ [`toDOM`](https://codemirror.net/6/docs/ref/#view.GutterMarker.toDOM) (or the marker will appear
8529
+ in all gutters for the line).
8530
+ */
8531
+ const gutterLineClass = /*@__PURE__*/Facet.define();
8532
+ const defaults = {
8533
+ class: "",
8534
+ renderEmptyElements: false,
8535
+ elementStyle: "",
8536
+ markers: () => RangeSet.empty,
8537
+ lineMarker: () => null,
8538
+ lineMarkerChange: null,
8539
+ initialSpacer: null,
8540
+ updateSpacer: null,
8541
+ domEventHandlers: {}
8542
+ };
8543
+ const activeGutters = /*@__PURE__*/Facet.define();
8544
+ /**
8545
+ Define an editor gutter. The order in which the gutters appear is
8546
+ determined by their extension priority.
8547
+ */
8548
+ function gutter(config) {
8549
+ return [gutters(), activeGutters.of(Object.assign(Object.assign({}, defaults), config))];
8550
+ }
8551
+ const unfixGutters = /*@__PURE__*/Facet.define({
8552
+ combine: values => values.some(x => x)
8553
+ });
8554
+ /**
8555
+ The gutter-drawing plugin is automatically enabled when you add a
8556
+ gutter, but you can use this function to explicitly configure it.
8557
+
8558
+ Unless `fixed` is explicitly set to `false`, the gutters are
8559
+ fixed, meaning they don't scroll along with the content
8560
+ horizontally (except on Internet Explorer, which doesn't support
8561
+ CSS [`position:
8562
+ sticky`](https://developer.mozilla.org/en-US/docs/Web/CSS/position#sticky)).
8563
+ */
8564
+ function gutters(config) {
8565
+ let result = [
8566
+ gutterView,
8567
+ ];
8568
+ if (config && config.fixed === false)
8569
+ result.push(unfixGutters.of(true));
8570
+ return result;
8571
+ }
8572
+ const gutterView = /*@__PURE__*/ViewPlugin.fromClass(class {
8573
+ constructor(view) {
8574
+ this.view = view;
8575
+ this.prevViewport = view.viewport;
8576
+ this.dom = document.createElement("div");
8577
+ this.dom.className = "cm-gutters";
8578
+ this.dom.setAttribute("aria-hidden", "true");
8579
+ this.dom.style.minHeight = this.view.contentHeight + "px";
8580
+ this.gutters = view.state.facet(activeGutters).map(conf => new SingleGutterView(view, conf));
8581
+ for (let gutter of this.gutters)
8582
+ this.dom.appendChild(gutter.dom);
8583
+ this.fixed = !view.state.facet(unfixGutters);
8584
+ if (this.fixed) {
8585
+ // FIXME IE11 fallback, which doesn't support position: sticky,
8586
+ // by using position: relative + event handlers that realign the
8587
+ // gutter (or just force fixed=false on IE11?)
8588
+ this.dom.style.position = "sticky";
8589
+ }
8590
+ this.syncGutters(false);
8591
+ view.scrollDOM.insertBefore(this.dom, view.contentDOM);
8592
+ }
8593
+ update(update) {
8594
+ if (this.updateGutters(update)) {
8595
+ // Detach during sync when the viewport changed significantly
8596
+ // (such as during scrolling), since for large updates that is
8597
+ // faster.
8598
+ let vpA = this.prevViewport, vpB = update.view.viewport;
8599
+ let vpOverlap = Math.min(vpA.to, vpB.to) - Math.max(vpA.from, vpB.from);
8600
+ this.syncGutters(vpOverlap < (vpB.to - vpB.from) * 0.8);
8601
+ }
8602
+ if (update.geometryChanged)
8603
+ this.dom.style.minHeight = this.view.contentHeight + "px";
8604
+ if (this.view.state.facet(unfixGutters) != !this.fixed) {
8605
+ this.fixed = !this.fixed;
8606
+ this.dom.style.position = this.fixed ? "sticky" : "";
8607
+ }
8608
+ this.prevViewport = update.view.viewport;
8609
+ }
8610
+ syncGutters(detach) {
8611
+ let after = this.dom.nextSibling;
8612
+ if (detach)
8613
+ this.dom.remove();
8614
+ let lineClasses = RangeSet.iter(this.view.state.facet(gutterLineClass), this.view.viewport.from);
8615
+ let classSet = [];
8616
+ let contexts = this.gutters.map(gutter => new UpdateContext(gutter, this.view.viewport, -this.view.documentPadding.top));
8617
+ for (let line of this.view.viewportLineBlocks) {
8618
+ let text;
8619
+ if (Array.isArray(line.type)) {
8620
+ for (let b of line.type)
8621
+ if (b.type == BlockType.Text) {
8622
+ text = b;
8623
+ break;
8624
+ }
8625
+ }
8626
+ else {
8627
+ text = line.type == BlockType.Text ? line : undefined;
8628
+ }
8629
+ if (!text)
8630
+ continue;
8631
+ if (classSet.length)
8632
+ classSet = [];
8633
+ advanceCursor(lineClasses, classSet, line.from);
8634
+ for (let cx of contexts)
8635
+ cx.line(this.view, text, classSet);
8636
+ }
8637
+ for (let cx of contexts)
8638
+ cx.finish();
8639
+ if (detach)
8640
+ this.view.scrollDOM.insertBefore(this.dom, after);
8641
+ }
8642
+ updateGutters(update) {
8643
+ let prev = update.startState.facet(activeGutters), cur = update.state.facet(activeGutters);
8644
+ let change = update.docChanged || update.heightChanged || update.viewportChanged ||
8645
+ !RangeSet.eq(update.startState.facet(gutterLineClass), update.state.facet(gutterLineClass), update.view.viewport.from, update.view.viewport.to);
8646
+ if (prev == cur) {
8647
+ for (let gutter of this.gutters)
8648
+ if (gutter.update(update))
8649
+ change = true;
8650
+ }
8651
+ else {
8652
+ change = true;
8653
+ let gutters = [];
8654
+ for (let conf of cur) {
8655
+ let known = prev.indexOf(conf);
8656
+ if (known < 0) {
8657
+ gutters.push(new SingleGutterView(this.view, conf));
8658
+ }
8659
+ else {
8660
+ this.gutters[known].update(update);
8661
+ gutters.push(this.gutters[known]);
8662
+ }
8663
+ }
8664
+ for (let g of this.gutters) {
8665
+ g.dom.remove();
8666
+ if (gutters.indexOf(g) < 0)
8667
+ g.destroy();
8668
+ }
8669
+ for (let g of gutters)
8670
+ this.dom.appendChild(g.dom);
8671
+ this.gutters = gutters;
8672
+ }
8673
+ return change;
8674
+ }
8675
+ destroy() {
8676
+ for (let view of this.gutters)
8677
+ view.destroy();
8678
+ this.dom.remove();
8679
+ }
8680
+ }, {
8681
+ provide: plugin => EditorView.scrollMargins.of(view => {
8682
+ let value = view.plugin(plugin);
8683
+ if (!value || value.gutters.length == 0 || !value.fixed)
8684
+ return null;
8685
+ return view.textDirection == Direction.LTR ? { left: value.dom.offsetWidth } : { right: value.dom.offsetWidth };
8686
+ })
8687
+ });
8688
+ function asArray(val) { return (Array.isArray(val) ? val : [val]); }
8689
+ function advanceCursor(cursor, collect, pos) {
8690
+ while (cursor.value && cursor.from <= pos) {
8691
+ if (cursor.from == pos)
8692
+ collect.push(cursor.value);
8693
+ cursor.next();
8694
+ }
8695
+ }
8696
+ class UpdateContext {
8697
+ constructor(gutter, viewport, height) {
8698
+ this.gutter = gutter;
8699
+ this.height = height;
8700
+ this.localMarkers = [];
8701
+ this.i = 0;
8702
+ this.cursor = RangeSet.iter(gutter.markers, viewport.from);
8703
+ }
8704
+ line(view, line, extraMarkers) {
8705
+ if (this.localMarkers.length)
8706
+ this.localMarkers = [];
8707
+ advanceCursor(this.cursor, this.localMarkers, line.from);
8708
+ let localMarkers = extraMarkers.length ? this.localMarkers.concat(extraMarkers) : this.localMarkers;
8709
+ let forLine = this.gutter.config.lineMarker(view, line, localMarkers);
8710
+ if (forLine)
8711
+ localMarkers.unshift(forLine);
8712
+ let gutter = this.gutter;
8713
+ if (localMarkers.length == 0 && !gutter.config.renderEmptyElements)
8714
+ return;
8715
+ let above = line.top - this.height;
8716
+ if (this.i == gutter.elements.length) {
8717
+ let newElt = new GutterElement(view, line.height, above, localMarkers);
8718
+ gutter.elements.push(newElt);
8719
+ gutter.dom.appendChild(newElt.dom);
8720
+ }
8721
+ else {
8722
+ gutter.elements[this.i].update(view, line.height, above, localMarkers);
8723
+ }
8724
+ this.height = line.bottom;
8725
+ this.i++;
8726
+ }
8727
+ finish() {
8728
+ let gutter = this.gutter;
8729
+ while (gutter.elements.length > this.i) {
8730
+ let last = gutter.elements.pop();
8731
+ gutter.dom.removeChild(last.dom);
8732
+ last.destroy();
8733
+ }
8734
+ }
8735
+ }
8736
+ class SingleGutterView {
8737
+ constructor(view, config) {
8738
+ this.view = view;
8739
+ this.config = config;
8740
+ this.elements = [];
8741
+ this.spacer = null;
8742
+ this.dom = document.createElement("div");
8743
+ this.dom.className = "cm-gutter" + (this.config.class ? " " + this.config.class : "");
8744
+ for (let prop in config.domEventHandlers) {
8745
+ this.dom.addEventListener(prop, (event) => {
8746
+ let line = view.lineBlockAtHeight(event.clientY - view.documentTop);
8747
+ if (config.domEventHandlers[prop](view, line, event))
8748
+ event.preventDefault();
8749
+ });
8750
+ }
8751
+ this.markers = asArray(config.markers(view));
8752
+ if (config.initialSpacer) {
8753
+ this.spacer = new GutterElement(view, 0, 0, [config.initialSpacer(view)]);
8754
+ this.dom.appendChild(this.spacer.dom);
8755
+ this.spacer.dom.style.cssText += "visibility: hidden; pointer-events: none";
8756
+ }
8757
+ }
8758
+ update(update) {
8759
+ let prevMarkers = this.markers;
8760
+ this.markers = asArray(this.config.markers(update.view));
8761
+ if (this.spacer && this.config.updateSpacer) {
8762
+ let updated = this.config.updateSpacer(this.spacer.markers[0], update);
8763
+ if (updated != this.spacer.markers[0])
8764
+ this.spacer.update(update.view, 0, 0, [updated]);
8765
+ }
8766
+ let vp = update.view.viewport;
8767
+ return !RangeSet.eq(this.markers, prevMarkers, vp.from, vp.to) ||
8768
+ (this.config.lineMarkerChange ? this.config.lineMarkerChange(update) : false);
8769
+ }
8770
+ destroy() {
8771
+ for (let elt of this.elements)
8772
+ elt.destroy();
8773
+ }
8774
+ }
8775
+ class GutterElement {
8776
+ constructor(view, height, above, markers) {
8777
+ this.height = -1;
8778
+ this.above = 0;
8779
+ this.markers = [];
8780
+ this.dom = document.createElement("div");
8781
+ this.update(view, height, above, markers);
8782
+ }
8783
+ update(view, height, above, markers) {
8784
+ if (this.height != height)
8785
+ this.dom.style.height = (this.height = height) + "px";
8786
+ if (this.above != above)
8787
+ this.dom.style.marginTop = (this.above = above) ? above + "px" : "";
8788
+ if (!sameMarkers(this.markers, markers))
8789
+ this.setMarkers(view, markers);
8790
+ }
8791
+ setMarkers(view, markers) {
8792
+ let cls = "cm-gutterElement", domPos = this.dom.firstChild;
8793
+ for (let iNew = 0, iOld = 0;;) {
8794
+ let skipTo = iOld, marker = iNew < markers.length ? markers[iNew++] : null, matched = false;
8795
+ if (marker) {
8796
+ let c = marker.elementClass;
8797
+ if (c)
8798
+ cls += " " + c;
8799
+ for (let i = iOld; i < this.markers.length; i++)
8800
+ if (this.markers[i].compare(marker)) {
8801
+ skipTo = i;
8802
+ matched = true;
8803
+ break;
8804
+ }
8805
+ }
8806
+ else {
8807
+ skipTo = this.markers.length;
8808
+ }
8809
+ while (iOld < skipTo) {
8810
+ let next = this.markers[iOld++];
8811
+ if (next.toDOM) {
8812
+ next.destroy(domPos);
8813
+ let after = domPos.nextSibling;
8814
+ domPos.remove();
8815
+ domPos = after;
8816
+ }
8817
+ }
8818
+ if (!marker)
8819
+ break;
8820
+ if (marker.toDOM) {
8821
+ if (matched)
8822
+ domPos = domPos.nextSibling;
8823
+ else
8824
+ this.dom.insertBefore(marker.toDOM(view), domPos);
8825
+ }
8826
+ if (matched)
8827
+ iOld++;
8828
+ }
8829
+ this.dom.className = cls;
8830
+ this.markers = markers;
8831
+ }
8832
+ destroy() {
8833
+ this.setMarkers(null, []); // First argument not used unless creating markers
8834
+ }
8835
+ }
8836
+ function sameMarkers(a, b) {
8837
+ if (a.length != b.length)
8838
+ return false;
8839
+ for (let i = 0; i < a.length; i++)
8840
+ if (!a[i].compare(b[i]))
8841
+ return false;
8842
+ return true;
8843
+ }
8844
+ /**
8845
+ Facet used to provide markers to the line number gutter.
8846
+ */
8847
+ const lineNumberMarkers = /*@__PURE__*/Facet.define();
8848
+ const lineNumberConfig = /*@__PURE__*/Facet.define({
8849
+ combine(values) {
8850
+ return combineConfig(values, { formatNumber: String, domEventHandlers: {} }, {
8851
+ domEventHandlers(a, b) {
8852
+ let result = Object.assign({}, a);
8853
+ for (let event in b) {
8854
+ let exists = result[event], add = b[event];
8855
+ result[event] = exists ? (view, line, event) => exists(view, line, event) || add(view, line, event) : add;
8856
+ }
8857
+ return result;
8858
+ }
8859
+ });
8860
+ }
8861
+ });
8862
+ class NumberMarker extends GutterMarker {
8863
+ constructor(number) {
8864
+ super();
8865
+ this.number = number;
8866
+ }
8867
+ eq(other) { return this.number == other.number; }
8868
+ toDOM() { return document.createTextNode(this.number); }
8869
+ }
8870
+ function formatNumber(view, number) {
8871
+ return view.state.facet(lineNumberConfig).formatNumber(number, view.state);
8872
+ }
8873
+ const lineNumberGutter = /*@__PURE__*/activeGutters.compute([lineNumberConfig], state => ({
8874
+ class: "cm-lineNumbers",
8875
+ renderEmptyElements: false,
8876
+ markers(view) { return view.state.facet(lineNumberMarkers); },
8877
+ lineMarker(view, line, others) {
8878
+ if (others.some(m => m.toDOM))
8879
+ return null;
8880
+ return new NumberMarker(formatNumber(view, view.state.doc.lineAt(line.from).number));
8881
+ },
8882
+ lineMarkerChange: update => update.startState.facet(lineNumberConfig) != update.state.facet(lineNumberConfig),
8883
+ initialSpacer(view) {
8884
+ return new NumberMarker(formatNumber(view, maxLineNumber(view.state.doc.lines)));
8885
+ },
8886
+ updateSpacer(spacer, update) {
8887
+ let max = formatNumber(update.view, maxLineNumber(update.view.state.doc.lines));
8888
+ return max == spacer.number ? spacer : new NumberMarker(max);
8889
+ },
8890
+ domEventHandlers: state.facet(lineNumberConfig).domEventHandlers
8891
+ }));
8892
+ /**
8893
+ Create a line number gutter extension.
8894
+ */
8895
+ function lineNumbers(config = {}) {
8896
+ return [
8897
+ lineNumberConfig.of(config),
8898
+ gutters(),
8899
+ lineNumberGutter
8900
+ ];
8901
+ }
8902
+ function maxLineNumber(lines) {
8903
+ let last = 9;
8904
+ while (last < lines)
8905
+ last = last * 10 + 9;
8906
+ return last;
8907
+ }
8908
+ const activeLineGutterMarker = /*@__PURE__*/new class extends GutterMarker {
8909
+ constructor() {
8910
+ super(...arguments);
8911
+ this.elementClass = "cm-activeLineGutter";
8912
+ }
8913
+ };
8914
+ const activeLineGutterHighlighter = /*@__PURE__*/gutterLineClass.compute(["selection"], state => {
8915
+ let marks = [], last = -1;
8916
+ for (let range of state.selection.ranges)
8917
+ if (range.empty) {
8918
+ let linePos = state.doc.lineAt(range.head).from;
8919
+ if (linePos > last) {
8920
+ last = linePos;
8921
+ marks.push(activeLineGutterMarker.range(linePos));
8922
+ }
8923
+ }
8924
+ return RangeSet.of(marks);
8925
+ });
8926
+ /**
8927
+ Returns an extension that adds a `cm-activeLineGutter` class to
8928
+ all gutter elements on the [active
8929
+ line](https://codemirror.net/6/docs/ref/#view.highlightActiveLine).
8930
+ */
8931
+ function highlightActiveLineGutter() {
8932
+ return activeLineGutterHighlighter;
8933
+ }
8934
+
7710
8935
  /**
7711
8936
  @internal
7712
8937
  */
7713
8938
  const __test = { HeightMap, HeightOracle, MeasuredHeights, QueryType, ChangedRange, computeOrder, moveVisually };
7714
8939
 
7715
- export { BidiSpan, BlockInfo, BlockType, Decoration, Direction, EditorView, MatchDecorator, PluginField, PluginFieldProvider, ViewPlugin, ViewUpdate, WidgetType, __test, drawSelection, dropCursor, highlightActiveLine, highlightSpecialChars, keymap, logException, placeholder, runScopeHandlers, scrollPastEnd };
8940
+ export { BidiSpan, BlockInfo, BlockType, Decoration, Direction, EditorView, GutterMarker, MatchDecorator, ViewPlugin, ViewUpdate, WidgetType, __test, closeHoverTooltips, crosshairCursor, drawSelection, dropCursor, getPanel, getTooltip, gutter, gutterLineClass, gutters, hasHoverTooltips, highlightActiveLine, highlightActiveLineGutter, highlightSpecialChars, hoverTooltip, keymap, lineNumberMarkers, lineNumbers, logException, panels, placeholder, rectangularSelection, repositionTooltips, runScopeHandlers, scrollPastEnd, showPanel, showTooltip, tooltips };