diff --git a/modules/services/kanshi.nix b/modules/services/kanshi.nix index 02fe8e3cf..1e6950304 100644 --- a/modules/services/kanshi.nix +++ b/modules/services/kanshi.nix @@ -6,6 +6,48 @@ let cfg = config.services.kanshi; + directivesTag = types.attrTag { + profile = mkOption { + type = profileModule; + description = '' + profile attribute set. + ''; + }; + output = mkOption { + type = outputModule; + description = '' + output attribute set. + ''; + }; + include = mkOption { + type = types.str; + description = '' + Include as another file from _path_. + Expands shell syntax (see *wordexp*(3) for details). + ''; + }; + }; + + tagToStr = x: + if x ? profile then + profileStr x.profile + else if x ? output then + outputStr x.output + else if x ? include then + ''include "${x.include}"'' + else + throw "Unknown tags ${attrNames x}"; + + directivesStr = '' + ${concatStringsSep "\n" (map tagToStr cfg.settings)} + ''; + + oldDirectivesStr = '' + ${concatStringsSep "\n" + (mapAttrsToList (n: v: profileStr (v // { name = n; })) cfg.profiles)} + ${cfg.extraConfig} + ''; + outputModule = types.submodule { options = { @@ -113,6 +155,14 @@ let ''; }; + name = mkOption { + type = types.str; + default = ""; + description = '' + Profile name + ''; + }; + exec = mkOption { type = with types; coercedTo str singleton (listOf str); default = [ ]; @@ -127,15 +177,14 @@ let }; }; - profileStr = name: - { outputs, exec, ... }: '' - profile ${name} { - ${ - concatStringsSep "\n " - (map outputStr outputs ++ map (cmd: "exec ${cmd}") exec) - } + profileStr = { outputs, exec, ... }@args: '' + profile ${args.name or ""} { + ${ + concatStringsSep "\n " + (map outputStr outputs ++ map (cmd: "exec ${cmd}") exec) } - ''; + } + ''; in { meta.maintainers = [ hm.maintainers.nurelin ]; @@ -157,7 +206,7 @@ in { type = types.attrsOf profileModule; default = { }; description = '' - List of profiles. + Attribute set of profiles. ''; example = literalExpression '' undocked = { @@ -190,6 +239,39 @@ in { ''; }; + settings = mkOption { + type = types.listOf directivesTag; + default = [ ]; + description = '' + Ordered list of directives. + See kanshi(5) for informations. + ''; + example = literalExpression '' + { include = "path/to/included/files"; } + { output.criteria = "eDP-1"; + output.scale = 2; + } + { profile.name = "undocked"; + profile.outputs = [ + { + criteria = "eDP-1"; + } + ]; + } + { profile.name = "docked"; + profile.outputs = [ + { + criteria = "eDP-1"; + } + { + criteria = "Some Company ASDF 4242"; + transform = "90"; + } + ]; + } + ''; + }; + systemdTarget = mkOption { type = types.str; default = "sway-session.target"; @@ -199,33 +281,56 @@ in { }; }; - config = mkIf cfg.enable { - assertions = [ - (lib.hm.assertions.assertPlatform "services.kanshi" pkgs - lib.platforms.linux) - ]; + config = mkIf cfg.enable (mkMerge [ + { + assertions = [ + (lib.hm.assertions.assertPlatform "services.kanshi" pkgs + lib.platforms.linux) + { + assertion = (cfg.profiles == { } && cfg.extraConfig == "") + || (length cfg.settings) == 0; + message = + "Cannot mix kanshi.settings with kanshi.profiles or kanshi.extraConfig"; + } + ]; + } - xdg.configFile."kanshi/config".text = '' - ${concatStringsSep "\n" (mapAttrsToList profileStr cfg.profiles)} - ${cfg.extraConfig} - ''; + (mkIf (cfg.profiles != { }) { + warnings = [ + "kanshi.profiles option is deprecated. Use kanshi.settings instead." + ]; + }) - systemd.user.services.kanshi = { - Unit = { - Description = "Dynamic output configuration"; - Documentation = "man:kanshi(1)"; - PartOf = cfg.systemdTarget; - Requires = cfg.systemdTarget; - After = cfg.systemdTarget; + (mkIf (cfg.extraConfig != "") { + warnings = [ + "kanshi.extraConfig option is deprecated. Use kanshi.settings instead." + ]; + }) + + { + xdg.configFile."kanshi/config".text = + if cfg.profiles == { } && cfg.extraConfig == "" then + directivesStr + else + oldDirectivesStr; + + systemd.user.services.kanshi = { + Unit = { + Description = "Dynamic output configuration"; + Documentation = "man:kanshi(1)"; + PartOf = cfg.systemdTarget; + Requires = cfg.systemdTarget; + After = cfg.systemdTarget; + }; + + Service = { + Type = "simple"; + ExecStart = "${cfg.package}/bin/kanshi"; + Restart = "always"; + }; + + Install = { WantedBy = [ cfg.systemdTarget ]; }; }; - - Service = { - Type = "simple"; - ExecStart = "${cfg.package}/bin/kanshi"; - Restart = "always"; - }; - - Install = { WantedBy = [ cfg.systemdTarget ]; }; - }; - }; + } + ]); } diff --git a/tests/modules/services/kanshi/basic-configuration.nix b/tests/modules/services/kanshi/basic-configuration.nix index c5706e635..ffb6db7b1 100644 --- a/tests/modules/services/kanshi/basic-configuration.nix +++ b/tests/modules/services/kanshi/basic-configuration.nix @@ -47,6 +47,11 @@ ''; }; + test.asserts.warnings.expected = [ + "kanshi.profiles option is deprecated. Use kanshi.settings instead." + "kanshi.extraConfig option is deprecated. Use kanshi.settings instead." + ]; + nmt.script = '' serviceFile=home-files/.config/systemd/user/kanshi.service assertFileExists $serviceFile diff --git a/tests/modules/services/kanshi/default.nix b/tests/modules/services/kanshi/default.nix index cb6b2a6b7..b7704b112 100644 --- a/tests/modules/services/kanshi/default.nix +++ b/tests/modules/services/kanshi/default.nix @@ -1 +1,4 @@ -{ kanshi-basic-configuration = ./basic-configuration.nix; } +{ + kanshi-basic-configuration = ./basic-configuration.nix; + kanshi-new-configuration = ./new-configuration.nix; +} diff --git a/tests/modules/services/kanshi/new-configuration.conf b/tests/modules/services/kanshi/new-configuration.conf new file mode 100644 index 000000000..c0858a048 --- /dev/null +++ b/tests/modules/services/kanshi/new-configuration.conf @@ -0,0 +1,19 @@ +include "path/to/included/file" +output "*" enable +profile nomad { + output "eDP-1" enable +} + +profile desktop { + output "eDP-1" disable + output "Iiyama North America PLE2483H-DP" enable position 0,0 + output "Iiyama North America PLE2483H-DP 1158765348486" enable mode 1920x1080 position 1920,0 scale 2.100000 transform flipped-270 + exec echo "1 two 3" + exec echo "4 five 6" +} + +profile { + output "LVDS-1" enable + exec echo "7 eight 9" +} + diff --git a/tests/modules/services/kanshi/new-configuration.nix b/tests/modules/services/kanshi/new-configuration.nix new file mode 100644 index 000000000..9b3a36478 --- /dev/null +++ b/tests/modules/services/kanshi/new-configuration.nix @@ -0,0 +1,63 @@ +{ config, pkgs, ... }: { + config = { + services.kanshi = { + enable = true; + package = config.lib.test.mkStubPackage { }; + settings = [ + { include = "path/to/included/file"; } + { + output = { + criteria = "*"; + status = "enable"; + }; + } + { + profile.name = "nomad"; + profile.outputs = [{ + criteria = "eDP-1"; + status = "enable"; + }]; + } + { + profile.name = "desktop"; + profile.exec = [ ''echo "1 two 3"'' ''echo "4 five 6"'' ]; + profile.outputs = [ + { + criteria = "eDP-1"; + status = "disable"; + } + { + criteria = "Iiyama North America PLE2483H-DP"; + status = "enable"; + position = "0,0"; + } + { + criteria = "Iiyama North America PLE2483H-DP 1158765348486"; + status = "enable"; + position = "1920,0"; + scale = 2.1; + mode = "1920x1080"; + transform = "flipped-270"; + } + ]; + } + { + profile.outputs = [{ + criteria = "LVDS-1"; + status = "enable"; + }]; + profile.exec = ''echo "7 eight 9"''; + } + ]; + }; + + nmt.script = '' + serviceFile=home-files/.config/systemd/user/kanshi.service + assertFileExists $serviceFile + + assertFileExists home-files/.config/kanshi/config + assertFileContent home-files/.config/kanshi/config \ + ${./new-configuration.conf} + ''; + }; +}