feat(core): migrate system state to unified declarative JSON

- Consolidate all configuration toggles (suspend, idle, waybar, etc.) into ~/.config/home-manager/state.json
- Introduce nomarchy.toggles and nomarchy.hyprland options in Nix
- Inject toggle states into all bin/ scripts via environment variables
- Update toggle scripts to mutate JSON and trigger background rebuilds
- Add a migration script to transition legacy flag files to the new format
This commit is contained in:
Bernardo Magri
2026-04-04 10:11:09 +01:00
parent f1ed0d7f47
commit cfd5e4bb65
23 changed files with 378 additions and 173 deletions

View File

@@ -11,12 +11,14 @@ if [[ -z $font_name ]]; then
fi
STATE_DIR="$HOME/.config/home-manager"
STATE_FILE="$STATE_DIR/font-state.nix"
STATE_FILE="$STATE_DIR/state.json"
mkdir -p "$STATE_DIR"
[[ ! -f $STATE_FILE ]] && echo "{}" > "$STATE_FILE"
if fc-list | grep -iq "$font_name"; then
echo "$font_name" > "$STATE_FILE"
TMP_JSON=$(mktemp)
jq ".font = \"$font_name\"" "$STATE_FILE" > "$TMP_JSON" && mv "$TMP_JSON" "$STATE_FILE"
echo "Font set to $font_name declaratively. Applying changes..."
env-update

View File

@@ -2,14 +2,14 @@
# Toggles the window gaps globally between no gaps and the default 10/5/2, declaratively and instantly.
STATE_FILE="$HOME/.config/home-manager/hyprland-state.json"
STATE_FILE="$HOME/.config/home-manager/state.json"
mkdir -p "$(dirname "$STATE_FILE")"
if [ ! -f "$STATE_FILE" ]; then
echo '{"gaps_out": 10, "gaps_in": 5, "border_size": 2}' > "$STATE_FILE"
echo "{}" > "$STATE_FILE"
fi
gaps=$(jq -r '.gaps_out' "$STATE_FILE")
gaps=$(jq -r '.hyprland.gaps_out // 10' "$STATE_FILE")
if [[ $gaps == "0" ]]; then
NEW_STATE='{"gaps_out": 10, "gaps_in": 5, "border_size": 2}'
@@ -23,5 +23,7 @@ else
hyprctl keyword general:border_size 0
fi
echo "$NEW_STATE" > "$STATE_FILE"
TMP_JSON=$(mktemp)
jq ".hyprland = $NEW_STATE" "$STATE_FILE" > "$TMP_JSON" && mv "$TMP_JSON" "$STATE_FILE"
echo "Toggled gaps to $NEW_STATE declaratively."

View File

@@ -11,10 +11,12 @@ fi
pgrep -f org.nomarchy.screensaver && exit 0
# Allow screensaver to be turned off but also force started
if [[ -f ~/.local/state/nomarchy/toggles/screensaver-off ]] && [[ $1 != "force" ]]; then
exit 1
# Skip if screensaver is disabled in configuration
if [[ $NOMARCHY_TOGGLE_SCREENSAVER == "false" ]] && [[ $1 != "force" ]]; then
exit 0
fi
# Silently quit Walker on overlay
walker -q

View File

@@ -1,8 +1,10 @@
#!/bin/bash
# Manage persistent state files for Nomarchy toggles and settings.
# Manage persistent runtime state files for Nomarchy indicators.
# Usage: nomarchy-state <set|clear> <state-name-or-pattern>
# Used to track whether features like suspend, idle lock, etc are enabled or disabled.
# Used to track whether things like reboot, restart, etc are required.
# DO NOT use this for configuration toggles (suspend, screensaver, etc).
# Use declarative Nomarchy NixOS home-manager options for those instead.
STATE_DIR="$HOME/.local/state/nomarchy"
mkdir -p "$STATE_DIR"

View File

