Some checks failed
Check / eval (push) Has been cancelled
The machine flake's git-tracked settings file is system state, not "theme" only — rename it to state.json. CLI becomes nomarchy-state-sync with a nomarchy-theme-sync symlink for scripts and muscle memory. Eval (mkFlake, doctor, lifecycle) still accepts theme-state.json; the next write migrates to state.json and removes the legacy file. Documented in MIGRATION.md; drop the CLI alias after release notes.
134 lines
5.7 KiB
Nix
134 lines
5.7 KiB
Nix
# Greeter — greetd/tuigreet, themed from the same state.json that
|
||
# drives the desktop (nomarchy.system.stateFile; the Plymouth model:
|
||
# baked at SYSTEM rebuild, so it follows the theme as of the last
|
||
# sys-update, not the last instant apply).
|
||
#
|
||
# tuigreet draws on the virtual console with the 16 ANSI slots, so the
|
||
# theming is two-part:
|
||
# 1. console.colors — the VT palette becomes the theme's ansi[] hexes
|
||
# (which also themes raw ttys and the LUKS passphrase prompt: the
|
||
# same JSON reaches every pre-session surface).
|
||
# 2. --theme — tuigreet components on NAMED slots (its parser is
|
||
# ratatui Color::from_str; names map to the standard indexes, e.g.
|
||
# blue=4, gray=7, white=15, so the palette above hands them the
|
||
# theme's colors). ANSI "black" stays dark even in light themes —
|
||
# the greeter reads terminal-dark there, the same convention every
|
||
# terminal applies to ANSI colors.
|
||
#
|
||
# Auto-login is in-flake state like the rest (settings.greeter.autoLogin,
|
||
# written by System › Auto-login via nomarchy-autologin below), NOT a baked
|
||
# line in system.nix: a hand-set `nomarchy.system.greeter.autoLogin` outranks
|
||
# the state default, which would leave the menu toggle flipping JSON that
|
||
# nothing reads. The installer therefore seeds the STATE on LUKS machines and
|
||
# the template keeps its example commented (templates/downstream/system.nix).
|
||
{ config, lib, pkgs, ... }:
|
||
|
||
let
|
||
cfg = config.nomarchy.system;
|
||
distroName = config.system.nixos.distroName;
|
||
|
||
sync = lib.getExe pkgs.nomarchy-state-sync;
|
||
|
||
# Menu/CLI toggle, same shape as nomarchy-autotimezone: runs as the normal
|
||
# user (it owns the flake checkout + writes the state), sudos only the
|
||
# system switch. greetd's initial_session is baked at system rebuild, so
|
||
# there is nothing to apply live — the next boot is the observable change.
|
||
nomarchy-autologin = pkgs.writeShellScriptBin "nomarchy-autologin" ''
|
||
set -e
|
||
if [ "$(id -u)" -eq 0 ]; then
|
||
echo "nomarchy-autologin: run as your normal user (it sudos the rebuild itself)" >&2
|
||
exit 1
|
||
fi
|
||
flake="''${NOMARCHY_PATH:-$HOME/.nomarchy}"
|
||
|
||
cur=$(${sync} get settings.greeter.autoLogin 2>/dev/null) || cur=null
|
||
case "''${1:-toggle}" in
|
||
on) new="\"$USER\"" ;;
|
||
off) new=null ;;
|
||
toggle) case "$cur" in null|""|None) new="\"$USER\"" ;; *) new=null ;; esac ;;
|
||
status) echo "$cur"; exit 0 ;;
|
||
*) echo "usage: nomarchy-autologin [toggle|on|off|status]" >&2; exit 64 ;;
|
||
esac
|
||
|
||
${sync} --quiet set settings.greeter.autoLogin "$new" --no-switch
|
||
|
||
notify-send "Auto-login" "Rebuilding the system…" 2>/dev/null || true
|
||
sudo nixos-rebuild switch --flake "$flake#default"
|
||
|
||
if [ "$new" = null ]; then
|
||
notify-send "Auto-login off" "The greeter asks who you are on the next boot." 2>/dev/null || true
|
||
else
|
||
notify-send "Auto-login on" "Next boot goes straight to the desktop." 2>/dev/null || true
|
||
fi
|
||
'';
|
||
|
||
# Fails closed with an actionable message via state-read.nix, like
|
||
# every other stateFile consumer — a raw fromJSON here would bury a bad
|
||
# state file under a Nix stack pointing at greeter.nix.
|
||
state =
|
||
if cfg.stateFile != null
|
||
then import ../state-read.nix { inherit lib; } cfg.stateFile
|
||
else { };
|
||
|
||
# The auto-login user from the state, or null. Read here via the state file
|
||
# — NOT `config.nomarchy.settings`, which exists only on the Home Manager
|
||
# side: on NixOS that attribute is missing, and `or null` swallows the
|
||
# error, so the old default silently evaluated to null on every machine.
|
||
stateAutoLogin =
|
||
let v = (state.settings or { }).greeter.autoLogin or null;
|
||
in if builtins.isString v && v != "" then v else null;
|
||
|
||
# A sparse/hand-rolled state without a proper ansi block just skips the
|
||
# theming (stock tuigreet grey) — never an eval error.
|
||
ansi = state.ansi or [ ];
|
||
themed = builtins.isList ansi && builtins.length ansi == 16;
|
||
|
||
tuigreetTheme = lib.concatStringsSep ";" [
|
||
"container=black" # ansi[0] — the theme's terminal background
|
||
"border=blue" # ansi[4] — the accent family in every shipped palette
|
||
"title=cyan"
|
||
"greet=cyan"
|
||
"prompt=green"
|
||
"input=white" # ansi[15] — bright foreground
|
||
"action=blue"
|
||
"button=yellow"
|
||
"time=cyan"
|
||
"text=gray" # ansi[7] — muted foreground
|
||
];
|
||
in
|
||
{
|
||
config = {
|
||
# Shipped unconditionally so the menu can turn auto-login back ON while
|
||
# it's off — the same reason nomarchy-autotimezone is unconditional.
|
||
environment.systemPackages = [ nomarchy-autologin ];
|
||
|
||
# Track the in-flake flag; mkDefault so a hand-set
|
||
# nomarchy.system.greeter.autoLogin in system.nix still wins (the
|
||
# autoTimezone pattern).
|
||
nomarchy.system.greeter.autoLogin = lib.mkDefault stateAutoLogin;
|
||
|
||
# VT palette from the theme (RRGGBB, no #; lands as vt.default_* kernel
|
||
# params). mkDefault so a downstream console.colors wins.
|
||
console.colors = lib.mkIf themed (lib.mkDefault (map (lib.removePrefix "#") ansi));
|
||
|
||
services.greetd = lib.mkIf cfg.greeter.enable {
|
||
enable = lib.mkDefault true;
|
||
settings = {
|
||
default_session = {
|
||
# start-hyprland is Hyprland 0.55's watchdog launcher; running
|
||
# the bare binary makes every session print a warning.
|
||
command = lib.mkDefault ("${pkgs.tuigreet}/bin/tuigreet --time --remember --greeting 'Welcome to ${distroName}'"
|
||
+ lib.optionalString themed " --theme '${tuigreetTheme}'"
|
||
+ " --cmd start-hyprland");
|
||
user = "greeter";
|
||
};
|
||
# Boot straight into the session once; logout → normal greeter.
|
||
initial_session = lib.mkIf (cfg.greeter.autoLogin != null) {
|
||
command = "start-hyprland";
|
||
user = cfg.greeter.autoLogin;
|
||
};
|
||
};
|
||
};
|
||
};
|
||
}
|