1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
use crate::errors::{Error, Result};
use crate::parser::ast::MacroDefinition;
use crate::template::Template;
use crate::tera::Tera;
use std::collections::HashMap;
pub type MacroDefinitionMap = HashMap<String, MacroDefinition>;
pub type MacroNamespaceMap<'a> = HashMap<&'a str, (&'a str, &'a MacroDefinitionMap)>;
pub type MacroTemplateMap<'a> = HashMap<&'a str, MacroNamespaceMap<'a>>;
#[derive(Clone, Debug, Default)]
pub struct MacroCollection<'a> {
macros: MacroTemplateMap<'a>,
}
impl<'a> MacroCollection<'a> {
pub fn from_original_template(tpl: &'a Template, tera: &'a Tera) -> MacroCollection<'a> {
let mut macro_collection = MacroCollection { macros: MacroTemplateMap::new() };
macro_collection
.add_macros_from_template(tera, tpl)
.expect("Couldn't load macros from base template");
macro_collection
}
pub fn add_macros_from_template(
&mut self,
tera: &'a Tera,
template: &'a Template,
) -> Result<()> {
let template_name = &template.name[..];
if self.macros.contains_key(template_name) {
return Ok(());
}
let mut macro_namespace_map = MacroNamespaceMap::new();
if !template.macros.is_empty() {
macro_namespace_map.insert("self", (template_name, &template.macros));
}
for (filename, namespace) in &template.imported_macro_files {
let macro_tpl = tera.get_template(filename)?;
macro_namespace_map.insert(namespace, (filename, ¯o_tpl.macros));
self.add_macros_from_template(tera, macro_tpl)?;
for (namespace, m) in &self.macros[¯o_tpl.name.as_ref()].clone() {
if macro_namespace_map.contains_key(namespace) {
continue;
}
macro_namespace_map.insert(namespace, *m);
}
}
self.macros.insert(template_name, macro_namespace_map);
for parent in &template.parents {
let parent = &parent[..];
let parent_template = tera.get_template(parent)?;
self.add_macros_from_template(tera, parent_template)?;
for (namespace, m) in &self.macros[parent].clone() {
if self.macros[template_name].contains_key(namespace) {
continue;
}
self.macros.get_mut(template_name).unwrap().insert(namespace, *m);
}
}
Ok(())
}
pub fn lookup_macro(
&self,
template_name: &'a str,
macro_namespace: &'a str,
macro_name: &'a str,
) -> Result<(&'a str, &'a MacroDefinition)> {
let namespace = self
.macros
.get(template_name)
.and_then(|namespace_map| namespace_map.get(macro_namespace));
if let Some(n) = namespace {
let &(macro_template, macro_definition_map) = n;
if let Some(m) = macro_definition_map.get(macro_name).map(|md| (macro_template, md)) {
Ok(m)
} else {
Err(Error::msg(format!(
"Macro `{}::{}` not found in template `{}`",
macro_namespace, macro_name, template_name
)))
}
} else {
Err(Error::msg(format!(
"Macro namespace `{}` was not found in template `{}`. Have you maybe forgotten to import it, or misspelled it?",
macro_namespace, template_name
)))
}
}
}