~nico-inattendu/luciole/0.9

« back to all changes in this revision

Viewing changes to pitivi/log/termcolor.py

  • Committer: NicoInattendu
  • Date: 2011-02-28 18:27:56 UTC
  • mfrom: (123.1.54 luciole-with-sound)
  • Revision ID: nico@inattendu.org-20110228182756-weonszu8zpzermrl
initial merge with luciole-with-sound branch

Show diffs side-by-side

added added

removed removed

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