Deeply nested parser

Hey, and thanks for the great work on CodeMirror and Lezer!

I’ve been extending the JavaScript parser to support nested grammars with template literals, e.g.

html`<span>hello</span>`

has HTML highlighting. I have been using parseMixed to embed grammars, but am unable to nest grammars. For instance,

html`<span>hello ${"world"}</span>`

works fine, but

html`<span>hello ${html`<b>world`}</span>`

fails to highlight <b>world.

I’m using overlays to re-highlight template parts in JavaScript. The full code is:

/* wrap: */ parseMixed((node, input) => {
  if (node.type.id !== 38 /* TemplateString */) {
    return null;
  }

  const tagNode = node.node.prevSibling;

  if (tagNode === null || tagNode.type.id !== 11 /* VariableName */) {
    return null;
  }

  const tag = input.read(tagNode.from, tagNode.to);
  let parser: Parser;

  if (tag === "css") {
    parser = cssLanguage.parser;
  } else if (tag === "html") {
    parser = htmlLanguage.parser;
  } else if (tag === "md") {
    parser = markdownLanguage.parser;
  } else {
    return null;
  }

  const overlay: { from: number, to: number }[] = [];
  let from = node.from;

  for (let child = node.node.firstChild; child !== null; child = child!.nextSibling) {
    overlay.push({ from, to: child.from });
    from = child.to;
  }

  if (overlay.length === 0) {
    return { parser };
  }

  overlay.push({ from, to: node.to });

  return { parser, overlay };
})

Instead of using overlays, I thought about configuring nested parsers to highlight specific ranges in my custom syntax, but am not sure how to achieve that.

Any idea on how I could achieve any of the above ideas?

Cheers,

That was unintentional behavior. Upgrade to @lezer/common 0.15.4, it should fix it.

1 Like

Great, upgrading to 0.15.4 did fix it! Thank you.

In case anyone else is reading this in the very near future, right now other Lezer / CodeMirror packages aren’t up to date yet and will conflict with @lezer/common 0.15.4, which can be fixed by adding a resolution like so in package.json:

"resolutions": {
  "@lezer/common": "0.15.4"
}