use std::fs;
use std::path::PathBuf;
use crate::markdown::parse_markdown;
use clap::Parser;
use handlebars::handlebars_helper;
use serde_json::json;
use toml::value::Datetime;
use walkdir::WalkDir;
handlebars_helper!(format_timestamp: |timestamp: Datetime| {
crate::toml::format_datetime(timestamp)
});
#[derive(Parser, Debug)]
#[command(author, version, about, long_about = None)]
pub struct Args {
#[arg(short, long, default_value = ".")]
pub input_dir: String,
#[arg(short, long, default_value = "./dist")]
pub output_dir: String,
#[arg(short, long, default_value = "false")]
pub verbose: bool,
#[arg(short, long, default_value = "false")]
pub watch: bool,
}
pub struct Paths {
pub input_dir: PathBuf,
pub output_dir: PathBuf,
pub pages_path: PathBuf,
pub templates_path: PathBuf,
}
impl Paths {
pub fn new(input_dir: &str, output_dir: &str) -> Self {
let input_dir = PathBuf::from(input_dir);
let output_dir = PathBuf::from(output_dir);
let pages_path = input_dir.join("pages");
let templates_path = input_dir.join("templates");
Self {
input_dir,
output_dir,
pages_path,
templates_path,
}
}
}
pub fn build_handlebars_stack(templates_path: &PathBuf) -> handlebars::Handlebars<'static> {
let mut handlebars = handlebars::Handlebars::new();
for entry in WalkDir::new(templates_path)
.into_iter()
.filter_map(|e| e.ok())
{
if entry.file_type().is_file() {
let file_name = entry.path().file_stem().unwrap().to_str().unwrap();
let tpl_path = entry.path().to_str().unwrap();
handlebars
.register_template_file(file_name, tpl_path)
.expect("Should have been able to register the template");
}
}
handlebars.register_helper("format_timestamp", Box::new(format_timestamp));
handlebars
}
pub fn build_pages(
verbose: bool,
pages_path: &PathBuf,
output_dir: &PathBuf,
templates_path: &PathBuf,
) {
let handlebars = build_handlebars_stack(templates_path);
for entry in WalkDir::new(pages_path).into_iter().filter_map(|e| e.ok()) {
if entry.file_type().is_file() {
if verbose {
println!(" input: {}", entry.path().display());
}
let contents =
fs::read_to_string(entry.path()).expect("Should have been able to read the file");
let (attrs, html_output) =
parse_markdown(contents.as_str(), "Solarized (dark)".to_string());
let data = json!({
"title": attrs.title,
"author": attrs.author,
"timestamp": attrs.timestamp,
"content": html_output,
});
let output = handlebars
.render("page", &data)
.expect("Should have been able to render the template");
let mut slug = entry.path().file_stem().unwrap().to_str().unwrap();
if slug == "index" {
slug = "";
}
let output_path = output_dir.join(slug).join("index.html");
if verbose {
println!("output: {}", output_path.display());
}
let prefix = output_path.parent().unwrap();
fs::create_dir_all(prefix).expect("Should have been able to create the directory");
fs::write(output_path, output).expect("Should have been able to write the file");
}
}
}