Diffdown is a real-time collaborative Markdown editor/previewer built on the AT Protocol diffdown.com
1import {SyntaxNode, Parser, Input, parseMixed, SyntaxNodeRef} from "@lezer/common" 2import {Type, MarkdownExtension} from "./markdown" 3 4function leftOverSpace(node: SyntaxNode, from: number, to: number) { 5 let ranges = [] 6 for (let n = node.firstChild, pos = from;; n = n.nextSibling) { 7 let nextPos = n ? n.from : to 8 if (nextPos > pos) ranges.push({from: pos, to: nextPos}) 9 if (!n) break 10 pos = n.to 11 } 12 return ranges 13} 14 15/// Create a Markdown extension to enable nested parsing on code 16/// blocks and/or embedded HTML. 17export function parseCode(config: { 18 /// When provided, this will be used to parse the content of code 19 /// blocks. `info` is the string after the opening ` ``` ` marker, 20 /// or the empty string if there is no such info or this is an 21 /// indented code block. If there is a parser available for the 22 /// code, it should return a function that can construct the 23 /// [parse](https://lezer.codemirror.net/docs/ref/#common.PartialParse). 24 codeParser?: (info: string) => null | Parser 25 /// The parser used to parse HTML tags (both block and inline). 26 htmlParser?: Parser, 27}): MarkdownExtension { 28 let {codeParser, htmlParser} = config 29 let wrap = parseMixed((node: SyntaxNodeRef, input: Input) => { 30 let id = node.type.id 31 if (codeParser && (id == Type.CodeBlock || id == Type.FencedCode)) { 32 let info = "" 33 if (id == Type.FencedCode) { 34 let infoNode = node.node.getChild(Type.CodeInfo) 35 if (infoNode) info = input.read(infoNode.from, infoNode.to) 36 } 37 let parser = codeParser(info) 38 if (parser) 39 return {parser, overlay: node => node.type.id == Type.CodeText, bracketed: id == Type.FencedCode} 40 } else if (htmlParser && (id == Type.HTMLBlock || id == Type.HTMLTag || id == Type.CommentBlock)) { 41 return {parser: htmlParser, overlay: leftOverSpace(node.node, node.from, node.to)} 42 } 43 return null 44 }) 45 return {wrap} 46}