Various changes.
[python_utils.git] / text_utils.py
index a71a99dff943df0058cf080100c7feeedf97a6ed..3be32ff49ec05b2d7ca0978e6cb34b65da64162e 100644 (file)
@@ -2,12 +2,12 @@
 
 """Utilities for dealing with "text"."""
 
+from collections import defaultdict
 import math
 import sys
-from typing import List, NamedTuple
+from typing import List, NamedTuple, Optional
 
 from ansi import fg, reset
-import exec_utils
 
 
 class RowsColumns(NamedTuple):
@@ -16,7 +16,8 @@ class RowsColumns(NamedTuple):
 
 
 def get_console_rows_columns() -> RowsColumns:
-    rows, columns = exec_utils.cmd("stty size").split()
+    from exec_utils import cmd
+    rows, columns = cmd("stty size").split()
     return RowsColumns(int(rows), int(columns))
 
 
@@ -151,3 +152,67 @@ def justify_text(text: str, *, width: int = 80, alignment: str = "c") -> str:
     if len(line) > 0:
         retval += "\n" + line[1:]
     return retval[1:]
+
+
+def generate_padded_columns(text: List[str]) -> str:
+    max_width = defaultdict(int)
+    for line in text:
+        for pos, word in enumerate(line.split()):
+            max_width[pos] = max(max_width[pos], len(word))
+
+    for line in text:
+        out = ""
+        for pos, word in enumerate(line.split()):
+            width = max_width[pos]
+            word = justify_string(word, width=width, alignment='l')
+            out += f'{word} '
+        yield out
+
+
+def wrap_string(text: str, n: int) -> str:
+    chunks = text.split()
+    out = ''
+    width = 0
+    for chunk in chunks:
+        if width + len(chunk) > n:
+            out += '\n'
+            width = 0
+        out += chunk + ' '
+        width += len(chunk) + 1
+    return out
+
+
+class Indenter:
+    """
+    with Indenter(pad_count = 8) as i:
+        i.print('test')
+        with i:
+            i.print('-ing')
+            with i:
+                i.print('1, 2, 3')
+    """
+    def __init__(self,
+                 *,
+                 pad_prefix: Optional[str] = None,
+                 pad_char: str = ' ',
+                 pad_count: int = 4):
+        self.level = -1
+        if pad_prefix is not None:
+            self.pad_prefix = pad_prefix
+        else:
+            self.pad_prefix = ''
+        self.padding = pad_char * pad_count
+
+    def __enter__(self):
+        self.level += 1
+        return self
+
+    def __exit__(self, exc_type, exc_value, exc_tb):
+        self.level -= 1
+        if self.level < -1:
+            self.level = -1
+
+    def print(self, *arg, **kwargs):
+        import string_utils
+        text = string_utils.sprintf(*arg, **kwargs)
+        print(self.pad_prefix + self.padding * self.level + text, end='')