|
|
|
@ -20,6 +20,7 @@ pub enum MetadataValue {
|
|
|
|
|
Float(f64),
|
|
|
|
|
Bool(bool),
|
|
|
|
|
Placeholder(Arc<Mutex<Placeholder>>),
|
|
|
|
|
Template(Template),
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#[derive(Clone, Debug)]
|
|
|
|
@ -161,6 +162,7 @@ pub enum Inline {
|
|
|
|
|
Emoji(Emoji),
|
|
|
|
|
Colored(Colored),
|
|
|
|
|
BibReference(Arc<Mutex<BibReference>>),
|
|
|
|
|
TemplateVar(Arc<Mutex<TemplateVariable>>),
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#[derive(Clone, Debug)]
|
|
|
|
@ -245,6 +247,20 @@ pub struct Colored {
|
|
|
|
|
pub(crate) color: String,
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#[derive(Clone, Debug)]
|
|
|
|
|
pub struct Template {
|
|
|
|
|
pub(crate) text: Vec<Element>,
|
|
|
|
|
pub(crate) variables: HashMap<String, Arc<Mutex<TemplateVariable>>>,
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#[derive(Clone, Debug)]
|
|
|
|
|
pub struct TemplateVariable {
|
|
|
|
|
pub(crate) prefix: String,
|
|
|
|
|
pub(crate) name: String,
|
|
|
|
|
pub(crate) suffix: String,
|
|
|
|
|
pub(crate) value: Option<Element>,
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// implementations
|
|
|
|
|
|
|
|
|
|
impl Document {
|
|
|
|
@ -592,3 +608,208 @@ impl Metadata for InlineMetadata {
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
impl Element {
|
|
|
|
|
pub fn get_template_variables(&self) -> Vec<Arc<Mutex<TemplateVariable>>> {
|
|
|
|
|
match self {
|
|
|
|
|
Element::Block(block) => block
|
|
|
|
|
.get_template_variables()
|
|
|
|
|
.iter()
|
|
|
|
|
.filter_map(|e| e.clone())
|
|
|
|
|
.collect(),
|
|
|
|
|
Element::Inline(inline) => vec![inline.get_template_variable()]
|
|
|
|
|
.iter()
|
|
|
|
|
.filter_map(|e| e.clone())
|
|
|
|
|
.collect(),
|
|
|
|
|
Element::Line(line) => line
|
|
|
|
|
.get_template_variables()
|
|
|
|
|
.iter()
|
|
|
|
|
.filter_map(|e| e.clone())
|
|
|
|
|
.collect(),
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
pub fn freeze_variables(&mut self) -> Option<Arc<Mutex<TemplateVariable>>> {
|
|
|
|
|
match self {
|
|
|
|
|
Element::Block(b) => b.freeze_template_variables(),
|
|
|
|
|
Element::Line(l) => l.freeze_variables(),
|
|
|
|
|
Element::Inline(i) => return i.freeze_variables(),
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
None
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
impl Block {
|
|
|
|
|
pub fn get_template_variables(&self) -> Vec<Option<Arc<Mutex<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_variable()))
|
|
|
|
|
.flatten()
|
|
|
|
|
.collect(),
|
|
|
|
|
_ => Vec::new(),
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
pub fn freeze_template_variables(&mut self) {
|
|
|
|
|
match self {
|
|
|
|
|
Block::Section(s) => s
|
|
|
|
|
.elements
|
|
|
|
|
.iter_mut()
|
|
|
|
|
.for_each(|b| b.freeze_template_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()
|
|
|
|
|
}),
|
|
|
|
|
_ => {}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
impl Line {
|
|
|
|
|
pub fn get_template_variables(&self) -> Vec<Option<Arc<Mutex<TemplateVariable>>>> {
|
|
|
|
|
match self {
|
|
|
|
|
Line::Text(line) => line
|
|
|
|
|
.subtext
|
|
|
|
|
.iter()
|
|
|
|
|
.map(|s| s.get_template_variable())
|
|
|
|
|
.collect(),
|
|
|
|
|
_ => Vec::new(),
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
pub fn freeze_variables(&mut self) {
|
|
|
|
|
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()
|
|
|
|
|
}
|
|
|
|
|
_ => {}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
impl Inline {
|
|
|
|
|
pub fn get_template_variable(&self) -> Option<Arc<Mutex<TemplateVariable>>> {
|
|
|
|
|
match self {
|
|
|
|
|
Inline::TemplateVar(temp) => Some(Arc::clone(temp)),
|
|
|
|
|
Inline::Colored(col) => col.value.get_template_variable(),
|
|
|
|
|
Inline::Superscript(sup) => sup.value.get_template_variable(),
|
|
|
|
|
Inline::Striked(striked) => striked.value.get_template_variable(),
|
|
|
|
|
Inline::Underlined(under) => under.value.get_template_variable(),
|
|
|
|
|
Inline::Italic(it) => it.value.get_template_variable(),
|
|
|
|
|
Inline::Bold(bo) => bo.value.get_template_variable(),
|
|
|
|
|
_ => None,
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
pub fn freeze_variables(&mut self) -> Option<Arc<Mutex<TemplateVariable>>> {
|
|
|
|
|
match self {
|
|
|
|
|
Inline::TemplateVar(temp) => {
|
|
|
|
|
let temp = temp.lock().unwrap();
|
|
|
|
|
return Some(Arc::new(Mutex::new((*temp).clone())));
|
|
|
|
|
}
|
|
|
|
|
Inline::Colored(col) => {
|
|
|
|
|
if let Some(temp) = col.value.freeze_variables() {
|
|
|
|
|
col.value = Box::new(Inline::TemplateVar(temp))
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
Inline::Superscript(sup) => {
|
|
|
|
|
if let Some(temp) = sup.value.freeze_variables() {
|
|
|
|
|
sup.value = Box::new(Inline::TemplateVar(temp))
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
Inline::Striked(striked) => {
|
|
|
|
|
if let Some(temp) = striked.value.freeze_variables() {
|
|
|
|
|
striked.value = Box::new(Inline::TemplateVar(temp))
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
Inline::Underlined(under) => {
|
|
|
|
|
if let Some(temp) = under.value.freeze_variables() {
|
|
|
|
|
under.value = Box::new(Inline::TemplateVar(temp))
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
Inline::Italic(it) => {
|
|
|
|
|
if let Some(temp) = it.value.freeze_variables() {
|
|
|
|
|
it.value = Box::new(Inline::TemplateVar(temp))
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
Inline::Bold(bo) => {
|
|
|
|
|
if let Some(temp) = bo.value.freeze_variables() {
|
|
|
|
|
bo.value = Box::new(Inline::TemplateVar(temp))
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
_ => {}
|
|
|
|
|
}
|
|
|
|
|
None
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
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.lock().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.lock().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
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|