diff options
| -rw-r--r-- | docs/news.txt | 3 | ||||
| -rw-r--r-- | paste/util/template.py | 59 | ||||
| -rw-r--r-- | tests/test_template.txt | 11 |
3 files changed, 68 insertions, 5 deletions
diff --git a/docs/news.txt b/docs/news.txt index 00274bb..e886faf 100644 --- a/docs/news.txt +++ b/docs/news.txt @@ -20,6 +20,9 @@ svn trunk * ``egg:Paste#watch_threads`` will show tracebacks of each thread under Python 2.5. +* Made ``paste.util.template`` trim whitespace around statements that + are on their own line. + 1.2.1 ----- diff --git a/paste/util/template.py b/paste/util/template.py index 977a4e1..d76f6b3 100644 --- a/paste/util/template.py +++ b/paste/util/template.py @@ -358,7 +358,7 @@ def sub_html(content, **kw): ## Lexing and Parsing ############################################################ -def lex(s, name=None): +def lex(s, name=None, trim_whitespace=True): """ Lex a string into chunks: @@ -409,8 +409,59 @@ def lex(s, name=None): part = s[last:] if part: chunks.append(part) + if trim_whitespace: + chunks = trim_lex(chunks) return chunks +statement_re = re.compile(r'^(?:if |elif |else |for |py:)') +single_statements = ['endif', 'endfor', 'continue', 'break'] +trail_whitespace_re = re.compile(r'\n[\t ]*$') +lead_whitespace_re = re.compile(r'^[\t ]*\n') + +def trim_lex(tokens): + r""" + Takes a lexed set of tokens, and removes whitespace when there is + a directive on a line by itself: + + >>> tokens = lex('{{if x}}\nx\n{{endif}}\ny', trim_whitespace=False) + >>> tokens + [('if x', (1, 3)), '\nx\n', ('endif', (3, 3)), '\ny'] + >>> trim_lex(tokens) + [('if x', (1, 3)), 'x\n', ('endif', (3, 3)), 'y'] + """ + for i in range(len(tokens)): + current = tokens[i] + if isinstance(tokens[i], basestring): + # we don't trim this + continue + item = current[0] + if not statement_re.search(item) and item not in single_statements: + continue + if not i: + prev = '' + else: + prev = tokens[i-1] + if i+1 >= len(tokens): + next = '' + else: + next = tokens[i+1] + if (not isinstance(next, basestring) + or not isinstance(prev, basestring)): + continue + if ((not prev or trail_whitespace_re.search(prev)) + and (not next or lead_whitespace_re.search(next))): + if prev: + m = trail_whitespace_re.search(prev) + # +1 to leave the leading \n on: + prev = prev[:m.start()+1] + tokens[i-1] = prev + if next: + m = lead_whitespace_re.search(next) + next = next[m.end():] + tokens[i+1] = next + return tokens + + def find_position(string, index): """Given a string and index, return (line, column)""" leading = string[:index].splitlines() @@ -547,9 +598,9 @@ def parse_one_cond(tokens, name, context): 'No {{endif}}', position=pos, name=name) if (isinstance(tokens[0], tuple) - and tokens[0][0] == 'endif' - or tokens[0][0].startswith('elif ') - or tokens[0][0] == 'else'): + and (tokens[0][0] == 'endif' + or tokens[0][0].startswith('elif ') + or tokens[0][0] == 'else')): return part, tokens next, tokens = parse_expr(tokens, name, context) content.append(next) diff --git a/tests/test_template.txt b/tests/test_template.txt index 9765011..a56049f 100644 --- a/tests/test_template.txt +++ b/tests/test_template.txt @@ -106,4 +106,13 @@ in Python, but it's more useful in templates generally):: 3 Banana O: 4 orange -
\ No newline at end of file + +It will also strip out empty lines, when there is a line that only +contains a directive/statement (if/for, etc):: + + >>> sub('{{if 1}}\n{{x}}\n{{endif}}\n', x=0) + '0\n' + >>> sub('{{if 1}}x={{x}}\n{{endif}}\n', x=1) + 'x=1\n' + >>> sub('{{if 1}}\nx={{x}}\n{{endif}}\n', x=1) + 'x=1\n' |
