@lezer/common 0.15.11 → 0.16.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.cjs +199 -69
- package/dist/index.d.ts +1 -1
- package/dist/{tree.cjs → index.es.js} +749 -89
- package/dist/index.js +199 -70
- package/dist/mix.d.ts +3 -3
- package/dist/tree.d.ts +59 -39
- package/package.json +1 -1
- package/dist/composite.d.ts +0 -42
- package/dist/frame.d.ts +0 -25
- package/dist/scaffold.d.ts +0 -25
- package/dist/tree.cjs.map +0 -1
- package/dist/tree.es.js +0 -1143
- package/dist/tree.es.js.map +0 -1
|
@@ -1,7 +1,3 @@
|
|
|
1
|
-
'use strict';
|
|
2
|
-
|
|
3
|
-
Object.defineProperty(exports, '__esModule', { value: true });
|
|
4
|
-
|
|
5
1
|
// FIXME profile adding a per-Tree TreeNode cache, validating it by
|
|
6
2
|
// parent pointer
|
|
7
3
|
/// The default maximum length of a `TreeBuffer` node (1024).
|
|
@@ -213,7 +209,29 @@ class NodeSet {
|
|
|
213
209
|
return new NodeSet(newTypes);
|
|
214
210
|
}
|
|
215
211
|
}
|
|
216
|
-
const CachedNode = new WeakMap();
|
|
212
|
+
const CachedNode = new WeakMap(), CachedInnerNode = new WeakMap();
|
|
213
|
+
/// Options that control iteration. Can be combined with the `|`
|
|
214
|
+
/// operator to enable multiple ones.
|
|
215
|
+
var IterMode;
|
|
216
|
+
(function (IterMode) {
|
|
217
|
+
/// When enabled, iteration will only visit [`Tree`](#common.Tree)
|
|
218
|
+
/// objects, not nodes packed into
|
|
219
|
+
/// [`TreeBuffer`](#common.TreeBuffer)s.
|
|
220
|
+
IterMode[IterMode["ExcludeBuffers"] = 1] = "ExcludeBuffers";
|
|
221
|
+
/// Enable this to make iteration include anonymous nodes (such as
|
|
222
|
+
/// the nodes that wrap repeated grammar constructs into a balanced
|
|
223
|
+
/// tree).
|
|
224
|
+
IterMode[IterMode["IncludeAnonymous"] = 2] = "IncludeAnonymous";
|
|
225
|
+
/// By default, regular [mounted](#common.NodeProp^mounted) nodes
|
|
226
|
+
/// replace their base node in iteration. Enable this to ignore them
|
|
227
|
+
/// instead.
|
|
228
|
+
IterMode[IterMode["IgnoreMounts"] = 4] = "IgnoreMounts";
|
|
229
|
+
/// This option only applies in
|
|
230
|
+
/// [`enter`](#common.SyntaxNode.enter)-style methods. It tells the
|
|
231
|
+
/// library to not enter mounted overlays if one covers the given
|
|
232
|
+
/// position.
|
|
233
|
+
IterMode[IterMode["IgnoreOverlays"] = 8] = "IgnoreOverlays";
|
|
234
|
+
})(IterMode || (IterMode = {}));
|
|
217
235
|
/// A piece of syntax tree. There are two ways to approach these
|
|
218
236
|
/// trees: the way they are actually stored in memory, and the
|
|
219
237
|
/// convenient way.
|
|
@@ -272,25 +290,22 @@ class Tree {
|
|
|
272
290
|
(/\W/.test(this.type.name) && !this.type.isError ? JSON.stringify(this.type.name) : this.type.name) +
|
|
273
291
|
(children.length ? "(" + children + ")" : "");
|
|
274
292
|
}
|
|
275
|
-
/// Get a [tree cursor](#common.TreeCursor)
|
|
276
|
-
///
|
|
277
|
-
///
|
|
278
|
-
cursor(
|
|
279
|
-
|
|
293
|
+
/// Get a [tree cursor](#common.TreeCursor) positioned at the top of
|
|
294
|
+
/// the tree. Mode can be used to [control](#common.IterMode) which
|
|
295
|
+
/// nodes the cursor visits.
|
|
296
|
+
cursor(mode = 0) {
|
|
297
|
+
return new TreeCursor(this.topNode, mode);
|
|
298
|
+
}
|
|
299
|
+
/// Get a [tree cursor](#common.TreeCursor) pointing into this tree
|
|
300
|
+
/// at the given position and side (see
|
|
301
|
+
/// [`moveTo`](#common.TreeCursor.moveTo).
|
|
302
|
+
cursorAt(pos, side = 0, mode = 0) {
|
|
303
|
+
let scope = CachedNode.get(this) || this.topNode;
|
|
280
304
|
let cursor = new TreeCursor(scope);
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
CachedNode.set(this, cursor._tree);
|
|
284
|
-
}
|
|
305
|
+
cursor.moveTo(pos, side);
|
|
306
|
+
CachedNode.set(this, cursor._tree);
|
|
285
307
|
return cursor;
|
|
286
308
|
}
|
|
287
|
-
/// Get a [tree cursor](#common.TreeCursor) that, unlike regular
|
|
288
|
-
/// cursors, doesn't skip through
|
|
289
|
-
/// [anonymous](#common.NodeType.isAnonymous) nodes and doesn't
|
|
290
|
-
/// automatically enter mounted nodes.
|
|
291
|
-
fullCursor() {
|
|
292
|
-
return new TreeCursor(this.topNode, 1 /* Full */);
|
|
293
|
-
}
|
|
294
309
|
/// Get a [syntax node](#common.SyntaxNode) object for the top of the
|
|
295
310
|
/// tree.
|
|
296
311
|
get topNode() {
|
|
@@ -302,7 +317,9 @@ class Tree {
|
|
|
302
317
|
/// position. With 0, it'll only enter nodes that cover the position
|
|
303
318
|
/// from both sides.
|
|
304
319
|
resolve(pos, side = 0) {
|
|
305
|
-
|
|
320
|
+
let node = resolveNode(CachedNode.get(this) || this.topNode, pos, side, false);
|
|
321
|
+
CachedNode.set(this, node);
|
|
322
|
+
return node;
|
|
306
323
|
}
|
|
307
324
|
/// Like [`resolve`](#common.Tree.resolve), but will enter
|
|
308
325
|
/// [overlaid](#common.MountedTree.overlay) nodes, producing a syntax node
|
|
@@ -310,13 +327,9 @@ class Tree {
|
|
|
310
327
|
/// (with parent links going through all parent structure, including
|
|
311
328
|
/// the host trees).
|
|
312
329
|
resolveInner(pos, side = 0) {
|
|
313
|
-
let
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
if (!inner)
|
|
317
|
-
return result;
|
|
318
|
-
result = inner;
|
|
319
|
-
}
|
|
330
|
+
let node = resolveNode(CachedInnerNode.get(this) || this.topNode, pos, side, true);
|
|
331
|
+
CachedInnerNode.set(this, node);
|
|
332
|
+
return node;
|
|
320
333
|
}
|
|
321
334
|
/// Iterate over the tree and its children, calling `enter` for any
|
|
322
335
|
/// node that touches the `from`/`to` region (if given) before
|
|
@@ -325,23 +338,21 @@ class Tree {
|
|
|
325
338
|
/// not have its children iterated over (or `leave` called).
|
|
326
339
|
iterate(spec) {
|
|
327
340
|
let { enter, leave, from = 0, to = this.length } = spec;
|
|
328
|
-
for (let c = this.cursor(
|
|
329
|
-
let
|
|
330
|
-
if (c.from <= to && c.to >= from && (c.type.isAnonymous || enter(c
|
|
341
|
+
for (let c = this.cursor((spec.mode || 0) | IterMode.IncludeAnonymous);;) {
|
|
342
|
+
let entered = false;
|
|
343
|
+
if (c.from <= to && c.to >= from && (c.type.isAnonymous || enter(c) !== false)) {
|
|
331
344
|
if (c.firstChild())
|
|
332
345
|
continue;
|
|
333
|
-
|
|
334
|
-
mustLeave = true;
|
|
346
|
+
entered = true;
|
|
335
347
|
}
|
|
336
348
|
for (;;) {
|
|
337
|
-
if (
|
|
338
|
-
leave(c
|
|
339
|
-
mustLeave = c.type.isAnonymous;
|
|
349
|
+
if (entered && leave && !c.type.isAnonymous)
|
|
350
|
+
leave(c);
|
|
340
351
|
if (c.nextSibling())
|
|
341
352
|
break;
|
|
342
353
|
if (!c.parent())
|
|
343
354
|
return;
|
|
344
|
-
|
|
355
|
+
entered = true;
|
|
345
356
|
}
|
|
346
357
|
}
|
|
347
358
|
}
|
|
@@ -481,59 +492,84 @@ function enterUnfinishedNodesBefore(node, pos) {
|
|
|
481
492
|
}
|
|
482
493
|
return node;
|
|
483
494
|
}
|
|
495
|
+
function resolveNode(node, pos, side, overlays) {
|
|
496
|
+
var _a;
|
|
497
|
+
// Move up to a node that actually holds the position, if possible
|
|
498
|
+
while (node.from == node.to ||
|
|
499
|
+
(side < 1 ? node.from >= pos : node.from > pos) ||
|
|
500
|
+
(side > -1 ? node.to <= pos : node.to < pos)) {
|
|
501
|
+
let parent = !overlays && node instanceof TreeNode && node.index < 0 ? null : node.parent;
|
|
502
|
+
if (!parent)
|
|
503
|
+
return node;
|
|
504
|
+
node = parent;
|
|
505
|
+
}
|
|
506
|
+
let mode = overlays ? 0 : IterMode.IgnoreOverlays;
|
|
507
|
+
// Must go up out of overlays when those do not overlap with pos
|
|
508
|
+
if (overlays)
|
|
509
|
+
for (let scan = node, parent = scan.parent; parent; scan = parent, parent = scan.parent) {
|
|
510
|
+
if (scan instanceof TreeNode && scan.index < 0 && ((_a = parent.enter(pos, side, mode)) === null || _a === void 0 ? void 0 : _a.from) != scan.from)
|
|
511
|
+
node = parent;
|
|
512
|
+
}
|
|
513
|
+
for (;;) {
|
|
514
|
+
let inner = node.enter(pos, side, mode);
|
|
515
|
+
if (!inner)
|
|
516
|
+
return node;
|
|
517
|
+
node = inner;
|
|
518
|
+
}
|
|
519
|
+
}
|
|
484
520
|
class TreeNode {
|
|
485
|
-
constructor(
|
|
521
|
+
constructor(_tree, from,
|
|
486
522
|
// Index in parent node, set to -1 if the node is not a direct child of _parent.node (overlay)
|
|
487
523
|
index, _parent) {
|
|
488
|
-
this.
|
|
489
|
-
this.
|
|
524
|
+
this._tree = _tree;
|
|
525
|
+
this.from = from;
|
|
490
526
|
this.index = index;
|
|
491
527
|
this._parent = _parent;
|
|
492
528
|
}
|
|
493
|
-
get type() { return this.
|
|
494
|
-
get name() { return this.
|
|
495
|
-
get
|
|
496
|
-
get to() { return this._from + this.node.length; }
|
|
529
|
+
get type() { return this._tree.type; }
|
|
530
|
+
get name() { return this._tree.type.name; }
|
|
531
|
+
get to() { return this.from + this._tree.length; }
|
|
497
532
|
nextChild(i, dir, pos, side, mode = 0) {
|
|
498
533
|
for (let parent = this;;) {
|
|
499
|
-
for (let { children, positions } = parent.
|
|
500
|
-
let next = children[i], start = positions[i] + parent.
|
|
534
|
+
for (let { children, positions } = parent._tree, e = dir > 0 ? children.length : -1; i != e; i += dir) {
|
|
535
|
+
let next = children[i], start = positions[i] + parent.from;
|
|
501
536
|
if (!checkSide(side, pos, start, start + next.length))
|
|
502
537
|
continue;
|
|
503
538
|
if (next instanceof TreeBuffer) {
|
|
504
|
-
if (mode &
|
|
539
|
+
if (mode & IterMode.ExcludeBuffers)
|
|
505
540
|
continue;
|
|
506
541
|
let index = next.findChild(0, next.buffer.length, dir, pos - start, side);
|
|
507
542
|
if (index > -1)
|
|
508
543
|
return new BufferNode(new BufferContext(parent, next, i, start), null, index);
|
|
509
544
|
}
|
|
510
|
-
else if ((mode &
|
|
545
|
+
else if ((mode & IterMode.IncludeAnonymous) || (!next.type.isAnonymous || hasChild(next))) {
|
|
511
546
|
let mounted;
|
|
512
|
-
if (!(mode &
|
|
547
|
+
if (!(mode & IterMode.IgnoreMounts) &&
|
|
548
|
+
next.props && (mounted = next.prop(NodeProp.mounted)) && !mounted.overlay)
|
|
513
549
|
return new TreeNode(mounted.tree, start, i, parent);
|
|
514
550
|
let inner = new TreeNode(next, start, i, parent);
|
|
515
|
-
return (mode &
|
|
551
|
+
return (mode & IterMode.IncludeAnonymous) || !inner.type.isAnonymous ? inner
|
|
516
552
|
: inner.nextChild(dir < 0 ? next.children.length - 1 : 0, dir, pos, side);
|
|
517
553
|
}
|
|
518
554
|
}
|
|
519
|
-
if ((mode &
|
|
555
|
+
if ((mode & IterMode.IncludeAnonymous) || !parent.type.isAnonymous)
|
|
520
556
|
return null;
|
|
521
557
|
if (parent.index >= 0)
|
|
522
558
|
i = parent.index + dir;
|
|
523
559
|
else
|
|
524
|
-
i = dir < 0 ? -1 : parent._parent.
|
|
560
|
+
i = dir < 0 ? -1 : parent._parent._tree.children.length;
|
|
525
561
|
parent = parent._parent;
|
|
526
562
|
if (!parent)
|
|
527
563
|
return null;
|
|
528
564
|
}
|
|
529
565
|
}
|
|
530
566
|
get firstChild() { return this.nextChild(0, 1, 0, 4 /* DontCare */); }
|
|
531
|
-
get lastChild() { return this.nextChild(this.
|
|
567
|
+
get lastChild() { return this.nextChild(this._tree.children.length - 1, -1, 0, 4 /* DontCare */); }
|
|
532
568
|
childAfter(pos) { return this.nextChild(0, 1, pos, 2 /* After */); }
|
|
533
|
-
childBefore(pos) { return this.nextChild(this.
|
|
534
|
-
enter(pos, side,
|
|
569
|
+
childBefore(pos) { return this.nextChild(this._tree.children.length - 1, -1, pos, -2 /* Before */); }
|
|
570
|
+
enter(pos, side, mode = 0) {
|
|
535
571
|
let mounted;
|
|
536
|
-
if (
|
|
572
|
+
if (!(mode & IterMode.IgnoreOverlays) && (mounted = this._tree.prop(NodeProp.mounted)) && mounted.overlay) {
|
|
537
573
|
let rPos = pos - this.from;
|
|
538
574
|
for (let { from, to } of mounted.overlay) {
|
|
539
575
|
if ((side > 0 ? from <= rPos : from < rPos) &&
|
|
@@ -541,7 +577,7 @@ class TreeNode {
|
|
|
541
577
|
return new TreeNode(mounted.tree, mounted.overlay[0].from + this.from, -1, this);
|
|
542
578
|
}
|
|
543
579
|
}
|
|
544
|
-
return this.nextChild(0, 1, pos, side,
|
|
580
|
+
return this.nextChild(0, 1, pos, side, mode);
|
|
545
581
|
}
|
|
546
582
|
nextSignificantParent() {
|
|
547
583
|
let val = this;
|
|
@@ -558,11 +594,14 @@ class TreeNode {
|
|
|
558
594
|
get prevSibling() {
|
|
559
595
|
return this._parent && this.index >= 0 ? this._parent.nextChild(this.index - 1, -1, 0, 4 /* DontCare */) : null;
|
|
560
596
|
}
|
|
561
|
-
|
|
562
|
-
get tree() { return this.
|
|
563
|
-
toTree() { return this.
|
|
597
|
+
cursor(mode = 0) { return new TreeCursor(this, mode); }
|
|
598
|
+
get tree() { return this._tree; }
|
|
599
|
+
toTree() { return this._tree; }
|
|
564
600
|
resolve(pos, side = 0) {
|
|
565
|
-
return this
|
|
601
|
+
return resolveNode(this, pos, side, false);
|
|
602
|
+
}
|
|
603
|
+
resolveInner(pos, side = 0) {
|
|
604
|
+
return resolveNode(this, pos, side, true);
|
|
566
605
|
}
|
|
567
606
|
enterUnfinishedNodesBefore(pos) { return enterUnfinishedNodesBefore(this, pos); }
|
|
568
607
|
getChild(type, before = null, after = null) {
|
|
@@ -573,10 +612,12 @@ class TreeNode {
|
|
|
573
612
|
return getChildren(this, type, before, after);
|
|
574
613
|
}
|
|
575
614
|
/// @internal
|
|
576
|
-
toString() { return this.
|
|
615
|
+
toString() { return this._tree.toString(); }
|
|
616
|
+
get node() { return this; }
|
|
617
|
+
matchContext(context) { return matchNodeContext(this, context); }
|
|
577
618
|
}
|
|
578
619
|
function getChildren(node, type, before, after) {
|
|
579
|
-
let cur = node.cursor, result = [];
|
|
620
|
+
let cur = node.cursor(), result = [];
|
|
580
621
|
if (!cur.firstChild())
|
|
581
622
|
return result;
|
|
582
623
|
if (before != null)
|
|
@@ -592,6 +633,18 @@ function getChildren(node, type, before, after) {
|
|
|
592
633
|
return after == null ? result : [];
|
|
593
634
|
}
|
|
594
635
|
}
|
|
636
|
+
function matchNodeContext(node, context, i = context.length - 1) {
|
|
637
|
+
for (let p = node.parent; i >= 0; p = p.parent) {
|
|
638
|
+
if (!p)
|
|
639
|
+
return false;
|
|
640
|
+
if (!p.type.isAnonymous) {
|
|
641
|
+
if (context[i] && context[i] != p.name)
|
|
642
|
+
return false;
|
|
643
|
+
i--;
|
|
644
|
+
}
|
|
645
|
+
}
|
|
646
|
+
return true;
|
|
647
|
+
}
|
|
595
648
|
class BufferContext {
|
|
596
649
|
constructor(parent, buffer, index, start) {
|
|
597
650
|
this.parent = parent;
|
|
@@ -619,8 +672,8 @@ class BufferNode {
|
|
|
619
672
|
get lastChild() { return this.child(-1, 0, 4 /* DontCare */); }
|
|
620
673
|
childAfter(pos) { return this.child(1, pos, 2 /* After */); }
|
|
621
674
|
childBefore(pos) { return this.child(-1, pos, -2 /* Before */); }
|
|
622
|
-
enter(pos, side,
|
|
623
|
-
if (
|
|
675
|
+
enter(pos, side, mode = 0) {
|
|
676
|
+
if (mode & IterMode.ExcludeBuffers)
|
|
624
677
|
return null;
|
|
625
678
|
let { buffer } = this.context;
|
|
626
679
|
let index = buffer.findChild(this.index + 4, buffer.buffer[this.index + 3], side > 0 ? 1 : -1, pos - this.context.start, side);
|
|
@@ -646,7 +699,7 @@ class BufferNode {
|
|
|
646
699
|
return this.externalSibling(-1);
|
|
647
700
|
return new BufferNode(this.context, this._parent, buffer.findChild(parentStart, this.index, -1, 0, 4 /* DontCare */));
|
|
648
701
|
}
|
|
649
|
-
|
|
702
|
+
cursor(mode = 0) { return new TreeCursor(this, mode); }
|
|
650
703
|
get tree() { return null; }
|
|
651
704
|
toTree() {
|
|
652
705
|
let children = [], positions = [];
|
|
@@ -660,7 +713,10 @@ class BufferNode {
|
|
|
660
713
|
return new Tree(this.type, children, positions, this.to - this.from);
|
|
661
714
|
}
|
|
662
715
|
resolve(pos, side = 0) {
|
|
663
|
-
return this
|
|
716
|
+
return resolveNode(this, pos, side, false);
|
|
717
|
+
}
|
|
718
|
+
resolveInner(pos, side = 0) {
|
|
719
|
+
return resolveNode(this, pos, side, true);
|
|
664
720
|
}
|
|
665
721
|
enterUnfinishedNodesBefore(pos) { return enterUnfinishedNodesBefore(this, pos); }
|
|
666
722
|
/// @internal
|
|
@@ -672,6 +728,8 @@ class BufferNode {
|
|
|
672
728
|
getChildren(type, before = null, after = null) {
|
|
673
729
|
return getChildren(this, type, before, after);
|
|
674
730
|
}
|
|
731
|
+
get node() { return this; }
|
|
732
|
+
matchContext(context) { return matchNodeContext(this, context); }
|
|
675
733
|
}
|
|
676
734
|
/// A tree cursor object focuses on a given node in a syntax tree, and
|
|
677
735
|
/// allows you to move to adjacent nodes.
|
|
@@ -681,8 +739,10 @@ class TreeCursor {
|
|
|
681
739
|
/// @internal
|
|
682
740
|
mode = 0) {
|
|
683
741
|
this.mode = mode;
|
|
742
|
+
/// @internal
|
|
684
743
|
this.buffer = null;
|
|
685
744
|
this.stack = [];
|
|
745
|
+
/// @internal
|
|
686
746
|
this.index = 0;
|
|
687
747
|
this.bufferNode = null;
|
|
688
748
|
if (node instanceof TreeNode) {
|
|
@@ -733,7 +793,7 @@ class TreeCursor {
|
|
|
733
793
|
/// @internal
|
|
734
794
|
enterChild(dir, pos, side) {
|
|
735
795
|
if (!this.buffer)
|
|
736
|
-
return this.yield(this._tree.nextChild(dir < 0 ? this._tree.
|
|
796
|
+
return this.yield(this._tree.nextChild(dir < 0 ? this._tree._tree.children.length - 1 : 0, dir, pos, side, this.mode));
|
|
737
797
|
let { buffer } = this.buffer;
|
|
738
798
|
let index = buffer.findChild(this.index + 4, buffer.buffer[this.index + 3], dir, pos - this.buffer.start, side);
|
|
739
799
|
if (index < 0)
|
|
@@ -755,18 +815,18 @@ class TreeCursor {
|
|
|
755
815
|
/// will also enter [overlaid](#common.MountedTree.overlay)
|
|
756
816
|
/// [mounted](#common.NodeProp^mounted) trees unless `overlays` is
|
|
757
817
|
/// set to false.
|
|
758
|
-
enter(pos, side,
|
|
818
|
+
enter(pos, side, mode = this.mode) {
|
|
759
819
|
if (!this.buffer)
|
|
760
|
-
return this.yield(this._tree.enter(pos, side,
|
|
761
|
-
return
|
|
820
|
+
return this.yield(this._tree.enter(pos, side, mode));
|
|
821
|
+
return mode & IterMode.ExcludeBuffers ? false : this.enterChild(1, pos, side);
|
|
762
822
|
}
|
|
763
823
|
/// Move to the node's parent node, if this isn't the top node.
|
|
764
824
|
parent() {
|
|
765
825
|
if (!this.buffer)
|
|
766
|
-
return this.yieldNode((this.mode &
|
|
826
|
+
return this.yieldNode((this.mode & IterMode.IncludeAnonymous) ? this._tree._parent : this._tree.parent);
|
|
767
827
|
if (this.stack.length)
|
|
768
828
|
return this.yieldBuf(this.stack.pop());
|
|
769
|
-
let parent = (this.mode &
|
|
829
|
+
let parent = (this.mode & IterMode.IncludeAnonymous) ? this.buffer.parent : this.buffer.parent.nextSignificantParent();
|
|
770
830
|
this.buffer = null;
|
|
771
831
|
return this.yieldNode(parent);
|
|
772
832
|
}
|
|
@@ -812,9 +872,12 @@ class TreeCursor {
|
|
|
812
872
|
}
|
|
813
873
|
for (; parent; { index, _parent: parent } = parent) {
|
|
814
874
|
if (index > -1)
|
|
815
|
-
for (let i = index + dir, e = dir < 0 ? -1 : parent.
|
|
816
|
-
let child = parent.
|
|
817
|
-
if ((this.mode &
|
|
875
|
+
for (let i = index + dir, e = dir < 0 ? -1 : parent._tree.children.length; i != e; i += dir) {
|
|
876
|
+
let child = parent._tree.children[i];
|
|
877
|
+
if ((this.mode & IterMode.IncludeAnonymous) ||
|
|
878
|
+
child instanceof TreeBuffer ||
|
|
879
|
+
!child.type.isAnonymous ||
|
|
880
|
+
hasChild(child))
|
|
818
881
|
return false;
|
|
819
882
|
}
|
|
820
883
|
}
|
|
@@ -882,7 +945,55 @@ class TreeCursor {
|
|
|
882
945
|
/// any. Will return null when the node is in a [tree
|
|
883
946
|
/// buffer](#common.TreeBuffer).
|
|
884
947
|
get tree() {
|
|
885
|
-
return this.buffer ? null : this._tree.
|
|
948
|
+
return this.buffer ? null : this._tree._tree;
|
|
949
|
+
}
|
|
950
|
+
/// Iterate over the current node and all its descendants, calling
|
|
951
|
+
/// `enter` when entering a node and `leave`, if given, when leaving
|
|
952
|
+
/// one. When `enter` returns `false`, any children of that node are
|
|
953
|
+
/// skipped, and `leave` isn't called for it.
|
|
954
|
+
iterate(enter, leave) {
|
|
955
|
+
for (let depth = 0;;) {
|
|
956
|
+
let mustLeave = false;
|
|
957
|
+
if (this.type.isAnonymous || enter(this) !== false) {
|
|
958
|
+
if (this.firstChild()) {
|
|
959
|
+
depth++;
|
|
960
|
+
continue;
|
|
961
|
+
}
|
|
962
|
+
if (!this.type.isAnonymous)
|
|
963
|
+
mustLeave = true;
|
|
964
|
+
}
|
|
965
|
+
for (;;) {
|
|
966
|
+
if (mustLeave && leave)
|
|
967
|
+
leave(this);
|
|
968
|
+
mustLeave = this.type.isAnonymous;
|
|
969
|
+
if (this.nextSibling())
|
|
970
|
+
break;
|
|
971
|
+
if (!depth)
|
|
972
|
+
return;
|
|
973
|
+
this.parent();
|
|
974
|
+
depth--;
|
|
975
|
+
mustLeave = true;
|
|
976
|
+
}
|
|
977
|
+
}
|
|
978
|
+
}
|
|
979
|
+
/// Test whether the current node matches a given context—a sequence
|
|
980
|
+
/// of direct parent node names. Empty strings in the context array
|
|
981
|
+
/// are treated as wildcards.
|
|
982
|
+
matchContext(context) {
|
|
983
|
+
if (!this.buffer)
|
|
984
|
+
return matchNodeContext(this.node, context);
|
|
985
|
+
let { buffer } = this.buffer, { types } = buffer.set;
|
|
986
|
+
for (let i = context.length - 1, d = this.stack.length - 1; i >= 0; d--) {
|
|
987
|
+
if (d < 0)
|
|
988
|
+
return matchNodeContext(this.node, context, i);
|
|
989
|
+
let type = types[buffer.buffer[this.stack[d]]];
|
|
990
|
+
if (!type.isAnonymous) {
|
|
991
|
+
if (context[i] && context[i] != type.name)
|
|
992
|
+
return false;
|
|
993
|
+
i--;
|
|
994
|
+
}
|
|
995
|
+
}
|
|
996
|
+
return true;
|
|
886
997
|
}
|
|
887
998
|
}
|
|
888
999
|
function hasChild(tree) {
|
|
@@ -1142,15 +1253,564 @@ mkTree) {
|
|
|
1142
1253
|
divide(children, positions, from, to, 0);
|
|
1143
1254
|
return (mkTop || mkTree)(localChildren, localPositions, length);
|
|
1144
1255
|
}
|
|
1256
|
+
/// Provides a way to associate values with pieces of trees. As long
|
|
1257
|
+
/// as that part of the tree is reused, the associated values can be
|
|
1258
|
+
/// retrieved from an updated tree.
|
|
1259
|
+
class NodeWeakMap {
|
|
1260
|
+
constructor() {
|
|
1261
|
+
this.map = new WeakMap();
|
|
1262
|
+
}
|
|
1263
|
+
setBuffer(buffer, index, value) {
|
|
1264
|
+
let inner = this.map.get(buffer);
|
|
1265
|
+
if (!inner)
|
|
1266
|
+
this.map.set(buffer, inner = new Map);
|
|
1267
|
+
inner.set(index, value);
|
|
1268
|
+
}
|
|
1269
|
+
getBuffer(buffer, index) {
|
|
1270
|
+
let inner = this.map.get(buffer);
|
|
1271
|
+
return inner && inner.get(index);
|
|
1272
|
+
}
|
|
1273
|
+
/// Set the value for this syntax node.
|
|
1274
|
+
set(node, value) {
|
|
1275
|
+
if (node instanceof BufferNode)
|
|
1276
|
+
this.setBuffer(node.context.buffer, node.index, value);
|
|
1277
|
+
else if (node instanceof TreeNode)
|
|
1278
|
+
this.map.set(node.tree, value);
|
|
1279
|
+
}
|
|
1280
|
+
/// Retrieve value for this syntax node, if it exists in the map.
|
|
1281
|
+
get(node) {
|
|
1282
|
+
return node instanceof BufferNode ? this.getBuffer(node.context.buffer, node.index)
|
|
1283
|
+
: node instanceof TreeNode ? this.map.get(node.tree) : undefined;
|
|
1284
|
+
}
|
|
1285
|
+
/// Set the value for the node that a cursor currently points to.
|
|
1286
|
+
cursorSet(cursor, value) {
|
|
1287
|
+
if (cursor.buffer)
|
|
1288
|
+
this.setBuffer(cursor.buffer.buffer, cursor.index, value);
|
|
1289
|
+
else
|
|
1290
|
+
this.map.set(cursor.tree, value);
|
|
1291
|
+
}
|
|
1292
|
+
/// Retrieve the value for the node that a cursor currently points
|
|
1293
|
+
/// to.
|
|
1294
|
+
cursorGet(cursor) {
|
|
1295
|
+
return cursor.buffer ? this.getBuffer(cursor.buffer.buffer, cursor.index) : this.map.get(cursor.tree);
|
|
1296
|
+
}
|
|
1297
|
+
}
|
|
1298
|
+
|
|
1299
|
+
/// Tree fragments are used during [incremental
|
|
1300
|
+
/// parsing](#common.Parser.startParse) to track parts of old trees
|
|
1301
|
+
/// that can be reused in a new parse. An array of fragments is used
|
|
1302
|
+
/// to track regions of an old tree whose nodes might be reused in new
|
|
1303
|
+
/// parses. Use the static
|
|
1304
|
+
/// [`applyChanges`](#common.TreeFragment^applyChanges) method to
|
|
1305
|
+
/// update fragments for document changes.
|
|
1306
|
+
class TreeFragment {
|
|
1307
|
+
/// Construct a tree fragment.
|
|
1308
|
+
constructor(
|
|
1309
|
+
/// The start of the unchanged range pointed to by this fragment.
|
|
1310
|
+
/// This refers to an offset in the _updated_ document (as opposed
|
|
1311
|
+
/// to the original tree).
|
|
1312
|
+
from,
|
|
1313
|
+
/// The end of the unchanged range.
|
|
1314
|
+
to,
|
|
1315
|
+
/// The tree that this fragment is based on.
|
|
1316
|
+
tree,
|
|
1317
|
+
/// The offset between the fragment's tree and the document that
|
|
1318
|
+
/// this fragment can be used against. Add this when going from
|
|
1319
|
+
/// document to tree positions, subtract it to go from tree to
|
|
1320
|
+
/// document positions.
|
|
1321
|
+
offset, openStart = false, openEnd = false) {
|
|
1322
|
+
this.from = from;
|
|
1323
|
+
this.to = to;
|
|
1324
|
+
this.tree = tree;
|
|
1325
|
+
this.offset = offset;
|
|
1326
|
+
this.open = (openStart ? 1 /* Start */ : 0) | (openEnd ? 2 /* End */ : 0);
|
|
1327
|
+
}
|
|
1328
|
+
/// Whether the start of the fragment represents the start of a
|
|
1329
|
+
/// parse, or the end of a change. (In the second case, it may not
|
|
1330
|
+
/// be safe to reuse some nodes at the start, depending on the
|
|
1331
|
+
/// parsing algorithm.)
|
|
1332
|
+
get openStart() { return (this.open & 1 /* Start */) > 0; }
|
|
1333
|
+
/// Whether the end of the fragment represents the end of a
|
|
1334
|
+
/// full-document parse, or the start of a change.
|
|
1335
|
+
get openEnd() { return (this.open & 2 /* End */) > 0; }
|
|
1336
|
+
/// Create a set of fragments from a freshly parsed tree, or update
|
|
1337
|
+
/// an existing set of fragments by replacing the ones that overlap
|
|
1338
|
+
/// with a tree with content from the new tree. When `partial` is
|
|
1339
|
+
/// true, the parse is treated as incomplete, and the resulting
|
|
1340
|
+
/// fragment has [`openEnd`](#common.TreeFragment.openEnd) set to
|
|
1341
|
+
/// true.
|
|
1342
|
+
static addTree(tree, fragments = [], partial = false) {
|
|
1343
|
+
let result = [new TreeFragment(0, tree.length, tree, 0, false, partial)];
|
|
1344
|
+
for (let f of fragments)
|
|
1345
|
+
if (f.to > tree.length)
|
|
1346
|
+
result.push(f);
|
|
1347
|
+
return result;
|
|
1348
|
+
}
|
|
1349
|
+
/// Apply a set of edits to an array of fragments, removing or
|
|
1350
|
+
/// splitting fragments as necessary to remove edited ranges, and
|
|
1351
|
+
/// adjusting offsets for fragments that moved.
|
|
1352
|
+
static applyChanges(fragments, changes, minGap = 128) {
|
|
1353
|
+
if (!changes.length)
|
|
1354
|
+
return fragments;
|
|
1355
|
+
let result = [];
|
|
1356
|
+
let fI = 1, nextF = fragments.length ? fragments[0] : null;
|
|
1357
|
+
for (let cI = 0, pos = 0, off = 0;; cI++) {
|
|
1358
|
+
let nextC = cI < changes.length ? changes[cI] : null;
|
|
1359
|
+
let nextPos = nextC ? nextC.fromA : 1e9;
|
|
1360
|
+
if (nextPos - pos >= minGap)
|
|
1361
|
+
while (nextF && nextF.from < nextPos) {
|
|
1362
|
+
let cut = nextF;
|
|
1363
|
+
if (pos >= cut.from || nextPos <= cut.to || off) {
|
|
1364
|
+
let fFrom = Math.max(cut.from, pos) - off, fTo = Math.min(cut.to, nextPos) - off;
|
|
1365
|
+
cut = fFrom >= fTo ? null : new TreeFragment(fFrom, fTo, cut.tree, cut.offset + off, cI > 0, !!nextC);
|
|
1366
|
+
}
|
|
1367
|
+
if (cut)
|
|
1368
|
+
result.push(cut);
|
|
1369
|
+
if (nextF.to > nextPos)
|
|
1370
|
+
break;
|
|
1371
|
+
nextF = fI < fragments.length ? fragments[fI++] : null;
|
|
1372
|
+
}
|
|
1373
|
+
if (!nextC)
|
|
1374
|
+
break;
|
|
1375
|
+
pos = nextC.toA;
|
|
1376
|
+
off = nextC.toA - nextC.toB;
|
|
1377
|
+
}
|
|
1378
|
+
return result;
|
|
1379
|
+
}
|
|
1380
|
+
}
|
|
1381
|
+
/// A superclass that parsers should extend.
|
|
1382
|
+
class Parser {
|
|
1383
|
+
/// Start a parse, returning a [partial parse](#common.PartialParse)
|
|
1384
|
+
/// object. [`fragments`](#common.TreeFragment) can be passed in to
|
|
1385
|
+
/// make the parse incremental.
|
|
1386
|
+
///
|
|
1387
|
+
/// By default, the entire input is parsed. You can pass `ranges`,
|
|
1388
|
+
/// which should be a sorted array of non-empty, non-overlapping
|
|
1389
|
+
/// ranges, to parse only those ranges. The tree returned in that
|
|
1390
|
+
/// case will start at `ranges[0].from`.
|
|
1391
|
+
startParse(input, fragments, ranges) {
|
|
1392
|
+
if (typeof input == "string")
|
|
1393
|
+
input = new StringInput(input);
|
|
1394
|
+
ranges = !ranges ? [new Range(0, input.length)] : ranges.length ? ranges.map(r => new Range(r.from, r.to)) : [new Range(0, 0)];
|
|
1395
|
+
return this.createParse(input, fragments || [], ranges);
|
|
1396
|
+
}
|
|
1397
|
+
/// Run a full parse, returning the resulting tree.
|
|
1398
|
+
parse(input, fragments, ranges) {
|
|
1399
|
+
let parse = this.startParse(input, fragments, ranges);
|
|
1400
|
+
for (;;) {
|
|
1401
|
+
let done = parse.advance();
|
|
1402
|
+
if (done)
|
|
1403
|
+
return done;
|
|
1404
|
+
}
|
|
1405
|
+
}
|
|
1406
|
+
}
|
|
1407
|
+
class StringInput {
|
|
1408
|
+
constructor(string) {
|
|
1409
|
+
this.string = string;
|
|
1410
|
+
}
|
|
1411
|
+
get length() { return this.string.length; }
|
|
1412
|
+
chunk(from) { return this.string.slice(from); }
|
|
1413
|
+
get lineChunks() { return false; }
|
|
1414
|
+
read(from, to) { return this.string.slice(from, to); }
|
|
1415
|
+
}
|
|
1416
|
+
|
|
1417
|
+
/// Create a parse wrapper that, after the inner parse completes,
|
|
1418
|
+
/// scans its tree for mixed language regions with the `nest`
|
|
1419
|
+
/// function, runs the resulting [inner parses](#common.NestedParse),
|
|
1420
|
+
/// and then [mounts](#common.NodeProp^mounted) their results onto the
|
|
1421
|
+
/// tree.
|
|
1422
|
+
///
|
|
1423
|
+
/// The nesting function is passed a cursor to provide context for a
|
|
1424
|
+
/// node, but _should not_ move that cursor, only inspect its
|
|
1425
|
+
/// properties and optionally access its
|
|
1426
|
+
/// [node object](#common.TreeCursor.node).
|
|
1427
|
+
function parseMixed(nest) {
|
|
1428
|
+
return (parse, input, fragments, ranges) => new MixedParse(parse, nest, input, fragments, ranges);
|
|
1429
|
+
}
|
|
1430
|
+
class InnerParse {
|
|
1431
|
+
constructor(parser, parse, overlay, target, ranges) {
|
|
1432
|
+
this.parser = parser;
|
|
1433
|
+
this.parse = parse;
|
|
1434
|
+
this.overlay = overlay;
|
|
1435
|
+
this.target = target;
|
|
1436
|
+
this.ranges = ranges;
|
|
1437
|
+
}
|
|
1438
|
+
}
|
|
1439
|
+
class ActiveOverlay {
|
|
1440
|
+
constructor(parser, predicate, mounts, index, start, target, prev) {
|
|
1441
|
+
this.parser = parser;
|
|
1442
|
+
this.predicate = predicate;
|
|
1443
|
+
this.mounts = mounts;
|
|
1444
|
+
this.index = index;
|
|
1445
|
+
this.start = start;
|
|
1446
|
+
this.target = target;
|
|
1447
|
+
this.prev = prev;
|
|
1448
|
+
this.depth = 0;
|
|
1449
|
+
this.ranges = [];
|
|
1450
|
+
}
|
|
1451
|
+
}
|
|
1452
|
+
const stoppedInner = new NodeProp({ perNode: true });
|
|
1453
|
+
class MixedParse {
|
|
1454
|
+
constructor(base, nest, input, fragments, ranges) {
|
|
1455
|
+
this.nest = nest;
|
|
1456
|
+
this.input = input;
|
|
1457
|
+
this.fragments = fragments;
|
|
1458
|
+
this.ranges = ranges;
|
|
1459
|
+
this.inner = [];
|
|
1460
|
+
this.innerDone = 0;
|
|
1461
|
+
this.baseTree = null;
|
|
1462
|
+
this.stoppedAt = null;
|
|
1463
|
+
this.baseParse = base;
|
|
1464
|
+
}
|
|
1465
|
+
advance() {
|
|
1466
|
+
if (this.baseParse) {
|
|
1467
|
+
let done = this.baseParse.advance();
|
|
1468
|
+
if (!done)
|
|
1469
|
+
return null;
|
|
1470
|
+
this.baseParse = null;
|
|
1471
|
+
this.baseTree = done;
|
|
1472
|
+
this.startInner();
|
|
1473
|
+
if (this.stoppedAt != null)
|
|
1474
|
+
for (let inner of this.inner)
|
|
1475
|
+
inner.parse.stopAt(this.stoppedAt);
|
|
1476
|
+
}
|
|
1477
|
+
if (this.innerDone == this.inner.length) {
|
|
1478
|
+
let result = this.baseTree;
|
|
1479
|
+
if (this.stoppedAt != null)
|
|
1480
|
+
result = new Tree(result.type, result.children, result.positions, result.length, result.propValues.concat([[stoppedInner, this.stoppedAt]]));
|
|
1481
|
+
return result;
|
|
1482
|
+
}
|
|
1483
|
+
let inner = this.inner[this.innerDone], done = inner.parse.advance();
|
|
1484
|
+
if (done) {
|
|
1485
|
+
this.innerDone++;
|
|
1486
|
+
// This is a somewhat dodgy but super helpful hack where we
|
|
1487
|
+
// patch up nodes created by the inner parse (and thus
|
|
1488
|
+
// presumably not aliased anywhere else) to hold the information
|
|
1489
|
+
// about the inner parse.
|
|
1490
|
+
let props = Object.assign(Object.create(null), inner.target.props);
|
|
1491
|
+
props[NodeProp.mounted.id] = new MountedTree(done, inner.overlay, inner.parser);
|
|
1492
|
+
inner.target.props = props;
|
|
1493
|
+
}
|
|
1494
|
+
return null;
|
|
1495
|
+
}
|
|
1496
|
+
get parsedPos() {
|
|
1497
|
+
if (this.baseParse)
|
|
1498
|
+
return 0;
|
|
1499
|
+
let pos = this.input.length;
|
|
1500
|
+
for (let i = this.innerDone; i < this.inner.length; i++) {
|
|
1501
|
+
if (this.inner[i].ranges[0].from < pos)
|
|
1502
|
+
pos = Math.min(pos, this.inner[i].parse.parsedPos);
|
|
1503
|
+
}
|
|
1504
|
+
return pos;
|
|
1505
|
+
}
|
|
1506
|
+
stopAt(pos) {
|
|
1507
|
+
this.stoppedAt = pos;
|
|
1508
|
+
if (this.baseParse)
|
|
1509
|
+
this.baseParse.stopAt(pos);
|
|
1510
|
+
else
|
|
1511
|
+
for (let i = this.innerDone; i < this.inner.length; i++)
|
|
1512
|
+
this.inner[i].parse.stopAt(pos);
|
|
1513
|
+
}
|
|
1514
|
+
startInner() {
|
|
1515
|
+
let fragmentCursor = new FragmentCursor(this.fragments);
|
|
1516
|
+
let overlay = null;
|
|
1517
|
+
let covered = null;
|
|
1518
|
+
let cursor = new TreeCursor(new TreeNode(this.baseTree, this.ranges[0].from, 0, null), IterMode.IncludeAnonymous | IterMode.IgnoreMounts);
|
|
1519
|
+
scan: for (let nest, isCovered; this.stoppedAt == null || cursor.from < this.stoppedAt;) {
|
|
1520
|
+
let enter = true, range;
|
|
1521
|
+
if (fragmentCursor.hasNode(cursor)) {
|
|
1522
|
+
if (overlay) {
|
|
1523
|
+
let match = overlay.mounts.find(m => m.frag.from <= cursor.from && m.frag.to >= cursor.to && m.mount.overlay);
|
|
1524
|
+
if (match)
|
|
1525
|
+
for (let r of match.mount.overlay) {
|
|
1526
|
+
let from = r.from + match.pos, to = r.to + match.pos;
|
|
1527
|
+
if (from >= cursor.from && to <= cursor.to && !overlay.ranges.some(r => r.from < to && r.to > from))
|
|
1528
|
+
overlay.ranges.push({ from, to });
|
|
1529
|
+
}
|
|
1530
|
+
}
|
|
1531
|
+
enter = false;
|
|
1532
|
+
}
|
|
1533
|
+
else if (covered && (isCovered = checkCover(covered.ranges, cursor.from, cursor.to))) {
|
|
1534
|
+
enter = isCovered != 2 /* Full */;
|
|
1535
|
+
}
|
|
1536
|
+
else if (!cursor.type.isAnonymous && cursor.from < cursor.to && (nest = this.nest(cursor, this.input))) {
|
|
1537
|
+
if (!cursor.tree)
|
|
1538
|
+
materialize(cursor);
|
|
1539
|
+
let oldMounts = fragmentCursor.findMounts(cursor.from, nest.parser);
|
|
1540
|
+
if (typeof nest.overlay == "function") {
|
|
1541
|
+
overlay = new ActiveOverlay(nest.parser, nest.overlay, oldMounts, this.inner.length, cursor.from, cursor.tree, overlay);
|
|
1542
|
+
}
|
|
1543
|
+
else {
|
|
1544
|
+
let ranges = punchRanges(this.ranges, nest.overlay || [new Range(cursor.from, cursor.to)]);
|
|
1545
|
+
if (ranges.length)
|
|
1546
|
+
this.inner.push(new InnerParse(nest.parser, nest.parser.startParse(this.input, enterFragments(oldMounts, ranges), ranges), nest.overlay ? nest.overlay.map(r => new Range(r.from - cursor.from, r.to - cursor.from)) : null, cursor.tree, ranges));
|
|
1547
|
+
if (!nest.overlay)
|
|
1548
|
+
enter = false;
|
|
1549
|
+
else if (ranges.length)
|
|
1550
|
+
covered = { ranges, depth: 0, prev: covered };
|
|
1551
|
+
}
|
|
1552
|
+
}
|
|
1553
|
+
else if (overlay && (range = overlay.predicate(cursor))) {
|
|
1554
|
+
if (range === true)
|
|
1555
|
+
range = new Range(cursor.from, cursor.to);
|
|
1556
|
+
if (range.from < range.to)
|
|
1557
|
+
overlay.ranges.push(range);
|
|
1558
|
+
}
|
|
1559
|
+
if (enter && cursor.firstChild()) {
|
|
1560
|
+
if (overlay)
|
|
1561
|
+
overlay.depth++;
|
|
1562
|
+
if (covered)
|
|
1563
|
+
covered.depth++;
|
|
1564
|
+
}
|
|
1565
|
+
else {
|
|
1566
|
+
for (;;) {
|
|
1567
|
+
if (cursor.nextSibling())
|
|
1568
|
+
break;
|
|
1569
|
+
if (!cursor.parent())
|
|
1570
|
+
break scan;
|
|
1571
|
+
if (overlay && !--overlay.depth) {
|
|
1572
|
+
let ranges = punchRanges(this.ranges, overlay.ranges);
|
|
1573
|
+
if (ranges.length)
|
|
1574
|
+
this.inner.splice(overlay.index, 0, new InnerParse(overlay.parser, overlay.parser.startParse(this.input, enterFragments(overlay.mounts, ranges), ranges), overlay.ranges.map(r => new Range(r.from - overlay.start, r.to - overlay.start)), overlay.target, ranges));
|
|
1575
|
+
overlay = overlay.prev;
|
|
1576
|
+
}
|
|
1577
|
+
if (covered && !--covered.depth)
|
|
1578
|
+
covered = covered.prev;
|
|
1579
|
+
}
|
|
1580
|
+
}
|
|
1581
|
+
}
|
|
1582
|
+
}
|
|
1583
|
+
}
|
|
1584
|
+
function checkCover(covered, from, to) {
|
|
1585
|
+
for (let range of covered) {
|
|
1586
|
+
if (range.from >= to)
|
|
1587
|
+
break;
|
|
1588
|
+
if (range.to > from)
|
|
1589
|
+
return range.from <= from && range.to >= to ? 2 /* Full */ : 1 /* Partial */;
|
|
1590
|
+
}
|
|
1591
|
+
return 0 /* None */;
|
|
1592
|
+
}
|
|
1593
|
+
// Take a piece of buffer and convert it into a stand-alone
|
|
1594
|
+
// TreeBuffer.
|
|
1595
|
+
function sliceBuf(buf, startI, endI, nodes, positions, off) {
|
|
1596
|
+
if (startI < endI) {
|
|
1597
|
+
let from = buf.buffer[startI + 1], to = buf.buffer[endI - 2];
|
|
1598
|
+
nodes.push(buf.slice(startI, endI, from, to));
|
|
1599
|
+
positions.push(from - off);
|
|
1600
|
+
}
|
|
1601
|
+
}
|
|
1602
|
+
// This function takes a node that's in a buffer, and converts it, and
|
|
1603
|
+
// its parent buffer nodes, into a Tree. This is again acting on the
|
|
1604
|
+
// assumption that the trees and buffers have been constructed by the
|
|
1605
|
+
// parse that was ran via the mix parser, and thus aren't shared with
|
|
1606
|
+
// any other code, making violations of the immutability safe.
|
|
1607
|
+
function materialize(cursor) {
|
|
1608
|
+
let { node } = cursor, depth = 0;
|
|
1609
|
+
// Scan up to the nearest tree
|
|
1610
|
+
do {
|
|
1611
|
+
cursor.parent();
|
|
1612
|
+
depth++;
|
|
1613
|
+
} while (!cursor.tree);
|
|
1614
|
+
// Find the index of the buffer in that tree
|
|
1615
|
+
let i = 0, base = cursor.tree, off = 0;
|
|
1616
|
+
for (;; i++) {
|
|
1617
|
+
off = base.positions[i] + cursor.from;
|
|
1618
|
+
if (off <= node.from && off + base.children[i].length >= node.to)
|
|
1619
|
+
break;
|
|
1620
|
+
}
|
|
1621
|
+
let buf = base.children[i], b = buf.buffer;
|
|
1622
|
+
// Split a level in the buffer, putting the nodes before and after
|
|
1623
|
+
// the child that contains `node` into new buffers.
|
|
1624
|
+
function split(startI, endI, type, innerOffset, length) {
|
|
1625
|
+
let i = startI;
|
|
1626
|
+
while (b[i + 2] + off <= node.from)
|
|
1627
|
+
i = b[i + 3];
|
|
1628
|
+
let children = [], positions = [];
|
|
1629
|
+
sliceBuf(buf, startI, i, children, positions, innerOffset);
|
|
1630
|
+
let from = b[i + 1], to = b[i + 2];
|
|
1631
|
+
let isTarget = from + off == node.from && to + off == node.to && b[i] == node.type.id;
|
|
1632
|
+
children.push(isTarget ? node.toTree() : split(i + 4, b[i + 3], buf.set.types[b[i]], from, to - from));
|
|
1633
|
+
positions.push(from - innerOffset);
|
|
1634
|
+
sliceBuf(buf, b[i + 3], endI, children, positions, innerOffset);
|
|
1635
|
+
return new Tree(type, children, positions, length);
|
|
1636
|
+
}
|
|
1637
|
+
base.children[i] = split(0, b.length, NodeType.none, 0, buf.length);
|
|
1638
|
+
// Move the cursor back to the target node
|
|
1639
|
+
for (let d = 0; d <= depth; d++)
|
|
1640
|
+
cursor.childAfter(node.from);
|
|
1641
|
+
}
|
|
1642
|
+
class StructureCursor {
|
|
1643
|
+
constructor(root, offset) {
|
|
1644
|
+
this.offset = offset;
|
|
1645
|
+
this.done = false;
|
|
1646
|
+
this.cursor = root.cursor(IterMode.IncludeAnonymous | IterMode.IgnoreMounts);
|
|
1647
|
+
}
|
|
1648
|
+
// Move to the first node (in pre-order) that starts at or after `pos`.
|
|
1649
|
+
moveTo(pos) {
|
|
1650
|
+
let { cursor } = this, p = pos - this.offset;
|
|
1651
|
+
while (!this.done && cursor.from < p) {
|
|
1652
|
+
if (cursor.to >= pos && cursor.enter(p, 1, IterMode.IgnoreOverlays | IterMode.ExcludeBuffers)) ;
|
|
1653
|
+
else if (!cursor.next(false))
|
|
1654
|
+
this.done = true;
|
|
1655
|
+
}
|
|
1656
|
+
}
|
|
1657
|
+
hasNode(cursor) {
|
|
1658
|
+
this.moveTo(cursor.from);
|
|
1659
|
+
if (!this.done && this.cursor.from + this.offset == cursor.from && this.cursor.tree) {
|
|
1660
|
+
for (let tree = this.cursor.tree;;) {
|
|
1661
|
+
if (tree == cursor.tree)
|
|
1662
|
+
return true;
|
|
1663
|
+
if (tree.children.length && tree.positions[0] == 0 && tree.children[0] instanceof Tree)
|
|
1664
|
+
tree = tree.children[0];
|
|
1665
|
+
else
|
|
1666
|
+
break;
|
|
1667
|
+
}
|
|
1668
|
+
}
|
|
1669
|
+
return false;
|
|
1670
|
+
}
|
|
1671
|
+
}
|
|
1672
|
+
class FragmentCursor {
|
|
1673
|
+
constructor(fragments) {
|
|
1674
|
+
var _a;
|
|
1675
|
+
this.fragments = fragments;
|
|
1676
|
+
this.curTo = 0;
|
|
1677
|
+
this.fragI = 0;
|
|
1678
|
+
if (fragments.length) {
|
|
1679
|
+
let first = this.curFrag = fragments[0];
|
|
1680
|
+
this.curTo = (_a = first.tree.prop(stoppedInner)) !== null && _a !== void 0 ? _a : first.to;
|
|
1681
|
+
this.inner = new StructureCursor(first.tree, -first.offset);
|
|
1682
|
+
}
|
|
1683
|
+
else {
|
|
1684
|
+
this.curFrag = this.inner = null;
|
|
1685
|
+
}
|
|
1686
|
+
}
|
|
1687
|
+
hasNode(node) {
|
|
1688
|
+
while (this.curFrag && node.from >= this.curTo)
|
|
1689
|
+
this.nextFrag();
|
|
1690
|
+
return this.curFrag && this.curFrag.from <= node.from && this.curTo >= node.to && this.inner.hasNode(node);
|
|
1691
|
+
}
|
|
1692
|
+
nextFrag() {
|
|
1693
|
+
var _a;
|
|
1694
|
+
this.fragI++;
|
|
1695
|
+
if (this.fragI == this.fragments.length) {
|
|
1696
|
+
this.curFrag = this.inner = null;
|
|
1697
|
+
}
|
|
1698
|
+
else {
|
|
1699
|
+
let frag = this.curFrag = this.fragments[this.fragI];
|
|
1700
|
+
this.curTo = (_a = frag.tree.prop(stoppedInner)) !== null && _a !== void 0 ? _a : frag.to;
|
|
1701
|
+
this.inner = new StructureCursor(frag.tree, -frag.offset);
|
|
1702
|
+
}
|
|
1703
|
+
}
|
|
1704
|
+
findMounts(pos, parser) {
|
|
1705
|
+
var _a;
|
|
1706
|
+
let result = [];
|
|
1707
|
+
if (this.inner) {
|
|
1708
|
+
this.inner.cursor.moveTo(pos, 1);
|
|
1709
|
+
for (let pos = this.inner.cursor.node; pos; pos = pos.parent) {
|
|
1710
|
+
let mount = (_a = pos.tree) === null || _a === void 0 ? void 0 : _a.prop(NodeProp.mounted);
|
|
1711
|
+
if (mount && mount.parser == parser) {
|
|
1712
|
+
for (let i = this.fragI; i < this.fragments.length; i++) {
|
|
1713
|
+
let frag = this.fragments[i];
|
|
1714
|
+
if (frag.from >= pos.to)
|
|
1715
|
+
break;
|
|
1716
|
+
if (frag.tree == this.curFrag.tree)
|
|
1717
|
+
result.push({
|
|
1718
|
+
frag,
|
|
1719
|
+
pos: pos.from - frag.offset,
|
|
1720
|
+
mount
|
|
1721
|
+
});
|
|
1722
|
+
}
|
|
1723
|
+
}
|
|
1724
|
+
}
|
|
1725
|
+
}
|
|
1726
|
+
return result;
|
|
1727
|
+
}
|
|
1728
|
+
}
|
|
1729
|
+
function punchRanges(outer, ranges) {
|
|
1730
|
+
let copy = null, current = ranges;
|
|
1731
|
+
for (let i = 1, j = 0; i < outer.length; i++) {
|
|
1732
|
+
let gapFrom = outer[i - 1].to, gapTo = outer[i].from;
|
|
1733
|
+
for (; j < current.length; j++) {
|
|
1734
|
+
let r = current[j];
|
|
1735
|
+
if (r.from >= gapTo)
|
|
1736
|
+
break;
|
|
1737
|
+
if (r.to <= gapFrom)
|
|
1738
|
+
continue;
|
|
1739
|
+
if (!copy)
|
|
1740
|
+
current = copy = ranges.slice();
|
|
1741
|
+
if (r.from < gapFrom) {
|
|
1742
|
+
copy[j] = new Range(r.from, gapFrom);
|
|
1743
|
+
if (r.to > gapTo)
|
|
1744
|
+
copy.splice(j + 1, 0, new Range(gapTo, r.to));
|
|
1745
|
+
}
|
|
1746
|
+
else if (r.to > gapTo) {
|
|
1747
|
+
copy[j--] = new Range(gapTo, r.to);
|
|
1748
|
+
}
|
|
1749
|
+
else {
|
|
1750
|
+
copy.splice(j--, 1);
|
|
1751
|
+
}
|
|
1752
|
+
}
|
|
1753
|
+
}
|
|
1754
|
+
return current;
|
|
1755
|
+
}
|
|
1756
|
+
function findCoverChanges(a, b, from, to) {
|
|
1757
|
+
let iA = 0, iB = 0, inA = false, inB = false, pos = -1e9;
|
|
1758
|
+
let result = [];
|
|
1759
|
+
for (;;) {
|
|
1760
|
+
let nextA = iA == a.length ? 1e9 : inA ? a[iA].to : a[iA].from;
|
|
1761
|
+
let nextB = iB == b.length ? 1e9 : inB ? b[iB].to : b[iB].from;
|
|
1762
|
+
if (inA != inB) {
|
|
1763
|
+
let start = Math.max(pos, from), end = Math.min(nextA, nextB, to);
|
|
1764
|
+
if (start < end)
|
|
1765
|
+
result.push(new Range(start, end));
|
|
1766
|
+
}
|
|
1767
|
+
pos = Math.min(nextA, nextB);
|
|
1768
|
+
if (pos == 1e9)
|
|
1769
|
+
break;
|
|
1770
|
+
if (nextA == pos) {
|
|
1771
|
+
if (!inA)
|
|
1772
|
+
inA = true;
|
|
1773
|
+
else {
|
|
1774
|
+
inA = false;
|
|
1775
|
+
iA++;
|
|
1776
|
+
}
|
|
1777
|
+
}
|
|
1778
|
+
if (nextB == pos) {
|
|
1779
|
+
if (!inB)
|
|
1780
|
+
inB = true;
|
|
1781
|
+
else {
|
|
1782
|
+
inB = false;
|
|
1783
|
+
iB++;
|
|
1784
|
+
}
|
|
1785
|
+
}
|
|
1786
|
+
}
|
|
1787
|
+
return result;
|
|
1788
|
+
}
|
|
1789
|
+
// Given a number of fragments for the outer tree, and a set of ranges
|
|
1790
|
+
// to parse, find fragments for inner trees mounted around those
|
|
1791
|
+
// ranges, if any.
|
|
1792
|
+
function enterFragments(mounts, ranges) {
|
|
1793
|
+
let result = [];
|
|
1794
|
+
for (let { pos, mount, frag } of mounts) {
|
|
1795
|
+
let startPos = pos + (mount.overlay ? mount.overlay[0].from : 0), endPos = startPos + mount.tree.length;
|
|
1796
|
+
let from = Math.max(frag.from, startPos), to = Math.min(frag.to, endPos);
|
|
1797
|
+
if (mount.overlay) {
|
|
1798
|
+
let overlay = mount.overlay.map(r => new Range(r.from + pos, r.to + pos));
|
|
1799
|
+
let changes = findCoverChanges(ranges, overlay, from, to);
|
|
1800
|
+
for (let i = 0, pos = from;; i++) {
|
|
1801
|
+
let last = i == changes.length, end = last ? to : changes[i].from;
|
|
1802
|
+
if (end > pos)
|
|
1803
|
+
result.push(new TreeFragment(pos, end, mount.tree, -startPos, frag.from >= pos, frag.to <= end));
|
|
1804
|
+
if (last)
|
|
1805
|
+
break;
|
|
1806
|
+
pos = changes[i].to;
|
|
1807
|
+
}
|
|
1808
|
+
}
|
|
1809
|
+
else {
|
|
1810
|
+
result.push(new TreeFragment(from, to, mount.tree, -startPos, frag.from >= startPos, frag.to <= endPos));
|
|
1811
|
+
}
|
|
1812
|
+
}
|
|
1813
|
+
return result;
|
|
1814
|
+
}
|
|
1145
1815
|
|
|
1146
|
-
|
|
1147
|
-
exports.MountedTree = MountedTree;
|
|
1148
|
-
exports.NodeProp = NodeProp;
|
|
1149
|
-
exports.NodeSet = NodeSet;
|
|
1150
|
-
exports.NodeType = NodeType;
|
|
1151
|
-
exports.Range = Range;
|
|
1152
|
-
exports.Tree = Tree;
|
|
1153
|
-
exports.TreeBuffer = TreeBuffer;
|
|
1154
|
-
exports.TreeCursor = TreeCursor;
|
|
1155
|
-
exports.TreeNode = TreeNode;
|
|
1156
|
-
//# sourceMappingURL=tree.cjs.map
|
|
1816
|
+
export { DefaultBufferLength, IterMode, MountedTree, NodeProp, NodeSet, NodeType, NodeWeakMap, Parser, Tree, TreeBuffer, TreeCursor, TreeFragment, parseMixed };
|