Fancy text tables
This commit is contained in:
parent
c367d642d8
commit
2578fdca75
3 changed files with 179 additions and 0 deletions
1
.gitignore
vendored
Normal file
1
.gitignore
vendored
Normal file
|
@ -0,0 +1 @@
|
||||||
|
*.py[ocd]
|
65
draw_memory_map.py
Normal file
65
draw_memory_map.py
Normal file
|
@ -0,0 +1,65 @@
|
||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
from typing import Iterable
|
||||||
|
|
||||||
|
from table_drawing import table
|
||||||
|
|
||||||
|
|
||||||
|
def memory_table(data: Iterable[int], start: int = 0, wordsize: int = 2):
|
||||||
|
data_iter = iter(data)
|
||||||
|
data_rows = []
|
||||||
|
position = start
|
||||||
|
try:
|
||||||
|
while True:
|
||||||
|
try:
|
||||||
|
row_id = position
|
||||||
|
row = []
|
||||||
|
for _ in range(16):
|
||||||
|
try:
|
||||||
|
cell = []
|
||||||
|
for _ in range(wordsize):
|
||||||
|
d = data_iter.__next__() & 0xFF
|
||||||
|
cell.append(d)
|
||||||
|
position += 1
|
||||||
|
finally:
|
||||||
|
if cell:
|
||||||
|
row.append(cell)
|
||||||
|
finally:
|
||||||
|
if row:
|
||||||
|
row_hex = [" ".join([f"{n:02X}" for n in cell]) for cell in row]
|
||||||
|
row_ascii = [
|
||||||
|
" ".join(
|
||||||
|
[
|
||||||
|
" " + chr(n) if chr(n).isprintable() else " "
|
||||||
|
for n in cell
|
||||||
|
]
|
||||||
|
)
|
||||||
|
for cell in row
|
||||||
|
]
|
||||||
|
row_head = f"{row_id:04X}"[:3] + "·"
|
||||||
|
data_rows.append([row_head] + row_hex)
|
||||||
|
if " ".join(row_ascii).strip():
|
||||||
|
data_rows.append([""] + row_ascii)
|
||||||
|
except StopIteration:
|
||||||
|
pass
|
||||||
|
|
||||||
|
headers = [""] + [
|
||||||
|
("" if wordsize % 2 else " ") + "···{:01X}".format(x) for x in range(16)
|
||||||
|
]
|
||||||
|
return table(
|
||||||
|
data_rows,
|
||||||
|
headers=headers,
|
||||||
|
justify="^",
|
||||||
|
header_interval=8 * 2,
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
data = list(range(256))
|
||||||
|
|
||||||
|
|
||||||
|
print(memory_table(data, wordsize=1))
|
||||||
|
|
||||||
|
#
|
||||||
|
# rows = [[f"{x:03X}·"] for x in range(32)]
|
||||||
|
|
||||||
|
|
||||||
|
#
|
113
table_drawing.py
Normal file
113
table_drawing.py
Normal file
|
@ -0,0 +1,113 @@
|
||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
from typing import Collection, Optional, Union
|
||||||
|
|
||||||
|
C_UL = "┌"
|
||||||
|
C_UR = "┐"
|
||||||
|
C_LL = "└"
|
||||||
|
C_LR = "┘"
|
||||||
|
|
||||||
|
C_V = "│"
|
||||||
|
C_VL = "├"
|
||||||
|
C_VR = "┤"
|
||||||
|
|
||||||
|
C_H = "─"
|
||||||
|
C_HD = "┬"
|
||||||
|
C_HU = "┴"
|
||||||
|
C_X = "┼"
|
||||||
|
|
||||||
|
|
||||||
|
def row(
|
||||||
|
fields: Collection[str],
|
||||||
|
sep: str = C_V,
|
||||||
|
start: str = C_V,
|
||||||
|
end: str = C_V,
|
||||||
|
) -> str:
|
||||||
|
res = []
|
||||||
|
|
||||||
|
for i, field in enumerate(fields):
|
||||||
|
if not i:
|
||||||
|
res.append(start)
|
||||||
|
else:
|
||||||
|
res.append(sep)
|
||||||
|
|
||||||
|
res.append(field)
|
||||||
|
|
||||||
|
res.append(end)
|
||||||
|
|
||||||
|
return "".join(res)
|
||||||
|
|
||||||
|
|
||||||
|
def table(
|
||||||
|
data: Collection[Collection[str]],
|
||||||
|
headers: Optional[Collection] = None,
|
||||||
|
header_interval: Optional[int] = None,
|
||||||
|
justify: Optional[Union[str, Collection[str]]] = None,
|
||||||
|
):
|
||||||
|
res = []
|
||||||
|
|
||||||
|
if not data:
|
||||||
|
return ""
|
||||||
|
|
||||||
|
columns = max([len(x) for x in data])
|
||||||
|
if headers:
|
||||||
|
columns = max(columns, len(headers))
|
||||||
|
|
||||||
|
if isinstance(justify, str):
|
||||||
|
justify = [justify] * columns
|
||||||
|
elif not justify:
|
||||||
|
justify = []
|
||||||
|
|
||||||
|
justify = list(justify) + ["^"] * (columns - len(justify))
|
||||||
|
|
||||||
|
colwidths = [0] * columns
|
||||||
|
|
||||||
|
if headers:
|
||||||
|
for i, col in enumerate(headers):
|
||||||
|
colwidths[i] = max(colwidths[i], len(col))
|
||||||
|
|
||||||
|
for data_row in data:
|
||||||
|
for i, col in enumerate(data_row):
|
||||||
|
colwidths[i] = max(colwidths[i], len(col))
|
||||||
|
|
||||||
|
def row_iterable():
|
||||||
|
if headers and not header_interval:
|
||||||
|
yield headers
|
||||||
|
|
||||||
|
for i, data_row in enumerate(data):
|
||||||
|
if header_interval and i % header_interval == 0:
|
||||||
|
yield headers
|
||||||
|
yield data_row
|
||||||
|
|
||||||
|
for i, data_row in enumerate(row_iterable()):
|
||||||
|
if not i:
|
||||||
|
res.append(
|
||||||
|
row([C_H * colw for colw in colwidths], start=C_UL, sep=C_HD, end=C_UR)
|
||||||
|
)
|
||||||
|
else:
|
||||||
|
res.append(
|
||||||
|
row([C_H * colw for colw in colwidths], start=C_VL, sep=C_X, end=C_VR)
|
||||||
|
)
|
||||||
|
padding = [""] * (columns - len(data_row))
|
||||||
|
padded_row = [
|
||||||
|
f"{cell:{justify[j]}{colwidths[j]}s}"
|
||||||
|
for j, cell in enumerate(list(data_row) + padding)
|
||||||
|
]
|
||||||
|
res.append(row(padded_row))
|
||||||
|
|
||||||
|
res.append(row([C_H * colw for colw in colwidths], start=C_LL, sep=C_HU, end=C_LR))
|
||||||
|
|
||||||
|
return "\n".join(res)
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
headers = [""] + ["···{:01X}".format(x) for x in range(16)]
|
||||||
|
data = [[f"{x:03X}·"] for x in range(32)]
|
||||||
|
|
||||||
|
print(
|
||||||
|
table(
|
||||||
|
data,
|
||||||
|
headers=headers,
|
||||||
|
justify=">",
|
||||||
|
header_interval=8,
|
||||||
|
)
|
||||||
|
)
|
Loading…
Reference in a new issue