simple_mermaid/
lib.rs

1//! Simple Mermaid diagrams RustDoc integration
2//!
3//! This crate provides a simple declarative macro to include [mermaid] diagrams in your rustdoc documentation.
4//! Lookup the great [mermaid documentation] for details on the diagram syntax.
5//!
6//! # Usage
7//! 1. Create your [mermaid] diagrams in their own files (usually with `.mmd` or `.mermaid` extension).
8//! 2. Call the [mermaid!] macro in a `#[doc]` attribute. Specify the route to the diagram file as a
9//!    string literal. Note that the path is interpreted relative to the file where the macro is called,
10//!    as it happens with the underlying [include_str].
11//! 3. Done!
12//!
13//! Diagrams can be intermixed freely with regular documentation comments.
14//!
15//! ```rust
16//! # use simple_mermaid::mermaid;
17//! /// A sequence diagram
18//! #[doc = mermaid!("sequence.mmd")]
19//! ///
20//! /// Then a flowchart
21//! #[doc = mermaid!("flowchart.mmd")]
22//! ///
23//! /// And some more regular text to end this block
24//! # fn function() {}
25//! ```
26//! Outputs:
27//!
28//! <pre>
29//! A sequence diagram
30#![doc = mermaid!("sequence.mmd")]
31//! Then a flowchart
32#![doc = mermaid!("flowchart.mmd")]
33//! And some more regular text to end this block
34//! </pre>
35//!
36//! # Options
37//! By default, diagrams will be centered and have a transparent background. This behaviour can be
38//! controlled with the following keywords after the path to the [mermaid] file:
39//!
40//! * **left**, left align the diagram.
41//! * **right**, right align the diagram.
42//! * **center**, has not effect, but it\"s accepted for completeness.
43//! * **framed**, add a gray frame to the diagram.
44//! * **transparent**, do not add the gray frame to the diagram.
45//!
46//! *Left*, *center* and *right* are, of course, mutually exclusive; but either can be combined with *framed*.
47//!
48//! ```rust
49//! # use simple_mermaid::mermaid;
50//! #[doc = mermaid!("er.mmd" left)]
51//! #[doc = mermaid!("graph.mmd" framed)]
52//! #[doc = mermaid!("timeline.mmd" right)]
53//! #[doc = mermaid!("larger.mmd" center framed)]
54//! # fn function() {}
55//! ```
56#![doc = mermaid!("er.mmd" left)]
57#![doc = mermaid!("graph.mmd" framed)]
58#![doc = mermaid!("timeline.mmd" right)]
59#![doc = mermaid!("larger.mmd" center)]
60//!
61//! # Alternatives
62//! ## aquamarine
63//! The [aquamarine] introduces a procedural macro that converts regular code blocks marked with the
64//! [mermaid] language tag. It also allows including the diagram from external files, but that comes with some limitations:
65//! * Only one external diagram can be added to a single doc block.
66//! * The external diagram will always appear at the end of the doc block.
67//!
68//! Those limitations made [aquamarine] a non-option for me, since I strongly prefer leaving the diagrams in external files for several reasons:
69//! clutter, maintainability, IDE support, and, re-usability of the diagrams.
70//!
71//! Besides, the declarative macro used in this crate should be easier on compile times. And it comes with no dependencies at all!
72//!
73//! ## rsdoc
74//! The [rsdoc] crate provides procedural macros to embed [PlantUML] and images in doc coments.
75//! It can be used with code-blocks (similar to aquamarine) or with external files (similar to this crate).
76//! So, in this case, for me it was just a matter of personal taste, both [PlantUML] and [mermaid] are fantastic
77//! opensource projects. But PlantUML is Java... and my plants always die (_even a cactus I once had! How can a cactus die? The thing should not need water!_).
78//!
79//! # Disclaimer
80//! Neither this crate nor it's autor have any relation or affiliation with the [mermaid] project, other that being an user of this magnific library.
81//!
82//! All the examples in this documentation have been extracted, verbatim or with minor updates, from the [mermaid documentation].
83//!
84//! [mermaid]: https://mermaid.js.org/
85//! [include_str]: https://doc.rust-lang.org/std/macro.include_str.html
86//! [mermaid documentation]: https://mermaid.js.org/intro/n00b-gettingStarted.html
87//! [aquamarine]: https://crates.io/crates/aquamarine
88//! [rsdoc]: https://crates.io/crates/rsdoc
89//! [PlantUML]: https://plantuml.com/
90
91#![no_std]
92
93/// Include a mermaid diagram in the documentation.
94///
95/// This macro is meant to be used as argument of the `#[doc]` attribute.
96///
97/// ```rust
98/// # use simple_mermaid::mermaid;
99/// /// Some documentation about a function
100/// /// Then include a diagram:
101/// #[doc = mermaid!("netflix.mmd")]
102/// fn a_function() {}
103/// ```
104///
105/// This would produce:
106///
107/// > Some documentation
108/// >
109/// > Then include a diagram:
110#[doc = mermaid!("netflix.mmd" framed)]
111///
112/// Look at the crate level documentation for all the options.
113#[macro_export]
114macro_rules! mermaid {
115    ($file:literal)               => { $crate::_mermaid_inner!($file center transparent) };
116    ($file:literal left framed)   => { $crate::_mermaid_inner!($file left framed) };
117    ($file:literal framed left)   => { $crate::_mermaid_inner!($file left framed) };
118    ($file:literal center framed) => { $crate::_mermaid_inner!($file center framed) };
119    ($file:literal framed center) => { $crate::_mermaid_inner!($file center framed) };
120    ($file:literal right framed)  => { $crate::_mermaid_inner!($file right framed) };
121    ($file:literal framed right)  => { $crate::_mermaid_inner!($file right framed) };
122    ($file:literal framed)        => { $crate::_mermaid_inner!($file center framed) };
123    ($file:literal left)          => { $crate::_mermaid_inner!($file left transparent) };
124    ($file:literal right)         => { $crate::_mermaid_inner!($file right transparent) };
125    ($file:literal center)        => { $crate::_mermaid_inner!($file center transparent) };
126}
127
128#[doc(hidden)]
129#[macro_export]
130macro_rules! _mermaid_inner {
131    ($file:literal $pos:ident $style:ident)  =>
132    {
133        concat!("<pre class=\"mermaid\" style=\"text-align:", stringify!($pos), ";", $crate::_mermaid_background!($style), "\">\n",
134                    include_str!($file), "\n",
135                "</pre>",
136                "<script type=\"module\">",
137                    "import mermaid from \"https://cdn.jsdelivr.net/npm/mermaid@11/dist/mermaid.esm.min.mjs\";",
138                    "var doc_theme = localStorage.getItem(\"rustdoc-theme\");",
139                    "if (doc_theme === \"dark\" || doc_theme === \"ayu\") mermaid.initialize({theme: \"dark\"});",
140                "</script>")
141    };
142}
143
144#[doc(hidden)]
145#[macro_export]
146macro_rules! _mermaid_background {
147    (framed) =>  { "" };
148    (transparent) => { "background: transparent;" };
149}