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