
Leaves.pudu
Pudu82 lines3.9 KB
1/** @Docgen.Markdown.Leaves — blocks read without nested content: code, math, and raw HTML */2module PuduLangDocgen.Markdown.Leaves34import PuduLangDocgen.Constants.Codes as Codes5import PuduLangDocgen as Docgen6import PuduLangDocgen.Markdown.Directives as Directives7import PuduLangDocgen.Markdown.FrontMatter as FrontMatter8import PuduLangDocgen.Markdown.Layout as Layout9import PuduLangDocgen.Markdown.Snippet as Snippet10import PuduLangDocgen.Markdown.Syntax as Syntax1112/** @Docgen.Markdown.Step — blocks read from one position and where reading resumes */13export type Step = { blocks: Array[Syntax.Block], next: Int, diagnostics: Array[Docgen.Diagnostic] }141516export fn fenced(lines: &Array[FrontMatter.Line], index: Int, opened: &Layout.Fence, origin: Str) -> Step {17 var end = index + 118 var code: Array[Str] = []19 while end < lines.length() && !Layout.closes(lines[end].text, opened) {20 code = code.push(Layout.strip(lines[end].text, opened.indent))21 end = end + 122 }23 let words = opened.info.split(" ")24 let options = Directives.attributes(opened.info.drop(words[0].length()))25 let found = Directives.Directive{name: "", attributes: options, closed: true}26 let highlight = match Snippet.ranges(Directives.value(&found, "highlight")) {27 case Ok(bounds) => Layout.expand(&bounds, code.length())28 case Err(_) => []29 }30 let sample = Syntax.Sample{language: words[0], title: Directives.value(&found, "title"), text: code.join("\n"), highlight: highlight, line: lines[index].number}31 let problems = if end >= lines.length() { [Docgen.warning(Codes.UNCLOSED_BLOCK, origin, lines[index].number, "code fence is not closed")] } else { [] }32 Step{blocks: [Syntax.CodeBlock(sample)], next: end + 1, diagnostics: problems}33}343536export fn indented(lines: &Array[FrontMatter.Line], index: Int) -> Step {37 var end = index38 var last = index39 while end < lines.length() && (Layout.blank(lines[end].text) || Layout.indent(lines[end].text) >= 4) {40 if !Layout.blank(lines[end].text) { last = end }41 end = end + 142 }43 let code = lines.slice(index, last + 1).map(|line: FrontMatter.Line| Layout.strip(line.text, 4)).join("\n")44 Step{blocks: [Syntax.CodeBlock(Syntax.Sample{language: "", title: "", text: code, highlight: [], line: lines[index].number})], next: last + 1, diagnostics: []}45}464748export fn mathBlock(lines: &Array[FrontMatter.Line], index: Int, origin: Str) -> Step {49 let first = lines[index].text.trim().drop(2)50 if first.endsWith("$$") && first.length() >= 2 {51 return Step{blocks: [Syntax.MathBlock(first.take(first.length() - 2).trim())], next: index + 1, diagnostics: []}52 }53 var body: Array[Str] = if first.trim().isEmpty() { [] } else { [first] }54 var end = index + 155 while end < lines.length() && !lines[end].text.trim().endsWith("$$") {56 body = body.push(lines[end].text)57 end = end + 158 }59 if end >= lines.length() {60 return Step{blocks: [Syntax.MathBlock(body.join("\n"))], next: end, diagnostics: [Docgen.warning(Codes.UNCLOSED_BLOCK, origin, lines[index].number, "math block is not closed")]}61 }62 let closing = lines[end].text.trim()63 let tail = closing.take(closing.length() - 2)64 let all = if tail.trim().isEmpty() { body } else { body.push(tail) }65 Step{blocks: [Syntax.MathBlock(all.join("\n"))], next: end + 1, diagnostics: []}66}676869export fn markup(lines: &Array[FrontMatter.Line], index: Int) -> Step {70 let comment = lines[index].text.trim().startsWith("<!--")71 var end = index72 var body: Array[Str] = []73 while end < lines.length() {74 let text = lines[end].text75 if !comment && Layout.blank(text) { break }76 body = body.push(text)77 end = end + 178 if comment && text.contains("-->") { break }79 }80 Step{blocks: if comment { [] } else { [Syntax.HtmlBlock(body.join("\n"))] }, next: end, diagnostics: []}81}82