@@ -4,10 +4,11 @@
# Declarative + Hybrid (instant swww) for Nomarchy NixOS.
STATE_DIR="$HOME/.config/home-manager"
THEME_STATE_FILE="$STATE_DIR/theme-state.nix"
WALLPAPER_STATE_FILE="$STATE_DIR/wallpaper-state.nix"
STATE_FILE="$STATE_DIR/state.json"
mkdir -p "$STATE_DIR"
[[ ! -f $STATE_FILE ]] && echo "{}" > "$STATE_FILE"
THEME_NAME=$(cat "$THEME_STATE_FILE" 2>/dev/null || echo "nord")
THEME_NAME=$(jq -r '.theme // "nord"' "$STATE_FILE")
if [ -d "/etc/nixos/nomarchy/themes" ]; then
THEMES_DIR="/etc/nixos/nomarchy/themes"
@@ -32,7 +33,7 @@ if (( TOTAL == 0 )); then
exit 1
fi
CURRENT_BG=$(cat "$WALLPAPER_STATE_FILE" 2>/dev/null)
CURRENT_BG=$(jq -r '.wallpaper' "$STATE_FILE")
INDEX=-1
for i in "${!BACKGROUNDS[@]}"; do
if [[ "$BG_DIR/${BACKGROUNDS[$i]}" == "$CURRENT_BG" ]]; then
@@ -44,7 +45,8 @@ done
NEXT_INDEX=$(((INDEX + 1) % TOTAL))
NEW_BG="$BG_DIR/${BACKGROUNDS[$NEXT_INDEX]}"
echo "$NEW_BG" > "$WALLPAPER_STATE_FILE"
TMP_JSON=$(mktemp)
jq ".wallpaper = \"$NEW_BG\"" "$STATE_FILE" > "$TMP_JSON" && mv "$TMP_JSON" "$STATE_FILE"
# Instant feedback via swww
if pgrep -x swww-daemon >/dev/null; then

View File

@@ -11,8 +11,7 @@ if [[ -z $THEME_NAME ]]; then
fi
STATE_DIR="$HOME/.config/home-manager"
THEME_STATE_FILE="$STATE_DIR/theme-state.nix"
WALLPAPER_STATE_FILE="$STATE_DIR/wallpaper-state.nix"
STATE_FILE="$STATE_DIR/state.json"
# Logic for finding themes
if [ -d "/etc/nixos/nomarchy/themes" ]; then
@@ -24,6 +23,7 @@ else
fi
mkdir -p "$STATE_DIR"
[[ ! -f $STATE_FILE ]] && echo "{}" > "$STATE_FILE"
if [ ! -d "$THEMES_DIR/$THEME_NAME" ] && ! [[ "$THEME_NAME" == "nord" ]]; then
echo "Theme '$THEME_NAME' not found in $THEMES_DIR"
@@ -31,18 +31,23 @@ if [ ! -d "$THEMES_DIR/$THEME_NAME" ] && ! [[ "$THEME_NAME" == "nord" ]]; then
# (Assuming nomarchy-palettes.nix is imported in Nix)
fi
echo "$THEME_NAME" > "$THEME_STATE_FILE"
TMP_JSON=$(mktemp)
jq ".theme = \"$THEME_NAME\"" "$STATE_FILE" > "$TMP_JSON" && mv "$TMP_JSON" "$STATE_FILE"
# Try to find a background for this theme
BG_DIR="$THEMES_DIR/$THEME_NAME/backgrounds"
if [ -d "$BG_DIR" ]; then
BG=$(ls "$BG_DIR" | head -n 1)
if [ -n "$BG" ]; then
echo "$BG_DIR/$BG" > "$WALLPAPER_STATE_FILE"
TMP_JSON=$(mktemp)
jq ".wallpaper = \"$BG_DIR/$BG\"" "$STATE_FILE" > "$TMP_JSON" && mv "$TMP_JSON" "$STATE_FILE"
fi
fi
echo "Theme set to $THEME_NAME. Applying changes with env-update..."
rm -rf "$HOME/.config/nomarchy/current/theme"
env-update
nomarchy-theme-set-templates
nomarchy-hook theme-set "$THEME_NAME"

View File

