|
import { |
|
Decoration, |
|
Direction, |
|
EditorView, |
|
GutterMarker, |
|
StyleModule, |
|
ViewPlugin, |
|
WidgetType, |
|
gutter, |
|
logException |
|
} from "./chunk-UKXRAEWG.js"; |
|
import { |
|
EditorState, |
|
Facet, |
|
Prec, |
|
RangeSet, |
|
RangeSetBuilder, |
|
StateEffect, |
|
StateField, |
|
combineConfig, |
|
countColumn |
|
} from "./chunk-3BHLKIA4.js"; |
|
|
|
|
|
var DefaultBufferLength = 1024; |
|
var nextPropID = 0; |
|
var Range = class { |
|
constructor(from, to) { |
|
this.from = from; |
|
this.to = to; |
|
} |
|
}; |
|
var NodeProp = class { |
|
|
|
|
|
|
|
constructor(config = {}) { |
|
this.id = nextPropID++; |
|
this.perNode = !!config.perNode; |
|
this.deserialize = config.deserialize || (() => { |
|
throw new Error("This node type doesn't define a deserialize function"); |
|
}); |
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
add(match) { |
|
if (this.perNode) |
|
throw new RangeError("Can't add per-node props to node types"); |
|
if (typeof match != "function") |
|
match = NodeType.match(match); |
|
return (type) => { |
|
let result = match(type); |
|
return result === void 0 ? null : [this, result]; |
|
}; |
|
} |
|
}; |
|
NodeProp.closedBy = new NodeProp({ deserialize: (str) => str.split(" ") }); |
|
NodeProp.openedBy = new NodeProp({ deserialize: (str) => str.split(" ") }); |
|
NodeProp.group = new NodeProp({ deserialize: (str) => str.split(" ") }); |
|
NodeProp.isolate = new NodeProp({ deserialize: (value) => { |
|
if (value && value != "rtl" && value != "ltr" && value != "auto") |
|
throw new RangeError("Invalid value for isolate: " + value); |
|
return value || "auto"; |
|
} }); |
|
NodeProp.contextHash = new NodeProp({ perNode: true }); |
|
NodeProp.lookAhead = new NodeProp({ perNode: true }); |
|
NodeProp.mounted = new NodeProp({ perNode: true }); |
|
var MountedTree = class { |
|
constructor(tree, overlay, parser) { |
|
this.tree = tree; |
|
this.overlay = overlay; |
|
this.parser = parser; |
|
} |
|
|
|
|
|
|
|
static get(tree) { |
|
return tree && tree.props && tree.props[NodeProp.mounted.id]; |
|
} |
|
}; |
|
var noProps = Object.create(null); |
|
var NodeType = class _NodeType { |
|
|
|
|
|
|
|
constructor(name2, props, id, flags = 0) { |
|
this.name = name2; |
|
this.props = props; |
|
this.id = id; |
|
this.flags = flags; |
|
} |
|
|
|
|
|
|
|
static define(spec) { |
|
let props = spec.props && spec.props.length ? Object.create(null) : noProps; |
|
let flags = (spec.top ? 1 : 0) | (spec.skipped ? 2 : 0) | (spec.error ? 4 : 0) | (spec.name == null ? 8 : 0); |
|
let type = new _NodeType(spec.name || "", props, spec.id, flags); |
|
if (spec.props) |
|
for (let src of spec.props) { |
|
if (!Array.isArray(src)) |
|
src = src(type); |
|
if (src) { |
|
if (src[0].perNode) |
|
throw new RangeError("Can't store a per-node prop on a node type"); |
|
props[src[0].id] = src[1]; |
|
} |
|
} |
|
return type; |
|
} |
|
|
|
|
|
|
|
|
|
prop(prop) { |
|
return this.props[prop.id]; |
|
} |
|
|
|
|
|
|
|
get isTop() { |
|
return (this.flags & 1) > 0; |
|
} |
|
|
|
|
|
|
|
get isSkipped() { |
|
return (this.flags & 2) > 0; |
|
} |
|
|
|
|
|
|
|
get isError() { |
|
return (this.flags & 4) > 0; |
|
} |
|
|
|
|
|
|
|
|
|
get isAnonymous() { |
|
return (this.flags & 8) > 0; |
|
} |
|
|
|
|
|
|
|
|
|
is(name2) { |
|
if (typeof name2 == "string") { |
|
if (this.name == name2) |
|
return true; |
|
let group = this.prop(NodeProp.group); |
|
return group ? group.indexOf(name2) > -1 : false; |
|
} |
|
return this.id == name2; |
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
static match(map) { |
|
let direct = Object.create(null); |
|
for (let prop in map) |
|
for (let name2 of prop.split(" ")) |
|
direct[name2] = map[prop]; |
|
return (node) => { |
|
for (let groups = node.prop(NodeProp.group), i = -1; i < (groups ? groups.length : 0); i++) { |
|
let found = direct[i < 0 ? node.name : groups[i]]; |
|
if (found) |
|
return found; |
|
} |
|
}; |
|
} |
|
}; |
|
NodeType.none = new NodeType( |
|
"", |
|
Object.create(null), |
|
0, |
|
8 |
|
|
|
); |
|
var NodeSet = class _NodeSet { |
|
|
|
|
|
|
|
|
|
constructor(types) { |
|
this.types = types; |
|
for (let i = 0; i < types.length; i++) |
|
if (types[i].id != i) |
|
throw new RangeError("Node type ids should correspond to array positions when creating a node set"); |
|
} |
|
|
|
|
|
|
|
|
|
|
|
extend(...props) { |
|
let newTypes = []; |
|
for (let type of this.types) { |
|
let newProps = null; |
|
for (let source of props) { |
|
let add = source(type); |
|
if (add) { |
|
if (!newProps) |
|
newProps = Object.assign({}, type.props); |
|
newProps[add[0].id] = add[1]; |
|
} |
|
} |
|
newTypes.push(newProps ? new NodeType(type.name, newProps, type.id, type.flags) : type); |
|
} |
|
return new _NodeSet(newTypes); |
|
} |
|
}; |
|
var CachedNode = new WeakMap(); |
|
var CachedInnerNode = new WeakMap(); |
|
var IterMode; |
|
(function(IterMode2) { |
|
IterMode2[IterMode2["ExcludeBuffers"] = 1] = "ExcludeBuffers"; |
|
IterMode2[IterMode2["IncludeAnonymous"] = 2] = "IncludeAnonymous"; |
|
IterMode2[IterMode2["IgnoreMounts"] = 4] = "IgnoreMounts"; |
|
IterMode2[IterMode2["IgnoreOverlays"] = 8] = "IgnoreOverlays"; |
|
})(IterMode || (IterMode = {})); |
|
var Tree = class _Tree { |
|
|
|
|
|
|
|
constructor(type, children, positions, length, props) { |
|
this.type = type; |
|
this.children = children; |
|
this.positions = positions; |
|
this.length = length; |
|
this.props = null; |
|
if (props && props.length) { |
|
this.props = Object.create(null); |
|
for (let [prop, value] of props) |
|
this.props[typeof prop == "number" ? prop : prop.id] = value; |
|
} |
|
} |
|
|
|
|
|
|
|
toString() { |
|
let mounted = MountedTree.get(this); |
|
if (mounted && !mounted.overlay) |
|
return mounted.tree.toString(); |
|
let children = ""; |
|
for (let ch of this.children) { |
|
let str = ch.toString(); |
|
if (str) { |
|
if (children) |
|
children += ","; |
|
children += str; |
|
} |
|
} |
|
return !this.type.name ? children : (/\W/.test(this.type.name) && !this.type.isError ? JSON.stringify(this.type.name) : this.type.name) + (children.length ? "(" + children + ")" : ""); |
|
} |
|
|
|
|
|
|
|
|
|
|
|
cursor(mode = 0) { |
|
return new TreeCursor(this.topNode, mode); |
|
} |
|
|
|
|
|
|
|
|
|
|
|
cursorAt(pos, side = 0, mode = 0) { |
|
let scope = CachedNode.get(this) || this.topNode; |
|
let cursor = new TreeCursor(scope); |
|
cursor.moveTo(pos, side); |
|
CachedNode.set(this, cursor._tree); |
|
return cursor; |
|
} |
|
|
|
|
|
|
|
|
|
get topNode() { |
|
return new TreeNode(this, 0, 0, null); |
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
resolve(pos, side = 0) { |
|
let node = resolveNode(CachedNode.get(this) || this.topNode, pos, side, false); |
|
CachedNode.set(this, node); |
|
return node; |
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
resolveInner(pos, side = 0) { |
|
let node = resolveNode(CachedInnerNode.get(this) || this.topNode, pos, side, true); |
|
CachedInnerNode.set(this, node); |
|
return node; |
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
resolveStack(pos, side = 0) { |
|
return stackIterator(this, pos, side); |
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
iterate(spec) { |
|
let { enter, leave, from = 0, to = this.length } = spec; |
|
let mode = spec.mode || 0, anon = (mode & IterMode.IncludeAnonymous) > 0; |
|
for (let c = this.cursor(mode | IterMode.IncludeAnonymous); ; ) { |
|
let entered = false; |
|
if (c.from <= to && c.to >= from && (!anon && c.type.isAnonymous || enter(c) !== false)) { |
|
if (c.firstChild()) |
|
continue; |
|
entered = true; |
|
} |
|
for (; ; ) { |
|
if (entered && leave && (anon || !c.type.isAnonymous)) |
|
leave(c); |
|
if (c.nextSibling()) |
|
break; |
|
if (!c.parent()) |
|
return; |
|
entered = true; |
|
} |
|
} |
|
} |
|
|
|
|
|
|
|
|
|
prop(prop) { |
|
return !prop.perNode ? this.type.prop(prop) : this.props ? this.props[prop.id] : void 0; |
|
} |
|
|
|
|
|
|
|
|
|
|
|
get propValues() { |
|
let result = []; |
|
if (this.props) |
|
for (let id in this.props) |
|
result.push([+id, this.props[id]]); |
|
return result; |
|
} |
|
|
|
|
|
|
|
|
|
|
|
balance(config = {}) { |
|
return this.children.length <= 8 ? this : balanceRange(NodeType.none, this.children, this.positions, 0, this.children.length, 0, this.length, (children, positions, length) => new _Tree(this.type, children, positions, length, this.propValues), config.makeTree || ((children, positions, length) => new _Tree(NodeType.none, children, positions, length))); |
|
} |
|
|
|
|
|
|
|
|
|
static build(data) { |
|
return buildTree(data); |
|
} |
|
}; |
|
Tree.empty = new Tree(NodeType.none, [], [], 0); |
|
var FlatBufferCursor = class _FlatBufferCursor { |
|
constructor(buffer, index) { |
|
this.buffer = buffer; |
|
this.index = index; |
|
} |
|
get id() { |
|
return this.buffer[this.index - 4]; |
|
} |
|
get start() { |
|
return this.buffer[this.index - 3]; |
|
} |
|
get end() { |
|
return this.buffer[this.index - 2]; |
|
} |
|
get size() { |
|
return this.buffer[this.index - 1]; |
|
} |
|
get pos() { |
|
return this.index; |
|
} |
|
next() { |
|
this.index -= 4; |
|
} |
|
fork() { |
|
return new _FlatBufferCursor(this.buffer, this.index); |
|
} |
|
}; |
|
var TreeBuffer = class _TreeBuffer { |
|
|
|
|
|
|
|
constructor(buffer, length, set) { |
|
this.buffer = buffer; |
|
this.length = length; |
|
this.set = set; |
|
} |
|
|
|
|
|
|
|
get type() { |
|
return NodeType.none; |
|
} |
|
|
|
|
|
|
|
toString() { |
|
let result = []; |
|
for (let index = 0; index < this.buffer.length; ) { |
|
result.push(this.childString(index)); |
|
index = this.buffer[index + 3]; |
|
} |
|
return result.join(","); |
|
} |
|
|
|
|
|
|
|
childString(index) { |
|
let id = this.buffer[index], endIndex = this.buffer[index + 3]; |
|
let type = this.set.types[id], result = type.name; |
|
if (/\W/.test(result) && !type.isError) |
|
result = JSON.stringify(result); |
|
index += 4; |
|
if (endIndex == index) |
|
return result; |
|
let children = []; |
|
while (index < endIndex) { |
|
children.push(this.childString(index)); |
|
index = this.buffer[index + 3]; |
|
} |
|
return result + "(" + children.join(",") + ")"; |
|
} |
|
|
|
|
|
|
|
findChild(startIndex, endIndex, dir, pos, side) { |
|
let { buffer } = this, pick = -1; |
|
for (let i = startIndex; i != endIndex; i = buffer[i + 3]) { |
|
if (checkSide(side, pos, buffer[i + 1], buffer[i + 2])) { |
|
pick = i; |
|
if (dir > 0) |
|
break; |
|
} |
|
} |
|
return pick; |
|
} |
|
|
|
|
|
|
|
slice(startI, endI, from) { |
|
let b = this.buffer; |
|
let copy = new Uint16Array(endI - startI), len = 0; |
|
for (let i = startI, j = 0; i < endI; ) { |
|
copy[j++] = b[i++]; |
|
copy[j++] = b[i++] - from; |
|
let to = copy[j++] = b[i++] - from; |
|
copy[j++] = b[i++] - startI; |
|
len = Math.max(len, to); |
|
} |
|
return new _TreeBuffer(copy, len, this.set); |
|
} |
|
}; |
|
function checkSide(side, pos, from, to) { |
|
switch (side) { |
|
case -2: |
|
return from < pos; |
|
case -1: |
|
return to >= pos && from < pos; |
|
case 0: |
|
return from < pos && to > pos; |
|
case 1: |
|
return from <= pos && to > pos; |
|
case 2: |
|
return to > pos; |
|
case 4: |
|
return true; |
|
} |
|
} |
|
function resolveNode(node, pos, side, overlays) { |
|
var _a2; |
|
while (node.from == node.to || (side < 1 ? node.from >= pos : node.from > pos) || (side > -1 ? node.to <= pos : node.to < pos)) { |
|
let parent = !overlays && node instanceof TreeNode && node.index < 0 ? null : node.parent; |
|
if (!parent) |
|
return node; |
|
node = parent; |
|
} |
|
let mode = overlays ? 0 : IterMode.IgnoreOverlays; |
|
if (overlays) |
|
for (let scan = node, parent = scan.parent; parent; scan = parent, parent = scan.parent) { |
|
if (scan instanceof TreeNode && scan.index < 0 && ((_a2 = parent.enter(pos, side, mode)) === null || _a2 === void 0 ? void 0 : _a2.from) != scan.from) |
|
node = parent; |
|
} |
|
for (; ; ) { |
|
let inner = node.enter(pos, side, mode); |
|
if (!inner) |
|
return node; |
|
node = inner; |
|
} |
|
} |
|
var BaseNode = class { |
|
cursor(mode = 0) { |
|
return new TreeCursor(this, mode); |
|
} |
|
getChild(type, before = null, after = null) { |
|
let r = getChildren(this, type, before, after); |
|
return r.length ? r[0] : null; |
|
} |
|
getChildren(type, before = null, after = null) { |
|
return getChildren(this, type, before, after); |
|
} |
|
resolve(pos, side = 0) { |
|
return resolveNode(this, pos, side, false); |
|
} |
|
resolveInner(pos, side = 0) { |
|
return resolveNode(this, pos, side, true); |
|
} |
|
matchContext(context) { |
|
return matchNodeContext(this, context); |
|
} |
|
enterUnfinishedNodesBefore(pos) { |
|
let scan = this.childBefore(pos), node = this; |
|
while (scan) { |
|
let last = scan.lastChild; |
|
if (!last || last.to != scan.to) |
|
break; |
|
if (last.type.isError && last.from == last.to) { |
|
node = scan; |
|
scan = last.prevSibling; |
|
} else { |
|
scan = last; |
|
} |
|
} |
|
return node; |
|
} |
|
get node() { |
|
return this; |
|
} |
|
get next() { |
|
return this.parent; |
|
} |
|
}; |
|
var TreeNode = class _TreeNode extends BaseNode { |
|
constructor(_tree, from, index, _parent) { |
|
super(); |
|
this._tree = _tree; |
|
this.from = from; |
|
this.index = index; |
|
this._parent = _parent; |
|
} |
|
get type() { |
|
return this._tree.type; |
|
} |
|
get name() { |
|
return this._tree.type.name; |
|
} |
|
get to() { |
|
return this.from + this._tree.length; |
|
} |
|
nextChild(i, dir, pos, side, mode = 0) { |
|
for (let parent = this; ; ) { |
|
for (let { children, positions } = parent._tree, e = dir > 0 ? children.length : -1; i != e; i += dir) { |
|
let next = children[i], start = positions[i] + parent.from; |
|
if (!checkSide(side, pos, start, start + next.length)) |
|
continue; |
|
if (next instanceof TreeBuffer) { |
|
if (mode & IterMode.ExcludeBuffers) |
|
continue; |
|
let index = next.findChild(0, next.buffer.length, dir, pos - start, side); |
|
if (index > -1) |
|
return new BufferNode(new BufferContext(parent, next, i, start), null, index); |
|
} else if (mode & IterMode.IncludeAnonymous || (!next.type.isAnonymous || hasChild(next))) { |
|
let mounted; |
|
if (!(mode & IterMode.IgnoreMounts) && (mounted = MountedTree.get(next)) && !mounted.overlay) |
|
return new _TreeNode(mounted.tree, start, i, parent); |
|
let inner = new _TreeNode(next, start, i, parent); |
|
return mode & IterMode.IncludeAnonymous || !inner.type.isAnonymous ? inner : inner.nextChild(dir < 0 ? next.children.length - 1 : 0, dir, pos, side); |
|
} |
|
} |
|
if (mode & IterMode.IncludeAnonymous || !parent.type.isAnonymous) |
|
return null; |
|
if (parent.index >= 0) |
|
i = parent.index + dir; |
|
else |
|
i = dir < 0 ? -1 : parent._parent._tree.children.length; |
|
parent = parent._parent; |
|
if (!parent) |
|
return null; |
|
} |
|
} |
|
get firstChild() { |
|
return this.nextChild( |
|
0, |
|
1, |
|
0, |
|
4 |
|
|
|
); |
|
} |
|
get lastChild() { |
|
return this.nextChild( |
|
this._tree.children.length - 1, |
|
-1, |
|
0, |
|
4 |
|
|
|
); |
|
} |
|
childAfter(pos) { |
|
return this.nextChild( |
|
0, |
|
1, |
|
pos, |
|
2 |
|
|
|
); |
|
} |
|
childBefore(pos) { |
|
return this.nextChild( |
|
this._tree.children.length - 1, |
|
-1, |
|
pos, |
|
-2 |
|
|
|
); |
|
} |
|
enter(pos, side, mode = 0) { |
|
let mounted; |
|
if (!(mode & IterMode.IgnoreOverlays) && (mounted = MountedTree.get(this._tree)) && mounted.overlay) { |
|
let rPos = pos - this.from; |
|
for (let { from, to } of mounted.overlay) { |
|
if ((side > 0 ? from <= rPos : from < rPos) && (side < 0 ? to >= rPos : to > rPos)) |
|
return new _TreeNode(mounted.tree, mounted.overlay[0].from + this.from, -1, this); |
|
} |
|
} |
|
return this.nextChild(0, 1, pos, side, mode); |
|
} |
|
nextSignificantParent() { |
|
let val = this; |
|
while (val.type.isAnonymous && val._parent) |
|
val = val._parent; |
|
return val; |
|
} |
|
get parent() { |
|
return this._parent ? this._parent.nextSignificantParent() : null; |
|
} |
|
get nextSibling() { |
|
return this._parent && this.index >= 0 ? this._parent.nextChild( |
|
this.index + 1, |
|
1, |
|
0, |
|
4 |
|
|
|
) : null; |
|
} |
|
get prevSibling() { |
|
return this._parent && this.index >= 0 ? this._parent.nextChild( |
|
this.index - 1, |
|
-1, |
|
0, |
|
4 |
|
|
|
) : null; |
|
} |
|
get tree() { |
|
return this._tree; |
|
} |
|
toTree() { |
|
return this._tree; |
|
} |
|
|
|
|
|
|
|
toString() { |
|
return this._tree.toString(); |
|
} |
|
}; |
|
function getChildren(node, type, before, after) { |
|
let cur = node.cursor(), result = []; |
|
if (!cur.firstChild()) |
|
return result; |
|
if (before != null) |
|
for (let found = false; !found; ) { |
|
found = cur.type.is(before); |
|
if (!cur.nextSibling()) |
|
return result; |
|
} |
|
for (; ; ) { |
|
if (after != null && cur.type.is(after)) |
|
return result; |
|
if (cur.type.is(type)) |
|
result.push(cur.node); |
|
if (!cur.nextSibling()) |
|
return after == null ? result : []; |
|
} |
|
} |
|
function matchNodeContext(node, context, i = context.length - 1) { |
|
for (let p = node.parent; i >= 0; p = p.parent) { |
|
if (!p) |
|
return false; |
|
if (!p.type.isAnonymous) { |
|
if (context[i] && context[i] != p.name) |
|
return false; |
|
i--; |
|
} |
|
} |
|
return true; |
|
} |
|
var BufferContext = class { |
|
constructor(parent, buffer, index, start) { |
|
this.parent = parent; |
|
this.buffer = buffer; |
|
this.index = index; |
|
this.start = start; |
|
} |
|
}; |
|
var BufferNode = class _BufferNode extends BaseNode { |
|
get name() { |
|
return this.type.name; |
|
} |
|
get from() { |
|
return this.context.start + this.context.buffer.buffer[this.index + 1]; |
|
} |
|
get to() { |
|
return this.context.start + this.context.buffer.buffer[this.index + 2]; |
|
} |
|
constructor(context, _parent, index) { |
|
super(); |
|
this.context = context; |
|
this._parent = _parent; |
|
this.index = index; |
|
this.type = context.buffer.set.types[context.buffer.buffer[index]]; |
|
} |
|
child(dir, pos, side) { |
|
let { buffer } = this.context; |
|
let index = buffer.findChild(this.index + 4, buffer.buffer[this.index + 3], dir, pos - this.context.start, side); |
|
return index < 0 ? null : new _BufferNode(this.context, this, index); |
|
} |
|
get firstChild() { |
|
return this.child( |
|
1, |
|
0, |
|
4 |
|
|
|
); |
|
} |
|
get lastChild() { |
|
return this.child( |
|
-1, |
|
0, |
|
4 |
|
|
|
); |
|
} |
|
childAfter(pos) { |
|
return this.child( |
|
1, |
|
pos, |
|
2 |
|
|
|
); |
|
} |
|
childBefore(pos) { |
|
return this.child( |
|
-1, |
|
pos, |
|
-2 |
|
|
|
); |
|
} |
|
enter(pos, side, mode = 0) { |
|
if (mode & IterMode.ExcludeBuffers) |
|
return null; |
|
let { buffer } = this.context; |
|
let index = buffer.findChild(this.index + 4, buffer.buffer[this.index + 3], side > 0 ? 1 : -1, pos - this.context.start, side); |
|
return index < 0 ? null : new _BufferNode(this.context, this, index); |
|
} |
|
get parent() { |
|
return this._parent || this.context.parent.nextSignificantParent(); |
|
} |
|
externalSibling(dir) { |
|
return this._parent ? null : this.context.parent.nextChild( |
|
this.context.index + dir, |
|
dir, |
|
0, |
|
4 |
|
|
|
); |
|
} |
|
get nextSibling() { |
|
let { buffer } = this.context; |
|
let after = buffer.buffer[this.index + 3]; |
|
if (after < (this._parent ? buffer.buffer[this._parent.index + 3] : buffer.buffer.length)) |
|
return new _BufferNode(this.context, this._parent, after); |
|
return this.externalSibling(1); |
|
} |
|
get prevSibling() { |
|
let { buffer } = this.context; |
|
let parentStart = this._parent ? this._parent.index + 4 : 0; |
|
if (this.index == parentStart) |
|
return this.externalSibling(-1); |
|
return new _BufferNode(this.context, this._parent, buffer.findChild( |
|
parentStart, |
|
this.index, |
|
-1, |
|
0, |
|
4 |
|
|
|
)); |
|
} |
|
get tree() { |
|
return null; |
|
} |
|
toTree() { |
|
let children = [], positions = []; |
|
let { buffer } = this.context; |
|
let startI = this.index + 4, endI = buffer.buffer[this.index + 3]; |
|
if (endI > startI) { |
|
let from = buffer.buffer[this.index + 1]; |
|
children.push(buffer.slice(startI, endI, from)); |
|
positions.push(0); |
|
} |
|
return new Tree(this.type, children, positions, this.to - this.from); |
|
} |
|
|
|
|
|
|
|
toString() { |
|
return this.context.buffer.childString(this.index); |
|
} |
|
}; |
|
function iterStack(heads) { |
|
if (!heads.length) |
|
return null; |
|
let pick = 0, picked = heads[0]; |
|
for (let i = 1; i < heads.length; i++) { |
|
let node = heads[i]; |
|
if (node.from > picked.from || node.to < picked.to) { |
|
picked = node; |
|
pick = i; |
|
} |
|
} |
|
let next = picked instanceof TreeNode && picked.index < 0 ? null : picked.parent; |
|
let newHeads = heads.slice(); |
|
if (next) |
|
newHeads[pick] = next; |
|
else |
|
newHeads.splice(pick, 1); |
|
return new StackIterator(newHeads, picked); |
|
} |
|
var StackIterator = class { |
|
constructor(heads, node) { |
|
this.heads = heads; |
|
this.node = node; |
|
} |
|
get next() { |
|
return iterStack(this.heads); |
|
} |
|
}; |
|
function stackIterator(tree, pos, side) { |
|
let inner = tree.resolveInner(pos, side), layers = null; |
|
for (let scan = inner instanceof TreeNode ? inner : inner.context.parent; scan; scan = scan.parent) { |
|
if (scan.index < 0) { |
|
let parent = scan.parent; |
|
(layers || (layers = [inner])).push(parent.resolve(pos, side)); |
|
scan = parent; |
|
} else { |
|
let mount = MountedTree.get(scan.tree); |
|
if (mount && mount.overlay && mount.overlay[0].from <= pos && mount.overlay[mount.overlay.length - 1].to >= pos) { |
|
let root = new TreeNode(mount.tree, mount.overlay[0].from + scan.from, -1, scan); |
|
(layers || (layers = [inner])).push(resolveNode(root, pos, side, false)); |
|
} |
|
} |
|
} |
|
return layers ? iterStack(layers) : inner; |
|
} |
|
var TreeCursor = class { |
|
|
|
|
|
|
|
get name() { |
|
return this.type.name; |
|
} |
|
|
|
|
|
|
|
constructor(node, mode = 0) { |
|
this.mode = mode; |
|
this.buffer = null; |
|
this.stack = []; |
|
this.index = 0; |
|
this.bufferNode = null; |
|
if (node instanceof TreeNode) { |
|
this.yieldNode(node); |
|
} else { |
|
this._tree = node.context.parent; |
|
this.buffer = node.context; |
|
for (let n = node._parent; n; n = n._parent) |
|
this.stack.unshift(n.index); |
|
this.bufferNode = node; |
|
this.yieldBuf(node.index); |
|
} |
|
} |
|
yieldNode(node) { |
|
if (!node) |
|
return false; |
|
this._tree = node; |
|
this.type = node.type; |
|
this.from = node.from; |
|
this.to = node.to; |
|
return true; |
|
} |
|
yieldBuf(index, type) { |
|
this.index = index; |
|
let { start, buffer } = this.buffer; |
|
this.type = type || buffer.set.types[buffer.buffer[index]]; |
|
this.from = start + buffer.buffer[index + 1]; |
|
this.to = start + buffer.buffer[index + 2]; |
|
return true; |
|
} |
|
|
|
|
|
|
|
yield(node) { |
|
if (!node) |
|
return false; |
|
if (node instanceof TreeNode) { |
|
this.buffer = null; |
|
return this.yieldNode(node); |
|
} |
|
this.buffer = node.context; |
|
return this.yieldBuf(node.index, node.type); |
|
} |
|
|
|
|
|
|
|
toString() { |
|
return this.buffer ? this.buffer.buffer.childString(this.index) : this._tree.toString(); |
|
} |
|
|
|
|
|
|
|
enterChild(dir, pos, side) { |
|
if (!this.buffer) |
|
return this.yield(this._tree.nextChild(dir < 0 ? this._tree._tree.children.length - 1 : 0, dir, pos, side, this.mode)); |
|
let { buffer } = this.buffer; |
|
let index = buffer.findChild(this.index + 4, buffer.buffer[this.index + 3], dir, pos - this.buffer.start, side); |
|
if (index < 0) |
|
return false; |
|
this.stack.push(this.index); |
|
return this.yieldBuf(index); |
|
} |
|
|
|
|
|
|
|
|
|
firstChild() { |
|
return this.enterChild( |
|
1, |
|
0, |
|
4 |
|
|
|
); |
|
} |
|
|
|
|
|
|
|
lastChild() { |
|
return this.enterChild( |
|
-1, |
|
0, |
|
4 |
|
|
|
); |
|
} |
|
|
|
|
|
|
|
childAfter(pos) { |
|
return this.enterChild( |
|
1, |
|
pos, |
|
2 |
|
|
|
); |
|
} |
|
|
|
|
|
|
|
childBefore(pos) { |
|
return this.enterChild( |
|
-1, |
|
pos, |
|
-2 |
|
|
|
); |
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
enter(pos, side, mode = this.mode) { |
|
if (!this.buffer) |
|
return this.yield(this._tree.enter(pos, side, mode)); |
|
return mode & IterMode.ExcludeBuffers ? false : this.enterChild(1, pos, side); |
|
} |
|
|
|
|
|
|
|
parent() { |
|
if (!this.buffer) |
|
return this.yieldNode(this.mode & IterMode.IncludeAnonymous ? this._tree._parent : this._tree.parent); |
|
if (this.stack.length) |
|
return this.yieldBuf(this.stack.pop()); |
|
let parent = this.mode & IterMode.IncludeAnonymous ? this.buffer.parent : this.buffer.parent.nextSignificantParent(); |
|
this.buffer = null; |
|
return this.yieldNode(parent); |
|
} |
|
|
|
|
|
|
|
sibling(dir) { |
|
if (!this.buffer) |
|
return !this._tree._parent ? false : this.yield(this._tree.index < 0 ? null : this._tree._parent.nextChild(this._tree.index + dir, dir, 0, 4, this.mode)); |
|
let { buffer } = this.buffer, d = this.stack.length - 1; |
|
if (dir < 0) { |
|
let parentStart = d < 0 ? 0 : this.stack[d] + 4; |
|
if (this.index != parentStart) |
|
return this.yieldBuf(buffer.findChild( |
|
parentStart, |
|
this.index, |
|
-1, |
|
0, |
|
4 |
|
|
|
)); |
|
} else { |
|
let after = buffer.buffer[this.index + 3]; |
|
if (after < (d < 0 ? buffer.buffer.length : buffer.buffer[this.stack[d] + 3])) |
|
return this.yieldBuf(after); |
|
} |
|
return d < 0 ? this.yield(this.buffer.parent.nextChild(this.buffer.index + dir, dir, 0, 4, this.mode)) : false; |
|
} |
|
|
|
|
|
|
|
nextSibling() { |
|
return this.sibling(1); |
|
} |
|
|
|
|
|
|
|
prevSibling() { |
|
return this.sibling(-1); |
|
} |
|
atLastNode(dir) { |
|
let index, parent, { buffer } = this; |
|
if (buffer) { |
|
if (dir > 0) { |
|
if (this.index < buffer.buffer.buffer.length) |
|
return false; |
|
} else { |
|
for (let i = 0; i < this.index; i++) |
|
if (buffer.buffer.buffer[i + 3] < this.index) |
|
return false; |
|
} |
|
({ index, parent } = buffer); |
|
} else { |
|
({ index, _parent: parent } = this._tree); |
|
} |
|
for (; parent; { index, _parent: parent } = parent) { |
|
if (index > -1) |
|
for (let i = index + dir, e = dir < 0 ? -1 : parent._tree.children.length; i != e; i += dir) { |
|
let child = parent._tree.children[i]; |
|
if (this.mode & IterMode.IncludeAnonymous || child instanceof TreeBuffer || !child.type.isAnonymous || hasChild(child)) |
|
return false; |
|
} |
|
} |
|
return true; |
|
} |
|
move(dir, enter) { |
|
if (enter && this.enterChild( |
|
dir, |
|
0, |
|
4 |
|
|
|
)) |
|
return true; |
|
for (; ; ) { |
|
if (this.sibling(dir)) |
|
return true; |
|
if (this.atLastNode(dir) || !this.parent()) |
|
return false; |
|
} |
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
next(enter = true) { |
|
return this.move(1, enter); |
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
prev(enter = true) { |
|
return this.move(-1, enter); |
|
} |
|
|
|
|
|
|
|
|
|
|
|
moveTo(pos, side = 0) { |
|
while (this.from == this.to || (side < 1 ? this.from >= pos : this.from > pos) || (side > -1 ? this.to <= pos : this.to < pos)) |
|
if (!this.parent()) |
|
break; |
|
while (this.enterChild(1, pos, side)) { |
|
} |
|
return this; |
|
} |
|
|
|
|
|
|
|
|
|
get node() { |
|
if (!this.buffer) |
|
return this._tree; |
|
let cache = this.bufferNode, result = null, depth = 0; |
|
if (cache && cache.context == this.buffer) { |
|
scan: for (let index = this.index, d = this.stack.length; d >= 0; ) { |
|
for (let c = cache; c; c = c._parent) |
|
if (c.index == index) { |
|
if (index == this.index) |
|
return c; |
|
result = c; |
|
depth = d + 1; |
|
break scan; |
|
} |
|
index = this.stack[--d]; |
|
} |
|
} |
|
for (let i = depth; i < this.stack.length; i++) |
|
result = new BufferNode(this.buffer, result, this.stack[i]); |
|
return this.bufferNode = new BufferNode(this.buffer, result, this.index); |
|
} |
|
|
|
|
|
|
|
|
|
|
|
get tree() { |
|
return this.buffer ? null : this._tree._tree; |
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
iterate(enter, leave) { |
|
for (let depth = 0; ; ) { |
|
let mustLeave = false; |
|
if (this.type.isAnonymous || enter(this) !== false) { |
|
if (this.firstChild()) { |
|
depth++; |
|
continue; |
|
} |
|
if (!this.type.isAnonymous) |
|
mustLeave = true; |
|
} |
|
for (; ; ) { |
|
if (mustLeave && leave) |
|
leave(this); |
|
mustLeave = this.type.isAnonymous; |
|
if (this.nextSibling()) |
|
break; |
|
if (!depth) |
|
return; |
|
this.parent(); |
|
depth--; |
|
mustLeave = true; |
|
} |
|
} |
|
} |
|
|
|
|
|
|
|
|
|
|
|
matchContext(context) { |
|
if (!this.buffer) |
|
return matchNodeContext(this.node, context); |
|
let { buffer } = this.buffer, { types } = buffer.set; |
|
for (let i = context.length - 1, d = this.stack.length - 1; i >= 0; d--) { |
|
if (d < 0) |
|
return matchNodeContext(this.node, context, i); |
|
let type = types[buffer.buffer[this.stack[d]]]; |
|
if (!type.isAnonymous) { |
|
if (context[i] && context[i] != type.name) |
|
return false; |
|
i--; |
|
} |
|
} |
|
return true; |
|
} |
|
}; |
|
function hasChild(tree) { |
|
return tree.children.some((ch) => ch instanceof TreeBuffer || !ch.type.isAnonymous || hasChild(ch)); |
|
} |
|
function buildTree(data) { |
|
var _a2; |
|
let { buffer, nodeSet: nodeSet2, maxBufferLength = DefaultBufferLength, reused = [], minRepeatType = nodeSet2.types.length } = data; |
|
let cursor = Array.isArray(buffer) ? new FlatBufferCursor(buffer, buffer.length) : buffer; |
|
let types = nodeSet2.types; |
|
let contextHash = 0, lookAhead = 0; |
|
function takeNode(parentStart, minPos, children2, positions2, inRepeat, depth) { |
|
let { id, start, end, size } = cursor; |
|
let lookAheadAtStart = lookAhead; |
|
while (size < 0) { |
|
cursor.next(); |
|
if (size == -1) { |
|
let node2 = reused[id]; |
|
children2.push(node2); |
|
positions2.push(start - parentStart); |
|
return; |
|
} else if (size == -3) { |
|
contextHash = id; |
|
return; |
|
} else if (size == -4) { |
|
lookAhead = id; |
|
return; |
|
} else { |
|
throw new RangeError(`Unrecognized record size: ${size}`); |
|
} |
|
} |
|
let type = types[id], node, buffer2; |
|
let startPos = start - parentStart; |
|
if (end - start <= maxBufferLength && (buffer2 = findBufferSize(cursor.pos - minPos, inRepeat))) { |
|
let data2 = new Uint16Array(buffer2.size - buffer2.skip); |
|
let endPos = cursor.pos - buffer2.size, index = data2.length; |
|
while (cursor.pos > endPos) |
|
index = copyToBuffer(buffer2.start, data2, index); |
|
node = new TreeBuffer(data2, end - buffer2.start, nodeSet2); |
|
startPos = buffer2.start - parentStart; |
|
} else { |
|
let endPos = cursor.pos - size; |
|
cursor.next(); |
|
let localChildren = [], localPositions = []; |
|
let localInRepeat = id >= minRepeatType ? id : -1; |
|
let lastGroup = 0, lastEnd = end; |
|
while (cursor.pos > endPos) { |
|
if (localInRepeat >= 0 && cursor.id == localInRepeat && cursor.size >= 0) { |
|
if (cursor.end <= lastEnd - maxBufferLength) { |
|
makeRepeatLeaf(localChildren, localPositions, start, lastGroup, cursor.end, lastEnd, localInRepeat, lookAheadAtStart); |
|
lastGroup = localChildren.length; |
|
lastEnd = cursor.end; |
|
} |
|
cursor.next(); |
|
} else if (depth > 2500) { |
|
takeFlatNode(start, endPos, localChildren, localPositions); |
|
} else { |
|
takeNode(start, endPos, localChildren, localPositions, localInRepeat, depth + 1); |
|
} |
|
} |
|
if (localInRepeat >= 0 && lastGroup > 0 && lastGroup < localChildren.length) |
|
makeRepeatLeaf(localChildren, localPositions, start, lastGroup, start, lastEnd, localInRepeat, lookAheadAtStart); |
|
localChildren.reverse(); |
|
localPositions.reverse(); |
|
if (localInRepeat > -1 && lastGroup > 0) { |
|
let make = makeBalanced(type); |
|
node = balanceRange(type, localChildren, localPositions, 0, localChildren.length, 0, end - start, make, make); |
|
} else { |
|
node = makeTree(type, localChildren, localPositions, end - start, lookAheadAtStart - end); |
|
} |
|
} |
|
children2.push(node); |
|
positions2.push(startPos); |
|
} |
|
function takeFlatNode(parentStart, minPos, children2, positions2) { |
|
let nodes = []; |
|
let nodeCount = 0, stopAt = -1; |
|
while (cursor.pos > minPos) { |
|
let { id, start, end, size } = cursor; |
|
if (size > 4) { |
|
cursor.next(); |
|
} else if (stopAt > -1 && start < stopAt) { |
|
break; |
|
} else { |
|
if (stopAt < 0) |
|
stopAt = end - maxBufferLength; |
|
nodes.push(id, start, end); |
|
nodeCount++; |
|
cursor.next(); |
|
} |
|
} |
|
if (nodeCount) { |
|
let buffer2 = new Uint16Array(nodeCount * 4); |
|
let start = nodes[nodes.length - 2]; |
|
for (let i = nodes.length - 3, j = 0; i >= 0; i -= 3) { |
|
buffer2[j++] = nodes[i]; |
|
buffer2[j++] = nodes[i + 1] - start; |
|
buffer2[j++] = nodes[i + 2] - start; |
|
buffer2[j++] = j; |
|
} |
|
children2.push(new TreeBuffer(buffer2, nodes[2] - start, nodeSet2)); |
|
positions2.push(start - parentStart); |
|
} |
|
} |
|
function makeBalanced(type) { |
|
return (children2, positions2, length2) => { |
|
let lookAhead2 = 0, lastI = children2.length - 1, last, lookAheadProp; |
|
if (lastI >= 0 && (last = children2[lastI]) instanceof Tree) { |
|
if (!lastI && last.type == type && last.length == length2) |
|
return last; |
|
if (lookAheadProp = last.prop(NodeProp.lookAhead)) |
|
lookAhead2 = positions2[lastI] + last.length + lookAheadProp; |
|
} |
|
return makeTree(type, children2, positions2, length2, lookAhead2); |
|
}; |
|
} |
|
function makeRepeatLeaf(children2, positions2, base, i, from, to, type, lookAhead2) { |
|
let localChildren = [], localPositions = []; |
|
while (children2.length > i) { |
|
localChildren.push(children2.pop()); |
|
localPositions.push(positions2.pop() + base - from); |
|
} |
|
children2.push(makeTree(nodeSet2.types[type], localChildren, localPositions, to - from, lookAhead2 - to)); |
|
positions2.push(from - base); |
|
} |
|
function makeTree(type, children2, positions2, length2, lookAhead2 = 0, props) { |
|
if (contextHash) { |
|
let pair = [NodeProp.contextHash, contextHash]; |
|
props = props ? [pair].concat(props) : [pair]; |
|
} |
|
if (lookAhead2 > 25) { |
|
let pair = [NodeProp.lookAhead, lookAhead2]; |
|
props = props ? [pair].concat(props) : [pair]; |
|
} |
|
return new Tree(type, children2, positions2, length2, props); |
|
} |
|
function findBufferSize(maxSize, inRepeat) { |
|
let fork = cursor.fork(); |
|
let size = 0, start = 0, skip = 0, minStart = fork.end - maxBufferLength; |
|
let result = { size: 0, start: 0, skip: 0 }; |
|
scan: for (let minPos = fork.pos - maxSize; fork.pos > minPos; ) { |
|
let nodeSize2 = fork.size; |
|
if (fork.id == inRepeat && nodeSize2 >= 0) { |
|
result.size = size; |
|
result.start = start; |
|
result.skip = skip; |
|
skip += 4; |
|
size += 4; |
|
fork.next(); |
|
continue; |
|
} |
|
let startPos = fork.pos - nodeSize2; |
|
if (nodeSize2 < 0 || startPos < minPos || fork.start < minStart) |
|
break; |
|
let localSkipped = fork.id >= minRepeatType ? 4 : 0; |
|
let nodeStart = fork.start; |
|
fork.next(); |
|
while (fork.pos > startPos) { |
|
if (fork.size < 0) { |
|
if (fork.size == -3) |
|
localSkipped += 4; |
|
else |
|
break scan; |
|
} else if (fork.id >= minRepeatType) { |
|
localSkipped += 4; |
|
} |
|
fork.next(); |
|
} |
|
start = nodeStart; |
|
size += nodeSize2; |
|
skip += localSkipped; |
|
} |
|
if (inRepeat < 0 || size == maxSize) { |
|
result.size = size; |
|
result.start = start; |
|
result.skip = skip; |
|
} |
|
return result.size > 4 ? result : void 0; |
|
} |
|
function copyToBuffer(bufferStart, buffer2, index) { |
|
let { id, start, end, size } = cursor; |
|
cursor.next(); |
|
if (size >= 0 && id < minRepeatType) { |
|
let startIndex = index; |
|
if (size > 4) { |
|
let endPos = cursor.pos - (size - 4); |
|
while (cursor.pos > endPos) |
|
index = copyToBuffer(bufferStart, buffer2, index); |
|
} |
|
buffer2[--index] = startIndex; |
|
buffer2[--index] = end - bufferStart; |
|
buffer2[--index] = start - bufferStart; |
|
buffer2[--index] = id; |
|
} else if (size == -3) { |
|
contextHash = id; |
|
} else if (size == -4) { |
|
lookAhead = id; |
|
} |
|
return index; |
|
} |
|
let children = [], positions = []; |
|
while (cursor.pos > 0) |
|
takeNode(data.start || 0, data.bufferStart || 0, children, positions, -1, 0); |
|
let length = (_a2 = data.length) !== null && _a2 !== void 0 ? _a2 : children.length ? positions[0] + children[0].length : 0; |
|
return new Tree(types[data.topID], children.reverse(), positions.reverse(), length); |
|
} |
|
var nodeSizeCache = new WeakMap(); |
|
function nodeSize(balanceType, node) { |
|
if (!balanceType.isAnonymous || node instanceof TreeBuffer || node.type != balanceType) |
|
return 1; |
|
let size = nodeSizeCache.get(node); |
|
if (size == null) { |
|
size = 1; |
|
for (let child of node.children) { |
|
if (child.type != balanceType || !(child instanceof Tree)) { |
|
size = 1; |
|
break; |
|
} |
|
size += nodeSize(balanceType, child); |
|
} |
|
nodeSizeCache.set(node, size); |
|
} |
|
return size; |
|
} |
|
function balanceRange(balanceType, children, positions, from, to, start, length, mkTop, mkTree) { |
|
let total = 0; |
|
for (let i = from; i < to; i++) |
|
total += nodeSize(balanceType, children[i]); |
|
let maxChild = Math.ceil( |
|
total * 1.5 / 8 |
|
|
|
); |
|
let localChildren = [], localPositions = []; |
|
function divide(children2, positions2, from2, to2, offset) { |
|
for (let i = from2; i < to2; ) { |
|
let groupFrom = i, groupStart = positions2[i], groupSize = nodeSize(balanceType, children2[i]); |
|
i++; |
|
for (; i < to2; i++) { |
|
let nextSize = nodeSize(balanceType, children2[i]); |
|
if (groupSize + nextSize >= maxChild) |
|
break; |
|
groupSize += nextSize; |
|
} |
|
if (i == groupFrom + 1) { |
|
if (groupSize > maxChild) { |
|
let only = children2[groupFrom]; |
|
divide(only.children, only.positions, 0, only.children.length, positions2[groupFrom] + offset); |
|
continue; |
|
} |
|
localChildren.push(children2[groupFrom]); |
|
} else { |
|
let length2 = positions2[i - 1] + children2[i - 1].length - groupStart; |
|
localChildren.push(balanceRange(balanceType, children2, positions2, groupFrom, i, groupStart, length2, null, mkTree)); |
|
} |
|
localPositions.push(groupStart + offset - start); |
|
} |
|
} |
|
divide(children, positions, from, to, 0); |
|
return (mkTop || mkTree)(localChildren, localPositions, length); |
|
} |
|
var NodeWeakMap = class { |
|
constructor() { |
|
this.map = new WeakMap(); |
|
} |
|
setBuffer(buffer, index, value) { |
|
let inner = this.map.get(buffer); |
|
if (!inner) |
|
this.map.set(buffer, inner = new Map()); |
|
inner.set(index, value); |
|
} |
|
getBuffer(buffer, index) { |
|
let inner = this.map.get(buffer); |
|
return inner && inner.get(index); |
|
} |
|
|
|
|
|
|
|
set(node, value) { |
|
if (node instanceof BufferNode) |
|
this.setBuffer(node.context.buffer, node.index, value); |
|
else if (node instanceof TreeNode) |
|
this.map.set(node.tree, value); |
|
} |
|
|
|
|
|
|
|
get(node) { |
|
return node instanceof BufferNode ? this.getBuffer(node.context.buffer, node.index) : node instanceof TreeNode ? this.map.get(node.tree) : void 0; |
|
} |
|
|
|
|
|
|
|
cursorSet(cursor, value) { |
|
if (cursor.buffer) |
|
this.setBuffer(cursor.buffer.buffer, cursor.index, value); |
|
else |
|
this.map.set(cursor.tree, value); |
|
} |
|
|
|
|
|
|
|
|
|
cursorGet(cursor) { |
|
return cursor.buffer ? this.getBuffer(cursor.buffer.buffer, cursor.index) : this.map.get(cursor.tree); |
|
} |
|
}; |
|
var TreeFragment = class _TreeFragment { |
|
|
|
|
|
|
|
|
|
|
|
|
|
constructor(from, to, tree, offset, openStart = false, openEnd = false) { |
|
this.from = from; |
|
this.to = to; |
|
this.tree = tree; |
|
this.offset = offset; |
|
this.open = (openStart ? 1 : 0) | (openEnd ? 2 : 0); |
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
get openStart() { |
|
return (this.open & 1) > 0; |
|
} |
|
|
|
|
|
|
|
|
|
get openEnd() { |
|
return (this.open & 2) > 0; |
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
static addTree(tree, fragments = [], partial = false) { |
|
let result = [new _TreeFragment(0, tree.length, tree, 0, false, partial)]; |
|
for (let f of fragments) |
|
if (f.to > tree.length) |
|
result.push(f); |
|
return result; |
|
} |
|
|
|
|
|
|
|
|
|
|
|
static applyChanges(fragments, changes, minGap = 128) { |
|
if (!changes.length) |
|
return fragments; |
|
let result = []; |
|
let fI = 1, nextF = fragments.length ? fragments[0] : null; |
|
for (let cI = 0, pos = 0, off = 0; ; cI++) { |
|
let nextC = cI < changes.length ? changes[cI] : null; |
|
let nextPos = nextC ? nextC.fromA : 1e9; |
|
if (nextPos - pos >= minGap) |
|
while (nextF && nextF.from < nextPos) { |
|
let cut = nextF; |
|
if (pos >= cut.from || nextPos <= cut.to || off) { |
|
let fFrom = Math.max(cut.from, pos) - off, fTo = Math.min(cut.to, nextPos) - off; |
|
cut = fFrom >= fTo ? null : new _TreeFragment(fFrom, fTo, cut.tree, cut.offset + off, cI > 0, !!nextC); |
|
} |
|
if (cut) |
|
result.push(cut); |
|
if (nextF.to > nextPos) |
|
break; |
|
nextF = fI < fragments.length ? fragments[fI++] : null; |
|
} |
|
if (!nextC) |
|
break; |
|
pos = nextC.toA; |
|
off = nextC.toA - nextC.toB; |
|
} |
|
return result; |
|
} |
|
}; |
|
var Parser = class { |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
startParse(input, fragments, ranges) { |
|
if (typeof input == "string") |
|
input = new StringInput(input); |
|
ranges = !ranges ? [new Range(0, input.length)] : ranges.length ? ranges.map((r) => new Range(r.from, r.to)) : [new Range(0, 0)]; |
|
return this.createParse(input, fragments || [], ranges); |
|
} |
|
|
|
|
|
|
|
parse(input, fragments, ranges) { |
|
let parse = this.startParse(input, fragments, ranges); |
|
for (; ; ) { |
|
let done = parse.advance(); |
|
if (done) |
|
return done; |
|
} |
|
} |
|
}; |
|
var StringInput = class { |
|
constructor(string2) { |
|
this.string = string2; |
|
} |
|
get length() { |
|
return this.string.length; |
|
} |
|
chunk(from) { |
|
return this.string.slice(from); |
|
} |
|
get lineChunks() { |
|
return false; |
|
} |
|
read(from, to) { |
|
return this.string.slice(from, to); |
|
} |
|
}; |
|
var stoppedInner = new NodeProp({ perNode: true }); |
|
|
|
|
|
var nextTagID = 0; |
|
var Tag = class _Tag { |
|
|
|
|
|
|
|
constructor(set, base, modified) { |
|
this.set = set; |
|
this.base = base; |
|
this.modified = modified; |
|
this.id = nextTagID++; |
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
static define(parent) { |
|
if (parent === null || parent === void 0 ? void 0 : parent.base) |
|
throw new Error("Can not derive from a modified tag"); |
|
let tag = new _Tag([], null, []); |
|
tag.set.push(tag); |
|
if (parent) |
|
for (let t2 of parent.set) |
|
tag.set.push(t2); |
|
return tag; |
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
static defineModifier() { |
|
let mod = new Modifier(); |
|
return (tag) => { |
|
if (tag.modified.indexOf(mod) > -1) |
|
return tag; |
|
return Modifier.get(tag.base || tag, tag.modified.concat(mod).sort((a, b) => a.id - b.id)); |
|
}; |
|
} |
|
}; |
|
var nextModifierID = 0; |
|
var Modifier = class _Modifier { |
|
constructor() { |
|
this.instances = []; |
|
this.id = nextModifierID++; |
|
} |
|
static get(base, mods) { |
|
if (!mods.length) |
|
return base; |
|
let exists = mods[0].instances.find((t2) => t2.base == base && sameArray(mods, t2.modified)); |
|
if (exists) |
|
return exists; |
|
let set = [], tag = new Tag(set, base, mods); |
|
for (let m of mods) |
|
m.instances.push(tag); |
|
let configs = powerSet(mods); |
|
for (let parent of base.set) |
|
if (!parent.modified.length) |
|
for (let config of configs) |
|
set.push(_Modifier.get(parent, config)); |
|
return tag; |
|
} |
|
}; |
|
function sameArray(a, b) { |
|
return a.length == b.length && a.every((x, i) => x == b[i]); |
|
} |
|
function powerSet(array) { |
|
let sets = [[]]; |
|
for (let i = 0; i < array.length; i++) { |
|
for (let j = 0, e = sets.length; j < e; j++) { |
|
sets.push(sets[j].concat(array[i])); |
|
} |
|
} |
|
return sets.sort((a, b) => b.length - a.length); |
|
} |
|
function styleTags(spec) { |
|
let byName = Object.create(null); |
|
for (let prop in spec) { |
|
let tags2 = spec[prop]; |
|
if (!Array.isArray(tags2)) |
|
tags2 = [tags2]; |
|
for (let part of prop.split(" ")) |
|
if (part) { |
|
let pieces = [], mode = 2, rest = part; |
|
for (let pos = 0; ; ) { |
|
if (rest == "..." && pos > 0 && pos + 3 == part.length) { |
|
mode = 1; |
|
break; |
|
} |
|
let m = /^"(?:[^"\\]|\\.)*?"|[^\/!]+/.exec(rest); |
|
if (!m) |
|
throw new RangeError("Invalid path: " + part); |
|
pieces.push(m[0] == "*" ? "" : m[0][0] == '"' ? JSON.parse(m[0]) : m[0]); |
|
pos += m[0].length; |
|
if (pos == part.length) |
|
break; |
|
let next = part[pos++]; |
|
if (pos == part.length && next == "!") { |
|
mode = 0; |
|
break; |
|
} |
|
if (next != "/") |
|
throw new RangeError("Invalid path: " + part); |
|
rest = part.slice(pos); |
|
} |
|
let last = pieces.length - 1, inner = pieces[last]; |
|
if (!inner) |
|
throw new RangeError("Invalid path: " + part); |
|
let rule = new Rule(tags2, mode, last > 0 ? pieces.slice(0, last) : null); |
|
byName[inner] = rule.sort(byName[inner]); |
|
} |
|
} |
|
return ruleNodeProp.add(byName); |
|
} |
|
var ruleNodeProp = new NodeProp(); |
|
var Rule = class { |
|
constructor(tags2, mode, context, next) { |
|
this.tags = tags2; |
|
this.mode = mode; |
|
this.context = context; |
|
this.next = next; |
|
} |
|
get opaque() { |
|
return this.mode == 0; |
|
} |
|
get inherit() { |
|
return this.mode == 1; |
|
} |
|
sort(other) { |
|
if (!other || other.depth < this.depth) { |
|
this.next = other; |
|
return this; |
|
} |
|
other.next = this.sort(other.next); |
|
return other; |
|
} |
|
get depth() { |
|
return this.context ? this.context.length : 0; |
|
} |
|
}; |
|
Rule.empty = new Rule([], 2, null); |
|
function tagHighlighter(tags2, options) { |
|
let map = Object.create(null); |
|
for (let style of tags2) { |
|
if (!Array.isArray(style.tag)) |
|
map[style.tag.id] = style.class; |
|
else |
|
for (let tag of style.tag) |
|
map[tag.id] = style.class; |
|
} |
|
let { scope, all = null } = options || {}; |
|
return { |
|
style: (tags3) => { |
|
let cls = all; |
|
for (let tag of tags3) { |
|
for (let sub of tag.set) { |
|
let tagClass = map[sub.id]; |
|
if (tagClass) { |
|
cls = cls ? cls + " " + tagClass : tagClass; |
|
break; |
|
} |
|
} |
|
} |
|
return cls; |
|
}, |
|
scope |
|
}; |
|
} |
|
function highlightTags(highlighters, tags2) { |
|
let result = null; |
|
for (let highlighter of highlighters) { |
|
let value = highlighter.style(tags2); |
|
if (value) |
|
result = result ? result + " " + value : value; |
|
} |
|
return result; |
|
} |
|
function highlightTree(tree, highlighter, putStyle, from = 0, to = tree.length) { |
|
let builder = new HighlightBuilder(from, Array.isArray(highlighter) ? highlighter : [highlighter], putStyle); |
|
builder.highlightRange(tree.cursor(), from, to, "", builder.highlighters); |
|
builder.flush(to); |
|
} |
|
var HighlightBuilder = class { |
|
constructor(at, highlighters, span) { |
|
this.at = at; |
|
this.highlighters = highlighters; |
|
this.span = span; |
|
this.class = ""; |
|
} |
|
startSpan(at, cls) { |
|
if (cls != this.class) { |
|
this.flush(at); |
|
if (at > this.at) |
|
this.at = at; |
|
this.class = cls; |
|
} |
|
} |
|
flush(to) { |
|
if (to > this.at && this.class) |
|
this.span(this.at, to, this.class); |
|
} |
|
highlightRange(cursor, from, to, inheritedClass, highlighters) { |
|
let { type, from: start, to: end } = cursor; |
|
if (start >= to || end <= from) |
|
return; |
|
if (type.isTop) |
|
highlighters = this.highlighters.filter((h) => !h.scope || h.scope(type)); |
|
let cls = inheritedClass; |
|
let rule = getStyleTags(cursor) || Rule.empty; |
|
let tagCls = highlightTags(highlighters, rule.tags); |
|
if (tagCls) { |
|
if (cls) |
|
cls += " "; |
|
cls += tagCls; |
|
if (rule.mode == 1) |
|
inheritedClass += (inheritedClass ? " " : "") + tagCls; |
|
} |
|
this.startSpan(Math.max(from, start), cls); |
|
if (rule.opaque) |
|
return; |
|
let mounted = cursor.tree && cursor.tree.prop(NodeProp.mounted); |
|
if (mounted && mounted.overlay) { |
|
let inner = cursor.node.enter(mounted.overlay[0].from + start, 1); |
|
let innerHighlighters = this.highlighters.filter((h) => !h.scope || h.scope(mounted.tree.type)); |
|
let hasChild2 = cursor.firstChild(); |
|
for (let i = 0, pos = start; ; i++) { |
|
let next = i < mounted.overlay.length ? mounted.overlay[i] : null; |
|
let nextPos = next ? next.from + start : end; |
|
let rangeFrom = Math.max(from, pos), rangeTo = Math.min(to, nextPos); |
|
if (rangeFrom < rangeTo && hasChild2) { |
|
while (cursor.from < rangeTo) { |
|
this.highlightRange(cursor, rangeFrom, rangeTo, inheritedClass, highlighters); |
|
this.startSpan(Math.min(rangeTo, cursor.to), cls); |
|
if (cursor.to >= nextPos || !cursor.nextSibling()) |
|
break; |
|
} |
|
} |
|
if (!next || nextPos > to) |
|
break; |
|
pos = next.to + start; |
|
if (pos > from) { |
|
this.highlightRange(inner.cursor(), Math.max(from, next.from + start), Math.min(to, pos), "", innerHighlighters); |
|
this.startSpan(Math.min(to, pos), cls); |
|
} |
|
} |
|
if (hasChild2) |
|
cursor.parent(); |
|
} else if (cursor.firstChild()) { |
|
if (mounted) |
|
inheritedClass = ""; |
|
do { |
|
if (cursor.to <= from) |
|
continue; |
|
if (cursor.from >= to) |
|
break; |
|
this.highlightRange(cursor, from, to, inheritedClass, highlighters); |
|
this.startSpan(Math.min(to, cursor.to), cls); |
|
} while (cursor.nextSibling()); |
|
cursor.parent(); |
|
} |
|
} |
|
}; |
|
function getStyleTags(node) { |
|
let rule = node.type.prop(ruleNodeProp); |
|
while (rule && rule.context && !node.matchContext(rule.context)) |
|
rule = rule.next; |
|
return rule || null; |
|
} |
|
var t = Tag.define; |
|
var comment = t(); |
|
var name = t(); |
|
var typeName = t(name); |
|
var propertyName = t(name); |
|
var literal = t(); |
|
var string = t(literal); |
|
var number = t(literal); |
|
var content = t(); |
|
var heading = t(content); |
|
var keyword = t(); |
|
var operator = t(); |
|
var punctuation = t(); |
|
var bracket = t(punctuation); |
|
var meta = t(); |
|
var tags = { |
|
|
|
|
|
|
|
comment, |
|
|
|
|
|
|
|
lineComment: t(comment), |
|
|
|
|
|
|
|
blockComment: t(comment), |
|
|
|
|
|
|
|
docComment: t(comment), |
|
|
|
|
|
|
|
name, |
|
|
|
|
|
|
|
variableName: t(name), |
|
|
|
|
|
|
|
typeName, |
|
|
|
|
|
|
|
tagName: t(typeName), |
|
|
|
|
|
|
|
propertyName, |
|
|
|
|
|
|
|
attributeName: t(propertyName), |
|
|
|
|
|
|
|
className: t(name), |
|
|
|
|
|
|
|
labelName: t(name), |
|
|
|
|
|
|
|
namespace: t(name), |
|
|
|
|
|
|
|
macroName: t(name), |
|
|
|
|
|
|
|
literal, |
|
|
|
|
|
|
|
string, |
|
|
|
|
|
|
|
docString: t(string), |
|
|
|
|
|
|
|
character: t(string), |
|
|
|
|
|
|
|
attributeValue: t(string), |
|
|
|
|
|
|
|
number, |
|
|
|
|
|
|
|
integer: t(number), |
|
|
|
|
|
|
|
float: t(number), |
|
|
|
|
|
|
|
bool: t(literal), |
|
|
|
|
|
|
|
regexp: t(literal), |
|
|
|
|
|
|
|
|
|
escape: t(literal), |
|
|
|
|
|
|
|
color: t(literal), |
|
|
|
|
|
|
|
url: t(literal), |
|
|
|
|
|
|
|
keyword, |
|
|
|
|
|
|
|
|
|
self: t(keyword), |
|
|
|
|
|
|
|
null: t(keyword), |
|
|
|
|
|
|
|
atom: t(keyword), |
|
|
|
|
|
|
|
unit: t(keyword), |
|
|
|
|
|
|
|
modifier: t(keyword), |
|
|
|
|
|
|
|
operatorKeyword: t(keyword), |
|
|
|
|
|
|
|
controlKeyword: t(keyword), |
|
|
|
|
|
|
|
definitionKeyword: t(keyword), |
|
|
|
|
|
|
|
|
|
moduleKeyword: t(keyword), |
|
|
|
|
|
|
|
operator, |
|
|
|
|
|
|
|
derefOperator: t(operator), |
|
|
|
|
|
|
|
arithmeticOperator: t(operator), |
|
|
|
|
|
|
|
logicOperator: t(operator), |
|
|
|
|
|
|
|
bitwiseOperator: t(operator), |
|
|
|
|
|
|
|
compareOperator: t(operator), |
|
|
|
|
|
|
|
updateOperator: t(operator), |
|
|
|
|
|
|
|
definitionOperator: t(operator), |
|
|
|
|
|
|
|
typeOperator: t(operator), |
|
|
|
|
|
|
|
controlOperator: t(operator), |
|
|
|
|
|
|
|
punctuation, |
|
|
|
|
|
|
|
|
|
separator: t(punctuation), |
|
|
|
|
|
|
|
bracket, |
|
|
|
|
|
|
|
|
|
angleBracket: t(bracket), |
|
|
|
|
|
|
|
|
|
squareBracket: t(bracket), |
|
|
|
|
|
|
|
|
|
paren: t(bracket), |
|
|
|
|
|
|
|
|
|
brace: t(bracket), |
|
|
|
|
|
|
|
content, |
|
|
|
|
|
|
|
heading, |
|
|
|
|
|
|
|
heading1: t(heading), |
|
|
|
|
|
|
|
heading2: t(heading), |
|
|
|
|
|
|
|
heading3: t(heading), |
|
|
|
|
|
|
|
heading4: t(heading), |
|
|
|
|
|
|
|
heading5: t(heading), |
|
|
|
|
|
|
|
heading6: t(heading), |
|
|
|
|
|
|
|
contentSeparator: t(content), |
|
|
|
|
|
|
|
list: t(content), |
|
|
|
|
|
|
|
quote: t(content), |
|
|
|
|
|
|
|
emphasis: t(content), |
|
|
|
|
|
|
|
strong: t(content), |
|
|
|
|
|
|
|
link: t(content), |
|
|
|
|
|
|
|
|
|
monospace: t(content), |
|
|
|
|
|
|
|
|
|
strikethrough: t(content), |
|
|
|
|
|
|
|
inserted: t(), |
|
|
|
|
|
|
|
deleted: t(), |
|
|
|
|
|
|
|
changed: t(), |
|
|
|
|
|
|
|
invalid: t(), |
|
|
|
|
|
|
|
meta, |
|
|
|
|
|
|
|
|
|
documentMeta: t(meta), |
|
|
|
|
|
|
|
|
|
annotation: t(meta), |
|
|
|
|
|
|
|
|
|
processingInstruction: t(meta), |
|
|
|
|
|
|
|
|
|
|
|
definition: Tag.defineModifier(), |
|
|
|
|
|
|
|
|
|
|
|
constant: Tag.defineModifier(), |
|
|
|
|
|
|
|
|
|
|
|
|
|
function: Tag.defineModifier(), |
|
|
|
|
|
|
|
|
|
|
|
standard: Tag.defineModifier(), |
|
|
|
|
|
|
|
|
|
local: Tag.defineModifier(), |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
special: Tag.defineModifier() |
|
}; |
|
var classHighlighter = tagHighlighter([ |
|
{ tag: tags.link, class: "tok-link" }, |
|
{ tag: tags.heading, class: "tok-heading" }, |
|
{ tag: tags.emphasis, class: "tok-emphasis" }, |
|
{ tag: tags.strong, class: "tok-strong" }, |
|
{ tag: tags.keyword, class: "tok-keyword" }, |
|
{ tag: tags.atom, class: "tok-atom" }, |
|
{ tag: tags.bool, class: "tok-bool" }, |
|
{ tag: tags.url, class: "tok-url" }, |
|
{ tag: tags.labelName, class: "tok-labelName" }, |
|
{ tag: tags.inserted, class: "tok-inserted" }, |
|
{ tag: tags.deleted, class: "tok-deleted" }, |
|
{ tag: tags.literal, class: "tok-literal" }, |
|
{ tag: tags.string, class: "tok-string" }, |
|
{ tag: tags.number, class: "tok-number" }, |
|
{ tag: [tags.regexp, tags.escape, tags.special(tags.string)], class: "tok-string2" }, |
|
{ tag: tags.variableName, class: "tok-variableName" }, |
|
{ tag: tags.local(tags.variableName), class: "tok-variableName tok-local" }, |
|
{ tag: tags.definition(tags.variableName), class: "tok-variableName tok-definition" }, |
|
{ tag: tags.special(tags.variableName), class: "tok-variableName2" }, |
|
{ tag: tags.definition(tags.propertyName), class: "tok-propertyName tok-definition" }, |
|
{ tag: tags.typeName, class: "tok-typeName" }, |
|
{ tag: tags.namespace, class: "tok-namespace" }, |
|
{ tag: tags.className, class: "tok-className" }, |
|
{ tag: tags.macroName, class: "tok-macroName" }, |
|
{ tag: tags.propertyName, class: "tok-propertyName" }, |
|
{ tag: tags.operator, class: "tok-operator" }, |
|
{ tag: tags.comment, class: "tok-comment" }, |
|
{ tag: tags.meta, class: "tok-meta" }, |
|
{ tag: tags.invalid, class: "tok-invalid" }, |
|
{ tag: tags.punctuation, class: "tok-punctuation" } |
|
]); |
|
|
|
|
|
var _a; |
|
var languageDataProp = new NodeProp(); |
|
function defineLanguageFacet(baseData) { |
|
return Facet.define({ |
|
combine: baseData ? (values) => values.concat(baseData) : void 0 |
|
}); |
|
} |
|
var sublanguageProp = new NodeProp(); |
|
var Language = class { |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
constructor(data, parser, extraExtensions = [], name2 = "") { |
|
this.data = data; |
|
this.name = name2; |
|
if (!EditorState.prototype.hasOwnProperty("tree")) |
|
Object.defineProperty(EditorState.prototype, "tree", { get() { |
|
return syntaxTree(this); |
|
} }); |
|
this.parser = parser; |
|
this.extension = [ |
|
language.of(this), |
|
EditorState.languageData.of((state, pos, side) => { |
|
let top = topNodeAt(state, pos, side), data2 = top.type.prop(languageDataProp); |
|
if (!data2) |
|
return []; |
|
let base = state.facet(data2), sub = top.type.prop(sublanguageProp); |
|
if (sub) { |
|
let innerNode = top.resolve(pos - top.from, side); |
|
for (let sublang of sub) |
|
if (sublang.test(innerNode, state)) { |
|
let data3 = state.facet(sublang.facet); |
|
return sublang.type == "replace" ? data3 : data3.concat(base); |
|
} |
|
} |
|
return base; |
|
}) |
|
].concat(extraExtensions); |
|
} |
|
|
|
|
|
|
|
isActiveAt(state, pos, side = -1) { |
|
return topNodeAt(state, pos, side).type.prop(languageDataProp) == this.data; |
|
} |
|
|
|
|
|
|
|
|
|
|
|
findRegions(state) { |
|
let lang = state.facet(language); |
|
if ((lang === null || lang === void 0 ? void 0 : lang.data) == this.data) |
|
return [{ from: 0, to: state.doc.length }]; |
|
if (!lang || !lang.allowsNesting) |
|
return []; |
|
let result = []; |
|
let explore = (tree, from) => { |
|
if (tree.prop(languageDataProp) == this.data) { |
|
result.push({ from, to: from + tree.length }); |
|
return; |
|
} |
|
let mount = tree.prop(NodeProp.mounted); |
|
if (mount) { |
|
if (mount.tree.prop(languageDataProp) == this.data) { |
|
if (mount.overlay) |
|
for (let r of mount.overlay) |
|
result.push({ from: r.from + from, to: r.to + from }); |
|
else |
|
result.push({ from, to: from + tree.length }); |
|
return; |
|
} else if (mount.overlay) { |
|
let size = result.length; |
|
explore(mount.tree, mount.overlay[0].from + from); |
|
if (result.length > size) |
|
return; |
|
} |
|
} |
|
for (let i = 0; i < tree.children.length; i++) { |
|
let ch = tree.children[i]; |
|
if (ch instanceof Tree) |
|
explore(ch, tree.positions[i] + from); |
|
} |
|
}; |
|
explore(syntaxTree(state), 0); |
|
return result; |
|
} |
|
|
|
|
|
|
|
|
|
get allowsNesting() { |
|
return true; |
|
} |
|
}; |
|
Language.setState = StateEffect.define(); |
|
function topNodeAt(state, pos, side) { |
|
let topLang = state.facet(language), tree = syntaxTree(state).topNode; |
|
if (!topLang || topLang.allowsNesting) { |
|
for (let node = tree; node; node = node.enter(pos, side, IterMode.ExcludeBuffers)) |
|
if (node.type.isTop) |
|
tree = node; |
|
} |
|
return tree; |
|
} |
|
var LRLanguage = class _LRLanguage extends Language { |
|
constructor(data, parser, name2) { |
|
super(data, parser, [], name2); |
|
this.parser = parser; |
|
} |
|
|
|
|
|
|
|
static define(spec) { |
|
let data = defineLanguageFacet(spec.languageData); |
|
return new _LRLanguage(data, spec.parser.configure({ |
|
props: [languageDataProp.add((type) => type.isTop ? data : void 0)] |
|
}), spec.name); |
|
} |
|
|
|
|
|
|
|
|
|
configure(options, name2) { |
|
return new _LRLanguage(this.data, this.parser.configure(options), name2 || this.name); |
|
} |
|
get allowsNesting() { |
|
return this.parser.hasWrappers(); |
|
} |
|
}; |
|
function syntaxTree(state) { |
|
let field = state.field(Language.state, false); |
|
return field ? field.tree : Tree.empty; |
|
} |
|
function ensureSyntaxTree(state, upto, timeout = 50) { |
|
var _a2; |
|
let parse = (_a2 = state.field(Language.state, false)) === null || _a2 === void 0 ? void 0 : _a2.context; |
|
if (!parse) |
|
return null; |
|
let oldVieport = parse.viewport; |
|
parse.updateViewport({ from: 0, to: upto }); |
|
let result = parse.isDone(upto) || parse.work(timeout, upto) ? parse.tree : null; |
|
parse.updateViewport(oldVieport); |
|
return result; |
|
} |
|
function syntaxTreeAvailable(state, upto = state.doc.length) { |
|
var _a2; |
|
return ((_a2 = state.field(Language.state, false)) === null || _a2 === void 0 ? void 0 : _a2.context.isDone(upto)) || false; |
|
} |
|
function forceParsing(view, upto = view.viewport.to, timeout = 100) { |
|
let success = ensureSyntaxTree(view.state, upto, timeout); |
|
if (success != syntaxTree(view.state)) |
|
view.dispatch({}); |
|
return !!success; |
|
} |
|
function syntaxParserRunning(view) { |
|
var _a2; |
|
return ((_a2 = view.plugin(parseWorker)) === null || _a2 === void 0 ? void 0 : _a2.isWorking()) || false; |
|
} |
|
var DocInput = class { |
|
|
|
|
|
|
|
constructor(doc) { |
|
this.doc = doc; |
|
this.cursorPos = 0; |
|
this.string = ""; |
|
this.cursor = doc.iter(); |
|
} |
|
get length() { |
|
return this.doc.length; |
|
} |
|
syncTo(pos) { |
|
this.string = this.cursor.next(pos - this.cursorPos).value; |
|
this.cursorPos = pos + this.string.length; |
|
return this.cursorPos - this.string.length; |
|
} |
|
chunk(pos) { |
|
this.syncTo(pos); |
|
return this.string; |
|
} |
|
get lineChunks() { |
|
return true; |
|
} |
|
read(from, to) { |
|
let stringStart = this.cursorPos - this.string.length; |
|
if (from < stringStart || to >= this.cursorPos) |
|
return this.doc.sliceString(from, to); |
|
else |
|
return this.string.slice(from - stringStart, to - stringStart); |
|
} |
|
}; |
|
var currentContext = null; |
|
var ParseContext = class _ParseContext { |
|
constructor(parser, state, fragments = [], tree, treeLen, viewport, skipped, scheduleOn) { |
|
this.parser = parser; |
|
this.state = state; |
|
this.fragments = fragments; |
|
this.tree = tree; |
|
this.treeLen = treeLen; |
|
this.viewport = viewport; |
|
this.skipped = skipped; |
|
this.scheduleOn = scheduleOn; |
|
this.parse = null; |
|
this.tempSkipped = []; |
|
} |
|
|
|
|
|
|
|
static create(parser, state, viewport) { |
|
return new _ParseContext(parser, state, [], Tree.empty, 0, viewport, [], null); |
|
} |
|
startParse() { |
|
return this.parser.startParse(new DocInput(this.state.doc), this.fragments); |
|
} |
|
|
|
|
|
|
|
work(until, upto) { |
|
if (upto != null && upto >= this.state.doc.length) |
|
upto = void 0; |
|
if (this.tree != Tree.empty && this.isDone(upto !== null && upto !== void 0 ? upto : this.state.doc.length)) { |
|
this.takeTree(); |
|
return true; |
|
} |
|
return this.withContext(() => { |
|
var _a2; |
|
if (typeof until == "number") { |
|
let endTime = Date.now() + until; |
|
until = () => Date.now() > endTime; |
|
} |
|
if (!this.parse) |
|
this.parse = this.startParse(); |
|
if (upto != null && (this.parse.stoppedAt == null || this.parse.stoppedAt > upto) && upto < this.state.doc.length) |
|
this.parse.stopAt(upto); |
|
for (; ; ) { |
|
let done = this.parse.advance(); |
|
if (done) { |
|
this.fragments = this.withoutTempSkipped(TreeFragment.addTree(done, this.fragments, this.parse.stoppedAt != null)); |
|
this.treeLen = (_a2 = this.parse.stoppedAt) !== null && _a2 !== void 0 ? _a2 : this.state.doc.length; |
|
this.tree = done; |
|
this.parse = null; |
|
if (this.treeLen < (upto !== null && upto !== void 0 ? upto : this.state.doc.length)) |
|
this.parse = this.startParse(); |
|
else |
|
return true; |
|
} |
|
if (until()) |
|
return false; |
|
} |
|
}); |
|
} |
|
|
|
|
|
|
|
takeTree() { |
|
let pos, tree; |
|
if (this.parse && (pos = this.parse.parsedPos) >= this.treeLen) { |
|
if (this.parse.stoppedAt == null || this.parse.stoppedAt > pos) |
|
this.parse.stopAt(pos); |
|
this.withContext(() => { |
|
while (!(tree = this.parse.advance())) { |
|
} |
|
}); |
|
this.treeLen = pos; |
|
this.tree = tree; |
|
this.fragments = this.withoutTempSkipped(TreeFragment.addTree(this.tree, this.fragments, true)); |
|
this.parse = null; |
|
} |
|
} |
|
withContext(f) { |
|
let prev = currentContext; |
|
currentContext = this; |
|
try { |
|
return f(); |
|
} finally { |
|
currentContext = prev; |
|
} |
|
} |
|
withoutTempSkipped(fragments) { |
|
for (let r; r = this.tempSkipped.pop(); ) |
|
fragments = cutFragments(fragments, r.from, r.to); |
|
return fragments; |
|
} |
|
|
|
|
|
|
|
changes(changes, newState) { |
|
let { fragments, tree, treeLen, viewport, skipped } = this; |
|
this.takeTree(); |
|
if (!changes.empty) { |
|
let ranges = []; |
|
changes.iterChangedRanges((fromA, toA, fromB, toB) => ranges.push({ fromA, toA, fromB, toB })); |
|
fragments = TreeFragment.applyChanges(fragments, ranges); |
|
tree = Tree.empty; |
|
treeLen = 0; |
|
viewport = { from: changes.mapPos(viewport.from, -1), to: changes.mapPos(viewport.to, 1) }; |
|
if (this.skipped.length) { |
|
skipped = []; |
|
for (let r of this.skipped) { |
|
let from = changes.mapPos(r.from, 1), to = changes.mapPos(r.to, -1); |
|
if (from < to) |
|
skipped.push({ from, to }); |
|
} |
|
} |
|
} |
|
return new _ParseContext(this.parser, newState, fragments, tree, treeLen, viewport, skipped, this.scheduleOn); |
|
} |
|
|
|
|
|
|
|
updateViewport(viewport) { |
|
if (this.viewport.from == viewport.from && this.viewport.to == viewport.to) |
|
return false; |
|
this.viewport = viewport; |
|
let startLen = this.skipped.length; |
|
for (let i = 0; i < this.skipped.length; i++) { |
|
let { from, to } = this.skipped[i]; |
|
if (from < viewport.to && to > viewport.from) { |
|
this.fragments = cutFragments(this.fragments, from, to); |
|
this.skipped.splice(i--, 1); |
|
} |
|
} |
|
if (this.skipped.length >= startLen) |
|
return false; |
|
this.reset(); |
|
return true; |
|
} |
|
|
|
|
|
|
|
reset() { |
|
if (this.parse) { |
|
this.takeTree(); |
|
this.parse = null; |
|
} |
|
} |
|
|
|
|
|
|
|
|
|
|
|
skipUntilInView(from, to) { |
|
this.skipped.push({ from, to }); |
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
static getSkippingParser(until) { |
|
return new class extends Parser { |
|
createParse(input, fragments, ranges) { |
|
let from = ranges[0].from, to = ranges[ranges.length - 1].to; |
|
let parser = { |
|
parsedPos: from, |
|
advance() { |
|
let cx = currentContext; |
|
if (cx) { |
|
for (let r of ranges) |
|
cx.tempSkipped.push(r); |
|
if (until) |
|
cx.scheduleOn = cx.scheduleOn ? Promise.all([cx.scheduleOn, until]) : until; |
|
} |
|
this.parsedPos = to; |
|
return new Tree(NodeType.none, [], [], to - from); |
|
}, |
|
stoppedAt: null, |
|
stopAt() { |
|
} |
|
}; |
|
return parser; |
|
} |
|
}(); |
|
} |
|
|
|
|
|
|
|
isDone(upto) { |
|
upto = Math.min(upto, this.state.doc.length); |
|
let frags = this.fragments; |
|
return this.treeLen >= upto && frags.length && frags[0].from == 0 && frags[0].to >= upto; |
|
} |
|
|
|
|
|
|
|
|
|
static get() { |
|
return currentContext; |
|
} |
|
}; |
|
function cutFragments(fragments, from, to) { |
|
return TreeFragment.applyChanges(fragments, [{ fromA: from, toA: to, fromB: from, toB: to }]); |
|
} |
|
var LanguageState = class _LanguageState { |
|
constructor(context) { |
|
this.context = context; |
|
this.tree = context.tree; |
|
} |
|
apply(tr) { |
|
if (!tr.docChanged && this.tree == this.context.tree) |
|
return this; |
|
let newCx = this.context.changes(tr.changes, tr.state); |
|
let upto = this.context.treeLen == tr.startState.doc.length ? void 0 : Math.max(tr.changes.mapPos(this.context.treeLen), newCx.viewport.to); |
|
if (!newCx.work(20, upto)) |
|
newCx.takeTree(); |
|
return new _LanguageState(newCx); |
|
} |
|
static init(state) { |
|
let vpTo = Math.min(3e3, state.doc.length); |
|
let parseState = ParseContext.create(state.facet(language).parser, state, { from: 0, to: vpTo }); |
|
if (!parseState.work(20, vpTo)) |
|
parseState.takeTree(); |
|
return new _LanguageState(parseState); |
|
} |
|
}; |
|
Language.state = StateField.define({ |
|
create: LanguageState.init, |
|
update(value, tr) { |
|
for (let e of tr.effects) |
|
if (e.is(Language.setState)) |
|
return e.value; |
|
if (tr.startState.facet(language) != tr.state.facet(language)) |
|
return LanguageState.init(tr.state); |
|
return value.apply(tr); |
|
} |
|
}); |
|
var requestIdle = (callback) => { |
|
let timeout = setTimeout( |
|
() => callback(), |
|
500 |
|
|
|
); |
|
return () => clearTimeout(timeout); |
|
}; |
|
if (typeof requestIdleCallback != "undefined") |
|
requestIdle = (callback) => { |
|
let idle = -1, timeout = setTimeout( |
|
() => { |
|
idle = requestIdleCallback(callback, { |
|
timeout: 500 - 100 |
|
|
|
}); |
|
}, |
|
100 |
|
|
|
); |
|
return () => idle < 0 ? clearTimeout(timeout) : cancelIdleCallback(idle); |
|
}; |
|
var isInputPending = typeof navigator != "undefined" && ((_a = navigator.scheduling) === null || _a === void 0 ? void 0 : _a.isInputPending) ? () => navigator.scheduling.isInputPending() : null; |
|
var parseWorker = ViewPlugin.fromClass(class ParseWorker { |
|
constructor(view) { |
|
this.view = view; |
|
this.working = null; |
|
this.workScheduled = 0; |
|
this.chunkEnd = -1; |
|
this.chunkBudget = -1; |
|
this.work = this.work.bind(this); |
|
this.scheduleWork(); |
|
} |
|
update(update) { |
|
let cx = this.view.state.field(Language.state).context; |
|
if (cx.updateViewport(update.view.viewport) || this.view.viewport.to > cx.treeLen) |
|
this.scheduleWork(); |
|
if (update.docChanged || update.selectionSet) { |
|
if (this.view.hasFocus) |
|
this.chunkBudget += 50; |
|
this.scheduleWork(); |
|
} |
|
this.checkAsyncSchedule(cx); |
|
} |
|
scheduleWork() { |
|
if (this.working) |
|
return; |
|
let { state } = this.view, field = state.field(Language.state); |
|
if (field.tree != field.context.tree || !field.context.isDone(state.doc.length)) |
|
this.working = requestIdle(this.work); |
|
} |
|
work(deadline) { |
|
this.working = null; |
|
let now = Date.now(); |
|
if (this.chunkEnd < now && (this.chunkEnd < 0 || this.view.hasFocus)) { |
|
this.chunkEnd = now + 3e4; |
|
this.chunkBudget = 3e3; |
|
} |
|
if (this.chunkBudget <= 0) |
|
return; |
|
let { state, viewport: { to: vpTo } } = this.view, field = state.field(Language.state); |
|
if (field.tree == field.context.tree && field.context.isDone( |
|
vpTo + 1e5 |
|
|
|
)) |
|
return; |
|
let endTime = Date.now() + Math.min(this.chunkBudget, 100, deadline && !isInputPending ? Math.max(25, deadline.timeRemaining() - 5) : 1e9); |
|
let viewportFirst = field.context.treeLen < vpTo && state.doc.length > vpTo + 1e3; |
|
let done = field.context.work(() => { |
|
return isInputPending && isInputPending() || Date.now() > endTime; |
|
}, vpTo + (viewportFirst ? 0 : 1e5)); |
|
this.chunkBudget -= Date.now() - now; |
|
if (done || this.chunkBudget <= 0) { |
|
field.context.takeTree(); |
|
this.view.dispatch({ effects: Language.setState.of(new LanguageState(field.context)) }); |
|
} |
|
if (this.chunkBudget > 0 && !(done && !viewportFirst)) |
|
this.scheduleWork(); |
|
this.checkAsyncSchedule(field.context); |
|
} |
|
checkAsyncSchedule(cx) { |
|
if (cx.scheduleOn) { |
|
this.workScheduled++; |
|
cx.scheduleOn.then(() => this.scheduleWork()).catch((err) => logException(this.view.state, err)).then(() => this.workScheduled--); |
|
cx.scheduleOn = null; |
|
} |
|
} |
|
destroy() { |
|
if (this.working) |
|
this.working(); |
|
} |
|
isWorking() { |
|
return !!(this.working || this.workScheduled > 0); |
|
} |
|
}, { |
|
eventHandlers: { focus() { |
|
this.scheduleWork(); |
|
} } |
|
}); |
|
var language = Facet.define({ |
|
combine(languages) { |
|
return languages.length ? languages[0] : null; |
|
}, |
|
enables: (language2) => [ |
|
Language.state, |
|
parseWorker, |
|
EditorView.contentAttributes.compute([language2], (state) => { |
|
let lang = state.facet(language2); |
|
return lang && lang.name ? { "data-language": lang.name } : {}; |
|
}) |
|
] |
|
}); |
|
var LanguageSupport = class { |
|
|
|
|
|
|
|
constructor(language2, support = []) { |
|
this.language = language2; |
|
this.support = support; |
|
this.extension = [language2, support]; |
|
} |
|
}; |
|
var LanguageDescription = class _LanguageDescription { |
|
constructor(name2, alias, extensions, filename, loadFunc, support = void 0) { |
|
this.name = name2; |
|
this.alias = alias; |
|
this.extensions = extensions; |
|
this.filename = filename; |
|
this.loadFunc = loadFunc; |
|
this.support = support; |
|
this.loading = null; |
|
} |
|
|
|
|
|
|
|
|
|
|
|
load() { |
|
return this.loading || (this.loading = this.loadFunc().then((support) => this.support = support, (err) => { |
|
this.loading = null; |
|
throw err; |
|
})); |
|
} |
|
|
|
|
|
|
|
static of(spec) { |
|
let { load, support } = spec; |
|
if (!load) { |
|
if (!support) |
|
throw new RangeError("Must pass either 'load' or 'support' to LanguageDescription.of"); |
|
load = () => Promise.resolve(support); |
|
} |
|
return new _LanguageDescription(spec.name, (spec.alias || []).concat(spec.name).map((s) => s.toLowerCase()), spec.extensions || [], spec.filename, load, support); |
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
static matchFilename(descs, filename) { |
|
for (let d of descs) |
|
if (d.filename && d.filename.test(filename)) |
|
return d; |
|
let ext = /\.([^.]+)$/.exec(filename); |
|
if (ext) { |
|
for (let d of descs) |
|
if (d.extensions.indexOf(ext[1]) > -1) |
|
return d; |
|
} |
|
return null; |
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
static matchLanguageName(descs, name2, fuzzy = true) { |
|
name2 = name2.toLowerCase(); |
|
for (let d of descs) |
|
if (d.alias.some((a) => a == name2)) |
|
return d; |
|
if (fuzzy) |
|
for (let d of descs) |
|
for (let a of d.alias) { |
|
let found = name2.indexOf(a); |
|
if (found > -1 && (a.length > 2 || !/\w/.test(name2[found - 1]) && !/\w/.test(name2[found + a.length]))) |
|
return d; |
|
} |
|
return null; |
|
} |
|
}; |
|
var indentService = Facet.define(); |
|
var indentUnit = Facet.define({ |
|
combine: (values) => { |
|
if (!values.length) |
|
return " "; |
|
let unit = values[0]; |
|
if (!unit || /\S/.test(unit) || Array.from(unit).some((e) => e != unit[0])) |
|
throw new Error("Invalid indent unit: " + JSON.stringify(values[0])); |
|
return unit; |
|
} |
|
}); |
|
function getIndentUnit(state) { |
|
let unit = state.facet(indentUnit); |
|
return unit.charCodeAt(0) == 9 ? state.tabSize * unit.length : unit.length; |
|
} |
|
function indentString(state, cols) { |
|
let result = "", ts = state.tabSize, ch = state.facet(indentUnit)[0]; |
|
if (ch == " ") { |
|
while (cols >= ts) { |
|
result += " "; |
|
cols -= ts; |
|
} |
|
ch = " "; |
|
} |
|
for (let i = 0; i < cols; i++) |
|
result += ch; |
|
return result; |
|
} |
|
function getIndentation(context, pos) { |
|
if (context instanceof EditorState) |
|
context = new IndentContext(context); |
|
for (let service of context.state.facet(indentService)) { |
|
let result = service(context, pos); |
|
if (result !== void 0) |
|
return result; |
|
} |
|
let tree = syntaxTree(context.state); |
|
return tree.length >= pos ? syntaxIndentation(context, tree, pos) : null; |
|
} |
|
function indentRange(state, from, to) { |
|
let updated = Object.create(null); |
|
let context = new IndentContext(state, { overrideIndentation: (start) => { |
|
var _a2; |
|
return (_a2 = updated[start]) !== null && _a2 !== void 0 ? _a2 : -1; |
|
} }); |
|
let changes = []; |
|
for (let pos = from; pos <= to; ) { |
|
let line = state.doc.lineAt(pos); |
|
pos = line.to + 1; |
|
let indent = getIndentation(context, line.from); |
|
if (indent == null) |
|
continue; |
|
if (!/\S/.test(line.text)) |
|
indent = 0; |
|
let cur = /^\s*/.exec(line.text)[0]; |
|
let norm = indentString(state, indent); |
|
if (cur != norm) { |
|
updated[line.from] = indent; |
|
changes.push({ from: line.from, to: line.from + cur.length, insert: norm }); |
|
} |
|
} |
|
return state.changes(changes); |
|
} |
|
var IndentContext = class { |
|
|
|
|
|
|
|
constructor(state, options = {}) { |
|
this.state = state; |
|
this.options = options; |
|
this.unit = getIndentUnit(state); |
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
lineAt(pos, bias = 1) { |
|
let line = this.state.doc.lineAt(pos); |
|
let { simulateBreak, simulateDoubleBreak } = this.options; |
|
if (simulateBreak != null && simulateBreak >= line.from && simulateBreak <= line.to) { |
|
if (simulateDoubleBreak && simulateBreak == pos) |
|
return { text: "", from: pos }; |
|
else if (bias < 0 ? simulateBreak < pos : simulateBreak <= pos) |
|
return { text: line.text.slice(simulateBreak - line.from), from: simulateBreak }; |
|
else |
|
return { text: line.text.slice(0, simulateBreak - line.from), from: line.from }; |
|
} |
|
return line; |
|
} |
|
|
|
|
|
|
|
|
|
textAfterPos(pos, bias = 1) { |
|
if (this.options.simulateDoubleBreak && pos == this.options.simulateBreak) |
|
return ""; |
|
let { text, from } = this.lineAt(pos, bias); |
|
return text.slice(pos - from, Math.min(text.length, pos + 100 - from)); |
|
} |
|
|
|
|
|
|
|
column(pos, bias = 1) { |
|
let { text, from } = this.lineAt(pos, bias); |
|
let result = this.countColumn(text, pos - from); |
|
let override = this.options.overrideIndentation ? this.options.overrideIndentation(from) : -1; |
|
if (override > -1) |
|
result += override - this.countColumn(text, text.search(/\S|$/)); |
|
return result; |
|
} |
|
|
|
|
|
|
|
|
|
countColumn(line, pos = line.length) { |
|
return countColumn(line, this.state.tabSize, pos); |
|
} |
|
|
|
|
|
|
|
lineIndent(pos, bias = 1) { |
|
let { text, from } = this.lineAt(pos, bias); |
|
let override = this.options.overrideIndentation; |
|
if (override) { |
|
let overriden = override(from); |
|
if (overriden > -1) |
|
return overriden; |
|
} |
|
return this.countColumn(text, text.search(/\S|$/)); |
|
} |
|
|
|
|
|
|
|
|
|
|
|
get simulatedBreak() { |
|
return this.options.simulateBreak || null; |
|
} |
|
}; |
|
var indentNodeProp = new NodeProp(); |
|
function syntaxIndentation(cx, ast, pos) { |
|
let stack = ast.resolveStack(pos); |
|
let inner = stack.node.enterUnfinishedNodesBefore(pos); |
|
if (inner != stack.node) { |
|
let add = []; |
|
for (let cur = inner; cur != stack.node; cur = cur.parent) |
|
add.push(cur); |
|
for (let i = add.length - 1; i >= 0; i--) |
|
stack = { node: add[i], next: stack }; |
|
} |
|
return indentFor(stack, cx, pos); |
|
} |
|
function indentFor(stack, cx, pos) { |
|
for (let cur = stack; cur; cur = cur.next) { |
|
let strategy = indentStrategy(cur.node); |
|
if (strategy) |
|
return strategy(TreeIndentContext.create(cx, pos, cur)); |
|
} |
|
return 0; |
|
} |
|
function ignoreClosed(cx) { |
|
return cx.pos == cx.options.simulateBreak && cx.options.simulateDoubleBreak; |
|
} |
|
function indentStrategy(tree) { |
|
let strategy = tree.type.prop(indentNodeProp); |
|
if (strategy) |
|
return strategy; |
|
let first = tree.firstChild, close; |
|
if (first && (close = first.type.prop(NodeProp.closedBy))) { |
|
let last = tree.lastChild, closed = last && close.indexOf(last.name) > -1; |
|
return (cx) => delimitedStrategy(cx, true, 1, void 0, closed && !ignoreClosed(cx) ? last.from : void 0); |
|
} |
|
return tree.parent == null ? topIndent : null; |
|
} |
|
function topIndent() { |
|
return 0; |
|
} |
|
var TreeIndentContext = class _TreeIndentContext extends IndentContext { |
|
constructor(base, pos, context) { |
|
super(base.state, base.options); |
|
this.base = base; |
|
this.pos = pos; |
|
this.context = context; |
|
} |
|
|
|
|
|
|
|
|
|
get node() { |
|
return this.context.node; |
|
} |
|
|
|
|
|
|
|
static create(base, pos, context) { |
|
return new _TreeIndentContext(base, pos, context); |
|
} |
|
|
|
|
|
|
|
|
|
get textAfter() { |
|
return this.textAfterPos(this.pos); |
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
get baseIndent() { |
|
return this.baseIndentFor(this.node); |
|
} |
|
|
|
|
|
|
|
|
|
baseIndentFor(node) { |
|
let line = this.state.doc.lineAt(node.from); |
|
for (; ; ) { |
|
let atBreak = node.resolve(line.from); |
|
while (atBreak.parent && atBreak.parent.from == atBreak.from) |
|
atBreak = atBreak.parent; |
|
if (isParent(atBreak, node)) |
|
break; |
|
line = this.state.doc.lineAt(atBreak.from); |
|
} |
|
return this.lineIndent(line.from); |
|
} |
|
|
|
|
|
|
|
|
|
continue() { |
|
return indentFor(this.context.next, this.base, this.pos); |
|
} |
|
}; |
|
function isParent(parent, of) { |
|
for (let cur = of; cur; cur = cur.parent) |
|
if (parent == cur) |
|
return true; |
|
return false; |
|
} |
|
function bracketedAligned(context) { |
|
let tree = context.node; |
|
let openToken = tree.childAfter(tree.from), last = tree.lastChild; |
|
if (!openToken) |
|
return null; |
|
let sim = context.options.simulateBreak; |
|
let openLine = context.state.doc.lineAt(openToken.from); |
|
let lineEnd = sim == null || sim <= openLine.from ? openLine.to : Math.min(openLine.to, sim); |
|
for (let pos = openToken.to; ; ) { |
|
let next = tree.childAfter(pos); |
|
if (!next || next == last) |
|
return null; |
|
if (!next.type.isSkipped) |
|
return next.from < lineEnd ? openToken : null; |
|
pos = next.to; |
|
} |
|
} |
|
function delimitedIndent({ closing, align = true, units = 1 }) { |
|
return (context) => delimitedStrategy(context, align, units, closing); |
|
} |
|
function delimitedStrategy(context, align, units, closing, closedAt) { |
|
let after = context.textAfter, space = after.match(/^\s*/)[0].length; |
|
let closed = closing && after.slice(space, space + closing.length) == closing || closedAt == context.pos + space; |
|
let aligned = align ? bracketedAligned(context) : null; |
|
if (aligned) |
|
return closed ? context.column(aligned.from) : context.column(aligned.to); |
|
return context.baseIndent + (closed ? 0 : context.unit * units); |
|
} |
|
var flatIndent = (context) => context.baseIndent; |
|
function continuedIndent({ except, units = 1 } = {}) { |
|
return (context) => { |
|
let matchExcept = except && except.test(context.textAfter); |
|
return context.baseIndent + (matchExcept ? 0 : units * context.unit); |
|
}; |
|
} |
|
var DontIndentBeyond = 200; |
|
function indentOnInput() { |
|
return EditorState.transactionFilter.of((tr) => { |
|
if (!tr.docChanged || !tr.isUserEvent("input.type") && !tr.isUserEvent("input.complete")) |
|
return tr; |
|
let rules = tr.startState.languageDataAt("indentOnInput", tr.startState.selection.main.head); |
|
if (!rules.length) |
|
return tr; |
|
let doc = tr.newDoc, { head } = tr.newSelection.main, line = doc.lineAt(head); |
|
if (head > line.from + DontIndentBeyond) |
|
return tr; |
|
let lineStart = doc.sliceString(line.from, head); |
|
if (!rules.some((r) => r.test(lineStart))) |
|
return tr; |
|
let { state } = tr, last = -1, changes = []; |
|
for (let { head: head2 } of state.selection.ranges) { |
|
let line2 = state.doc.lineAt(head2); |
|
if (line2.from == last) |
|
continue; |
|
last = line2.from; |
|
let indent = getIndentation(state, line2.from); |
|
if (indent == null) |
|
continue; |
|
let cur = /^\s*/.exec(line2.text)[0]; |
|
let norm = indentString(state, indent); |
|
if (cur != norm) |
|
changes.push({ from: line2.from, to: line2.from + cur.length, insert: norm }); |
|
} |
|
return changes.length ? [tr, { changes, sequential: true }] : tr; |
|
}); |
|
} |
|
var foldService = Facet.define(); |
|
var foldNodeProp = new NodeProp(); |
|
function foldInside(node) { |
|
let first = node.firstChild, last = node.lastChild; |
|
return first && first.to < last.from ? { from: first.to, to: last.type.isError ? node.to : last.from } : null; |
|
} |
|
function syntaxFolding(state, start, end) { |
|
let tree = syntaxTree(state); |
|
if (tree.length < end) |
|
return null; |
|
let stack = tree.resolveStack(end, 1); |
|
let found = null; |
|
for (let iter = stack; iter; iter = iter.next) { |
|
let cur = iter.node; |
|
if (cur.to <= end || cur.from > end) |
|
continue; |
|
if (found && cur.from < start) |
|
break; |
|
let prop = cur.type.prop(foldNodeProp); |
|
if (prop && (cur.to < tree.length - 50 || tree.length == state.doc.length || !isUnfinished(cur))) { |
|
let value = prop(cur, state); |
|
if (value && value.from <= end && value.from >= start && value.to > end) |
|
found = value; |
|
} |
|
} |
|
return found; |
|
} |
|
function isUnfinished(node) { |
|
let ch = node.lastChild; |
|
return ch && ch.to == node.to && ch.type.isError; |
|
} |
|
function foldable(state, lineStart, lineEnd) { |
|
for (let service of state.facet(foldService)) { |
|
let result = service(state, lineStart, lineEnd); |
|
if (result) |
|
return result; |
|
} |
|
return syntaxFolding(state, lineStart, lineEnd); |
|
} |
|
function mapRange(range, mapping) { |
|
let from = mapping.mapPos(range.from, 1), to = mapping.mapPos(range.to, -1); |
|
return from >= to ? void 0 : { from, to }; |
|
} |
|
var foldEffect = StateEffect.define({ map: mapRange }); |
|
var unfoldEffect = StateEffect.define({ map: mapRange }); |
|
function selectedLines(view) { |
|
let lines = []; |
|
for (let { head } of view.state.selection.ranges) { |
|
if (lines.some((l) => l.from <= head && l.to >= head)) |
|
continue; |
|
lines.push(view.lineBlockAt(head)); |
|
} |
|
return lines; |
|
} |
|
var foldState = StateField.define({ |
|
create() { |
|
return Decoration.none; |
|
}, |
|
update(folded, tr) { |
|
folded = folded.map(tr.changes); |
|
for (let e of tr.effects) { |
|
if (e.is(foldEffect) && !foldExists(folded, e.value.from, e.value.to)) { |
|
let { preparePlaceholder } = tr.state.facet(foldConfig); |
|
let widget = !preparePlaceholder ? foldWidget : Decoration.replace({ widget: new PreparedFoldWidget(preparePlaceholder(tr.state, e.value)) }); |
|
folded = folded.update({ add: [widget.range(e.value.from, e.value.to)] }); |
|
} else if (e.is(unfoldEffect)) { |
|
folded = folded.update({ |
|
filter: (from, to) => e.value.from != from || e.value.to != to, |
|
filterFrom: e.value.from, |
|
filterTo: e.value.to |
|
}); |
|
} |
|
} |
|
if (tr.selection) { |
|
let onSelection = false, { head } = tr.selection.main; |
|
folded.between(head, head, (a, b) => { |
|
if (a < head && b > head) |
|
onSelection = true; |
|
}); |
|
if (onSelection) |
|
folded = folded.update({ |
|
filterFrom: head, |
|
filterTo: head, |
|
filter: (a, b) => b <= head || a >= head |
|
}); |
|
} |
|
return folded; |
|
}, |
|
provide: (f) => EditorView.decorations.from(f), |
|
toJSON(folded, state) { |
|
let ranges = []; |
|
folded.between(0, state.doc.length, (from, to) => { |
|
ranges.push(from, to); |
|
}); |
|
return ranges; |
|
}, |
|
fromJSON(value) { |
|
if (!Array.isArray(value) || value.length % 2) |
|
throw new RangeError("Invalid JSON for fold state"); |
|
let ranges = []; |
|
for (let i = 0; i < value.length; ) { |
|
let from = value[i++], to = value[i++]; |
|
if (typeof from != "number" || typeof to != "number") |
|
throw new RangeError("Invalid JSON for fold state"); |
|
ranges.push(foldWidget.range(from, to)); |
|
} |
|
return Decoration.set(ranges, true); |
|
} |
|
}); |
|
function foldedRanges(state) { |
|
return state.field(foldState, false) || RangeSet.empty; |
|
} |
|
function findFold(state, from, to) { |
|
var _a2; |
|
let found = null; |
|
(_a2 = state.field(foldState, false)) === null || _a2 === void 0 ? void 0 : _a2.between(from, to, (from2, to2) => { |
|
if (!found || found.from > from2) |
|
found = { from: from2, to: to2 }; |
|
}); |
|
return found; |
|
} |
|
function foldExists(folded, from, to) { |
|
let found = false; |
|
folded.between(from, from, (a, b) => { |
|
if (a == from && b == to) |
|
found = true; |
|
}); |
|
return found; |
|
} |
|
function maybeEnable(state, other) { |
|
return state.field(foldState, false) ? other : other.concat(StateEffect.appendConfig.of(codeFolding())); |
|
} |
|
var foldCode = (view) => { |
|
for (let line of selectedLines(view)) { |
|
let range = foldable(view.state, line.from, line.to); |
|
if (range) { |
|
view.dispatch({ effects: maybeEnable(view.state, [foldEffect.of(range), announceFold(view, range)]) }); |
|
return true; |
|
} |
|
} |
|
return false; |
|
}; |
|
var unfoldCode = (view) => { |
|
if (!view.state.field(foldState, false)) |
|
return false; |
|
let effects = []; |
|
for (let line of selectedLines(view)) { |
|
let folded = findFold(view.state, line.from, line.to); |
|
if (folded) |
|
effects.push(unfoldEffect.of(folded), announceFold(view, folded, false)); |
|
} |
|
if (effects.length) |
|
view.dispatch({ effects }); |
|
return effects.length > 0; |
|
}; |
|
function announceFold(view, range, fold = true) { |
|
let lineFrom = view.state.doc.lineAt(range.from).number, lineTo = view.state.doc.lineAt(range.to).number; |
|
return EditorView.announce.of(`${view.state.phrase(fold ? "Folded lines" : "Unfolded lines")} ${lineFrom} ${view.state.phrase("to")} ${lineTo}.`); |
|
} |
|
var foldAll = (view) => { |
|
let { state } = view, effects = []; |
|
for (let pos = 0; pos < state.doc.length; ) { |
|
let line = view.lineBlockAt(pos), range = foldable(state, line.from, line.to); |
|
if (range) |
|
effects.push(foldEffect.of(range)); |
|
pos = (range ? view.lineBlockAt(range.to) : line).to + 1; |
|
} |
|
if (effects.length) |
|
view.dispatch({ effects: maybeEnable(view.state, effects) }); |
|
return !!effects.length; |
|
}; |
|
var unfoldAll = (view) => { |
|
let field = view.state.field(foldState, false); |
|
if (!field || !field.size) |
|
return false; |
|
let effects = []; |
|
field.between(0, view.state.doc.length, (from, to) => { |
|
effects.push(unfoldEffect.of({ from, to })); |
|
}); |
|
view.dispatch({ effects }); |
|
return true; |
|
}; |
|
function foldableContainer(view, lineBlock) { |
|
for (let line = lineBlock; ; ) { |
|
let foldableRegion = foldable(view.state, line.from, line.to); |
|
if (foldableRegion && foldableRegion.to > lineBlock.from) |
|
return foldableRegion; |
|
if (!line.from) |
|
return null; |
|
line = view.lineBlockAt(line.from - 1); |
|
} |
|
} |
|
var toggleFold = (view) => { |
|
let effects = []; |
|
for (let line of selectedLines(view)) { |
|
let folded = findFold(view.state, line.from, line.to); |
|
if (folded) { |
|
effects.push(unfoldEffect.of(folded), announceFold(view, folded, false)); |
|
} else { |
|
let foldRange = foldableContainer(view, line); |
|
if (foldRange) |
|
effects.push(foldEffect.of(foldRange), announceFold(view, foldRange)); |
|
} |
|
} |
|
if (effects.length > 0) |
|
view.dispatch({ effects: maybeEnable(view.state, effects) }); |
|
return !!effects.length; |
|
}; |
|
var foldKeymap = [ |
|
{ key: "Ctrl-Shift-[", mac: "Cmd-Alt-[", run: foldCode }, |
|
{ key: "Ctrl-Shift-]", mac: "Cmd-Alt-]", run: unfoldCode }, |
|
{ key: "Ctrl-Alt-[", run: foldAll }, |
|
{ key: "Ctrl-Alt-]", run: unfoldAll } |
|
]; |
|
var defaultConfig = { |
|
placeholderDOM: null, |
|
preparePlaceholder: null, |
|
placeholderText: "…" |
|
}; |
|
var foldConfig = Facet.define({ |
|
combine(values) { |
|
return combineConfig(values, defaultConfig); |
|
} |
|
}); |
|
function codeFolding(config) { |
|
let result = [foldState, baseTheme$1]; |
|
if (config) |
|
result.push(foldConfig.of(config)); |
|
return result; |
|
} |
|
function widgetToDOM(view, prepared) { |
|
let { state } = view, conf = state.facet(foldConfig); |
|
let onclick = (event) => { |
|
let line = view.lineBlockAt(view.posAtDOM(event.target)); |
|
let folded = findFold(view.state, line.from, line.to); |
|
if (folded) |
|
view.dispatch({ effects: unfoldEffect.of(folded) }); |
|
event.preventDefault(); |
|
}; |
|
if (conf.placeholderDOM) |
|
return conf.placeholderDOM(view, onclick, prepared); |
|
let element = document.createElement("span"); |
|
element.textContent = conf.placeholderText; |
|
element.setAttribute("aria-label", state.phrase("folded code")); |
|
element.title = state.phrase("unfold"); |
|
element.className = "cm-foldPlaceholder"; |
|
element.onclick = onclick; |
|
return element; |
|
} |
|
var foldWidget = Decoration.replace({ widget: new class extends WidgetType { |
|
toDOM(view) { |
|
return widgetToDOM(view, null); |
|
} |
|
}() }); |
|
var PreparedFoldWidget = class extends WidgetType { |
|
constructor(value) { |
|
super(); |
|
this.value = value; |
|
} |
|
eq(other) { |
|
return this.value == other.value; |
|
} |
|
toDOM(view) { |
|
return widgetToDOM(view, this.value); |
|
} |
|
}; |
|
var foldGutterDefaults = { |
|
openText: "⌄", |
|
closedText: "›", |
|
markerDOM: null, |
|
domEventHandlers: {}, |
|
foldingChanged: () => false |
|
}; |
|
var FoldMarker = class extends GutterMarker { |
|
constructor(config, open) { |
|
super(); |
|
this.config = config; |
|
this.open = open; |
|
} |
|
eq(other) { |
|
return this.config == other.config && this.open == other.open; |
|
} |
|
toDOM(view) { |
|
if (this.config.markerDOM) |
|
return this.config.markerDOM(this.open); |
|
let span = document.createElement("span"); |
|
span.textContent = this.open ? this.config.openText : this.config.closedText; |
|
span.title = view.state.phrase(this.open ? "Fold line" : "Unfold line"); |
|
return span; |
|
} |
|
}; |
|
function foldGutter(config = {}) { |
|
let fullConfig = Object.assign(Object.assign({}, foldGutterDefaults), config); |
|
let canFold = new FoldMarker(fullConfig, true), canUnfold = new FoldMarker(fullConfig, false); |
|
let markers = ViewPlugin.fromClass(class { |
|
constructor(view) { |
|
this.from = view.viewport.from; |
|
this.markers = this.buildMarkers(view); |
|
} |
|
update(update) { |
|
if (update.docChanged || update.viewportChanged || update.startState.facet(language) != update.state.facet(language) || update.startState.field(foldState, false) != update.state.field(foldState, false) || syntaxTree(update.startState) != syntaxTree(update.state) || fullConfig.foldingChanged(update)) |
|
this.markers = this.buildMarkers(update.view); |
|
} |
|
buildMarkers(view) { |
|
let builder = new RangeSetBuilder(); |
|
for (let line of view.viewportLineBlocks) { |
|
let mark = findFold(view.state, line.from, line.to) ? canUnfold : foldable(view.state, line.from, line.to) ? canFold : null; |
|
if (mark) |
|
builder.add(line.from, line.from, mark); |
|
} |
|
return builder.finish(); |
|
} |
|
}); |
|
let { domEventHandlers } = fullConfig; |
|
return [ |
|
markers, |
|
gutter({ |
|
class: "cm-foldGutter", |
|
markers(view) { |
|
var _a2; |
|
return ((_a2 = view.plugin(markers)) === null || _a2 === void 0 ? void 0 : _a2.markers) || RangeSet.empty; |
|
}, |
|
initialSpacer() { |
|
return new FoldMarker(fullConfig, false); |
|
}, |
|
domEventHandlers: Object.assign(Object.assign({}, domEventHandlers), { click: (view, line, event) => { |
|
if (domEventHandlers.click && domEventHandlers.click(view, line, event)) |
|
return true; |
|
let folded = findFold(view.state, line.from, line.to); |
|
if (folded) { |
|
view.dispatch({ effects: unfoldEffect.of(folded) }); |
|
return true; |
|
} |
|
let range = foldable(view.state, line.from, line.to); |
|
if (range) { |
|
view.dispatch({ effects: foldEffect.of(range) }); |
|
return true; |
|
} |
|
return false; |
|
} }) |
|
}), |
|
codeFolding() |
|
]; |
|
} |
|
var baseTheme$1 = EditorView.baseTheme({ |
|
".cm-foldPlaceholder": { |
|
backgroundColor: "#eee", |
|
border: "1px solid #ddd", |
|
color: "#888", |
|
borderRadius: ".2em", |
|
margin: "0 1px", |
|
padding: "0 1px", |
|
cursor: "pointer" |
|
}, |
|
".cm-foldGutter span": { |
|
padding: "0 1px", |
|
cursor: "pointer" |
|
} |
|
}); |
|
var HighlightStyle = class _HighlightStyle { |
|
constructor(specs, options) { |
|
this.specs = specs; |
|
let modSpec; |
|
function def(spec) { |
|
let cls = StyleModule.newName(); |
|
(modSpec || (modSpec = Object.create(null)))["." + cls] = spec; |
|
return cls; |
|
} |
|
const all = typeof options.all == "string" ? options.all : options.all ? def(options.all) : void 0; |
|
const scopeOpt = options.scope; |
|
this.scope = scopeOpt instanceof Language ? (type) => type.prop(languageDataProp) == scopeOpt.data : scopeOpt ? (type) => type == scopeOpt : void 0; |
|
this.style = tagHighlighter(specs.map((style) => ({ |
|
tag: style.tag, |
|
class: style.class || def(Object.assign({}, style, { tag: null })) |
|
})), { |
|
all |
|
}).style; |
|
this.module = modSpec ? new StyleModule(modSpec) : null; |
|
this.themeType = options.themeType; |
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
static define(specs, options) { |
|
return new _HighlightStyle(specs, options || {}); |
|
} |
|
}; |
|
var highlighterFacet = Facet.define(); |
|
var fallbackHighlighter = Facet.define({ |
|
combine(values) { |
|
return values.length ? [values[0]] : null; |
|
} |
|
}); |
|
function getHighlighters(state) { |
|
let main = state.facet(highlighterFacet); |
|
return main.length ? main : state.facet(fallbackHighlighter); |
|
} |
|
function syntaxHighlighting(highlighter, options) { |
|
let ext = [treeHighlighter], themeType; |
|
if (highlighter instanceof HighlightStyle) { |
|
if (highlighter.module) |
|
ext.push(EditorView.styleModule.of(highlighter.module)); |
|
themeType = highlighter.themeType; |
|
} |
|
if (options === null || options === void 0 ? void 0 : options.fallback) |
|
ext.push(fallbackHighlighter.of(highlighter)); |
|
else if (themeType) |
|
ext.push(highlighterFacet.computeN([EditorView.darkTheme], (state) => { |
|
return state.facet(EditorView.darkTheme) == (themeType == "dark") ? [highlighter] : []; |
|
})); |
|
else |
|
ext.push(highlighterFacet.of(highlighter)); |
|
return ext; |
|
} |
|
function highlightingFor(state, tags2, scope) { |
|
let highlighters = getHighlighters(state); |
|
let result = null; |
|
if (highlighters) |
|
for (let highlighter of highlighters) { |
|
if (!highlighter.scope || scope && highlighter.scope(scope)) { |
|
let cls = highlighter.style(tags2); |
|
if (cls) |
|
result = result ? result + " " + cls : cls; |
|
} |
|
} |
|
return result; |
|
} |
|
var TreeHighlighter = class { |
|
constructor(view) { |
|
this.markCache = Object.create(null); |
|
this.tree = syntaxTree(view.state); |
|
this.decorations = this.buildDeco(view, getHighlighters(view.state)); |
|
this.decoratedTo = view.viewport.to; |
|
} |
|
update(update) { |
|
let tree = syntaxTree(update.state), highlighters = getHighlighters(update.state); |
|
let styleChange = highlighters != getHighlighters(update.startState); |
|
let { viewport } = update.view, decoratedToMapped = update.changes.mapPos(this.decoratedTo, 1); |
|
if (tree.length < viewport.to && !styleChange && tree.type == this.tree.type && decoratedToMapped >= viewport.to) { |
|
this.decorations = this.decorations.map(update.changes); |
|
this.decoratedTo = decoratedToMapped; |
|
} else if (tree != this.tree || update.viewportChanged || styleChange) { |
|
this.tree = tree; |
|
this.decorations = this.buildDeco(update.view, highlighters); |
|
this.decoratedTo = viewport.to; |
|
} |
|
} |
|
buildDeco(view, highlighters) { |
|
if (!highlighters || !this.tree.length) |
|
return Decoration.none; |
|
let builder = new RangeSetBuilder(); |
|
for (let { from, to } of view.visibleRanges) { |
|
highlightTree(this.tree, highlighters, (from2, to2, style) => { |
|
builder.add(from2, to2, this.markCache[style] || (this.markCache[style] = Decoration.mark({ class: style }))); |
|
}, from, to); |
|
} |
|
return builder.finish(); |
|
} |
|
}; |
|
var treeHighlighter = Prec.high(ViewPlugin.fromClass(TreeHighlighter, { |
|
decorations: (v) => v.decorations |
|
})); |
|
var defaultHighlightStyle = HighlightStyle.define([ |
|
{ |
|
tag: tags.meta, |
|
color: "#404740" |
|
}, |
|
{ |
|
tag: tags.link, |
|
textDecoration: "underline" |
|
}, |
|
{ |
|
tag: tags.heading, |
|
textDecoration: "underline", |
|
fontWeight: "bold" |
|
}, |
|
{ |
|
tag: tags.emphasis, |
|
fontStyle: "italic" |
|
}, |
|
{ |
|
tag: tags.strong, |
|
fontWeight: "bold" |
|
}, |
|
{ |
|
tag: tags.strikethrough, |
|
textDecoration: "line-through" |
|
}, |
|
{ |
|
tag: tags.keyword, |
|
color: "#708" |
|
}, |
|
{ |
|
tag: [tags.atom, tags.bool, tags.url, tags.contentSeparator, tags.labelName], |
|
color: "#219" |
|
}, |
|
{ |
|
tag: [tags.literal, tags.inserted], |
|
color: "#164" |
|
}, |
|
{ |
|
tag: [tags.string, tags.deleted], |
|
color: "#a11" |
|
}, |
|
{ |
|
tag: [tags.regexp, tags.escape, tags.special(tags.string)], |
|
color: "#e40" |
|
}, |
|
{ |
|
tag: tags.definition(tags.variableName), |
|
color: "#00f" |
|
}, |
|
{ |
|
tag: tags.local(tags.variableName), |
|
color: "#30a" |
|
}, |
|
{ |
|
tag: [tags.typeName, tags.namespace], |
|
color: "#085" |
|
}, |
|
{ |
|
tag: tags.className, |
|
color: "#167" |
|
}, |
|
{ |
|
tag: [tags.special(tags.variableName), tags.macroName], |
|
color: "#256" |
|
}, |
|
{ |
|
tag: tags.definition(tags.propertyName), |
|
color: "#00c" |
|
}, |
|
{ |
|
tag: tags.comment, |
|
color: "#940" |
|
}, |
|
{ |
|
tag: tags.invalid, |
|
color: "#f00" |
|
} |
|
]); |
|
var baseTheme = EditorView.baseTheme({ |
|
"&.cm-focused .cm-matchingBracket": { backgroundColor: "#328c8252" }, |
|
"&.cm-focused .cm-nonmatchingBracket": { backgroundColor: "#bb555544" } |
|
}); |
|
var DefaultScanDist = 1e4; |
|
var DefaultBrackets = "()[]{}"; |
|
var bracketMatchingConfig = Facet.define({ |
|
combine(configs) { |
|
return combineConfig(configs, { |
|
afterCursor: true, |
|
brackets: DefaultBrackets, |
|
maxScanDistance: DefaultScanDist, |
|
renderMatch: defaultRenderMatch |
|
}); |
|
} |
|
}); |
|
var matchingMark = Decoration.mark({ class: "cm-matchingBracket" }); |
|
var nonmatchingMark = Decoration.mark({ class: "cm-nonmatchingBracket" }); |
|
function defaultRenderMatch(match) { |
|
let decorations = []; |
|
let mark = match.matched ? matchingMark : nonmatchingMark; |
|
decorations.push(mark.range(match.start.from, match.start.to)); |
|
if (match.end) |
|
decorations.push(mark.range(match.end.from, match.end.to)); |
|
return decorations; |
|
} |
|
var bracketMatchingState = StateField.define({ |
|
create() { |
|
return Decoration.none; |
|
}, |
|
update(deco, tr) { |
|
if (!tr.docChanged && !tr.selection) |
|
return deco; |
|
let decorations = []; |
|
let config = tr.state.facet(bracketMatchingConfig); |
|
for (let range of tr.state.selection.ranges) { |
|
if (!range.empty) |
|
continue; |
|
let match = matchBrackets(tr.state, range.head, -1, config) || range.head > 0 && matchBrackets(tr.state, range.head - 1, 1, config) || config.afterCursor && (matchBrackets(tr.state, range.head, 1, config) || range.head < tr.state.doc.length && matchBrackets(tr.state, range.head + 1, -1, config)); |
|
if (match) |
|
decorations = decorations.concat(config.renderMatch(match, tr.state)); |
|
} |
|
return Decoration.set(decorations, true); |
|
}, |
|
provide: (f) => EditorView.decorations.from(f) |
|
}); |
|
var bracketMatchingUnique = [ |
|
bracketMatchingState, |
|
baseTheme |
|
]; |
|
function bracketMatching(config = {}) { |
|
return [bracketMatchingConfig.of(config), bracketMatchingUnique]; |
|
} |
|
var bracketMatchingHandle = new NodeProp(); |
|
function matchingNodes(node, dir, brackets) { |
|
let byProp = node.prop(dir < 0 ? NodeProp.openedBy : NodeProp.closedBy); |
|
if (byProp) |
|
return byProp; |
|
if (node.name.length == 1) { |
|
let index = brackets.indexOf(node.name); |
|
if (index > -1 && index % 2 == (dir < 0 ? 1 : 0)) |
|
return [brackets[index + dir]]; |
|
} |
|
return null; |
|
} |
|
function findHandle(node) { |
|
let hasHandle = node.type.prop(bracketMatchingHandle); |
|
return hasHandle ? hasHandle(node.node) : node; |
|
} |
|
function matchBrackets(state, pos, dir, config = {}) { |
|
let maxScanDistance = config.maxScanDistance || DefaultScanDist, brackets = config.brackets || DefaultBrackets; |
|
let tree = syntaxTree(state), node = tree.resolveInner(pos, dir); |
|
for (let cur = node; cur; cur = cur.parent) { |
|
let matches = matchingNodes(cur.type, dir, brackets); |
|
if (matches && cur.from < cur.to) { |
|
let handle = findHandle(cur); |
|
if (handle && (dir > 0 ? pos >= handle.from && pos < handle.to : pos > handle.from && pos <= handle.to)) |
|
return matchMarkedBrackets(state, pos, dir, cur, handle, matches, brackets); |
|
} |
|
} |
|
return matchPlainBrackets(state, pos, dir, tree, node.type, maxScanDistance, brackets); |
|
} |
|
function matchMarkedBrackets(_state, _pos, dir, token, handle, matching, brackets) { |
|
let parent = token.parent, firstToken = { from: handle.from, to: handle.to }; |
|
let depth = 0, cursor = parent === null || parent === void 0 ? void 0 : parent.cursor(); |
|
if (cursor && (dir < 0 ? cursor.childBefore(token.from) : cursor.childAfter(token.to))) |
|
do { |
|
if (dir < 0 ? cursor.to <= token.from : cursor.from >= token.to) { |
|
if (depth == 0 && matching.indexOf(cursor.type.name) > -1 && cursor.from < cursor.to) { |
|
let endHandle = findHandle(cursor); |
|
return { start: firstToken, end: endHandle ? { from: endHandle.from, to: endHandle.to } : void 0, matched: true }; |
|
} else if (matchingNodes(cursor.type, dir, brackets)) { |
|
depth++; |
|
} else if (matchingNodes(cursor.type, -dir, brackets)) { |
|
if (depth == 0) { |
|
let endHandle = findHandle(cursor); |
|
return { |
|
start: firstToken, |
|
end: endHandle && endHandle.from < endHandle.to ? { from: endHandle.from, to: endHandle.to } : void 0, |
|
matched: false |
|
}; |
|
} |
|
depth--; |
|
} |
|
} |
|
} while (dir < 0 ? cursor.prevSibling() : cursor.nextSibling()); |
|
return { start: firstToken, matched: false }; |
|
} |
|
function matchPlainBrackets(state, pos, dir, tree, tokenType, maxScanDistance, brackets) { |
|
let startCh = dir < 0 ? state.sliceDoc(pos - 1, pos) : state.sliceDoc(pos, pos + 1); |
|
let bracket2 = brackets.indexOf(startCh); |
|
if (bracket2 < 0 || bracket2 % 2 == 0 != dir > 0) |
|
return null; |
|
let startToken = { from: dir < 0 ? pos - 1 : pos, to: dir > 0 ? pos + 1 : pos }; |
|
let iter = state.doc.iterRange(pos, dir > 0 ? state.doc.length : 0), depth = 0; |
|
for (let distance = 0; !iter.next().done && distance <= maxScanDistance; ) { |
|
let text = iter.value; |
|
if (dir < 0) |
|
distance += text.length; |
|
let basePos = pos + distance * dir; |
|
for (let pos2 = dir > 0 ? 0 : text.length - 1, end = dir > 0 ? text.length : -1; pos2 != end; pos2 += dir) { |
|
let found = brackets.indexOf(text[pos2]); |
|
if (found < 0 || tree.resolveInner(basePos + pos2, 1).type != tokenType) |
|
continue; |
|
if (found % 2 == 0 == dir > 0) { |
|
depth++; |
|
} else if (depth == 1) { |
|
return { start: startToken, end: { from: basePos + pos2, to: basePos + pos2 + 1 }, matched: found >> 1 == bracket2 >> 1 }; |
|
} else { |
|
depth--; |
|
} |
|
} |
|
if (dir > 0) |
|
distance += text.length; |
|
} |
|
return iter.done ? { start: startToken, matched: false } : null; |
|
} |
|
function countCol(string2, end, tabSize, startIndex = 0, startValue = 0) { |
|
if (end == null) { |
|
end = string2.search(/[^\s\u00a0]/); |
|
if (end == -1) |
|
end = string2.length; |
|
} |
|
let n = startValue; |
|
for (let i = startIndex; i < end; i++) { |
|
if (string2.charCodeAt(i) == 9) |
|
n += tabSize - n % tabSize; |
|
else |
|
n++; |
|
} |
|
return n; |
|
} |
|
var StringStream = class { |
|
|
|
|
|
|
|
constructor(string2, tabSize, indentUnit2, overrideIndent) { |
|
this.string = string2; |
|
this.tabSize = tabSize; |
|
this.indentUnit = indentUnit2; |
|
this.overrideIndent = overrideIndent; |
|
this.pos = 0; |
|
this.start = 0; |
|
this.lastColumnPos = 0; |
|
this.lastColumnValue = 0; |
|
} |
|
|
|
|
|
|
|
eol() { |
|
return this.pos >= this.string.length; |
|
} |
|
|
|
|
|
|
|
sol() { |
|
return this.pos == 0; |
|
} |
|
|
|
|
|
|
|
|
|
peek() { |
|
return this.string.charAt(this.pos) || void 0; |
|
} |
|
|
|
|
|
|
|
next() { |
|
if (this.pos < this.string.length) |
|
return this.string.charAt(this.pos++); |
|
} |
|
|
|
|
|
|
|
|
|
eat(match) { |
|
let ch = this.string.charAt(this.pos); |
|
let ok; |
|
if (typeof match == "string") |
|
ok = ch == match; |
|
else |
|
ok = ch && (match instanceof RegExp ? match.test(ch) : match(ch)); |
|
if (ok) { |
|
++this.pos; |
|
return ch; |
|
} |
|
} |
|
|
|
|
|
|
|
|
|
|
|
eatWhile(match) { |
|
let start = this.pos; |
|
while (this.eat(match)) { |
|
} |
|
return this.pos > start; |
|
} |
|
|
|
|
|
|
|
|
|
eatSpace() { |
|
let start = this.pos; |
|
while (/[\s\u00a0]/.test(this.string.charAt(this.pos))) |
|
++this.pos; |
|
return this.pos > start; |
|
} |
|
|
|
|
|
|
|
skipToEnd() { |
|
this.pos = this.string.length; |
|
} |
|
|
|
|
|
|
|
|
|
skipTo(ch) { |
|
let found = this.string.indexOf(ch, this.pos); |
|
if (found > -1) { |
|
this.pos = found; |
|
return true; |
|
} |
|
} |
|
|
|
|
|
|
|
backUp(n) { |
|
this.pos -= n; |
|
} |
|
|
|
|
|
|
|
column() { |
|
if (this.lastColumnPos < this.start) { |
|
this.lastColumnValue = countCol(this.string, this.start, this.tabSize, this.lastColumnPos, this.lastColumnValue); |
|
this.lastColumnPos = this.start; |
|
} |
|
return this.lastColumnValue; |
|
} |
|
|
|
|
|
|
|
indentation() { |
|
var _a2; |
|
return (_a2 = this.overrideIndent) !== null && _a2 !== void 0 ? _a2 : countCol(this.string, null, this.tabSize); |
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
match(pattern, consume, caseInsensitive) { |
|
if (typeof pattern == "string") { |
|
let cased = (str) => caseInsensitive ? str.toLowerCase() : str; |
|
let substr = this.string.substr(this.pos, pattern.length); |
|
if (cased(substr) == cased(pattern)) { |
|
if (consume !== false) |
|
this.pos += pattern.length; |
|
return true; |
|
} else |
|
return null; |
|
} else { |
|
let match = this.string.slice(this.pos).match(pattern); |
|
if (match && match.index > 0) |
|
return null; |
|
if (match && consume !== false) |
|
this.pos += match[0].length; |
|
return match; |
|
} |
|
} |
|
|
|
|
|
|
|
current() { |
|
return this.string.slice(this.start, this.pos); |
|
} |
|
}; |
|
function fullParser(spec) { |
|
return { |
|
name: spec.name || "", |
|
token: spec.token, |
|
blankLine: spec.blankLine || (() => { |
|
}), |
|
startState: spec.startState || (() => true), |
|
copyState: spec.copyState || defaultCopyState, |
|
indent: spec.indent || (() => null), |
|
languageData: spec.languageData || {}, |
|
tokenTable: spec.tokenTable || noTokens |
|
}; |
|
} |
|
function defaultCopyState(state) { |
|
if (typeof state != "object") |
|
return state; |
|
let newState = {}; |
|
for (let prop in state) { |
|
let val = state[prop]; |
|
newState[prop] = val instanceof Array ? val.slice() : val; |
|
} |
|
return newState; |
|
} |
|
var IndentedFrom = new WeakMap(); |
|
var StreamLanguage = class _StreamLanguage extends Language { |
|
constructor(parser) { |
|
let data = defineLanguageFacet(parser.languageData); |
|
let p = fullParser(parser), self; |
|
let impl = new class extends Parser { |
|
createParse(input, fragments, ranges) { |
|
return new Parse(self, input, fragments, ranges); |
|
} |
|
}(); |
|
super(data, impl, [indentService.of((cx, pos) => this.getIndent(cx, pos))], parser.name); |
|
this.topNode = docID(data); |
|
self = this; |
|
this.streamParser = p; |
|
this.stateAfter = new NodeProp({ perNode: true }); |
|
this.tokenTable = parser.tokenTable ? new TokenTable(p.tokenTable) : defaultTokenTable; |
|
} |
|
|
|
|
|
|
|
static define(spec) { |
|
return new _StreamLanguage(spec); |
|
} |
|
getIndent(cx, pos) { |
|
let tree = syntaxTree(cx.state), at = tree.resolve(pos); |
|
while (at && at.type != this.topNode) |
|
at = at.parent; |
|
if (!at) |
|
return null; |
|
let from = void 0; |
|
let { overrideIndentation } = cx.options; |
|
if (overrideIndentation) { |
|
from = IndentedFrom.get(cx.state); |
|
if (from != null && from < pos - 1e4) |
|
from = void 0; |
|
} |
|
let start = findState(this, tree, 0, at.from, from !== null && from !== void 0 ? from : pos), statePos, state; |
|
if (start) { |
|
state = start.state; |
|
statePos = start.pos + 1; |
|
} else { |
|
state = this.streamParser.startState(cx.unit); |
|
statePos = 0; |
|
} |
|
if (pos - statePos > 1e4) |
|
return null; |
|
while (statePos < pos) { |
|
let line2 = cx.state.doc.lineAt(statePos), end = Math.min(pos, line2.to); |
|
if (line2.length) { |
|
let indentation = overrideIndentation ? overrideIndentation(line2.from) : -1; |
|
let stream = new StringStream(line2.text, cx.state.tabSize, cx.unit, indentation < 0 ? void 0 : indentation); |
|
while (stream.pos < end - line2.from) |
|
readToken(this.streamParser.token, stream, state); |
|
} else { |
|
this.streamParser.blankLine(state, cx.unit); |
|
} |
|
if (end == pos) |
|
break; |
|
statePos = line2.to + 1; |
|
} |
|
let line = cx.lineAt(pos); |
|
if (overrideIndentation && from == null) |
|
IndentedFrom.set(cx.state, line.from); |
|
return this.streamParser.indent(state, /^\s*(.*)/.exec(line.text)[1], cx); |
|
} |
|
get allowsNesting() { |
|
return false; |
|
} |
|
}; |
|
function findState(lang, tree, off, startPos, before) { |
|
let state = off >= startPos && off + tree.length <= before && tree.prop(lang.stateAfter); |
|
if (state) |
|
return { state: lang.streamParser.copyState(state), pos: off + tree.length }; |
|
for (let i = tree.children.length - 1; i >= 0; i--) { |
|
let child = tree.children[i], pos = off + tree.positions[i]; |
|
let found = child instanceof Tree && pos < before && findState(lang, child, pos, startPos, before); |
|
if (found) |
|
return found; |
|
} |
|
return null; |
|
} |
|
function cutTree(lang, tree, from, to, inside) { |
|
if (inside && from <= 0 && to >= tree.length) |
|
return tree; |
|
if (!inside && tree.type == lang.topNode) |
|
inside = true; |
|
for (let i = tree.children.length - 1; i >= 0; i--) { |
|
let pos = tree.positions[i], child = tree.children[i], inner; |
|
if (pos < to && child instanceof Tree) { |
|
if (!(inner = cutTree(lang, child, from - pos, to - pos, inside))) |
|
break; |
|
return !inside ? inner : new Tree(tree.type, tree.children.slice(0, i).concat(inner), tree.positions.slice(0, i + 1), pos + inner.length); |
|
} |
|
} |
|
return null; |
|
} |
|
function findStartInFragments(lang, fragments, startPos, editorState) { |
|
for (let f of fragments) { |
|
let from = f.from + (f.openStart ? 25 : 0), to = f.to - (f.openEnd ? 25 : 0); |
|
let found = from <= startPos && to > startPos && findState(lang, f.tree, 0 - f.offset, startPos, to), tree; |
|
if (found && (tree = cutTree(lang, f.tree, startPos + f.offset, found.pos + f.offset, false))) |
|
return { state: found.state, tree }; |
|
} |
|
return { state: lang.streamParser.startState(editorState ? getIndentUnit(editorState) : 4), tree: Tree.empty }; |
|
} |
|
var Parse = class { |
|
constructor(lang, input, fragments, ranges) { |
|
this.lang = lang; |
|
this.input = input; |
|
this.fragments = fragments; |
|
this.ranges = ranges; |
|
this.stoppedAt = null; |
|
this.chunks = []; |
|
this.chunkPos = []; |
|
this.chunk = []; |
|
this.chunkReused = void 0; |
|
this.rangeIndex = 0; |
|
this.to = ranges[ranges.length - 1].to; |
|
let context = ParseContext.get(), from = ranges[0].from; |
|
let { state, tree } = findStartInFragments(lang, fragments, from, context === null || context === void 0 ? void 0 : context.state); |
|
this.state = state; |
|
this.parsedPos = this.chunkStart = from + tree.length; |
|
for (let i = 0; i < tree.children.length; i++) { |
|
this.chunks.push(tree.children[i]); |
|
this.chunkPos.push(tree.positions[i]); |
|
} |
|
if (context && this.parsedPos < context.viewport.from - 1e5) { |
|
this.state = this.lang.streamParser.startState(getIndentUnit(context.state)); |
|
context.skipUntilInView(this.parsedPos, context.viewport.from); |
|
this.parsedPos = context.viewport.from; |
|
} |
|
this.moveRangeIndex(); |
|
} |
|
advance() { |
|
let context = ParseContext.get(); |
|
let parseEnd = this.stoppedAt == null ? this.to : Math.min(this.to, this.stoppedAt); |
|
let end = Math.min( |
|
parseEnd, |
|
this.chunkStart + 2048 |
|
|
|
); |
|
if (context) |
|
end = Math.min(end, context.viewport.to); |
|
while (this.parsedPos < end) |
|
this.parseLine(context); |
|
if (this.chunkStart < this.parsedPos) |
|
this.finishChunk(); |
|
if (this.parsedPos >= parseEnd) |
|
return this.finish(); |
|
if (context && this.parsedPos >= context.viewport.to) { |
|
context.skipUntilInView(this.parsedPos, parseEnd); |
|
return this.finish(); |
|
} |
|
return null; |
|
} |
|
stopAt(pos) { |
|
this.stoppedAt = pos; |
|
} |
|
lineAfter(pos) { |
|
let chunk = this.input.chunk(pos); |
|
if (!this.input.lineChunks) { |
|
let eol = chunk.indexOf("\n"); |
|
if (eol > -1) |
|
chunk = chunk.slice(0, eol); |
|
} else if (chunk == "\n") { |
|
chunk = ""; |
|
} |
|
return pos + chunk.length <= this.to ? chunk : chunk.slice(0, this.to - pos); |
|
} |
|
nextLine() { |
|
let from = this.parsedPos, line = this.lineAfter(from), end = from + line.length; |
|
for (let index = this.rangeIndex; ; ) { |
|
let rangeEnd = this.ranges[index].to; |
|
if (rangeEnd >= end) |
|
break; |
|
line = line.slice(0, rangeEnd - (end - line.length)); |
|
index++; |
|
if (index == this.ranges.length) |
|
break; |
|
let rangeStart = this.ranges[index].from; |
|
let after = this.lineAfter(rangeStart); |
|
line += after; |
|
end = rangeStart + after.length; |
|
} |
|
return { line, end }; |
|
} |
|
skipGapsTo(pos, offset, side) { |
|
for (; ; ) { |
|
let end = this.ranges[this.rangeIndex].to, offPos = pos + offset; |
|
if (side > 0 ? end > offPos : end >= offPos) |
|
break; |
|
let start = this.ranges[++this.rangeIndex].from; |
|
offset += start - end; |
|
} |
|
return offset; |
|
} |
|
moveRangeIndex() { |
|
while (this.ranges[this.rangeIndex].to < this.parsedPos) |
|
this.rangeIndex++; |
|
} |
|
emitToken(id, from, to, size, offset) { |
|
if (this.ranges.length > 1) { |
|
offset = this.skipGapsTo(from, offset, 1); |
|
from += offset; |
|
let len0 = this.chunk.length; |
|
offset = this.skipGapsTo(to, offset, -1); |
|
to += offset; |
|
size += this.chunk.length - len0; |
|
} |
|
this.chunk.push(id, from, to, size); |
|
return offset; |
|
} |
|
parseLine(context) { |
|
let { line, end } = this.nextLine(), offset = 0, { streamParser } = this.lang; |
|
let stream = new StringStream(line, context ? context.state.tabSize : 4, context ? getIndentUnit(context.state) : 2); |
|
if (stream.eol()) { |
|
streamParser.blankLine(this.state, stream.indentUnit); |
|
} else { |
|
while (!stream.eol()) { |
|
let token = readToken(streamParser.token, stream, this.state); |
|
if (token) |
|
offset = this.emitToken(this.lang.tokenTable.resolve(token), this.parsedPos + stream.start, this.parsedPos + stream.pos, 4, offset); |
|
if (stream.start > 1e4) |
|
break; |
|
} |
|
} |
|
this.parsedPos = end; |
|
this.moveRangeIndex(); |
|
if (this.parsedPos < this.to) |
|
this.parsedPos++; |
|
} |
|
finishChunk() { |
|
let tree = Tree.build({ |
|
buffer: this.chunk, |
|
start: this.chunkStart, |
|
length: this.parsedPos - this.chunkStart, |
|
nodeSet, |
|
topID: 0, |
|
maxBufferLength: 2048, |
|
reused: this.chunkReused |
|
}); |
|
tree = new Tree(tree.type, tree.children, tree.positions, tree.length, [[this.lang.stateAfter, this.lang.streamParser.copyState(this.state)]]); |
|
this.chunks.push(tree); |
|
this.chunkPos.push(this.chunkStart - this.ranges[0].from); |
|
this.chunk = []; |
|
this.chunkReused = void 0; |
|
this.chunkStart = this.parsedPos; |
|
} |
|
finish() { |
|
return new Tree(this.lang.topNode, this.chunks, this.chunkPos, this.parsedPos - this.ranges[0].from).balance(); |
|
} |
|
}; |
|
function readToken(token, stream, state) { |
|
stream.start = stream.pos; |
|
for (let i = 0; i < 10; i++) { |
|
let result = token(stream, state); |
|
if (stream.pos > stream.start) |
|
return result; |
|
} |
|
throw new Error("Stream parser failed to advance stream."); |
|
} |
|
var noTokens = Object.create(null); |
|
var typeArray = [NodeType.none]; |
|
var nodeSet = new NodeSet(typeArray); |
|
var warned = []; |
|
var byTag = Object.create(null); |
|
var defaultTable = Object.create(null); |
|
for (let [legacyName, name2] of [ |
|
["variable", "variableName"], |
|
["variable-2", "variableName.special"], |
|
["string-2", "string.special"], |
|
["def", "variableName.definition"], |
|
["tag", "tagName"], |
|
["attribute", "attributeName"], |
|
["type", "typeName"], |
|
["builtin", "variableName.standard"], |
|
["qualifier", "modifier"], |
|
["error", "invalid"], |
|
["header", "heading"], |
|
["property", "propertyName"] |
|
]) |
|
defaultTable[legacyName] = createTokenType(noTokens, name2); |
|
var TokenTable = class { |
|
constructor(extra) { |
|
this.extra = extra; |
|
this.table = Object.assign( Object.create(null), defaultTable); |
|
} |
|
resolve(tag) { |
|
return !tag ? 0 : this.table[tag] || (this.table[tag] = createTokenType(this.extra, tag)); |
|
} |
|
}; |
|
var defaultTokenTable = new TokenTable(noTokens); |
|
function warnForPart(part, msg) { |
|
if (warned.indexOf(part) > -1) |
|
return; |
|
warned.push(part); |
|
console.warn(msg); |
|
} |
|
function createTokenType(extra, tagStr) { |
|
let tags$1 = []; |
|
for (let name3 of tagStr.split(" ")) { |
|
let found = []; |
|
for (let part of name3.split(".")) { |
|
let value = extra[part] || tags[part]; |
|
if (!value) { |
|
warnForPart(part, `Unknown highlighting tag ${part}`); |
|
} else if (typeof value == "function") { |
|
if (!found.length) |
|
warnForPart(part, `Modifier ${part} used at start of tag`); |
|
else |
|
found = found.map(value); |
|
} else { |
|
if (found.length) |
|
warnForPart(part, `Tag ${part} used as modifier`); |
|
else |
|
found = Array.isArray(value) ? value : [value]; |
|
} |
|
} |
|
for (let tag of found) |
|
tags$1.push(tag); |
|
} |
|
if (!tags$1.length) |
|
return 0; |
|
let name2 = tagStr.replace(/ /g, "_"), key = name2 + " " + tags$1.map((t2) => t2.id); |
|
let known = byTag[key]; |
|
if (known) |
|
return known.id; |
|
let type = byTag[key] = NodeType.define({ |
|
id: typeArray.length, |
|
name: name2, |
|
props: [styleTags({ [name2]: tags$1 })] |
|
}); |
|
typeArray.push(type); |
|
return type.id; |
|
} |
|
function docID(data) { |
|
let type = NodeType.define({ id: typeArray.length, name: "Document", props: [languageDataProp.add(() => data)], top: true }); |
|
typeArray.push(type); |
|
return type; |
|
} |
|
function buildForLine(line) { |
|
return line.length <= 4096 && /[\u0590-\u05f4\u0600-\u06ff\u0700-\u08ac\ufb50-\ufdff]/.test(line); |
|
} |
|
function textHasRTL(text) { |
|
for (let i = text.iter(); !i.next().done; ) |
|
if (buildForLine(i.value)) |
|
return true; |
|
return false; |
|
} |
|
function changeAddsRTL(change) { |
|
let added = false; |
|
change.iterChanges((fA, tA, fB, tB, ins) => { |
|
if (!added && textHasRTL(ins)) |
|
added = true; |
|
}); |
|
return added; |
|
} |
|
var alwaysIsolate = Facet.define({ combine: (values) => values.some((x) => x) }); |
|
function bidiIsolates(options = {}) { |
|
let extensions = [isolateMarks]; |
|
if (options.alwaysIsolate) |
|
extensions.push(alwaysIsolate.of(true)); |
|
return extensions; |
|
} |
|
var isolateMarks = ViewPlugin.fromClass(class { |
|
constructor(view) { |
|
this.always = view.state.facet(alwaysIsolate) || view.textDirection != Direction.LTR || view.state.facet(EditorView.perLineTextDirection); |
|
this.hasRTL = !this.always && textHasRTL(view.state.doc); |
|
this.tree = syntaxTree(view.state); |
|
this.decorations = this.always || this.hasRTL ? buildDeco(view, this.tree, this.always) : Decoration.none; |
|
} |
|
update(update) { |
|
let always = update.state.facet(alwaysIsolate) || update.view.textDirection != Direction.LTR || update.state.facet(EditorView.perLineTextDirection); |
|
if (!always && !this.hasRTL && changeAddsRTL(update.changes)) |
|
this.hasRTL = true; |
|
if (!always && !this.hasRTL) |
|
return; |
|
let tree = syntaxTree(update.state); |
|
if (always != this.always || tree != this.tree || update.docChanged || update.viewportChanged) { |
|
this.tree = tree; |
|
this.always = always; |
|
this.decorations = buildDeco(update.view, tree, always); |
|
} |
|
} |
|
}, { |
|
provide: (plugin) => { |
|
function access(view) { |
|
var _a2, _b; |
|
return (_b = (_a2 = view.plugin(plugin)) === null || _a2 === void 0 ? void 0 : _a2.decorations) !== null && _b !== void 0 ? _b : Decoration.none; |
|
} |
|
return [ |
|
EditorView.outerDecorations.of(access), |
|
Prec.lowest(EditorView.bidiIsolatedRanges.of(access)) |
|
]; |
|
} |
|
}); |
|
function buildDeco(view, tree, always) { |
|
let deco = new RangeSetBuilder(); |
|
let ranges = view.visibleRanges; |
|
if (!always) |
|
ranges = clipRTLLines(ranges, view.state.doc); |
|
for (let { from, to } of ranges) { |
|
tree.iterate({ |
|
enter: (node) => { |
|
let iso = node.type.prop(NodeProp.isolate); |
|
if (iso) |
|
deco.add(node.from, node.to, marks[iso]); |
|
}, |
|
from, |
|
to |
|
}); |
|
} |
|
return deco.finish(); |
|
} |
|
function clipRTLLines(ranges, doc) { |
|
let cur = doc.iter(), pos = 0, result = [], last = null; |
|
for (let { from, to } of ranges) { |
|
if (last && last.to > from) { |
|
from = last.to; |
|
if (from >= to) |
|
continue; |
|
} |
|
if (pos + cur.value.length < from) { |
|
cur.next(from - (pos + cur.value.length)); |
|
pos = from; |
|
} |
|
for (; ; ) { |
|
let start = pos, end = pos + cur.value.length; |
|
if (!cur.lineBreak && buildForLine(cur.value)) { |
|
if (last && last.to > start - 10) |
|
last.to = Math.min(to, end); |
|
else |
|
result.push(last = { from: start, to: Math.min(to, end) }); |
|
} |
|
if (end >= to) |
|
break; |
|
pos = end; |
|
cur.next(); |
|
} |
|
} |
|
return result; |
|
} |
|
var marks = { |
|
rtl: Decoration.mark({ class: "cm-iso", inclusive: true, attributes: { dir: "rtl" }, bidiIsolate: Direction.RTL }), |
|
ltr: Decoration.mark({ class: "cm-iso", inclusive: true, attributes: { dir: "ltr" }, bidiIsolate: Direction.LTR }), |
|
auto: Decoration.mark({ class: "cm-iso", inclusive: true, attributes: { dir: "auto" }, bidiIsolate: null }) |
|
}; |
|
|
|
export { |
|
DefaultBufferLength, |
|
NodeProp, |
|
NodeType, |
|
NodeSet, |
|
IterMode, |
|
Tree, |
|
NodeWeakMap, |
|
Parser, |
|
styleTags, |
|
tags, |
|
languageDataProp, |
|
defineLanguageFacet, |
|
sublanguageProp, |
|
Language, |
|
LRLanguage, |
|
syntaxTree, |
|
ensureSyntaxTree, |
|
syntaxTreeAvailable, |
|
forceParsing, |
|
syntaxParserRunning, |
|
DocInput, |
|
ParseContext, |
|
language, |
|
LanguageSupport, |
|
LanguageDescription, |
|
indentService, |
|
indentUnit, |
|
getIndentUnit, |
|
indentString, |
|
getIndentation, |
|
indentRange, |
|
IndentContext, |
|
indentNodeProp, |
|
TreeIndentContext, |
|
delimitedIndent, |
|
flatIndent, |
|
continuedIndent, |
|
indentOnInput, |
|
foldService, |
|
foldNodeProp, |
|
foldInside, |
|
foldable, |
|
foldEffect, |
|
unfoldEffect, |
|
foldState, |
|
foldedRanges, |
|
foldCode, |
|
unfoldCode, |
|
foldAll, |
|
unfoldAll, |
|
toggleFold, |
|
foldKeymap, |
|
codeFolding, |
|
foldGutter, |
|
HighlightStyle, |
|
syntaxHighlighting, |
|
highlightingFor, |
|
defaultHighlightStyle, |
|
bracketMatching, |
|
bracketMatchingHandle, |
|
matchBrackets, |
|
StringStream, |
|
StreamLanguage, |
|
bidiIsolates |
|
}; |
|
|
|
|