aboutsummaryrefslogtreecommitdiffstats
path: root/deckit/config.py
diff options
context:
space:
mode:
Diffstat (limited to 'deckit/config.py')
-rw-r--r--deckit/config.py40
1 files changed, 40 insertions, 0 deletions
diff --git a/deckit/config.py b/deckit/config.py
new file mode 100644
index 0000000..151207b
--- /dev/null
+++ b/deckit/config.py
@@ -0,0 +1,40 @@
+"""Configuration loading and validation for deck-it."""
+
+import os
+import re
+import sys
+import tomllib
+from pathlib import Path
+
+ROOT = Path(__file__).resolve().parent.parent
+MONITOR_NAME = re.compile(r"[A-Za-z0-9_-]{1,32}")
+
+
+def user_config_path() -> Path:
+ return Path(os.environ.get("XDG_CONFIG_HOME", Path.home() / ".config")) / "deck-it" / "config.toml"
+
+
+def config_error(cfg: dict) -> str | None:
+ d, ports = cfg.get("display", {}), cfg.get("ports", {})
+ if not MONITOR_NAME.fullmatch(str(d.get("name", "TAB"))):
+ return "display.name must be letters, digits, - or _"
+ refresh = d.get("refresh", 60)
+ if not isinstance(refresh, int) or not 1 <= refresh <= 240:
+ return "display.refresh must be a number from 1 to 240"
+ for key in ("command_center", "display"):
+ if key in ports:
+ v = ports[key]
+ if not isinstance(v, int) or not 1024 <= v <= 65535:
+ return f"ports.{key} must be a number from 1024 to 65535"
+ if ports.get("command_center", 8765) == ports.get("display", 5900):
+ return "ports.command_center and ports.display must differ"
+ return None
+
+
+def load_config() -> dict:
+ path = user_config_path() if user_config_path().is_file() else ROOT / "config.toml"
+ with open(path, "rb") as f:
+ cfg = tomllib.load(f)
+ if err := config_error(cfg):
+ sys.exit(f"{path}: {err}")
+ return cfg