From 2bc0ea9cebeda00b0b23d633ee87cbc819829fd8 Mon Sep 17 00:00:00 2001
From: Mike Bayer <mike_mp@zzzcomputing.com>
Date: Fri, 5 Mar 2010 01:55:41 +0000
Subject: [PATCH] - A percent sign can be emitted as the first   non-whitespace
 character on a line by escaping   it as in "%%". [ticket:112]

---
 CHANGES                      |  4 ++++
 doc/build/content/syntax.txt |  9 +++++++--
 mako/ext/pygmentplugin.py    |  4 ++--
 mako/lexer.py                |  2 +-
 test/test_lexer.py           | 15 +++++++++++++++
 5 files changed, 29 insertions(+), 5 deletions(-)

diff --git a/CHANGES b/CHANGES
index badefd8..91bfa09 100644
--- a/CHANGES
+++ b/CHANGES
@@ -25,6 +25,10 @@
   format_exceptions=True will now be as a Python
   unicode if it occurred during render_unicode(),
   or an encoded string if during render().
+
+- A percent sign can be emitted as the first
+  non-whitespace character on a line by escaping
+  it as in "%%". [ticket:112]
   
 0.2.6
 
diff --git a/doc/build/content/syntax.txt b/doc/build/content/syntax.txt
index d71971c..565687d 100644
--- a/doc/build/content/syntax.txt
+++ b/doc/build/content/syntax.txt
@@ -46,7 +46,14 @@ The `%` can appear anywhere on the line as long as no text precedes it; indentat
         one
         %endif
     % endfor
+
+The `%` sign can also be "escaped", if you actually want to emit a percent sign as the first non whitespace character on a line, by escaping it as in `%%`:
+
+    %% some text
     
+        %% some more text
+
+
 ### Comments
 
 Comments come in two varieties.  The single line comment uses `##` as the first non-space characters on a line:
@@ -61,8 +68,6 @@ A multiline version exists using `<%doc>  ...text... </%doc>`:
         more comments
     </%doc>
 
-Note that this is **new behavior as of Mako 0.1.3**.  The syntax prior to this version was the single pound sign (`#`), which was agreed by the Mako userbase that it conflicted with CSS elements too often and also did not address multiline comments easily.
-
 ### Newline Filters
 
 The backslash ("`\`") character, placed at the end of any line, will consume the newline character before continuing to the next line:
diff --git a/mako/ext/pygmentplugin.py b/mako/ext/pygmentplugin.py
index 09ffe12..2e7ff0d 100644
--- a/mako/ext/pygmentplugin.py
+++ b/mako/ext/pygmentplugin.py
@@ -22,7 +22,7 @@ class MakoLexer(RegexLexer):
         'root': [
             (r'(\s*)(\%)(\s*end(?:\w+))(\n|\Z)',
              bygroups(Text, Comment.Preproc, Keyword, Other)),
-            (r'(\s*)(\%)([^\n]*)(\n|\Z)',
+            (r'(\s*)(\%(?!%))([^\n]*)(\n|\Z)',
              bygroups(Text, Comment.Preproc, using(PythonLexer), Other)),
              (r'(\s*)(##[^\n]*)(\n|\Z)',
               bygroups(Text, Comment.Preproc, Other)),
@@ -36,7 +36,7 @@ class MakoLexer(RegexLexer):
             (r'''(?sx)
                 (.+?)               # anything, followed by:
                 (?:
-                 (?<=\n)(?=%|\#\#) |  # an eval or comment line
+                 (?<=\n)(?=%(?!%)|\#\#) |  # an eval or comment line
                  (?=\#\*) |          # multiline comment
                  (?=</?%) |         # a python block
                                     # call start or end
diff --git a/mako/lexer.py b/mako/lexer.py
index 5e4a3bc..34fe80b 100644
--- a/mako/lexer.py
+++ b/mako/lexer.py
@@ -371,7 +371,7 @@ class Lexer(object):
             return False
 
     def match_control_line(self):
-        match = self.match(r"(?<=^)[\t ]*(%|##)[\t ]*((?:(?:\\r?\n)|[^\r\n])*)(?:\r?\n|\Z)", re.M)
+        match = self.match(r"(?<=^)[\t ]*(%(?!%)|##)[\t ]*((?:(?:\\r?\n)|[^\r\n])*)(?:\r?\n|\Z)", re.M)
         if match:
             operator = match.group(1)
             text = match.group(2)
diff --git a/test/test_lexer.py b/test/test_lexer.py
index 00d16af..2f6a61c 100644
--- a/test/test_lexer.py
+++ b/test/test_lexer.py
@@ -106,6 +106,21 @@ class LexerTest(TemplateTest):
         """
         
         self.assertRaises(exceptions.CompileException, Lexer(template).parse)
+    
+    def test_percent_escape(self):
+        template = """
+        
+%% some whatever.
+
+    %% more some whatever
+    % if foo:
+    % endif
+        """
+        node = Lexer(template).parse()
+        self._compare(
+            node,
+            TemplateNode({}, [Text(u'\n        \n', (1, 1)), Text(u'', (3, 1)), Text(u'% some whatever.\n\n', (3, 2)), Text(u'', (5, 1)), Text(u'   %% more some whatever\n', (5, 2)), ControlLine(u'if', u'if foo:', False, (6, 1)), ControlLine(u'if', u'endif', True, (7, 1)), Text(u'        ', (8, 1))])
+        )
         
     def test_text_tag(self):
         template = """
-- 
GitLab