Skip to content

Commit

Permalink
feat(formatter): added option to add blank line before tags
Browse files Browse the repository at this point in the history
closes #307
  • Loading branch information
Christopher Pickering committed Jul 28, 2022
1 parent ee87ef7 commit b2bd1ea
Show file tree
Hide file tree
Showing 14 changed files with 205 additions and 5 deletions.
18 changes: 18 additions & 0 deletions docs/src/_data/configuration.json
Expand Up @@ -143,6 +143,24 @@
}
]
},
{
"name": "blank_line_before_tag",
"description": {
"en": "Add an additional blank line before `{% <tag> ... %}` tag groups. Blank lines will never be added to start of file or between similar tags.",
"ru": "Добавляет дополнительную пустую строку перед группами тегов `{% <tag> ... %}`. Пустые строки никогда не будут добавлены в начало файла или между похожими тегами.",
"fr": "Ajoute une ligne blanche supplémentaire avant les groupes de balises `{% <tag> ... %}`. Les lignes vides ne seront jamais ajoutées au début du fichier ou entre des balises similaires."
},
"usage": [
{
"name": "pyproject.toml",
"value": "blank_line_before_tag=\"load,extends,include\""
},
{
"name": ".djlintrc",
"value": "\"blank_line_before_tag\": \"load,extends,include\""
}
]
},
{
"name": "profile",
"description": {
Expand Down
50 changes: 45 additions & 5 deletions src/djlint/formatter/condense.py
Expand Up @@ -70,24 +70,43 @@ def if_blank_line_after_match(config: Config, html: str) -> bool:
)
return True

def if_blank_line_before_match(config: Config, html: str) -> bool:
"""Check if there should be a blank line before."""
if config.blank_line_before_tag:
return not any(
re.findall(
re.compile(
rf"((?:{{%\s*?{tag}[^}}]+?%}}\n?)+)",
re.IGNORECASE | re.MULTILINE | re.DOTALL,
),
html,
)
for tag in [x.strip() for x in config.blank_line_before_tag.split(",")]
)
return True

def condense_line(config: Config, match: re.Match) -> str:
"""Put contents on a single line if below max line length."""
if (
len(match.group(1) + match.group(3) + match.group(4))
< config.max_line_length
) and if_blank_line_after_match(config, match.group(3)):
(
len(match.group(1) + match.group(3) + match.group(4))
< config.max_line_length
)
and if_blank_line_after_match(config, match.group(3))
and if_blank_line_before_match(config, match.group(3))
):
return match.group(1) + match.group(3) + match.group(4)

return match.group()

def add_blank_line(config: Config, html: str, match: re.Match) -> str:
def add_blank_line_after(config: Config, html: str, match: re.Match) -> str:
"""Add break after if not in ignored block."""
if inside_ignored_block(config, html, match):
return match.group()

return match.group() + "\n"

func = partial(add_blank_line, config, html)
func = partial(add_blank_line_after, config, html)

# should we add blank lines after load tags?
if config.blank_line_after_tag:
Expand All @@ -101,6 +120,27 @@ def add_blank_line(config: Config, html: str, match: re.Match) -> str:
html,
)

def add_blank_line_before(config: Config, html: str, match: re.Match) -> str:
"""Add break before if not in ignored block and not first line in file."""
if inside_ignored_block(config, html, match) or match.start() == 0:
return match.group()

return "\n" + match.group()

func = partial(add_blank_line_before, config, html)

# should we add blank lines before load tags?
if config.blank_line_before_tag:
for tag in [x.strip() for x in config.blank_line_before_tag.split(",")]:
html = re.sub(
re.compile(
rf"(?<!^\n$)((?:{{%\s*?{tag}\b[^}}]+?%}}\n?)+)",
re.IGNORECASE | re.MULTILINE | re.DOTALL,
),
func,
html,
)

func = partial(condense_line, config)

# put short single line tags on one line
Expand Down
5 changes: 5 additions & 0 deletions src/djlint/settings.py
Expand Up @@ -334,6 +334,11 @@ def __init__(
"blank_line_after_tag", None
)

# add blank line before load tags
self.blank_line_before_tag: Optional[str] = djlint_settings.get(
"blank_line_before_tag", None
)

