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(?(?:{html_tags})\b(\"[^\"]*\"|'[^']*'|{{[^}}]*}}|[^'\">{{}}])*>)",
- 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"(?(?:{html_tags})\b(\"[^\"]*\"|'[^']*'|{{[^}}]*}}|[^'\">{{}}])*>)(?!\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})>)(?:.*?)(?:(?:\1)>) # stuff >>>> match 1
- |(?:<({slt_html})\b[^>]+?>)(?:.*?)(?:(?:\2)>) # 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})>)(?:.*?)(?:(?:\4)>) # stuff >>>> match 1
- |(?:<({slt_html})\b[^>]+?>)(?:.*?)(?:(?:\5)>) # 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})>)(.*?)((\2)>[^<]*?$)",
- item,
- flags=RE_FLAGS_IMX,
- )
- and not re.search(
- rf"(<({slt_html})\\b[^>]+?>)(.*?)((\2)>[^<]*?$)",
- 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})>)(.*?)((\2)>)", item, flags=RE_FLAGS_IMX
- ) or re.search(
- rf"(^<({slt_html})\b[^>]+?>)(.*?)((\2)>)",
- 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(?(?:{html_tags})\b(\"[^\"]*\"|'[^']*'|{{[^}}]*}}|[^'\">{{}}])*>)",
+ RE_FLAGS_IX,
+ )
+ self.expand_break_after_IX = re.compile(
+ rf"(?(?:{html_tags})\b(\"[^\"]*\"|'[^']*'|{{[^}}]*}}|[^'\">{{}}])*>)(?!\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})>)(?:.*?)(?:(?:\1)>) # stuff >>>> match 1
+ |(?:<({slt_html})\b[^>]+?>)(?:.*?)(?:(?:\2)>) # 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})>)(?:.*?)(?:(?:\4)>) # stuff >>>> match 1
+ |(?:<({slt_html})\b[^>]+?>)(?:.*?)(?:(?:\5)>) # 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})>)(.*?)((\2)>[^<]*?$)", RE_FLAGS_IMX
+ )
+ self.indent_unindent_left_2_IMX = re.compile(
+ rf"(<({slt_html})\\b[^>]+?>)(.*?)((\2)>[^<]*?$)", 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})>)(.*?)((\2)>)", RE_FLAGS_IMX
+ )
+ self.indent_inline_block_2_IMX = re.compile(
+ rf"(^<({slt_html})\b[^>]+?>)(.*?)((\2)>)", RE_FLAGS_IMX
+ )