improve context storage

This commit is contained in:
KitsuneCafe 2024-02-10 23:38:29 -05:00
parent a5889e0368
commit 0fc188dbb8
4 changed files with 174 additions and 21 deletions

13
Cargo.lock generated
View file

@ -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",

View file

@ -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"

View file

@ -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<String, Value>, b: &'a Value) -> Option<Value> {
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<I: Iterator> 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<I, F, V> {
iter: I,
f: F,
accum: V,
}
impl<I, F, V> MapFold<I, F, V> {
pub fn new(iter: I, init: V, f: F) -> MapFold<I, F, V> {
Self {
iter,
f,
accum: init,
}
}
}
impl<I: Iterator, F: FnMut(&V, &I::Item) -> V, V: Clone> Iterator for MapFold<I, F, V> {
type Item = V;
fn next(&mut self) -> Option<Self::Item> {
self.accum = (self.f)(&self.accum, &self.iter.next()?);
Some(self.accum.clone())
}
}
trait MapFoldExt {
type Item;
fn map_fold<B, F>(mut self, init: B, f: F) -> MapFold<Self, F, B>
where
Self: Sized,
F: FnMut(&B, &Self::Item) -> B,
{
MapFold::new(self, init, f)
}
}
impl<I: Iterator> 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<P: AsRef<Path>>(path: &P) -> String {
path.as_ref()
fn path_to_string<P: AsRef<Path>>(path: &P) -> String {
path.as_ref().to_string_lossy().to_string()
}
fn create_path<P: AsRef<Path>>(path: &P, value: &Value) -> Option<Value> {
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<P: AsRef<Path>>(&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<P: AsRef<Path>>(&mut self, path: &P, value: &tera::Value) {
self.inner
.insert(Self::normalize_path(path).trim_start_matches('.'), &value);
}
pub fn get<P: AsRef<Path>>(&self, path: &P) -> Option<&tera::Value> {
self.inner.get(&Self::normalize_path(path))
pub fn get<P: AsRef<Path>>(&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:?}");
}
}

View file

@ -72,6 +72,7 @@ fn context_from_meta_files<'a, T: AsRef<Path>>(
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<dyn std::error::Error>> {
}
}
//println!("{context:?}");
let mut tera = tera::Tera::default();
let mut html = TeraParser::new(&mut tera, TeraParserOptions::default());
html.add_context(context.to_inner());