from typing import Any, Dict, List, Union from rich.console import Console, RenderableType from rich.theme import Theme from .styles.base import BaseStyle from .input import Input from .menu import Menu, Option, ReturnValue from .progress import Progress class RichToolkitTheme: def __init__(self, style: BaseStyle, theme: Dict[str, str]) -> None: self.style = style self.rich_theme = Theme(theme) class RichToolkit: def __init__( self, theme: RichToolkitTheme, handle_keyboard_interrupts: bool = True, ) -> None: self.console = Console(theme=theme.rich_theme) self.theme = theme self.handle_keyboard_interrupts = handle_keyboard_interrupts def __enter__(self): self.console.print() return self def __exit__( self, exc_type: Any, exc_value: Any, traceback: Any ) -> Union[bool, None]: if self.handle_keyboard_interrupts and exc_type is KeyboardInterrupt: # we want to handle keyboard interrupts gracefully, instead of showing a traceback # or any other error message return True self.console.print() def print_title(self, title: str, **metadata: Any) -> None: self.console.print( self.theme.style.with_decoration(title, title=True, **metadata) ) def print(self, *renderables: RenderableType, **metadata: Any) -> None: self.console.print(self.theme.style.with_decoration(*renderables, **metadata)) def print_as_string(self, *renderables: RenderableType, **metadata: Any) -> str: with self.console.capture() as capture: self.print(*renderables, **metadata) return capture.get().rstrip() def print_line(self) -> None: self.console.print(self.theme.style.empty_line()) def confirm(self, title: str, **metadata: Any) -> bool: return self.ask( title=title, options=[ Option({"value": True, "name": "Yes"}), Option({"value": False, "name": "No"}), ], inline=True, **metadata, ) def ask( self, title: str, options: List[Option[ReturnValue]], inline: bool = False, allow_filtering: bool = False, **metadata: Any, ) -> ReturnValue: return Menu( title=title, options=options, console=self.console, style=self.theme.style, inline=inline, allow_filtering=allow_filtering, cursor_offset=self.theme.style.cursor_offset, **metadata, ).ask() def input( self, title: str, default: str = "", password: bool = False, **metadata: Any ) -> str: return Input( console=self.console, style=self.theme.style, title=title, default=default, cursor_offset=self.theme.style.cursor_offset, password=password, **metadata, ).ask() def progress( self, title: str, transient: bool = False, transient_on_error: bool = False ) -> Progress: return Progress( title=title, console=self.console, style=self.theme.style, transient=transient, transient_on_error=transient_on_error, )