Skip to content

Commit 72789b3

Browse files
committed
Added function to strip styles for strings rendered by prompt-toolkit.
1 parent 775931e commit 72789b3

2 files changed

Lines changed: 32 additions & 14 deletions

File tree

cmd2/cmd2.py

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -66,6 +66,7 @@
6666
)
6767

6868
import rich.box
69+
from prompt_toolkit import print_formatted_text
6970
from rich.console import (
7071
Group,
7172
RenderableType,
@@ -182,6 +183,7 @@ def __init__(self, msg: str = '') -> None:
182183
Cmd2Completer,
183184
Cmd2History,
184185
Cmd2Lexer,
186+
pt_filter_style,
185187
)
186188
from .utils import (
187189
Settable,
@@ -388,7 +390,7 @@ def __init__(
388390
self._initialize_plugin_system()
389391

390392
# Configure a few defaults
391-
self.prompt = Cmd.DEFAULT_PROMPT
393+
self.prompt: str = Cmd.DEFAULT_PROMPT
392394
self.intro = intro
393395

394396
# What to use for standard input
@@ -3239,6 +3241,8 @@ def _read_raw_input(
32393241
# Check if the session is configured for interactive terminal use.
32403242
if not isinstance(session.input, DummyInput):
32413243
with patch_stdout():
3244+
if not callable(prompt):
3245+
prompt = pt_filter_style(prompt)
32423246
return session.prompt(prompt, completer=completer, **prompt_kwargs)
32433247

32443248
# We're not at a terminal, so we're likely reading from a file or a pipe.
@@ -3367,7 +3371,7 @@ def _process_alerts(self) -> None:
33673371
# Print and update
33683372
with patch_stdout():
33693373
if alert.msg:
3370-
print(alert.msg)
3374+
print_formatted_text(pt_filter_style(alert.msg))
33713375

33723376
# Only update if the alert was generated after the current prompt was drawn on the screen.
33733377
if (alert.prompt is not None and
@@ -3393,7 +3397,7 @@ def _read_command_line(self, prompt: str) -> str:
33933397

33943398
# Use dynamic prompt if the prompt matches self.prompt
33953399
def get_prompt() -> ANSI:
3396-
return ANSI(self.prompt)
3400+
return pt_filter_style(self.prompt)
33973401

33983402
prompt_to_use: Callable[[], ANSI | str] | ANSI | str = ANSI(prompt)
33993403
if prompt == self.prompt:

cmd2/pt_utils.py

Lines changed: 25 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@
2626
utils,
2727
)
2828
from . import rich_utils as ru
29+
from . import string_utils as su
2930

3031
if TYPE_CHECKING: # pragma: no cover
3132
from .cmd2 import Cmd
@@ -34,6 +35,21 @@
3435
BASE_DELIMITERS = " \t\n" + "".join(constants.QUOTES) + "".join(constants.REDIRECTION_CHARS)
3536

3637

38+
def pt_filter_style(text: str | ANSI) -> str | ANSI:
39+
"""Strip styles if disallowed by ru.ALLOW_STYLE. Otherwise return an ANSI object.
40+
41+
This function is intended specifically for text rendered by prompt-toolkit.
42+
"""
43+
# We only use prompt-toolkit to write to a terminal. Therefore
44+
# we only have to check if ALLOW_STYLE is Never.
45+
if ru.ALLOW_STYLE == ru.AllowStyle.NEVER:
46+
raw_text = text.value if isinstance(text, ANSI) else text
47+
return su.strip_style(raw_text)
48+
49+
# String must be an ANSI object for prompt-toolkit to render ANSI style sequences.
50+
return text if isinstance(text, ANSI) else ANSI(text)
51+
52+
3753
class Cmd2Completer(Completer):
3854
"""Completer that delegates to cmd2's completion logic."""
3955

@@ -72,16 +88,16 @@ def get_completions(self, document: Document, _complete_event: object) -> Iterab
7288
)
7389

7490
if completions.completion_error:
75-
print_formatted_text(ANSI(completions.completion_error))
91+
print_formatted_text(pt_filter_style(completions.completion_error))
7692
return
7793

7894
# Print completion table if present
7995
if completions.completion_table:
80-
print_formatted_text(ANSI("\n" + completions.completion_table))
96+
print_formatted_text(pt_filter_style("\n" + completions.completion_table))
8197

8298
# Print hint if present and settings say we should
8399
if completions.completion_hint and (self.cmd_app.always_show_hint or not completions):
84-
print_formatted_text(ANSI(completions.completion_hint))
100+
print_formatted_text(pt_filter_style(completions.completion_hint))
85101

86102
if not completions:
87103
return
@@ -103,9 +119,6 @@ def get_completions(self, document: Document, _complete_event: object) -> Iterab
103119
buffer.cursor_right(search_text_length)
104120
return
105121

106-
# Determine if we should remove style from completion text
107-
remove_style = ru.ALLOW_STYLE == ru.AllowStyle.NEVER
108-
109122
# Return the completions
110123
for item in completions:
111124
# Set offset to the start of the current word to overwrite it with the completion
@@ -134,8 +147,8 @@ def get_completions(self, document: Document, _complete_event: object) -> Iterab
134147
yield Completion(
135148
match_text,
136149
start_position=start_position,
137-
display=item.display_plain if remove_style else ANSI(item.display),
138-
display_meta=item.display_meta_plain if remove_style else ANSI(item.display_meta),
150+
display=pt_filter_style(item.display),
151+
display_meta=pt_filter_style(item.display_meta),
139152
)
140153

141154

@@ -215,8 +228,9 @@ def get_line(lineno: int) -> list[tuple[str, str]]:
215228
tokens: list[tuple[str, str]] = []
216229

217230
# Use cmd2's command pattern to find the first word (the command)
218-
match = self.cmd_app.statement_parser._command_pattern.search(line)
219-
if match:
231+
if ru.ALLOW_STYLE != ru.AllowStyle.NEVER and (
232+
match := self.cmd_app.statement_parser._command_pattern.search(line)
233+
):
220234
# Group 1 is the command, Group 2 is the character(s) that terminated the command match
221235
command = match.group(1)
222236
cmd_start = match.start(1)
@@ -277,7 +291,7 @@ def get_line(lineno: int) -> list[tuple[str, str]]:
277291
else:
278292
tokens.append(('', text))
279293
elif line:
280-
# No command match found, add the entire line unstyled
294+
# No command match found or colors aren't allowed, add the entire line unstyled
281295
tokens.append(('', line))
282296

283297
return tokens

0 commit comments

Comments
 (0)