Skip to content

Instantly share code, notes, and snippets.

@furnox
Created February 3, 2020 18:18
Show Gist options
  • Save furnox/e07d714df76244bacd350622b86c3122 to your computer and use it in GitHub Desktop.
Save furnox/e07d714df76244bacd350622b86c3122 to your computer and use it in GitHub Desktop.
PyCurses manager for git stashes
#!//usr/bin/python3
import curses
import subprocess
import io
import re, time
def anyKeyToContinue(stdscr):
stdscr.addstr('\n\nPress any key to continue...')
curses.doupdate()
while stdscr.getch() < 1:
pass
stdscr.clear()
def getStashes():
raw_stash = subprocess.run(['git', 'stash', 'list'], stdout=subprocess.PIPE).stdout.decode('utf-8')
stash = {}
with io.StringIO(raw_stash, newline='\n') as file_stash:
for line in file_stash:
cols = line.split(':')
index = int(re.search('\d+', cols[0]).group(0))
stash[index] = (cols[1].strip(),cols[2].strip())
return (stash, len(stash))
def main(stdscr):
curses.init_pair(1, curses.COLOR_BLACK, curses.COLOR_WHITE) # Highlighted
curses.init_pair(2, curses.COLOR_CYAN, curses.COLOR_BLACK) # index, description
curses.init_pair(3, curses.COLOR_BLUE, curses.COLOR_BLACK) # Branch
curses.curs_set(False)
stdscr.scrollok(True)
(stash, num_stashes) = getStashes()
if num_stashes == 0:
stdscr.addstr('This either is not a git repository, or there are no stashes.')
anyKeyToContinue(stdscr)
exit(0)
max_index_len = 0
max_branch_len = 0
max_description_len = 0
for index, item in stash.items():
if len(str(index)) > max_index_len:
max_index_len = len(str(index))
if len(item[0]) > max_branch_len:
max_branch_len = len(item[0])
if len(item[1]) > max_description_len:
max_description_len = len(item[1])
key = 0
position = 0
while True:
stdscr.addstr(1, 1, ' '.ljust(max_index_len + 3, ' ') + 'Branch'.ljust(max_branch_len + 2, ' ') + 'Description')
for index, item in stash.items():
index_string = '%s)' % (index)
branch_string = item[0]
description_string = item[1]
index_color = 2
branch_color = 3
description_color = 2
space_color = 0
if index == position:
index_color = branch_color = description_color = space_color = 1
cursor_y = 2+index
cursor_x = 1
stdscr.addstr(cursor_y, cursor_x, index_string.ljust(max_index_len + 3, ' '), curses.color_pair(index_color))
cursor_x += max_index_len + 3
stdscr.addstr(cursor_y, cursor_x, branch_string.ljust(max_branch_len + 2, ' '), curses.color_pair(branch_color))
cursor_x += max_branch_len + 2
stdscr.addstr(cursor_y, cursor_x, description_string.ljust(max_description_len, ' '), curses.color_pair(description_color))
stdscr.addstr('\n [A]pply; [P]op; [S]how; [D]rop; [Q]uit')
curses.doupdate()
key = stdscr.getch()
if key in [ord('a'), ord('A'), ord('p'), ord('P'), ord('s'), ord('S'), ord('d'), ord('D')]:
stash_key = 'stash@{%d}' % position
keys = None
if chr(key).upper() == 'P':
mode = 'pop'
elif chr(key).upper() == 'A':
mode = 'apply'
elif chr(key).upper() == 'D':
mode = 'drop'
elif chr(key).upper() == 'S':
mode = 'show'
run = subprocess.run(['git', 'stash', mode, stash_key], stdout=subprocess.PIPE, stderr=subprocess.PIPE)
if run.stdout:
stdscr.addstr('\n\n' + run.stdout.decode('utf-8'))
elif run.stderr:
stdscr.addstr('\n\n' + run.stderr.decode('utf-8'))
anyKeyToContinue(stdscr)
if mode == 'drop' or mode == 'pop':
(stash, num_stashes) = getStashes()
position = 0
if num_stashes == 0:
exit()
elif key == curses.KEY_UP:
if position > 0:
position = position - 1
elif key == curses.KEY_DOWN:
if position < num_stashes - 1:
position = position + 1
elif key in [ord('q'), ord('Q')]:
exit(0)
if __name__ == "__main__":
curses.wrapper(main)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment