Skip to content

Commit 58a3d81

Browse files
authored
NestedTemplateOnce without filter renders directly to buffer (#171)
Thanks!
1 parent 276be76 commit 58a3d81

1 file changed

Lines changed: 75 additions & 51 deletions

File tree

sailfish-compiler/src/translator.rs

Lines changed: 75 additions & 51 deletions
Original file line numberDiff line numberDiff line change
@@ -130,27 +130,69 @@ impl SourceBuilder {
130130
Ok(())
131131
}
132132

133-
fn write_buffered_code(
134-
&mut self,
135-
token: &Token<'_>,
136-
escape: bool,
137-
) -> Result<(), Error> {
138-
self.write_buffered_code_with_suffix(token, escape, "")
139-
}
140-
141-
fn write_buffered_code_with_suffix(
133+
fn parse_filter(
142134
&mut self,
143135
token: &Token<'_>,
144-
escape: bool,
145-
suffix: &str,
146-
) -> Result<(), Error> {
136+
) -> Result<Option<(Filter, TokenStream)>, Error> {
147137
// parse and split off filter
148138
let code_block = syn::parse_str::<CodeBlock>(token.as_str()).map_err(|e| {
149139
let span = e.span();
150140
let mut err = make_error!(ErrorKind::RustSyntaxError(e));
151141
err.offset = into_offset(token.as_str(), span).map(|p| token.offset() + p);
152142
err
153143
})?;
144+
145+
Ok(code_block
146+
.filter
147+
.map(|filter| (filter, code_block.expr.into_token_stream())))
148+
}
149+
150+
fn write_with_filter(
151+
&mut self,
152+
token: &Token<'_>,
153+
filter: Filter,
154+
expr_str: &str,
155+
) -> Result<(), Error> {
156+
let (name, extra_args) = match filter {
157+
Filter::Ident(i) => (i.to_string(), None),
158+
Filter::Call(c) => (
159+
c.func.into_token_stream().to_string(),
160+
Some(c.args.into_token_stream().to_string()),
161+
),
162+
};
163+
164+
self.source.push_str("sailfish::runtime::filter::");
165+
self.source.push_str(&name);
166+
self.source.push('(');
167+
168+
// arguments to filter function
169+
{
170+
self.source.push_str("&(");
171+
let entry = SourceMapEntry {
172+
original: token.offset(),
173+
new: self.source.len(),
174+
length: expr_str.len(),
175+
};
176+
self.source_map.entries.push(entry);
177+
self.source.push_str(expr_str);
178+
self.source.push(')');
179+
180+
if let Some(extra_args) = extra_args {
181+
self.source.push_str(", ");
182+
self.source.push_str(&extra_args);
183+
}
184+
}
185+
186+
self.source.push(')');
187+
188+
Ok(())
189+
}
190+
191+
fn write_buffered_code(
192+
&mut self,
193+
token: &Token<'_>,
194+
escape: bool,
195+
) -> Result<(), Error> {
154196
let method = if self.escape && escape {
155197
"render_escaped"
156198
} else {
@@ -161,46 +203,30 @@ impl SourceBuilder {
161203
self.source.push_str(method);
162204
self.source.push_str("!(__sf_buf, ");
163205

164-
if let Some(filter) = code_block.filter {
165-
let expr_str = format!("{}{}", code_block.expr.into_token_stream(), suffix);
166-
let (name, extra_args) = match filter {
167-
Filter::Ident(i) => (i.to_string(), None),
168-
Filter::Call(c) => (
169-
c.func.into_token_stream().to_string(),
170-
Some(c.args.into_token_stream().to_string()),
171-
),
172-
};
206+
if let Some((filter, code_token_stream)) = self.parse_filter(token)? {
207+
let expr_str = format!("{}", code_token_stream);
208+
self.write_with_filter(token, filter, &expr_str)?;
209+
} else {
210+
self.write_token(token);
211+
}
173212

174-
self.source.push_str("sailfish::runtime::filter::");
175-
self.source.push_str(&name);
176-
self.source.push('(');
213+
self.source.push_str(");\n");
177214

178-
// arguments to filter function
179-
{
180-
self.source.push_str("&(");
181-
let entry = SourceMapEntry {
182-
original: token.offset(),
183-
new: self.source.len(),
184-
length: expr_str.len(),
185-
};
186-
self.source_map.entries.push(entry);
187-
self.source.push_str(&expr_str);
188-
self.source.push(')');
189-
190-
if let Some(extra_args) = extra_args {
191-
self.source.push_str(", ");
192-
self.source.push_str(&extra_args);
193-
}
194-
}
215+
Ok(())
216+
}
195217

196-
self.source.push(')');
218+
fn write_nested_template_once(&mut self, token: &Token<'_>) -> Result<(), Error> {
219+
if let Some((filter, code_token_stream)) = self.parse_filter(token)? {
220+
self.source.push_str("__sf_rt::render!(__sf_buf, ");
221+
let expr_str = format!("{}{}", code_token_stream, ".render_once()?");
222+
self.write_with_filter(token, filter, &expr_str)?;
223+
self.source.push_str(");\n");
197224
} else {
225+
self.source.push('(');
198226
self.write_token(token);
199-
self.source.push_str(suffix);
227+
self.source.push_str(").render_once_to(__sf_buf)?;\n");
200228
}
201229

202-
self.source.push_str(");\n");
203-
204230
Ok(())
205231
}
206232

@@ -214,11 +240,9 @@ impl SourceBuilder {
214240
TokenKind::BufferedCode { escape } => {
215241
self.write_buffered_code(&token, escape)?
216242
}
217-
TokenKind::NestedTemplateOnce => self.write_buffered_code_with_suffix(
218-
&token,
219-
false,
220-
".render_once()?",
221-
)?,
243+
TokenKind::NestedTemplateOnce => {
244+
self.write_nested_template_once(&token)?
245+
}
222246
TokenKind::Text => {
223247
// concatenate repeated text token
224248
let offset = token.offset();
@@ -399,7 +423,7 @@ mod tests {
399423
.ast
400424
.into_token_stream()
401425
.to_string(),
402-
r#"{ __sf_rt :: render_text ! (__sf_buf , "outer ") ; __sf_rt :: render ! (__sf_buf , inner . render_once () ?) ; __sf_rt :: render_text ! (__sf_buf , " outer") ; }"#
426+
r#"{ __sf_rt :: render_text ! (__sf_buf , "outer ") ; (inner) . render_once_to (__sf_buf) ? ; __sf_rt :: render_text ! (__sf_buf , " outer") ; }"#
403427
);
404428
}
405429

0 commit comments

Comments
 (0)