Support direct EvColumn adds to EvTable. Resolves #2762
This commit is contained in:
parent
7d8c6f2a26
commit
9438e5856a
4 changed files with 102 additions and 20 deletions
|
|
@ -217,6 +217,7 @@ Up requirements to Django 4.0+, Twisted 22+, Python 3.9 or 3.10
|
||||||
(mainly for custom align/valign). `EvCells` now makes use of `utils.justify`.
|
(mainly for custom align/valign). `EvCells` now makes use of `utils.justify`.
|
||||||
- `utils.justify` now supports `align="a"` (absolute alignments. This keeps
|
- `utils.justify` now supports `align="a"` (absolute alignments. This keeps
|
||||||
the given left indent but crops/fills to the width. Used in EvCells.
|
the given left indent but crops/fills to the width. Used in EvCells.
|
||||||
|
- `EvTable` now supports passing `EvColumn`s as a list directly, (`EvTable(table=[colA,colB])`)
|
||||||
|
|
||||||
## Evennia 0.9.5
|
## Evennia 0.9.5
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -471,9 +471,6 @@ class EvCell:
|
||||||
else:
|
else:
|
||||||
self.height = self.raw_height
|
self.height = self.raw_height
|
||||||
|
|
||||||
# prepare data
|
|
||||||
# self.formatted = self._reformat()
|
|
||||||
|
|
||||||
def _crop(self, text, width):
|
def _crop(self, text, width):
|
||||||
"""
|
"""
|
||||||
Apply cropping of text.
|
Apply cropping of text.
|
||||||
|
|
@ -853,15 +850,18 @@ class EvCell:
|
||||||
Get data, padded and aligned in the form of a list of lines.
|
Get data, padded and aligned in the form of a list of lines.
|
||||||
|
|
||||||
"""
|
"""
|
||||||
|
if not self.formatted:
|
||||||
self.formatted = self._reformat()
|
self.formatted = self._reformat()
|
||||||
return self.formatted
|
return self.formatted
|
||||||
|
|
||||||
def __repr__(self):
|
def __repr__(self):
|
||||||
|
if not self.formatted:
|
||||||
self.formatted = self._reformat()
|
self.formatted = self._reformat()
|
||||||
return str(ANSIString("<EvCel %s>" % self.formatted))
|
return str(ANSIString("<EvCel %s>" % self.formatted))
|
||||||
|
|
||||||
def __str__(self):
|
def __str__(self):
|
||||||
"returns cell contents on string form"
|
"returns cell contents on string form"
|
||||||
|
if not self.formatted:
|
||||||
self.formatted = self._reformat()
|
self.formatted = self._reformat()
|
||||||
return str(ANSIString("\n").join(self.formatted))
|
return str(ANSIString("\n").join(self.formatted))
|
||||||
|
|
||||||
|
|
@ -1146,7 +1146,19 @@ class EvTable:
|
||||||
self.options = kwargs
|
self.options = kwargs
|
||||||
|
|
||||||
# use the temporary table to generate the table on the fly, as a list of EvColumns
|
# use the temporary table to generate the table on the fly, as a list of EvColumns
|
||||||
self.table = [EvColumn(*col, **kwargs) for col in table]
|
self.table = []
|
||||||
|
for col in table:
|
||||||
|
if isinstance(col, EvColumn):
|
||||||
|
self.add_column(col, **kwargs)
|
||||||
|
elif isinstance(col, (list, tuple)):
|
||||||
|
self.table.append(EvColumn(*col, **kwargs))
|
||||||
|
else:
|
||||||
|
raise RuntimeError(
|
||||||
|
"EvTable 'table' kwarg must be a list of EvColumns or a list-of-lists of"
|
||||||
|
f" strings. Found {type(col)}."
|
||||||
|
)
|
||||||
|
|
||||||
|
# self.table = [EvColumn(*col, **kwargs) for col in table]
|
||||||
|
|
||||||
# this is the actual working table
|
# this is the actual working table
|
||||||
self.worktable = None
|
self.worktable = None
|
||||||
|
|
@ -1508,6 +1520,11 @@ class EvTable:
|
||||||
options = dict(list(self.options.items()) + list(kwargs.items()))
|
options = dict(list(self.options.items()) + list(kwargs.items()))
|
||||||
|
|
||||||
xpos = kwargs.get("xpos", None)
|
xpos = kwargs.get("xpos", None)
|
||||||
|
|
||||||
|
if args and isinstance(args[0], EvColumn):
|
||||||
|
column = args[0]
|
||||||
|
column.reformat(**kwargs)
|
||||||
|
else:
|
||||||
column = EvColumn(*args, **options)
|
column = EvColumn(*args, **options)
|
||||||
wtable = self.ncols
|
wtable = self.ncols
|
||||||
htable = self.nrows
|
htable = self.nrows
|
||||||
|
|
@ -1546,7 +1563,6 @@ class EvTable:
|
||||||
xpos = min(wtable - 1, max(0, int(xpos)))
|
xpos = min(wtable - 1, max(0, int(xpos)))
|
||||||
self.table.insert(xpos, column)
|
self.table.insert(xpos, column)
|
||||||
self.ncols += 1
|
self.ncols += 1
|
||||||
# self._balance()
|
|
||||||
|
|
||||||
def add_row(self, *args, **kwargs):
|
def add_row(self, *args, **kwargs):
|
||||||
"""
|
"""
|
||||||
|
|
|
||||||
|
|
@ -196,7 +196,8 @@ class TestEvTable(EvenniaTestCase):
|
||||||
|
|
||||||
def test_multiple_rows(self):
|
def test_multiple_rows(self):
|
||||||
"""
|
"""
|
||||||
adding a lot of rows with `.add_row`.
|
Adding a lot of rows with `.add_row`.
|
||||||
|
|
||||||
"""
|
"""
|
||||||
table = evtable.EvTable("|yHeading1|n", "|B|[GHeading2|n", "Heading3")
|
table = evtable.EvTable("|yHeading1|n", "|B|[GHeading2|n", "Heading3")
|
||||||
nlines = 12
|
nlines = 12
|
||||||
|
|
@ -222,3 +223,56 @@ class TestEvTable(EvenniaTestCase):
|
||||||
expected = "\n".join(expected)
|
expected = "\n".join(expected)
|
||||||
|
|
||||||
self._validate(expected, str(table))
|
self._validate(expected, str(table))
|
||||||
|
|
||||||
|
def test_2762(self):
|
||||||
|
"""
|
||||||
|
Testing https://github.com/evennia/evennia/issues/2762
|
||||||
|
|
||||||
|
Extra spaces getting added to cell content
|
||||||
|
|
||||||
|
Also testing out adding EvColumns directly to the table kwarg.
|
||||||
|
|
||||||
|
"""
|
||||||
|
# direct table add
|
||||||
|
table = evtable.EvTable(table=[["another"]], fill_char=".", pad_char="#", width=8)
|
||||||
|
|
||||||
|
expected = """
|
||||||
|
+------+
|
||||||
|
|#anot#|
|
||||||
|
|#her.#|
|
||||||
|
+------+
|
||||||
|
"""
|
||||||
|
self._validate(expected, str(table))
|
||||||
|
|
||||||
|
# add with .add_column
|
||||||
|
table = evtable.EvTable(fill_char=".", pad_char="#")
|
||||||
|
table.add_column("another", width=8)
|
||||||
|
|
||||||
|
self._validate(expected, str(table))
|
||||||
|
|
||||||
|
# add by passing a column to constructor directly
|
||||||
|
|
||||||
|
colB = evtable.EvColumn("another", width=8)
|
||||||
|
|
||||||
|
table = evtable.EvTable(table=[colB], fill_char=".", pad_char="#")
|
||||||
|
|
||||||
|
self._validate(expected, str(table))
|
||||||
|
|
||||||
|
# more complex table
|
||||||
|
|
||||||
|
colA = evtable.EvColumn("this", "is", "a", "column") # no width
|
||||||
|
colB = evtable.EvColumn("and", "another", "one", "here", width=8)
|
||||||
|
|
||||||
|
table = evtable.EvTable(table=[colA, colB], fill_char=".", pad_char="#")
|
||||||
|
|
||||||
|
expected = """
|
||||||
|
+--------+-------+
|
||||||
|
|#this..#|#and..#|
|
||||||
|
|#is....#|#anoth#|
|
||||||
|
|#......#|#er...#|
|
||||||
|
|#a.....#|#one..#|
|
||||||
|
|#column#|#here.#|
|
||||||
|
+--------+-------+
|
||||||
|
"""
|
||||||
|
|
||||||
|
self._validate(expected, str(table))
|
||||||
|
|
|
||||||
|
|
@ -2193,23 +2193,34 @@ def calledby(callerdepth=1):
|
||||||
another function; it will print which function called it.
|
another function; it will print which function called it.
|
||||||
|
|
||||||
Args:
|
Args:
|
||||||
callerdepth (int): Must be larger than 0. When > 1, it will
|
callerdepth (int or None): If None, show entire stack. If int, must be larger than 0.
|
||||||
print the caller of the caller etc.
|
When > 1, it will print the sequence to that depth.
|
||||||
|
|
||||||
Returns:
|
Returns:
|
||||||
calledby (str): A debug string detailing which routine called
|
calledby (str): A debug string detailing the code that called us.
|
||||||
us.
|
|
||||||
|
|
||||||
"""
|
"""
|
||||||
import inspect
|
import inspect
|
||||||
|
|
||||||
|
def _stack_display(frame):
|
||||||
|
path = os.path.sep.join(frame[1].rsplit(os.path.sep, 2)[-2:])
|
||||||
|
return (
|
||||||
|
f"> called by '{frame[3]}': {path}:{frame[2]} >>>"
|
||||||
|
f" {frame[4][0].strip() if frame[4] else ''}"
|
||||||
|
)
|
||||||
|
|
||||||
stack = inspect.stack()
|
stack = inspect.stack()
|
||||||
|
|
||||||
|
out = []
|
||||||
|
if callerdepth is None:
|
||||||
|
callerdepth = len(stack) - 1
|
||||||
|
|
||||||
|
# show range
|
||||||
|
for idepth in range(1, max(1, callerdepth + 1)):
|
||||||
# we must step one extra level back in stack since we don't want
|
# we must step one extra level back in stack since we don't want
|
||||||
# to include the call of this function itself.
|
# to include the call of this function itself.
|
||||||
callerdepth = min(max(2, callerdepth + 1), len(stack) - 1)
|
out.append(_stack_display(stack[min(idepth + 1, len(stack) - 1)]))
|
||||||
frame = inspect.stack()[callerdepth]
|
return "\n".join(out[::-1])
|
||||||
path = os.path.sep.join(frame[1].rsplit(os.path.sep, 2)[-2:])
|
|
||||||
return "[called by '%s': %s:%s %s]" % (frame[3], path, frame[2], frame[4])
|
|
||||||
|
|
||||||
|
|
||||||
def m_len(target):
|
def m_len(target):
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue