use comrak::{ nodes::{AstNode, NodeHeading, NodeValue}, Arena, ComrakOptions, }; use std::{fs, io, path::Path, sync::LazyLock}; pub struct Page<'a> { pub title: Option<&'a AstNode<'a>>, pub content: &'a AstNode<'a>, } impl<'a> Page<'a> { pub fn load(arena: &'a Arena<AstNode<'a>>, path: impl AsRef<Path>) -> io::Result<Self> { let buffer = fs::read_to_string(path)?; let content = comrak::parse_document(arena, &buffer, &COMRAK_OPTIONS); let title = content.first_child().filter(|node| { let mut data = node.data.borrow_mut(); if let NodeValue::Heading(NodeHeading { level: 1, .. }) = data.value { node.detach(); data.value = NodeValue::Document; true } else { false } }); Ok(Self { title, content }) } } pub static COMRAK_OPTIONS: LazyLock<ComrakOptions> = LazyLock::new(|| { let mut options = ComrakOptions::default(); options.extension.header_ids = Some("".to_string()); options.render.unsafe_ = true; options });