From 0fc188dbb8d41e34a37d0dbb811f20ebff289e51 Mon Sep 17 00:00:00 2001 From: KitsuneCafe <10284516+kitsunecafe@users.noreply.github.com> Date: Sat, 10 Feb 2024 23:38:29 -0500 Subject: [PATCH] improve context storage --- Cargo.lock | 13 +++- Cargo.toml | 1 + src/context.rs | 178 ++++++++++++++++++++++++++++++++++++++++++++----- src/main.rs | 3 + 4 files changed, 174 insertions(+), 21 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 6cc8577..940847d 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -48,9 +48,9 @@ dependencies = [ [[package]] name = "anstyle" -version = "1.0.5" +version = "1.0.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2faccea4cc4ab4a667ce676a30e8ec13922a692c99bb8f5b11f1502c72e04220" +checksum = "8901269c6307e8d93993578286ac0edf7f195079ffff5ebdeea6a59ffb7e36bc" [[package]] name = "anstyle-parse" @@ -317,6 +317,12 @@ dependencies = [ "crypto-common", ] +[[package]] +name = "either" +version = "1.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "11157ac094ffbdde99aa67b23417ebdd801842852b500e395a45a9c0aac03e4a" + [[package]] name = "equivalent" version = "1.0.1" @@ -820,6 +826,7 @@ name = "roxy_cli" version = "0.1.0" dependencies = [ "clap", + "either", "glob", "roxy_core", "roxy_markdown_parser", @@ -870,7 +877,7 @@ dependencies = [ [[package]] name = "roxy_tera_parser" version = "0.1.0" -source = "git+https://fem.mint.lgbt/kitsunecafe/roxy-tera-parser.git#d7a364b1af1c2ec400d951fcd41560f929feb12c" +source = "git+https://fem.mint.lgbt/kitsunecafe/roxy-tera-parser.git#13868747c22d09c6cd61bebb4dbb69e299be6bdb" dependencies = [ "once_cell", "regex", diff --git a/Cargo.toml b/Cargo.toml index 63c03fe..446eb08 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -15,4 +15,5 @@ clap = { version = "4.4.17", features = ["derive"] } toml = "0.8.8" tera = "1.19.1" serde = "1.0.195" +either = "1.10.0" diff --git a/src/context.rs b/src/context.rs index 419f5d7..8d375b6 100644 --- a/src/context.rs +++ b/src/context.rs @@ -1,4 +1,107 @@ -use std::path::{Path, MAIN_SEPARATOR_STR}; +use std::path::Path; + +use tera::{Map, Value}; + +fn inner_merge<'a>(a: &mut Map, b: &'a Value) -> Option { + match b { + Value::Object(o) => { + let mut map = Map::new(); + for (key, entry) in o.iter() { + let mut child_map = if a.contains_key(key) { + a[key] + .as_object() + .map(|m| m.to_owned()) + .unwrap_or(Map::new()) + } else { + Map::new() + }; + + if let Some(value) = inner_merge(&mut child_map, entry) { + child_map.insert(key.into(), value); + } + + map.extend(child_map); + } + + Some(map.into()) + } + value => Some(value.to_owned()), + } +} + +trait Merge { + fn merge(&mut self, other: Self); +} + +impl Merge for tera::Context { + fn merge(&mut self, other: Self) { + let mut json = self.clone().into_json(); + let map = json.as_object_mut().unwrap(); + + if let Some(value) = inner_merge(map, &other.into_json()) { + if let Ok(new_map) = tera::Context::from_value(value) { + self.extend(new_map) + } + } + } +} + +trait Head: Iterator { + fn head(self) -> Option<(Self::Item, Self)> + where + Self: Sized; +} + +impl Head for I { + fn head(mut self) -> Option<(Self::Item, Self)> { + match self.next() { + Some(x) => Some((x, self)), + None => None, + } + } +} + +#[derive(Debug)] +struct MapFold { + iter: I, + f: F, + accum: V, +} + +impl MapFold { + pub fn new(iter: I, init: V, f: F) -> MapFold { + Self { + iter, + f, + accum: init, + } + } +} + +impl V, V: Clone> Iterator for MapFold { + type Item = V; + + fn next(&mut self) -> Option { + self.accum = (self.f)(&self.accum, &self.iter.next()?); + Some(self.accum.clone()) + } +} + +trait MapFoldExt { + type Item; + + fn map_fold(mut self, init: B, f: F) -> MapFold + where + Self: Sized, + F: FnMut(&B, &Self::Item) -> B, + { + MapFold::new(self, init, f) + } +} + +impl MapFoldExt for I { + type Item = I::Item; +} #[derive(Debug)] pub(crate) struct Context { @@ -12,28 +115,67 @@ impl Context { } } - pub fn to_inner(&self) -> &tera::Context { - &self.inner + pub fn to_inner(&mut self) -> &mut tera::Context { + &mut self.inner } - pub fn normalize_path>(path: &P) -> String { - path.as_ref() + fn path_to_string>(path: &P) -> String { + path.as_ref().to_string_lossy().to_string() + } + + fn create_path>(path: &P, value: &Value) -> Option { + let path = path.as_ref(); + let (head, tail) = path.components().head()?; + + let mut map = Map::new(); + + if tail.clone().count() > 0 { + let child = Self::create_path(&tail, value)?; + map.insert(Self::path_to_string(&head), child); + } else { + let key = Self::path_to_string(&path.with_extension("").file_name()?); + map.insert(key, value.to_owned()); + } + + Some(map.into()) + } + + pub fn insert>(&mut self, path: &P, value: &Value) { + let path = path.as_ref(); + let path = if path .with_extension("") - .to_string_lossy() - .trim() - .split(MAIN_SEPARATOR_STR) - .fold(String::new(), |a, b| format!("{a}.{b}")) - .trim_matches('.') - .to_string() + .file_name() + .map_or(false, |f| f.to_os_string() == "index") + { + path.parent() + } else { + Some(path) + }; + + if let Some(v) = Self::create_path(&path.unwrap(), value) { + if let Ok(ctx) = tera::Context::from_value(v) { + self.inner.merge(ctx) + } + } } - pub fn insert>(&mut self, path: &P, value: &tera::Value) { - self.inner - .insert(Self::normalize_path(path).trim_start_matches('.'), &value); - } - - pub fn get>(&self, path: &P) -> Option<&tera::Value> { - self.inner.get(&Self::normalize_path(path)) + pub fn get>(&self, path: &P) -> Option<&Value> { + None } } +#[cfg(test)] +mod tests { + use std::path::Path; + + use super::Context; + + #[test] + fn whatever() { + let path = "this/is/a/test.html"; + let mut context = Context::new(); + println!("{context:?}"); + context.insert(&Path::new(&path), &":3".into()); + println!("{context:?}"); + } +} diff --git a/src/main.rs b/src/main.rs index 2e3db55..86a1291 100644 --- a/src/main.rs +++ b/src/main.rs @@ -72,6 +72,7 @@ fn context_from_meta_files<'a, T: AsRef>( let mut context = Context::new(); for path in files { + //println!("{path:?}"); let mut buf = Vec::new(); let mut file = File::open(path).map(BufReader::new)?; @@ -154,6 +155,8 @@ fn main() -> Result<(), Box> { } } + //println!("{context:?}"); + let mut tera = tera::Tera::default(); let mut html = TeraParser::new(&mut tera, TeraParserOptions::default()); html.add_context(context.to_inner());