summaryrefslogtreecommitdiffstats
path: root/vendor/handlebars/src/registry.rs
diff options
context:
space:
mode:
Diffstat (limited to 'vendor/handlebars/src/registry.rs')
-rw-r--r--vendor/handlebars/src/registry.rs272
1 files changed, 215 insertions, 57 deletions
diff --git a/vendor/handlebars/src/registry.rs b/vendor/handlebars/src/registry.rs
index e7f5f1cfd..438f8573c 100644
--- a/vendor/handlebars/src/registry.rs
+++ b/vendor/handlebars/src/registry.rs
@@ -17,12 +17,10 @@ use crate::output::{Output, StringOutput, WriteOutput};
use crate::render::{RenderContext, Renderable};
use crate::sources::{FileSource, Source};
use crate::support::str::{self, StringWriter};
-use crate::template::Template;
+use crate::template::{Template, TemplateOptions};
#[cfg(feature = "dir_source")]
-use std::path;
-#[cfg(feature = "dir_source")]
-use walkdir::{DirEntry, WalkDir};
+use walkdir::WalkDir;
#[cfg(feature = "script_helper")]
use rhai::Engine;
@@ -30,6 +28,9 @@ use rhai::Engine;
#[cfg(feature = "script_helper")]
use crate::helpers::scripting::ScriptHelper;
+#[cfg(feature = "rust-embed")]
+use rust_embed::RustEmbed;
+
/// This type represents an *escape fn*, that is a function whose purpose it is
/// to escape potentially problematic characters in a string.
///
@@ -62,6 +63,7 @@ pub struct Registry<'reg> {
escape_fn: EscapeFn,
strict_mode: bool,
dev_mode: bool,
+ prevent_indent: bool,
#[cfg(feature = "script_helper")]
pub(crate) engine: Arc<Engine>,
@@ -90,21 +92,6 @@ impl<'reg> Default for Registry<'reg> {
}
}
-#[cfg(feature = "dir_source")]
-fn filter_file(entry: &DirEntry, suffix: &str) -> bool {
- let path = entry.path();
-
- // ignore hidden files, emacs buffers and files with wrong suffix
- !path.is_file()
- || path
- .file_name()
- .map(|s| {
- let ds = s.to_string_lossy();
- ds.starts_with('.') || ds.starts_with('#') || !ds.ends_with(suffix)
- })
- .unwrap_or(true)
-}
-
#[cfg(feature = "script_helper")]
fn rhai_engine() -> Engine {
Engine::new()
@@ -120,6 +107,7 @@ impl<'reg> Registry<'reg> {
escape_fn: Arc::new(html_escape),
strict_mode: false,
dev_mode: false,
+ prevent_indent: false,
#[cfg(feature = "script_helper")]
engine: Arc::new(rhai_engine()),
#[cfg(feature = "script_helper")]
@@ -178,7 +166,7 @@ impl<'reg> Registry<'reg> {
/// Return dev mode state, default is false
///
/// With dev mode turned on, handlebars enables a set of development
- /// firendly features, that may affect its performance.
+ /// friendly features, that may affect its performance.
pub fn dev_mode(&self) -> bool {
self.dev_mode
}
@@ -186,9 +174,30 @@ impl<'reg> Registry<'reg> {
/// Enable or disable dev mode
///
/// With dev mode turned on, handlebars enables a set of development
- /// firendly features, that may affect its performance.
+ /// friendly features, that may affect its performance.
+ ///
+ /// **Note that you have to enable dev mode before adding templates to
+ /// the registry**. Otherwise it won't take effect at all.
pub fn set_dev_mode(&mut self, enabled: bool) {
self.dev_mode = enabled;
+
+ // clear template source when disabling dev mode
+ if !enabled {
+ self.template_sources.clear();
+ }
+ }
+
+ /// Enable or disable indent for partial include tag `{{>}}`
+ ///
+ /// By default handlebars keeps indent whitespaces for partial
+ /// include tag, to change this behaviour, set this toggle to `true`.
+ pub fn set_prevent_indent(&mut self, enable: bool) {
+ self.prevent_indent = enable;
+ }
+
+ /// Return state for `prevent_indent` option, default to `false`.
+ pub fn prevent_indent(&self) -> bool {
+ self.prevent_indent
}
/// Register a `Template`
@@ -196,6 +205,9 @@ impl<'reg> Registry<'reg> {
/// This is infallible since the template has already been parsed and
/// insert cannot fail. If there is an existing template with this name it
/// will be overwritten.
+ ///
+ /// Dev mode doesn't apply for pre-compiled template because it's lifecycle
+ /// is not managed by the registry.
pub fn register_template(&mut self, name: &str, tpl: Template) {
self.templates.insert(name.to_string(), tpl);
}
@@ -211,7 +223,13 @@ impl<'reg> Registry<'reg> {
where
S: AsRef<str>,
{
- let template = Template::compile_with_name(tpl_str, name.to_owned())?;
+ let template = Template::compile2(
+ tpl_str.as_ref(),
+ TemplateOptions {
+ name: Some(name.to_owned()),
+ prevent_indent: self.prevent_indent,
+ },
+ )?;
self.register_template(name, template);
Ok(())
}
@@ -227,7 +245,10 @@ impl<'reg> Registry<'reg> {
self.register_template_string(name, partial_str)
}
- /// Register a template from a path
+ /// Register a template from a path on file system
+ ///
+ /// If dev mode is enabled, the registry will keep reading the template file
+ /// from file system everytime it's visited.
pub fn register_template_file<P>(
&mut self,
name: &str,
@@ -262,11 +283,14 @@ impl<'reg> Registry<'reg> {
///
/// This method is not available by default.
/// You will need to enable the `dir_source` feature to use it.
+ ///
+ /// When dev_mode enabled, like `register_template_file`, templates is reloaded
+ /// from file system everytime it's visied.
#[cfg(feature = "dir_source")]
#[cfg_attr(docsrs, doc(cfg(feature = "dir_source")))]
pub fn register_templates_directory<P>(
&mut self,
- tpl_extension: &'static str,
+ tpl_extension: &str,
dir_path: P,
) -> Result<(), TemplateError>
where
@@ -274,40 +298,88 @@ impl<'reg> Registry<'reg> {
{
let dir_path = dir_path.as_ref();
- let prefix_len = if dir_path
- .to_string_lossy()
- .ends_with(|c| c == '\\' || c == '/')
- // `/` will work on windows too so we still need to check
- {
- dir_path.to_string_lossy().len()
- } else {
- dir_path.to_string_lossy().len() + 1
- };
+ // Allowing dots at the beginning as to not break old
+ // applications.
+ let tpl_extension = tpl_extension.strip_prefix('.').unwrap_or(tpl_extension);
let walker = WalkDir::new(dir_path);
let dir_iter = walker
.min_depth(1)
.into_iter()
- .filter(|e| e.is_ok() && !filter_file(e.as_ref().unwrap(), tpl_extension));
+ .filter_map(|e| e.ok().map(|e| e.into_path()))
+ // Checks if extension matches
+ .filter(|tpl_path| {
+ tpl_path
+ .extension()
+ .map(|extension| extension == tpl_extension)
+ .unwrap_or(false)
+ })
+ // Rejects any hidden or temporary files.
+ .filter(|tpl_path| {
+ tpl_path
+ .file_stem()
+ .map(|stem| stem.to_string_lossy())
+ .map(|stem| !(stem.starts_with('.') || stem.starts_with('#')))
+ .unwrap_or(false)
+ })
+ .filter_map(|tpl_path| {
+ tpl_path
+ .strip_prefix(dir_path)
+ .ok()
+ .map(|tpl_canonical_name| {
+ tpl_canonical_name
+ .with_extension("")
+ .components()
+ .map(|component| component.as_os_str().to_string_lossy())
+ .collect::<Vec<_>>()
+ .join("/")
+ })
+ .map(|tpl_canonical_name| (tpl_canonical_name, tpl_path))
+ });
+
+ for (tpl_canonical_name, tpl_path) in dir_iter {
+ self.register_template_file(&tpl_canonical_name, &tpl_path)?;
+ }
- for entry in dir_iter {
- let entry = entry?;
+ Ok(())
+ }
- let tpl_path = entry.path();
- let tpl_file_path = entry.path().to_string_lossy();
+ /// Register templates using a
+ /// [RustEmbed](https://github.com/pyros2097/rust-embed) type
+ ///
+ /// File names from embed struct are used as template name.
+ ///
+ /// ```skip
+ /// #[derive(RustEmbed)]
+ /// #[folder = "templates"]
+ /// struct Assets;
+ ///
+ /// let mut hbs = Handlebars::new();
+ /// hbs.register_embed_templates::<Assets>();
+ /// ```
+ ///
+ #[cfg(feature = "rust-embed")]
+ #[cfg_attr(docsrs, doc(cfg(feature = "rust-embed")))]
+ pub fn register_embed_templates<E>(&mut self) -> Result<(), TemplateError>
+ where
+ E: RustEmbed,
+ {
+ for item in E::iter() {
+ let file_name = item.as_ref();
+ if let Some(file) = E::get(file_name) {
+ let data = file.data;
- let tpl_name = &tpl_file_path[prefix_len..tpl_file_path.len() - tpl_extension.len()];
- // replace platform path separator with our internal one
- let tpl_canonical_name = tpl_name.replace(path::MAIN_SEPARATOR, "/");
- self.register_template_file(&tpl_canonical_name, &tpl_path)?;
+ let tpl_content = String::from_utf8_lossy(data.as_ref());
+ self.register_template_string(file_name, tpl_content)?;
+ }
}
-
Ok(())
}
/// Remove a template from the registry
pub fn unregister_template(&mut self, name: &str) {
self.templates.remove(name);
+ self.template_sources.remove(name);
}
/// Register a helper
@@ -335,7 +407,6 @@ impl<'reg> Registry<'reg> {
/// (value * 100).to_string() + label
/// ```
///
- ///
#[cfg(feature = "script_helper")]
#[cfg_attr(docsrs, doc(cfg(feature = "script_helper")))]
pub fn register_script_helper(&mut self, name: &str, script: &str) -> Result<(), ScriptError> {
@@ -347,6 +418,9 @@ impl<'reg> Registry<'reg> {
}
/// Register a [rhai](https://docs.rs/rhai/) script from file
+ ///
+ /// When dev mode is enable, script file is reloaded from original file
+ /// everytime it is called.
#[cfg(feature = "script_helper")]
#[cfg_attr(docsrs, doc(cfg(feature = "script_helper")))]
pub fn register_script_helper_file<P>(
@@ -365,6 +439,22 @@ impl<'reg> Registry<'reg> {
self.register_script_helper(name, &script)
}
+ /// Borrow a read-only reference to current rhai engine
+ #[cfg(feature = "script_helper")]
+ #[cfg_attr(docsrs, doc(cfg(feature = "script_helper")))]
+ pub fn engine(&self) -> &Engine {
+ self.engine.as_ref()
+ }
+
+ /// Set a custom rhai engine for the registry.
+ ///
+ /// *Note that* you need to set custom engine before adding scripts.
+ #[cfg(feature = "script_helper")]
+ #[cfg_attr(docsrs, doc(cfg(feature = "script_helper")))]
+ pub fn set_engine(&mut self, engine: Engine) {
+ self.engine = Arc::new(engine);
+ }
+
/// Register a decorator
pub fn register_decorator(
&mut self,
@@ -389,7 +479,7 @@ impl<'reg> Registry<'reg> {
/// Get a reference to the current *escape fn*.
pub fn get_escape_fn(&self) -> &dyn Fn(&str) -> String {
- &*self.escape_fn
+ self.escape_fn.as_ref()
}
/// Return `true` if a template is registered for the given name
@@ -411,7 +501,15 @@ impl<'reg> Registry<'reg> {
let r = source
.load()
.map_err(|e| TemplateError::from((e, name.to_owned())))
- .and_then(|tpl_str| Template::compile_with_name(tpl_str, name.to_owned()))
+ .and_then(|tpl_str| {
+ Template::compile2(
+ tpl_str.as_ref(),
+ TemplateOptions {
+ name: Some(name.to_owned()),
+ prevent_indent: self.prevent_indent,
+ },
+ )
+ })
.map(Cow::Owned)
.map_err(RenderError::from);
Some(r)
@@ -433,6 +531,7 @@ impl<'reg> Registry<'reg> {
}
/// Return a registered helper
+ #[inline]
pub(crate) fn get_or_load_helper(
&'reg self,
name: &str,
@@ -460,6 +559,7 @@ impl<'reg> Registry<'reg> {
}
/// Return a registered decorator
+ #[inline]
pub(crate) fn get_decorator(
&self,
name: &str,
@@ -468,6 +568,10 @@ impl<'reg> Registry<'reg> {
}
/// Return all templates registered
+ ///
+ /// **Note that** in dev mode, the template returned from this method may
+ /// not reflect its latest state. This method doesn't try to reload templates
+ /// from its source.
pub fn get_templates(&self) -> &HashMap<String, Template> {
&self.templates
}
@@ -475,6 +579,7 @@ impl<'reg> Registry<'reg> {
/// Unregister all templates
pub fn clear_templates(&mut self) {
self.templates.clear();
+ self.template_sources.clear();
}
#[inline]
@@ -489,7 +594,7 @@ impl<'reg> Registry<'reg> {
{
self.get_or_load_template(name).and_then(|t| {
let mut render_context = RenderContext::new(t.name.as_ref());
- t.render(self, &ctx, &mut render_context, output)
+ t.render(self, ctx, &mut render_context, output)
})
}
@@ -516,7 +621,7 @@ impl<'reg> Registry<'reg> {
output.into_string().map_err(RenderError::from)
}
- /// Render a registered template and write some data to the `std::io::Write`
+ /// Render a registered template and write data to the `std::io::Write`
pub fn render_to_write<T, W>(&self, name: &str, data: &T, writer: W) -> Result<(), RenderError>
where
T: Serialize,
@@ -527,6 +632,21 @@ impl<'reg> Registry<'reg> {
self.render_to_output(name, &ctx, &mut output)
}
+ /// Render a registered template using reusable `Context`, and write data to
+ /// the `std::io::Write`
+ pub fn render_with_context_to_write<W>(
+ &self,
+ name: &str,
+ ctx: &Context,
+ writer: W,
+ ) -> Result<(), RenderError>
+ where
+ W: Write,
+ {
+ let mut output = WriteOutput::new(writer);
+ self.render_to_output(name, ctx, &mut output)
+ }
+
/// Render a template string using current registry without registering it
pub fn render_template<T>(&self, template_string: &str, data: &T) -> Result<String, RenderError>
where
@@ -537,23 +657,52 @@ impl<'reg> Registry<'reg> {
Ok(writer.into_string())
}
- /// Render a template string using reused context data
+ /// Render a template string using reusable context data
pub fn render_template_with_context(
&self,
template_string: &str,
ctx: &Context,
) -> Result<String, RenderError> {
- let tpl = Template::compile(template_string)?;
+ let tpl = Template::compile2(
+ template_string,
+ TemplateOptions {
+ prevent_indent: self.prevent_indent,
+ ..Default::default()
+ },
+ )?;
let mut out = StringOutput::new();
{
let mut render_context = RenderContext::new(None);
- tpl.render(self, &ctx, &mut render_context, &mut out)?;
+ tpl.render(self, ctx, &mut render_context, &mut out)?;
}
out.into_string().map_err(RenderError::from)
}
+ /// Render a template string using resuable context, and write data into
+ /// `std::io::Write`
+ pub fn render_template_with_context_to_write<W>(
+ &self,
+ template_string: &str,
+ ctx: &Context,
+ writer: W,
+ ) -> Result<(), RenderError>
+ where
+ W: Write,
+ {
+ let tpl = Template::compile2(
+ template_string,
+ TemplateOptions {
+ prevent_indent: self.prevent_indent,
+ ..Default::default()
+ },
+ )?;
+ let mut render_context = RenderContext::new(None);
+ let mut out = WriteOutput::new(writer);
+ tpl.render(self, ctx, &mut render_context, &mut out)
+ }
+
/// Render a template string using current registry without registering it
pub fn render_template_to_write<T, W>(
&self,
@@ -565,11 +714,8 @@ impl<'reg> Registry<'reg> {
T: Serialize,
W: Write,
{
- let tpl = Template::compile(template_string)?;
let ctx = Context::wraps(data)?;
- let mut render_context = RenderContext::new(None);
- let mut out = WriteOutput::new(writer);
- tpl.render(self, &ctx, &mut render_context, &mut out)
+ self.render_template_with_context_to_write(template_string, &ctx, writer)
}
}
@@ -944,8 +1090,7 @@ mod test {
.unwrap();
assert_eq!(
"0123",
- reg.render_with_context("t0", &Context::wraps(&data).unwrap())
- .unwrap()
+ reg.render_with_context("t0", &Context::from(data)).unwrap()
);
}
@@ -1089,4 +1234,17 @@ mod test {
dir.close().unwrap();
}
+
+ #[test]
+ #[cfg(feature = "script_helper")]
+ fn test_engine_access() {
+ use rhai::Engine;
+
+ let mut registry = Registry::new();
+ let mut eng = Engine::new();
+ eng.set_max_string_size(1000);
+ registry.set_engine(eng);
+
+ assert_eq!(1000, registry.engine().max_string_size());
+ }
}