improve context storage
This commit is contained in:
parent
a5889e0368
commit
0fc188dbb8
13
Cargo.lock
generated
13
Cargo.lock
generated
|
@ -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",
|
||||
|
|
|
@ -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"
|
||||
|
||||
|
|
178
src/context.rs
178
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<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:?}");
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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());
|
||||
|
|
Loading…
Reference in a new issue