@@ -7,9 +7,8 @@ VS_CODE_THEME="$HOME/.config/nomarchy/current/theme/vscode.json"
set_theme() {
local editor_cmd="$1"
local settings_path="$2"
local skip_flag="$3"
nomarchy-cmd-present "$editor_cmd" && [[ ! -f $skip_flag ]] || return 0
nomarchy-cmd-present "$editor_cmd" && [[ $NOMARCHY_TOGGLE_SKIP_VSCODE_THEME != "true" ]] || return 0
if [[ -f $VS_CODE_THEME ]]; then
theme_name=$(jq -r '.name' "$VS_CODE_THEME")
@@ -34,7 +33,7 @@ set_theme() {
fi
}
set_theme "code" "$HOME/.config/Code/User/settings.json" "$HOME/.local/state/nomarchy/toggles/skip-vscode-theme-changes"
set_theme "code-insiders" "$HOME/.config/Code - Insiders/User/settings.json" "$HOME/.local/state/nomarchy/toggles/skip-vscode-insiders-theme-changes"
set_theme "codium" "$HOME/.config/VSCodium/User/settings.json" "$HOME/.local/state/nomarchy/toggles/skip-codium-theme-changes"
set_theme "cursor" "$HOME/.config/Cursor/User/settings.json" "$HOME/.local/state/nomarchy/toggles/skip-cursor-theme-changes"
set_theme "code" "$HOME/.config/Code/User/settings.json"
set_theme "code-insiders" "$HOME/.config/Code - Insiders/User/settings.json"
set_theme "codium" "$HOME/.config/VSCodium/User/settings.json"
set_theme "cursor" "$HOME/.config/Cursor/User/settings.json"

View File

@@ -1,28 +1,27 @@
#!/usr/bin/env bash
# Toggles the idle daemon (hypridle) between enabled and disabled.
# Declarative + Hybrid (instant IPC/kill) for Nomarchy NixOS.
# Hybrid: updates state.json and provides instant feedback.
STATE_FILE="$HOME/.config/home-manager/idle-state.json"
STATE_FILE="$HOME/.config/home-manager/state.json"
mkdir -p "$(dirname "$STATE_FILE")"
if [ ! -f "$STATE_FILE" ]; then
echo '{"enabled": true}' > "$STATE_FILE"
fi
# Initialize if doesn't exist
[[ ! -f $STATE_FILE ]] && echo "{}" > "$STATE_FILE"
enabled=$(jq -r '.enabled' "$STATE_FILE")
if [[ $enabled == "true" ]]; then
NEW_ENABLED="false"
pkill -x hypridle
notify-send -u low "󱫖 Stop locking computer when idle"
else
NEW_ENABLED="true"
if [[ $NOMARCHY_TOGGLE_IDLE == "false" ]]; then
NEW_VALUE="true"
setsid hypridle >/dev/null 2>&1 &
notify-send -u low "󱫖 Now locking computer when idle"
else
NEW_VALUE="false"
pkill -x hypridle
notify-send -u low "󱫖 Stop locking computer when idle"
fi
echo "{\"enabled\": $NEW_ENABLED}" > "$STATE_FILE"
echo "Idle daemon set to $NEW_ENABLED declaratively."
TMP_JSON=$(mktemp)
jq ".idle = $NEW_VALUE" "$STATE_FILE" > "$TMP_JSON" && mv "$TMP_JSON" "$STATE_FILE"
echo "Idle state set to $NEW_VALUE. Environment will be fully updated on next rebuild."
pkill -RTMIN+9 waybar # Signal waybar if needed

View File

@@ -1,36 +1,25 @@
#!/usr/bin/env bash
# Toggles the nightlight (hyprsunset) between enabled (4000) and disabled (6500)
# Declarative + Hybrid (instant IPC) for Nomarchy NixOS.
# Toggles the nightlight (hyprsunset).
# Hybrid: updates state.json and provides instant feedback.
STATE_FILE="$HOME/.config/home-manager/hyprsunset-state.json"
STATE_FILE="$HOME/.config/home-manager/state.json"
mkdir -p "$(dirname "$STATE_FILE")"
if [ ! -f "$STATE_FILE" ]; then
echo '{"enabled": false, "temperature": 4000}' > "$STATE_FILE"
fi
# Initialize if doesn't exist
[[ ! -f $STATE_FILE ]] && echo "{}" > "$STATE_FILE"
enabled=$(jq -r '.enabled' "$STATE_FILE")
if [[ $enabled == "true" ]]; then
NEW_ENABLED="false"
TEMP=6500
notify-send -u low " Nightlight DISABLED"
if [[ $NOMARCHY_TOGGLE_NIGHTLIGHT == "false" ]]; then
NEW_VALUE="true"
hyprctl dispatch exec hyprsunset --temperature 4000
notify-send -u low "󰔎 Nightlight enabled"
else
NEW_ENABLED="true"
TEMP=4000
notify-send -u low " Nightlight ENABLED"
NEW_VALUE="false"
pkill hyprsunset
notify-send -u low "󰔎 Nightlight disabled"
fi
# Instant feedback via IPC
if pgrep -x hyprsunset >/dev/null; then
hyprctl hyprsunset temperature $TEMP
else
# Should be started by systemd, but just in case
setsid hyprsunset -t $TEMP &
fi
TMP_JSON=$(mktemp)
jq ".nightlight = $NEW_VALUE" "$STATE_FILE" > "$TMP_JSON" && mv "$TMP_JSON" "$STATE_FILE"
echo "{\"enabled\": $NEW_ENABLED, \"temperature\": 4000}" > "$STATE_FILE"
echo "Nightlight set to $NEW_ENABLED ($TEMP) declaratively."
# No need to run env-update if we don't want the delay,
# as next HM switch will pick it up and apply it.
echo "Nightlight state set to $NEW_VALUE. Environment will be fully updated on next rebuild."

View File

@@ -1,12 +1,25 @@
#!/bin/bash
#!/usr/bin/env bash
STATE_FILE=~/.local/state/nomarchy/toggles/screensaver-off
# Toggles the screensaver availability.
# Hybrid: updates state.json and runs env-update for persistence.
if [[ -f $STATE_FILE ]]; then
rm -f $STATE_FILE
notify-send -u low "󱄄 Screensaver enabled"
STATE_FILE="$HOME/.config/home-manager/state.json"
mkdir -p "$(dirname "$STATE_FILE")"
# Initialize if doesn't exist
[[ ! -f $STATE_FILE ]] && echo "{}" > "$STATE_FILE"
if [[ $NOMARCHY_TOGGLE_SCREENSAVER == "false" ]]; then
NEW_VALUE="true"
notify-send -u low "󱄄 Screensaver enabled"
else
mkdir -p "$(dirname $STATE_FILE)"
touch $STATE_FILE
notify-send -u low "󱄄 Screensaver disabled"
NEW_VALUE="false"
notify-send -u low "󱄄 Screensaver disabled"
fi
TMP_JSON=$(mktemp)
jq ".screensaver = $NEW_VALUE" "$STATE_FILE" > "$TMP_JSON" && mv "$TMP_JSON" "$STATE_FILE"
echo "Screensaver state set to $NEW_VALUE. Updating environment..."
env-update

View File

@@ -1,12 +1,29 @@
#!/bin/bash
#!/usr/bin/env bash
STATE_FILE=~/.local/state/nomarchy/toggles/suspend-off
# Toggles the suspend menu option availability.
# Hybrid: updates state.json and runs env-update for persistence.
if [[ -f $STATE_FILE ]]; then
rm -f $STATE_FILE
notify-send -u low "󰒲 Suspend now available in system menu"
STATE_FILE="$HOME/.config/home-manager/state.json"
mkdir -p "$(dirname "$STATE_FILE")"
# Initialize if doesn't exist
[[ ! -f $STATE_FILE ]] && echo "{}" > "$STATE_FILE"
# Get current state from env or state file
if [[ $NOMARCHY_TOGGLE_SUSPEND == "false" ]]; then
NEW_VALUE="true"
notify-send -u low "󰒲 Suspend now available in system menu"
else
mkdir -p "$(dirname $STATE_FILE)"
touch $STATE_FILE
notify-send -u low "󰒲 Suspend removed from system menu"
NEW_VALUE="false"
notify-send -u low "󰒲 Suspend removed from system menu"
fi
# Update JSON using jq
# We use a temporary file to avoid corruption if the shell is interrupted
TMP_JSON=$(mktemp)
jq ".suspend = $NEW_VALUE" "$STATE_FILE" > "$TMP_JSON" && mv "$TMP_JSON" "$STATE_FILE"
echo "Suspend availability set to $NEW_VALUE. Updating environment..."
# Run env-update to apply changes to the menu
env-update

View File

@@ -1,7 +1,25 @@
#!/bin/bash
#!/usr/bin/env bash
if pgrep -x waybar >/dev/null; then
pkill -x waybar
# Toggles the waybar top bar.
# Hybrid: updates state.json and provides instant feedback.
STATE_FILE="$HOME/.config/home-manager/state.json"
mkdir -p "$(dirname "$STATE_FILE")"
# Initialize if doesn't exist
[[ ! -f $STATE_FILE ]] && echo "{}" > "$STATE_FILE"
if [[ $NOMARCHY_TOGGLE_WAYBAR == "false" ]]; then
NEW_VALUE="true"
uwsm-app -- waybar >/dev/null 2>&1 &
notify-send -u low "󰍜 Top bar enabled"
else
uwsm-app -- waybar >/dev/null 2>&1 &
NEW_VALUE="false"
pkill -x waybar
notify-send -u low "󰍜 Top bar disabled"
fi
TMP_JSON=$(mktemp)
jq ".waybar = $NEW_VALUE" "$STATE_FILE" > "$TMP_JSON" && mv "$TMP_JSON" "$STATE_FILE"
echo "Waybar state set to $NEW_VALUE. Environment will be fully updated on next rebuild."