% mermaid.sty -- Embed Mermaid diagrams in LaTeX. % % Copyright (C) 2026 Ryoya Ando (https://ryoya9826.github.io/) % % This work may be distributed and/or modified under the % conditions of the LaTeX Project Public License, either version 1.3c % of this license or (at your option) any later version. % The latest version of this license is in % https://www.latex-project.org/lppl.txt % and version 1.3c or later is part of all distributions of LaTeX % version 2008/05/04 or later. \NeedsTeXFormat{LaTeX2e} \ProvidesPackage{mermaid}[2026/04/16 v1.0 Mermaid via Mermaid CLI / PDF] \RequirePackage{shellesc} \RequirePackage{graphicx} \RequirePackage{adjustbox} \RequirePackage{fancyvrb} \RequirePackage{kvoptions} \SetupKeyvalOptions{family=mermaid,prefix=mermaid@,setkeys=\kvsetkeys} \DeclareStringOption[]{Renderer} \ProcessKeyvalOptions* \newread\mermaid@login \def\mermaid@cmd{} \def\mermaid@xargs{} \AtEndOfPackage{% \edef\mermaid@renderer@nonempty{\mermaid@Renderer}% \ifx\mermaid@renderer@nonempty\@empty \else \let\mermaid@cmd\mermaid@Renderer \fi } \newcommand{\MermaidRendererOptions}[1]{\def\mermaid@xargs{#1}} \def\mermaid@pdffit{-f} \newcommand{\MermaidNoPdfFit}{\def\mermaid@pdffit{}} \def\mermaid@graphicsopts{} \newcommand{\MermaidGraphicsOpts}[1]{\def\mermaid@graphicsopts{#1}} \def\mermaid@boxopts{max width=0.9\linewidth,center} \newcommand{\MermaidAdjustBoxOpts}[1]{\def\mermaid@boxopts{#1}} \def\mermaid@resolverenderer{% \ifx\mermaid@cmd\@empty \def\mermaid@resolvedrenderer{mmdc}% \else \let\mermaid@resolvedrenderer\mermaid@cmd \fi } \def\mermaid@buildmergeargs{% \ifx\mermaid@pdffit\@empty \let\mermaid@mergeargs\mermaid@xargs \else \ifx\mermaid@xargs\@empty \let\mermaid@mergeargs\mermaid@pdffit \else \edef\mermaid@mergeargs{\mermaid@pdffit\space\mermaid@xargs}% \fi \fi } \def\mermaid@log#1{\typeout{[mermaid] #1}} \def\mermaid@logcwd{% \edef\mermaid@cwdfile{mermaid/mermaid-cwd-\the\c@mermaid@diag.txt}% \ShellEscape{pwd > \mermaid@cwdfile}% \openin\mermaid@login=\mermaid@cwdfile\relax \ifeof\mermaid@login \mermaid@log{cwd: (unavailable)}% \else \read\mermaid@login to \mermaid@cwdline \closein\mermaid@login \mermaid@log{cwd: \mermaid@cwdline}% \fi } \def\mermaid@run#1#2{% \mermaid@buildmergeargs \mermaid@resolverenderer \edef\mermaid@stdout{mermaid/\jobname-mermaid-\the\c@mermaid@diag.out}% \edef\mermaid@stderr{mermaid/\jobname-mermaid-\the\c@mermaid@diag.err}% \ShellEscape{mkdir -p mermaid}% \mermaid@log{----------}% \mermaid@log{diagram \the\c@mermaid@diag: #1 -> #2}% \mermaid@logcwd \mermaid@log{renderer (resolved): \mermaid@resolvedrenderer}% \ifx\mermaid@mergeargs\@empty\else \mermaid@log{CLI extra args (incl. pdf-fit): \mermaid@mergeargs}% \fi \mermaid@log{full shell command: \mermaid@resolvedrenderer\space\mermaid@mergeargs\space -i "#1" -o "#2" >"\mermaid@stdout" 2>"\mermaid@stderr"}% \ifcsname pdffilesize\endcsname \IfFileExists{#1}{% \mermaid@log{.mmd size (bytes): \pdffilesize{#1}}% }{% \mermaid@log{.mmd size (bytes): (missing)}% }% \else \mermaid@log{.mmd size (bytes): unavailable (no pdffilesize on this engine)}% \fi \ifcsname pdfresettimer\endcsname\pdfresettimer\fi \immediate\write18{\mermaid@resolvedrenderer\space\mermaid@mergeargs\space -i "#1" -o "#2" >"\mermaid@stdout" 2>"\mermaid@stderr"}% \ifcsname pdfelapsedtime\endcsname \mermaid@log{timing: \the\pdfelapsedtime\space ms (pdfelapsedtime)}% \else \mermaid@log{timing: (pdfelapsedtime not available on this engine)}% \fi \IfFileExists{#2}{% \mermaid@log{renderer subprocess: finished (parsed as success)}% \ifcsname pdffilesize\endcsname \mermaid@log{output PDF size (bytes): \pdffilesize{#2}}% \else \mermaid@log{output PDF size (bytes): unavailable}% \fi \mermaid@log{PDF header check: OK}% \mermaid@log{----------}% }{% \mermaid@log{expected output PDF missing after write18 (exit status not checked)}% }% } \newcount\c@mermaid@diag \c@mermaid@diag=\z@ \newenvironment{mermaid}{% \global\advance\c@mermaid@diag\@ne\relax \edef\mermaid@in{mermaid/\jobname-mermaid-\the\c@mermaid@diag.mmd}% \edef\mermaid@out{mermaid/\jobname-mermaid-\the\c@mermaid@diag.pdf}% \ShellEscape{mkdir -p mermaid}% \VerbatimOut{\mermaid@in}% }{% \endVerbatimOut \mermaid@run{\mermaid@in}{\mermaid@out}% \IfFileExists{\mermaid@out}{% \begin{center}% \bgroup \edef\mermaid@tmp{% \egroup \noexpand\adjustbox{\mermaid@boxopts}{% \noexpand\includegraphics[\mermaid@graphicsopts]{\mermaid@out}% }% }% \mermaid@tmp \end{center}% }{% \PackageError{mermaid}{% Output PDF was not produced. Check mermaid/\jobname-mermaid-\the\c@mermaid@diag.err for mmdc messages; % ensure -shell-escape and Mermaid CLI.% }{}% }% } \endinput