From ff8ce2e128098560e3988bb2375a49fa8649d3d5 Mon Sep 17 00:00:00 2001 From: Hai Zhu <35182391+cocolato@users.noreply.github.com> Date: Fri, 26 Jan 2024 14:01:24 +0000 Subject: [PATCH] don't replace percent when it is not the first non-whitespace character --- mako/lexer.py | 17 +++++++++--- test/test_lexer.py | 63 ++++++++++++++++++++++++++++++++++++------- test/test_template.py | 18 +++++++++++++ 3 files changed, 84 insertions(+), 14 deletions(-) diff --git a/mako/lexer.py b/mako/lexer.py index 8ce3fd6..15975b4 100644 --- a/mako/lexer.py +++ b/mako/lexer.py @@ -247,6 +247,8 @@ def parse(self): continue if self.match_python_block(): continue + if self.match_percent(): + continue if self.match_text(): continue @@ -352,18 +354,25 @@ def match_end(self): else: return True + def match_percent(self): + match = self.match(r"(?<=^)(\s*)%%(%*)", re.M) + if match: + self.append_node( + parsetree.Text, match.group(1) + "%" + match.group(2) + ) + return True + else: + return False + def match_text(self): match = self.match( r""" (.*?) # anything, followed by: ( - (?<=\n)(?=[ \t]*(?=%(?!%)|\#\#)) # an eval or line-based + (?<=\n)(?=[ \t]*(?=%|\#\#)) # an eval or line-based # comment, preceded by a # consumed newline and whitespace | - (?:\n ", (2, 2) - ), - Text("%%% do something\n ", (4, 6)), + Text("%", (1, 1)), + Text(" do something\n", (1, 3)), + Text("%%", (2, 1)), + Text(" do something\nif :\n", (2, 4)), + Text(" %%%", (4, 1)), + Text(" do something\n ", (4, 9)), ], ), ) @@ -245,8 +247,8 @@ def test_percent_escape_with_control_block(self): [ Text("\n", (1, 1)), ControlLine("for", "for i in [1, 2, 3]:", False, (2, 1)), - Text(" ", (3, 1)), - Text("% do something ", (3, 6)), + Text(" %", (3, 1)), + Text(" do something ", (3, 7)), Expression("i", [], (3, 21)), Text("\n", (3, 25)), ControlLine("for", "endfor", True, (4, 1)), @@ -254,6 +256,47 @@ def test_percent_escape_with_control_block(self): ), ) + def test_inline_percent(self): + template = """ +%% foo +bar %% baz +""" + node = Lexer(template).parse() + self._compare( + node, + TemplateNode( + {}, + [Text("\n%", (1, 1)), Text(" foo\nbar %% baz\n", (2, 3))], + ), + ) + + def test_inline_percent_with_control_block(self): + template = """ +% for i in [1, 2, 3]: +%% foo +bar %% baz +% endfor +""" + node = Lexer(template).parse() + self._compare( + node, + TemplateNode( + {}, + [ + Text("\n", (1, 1)), + ControlLine( + "for", "for i in [1, 2, 3]:", False, (2, 1) + ), + Text("%", (3, 1)), + Text(" foo\nbar ", (3, 3)), + Text("%", (3, 3)), + Text("%", (3, 3)), + Text(" baz\n", (4, 7)), + ControlLine("for", "endfor", True, (5, 1)), + ], + ), + ) + def test_old_multiline_comment(self): template = """#*""" node = Lexer(template).parse() diff --git a/test/test_template.py b/test/test_template.py index 79017f7..e03415e 100644 --- a/test/test_template.py +++ b/test/test_template.py @@ -1699,3 +1699,21 @@ def test_percent_escape2(self): " % do something 2", " % do something 3", ] + + def test_inline_percent(self): + t = Template( + """ +% for i in [1, 2, 3]: +%% foo +bar %% baz +% endfor +""" + ) + assert result_raw_lines(t.render()) == [ + "% foo", + "bar %% baz", + "% foo", + "bar %% baz", + "% foo", + "bar %% baz", + ]