You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

115 lines
4.2KB

  1. use std::collections::HashMap;
  2. use tera::{Tera, Context};
  3. use errors::Result;
  4. static DEFAULT_TPL: &str = include_str!("default_tpl.html");
  5. macro_rules! render_default_tpl {
  6. ($filename: expr, $url: expr) => {
  7. {
  8. let mut context = Context::new();
  9. context.insert("filename", $filename);
  10. context.insert("url", $url);
  11. Tera::one_off(DEFAULT_TPL, &context, true).map_err(|e| e.into())
  12. }
  13. };
  14. }
  15. /// Renders the given template with the given context, but also ensures that, if the default file
  16. /// is not found, it will look up for the equivalent template for the current theme if there is one.
  17. /// Lastly, if it's a default template (index, section or page), it will just return an empty string
  18. /// to avoid an error if there isn't a template with that name
  19. pub fn render_template(name: &str, tera: &Tera, context: &Context, theme: &Option<String>) -> Result<String> {
  20. if tera.templates.contains_key(name) {
  21. return tera
  22. .render(name, context)
  23. .map_err(|e| e.into());
  24. }
  25. if let Some(ref t) = *theme {
  26. return tera
  27. .render(&format!("{}/templates/{}", t, name), context)
  28. .map_err(|e| e.into());
  29. }
  30. // maybe it's a default one?
  31. match name {
  32. "index.html" | "section.html" => {
  33. render_default_tpl!(name, "https://www.getzola.org/documentation/templates/pages-sections/#section-variables")
  34. }
  35. "page.html" => {
  36. render_default_tpl!(name, "https://www.getzola.org/documentation/templates/pages-sections/#page-variables")
  37. }
  38. "single.html" | "list.html" => {
  39. render_default_tpl!(name, "https://www.getzola.org/documentation/templates/taxonomies/")
  40. }
  41. _ => bail!("Tried to render `{}` but the template wasn't found", name)
  42. }
  43. }
  44. /// Rewrites the path from extend/macros of the theme used to ensure
  45. /// that they will point to the right place (theme/templates/...)
  46. /// Include is NOT supported as it would be a pain to add and using blocks
  47. /// or macros is always better anyway for themes
  48. /// This will also rename the shortcodes to NOT have the themes in the path
  49. /// so themes shortcodes can be used.
  50. pub fn rewrite_theme_paths(tera: &mut Tera, theme: &str) {
  51. let mut shortcodes_to_move = vec![];
  52. let mut templates = HashMap::new();
  53. let old_templates = ::std::mem::replace(&mut tera.templates, HashMap::new());
  54. // We want to match the paths in the templates to the new names
  55. for (key, mut tpl) in old_templates{
  56. tpl.name = format!("{}/templates/{}", theme, tpl.name);
  57. // First the parent if there is none
  58. if let Some(ref p) = tpl.parent.clone() {
  59. tpl.parent = Some(format!("{}/templates/{}", theme, p));
  60. }
  61. // Next the macros import
  62. let mut updated = vec![];
  63. for &(ref filename, ref namespace) in &tpl.imported_macro_files {
  64. updated.push((format!("{}/templates/{}", theme, filename), namespace.to_string()));
  65. }
  66. tpl.imported_macro_files = updated;
  67. if tpl.name.starts_with(&format!("{}/templates/shortcodes", theme)) {
  68. let new_name = tpl.name.replace(&format!("{}/templates/", theme), "");
  69. shortcodes_to_move.push((key, new_name.clone()));
  70. tpl.name = new_name;
  71. }
  72. templates.insert(tpl.name.clone(), tpl);
  73. }
  74. tera.templates = templates;
  75. // and then replace shortcodes in the Tera instance using the new names
  76. for (old_name, new_name) in shortcodes_to_move {
  77. let tpl = tera.templates.remove(&old_name).unwrap();
  78. tera.templates.insert(new_name, tpl);
  79. }
  80. }
  81. #[cfg(test)]
  82. mod tests {
  83. use tera::Tera;
  84. use super::rewrite_theme_paths;
  85. #[test]
  86. fn can_rewrite_all_paths_of_theme() {
  87. let mut tera = Tera::parse("test-templates/*.html").unwrap();
  88. rewrite_theme_paths(&mut tera, "hyde");
  89. // special case to make the test work: we also rename the files to
  90. // match the imports
  91. for (key, val) in tera.templates.clone() {
  92. tera.templates.insert(format!("hyde/templates/{}", key), val.clone());
  93. }
  94. tera.build_inheritance_chains().unwrap();
  95. }
  96. }