Created
September 10, 2024 20:21
-
-
Save simonLeary42/ff794cf4425a4bea52a9ff17c1bc31c3 to your computer and use it in GitHub Desktop.
parses a patch file and adds highlighting for specific changes made within a block of text. May pass large strings into SequenceMatcher, which scales very poorly.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
def _format_diff_strings(before: str, after: str) -> str: | |
before_lines = before.splitlines() | |
after_lines = after.splitlines() | |
diff = difflib.unified_diff(before_lines, after_lines, lineterm="") | |
output = "" | |
removed_lines = [] | |
added_lines = [] | |
def _format_added_removed(): | |
# given the current state of the `added` and `removed` variables, add text to the `output` | |
# variable. if both added and removed have text, then there's a replacement, which gets | |
# special formatting | |
nonlocal added_lines, removed_lines, output | |
added = "\n".join(added_lines) | |
removed = "\n".join(removed_lines) | |
def _format_diff_replacement(before: str, after: str) -> str: | |
# print before and after lines highlight specific changes on those lines based | |
# on the longest common substrings | |
before = re.sub(r"(^|\n)-", r"\1", before) | |
after = re.sub(r"(^|\n)\+", r"\1", after) | |
def _colorize_str(x: str, color: str) -> str: | |
return ANSI_RESET + color + x + ANSI_RESET | |
matcher = difflib.SequenceMatcher(None, before, after) | |
before_output = "" | |
after_output = "" | |
for tag, i1, i2, j1, j2 in matcher.get_opcodes(): | |
before_substr = before[i1:i2] | |
after_substr = after[j1:j2] | |
if tag == "equal": | |
before_output += _colorize_str(before_substr, ANSI_RED) | |
after_output += _colorize_str(after_substr, ANSI_GREEN) | |
elif tag == "delete": | |
before_output += _colorize_str(before_substr, ANSI_BG_RED) | |
elif tag == "insert": | |
after_output += _colorize_str(after_substr, ANSI_BG_GREEN) | |
elif tag == "replace": | |
before_output += _colorize_str(before_substr, ANSI_BG_RED) | |
after_output += _colorize_str(after_substr, ANSI_BG_GREEN) | |
before_output = re.sub(r"(^|\n)", rf"\1{ANSI_RED}-{ANSI_RESET}", before_output) | |
after_output = re.sub(r"(^|\n)", rf"\1{ANSI_GREEN}+{ANSI_RESET}", after_output) | |
return before_output + "\n" + after_output + "\n" | |
if added or removed: | |
if added and not removed: | |
output += f"{ANSI_RESET}{ANSI_GREEN}{added}{ANSI_RESET}\n" | |
elif removed and not added: | |
output += f"{ANSI_RESET}{ANSI_RED}{removed}{ANSI_RESET}\n" | |
elif added and removed: | |
output += _format_diff_replacement(removed, added) | |
del added_lines, removed_lines | |
added_lines = [] | |
removed_lines = [] | |
# for line in diff: | |
delme = [x for x in diff] | |
for line in delme: | |
if line.strip() in ["---", "+++"]: | |
continue | |
if line.startswith("+"): | |
added_lines.append(line) | |
elif line.startswith("-"): | |
removed_lines.append(line) | |
else: | |
# print any cached added and removed lines, then reset cached lines, then print line | |
_format_added_removed() | |
if line.startswith("@@") and line.endswith("@@"): | |
output += stringc(line, C.COLOR_DIFF_LINES) | |
else: | |
output += line | |
output += "\n" | |
_format_added_removed() | |
return output |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment