summaryrefslogtreecommitdiff
path: root/text_utils.py
diff options
context:
space:
mode:
Diffstat (limited to 'text_utils.py')
-rw-r--r--text_utils.py153
1 files changed, 153 insertions, 0 deletions
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:]