Last active
December 19, 2024 17:03
-
-
Save soxofaan/e97112c4789ee74e1bf61532c998c0eb to your computer and use it in GitHub Desktop.
Python implementation of side-by-side diff
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
# Code licensed MIT 2023 Stefaan Lippens | |
import difflib | |
import itertools | |
from typing import List, Tuple, Iterator | |
class Sdiffer: | |
def __init__(self, max_width:int = 80): | |
# Two columns with a gutter | |
self._col_width = (max_width - 3) // 2 | |
assert self._col_width > 0 | |
def _fit(self, s: str) -> str: | |
s = s.rstrip()[:self._col_width] | |
return f"{s: <{self._col_width}}" | |
def sdiff(self, a: List[str], b: List[str]) -> Iterator[str]: | |
diff_lines = difflib.Differ().compare(a, b) | |
diff_table: List[Tuple[str, List[str], List[str]]] = [] | |
for diff_type, line_group in itertools.groupby(diff_lines, key=lambda ln: ln[:1]): | |
lines = [ln[2:] for ln in line_group] | |
if diff_type == " ": | |
diff_table.append((" ", lines, lines)) | |
else: | |
if not diff_table or diff_table[-1][0] != "|": | |
diff_table.append(("|", [], [])) | |
if diff_type == "-": | |
# Lines only in `a` | |
diff_table[-1][1].extend(lines) | |
elif diff_type == "+": | |
# Lines only in `b` | |
diff_table[-1][2].extend(lines) | |
for diff_type, cell_a, cell_b in diff_table: | |
for left, right in itertools.zip_longest(cell_a, cell_b, fillvalue=""): | |
yield f"{self._fit(left)} {diff_type} {self._fit(right)}" | |
def print_sdiff(self, a: List[str], b: List[str]) -> Iterator[str]: | |
print("\n".join(self.sdiff(a, b))) |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
usage example: