Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Graphs in docs #51

Merged
merged 13 commits into from
Jun 4, 2024
Prev Previous commit
Next Next commit
fix clippy&fmt
jdonszelmann committed Jun 3, 2024
commit 2debdbf179f1fcbf0b87ef1e65f773f0d259f34b
1 change: 0 additions & 1 deletion scopegraphs-render-docs
Submodule scopegraphs-render-docs deleted from 3dd75e
6 changes: 6 additions & 0 deletions scopegraphs-render-docs/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
**/target
**/*.rs.bk
Cargo.lock
.idea/

render-docs
149 changes: 149 additions & 0 deletions scopegraphs-render-docs/CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,149 @@
<a name="v0.5.0"></a>
### v0.5.0 (2024-01-12)

#### Breaking Changes

* include_mmd! now always uses CARGO_MANIFEST_DIR as root (PR #47 by [Rjected](https://github.com/Rjected))

#### Miscellaneous

<a name="v0.4.0"></a>
### v0.4.0 (2023-12-13) YANKED

#### Breaking Changes

* `path` attribute is no longer supported for importing diagrams from external files

#### Features

* `include_mmd!` macro-like syntax for embedding diagrams from files
* multiple diagrams can now be imported from filesystem per documented entity
* imported diagrams can now be placed freely at any place inside the doc comment

#### Miscellaneous

* syn bumped to version 2 (PR #42 by [maurer](https://github.com/maurer)

<a name="v0.3.1"></a>
### v0.3.1 (2023-04-17)

#### Features

* mermaid is updated to v10 (PR #46 by [frehberg](https://github.com/frehberg))
* better handling of a failure to load mermaidjs (PR #46 by [frehberg](https://github.com/frehberg))

#### Miscellaneous

* add Frehberg as a maintainer on GitHub, and package owner on Crates.io

<a name="v0.3.0"></a>
### v0.3.0 (2023-02-16)

#### Maintenance

* update dependencies

<a name="v0.2.2"></a>
### v0.2.2 (2023-02-02)

#### Bug Fixes

* gracefully handle failure to write mermaid.js files ([514c67c9](514c67c9))

<a name="v0.2.1"></a>
### v0.2.1 (2023-02-01)

#### Maintenance

* MermaidJS updated to version 9.3.0

<a name="v0.2.0"></a>
## v0.2.0 (2023-01-31)

#### Bug Fixes

* embedding broken when dependants are built with `--no-deps` [06e263b3](06e263b3) by [frehberg](https://github.com/frehberg)

#### Features

* allow loading diagrams from filesystem via macro attrs [0eb7e08f](0eb7e08f) by [drbh](https://github.com/drbh)

<a name="v0.1.12"></a>
### v0.1.12 (2022-08-17)

mermaid.js upgraded to version 9.1.4

#### Bug Fixes

* failing doctest ([680ea555](680ea555))
* typo in changelog ([75419467](75419467))


<a name="0.1.11"></a>
## 0.1.11 (2021-05-31)


#### Features

* verbose mermaid.js logging ([33746ab3](33746ab3)) by [yunhong](https://github.com/allenchou13)
* mermaid.js version 13.4 ([33746ab3](33746ab3)) by [yunhong](https://github.com/allenchou13)

<a name="0.1.10"></a>
## 0.1.10 (2021-05-31)


#### Features

* lower MSRV to 1.31.1 ([2fd0f032](2fd0f032))

<a name="0.1.9"></a>
## 0.1.9 (2021-05-15)

#### Features

* upgrade mermaid.js to 8.10.1 ([fbb13e1db](fbb13e1db)) by [José Duarte](https://github.com/jmg-duarte)

<a name="0.1.8"></a>
## 0.1.8 (2021-04-08)

#### Bug Fixes

* fallback to CDN version of mermaid.js if local isn't found ([de9f274e](de9f274e))

<a name="0.1.7"></a>
## 0.1.7 (2021-04-08)

#### Features

* use local version of the mermaid.js library ([8f523072](8f523072)) by [Le Savon Fou](https://github.com/lesavonfou)

#### Bug Fixes

* fix doctests ([ea685563](ea685563)) by [Le Savon Fou](https://github.com/lesavonfou)

<a name="0.1.6"></a>
## 0.1.6 (2021-01-28)


#### Bug Fixes

* use regex to detect the dark themes reliably on docs.rs ([ce24cd6e](ce24cd6e))


<a name="0.1.5"></a>
## 0.1.5 (2021-01-28)


#### Bug Fixes

* initialization script wasn't firing at page load ([36268718](36268718))


<a name="0.1.4"></a>
## 0.1.4 (2021-01-28)


#### Features

* dark mode and custom themes ([62ec6783](62ec6783))
* add crossorigin attribute to script tag ([fa9f4546](fa9f4546)) by [Mark Schmale](https://github.com/themasch)
25 changes: 25 additions & 0 deletions scopegraphs-render-docs/Cargo.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
[package]
name = "scopegraphs-render-docs"
version = "0.2.0"
authors = ["Mike Lubinets <git@mkl.dev>", "Frank Rehberger <frehberg@gmail.com>", "Jonathan Dönszelmann <jonathan@donsz.nl>"]
description = "Derived from Aquamarine, a mermaid.js integration for rustdoc, renders scopegraphs by executing doctests to generate mermaid"
keywords = ["proc_macro", "docs", "rustdoc", "mermaid", "diagram"]
categories = ["visualization", "development-tools::build-utils"]
repository = "https://github.com/mersinvald/aquamarine"
edition = "2018"
license = "MIT"
include = ["src/**/*", "Cargo.toml", "doc/js/**"]

[lib]
proc-macro = true

[dependencies]
quote = "1"
proc-macro2 = "1"
proc-macro-error = { version = "1", default-features = false }
itertools = "0.10"
syn = "2"
include_dir = "0.7"

[dev-dependencies]
pretty_assertions = "1"
21 changes: 21 additions & 0 deletions scopegraphs-render-docs/LICENSE
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
The MIT License (MIT)

Copyright (c) 2020 Mike Lubinets <git@mkl.dev>

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
93 changes: 93 additions & 0 deletions scopegraphs-render-docs/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,93 @@
# Aquamarine

[![GitHub](https://img.shields.io/github/license/mersinvald/aquamarine)](LICENSE)
[![crates.io](https://img.shields.io/crates/d/aquamarine)](https://crates.io/crates/aquamarine)
[![docs.rs](https://docs.rs/aquamarine/badge.svg)](https://docs.rs/aquamarine)

*Compiler support: this crate requires rustc 1.38.0 or newer*

Aquamarine is a procedural macro extension for [rustdoc](https://doc.rust-lang.org/rustdoc/index.html),
that aims to improve the visual component of Rust documentation through use of the [mermaid.js](https://mermaid-js.github.io/mermaid/#/) diagrams.

`#[aquamarine]` macro works through embedding the [mermaid.js](https://github.com/mermaid-js/mermaid) into the generated rustdoc HTML page, modifying the doc comment attributes.

To inline a diagram into the documentation, use the `mermaid` snippet in a doc-string:

```rust
#[cfg_attr(doc, aquamarine::aquamarine)]
/// ```mermaid
/// graph LR
/// s([Source]) --> a[[aquamarine]]
/// r[[rustdoc]] --> f([Docs w/ Mermaid!])
/// subgraph rustc[Rust Compiler]
/// a -. inject mermaid.js .-> r
/// end
/// ```
pub fn example() {}
```
The diagram will appear in place of the `mermaid` code block, preserving all the comments around it. You can even add multiple diagrams!

To see it in action, go to the [demo crate](https://docs.rs/aquamarine-demo-crate) docs.rs page.

![light](resources/light.png)

You can learn more about `mermaid.js` and what it can do in the mermaid's [documentation MdBook](https://mermaid-js.github.io/mermaid/#/)

### Dark-mode

Aquamarine will automatically select the `dark` theme as a default, if the current `rustdoc` theme is either `ayu` or `dark`.

You might need to reload the page to redraw the diagrams after changing the theme.

![light](resources/dark.png)

### Custom themes

Theming is supported on per-diagram basis, through the mermaid's `%%init%%` attribute.

*Note*: custom theme will override the default theme

```rust
/// ```mermaid
/// %%{init: {
/// 'theme': 'base',
/// 'themeVariables': {
/// 'primaryColor': '#ffcccc',
/// 'edgeLabelBackground':'#ccccff',
/// 'tertiaryColor': '#fff0f0' }}}%%
/// graph TD
/// A(Diagram needs to be drawn) --> B{Does it have 'init' annotation?}
/// B -->|No| C(Apply default theme)
/// B -->|Yes| D(Apply customized theme)
/// ```
```

![custom](resources/custom.png)

To learn more, see the [Theming Section](https://mermaid-js.github.io/mermaid/#/theming) of the mermaid.js book

### Separating diagrams from code

A diagram, or multiple, can be loaded from file to reduce clutter in the documentation comments.


```rust
#[cfg_attr(doc, aquamarine::aquamarine)]
/// My diagram #1
/// include_mmd!("diagram1.mmd")
/// My diagram #2
/// include_mmd!("diagram2.mmd")
pub fn example_foad_from_file() {}
```

![import](resources/import.png)

### In the wild

Crates that use `aquamarine` in their documentation

- [google/autocxx](https://github.com/google/autocxx)
- [replicadse/senile](https://github.com/replicadse/senile)
- [teloxide](https://github.com/teloxide/teloxide)

[and other](https://crates.io/crates/aquamarine/reverse_dependencies)
37 changes: 37 additions & 0 deletions scopegraphs-render-docs/scripts/package_mermaid_release.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
#!/bin/sh

# Download and bundle mermaid module files into single Zip
# Author: Frank Rehberger
# Date: 2023.03.09
# Usage: scripts/package_mermaid_release.sh doc/js https://cdn.jsdelivr.net/npm/mermaid@10/dist/ mermaid.esm.min.mjs

PKG_DIR="${1:-./doc/js}"
PKG_URL="${2:-https://cdn.jsdelivr.net/npm/mermaid@10.0.2/dist/}"
PKG_NAME="${3:-mermaid.esm.min.mjs}"

DOWNLOAD_DIR="${PKG_DIR}.dl"

pkg_download() {
url="$1"

curl -s "$url" | grep 'href="/npm/mermaid' | grep -io '<a .*href=['"'"'"][^"'"'"']*['"'"'"]' | sed -e 's/^<a rel="nofollow" href=["'"'"']//i' -e 's/["'"'"']$//i' | while read uri; do
echo "Downloading https://cdn.jsdelivr.net$uri"
wget "https://cdn.jsdelivr.net$uri" 2>/dev/null;
done
}

echo "Downloading packages from $PKG_URL"
if ! test -d "$DOWNLOAD_DIR"; then
mkdir -p "$DOWNLOAD_DIR"
( cd "$DOWNLOAD_DIR"; pkg_download "$PKG_URL")
fi

mkdir -p "$PKG_DIR"
echo "Creating bundle $PKG_DIR/$PKG_NAME.zip"
PKG_FILE=$(realpath $PKG_DIR/$PKG_NAME.zip)
( cd "$DOWNLOAD_DIR"; zip -9 -r "$PKG_FILE" *)
echo
echo "Bundle size"
ls -alh "$PKG_DIR/$PKG_NAME.zip"


755 changes: 755 additions & 0 deletions scopegraphs-render-docs/src/attrs.rs

Large diffs are not rendered by default.

192 changes: 192 additions & 0 deletions scopegraphs-render-docs/src/lib.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,192 @@
//! Render_scopegraph is a procedural macro extension for [rustdoc](https://doc.rust-lang.org/rustdoc/what-is-rustdoc.html),
//! that aims to improve the visual component of Rust documentation through use of the [mermaid.js](https://mermaid-js.github.io/mermaid/#/) diagrams.
//!
//! > NOTE: This is a custom, heavily modified version of the [Aquamarine](https://github.com/mersinvald/aquamarine) library, distributed under the MIT license.
//!
//! `#[render_scopegraphs]` macro works through embedding the [mermaid.js](https://github.com/mermaid-js/mermaid) into the generated rustdoc HTML page, modifying the doc comment attributes.
//!
//! To inline a diagram into the documentation, use the `mermaid` snippet in a doc-string:
//!
//! ```rust
//! # use scopegraphs_render_docs::render_scopegraphs;
//! #[cfg_attr(doc, render_scopegraph)]
//! /// ```rust
//! /// todo!()
//! ///
//! /// ```
//! pub fn example() {}
//! ```
//! The diagram will appear in place of the `mermaid` code block, preserving all the comments around it.
//!
//! You can even add multiple diagrams!
//!
//! To see it in action, go to the [demo crate](https://docs.rs/aquamarine-demo-crate/0.5.0/aquamarine_demo_crate/fn.example.html) docs.rs page.
//!
//! ### Dark-mode
//!
//! Aquamarine will automatically select the `dark` theme as a default, if the current `rustdoc` theme is either `ayu` or `dark`.
//!
//! You might need to reload the page to redraw the diagrams after changing the theme.
//!
//! ### Custom themes
//!
//! Theming is supported on per-diagram basis, through the mermaid's `%%init%%` attribute.
//!
//! *Note*: custom theme will override the default theme
//!
//! ```no_run
//! /// ```mermaid
//! /// %%{init: {
//! /// 'theme': 'base',
//! /// 'themeVariables': {
//! /// 'primaryColor': '#ffcccc',
//! /// 'edgeLabelBackground':'#ccccff',
//! /// 'tertiaryColor': '#fff0f0' }}}%%
//! /// graph TD
//! /// A(Diagram needs to be drawn) --> B{Does it have 'init' annotation?}
//! /// B -->|No| C(Apply default theme)
//! /// B -->|Yes| D(Apply customized theme)
//! /// ```
//! # fn example() {}
//! ```
//! [Demo on docs.rs](https://docs.rs/aquamarine-demo-crate/0.5.0/aquamarine_demo_crate/fn.example_with_styling.html)
//!
//! To learn more, see the [Theming Section](https://mermaid-js.github.io/mermaid/#/theming) of the mermaid.js book
//!
//! ### Loading from a file
//!
//! When describing complex logic, a diagram can get quite big.
//!
//! To reduce clutter in your doc comments, you can load a diagram from file using the `include_mmd!` macro-like syntax.
//!
//! ```no_run
//! /// Diagram #1
//! /// include_mmd!("diagram_1.mmd")
//! ///
//! /// Diagram #2
//! /// include_mmd!("diagram_2.mmd")
//! # fn example() {}
//! ```
//! [Demo on docs.rs](https://docs.rs/aquamarine-demo-crate/0.5.0/aquamarine_demo_crate/fn.example_load_from_file.html)
extern crate proc_macro;

use proc_macro::TokenStream;
use proc_macro_error::{abort, proc_macro_error};

use quote::quote;
use syn::{parse_macro_input, Attribute};

mod attrs;
mod parse;

/// Aquamarine is a proc-macro that adds [Mermaid](https://mermaid-js.github.io/mermaid/#/) diagrams to rustdoc
///
/// To inline a diagram into the documentation, use the `mermaid` snippet:
///
/// ```rust
/// # use scopegraphs_render_docs::render_scopegraphs;
/// #[render_scopegraphs]
/// /// ```rust
/// /// # use scopegraphs::*;
/// /// # use completeness::{UncheckedCompleteness};
/// /// # use resolve::{DataWellformedness, Resolve, ResolvedPath};
/// /// # use render::{RenderSettings, RenderScopeData, RenderScopeLabel};
/// /// #
/// /// # #[derive(Label, Hash, PartialEq, Eq, Debug, Clone, Copy)]
/// /// # enum Lbl {
/// /// # Lex,
/// /// # Imp,
/// /// # Def,
/// /// # }
/// /// # use Lbl::*;
/// /// #
/// /// # #[derive(Hash, PartialEq, Eq, Debug, Default, Clone)]
/// /// # enum TData<'a> {
/// /// # #[default]
/// /// # NoData,
/// /// # Data {
/// /// # name: &'a str,
/// /// # data: usize,
/// /// # },
/// /// # }
/// /// #
/// /// # use TData::*;
/// /// #
/// /// # impl RenderScopeData for TData<'_> {
/// /// # fn render_node(&self) -> Option<String> {
/// /// # match self {
/// /// # NoData => None,
/// /// # Data {name, data} => Some(format!("{name}: {data}")),
/// /// # }
/// /// # }
/// /// # }
/// /// #
/// /// # impl RenderScopeLabel for Lbl {
/// /// # fn render(&self) -> String {
/// /// # match self {
/// /// # Lex => "lex",
/// /// # Imp => "imp",
/// /// # Def => "def",
/// /// # }.to_string()
/// /// # }
/// /// # }
/// /// #
/// /// # impl<'a> TData<'a> {
/// /// # fn matches(&self, n: &str) -> bool {
/// /// # match self {
/// /// # NoData => false,
/// /// # Data { name, .. } => *name == n,
/// /// # }
/// /// # }
/// /// #
/// /// # fn matcher(n: &'a str) -> impl DataWellformedness<Self> {
/// /// # |data: &Self| data.matches(n)
/// /// # }
/// /// #
/// /// # fn from_default(name: &'a str) -> Self {
/// /// # Data { name, data: 0 }
/// /// # }
/// /// # }
/// /// # let storage = Storage::new();
/// /// # let sg: ScopeGraph<Lbl, TData, UncheckedCompleteness> =
/// /// # unsafe { ScopeGraph::raw(&storage) };
/// ///
/// /// let s0 = sg.add_scope_default();
/// /// let s1 = sg.add_scope_default();
/// /// sg.add_edge(s0, Lex, s1);
/// /// sg.add_decl(s0, Def, Data { name: "x", data: 0 });
/// /// sg.add_decl(s1, Def, Data { name: "x", data: 1 });
/// ///
/// /// sg.render_to("output.dot", RenderSettings::default()).unwrap();
/// /// ```
/// struct Foo;
/// ```
#[proc_macro_attribute]
#[proc_macro_error]
pub fn render_scopegraphs(_args: TokenStream, input: TokenStream) -> TokenStream {
let input = parse_macro_input!(input as parse::Input);

check_input_attrs(&input.attrs);

let attrs = attrs::Attrs::from(input.attrs);
let forward = input.rest;

let tokens = quote! {
#attrs
#forward
};

tokens.into()
}

fn check_input_attrs(input: &[Attribute]) {
for attr in input {
if attr.path().is_ident("render_scopegraph") {
abort!(
attr,
"multiple `render_scopegraph` attributes on one entity are illegal"
);
}
}
}
18 changes: 18 additions & 0 deletions scopegraphs-render-docs/src/parse.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
use proc_macro2::TokenStream;
use syn::{
parse::{Parse, ParseStream},
Attribute,
};

pub struct Input {
pub attrs: Vec<Attribute>,
pub rest: TokenStream,
}

impl Parse for Input {
fn parse(input: ParseStream) -> syn::Result<Self> {
let attrs = input.call(Attribute::parse_outer)?;
let rest = input.parse()?;
Ok(Input { attrs, rest })
}
}