81 lines
2.3 KiB
Rust
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()))
|
|
}
|