v6/src/generator/util/mod.rs

81 lines
2.3 KiB
Rust

pub mod one_more;
pub mod slugify;
pub mod templates;
pub mod word_count;
use anyhow::anyhow;
use askama::Template;
use serde::Deserialize;
use std::fs::File;
use std::io::{BufWriter, Write};
use std::path::Path;
pub fn output_writer(path: impl AsRef<Path>) -> Result<impl Write, std::io::Error> {
let path = crate::generator::output_path(path);
if let Some(parent) = path.parent() {
std::fs::create_dir_all(parent)?;
}
let file = File::create(path)?;
Ok(BufWriter::new(file))
}
pub fn output_rendered_template(
template: &impl Template,
file: impl AsRef<Path>,
) -> Result<(), std::io::Error> {
let path = file.as_ref();
let writer = output_writer(path)?;
template.render_into(&mut FmtWriter(writer)).map_err(|e| {
std::io::Error::new(
std::io::ErrorKind::Other,
format!("writing template {}: {}", path.display(), e),
)
})
}
struct FmtWriter<W: Write>(W);
impl<W: Write> std::fmt::Write for FmtWriter<W> {
fn write_str(&mut self, s: &str) -> std::fmt::Result {
self.0.write_all(s.as_bytes()).map_err(|_| std::fmt::Error)
}
fn write_char(&mut self, c: char) -> std::fmt::Result {
let mut buf = [0u8; 4];
c.encode_utf8(&mut buf);
self.0.write_all(&buf).map_err(|_| std::fmt::Error)
}
fn write_fmt(&mut self, args: std::fmt::Arguments<'_>) -> std::fmt::Result {
self.0.write_fmt(args).map_err(|_| std::fmt::Error)
}
}
pub fn from_frontmatter<'de, D: Deserialize<'de>>(
contents: &'de str,
) -> anyhow::Result<(D, &'de str)> {
let mut chars = contents.char_indices();
for i in 0..=2 {
if chars.next() != Some((i, '`')) {
return Err(anyhow!("no frontmatter"));
}
}
let mut seen_backticks = 0;
let mut end_index = None;
while let Some((idx, c)) = chars.next() {
if c == '`' {
seen_backticks += 1;
if seen_backticks == 3 {
end_index = Some(idx - 3);
break;
}
} else {
seen_backticks = 0;
}
}
let end_index = end_index.ok_or(anyhow!("missing frontmatter end"))?;
let frontmatter = &contents[3..=end_index];
let deserialized = toml::from_str::<'de, D>(frontmatter)?;
Ok((deserialized, chars.as_str()))
}