From 62dd3d048f679b48a174bbbb21cfe24dc1c20070 Mon Sep 17 00:00:00 2001 From: Ning Sun Date: Sun, 13 Dec 2020 21:51:24 +0800 Subject: [PATCH 1/5] (test) add test case to reproduce #400 --- src/partial.rs | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/src/partial.rs b/src/partial.rs index f098e6420..c3b086a0c 100644 --- a/src/partial.rs +++ b/src/partial.rs @@ -250,4 +250,22 @@ mod test { let r0 = handlebars.render("t", &data); assert_eq!(r0.ok().unwrap(), "2 true2 false"); } + + #[test] + fn test_nested_partials() { + let mut handlebars = Registry::new(); + let template1 = "{{> @partial-block }}"; + let template2 = "{{#> t1 }}{{> @partial-block }}{{/ t1 }}"; + let template3 = "{{#> t2 }}Hello{{/ t2 }}"; + + handlebars + .register_template_string("t1", &template1) + .unwrap(); + handlebars + .register_template_string("t2", &template2) + .unwrap(); + + let page = handlebars.render_template(&template3, &json!({})).unwrap(); + assert_eq!("Hello", page); + } } From 42c220f2a65c27fc06612ccd521da0375262dea6 Mon Sep 17 00:00:00 2001 From: Ning Sun Date: Wed, 23 Dec 2020 21:53:37 +0800 Subject: [PATCH 2/5] (fix) add partial block stack --- src/partial.rs | 10 +++++----- src/render.rs | 19 +++++++++++++++++++ 2 files changed, 24 insertions(+), 5 deletions(-) diff --git a/src/partial.rs b/src/partial.rs index c3b086a0c..70943c194 100644 --- a/src/partial.rs +++ b/src/partial.rs @@ -9,7 +9,7 @@ use crate::output::Output; use crate::registry::Registry; use crate::render::{Decorator, Evaluable, RenderContext, Renderable}; -const PARTIAL_BLOCK: &str = "@partial-block"; +pub(crate) const PARTIAL_BLOCK: &str = "@partial-block"; pub fn expand_partial<'reg: 'rc, 'rc>( d: &Decorator<'reg, 'rc>, @@ -44,11 +44,11 @@ pub fn expand_partial<'reg: 'rc, 'rc>( } // @partial-block - if let Some(t) = d.template() { - local_rc.set_partial(PARTIAL_BLOCK.to_owned(), t); - } + local_rc.push_partial_block(d.template()); let result = if d.hash().is_empty() { + dbg!(&t); + dbg!(&local_rc); t.render(r, ctx, &mut local_rc, out) } else { let hash_ctx = d @@ -64,7 +64,7 @@ pub fn expand_partial<'reg: 'rc, 'rc>( t.render(r, &ctx, &mut partial_rc, out) }; - local_rc.remove_partial(PARTIAL_BLOCK); + local_rc.pop_partial_block(); result } else { diff --git a/src/render.rs b/src/render.rs index 82791ac31..d5e818117 100644 --- a/src/render.rs +++ b/src/render.rs @@ -39,6 +39,7 @@ pub struct RenderContext<'reg, 'rc> { #[derive(Clone)] pub struct RenderContextInner<'reg: 'rc, 'rc> { partials: BTreeMap, + partial_block_stack: VecDeque>, local_helpers: BTreeMap>, /// current template name current_template: Option<&'reg String>, @@ -52,6 +53,7 @@ impl<'reg: 'rc, 'rc> RenderContext<'reg, 'rc> { pub fn new(root_template: Option<&'reg String>) -> RenderContext<'reg, 'rc> { let inner = Rc::new(RenderContextInner { partials: BTreeMap::new(), + partial_block_stack: VecDeque::new(), local_helpers: BTreeMap::new(), current_template: None, root_template, @@ -158,6 +160,14 @@ impl<'reg: 'rc, 'rc> RenderContext<'reg, 'rc> { /// Get registered partial in this render context pub fn get_partial(&self, name: &str) -> Option<&Template> { + if name == partial::PARTIAL_BLOCK { + return self + .inner() + .partial_block_stack + .front() // TODO: + .map(|v| *v) + .unwrap_or(None); + } self.inner().partials.get(name).map(|v| *v) } @@ -166,6 +176,14 @@ impl<'reg: 'rc, 'rc> RenderContext<'reg, 'rc> { self.inner_mut().partials.insert(name, partial); } + pub(crate) fn push_partial_block(&mut self, partial: Option<&'reg Template>) { + self.inner_mut().partial_block_stack.push_front(partial); + } + + pub(crate) fn pop_partial_block(&mut self) { + self.inner_mut().partial_block_stack.pop_front(); + } + /// Remove a registered partial pub fn remove_partial(&mut self, name: &str) { self.inner_mut().partials.remove(name); @@ -247,6 +265,7 @@ impl<'reg, 'rc> fmt::Debug for RenderContextInner<'reg, 'rc> { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> Result<(), fmt::Error> { f.debug_struct("RenderContextInner") .field("partials", &self.partials) + .field("partial_block_stack", &self.partial_block_stack) .field("root_template", &self.root_template) .field("current_template", &self.current_template) .field("disable_eacape", &self.disable_escape) From 27038d040e94d6dd2145fe91d9286bcacbb4c70e Mon Sep 17 00:00:00 2001 From: Ning Sun Date: Thu, 24 Dec 2020 22:13:29 +0800 Subject: [PATCH 3/5] (fix) maintain partial_block_depth for @partial-block --- src/partial.rs | 19 +++++++++++++++---- src/render.rs | 12 +++++++++++- 2 files changed, 26 insertions(+), 5 deletions(-) diff --git a/src/partial.rs b/src/partial.rs index 70943c194..7e1d26950 100644 --- a/src/partial.rs +++ b/src/partial.rs @@ -28,6 +28,7 @@ pub fn expand_partial<'reg: 'rc, 'rc>( return Err(RenderError::new("Cannot include self in >")); } + // if tname == PARTIAL_BLOCK let partial = rc .get_partial(tname) .or_else(|| r.get_template(tname)) @@ -35,6 +36,10 @@ pub fn expand_partial<'reg: 'rc, 'rc>( if let Some(t) = partial { let mut local_rc = rc.clone(); + let is_partial_block = tname == PARTIAL_BLOCK; + if is_partial_block { + local_rc.inc_partial_block_depth(); + } // partial context path if let Some(ref param_ctx) = d.param(0) { @@ -44,11 +49,11 @@ pub fn expand_partial<'reg: 'rc, 'rc>( } // @partial-block - local_rc.push_partial_block(d.template()); + if d.template().is_some() { + local_rc.push_partial_block(d.template()); + } let result = if d.hash().is_empty() { - dbg!(&t); - dbg!(&local_rc); t.render(r, ctx, &mut local_rc, out) } else { let hash_ctx = d @@ -64,7 +69,13 @@ pub fn expand_partial<'reg: 'rc, 'rc>( t.render(r, &ctx, &mut partial_rc, out) }; - local_rc.pop_partial_block(); + if is_partial_block { + local_rc.dec_partial_block_depth(); + } + + if d.template().is_some() { + local_rc.pop_partial_block(); + } result } else { diff --git a/src/render.rs b/src/render.rs index d5e818117..884021c66 100644 --- a/src/render.rs +++ b/src/render.rs @@ -40,6 +40,7 @@ pub struct RenderContext<'reg, 'rc> { pub struct RenderContextInner<'reg: 'rc, 'rc> { partials: BTreeMap, partial_block_stack: VecDeque>, + partial_block_depth: isize, local_helpers: BTreeMap>, /// current template name current_template: Option<&'reg String>, @@ -54,6 +55,7 @@ impl<'reg: 'rc, 'rc> RenderContext<'reg, 'rc> { let inner = Rc::new(RenderContextInner { partials: BTreeMap::new(), partial_block_stack: VecDeque::new(), + partial_block_depth: 0, local_helpers: BTreeMap::new(), current_template: None, root_template, @@ -164,7 +166,7 @@ impl<'reg: 'rc, 'rc> RenderContext<'reg, 'rc> { return self .inner() .partial_block_stack - .front() // TODO: + .get(self.inner().partial_block_depth as usize) .map(|v| *v) .unwrap_or(None); } @@ -184,6 +186,14 @@ impl<'reg: 'rc, 'rc> RenderContext<'reg, 'rc> { self.inner_mut().partial_block_stack.pop_front(); } + pub(crate) fn inc_partial_block_depth(&mut self) { + self.inner_mut().partial_block_depth += 1; + } + + pub(crate) fn dec_partial_block_depth(&mut self) { + self.inner_mut().partial_block_depth -= 1; + } + /// Remove a registered partial pub fn remove_partial(&mut self, name: &str) { self.inner_mut().partials.remove(name); From 77b8d685e9f571a164465d04e872895f3d9a329b Mon Sep 17 00:00:00 2001 From: Ning Sun Date: Thu, 24 Dec 2020 22:22:32 +0800 Subject: [PATCH 4/5] (refactor) remove Nones from partial stack --- src/partial.rs | 5 +++-- src/render.rs | 7 +++---- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/src/partial.rs b/src/partial.rs index 7e1d26950..ad7a27345 100644 --- a/src/partial.rs +++ b/src/partial.rs @@ -37,6 +37,7 @@ pub fn expand_partial<'reg: 'rc, 'rc>( if let Some(t) = partial { let mut local_rc = rc.clone(); let is_partial_block = tname == PARTIAL_BLOCK; + if is_partial_block { local_rc.inc_partial_block_depth(); } @@ -49,8 +50,8 @@ pub fn expand_partial<'reg: 'rc, 'rc>( } // @partial-block - if d.template().is_some() { - local_rc.push_partial_block(d.template()); + if let Some(pb) = d.template() { + local_rc.push_partial_block(pb); } let result = if d.hash().is_empty() { diff --git a/src/render.rs b/src/render.rs index 884021c66..01b48d851 100644 --- a/src/render.rs +++ b/src/render.rs @@ -39,7 +39,7 @@ pub struct RenderContext<'reg, 'rc> { #[derive(Clone)] pub struct RenderContextInner<'reg: 'rc, 'rc> { partials: BTreeMap, - partial_block_stack: VecDeque>, + partial_block_stack: VecDeque<&'reg Template>, partial_block_depth: isize, local_helpers: BTreeMap>, /// current template name @@ -167,8 +167,7 @@ impl<'reg: 'rc, 'rc> RenderContext<'reg, 'rc> { .inner() .partial_block_stack .get(self.inner().partial_block_depth as usize) - .map(|v| *v) - .unwrap_or(None); + .map(|v| *v); } self.inner().partials.get(name).map(|v| *v) } @@ -178,7 +177,7 @@ impl<'reg: 'rc, 'rc> RenderContext<'reg, 'rc> { self.inner_mut().partials.insert(name, partial); } - pub(crate) fn push_partial_block(&mut self, partial: Option<&'reg Template>) { + pub(crate) fn push_partial_block(&mut self, partial: &'reg Template) { self.inner_mut().partial_block_stack.push_front(partial); } From c90059cd97d5e045ddb2e360c32f91a1e06114a5 Mon Sep 17 00:00:00 2001 From: Ning Sun Date: Thu, 24 Dec 2020 22:48:50 +0800 Subject: [PATCH 5/5] (fix) clippy warnings --- src/render.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/render.rs b/src/render.rs index 01b48d851..d9da9e4a7 100644 --- a/src/render.rs +++ b/src/render.rs @@ -167,9 +167,9 @@ impl<'reg: 'rc, 'rc> RenderContext<'reg, 'rc> { .inner() .partial_block_stack .get(self.inner().partial_block_depth as usize) - .map(|v| *v); + .copied(); } - self.inner().partials.get(name).map(|v| *v) + self.inner().partials.get(name).copied() } /// Register a partial for this context