Colorize multi-valued field changes distinctly

This commit is contained in:
Šarūnas Nejus 2026-02-22 01:12:04 +00:00
parent 9d237d10fc
commit 31f79f14a3
No known key found for this signature in database
3 changed files with 34 additions and 2 deletions

View file

@ -1048,6 +1048,18 @@ def print_newline_layout(
FLOAT_EPSILON = 0.01
def _multi_value_diff(field: str, oldset: set[str], newset: set[str]) -> str:
added = newset - oldset
removed = oldset - newset
parts = [
f"{field}:",
*(colorize("text_diff_removed", f" - {i}") for i in sorted(removed)),
*(colorize("text_diff_added", f" + {i}") for i in sorted(added)),
]
return "\n".join(parts)
def _field_diff(
field: str, old: FormattedMapping, new: FormattedMapping
) -> str | None:
@ -1063,6 +1075,11 @@ def _field_diff(
):
return None
if isinstance(oldval, list):
if (oldset := set(oldval)) != (newset := set(newval)):
return _multi_value_diff(field, oldset, newset)
return None
# Get formatted values for output.
oldstr, newstr = old.get(field, ""), new.get(field, "")
if field not in new:
@ -1071,8 +1088,7 @@ def _field_diff(
if field not in old:
return colorize("text_diff_added", f"{field}: {newstr}")
# For strings, highlight changes. For others, colorize the whole
# thing.
# For strings, highlight changes. For others, colorize the whole thing.
if isinstance(oldval, str):
oldstr, newstr = colordiff(oldstr, newstr)
else:

View file

@ -28,6 +28,7 @@ Other changes
values: |semicolon_space|. For example ``beet modify albumtypes="album; ep"``.
Previously, ``\␀`` was used as a separator. This applies to fields such as
``artists``, ``albumtypes`` etc.
- Improve highlighting of multi-valued fields changes.
2.6.2 (February 22, 2026)
-------------------------

View file

@ -1,3 +1,5 @@
from textwrap import dedent
import pytest
from beets.library import Item
@ -38,6 +40,19 @@ class TestFieldDiff:
p({"mb_trackid": None}, {"mb_trackid": "1234"}, "mb_trackid", "mb_trackid: -> [text_diff_added]1234[/]", id="none_to_value"),
p({}, {"new_flex": "foo"}, "new_flex", "[text_diff_added]new_flex: foo[/]", id="flex_field_added"),
p({"old_flex": "foo"}, {}, "old_flex", "[text_diff_removed]old_flex: foo[/]", id="flex_field_removed"),
p({"albumtypes": ["album", "ep"]}, {"albumtypes": ["ep", "album"]}, "albumtypes", None, id="multi_value_unchanged"),
p(
{"albumtypes": ["ep"]},
{"albumtypes": ["album", "compilation"]},
"albumtypes",
dedent("""
albumtypes:
[text_diff_removed] - ep[/]
[text_diff_added] + album[/]
[text_diff_added] + compilation[/]
""").strip(),
id="multi_value_changed"
),
],
) # fmt: skip
@pytest.mark.parametrize("color", [True], ids=["color_enabled"])