[svn] implemented {% raw %} and improved jinja/django highlighter
authorArmin Ronacher <armin.ronacher@active-4.com>
Mon, 19 Mar 2007 23:14:10 +0000 (00:14 +0100)
committerArmin Ronacher <armin.ronacher@active-4.com>
Mon, 19 Mar 2007 23:14:10 +0000 (00:14 +0100)
--HG--
branch : trunk

docs/src/designerdoc.txt
jdebug.py
jinja/lexer.py
jinja/parser.py
jinja/translators/python.py
jinja/utils.py

index df3ca95eb2cbeb00176d33ea2622333689d0b4c9..77700c0fb4a0f8d61e91476191e4dc192ddf42bc 100644 (file)
@@ -119,6 +119,23 @@ These tests are especially useful when used in `if` conditions.
 
 [[list_of_tests]]
 
+Global Functions
+================
+
+Test functions and filter functions live in their own namespace. Global
+functions not. They behave like normal objects in the context. Beside the
+functions added by the application or framewhere there are two functions
+available per default:
+
+`range`
+    
+    Works like the python `range function`_ just that it doesn't support
+    ranges greater than ``1000000``.
+
+`debug`
+
+    Function that outputs the contents of the context.
+
 Loops
 =====
 
@@ -136,7 +153,7 @@ normal Python `for` loop and works pretty much the same:
     {% endfor %}
     </ul>
 
-*Important difference from Python:* the optional ``else`` block is only
+*Important* Contrary to Python is the optional ``else`` block only
 executed if there was no iteration because the sequence was empty.
 
 Inside of a `for` loop block you can access some special variables:
@@ -580,6 +597,31 @@ attribute calls return undefined, calling too:
     {{ undefined.attribute().attribute_too[42] }}
         still returns `undefined`.
 
+Escaping
+========
+
+Sometimes you might want to add Jinja syntax elements into the template
+without executing them. In that case you have quite a few possibilities.
+
+For small parts this might be a good way:
+
+.. sourcecode:: jinja
+
+    {{ "{{ foo }} is variable syntax and {% foo %} is block syntax" }}
+
+When you have multiple elements you can use the ``raw`` block:
+
+.. sourcecode:: jinja
+
+    {% raw %}
+        Filtering blocks works like this in Jinja:
+        {% filter escape %}
+            <html>
+              <code>goes here</code>
+            </html>
+        {% endfilter %}
+    {% endraw %}
+
 Internationalization
 ====================
 
@@ -619,9 +661,10 @@ number that is used to determine the correct singular or plural form. If you
 don't have the indicator variable on position 1 you have to tell the `pluralize`
 tag the correct variable name.
 
-Inside translatable blocks you cannot use blocks or expressions. The variable
-print syntax (``{{ variablename }}``) can just be used to insert the variables defined
-in the ``trans`` header.
+Inside translatable blocks you cannot use blocks or expressions (however you can
+still use the ``raw`` block which will work as expected). The variable
+print syntax (``{{ variablename }}``) is the only way to insert the variables
+defined in the ``trans`` header. Filters must be applied in the header.
 
 .. admonition:: note
 
@@ -639,3 +682,4 @@ in the ``trans`` header.
         {% endif %}
 
 .. _slicing chapter: http://diveintopython.org/native_data_types/lists.html#odbchelper.list.slice
+.. _range function: http://docs.python.org/tut/node6.html#SECTION006300000000000000000
index 95f10cc29e87c14a9461e11055a2c4ee955e7757..5de88155f6ccd013be5850142c576ac24323be65 100644 (file)
--- a/jdebug.py
+++ b/jdebug.py
 """
 from jinja import Environment
 from jinja.parser import Parser
+from jinja.lexer import Lexer
 from jinja.translators.python import PythonTranslator
 
 
-__all__ = ['e', 't', 'p']
+__all__ = ['e', 't', 'p', 'l']
 
 e = Environment()
 t = e.from_string
 
 def p(x):
     print PythonTranslator(e, Parser(e, x).parse()).translate()
+
+def l(x):
+    for item in e.lexer.tokenize(x):
+        print '%5s  %-20s  %r' % item
index 2793c5019cbc56afaa0217691aee3cb12632ca07..7a442d13a4c34856bd4de1f86fdcfbea2a36217e 100644 (file)
@@ -90,6 +90,10 @@ class Lexer(object):
         # global parsing rules
         self.rules = {
             'root': [
+                (c('(%s\s*raw\s%s)(.*?)(%s\s*endraw\s*%s)' % (
+                    (e(environment.block_start_string),
+                     e(environment.block_end_string)) * 2)),
+                   (None, 'data', None), None),
                 (c('(.*?)(?:%s)' % '|'.join([
                     '(?P<%s_begin>%s)' % (n, e(r)) for n, r in root_tag_rules
                 ])), ('data', '#bygroup'), '#bygroup'),
@@ -150,7 +154,7 @@ class Lexer(object):
                         for idx, token in enumerate(tokens):
                             # hidden group
                             if token is None:
-                                g += m.group(idx)
+                                g = m.group(idx)
                                 if g:
                                     lineno += g.count('\n')
                                 continue
index 11d031fdaab1ca3a10990e9029a7936850e193b5..cafa45c16bcd5df4cfe4a5a5c642e7594e343df8 100644 (file)
@@ -480,7 +480,7 @@ class Parser(object):
             # here the only token we should get is "data". all other
             # tokens just exist in block or variable sections. (if the
             # tokenizer is not brocken)
-            elif token == 'data':
+            elif token in 'data':
                 result.append(nodes.Text(lineno, data))
 
             # so this should be unreachable code
index 0a53a62e246b33496fa14da26d5f50fe39e9f90f..6c8ba9492fd47e1bb029a809c03a382d0b6a56c2 100644 (file)
@@ -173,6 +173,8 @@ class PythonTranslator(Translator):
         Return a comment that helds the node informations or None
         if there is no need to add a debug comment.
         """
+        if node.filename is None:
+            return
         rv = '# DEBUG(filename=%s, lineno=%s)' % (
             node.filename,
             node.lineno
index 83746e3a73bb7934b821544741d366b281978e07..4646d1dc832a5eac0f6950b6f16b2cc8642174b5 100644 (file)
@@ -203,17 +203,16 @@ def translate_exception(template, exc_type, exc_value, traceback, context):
         if m is not None:
             filename, lineno = m.groups()
             if filename == 'None':
-                filename = ''
-            if lineno == 'None':
-                lineno = 0
-            else:
+                filename = None
+            if lineno != 'None':
                 lineno = int(lineno)
             break
         startpos -= 1
 
     # no traceback information found, reraise unchanged
-    if filename is None:
+    if not filename:
         return traceback
+
     return raise_template_exception(exc_value, filename,
                                     lineno, context)
 
@@ -317,17 +316,10 @@ class CacheDict(object):
             self._queue = []
             pop = self._queue.pop
             self._popleft = lambda: pop(0)
+
         # alias all queue methods for faster lookup
         self._pop = self._queue.pop
-
-        # XXX: Is this good? Didn't find another sollution
-        def remove_by_value(value):
-            for i, v in enumerate(self._queue):
-                if v == value:
-                    self._queue.__delitem__(i)
-                    break
-
-        self._remove = remove_by_value
+        self._remove = self._queue.remove
         self._append = self._queue.append
 
     def copy(self):