@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.cjs CHANGED
@@ -4,8 +4,6 @@ Object.defineProperty(exports, '__esModule', { value: true });
4
4
 
5
5
  var state = require('@codemirror/state');
6
6
  var styleMod = require('style-mod');
7
- var rangeset = require('@codemirror/rangeset');
8
- var text = require('@codemirror/text');
9
7
  var w3cKeyname = require('w3c-keyname');
10
8
 
11
9
  function getSelection(root) {
@@ -318,32 +316,34 @@ class ContentView {
318
316
  sync(track) {
319
317
  if (this.dirty & 2 /* Node */) {
320
318
  let parent = this.dom;
321
- let pos = parent.firstChild;
319
+ let prev = null, next;
322
320
  for (let child of this.children) {
323
321
  if (child.dirty) {
324
- if (!child.dom && pos) {
325
- let contentView = ContentView.get(pos);
322
+ if (!child.dom && (next = prev ? prev.nextSibling : parent.firstChild)) {
323
+ let contentView = ContentView.get(next);
326
324
  if (!contentView || !contentView.parent && contentView.constructor == child.constructor)
327
- child.reuseDOM(pos);
325
+ child.reuseDOM(next);
328
326
  }
329
327
  child.sync(track);
330
328
  child.dirty = 0 /* Not */;
331
329
  }
332
- if (track && !track.written && track.node == parent && pos != child.dom)
330
+ next = prev ? prev.nextSibling : parent.firstChild;
331
+ if (track && !track.written && track.node == parent && next != child.dom)
333
332
  track.written = true;
334
333
  if (child.dom.parentNode == parent) {
335
- while (pos && pos != child.dom)
336
- pos = rm(pos);
337
- pos = child.dom.nextSibling;
334
+ while (next && next != child.dom)
335
+ next = rm$1(next);
338
336
  }
339
337
  else {
340
- parent.insertBefore(child.dom, pos);
338
+ parent.insertBefore(child.dom, next);
341
339
  }
340
+ prev = child.dom;
342
341
  }
343
- if (pos && track && track.node == parent)
342
+ next = prev ? prev.nextSibling : parent.firstChild;
343
+ if (next && track && track.node == parent)
344
344
  track.written = true;
345
- while (pos)
346
- pos = rm(pos);
345
+ while (next)
346
+ next = rm$1(next);
347
347
  }
348
348
  else if (this.dirty & 1 /* Child */) {
349
349
  for (let child of this.children)
@@ -489,7 +489,7 @@ class ContentView {
489
489
  }
490
490
  ContentView.prototype.breakAfter = 0;
491
491
  // Remove a DOM node and return its next sibling.
492
- function rm(dom) {
492
+ function rm$1(dom) {
493
493
  let next = dom.nextSibling;
494
494
  dom.parentNode.removeChild(dom);
495
495
  return next;
@@ -825,12 +825,12 @@ class WidgetView extends ContentView {
825
825
  ignoreEvent(event) { return this.widget.ignoreEvent(event); }
826
826
  get overrideDOMText() {
827
827
  if (this.length == 0)
828
- return text.Text.empty;
828
+ return state.Text.empty;
829
829
  let top = this;
830
830
  while (top.parent)
831
831
  top = top.parent;
832
- let view = top.editorView, text$1 = view && view.state.doc, start = this.posAtStart;
833
- return text$1 ? text$1.slice(start, start + this.length) : text.Text.empty;
832
+ let view = top.editorView, text = view && view.state.doc, start = this.posAtStart;
833
+ return text ? text.slice(start, start + this.length) : state.Text.empty;
834
834
  }
835
835
  domAtPos(pos) {
836
836
  return pos == 0 ? DOMPos.before(this.dom) : DOMPos.after(this.dom, pos == this.length);
@@ -953,7 +953,7 @@ class WidgetBufferView extends ContentView {
953
953
  ? { left: imgRect.left, right: imgRect.right, top: siblingRect.top, bottom: siblingRect.bottom } : imgRect;
954
954
  }
955
955
  get overrideDOMText() {
956
- return text.Text.empty;
956
+ return state.Text.empty;
957
957
  }
958
958
  }
959
959
  TextView.prototype.children = WidgetView.prototype.children = WidgetBufferView.prototype.children = noChildren;
@@ -1077,7 +1077,7 @@ function updateAttrs(dom, prev, attrs) {
1077
1077
  Widgets added to the content are described by subclasses of this
1078
1078
  class. Using a description object like that makes it possible to
1079
1079
  delay creating of the DOM structure for a widget until it is
1080
- needed, and to avoid redrawing widgets even when the decorations
1080
+ needed, and to avoid redrawing widgets even if the decorations
1081
1081
  that define them are recreated.
1082
1082
  */
1083
1083
  class WidgetType {
@@ -1090,7 +1090,7 @@ class WidgetType {
1090
1090
  returns `false`, which will cause new instances of the widget to
1091
1091
  always be redrawn.
1092
1092
  */
1093
- eq(_widget) { return false; }
1093
+ eq(widget) { return false; }
1094
1094
  /**
1095
1095
  Update a DOM element created by a widget of the same type (but
1096
1096
  different, non-`eq` content) to reflect this widget. May return
@@ -1098,7 +1098,7 @@ class WidgetType {
1098
1098
  couldn't (in which case the widget will be redrawn). The default
1099
1099
  implementation just returns false.
1100
1100
  */
1101
- updateDOM(_dom) { return false; }
1101
+ updateDOM(dom) { return false; }
1102
1102
  /**
1103
1103
  @internal
1104
1104
  */
@@ -1117,7 +1117,7 @@ class WidgetType {
1117
1117
  should be ignored by the editor. The default is to ignore all
1118
1118
  events.
1119
1119
  */
1120
- ignoreEvent(_event) { return true; }
1120
+ ignoreEvent(event) { return true; }
1121
1121
  /**
1122
1122
  @internal
1123
1123
  */
@@ -1126,7 +1126,7 @@ class WidgetType {
1126
1126
  This is called when the an instance of the widget is removed
1127
1127
  from the editor view.
1128
1128
  */
1129
- destroy(_dom) { }
1129
+ destroy(dom) { }
1130
1130
  }
1131
1131
  /**
1132
1132
  The different types of blocks that can occur in an editor view.
@@ -1153,9 +1153,10 @@ exports.BlockType = void 0;
1153
1153
  /**
1154
1154
  A decoration provides information on how to draw or style a piece
1155
1155
  of content. You'll usually use it wrapped in a
1156
- [`Range`](https://codemirror.net/6/docs/ref/#rangeset.Range), which adds a start and end position.
1156
+ [`Range`](https://codemirror.net/6/docs/ref/#state.Range), which adds a start and end position.
1157
+ @nonabstract
1157
1158
  */
1158
- class Decoration extends rangeset.RangeValue {
1159
+ class Decoration extends state.RangeValue {
1159
1160
  /**
1160
1161
  @internal
1161
1162
  */
@@ -1192,18 +1193,17 @@ class Decoration extends rangeset.RangeValue {
1192
1193
  Create a mark decoration, which influences the styling of the
1193
1194
  content in its range. Nested mark decorations will cause nested
1194
1195
  DOM elements to be created. Nesting order is determined by
1195
- precedence of the [facet](https://codemirror.net/6/docs/ref/#view.EditorView^decorations) or
1196
- (below the facet-provided decorations) [view
1197
- plugin](https://codemirror.net/6/docs/ref/#view.PluginSpec.decorations). Such elements are split
1198
- on line boundaries and on the boundaries of higher-precedence
1199
- decorations.
1196
+ precedence of the [facet](https://codemirror.net/6/docs/ref/#view.EditorView^decorations), with
1197
+ the higher-precedence decorations creating the inner DOM nodes.
1198
+ Such elements are split on line boundaries and on the boundaries
1199
+ of lower-precedence decorations.
1200
1200
  */
1201
1201
  static mark(spec) {
1202
1202
  return new MarkDecoration(spec);
1203
1203
  }
1204
1204
  /**
1205
- Create a widget decoration, which adds an element at the given
1206
- position.
1205
+ Create a widget decoration, which displays a DOM element at the
1206
+ given position.
1207
1207
  */
1208
1208
  static widget(spec) {
1209
1209
  let side = spec.side || 0, block = !!spec.block;
@@ -1240,7 +1240,7 @@ class Decoration extends rangeset.RangeValue {
1240
1240
  pass `true` for `sort` to make the library sort them for you.
1241
1241
  */
1242
1242
  static set(of, sort = false) {
1243
- return rangeset.RangeSet.of(of, sort);
1243
+ return state.RangeSet.of(of, sort);
1244
1244
  }
1245
1245
  /**
1246
1246
  @internal
@@ -1250,7 +1250,7 @@ class Decoration extends rangeset.RangeValue {
1250
1250
  /**
1251
1251
  The empty set of decorations.
1252
1252
  */
1253
- Decoration.none = rangeset.RangeSet.empty;
1253
+ Decoration.none = state.RangeSet.empty;
1254
1254
  class MarkDecoration extends Decoration {
1255
1255
  constructor(spec) {
1256
1256
  let { start, end } = getInclusive(spec);
@@ -1541,11 +1541,11 @@ class BlockWidgetView extends ContentView {
1541
1541
  }
1542
1542
 
1543
1543
  class ContentBuilder {
1544
- constructor(doc, pos, end, disallowBlockEffectsBelow) {
1544
+ constructor(doc, pos, end, disallowBlockEffectsFor) {
1545
1545
  this.doc = doc;
1546
1546
  this.pos = pos;
1547
1547
  this.end = end;
1548
- this.disallowBlockEffectsBelow = disallowBlockEffectsBelow;
1548
+ this.disallowBlockEffectsFor = disallowBlockEffectsFor;
1549
1549
  this.content = [];
1550
1550
  this.curLine = null;
1551
1551
  this.breakAtStart = 0;
@@ -1630,7 +1630,13 @@ class ContentBuilder {
1630
1630
  if (this.openStart < 0)
1631
1631
  this.openStart = openStart;
1632
1632
  }
1633
- point(from, to, deco, active, openStart) {
1633
+ point(from, to, deco, active, openStart, index) {
1634
+ if (this.disallowBlockEffectsFor[index] && deco instanceof PointDecoration) {
1635
+ if (deco.block)
1636
+ throw new RangeError("Block decorations may not be specified via plugins");
1637
+ if (to > this.doc.lineAt(this.pos).to)
1638
+ throw new RangeError("Decorations that replace line breaks may not be specified via plugins");
1639
+ }
1634
1640
  let len = to - from;
1635
1641
  if (deco instanceof PointDecoration) {
1636
1642
  if (deco.block) {
@@ -1674,18 +1680,9 @@ class ContentBuilder {
1674
1680
  if (this.openStart < 0)
1675
1681
  this.openStart = openStart;
1676
1682
  }
1677
- filterPoint(from, to, value, index) {
1678
- if (index < this.disallowBlockEffectsBelow && value instanceof PointDecoration) {
1679
- if (value.block)
1680
- throw new RangeError("Block decorations may not be specified via plugins");
1681
- if (to > this.doc.lineAt(this.pos).to)
1682
- throw new RangeError("Decorations that replace line breaks may not be specified via plugins");
1683
- }
1684
- return true;
1685
- }
1686
- static build(text, from, to, decorations, pluginDecorationLength) {
1687
- let builder = new ContentBuilder(text, from, to, pluginDecorationLength);
1688
- builder.openEnd = rangeset.RangeSet.spans(decorations, from, to, builder);
1683
+ static build(text, from, to, decorations, dynamicDecorationMap) {
1684
+ let builder = new ContentBuilder(text, from, to, dynamicDecorationMap);
1685
+ builder.openEnd = state.RangeSet.spans(decorations, from, to, builder);
1689
1686
  if (builder.openStart < 0)
1690
1687
  builder.openStart = builder.openEnd;
1691
1688
  builder.finish(builder.openEnd);
@@ -1714,13 +1711,8 @@ const mouseSelectionStyle = state.Facet.define();
1714
1711
  const exceptionSink = state.Facet.define();
1715
1712
  const updateListener = state.Facet.define();
1716
1713
  const inputHandler = state.Facet.define();
1717
- // FIXME remove
1718
- const scrollTo = state.StateEffect.define({
1719
- map: (range, changes) => range.map(changes)
1720
- });
1721
- // FIXME remove
1722
- const centerOn = state.StateEffect.define({
1723
- map: (range, changes) => range.map(changes)
1714
+ const perLineTextDirection = state.Facet.define({
1715
+ combine: values => values.some(x => x)
1724
1716
  });
1725
1717
  class ScrollTarget {
1726
1718
  constructor(range, y = "nearest", x = "nearest", yMargin = 5, xMargin = 5) {
@@ -1759,83 +1751,6 @@ function logException(state, exception, context) {
1759
1751
  console.error(exception);
1760
1752
  }
1761
1753
  const editable = state.Facet.define({ combine: values => values.length ? values[0] : true });
1762
- /**
1763
- Used to [declare](https://codemirror.net/6/docs/ref/#view.PluginSpec.provide) which
1764
- [fields](https://codemirror.net/6/docs/ref/#view.PluginValue) a [view plugin](https://codemirror.net/6/docs/ref/#view.ViewPlugin)
1765
- provides.
1766
- */
1767
- class PluginFieldProvider {
1768
- /**
1769
- @internal
1770
- */
1771
- constructor(
1772
- /**
1773
- @internal
1774
- */
1775
- field,
1776
- /**
1777
- @internal
1778
- */
1779
- get) {
1780
- this.field = field;
1781
- this.get = get;
1782
- }
1783
- }
1784
- /**
1785
- Plugin fields are a mechanism for allowing plugins to provide
1786
- values that can be retrieved through the
1787
- [`pluginField`](https://codemirror.net/6/docs/ref/#view.EditorView.pluginField) view method.
1788
- */
1789
- class PluginField {
1790
- /**
1791
- Create a [provider](https://codemirror.net/6/docs/ref/#view.PluginFieldProvider) for this field,
1792
- to use with a plugin's [provide](https://codemirror.net/6/docs/ref/#view.PluginSpec.provide)
1793
- option.
1794
- */
1795
- from(get) {
1796
- return new PluginFieldProvider(this, get);
1797
- }
1798
- /**
1799
- Define a new plugin field.
1800
- */
1801
- static define() { return new PluginField(); }
1802
- }
1803
- /**
1804
- This field can be used by plugins to provide
1805
- [decorations](https://codemirror.net/6/docs/ref/#view.Decoration).
1806
-
1807
- **Note**: For reasons of data flow (plugins are only updated
1808
- after the viewport is computed), decorations produced by plugins
1809
- are _not_ taken into account when predicting the vertical layout
1810
- structure of the editor. They **must not** introduce block
1811
- widgets (that will raise an error) or replacing decorations that
1812
- cover line breaks (these will be ignored if they occur). Such
1813
- decorations, or others that cause a large amount of vertical
1814
- size shift compared to the undecorated content, should be
1815
- provided through the state-level [`decorations`
1816
- facet](https://codemirror.net/6/docs/ref/#view.EditorView^decorations) instead.
1817
- */
1818
- PluginField.decorations = PluginField.define();
1819
- /**
1820
- Used to provide ranges that should be treated as atoms as far as
1821
- cursor motion is concerned. This causes methods like
1822
- [`moveByChar`](https://codemirror.net/6/docs/ref/#view.EditorView.moveByChar) and
1823
- [`moveVertically`](https://codemirror.net/6/docs/ref/#view.EditorView.moveVertically) (and the
1824
- commands built on top of them) to skip across such regions when
1825
- a selection endpoint would enter them. This does _not_ prevent
1826
- direct programmatic [selection
1827
- updates](https://codemirror.net/6/docs/ref/#state.TransactionSpec.selection) from moving into such
1828
- regions.
1829
- */
1830
- PluginField.atomicRanges = PluginField.define();
1831
- /**
1832
- Plugins can provide additional scroll margins (space around the
1833
- sides of the scrolling element that should be considered
1834
- invisible) through this field. This can be useful when the
1835
- plugin introduces elements that cover part of that element (for
1836
- example a horizontally fixed gutter).
1837
- */
1838
- PluginField.scrollMargins = PluginField.define();
1839
1754
  let nextPluginID = 0;
1840
1755
  const viewPlugin = state.Facet.define();
1841
1756
  /**
@@ -1856,27 +1771,29 @@ class ViewPlugin {
1856
1771
  /**
1857
1772
  @internal
1858
1773
  */
1859
- fields) {
1774
+ domEventHandlers, buildExtensions) {
1860
1775
  this.id = id;
1861
1776
  this.create = create;
1862
- this.fields = fields;
1863
- this.extension = viewPlugin.of(this);
1777
+ this.domEventHandlers = domEventHandlers;
1778
+ this.extension = buildExtensions(this);
1864
1779
  }
1865
1780
  /**
1866
1781
  Define a plugin from a constructor function that creates the
1867
1782
  plugin's value, given an editor view.
1868
1783
  */
1869
1784
  static define(create, spec) {
1870
- let { eventHandlers, provide, decorations } = spec || {};
1871
- let fields = [];
1872
- if (provide)
1873
- for (let provider of Array.isArray(provide) ? provide : [provide])
1874
- fields.push(provider);
1875
- if (eventHandlers)
1876
- fields.push(domEventHandlers.from((value) => ({ plugin: value, handlers: eventHandlers })));
1877
- if (decorations)
1878
- fields.push(PluginField.decorations.from(decorations));
1879
- return new ViewPlugin(nextPluginID++, create, fields);
1785
+ const { eventHandlers, provide, decorations: deco } = spec || {};
1786
+ return new ViewPlugin(nextPluginID++, create, eventHandlers, plugin => {
1787
+ let ext = [viewPlugin.of(plugin)];
1788
+ if (deco)
1789
+ ext.push(decorations.of(view => {
1790
+ let pluginInst = view.plugin(plugin);
1791
+ return pluginInst ? deco(pluginInst) : Decoration.none;
1792
+ }));
1793
+ if (provide)
1794
+ ext.push(provide(plugin));
1795
+ return ext;
1796
+ });
1880
1797
  }
1881
1798
  /**
1882
1799
  Create a plugin for a class whose constructor takes a single
@@ -1886,7 +1803,6 @@ class ViewPlugin {
1886
1803
  return ViewPlugin.define(view => new cls(view), spec);
1887
1804
  }
1888
1805
  }
1889
- const domEventHandlers = PluginField.define();
1890
1806
  class PluginInstance {
1891
1807
  constructor(spec) {
1892
1808
  this.spec = spec;
@@ -1899,12 +1815,6 @@ class PluginInstance {
1899
1815
  // initialized on the first update.
1900
1816
  this.value = null;
1901
1817
  }
1902
- takeField(type, target) {
1903
- if (this.spec)
1904
- for (let { field, get } of this.spec.fields)
1905
- if (field == type)
1906
- target.push(get(this.value));
1907
- }
1908
1818
  update(view) {
1909
1819
  if (!this.value) {
1910
1820
  if (this.spec) {
@@ -1956,6 +1866,8 @@ const editorAttributes = state.Facet.define();
1956
1866
  const contentAttributes = state.Facet.define();
1957
1867
  // Provide decorations
1958
1868
  const decorations = state.Facet.define();
1869
+ const atomicRanges = state.Facet.define();
1870
+ const scrollMargins = state.Facet.define();
1959
1871
  const styleModule = state.Facet.define();
1960
1872
  class ChangedRange {
1961
1873
  constructor(fromA, toA, fromB, toB) {
@@ -2056,8 +1968,8 @@ class ViewUpdate {
2056
1968
  return (this.flags & 4 /* Viewport */) > 0;
2057
1969
  }
2058
1970
  /**
2059
- Indicates whether the height of an element in the editor changed
2060
- in this update.
1971
+ Indicates whether the height of a block element in the editor
1972
+ changed in this update.
2061
1973
  */
2062
1974
  get heightChanged() {
2063
1975
  return (this.flags & 2 /* Height */) > 0;
@@ -2393,7 +2305,7 @@ function moveVisually(line, order, dir, start, forward) {
2393
2305
  startIndex = span.side(!forward, dir);
2394
2306
  }
2395
2307
  let indexForward = forward == (span.dir == dir);
2396
- let nextIndex = text.findClusterBreak(line.text, startIndex, indexForward);
2308
+ let nextIndex = state.findClusterBreak(line.text, startIndex, indexForward);
2397
2309
  movedOver = line.text.slice(Math.min(startIndex, nextIndex), Math.max(startIndex, nextIndex));
2398
2310
  if (nextIndex != span.side(forward, dir))
2399
2311
  return state.EditorSelection.cursor(nextIndex + line.from, indexForward ? -1 : 1, span.level);
@@ -2517,7 +2429,7 @@ class DocView extends ContentView {
2517
2429
  this.view = view;
2518
2430
  this.compositionDeco = Decoration.none;
2519
2431
  this.decorations = [];
2520
- this.pluginDecorationLength = 0;
2432
+ this.dynamicDecorationMap = [];
2521
2433
  // Track a minimum width for the editor. When measuring sizes in
2522
2434
  // measureVisibleLineHeights, this is updated to point at the width
2523
2435
  // of a given element and its extent in the document. When a change
@@ -2623,7 +2535,7 @@ class DocView extends ContentView {
2623
2535
  if (!next)
2624
2536
  break;
2625
2537
  let { fromA, toA, fromB, toB } = next;
2626
- let { content, breakAtStart, openStart, openEnd } = ContentBuilder.build(this.view.state.doc, fromB, toB, this.decorations, this.pluginDecorationLength);
2538
+ let { content, breakAtStart, openStart, openEnd } = ContentBuilder.build(this.view.state.doc, fromB, toB, this.decorations, this.dynamicDecorationMap);
2627
2539
  let { i: toI, off: toOff } = cursor.findPos(toA, 1);
2628
2540
  let { i: fromI, off: fromOff } = cursor.findPos(fromA, -1);
2629
2541
  replaceRange(this, fromI, fromOff, toI, toOff, content, breakAtStart, openStart, openEnd);
@@ -2764,11 +2676,11 @@ class DocView extends ContentView {
2764
2676
  off = start;
2765
2677
  }
2766
2678
  }
2767
- measureVisibleLineHeights() {
2768
- let result = [], { from, to } = this.view.viewState.viewport;
2679
+ measureVisibleLineHeights(viewport) {
2680
+ let result = [], { from, to } = viewport;
2769
2681
  let contentWidth = this.view.contentDOM.clientWidth;
2770
2682
  let isWider = contentWidth > Math.max(this.view.scrollDOM.clientWidth, this.minWidth) + 1;
2771
- let widest = -1;
2683
+ let widest = -1, ltr = this.view.textDirection == exports.Direction.LTR;
2772
2684
  for (let pos = 0, i = 0; i < this.children.length; i++) {
2773
2685
  let child = this.children[i], end = pos + child.length;
2774
2686
  if (end > to)
@@ -2781,8 +2693,7 @@ class DocView extends ContentView {
2781
2693
  let rects = last ? clientRectsFor(last) : [];
2782
2694
  if (rects.length) {
2783
2695
  let rect = rects[rects.length - 1];
2784
- let width = this.view.textDirection == exports.Direction.LTR ? rect.right - childRect.left
2785
- : childRect.right - rect.left;
2696
+ let width = ltr ? rect.right - childRect.left : childRect.right - rect.left;
2786
2697
  if (width > widest) {
2787
2698
  widest = width;
2788
2699
  this.minWidth = contentWidth;
@@ -2796,6 +2707,10 @@ class DocView extends ContentView {
2796
2707
  }
2797
2708
  return result;
2798
2709
  }
2710
+ textDirectionAt(pos) {
2711
+ let { i } = this.childPos(pos, 1);
2712
+ return getComputedStyle(this.children[i].dom).direction == "rtl" ? exports.Direction.RTL : exports.Direction.LTR;
2713
+ }
2799
2714
  measureTextSize() {
2800
2715
  for (let child of this.children) {
2801
2716
  if (child instanceof LineView) {
@@ -2847,11 +2762,14 @@ class DocView extends ContentView {
2847
2762
  return Decoration.set(deco);
2848
2763
  }
2849
2764
  updateDeco() {
2850
- let pluginDecorations = this.view.pluginField(PluginField.decorations);
2851
- this.pluginDecorationLength = pluginDecorations.length;
2765
+ let allDeco = this.view.state.facet(decorations).map((d, i) => {
2766
+ let dynamic = this.dynamicDecorationMap[i] = typeof d == "function";
2767
+ return dynamic ? d(this.view) : d;
2768
+ });
2769
+ for (let i = allDeco.length; i < allDeco.length + 3; i++)
2770
+ this.dynamicDecorationMap[i] = false;
2852
2771
  return this.decorations = [
2853
- ...pluginDecorations,
2854
- ...this.view.state.facet(decorations),
2772
+ ...allDeco,
2855
2773
  this.compositionDeco,
2856
2774
  this.computeBlockGapDeco(),
2857
2775
  this.view.viewState.lineGapDeco
@@ -2866,7 +2784,7 @@ class DocView extends ContentView {
2866
2784
  rect = { left: Math.min(rect.left, other.left), top: Math.min(rect.top, other.top),
2867
2785
  right: Math.max(rect.right, other.right), bottom: Math.max(rect.bottom, other.bottom) };
2868
2786
  let mLeft = 0, mRight = 0, mTop = 0, mBottom = 0;
2869
- for (let margins of this.view.pluginField(PluginField.scrollMargins))
2787
+ for (let margins of this.view.state.facet(scrollMargins).map(f => f(this.view)))
2870
2788
  if (margins) {
2871
2789
  let { left, right, top, bottom } = margins;
2872
2790
  if (left != null)
@@ -3008,7 +2926,7 @@ class DecorationComparator$1 {
3008
2926
  }
3009
2927
  function findChangedDeco(a, b, diff) {
3010
2928
  let comp = new DecorationComparator$1;
3011
- rangeset.RangeSet.compare(a, b, diff, comp);
2929
+ state.RangeSet.compare(a, b, diff, comp);
3012
2930
  return comp.changes;
3013
2931
  }
3014
2932
  function inUneditable(node, inside) {
@@ -3031,18 +2949,18 @@ function groupAt(state$1, pos, bias = 1) {
3031
2949
  bias = -1;
3032
2950
  let from = linePos, to = linePos;
3033
2951
  if (bias < 0)
3034
- from = text.findClusterBreak(line.text, linePos, false);
2952
+ from = state.findClusterBreak(line.text, linePos, false);
3035
2953
  else
3036
- to = text.findClusterBreak(line.text, linePos);
2954
+ to = state.findClusterBreak(line.text, linePos);
3037
2955
  let cat = categorize(line.text.slice(from, to));
3038
2956
  while (from > 0) {
3039
- let prev = text.findClusterBreak(line.text, from, false);
2957
+ let prev = state.findClusterBreak(line.text, from, false);
3040
2958
  if (categorize(line.text.slice(prev, from)) != cat)
3041
2959
  break;
3042
2960
  from = prev;
3043
2961
  }
3044
2962
  while (to < line.length) {
3045
- let next = text.findClusterBreak(line.text, to);
2963
+ let next = state.findClusterBreak(line.text, to);
3046
2964
  if (categorize(line.text.slice(to, next)) != cat)
3047
2965
  break;
3048
2966
  to = next;
@@ -3234,7 +3152,7 @@ function posAtCoordsImprecise(view, contentRect, block, x, y) {
3234
3152
  into += line * view.viewState.heightOracle.lineLength;
3235
3153
  }
3236
3154
  let content = view.state.sliceDoc(block.from, block.to);
3237
- return block.from + text.findColumn(content, into, view.state.tabSize);
3155
+ return block.from + state.findColumn(content, into, view.state.tabSize);
3238
3156
  }
3239
3157
  // In case of a high line height, Safari's caretRangeFromPoint treats
3240
3158
  // the space between lines as belonging to the last character of the
@@ -3255,7 +3173,8 @@ function moveToLineBoundary(view, start, forward, includeWrap) {
3255
3173
  : view.coordsAtPos(start.assoc < 0 && start.head > line.from ? start.head - 1 : start.head);
3256
3174
  if (coords) {
3257
3175
  let editorRect = view.dom.getBoundingClientRect();
3258
- let pos = view.posAtCoords({ x: forward == (view.textDirection == exports.Direction.LTR) ? editorRect.right - 1 : editorRect.left + 1,
3176
+ let direction = view.textDirectionAt(line.from);
3177
+ let pos = view.posAtCoords({ x: forward == (direction == exports.Direction.LTR) ? editorRect.right - 1 : editorRect.left + 1,
3259
3178
  y: (coords.top + coords.bottom) / 2 });
3260
3179
  if (pos != null)
3261
3180
  return state.EditorSelection.cursor(pos, forward ? -1 : 1);
@@ -3266,8 +3185,9 @@ function moveToLineBoundary(view, start, forward, includeWrap) {
3266
3185
  }
3267
3186
  function moveByChar(view, start, forward, by) {
3268
3187
  let line = view.state.doc.lineAt(start.head), spans = view.bidiSpans(line);
3188
+ let direction = view.textDirectionAt(line.from);
3269
3189
  for (let cur = start, check = null;;) {
3270
- let next = moveVisually(line, spans, view.textDirection, cur, forward), char = movedOver;
3190
+ let next = moveVisually(line, spans, direction, cur, forward), char = movedOver;
3271
3191
  if (!next) {
3272
3192
  if (line.number == (forward ? view.state.doc.lines : 1))
3273
3193
  return cur;
@@ -3310,7 +3230,7 @@ function moveVertically(view, start, forward, distance) {
3310
3230
  startY = dir < 0 ? startCoords.top : startCoords.bottom;
3311
3231
  }
3312
3232
  else {
3313
- let line = view.viewState.lineBlockAt(startPos - docTop);
3233
+ let line = view.viewState.lineBlockAt(startPos);
3314
3234
  if (goal == null)
3315
3235
  goal = Math.min(rect.right - rect.left, view.defaultCharacterWidth * (startPos - line.from));
3316
3236
  startY = (dir < 0 ? line.top : line.bottom) + docTop;
@@ -3325,7 +3245,7 @@ function moveVertically(view, start, forward, distance) {
3325
3245
  }
3326
3246
  }
3327
3247
  function skipAtoms(view, oldPos, pos) {
3328
- let atoms = view.pluginField(PluginField.atomicRanges);
3248
+ let atoms = view.state.facet(atomicRanges).map(f => f(view));
3329
3249
  for (;;) {
3330
3250
  let moved = false;
3331
3251
  for (let set of atoms) {
@@ -3373,10 +3293,10 @@ class InputState {
3373
3293
  for (let type in handlers) {
3374
3294
  let handler = handlers[type];
3375
3295
  view.contentDOM.addEventListener(type, (event) => {
3376
- if (type == "keydown" && this.keydown(view, event))
3377
- return;
3378
3296
  if (!eventBelongsToEditor(view, event) || this.ignoreDuringComposition(event))
3379
3297
  return;
3298
+ if (type == "keydown" && this.keydown(view, event))
3299
+ return;
3380
3300
  if (this.mustFlushObserver(event))
3381
3301
  view.observer.forceFlush();
3382
3302
  if (this.runCustomHandlers(type, view, event))
@@ -3387,7 +3307,6 @@ class InputState {
3387
3307
  this.registeredEvents.push(type);
3388
3308
  }
3389
3309
  this.notifiedFocused = view.hasFocus;
3390
- this.ensureHandlers(view);
3391
3310
  // On Safari adding an input event handler somehow prevents an
3392
3311
  // issue where the composition vanishes when you press enter.
3393
3312
  if (browser.safari)
@@ -3397,20 +3316,23 @@ class InputState {
3397
3316
  this.lastSelectionOrigin = origin;
3398
3317
  this.lastSelectionTime = Date.now();
3399
3318
  }
3400
- ensureHandlers(view) {
3401
- let handlers = this.customHandlers = view.pluginField(domEventHandlers);
3402
- for (let set of handlers) {
3403
- for (let type in set.handlers)
3404
- if (this.registeredEvents.indexOf(type) < 0 && type != "scroll") {
3405
- this.registeredEvents.push(type);
3406
- view.contentDOM.addEventListener(type, (event) => {
3407
- if (!eventBelongsToEditor(view, event))
3408
- return;
3409
- if (this.runCustomHandlers(type, view, event))
3410
- event.preventDefault();
3411
- });
3412
- }
3413
- }
3319
+ ensureHandlers(view, plugins) {
3320
+ var _a;
3321
+ let handlers;
3322
+ for (let plugin of plugins)
3323
+ if (handlers = (_a = plugin.update(view).spec) === null || _a === void 0 ? void 0 : _a.domEventHandlers) {
3324
+ this.customHandlers.push({ plugin: plugin.value, handlers });
3325
+ for (let type in handlers)
3326
+ if (this.registeredEvents.indexOf(type) < 0 && type != "scroll") {
3327
+ this.registeredEvents.push(type);
3328
+ view.contentDOM.addEventListener(type, (event) => {
3329
+ if (!eventBelongsToEditor(view, event))
3330
+ return;
3331
+ if (this.runCustomHandlers(type, view, event))
3332
+ event.preventDefault();
3333
+ });
3334
+ }
3335
+ }
3414
3336
  }
3415
3337
  runCustomHandlers(type, view, event) {
3416
3338
  for (let set of this.customHandlers) {
@@ -3444,7 +3366,7 @@ class InputState {
3444
3366
  // Must always run, even if a custom handler handled the event
3445
3367
  this.lastKeyCode = event.keyCode;
3446
3368
  this.lastKeyTime = Date.now();
3447
- if (this.screenKeyEvent(view, event))
3369
+ if (event.keyCode == 9 && Date.now() < this.lastEscPress + 2000)
3448
3370
  return true;
3449
3371
  // Chrome for Android usually doesn't fire proper key events, but
3450
3372
  // occasionally does, usually surrounded by a bunch of complicated
@@ -3488,20 +3410,12 @@ class InputState {
3488
3410
  // compositionend and keydown events are sometimes emitted in the
3489
3411
  // wrong order. The key event should still be ignored, even when
3490
3412
  // it happens after the compositionend event.
3491
- if (browser.safari && Date.now() - this.compositionEndedAt < 500) {
3413
+ if (browser.safari && Date.now() - this.compositionEndedAt < 100) {
3492
3414
  this.compositionEndedAt = 0;
3493
3415
  return true;
3494
3416
  }
3495
3417
  return false;
3496
3418
  }
3497
- screenKeyEvent(view, event) {
3498
- let protectedTab = event.keyCode == 9 && Date.now() < this.lastEscPress + 2000;
3499
- if (event.keyCode == 27)
3500
- this.lastEscPress = Date.now();
3501
- else if (modifierCodes.indexOf(event.keyCode) < 0)
3502
- this.lastEscPress = 0;
3503
- return protectedTab;
3504
- }
3505
3419
  mustFlushObserver(event) {
3506
3420
  return (event.type == "keydown" && event.keyCode != 229) ||
3507
3421
  event.type == "compositionend" && !browser.ios;
@@ -3675,6 +3589,10 @@ function doPaste(view, input) {
3675
3589
  }
3676
3590
  handlers.keydown = (view, event) => {
3677
3591
  view.inputState.setSelectionOrigin("select");
3592
+ if (event.keyCode == 27)
3593
+ view.inputState.lastEscPress = Date.now();
3594
+ else if (modifierCodes.indexOf(event.keyCode) < 0)
3595
+ view.inputState.lastEscPress = 0;
3678
3596
  };
3679
3597
  let lastTouch = 0;
3680
3598
  handlers.touchstart = (view, e) => {
@@ -3932,14 +3850,6 @@ handlers.focus = handlers.blur = view => {
3932
3850
  view.update([]);
3933
3851
  }, 10);
3934
3852
  };
3935
- handlers.beforeprint = view => {
3936
- view.viewState.printing = true;
3937
- view.requestMeasure();
3938
- setTimeout(() => {
3939
- view.viewState.printing = false;
3940
- view.requestMeasure();
3941
- }, 2000);
3942
- };
3943
3853
  function forceClearComposition(view, rapid) {
3944
3854
  if (view.docView.compositionDeco.size) {
3945
3855
  view.inputState.rapidCompositionStart = rapid;
@@ -4006,9 +3916,8 @@ handlers.beforeinput = (view, event) => {
4006
3916
  const wrappingWhiteSpace = ["pre-wrap", "normal", "pre-line", "break-spaces"];
4007
3917
  class HeightOracle {
4008
3918
  constructor() {
4009
- this.doc = text.Text.empty;
3919
+ this.doc = state.Text.empty;
4010
3920
  this.lineWrapping = false;
4011
- this.direction = exports.Direction.LTR;
4012
3921
  this.heightSamples = {};
4013
3922
  this.lineHeight = 14;
4014
3923
  this.charWidth = 7;
@@ -4029,8 +3938,8 @@ class HeightOracle {
4029
3938
  return lines * this.lineHeight;
4030
3939
  }
4031
3940
  setDoc(doc) { this.doc = doc; return this; }
4032
- mustRefreshForStyle(whiteSpace, direction) {
4033
- return (wrappingWhiteSpace.indexOf(whiteSpace) > -1) != this.lineWrapping || this.direction != direction;
3941
+ mustRefreshForWrapping(whiteSpace) {
3942
+ return (wrappingWhiteSpace.indexOf(whiteSpace) > -1) != this.lineWrapping;
4034
3943
  }
4035
3944
  mustRefreshForHeights(lineHeights) {
4036
3945
  let newHeight = false;
@@ -4046,13 +3955,10 @@ class HeightOracle {
4046
3955
  }
4047
3956
  return newHeight;
4048
3957
  }
4049
- refresh(whiteSpace, direction, lineHeight, charWidth, lineLength, knownHeights) {
3958
+ refresh(whiteSpace, lineHeight, charWidth, lineLength, knownHeights) {
4050
3959
  let lineWrapping = wrappingWhiteSpace.indexOf(whiteSpace) > -1;
4051
- let changed = Math.round(lineHeight) != Math.round(this.lineHeight) ||
4052
- this.lineWrapping != lineWrapping ||
4053
- this.direction != direction;
3960
+ let changed = Math.round(lineHeight) != Math.round(this.lineHeight) || this.lineWrapping != lineWrapping;
4054
3961
  this.lineWrapping = lineWrapping;
4055
- this.direction = direction;
4056
3962
  this.lineHeight = lineHeight;
4057
3963
  this.charWidth = charWidth;
4058
3964
  this.lineLength = lineLength;
@@ -4133,12 +4039,6 @@ class BlockInfo {
4133
4039
  .concat(Array.isArray(other.type) ? other.type : [other]);
4134
4040
  return new BlockInfo(this.from, this.length + other.length, this.top, this.height + other.height, detail);
4135
4041
  }
4136
- /**
4137
- FIXME remove on next breaking release @internal
4138
- */
4139
- moveY(offset) {
4140
- 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);
4141
- }
4142
4042
  }
4143
4043
  var QueryType;
4144
4044
  (function (QueryType) {
@@ -4263,8 +4163,9 @@ class HeightMapBlock extends HeightMap {
4263
4163
  lineAt(_value, _type, doc, top, offset) {
4264
4164
  return this.blockAt(0, doc, top, offset);
4265
4165
  }
4266
- forEachLine(_from, _to, doc, top, offset, f) {
4267
- f(this.blockAt(0, doc, top, offset));
4166
+ forEachLine(from, to, doc, top, offset, f) {
4167
+ if (from <= offset + this.length && to >= offset)
4168
+ f(this.blockAt(0, doc, top, offset));
4268
4169
  }
4269
4170
  updateHeight(oracle, offset = 0, _force = false, measured) {
4270
4171
  if (measured && measured.from <= offset && measured.more)
@@ -4646,13 +4547,13 @@ class NodeBuilder {
4646
4547
  // to each other.
4647
4548
  static build(oracle, decorations, from, to) {
4648
4549
  let builder = new NodeBuilder(from, oracle);
4649
- rangeset.RangeSet.spans(decorations, from, to, builder, 0);
4550
+ state.RangeSet.spans(decorations, from, to, builder, 0);
4650
4551
  return builder.finish(from);
4651
4552
  }
4652
4553
  }
4653
4554
  function heightRelevantDecoChanges(a, b, diff) {
4654
4555
  let comp = new DecorationComparator;
4655
- rangeset.RangeSet.compare(a, b, diff, comp, 0);
4556
+ state.RangeSet.compare(a, b, diff, comp, 0);
4656
4557
  return comp.changes;
4657
4558
  }
4658
4559
  class DecorationComparator {
@@ -4695,6 +4596,11 @@ function visiblePixelRange(dom, paddingTop) {
4695
4596
  return { left: left - rect.left, right: Math.max(left, right) - rect.left,
4696
4597
  top: top - (rect.top + paddingTop), bottom: Math.max(top, bottom) - (rect.top + paddingTop) };
4697
4598
  }
4599
+ function fullPixelRange(dom, paddingTop) {
4600
+ let rect = dom.getBoundingClientRect();
4601
+ return { left: 0, right: rect.right - rect.left,
4602
+ top: paddingTop, bottom: rect.bottom - (rect.top + paddingTop) };
4603
+ }
4698
4604
  // Line gaps are placeholder widgets used to hide pieces of overlong
4699
4605
  // lines within the viewport, as a kludge to keep the editor
4700
4606
  // responsive when a ridiculously long line is loaded into it.
@@ -4740,8 +4646,8 @@ class LineGapWidget extends WidgetType {
4740
4646
  get estimatedHeight() { return this.vertical ? this.size : -1; }
4741
4647
  }
4742
4648
  class ViewState {
4743
- constructor(state) {
4744
- this.state = state;
4649
+ constructor(state$1) {
4650
+ this.state = state$1;
4745
4651
  // These are contentDOM-local coordinates
4746
4652
  this.pixelViewport = { left: 0, right: window.innerWidth, top: 0, bottom: 0 };
4747
4653
  this.inView = true;
@@ -4760,6 +4666,7 @@ class ViewState {
4760
4666
  // Flag set when editor content was redrawn, so that the next
4761
4667
  // measure stage knows it must read DOM layout
4762
4668
  this.mustMeasureContent = true;
4669
+ this.defaultTextDirection = exports.Direction.RTL;
4763
4670
  this.visibleRanges = [];
4764
4671
  // Cursor 'assoc' is only significant when the cursor is on a line
4765
4672
  // wrap point, where it must stick to the character that it is
@@ -4770,7 +4677,8 @@ class ViewState {
4770
4677
  // boundary and, if so, reset it to make sure it is positioned in
4771
4678
  // the right place.
4772
4679
  this.mustEnforceCursorAssoc = false;
4773
- this.heightMap = HeightMap.empty().applyChanges(state.facet(decorations), text.Text.empty, this.heightOracle.setDoc(state.doc), [new ChangedRange(0, 0, 0, state.doc.length)]);
4680
+ this.stateDeco = state$1.facet(decorations).filter(d => typeof d != "function");
4681
+ this.heightMap = HeightMap.empty().applyChanges(this.stateDeco, state.Text.empty, this.heightOracle.setDoc(state$1.doc), [new ChangedRange(0, 0, 0, state$1.doc.length)]);
4774
4682
  this.viewport = this.getViewport(0, null);
4775
4683
  this.updateViewportLines();
4776
4684
  this.updateForViewport();
@@ -4798,13 +4706,13 @@ class ViewState {
4798
4706
  });
4799
4707
  }
4800
4708
  update(update, scrollTarget = null) {
4801
- let prev = this.state;
4802
4709
  this.state = update.state;
4803
- let newDeco = this.state.facet(decorations);
4710
+ let prevDeco = this.stateDeco;
4711
+ this.stateDeco = this.state.facet(decorations).filter(d => typeof d != "function");
4804
4712
  let contentChanges = update.changedRanges;
4805
- let heightChanges = ChangedRange.extendWithRanges(contentChanges, heightRelevantDecoChanges(update.startState.facet(decorations), newDeco, update ? update.changes : state.ChangeSet.empty(this.state.doc.length)));
4713
+ let heightChanges = ChangedRange.extendWithRanges(contentChanges, heightRelevantDecoChanges(prevDeco, this.stateDeco, update ? update.changes : state.ChangeSet.empty(this.state.doc.length)));
4806
4714
  let prevHeight = this.heightMap.height;
4807
- this.heightMap = this.heightMap.applyChanges(newDeco, prev.doc, this.heightOracle.setDoc(this.state.doc), heightChanges);
4715
+ this.heightMap = this.heightMap.applyChanges(this.stateDeco, update.startState.doc, this.heightOracle.setDoc(this.state.doc), heightChanges);
4808
4716
  if (this.heightMap.height != prevHeight)
4809
4717
  update.flags |= 2 /* Height */;
4810
4718
  let viewport = heightChanges.length ? this.mapViewport(this.viewport, update.changes) : this.viewport;
@@ -4829,8 +4737,9 @@ class ViewState {
4829
4737
  measure(view) {
4830
4738
  let dom = view.contentDOM, style = window.getComputedStyle(dom);
4831
4739
  let oracle = this.heightOracle;
4832
- let whiteSpace = style.whiteSpace, direction = style.direction == "rtl" ? exports.Direction.RTL : exports.Direction.LTR;
4833
- let refresh = this.heightOracle.mustRefreshForStyle(whiteSpace, direction);
4740
+ let whiteSpace = style.whiteSpace;
4741
+ this.defaultTextDirection = style.direction == "rtl" ? exports.Direction.RTL : exports.Direction.LTR;
4742
+ let refresh = this.heightOracle.mustRefreshForWrapping(whiteSpace);
4834
4743
  let measureContent = refresh || this.mustMeasureContent || this.contentDOMHeight != dom.clientHeight;
4835
4744
  let result = 0, bias = 0;
4836
4745
  if (this.editorWidth != view.scrollDOM.clientWidth) {
@@ -4851,8 +4760,7 @@ class ViewState {
4851
4760
  }
4852
4761
  }
4853
4762
  // Pixel viewport
4854
- let pixelViewport = this.printing ? { top: -1e8, bottom: 1e8, left: -1e8, right: 1e8 }
4855
- : visiblePixelRange(dom, this.paddingTop);
4763
+ let pixelViewport = (this.printing ? fullPixelRange : visiblePixelRange)(dom, this.paddingTop);
4856
4764
  let dTop = pixelViewport.top - this.pixelViewport.top, dBottom = pixelViewport.bottom - this.pixelViewport.bottom;
4857
4765
  this.pixelViewport = pixelViewport;
4858
4766
  let inView = this.pixelViewport.bottom > this.pixelViewport.top && this.pixelViewport.right > this.pixelViewport.left;
@@ -4870,12 +4778,12 @@ class ViewState {
4870
4778
  result |= 8 /* Geometry */;
4871
4779
  }
4872
4780
  if (measureContent) {
4873
- let lineHeights = view.docView.measureVisibleLineHeights();
4781
+ let lineHeights = view.docView.measureVisibleLineHeights(this.viewport);
4874
4782
  if (oracle.mustRefreshForHeights(lineHeights))
4875
4783
  refresh = true;
4876
4784
  if (refresh || oracle.lineWrapping && Math.abs(contentWidth - this.contentDOMWidth) > oracle.charWidth) {
4877
4785
  let { lineHeight, charWidth } = view.docView.measureTextSize();
4878
- refresh = oracle.refresh(whiteSpace, direction, lineHeight, charWidth, contentWidth / charWidth, lineHeights);
4786
+ refresh = oracle.refresh(whiteSpace, lineHeight, charWidth, contentWidth / charWidth, lineHeights);
4879
4787
  if (refresh) {
4880
4788
  view.docView.minWidth = 0;
4881
4789
  result |= 8 /* Geometry */;
@@ -4886,7 +4794,10 @@ class ViewState {
4886
4794
  else if (dTop < 0 && dBottom < 0)
4887
4795
  bias = Math.min(dTop, dBottom);
4888
4796
  oracle.heightChanged = false;
4889
- this.heightMap = this.heightMap.updateHeight(oracle, 0, refresh, new MeasuredHeights(this.viewport.from, lineHeights));
4797
+ for (let vp of this.viewports) {
4798
+ let heights = vp.from == this.viewport.from ? lineHeights : view.docView.measureVisibleLineHeights(vp);
4799
+ this.heightMap = this.heightMap.updateHeight(oracle, 0, refresh, new MeasuredHeights(vp.from, heights));
4800
+ }
4890
4801
  if (oracle.heightChanged)
4891
4802
  result |= 2 /* Height */;
4892
4803
  }
@@ -4972,12 +4883,12 @@ class ViewState {
4972
4883
  ensureLineGaps(current) {
4973
4884
  let gaps = [];
4974
4885
  // This won't work at all in predominantly right-to-left text.
4975
- if (this.heightOracle.direction != exports.Direction.LTR)
4886
+ if (this.defaultTextDirection != exports.Direction.LTR)
4976
4887
  return gaps;
4977
4888
  for (let line of this.viewportLines) {
4978
4889
  if (line.length < 4000 /* DoubleMargin */)
4979
4890
  continue;
4980
- let structure = lineStructure(line.from, line.to, this.state);
4891
+ let structure = lineStructure(line.from, line.to, this.stateDeco);
4981
4892
  if (structure.total < 4000 /* DoubleMargin */)
4982
4893
  continue;
4983
4894
  let viewFrom, viewTo;
@@ -5028,11 +4939,11 @@ class ViewState {
5028
4939
  }
5029
4940
  }
5030
4941
  computeVisibleRanges() {
5031
- let deco = this.state.facet(decorations);
4942
+ let deco = this.stateDeco;
5032
4943
  if (this.lineGaps.length)
5033
4944
  deco = deco.concat(this.lineGapDeco);
5034
4945
  let ranges = [];
5035
- rangeset.RangeSet.spans(deco, this.viewport.from, this.viewport.to, {
4946
+ state.RangeSet.spans(deco, this.viewport.from, this.viewport.to, {
5036
4947
  span(from, to) { ranges.push({ from, to }); },
5037
4948
  point() { }
5038
4949
  }, 20);
@@ -5064,9 +4975,9 @@ class Viewport {
5064
4975
  this.to = to;
5065
4976
  }
5066
4977
  }
5067
- function lineStructure(from, to, state) {
4978
+ function lineStructure(from, to, stateDeco) {
5068
4979
  let ranges = [], pos = from, total = 0;
5069
- rangeset.RangeSet.spans(state.facet(decorations), from, to, {
4980
+ state.RangeSet.spans(stateDeco, from, to, {
5070
4981
  span() { },
5071
4982
  point(from, to) {
5072
4983
  if (from > pos) {
@@ -5199,7 +5110,7 @@ function buildTheme(main, spec, scopes) {
5199
5110
  }
5200
5111
  });
5201
5112
  }
5202
- const baseTheme = buildTheme("." + baseThemeID, {
5113
+ const baseTheme$1 = buildTheme("." + baseThemeID, {
5203
5114
  "&.cm-editor": {
5204
5115
  position: "relative !important",
5205
5116
  boxSizing: "border-box",
@@ -5304,6 +5215,65 @@ const baseTheme = buildTheme("." + baseThemeID, {
5304
5215
  "&dark .cm-activeLine": { backgroundColor: "#223039" },
5305
5216
  "&light .cm-specialChar": { color: "red" },
5306
5217
  "&dark .cm-specialChar": { color: "#f78" },
5218
+ ".cm-gutters": {
5219
+ display: "flex",
5220
+ height: "100%",
5221
+ boxSizing: "border-box",
5222
+ left: 0,
5223
+ zIndex: 200
5224
+ },
5225
+ "&light .cm-gutters": {
5226
+ backgroundColor: "#f5f5f5",
5227
+ color: "#6c6c6c",
5228
+ borderRight: "1px solid #ddd"
5229
+ },
5230
+ "&dark .cm-gutters": {
5231
+ backgroundColor: "#333338",
5232
+ color: "#ccc"
5233
+ },
5234
+ ".cm-gutter": {
5235
+ display: "flex !important",
5236
+ flexDirection: "column",
5237
+ flexShrink: 0,
5238
+ boxSizing: "border-box",
5239
+ minHeight: "100%",
5240
+ overflow: "hidden"
5241
+ },
5242
+ ".cm-gutterElement": {
5243
+ boxSizing: "border-box"
5244
+ },
5245
+ ".cm-lineNumbers .cm-gutterElement": {
5246
+ padding: "0 3px 0 5px",
5247
+ minWidth: "20px",
5248
+ textAlign: "right",
5249
+ whiteSpace: "nowrap"
5250
+ },
5251
+ "&light .cm-activeLineGutter": {
5252
+ backgroundColor: "#e2f2ff"
5253
+ },
5254
+ "&dark .cm-activeLineGutter": {
5255
+ backgroundColor: "#222227"
5256
+ },
5257
+ ".cm-panels": {
5258
+ boxSizing: "border-box",
5259
+ position: "sticky",
5260
+ left: 0,
5261
+ right: 0
5262
+ },
5263
+ "&light .cm-panels": {
5264
+ backgroundColor: "#f5f5f5",
5265
+ color: "black"
5266
+ },
5267
+ "&light .cm-panels-top": {
5268
+ borderBottom: "1px solid #ddd"
5269
+ },
5270
+ "&light .cm-panels-bottom": {
5271
+ borderTop: "1px solid #ddd"
5272
+ },
5273
+ "&dark .cm-panels": {
5274
+ backgroundColor: "#333338",
5275
+ color: "white"
5276
+ },
5307
5277
  ".cm-tab": {
5308
5278
  display: "inline-block",
5309
5279
  overflow: "hidden",
@@ -5429,6 +5399,7 @@ class DOMObserver {
5429
5399
  });
5430
5400
  this.resize.observe(view.scrollDOM);
5431
5401
  }
5402
+ window.addEventListener("beforeprint", this.onPrint = this.onPrint.bind(this));
5432
5403
  this.start();
5433
5404
  window.addEventListener("scroll", this.onScroll = this.onScroll.bind(this));
5434
5405
  if (typeof IntersectionObserver == "function") {
@@ -5463,6 +5434,14 @@ class DOMObserver {
5463
5434
  this.view.requestMeasure();
5464
5435
  }, 50);
5465
5436
  }
5437
+ onPrint() {
5438
+ this.view.viewState.printing = true;
5439
+ this.view.measure();
5440
+ setTimeout(() => {
5441
+ this.view.viewState.printing = false;
5442
+ this.view.requestMeasure();
5443
+ }, 500);
5444
+ }
5466
5445
  updateGaps(gaps) {
5467
5446
  if (this.gapIntersection && (gaps.length != this.gaps.length || this.gaps.some((g, i) => g != gaps[i]))) {
5468
5447
  this.gapIntersection.disconnect();
@@ -5680,6 +5659,7 @@ class DOMObserver {
5680
5659
  dom.removeEventListener("scroll", this.onScroll);
5681
5660
  window.removeEventListener("scroll", this.onScroll);
5682
5661
  window.removeEventListener("resize", this.onResize);
5662
+ window.removeEventListener("beforeprint", this.onPrint);
5683
5663
  this.dom.ownerDocument.removeEventListener("selectionchange", this.onSelectionChange);
5684
5664
  clearTimeout(this.parentCheck);
5685
5665
  clearTimeout(this.resizeTimeout);
@@ -5942,9 +5922,9 @@ transactions for editing actions.
5942
5922
  */
5943
5923
  class EditorView {
5944
5924
  /**
5945
- Construct a new view. You'll usually want to put `view.dom` into
5946
- your document after creating a view, so that the user can see
5947
- it.
5925
+ Construct a new view. You'll want to either provide a `parent`
5926
+ option, or put `view.dom` into your document after creating a
5927
+ view, so that the user can see the editor.
5948
5928
  */
5949
5929
  constructor(
5950
5930
  /**
@@ -5995,6 +5975,7 @@ class EditorView {
5995
5975
  this.measure();
5996
5976
  });
5997
5977
  this.inputState = new InputState(this);
5978
+ this.inputState.ensureHandlers(this, this.plugins);
5998
5979
  this.docView = new DocView(this);
5999
5980
  this.mountStyles();
6000
5981
  this.updateAttrs();
@@ -6082,14 +6063,9 @@ class EditorView {
6082
6063
  let { main } = tr.state.selection;
6083
6064
  scrollTarget = new ScrollTarget(main.empty ? main : state.EditorSelection.cursor(main.head, main.head > main.anchor ? -1 : 1));
6084
6065
  }
6085
- for (let e of tr.effects) {
6086
- if (e.is(scrollTo))
6087
- scrollTarget = new ScrollTarget(e.value);
6088
- else if (e.is(centerOn))
6089
- scrollTarget = new ScrollTarget(e.value, "center");
6090
- else if (e.is(scrollIntoView))
6066
+ for (let e of tr.effects)
6067
+ if (e.is(scrollIntoView))
6091
6068
  scrollTarget = e.value;
6092
- }
6093
6069
  }
6094
6070
  this.viewState.update(update, scrollTarget);
6095
6071
  this.bidiCache = CachedOrder.update(this.bidiCache, update.changes);
@@ -6140,7 +6116,7 @@ class EditorView {
6140
6116
  for (let plugin of this.plugins)
6141
6117
  plugin.update(this);
6142
6118
  this.docView = new DocView(this);
6143
- this.inputState.ensureHandlers(this);
6119
+ this.inputState.ensureHandlers(this, this.plugins);
6144
6120
  this.mountStyles();
6145
6121
  this.updateAttrs();
6146
6122
  this.bidiCache = [];
@@ -6172,7 +6148,7 @@ class EditorView {
6172
6148
  plugin.destroy(this);
6173
6149
  this.plugins = newPlugins;
6174
6150
  this.pluginMap.clear();
6175
- this.inputState.ensureHandlers(this);
6151
+ this.inputState.ensureHandlers(this, this.plugins);
6176
6152
  }
6177
6153
  else {
6178
6154
  for (let p of this.plugins)
@@ -6310,7 +6286,7 @@ class EditorView {
6310
6286
  }
6311
6287
  mountStyles() {
6312
6288
  this.styleModules = this.state.facet(styleModule);
6313
- styleMod.StyleModule.mount(this.root, this.styleModules.concat(baseTheme).reverse());
6289
+ styleMod.StyleModule.mount(this.root, this.styleModules.concat(baseTheme$1).reverse());
6314
6290
  }
6315
6291
  readMeasured() {
6316
6292
  if (this.updateState == 2 /* Updating */)
@@ -6341,16 +6317,6 @@ class EditorView {
6341
6317
  }
6342
6318
  }
6343
6319
  /**
6344
- Collect all values provided by the active plugins for a given
6345
- field.
6346
- */
6347
- pluginField(field) {
6348
- let result = [];
6349
- for (let plugin of this.plugins)
6350
- plugin.update(this).takeField(field, result);
6351
- return result;
6352
- }
6353
- /**
6354
6320
  Get the value of a specific plugin, if present. Note that
6355
6321
  plugins that crash can be dropped from a view, so even when you
6356
6322
  know you registered a given plugin, it is recommended to check
@@ -6377,23 +6343,6 @@ class EditorView {
6377
6343
  return { top: this.viewState.paddingTop, bottom: this.viewState.paddingBottom };
6378
6344
  }
6379
6345
  /**
6380
- Find the line or block widget at the given vertical position.
6381
-
6382
- By default, this position is interpreted as a screen position,
6383
- meaning `docTop` is set to the DOM top position of the editor
6384
- content (forcing a layout). You can pass a different `docTop`
6385
- value—for example 0 to interpret `height` as a document-relative
6386
- position, or a precomputed document top
6387
- (`view.contentDOM.getBoundingClientRect().top`) to limit layout
6388
- queries.
6389
-
6390
- *Deprecated: use `elementAtHeight` instead.*
6391
- */
6392
- blockAtHeight(height, docTop) {
6393
- let top = ensureTop(docTop, this);
6394
- return this.elementAtHeight(height - top).moveY(top);
6395
- }
6396
- /**
6397
6346
  Find the text line or block widget at the given vertical
6398
6347
  position (which is interpreted as relative to the [top of the
6399
6348
  document](https://codemirror.net/6/docs/ref/#view.EditorView.documentTop)
@@ -6403,23 +6352,6 @@ class EditorView {
6403
6352
  return this.viewState.elementAtHeight(height);
6404
6353
  }
6405
6354
  /**
6406
- Find information for the visual line (see
6407
- [`visualLineAt`](https://codemirror.net/6/docs/ref/#view.EditorView.visualLineAt)) at the given
6408
- vertical position. The resulting block info might hold another
6409
- array of block info structs in its `type` field if this line
6410
- consists of more than one block.
6411
-
6412
- Defaults to treating `height` as a screen position. See
6413
- [`blockAtHeight`](https://codemirror.net/6/docs/ref/#view.EditorView.blockAtHeight) for the
6414
- interpretation of the `docTop` parameter.
6415
-
6416
- *Deprecated: use `lineBlockAtHeight` instead.*
6417
- */
6418
- visualLineAtHeight(height, docTop) {
6419
- let top = ensureTop(docTop, this);
6420
- return this.lineBlockAtHeight(height - top).moveY(top);
6421
- }
6422
- /**
6423
6355
  Find the line block (see
6424
6356
  [`lineBlockAt`](https://codemirror.net/6/docs/ref/#view.EditorView.lineBlockAt) at the given
6425
6357
  height.
@@ -6429,19 +6361,6 @@ class EditorView {
6429
6361
  return this.viewState.lineBlockAtHeight(height);
6430
6362
  }
6431
6363
  /**
6432
- Iterate over the height information of the visual lines in the
6433
- viewport. The heights of lines are reported relative to the
6434
- given document top, which defaults to the screen position of the
6435
- document (forcing a layout).
6436
-
6437
- *Deprecated: use `viewportLineBlocks` instead.*
6438
- */
6439
- viewportLines(f, docTop) {
6440
- let top = ensureTop(docTop, this);
6441
- for (let line of this.viewportLineBlocks)
6442
- f(line.moveY(top));
6443
- }
6444
- /**
6445
6364
  Get the extent and vertical position of all [line
6446
6365
  blocks](https://codemirror.net/6/docs/ref/#view.EditorView.lineBlockAt) in the viewport. Positions
6447
6366
  are relative to the [top of the
@@ -6451,24 +6370,9 @@ class EditorView {
6451
6370
  return this.viewState.viewportLines;
6452
6371
  }
6453
6372
  /**
6454
- Find the extent and height of the visual line (a range delimited
6455
- on both sides by either non-[hidden](https://codemirror.net/6/docs/ref/#view.Decoration^range)
6456
- line breaks, or the start/end of the document) at the given position.
6457
-
6458
- Vertical positions are computed relative to the `docTop`
6459
- argument, which defaults to 0 for this method. You can pass
6460
- `view.contentDOM.getBoundingClientRect().top` here to get screen
6461
- coordinates.
6462
-
6463
- *Deprecated: use `lineBlockAt` instead.*
6464
- */
6465
- visualLineAt(pos, docTop = 0) {
6466
- return this.lineBlockAt(pos).moveY(docTop + this.viewState.paddingTop);
6467
- }
6468
- /**
6469
6373
  Find the line block around the given document position. A line
6470
6374
  block is a range delimited on both sides by either a
6471
- non-[hidden](https://codemirror.net/6/docs/ref/#view.Decoration^range) line breaks, or the
6375
+ non-[hidden](https://codemirror.net/6/docs/ref/#view.Decoration^replace) line breaks, or the
6472
6376
  start/end of the document. It will usually just hold a line of
6473
6377
  text, but may be broken into multiple textblocks by block
6474
6378
  widgets.
@@ -6484,13 +6388,13 @@ class EditorView {
6484
6388
  }
6485
6389
  /**
6486
6390
  Move a cursor position by [grapheme
6487
- cluster](https://codemirror.net/6/docs/ref/#text.findClusterBreak). `forward` determines whether
6488
- the motion is away from the line start, or towards it. Motion in
6489
- bidirectional text is in visual order, in the editor's [text
6490
- direction](https://codemirror.net/6/docs/ref/#view.EditorView.textDirection). When the start
6491
- position was the last one on the line, the returned position
6492
- will be across the line break. If there is no further line, the
6493
- original position is returned.
6391
+ cluster](https://codemirror.net/6/docs/ref/#state.findClusterBreak). `forward` determines whether
6392
+ the motion is away from the line start, or towards it. In
6393
+ bidirectional text, the line is traversed in visual order, using
6394
+ the editor's [text direction](https://codemirror.net/6/docs/ref/#view.EditorView.textDirection).
6395
+ When the start position was the last one on the line, the
6396
+ returned position will be across the line break. If there is no
6397
+ further line, the original position is returned.
6494
6398
 
6495
6399
  By default, this method moves over a single cluster. The
6496
6400
  optional `by` argument can be used to move across more. It will
@@ -6535,10 +6439,6 @@ class EditorView {
6535
6439
  moveVertically(start, forward, distance) {
6536
6440
  return skipAtoms(this, start, moveVertically(this, start, forward, distance));
6537
6441
  }
6538
- // FIXME remove on next major version
6539
- scrollPosIntoView(pos) {
6540
- this.dispatch({ effects: scrollTo.of(state.EditorSelection.cursor(pos)) });
6541
- }
6542
6442
  /**
6543
6443
  Find the DOM parent node and offset (child offset if `node` is
6544
6444
  an element, character offset when it is a text node) at the
@@ -6594,9 +6494,25 @@ class EditorView {
6594
6494
  /**
6595
6495
  The text direction
6596
6496
  ([`direction`](https://developer.mozilla.org/en-US/docs/Web/CSS/direction)
6597
- CSS property) of the editor.
6497
+ CSS property) of the editor's content element.
6498
+ */
6499
+ get textDirection() { return this.viewState.defaultTextDirection; }
6500
+ /**
6501
+ Find the text direction of the block at the given position, as
6502
+ assigned by CSS. If
6503
+ [`perLineTextDirection`](https://codemirror.net/6/docs/ref/#view.EditorView^perLineTextDirection)
6504
+ isn't enabled, or the given position is outside of the viewport,
6505
+ this will always return the same as
6506
+ [`textDirection`](https://codemirror.net/6/docs/ref/#view.EditorView.textDirection). Note that
6507
+ this may trigger a DOM layout.
6598
6508
  */
6599
- get textDirection() { return this.viewState.heightOracle.direction; }
6509
+ textDirectionAt(pos) {
6510
+ let perLine = this.state.facet(perLineTextDirection);
6511
+ if (!perLine || pos < this.viewport.from || pos > this.viewport.to)
6512
+ return this.textDirection;
6513
+ this.readMeasured();
6514
+ return this.docView.textDirectionAt(pos);
6515
+ }
6600
6516
  /**
6601
6517
  Whether this editor [wraps lines](https://codemirror.net/6/docs/ref/#view.EditorView.lineWrapping)
6602
6518
  (as determined by the
@@ -6615,11 +6531,11 @@ class EditorView {
6615
6531
  bidiSpans(line) {
6616
6532
  if (line.length > MaxBidiLine)
6617
6533
  return trivialOrder(line.length);
6618
- let dir = this.textDirection;
6534
+ let dir = this.textDirectionAt(line.from);
6619
6535
  for (let entry of this.bidiCache)
6620
6536
  if (entry.from == line.from && entry.dir == dir)
6621
6537
  return entry.order;
6622
- let order = computeOrder(line.text, this.textDirection);
6538
+ let order = computeOrder(line.text, dir);
6623
6539
  this.bidiCache.push(new CachedOrder(line.from, line.to, dir, order));
6624
6540
  return order;
6625
6541
  }
@@ -6670,16 +6586,16 @@ class EditorView {
6670
6586
  return scrollIntoView.of(new ScrollTarget(typeof pos == "number" ? state.EditorSelection.cursor(pos) : pos, options.y, options.x, options.yMargin, options.xMargin));
6671
6587
  }
6672
6588
  /**
6673
- Facet that can be used to add DOM event handlers. The value
6674
- should be an object mapping event names to handler functions. The
6675
- first such function to return true will be assumed to have handled
6676
- that event, and no other handlers or built-in behavior will be
6677
- activated for it.
6678
- These are registered on the [content
6679
- element](https://codemirror.net/6/docs/ref/#view.EditorView.contentDOM), except for `scroll`
6680
- handlers, which will be called any time the editor's [scroll
6681
- element](https://codemirror.net/6/docs/ref/#view.EditorView.scrollDOM) or one of its parent nodes
6682
- is scrolled.
6589
+ Returns an extension that can be used to add DOM event handlers.
6590
+ The value should be an object mapping event names to handler
6591
+ functions. For any given event, such functions are ordered by
6592
+ extension precedence, and the first handler to return true will
6593
+ be assumed to have handled that event, and no other handlers or
6594
+ built-in behavior will be activated for it. These are registered
6595
+ on the [content element](https://codemirror.net/6/docs/ref/#view.EditorView.contentDOM), except
6596
+ for `scroll` handlers, which will be called any time the
6597
+ editor's [scroll element](https://codemirror.net/6/docs/ref/#view.EditorView.scrollDOM) or one of
6598
+ its parent nodes is scrolled.
6683
6599
  */
6684
6600
  static domEventHandlers(handlers) {
6685
6601
  return ViewPlugin.define(() => ({}), { eventHandlers: handlers });
@@ -6721,20 +6637,6 @@ class EditorView {
6721
6637
  }
6722
6638
  }
6723
6639
  /**
6724
- Effect that can be [added](https://codemirror.net/6/docs/ref/#state.TransactionSpec.effects) to a
6725
- transaction to make it scroll the given range into view.
6726
-
6727
- *Deprecated*. Use [`scrollIntoView`](https://codemirror.net/6/docs/ref/#view.EditorView^scrollIntoView) instead.
6728
- */
6729
- EditorView.scrollTo = scrollTo;
6730
- /**
6731
- Effect that makes the editor scroll the given range to the
6732
- center of the visible view.
6733
-
6734
- *Deprecated*. Use [`scrollIntoView`](https://codemirror.net/6/docs/ref/#view.EditorView^scrollIntoView) instead.
6735
- */
6736
- EditorView.centerOn = centerOn;
6737
- /**
6738
6640
  Facet to add a [style
6739
6641
  module](https://github.com/marijnh/style-mod#documentation) to
6740
6642
  an editor view. The view will ensure that the module is
@@ -6751,6 +6653,13 @@ called and the default behavior is prevented.
6751
6653
  */
6752
6654
  EditorView.inputHandler = inputHandler;
6753
6655
  /**
6656
+ By default, the editor assumes all its content has the same
6657
+ [text direction](https://codemirror.net/6/docs/ref/#view.Direction). Configure this with a `true`
6658
+ value to make it read and store the text direction of every
6659
+ (rendered) line separately.
6660
+ */
6661
+ EditorView.perLineTextDirection = perLineTextDirection;
6662
+ /**
6754
6663
  Allows you to provide a function that should be called when the
6755
6664
  library catches an exception from an extension (mostly from view
6756
6665
  plugins, but may be used by other extensions to route exceptions
@@ -6766,9 +6675,9 @@ EditorView.updateListener = updateListener;
6766
6675
  /**
6767
6676
  Facet that controls whether the editor content DOM is editable.
6768
6677
  When its highest-precedence value is `false`, the element will
6769
- not longer have its `contenteditable` attribute set. (Note that
6770
- this doesn't affect API calls that change the editor content,
6771
- even when those are bound to keys or buttons. See the
6678
+ not have its `contenteditable` attribute set. (Note that this
6679
+ doesn't affect API calls that change the editor content, even
6680
+ when those are bound to keys or buttons. See the
6772
6681
  [`readOnly`](https://codemirror.net/6/docs/ref/#state.EditorState.readOnly) facet for that.)
6773
6682
  */
6774
6683
  EditorView.editable = editable;
@@ -6787,18 +6696,45 @@ the drag should move the content.
6787
6696
  */
6788
6697
  EditorView.dragMovesSelection = dragMovesSelection$1;
6789
6698
  /**
6790
- Facet used to configure whether a given selecting click adds
6791
- a new range to the existing selection or replaces it entirely.
6699
+ Facet used to configure whether a given selecting click adds a
6700
+ new range to the existing selection or replaces it entirely. The
6701
+ default behavior is to check `event.metaKey` on macOS, and
6702
+ `event.ctrlKey` elsewhere.
6792
6703
  */
6793
6704
  EditorView.clickAddsSelectionRange = clickAddsSelectionRange;
6794
6705
  /**
6795
6706
  A facet that determines which [decorations](https://codemirror.net/6/docs/ref/#view.Decoration)
6796
- are shown in the view. See also [view
6797
- plugins](https://codemirror.net/6/docs/ref/#view.EditorView^decorations), which have a separate
6798
- mechanism for providing decorations.
6707
+ are shown in the view. Decorations can be provided in two
6708
+ ways—directly, or via a function that takes an editor view.
6709
+
6710
+ Only decoration sets provided directly are allowed to influence
6711
+ the editor's vertical layout structure. The ones provided as
6712
+ functions are called _after_ the new viewport has been computed,
6713
+ and thus **must not** introduce block widgets or replacing
6714
+ decorations that cover line breaks.
6799
6715
  */
6800
6716
  EditorView.decorations = decorations;
6801
6717
  /**
6718
+ Used to provide ranges that should be treated as atoms as far as
6719
+ cursor motion is concerned. This causes methods like
6720
+ [`moveByChar`](https://codemirror.net/6/docs/ref/#view.EditorView.moveByChar) and
6721
+ [`moveVertically`](https://codemirror.net/6/docs/ref/#view.EditorView.moveVertically) (and the
6722
+ commands built on top of them) to skip across such regions when
6723
+ a selection endpoint would enter them. This does _not_ prevent
6724
+ direct programmatic [selection
6725
+ updates](https://codemirror.net/6/docs/ref/#state.TransactionSpec.selection) from moving into such
6726
+ regions.
6727
+ */
6728
+ EditorView.atomicRanges = atomicRanges;
6729
+ /**
6730
+ Facet that allows extensions to provide additional scroll
6731
+ margins (space around the sides of the scrolling element that
6732
+ should be considered invisible). This can be useful when the
6733
+ plugin introduces elements that cover part of that element (for
6734
+ example a horizontally fixed gutter).
6735
+ */
6736
+ EditorView.scrollMargins = scrollMargins;
6737
+ /**
6802
6738
  This facet records whether a dark theme is active. The extension
6803
6739
  returned by [`theme`](https://codemirror.net/6/docs/ref/#view.EditorView^theme) automatically
6804
6740
  includes an instance of this when the `dark` option is set to
@@ -6831,10 +6767,6 @@ search match).
6831
6767
  EditorView.announce = state.StateEffect.define();
6832
6768
  // Maximum line length for which we compute accurate bidi info
6833
6769
  const MaxBidiLine = 4096;
6834
- // FIXME remove this and its callers on next breaking release
6835
- function ensureTop(given, view) {
6836
- return (given == null ? view.contentDOM.getBoundingClientRect().top : given) + view.viewState.paddingTop;
6837
- }
6838
6770
  const BadMeasure = {};
6839
6771
  class CachedOrder {
6840
6772
  constructor(from, to, dir, order) {
@@ -6937,7 +6869,7 @@ function getKeymap(state) {
6937
6869
  }
6938
6870
  /**
6939
6871
  Run the key handlers registered for a given scope. The event
6940
- object should be `"keydown"` event. Returns true if any of the
6872
+ object should be a `"keydown"` event. Returns true if any of the
6941
6873
  handlers handled it.
6942
6874
  */
6943
6875
  function runScopeHandlers(view, event, scope) {
@@ -7417,7 +7349,7 @@ class MatchDecorator {
7417
7349
  plugin.
7418
7350
  */
7419
7351
  createDeco(view) {
7420
- let build = new rangeset.RangeSetBuilder();
7352
+ let build = new state.RangeSetBuilder();
7421
7353
  for (let { from, to } of matchRanges(view, this.maxLength))
7422
7354
  iterMatches(view.state.doc, this.regexp, from, to, (a, b, m) => build.add(a, b, this.getDeco(m, view, a)));
7423
7355
  return build.finish();
@@ -7549,10 +7481,10 @@ function specialCharPlugin() {
7549
7481
  regexp: conf.specialChars,
7550
7482
  decoration: (m, view, pos) => {
7551
7483
  let { doc } = view.state;
7552
- let code = text.codePointAt(m[0], 0);
7484
+ let code = state.codePointAt(m[0], 0);
7553
7485
  if (code == 9) {
7554
7486
  let line = doc.lineAt(pos);
7555
- let size = view.state.tabSize, col = text.countColumn(line.text, size, pos - line.from);
7487
+ let size = view.state.tabSize, col = state.countColumn(line.text, size, pos - line.from);
7556
7488
  return Decoration.replace({ widget: new TabWidget((size - (col % size)) * this.view.defaultCharacterWidth) });
7557
7489
  }
7558
7490
  return this.decorationCache[code] ||
@@ -7714,32 +7646,1333 @@ function placeholder(content) {
7714
7646
  }, { decorations: v => v.decorations });
7715
7647
  }
7716
7648
 
7649
+ // Don't compute precise column positions for line offsets above this
7650
+ // (since it could get expensive). Assume offset==column for them.
7651
+ const MaxOff = 2000;
7652
+ function rectangleFor(state$1, a, b) {
7653
+ let startLine = Math.min(a.line, b.line), endLine = Math.max(a.line, b.line);
7654
+ let ranges = [];
7655
+ if (a.off > MaxOff || b.off > MaxOff || a.col < 0 || b.col < 0) {
7656
+ let startOff = Math.min(a.off, b.off), endOff = Math.max(a.off, b.off);
7657
+ for (let i = startLine; i <= endLine; i++) {
7658
+ let line = state$1.doc.line(i);
7659
+ if (line.length <= endOff)
7660
+ ranges.push(state.EditorSelection.range(line.from + startOff, line.to + endOff));
7661
+ }
7662
+ }
7663
+ else {
7664
+ let startCol = Math.min(a.col, b.col), endCol = Math.max(a.col, b.col);
7665
+ for (let i = startLine; i <= endLine; i++) {
7666
+ let line = state$1.doc.line(i);
7667
+ let start = state.findColumn(line.text, startCol, state$1.tabSize, true);
7668
+ if (start > -1) {
7669
+ let end = state.findColumn(line.text, endCol, state$1.tabSize);
7670
+ ranges.push(state.EditorSelection.range(line.from + start, line.from + end));
7671
+ }
7672
+ }
7673
+ }
7674
+ return ranges;
7675
+ }
7676
+ function absoluteColumn(view, x) {
7677
+ let ref = view.coordsAtPos(view.viewport.from);
7678
+ return ref ? Math.round(Math.abs((ref.left - x) / view.defaultCharacterWidth)) : -1;
7679
+ }
7680
+ function getPos(view, event) {
7681
+ let offset = view.posAtCoords({ x: event.clientX, y: event.clientY }, false);
7682
+ let line = view.state.doc.lineAt(offset), off = offset - line.from;
7683
+ let col = off > MaxOff ? -1
7684
+ : off == line.length ? absoluteColumn(view, event.clientX)
7685
+ : state.countColumn(line.text, view.state.tabSize, offset - line.from);
7686
+ return { line: line.number, col, off };
7687
+ }
7688
+ function rectangleSelectionStyle(view, event) {
7689
+ let start = getPos(view, event), startSel = view.state.selection;
7690
+ if (!start)
7691
+ return null;
7692
+ return {
7693
+ update(update) {
7694
+ if (update.docChanged) {
7695
+ let newStart = update.changes.mapPos(update.startState.doc.line(start.line).from);
7696
+ let newLine = update.state.doc.lineAt(newStart);
7697
+ start = { line: newLine.number, col: start.col, off: Math.min(start.off, newLine.length) };
7698
+ startSel = startSel.map(update.changes);
7699
+ }
7700
+ },
7701
+ get(event, _extend, multiple) {
7702
+ let cur = getPos(view, event);
7703
+ if (!cur)
7704
+ return startSel;
7705
+ let ranges = rectangleFor(view.state, start, cur);
7706
+ if (!ranges.length)
7707
+ return startSel;
7708
+ if (multiple)
7709
+ return state.EditorSelection.create(ranges.concat(startSel.ranges));
7710
+ else
7711
+ return state.EditorSelection.create(ranges);
7712
+ }
7713
+ };
7714
+ }
7717
7715
  /**
7718
- @internal
7716
+ Create an extension that enables rectangular selections. By
7717
+ default, it will react to left mouse drag with the Alt key held
7718
+ down. When such a selection occurs, the text within the rectangle
7719
+ that was dragged over will be selected, as one selection
7720
+ [range](https://codemirror.net/6/docs/ref/#state.SelectionRange) per line.
7719
7721
  */
7720
- const __test = { HeightMap, HeightOracle, MeasuredHeights, QueryType, ChangedRange, computeOrder, moveVisually };
7722
+ function rectangularSelection(options) {
7723
+ let filter = (options === null || options === void 0 ? void 0 : options.eventFilter) || (e => e.altKey && e.button == 0);
7724
+ return EditorView.mouseSelectionStyle.of((view, event) => filter(event) ? rectangleSelectionStyle(view, event) : null);
7725
+ }
7726
+ const keys = {
7727
+ Alt: [18, e => e.altKey],
7728
+ Control: [17, e => e.ctrlKey],
7729
+ Shift: [16, e => e.shiftKey],
7730
+ Meta: [91, e => e.metaKey]
7731
+ };
7732
+ const showCrosshair = { style: "cursor: crosshair" };
7733
+ /**
7734
+ Returns an extension that turns the pointer cursor into a
7735
+ crosshair when a given modifier key, defaulting to Alt, is held
7736
+ down. Can serve as a visual hint that rectangular selection is
7737
+ going to happen when paired with
7738
+ [`rectangularSelection`](https://codemirror.net/6/docs/ref/#view.rectangularSelection).
7739
+ */
7740
+ function crosshairCursor(options = {}) {
7741
+ let [code, getter] = keys[options.key || "Alt"];
7742
+ let plugin = ViewPlugin.fromClass(class {
7743
+ constructor(view) {
7744
+ this.view = view;
7745
+ this.isDown = false;
7746
+ }
7747
+ set(isDown) {
7748
+ if (this.isDown != isDown) {
7749
+ this.isDown = isDown;
7750
+ this.view.update([]);
7751
+ }
7752
+ }
7753
+ }, {
7754
+ eventHandlers: {
7755
+ keydown(e) {
7756
+ this.set(e.keyCode == code || getter(e));
7757
+ },
7758
+ keyup(e) {
7759
+ if (e.keyCode == code || !getter(e))
7760
+ this.set(false);
7761
+ }
7762
+ }
7763
+ });
7764
+ return [
7765
+ plugin,
7766
+ EditorView.contentAttributes.of(view => { var _a; return ((_a = view.plugin(plugin)) === null || _a === void 0 ? void 0 : _a.isDown) ? showCrosshair : null; })
7767
+ ];
7768
+ }
7721
7769
 
7722
- Object.defineProperty(exports, 'Range', {
7723
- enumerable: true,
7724
- get: function () { return rangeset.Range; }
7770
+ const Outside = "-10000px";
7771
+ class TooltipViewManager {
7772
+ constructor(view, facet, createTooltipView) {
7773
+ this.facet = facet;
7774
+ this.createTooltipView = createTooltipView;
7775
+ this.input = view.state.facet(facet);
7776
+ this.tooltips = this.input.filter(t => t);
7777
+ this.tooltipViews = this.tooltips.map(createTooltipView);
7778
+ }
7779
+ update(update) {
7780
+ let input = update.state.facet(this.facet);
7781
+ let tooltips = input.filter(x => x);
7782
+ if (input === this.input) {
7783
+ for (let t of this.tooltipViews)
7784
+ if (t.update)
7785
+ t.update(update);
7786
+ return false;
7787
+ }
7788
+ let tooltipViews = [];
7789
+ for (let i = 0; i < tooltips.length; i++) {
7790
+ let tip = tooltips[i], known = -1;
7791
+ if (!tip)
7792
+ continue;
7793
+ for (let i = 0; i < this.tooltips.length; i++) {
7794
+ let other = this.tooltips[i];
7795
+ if (other && other.create == tip.create)
7796
+ known = i;
7797
+ }
7798
+ if (known < 0) {
7799
+ tooltipViews[i] = this.createTooltipView(tip);
7800
+ }
7801
+ else {
7802
+ let tooltipView = tooltipViews[i] = this.tooltipViews[known];
7803
+ if (tooltipView.update)
7804
+ tooltipView.update(update);
7805
+ }
7806
+ }
7807
+ for (let t of this.tooltipViews)
7808
+ if (tooltipViews.indexOf(t) < 0)
7809
+ t.dom.remove();
7810
+ this.input = input;
7811
+ this.tooltips = tooltips;
7812
+ this.tooltipViews = tooltipViews;
7813
+ return true;
7814
+ }
7815
+ }
7816
+ /**
7817
+ Creates an extension that configures tooltip behavior.
7818
+ */
7819
+ function tooltips(config = {}) {
7820
+ return tooltipConfig.of(config);
7821
+ }
7822
+ function windowSpace() {
7823
+ return { top: 0, left: 0, bottom: innerHeight, right: innerWidth };
7824
+ }
7825
+ const tooltipConfig = state.Facet.define({
7826
+ combine: values => {
7827
+ var _a, _b, _c;
7828
+ return ({
7829
+ position: browser.ios ? "absolute" : ((_a = values.find(conf => conf.position)) === null || _a === void 0 ? void 0 : _a.position) || "fixed",
7830
+ parent: ((_b = values.find(conf => conf.parent)) === null || _b === void 0 ? void 0 : _b.parent) || null,
7831
+ tooltipSpace: ((_c = values.find(conf => conf.tooltipSpace)) === null || _c === void 0 ? void 0 : _c.tooltipSpace) || windowSpace,
7832
+ });
7833
+ }
7834
+ });
7835
+ const tooltipPlugin = ViewPlugin.fromClass(class {
7836
+ constructor(view) {
7837
+ var _a;
7838
+ this.view = view;
7839
+ this.inView = true;
7840
+ this.lastTransaction = 0;
7841
+ this.measureTimeout = -1;
7842
+ let config = view.state.facet(tooltipConfig);
7843
+ this.position = config.position;
7844
+ this.parent = config.parent;
7845
+ this.classes = view.themeClasses;
7846
+ this.createContainer();
7847
+ this.measureReq = { read: this.readMeasure.bind(this), write: this.writeMeasure.bind(this), key: this };
7848
+ this.manager = new TooltipViewManager(view, showTooltip, t => this.createTooltip(t));
7849
+ this.intersectionObserver = typeof IntersectionObserver == "function" ? new IntersectionObserver(entries => {
7850
+ if (Date.now() > this.lastTransaction - 50 &&
7851
+ entries.length > 0 && entries[entries.length - 1].intersectionRatio < 1)
7852
+ this.measureSoon();
7853
+ }, { threshold: [1] }) : null;
7854
+ this.observeIntersection();
7855
+ (_a = view.dom.ownerDocument.defaultView) === null || _a === void 0 ? void 0 : _a.addEventListener("resize", this.measureSoon = this.measureSoon.bind(this));
7856
+ this.maybeMeasure();
7857
+ }
7858
+ createContainer() {
7859
+ if (this.parent) {
7860
+ this.container = document.createElement("div");
7861
+ this.container.style.position = "relative";
7862
+ this.container.className = this.view.themeClasses;
7863
+ this.parent.appendChild(this.container);
7864
+ }
7865
+ else {
7866
+ this.container = this.view.dom;
7867
+ }
7868
+ }
7869
+ observeIntersection() {
7870
+ if (this.intersectionObserver) {
7871
+ this.intersectionObserver.disconnect();
7872
+ for (let tooltip of this.manager.tooltipViews)
7873
+ this.intersectionObserver.observe(tooltip.dom);
7874
+ }
7875
+ }
7876
+ measureSoon() {
7877
+ if (this.measureTimeout < 0)
7878
+ this.measureTimeout = setTimeout(() => {
7879
+ this.measureTimeout = -1;
7880
+ this.maybeMeasure();
7881
+ }, 50);
7882
+ }
7883
+ update(update) {
7884
+ if (update.transactions.length)
7885
+ this.lastTransaction = Date.now();
7886
+ let updated = this.manager.update(update);
7887
+ if (updated)
7888
+ this.observeIntersection();
7889
+ let shouldMeasure = updated || update.geometryChanged;
7890
+ let newConfig = update.state.facet(tooltipConfig);
7891
+ if (newConfig.position != this.position) {
7892
+ this.position = newConfig.position;
7893
+ for (let t of this.manager.tooltipViews)
7894
+ t.dom.style.position = this.position;
7895
+ shouldMeasure = true;
7896
+ }
7897
+ if (newConfig.parent != this.parent) {
7898
+ if (this.parent)
7899
+ this.container.remove();
7900
+ this.parent = newConfig.parent;
7901
+ this.createContainer();
7902
+ for (let t of this.manager.tooltipViews)
7903
+ this.container.appendChild(t.dom);
7904
+ shouldMeasure = true;
7905
+ }
7906
+ else if (this.parent && this.view.themeClasses != this.classes) {
7907
+ this.classes = this.container.className = this.view.themeClasses;
7908
+ }
7909
+ if (shouldMeasure)
7910
+ this.maybeMeasure();
7911
+ }
7912
+ createTooltip(tooltip) {
7913
+ let tooltipView = tooltip.create(this.view);
7914
+ tooltipView.dom.classList.add("cm-tooltip");
7915
+ if (tooltip.arrow && !tooltipView.dom.querySelector(".cm-tooltip > .cm-tooltip-arrow")) {
7916
+ let arrow = document.createElement("div");
7917
+ arrow.className = "cm-tooltip-arrow";
7918
+ tooltipView.dom.appendChild(arrow);
7919
+ }
7920
+ tooltipView.dom.style.position = this.position;
7921
+ tooltipView.dom.style.top = Outside;
7922
+ this.container.appendChild(tooltipView.dom);
7923
+ if (tooltipView.mount)
7924
+ tooltipView.mount(this.view);
7925
+ return tooltipView;
7926
+ }
7927
+ destroy() {
7928
+ var _a, _b;
7929
+ (_a = this.view.dom.ownerDocument.defaultView) === null || _a === void 0 ? void 0 : _a.removeEventListener("resize", this.measureSoon);
7930
+ for (let { dom } of this.manager.tooltipViews)
7931
+ dom.remove();
7932
+ (_b = this.intersectionObserver) === null || _b === void 0 ? void 0 : _b.disconnect();
7933
+ clearTimeout(this.measureTimeout);
7934
+ }
7935
+ readMeasure() {
7936
+ let editor = this.view.dom.getBoundingClientRect();
7937
+ return {
7938
+ editor,
7939
+ parent: this.parent ? this.container.getBoundingClientRect() : editor,
7940
+ pos: this.manager.tooltips.map((t, i) => {
7941
+ let tv = this.manager.tooltipViews[i];
7942
+ return tv.getCoords ? tv.getCoords(t.pos) : this.view.coordsAtPos(t.pos);
7943
+ }),
7944
+ size: this.manager.tooltipViews.map(({ dom }) => dom.getBoundingClientRect()),
7945
+ space: this.view.state.facet(tooltipConfig).tooltipSpace(this.view),
7946
+ };
7947
+ }
7948
+ writeMeasure(measured) {
7949
+ let { editor, space } = measured;
7950
+ let others = [];
7951
+ for (let i = 0; i < this.manager.tooltips.length; i++) {
7952
+ let tooltip = this.manager.tooltips[i], tView = this.manager.tooltipViews[i], { dom } = tView;
7953
+ let pos = measured.pos[i], size = measured.size[i];
7954
+ // Hide tooltips that are outside of the editor.
7955
+ if (!pos || pos.bottom <= Math.max(editor.top, space.top) ||
7956
+ pos.top >= Math.min(editor.bottom, space.bottom) ||
7957
+ pos.right < Math.max(editor.left, space.left) - .1 ||
7958
+ pos.left > Math.min(editor.right, space.right) + .1) {
7959
+ dom.style.top = Outside;
7960
+ continue;
7961
+ }
7962
+ let arrow = tooltip.arrow ? tView.dom.querySelector(".cm-tooltip-arrow") : null;
7963
+ let arrowHeight = arrow ? 7 /* Size */ : 0;
7964
+ let width = size.right - size.left, height = size.bottom - size.top;
7965
+ let offset = tView.offset || noOffset, ltr = this.view.textDirection == exports.Direction.LTR;
7966
+ let left = size.width > space.right - space.left ? (ltr ? space.left : space.right - size.width)
7967
+ : ltr ? Math.min(pos.left - (arrow ? 14 /* Offset */ : 0) + offset.x, space.right - width)
7968
+ : Math.max(space.left, pos.left - width + (arrow ? 14 /* Offset */ : 0) - offset.x);
7969
+ let above = !!tooltip.above;
7970
+ if (!tooltip.strictSide && (above
7971
+ ? pos.top - (size.bottom - size.top) - offset.y < space.top
7972
+ : pos.bottom + (size.bottom - size.top) + offset.y > space.bottom) &&
7973
+ above == (space.bottom - pos.bottom > pos.top - space.top))
7974
+ above = !above;
7975
+ let top = above ? pos.top - height - arrowHeight - offset.y : pos.bottom + arrowHeight + offset.y;
7976
+ let right = left + width;
7977
+ if (tView.overlap !== true)
7978
+ for (let r of others)
7979
+ if (r.left < right && r.right > left && r.top < top + height && r.bottom > top)
7980
+ top = above ? r.top - height - 2 - arrowHeight : r.bottom + arrowHeight + 2;
7981
+ if (this.position == "absolute") {
7982
+ dom.style.top = (top - measured.parent.top) + "px";
7983
+ dom.style.left = (left - measured.parent.left) + "px";
7984
+ }
7985
+ else {
7986
+ dom.style.top = top + "px";
7987
+ dom.style.left = left + "px";
7988
+ }
7989
+ if (arrow)
7990
+ arrow.style.left = `${pos.left + (ltr ? offset.x : -offset.x) - (left + 14 /* Offset */ - 7 /* Size */)}px`;
7991
+ if (tView.overlap !== true)
7992
+ others.push({ left, top, right, bottom: top + height });
7993
+ dom.classList.toggle("cm-tooltip-above", above);
7994
+ dom.classList.toggle("cm-tooltip-below", !above);
7995
+ if (tView.positioned)
7996
+ tView.positioned();
7997
+ }
7998
+ }
7999
+ maybeMeasure() {
8000
+ if (this.manager.tooltips.length) {
8001
+ if (this.view.inView)
8002
+ this.view.requestMeasure(this.measureReq);
8003
+ if (this.inView != this.view.inView) {
8004
+ this.inView = this.view.inView;
8005
+ if (!this.inView)
8006
+ for (let tv of this.manager.tooltipViews)
8007
+ tv.dom.style.top = Outside;
8008
+ }
8009
+ }
8010
+ }
8011
+ }, {
8012
+ eventHandlers: {
8013
+ scroll() { this.maybeMeasure(); }
8014
+ }
7725
8015
  });
8016
+ const baseTheme = EditorView.baseTheme({
8017
+ ".cm-tooltip": {
8018
+ zIndex: 100
8019
+ },
8020
+ "&light .cm-tooltip": {
8021
+ border: "1px solid #bbb",
8022
+ backgroundColor: "#f5f5f5"
8023
+ },
8024
+ "&light .cm-tooltip-section:not(:first-child)": {
8025
+ borderTop: "1px solid #bbb",
8026
+ },
8027
+ "&dark .cm-tooltip": {
8028
+ backgroundColor: "#333338",
8029
+ color: "white"
8030
+ },
8031
+ ".cm-tooltip-arrow": {
8032
+ height: `${7 /* Size */}px`,
8033
+ width: `${7 /* Size */ * 2}px`,
8034
+ position: "absolute",
8035
+ zIndex: -1,
8036
+ overflow: "hidden",
8037
+ "&:before, &:after": {
8038
+ content: "''",
8039
+ position: "absolute",
8040
+ width: 0,
8041
+ height: 0,
8042
+ borderLeft: `${7 /* Size */}px solid transparent`,
8043
+ borderRight: `${7 /* Size */}px solid transparent`,
8044
+ },
8045
+ ".cm-tooltip-above &": {
8046
+ bottom: `-${7 /* Size */}px`,
8047
+ "&:before": {
8048
+ borderTop: `${7 /* Size */}px solid #bbb`,
8049
+ },
8050
+ "&:after": {
8051
+ borderTop: `${7 /* Size */}px solid #f5f5f5`,
8052
+ bottom: "1px"
8053
+ }
8054
+ },
8055
+ ".cm-tooltip-below &": {
8056
+ top: `-${7 /* Size */}px`,
8057
+ "&:before": {
8058
+ borderBottom: `${7 /* Size */}px solid #bbb`,
8059
+ },
8060
+ "&:after": {
8061
+ borderBottom: `${7 /* Size */}px solid #f5f5f5`,
8062
+ top: "1px"
8063
+ }
8064
+ },
8065
+ },
8066
+ "&dark .cm-tooltip .cm-tooltip-arrow": {
8067
+ "&:before": {
8068
+ borderTopColor: "#333338",
8069
+ borderBottomColor: "#333338"
8070
+ },
8071
+ "&:after": {
8072
+ borderTopColor: "transparent",
8073
+ borderBottomColor: "transparent"
8074
+ }
8075
+ }
8076
+ });
8077
+ const noOffset = { x: 0, y: 0 };
8078
+ /**
8079
+ Facet to which an extension can add a value to show a tooltip.
8080
+ */
8081
+ const showTooltip = state.Facet.define({
8082
+ enables: [tooltipPlugin, baseTheme]
8083
+ });
8084
+ const showHoverTooltip = state.Facet.define();
8085
+ class HoverTooltipHost {
8086
+ constructor(view) {
8087
+ this.view = view;
8088
+ this.mounted = false;
8089
+ this.dom = document.createElement("div");
8090
+ this.dom.classList.add("cm-tooltip-hover");
8091
+ this.manager = new TooltipViewManager(view, showHoverTooltip, t => this.createHostedView(t));
8092
+ }
8093
+ // Needs to be static so that host tooltip instances always match
8094
+ static create(view) {
8095
+ return new HoverTooltipHost(view);
8096
+ }
8097
+ createHostedView(tooltip) {
8098
+ let hostedView = tooltip.create(this.view);
8099
+ hostedView.dom.classList.add("cm-tooltip-section");
8100
+ this.dom.appendChild(hostedView.dom);
8101
+ if (this.mounted && hostedView.mount)
8102
+ hostedView.mount(this.view);
8103
+ return hostedView;
8104
+ }
8105
+ mount(view) {
8106
+ for (let hostedView of this.manager.tooltipViews) {
8107
+ if (hostedView.mount)
8108
+ hostedView.mount(view);
8109
+ }
8110
+ this.mounted = true;
8111
+ }
8112
+ positioned() {
8113
+ for (let hostedView of this.manager.tooltipViews) {
8114
+ if (hostedView.positioned)
8115
+ hostedView.positioned();
8116
+ }
8117
+ }
8118
+ update(update) {
8119
+ this.manager.update(update);
8120
+ }
8121
+ }
8122
+ const showHoverTooltipHost = showTooltip.compute([showHoverTooltip], state => {
8123
+ let tooltips = state.facet(showHoverTooltip).filter(t => t);
8124
+ if (tooltips.length === 0)
8125
+ return null;
8126
+ return {
8127
+ pos: Math.min(...tooltips.map(t => t.pos)),
8128
+ end: Math.max(...tooltips.filter(t => t.end != null).map(t => t.end)),
8129
+ create: HoverTooltipHost.create,
8130
+ above: tooltips[0].above,
8131
+ arrow: tooltips.some(t => t.arrow),
8132
+ };
8133
+ });
8134
+ class HoverPlugin {
8135
+ constructor(view, source, field, setHover, hoverTime) {
8136
+ this.view = view;
8137
+ this.source = source;
8138
+ this.field = field;
8139
+ this.setHover = setHover;
8140
+ this.hoverTime = hoverTime;
8141
+ this.hoverTimeout = -1;
8142
+ this.restartTimeout = -1;
8143
+ this.pending = null;
8144
+ this.lastMove = { x: 0, y: 0, target: view.dom, time: 0 };
8145
+ this.checkHover = this.checkHover.bind(this);
8146
+ view.dom.addEventListener("mouseleave", this.mouseleave = this.mouseleave.bind(this));
8147
+ view.dom.addEventListener("mousemove", this.mousemove = this.mousemove.bind(this));
8148
+ }
8149
+ update() {
8150
+ if (this.pending) {
8151
+ this.pending = null;
8152
+ clearTimeout(this.restartTimeout);
8153
+ this.restartTimeout = setTimeout(() => this.startHover(), 20);
8154
+ }
8155
+ }
8156
+ get active() {
8157
+ return this.view.state.field(this.field);
8158
+ }
8159
+ checkHover() {
8160
+ this.hoverTimeout = -1;
8161
+ if (this.active)
8162
+ return;
8163
+ let hovered = Date.now() - this.lastMove.time;
8164
+ if (hovered < this.hoverTime)
8165
+ this.hoverTimeout = setTimeout(this.checkHover, this.hoverTime - hovered);
8166
+ else
8167
+ this.startHover();
8168
+ }
8169
+ startHover() {
8170
+ var _a;
8171
+ clearTimeout(this.restartTimeout);
8172
+ let { lastMove } = this;
8173
+ let pos = this.view.contentDOM.contains(lastMove.target) ? this.view.posAtCoords(lastMove) : null;
8174
+ if (pos == null)
8175
+ return;
8176
+ let posCoords = this.view.coordsAtPos(pos);
8177
+ if (posCoords == null || lastMove.y < posCoords.top || lastMove.y > posCoords.bottom ||
8178
+ lastMove.x < posCoords.left - this.view.defaultCharacterWidth ||
8179
+ lastMove.x > posCoords.right + this.view.defaultCharacterWidth)
8180
+ return;
8181
+ let bidi = this.view.bidiSpans(this.view.state.doc.lineAt(pos)).find(s => s.from <= pos && s.to >= pos);
8182
+ let rtl = bidi && bidi.dir == exports.Direction.RTL ? -1 : 1;
8183
+ let open = this.source(this.view, pos, (lastMove.x < posCoords.left ? -rtl : rtl));
8184
+ if ((_a = open) === null || _a === void 0 ? void 0 : _a.then) {
8185
+ let pending = this.pending = { pos };
8186
+ open.then(result => {
8187
+ if (this.pending == pending) {
8188
+ this.pending = null;
8189
+ if (result)
8190
+ this.view.dispatch({ effects: this.setHover.of(result) });
8191
+ }
8192
+ }, e => logException(this.view.state, e, "hover tooltip"));
8193
+ }
8194
+ else if (open) {
8195
+ this.view.dispatch({ effects: this.setHover.of(open) });
8196
+ }
8197
+ }
8198
+ mousemove(event) {
8199
+ var _a;
8200
+ this.lastMove = { x: event.clientX, y: event.clientY, target: event.target, time: Date.now() };
8201
+ if (this.hoverTimeout < 0)
8202
+ this.hoverTimeout = setTimeout(this.checkHover, this.hoverTime);
8203
+ let tooltip = this.active;
8204
+ if (tooltip && !isInTooltip(this.lastMove.target) || this.pending) {
8205
+ let { pos } = tooltip || this.pending, end = (_a = tooltip === null || tooltip === void 0 ? void 0 : tooltip.end) !== null && _a !== void 0 ? _a : pos;
8206
+ if ((pos == end ? this.view.posAtCoords(this.lastMove) != pos
8207
+ : !isOverRange(this.view, pos, end, event.clientX, event.clientY, 6 /* MaxDist */))) {
8208
+ this.view.dispatch({ effects: this.setHover.of(null) });
8209
+ this.pending = null;
8210
+ }
8211
+ }
8212
+ }
8213
+ mouseleave() {
8214
+ clearTimeout(this.hoverTimeout);
8215
+ this.hoverTimeout = -1;
8216
+ if (this.active)
8217
+ this.view.dispatch({ effects: this.setHover.of(null) });
8218
+ }
8219
+ destroy() {
8220
+ clearTimeout(this.hoverTimeout);
8221
+ this.view.dom.removeEventListener("mouseleave", this.mouseleave);
8222
+ this.view.dom.removeEventListener("mousemove", this.mousemove);
8223
+ }
8224
+ }
8225
+ function isInTooltip(elt) {
8226
+ for (let cur = elt; cur; cur = cur.parentNode)
8227
+ if (cur.nodeType == 1 && cur.classList.contains("cm-tooltip"))
8228
+ return true;
8229
+ return false;
8230
+ }
8231
+ function isOverRange(view, from, to, x, y, margin) {
8232
+ let range = document.createRange();
8233
+ let fromDOM = view.domAtPos(from), toDOM = view.domAtPos(to);
8234
+ range.setEnd(toDOM.node, toDOM.offset);
8235
+ range.setStart(fromDOM.node, fromDOM.offset);
8236
+ let rects = range.getClientRects();
8237
+ range.detach();
8238
+ for (let i = 0; i < rects.length; i++) {
8239
+ let rect = rects[i];
8240
+ let dist = Math.max(rect.top - y, y - rect.bottom, rect.left - x, x - rect.right);
8241
+ if (dist <= margin)
8242
+ return true;
8243
+ }
8244
+ return false;
8245
+ }
8246
+ /**
8247
+ Set up a hover tooltip, which shows up when the pointer hovers
8248
+ over ranges of text. The callback is called when the mouse hovers
8249
+ over the document text. It should, if there is a tooltip
8250
+ associated with position `pos`, return the tooltip description
8251
+ (either directly or in a promise). The `side` argument indicates
8252
+ on which side of the position the pointer is—it will be -1 if the
8253
+ pointer is before the position, 1 if after the position.
8254
+
8255
+ Note that all hover tooltips are hosted within a single tooltip
8256
+ container element. This allows multiple tooltips over the same
8257
+ range to be "merged" together without overlapping.
8258
+ */
8259
+ function hoverTooltip(source, options = {}) {
8260
+ let setHover = state.StateEffect.define();
8261
+ let hoverState = state.StateField.define({
8262
+ create() { return null; },
8263
+ update(value, tr) {
8264
+ if (value && (options.hideOnChange && (tr.docChanged || tr.selection)))
8265
+ return null;
8266
+ if (value && tr.docChanged) {
8267
+ let newPos = tr.changes.mapPos(value.pos, -1, state.MapMode.TrackDel);
8268
+ if (newPos == null)
8269
+ return null;
8270
+ let copy = Object.assign(Object.create(null), value);
8271
+ copy.pos = newPos;
8272
+ if (value.end != null)
8273
+ copy.end = tr.changes.mapPos(value.end);
8274
+ value = copy;
8275
+ }
8276
+ for (let effect of tr.effects) {
8277
+ if (effect.is(setHover))
8278
+ value = effect.value;
8279
+ if (effect.is(closeHoverTooltipEffect))
8280
+ value = null;
8281
+ }
8282
+ return value;
8283
+ },
8284
+ provide: f => showHoverTooltip.from(f)
8285
+ });
8286
+ return [
8287
+ hoverState,
8288
+ ViewPlugin.define(view => new HoverPlugin(view, source, hoverState, setHover, options.hoverTime || 300 /* Time */)),
8289
+ showHoverTooltipHost
8290
+ ];
8291
+ }
8292
+ /**
8293
+ Get the active tooltip view for a given tooltip, if available.
8294
+ */
8295
+ function getTooltip(view, tooltip) {
8296
+ let plugin = view.plugin(tooltipPlugin);
8297
+ if (!plugin)
8298
+ return null;
8299
+ let found = plugin.manager.tooltips.indexOf(tooltip);
8300
+ return found < 0 ? null : plugin.manager.tooltipViews[found];
8301
+ }
8302
+ /**
8303
+ Returns true if any hover tooltips are currently active.
8304
+ */
8305
+ function hasHoverTooltips(state) {
8306
+ return state.facet(showHoverTooltip).some(x => x);
8307
+ }
8308
+ const closeHoverTooltipEffect = state.StateEffect.define();
8309
+ /**
8310
+ Transaction effect that closes all hover tooltips.
8311
+ */
8312
+ const closeHoverTooltips = closeHoverTooltipEffect.of(null);
8313
+ /**
8314
+ Tell the tooltip extension to recompute the position of the active
8315
+ tooltips. This can be useful when something happens (such as a
8316
+ re-positioning or CSS change affecting the editor) that could
8317
+ invalidate the existing tooltip positions.
8318
+ */
8319
+ function repositionTooltips(view) {
8320
+ var _a;
8321
+ (_a = view.plugin(tooltipPlugin)) === null || _a === void 0 ? void 0 : _a.maybeMeasure();
8322
+ }
8323
+
8324
+ const panelConfig = state.Facet.define({
8325
+ combine(configs) {
8326
+ let topContainer, bottomContainer;
8327
+ for (let c of configs) {
8328
+ topContainer = topContainer || c.topContainer;
8329
+ bottomContainer = bottomContainer || c.bottomContainer;
8330
+ }
8331
+ return { topContainer, bottomContainer };
8332
+ }
8333
+ });
8334
+ /**
8335
+ Configures the panel-managing extension.
8336
+ */
8337
+ function panels(config) {
8338
+ return config ? [panelConfig.of(config)] : [];
8339
+ }
8340
+ /**
8341
+ Get the active panel created by the given constructor, if any.
8342
+ This can be useful when you need access to your panels' DOM
8343
+ structure.
8344
+ */
8345
+ function getPanel(view, panel) {
8346
+ let plugin = view.plugin(panelPlugin);
8347
+ let index = plugin ? plugin.specs.indexOf(panel) : -1;
8348
+ return index > -1 ? plugin.panels[index] : null;
8349
+ }
8350
+ const panelPlugin = ViewPlugin.fromClass(class {
8351
+ constructor(view) {
8352
+ this.input = view.state.facet(showPanel);
8353
+ this.specs = this.input.filter(s => s);
8354
+ this.panels = this.specs.map(spec => spec(view));
8355
+ let conf = view.state.facet(panelConfig);
8356
+ this.top = new PanelGroup(view, true, conf.topContainer);
8357
+ this.bottom = new PanelGroup(view, false, conf.bottomContainer);
8358
+ this.top.sync(this.panels.filter(p => p.top));
8359
+ this.bottom.sync(this.panels.filter(p => !p.top));
8360
+ for (let p of this.panels) {
8361
+ p.dom.classList.add("cm-panel");
8362
+ if (p.mount)
8363
+ p.mount();
8364
+ }
8365
+ }
8366
+ update(update) {
8367
+ let conf = update.state.facet(panelConfig);
8368
+ if (this.top.container != conf.topContainer) {
8369
+ this.top.sync([]);
8370
+ this.top = new PanelGroup(update.view, true, conf.topContainer);
8371
+ }
8372
+ if (this.bottom.container != conf.bottomContainer) {
8373
+ this.bottom.sync([]);
8374
+ this.bottom = new PanelGroup(update.view, false, conf.bottomContainer);
8375
+ }
8376
+ this.top.syncClasses();
8377
+ this.bottom.syncClasses();
8378
+ let input = update.state.facet(showPanel);
8379
+ if (input != this.input) {
8380
+ let specs = input.filter(x => x);
8381
+ let panels = [], top = [], bottom = [], mount = [];
8382
+ for (let spec of specs) {
8383
+ let known = this.specs.indexOf(spec), panel;
8384
+ if (known < 0) {
8385
+ panel = spec(update.view);
8386
+ mount.push(panel);
8387
+ }
8388
+ else {
8389
+ panel = this.panels[known];
8390
+ if (panel.update)
8391
+ panel.update(update);
8392
+ }
8393
+ panels.push(panel);
8394
+ (panel.top ? top : bottom).push(panel);
8395
+ }
8396
+ this.specs = specs;
8397
+ this.panels = panels;
8398
+ this.top.sync(top);
8399
+ this.bottom.sync(bottom);
8400
+ for (let p of mount) {
8401
+ p.dom.classList.add("cm-panel");
8402
+ if (p.mount)
8403
+ p.mount();
8404
+ }
8405
+ }
8406
+ else {
8407
+ for (let p of this.panels)
8408
+ if (p.update)
8409
+ p.update(update);
8410
+ }
8411
+ }
8412
+ destroy() {
8413
+ this.top.sync([]);
8414
+ this.bottom.sync([]);
8415
+ }
8416
+ }, {
8417
+ provide: plugin => EditorView.scrollMargins.of(view => {
8418
+ let value = view.plugin(plugin);
8419
+ return value && { top: value.top.scrollMargin(), bottom: value.bottom.scrollMargin() };
8420
+ })
8421
+ });
8422
+ class PanelGroup {
8423
+ constructor(view, top, container) {
8424
+ this.view = view;
8425
+ this.top = top;
8426
+ this.container = container;
8427
+ this.dom = undefined;
8428
+ this.classes = "";
8429
+ this.panels = [];
8430
+ this.syncClasses();
8431
+ }
8432
+ sync(panels) {
8433
+ for (let p of this.panels)
8434
+ if (p.destroy && panels.indexOf(p) < 0)
8435
+ p.destroy();
8436
+ this.panels = panels;
8437
+ this.syncDOM();
8438
+ }
8439
+ syncDOM() {
8440
+ if (this.panels.length == 0) {
8441
+ if (this.dom) {
8442
+ this.dom.remove();
8443
+ this.dom = undefined;
8444
+ }
8445
+ return;
8446
+ }
8447
+ if (!this.dom) {
8448
+ this.dom = document.createElement("div");
8449
+ this.dom.className = this.top ? "cm-panels cm-panels-top" : "cm-panels cm-panels-bottom";
8450
+ this.dom.style[this.top ? "top" : "bottom"] = "0";
8451
+ let parent = this.container || this.view.dom;
8452
+ parent.insertBefore(this.dom, this.top ? parent.firstChild : null);
8453
+ }
8454
+ let curDOM = this.dom.firstChild;
8455
+ for (let panel of this.panels) {
8456
+ if (panel.dom.parentNode == this.dom) {
8457
+ while (curDOM != panel.dom)
8458
+ curDOM = rm(curDOM);
8459
+ curDOM = curDOM.nextSibling;
8460
+ }
8461
+ else {
8462
+ this.dom.insertBefore(panel.dom, curDOM);
8463
+ }
8464
+ }
8465
+ while (curDOM)
8466
+ curDOM = rm(curDOM);
8467
+ }
8468
+ scrollMargin() {
8469
+ return !this.dom || this.container ? 0
8470
+ : Math.max(0, this.top ?
8471
+ this.dom.getBoundingClientRect().bottom - Math.max(0, this.view.scrollDOM.getBoundingClientRect().top) :
8472
+ Math.min(innerHeight, this.view.scrollDOM.getBoundingClientRect().bottom) - this.dom.getBoundingClientRect().top);
8473
+ }
8474
+ syncClasses() {
8475
+ if (!this.container || this.classes == this.view.themeClasses)
8476
+ return;
8477
+ for (let cls of this.classes.split(" "))
8478
+ if (cls)
8479
+ this.container.classList.remove(cls);
8480
+ for (let cls of (this.classes = this.view.themeClasses).split(" "))
8481
+ if (cls)
8482
+ this.container.classList.add(cls);
8483
+ }
8484
+ }
8485
+ function rm(node) {
8486
+ let next = node.nextSibling;
8487
+ node.remove();
8488
+ return next;
8489
+ }
8490
+ /**
8491
+ Opening a panel is done by providing a constructor function for
8492
+ the panel through this facet. (The panel is closed again when its
8493
+ constructor is no longer provided.) Values of `null` are ignored.
8494
+ */
8495
+ const showPanel = state.Facet.define({
8496
+ enables: panelPlugin
8497
+ });
8498
+
8499
+ /**
8500
+ A gutter marker represents a bit of information attached to a line
8501
+ in a specific gutter. Your own custom markers have to extend this
8502
+ class.
8503
+ */
8504
+ class GutterMarker extends state.RangeValue {
8505
+ /**
8506
+ @internal
8507
+ */
8508
+ compare(other) {
8509
+ return this == other || this.constructor == other.constructor && this.eq(other);
8510
+ }
8511
+ /**
8512
+ Compare this marker to another marker of the same type.
8513
+ */
8514
+ eq(other) { return false; }
8515
+ /**
8516
+ Called if the marker has a `toDOM` method and its representation
8517
+ was removed from a gutter.
8518
+ */
8519
+ destroy(dom) { }
8520
+ }
8521
+ GutterMarker.prototype.elementClass = "";
8522
+ GutterMarker.prototype.toDOM = undefined;
8523
+ GutterMarker.prototype.mapMode = state.MapMode.TrackBefore;
8524
+ GutterMarker.prototype.startSide = GutterMarker.prototype.endSide = -1;
8525
+ GutterMarker.prototype.point = true;
8526
+ /**
8527
+ Facet used to add a class to all gutter elements for a given line.
8528
+ Markers given to this facet should _only_ define an
8529
+ [`elementclass`](https://codemirror.net/6/docs/ref/#view.GutterMarker.elementClass), not a
8530
+ [`toDOM`](https://codemirror.net/6/docs/ref/#view.GutterMarker.toDOM) (or the marker will appear
8531
+ in all gutters for the line).
8532
+ */
8533
+ const gutterLineClass = state.Facet.define();
8534
+ const defaults = {
8535
+ class: "",
8536
+ renderEmptyElements: false,
8537
+ elementStyle: "",
8538
+ markers: () => state.RangeSet.empty,
8539
+ lineMarker: () => null,
8540
+ lineMarkerChange: null,
8541
+ initialSpacer: null,
8542
+ updateSpacer: null,
8543
+ domEventHandlers: {}
8544
+ };
8545
+ const activeGutters = state.Facet.define();
8546
+ /**
8547
+ Define an editor gutter. The order in which the gutters appear is
8548
+ determined by their extension priority.
8549
+ */
8550
+ function gutter(config) {
8551
+ return [gutters(), activeGutters.of(Object.assign(Object.assign({}, defaults), config))];
8552
+ }
8553
+ const unfixGutters = state.Facet.define({
8554
+ combine: values => values.some(x => x)
8555
+ });
8556
+ /**
8557
+ The gutter-drawing plugin is automatically enabled when you add a
8558
+ gutter, but you can use this function to explicitly configure it.
8559
+
8560
+ Unless `fixed` is explicitly set to `false`, the gutters are
8561
+ fixed, meaning they don't scroll along with the content
8562
+ horizontally (except on Internet Explorer, which doesn't support
8563
+ CSS [`position:
8564
+ sticky`](https://developer.mozilla.org/en-US/docs/Web/CSS/position#sticky)).
8565
+ */
8566
+ function gutters(config) {
8567
+ let result = [
8568
+ gutterView,
8569
+ ];
8570
+ if (config && config.fixed === false)
8571
+ result.push(unfixGutters.of(true));
8572
+ return result;
8573
+ }
8574
+ const gutterView = ViewPlugin.fromClass(class {
8575
+ constructor(view) {
8576
+ this.view = view;
8577
+ this.prevViewport = view.viewport;
8578
+ this.dom = document.createElement("div");
8579
+ this.dom.className = "cm-gutters";
8580
+ this.dom.setAttribute("aria-hidden", "true");
8581
+ this.dom.style.minHeight = this.view.contentHeight + "px";
8582
+ this.gutters = view.state.facet(activeGutters).map(conf => new SingleGutterView(view, conf));
8583
+ for (let gutter of this.gutters)
8584
+ this.dom.appendChild(gutter.dom);
8585
+ this.fixed = !view.state.facet(unfixGutters);
8586
+ if (this.fixed) {
8587
+ // FIXME IE11 fallback, which doesn't support position: sticky,
8588
+ // by using position: relative + event handlers that realign the
8589
+ // gutter (or just force fixed=false on IE11?)
8590
+ this.dom.style.position = "sticky";
8591
+ }
8592
+ this.syncGutters(false);
8593
+ view.scrollDOM.insertBefore(this.dom, view.contentDOM);
8594
+ }
8595
+ update(update) {
8596
+ if (this.updateGutters(update)) {
8597
+ // Detach during sync when the viewport changed significantly
8598
+ // (such as during scrolling), since for large updates that is
8599
+ // faster.
8600
+ let vpA = this.prevViewport, vpB = update.view.viewport;
8601
+ let vpOverlap = Math.min(vpA.to, vpB.to) - Math.max(vpA.from, vpB.from);
8602
+ this.syncGutters(vpOverlap < (vpB.to - vpB.from) * 0.8);
8603
+ }
8604
+ if (update.geometryChanged)
8605
+ this.dom.style.minHeight = this.view.contentHeight + "px";
8606
+ if (this.view.state.facet(unfixGutters) != !this.fixed) {
8607
+ this.fixed = !this.fixed;
8608
+ this.dom.style.position = this.fixed ? "sticky" : "";
8609
+ }
8610
+ this.prevViewport = update.view.viewport;
8611
+ }
8612
+ syncGutters(detach) {
8613
+ let after = this.dom.nextSibling;
8614
+ if (detach)
8615
+ this.dom.remove();
8616
+ let lineClasses = state.RangeSet.iter(this.view.state.facet(gutterLineClass), this.view.viewport.from);
8617
+ let classSet = [];
8618
+ let contexts = this.gutters.map(gutter => new UpdateContext(gutter, this.view.viewport, -this.view.documentPadding.top));
8619
+ for (let line of this.view.viewportLineBlocks) {
8620
+ let text;
8621
+ if (Array.isArray(line.type)) {
8622
+ for (let b of line.type)
8623
+ if (b.type == exports.BlockType.Text) {
8624
+ text = b;
8625
+ break;
8626
+ }
8627
+ }
8628
+ else {
8629
+ text = line.type == exports.BlockType.Text ? line : undefined;
8630
+ }
8631
+ if (!text)
8632
+ continue;
8633
+ if (classSet.length)
8634
+ classSet = [];
8635
+ advanceCursor(lineClasses, classSet, line.from);
8636
+ for (let cx of contexts)
8637
+ cx.line(this.view, text, classSet);
8638
+ }
8639
+ for (let cx of contexts)
8640
+ cx.finish();
8641
+ if (detach)
8642
+ this.view.scrollDOM.insertBefore(this.dom, after);
8643
+ }
8644
+ updateGutters(update) {
8645
+ let prev = update.startState.facet(activeGutters), cur = update.state.facet(activeGutters);
8646
+ let change = update.docChanged || update.heightChanged || update.viewportChanged ||
8647
+ !state.RangeSet.eq(update.startState.facet(gutterLineClass), update.state.facet(gutterLineClass), update.view.viewport.from, update.view.viewport.to);
8648
+ if (prev == cur) {
8649
+ for (let gutter of this.gutters)
8650
+ if (gutter.update(update))
8651
+ change = true;
8652
+ }
8653
+ else {
8654
+ change = true;
8655
+ let gutters = [];
8656
+ for (let conf of cur) {
8657
+ let known = prev.indexOf(conf);
8658
+ if (known < 0) {
8659
+ gutters.push(new SingleGutterView(this.view, conf));
8660
+ }
8661
+ else {
8662
+ this.gutters[known].update(update);
8663
+ gutters.push(this.gutters[known]);
8664
+ }
8665
+ }
8666
+ for (let g of this.gutters) {
8667
+ g.dom.remove();
8668
+ if (gutters.indexOf(g) < 0)
8669
+ g.destroy();
8670
+ }
8671
+ for (let g of gutters)
8672
+ this.dom.appendChild(g.dom);
8673
+ this.gutters = gutters;
8674
+ }
8675
+ return change;
8676
+ }
8677
+ destroy() {
8678
+ for (let view of this.gutters)
8679
+ view.destroy();
8680
+ this.dom.remove();
8681
+ }
8682
+ }, {
8683
+ provide: plugin => EditorView.scrollMargins.of(view => {
8684
+ let value = view.plugin(plugin);
8685
+ if (!value || value.gutters.length == 0 || !value.fixed)
8686
+ return null;
8687
+ return view.textDirection == exports.Direction.LTR ? { left: value.dom.offsetWidth } : { right: value.dom.offsetWidth };
8688
+ })
8689
+ });
8690
+ function asArray(val) { return (Array.isArray(val) ? val : [val]); }
8691
+ function advanceCursor(cursor, collect, pos) {
8692
+ while (cursor.value && cursor.from <= pos) {
8693
+ if (cursor.from == pos)
8694
+ collect.push(cursor.value);
8695
+ cursor.next();
8696
+ }
8697
+ }
8698
+ class UpdateContext {
8699
+ constructor(gutter, viewport, height) {
8700
+ this.gutter = gutter;
8701
+ this.height = height;
8702
+ this.localMarkers = [];
8703
+ this.i = 0;
8704
+ this.cursor = state.RangeSet.iter(gutter.markers, viewport.from);
8705
+ }
8706
+ line(view, line, extraMarkers) {
8707
+ if (this.localMarkers.length)
8708
+ this.localMarkers = [];
8709
+ advanceCursor(this.cursor, this.localMarkers, line.from);
8710
+ let localMarkers = extraMarkers.length ? this.localMarkers.concat(extraMarkers) : this.localMarkers;
8711
+ let forLine = this.gutter.config.lineMarker(view, line, localMarkers);
8712
+ if (forLine)
8713
+ localMarkers.unshift(forLine);
8714
+ let gutter = this.gutter;
8715
+ if (localMarkers.length == 0 && !gutter.config.renderEmptyElements)
8716
+ return;
8717
+ let above = line.top - this.height;
8718
+ if (this.i == gutter.elements.length) {
8719
+ let newElt = new GutterElement(view, line.height, above, localMarkers);
8720
+ gutter.elements.push(newElt);
8721
+ gutter.dom.appendChild(newElt.dom);
8722
+ }
8723
+ else {
8724
+ gutter.elements[this.i].update(view, line.height, above, localMarkers);
8725
+ }
8726
+ this.height = line.bottom;
8727
+ this.i++;
8728
+ }
8729
+ finish() {
8730
+ let gutter = this.gutter;
8731
+ while (gutter.elements.length > this.i) {
8732
+ let last = gutter.elements.pop();
8733
+ gutter.dom.removeChild(last.dom);
8734
+ last.destroy();
8735
+ }
8736
+ }
8737
+ }
8738
+ class SingleGutterView {
8739
+ constructor(view, config) {
8740
+ this.view = view;
8741
+ this.config = config;
8742
+ this.elements = [];
8743
+ this.spacer = null;
8744
+ this.dom = document.createElement("div");
8745
+ this.dom.className = "cm-gutter" + (this.config.class ? " " + this.config.class : "");
8746
+ for (let prop in config.domEventHandlers) {
8747
+ this.dom.addEventListener(prop, (event) => {
8748
+ let line = view.lineBlockAtHeight(event.clientY - view.documentTop);
8749
+ if (config.domEventHandlers[prop](view, line, event))
8750
+ event.preventDefault();
8751
+ });
8752
+ }
8753
+ this.markers = asArray(config.markers(view));
8754
+ if (config.initialSpacer) {
8755
+ this.spacer = new GutterElement(view, 0, 0, [config.initialSpacer(view)]);
8756
+ this.dom.appendChild(this.spacer.dom);
8757
+ this.spacer.dom.style.cssText += "visibility: hidden; pointer-events: none";
8758
+ }
8759
+ }
8760
+ update(update) {
8761
+ let prevMarkers = this.markers;
8762
+ this.markers = asArray(this.config.markers(update.view));
8763
+ if (this.spacer && this.config.updateSpacer) {
8764
+ let updated = this.config.updateSpacer(this.spacer.markers[0], update);
8765
+ if (updated != this.spacer.markers[0])
8766
+ this.spacer.update(update.view, 0, 0, [updated]);
8767
+ }
8768
+ let vp = update.view.viewport;
8769
+ return !state.RangeSet.eq(this.markers, prevMarkers, vp.from, vp.to) ||
8770
+ (this.config.lineMarkerChange ? this.config.lineMarkerChange(update) : false);
8771
+ }
8772
+ destroy() {
8773
+ for (let elt of this.elements)
8774
+ elt.destroy();
8775
+ }
8776
+ }
8777
+ class GutterElement {
8778
+ constructor(view, height, above, markers) {
8779
+ this.height = -1;
8780
+ this.above = 0;
8781
+ this.markers = [];
8782
+ this.dom = document.createElement("div");
8783
+ this.update(view, height, above, markers);
8784
+ }
8785
+ update(view, height, above, markers) {
8786
+ if (this.height != height)
8787
+ this.dom.style.height = (this.height = height) + "px";
8788
+ if (this.above != above)
8789
+ this.dom.style.marginTop = (this.above = above) ? above + "px" : "";
8790
+ if (!sameMarkers(this.markers, markers))
8791
+ this.setMarkers(view, markers);
8792
+ }
8793
+ setMarkers(view, markers) {
8794
+ let cls = "cm-gutterElement", domPos = this.dom.firstChild;
8795
+ for (let iNew = 0, iOld = 0;;) {
8796
+ let skipTo = iOld, marker = iNew < markers.length ? markers[iNew++] : null, matched = false;
8797
+ if (marker) {
8798
+ let c = marker.elementClass;
8799
+ if (c)
8800
+ cls += " " + c;
8801
+ for (let i = iOld; i < this.markers.length; i++)
8802
+ if (this.markers[i].compare(marker)) {
8803
+ skipTo = i;
8804
+ matched = true;
8805
+ break;
8806
+ }
8807
+ }
8808
+ else {
8809
+ skipTo = this.markers.length;
8810
+ }
8811
+ while (iOld < skipTo) {
8812
+ let next = this.markers[iOld++];
8813
+ if (next.toDOM) {
8814
+ next.destroy(domPos);
8815
+ let after = domPos.nextSibling;
8816
+ domPos.remove();
8817
+ domPos = after;
8818
+ }
8819
+ }
8820
+ if (!marker)
8821
+ break;
8822
+ if (marker.toDOM) {
8823
+ if (matched)
8824
+ domPos = domPos.nextSibling;
8825
+ else
8826
+ this.dom.insertBefore(marker.toDOM(view), domPos);
8827
+ }
8828
+ if (matched)
8829
+ iOld++;
8830
+ }
8831
+ this.dom.className = cls;
8832
+ this.markers = markers;
8833
+ }
8834
+ destroy() {
8835
+ this.setMarkers(null, []); // First argument not used unless creating markers
8836
+ }
8837
+ }
8838
+ function sameMarkers(a, b) {
8839
+ if (a.length != b.length)
8840
+ return false;
8841
+ for (let i = 0; i < a.length; i++)
8842
+ if (!a[i].compare(b[i]))
8843
+ return false;
8844
+ return true;
8845
+ }
8846
+ /**
8847
+ Facet used to provide markers to the line number gutter.
8848
+ */
8849
+ const lineNumberMarkers = state.Facet.define();
8850
+ const lineNumberConfig = state.Facet.define({
8851
+ combine(values) {
8852
+ return state.combineConfig(values, { formatNumber: String, domEventHandlers: {} }, {
8853
+ domEventHandlers(a, b) {
8854
+ let result = Object.assign({}, a);
8855
+ for (let event in b) {
8856
+ let exists = result[event], add = b[event];
8857
+ result[event] = exists ? (view, line, event) => exists(view, line, event) || add(view, line, event) : add;
8858
+ }
8859
+ return result;
8860
+ }
8861
+ });
8862
+ }
8863
+ });
8864
+ class NumberMarker extends GutterMarker {
8865
+ constructor(number) {
8866
+ super();
8867
+ this.number = number;
8868
+ }
8869
+ eq(other) { return this.number == other.number; }
8870
+ toDOM() { return document.createTextNode(this.number); }
8871
+ }
8872
+ function formatNumber(view, number) {
8873
+ return view.state.facet(lineNumberConfig).formatNumber(number, view.state);
8874
+ }
8875
+ const lineNumberGutter = activeGutters.compute([lineNumberConfig], state => ({
8876
+ class: "cm-lineNumbers",
8877
+ renderEmptyElements: false,
8878
+ markers(view) { return view.state.facet(lineNumberMarkers); },
8879
+ lineMarker(view, line, others) {
8880
+ if (others.some(m => m.toDOM))
8881
+ return null;
8882
+ return new NumberMarker(formatNumber(view, view.state.doc.lineAt(line.from).number));
8883
+ },
8884
+ lineMarkerChange: update => update.startState.facet(lineNumberConfig) != update.state.facet(lineNumberConfig),
8885
+ initialSpacer(view) {
8886
+ return new NumberMarker(formatNumber(view, maxLineNumber(view.state.doc.lines)));
8887
+ },
8888
+ updateSpacer(spacer, update) {
8889
+ let max = formatNumber(update.view, maxLineNumber(update.view.state.doc.lines));
8890
+ return max == spacer.number ? spacer : new NumberMarker(max);
8891
+ },
8892
+ domEventHandlers: state.facet(lineNumberConfig).domEventHandlers
8893
+ }));
8894
+ /**
8895
+ Create a line number gutter extension.
8896
+ */
8897
+ function lineNumbers(config = {}) {
8898
+ return [
8899
+ lineNumberConfig.of(config),
8900
+ gutters(),
8901
+ lineNumberGutter
8902
+ ];
8903
+ }
8904
+ function maxLineNumber(lines) {
8905
+ let last = 9;
8906
+ while (last < lines)
8907
+ last = last * 10 + 9;
8908
+ return last;
8909
+ }
8910
+ const activeLineGutterMarker = new class extends GutterMarker {
8911
+ constructor() {
8912
+ super(...arguments);
8913
+ this.elementClass = "cm-activeLineGutter";
8914
+ }
8915
+ };
8916
+ const activeLineGutterHighlighter = gutterLineClass.compute(["selection"], state$1 => {
8917
+ let marks = [], last = -1;
8918
+ for (let range of state$1.selection.ranges)
8919
+ if (range.empty) {
8920
+ let linePos = state$1.doc.lineAt(range.head).from;
8921
+ if (linePos > last) {
8922
+ last = linePos;
8923
+ marks.push(activeLineGutterMarker.range(linePos));
8924
+ }
8925
+ }
8926
+ return state.RangeSet.of(marks);
8927
+ });
8928
+ /**
8929
+ Returns an extension that adds a `cm-activeLineGutter` class to
8930
+ all gutter elements on the [active
8931
+ line](https://codemirror.net/6/docs/ref/#view.highlightActiveLine).
8932
+ */
8933
+ function highlightActiveLineGutter() {
8934
+ return activeLineGutterHighlighter;
8935
+ }
8936
+
8937
+ /**
8938
+ @internal
8939
+ */
8940
+ const __test = { HeightMap, HeightOracle, MeasuredHeights, QueryType, ChangedRange, computeOrder, moveVisually };
8941
+
7726
8942
  exports.BidiSpan = BidiSpan;
7727
8943
  exports.BlockInfo = BlockInfo;
7728
8944
  exports.Decoration = Decoration;
7729
8945
  exports.EditorView = EditorView;
8946
+ exports.GutterMarker = GutterMarker;
7730
8947
  exports.MatchDecorator = MatchDecorator;
7731
- exports.PluginField = PluginField;
7732
- exports.PluginFieldProvider = PluginFieldProvider;
7733
8948
  exports.ViewPlugin = ViewPlugin;
7734
8949
  exports.ViewUpdate = ViewUpdate;
7735
8950
  exports.WidgetType = WidgetType;
7736
8951
  exports.__test = __test;
8952
+ exports.closeHoverTooltips = closeHoverTooltips;
8953
+ exports.crosshairCursor = crosshairCursor;
7737
8954
  exports.drawSelection = drawSelection;
7738
8955
  exports.dropCursor = dropCursor;
8956
+ exports.getPanel = getPanel;
8957
+ exports.getTooltip = getTooltip;
8958
+ exports.gutter = gutter;
8959
+ exports.gutterLineClass = gutterLineClass;
8960
+ exports.gutters = gutters;
8961
+ exports.hasHoverTooltips = hasHoverTooltips;
7739
8962
  exports.highlightActiveLine = highlightActiveLine;
8963
+ exports.highlightActiveLineGutter = highlightActiveLineGutter;
7740
8964
  exports.highlightSpecialChars = highlightSpecialChars;
8965
+ exports.hoverTooltip = hoverTooltip;
7741
8966
  exports.keymap = keymap;
8967
+ exports.lineNumberMarkers = lineNumberMarkers;
8968
+ exports.lineNumbers = lineNumbers;
7742
8969
  exports.logException = logException;
8970
+ exports.panels = panels;
7743
8971
  exports.placeholder = placeholder;
8972
+ exports.rectangularSelection = rectangularSelection;
8973
+ exports.repositionTooltips = repositionTooltips;
7744
8974
  exports.runScopeHandlers = runScopeHandlers;
7745
8975
  exports.scrollPastEnd = scrollPastEnd;
8976
+ exports.showPanel = showPanel;
8977
+ exports.showTooltip = showTooltip;
8978
+ exports.tooltips = tooltips;