import {SyntaxNode, Parser, Input, parseMixed, SyntaxNodeRef} from "@lezer/common" import {Type, MarkdownExtension} from "./markdown" function leftOverSpace(node: SyntaxNode, from: number, to: number) { let ranges = [] for (let n = node.firstChild, pos = from;; n = n.nextSibling) { let nextPos = n ? n.from : to if (nextPos > pos) ranges.push({from: pos, to: nextPos}) if (!n) break pos = n.to } return ranges } /// Create a Markdown extension to enable nested parsing on code /// blocks and/or embedded HTML. export function parseCode(config: { /// When provided, this will be used to parse the content of code /// blocks. `info` is the string after the opening ` ``` ` marker, /// or the empty string if there is no such info or this is an /// indented code block. If there is a parser available for the /// code, it should return a function that can construct the /// [parse](https://lezer.codemirror.net/docs/ref/#common.PartialParse). codeParser?: (info: string) => null | Parser /// The parser used to parse HTML tags (both block and inline). htmlParser?: Parser, }): MarkdownExtension { let {codeParser, htmlParser} = config let wrap = parseMixed((node: SyntaxNodeRef, input: Input) => { let id = node.type.id if (codeParser && (id == Type.CodeBlock || id == Type.FencedCode)) { let info = "" if (id == Type.FencedCode) { let infoNode = node.node.getChild(Type.CodeInfo) if (infoNode) info = input.read(infoNode.from, infoNode.to) } let parser = codeParser(info) if (parser) return {parser, overlay: node => node.type.id == Type.CodeText, bracketed: id == Type.FencedCode} } else if (htmlParser && (id == Type.HTMLBlock || id == Type.HTMLTag || id == Type.CommentBlock)) { return {parser: htmlParser, overlay: leftOverSpace(node.node, node.from, node.to)} } return null }) return {wrap} }