diff --git a/src/builder.rs b/src/builder.rs index 83c5ca4..2ba8443 100644 --- a/src/builder.rs +++ b/src/builder.rs @@ -149,6 +149,15 @@ impl MapBuilder { data.insert(key.to_string(), Data::Fun(RefCell::new(Box::new(f)))); MapBuilder { data: data } } + #[inline] + pub fn insert_fn2(self, key: K, f: F) -> MapBuilder + where + F: FnMut(String, &mut (FnMut(String) -> String)) -> String + Send + 'static, + { + let MapBuilder { mut data } = self; + data.insert(key.to_string(), Data::Fun2(RefCell::new(Box::new(f)))); + MapBuilder { data: data } + } /// Return the built `Data`. #[inline] diff --git a/src/data.rs b/src/data.rs index b71c79f..ae518ce 100644 --- a/src/data.rs +++ b/src/data.rs @@ -9,6 +9,7 @@ pub enum Data { Vec(Vec), Map(HashMap), Fun(RefCell String + Send>>), + Fun2(RefCell String)) -> String + Send>>), } impl PartialEq for Data { @@ -35,6 +36,7 @@ impl fmt::Debug for Data { Data::Vec(ref v) => write!(f, "VecVal({:?})", v), Data::Map(ref v) => write!(f, "Map({:?})", v), Data::Fun(_) => write!(f, "Fun(...)"), + Data::Fun2(_) => write!(f, "Fun2(...)"), } } -} \ No newline at end of file +} diff --git a/src/template.rs b/src/template.rs index 1d6825e..e97b206 100644 --- a/src/template.rs +++ b/src/template.rs @@ -65,6 +65,7 @@ struct RenderContext<'a> { template: &'a Template, indent: String, line_start: bool, + inner_fn2_rendered: bool, } impl<'a> RenderContext<'a> { @@ -73,6 +74,7 @@ impl<'a> RenderContext<'a> { template: template, indent: "".to_string(), line_start: true, + inner_fn2_rendered: true, } } @@ -291,6 +293,50 @@ impl<'a> RenderContext<'a> { let tokens = try!(self.render_fun(src, otag, ctag, f)); try!(self.render(wr, stack, &tokens)); } + Data::Fun2(ref fcell) => { + let f = &mut *fcell.borrow_mut(); + let ctx2 = self.template.ctx.clone(); + let partials2 = self.template.partials.clone(); + self.inner_fn2_rendered = false; + + let mut f0 = { + |src: String| { + let compiler = Compiler::new_with( + ctx2.clone(), + src.chars(), + partials2.clone(), + otag.to_string(), + ctag.to_string(), + ); + let mut vw: Vec = vec![]; + match compiler.compile() { + Ok((tokens, _)) => { + /* a trick to reset the flag is to pass an empty string */ + self.inner_fn2_rendered = (src.len() > 0); + self.render(&mut vw, stack, &tokens).unwrap_or(()) + } + _ => (), + } + String::from_utf8_lossy(&vw).to_string() + } + }; + let src = f(src.to_string(), &mut f0); + if self.inner_fn2_rendered { + self.inner_fn2_rendered = false; + try!(self.render_text(wr, &src)); + } else { + let compiler = Compiler::new_with( + self.template.ctx.clone(), + src.chars(), + self.template.partials.clone(), + otag.to_string(), + ctag.to_string(), + ); + + let (tokens, _) = try!(compiler.compile()); + try!(self.render(wr, stack, &tokens)); + } + } } } };