1use std::sync::{Arc, RwLock};
2
3#[derive(Clone)]
4pub struct Template {
5 template_dir: String,
6 tera: Arc<RwLock<tera::Tera>>,
7}
8
9impl Template {
10 #[must_use]
11 pub fn new(template_dir: &str) -> Self {
12 let path = format!("{template_dir}/**/*");
13 let tera = match tera::Tera::new(&path) {
14 Ok(tera) => tera,
15 Err(err) => panic!("Parsing error(s): {err}"),
16 };
17
18 Self {
19 tera: Arc::new(RwLock::new(tera)),
20 template_dir: template_dir.to_string(),
21 }
22 }
23
24 pub fn render(&self, template: &str, context: &tera::Context) -> tera::Result<String> {
25 let tera = self.tera.read().unwrap();
26
27 tera.render(template, context)
28 }
29
30 #[cfg(debug_assertions)]
31 pub fn watch(self) {
32 use notify::Watcher;
33
34 let mut watcher = notify::recommended_watcher(move |res| match res {
35 Ok(event) => {
36 log::info!("reloading templates: {event:?}");
37
38 let mut tera = self.tera.write().unwrap();
39
40 match tera.full_reload() {
41 Ok(_) => log::info!("templates reloaded"),
42 Err(e) => log::error!("failed to reload templates: {e}"),
43 }
44 }
45 Err(e) => log::warn!("watch error: {e:?}"),
46 })
47 .unwrap();
48
49 log::debug!("watching {} for changes", self.template_dir);
50
51 watcher
52 .watch(
53 &std::path::PathBuf::from(&self.template_dir),
54 notify::RecursiveMode::Recursive,
55 )
56 .unwrap();
57 }
58
59 pub fn register_function<F: tera::Function + 'static>(&mut self, name: &str, function: F) {
60 let mut tera = self.tera.write().unwrap();
61
62 tera.register_function(name, function);
63 }
64
65 pub fn register_filter<F: tera::Filter + 'static>(&mut self, name: &str, filter: F) {
66 let mut tera = self.tera.write().unwrap();
67
68 tera.register_filter(name, filter);
69 }
70
71 pub fn register_tester<T: tera::Test + 'static>(&mut self, name: &str, tester: T) {
72 let mut tera = self.tera.write().unwrap();
73
74 tera.register_tester(name, tester);
75 }
76
77 #[cfg(not(debug_assertions))]
78 pub fn watch(self) {}
79}