From 3acf8b050dbb63f4d93d8d917d59865fe3c2ce93 Mon Sep 17 00:00:00 2001 From: adnrs96 Date: Fri, 17 Feb 2017 00:55:53 +0530 Subject: [PATCH] Add Django and html singleton tags support to pretty print. In this commit we are modifying pretty print tool to support Django and html singleton tags. For Addition of html singleton tags template parser was modified to emit psudeo html singleton end tags to accompany html singleton tags and token class was updated to have line_span field. --- tools/lib/pretty_print.py | 77 +++++++++++++++++++------------- tools/lib/template_parser.py | 20 ++++++++- tools/tests/test_pretty_print.py | 44 ++++++++++++++++++ 3 files changed, 107 insertions(+), 34 deletions(-) diff --git a/tools/lib/pretty_print.py b/tools/lib/pretty_print.py index 71380f4e52..116c68b6d2 100644 --- a/tools/lib/pretty_print.py +++ b/tools/lib/pretty_print.py @@ -38,39 +38,50 @@ def pretty_print_html(html, num_spaces=4): # we proceed, we will push/pop info dictionaries on/off a stack. for token in tokens: - if token.kind in ('html_start', 'handlebars_start'): + if token.kind in ('html_start', 'handlebars_start', + 'html_singleton', 'django_start'): # An HTML start tag should only cause a new indent if we # are on a new line. - is_block = token.line > stack[-1]['line'] + if token.tag not in ('extends', 'include', 'else', 'elif'): + is_block = token.line > stack[-1]['line'] - if is_block: - if token.kind == 'handlebars_start' and stack[-1]['token_kind'] == 'handlebars_start': - info = stack.pop() - info['depth'] = info['depth'] + 1 - stack.append(info) - new_depth = stack[-1]['depth'] + 1 - extra_indent = stack[-1]['extra_indent'] - line = lines[token.line - 1] - adjustment = len(line)-len(line.lstrip()) + 1 - offset = (1 + extra_indent + new_depth * num_spaces) - adjustment - info = dict( - block=True, - depth=new_depth, - actual_depth=new_depth, - line=token.line, - token_kind=token.kind, - offset=offset, - extra_indent=token.col - adjustment + extra_indent - ) - if token.kind == 'handlebars_start': - info.update(dict(depth=new_depth - 1)) - else: - info = dict( - block=False, - line=token.line - ) - stack.append(info) - elif token.kind in ('html_end', 'handlebars_end'): + if is_block: + if (token.kind == 'handlebars_start' and + stack[-1]['token_kind'] == 'handlebars_start' and + not stack[-1]['indenting']): + info = stack.pop() + info['depth'] = info['depth'] + 1 + info['indenting'] = True + stack.append(info) + new_depth = stack[-1]['depth'] + 1 + extra_indent = stack[-1]['extra_indent'] + line = lines[token.line - 1] + adjustment = len(line)-len(line.lstrip()) + 1 + offset = (1 + extra_indent + new_depth * num_spaces) - adjustment + info = dict( + block=True, + depth=new_depth, + actual_depth=new_depth, + line=token.line, + token_kind=token.kind, + offset=offset, + extra_indent=token.col - adjustment + extra_indent, + indenting=True + ) + if token.kind == 'handlebars_start': + info.update(dict(depth=new_depth - 1, indenting=False)) + else: + info = dict( + block=False, + depth=stack[-1]['depth'], + actual_depth=stack[-1]['depth'], + line=token.line, + token_kind=token.kind, + extra_indent=stack[-1]['extra_indent'] + ) + stack.append(info) + elif token.kind in ('html_end', 'handlebars_end', + 'html_singleton_end', 'django_end'): info = stack.pop() if info['block']: # We are at the end of an indentation block. We @@ -81,14 +92,16 @@ def pretty_print_html(html, num_spaces=4): end_line = token.line offsets[start_line] = info['offset'] offsets[end_line] = info['offset'] - if token.tag != 'pre': + if token.tag != 'pre' and token.kind != 'html_singleton_end' and token.tag != 'script': for line_num in range(start_line + 1, end_line): # Be careful not to override offsets that happened # deeper in the HTML within our block. if line_num not in offsets: line = lines[line_num - 1] new_depth = info['depth'] + 1 - if line.lstrip().startswith('{{else}}'): + if (line.lstrip().startswith('{{else}}') or + line.lstrip().startswith('{% else %}') or + line.lstrip().startswith('{% elif')): new_depth = info['actual_depth'] extra_indent = info['extra_indent'] adjustment = len(line)-len(line.lstrip()) + 1 diff --git a/tools/lib/template_parser.py b/tools/lib/template_parser.py index 32a1db8b58..db4902a48e 100644 --- a/tools/lib/template_parser.py +++ b/tools/lib/template_parser.py @@ -27,13 +27,14 @@ class TokenizerState(object): self.col = 1 class Token(object): - def __init__(self, kind, s, tag, line, col): - # type: (str, str, str, int, int) -> None + def __init__(self, kind, s, tag, line, col, line_span): + # type: (str, str, str, int, int, int) -> None self.kind = kind self.s = s self.tag = tag self.line = line self.col = col + self.line_span = line_span def tokenize(text): # type: (str) -> List[Token] @@ -131,15 +132,30 @@ def tokenize(text): (e.message, state.line, state.col, e.line_content)) + line_span = len(s.split('\n')) token = Token( kind=kind, s=s, tag=tag, line=state.line, col=state.col, + line_span=line_span ) tokens.append(token) advance(len(s)) + if kind == 'html_singleton': + # Here we insert a Pseudo html_singleton_end tag so as to have + # ease of detection of end of singleton html tags which might be + # needed in some cases as with our html pretty printer. + token = Token( + kind='html_singleton_end', + s='', + tag=tag, + line=state.line, + col=state.col, + line_span=1 + ) + tokens.append(token) return tokens diff --git a/tools/tests/test_pretty_print.py b/tools/tests/test_pretty_print.py index 9c773afd4c..2cda9758ea 100644 --- a/tools/tests/test_pretty_print.py +++ b/tools/tests/test_pretty_print.py @@ -188,6 +188,48 @@ GOOD_HTML6 = """

foobar

""" + +BAD_HTML7 = """ +
+ {{dyn_name}} +{{#if invite_only}}{{/if}} +
+""" + +GOOD_HTML7 = """ +
+ {{dyn_name}} + {{#if invite_only}}{{/if}} +
+""" + +BAD_HTML8 = """ +{{#each test}} + {{#with this}} + {{#if foobar}} +
{{{test}}}
+ {{/if}} + {{#if foobar2}} + {{partial "teststuff"}} + {{/if}} + {{/with}} +{{/each}} +""" + +GOOD_HTML8 = """ +{{#each test}} + {{#with this}} + {{#if foobar}} +
{{{test}}}
+ {{/if}} + {{#if foobar2}} + {{partial "teststuff"}} + {{/if}} + {{/with}} +{{/each}} +""" class TestPrettyPrinter(unittest.TestCase): def compare(self, a, b): # type: (str, str) -> None @@ -203,3 +245,5 @@ class TestPrettyPrinter(unittest.TestCase): self.compare(pretty_print_html(BAD_HTML4), GOOD_HTML4) self.compare(pretty_print_html(BAD_HTML5), GOOD_HTML5) self.compare(pretty_print_html(BAD_HTML6), GOOD_HTML6) + self.compare(pretty_print_html(BAD_HTML7), GOOD_HTML7) + self.compare(pretty_print_html(BAD_HTML8), GOOD_HTML8)