diff --git a/docs/src/docs/configuration.md b/docs/src/docs/configuration.md index efa3809..fb929dc 100644 --- a/docs/src/docs/configuration.md +++ b/docs/src/docs/configuration.md @@ -393,3 +393,28 @@ preserve_leading_space=true } ``` +## preserve_blank_lines + +Preserve blank where possible. Ideal for non-html template files where blank lines are intentional. + +Usage: + +**flag** + +```bash +--preserve-blank-lines +``` + +**pyproject.toml** + +```ini +preserve_blank_lines=true +``` + +**.djlintrc** + +```json +{ + "preserve_blank_lines": true +} +``` diff --git a/docs/src/fr/docs/configuration.md b/docs/src/fr/docs/configuration.md index 4646e99..b713ca2 100644 --- a/docs/src/fr/docs/configuration.md +++ b/docs/src/fr/docs/configuration.md @@ -392,3 +392,30 @@ preserve_leading_space=true "preserve_leading_space": true } ``` + + +## preserve_blank_lines + +Préserve les blancs lorsque cela est possible. Idéal pour les fichiers de modèles non-html où les lignes vides sont intentionnelles. + +Utilisation: + +**flag** + +```bash +--preserve-blank-lines +``` + +**pyproject.toml** + +```ini +preserve_blank_lines=true +``` + +**.djlintrc** + +```json +{ + "preserve_blank_lines": true +} +``` diff --git a/docs/src/ru/docs/configuration.md b/docs/src/ru/docs/configuration.md index b3fc345..c3dc892 100644 --- a/docs/src/ru/docs/configuration.md +++ b/docs/src/ru/docs/configuration.md @@ -388,3 +388,30 @@ preserve_leading_space=true "preserve_leading_space": true } ``` + + +## preserve_blank_lines + +Сохраняйте пробелы там, где это возможно. Идеально подходит для не-html файлов шаблонов, где пустые строки являются намеренными. + +Использование: + +**flag** + +```bash +--preserve-blank-lines +``` + +**pyproject.toml** + +```ini +preserve_blank_lines=true +``` + +**.djlintrc** + +```json +{ + "preserve_blank_lines": true +} +``` diff --git a/src/djlint/__init__.py b/src/djlint/__init__.py index 2c2df8f..acec050 100644 --- a/src/djlint/__init__.py +++ b/src/djlint/__init__.py @@ -99,6 +99,11 @@ from .src import get_src is_flag=True, help="Attempt to preserve leading space on text.", ) +@click.option( + "--preserve-blank-lines", + is_flag=True, + help="Attempt to preserve blank lines.", +) @colorama_text(autoreset=True) def main( src: List[str], @@ -114,6 +119,7 @@ def main( use_gitignore: bool, warn: bool, preserve_leading_space: bool, + preserve_blank_lines: bool, ) -> None: """djLint · HTML template linter and formatter.""" config = Config( @@ -130,6 +136,7 @@ def main( use_gitignore=use_gitignore, warn=warn, preserve_leading_space=preserve_leading_space, + preserve_blank_lines=preserve_blank_lines, ) temp_file = None diff --git a/src/djlint/formatter/condense.py b/src/djlint/formatter/condense.py index fa7b5ba..eb47775 100644 --- a/src/djlint/formatter/condense.py +++ b/src/djlint/formatter/condense.py @@ -25,16 +25,35 @@ def condense_html(html: str, config: Config) -> str: func = partial(strip_space, config, html) + line_contents = r"(.*?)" + trailing_contents = r"\n \t" + + if config.preserve_blank_lines: + line_contents = r"([^\n]+?)" + trailing_contents = r" \t" + if not config.preserve_leading_space: # remove any leading/trailing space - html = re.sub(re.compile(r"^[ \t]*(.*?)[\n \t]*$", re.M), func, html) + + html = re.sub( + re.compile(rf"^[ \t]*{line_contents}[{trailing_contents}]*$", re.M), + func, + html, + ) + else: # only remove leading space in front of tags # <, {%, {#, {{ html = re.sub( - re.compile(r"^[ \t]*((?:<|{%|{#|{{).*?)[\n \t]*$", re.M), func, html + re.compile( + rf"^[ \t]*((?:<|{{%|{{\#|{{{{).*?)[{trailing_contents}]*$", re.M + ), + func, + html, + ) + html = re.sub( + re.compile(rf"^{line_contents}[{trailing_contents}]*$", re.M), func, html ) - html = re.sub(re.compile(r"^(.*?)[\n \t]*$", re.M), func, html) def if_blank_line_after_match(config: Config, html: str) -> bool: """Check if there should be a blank line after.""" diff --git a/src/djlint/formatter/indent.py b/src/djlint/formatter/indent.py index 3c08d23..b764252 100644 --- a/src/djlint/formatter/indent.py +++ b/src/djlint/formatter/indent.py @@ -248,4 +248,7 @@ def indent_html(rawcode: str, config: Config) -> str: # handlebars templates beautified_code = re.sub(r"({{#(?:each|if).+?[^ ])(}})", func, beautified_code) - return beautified_code.strip() + "\n" + if not config.preserve_blank_lines: + beautified_code = beautified_code.lstrip() + + return beautified_code.rstrip() + "\n" diff --git a/src/djlint/settings.py b/src/djlint/settings.py index 91470fa..a020ccf 100644 --- a/src/djlint/settings.py +++ b/src/djlint/settings.py @@ -192,6 +192,7 @@ class Config: use_gitignore: bool = False, warn: bool = False, preserve_leading_space: bool = False, + preserve_blank_lines: bool = False, ): self.reformat = reformat @@ -234,6 +235,10 @@ class Config: or djlint_settings.get("preserve_leading_space", False) ) + self.preserve_blank_lines: bool = preserve_blank_lines or djlint_settings.get( + "preserve_blank_lines", False + ) + # ignore is based on input and also profile self.ignore: str = str(ignore or djlint_settings.get("ignore", "")) diff --git a/tests/test_config/test_preserve_blank_lines/__init__.py b/tests/test_config/test_preserve_blank_lines/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/tests/test_config/test_preserve_blank_lines/html.html b/tests/test_config/test_preserve_blank_lines/html.html new file mode 100644 index 0000000..c82af37 --- /dev/null +++ b/tests/test_config/test_preserve_blank_lines/html.html @@ -0,0 +1,28 @@ + +{% if abc == 101 %} + interface Ethernet1/2 + description // Connected to leaf-2 + no switchport + ip address 10.1.2.1/30 + ip router ospf 1 area 0.0.0.0 + no shutdown +{% endif %} + + +{% if abc == 102 %} + interface Ethernet1/2 + description // Connected to leaf-2 + no switchport + ip address 10.1.2.1/30 + ip router ospf 1 area 0.0.0.0 + no shutdown +{% endif %} + +{% if abc == 103 %} + interface Ethernet1/2 + description // Connected to leaf-2 + no switchport + ip address 10.1.2.1/30 + ip router ospf 1 area 0.0.0.0 + no shutdown +{% endif %} diff --git a/tests/test_config/test_preserve_blank_lines/test_config.py b/tests/test_config/test_preserve_blank_lines/test_config.py new file mode 100644 index 0000000..2381d69 --- /dev/null +++ b/tests/test_config/test_preserve_blank_lines/test_config.py @@ -0,0 +1,29 @@ +"""Djlint tests specific to --preserve-leading-space option. + +run:: + + pytest tests/test_config/test_preserve_blank_lines/test_config.py --cov=src/djlint --cov-branch \ + --cov-report xml:coverage.xml --cov-report term-missing + + pytest tests/test_config/test_preserve_blank_lines/test_config.py::test_config + +""" +# pylint: disable=C0116 +from click.testing import CliRunner + +from src.djlint import main as djlint + + +def test_config(runner: CliRunner) -> None: + + result = runner.invoke( + djlint, + [ + "tests/test_config/test_preserve_blank_lines/html.html", + "--check", + "--preserve-leading-space", + "--preserve-blank-lines", + ], + ) + + assert result.exit_code == 0