summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
author2 * r + 2 * t <61896496+soramanew@users.noreply.github.com>2025-06-11 17:37:04 +1000
committer2 * r + 2 * t <61896496+soramanew@users.noreply.github.com>2025-06-11 17:37:04 +1000
commitdc855e1b01e9b4526927b8bd69daca733afd97c2 (patch)
tree38adb17eb316e92d70b64df6824d3ad91901028f
parentparser: print help when no args (diff)
downloadcaelestia-cli-dc855e1b01e9b4526927b8bd69daca733afd97c2.tar.gz
caelestia-cli-dc855e1b01e9b4526927b8bd69daca733afd97c2.tar.bz2
caelestia-cli-dc855e1b01e9b4526927b8bd69daca733afd97c2.zip
internal: refactor scheme
Also use a single file to store scheme data
-rw-r--r--src/caelestia/data.py120
-rw-r--r--src/caelestia/parser.py2
-rw-r--r--src/caelestia/subcommands/shell.py4
-rw-r--r--src/caelestia/utils/hypr.py2
-rw-r--r--src/caelestia/utils/paths.py13
-rw-r--r--src/caelestia/utils/scheme.py194
6 files changed, 211 insertions, 124 deletions
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