Skip to content

Commit ae78cb4

Browse files
committed
Lexer colors now change if a user changes the theme during runtime
Since prommpt-toolkit calls the lex_document method of the Cmd2Lexer instance quite frequnetly, we don't want to dynamically fetech the colors to use on every call. Instead I extracted the code for retrieving the lexer colors from the rich theme into a set_colors helper method and the set_theme method will call this for any Cmd2Lexer instances.
1 parent d580970 commit ae78cb4

3 files changed

Lines changed: 43 additions & 0 deletions

File tree

cmd2/pt_utils.py

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
"""Utilities for integrating prompt_toolkit with cmd2."""
22

33
import re
4+
import weakref
45
from collections.abc import (
56
Callable,
67
Iterable,
@@ -254,6 +255,9 @@ def clear(self) -> None:
254255
self._loaded_strings.clear()
255256

256257

258+
_lexers: "weakref.WeakSet[Cmd2Lexer]" = weakref.WeakSet()
259+
260+
257261
class Cmd2Lexer(Lexer):
258262
"""Lexer that highlights cmd2 command names, aliases, and macros."""
259263

@@ -268,6 +272,11 @@ def __init__(
268272
super().__init__()
269273
self.cmd_app = cmd_app
270274

275+
_lexers.add(self)
276+
self.set_colors()
277+
278+
def set_colors(self) -> None:
279+
"""Update colors from the current rich theme."""
271280
# Retrieve styles dynamically from the current theme
272281
theme = ru.get_theme()
273282
self.command_color = rich_to_pt_style(theme.styles.get(Cmd2Style.LEXER_COMMAND, ""))

cmd2/rich_utils.py

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -351,6 +351,15 @@ def set_theme(styles: Mapping[str, StyleType] | None = None) -> None:
351351
for name in Cmd2HelpFormatter.styles.keys() & theme.styles.keys():
352352
Cmd2HelpFormatter.styles[name] = theme.styles[name]
353353

354+
# Update colors in active prompt-toolkit lexers
355+
try:
356+
from . import pt_utils
357+
358+
for lexer in pt_utils._lexers:
359+
lexer.set_colors()
360+
except ImportError:
361+
pass
362+
354363

355364
def _create_default_theme() -> Theme:
356365
"""Create a default theme for the application.

tests/test_pt_utils.py

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -278,6 +278,31 @@ def test_lex_document_multiline(self, mock_cmd_app):
278278
tokens1 = get_line(1)
279279
assert tokens1 == [("noreverse fg:ansiyellow bg:default", "help")]
280280

281+
def test_lexer_set_theme_runtime_update(self, mock_cmd_app):
282+
"""Test that changing the theme updates active lexers."""
283+
lexer = pt_utils.Cmd2Lexer(cast(Any, mock_cmd_app))
284+
285+
# Get the old color for command
286+
old_color = lexer.command_color
287+
288+
# Change the theme dynamically
289+
from rich.style import Style
290+
291+
from cmd2.styles import Cmd2Style
292+
293+
new_styles = {Cmd2Style.LEXER_COMMAND: Style(color="red", bgcolor="black")}
294+
295+
try:
296+
ru.set_theme(new_styles)
297+
298+
# Now verify the lexer's color was updated
299+
assert lexer.command_color != old_color
300+
assert "ansired" in lexer.command_color
301+
assert "ansiblack" in lexer.command_color
302+
303+
finally:
304+
ru.set_theme() # Reset to default
305+
281306

282307
class TestCmd2Completer:
283308
def test_get_completions(self, mock_cmd_app: MockCmd, monkeypatch) -> None:

0 commit comments

Comments
 (0)