colify handles ansi color input directly; no more decorator.
This commit is contained in:
parent
40b4fa5443
commit
11cffff943
5 changed files with 55 additions and 47 deletions
|
@ -145,18 +145,16 @@ def get_yes_or_no(prompt, **kwargs):
|
||||||
|
|
||||||
|
|
||||||
def hline(label=None, **kwargs):
|
def hline(label=None, **kwargs):
|
||||||
"""Draw an optionally colored or labeled horizontal line.
|
"""Draw a labeled horizontal line.
|
||||||
Options:
|
Options:
|
||||||
|
|
||||||
char Char to draw the line with. Default '-'
|
char Char to draw the line with. Default '-'
|
||||||
color Color of the label. Default is no color.
|
|
||||||
max_width Maximum width of the line. Default is 64 chars.
|
max_width Maximum width of the line. Default is 64 chars.
|
||||||
|
|
||||||
See tty.color for possible color formats.
|
|
||||||
"""
|
"""
|
||||||
char = kwargs.get('char', '-')
|
char = kwargs.pop('char', '-')
|
||||||
color = kwargs.get('color', '')
|
max_width = kwargs.pop('max_width', 64)
|
||||||
max_width = kwargs.get('max_width', 64)
|
if kwargs:
|
||||||
|
raise TypeError("'%s' is an invalid keyword argument for this function."
|
||||||
|
% next(kwargs.iterkeys()))
|
||||||
|
|
||||||
rows, cols = terminal_size()
|
rows, cols = terminal_size()
|
||||||
if not cols:
|
if not cols:
|
||||||
|
@ -166,15 +164,12 @@ def hline(label=None, **kwargs):
|
||||||
cols = min(max_width, cols)
|
cols = min(max_width, cols)
|
||||||
|
|
||||||
label = str(label)
|
label = str(label)
|
||||||
prefix = char * 2 + " " + label + " "
|
prefix = char * 2 + " "
|
||||||
suffix = (cols - len(prefix)) * char
|
suffix = " " + (cols - len(prefix) - clen(label)) * char
|
||||||
|
|
||||||
out = StringIO()
|
out = StringIO()
|
||||||
if color:
|
out.write(prefix)
|
||||||
prefix = char * 2 + " " + color + cescape(label) + "@. "
|
out.write(label)
|
||||||
cwrite(prefix, stream=out, color=True)
|
|
||||||
else:
|
|
||||||
out.write(prefix)
|
|
||||||
out.write(suffix)
|
out.write(suffix)
|
||||||
|
|
||||||
print out.getvalue()
|
print out.getvalue()
|
||||||
|
|
|
@ -33,6 +33,7 @@
|
||||||
from StringIO import StringIO
|
from StringIO import StringIO
|
||||||
|
|
||||||
from llnl.util.tty import terminal_size
|
from llnl.util.tty import terminal_size
|
||||||
|
from llnl.util.tty.color import clen
|
||||||
|
|
||||||
|
|
||||||
class ColumnConfig:
|
class ColumnConfig:
|
||||||
|
@ -40,7 +41,8 @@ def __init__(self, cols):
|
||||||
self.cols = cols
|
self.cols = cols
|
||||||
self.line_length = 0
|
self.line_length = 0
|
||||||
self.valid = True
|
self.valid = True
|
||||||
self.widths = [0] * cols
|
self.widths = [0] * cols # does not include ansi colors
|
||||||
|
self.cwidths = [0] * cols # includes ansi colors
|
||||||
|
|
||||||
def __repr__(self):
|
def __repr__(self):
|
||||||
attrs = [(a,getattr(self, a)) for a in dir(self) if not a.startswith("__")]
|
attrs = [(a,getattr(self, a)) for a in dir(self) if not a.startswith("__")]
|
||||||
|
@ -62,7 +64,10 @@ def config_variable_cols(elts, console_width, padding, cols=0):
|
||||||
raise ValueError("cols must be non-negative.")
|
raise ValueError("cols must be non-negative.")
|
||||||
|
|
||||||
# Get a bound on the most columns we could possibly have.
|
# Get a bound on the most columns we could possibly have.
|
||||||
lengths = [len(elt) for elt in elts]
|
# 'clen' ignores length of ansi color sequences.
|
||||||
|
lengths = [clen(e) for e in elts]
|
||||||
|
clengths = [len(e) for e in elts]
|
||||||
|
|
||||||
max_cols = max(1, console_width / (min(lengths) + padding))
|
max_cols = max(1, console_width / (min(lengths) + padding))
|
||||||
max_cols = min(len(elts), max_cols)
|
max_cols = min(len(elts), max_cols)
|
||||||
|
|
||||||
|
@ -71,17 +76,16 @@ def config_variable_cols(elts, console_width, padding, cols=0):
|
||||||
|
|
||||||
# Determine the most columns possible for the console width.
|
# Determine the most columns possible for the console width.
|
||||||
configs = [ColumnConfig(c) for c in col_range]
|
configs = [ColumnConfig(c) for c in col_range]
|
||||||
for elt, length in enumerate(lengths):
|
for i, length in enumerate(lengths):
|
||||||
for conf in configs:
|
for conf in configs:
|
||||||
if conf.valid:
|
if conf.valid:
|
||||||
col = elt / ((len(elts) + conf.cols - 1) / conf.cols)
|
col = i / ((len(elts) + conf.cols - 1) / conf.cols)
|
||||||
padded = length
|
p = padding if col < (conf.cols - 1) else 0
|
||||||
if col < (conf.cols - 1):
|
|
||||||
padded += padding
|
|
||||||
|
|
||||||
if conf.widths[col] < padded:
|
if conf.widths[col] < (length + p):
|
||||||
conf.line_length += padded - conf.widths[col]
|
conf.line_length += length + p - conf.widths[col]
|
||||||
conf.widths[col] = padded
|
conf.widths[col] = length + p
|
||||||
|
conf.cwidths[col] = clengths[i] + p
|
||||||
conf.valid = (conf.line_length < console_width)
|
conf.valid = (conf.line_length < console_width)
|
||||||
|
|
||||||
try:
|
try:
|
||||||
|
@ -105,12 +109,17 @@ def config_uniform_cols(elts, console_width, padding, cols=0):
|
||||||
if cols < 0:
|
if cols < 0:
|
||||||
raise ValueError("cols must be non-negative.")
|
raise ValueError("cols must be non-negative.")
|
||||||
|
|
||||||
max_len = max(len(elt) for elt in elts) + padding
|
# 'clen' ignores length of ansi color sequences.
|
||||||
|
max_len = max(clen(e) for e in elts) + padding
|
||||||
|
max_clen = max(len(e) for e in elts) + padding
|
||||||
if cols == 0:
|
if cols == 0:
|
||||||
cols = max(1, console_width / max_len)
|
cols = max(1, console_width / max_len)
|
||||||
cols = min(len(elts), cols)
|
cols = min(len(elts), cols)
|
||||||
|
|
||||||
config = ColumnConfig(cols)
|
config = ColumnConfig(cols)
|
||||||
config.widths = [max_len] * cols
|
config.widths = [max_len] * cols
|
||||||
|
config.cwidths = [max_clen] * cols
|
||||||
|
|
||||||
return config
|
return config
|
||||||
|
|
||||||
|
|
||||||
|
@ -139,9 +148,8 @@ def colify(elts, **options):
|
||||||
Variable-width columns are tighter, uniform columns are all the
|
Variable-width columns are tighter, uniform columns are all the
|
||||||
same width and fit less data on the screen.
|
same width and fit less data on the screen.
|
||||||
|
|
||||||
decorator=<func> Function to add decoration (such as color) after columns have
|
len=<func> Function to use for calculating string length.
|
||||||
already been fitted. Useful for fitting based only on
|
Useful for ignoring ansi color. Default is 'len'.
|
||||||
positive-width characters.
|
|
||||||
"""
|
"""
|
||||||
# Get keyword arguments or set defaults
|
# Get keyword arguments or set defaults
|
||||||
cols = options.pop("cols", 0)
|
cols = options.pop("cols", 0)
|
||||||
|
@ -151,7 +159,6 @@ def colify(elts, **options):
|
||||||
tty = options.pop('tty', None)
|
tty = options.pop('tty', None)
|
||||||
method = options.pop("method", "variable")
|
method = options.pop("method", "variable")
|
||||||
console_cols = options.pop("width", None)
|
console_cols = options.pop("width", None)
|
||||||
decorator = options.pop("decorator", lambda x:x)
|
|
||||||
|
|
||||||
if options:
|
if options:
|
||||||
raise TypeError("'%s' is an invalid keyword argument for this function."
|
raise TypeError("'%s' is an invalid keyword argument for this function."
|
||||||
|
@ -162,13 +169,10 @@ def colify(elts, **options):
|
||||||
if not elts:
|
if not elts:
|
||||||
return (0, ())
|
return (0, ())
|
||||||
|
|
||||||
|
# Use only one column if not a tty.
|
||||||
if not tty:
|
if not tty:
|
||||||
if tty is False or not output.isatty():
|
if tty is False or not output.isatty():
|
||||||
for elt in elts:
|
cols = 1
|
||||||
output.write("%s\n" % elt)
|
|
||||||
|
|
||||||
maxlen = max(len(str(s)) for s in elts)
|
|
||||||
return (1, (maxlen,))
|
|
||||||
|
|
||||||
# Specify the number of character columns to use.
|
# Specify the number of character columns to use.
|
||||||
if not console_cols:
|
if not console_cols:
|
||||||
|
@ -186,7 +190,7 @@ def colify(elts, **options):
|
||||||
raise ValueError("method must be one of: " + allowed_methods)
|
raise ValueError("method must be one of: " + allowed_methods)
|
||||||
|
|
||||||
cols = config.cols
|
cols = config.cols
|
||||||
formats = ["%%-%ds" % width for width in config.widths[:-1]]
|
formats = ["%%-%ds" % width for width in config.cwidths[:-1]]
|
||||||
formats.append("%s") # last column has no trailing space
|
formats.append("%s") # last column has no trailing space
|
||||||
|
|
||||||
rows = (len(elts) + cols - 1) / cols
|
rows = (len(elts) + cols - 1) / cols
|
||||||
|
@ -196,7 +200,7 @@ def colify(elts, **options):
|
||||||
output.write(" " * indent)
|
output.write(" " * indent)
|
||||||
for col in xrange(cols):
|
for col in xrange(cols):
|
||||||
elt = col * rows + row
|
elt = col * rows + row
|
||||||
output.write(decorator(formats[col] % elts[elt]))
|
output.write(formats[col] % elts[elt])
|
||||||
|
|
||||||
output.write("\n")
|
output.write("\n")
|
||||||
row += 1
|
row += 1
|
||||||
|
|
|
@ -149,6 +149,11 @@ def colorize(string, **kwargs):
|
||||||
return re.sub(color_re, match_to_ansi(color), string)
|
return re.sub(color_re, match_to_ansi(color), string)
|
||||||
|
|
||||||
|
|
||||||
|
def clen(string):
|
||||||
|
"""Return the length of a string, excluding ansi color sequences."""
|
||||||
|
return len(re.sub(r'\033[^m]*m', '', string))
|
||||||
|
|
||||||
|
|
||||||
def cwrite(string, stream=sys.stdout, color=None):
|
def cwrite(string, stream=sys.stdout, color=None):
|
||||||
"""Replace all color expressions in string with ANSI control
|
"""Replace all color expressions in string with ANSI control
|
||||||
codes and write the result to the stream. If color is
|
codes and write the result to the stream. If color is
|
||||||
|
|
|
@ -25,6 +25,7 @@
|
||||||
from external import argparse
|
from external import argparse
|
||||||
|
|
||||||
import llnl.util.tty as tty
|
import llnl.util.tty as tty
|
||||||
|
from llnl.util.tty.color import colorize
|
||||||
from llnl.util.tty.colify import colify
|
from llnl.util.tty.colify import colify
|
||||||
from llnl.util.lang import index_by
|
from llnl.util.lang import index_by
|
||||||
|
|
||||||
|
@ -96,9 +97,12 @@ def compiler_info(args):
|
||||||
def compiler_list(args):
|
def compiler_list(args):
|
||||||
tty.msg("Available compilers")
|
tty.msg("Available compilers")
|
||||||
index = index_by(spack.compilers.all_compilers(), 'name')
|
index = index_by(spack.compilers.all_compilers(), 'name')
|
||||||
for name, compilers in index.items():
|
for i, (name, compilers) in enumerate(index.items()):
|
||||||
tty.hline(name, char='-', color=spack.spec.compiler_color)
|
if i >= 1: print
|
||||||
colify(reversed(sorted(compilers)), indent=4)
|
|
||||||
|
cname = "%s{%s}" % (spack.spec.compiler_color, name)
|
||||||
|
tty.hline(colorize(cname), char='-')
|
||||||
|
colify(reversed(sorted(compilers)))
|
||||||
|
|
||||||
|
|
||||||
def compiler(parser, args):
|
def compiler(parser, args):
|
||||||
|
|
|
@ -79,13 +79,16 @@ def find(parser, args):
|
||||||
# Traverse the index and print out each package
|
# Traverse the index and print out each package
|
||||||
for i, (architecture, compiler) in enumerate(sorted(index)):
|
for i, (architecture, compiler) in enumerate(sorted(index)):
|
||||||
if i > 0: print
|
if i > 0: print
|
||||||
tty.hline("%s / %s" % (compiler, architecture), char='-')
|
|
||||||
|
|
||||||
specs = index[(architecture, compiler)]
|
header = "%s{%s} / %s{%s}" % (
|
||||||
|
spack.spec.architecture_color, architecture,
|
||||||
|
spack.spec.compiler_color, compiler)
|
||||||
|
tty.hline(colorize(header), char='-')
|
||||||
|
|
||||||
|
specs = index[(architecture,compiler)]
|
||||||
specs.sort()
|
specs.sort()
|
||||||
|
|
||||||
abbreviated = [s.format('$_$@$+$#', color=True) for s in specs]
|
abbreviated = [s.format('$_$@$+$#', color=True) for s in specs]
|
||||||
|
|
||||||
if args.paths:
|
if args.paths:
|
||||||
# Print one spec per line along with prefix path
|
# Print one spec per line along with prefix path
|
||||||
width = max(len(s) for s in abbreviated)
|
width = max(len(s) for s in abbreviated)
|
||||||
|
@ -99,7 +102,4 @@ def find(parser, args):
|
||||||
for spec in specs:
|
for spec in specs:
|
||||||
print spec.tree(indent=4, format='$_$@$+', color=True),
|
print spec.tree(indent=4, format='$_$@$+', color=True),
|
||||||
else:
|
else:
|
||||||
max_len = max([len(s.name) for s in specs])
|
colify(s.format('$-_$@$+$#', color=True) for s in specs)
|
||||||
max_len += 4
|
|
||||||
|
|
||||||
colify((s.format('$-_$@$+$#') for s in specs), decorator=spack.spec.colorize_spec)
|
|
||||||
|
|
Loading…
Reference in a new issue