Repository: mitsuhiko/minijinja (rust)

Issue:
`lstrip_blocks` differs from jinja2's `lstrip_blocks`
## Description
`lstrip_blocks` in minijinja handles whitespace inside a block differently from `lstrip_blocks` in jinja2.
minijinja removes whitespace inside the block, whereas jinja2 doesn't.

## Reproduction steps
Rust's output here is empty but python has `' '` as output:

```rs
use minijinja::{context, Environment};

fn main() {
    let mut env = Environment::new();

    env.set_lstrip_blocks(true);

    env.add_template("template", "{% if 1 %} {% endif %}")
        .unwrap();

    let out = env
        .get_template("template")
        .unwrap()
        .render(context! {})
        .unwrap();

    assert_eq!(out, "");
}
```

```py
from jinja2 import Environment

out = Environment(lstrip_blocks=True).from_string('{% if 1 %} {% endif %}').render()
assert out == ' '
```

The same happens with `'\t'` instead of a space.

Additional helpful information:

- Version of minijinja:
- Version of rustc: `v1.83.0-nightly`
- Operating system and version: Ubuntu 24.04

## What did you expect

I would expect the output of miinijinja to match the output of jinja2.
If not, it should probably be added to `COMPATIBILITY.md`




Pull request:
Fix lstrip_blocks being too eager
This is an AI generated fix.  Will clean this up.

Fixes #672

Patch:
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 476d63c..36dbdb0 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -21,6 +21,7 @@ All notable changes to MiniJinja are documented here.
   iterators that were projected from objects.  #663
 - The `|items` filter will no longer allocate a list and instead
   return an iterator.  #665
+- Fixed a bug that caused `lstrip_blocks` to act too eager.  #674
 
 ## 2.5.0
 
diff --git a/minijinja/src/compiler/lexer.rs b/minijinja/src/compiler/lexer.rs
index 24bb236..b6da6c3 100644
--- a/minijinja/src/compiler/lexer.rs
+++ b/minijinja/src/compiler/lexer.rs
@@ -228,8 +228,17 @@ fn lstrip_block(s: &str) -> &str {
     }
 }
 
-fn should_lstrip_block(flag: bool, marker: StartMarker) -> bool {
+fn should_lstrip_block(flag: bool, marker: StartMarker, prefix: &str) -> bool {
     if flag && !matches!(marker, StartMarker::Variable) {
+        // Only strip if we're at the start of a line
+        for c in prefix.chars().rev() {
+            if is_nl(c) {
+                return true;
+            } else if !c.is_whitespace() {
+                return false;
+            }
+        }
+        // If we get here, we're at the start of the file
         return true;
     }
     #[cfg(feature = "custom_syntax")]
@@ -600,7 +609,11 @@ impl<'s> Tokenizer<'s> {
                     self.pending_start_marker = Some((marker, len));
                     match whitespace {
                         Whitespace::Default
-                            if should_lstrip_block(self.ws_config.lstrip_blocks, marker) =>
+                            if should_lstrip_block(
+                                self.ws_config.lstrip_blocks,
+                                marker,
+                                &self.source[..self.current_offset + start],
+                            ) =>
                         {
                             let peeked = &self.rest()[..start];
                             let trimmed = lstrip_block(peeked);


Test patch:
diff --git a/minijinja/tests/lexer-inputs/lstrip-blocks-keep-inline-space.txt b/minijinja/tests/lexer-inputs/lstrip-blocks-keep-inline-space.txt
new file mode 100644
index 0000000..c774384
--- /dev/null
+++ b/minijinja/tests/lexer-inputs/lstrip-blocks-keep-inline-space.txt
@@ -0,0 +1,5 @@
+{
+  "lstrip_blocks": true
+}
+---
+[{% if true %} {% endif %}]
diff --git a/minijinja/tests/snapshots/test_lexer__lexer@lstrip-blocks-keep-inline-space.txt.snap b/minijinja/tests/snapshots/test_lexer__lexer@lstrip-blocks-keep-inline-space.txt.snap
new file mode 100644
index 0000000..71addbe
--- /dev/null
+++ b/minijinja/tests/snapshots/test_lexer__lexer@lstrip-blocks-keep-inline-space.txt.snap
@@ -0,0 +1,25 @@
+---
+source: minijinja/tests/test_lexer.rs
+description: "[{% if true %} {% endif %}]"
+input_file: minijinja/tests/lexer-inputs/lstrip-blocks-keep-inline-space.txt
+---
+TemplateData("[")
+  "["
+BlockStart
+  "{%"
+Ident("if")
+  "if"
+Ident("true")
+  "true"
+BlockEnd
+  "%}"
+TemplateData(" ")
+  " "
+BlockStart
+  "{%"
+Ident("endif")
+  "endif"
+BlockEnd
+  "%}"
+TemplateData("]")
+  "]"