Source code for opennode.oms.endpoint.ssh.colored_columnize

# -*- coding: utf-8 -*-
"""Returns a compact set of columns as a string with newlines for an
array of strings.

Adapted from the routine of the same name inside cmd.py

mmikulicic: taken from http://pypi.python.org/pypi/columnize and
adapted for strings containing ANSI escapes (should work mostly for
colors).

"""
import re


CLEAN_COLOR_RE = re.compile('\x1b[^;]*;?..?m')


[docs]def bw(text): """Plain black and white text.""" return CLEAN_COLOR_RE.sub('', text)
[docs]def color_ljust(text, size): return text.ljust(size + len(text) - len(bw(text)))
[docs]def color_rjust(text, size): return text.rjust(size + len(text) - len(bw(text)))
[docs]def columnize(array, displaywidth=80, colsep=' ', arrange_vertical=True, ljust=True, lineprefix=''): """Return a list of strings as a compact set of columns arranged horizontally or vertically. For example, for a line width of 4 characters (arranged vertically): ['1', '2,', '3', '4'] => '1 3\n2 4\n' or arranged horizontally: ['1', '2,', '3', '4'] => '1 2\n3 4\n' Each column is only as wide as necessary. By default, columns are separated by two spaces - one was not legible enough. Set "colsep" to adjust the string separate columns. Set `displaywidth' to set the line width. Normally, consecutive items go down from the top to bottom from the left-most column to the right-most. If "arrange_vertical" is set false, consecutive items will go across, left to right, top to bottom.""" if not isinstance(array, list) and not isinstance(array, tuple): raise TypeError( 'array needs to be an instance of a list or a tuple') array = [str(i) for i in array] # Some degenerate cases size = len(array) if 0 == size: return "<empty>\n" elif size == 1: return '%s\n' % str(array[0]) displaywidth = max(4, displaywidth - len(lineprefix)) if arrange_vertical: array_index = lambda nrows, row, col: nrows * col + row # Try every row count from 1 upwards for nrows in range(1, size): ncols = (size + nrows - 1) // nrows colwidths = [] totwidth = -len(colsep) for col in range(ncols): # get max column width for this column colwidth = 0 for row in range(nrows): i = array_index(nrows, row, col) if i >= size: break x = array[i] colwidth = max(colwidth, len(bw(x))) pass colwidths.append(colwidth) totwidth += colwidth + len(colsep) if totwidth > displaywidth: break pass if totwidth <= displaywidth: break pass # The smallest number of rows computed and the # max widths for each column has been obtained. # Now we just have to format each of the # rows. s = '' for row in range(nrows): texts = [] for col in range(ncols): i = row + nrows * col if i >= size: x = "" else: x = array[i] texts.append(x) while texts and not texts[-1]: del texts[-1] for col in range(len(texts)): if ljust: texts[col] = color_ljust(texts[col], colwidths[col]) else: texts[col] = color_rjust(texts[col], colwidths[col]) pass pass s += "%s%s\n" % (lineprefix, str(colsep.join(texts))) pass return s else: array_index = lambda nrows, row, col: ncols * (row - 1) + col # Try every column count from size downwards colwidths = [] for ncols in range(size, 0, -1): # Try every row count from 1 upwards min_rows = (size + ncols - 1) // ncols for nrows in range(min_rows, size): rounded_size = nrows * ncols colwidths = [] totwidth = -len(colsep) for col in range(ncols): # get max column width for this column colwidth = 0 for row in range(1, nrows + 1): i = array_index(nrows, row, col) if i >= rounded_size: break elif i < size: x = array[i] colwidth = max(colwidth, len(bw(x))) pass pass colwidths.append(colwidth) totwidth += colwidth + len(colsep) if totwidth >= displaywidth: break pass if totwidth <= displaywidth and i >= rounded_size - 1: # Found the right nrows and ncols nrows = row break elif totwidth >= displaywidth: # Need to reduce ncols break pass if totwidth <= displaywidth and i >= rounded_size - 1: break pass # The smallest number of rows computed and the # max widths for each column has been obtained. # Now we just have to format each of the # rows. s = '' for row in range(1, nrows + 1): texts = [] for col in range(ncols): i = array_index(nrows, row, col) if i >= size: break else: x = array[i] texts.append(x) pass for col in range(len(texts)): if ljust: texts[col] = color_ljust(texts[col], colwidths[col]) else: texts[col] = color_rjust(texts[col], colwidths[col]) pass pass s += "%s%s\n" % (lineprefix, str(colsep.join(texts))) pass return s pass

This Page