From 5b532e914bcad238af03a8916d961827bffc8058 Mon Sep 17 00:00:00 2001 From: radhitya Date: Sat, 20 Jun 2026 16:38:10 +0700 Subject: parse markdown, parse frontmatter --- src/page.rs | 87 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 87 insertions(+) create mode 100644 src/page.rs (limited to 'src/page.rs') diff --git a/src/page.rs b/src/page.rs new file mode 100644 index 0000000..c81887d --- /dev/null +++ b/src/page.rs @@ -0,0 +1,87 @@ +use serde::Deserialize; +use chrono::NaiveDate; +use std::path::PathBuf; +use std::fs; + +#[derive(Deserialize, Debug)] +pub struct Frontmatter { + pub title: String, + pub date: NaiveDate, + #[serde(default)] + pub draft: bool, +} + +#[derive(Debug)] +pub struct Page { + pub meta: Frontmatter, + pub source_path: PathBuf, + pub output_path: PathBuf, + pub body: String, + pub html: String, +} + +pub fn parse_frontmatter(content: &str) -> Option { + if !content.starts_with("+++\n") { + return None; + } + let rest = &content[4..]; + let end = rest.find("\n+++\n")?; + + let toml_str = &rest[..end]; + let meta: Frontmatter = toml::from_str(toml_str) + .expect("frontmatter failed parsed"); + Some(meta) +} + +pub fn parse_page(source_path: &PathBuf) -> anyhow::Result { + let content = fs::read_to_string(source_path)?; + let maybe_meta = parse_frontmatter(&content); + let meta: Frontmatter; + let body: String; + + if let Some(fm) = maybe_meta { + let end_post = content.find("\n+++\n").unwrap(); + println!("end_post: {}", end_post); + meta = fm; + body = content[(end_post + 5)..].to_string(); + } else { + let fallback_title = source_path + .file_stem() + .and_then(|s| s.to_str()) + .unwrap_or("untitled") + .to_string(); + + meta = Frontmatter { + title: fallback_title, + date: chrono::Utc::now().date_naive(), + draft: true, + }; + body = content; + } + + let html = render_markdown(&body); + + let slug = meta.title.to_lowercase().replace(' ', "-"); + let output_path = PathBuf::from("public").join(&slug).join("index.html"); + + Ok (Page { + meta, + source_path: source_path.clone(), + output_path, + body, + html, + }) +} + +pub fn render_markdown(input: &str) -> String { + use pulldown_cmark::{Parser, Options, html}; + + let mut options = Options::empty(); + options.insert(Options::ENABLE_STRIKETHROUGH); + options.insert(Options::ENABLE_TABLES); + + let parser = Parser::new_ext(input, options); + let mut out = String::new(); + html::push_html(&mut out, parser); + out +} -- cgit v1.2.3