4b6817381b
Benchmark image — build + push to ECR (any adapter) / build + push (push) Waiting to run
CI / quality (ubuntu-latest) (push) Waiting to run
CI / test (tools-runtime) (push) Waiting to run
CI / test (e2e-general) (push) Waiting to run
CI / test (cli-runtime) (push) Waiting to run
CI / test (e2e-provider-and-openclaw) (push) Waiting to run
CI / test (integrations-and-misc) (push) Waiting to run
CI / coverage-report (push) Blocked by required conditions
CI / test-kubernetes (push) Waiting to run
CI / should-run-thorough (push) Waiting to run
CI / test-thorough (cloudwatch-demo) (push) Blocked by required conditions
CI / test-thorough (flink-ecs) (push) Blocked by required conditions
CI / test-thorough (upstream-lambda) (push) Blocked by required conditions
CI / test-thorough (prefect-ecs-fargate) (push) Blocked by required conditions
CodeQL / Analyze (python) (push) Waiting to run
Release / build-binaries (zip, opensre.exe, onefile, windows-latest, windows-x64) (push) Blocked by required conditions
Release / publish-release (push) Blocked by required conditions
Release / publish-main-release (push) Blocked by required conditions
Release / prepare (push) Waiting to run
Release / verify (push) Blocked by required conditions
Release / build-python-dist (push) Blocked by required conditions
Release / build-binaries (tar.gz, opensre, onedir, macos-15-intel, darwin-x64) (push) Blocked by required conditions
Release / build-binaries (tar.gz, opensre, onedir, macos-latest, darwin-arm64) (push) Blocked by required conditions
Release / build-binaries (tar.gz, opensre, onedir, ubuntu-22.04, linux-x64) (push) Blocked by required conditions
Release / build-binaries (tar.gz, opensre, onedir, ubuntu-22.04-arm, linux-arm64) (push) Blocked by required conditions
Synthetic Deterministic Tests / Synthetic offline (deterministic) (push) Waiting to run
Interactive Shell Live (PR + post-merge) / turn-checks (no-LLM) (push) Waiting to run
Interactive Shell Live (PR + post-merge) / turn-live shard ${{ matrix.shard_index }} (push) Waiting to run
CI (OpenClaw E2E) / openclaw test (push) Has been cancelled
520 lines
15 KiB
Python
520 lines
15 KiB
Python
"""Shared color theme for the OpenSRE CLI.
|
||
|
||
Single source of truth for every colour rendered to the terminal. Eight
|
||
semantic tokens — never introduce new hexes, never use Rich named colours
|
||
(red / yellow / cyan / ...), never embed raw ANSI colour escapes outside
|
||
this module.
|
||
|
||
Token reference
|
||
---------------
|
||
HIGHLIGHT brand name, ❯ prompt, ✓ success, /commands, key findings, live indicator
|
||
BRAND model name, file paths, version numbers, secondary labels
|
||
TEXT all primary body text, step names, values, section headers
|
||
SECONDARY tips, descriptions, muted info, secondary body text
|
||
DIM timestamps, dividers, labels, ruled-out items, dim context
|
||
WARNING warnings only — no auth, fallback store, config issues
|
||
ERROR errors only — missing required config, failures
|
||
BG terminal background, never used as foreground
|
||
INPUT_SURFACE prompt/menu surface background
|
||
|
||
Optional per-theme splash gradient (``CliTheme`` only)
|
||
----------------------------------------------------
|
||
SPLASH_GRADIENT_START left/start colour for splash ASCII art gradients
|
||
SPLASH_GRADIENT_END right/end colour for splash ASCII art gradients
|
||
|
||
When both gradient fields are set, the splash banner interpolates between
|
||
them across each row of ``█`` block characters. Themes without these fields
|
||
continue to use ``HIGHLIGHT`` for splash art.
|
||
|
||
Usage
|
||
-----
|
||
from platform.terminal.theme import HIGHLIGHT, ERROR, DIM
|
||
console.print(f"[{HIGHLIGHT}]✓ success[/]")
|
||
console.print(f"[{ERROR}]✗ failed[/]")
|
||
"""
|
||
|
||
from __future__ import annotations
|
||
|
||
from dataclasses import dataclass
|
||
from typing import SupportsIndex
|
||
|
||
from rich.theme import Theme
|
||
|
||
|
||
@dataclass(frozen=True)
|
||
class CliTheme:
|
||
"""Named palette for interactive shell rendering."""
|
||
|
||
name: str
|
||
HIGHLIGHT: str
|
||
BRAND: str
|
||
TEXT: str
|
||
SECONDARY: str
|
||
DIM: str
|
||
WARNING: str
|
||
ERROR: str
|
||
BG: str
|
||
INPUT_SURFACE: str
|
||
SPLASH_GRADIENT_START: str | None = None
|
||
SPLASH_GRADIENT_END: str | None = None
|
||
|
||
|
||
THEME_REGISTRY: dict[str, CliTheme] = {
|
||
"green": CliTheme(
|
||
name="green",
|
||
HIGHLIGHT="#B9EDAF",
|
||
BRAND="#66A17D",
|
||
TEXT="#E0E0E0",
|
||
SECONDARY="#A6A6A6",
|
||
DIM="#6E6E6E",
|
||
WARNING="#CEA25C",
|
||
ERROR="#C45B52",
|
||
BG="#0A0A0A",
|
||
INPUT_SURFACE="#141414",
|
||
),
|
||
"blue": CliTheme(
|
||
name="blue",
|
||
HIGHLIGHT="#A8D4FF",
|
||
BRAND="#6FA5D8",
|
||
TEXT="#E0E0E0",
|
||
SECONDARY="#A6A6A6",
|
||
DIM="#6E6E6E",
|
||
WARNING="#D8B06F",
|
||
ERROR="#CF6B63",
|
||
BG="#0A0A0A",
|
||
INPUT_SURFACE="#141414",
|
||
),
|
||
"amber": CliTheme(
|
||
name="amber",
|
||
HIGHLIGHT="#F2D48A",
|
||
BRAND="#C99944",
|
||
TEXT="#E0E0E0",
|
||
SECONDARY="#A6A6A6",
|
||
DIM="#6E6E6E",
|
||
WARNING="#E0B466",
|
||
ERROR="#CF6B63",
|
||
BG="#0A0A0A",
|
||
INPUT_SURFACE="#141414",
|
||
),
|
||
"mono": CliTheme(
|
||
name="mono",
|
||
HIGHLIGHT="#C6C6C6",
|
||
BRAND="#A7A7A7",
|
||
TEXT="#E0E0E0",
|
||
SECONDARY="#A6A6A6",
|
||
DIM="#6E6E6E",
|
||
WARNING="#B0B0B0",
|
||
ERROR="#8E8E8E",
|
||
BG="#0A0A0A",
|
||
INPUT_SURFACE="#141414",
|
||
),
|
||
"red": CliTheme(
|
||
name="red",
|
||
HIGHLIGHT="#FF9E8A",
|
||
BRAND="#C45B52",
|
||
TEXT="#E0E0E0",
|
||
SECONDARY="#A6A6A6",
|
||
DIM="#6E6E6E",
|
||
WARNING="#E0B466",
|
||
ERROR="#CF6B63",
|
||
BG="#0A0A0A",
|
||
INPUT_SURFACE="#141414",
|
||
),
|
||
"pink": CliTheme(
|
||
name="pink",
|
||
HIGHLIGHT="#FFB3D9",
|
||
BRAND="#D4729A",
|
||
TEXT="#E0E0E0",
|
||
SECONDARY="#A6A6A6",
|
||
DIM="#6E6E6E",
|
||
WARNING="#E0B466",
|
||
ERROR="#CF6B63",
|
||
BG="#0A0A0A",
|
||
INPUT_SURFACE="#141414",
|
||
),
|
||
"purple": CliTheme(
|
||
name="purple",
|
||
HIGHLIGHT="#C8A8FF",
|
||
BRAND="#9678C0",
|
||
TEXT="#E0E0E0",
|
||
SECONDARY="#A6A6A6",
|
||
DIM="#6E6E6E",
|
||
WARNING="#D8B06F",
|
||
ERROR="#CF6B63",
|
||
BG="#0A0A0A",
|
||
INPUT_SURFACE="#141414",
|
||
),
|
||
"orange": CliTheme(
|
||
name="orange",
|
||
HIGHLIGHT="#FFC08A",
|
||
BRAND="#D4884A",
|
||
TEXT="#E0E0E0",
|
||
SECONDARY="#A6A6A6",
|
||
DIM="#6E6E6E",
|
||
WARNING="#E0B466",
|
||
ERROR="#CF6B63",
|
||
BG="#0A0A0A",
|
||
INPUT_SURFACE="#141414",
|
||
),
|
||
"teal": CliTheme(
|
||
name="teal",
|
||
HIGHLIGHT="#8AE2D6",
|
||
BRAND="#5BA89D",
|
||
TEXT="#E0E0E0",
|
||
SECONDARY="#A6A6A6",
|
||
DIM="#6E6E6E",
|
||
WARNING="#CEA25C",
|
||
ERROR="#C45B52",
|
||
BG="#0A0A0A",
|
||
INPUT_SURFACE="#141414",
|
||
),
|
||
"lime": CliTheme(
|
||
name="lime",
|
||
HIGHLIGHT="#D4FF7A",
|
||
BRAND="#94C845",
|
||
TEXT="#E0E0E0",
|
||
SECONDARY="#A6A6A6",
|
||
DIM="#6E6E6E",
|
||
WARNING="#CEA25C",
|
||
ERROR="#C45B52",
|
||
BG="#0A0A0A",
|
||
INPUT_SURFACE="#141414",
|
||
),
|
||
"nord": CliTheme(
|
||
name="nord",
|
||
HIGHLIGHT="#88C0D0",
|
||
BRAND="#81A1C1",
|
||
TEXT="#E5E9F0",
|
||
SECONDARY="#ACB5C2",
|
||
DIM="#757D8C",
|
||
WARNING="#EBCB8B",
|
||
ERROR="#BF616A",
|
||
BG="#2E3440",
|
||
INPUT_SURFACE="#3B4252",
|
||
),
|
||
"dracula": CliTheme(
|
||
name="dracula",
|
||
HIGHLIGHT="#BD93F9",
|
||
BRAND="#8BE9FD",
|
||
TEXT="#F8F8F2",
|
||
SECONDARY="#B4B7C5",
|
||
DIM="#6272A4",
|
||
WARNING="#F1FA8C",
|
||
ERROR="#FF5555",
|
||
BG="#282A36",
|
||
INPUT_SURFACE="#303443",
|
||
),
|
||
"solarized": CliTheme(
|
||
name="solarized",
|
||
HIGHLIGHT="#2AA198",
|
||
BRAND="#268BD2",
|
||
TEXT="#EEE8D5",
|
||
SECONDARY="#99A7A7",
|
||
DIM="#5F747B",
|
||
WARNING="#B58900",
|
||
ERROR="#DC322F",
|
||
BG="#002B36",
|
||
INPUT_SURFACE="#073642",
|
||
),
|
||
"gruvbox": CliTheme(
|
||
name="gruvbox",
|
||
HIGHLIGHT="#FABD2F",
|
||
BRAND="#83A598",
|
||
TEXT="#EBDBB2",
|
||
SECONDARY="#B2A492",
|
||
DIM="#787069",
|
||
WARNING="#FE8019",
|
||
ERROR="#FB4934",
|
||
BG="#282828",
|
||
INPUT_SURFACE="#32302F",
|
||
),
|
||
"webflux": CliTheme(
|
||
name="webflux",
|
||
HIGHLIGHT="#E23636",
|
||
BRAND="#2B63F5",
|
||
TEXT="#EAF0FF",
|
||
SECONDARY="#9CA8C6",
|
||
DIM="#566282",
|
||
WARNING="#FFC857",
|
||
ERROR="#FF4D4D",
|
||
BG="#0D1220",
|
||
INPUT_SURFACE="#151D33",
|
||
SPLASH_GRADIENT_START="#E23636",
|
||
SPLASH_GRADIENT_END="#2B63F5",
|
||
),
|
||
"sunset": CliTheme(
|
||
name="sunset",
|
||
HIGHLIGHT="#FFB067",
|
||
BRAND="#FF6FA8",
|
||
TEXT="#FFE8D5",
|
||
SECONDARY="#C8A79B",
|
||
DIM="#7B605C",
|
||
WARNING="#FFD166",
|
||
ERROR="#FF5A5F",
|
||
BG="#22151A",
|
||
INPUT_SURFACE="#2B1C24",
|
||
SPLASH_GRADIENT_START="#FFB067",
|
||
SPLASH_GRADIENT_END="#FF6FA8",
|
||
),
|
||
}
|
||
|
||
DEFAULT_THEME_NAME = "blue"
|
||
|
||
|
||
def _fg(rgb: tuple[int, int, int]) -> str:
|
||
return f"\x1b[38;2;{rgb[0]};{rgb[1]};{rgb[2]}m"
|
||
|
||
|
||
def _parse_hex_color(value: str) -> tuple[int, int, int]:
|
||
stripped = value.lstrip("#")
|
||
return (int(stripped[0:2], 16), int(stripped[2:4], 16), int(stripped[4:6], 16))
|
||
|
||
|
||
class _LazyRichStyle(str):
|
||
"""Rich markup colour token that tracks :func:`set_active_theme`.
|
||
|
||
Importers can bind ``HIGHLIGHT`` (etc.) at module load; ``str()`` and
|
||
``f"[{HIGHLIGHT}]"`` resolve against the active palette at render time.
|
||
"""
|
||
|
||
__slots__ = ("_field", "_bold")
|
||
|
||
def __new__(cls, field: str, *, bold: bool = False) -> _LazyRichStyle:
|
||
instance = str.__new__(cls, "")
|
||
object.__setattr__(instance, "_field", field)
|
||
object.__setattr__(instance, "_bold", bold)
|
||
return instance
|
||
|
||
def _resolve(self) -> str:
|
||
field = object.__getattribute__(self, "_field")
|
||
bold = object.__getattribute__(self, "_bold")
|
||
value = getattr(_ACTIVE_THEME, field)
|
||
return f"bold {value}" if bold else value
|
||
|
||
def __str__(self) -> str:
|
||
return self._resolve()
|
||
|
||
def __format__(self, format_spec: str) -> str:
|
||
return format(self._resolve(), format_spec)
|
||
|
||
def __bool__(self) -> bool:
|
||
return bool(self._resolve())
|
||
|
||
# Hash/compare as the resolved style string. The underlying str value is
|
||
# "" for every token, so without these overrides all tokens collide on
|
||
# the same key in caches keyed by style strings — Rich's lru_cached
|
||
# ``Style.parse`` then renders every ``style=TOKEN`` usage with whichever
|
||
# token happened to be parsed first.
|
||
def __eq__(self, other: object) -> bool:
|
||
return self._resolve() == other
|
||
|
||
def __ne__(self, other: object) -> bool:
|
||
return self._resolve() != other
|
||
|
||
def __hash__(self) -> int:
|
||
return hash(self._resolve())
|
||
|
||
def lstrip(self, chars: str | None = None) -> str:
|
||
resolved = self._resolve()
|
||
return resolved.lstrip() if chars is None else resolved.lstrip(chars)
|
||
|
||
def rstrip(self, chars: str | None = None) -> str:
|
||
resolved = self._resolve()
|
||
return resolved.rstrip() if chars is None else resolved.rstrip(chars)
|
||
|
||
def strip(self, chars: str | None = None) -> str:
|
||
resolved = self._resolve()
|
||
return resolved.strip() if chars is None else resolved.strip(chars)
|
||
|
||
def split(self, sep: str | None = None, maxsplit: SupportsIndex = -1) -> list[str]:
|
||
resolved = self._resolve()
|
||
return resolved.split(sep, maxsplit)
|
||
|
||
def rsplit(self, sep: str | None = None, maxsplit: SupportsIndex = -1) -> list[str]:
|
||
resolved = self._resolve()
|
||
return resolved.rsplit(sep, maxsplit)
|
||
|
||
|
||
def _resolve_theme_name(name: str | None) -> str:
|
||
normalized = (name or DEFAULT_THEME_NAME).strip().lower()
|
||
return normalized if normalized in THEME_REGISTRY else DEFAULT_THEME_NAME
|
||
|
||
|
||
def get_theme(theme_name: str | None) -> CliTheme:
|
||
"""Return a registered palette by name; fall back to default."""
|
||
return THEME_REGISTRY[_resolve_theme_name(theme_name)]
|
||
|
||
|
||
def list_theme_names() -> tuple[str, ...]:
|
||
"""Return available theme names in display order."""
|
||
return tuple(THEME_REGISTRY.keys())
|
||
|
||
|
||
def get_active_theme() -> CliTheme:
|
||
"""Return the currently active palette."""
|
||
return _ACTIVE_THEME
|
||
|
||
|
||
def get_active_theme_name() -> str:
|
||
"""Return the currently active palette name."""
|
||
return _ACTIVE_THEME.name
|
||
|
||
|
||
def _apply_theme(theme: CliTheme) -> None:
|
||
global HIGHLIGHT_ANSI, BRAND_ANSI, TEXT_ANSI, SECONDARY_ANSI, DIM_ANSI, BOLD_BRAND_ANSI
|
||
global PROMPT_ACCENT_ANSI, PROMPT_FRAME_ANSI, DIM_COUNTER_ANSI, SURFACE_BG_ANSI
|
||
global INPUT_SURFACE_BG_ANSI, MENU_SELECTION_ROW_ANSI, MARKDOWN_THEME
|
||
global DEVICE_CODE_ANSI
|
||
|
||
_highlight_rgb = _parse_hex_color(theme.HIGHLIGHT)
|
||
_brand_rgb = _parse_hex_color(theme.BRAND)
|
||
_text_rgb = _parse_hex_color(theme.TEXT)
|
||
_secondary_rgb = _parse_hex_color(theme.SECONDARY)
|
||
_dim_rgb = _parse_hex_color(theme.DIM)
|
||
_bg_rgb = _parse_hex_color(theme.BG)
|
||
_input_surface_rgb = _parse_hex_color(theme.INPUT_SURFACE)
|
||
|
||
HIGHLIGHT_ANSI = _fg(_highlight_rgb)
|
||
BRAND_ANSI = _fg(_brand_rgb)
|
||
TEXT_ANSI = _fg(_text_rgb)
|
||
SECONDARY_ANSI = _fg(_secondary_rgb)
|
||
DIM_ANSI = _fg(_dim_rgb)
|
||
BOLD_BRAND_ANSI = f"\x1b[1m{BRAND_ANSI}"
|
||
|
||
PROMPT_ACCENT_ANSI = f"\x1b[1;38;2;{_highlight_rgb[0]};{_highlight_rgb[1]};{_highlight_rgb[2]}m"
|
||
PROMPT_FRAME_ANSI = PROMPT_ACCENT_ANSI
|
||
DEVICE_CODE_ANSI = PROMPT_ACCENT_ANSI
|
||
DIM_COUNTER_ANSI = DIM_ANSI
|
||
SURFACE_BG_ANSI = f"\x1b[48;2;{_bg_rgb[0]};{_bg_rgb[1]};{_bg_rgb[2]}m"
|
||
INPUT_SURFACE_BG_ANSI = (
|
||
f"\x1b[48;2;{_input_surface_rgb[0]};{_input_surface_rgb[1]};{_input_surface_rgb[2]}m"
|
||
)
|
||
MENU_SELECTION_ROW_ANSI = f"{INPUT_SURFACE_BG_ANSI}\x1b[1m{HIGHLIGHT_ANSI}"
|
||
|
||
MARKDOWN_THEME = Theme(
|
||
{
|
||
"markdown.code": f"bold {theme.HIGHLIGHT}",
|
||
"markdown.code_block": theme.TEXT,
|
||
"markdown.h1": f"bold {theme.HIGHLIGHT}",
|
||
"markdown.h2": f"bold {theme.BRAND}",
|
||
"markdown.h3": f"bold {theme.BRAND}",
|
||
}
|
||
)
|
||
|
||
|
||
def set_active_theme(theme_name: str | None) -> CliTheme:
|
||
"""Activate a palette and refresh all derived style constants."""
|
||
global _ACTIVE_THEME
|
||
_ACTIVE_THEME = get_theme(theme_name)
|
||
_apply_theme(_ACTIVE_THEME)
|
||
return _ACTIVE_THEME
|
||
|
||
|
||
# ── Semantic color tokens (the only permitted colours) ─────────────────────
|
||
_ACTIVE_THEME = get_theme(DEFAULT_THEME_NAME)
|
||
|
||
HIGHLIGHT = _LazyRichStyle("HIGHLIGHT")
|
||
BRAND = _LazyRichStyle("BRAND")
|
||
TEXT = _LazyRichStyle("TEXT")
|
||
SECONDARY = _LazyRichStyle("SECONDARY")
|
||
DIM = _LazyRichStyle("DIM")
|
||
WARNING = _LazyRichStyle("WARNING")
|
||
ERROR = _LazyRichStyle("ERROR")
|
||
BG = _LazyRichStyle("BG")
|
||
INPUT_SURFACE = _LazyRichStyle("INPUT_SURFACE")
|
||
|
||
# ── Rich style shorthands (bold variants of the semantic tokens) ──────────
|
||
|
||
BOLD_HIGHLIGHT = _LazyRichStyle("HIGHLIGHT", bold=True)
|
||
BOLD_BRAND = _LazyRichStyle("BRAND", bold=True)
|
||
BOLD_TEXT = _LazyRichStyle("TEXT", bold=True)
|
||
BOLD_WARNING = _LazyRichStyle("WARNING", bold=True)
|
||
BOLD_ERROR = _LazyRichStyle("ERROR", bold=True)
|
||
|
||
# GitHub/device-flow one-time codes should be easy to spot and transcribe.
|
||
DEVICE_CODE = BOLD_HIGHLIGHT
|
||
|
||
# Distinct accent for incoming alerts (visually distinct from BOLD_BRAND used for assistant)
|
||
INCOMING_ALERT_ACCENT = BOLD_WARNING
|
||
|
||
__all__ = [
|
||
"ANSI_BOLD",
|
||
"ANSI_DIM",
|
||
"ANSI_RESET",
|
||
"BG",
|
||
"BOLD_BRAND",
|
||
"BOLD_BRAND_ANSI",
|
||
"BOLD_ERROR",
|
||
"BOLD_HIGHLIGHT",
|
||
"BOLD_TEXT",
|
||
"BOLD_WARNING",
|
||
"BRAND",
|
||
"BRAND_ANSI",
|
||
"DEVICE_CODE",
|
||
"DEVICE_CODE_ANSI",
|
||
"DIM",
|
||
"DIM_ANSI",
|
||
"DIM_COUNTER_ANSI",
|
||
"ERROR",
|
||
"GLYPH_ACTIVE",
|
||
"GLYPH_BULLET",
|
||
"GLYPH_ERROR",
|
||
"GLYPH_PROMPT",
|
||
"GLYPH_SUCCESS",
|
||
"GLYPH_WARNING",
|
||
"HIGHLIGHT",
|
||
"HIGHLIGHT_ANSI",
|
||
"INCOMING_ALERT_ACCENT",
|
||
"INPUT_SURFACE",
|
||
"INPUT_SURFACE_BG_ANSI",
|
||
"MARKDOWN_THEME",
|
||
"MENU_SELECTION_ROW_ANSI",
|
||
"PROMPT_ACCENT_ANSI",
|
||
"PROMPT_FRAME_ANSI",
|
||
"SECONDARY",
|
||
"SECONDARY_ANSI",
|
||
"SURFACE_BG_ANSI",
|
||
"TEXT",
|
||
"TEXT_ANSI",
|
||
"WARNING",
|
||
]
|
||
|
||
# ── Semantic glyphs ────────────────────────────────────────────────────────
|
||
|
||
GLYPH_SUCCESS = "✓"
|
||
GLYPH_WARNING = "⚠"
|
||
GLYPH_ERROR = "✗"
|
||
GLYPH_PROMPT = "◆"
|
||
GLYPH_ACTIVE = "◉"
|
||
GLYPH_BULLET = "·"
|
||
|
||
# ── ANSI escape sequences for prompt_toolkit (bypasses Rich markup) ────────
|
||
# This module is the only place in the codebase where raw ANSI escapes are
|
||
# permitted. Every truecolour value below corresponds to one of the eight
|
||
# semantic tokens above.
|
||
|
||
# Placeholders — populated by :func:`set_active_theme` (ANSI + Markdown only).
|
||
HIGHLIGHT_ANSI = ""
|
||
BRAND_ANSI = ""
|
||
TEXT_ANSI = ""
|
||
SECONDARY_ANSI = ""
|
||
DIM_ANSI = ""
|
||
BOLD_BRAND_ANSI = ""
|
||
DEVICE_CODE_ANSI = ""
|
||
|
||
ANSI_RESET = "\x1b[0m"
|
||
ANSI_BOLD = "\x1b[1m"
|
||
ANSI_DIM = "\x1b[2m"
|
||
|
||
PROMPT_ACCENT_ANSI = ""
|
||
PROMPT_FRAME_ANSI = ""
|
||
DIM_COUNTER_ANSI = ""
|
||
SURFACE_BG_ANSI = ""
|
||
INPUT_SURFACE_BG_ANSI = ""
|
||
MENU_SELECTION_ROW_ANSI = ""
|
||
|
||
MARKDOWN_THEME = Theme({})
|
||
|
||
# Ensure ANSI/Markdown derived constants match the default active theme.
|
||
set_active_theme(DEFAULT_THEME_NAME)
|