Skip to content

Instantly share code, notes, and snippets.

@tos-kamiya
Created June 2, 2024 22:13
Show Gist options
  • Save tos-kamiya/aac13869b2d226e01ed4bac32589e990 to your computer and use it in GitHub Desktop.
Save tos-kamiya/aac13869b2d226e01ed4bac32589e990 to your computer and use it in GitHub Desktop.
VSCode like Git status viewer
#!/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