Missing, empty, or non-object theme-state.json now throws a short message pointing at the template and `nomarchy-theme-sync validate` instead of a raw readFile/fromJSON stack. Shared reader: modules/theme-state-read.nix — wired in theme.nix, plymouth/timezone/ hardware, and lib.mkFlake (seq-forced early gate). Field-level schema in theme.nix kept; unknown border roles still fail there; resolveColor no longer falls through on missing palette keys. Defaults added for settings.displayProfile / displayProfileAuto. Verified: V0 nix flake check --no-build; negative evals (missing, empty, [], bad border role); good-path template mode + displayProfile defaults.
85 lines
2.5 KiB
Nix
85 lines
2.5 KiB
Nix
# Pure theme-state.json loader — fail closed with a short, actionable
|
|
# message instead of a raw `readFile` / `fromJSON` stack buried in a
|
|
# consumer. Used by modules/home/theme.nix (required path), the NixOS
|
|
# stateFile consumers, and lib.mkFlake (early gate).
|
|
#
|
|
# Field-level schema checks stay in theme.nix (post-defaults). This file
|
|
# only gates *existence* and *JSON-shape* so the first failure the user
|
|
# sees points at the state file, not at nightlight.nix.
|
|
{ lib }:
|
|
|
|
path:
|
|
|
|
let
|
|
pathStr = toString path;
|
|
|
|
tip = ''
|
|
Fix:
|
|
• Missing file → copy the template next to your flake.nix:
|
|
templates/downstream/theme-state.json
|
|
or regenerate from a preset:
|
|
nomarchy-theme-sync apply boreal
|
|
• Bad syntax / wrong shape → edit theme-state.json (trailing commas
|
|
are the usual culprit) or reset with `apply` as above.
|
|
• Field-level schema (colors, ui, border, …):
|
|
nomarchy-theme-sync validate
|
|
Eval-time field checks live in modules/home/theme.nix.'';
|
|
|
|
missingMsg = ''
|
|
|
|
Nomarchy: theme-state.json is missing:
|
|
${pathStr}
|
|
|
|
This file is required (appearance + menu settings). Add it to your
|
|
flake checkout so evaluation stays pure.
|
|
${tip}'';
|
|
|
|
emptyMsg = ''
|
|
|
|
Nomarchy: theme-state.json is empty:
|
|
${pathStr}
|
|
${tip}'';
|
|
|
|
notObjectMsg = ''
|
|
|
|
Nomarchy: theme-state.json must be a JSON object `{ ... }`:
|
|
${pathStr}
|
|
${tip}'';
|
|
|
|
# lib.trim / lib.strings.trim — strip leading/trailing whitespace so an
|
|
# all-whitespace file counts as empty and a BOM-less `{` is recognized.
|
|
strip = s:
|
|
let
|
|
# Prefer lib.trim when present (nixpkgs ≥ 23.11); fall back so a
|
|
# very old pin still gates missing/non-object.
|
|
trim =
|
|
if lib ? trim then lib.trim
|
|
else if lib.strings ? trim then lib.strings.trim
|
|
else (x: x);
|
|
in trim s;
|
|
|
|
in
|
|
if !(builtins.pathExists path) then
|
|
throw missingMsg
|
|
else
|
|
let
|
|
raw = builtins.readFile path;
|
|
stripped = strip raw;
|
|
in
|
|
if stripped == "" then
|
|
throw emptyMsg
|
|
# Reject non-objects before fromJSON where we can (null / array / string
|
|
# literals). Subtle syntax errors still surface from fromJSON itself —
|
|
# those messages already include line/column; the path tip above is the
|
|
# part a raw stack used to bury.
|
|
else if builtins.match "[[:space:]]*\\{.*" stripped == null then
|
|
throw notObjectMsg
|
|
else
|
|
let
|
|
value = builtins.fromJSON raw;
|
|
in
|
|
if !(builtins.isAttrs value) then
|
|
throw notObjectMsg
|
|
else
|
|
value
|