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 --- Cargo.lock | 285 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Cargo.toml | 2 + src/config.rs | 8 +- src/main.rs | 13 +++ src/page.rs | 87 ++++++++++++++++++ 5 files changed, 391 insertions(+), 4 deletions(-) create mode 100644 src/page.rs diff --git a/Cargo.lock b/Cargo.lock index a85a66d..f6b9ea9 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -6,6 +6,8 @@ version = 4 name = "ahsi" version = "0.1.0" dependencies = [ + "anyhow", + "chrono", "minijinja", "pulldown-cmark", "serde", @@ -13,18 +15,111 @@ dependencies = [ "toml", ] +[[package]] +name = "android_system_properties" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "819e7219dbd41043ac279b19830f2efc897156490d7fd6ea916720117ee66311" +dependencies = [ + "libc", +] + +[[package]] +name = "anyhow" +version = "1.0.102" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7f202df86484c868dbad7eaa557ef785d5c66295e41b460ef922eca0723b842c" + +[[package]] +name = "autocfg" +version = "1.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f2032f911046de80f0a198e0901378627c33f59ea0ac00e363d481118bd70a53" + [[package]] name = "bitflags" version = "2.13.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b4388bee8683e3d04af747c73422af53102d2bd24d9eadb6cbc100baef4b43f8" +[[package]] +name = "bumpalo" +version = "3.20.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "72f5acc6cb2ba439de613abc23857ec3d78374d8ed5ac84e9d11336e87da8649" + +[[package]] +name = "cc" +version = "1.2.65" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e228eec9be7c17ccb640b59b36a5cd805ea2a564a4c5e162c2f659fea30d3b96" +dependencies = [ + "find-msvc-tools", + "shlex", +] + +[[package]] +name = "cfg-if" +version = "1.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9330f8b2ff13f34540b44e946ef35111825727b38d33286ef986142615121801" + +[[package]] +name = "chrono" +version = "0.4.45" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1aa79e62e7697b8e29b513a68abacf485adcd1fe8284a4316c5ae868e6633327" +dependencies = [ + "iana-time-zone", + "js-sys", + "num-traits", + "serde", + "wasm-bindgen", + "windows-link", +] + +[[package]] +name = "core-foundation-sys" +version = "0.8.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "773648b94d0e5d620f64f280777445740e61fe701025087ec8b57f45c791888b" + [[package]] name = "equivalent" version = "1.0.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "877a4ace8713b0bcf2a4e7eec82529c029f1d0619886d18145fea96c3ffe5c0f" +[[package]] +name = "find-msvc-tools" +version = "0.1.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5baebc0774151f905a1a2cc41989300b1e6fbb29aff0ceffa1064fdd3088d582" + +[[package]] +name = "futures-core" +version = "0.3.32" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7e3450815272ef58cec6d564423f6e755e25379b217b0bc688e295ba24df6b1d" + +[[package]] +name = "futures-task" +version = "0.3.32" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "037711b3d59c33004d3856fbdc83b99d4ff37a24768fa1be9ce3538a1cde4393" + +[[package]] +name = "futures-util" +version = "0.3.32" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "389ca41296e6190b48053de0321d02a77f32f8a5d2461dd38762c0593805c6d6" +dependencies = [ + "futures-core", + "futures-task", + "pin-project-lite", + "slab", +] + [[package]] name = "getopts" version = "0.2.24" @@ -40,6 +135,30 @@ version = "0.17.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ed5909b6e89a2db4456e54cd5f673791d7eca6732202bbf2a9cc504fe2f9b84a" +[[package]] +name = "iana-time-zone" +version = "0.1.65" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e31bc9ad994ba00e440a8aa5c9ef0ec67d5cb5e5cb0cc7f8b744a35b389cc470" +dependencies = [ + "android_system_properties", + "core-foundation-sys", + "iana-time-zone-haiku", + "js-sys", + "log", + "wasm-bindgen", + "windows-core", +] + +[[package]] +name = "iana-time-zone-haiku" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f31827a206f56af32e590ba56d5d2d085f558508192593743f16b2306495269f" +dependencies = [ + "cc", +] + [[package]] name = "indexmap" version = "2.14.0" @@ -50,6 +169,29 @@ dependencies = [ "hashbrown", ] +[[package]] +name = "js-sys" +version = "0.3.102" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "03d04c30968dffe80775bd4d7fb676131cd04a1fb46d2686dbffbaec2d9dfd31" +dependencies = [ + "cfg-if", + "futures-util", + "wasm-bindgen", +] + +[[package]] +name = "libc" +version = "0.2.186" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "68ab91017fe16c622486840e4c83c9a37afeff978bd239b5293d61ece587de66" + +[[package]] +name = "log" +version = "0.4.32" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "953f07c43838f8e6f9758cab68bf5bed85465e7587ebe0b823f1bcd81978ad3a" + [[package]] name = "memchr" version = "2.8.2" @@ -72,6 +214,27 @@ dependencies = [ "serde", ] +[[package]] +name = "num-traits" +version = "0.2.19" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "071dfc062690e90b734c0b2273ce72ad0ffa95f0c74596bc250dcfd960262841" +dependencies = [ + "autocfg", +] + +[[package]] +name = "once_cell" +version = "1.21.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9f7c3e4beb33f85d45ae3e3a1792185706c8e16d043238c593331cc7cd313b50" + +[[package]] +name = "pin-project-lite" +version = "0.2.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a89322df9ebe1c1578d689c92318e070967d1042b512afbe49518723f4e6d5cd" + [[package]] name = "proc-macro2" version = "1.0.106" @@ -109,6 +272,12 @@ dependencies = [ "proc-macro2", ] +[[package]] +name = "rustversion" +version = "1.0.22" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b39cdef0fa800fc44525c84ccb54a029961a8215f9619753635a9c0d2538d46d" + [[package]] name = "serde" version = "1.0.228" @@ -148,6 +317,18 @@ dependencies = [ "serde_core", ] +[[package]] +name = "shlex" +version = "2.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f8fadd59c855ef2080decdef8ff161eb6661b86933c9d82e5ba29dc602a55aba" + +[[package]] +name = "slab" +version = "0.4.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0c790de23124f9ab44544d7ac05d60440adc586479ce501c1d6d7da3cd8c9cf5" + [[package]] name = "syn" version = "2.0.118" @@ -216,6 +397,110 @@ version = "0.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b4ac048d71ede7ee76d585517add45da530660ef4390e49b098733c6e897f254" +[[package]] +name = "wasm-bindgen" +version = "0.2.125" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8ddb3f79143bced6de84270411622a2699cee572fc0875aeaf1e7867cf9fca1a" +dependencies = [ + "cfg-if", + "once_cell", + "rustversion", + "wasm-bindgen-macro", + "wasm-bindgen-shared", +] + +[[package]] +name = "wasm-bindgen-macro" +version = "0.2.125" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4e21a184b13fb19e157296e2c46056aec9092264fab83e4ba59e68c61b323c3d" +dependencies = [ + "quote", + "wasm-bindgen-macro-support", +] + +[[package]] +name = "wasm-bindgen-macro-support" +version = "0.2.125" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fecefd9c35bd935a20fc3fc344b5f29138961e4f47fb03297d88f2587afb5ebd" +dependencies = [ + "bumpalo", + "proc-macro2", + "quote", + "syn", + "wasm-bindgen-shared", +] + +[[package]] +name = "wasm-bindgen-shared" +version = "0.2.125" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "23939e44bb9a5d7576fa2b563dc2e136628f1224e88a8deed09e04858b77871f" +dependencies = [ + "unicode-ident", +] + +[[package]] +name = "windows-core" +version = "0.62.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b8e83a14d34d0623b51dce9581199302a221863196a1dde71a7663a4c2be9deb" +dependencies = [ + "windows-implement", + "windows-interface", + "windows-link", + "windows-result", + "windows-strings", +] + +[[package]] +name = "windows-implement" +version = "0.60.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "053e2e040ab57b9dc951b72c264860db7eb3b0200ba345b4e4c3b14f67855ddf" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "windows-interface" +version = "0.59.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3f316c4a2570ba26bbec722032c4099d8c8bc095efccdc15688708623367e358" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "windows-link" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f0805222e57f7521d6a62e36fa9163bc891acd422f971defe97d64e70d0a4fe5" + +[[package]] +name = "windows-result" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7781fa89eaf60850ac3d2da7af8e5242a5ea78d1a11c49bf2910bb5a73853eb5" +dependencies = [ + "windows-link", +] + +[[package]] +name = "windows-strings" +version = "0.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7837d08f69c77cf6b07689544538e017c1bfcf57e34b4c0ff58e6c2cd3b37091" +dependencies = [ + "windows-link", +] + [[package]] name = "winnow" version = "1.0.3" diff --git a/Cargo.toml b/Cargo.toml index 435cd41..f015f5f 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -9,3 +9,5 @@ minijinja = "2.21.0" toml = "1.1.2" serde = { version = "1.0.228", features = ["derive"] } serde_derive = "1.0.228" +chrono = { version = "0.4.45", features = ["serde"] } +anyhow = "1.0.102" diff --git a/src/config.rs b/src/config.rs index f101456..8dc8a6f 100644 --- a/src/config.rs +++ b/src/config.rs @@ -2,10 +2,10 @@ use serde::Deserialize; use std::fs; #[derive(Deserialize, Debug)] -struct Config { - title: String, - url: String, - author: String, +pub struct Config { + pub title: String, + pub url: String, + pub author: String, } pub fn parse_file(filename: &str) { diff --git a/src/main.rs b/src/main.rs index 04d0a96..b93d80f 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,5 +1,18 @@ mod config; +mod page; +use std::env; +use std::path::PathBuf; fn main() { + config::parse_file("ahsi.toml"); + let args: Vec = env::args().collect(); + if args.len() > 1 { + let first_arg = &args[1]; + let path = PathBuf::from(first_arg); + match page::parse_page(&path) { + Ok(p) => println!("{}", p.html), + Err(e) => eprintln!("error: {e:#}"), + } + } } 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