Skip to content

cmd2.theme

cmd2.theme

Provides a centralized theming system for cmd2.

This module manages the global theme used for both Rich terminal output and prompt-toolkit interactive components. It ensures that styling is consistent and synchronized across the entire application when the theme is updated using the following strategy.

  1. Rich consoles use a persistent Theme object that is updated in-place.
  2. prompt-toolkit integration in cmd2 uses a DynamicStyle wrapper around a callable that returns the current prompt-toolkit theme.

To prevent Rich's built-in styles (like 'bold', or 'italic') from polluting the prompt-toolkit namespace or colliding with its own internal names, only styles starting with registered prefixes (e.g., 'cmd2.') or those explicitly mapped to UI elements are synchronized to the prompt-toolkit theme.

get_theme

get_theme()

Get the application-wide Rich theme. Initializes it on the first call.

Source code in cmd2/theme.py
def get_theme() -> Theme:
    """Get the application-wide Rich theme. Initializes it on the first call."""
    if _THEME is None:
        reset_theme()
    return cast(Theme, _THEME)

get_pt_theme

get_pt_theme()

Get the application-wide prompt-toolkit style. Initializes it on the first call.

Source code in cmd2/theme.py
def get_pt_theme() -> PtStyle:
    """Get the application-wide prompt-toolkit style. Initializes it on the first call."""
    if _PT_THEME is None:
        reset_theme()
    return cast(PtStyle, _PT_THEME)

reset_theme

reset_theme()

Reset the application-wide theme to its initial state.

This function performs an in-place reset of the existing Rich theme's styles. This ensures that any Console objects already using the theme will reflect the changes immediately without needing to be recreated.

Changes are automatically propagated to all synchronized components.

Source code in cmd2/theme.py
def reset_theme() -> None:
    """Reset the application-wide theme to its initial state.

    This function performs an in-place reset of the existing Rich theme's
    styles. This ensures that any Console objects already using the theme
    will reflect the changes immediately without needing to be recreated.

    Changes are automatically propagated to all synchronized components.
    """
    global _THEME  # noqa: PLW0603

    # Include default styles from cmd2, rich-argparse, and Rich.
    styles = DEFAULT_CMD2_STYLES.copy()
    styles.update(DEFAULT_ARGPARSE_STYLES)
    default_theme = Theme(styles, inherit=True)

    if _THEME is None:
        # Initial assignment
        _THEME = default_theme
    else:
        # Perform in-place reset to preserve existing references
        _THEME.styles.clear()
        _THEME.styles.update(default_theme.styles)

    _sync_all()

update_theme

update_theme(styles)

Update the existing theme.

This function performs an in-place update of the existing Rich theme's styles. This ensures that any Console objects already using the theme will reflect the changes immediately without needing to be recreated.

Changes are automatically propagated to all synchronized components.

PARAMETER DESCRIPTION
styles

mapping of style names to styles

TYPE: Mapping[str, StyleType]

Source code in cmd2/theme.py
def update_theme(styles: Mapping[str, StyleType]) -> None:
    """Update the existing theme.

    This function performs an in-place update of the existing Rich theme's
    styles. This ensures that any Console objects already using the theme
    will reflect the changes immediately without needing to be recreated.

    Changes are automatically propagated to all synchronized components.

    :param styles: mapping of style names to styles
    """
    # Convert any string styles to Style objects
    parsed_styles = {name: style if isinstance(style, Style) else Style.parse(style) for name, style in styles.items()}

    # Perform in-place update to preserve existing references
    get_theme().styles.update(parsed_styles)

    _sync_all()

register_pt_mapping

register_pt_mapping(style_name, pt_ui_names)

Map a Rich theme style name to one or more prompt-toolkit UI components.

This enables styling of prompt-toolkit's internal elements (such as the completion menu) using styles in the application's Rich theme.

Registering a mapping also flags the style for synchronization to the prompt-toolkit theme, making it accessible via 'class:style_name'.

PARAMETER DESCRIPTION
style_name

The style name used in the Rich theme.

TYPE: str

pt_ui_names

One or more prompt-toolkit UI component names (e.g., 'completion-menu').

TYPE: str | Iterable[str]

Source code in cmd2/theme.py
def register_pt_mapping(style_name: str, pt_ui_names: str | Iterable[str]) -> None:
    """Map a Rich theme style name to one or more prompt-toolkit UI components.

    This enables styling of prompt-toolkit's internal elements (such as the
    completion menu) using styles in the application's Rich theme.

    Registering a mapping also flags the style for synchronization to the
    prompt-toolkit theme, making it accessible via 'class:style_name'.

    :param style_name: The style name used in the Rich theme.
    :param pt_ui_names: One or more prompt-toolkit UI component names (e.g., 'completion-menu').
    """
    if isinstance(pt_ui_names, str):
        pt_ui_names = [pt_ui_names]

    # Register the style in the map.
    if style_name not in _PT_UI_MAP:
        _PT_UI_MAP[style_name] = set()
        changed = True
    else:
        changed = False

    # Add UI mappings, excluding 'style_name' which the sync handles by default.
    original_size = len(_PT_UI_MAP[style_name])
    _PT_UI_MAP[style_name].update(n for n in pt_ui_names if n != style_name)

    if len(_PT_UI_MAP[style_name]) != original_size:
        changed = True

    # Trigger a re-sync if the theme is already initialized
    if changed and _PT_THEME is not None:
        _sync_pt_theme()

