Source code for framed_text.shorten_text

import textwrap
from typing import Literal

from framed_text.labeled_data import AnyLabeledData, LabeledData
from framed_text.status import AnyStatus
from framed_text.utils import (
    _remove_ansi,
    _truncate_text_middle,
    _get_terminal_width,
)


[docs] class ShortenText:
[docs] def __init__(self, text: str | AnyStatus | AnyLabeledData, limit: int | None = None, mode: Literal["char", "word", "middle"] = "char"): """ Shorten text to a specified limit. Supports ``LabeledData``, ``Status`` and regular strings. **Modes** - ``char``: Cutoff char at end of text (The quick brown fox jumped ove…) - ``word``: Cutoff word at end of text (The quick brown fox jumped…) - ``middle``: Cutoff chars at middle of text (The quick brown…the lazy dog) :param text: Text to shorten :param limit: Limit. Text will be shortened to this length. If no limit is passed, will default to the width of the terminal. :param mode: Mode to use to shorten text. See above for more info. """ self._text: str | AnyStatus | AnyLabeledData = text self._limit: int = limit if limit and limit > 0 else _get_terminal_width() self._mode: Literal["char", "word", "middle"] = mode self._text_no_ansi: str = '' self._ph_char: str = '…' # Placeholder character self.text_shorten: str = '' if self._limit <= 0: # Error in case limit is ever below 1 (Likely won't happen) raise ValueError("Limit must be a positive integer.") if not isinstance(self._text, (str, AnyStatus, AnyLabeledData)): raise ValueError("Text must be a string, Status, or LabeledData.") self._text_no_ansi = _remove_ansi(text=self._text.__str__()).rstrip() if isinstance(self._text, str): # Handle regular strings self.text_shorten = self._handle_str(text=self._text_no_ansi) else: # Handle special framed-text types self.text_shorten = self._handle_ft(text=self._text)
def __str__(self) -> str: return self.text_shorten def _handle_str(self, text: str) -> str: """ Handle string logic :return: Shortened text """ if len(text) > self._limit: match self._mode.lower(): case "char": # Shorten by char return f"{text[:self._limit - 1]}{self._ph_char}" case "word": # Shorten by word return textwrap.shorten(text=text, width=self._limit, placeholder=self._ph_char) case "middle": # Shorten by middle characters return _truncate_text_middle(text=text, limit=self._limit) else: return text def _handle_ft(self, text: AnyStatus | AnyLabeledData) -> str: """ Handle framed-text specific logic. :return: Shortened text """ if isinstance(text, AnyStatus): # Status object if len(self._text_no_ansi) > self._limit: text.cutoff_text(limit=self._limit, mode=self._mode) return text.text_shorten else: return text.text else: # LabeledData object if len(self._text_no_ansi) > self._limit: if isinstance(text, ( LabeledData.String, LabeledData.Path )): # These types use mode text.cutoff_text(limit=self._limit, mode=self._mode) return text.text_shorten else: # These types don't use mode text.cutoff_text(limit=self._limit) return text.text_shorten else: # Text does not need to be shortened return text.text