editor/node_modules/.vite/deps/chunk-M6T3QFJD.js

11030 lines
381 KiB
JavaScript
Raw Normal View History

import {
Annotation,
ChangeSet,
CharCategory,
EditorSelection,
EditorState,
Facet,
MapMode,
Prec,
RangeSet,
RangeSetBuilder,
RangeValue,
StateEffect,
StateField,
Text,
Transaction,
codePointAt,
codePointSize,
combineConfig,
countColumn,
findClusterBreak,
findColumn
} from "./chunk-4MUKC4ON.js";
// node_modules/style-mod/src/style-mod.js
var C = "ͼ";
var COUNT = typeof Symbol == "undefined" ? "__" + C : Symbol.for(C);
var SET = typeof Symbol == "undefined" ? "__styleSet" + Math.floor(Math.random() * 1e8) : Symbol("styleSet");
var top = typeof globalThis != "undefined" ? globalThis : typeof window != "undefined" ? window : {};
var StyleModule = class {
// :: (Object<Style>, ?{finish: ?(string) → string})
// Create a style module from the given spec.
//
// When `finish` is given, it is called on regular (non-`@`)
// selectors (after `&` expansion) to compute the final selector.
constructor(spec, options) {
this.rules = [];
let { finish } = options || {};
function splitSelector(selector) {
return /^@/.test(selector) ? [selector] : selector.split(/,\s*/);
}
function render(selectors, spec2, target, isKeyframes) {
let local = [], isAt = /^@(\w+)\b/.exec(selectors[0]), keyframes = isAt && isAt[1] == "keyframes";
if (isAt && spec2 == null) return target.push(selectors[0] + ";");
for (let prop in spec2) {
let value = spec2[prop];
if (/&/.test(prop)) {
render(
prop.split(/,\s*/).map((part) => selectors.map((sel) => part.replace(/&/, sel))).reduce((a, b) => a.concat(b)),
value,
target
);
} else if (value && typeof value == "object") {
if (!isAt) throw new RangeError("The value of a property (" + prop + ") should be a primitive value.");
render(splitSelector(prop), value, local, keyframes);
} else if (value != null) {
local.push(prop.replace(/_.*/, "").replace(/[A-Z]/g, (l) => "-" + l.toLowerCase()) + ": " + value + ";");
}
}
if (local.length || keyframes) {
target.push((finish && !isAt && !isKeyframes ? selectors.map(finish) : selectors).join(", ") + " {" + local.join(" ") + "}");
}
}
for (let prop in spec) render(splitSelector(prop), spec[prop], this.rules);
}
// :: () → string
// Returns a string containing the module's CSS rules.
getRules() {
return this.rules.join("\n");
}
// :: () → string
// Generate a new unique CSS class name.
static newName() {
let id = top[COUNT] || 1;
top[COUNT] = id + 1;
return C + id.toString(36);
}
// :: (union<Document, ShadowRoot>, union<[StyleModule], StyleModule>, ?{nonce: ?string})
//
// Mount the given set of modules in the given DOM root, which ensures
// that the CSS rules defined by the module are available in that
// context.
//
// Rules are only added to the document once per root.
//
// Rule order will follow the order of the modules, so that rules from
// modules later in the array take precedence of those from earlier
// modules. If you call this function multiple times for the same root
// in a way that changes the order of already mounted modules, the old
// order will be changed.
//
// If a Content Security Policy nonce is provided, it is added to
// the `<style>` tag generated by the library.
static mount(root, modules, options) {
let set = root[SET], nonce = options && options.nonce;
if (!set) set = new StyleSet(root, nonce);
else if (nonce) set.setNonce(nonce);
set.mount(Array.isArray(modules) ? modules : [modules], root);
}
};
var adoptedSet = /* @__PURE__ */ new Map();
var StyleSet = class {
constructor(root, nonce) {
let doc2 = root.ownerDocument || root, win = doc2.defaultView;
if (!root.head && root.adoptedStyleSheets && win.CSSStyleSheet) {
let adopted = adoptedSet.get(doc2);
if (adopted) return root[SET] = adopted;
this.sheet = new win.CSSStyleSheet();
adoptedSet.set(doc2, this);
} else {
this.styleTag = doc2.createElement("style");
if (nonce) this.styleTag.setAttribute("nonce", nonce);
}
this.modules = [];
root[SET] = this;
}
mount(modules, root) {
let sheet = this.sheet;
let pos = 0, j = 0;
for (let i = 0; i < modules.length; i++) {
let mod = modules[i], index = this.modules.indexOf(mod);
if (index < j && index > -1) {
this.modules.splice(index, 1);
j--;
index = -1;
}
if (index == -1) {
this.modules.splice(j++, 0, mod);
if (sheet) for (let k = 0; k < mod.rules.length; k++)
sheet.insertRule(mod.rules[k], pos++);
} else {
while (j < index) pos += this.modules[j++].rules.length;
pos += mod.rules.length;
j++;
}
}
if (sheet) {
if (root.adoptedStyleSheets.indexOf(this.sheet) < 0)
root.adoptedStyleSheets = [this.sheet, ...root.adoptedStyleSheets];
} else {
let text = "";
for (let i = 0; i < this.modules.length; i++)
text += this.modules[i].getRules() + "\n";
this.styleTag.textContent = text;
let target = root.head || root;
if (this.styleTag.parentNode != target)
target.insertBefore(this.styleTag, target.firstChild);
}
}
setNonce(nonce) {
if (this.styleTag && this.styleTag.getAttribute("nonce") != nonce)
this.styleTag.setAttribute("nonce", nonce);
}
};
// node_modules/w3c-keyname/index.js
var base = {
8: "Backspace",
9: "Tab",
10: "Enter",
12: "NumLock",
13: "Enter",
16: "Shift",
17: "Control",
18: "Alt",
20: "CapsLock",
27: "Escape",
32: " ",
33: "PageUp",
34: "PageDown",
35: "End",
36: "Home",
37: "ArrowLeft",
38: "ArrowUp",
39: "ArrowRight",
40: "ArrowDown",
44: "PrintScreen",
45: "Insert",
46: "Delete",
59: ";",
61: "=",
91: "Meta",
92: "Meta",
106: "*",
107: "+",
108: ",",
109: "-",
110: ".",
111: "/",
144: "NumLock",
145: "ScrollLock",
160: "Shift",
161: "Shift",
162: "Control",
163: "Control",
164: "Alt",
165: "Alt",
173: "-",
186: ";",
187: "=",
188: ",",
189: "-",
190: ".",
191: "/",
192: "`",
219: "[",
220: "\\",
221: "]",
222: "'"
};
var shift = {
48: ")",
49: "!",
50: "@",
51: "#",
52: "$",
53: "%",
54: "^",
55: "&",
56: "*",
57: "(",
59: ":",
61: "+",
173: "_",
186: ":",
187: "+",
188: "<",
189: "_",
190: ">",
191: "?",
192: "~",
219: "{",
220: "|",
221: "}",
222: '"'
};
var mac = typeof navigator != "undefined" && /Mac/.test(navigator.platform);
var ie = typeof navigator != "undefined" && /MSIE \d|Trident\/(?:[7-9]|\d{2,})\..*rv:(\d+)/.exec(navigator.userAgent);
for (i = 0; i < 10; i++) base[48 + i] = base[96 + i] = String(i);
var i;
for (i = 1; i <= 24; i++) base[i + 111] = "F" + i;
var i;
for (i = 65; i <= 90; i++) {
base[i] = String.fromCharCode(i + 32);
shift[i] = String.fromCharCode(i);
}
var i;
for (code in base) if (!shift.hasOwnProperty(code)) shift[code] = base[code];
var code;
function keyName(event) {
var ignoreKey = mac && event.metaKey && event.shiftKey && !event.ctrlKey && !event.altKey || ie && event.shiftKey && event.key && event.key.length == 1 || event.key == "Unidentified";
var name = !ignoreKey && event.key || (event.shiftKey ? shift : base)[event.keyCode] || event.key || "Unidentified";
if (name == "Esc") name = "Escape";
if (name == "Del") name = "Delete";
if (name == "Left") name = "ArrowLeft";
if (name == "Up") name = "ArrowUp";
if (name == "Right") name = "ArrowRight";
if (name == "Down") name = "ArrowDown";
return name;
}
// node_modules/crelt/index.js
function crelt() {
var elt = arguments[0];
if (typeof elt == "string") elt = document.createElement(elt);
var i = 1, next = arguments[1];
if (next && typeof next == "object" && next.nodeType == null && !Array.isArray(next)) {
for (var name in next) if (Object.prototype.hasOwnProperty.call(next, name)) {
var value = next[name];
if (typeof value == "string") elt.setAttribute(name, value);
else if (value != null) elt[name] = value;
}
i++;
}
for (; i < arguments.length; i++) add(elt, arguments[i]);
return elt;
}
function add(elt, child) {
if (typeof child == "string") {
elt.appendChild(document.createTextNode(child));
} else if (child == null) {
} else if (child.nodeType != null) {
elt.appendChild(child);
} else if (Array.isArray(child)) {
for (var i = 0; i < child.length; i++) add(elt, child[i]);
} else {
throw new RangeError("Unsupported child node: " + child);
}
}
// node_modules/@codemirror/view/dist/index.js
var nav = typeof navigator != "undefined" ? navigator : { userAgent: "", vendor: "", platform: "" };
var doc = typeof document != "undefined" ? document : { documentElement: { style: {} } };
var ie_edge = /Edge\/(\d+)/.exec(nav.userAgent);
var ie_upto10 = /MSIE \d/.test(nav.userAgent);
var ie_11up = /Trident\/(?:[7-9]|\d{2,})\..*rv:(\d+)/.exec(nav.userAgent);
var ie2 = !!(ie_upto10 || ie_11up || ie_edge);
var gecko = !ie2 && /gecko\/(\d+)/i.test(nav.userAgent);
var chrome = !ie2 && /Chrome\/(\d+)/.exec(nav.userAgent);
var webkit = "webkitFontSmoothing" in doc.documentElement.style;
var safari = !ie2 && /Apple Computer/.test(nav.vendor);
var ios = safari && (/Mobile\/\w+/.test(nav.userAgent) || nav.maxTouchPoints > 2);
var browser = {
mac: ios || /Mac/.test(nav.platform),
windows: /Win/.test(nav.platform),
linux: /Linux|X11/.test(nav.platform),
ie: ie2,
ie_version: ie_upto10 ? doc.documentMode || 6 : ie_11up ? +ie_11up[1] : ie_edge ? +ie_edge[1] : 0,
gecko,
gecko_version: gecko ? +(/Firefox\/(\d+)/.exec(nav.userAgent) || [0, 0])[1] : 0,
chrome: !!chrome,
chrome_version: chrome ? +chrome[1] : 0,
ios,
android: /Android\b/.test(nav.userAgent),
webkit,
webkit_version: webkit ? +(/\bAppleWebKit\/(\d+)/.exec(nav.userAgent) || [0, 0])[1] : 0,
safari,
safari_version: safari ? +(/\bVersion\/(\d+(\.\d+)?)/.exec(nav.userAgent) || [0, 0])[1] : 0,
tabSize: doc.documentElement.style.tabSize != null ? "tab-size" : "-moz-tab-size"
};
function combineAttrs(source, target) {
for (let name in source) {
if (name == "class" && target.class)
target.class += " " + source.class;
else if (name == "style" && target.style)
target.style += ";" + source.style;
else
target[name] = source[name];
}
return target;
}
var noAttrs = /* @__PURE__ */ Object.create(null);
function attrsEq(a, b, ignore) {
if (a == b)
return true;
if (!a)
a = noAttrs;
if (!b)
b = noAttrs;
let keysA = Object.keys(a), keysB = Object.keys(b);
if (keysA.length - (ignore && keysA.indexOf(ignore) > -1 ? 1 : 0) != keysB.length - (ignore && keysB.indexOf(ignore) > -1 ? 1 : 0))
return false;
for (let key of keysA) {
if (key != ignore && (keysB.indexOf(key) == -1 || a[key] !== b[key]))
return false;
}
return true;
}
function setAttrs(dom, attrs) {
for (let i = dom.attributes.length - 1; i >= 0; i--) {
let name = dom.attributes[i].name;
if (attrs[name] == null)
dom.removeAttribute(name);
}
for (let name in attrs) {
let value = attrs[name];
if (name == "style")
dom.style.cssText = value;
else if (dom.getAttribute(name) != value)
dom.setAttribute(name, value);
}
}
function updateAttrs(dom, prev, attrs) {
let changed = false;
if (prev) {
for (let name in prev)
if (!(attrs && name in attrs)) {
changed = true;
if (name == "style")
dom.style.cssText = "";
else
dom.removeAttribute(name);
}
}
if (attrs) {
for (let name in attrs)
if (!(prev && prev[name] == attrs[name])) {
changed = true;
if (name == "style")
dom.style.cssText = attrs[name];
else
dom.setAttribute(name, attrs[name]);
}
}
return changed;
}
function getAttrs(dom) {
let attrs = /* @__PURE__ */ Object.create(null);
for (let i = 0; i < dom.attributes.length; i++) {
let attr = dom.attributes[i];
attrs[attr.name] = attr.value;
}
return attrs;
}
var WidgetType = class {
/**
Compare this instance to another instance of the same type.
(TypeScript can't express this, but only instances of the same
specific class will be passed to this method.) This is used to
avoid redrawing widgets when they are replaced by a new
decoration of the same type. The default implementation just
returns `false`, which will cause new instances of the widget to
always be redrawn.
*/
eq(widget) {
return false;
}
/**
Update a DOM element created by a widget of the same type (but
different, non-`eq` content) to reflect this widget. May return
true to indicate that it could update, false to indicate it
couldn't (in which case the widget will be redrawn). The default
implementation just returns false.
*/
updateDOM(dom, view, from) {
return false;
}
/**
@internal
*/
compare(other) {
return this == other || this.constructor == other.constructor && this.eq(other);
}
/**
The estimated height this widget will have, to be used when
estimating the height of content that hasn't been drawn. May
return -1 to indicate you don't know. The default implementation
returns -1.
*/
get estimatedHeight() {
return -1;
}
/**
For inline widgets that are displayed inline (as opposed to
`inline-block`) and introduce line breaks (through `<br>` tags
or textual newlines), this must indicate the amount of line
breaks they introduce. Defaults to 0.
*/
get lineBreaks() {
return 0;
}
/**
Can be used to configure which kinds of events inside the widget
should be ignored by the editor. The default is to ignore all
events.
*/
ignoreEvent(event) {
return true;
}
/**
Override the way screen coordinates for positions at/in the
widget are found. `pos` will be the offset into the widget, and
`side` the side of the position that is being queriedless than
zero for before, greater than zero for after, and zero for
directly at that position.
*/
coordsAt(dom, pos, side) {
return null;
}
/**
@internal
*/
get isHidden() {
return false;
}
/**
@internal
*/
get editable() {
return false;
}
/**
This is called when the an instance of the widget is removed
from the editor view.
*/
destroy(dom) {
}
};
var BlockType = function(BlockType2) {
BlockType2[BlockType2["Text"] = 0] = "Text";
BlockType2[BlockType2["WidgetBefore"] = 1] = "WidgetBefore";
BlockType2[BlockType2["WidgetAfter"] = 2] = "WidgetAfter";
BlockType2[BlockType2["WidgetRange"] = 3] = "WidgetRange";
return BlockType2;
}(BlockType || (BlockType = {}));
var Decoration = class extends RangeValue {
constructor(startSide, endSide, widget, spec) {
super();
this.startSide = startSide;
this.endSide = endSide;
this.widget = widget;
this.spec = spec;
}
/**
@internal
*/
get heightRelevant() {
return false;
}
/**
Create a mark decoration, which influences the styling of the
content in its range. Nested mark decorations will cause nested
DOM elements to be created. Nesting order is determined by
precedence of the [facet](https://codemirror.net/6/docs/ref/#view.EditorView^decorations), with
the higher-precedence decorations creating the inner DOM nodes.
Such elements are split on line boundaries and on the boundaries
of lower-precedence decorations.
*/
static mark(spec) {
return new MarkDecoration(spec);
}
/**
Create a widget decoration, which displays a DOM element at the
given position.
*/
static widget(spec) {
let side = Math.max(-1e4, Math.min(1e4, spec.side || 0)), block = !!spec.block;
side += block && !spec.inlineOrder ? side > 0 ? 3e8 : -4e8 : side > 0 ? 1e8 : -1e8;
return new PointDecoration(spec, side, side, block, spec.widget || null, false);
}
/**
Create a replace decoration which replaces the given range with
a widget, or simply hides it.
*/
static replace(spec) {
let block = !!spec.block, startSide, endSide;
if (spec.isBlockGap) {
startSide = -5e8;
endSide = 4e8;
} else {
let { start, end } = getInclusive(spec, block);
startSide = (start ? block ? -3e8 : -1 : 5e8) - 1;
endSide = (end ? block ? 2e8 : 1 : -6e8) + 1;
}
return new PointDecoration(spec, startSide, endSide, block, spec.widget || null, true);
}
/**
Create a line decoration, which can add DOM attributes to the
line starting at the given position.
*/
static line(spec) {
return new LineDecoration(spec);
}
/**
Build a [`DecorationSet`](https://codemirror.net/6/docs/ref/#view.DecorationSet) from the given
decorated range or ranges. If the ranges aren't already sorted,
pass `true` for `sort` to make the library sort them for you.
*/
static set(of, sort = false) {
return RangeSet.of(of, sort);
}
/**
@internal
*/
hasHeight() {
return this.widget ? this.widget.estimatedHeight > -1 : false;
}
};
Decoration.none = RangeSet.empty;
var MarkDecoration = class _MarkDecoration extends Decoration {
constructor(spec) {
let { start, end } = getInclusive(spec);
super(start ? -1 : 5e8, end ? 1 : -6e8, null, spec);
this.tagName = spec.tagName || "span";
this.attrs = spec.class && spec.attributes ? combineAttrs(spec.attributes, { class: spec.class }) : spec.class ? { class: spec.class } : spec.attributes || noAttrs;
}
eq(other) {
return this == other || other instanceof _MarkDecoration && this.tagName == other.tagName && attrsEq(this.attrs, other.attrs);
}
range(from, to = from) {
if (from >= to)
throw new RangeError("Mark decorations may not be empty");
return super.range(from, to);
}
};
MarkDecoration.prototype.point = false;
var LineDecoration = class _LineDecoration extends Decoration {
constructor(spec) {
super(-2e8, -2e8, null, spec);
}
eq(other) {
return other instanceof _LineDecoration && this.spec.class == other.spec.class && attrsEq(this.spec.attributes, other.spec.attributes);
}
range(from, to = from) {
if (to != from)
throw new RangeError("Line decoration ranges must be zero-length");
return super.range(from, to);
}
};
LineDecoration.prototype.mapMode = MapMode.TrackBefore;
LineDecoration.prototype.point = true;
var PointDecoration = class _PointDecoration extends Decoration {
constructor(spec, startSide, endSide, block, widget, isReplace) {
super(startSide, endSide, widget, spec);
this.block = block;
this.isReplace = isReplace;
this.mapMode = !block ? MapMode.TrackDel : startSide <= 0 ? MapMode.TrackBefore : MapMode.TrackAfter;
}
// Only relevant when this.block == true
get type() {
return this.startSide != this.endSide ? BlockType.WidgetRange : this.startSide <= 0 ? BlockType.WidgetBefore : BlockType.WidgetAfter;
}
get heightRelevant() {
return this.block || !!this.widget && (this.widget.estimatedHeight >= 5 || this.widget.lineBreaks > 0);
}
eq(other) {
return other instanceof _PointDecoration && widgetsEq(this.widget, other.widget) && this.block == other.block && this.startSide == other.startSide && this.endSide == other.endSide;
}
range(from, to = from) {
if (this.isReplace && (from > to || from == to && this.startSide > 0 && this.endSide <= 0))
throw new RangeError("Invalid range for replacement decoration");
if (!this.isReplace && to != from)
throw new RangeError("Widget decorations can only have zero-length ranges");
return super.range(from, to);
}
};
PointDecoration.prototype.point = true;
function getInclusive(spec, block = false) {
let { inclusiveStart: start, inclusiveEnd: end } = spec;
if (start == null)
start = spec.inclusive;
if (end == null)
end = spec.inclusive;
return { start: start !== null && start !== void 0 ? start : block, end: end !== null && end !== void 0 ? end : block };
}
function widgetsEq(a, b) {
return a == b || !!(a && b && a.compare(b));
}
function addRange(from, to, ranges, margin = 0) {
let last = ranges.length - 1;
if (last >= 0 && ranges[last] + margin >= from)
ranges[last] = Math.max(ranges[last], to);
else
ranges.push(from, to);
}
var BlockWrapper = class _BlockWrapper extends RangeValue {
constructor(tagName, attributes, rank) {
super();
this.tagName = tagName;
this.attributes = attributes;
this.rank = rank;
}
eq(other) {
return other == this || other instanceof _BlockWrapper && this.tagName == other.tagName && attrsEq(this.attributes, other.attributes);
}
/**
Create a block wrapper object with the given tag name and
attributes.
*/
static create(spec) {
return new _BlockWrapper(spec.tagName, spec.attributes || noAttrs, spec.rank == null ? 50 : Math.max(0, Math.min(spec.rank, 100)));
}
/**
Create a range set from the given block wrapper ranges.
*/
static set(of, sort = false) {
return RangeSet.of(of, sort);
}
};
BlockWrapper.prototype.startSide = BlockWrapper.prototype.endSide = -1;
function getSelection(root) {
let target;
if (root.nodeType == 11) {
target = root.getSelection ? root : root.ownerDocument;
} else {
target = root;
}
return target.getSelection();
}
function contains(dom, node) {
return node ? dom == node || dom.contains(node.nodeType != 1 ? node.parentNode : node) : false;
}
function hasSelection(dom, selection) {
if (!selection.anchorNode)
return false;
try {
return contains(dom, selection.anchorNode);
} catch (_) {
return false;
}
}
function clientRectsFor(dom) {
if (dom.nodeType == 3)
return textRange(dom, 0, dom.nodeValue.length).getClientRects();
else if (dom.nodeType == 1)
return dom.getClientRects();
else
return [];
}
function isEquivalentPosition(node, off, targetNode, targetOff) {
return targetNode ? scanFor(node, off, targetNode, targetOff, -1) || scanFor(node, off, targetNode, targetOff, 1) : false;
}
function domIndex(node) {
for (var index = 0; ; index++) {
node = node.previousSibling;
if (!node)
return index;
}
}
function isBlockElement(node) {
return node.nodeType == 1 && /^(DIV|P|LI|UL|OL|BLOCKQUOTE|DD|DT|H\d|SECTION|PRE)$/.test(node.nodeName);
}
function scanFor(node, off, targetNode, targetOff, dir) {
for (; ; ) {
if (node == targetNode && off == targetOff)
return true;
if (off == (dir < 0 ? 0 : maxOffset(node))) {
if (node.nodeName == "DIV")
return false;
let parent = node.parentNode;
if (!parent || parent.nodeType != 1)
return false;
off = domIndex(node) + (dir < 0 ? 0 : 1);
node = parent;
} else if (node.nodeType == 1) {
node = node.childNodes[off + (dir < 0 ? -1 : 0)];
if (node.nodeType == 1 && node.contentEditable == "false")
return false;
off = dir < 0 ? maxOffset(node) : 0;
} else {
return false;
}
}
}
function maxOffset(node) {
return node.nodeType == 3 ? node.nodeValue.length : node.childNodes.length;
}
function flattenRect(rect, left) {
let x = left ? rect.left : rect.right;
return { left: x, right: x, top: rect.top, bottom: rect.bottom };
}
function windowRect(win) {
let vp = win.visualViewport;
if (vp)
return {
left: 0,
right: vp.width,
top: 0,
bottom: vp.height
};
return {
left: 0,
right: win.innerWidth,
top: 0,
bottom: win.innerHeight
};
}
function getScale(elt, rect) {
let scaleX = rect.width / elt.offsetWidth;
let scaleY = rect.height / elt.offsetHeight;
if (scaleX > 0.995 && scaleX < 1.005 || !isFinite(scaleX) || Math.abs(rect.width - elt.offsetWidth) < 1)
scaleX = 1;
if (scaleY > 0.995 && scaleY < 1.005 || !isFinite(scaleY) || Math.abs(rect.height - elt.offsetHeight) < 1)
scaleY = 1;
return { scaleX, scaleY };
}
function scrollRectIntoView(dom, rect, side, x, y, xMargin, yMargin, ltr) {
let doc2 = dom.ownerDocument, win = doc2.defaultView || window;
for (let cur = dom, stop = false; cur && !stop; ) {
if (cur.nodeType == 1) {
let bounding, top2 = cur == doc2.body;
let scaleX = 1, scaleY = 1;
if (top2) {
bounding = windowRect(win);
} else {
if (/^(fixed|sticky)$/.test(getComputedStyle(cur).position))
stop = true;
if (cur.scrollHeight <= cur.clientHeight && cur.scrollWidth <= cur.clientWidth) {
cur = cur.assignedSlot || cur.parentNode;
continue;
}
let rect2 = cur.getBoundingClientRect();
({ scaleX, scaleY } = getScale(cur, rect2));
bounding = {
left: rect2.left,
right: rect2.left + cur.clientWidth * scaleX,
top: rect2.top,
bottom: rect2.top + cur.clientHeight * scaleY
};
}
let moveX = 0, moveY = 0;
if (y == "nearest") {
if (rect.top < bounding.top + yMargin) {
moveY = rect.top - (bounding.top + yMargin);
if (side > 0 && rect.bottom > bounding.bottom + moveY)
moveY = rect.bottom - bounding.bottom + yMargin;
} else if (rect.bottom > bounding.bottom - yMargin) {
moveY = rect.bottom - bounding.bottom + yMargin;
if (side < 0 && rect.top - moveY < bounding.top)
moveY = rect.top - (bounding.top + yMargin);
}
} else {
let rectHeight = rect.bottom - rect.top, boundingHeight = bounding.bottom - bounding.top;
let targetTop = y == "center" && rectHeight <= boundingHeight ? rect.top + rectHeight / 2 - boundingHeight / 2 : y == "start" || y == "center" && side < 0 ? rect.top - yMargin : rect.bottom - boundingHeight + yMargin;
moveY = targetTop - bounding.top;
}
if (x == "nearest") {
if (rect.left < bounding.left + xMargin) {
moveX = rect.left - (bounding.left + xMargin);
if (side > 0 && rect.right > bounding.right + moveX)
moveX = rect.right - bounding.right + xMargin;
} else if (rect.right > bounding.right - xMargin) {
moveX = rect.right - bounding.right + xMargin;
if (side < 0 && rect.left < bounding.left + moveX)
moveX = rect.left - (bounding.left + xMargin);
}
} else {
let targetLeft = x == "center" ? rect.left + (rect.right - rect.left) / 2 - (bounding.right - bounding.left) / 2 : x == "start" == ltr ? rect.left - xMargin : rect.right - (bounding.right - bounding.left) + xMargin;
moveX = targetLeft - bounding.left;
}
if (moveX || moveY) {
if (top2) {
win.scrollBy(moveX, moveY);
} else {
let movedX = 0, movedY = 0;
if (moveY) {
let start = cur.scrollTop;
cur.scrollTop += moveY / scaleY;
movedY = (cur.scrollTop - start) * scaleY;
}
if (moveX) {
let start = cur.scrollLeft;
cur.scrollLeft += moveX / scaleX;
movedX = (cur.scrollLeft - start) * scaleX;
}
rect = {
left: rect.left - movedX,
top: rect.top - movedY,
right: rect.right - movedX,
bottom: rect.bottom - movedY
};
if (movedX && Math.abs(movedX - moveX) < 1)
x = "nearest";
if (movedY && Math.abs(movedY - moveY) < 1)
y = "nearest";
}
}
if (top2)
break;
if (rect.top < bounding.top || rect.bottom > bounding.bottom || rect.left < bounding.left || rect.right > bounding.right)
rect = {
left: Math.max(rect.left, bounding.left),
right: Math.min(rect.right, bounding.right),
top: Math.max(rect.top, bounding.top),
bottom: Math.min(rect.bottom, bounding.bottom)
};
cur = cur.assignedSlot || cur.parentNode;
} else if (cur.nodeType == 11) {
cur = cur.host;
} else {
break;
}
}
}
function scrollableParents(dom, getX = true) {
let doc2 = dom.ownerDocument, x = null, y = null;
for (let cur = dom.parentNode; cur; ) {
if (cur == doc2.body || (!getX || x) && y) {
break;
} else if (cur.nodeType == 1) {
if (!y && cur.scrollHeight > cur.clientHeight)
y = cur;
if (getX && !x && cur.scrollWidth > cur.clientWidth)
x = cur;
cur = cur.assignedSlot || cur.parentNode;
} else if (cur.nodeType == 11) {
cur = cur.host;
} else {
break;
}
}
return { x, y };
}
var DOMSelectionState = class {
constructor() {
this.anchorNode = null;
this.anchorOffset = 0;
this.focusNode = null;
this.focusOffset = 0;
}
eq(domSel) {
return this.anchorNode == domSel.anchorNode && this.anchorOffset == domSel.anchorOffset && this.focusNode == domSel.focusNode && this.focusOffset == domSel.focusOffset;
}
setRange(range) {
let { anchorNode, focusNode } = range;
this.set(anchorNode, Math.min(range.anchorOffset, anchorNode ? maxOffset(anchorNode) : 0), focusNode, Math.min(range.focusOffset, focusNode ? maxOffset(focusNode) : 0));
}
set(anchorNode, anchorOffset, focusNode, focusOffset) {
this.anchorNode = anchorNode;
this.anchorOffset = anchorOffset;
this.focusNode = focusNode;
this.focusOffset = focusOffset;
}
};
var preventScrollSupported = null;
if (browser.safari && browser.safari_version >= 26)
preventScrollSupported = false;
function focusPreventScroll(dom) {
if (dom.setActive)
return dom.setActive();
if (preventScrollSupported)
return dom.focus(preventScrollSupported);
let stack = [];
for (let cur = dom; cur; cur = cur.parentNode) {
stack.push(cur, cur.scrollTop, cur.scrollLeft);
if (cur == cur.ownerDocument)
break;
}
dom.focus(preventScrollSupported == null ? {
get preventScroll() {
preventScrollSupported = { preventScroll: true };
return true;
}
} : void 0);
if (!preventScrollSupported) {
preventScrollSupported = false;
for (let i = 0; i < stack.length; ) {
let elt = stack[i++], top2 = stack[i++], left = stack[i++];
if (elt.scrollTop != top2)
elt.scrollTop = top2;
if (elt.scrollLeft != left)
elt.scrollLeft = left;
}
}
}
var scratchRange;
function textRange(node, from, to = from) {
let range = scratchRange || (scratchRange = document.createRange());
range.setEnd(node, to);
range.setStart(node, from);
return range;
}
function dispatchKey(elt, name, code, mods) {
let options = { key: name, code: name, keyCode: code, which: code, cancelable: true };
if (mods)
({ altKey: options.altKey, ctrlKey: options.ctrlKey, shiftKey: options.shiftKey, metaKey: options.metaKey } = mods);
let down = new KeyboardEvent("keydown", options);
down.synthetic = true;
elt.dispatchEvent(down);
let up = new KeyboardEvent("keyup", options);
up.synthetic = true;
elt.dispatchEvent(up);
return down.defaultPrevented || up.defaultPrevented;
}
function getRoot(node) {
while (node) {
if (node && (node.nodeType == 9 || node.nodeType == 11 && node.host))
return node;
node = node.assignedSlot || node.parentNode;
}
return null;
}
function atElementStart(doc2, selection) {
let node = selection.focusNode, offset = selection.focusOffset;
if (!node || selection.anchorNode != node || selection.anchorOffset != offset)
return false;
offset = Math.min(offset, maxOffset(node));
for (; ; ) {
if (offset) {
if (node.nodeType != 1)
return false;
let prev = node.childNodes[offset - 1];
if (prev.contentEditable == "false")
offset--;
else {
node = prev;
offset = maxOffset(node);
}
} else if (node == doc2) {
return true;
} else {
offset = domIndex(node);
node = node.parentNode;
}
}
}
function isScrolledToBottom(elt) {
if (elt instanceof Window)
return elt.pageYOffset > Math.max(0, elt.document.documentElement.scrollHeight - elt.innerHeight - 4);
return elt.scrollTop > Math.max(1, elt.scrollHeight - elt.clientHeight - 4);
}
function textNodeBefore(startNode, startOffset) {
for (let node = startNode, offset = startOffset; ; ) {
if (node.nodeType == 3 && offset > 0) {
return { node, offset };
} else if (node.nodeType == 1 && offset > 0) {
if (node.contentEditable == "false")
return null;
node = node.childNodes[offset - 1];
offset = maxOffset(node);
} else if (node.parentNode && !isBlockElement(node)) {
offset = domIndex(node);
node = node.parentNode;
} else {
return null;
}
}
}
function textNodeAfter(startNode, startOffset) {
for (let node = startNode, offset = startOffset; ; ) {
if (node.nodeType == 3 && offset < node.nodeValue.length) {
return { node, offset };
} else if (node.nodeType == 1 && offset < node.childNodes.length) {
if (node.contentEditable == "false")
return null;
node = node.childNodes[offset];
offset = 0;
} else if (node.parentNode && !isBlockElement(node)) {
offset = domIndex(node) + 1;
node = node.parentNode;
} else {
return null;
}
}
}
var DOMPos = class _DOMPos {
constructor(node, offset, precise = true) {
this.node = node;
this.offset = offset;
this.precise = precise;
}
static before(dom, precise) {
return new _DOMPos(dom.parentNode, domIndex(dom), precise);
}
static after(dom, precise) {
return new _DOMPos(dom.parentNode, domIndex(dom) + 1, precise);
}
};
var Direction = function(Direction2) {
Direction2[Direction2["LTR"] = 0] = "LTR";
Direction2[Direction2["RTL"] = 1] = "RTL";
return Direction2;
}(Direction || (Direction = {}));
var LTR = Direction.LTR;
var RTL = Direction.RTL;
function dec(str) {
let result = [];
for (let i = 0; i < str.length; i++)
result.push(1 << +str[i]);
return result;
}
var LowTypes = dec("88888888888888888888888888888888888666888888787833333333337888888000000000000000000000000008888880000000000000000000000000088888888888888888888888888888888888887866668888088888663380888308888800000000000000000000000800000000000000000000000000000008");
var ArabicTypes = dec("4444448826627288999999999992222222222222222222222222222222222222222222222229999999999999999999994444444444644222822222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222999999949999999229989999223333333333");
var Brackets = /* @__PURE__ */ Object.create(null);
var BracketStack = [];
for (let p of ["()", "[]", "{}"]) {
let l = p.charCodeAt(0), r = p.charCodeAt(1);
Brackets[l] = r;
Brackets[r] = -l;
}
function charType(ch) {
return ch <= 247 ? LowTypes[ch] : 1424 <= ch && ch <= 1524 ? 2 : 1536 <= ch && ch <= 1785 ? ArabicTypes[ch - 1536] : 1774 <= ch && ch <= 2220 ? 4 : 8192 <= ch && ch <= 8204 ? 256 : 64336 <= ch && ch <= 65023 ? 4 : 1;
}
var BidiRE = /[\u0590-\u05f4\u0600-\u06ff\u0700-\u08ac\ufb50-\ufdff]/;
var BidiSpan = class {
/**
The direction of this span.
*/
get dir() {
return this.level % 2 ? RTL : LTR;
}
/**
@internal
*/
constructor(from, to, level) {
this.from = from;
this.to = to;
this.level = level;
}
/**
@internal
*/
side(end, dir) {
return this.dir == dir == end ? this.to : this.from;
}
/**
@internal
*/
forward(forward, dir) {
return forward == (this.dir == dir);
}
/**
@internal
*/
static find(order, index, level, assoc) {
let maybe = -1;
for (let i = 0; i < order.length; i++) {
let span = order[i];
if (span.from <= index && span.to >= index) {
if (span.level == level)
return i;
if (maybe < 0 || (assoc != 0 ? assoc < 0 ? span.from < index : span.to > index : order[maybe].level > span.level))
maybe = i;
}
}
if (maybe < 0)
throw new RangeError("Index out of range");
return maybe;
}
};
function isolatesEq(a, b) {
if (a.length != b.length)
return false;
for (let i = 0; i < a.length; i++) {
let iA = a[i], iB = b[i];
if (iA.from != iB.from || iA.to != iB.to || iA.direction != iB.direction || !isolatesEq(iA.inner, iB.inner))
return false;
}
return true;
}
var types = [];
function computeCharTypes(line, rFrom, rTo, isolates, outerType) {
for (let iI = 0; iI <= isolates.length; iI++) {
let from = iI ? isolates[iI - 1].to : rFrom, to = iI < isolates.length ? isolates[iI].from : rTo;
let prevType = iI ? 256 : outerType;
for (let i = from, prev = prevType, prevStrong = prevType; i < to; i++) {
let type = charType(line.charCodeAt(i));
if (type == 512)
type = prev;
else if (type == 8 && prevStrong == 4)
type = 16;
types[i] = type == 4 ? 2 : type;
if (type & 7)
prevStrong = type;
prev = type;
}
for (let i = from, prev = prevType, prevStrong = prevType; i < to; i++) {
let type = types[i];
if (type == 128) {
if (i < to - 1 && prev == types[i + 1] && prev & 24)
type = types[i] = prev;
else
types[i] = 256;
} else if (type == 64) {
let end = i + 1;
while (end < to && types[end] == 64)
end++;
let replace2 = i && prev == 8 || end < rTo && types[end] == 8 ? prevStrong == 1 ? 1 : 8 : 256;
for (let j = i; j < end; j++)
types[j] = replace2;
i = end - 1;
} else if (type == 8 && prevStrong == 1) {
types[i] = 1;
}
prev = type;
if (type & 7)
prevStrong = type;
}
}
}
function processBracketPairs(line, rFrom, rTo, isolates, outerType) {
let oppositeType = outerType == 1 ? 2 : 1;
for (let iI = 0, sI = 0, context = 0; iI <= isolates.length; iI++) {
let from = iI ? isolates[iI - 1].to : rFrom, to = iI < isolates.length ? isolates[iI].from : rTo;
for (let i = from, ch, br, type; i < to; i++) {
if (br = Brackets[ch = line.charCodeAt(i)]) {
if (br < 0) {
for (let sJ = sI - 3; sJ >= 0; sJ -= 3) {
if (BracketStack[sJ + 1] == -br) {
let flags = BracketStack[sJ + 2];
let type2 = flags & 2 ? outerType : !(flags & 4) ? 0 : flags & 1 ? oppositeType : outerType;
if (type2)
types[i] = types[BracketStack[sJ]] = type2;
sI = sJ;
break;
}
}
} else if (BracketStack.length == 189) {
break;
} else {
BracketStack[sI++] = i;
BracketStack[sI++] = ch;
BracketStack[sI++] = context;
}
} else if ((type = types[i]) == 2 || type == 1) {
let embed = type == outerType;
context = embed ? 0 : 1;
for (let sJ = sI - 3; sJ >= 0; sJ -= 3) {
let cur = BracketStack[sJ + 2];
if (cur & 2)
break;
if (embed) {
BracketStack[sJ + 2] |= 2;
} else {
if (cur & 4)
break;
BracketStack[sJ + 2] |= 4;
}
}
}
}
}
}
function processNeutrals(rFrom, rTo, isolates, outerType) {
for (let iI = 0, prev = outerType; iI <= isolates.length; iI++) {
let from = iI ? isolates[iI - 1].to : rFrom, to = iI < isolates.length ? isolates[iI].from : rTo;
for (let i = from; i < to; ) {
let type = types[i];
if (type == 256) {
let end = i + 1;
for (; ; ) {
if (end == to) {
if (iI == isolates.length)
break;
end = isolates[iI++].to;
to = iI < isolates.length ? isolates[iI].from : rTo;
} else if (types[end] == 256) {
end++;
} else {
break;
}
}
let beforeL = prev == 1;
let afterL = (end < rTo ? types[end] : outerType) == 1;
let replace2 = beforeL == afterL ? beforeL ? 1 : 2 : outerType;
for (let j = end, jI = iI, fromJ = jI ? isolates[jI - 1].to : rFrom; j > i; ) {
if (j == fromJ) {
j = isolates[--jI].from;
fromJ = jI ? isolates[jI - 1].to : rFrom;
}
types[--j] = replace2;
}
i = end;
} else {
prev = type;
i++;
}
}
}
}
function emitSpans(line, from, to, level, baseLevel, isolates, order) {
let ourType = level % 2 ? 2 : 1;
if (level % 2 == baseLevel % 2) {
for (let iCh = from, iI = 0; iCh < to; ) {
let sameDir = true, isNum = false;
if (iI == isolates.length || iCh < isolates[iI].from) {
let next = types[iCh];
if (next != ourType) {
sameDir = false;
isNum = next == 16;
}
}
let recurse = !sameDir && ourType == 1 ? [] : null;
let localLevel = sameDir ? level : level + 1;
let iScan = iCh;
run: for (; ; ) {
if (iI < isolates.length && iScan == isolates[iI].from) {
if (isNum)
break run;
let iso = isolates[iI];
if (!sameDir)
for (let upto = iso.to, jI = iI + 1; ; ) {
if (upto == to)
break run;
if (jI < isolates.length && isolates[jI].from == upto)
upto = isolates[jI++].to;
else if (types[upto] == ourType)
break run;
else
break;
}
iI++;
if (recurse) {
recurse.push(iso);
} else {
if (iso.from > iCh)
order.push(new BidiSpan(iCh, iso.from, localLevel));
let dirSwap = iso.direction == LTR != !(localLevel % 2);
computeSectionOrder(line, dirSwap ? level + 1 : level, baseLevel, iso.inner, iso.from, iso.to, order);
iCh = iso.to;
}
iScan = iso.to;
} else if (iScan == to || (sameDir ? types[iScan] != ourType : types[iScan] == ourType)) {
break;
} else {
iScan++;
}
}
if (recurse)
emitSpans(line, iCh, iScan, level + 1, baseLevel, recurse, order);
else if (iCh < iScan)
order.push(new BidiSpan(iCh, iScan, localLevel));
iCh = iScan;
}
} else {
for (let iCh = to, iI = isolates.length; iCh > from; ) {
let sameDir = true, isNum = false;
if (!iI || iCh > isolates[iI - 1].to) {
let next = types[iCh - 1];
if (next != ourType) {
sameDir = false;
isNum = next == 16;
}
}
let recurse = !sameDir && ourType == 1 ? [] : null;
let localLevel = sameDir ? level : level + 1;
let iScan = iCh;
run: for (; ; ) {
if (iI && iScan == isolates[iI - 1].to) {
if (isNum)
break run;
let iso = isolates[--iI];
if (!sameDir)
for (let upto = iso.from, jI = iI; ; ) {
if (upto == from)
break run;
if (jI && isolates[jI - 1].to == upto)
upto = isolates[--jI].from;
else if (types[upto - 1] == ourType)
break run;
else
break;
}
if (recurse) {
recurse.push(iso);
} else {
if (iso.to < iCh)
order.push(new BidiSpan(iso.to, iCh, localLevel));
let dirSwap = iso.direction == LTR != !(localLevel % 2);
computeSectionOrder(line, dirSwap ? level + 1 : level, baseLevel, iso.inner, iso.from, iso.to, order);
iCh = iso.from;
}
iScan = iso.from;
} else if (iScan == from || (sameDir ? types[iScan - 1] != ourType : types[iScan - 1] == ourType)) {
break;
} else {
iScan--;
}
}
if (recurse)
emitSpans(line, iScan, iCh, level + 1, baseLevel, recurse, order);
else if (iScan < iCh)
order.push(new BidiSpan(iScan, iCh, localLevel));
iCh = iScan;
}
}
}
function computeSectionOrder(line, level, baseLevel, isolates, from, to, order) {
let outerType = level % 2 ? 2 : 1;
computeCharTypes(line, from, to, isolates, outerType);
processBracketPairs(line, from, to, isolates, outerType);
processNeutrals(from, to, isolates, outerType);
emitSpans(line, from, to, level, baseLevel, isolates, order);
}
function computeOrder(line, direction, isolates) {
if (!line)
return [new BidiSpan(0, 0, direction == RTL ? 1 : 0)];
if (direction == LTR && !isolates.length && !BidiRE.test(line))
return trivialOrder(line.length);
if (isolates.length)
while (line.length > types.length)
types[types.length] = 256;
let order = [], level = direction == LTR ? 0 : 1;
computeSectionOrder(line, level, level, isolates, 0, line.length, order);
return order;
}
function trivialOrder(length) {
return [new BidiSpan(0, length, 0)];
}
var movedOver = "";
function moveVisually(line, order, dir, start, forward) {
var _a;
let startIndex = start.head - line.from;
let spanI = BidiSpan.find(order, startIndex, (_a = start.bidiLevel) !== null && _a !== void 0 ? _a : -1, start.assoc);
let span = order[spanI], spanEnd = span.side(forward, dir);
if (startIndex == spanEnd) {
let nextI = spanI += forward ? 1 : -1;
if (nextI < 0 || nextI >= order.length)
return null;
span = order[spanI = nextI];
startIndex = span.side(!forward, dir);
spanEnd = span.side(forward, dir);
}
let nextIndex = findClusterBreak(line.text, startIndex, span.forward(forward, dir));
if (nextIndex < span.from || nextIndex > span.to)
nextIndex = spanEnd;
movedOver = line.text.slice(Math.min(startIndex, nextIndex), Math.max(startIndex, nextIndex));
let nextSpan = spanI == (forward ? order.length - 1 : 0) ? null : order[spanI + (forward ? 1 : -1)];
if (nextSpan && nextIndex == spanEnd && nextSpan.level + (forward ? 0 : 1) < span.level)
return EditorSelection.cursor(nextSpan.side(!forward, dir) + line.from, nextSpan.forward(forward, dir) ? 1 : -1, nextSpan.level);
return EditorSelection.cursor(nextIndex + line.from, span.forward(forward, dir) ? -1 : 1, span.level);
}
function autoDirection(text, from, to) {
for (let i = from; i < to; i++) {
let type = charType(text.charCodeAt(i));
if (type == 1)
return LTR;
if (type == 2 || type == 4)
return RTL;
}
return LTR;
}
var clickAddsSelectionRange = Facet.define();
var dragMovesSelection$1 = Facet.define();
var mouseSelectionStyle = Facet.define();
var exceptionSink = Facet.define();
var updateListener = Facet.define();
var inputHandler = Facet.define();
var focusChangeEffect = Facet.define();
var clipboardInputFilter = Facet.define();
var clipboardOutputFilter = Facet.define();
var perLineTextDirection = Facet.define({
combine: (values) => values.some((x) => x)
});
var nativeSelectionHidden = Facet.define({
combine: (values) => values.some((x) => x)
});
var scrollHandler = Facet.define();
var ScrollTarget = class _ScrollTarget {
constructor(range, y, x, yMargin, xMargin, isSnapshot = false) {
this.range = range;
this.y = y;
this.x = x;
this.yMargin = yMargin;
this.xMargin = xMargin;
this.isSnapshot = isSnapshot;
}
map(changes) {
return changes.empty ? this : new _ScrollTarget(this.range.map(changes), this.y, this.x, this.yMargin, this.xMargin, this.isSnapshot);
}
clip(state) {
return this.range.to <= state.doc.length ? this : new _ScrollTarget(EditorSelection.cursor(state.doc.length), this.y, this.x, this.yMargin, this.xMargin, this.isSnapshot);
}
};
var scrollIntoView = StateEffect.define({ map: (t, ch) => t.map(ch) });
var setEditContextFormatting = StateEffect.define();
function logException(state, exception, context) {
let handler = state.facet(exceptionSink);
if (handler.length)
handler[0](exception);
else if (window.onerror && window.onerror(String(exception), context, void 0, void 0, exception)) ;
else if (context)
console.error(context + ":", exception);
else
console.error(exception);
}
var editable = Facet.define({ combine: (values) => values.length ? values[0] : true });
var nextPluginID = 0;
var viewPlugin = Facet.define({
combine(plugins) {
return plugins.filter((p, i) => {
for (let j = 0; j < i; j++)
if (plugins[j].plugin == p.plugin)
return false;
return true;
});
}
});
var ViewPlugin = class _ViewPlugin {
constructor(id, create, domEventHandlers, domEventObservers, buildExtensions) {
this.id = id;
this.create = create;
this.domEventHandlers = domEventHandlers;
this.domEventObservers = domEventObservers;
this.baseExtensions = buildExtensions(this);
this.extension = this.baseExtensions.concat(viewPlugin.of({ plugin: this, arg: void 0 }));
}
/**
Create an extension for this plugin with the given argument.
*/
of(arg) {
return this.baseExtensions.concat(viewPlugin.of({ plugin: this, arg }));
}
/**
Define a plugin from a constructor function that creates the
plugin's value, given an editor view.
*/
static define(create, spec) {
const { eventHandlers, eventObservers, provide, decorations: deco } = spec || {};
return new _ViewPlugin(nextPluginID++, create, eventHandlers, eventObservers, (plugin2) => {
let ext = [];
if (deco)
ext.push(decorations.of((view) => {
let pluginInst = view.plugin(plugin2);
return pluginInst ? deco(pluginInst) : Decoration.none;
}));
if (provide)
ext.push(provide(plugin2));
return ext;
});
}
/**
Create a plugin for a class whose constructor takes a single
editor view as argument.
*/
static fromClass(cls, spec) {
return _ViewPlugin.define((view, arg) => new cls(view, arg), spec);
}
};
var PluginInstance = class {
constructor(spec) {
this.spec = spec;
this.mustUpdate = null;
this.value = null;
}
get plugin() {
return this.spec && this.spec.plugin;
}
update(view) {
if (!this.value) {
if (this.spec) {
try {
this.value = this.spec.plugin.create(view, this.spec.arg);
} catch (e) {
logException(view.state, e, "CodeMirror plugin crashed");
this.deactivate();
}
}
} else if (this.mustUpdate) {
let update = this.mustUpdate;
this.mustUpdate = null;
if (this.value.update) {
try {
this.value.update(update);
} catch (e) {
logException(update.state, e, "CodeMirror plugin crashed");
if (this.value.destroy)
try {
this.value.destroy();
} catch (_) {
}
this.deactivate();
}
}
}
return this;
}
destroy(view) {
var _a;
if ((_a = this.value) === null || _a === void 0 ? void 0 : _a.destroy) {
try {
this.value.destroy();
} catch (e) {
logException(view.state, e, "CodeMirror plugin crashed");
}
}
}
deactivate() {
this.spec = this.value = null;
}
};
var editorAttributes = Facet.define();
var contentAttributes = Facet.define();
var decorations = Facet.define();
var blockWrappers = Facet.define();
var outerDecorations = Facet.define();
var atomicRanges = Facet.define();
var bidiIsolatedRanges = Facet.define();
function getIsolatedRanges(view, line) {
let isolates = view.state.facet(bidiIsolatedRanges);
if (!isolates.length)
return isolates;
let sets = isolates.map((i) => i instanceof Function ? i(view) : i);
let result = [];
RangeSet.spans(sets, line.from, line.to, {
point() {
},
span(fromDoc, toDoc, active, open) {
let from = fromDoc - line.from, to = toDoc - line.from;
let level = result;
for (let i = active.length - 1; i >= 0; i--, open--) {
let direction = active[i].spec.bidiIsolate, update;
if (direction == null)
direction = autoDirection(line.text, from, to);
if (open > 0 && level.length && (update = level[level.length - 1]).to == from && update.direction == direction) {
update.to = to;
level = update.inner;
} else {
let add2 = { from, to, direction, inner: [] };
level.push(add2);
level = add2.inner;
}
}
}
});
return result;
}
var scrollMargins = Facet.define();
function getScrollMargins(view) {
let left = 0, right = 0, top2 = 0, bottom = 0;
for (let source of view.state.facet(scrollMargins)) {
let m = source(view);
if (m) {
if (m.left != null)
left = Math.max(left, m.left);
if (m.right != null)
right = Math.max(right, m.right);
if (m.top != null)
top2 = Math.max(top2, m.top);
if (m.bottom != null)
bottom = Math.max(bottom, m.bottom);
}
}
return { left, right, top: top2, bottom };
}
var styleModule = Facet.define();
var ChangedRange = class _ChangedRange {
constructor(fromA, toA, fromB, toB) {
this.fromA = fromA;
this.toA = toA;
this.fromB = fromB;
this.toB = toB;
}
join(other) {
return new _ChangedRange(Math.min(this.fromA, other.fromA), Math.max(this.toA, other.toA), Math.min(this.fromB, other.fromB), Math.max(this.toB, other.toB));
}
addToSet(set) {
let i = set.length, me = this;
for (; i > 0; i--) {
let range = set[i - 1];
if (range.fromA > me.toA)
continue;
if (range.toA < me.fromA)
break;
me = me.join(range);
set.splice(i - 1, 1);
}
set.splice(i, 0, me);
return set;
}
// Extend a set to cover all the content in `ranges`, which is a
// flat array with each pair of numbers representing fromB/toB
// positions. These pairs are generated in unchanged ranges, so the
// offset between doc A and doc B is the same for their start and
// end points.
static extendWithRanges(diff, ranges) {
if (ranges.length == 0)
return diff;
let result = [];
for (let dI = 0, rI = 0, off = 0; ; ) {
let nextD = dI < diff.length ? diff[dI].fromB : 1e9;
let nextR = rI < ranges.length ? ranges[rI] : 1e9;
let fromB = Math.min(nextD, nextR);
if (fromB == 1e9)
break;
let fromA = fromB + off, toB = fromB, toA = fromA;
for (; ; ) {
if (rI < ranges.length && ranges[rI] <= toB) {
let end = ranges[rI + 1];
rI += 2;
toB = Math.max(toB, end);
for (let i = dI; i < diff.length && diff[i].fromB <= toB; i++)
off = diff[i].toA - diff[i].toB;
toA = Math.max(toA, end + off);
} else if (dI < diff.length && diff[dI].fromB <= toB) {
let next = diff[dI++];
toB = Math.max(toB, next.toB);
toA = Math.max(toA, next.toA);
off = next.toA - next.toB;
} else {
break;
}
}
result.push(new _ChangedRange(fromA, toA, fromB, toB));
}
return result;
}
};
var ViewUpdate = class _ViewUpdate {
constructor(view, state, transactions) {
this.view = view;
this.state = state;
this.transactions = transactions;
this.flags = 0;
this.startState = view.state;
this.changes = ChangeSet.empty(this.startState.doc.length);
for (let tr of transactions)
this.changes = this.changes.compose(tr.changes);
let changedRanges = [];
this.changes.iterChangedRanges((fromA, toA, fromB, toB) => changedRanges.push(new ChangedRange(fromA, toA, fromB, toB)));
this.changedRanges = changedRanges;
}
/**
@internal
*/
static create(view, state, transactions) {
return new _ViewUpdate(view, state, transactions);
}
/**
Tells you whether the [viewport](https://codemirror.net/6/docs/ref/#view.EditorView.viewport) or
[visible ranges](https://codemirror.net/6/docs/ref/#view.EditorView.visibleRanges) changed in this
update.
*/
get viewportChanged() {
return (this.flags & 4) > 0;
}
/**
Returns true when
[`viewportChanged`](https://codemirror.net/6/docs/ref/#view.ViewUpdate.viewportChanged) is true
and the viewport change is not just the result of mapping it in
response to document changes.
*/
get viewportMoved() {
return (this.flags & 8) > 0;
}
/**
Indicates whether the height of a block element in the editor
changed in this update.
*/
get heightChanged() {
return (this.flags & 2) > 0;
}
/**
Returns true when the document was modified or the size of the
editor, or elements within the editor, changed.
*/
get geometryChanged() {
return this.docChanged || (this.flags & (16 | 2)) > 0;
}
/**
True when this update indicates a focus change.
*/
get focusChanged() {
return (this.flags & 1) > 0;
}
/**
Whether the document changed in this update.
*/
get docChanged() {
return !this.changes.empty;
}
/**
Whether the selection was explicitly set in this update.
*/
get selectionSet() {
return this.transactions.some((tr) => tr.selection);
}
/**
@internal
*/
get empty() {
return this.flags == 0 && this.transactions.length == 0;
}
};
var noChildren = [];
var Tile = class {
constructor(dom, length, flags = 0) {
this.dom = dom;
this.length = length;
this.flags = flags;
this.parent = null;
dom.cmTile = this;
}
get breakAfter() {
return this.flags & 1;
}
get children() {
return noChildren;
}
isWidget() {
return false;
}
get isHidden() {
return false;
}
isComposite() {
return false;
}
isLine() {
return false;
}
isText() {
return false;
}
isBlock() {
return false;
}
get domAttrs() {
return null;
}
sync(track) {
this.flags |= 2;
if (this.flags & 4) {
this.flags &= ~4;
let attrs = this.domAttrs;
if (attrs)
setAttrs(this.dom, attrs);
}
}
toString() {
return this.constructor.name + (this.children.length ? `(${this.children})` : "") + (this.breakAfter ? "#" : "");
}
destroy() {
this.parent = null;
}
setDOM(dom) {
this.dom = dom;
dom.cmTile = this;
}
get posAtStart() {
return this.parent ? this.parent.posBefore(this) : 0;
}
get posAtEnd() {
return this.posAtStart + this.length;
}
posBefore(tile, start = this.posAtStart) {
let pos = start;
for (let child of this.children) {
if (child == tile)
return pos;
pos += child.length + child.breakAfter;
}
throw new RangeError("Invalid child in posBefore");
}
posAfter(tile) {
return this.posBefore(tile) + tile.length;
}
covers(side) {
return true;
}
coordsIn(pos, side) {
return null;
}
domPosFor(off, side) {
let index = domIndex(this.dom);
let after = this.length ? off > 0 : side > 0;
return new DOMPos(this.parent.dom, index + (after ? 1 : 0), off == 0 || off == this.length);
}
markDirty(attrs) {
this.flags &= ~2;
if (attrs)
this.flags |= 4;
if (this.parent && this.parent.flags & 2)
this.parent.markDirty(false);
}
get overrideDOMText() {
return null;
}
get root() {
for (let t = this; t; t = t.parent)
if (t instanceof DocTile)
return t;
return null;
}
static get(dom) {
return dom.cmTile;
}
};
var CompositeTile = class extends Tile {
constructor(dom) {
super(dom, 0);
this._children = [];
}
isComposite() {
return true;
}
get children() {
return this._children;
}
get lastChild() {
return this.children.length ? this.children[this.children.length - 1] : null;
}
append(child) {
this.children.push(child);
child.parent = this;
}
sync(track) {
if (this.flags & 2)
return;
super.sync(track);
let parent = this.dom, prev = null, next;
let tracking = (track === null || track === void 0 ? void 0 : track.node) == parent ? track : null;
let length = 0;
for (let child of this.children) {
child.sync(track);
length += child.length + child.breakAfter;
next = prev ? prev.nextSibling : parent.firstChild;
if (tracking && next != child.dom)
tracking.written = true;
if (child.dom.parentNode == parent) {
while (next && next != child.dom)
next = rm$1(next);
} else {
parent.insertBefore(child.dom, next);
}
prev = child.dom;
}
next = prev ? prev.nextSibling : parent.firstChild;
if (tracking && next)
tracking.written = true;
while (next)
next = rm$1(next);
this.length = length;
}
};
function rm$1(dom) {
let next = dom.nextSibling;
dom.parentNode.removeChild(dom);
return next;
}
var DocTile = class extends CompositeTile {
constructor(view, dom) {
super(dom);
this.view = view;
}
owns(tile) {
for (; tile; tile = tile.parent)
if (tile == this)
return true;
return false;
}
isBlock() {
return true;
}
nearest(dom) {
for (; ; ) {
if (!dom)
return null;
let tile = Tile.get(dom);
if (tile && this.owns(tile))
return tile;
dom = dom.parentNode;
}
}
blockTiles(f) {
for (let stack = [], cur = this, i = 0, pos = 0; ; ) {
if (i == cur.children.length) {
if (!stack.length)
return;
cur = cur.parent;
if (cur.breakAfter)
pos++;
i = stack.pop();
} else {
let next = cur.children[i++];
if (next instanceof BlockWrapperTile) {
stack.push(i);
cur = next;
i = 0;
} else {
let end = pos + next.length;
let result = f(next, pos);
if (result !== void 0)
return result;
pos = end + next.breakAfter;
}
}
}
}
// Find the block at the given position. If side < -1, make sure to
// stay before block widgets at that position, if side > 1, after
// such widgets (used for selection drawing, which needs to be able
// to get coordinates for positions that aren't valid cursor positions).
resolveBlock(pos, side) {
let before, beforeOff = -1, after, afterOff = -1;
this.blockTiles((tile, off) => {
let end = off + tile.length;
if (pos >= off && pos <= end) {
if (tile.isWidget() && side >= -1 && side <= 1) {
if (tile.flags & 32)
return true;
if (tile.flags & 16)
before = void 0;
}
if ((off < pos || pos == end && (side < -1 ? tile.length : tile.covers(1))) && (!before || !tile.isWidget() && before.isWidget())) {
before = tile;
beforeOff = pos - off;
}
if ((end > pos || pos == off && (side > 1 ? tile.length : tile.covers(-1))) && (!after || !tile.isWidget() && after.isWidget())) {
after = tile;
afterOff = pos - off;
}
}
});
if (!before && !after)
throw new Error("No tile at position " + pos);
return before && side < 0 || !after ? { tile: before, offset: beforeOff } : { tile: after, offset: afterOff };
}
};
var BlockWrapperTile = class _BlockWrapperTile extends CompositeTile {
constructor(dom, wrapper) {
super(dom);
this.wrapper = wrapper;
}
isBlock() {
return true;
}
covers(side) {
if (!this.children.length)
return false;
return side < 0 ? this.children[0].covers(-1) : this.lastChild.covers(1);
}
get domAttrs() {
return this.wrapper.attributes;
}
static of(wrapper, dom) {
let tile = new _BlockWrapperTile(dom || document.createElement(wrapper.tagName), wrapper);
if (!dom)
tile.flags |= 4;
return tile;
}
};
var LineTile = class _LineTile extends CompositeTile {
constructor(dom, attrs) {
super(dom);
this.attrs = attrs;
}
isLine() {
return true;
}
static start(attrs, dom, keepAttrs) {
let line = new _LineTile(dom || document.createElement("div"), attrs);
if (!dom || !keepAttrs)
line.flags |= 4;
return line;
}
get domAttrs() {
return this.attrs;
}
// Find the tile associated with a given position in this line.
resolveInline(pos, side, forCoords) {
let before = null, beforeOff = -1, after = null, afterOff = -1;
function scan(tile, pos2) {
for (let i = 0, off = 0; i < tile.children.length && off <= pos2; i++) {
let child = tile.children[i], end = off + child.length;
if (end >= pos2) {
if (child.isComposite()) {
scan(child, pos2 - off);
} else if ((!after || after.isHidden && (side > 0 || forCoords && onSameLine(after, child))) && (end > pos2 || child.flags & 32)) {
after = child;
afterOff = pos2 - off;
} else if (off < pos2 || child.flags & 16 && !child.isHidden) {
before = child;
beforeOff = pos2 - off;
}
}
off = end;
}
}
scan(this, pos);
let target = (side < 0 ? before : after) || before || after;
return target ? { tile: target, offset: target == before ? beforeOff : afterOff } : null;
}
coordsIn(pos, side) {
let found = this.resolveInline(pos, side, true);
if (!found)
return fallbackRect(this);
return found.tile.coordsIn(Math.max(0, found.offset), side);
}
domIn(pos, side) {
let found = this.resolveInline(pos, side);
if (found) {
let { tile, offset } = found;
if (this.dom.contains(tile.dom)) {
if (tile.isText())
return new DOMPos(tile.dom, Math.min(tile.dom.nodeValue.length, offset));
return tile.domPosFor(offset, tile.flags & 16 ? 1 : tile.flags & 32 ? -1 : side);
}
let parent = found.tile.parent, saw = false;
for (let ch of parent.children) {
if (saw)
return new DOMPos(ch.dom, 0);
if (ch == found.tile) {
saw = true;
}
}
}
return new DOMPos(this.dom, 0);
}
};
function fallbackRect(tile) {
let last = tile.dom.lastChild;
if (!last)
return tile.dom.getBoundingClientRect();
let rects = clientRectsFor(last);
return rects[rects.length - 1] || null;
}
function onSameLine(a, b) {
let posA = a.coordsIn(0, 1), posB = b.coordsIn(0, 1);
return posA && posB && posB.top < posA.bottom;
}
var MarkTile = class _MarkTile extends CompositeTile {
constructor(dom, mark) {
super(dom);
this.mark = mark;
}
get domAttrs() {
return this.mark.attrs;
}
static of(mark, dom) {
let tile = new _MarkTile(dom || document.createElement(mark.tagName), mark);
if (!dom)
tile.flags |= 4;
return tile;
}
};
var TextTile = class _TextTile extends Tile {
constructor(dom, text) {
super(dom, text.length);
this.text = text;
}
sync(track) {
if (this.flags & 2)
return;
super.sync(track);
if (this.dom.nodeValue != this.text) {
if (track && track.node == this.dom)
track.written = true;
this.dom.nodeValue = this.text;
}
}
isText() {
return true;
}
toString() {
return JSON.stringify(this.text);
}
coordsIn(pos, side) {
let length = this.dom.nodeValue.length;
if (pos > length)
pos = length;
let from = pos, to = pos, flatten = 0;
if (pos == 0 && side < 0 || pos == length && side >= 0) {
if (!(browser.chrome || browser.gecko)) {
if (pos) {
from--;
flatten = 1;
} else if (to < length) {
to++;
flatten = -1;
}
}
} else {
if (side < 0)
from--;
else if (to < length)
to++;
}
let rects = textRange(this.dom, from, to).getClientRects();
if (!rects.length)
return null;
let rect = rects[(flatten ? flatten < 0 : side >= 0) ? 0 : rects.length - 1];
if (browser.safari && !flatten && rect.width == 0)
rect = Array.prototype.find.call(rects, (r) => r.width) || rect;
return flatten ? flattenRect(rect, flatten < 0) : rect || null;
}
static of(text, dom) {
let tile = new _TextTile(dom || document.createTextNode(text), text);
if (!dom)
tile.flags |= 2;
return tile;
}
};
var WidgetTile = class _WidgetTile extends Tile {
constructor(dom, length, widget, flags) {
super(dom, length, flags);
this.widget = widget;
}
isWidget() {
return true;
}
get isHidden() {
return this.widget.isHidden;
}
covers(side) {
if (this.flags & 48)
return false;
return (this.flags & (side < 0 ? 64 : 128)) > 0;
}
coordsIn(pos, side) {
return this.coordsInWidget(pos, side, false);
}
coordsInWidget(pos, side, block) {
let custom = this.widget.coordsAt(this.dom, pos, side);
if (custom)
return custom;
if (block) {
return flattenRect(this.dom.getBoundingClientRect(), this.length ? pos == 0 : side <= 0);
} else {
let rects = this.dom.getClientRects(), rect = null;
if (!rects.length)
return null;
let fromBack = this.flags & 16 ? true : this.flags & 32 ? false : pos > 0;
for (let i = fromBack ? rects.length - 1 : 0; ; i += fromBack ? -1 : 1) {
rect = rects[i];
if (pos > 0 ? i == 0 : i == rects.length - 1 || rect.top < rect.bottom)
break;
}
return flattenRect(rect, !fromBack);
}
}
get overrideDOMText() {
if (!this.length)
return Text.empty;
let { root } = this;
if (!root)
return Text.empty;
let start = this.posAtStart;
return root.view.state.doc.slice(start, start + this.length);
}
destroy() {
super.destroy();
this.widget.destroy(this.dom);
}
static of(widget, view, length, flags, dom) {
if (!dom) {
dom = widget.toDOM(view);
if (!widget.editable)
dom.contentEditable = "false";
}
return new _WidgetTile(dom, length, widget, flags);
}
};
var WidgetBufferTile = class extends Tile {
constructor(flags) {
let img = document.createElement("img");
img.className = "cm-widgetBuffer";
img.setAttribute("aria-hidden", "true");
super(img, 0, flags);
}
get isHidden() {
return true;
}
get overrideDOMText() {
return Text.empty;
}
coordsIn(pos) {
return this.dom.getBoundingClientRect();
}
};
var TilePointer = class {
constructor(top2) {
this.index = 0;
this.beforeBreak = false;
this.parents = [];
this.tile = top2;
}
// Advance by the given distance. If side is -1, stop leaving or
// entering tiles, or skipping zero-length tiles, once the distance
// has been traversed. When side is 1, leave, enter, or skip
// everything at the end position.
advance(dist2, side, walker) {
let { tile, index, beforeBreak, parents } = this;
while (dist2 || side > 0) {
if (!tile.isComposite()) {
if (index == tile.length) {
beforeBreak = !!tile.breakAfter;
({ tile, index } = parents.pop());
index++;
} else if (!dist2) {
break;
} else {
let take = Math.min(dist2, tile.length - index);
if (walker)
walker.skip(tile, index, index + take);
dist2 -= take;
index += take;
}
} else if (beforeBreak) {
if (!dist2)
break;
if (walker)
walker.break();
dist2--;
beforeBreak = false;
} else if (index == tile.children.length) {
if (!dist2 && !parents.length)
break;
if (walker)
walker.leave(tile);
beforeBreak = !!tile.breakAfter;
({ tile, index } = parents.pop());
index++;
} else {
let next = tile.children[index], brk = next.breakAfter;
if ((side > 0 ? next.length <= dist2 : next.length < dist2) && (!walker || walker.skip(next, 0, next.length) !== false || !next.isComposite)) {
beforeBreak = !!brk;
index++;
dist2 -= next.length;
} else {
parents.push({ tile, index });
tile = next;
index = 0;
if (walker && next.isComposite())
walker.enter(next);
}
}
}
this.tile = tile;
this.index = index;
this.beforeBreak = beforeBreak;
return this;
}
get root() {
return this.parents.length ? this.parents[0].tile : this.tile;
}
};
var OpenWrapper = class {
constructor(from, to, wrapper, rank) {
this.from = from;
this.to = to;
this.wrapper = wrapper;
this.rank = rank;
}
};
var TileBuilder = class {
constructor(cache, root, blockWrappers2) {
this.cache = cache;
this.root = root;
this.blockWrappers = blockWrappers2;
this.curLine = null;
this.lastBlock = null;
this.afterWidget = null;
this.pos = 0;
this.wrappers = [];
this.wrapperPos = 0;
}
addText(text, marks, openStart, tile) {
var _a;
this.flushBuffer();
let parent = this.ensureMarks(marks, openStart);
let prev = parent.lastChild;
if (prev && prev.isText() && !(prev.flags & 8) && prev.length + text.length < 512) {
this.cache.reused.set(
prev,
2
/* Reused.DOM */
);
let tile2 = parent.children[parent.children.length - 1] = new TextTile(prev.dom, prev.text + text);
tile2.parent = parent;
} else {
parent.append(tile || TextTile.of(text, (_a = this.cache.find(TextTile)) === null || _a === void 0 ? void 0 : _a.dom));
}
this.pos += text.length;
this.afterWidget = null;
}
addComposition(composition, context) {
let line = this.curLine;
if (line.dom != context.line.dom) {
line.setDOM(this.cache.reused.has(context.line) ? freeNode(context.line.dom) : context.line.dom);
this.cache.reused.set(
context.line,
2
/* Reused.DOM */
);
}
let head = line;
for (let i = context.marks.length - 1; i >= 0; i--) {
let mark = context.marks[i];
let last = head.lastChild;
if (last instanceof MarkTile && last.mark.eq(mark.mark)) {
if (last.dom != mark.dom)
last.setDOM(freeNode(mark.dom));
head = last;
} else {
if (this.cache.reused.get(mark)) {
let tile = Tile.get(mark.dom);
if (tile)
tile.setDOM(freeNode(mark.dom));
}
let nw = MarkTile.of(mark.mark, mark.dom);
head.append(nw);
head = nw;
}
this.cache.reused.set(
mark,
2
/* Reused.DOM */
);
}
let oldTile = Tile.get(composition.text);
if (oldTile)
this.cache.reused.set(
oldTile,
2
/* Reused.DOM */
);
let text = new TextTile(composition.text, composition.text.nodeValue);
text.flags |= 8;
this.pos = composition.range.toB;
head.append(text);
}
addInlineWidget(widget, marks, openStart) {
let noSpace = this.afterWidget && widget.flags & 48 && (this.afterWidget.flags & 48) == (widget.flags & 48);
if (!noSpace)
this.flushBuffer();
let parent = this.ensureMarks(marks, openStart);
if (!noSpace && !(widget.flags & 16))
parent.append(this.getBuffer(1));
parent.append(widget);
this.pos += widget.length;
this.afterWidget = widget;
}
addMark(tile, marks, openStart) {
this.flushBuffer();
let parent = this.ensureMarks(marks, openStart);
parent.append(tile);
this.pos += tile.length;
this.afterWidget = null;
}
addBlockWidget(widget) {
this.getBlockPos().append(widget);
this.pos += widget.length;
this.lastBlock = widget;
this.endLine();
}
continueWidget(length) {
let widget = this.afterWidget || this.lastBlock;
widget.length += length;
this.pos += length;
}
addLineStart(attrs, dom) {
var _a;
if (!attrs)
attrs = lineBaseAttrs;
let tile = LineTile.start(attrs, dom || ((_a = this.cache.find(LineTile)) === null || _a === void 0 ? void 0 : _a.dom), !!dom);
this.getBlockPos().append(this.lastBlock = this.curLine = tile);
}
addLine(tile) {
this.getBlockPos().append(tile);
this.pos += tile.length;
this.lastBlock = tile;
this.endLine();
}
addBreak() {
this.lastBlock.flags |= 1;
this.endLine();
this.pos++;
}
addLineStartIfNotCovered(attrs) {
if (!this.blockPosCovered())
this.addLineStart(attrs);
}
ensureLine(attrs) {
if (!this.curLine)
this.addLineStart(attrs);
}
ensureMarks(marks, openStart) {
var _a;
let parent = this.curLine;
for (let i = marks.length - 1; i >= 0; i--) {
let mark = marks[i], last;
if (openStart > 0 && (last = parent.lastChild) && last instanceof MarkTile && last.mark.eq(mark)) {
parent = last;
openStart--;
} else {
let tile = MarkTile.of(mark, (_a = this.cache.find(MarkTile, (m) => m.mark.eq(mark))) === null || _a === void 0 ? void 0 : _a.dom);
parent.append(tile);
parent = tile;
openStart = 0;
}
}
return parent;
}
endLine() {
if (this.curLine) {
this.flushBuffer();
let last = this.curLine.lastChild;
if (!last || !hasContent(this.curLine, false) || last.dom.nodeName != "BR" && last.isWidget() && !(browser.ios && hasContent(this.curLine, true)))
this.curLine.append(this.cache.findWidget(
BreakWidget,
0,
32
/* TileFlag.After */
) || new WidgetTile(
BreakWidget.toDOM(),
0,
BreakWidget,
32
/* TileFlag.After */
));
this.curLine = this.afterWidget = null;
}
}
updateBlockWrappers() {
if (this.wrapperPos > this.pos + 1e4) {
this.blockWrappers.goto(this.pos);
this.wrappers.length = 0;
}
for (let i = this.wrappers.length - 1; i >= 0; i--)
if (this.wrappers[i].to < this.pos)
this.wrappers.splice(i, 1);
for (let cur = this.blockWrappers; cur.value && cur.from <= this.pos; cur.next())
if (cur.to >= this.pos) {
let rank = cur.rank * 102 + cur.value.rank;
let wrap = new OpenWrapper(cur.from, cur.to, cur.value, rank), i = this.wrappers.length;
while (i > 0 && (this.wrappers[i - 1].rank - wrap.rank || this.wrappers[i - 1].to - wrap.to) < 0)
i--;
this.wrappers.splice(i, 0, wrap);
}
this.wrapperPos = this.pos;
}
getBlockPos() {
var _a;
this.updateBlockWrappers();
let parent = this.root;
for (let wrap of this.wrappers) {
let last = parent.lastChild;
if (wrap.from < this.pos && last instanceof BlockWrapperTile && last.wrapper.eq(wrap.wrapper)) {
parent = last;
} else {
let tile = BlockWrapperTile.of(wrap.wrapper, (_a = this.cache.find(BlockWrapperTile, (t) => t.wrapper.eq(wrap.wrapper))) === null || _a === void 0 ? void 0 : _a.dom);
parent.append(tile);
parent = tile;
}
}
return parent;
}
blockPosCovered() {
let last = this.lastBlock;
return last != null && !last.breakAfter && (!last.isWidget() || (last.flags & (32 | 128)) > 0);
}
getBuffer(side) {
let flags = 2 | (side < 0 ? 16 : 32);
let found = this.cache.find(
WidgetBufferTile,
void 0,
1
/* Reused.Full */
);
if (found)
found.flags = flags;
return found || new WidgetBufferTile(flags);
}
flushBuffer() {
if (this.afterWidget && !(this.afterWidget.flags & 32)) {
this.afterWidget.parent.append(this.getBuffer(-1));
this.afterWidget = null;
}
}
};
var TextStream = class {
constructor(doc2) {
this.skipCount = 0;
this.text = "";
this.textOff = 0;
this.cursor = doc2.iter();
}
skip(len) {
if (this.textOff + len <= this.text.length) {
this.textOff += len;
} else {
this.skipCount += len - (this.text.length - this.textOff);
this.text = "";
this.textOff = 0;
}
}
next(maxLen) {
if (this.textOff == this.text.length) {
let { value, lineBreak, done } = this.cursor.next(this.skipCount);
this.skipCount = 0;
if (done)
throw new Error("Ran out of text content when drawing inline views");
this.text = value;
let len = this.textOff = Math.min(maxLen, value.length);
return lineBreak ? null : value.slice(0, len);
}
let end = Math.min(this.text.length, this.textOff + maxLen);
let chars = this.text.slice(this.textOff, end);
this.textOff = end;
return chars;
}
};
var buckets = [WidgetTile, LineTile, TextTile, MarkTile, WidgetBufferTile, BlockWrapperTile, DocTile];
for (let i = 0; i < buckets.length; i++)
buckets[i].bucket = i;
var TileCache = class {
constructor(view) {
this.view = view;
this.buckets = buckets.map(() => []);
this.index = buckets.map(() => 0);
this.reused = /* @__PURE__ */ new Map();
}
// Put a tile in the cache.
add(tile) {
let i = tile.constructor.bucket, bucket = this.buckets[i];
if (bucket.length < 6)
bucket.push(tile);
else
bucket[
this.index[i] = (this.index[i] + 1) % 6
/* C.Bucket */
] = tile;
}
find(cls, test, type = 2) {
let i = cls.bucket;
let bucket = this.buckets[i], off = this.index[i];
for (let j = bucket.length - 1; j >= 0; j--) {
let index = (j + off) % bucket.length, tile = bucket[index];
if ((!test || test(tile)) && !this.reused.has(tile)) {
bucket.splice(index, 1);
if (index < off)
this.index[i]--;
this.reused.set(tile, type);
return tile;
}
}
return null;
}
findWidget(widget, length, flags) {
let widgets = this.buckets[0];
if (widgets.length)
for (let i = 0, pass = 0; ; i++) {
if (i == widgets.length) {
if (pass)
return null;
pass = 1;
i = 0;
}
let tile = widgets[i];
if (!this.reused.has(tile) && (pass == 0 ? tile.widget.compare(widget) : tile.widget.constructor == widget.constructor && widget.updateDOM(tile.dom, this.view, tile.widget))) {
widgets.splice(i, 1);
if (i < this.index[0])
this.index[0]--;
if (tile.widget == widget && tile.length == length && (tile.flags & (496 | 1)) == flags) {
this.reused.set(
tile,
1
/* Reused.Full */
);
return tile;
} else {
this.reused.set(
tile,
2
/* Reused.DOM */
);
return new WidgetTile(tile.dom, length, widget, tile.flags & ~(496 | 1) | flags);
}
}
}
}
reuse(tile) {
this.reused.set(
tile,
1
/* Reused.Full */
);
return tile;
}
maybeReuse(tile, type = 2) {
if (this.reused.has(tile))
return void 0;
this.reused.set(tile, type);
return tile.dom;
}
clear() {
for (let i = 0; i < this.buckets.length; i++)
this.buckets[i].length = this.index[i] = 0;
}
};
var TileUpdate = class {
constructor(view, old, blockWrappers2, decorations2, disallowBlockEffectsFor) {
this.view = view;
this.decorations = decorations2;
this.disallowBlockEffectsFor = disallowBlockEffectsFor;
this.openWidget = false;
this.openMarks = 0;
this.cache = new TileCache(view);
this.text = new TextStream(view.state.doc);
this.builder = new TileBuilder(this.cache, new DocTile(view, view.contentDOM), RangeSet.iter(blockWrappers2));
this.cache.reused.set(
old,
2
/* Reused.DOM */
);
this.old = new TilePointer(old);
this.reuseWalker = {
skip: (tile, from, to) => {
this.cache.add(tile);
if (tile.isComposite())
return false;
},
enter: (tile) => this.cache.add(tile),
leave: () => {
},
break: () => {
}
};
}
run(changes, composition) {
let compositionContext = composition && this.getCompositionContext(composition.text);
for (let posA = 0, posB = 0, i = 0; ; ) {
let next = i < changes.length ? changes[i++] : null;
let skipA = next ? next.fromA : this.old.root.length;
if (skipA > posA) {
let len = skipA - posA;
this.preserve(len, !i, !next);
posA = skipA;
posB += len;
}
if (!next)
break;
if (composition && next.fromA <= composition.range.fromA && next.toA >= composition.range.toA) {
this.forward(next.fromA, composition.range.fromA, composition.range.fromA < composition.range.toA ? 1 : -1);
this.emit(posB, composition.range.fromB);
this.cache.clear();
this.builder.addComposition(composition, compositionContext);
this.text.skip(composition.range.toB - composition.range.fromB);
this.forward(composition.range.fromA, next.toA);
this.emit(composition.range.toB, next.toB);
} else {
this.forward(next.fromA, next.toA);
this.emit(posB, next.toB);
}
posB = next.toB;
posA = next.toA;
}
if (this.builder.curLine)
this.builder.endLine();
return this.builder.root;
}
preserve(length, incStart, incEnd) {
let activeMarks = getMarks(this.old), openMarks = this.openMarks;
this.old.advance(length, incEnd ? 1 : -1, {
skip: (tile, from, to) => {
if (tile.isWidget()) {
if (this.openWidget) {
this.builder.continueWidget(to - from);
} else {
let widget = to > 0 || from < tile.length ? WidgetTile.of(tile.widget, this.view, to - from, tile.flags & 496, this.cache.maybeReuse(tile)) : this.cache.reuse(tile);
if (widget.flags & 256) {
widget.flags &= ~1;
this.builder.addBlockWidget(widget);
} else {
this.builder.ensureLine(null);
this.builder.addInlineWidget(widget, activeMarks, openMarks);
openMarks = activeMarks.length;
}
}
} else if (tile.isText()) {
this.builder.ensureLine(null);
if (!from && to == tile.length && !this.cache.reused.has(tile)) {
this.builder.addText(tile.text, activeMarks, openMarks, this.cache.reuse(tile));
} else {
this.cache.add(tile);
this.builder.addText(tile.text.slice(from, to), activeMarks, openMarks);
}
openMarks = activeMarks.length;
} else if (tile.isLine()) {
tile.flags &= ~1;
this.cache.reused.set(
tile,
1
/* Reused.Full */
);
this.builder.addLine(tile);
} else if (tile instanceof WidgetBufferTile) {
this.cache.add(tile);
} else if (tile instanceof MarkTile) {
this.builder.ensureLine(null);
this.builder.addMark(tile, activeMarks, openMarks);
this.cache.reused.set(
tile,
1
/* Reused.Full */
);
openMarks = activeMarks.length;
} else {
return false;
}
this.openWidget = false;
},
enter: (tile) => {
if (tile.isLine()) {
this.builder.addLineStart(tile.attrs, this.cache.maybeReuse(tile));
} else {
this.cache.add(tile);
if (tile instanceof MarkTile)
activeMarks.unshift(tile.mark);
}
this.openWidget = false;
},
leave: (tile) => {
if (tile.isLine()) {
if (activeMarks.length)
activeMarks.length = openMarks = 0;
} else if (tile instanceof MarkTile) {
activeMarks.shift();
openMarks = Math.min(openMarks, activeMarks.length);
}
},
break: () => {
this.builder.addBreak();
this.openWidget = false;
}
});
this.text.skip(length);
}
emit(from, to) {
let pendingLineAttrs = null;
let b = this.builder, markCount = 0;
let openEnd = RangeSet.spans(this.decorations, from, to, {
point: (from2, to2, deco, active, openStart, index) => {
if (deco instanceof PointDecoration) {
if (this.disallowBlockEffectsFor[index]) {
if (deco.block)
throw new RangeError("Block decorations may not be specified via plugins");
if (to2 > this.view.state.doc.lineAt(from2).to)
throw new RangeError("Decorations that replace line breaks may not be specified via plugins");
}
markCount = active.length;
if (openStart > active.length) {
b.continueWidget(to2 - from2);
} else {
let widget = deco.widget || (deco.block ? NullWidget.block : NullWidget.inline);
let flags = widgetFlags(deco);
let tile = this.cache.findWidget(widget, to2 - from2, flags) || WidgetTile.of(widget, this.view, to2 - from2, flags);
if (deco.block) {
if (deco.startSide > 0)
b.addLineStartIfNotCovered(pendingLineAttrs);
b.addBlockWidget(tile);
} else {
b.ensureLine(pendingLineAttrs);
b.addInlineWidget(tile, active, openStart);
}
}
pendingLineAttrs = null;
} else {
pendingLineAttrs = addLineDeco(pendingLineAttrs, deco);
}
if (to2 > from2)
this.text.skip(to2 - from2);
},
span: (from2, to2, active, openStart) => {
for (let pos = from2; pos < to2; ) {
let chars = this.text.next(Math.min(512, to2 - pos));
if (chars == null) {
b.addLineStartIfNotCovered(pendingLineAttrs);
b.addBreak();
pos++;
} else {
b.ensureLine(pendingLineAttrs);
b.addText(chars, active, pos == from2 ? openStart : active.length);
pos += chars.length;
}
pendingLineAttrs = null;
}
}
});
b.addLineStartIfNotCovered(pendingLineAttrs);
this.openWidget = openEnd > markCount;
this.openMarks = openEnd;
}
forward(from, to, side = 1) {
if (to - from <= 10) {
this.old.advance(to - from, side, this.reuseWalker);
} else {
this.old.advance(5, -1, this.reuseWalker);
this.old.advance(to - from - 10, -1);
this.old.advance(5, side, this.reuseWalker);
}
}
getCompositionContext(text) {
let marks = [], line = null;
for (let parent = text.parentNode; ; parent = parent.parentNode) {
let tile = Tile.get(parent);
if (parent == this.view.contentDOM)
break;
if (tile instanceof MarkTile)
marks.push(tile);
else if (tile === null || tile === void 0 ? void 0 : tile.isLine())
line = tile;
else if (tile instanceof BlockWrapperTile) ;
else if (parent.nodeName == "DIV" && !line && parent != this.view.contentDOM)
line = new LineTile(parent, lineBaseAttrs);
else if (!line)
marks.push(MarkTile.of(new MarkDecoration({ tagName: parent.nodeName.toLowerCase(), attributes: getAttrs(parent) }), parent));
}
return { line, marks };
}
};
function hasContent(tile, requireText) {
let scan = (tile2) => {
for (let ch of tile2.children)
if ((requireText ? ch.isText() : ch.length) || scan(ch))
return true;
return false;
};
return scan(tile);
}
function widgetFlags(deco) {
let flags = deco.isReplace ? (deco.startSide < 0 ? 64 : 0) | (deco.endSide > 0 ? 128 : 0) : deco.startSide > 0 ? 32 : 16;
if (deco.block)
flags |= 256;
return flags;
}
var lineBaseAttrs = { class: "cm-line" };
function addLineDeco(value, deco) {
let attrs = deco.spec.attributes, cls = deco.spec.class;
if (!attrs && !cls)
return value;
if (!value)
value = { class: "cm-line" };
if (attrs)
combineAttrs(attrs, value);
if (cls)
value.class += " " + cls;
return value;
}
function getMarks(ptr) {
let found = [];
for (let i = ptr.parents.length; i > 1; i--) {
let tile = i == ptr.parents.length ? ptr.tile : ptr.parents[i].tile;
if (tile instanceof MarkTile)
found.push(tile.mark);
}
return found;
}
function freeNode(node) {
let tile = Tile.get(node);
if (tile)
tile.setDOM(node.cloneNode());
return node;
}
var NullWidget = class extends WidgetType {
constructor(tag) {
super();
this.tag = tag;
}
eq(other) {
return other.tag == this.tag;
}
toDOM() {
return document.createElement(this.tag);
}
updateDOM(elt) {
return elt.nodeName.toLowerCase() == this.tag;
}
get isHidden() {
return true;
}
};
NullWidget.inline = new NullWidget("span");
NullWidget.block = new NullWidget("div");
var BreakWidget = new class extends WidgetType {
toDOM() {
return document.createElement("br");
}
get isHidden() {
return true;
}
get editable() {
return true;
}
}();
var DocView = class {
constructor(view) {
this.view = view;
this.decorations = [];
this.blockWrappers = [];
this.dynamicDecorationMap = [false];
this.domChanged = null;
this.hasComposition = null;
this.editContextFormatting = Decoration.none;
this.lastCompositionAfterCursor = false;
this.minWidth = 0;
this.minWidthFrom = 0;
this.minWidthTo = 0;
this.impreciseAnchor = null;
this.impreciseHead = null;
this.forceSelection = false;
this.lastUpdate = Date.now();
this.updateDeco();
this.tile = new DocTile(view, view.contentDOM);
this.updateInner([new ChangedRange(0, 0, 0, view.state.doc.length)], null);
}
// Update the document view to a given state.
update(update) {
var _a;
let changedRanges = update.changedRanges;
if (this.minWidth > 0 && changedRanges.length) {
if (!changedRanges.every(({ fromA, toA }) => toA < this.minWidthFrom || fromA > this.minWidthTo)) {
this.minWidth = this.minWidthFrom = this.minWidthTo = 0;
} else {
this.minWidthFrom = update.changes.mapPos(this.minWidthFrom, 1);
this.minWidthTo = update.changes.mapPos(this.minWidthTo, 1);
}
}
this.updateEditContextFormatting(update);
let readCompositionAt = -1;
if (this.view.inputState.composing >= 0 && !this.view.observer.editContext) {
if ((_a = this.domChanged) === null || _a === void 0 ? void 0 : _a.newSel)
readCompositionAt = this.domChanged.newSel.head;
else if (!touchesComposition(update.changes, this.hasComposition) && !update.selectionSet)
readCompositionAt = update.state.selection.main.head;
}
let composition = readCompositionAt > -1 ? findCompositionRange(this.view, update.changes, readCompositionAt) : null;
this.domChanged = null;
if (this.hasComposition) {
let { from, to } = this.hasComposition;
changedRanges = new ChangedRange(from, to, update.changes.mapPos(from, -1), update.changes.mapPos(to, 1)).addToSet(changedRanges.slice());
}
this.hasComposition = composition ? { from: composition.range.fromB, to: composition.range.toB } : null;
if ((browser.ie || browser.chrome) && !composition && update && update.state.doc.lines != update.startState.doc.lines)
this.forceSelection = true;
let prevDeco = this.decorations, prevWrappers = this.blockWrappers;
this.updateDeco();
let decoDiff = findChangedDeco(prevDeco, this.decorations, update.changes);
if (decoDiff.length)
changedRanges = ChangedRange.extendWithRanges(changedRanges, decoDiff);
let blockDiff = findChangedWrappers(prevWrappers, this.blockWrappers, update.changes);
if (blockDiff.length)
changedRanges = ChangedRange.extendWithRanges(changedRanges, blockDiff);
if (composition && !changedRanges.some((r) => r.fromA <= composition.range.fromA && r.toA >= composition.range.toA))
changedRanges = composition.range.addToSet(changedRanges.slice());
if (this.tile.flags & 2 && changedRanges.length == 0) {
return false;
} else {
this.updateInner(changedRanges, composition);
if (update.transactions.length)
this.lastUpdate = Date.now();
return true;
}
}
// Used by update and the constructor do perform the actual DOM
// update
updateInner(changes, composition) {
this.view.viewState.mustMeasureContent = true;
let { observer } = this.view;
observer.ignore(() => {
if (composition || changes.length) {
let oldTile = this.tile;
let builder = new TileUpdate(this.view, oldTile, this.blockWrappers, this.decorations, this.dynamicDecorationMap);
if (composition && Tile.get(composition.text))
builder.cache.reused.set(
Tile.get(composition.text),
2
/* Reused.DOM */
);
this.tile = builder.run(changes, composition);
destroyDropped(oldTile, builder.cache.reused);
}
this.tile.dom.style.height = this.view.viewState.contentHeight / this.view.scaleY + "px";
this.tile.dom.style.flexBasis = this.minWidth ? this.minWidth + "px" : "";
let track = browser.chrome || browser.ios ? { node: observer.selectionRange.focusNode, written: false } : void 0;
this.tile.sync(track);
if (track && (track.written || observer.selectionRange.focusNode != track.node || !this.tile.dom.contains(track.node)))
this.forceSelection = true;
this.tile.dom.style.height = "";
});
let gaps = [];
if (this.view.viewport.from || this.view.viewport.to < this.view.state.doc.length) {
for (let child of this.tile.children)
if (child.isWidget() && child.widget instanceof BlockGapWidget)
gaps.push(child.dom);
}
observer.updateGaps(gaps);
}
updateEditContextFormatting(update) {
this.editContextFormatting = this.editContextFormatting.map(update.changes);
for (let tr of update.transactions)
for (let effect of tr.effects)
if (effect.is(setEditContextFormatting)) {
this.editContextFormatting = effect.value;
}
}
// Sync the DOM selection to this.state.selection
updateSelection(mustRead = false, fromPointer = false) {
if (mustRead || !this.view.observer.selectionRange.focusNode)
this.view.observer.readSelectionRange();
let { dom } = this.tile;
let activeElt = this.view.root.activeElement, focused = activeElt == dom;
let selectionNotFocus = !focused && !(this.view.state.facet(editable) || dom.tabIndex > -1) && hasSelection(dom, this.view.observer.selectionRange) && !(activeElt && dom.contains(activeElt));
if (!(focused || fromPointer || selectionNotFocus))
return;
let force = this.forceSelection;
this.forceSelection = false;
let main = this.view.state.selection.main, anchor, head;
if (main.empty) {
head = anchor = this.inlineDOMNearPos(main.anchor, main.assoc || 1);
} else {
head = this.inlineDOMNearPos(main.head, main.head == main.from ? 1 : -1);
anchor = this.inlineDOMNearPos(main.anchor, main.anchor == main.from ? 1 : -1);
}
if (browser.gecko && main.empty && !this.hasComposition && betweenUneditable(anchor)) {
let dummy = document.createTextNode("");
this.view.observer.ignore(() => anchor.node.insertBefore(dummy, anchor.node.childNodes[anchor.offset] || null));
anchor = head = new DOMPos(dummy, 0);
force = true;
}
let domSel = this.view.observer.selectionRange;
if (force || !domSel.focusNode || (!isEquivalentPosition(anchor.node, anchor.offset, domSel.anchorNode, domSel.anchorOffset) || !isEquivalentPosition(head.node, head.offset, domSel.focusNode, domSel.focusOffset)) && !this.suppressWidgetCursorChange(domSel, main)) {
this.view.observer.ignore(() => {
if (browser.android && browser.chrome && dom.contains(domSel.focusNode) && inUneditable(domSel.focusNode, dom)) {
dom.blur();
dom.focus({ preventScroll: true });
}
let rawSel = getSelection(this.view.root);
if (!rawSel) ;
else if (main.empty) {
if (browser.gecko) {
let nextTo = nextToUneditable(anchor.node, anchor.offset);
if (nextTo && nextTo != (1 | 2)) {
let text = (nextTo == 1 ? textNodeBefore : textNodeAfter)(anchor.node, anchor.offset);
if (text)
anchor = new DOMPos(text.node, text.offset);
}
}
rawSel.collapse(anchor.node, anchor.offset);
if (main.bidiLevel != null && rawSel.caretBidiLevel !== void 0)
rawSel.caretBidiLevel = main.bidiLevel;
} else if (rawSel.extend) {
rawSel.collapse(anchor.node, anchor.offset);
try {
rawSel.extend(head.node, head.offset);
} catch (_) {
}
} else {
let range = document.createRange();
if (main.anchor > main.head)
[anchor, head] = [head, anchor];
range.setEnd(head.node, head.offset);
range.setStart(anchor.node, anchor.offset);
rawSel.removeAllRanges();
rawSel.addRange(range);
}
if (selectionNotFocus && this.view.root.activeElement == dom) {
dom.blur();
if (activeElt)
activeElt.focus();
}
});
this.view.observer.setSelectionRange(anchor, head);
}
this.impreciseAnchor = anchor.precise ? null : new DOMPos(domSel.anchorNode, domSel.anchorOffset);
this.impreciseHead = head.precise ? null : new DOMPos(domSel.focusNode, domSel.focusOffset);
}
// If a zero-length widget is inserted next to the cursor during
// composition, avoid moving it across it and disrupting the
// composition.
suppressWidgetCursorChange(sel, cursor) {
return this.hasComposition && cursor.empty && isEquivalentPosition(sel.focusNode, sel.focusOffset, sel.anchorNode, sel.anchorOffset) && this.posFromDOM(sel.focusNode, sel.focusOffset) == cursor.head;
}
enforceCursorAssoc() {
if (this.hasComposition)
return;
let { view } = this, cursor = view.state.selection.main;
let sel = getSelection(view.root);
let { anchorNode, anchorOffset } = view.observer.selectionRange;
if (!sel || !cursor.empty || !cursor.assoc || !sel.modify)
return;
let line = this.lineAt(cursor.head, cursor.assoc);
if (!line)
return;
let lineStart = line.posAtStart;
if (cursor.head == lineStart || cursor.head == lineStart + line.length)
return;
let before = this.coordsAt(cursor.head, -1), after = this.coordsAt(cursor.head, 1);
if (!before || !after || before.bottom > after.top)
return;
let dom = this.domAtPos(cursor.head + cursor.assoc, cursor.assoc);
sel.collapse(dom.node, dom.offset);
sel.modify("move", cursor.assoc < 0 ? "forward" : "backward", "lineboundary");
view.observer.readSelectionRange();
let newRange = view.observer.selectionRange;
if (view.docView.posFromDOM(newRange.anchorNode, newRange.anchorOffset) != cursor.from)
sel.collapse(anchorNode, anchorOffset);
}
posFromDOM(node, offset) {
let tile = this.tile.nearest(node);
if (!tile)
return this.tile.dom.compareDocumentPosition(node) & 2 ? 0 : this.view.state.doc.length;
let start = tile.posAtStart;
if (tile.isComposite()) {
let after;
if (node == tile.dom) {
after = tile.dom.childNodes[offset];
} else {
let bias = maxOffset(node) == 0 ? 0 : offset == 0 ? -1 : 1;
for (; ; ) {
let parent = node.parentNode;
if (parent == tile.dom)
break;
if (bias == 0 && parent.firstChild != parent.lastChild) {
if (node == parent.firstChild)
bias = -1;
else
bias = 1;
}
node = parent;
}
if (bias < 0)
after = node;
else
after = node.nextSibling;
}
if (after == tile.dom.firstChild)
return start;
while (after && !Tile.get(after))
after = after.nextSibling;
if (!after)
return start + tile.length;
for (let i = 0, pos = start; ; i++) {
let child = tile.children[i];
if (child.dom == after)
return pos;
pos += child.length + child.breakAfter;
}
} else if (tile.isText()) {
return node == tile.dom ? start + offset : start + (offset ? tile.length : 0);
} else {
return start;
}
}
domAtPos(pos, side) {
let { tile, offset } = this.tile.resolveBlock(pos, side);
if (tile.isWidget())
return tile.domPosFor(pos, side);
return tile.domIn(offset, side);
}
inlineDOMNearPos(pos, side) {
let before, beforeOff = -1, beforeBad = false;
let after, afterOff = -1, afterBad = false;
this.tile.blockTiles((tile, off) => {
if (tile.isWidget()) {
if (tile.flags & 32 && off >= pos)
return true;
if (tile.flags & 16)
beforeBad = true;
} else {
let end = off + tile.length;
if (off <= pos) {
before = tile;
beforeOff = pos - off;
beforeBad = end < pos;
}
if (end >= pos && !after) {
after = tile;
afterOff = pos - off;
afterBad = off > pos;
}
if (off > pos && after)
return true;
}
});
if (!before && !after)
return this.domAtPos(pos, side);
if (beforeBad && after)
before = null;
else if (afterBad && before)
after = null;
return before && side < 0 || !after ? before.domIn(beforeOff, side) : after.domIn(afterOff, side);
}
coordsAt(pos, side) {
let { tile, offset } = this.tile.resolveBlock(pos, side);
if (tile.isWidget()) {
if (tile.widget instanceof BlockGapWidget)
return null;
return tile.coordsInWidget(offset, side, true);
}
return tile.coordsIn(offset, side);
}
lineAt(pos, side) {
let { tile } = this.tile.resolveBlock(pos, side);
return tile.isLine() ? tile : null;
}
coordsForChar(pos) {
let { tile, offset } = this.tile.resolveBlock(pos, 1);
if (!tile.isLine())
return null;
function scan(tile2, offset2) {
if (tile2.isComposite()) {
for (let ch of tile2.children) {
if (ch.length >= offset2) {
let found = scan(ch, offset2);
if (found)
return found;
}
offset2 -= ch.length;
if (offset2 < 0)
break;
}
} else if (tile2.isText() && offset2 < tile2.length) {
let end = findClusterBreak(tile2.text, offset2);
if (end == offset2)
return null;
let rects = textRange(tile2.dom, offset2, end).getClientRects();
for (let i = 0; i < rects.length; i++) {
let rect = rects[i];
if (i == rects.length - 1 || rect.top < rect.bottom && rect.left < rect.right)
return rect;
}
}
return null;
}
return scan(tile, offset);
}
measureVisibleLineHeights(viewport) {
let result = [], { from, to } = viewport;
let contentWidth = this.view.contentDOM.clientWidth;
let isWider = contentWidth > Math.max(this.view.scrollDOM.clientWidth, this.minWidth) + 1;
let widest = -1, ltr = this.view.textDirection == Direction.LTR;
let spaceAbove = 0;
let scan = (tile, pos, measureBounds) => {
for (let i = 0; i < tile.children.length; i++) {
if (pos > to)
break;
let child = tile.children[i], end = pos + child.length;
let childRect = child.dom.getBoundingClientRect(), { height } = childRect;
if (measureBounds && !i)
spaceAbove += childRect.top - measureBounds.top;
if (child instanceof BlockWrapperTile) {
if (end > from)
scan(child, pos, childRect);
} else if (pos >= from) {
if (spaceAbove > 0)
result.push(-spaceAbove);
result.push(height + spaceAbove);
spaceAbove = 0;
if (isWider) {
let last = child.dom.lastChild;
let rects = last ? clientRectsFor(last) : [];
if (rects.length) {
let rect = rects[rects.length - 1];
let width = ltr ? rect.right - childRect.left : childRect.right - rect.left;
if (width > widest) {
widest = width;
this.minWidth = contentWidth;
this.minWidthFrom = pos;
this.minWidthTo = end;
}
}
}
}
if (measureBounds && i == tile.children.length - 1)
spaceAbove += measureBounds.bottom - childRect.bottom;
pos = end + child.breakAfter;
}
};
scan(this.tile, 0, null);
return result;
}
textDirectionAt(pos) {
let { tile } = this.tile.resolveBlock(pos, 1);
return getComputedStyle(tile.dom).direction == "rtl" ? Direction.RTL : Direction.LTR;
}
measureTextSize() {
let lineMeasure = this.tile.blockTiles((tile) => {
if (tile.isLine() && tile.children.length && tile.length <= 20) {
let totalWidth = 0, textHeight2;
for (let child of tile.children) {
if (!child.isText() || /[^ -~]/.test(child.text))
return void 0;
let rects = clientRectsFor(child.dom);
if (rects.length != 1)
return void 0;
totalWidth += rects[0].width;
textHeight2 = rects[0].height;
}
if (totalWidth)
return {
lineHeight: tile.dom.getBoundingClientRect().height,
charWidth: totalWidth / tile.length,
textHeight: textHeight2
};
}
});
if (lineMeasure)
return lineMeasure;
let dummy = document.createElement("div"), lineHeight, charWidth, textHeight;
dummy.className = "cm-line";
dummy.style.width = "99999px";
dummy.style.position = "absolute";
dummy.textContent = "abc def ghi jkl mno pqr stu";
this.view.observer.ignore(() => {
this.tile.dom.appendChild(dummy);
let rect = clientRectsFor(dummy.firstChild)[0];
lineHeight = dummy.getBoundingClientRect().height;
charWidth = rect && rect.width ? rect.width / 27 : 7;
textHeight = rect && rect.height ? rect.height : lineHeight;
dummy.remove();
});
return { lineHeight, charWidth, textHeight };
}
computeBlockGapDeco() {
let deco = [], vs = this.view.viewState;
for (let pos = 0, i = 0; ; i++) {
let next = i == vs.viewports.length ? null : vs.viewports[i];
let end = next ? next.from - 1 : this.view.state.doc.length;
if (end > pos) {
let height = (vs.lineBlockAt(end).bottom - vs.lineBlockAt(pos).top) / this.view.scaleY;
deco.push(Decoration.replace({
widget: new BlockGapWidget(height),
block: true,
inclusive: true,
isBlockGap: true
}).range(pos, end));
}
if (!next)
break;
pos = next.to + 1;
}
return Decoration.set(deco);
}
updateDeco() {
let i = 1;
let allDeco = this.view.state.facet(decorations).map((d) => {
let dynamic = this.dynamicDecorationMap[i++] = typeof d == "function";
return dynamic ? d(this.view) : d;
});
let dynamicOuter = false, outerDeco = this.view.state.facet(outerDecorations).map((d, i2) => {
let dynamic = typeof d == "function";
if (dynamic)
dynamicOuter = true;
return dynamic ? d(this.view) : d;
});
if (outerDeco.length) {
this.dynamicDecorationMap[i++] = dynamicOuter;
allDeco.push(RangeSet.join(outerDeco));
}
this.decorations = [
this.editContextFormatting,
...allDeco,
this.computeBlockGapDeco(),
this.view.viewState.lineGapDeco
];
while (i < this.decorations.length)
this.dynamicDecorationMap[i++] = false;
this.blockWrappers = this.view.state.facet(blockWrappers).map((v) => typeof v == "function" ? v(this.view) : v);
}
scrollIntoView(target) {
var _a;
if (target.isSnapshot) {
let ref = this.view.viewState.lineBlockAt(target.range.head);
this.view.scrollDOM.scrollTop = ref.top - target.yMargin;
this.view.scrollDOM.scrollLeft = target.xMargin;
return;
}
for (let handler of this.view.state.facet(scrollHandler)) {
try {
if (handler(this.view, target.range, target))
return true;
} catch (e) {
logException(this.view.state, e, "scroll handler");
}
}
let { range } = target;
let rect = this.coordsAt(range.head, (_a = range.assoc) !== null && _a !== void 0 ? _a : range.empty ? 0 : range.head > range.anchor ? -1 : 1), other;
if (!rect)
return;
if (!range.empty && (other = this.coordsAt(range.anchor, range.anchor > range.head ? -1 : 1)))
rect = {
left: Math.min(rect.left, other.left),
top: Math.min(rect.top, other.top),
right: Math.max(rect.right, other.right),
bottom: Math.max(rect.bottom, other.bottom)
};
let margins = getScrollMargins(this.view);
let targetRect = {
left: rect.left - margins.left,
top: rect.top - margins.top,
right: rect.right + margins.right,
bottom: rect.bottom + margins.bottom
};
let { offsetWidth, offsetHeight } = this.view.scrollDOM;
scrollRectIntoView(this.view.scrollDOM, targetRect, range.head < range.anchor ? -1 : 1, target.x, target.y, Math.max(Math.min(target.xMargin, offsetWidth), -offsetWidth), Math.max(Math.min(target.yMargin, offsetHeight), -offsetHeight), this.view.textDirection == Direction.LTR);
if (window.visualViewport && window.innerHeight - window.visualViewport.height > 1 && (rect.top > window.pageYOffset + window.visualViewport.offsetTop + window.visualViewport.height || rect.bottom < window.pageYOffset + window.visualViewport.offsetTop)) {
let line = this.view.docView.lineAt(range.head, 1);
if (line)
line.dom.scrollIntoView({ block: "nearest" });
}
}
lineHasWidget(pos) {
let scan = (child) => child.isWidget() || child.children.some(scan);
return scan(this.tile.resolveBlock(pos, 1).tile);
}
destroy() {
destroyDropped(this.tile);
}
};
function destroyDropped(tile, reused) {
let r = reused === null || reused === void 0 ? void 0 : reused.get(tile);
if (r != 1) {
if (r == null)
tile.destroy();
for (let ch of tile.children)
destroyDropped(ch, reused);
}
}
function betweenUneditable(pos) {
return pos.node.nodeType == 1 && pos.node.firstChild && (pos.offset == 0 || pos.node.childNodes[pos.offset - 1].contentEditable == "false") && (pos.offset == pos.node.childNodes.length || pos.node.childNodes[pos.offset].contentEditable == "false");
}
function findCompositionNode(view, headPos) {
let sel = view.observer.selectionRange;
if (!sel.focusNode)
return null;
let textBefore = textNodeBefore(sel.focusNode, sel.focusOffset);
let textAfter = textNodeAfter(sel.focusNode, sel.focusOffset);
let textNode = textBefore || textAfter;
if (textAfter && textBefore && textAfter.node != textBefore.node) {
let tileAfter = Tile.get(textAfter.node);
if (!tileAfter || tileAfter.isText() && tileAfter.text != textAfter.node.nodeValue) {
textNode = textAfter;
} else if (view.docView.lastCompositionAfterCursor) {
let tileBefore = Tile.get(textBefore.node);
if (!(!tileBefore || tileBefore.isText() && tileBefore.text != textBefore.node.nodeValue))
textNode = textAfter;
}
}
view.docView.lastCompositionAfterCursor = textNode != textBefore;
if (!textNode)
return null;
let from = headPos - textNode.offset;
return { from, to: from + textNode.node.nodeValue.length, node: textNode.node };
}
function findCompositionRange(view, changes, headPos) {
let found = findCompositionNode(view, headPos);
if (!found)
return null;
let { node: textNode, from, to } = found, text = textNode.nodeValue;
if (/[\n\r]/.test(text))
return null;
if (view.state.doc.sliceString(found.from, found.to) != text)
return null;
let inv = changes.invertedDesc;
return { range: new ChangedRange(inv.mapPos(from), inv.mapPos(to), from, to), text: textNode };
}
function nextToUneditable(node, offset) {
if (node.nodeType != 1)
return 0;
return (offset && node.childNodes[offset - 1].contentEditable == "false" ? 1 : 0) | (offset < node.childNodes.length && node.childNodes[offset].contentEditable == "false" ? 2 : 0);
}
var DecorationComparator$1 = class DecorationComparator {
constructor() {
this.changes = [];
}
compareRange(from, to) {
addRange(from, to, this.changes);
}
comparePoint(from, to) {
addRange(from, to, this.changes);
}
boundChange(pos) {
addRange(pos, pos, this.changes);
}
};
function findChangedDeco(a, b, diff) {
let comp = new DecorationComparator$1();
RangeSet.compare(a, b, diff, comp);
return comp.changes;
}
var WrapperComparator = class {
constructor() {
this.changes = [];
}
compareRange(from, to) {
addRange(from, to, this.changes);
}
comparePoint() {
}
boundChange(pos) {
addRange(pos, pos, this.changes);
}
};
function findChangedWrappers(a, b, diff) {
let comp = new WrapperComparator();
RangeSet.compare(a, b, diff, comp);
return comp.changes;
}
function inUneditable(node, inside) {
for (let cur = node; cur && cur != inside; cur = cur.assignedSlot || cur.parentNode) {
if (cur.nodeType == 1 && cur.contentEditable == "false") {
return true;
}
}
return false;
}
function touchesComposition(changes, composition) {
let touched = false;
if (composition)
changes.iterChangedRanges((from, to) => {
if (from < composition.to && to > composition.from)
touched = true;
});
return touched;
}
var BlockGapWidget = class extends WidgetType {
constructor(height) {
super();
this.height = height;
}
toDOM() {
let elt = document.createElement("div");
elt.className = "cm-gap";
this.updateDOM(elt);
return elt;
}
eq(other) {
return other.height == this.height;
}
updateDOM(elt) {
elt.style.height = this.height + "px";
return true;
}
get editable() {
return true;
}
get estimatedHeight() {
return this.height;
}
ignoreEvent() {
return false;
}
};
function groupAt(state, pos, bias = 1) {
let categorize = state.charCategorizer(pos);
let line = state.doc.lineAt(pos), linePos = pos - line.from;
if (line.length == 0)
return EditorSelection.cursor(pos);
if (linePos == 0)
bias = 1;
else if (linePos == line.length)
bias = -1;
let from = linePos, to = linePos;
if (bias < 0)
from = findClusterBreak(line.text, linePos, false);
else
to = findClusterBreak(line.text, linePos);
let cat = categorize(line.text.slice(from, to));
while (from > 0) {
let prev = findClusterBreak(line.text, from, false);
if (categorize(line.text.slice(prev, from)) != cat)
break;
from = prev;
}
while (to < line.length) {
let next = findClusterBreak(line.text, to);
if (categorize(line.text.slice(to, next)) != cat)
break;
to = next;
}
return EditorSelection.range(from + line.from, to + line.from);
}
function posAtCoordsImprecise(view, contentRect, block, x, y) {
let into = Math.round((x - contentRect.left) * view.defaultCharacterWidth);
if (view.lineWrapping && block.height > view.defaultLineHeight * 1.5) {
let textHeight = view.viewState.heightOracle.textHeight;
let line = Math.floor((y - block.top - (view.defaultLineHeight - textHeight) * 0.5) / textHeight);
into += line * view.viewState.heightOracle.lineLength;
}
let content = view.state.sliceDoc(block.from, block.to);
return block.from + findColumn(content, into, view.state.tabSize);
}
function blockAt(view, pos, side) {
let line = view.lineBlockAt(pos);
if (Array.isArray(line.type)) {
let best;
for (let l of line.type) {
if (l.from > pos)
break;
if (l.to < pos)
continue;
if (l.from < pos && l.to > pos)
return l;
if (!best || l.type == BlockType.Text && (best.type != l.type || (side < 0 ? l.from < pos : l.to > pos)))
best = l;
}
return best || line;
}
return line;
}
function moveToLineBoundary(view, start, forward, includeWrap) {
let line = blockAt(view, start.head, start.assoc || -1);
let coords = !includeWrap || line.type != BlockType.Text || !(view.lineWrapping || line.widgetLineBreaks) ? null : view.coordsAtPos(start.assoc < 0 && start.head > line.from ? start.head - 1 : start.head);
if (coords) {
let editorRect = view.dom.getBoundingClientRect();
let direction = view.textDirectionAt(line.from);
let pos = view.posAtCoords({
x: forward == (direction == Direction.LTR) ? editorRect.right - 1 : editorRect.left + 1,
y: (coords.top + coords.bottom) / 2
});
if (pos != null)
return EditorSelection.cursor(pos, forward ? -1 : 1);
}
return EditorSelection.cursor(forward ? line.to : line.from, forward ? -1 : 1);
}
function moveByChar(view, start, forward, by) {
let line = view.state.doc.lineAt(start.head), spans = view.bidiSpans(line);
let direction = view.textDirectionAt(line.from);
for (let cur = start, check = null; ; ) {
let next = moveVisually(line, spans, direction, cur, forward), char = movedOver;
if (!next) {
if (line.number == (forward ? view.state.doc.lines : 1))
return cur;
char = "\n";
line = view.state.doc.line(line.number + (forward ? 1 : -1));
spans = view.bidiSpans(line);
next = view.visualLineSide(line, !forward);
}
if (!check) {
if (!by)
return next;
check = by(char);
} else if (!check(char)) {
return cur;
}
cur = next;
}
}
function byGroup(view, pos, start) {
let categorize = view.state.charCategorizer(pos);
let cat = categorize(start);
return (next) => {
let nextCat = categorize(next);
if (cat == CharCategory.Space)
cat = nextCat;
return cat == nextCat;
};
}
function moveVertically(view, start, forward, distance) {
let startPos = start.head, dir = forward ? 1 : -1;
if (startPos == (forward ? view.state.doc.length : 0))
return EditorSelection.cursor(startPos, start.assoc);
let goal = start.goalColumn, startY;
let rect = view.contentDOM.getBoundingClientRect();
let startCoords = view.coordsAtPos(startPos, start.assoc || ((start.empty ? forward : start.head == start.from) ? 1 : -1));
let docTop = view.documentTop;
if (startCoords) {
if (goal == null)
goal = startCoords.left - rect.left;
startY = dir < 0 ? startCoords.top : startCoords.bottom;
} else {
let line = view.viewState.lineBlockAt(startPos);
if (goal == null)
goal = Math.min(rect.right - rect.left, view.defaultCharacterWidth * (startPos - line.from));
startY = (dir < 0 ? line.top : line.bottom) + docTop;
}
let resolvedGoal = rect.left + goal;
let halfText = view.viewState.heightOracle.textHeight >> 1, dist2 = distance !== null && distance !== void 0 ? distance : halfText;
for (let scan = 0; ; scan += halfText) {
let y = startY + (dist2 + scan) * dir;
let pos = posAtCoords(view, { x: resolvedGoal, y }, false, dir);
if (forward ? y > rect.bottom : y < rect.top)
return EditorSelection.cursor(pos.pos, pos.assoc);
let posCoords = view.coordsAtPos(pos.pos, pos.assoc), mid = posCoords ? (posCoords.top + posCoords.bottom) / 2 : 0;
if (!posCoords || (forward ? mid > startY : mid < startY))
return EditorSelection.cursor(pos.pos, pos.assoc, void 0, goal);
}
}
function skipAtomicRanges(atoms, pos, bias) {
for (; ; ) {
let moved = 0;
for (let set of atoms) {
set.between(pos - 1, pos + 1, (from, to, value) => {
if (pos > from && pos < to) {
let side = moved || bias || (pos - from < to - pos ? -1 : 1);
pos = side < 0 ? from : to;
moved = side;
}
});
}
if (!moved)
return pos;
}
}
function skipAtomsForSelection(atoms, sel) {
let ranges = null;
for (let i = 0; i < sel.ranges.length; i++) {
let range = sel.ranges[i], updated = null;
if (range.empty) {
let pos = skipAtomicRanges(atoms, range.from, 0);
if (pos != range.from)
updated = EditorSelection.cursor(pos, -1);
} else {
let from = skipAtomicRanges(atoms, range.from, -1);
let to = skipAtomicRanges(atoms, range.to, 1);
if (from != range.from || to != range.to)
updated = EditorSelection.range(range.from == range.anchor ? from : to, range.from == range.head ? from : to);
}
if (updated) {
if (!ranges)
ranges = sel.ranges.slice();
ranges[i] = updated;
}
}
return ranges ? EditorSelection.create(ranges, sel.mainIndex) : sel;
}
function skipAtoms(view, oldPos, pos) {
let newPos = skipAtomicRanges(view.state.facet(atomicRanges).map((f) => f(view)), pos.from, oldPos.head > pos.from ? -1 : 1);
return newPos == pos.from ? pos : EditorSelection.cursor(newPos, newPos < pos.from ? 1 : -1);
}
var PosAssoc = class {
constructor(pos, assoc) {
this.pos = pos;
this.assoc = assoc;
}
};
function posAtCoords(view, coords, precise, scanY) {
let content = view.contentDOM.getBoundingClientRect(), docTop = content.top + view.viewState.paddingTop;
let { x, y } = coords, yOffset = y - docTop, block;
for (; ; ) {
if (yOffset < 0)
return new PosAssoc(0, 1);
if (yOffset > view.viewState.docHeight)
return new PosAssoc(view.state.doc.length, -1);
block = view.elementAtHeight(yOffset);
if (scanY == null)
break;
if (block.type == BlockType.Text) {
if (scanY < 0 ? block.to < view.viewport.from : block.from > view.viewport.to)
break;
let rect = view.docView.coordsAt(scanY < 0 ? block.from : block.to, scanY > 0 ? -1 : 1);
if (rect && (scanY < 0 ? rect.top <= yOffset + docTop : rect.bottom >= yOffset + docTop))
break;
}
let halfLine = view.viewState.heightOracle.textHeight / 2;
yOffset = scanY > 0 ? block.bottom + halfLine : block.top - halfLine;
}
if (view.viewport.from >= block.to || view.viewport.to <= block.from) {
if (precise)
return null;
if (block.type == BlockType.Text) {
let pos = posAtCoordsImprecise(view, content, block, x, y);
return new PosAssoc(pos, pos == block.from ? 1 : -1);
}
}
if (block.type != BlockType.Text)
return yOffset < (block.top + block.bottom) / 2 ? new PosAssoc(block.from, 1) : new PosAssoc(block.to, -1);
let line = view.docView.lineAt(block.from, 2);
if (!line || line.length != block.length)
line = view.docView.lineAt(block.from, -2);
return new InlineCoordsScan(view, x, y, view.textDirectionAt(block.from)).scanTile(line, block.from);
}
var InlineCoordsScan = class {
constructor(view, x, y, baseDir) {
this.view = view;
this.x = x;
this.y = y;
this.baseDir = baseDir;
this.line = null;
this.spans = null;
}
bidiSpansAt(pos) {
if (!this.line || this.line.from > pos || this.line.to < pos) {
this.line = this.view.state.doc.lineAt(pos);
this.spans = this.view.bidiSpans(this.line);
}
return this;
}
baseDirAt(pos, side) {
let { line, spans } = this.bidiSpansAt(pos);
let level = spans[BidiSpan.find(spans, pos - line.from, -1, side)].level;
return level == this.baseDir;
}
dirAt(pos, side) {
let { line, spans } = this.bidiSpansAt(pos);
return spans[BidiSpan.find(spans, pos - line.from, -1, side)].dir;
}
// Used to short-circuit bidi tests for content with a uniform direction
bidiIn(from, to) {
let { spans, line } = this.bidiSpansAt(from);
return spans.length > 1 || spans.length && (spans[0].level != this.baseDir || spans[0].to + line.from < to);
}
// Scan through the rectangles for the content of a tile with inline
// content, looking for one that overlaps the queried position
// vertically andis
// closest horizontally. The caller is responsible for dividing its
// content into N pieces, and pass an array with N+1 positions
// (including the position after the last piece). For a text tile,
// these will be character clusters, for a composite tile, these
// will be child tiles.
scan(positions, getRects, recursed = false) {
let lo = 0, hi = positions.length - 1, seen = /* @__PURE__ */ new Set();
let bidi = this.bidiIn(positions[0], positions[hi]);
let above, below;
let closestI = -1, closestDx = 1e9, closestRect;
search: while (lo < hi) {
let dist2 = hi - lo, mid = lo + hi >> 1;
adjust: if (seen.has(mid)) {
let scan = lo + Math.floor(Math.random() * dist2);
for (let i = 0; i < dist2; i++) {
if (!seen.has(scan)) {
mid = scan;
break adjust;
}
scan++;
if (scan == hi)
scan = lo;
}
break search;
}
seen.add(mid);
let rects = getRects(mid);
if (rects)
for (let i = 0; i < rects.length; i++) {
let rect = rects[i], side = 0;
if (rect.width == 0 && rects.length > 1)
continue;
if (rect.bottom < this.y) {
if (!above || above.bottom < rect.bottom)
above = rect;
side = 1;
} else if (rect.top > this.y) {
if (!below || below.top > rect.top)
below = rect;
side = -1;
} else {
let off = rect.left > this.x ? this.x - rect.left : rect.right < this.x ? this.x - rect.right : 0;
let dx = Math.abs(off);
if (dx < closestDx) {
closestI = mid;
closestDx = dx;
closestRect = rect;
}
if (off)
side = off < 0 == (this.baseDir == Direction.LTR) ? -1 : 1;
}
if (side == -1 && (!bidi || this.baseDirAt(positions[mid], 1)))
hi = mid;
else if (side == 1 && (!bidi || this.baseDirAt(positions[mid + 1], -1)))
lo = mid + 1;
}
}
if (!closestRect) {
let side = above && (!below || this.y - above.bottom < below.top - this.y) ? above : below;
this.y = (side.top + side.bottom) / 2;
return this.scan(positions, getRects, true);
}
if (closestDx && !recursed) {
let { top: top2, bottom } = closestRect;
if (above && above.bottom > (top2 + top2 + bottom) / 3) {
this.y = above.bottom - 1;
return this.scan(positions, getRects, true);
}
if (below && below.top < (top2 + bottom + bottom) / 3) {
this.y = below.top + 1;
return this.scan(positions, getRects, true);
}
}
let ltr = (bidi ? this.dirAt(positions[closestI], 1) : this.baseDir) == Direction.LTR;
return {
i: closestI,
// Test whether x is closes to the start or end of this element
after: this.x > (closestRect.left + closestRect.right) / 2 == ltr
};
}
scanText(tile, offset) {
let positions = [];
for (let i = 0; i < tile.length; i = findClusterBreak(tile.text, i))
positions.push(offset + i);
positions.push(offset + tile.length);
let scan = this.scan(positions, (i) => {
let off = positions[i] - offset, end = positions[i + 1] - offset;
return textRange(tile.dom, off, end).getClientRects();
});
return scan.after ? new PosAssoc(positions[scan.i + 1], -1) : new PosAssoc(positions[scan.i], 1);
}
scanTile(tile, offset) {
if (!tile.length)
return new PosAssoc(offset, 1);
if (tile.children.length == 1) {
let child2 = tile.children[0];
if (child2.isText())
return this.scanText(child2, offset);
else if (child2.isComposite())
return this.scanTile(child2, offset);
}
let positions = [offset];
for (let i = 0, pos2 = offset; i < tile.children.length; i++)
positions.push(pos2 += tile.children[i].length);
let scan = this.scan(positions, (i) => {
let child2 = tile.children[i];
if (child2.flags & 48)
return null;
return (child2.dom.nodeType == 1 ? child2.dom : textRange(child2.dom, 0, child2.length)).getClientRects();
});
let child = tile.children[scan.i], pos = positions[scan.i];
if (child.isText())
return this.scanText(child, pos);
if (child.isComposite())
return this.scanTile(child, pos);
return scan.after ? new PosAssoc(positions[scan.i + 1], -1) : new PosAssoc(pos, 1);
}
};
var LineBreakPlaceholder = "￿";
var DOMReader = class {
constructor(points, view) {
this.points = points;
this.view = view;
this.text = "";
this.lineSeparator = view.state.facet(EditorState.lineSeparator);
}
append(text) {
this.text += text;
}
lineBreak() {
this.text += LineBreakPlaceholder;
}
readRange(start, end) {
if (!start)
return this;
let parent = start.parentNode;
for (let cur = start; ; ) {
this.findPointBefore(parent, cur);
let oldLen = this.text.length;
this.readNode(cur);
let tile = Tile.get(cur), next = cur.nextSibling;
if (next == end) {
if ((tile === null || tile === void 0 ? void 0 : tile.breakAfter) && !next && parent != this.view.contentDOM)
this.lineBreak();
break;
}
let nextTile = Tile.get(next);
if ((tile && nextTile ? tile.breakAfter : (tile ? tile.breakAfter : isBlockElement(cur)) || isBlockElement(next) && (cur.nodeName != "BR" || (tile === null || tile === void 0 ? void 0 : tile.isWidget())) && this.text.length > oldLen) && !isEmptyToEnd(next, end))
this.lineBreak();
cur = next;
}
this.findPointBefore(parent, end);
return this;
}
readTextNode(node) {
let text = node.nodeValue;
for (let point of this.points)
if (point.node == node)
point.pos = this.text.length + Math.min(point.offset, text.length);
for (let off = 0, re = this.lineSeparator ? null : /\r\n?|\n/g; ; ) {
let nextBreak = -1, breakSize = 1, m;
if (this.lineSeparator) {
nextBreak = text.indexOf(this.lineSeparator, off);
breakSize = this.lineSeparator.length;
} else if (m = re.exec(text)) {
nextBreak = m.index;
breakSize = m[0].length;
}
this.append(text.slice(off, nextBreak < 0 ? text.length : nextBreak));
if (nextBreak < 0)
break;
this.lineBreak();
if (breakSize > 1) {
for (let point of this.points)
if (point.node == node && point.pos > this.text.length)
point.pos -= breakSize - 1;
}
off = nextBreak + breakSize;
}
}
readNode(node) {
let tile = Tile.get(node);
let fromView = tile && tile.overrideDOMText;
if (fromView != null) {
this.findPointInside(node, fromView.length);
for (let i = fromView.iter(); !i.next().done; ) {
if (i.lineBreak)
this.lineBreak();
else
this.append(i.value);
}
} else if (node.nodeType == 3) {
this.readTextNode(node);
} else if (node.nodeName == "BR") {
if (node.nextSibling)
this.lineBreak();
} else if (node.nodeType == 1) {
this.readRange(node.firstChild, null);
}
}
findPointBefore(node, next) {
for (let point of this.points)
if (point.node == node && node.childNodes[point.offset] == next)
point.pos = this.text.length;
}
findPointInside(node, length) {
for (let point of this.points)
if (node.nodeType == 3 ? point.node == node : node.contains(point.node))
point.pos = this.text.length + (isAtEnd(node, point.node, point.offset) ? length : 0);
}
};
function isAtEnd(parent, node, offset) {
for (; ; ) {
if (!node || offset < maxOffset(node))
return false;
if (node == parent)
return true;
offset = domIndex(node) + 1;
node = node.parentNode;
}
}
function isEmptyToEnd(node, end) {
let widgets;
for (; ; node = node.nextSibling) {
if (node == end || !node)
break;
let view = Tile.get(node);
if (!(view === null || view === void 0 ? void 0 : view.isWidget()))
return false;
if (view)
(widgets || (widgets = [])).push(view);
}
if (widgets)
for (let w of widgets) {
let override = w.overrideDOMText;
if (override === null || override === void 0 ? void 0 : override.length)
return false;
}
return true;
}
var DOMPoint = class {
constructor(node, offset) {
this.node = node;
this.offset = offset;
this.pos = -1;
}
};
var DOMChange = class {
constructor(view, start, end, typeOver) {
this.typeOver = typeOver;
this.bounds = null;
this.text = "";
this.domChanged = start > -1;
let { impreciseHead: iHead, impreciseAnchor: iAnchor } = view.docView, curSel = view.state.selection;
if (view.state.readOnly && start > -1) {
this.newSel = null;
} else if (start > -1 && (this.bounds = domBoundsAround(view.docView.tile, start, end, 0))) {
let selPoints = iHead || iAnchor ? [] : selectionPoints(view);
let reader = new DOMReader(selPoints, view);
reader.readRange(this.bounds.startDOM, this.bounds.endDOM);
this.text = reader.text;
this.newSel = selectionFromPoints(selPoints, this.bounds.from);
} else {
let domSel = view.observer.selectionRange;
let head = iHead && iHead.node == domSel.focusNode && iHead.offset == domSel.focusOffset || !contains(view.contentDOM, domSel.focusNode) ? curSel.main.head : view.docView.posFromDOM(domSel.focusNode, domSel.focusOffset);
let anchor = iAnchor && iAnchor.node == domSel.anchorNode && iAnchor.offset == domSel.anchorOffset || !contains(view.contentDOM, domSel.anchorNode) ? curSel.main.anchor : view.docView.posFromDOM(domSel.anchorNode, domSel.anchorOffset);
let vp = view.viewport;
if ((browser.ios || browser.chrome) && curSel.main.empty && head != anchor && (vp.from > 0 || vp.to < view.state.doc.length)) {
let from = Math.min(head, anchor), to = Math.max(head, anchor);
let offFrom = vp.from - from, offTo = vp.to - to;
if ((offFrom == 0 || offFrom == 1 || from == 0) && (offTo == 0 || offTo == -1 || to == view.state.doc.length)) {
head = 0;
anchor = view.state.doc.length;
}
}
if (view.inputState.composing > -1 && curSel.ranges.length > 1) {
this.newSel = curSel.replaceRange(EditorSelection.range(anchor, head));
} else if (view.lineWrapping && anchor == head && !(curSel.main.empty && curSel.main.head == head) && view.inputState.lastTouchTime > Date.now() - 100) {
let before = view.coordsAtPos(head, -1), assoc = 0;
if (before)
assoc = view.inputState.lastTouchY <= before.bottom ? -1 : 1;
this.newSel = EditorSelection.create([EditorSelection.cursor(head, assoc)]);
} else {
this.newSel = EditorSelection.single(anchor, head);
}
}
}
};
function domBoundsAround(tile, from, to, offset) {
if (tile.isComposite()) {
let fromI = -1, fromStart = -1, toI = -1, toEnd = -1;
for (let i = 0, pos = offset, prevEnd = offset; i < tile.children.length; i++) {
let child = tile.children[i], end = pos + child.length;
if (pos < from && end > to)
return domBoundsAround(child, from, to, pos);
if (end >= from && fromI == -1) {
fromI = i;
fromStart = pos;
}
if (pos > to && child.dom.parentNode == tile.dom) {
toI = i;
toEnd = prevEnd;
break;
}
prevEnd = end;
pos = end + child.breakAfter;
}
return {
from: fromStart,
to: toEnd < 0 ? offset + tile.length : toEnd,
startDOM: (fromI ? tile.children[fromI - 1].dom.nextSibling : null) || tile.dom.firstChild,
endDOM: toI < tile.children.length && toI >= 0 ? tile.children[toI].dom : null
};
} else if (tile.isText()) {
return { from: offset, to: offset + tile.length, startDOM: tile.dom, endDOM: tile.dom.nextSibling };
} else {
return null;
}
}
function applyDOMChange(view, domChange) {
let change;
let { newSel } = domChange, { state } = view, sel = state.selection.main;
let lastKey = view.inputState.lastKeyTime > Date.now() - 100 ? view.inputState.lastKeyCode : -1;
if (domChange.bounds) {
let { from, to } = domChange.bounds;
let preferredPos = sel.from, preferredSide = null;
if (lastKey === 8 || browser.android && domChange.text.length < to - from) {
preferredPos = sel.to;
preferredSide = "end";
}
let cmp = state.doc.sliceString(from, to, LineBreakPlaceholder), selEnd, diff;
if (!sel.empty && sel.from >= from && sel.to <= to && (domChange.typeOver || cmp != domChange.text) && cmp.slice(0, sel.from - from) == domChange.text.slice(0, sel.from - from) && cmp.slice(sel.to - from) == domChange.text.slice(selEnd = domChange.text.length - (cmp.length - (sel.to - from)))) {
change = {
from: sel.from,
to: sel.to,
insert: Text.of(domChange.text.slice(sel.from - from, selEnd).split(LineBreakPlaceholder))
};
} else if (diff = findDiff(cmp, domChange.text, preferredPos - from, preferredSide)) {
if (browser.chrome && lastKey == 13 && diff.toB == diff.from + 2 && domChange.text.slice(diff.from, diff.toB) == LineBreakPlaceholder + LineBreakPlaceholder)
diff.toB--;
change = {
from: from + diff.from,
to: from + diff.toA,
insert: Text.of(domChange.text.slice(diff.from, diff.toB).split(LineBreakPlaceholder))
};
}
} else if (newSel && (!view.hasFocus && state.facet(editable) || sameSelPos(newSel, sel))) {
newSel = null;
}
if (!change && !newSel)
return false;
if ((browser.mac || browser.android) && change && change.from == change.to && change.from == sel.head - 1 && /^\. ?$/.test(change.insert.toString()) && view.contentDOM.getAttribute("autocorrect") == "off") {
if (newSel && change.insert.length == 2)
newSel = EditorSelection.single(newSel.main.anchor - 1, newSel.main.head - 1);
change = { from: change.from, to: change.to, insert: Text.of([change.insert.toString().replace(".", " ")]) };
} else if (state.doc.lineAt(sel.from).to < sel.to && view.docView.lineHasWidget(sel.to) && view.inputState.insertingTextAt > Date.now() - 50) {
change = {
from: sel.from,
to: sel.to,
insert: state.toText(view.inputState.insertingText)
};
} else if (browser.chrome && change && change.from == change.to && change.from == sel.head && change.insert.toString() == "\n " && view.lineWrapping) {
if (newSel)
newSel = EditorSelection.single(newSel.main.anchor - 1, newSel.main.head - 1);
change = { from: sel.from, to: sel.to, insert: Text.of([" "]) };
}
if (change) {
return applyDOMChangeInner(view, change, newSel, lastKey);
} else if (newSel && !sameSelPos(newSel, sel)) {
let scrollIntoView2 = false, userEvent = "select";
if (view.inputState.lastSelectionTime > Date.now() - 50) {
if (view.inputState.lastSelectionOrigin == "select")
scrollIntoView2 = true;
userEvent = view.inputState.lastSelectionOrigin;
if (userEvent == "select.pointer")
newSel = skipAtomsForSelection(state.facet(atomicRanges).map((f) => f(view)), newSel);
}
view.dispatch({ selection: newSel, scrollIntoView: scrollIntoView2, userEvent });
return true;
} else {
return false;
}
}
function applyDOMChangeInner(view, change, newSel, lastKey = -1) {
if (browser.ios && view.inputState.flushIOSKey(change))
return true;
let sel = view.state.selection.main;
if (browser.android && (change.to == sel.to && // GBoard will sometimes remove a space it just inserted
// after a completion when you press enter
(change.from == sel.from || change.from == sel.from - 1 && view.state.sliceDoc(change.from, sel.from) == " ") && change.insert.length == 1 && change.insert.lines == 2 && dispatchKey(view.contentDOM, "Enter", 13) || (change.from == sel.from - 1 && change.to == sel.to && change.insert.length == 0 || lastKey == 8 && change.insert.length < change.to - change.from && change.to > sel.head) && dispatchKey(view.contentDOM, "Backspace", 8) || change.from == sel.from && change.to == sel.to + 1 && change.insert.length == 0 && dispatchKey(view.contentDOM, "Delete", 46)))
return true;
let text = change.insert.toString();
if (view.inputState.composing >= 0)
view.inputState.composing++;
let defaultTr;
let defaultInsert = () => defaultTr || (defaultTr = applyDefaultInsert(view, change, newSel));
if (!view.state.facet(inputHandler).some((h) => h(view, change.from, change.to, text, defaultInsert)))
view.dispatch(defaultInsert());
return true;
}
function applyDefaultInsert(view, change, newSel) {
let tr, startState = view.state, sel = startState.selection.main, inAtomic = -1;
if (change.from == change.to && change.from < sel.from || change.from > sel.to) {
let side = change.from < sel.from ? -1 : 1, pos = side < 0 ? sel.from : sel.to;
let moved = skipAtomicRanges(startState.facet(atomicRanges).map((f) => f(view)), pos, side);
if (change.from == moved)
inAtomic = moved;
}
if (inAtomic > -1) {
tr = {
changes: change,
selection: EditorSelection.cursor(change.from + change.insert.length, -1)
};
} else if (change.from >= sel.from && change.to <= sel.to && change.to - change.from >= (sel.to - sel.from) / 3 && (!newSel || newSel.main.empty && newSel.main.from == change.from + change.insert.length) && view.inputState.composing < 0) {
let before = sel.from < change.from ? startState.sliceDoc(sel.from, change.from) : "";
let after = sel.to > change.to ? startState.sliceDoc(change.to, sel.to) : "";
tr = startState.replaceSelection(view.state.toText(before + change.insert.sliceString(0, void 0, view.state.lineBreak) + after));
} else {
let changes = startState.changes(change);
let mainSel = newSel && newSel.main.to <= changes.newLength ? newSel.main : void 0;
if (startState.selection.ranges.length > 1 && (view.inputState.composing >= 0 || view.inputState.compositionPendingChange) && change.to <= sel.to + 10 && change.to >= sel.to - 10) {
let replaced = view.state.sliceDoc(change.from, change.to);
let compositionRange, composition = newSel && findCompositionNode(view, newSel.main.head);
if (composition) {
let dLen = change.insert.length - (change.to - change.from);
compositionRange = { from: composition.from, to: composition.to - dLen };
} else {
compositionRange = view.state.doc.lineAt(sel.head);
}
let offset = sel.to - change.to;
tr = startState.changeByRange((range) => {
if (range.from == sel.from && range.to == sel.to)
return { changes, range: mainSel || range.map(changes) };
let to = range.to - offset, from = to - replaced.length;
if (view.state.sliceDoc(from, to) != replaced || // Unfortunately, there's no way to make multiple
// changes in the same node work without aborting
// composition, so cursors in the composition range are
// ignored.
to >= compositionRange.from && from <= compositionRange.to)
return { range };
let rangeChanges = startState.changes({ from, to, insert: change.insert }), selOff = range.to - sel.to;
return {
changes: rangeChanges,
range: !mainSel ? range.map(rangeChanges) : EditorSelection.range(Math.max(0, mainSel.anchor + selOff), Math.max(0, mainSel.head + selOff))
};
});
} else {
tr = {
changes,
selection: mainSel && startState.selection.replaceRange(mainSel)
};
}
}
let userEvent = "input.type";
if (view.composing || view.inputState.compositionPendingChange && view.inputState.compositionEndedAt > Date.now() - 50) {
view.inputState.compositionPendingChange = false;
userEvent += ".compose";
if (view.inputState.compositionFirstChange) {
userEvent += ".start";
view.inputState.compositionFirstChange = false;
}
}
return startState.update(tr, { userEvent, scrollIntoView: true });
}
function findDiff(a, b, preferredPos, preferredSide) {
let minLen = Math.min(a.length, b.length);
let from = 0;
while (from < minLen && a.charCodeAt(from) == b.charCodeAt(from))
from++;
if (from == minLen && a.length == b.length)
return null;
let toA = a.length, toB = b.length;
while (toA > 0 && toB > 0 && a.charCodeAt(toA - 1) == b.charCodeAt(toB - 1)) {
toA--;
toB--;
}
if (preferredSide == "end") {
let adjust = Math.max(0, from - Math.min(toA, toB));
preferredPos -= toA + adjust - from;
}
if (toA < from && a.length < b.length) {
let move = preferredPos <= from && preferredPos >= toA ? from - preferredPos : 0;
from -= move;
toB = from + (toB - toA);
toA = from;
} else if (toB < from) {
let move = preferredPos <= from && preferredPos >= toB ? from - preferredPos : 0;
from -= move;
toA = from + (toA - toB);
toB = from;
}
return { from, toA, toB };
}
function selectionPoints(view) {
let result = [];
if (view.root.activeElement != view.contentDOM)
return result;
let { anchorNode, anchorOffset, focusNode, focusOffset } = view.observer.selectionRange;
if (anchorNode) {
result.push(new DOMPoint(anchorNode, anchorOffset));
if (focusNode != anchorNode || focusOffset != anchorOffset)
result.push(new DOMPoint(focusNode, focusOffset));
}
return result;
}
function selectionFromPoints(points, base2) {
if (points.length == 0)
return null;
let anchor = points[0].pos, head = points.length == 2 ? points[1].pos : anchor;
return anchor > -1 && head > -1 ? EditorSelection.single(anchor + base2, head + base2) : null;
}
function sameSelPos(selection, range) {
return range.head == selection.main.head && range.anchor == selection.main.anchor;
}
var InputState = class {
setSelectionOrigin(origin) {
this.lastSelectionOrigin = origin;
this.lastSelectionTime = Date.now();
}
constructor(view) {
this.view = view;
this.lastKeyCode = 0;
this.lastKeyTime = 0;
this.lastTouchTime = 0;
this.lastTouchX = 0;
this.lastTouchY = 0;
this.lastFocusTime = 0;
this.lastScrollTop = 0;
this.lastScrollLeft = 0;
this.lastWheelEvent = 0;
this.pendingIOSKey = void 0;
this.tabFocusMode = -1;
this.lastSelectionOrigin = null;
this.lastSelectionTime = 0;
this.lastContextMenu = 0;
this.scrollHandlers = [];
this.handlers = /* @__PURE__ */ Object.create(null);
this.composing = -1;
this.compositionFirstChange = null;
this.compositionEndedAt = 0;
this.compositionPendingKey = false;
this.compositionPendingChange = false;
this.insertingText = "";
this.insertingTextAt = 0;
this.mouseSelection = null;
this.draggedContent = null;
this.handleEvent = this.handleEvent.bind(this);
this.notifiedFocused = view.hasFocus;
if (browser.safari)
view.contentDOM.addEventListener("input", () => null);
if (browser.gecko)
firefoxCopyCutHack(view.contentDOM.ownerDocument);
}
handleEvent(event) {
if (!eventBelongsToEditor(this.view, event) || this.ignoreDuringComposition(event))
return;
if (event.type == "keydown" && this.keydown(event))
return;
if (this.view.updateState != 0)
Promise.resolve().then(() => this.runHandlers(event.type, event));
else
this.runHandlers(event.type, event);
}
runHandlers(type, event) {
let handlers2 = this.handlers[type];
if (handlers2) {
for (let observer of handlers2.observers)
observer(this.view, event);
for (let handler of handlers2.handlers) {
if (event.defaultPrevented)
break;
if (handler(this.view, event)) {
event.preventDefault();
break;
}
}
}
}
ensureHandlers(plugins) {
let handlers2 = computeHandlers(plugins), prev = this.handlers, dom = this.view.contentDOM;
for (let type in handlers2)
if (type != "scroll") {
let passive = !handlers2[type].handlers.length;
let exists = prev[type];
if (exists && passive != !exists.handlers.length) {
dom.removeEventListener(type, this.handleEvent);
exists = null;
}
if (!exists)
dom.addEventListener(type, this.handleEvent, { passive });
}
for (let type in prev)
if (type != "scroll" && !handlers2[type])
dom.removeEventListener(type, this.handleEvent);
this.handlers = handlers2;
}
keydown(event) {
this.lastKeyCode = event.keyCode;
this.lastKeyTime = Date.now();
if (event.keyCode == 9 && this.tabFocusMode > -1 && (!this.tabFocusMode || Date.now() <= this.tabFocusMode))
return true;
if (this.tabFocusMode > 0 && event.keyCode != 27 && modifierCodes.indexOf(event.keyCode) < 0)
this.tabFocusMode = -1;
if (browser.android && browser.chrome && !event.synthetic && (event.keyCode == 13 || event.keyCode == 8)) {
this.view.observer.delayAndroidKey(event.key, event.keyCode);
return true;
}
let pending;
if (browser.ios && !event.synthetic && !event.altKey && !event.metaKey && !event.shiftKey && ((pending = PendingKeys.find((key) => key.keyCode == event.keyCode)) && !event.ctrlKey || EmacsyPendingKeys.indexOf(event.key) > -1 && event.ctrlKey)) {
this.pendingIOSKey = pending || event;
setTimeout(() => this.flushIOSKey(), 250);
return true;
}
if (event.keyCode != 229)
this.view.observer.forceFlush();
return false;
}
flushIOSKey(change) {
let key = this.pendingIOSKey;
if (!key)
return false;
if (key.key == "Enter" && change && change.from < change.to && /^\S+$/.test(change.insert.toString()))
return false;
this.pendingIOSKey = void 0;
return dispatchKey(this.view.contentDOM, key.key, key.keyCode, key instanceof KeyboardEvent ? key : void 0);
}
ignoreDuringComposition(event) {
if (!/^key/.test(event.type) || event.synthetic)
return false;
if (this.composing > 0)
return true;
if (browser.safari && !browser.ios && this.compositionPendingKey && Date.now() - this.compositionEndedAt < 100) {
this.compositionPendingKey = false;
return true;
}
return false;
}
startMouseSelection(mouseSelection) {
if (this.mouseSelection)
this.mouseSelection.destroy();
this.mouseSelection = mouseSelection;
}
update(update) {
this.view.observer.update(update);
if (this.mouseSelection)
this.mouseSelection.update(update);
if (this.draggedContent && update.docChanged)
this.draggedContent = this.draggedContent.map(update.changes);
if (update.transactions.length)
this.lastKeyCode = this.lastSelectionTime = 0;
}
destroy() {
if (this.mouseSelection)
this.mouseSelection.destroy();
}
};
function bindHandler(plugin2, handler) {
return (view, event) => {
try {
return handler.call(plugin2, event, view);
} catch (e) {
logException(view.state, e);
}
};
}
function computeHandlers(plugins) {
let result = /* @__PURE__ */ Object.create(null);
function record(type) {
return result[type] || (result[type] = { observers: [], handlers: [] });
}
for (let plugin2 of plugins) {
let spec = plugin2.spec, handlers2 = spec && spec.plugin.domEventHandlers, observers2 = spec && spec.plugin.domEventObservers;
if (handlers2)
for (let type in handlers2) {
let f = handlers2[type];
if (f)
record(type).handlers.push(bindHandler(plugin2.value, f));
}
if (observers2)
for (let type in observers2) {
let f = observers2[type];
if (f)
record(type).observers.push(bindHandler(plugin2.value, f));
}
}
for (let type in handlers)
record(type).handlers.push(handlers[type]);
for (let type in observers)
record(type).observers.push(observers[type]);
return result;
}
var PendingKeys = [
{ key: "Backspace", keyCode: 8, inputType: "deleteContentBackward" },
{ key: "Enter", keyCode: 13, inputType: "insertParagraph" },
{ key: "Enter", keyCode: 13, inputType: "insertLineBreak" },
{ key: "Delete", keyCode: 46, inputType: "deleteContentForward" }
];
var EmacsyPendingKeys = "dthko";
var modifierCodes = [16, 17, 18, 20, 91, 92, 224, 225];
var dragScrollMargin = 6;
function dragScrollSpeed(dist2) {
return Math.max(0, dist2) * 0.7 + 8;
}
function dist(a, b) {
return Math.max(Math.abs(a.clientX - b.clientX), Math.abs(a.clientY - b.clientY));
}
var MouseSelection = class {
constructor(view, startEvent, style, mustSelect) {
this.view = view;
this.startEvent = startEvent;
this.style = style;
this.mustSelect = mustSelect;
this.scrollSpeed = { x: 0, y: 0 };
this.scrolling = -1;
this.lastEvent = startEvent;
this.scrollParents = scrollableParents(view.contentDOM);
this.atoms = view.state.facet(atomicRanges).map((f) => f(view));
let doc2 = view.contentDOM.ownerDocument;
doc2.addEventListener("mousemove", this.move = this.move.bind(this));
doc2.addEventListener("mouseup", this.up = this.up.bind(this));
this.extend = startEvent.shiftKey;
this.multiple = view.state.facet(EditorState.allowMultipleSelections) && addsSelectionRange(view, startEvent);
this.dragging = isInPrimarySelection(view, startEvent) && getClickType(startEvent) == 1 ? null : false;
}
start(event) {
if (this.dragging === false)
this.select(event);
}
move(event) {
if (event.buttons == 0)
return this.destroy();
if (this.dragging || this.dragging == null && dist(this.startEvent, event) < 10)
return;
this.select(this.lastEvent = event);
let sx = 0, sy = 0;
let left = 0, top2 = 0, right = this.view.win.innerWidth, bottom = this.view.win.innerHeight;
if (this.scrollParents.x)
({ left, right } = this.scrollParents.x.getBoundingClientRect());
if (this.scrollParents.y)
({ top: top2, bottom } = this.scrollParents.y.getBoundingClientRect());
let margins = getScrollMargins(this.view);
if (event.clientX - margins.left <= left + dragScrollMargin)
sx = -dragScrollSpeed(left - event.clientX);
else if (event.clientX + margins.right >= right - dragScrollMargin)
sx = dragScrollSpeed(event.clientX - right);
if (event.clientY - margins.top <= top2 + dragScrollMargin)
sy = -dragScrollSpeed(top2 - event.clientY);
else if (event.clientY + margins.bottom >= bottom - dragScrollMargin)
sy = dragScrollSpeed(event.clientY - bottom);
this.setScrollSpeed(sx, sy);
}
up(event) {
if (this.dragging == null)
this.select(this.lastEvent);
if (!this.dragging)
event.preventDefault();
this.destroy();
}
destroy() {
this.setScrollSpeed(0, 0);
let doc2 = this.view.contentDOM.ownerDocument;
doc2.removeEventListener("mousemove", this.move);
doc2.removeEventListener("mouseup", this.up);
this.view.inputState.mouseSelection = this.view.inputState.draggedContent = null;
}
setScrollSpeed(sx, sy) {
this.scrollSpeed = { x: sx, y: sy };
if (sx || sy) {
if (this.scrolling < 0)
this.scrolling = setInterval(() => this.scroll(), 50);
} else if (this.scrolling > -1) {
clearInterval(this.scrolling);
this.scrolling = -1;
}
}
scroll() {
let { x, y } = this.scrollSpeed;
if (x && this.scrollParents.x) {
this.scrollParents.x.scrollLeft += x;
x = 0;
}
if (y && this.scrollParents.y) {
this.scrollParents.y.scrollTop += y;
y = 0;
}
if (x || y)
this.view.win.scrollBy(x, y);
if (this.dragging === false)
this.select(this.lastEvent);
}
select(event) {
let { view } = this, selection = skipAtomsForSelection(this.atoms, this.style.get(event, this.extend, this.multiple));
if (this.mustSelect || !selection.eq(view.state.selection, this.dragging === false))
this.view.dispatch({
selection,
userEvent: "select.pointer"
});
this.mustSelect = false;
}
update(update) {
if (update.transactions.some((tr) => tr.isUserEvent("input.type")))
this.destroy();
else if (this.style.update(update))
setTimeout(() => this.select(this.lastEvent), 20);
}
};
function addsSelectionRange(view, event) {
let facet = view.state.facet(clickAddsSelectionRange);
return facet.length ? facet[0](event) : browser.mac ? event.metaKey : event.ctrlKey;
}
function dragMovesSelection(view, event) {
let facet = view.state.facet(dragMovesSelection$1);
return facet.length ? facet[0](event) : browser.mac ? !event.altKey : !event.ctrlKey;
}
function isInPrimarySelection(view, event) {
let { main } = view.state.selection;
if (main.empty)
return false;
let sel = getSelection(view.root);
if (!sel || sel.rangeCount == 0)
return true;
let rects = sel.getRangeAt(0).getClientRects();
for (let i = 0; i < rects.length; i++) {
let rect = rects[i];
if (rect.left <= event.clientX && rect.right >= event.clientX && rect.top <= event.clientY && rect.bottom >= event.clientY)
return true;
}
return false;
}
function eventBelongsToEditor(view, event) {
if (!event.bubbles)
return true;
if (event.defaultPrevented)
return false;
for (let node = event.target, tile; node != view.contentDOM; node = node.parentNode)
if (!node || node.nodeType == 11 || (tile = Tile.get(node)) && tile.isWidget() && !tile.isHidden && tile.widget.ignoreEvent(event))
return false;
return true;
}
var handlers = /* @__PURE__ */ Object.create(null);
var observers = /* @__PURE__ */ Object.create(null);
var brokenClipboardAPI = browser.ie && browser.ie_version < 15 || browser.ios && browser.webkit_version < 604;
function capturePaste(view) {
let parent = view.dom.parentNode;
if (!parent)
return;
let target = parent.appendChild(document.createElement("textarea"));
target.style.cssText = "position: fixed; left: -10000px; top: 10px";
target.focus();
setTimeout(() => {
view.focus();
target.remove();
doPaste(view, target.value);
}, 50);
}
function textFilter(state, facet, text) {
for (let filter of state.facet(facet))
text = filter(text, state);
return text;
}
function doPaste(view, input) {
input = textFilter(view.state, clipboardInputFilter, input);
let { state } = view, changes, i = 1, text = state.toText(input);
let byLine = text.lines == state.selection.ranges.length;
let linewise = lastLinewiseCopy != null && state.selection.ranges.every((r) => r.empty) && lastLinewiseCopy == text.toString();
if (linewise) {
let lastLine = -1;
changes = state.changeByRange((range) => {
let line = state.doc.lineAt(range.from);
if (line.from == lastLine)
return { range };
lastLine = line.from;
let insert = state.toText((byLine ? text.line(i++).text : input) + state.lineBreak);
return {
changes: { from: line.from, insert },
range: EditorSelection.cursor(range.from + insert.length)
};
});
} else if (byLine) {
changes = state.changeByRange((range) => {
let line = text.line(i++);
return {
changes: { from: range.from, to: range.to, insert: line.text },
range: EditorSelection.cursor(range.from + line.length)
};
});
} else {
changes = state.replaceSelection(text);
}
view.dispatch(changes, {
userEvent: "input.paste",
scrollIntoView: true
});
}
observers.scroll = (view) => {
view.inputState.lastScrollTop = view.scrollDOM.scrollTop;
view.inputState.lastScrollLeft = view.scrollDOM.scrollLeft;
};
observers.wheel = observers.mousewheel = (view) => {
view.inputState.lastWheelEvent = Date.now();
};
handlers.keydown = (view, event) => {
view.inputState.setSelectionOrigin("select");
if (event.keyCode == 27 && view.inputState.tabFocusMode != 0)
view.inputState.tabFocusMode = Date.now() + 2e3;
return false;
};
observers.touchstart = (view, e) => {
let iState = view.inputState, touch = e.targetTouches[0];
iState.lastTouchTime = Date.now();
if (touch) {
iState.lastTouchX = touch.clientX;
iState.lastTouchY = touch.clientY;
}
iState.setSelectionOrigin("select.pointer");
};
observers.touchmove = (view) => {
view.inputState.setSelectionOrigin("select.pointer");
};
handlers.mousedown = (view, event) => {
view.observer.flush();
if (view.inputState.lastTouchTime > Date.now() - 2e3)
return false;
let style = null;
for (let makeStyle of view.state.facet(mouseSelectionStyle)) {
style = makeStyle(view, event);
if (style)
break;
}
if (!style && event.button == 0)
style = basicMouseSelection(view, event);
if (style) {
let mustFocus = !view.hasFocus;
view.inputState.startMouseSelection(new MouseSelection(view, event, style, mustFocus));
if (mustFocus)
view.observer.ignore(() => {
focusPreventScroll(view.contentDOM);
let active = view.root.activeElement;
if (active && !active.contains(view.contentDOM))
active.blur();
});
let mouseSel = view.inputState.mouseSelection;
if (mouseSel) {
mouseSel.start(event);
return mouseSel.dragging === false;
}
} else {
view.inputState.setSelectionOrigin("select.pointer");
}
return false;
};
function rangeForClick(view, pos, bias, type) {
if (type == 1) {
return EditorSelection.cursor(pos, bias);
} else if (type == 2) {
return groupAt(view.state, pos, bias);
} else {
let visual = view.docView.lineAt(pos, bias), line = view.state.doc.lineAt(visual ? visual.posAtEnd : pos);
let from = visual ? visual.posAtStart : line.from, to = visual ? visual.posAtEnd : line.to;
if (to < view.state.doc.length && to == line.to)
to++;
return EditorSelection.range(from, to);
}
}
var BadMouseDetail = browser.ie && browser.ie_version <= 11;
var lastMouseDown = null;
var lastMouseDownCount = 0;
var lastMouseDownTime = 0;
function getClickType(event) {
if (!BadMouseDetail)
return event.detail;
let last = lastMouseDown, lastTime = lastMouseDownTime;
lastMouseDown = event;
lastMouseDownTime = Date.now();
return lastMouseDownCount = !last || lastTime > Date.now() - 400 && Math.abs(last.clientX - event.clientX) < 2 && Math.abs(last.clientY - event.clientY) < 2 ? (lastMouseDownCount + 1) % 3 : 1;
}
function basicMouseSelection(view, event) {
let start = view.posAndSideAtCoords({ x: event.clientX, y: event.clientY }, false), type = getClickType(event);
let startSel = view.state.selection;
return {
update(update) {
if (update.docChanged) {
start.pos = update.changes.mapPos(start.pos);
startSel = startSel.map(update.changes);
}
},
get(event2, extend, multiple) {
let cur = view.posAndSideAtCoords({ x: event2.clientX, y: event2.clientY }, false), removed;
let range = rangeForClick(view, cur.pos, cur.assoc, type);
if (start.pos != cur.pos && !extend) {
let startRange = rangeForClick(view, start.pos, start.assoc, type);
let from = Math.min(startRange.from, range.from), to = Math.max(startRange.to, range.to);
range = from < range.from ? EditorSelection.range(from, to, range.assoc) : EditorSelection.range(to, from, range.assoc);
}
if (extend)
return startSel.replaceRange(startSel.main.extend(range.from, range.to, range.assoc));
else if (multiple && type == 1 && startSel.ranges.length > 1 && (removed = removeRangeAround(startSel, cur.pos)))
return removed;
else if (multiple)
return startSel.addRange(range);
else
return EditorSelection.create([range]);
}
};
}
function removeRangeAround(sel, pos) {
for (let i = 0; i < sel.ranges.length; i++) {
let { from, to } = sel.ranges[i];
if (from <= pos && to >= pos)
return EditorSelection.create(sel.ranges.slice(0, i).concat(sel.ranges.slice(i + 1)), sel.mainIndex == i ? 0 : sel.mainIndex - (sel.mainIndex > i ? 1 : 0));
}
return null;
}
handlers.dragstart = (view, event) => {
let { selection: { main: range } } = view.state;
if (event.target.draggable) {
let tile = view.docView.tile.nearest(event.target);
if (tile && tile.isWidget()) {
let from = tile.posAtStart, to = from + tile.length;
if (from >= range.to || to <= range.from)
range = EditorSelection.range(from, to);
}
}
let { inputState } = view;
if (inputState.mouseSelection)
inputState.mouseSelection.dragging = true;
inputState.draggedContent = range;
if (event.dataTransfer) {
event.dataTransfer.setData("Text", textFilter(view.state, clipboardOutputFilter, view.state.sliceDoc(range.from, range.to)));
event.dataTransfer.effectAllowed = "copyMove";
}
return false;
};
handlers.dragend = (view) => {
view.inputState.draggedContent = null;
return false;
};
function dropText(view, event, text, direct) {
text = textFilter(view.state, clipboardInputFilter, text);
if (!text)
return;
let dropPos = view.posAtCoords({ x: event.clientX, y: event.clientY }, false);
let { draggedContent } = view.inputState;
let del = direct && draggedContent && dragMovesSelection(view, event) ? { from: draggedContent.from, to: draggedContent.to } : null;
let ins = { from: dropPos, insert: text };
let changes = view.state.changes(del ? [del, ins] : ins);
view.focus();
view.dispatch({
changes,
selection: { anchor: changes.mapPos(dropPos, -1), head: changes.mapPos(dropPos, 1) },
userEvent: del ? "move.drop" : "input.drop"
});
view.inputState.draggedContent = null;
}
handlers.drop = (view, event) => {
if (!event.dataTransfer)
return false;
if (view.state.readOnly)
return true;
let files = event.dataTransfer.files;
if (files && files.length) {
let text = Array(files.length), read = 0;
let finishFile = () => {
if (++read == files.length)
dropText(view, event, text.filter((s) => s != null).join(view.state.lineBreak), false);
};
for (let i = 0; i < files.length; i++) {
let reader = new FileReader();
reader.onerror = finishFile;
reader.onload = () => {
if (!/[\x00-\x08\x0e-\x1f]{2}/.test(reader.result))
text[i] = reader.result;
finishFile();
};
reader.readAsText(files[i]);
}
return true;
} else {
let text = event.dataTransfer.getData("Text");
if (text) {
dropText(view, event, text, true);
return true;
}
}
return false;
};
handlers.paste = (view, event) => {
if (view.state.readOnly)
return true;
view.observer.flush();
let data = brokenClipboardAPI ? null : event.clipboardData;
if (data) {
doPaste(view, data.getData("text/plain") || data.getData("text/uri-list"));
return true;
} else {
capturePaste(view);
return false;
}
};
function captureCopy(view, text) {
let parent = view.dom.parentNode;
if (!parent)
return;
let target = parent.appendChild(document.createElement("textarea"));
target.style.cssText = "position: fixed; left: -10000px; top: 10px";
target.value = text;
target.focus();
target.selectionEnd = text.length;
target.selectionStart = 0;
setTimeout(() => {
target.remove();
view.focus();
}, 50);
}
function copiedRange(state) {
let content = [], ranges = [], linewise = false;
for (let range of state.selection.ranges)
if (!range.empty) {
content.push(state.sliceDoc(range.from, range.to));
ranges.push(range);
}
if (!content.length) {
let upto = -1;
for (let { from } of state.selection.ranges) {
let line = state.doc.lineAt(from);
if (line.number > upto) {
content.push(line.text);
ranges.push({ from: line.from, to: Math.min(state.doc.length, line.to + 1) });
}
upto = line.number;
}
linewise = true;
}
return { text: textFilter(state, clipboardOutputFilter, content.join(state.lineBreak)), ranges, linewise };
}
var lastLinewiseCopy = null;
handlers.copy = handlers.cut = (view, event) => {
if (!hasSelection(view.contentDOM, view.observer.selectionRange))
return false;
let { text, ranges, linewise } = copiedRange(view.state);
if (!text && !linewise)
return false;
lastLinewiseCopy = linewise ? text : null;
if (event.type == "cut" && !view.state.readOnly)
view.dispatch({
changes: ranges,
scrollIntoView: true,
userEvent: "delete.cut"
});
let data = brokenClipboardAPI ? null : event.clipboardData;
if (data) {
data.clearData();
data.setData("text/plain", text);
return true;
} else {
captureCopy(view, text);
return false;
}
};
var isFocusChange = Annotation.define();
function focusChangeTransaction(state, focus) {
let effects = [];
for (let getEffect of state.facet(focusChangeEffect)) {
let effect = getEffect(state, focus);
if (effect)
effects.push(effect);
}
return effects.length ? state.update({ effects, annotations: isFocusChange.of(true) }) : null;
}
function updateForFocusChange(view) {
setTimeout(() => {
let focus = view.hasFocus;
if (focus != view.inputState.notifiedFocused) {
let tr = focusChangeTransaction(view.state, focus);
if (tr)
view.dispatch(tr);
else
view.update([]);
}
}, 10);
}
observers.focus = (view) => {
view.inputState.lastFocusTime = Date.now();
if (!view.scrollDOM.scrollTop && (view.inputState.lastScrollTop || view.inputState.lastScrollLeft)) {
view.scrollDOM.scrollTop = view.inputState.lastScrollTop;
view.scrollDOM.scrollLeft = view.inputState.lastScrollLeft;
}
updateForFocusChange(view);
};
observers.blur = (view) => {
view.observer.clearSelectionRange();
updateForFocusChange(view);
};
observers.compositionstart = observers.compositionupdate = (view) => {
if (view.observer.editContext)
return;
if (view.inputState.compositionFirstChange == null)
view.inputState.compositionFirstChange = true;
if (view.inputState.composing < 0) {
view.inputState.composing = 0;
}
};
observers.compositionend = (view) => {
if (view.observer.editContext)
return;
view.inputState.composing = -1;
view.inputState.compositionEndedAt = Date.now();
view.inputState.compositionPendingKey = true;
view.inputState.compositionPendingChange = view.observer.pendingRecords().length > 0;
view.inputState.compositionFirstChange = null;
if (browser.chrome && browser.android) {
view.observer.flushSoon();
} else if (view.inputState.compositionPendingChange) {
Promise.resolve().then(() => view.observer.flush());
} else {
setTimeout(() => {
if (view.inputState.composing < 0 && view.docView.hasComposition)
view.update([]);
}, 50);
}
};
observers.contextmenu = (view) => {
view.inputState.lastContextMenu = Date.now();
};
handlers.beforeinput = (view, event) => {
var _a, _b;
if (event.inputType == "insertText" || event.inputType == "insertCompositionText") {
view.inputState.insertingText = event.data;
view.inputState.insertingTextAt = Date.now();
}
if (event.inputType == "insertReplacementText" && view.observer.editContext) {
let text = (_a = event.dataTransfer) === null || _a === void 0 ? void 0 : _a.getData("text/plain"), ranges = event.getTargetRanges();
if (text && ranges.length) {
let r = ranges[0];
let from = view.posAtDOM(r.startContainer, r.startOffset), to = view.posAtDOM(r.endContainer, r.endOffset);
applyDOMChangeInner(view, { from, to, insert: view.state.toText(text) }, null);
return true;
}
}
let pending;
if (browser.chrome && browser.android && (pending = PendingKeys.find((key) => key.inputType == event.inputType))) {
view.observer.delayAndroidKey(pending.key, pending.keyCode);
if (pending.key == "Backspace" || pending.key == "Delete") {
let startViewHeight = ((_b = window.visualViewport) === null || _b === void 0 ? void 0 : _b.height) || 0;
setTimeout(() => {
var _a2;
if ((((_a2 = window.visualViewport) === null || _a2 === void 0 ? void 0 : _a2.height) || 0) > startViewHeight + 10 && view.hasFocus) {
view.contentDOM.blur();
view.focus();
}
}, 100);
}
}
if (browser.ios && event.inputType == "deleteContentForward") {
view.observer.flushSoon();
}
if (browser.safari && event.inputType == "insertText" && view.inputState.composing >= 0) {
setTimeout(() => observers.compositionend(view, event), 20);
}
return false;
};
var appliedFirefoxHack = /* @__PURE__ */ new Set();
function firefoxCopyCutHack(doc2) {
if (!appliedFirefoxHack.has(doc2)) {
appliedFirefoxHack.add(doc2);
doc2.addEventListener("copy", () => {
});
doc2.addEventListener("cut", () => {
});
}
}
var wrappingWhiteSpace = ["pre-wrap", "normal", "pre-line", "break-spaces"];
var heightChangeFlag = false;
function clearHeightChangeFlag() {
heightChangeFlag = false;
}
var HeightOracle = class {
constructor(lineWrapping) {
this.lineWrapping = lineWrapping;
this.doc = Text.empty;
this.heightSamples = {};
this.lineHeight = 14;
this.charWidth = 7;
this.textHeight = 14;
this.lineLength = 30;
}
heightForGap(from, to) {
let lines = this.doc.lineAt(to).number - this.doc.lineAt(from).number + 1;
if (this.lineWrapping)
lines += Math.max(0, Math.ceil((to - from - lines * this.lineLength * 0.5) / this.lineLength));
return this.lineHeight * lines;
}
heightForLine(length) {
if (!this.lineWrapping)
return this.lineHeight;
let lines = 1 + Math.max(0, Math.ceil((length - this.lineLength) / Math.max(1, this.lineLength - 5)));
return lines * this.lineHeight;
}
setDoc(doc2) {
this.doc = doc2;
return this;
}
mustRefreshForWrapping(whiteSpace) {
return wrappingWhiteSpace.indexOf(whiteSpace) > -1 != this.lineWrapping;
}
mustRefreshForHeights(lineHeights) {
let newHeight = false;
for (let i = 0; i < lineHeights.length; i++) {
let h = lineHeights[i];
if (h < 0) {
i++;
} else if (!this.heightSamples[Math.floor(h * 10)]) {
newHeight = true;
this.heightSamples[Math.floor(h * 10)] = true;
}
}
return newHeight;
}
refresh(whiteSpace, lineHeight, charWidth, textHeight, lineLength, knownHeights) {
let lineWrapping = wrappingWhiteSpace.indexOf(whiteSpace) > -1;
let changed = Math.abs(lineHeight - this.lineHeight) > 0.3 || this.lineWrapping != lineWrapping;
this.lineWrapping = lineWrapping;
this.lineHeight = lineHeight;
this.charWidth = charWidth;
this.textHeight = textHeight;
this.lineLength = lineLength;
if (changed) {
this.heightSamples = {};
for (let i = 0; i < knownHeights.length; i++) {
let h = knownHeights[i];
if (h < 0)
i++;
else
this.heightSamples[Math.floor(h * 10)] = true;
}
}
return changed;
}
};
var MeasuredHeights = class {
constructor(from, heights) {
this.from = from;
this.heights = heights;
this.index = 0;
}
get more() {
return this.index < this.heights.length;
}
};
var BlockInfo = class _BlockInfo {
/**
@internal
*/
constructor(from, length, top2, height, _content) {
this.from = from;
this.length = length;
this.top = top2;
this.height = height;
this._content = _content;
}
/**
The type of element this is. When querying lines, this may be
an array of all the blocks that make up the line.
*/
get type() {
return typeof this._content == "number" ? BlockType.Text : Array.isArray(this._content) ? this._content : this._content.type;
}
/**
The end of the element as a document position.
*/
get to() {
return this.from + this.length;
}
/**
The bottom position of the element.
*/
get bottom() {
return this.top + this.height;
}
/**
If this is a widget block, this will return the widget
associated with it.
*/
get widget() {
return this._content instanceof PointDecoration ? this._content.widget : null;
}
/**
If this is a textblock, this holds the number of line breaks
that appear in widgets inside the block.
*/
get widgetLineBreaks() {
return typeof this._content == "number" ? this._content : 0;
}
/**
@internal
*/
join(other) {
let content = (Array.isArray(this._content) ? this._content : [this]).concat(Array.isArray(other._content) ? other._content : [other]);
return new _BlockInfo(this.from, this.length + other.length, this.top, this.height + other.height, content);
}
};
var QueryType = function(QueryType2) {
QueryType2[QueryType2["ByPos"] = 0] = "ByPos";
QueryType2[QueryType2["ByHeight"] = 1] = "ByHeight";
QueryType2[QueryType2["ByPosNoHeight"] = 2] = "ByPosNoHeight";
return QueryType2;
}(QueryType || (QueryType = {}));
var Epsilon = 1e-3;
var HeightMap = class _HeightMap {
constructor(length, height, flags = 2) {
this.length = length;
this.height = height;
this.flags = flags;
}
get outdated() {
return (this.flags & 2) > 0;
}
set outdated(value) {
this.flags = (value ? 2 : 0) | this.flags & ~2;
}
setHeight(height) {
if (this.height != height) {
if (Math.abs(this.height - height) > Epsilon)
heightChangeFlag = true;
this.height = height;
}
}
// Base case is to replace a leaf node, which simply builds a tree
// from the new nodes and returns that (HeightMapBranch and
// HeightMapGap override this to actually use from/to)
replace(_from, _to, nodes) {
return _HeightMap.of(nodes);
}
// Again, these are base cases, and are overridden for branch and gap nodes.
decomposeLeft(_to, result) {
result.push(this);
}
decomposeRight(_from, result) {
result.push(this);
}
applyChanges(decorations2, oldDoc, oracle, changes) {
let me = this, doc2 = oracle.doc;
for (let i = changes.length - 1; i >= 0; i--) {
let { fromA, toA, fromB, toB } = changes[i];
let start = me.lineAt(fromA, QueryType.ByPosNoHeight, oracle.setDoc(oldDoc), 0, 0);
let end = start.to >= toA ? start : me.lineAt(toA, QueryType.ByPosNoHeight, oracle, 0, 0);
toB += end.to - toA;
toA = end.to;
while (i > 0 && start.from <= changes[i - 1].toA) {
fromA = changes[i - 1].fromA;
fromB = changes[i - 1].fromB;
i--;
if (fromA < start.from)
start = me.lineAt(fromA, QueryType.ByPosNoHeight, oracle, 0, 0);
}
fromB += start.from - fromA;
fromA = start.from;
let nodes = NodeBuilder.build(oracle.setDoc(doc2), decorations2, fromB, toB);
me = replace(me, me.replace(fromA, toA, nodes));
}
return me.updateHeight(oracle, 0);
}
static empty() {
return new HeightMapText(0, 0, 0);
}
// nodes uses null values to indicate the position of line breaks.
// There are never line breaks at the start or end of the array, or
// two line breaks next to each other, and the array isn't allowed
// to be empty (same restrictions as return value from the builder).
static of(nodes) {
if (nodes.length == 1)
return nodes[0];
let i = 0, j = nodes.length, before = 0, after = 0;
for (; ; ) {
if (i == j) {
if (before > after * 2) {
let split = nodes[i - 1];
if (split.break)
nodes.splice(--i, 1, split.left, null, split.right);
else
nodes.splice(--i, 1, split.left, split.right);
j += 1 + split.break;
before -= split.size;
} else if (after > before * 2) {
let split = nodes[j];
if (split.break)
nodes.splice(j, 1, split.left, null, split.right);
else
nodes.splice(j, 1, split.left, split.right);
j += 2 + split.break;
after -= split.size;
} else {
break;
}
} else if (before < after) {
let next = nodes[i++];
if (next)
before += next.size;
} else {
let next = nodes[--j];
if (next)
after += next.size;
}
}
let brk = 0;
if (nodes[i - 1] == null) {
brk = 1;
i--;
} else if (nodes[i] == null) {
brk = 1;
j++;
}
return new HeightMapBranch(_HeightMap.of(nodes.slice(0, i)), brk, _HeightMap.of(nodes.slice(j)));
}
};
function replace(old, val) {
if (old == val)
return old;
if (old.constructor != val.constructor)
heightChangeFlag = true;
return val;
}
HeightMap.prototype.size = 1;
var SpaceDeco = Decoration.replace({});
var HeightMapBlock = class extends HeightMap {
constructor(length, height, deco) {
super(length, height);
this.deco = deco;
this.spaceAbove = 0;
}
mainBlock(top2, offset) {
return new BlockInfo(offset, this.length, top2 + this.spaceAbove, this.height - this.spaceAbove, this.deco || 0);
}
blockAt(height, _oracle, top2, offset) {
return this.spaceAbove && height < top2 + this.spaceAbove ? new BlockInfo(offset, 0, top2, this.spaceAbove, SpaceDeco) : this.mainBlock(top2, offset);
}
lineAt(_value, _type, oracle, top2, offset) {
let main = this.mainBlock(top2, offset);
return this.spaceAbove ? this.blockAt(0, oracle, top2, offset).join(main) : main;
}
forEachLine(from, to, oracle, top2, offset, f) {
if (from <= offset + this.length && to >= offset)
f(this.lineAt(0, QueryType.ByPos, oracle, top2, offset));
}
setMeasuredHeight(measured) {
let next = measured.heights[measured.index++];
if (next < 0) {
this.spaceAbove = -next;
next = measured.heights[measured.index++];
} else {
this.spaceAbove = 0;
}
this.setHeight(next);
}
updateHeight(oracle, offset = 0, _force = false, measured) {
if (measured && measured.from <= offset && measured.more)
this.setMeasuredHeight(measured);
this.outdated = false;
return this;
}
toString() {
return `block(${this.length})`;
}
};
var HeightMapText = class _HeightMapText extends HeightMapBlock {
constructor(length, height, above) {
super(length, height, null);
this.collapsed = 0;
this.widgetHeight = 0;
this.breaks = 0;
this.spaceAbove = above;
}
mainBlock(top2, offset) {
return new BlockInfo(offset, this.length, top2 + this.spaceAbove, this.height - this.spaceAbove, this.breaks);
}
replace(_from, _to, nodes) {
let node = nodes[0];
if (nodes.length == 1 && (node instanceof _HeightMapText || node instanceof HeightMapGap && node.flags & 4) && Math.abs(this.length - node.length) < 10) {
if (node instanceof HeightMapGap)
node = new _HeightMapText(node.length, this.height, this.spaceAbove);
else
node.height = this.height;
if (!this.outdated)
node.outdated = false;
return node;
} else {
return HeightMap.of(nodes);
}
}
updateHeight(oracle, offset = 0, force = false, measured) {
if (measured && measured.from <= offset && measured.more) {
this.setMeasuredHeight(measured);
} else if (force || this.outdated) {
this.spaceAbove = 0;
this.setHeight(Math.max(this.widgetHeight, oracle.heightForLine(this.length - this.collapsed)) + this.breaks * oracle.lineHeight);
}
this.outdated = false;
return this;
}
toString() {
return `line(${this.length}${this.collapsed ? -this.collapsed : ""}${this.widgetHeight ? ":" + this.widgetHeight : ""})`;
}
};
var HeightMapGap = class _HeightMapGap extends HeightMap {
constructor(length) {
super(length, 0);
}
heightMetrics(oracle, offset) {
let firstLine = oracle.doc.lineAt(offset).number, lastLine = oracle.doc.lineAt(offset + this.length).number;
let lines = lastLine - firstLine + 1;
let perLine, perChar = 0;
if (oracle.lineWrapping) {
let totalPerLine = Math.min(this.height, oracle.lineHeight * lines);
perLine = totalPerLine / lines;
if (this.length > lines + 1)
perChar = (this.height - totalPerLine) / (this.length - lines - 1);
} else {
perLine = this.height / lines;
}
return { firstLine, lastLine, perLine, perChar };
}
blockAt(height, oracle, top2, offset) {
let { firstLine, lastLine, perLine, perChar } = this.heightMetrics(oracle, offset);
if (oracle.lineWrapping) {
let guess = offset + (height < oracle.lineHeight ? 0 : Math.round(Math.max(0, Math.min(1, (height - top2) / this.height)) * this.length));
let line = oracle.doc.lineAt(guess), lineHeight = perLine + line.length * perChar;
let lineTop = Math.max(top2, height - lineHeight / 2);
return new BlockInfo(line.from, line.length, lineTop, lineHeight, 0);
} else {
let line = Math.max(0, Math.min(lastLine - firstLine, Math.floor((height - top2) / perLine)));
let { from, length } = oracle.doc.line(firstLine + line);
return new BlockInfo(from, length, top2 + perLine * line, perLine, 0);
}
}
lineAt(value, type, oracle, top2, offset) {
if (type == QueryType.ByHeight)
return this.blockAt(value, oracle, top2, offset);
if (type == QueryType.ByPosNoHeight) {
let { from, to } = oracle.doc.lineAt(value);
return new BlockInfo(from, to - from, 0, 0, 0);
}
let { firstLine, perLine, perChar } = this.heightMetrics(oracle, offset);
let line = oracle.doc.lineAt(value), lineHeight = perLine + line.length * perChar;
let linesAbove = line.number - firstLine;
let lineTop = top2 + perLine * linesAbove + perChar * (line.from - offset - linesAbove);
return new BlockInfo(line.from, line.length, Math.max(top2, Math.min(lineTop, top2 + this.height - lineHeight)), lineHeight, 0);
}
forEachLine(from, to, oracle, top2, offset, f) {
from = Math.max(from, offset);
to = Math.min(to, offset + this.length);
let { firstLine, perLine, perChar } = this.heightMetrics(oracle, offset);
for (let pos = from, lineTop = top2; pos <= to; ) {
let line = oracle.doc.lineAt(pos);
if (pos == from) {
let linesAbove = line.number - firstLine;
lineTop += perLine * linesAbove + perChar * (from - offset - linesAbove);
}
let lineHeight = perLine + perChar * line.length;
f(new BlockInfo(line.from, line.length, lineTop, lineHeight, 0));
lineTop += lineHeight;
pos = line.to + 1;
}
}
replace(from, to, nodes) {
let after = this.length - to;
if (after > 0) {
let last = nodes[nodes.length - 1];
if (last instanceof _HeightMapGap)
nodes[nodes.length - 1] = new _HeightMapGap(last.length + after);
else
nodes.push(null, new _HeightMapGap(after - 1));
}
if (from > 0) {
let first = nodes[0];
if (first instanceof _HeightMapGap)
nodes[0] = new _HeightMapGap(from + first.length);
else
nodes.unshift(new _HeightMapGap(from - 1), null);
}
return HeightMap.of(nodes);
}
decomposeLeft(to, result) {
result.push(new _HeightMapGap(to - 1), null);
}
decomposeRight(from, result) {
result.push(null, new _HeightMapGap(this.length - from - 1));
}
updateHeight(oracle, offset = 0, force = false, measured) {
let end = offset + this.length;
if (measured && measured.from <= offset + this.length && measured.more) {
let nodes = [], pos = Math.max(offset, measured.from), singleHeight = -1;
if (measured.from > offset)
nodes.push(new _HeightMapGap(measured.from - offset - 1).updateHeight(oracle, offset));
while (pos <= end && measured.more) {
let len = oracle.doc.lineAt(pos).length;
if (nodes.length)
nodes.push(null);
let height = measured.heights[measured.index++], above = 0;
if (height < 0) {
above = -height;
height = measured.heights[measured.index++];
}
if (singleHeight == -1)
singleHeight = height;
else if (Math.abs(height - singleHeight) >= Epsilon)
singleHeight = -2;
let line = new HeightMapText(len, height, above);
line.outdated = false;
nodes.push(line);
pos += len + 1;
}
if (pos <= end)
nodes.push(null, new _HeightMapGap(end - pos).updateHeight(oracle, pos));
let result = HeightMap.of(nodes);
if (singleHeight < 0 || Math.abs(result.height - this.height) >= Epsilon || Math.abs(singleHeight - this.heightMetrics(oracle, offset).perLine) >= Epsilon)
heightChangeFlag = true;
return replace(this, result);
} else if (force || this.outdated) {
this.setHeight(oracle.heightForGap(offset, offset + this.length));
this.outdated = false;
}
return this;
}
toString() {
return `gap(${this.length})`;
}
};
var HeightMapBranch = class extends HeightMap {
constructor(left, brk, right) {
super(left.length + brk + right.length, left.height + right.height, brk | (left.outdated || right.outdated ? 2 : 0));
this.left = left;
this.right = right;
this.size = left.size + right.size;
}
get break() {
return this.flags & 1;
}
blockAt(height, oracle, top2, offset) {
let mid = top2 + this.left.height;
return height < mid ? this.left.blockAt(height, oracle, top2, offset) : this.right.blockAt(height, oracle, mid, offset + this.left.length + this.break);
}
lineAt(value, type, oracle, top2, offset) {
let rightTop = top2 + this.left.height, rightOffset = offset + this.left.length + this.break;
let left = type == QueryType.ByHeight ? value < rightTop : value < rightOffset;
let base2 = left ? this.left.lineAt(value, type, oracle, top2, offset) : this.right.lineAt(value, type, oracle, rightTop, rightOffset);
if (this.break || (left ? base2.to < rightOffset : base2.from > rightOffset))
return base2;
let subQuery = type == QueryType.ByPosNoHeight ? QueryType.ByPosNoHeight : QueryType.ByPos;
if (left)
return base2.join(this.right.lineAt(rightOffset, subQuery, oracle, rightTop, rightOffset));
else
return this.left.lineAt(rightOffset, subQuery, oracle, top2, offset).join(base2);
}
forEachLine(from, to, oracle, top2, offset, f) {
let rightTop = top2 + this.left.height, rightOffset = offset + this.left.length + this.break;
if (this.break) {
if (from < rightOffset)
this.left.forEachLine(from, to, oracle, top2, offset, f);
if (to >= rightOffset)
this.right.forEachLine(from, to, oracle, rightTop, rightOffset, f);
} else {
let mid = this.lineAt(rightOffset, QueryType.ByPos, oracle, top2, offset);
if (from < mid.from)
this.left.forEachLine(from, mid.from - 1, oracle, top2, offset, f);
if (mid.to >= from && mid.from <= to)
f(mid);
if (to > mid.to)
this.right.forEachLine(mid.to + 1, to, oracle, rightTop, rightOffset, f);
}
}
replace(from, to, nodes) {
let rightStart = this.left.length + this.break;
if (to < rightStart)
return this.balanced(this.left.replace(from, to, nodes), this.right);
if (from > this.left.length)
return this.balanced(this.left, this.right.replace(from - rightStart, to - rightStart, nodes));
let result = [];
if (from > 0)
this.decomposeLeft(from, result);
let left = result.length;
for (let node of nodes)
result.push(node);
if (from > 0)
mergeGaps(result, left - 1);
if (to < this.length) {
let right = result.length;
this.decomposeRight(to, result);
mergeGaps(result, right);
}
return HeightMap.of(result);
}
decomposeLeft(to, result) {
let left = this.left.length;
if (to <= left)
return this.left.decomposeLeft(to, result);
result.push(this.left);
if (this.break) {
left++;
if (to >= left)
result.push(null);
}
if (to > left)
this.right.decomposeLeft(to - left, result);
}
decomposeRight(from, result) {
let left = this.left.length, right = left + this.break;
if (from >= right)
return this.right.decomposeRight(from - right, result);
if (from < left)
this.left.decomposeRight(from, result);
if (this.break && from < right)
result.push(null);
result.push(this.right);
}
balanced(left, right) {
if (left.size > 2 * right.size || right.size > 2 * left.size)
return HeightMap.of(this.break ? [left, null, right] : [left, right]);
this.left = replace(this.left, left);
this.right = replace(this.right, right);
this.setHeight(left.height + right.height);
this.outdated = left.outdated || right.outdated;
this.size = left.size + right.size;
this.length = left.length + this.break + right.length;
return this;
}
updateHeight(oracle, offset = 0, force = false, measured) {
let { left, right } = this, rightStart = offset + left.length + this.break, rebalance = null;
if (measured && measured.from <= offset + left.length && measured.more)
rebalance = left = left.updateHeight(oracle, offset, force, measured);
else
left.updateHeight(oracle, offset, force);
if (measured && measured.from <= rightStart + right.length && measured.more)
rebalance = right = right.updateHeight(oracle, rightStart, force, measured);
else
right.updateHeight(oracle, rightStart, force);
if (rebalance)
return this.balanced(left, right);
this.height = this.left.height + this.right.height;
this.outdated = false;
return this;
}
toString() {
return this.left + (this.break ? " " : "-") + this.right;
}
};
function mergeGaps(nodes, around) {
let before, after;
if (nodes[around] == null && (before = nodes[around - 1]) instanceof HeightMapGap && (after = nodes[around + 1]) instanceof HeightMapGap)
nodes.splice(around - 1, 3, new HeightMapGap(before.length + 1 + after.length));
}
var relevantWidgetHeight = 5;
var NodeBuilder = class _NodeBuilder {
constructor(pos, oracle) {
this.pos = pos;
this.oracle = oracle;
this.nodes = [];
this.lineStart = -1;
this.lineEnd = -1;
this.covering = null;
this.writtenTo = pos;
}
get isCovered() {
return this.covering && this.nodes[this.nodes.length - 1] == this.covering;
}
span(_from, to) {
if (this.lineStart > -1) {
let end = Math.min(to, this.lineEnd), last = this.nodes[this.nodes.length - 1];
if (last instanceof HeightMapText)
last.length += end - this.pos;
else if (end > this.pos || !this.isCovered)
this.nodes.push(new HeightMapText(end - this.pos, -1, 0));
this.writtenTo = end;
if (to > end) {
this.nodes.push(null);
this.writtenTo++;
this.lineStart = -1;
}
}
this.pos = to;
}
point(from, to, deco) {
if (from < to || deco.heightRelevant) {
let height = deco.widget ? deco.widget.estimatedHeight : 0;
let breaks = deco.widget ? deco.widget.lineBreaks : 0;
if (height < 0)
height = this.oracle.lineHeight;
let len = to - from;
if (deco.block) {
this.addBlock(new HeightMapBlock(len, height, deco));
} else if (len || breaks || height >= relevantWidgetHeight) {
this.addLineDeco(height, breaks, len);
}
} else if (to > from) {
this.span(from, to);
}
if (this.lineEnd > -1 && this.lineEnd < this.pos)
this.lineEnd = this.oracle.doc.lineAt(this.pos).to;
}
enterLine() {
if (this.lineStart > -1)
return;
let { from, to } = this.oracle.doc.lineAt(this.pos);
this.lineStart = from;
this.lineEnd = to;
if (this.writtenTo < from) {
if (this.writtenTo < from - 1 || this.nodes[this.nodes.length - 1] == null)
this.nodes.push(this.blankContent(this.writtenTo, from - 1));
this.nodes.push(null);
}
if (this.pos > from)
this.nodes.push(new HeightMapText(this.pos - from, -1, 0));
this.writtenTo = this.pos;
}
blankContent(from, to) {
let gap = new HeightMapGap(to - from);
if (this.oracle.doc.lineAt(from).to == to)
gap.flags |= 4;
return gap;
}
ensureLine() {
this.enterLine();
let last = this.nodes.length ? this.nodes[this.nodes.length - 1] : null;
if (last instanceof HeightMapText)
return last;
let line = new HeightMapText(0, -1, 0);
this.nodes.push(line);
return line;
}
addBlock(block) {
this.enterLine();
let deco = block.deco;
if (deco && deco.startSide > 0 && !this.isCovered)
this.ensureLine();
this.nodes.push(block);
this.writtenTo = this.pos = this.pos + block.length;
if (deco && deco.endSide > 0)
this.covering = block;
}
addLineDeco(height, breaks, length) {
let line = this.ensureLine();
line.length += length;
line.collapsed += length;
line.widgetHeight = Math.max(line.widgetHeight, height);
line.breaks += breaks;
this.writtenTo = this.pos = this.pos + length;
}
finish(from) {
let last = this.nodes.length == 0 ? null : this.nodes[this.nodes.length - 1];
if (this.lineStart > -1 && !(last instanceof HeightMapText) && !this.isCovered)
this.nodes.push(new HeightMapText(0, -1, 0));
else if (this.writtenTo < this.pos || last == null)
this.nodes.push(this.blankContent(this.writtenTo, this.pos));
let pos = from;
for (let node of this.nodes) {
if (node instanceof HeightMapText)
node.updateHeight(this.oracle, pos);
pos += node ? node.length : 1;
}
return this.nodes;
}
// Always called with a region that on both sides either stretches
// to a line break or the end of the document.
// The returned array uses null to indicate line breaks, but never
// starts or ends in a line break, or has multiple line breaks next
// to each other.
static build(oracle, decorations2, from, to) {
let builder = new _NodeBuilder(from, oracle);
RangeSet.spans(decorations2, from, to, builder, 0);
return builder.finish(from);
}
};
function heightRelevantDecoChanges(a, b, diff) {
let comp = new DecorationComparator2();
RangeSet.compare(a, b, diff, comp, 0);
return comp.changes;
}
var DecorationComparator2 = class {
constructor() {
this.changes = [];
}
compareRange() {
}
comparePoint(from, to, a, b) {
if (from < to || a && a.heightRelevant || b && b.heightRelevant)
addRange(from, to, this.changes, 5);
}
};
function visiblePixelRange(dom, paddingTop) {
let rect = dom.getBoundingClientRect();
let doc2 = dom.ownerDocument, win = doc2.defaultView || window;
let left = Math.max(0, rect.left), right = Math.min(win.innerWidth, rect.right);
let top2 = Math.max(0, rect.top), bottom = Math.min(win.innerHeight, rect.bottom);
for (let parent = dom.parentNode; parent && parent != doc2.body; ) {
if (parent.nodeType == 1) {
let elt = parent;
let style = window.getComputedStyle(elt);
if ((elt.scrollHeight > elt.clientHeight || elt.scrollWidth > elt.clientWidth) && style.overflow != "visible") {
let parentRect = elt.getBoundingClientRect();
left = Math.max(left, parentRect.left);
right = Math.min(right, parentRect.right);
top2 = Math.max(top2, parentRect.top);
bottom = Math.min(parent == dom.parentNode ? win.innerHeight : bottom, parentRect.bottom);
}
parent = style.position == "absolute" || style.position == "fixed" ? elt.offsetParent : elt.parentNode;
} else if (parent.nodeType == 11) {
parent = parent.host;
} else {
break;
}
}
return {
left: left - rect.left,
right: Math.max(left, right) - rect.left,
top: top2 - (rect.top + paddingTop),
bottom: Math.max(top2, bottom) - (rect.top + paddingTop)
};
}
function inWindow(elt) {
let rect = elt.getBoundingClientRect(), win = elt.ownerDocument.defaultView || window;
return rect.left < win.innerWidth && rect.right > 0 && rect.top < win.innerHeight && rect.bottom > 0;
}
function fullPixelRange(dom, paddingTop) {
let rect = dom.getBoundingClientRect();
return {
left: 0,
right: rect.right - rect.left,
top: paddingTop,
bottom: rect.bottom - (rect.top + paddingTop)
};
}
var LineGap = class {
constructor(from, to, size, displaySize) {
this.from = from;
this.to = to;
this.size = size;
this.displaySize = displaySize;
}
static same(a, b) {
if (a.length != b.length)
return false;
for (let i = 0; i < a.length; i++) {
let gA = a[i], gB = b[i];
if (gA.from != gB.from || gA.to != gB.to || gA.size != gB.size)
return false;
}
return true;
}
draw(viewState, wrapping) {
return Decoration.replace({
widget: new LineGapWidget(this.displaySize * (wrapping ? viewState.scaleY : viewState.scaleX), wrapping)
}).range(this.from, this.to);
}
};
var LineGapWidget = class extends WidgetType {
constructor(size, vertical) {
super();
this.size = size;
this.vertical = vertical;
}
eq(other) {
return other.size == this.size && other.vertical == this.vertical;
}
toDOM() {
let elt = document.createElement("div");
if (this.vertical) {
elt.style.height = this.size + "px";
} else {
elt.style.width = this.size + "px";
elt.style.height = "2px";
elt.style.display = "inline-block";
}
return elt;
}
get estimatedHeight() {
return this.vertical ? this.size : -1;
}
};
var ViewState = class {
constructor(view, state) {
this.view = view;
this.state = state;
this.pixelViewport = { left: 0, right: window.innerWidth, top: 0, bottom: 0 };
this.inView = true;
this.paddingTop = 0;
this.paddingBottom = 0;
this.contentDOMWidth = 0;
this.contentDOMHeight = 0;
this.editorHeight = 0;
this.editorWidth = 0;
this.scaleX = 1;
this.scaleY = 1;
this.scrollOffset = 0;
this.scrolledToBottom = false;
this.scrollAnchorPos = 0;
this.scrollAnchorHeight = -1;
this.scaler = IdScaler;
this.scrollTarget = null;
this.printing = false;
this.mustMeasureContent = true;
this.defaultTextDirection = Direction.LTR;
this.visibleRanges = [];
this.mustEnforceCursorAssoc = false;
let guessWrapping = state.facet(contentAttributes).some((v) => typeof v != "function" && v.class == "cm-lineWrapping");
this.heightOracle = new HeightOracle(guessWrapping);
this.stateDeco = staticDeco(state);
this.heightMap = HeightMap.empty().applyChanges(this.stateDeco, Text.empty, this.heightOracle.setDoc(state.doc), [new ChangedRange(0, 0, 0, state.doc.length)]);
for (let i = 0; i < 2; i++) {
this.viewport = this.getViewport(0, null);
if (!this.updateForViewport())
break;
}
this.updateViewportLines();
this.lineGaps = this.ensureLineGaps([]);
this.lineGapDeco = Decoration.set(this.lineGaps.map((gap) => gap.draw(this, false)));
this.scrollParent = view.scrollDOM;
this.computeVisibleRanges();
}
updateForViewport() {
let viewports = [this.viewport], { main } = this.state.selection;
for (let i = 0; i <= 1; i++) {
let pos = i ? main.head : main.anchor;
if (!viewports.some(({ from, to }) => pos >= from && pos <= to)) {
let { from, to } = this.lineBlockAt(pos);
viewports.push(new Viewport(from, to));
}
}
this.viewports = viewports.sort((a, b) => a.from - b.from);
return this.updateScaler();
}
updateScaler() {
let scaler = this.scaler;
this.scaler = this.heightMap.height <= 7e6 ? IdScaler : new BigScaler(this.heightOracle, this.heightMap, this.viewports);
return scaler.eq(this.scaler) ? 0 : 2;
}
updateViewportLines() {
this.viewportLines = [];
this.heightMap.forEachLine(this.viewport.from, this.viewport.to, this.heightOracle.setDoc(this.state.doc), 0, 0, (block) => {
this.viewportLines.push(scaleBlock(block, this.scaler));
});
}
update(update, scrollTarget = null) {
this.state = update.state;
let prevDeco = this.stateDeco;
this.stateDeco = staticDeco(this.state);
let contentChanges = update.changedRanges;
let heightChanges = ChangedRange.extendWithRanges(contentChanges, heightRelevantDecoChanges(prevDeco, this.stateDeco, update ? update.changes : ChangeSet.empty(this.state.doc.length)));
let prevHeight = this.heightMap.height;
let scrollAnchor = this.scrolledToBottom ? null : this.scrollAnchorAt(this.scrollOffset);
clearHeightChangeFlag();
this.heightMap = this.heightMap.applyChanges(this.stateDeco, update.startState.doc, this.heightOracle.setDoc(this.state.doc), heightChanges);
if (this.heightMap.height != prevHeight || heightChangeFlag)
update.flags |= 2;
if (scrollAnchor) {
this.scrollAnchorPos = update.changes.mapPos(scrollAnchor.from, -1);
this.scrollAnchorHeight = scrollAnchor.top;
} else {
this.scrollAnchorPos = -1;
this.scrollAnchorHeight = prevHeight;
}
let viewport = heightChanges.length ? this.mapViewport(this.viewport, update.changes) : this.viewport;
if (scrollTarget && (scrollTarget.range.head < viewport.from || scrollTarget.range.head > viewport.to) || !this.viewportIsAppropriate(viewport))
viewport = this.getViewport(0, scrollTarget);
let viewportChange = viewport.from != this.viewport.from || viewport.to != this.viewport.to;
this.viewport = viewport;
update.flags |= this.updateForViewport();
if (viewportChange || !update.changes.empty || update.flags & 2)
this.updateViewportLines();
if (this.lineGaps.length || this.viewport.to - this.viewport.from > 2e3 << 1)
this.updateLineGaps(this.ensureLineGaps(this.mapLineGaps(this.lineGaps, update.changes)));
update.flags |= this.computeVisibleRanges(update.changes);
if (scrollTarget)
this.scrollTarget = scrollTarget;
if (!this.mustEnforceCursorAssoc && (update.selectionSet || update.focusChanged) && update.view.lineWrapping && update.state.selection.main.empty && update.state.selection.main.assoc && !update.state.facet(nativeSelectionHidden))
this.mustEnforceCursorAssoc = true;
}
measure() {
let { view } = this, dom = view.contentDOM, style = window.getComputedStyle(dom);
let oracle = this.heightOracle;
let whiteSpace = style.whiteSpace;
this.defaultTextDirection = style.direction == "rtl" ? Direction.RTL : Direction.LTR;
let refresh = this.heightOracle.mustRefreshForWrapping(whiteSpace) || this.mustMeasureContent === "refresh";
let domRect = dom.getBoundingClientRect();
let measureContent = refresh || this.mustMeasureContent || this.contentDOMHeight != domRect.height;
this.contentDOMHeight = domRect.height;
this.mustMeasureContent = false;
let result = 0, bias = 0;
if (domRect.width && domRect.height) {
let { scaleX, scaleY } = getScale(dom, domRect);
if (scaleX > 5e-3 && Math.abs(this.scaleX - scaleX) > 5e-3 || scaleY > 5e-3 && Math.abs(this.scaleY - scaleY) > 5e-3) {
this.scaleX = scaleX;
this.scaleY = scaleY;
result |= 16;
refresh = measureContent = true;
}
}
let paddingTop = (parseInt(style.paddingTop) || 0) * this.scaleY;
let paddingBottom = (parseInt(style.paddingBottom) || 0) * this.scaleY;
if (this.paddingTop != paddingTop || this.paddingBottom != paddingBottom) {
this.paddingTop = paddingTop;
this.paddingBottom = paddingBottom;
result |= 16 | 2;
}
if (this.editorWidth != view.scrollDOM.clientWidth) {
if (oracle.lineWrapping)
measureContent = true;
this.editorWidth = view.scrollDOM.clientWidth;
result |= 16;
}
let scrollParent = scrollableParents(this.view.contentDOM, false).y;
if (scrollParent != this.scrollParent) {
this.scrollParent = scrollParent;
this.scrollAnchorHeight = -1;
this.scrollOffset = 0;
}
let scrollOffset = this.getScrollOffset();
if (this.scrollOffset != scrollOffset) {
this.scrollAnchorHeight = -1;
this.scrollOffset = scrollOffset;
}
this.scrolledToBottom = isScrolledToBottom(this.scrollParent || view.win);
let pixelViewport = (this.printing ? fullPixelRange : visiblePixelRange)(dom, this.paddingTop);
let dTop = pixelViewport.top - this.pixelViewport.top, dBottom = pixelViewport.bottom - this.pixelViewport.bottom;
this.pixelViewport = pixelViewport;
let inView = this.pixelViewport.bottom > this.pixelViewport.top && this.pixelViewport.right > this.pixelViewport.left;
if (inView != this.inView) {
this.inView = inView;
if (inView)
measureContent = true;
}
if (!this.inView && !this.scrollTarget && !inWindow(view.dom))
return 0;
let contentWidth = domRect.width;
if (this.contentDOMWidth != contentWidth || this.editorHeight != view.scrollDOM.clientHeight) {
this.contentDOMWidth = domRect.width;
this.editorHeight = view.scrollDOM.clientHeight;
result |= 16;
}
if (measureContent) {
let lineHeights = view.docView.measureVisibleLineHeights(this.viewport);
if (oracle.mustRefreshForHeights(lineHeights))
refresh = true;
if (refresh || oracle.lineWrapping && Math.abs(contentWidth - this.contentDOMWidth) > oracle.charWidth) {
let { lineHeight, charWidth, textHeight } = view.docView.measureTextSize();
refresh = lineHeight > 0 && oracle.refresh(whiteSpace, lineHeight, charWidth, textHeight, Math.max(5, contentWidth / charWidth), lineHeights);
if (refresh) {
view.docView.minWidth = 0;
result |= 16;
}
}
if (dTop > 0 && dBottom > 0)
bias = Math.max(dTop, dBottom);
else if (dTop < 0 && dBottom < 0)
bias = Math.min(dTop, dBottom);
clearHeightChangeFlag();
for (let vp of this.viewports) {
let heights = vp.from == this.viewport.from ? lineHeights : view.docView.measureVisibleLineHeights(vp);
this.heightMap = (refresh ? HeightMap.empty().applyChanges(this.stateDeco, Text.empty, this.heightOracle, [new ChangedRange(0, 0, 0, view.state.doc.length)]) : this.heightMap).updateHeight(oracle, 0, refresh, new MeasuredHeights(vp.from, heights));
}
if (heightChangeFlag)
result |= 2;
}
let viewportChange = !this.viewportIsAppropriate(this.viewport, bias) || this.scrollTarget && (this.scrollTarget.range.head < this.viewport.from || this.scrollTarget.range.head > this.viewport.to);
if (viewportChange) {
if (result & 2)
result |= this.updateScaler();
this.viewport = this.getViewport(bias, this.scrollTarget);
result |= this.updateForViewport();
}
if (result & 2 || viewportChange)
this.updateViewportLines();
if (this.lineGaps.length || this.viewport.to - this.viewport.from > 2e3 << 1)
this.updateLineGaps(this.ensureLineGaps(refresh ? [] : this.lineGaps, view));
result |= this.computeVisibleRanges();
if (this.mustEnforceCursorAssoc) {
this.mustEnforceCursorAssoc = false;
view.docView.enforceCursorAssoc();
}
return result;
}
get visibleTop() {
return this.scaler.fromDOM(this.pixelViewport.top);
}
get visibleBottom() {
return this.scaler.fromDOM(this.pixelViewport.bottom);
}
getViewport(bias, scrollTarget) {
let marginTop = 0.5 - Math.max(-0.5, Math.min(0.5, bias / 1e3 / 2));
let map = this.heightMap, oracle = this.heightOracle;
let { visibleTop, visibleBottom } = this;
let viewport = new Viewport(map.lineAt(visibleTop - marginTop * 1e3, QueryType.ByHeight, oracle, 0, 0).from, map.lineAt(visibleBottom + (1 - marginTop) * 1e3, QueryType.ByHeight, oracle, 0, 0).to);
if (scrollTarget) {
let { head } = scrollTarget.range;
if (head < viewport.from || head > viewport.to) {
let viewHeight = Math.min(this.editorHeight, this.pixelViewport.bottom - this.pixelViewport.top);
let block = map.lineAt(head, QueryType.ByPos, oracle, 0, 0), topPos;
if (scrollTarget.y == "center")
topPos = (block.top + block.bottom) / 2 - viewHeight / 2;
else if (scrollTarget.y == "start" || scrollTarget.y == "nearest" && head < viewport.from)
topPos = block.top;
else
topPos = block.bottom - viewHeight;
viewport = new Viewport(map.lineAt(topPos - 1e3 / 2, QueryType.ByHeight, oracle, 0, 0).from, map.lineAt(topPos + viewHeight + 1e3 / 2, QueryType.ByHeight, oracle, 0, 0).to);
}
}
return viewport;
}
mapViewport(viewport, changes) {
let from = changes.mapPos(viewport.from, -1), to = changes.mapPos(viewport.to, 1);
return new Viewport(this.heightMap.lineAt(from, QueryType.ByPos, this.heightOracle, 0, 0).from, this.heightMap.lineAt(to, QueryType.ByPos, this.heightOracle, 0, 0).to);
}
// Checks if a given viewport covers the visible part of the
// document and not too much beyond that.
viewportIsAppropriate({ from, to }, bias = 0) {
if (!this.inView)
return true;
let { top: top2 } = this.heightMap.lineAt(from, QueryType.ByPos, this.heightOracle, 0, 0);
let { bottom } = this.heightMap.lineAt(to, QueryType.ByPos, this.heightOracle, 0, 0);
let { visibleTop, visibleBottom } = this;
return (from == 0 || top2 <= visibleTop - Math.max(10, Math.min(
-bias,
250
/* VP.MaxCoverMargin */
))) && (to == this.state.doc.length || bottom >= visibleBottom + Math.max(10, Math.min(
bias,
250
/* VP.MaxCoverMargin */
))) && (top2 > visibleTop - 2 * 1e3 && bottom < visibleBottom + 2 * 1e3);
}
mapLineGaps(gaps, changes) {
if (!gaps.length || changes.empty)
return gaps;
let mapped = [];
for (let gap of gaps)
if (!changes.touchesRange(gap.from, gap.to))
mapped.push(new LineGap(changes.mapPos(gap.from), changes.mapPos(gap.to), gap.size, gap.displaySize));
return mapped;
}
// Computes positions in the viewport where the start or end of a
// line should be hidden, trying to reuse existing line gaps when
// appropriate to avoid unneccesary redraws.
// Uses crude character-counting for the positioning and sizing,
// since actual DOM coordinates aren't always available and
// predictable. Relies on generous margins (see LG.Margin) to hide
// the artifacts this might produce from the user.
ensureLineGaps(current, mayMeasure) {
let wrapping = this.heightOracle.lineWrapping;
let margin = wrapping ? 1e4 : 2e3, halfMargin = margin >> 1, doubleMargin = margin << 1;
if (this.defaultTextDirection != Direction.LTR && !wrapping)
return [];
let gaps = [];
let addGap = (from, to, line, structure) => {
if (to - from < halfMargin)
return;
let sel = this.state.selection.main, avoid = [sel.from];
if (!sel.empty)
avoid.push(sel.to);
for (let pos of avoid) {
if (pos > from && pos < to) {
addGap(from, pos - 10, line, structure);
addGap(pos + 10, to, line, structure);
return;
}
}
let gap = find(current, (gap2) => gap2.from >= line.from && gap2.to <= line.to && Math.abs(gap2.from - from) < halfMargin && Math.abs(gap2.to - to) < halfMargin && !avoid.some((pos) => gap2.from < pos && gap2.to > pos));
if (!gap) {
if (to < line.to && mayMeasure && wrapping && mayMeasure.visibleRanges.some((r) => r.from <= to && r.to >= to)) {
let lineStart = mayMeasure.moveToLineBoundary(EditorSelection.cursor(to), false, true).head;
if (lineStart > from)
to = lineStart;
}
let size = this.gapSize(line, from, to, structure);
let displaySize = wrapping || size < 2e6 ? size : 2e6;
gap = new LineGap(from, to, size, displaySize);
}
gaps.push(gap);
};
let checkLine = (line) => {
if (line.length < doubleMargin || line.type != BlockType.Text)
return;
let structure = lineStructure(line.from, line.to, this.stateDeco);
if (structure.total < doubleMargin)
return;
let target = this.scrollTarget ? this.scrollTarget.range.head : null;
let viewFrom, viewTo;
if (wrapping) {
let marginHeight = margin / this.heightOracle.lineLength * this.heightOracle.lineHeight;
let top2, bot;
if (target != null) {
let targetFrac = findFraction(structure, target);
let spaceFrac = ((this.visibleBottom - this.visibleTop) / 2 + marginHeight) / line.height;
top2 = targetFrac - spaceFrac;
bot = targetFrac + spaceFrac;
} else {
top2 = (this.visibleTop - line.top - marginHeight) / line.height;
bot = (this.visibleBottom - line.top + marginHeight) / line.height;
}
viewFrom = findPosition(structure, top2);
viewTo = findPosition(structure, bot);
} else {
let totalWidth = structure.total * this.heightOracle.charWidth;
let marginWidth = margin * this.heightOracle.charWidth;
let horizOffset = 0;
if (totalWidth > 2e6)
for (let old of current) {
if (old.from >= line.from && old.from < line.to && old.size != old.displaySize && old.from * this.heightOracle.charWidth + horizOffset < this.pixelViewport.left)
horizOffset = old.size - old.displaySize;
}
let pxLeft = this.pixelViewport.left + horizOffset, pxRight = this.pixelViewport.right + horizOffset;
let left, right;
if (target != null) {
let targetFrac = findFraction(structure, target);
let spaceFrac = ((pxRight - pxLeft) / 2 + marginWidth) / totalWidth;
left = targetFrac - spaceFrac;
right = targetFrac + spaceFrac;
} else {
left = (pxLeft - marginWidth) / totalWidth;
right = (pxRight + marginWidth) / totalWidth;
}
viewFrom = findPosition(structure, left);
viewTo = findPosition(structure, right);
}
if (viewFrom > line.from)
addGap(line.from, viewFrom, line, structure);
if (viewTo < line.to)
addGap(viewTo, line.to, line, structure);
};
for (let line of this.viewportLines) {
if (Array.isArray(line.type))
line.type.forEach(checkLine);
else
checkLine(line);
}
return gaps;
}
gapSize(line, from, to, structure) {
let fraction = findFraction(structure, to) - findFraction(structure, from);
if (this.heightOracle.lineWrapping) {
return line.height * fraction;
} else {
return structure.total * this.heightOracle.charWidth * fraction;
}
}
updateLineGaps(gaps) {
if (!LineGap.same(gaps, this.lineGaps)) {
this.lineGaps = gaps;
this.lineGapDeco = Decoration.set(gaps.map((gap) => gap.draw(this, this.heightOracle.lineWrapping)));
}
}
computeVisibleRanges(changes) {
let deco = this.stateDeco;
if (this.lineGaps.length)
deco = deco.concat(this.lineGapDeco);
let ranges = [];
RangeSet.spans(deco, this.viewport.from, this.viewport.to, {
span(from, to) {
ranges.push({ from, to });
},
point() {
}
}, 20);
let changed = 0;
if (ranges.length != this.visibleRanges.length) {
changed = 8 | 4;
} else {
for (let i = 0; i < ranges.length && !(changed & 8); i++) {
let old = this.visibleRanges[i], nw = ranges[i];
if (old.from != nw.from || old.to != nw.to) {
changed |= 4;
if (!(changes && changes.mapPos(old.from, -1) == nw.from && changes.mapPos(old.to, 1) == nw.to))
changed |= 8;
}
}
}
this.visibleRanges = ranges;
return changed;
}
lineBlockAt(pos) {
return pos >= this.viewport.from && pos <= this.viewport.to && this.viewportLines.find((b) => b.from <= pos && b.to >= pos) || scaleBlock(this.heightMap.lineAt(pos, QueryType.ByPos, this.heightOracle, 0, 0), this.scaler);
}
lineBlockAtHeight(height) {
return height >= this.viewportLines[0].top && height <= this.viewportLines[this.viewportLines.length - 1].bottom && this.viewportLines.find((l) => l.top <= height && l.bottom >= height) || scaleBlock(this.heightMap.lineAt(this.scaler.fromDOM(height), QueryType.ByHeight, this.heightOracle, 0, 0), this.scaler);
}
getScrollOffset() {
let base2 = this.scrollParent == this.view.scrollDOM ? this.scrollParent.scrollTop : (this.scrollParent ? this.scrollParent.getBoundingClientRect().top : 0) - this.view.contentDOM.getBoundingClientRect().top;
return base2 * this.scaleY;
}
scrollAnchorAt(scrollOffset) {
let block = this.lineBlockAtHeight(scrollOffset + 8);
return block.from >= this.viewport.from || this.viewportLines[0].top - scrollOffset > 200 ? block : this.viewportLines[0];
}
elementAtHeight(height) {
return scaleBlock(this.heightMap.blockAt(this.scaler.fromDOM(height), this.heightOracle, 0, 0), this.scaler);
}
get docHeight() {
return this.scaler.toDOM(this.heightMap.height);
}
get contentHeight() {
return this.docHeight + this.paddingTop + this.paddingBottom;
}
};
var Viewport = class {
constructor(from, to) {
this.from = from;
this.to = to;
}
};
function lineStructure(from, to, stateDeco) {
let ranges = [], pos = from, total = 0;
RangeSet.spans(stateDeco, from, to, {
span() {
},
point(from2, to2) {
if (from2 > pos) {
ranges.push({ from: pos, to: from2 });
total += from2 - pos;
}
pos = to2;
}
}, 20);
if (pos < to) {
ranges.push({ from: pos, to });
total += to - pos;
}
return { total, ranges };
}
function findPosition({ total, ranges }, ratio) {
if (ratio <= 0)
return ranges[0].from;
if (ratio >= 1)
return ranges[ranges.length - 1].to;
let dist2 = Math.floor(total * ratio);
for (let i = 0; ; i++) {
let { from, to } = ranges[i], size = to - from;
if (dist2 <= size)
return from + dist2;
dist2 -= size;
}
}
function findFraction(structure, pos) {
let counted = 0;
for (let { from, to } of structure.ranges) {
if (pos <= to) {
counted += pos - from;
break;
}
counted += to - from;
}
return counted / structure.total;
}
function find(array, f) {
for (let val of array)
if (f(val))
return val;
return void 0;
}
var IdScaler = {
toDOM(n) {
return n;
},
fromDOM(n) {
return n;
},
scale: 1,
eq(other) {
return other == this;
}
};
function staticDeco(state) {
let deco = state.facet(decorations).filter((d) => typeof d != "function");
let outer = state.facet(outerDecorations).filter((d) => typeof d != "function");
if (outer.length)
deco.push(RangeSet.join(outer));
return deco;
}
var BigScaler = class _BigScaler {
constructor(oracle, heightMap, viewports) {
let vpHeight = 0, base2 = 0, domBase = 0;
this.viewports = viewports.map(({ from, to }) => {
let top2 = heightMap.lineAt(from, QueryType.ByPos, oracle, 0, 0).top;
let bottom = heightMap.lineAt(to, QueryType.ByPos, oracle, 0, 0).bottom;
vpHeight += bottom - top2;
return { from, to, top: top2, bottom, domTop: 0, domBottom: 0 };
});
this.scale = (7e6 - vpHeight) / (heightMap.height - vpHeight);
for (let obj of this.viewports) {
obj.domTop = domBase + (obj.top - base2) * this.scale;
domBase = obj.domBottom = obj.domTop + (obj.bottom - obj.top);
base2 = obj.bottom;
}
}
toDOM(n) {
for (let i = 0, base2 = 0, domBase = 0; ; i++) {
let vp = i < this.viewports.length ? this.viewports[i] : null;
if (!vp || n < vp.top)
return domBase + (n - base2) * this.scale;
if (n <= vp.bottom)
return vp.domTop + (n - vp.top);
base2 = vp.bottom;
domBase = vp.domBottom;
}
}
fromDOM(n) {
for (let i = 0, base2 = 0, domBase = 0; ; i++) {
let vp = i < this.viewports.length ? this.viewports[i] : null;
if (!vp || n < vp.domTop)
return base2 + (n - domBase) / this.scale;
if (n <= vp.domBottom)
return vp.top + (n - vp.domTop);
base2 = vp.bottom;
domBase = vp.domBottom;
}
}
eq(other) {
if (!(other instanceof _BigScaler))
return false;
return this.scale == other.scale && this.viewports.length == other.viewports.length && this.viewports.every((vp, i) => vp.from == other.viewports[i].from && vp.to == other.viewports[i].to);
}
};
function scaleBlock(block, scaler) {
if (scaler.scale == 1)
return block;
let bTop = scaler.toDOM(block.top), bBottom = scaler.toDOM(block.bottom);
return new BlockInfo(block.from, block.length, bTop, bBottom - bTop, Array.isArray(block._content) ? block._content.map((b) => scaleBlock(b, scaler)) : block._content);
}
var theme = Facet.define({ combine: (strs) => strs.join(" ") });
var darkTheme = Facet.define({ combine: (values) => values.indexOf(true) > -1 });
var baseThemeID = StyleModule.newName();
var baseLightID = StyleModule.newName();
var baseDarkID = StyleModule.newName();
var lightDarkIDs = { "&light": "." + baseLightID, "&dark": "." + baseDarkID };
function buildTheme(main, spec, scopes) {
return new StyleModule(spec, {
finish(sel) {
return /&/.test(sel) ? sel.replace(/&\w*/, (m) => {
if (m == "&")
return main;
if (!scopes || !scopes[m])
throw new RangeError(`Unsupported selector: ${m}`);
return scopes[m];
}) : main + " " + sel;
}
});
}
var baseTheme$1 = buildTheme("." + baseThemeID, {
"&": {
position: "relative !important",
boxSizing: "border-box",
"&.cm-focused": {
// Provide a simple default outline to make sure a focused
// editor is visually distinct. Can't leave the default behavior
// because that will apply to the content element, which is
// inside the scrollable container and doesn't include the
// gutters. We also can't use an 'auto' outline, since those
// are, for some reason, drawn behind the element content, which
// will cause things like the active line background to cover
// the outline (#297).
outline: "1px dotted #212121"
},
display: "flex !important",
flexDirection: "column"
},
".cm-scroller": {
display: "flex !important",
alignItems: "flex-start !important",
fontFamily: "monospace",
lineHeight: 1.4,
height: "100%",
overflowX: "auto",
position: "relative",
zIndex: 0,
overflowAnchor: "none"
},
".cm-content": {
margin: 0,
flexGrow: 2,
flexShrink: 0,
display: "block",
whiteSpace: "pre",
wordWrap: "normal",
// Issue #456
boxSizing: "border-box",
minHeight: "100%",
padding: "4px 0",
outline: "none",
"&[contenteditable=true]": {
WebkitUserModify: "read-write-plaintext-only"
}
},
".cm-lineWrapping": {
whiteSpace_fallback: "pre-wrap",
// For IE
whiteSpace: "break-spaces",
wordBreak: "break-word",
// For Safari, which doesn't support overflow-wrap: anywhere
overflowWrap: "anywhere",
flexShrink: 1
},
"&light .cm-content": { caretColor: "black" },
"&dark .cm-content": { caretColor: "white" },
".cm-line": {
display: "block",
padding: "0 2px 0 6px"
},
".cm-layer": {
position: "absolute",
left: 0,
top: 0,
contain: "size style",
"& > *": {
position: "absolute"
}
},
"&light .cm-selectionBackground": {
background: "#d9d9d9"
},
"&dark .cm-selectionBackground": {
background: "#222"
},
"&light.cm-focused > .cm-scroller > .cm-selectionLayer .cm-selectionBackground": {
background: "#d7d4f0"
},
"&dark.cm-focused > .cm-scroller > .cm-selectionLayer .cm-selectionBackground": {
background: "#233"
},
".cm-cursorLayer": {
pointerEvents: "none"
},
"&.cm-focused > .cm-scroller > .cm-cursorLayer": {
animation: "steps(1) cm-blink 1.2s infinite"
},
// Two animations defined so that we can switch between them to
// restart the animation without forcing another style
// recomputation.
"@keyframes cm-blink": { "0%": {}, "50%": { opacity: 0 }, "100%": {} },
"@keyframes cm-blink2": { "0%": {}, "50%": { opacity: 0 }, "100%": {} },
".cm-cursor, .cm-dropCursor": {
borderLeft: "1.2px solid black",
marginLeft: "-0.6px",
pointerEvents: "none"
},
".cm-cursor": {
display: "none"
},
"&dark .cm-cursor": {
borderLeftColor: "#ddd"
},
".cm-selectionHandle": {
backgroundColor: "currentColor",
width: "1.5px"
},
".cm-selectionHandle-start::before, .cm-selectionHandle-end::before": {
content: '""',
backgroundColor: "inherit",
borderRadius: "50%",
width: "8px",
height: "8px",
position: "absolute",
left: "-3.25px"
},
".cm-selectionHandle-start::before": { top: "-8px" },
".cm-selectionHandle-end::before": { bottom: "-8px" },
".cm-dropCursor": {
position: "absolute"
},
"&.cm-focused > .cm-scroller > .cm-cursorLayer .cm-cursor": {
display: "block"
},
".cm-iso": {
unicodeBidi: "isolate"
},
".cm-announced": {
position: "fixed",
top: "-10000px"
},
"@media print": {
".cm-announced": { display: "none" }
},
"&light .cm-activeLine": { backgroundColor: "#cceeff44" },
"&dark .cm-activeLine": { backgroundColor: "#99eeff33" },
"&light .cm-specialChar": { color: "red" },
"&dark .cm-specialChar": { color: "#f78" },
".cm-gutters": {
flexShrink: 0,
display: "flex",
height: "100%",
boxSizing: "border-box",
zIndex: 200
},
".cm-gutters-before": { insetInlineStart: 0 },
".cm-gutters-after": { insetInlineEnd: 0 },
"&light .cm-gutters": {
backgroundColor: "#f5f5f5",
color: "#6c6c6c",
border: "0px solid #ddd",
"&.cm-gutters-before": { borderRightWidth: "1px" },
"&.cm-gutters-after": { borderLeftWidth: "1px" }
},
"&dark .cm-gutters": {
backgroundColor: "#333338",
color: "#ccc"
},
".cm-gutter": {
display: "flex !important",
// Necessary -- prevents margin collapsing
flexDirection: "column",
flexShrink: 0,
boxSizing: "border-box",
minHeight: "100%",
overflow: "hidden"
},
".cm-gutterElement": {
boxSizing: "border-box"
},
".cm-lineNumbers .cm-gutterElement": {
padding: "0 3px 0 5px",
minWidth: "20px",
textAlign: "right",
whiteSpace: "nowrap"
},
"&light .cm-activeLineGutter": {
backgroundColor: "#e2f2ff"
},
"&dark .cm-activeLineGutter": {
backgroundColor: "#222227"
},
".cm-panels": {
boxSizing: "border-box",
position: "sticky",
left: 0,
right: 0,
zIndex: 300
},
"&light .cm-panels": {
backgroundColor: "#f5f5f5",
color: "black"
},
"&light .cm-panels-top": {
borderBottom: "1px solid #ddd"
},
"&light .cm-panels-bottom": {
borderTop: "1px solid #ddd"
},
"&dark .cm-panels": {
backgroundColor: "#333338",
color: "white"
},
".cm-dialog": {
padding: "2px 19px 4px 6px",
position: "relative",
"& label": { fontSize: "80%" }
},
".cm-dialog-close": {
position: "absolute",
top: "3px",
right: "4px",
backgroundColor: "inherit",
border: "none",
font: "inherit",
fontSize: "14px",
padding: "0"
},
".cm-tab": {
display: "inline-block",
overflow: "hidden",
verticalAlign: "bottom"
},
".cm-widgetBuffer": {
verticalAlign: "text-top",
height: "1em",
width: 0,
display: "inline"
},
".cm-placeholder": {
color: "#888",
display: "inline-block",
verticalAlign: "top",
userSelect: "none"
},
".cm-highlightSpace": {
backgroundImage: "radial-gradient(circle at 50% 55%, #aaa 20%, transparent 5%)",
backgroundPosition: "center"
},
".cm-highlightTab": {
backgroundImage: `url('data:image/svg+xml,<svg xmlns="http://www.w3.org/2000/svg" width="200" height="20"><path stroke="%23888" stroke-width="1" fill="none" d="M1 10H196L190 5M190 15L196 10M197 4L197 16"/></svg>')`,
backgroundSize: "auto 100%",
backgroundPosition: "right 90%",
backgroundRepeat: "no-repeat"
},
".cm-trailingSpace": {
backgroundColor: "#ff332255"
},
".cm-button": {
verticalAlign: "middle",
color: "inherit",
fontSize: "70%",
padding: ".2em 1em",
borderRadius: "1px"
},
"&light .cm-button": {
backgroundImage: "linear-gradient(#eff1f5, #d9d9df)",
border: "1px solid #888",
"&:active": {
backgroundImage: "linear-gradient(#b4b4b4, #d0d3d6)"
}
},
"&dark .cm-button": {
backgroundImage: "linear-gradient(#393939, #111)",
border: "1px solid #888",
"&:active": {
backgroundImage: "linear-gradient(#111, #333)"
}
},
".cm-textfield": {
verticalAlign: "middle",
color: "inherit",
fontSize: "70%",
border: "1px solid silver",
padding: ".2em .5em"
},
"&light .cm-textfield": {
backgroundColor: "white"
},
"&dark .cm-textfield": {
border: "1px solid #555",
backgroundColor: "inherit"
}
}, lightDarkIDs);
var observeOptions = {
childList: true,
characterData: true,
subtree: true,
attributes: true,
characterDataOldValue: true
};
var useCharData = browser.ie && browser.ie_version <= 11;
var DOMObserver = class {
constructor(view) {
this.view = view;
this.active = false;
this.editContext = null;
this.selectionRange = new DOMSelectionState();
this.selectionChanged = false;
this.delayedFlush = -1;
this.resizeTimeout = -1;
this.queue = [];
this.delayedAndroidKey = null;
this.flushingAndroidKey = -1;
this.lastChange = 0;
this.scrollTargets = [];
this.intersection = null;
this.resizeScroll = null;
this.intersecting = false;
this.gapIntersection = null;
this.gaps = [];
this.printQuery = null;
this.parentCheck = -1;
this.dom = view.contentDOM;
this.observer = new MutationObserver((mutations) => {
for (let mut of mutations)
this.queue.push(mut);
if ((browser.ie && browser.ie_version <= 11 || browser.ios && view.composing) && mutations.some((m) => m.type == "childList" && m.removedNodes.length || m.type == "characterData" && m.oldValue.length > m.target.nodeValue.length))
this.flushSoon();
else
this.flush();
});
if (window.EditContext && browser.android && view.constructor.EDIT_CONTEXT !== false && // Chrome <126 doesn't support inverted selections in edit context (#1392)
!(browser.chrome && browser.chrome_version < 126)) {
this.editContext = new EditContextManager(view);
if (view.state.facet(editable))
view.contentDOM.editContext = this.editContext.editContext;
}
if (useCharData)
this.onCharData = (event) => {
this.queue.push({
target: event.target,
type: "characterData",
oldValue: event.prevValue
});
this.flushSoon();
};
this.onSelectionChange = this.onSelectionChange.bind(this);
this.onResize = this.onResize.bind(this);
this.onPrint = this.onPrint.bind(this);
this.onScroll = this.onScroll.bind(this);
if (window.matchMedia)
this.printQuery = window.matchMedia("print");
if (typeof ResizeObserver == "function") {
this.resizeScroll = new ResizeObserver(() => {
var _a;
if (((_a = this.view.docView) === null || _a === void 0 ? void 0 : _a.lastUpdate) < Date.now() - 75)
this.onResize();
});
this.resizeScroll.observe(view.scrollDOM);
}
this.addWindowListeners(this.win = view.win);
this.start();
if (typeof IntersectionObserver == "function") {
this.intersection = new IntersectionObserver((entries) => {
if (this.parentCheck < 0)
this.parentCheck = setTimeout(this.listenForScroll.bind(this), 1e3);
if (entries.length > 0 && entries[entries.length - 1].intersectionRatio > 0 != this.intersecting) {
this.intersecting = !this.intersecting;
if (this.intersecting != this.view.inView)
this.onScrollChanged(document.createEvent("Event"));
}
}, { threshold: [0, 1e-3] });
this.intersection.observe(this.dom);
this.gapIntersection = new IntersectionObserver((entries) => {
if (entries.length > 0 && entries[entries.length - 1].intersectionRatio > 0)
this.onScrollChanged(document.createEvent("Event"));
}, {});
}
this.listenForScroll();
this.readSelectionRange();
}
onScrollChanged(e) {
this.view.inputState.runHandlers("scroll", e);
if (this.intersecting)
this.view.measure();
}
onScroll(e) {
if (this.intersecting)
this.flush(false);
if (this.editContext)
this.view.requestMeasure(this.editContext.measureReq);
this.onScrollChanged(e);
}
onResize() {
if (this.resizeTimeout < 0)
this.resizeTimeout = setTimeout(() => {
this.resizeTimeout = -1;
this.view.requestMeasure();
}, 50);
}
onPrint(event) {
if ((event.type == "change" || !event.type) && !event.matches)
return;
this.view.viewState.printing = true;
this.view.measure();
setTimeout(() => {
this.view.viewState.printing = false;
this.view.requestMeasure();
}, 500);
}
updateGaps(gaps) {
if (this.gapIntersection && (gaps.length != this.gaps.length || this.gaps.some((g, i) => g != gaps[i]))) {
this.gapIntersection.disconnect();
for (let gap of gaps)
this.gapIntersection.observe(gap);
this.gaps = gaps;
}
}
onSelectionChange(event) {
let wasChanged = this.selectionChanged;
if (!this.readSelectionRange() || this.delayedAndroidKey)
return;
let { view } = this, sel = this.selectionRange;
if (view.state.facet(editable) ? view.root.activeElement != this.dom : !hasSelection(this.dom, sel))
return;
let context = sel.anchorNode && view.docView.tile.nearest(sel.anchorNode);
if (context && context.isWidget() && context.widget.ignoreEvent(event)) {
if (!wasChanged)
this.selectionChanged = false;
return;
}
if ((browser.ie && browser.ie_version <= 11 || browser.android && browser.chrome) && !view.state.selection.main.empty && // (Selection.isCollapsed isn't reliable on IE)
sel.focusNode && isEquivalentPosition(sel.focusNode, sel.focusOffset, sel.anchorNode, sel.anchorOffset))
this.flushSoon();
else
this.flush(false);
}
readSelectionRange() {
let { view } = this;
let selection = getSelection(view.root);
if (!selection)
return false;
let range = browser.safari && view.root.nodeType == 11 && view.root.activeElement == this.dom && safariSelectionRangeHack(this.view, selection) || selection;
if (!range || this.selectionRange.eq(range))
return false;
let local = hasSelection(this.dom, range);
if (local && !this.selectionChanged && view.inputState.lastFocusTime > Date.now() - 200 && view.inputState.lastTouchTime < Date.now() - 300 && atElementStart(this.dom, range)) {
this.view.inputState.lastFocusTime = 0;
view.docView.updateSelection();
return false;
}
this.selectionRange.setRange(range);
if (local)
this.selectionChanged = true;
return true;
}
setSelectionRange(anchor, head) {
this.selectionRange.set(anchor.node, anchor.offset, head.node, head.offset);
this.selectionChanged = false;
}
clearSelectionRange() {
this.selectionRange.set(null, 0, null, 0);
}
listenForScroll() {
this.parentCheck = -1;
let i = 0, changed = null;
for (let dom = this.dom; dom; ) {
if (dom.nodeType == 1) {
if (!changed && i < this.scrollTargets.length && this.scrollTargets[i] == dom)
i++;
else if (!changed)
changed = this.scrollTargets.slice(0, i);
if (changed)
changed.push(dom);
dom = dom.assignedSlot || dom.parentNode;
} else if (dom.nodeType == 11) {
dom = dom.host;
} else {
break;
}
}
if (i < this.scrollTargets.length && !changed)
changed = this.scrollTargets.slice(0, i);
if (changed) {
for (let dom of this.scrollTargets)
dom.removeEventListener("scroll", this.onScroll);
for (let dom of this.scrollTargets = changed)
dom.addEventListener("scroll", this.onScroll);
}
}
ignore(f) {
if (!this.active)
return f();
try {
this.stop();
return f();
} finally {
this.start();
this.clear();
}
}
start() {
if (this.active)
return;
this.observer.observe(this.dom, observeOptions);
if (useCharData)
this.dom.addEventListener("DOMCharacterDataModified", this.onCharData);
this.active = true;
}
stop() {
if (!this.active)
return;
this.active = false;
this.observer.disconnect();
if (useCharData)
this.dom.removeEventListener("DOMCharacterDataModified", this.onCharData);
}
// Throw away any pending changes
clear() {
this.processRecords();
this.queue.length = 0;
this.selectionChanged = false;
}
// Chrome Android, especially in combination with GBoard, not only
// doesn't reliably fire regular key events, but also often
// surrounds the effect of enter or backspace with a bunch of
// composition events that, when interrupted, cause text duplication
// or other kinds of corruption. This hack makes the editor back off
// from handling DOM changes for a moment when such a key is
// detected (via beforeinput or keydown), and then tries to flush
// them or, if that has no effect, dispatches the given key.
delayAndroidKey(key, keyCode) {
var _a;
if (!this.delayedAndroidKey) {
let flush = () => {
let key2 = this.delayedAndroidKey;
if (key2) {
this.clearDelayedAndroidKey();
this.view.inputState.lastKeyCode = key2.keyCode;
this.view.inputState.lastKeyTime = Date.now();
let flushed = this.flush();
if (!flushed && key2.force)
dispatchKey(this.dom, key2.key, key2.keyCode);
}
};
this.flushingAndroidKey = this.view.win.requestAnimationFrame(flush);
}
if (!this.delayedAndroidKey || key == "Enter")
this.delayedAndroidKey = {
key,
keyCode,
// Only run the key handler when no changes are detected if
// this isn't coming right after another change, in which case
// it is probably part of a weird chain of updates, and should
// be ignored if it returns the DOM to its previous state.
force: this.lastChange < Date.now() - 50 || !!((_a = this.delayedAndroidKey) === null || _a === void 0 ? void 0 : _a.force)
};
}
clearDelayedAndroidKey() {
this.win.cancelAnimationFrame(this.flushingAndroidKey);
this.delayedAndroidKey = null;
this.flushingAndroidKey = -1;
}
flushSoon() {
if (this.delayedFlush < 0)
this.delayedFlush = this.view.win.requestAnimationFrame(() => {
this.delayedFlush = -1;
this.flush();
});
}
forceFlush() {
if (this.delayedFlush >= 0) {
this.view.win.cancelAnimationFrame(this.delayedFlush);
this.delayedFlush = -1;
}
this.flush();
}
pendingRecords() {
for (let mut of this.observer.takeRecords())
this.queue.push(mut);
return this.queue;
}
processRecords() {
let records = this.pendingRecords();
if (records.length)
this.queue = [];
let from = -1, to = -1, typeOver = false;
for (let record of records) {
let range = this.readMutation(record);
if (!range)
continue;
if (range.typeOver)
typeOver = true;
if (from == -1) {
({ from, to } = range);
} else {
from = Math.min(range.from, from);
to = Math.max(range.to, to);
}
}
return { from, to, typeOver };
}
readChange() {
let { from, to, typeOver } = this.processRecords();
let newSel = this.selectionChanged && hasSelection(this.dom, this.selectionRange);
if (from < 0 && !newSel)
return null;
if (from > -1)
this.lastChange = Date.now();
this.view.inputState.lastFocusTime = 0;
this.selectionChanged = false;
let change = new DOMChange(this.view, from, to, typeOver);
this.view.docView.domChanged = { newSel: change.newSel ? change.newSel.main : null };
return change;
}
// Apply pending changes, if any
flush(readSelection = true) {
if (this.delayedFlush >= 0 || this.delayedAndroidKey)
return false;
if (readSelection)
this.readSelectionRange();
let domChange = this.readChange();
if (!domChange) {
this.view.requestMeasure();
return false;
}
let startState = this.view.state;
let handled = applyDOMChange(this.view, domChange);
if (this.view.state == startState && (domChange.domChanged || domChange.newSel && !sameSelPos(this.view.state.selection, domChange.newSel.main)))
this.view.update([]);
return handled;
}
readMutation(rec) {
let tile = this.view.docView.tile.nearest(rec.target);
if (!tile || tile.isWidget())
return null;
tile.markDirty(rec.type == "attributes");
if (rec.type == "childList") {
let childBefore = findChild(tile, rec.previousSibling || rec.target.previousSibling, -1);
let childAfter = findChild(tile, rec.nextSibling || rec.target.nextSibling, 1);
return {
from: childBefore ? tile.posAfter(childBefore) : tile.posAtStart,
to: childAfter ? tile.posBefore(childAfter) : tile.posAtEnd,
typeOver: false
};
} else if (rec.type == "characterData") {
return { from: tile.posAtStart, to: tile.posAtEnd, typeOver: rec.target.nodeValue == rec.oldValue };
} else {
return null;
}
}
setWindow(win) {
if (win != this.win) {
this.removeWindowListeners(this.win);
this.win = win;
this.addWindowListeners(this.win);
}
}
addWindowListeners(win) {
win.addEventListener("resize", this.onResize);
if (this.printQuery) {
if (this.printQuery.addEventListener)
this.printQuery.addEventListener("change", this.onPrint);
else
this.printQuery.addListener(this.onPrint);
} else
win.addEventListener("beforeprint", this.onPrint);
win.addEventListener("scroll", this.onScroll);
win.document.addEventListener("selectionchange", this.onSelectionChange);
}
removeWindowListeners(win) {
win.removeEventListener("scroll", this.onScroll);
win.removeEventListener("resize", this.onResize);
if (this.printQuery) {
if (this.printQuery.removeEventListener)
this.printQuery.removeEventListener("change", this.onPrint);
else
this.printQuery.removeListener(this.onPrint);
} else
win.removeEventListener("beforeprint", this.onPrint);
win.document.removeEventListener("selectionchange", this.onSelectionChange);
}
update(update) {
if (this.editContext) {
this.editContext.update(update);
if (update.startState.facet(editable) != update.state.facet(editable))
update.view.contentDOM.editContext = update.state.facet(editable) ? this.editContext.editContext : null;
}
}
destroy() {
var _a, _b, _c;
this.stop();
(_a = this.intersection) === null || _a === void 0 ? void 0 : _a.disconnect();
(_b = this.gapIntersection) === null || _b === void 0 ? void 0 : _b.disconnect();
(_c = this.resizeScroll) === null || _c === void 0 ? void 0 : _c.disconnect();
for (let dom of this.scrollTargets)
dom.removeEventListener("scroll", this.onScroll);
this.removeWindowListeners(this.win);
clearTimeout(this.parentCheck);
clearTimeout(this.resizeTimeout);
this.win.cancelAnimationFrame(this.delayedFlush);
this.win.cancelAnimationFrame(this.flushingAndroidKey);
if (this.editContext) {
this.view.contentDOM.editContext = null;
this.editContext.destroy();
}
}
};
function findChild(tile, dom, dir) {
while (dom) {
let curTile = Tile.get(dom);
if (curTile && curTile.parent == tile)
return curTile;
let parent = dom.parentNode;
dom = parent != tile.dom ? parent : dir > 0 ? dom.nextSibling : dom.previousSibling;
}
return null;
}
function buildSelectionRangeFromRange(view, range) {
let anchorNode = range.startContainer, anchorOffset = range.startOffset;
let focusNode = range.endContainer, focusOffset = range.endOffset;
let curAnchor = view.docView.domAtPos(view.state.selection.main.anchor, 1);
if (isEquivalentPosition(curAnchor.node, curAnchor.offset, focusNode, focusOffset))
[anchorNode, anchorOffset, focusNode, focusOffset] = [focusNode, focusOffset, anchorNode, anchorOffset];
return { anchorNode, anchorOffset, focusNode, focusOffset };
}
function safariSelectionRangeHack(view, selection) {
if (selection.getComposedRanges) {
let range = selection.getComposedRanges(view.root)[0];
if (range)
return buildSelectionRangeFromRange(view, range);
}
let found = null;
function read(event) {
event.preventDefault();
event.stopImmediatePropagation();
found = event.getTargetRanges()[0];
}
view.contentDOM.addEventListener("beforeinput", read, true);
view.dom.ownerDocument.execCommand("indent");
view.contentDOM.removeEventListener("beforeinput", read, true);
return found ? buildSelectionRangeFromRange(view, found) : null;
}
var EditContextManager = class {
constructor(view) {
this.from = 0;
this.to = 0;
this.pendingContextChange = null;
this.handlers = /* @__PURE__ */ Object.create(null);
this.composing = null;
this.resetRange(view.state);
let context = this.editContext = new window.EditContext({
text: view.state.doc.sliceString(this.from, this.to),
selectionStart: this.toContextPos(Math.max(this.from, Math.min(this.to, view.state.selection.main.anchor))),
selectionEnd: this.toContextPos(view.state.selection.main.head)
});
this.handlers.textupdate = (e) => {
let main = view.state.selection.main, { anchor, head } = main;
let from = this.toEditorPos(e.updateRangeStart), to = this.toEditorPos(e.updateRangeEnd);
if (view.inputState.composing >= 0 && !this.composing)
this.composing = { contextBase: e.updateRangeStart, editorBase: from, drifted: false };
let deletes = to - from > e.text.length;
if (from == this.from && anchor < this.from)
from = anchor;
else if (to == this.to && anchor > this.to)
to = anchor;
let diff = findDiff(view.state.sliceDoc(from, to), e.text, (deletes ? main.from : main.to) - from, deletes ? "end" : null);
if (!diff) {
let newSel = EditorSelection.single(this.toEditorPos(e.selectionStart), this.toEditorPos(e.selectionEnd));
if (!sameSelPos(newSel, main))
view.dispatch({ selection: newSel, userEvent: "select" });
return;
}
let change = {
from: diff.from + from,
to: diff.toA + from,
insert: Text.of(e.text.slice(diff.from, diff.toB).split("\n"))
};
if ((browser.mac || browser.android) && change.from == head - 1 && /^\. ?$/.test(e.text) && view.contentDOM.getAttribute("autocorrect") == "off")
change = { from, to, insert: Text.of([e.text.replace(".", " ")]) };
this.pendingContextChange = change;
if (!view.state.readOnly) {
let newLen = this.to - this.from + (change.to - change.from + change.insert.length);
applyDOMChangeInner(view, change, EditorSelection.single(this.toEditorPos(e.selectionStart, newLen), this.toEditorPos(e.selectionEnd, newLen)));
}
if (this.pendingContextChange) {
this.revertPending(view.state);
this.setSelection(view.state);
}
if (change.from < change.to && !change.insert.length && view.inputState.composing >= 0 && !/[\\p{Alphabetic}\\p{Number}_]/.test(context.text.slice(Math.max(0, e.updateRangeStart - 1), Math.min(context.text.length, e.updateRangeStart + 1))))
this.handlers.compositionend(e);
};
this.handlers.characterboundsupdate = (e) => {
let rects = [], prev = null;
for (let i = this.toEditorPos(e.rangeStart), end = this.toEditorPos(e.rangeEnd); i < end; i++) {
let rect = view.coordsForChar(i);
prev = rect && new DOMRect(rect.left, rect.top, rect.right - rect.left, rect.bottom - rect.top) || prev || new DOMRect();
rects.push(prev);
}
context.updateCharacterBounds(e.rangeStart, rects);
};
this.handlers.textformatupdate = (e) => {
let deco = [];
for (let format of e.getTextFormats()) {
let lineStyle = format.underlineStyle, thickness = format.underlineThickness;
if (!/none/i.test(lineStyle) && !/none/i.test(thickness)) {
let from = this.toEditorPos(format.rangeStart), to = this.toEditorPos(format.rangeEnd);
if (from < to) {
let style = `text-decoration: underline ${/^[a-z]/.test(lineStyle) ? lineStyle + " " : lineStyle == "Dashed" ? "dashed " : lineStyle == "Squiggle" ? "wavy " : ""}${/thin/i.test(thickness) ? 1 : 2}px`;
deco.push(Decoration.mark({ attributes: { style } }).range(from, to));
}
}
}
view.dispatch({ effects: setEditContextFormatting.of(Decoration.set(deco)) });
};
this.handlers.compositionstart = () => {
if (view.inputState.composing < 0) {
view.inputState.composing = 0;
view.inputState.compositionFirstChange = true;
}
};
this.handlers.compositionend = () => {
view.inputState.composing = -1;
view.inputState.compositionFirstChange = null;
if (this.composing) {
let { drifted } = this.composing;
this.composing = null;
if (drifted)
this.reset(view.state);
}
};
for (let event in this.handlers)
context.addEventListener(event, this.handlers[event]);
this.measureReq = { read: (view2) => {
this.editContext.updateControlBounds(view2.contentDOM.getBoundingClientRect());
let sel = getSelection(view2.root);
if (sel && sel.rangeCount)
this.editContext.updateSelectionBounds(sel.getRangeAt(0).getBoundingClientRect());
} };
}
applyEdits(update) {
let off = 0, abort = false, pending = this.pendingContextChange;
update.changes.iterChanges((fromA, toA, _fromB, _toB, insert) => {
if (abort)
return;
let dLen = insert.length - (toA - fromA);
if (pending && toA >= pending.to) {
if (pending.from == fromA && pending.to == toA && pending.insert.eq(insert)) {
pending = this.pendingContextChange = null;
off += dLen;
this.to += dLen;
return;
} else {
pending = null;
this.revertPending(update.state);
}
}
fromA += off;
toA += off;
if (toA <= this.from) {
this.from += dLen;
this.to += dLen;
} else if (fromA < this.to) {
if (fromA < this.from || toA > this.to || this.to - this.from + insert.length > 3e4) {
abort = true;
return;
}
this.editContext.updateText(this.toContextPos(fromA), this.toContextPos(toA), insert.toString());
this.to += dLen;
}
off += dLen;
});
if (pending && !abort)
this.revertPending(update.state);
return !abort;
}
update(update) {
let reverted = this.pendingContextChange, startSel = update.startState.selection.main;
if (this.composing && (this.composing.drifted || !update.changes.touchesRange(startSel.from, startSel.to) && update.transactions.some((tr) => !tr.isUserEvent("input.type") && tr.changes.touchesRange(this.from, this.to)))) {
this.composing.drifted = true;
this.composing.editorBase = update.changes.mapPos(this.composing.editorBase);
} else if (!this.applyEdits(update) || !this.rangeIsValid(update.state)) {
this.pendingContextChange = null;
this.reset(update.state);
} else if (update.docChanged || update.selectionSet || reverted) {
this.setSelection(update.state);
}
if (update.geometryChanged || update.docChanged || update.selectionSet)
update.view.requestMeasure(this.measureReq);
}
resetRange(state) {
let { head } = state.selection.main;
this.from = Math.max(
0,
head - 1e4
/* CxVp.Margin */
);
this.to = Math.min(
state.doc.length,
head + 1e4
/* CxVp.Margin */
);
}
reset(state) {
this.resetRange(state);
this.editContext.updateText(0, this.editContext.text.length, state.doc.sliceString(this.from, this.to));
this.setSelection(state);
}
revertPending(state) {
let pending = this.pendingContextChange;
this.pendingContextChange = null;
this.editContext.updateText(this.toContextPos(pending.from), this.toContextPos(pending.from + pending.insert.length), state.doc.sliceString(pending.from, pending.to));
}
setSelection(state) {
let { main } = state.selection;
let start = this.toContextPos(Math.max(this.from, Math.min(this.to, main.anchor)));
let end = this.toContextPos(main.head);
if (this.editContext.selectionStart != start || this.editContext.selectionEnd != end)
this.editContext.updateSelection(start, end);
}
rangeIsValid(state) {
let { head } = state.selection.main;
return !(this.from > 0 && head - this.from < 500 || this.to < state.doc.length && this.to - head < 500 || this.to - this.from > 1e4 * 3);
}
toEditorPos(contextPos, clipLen = this.to - this.from) {
contextPos = Math.min(contextPos, clipLen);
let c = this.composing;
return c && c.drifted ? c.editorBase + (contextPos - c.contextBase) : contextPos + this.from;
}
toContextPos(editorPos) {
let c = this.composing;
return c && c.drifted ? c.contextBase + (editorPos - c.editorBase) : editorPos - this.from;
}
destroy() {
for (let event in this.handlers)
this.editContext.removeEventListener(event, this.handlers[event]);
}
};
var EditorView = class _EditorView {
/**
The current editor state.
*/
get state() {
return this.viewState.state;
}
/**
To be able to display large documents without consuming too much
memory or overloading the browser, CodeMirror only draws the
code that is visible (plus a margin around it) to the DOM. This
property tells you the extent of the current drawn viewport, in
document positions.
*/
get viewport() {
return this.viewState.viewport;
}
/**
When there are, for example, large collapsed ranges in the
viewport, its size can be a lot bigger than the actual visible
content. Thus, if you are doing something like styling the
content in the viewport, it is preferable to only do so for
these ranges, which are the subset of the viewport that is
actually drawn.
*/
get visibleRanges() {
return this.viewState.visibleRanges;
}
/**
Returns false when the editor is entirely scrolled out of view
or otherwise hidden.
*/
get inView() {
return this.viewState.inView;
}
/**
Indicates whether the user is currently composing text via
[IME](https://en.wikipedia.org/wiki/Input_method), and at least
one change has been made in the current composition.
*/
get composing() {
return !!this.inputState && this.inputState.composing > 0;
}
/**
Indicates whether the user is currently in composing state. Note
that on some platforms, like Android, this will be the case a
lot, since just putting the cursor on a word starts a
composition there.
*/
get compositionStarted() {
return !!this.inputState && this.inputState.composing >= 0;
}
/**
The document or shadow root that the view lives in.
*/
get root() {
return this._root;
}
/**
@internal
*/
get win() {
return this.dom.ownerDocument.defaultView || window;
}
/**
Construct a new view. You'll want to either provide a `parent`
option, or put `view.dom` into your document after creating a
view, so that the user can see the editor.
*/
constructor(config = {}) {
var _a;
this.plugins = [];
this.pluginMap = /* @__PURE__ */ new Map();
this.editorAttrs = {};
this.contentAttrs = {};
this.bidiCache = [];
this.destroyed = false;
this.updateState = 2;
this.measureScheduled = -1;
this.measureRequests = [];
this.contentDOM = document.createElement("div");
this.scrollDOM = document.createElement("div");
this.scrollDOM.tabIndex = -1;
this.scrollDOM.className = "cm-scroller";
this.scrollDOM.appendChild(this.contentDOM);
this.announceDOM = document.createElement("div");
this.announceDOM.className = "cm-announced";
this.announceDOM.setAttribute("aria-live", "polite");
this.dom = document.createElement("div");
this.dom.appendChild(this.announceDOM);
this.dom.appendChild(this.scrollDOM);
if (config.parent)
config.parent.appendChild(this.dom);
let { dispatch } = config;
this.dispatchTransactions = config.dispatchTransactions || dispatch && ((trs) => trs.forEach((tr) => dispatch(tr, this))) || ((trs) => this.update(trs));
this.dispatch = this.dispatch.bind(this);
this._root = config.root || getRoot(config.parent) || document;
this.viewState = new ViewState(this, config.state || EditorState.create(config));
if (config.scrollTo && config.scrollTo.is(scrollIntoView))
this.viewState.scrollTarget = config.scrollTo.value.clip(this.viewState.state);
this.plugins = this.state.facet(viewPlugin).map((spec) => new PluginInstance(spec));
for (let plugin2 of this.plugins)
plugin2.update(this);
this.observer = new DOMObserver(this);
this.inputState = new InputState(this);
this.inputState.ensureHandlers(this.plugins);
this.docView = new DocView(this);
this.mountStyles();
this.updateAttrs();
this.updateState = 0;
this.requestMeasure();
if ((_a = document.fonts) === null || _a === void 0 ? void 0 : _a.ready)
document.fonts.ready.then(() => {
this.viewState.mustMeasureContent = "refresh";
this.requestMeasure();
});
}
dispatch(...input) {
let trs = input.length == 1 && input[0] instanceof Transaction ? input : input.length == 1 && Array.isArray(input[0]) ? input[0] : [this.state.update(...input)];
this.dispatchTransactions(trs, this);
}
/**
Update the view for the given array of transactions. This will
update the visible document and selection to match the state
produced by the transactions, and notify view plugins of the
change. You should usually call
[`dispatch`](https://codemirror.net/6/docs/ref/#view.EditorView.dispatch) instead, which uses this
as a primitive.
*/
update(transactions) {
if (this.updateState != 0)
throw new Error("Calls to EditorView.update are not allowed while an update is in progress");
let redrawn = false, attrsChanged = false, update;
let state = this.state;
for (let tr of transactions) {
if (tr.startState != state)
throw new RangeError("Trying to update state with a transaction that doesn't start from the previous state.");
state = tr.state;
}
if (this.destroyed) {
this.viewState.state = state;
return;
}
let focus = this.hasFocus, focusFlag = 0, dispatchFocus = null;
if (transactions.some((tr) => tr.annotation(isFocusChange))) {
this.inputState.notifiedFocused = focus;
focusFlag = 1;
} else if (focus != this.inputState.notifiedFocused) {
this.inputState.notifiedFocused = focus;
dispatchFocus = focusChangeTransaction(state, focus);
if (!dispatchFocus)
focusFlag = 1;
}
let pendingKey = this.observer.delayedAndroidKey, domChange = null;
if (pendingKey) {
this.observer.clearDelayedAndroidKey();
domChange = this.observer.readChange();
if (domChange && !this.state.doc.eq(state.doc) || !this.state.selection.eq(state.selection))
domChange = null;
} else {
this.observer.clear();
}
if (state.facet(EditorState.phrases) != this.state.facet(EditorState.phrases))
return this.setState(state);
update = ViewUpdate.create(this, state, transactions);
update.flags |= focusFlag;
let scrollTarget = this.viewState.scrollTarget;
try {
this.updateState = 2;
for (let tr of transactions) {
if (scrollTarget)
scrollTarget = scrollTarget.map(tr.changes);
if (tr.scrollIntoView) {
let { main } = tr.state.selection;
let { x, y } = this.state.facet(_EditorView.cursorScrollMargin);
scrollTarget = new ScrollTarget(main.empty ? main : EditorSelection.cursor(main.head, main.head > main.anchor ? -1 : 1), "nearest", "nearest", y, x);
}
for (let e of tr.effects)
if (e.is(scrollIntoView))
scrollTarget = e.value.clip(this.state);
}
this.viewState.update(update, scrollTarget);
this.bidiCache = CachedOrder.update(this.bidiCache, update.changes);
if (!update.empty) {
this.updatePlugins(update);
this.inputState.update(update);
}
redrawn = this.docView.update(update);
if (this.state.facet(styleModule) != this.styleModules)
this.mountStyles();
attrsChanged = this.updateAttrs();
this.showAnnouncements(transactions);
this.docView.updateSelection(redrawn, transactions.some((tr) => tr.isUserEvent("select.pointer")));
} finally {
this.updateState = 0;
}
if (update.startState.facet(theme) != update.state.facet(theme))
this.viewState.mustMeasureContent = true;
if (redrawn || attrsChanged || scrollTarget || this.viewState.mustEnforceCursorAssoc || this.viewState.mustMeasureContent)
this.requestMeasure();
if (redrawn)
this.docViewUpdate();
if (!update.empty)
for (let listener of this.state.facet(updateListener)) {
try {
listener(update);
} catch (e) {
logException(this.state, e, "update listener");
}
}
if (dispatchFocus || domChange)
Promise.resolve().then(() => {
if (dispatchFocus && this.state == dispatchFocus.startState)
this.dispatch(dispatchFocus);
if (domChange) {
if (!applyDOMChange(this, domChange) && pendingKey.force)
dispatchKey(this.contentDOM, pendingKey.key, pendingKey.keyCode);
}
});
}
/**
Reset the view to the given state. (This will cause the entire
document to be redrawn and all view plugins to be reinitialized,
so you should probably only use it when the new state isn't
derived from the old state. Otherwise, use
[`dispatch`](https://codemirror.net/6/docs/ref/#view.EditorView.dispatch) instead.)
*/
setState(newState) {
if (this.updateState != 0)
throw new Error("Calls to EditorView.setState are not allowed while an update is in progress");
if (this.destroyed) {
this.viewState.state = newState;
return;
}
this.updateState = 2;
let hadFocus = this.hasFocus;
try {
for (let plugin2 of this.plugins)
plugin2.destroy(this);
this.viewState = new ViewState(this, newState);
this.plugins = newState.facet(viewPlugin).map((spec) => new PluginInstance(spec));
this.pluginMap.clear();
for (let plugin2 of this.plugins)
plugin2.update(this);
this.docView.destroy();
this.docView = new DocView(this);
this.inputState.ensureHandlers(this.plugins);
this.mountStyles();
this.updateAttrs();
this.bidiCache = [];
} finally {
this.updateState = 0;
}
if (hadFocus)
this.focus();
this.requestMeasure();
}
updatePlugins(update) {
let prevSpecs = update.startState.facet(viewPlugin), specs = update.state.facet(viewPlugin);
if (prevSpecs != specs) {
let newPlugins = [];
for (let spec of specs) {
let found = prevSpecs.indexOf(spec);
if (found < 0) {
newPlugins.push(new PluginInstance(spec));
} else {
let plugin2 = this.plugins[found];
plugin2.mustUpdate = update;
newPlugins.push(plugin2);
}
}
for (let plugin2 of this.plugins)
if (plugin2.mustUpdate != update)
plugin2.destroy(this);
this.plugins = newPlugins;
this.pluginMap.clear();
} else {
for (let p of this.plugins)
p.mustUpdate = update;
}
for (let i = 0; i < this.plugins.length; i++)
this.plugins[i].update(this);
if (prevSpecs != specs)
this.inputState.ensureHandlers(this.plugins);
}
docViewUpdate() {
for (let plugin2 of this.plugins) {
let val = plugin2.value;
if (val && val.docViewUpdate) {
try {
val.docViewUpdate(this);
} catch (e) {
logException(this.state, e, "doc view update listener");
}
}
}
}
/**
@internal
*/
measure(flush = true) {
if (this.destroyed)
return;
if (this.measureScheduled > -1)
this.win.cancelAnimationFrame(this.measureScheduled);
if (this.observer.delayedAndroidKey) {
this.measureScheduled = -1;
this.requestMeasure();
return;
}
this.measureScheduled = 0;
if (flush)
this.observer.forceFlush();
let updated = null;
let scroll = this.viewState.scrollParent, scrollOffset = this.viewState.getScrollOffset();
let { scrollAnchorPos, scrollAnchorHeight } = this.viewState;
if (Math.abs(scrollOffset - this.viewState.scrollOffset) > 1)
scrollAnchorHeight = -1;
this.viewState.scrollAnchorHeight = -1;
try {
for (let i = 0; ; i++) {
if (scrollAnchorHeight < 0) {
if (isScrolledToBottom(scroll || this.win)) {
scrollAnchorPos = -1;
scrollAnchorHeight = this.viewState.heightMap.height;
} else {
let block = this.viewState.scrollAnchorAt(scrollOffset);
scrollAnchorPos = block.from;
scrollAnchorHeight = block.top;
}
}
this.updateState = 1;
let changed = this.viewState.measure();
if (!changed && !this.measureRequests.length && this.viewState.scrollTarget == null)
break;
if (i > 5) {
console.warn(this.measureRequests.length ? "Measure loop restarted more than 5 times" : "Viewport failed to stabilize");
break;
}
let measuring = [];
if (!(changed & 4))
[this.measureRequests, measuring] = [measuring, this.measureRequests];
let measured = measuring.map((m) => {
try {
return m.read(this);
} catch (e) {
logException(this.state, e);
return BadMeasure;
}
});
let update = ViewUpdate.create(this, this.state, []), redrawn = false;
update.flags |= changed;
if (!updated)
updated = update;
else
updated.flags |= changed;
this.updateState = 2;
if (!update.empty) {
this.updatePlugins(update);
this.inputState.update(update);
this.updateAttrs();
redrawn = this.docView.update(update);
if (redrawn)
this.docViewUpdate();
}
for (let i2 = 0; i2 < measuring.length; i2++)
if (measured[i2] != BadMeasure) {
try {
let m = measuring[i2];
if (m.write)
m.write(measured[i2], this);
} catch (e) {
logException(this.state, e);
}
}
if (redrawn)
this.docView.updateSelection(true);
if (!update.viewportChanged && this.measureRequests.length == 0) {
if (this.viewState.editorHeight) {
if (this.viewState.scrollTarget) {
this.docView.scrollIntoView(this.viewState.scrollTarget);
this.viewState.scrollTarget = null;
scrollAnchorHeight = -1;
continue;
} else {
let newAnchorHeight = scrollAnchorPos < 0 ? this.viewState.heightMap.height : this.viewState.lineBlockAt(scrollAnchorPos).top;
let diff = (newAnchorHeight - scrollAnchorHeight) / this.scaleY;
if ((diff > 1 || diff < -1) && (scroll == this.scrollDOM || this.hasFocus || Math.max(this.inputState.lastWheelEvent, this.inputState.lastTouchTime) > Date.now() - 100)) {
scrollOffset = scrollOffset + diff;
if (scroll)
scroll.scrollTop += diff;
else
this.win.scrollBy(0, diff);
scrollAnchorHeight = -1;
continue;
}
}
}
break;
}
}
} finally {
this.updateState = 0;
this.measureScheduled = -1;
}
if (updated && !updated.empty)
for (let listener of this.state.facet(updateListener))
listener(updated);
}
/**
Get the CSS classes for the currently active editor themes.
*/
get themeClasses() {
return baseThemeID + " " + (this.state.facet(darkTheme) ? baseDarkID : baseLightID) + " " + this.state.facet(theme);
}
updateAttrs() {
let editorAttrs = attrsFromFacet(this, editorAttributes, {
class: "cm-editor" + (this.hasFocus ? " cm-focused " : " ") + this.themeClasses
});
let contentAttrs = {
spellcheck: "false",
autocorrect: "off",
autocapitalize: "off",
writingsuggestions: "false",
translate: "no",
contenteditable: !this.state.facet(editable) ? "false" : "true",
class: "cm-content",
style: `${browser.tabSize}: ${this.state.tabSize}`,
role: "textbox",
"aria-multiline": "true"
};
if (this.state.readOnly)
contentAttrs["aria-readonly"] = "true";
attrsFromFacet(this, contentAttributes, contentAttrs);
let changed = this.observer.ignore(() => {
let changedContent = updateAttrs(this.contentDOM, this.contentAttrs, contentAttrs);
let changedEditor = updateAttrs(this.dom, this.editorAttrs, editorAttrs);
return changedContent || changedEditor;
});
this.editorAttrs = editorAttrs;
this.contentAttrs = contentAttrs;
return changed;
}
showAnnouncements(trs) {
let first = true;
for (let tr of trs)
for (let effect of tr.effects)
if (effect.is(_EditorView.announce)) {
if (first)
this.announceDOM.textContent = "";
first = false;
let div = this.announceDOM.appendChild(document.createElement("div"));
div.textContent = effect.value;
}
}
mountStyles() {
this.styleModules = this.state.facet(styleModule);
let nonce = this.state.facet(_EditorView.cspNonce);
StyleModule.mount(this.root, this.styleModules.concat(baseTheme$1).reverse(), nonce ? { nonce } : void 0);
}
readMeasured() {
if (this.updateState == 2)
throw new Error("Reading the editor layout isn't allowed during an update");
if (this.updateState == 0 && this.measureScheduled > -1)
this.measure(false);
}
/**
Schedule a layout measurement, optionally providing callbacks to
do custom DOM measuring followed by a DOM write phase. Using
this is preferable reading DOM layout directly from, for
example, an event handler, because it'll make sure measuring and
drawing done by other components is synchronized, avoiding
unnecessary DOM layout computations.
*/
requestMeasure(request) {
if (this.measureScheduled < 0)
this.measureScheduled = this.win.requestAnimationFrame(() => this.measure());
if (request) {
if (this.measureRequests.indexOf(request) > -1)
return;
if (request.key != null)
for (let i = 0; i < this.measureRequests.length; i++) {
if (this.measureRequests[i].key === request.key) {
this.measureRequests[i] = request;
return;
}
}
this.measureRequests.push(request);
}
}
/**
Get the value of a specific plugin, if present. Note that
plugins that crash can be dropped from a view, so even when you
know you registered a given plugin, it is recommended to check
the return value of this method.
*/
plugin(plugin2) {
let known = this.pluginMap.get(plugin2);
if (known === void 0 || known && known.plugin != plugin2)
this.pluginMap.set(plugin2, known = this.plugins.find((p) => p.plugin == plugin2) || null);
return known && known.update(this).value;
}
/**
The top position of the document, in screen coordinates. This
may be negative when the editor is scrolled down. Points
directly to the top of the first line, not above the padding.
*/
get documentTop() {
return this.contentDOM.getBoundingClientRect().top + this.viewState.paddingTop;
}
/**
Reports the padding above and below the document.
*/
get documentPadding() {
return { top: this.viewState.paddingTop, bottom: this.viewState.paddingBottom };
}
/**
If the editor is transformed with CSS, this provides the scale
along the X axis. Otherwise, it will just be 1. Note that
transforms other than translation and scaling are not supported.
*/
get scaleX() {
return this.viewState.scaleX;
}
/**
Provide the CSS transformed scale along the Y axis.
*/
get scaleY() {
return this.viewState.scaleY;
}
/**
Find the text line or block widget at the given vertical
position (which is interpreted as relative to the [top of the
document](https://codemirror.net/6/docs/ref/#view.EditorView.documentTop)).
*/
elementAtHeight(height) {
this.readMeasured();
return this.viewState.elementAtHeight(height);
}
/**
Find the line block (see
[`lineBlockAt`](https://codemirror.net/6/docs/ref/#view.EditorView.lineBlockAt)) at the given
height, again interpreted relative to the [top of the
document](https://codemirror.net/6/docs/ref/#view.EditorView.documentTop).
*/
lineBlockAtHeight(height) {
this.readMeasured();
return this.viewState.lineBlockAtHeight(height);
}
/**
Get the extent and vertical position of all [line
blocks](https://codemirror.net/6/docs/ref/#view.EditorView.lineBlockAt) in the viewport. Positions
are relative to the [top of the
document](https://codemirror.net/6/docs/ref/#view.EditorView.documentTop);
*/
get viewportLineBlocks() {
return this.viewState.viewportLines;
}
/**
Find the line block around the given document position. A line
block is a range delimited on both sides by either a
non-[hidden](https://codemirror.net/6/docs/ref/#view.Decoration^replace) line break, or the
start/end of the document. It will usually just hold a line of
text, but may be broken into multiple textblocks by block
widgets.
*/
lineBlockAt(pos) {
return this.viewState.lineBlockAt(pos);
}
/**
The editor's total content height.
*/
get contentHeight() {
return this.viewState.contentHeight;
}
/**
Move a cursor position by [grapheme
cluster](https://codemirror.net/6/docs/ref/#state.findClusterBreak). `forward` determines whether
the motion is away from the line start, or towards it. In
bidirectional text, the line is traversed in visual order, using
the editor's [text direction](https://codemirror.net/6/docs/ref/#view.EditorView.textDirection).
When the start position was the last one on the line, the
returned position will be across the line break. If there is no
further line, the original position is returned.
By default, this method moves over a single cluster. The
optional `by` argument can be used to move across more. It will
be called with the first cluster as argument, and should return
a predicate that determines, for each subsequent cluster,
whether it should also be moved over.
*/
moveByChar(start, forward, by) {
return skipAtoms(this, start, moveByChar(this, start, forward, by));
}
/**
Move a cursor position across the next group of either
[letters](https://codemirror.net/6/docs/ref/#state.EditorState.charCategorizer) or non-letter
non-whitespace characters.
*/
moveByGroup(start, forward) {
return skipAtoms(this, start, moveByChar(this, start, forward, (initial) => byGroup(this, start.head, initial)));
}
/**
Get the cursor position visually at the start or end of a line.
Note that this may differ from the _logical_ position at its
start or end (which is simply at `line.from`/`line.to`) if text
at the start or end goes against the line's base text direction.
*/
visualLineSide(line, end) {
let order = this.bidiSpans(line), dir = this.textDirectionAt(line.from);
let span = order[end ? order.length - 1 : 0];
return EditorSelection.cursor(span.side(end, dir) + line.from, span.forward(!end, dir) ? 1 : -1);
}
/**
Move to the next line boundary in the given direction. If
`includeWrap` is true, line wrapping is on, and there is a
further wrap point on the current line, the wrap point will be
returned. Otherwise this function will return the start or end
of the line.
*/
moveToLineBoundary(start, forward, includeWrap = true) {
return moveToLineBoundary(this, start, forward, includeWrap);
}
/**
Move a cursor position vertically. When `distance` isn't given,
it defaults to moving to the next line (including wrapped
lines). Otherwise, `distance` should provide a positive distance
in pixels.
When `start` has a
[`goalColumn`](https://codemirror.net/6/docs/ref/#state.SelectionRange.goalColumn), the vertical
motion will use that as a target horizontal position. Otherwise,
the cursor's own horizontal position is used. The returned
cursor will have its goal column set to whichever column was
used.
*/
moveVertically(start, forward, distance) {
return skipAtoms(this, start, moveVertically(this, start, forward, distance));
}
/**
Find the DOM parent node and offset (child offset if `node` is
an element, character offset when it is a text node) at the
given document position.
Note that for positions that aren't currently in
`visibleRanges`, the resulting DOM position isn't necessarily
meaningful (it may just point before or after a placeholder
element).
*/
domAtPos(pos, side = 1) {
return this.docView.domAtPos(pos, side);
}
/**
Find the document position at the given DOM node. Can be useful
for associating positions with DOM events. Will raise an error
when `node` isn't part of the editor content.
*/
posAtDOM(node, offset = 0) {
return this.docView.posFromDOM(node, offset);
}
posAtCoords(coords, precise = true) {
this.readMeasured();
let found = posAtCoords(this, coords, precise);
return found && found.pos;
}
posAndSideAtCoords(coords, precise = true) {
this.readMeasured();
return posAtCoords(this, coords, precise);
}
/**
Get the screen coordinates at the given document position.
`side` determines whether the coordinates are based on the
element before (-1) or after (1) the position (if no element is
available on the given side, the method will transparently use
another strategy to get reasonable coordinates).
*/
coordsAtPos(pos, side = 1) {
this.readMeasured();
let rect = this.docView.coordsAt(pos, side);
if (!rect || rect.left == rect.right)
return rect;
let line = this.state.doc.lineAt(pos), order = this.bidiSpans(line);
let span = order[BidiSpan.find(order, pos - line.from, -1, side)];
return flattenRect(rect, span.dir == Direction.LTR == side > 0);
}
/**
Return the rectangle around a given character. If `pos` does not
point in front of a character that is in the viewport and
rendered (i.e. not replaced, not a line break), this will return
null. For space characters that are a line wrap point, this will
return the position before the line break.
*/
coordsForChar(pos) {
this.readMeasured();
return this.docView.coordsForChar(pos);
}
/**
The default width of a character in the editor. May not
accurately reflect the width of all characters (given variable
width fonts or styling of invididual ranges).
*/
get defaultCharacterWidth() {
return this.viewState.heightOracle.charWidth;
}
/**
The default height of a line in the editor. May not be accurate
for all lines.
*/
get defaultLineHeight() {
return this.viewState.heightOracle.lineHeight;
}
/**
The text direction
([`direction`](https://developer.mozilla.org/en-US/docs/Web/CSS/direction)
CSS property) of the editor's content element.
*/
get textDirection() {
return this.viewState.defaultTextDirection;
}
/**
Find the text direction of the block at the given position, as
assigned by CSS. If
[`perLineTextDirection`](https://codemirror.net/6/docs/ref/#view.EditorView^perLineTextDirection)
isn't enabled, or the given position is outside of the viewport,
this will always return the same as
[`textDirection`](https://codemirror.net/6/docs/ref/#view.EditorView.textDirection). Note that
this may trigger a DOM layout.
*/
textDirectionAt(pos) {
let perLine = this.state.facet(perLineTextDirection);
if (!perLine || pos < this.viewport.from || pos > this.viewport.to)
return this.textDirection;
this.readMeasured();
return this.docView.textDirectionAt(pos);
}
/**
Whether this editor [wraps lines](https://codemirror.net/6/docs/ref/#view.EditorView.lineWrapping)
(as determined by the
[`white-space`](https://developer.mozilla.org/en-US/docs/Web/CSS/white-space)
CSS property of its content element).
*/
get lineWrapping() {
return this.viewState.heightOracle.lineWrapping;
}
/**
Returns the bidirectional text structure of the given line
(which should be in the current document) as an array of span
objects. The order of these spans matches the [text
direction](https://codemirror.net/6/docs/ref/#view.EditorView.textDirection)—if that is
left-to-right, the leftmost spans come first, otherwise the
rightmost spans come first.
*/
bidiSpans(line) {
if (line.length > MaxBidiLine)
return trivialOrder(line.length);
let dir = this.textDirectionAt(line.from), isolates;
for (let entry of this.bidiCache) {
if (entry.from == line.from && entry.dir == dir && (entry.fresh || isolatesEq(entry.isolates, isolates = getIsolatedRanges(this, line))))
return entry.order;
}
if (!isolates)
isolates = getIsolatedRanges(this, line);
let order = computeOrder(line.text, dir, isolates);
this.bidiCache.push(new CachedOrder(line.from, line.to, dir, isolates, true, order));
return order;
}
/**
Check whether the editor has focus.
*/
get hasFocus() {
var _a;
return (this.dom.ownerDocument.hasFocus() || browser.safari && ((_a = this.inputState) === null || _a === void 0 ? void 0 : _a.lastContextMenu) > Date.now() - 3e4) && this.root.activeElement == this.contentDOM;
}
/**
Put focus on the editor.
*/
focus() {
this.observer.ignore(() => {
focusPreventScroll(this.contentDOM);
this.docView.updateSelection();
});
}
/**
Update the [root](https://codemirror.net/6/docs/ref/##view.EditorViewConfig.root) in which the editor lives. This is only
necessary when moving the editor's existing DOM to a new window or shadow root.
*/
setRoot(root) {
if (this._root != root) {
this._root = root;
this.observer.setWindow((root.nodeType == 9 ? root : root.ownerDocument).defaultView || window);
this.mountStyles();
}
}
/**
Clean up this editor view, removing its element from the
document, unregistering event handlers, and notifying
plugins. The view instance can no longer be used after
calling this.
*/
destroy() {
if (this.root.activeElement == this.contentDOM)
this.contentDOM.blur();
for (let plugin2 of this.plugins)
plugin2.destroy(this);
this.plugins = [];
this.inputState.destroy();
this.docView.destroy();
this.dom.remove();
this.observer.destroy();
if (this.measureScheduled > -1)
this.win.cancelAnimationFrame(this.measureScheduled);
this.destroyed = true;
}
/**
Returns an effect that can be
[added](https://codemirror.net/6/docs/ref/#state.TransactionSpec.effects) to a transaction to
cause it to scroll the given position or range into view.
*/
static scrollIntoView(pos, options = {}) {
var _a, _b, _c, _d;
return scrollIntoView.of(new ScrollTarget(typeof pos == "number" ? EditorSelection.cursor(pos) : pos, (_a = options.y) !== null && _a !== void 0 ? _a : "nearest", (_b = options.x) !== null && _b !== void 0 ? _b : "nearest", (_c = options.yMargin) !== null && _c !== void 0 ? _c : 5, (_d = options.xMargin) !== null && _d !== void 0 ? _d : 5));
}
/**
Return an effect that resets the editor to its current (at the
time this method was called) scroll position. Note that this
only affects the editor's own scrollable element, not parents.
See also
[`EditorViewConfig.scrollTo`](https://codemirror.net/6/docs/ref/#view.EditorViewConfig.scrollTo).
The effect should be used with a document identical to the one
it was created for. Failing to do so is not an error, but may
not scroll to the expected position. You can
[map](https://codemirror.net/6/docs/ref/#state.StateEffect.map) the effect to account for changes.
*/
scrollSnapshot() {
let { scrollTop, scrollLeft } = this.scrollDOM;
let ref = this.viewState.scrollAnchorAt(scrollTop);
return scrollIntoView.of(new ScrollTarget(EditorSelection.cursor(ref.from), "start", "start", ref.top - scrollTop, scrollLeft, true));
}
/**
Enable or disable tab-focus mode, which disables key bindings
for Tab and Shift-Tab, letting the browser's default
focus-changing behavior go through instead. This is useful to
prevent trapping keyboard users in your editor.
Without argument, this toggles the mode. With a boolean, it
enables (true) or disables it (false). Given a number, it
temporarily enables the mode until that number of milliseconds
have passed or another non-Tab key is pressed.
*/
setTabFocusMode(to) {
if (to == null)
this.inputState.tabFocusMode = this.inputState.tabFocusMode < 0 ? 0 : -1;
else if (typeof to == "boolean")
this.inputState.tabFocusMode = to ? 0 : -1;
else if (this.inputState.tabFocusMode != 0)
this.inputState.tabFocusMode = Date.now() + to;
}
/**
Returns an extension that can be used to add DOM event handlers.
The value should be an object mapping event names to handler
functions. For any given event, such functions are ordered by
extension precedence, and the first handler to return true will
be assumed to have handled that event, and no other handlers or
built-in behavior will be activated for it. These are registered
on the [content element](https://codemirror.net/6/docs/ref/#view.EditorView.contentDOM), except
for `scroll` handlers, which will be called any time the
editor's [scroll element](https://codemirror.net/6/docs/ref/#view.EditorView.scrollDOM) or one of
its parent nodes is scrolled.
*/
static domEventHandlers(handlers2) {
return ViewPlugin.define(() => ({}), { eventHandlers: handlers2 });
}
/**
Create an extension that registers DOM event observers. Contrary
to event [handlers](https://codemirror.net/6/docs/ref/#view.EditorView^domEventHandlers),
observers can't be prevented from running by a higher-precedence
handler returning true. They also don't prevent other handlers
and observers from running when they return true, and should not
call `preventDefault`.
*/
static domEventObservers(observers2) {
return ViewPlugin.define(() => ({}), { eventObservers: observers2 });
}
/**
Create a theme extension. The first argument can be a
[`style-mod`](https://code.haverbeke.berlin/marijn/style-mod#documentation)
style spec providing the styles for the theme. These will be
prefixed with a generated class for the style.
Because the selectors will be prefixed with a scope class, rule
that directly match the editor's [wrapper
element](https://codemirror.net/6/docs/ref/#view.EditorView.dom)—to which the scope class will be
addedneed to be explicitly differentiated by adding an `&` to
the selector for that elementfor example
`&.cm-focused`.
When `dark` is set to true, the theme will be marked as dark,
which will cause the `&dark` rules from [base
themes](https://codemirror.net/6/docs/ref/#view.EditorView^baseTheme) to be used (as opposed to
`&light` when a light theme is active).
*/
static theme(spec, options) {
let prefix = StyleModule.newName();
let result = [theme.of(prefix), styleModule.of(buildTheme(`.${prefix}`, spec))];
if (options && options.dark)
result.push(darkTheme.of(true));
return result;
}
/**
Create an extension that adds styles to the base theme. Like
with [`theme`](https://codemirror.net/6/docs/ref/#view.EditorView^theme), use `&` to indicate the
place of the editor wrapper element when directly targeting
that. You can also use `&dark` or `&light` instead to only
target editors with a dark or light theme.
*/
static baseTheme(spec) {
return Prec.lowest(styleModule.of(buildTheme("." + baseThemeID, spec, lightDarkIDs)));
}
/**
Retrieve an editor view instance from the view's DOM
representation.
*/
static findFromDOM(dom) {
var _a;
let content = dom.querySelector(".cm-content");
let tile = content && Tile.get(content) || Tile.get(dom);
return ((_a = tile === null || tile === void 0 ? void 0 : tile.root) === null || _a === void 0 ? void 0 : _a.view) || null;
}
};
EditorView.styleModule = styleModule;
EditorView.inputHandler = inputHandler;
EditorView.clipboardInputFilter = clipboardInputFilter;
EditorView.clipboardOutputFilter = clipboardOutputFilter;
EditorView.scrollHandler = scrollHandler;
EditorView.focusChangeEffect = focusChangeEffect;
EditorView.perLineTextDirection = perLineTextDirection;
EditorView.exceptionSink = exceptionSink;
EditorView.updateListener = updateListener;
EditorView.editable = editable;
EditorView.mouseSelectionStyle = mouseSelectionStyle;
EditorView.dragMovesSelection = dragMovesSelection$1;
EditorView.clickAddsSelectionRange = clickAddsSelectionRange;
EditorView.decorations = decorations;
EditorView.blockWrappers = blockWrappers;
EditorView.outerDecorations = outerDecorations;
EditorView.atomicRanges = atomicRanges;
EditorView.bidiIsolatedRanges = bidiIsolatedRanges;
EditorView.cursorScrollMargin = Facet.define({
combine: (inputs) => {
let x = 5, y = 5;
for (let i of inputs) {
if (typeof i == "number")
x = y = i;
else
({ x, y } = i);
}
return { x, y };
}
});
EditorView.scrollMargins = scrollMargins;
EditorView.darkTheme = darkTheme;
EditorView.cspNonce = Facet.define({ combine: (values) => values.length ? values[0] : "" });
EditorView.contentAttributes = contentAttributes;
EditorView.editorAttributes = editorAttributes;
EditorView.lineWrapping = EditorView.contentAttributes.of({ "class": "cm-lineWrapping" });
EditorView.announce = StateEffect.define();
var MaxBidiLine = 4096;
var BadMeasure = {};
var CachedOrder = class _CachedOrder {
constructor(from, to, dir, isolates, fresh, order) {
this.from = from;
this.to = to;
this.dir = dir;
this.isolates = isolates;
this.fresh = fresh;
this.order = order;
}
static update(cache, changes) {
if (changes.empty && !cache.some((c) => c.fresh))
return cache;
let result = [], lastDir = cache.length ? cache[cache.length - 1].dir : Direction.LTR;
for (let i = Math.max(0, cache.length - 10); i < cache.length; i++) {
let entry = cache[i];
if (entry.dir == lastDir && !changes.touchesRange(entry.from, entry.to))
result.push(new _CachedOrder(changes.mapPos(entry.from, 1), changes.mapPos(entry.to, -1), entry.dir, entry.isolates, false, entry.order));
}
return result;
}
};
function attrsFromFacet(view, facet, base2) {
for (let sources = view.state.facet(facet), i = sources.length - 1; i >= 0; i--) {
let source = sources[i], value = typeof source == "function" ? source(view) : source;
if (value)
combineAttrs(value, base2);
}
return base2;
}
var currentPlatform = browser.mac ? "mac" : browser.windows ? "win" : browser.linux ? "linux" : "key";
function normalizeKeyName(name, platform) {
const parts = name.split(/-(?!$)/);
let result = parts[parts.length - 1];
if (result == "Space")
result = " ";
let alt, ctrl, shift2, meta;
for (let i = 0; i < parts.length - 1; ++i) {
const mod = parts[i];
if (/^(cmd|meta|m)$/i.test(mod))
meta = true;
else if (/^a(lt)?$/i.test(mod))
alt = true;
else if (/^(c|ctrl|control)$/i.test(mod))
ctrl = true;
else if (/^s(hift)?$/i.test(mod))
shift2 = true;
else if (/^mod$/i.test(mod)) {
if (platform == "mac")
meta = true;
else
ctrl = true;
} else
throw new Error("Unrecognized modifier name: " + mod);
}
if (alt)
result = "Alt-" + result;
if (ctrl)
result = "Ctrl-" + result;
if (meta)
result = "Meta-" + result;
if (shift2)
result = "Shift-" + result;
return result;
}
function modifiers(name, event, shift2) {
if (event.altKey)
name = "Alt-" + name;
if (event.ctrlKey)
name = "Ctrl-" + name;
if (event.metaKey)
name = "Meta-" + name;
if (shift2 !== false && event.shiftKey)
name = "Shift-" + name;
return name;
}
var handleKeyEvents = Prec.default(EditorView.domEventHandlers({
keydown(event, view) {
return runHandlers(getKeymap(view.state), event, view, "editor");
}
}));
var keymap = Facet.define({ enables: handleKeyEvents });
var Keymaps = /* @__PURE__ */ new WeakMap();
function getKeymap(state) {
let bindings = state.facet(keymap);
let map = Keymaps.get(bindings);
if (!map)
Keymaps.set(bindings, map = buildKeymap(bindings.reduce((a, b) => a.concat(b), [])));
return map;
}
function runScopeHandlers(view, event, scope) {
return runHandlers(getKeymap(view.state), event, view, scope);
}
var storedPrefix = null;
var PrefixTimeout = 4e3;
function buildKeymap(bindings, platform = currentPlatform) {
let bound = /* @__PURE__ */ Object.create(null);
let isPrefix = /* @__PURE__ */ Object.create(null);
let checkPrefix = (name, is) => {
let current = isPrefix[name];
if (current == null)
isPrefix[name] = is;
else if (current != is)
throw new Error("Key binding " + name + " is used both as a regular binding and as a multi-stroke prefix");
};
let add2 = (scope, key, command, preventDefault, stopPropagation) => {
var _a, _b;
let scopeObj = bound[scope] || (bound[scope] = /* @__PURE__ */ Object.create(null));
let parts = key.split(/ (?!$)/).map((k) => normalizeKeyName(k, platform));
for (let i = 1; i < parts.length; i++) {
let prefix = parts.slice(0, i).join(" ");
checkPrefix(prefix, true);
if (!scopeObj[prefix])
scopeObj[prefix] = {
preventDefault: true,
stopPropagation: false,
run: [(view) => {
let ourObj = storedPrefix = { view, prefix, scope };
setTimeout(() => {
if (storedPrefix == ourObj)
storedPrefix = null;
}, PrefixTimeout);
return true;
}]
};
}
let full = parts.join(" ");
checkPrefix(full, false);
let binding = scopeObj[full] || (scopeObj[full] = {
preventDefault: false,
stopPropagation: false,
run: ((_b = (_a = scopeObj._any) === null || _a === void 0 ? void 0 : _a.run) === null || _b === void 0 ? void 0 : _b.slice()) || []
});
if (command)
binding.run.push(command);
if (preventDefault)
binding.preventDefault = true;
if (stopPropagation)
binding.stopPropagation = true;
};
for (let b of bindings) {
let scopes = b.scope ? b.scope.split(" ") : ["editor"];
if (b.any)
for (let scope of scopes) {
let scopeObj = bound[scope] || (bound[scope] = /* @__PURE__ */ Object.create(null));
if (!scopeObj._any)
scopeObj._any = { preventDefault: false, stopPropagation: false, run: [] };
let { any } = b;
for (let key in scopeObj)
scopeObj[key].run.push((view) => any(view, currentKeyEvent));
}
let name = b[platform] || b.key;
if (!name)
continue;
for (let scope of scopes) {
add2(scope, name, b.run, b.preventDefault, b.stopPropagation);
if (b.shift)
add2(scope, "Shift-" + name, b.shift, b.preventDefault, b.stopPropagation);
}
}
return bound;
}
var currentKeyEvent = null;
function runHandlers(map, event, view, scope) {
currentKeyEvent = event;
let name = keyName(event);
let charCode = codePointAt(name, 0), isChar = codePointSize(charCode) == name.length && name != " ";
let prefix = "", handled = false, prevented = false, stopPropagation = false;
if (storedPrefix && storedPrefix.view == view && storedPrefix.scope == scope) {
prefix = storedPrefix.prefix + " ";
if (modifierCodes.indexOf(event.keyCode) < 0) {
prevented = true;
storedPrefix = null;
}
}
let ran = /* @__PURE__ */ new Set();
let runFor = (binding) => {
if (binding) {
for (let cmd of binding.run)
if (!ran.has(cmd)) {
ran.add(cmd);
if (cmd(view)) {
if (binding.stopPropagation)
stopPropagation = true;
return true;
}
}
if (binding.preventDefault) {
if (binding.stopPropagation)
stopPropagation = true;
prevented = true;
}
}
return false;
};
let scopeObj = map[scope], baseName, shiftName;
if (scopeObj) {
if (runFor(scopeObj[prefix + modifiers(name, event, !isChar)])) {
handled = true;
} else if (isChar && (event.altKey || event.metaKey || event.ctrlKey) && // Ctrl-Alt may be used for AltGr on Windows
!(browser.windows && event.ctrlKey && event.altKey) && // Alt-combinations on macOS tend to be typed characters
!(browser.mac && event.altKey && !(event.ctrlKey || event.metaKey)) && (baseName = base[event.keyCode]) && baseName != name) {
if (runFor(scopeObj[prefix + modifiers(baseName, event, true)])) {
handled = true;
} else if (event.shiftKey && (shiftName = shift[event.keyCode]) != name && shiftName != baseName && runFor(scopeObj[prefix + modifiers(shiftName, event, false)])) {
handled = true;
}
} else if (isChar && event.shiftKey && runFor(scopeObj[prefix + modifiers(name, event, true)])) {
handled = true;
}
if (!handled && runFor(scopeObj._any))
handled = true;
}
if (prevented)
handled = true;
if (handled && stopPropagation)
event.stopPropagation();
currentKeyEvent = null;
return handled;
}
var RectangleMarker = class _RectangleMarker {
/**
Create a marker with the given class and dimensions. If `width`
is null, the DOM element will get no width style.
*/
constructor(className, left, top2, width, height) {
this.className = className;
this.left = left;
this.top = top2;
this.width = width;
this.height = height;
}
draw() {
let elt = document.createElement("div");
elt.className = this.className;
this.adjust(elt);
return elt;
}
update(elt, prev) {
if (prev.className != this.className)
return false;
this.adjust(elt);
return true;
}
adjust(elt) {
elt.style.left = this.left + "px";
elt.style.top = this.top + "px";
if (this.width != null)
elt.style.width = this.width + "px";
elt.style.height = this.height + "px";
}
eq(p) {
return this.left == p.left && this.top == p.top && this.width == p.width && this.height == p.height && this.className == p.className;
}
/**
Create a set of rectangles for the given selection range,
assigning them theclass`className`. Will create a single
rectangle for empty ranges, and a set of selection-style
rectangles covering the range's content (in a bidi-aware
way) for non-empty ones.
*/
static forRange(view, className, range) {
if (range.empty) {
let pos = view.coordsAtPos(range.head, range.assoc || 1);
if (!pos)
return [];
let base2 = getBase(view);
return [new _RectangleMarker(className, pos.left - base2.left, pos.top - base2.top, null, pos.bottom - pos.top)];
} else {
return rectanglesForRange(view, className, range);
}
}
};
function getBase(view) {
let rect = view.scrollDOM.getBoundingClientRect();
let left = view.textDirection == Direction.LTR ? rect.left : rect.right - view.scrollDOM.clientWidth * view.scaleX;
return { left: left - view.scrollDOM.scrollLeft * view.scaleX, top: rect.top - view.scrollDOM.scrollTop * view.scaleY };
}
function wrappedLine(view, pos, side, inside) {
let coords = view.coordsAtPos(pos, side * 2);
if (!coords)
return inside;
let editorRect = view.dom.getBoundingClientRect();
let y = (coords.top + coords.bottom) / 2;
let left = view.posAtCoords({ x: editorRect.left + 1, y });
let right = view.posAtCoords({ x: editorRect.right - 1, y });
if (left == null || right == null)
return inside;
return { from: Math.max(inside.from, Math.min(left, right)), to: Math.min(inside.to, Math.max(left, right)) };
}
function rectanglesForRange(view, className, range) {
if (range.to <= view.viewport.from || range.from >= view.viewport.to)
return [];
let from = Math.max(range.from, view.viewport.from), to = Math.min(range.to, view.viewport.to);
let ltr = view.textDirection == Direction.LTR;
let content = view.contentDOM, contentRect = content.getBoundingClientRect(), base2 = getBase(view);
let lineElt = content.querySelector(".cm-line"), lineStyle = lineElt && window.getComputedStyle(lineElt);
let leftSide = contentRect.left + (lineStyle ? parseInt(lineStyle.paddingLeft) + Math.min(0, parseInt(lineStyle.textIndent)) : 0);
let rightSide = contentRect.right - (lineStyle ? parseInt(lineStyle.paddingRight) : 0);
let startBlock = blockAt(view, from, 1), endBlock = blockAt(view, to, -1);
let visualStart = startBlock.type == BlockType.Text ? startBlock : null;
let visualEnd = endBlock.type == BlockType.Text ? endBlock : null;
if (visualStart && (view.lineWrapping || startBlock.widgetLineBreaks))
visualStart = wrappedLine(view, from, 1, visualStart);
if (visualEnd && (view.lineWrapping || endBlock.widgetLineBreaks))
visualEnd = wrappedLine(view, to, -1, visualEnd);
if (visualStart && visualEnd && visualStart.from == visualEnd.from && visualStart.to == visualEnd.to) {
return pieces(drawForLine(range.from, range.to, visualStart));
} else {
let top2 = visualStart ? drawForLine(range.from, null, visualStart) : drawForWidget(startBlock, false);
let bottom = visualEnd ? drawForLine(null, range.to, visualEnd) : drawForWidget(endBlock, true);
let between = [];
if ((visualStart || startBlock).to < (visualEnd || endBlock).from - (visualStart && visualEnd ? 1 : 0) || startBlock.widgetLineBreaks > 1 && top2.bottom + view.defaultLineHeight / 2 < bottom.top)
between.push(piece(leftSide, top2.bottom, rightSide, bottom.top));
else if (top2.bottom < bottom.top && view.elementAtHeight((top2.bottom + bottom.top) / 2).type == BlockType.Text)
top2.bottom = bottom.top = (top2.bottom + bottom.top) / 2;
return pieces(top2).concat(between).concat(pieces(bottom));
}
function piece(left, top2, right, bottom) {
return new RectangleMarker(className, left - base2.left, top2 - base2.top, Math.max(0, right - left), bottom - top2);
}
function pieces({ top: top2, bottom, horizontal }) {
let pieces2 = [];
for (let i = 0; i < horizontal.length; i += 2)
pieces2.push(piece(horizontal[i], top2, horizontal[i + 1], bottom));
return pieces2;
}
function drawForLine(from2, to2, line) {
let top2 = 1e9, bottom = -1e9, horizontal = [];
function addSpan(from3, fromOpen, to3, toOpen, dir) {
let fromCoords = view.coordsAtPos(from3, from3 == line.to ? -2 : 2);
let toCoords = view.coordsAtPos(to3, to3 == line.from ? 2 : -2);
if (!fromCoords || !toCoords)
return;
top2 = Math.min(fromCoords.top, toCoords.top, top2);
bottom = Math.max(fromCoords.bottom, toCoords.bottom, bottom);
if (dir == Direction.LTR)
horizontal.push(ltr && fromOpen ? leftSide : fromCoords.left, ltr && toOpen ? rightSide : toCoords.right);
else
horizontal.push(!ltr && toOpen ? leftSide : toCoords.left, !ltr && fromOpen ? rightSide : fromCoords.right);
}
let start = from2 !== null && from2 !== void 0 ? from2 : line.from, end = to2 !== null && to2 !== void 0 ? to2 : line.to;
for (let r of view.visibleRanges)
if (r.to > start && r.from < end) {
for (let pos = Math.max(r.from, start), endPos = Math.min(r.to, end); ; ) {
let docLine = view.state.doc.lineAt(pos);
for (let span of view.bidiSpans(docLine)) {
let spanFrom = span.from + docLine.from, spanTo = span.to + docLine.from;
if (spanFrom >= endPos)
break;
if (spanTo > pos)
addSpan(Math.max(spanFrom, pos), from2 == null && spanFrom <= start, Math.min(spanTo, endPos), to2 == null && spanTo >= end, span.dir);
}
pos = docLine.to + 1;
if (pos >= endPos)
break;
}
}
if (horizontal.length == 0)
addSpan(start, from2 == null, end, to2 == null, view.textDirection);
return { top: top2, bottom, horizontal };
}
function drawForWidget(block, top2) {
let y = contentRect.top + (top2 ? block.top : block.bottom);
return { top: y, bottom: y, horizontal: [] };
}
}
function sameMarker(a, b) {
return a.constructor == b.constructor && a.eq(b);
}
var LayerView = class {
constructor(view, layer2) {
this.view = view;
this.layer = layer2;
this.drawn = [];
this.scaleX = 1;
this.scaleY = 1;
this.measureReq = { read: this.measure.bind(this), write: this.draw.bind(this) };
this.dom = view.scrollDOM.appendChild(document.createElement("div"));
this.dom.classList.add("cm-layer");
if (layer2.above)
this.dom.classList.add("cm-layer-above");
if (layer2.class)
this.dom.classList.add(layer2.class);
this.scale();
this.dom.setAttribute("aria-hidden", "true");
this.setOrder(view.state);
view.requestMeasure(this.measureReq);
if (layer2.mount)
layer2.mount(this.dom, view);
}
update(update) {
if (update.startState.facet(layerOrder) != update.state.facet(layerOrder))
this.setOrder(update.state);
if (this.layer.update(update, this.dom) || update.geometryChanged) {
this.scale();
update.view.requestMeasure(this.measureReq);
}
}
docViewUpdate(view) {
if (this.layer.updateOnDocViewUpdate !== false)
view.requestMeasure(this.measureReq);
}
setOrder(state) {
let pos = 0, order = state.facet(layerOrder);
while (pos < order.length && order[pos] != this.layer)
pos++;
this.dom.style.zIndex = String((this.layer.above ? 150 : -1) - pos);
}
measure() {
return this.layer.markers(this.view);
}
scale() {
let { scaleX, scaleY } = this.view;
if (scaleX != this.scaleX || scaleY != this.scaleY) {
this.scaleX = scaleX;
this.scaleY = scaleY;
this.dom.style.transform = `scale(${1 / scaleX}, ${1 / scaleY})`;
}
}
draw(markers) {
if (markers.length != this.drawn.length || markers.some((p, i) => !sameMarker(p, this.drawn[i]))) {
let old = this.dom.firstChild, oldI = 0;
for (let marker of markers) {
if (marker.update && old && marker.constructor && this.drawn[oldI].constructor && marker.update(old, this.drawn[oldI])) {
old = old.nextSibling;
oldI++;
} else {
this.dom.insertBefore(marker.draw(), old);
}
}
while (old) {
let next = old.nextSibling;
old.remove();
old = next;
}
this.drawn = markers;
if (browser.webkit)
this.dom.style.display = this.dom.firstChild ? "" : "none";
}
}
destroy() {
if (this.layer.destroy)
this.layer.destroy(this.dom, this.view);
this.dom.remove();
}
};
var layerOrder = Facet.define();
function layer(config) {
return [
ViewPlugin.define((v) => new LayerView(v, config)),
layerOrder.of(config)
];
}
var selectionConfig = Facet.define({
combine(configs) {
return combineConfig(configs, {
cursorBlinkRate: 1200,
drawRangeCursor: true,
iosSelectionHandles: true
}, {
cursorBlinkRate: (a, b) => Math.min(a, b),
drawRangeCursor: (a, b) => a || b
});
}
});
function drawSelection(config = {}) {
return [
selectionConfig.of(config),
cursorLayer,
selectionLayer,
hideNativeSelection,
nativeSelectionHidden.of(true)
];
}
function getDrawSelectionConfig(state) {
return state.facet(selectionConfig);
}
function configChanged(update) {
return update.startState.facet(selectionConfig) != update.state.facet(selectionConfig);
}
var cursorLayer = layer({
above: true,
markers(view) {
let { state } = view, conf = state.facet(selectionConfig);
let cursors = [];
for (let r of state.selection.ranges) {
let prim = r == state.selection.main;
if (r.empty || conf.drawRangeCursor && !(prim && browser.ios && conf.iosSelectionHandles)) {
let className = prim ? "cm-cursor cm-cursor-primary" : "cm-cursor cm-cursor-secondary";
let cursor = r.empty ? r : EditorSelection.cursor(r.head, r.assoc);
for (let piece of RectangleMarker.forRange(view, className, cursor))
cursors.push(piece);
}
}
return cursors;
},
update(update, dom) {
if (update.transactions.some((tr) => tr.selection))
dom.style.animationName = dom.style.animationName == "cm-blink" ? "cm-blink2" : "cm-blink";
let confChange = configChanged(update);
if (confChange)
setBlinkRate(update.state, dom);
return update.docChanged || update.selectionSet || confChange;
},
mount(dom, view) {
setBlinkRate(view.state, dom);
},
class: "cm-cursorLayer"
});
function setBlinkRate(state, dom) {
dom.style.animationDuration = state.facet(selectionConfig).cursorBlinkRate + "ms";
}
var selectionLayer = layer({
above: false,
markers(view) {
let markers = [], { main, ranges } = view.state.selection;
for (let r of ranges)
if (!r.empty) {
for (let marker of RectangleMarker.forRange(view, "cm-selectionBackground", r))
markers.push(marker);
}
if (browser.ios && !main.empty && view.state.facet(selectionConfig).iosSelectionHandles) {
for (let piece of RectangleMarker.forRange(view, "cm-selectionHandle cm-selectionHandle-start", EditorSelection.cursor(main.from, 1)))
markers.push(piece);
for (let piece of RectangleMarker.forRange(view, "cm-selectionHandle cm-selectionHandle-end", EditorSelection.cursor(main.to, 1)))
markers.push(piece);
}
return markers;
},
update(update, dom) {
return update.docChanged || update.selectionSet || update.viewportChanged || configChanged(update);
},
class: "cm-selectionLayer"
});
var hideNativeSelection = Prec.highest(EditorView.theme({
".cm-line": {
"& ::selection, &::selection": { backgroundColor: "transparent !important" },
caretColor: "transparent !important"
},
".cm-content": {
caretColor: "transparent !important",
"& :focus": {
caretColor: "initial !important",
"&::selection, & ::selection": {
backgroundColor: "Highlight !important"
}
}
}
}));
var setDropCursorPos = StateEffect.define({
map(pos, mapping) {
return pos == null ? null : mapping.mapPos(pos);
}
});
var dropCursorPos = StateField.define({
create() {
return null;
},
update(pos, tr) {
if (pos != null)
pos = tr.changes.mapPos(pos);
return tr.effects.reduce((pos2, e) => e.is(setDropCursorPos) ? e.value : pos2, pos);
}
});
var drawDropCursor = ViewPlugin.fromClass(class {
constructor(view) {
this.view = view;
this.cursor = null;
this.measureReq = { read: this.readPos.bind(this), write: this.drawCursor.bind(this) };
}
update(update) {
var _a;
let cursorPos = update.state.field(dropCursorPos);
if (cursorPos == null) {
if (this.cursor != null) {
(_a = this.cursor) === null || _a === void 0 ? void 0 : _a.remove();
this.cursor = null;
}
} else {
if (!this.cursor) {
this.cursor = this.view.scrollDOM.appendChild(document.createElement("div"));
this.cursor.className = "cm-dropCursor";
}
if (update.startState.field(dropCursorPos) != cursorPos || update.docChanged || update.geometryChanged)
this.view.requestMeasure(this.measureReq);
}
}
readPos() {
let { view } = this;
let pos = view.state.field(dropCursorPos);
let rect = pos != null && view.coordsAtPos(pos);
if (!rect)
return null;
let outer = view.scrollDOM.getBoundingClientRect();
return {
left: rect.left - outer.left + view.scrollDOM.scrollLeft * view.scaleX,
top: rect.top - outer.top + view.scrollDOM.scrollTop * view.scaleY,
height: rect.bottom - rect.top
};
}
drawCursor(pos) {
if (this.cursor) {
let { scaleX, scaleY } = this.view;
if (pos) {
this.cursor.style.left = pos.left / scaleX + "px";
this.cursor.style.top = pos.top / scaleY + "px";
this.cursor.style.height = pos.height / scaleY + "px";
} else {
this.cursor.style.left = "-100000px";
}
}
}
destroy() {
if (this.cursor)
this.cursor.remove();
}
setDropPos(pos) {
if (this.view.state.field(dropCursorPos) != pos)
this.view.dispatch({ effects: setDropCursorPos.of(pos) });
}
}, {
eventObservers: {
dragover(event) {
this.setDropPos(this.view.posAtCoords({ x: event.clientX, y: event.clientY }));
},
dragleave(event) {
if (event.target == this.view.contentDOM || !this.view.contentDOM.contains(event.relatedTarget))
this.setDropPos(null);
},
dragend() {
this.setDropPos(null);
},
drop() {
this.setDropPos(null);
}
}
});
function dropCursor() {
return [dropCursorPos, drawDropCursor];
}
function iterMatches(doc2, re, from, to, f) {
re.lastIndex = 0;
for (let cursor = doc2.iterRange(from, to), pos = from, m; !cursor.next().done; pos += cursor.value.length) {
if (!cursor.lineBreak)
while (m = re.exec(cursor.value))
f(pos + m.index, m);
}
}
function matchRanges(view, maxLength) {
let visible = view.visibleRanges;
if (visible.length == 1 && visible[0].from == view.viewport.from && visible[0].to == view.viewport.to)
return visible;
let result = [];
for (let { from, to } of visible) {
from = Math.max(view.state.doc.lineAt(from).from, from - maxLength);
to = Math.min(view.state.doc.lineAt(to).to, to + maxLength);
if (result.length && result[result.length - 1].to >= from)
result[result.length - 1].to = to;
else
result.push({ from, to });
}
return result;
}
var MatchDecorator = class {
/**
Create a decorator.
*/
constructor(config) {
const { regexp, decoration, decorate, boundary, maxLength = 1e3 } = config;
if (!regexp.global)
throw new RangeError("The regular expression given to MatchDecorator should have its 'g' flag set");
this.regexp = regexp;
if (decorate) {
this.addMatch = (match, view, from, add2) => decorate(add2, from, from + match[0].length, match, view);
} else if (typeof decoration == "function") {
this.addMatch = (match, view, from, add2) => {
let deco = decoration(match, view, from);
if (deco)
add2(from, from + match[0].length, deco);
};
} else if (decoration) {
this.addMatch = (match, _view, from, add2) => add2(from, from + match[0].length, decoration);
} else {
throw new RangeError("Either 'decorate' or 'decoration' should be provided to MatchDecorator");
}
this.boundary = boundary;
this.maxLength = maxLength;
}
/**
Compute the full set of decorations for matches in the given
view's viewport. You'll want to call this when initializing your
plugin.
*/
createDeco(view) {
let build = new RangeSetBuilder(), add2 = build.add.bind(build);
for (let { from, to } of matchRanges(view, this.maxLength))
iterMatches(view.state.doc, this.regexp, from, to, (from2, m) => this.addMatch(m, view, from2, add2));
return build.finish();
}
/**
Update a set of decorations for a view update. `deco` _must_ be
the set of decorations produced by _this_ `MatchDecorator` for
the view state before the update.
*/
updateDeco(update, deco) {
let changeFrom = 1e9, changeTo = -1;
if (update.docChanged)
update.changes.iterChanges((_f, _t, from, to) => {
if (to >= update.view.viewport.from && from <= update.view.viewport.to) {
changeFrom = Math.min(from, changeFrom);
changeTo = Math.max(to, changeTo);
}
});
if (update.viewportMoved || changeTo - changeFrom > 1e3)
return this.createDeco(update.view);
if (changeTo > -1)
return this.updateRange(update.view, deco.map(update.changes), changeFrom, changeTo);
return deco;
}
updateRange(view, deco, updateFrom, updateTo) {
for (let r of view.visibleRanges) {
let from = Math.max(r.from, updateFrom), to = Math.min(r.to, updateTo);
if (to >= from) {
let fromLine = view.state.doc.lineAt(from), toLine = fromLine.to < to ? view.state.doc.lineAt(to) : fromLine;
let start = Math.max(r.from, fromLine.from), end = Math.min(r.to, toLine.to);
if (this.boundary) {
for (; from > fromLine.from; from--)
if (this.boundary.test(fromLine.text[from - 1 - fromLine.from])) {
start = from;
break;
}
for (; to < toLine.to; to++)
if (this.boundary.test(toLine.text[to - toLine.from])) {
end = to;
break;
}
}
let ranges = [], m;
let add2 = (from2, to2, deco2) => ranges.push(deco2.range(from2, to2));
if (fromLine == toLine) {
this.regexp.lastIndex = start - fromLine.from;
while ((m = this.regexp.exec(fromLine.text)) && m.index < end - fromLine.from)
this.addMatch(m, view, m.index + fromLine.from, add2);
} else {
iterMatches(view.state.doc, this.regexp, start, end, (from2, m2) => this.addMatch(m2, view, from2, add2));
}
deco = deco.update({ filterFrom: start, filterTo: end, filter: (from2, to2) => from2 < start || to2 > end, add: ranges });
}
}
return deco;
}
};
var UnicodeRegexpSupport = /x/.unicode != null ? "gu" : "g";
var Specials = new RegExp("[\0-\b\n--Ÿ­؜\u2028\u2029\uFEFF-]", UnicodeRegexpSupport);
var Names = {
0: "null",
7: "bell",
8: "backspace",
10: "newline",
11: "vertical tab",
13: "carriage return",
27: "escape",
8203: "zero width space",
8204: "zero width non-joiner",
8205: "zero width joiner",
8206: "left-to-right mark",
8207: "right-to-left mark",
8232: "line separator",
8237: "left-to-right override",
8238: "right-to-left override",
8294: "left-to-right isolate",
8295: "right-to-left isolate",
8297: "pop directional isolate",
8233: "paragraph separator",
65279: "zero width no-break space",
65532: "object replacement"
};
var _supportsTabSize = null;
function supportsTabSize() {
var _a;
if (_supportsTabSize == null && typeof document != "undefined" && document.body) {
let styles = document.body.style;
_supportsTabSize = ((_a = styles.tabSize) !== null && _a !== void 0 ? _a : styles.MozTabSize) != null;
}
return _supportsTabSize || false;
}
var specialCharConfig = Facet.define({
combine(configs) {
let config = combineConfig(configs, {
render: null,
specialChars: Specials,
addSpecialChars: null
});
if (config.replaceTabs = !supportsTabSize())
config.specialChars = new RegExp(" |" + config.specialChars.source, UnicodeRegexpSupport);
if (config.addSpecialChars)
config.specialChars = new RegExp(config.specialChars.source + "|" + config.addSpecialChars.source, UnicodeRegexpSupport);
return config;
}
});
function highlightSpecialChars(config = {}) {
return [specialCharConfig.of(config), specialCharPlugin()];
}
var _plugin = null;
function specialCharPlugin() {
return _plugin || (_plugin = ViewPlugin.fromClass(class {
constructor(view) {
this.view = view;
this.decorations = Decoration.none;
this.decorationCache = /* @__PURE__ */ Object.create(null);
this.decorator = this.makeDecorator(view.state.facet(specialCharConfig));
this.decorations = this.decorator.createDeco(view);
}
makeDecorator(conf) {
return new MatchDecorator({
regexp: conf.specialChars,
decoration: (m, view, pos) => {
let { doc: doc2 } = view.state;
let code = codePointAt(m[0], 0);
if (code == 9) {
let line = doc2.lineAt(pos);
let size = view.state.tabSize, col = countColumn(line.text, size, pos - line.from);
return Decoration.replace({
widget: new TabWidget((size - col % size) * this.view.defaultCharacterWidth / this.view.scaleX)
});
}
return this.decorationCache[code] || (this.decorationCache[code] = Decoration.replace({ widget: new SpecialCharWidget(conf, code) }));
},
boundary: conf.replaceTabs ? void 0 : /[^]/
});
}
update(update) {
let conf = update.state.facet(specialCharConfig);
if (update.startState.facet(specialCharConfig) != conf) {
this.decorator = this.makeDecorator(conf);
this.decorations = this.decorator.createDeco(update.view);
} else {
this.decorations = this.decorator.updateDeco(update, this.decorations);
}
}
}, {
decorations: (v) => v.decorations
}));
}
var DefaultPlaceholder = "•";
function placeholder$1(code) {
if (code >= 32)
return DefaultPlaceholder;
if (code == 10)
return "␤";
return String.fromCharCode(9216 + code);
}
var SpecialCharWidget = class extends WidgetType {
constructor(options, code) {
super();
this.options = options;
this.code = code;
}
eq(other) {
return other.code == this.code;
}
toDOM(view) {
let ph = placeholder$1(this.code);
let desc = view.state.phrase("Control character") + " " + (Names[this.code] || "0x" + this.code.toString(16));
let custom = this.options.render && this.options.render(this.code, desc, ph);
if (custom)
return custom;
let span = document.createElement("span");
span.textContent = ph;
span.title = desc;
span.setAttribute("aria-label", desc);
span.className = "cm-specialChar";
return span;
}
ignoreEvent() {
return false;
}
};
var TabWidget = class extends WidgetType {
constructor(width) {
super();
this.width = width;
}
eq(other) {
return other.width == this.width;
}
toDOM() {
let span = document.createElement("span");
span.textContent = " ";
span.className = "cm-tab";
span.style.width = this.width + "px";
return span;
}
ignoreEvent() {
return false;
}
};
var plugin = ViewPlugin.fromClass(class {
constructor() {
this.height = 1e3;
this.attrs = { style: "padding-bottom: 1000px" };
}
update(update) {
let { view } = update;
let height = view.viewState.editorHeight - view.defaultLineHeight - view.documentPadding.top - 0.5;
if (height >= 0 && height != this.height) {
this.height = height;
this.attrs = { style: `padding-bottom: ${height}px` };
}
}
});
function scrollPastEnd() {
return [plugin, contentAttributes.of((view) => {
var _a;
return ((_a = view.plugin(plugin)) === null || _a === void 0 ? void 0 : _a.attrs) || null;
})];
}
function highlightActiveLine() {
return activeLineHighlighter;
}
var lineDeco = Decoration.line({ class: "cm-activeLine" });
var activeLineHighlighter = ViewPlugin.fromClass(class {
constructor(view) {
this.decorations = this.getDeco(view);
}
update(update) {
if (update.docChanged || update.selectionSet)
this.decorations = this.getDeco(update.view);
}
getDeco(view) {
let lastLineStart = -1, deco = [];
for (let r of view.state.selection.ranges) {
let line = view.lineBlockAt(r.head);
if (line.from > lastLineStart) {
deco.push(lineDeco.range(line.from));
lastLineStart = line.from;
}
}
return Decoration.set(deco);
}
}, {
decorations: (v) => v.decorations
});
var Placeholder = class extends WidgetType {
constructor(content) {
super();
this.content = content;
}
toDOM(view) {
let wrap = document.createElement("span");
wrap.className = "cm-placeholder";
wrap.style.pointerEvents = "none";
wrap.appendChild(typeof this.content == "string" ? document.createTextNode(this.content) : typeof this.content == "function" ? this.content(view) : this.content.cloneNode(true));
wrap.setAttribute("aria-hidden", "true");
return wrap;
}
coordsAt(dom) {
let rects = dom.firstChild ? clientRectsFor(dom.firstChild) : [];
if (!rects.length)
return null;
let style = window.getComputedStyle(dom.parentNode);
let rect = flattenRect(rects[0], style.direction != "rtl");
let lineHeight = parseInt(style.lineHeight);
if (rect.bottom - rect.top > lineHeight * 1.5)
return { left: rect.left, right: rect.right, top: rect.top, bottom: rect.top + lineHeight };
return rect;
}
ignoreEvent() {
return false;
}
};
function placeholder(content) {
let plugin2 = ViewPlugin.fromClass(class {
constructor(view) {
this.view = view;
this.placeholder = content ? Decoration.set([Decoration.widget({ widget: new Placeholder(content), side: 1 }).range(0)]) : Decoration.none;
}
get decorations() {
return this.view.state.doc.length ? Decoration.none : this.placeholder;
}
}, { decorations: (v) => v.decorations });
return typeof content == "string" ? [
plugin2,
EditorView.contentAttributes.of({ "aria-placeholder": content })
] : plugin2;
}
var MaxOff = 2e3;
function rectangleFor(state, a, b) {
let startLine = Math.min(a.line, b.line), endLine = Math.max(a.line, b.line);
let ranges = [];
if (a.off > MaxOff || b.off > MaxOff || a.col < 0 || b.col < 0) {
let startOff = Math.min(a.off, b.off), endOff = Math.max(a.off, b.off);
for (let i = startLine; i <= endLine; i++) {
let line = state.doc.line(i);
if (line.length <= endOff)
ranges.push(EditorSelection.range(line.from + startOff, line.to + endOff));
}
} else {
let startCol = Math.min(a.col, b.col), endCol = Math.max(a.col, b.col);
for (let i = startLine; i <= endLine; i++) {
let line = state.doc.line(i);
let start = findColumn(line.text, startCol, state.tabSize, true);
if (start < 0) {
ranges.push(EditorSelection.cursor(line.to));
} else {
let end = findColumn(line.text, endCol, state.tabSize);
ranges.push(EditorSelection.range(line.from + start, line.from + end));
}
}
}
return ranges;
}
function absoluteColumn(view, x) {
let ref = view.coordsAtPos(view.viewport.from);
return ref ? Math.round(Math.abs((ref.left - x) / view.defaultCharacterWidth)) : -1;
}
function getPos(view, event) {
let offset = view.posAtCoords({ x: event.clientX, y: event.clientY }, false);
let line = view.state.doc.lineAt(offset), off = offset - line.from;
let col = off > MaxOff ? -1 : off == line.length ? absoluteColumn(view, event.clientX) : countColumn(line.text, view.state.tabSize, offset - line.from);
return { line: line.number, col, off };
}
function rectangleSelectionStyle(view, event) {
let start = getPos(view, event), startSel = view.state.selection;
if (!start)
return null;
return {
update(update) {
if (update.docChanged) {
let newStart = update.changes.mapPos(update.startState.doc.line(start.line).from);
let newLine = update.state.doc.lineAt(newStart);
start = { line: newLine.number, col: start.col, off: Math.min(start.off, newLine.length) };
startSel = startSel.map(update.changes);
}
},
get(event2, _extend, multiple) {
let cur = getPos(view, event2);
if (!cur)
return startSel;
let ranges = rectangleFor(view.state, start, cur);
if (!ranges.length)
return startSel;
if (multiple)
return EditorSelection.create(ranges.concat(startSel.ranges));
else
return EditorSelection.create(ranges);
}
};
}
function rectangularSelection(options) {
let filter = (options === null || options === void 0 ? void 0 : options.eventFilter) || ((e) => e.altKey && e.button == 0);
return EditorView.mouseSelectionStyle.of((view, event) => filter(event) ? rectangleSelectionStyle(view, event) : null);
}
var keys = {
Alt: [18, (e) => !!e.altKey],
Control: [17, (e) => !!e.ctrlKey],
Shift: [16, (e) => !!e.shiftKey],
Meta: [91, (e) => !!e.metaKey]
};
var showCrosshair = { style: "cursor: crosshair" };
function crosshairCursor(options = {}) {
let [code, getter] = keys[options.key || "Alt"];
let plugin2 = ViewPlugin.fromClass(class {
constructor(view) {
this.view = view;
this.isDown = false;
}
set(isDown) {
if (this.isDown != isDown) {
this.isDown = isDown;
this.view.update([]);
}
}
}, {
eventObservers: {
keydown(e) {
this.set(e.keyCode == code || getter(e));
},
keyup(e) {
if (e.keyCode == code || !getter(e))
this.set(false);
},
mousemove(e) {
this.set(getter(e));
}
}
});
return [
plugin2,
EditorView.contentAttributes.of((view) => {
var _a;
return ((_a = view.plugin(plugin2)) === null || _a === void 0 ? void 0 : _a.isDown) ? showCrosshair : null;
})
];
}
var Outside = "-10000px";
var TooltipViewManager = class {
constructor(view, facet, createTooltipView, removeTooltipView) {
this.facet = facet;
this.createTooltipView = createTooltipView;
this.removeTooltipView = removeTooltipView;
this.input = view.state.facet(facet);
this.tooltips = this.input.filter((t) => t);
let prev = null;
this.tooltipViews = this.tooltips.map((t) => prev = createTooltipView(t, prev));
}
update(update, above) {
var _a;
let input = update.state.facet(this.facet);
let tooltips2 = input.filter((x) => x);
if (input === this.input) {
for (let t of this.tooltipViews)
if (t.update)
t.update(update);
return false;
}
let tooltipViews = [], newAbove = above ? [] : null;
for (let i = 0; i < tooltips2.length; i++) {
let tip = tooltips2[i], known = -1;
if (!tip)
continue;
for (let i2 = 0; i2 < this.tooltips.length; i2++) {
let other = this.tooltips[i2];
if (other && other.create == tip.create)
known = i2;
}
if (known < 0) {
tooltipViews[i] = this.createTooltipView(tip, i ? tooltipViews[i - 1] : null);
if (newAbove)
newAbove[i] = !!tip.above;
} else {
let tooltipView = tooltipViews[i] = this.tooltipViews[known];
if (newAbove)
newAbove[i] = above[known];
if (tooltipView.update)
tooltipView.update(update);
}
}
for (let t of this.tooltipViews)
if (tooltipViews.indexOf(t) < 0) {
this.removeTooltipView(t);
(_a = t.destroy) === null || _a === void 0 ? void 0 : _a.call(t);
}
if (above) {
newAbove.forEach((val, i) => above[i] = val);
above.length = newAbove.length;
}
this.input = input;
this.tooltips = tooltips2;
this.tooltipViews = tooltipViews;
return true;
}
};
function tooltips(config = {}) {
return tooltipConfig.of(config);
}
function windowSpace(view) {
let docElt = view.dom.ownerDocument.documentElement;
return { top: 0, left: 0, bottom: docElt.clientHeight, right: docElt.clientWidth };
}
var tooltipConfig = Facet.define({
combine: (values) => {
var _a, _b, _c;
return {
position: browser.ios ? "absolute" : ((_a = values.find((conf) => conf.position)) === null || _a === void 0 ? void 0 : _a.position) || "fixed",
parent: ((_b = values.find((conf) => conf.parent)) === null || _b === void 0 ? void 0 : _b.parent) || null,
tooltipSpace: ((_c = values.find((conf) => conf.tooltipSpace)) === null || _c === void 0 ? void 0 : _c.tooltipSpace) || windowSpace
};
}
});
var knownHeight = /* @__PURE__ */ new WeakMap();
var tooltipPlugin = ViewPlugin.fromClass(class {
constructor(view) {
this.view = view;
this.above = [];
this.inView = true;
this.madeAbsolute = false;
this.lastTransaction = 0;
this.measureTimeout = -1;
let config = view.state.facet(tooltipConfig);
this.position = config.position;
this.parent = config.parent;
this.classes = view.themeClasses;
this.createContainer();
this.measureReq = { read: this.readMeasure.bind(this), write: this.writeMeasure.bind(this), key: this };
this.resizeObserver = typeof ResizeObserver == "function" ? new ResizeObserver(() => this.measureSoon()) : null;
this.manager = new TooltipViewManager(view, showTooltip, (t, p) => this.createTooltip(t, p), (t) => {
if (this.resizeObserver)
this.resizeObserver.unobserve(t.dom);
t.dom.remove();
});
this.above = this.manager.tooltips.map((t) => !!t.above);
this.intersectionObserver = typeof IntersectionObserver == "function" ? new IntersectionObserver((entries) => {
if (Date.now() > this.lastTransaction - 50 && entries.length > 0 && entries[entries.length - 1].intersectionRatio < 1)
this.measureSoon();
}, { threshold: [1] }) : null;
this.observeIntersection();
view.win.addEventListener("resize", this.measureSoon = this.measureSoon.bind(this));
this.maybeMeasure();
}
createContainer() {
if (this.parent) {
this.container = document.createElement("div");
this.container.style.position = "relative";
this.container.className = this.view.themeClasses;
this.parent.appendChild(this.container);
} else {
this.container = this.view.dom;
}
}
observeIntersection() {
if (this.intersectionObserver) {
this.intersectionObserver.disconnect();
for (let tooltip of this.manager.tooltipViews)
this.intersectionObserver.observe(tooltip.dom);
}
}
measureSoon() {
if (this.measureTimeout < 0)
this.measureTimeout = setTimeout(() => {
this.measureTimeout = -1;
this.maybeMeasure();
}, 50);
}
update(update) {
if (update.transactions.length)
this.lastTransaction = Date.now();
let updated = this.manager.update(update, this.above);
if (updated)
this.observeIntersection();
let shouldMeasure = updated || update.geometryChanged;
let newConfig = update.state.facet(tooltipConfig);
if (newConfig.position != this.position && !this.madeAbsolute) {
this.position = newConfig.position;
for (let t of this.manager.tooltipViews)
t.dom.style.position = this.position;
shouldMeasure = true;
}
if (newConfig.parent != this.parent) {
if (this.parent)
this.container.remove();
this.parent = newConfig.parent;
this.createContainer();
for (let t of this.manager.tooltipViews)
this.container.appendChild(t.dom);
shouldMeasure = true;
} else if (this.parent && this.view.themeClasses != this.classes) {
this.classes = this.container.className = this.view.themeClasses;
}
if (shouldMeasure)
this.maybeMeasure();
}
createTooltip(tooltip, prev) {
let tooltipView = tooltip.create(this.view);
let before = prev ? prev.dom : null;
tooltipView.dom.classList.add("cm-tooltip");
if (tooltip.arrow && !tooltipView.dom.querySelector(".cm-tooltip > .cm-tooltip-arrow")) {
let arrow = document.createElement("div");
arrow.className = "cm-tooltip-arrow";
tooltipView.dom.appendChild(arrow);
}
tooltipView.dom.style.position = this.position;
tooltipView.dom.style.top = Outside;
tooltipView.dom.style.left = "0px";
this.container.insertBefore(tooltipView.dom, before);
if (tooltipView.mount)
tooltipView.mount(this.view);
if (this.resizeObserver)
this.resizeObserver.observe(tooltipView.dom);
return tooltipView;
}
destroy() {
var _a, _b, _c;
this.view.win.removeEventListener("resize", this.measureSoon);
for (let tooltipView of this.manager.tooltipViews) {
tooltipView.dom.remove();
(_a = tooltipView.destroy) === null || _a === void 0 ? void 0 : _a.call(tooltipView);
}
if (this.parent)
this.container.remove();
(_b = this.resizeObserver) === null || _b === void 0 ? void 0 : _b.disconnect();
(_c = this.intersectionObserver) === null || _c === void 0 ? void 0 : _c.disconnect();
clearTimeout(this.measureTimeout);
}
readMeasure() {
let scaleX = 1, scaleY = 1, makeAbsolute = false;
if (this.position == "fixed" && this.manager.tooltipViews.length) {
let { dom } = this.manager.tooltipViews[0];
if (browser.safari) {
let rect = dom.getBoundingClientRect();
makeAbsolute = Math.abs(rect.top + 1e4) > 1 || Math.abs(rect.left) > 1;
} else {
makeAbsolute = !!dom.offsetParent && dom.offsetParent != this.container.ownerDocument.body;
}
}
if (makeAbsolute || this.position == "absolute") {
if (this.parent) {
let rect = this.parent.getBoundingClientRect();
if (rect.width && rect.height) {
scaleX = rect.width / this.parent.offsetWidth;
scaleY = rect.height / this.parent.offsetHeight;
}
} else {
({ scaleX, scaleY } = this.view.viewState);
}
}
let visible = this.view.scrollDOM.getBoundingClientRect(), margins = getScrollMargins(this.view);
return {
visible: {
left: visible.left + margins.left,
top: visible.top + margins.top,
right: visible.right - margins.right,
bottom: visible.bottom - margins.bottom
},
parent: this.parent ? this.container.getBoundingClientRect() : this.view.dom.getBoundingClientRect(),
pos: this.manager.tooltips.map((t, i) => {
let tv = this.manager.tooltipViews[i];
return tv.getCoords ? tv.getCoords(t.pos) : this.view.coordsAtPos(t.pos);
}),
size: this.manager.tooltipViews.map(({ dom }) => dom.getBoundingClientRect()),
space: this.view.state.facet(tooltipConfig).tooltipSpace(this.view),
scaleX,
scaleY,
makeAbsolute
};
}
writeMeasure(measured) {
var _a;
if (measured.makeAbsolute) {
this.madeAbsolute = true;
this.position = "absolute";
for (let t of this.manager.tooltipViews)
t.dom.style.position = "absolute";
}
let { visible, space, scaleX, scaleY } = measured;
let others = [];
for (let i = 0; i < this.manager.tooltips.length; i++) {
let tooltip = this.manager.tooltips[i], tView = this.manager.tooltipViews[i], { dom } = tView;
let pos = measured.pos[i], size = measured.size[i];
if (!pos || tooltip.clip !== false && (pos.bottom <= Math.max(visible.top, space.top) || pos.top >= Math.min(visible.bottom, space.bottom) || pos.right < Math.max(visible.left, space.left) - 0.1 || pos.left > Math.min(visible.right, space.right) + 0.1)) {
dom.style.top = Outside;
continue;
}
let arrow = tooltip.arrow ? tView.dom.querySelector(".cm-tooltip-arrow") : null;
let arrowHeight = arrow ? 7 : 0;
let width = size.right - size.left, height = (_a = knownHeight.get(tView)) !== null && _a !== void 0 ? _a : size.bottom - size.top;
let offset = tView.offset || noOffset, ltr = this.view.textDirection == Direction.LTR;
let left = size.width > space.right - space.left ? ltr ? space.left : space.right - size.width : ltr ? Math.max(space.left, Math.min(pos.left - (arrow ? 14 : 0) + offset.x, space.right - width)) : Math.min(Math.max(space.left, pos.left - width + (arrow ? 14 : 0) - offset.x), space.right - width);
let above = this.above[i];
if (!tooltip.strictSide && (above ? pos.top - height - arrowHeight - offset.y < space.top : pos.bottom + height + arrowHeight + offset.y > space.bottom) && above == space.bottom - pos.bottom > pos.top - space.top)
above = this.above[i] = !above;
let spaceVert = (above ? pos.top - space.top : space.bottom - pos.bottom) - arrowHeight;
if (spaceVert < height && tView.resize !== false) {
if (spaceVert < this.view.defaultLineHeight) {
dom.style.top = Outside;
continue;
}
knownHeight.set(tView, height);
dom.style.height = (height = spaceVert) / scaleY + "px";
} else if (dom.style.height) {
dom.style.height = "";
}
let top2 = above ? pos.top - height - arrowHeight - offset.y : pos.bottom + arrowHeight + offset.y;
let right = left + width;
if (tView.overlap !== true) {
for (let r of others)
if (r.left < right && r.right > left && r.top < top2 + height && r.bottom > top2)
top2 = above ? r.top - height - 2 - arrowHeight : r.bottom + arrowHeight + 2;
}
if (this.position == "absolute") {
dom.style.top = (top2 - measured.parent.top) / scaleY + "px";
setLeftStyle(dom, (left - measured.parent.left) / scaleX);
} else {
dom.style.top = top2 / scaleY + "px";
setLeftStyle(dom, left / scaleX);
}
if (arrow) {
let arrowLeft = pos.left + (ltr ? offset.x : -offset.x) - (left + 14 - 7);
arrow.style.left = arrowLeft / scaleX + "px";
}
if (tView.overlap !== true)
others.push({ left, top: top2, right, bottom: top2 + height });
dom.classList.toggle("cm-tooltip-above", above);
dom.classList.toggle("cm-tooltip-below", !above);
if (tView.positioned)
tView.positioned(measured.space);
}
}
maybeMeasure() {
if (this.manager.tooltips.length) {
if (this.view.inView)
this.view.requestMeasure(this.measureReq);
if (this.inView != this.view.inView) {
this.inView = this.view.inView;
if (!this.inView)
for (let tv of this.manager.tooltipViews)
tv.dom.style.top = Outside;
}
}
}
}, {
eventObservers: {
scroll() {
this.maybeMeasure();
}
}
});
function setLeftStyle(elt, value) {
let current = parseInt(elt.style.left, 10);
if (isNaN(current) || Math.abs(value - current) > 1)
elt.style.left = value + "px";
}
var baseTheme = EditorView.baseTheme({
".cm-tooltip": {
zIndex: 500,
boxSizing: "border-box"
},
"&light .cm-tooltip": {
border: "1px solid #bbb",
backgroundColor: "#f5f5f5"
},
"&light .cm-tooltip-section:not(:first-child)": {
borderTop: "1px solid #bbb"
},
"&dark .cm-tooltip": {
backgroundColor: "#333338",
color: "white"
},
".cm-tooltip-arrow": {
height: `${7}px`,
width: `${7 * 2}px`,
position: "absolute",
zIndex: -1,
overflow: "hidden",
"&:before, &:after": {
content: "''",
position: "absolute",
width: 0,
height: 0,
borderLeft: `${7}px solid transparent`,
borderRight: `${7}px solid transparent`
},
".cm-tooltip-above &": {
bottom: `-${7}px`,
"&:before": {
borderTop: `${7}px solid #bbb`
},
"&:after": {
borderTop: `${7}px solid #f5f5f5`,
bottom: "1px"
}
},
".cm-tooltip-below &": {
top: `-${7}px`,
"&:before": {
borderBottom: `${7}px solid #bbb`
},
"&:after": {
borderBottom: `${7}px solid #f5f5f5`,
top: "1px"
}
}
},
"&dark .cm-tooltip .cm-tooltip-arrow": {
"&:before": {
borderTopColor: "#333338",
borderBottomColor: "#333338"
},
"&:after": {
borderTopColor: "transparent",
borderBottomColor: "transparent"
}
}
});
var noOffset = { x: 0, y: 0 };
var showTooltip = Facet.define({
enables: [tooltipPlugin, baseTheme]
});
var showHoverTooltip = Facet.define({
combine: (inputs) => inputs.reduce((a, i) => a.concat(i), [])
});
var HoverTooltipHost = class _HoverTooltipHost {
// Needs to be static so that host tooltip instances always match
static create(view) {
return new _HoverTooltipHost(view);
}
constructor(view) {
this.view = view;
this.mounted = false;
this.dom = document.createElement("div");
this.dom.classList.add("cm-tooltip-hover");
this.manager = new TooltipViewManager(view, showHoverTooltip, (t, p) => this.createHostedView(t, p), (t) => t.dom.remove());
}
createHostedView(tooltip, prev) {
let hostedView = tooltip.create(this.view);
hostedView.dom.classList.add("cm-tooltip-section");
this.dom.insertBefore(hostedView.dom, prev ? prev.dom.nextSibling : this.dom.firstChild);
if (this.mounted && hostedView.mount)
hostedView.mount(this.view);
return hostedView;
}
mount(view) {
for (let hostedView of this.manager.tooltipViews) {
if (hostedView.mount)
hostedView.mount(view);
}
this.mounted = true;
}
positioned(space) {
for (let hostedView of this.manager.tooltipViews) {
if (hostedView.positioned)
hostedView.positioned(space);
}
}
update(update) {
this.manager.update(update);
}
destroy() {
var _a;
for (let t of this.manager.tooltipViews)
(_a = t.destroy) === null || _a === void 0 ? void 0 : _a.call(t);
}
passProp(name) {
let value = void 0;
for (let view of this.manager.tooltipViews) {
let given = view[name];
if (given !== void 0) {
if (value === void 0)
value = given;
else if (value !== given)
return void 0;
}
}
return value;
}
get offset() {
return this.passProp("offset");
}
get getCoords() {
return this.passProp("getCoords");
}
get overlap() {
return this.passProp("overlap");
}
get resize() {
return this.passProp("resize");
}
};
var showHoverTooltipHost = showTooltip.compute([showHoverTooltip], (state) => {
let tooltips2 = state.facet(showHoverTooltip);
if (tooltips2.length === 0)
return null;
return {
pos: Math.min(...tooltips2.map((t) => t.pos)),
end: Math.max(...tooltips2.map((t) => {
var _a;
return (_a = t.end) !== null && _a !== void 0 ? _a : t.pos;
})),
create: HoverTooltipHost.create,
above: tooltips2[0].above,
arrow: tooltips2.some((t) => t.arrow)
};
});
var hoverPlugin = Facet.define();
var HoverPlugin = class {
constructor(view, source, field, locked, setHover, hoverTime) {
this.view = view;
this.source = source;
this.field = field;
this.locked = locked;
this.setHover = setHover;
this.hoverTime = hoverTime;
this.hoverTimeout = -1;
this.restartTimeout = -1;
this.pending = null;
this.lastMove = { x: 0, y: 0, target: view.dom, time: 0 };
this.checkHover = this.checkHover.bind(this);
view.dom.addEventListener("mouseleave", this.mouseleave = this.mouseleave.bind(this));
view.dom.addEventListener("mousemove", this.mousemove = this.mousemove.bind(this));
}
update(update) {
if (this.pending) {
this.pending = null;
clearTimeout(this.restartTimeout);
this.restartTimeout = setTimeout(() => this.startHover(), 20);
}
}
get active() {
return this.view.state.field(this.field);
}
checkHover() {
this.hoverTimeout = -1;
if (this.active.length)
return;
let hovered = Date.now() - this.lastMove.time;
if (hovered < this.hoverTime)
this.hoverTimeout = setTimeout(this.checkHover, this.hoverTime - hovered);
else
this.startHover();
}
startHover() {
clearTimeout(this.restartTimeout);
let { view, lastMove } = this;
let tile = view.docView.tile.nearest(lastMove.target);
if (!tile)
return;
let pos, side = 1;
if (tile.isWidget()) {
pos = tile.posAtStart;
} else {
pos = view.posAtCoords(lastMove);
if (pos == null)
return;
let posCoords = view.coordsAtPos(pos);
if (!posCoords || lastMove.y < posCoords.top || lastMove.y > posCoords.bottom || lastMove.x < posCoords.left - view.defaultCharacterWidth || lastMove.x > posCoords.right + view.defaultCharacterWidth)
return;
let bidi = view.bidiSpans(view.state.doc.lineAt(pos)).find((s) => s.from <= pos && s.to >= pos);
let rtl = bidi && bidi.dir == Direction.RTL ? -1 : 1;
side = lastMove.x < posCoords.left ? -rtl : rtl;
}
this.activateHover(view, pos, side);
}
activateHover(view, pos, side, locked) {
let open = this.source(view, pos, side);
let done = (value) => {
if (value && !(Array.isArray(value) && !value.length)) {
let tooltips2 = Array.isArray(value) ? value : [value];
if (locked)
this.locked.set(tooltips2, locked);
view.dispatch({ effects: this.setHover.of(tooltips2) });
}
};
if (open && "then" in open) {
let pending = this.pending = { pos };
open.then((result) => {
if (this.pending == pending) {
this.pending = null;
done(result);
}
}, (e) => logException(view.state, e, "hover tooltip"));
} else {
done(open);
}
}
get tooltip() {
let plugin2 = this.view.plugin(tooltipPlugin);
let index = plugin2 ? plugin2.manager.tooltips.findIndex((t) => t.create == HoverTooltipHost.create) : -1;
return index > -1 ? plugin2.manager.tooltipViews[index] : null;
}
mousemove(event) {
var _a, _b;
this.lastMove = { x: event.clientX, y: event.clientY, target: event.target, time: Date.now() };
if (this.hoverTimeout < 0)
this.hoverTimeout = setTimeout(this.checkHover, this.hoverTime);
let { active, tooltip } = this;
if (active.length && !this.locked.has(active) && tooltip && !isInTooltip(tooltip.dom, event) || this.pending) {
let { pos } = active[0] || this.pending, end = (_b = (_a = active[0]) === null || _a === void 0 ? void 0 : _a.end) !== null && _b !== void 0 ? _b : pos;
if (pos == end ? this.view.posAtCoords(this.lastMove) != pos : !isOverRange(this.view, pos, end, event.clientX, event.clientY)) {
this.view.dispatch({ effects: this.setHover.of([]) });
this.pending = null;
}
}
}
mouseleave(event) {
clearTimeout(this.hoverTimeout);
this.hoverTimeout = -1;
let { active } = this;
if (active.length && !this.locked.has(active)) {
let { tooltip } = this;
let inTooltip = tooltip && tooltip.dom.contains(event.relatedTarget);
if (!inTooltip)
this.view.dispatch({ effects: this.setHover.of([]) });
else
this.watchTooltipLeave(tooltip.dom);
}
}
watchTooltipLeave(tooltip) {
let watch = (event) => {
tooltip.removeEventListener("mouseleave", watch);
let { active } = this;
if (active.length && !this.locked.has(active) && !this.view.dom.contains(event.relatedTarget))
this.view.dispatch({ effects: this.setHover.of([]) });
};
tooltip.addEventListener("mouseleave", watch);
}
destroy() {
clearTimeout(this.hoverTimeout);
clearTimeout(this.restartTimeout);
this.view.dom.removeEventListener("mouseleave", this.mouseleave);
this.view.dom.removeEventListener("mousemove", this.mousemove);
}
};
var tooltipMargin = 4;
function isInTooltip(tooltip, event) {
let { left, right, top: top2, bottom } = tooltip.getBoundingClientRect(), arrow;
if (arrow = tooltip.querySelector(".cm-tooltip-arrow")) {
let arrowRect = arrow.getBoundingClientRect();
top2 = Math.min(arrowRect.top, top2);
bottom = Math.max(arrowRect.bottom, bottom);
}
return event.clientX >= left - tooltipMargin && event.clientX <= right + tooltipMargin && event.clientY >= top2 - tooltipMargin && event.clientY <= bottom + tooltipMargin;
}
function isOverRange(view, from, to, x, y, margin) {
let rect = view.scrollDOM.getBoundingClientRect();
let docBottom = view.documentTop + view.documentPadding.top + view.contentHeight;
if (rect.left > x || rect.right < x || rect.top > y || Math.min(rect.bottom, docBottom) < y)
return false;
let pos = view.posAtCoords({ x, y }, false);
return pos >= from && pos <= to;
}
function hoverTooltip(source, options = {}) {
let setHover = StateEffect.define();
let locked = /* @__PURE__ */ new WeakMap();
let hoverState = StateField.define({
create() {
return [];
},
update(value, tr) {
let lock = locked.get(value);
if (value.length) {
if (options.hideOnChange && (tr.docChanged || tr.selection))
value = [];
else if (lock && lock(tr))
value = [];
else if (options.hideOn)
value = value.filter((v) => !options.hideOn(tr, v));
}
if (tr.docChanged && value.length) {
let mapped = [];
for (let tooltip of value) {
let newPos = tr.changes.mapPos(tooltip.pos, -1, MapMode.TrackDel);
if (newPos != null) {
let copy = Object.assign(/* @__PURE__ */ Object.create(null), tooltip);
copy.pos = newPos;
if (copy.end != null)
copy.end = tr.changes.mapPos(copy.end);
mapped.push(copy);
}
}
value = mapped;
}
for (let effect of tr.effects) {
if (effect.is(setHover)) {
value = effect.value;
lock = void 0;
}
if (effect.is(closeHoverTooltipEffect) && !effect.value || effect.value == hoverState)
value = [];
}
if (value.length && lock)
locked.set(value, lock);
return value;
},
provide: (f) => showHoverTooltip.from(f)
});
const plugin2 = ViewPlugin.define((view) => new HoverPlugin(
view,
source,
hoverState,
locked,
setHover,
options.hoverTime || 300
/* Hover.Time */
));
return {
active: hoverState,
extension: [
hoverState,
plugin2,
hoverPlugin.of(plugin2),
showHoverTooltipHost
]
};
}
function activateHover(view, pos, side, options = {}) {
var _a;
let plugins = view.state.facet(hoverPlugin).map((p) => view.plugin(p)).filter((p) => !!p);
if (options.tooltip && options.tooltip.active) {
let found = plugins.find((p) => p.field == options.tooltip.active);
if (found)
plugins = [found];
}
for (let plugin2 of plugins)
plugin2.activateHover(view, pos, side, (_a = options.until) !== null && _a !== void 0 ? _a : () => false);
}
function getTooltip(view, tooltip) {
let plugin2 = view.plugin(tooltipPlugin);
if (!plugin2)
return null;
let found = plugin2.manager.tooltips.indexOf(tooltip);
return found < 0 ? null : plugin2.manager.tooltipViews[found];
}
function hasHoverTooltips(state) {
return state.facet(showHoverTooltip).some((x) => x);
}
var closeHoverTooltipEffect = StateEffect.define();
var closeHoverTooltips = closeHoverTooltipEffect.of(null);
function closeHoverTooltip(tooltip) {
return closeHoverTooltipEffect.of(tooltip.active);
}
function repositionTooltips(view) {
let plugin2 = view.plugin(tooltipPlugin);
if (plugin2)
plugin2.maybeMeasure();
}
var panelConfig = Facet.define({
combine(configs) {
let topContainer, bottomContainer;
for (let c of configs) {
topContainer = topContainer || c.topContainer;
bottomContainer = bottomContainer || c.bottomContainer;
}
return { topContainer, bottomContainer };
}
});
function panels(config) {
return config ? [panelConfig.of(config)] : [];
}
function getPanel(view, panel) {
let plugin2 = view.plugin(panelPlugin);
let index = plugin2 ? plugin2.specs.indexOf(panel) : -1;
return index > -1 ? plugin2.panels[index] : null;
}
var panelPlugin = ViewPlugin.fromClass(class {
constructor(view) {
this.input = view.state.facet(showPanel);
this.specs = this.input.filter((s) => s);
this.panels = this.specs.map((spec) => spec(view));
let conf = view.state.facet(panelConfig);
this.top = new PanelGroup(view, true, conf.topContainer);
this.bottom = new PanelGroup(view, false, conf.bottomContainer);
this.top.sync(this.panels.filter((p) => p.top));
this.bottom.sync(this.panels.filter((p) => !p.top));
for (let p of this.panels) {
p.dom.classList.add("cm-panel");
if (p.mount)
p.mount();
}
}
update(update) {
let conf = update.state.facet(panelConfig);
if (this.top.container != conf.topContainer) {
this.top.sync([]);
this.top = new PanelGroup(update.view, true, conf.topContainer);
}
if (this.bottom.container != conf.bottomContainer) {
this.bottom.sync([]);
this.bottom = new PanelGroup(update.view, false, conf.bottomContainer);
}
this.top.syncClasses();
this.bottom.syncClasses();
let input = update.state.facet(showPanel);
if (input != this.input) {
let specs = input.filter((x) => x);
let panels2 = [], top2 = [], bottom = [], mount = [];
for (let spec of specs) {
let known = this.specs.indexOf(spec), panel;
if (known < 0) {
panel = spec(update.view);
mount.push(panel);
} else {
panel = this.panels[known];
if (panel.update)
panel.update(update);
}
panels2.push(panel);
(panel.top ? top2 : bottom).push(panel);
}
this.specs = specs;
this.panels = panels2;
this.top.sync(top2);
this.bottom.sync(bottom);
for (let p of mount) {
p.dom.classList.add("cm-panel");
if (p.mount)
p.mount();
}
} else {
for (let p of this.panels)
if (p.update)
p.update(update);
}
}
destroy() {
this.top.sync([]);
this.bottom.sync([]);
}
}, {
provide: (plugin2) => EditorView.scrollMargins.of((view) => {
let value = view.plugin(plugin2);
return value && { top: value.top.scrollMargin(), bottom: value.bottom.scrollMargin() };
})
});
var PanelGroup = class {
constructor(view, top2, container) {
this.view = view;
this.top = top2;
this.container = container;
this.dom = void 0;
this.classes = "";
this.panels = [];
this.syncClasses();
}
sync(panels2) {
for (let p of this.panels)
if (p.destroy && panels2.indexOf(p) < 0)
p.destroy();
this.panels = panels2;
this.syncDOM();
}
syncDOM() {
if (this.panels.length == 0) {
if (this.dom) {
this.dom.remove();
this.dom = void 0;
}
return;
}
if (!this.dom) {
this.dom = document.createElement("div");
this.dom.className = this.top ? "cm-panels cm-panels-top" : "cm-panels cm-panels-bottom";
this.dom.style[this.top ? "top" : "bottom"] = "0";
let parent = this.container || this.view.dom;
parent.insertBefore(this.dom, this.top ? parent.firstChild : null);
}
let curDOM = this.dom.firstChild;
for (let panel of this.panels) {
if (panel.dom.parentNode == this.dom) {
while (curDOM != panel.dom)
curDOM = rm(curDOM);
curDOM = curDOM.nextSibling;
} else {
this.dom.insertBefore(panel.dom, curDOM);
}
}
while (curDOM)
curDOM = rm(curDOM);
}
scrollMargin() {
return !this.dom || this.container ? 0 : Math.max(0, this.top ? this.dom.getBoundingClientRect().bottom - Math.max(0, this.view.scrollDOM.getBoundingClientRect().top) : Math.min(innerHeight, this.view.scrollDOM.getBoundingClientRect().bottom) - this.dom.getBoundingClientRect().top);
}
syncClasses() {
if (!this.container || this.classes == this.view.themeClasses)
return;
for (let cls of this.classes.split(" "))
if (cls)
this.container.classList.remove(cls);
for (let cls of (this.classes = this.view.themeClasses).split(" "))
if (cls)
this.container.classList.add(cls);
}
};
function rm(node) {
let next = node.nextSibling;
node.remove();
return next;
}
var showPanel = Facet.define({
enables: panelPlugin
});
function showDialog(view, config) {
let resolve;
let promise = new Promise((r) => resolve = r);
let panelCtor = (view2) => createDialog(view2, config, resolve);
if (view.state.field(dialogField, false)) {
view.dispatch({ effects: openDialogEffect.of(panelCtor) });
} else {
view.dispatch({ effects: StateEffect.appendConfig.of(dialogField.init(() => [panelCtor])) });
}
let close = closeDialogEffect.of(panelCtor);
return { close, result: promise.then((form) => {
let queue = view.win.queueMicrotask || ((f) => view.win.setTimeout(f, 10));
queue(() => {
if (view.state.field(dialogField).indexOf(panelCtor) > -1)
view.dispatch({ effects: close });
});
return form;
}) };
}
function getDialog(view, className) {
let dialogs = view.state.field(dialogField, false) || [];
for (let open of dialogs) {
let panel = getPanel(view, open);
if (panel && panel.dom.classList.contains(className))
return panel;
}
return null;
}
var dialogField = StateField.define({
create() {
return [];
},
update(dialogs, tr) {
for (let e of tr.effects) {
if (e.is(openDialogEffect))
dialogs = [e.value].concat(dialogs);
else if (e.is(closeDialogEffect))
dialogs = dialogs.filter((d) => d != e.value);
}
return dialogs;
},
provide: (f) => showPanel.computeN([f], (state) => state.field(f))
});
var openDialogEffect = StateEffect.define();
var closeDialogEffect = StateEffect.define();
function createDialog(view, config, result) {
let content = config.content ? config.content(view, () => done(null)) : null;
if (!content) {
content = crelt("form");
if (config.input) {
let input = crelt("input", config.input);
if (/^(text|password|number|email|tel|url)$/.test(input.type))
input.classList.add("cm-textfield");
if (!input.name)
input.name = "input";
content.appendChild(crelt("label", (config.label || "") + ": ", input));
} else {
content.appendChild(document.createTextNode(config.label || ""));
}
content.appendChild(document.createTextNode(" "));
content.appendChild(crelt("button", { class: "cm-button", type: "submit" }, config.submitLabel || "OK"));
}
let forms = content.nodeName == "FORM" ? [content] : content.querySelectorAll("form");
for (let i = 0; i < forms.length; i++) {
let form = forms[i];
form.addEventListener("keydown", (event) => {
if (event.keyCode == 27) {
event.preventDefault();
done(null);
} else if (event.keyCode == 13) {
event.preventDefault();
done(form);
}
});
form.addEventListener("submit", (event) => {
event.preventDefault();
done(form);
});
}
let panel = crelt("div", content, crelt("button", {
onclick: () => done(null),
"aria-label": view.state.phrase("close"),
class: "cm-dialog-close",
type: "button"
}, ["×"]));
if (config.class)
panel.className = config.class;
panel.classList.add("cm-dialog");
function done(form) {
if (panel.contains(panel.ownerDocument.activeElement))
view.focus();
result(form);
}
return {
dom: panel,
top: config.top,
mount: () => {
if (config.focus) {
let focus;
if (typeof config.focus == "string")
focus = content.querySelector(config.focus);
else
focus = content.querySelector("input") || content.querySelector("button");
if (focus && "select" in focus)
focus.select();
else if (focus && "focus" in focus)
focus.focus();
}
}
};
}
var GutterMarker = class extends RangeValue {
/**
@internal
*/
compare(other) {
return this == other || this.constructor == other.constructor && this.eq(other);
}
/**
Compare this marker to another marker of the same type.
*/
eq(other) {
return false;
}
/**
Called if the marker has a `toDOM` method and its representation
was removed from a gutter.
*/
destroy(dom) {
}
};
GutterMarker.prototype.elementClass = "";
GutterMarker.prototype.toDOM = void 0;
GutterMarker.prototype.mapMode = MapMode.TrackBefore;
GutterMarker.prototype.startSide = GutterMarker.prototype.endSide = -1;
GutterMarker.prototype.point = true;
var gutterLineClass = Facet.define();
var gutterWidgetClass = Facet.define();
var defaults = {
class: "",
renderEmptyElements: false,
elementStyle: "",
markers: () => RangeSet.empty,
lineMarker: () => null,
widgetMarker: () => null,
lineMarkerChange: null,
initialSpacer: null,
updateSpacer: null,
domEventHandlers: {},
side: "before"
};
var activeGutters = Facet.define();
function gutter(config) {
return [gutters(), activeGutters.of({ ...defaults, ...config })];
}
var unfixGutters = Facet.define({
combine: (values) => values.some((x) => x)
});
function gutters(config) {
let result = [
gutterView
];
if (config && config.fixed === false)
result.push(unfixGutters.of(true));
return result;
}
var gutterView = ViewPlugin.fromClass(class {
constructor(view) {
this.view = view;
this.domAfter = null;
this.prevViewport = view.viewport;
this.dom = document.createElement("div");
this.dom.className = "cm-gutters cm-gutters-before";
this.dom.setAttribute("aria-hidden", "true");
this.dom.style.minHeight = this.view.contentHeight / this.view.scaleY + "px";
this.gutters = view.state.facet(activeGutters).map((conf) => new SingleGutterView(view, conf));
this.fixed = !view.state.facet(unfixGutters);
for (let gutter2 of this.gutters) {
if (gutter2.config.side == "after")
this.getDOMAfter().appendChild(gutter2.dom);
else
this.dom.appendChild(gutter2.dom);
}
if (this.fixed) {
this.dom.style.position = "sticky";
}
this.syncGutters(false);
view.scrollDOM.insertBefore(this.dom, view.contentDOM);
}
getDOMAfter() {
if (!this.domAfter) {
this.domAfter = document.createElement("div");
this.domAfter.className = "cm-gutters cm-gutters-after";
this.domAfter.setAttribute("aria-hidden", "true");
this.domAfter.style.minHeight = this.view.contentHeight / this.view.scaleY + "px";
this.domAfter.style.position = this.fixed ? "sticky" : "";
this.view.scrollDOM.appendChild(this.domAfter);
}
return this.domAfter;
}
update(update) {
if (this.updateGutters(update)) {
let vpA = this.prevViewport, vpB = update.view.viewport;
let vpOverlap = Math.min(vpA.to, vpB.to) - Math.max(vpA.from, vpB.from);
this.syncGutters(vpOverlap < (vpB.to - vpB.from) * 0.8);
}
if (update.geometryChanged) {
let min = this.view.contentHeight / this.view.scaleY + "px";
this.dom.style.minHeight = min;
if (this.domAfter)
this.domAfter.style.minHeight = min;
}
if (this.view.state.facet(unfixGutters) != !this.fixed) {
this.fixed = !this.fixed;
this.dom.style.position = this.fixed ? "sticky" : "";
if (this.domAfter)
this.domAfter.style.position = this.fixed ? "sticky" : "";
}
this.prevViewport = update.view.viewport;
}
syncGutters(detach) {
let after = this.dom.nextSibling;
if (detach) {
this.dom.remove();
if (this.domAfter)
this.domAfter.remove();
}
let lineClasses = RangeSet.iter(this.view.state.facet(gutterLineClass), this.view.viewport.from);
let classSet = [];
let contexts = this.gutters.map((gutter2) => new UpdateContext(gutter2, this.view.viewport, -this.view.documentPadding.top));
for (let line of this.view.viewportLineBlocks) {
if (classSet.length)
classSet = [];
if (Array.isArray(line.type)) {
let first = true;
for (let b of line.type) {
if (b.type == BlockType.Text && first) {
advanceCursor(lineClasses, classSet, b.from);
for (let cx of contexts)
cx.line(this.view, b, classSet);
first = false;
} else if (b.widget) {
for (let cx of contexts)
cx.widget(this.view, b);
}
}
} else if (line.type == BlockType.Text) {
advanceCursor(lineClasses, classSet, line.from);
for (let cx of contexts)
cx.line(this.view, line, classSet);
} else if (line.widget) {
for (let cx of contexts)
cx.widget(this.view, line);
}
}
for (let cx of contexts)
cx.finish();
if (detach) {
this.view.scrollDOM.insertBefore(this.dom, after);
if (this.domAfter)
this.view.scrollDOM.appendChild(this.domAfter);
}
}
updateGutters(update) {
let prev = update.startState.facet(activeGutters), cur = update.state.facet(activeGutters);
let change = update.docChanged || update.heightChanged || update.viewportChanged || !RangeSet.eq(update.startState.facet(gutterLineClass), update.state.facet(gutterLineClass), update.view.viewport.from, update.view.viewport.to);
if (prev == cur) {
for (let gutter2 of this.gutters)
if (gutter2.update(update))
change = true;
} else {
change = true;
let gutters2 = [];
for (let conf of cur) {
let known = prev.indexOf(conf);
if (known < 0) {
gutters2.push(new SingleGutterView(this.view, conf));
} else {
this.gutters[known].update(update);
gutters2.push(this.gutters[known]);
}
}
for (let g of this.gutters) {
g.dom.remove();
if (gutters2.indexOf(g) < 0)
g.destroy();
}
for (let g of gutters2) {
if (g.config.side == "after")
this.getDOMAfter().appendChild(g.dom);
else
this.dom.appendChild(g.dom);
}
this.gutters = gutters2;
}
return change;
}
destroy() {
for (let view of this.gutters)
view.destroy();
this.dom.remove();
if (this.domAfter)
this.domAfter.remove();
}
}, {
provide: (plugin2) => EditorView.scrollMargins.of((view) => {
let value = view.plugin(plugin2);
if (!value || value.gutters.length == 0 || !value.fixed)
return null;
let before = value.dom.offsetWidth * view.scaleX, after = value.domAfter ? value.domAfter.offsetWidth * view.scaleX : 0;
return view.textDirection == Direction.LTR ? { left: before, right: after } : { right: before, left: after };
})
});
function asArray(val) {
return Array.isArray(val) ? val : [val];
}
function advanceCursor(cursor, collect, pos) {
while (cursor.value && cursor.from <= pos) {
if (cursor.from == pos)
collect.push(cursor.value);
cursor.next();
}
}
var UpdateContext = class {
constructor(gutter2, viewport, height) {
this.gutter = gutter2;
this.height = height;
this.i = 0;
this.cursor = RangeSet.iter(gutter2.markers, viewport.from);
}
addElement(view, block, markers) {
let { gutter: gutter2 } = this, above = (block.top - this.height) / view.scaleY, height = block.height / view.scaleY;
if (this.i == gutter2.elements.length) {
let newElt = new GutterElement(view, height, above, markers);
gutter2.elements.push(newElt);
gutter2.dom.appendChild(newElt.dom);
} else {
gutter2.elements[this.i].update(view, height, above, markers);
}
this.height = block.bottom;
this.i++;
}
line(view, line, extraMarkers) {
let localMarkers = [];
advanceCursor(this.cursor, localMarkers, line.from);
if (extraMarkers.length)
localMarkers = localMarkers.concat(extraMarkers);
let forLine = this.gutter.config.lineMarker(view, line, localMarkers);
if (forLine)
localMarkers.unshift(forLine);
let gutter2 = this.gutter;
if (localMarkers.length == 0 && !gutter2.config.renderEmptyElements)
return;
this.addElement(view, line, localMarkers);
}
widget(view, block) {
let marker = this.gutter.config.widgetMarker(view, block.widget, block), markers = marker ? [marker] : null;
for (let cls of view.state.facet(gutterWidgetClass)) {
let marker2 = cls(view, block.widget, block);
if (marker2)
(markers || (markers = [])).push(marker2);
}
if (markers)
this.addElement(view, block, markers);
}
finish() {
let gutter2 = this.gutter;
while (gutter2.elements.length > this.i) {
let last = gutter2.elements.pop();
gutter2.dom.removeChild(last.dom);
last.destroy();
}
}
};
var SingleGutterView = class {
constructor(view, config) {
this.view = view;
this.config = config;
this.elements = [];
this.spacer = null;
this.dom = document.createElement("div");
this.dom.className = "cm-gutter" + (this.config.class ? " " + this.config.class : "");
for (let prop in config.domEventHandlers) {
this.dom.addEventListener(prop, (event) => {
let target = event.target, y;
if (target != this.dom && this.dom.contains(target)) {
while (target.parentNode != this.dom)
target = target.parentNode;
let rect = target.getBoundingClientRect();
y = (rect.top + rect.bottom) / 2;
} else {
y = event.clientY;
}
let line = view.lineBlockAtHeight(y - view.documentTop);
if (config.domEventHandlers[prop](view, line, event))
event.preventDefault();
});
}
this.markers = asArray(config.markers(view));
if (config.initialSpacer) {
this.spacer = new GutterElement(view, 0, 0, [config.initialSpacer(view)]);
this.dom.appendChild(this.spacer.dom);
this.spacer.dom.style.cssText += "visibility: hidden; pointer-events: none";
}
}
update(update) {
let prevMarkers = this.markers;
this.markers = asArray(this.config.markers(update.view));
if (this.spacer && this.config.updateSpacer) {
let updated = this.config.updateSpacer(this.spacer.markers[0], update);
if (updated != this.spacer.markers[0])
this.spacer.update(update.view, 0, 0, [updated]);
}
let vp = update.view.viewport;
return !RangeSet.eq(this.markers, prevMarkers, vp.from, vp.to) || (this.config.lineMarkerChange ? this.config.lineMarkerChange(update) : false);
}
destroy() {
for (let elt of this.elements)
elt.destroy();
}
};
var GutterElement = class {
constructor(view, height, above, markers) {
this.height = -1;
this.above = 0;
this.markers = [];
this.dom = document.createElement("div");
this.dom.className = "cm-gutterElement";
this.update(view, height, above, markers);
}
update(view, height, above, markers) {
if (this.height != height) {
this.height = height;
this.dom.style.height = height + "px";
}
if (this.above != above)
this.dom.style.marginTop = (this.above = above) ? above + "px" : "";
if (!sameMarkers(this.markers, markers))
this.setMarkers(view, markers);
}
setMarkers(view, markers) {
let cls = "cm-gutterElement", domPos = this.dom.firstChild;
for (let iNew = 0, iOld = 0; ; ) {
let skipTo = iOld, marker = iNew < markers.length ? markers[iNew++] : null, matched = false;
if (marker) {
let c = marker.elementClass;
if (c)
cls += " " + c;
for (let i = iOld; i < this.markers.length; i++)
if (this.markers[i].compare(marker)) {
skipTo = i;
matched = true;
break;
}
} else {
skipTo = this.markers.length;
}
while (iOld < skipTo) {
let next = this.markers[iOld++];
if (next.toDOM) {
next.destroy(domPos);
let after = domPos.nextSibling;
domPos.remove();
domPos = after;
}
}
if (!marker)
break;
if (marker.toDOM) {
if (matched)
domPos = domPos.nextSibling;
else
this.dom.insertBefore(marker.toDOM(view), domPos);
}
if (matched)
iOld++;
}
this.dom.className = cls;
this.markers = markers;
}
destroy() {
this.setMarkers(null, []);
}
};
function sameMarkers(a, b) {
if (a.length != b.length)
return false;
for (let i = 0; i < a.length; i++)
if (!a[i].compare(b[i]))
return false;
return true;
}
var lineNumberMarkers = Facet.define();
var lineNumberWidgetMarker = Facet.define();
var lineNumberConfig = Facet.define({
combine(values) {
return combineConfig(values, { formatNumber: String, domEventHandlers: {} }, {
domEventHandlers(a, b) {
let result = Object.assign({}, a);
for (let event in b) {
let exists = result[event], add2 = b[event];
result[event] = exists ? (view, line, event2) => exists(view, line, event2) || add2(view, line, event2) : add2;
}
return result;
}
});
}
});
var NumberMarker = class extends GutterMarker {
constructor(number) {
super();
this.number = number;
}
eq(other) {
return this.number == other.number;
}
toDOM() {
return document.createTextNode(this.number);
}
};
function formatNumber(view, number) {
return view.state.facet(lineNumberConfig).formatNumber(number, view.state);
}
var lineNumberGutter = activeGutters.compute([lineNumberConfig], (state) => ({
class: "cm-lineNumbers",
renderEmptyElements: false,
markers(view) {
return view.state.facet(lineNumberMarkers);
},
lineMarker(view, line, others) {
if (others.some((m) => m.toDOM))
return null;
return new NumberMarker(formatNumber(view, view.state.doc.lineAt(line.from).number));
},
widgetMarker: (view, widget, block) => {
for (let m of view.state.facet(lineNumberWidgetMarker)) {
let result = m(view, widget, block);
if (result)
return result;
}
return null;
},
lineMarkerChange: (update) => update.startState.facet(lineNumberConfig) != update.state.facet(lineNumberConfig),
initialSpacer(view) {
return new NumberMarker(formatNumber(view, maxLineNumber(view.state.doc.lines)));
},
updateSpacer(spacer, update) {
let max = formatNumber(update.view, maxLineNumber(update.view.state.doc.lines));
return max == spacer.number ? spacer : new NumberMarker(max);
},
domEventHandlers: state.facet(lineNumberConfig).domEventHandlers,
side: "before"
}));
function lineNumbers(config = {}) {
return [
lineNumberConfig.of(config),
gutters(),
lineNumberGutter
];
}
function maxLineNumber(lines) {
let last = 9;
while (last < lines)
last = last * 10 + 9;
return last;
}
var activeLineGutterMarker = new class extends GutterMarker {
constructor() {
super(...arguments);
this.elementClass = "cm-activeLineGutter";
}
}();
var activeLineGutterHighlighter = gutterLineClass.compute(["selection"], (state) => {
let marks = [], last = -1;
for (let range of state.selection.ranges) {
let linePos = state.doc.lineAt(range.head).from;
if (linePos > last) {
last = linePos;
marks.push(activeLineGutterMarker.range(linePos));
}
}
return RangeSet.of(marks);
});
function highlightActiveLineGutter() {
return activeLineGutterHighlighter;
}
function matcher(decorator) {
return ViewPlugin.define((view) => ({
decorations: decorator.createDeco(view),
update(u) {
this.decorations = decorator.updateDeco(u, this.decorations);
}
}), {
decorations: (v) => v.decorations
});
}
var tabDeco = Decoration.mark({ class: "cm-highlightTab" });
var spaceDeco = Decoration.mark({ class: "cm-highlightSpace" });
var whitespaceHighlighter = matcher(new MatchDecorator({
regexp: /\t| /g,
decoration: (match) => match[0] == " " ? tabDeco : spaceDeco,
boundary: /\S/
}));
function highlightWhitespace() {
return whitespaceHighlighter;
}
var trailingHighlighter = matcher(new MatchDecorator({
regexp: /\s+$/g,
decoration: Decoration.mark({ class: "cm-trailingSpace" })
}));
function highlightTrailingWhitespace() {
return trailingHighlighter;
}
var __test = {
HeightMap,
HeightOracle,
MeasuredHeights,
QueryType,
ChangedRange,
computeOrder,
moveVisually,
clearHeightChangeFlag,
getHeightChangeFlag: () => heightChangeFlag
};
export {
StyleModule,
crelt,
WidgetType,
BlockType,
Decoration,
BlockWrapper,
Direction,
BidiSpan,
logException,
ViewPlugin,
ViewUpdate,
BlockInfo,
EditorView,
keymap,
runScopeHandlers,
RectangleMarker,
layer,
drawSelection,
getDrawSelectionConfig,
dropCursor,
MatchDecorator,
highlightSpecialChars,
scrollPastEnd,
highlightActiveLine,
placeholder,
rectangularSelection,
crosshairCursor,
tooltips,
showTooltip,
hoverTooltip,
activateHover,
getTooltip,
hasHoverTooltips,
closeHoverTooltips,
closeHoverTooltip,
repositionTooltips,
panels,
getPanel,
showPanel,
showDialog,
getDialog,
GutterMarker,
gutterLineClass,
gutterWidgetClass,
gutter,
gutters,
lineNumberMarkers,
lineNumberWidgetMarker,
lineNumbers,
highlightActiveLineGutter,
highlightWhitespace,
highlightTrailingWhitespace,
__test
};
//# sourceMappingURL=chunk-M6T3QFJD.js.map