Pudu programming language
Menu
Package

@chrismichaelps / pudu-lang-docgen

Documentation publishing for Pudu: articles, API references, navigation, search, and static websites

0.1.0Apache-2.01

InstallClose

Leaves.pudu

Pudu82 lines3.9 KB

GitHub ↗
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] }1415/// A fenced code block; an unclosed fence runs to the end of its container.16export 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}3435/// Code indented by four columns; blank lines inside are kept.36export 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}4647/// A display math block between `$$` lines, or on one line.48export 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}6768/// Raw HTML running to the next blank line, or to the end of a comment.69export 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