From dc855e1b01e9b4526927b8bd69daca733afd97c2 Mon Sep 17 00:00:00 2001 From: 2 * r + 2 * t <61896496+soramanew@users.noreply.github.com> Date: Wed, 11 Jun 2025 17:37:04 +1000 Subject: internal: refactor scheme Also use a single file to store scheme data --- src/caelestia/data.py | 120 ----------------------- src/caelestia/parser.py | 2 +- src/caelestia/subcommands/shell.py | 4 +- src/caelestia/utils/hypr.py | 2 +- src/caelestia/utils/paths.py | 13 +++ src/caelestia/utils/scheme.py | 194 +++++++++++++++++++++++++++++++++++++ 6 files changed, 211 insertions(+), 124 deletions(-) delete mode 100644 src/caelestia/data.py create mode 100644 src/caelestia/utils/paths.py (limited to 'src/caelestia') diff --git a/src/caelestia/data.py b/src/caelestia/data.py deleted file mode 100644 index fa97a03..0000000 --- a/src/caelestia/data.py +++ /dev/null @@ -1,120 +0,0 @@ -import os -from pathlib import Path - -config_dir = Path(os.getenv("XDG_CONFIG_HOME", Path.home() / ".config")) -data_dir = Path(os.getenv("XDG_DATA_HOME", Path.home() / ".local/share")) -state_dir = Path(os.getenv("XDG_STATE_HOME", Path.home() / ".local/state")) - -c_config_dir = config_dir / "caelestia" -c_data_dir = data_dir / "caelestia" -c_state_dir = state_dir / "caelestia" - -scheme_name_path = c_state_dir / "scheme/name.txt" -scheme_flavour_path = c_state_dir / "scheme/flavour.txt" -scheme_colours_path = c_state_dir / "scheme/colours.txt" -scheme_mode_path = c_state_dir / "scheme/mode.txt" -scheme_variant_path = c_state_dir / "scheme/variant.txt" - -scheme_data_path = Path(__file__).parent / "data/schemes" - -scheme_variants = [ - "tonalspot", - "vibrant", - "expressive", - "fidelity", - "fruitsalad", - "monochrome", - "neutral", - "rainbow", - "content", -] - -scheme_names: list[str] = None -scheme_flavours: list[str] = None -scheme_modes: list[str] = None - -scheme_name: str = None -scheme_flavour: str = None -scheme_colours: dict[str, str] = None -scheme_mode: str = None -scheme_variant: str = None - - -def get_scheme_path() -> Path: - return (scheme_data_path / get_scheme_name() / get_scheme_flavour() / get_scheme_mode()).with_suffix(".txt") - - -def get_scheme_names() -> list[str]: - global scheme_names - - if scheme_names is None: - scheme_names = [f.name for f in scheme_data_path.iterdir() if f.is_dir()] - - return scheme_names - - -def get_scheme_flavours() -> list[str]: - global scheme_flavours - - if scheme_flavours is None: - scheme_flavours = [f.name for f in (scheme_data_path / get_scheme_name()).iterdir() if f.is_dir()] - - return scheme_flavours - - -def get_scheme_modes() -> list[str]: - global scheme_modes - - if scheme_modes is None: - scheme_modes = [ - f.stem for f in (scheme_data_path / get_scheme_name() / get_scheme_flavour()).iterdir() if f.is_file() - ] - - return scheme_modes - - -def get_scheme_name() -> str: - global scheme_name - - if scheme_name is None: - scheme_name = scheme_name_path.read_text().strip() if scheme_name_path.exists() else "catppuccin" - - return scheme_name - - -def get_scheme_flavour() -> str: - global scheme_flavour - - if scheme_flavour is None: - scheme_flavour = scheme_flavour_path.read_text().strip() if scheme_flavour_path.exists() else "mocha" - - return scheme_flavour - - -def get_scheme_colours() -> dict[str, str]: - global scheme_colours - - if scheme_colours is None: - scheme_colours = { - k.strip(): v.strip() for k, v in (line.split(" ") for line in get_scheme_path().read_text().splitlines()) - } - - return scheme_colours - - -def get_scheme_mode() -> str: - global scheme_mode - - if scheme_mode is None: - scheme_mode = scheme_mode_path.read_text().strip() if scheme_mode_path.exists() else "dark" - - return scheme_mode - - -def get_scheme_variant() -> str: - global scheme_variant - - if scheme_variant is None: - scheme_variant = scheme_variant_path.read_text().strip() if scheme_variant_path.exists() else "tonalspot" - - return scheme_variant diff --git a/src/caelestia/parser.py b/src/caelestia/parser.py index 00556b0..eb8734e 100644 --- a/src/caelestia/parser.py +++ b/src/caelestia/parser.py @@ -1,6 +1,5 @@ import argparse -from caelestia.data import get_scheme_names, scheme_variants from caelestia.subcommands import ( clipboard, emoji, @@ -14,6 +13,7 @@ from caelestia.subcommands import ( wallpaper, wsaction, ) +from caelestia.utils.scheme import get_scheme_names, scheme_variants def parse_args() -> (argparse.ArgumentParser, argparse.Namespace): diff --git a/src/caelestia/subcommands/shell.py b/src/caelestia/subcommands/shell.py index 2d8d14e..25a39d8 100644 --- a/src/caelestia/subcommands/shell.py +++ b/src/caelestia/subcommands/shell.py @@ -1,7 +1,7 @@ import subprocess from argparse import Namespace -from caelestia import data +from caelestia.utils import paths class Command: @@ -25,7 +25,7 @@ class Command: self.shell() def shell(self, *args: list[str]) -> str: - return subprocess.check_output(["qs", "-p", data.c_data_dir / "shell", *args], text=True) + return subprocess.check_output(["qs", "-p", paths.c_data_dir / "shell", *args], text=True) def print_ipc(self) -> None: print(self.shell("ipc", "show"), end="") diff --git a/src/caelestia/utils/hypr.py b/src/caelestia/utils/hypr.py index d829f22..621e28e 100644 --- a/src/caelestia/utils/hypr.py +++ b/src/caelestia/utils/hypr.py @@ -5,7 +5,7 @@ import socket socket_path = f"{os.getenv('XDG_RUNTIME_DIR')}/hypr/{os.getenv('HYPRLAND_INSTANCE_SIGNATURE')}/.socket.sock" -def message(msg: str, json: bool = True) -> str or dict[str, any]: +def message(msg: str, json: bool = True) -> str | dict[str, any]: with socket.socket(socket.AF_UNIX, socket.SOCK_STREAM) as sock: sock.connect(socket_path) diff --git a/src/caelestia/utils/paths.py b/src/caelestia/utils/paths.py new file mode 100644 index 0000000..aff6ea0 --- /dev/null +++ b/src/caelestia/utils/paths.py @@ -0,0 +1,13 @@ +import os +from pathlib import Path + +config_dir = Path(os.getenv("XDG_CONFIG_HOME", Path.home() / ".config")) +data_dir = Path(os.getenv("XDG_DATA_HOME", Path.home() / ".local/share")) +state_dir = Path(os.getenv("XDG_STATE_HOME", Path.home() / ".local/state")) + +c_config_dir = config_dir / "caelestia" +c_data_dir = data_dir / "caelestia" +c_state_dir = state_dir / "caelestia" + +scheme_path = c_state_dir / "scheme.json" +scheme_data_path = Path(__file__).parent.parent / "data/schemes" diff --git a/src/caelestia/utils/scheme.py b/src/caelestia/utils/scheme.py index e69de29..79a0c21 100644 --- a/src/caelestia/utils/scheme.py +++ b/src/caelestia/utils/scheme.py @@ -0,0 +1,194 @@ +import json +from pathlib import Path + +from caelestia.utils.paths import scheme_data_path, scheme_path + + +class Scheme: + _name: str + _flavour: str + _mode: str + _variant: str + _colours: dict[str, str] + + def __init__(self, json: dict[str, any] | None) -> None: + if json is None: + self._name = "catppuccin" + self._flavour = "mocha" + self._mode = "dark" + self._variant = "tonalspot" + self._colours = read_colours_from_file(self.get_colours_path()) + else: + self._name = json["name"] + self._flavour = json["flavour"] + self._mode = json["mode"] + self._variant = json["variant"] + self._colours = json["colours"] + + @property + def name(self) -> str: + return self._name + + @name.setter + def name(self, name: str) -> None: + if name == self._name: + return + + if name not in get_scheme_names(): + raise ValueError(f"Invalid scheme name: {name}") + + self._name = name + self._check_flavour() + self._check_mode() + self._update_colours() + self.save() + + @property + def flavour(self) -> str: + return self._flavour + + @flavour.setter + def flavour(self, flavour: str) -> None: + if flavour == self._flavour: + return + + if flavour not in get_scheme_flavours(): + raise ValueError(f"Invalid scheme flavour: {flavour}") + + self._flavour = flavour + self._check_mode() + self._update_colours() + self.save() + + @property + def mode(self) -> str: + return self._mode + + @mode.setter + def mode(self, mode: str) -> None: + if mode == self._mode: + return + + if mode not in get_scheme_modes(): + raise ValueError(f"Invalid scheme mode: {mode}") + + self._mode = mode + self._update_colours() + self.save() + + @property + def variant(self) -> str: + return self._variant + + @variant.setter + def variant(self, variant: str) -> None: + self._variant = variant + + @property + def colours(self) -> dict[str, str]: + return self._colours + + def get_colours_path(self) -> Path: + return (scheme_data_path / self.name / self.flavour / self.mode).with_suffix(".txt") + + def save(self) -> None: + scheme_path.parent.mkdir(parents=True, exist_ok=True) + with scheme_path.open("w") as f: + json.dump( + { + "name": self.name, + "flavour": self.flavour, + "mode": self.mode, + "variant": self.variant, + "colours": self.colours, + }, + f, + ) + + def _check_flavour(self) -> None: + global scheme_flavours + scheme_flavours = None + if self._flavour not in get_scheme_flavours(): + self._flavour = get_scheme_flavours()[0] + + def _check_mode(self) -> None: + global scheme_modes + scheme_modes = None + if self._mode not in get_scheme_modes(): + self._mode = get_scheme_modes()[0] + + def _update_colours(self) -> None: + self._colours = read_colours_from_file(self.get_colours_path()) + + +scheme_variants = [ + "tonalspot", + "vibrant", + "expressive", + "fidelity", + "fruitsalad", + "monochrome", + "neutral", + "rainbow", + "content", +] + +scheme_names: list[str] = None +scheme_flavours: list[str] = None +scheme_modes: list[str] = None + +scheme: Scheme = None + + +def read_colours_from_file(path: Path) -> dict[str, str]: + return {k.strip(): v.strip() for k, v in (line.split(" ") for line in path.read_text().splitlines())} + + +def get_scheme_path() -> Path: + return get_scheme().get_colours_path() + + +def get_scheme() -> Scheme: + global scheme + + if scheme is None: + try: + scheme_json = json.loads(scheme_path.read_text()) + scheme = Scheme(scheme_json) + except (IOError, json.JSONDecodeError): + scheme = Scheme(None) + + return scheme + + +def get_scheme_names() -> list[str]: + global scheme_names + + if scheme_names is None: + scheme_names = [f.name for f in scheme_data_path.iterdir() if f.is_dir()] + scheme_names.append("dynamic") + + return scheme_names + + +def get_scheme_flavours() -> list[str]: + global scheme_flavours + + if scheme_flavours is None: + name = get_scheme().name + if name == "dynamic": + scheme_flavours = ["default", "alt1", "alt2"] + else: + scheme_flavours = [f.name for f in (scheme_data_path / name).iterdir() if f.is_dir()] + + return scheme_flavours + + +def get_scheme_modes() -> list[str]: + global scheme_modes + + if scheme_modes is None: + scheme = get_scheme() + scheme_modes = [f.stem for f in (scheme_data_path / scheme.name / scheme.flavour).iterdir() if f.is_file()] + + return scheme_modes -- cgit v1.2.3-freya