From 497fb9e21f45ec08e1486abaee6dfa7b20b8a691 Mon Sep 17 00:00:00 2001 From: Scott Gasch Date: Wed, 24 Mar 2021 18:08:54 -0700 Subject: Initial revision --- text_utils.py | 153 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 153 insertions(+) create mode 100644 text_utils.py (limited to 'text_utils.py') diff --git a/text_utils.py b/text_utils.py new file mode 100644 index 0000000..a71a99d --- /dev/null +++ b/text_utils.py @@ -0,0 +1,153 @@ +#!/usr/bin/env python3 + +"""Utilities for dealing with "text".""" + +import math +import sys +from typing import List, NamedTuple + +from ansi import fg, reset +import exec_utils + + +class RowsColumns(NamedTuple): + rows: int + columns: int + + +def get_console_rows_columns() -> RowsColumns: + rows, columns = exec_utils.cmd("stty size").split() + return RowsColumns(int(rows), int(columns)) + + +def progress_graph( + current: int, + total: int, + *, + width=70, + fgcolor=fg("school bus yellow"), + left_end="[", + right_end="]", + redraw=True, +) -> None: + percent = current / total + ret = "\r" if redraw else "\n" + bar = bar_graph( + percent, + include_text = True, + width = width, + fgcolor = fgcolor, + left_end = left_end, + right_end = right_end) + print( + bar, + end=ret, + flush=True, + file=sys.stderr) + + +def bar_graph( + percentage: float, + *, + include_text=True, + width=70, + fgcolor=fg("school bus yellow"), + left_end="[", + right_end="]", +) -> None: + if percentage < 0.0 or percentage > 1.0: + raise ValueError(percentage) + if include_text: + text = f"{percentage*100.0:2.1f}%" + else: + text = "" + whole_width = math.floor(percentage * width) + if whole_width == width: + whole_width -= 1 + part_char = "▉" + else: + remainder_width = (percentage * width) % 1 + part_width = math.floor(remainder_width * 8) + part_char = [" ", "▏", "▎", "▍", "▌", "▋", "▊", "▉"][part_width] + return ( + left_end + + fgcolor + + "█" * whole_width + part_char + + " " * (width - whole_width - 1) + + reset() + + right_end + " " + + text) + + +def distribute_strings( + strings: List[str], + *, + width: int = 80, + alignment: str = "c", + padding: str = " ", +) -> str: + subwidth = math.floor(width / len(strings)) + retval = "" + for string in strings: + string = justify_string( + string, width=subwidth, alignment=alignment, padding=padding + ) + retval += string + return retval + + +def justify_string_by_chunk( + string: str, width: int = 80, padding: str = " " +) -> str: + padding = padding[0] + first, *rest, last = string.split() + w = width - (len(first) + 1 + len(last) + 1) + retval = ( + first + padding + distribute_strings(rest, width=w, padding=padding) + ) + while len(retval) + len(last) < width: + retval += padding + retval += last + return retval + + +def justify_string( + string: str, *, width: int = 80, alignment: str = "c", padding: str = " " +) -> str: + alignment = alignment[0] + padding = padding[0] + while len(string) < width: + if alignment == "l": + string += padding + elif alignment == "r": + string = padding + string + elif alignment == "j": + return justify_string_by_chunk( + string, + width=width, + padding=padding + ) + elif alignment == "c": + if len(string) % 2 == 0: + string += padding + else: + string = padding + string + else: + raise ValueError + return string + + +def justify_text(text: str, *, width: int = 80, alignment: str = "c") -> str: + print("-" * width) + retval = "" + line = "" + for word in text.split(): + if len(line) + len(word) > width: + line = line[1:] + line = justify_string(line, width=width, alignment=alignment) + retval = retval + "\n" + line + line = "" + line = line + " " + word + if len(line) > 0: + retval += "\n" + line[1:] + return retval[1:] -- cgit v1.3