3 """Utilities for dealing with "text"."""
5 from collections import defaultdict
8 from typing import List, NamedTuple
10 from ansi import fg, reset
13 class RowsColumns(NamedTuple):
18 def get_console_rows_columns() -> RowsColumns:
19 from exec_utils import cmd
20 rows, columns = cmd("stty size").split()
21 return RowsColumns(int(rows), int(columns))
29 fgcolor=fg("school bus yellow"),
34 percent = current / total
35 ret = "\r" if redraw else "\n"
42 right_end = right_end)
55 fgcolor=fg("school bus yellow"),
59 if percentage < 0.0 or percentage > 1.0:
60 raise ValueError(percentage)
62 text = f"{percentage*100.0:2.1f}%"
65 whole_width = math.floor(percentage * width)
66 if whole_width == width:
70 remainder_width = (percentage * width) % 1
71 part_width = math.floor(remainder_width * 8)
72 part_char = [" ", "▏", "▎", "▍", "▌", "▋", "▊", "▉"][part_width]
76 "█" * whole_width + part_char +
77 " " * (width - whole_width - 1) +
83 def distribute_strings(
90 subwidth = math.floor(width / len(strings))
92 for string in strings:
93 string = justify_string(
94 string, width=subwidth, alignment=alignment, padding=padding
100 def justify_string_by_chunk(
101 string: str, width: int = 80, padding: str = " "
104 first, *rest, last = string.split()
105 w = width - (len(first) + 1 + len(last) + 1)
107 first + padding + distribute_strings(rest, width=w, padding=padding)
109 while len(retval) + len(last) < width:
116 string: str, *, width: int = 80, alignment: str = "c", padding: str = " "
118 alignment = alignment[0]
120 while len(string) < width:
123 elif alignment == "r":
124 string = padding + string
125 elif alignment == "j":
126 return justify_string_by_chunk(
131 elif alignment == "c":
132 if len(string) % 2 == 0:
135 string = padding + string
141 def justify_text(text: str, *, width: int = 80, alignment: str = "c") -> str:
145 for word in text.split():
146 if len(line) + len(word) > width:
148 line = justify_string(line, width=width, alignment=alignment)
149 retval = retval + "\n" + line
151 line = line + " " + word
153 retval += "\n" + line[1:]
157 def generate_padded_columns(text: List[str]) -> str:
158 max_width = defaultdict(int)
160 for pos, word in enumerate(line.split()):
161 max_width[pos] = max(max_width[pos], len(word))
165 for pos, word in enumerate(line.split()):
166 width = max_width[pos]
167 word = justify_string(word, width=width, alignment='l')
174 with Indenter() as i:
188 def __exit__(self, exc_type, exc_value, exc_tb):
193 def print(self, *arg, **kwargs):
195 text = string_utils.sprintf(*arg, **kwargs)
196 print(" " * self.level + text)