You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
snekdown/src/references/templates.rs

364 lines
11 KiB
Rust

/*
* Snekdown - Custom Markdown flavour and parser
* Copyright (C) 2021 Trivernis
* See LICENSE for more information.
*/
use crate::elements::{Block, Element, Inline, Line, ListItem};
use std::collections::HashMap;
use std::sync::{Arc, RwLock};
pub trait FreezeVariables {
fn freeze_variables(&mut self) -> Option<Arc<RwLock<TemplateVariable>>>;
}
pub trait GetTemplateVariables {
fn get_template_variables(&self) -> Vec<Arc<RwLock<TemplateVariable>>>;
}
#[derive(Clone, Debug)]
pub struct Template {
pub(crate) text: Vec<Element>,
pub(crate) variables: HashMap<String, Arc<RwLock<TemplateVariable>>>,
}
#[derive(Clone, Debug)]
pub struct TemplateVariable {
pub(crate) prefix: String,
pub(crate) name: String,
pub(crate) suffix: String,
pub(crate) value: Option<Element>,
}
impl Template {
pub fn render(&self, replacements: HashMap<String, Element>) -> Vec<Element> {
replacements.iter().for_each(|(k, r)| {
if let Some(v) = self.variables.get(k) {
v.write().unwrap().set_value(r.clone())
}
});
let elements = self
.text
.iter()
.map(|e| {
let mut e = e.clone();
if let Some(template) = e.freeze_variables() {
Element::Inline(Box::new(Inline::TemplateVar(template)))
} else {
e
}
})
.collect();
self.variables
.iter()
.for_each(|(_, v)| v.write().unwrap().reset());
elements
}
}
impl TemplateVariable {
pub fn set_value(&mut self, value: Element) {
self.value = Some(value)
}
pub fn reset(&mut self) {
self.value = None
}
}
impl GetTemplateVariables for Inline {
fn get_template_variables(&self) -> Vec<Arc<RwLock<TemplateVariable>>> {
match self {
Inline::TemplateVar(temp) => vec![Arc::clone(temp)],
Inline::Colored(col) => col.value.get_template_variables(),
Inline::Superscript(sup) => sup
.value
.iter()
.map(|e| e.get_template_variables())
.flatten()
.collect(),
Inline::Striked(striked) => striked
.value
.iter()
.map(|e| e.get_template_variables())
.flatten()
.collect(),
Inline::Underlined(under) => under
.value
.iter()
.map(|e| e.get_template_variables())
.flatten()
.collect(),
Inline::Italic(it) => it
.value
.iter()
.map(|e| e.get_template_variables())
.flatten()
.collect(),
Inline::Bold(bo) => bo
.value
.iter()
.map(|e| e.get_template_variables())
.flatten()
.collect(),
_ => Vec::new(),
}
}
}
impl GetTemplateVariables for Line {
fn get_template_variables(&self) -> Vec<Arc<RwLock<TemplateVariable>>> {
match self {
Line::Text(line) => line
.subtext
.iter()
.map(|s| s.get_template_variables())
.flatten()
.collect(),
Line::Centered(center) => center
.line
.subtext
.iter()
.map(|s| s.get_template_variables())
.flatten()
.collect(),
_ => Vec::new(),
}
}
}
impl GetTemplateVariables for Block {
fn get_template_variables(&self) -> Vec<Arc<RwLock<TemplateVariable>>> {
match self {
Block::Section(sec) => sec
.elements
.iter()
.map(|e| e.get_template_variables())
.flatten()
.collect(),
Block::Paragraph(par) => par
.elements
.iter()
.map(|l| l.get_template_variables())
.flatten()
.collect(),
Block::Quote(q) => q
.text
.iter()
.map(|t| {
t.subtext
.iter()
.map(|i| i.get_template_variables())
.flatten()
})
.flatten()
.collect(),
Block::List(list) => list
.items
.iter()
.map(|item| item.get_template_variables())
.flatten()
.collect(),
_ => Vec::new(),
}
}
}
impl GetTemplateVariables for Element {
fn get_template_variables(&self) -> Vec<Arc<RwLock<TemplateVariable>>> {
match self {
Element::Block(block) => block.get_template_variables(),
Element::Inline(inline) => inline.get_template_variables(),
Element::Line(line) => line.get_template_variables(),
}
}
}
impl FreezeVariables for Inline {
fn freeze_variables(&mut self) -> Option<Arc<RwLock<TemplateVariable>>> {
match self {
Inline::TemplateVar(temp) => {
let temp = temp.read().unwrap();
return Some(Arc::new(RwLock::new((*temp).clone())));
}
Inline::Colored(col) => {
if let Some(temp) = col.value.freeze_variables() {
col.value = Box::new(Inline::TemplateVar(temp))
}
}
Inline::Superscript(sup) => {
sup.value = sup
.value
.iter_mut()
.map(|e| {
if let Some(temp) = e.freeze_variables() {
Inline::TemplateVar(temp)
} else {
e.clone()
}
})
.collect();
}
Inline::Striked(striked) => {
striked.value = striked
.value
.iter_mut()
.map(|e| {
if let Some(temp) = e.freeze_variables() {
Inline::TemplateVar(temp)
} else {
e.clone()
}
})
.collect();
}
Inline::Underlined(under) => {
under.value = under
.value
.iter_mut()
.map(|e| {
if let Some(temp) = e.freeze_variables() {
Inline::TemplateVar(temp)
} else {
e.clone()
}
})
.collect();
}
Inline::Italic(it) => {
it.value = it
.value
.iter_mut()
.map(|e| {
if let Some(temp) = e.freeze_variables() {
Inline::TemplateVar(temp)
} else {
e.clone()
}
})
.collect();
}
Inline::Bold(bo) => {
bo.value = bo
.value
.iter_mut()
.map(|e| {
if let Some(temp) = e.freeze_variables() {
Inline::TemplateVar(temp)
} else {
e.clone()
}
})
.collect();
}
_ => {}
}
None
}
}
impl GetTemplateVariables for ListItem {
fn get_template_variables(&self) -> Vec<Arc<RwLock<TemplateVariable>>> {
let mut inner_vars: Vec<Arc<RwLock<TemplateVariable>>> = self
.children
.iter()
.map(|child| child.get_template_variables())
.flatten()
.collect();
inner_vars.append(&mut self.text.get_template_variables());
inner_vars
}
}
impl FreezeVariables for Line {
fn freeze_variables(&mut self) -> Option<Arc<RwLock<TemplateVariable>>> {
match self {
Line::Text(text) => {
text.subtext = text
.subtext
.iter_mut()
.map(|i| {
if let Some(t) = i.freeze_variables() {
Inline::TemplateVar(t)
} else {
(*i).clone()
}
})
.collect()
}
Line::Centered(center) => {
center.line.subtext = center
.line
.subtext
.iter_mut()
.map(|i| {
if let Some(t) = i.freeze_variables() {
Inline::TemplateVar(t)
} else {
(*i).clone()
}
})
.collect()
}
_ => {}
}
None
}
}
impl FreezeVariables for Block {
fn freeze_variables(&mut self) -> Option<Arc<RwLock<TemplateVariable>>> {
match self {
Block::Section(s) => s.elements.iter_mut().for_each(|b| {
b.freeze_variables();
}),
Block::Paragraph(p) => p.elements.iter_mut().for_each(|l| {
l.freeze_variables();
}),
Block::Quote(q) => q.text.iter_mut().for_each(|t| {
t.subtext = t
.subtext
.iter_mut()
.map(|i| {
if let Some(t) = i.freeze_variables() {
Inline::TemplateVar(t)
} else {
(*i).clone()
}
})
.collect()
}),
Block::List(list) => list.items.iter_mut().for_each(|item| {
item.freeze_variables();
}),
_ => {}
};
None
}
}
impl FreezeVariables for Element {
fn freeze_variables(&mut self) -> Option<Arc<RwLock<TemplateVariable>>> {
match self {
Element::Block(b) => b.freeze_variables(),
Element::Line(l) => l.freeze_variables(),
Element::Inline(i) => return i.freeze_variables(),
};
None
}
}
impl FreezeVariables for ListItem {
fn freeze_variables(&mut self) -> Option<Arc<RwLock<TemplateVariable>>> {
self.children.iter_mut().for_each(|child| {
child.freeze_variables();
});
self.text.freeze_variables();
None
}
}