Skip to content

Instantly share code, notes, and snippets.

@simonLeary42
Created September 10, 2024 20:21
Show Gist options
  • Save simonLeary42/ff794cf4425a4bea52a9ff17c1bc31c3 to your computer and use it in GitHub Desktop.
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.
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