Fix bugs in format_grid, include verbatim elements

This commit is contained in:
Griatch 2020-04-11 13:28:24 +02:00
parent a863ff77db
commit 458df00272
4 changed files with 67 additions and 61 deletions

View file

@ -14,6 +14,7 @@ from evennia.utils.utils import fill, dedent
from evennia.commands.command import Command
from evennia.help.models import HelpEntry
from evennia.utils import create, evmore
from evennia.utils.ansi import ANSIString
from evennia.utils.eveditor import EvEditor
from evennia.utils.utils import string_suggestions, class_from_module, inherits_from, format_grid
@ -40,6 +41,7 @@ class HelpCategory:
"tags": "",
"text": ""
}
def __str__(self):
return f"Category: {self.key}"
@ -178,39 +180,27 @@ class CmdHelp(Command):
string += "\n" + _SEP
return string
@staticmethod
def format_help_list(hdict_cmds, hdict_db):
def format_help_list(self, hdict_cmds, hdict_db):
"""
Output a category-ordered list. The input are the
pre-loaded help files for commands and database-helpfiles
respectively. You can override this method to return a
custom display of the list of commands and topics.
"""
output = []
width = self.client_width()
grid = []
verbatim_elements = []
for category in sorted(set(list(hdict_cmds.keys()) + list(hdict_db.keys()))):
output.append(f"|w{category.title()}|G")
category_str = f"-- {category.title()} "
grid.append(ANSIString("|w" + category_str + "-" * (width - len(category_str)) + "|G"))
verbatim_elements.append(len(grid) - 1)
entries = sorted(set(hdict_cmds.get(category, []) + hdict_db.get(category, [])))
output.append(format_grid(entries, width=78)) # self.client_width()))
return "\n".join(output)
grid.extend(entries)
string = ""
if hdict_cmds and any(hdict_cmds.values()):
string += "\n" + _SEP + "\n |CCommand help entries|n\n" + _SEP
for category in sorted(hdict_cmds.keys()):
string += "\n |w%s|n:\n" % (str(category).title())
string += "|G" + fill("|C, |G".join(sorted(hdict_cmds[category]))) + "|n"
if hdict_db and any(hdict_db.values()):
string += "\n\n" + _SEP + "\n\r |COther help entries|n\n" + _SEP
for category in sorted(hdict_db.keys()):
string += "\n\r |w%s|n:\n" % (str(category).title())
string += (
"|G"
+ fill(", ".join(sorted([str(topic) for topic in hdict_db[category]])))
+ "|n"
)
return string
gridrows = format_grid(grid, width, sep=" ", verbatim_elements=verbatim_elements)
return "\n".join(gridrows)
def check_show_help(self, cmd, caller):
"""
@ -320,9 +310,9 @@ class CmdHelp(Command):
if isinstance(match, HelpCategory):
formatted = self.format_help_list(
{match.key: [cmd.key for cmd in all_cmds
if match.key.lower() == cmd.help_category]},
if match.key.lower() == cmd.help_category]},
{match.key: [topic.key for topic in all_topics
if match.key.lower() == topic.help_category]}
if match.key.lower() == topic.help_category]}
)
elif inherits_from(match, "evennia.commands.command.Command"):
formatted = self.format_help_entry(

View file

@ -298,7 +298,7 @@ class EvMore(object):
nsize = len(inp)
self._npages = nsize // self.height + (0 if nsize % self.height == 0 else 1)
self._data = inp
self._paginator_slice
self._paginator = self.paginator_slice
def init_f_str(self, text):
"""

View file

@ -289,8 +289,6 @@ class TestFormatGrid(TestCase):
elements = self._generate_elements(3, 1, 30)
result = utils.format_grid(elements, width=78)
rows = result.split("\n")
for row in rows:
print(f"'{row}'")
self.assertEqual(len(rows), 3)
self.assertTrue(all(len(row) == 78 for row in rows))
@ -299,20 +297,14 @@ class TestFormatGrid(TestCase):
elements = self._generate_elements(3, 15, 30)
result = utils.format_grid(elements, width=82, sep=" ")
rows = result.split("\n")
for row in rows:
print(f"'{row}'")
self.assertEqual(len(rows), 8)
self.assertTrue(all(len(row) == 82 for row in rows))
def test_huge_grid(self):
"""Grid with very long strings"""
# from pudb import debugger
# debugger.Debugger().set_trace()
elements = self._generate_elements(70, 20, 30)
result = utils.format_grid(elements, width=78)
rows = result.split("\n")
for row in rows:
print(f"'{row}'")
self.assertEqual(len(rows), 30)
self.assertTrue(all(len(row) == 78 for row in rows))
@ -324,7 +316,18 @@ class TestFormatGrid(TestCase):
result = utils.format_grid(elements, width=78)
rows = result.split("\n")
self.assertEqual(len(rows), 2)
for row in rows:
print(f"'{row}'")
for element in elements:
self.assertTrue(element in result, f"element {element} is missing.")
def test_breakline(self):
"""Grid with line-long elements in middle"""
elements = self._generate_elements(6, 4, 30)
elements[10] = elements[20] = "-" * 78
# from pudb import debugger
# debugger.Debugger().set_trace()
result = utils.format_grid(elements, width=78)
rows = result.split("\n")
self.assertEqual(len(rows), 8)
for element in elements:
self.assertTrue(element in result, f"element {element} is missing.")

