Created
June 2, 2024 22:13
-
-
Save tos-kamiya/aac13869b2d226e01ed4bac32589e990 to your computer and use it in GitHub Desktop.
VSCode like Git status viewer
This file contains 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
#!/usr/bin/env python3 | |
from typing import List, Iterable, Iterator, Tuple | |
import subprocess | |
import sys | |
def colorize(text: str, color: str) -> str: | |
""" | |
Colorize the text for terminal output. | |
Args: | |
text: The text to colorize. | |
color: The color to use. | |
Returns: | |
The colorized text. | |
""" | |
if sys.stdout.isatty(): # Only colorize if outputting to a tty | |
if color == 'red': | |
return f"\033[91m{text}\033[0m" | |
elif color == 'green': | |
return f"\033[92m{text}\033[0m" | |
elif color == 'dim': | |
return f"\033[2m{text}\033[0m" | |
return text | |
def change_iter(lines: Iterable[str]) -> Iterator[Tuple[str, str, str]]: | |
""" | |
Iterate over git status lines and yield formatted output. | |
Args: | |
lines: Lines from `git status -s` output. | |
Yields: | |
Tuple[str, str, str]: Staged status, Changed status, filename. | |
""" | |
for line in lines: | |
assert line[2] == " " | |
status, filename = line[:2], line[3:] | |
# Format the output string based on the status | |
if status in ["AA", "DD"] or "U" in status: | |
yield "", "C", filename # conflicts | |
elif status == "??": | |
yield "", "U", filename | |
else: | |
staged_str = status[0] if status[0] != ' ' else "" | |
changes_str = status[1] if status[1] != ' ' else "" | |
if staged_str or changes_str: | |
yield staged_str, changes_str, filename | |
def main() -> None: | |
""" | |
Parse the output of git status -s and print it in a VSCode-like format. | |
""" | |
# Run git status -s and get the output | |
result = subprocess.run(['git', 'status', '-s'], capture_output=True, text=True) | |
output = result.stdout.splitlines() | |
staged_changes: List[str] = [] | |
changes: List[str] = [] | |
merge_conflict_files: List[str] = [] | |
# Iterate over changes using the iterator | |
for staged_str, changes_str, filename in change_iter(output): | |
if changes_str == "C": # Conflict | |
merge_conflict_files.append(filename) | |
else: | |
if staged_str: | |
staged_changes.append(colorize(staged_str, 'red' if staged_str == 'D' else 'green') + f" {filename}") | |
if changes_str: | |
changes.append(colorize(changes_str, 'red' if changes_str == 'D' else 'green') + f" {filename}") | |
# Print the results | |
if merge_conflict_files: | |
print("Merge Conflicts:") | |
for filename in merge_conflict_files: | |
print(" " + filename) | |
else: | |
print("Staged Changes:") | |
if staged_changes: | |
for filename in staged_changes: | |
print(filename) | |
else: | |
print(colorize(" -- No staged changes --", 'dim')) | |
print() | |
print("Changes:") | |
if changes: | |
for filename in changes: | |
print(filename) | |
else: | |
print(colorize(" -- No changes --", 'dim')) | |
if __name__ == "__main__": | |
main() |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment