From 161542c420054ac84f01b77509877b67ffbc4b4f Mon Sep 17 00:00:00 2001 From: Bernardo Magri Date: Fri, 22 May 2026 18:20:44 +0100 Subject: [PATCH] fix(nightlight): gate hyprsunset on the toggle, drop hardcoded temperature MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit features/desktop/nightlight.nix previously set `services.hyprsunset.enable = lib.mkDefault true` unconditionally and baked the temperature (4000K when toggles.nightlight, 6500K otherwise) into extraArgs at Nix-eval time. The toggle script bypassed systemd: pkill on disable, `hyprctl dispatch exec hyprsunset --temperature 4000` on enable — racing the systemd-managed instance and hardcoding 4000K regardless of nomarchy.nightlightTemperature. The "Always enabled, we control via IPC and state" comment was misleading: no IPC, the temperature was rebuild-time, and the script forked a parallel process. Path (b) from the Later row: - services.hyprsunset.enable now follows config.nomarchy.toggles. nightlight — symmetric with services.hypridle.enable ← toggles.idle. Disabled toggle = no process running. - extraArgs always reads from config.nomarchy.nightlightTemperature. Drops the 6500K neutralising fork; when off the unit just doesn't start. - nomarchy-toggle-nightlight flips the running systemd user unit via `systemctl --user start/stop hyprsunset.service` for instant feedback, reads nightlightTemperature from state.json for the notify-send line, and writes .nightlight back to state.json so the next rebuild realigns services.hyprsunset.enable. `nix flake check --no-build` + `bash -n` clean. --- docs/ROADMAP.md | 2 +- features/desktop/nightlight.nix | 20 ++++++++++++++----- .../engine/scripts/nomarchy-toggle-nightlight | 18 ++++++++++------- 3 files changed, 27 insertions(+), 13 deletions(-) diff --git a/docs/ROADMAP.md b/docs/ROADMAP.md index 69b5908..fb39c59 100644 --- a/docs/ROADMAP.md +++ b/docs/ROADMAP.md @@ -43,7 +43,6 @@ Guardrails (apply when adding anything): - **`themes/templates/*.tpl` — prune the truly dead, document the rest.** Eleven mustache-style templates deployed to `~/.local/share/nomarchy/templates/` via `themes/engine/files.nix`. Originally flagged as "no script consumes them" — that was wrong: `themes/engine/scripts/nomarchy-theme-set-templates` (called at the end of `nomarchy-theme-set`) reads them, substitutes palette colors, and writes the output to `~/.config/nomarchy/current/theme/` only when no file is already there. Now categorise: **(a) functionally dead** — `alacritty.toml.tpl`, `btop.theme.tpl`, `chromium.theme.tpl`, `swayosd.css.tpl` all produce files at paths nothing reads (alacritty + swayosd are Stylix/Nix-themed; btop reads from `~/.config/btop/themes/nomarchy.theme` not from the theme symlink; chromium.theme references were deleted in `9b06b6c`). **(b) superseded** — `kitty.conf.tpl` and `ghostty.conf.tpl` are now generated by `themes/engine/files.nix` (commit `8d3ce2d`); the template path skips harmlessly via the "if not exists" check. **(c) still relevant** — `hyprland.conf.tpl`, `hyprlock.conf.tpl`, `obsidian.css.tpl`, `keyboard.rgb.tpl`, `hyprland-preview-share-picker.css.tpl` (this last one was orphaned when the share-picker dir was deleted in `20de3d4` — verify before keeping). Delete (a) + (b) + the orphan share-picker tpl; document the rest in `docs/creating-themes.md` as the layered override surface they actually are. - **Make `nomarchy.toggles.waybar` a Nix-level gate, or document it as runtime-only.** Today the toggle is exported as `NOMARCHY_TOGGLE_WAYBAR` env, consumed only by `nomarchy-toggle-waybar` (which pkill/exec's at runtime). The Nix module always sets `programs.waybar.enable = lib.mkDefault true`, so waybar comes back on every rebuild/reboot regardless of the toggle. Inconsistent with `toggles.idle`, which correctly gates `services.hypridle.enable`. Either gate `programs.waybar.enable` on the toggle (persistent) or rename the option to make its session-only nature obvious. - **Package missing VSCode theme extensions via `extensionFromVscodeMarketplace`.** 15 of the 21 palettes that ship a `themes/palettes//apps/vscode.json` declare a theme extension that isn't in `pkgs.vscode-extensions` — including `sainnhe.everforest` which is the default `summer-night` palette's theme. With the `577b3ae` fix in place, the 6 nixpkgs-packaged extensions install by default (catppuccin, catppuccin-latte, nord, tokyo-night, rose-pine, gruvbox), but the other 15 (`sainnhe.everforest`, `qufiwefefwoyn.kanagawa`, `monokai.theme-monokai-pro-vscode`, `oldjobobo.{lumon,miasma,retro-82}-theme`, `Bjarne.{ethereal,hackerman,vantablack,white}-nomarchy`, `shadesOfBuntu.flexoki-light`, `jovejonovski.ocean-green`, `TahaYVR.matteblack`) still leave `workbench.colorTheme` referencing an unloaded theme, so VSCode silently falls back. Fix: extend `features/apps/vscode.nix` to look up the active palette's extension via `pkgs.vscode-utils.extensionFromVscodeMarketplace { publisher; name; version; sha256; }` — each entry pinned by hash. Could be table-driven in `lib/` so a new palette only needs to add a row. -- **Reconcile nightlight: systemd-managed hyprsunset vs `pkill`/`hyprctl exec` toggle.** `features/desktop/nightlight.nix` always sets `services.hyprsunset.enable = lib.mkDefault true` and bakes the temperature (`toggles.nightlight ? nightlightTemperature : 6500`) into `extraArgs` at Nix-eval time. The toggle script `themes/engine/scripts/nomarchy-toggle-nightlight` bypasses systemd entirely: `pkill hyprsunset` on disable, `hyprctl dispatch exec hyprsunset --temperature 4000` on enable — racing the systemd-managed instance and ignoring the user's chosen `nightlightTemperature`. The comment "Always enabled, we control via IPC and state" doesn't match the implementation (there's no IPC; the temperature is rebuild-time, not runtime). Pick one: (a) toggle stays as `hyprctl dispatch hyprsunset temperature ${T}` (proper IPC, no daemon restart), with Nix dropping `extraArgs` to just `--temperature 6500` on boot; or (b) gate `services.hyprsunset.enable` on the toggle and run `systemctl --user restart hyprsunset` from the script. Both also need the script to read `nightlightTemperature` instead of hardcoding 4000. ## 3. Pillar: Script & menu audit @@ -154,6 +153,7 @@ Pillar is **done** when every component has a closed `wave/qa-` PR an (Move items here when they land — keep them brief, link the commit/PR.) +- _2026-05-22_ — **Nightlight reconciled: hyprsunset gated on the toggle.** Path (b) from the Later row. `features/desktop/nightlight.nix` previously set `services.hyprsunset.enable = lib.mkDefault true` unconditionally and baked the temperature (4000K or a neutralising 6500K) into `extraArgs` at Nix-eval time, while the toggle script `pkill`'d the daemon on disable and `hyprctl dispatch exec hyprsunset --temperature 4000`'d a new one on enable — racing the systemd unit and hardcoding 4000K regardless of `nomarchy.nightlightTemperature`. Now: `services.hyprsunset.enable = lib.mkDefault config.nomarchy.toggles.nightlight` (symmetric with `services.hypridle.enable` ← `toggles.idle`), `extraArgs` always uses the option value, and the toggle script flips the running unit via `systemctl --user start/stop hyprsunset.service`, reads `nightlightTemperature` from `state.json` for the notification, and writes `.nightlight` back to `state.json` so the next rebuild realigns. Dropped the misleading "Always enabled, we control via IPC and state" comment. `nix flake check --no-build` + `bash -n` clean. - _2026-05-22_ — **Installer keymap reaches Hyprland's Wayland session.** `core/home/config/nomarchy/default/hypr/input.conf` hardcoded `kb_layout = us`, so the installer's `services.xserver.xkb.layout` / `console.keyMap` writes only reached XWayland and the TTY — native-Wayland apps fell back to US. Option-route fix (path (a) from the Later row): added `nomarchy.keymap.{layout,variant}` to `core/home/options.nix` (defaults `"us"` / `""`); deleted the static `input.conf` from the bulk `nomarchy/` deploy; moved it into `core/home/configs.nix` as an explicit `xdg.configFile."nomarchy/default/hypr/input.conf".text = ''…''` that interpolates the option values. Installer's `home.nix` heredoc now writes `nomarchy.keymap = { layout = "$KEYMAP_LAYOUT"; variant = "$KEYMAP_VARIANT"; };` alongside `nomarchy.formFactor`, so a non-US install propagates the layout consistently to Hyprland, XWayland, and the TTY. Documented in `docs/OPTIONS.md`. `nix flake check --no-build` clean. - _2026-05-22_ — **`flake.nix` palette imports consolidated through `nomarchyLib`.** `flake.nix` was re-importing `./themes/palettes` and recomputing `themeNames` via `builtins.attrNames` even though `lib/default.nix` already exports both. Two evaluations of the same data set with the same result today — drift risk tomorrow. Added `nomarchyLib = import ./lib { inherit lib; }` once in the outputs `let` and reused it via `inherit (nomarchyLib) themeNames;` for the `allThemeVariants` linkFarm. `lib/default.nix` is now the single source of truth for the theme list — modules that need palette data import `../../lib` the same way and resolve to the same evaluation. `nix flake check --no-build` clean. - _2026-05-22_ — **`programs.uwsm` moved to `core/system/session.nix`.** The session-manager wiring (uwsm + the Hyprland Wayland-compositor entry that gives Hyprland a proper `graphical-session.target` so user services like `nomarchy-wallpaper`, walker and elephant chain off it) had lived in `core/system/virtualization.nix` by historical accident — loaded unconditionally on every install, nothing to do with libvirt/docker. Lifted into a dedicated `core/system/session.nix` and imported from `core/system/default.nix` between `systemd.nix` and `virtualization.nix`. `virtualization.nix` now contains only the libvirt + docker branches its filename implies. `nix flake check --no-build` clean. No behaviour change. diff --git a/features/desktop/nightlight.nix b/features/desktop/nightlight.nix index 124ecef..23f6d50 100644 --- a/features/desktop/nightlight.nix +++ b/features/desktop/nightlight.nix @@ -1,11 +1,21 @@ { config, lib, ... }: -let - temp = toString (if config.nomarchy.toggles.nightlight then config.nomarchy.nightlightTemperature else 6500); -in +# hyprsunset (the blue-light filter) is gated on `nomarchy.toggles.nightlight` +# so a disabled toggle means no process runs — symmetric with how +# `services.hypridle.enable` is wired off `toggles.idle`. The temperature +# comes from `nomarchy.nightlightTemperature`, evaluated at Nix-eval time +# and baked into `extraArgs`. The toggle script (themes/engine/scripts/ +# nomarchy-toggle-nightlight) writes both the toggle and the same +# temperature value into state.json and flips the systemd unit for +# instant feedback; the next rebuild's HM activation realigns systemd +# with the persistent state. + { services.hyprsunset = { - enable = lib.mkDefault true; # Always enabled, we control via IPC and state - extraArgs = lib.mkDefault [ "--temperature" temp ]; + enable = lib.mkDefault config.nomarchy.toggles.nightlight; + extraArgs = lib.mkDefault [ + "--temperature" + (toString config.nomarchy.nightlightTemperature) + ]; }; } diff --git a/themes/engine/scripts/nomarchy-toggle-nightlight b/themes/engine/scripts/nomarchy-toggle-nightlight index aa9de23..7af505d 100755 --- a/themes/engine/scripts/nomarchy-toggle-nightlight +++ b/themes/engine/scripts/nomarchy-toggle-nightlight @@ -1,27 +1,31 @@ #!/usr/bin/env bash set -e -# Toggles the nightlight (hyprsunset). -# Hybrid: updates state.json and provides instant feedback. +# Toggles the nightlight (hyprsunset). Writes the new state to state.json +# (so the next home-manager rebuild realigns services.hyprsunset.enable +# via features/desktop/nightlight.nix) and flips the running systemd +# user unit for instant feedback. Reads nightlightTemperature from +# state.json so the value the user picked is honoured instead of a +# hardcoded constant. STATE_DIR="$HOME/.config/nomarchy" STATE_FILE="$STATE_DIR/state.json" mkdir -p "$STATE_DIR" -# Initialize if doesn't exist [[ ! -f $STATE_FILE ]] && echo "{}" > "$STATE_FILE" if [[ $NOMARCHY_TOGGLE_NIGHTLIGHT == "false" ]]; then NEW_VALUE="true" - hyprctl dispatch exec hyprsunset --temperature 4000 - notify-send -u low " Nightlight enabled" + systemctl --user start hyprsunset.service 2>/dev/null || true + TEMP=$(jq -r '.nightlightTemperature // 4000' "$STATE_FILE") + notify-send -u low " Nightlight enabled (${TEMP}K)" else NEW_VALUE="false" - pkill hyprsunset + systemctl --user stop hyprsunset.service 2>/dev/null || true notify-send -u low " Nightlight disabled" fi TMP_JSON=$(mktemp) jq --argjson val "$NEW_VALUE" '.nightlight = $val' "$STATE_FILE" > "$TMP_JSON" && mv "$TMP_JSON" "$STATE_FILE" -echo "Nightlight state set to $NEW_VALUE. Environment will be fully updated on next rebuild." +echo "Nightlight state set to $NEW_VALUE."