webdog/
util.rs

1//! Module containing various utilities.
2
3use std::path::Path;
4
5use pulldown_cmark::{Options, Parser};
6use time::OffsetDateTime;
7
8use crate::builder::SiteBuilder;
9
10/// Simple helper to remove the contents of a directory without removing the directory itself.
11pub fn remove_dir_contents(path: &Path) -> eyre::Result<()> {
12	for entry in path.read_dir()? {
13		let entry = entry?;
14		let path = entry.path();
15		if path.is_file() {
16			std::fs::remove_file(&path)?;
17		} else {
18			std::fs::remove_dir_all(&path)?;
19		}
20	}
21
22	Ok(())
23}
24
25/// Helper to format a timestamp according to the given format.
26pub fn format_timestamp(ts: OffsetDateTime, format: &str) -> eyre::Result<String> {
27	let fmt = time::format_description::parse_borrowed::<2>(format)?;
28	Ok(ts.format(&fmt)?)
29}
30
31/// Helper to render markdown.
32pub fn render_markdown(builder: &SiteBuilder, input: &str) -> eyre::Result<String> {
33	let mut language = None;
34	let parser = Parser::new_ext(input, Options::all()).filter_map(|event| {
35		// syntax highlighting for code blocks
36		match event {
37			pulldown_cmark::Event::Start(pulldown_cmark::Tag::CodeBlock(
38				pulldown_cmark::CodeBlockKind::Fenced(name),
39			)) => {
40				language = Some(name);
41				None
42			}
43			pulldown_cmark::Event::Text(code) => {
44				if let Some(language) = language.take() {
45					let syntax_reference = builder
46						.syntax_set
47						.find_syntax_by_token(&language)
48						.unwrap_or_else(|| builder.syntax_set.find_syntax_plain_text());
49					let html = format!(
50						r#"<div class="wd-codeblock">
51							<button class="copy">Copy</button>
52							{}
53						</div>"#,
54						syntect::html::highlighted_html_for_string(
55							&code,
56							&builder.syntax_set,
57							syntax_reference,
58							builder
59								.theme_set
60								.themes
61								.get(&builder.site.config.code_theme)
62								.as_ref()
63								.expect("should never fail"),
64						)
65						.expect("failed to highlight syntax")
66					);
67					Some(pulldown_cmark::Event::Html(html.into()))
68				} else {
69					Some(pulldown_cmark::Event::Text(code))
70				}
71			}
72			_ => Some(event),
73		}
74	});
75	let mut page_html = String::new();
76	pulldown_cmark::html::push_html(&mut page_html, parser);
77
78	Ok(page_html)
79}