diff --git a/djlint/formatter/compress.py b/djlint/formatter/compress.py index 00faeb1d9..11030e53d 100644 --- a/djlint/formatter/compress.py +++ b/djlint/formatter/compress.py @@ -7,13 +7,14 @@ from typing import TYPE_CHECKING -import regex as re from HtmlTagNames import html_tag_names from HtmlVoidElements import html_void_elements -from ..helpers import RE_FLAGS_IMX, child_of_unformatted_block +from ..helpers import child_of_unformatted_block if TYPE_CHECKING: + import regex as re + from ..settings import Config @@ -65,4 +66,4 @@ def _clean_tag(match: re.Match[str]) -> str: return f"{open_bracket}{tag}{attributes}{close_bracket}" - return re.sub(config.html_tag_regex, _clean_tag, html, flags=RE_FLAGS_IMX) + return config.html_tag_regex_IMX.sub(_clean_tag, html) diff --git a/djlint/formatter/condense.py b/djlint/formatter/condense.py index 721a5e07a..c0825f413 100644 --- a/djlint/formatter/condense.py +++ b/djlint/formatter/condense.py @@ -45,7 +45,7 @@ def strip_space(config: Config, html: str, match: re.Match[str]) -> str: if inside_protected_trans_block(config, html[: match.end()], match): return match.group().rstrip() - lines = sum(1 for _ in re.finditer(r"\n", match.group(2))) + lines = sum(1 for _ in config.newline_pattern.finditer(match.group(2))) blank_lines = "\n" * lines if lines > config.max_blank_lines: blank_lines = "\n" * max(config.max_blank_lines, 0) diff --git a/djlint/formatter/expand.py b/djlint/formatter/expand.py index 37caf19c5..8897bb553 100644 --- a/djlint/formatter/expand.py +++ b/djlint/formatter/expand.py @@ -11,13 +11,7 @@ import regex as re -from ..helpers import ( - RE_FLAGS_IMX, - RE_FLAGS_IX, - RE_FLAGS_MX, - inside_ignored_block, - inside_template_block, -) +from ..helpers import RE_FLAGS_MX, inside_ignored_block, inside_template_block if TYPE_CHECKING: from ..settings import Config @@ -44,28 +38,14 @@ def add_html_line(out_format: str, match: re.Match[str]) -> str: return out_format % match.group(1) - html_tags = config.break_html_tags - add_left = partial(add_html_line, "\n%s") add_right = partial(add_html_line, "%s\n") - break_char = config.break_before - # html tags - break before - html = re.sub( - rf"{break_char}\K({{}}])*>)", - add_left, - html, - flags=RE_FLAGS_IX, - ) + html = config.expand_break_before_IX.sub(add_left, html) # html tags - break after - html = re.sub( - rf"({{}}])*>)(?!\s*?\n)(?=[^\n])", - add_right, - html, - flags=RE_FLAGS_IX, - ) + html = config.expand_break_after_IX.sub(add_right, html) # template tag breaks def should_i_move_template_tag( @@ -94,22 +74,11 @@ def should_i_move_template_tag( # template tags # break before - html = re.sub( - break_char - + r"\K((?:{%|{{\#)[ ]*?(?:" - + config.break_template_tags - + ")[^}]+?[%}]})", - partial(should_i_move_template_tag, "\n%s"), - html, - flags=RE_FLAGS_IMX, + html = config.expand_template_tags_before_IMX.sub( + partial(should_i_move_template_tag, "\n%s"), html ) # break after - return re.sub( - r"((?:{%|{{\#)[ ]*?(?:" - + config.break_template_tags - + ")[^}]+?[%}]})(?=[^\n])", - partial(should_i_move_template_tag, "%s\n"), - html, - flags=RE_FLAGS_IMX, + return config.expand_template_tags_after_IMX.sub( + partial(should_i_move_template_tag, "%s\n"), html ) diff --git a/djlint/formatter/indent.py b/djlint/formatter/indent.py index 130c8a847..792aa2dbd 100644 --- a/djlint/formatter/indent.py +++ b/djlint/formatter/indent.py @@ -11,7 +11,6 @@ from ..helpers import ( RE_FLAGS_IMSX, RE_FLAGS_IMX, - RE_FLAGS_IX, inside_ignored_block, is_ignored_block_closing, is_ignored_block_opening, @@ -79,14 +78,6 @@ def fix_handlebars_template_tags( is_block_raw = False jinja_replace_list = [] - slt_html = config.indent_html_tags - - # here using all tags cause we allow empty tags on one line - always_self_closing_html = config.always_self_closing_html_tags - - # here using all tags cause we allow empty tags on one line - slt_template = config.optional_single_line_template_tags - # nested ignored blocks.. ignored_level = 0 @@ -112,43 +103,8 @@ def fix_handlebars_template_tags( if is_block_raw and ignored_level == 0: is_block_raw = False - if ( - not is_block_raw - and re.search( - rf"^\s*?(?:{config.ignored_inline_blocks})", - item, - flags=RE_FLAGS_IMX, - ) - ) or ( - not is_block_raw - and ( - re.search( - rf"""^(?:[^<\s].*?)? # start of a line, optionally with some text - (?: - (?:<({slt_html})>)(?:.*?)(?:) # stuff >>>> match 1 - |(?:<({slt_html})\b[^>]+?>)(?:.*?)(?:) # stuff >>> match 2 - |(?:<(?:{always_self_closing_html})\b[^>]*?/?>) # - |(?:<(?:{slt_html})\b[^>]*?/>) # - |(?:{{%[ ]*?({slt_template})[ ]+?.*?%}})(?:.*?)(?:{{%[ ]+?end(?:\3)[ ]+?.*?%}}) # >>> match 3 - |{config.ignored_inline_blocks} - )[ \t]*? - (?: - .*? # anything - (?: # followed by another slt - (?:<({slt_html})>)(?:.*?)(?:) # stuff >>>> match 1 - |(?:<({slt_html})\b[^>]+?>)(?:.*?)(?:) # stuff >>> match 2 - |(?:<(?:{always_self_closing_html})\b[^>]*?/?>) # - |(?:<(?:{slt_html})\b[^>]*?/>) # - |(?:{{%[ ]*?({slt_template})[ ]+?.*?%}})(?:.*?)(?:{{%[ ]+?end(?:\6)[ ]+?.*?%}}) # >>> match 3 - |{config.ignored_inline_blocks} - )[ \t]*? - )*? # optional of course - [^<]*?$ # with no other tags following until end of line - """, - item, - flags=RE_FLAGS_IMX, - ) - ) + if (not is_block_raw and config.indent_block_raw_IMX.search(item)) or ( + not is_block_raw and (config.indent_full_match_IMX.search(item)) ): tmp = (indent * indent_level) + item + "\n" @@ -157,7 +113,7 @@ def fix_handlebars_template_tags( not config.no_set_formatting and not is_block_raw and in_set_tag - and re.search(r"^(?!.*\{\%).*%\}.*$", item, flags=RE_FLAGS_IMX) + and config.indent_closing_set_tag_IMX.search(item) ): indent_level = max(indent_level - 1, 0) in_set_tag = False @@ -168,7 +124,7 @@ def fix_handlebars_template_tags( not config.no_set_formatting and not is_block_raw and in_set_tag - and re.search(r"^[ ]*}|^[ ]*]", item, flags=RE_FLAGS_IMX) + and config.indent_closing_curly_IMX.search(item) ): indent_level = max(indent_level - 1, 0) tmp = (indent * indent_level) + item + "\n" @@ -177,27 +133,15 @@ def fix_handlebars_template_tags( elif ( not is_block_raw and not is_safe_closing_tag_ - and re.search(config.tag_unindent, item, flags=RE_FLAGS_IMX) + and config.tag_unindent_IMX.search(item) # and not ending in a slt like . - and not re.search( - rf"(<({slt_html})>)(.*?)([^<]*?$)", - item, - flags=RE_FLAGS_IMX, - ) - and not re.search( - rf"(<({slt_html})\\b[^>]+?>)(.*?)([^<]*?$)", - item, - flags=RE_FLAGS_IMX, - ) + and not config.indent_unindent_left_1_IMX.search(item) + and not config.indent_unindent_left_2_IMX.search(item) ): # block to catch inline block followed by a non-break tag - if re.search( - rf"(^<({slt_html})>)(.*?)()", item, flags=RE_FLAGS_IMX - ) or re.search( - rf"(^<({slt_html})\b[^>]+?>)(.*?)()", - item, - flags=RE_FLAGS_IMX, - ): + if config.indent_inline_block_1_IMX.search( + item + ) or config.indent_inline_block_2_IMX.search(item): # unindent after instead of before tmp = (indent * indent_level) + item + "\n" indent_level = max(indent_level - 1, 0) @@ -205,9 +149,7 @@ def fix_handlebars_template_tags( indent_level = max(indent_level - 1, 0) tmp = (indent * indent_level) + item + "\n" - elif not is_block_raw and re.search( - r"^" + str(config.tag_unindent_line), item, flags=RE_FLAGS_IMX - ): + elif not is_block_raw and config.indent_find_unindent_IMX.search(item): tmp = (indent * (indent_level - 1)) + item + "\n" # if indent, move right @@ -217,9 +159,7 @@ def fix_handlebars_template_tags( not config.no_set_formatting and not is_block_raw and not in_set_tag - and re.search( - r"^([ ]*{%[ ]*?set)(?!.*%}).*$", item, flags=RE_FLAGS_IMX - ) + and config.indent_opening_set_tag_IMX.search(item) ): tmp = (indent * indent_level) + item + "\n" indent_level += 1 @@ -235,14 +175,7 @@ def fix_handlebars_template_tags( item, flags=RE_FLAGS_IMX, ) - ) or ( - re.search( - r"^(?:" + str(config.tag_indent) + r")", - item, - flags=RE_FLAGS_IMX, - ) - and not is_block_raw - ): + ) or (config.indent_tag_indent_IMX.search(item) and not is_block_raw): tmp = (indent * indent_level) + item + "\n" indent_level += 1 @@ -272,12 +205,7 @@ def fix_handlebars_template_tags( func = partial(format_attributes, config, item) - tmp = re.sub( - rf"(\s*?)(<(?:{config.indent_html_tags}))\s((?:\"[^\"]*\"|'[^']*'|{{[^}}]*}}|[^'\">{{}}\/])+?)(\s?/?>)", - func, - tmp, - flags=RE_FLAGS_IX, - ) + tmp = config.indent_leading_space_IX.sub(func, tmp) # turn off raw block if we hit end - for one line raw blocks, but not an inline raw if ( diff --git a/djlint/helpers.py b/djlint/helpers.py index dc162c106..3be7ef66c 100644 --- a/djlint/helpers.py +++ b/djlint/helpers.py @@ -7,13 +7,13 @@ from functools import cache from typing import TYPE_CHECKING -import regex as re - if TYPE_CHECKING: from typing import Final from .settings import Config +import regex as re + RE_FLAGS_IS: Final = re.I | re.S RE_FLAGS_IX: Final = re.I | re.X RE_FLAGS_MS: Final = re.M | re.S @@ -31,20 +31,14 @@ def is_ignored_block_opening(config: Config, item: str) -> bool: single line block. """ last_index = 0 - inline = tuple( - re.finditer(config.ignored_blocks_inline, item, flags=RE_FLAGS_IMSX) - ) + inline = tuple(config.ignored_blocks_inline_IMSX.finditer(item)) if inline: last_index = ( inline[-1].end() ) # get the last index. The ignored opening should start after this. - return bool( - re.search( - config.ignored_block_opening, item[last_index:], flags=RE_FLAGS_IX - ) - ) + return bool(config.ignored_block_opening_IX.search(item[last_index:])) def is_script_style_block_opening(config: Config, item: str) -> bool: @@ -54,20 +48,14 @@ def is_script_style_block_opening(config: Config, item: str) -> bool: single line block. """ last_index = 0 - inline = tuple( - re.finditer(config.script_style_inline, item, flags=RE_FLAGS_IMSX) - ) + inline = tuple(config.script_style_inline_IMSX.finditer(item)) if inline: last_index = ( inline[-1].end() ) # get the last index. The ignored opening should start after this. - return bool( - re.search( - config.script_style_opening, item[last_index:], flags=RE_FLAGS_IX - ) - ) + return bool(config.script_style_opening_IX.search(item[last_index:])) def inside_protected_trans_block( @@ -82,9 +70,7 @@ def inside_protected_trans_block( False = indentable > either inside a trans trimmed block, or somewhere else, but not a trans non trimmed :) """ last_index = 0 - close_block = re.search( - config.ignored_trans_blocks_closing, match.group(), flags=RE_FLAGS_IX - ) + close_block = config.ignored_trans_blocks_closing_IX.search(match.group()) if not close_block: return False @@ -150,20 +136,14 @@ def is_ignored_block_closing(config: Config, item: str) -> bool: single line block. """ last_index = 0 - inline = tuple( - re.finditer(config.ignored_inline_blocks, item, flags=RE_FLAGS_IX) - ) + inline = tuple(config.ignored_inline_blocks_IX.finditer(item)) if inline: last_index = ( inline[-1].end() ) # get the last index. The ignored opening should start after this. - return bool( - re.search( - config.ignored_block_closing, item[last_index:], flags=RE_FLAGS_IX - ) - ) + return bool(config.ignored_block_closing_IX.search(item[last_index:])) def is_script_style_block_closing(config: Config, item: str) -> bool: @@ -173,9 +153,7 @@ def is_script_style_block_closing(config: Config, item: str) -> bool: single line block. """ last_index = 0 - inline = tuple( - re.finditer(config.script_style_inline, item, flags=RE_FLAGS_IX) - ) + inline = tuple(config.script_style_inline_IX.finditer(item)) if inline: last_index = ( @@ -196,22 +174,14 @@ def is_safe_closing_tag(config: Config, item: str) -> bool: single line block. """ last_index = 0 - inline = tuple( - re.finditer( - config.ignored_inline_blocks + r" | " + config.ignored_blocks, - item, - flags=RE_FLAGS_IMSX, - ) - ) + inline = tuple(config.ignored_group_opening_IMSX.finditer(item)) if inline: last_index = ( inline[-1].end() ) # get the last index. The ignored opening should start after this. - return bool( - re.search(config.safe_closing_tag, item[last_index:], flags=RE_FLAGS_IX) - ) + return bool(config.safe_closing_tag_IX.search(item[last_index:])) def inside_template_block( @@ -220,9 +190,7 @@ def inside_template_block( """Check if a re.Match is inside of a template block.""" match_start = match.start() match_end = match.end(0) - for ignored_match in re.finditer( - config.template_blocks, html, flags=RE_FLAGS_IMSX - ): + for ignored_match in config.template_blocks_IMSX.finditer(html): if ( ignored_match.start(0) <= match_start and match_end <= ignored_match.end() @@ -250,13 +218,16 @@ def inside_ignored_linter_block( @cache def _inside_ignored_block( - html: str, /, *, ignored_blocks: str, ignored_inline_blocks: str + html: str, + /, + *, + ignored_blocks: re.Pattern[str], + ignored_inline_blocks: re.Pattern[str], ) -> tuple[tuple[int, int], ...]: return tuple( (x.start(0), x.end()) for x in itertools.chain( - re.finditer(ignored_blocks, html, flags=RE_FLAGS_IMSX), - re.finditer(ignored_inline_blocks, html, flags=RE_FLAGS_IX), + ignored_blocks.finditer(html), ignored_inline_blocks.finditer(html) ) ) @@ -269,8 +240,8 @@ def inside_ignored_block( match_end = match.end(0) for ignored_match_start, ignored_match_end in _inside_ignored_block( html, - ignored_blocks=config.ignored_blocks, - ignored_inline_blocks=config.ignored_inline_blocks, + ignored_blocks=config.ignored_blocks_IMSX, + ignored_inline_blocks=config.ignored_inline_blocks_IX, ): if ( ignored_match_start <= match_start @@ -282,11 +253,10 @@ def inside_ignored_block( @cache def _child_of_unformatted_block( - html: str, /, *, unformatted_blocks: str + html: str, /, *, unformatted_blocks: re.Pattern[str] ) -> tuple[tuple[int, int], ...]: return tuple( - (x.start(0), x.end()) - for x in re.finditer(unformatted_blocks, html, flags=RE_FLAGS_IMSX) + (x.start(0), x.end()) for x in unformatted_blocks.finditer(html) ) @@ -297,7 +267,7 @@ def child_of_unformatted_block( match_start = match.start() match_end = match.end(0) for ignored_match_start, ignored_match_end in _child_of_unformatted_block( - html, unformatted_blocks=config.unformatted_blocks + html, unformatted_blocks=config.unformatted_blocks_IMSX ): if ignored_match_start < match_start and match_end <= ignored_match_end: return True @@ -312,7 +282,7 @@ def child_of_ignored_block( match_end = match.end(0) for ignored_match in itertools.chain( re.finditer(config.ignored_blocks, html, flags=RE_FLAGS_IMSX), - re.finditer(config.ignored_inline_blocks, html, flags=RE_FLAGS_IX), + config.ignored_inline_blocks_IX.finditer(html), ): if ( ignored_match.start(0) < match_start @@ -331,7 +301,7 @@ def overlaps_ignored_block( for ignored_match in itertools.chain( re.finditer(config.ignored_blocks, html, flags=RE_FLAGS_IMSX), - re.finditer(config.ignored_inline_blocks, html, flags=RE_FLAGS_IX), + config.ignored_inline_blocks_IX.finditer(html), ): # don't require the match to be fully inside the ignored block. # poorly build html will probably span ignored blocks and should be ignored. diff --git a/djlint/lint.py b/djlint/lint.py index ae956c7e8..76a22d968 100644 --- a/djlint/lint.py +++ b/djlint/lint.py @@ -4,6 +4,7 @@ import importlib from collections.abc import Sequence +from functools import cache from typing import TYPE_CHECKING import regex as re @@ -63,6 +64,11 @@ def get_line(start: int, line_ends: Sequence[Mapping[str, int]]) -> str: return "{}:{}".format(line_ends.index(line) + 1, start - line["start"]) +@cache +def get_compiled_rule_pattern(regex: str, pattern: str) -> re.Pattern[str]: + return re.compile(regex, build_flags(pattern)) + + def linter( config: Config, html: str, filename: str, filepath: str ) -> dict[str, list[LintError]]: @@ -109,9 +115,10 @@ def linter( # rule based on patterns else: for pattern in rule["patterns"]: - for match in re.finditer( - pattern, html, flags=build_flags(rule.get("flags", "re.S")) - ): + compiled = get_compiled_rule_pattern( + pattern, rule.get("flags", "re.S") + ) + for match in compiled.finditer(html): if ( not overlaps_ignored_block(config, html, match) and not inside_ignored_rule( diff --git a/djlint/rules/H025.py b/djlint/rules/H025.py index 911a56ee1..66096f99c 100644 --- a/djlint/rules/H025.py +++ b/djlint/rules/H025.py @@ -6,10 +6,7 @@ from itertools import chain from typing import TYPE_CHECKING -import regex as re - from ..helpers import ( - RE_FLAGS_IX, inside_ignored_linter_block, inside_ignored_rule, overlaps_ignored_block, @@ -17,6 +14,7 @@ from ..lint import get_line if TYPE_CHECKING: + import regex as re from typing_extensions import Any from ..lint import LintError @@ -36,15 +34,9 @@ def run( open_tags: list[re.Match[str]] = [] orphan_tags: list[re.Match[str]] = [] - for match in re.finditer( - r"<(/?(\w+))\s*(" + config.attribute_pattern + r"|\s*)*\s*?>", - html, - flags=re.X, - ): - if match.group(1) and not re.search( - rf"^/?{config.always_self_closing_html_tags}\b", - match.group(1), - flags=RE_FLAGS_IX, + for match in config.h025_mismatching_X.finditer(html): + if match.group(1) and not config.h025_selfclosing_IX.search( + match.group(1) ): # close tags should equal open tags if match.group(1)[0] != "/": diff --git a/djlint/settings.py b/djlint/settings.py index b379ed00f..8b70fe08d 100644 --- a/djlint/settings.py +++ b/djlint/settings.py @@ -9,6 +9,7 @@ from pathlib import Path from typing import TYPE_CHECKING +import regex as re import yaml from click import echo from colorama import Fore @@ -17,6 +18,8 @@ from pathspec import PathSpec from pathspec.patterns.gitwildmatch import GitWildMatchPatternError +from djlint.helpers import RE_FLAGS_IMSX, RE_FLAGS_IMX, RE_FLAGS_IX + if sys.version_info >= (3, 11): try: import tomllib @@ -1069,3 +1072,141 @@ def __init__( ) """ ) + self.compile_regex() + + def compile_regex(self) -> None: + self.ignored_inline_blocks_IX = re.compile( + self.ignored_inline_blocks, RE_FLAGS_IX + ) + self.ignored_trans_blocks_closing_IX = re.compile( + self.ignored_trans_blocks_closing, RE_FLAGS_IX + ) + self.newline_pattern = re.compile("\n") + self.ignored_group_opening_IMSX = re.compile( + self.ignored_inline_blocks + r" | " + self.ignored_blocks, + RE_FLAGS_IMSX, + ) + self.safe_closing_tag_IX = re.compile( + self.safe_closing_tag, RE_FLAGS_IX + ) + self.script_style_inline_IMSX = re.compile( + self.script_style_inline, RE_FLAGS_IMSX + ) + self.script_style_inline_IX = re.compile( + self.script_style_inline, RE_FLAGS_IX + ) + self.ignored_block_closing_IX = re.compile( + self.ignored_block_closing, RE_FLAGS_IX + ) + self.script_style_opening_IX = re.compile( + self.script_style_opening, RE_FLAGS_IX + ) + self.ignored_block_opening_IX = re.compile( + self.ignored_block_opening, RE_FLAGS_IX + ) + self.ignored_blocks_inline_IMSX = re.compile( + self.ignored_blocks_inline, RE_FLAGS_IMSX + ) + self.html_tag_regex_IMX = re.compile(self.html_tag_regex, RE_FLAGS_IMX) + html_tags = self.break_html_tags + break_char = self.break_before + self.expand_break_before_IX = re.compile( + rf"{break_char}\K({{}}])*>)", + RE_FLAGS_IX, + ) + self.expand_break_after_IX = re.compile( + rf"({{}}])*>)(?!\s*?\n)(?=[^\n])", + RE_FLAGS_IX, + ) + self.expand_template_tags_before_IMX = re.compile( + break_char + + r"\K((?:{%|{{\#)[ ]*?(?:" + + self.break_template_tags + + ")[^}]+?[%}]})", + RE_FLAGS_IMX, + ) + self.expand_template_tags_after_IMX = re.compile( + r"((?:{%|{{\#)[ ]*?(?:" + + self.break_template_tags + + ")[^}]+?[%}]})(?=[^\n])", + RE_FLAGS_IMX, + ) + self.unformatted_blocks_IMSX = re.compile( + self.unformatted_blocks, RE_FLAGS_IMSX + ) + self.template_blocks_IMSX = re.compile( + self.template_blocks, RE_FLAGS_IMSX + ) + self.ignored_blocks_IMSX = re.compile( + self.ignored_blocks, RE_FLAGS_IMSX + ) + self.indent_block_raw_IMX = re.compile( + rf"^\s*?(?:{self.ignored_inline_blocks})", RE_FLAGS_IMX + ) + self.indent_leading_space_IX = re.compile( + rf"(\s*?)(<(?:{self.indent_html_tags}))\s((?:\"[^\"]*\"|'[^']*'|{{[^}}]*}}|[^'\">{{}}\/])+?)(\s?/?>)", + RE_FLAGS_IX, + ) + slt_html = self.indent_html_tags + always_self_closing_html = self.always_self_closing_html_tags + slt_template = self.optional_single_line_template_tags + # TODO: How to call it? + self.indent_full_match_IMX = re.compile( + rf"""^(?:[^<\s].*?)? # start of a line, optionally with some text + (?: + (?:<({slt_html})>)(?:.*?)(?:) # stuff >>>> match 1 + |(?:<({slt_html})\b[^>]+?>)(?:.*?)(?:) # stuff >>> match 2 + |(?:<(?:{always_self_closing_html})\b[^>]*?/?>) # + |(?:<(?:{slt_html})\b[^>]*?/>) # + |(?:{{%[ ]*?({slt_template})[ ]+?.*?%}})(?:.*?)(?:{{%[ ]+?end(?:\3)[ ]+?.*?%}}) # >>> match 3 + |{self.ignored_inline_blocks} + )[ \t]*? + (?: + .*? # anything + (?: # followed by another slt + (?:<({slt_html})>)(?:.*?)(?:) # stuff >>>> match 1 + |(?:<({slt_html})\b[^>]+?>)(?:.*?)(?:) # stuff >>> match 2 + |(?:<(?:{always_self_closing_html})\b[^>]*?/?>) # + |(?:<(?:{slt_html})\b[^>]*?/>) # + |(?:{{%[ ]*?({slt_template})[ ]+?.*?%}})(?:.*?)(?:{{%[ ]+?end(?:\6)[ ]+?.*?%}}) # >>> match 3 + |{self.ignored_inline_blocks} + )[ \t]*? + )*? # optional of course + [^<]*?$ # with no other tags following until end of line + """, + RE_FLAGS_IMX, + ) + self.tag_unindent_IMX = re.compile(self.tag_unindent, RE_FLAGS_IMX) + self.h025_mismatching_X = re.compile( + r"<(/?(\w+))\s*(" + self.attribute_pattern + r"|\s*)*\s*?>", re.X + ) + self.h025_selfclosing_IX = re.compile( + rf"^/?{self.always_self_closing_html_tags}\b", RE_FLAGS_IX + ) + self.indent_tag_indent_IMX = re.compile( + r"^(?:" + str(self.tag_indent) + r")", RE_FLAGS_IMX + ) + self.indent_find_unindent_IMX = re.compile( + r"^" + str(self.tag_unindent_line), RE_FLAGS_IMX + ) + self.indent_opening_set_tag_IMX = re.compile( + r"^([ ]*{%[ ]*?set)(?!.*%}).*$", RE_FLAGS_IMX + ) + self.indent_unindent_left_1_IMX = re.compile( + rf"(<({slt_html})>)(.*?)([^<]*?$)", RE_FLAGS_IMX + ) + self.indent_unindent_left_2_IMX = re.compile( + rf"(<({slt_html})\\b[^>]+?>)(.*?)([^<]*?$)", RE_FLAGS_IMX + ) + self.indent_closing_set_tag_IMX = re.compile( + r"^(?!.*\{\%).*%\}.*$", RE_FLAGS_IMX + ) + self.indent_closing_curly_IMX = re.compile( + r"^[ ]*}|^[ ]*]", RE_FLAGS_IMX + ) + self.indent_inline_block_1_IMX = re.compile( + rf"(^<({slt_html})>)(.*?)()", RE_FLAGS_IMX + ) + self.indent_inline_block_2_IMX = re.compile( + rf"(^<({slt_html})\b[^>]+?>)(.*?)()", RE_FLAGS_IMX + )