# contents of tags will not be formatted
self.ignored_block_opening: str = r"""
<style
Expand Down
Empty file.
1 change: 1 addition & 0 deletions tests/test_config/test_blank_lines_before_tag/html.html
@@ -0,0 +1 @@
{% extends "nothing.html" %}{% load stuff %}{% load stuff 2 %}{% include "html_two.html" %}<div></div>
3 changes: 3 additions & 0 deletions tests/test_config/test_blank_lines_before_tag/html_eight.html
@@ -0,0 +1,3 @@
{% extends nothing %}

<div></div>
6 changes: 6 additions & 0 deletions tests/test_config/test_blank_lines_before_tag/html_five.html
@@ -0,0 +1,6 @@
<tr>
<td rowspan="{{ quality.row_span }}">

{% include "common/pdfs/partials/display_quality_improvements.html" %}
</td>
</tr>
3 changes: 3 additions & 0 deletions tests/test_config/test_blank_lines_before_tag/html_four.html
@@ -0,0 +1,3 @@
{% block this %}
{% load i18n %}
{% endblock this %}
6 changes: 6 additions & 0 deletions tests/test_config/test_blank_lines_before_tag/html_seven.html
@@ -0,0 +1,6 @@
{% blocktrans %}my words{% endblocktrans %}
{% block body %}
<div></div>

{% endblock body %}
{% block js %}{% endblock %}
4 changes: 4 additions & 0 deletions tests/test_config/test_blank_lines_before_tag/html_six.html
@@ -0,0 +1,4 @@
{% block include %}
{# {% include 'common/sticky-topbar-hidden-nav.html' %}#}

{% endblock %}
8 changes: 8 additions & 0 deletions tests/test_config/test_blank_lines_before_tag/html_three.html
@@ -0,0 +1,8 @@
<div class="tab-cnt">
<div class="tab-dta active" id="details">
<div class="em-grid">

{% include "pages/task/details_source.html.j2" %}
</div>
</div>
</div>
2 changes: 2 additions & 0 deletions tests/test_config/test_blank_lines_before_tag/html_two.html
@@ -0,0 +1,2 @@
{% load stuff %}
<div></div>
3 changes: 3 additions & 0 deletions tests/test_config/test_blank_lines_before_tag/pyproject.toml
@@ -0,0 +1,3 @@
[tool]
[tool.djlint]
blank_line_before_tag = "load, extends, include ,endblock "
101 changes: 101 additions & 0 deletions tests/test_config/test_blank_lines_before_tag/test_config.py
@@ -0,0 +1,101 @@
"""Djlint tests specific to pyproject.toml configuration.
run::
pytest tests/test_config/test_blank_lines_before_tag/test_config.py --cov=src/djlint --cov-branch \
--cov-report xml:coverage.xml --cov-report term-missing
for a single test, run::
pytest tests/test_config.py::test_custom_html --cov=src/djlint \
--cov-branch --cov-report xml:coverage.xml --cov-report term-missing
"""
# pylint: disable=C0116

from click.testing import CliRunner

from src.djlint import main as djlint


def test_blank_lines_before_tag(runner: CliRunner) -> None:
result = runner.invoke(
djlint, ["tests/test_config/test_blank_lines_before_tag/html.html", "--check"]
)

assert (
"""+{% extends "nothing.html" %}
+
+{% load stuff %}
+{% load stuff 2 %}
+
+{% include "html_two.html" %}
+<div></div>"""
in result.output
)
assert """1 file would be updated.""" in result.output
assert result.exit_code == 1

result = runner.invoke(
djlint,
["tests/test_config/test_blank_lines_before_tag/html_two.html", "--check"],
)
assert result.exit_code == 0

# check blocks that do not start on a newline - they should be left as is.
result = runner.invoke(
djlint,
["tests/test_config/test_blank_lines_before_tag/html_three.html", "--check"],
)

assert """0 files would be updated.""" in result.output
assert result.exit_code == 0

result = runner.invoke(
djlint,
["tests/test_config/test_blank_lines_before_tag/html_four.html", "--check"],
)

assert result.exit_code == 1
assert (
""" {% block this %}
-{% load i18n %}
+
+ {% load i18n %}
+
{% endblock this %}
"""
in result.output
)

# something perfect should stay perfect :)
result = runner.invoke(
djlint,
["tests/test_config/test_blank_lines_before_tag/html_five.html", "--check"],
)
assert result.exit_code == 0

# something perfect should stay perfect :)
result = runner.invoke(
djlint,
["tests/test_config/test_blank_lines_before_tag/html_six.html", "--check"],
)
assert result.exit_code == 0

# make sure endblock doesn't pick up endblocktrans :)
result = runner.invoke(
djlint,
["tests/test_config/test_blank_lines_before_tag/html_seven.html", "--check"],
)
assert result.exit_code == 0

# check that multiple blank lines are not added
result = runner.invoke(
djlint,
[
"tests/test_config/test_blank_lines_before_tag/html_eight.html",
"--preserve-blank-lines",
"--check",
],
)
assert result.exit_code == 0

0 comments on commit b2bd1ea

Please sign in to comment.