feat(home): mkDefault behaviour settings so downstream can plain-override
Nomarchy's Hyprland/Ghostty/Waybar settings were set at normal priority, so a downstream `home.nix` setting any value Nomarchy already set threw a "conflicting definition values" error — overriding required lib.mkForce, contradicting the README's "mkDefault throughout" claim. Now: behaviour/chrome leaves (input, misc, monitor, animations, dwindle, gesture, decoration.blur sizing, ghostty padding/decoration, waybar settings+style) are lib.mkDefault — a plain home.nix assignment wins. Appearance values that flow from theme-state.json (gaps, colors, rounding, opacity, fonts) stay at normal priority on purpose: change them via nomarchy-theme-sync (their source of truth) or lib.mkForce to hardcode. bind/exec-once lists stay normal priority so additions concatenate rather than replace. Verified: behaviour/ghostty plain overrides build; theme values still conflict (steering to the CLI); default rendered config is byte-identical. New docs/OVERRIDES.md with the appearance→CLI / behaviour→home.nix / component→toggle model and worked examples; linked from the README. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
@@ -66,6 +66,7 @@ Flat on purpose. Two module trees, one options file each, no hidden layers.
|
|||||||
│ └── nomarchy-install/ # live-ISO installer (gum + disko + mkFlake)
|
│ └── nomarchy-install/ # live-ISO installer (gum + disko + mkFlake)
|
||||||
├── templates/downstream/ # `nix flake init -t` starter for users
|
├── templates/downstream/ # `nix flake init -t` starter for users
|
||||||
├── docs/TESTING.md # how to verify changes (incl. AI-agent rules)
|
├── docs/TESTING.md # how to verify changes (incl. AI-agent rules)
|
||||||
|
├── docs/OVERRIDES.md # how downstream users override defaults
|
||||||
└── tools/ # maintainer-only
|
└── tools/ # maintainer-only
|
||||||
├── import-palettes.py # converts old-distro themes → JSON + assets
|
├── import-palettes.py # converts old-distro themes → JSON + assets
|
||||||
├── test-live-iso.sh # build the ISO + boot it in QEMU
|
├── test-live-iso.sh # build the ISO + boot it in QEMU
|
||||||
@@ -154,8 +155,11 @@ sys-update # nix flake update + system rebuild (BTRFS snapshot first when ava
|
|||||||
home-update # home-manager switch (no flake update, no sudo)
|
home-update # home-manager switch (no flake update, no sudo)
|
||||||
```
|
```
|
||||||
|
|
||||||
Override anything with plain NixOS/HM options (the distro uses `mkDefault`
|
Override anything via the `nomarchy.*` surface or plain NixOS/HM options:
|
||||||
throughout) or the `nomarchy.*` surface:
|
appearance (gaps/colors/fonts) changes through `nomarchy-theme-sync`,
|
||||||
|
behaviour (input/misc/monitor/chrome) is `mkDefault` so a plain `home.nix`
|
||||||
|
assignment wins, and bind/exec-once lists concatenate. Full guide with
|
||||||
|
examples: **[docs/OVERRIDES.md](docs/OVERRIDES.md)**.
|
||||||
|
|
||||||
| Option | Default | Purpose |
|
| Option | Default | Purpose |
|
||||||
|---|---|---|
|
|---|---|---|
|
||||||
|
|||||||
147
docs/OVERRIDES.md
Normal file
147
docs/OVERRIDES.md
Normal file
@@ -0,0 +1,147 @@
|
|||||||
|
# Overriding Nomarchy's defaults
|
||||||
|
|
||||||
|
You consume Nomarchy as a flake input and own two files: `system.nix` and
|
||||||
|
`home.nix`. Your config is **merged** with Nomarchy's modules, so changing a
|
||||||
|
default is just a matter of knowing which of three knobs to reach for. The
|
||||||
|
rule of thumb:
|
||||||
|
|
||||||
|
> **Appearance → the CLI. Behaviour → `home.nix`. Whole component → toggle it off.**
|
||||||
|
|
||||||
|
## 1. Appearance (gaps, colors, rounding, fonts, opacity) — use the CLI
|
||||||
|
|
||||||
|
Everything that defines the *look* flows from `theme-state.json`, the single
|
||||||
|
source of truth. Change it with `nomarchy-theme-sync`, which writes the JSON
|
||||||
|
and rebuilds — one generation, applied to Hyprland, Waybar, Ghostty, btop and
|
||||||
|
Stylix at once:
|
||||||
|
|
||||||
|
```sh
|
||||||
|
nomarchy-theme-sync set ui.gapsOut 16 # gaps, borders, rounding, opacity
|
||||||
|
nomarchy-theme-sync set ui.rounding 0
|
||||||
|
nomarchy-theme-sync set fonts.mono "FiraCode Nerd Font"
|
||||||
|
nomarchy-theme-sync apply gruvbox # whole palette
|
||||||
|
```
|
||||||
|
|
||||||
|
These values are deliberately kept at normal priority in the modules, so they
|
||||||
|
stay owned by the theme system. If you *insist* on pinning one in `home.nix`
|
||||||
|
regardless of the active theme, use `lib.mkForce` (see §4) — but then the CLI
|
||||||
|
can no longer change that knob.
|
||||||
|
|
||||||
|
## 2. Behaviour (input, misc, monitor, animations, terminal chrome) — `home.nix`
|
||||||
|
|
||||||
|
Non-appearance defaults are set with `lib.mkDefault`, so a **plain assignment**
|
||||||
|
in your `home.nix` wins — no `mkForce` needed:
|
||||||
|
|
||||||
|
```nix
|
||||||
|
# home.nix
|
||||||
|
{ ... }:
|
||||||
|
{
|
||||||
|
wayland.windowManager.hyprland.settings = {
|
||||||
|
input.follow_mouse = 0; # was 1
|
||||||
|
input.touchpad.natural_scroll = false;
|
||||||
|
misc.disable_splash_rendering = false;
|
||||||
|
monitor = [ "DP-1,2560x1440@144,0x0,1" ]; # replaces the default rule
|
||||||
|
animations.enabled = false;
|
||||||
|
};
|
||||||
|
|
||||||
|
programs.ghostty.settings = {
|
||||||
|
window-padding-x = 4; # was 12
|
||||||
|
window-decoration = true;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### Adding vs. overriding lists
|
||||||
|
|
||||||
|
`bind`, `bindel`, `bindl`, `bindm` and `exec-once` are lists kept at normal
|
||||||
|
priority, so anything you add **concatenates** with Nomarchy's — your binds and
|
||||||
|
autostarts run *alongside* the defaults:
|
||||||
|
|
||||||
|
```nix
|
||||||
|
{
|
||||||
|
wayland.windowManager.hyprland.settings = {
|
||||||
|
bind = [
|
||||||
|
"$mod, B, exec, firefox"
|
||||||
|
"$mod SHIFT, S, exec, grim -g \"$(slurp)\" - | swappy -f -"
|
||||||
|
];
|
||||||
|
exec-once = [ "nm-applet --indicator" ];
|
||||||
|
};
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
To **remove or replace** a default bind, override the whole `bind` list with
|
||||||
|
`lib.mkForce [ … ]` (you then own the full list), or rebind the key to
|
||||||
|
something else (last definition for a key wins in Hyprland).
|
||||||
|
|
||||||
|
You can also drop raw config that doesn't fit the Nix schema:
|
||||||
|
|
||||||
|
```nix
|
||||||
|
{ wayland.windowManager.hyprland.extraConfig = ''
|
||||||
|
bindl = , switch:Lid Switch, exec, hyprlock
|
||||||
|
'';
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### Waybar
|
||||||
|
|
||||||
|
For a themed bar identity, ship whole-swap assets
|
||||||
|
(`themes/<slug>/waybar.jsonc` and `waybar.css`) — see the main README. To
|
||||||
|
replace the bar wholesale from `home.nix`, assign `programs.waybar.settings.
|
||||||
|
mainBar` / `programs.waybar.style` (both `mkDefault`, so a plain assignment
|
||||||
|
wins). For a one-off tweak of a single generated key, `lib.mkForce` it.
|
||||||
|
|
||||||
|
## 3. Whole component — toggle it off and bring your own
|
||||||
|
|
||||||
|
Each desktop piece has an enable flag (all default `true`). Turn one off and
|
||||||
|
Nomarchy contributes nothing for it, leaving the field clear for your own:
|
||||||
|
|
||||||
|
```nix
|
||||||
|
# home.nix
|
||||||
|
{
|
||||||
|
nomarchy.hyprland.enable = false; # then write your own wayland.windowManager.hyprland
|
||||||
|
nomarchy.waybar.enable = false;
|
||||||
|
nomarchy.swaync.enable = false;
|
||||||
|
nomarchy.idle.enable = false; # no hyprlock/hypridle
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
```nix
|
||||||
|
# system.nix
|
||||||
|
{
|
||||||
|
nomarchy.system.plymouth.enable = false;
|
||||||
|
nomarchy.system.greeter.enable = false; # bring your own login manager
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
See the option tables in the README for the full list.
|
||||||
|
|
||||||
|
## 4. Last resort: `lib.mkForce`
|
||||||
|
|
||||||
|
To override a value Nomarchy sets at normal priority (an appearance value, or
|
||||||
|
a whole list), raise your definition's priority:
|
||||||
|
|
||||||
|
```nix
|
||||||
|
{ lib, ... }:
|
||||||
|
{
|
||||||
|
# hardcode rounding against the theme (the CLI can no longer change it)
|
||||||
|
wayland.windowManager.hyprland.settings.decoration.rounding = lib.mkForce 0;
|
||||||
|
|
||||||
|
# own the entire keybind list
|
||||||
|
wayland.windowManager.hyprland.settings.bind = lib.mkForce [ "$mod, Return, exec, kitty" ];
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
If a plain assignment errors with *"has conflicting definition values"*, that
|
||||||
|
value is theme-owned at normal priority — either change it via the CLI (§1) or
|
||||||
|
`mkForce` it here.
|
||||||
|
|
||||||
|
## Quick reference
|
||||||
|
|
||||||
|
| You want to… | Do this |
|
||||||
|
|---|---|
|
||||||
|
| Change gaps / colors / rounding / fonts | `nomarchy-theme-sync set …` or `apply` |
|
||||||
|
| Change input / misc / monitor / animations / terminal chrome | plain assignment in `home.nix` |
|
||||||
|
| Add keybinds / autostarts | add to the `bind` / `exec-once` list (concatenates) |
|
||||||
|
| Replace all keybinds | `bind = lib.mkForce [ … ]` |
|
||||||
|
| Hardcode an appearance value against the theme | `lib.mkForce` in `home.nix` |
|
||||||
|
| Drop a whole component | `nomarchy.<component>.enable = false` |
|
||||||
|
| Raw Hyprland lines | `wayland.windowManager.hyprland.extraConfig` |
|
||||||
@@ -30,12 +30,14 @@ in
|
|||||||
palette = lib.imap0 (i: color: "${toString i}=${color}") t.ansi;
|
palette = lib.imap0 (i: color: "${toString i}=${color}") t.ansi;
|
||||||
|
|
||||||
# ── Chrome ────────────────────────────────────────────────────
|
# ── Chrome ────────────────────────────────────────────────────
|
||||||
|
# background-opacity is theme-driven (normal priority — use the
|
||||||
|
# CLI); the rest are mkDefault so a plain home.nix value wins.
|
||||||
background-opacity = t.ui.terminalOpacity;
|
background-opacity = t.ui.terminalOpacity;
|
||||||
window-padding-x = 12;
|
window-padding-x = lib.mkDefault 12;
|
||||||
window-padding-y = 12;
|
window-padding-y = lib.mkDefault 12;
|
||||||
window-decoration = false;
|
window-decoration = lib.mkDefault false;
|
||||||
gtk-single-instance = true;
|
gtk-single-instance = lib.mkDefault true;
|
||||||
confirm-close-surface = false;
|
confirm-close-surface = lib.mkDefault false;
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -35,8 +35,13 @@ in
|
|||||||
"$mod" = "SUPER";
|
"$mod" = "SUPER";
|
||||||
"$terminal" = config.nomarchy.terminal;
|
"$terminal" = config.nomarchy.terminal;
|
||||||
|
|
||||||
monitor = [ ",preferred,auto,1" ];
|
# mkDefault so a downstream `monitor = [...]` replaces it with a
|
||||||
|
# plain assignment (the live ISO uses mkForce for the same reason).
|
||||||
|
monitor = lib.mkDefault [ ",preferred,auto,1" ];
|
||||||
|
|
||||||
|
# exec-once is a list at normal priority, so downstream additions
|
||||||
|
# CONCATENATE (your autostart runs alongside ours) rather than
|
||||||
|
# replace. Same for the bind* lists below.
|
||||||
exec-once = [
|
exec-once = [
|
||||||
# nixpkgs' swww is awww (renamed fork); the binary is awww-daemon.
|
# nixpkgs' swww is awww (renamed fork); the binary is awww-daemon.
|
||||||
"awww-daemon"
|
"awww-daemon"
|
||||||
@@ -46,14 +51,19 @@ in
|
|||||||
];
|
];
|
||||||
|
|
||||||
# ── Theme-driven look ──────────────────────────────────────────
|
# ── Theme-driven look ──────────────────────────────────────────
|
||||||
|
# These flow from theme-state.json and stay at NORMAL priority:
|
||||||
|
# change them with `nomarchy-theme-sync set ui.<key>` (the intended
|
||||||
|
# path), or lib.mkForce in home.nix to hardcode against the theme.
|
||||||
|
# The non-theme knobs around them are lib.mkDefault — override
|
||||||
|
# those with a plain home.nix assignment. See docs/OVERRIDES.md.
|
||||||
general = {
|
general = {
|
||||||
gaps_in = t.ui.gapsIn;
|
gaps_in = t.ui.gapsIn;
|
||||||
gaps_out = t.ui.gapsOut;
|
gaps_out = t.ui.gapsOut;
|
||||||
border_size = t.ui.borderSize;
|
border_size = t.ui.borderSize;
|
||||||
"col.active_border" = "${rgb c.accent} ${rgb c.accentAlt} 45deg";
|
"col.active_border" = "${rgb c.accent} ${rgb c.accentAlt} 45deg";
|
||||||
"col.inactive_border" = rgb c.overlay;
|
"col.inactive_border" = rgb c.overlay;
|
||||||
layout = "dwindle";
|
layout = lib.mkDefault "dwindle";
|
||||||
resize_on_border = true;
|
resize_on_border = lib.mkDefault true;
|
||||||
};
|
};
|
||||||
|
|
||||||
decoration = {
|
decoration = {
|
||||||
@@ -62,25 +72,26 @@ in
|
|||||||
inactive_opacity = t.ui.inactiveOpacity;
|
inactive_opacity = t.ui.inactiveOpacity;
|
||||||
blur = {
|
blur = {
|
||||||
enabled = t.ui.blur;
|
enabled = t.ui.blur;
|
||||||
size = 8;
|
size = lib.mkDefault 8;
|
||||||
passes = 2;
|
passes = lib.mkDefault 2;
|
||||||
popups = true;
|
popups = lib.mkDefault true;
|
||||||
};
|
};
|
||||||
shadow = {
|
shadow = {
|
||||||
enabled = t.ui.shadow;
|
enabled = t.ui.shadow;
|
||||||
range = 20;
|
range = lib.mkDefault 20;
|
||||||
render_power = 3;
|
render_power = lib.mkDefault 3;
|
||||||
color = rgba c.mantle "aa";
|
color = rgba c.mantle "aa";
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
|
# ── Behaviour (mkDefault → plain home.nix assignment overrides) ──
|
||||||
animations = {
|
animations = {
|
||||||
enabled = true;
|
enabled = lib.mkDefault true;
|
||||||
bezier = [
|
bezier = lib.mkDefault [
|
||||||
"smooth, 0.25, 0.1, 0.25, 1.0"
|
"smooth, 0.25, 0.1, 0.25, 1.0"
|
||||||
"snappy, 0.6, 0.0, 0.1, 1.0"
|
"snappy, 0.6, 0.0, 0.1, 1.0"
|
||||||
];
|
];
|
||||||
animation = [
|
animation = lib.mkDefault [
|
||||||
"windows, 1, 4, snappy, popin 85%"
|
"windows, 1, 4, snappy, popin 85%"
|
||||||
"border, 1, 8, smooth"
|
"border, 1, 8, smooth"
|
||||||
"fade, 1, 5, smooth"
|
"fade, 1, 5, smooth"
|
||||||
@@ -88,29 +99,30 @@ in
|
|||||||
];
|
];
|
||||||
};
|
};
|
||||||
|
|
||||||
# ── Behaviour ──────────────────────────────────────────────────
|
|
||||||
input = {
|
input = {
|
||||||
|
# kb_layout/variant come from nomarchy.keyboard.* — set that
|
||||||
|
# option (the installer writes it; it also drives tty/LUKS).
|
||||||
kb_layout = config.nomarchy.keyboard.layout;
|
kb_layout = config.nomarchy.keyboard.layout;
|
||||||
kb_variant = config.nomarchy.keyboard.variant;
|
kb_variant = config.nomarchy.keyboard.variant;
|
||||||
follow_mouse = 1;
|
follow_mouse = lib.mkDefault 1;
|
||||||
touchpad.natural_scroll = true;
|
touchpad.natural_scroll = lib.mkDefault true;
|
||||||
};
|
};
|
||||||
|
|
||||||
# dwindle:pseudotile was removed in Hyprland 0.55 (the `pseudo`
|
# dwindle:pseudotile was removed in Hyprland 0.55 (the `pseudo`
|
||||||
# dispatcher still exists); setting it aborts config parsing.
|
# dispatcher still exists); setting it aborts config parsing.
|
||||||
dwindle.preserve_split = true;
|
dwindle.preserve_split = lib.mkDefault true;
|
||||||
|
|
||||||
# Hyprland 0.51+ replaced gestures:workspace_swipe with the
|
# Hyprland 0.51+ replaced gestures:workspace_swipe with the
|
||||||
# gesture keyword — without this, touchpads have NO gestures.
|
# gesture keyword — without this, touchpads have NO gestures.
|
||||||
gesture = [
|
gesture = lib.mkDefault [
|
||||||
"3, horizontal, workspace"
|
"3, horizontal, workspace"
|
||||||
"4, pinch, fullscreen"
|
"4, pinch, fullscreen"
|
||||||
];
|
];
|
||||||
|
|
||||||
misc = {
|
misc = {
|
||||||
disable_hyprland_logo = true;
|
disable_hyprland_logo = lib.mkDefault true;
|
||||||
disable_splash_rendering = true;
|
disable_splash_rendering = lib.mkDefault true;
|
||||||
force_default_wallpaper = 0;
|
force_default_wallpaper = lib.mkDefault 0;
|
||||||
};
|
};
|
||||||
|
|
||||||
bind = [
|
bind = [
|
||||||
|
|||||||
@@ -145,14 +145,21 @@ in
|
|||||||
enable = true;
|
enable = true;
|
||||||
systemd.enable = true; # started/stopped with graphical-session.target
|
systemd.enable = true; # started/stopped with graphical-session.target
|
||||||
|
|
||||||
settings.mainBar =
|
# mkDefault so downstream can replace the whole bar config/style with
|
||||||
|
# a plain home.nix assignment. For per-theme identity, prefer the
|
||||||
|
# whole-swap assets (themes/<slug>/waybar.{jsonc,css}); for one-off
|
||||||
|
# tweaks of the generated bar, lib.mkForce a sub-key. See
|
||||||
|
# docs/OVERRIDES.md.
|
||||||
|
settings.mainBar = lib.mkDefault (
|
||||||
if hasConfigOverride
|
if hasConfigOverride
|
||||||
then builtins.fromJSON (builtins.readFile configOverride)
|
then builtins.fromJSON (builtins.readFile configOverride)
|
||||||
else generatedSettings;
|
else generatedSettings
|
||||||
|
);
|
||||||
|
|
||||||
style =
|
style = lib.mkDefault (
|
||||||
if hasStyleOverride
|
if hasStyleOverride
|
||||||
then builtins.readFile styleOverride
|
then builtins.readFile styleOverride
|
||||||
else generatedStyle;
|
else generatedStyle
|
||||||
|
);
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user