register_synchronized_style

register_synchronized_style(style_name)

Register a Rich theme style for synchronization with prompt-toolkit.

This ensures that the style is synchronized to the prompt-toolkit theme (accessible via 'class:style_name') even if it does not begin with a registered prefix.

PARAMETER DESCRIPTION
style_name

The style name used in the Rich theme.

TYPE: str

Source code in cmd2/theme.py
def register_synchronized_style(style_name: str) -> None:
    """Register a Rich theme style for synchronization with prompt-toolkit.

    This ensures that the style is synchronized to the prompt-toolkit theme
    (accessible via 'class:style_name') even if it does not begin with a
    registered prefix.

    :param style_name: The style name used in the Rich theme.
    """
    register_pt_mapping(style_name, [])

unregister_pt_mapping

unregister_pt_mapping(style_name, pt_ui_names)

Remove one or more prompt-toolkit UI component mappings.

The style itself remains in the synchronization mapping (even if no UI component mappings remain), ensuring it continues to be synchronized to the prompt-toolkit theme.

To completely remove a style from synchronization, use unregister_synchronized_style().

PARAMETER DESCRIPTION
style_name

The style name used in the Rich theme.

TYPE: str

pt_ui_names

Specific UI component(s) to unmap.

TYPE: str | Iterable[str]

Source code in cmd2/theme.py
def unregister_pt_mapping(style_name: str, pt_ui_names: str | Iterable[str]) -> None:
    """Remove one or more prompt-toolkit UI component mappings.

    The style itself remains in the synchronization mapping (even if no
    UI component mappings remain), ensuring it continues to be synchronized
    to the prompt-toolkit theme.

    To completely remove a style from synchronization, use
    unregister_synchronized_style().

    :param style_name: The style name used in the Rich theme.
    :param pt_ui_names: Specific UI component(s) to unmap.
    """
    if style_name not in _PT_UI_MAP:
        return

    if isinstance(pt_ui_names, str):
        pt_ui_names = [pt_ui_names]

    original_size = len(_PT_UI_MAP[style_name])
    for name in pt_ui_names:
        _PT_UI_MAP[style_name].discard(name)

    changed = len(_PT_UI_MAP[style_name]) != original_size

    # Trigger a re-sync if the theme is already initialized
    if changed and _PT_THEME is not None:
        _sync_pt_theme()

unregister_synchronized_style

unregister_synchronized_style(style_name)

Stop synchronizing a Rich theme style with prompt-toolkit.

This removes the style and all its mappings entirely from the prompt-toolkit theme synchronization.

PARAMETER DESCRIPTION
style_name

The style name to unregister.

TYPE: str

Source code in cmd2/theme.py
def unregister_synchronized_style(style_name: str) -> None:
    """Stop synchronizing a Rich theme style with prompt-toolkit.

    This removes the style and all its mappings entirely from the
    prompt-toolkit theme synchronization.

    :param style_name: The style name to unregister.
    """
    if style_name in _PT_UI_MAP:
        del _PT_UI_MAP[style_name]

        # Trigger a re-sync if the theme is already initialized
        if _PT_THEME is not None:
            _sync_pt_theme()

register_synchronized_prefix

register_synchronized_prefix(prefix)

Register a prefix whose styles will be synchronized to the prompt-toolkit theme.

The prefix must include any desired delimiters (e.g., 'myapp.' or 'plugin-').

PARAMETER DESCRIPTION
prefix

The prefix string. Must be at least 1 character.

TYPE: str

RAISES DESCRIPTION
ValueError

If the prefix is empty.

Source code in cmd2/theme.py
def register_synchronized_prefix(prefix: str) -> None:
    """Register a prefix whose styles will be synchronized to the prompt-toolkit theme.

    The prefix must include any desired delimiters (e.g., 'myapp.' or 'plugin-').

    :param prefix: The prefix string. Must be at least 1 character.
    :raises ValueError: If the prefix is empty.
    """
    if not prefix:
        raise ValueError("Prefix cannot be empty.")

    if prefix not in _SYNCHRONIZED_PREFIXES:
        _SYNCHRONIZED_PREFIXES.add(prefix)

        # Trigger a re-sync if the theme is already initialized
        if _PT_THEME is not None:
            _sync_pt_theme()

unregister_synchronized_prefix

unregister_synchronized_prefix(prefix)

Stop synchronizing styles starting with the given prefix.

PARAMETER DESCRIPTION
prefix

The prefix string to remove.

TYPE: str

Source code in cmd2/theme.py
def unregister_synchronized_prefix(prefix: str) -> None:
    """Stop synchronizing styles starting with the given prefix.

    :param prefix: The prefix string to remove.
    """
    if prefix in _SYNCHRONIZED_PREFIXES:
        _SYNCHRONIZED_PREFIXES.remove(prefix)

        # Trigger a re-sync if the theme is already initialized
        if _PT_THEME is not None:
            _sync_pt_theme()