11"""Provides common utilities to support Rich in cmd2-based applications."""
22
3+ import re
34from collections .abc import Mapping
45from enum import Enum
56from typing import (
2829
2930from .styles import DEFAULT_CMD2_STYLES
3031
32+ # A compiled regular expression to detect ANSI style sequences.
33+ ANSI_STYLE_SEQUENCE_RE = re .compile (r"\x1b\[[0-9;?]*m" )
34+
3135
3236class AllowStyle (Enum ):
3337 """Values for ``cmd2.rich_utils.ALLOW_STYLE``."""
3438
35- ALWAYS = ' Always' # Always output ANSI style sequences
36- NEVER = ' Never' # Remove ANSI style sequences from all output
37- TERMINAL = ' Terminal' # Remove ANSI style sequences if the output is not going to the terminal
39+ ALWAYS = " Always" # Always output ANSI style sequences
40+ NEVER = " Never" # Remove ANSI style sequences from all output
41+ TERMINAL = " Terminal" # Remove ANSI style sequences if the output is not going to the terminal
3842
3943 def __str__ (self ) -> str :
4044 """Return value instead of enum name for printing in cmd2's set command."""
@@ -234,7 +238,7 @@ def rich_text_to_string(text: Text) -> str:
234238 """Convert a Rich Text object to a string.
235239
236240 This function's purpose is to render a Rich Text object, including any styles (e.g., color, bold),
237- to a plain Python string with ANSI escape codes . It differs from `text.plain`, which strips
241+ to a plain Python string with ANSI style sequences . It differs from `text.plain`, which strips
238242 all formatting.
239243
240244 :param text: the text object to convert
@@ -259,7 +263,7 @@ def rich_text_to_string(text: Text) -> str:
259263
260264
261265def string_to_rich_text (text : str ) -> Text :
262- r"""Create a Text object from a string which can contain ANSI escape codes .
266+ r"""Create a Rich Text object from a string which can contain ANSI style sequences .
263267
264268 This wraps rich.Text.from_ansi() to handle an issue where it removes the
265269 trailing line break from a string (e.g. "Hello\n" becomes "Hello").
@@ -323,9 +327,9 @@ def prepare_objects_for_rendering(*objects: Any) -> tuple[Any, ...]:
323327 """Prepare a tuple of objects for printing by Rich's Console.print().
324328
325329 This function converts any non-Rich object whose string representation contains
326- ANSI style codes into a rich. Text object. This ensures correct display width
327- calculation, as Rich can then properly parse and account for the non-printing
328- ANSI codes. All other objects are left untouched, allowing Rich's native
330+ ANSI style sequences into a Rich Text object. This ensures correct display width
331+ calculation, as Rich can then properly parse and account for these non-printing
332+ codes. All other objects are left untouched, allowing Rich's native
329333 renderers to handle them.
330334
331335 :param objects: objects to prepare
@@ -342,12 +346,10 @@ def prepare_objects_for_rendering(*objects: Any) -> tuple[Any, ...]:
342346 if isinstance (renderable , ConsoleRenderable ):
343347 continue
344348
345- # Check if the object's string representation contains ANSI styles, and if so,
346- # replace it with a Rich Text object for correct width calculation.
347349 renderable_as_str = str (renderable )
348- renderable_as_text = string_to_rich_text (renderable_as_str )
349350
350- if renderable_as_text .plain != renderable_as_str :
351- object_list [i ] = renderable_as_text
351+ # Check for any ANSI style sequences in the string.
352+ if ANSI_STYLE_SEQUENCE_RE .search (renderable_as_str ):
353+ object_list [i ] = string_to_rich_text (renderable_as_str )
352354
353355 return tuple (object_list )
0 commit comments