"""Miscellaneous small utility functions. vol(vol=None) - get or set volume using aumix progress(ratio, length=40, col=1, cols=("yellow", None, "cyan"), nocol="=.") Text mode progress bar. yes(question, [default answer]) i.e. if yes("erase file?", 'n'): erase_file() color(text, fg, [bg]) colorize text using terminal color codes beep() - beep terminal bell once ftime(seconds) - returns h:m:s or m:s if there's no hours. Term() - terminal stuff term.size() => height, width term.clear() => clear terminal term.getch() => get one char at a time Copyright (C) 2002 Andrei Kulakov Licence: GPL [see http://www.gnu.org/copyleft/gpl.html] """ import os import sys import termios import commands from types import * enable_color = 1 def vol(vol=None): """Set or show audio volume. Uses external mixer called aumix. One optional argument, vol, may be an int or a string. If a string, it can be of the form "+10". """ if vol: vol = str(vol) os.system("aumix -v" + vol) else: v = commands.getoutput("aumix -vq").split()[1] return v[:-1] def progress(ratio, length=40, col=1, cols=("yellow", None, "cyan"), nocol="=."): """Text mode progress bar. ratio - current position / total (e.g. 0.6 is 60%) length - bar size col - color bar cols - tuple: (elapsed, left, percentage num) nocol - string, if default="=.", bar is [=======.....] """ # TODO: percent display in the middle of the bar if ratio > 1: ratio = 1 elchar, leftchar = nocol elapsed = int(round(ratio*length)) left = length - elapsed bar = elchar*elapsed + leftchar*left bar = bar[:length] if col: c_elapsed, c_left, perc = cols bar = color(' '*elapsed, "gray", c_elapsed) bar += color(' '*left, "gray", c_left) else: bar = elchar*elapsed + leftchar*left return bar def yes(question, default=None): """Get an answer for the question. Return 1 on 'yes' and 0 on 'no'; default may be set to 'y' or 'n'; asks "Question? [Y/n]" (default is capitalized). Yy and Nn are acceptable. Question is asked until a valid answer is given. """ y = 'y' n = 'n' if default: if default in "Yy": y = 'Y' elif default in "Nn": n = 'N' else: print "Error: default must be 'y' or 'n'." return while 1: answer = raw_input(question + " [%s/%s] " % (y, n)) if default: if default in "Yy": if not answer or (len(answer) == 1 and answer in "Yy"): return 1 elif len(answer) == 1 and answer in "Nn": return 0 elif default in "Nn": if not answer or (len(answer) == 1 and answer in "Nn"): return 0 elif len(answer) == 1 and answer in "Yy": return 1 else: if len(answer) == 1 and answer in "Yy": return 1 elif len(answer) == 1 and answer in "Nn": return 0 def no(question, default=None): return not yes(question, default) def color(text, fg, bg=None): """Return colored text. Uses terminal color codes; set avk_util.enable_color to 0 to return plain un-colored text. If fg is a tuple, it's assumed to be (fg, bg). """ if type(fg) == TupleType: fg, bg = fg xterm = 0 if os.environ["TERM"] == "xterm": xterm = 1 if enable_color: col_dict = { "black" : "30m", "red" : "31m", "green" : "32m", "brown" : "33m", "blue" : "34m", "purple" : "35m", "cyan" : "36m", "lgray" : "37m", "gray" : "1;30m", "lred" : "1;31m", "lgreen" : "1;32m", "yellow" : "1;33m", "lblue" : "1;34m", "pink" : "1;35m", "lcyan" : "1;36m", "white" : "1;37m", } b = "0m" s = "\033[" clear = "0m" # In xterm, brown comes out as yellow.. if xterm and fg == "yellow": color = "brown" f = col_dict[fg] if bg: if bg == "yellow" and xterm: bg = "brown" try: b = col_dict[bg].replace('3', '4', 1) except KeyError: pass return "%s%s%s%s%s%s%s" % (s, b, s, f, text, s, clear) else: return text def beep(): """Beep terminal bell one time.""" print '\a' def ftime(seconds): """Format time. hour:min:sec if hours > 0; otherwise min:sec. """ seconds = int(seconds) hours = seconds / (60*60) seconds = seconds - hours*60*60 mins = seconds / 60 secs = seconds - mins*60 if int(hours): s = "%d:%02d:%02d" % (hours, mins, secs) else: s = "%d:%02d" % (mins, secs) return s class Term: """Linux terminal management. clear - calls os.system("clear") getch - get one char at a time size - return height, width of the terminal """ def __init__(self): self.fd = sys.stdin.fileno() self.new_term = termios.tcgetattr(self.fd) self.old_term = termios.tcgetattr(self.fd) self.ver = None if sys.version_info[0] == 2 and sys.version_info[1] == 0: self.ver = 20 if self.ver == 20: self.new_term[3] = (self.new_term[3] & ~TERMIOS.ICANON & ~TERMIOS.ECHO) else: self.new_term[3] = (self.new_term[3] & ~termios.ICANON & ~termios.ECHO) def normal(self): """Set 'normal' terminal settings.""" if self.ver == 20: termios.tcsetattr(self.fd, TERMIOS.TCSAFLUSH, self.old_term) else: termios.tcsetattr(self.fd, termios.TCSAFLUSH, self.old_term) def clear(self): """Clear screen.""" os.system("clear") def curses(self): """Set 'curses' terminal settings.""" if self.ver == 20: termios.tcsetattr(self.fd, TERMIOS.TCSAFLUSH, self.new_term) else: termios.tcsetattr(self.fd, termios.TCSAFLUSH, self.new_term) def getch(self): """Get one character at a time. NOTE: if the user suspends (^Z) running program, then brings it back to foreground, you have to instantiate Term class again. Otherwise getch() won't work. Even after that, the user has to hit 'enter' once before he can enter commands. """ self.curses() c = os.read(self.fd, 1) self.normal() return c def size(self): """Return terminal size as tuple (height, width).""" import struct, fcntl h,w = 0,0 if self.ver == 20: h, w = struct.unpack("hhhh", fcntl.ioctl(0, TERMIOS.TIOCGWINSZ, "\000"*8))[0:2] else: h, w = struct.unpack("hhhh", fcntl.ioctl(0, termios.TIOCGWINSZ, "\000"*8))[0:2] if not h and w: h, w = 24, 80 return h, w