X-Git-Url: https://wannabe.guru.org/gitweb/?a=blobdiff_plain;f=src%2Fpyutils%2Ftext_utils.py;h=66f6f22dcd5dc8dcbd57777947002936e50e01f6;hb=ccca7ea8fae7ab9a79a88baf9a7f8f3219403c7b;hp=93355aa1450f837c3c05336185bf59578399795b;hpb=69566c003b4f1c3a4905f37d3735d7921502d14a;p=pyutils.git diff --git a/src/pyutils/text_utils.py b/src/pyutils/text_utils.py index 93355aa..66f6f22 100644 --- a/src/pyutils/text_utils.py +++ b/src/pyutils/text_utils.py @@ -3,7 +3,18 @@ # © 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 @@ -14,7 +25,7 @@ import re 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 @@ -41,37 +52,26 @@ def get_console_rows_columns() -> RowsColumns: """ 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: @@ -116,6 +116,13 @@ def bar_graph( 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( @@ -165,6 +172,8 @@ def 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' @@ -214,6 +223,8 @@ def sparkline(numbers: List[float]) -> Tuple[float, float, str]: * 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, '▁▁▂▄█▂▄▆') @@ -249,6 +260,8 @@ def distribute_strings( 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 ' """ @@ -359,6 +372,8 @@ def justify_text( 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.' @@ -596,6 +611,8 @@ def box( 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 │ @@ -628,6 +645,8 @@ def preformatted_box( 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 │ @@ -686,6 +705,20 @@ def print_box( ) -> 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 │