From ea752bef9c415585478c50bb8a72ec60c0c6eedd Mon Sep 17 00:00:00 2001 From: Kevin Van Brunt Date: Tue, 19 Aug 2025 19:02:44 -0400 Subject: [PATCH 1/2] Simplied string_to_rich_text(). --- cmd2/rich_utils.py | 30 ++++++------------------------ 1 file changed, 6 insertions(+), 24 deletions(-) diff --git a/cmd2/rich_utils.py b/cmd2/rich_utils.py index 55f0f9ae1..313a82820 100644 --- a/cmd2/rich_utils.py +++ b/cmd2/rich_utils.py @@ -188,36 +188,18 @@ def rich_text_to_string(text: Text) -> str: def string_to_rich_text(text: str) -> Text: r"""Create a Text object from a string which can contain ANSI escape codes. - This wraps rich.Text.from_ansi() to handle a discarded newline issue. + This function is a workaround for a bug where rich.Text.from_ansi() incorrectly + removes a trailing newline. The official fix is pending. - Text.from_ansi() currently removes the ending line break from string. - e.g. "Hello\n" becomes "Hello" - - There is currently a pull request to fix this. - https://github.com/Textualize/rich/pull/3793 + See: https://github.com/Textualize/rich/pull/3793 :param text: a string to convert to a Text object. - :return: the converted string + :return: the string converted to a Text object """ result = Text.from_ansi(text) - # If 'text' ends with a line break character, restore the missing newline to 'result'. - # Note: '\r\n' is handled as its last character is '\n'. - # Source: https://docs.python.org/3/library/stdtypes.html#str.splitlines - line_break_chars = { - "\n", # Line Feed - "\r", # Carriage Return - "\v", # Vertical Tab - "\f", # Form Feed - "\x1c", # File Separator - "\x1d", # Group Separator - "\x1e", # Record Separator - "\x85", # Next Line (NEL) - "\u2028", # Line Separator - "\u2029", # Paragraph Separator - } - if text and text[-1] in line_break_chars: - # We use "\n" because Text.from_ansi() converts all line breaks chars into newlines. + # Handle case where Text.from_ansi() removed the trailing newline. + if text.endswith("\n"): result.append("\n") return result From 71ab48bfa6695cc664279b4f48519983f0be5176 Mon Sep 17 00:00:00 2001 From: Kevin Van Brunt Date: Tue, 19 Aug 2025 23:03:23 -0400 Subject: [PATCH 2/2] Updated comments. --- cmd2/rich_utils.py | 28 ++++++++++++++++++++++------ 1 file changed, 22 insertions(+), 6 deletions(-) diff --git a/cmd2/rich_utils.py b/cmd2/rich_utils.py index 313a82820..3e06dfaba 100644 --- a/cmd2/rich_utils.py +++ b/cmd2/rich_utils.py @@ -188,18 +188,34 @@ def rich_text_to_string(text: Text) -> str: def string_to_rich_text(text: str) -> Text: r"""Create a Text object from a string which can contain ANSI escape codes. - This function is a workaround for a bug where rich.Text.from_ansi() incorrectly - removes a trailing newline. The official fix is pending. + This wraps rich.Text.from_ansi() to handle an issue where it removes the + trailing line break from a string (e.g. "Hello\n" becomes "Hello"). - See: https://github.com/Textualize/rich/pull/3793 + There is currently a pull request to fix this. + https://github.com/Textualize/rich/pull/3793 :param text: a string to convert to a Text object. - :return: the string converted to a Text object + :return: the converted string """ result = Text.from_ansi(text) - # Handle case where Text.from_ansi() removed the trailing newline. - if text.endswith("\n"): + # If the original string ends with a recognized line break character, + # then restore the missing newline. We use "\n" because Text.from_ansi() + # converts all line breaks into newlines. + # Source: https://docs.python.org/3/library/stdtypes.html#str.splitlines + line_break_chars = { + "\n", # Line Feed + "\r", # Carriage Return + "\v", # Vertical Tab + "\f", # Form Feed + "\x1c", # File Separator + "\x1d", # Group Separator + "\x1e", # Record Separator + "\x85", # Next Line (NEL) + "\u2028", # Line Separator + "\u2029", # Paragraph Separator + } + if text and text[-1] in line_break_chars: result.append("\n") return result