diff --git a/Cargo.lock b/Cargo.lock index 0ee9970..1e897c2 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -41,6 +41,12 @@ version = "0.2.21" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "683d7910e743518b0e34f1186f92494becacb047c7b6bf616c96772180fef923" +[[package]] +name = "anyhow" +version = "1.0.100" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a23eb6b1614318a8071c9b2521f36b424b2c83db5eb3a0fead4a6c0809af6e61" + [[package]] name = "arraydeque" version = "0.5.1" @@ -74,6 +80,15 @@ dependencies = [ "wyz", ] +[[package]] +name = "block-buffer" +version = "0.10.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3078c7629b62d3f0439517fa394996acacc5cbc91c5a20d8c658e77abd503a71" +dependencies = [ + "generic-array", +] + [[package]] name = "bon" version = "3.8.2" @@ -178,6 +193,15 @@ dependencies = [ "unicode-segmentation", ] +[[package]] +name = "cpufeatures" +version = "0.2.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "59ed5838eebb26a2bb2e58f6d5b5316989ae9d08bab10e0e6d103e656d1b0280" +dependencies = [ + "libc", +] + [[package]] name = "crossbeam-deque" version = "0.8.6" @@ -203,6 +227,16 @@ version = "0.8.21" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d0a5c400df2834b80a4c3327b3aad3a4c4cd4de0629063962b03235697506a28" +[[package]] +name = "crypto-common" +version = "0.1.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "78c8292055d1c1df0cce5d180393dc8cce0abec0a7102adb6c7b1eef6016d60a" +dependencies = [ + "generic-array", + "typenum", +] + [[package]] name = "cssparser" version = "0.33.0" @@ -235,6 +269,16 @@ dependencies = [ "syn 2.0.114", ] +[[package]] +name = "dagre_rust" +version = "0.0.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "be0e44f22d2a32979a1265aa1a70f6e2f4f43ec0d562d483a1c818f9a4121926" +dependencies = [ + "graphlib_rust", + "ordered_hashmap", +] + [[package]] name = "darling" version = "0.23.0" @@ -297,6 +341,16 @@ dependencies = [ "matches", ] +[[package]] +name = "digest" +version = "0.10.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9ed9a281f7bc9b7576e61468ba615a66a5c8cfdff42420a70aa82701a3b1e292" +dependencies = [ + "block-buffer", + "crypto-common", +] + [[package]] name = "dtoa" version = "1.0.11" @@ -351,6 +405,16 @@ version = "2.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e6d5a32815ae3f33302d95fdcb2ce17862f8c65363dcfd29360480ba1001fc9c" +[[package]] +name = "generic-array" +version = "0.14.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "85649ca51fd72272d7821adaf274ad91c288277713d9c18820d8499a7ff69e9a" +dependencies = [ + "typenum", + "version_check", +] + [[package]] name = "getopts" version = "0.2.24" @@ -383,6 +447,15 @@ dependencies = [ "wasip2", ] +[[package]] +name = "graphlib_rust" +version = "0.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b47de2c5685b5bb3689d6b0977f38959f3d7d82d3556627cfebbfaa42eda05ea" +dependencies = [ + "ordered_hashmap", +] + [[package]] name = "gray_matter" version = "0.2.9" @@ -478,6 +551,17 @@ dependencies = [ "wasm-bindgen", ] +[[package]] +name = "json5" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "96b0db21af676c1ce64250b5f40f3ce2cf27e4e47cb91ed91eb6fe9350b430c1" +dependencies = [ + "pest", + "pest_derive", + "serde", +] + [[package]] name = "katex-rs" version = "0.2.3" @@ -597,6 +681,22 @@ version = "2.7.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f52b00d39961fc5b2736ea853c9cc86238e165017a493d1d5c8eac6bdc4cc273" +[[package]] +name = "mermaid-rs-renderer" +version = "0.1.2" +source = "git+https://github.com/1jehuang/mermaid-rs-renderer#66b7d8c3f3152153666d589e789a143e87afcec5" +dependencies = [ + "anyhow", + "dagre_rust", + "graphlib_rust", + "json5", + "once_cell", + "regex", + "serde", + "serde_json", + "thiserror", +] + [[package]] name = "nrd-sh" version = "0.1.0" @@ -605,6 +705,7 @@ dependencies = [ "katex-rs", "lightningcss", "maud", + "mermaid-rs-renderer", "pulldown-cmark", "serde", "thiserror", @@ -632,6 +733,12 @@ version = "1.21.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "42f5e15c9953c5e4ccceeb2e7382a716482c34515315f7b03532b8b4e8393d2d" +[[package]] +name = "ordered_hashmap" +version = "0.0.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cb1ea499d242299d564879c8b375c11285f5a26d62d8010768909d6d099c4c5a" + [[package]] name = "outref" version = "0.1.0" @@ -693,6 +800,49 @@ version = "0.2.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "df94ce210e5bc13cb6651479fa48d14f601d9858cfe0467f43ae157023b938d3" +[[package]] +name = "pest" +version = "2.8.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2c9eb05c21a464ea704b53158d358a31e6425db2f63a1a7312268b05fe2b75f7" +dependencies = [ + "memchr", + "ucd-trie", +] + +[[package]] +name = "pest_derive" +version = "2.8.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "68f9dbced329c441fa79d80472764b1a2c7e57123553b8519b36663a2fb234ed" +dependencies = [ + "pest", + "pest_generator", +] + +[[package]] +name = "pest_generator" +version = "2.8.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3bb96d5051a78f44f43c8f712d8e810adb0ebf923fc9ed2655a7f66f63ba8ee5" +dependencies = [ + "pest", + "pest_meta", + "proc-macro2", + "quote", + "syn 2.0.114", +] + +[[package]] +name = "pest_meta" +version = "2.8.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "602113b5b5e8621770cfd490cfd90b9f84ab29bd2b0e49ad83eb6d186cef2365" +dependencies = [ + "pest", + "sha2", +] + [[package]] name = "phf" version = "0.11.3" @@ -1121,6 +1271,17 @@ dependencies = [ "serde", ] +[[package]] +name = "sha2" +version = "0.10.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a7507d819769d01a365ab707794a4084392c824f54a7a6a7862f8c3d0892b283" +dependencies = [ + "cfg-if", + "cpufeatures", + "digest", +] + [[package]] name = "shlex" version = "1.3.0" @@ -1452,6 +1613,18 @@ dependencies = [ "tree-sitter-language", ] +[[package]] +name = "typenum" +version = "1.19.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "562d481066bde0658276a35467c4af00bdc6ee726305698a55b86e61d7ad82bb" + +[[package]] +name = "ucd-trie" +version = "0.1.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2896d95c02a80c6d6a5d6e953d479f5ddf2dfdb6a244441010e373ac0fb88971" + [[package]] name = "unicase" version = "2.9.0" diff --git a/Cargo.toml b/Cargo.toml index 7182666..3ef4eed 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -35,3 +35,6 @@ lightningcss = "1.0.0-alpha.70" katex-rs = "0.2.3" serde = { version = "1", features = ["derive"] } toml = "0.8" + +# Diagram rendering +mermaid-rs-renderer = { git = "https://github.com/1jehuang/mermaid-rs-renderer", default-features = false } diff --git a/src/main.rs b/src/main.rs index 8a675c1..f0c283f 100644 --- a/src/main.rs +++ b/src/main.rs @@ -9,6 +9,7 @@ mod error; mod feed; mod highlight; mod math; +mod mermaid; mod render; mod templates; diff --git a/src/mermaid.rs b/src/mermaid.rs new file mode 100644 index 0000000..caa437b --- /dev/null +++ b/src/mermaid.rs @@ -0,0 +1,43 @@ +//! Mermaid diagram rendering via mermaid-rs-renderer. +//! +//! Converts Mermaid diagram definitions to SVG at build-time. + +use mermaid_rs_renderer::RenderOptions; + +/// Render a Mermaid diagram to SVG. +/// +/// # Arguments +/// * `code` - The Mermaid diagram definition +/// +/// # Returns +/// The rendered SVG string, or an error message on failure. +pub fn render_diagram(code: &str) -> Result { + let opts = RenderOptions::modern(); + mermaid_rs_renderer::render_with_options(code, opts).map_err(|e| e.to_string()) +} + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn test_simple_flowchart() { + let result = render_diagram("flowchart LR; A-->B-->C").unwrap(); + assert!(result.contains("")); + } + + #[test] + fn test_sequence_diagram() { + let result = render_diagram("sequenceDiagram\n Alice->>Bob: Hello").unwrap(); + assert!(result.contains("