| 82 | | """ Find the current terminal width """ |
|---|
| 83 | | return 'COLUMNS' in os.environ and int(os.environ['COLUMNS']) or 80 |
|---|
| 84 | | |
|---|
| 85 | | def wraptoterm(text, **argd): |
|---|
| | 87 | """ Guess the current terminal width. """ |
|---|
| | 88 | try: |
|---|
| | 89 | return curses.tigetnum('cols') |
|---|
| | 90 | except: |
|---|
| | 91 | return 'COLUMNS' in os.environ and int(os.environ['COLUMNS']) or 80 |
|---|
| | 92 | |
|---|
| | 93 | def termheight(): |
|---|
| | 94 | """ Guess the current terminal height. """ |
|---|
| | 95 | try: |
|---|
| | 96 | return curses.tigetnum('lines') |
|---|
| | 97 | except: |
|---|
| | 98 | return 'LINES' in os.environ and int(os.environ['LINES']) or 25 |
|---|
| | 99 | |
|---|
| | 100 | def csplice(text, start = 0, end = -1): |
|---|
| | 101 | """ Splice a colour encoded string. """ |
|---|
| | 102 | out = '' |
|---|
| | 103 | if end == -1: |
|---|
| | 104 | end = len(text) |
|---|
| | 105 | sofar = 0 |
|---|
| | 106 | for token in __cprint_re.finditer(text): |
|---|
| | 107 | if sofar > end: break |
|---|
| | 108 | txt = token.group(0) |
|---|
| | 109 | if token.group(1): |
|---|
| | 110 | if start < sofar < end: |
|---|
| | 111 | out += txt |
|---|
| | 112 | else: |
|---|
| | 113 | # Whether beginning and end of segment are in slice |
|---|
| | 114 | bs = start < sofar < end |
|---|
| | 115 | es = start < sofar + len(txt) < end |
|---|
| | 116 | if bs and es: |
|---|
| | 117 | out += txt |
|---|
| | 118 | elif not bs and es: |
|---|
| | 119 | out += txt[start - sofar:] |
|---|
| | 120 | elif bs and not es: |
|---|
| | 121 | out += txt[:end - sofar] |
|---|
| | 122 | break |
|---|
| | 123 | elif sofar <= start and sofar + len(txt) >= end: |
|---|
| | 124 | out += txt[start - sofar:end] |
|---|
| | 125 | break |
|---|
| | 126 | sofar += len(txt) |
|---|
| | 127 | return out |
|---|
| | 128 | |
|---|
| | 129 | __cwrap_re = re.compile(r'''(\n)|(\s+)|((?:\^[N0-7BU]|\S)+\b[^^\w]*)''') |
|---|
| | 130 | def cwraptext(text, width = termwidth(), subsequent_indent = ''): |
|---|
| | 131 | """ Wrap multi-line text to width (defaults to termwidth()) """ |
|---|
| | 132 | out = [] |
|---|
| | 133 | tokens = [t.group(0) for t in __cwrap_re.finditer(text)] + [' ' * width] |
|---|
| | 134 | line = tokens.pop(0) |
|---|
| | 135 | first_line = 1 |
|---|
| | 136 | |
|---|
| | 137 | |
|---|
| | 138 | def add_line(line, first_line): |
|---|
| | 139 | if clen(line.rstrip()) > width: |
|---|
| | 140 | tokens.insert(0, csplice(line, width)) |
|---|
| | 141 | line = csplice(line, 0, width) |
|---|
| | 142 | out.append((not first_line and subsequent_indent or '') + line.rstrip()) |
|---|
| | 143 | first_line = 0 |
|---|
| | 144 | if not out[-1]: |
|---|
| | 145 | out.pop() |
|---|
| | 146 | return first_line |
|---|
| | 147 | |
|---|
| | 148 | while tokens: |
|---|
| | 149 | if clen(line) + clen(tokens[0].rstrip()) > width: |
|---|
| | 150 | first_line = add_line(line, first_line) |
|---|
| | 151 | line = tokens.pop(0) |
|---|
| | 152 | else: |
|---|
| | 153 | line += tokens.pop(0) |
|---|
| | 154 | if line: |
|---|
| | 155 | add_line(line, first_line) |
|---|
| | 156 | return out |
|---|
| | 157 | |
|---|
| | 158 | def wraptoterm(text, **kwargs): |
|---|
| 87 | | return '\n'.join(textwrap.wrap(text, termwidth(), **argd)) |
|---|
| 88 | | |
|---|
| 89 | | def print_table(table, header=None, sep=' ', numfmt='%g', auto_format = True): |
|---|
| | 160 | return '\n'.join(cwraptext(text, **kwargs)) |
|---|
| | 161 | |
|---|
| | 162 | def rjustify(text, width = termwidth()): |
|---|
| | 163 | """ Right justify the given text. """ |
|---|
| | 164 | text = cwraptext(text, width) |
|---|
| | 165 | out = '' |
|---|
| | 166 | for line in text: |
|---|
| | 167 | out += (' ' * (width - clen(line))) + line + '\n' |
|---|
| | 168 | return out.rstrip() |
|---|
| | 169 | |
|---|
| | 170 | def cjustify(text, width = termwidth()): |
|---|
| | 171 | """ Centre the given text. """ |
|---|
| | 172 | text = cwraptext(text, width) |
|---|
| | 173 | out = '' |
|---|
| | 174 | for line in text: |
|---|
| | 175 | out += (' ' * ((width - clen(line)) / 2)) + line + '\n' |
|---|
| | 176 | return out.rstrip() |
|---|
| | 177 | |
|---|
| | 178 | def print_table(table, header = None, sep = ' ', auto_format = ['^B^U', '^6', '^B^6']): |
|---|
| 91 | | header, if specified, will be printed as the first row. |
|---|
| 92 | | numfmt is the format for all numbers; you might want e.g. '%6.2f'. |
|---|
| 93 | | (If you want different formats in different columns, don't use |
|---|
| 94 | | print_table.) sep is the separator between columns. |
|---|
| | 180 | header, if specified, will be printed as the first row. sep is the |
|---|
| | 181 | separator between columns. |
|---|
| 98 | | for alternating rows. eg. [ '^B', '^1', '^2' ] """ |
|---|
| 99 | | if not table and not header: |
|---|
| 100 | | return |
|---|
| 101 | | def ljust(s, size): |
|---|
| 102 | | return s + ' ' * (size - clen(s)) |
|---|
| 103 | | def rjust(s, size): |
|---|
| 104 | | return ' ' * (size - clen(s)) + s |
|---|
| 105 | | if auto_format and type(auto_format) is not list: |
|---|
| 106 | | auto_format = ['^B^U', '^6', '^B^6'] |
|---|
| | 185 | for alternating rows. eg. [ '^B', '^1', '^2' ] |
|---|
| | 186 | |
|---|
| | 187 | Note: print_table supports an additional formatting code, ^R, which |
|---|
| | 188 | corresponds to the colour formatting of the current table row. """ |
|---|
| | 189 | def ctlen(s): |
|---|
| | 190 | return clen(s.replace('^R', '')) |
|---|
| | 191 | |
|---|
| | 192 | # Find column scale factor |
|---|
| 108 | | table = [header] + table |
|---|
| 109 | | justs = [isnumber(x) and rjust or ljust for x in table[0]] |
|---|
| 110 | | table = [[if_(isnumber(x), lambda: numfmt % x, x) for x in row] |
|---|
| 111 | | for row in table] |
|---|
| 112 | | maxlen = lambda seq: max(map(clen, seq)) |
|---|
| 113 | | sizes = map(maxlen, zip(*[map(str, row) for row in table])) |
|---|
| | 194 | table.insert(0, header) |
|---|
| | 195 | rows, cols = len(table), len(table[0]) |
|---|
| | 196 | colwidths = [0] * cols |
|---|
| | 197 | #minwidth = termwidth() / cols |
|---|
| | 198 | for i in range(0, cols): |
|---|
| | 199 | colwidths[i] = max(map(lambda c: max(map(ctlen, c[i].splitlines())), table)) |
|---|
| | 200 | if i < cols - 1: |
|---|
| | 201 | colwidths[i] += len(sep) |
|---|
| | 202 | twidth = sum(colwidths) |
|---|
| | 203 | scale = float(termwidth() - 1) / float(twidth) |
|---|
| | 204 | colwidths = [int(float(x) * scale) for x in colwidths] |
|---|
| | 205 | auto_format = auto_format[:] |
|---|
| | 206 | |
|---|
| 117 | | if auto_format: |
|---|
| 118 | | if rowalt == -1: |
|---|
| 119 | | fmt = auto_format[0] |
|---|
| 120 | | auto_format.pop(0) |
|---|
| 121 | | else: |
|---|
| 122 | | fmt = auto_format[rowalt % len(auto_format)] |
|---|
| 123 | | cwrite(sys.stdout, fmt) |
|---|
| 124 | | for (j, size, x) in zip(justs, sizes, row): |
|---|
| 125 | | cwrite(sys.stdout, j(x, size), sep) |
|---|
| 126 | | cprint('^N') |
|---|
| | 215 | if rowalt == -1: |
|---|
| | 216 | fmt = auto_format[0] |
|---|
| | 217 | auto_format.pop(0) |
|---|
| | 218 | else: |
|---|
| | 219 | fmt = auto_format[rowalt % len(auto_format)] |
|---|
| | 220 | xrow = [cwraptext(col.replace('^R', fmt), colwidths[i]) for i, col in enumerate(row)] |
|---|
| | 221 | realrows = max(map(len, xrow)) |
|---|
| | 222 | xrow = [x + [''] * (realrows - len(x)) for x in xrow] |
|---|
| | 223 | for i in range(0, realrows): |
|---|
| | 224 | cwrite(sys.stdout, fmt) |
|---|
| | 225 | for j, col in enumerate(xrow): |
|---|
| | 226 | cwrite(sys.stdout, col[i].replace('^R', fmt) + sep * (colwidths[j] - ctlen(col[i]))) |
|---|
| | 227 | if j < cols - 1: |
|---|
| | 228 | cwrite(sys.stdout, sep) |
|---|
| | 229 | cwrite(sys.stdout, '^N\n') |
|---|