From 06e112a6d04c7c3a2a7dda17e05216b37fe42df9 Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Sat, 27 Apr 2024 21:36:07 +0200 Subject: [PATCH 1/8] Remove unneeded `IntoIterator` implementation for `WritableBuffer` --- askama_derive/src/generator.rs | 20 +++++--------------- 1 file changed, 5 insertions(+), 15 deletions(-) diff --git a/askama_derive/src/generator.rs b/askama_derive/src/generator.rs index 58da7f72..aebe3a2e 100644 --- a/askama_derive/src/generator.rs +++ b/askama_derive/src/generator.rs @@ -705,7 +705,7 @@ impl<'a> Generator<'a> { break; } } - let current_buf = mem::take(&mut self.buf_writable); + let current_buf = mem::take(&mut self.buf_writable.buf); self.prepare_ws(filter.ws1); let mut size_hint = self.handle(ctx, &filter.nodes, buf, AstLevel::Nested)?; @@ -734,7 +734,7 @@ impl<'a> Generator<'a> { } }; - mem::drop(mem::replace(&mut self.buf_writable, current_buf)); + mem::drop(mem::replace(&mut self.buf_writable.buf, current_buf)); let mut filter_buf = Buffer::new(buf.indent); let Filter { @@ -962,8 +962,7 @@ impl<'a> Generator<'a> { child.write_buf_writable(buf)?; } child.flush_ws(def.ws2); - let buf_writable = mem::take(&mut child.buf_writable); - self.buf_writable = buf_writable; + self.buf_writable = child.buf_writable; // Restore original block context and set whitespace suppression for // succeeding whitespace according to the outer WS spec @@ -1024,7 +1023,7 @@ impl<'a> Generator<'a> { .all(|w| matches!(w, Writable::Lit(_))) { let mut buf_lit = Buffer::new(0); - for s in mem::take(&mut self.buf_writable) { + for s in mem::take(&mut self.buf_writable.buf) { if let Writable::Lit(s) = s { buf_lit.write(s); }; @@ -1044,7 +1043,7 @@ impl<'a> Generator<'a> { let mut buf_format = Buffer::new(0); let mut buf_expr = Buffer::new(indent + 1); - for s in mem::take(&mut self.buf_writable) { + for s in mem::take(&mut self.buf_writable.buf) { match s { Writable::Lit(s) => { buf_format.write(&s.replace('{', "{{").replace('}', "}}")); @@ -2119,15 +2118,6 @@ impl<'a> WritableBuffer<'a> { } } -impl<'a> IntoIterator for WritableBuffer<'a> { - type Item = Writable<'a>; - type IntoIter = > as IntoIterator>::IntoIter; - - fn into_iter(self) -> Self::IntoIter { - self.buf.into_iter() - } -} - impl<'a> Deref for WritableBuffer<'a> { type Target = [Writable<'a>]; From 4d64819d57dc25f978e23257da8904398b41d628 Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Sat, 27 Apr 2024 22:51:24 +0200 Subject: [PATCH 2/8] Prevent generating unused code if a block is specified --- askama_derive/src/generator.rs | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/askama_derive/src/generator.rs b/askama_derive/src/generator.rs index aebe3a2e..6b980f3a 100644 --- a/askama_derive/src/generator.rs +++ b/askama_derive/src/generator.rs @@ -895,8 +895,11 @@ impl<'a> Generator<'a> { let block_fragment_write = self.input.block == name && self.buf_writable.discard; // Allow writing to the buffer if we're in the block fragment + let mut prev_buf_discard = buf.discard; if block_fragment_write { self.buf_writable.discard = false; + } else if self.buf_writable.discard { + prev_buf_discard = mem::replace(&mut buf.discard, true); } // Flush preceding whitespace according to the outer WS spec @@ -972,6 +975,7 @@ impl<'a> Generator<'a> { if block_fragment_write { self.buf_writable.discard = true; } + buf.discard = prev_buf_discard; Ok(size_hint) } @@ -1813,6 +1817,7 @@ struct Buffer { indent: u8, // Whether the output buffer is currently at the start of a line start: bool, + discard: bool, } impl Buffer { @@ -1821,10 +1826,14 @@ impl Buffer { buf: String::new(), indent, start: true, + discard: false, } } fn writeln(&mut self, s: &str) -> Result<(), CompileError> { + if self.discard { + return Ok(()); + } if s == "}" { self.dedent()?; } @@ -1840,6 +1849,9 @@ impl Buffer { } fn write(&mut self, s: &str) { + if self.discard { + return; + } if self.start { for _ in 0..(self.indent * 4) { self.buf.push(' '); From 22fb4a26500c168279c4ad6706202be6124addf9 Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Thu, 2 May 2024 17:40:11 +0200 Subject: [PATCH 3/8] Fix wrong handling of nested templates with `block` --- askama_derive/src/generator.rs | 22 +++++++++++----------- testing/templates/blocks.txt | 11 +++++++++++ testing/tests/block_fragments.rs | 32 +++++++++++++++++++++++++++----- 3 files changed, 49 insertions(+), 16 deletions(-) create mode 100644 testing/templates/blocks.txt diff --git a/askama_derive/src/generator.rs b/askama_derive/src/generator.rs index 6b980f3a..6fcadc79 100644 --- a/askama_derive/src/generator.rs +++ b/askama_derive/src/generator.rs @@ -734,7 +734,7 @@ impl<'a> Generator<'a> { } }; - mem::drop(mem::replace(&mut self.buf_writable.buf, current_buf)); + self.buf_writable.buf = current_buf; let mut filter_buf = Buffer::new(buf.indent); let Filter { @@ -892,16 +892,6 @@ impl<'a> Generator<'a> { name: Option<&'a str>, outer: Ws, ) -> Result { - let block_fragment_write = self.input.block == name && self.buf_writable.discard; - - // Allow writing to the buffer if we're in the block fragment - let mut prev_buf_discard = buf.discard; - if block_fragment_write { - self.buf_writable.discard = false; - } else if self.buf_writable.discard { - prev_buf_discard = mem::replace(&mut buf.discard, true); - } - // Flush preceding whitespace according to the outer WS spec self.flush_ws(outer); @@ -920,6 +910,15 @@ impl<'a> Generator<'a> { (None, None) => return Err("cannot call 'super()' outside block".into()), }; + self.write_buf_writable(buf)?; + + let block_fragment_write = self.input.block == name && self.buf_writable.discard; + // Allow writing to the buffer if we're in the block fragment + if block_fragment_write { + self.buf_writable.discard = false; + } + let prev_buf_discard = mem::replace(&mut buf.discard, self.buf_writable.discard); + // Get the block definition from the heritage chain let heritage = self .heritage @@ -964,6 +963,7 @@ impl<'a> Generator<'a> { // Need to flush the buffer before popping the variable stack child.write_buf_writable(buf)?; } + child.flush_ws(def.ws2); self.buf_writable = child.buf_writable; diff --git a/testing/templates/blocks.txt b/testing/templates/blocks.txt new file mode 100644 index 00000000..2272d82d --- /dev/null +++ b/testing/templates/blocks.txt @@ -0,0 +1,11 @@ +{% block index %} +Section: {{ s1 }} +{% endblock %} + +{% block section -%} + [ + {%- for value in values -%} + {{ value }} + {%- endfor -%} + ] +{%- endblock %} diff --git a/testing/tests/block_fragments.rs b/testing/tests/block_fragments.rs index b84a5113..ae723b6d 100644 --- a/testing/tests/block_fragments.rs +++ b/testing/tests/block_fragments.rs @@ -11,7 +11,7 @@ struct FragmentSimple<'a> { fn test_fragment_simple() { let simple = FragmentSimple { name: "world" }; - assert_eq!(simple.render().unwrap(), "\n\n

Hello world!

\n"); + assert_eq!(simple.render().unwrap(), "\n

Hello world!

\n"); } #[derive(Template)] @@ -28,7 +28,7 @@ fn test_fragment_super() { assert_eq!( sup.render().unwrap(), - "\n\n

Hello world!

\n\n

Parent body content

\n\n" + "\n

Hello world!

\n\n

Parent body content

\n\n" ); } @@ -43,7 +43,7 @@ fn test_fragment_nested_block() { assert_eq!( nested_block.render().unwrap(), - "\n\n

I should be here.

\n" + "\n

I should be here.

\n" ); } @@ -61,7 +61,7 @@ fn test_fragment_nested_super() { assert_eq!( nested_sup.render().unwrap(), - "\n\n

Hello world!

\n\n[\n

Parent body content

\n]\n\n" + "\n

Hello world!

\n\n[\n

Parent body content

\n]\n\n" ); } @@ -79,5 +79,27 @@ fn test_fragment_unused_expression() { required: "Required", }; - assert_eq!(unused_expr.render().unwrap(), "\n\n

Required

\n"); + assert_eq!(unused_expr.render().unwrap(), "\n

Required

\n"); +} + +#[derive(Template)] +#[template(path = "blocks.txt", block = "index")] +struct RenderInPlace<'a> { + s1: Section<'a>, +} + +#[derive(Template)] +#[template(path = "blocks.txt", block = "section")] +struct Section<'a> { + values: &'a [&'a str], +} + +#[test] +fn test_specific_block() { + let s1 = Section { + values: &["a", "b", "c"], + }; + assert_eq!(s1.render().unwrap(), "[abc]"); + let t = RenderInPlace { s1 }; + assert_eq!(t.render().unwrap(), "\nSection: [abc]\n"); } From eec57523103e8455961b27c68510c190ed03260d Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Thu, 2 May 2024 17:44:36 +0200 Subject: [PATCH 4/8] Fix new rustc lints --- testing/tests/inheritance.rs | 7 +------ testing/tests/simple.rs | 1 + 2 files changed, 2 insertions(+), 6 deletions(-) diff --git a/testing/tests/inheritance.rs b/testing/tests/inheritance.rs index 87232b37..926008f6 100644 --- a/testing/tests/inheritance.rs +++ b/testing/tests/inheritance.rs @@ -329,14 +329,9 @@ fn test_flat_deep() { #[derive(Template)] #[template(path = "let-base.html")] +#[allow(dead_code)] struct LetBase {} -#[test] -fn test_let_base() { - let t = LetBase {}; - assert_eq!(t.render().unwrap(), ""); -} - #[derive(Template)] #[template(path = "let-child.html")] struct LetChild {} diff --git a/testing/tests/simple.rs b/testing/tests/simple.rs index 40121288..a8ecb76f 100644 --- a/testing/tests/simple.rs +++ b/testing/tests/simple.rs @@ -345,6 +345,7 @@ struct FunctionTemplate; impl FunctionTemplate { #[allow(clippy::trivially_copy_pass_by_ref)] + #[allow(dead_code)] fn world3(&self, s: &str, v: u8) -> String { format!("world{s}{v}") } From cbddeda78164fae8096d6cc07c3cbde7f87f7af3 Mon Sep 17 00:00:00 2001 From: Lorenzo Fontoura Date: Sat, 4 May 2024 08:06:44 +1000 Subject: [PATCH 5/8] test: partial render with block fragments --- testing/tests/block_fragments.rs | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) diff --git a/testing/tests/block_fragments.rs b/testing/tests/block_fragments.rs index b84a5113..b2aace65 100644 --- a/testing/tests/block_fragments.rs +++ b/testing/tests/block_fragments.rs @@ -81,3 +81,22 @@ fn test_fragment_unused_expression() { assert_eq!(unused_expr.render().unwrap(), "\n\n

Required

\n"); } + +/// Tests rendering a block fragment that inherits a template. +/// Only the block, i.e. the partial content, should be rendered. +#[derive(Template)] +#[template(path = "child.html", block = "content")] +struct Partial<'a> { + title: &'a str +} + +#[test] +fn test_partial_render() { + let t = Partial { + title: "the title" + }; + assert_eq!( + t.render().unwrap(), + "(the title) Content goes here" + ); +} From 8f600e06911decc85ea8ea46a819f65eb2af15b5 Mon Sep 17 00:00:00 2001 From: Lorenzo Fontoura Date: Sat, 4 May 2024 08:15:19 +1000 Subject: [PATCH 6/8] chore: gitignore .idea --- .gitignore | 1 + 1 file changed, 1 insertion(+) diff --git a/.gitignore b/.gitignore index 22d9b57e..ced7a258 100644 --- a/.gitignore +++ b/.gitignore @@ -1,3 +1,4 @@ target Cargo.lock .DS_Store +.idea \ No newline at end of file From cfd03d1ba363d756fbdaa940bec43c129fd9943b Mon Sep 17 00:00:00 2001 From: Lorenzo Date: Sat, 4 May 2024 20:54:31 +1000 Subject: [PATCH 7/8] chore: add backline --- .gitignore | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/.gitignore b/.gitignore index ced7a258..2f503d44 100644 --- a/.gitignore +++ b/.gitignore @@ -1,4 +1,5 @@ target Cargo.lock .DS_Store -.idea \ No newline at end of file +.idea + From 85520c71fc23fd3db3f0b62b989375238756cc30 Mon Sep 17 00:00:00 2001 From: Lorenzo Fontoura Date: Wed, 14 Aug 2024 11:25:13 +1000 Subject: [PATCH 8/8] fix: trim --- testing/tests/block_fragments.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/testing/tests/block_fragments.rs b/testing/tests/block_fragments.rs index c8290697..c9e8d0c4 100644 --- a/testing/tests/block_fragments.rs +++ b/testing/tests/block_fragments.rs @@ -118,7 +118,7 @@ fn test_partial_render() { title: "the title" }; assert_eq!( - t.render().unwrap(), + t.render().unwrap().trim(), "(the title) Content goes here" ); }