@codemirror/view 0.19.47 → 0.20.1

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;
@@ -1074,7 +1073,7 @@ function updateAttrs(dom, prev, attrs) {
1074
1073
  Widgets added to the content are described by subclasses of this
1075
1074
  class. Using a description object like that makes it possible to
1076
1075
  delay creating of the DOM structure for a widget until it is
1077
- needed, and to avoid redrawing widgets even when the decorations
1076
+ needed, and to avoid redrawing widgets even if the decorations
1078
1077
  that define them are recreated.
1079
1078
  */
1080
1079
  class WidgetType {
@@ -1087,7 +1086,7 @@ class WidgetType {
1087
1086
  returns `false`, which will cause new instances of the widget to
1088
1087
  always be redrawn.
1089
1088
  */
1090
- eq(_widget) { return false; }
1089
+ eq(widget) { return false; }
1091
1090
  /**
1092
1091
  Update a DOM element created by a widget of the same type (but
1093
1092
  different, non-`eq` content) to reflect this widget. May return
@@ -1095,7 +1094,7 @@ class WidgetType {
1095
1094
  couldn't (in which case the widget will be redrawn). The default
1096
1095
  implementation just returns false.
1097
1096
  */
1098
- updateDOM(_dom) { return false; }
1097
+ updateDOM(dom) { return false; }
1099
1098
  /**
1100
1099
  @internal
1101
1100
  */
@@ -1114,7 +1113,7 @@ class WidgetType {
1114
1113
  should be ignored by the editor. The default is to ignore all
1115
1114
  events.
1116
1115
  */
1117
- ignoreEvent(_event) { return true; }
1116
+ ignoreEvent(event) { return true; }
1118
1117
  /**
1119
1118
  @internal
1120
1119
  */
@@ -1123,7 +1122,7 @@ class WidgetType {
1123
1122
  This is called when the an instance of the widget is removed
1124
1123
  from the editor view.
1125
1124
  */
1126
- destroy(_dom) { }
1125
+ destroy(dom) { }
1127
1126
  }
1128
1127
  /**
1129
1128
  The different types of blocks that can occur in an editor view.
@@ -1149,7 +1148,8 @@ return BlockType})(BlockType || (BlockType = {}));
1149
1148
  /**
1150
1149
  A decoration provides information on how to draw or style a piece
1151
1150
  of content. You'll usually use it wrapped in a
1152
- [`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
1153
1153
  */
1154
1154
  class Decoration extends RangeValue {
1155
1155
  /**
@@ -1188,18 +1188,17 @@ class Decoration extends RangeValue {
1188
1188
  Create a mark decoration, which influences the styling of the
1189
1189
  content in its range. Nested mark decorations will cause nested
1190
1190
  DOM elements to be created. Nesting order is determined by
1191
- precedence of the [facet](https://codemirror.net/6/docs/ref/#view.EditorView^decorations) or
1192
- (below the facet-provided decorations) [view
1193
- plugin](https://codemirror.net/6/docs/ref/#view.PluginSpec.decorations). Such elements are split
1194
- on line boundaries and on the boundaries of higher-precedence
1195
- 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.
1196
1195
  */
1197
1196
  static mark(spec) {
1198
1197
  return new MarkDecoration(spec);
1199
1198
  }
1200
1199
  /**
1201
- Create a widget decoration, which adds an element at the given
1202
- position.
1200
+ Create a widget decoration, which displays a DOM element at the
1201
+ given position.
1203
1202
  */
1204
1203
  static widget(spec) {
1205
1204
  let side = spec.side || 0, block = !!spec.block;
@@ -1510,7 +1509,7 @@ class BlockWidgetView extends ContentView {
1510
1509
  }
1511
1510
  }
1512
1511
  get overrideDOMText() {
1513
- 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;
1514
1513
  }
1515
1514
  domBoundsAround() { return null; }
1516
1515
  become(other) {
@@ -1537,11 +1536,11 @@ class BlockWidgetView extends ContentView {
1537
1536
  }
1538
1537
 
1539
1538
  class ContentBuilder {
1540
- constructor(doc, pos, end, disallowBlockEffectsBelow) {
1539
+ constructor(doc, pos, end, disallowBlockEffectsFor) {
1541
1540
  this.doc = doc;
1542
1541
  this.pos = pos;
1543
1542
  this.end = end;
1544
- this.disallowBlockEffectsBelow = disallowBlockEffectsBelow;
1543
+ this.disallowBlockEffectsFor = disallowBlockEffectsFor;
1545
1544
  this.content = [];
1546
1545
  this.curLine = null;
1547
1546
  this.breakAtStart = 0;
@@ -1626,7 +1625,13 @@ class ContentBuilder {
1626
1625
  if (this.openStart < 0)
1627
1626
  this.openStart = openStart;
1628
1627
  }
1629
- 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
+ }
1630
1635
  let len = to - from;
1631
1636
  if (deco instanceof PointDecoration) {
1632
1637
  if (deco.block) {
@@ -1670,17 +1675,8 @@ class ContentBuilder {
1670
1675
  if (this.openStart < 0)
1671
1676
  this.openStart = openStart;
1672
1677
  }
1673
- filterPoint(from, to, value, index) {
1674
- if (index < this.disallowBlockEffectsBelow && value instanceof PointDecoration) {
1675
- if (value.block)
1676
- throw new RangeError("Block decorations may not be specified via plugins");
1677
- if (to > this.doc.lineAt(this.pos).to)
1678
- throw new RangeError("Decorations that replace line breaks may not be specified via plugins");
1679
- }
1680
- return true;
1681
- }
1682
- static build(text, from, to, decorations, pluginDecorationLength) {
1683
- 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);
1684
1680
  builder.openEnd = RangeSet.spans(decorations, from, to, builder);
1685
1681
  if (builder.openStart < 0)
1686
1682
  builder.openStart = builder.openEnd;
@@ -1710,13 +1706,8 @@ const mouseSelectionStyle = /*@__PURE__*/Facet.define();
1710
1706
  const exceptionSink = /*@__PURE__*/Facet.define();
1711
1707
  const updateListener = /*@__PURE__*/Facet.define();
1712
1708
  const inputHandler = /*@__PURE__*/Facet.define();
1713
- // FIXME remove
1714
- const scrollTo = /*@__PURE__*/StateEffect.define({
1715
- map: (range, changes) => range.map(changes)
1716
- });
1717
- // FIXME remove
1718
- const centerOn = /*@__PURE__*/StateEffect.define({
1719
- map: (range, changes) => range.map(changes)
1709
+ const perLineTextDirection = /*@__PURE__*/Facet.define({
1710
+ combine: values => values.some(x => x)
1720
1711
  });
1721
1712
  class ScrollTarget {
1722
1713
  constructor(range, y = "nearest", x = "nearest", yMargin = 5, xMargin = 5) {
@@ -1755,83 +1746,6 @@ function logException(state, exception, context) {
1755
1746
  console.error(exception);
1756
1747
  }
1757
1748
  const editable = /*@__PURE__*/Facet.define({ combine: values => values.length ? values[0] : true });
1758
- /**
1759
- Used to [declare](https://codemirror.net/6/docs/ref/#view.PluginSpec.provide) which
1760
- [fields](https://codemirror.net/6/docs/ref/#view.PluginValue) a [view plugin](https://codemirror.net/6/docs/ref/#view.ViewPlugin)
1761
- provides.
1762
- */
1763
- class PluginFieldProvider {
1764
- /**
1765
- @internal
1766
- */
1767
- constructor(
1768
- /**
1769
- @internal
1770
- */
1771
- field,
1772
- /**
1773
- @internal
1774
- */
1775
- get) {
1776
- this.field = field;
1777
- this.get = get;
1778
- }
1779
- }
1780
- /**
1781
- Plugin fields are a mechanism for allowing plugins to provide
1782
- values that can be retrieved through the
1783
- [`pluginField`](https://codemirror.net/6/docs/ref/#view.EditorView.pluginField) view method.
1784
- */
1785
- class PluginField {
1786
- /**
1787
- Create a [provider](https://codemirror.net/6/docs/ref/#view.PluginFieldProvider) for this field,
1788
- to use with a plugin's [provide](https://codemirror.net/6/docs/ref/#view.PluginSpec.provide)
1789
- option.
1790
- */
1791
- from(get) {
1792
- return new PluginFieldProvider(this, get);
1793
- }
1794
- /**
1795
- Define a new plugin field.
1796
- */
1797
- static define() { return new PluginField(); }
1798
- }
1799
- /**
1800
- This field can be used by plugins to provide
1801
- [decorations](https://codemirror.net/6/docs/ref/#view.Decoration).
1802
-
1803
- **Note**: For reasons of data flow (plugins are only updated
1804
- after the viewport is computed), decorations produced by plugins
1805
- are _not_ taken into account when predicting the vertical layout
1806
- structure of the editor. They **must not** introduce block
1807
- widgets (that will raise an error) or replacing decorations that
1808
- cover line breaks (these will be ignored if they occur). Such
1809
- decorations, or others that cause a large amount of vertical
1810
- size shift compared to the undecorated content, should be
1811
- provided through the state-level [`decorations`
1812
- facet](https://codemirror.net/6/docs/ref/#view.EditorView^decorations) instead.
1813
- */
1814
- PluginField.decorations = /*@__PURE__*/PluginField.define();
1815
- /**
1816
- Used to provide ranges that should be treated as atoms as far as
1817
- cursor motion is concerned. This causes methods like
1818
- [`moveByChar`](https://codemirror.net/6/docs/ref/#view.EditorView.moveByChar) and
1819
- [`moveVertically`](https://codemirror.net/6/docs/ref/#view.EditorView.moveVertically) (and the
1820
- commands built on top of them) to skip across such regions when
1821
- a selection endpoint would enter them. This does _not_ prevent
1822
- direct programmatic [selection
1823
- updates](https://codemirror.net/6/docs/ref/#state.TransactionSpec.selection) from moving into such
1824
- regions.
1825
- */
1826
- PluginField.atomicRanges = /*@__PURE__*/PluginField.define();
1827
- /**
1828
- Plugins can provide additional scroll margins (space around the
1829
- sides of the scrolling element that should be considered
1830
- invisible) through this field. This can be useful when the
1831
- plugin introduces elements that cover part of that element (for
1832
- example a horizontally fixed gutter).
1833
- */
1834
- PluginField.scrollMargins = /*@__PURE__*/PluginField.define();
1835
1749
  let nextPluginID = 0;
1836
1750
  const viewPlugin = /*@__PURE__*/Facet.define();
1837
1751
  /**
@@ -1852,27 +1766,29 @@ class ViewPlugin {
1852
1766
  /**
1853
1767
  @internal
1854
1768
  */
1855
- fields) {
1769
+ domEventHandlers, buildExtensions) {
1856
1770
  this.id = id;
1857
1771
  this.create = create;
1858
- this.fields = fields;
1859
- this.extension = viewPlugin.of(this);
1772
+ this.domEventHandlers = domEventHandlers;
1773
+ this.extension = buildExtensions(this);
1860
1774
  }
1861
1775
  /**
1862
1776
  Define a plugin from a constructor function that creates the
1863
1777
  plugin's value, given an editor view.
1864
1778
  */
1865
1779
  static define(create, spec) {
1866
- let { eventHandlers, provide, decorations } = spec || {};
1867
- let fields = [];
1868
- if (provide)
1869
- for (let provider of Array.isArray(provide) ? provide : [provide])
1870
- fields.push(provider);
1871
- if (eventHandlers)
1872
- fields.push(domEventHandlers.from((value) => ({ plugin: value, handlers: eventHandlers })));
1873
- if (decorations)
1874
- fields.push(PluginField.decorations.from(decorations));
1875
- 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
+ });
1876
1792
  }
1877
1793
  /**
1878
1794
  Create a plugin for a class whose constructor takes a single
@@ -1882,7 +1798,6 @@ class ViewPlugin {
1882
1798
  return ViewPlugin.define(view => new cls(view), spec);
1883
1799
  }
1884
1800
  }
1885
- const domEventHandlers = /*@__PURE__*/PluginField.define();
1886
1801
  class PluginInstance {
1887
1802
  constructor(spec) {
1888
1803
  this.spec = spec;
@@ -1895,12 +1810,6 @@ class PluginInstance {
1895
1810
  // initialized on the first update.
1896
1811
  this.value = null;
1897
1812
  }
1898
- takeField(type, target) {
1899
- if (this.spec)
1900
- for (let { field, get } of this.spec.fields)
1901
- if (field == type)
1902
- target.push(get(this.value));
1903
- }
1904
1813
  update(view) {
1905
1814
  if (!this.value) {
1906
1815
  if (this.spec) {
@@ -1952,6 +1861,8 @@ const editorAttributes = /*@__PURE__*/Facet.define();
1952
1861
  const contentAttributes = /*@__PURE__*/Facet.define();
1953
1862
  // Provide decorations
1954
1863
  const decorations = /*@__PURE__*/Facet.define();
1864
+ const atomicRanges = /*@__PURE__*/Facet.define();
1865
+ const scrollMargins = /*@__PURE__*/Facet.define();
1955
1866
  const styleModule = /*@__PURE__*/Facet.define();
1956
1867
  class ChangedRange {
1957
1868
  constructor(fromA, toA, fromB, toB) {
@@ -2052,8 +1963,8 @@ class ViewUpdate {
2052
1963
  return (this.flags & 4 /* Viewport */) > 0;
2053
1964
  }
2054
1965
  /**
2055
- Indicates whether the height of an element in the editor changed
2056
- in this update.
1966
+ Indicates whether the height of a block element in the editor
1967
+ changed in this update.
2057
1968
  */
2058
1969
  get heightChanged() {
2059
1970
  return (this.flags & 2 /* Height */) > 0;
@@ -2512,7 +2423,7 @@ class DocView extends ContentView {
2512
2423
  this.view = view;
2513
2424
  this.compositionDeco = Decoration.none;
2514
2425
  this.decorations = [];
2515
- this.pluginDecorationLength = 0;
2426
+ this.dynamicDecorationMap = [];
2516
2427
  // Track a minimum width for the editor. When measuring sizes in
2517
2428
  // measureVisibleLineHeights, this is updated to point at the width
2518
2429
  // of a given element and its extent in the document. When a change
@@ -2618,7 +2529,7 @@ class DocView extends ContentView {
2618
2529
  if (!next)
2619
2530
  break;
2620
2531
  let { fromA, toA, fromB, toB } = next;
2621
- 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);
2622
2533
  let { i: toI, off: toOff } = cursor.findPos(toA, 1);
2623
2534
  let { i: fromI, off: fromOff } = cursor.findPos(fromA, -1);
2624
2535
  replaceRange(this, fromI, fromOff, toI, toOff, content, breakAtStart, openStart, openEnd);
@@ -2759,11 +2670,11 @@ class DocView extends ContentView {
2759
2670
  off = start;
2760
2671
  }
2761
2672
  }
2762
- measureVisibleLineHeights() {
2763
- let result = [], { from, to } = this.view.viewState.viewport;
2673
+ measureVisibleLineHeights(viewport) {
2674
+ let result = [], { from, to } = viewport;
2764
2675
  let contentWidth = this.view.contentDOM.clientWidth;
2765
2676
  let isWider = contentWidth > Math.max(this.view.scrollDOM.clientWidth, this.minWidth) + 1;
2766
- let widest = -1;
2677
+ let widest = -1, ltr = this.view.textDirection == Direction.LTR;
2767
2678
  for (let pos = 0, i = 0; i < this.children.length; i++) {
2768
2679
  let child = this.children[i], end = pos + child.length;
2769
2680
  if (end > to)
@@ -2776,8 +2687,7 @@ class DocView extends ContentView {
2776
2687
  let rects = last ? clientRectsFor(last) : [];
2777
2688
  if (rects.length) {
2778
2689
  let rect = rects[rects.length - 1];
2779
- let width = this.view.textDirection == Direction.LTR ? rect.right - childRect.left
2780
- : childRect.right - rect.left;
2690
+ let width = ltr ? rect.right - childRect.left : childRect.right - rect.left;
2781
2691
  if (width > widest) {
2782
2692
  widest = width;
2783
2693
  this.minWidth = contentWidth;
@@ -2791,6 +2701,10 @@ class DocView extends ContentView {
2791
2701
  }
2792
2702
  return result;
2793
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
+ }
2794
2708
  measureTextSize() {
2795
2709
  for (let child of this.children) {
2796
2710
  if (child instanceof LineView) {
@@ -2842,11 +2756,14 @@ class DocView extends ContentView {
2842
2756
  return Decoration.set(deco);
2843
2757
  }
2844
2758
  updateDeco() {
2845
- let pluginDecorations = this.view.pluginField(PluginField.decorations);
2846
- 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;
2847
2765
  return this.decorations = [
2848
- ...pluginDecorations,
2849
- ...this.view.state.facet(decorations),
2766
+ ...allDeco,
2850
2767
  this.compositionDeco,
2851
2768
  this.computeBlockGapDeco(),
2852
2769
  this.view.viewState.lineGapDeco
@@ -2861,7 +2778,7 @@ class DocView extends ContentView {
2861
2778
  rect = { left: Math.min(rect.left, other.left), top: Math.min(rect.top, other.top),
2862
2779
  right: Math.max(rect.right, other.right), bottom: Math.max(rect.bottom, other.bottom) };
2863
2780
  let mLeft = 0, mRight = 0, mTop = 0, mBottom = 0;
2864
- for (let margins of this.view.pluginField(PluginField.scrollMargins))
2781
+ for (let margins of this.view.state.facet(scrollMargins).map(f => f(this.view)))
2865
2782
  if (margins) {
2866
2783
  let { left, right, top, bottom } = margins;
2867
2784
  if (left != null)
@@ -3250,7 +3167,8 @@ function moveToLineBoundary(view, start, forward, includeWrap) {
3250
3167
  : view.coordsAtPos(start.assoc < 0 && start.head > line.from ? start.head - 1 : start.head);
3251
3168
  if (coords) {
3252
3169
  let editorRect = view.dom.getBoundingClientRect();
3253
- 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,
3254
3172
  y: (coords.top + coords.bottom) / 2 });
3255
3173
  if (pos != null)
3256
3174
  return EditorSelection.cursor(pos, forward ? -1 : 1);
@@ -3261,8 +3179,9 @@ function moveToLineBoundary(view, start, forward, includeWrap) {
3261
3179
  }
3262
3180
  function moveByChar(view, start, forward, by) {
3263
3181
  let line = view.state.doc.lineAt(start.head), spans = view.bidiSpans(line);
3182
+ let direction = view.textDirectionAt(line.from);
3264
3183
  for (let cur = start, check = null;;) {
3265
- let next = moveVisually(line, spans, view.textDirection, cur, forward), char = movedOver;
3184
+ let next = moveVisually(line, spans, direction, cur, forward), char = movedOver;
3266
3185
  if (!next) {
3267
3186
  if (line.number == (forward ? view.state.doc.lines : 1))
3268
3187
  return cur;
@@ -3305,7 +3224,7 @@ function moveVertically(view, start, forward, distance) {
3305
3224
  startY = dir < 0 ? startCoords.top : startCoords.bottom;
3306
3225
  }
3307
3226
  else {
3308
- let line = view.viewState.lineBlockAt(startPos - docTop);
3227
+ let line = view.viewState.lineBlockAt(startPos);
3309
3228
  if (goal == null)
3310
3229
  goal = Math.min(rect.right - rect.left, view.defaultCharacterWidth * (startPos - line.from));
3311
3230
  startY = (dir < 0 ? line.top : line.bottom) + docTop;
@@ -3320,7 +3239,7 @@ function moveVertically(view, start, forward, distance) {
3320
3239
  }
3321
3240
  }
3322
3241
  function skipAtoms(view, oldPos, pos) {
3323
- let atoms = view.pluginField(PluginField.atomicRanges);
3242
+ let atoms = view.state.facet(atomicRanges).map(f => f(view));
3324
3243
  for (;;) {
3325
3244
  let moved = false;
3326
3245
  for (let set of atoms) {
@@ -3368,10 +3287,10 @@ class InputState {
3368
3287
  for (let type in handlers) {
3369
3288
  let handler = handlers[type];
3370
3289
  view.contentDOM.addEventListener(type, (event) => {
3371
- if (type == "keydown" && this.keydown(view, event))
3372
- return;
3373
3290
  if (!eventBelongsToEditor(view, event) || this.ignoreDuringComposition(event))
3374
3291
  return;
3292
+ if (type == "keydown" && this.keydown(view, event))
3293
+ return;
3375
3294
  if (this.mustFlushObserver(event))
3376
3295
  view.observer.forceFlush();
3377
3296
  if (this.runCustomHandlers(type, view, event))
@@ -3382,7 +3301,6 @@ class InputState {
3382
3301
  this.registeredEvents.push(type);
3383
3302
  }
3384
3303
  this.notifiedFocused = view.hasFocus;
3385
- this.ensureHandlers(view);
3386
3304
  // On Safari adding an input event handler somehow prevents an
3387
3305
  // issue where the composition vanishes when you press enter.
3388
3306
  if (browser.safari)
@@ -3392,20 +3310,23 @@ class InputState {
3392
3310
  this.lastSelectionOrigin = origin;
3393
3311
  this.lastSelectionTime = Date.now();
3394
3312
  }
3395
- ensureHandlers(view) {
3396
- let handlers = this.customHandlers = view.pluginField(domEventHandlers);
3397
- for (let set of handlers) {
3398
- for (let type in set.handlers)
3399
- if (this.registeredEvents.indexOf(type) < 0 && type != "scroll") {
3400
- this.registeredEvents.push(type);
3401
- view.contentDOM.addEventListener(type, (event) => {
3402
- if (!eventBelongsToEditor(view, event))
3403
- return;
3404
- if (this.runCustomHandlers(type, view, event))
3405
- event.preventDefault();
3406
- });
3407
- }
3408
- }
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
+ }
3409
3330
  }
3410
3331
  runCustomHandlers(type, view, event) {
3411
3332
  for (let set of this.customHandlers) {
@@ -3439,7 +3360,7 @@ class InputState {
3439
3360
  // Must always run, even if a custom handler handled the event
3440
3361
  this.lastKeyCode = event.keyCode;
3441
3362
  this.lastKeyTime = Date.now();
3442
- if (this.screenKeyEvent(view, event))
3363
+ if (event.keyCode == 9 && Date.now() < this.lastEscPress + 2000)
3443
3364
  return true;
3444
3365
  // Chrome for Android usually doesn't fire proper key events, but
3445
3366
  // occasionally does, usually surrounded by a bunch of complicated
@@ -3483,20 +3404,12 @@ class InputState {
3483
3404
  // compositionend and keydown events are sometimes emitted in the
3484
3405
  // wrong order. The key event should still be ignored, even when
3485
3406
  // it happens after the compositionend event.
3486
- if (browser.safari && Date.now() - this.compositionEndedAt < 500) {
3407
+ if (browser.safari && Date.now() - this.compositionEndedAt < 100) {
3487
3408
  this.compositionEndedAt = 0;
3488
3409
  return true;
3489
3410
  }
3490
3411
  return false;
3491
3412
  }
3492
- screenKeyEvent(view, event) {
3493
- let protectedTab = event.keyCode == 9 && Date.now() < this.lastEscPress + 2000;
3494
- if (event.keyCode == 27)
3495
- this.lastEscPress = Date.now();
3496
- else if (modifierCodes.indexOf(event.keyCode) < 0)
3497
- this.lastEscPress = 0;
3498
- return protectedTab;
3499
- }
3500
3413
  mustFlushObserver(event) {
3501
3414
  return (event.type == "keydown" && event.keyCode != 229) ||
3502
3415
  event.type == "compositionend" && !browser.ios;
@@ -3670,6 +3583,10 @@ function doPaste(view, input) {
3670
3583
  }
3671
3584
  handlers.keydown = (view, event) => {
3672
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;
3673
3590
  };
3674
3591
  let lastTouch = 0;
3675
3592
  handlers.touchstart = (view, e) => {
@@ -3927,14 +3844,6 @@ handlers.focus = handlers.blur = view => {
3927
3844
  view.update([]);
3928
3845
  }, 10);
3929
3846
  };
3930
- handlers.beforeprint = view => {
3931
- view.viewState.printing = true;
3932
- view.requestMeasure();
3933
- setTimeout(() => {
3934
- view.viewState.printing = false;
3935
- view.requestMeasure();
3936
- }, 2000);
3937
- };
3938
3847
  function forceClearComposition(view, rapid) {
3939
3848
  if (view.docView.compositionDeco.size) {
3940
3849
  view.inputState.rapidCompositionStart = rapid;
@@ -4003,7 +3912,6 @@ class HeightOracle {
4003
3912
  constructor() {
4004
3913
  this.doc = Text.empty;
4005
3914
  this.lineWrapping = false;
4006
- this.direction = Direction.LTR;
4007
3915
  this.heightSamples = {};
4008
3916
  this.lineHeight = 14;
4009
3917
  this.charWidth = 7;
@@ -4024,8 +3932,8 @@ class HeightOracle {
4024
3932
  return lines * this.lineHeight;
4025
3933
  }
4026
3934
  setDoc(doc) { this.doc = doc; return this; }
4027
- mustRefreshForStyle(whiteSpace, direction) {
4028
- return (wrappingWhiteSpace.indexOf(whiteSpace) > -1) != this.lineWrapping || this.direction != direction;
3935
+ mustRefreshForWrapping(whiteSpace) {
3936
+ return (wrappingWhiteSpace.indexOf(whiteSpace) > -1) != this.lineWrapping;
4029
3937
  }
4030
3938
  mustRefreshForHeights(lineHeights) {
4031
3939
  let newHeight = false;
@@ -4041,13 +3949,10 @@ class HeightOracle {
4041
3949
  }
4042
3950
  return newHeight;
4043
3951
  }
4044
- refresh(whiteSpace, direction, lineHeight, charWidth, lineLength, knownHeights) {
3952
+ refresh(whiteSpace, lineHeight, charWidth, lineLength, knownHeights) {
4045
3953
  let lineWrapping = wrappingWhiteSpace.indexOf(whiteSpace) > -1;
4046
- let changed = Math.round(lineHeight) != Math.round(this.lineHeight) ||
4047
- this.lineWrapping != lineWrapping ||
4048
- this.direction != direction;
3954
+ let changed = Math.round(lineHeight) != Math.round(this.lineHeight) || this.lineWrapping != lineWrapping;
4049
3955
  this.lineWrapping = lineWrapping;
4050
- this.direction = direction;
4051
3956
  this.lineHeight = lineHeight;
4052
3957
  this.charWidth = charWidth;
4053
3958
  this.lineLength = lineLength;
@@ -4128,12 +4033,6 @@ class BlockInfo {
4128
4033
  .concat(Array.isArray(other.type) ? other.type : [other]);
4129
4034
  return new BlockInfo(this.from, this.length + other.length, this.top, this.height + other.height, detail);
4130
4035
  }
4131
- /**
4132
- FIXME remove on next breaking release @internal
4133
- */
4134
- moveY(offset) {
4135
- 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);
4136
- }
4137
4036
  }
4138
4037
  var QueryType = /*@__PURE__*/(function (QueryType) {
4139
4038
  QueryType[QueryType["ByPos"] = 0] = "ByPos";
@@ -4257,8 +4156,9 @@ class HeightMapBlock extends HeightMap {
4257
4156
  lineAt(_value, _type, doc, top, offset) {
4258
4157
  return this.blockAt(0, doc, top, offset);
4259
4158
  }
4260
- forEachLine(_from, _to, doc, top, offset, f) {
4261
- 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));
4262
4162
  }
4263
4163
  updateHeight(oracle, offset = 0, _force = false, measured) {
4264
4164
  if (measured && measured.from <= offset && measured.more)
@@ -4689,6 +4589,11 @@ function visiblePixelRange(dom, paddingTop) {
4689
4589
  return { left: left - rect.left, right: Math.max(left, right) - rect.left,
4690
4590
  top: top - (rect.top + paddingTop), bottom: Math.max(top, bottom) - (rect.top + paddingTop) };
4691
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
+ }
4692
4597
  // Line gaps are placeholder widgets used to hide pieces of overlong
4693
4598
  // lines within the viewport, as a kludge to keep the editor
4694
4599
  // responsive when a ridiculously long line is loaded into it.
@@ -4754,6 +4659,7 @@ class ViewState {
4754
4659
  // Flag set when editor content was redrawn, so that the next
4755
4660
  // measure stage knows it must read DOM layout
4756
4661
  this.mustMeasureContent = true;
4662
+ this.defaultTextDirection = Direction.RTL;
4757
4663
  this.visibleRanges = [];
4758
4664
  // Cursor 'assoc' is only significant when the cursor is on a line
4759
4665
  // wrap point, where it must stick to the character that it is
@@ -4764,7 +4670,8 @@ class ViewState {
4764
4670
  // boundary and, if so, reset it to make sure it is positioned in
4765
4671
  // the right place.
4766
4672
  this.mustEnforceCursorAssoc = false;
4767
- 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)]);
4768
4675
  this.viewport = this.getViewport(0, null);
4769
4676
  this.updateViewportLines();
4770
4677
  this.updateForViewport();
@@ -4792,13 +4699,13 @@ class ViewState {
4792
4699
  });
4793
4700
  }
4794
4701
  update(update, scrollTarget = null) {
4795
- let prev = this.state;
4796
4702
  this.state = update.state;
4797
- let newDeco = this.state.facet(decorations);
4703
+ let prevDeco = this.stateDeco;
4704
+ this.stateDeco = this.state.facet(decorations).filter(d => typeof d != "function");
4798
4705
  let contentChanges = update.changedRanges;
4799
- 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)));
4800
4707
  let prevHeight = this.heightMap.height;
4801
- 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);
4802
4709
  if (this.heightMap.height != prevHeight)
4803
4710
  update.flags |= 2 /* Height */;
4804
4711
  let viewport = heightChanges.length ? this.mapViewport(this.viewport, update.changes) : this.viewport;
@@ -4823,8 +4730,9 @@ class ViewState {
4823
4730
  measure(view) {
4824
4731
  let dom = view.contentDOM, style = window.getComputedStyle(dom);
4825
4732
  let oracle = this.heightOracle;
4826
- let whiteSpace = style.whiteSpace, direction = style.direction == "rtl" ? Direction.RTL : Direction.LTR;
4827
- 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);
4828
4736
  let measureContent = refresh || this.mustMeasureContent || this.contentDOMHeight != dom.clientHeight;
4829
4737
  let result = 0, bias = 0;
4830
4738
  if (this.editorWidth != view.scrollDOM.clientWidth) {
@@ -4845,8 +4753,7 @@ class ViewState {
4845
4753
  }
4846
4754
  }
4847
4755
  // Pixel viewport
4848
- let pixelViewport = this.printing ? { top: -1e8, bottom: 1e8, left: -1e8, right: 1e8 }
4849
- : visiblePixelRange(dom, this.paddingTop);
4756
+ let pixelViewport = (this.printing ? fullPixelRange : visiblePixelRange)(dom, this.paddingTop);
4850
4757
  let dTop = pixelViewport.top - this.pixelViewport.top, dBottom = pixelViewport.bottom - this.pixelViewport.bottom;
4851
4758
  this.pixelViewport = pixelViewport;
4852
4759
  let inView = this.pixelViewport.bottom > this.pixelViewport.top && this.pixelViewport.right > this.pixelViewport.left;
@@ -4864,12 +4771,12 @@ class ViewState {
4864
4771
  result |= 8 /* Geometry */;
4865
4772
  }
4866
4773
  if (measureContent) {
4867
- let lineHeights = view.docView.measureVisibleLineHeights();
4774
+ let lineHeights = view.docView.measureVisibleLineHeights(this.viewport);
4868
4775
  if (oracle.mustRefreshForHeights(lineHeights))
4869
4776
  refresh = true;
4870
4777
  if (refresh || oracle.lineWrapping && Math.abs(contentWidth - this.contentDOMWidth) > oracle.charWidth) {
4871
4778
  let { lineHeight, charWidth } = view.docView.measureTextSize();
4872
- refresh = oracle.refresh(whiteSpace, direction, lineHeight, charWidth, contentWidth / charWidth, lineHeights);
4779
+ refresh = oracle.refresh(whiteSpace, lineHeight, charWidth, contentWidth / charWidth, lineHeights);
4873
4780
  if (refresh) {
4874
4781
  view.docView.minWidth = 0;
4875
4782
  result |= 8 /* Geometry */;
@@ -4880,7 +4787,10 @@ class ViewState {
4880
4787
  else if (dTop < 0 && dBottom < 0)
4881
4788
  bias = Math.min(dTop, dBottom);
4882
4789
  oracle.heightChanged = false;
4883
- 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
+ }
4884
4794
  if (oracle.heightChanged)
4885
4795
  result |= 2 /* Height */;
4886
4796
  }
@@ -4966,12 +4876,12 @@ class ViewState {
4966
4876
  ensureLineGaps(current) {
4967
4877
  let gaps = [];
4968
4878
  // This won't work at all in predominantly right-to-left text.
4969
- if (this.heightOracle.direction != Direction.LTR)
4879
+ if (this.defaultTextDirection != Direction.LTR)
4970
4880
  return gaps;
4971
4881
  for (let line of this.viewportLines) {
4972
4882
  if (line.length < 4000 /* DoubleMargin */)
4973
4883
  continue;
4974
- let structure = lineStructure(line.from, line.to, this.state);
4884
+ let structure = lineStructure(line.from, line.to, this.stateDeco);
4975
4885
  if (structure.total < 4000 /* DoubleMargin */)
4976
4886
  continue;
4977
4887
  let viewFrom, viewTo;
@@ -5022,7 +4932,7 @@ class ViewState {
5022
4932
  }
5023
4933
  }
5024
4934
  computeVisibleRanges() {
5025
- let deco = this.state.facet(decorations);
4935
+ let deco = this.stateDeco;
5026
4936
  if (this.lineGaps.length)
5027
4937
  deco = deco.concat(this.lineGapDeco);
5028
4938
  let ranges = [];
@@ -5058,9 +4968,9 @@ class Viewport {
5058
4968
  this.to = to;
5059
4969
  }
5060
4970
  }
5061
- function lineStructure(from, to, state) {
4971
+ function lineStructure(from, to, stateDeco) {
5062
4972
  let ranges = [], pos = from, total = 0;
5063
- RangeSet.spans(state.facet(decorations), from, to, {
4973
+ RangeSet.spans(stateDeco, from, to, {
5064
4974
  span() { },
5065
4975
  point(from, to) {
5066
4976
  if (from > pos) {
@@ -5193,7 +5103,7 @@ function buildTheme(main, spec, scopes) {
5193
5103
  }
5194
5104
  });
5195
5105
  }
5196
- const baseTheme = /*@__PURE__*/buildTheme("." + baseThemeID, {
5106
+ const baseTheme$1 = /*@__PURE__*/buildTheme("." + baseThemeID, {
5197
5107
  "&.cm-editor": {
5198
5108
  position: "relative !important",
5199
5109
  boxSizing: "border-box",
@@ -5298,6 +5208,65 @@ const baseTheme = /*@__PURE__*/buildTheme("." + baseThemeID, {
5298
5208
  "&dark .cm-activeLine": { backgroundColor: "#223039" },
5299
5209
  "&light .cm-specialChar": { color: "red" },
5300
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
+ },
5301
5270
  ".cm-tab": {
5302
5271
  display: "inline-block",
5303
5272
  overflow: "hidden",
@@ -5423,6 +5392,7 @@ class DOMObserver {
5423
5392
  });
5424
5393
  this.resize.observe(view.scrollDOM);
5425
5394
  }
5395
+ window.addEventListener("beforeprint", this.onPrint = this.onPrint.bind(this));
5426
5396
  this.start();
5427
5397
  window.addEventListener("scroll", this.onScroll = this.onScroll.bind(this));
5428
5398
  if (typeof IntersectionObserver == "function") {
@@ -5457,6 +5427,14 @@ class DOMObserver {
5457
5427
  this.view.requestMeasure();
5458
5428
  }, 50);
5459
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
+ }
5460
5438
  updateGaps(gaps) {
5461
5439
  if (this.gapIntersection && (gaps.length != this.gaps.length || this.gaps.some((g, i) => g != gaps[i]))) {
5462
5440
  this.gapIntersection.disconnect();
@@ -5674,6 +5652,7 @@ class DOMObserver {
5674
5652
  dom.removeEventListener("scroll", this.onScroll);
5675
5653
  window.removeEventListener("scroll", this.onScroll);
5676
5654
  window.removeEventListener("resize", this.onResize);
5655
+ window.removeEventListener("beforeprint", this.onPrint);
5677
5656
  this.dom.ownerDocument.removeEventListener("selectionchange", this.onSelectionChange);
5678
5657
  clearTimeout(this.parentCheck);
5679
5658
  clearTimeout(this.resizeTimeout);
@@ -5745,7 +5724,7 @@ function applyDOMChange(view, start, end, typeOver) {
5745
5724
  diff.toB == diff.from + 2 && reader.text.slice(diff.from, diff.toB) == LineBreakPlaceholder + LineBreakPlaceholder)
5746
5725
  diff.toB--;
5747
5726
  change = { from: from + diff.from, to: from + diff.toA,
5748
- 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)) };
5749
5728
  }
5750
5729
  newSel = selectionFromPoints(selPoints, from);
5751
5730
  }
@@ -5936,9 +5915,9 @@ transactions for editing actions.
5936
5915
  */
5937
5916
  class EditorView {
5938
5917
  /**
5939
- Construct a new view. You'll usually want to put `view.dom` into
5940
- your document after creating a view, so that the user can see
5941
- 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.
5942
5921
  */
5943
5922
  constructor(
5944
5923
  /**
@@ -5989,6 +5968,7 @@ class EditorView {
5989
5968
  this.measure();
5990
5969
  });
5991
5970
  this.inputState = new InputState(this);
5971
+ this.inputState.ensureHandlers(this, this.plugins);
5992
5972
  this.docView = new DocView(this);
5993
5973
  this.mountStyles();
5994
5974
  this.updateAttrs();
@@ -6076,14 +6056,9 @@ class EditorView {
6076
6056
  let { main } = tr.state.selection;
6077
6057
  scrollTarget = new ScrollTarget(main.empty ? main : EditorSelection.cursor(main.head, main.head > main.anchor ? -1 : 1));
6078
6058
  }
6079
- for (let e of tr.effects) {
6080
- if (e.is(scrollTo))
6081
- scrollTarget = new ScrollTarget(e.value);
6082
- else if (e.is(centerOn))
6083
- scrollTarget = new ScrollTarget(e.value, "center");
6084
- else if (e.is(scrollIntoView))
6059
+ for (let e of tr.effects)
6060
+ if (e.is(scrollIntoView))
6085
6061
  scrollTarget = e.value;
6086
- }
6087
6062
  }
6088
6063
  this.viewState.update(update, scrollTarget);
6089
6064
  this.bidiCache = CachedOrder.update(this.bidiCache, update.changes);
@@ -6134,7 +6109,7 @@ class EditorView {
6134
6109
  for (let plugin of this.plugins)
6135
6110
  plugin.update(this);
6136
6111
  this.docView = new DocView(this);
6137
- this.inputState.ensureHandlers(this);
6112
+ this.inputState.ensureHandlers(this, this.plugins);
6138
6113
  this.mountStyles();
6139
6114
  this.updateAttrs();
6140
6115
  this.bidiCache = [];
@@ -6166,7 +6141,7 @@ class EditorView {
6166
6141
  plugin.destroy(this);
6167
6142
  this.plugins = newPlugins;
6168
6143
  this.pluginMap.clear();
6169
- this.inputState.ensureHandlers(this);
6144
+ this.inputState.ensureHandlers(this, this.plugins);
6170
6145
  }
6171
6146
  else {
6172
6147
  for (let p of this.plugins)
@@ -6304,7 +6279,7 @@ class EditorView {
6304
6279
  }
6305
6280
  mountStyles() {
6306
6281
  this.styleModules = this.state.facet(styleModule);
6307
- StyleModule.mount(this.root, this.styleModules.concat(baseTheme).reverse());
6282
+ StyleModule.mount(this.root, this.styleModules.concat(baseTheme$1).reverse());
6308
6283
  }
6309
6284
  readMeasured() {
6310
6285
  if (this.updateState == 2 /* Updating */)
@@ -6335,16 +6310,6 @@ class EditorView {
6335
6310
  }
6336
6311
  }
6337
6312
  /**
6338
- Collect all values provided by the active plugins for a given
6339
- field.
6340
- */
6341
- pluginField(field) {
6342
- let result = [];
6343
- for (let plugin of this.plugins)
6344
- plugin.update(this).takeField(field, result);
6345
- return result;
6346
- }
6347
- /**
6348
6313
  Get the value of a specific plugin, if present. Note that
6349
6314
  plugins that crash can be dropped from a view, so even when you
6350
6315
  know you registered a given plugin, it is recommended to check
@@ -6371,23 +6336,6 @@ class EditorView {
6371
6336
  return { top: this.viewState.paddingTop, bottom: this.viewState.paddingBottom };
6372
6337
  }
6373
6338
  /**
6374
- Find the line or block widget at the given vertical position.
6375
-
6376
- By default, this position is interpreted as a screen position,
6377
- meaning `docTop` is set to the DOM top position of the editor
6378
- content (forcing a layout). You can pass a different `docTop`
6379
- value—for example 0 to interpret `height` as a document-relative
6380
- position, or a precomputed document top
6381
- (`view.contentDOM.getBoundingClientRect().top`) to limit layout
6382
- queries.
6383
-
6384
- *Deprecated: use `elementAtHeight` instead.*
6385
- */
6386
- blockAtHeight(height, docTop) {
6387
- let top = ensureTop(docTop, this);
6388
- return this.elementAtHeight(height - top).moveY(top);
6389
- }
6390
- /**
6391
6339
  Find the text line or block widget at the given vertical
6392
6340
  position (which is interpreted as relative to the [top of the
6393
6341
  document](https://codemirror.net/6/docs/ref/#view.EditorView.documentTop)
@@ -6397,23 +6345,6 @@ class EditorView {
6397
6345
  return this.viewState.elementAtHeight(height);
6398
6346
  }
6399
6347
  /**
6400
- Find information for the visual line (see
6401
- [`visualLineAt`](https://codemirror.net/6/docs/ref/#view.EditorView.visualLineAt)) at the given
6402
- vertical position. The resulting block info might hold another
6403
- array of block info structs in its `type` field if this line
6404
- consists of more than one block.
6405
-
6406
- Defaults to treating `height` as a screen position. See
6407
- [`blockAtHeight`](https://codemirror.net/6/docs/ref/#view.EditorView.blockAtHeight) for the
6408
- interpretation of the `docTop` parameter.
6409
-
6410
- *Deprecated: use `lineBlockAtHeight` instead.*
6411
- */
6412
- visualLineAtHeight(height, docTop) {
6413
- let top = ensureTop(docTop, this);
6414
- return this.lineBlockAtHeight(height - top).moveY(top);
6415
- }
6416
- /**
6417
6348
  Find the line block (see
6418
6349
  [`lineBlockAt`](https://codemirror.net/6/docs/ref/#view.EditorView.lineBlockAt) at the given
6419
6350
  height.
@@ -6423,19 +6354,6 @@ class EditorView {
6423
6354
  return this.viewState.lineBlockAtHeight(height);
6424
6355
  }
6425
6356
  /**
6426
- Iterate over the height information of the visual lines in the
6427
- viewport. The heights of lines are reported relative to the
6428
- given document top, which defaults to the screen position of the
6429
- document (forcing a layout).
6430
-
6431
- *Deprecated: use `viewportLineBlocks` instead.*
6432
- */
6433
- viewportLines(f, docTop) {
6434
- let top = ensureTop(docTop, this);
6435
- for (let line of this.viewportLineBlocks)
6436
- f(line.moveY(top));
6437
- }
6438
- /**
6439
6357
  Get the extent and vertical position of all [line
6440
6358
  blocks](https://codemirror.net/6/docs/ref/#view.EditorView.lineBlockAt) in the viewport. Positions
6441
6359
  are relative to the [top of the
@@ -6445,24 +6363,9 @@ class EditorView {
6445
6363
  return this.viewState.viewportLines;
6446
6364
  }
6447
6365
  /**
6448
- Find the extent and height of the visual line (a range delimited
6449
- on both sides by either non-[hidden](https://codemirror.net/6/docs/ref/#view.Decoration^range)
6450
- line breaks, or the start/end of the document) at the given position.
6451
-
6452
- Vertical positions are computed relative to the `docTop`
6453
- argument, which defaults to 0 for this method. You can pass
6454
- `view.contentDOM.getBoundingClientRect().top` here to get screen
6455
- coordinates.
6456
-
6457
- *Deprecated: use `lineBlockAt` instead.*
6458
- */
6459
- visualLineAt(pos, docTop = 0) {
6460
- return this.lineBlockAt(pos).moveY(docTop + this.viewState.paddingTop);
6461
- }
6462
- /**
6463
6366
  Find the line block around the given document position. A line
6464
6367
  block is a range delimited on both sides by either a
6465
- 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
6466
6369
  start/end of the document. It will usually just hold a line of
6467
6370
  text, but may be broken into multiple textblocks by block
6468
6371
  widgets.
@@ -6478,13 +6381,13 @@ class EditorView {
6478
6381
  }
6479
6382
  /**
6480
6383
  Move a cursor position by [grapheme
6481
- cluster](https://codemirror.net/6/docs/ref/#text.findClusterBreak). `forward` determines whether
6482
- the motion is away from the line start, or towards it. Motion in
6483
- bidirectional text is in visual order, in the editor's [text
6484
- direction](https://codemirror.net/6/docs/ref/#view.EditorView.textDirection). When the start
6485
- position was the last one on the line, the returned position
6486
- will be across the line break. If there is no further line, the
6487
- 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.
6488
6391
 
6489
6392
  By default, this method moves over a single cluster. The
6490
6393
  optional `by` argument can be used to move across more. It will
@@ -6529,10 +6432,6 @@ class EditorView {
6529
6432
  moveVertically(start, forward, distance) {
6530
6433
  return skipAtoms(this, start, moveVertically(this, start, forward, distance));
6531
6434
  }
6532
- // FIXME remove on next major version
6533
- scrollPosIntoView(pos) {
6534
- this.dispatch({ effects: scrollTo.of(EditorSelection.cursor(pos)) });
6535
- }
6536
6435
  /**
6537
6436
  Find the DOM parent node and offset (child offset if `node` is
6538
6437
  an element, character offset when it is a text node) at the
@@ -6588,9 +6487,25 @@ class EditorView {
6588
6487
  /**
6589
6488
  The text direction
6590
6489
  ([`direction`](https://developer.mozilla.org/en-US/docs/Web/CSS/direction)
6591
- 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.
6592
6501
  */
6593
- 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
+ }
6594
6509
  /**
6595
6510
  Whether this editor [wraps lines](https://codemirror.net/6/docs/ref/#view.EditorView.lineWrapping)
6596
6511
  (as determined by the
@@ -6609,11 +6524,11 @@ class EditorView {
6609
6524
  bidiSpans(line) {
6610
6525
  if (line.length > MaxBidiLine)
6611
6526
  return trivialOrder(line.length);
6612
- let dir = this.textDirection;
6527
+ let dir = this.textDirectionAt(line.from);
6613
6528
  for (let entry of this.bidiCache)
6614
6529
  if (entry.from == line.from && entry.dir == dir)
6615
6530
  return entry.order;
6616
- let order = computeOrder(line.text, this.textDirection);
6531
+ let order = computeOrder(line.text, dir);
6617
6532
  this.bidiCache.push(new CachedOrder(line.from, line.to, dir, order));
6618
6533
  return order;
6619
6534
  }
@@ -6664,16 +6579,16 @@ class EditorView {
6664
6579
  return scrollIntoView.of(new ScrollTarget(typeof pos == "number" ? EditorSelection.cursor(pos) : pos, options.y, options.x, options.yMargin, options.xMargin));
6665
6580
  }
6666
6581
  /**
6667
- Facet that can be used to add DOM event handlers. The value
6668
- should be an object mapping event names to handler functions. The
6669
- first such function to return true will be assumed to have handled
6670
- that event, and no other handlers or built-in behavior will be
6671
- activated for it.
6672
- These are registered on the [content
6673
- element](https://codemirror.net/6/docs/ref/#view.EditorView.contentDOM), except for `scroll`
6674
- handlers, which will be called any time the editor's [scroll
6675
- element](https://codemirror.net/6/docs/ref/#view.EditorView.scrollDOM) or one of its parent nodes
6676
- 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.
6677
6592
  */
6678
6593
  static domEventHandlers(handlers) {
6679
6594
  return ViewPlugin.define(() => ({}), { eventHandlers: handlers });
@@ -6715,20 +6630,6 @@ class EditorView {
6715
6630
  }
6716
6631
  }
6717
6632
  /**
6718
- Effect that can be [added](https://codemirror.net/6/docs/ref/#state.TransactionSpec.effects) to a
6719
- transaction to make it scroll the given range into view.
6720
-
6721
- *Deprecated*. Use [`scrollIntoView`](https://codemirror.net/6/docs/ref/#view.EditorView^scrollIntoView) instead.
6722
- */
6723
- EditorView.scrollTo = scrollTo;
6724
- /**
6725
- Effect that makes the editor scroll the given range to the
6726
- center of the visible view.
6727
-
6728
- *Deprecated*. Use [`scrollIntoView`](https://codemirror.net/6/docs/ref/#view.EditorView^scrollIntoView) instead.
6729
- */
6730
- EditorView.centerOn = centerOn;
6731
- /**
6732
6633
  Facet to add a [style
6733
6634
  module](https://github.com/marijnh/style-mod#documentation) to
6734
6635
  an editor view. The view will ensure that the module is
@@ -6745,6 +6646,13 @@ called and the default behavior is prevented.
6745
6646
  */
6746
6647
  EditorView.inputHandler = inputHandler;
6747
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
+ /**
6748
6656
  Allows you to provide a function that should be called when the
6749
6657
  library catches an exception from an extension (mostly from view
6750
6658
  plugins, but may be used by other extensions to route exceptions
@@ -6760,9 +6668,9 @@ EditorView.updateListener = updateListener;
6760
6668
  /**
6761
6669
  Facet that controls whether the editor content DOM is editable.
6762
6670
  When its highest-precedence value is `false`, the element will
6763
- not longer have its `contenteditable` attribute set. (Note that
6764
- this doesn't affect API calls that change the editor content,
6765
- 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
6766
6674
  [`readOnly`](https://codemirror.net/6/docs/ref/#state.EditorState.readOnly) facet for that.)
6767
6675
  */
6768
6676
  EditorView.editable = editable;
@@ -6781,18 +6689,45 @@ the drag should move the content.
6781
6689
  */
6782
6690
  EditorView.dragMovesSelection = dragMovesSelection$1;
6783
6691
  /**
6784
- Facet used to configure whether a given selecting click adds
6785
- 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.
6786
6696
  */
6787
6697
  EditorView.clickAddsSelectionRange = clickAddsSelectionRange;
6788
6698
  /**
6789
6699
  A facet that determines which [decorations](https://codemirror.net/6/docs/ref/#view.Decoration)
6790
- are shown in the view. See also [view
6791
- plugins](https://codemirror.net/6/docs/ref/#view.EditorView^decorations), which have a separate
6792
- 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.
6793
6708
  */
6794
6709
  EditorView.decorations = decorations;
6795
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
+ /**
6796
6731
  This facet records whether a dark theme is active. The extension
6797
6732
  returned by [`theme`](https://codemirror.net/6/docs/ref/#view.EditorView^theme) automatically
6798
6733
  includes an instance of this when the `dark` option is set to
@@ -6825,10 +6760,6 @@ search match).
6825
6760
  EditorView.announce = /*@__PURE__*/StateEffect.define();
6826
6761
  // Maximum line length for which we compute accurate bidi info
6827
6762
  const MaxBidiLine = 4096;
6828
- // FIXME remove this and its callers on next breaking release
6829
- function ensureTop(given, view) {
6830
- return (given == null ? view.contentDOM.getBoundingClientRect().top : given) + view.viewState.paddingTop;
6831
- }
6832
6763
  const BadMeasure = {};
6833
6764
  class CachedOrder {
6834
6765
  constructor(from, to, dir, order) {
@@ -6931,7 +6862,7 @@ function getKeymap(state) {
6931
6862
  }
6932
6863
  /**
6933
6864
  Run the key handlers registered for a given scope. The event
6934
- object should be `"keydown"` event. Returns true if any of the
6865
+ object should be a `"keydown"` event. Returns true if any of the
6935
6866
  handlers handled it.
6936
6867
  */
6937
6868
  function runScopeHandlers(view, event, scope) {
@@ -7708,9 +7639,1297 @@ function placeholder(content) {
7708
7639
  }, { decorations: v => v.decorations });
7709
7640
  }
7710
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
+ class HoverTooltipHost {
8079
+ constructor(view) {
8080
+ this.view = view;
8081
+ this.mounted = false;
8082
+ this.dom = document.createElement("div");
8083
+ this.dom.classList.add("cm-tooltip-hover");
8084
+ this.manager = new TooltipViewManager(view, showHoverTooltip, t => this.createHostedView(t));
8085
+ }
8086
+ // Needs to be static so that host tooltip instances always match
8087
+ static create(view) {
8088
+ return new HoverTooltipHost(view);
8089
+ }
8090
+ createHostedView(tooltip) {
8091
+ let hostedView = tooltip.create(this.view);
8092
+ hostedView.dom.classList.add("cm-tooltip-section");
8093
+ this.dom.appendChild(hostedView.dom);
8094
+ if (this.mounted && hostedView.mount)
8095
+ hostedView.mount(this.view);
8096
+ return hostedView;
8097
+ }
8098
+ mount(view) {
8099
+ for (let hostedView of this.manager.tooltipViews) {
8100
+ if (hostedView.mount)
8101
+ hostedView.mount(view);
8102
+ }
8103
+ this.mounted = true;
8104
+ }
8105
+ positioned() {
8106
+ for (let hostedView of this.manager.tooltipViews) {
8107
+ if (hostedView.positioned)
8108
+ hostedView.positioned();
8109
+ }
8110
+ }
8111
+ update(update) {
8112
+ this.manager.update(update);
8113
+ }
8114
+ }
8115
+ const showHoverTooltipHost = /*@__PURE__*/showTooltip.compute([showHoverTooltip], state => {
8116
+ let tooltips = state.facet(showHoverTooltip).filter(t => t);
8117
+ if (tooltips.length === 0)
8118
+ return null;
8119
+ return {
8120
+ pos: Math.min(...tooltips.map(t => t.pos)),
8121
+ end: Math.max(...tooltips.filter(t => t.end != null).map(t => t.end)),
8122
+ create: HoverTooltipHost.create,
8123
+ above: tooltips[0].above,
8124
+ arrow: tooltips.some(t => t.arrow),
8125
+ };
8126
+ });
8127
+ class HoverPlugin {
8128
+ constructor(view, source, field, setHover, hoverTime) {
8129
+ this.view = view;
8130
+ this.source = source;
8131
+ this.field = field;
8132
+ this.setHover = setHover;
8133
+ this.hoverTime = hoverTime;
8134
+ this.hoverTimeout = -1;
8135
+ this.restartTimeout = -1;
8136
+ this.pending = null;
8137
+ this.lastMove = { x: 0, y: 0, target: view.dom, time: 0 };
8138
+ this.checkHover = this.checkHover.bind(this);
8139
+ view.dom.addEventListener("mouseleave", this.mouseleave = this.mouseleave.bind(this));
8140
+ view.dom.addEventListener("mousemove", this.mousemove = this.mousemove.bind(this));
8141
+ }
8142
+ update() {
8143
+ if (this.pending) {
8144
+ this.pending = null;
8145
+ clearTimeout(this.restartTimeout);
8146
+ this.restartTimeout = setTimeout(() => this.startHover(), 20);
8147
+ }
8148
+ }
8149
+ get active() {
8150
+ return this.view.state.field(this.field);
8151
+ }
8152
+ checkHover() {
8153
+ this.hoverTimeout = -1;
8154
+ if (this.active)
8155
+ return;
8156
+ let hovered = Date.now() - this.lastMove.time;
8157
+ if (hovered < this.hoverTime)
8158
+ this.hoverTimeout = setTimeout(this.checkHover, this.hoverTime - hovered);
8159
+ else
8160
+ this.startHover();
8161
+ }
8162
+ startHover() {
8163
+ var _a;
8164
+ clearTimeout(this.restartTimeout);
8165
+ let { lastMove } = this;
8166
+ let pos = this.view.contentDOM.contains(lastMove.target) ? this.view.posAtCoords(lastMove) : null;
8167
+ if (pos == null)
8168
+ return;
8169
+ let posCoords = this.view.coordsAtPos(pos);
8170
+ if (posCoords == null || lastMove.y < posCoords.top || lastMove.y > posCoords.bottom ||
8171
+ lastMove.x < posCoords.left - this.view.defaultCharacterWidth ||
8172
+ lastMove.x > posCoords.right + this.view.defaultCharacterWidth)
8173
+ return;
8174
+ let bidi = this.view.bidiSpans(this.view.state.doc.lineAt(pos)).find(s => s.from <= pos && s.to >= pos);
8175
+ let rtl = bidi && bidi.dir == Direction.RTL ? -1 : 1;
8176
+ let open = this.source(this.view, pos, (lastMove.x < posCoords.left ? -rtl : rtl));
8177
+ if ((_a = open) === null || _a === void 0 ? void 0 : _a.then) {
8178
+ let pending = this.pending = { pos };
8179
+ open.then(result => {
8180
+ if (this.pending == pending) {
8181
+ this.pending = null;
8182
+ if (result)
8183
+ this.view.dispatch({ effects: this.setHover.of(result) });
8184
+ }
8185
+ }, e => logException(this.view.state, e, "hover tooltip"));
8186
+ }
8187
+ else if (open) {
8188
+ this.view.dispatch({ effects: this.setHover.of(open) });
8189
+ }
8190
+ }
8191
+ mousemove(event) {
8192
+ var _a;
8193
+ this.lastMove = { x: event.clientX, y: event.clientY, target: event.target, time: Date.now() };
8194
+ if (this.hoverTimeout < 0)
8195
+ this.hoverTimeout = setTimeout(this.checkHover, this.hoverTime);
8196
+ let tooltip = this.active;
8197
+ if (tooltip && !isInTooltip(this.lastMove.target) || this.pending) {
8198
+ let { pos } = tooltip || this.pending, end = (_a = tooltip === null || tooltip === void 0 ? void 0 : tooltip.end) !== null && _a !== void 0 ? _a : pos;
8199
+ if ((pos == end ? this.view.posAtCoords(this.lastMove) != pos
8200
+ : !isOverRange(this.view, pos, end, event.clientX, event.clientY, 6 /* MaxDist */))) {
8201
+ this.view.dispatch({ effects: this.setHover.of(null) });
8202
+ this.pending = null;
8203
+ }
8204
+ }
8205
+ }
8206
+ mouseleave() {
8207
+ clearTimeout(this.hoverTimeout);
8208
+ this.hoverTimeout = -1;
8209
+ if (this.active)
8210
+ this.view.dispatch({ effects: this.setHover.of(null) });
8211
+ }
8212
+ destroy() {
8213
+ clearTimeout(this.hoverTimeout);
8214
+ this.view.dom.removeEventListener("mouseleave", this.mouseleave);
8215
+ this.view.dom.removeEventListener("mousemove", this.mousemove);
8216
+ }
8217
+ }
8218
+ function isInTooltip(elt) {
8219
+ for (let cur = elt; cur; cur = cur.parentNode)
8220
+ if (cur.nodeType == 1 && cur.classList.contains("cm-tooltip"))
8221
+ return true;
8222
+ return false;
8223
+ }
8224
+ function isOverRange(view, from, to, x, y, margin) {
8225
+ let range = document.createRange();
8226
+ let fromDOM = view.domAtPos(from), toDOM = view.domAtPos(to);
8227
+ range.setEnd(toDOM.node, toDOM.offset);
8228
+ range.setStart(fromDOM.node, fromDOM.offset);
8229
+ let rects = range.getClientRects();
8230
+ range.detach();
8231
+ for (let i = 0; i < rects.length; i++) {
8232
+ let rect = rects[i];
8233
+ let dist = Math.max(rect.top - y, y - rect.bottom, rect.left - x, x - rect.right);
8234
+ if (dist <= margin)
8235
+ return true;
8236
+ }
8237
+ return false;
8238
+ }
8239
+ /**
8240
+ Set up a hover tooltip, which shows up when the pointer hovers
8241
+ over ranges of text. The callback is called when the mouse hovers
8242
+ over the document text. It should, if there is a tooltip
8243
+ associated with position `pos`, return the tooltip description
8244
+ (either directly or in a promise). The `side` argument indicates
8245
+ on which side of the position the pointer is—it will be -1 if the
8246
+ pointer is before the position, 1 if after the position.
8247
+
8248
+ Note that all hover tooltips are hosted within a single tooltip
8249
+ container element. This allows multiple tooltips over the same
8250
+ range to be "merged" together without overlapping.
8251
+ */
8252
+ function hoverTooltip(source, options = {}) {
8253
+ let setHover = StateEffect.define();
8254
+ let hoverState = StateField.define({
8255
+ create() { return null; },
8256
+ update(value, tr) {
8257
+ if (value && (options.hideOnChange && (tr.docChanged || tr.selection)))
8258
+ return null;
8259
+ if (value && tr.docChanged) {
8260
+ let newPos = tr.changes.mapPos(value.pos, -1, MapMode.TrackDel);
8261
+ if (newPos == null)
8262
+ return null;
8263
+ let copy = Object.assign(Object.create(null), value);
8264
+ copy.pos = newPos;
8265
+ if (value.end != null)
8266
+ copy.end = tr.changes.mapPos(value.end);
8267
+ value = copy;
8268
+ }
8269
+ for (let effect of tr.effects) {
8270
+ if (effect.is(setHover))
8271
+ value = effect.value;
8272
+ if (effect.is(closeHoverTooltipEffect))
8273
+ value = null;
8274
+ }
8275
+ return value;
8276
+ },
8277
+ provide: f => showHoverTooltip.from(f)
8278
+ });
8279
+ return [
8280
+ hoverState,
8281
+ ViewPlugin.define(view => new HoverPlugin(view, source, hoverState, setHover, options.hoverTime || 300 /* Time */)),
8282
+ showHoverTooltipHost
8283
+ ];
8284
+ }
8285
+ /**
8286
+ Get the active tooltip view for a given tooltip, if available.
8287
+ */
8288
+ function getTooltip(view, tooltip) {
8289
+ let plugin = view.plugin(tooltipPlugin);
8290
+ if (!plugin)
8291
+ return null;
8292
+ let found = plugin.manager.tooltips.indexOf(tooltip);
8293
+ return found < 0 ? null : plugin.manager.tooltipViews[found];
8294
+ }
8295
+ /**
8296
+ Returns true if any hover tooltips are currently active.
8297
+ */
8298
+ function hasHoverTooltips(state) {
8299
+ return state.facet(showHoverTooltip).some(x => x);
8300
+ }
8301
+ const closeHoverTooltipEffect = /*@__PURE__*/StateEffect.define();
8302
+ /**
8303
+ Transaction effect that closes all hover tooltips.
8304
+ */
8305
+ const closeHoverTooltips = /*@__PURE__*/closeHoverTooltipEffect.of(null);
8306
+ /**
8307
+ Tell the tooltip extension to recompute the position of the active
8308
+ tooltips. This can be useful when something happens (such as a
8309
+ re-positioning or CSS change affecting the editor) that could
8310
+ invalidate the existing tooltip positions.
8311
+ */
8312
+ function repositionTooltips(view) {
8313
+ var _a;
8314
+ (_a = view.plugin(tooltipPlugin)) === null || _a === void 0 ? void 0 : _a.maybeMeasure();
8315
+ }
8316
+
8317
+ const panelConfig = /*@__PURE__*/Facet.define({
8318
+ combine(configs) {
8319
+ let topContainer, bottomContainer;
8320
+ for (let c of configs) {
8321
+ topContainer = topContainer || c.topContainer;
8322
+ bottomContainer = bottomContainer || c.bottomContainer;
8323
+ }
8324
+ return { topContainer, bottomContainer };
8325
+ }
8326
+ });
8327
+ /**
8328
+ Configures the panel-managing extension.
8329
+ */
8330
+ function panels(config) {
8331
+ return config ? [panelConfig.of(config)] : [];
8332
+ }
8333
+ /**
8334
+ Get the active panel created by the given constructor, if any.
8335
+ This can be useful when you need access to your panels' DOM
8336
+ structure.
8337
+ */
8338
+ function getPanel(view, panel) {
8339
+ let plugin = view.plugin(panelPlugin);
8340
+ let index = plugin ? plugin.specs.indexOf(panel) : -1;
8341
+ return index > -1 ? plugin.panels[index] : null;
8342
+ }
8343
+ const panelPlugin = /*@__PURE__*/ViewPlugin.fromClass(class {
8344
+ constructor(view) {
8345
+ this.input = view.state.facet(showPanel);
8346
+ this.specs = this.input.filter(s => s);
8347
+ this.panels = this.specs.map(spec => spec(view));
8348
+ let conf = view.state.facet(panelConfig);
8349
+ this.top = new PanelGroup(view, true, conf.topContainer);
8350
+ this.bottom = new PanelGroup(view, false, conf.bottomContainer);
8351
+ this.top.sync(this.panels.filter(p => p.top));
8352
+ this.bottom.sync(this.panels.filter(p => !p.top));
8353
+ for (let p of this.panels) {
8354
+ p.dom.classList.add("cm-panel");
8355
+ if (p.mount)
8356
+ p.mount();
8357
+ }
8358
+ }
8359
+ update(update) {
8360
+ let conf = update.state.facet(panelConfig);
8361
+ if (this.top.container != conf.topContainer) {
8362
+ this.top.sync([]);
8363
+ this.top = new PanelGroup(update.view, true, conf.topContainer);
8364
+ }
8365
+ if (this.bottom.container != conf.bottomContainer) {
8366
+ this.bottom.sync([]);
8367
+ this.bottom = new PanelGroup(update.view, false, conf.bottomContainer);
8368
+ }
8369
+ this.top.syncClasses();
8370
+ this.bottom.syncClasses();
8371
+ let input = update.state.facet(showPanel);
8372
+ if (input != this.input) {
8373
+ let specs = input.filter(x => x);
8374
+ let panels = [], top = [], bottom = [], mount = [];
8375
+ for (let spec of specs) {
8376
+ let known = this.specs.indexOf(spec), panel;
8377
+ if (known < 0) {
8378
+ panel = spec(update.view);
8379
+ mount.push(panel);
8380
+ }
8381
+ else {
8382
+ panel = this.panels[known];
8383
+ if (panel.update)
8384
+ panel.update(update);
8385
+ }
8386
+ panels.push(panel);
8387
+ (panel.top ? top : bottom).push(panel);
8388
+ }
8389
+ this.specs = specs;
8390
+ this.panels = panels;
8391
+ this.top.sync(top);
8392
+ this.bottom.sync(bottom);
8393
+ for (let p of mount) {
8394
+ p.dom.classList.add("cm-panel");
8395
+ if (p.mount)
8396
+ p.mount();
8397
+ }
8398
+ }
8399
+ else {
8400
+ for (let p of this.panels)
8401
+ if (p.update)
8402
+ p.update(update);
8403
+ }
8404
+ }
8405
+ destroy() {
8406
+ this.top.sync([]);
8407
+ this.bottom.sync([]);
8408
+ }
8409
+ }, {
8410
+ provide: plugin => EditorView.scrollMargins.of(view => {
8411
+ let value = view.plugin(plugin);
8412
+ return value && { top: value.top.scrollMargin(), bottom: value.bottom.scrollMargin() };
8413
+ })
8414
+ });
8415
+ class PanelGroup {
8416
+ constructor(view, top, container) {
8417
+ this.view = view;
8418
+ this.top = top;
8419
+ this.container = container;
8420
+ this.dom = undefined;
8421
+ this.classes = "";
8422
+ this.panels = [];
8423
+ this.syncClasses();
8424
+ }
8425
+ sync(panels) {
8426
+ for (let p of this.panels)
8427
+ if (p.destroy && panels.indexOf(p) < 0)
8428
+ p.destroy();
8429
+ this.panels = panels;
8430
+ this.syncDOM();
8431
+ }
8432
+ syncDOM() {
8433
+ if (this.panels.length == 0) {
8434
+ if (this.dom) {
8435
+ this.dom.remove();
8436
+ this.dom = undefined;
8437
+ }
8438
+ return;
8439
+ }
8440
+ if (!this.dom) {
8441
+ this.dom = document.createElement("div");
8442
+ this.dom.className = this.top ? "cm-panels cm-panels-top" : "cm-panels cm-panels-bottom";
8443
+ this.dom.style[this.top ? "top" : "bottom"] = "0";
8444
+ let parent = this.container || this.view.dom;
8445
+ parent.insertBefore(this.dom, this.top ? parent.firstChild : null);
8446
+ }
8447
+ let curDOM = this.dom.firstChild;
8448
+ for (let panel of this.panels) {
8449
+ if (panel.dom.parentNode == this.dom) {
8450
+ while (curDOM != panel.dom)
8451
+ curDOM = rm(curDOM);
8452
+ curDOM = curDOM.nextSibling;
8453
+ }
8454
+ else {
8455
+ this.dom.insertBefore(panel.dom, curDOM);
8456
+ }
8457
+ }
8458
+ while (curDOM)
8459
+ curDOM = rm(curDOM);
8460
+ }
8461
+ scrollMargin() {
8462
+ return !this.dom || this.container ? 0
8463
+ : Math.max(0, this.top ?
8464
+ this.dom.getBoundingClientRect().bottom - Math.max(0, this.view.scrollDOM.getBoundingClientRect().top) :
8465
+ Math.min(innerHeight, this.view.scrollDOM.getBoundingClientRect().bottom) - this.dom.getBoundingClientRect().top);
8466
+ }
8467
+ syncClasses() {
8468
+ if (!this.container || this.classes == this.view.themeClasses)
8469
+ return;
8470
+ for (let cls of this.classes.split(" "))
8471
+ if (cls)
8472
+ this.container.classList.remove(cls);
8473
+ for (let cls of (this.classes = this.view.themeClasses).split(" "))
8474
+ if (cls)
8475
+ this.container.classList.add(cls);
8476
+ }
8477
+ }
8478
+ function rm(node) {
8479
+ let next = node.nextSibling;
8480
+ node.remove();
8481
+ return next;
8482
+ }
8483
+ /**
8484
+ Opening a panel is done by providing a constructor function for
8485
+ the panel through this facet. (The panel is closed again when its
8486
+ constructor is no longer provided.) Values of `null` are ignored.
8487
+ */
8488
+ const showPanel = /*@__PURE__*/Facet.define({
8489
+ enables: panelPlugin
8490
+ });
8491
+
8492
+ /**
8493
+ A gutter marker represents a bit of information attached to a line
8494
+ in a specific gutter. Your own custom markers have to extend this
8495
+ class.
8496
+ */
8497
+ class GutterMarker extends RangeValue {
8498
+ /**
8499
+ @internal
8500
+ */
8501
+ compare(other) {
8502
+ return this == other || this.constructor == other.constructor && this.eq(other);
8503
+ }
8504
+ /**
8505
+ Compare this marker to another marker of the same type.
8506
+ */
8507
+ eq(other) { return false; }
8508
+ /**
8509
+ Called if the marker has a `toDOM` method and its representation
8510
+ was removed from a gutter.
8511
+ */
8512
+ destroy(dom) { }
8513
+ }
8514
+ GutterMarker.prototype.elementClass = "";
8515
+ GutterMarker.prototype.toDOM = undefined;
8516
+ GutterMarker.prototype.mapMode = MapMode.TrackBefore;
8517
+ GutterMarker.prototype.startSide = GutterMarker.prototype.endSide = -1;
8518
+ GutterMarker.prototype.point = true;
8519
+ /**
8520
+ Facet used to add a class to all gutter elements for a given line.
8521
+ Markers given to this facet should _only_ define an
8522
+ [`elementclass`](https://codemirror.net/6/docs/ref/#view.GutterMarker.elementClass), not a
8523
+ [`toDOM`](https://codemirror.net/6/docs/ref/#view.GutterMarker.toDOM) (or the marker will appear
8524
+ in all gutters for the line).
8525
+ */
8526
+ const gutterLineClass = /*@__PURE__*/Facet.define();
8527
+ const defaults = {
8528
+ class: "",
8529
+ renderEmptyElements: false,
8530
+ elementStyle: "",
8531
+ markers: () => RangeSet.empty,
8532
+ lineMarker: () => null,
8533
+ lineMarkerChange: null,
8534
+ initialSpacer: null,
8535
+ updateSpacer: null,
8536
+ domEventHandlers: {}
8537
+ };
8538
+ const activeGutters = /*@__PURE__*/Facet.define();
8539
+ /**
8540
+ Define an editor gutter. The order in which the gutters appear is
8541
+ determined by their extension priority.
8542
+ */
8543
+ function gutter(config) {
8544
+ return [gutters(), activeGutters.of(Object.assign(Object.assign({}, defaults), config))];
8545
+ }
8546
+ const unfixGutters = /*@__PURE__*/Facet.define({
8547
+ combine: values => values.some(x => x)
8548
+ });
8549
+ /**
8550
+ The gutter-drawing plugin is automatically enabled when you add a
8551
+ gutter, but you can use this function to explicitly configure it.
8552
+
8553
+ Unless `fixed` is explicitly set to `false`, the gutters are
8554
+ fixed, meaning they don't scroll along with the content
8555
+ horizontally (except on Internet Explorer, which doesn't support
8556
+ CSS [`position:
8557
+ sticky`](https://developer.mozilla.org/en-US/docs/Web/CSS/position#sticky)).
8558
+ */
8559
+ function gutters(config) {
8560
+ let result = [
8561
+ gutterView,
8562
+ ];
8563
+ if (config && config.fixed === false)
8564
+ result.push(unfixGutters.of(true));
8565
+ return result;
8566
+ }
8567
+ const gutterView = /*@__PURE__*/ViewPlugin.fromClass(class {
8568
+ constructor(view) {
8569
+ this.view = view;
8570
+ this.prevViewport = view.viewport;
8571
+ this.dom = document.createElement("div");
8572
+ this.dom.className = "cm-gutters";
8573
+ this.dom.setAttribute("aria-hidden", "true");
8574
+ this.dom.style.minHeight = this.view.contentHeight + "px";
8575
+ this.gutters = view.state.facet(activeGutters).map(conf => new SingleGutterView(view, conf));
8576
+ for (let gutter of this.gutters)
8577
+ this.dom.appendChild(gutter.dom);
8578
+ this.fixed = !view.state.facet(unfixGutters);
8579
+ if (this.fixed) {
8580
+ // FIXME IE11 fallback, which doesn't support position: sticky,
8581
+ // by using position: relative + event handlers that realign the
8582
+ // gutter (or just force fixed=false on IE11?)
8583
+ this.dom.style.position = "sticky";
8584
+ }
8585
+ this.syncGutters(false);
8586
+ view.scrollDOM.insertBefore(this.dom, view.contentDOM);
8587
+ }
8588
+ update(update) {
8589
+ if (this.updateGutters(update)) {
8590
+ // Detach during sync when the viewport changed significantly
8591
+ // (such as during scrolling), since for large updates that is
8592
+ // faster.
8593
+ let vpA = this.prevViewport, vpB = update.view.viewport;
8594
+ let vpOverlap = Math.min(vpA.to, vpB.to) - Math.max(vpA.from, vpB.from);
8595
+ this.syncGutters(vpOverlap < (vpB.to - vpB.from) * 0.8);
8596
+ }
8597
+ if (update.geometryChanged)
8598
+ this.dom.style.minHeight = this.view.contentHeight + "px";
8599
+ if (this.view.state.facet(unfixGutters) != !this.fixed) {
8600
+ this.fixed = !this.fixed;
8601
+ this.dom.style.position = this.fixed ? "sticky" : "";
8602
+ }
8603
+ this.prevViewport = update.view.viewport;
8604
+ }
8605
+ syncGutters(detach) {
8606
+ let after = this.dom.nextSibling;
8607
+ if (detach)
8608
+ this.dom.remove();
8609
+ let lineClasses = RangeSet.iter(this.view.state.facet(gutterLineClass), this.view.viewport.from);
8610
+ let classSet = [];
8611
+ let contexts = this.gutters.map(gutter => new UpdateContext(gutter, this.view.viewport, -this.view.documentPadding.top));
8612
+ for (let line of this.view.viewportLineBlocks) {
8613
+ let text;
8614
+ if (Array.isArray(line.type)) {
8615
+ for (let b of line.type)
8616
+ if (b.type == BlockType.Text) {
8617
+ text = b;
8618
+ break;
8619
+ }
8620
+ }
8621
+ else {
8622
+ text = line.type == BlockType.Text ? line : undefined;
8623
+ }
8624
+ if (!text)
8625
+ continue;
8626
+ if (classSet.length)
8627
+ classSet = [];
8628
+ advanceCursor(lineClasses, classSet, line.from);
8629
+ for (let cx of contexts)
8630
+ cx.line(this.view, text, classSet);
8631
+ }
8632
+ for (let cx of contexts)
8633
+ cx.finish();
8634
+ if (detach)
8635
+ this.view.scrollDOM.insertBefore(this.dom, after);
8636
+ }
8637
+ updateGutters(update) {
8638
+ let prev = update.startState.facet(activeGutters), cur = update.state.facet(activeGutters);
8639
+ let change = update.docChanged || update.heightChanged || update.viewportChanged ||
8640
+ !RangeSet.eq(update.startState.facet(gutterLineClass), update.state.facet(gutterLineClass), update.view.viewport.from, update.view.viewport.to);
8641
+ if (prev == cur) {
8642
+ for (let gutter of this.gutters)
8643
+ if (gutter.update(update))
8644
+ change = true;
8645
+ }
8646
+ else {
8647
+ change = true;
8648
+ let gutters = [];
8649
+ for (let conf of cur) {
8650
+ let known = prev.indexOf(conf);
8651
+ if (known < 0) {
8652
+ gutters.push(new SingleGutterView(this.view, conf));
8653
+ }
8654
+ else {
8655
+ this.gutters[known].update(update);
8656
+ gutters.push(this.gutters[known]);
8657
+ }
8658
+ }
8659
+ for (let g of this.gutters) {
8660
+ g.dom.remove();
8661
+ if (gutters.indexOf(g) < 0)
8662
+ g.destroy();
8663
+ }
8664
+ for (let g of gutters)
8665
+ this.dom.appendChild(g.dom);
8666
+ this.gutters = gutters;
8667
+ }
8668
+ return change;
8669
+ }
8670
+ destroy() {
8671
+ for (let view of this.gutters)
8672
+ view.destroy();
8673
+ this.dom.remove();
8674
+ }
8675
+ }, {
8676
+ provide: plugin => EditorView.scrollMargins.of(view => {
8677
+ let value = view.plugin(plugin);
8678
+ if (!value || value.gutters.length == 0 || !value.fixed)
8679
+ return null;
8680
+ return view.textDirection == Direction.LTR ? { left: value.dom.offsetWidth } : { right: value.dom.offsetWidth };
8681
+ })
8682
+ });
8683
+ function asArray(val) { return (Array.isArray(val) ? val : [val]); }
8684
+ function advanceCursor(cursor, collect, pos) {
8685
+ while (cursor.value && cursor.from <= pos) {
8686
+ if (cursor.from == pos)
8687
+ collect.push(cursor.value);
8688
+ cursor.next();
8689
+ }
8690
+ }
8691
+ class UpdateContext {
8692
+ constructor(gutter, viewport, height) {
8693
+ this.gutter = gutter;
8694
+ this.height = height;
8695
+ this.localMarkers = [];
8696
+ this.i = 0;
8697
+ this.cursor = RangeSet.iter(gutter.markers, viewport.from);
8698
+ }
8699
+ line(view, line, extraMarkers) {
8700
+ if (this.localMarkers.length)
8701
+ this.localMarkers = [];
8702
+ advanceCursor(this.cursor, this.localMarkers, line.from);
8703
+ let localMarkers = extraMarkers.length ? this.localMarkers.concat(extraMarkers) : this.localMarkers;
8704
+ let forLine = this.gutter.config.lineMarker(view, line, localMarkers);
8705
+ if (forLine)
8706
+ localMarkers.unshift(forLine);
8707
+ let gutter = this.gutter;
8708
+ if (localMarkers.length == 0 && !gutter.config.renderEmptyElements)
8709
+ return;
8710
+ let above = line.top - this.height;
8711
+ if (this.i == gutter.elements.length) {
8712
+ let newElt = new GutterElement(view, line.height, above, localMarkers);
8713
+ gutter.elements.push(newElt);
8714
+ gutter.dom.appendChild(newElt.dom);
8715
+ }
8716
+ else {
8717
+ gutter.elements[this.i].update(view, line.height, above, localMarkers);
8718
+ }
8719
+ this.height = line.bottom;
8720
+ this.i++;
8721
+ }
8722
+ finish() {
8723
+ let gutter = this.gutter;
8724
+ while (gutter.elements.length > this.i) {
8725
+ let last = gutter.elements.pop();
8726
+ gutter.dom.removeChild(last.dom);
8727
+ last.destroy();
8728
+ }
8729
+ }
8730
+ }
8731
+ class SingleGutterView {
8732
+ constructor(view, config) {
8733
+ this.view = view;
8734
+ this.config = config;
8735
+ this.elements = [];
8736
+ this.spacer = null;
8737
+ this.dom = document.createElement("div");
8738
+ this.dom.className = "cm-gutter" + (this.config.class ? " " + this.config.class : "");
8739
+ for (let prop in config.domEventHandlers) {
8740
+ this.dom.addEventListener(prop, (event) => {
8741
+ let line = view.lineBlockAtHeight(event.clientY - view.documentTop);
8742
+ if (config.domEventHandlers[prop](view, line, event))
8743
+ event.preventDefault();
8744
+ });
8745
+ }
8746
+ this.markers = asArray(config.markers(view));
8747
+ if (config.initialSpacer) {
8748
+ this.spacer = new GutterElement(view, 0, 0, [config.initialSpacer(view)]);
8749
+ this.dom.appendChild(this.spacer.dom);
8750
+ this.spacer.dom.style.cssText += "visibility: hidden; pointer-events: none";
8751
+ }
8752
+ }
8753
+ update(update) {
8754
+ let prevMarkers = this.markers;
8755
+ this.markers = asArray(this.config.markers(update.view));
8756
+ if (this.spacer && this.config.updateSpacer) {
8757
+ let updated = this.config.updateSpacer(this.spacer.markers[0], update);
8758
+ if (updated != this.spacer.markers[0])
8759
+ this.spacer.update(update.view, 0, 0, [updated]);
8760
+ }
8761
+ let vp = update.view.viewport;
8762
+ return !RangeSet.eq(this.markers, prevMarkers, vp.from, vp.to) ||
8763
+ (this.config.lineMarkerChange ? this.config.lineMarkerChange(update) : false);
8764
+ }
8765
+ destroy() {
8766
+ for (let elt of this.elements)
8767
+ elt.destroy();
8768
+ }
8769
+ }
8770
+ class GutterElement {
8771
+ constructor(view, height, above, markers) {
8772
+ this.height = -1;
8773
+ this.above = 0;
8774
+ this.markers = [];
8775
+ this.dom = document.createElement("div");
8776
+ this.update(view, height, above, markers);
8777
+ }
8778
+ update(view, height, above, markers) {
8779
+ if (this.height != height)
8780
+ this.dom.style.height = (this.height = height) + "px";
8781
+ if (this.above != above)
8782
+ this.dom.style.marginTop = (this.above = above) ? above + "px" : "";
8783
+ if (!sameMarkers(this.markers, markers))
8784
+ this.setMarkers(view, markers);
8785
+ }
8786
+ setMarkers(view, markers) {
8787
+ let cls = "cm-gutterElement", domPos = this.dom.firstChild;
8788
+ for (let iNew = 0, iOld = 0;;) {
8789
+ let skipTo = iOld, marker = iNew < markers.length ? markers[iNew++] : null, matched = false;
8790
+ if (marker) {
8791
+ let c = marker.elementClass;
8792
+ if (c)
8793
+ cls += " " + c;
8794
+ for (let i = iOld; i < this.markers.length; i++)
8795
+ if (this.markers[i].compare(marker)) {
8796
+ skipTo = i;
8797
+ matched = true;
8798
+ break;
8799
+ }
8800
+ }
8801
+ else {
8802
+ skipTo = this.markers.length;
8803
+ }
8804
+ while (iOld < skipTo) {
8805
+ let next = this.markers[iOld++];
8806
+ if (next.toDOM) {
8807
+ next.destroy(domPos);
8808
+ let after = domPos.nextSibling;
8809
+ domPos.remove();
8810
+ domPos = after;
8811
+ }
8812
+ }
8813
+ if (!marker)
8814
+ break;
8815
+ if (marker.toDOM) {
8816
+ if (matched)
8817
+ domPos = domPos.nextSibling;
8818
+ else
8819
+ this.dom.insertBefore(marker.toDOM(view), domPos);
8820
+ }
8821
+ if (matched)
8822
+ iOld++;
8823
+ }
8824
+ this.dom.className = cls;
8825
+ this.markers = markers;
8826
+ }
8827
+ destroy() {
8828
+ this.setMarkers(null, []); // First argument not used unless creating markers
8829
+ }
8830
+ }
8831
+ function sameMarkers(a, b) {
8832
+ if (a.length != b.length)
8833
+ return false;
8834
+ for (let i = 0; i < a.length; i++)
8835
+ if (!a[i].compare(b[i]))
8836
+ return false;
8837
+ return true;
8838
+ }
8839
+ /**
8840
+ Facet used to provide markers to the line number gutter.
8841
+ */
8842
+ const lineNumberMarkers = /*@__PURE__*/Facet.define();
8843
+ const lineNumberConfig = /*@__PURE__*/Facet.define({
8844
+ combine(values) {
8845
+ return combineConfig(values, { formatNumber: String, domEventHandlers: {} }, {
8846
+ domEventHandlers(a, b) {
8847
+ let result = Object.assign({}, a);
8848
+ for (let event in b) {
8849
+ let exists = result[event], add = b[event];
8850
+ result[event] = exists ? (view, line, event) => exists(view, line, event) || add(view, line, event) : add;
8851
+ }
8852
+ return result;
8853
+ }
8854
+ });
8855
+ }
8856
+ });
8857
+ class NumberMarker extends GutterMarker {
8858
+ constructor(number) {
8859
+ super();
8860
+ this.number = number;
8861
+ }
8862
+ eq(other) { return this.number == other.number; }
8863
+ toDOM() { return document.createTextNode(this.number); }
8864
+ }
8865
+ function formatNumber(view, number) {
8866
+ return view.state.facet(lineNumberConfig).formatNumber(number, view.state);
8867
+ }
8868
+ const lineNumberGutter = /*@__PURE__*/activeGutters.compute([lineNumberConfig], state => ({
8869
+ class: "cm-lineNumbers",
8870
+ renderEmptyElements: false,
8871
+ markers(view) { return view.state.facet(lineNumberMarkers); },
8872
+ lineMarker(view, line, others) {
8873
+ if (others.some(m => m.toDOM))
8874
+ return null;
8875
+ return new NumberMarker(formatNumber(view, view.state.doc.lineAt(line.from).number));
8876
+ },
8877
+ lineMarkerChange: update => update.startState.facet(lineNumberConfig) != update.state.facet(lineNumberConfig),
8878
+ initialSpacer(view) {
8879
+ return new NumberMarker(formatNumber(view, maxLineNumber(view.state.doc.lines)));
8880
+ },
8881
+ updateSpacer(spacer, update) {
8882
+ let max = formatNumber(update.view, maxLineNumber(update.view.state.doc.lines));
8883
+ return max == spacer.number ? spacer : new NumberMarker(max);
8884
+ },
8885
+ domEventHandlers: state.facet(lineNumberConfig).domEventHandlers
8886
+ }));
8887
+ /**
8888
+ Create a line number gutter extension.
8889
+ */
8890
+ function lineNumbers(config = {}) {
8891
+ return [
8892
+ lineNumberConfig.of(config),
8893
+ gutters(),
8894
+ lineNumberGutter
8895
+ ];
8896
+ }
8897
+ function maxLineNumber(lines) {
8898
+ let last = 9;
8899
+ while (last < lines)
8900
+ last = last * 10 + 9;
8901
+ return last;
8902
+ }
8903
+ const activeLineGutterMarker = /*@__PURE__*/new class extends GutterMarker {
8904
+ constructor() {
8905
+ super(...arguments);
8906
+ this.elementClass = "cm-activeLineGutter";
8907
+ }
8908
+ };
8909
+ const activeLineGutterHighlighter = /*@__PURE__*/gutterLineClass.compute(["selection"], state => {
8910
+ let marks = [], last = -1;
8911
+ for (let range of state.selection.ranges)
8912
+ if (range.empty) {
8913
+ let linePos = state.doc.lineAt(range.head).from;
8914
+ if (linePos > last) {
8915
+ last = linePos;
8916
+ marks.push(activeLineGutterMarker.range(linePos));
8917
+ }
8918
+ }
8919
+ return RangeSet.of(marks);
8920
+ });
8921
+ /**
8922
+ Returns an extension that adds a `cm-activeLineGutter` class to
8923
+ all gutter elements on the [active
8924
+ line](https://codemirror.net/6/docs/ref/#view.highlightActiveLine).
8925
+ */
8926
+ function highlightActiveLineGutter() {
8927
+ return activeLineGutterHighlighter;
8928
+ }
8929
+
7711
8930
  /**
7712
8931
  @internal
7713
8932
  */
7714
8933
  const __test = { HeightMap, HeightOracle, MeasuredHeights, QueryType, ChangedRange, computeOrder, moveVisually };
7715
8934
 
7716
- export { BidiSpan, BlockInfo, BlockType, Decoration, Direction, EditorView, MatchDecorator, PluginField, PluginFieldProvider, ViewPlugin, ViewUpdate, WidgetType, __test, drawSelection, dropCursor, highlightActiveLine, highlightSpecialChars, keymap, logException, placeholder, runScopeHandlers, scrollPastEnd };
8935
+ 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 };