A living almanac of seasons, soil, and the quiet knowledge that used to be common. Rust axum with minijinja and Vite.
agriculturealmanacaxumfolk-knowledgegardeningminijinjarustseasonalvite
1use comrak::{markdown_to_html, ComrakOptions};
2
3fn options() -> ComrakOptions {
4 let mut opts = ComrakOptions::default();
5 opts.render.unsafe_ = true;
6 opts
7}
8
9/// render markdown, then strip the single wrapping `<p>...</p>` if there's
10/// exactly one. matches `render_md` in the original almanac.py.
11pub fn render_inline(text: &str) -> String {
12 let html = markdown_to_html(text, &options()).trim().to_string();
13 if html.starts_with("<p>") && html.ends_with("</p>") && count_substr(&html, "<p>") == 1 {
14 html[3..html.len() - 4].to_string()
15 } else {
16 html
17 }
18}
19
20/// render markdown keeping block-level tags. matches `render_md_block`.
21pub fn render_block(text: &str) -> String {
22 markdown_to_html(text, &options()).trim().to_string()
23}
24
25fn count_substr(s: &str, needle: &str) -> usize {
26 s.matches(needle).count()
27}
28
29#[cfg(test)]
30mod tests {
31 use super::*;
32
33 #[test]
34 fn inline_strips_single_p() {
35 assert_eq!(render_inline("simple text"), "simple text");
36 }
37
38 #[test]
39 fn inline_keeps_bold() {
40 assert_eq!(
41 render_inline("**plant leafy things**: lettuce"),
42 "<strong>plant leafy things</strong>: lettuce"
43 );
44 }
45
46 #[test]
47 fn block_keeps_paragraphs() {
48 let out = render_block("paragraph one\n\nparagraph two");
49 assert_eq!(out, "<p>paragraph one</p>\n<p>paragraph two</p>");
50 }
51}