#!/usr/bin/env bash # A setting has one schema-routed owner. A second page may mirror it only when # this contract names the exact owner and mirror set. The same ownership rule # keeps colour scheme propagation away from the focused Prism border. set -euo pipefail repo_dir="$(cd "$(dirname "${BASH_SOURCE[0]}")/../.." && pwd)" pages_dir="$repo_dir/config/dot/quickshell/modules/settings" schema="$repo_dir/config/dot/quickshell/config/PreferenceSchema.qml" search="$repo_dir/config/dot/quickshell/services/SettingsSearch.qml" scheme="$repo_dir/config/dot/quickshell/services/ColorScheme.qml" looks="$repo_dir/config/dot/hypr/looks.lua" readme="$pages_dir/README.md" fail() { printf 'settings ownership contract: %s\n' "$1" >&2 exit 1 } python3 - "$pages_dir" "$schema" "$search" <<'PY' \ || fail 'page ownership or intentional mirrors drifted' from __future__ import annotations import re import sys from collections import defaultdict from pathlib import Path pages_dir = Path(sys.argv[1]) schema_text = Path(sys.argv[2]).read_text(encoding="utf-8") search_text = Path(sys.argv[3]).read_text(encoding="utf-8") expected = { "animationsEnabled": {"owner": "appearance", "mirrors": {"accessibility"}}, "cursorInactiveTimeout": {"owner": "mouse", "mirrors": {"accessibility"}}, "cursorSize": {"owner": "accessibility", "mirrors": {"mouse"}}, "inactiveOpacity": {"owner": "appearance", "mirrors": {"accessibility"}}, "lockMinutes": {"owner": "power", "mirrors": {"privacy"}}, "lockOnSleep": {"owner": "power", "mirrors": {"privacy"}}, } def strip_comments(text: str) -> str: return re.sub(r"//.*", "", text) def page_name(path: Path) -> str: stem = path.stem.removesuffix("Page") return re.sub(r"(?.*?)\}", re.S, ) for page_path in pages_dir.glob("*Page.qml"): text = strip_comments(page_path.read_text(encoding="utf-8")) for match in row_pattern.finditer(text): setting = re.search(r'setting\s*:\s*"([^"]+)"', match.group("body")) if setting: rows[setting.group(1)].append(page_name(page_path)) duplicates = {key: set(pages) for key, pages in rows.items() if len(pages) > 1} if set(duplicates) != set(expected): raise SystemExit( f"duplicate keys are {sorted(duplicates)}, expected {sorted(expected)}" ) group_pages = dict(re.findall(r'"([^"]+)"\s*:\s*"([^"]+)"', search_text)) for key, policy in expected.items(): wanted_pages = {policy["owner"], *policy["mirrors"]} if duplicates[key] != wanted_pages: raise SystemExit(f"{key} appears on {sorted(duplicates[key])}, expected {sorted(wanted_pages)}") block = re.search( r'\{\s*\n\s*key:\s*"' + re.escape(key) + r'"(?P.*?)\n\s*\}', schema_text, re.S, ) if not block: raise SystemExit(f"schema entry missing for {key}") group = re.search(r'group:\s*"([^"]+)"', block.group("body")) if not group: raise SystemExit(f"schema group missing for {key}") routed = group_pages.get(group.group(1)) if routed != policy["owner"]: raise SystemExit( f"{key} routes to {routed!r}, expected primary owner {policy['owner']!r}" ) PY for needle in \ '## Setting ownership' \ 'one primary page' \ 'Intentional mirrors' \ '`animationsEnabled`' \ '`cursorInactiveTimeout`' \ '`cursorSize`' \ '`inactiveOpacity`' \ '`lockMinutes`' \ '`lockOnSleep`' \ 'scheme-relative role'; do rg -Fq "$needle" "$readme" || fail "README is missing $needle" done python3 - "$scheme" "$looks" <<'PY' \ || fail 'scheme-relative border ownership drifted' import re import sys scheme = open(sys.argv[1], encoding="utf-8").read() looks = open(sys.argv[2], encoding="utf-8").read() dark = re.search(r'property string inactiveBorderDark:\s*"([^"]+)"', scheme) light = re.search(r'property string inactiveBorderLight:\s*"([^"]+)"', scheme) effective = re.search(r'property string inactiveBorder:\s*root\.dark\s*\?\s*root\.inactiveBorderDark\s*:\s*root\.inactiveBorderLight', scheme) if not dark or not light or not effective: raise SystemExit("ColorScheme does not expose the two inactive-border roles") if dark.group(1) not in looks or light.group(1) not in looks: raise SystemExit("Hyprland startup values disagree with the live scheme roles") without_comments = re.sub(r"//.*", "", scheme) if re.search(r"(?