Skip to content

Instantly share code, notes, and snippets.

@KaoruNishikawa
Last active January 2, 2025 02:31
Show Gist options
  • Save KaoruNishikawa/55781991af9d50494dd85ac6db0cad89 to your computer and use it in GitHub Desktop.
Save KaoruNishikawa/55781991af9d50494dd85ac6db0cad89 to your computer and use it in GitHub Desktop.
Print Git-like diff of arbitrary 2 strings in Python
import difflib
def diff(a: str, b: str) -> None:
line_color = {"+": 32, "-": 31}
diffs = difflib.ndiff(a.splitlines(keepends=True), b.splitlines(keepends=True))
diff_list = list(diffs)
styled: list[str] = []
for prev, next in zip(diff_list, diff_list[1:] + [""]):
color = line_color.get(prev[0], 0)
match prev[0]:
case " ":
styled.append(prev)
case "+" | "-":
index = [i for i, c in enumerate(next) if c == "^"]
_prev = list(prev)
for idx in index:
_prev[idx] = f"\x1b[97;{color+10};1m{_prev[idx]}\x1b[0;{color}m"
styled.append(f'\x1b[{color}m{"".join(_prev)}\x1b[0m')
case "?":
continue
print("".join(styled))
Display the source blob
Display the rendered blob
Raw
{
"cells": [
{
"cell_type": "code",
"execution_count": 59,
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
" foo\n",
"\u001b[31m- b\u001b[97;41;1ma\u001b[0;31mr\n",
"\u001b[0m\u001b[32m+ b\u001b[97;42;1mb\u001b[0;32mr\n",
"\u001b[0m\u001b[31m- baz\n",
"\u001b[0m\u001b[32m+ quux\n",
"\u001b[0m\u001b[31m- ho\u001b[97;41;1mg\u001b[0;31meho\u001b[97;41;1mg\u001b[0;31me\n",
"\u001b[0m\u001b[32m+ ho\u001b[97;42;1md\u001b[0;32meho\u001b[97;42;1md\u001b[0;32me\n",
"\u001b[0m\n"
]
}
],
"source": [
"import difflib\n",
"\n",
"\n",
"def diff(a: str, b: str) -> None:\n",
" line_color = {\"+\": 32, \"-\": 31}\n",
"\n",
" diffs = difflib.ndiff(a.splitlines(keepends=True), b.splitlines(keepends=True))\n",
" diff_list = list(diffs)\n",
" styled: list[str] = []\n",
" for prev, next in zip(diff_list, diff_list[1:] + [\"\"]):\n",
" color = line_color.get(prev[0], 0)\n",
" match prev[0]:\n",
" case \" \":\n",
" styled.append(prev)\n",
" case \"+\" | \"-\":\n",
" index = [i for i, c in enumerate(next) if c == \"^\"]\n",
" _prev = list(prev)\n",
" for idx in index:\n",
" _prev[idx] = f\"\\x1b[97;{color+10};1m{_prev[idx]}\\x1b[0;{color}m\"\n",
" styled.append(f'\\x1b[{color}m{\"\".join(_prev)}\\x1b[0m')\n",
" case \"?\":\n",
" continue\n",
" print(\"\".join(styled))\n",
"\n",
"\n",
"a = \"\"\"\\\n",
"foo\n",
"bar\n",
"baz\n",
"hogehoge\n",
"\"\"\"\n",
"\n",
"b = \"\"\"\\\n",
"foo\n",
"bbr\n",
"quux\n",
"hodehode\n",
"\"\"\"\n",
"\n",
"diff(a, b)"
]
}
],
"metadata": {
"kernelspec": {
"display_name": ".venv",
"language": "python",
"name": "python3"
},
"language_info": {
"codemirror_mode": {
"name": "ipython",
"version": 3
},
"file_extension": ".py",
"mimetype": "text/x-python",
"name": "python",
"nbconvert_exporter": "python",
"pygments_lexer": "ipython3",
"version": "3.11.3"
},
"orig_nbformat": 4
},
"nbformat": 4,
"nbformat_minor": 2
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment