diff --git a/README.md b/README.md index e78e6f6..450ff6a 100644 --- a/README.md +++ b/README.md @@ -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) ├── templates/downstream/ # `nix flake init -t` starter for users ├── docs/TESTING.md # how to verify changes (incl. AI-agent rules) +├── docs/OVERRIDES.md # how downstream users override defaults └── tools/ # maintainer-only ├── import-palettes.py # converts old-distro themes → JSON + assets ├── 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) ``` -Override anything with plain NixOS/HM options (the distro uses `mkDefault` -throughout) or the `nomarchy.*` surface: +Override anything via the `nomarchy.*` surface or plain NixOS/HM options: +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 | |---|---|---| diff --git a/docs/OVERRIDES.md b/docs/OVERRIDES.md new file mode 100644 index 0000000..cc917d3 --- /dev/null +++ b/docs/OVERRIDES.md @@ -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//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..enable = false` | +| Raw Hyprland lines | `wayland.windowManager.hyprland.extraConfig` | diff --git a/modules/home/ghostty.nix b/modules/home/ghostty.nix index 01c45f5..1c54715 100644 --- a/modules/home/ghostty.nix +++ b/modules/home/ghostty.nix @@ -30,12 +30,14 @@ in palette = lib.imap0 (i: color: "${toString i}=${color}") t.ansi; # ── 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; - window-padding-x = 12; - window-padding-y = 12; - window-decoration = false; - gtk-single-instance = true; - confirm-close-surface = false; + window-padding-x = lib.mkDefault 12; + window-padding-y = lib.mkDefault 12; + window-decoration = lib.mkDefault false; + gtk-single-instance = lib.mkDefault true; + confirm-close-surface = lib.mkDefault false; }; }; } diff --git a/modules/home/hyprland.nix b/modules/home/hyprland.nix index c567e83..542e7fd 100644 --- a/modules/home/hyprland.nix +++ b/modules/home/hyprland.nix @@ -35,8 +35,13 @@ in "$mod" = "SUPER"; "$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 = [ # nixpkgs' swww is awww (renamed fork); the binary is awww-daemon. "awww-daemon" @@ -46,14 +51,19 @@ in ]; # ── Theme-driven look ────────────────────────────────────────── + # These flow from theme-state.json and stay at NORMAL priority: + # change them with `nomarchy-theme-sync set ui.` (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 = { gaps_in = t.ui.gapsIn; gaps_out = t.ui.gapsOut; border_size = t.ui.borderSize; "col.active_border" = "${rgb c.accent} ${rgb c.accentAlt} 45deg"; "col.inactive_border" = rgb c.overlay; - layout = "dwindle"; - resize_on_border = true; + layout = lib.mkDefault "dwindle"; + resize_on_border = lib.mkDefault true; }; decoration = { @@ -62,25 +72,26 @@ in inactive_opacity = t.ui.inactiveOpacity; blur = { enabled = t.ui.blur; - size = 8; - passes = 2; - popups = true; + size = lib.mkDefault 8; + passes = lib.mkDefault 2; + popups = lib.mkDefault true; }; shadow = { enabled = t.ui.shadow; - range = 20; - render_power = 3; + range = lib.mkDefault 20; + render_power = lib.mkDefault 3; color = rgba c.mantle "aa"; }; }; + # ── Behaviour (mkDefault → plain home.nix assignment overrides) ── animations = { - enabled = true; - bezier = [ + enabled = lib.mkDefault true; + bezier = lib.mkDefault [ "smooth, 0.25, 0.1, 0.25, 1.0" "snappy, 0.6, 0.0, 0.1, 1.0" ]; - animation = [ + animation = lib.mkDefault [ "windows, 1, 4, snappy, popin 85%" "border, 1, 8, smooth" "fade, 1, 5, smooth" @@ -88,29 +99,30 @@ in ]; }; - # ── Behaviour ────────────────────────────────────────────────── 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_variant = config.nomarchy.keyboard.variant; - follow_mouse = 1; - touchpad.natural_scroll = true; + follow_mouse = lib.mkDefault 1; + touchpad.natural_scroll = lib.mkDefault true; }; # dwindle:pseudotile was removed in Hyprland 0.55 (the `pseudo` # 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 # gesture keyword — without this, touchpads have NO gestures. - gesture = [ + gesture = lib.mkDefault [ "3, horizontal, workspace" "4, pinch, fullscreen" ]; misc = { - disable_hyprland_logo = true; - disable_splash_rendering = true; - force_default_wallpaper = 0; + disable_hyprland_logo = lib.mkDefault true; + disable_splash_rendering = lib.mkDefault true; + force_default_wallpaper = lib.mkDefault 0; }; bind = [ diff --git a/modules/home/waybar.nix b/modules/home/waybar.nix index 2770db0..00cf348 100644 --- a/modules/home/waybar.nix +++ b/modules/home/waybar.nix @@ -145,14 +145,21 @@ in enable = true; 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//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 then builtins.fromJSON (builtins.readFile configOverride) - else generatedSettings; + else generatedSettings + ); - style = + style = lib.mkDefault ( if hasStyleOverride then builtins.readFile styleOverride - else generatedStyle; + else generatedStyle + ); }; }