# © Copyright 2021-2022, Scott Gasch
-"""Utilities for dealing with "text"."""
+"""
+Utilities for dealing with and creating text chunks. For example:
+
+ - Make a bar graph / progress graph,
+ - make a spark line,
+ - left, right, center, justify text,
+ - word wrap text,
+ - indent / dedent text,
+ - create a header line,
+ - draw a box around some text.
+
+"""
import contextlib
import enum
import sys
from collections import defaultdict
from dataclasses import dataclass
-from typing import Dict, Generator, List, Literal, Optional, Tuple
+from typing import Dict, Generator, List, Literal, Optional, Tuple, Union
from pyutils import string_utils
from pyutils.ansi import fg, reset
"""
from pyutils.exec_utils import cmd
- rows: Optional[str] = os.environ.get('LINES', None)
- cols: Optional[str] = os.environ.get('COLUMNS', None)
+ rows: Union[Optional[str], int] = os.environ.get('LINES', None)
+ cols: Union[Optional[str], int] = os.environ.get('COLUMNS', None)
if not rows or not cols:
- logger.debug('Rows: %s, cols: %s, trying stty.', rows, cols)
try:
- rows, cols = cmd(
- "stty size",
- timeout_seconds=1.0,
- ).split()
+ size = os.get_terminal_size()
+ rows = size.lines
+ cols = size.columns
except Exception:
rows = None
cols = None
- if rows is None:
- logger.debug('Rows: %s, cols: %s, tput rows.', rows, cols)
+ if not rows or not cols:
+ logger.debug('Rows: %s, cols: %s, trying stty.', rows, cols)
try:
- rows = cmd(
- "tput rows",
+ rows, cols = cmd(
+ "stty size",
timeout_seconds=1.0,
- )
+ ).split()
except Exception:
rows = None
-
- if cols is None:
- logger.debug('Rows: %s, cols: %s, tput cols.', rows, cols)
- try:
- cols = cmd(
- "tput cols",
- timeout_seconds=1.0,
- )
- except Exception:
cols = None
if not rows or not cols:
redraw: if True, omit a line feed after the carriage return
so that subsequent calls to this method redraw the graph
iteratively.
+
+ See also :meth:`bar_graph_string`, :meth:`sparkline`.
+
+ Example::
+
+ '[███████████████████████████████████ ] 0.5'
+
"""
ret = "\r" if redraw else "\n"
bar = bar_graph_string(
left_end: the character at the left side of the graph
right_end: the character at the right side of the graph
+ See also :meth:`bar_graph`, :meth:`sparkline`.
+
>>> bar_graph_string(5, 10, fgcolor='', reset_seq='')
'[███████████████████████████████████ ] 0.5'
* the maximum number in the population
* a string representation of the population in a concise format
+ See also :meth:`bar_graph`, :meth:`bar_graph_string`.
+
>>> sparkline([1, 2, 3, 5, 10, 3, 5, 7])
(1, 10, '▁▁▂▄█▂▄▆')
Returns:
The distributed, justified string.
+ See also :meth:`justify_string`, :meth:`justify_text`.
+
>>> distribute_strings(['this', 'is', 'a', 'test'], width=40)
' this is a test '
"""
Returns:
The justified text.
+ See also :meth:`justify_text`.
+
>>> justify_text('This is a test of the emergency broadcast system. This is only a test.',
... width=40, alignment='j') #doctest: +NORMALIZE_WHITESPACE
'This is a test of the emergency\\nbroadcast system. This is only a test.'
Returns:
the box as a string
+ See also :meth:`print_box`, :meth:`preformatted_box`.
+
>>> print(box('title', 'this is some text', width=20).strip())
╭──────────────────╮
│ title │
Returns:
the box as a string
+ See also :meth:`print_box`, :meth:`box`.
+
>>> print(preformatted_box('title', 'this\\nis\\nsome\\ntext', width=20).strip())
╭──────────────────╮
│ title │
) -> None:
"""Draws a box with nice rounded corners.
+ Args:
+ title: the title of the box
+ text: the text inside the box
+ width: the width of the box
+ color: the box's color
+
+ Returns:
+ None
+
+ Side-effects:
+ Prints a box with your text on the console to sys.stdout.
+
+ See also :meth:`preformatted_box`, :meth:`box`.
+
>>> print_box('Title', 'This is text', width=30)
╭────────────────────────────╮
│ Title │