You cannot select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
111 lines
2.7 KiB
Python
111 lines
2.7 KiB
Python
#!/usr/bin/python3
|
|
|
|
import subprocess
|
|
import re
|
|
import curses
|
|
import os
|
|
import sys
|
|
|
|
class Commit(object):
|
|
_RE_COMMIT = re.compile(r"(?P<hash>[abcdefABCDEF0-9]{3,16}) (?P<title>.+)")
|
|
def __init__(self, line):
|
|
"""@todo: to be defined1. """
|
|
match = Commit._RE_COMMIT.search(line)
|
|
if not match:
|
|
raise ValueError
|
|
self.hash = match.group("hash")
|
|
self.title = match.group("title")
|
|
|
|
process = subprocess.Popen(["git", "--no-pager", "log", "--decorate=short", "--oneline"] + sys.argv[1:], stdout=subprocess.PIPE, stderr=open('/dev/null', 'w'))
|
|
commits = []
|
|
for part in process.communicate():
|
|
if part == None:
|
|
break
|
|
for line in part.decode('utf-8').split('\n'):
|
|
if not line:
|
|
continue
|
|
commits.append(Commit(line))
|
|
|
|
|
|
if len(commits) == 0:
|
|
print("No repo?")
|
|
sys.exit(0)
|
|
|
|
stdscr = curses.initscr()
|
|
curses.start_color()
|
|
curses.curs_set(False)
|
|
curses.use_default_colors()
|
|
curses.noecho()
|
|
curses.cbreak()
|
|
stdscr.keypad(True)
|
|
stdscr.refresh()
|
|
curses.init_pair(1, curses.COLOR_BLACK, curses.COLOR_YELLOW)
|
|
curses.init_pair(2, curses.COLOR_YELLOW, curses.COLOR_BLACK)
|
|
|
|
maxcoords = stdscr.getmaxyx()
|
|
max_y, max_x = maxcoords[0], maxcoords[1]
|
|
|
|
|
|
def show_commit(commit):
|
|
stdscr.erase()
|
|
stdscr.refresh()
|
|
os.system(f"LESS='RSX' git show {commit.hash}")
|
|
|
|
|
|
pad = curses.newpad(len(commits), max_x)
|
|
|
|
|
|
def print_commit(commit, pos_y, selected):
|
|
pad.addstr(pos_y, 0, " " * (max_x - 1))
|
|
cut_to = max_x - 3 - len(commit.hash)
|
|
if selected:
|
|
pad.addstr(pos_y, 0, f"{commit.hash}", curses.color_pair(1))
|
|
pad.addstr(pos_y, len(commit.hash) + 2, f"{commit.title[:cut_to]}", curses.color_pair(1))
|
|
else:
|
|
pad.addstr(pos_y, 0, f"{commit.hash}", curses.color_pair(2))
|
|
pad.addstr(pos_y, len(commit.hash) + 2, f"{commit.title[:cut_to]}")
|
|
|
|
print_commit(commits[0], 0, True)
|
|
|
|
linenum = 1
|
|
for commit in commits[1:]:
|
|
print_commit(commit, linenum, False)
|
|
linenum += 1
|
|
|
|
pad.refresh(0, 0, 0, 0, max_y - 1, max_x - 1)
|
|
|
|
running = True
|
|
pos = 0
|
|
offset = 0
|
|
while running:
|
|
print_commit(commits[pos], pos, False)
|
|
|
|
mvmt = stdscr.getch()
|
|
if mvmt == ord('j'):
|
|
if pos < len(commits) - 1:
|
|
pos += 1
|
|
if pos - offset > max_y - 2 and offset < len(commits) - max_y + 5:
|
|
offset += 1
|
|
elif mvmt == ord('k'):
|
|
if pos > 0:
|
|
pos -= 1
|
|
if pos - offset < 4 and offset > 0:
|
|
offset -= 1
|
|
elif mvmt == ord('q'):
|
|
running = False
|
|
elif mvmt == ord('l'):
|
|
show_commit(commits[pos])
|
|
stdscr.clear()
|
|
stdscr.refresh()
|
|
|
|
print_commit(commits[pos], pos, True)
|
|
|
|
pad.refresh(offset, 0, 0, 0, max_y - 1, max_x - 1)
|
|
|
|
|
|
|
|
curses.nocbreak()
|
|
stdscr.keypad(False)
|
|
curses.echo()
|
|
curses.endwin()
|