View file

@ -153,6 +153,7 @@ def crop(text, width=None, suffix="[...]"):
if ltext <= width:
return text
else:
from evennia import set_trace;set_trace()
lsuffix = len(suffix)
text = text[:width] if lsuffix >= width else "%s%s" % (text[: width - lsuffix], suffix)
return to_str(text)
@ -1713,7 +1714,7 @@ def percentile(iterable, percent, key=lambda x: x):
return d0 + d1
def format_grid(elements, width=78, sep=" "):
def format_grid(elements, width=78, sep=" ", verbatim_elements=None):
"""
This helper function makes a 'grid' output, where it distributes the given
string-elements as evenly as possible to fill out the given width.
@ -1723,52 +1724,63 @@ def format_grid(elements, width=78, sep=" "):
elements (iterable): A 1D list of string elements to put in the grid.
width (int, optional): The width of the grid area to fill.
sep (str, optional): The extra separator to put between words. If
set to the empty string, words may run into each other
set to the empty string, words may run into each other.
verbatim_elements (list, optional): This is a list of indices pointing to
specific items in the `elements` list. An element at this index will
not be included in the calculation of the slot sizes. It will still
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.
Returns:
gridstr (str): The grid as a finished renderede multi-line string.
gridstr (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.
"""
nelements = len(elements)
elements = [elements[ie] + sep for ie in range(nelements - 1)] + [elements[-1]]
if not verbatim_elements:
verbatim_elements = []
nelements = len(elements)
# add sep to all but the very last element
elements = [elements[ie] + sep for ie in range(nelements - 1)] + [elements[-1]]
wls = [len(elem) for elem in elements]
wls_percentile = [wl for iw, wl in enumerate(wls) if iw not in verbatim_elements]
# get the nth percentile as a good representation of average width
averlen = int(percentile(sorted(wls), 0.9)) + 2 # include extra space
averlen = int(percentile(sorted(wls_percentile), 0.9)) + 2 # include extra space
aver_per_row = width // averlen + 1
if aver_per_row == 1:
# one line per row, output directly since this is trivial
# we use rstrip here to remove extra spaces added by sep
return "\n".join(
crop(element.rstrip(), width) + " " * max(0, width - len(element.rstrip()))
for iel, element in enumerate(elements)
)
indices = [averlen * ind for ind in range(aver_per_row - 1)]
rows = []
ic = 0
row = ""
for ie, element in enumerate(elements):
wl = wls[ie]
lrow = len(row)
debug = row.replace(" ", ".")
if lrow + wl > width:
# last slot extends outside grid, move to next line
# this slot extends outside grid, move to next line
row += " " * (width - lrow)
rows.append(row)
if wl >= width:
# remove sep if this fills the entire line
element = element.rstrip()
row = crop(element, width)
ic = 0
elif ic >= aver_per_row - 1:
# last slot on the line
if ic == 0:
# one slot per line
row = crop(element, width)
row += " " * max(0, (width - len(row)))
rows.append(row)
else:
# finish line, put slot on next line
row += " " * max(0, (width - lrow))
rows.append(row)
row = crop(element, width)
ic = 0
elif lrow + wl > width:
# last slot extends outside grid, move to next line
row += " " * (width - lrow)
# no more slots available on this line
row += " " * max(0, (width - lrow))
rows.append(row)
row = crop(element, width)
ic = 0
@ -1793,9 +1805,10 @@ def format_grid(elements, width=78, sep=" "):
if ie >= nelements - 1:
# last element, make sure to store
row += " " * max(0, width - len(row))
rows.append(row)
return "\n".join(rows)
return rows
def get_evennia_pids():