diff --git a/HISTORY.md b/HISTORY.md index 4e0dc5c..a1bf12f 100644 --- a/HISTORY.md +++ b/HISTORY.md @@ -2,8 +2,10 @@ ## 4.0.1 (unreleased) - -- Nothing changed yet. +- keep line breaks: Do not reformat class attribute values. + This allows for multi-line or otherwise manually strangely formatted + class attributes. + [thet] ## 4.0.0 (2026-04-10) diff --git a/zpretty/attributes.py b/zpretty/attributes.py index 05ec795..7ab080a 100644 --- a/zpretty/attributes.py +++ b/zpretty/attributes.py @@ -115,7 +115,8 @@ def sort_attributes(self, name): """ if name.startswith("xmlns"): return (0, name) - if name in ("class", "id"): + # data-zpretty-class being the class replacement to avoid reformatting. + if name in ("class", "data-zpretty-class", "id"): return (100, name) if name.startswith("data"): return (300, name) diff --git a/zpretty/prettifier.py b/zpretty/prettifier.py index 097d89d..03dfbe2 100644 --- a/zpretty/prettifier.py +++ b/zpretty/prettifier.py @@ -23,6 +23,9 @@ class ZPrettifier: _ampersand_marker = str(uuid4()) _cdata_marker = str(uuid4()) _cdata_pattern = re.compile(r"", re.DOTALL) + _class_marker_name = "data-zpretty-class" + _class_marker = " data-zpretty-class=" + _class_pattern = " class=" _doctype_marker = f"" _doctype_pattern = re.compile( r"([]*(\[[^]]*\])?>)", re.IGNORECASE | re.DOTALL @@ -50,6 +53,14 @@ def __init__(self, filename="", text="", encoding="utf8"): # in the attributes so that bogus ones can be escaped for el in soup.descendants: attrs = getattr(el, "attrs", {}) + + # Restore class attributes. + # Beautiful soup changes the formatting of class attributes into a + # single-line attribute. + if self._class_marker_name in attrs: + attrs["class"] = attrs.get(self._class_marker_name) + del attrs[self._class_marker_name] + for key, value in attrs.items(): if self._ampersand_marker in value: attrs[key] = value.replace(self._ampersand_marker, "&") @@ -122,6 +133,11 @@ def _prepare_text(self): text = re.sub(self._cdata_pattern, self._cdata_marker, text) text = re.sub(self._doctype_pattern, self._doctype_marker, text) + # Replace class attributes. + # Beautiful soup changes the formatting of class attributes into a + # single-line attribute, which we want to prevent. + text = re.sub(self._class_pattern, self._class_marker, text) + # Get all the entities in the text and replace them with a marker # The text might contain undefined entities that BeautifulSoup # will strip out. diff --git a/zpretty/tests/original/sample_pt.pt b/zpretty/tests/original/sample_pt.pt index c563553..b657e10 100644 --- a/zpretty/tests/original/sample_pt.pt +++ b/zpretty/tests/original/sample_pt.pt @@ -39,6 +39,30 @@ Foo Bar +
+
+ okay +
+