Skip to content

Commit

Permalink
Merge pull request #646 from cmrschwarz/nested_partial_indenting
Browse files Browse the repository at this point in the history
Fix nested partial indenting
  • Loading branch information
sunng87 authored Jun 16, 2024
2 parents 5dda501 + 18eeb6c commit 5513cfa
Show file tree
Hide file tree
Showing 3 changed files with 80 additions and 9 deletions.
45 changes: 44 additions & 1 deletion src/partial.rs
Original file line number Diff line number Diff line change
Expand Up @@ -133,11 +133,12 @@ pub fn expand_partial<'reg: 'rc, 'rc>(
}

// indent
local_rc.set_indent_string(d.indent());
local_rc.set_indent_string(d.indent().cloned());

let result = t.render(r, ctx, &mut local_rc, out);

// cleanup

if block_created {
local_rc.pop_block();
}
Expand Down Expand Up @@ -665,6 +666,48 @@ outer third line"#,
)
}

#[test]
fn test_indent_level_on_nested_partials() {
let nested_partial = "
<div>
content
</div>
";
let partial = "
<div>
{{>nested_partial}}
</div>
";

let partial_indented = "
<div>
{{>partial}}
</div>
";

let result = "
<div>
<div>
<div>
content
</div>
</div>
</div>
";

let mut hb = Registry::new();
hb.register_template_string("nested_partial", nested_partial.trim_start())
.unwrap();
hb.register_template_string("partial", partial.trim_start())
.unwrap();
hb.register_template_string("partial_indented", partial_indented.trim_start())
.unwrap();

let s = hb.render("partial_indented", &()).unwrap();

assert_eq!(&s, result.trim_start());
}

#[test]
fn test_issue_534() {
let t1 = "{{title}}";
Expand Down
33 changes: 25 additions & 8 deletions src/render.rs
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,7 @@ pub struct RenderContextInner<'reg: 'rc, 'rc> {
/// root template name
root_template: Option<&'reg String>,
disable_escape: bool,
indent_string: Option<&'reg String>,
indent_string: Option<Cow<'reg, str>>,
}

impl<'reg: 'rc, 'rc> RenderContext<'reg, 'rc> {
Expand Down Expand Up @@ -202,13 +202,13 @@ impl<'reg: 'rc, 'rc> RenderContext<'reg, 'rc> {
}
}

pub(crate) fn set_indent_string(&mut self, indent: Option<&'reg String>) {
pub(crate) fn set_indent_string(&mut self, indent: Option<Cow<'reg, str>>) {
self.inner_mut().indent_string = indent;
}

#[inline]
pub(crate) fn get_indent_string(&self) -> Option<&'reg String> {
self.inner.indent_string
pub(crate) fn get_indent_string(&self) -> Option<&Cow<'reg, str>> {
self.inner.indent_string.as_ref()
}

/// Remove a registered partial
Expand Down Expand Up @@ -454,7 +454,7 @@ pub struct Decorator<'rc> {
params: Vec<PathAndJson<'rc>>,
hash: BTreeMap<&'rc str, PathAndJson<'rc>>,
template: Option<&'rc Template>,
indent: Option<&'rc String>,
indent: Option<Cow<'rc, str>>,
}

impl<'reg: 'rc, 'rc> Decorator<'rc> {
Expand All @@ -478,12 +478,23 @@ impl<'reg: 'rc, 'rc> Decorator<'rc> {
hm.insert(k.as_ref(), r);
}

let indent = match (render_context.get_indent_string(), dt.indent.as_ref()) {
(None, None) => None,
(Some(s), None) => Some(s.clone()),
(None, Some(s)) => Some(Cow::Borrowed(&**s)),
(Some(s1), Some(s2)) => {
let mut res = s1.to_string();
res.push_str(s2);
Some(Cow::from(res))
}
};

Ok(Decorator {
name,
params: pv,
hash: hm,
template: dt.template.as_ref(),
indent: dt.indent.as_ref(),
indent,
})
}

Expand Down Expand Up @@ -517,8 +528,8 @@ impl<'reg: 'rc, 'rc> Decorator<'rc> {
self.template
}

pub fn indent(&self) -> Option<&'rc String> {
self.indent
pub fn indent(&self) -> Option<&Cow<'rc, str>> {
self.indent.as_ref()
}
}

Expand Down Expand Up @@ -796,6 +807,12 @@ impl Renderable for TemplateElement {
out: &mut dyn Output,
) -> Result<(), RenderError> {
match self {
Indent => {
if let Some(indent) = rc.get_indent_string() {
out.write(indent)?;
}
Ok(())
}
RawString(ref v) => indent_aware_write(v.as_ref(), rc, out),
Expression(ref ht) | HtmlExpression(ref ht) => {
let is_html_expression = matches!(self, HtmlExpression(_));
Expand Down
11 changes: 11 additions & 0 deletions src/template.rs
Original file line number Diff line number Diff line change
Expand Up @@ -634,6 +634,7 @@ impl Template {
// this option is marked as true when standalone statement is detected
// then the leading whitespaces and newline of next rawstring will be trimed
let mut trim_line_required = false;
let mut prev_rule = None;

let parser_queue = HandlebarsParser::parse(Rule::handlebars, source).map_err(|e| {
let (line_no, col_no) = match e.line_col {
Expand Down Expand Up @@ -718,6 +719,14 @@ impl Template {
};

let t = template_stack.front_mut().unwrap();

// If this text element is following a standalone partial, then
// we trim the whitespace between. But we still want the following text
// to be indented correctly, so we insert the special `Indent` element.
if trim_line_required && prev_rule == Some(Rule::partial_expression) {
t.push_element(TemplateElement::Indent, line_no, col_no);
}

t.push_element(
Template::raw_string(
&source[start..span.end()],
Expand Down Expand Up @@ -976,6 +985,7 @@ impl Template {
if rule != Rule::template {
end_pos = Some(span.end_pos());
}
prev_rule = Some(rule);
} else {
let prev_end = end_pos.as_ref().map(|e| e.pos()).unwrap_or(0);
if prev_end < source.len() {
Expand Down Expand Up @@ -1016,6 +1026,7 @@ impl Template {

#[derive(PartialEq, Eq, Clone, Debug)]
pub enum TemplateElement {
Indent,
RawString(String),
HtmlExpression(Box<HelperTemplate>),
Expression(Box<HelperTemplate>),
Expand Down

0 comments on commit 5513cfa

Please sign in to comment.