From: Armin Ronacher Date: Mon, 19 Mar 2007 23:14:10 +0000 (+0100) Subject: [svn] implemented {% raw %} and improved jinja/django highlighter X-Git-Tag: 2.0rc1~413 X-Git-Url: http://git.tremily.us/?a=commitdiff_plain;h=b9c8ae1bcd1b948757be4dfeb1ca9c73cbdd5c05;p=jinja2.git [svn] implemented {% raw %} and improved jinja/django highlighter --HG-- branch : trunk --- diff --git a/docs/src/designerdoc.txt b/docs/src/designerdoc.txt index df3ca95..77700c0 100644 --- a/docs/src/designerdoc.txt +++ b/docs/src/designerdoc.txt @@ -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 %} -*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 %} + + goes here + + {% 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 diff --git a/jdebug.py b/jdebug.py index 95f10cc..5de8815 100644 --- a/jdebug.py +++ b/jdebug.py @@ -10,13 +10,18 @@ """ 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 diff --git a/jinja/lexer.py b/jinja/lexer.py index 2793c50..7a442d1 100644 --- a/jinja/lexer.py +++ b/jinja/lexer.py @@ -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 diff --git a/jinja/parser.py b/jinja/parser.py index 11d031f..cafa45c 100644 --- a/jinja/parser.py +++ b/jinja/parser.py @@ -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 diff --git a/jinja/translators/python.py b/jinja/translators/python.py index 0a53a62..6c8ba94 100644 --- a/jinja/translators/python.py +++ b/jinja/translators/python.py @@ -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 diff --git a/jinja/utils.py b/jinja/utils.py index 83746e3..4646d1d 100644 --- a/jinja/utils.py +++ b/jinja/utils.py @@ -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):