#!/usr/bin/python # based on ratmenu(1) for compatibility, but uses curses directly. # One day it could/should evolve into doing curses and X... import optparse import itertools import curses import sys import time import os # def group_into_pairs(iterable): # """Group a list into pairs. There should a neater way...""" # return map(lambda x: list(x[1])[1], # itertools.groupby(enumerate(iterable), # lambda x: int(x[0]/2))) def group_into_pairs(iterable): return list(itertools.izip(*[iter(iterable)]*2)) def redraw(stdscr, cmdlist, target_line): for line, (label, cmd) in enumerate(cmdlist): stdscr.addstr(line, 0, label, line != target_line or curses.A_REVERSE) # keys documented in the ratmenu manpage up_keys = [ ord('k'), curses.KEY_UP, curses.KEY_BACKSPACE, ord('-') ] down_keys = [ ord('j'), curses.KEY_DOWN, ord(' '), ord('\t'), ord('+') ] select_keys = [ ord('l'), curses.KEY_RIGHT, curses.KEY_ENTER, ord('\n') ] back_keys = [ ord('h'), curses.KEY_LEFT ] exit_keys = [ ord('q'), 27 ] # esc def cursesui(stdscr, cmdlist): selected_line = 0 curses.curs_set(0) while True: redraw(stdscr, cmdlist, selected_line) # stdscr.refresh() c = stdscr.getch() if c == ord('q'): return elif c in down_keys: selected_line = (selected_line + 1) % len(cmdlist) elif c in up_keys: selected_line = (selected_line - 1) % len(cmdlist) elif c in select_keys: return selected_line elif c in back_keys: return -1 elif c in exit_keys: return None else: stdscr.addstr(9, 9, str(c)) if __name__ == "__main__": parser = optparse.OptionParser(usage="%prog: see ratmenu(1)") for compat_option in ["display", "font", "label"]: parser.add_option("--%s" % compat_option, help="ignored for compatibility") parser.add_option("--fg", help="foreground color (not yet)") parser.add_option("--bg", help="foreground color (not yet)") parser.add_option("--io", help="start from somewhere other than the top (1-based)") parser.add_option("--style", choices=["snazzy", "dreary"], default="snazzy", help="move cursor vs. move items") parser.add_option("--align", choices=["left", "center", "right"], default="left", help="menu item text alignment") parser.add_option("--shell", default="/bin/sh", help="alternative shell (default and fallback is /bin/sh)") parser.add_option("--back", help="command to back out to previous menu") parser.add_option("--persist", action="store_true", help="ignored for compatibility") # and we get --version for free options, args = parser.parse_args() cmdlist = group_into_pairs(args) selection = curses.wrapper(cursesui, cmdlist) if selection is None: sys.exit() elif selection == -1: if options.back: os.execv(options.shell, ["sh", "-c", options.back]) else: sys.exit("hit back, but no --back supplied") else: label, cmd = cmdlist[selection] os.execv(options.shell, ["sh", "-c", cmd])