From 2578fdca75530d0b11349df08fd98d0d6f05f484 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Odd=20Str=C3=A5b=C3=B8?= Date: Tue, 2 Nov 2021 23:43:16 +0100 Subject: [PATCH] Fancy text tables --- .gitignore | 1 + draw_memory_map.py | 65 ++++++++++++++++++++++++++ table_drawing.py | 113 +++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 179 insertions(+) create mode 100644 .gitignore create mode 100644 draw_memory_map.py create mode 100644 table_drawing.py diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..f0b7d96 --- /dev/null +++ b/.gitignore @@ -0,0 +1 @@ +*.py[ocd] diff --git a/draw_memory_map.py b/draw_memory_map.py new file mode 100644 index 0000000..5139033 --- /dev/null +++ b/draw_memory_map.py @@ -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)] + + +# diff --git a/table_drawing.py b/table_drawing.py new file mode 100644 index 0000000..c44f7f5 --- /dev/null +++ b/table_drawing.py @@ -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, + ) + )