#!/usr/bin/env bash # A search result must open the page that actually contains the setting. # # Every schema group routes to one page in services/SettingsSearch.qml, and the # ownership rule in modules/settings/README.md derives a setting's owner from # that route. Nothing checked the two agreed, and two groups had drifted: # # weather routed to Appearance while every weather control lived on Home, so # searching "temperature unit" opened a page without it. # # vitals routed to Appearance, but the refresh interval sat on Home while the # toggles it governs sat on Appearance -- one concept, two pages, which is # precisely what the ownership rule forbids. # # Neither is visible from the code: each page is coherent on its own, and only # following a search result reveals the mismatch. # # Groups whose settings are driven by bespoke UI rather than schema-bound rows # are skipped, because there is nothing to locate. set -uo pipefail repo_dir="$(cd "$(dirname "${BASH_SOURCE[0]}")/../.." && pwd)" schema="$repo_dir/config/dot/quickshell/config/PreferenceSchema.qml" search="$repo_dir/config/dot/quickshell/services/SettingsSearch.qml" pages_dir="$repo_dir/config/dot/quickshell/modules/settings" fail() { printf 'search routing contract: %s\n' "$1" >&2 exit 1 } routes="$(grep -oE '"[a-zA-Z]+": "[a-z-]+"' "$search" | tr -d '"' | tr ':' ' ')" [[ -n "$routes" ]] || fail 'no group routes found -- this contract is not reading SettingsSearch correctly' # page id -> Page component file, as SettingsShell maps them. page_file() { case "$1" in home) printf 'HomePage.qml' ;; appearance) printf 'AppearancePage.qml' ;; displays) printf 'DisplaysPage.qml' ;; connectivity) printf 'ConnectivityPage.qml' ;; home-phone) printf 'HomePhonePage.qml' ;; desktop) printf 'DesktopPage.qml' ;; sound) printf 'SoundPage.qml' ;; notifications) printf 'NotificationsPage.qml' ;; screen-intelligence) printf 'ScreenIntelligencePage.qml' ;; shortcuts) printf 'ShortcutsPage.qml' ;; mouse) printf 'MousePage.qml' ;; privacy) printf 'PrivacyPage.qml' ;; region) printf 'RegionPage.qml' ;; accounts) printf 'OnlineAccountsPage.qml' ;; accessibility) printf 'AccessibilityPage.qml' ;; power) printf 'PowerPage.qml' ;; datetime) printf 'DateTimePage.qml' ;; applications) printf 'ApplicationsPage.qml' ;; services) printf 'HealthPage.qml' ;; about) printf 'AboutPage.qml' ;; *) printf '' ;; esac } violations=0 checked=0 while read -r group page; do [[ -n "$group" && -n "$page" ]] || continue target="$(page_file "$page")" [[ -n "$target" ]] || fail "group \"$group\" routes to \"$page\", which is not a known page" [[ -r "$pages_dir/$target" ]] || fail "group \"$group\" routes to \"$page\" but $target does not exist" # Keys belonging to this group. keys="$(awk -v g="\"$group\"" ' /key: "/ { match($0, /key: "[a-zA-Z]+"/); k = substr($0, RSTART+6, RLENGTH-7) } $0 ~ "group: " g { if (k != "") print k; k = "" } ' "$schema" | sort -u)" while read -r key; do [[ -n "$key" ]] || continue # Only settings rendered as schema-bound rows can be located at all. homes="$(grep -rl "setting: \"$key\"" "$pages_dir"/*Page.qml 2>/dev/null | xargs -n1 basename 2>/dev/null || true)" [[ -n "$homes" ]] || continue checked=$((checked + 1)) grep -qx "$target" <<<"$homes" && continue printf ' %s (group "%s") routes to %s but appears only on: %s\n' \ "$key" "$group" "$page" "$(tr '\n' ' ' <<<"$homes")" >&2 violations=$((violations + 1)) done <<<"$keys" done <<<"$routes" if (( violations > 0 )); then fail "$violations setting(s) route to a page that does not contain them, so searching for them opens the wrong page" fi printf 'search routing contract: PASS (%d routed settings)\n' "$checked"