diff --git a/Cargo.lock b/Cargo.lock index c74bef9..5e4b1fe 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -80,6 +80,12 @@ dependencies = [ "windows-sys", ] +[[package]] +name = "anyhow" +version = "1.0.79" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "080e9890a082662b09c1ad45f567faeeb47f22b5fb23895fbe1e651e718e25ca" + [[package]] name = "autocfg" version = "1.1.0" @@ -134,9 +140,9 @@ dependencies = [ [[package]] name = "bumpalo" -version = "3.14.0" +version = "3.15.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7f30e7476521f6f8af1a1c4c0b8cc94f0bee37d91763d0ca2665f299b6cd8aec" +checksum = "d32a994c2b3ca201d9b263612a374263f05e7adde37c4707f693dcd375076d1f" [[package]] name = "cc" @@ -189,9 +195,9 @@ dependencies = [ [[package]] name = "clap" -version = "4.5.0" +version = "4.5.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "80c21025abd42669a92efc996ef13cfb2c5c627858421ea58d5c3b331a6c134f" +checksum = "c918d541ef2913577a0f9566e9ce27cb35b6df072075769e0b26cb5a554520da" dependencies = [ "clap_builder", "clap_derive", @@ -199,9 +205,9 @@ dependencies = [ [[package]] name = "clap_builder" -version = "4.5.0" +version = "4.5.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "458bf1f341769dfcf849846f65dffdf9146daa56bcd2a47cb4e1de9915567c99" +checksum = "9f3e7391dad68afb0c2ede1bf619f579a3dc9c2ec67f089baa397123a2f3d1eb" dependencies = [ "anstream", "anstyle", @@ -303,9 +309,9 @@ dependencies = [ [[package]] name = "deunicode" -version = "1.4.2" +version = "1.4.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3ae2a35373c5c74340b79ae6780b498b2b183915ec5dacf263aac5a099bf485a" +checksum = "b6e854126756c496b8c81dec88f9a706b15b875c5849d4097a3854476b9fdf94" [[package]] name = "digest" @@ -813,6 +819,7 @@ checksum = "c08c74e62047bb2de4ff487b251e4a92e24f48745648451635cec7d591162d9f" name = "roxy_cli" version = "0.1.0" dependencies = [ + "anyhow", "clap", "glob", "roxy_core", @@ -830,7 +837,11 @@ dependencies = [ [[package]] name = "roxy_core" version = "0.1.0" -source = "git+https://fem.mint.lgbt/kitsunecafe/roxy-core.git#7839db8b062698adfe81a86d2a0cf041a6711456" +source = "git+https://fem.mint.lgbt/kitsunecafe/roxy-core.git#6b5b3520b0623af071ffd3053c60448c8a0b66d3" +dependencies = [ + "anyhow", + "thiserror", +] [[package]] name = "roxy_markdown_parser" @@ -854,7 +865,7 @@ dependencies = [ [[package]] name = "roxy_syntect" version = "0.1.0" -source = "git+https://fem.mint.lgbt/kitsunecafe/roxy-syntect.git#48601fc5e6e0ee0e753c892f0eb42a9b0b48be99" +source = "git+https://fem.mint.lgbt/kitsunecafe/roxy-syntect.git#4a872d3642a428fc91afe3a519e9e4d1f3a6d3d0" dependencies = [ "once_cell", "regex", @@ -978,9 +989,9 @@ checksum = "5ee073c9e4cd00e28217186dbe12796d692868f432bf2e97ee73bed0c56dfa01" [[package]] name = "syn" -version = "2.0.48" +version = "2.0.49" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0f3531638e407dfc0814761abb7c00a5b54992b849452a0646b7f65c9f770f3f" +checksum = "915aea9e586f80826ee59f8453c1101f9d1c4b3964cd2460185ee8e299ada496" dependencies = [ "proc-macro2", "quote", @@ -1105,9 +1116,9 @@ dependencies = [ [[package]] name = "toml_edit" -version = "0.22.5" +version = "0.22.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "99e68c159e8f5ba8a28c4eb7b0c0c190d77bb479047ca713270048145a9ad28a" +checksum = "2c1b5fd4128cc8d3e0cb74d4ed9a9cc7c7284becd4df68f5f940e1ad123606f6" dependencies = [ "indexmap", "serde", diff --git a/Cargo.toml b/Cargo.toml index 94a3f50..faefa7c 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -16,4 +16,5 @@ toml = "0.8.8" tera = "1.19.1" serde = { version = "1.0.195", features = ["derive"]} slugify = "0.1.0" +anyhow = "1.0.79" diff --git a/src/context.rs b/src/context.rs index 66b0528..ada2eed 100644 --- a/src/context.rs +++ b/src/context.rs @@ -1,7 +1,14 @@ -use std::{path::Path, borrow::BorrowMut}; +use std::{ + borrow::BorrowMut, + fs::File, + io::{BufReader, Read}, + path::{Path, PathBuf}, +}; -use tera::{Map, Value}; -use crate::iter_ext::Head; +use crate::{file_path::FilePath, iter_ext::Head}; +use roxy_core::result::Result; +use tera::{to_value, Map, Value}; +use toml::Table; fn merge(a: &mut Value, b: Value) { match (a, b) { @@ -24,17 +31,64 @@ pub(crate) struct Context { impl Context { pub fn new() -> Self { Self { - inner: tera::Value::Null + inner: tera::Value::Null, } } pub fn merge(&mut self, other: tera::Context) { - merge( - self.inner.borrow_mut(), - other.into_json() - ) + merge(self.inner.borrow_mut(), other.into_json()) } + fn as_formatted_path>(path: &P) -> Option { + let path = path.as_ref(); + if path.with_extension("").file_name()? == "index" { + Some(path.with_file_name("")) + } else { + Some(path.with_extension("")) + } + } + + pub fn from_files<'a, T: AsRef>( + files: Vec<&PathBuf>, + file_path: &'a FilePath, + ) -> Result { + let mut context = Context::new(); + + for path in files { + let mut buf = Vec::new(); + + let mut file = File::open(path).map(BufReader::new)?; + file.read_to_end(&mut buf)?; + let mut str = String::from_utf8(buf).map_err(anyhow::Error::from)?; + let toml: Table = toml::from_str(&mut str).map_err(anyhow::Error::from)?; + + let path = file_path.strip_root(path).map_err(anyhow::Error::from)?; + + context.insert(&path, &tera::to_value(toml).map_err(anyhow::Error::from)?); + } + + Ok(context) + } + + pub fn build_paths<'a, T: AsRef>( + &mut self, + files: &Vec<&PathBuf>, + file_path: &'a FilePath, + ) -> Result<()> { + for path in files { + let path = file_path.strip_root(path).map_err(anyhow::Error::from)?; + if let Some(path) = Self::as_formatted_path(&path) { + if let Some(slug) = file_path.as_slug(&path) { + let slug = PathBuf::from("/").join(slug); + if let Ok(slug) = to_value(slug) { + self.insert(&path.join("path"), &slug); + } + } + } + } + + Ok(()) + } fn path_to_string>(path: &P) -> String { path.as_ref().to_string_lossy().to_string() @@ -57,9 +111,9 @@ impl Context { Some(map.into()) } - pub fn insert>(&mut self, path: &P, value: &Value) { + fn as_key>(path: &P) -> Option<&Path> { let path = path.as_ref(); - let path = if path + if path .with_extension("") .file_name() .map_or(false, |f| f.to_os_string() == "index") @@ -67,7 +121,11 @@ impl Context { path.parent() } else { Some(path) - }; + } + } + + pub fn insert>(&mut self, path: &P, value: &Value) { + let path = Self::as_key(path).map(|p| p.with_extension("")); if let Some(v) = Self::create_path(&path.unwrap(), value) { if let Ok(ctx) = tera::Context::from_value(v) { @@ -76,8 +134,12 @@ impl Context { } } - pub fn get>(&self, _path: &P) -> Option<&Value> { - None + pub fn get>(&self, path: &P) -> Option<&Value> { + Self::as_key(path)? + .with_extension("") + .components() + .filter_map(|c| c.as_os_str().to_str()) + .try_fold(&self.inner, |acc, i| acc.get(i)) } } @@ -90,8 +152,7 @@ impl Into for Context { impl TryInto for Context { type Error = tera::Error; - fn try_into(self) -> Result { + fn try_into(self) -> std::result::Result { tera::Context::from_value(self.inner) } } - diff --git a/src/main.rs b/src/main.rs index 34be3ef..aa40bcf 100644 --- a/src/main.rs +++ b/src/main.rs @@ -19,30 +19,21 @@ use roxy_tera_parser::{TeraParser, TeraParserOptions}; use clap::Parser as Clap; use std::{ ffi, - fs::{self, File}, - io::{BufReader, Read}, + fs, path::{Path, PathBuf}, }; -use tera::to_value; use syntect::{highlighting::ThemeSet, parsing::SyntaxSet}; -use toml::Table; use glob::glob; use roxy_core::roxy::{Parser, Roxy}; +use roxy_core::result::Result; -use crate::{ - iter_ext::{Head, MapFoldExt}, - result_ext::FilterExt, -}; +use crate::iter_ext::{Head, MapFoldExt}; const DEFAULT_THEME: &'static str = "base16-ocean.dark"; const CONTENT_EXT: [&'static str; 4] = ["md", "tera", "html", "htm"]; -fn handle_err(err: E) -> Error { - Error::new(err.to_string(), err) -} - #[derive(Clap)] #[command(name = "Roxy")] #[command(author = "KitsuneCafe")] @@ -53,14 +44,14 @@ pub struct Options { pub output: String, } -fn get_files + std::fmt::Debug>(path: &P) -> Result, Error> { +fn get_files + std::fmt::Debug>(path: &P) -> Result> { let path = path .as_ref() .to_str() - .ok_or_else(|| Error::from(format!("{path:?} is not a valid path.")))?; + .ok_or_else(|| anyhow::Error::msg(format!("{path:?} is not a valid path.")))?; let files: Vec = glob(path) - .map_err(handle_err)? + .map_err(anyhow::Error::from)? .filter_map(|x| x.ok()) .filter(|f| Path::is_file(f)) .collect(); @@ -101,49 +92,10 @@ fn load_config(path: &Path) -> Config { .into() } -fn as_formatted_path>(path: &P) -> Option { - let path = path.as_ref(); - if path.with_extension("").file_name()? == "index" { - Some(path.with_file_name("")) - } else { - Some(path.with_extension("")) - } -} - -fn context_from_meta_files<'a, T: AsRef>( - files: &Vec<&PathBuf>, - file_path: &'a FilePath, -) -> Result { - let mut context = Context::new(); - - for path in files { - let mut buf = Vec::new(); - - let mut file = File::open(path).map(BufReader::new)?; - file.read_to_end(&mut buf)?; - let mut str = String::from_utf8(buf).map_err(handle_err)?; - let toml: Table = toml::from_str(&mut str).map_err(handle_err)?; - - let path = file_path.strip_root(path)?; - - context.insert(&path, &tera::to_value(toml).map_err(handle_err)?); - if let Some(path) = as_formatted_path(&path) { - if let Some(slug) = file_path.as_slug(&path) { - let slug = PathBuf::from("/").join(slug); - if let Ok(slug) = to_value(slug) { - context.insert(&path.join("path"), &slug); - } - } - } - } - - Ok(context) -} - fn copy_static>( files: &Vec<&PathBuf>, file_path: &FilePath, -) -> Result<(), Error> { +) -> Result<()> { for file in files { let output = file_path.to_output(file).unwrap(); fs::create_dir_all(output.parent().unwrap())?; @@ -153,7 +105,7 @@ fn copy_static>( Ok(()) } -fn main() -> Result<(), Box> { +fn main() -> Result<()> { let opts = Options::parse(); let mut file_path = FilePath::new(&opts.input, &opts.output); @@ -173,7 +125,8 @@ fn main() -> Result<(), Box> { CONTENT_EXT.contains(&ext) }); - let mut context: Context = context_from_meta_files(&meta, &file_path)?; + let mut context = Context::from_files(meta, &file_path)?; + context.build_paths(&content, &file_path)?; let theme = config.syntect.theme; @@ -205,7 +158,7 @@ fn main() -> Result<(), Box> { let mut rewriter = MarkdownTeraRewriter::new(); parser.push(&mut rewriter); - if let Ok(path) = &file_path.strip_root(&file_name) { + if let Ok(path) = &file_path.strip_root(&file) { if let Some(current_context) = context.get(path) { context.insert(&"this", ¤t_context.clone()); }