linters: Rewrite check-templates.

I rewrote most of tools/lib/pretty-printer.py, which
was fairly easy due to being able to crib some
important details from the previous implementation.

The main motivation for the rewrite was that we weren't
handling else/elif blocks correctly, and it was difficult
to modify the previous code. The else/elif shortcomings
were somewhat historical in nature--the original parser
didn't recognize them (since they weren't in any Zulip
templates at the time), and then the pretty printer was
mostly able to hack around that due to the "nudge"
strategy. Eventually the nudge strategy became too
brittle.

The "nudge" strategy was that we would mostly trust
the existing templates, and we would just nudge over
some lines in cases of obviously faulty indentation.

Now we are bit more opinionated and rigorous, and
we basically set the indentation explicitly for any
line that is not in a code/script block. This leads
to this diff touching several templates for mostly
minor fix-ups.

We aren't completely opinionated, as we respect the
author's line wrapping decisions in many cases, and
we also allow authors not to indent blocks within
the template language's block constructs.
This commit is contained in:
Steve Howell
2021-11-20 12:25:41 +00:00
committed by Tim Abbott
parent 4792af5682
commit fdd63546b2
27 changed files with 389 additions and 306 deletions

View File

@@ -70,11 +70,17 @@ def tokenize(text: str) -> List[Token]:
def looking_at_handlebars_start() -> bool:
return looking_at("{{#") or looking_at("{{^")
def looking_at_handlebars_else() -> bool:
return looking_at("{{else")
def looking_at_handlebars_end() -> bool:
return looking_at("{{/")
def looking_at_django_start() -> bool:
return looking_at("{% ") and not looking_at("{% end")
return looking_at("{% ")
def looking_at_django_else() -> bool:
return looking_at("{% else") or looking_at("{% elif")
def looking_at_django_end() -> bool:
return looking_at("{% end")
@@ -130,6 +136,10 @@ def tokenize(text: str) -> List[Token]:
s = get_html_tag(text, state.i)
tag = s[2:-1]
kind = "html_end"
elif looking_at_handlebars_else():
s = get_handlebars_tag(text, state.i)
tag = "else"
kind = "handlebars_else"
elif looking_at_handlebars_start():
s = get_handlebars_tag(text, state.i)
tag = s[3:-2].split()[0]
@@ -140,17 +150,22 @@ def tokenize(text: str) -> List[Token]:
s = get_handlebars_tag(text, state.i)
tag = s[3:-2]
kind = "handlebars_end"
elif looking_at_django_else():
s = get_django_tag(text, state.i)
tag = "else"
kind = "django_else"
elif looking_at_django_end():
s = get_django_tag(text, state.i)
tag = s[6:-3]
kind = "django_end"
elif looking_at_django_start():
# must check this after end/else
s = get_django_tag(text, state.i)
tag = s[3:-2].split()[0]
kind = "django_start"
if s[-3] == "-":
kind = "jinja2_whitespace_stripped_start"
elif looking_at_django_end():
s = get_django_tag(text, state.i)
tag = s[6:-3]
kind = "django_end"
elif looking_at_jinja2_end_whitespace_stripped():
s = get_django_tag(text, state.i)
tag = s[7:-3]
@@ -284,6 +299,7 @@ def validate(
state.foreign = True
def f(end_token: Token) -> None:
is_else_tag = end_token.tag == "else"
end_tag = end_token.tag.strip("~")
end_line = end_token.line
@@ -297,9 +313,12 @@ def validate(
problem = None
if (start_tag == "code") and (end_line == start_line + 1):
problem = "Code tag is split across two lines."
if start_tag != end_tag:
if is_else_tag:
pass
elif start_tag != end_tag:
problem = "Mismatched tag."
elif check_indent and (end_line > start_line + max_lines):
if not problem and check_indent and (end_line > start_line + max_lines):
if end_col != start_col:
problem = "Bad indentation."
@@ -315,7 +334,7 @@ def validate(
raise TemplateParserException(
f"""
fn: {fn}
{problem}
{problem}
start:
{start_token.s}
line {start_line}, col {start_col}
@@ -324,9 +343,11 @@ def validate(
line {end_line}, col {end_col}
"""
)
state.matcher = old_matcher
state.foreign = old_foreign
state.depth -= 1
if not is_else_tag:
state.matcher = old_matcher
state.foreign = old_foreign
state.depth -= 1
state.matcher = f
@@ -350,17 +371,20 @@ def validate(
elif kind == "handlebars_start":
start_tag_matcher(token)
elif kind == "handlebars_else":
state.matcher(token)
elif kind == "handlebars_end":
state.matcher(token)
elif kind in {
"django_start",
"django_else",
"jinja2_whitespace_stripped_start",
"jinja2_whitespace_stripped_type2_start",
}:
if is_django_block_tag(tag):
start_tag_matcher(token)
elif kind in {"django_end", "jinja2_whitespace_stripped_end"}:
elif kind in {"django_else", "django_end", "jinja2_whitespace_stripped_end"}:
state.matcher(token)
if state.depth != 0: