diff --git a/Cargo.lock b/Cargo.lock index deb4d00..951e905 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -322,7 +322,7 @@ version = "4.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b8cd2b2a819ad6eec39e8f1d6b53001af1e5469f8c177579cdaeb313115b825f" dependencies = [ - "heck", + "heck 0.4.1", "proc-macro2", "quote", "syn", @@ -618,6 +618,15 @@ version = "0.14.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2c6201b9ff9fd90a5a3bac2e56a830d0caa509576f0e503818ee82c181b3437a" +[[package]] +name = "heck" +version = "0.3.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6d621efb26863f0e9924c6ac577e8275e5e6b77455db64ffa6c65c904e9e132c" +dependencies = [ + "unicode-segmentation", +] + [[package]] name = "heck" version = "0.4.1" @@ -1325,6 +1334,16 @@ dependencies = [ "unic-segment", ] +[[package]] +name = "tera-text-filters" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fef4d0b73a2c9f3cbf55a1b0511bf8173024471da07266d0184f8cd0a480a5a0" +dependencies = [ + "heck 0.3.3", + "tera", +] + [[package]] name = "terminal_size" version = "0.1.17" @@ -1589,6 +1608,12 @@ dependencies = [ "regex", ] +[[package]] +name = "unicode-segmentation" +version = "1.10.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1dd624098567895118886609431a7c3b8f516e41d30e0643f03d94592a147e36" + [[package]] name = "unicode-width" version = "0.1.10" @@ -1624,6 +1649,7 @@ dependencies = [ "miette", "serde", "tera", + "tera-text-filters", "tokio", "toml", "tracing", diff --git a/Cargo.toml b/Cargo.toml index a5d2296..e34ddbb 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -13,6 +13,7 @@ globset = { version = "0.4.10", features = ["serde", "serde1"] } miette = { version = "5.9.0", features = ["serde", "fancy"] } serde = { version = "1.0.164", features = ["derive"] } tera = "1.19.0" +tera-text-filters = "1.0.0" tokio = { version = "1.29.0", features = ["rt-multi-thread", "net", "macros", "sync", "fs", "io-std", "io-util", "time", "process"] } toml = "0.7.5" tracing = { version = "0.1.37", features = ["async-await", "release_max_level_debug"] } diff --git a/src/data/dir_loader.rs b/src/data/dir_loader.rs index 4e546b6..4808379 100644 --- a/src/data/dir_loader.rs +++ b/src/data/dir_loader.rs @@ -15,7 +15,6 @@ pub struct DirLoader { #[derive(Clone, Debug)] pub struct FolderData { - pub content_root: PathBuf, pub path: PathBuf, pub index: IndexData, pub pages: Vec, @@ -69,7 +68,6 @@ impl DirLoader { path, index: index_data, pages, - content_root: self.base_path.to_owned(), })) } } diff --git a/src/main.rs b/src/main.rs index 574ec51..4f62e0a 100644 --- a/src/main.rs +++ b/src/main.rs @@ -12,6 +12,7 @@ use crate::args::Args; mod args; mod config; pub mod data; +mod processors; mod rendering; #[tokio::main] @@ -32,11 +33,14 @@ async fn build(args: &Args, _build_args: &BuildArgs, cfg: Config) -> Result<()> let base_path = &args.directory; let content_dir = base_path.join(folders.content.unwrap_or("content".into())); let template_dir = base_path.join(folders.templates.unwrap_or("templates".into())); - let out_dir = base_path.join(folders.output.unwrap_or("public".into())); + let out_dir = base_path.join(folders.output.unwrap_or("dist".into())); + + let dirs = DirLoader::new(content_dir.to_owned()) + .read_content() + .await?; - let dirs = DirLoader::new(content_dir).read_content().await?; let template_glob = format!("{}/**/*", template_dir.to_string_lossy()); - ContentRenderer::new(template_glob, out_dir) + ContentRenderer::new(template_glob, content_dir, out_dir) .render_all(dirs) .await?; diff --git a/src/processors/filters/mod.rs b/src/processors/filters/mod.rs new file mode 100644 index 0000000..7b6d482 --- /dev/null +++ b/src/processors/filters/mod.rs @@ -0,0 +1,5 @@ +use tera::Tera; + +pub fn register_all(tera: &mut Tera) { + tera_text_filters::register_all(tera); +} diff --git a/src/processors/mod.rs b/src/processors/mod.rs new file mode 100644 index 0000000..7822754 --- /dev/null +++ b/src/processors/mod.rs @@ -0,0 +1,7 @@ +use tera::Tera; + +mod filters; + +pub fn register_all(tera: &mut Tera) { + filters::register_all(tera); +} diff --git a/src/rendering/mod.rs b/src/rendering/mod.rs index bf2659b..8537679 100644 --- a/src/rendering/mod.rs +++ b/src/rendering/mod.rs @@ -11,12 +11,14 @@ use crate::data::{load_page, FolderData}; pub struct ContentRenderer { template_glob: String, out_dir: PathBuf, + content_dir: PathBuf, } impl ContentRenderer { - pub fn new(template_glob: String, out_dir: PathBuf) -> Self { + pub fn new(template_glob: String, content_dir: PathBuf, out_dir: PathBuf) -> Self { Self { template_glob, + content_dir, out_dir, } } @@ -26,7 +28,8 @@ impl ContentRenderer { if self.out_dir.exists() { fs::remove_dir_all(&self.out_dir).await.into_diagnostic()?; } - let tera = Tera::new(&self.template_glob).into_diagnostic()?; + let mut tera = Tera::new(&self.template_glob).into_diagnostic()?; + super::processors::register_all(&mut tera); future::try_join_all(dirs.into_iter().map(|data| self.render_folder(&tera, data))).await?; Ok(()) @@ -34,40 +37,66 @@ impl ContentRenderer { #[tracing::instrument(level = "trace", skip_all)] async fn render_folder(&self, tera: &Tera, data: FolderData) -> Result<()> { - for page_path in data.pages { - let page = load_page(&page_path).await?; - let mut context = Context::new(); - let mut template_name = data - .index - .default_template - .to_owned() - .unwrap_or("default".into()); - - match page { - crate::data::Page::Data(data) => { - if let Some(tmpl) = data.metadata.template { - template_name = tmpl; - } - context.insert("data", &data.data); + let dir_name = data + .path + .components() + .last() + .unwrap() + .as_os_str() + .to_string_lossy(); + let default_template = data + .index + .default_template + .to_owned() + .unwrap_or(dir_name.into()); + + future::try_join_all( + data.pages + .into_iter() + .map(|page| self.render_page(tera, default_template.clone(), page)), + ) + .await?; + + Ok(()) + } + + #[tracing::instrument(level = "trace", skip_all)] + async fn render_page( + &self, + tera: &Tera, + default_template: String, + page_path: PathBuf, + ) -> Result<()> { + tracing::debug!("Rendering {page_path:?}"); + + let page = load_page(&page_path).await?; + let mut context = Context::new(); + let mut template_name = default_template; + + match page { + crate::data::Page::Data(data) => { + if let Some(tmpl) = data.metadata.template { + template_name = tmpl; } - crate::data::Page::Content(content) => context.insert("content", &content), + context.insert("data", &data.data); } + crate::data::Page::Content(content) => context.insert("content", &content), + } - tracing::debug!("context = {:?}", context); + tracing::debug!("context = {context:?}"); - let html = tera.render(&template_name, &context).into_diagnostic()?; - let rel_path = page_path - .strip_prefix(&data.content_root) - .into_diagnostic()?; - let mut out_path = self.out_dir.join(rel_path); - out_path.set_extension("html"); - let parent = out_path.parent().unwrap(); + let html = tera.render(&template_name, &context).into_diagnostic()?; + let rel_path = page_path + .strip_prefix(&self.content_dir) + .into_diagnostic()?; + let mut out_path = self.out_dir.join(rel_path); + out_path.set_extension("html"); + let parent = out_path.parent().unwrap(); - if !parent.exists() { - fs::create_dir_all(parent).await.into_diagnostic()?; - } - fs::write(out_path, html).await.into_diagnostic()?; + if !parent.exists() { + fs::create_dir_all(parent).await.into_diagnostic()?; } + fs::write(out_path, html).await.into_diagnostic()?; Ok(()) }