Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fix indent v2 #654

Merged
merged 10 commits into from
Jul 7, 2024
6 changes: 4 additions & 2 deletions src/helpers/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ use crate::error::{RenderError, RenderErrorReason};
use crate::json::value::ScopedJson;
use crate::output::Output;
use crate::registry::Registry;
use crate::render::{do_escape, Helper, RenderContext};
use crate::render::{do_escape, indent_aware_write, Helper, RenderContext};

pub use self::helper_each::EACH_HELPER;
pub use self::helper_if::{IF_HELPER, UNLESS_HELPER};
Expand Down Expand Up @@ -126,7 +126,9 @@ pub trait HelperDef {
} else {
// auto escape according to settings
let output = do_escape(r, rc, result.render());
out.write(output.as_ref())?;

indent_aware_write(&output, rc, out)?;

Ok(())
}
}
Expand Down
6 changes: 6 additions & 0 deletions src/partial.rs
Original file line number Diff line number Diff line change
Expand Up @@ -139,6 +139,8 @@ pub fn expand_partial<'reg: 'rc, 'rc>(

// cleanup

let trailing_newline = local_rc.get_trailine_newline();

if block_created {
local_rc.pop_block();
}
Expand All @@ -147,6 +149,10 @@ pub fn expand_partial<'reg: 'rc, 'rc>(
local_rc.pop_partial_block();
}

drop(local_rc);

rc.set_trailing_newline(trailing_newline);

result
} else {
Err(RenderErrorReason::PartialNotFound(tname.to_owned()).into())
Expand Down
71 changes: 59 additions & 12 deletions src/render.rs
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ use crate::json::value::{JsonRender, PathAndJson, ScopedJson};
use crate::output::{Output, StringOutput};
use crate::registry::Registry;
use crate::support;
use crate::support::str::newline_matcher;
use crate::template::TemplateElement::*;
use crate::template::{
BlockParam, DecoratorTemplate, HelperTemplate, Parameter, Template, TemplateElement,
Expand Down Expand Up @@ -48,6 +49,11 @@ pub struct RenderContextInner<'reg: 'rc, 'rc> {
/// root template name
root_template: Option<&'reg String>,
disable_escape: bool,
// whether the previous text that we rendered ended on a newline
// necessary to make indenting decisions after the end of partials
trailing_newline: bool,
// whether the previous text that we render should indent itself
indent_before_write: bool,
indent_string: Option<Cow<'reg, str>>,
}

Expand All @@ -62,6 +68,8 @@ impl<'reg: 'rc, 'rc> RenderContext<'reg, 'rc> {
current_template: None,
root_template,
disable_escape: false,
trailing_newline: false,
indent_before_write: false,
indent_string: None,
});

Expand Down Expand Up @@ -286,6 +294,33 @@ impl<'reg: 'rc, 'rc> RenderContext<'reg, 'rc> {
pub fn set_disable_escape(&mut self, disable: bool) {
self.inner_mut().disable_escape = disable
}

#[inline]
pub fn set_trailing_newline(&mut self, trailing_newline: bool) {
self.inner_mut().trailing_newline = trailing_newline;
}

#[inline]
pub fn get_trailine_newline(&self) -> bool {
self.inner().trailing_newline
}

#[inline]
pub fn set_indent_before_write(&mut self, indent_before_write: bool) {
self.inner_mut().indent_before_write = indent_before_write;
}

#[inline]
pub fn get_indent_before_write(&self) -> bool {
self.inner().indent_before_write
}

#[inline]
pub fn take_indent_before_write(&mut self) -> bool {
let res = self.get_indent_before_write();
self.set_indent_before_write(false);
res
}
}

impl<'reg, 'rc> fmt::Debug for RenderContextInner<'reg, 'rc> {
Expand Down Expand Up @@ -704,6 +739,7 @@ impl Renderable for Template {
e
})?;
}

Ok(())
}
}
Expand Down Expand Up @@ -757,8 +793,14 @@ fn render_helper<'reg: 'rc, 'rc>(
h.params(),
h.hash()
);
let mut call_indent_aware = |helper_def: &dyn HelperDef, rc: &mut RenderContext<'reg, 'rc>| {
rc.set_indent_before_write(ht.indent_before_write);
helper_def.call(&h, registry, ctx, rc, out)?;
rc.set_indent_before_write(rc.get_trailine_newline());
Ok(())
};
if let Some(ref d) = rc.get_local_helper(h.name()) {
d.call(&h, registry, ctx, rc, out)
call_indent_aware(&**d, rc)
} else {
let mut helper = registry.get_or_load_helper(h.name())?;

Expand All @@ -772,7 +814,7 @@ fn render_helper<'reg: 'rc, 'rc>(

helper
.ok_or_else(|| RenderErrorReason::HelperNotFound(h.name().to_owned()).into())
.and_then(|d| d.call(&h, registry, ctx, rc, out))
.and_then(|d| call_indent_aware(&*d, rc))
}
}

Expand All @@ -785,16 +827,25 @@ pub(crate) fn do_escape(r: &Registry<'_>, rc: &RenderContext<'_, '_>, content: S
}

#[inline]
fn indent_aware_write(
pub fn indent_aware_write(
v: &str,
rc: &RenderContext<'_, '_>,
rc: &mut RenderContext<'_, '_>,
out: &mut dyn Output,
) -> Result<(), RenderError> {
if v.is_empty() {
return Ok(());
}
if !v.starts_with(newline_matcher) && rc.take_indent_before_write() {
if let Some(indent) = rc.get_indent_string() {
out.write(indent)?;
}
}
if let Some(indent) = rc.get_indent_string() {
out.write(support::str::with_indent(v, indent).as_ref())?;
} else {
out.write(v.as_ref())?;
}
rc.set_trailing_newline(v.ends_with(newline_matcher));
Ok(())
}

Expand All @@ -807,12 +858,6 @@ 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 Expand Up @@ -861,8 +906,10 @@ impl Renderable for TemplateElement {
DecoratorExpression(_) | DecoratorBlock(_) => self.eval(registry, ctx, rc),
PartialExpression(ref dt) | PartialBlock(ref dt) => {
let di = Decorator::try_from_template(dt, registry, ctx, rc)?;

partial::expand_partial(&di, registry, ctx, rc, out)
rc.set_indent_before_write(dt.indent_before_write);
partial::expand_partial(&di, registry, ctx, rc, out)?;
rc.set_indent_before_write(rc.get_trailine_newline());
Ok(())
}
_ => Ok(()),
}
Expand Down
Loading
Loading