utils.format_grid strip ansi support

adds option to ignore ansi markups when calculating grid lengths.

evennia.utils.tests.test_utils.TestFormatgrid passes
This commit is contained in:
davewiththenicehat 2021-06-12 12:32:20 -04:00
parent e6fef4fb69
commit a85f8995b3

View file

@ -1837,7 +1837,10 @@ def percentile(iterable, percent, key=lambda x: x):
return d0 + d1
def format_grid(elements, width=78, sep=" ", verbatim_elements=None):
from evennia.utils.ansi import strip_ansi
def format_grid(elements, width=78, sep=" ", verbatim_elements=None, ignore_ansi=True):
"""
This helper function makes a 'grid' output, where it distributes the given
string-elements as evenly as possible to fill out the given width.
@ -1854,12 +1857,17 @@ def format_grid(elements, width=78, sep=" ", verbatim_elements=None):
be inserted into the grid at the correct position and may be surrounded
by padding unless filling the entire line. This is useful for embedding
decorations in the grid, such as horizontal bars.
ignore_ansi (bool, optional): Ignore ansi markups when calculating white spacing.
Returns:
list: The grid as a list of ready-formatted rows. We return it
like this to make it easier to insert decorations between rows, such
as horizontal bars.
"""
def ansi_len(text):
"""Use arg ignore_ansi to calculate length of text in element."""
return len(strip_ansi(text)) if ignore_ansi else len(text)
def _minimal_rows(elements):
"""
Minimalistic distribution with minimal spacing, good for single-line
@ -1867,8 +1875,8 @@ def format_grid(elements, width=78, sep=" ", verbatim_elements=None):
"""
rows = [""]
for element in elements:
rowlen = len(rows[-1])
elen = len(element)
rowlen = ansi_len((rows[-1]))
elen = ansi_len((element))
if rowlen + elen <= width:
rows[-1] += element
else:
@ -1880,8 +1888,7 @@ def format_grid(elements, width=78, sep=" ", verbatim_elements=None):
Dynamic-space, good for making even columns in a multi-line grid but
will look strange for a single line.
"""
wls = [len(elem) for elem in elements]
wls = [ansi_len((elem)) for elem in elements]
wls_percentile = [wl for iw, wl in enumerate(wls) if iw not in verbatim_elements]
if wls_percentile:
@ -1896,7 +1903,8 @@ def format_grid(elements, width=78, sep=" ", verbatim_elements=None):
# one line per row, output directly since this is trivial
# we use rstrip here to remove extra spaces added by sep
return [
crop(element.rstrip(), width) + " " * max(0, width - len(element.rstrip()))
crop(element.rstrip(), width) + " " \
* max(0, width - ansi_len((element.rstrip())))
for iel, element in enumerate(elements)
]
@ -1908,7 +1916,7 @@ def format_grid(elements, width=78, sep=" ", verbatim_elements=None):
for ie, element in enumerate(elements):
wl = wls[ie]
lrow = len(row)
lrow = ansi_len((row))
# debug = row.replace(" ", ".")
if lrow + wl > width:
@ -1947,7 +1955,7 @@ def format_grid(elements, width=78, sep=" ", verbatim_elements=None):
if ie >= nelements - 1:
# last element, make sure to store
row += " " * max(0, width - len(row))
row += " " * max(0, width - ansi_len((row)))
rows.append(row)
return rows
@ -1960,7 +1968,7 @@ def format_grid(elements, width=78, sep=" ", verbatim_elements=None):
# add sep to all but the very last element
elements = [elements[ie] + sep for ie in range(nelements - 1)] + [elements[-1]]
if sum(len(element) for element in elements) <= width:
if sum(ansi_len((element)) for element in elements) <= width:
# grid fits in one line
return _minimal_rows(elements)
else: