import codecs import itertools import sys def bordered(*columns: dict) -> str: """ credits to https://github.com/Cog-Creators/Red-DiscordBot/blob/V3/develop/redbot/core/utils/chat_formatting.py Get two blocks of text in a borders. Note ---- This will only work with a monospaced font. Parameters ---------- *columns : `sequence` of `str` The columns of text, each being a list of lines in that column. Returns ------- str The bordered text. """ encoder = codecs.getencoder(sys.stdout.encoding) try: encoder("┌┐└┘─│") # border symbols except UnicodeEncodeError: ascii_border = True else: ascii_border = False borders = { "TL": "+" if ascii_border else "┌", # Top-left "TR": "+" if ascii_border else "┐", # Top-right "BL": "+" if ascii_border else "└", # Bottom-left "BR": "+" if ascii_border else "┘", # Bottom-right "HZ": "-" if ascii_border else "─", # Horizontal "VT": "|" if ascii_border else "│", # Vertical } sep = " " * 4 # Separator between boxes widths = tuple( max(len(row) for row in column.get("rows")) + 9 for column in columns ) # width of each col cols_done = [False] * len(columns) # whether or not each column is done lines = [""] for i, column in enumerate(columns): lines[0] += ( "{TL}" + "{HZ}" + column.get("title") + "{HZ}" * (widths[i] - len(column.get("title")) - 1) + "{TR}" + sep ) for line in itertools.zip_longest(*[column.get("rows") for column in columns]): row = [] for colidx, column in enumerate(line): width = widths[colidx] done = cols_done[colidx] if column is None: if not done: # bottom border of column column = "{HZ}" * width row.append("{BL}" + column + "{BR}") cols_done[colidx] = True # mark column as done else: # leave empty row.append(" " * (width + 2)) else: column += " " * (width - len(column)) # append padded spaces row.append("{VT}" + column + "{VT}") lines.append(sep.join(row)) final_row = [] for width, done in zip(widths, cols_done): if not done: final_row.append("{BL}" + "{HZ}" * width + "{BR}") else: final_row.append(" " * (width + 2)) lines.append(sep.join(final_row)) return "\n".join(lines).format(**borders)