Skip to content

Commit 128f050

Browse files
committed
Add register_theme_update_callback function to rich_utils.py
Also: - Moved code for updating lexers when theme is updated to pt_utils.py and this now registers with the above callback - Update unit tests to cover new/modified code
1 parent 55785f5 commit 128f050

4 files changed

Lines changed: 54 additions & 5 deletions

File tree

cmd2/pt_utils.py

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -266,6 +266,15 @@ def clear(self) -> None:
266266
_lexers: "weakref.WeakSet[Cmd2Lexer]" = weakref.WeakSet()
267267

268268

269+
def _update_lexer_colors() -> None:
270+
"""Update colors for all active lexers."""
271+
for lexer in _lexers:
272+
lexer.set_colors()
273+
274+
275+
ru.register_theme_update_callback(_update_lexer_colors)
276+
277+
269278
class Cmd2Lexer(Lexer):
270279
"""Lexer that highlights cmd2 command names, aliases, and macros."""
271280

cmd2/rich_utils.py

Lines changed: 13 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44
import re
55
import sys
66
from collections.abc import (
7+
Callable,
78
Iterator,
89
Mapping,
910
)
@@ -309,6 +310,15 @@ def __cmd2_argparse_help__(self, formatter: Cmd2HelpFormatter) -> Group:
309310
# The application-wide theme. Use get_theme() and set_theme() to access it.
310311
_APP_THEME: Theme | None = None
311312

313+
# Callbacks to be executed when the theme is updated
314+
_theme_update_callbacks: list[Callable[[], None]] = []
315+
316+
317+
def register_theme_update_callback(callback: Callable[[], None]) -> None:
318+
"""Register a callback to be executed when the theme is updated."""
319+
if callback not in _theme_update_callbacks:
320+
_theme_update_callbacks.append(callback)
321+
312322

313323
def get_theme() -> Theme:
314324
"""Get the application-wide theme. Initializes it on the first call."""
@@ -351,11 +361,9 @@ def set_theme(styles: Mapping[str, StyleType] | None = None) -> None:
351361
for name in Cmd2HelpFormatter.styles.keys() & theme.styles.keys():
352362
Cmd2HelpFormatter.styles[name] = theme.styles[name]
353363

354-
# Update colors in active prompt-toolkit lexers
355-
from . import pt_utils
356-
357-
for lexer in pt_utils._lexers:
358-
lexer.set_colors()
364+
# Notify callbacks that the theme has been updated
365+
for callback in _theme_update_callbacks:
366+
callback()
359367

360368

361369
def _create_default_theme() -> Theme:

tests/test_pt_utils.py

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -803,3 +803,12 @@ def test_rich_to_pt_style_nohidden_conceal(self):
803803
style = Style(conceal=False)
804804
pt_style = pt_utils.rich_to_pt_style(style)
805805
assert "nohidden" in pt_style
806+
807+
808+
def test_update_lexer_colors() -> None:
809+
mock_lexer = Mock()
810+
pt_utils._lexers.add(mock_lexer)
811+
812+
pt_utils._update_lexer_colors()
813+
814+
mock_lexer.set_colors.assert_called_once()

tests/test_rich_utils.py

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -349,3 +349,26 @@ def side_effect(color: bool, **kwargs: Any) -> None:
349349
assert mock_set_color.call_count == 2
350350
mock_set_color.assert_any_call(True, file=sys.stdout)
351351
mock_set_color.assert_any_call(True)
352+
353+
354+
def test_register_theme_update_callback() -> None:
355+
# Clear callbacks for a clean state
356+
ru._theme_update_callbacks.clear()
357+
358+
# Define a dummy callback
359+
def my_callback() -> None:
360+
pass
361+
362+
ru.register_theme_update_callback(my_callback)
363+
assert my_callback in ru._theme_update_callbacks
364+
365+
# Test that registering the same callback again doesn't duplicate it
366+
ru.register_theme_update_callback(my_callback)
367+
assert len(ru._theme_update_callbacks) == 1
368+
369+
# Test that set_theme calls the callback
370+
mock_callback = mock.Mock()
371+
ru.register_theme_update_callback(mock_callback)
372+
373+
ru.set_theme()
374+
mock_callback.assert_called_once()

0 commit comments

Comments
 (0)