Repository navigation
feat: render mermaid and svg code blocks as diagrams - #10
Merged
Merged
Conversation
A ```mermaid block is now rendered to SVG and embedded as a picture, and a ```svg block is passed through, since Typst renders SVG natively. Everything else keeps rendering as syntax-highlighted code. Mermaid goes through mermaidx, which runs Mermaid on an embedded JavaScript engine — no Node install and no headless browser, so the tool stays a plain pip install. Wheels cover Linux, macOS, and Windows on Python 3.10 through 3.14. Invalid diagram sources are reported with Mermaid's own parse message instead of aborting with a traceback. Conversion now carries generated content alongside copied assets, since a rendered diagram has no file of its own. Pictures also stop being forced to full width. A new fit-image helper keeps an image at its natural size and shrinks it only when it is too wide for the text block, which fixes small figures being blown up to fill the page. Closes #8.
Every template hardcoded us-letter, which is the standard in the US and Canada and nowhere else. Page size is now a real option: --paper on the command line, or a paper key in front matter, covering A3 through A6, both ISO B5 and JIS B5, and the US letter, legal, and tabloid sizes. BREAKING CHANGE: the default page size is now a4 rather than us-letter. Pass --paper us-letter, or set paper: us-letter in front matter, to keep the previous output. Templates also gain an ..options sink, so adding an option in a later release no longer breaks a user-supplied .typ that has not been updated.
Markdown written for other toolchains carries LaTeX math, and Typst does not
speak it: a backslash escapes the next character, so $\frac{a}{b}$ reaches the
compiler as an unknown variable named rac. A new latex module rewrites it —
Greek letters, relations and operators, fractions and roots, scripts, font
commands, matrices, and cases. Unrecognized commands drop their backslash,
which lands on the right Typst symbol most of the time.
Two differences between the languages needed real handling rather than a
lookup table. Typst reads a run of letters as one identifier and rejects the
ones it does not know, while LaTeX reads xy as x times y, so runs are split
into single letters unless they name an operator such as sin or lim. And
matrix columns are separated by & in LaTeX but by a comma in Typst, with rows
moving from \\ to a semicolon, which made environments context-sensitive.
Inline math also gets a stricter rule than the one mistune ships, whose
closing guard is a lookahead where it needs a lookbehind. Without that fix
"it costs $10 and $20" parsed the middle as math and mangled it — the kind of
line that appears in nearly every README this tool is pointed at.
Every symbol in the table was checked against the compiler, and the tests
compile their translations rather than only comparing strings.
`doc-engine --help` listed two commands and two global flags, so finding the options that matter meant knowing to ask for `build --help` first. Since building is what nearly every run does, the top-level screen now shows those flags directly, grouped by what they affect — output, document details, appearance, and the flags used while writing — instead of one flat column. Both screens open with worked examples. Descriptions are read from the Click parameters, so the help text still has a single source of truth and cannot drift from the flags themselves. `info` moves to a grid so wrapped values line up under their label, and it now reports what the build can actually do: page sizes, accents, diagrams, math.
A project that outgrew a single file can now list its parts in doc-engine.md as ordinary Markdown links, so the manifest still reads as a table of contents on GitHub. Entries are handled by what they are: Markdown files become sections, .mmd sources are rendered where they appear, images are placed as captioned figures, and a .bib registers as the bibliography for the document. Front matter at the top carries the metadata for the whole thing. Each entry converts against its own folder, so a picture referenced from inside an included file resolves exactly as it does when that file is built alone. Asset names are namespaced per entry so two folders can both hold a logo.png without one overwriting the other. Watch mode follows every file the manifest names, and re-reads the list after each rebuild in case the manifest itself changed. Also fixes tables, which have been wrong since 1.0.0: the header row was read as a table_row when a table_head holds its cells directly, so the column count came from the first cell's text and every table collapsed into one column.
Two layouts join the set. `article` is the classic LaTeX paper: New Computer Modern, numbered sections, a title block at the top of the first page instead of a cover sheet. `report` trades density for legibility — 12pt on generous leading, wide margins that hold the measure near 65 characters, and a lot of air around headings. Section numbering in `article` drops the levels that never appear, because the first `#` becomes the document title and real sections usually start at `##`, which otherwise numbered them 0.1, 0.2, 0.3. The existing templates asked for Inter, Cascadia Code, and Linux Libertine and fell back to other system fonts. Typst only bundles New Computer Modern, Libertinus Serif, and DejaVu Sans Mono, so none of those existed inside the published Docker image and documents built there silently used whatever was left. Each stack now ends in a bundled font.
A team that always builds the same way can put it in .doc-engine.toml, or in a [tool.doc-engine] table in pyproject.toml, instead of repeating flags or copying front matter between documents. Only known keys are read, so a typo cannot quietly change how a document is built. Precedence runs flag, then front matter, then the project file. --pdf-standard writes PDF/A-2b or PDF/A-3b for archives that require it. --fetch-images downloads images linked by URL, which until now rendered as alt text. It stays off by default, because building a document should not reach the network on its own. Each download is bounded: http and https only, a ten second timeout, a size ceiling, and a check that the response really is an image. A download that fails warns and leaves the alt text rather than failing the build. Adopts ruff for linting and formatting, wired into CI and documented in CONTRIBUTING. This replaces the code-style badge that claimed a formatter the project never ran.
A tall picture had no good outcome. fit-image only constrained the width, so a top-down flowchart kept its natural height, ran past the bottom of the page, and Typst clipped whatever did not fit — the first steps of the diagram simply disappeared from the PDF. It now scales by whichever dimension is tighter, so the whole picture always survives. That still leaves such a diagram legible only in principle, so --tall-images split cuts it into page-tall pieces and places them one after another, which keeps the boxes at a readable size across several pages. The default stays fit, where the picture is scaled to sit on one page. Adds pillow, used only when a picture actually has to be cut.
Covers diagrams, math, the manifest, project configuration, page sizes, tall images, and archival output, and marks the roadmap items this release closes.
A tall picture used more than once left a dangling reference. It is registered under a single name, so the second occurrence tried to cut a file the first pass had already replaced, and the document pointed at an asset that no longer existed — the compile would fail on a missing file. The pieces are remembered per picture now. A Markdown file pulled in by a manifest had its own front matter rendered as body text, so "title: Internal" showed up as a heading in the PDF. The manifest owns the metadata, so only the body of an included file is used. Figure captions went into Typst content unescaped, which made a caption such as "Cost $5 and #1" open math and code expressions. Captions are Markdown, so they now go through the converter. Also closes forty gaps in the math translation, found by feeding it the kind of notation a real paper uses: logic, floors and ceilings, big operators, long and hooked arrows, order relations, and vector accents. CI gains a job that builds the Docker image and runs the CLI inside it, since this release adds dependencies with compiled parts, and the smoke test now exercises diagrams, math, tables, page size, and PDF/A rather than plain text.
Three sources can set the same option — a flag, the document's front matter, and the project file — and deciding between them had grown into the middle of a 200-line command callback, where the only way to exercise it was to run the whole program against a temporary directory. It moves to a settings module: a function over plain dictionaries returning what the build should use. Colour names and the template search stay in the CLI and are passed in, so the rules can be read without the vocabulary. No behaviour changes, and the precedence now has direct tests instead of being covered only through end-to-end invocations.
The header GIF still showed 0.1.x output from April, four versions back, and it is the first thing anyone arriving from a link sees. The new one runs v2.0.0 against a document with math, a diagram, and a table. Adds a note at the top saying plainly what this branch is: v2.0.0 complete but not published, with the commands to run it from a checkout, and pointers to issues and discussions for anyone willing to test it.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
A mermaid block is now rendered to SVG and embedded as a picture, and a svg block is passed through, since Typst renders SVG natively. Everything
else keeps rendering as syntax-highlighted code.
Mermaid goes through mermaidx, which runs Mermaid on an embedded JavaScript
engine — no Node install and no headless browser, so the tool stays a plain
pip install. Wheels cover Linux, macOS, and Windows on Python 3.10 through
3.14. Invalid diagram sources are reported with Mermaid's own parse message
instead of aborting with a traceback.
Conversion now carries generated content alongside copied assets, since a
rendered diagram has no file of its own.
Pictures also stop being forced to full width. A new fit-image helper keeps
an image at its natural size and shrinks it only when it is too wide for the
text block, which fixes small figures being blown up to fill the page.
Closes #8.