-
-
Notifications
You must be signed in to change notification settings - Fork 186
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
feat: add ability to show unified diffs for changed files #562
base: master
Are you sure you want to change the base?
Changes from 2 commits
cfd6918
57897f6
bef089c
7e7e1a7
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change | ||||||||||||||||||||||||||||||||||||||||||||
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
|
@@ -8,6 +8,7 @@ | |||||||||||||||||||||||||||||||||||||||||||||
import tempfile | ||||||||||||||||||||||||||||||||||||||||||||||
import warnings | ||||||||||||||||||||||||||||||||||||||||||||||
from contextlib import suppress | ||||||||||||||||||||||||||||||||||||||||||||||
from difflib import unified_diff | ||||||||||||||||||||||||||||||||||||||||||||||
from pathlib import Path | ||||||||||||||||||||||||||||||||||||||||||||||
from types import TracebackType | ||||||||||||||||||||||||||||||||||||||||||||||
from typing import Any, Callable, Optional, TextIO, Tuple, Union | ||||||||||||||||||||||||||||||||||||||||||||||
|
@@ -16,7 +17,7 @@ | |||||||||||||||||||||||||||||||||||||||||||||
from packaging.version import Version | ||||||||||||||||||||||||||||||||||||||||||||||
from pydantic import StrictBool | ||||||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||||||
from .types import IntSeq | ||||||||||||||||||||||||||||||||||||||||||||||
from .types import IntSeq, StrSeq | ||||||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||||||
try: | ||||||||||||||||||||||||||||||||||||||||||||||
from importlib.metadata import version | ||||||||||||||||||||||||||||||||||||||||||||||
|
@@ -172,3 +173,56 @@ def cleanup(self): | |||||||||||||||||||||||||||||||||||||||||||||
@staticmethod | ||||||||||||||||||||||||||||||||||||||||||||||
def _robust_cleanup(name): | ||||||||||||||||||||||||||||||||||||||||||||||
shutil.rmtree(name, ignore_errors=False, onerror=handle_remove_readonly) | ||||||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||||||
def get_lines(content: bytes) -> StrSeq: | ||||||||||||||||||||||||||||||||||||||||||||||
# Assume UTF-8 encoding for text files. Since Jinja2 is already doing this | ||||||||||||||||||||||||||||||||||||||||||||||
# for templates, there probably isn't much harm in also doing it for all | ||||||||||||||||||||||||||||||||||||||||||||||
# text files. The worst case should be a failure to show the diffs. An | ||||||||||||||||||||||||||||||||||||||||||||||
# alternative is to add chardet support. | ||||||||||||||||||||||||||||||||||||||||||||||
return content.decode("utf-8").split(os.linesep) | ||||||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||||||
def is_binary(content: bytes) -> bool: | ||||||||||||||||||||||||||||||||||||||||||||||
"""Return a boolean indicating if the content is a binary file.""" | ||||||||||||||||||||||||||||||||||||||||||||||
return b"\x00" in content or b"\xff" in content | ||||||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||||||
def color_print(color: int, msg: str): | ||||||||||||||||||||||||||||||||||||||||||||||
print(f"{color}{msg}{colorama.Fore.RESET}") | ||||||||||||||||||||||||||||||||||||||||||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. You have https://python-prompt-toolkit.readthedocs.io/en/master/pages/printing_text.html#html and https://plumbum.readthedocs.io/en/latest/colors.html for printing colorized output. You probably won't need this function. |
||||||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||||||
def print_diff(dst_relpath: Path, original_content: bytes, new_content: bytes): | ||||||||||||||||||||||||||||||||||||||||||||||
try: | ||||||||||||||||||||||||||||||||||||||||||||||
original_lines = get_lines(original_content) | ||||||||||||||||||||||||||||||||||||||||||||||
except Exception: | ||||||||||||||||||||||||||||||||||||||||||||||
color_print( | ||||||||||||||||||||||||||||||||||||||||||||||
colorama.Fore.YELLOW, "diff unavailable: unable to determine encoding" | ||||||||||||||||||||||||||||||||||||||||||||||
) | ||||||||||||||||||||||||||||||||||||||||||||||
return | ||||||||||||||||||||||||||||||||||||||||||||||
try: | ||||||||||||||||||||||||||||||||||||||||||||||
new_lines = get_lines(new_content) | ||||||||||||||||||||||||||||||||||||||||||||||
except Exception: | ||||||||||||||||||||||||||||||||||||||||||||||
color_print( | ||||||||||||||||||||||||||||||||||||||||||||||
colorama.Fore.YELLOW, "diff unavailable: unable to determine encoding" | ||||||||||||||||||||||||||||||||||||||||||||||
) | ||||||||||||||||||||||||||||||||||||||||||||||
return | ||||||||||||||||||||||||||||||||||||||||||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I know some flake8 plugins would say: "only one line in a try block", but this could probably be factorized as:
Suggested change
Also, is there a reason you catch There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I could combine the try blocks. The reason I'm currently catching Exception is mostly because this isn't ready to merge. My first version used Since the previous implementations had a few exceptions to catch and there is no particular handing for any of them I just went with Exception. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I see, thanks! |
||||||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||||||
indent = " " * 6 | ||||||||||||||||||||||||||||||||||||||||||||||
for line in unified_diff( | ||||||||||||||||||||||||||||||||||||||||||||||
original_lines, | ||||||||||||||||||||||||||||||||||||||||||||||
new_lines, | ||||||||||||||||||||||||||||||||||||||||||||||
f"old/{dst_relpath}", | ||||||||||||||||||||||||||||||||||||||||||||||
f"new/{dst_relpath}", | ||||||||||||||||||||||||||||||||||||||||||||||
lineterm="", | ||||||||||||||||||||||||||||||||||||||||||||||
): | ||||||||||||||||||||||||||||||||||||||||||||||
if line.startswith("---") or line.startswith("+++"): | ||||||||||||||||||||||||||||||||||||||||||||||
color_print(colorama.Fore.YELLOW, f"{indent}{line}") | ||||||||||||||||||||||||||||||||||||||||||||||
elif line.startswith("@@"): | ||||||||||||||||||||||||||||||||||||||||||||||
color_print(colorama.Fore.MAGENTA, f"{indent}{line}") | ||||||||||||||||||||||||||||||||||||||||||||||
elif line.startswith("-"): | ||||||||||||||||||||||||||||||||||||||||||||||
color_print(colorama.Fore.RED, f"{indent}{line}") | ||||||||||||||||||||||||||||||||||||||||||||||
elif line.startswith("+"): | ||||||||||||||||||||||||||||||||||||||||||||||
color_print(colorama.Fore.GREEN, f"{indent}{line}") | ||||||||||||||||||||||||||||||||||||||||||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. https://python-prompt-toolkit.readthedocs.io/en/master/pages/printing_text.html#pygments-token-text-tuples with a diff lexer should save a lot of code around here. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. So I was going down this path first, but it seemed very difficult to get the result I wanted. I went ahead and finished that work a put together a gist showing the differences. One reason the new code is much larger is that I wanted to have the two-line file header yellow like it is with git. This meant that I had to extend the lexer. In order to add the extra indentation, I had to also extend the There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I see. Well, I'll have to do local testing for both implementations, because code looks complex in both cases, so if we're getting a complexity, I'll get the one that looks/works better 😄 There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I'll update this implementation here since that's what I'm actively using and I think I can make it cleaner and more concise. If you like the other way better I can switch to that later. |
||||||||||||||||||||||||||||||||||||||||||||||
else: | ||||||||||||||||||||||||||||||||||||||||||||||
print(f"{indent}{line}") |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is a nice addition. I don't think it's needed to add a new flag for it.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Just default to always diff when we can?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yes, I can't imagine a use case where the no diff is more useful if we're on interactive mode.