From 08b9af9b3de97d5ac241b447335883c5f581d503 Mon Sep 17 00:00:00 2001 From: Joscha Date: Thu, 20 Jun 2019 19:49:44 +0000 Subject: [PATCH] Add euph-specific config --- cheuph/euphoria/__init__.py | 8 +++ cheuph/euphoria/euph_config.py | 124 +++++++++++++++++++++++++++++++++ 2 files changed, 132 insertions(+) create mode 100644 cheuph/euphoria/euph_config.py diff --git a/cheuph/euphoria/__init__.py b/cheuph/euphoria/__init__.py index d50e793..ec3bba2 100644 --- a/cheuph/euphoria/__init__.py +++ b/cheuph/euphoria/__init__.py @@ -1,9 +1,17 @@ from typing import List from .edit_widgets import * +from .euph_config import * from .euph_renderer import * +from .room_widget import * +from .single_room_application import * +from .user_list_widget import * __all__: List[str] = [] __all__ += edit_widgets.__all__ +__all__ += euph_config.__all__ __all__ += euph_renderer.__all__ +__all__ += room_widget.__all__ +__all__ += single_room_application.__all__ +__all__ += user_list_widget.__all__ diff --git a/cheuph/euphoria/euph_config.py b/cheuph/euphoria/euph_config.py new file mode 100644 index 0000000..6d942b4 --- /dev/null +++ b/cheuph/euphoria/euph_config.py @@ -0,0 +1,124 @@ +from typing import Any, Dict, List, Optional, TypeVar + +from ..config import (ConfigValueException, Kind, Option, TransparentConfig, + TreeLoader) + +__all__ = ["EuphConfig", "EuphLoader"] + +class EuphConfig(TransparentConfig): + + def __init__(self, parent: Optional[TransparentConfig] = None) -> None: + super().__init__(parent) + + @property + def room_style(self) -> str: + return self["visual.room_style"] + + @property + def error_style(self) -> str: + return self["visual.error.style"] + + @property + def error_room_style(self) -> str: + return self["visual.error.room_style"] + + @property + def palette(self) -> Any: + return self["palette"] + +class EuphLoader(TreeLoader): + + STYLE_PROPERTIES = [ + "visual.room_style", + "visual.error.style", + "visual.error.room_style", + ] + + DEFAULT_STYLES = { + "room": {"fg": "bold, light blue"}, + "error": {"fg": "light red"}, + "error_room": {"fg": "bold, yellow"}, + } + + def __init__(self) -> None: + super().__init__() + + self.add_option("visual.room_style", Option(Kind.STR, "room")) + self.add_option("visual.error.style", Option(Kind.STR, "error")) + self.add_option("visual.error.room_style", Option(Kind.STR, "error_room")) + self.add_option("styles", Option(Kind.DICT, self.DEFAULT_STYLES)) + + def load_to(self, config: TransparentConfig, data: Any) -> None: + super().load_to(config, data) + + styles = self._get_styles(config) + self._check_style_properties(config, styles) + config["palette"] = self._load_palette(styles) + + def _get_styles(self, config: TransparentConfig) -> Dict[str, Dict[str, str]]: + # First, collect all the styles from front to back + style_list = [] + current_config = config + while current_config is not None: + try: + style_list.append(current_config.get("styles")) + except ConfigValueException: + pass + + current_config = current_config.parent + + # Then, mush them together in reverse order + styles: Dict[str, Dict[str, str]] = {} + for style in reversed(style_list): + if type(style) is not dict: + raise ConfigValueException("invalid styles format") + + for name, info in style.items(): + if type(name) is not str: + raise ConfigValueException( + f"style {name!r} has to be named with a string") + + if info is None: + styles[name] = {} + continue + + if type(info) is not dict: + raise ConfigValueException( + f"style {name!r} has an incorrect value") + + for key, value in info.items(): + if type(key) is not str or type(value) is not str: + raise ConfigValueException( + f"style {name!r} has an incorrect value") + + styles[name] = info + + return styles + + def _load_palette(self, styles: Dict[str, Dict[str, str]]) -> List[Any]: + palette: List[Any] = [] + + for style, info in styles.items(): + keys = set(info.keys()) + + if keys == {"alias"}: + palette.append((style, info["alias"])) + elif keys.issubset({"fg", "bg"}): + fg = info.get("fg", "") + bg = info.get("bg", "") + palette.append((style, fg, bg)) + else: + raise ConfigValueException(f"style {style} has an incorrect format") + + return palette + + def _check_style_properties(self, + config: TransparentConfig, + styles: Dict[str, Dict[str, str]], + ) -> None: + + for name in self.STYLE_PROPERTIES: + style_name = config.get(name) + if style_name not in styles: + raise ConfigValueException((f"style {style_name!r} is not" + " specified in the styles section"))