mersinvald / aquamarine

Inline diagrams for rustdoc with mermaid.js
MIT License
487 stars 25 forks source link

Render diagrams on inner doc-comments (when custom_inner_attribute lands) #5

Open joseluis opened 3 years ago

joseluis commented 3 years ago

Currently is not possible to have diagrams at the inner doc comments, e.g.:

lib.rs:

#[cfg_attr(doc, aquamarine::aquamarine)]
//! demo
//!
//! ```mermaid
//! graph LR
//!     s([Source]) --> a[[aquamarine]]
//!     r[[rustdoc]] --> f([Docs w/ Mermaid!])
//!     subgraph rustc[Rust Compiler]
//!     a -. inject mermaid.js .-> r
//!     end
//! ```

since there can't be anything before the module-level doc-comment block...

mersinvald commented 3 years ago

I'm not sure that's even possible to do with attribute macros. Maybe with build.rs.

zbraniecki commented 3 years ago

Is there a workaround for this issue? I have a use case for a diagram that only makes sense on the entry point of the documentation.

mersinvald commented 3 years ago

I did investigate a bit, trying to produce a prototype implementation for generating inner attributes, but it doesn't seem to be possible at all on the current Rust.

custom_inner_attribute isn't stable yet, but that's only half of the problem. Even on nightly compiler cannot handle proc-macro-produced inner attributes at all at this time, and treats them as they were preceded by some non-existent outer attribute.

@zbraniecki the only workaround I can think of is to do what the macro does by hand, but I wouldn't recommend that.

mbergkvist commented 2 years ago

Is there a workaround for this issue? I have a use case for a diagram that only makes sense on the entry point of the documentation.

@zbraniecki Did you find a suitable workaround?

kjvalencik commented 2 years ago

One workaround is that it's possible to document modules in two different places:

  1. At the top of the file with //!
  2. On the pub mod ...; line

The 2nd option works; however, it requires the unstable #![feature(proc_macro_hygiene)] if the module isn't inline. It also only works for modules, not crate level docs. You can either enable that with the doc feature flag or you can define the module internally and then create an inline wrapper for it that re-exports.

#[cfg_attr(doc, feature(proc_macro_hygiene))]

#[cfg_attr(doc, aquamarine::aquamarine)]
/// The configuration module.
///
/// ```mermaid
/// graph LR
///     s([Source]) --> a[[aquamarine]]
///     r[[rustdoc]] --> f([Docs w/ Mermaid!])
///     subgraph rustc[Rust Compiler]
///     a -. inject mermaid.js .-> r
///     end
/// ```
pub mod config;

Or with the re-export workaround:

mod config_internal;

#[cfg_attr(doc, aquamarine::aquamarine)]
/// The configuration module.
///
/// ```mermaid
/// graph LR
///     s([Source]) --> a[[aquamarine]]
///     r[[rustdoc]] --> f([Docs w/ Mermaid!])
///     subgraph rustc[Rust Compiler]
///     a -. inject mermaid.js .-> r
///     end
/// ```
pub mod config {
    pub use crate::config_internal::*;
}

Unfortunately this can be a bit messy if there are a lot of modules because all of their docs live in the same file. I'm not aware of any other workaround.

Edit: I found one more workaround that allow separating the module docs into separate files. I like this one because it doesn't require re-naming modules:

lib.rs

mod config_impl;

pub use config_impl::exports as config;

config_impl.rs

#[cfg_attr(doc, aquamarine::aquamarine)]
/// The configuration module.
///
/// ```mermaid
/// graph LR
///     s([Source]) --> a[[aquamarine]]
///     r[[rustdoc]] --> f([Docs w/ Mermaid!])
///     subgraph rustc[Rust Compiler]
///     a -. inject mermaid.js .-> r
///     end
/// ```
pub mod exports {
    pub use super::*;
}

/// This is a config object
pub struct Config;

The idea is that each public module is actually private and has a public wrapper that provides documentation.

frehberg commented 1 year ago

support inner doc would be really nice

joeyame commented 10 months ago

For anyone else who needs mermaid in the top level, no compromise, you can check out the crate simple_mermaid: https://github.com/glueball/simple-mermaid

It supports top-level mermaid diagrams with the only disadvantage being needing to make the diagrams separate files. Perhaps this project could adopt a similar approach to allow in-file top level diagrams? For now though, I am going to have to use that crate because it better supports my needs.

mbergkvist commented 10 months ago

For anyone else who needs mermaid in the top level, no compromise, you can check out the crate _simplemermaid

@joeyame How do you accomplish mermaid in the top level with _simplemermaid?

joeyame commented 10 months ago

For anyone else who needs mermaid in the top level, no compromise, you can check out the crate _simplemermaid

@joeyame How do you accomplish mermaid in the top level with _simplemermaid?

Just like this:

//! # Brief Overview 
//! The following diagram is a simple overview of how Parrhesia is used. 
#![ doc=mermaid!( "diagrams/overall_form.mmd" ) ] 

Then, for non - top level, remove the exclamation

mbergkvist commented 10 months ago

Thanks! I was doing

//! # Brief Overview 
//! The following diagram is a simple overview of how Parrhesia is used. 
#[ doc=mermaid!( "diagrams/overall_form.mmd" ) ] 

i.e. no ! after the # 🤦

mersinvald commented 8 months ago

@joeyame great little crate, I love the simplicity. Hopefully one day I'll be able to support inner docs too, hehe.

Thanks for pointing out the aquamarine deficiency regarding filesystem-stored diagrams in your readme, btw, I've fixed it in 0.4.0.