Package libprs500 :: Module terminfo
[hide private]
[frames] | no frames]

Source Code for Module libprs500.terminfo

  1  import sys, re 
  2   
3 -class TerminalController:
4 """ 5 A class that can be used to portably generate formatted output to 6 a terminal. 7 8 `TerminalController` defines a set of instance variables whose 9 values are initialized to the control sequence necessary to 10 perform a given action. These can be simply included in normal 11 output to the terminal: 12 13 >>> term = TerminalController() 14 >>> print 'This is '+term.GREEN+'green'+term.NORMAL 15 16 Alternatively, the `render()` method can used, which replaces 17 '${action}' with the string required to perform 'action': 18 19 >>> term = TerminalController() 20 >>> print term.render('This is ${GREEN}green${NORMAL}') 21 22 If the terminal doesn't support a given action, then the value of 23 the corresponding instance variable will be set to ''. As a 24 result, the above code will still work on terminals that do not 25 support color, except that their output will not be colored. 26 Also, this means that you can test whether the terminal supports a 27 given action by simply testing the truth value of the 28 corresponding instance variable: 29 30 >>> term = TerminalController() 31 >>> if term.CLEAR_SCREEN: 32 ... print 'This terminal supports clearning the screen.' 33 34 Finally, if the width and height of the terminal are known, then 35 they will be stored in the `COLS` and `LINES` attributes. 36 """ 37 # Cursor movement: 38 BOL = '' #: Move the cursor to the beginning of the line 39 UP = '' #: Move the cursor up one line 40 DOWN = '' #: Move the cursor down one line 41 LEFT = '' #: Move the cursor left one char 42 RIGHT = '' #: Move the cursor right one char 43 44 # Deletion: 45 CLEAR_SCREEN = '' #: Clear the screen and move to home position 46 CLEAR_EOL = '' #: Clear to the end of the line. 47 CLEAR_BOL = '' #: Clear to the beginning of the line. 48 CLEAR_EOS = '' #: Clear to the end of the screen 49 50 # Output modes: 51 BOLD = '' #: Turn on bold mode 52 BLINK = '' #: Turn on blink mode 53 DIM = '' #: Turn on half-bright mode 54 REVERSE = '' #: Turn on reverse-video mode 55 NORMAL = '' #: Turn off all modes 56 57 # Cursor display: 58 HIDE_CURSOR = '' #: Make the cursor invisible 59 SHOW_CURSOR = '' #: Make the cursor visible 60 61 # Terminal size: 62 COLS = None #: Width of the terminal (None for unknown) 63 LINES = None #: Height of the terminal (None for unknown) 64 65 # Foreground colors: 66 BLACK = BLUE = GREEN = CYAN = RED = MAGENTA = YELLOW = WHITE = '' 67 68 # Background colors: 69 BG_BLACK = BG_BLUE = BG_GREEN = BG_CYAN = '' 70 BG_RED = BG_MAGENTA = BG_YELLOW = BG_WHITE = '' 71 72 _STRING_CAPABILITIES = """ 73 BOL=cr UP=cuu1 DOWN=cud1 LEFT=cub1 RIGHT=cuf1 74 CLEAR_SCREEN=clear CLEAR_EOL=el CLEAR_BOL=el1 CLEAR_EOS=ed BOLD=bold 75 BLINK=blink DIM=dim REVERSE=rev UNDERLINE=smul NORMAL=sgr0 76 HIDE_CURSOR=cinvis SHOW_CURSOR=cnorm""".split() 77 _COLORS = """BLACK BLUE GREEN CYAN RED MAGENTA YELLOW WHITE""".split() 78 _ANSICOLORS = "BLACK RED GREEN YELLOW BLUE MAGENTA CYAN WHITE".split() 79
80 - def __init__(self, term_stream=sys.stdout):
81 """ 82 Create a `TerminalController` and initialize its attributes 83 with appropriate values for the current terminal. 84 `term_stream` is the stream that will be used for terminal 85 output; if this stream is not a tty, then the terminal is 86 assumed to be a dumb terminal (i.e., have no capabilities). 87 """ 88 # Curses isn't available on all platforms 89 try: import curses 90 except: return 91 92 # If the stream isn't a tty, then assume it has no capabilities. 93 if not term_stream.isatty(): return 94 95 # Check the terminal type. If we fail, then assume that the 96 # terminal has no capabilities. 97 try: curses.setupterm() 98 except: return 99 100 # Look up numeric capabilities. 101 self.COLS = curses.tigetnum('cols') 102 self.LINES = curses.tigetnum('lines') 103 104 # Look up string capabilities. 105 for capability in self._STRING_CAPABILITIES: 106 (attrib, cap_name) = capability.split('=') 107 setattr(self, attrib, self._tigetstr(cap_name) or '') 108 109 # Colors 110 set_fg = self._tigetstr('setf') 111 if set_fg: 112 for i,color in zip(range(len(self._COLORS)), self._COLORS): 113 setattr(self, color, curses.tparm(set_fg, i) or '') 114 set_fg_ansi = self._tigetstr('setaf') 115 if set_fg_ansi: 116 for i,color in zip(range(len(self._ANSICOLORS)), self._ANSICOLORS): 117 setattr(self, color, curses.tparm(set_fg_ansi, i) or '') 118 set_bg = self._tigetstr('setb') 119 if set_bg: 120 for i,color in zip(range(len(self._COLORS)), self._COLORS): 121 setattr(self, 'BG_'+color, curses.tparm(set_bg, i) or '') 122 set_bg_ansi = self._tigetstr('setab') 123 if set_bg_ansi: 124 for i,color in zip(range(len(self._ANSICOLORS)), self._ANSICOLORS): 125 setattr(self, 'BG_'+color, curses.tparm(set_bg_ansi, i) or '')
126
127 - def _tigetstr(self, cap_name):
128 # String capabilities can include "delays" of the form "$<2>". 129 # For any modern terminal, we should be able to just ignore 130 # these, so strip them out. 131 import curses 132 cap = curses.tigetstr(cap_name) or '' 133 return re.sub(r'\$<\d+>[/*]?', '', cap)
134
135 - def render(self, template):
136 """ 137 Replace each $-substitutions in the given template string with 138 the corresponding terminal control string (if it's defined) or 139 '' (if it's not). 140 """ 141 return re.sub(r'\$\$|\${\w+}', self._render_sub, template)
142
143 - def _render_sub(self, match):
144 s = match.group() 145 if s == '$$': return s 146 else: return getattr(self, s[2:-1])
147 148 ####################################################################### 149 # Example use case: progress bar 150 ####################################################################### 151
152 -class ProgressBar:
153 """ 154 A 3-line progress bar, which looks like:: 155 156 Header 157 20% [===========----------------------------------] 158 progress message 159 160 The progress bar is colored, if the terminal supports color 161 output; and adjusts to the width of the terminal. 162 """ 163 BAR = '%3d%% ${GREEN}[${BOLD}%s%s${NORMAL}${GREEN}]${NORMAL}\n' 164 HEADER = '${BOLD}${CYAN}%s${NORMAL}\n\n' 165
166 - def __init__(self, term, header):
167 self.term = term 168 if not (self.term.CLEAR_EOL and self.term.UP and self.term.BOL): 169 raise ValueError("Terminal isn't capable enough -- you " 170 "should use a simpler progress dispaly.") 171 self.width = self.term.COLS or 75 172 self.bar = term.render(self.BAR) 173 self.header = self.term.render(self.HEADER % header.center(self.width)) 174 self.cleared = 1 #: true if we haven't drawn the bar yet. 175 self.update(0, '')
176
177 - def update(self, percent, message):
178 if self.cleared: 179 sys.stdout.write(self.header) 180 self.cleared = 0 181 n = int((self.width-10)*percent) 182 sys.stdout.write( 183 self.term.BOL + self.term.UP + self.term.CLEAR_EOL + 184 (self.bar % (100*percent, '='*n, '-'*(self.width-10-n))) + 185 self.term.CLEAR_EOL + message.center(self.width))
186
187 - def clear(self):
188 if not self.cleared: 189 sys.stdout.write(self.term.BOL + self.term.CLEAR_EOL + 190 self.term.UP + self.term.CLEAR_EOL + 191 self.term.UP + self.term.CLEAR_EOL) 192 self.cleared = 1
193