diff --git a/modules/services/window-managers/hyprland.nix b/modules/services/window-managers/hyprland.nix index 4401998f6..4f1c9e929 100644 --- a/modules/services/window-managers/hyprland.nix +++ b/modules/services/window-managers/hyprland.nix @@ -9,7 +9,6 @@ let systemdActivation = '' exec-once = ${pkgs.dbus}/bin/dbus-update-activation-environment --systemd ${variables} ${extraCommands} ''; - in { meta.maintainers = [ lib.maintainers.fufexan ]; @@ -178,6 +177,16 @@ in { '' // { default = true; }; + + importantPrefixes = lib.mkOption { + type = with lib.types; listOf str; + default = [ "$" "bezier" "name" ] + ++ lib.optionals cfg.sourceFirst [ "source" ]; + example = [ "$" "bezier" ]; + description = '' + List of prefix of attributes to source at the top of the config. + ''; + }; }; config = lib.mkIf cfg.enable { @@ -199,65 +208,28 @@ in { shouldGenerate = cfg.systemd.enable || cfg.extraConfig != "" || cfg.settings != { } || cfg.plugins != [ ]; - toHyprconf = with lib; - attrs: indentLevel: - let - indent = concatStrings (replicate indentLevel " "); - - sections = filterAttrs (n: v: isAttrs v && n != "device") attrs; - - mkSection = n: attrs: '' - ${indent}${n} { - ${toHyprconf attrs (indentLevel + 1)}${indent}} - ''; - - mkDeviceCategory = device: '' - ${indent}device { - name=${device.name} - ${ - toHyprconf (filterAttrs (n: _: "name" != n) device) - (indentLevel + 1) - }${indent}} - ''; - - deviceCategory = lib.optionalString (hasAttr "device" attrs) - (if isList attrs.device then - (concatMapStringsSep "\n" (d: mkDeviceCategory d) attrs.device) - else - mkDeviceCategory attrs.device); - - mkFields = generators.toKeyValue { - listsAsDuplicateKeys = true; - inherit indent; - }; - allFields = filterAttrs (n: v: !(isAttrs v) && n != "device") attrs; - - importantFields = filterAttrs (n: _: - (hasPrefix "$" n) || (hasPrefix "bezier" n) - || (cfg.sourceFirst && (hasPrefix "source" n))) allFields; - - fields = builtins.removeAttrs allFields - (mapAttrsToList (n: _: n) importantFields); - in mkFields importantFields + deviceCategory - + concatStringsSep "\n" (mapAttrsToList mkSection sections) - + mkFields fields; - pluginsToHyprconf = plugins: - toHyprconf { - plugin = let - mkEntry = entry: - if lib.types.package.check entry then - "${entry}/lib/lib${entry.pname}.so" - else - entry; - in map mkEntry cfg.plugins; - } 0; + lib.hm.generators.toHyprconf { + attrs = { + plugin = let + mkEntry = entry: + if lib.types.package.check entry then + "${entry}/lib/lib${entry.pname}.so" + else + entry; + in map mkEntry cfg.plugins; + }; + inherit (cfg) importantPrefixes; + }; in lib.mkIf shouldGenerate { text = lib.optionalString cfg.systemd.enable systemdActivation + lib.optionalString (cfg.plugins != [ ]) (pluginsToHyprconf cfg.plugins) - + lib.optionalString (cfg.settings != { }) (toHyprconf cfg.settings 0) - + lib.optionalString (cfg.extraConfig != "") cfg.extraConfig; + + lib.optionalString (cfg.settings != { }) + (lib.hm.generators.toHyprconf { + attrs = cfg.settings; + inherit (cfg) importantPrefixes; + }) + lib.optionalString (cfg.extraConfig != "") cfg.extraConfig; onChange = lib.mkIf (cfg.package != null) '' ( # Execute in subshell so we don't poision environment with vars diff --git a/tests/modules/services/window-managers/hyprland/default.nix b/tests/modules/services/window-managers/hyprland/default.nix index 96cae5e45..ae431939c 100644 --- a/tests/modules/services/window-managers/hyprland/default.nix +++ b/tests/modules/services/window-managers/hyprland/default.nix @@ -1,4 +1,6 @@ { hyprland-simple-config = ./simple-config.nix; + hyprland-multiple-devices-config = ./multiple-devices-config.nix; + hyprland-sourceFirst-false-config = ./sourceFirst-false-config.nix; hyprland-inconsistent-config = ./inconsistent-config.nix; } diff --git a/tests/modules/services/window-managers/hyprland/multiple-devices-config.conf b/tests/modules/services/window-managers/hyprland/multiple-devices-config.conf new file mode 100644 index 000000000..5d9102973 --- /dev/null +++ b/tests/modules/services/window-managers/hyprland/multiple-devices-config.conf @@ -0,0 +1,60 @@ +exec-once = /nix/store/00000000000000000000000000000000-dbus/bin/dbus-update-activation-environment --systemd DISPLAY HYPRLAND_INSTANCE_SIGNATURE WAYLAND_DISPLAY XDG_CURRENT_DESKTOP && systemctl --user stop hyprland-session.target && systemctl --user start hyprland-session.target +plugin=/path/to/plugin1 +plugin=/nix/store/00000000000000000000000000000000-foo/lib/libfoo.so +$mod=SUPER +bezier=smoothOut, 0.36, 0, 0.66, -0.56 +bezier=smoothIn, 0.25, 1, 0.5, 1 +bezier=overshot, 0.4,0.8,0.2,1.2 +source=sourced.conf +animations { + animation=border, 1, 2, smoothIn + animation=fade, 1, 4, smoothOut + animation=windows, 1, 3, overshot, popin 80% + enabled=true +} + +decoration { + col.shadow=rgba(00000099) + shadow_offset=0 5 +} + +device { + name=some:device + enable=true +} + +device { + name=some:device-secondary + enable=true +} + +input { + touchpad { + scroll_factor=0.300000 + } + accel_profile=flat + follow_mouse=1 + kb_layout=ro +} + +plugin { + plugin1 { + section { + other=dummy setting + } + dummy=plugin setting + } +} +bindm=$mod, mouse:272, movewindow +bindm=$mod, mouse:273, resizewindow +bindm=$mod ALT, mouse:272, resizewindow +# window resize +bind = $mod, S, submap, resize + +submap = resize +binde = , right, resizeactive, 10 0 +binde = , left, resizeactive, -10 0 +binde = , up, resizeactive, 0 -10 +binde = , down, resizeactive, 0 10 +bind = , escape, submap, reset +submap = reset diff --git a/tests/modules/services/window-managers/hyprland/multiple-devices-config.nix b/tests/modules/services/window-managers/hyprland/multiple-devices-config.nix new file mode 100644 index 000000000..86d60c632 --- /dev/null +++ b/tests/modules/services/window-managers/hyprland/multiple-devices-config.nix @@ -0,0 +1,88 @@ +{ config, lib, ... }: + +{ + wayland.windowManager.hyprland = { + enable = true; + package = lib.makeOverridable + (attrs: config.lib.test.mkStubPackage { name = "hyprland"; }) { }; + plugins = + [ "/path/to/plugin1" (config.lib.test.mkStubPackage { name = "foo"; }) ]; + settings = { + source = [ "sourced.conf" ]; + + decoration = { + shadow_offset = "0 5"; + "col.shadow" = "rgba(00000099)"; + }; + + "$mod" = "SUPER"; + + animations = { + enabled = true; + animation = [ + "border, 1, 2, smoothIn" + "fade, 1, 4, smoothOut" + "windows, 1, 3, overshot, popin 80%" + ]; + }; + + bezier = [ + "smoothOut, 0.36, 0, 0.66, -0.56" + "smoothIn, 0.25, 1, 0.5, 1" + "overshot, 0.4,0.8,0.2,1.2" + ]; + + input = { + kb_layout = "ro"; + follow_mouse = 1; + accel_profile = "flat"; + touchpad = { scroll_factor = 0.3; }; + }; + + bindm = [ + # mouse movements + "$mod, mouse:272, movewindow" + "$mod, mouse:273, resizewindow" + "$mod ALT, mouse:272, resizewindow" + ]; + + device = [ + { + name = "some:device"; + enable = true; + } + { + name = "some:device-secondary"; + enable = true; + } + ]; + + plugin = { + plugin1 = { + dummy = "plugin setting"; + section = { other = "dummy setting"; }; + }; + }; + }; + extraConfig = '' + # window resize + bind = $mod, S, submap, resize + + submap = resize + binde = , right, resizeactive, 10 0 + binde = , left, resizeactive, -10 0 + binde = , up, resizeactive, 0 -10 + binde = , down, resizeactive, 0 10 + bind = , escape, submap, reset + submap = reset + ''; + }; + + nmt.script = '' + config=home-files/.config/hypr/hyprland.conf + assertFileExists "$config" + + normalizedConfig=$(normalizeStorePaths "$config") + assertFileContent "$normalizedConfig" ${./multiple-devices-config.conf} + ''; +} diff --git a/tests/modules/services/window-managers/hyprland/simple-config.conf b/tests/modules/services/window-managers/hyprland/simple-config.conf index 9b15ba32a..29dcd7cd8 100644 --- a/tests/modules/services/window-managers/hyprland/simple-config.conf +++ b/tests/modules/services/window-managers/hyprland/simple-config.conf @@ -6,10 +6,6 @@ bezier=smoothOut, 0.36, 0, 0.66, -0.56 bezier=smoothIn, 0.25, 1, 0.5, 1 bezier=overshot, 0.4,0.8,0.2,1.2 source=sourced.conf -device { - name=some:device - enable=true -} animations { animation=border, 1, 2, smoothIn animation=fade, 1, 4, smoothOut @@ -22,6 +18,11 @@ decoration { shadow_offset=0 5 } +device { + name=some:device + enable=true +} + input { touchpad { scroll_factor=0.300000 diff --git a/tests/modules/services/window-managers/hyprland/sourceFirst-false-config.conf b/tests/modules/services/window-managers/hyprland/sourceFirst-false-config.conf new file mode 100644 index 000000000..3dc8c39c0 --- /dev/null +++ b/tests/modules/services/window-managers/hyprland/sourceFirst-false-config.conf @@ -0,0 +1,13 @@ +exec-once = /nix/store/00000000000000000000000000000000-dbus/bin/dbus-update-activation-environment --systemd DISPLAY HYPRLAND_INSTANCE_SIGNATURE WAYLAND_DISPLAY XDG_CURRENT_DESKTOP && systemctl --user stop hyprland-session.target && systemctl --user start hyprland-session.target +bezier=smoothOut, 0.36, 0, 0.66, -0.56 +bezier=smoothIn, 0.25, 1, 0.5, 1 +bezier=overshot, 0.4,0.8,0.2,1.2 +input { + touchpad { + scroll_factor=0.300000 + } + accel_profile=flat + follow_mouse=1 + kb_layout=ro +} +source=sourced.conf diff --git a/tests/modules/services/window-managers/hyprland/sourceFirst-false-config.nix b/tests/modules/services/window-managers/hyprland/sourceFirst-false-config.nix new file mode 100644 index 000000000..4161cd751 --- /dev/null +++ b/tests/modules/services/window-managers/hyprland/sourceFirst-false-config.nix @@ -0,0 +1,34 @@ +{ config, lib, ... }: + +{ + wayland.windowManager.hyprland = { + enable = true; + package = lib.makeOverridable + (attrs: config.lib.test.mkStubPackage { name = "hyprland"; }) { }; + settings = { + source = [ "sourced.conf" ]; + + bezier = [ + "smoothOut, 0.36, 0, 0.66, -0.56" + "smoothIn, 0.25, 1, 0.5, 1" + "overshot, 0.4,0.8,0.2,1.2" + ]; + + input = { + kb_layout = "ro"; + follow_mouse = 1; + accel_profile = "flat"; + touchpad = { scroll_factor = 0.3; }; + }; + }; + sourceFirst = false; + }; + + nmt.script = '' + config=home-files/.config/hypr/hyprland.conf + assertFileExists "$config" + + normalizedConfig=$(normalizeStorePaths "$config") + assertFileContent "$normalizedConfig" ${./sourceFirst-false-config.conf} + ''; +}