#!/usr/bin/env python3 """Render each docs/modules/*.md file to a PDF via reportlab.""" from __future__ import annotations from pathlib import Path from reportlab.lib.pagesizes import letter from reportlab.lib.styles import ParagraphStyle, getSampleStyleSheet from reportlab.lib.units import inch from reportlab.platypus import PageBreak, Paragraph, Preformatted, SimpleDocTemplate, Spacer ROOT = Path(__file__).resolve().parents[1] MD_ROOT = ROOT / "docs" / "modules" PDF_ROOT = ROOT / "docs" / "modules-pdf" def md_to_flowables(text: str, styles): story = [] in_code = False code_buf = [] for raw in text.splitlines(): line = raw.rstrip() if line.startswith("```"): if in_code: story.append(Preformatted("\n".join(code_buf) or " ", styles["ModuleCode"])) code_buf = [] in_code = False else: in_code = True continue if in_code: code_buf.append(line) continue if line.startswith("# "): story.append(Paragraph(esc(line[2:]), styles["Title"])) elif line.startswith("## "): story.append(Spacer(1, 8)) story.append(Paragraph(esc(line[3:]), styles["Heading2"])) elif line.startswith("### "): story.append(Paragraph(esc(line[4:]), styles["Heading3"])) elif line.startswith("|"): story.append(Paragraph(esc(line.replace("|", " · ")), styles["BodyText"])) elif line.startswith("- "): story.append(Paragraph("• " + esc(line[2:]), styles["BodyText"])) elif line.strip() == "": story.append(Spacer(1, 6)) else: story.append(Paragraph(esc(line), styles["BodyText"])) return story def esc(s: str) -> str: return ( s.replace("&", "&") .replace("<", "<") .replace(">", ">") .replace("`", "") ) def main() -> None: PDF_ROOT.mkdir(parents=True, exist_ok=True) styles = getSampleStyleSheet() styles.add( ParagraphStyle( name="ModuleCode", fontName="Courier", fontSize=7, leading=9, ) ) mds = sorted(MD_ROOT.rglob("*.md")) n = 0 combined = [] for md in mds: rel = md.relative_to(MD_ROOT) pdf_path = PDF_ROOT / rel.with_suffix(".pdf") pdf_path.parent.mkdir(parents=True, exist_ok=True) text = md.read_text(encoding="utf-8", errors="replace") doc = SimpleDocTemplate( str(pdf_path), pagesize=letter, leftMargin=0.7 * inch, rightMargin=0.7 * inch, topMargin=0.7 * inch, bottomMargin=0.7 * inch, ) flow = md_to_flowables(text, styles) doc.build(flow) combined.extend(flow) combined.append(PageBreak()) n += 1 try: from pypdf import PdfWriter writer = PdfWriter() for md in mds: pdf_path = PDF_ROOT / md.relative_to(MD_ROOT).with_suffix(".pdf") if pdf_path.exists(): writer.append(str(pdf_path)) book = PDF_ROOT / "ALL-MODULES.pdf" with open(book, "wb") as fh: writer.write(fh) print(f"wrote {n} pdfs + {book.name}") except Exception as exc: print(f"wrote {n} pdfs (combined book skipped: {exc})") if __name__ == "__main__": main()