diff --git a/.gitignore b/.gitignore index 26fb2f221..f39a8f740 100644 --- a/.gitignore +++ b/.gitignore @@ -3,7 +3,7 @@ node_modules source_django report.xml _site - +.ruff_cache # Created by https://www.toptal.com/developers/gitignore/api/macos,python # Edit at https://www.toptal.com/developers/gitignore?templates=macos,python diff --git a/src/djlint/formatter/condense.py b/src/djlint/formatter/condense.py index 6d1a049a8..931ec0929 100644 --- a/src/djlint/formatter/condense.py +++ b/src/djlint/formatter/condense.py @@ -12,7 +12,7 @@ from ..settings import Config -def condense_html(html: str, config: Config) -> str: +def clean_whitespace(html: str, config: Config) -> str: """Compress back tags that do not need to be expanded.""" # put empty tags on one line @@ -55,50 +55,6 @@ def strip_space(config: Config, html: str, match: re.Match) -> str: re.compile(rf"^{line_contents}[{trailing_contents}]*$", re.M), func, html ) - def if_blank_line_after_match(config: Config, html: str) -> bool: - """Check if there should be a blank line after.""" - if config.blank_line_after_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_after_tag.split(",")] - ) - 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)) - 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_after(config: Config, html: str, match: re.Match) -> str: """Add break after if not in ignored block.""" if inside_ignored_block(config, html, match): @@ -145,6 +101,58 @@ def add_blank_line_before(config: Config, html: str, match: re.Match) -> str: html, ) + return html + + +def condense_html(html, config): + """Put short tags back on a single line.""" + + 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).splitlines()[-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 if_blank_line_after_match(config: Config, html: str) -> bool: + """Check if there should be a blank line after.""" + if config.blank_line_after_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_after_tag.split(",")] + ) + 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 + + # add blank lines before tags + func = partial(condense_line, config) # put short single line tags on one line @@ -158,10 +166,11 @@ def add_blank_line_before(config: Config, html: str, match: re.Match) -> str: re.IGNORECASE | re.MULTILINE | re.DOTALL, ) - # put short template tags back on one line + # put short template tags back on one line. must have leading space + # jinja +%} and {%+ intentionally omitted. html = re.sub( re.compile( - rf"({{%-?[ ]*?({config.optional_single_line_template_tags})[^\n(?:%}})]*?%}})\s*?([ ]*?[^%\n]*?[ ]*?)\s*?({{%-?[ ]+?end(\2)[ ]*?%}})", + rf"((?:\s|^){{%-?[ ]*?({config.optional_single_line_template_tags})[^\n(?:%}})]*?%}})\s*([^%\n]*?)\s*?({{%-?[ ]+?end(\2)[ ]*?%}})", flags=re.IGNORECASE | re.MULTILINE | re.VERBOSE, ), func, diff --git a/src/djlint/reformat.py b/src/djlint/reformat.py index 9288f0929..0a07675fa 100644 --- a/src/djlint/reformat.py +++ b/src/djlint/reformat.py @@ -7,7 +7,7 @@ from pathlib import Path from .formatter.compress import compress_html -from .formatter.condense import condense_html +from .formatter.condense import clean_whitespace, condense_html from .formatter.css import format_css from .formatter.expand import expand_html from .formatter.indent import indent_html @@ -24,9 +24,10 @@ def reformat_file(config: Config, this_file: Path) -> dict: expanded = expand_html(compressed, config) - condensed = condense_html(expanded, config) + condensed = clean_whitespace(expanded, config) beautified_code = indent_html(condensed, config) + beautified_code = condense_html(beautified_code, config) if config.format_css: beautified_code = format_css(beautified_code, config) diff --git a/tests/test_config/test_format_attribute_template_tags/html-one.html b/tests/test_config/test_format_attribute_template_tags/html-one.html index 739369374..18bbcfc75 100644 --- a/tests/test_config/test_format_attribute_template_tags/html-one.html +++ b/tests/test_config/test_format_attribute_template_tags/html-one.html @@ -8,9 +8,7 @@ src="{% static '/img/loader.gif' %}" alt="report image"/> - + {% endifchanged %}> - - + - + {% if a %}checked{% endif %}> {% block body %}