diff --git a/modules/services/mako.nix b/modules/services/mako.nix index 40edcce4f..88d74aba8 100644 --- a/modules/services/mako.nix +++ b/modules/services/mako.nix @@ -5,371 +5,139 @@ ... }: let - inherit (lib) mkOption types; + inherit (lib) + types + mkIf + mkEnableOption + mkPackageOption + mkOption + ; cfg = config.services.mako; + generateConfig = lib.generators.toINIWithGlobalSection { }; + settingsType = with types; attrsOf str; + criteriasType = types.attrsOf settingsType; in { meta.maintainers = [ lib.maintainers.onny ]; - imports = [ (lib.mkRenamedOptionModule [ "programs" "mako" ] [ "services" "mako" ]) ]; + imports = + let + basePath = [ + "services" + "mako" + ]; - options = { - services.mako = { - enable = lib.mkEnableOption '' - Mako, lightweight notification daemon for Wayland + removedOptions = [ + (lib.mkRemovedOptionModule [ + "services" + "mako" + "extraConfig" + ] "Use services.mako.settings instead.") + ]; + + renamedOptions = [ + "maxVisible" + "maxHistory" + "sort" + "output" + "layer" + "anchor" + "font" + "backgroundColor" + "textColor" + "width" + "height" + "margin" + "padding" + "borderSize" + "borderColor" + "borderRadius" + "progressColor" + "icons" + "maxIconSize" + "iconPath" + "markup" + "actions" + "format" + "defaultTimeout" + "ignoreTimeout" + "groupBy" + ]; + + mkSettingsRenamedOptionModules = + oldPrefix: newPrefix: + map (option: lib.mkRenamedOptionModule (oldPrefix ++ [ option ]) (newPrefix ++ [ option ])); + in + removedOptions + ++ mkSettingsRenamedOptionModules basePath (basePath ++ [ "settings" ]) renamedOptions; + + options.services.mako = { + enable = mkEnableOption "mako"; + package = mkPackageOption pkgs "mako" { }; + settings = mkOption { + type = settingsType; + default = { }; + example = '' + { + actions = "true"; + anchor = "top-right"; + backgroundColor = "#000000"; + borderColor = "#FFFFFF"; + borderRadius = "0"; + defaultTimeout = "0"; + font = "monospace 10"; + height = "100"; + width = "300"; + icons = "true"; + ignoreTimeout = "false"; + layer = "top"; + margin = "10"; + markup = "true"; + } ''; + description = '' + Configuration settings for mako. All available options can be found + here: . + ''; + }; + criterias = mkOption { + type = criteriasType; + default = { }; + example = { + "actionable=true" = { + anchor = "top-left"; + }; - package = mkOption { - type = types.package; - default = pkgs.mako; - defaultText = lib.literalExpression "pkgs.mako"; - description = "The mako package to use."; - }; - - maxVisible = mkOption { - default = 5; - type = types.nullOr types.int; - description = '' - Set maximum number of visible notifications. Set -1 to show all. - ''; - }; - - maxHistory = mkOption { - default = 5; - type = types.nullOr types.int; - description = '' - Set maximum number of expired notifications to keep in the history - buffer. Set 0 to disable history. - ''; - }; - - sort = mkOption { - default = "-time"; - type = types.nullOr ( - types.enum [ - "+time" - "-time" - "+priority" - "-priority" - ] - ); - description = '' - Sorts incoming notifications by time and/or priority in ascending(+) - or descending(-) order. - ''; - }; - - output = mkOption { - default = null; - type = types.nullOr types.str; - description = '' - Show notifications on the specified output. If empty, notifications - will appear on the focused output. Requires the compositor to support - the Wayland protocol xdg-output-unstable-v1 version 2. - ''; - }; - - layer = mkOption { - default = "top"; - type = types.nullOr ( - types.enum [ - "background" - "bottom" - "top" - "overlay" - ] - ); - description = '' - Arrange mako at the specified layer, relative to normal windows. - Supported values are background, bottom, top, and overlay. Using - overlay will cause notifications to be displayed above fullscreen - windows, though this may also occur at top depending on your - compositor. - ''; - }; - - anchor = mkOption { - default = "top-right"; - type = types.nullOr ( - types.enum [ - "top-right" - "top-center" - "top-left" - "bottom-right" - "bottom-center" - "bottom-left" - "center-right" - "center-left" - "center" - ] - ); - description = '' - Show notifications at the specified position on the output. - Supported values are top-right, top-center, top-left, bottom-right, - bottom-center, bottom-left, center-right, center-left and center. - ''; - }; - - font = mkOption { - default = "monospace 10"; - type = types.nullOr types.str; - description = '' - Font to use, in Pango format. - ''; - }; - - backgroundColor = mkOption { - default = "#285577FF"; - type = types.nullOr types.str; - description = '' - Set popup background color to a specific color, represented in hex - color code. - ''; - }; - - textColor = mkOption { - default = "#FFFFFFFF"; - type = types.nullOr types.str; - description = '' - Set popup text color to a specific color, represented in hex color - code. - ''; - }; - - width = mkOption { - default = 300; - type = types.nullOr types.int; - description = '' - Set width of notification popups in specified number of pixels. - ''; - }; - - height = mkOption { - default = 100; - type = types.nullOr types.int; - description = '' - Set maximum height of notification popups. Notifications whose text - takes up less space are shrunk to fit. - ''; - }; - - margin = mkOption { - default = "10"; - type = types.nullOr types.str; - description = '' - Set margin of each edge specified in pixels. Specify single value to - apply margin on all sides. Two comma-separated values will set - vertical and horizontal edges separately. Four comma-separated will - give each edge a separate value. - For example: 10,20,5 will set top margin to 10, left and right to 20 - and bottom to five. - ''; - }; - - padding = mkOption { - default = "5"; - type = types.nullOr types.str; - description = '' - Set padding of each edge specified in pixels. Specify single value to - apply margin on all sides. Two comma-separated values will set - vertical and horizontal edges separately. Four comma-separated will - give each edge a separate value. - For example: 10,20,5 will set top margin to 10, left and right to 20 - and bottom to five. - ''; - }; - - borderSize = mkOption { - default = 1; - type = types.nullOr types.int; - description = '' - Set popup border size to the specified number of pixels. - ''; - }; - - borderColor = mkOption { - default = "#4C7899FF"; - type = types.nullOr types.str; - description = '' - Set popup border color to a specific color, represented in hex color - code. - ''; - }; - - borderRadius = mkOption { - default = 0; - type = types.nullOr types.int; - description = '' - Set popup corner radius to the specified number of pixels. - ''; - }; - - progressColor = mkOption { - default = "over #5588AAFF"; - type = types.nullOr types.str; - description = '' - Set popup progress indicator color to a specific color, - represented in hex color code. To draw the progress - indicator on top of the background color, use the - `over` attribute. To replace the background - color, use the `source` attribute (this can - be useful when the notification is semi-transparent). - ''; - }; - - icons = mkOption { - default = true; - type = types.nullOr types.bool; - description = '' - Whether or not to show icons in notifications. - ''; - }; - - maxIconSize = mkOption { - default = 64; - type = types.nullOr types.int; - description = '' - Set maximum icon size to the specified number of pixels. - ''; - }; - - iconPath = mkOption { - default = null; - type = types.nullOr types.str; - description = '' - Paths to search for icons when a notification specifies a name - instead of a full path. Colon-delimited. This approximates the search - algorithm used by the XDG Icon Theme Specification, but does not - support any of the theme metadata. Therefore, if you want to search - parent themes, you'll need to add them to the path manually. - - The {file}`/usr/share/icons/hicolor` and - {file}`/usr/share/pixmaps` directories are - always searched. - ''; - }; - - markup = mkOption { - default = true; - type = types.nullOr types.bool; - description = '' - If 1, enable Pango markup. If 0, disable Pango markup. If enabled, - Pango markup will be interpreted in your format specifier and in the - body of notifications. - ''; - }; - - actions = mkOption { - default = true; - type = types.nullOr types.bool; - description = '' - Applications may request an action to be associated with activating a - notification. Disabling this will cause mako to ignore these requests. - ''; - }; - - format = mkOption { - default = "%s\\n%b"; - type = types.nullOr types.str; - description = '' - Set notification format string to format. See FORMAT SPECIFIERS for - more information. To change this for grouped notifications, set it - within a grouped criteria. - ''; - }; - - defaultTimeout = mkOption { - default = 0; - type = types.nullOr types.int; - description = '' - Set the default timeout to timeout in milliseconds. To disable the - timeout, set it to zero. - ''; - }; - - ignoreTimeout = mkOption { - default = false; - type = types.nullOr types.bool; - description = '' - If set, mako will ignore the expire timeout sent by notifications - and use the one provided by default-timeout instead. - ''; - }; - - groupBy = mkOption { - default = null; - type = types.nullOr types.str; - description = '' - A comma-separated list of criteria fields that will be compared to - other visible notifications to determine if this one should form a - group with them. All listed criteria must be exactly equal for two - notifications to group. - ''; - }; - - extraConfig = mkOption { - default = ""; - type = types.lines; - example = lib.literalExpression '' - [urgency=low] - border-color=#b8bb26 - ''; - description = "Additional configuration."; + "app-name=Google\\ Chrome" = { + max-visible = "5"; + }; + + "field1=value field2=value" = { + text-alignment = "left"; + }; }; + description = '' + Criterias for mako's config. All the details can be found in the + CRITERIA section in the official documentation. + ''; }; }; - config = - let - boolToString = v: if v then "true" else "false"; - optionalBoolean = name: val: lib.optionalString (val != null) "${name}=${boolToString val}"; - optionalInteger = name: val: lib.optionalString (val != null) "${name}=${toString val}"; - optionalString = name: val: lib.optionalString (val != null) "${name}=${val}"; - in - lib.mkIf cfg.enable { - assertions = [ - (lib.hm.assertions.assertPlatform "services.mako" pkgs lib.platforms.linux) - ]; + config = lib.mkIf cfg.enable { + assertions = [ + (lib.hm.assertions.assertPlatform "services.mako" pkgs lib.platforms.linux) + ]; - home.packages = [ cfg.package ]; + home.packages = [ cfg.package ]; - xdg.configFile."mako/config" = { - onChange = '' - ${cfg.package}/bin/makoctl reload || true - ''; - text = '' - ${optionalInteger "max-visible" cfg.maxVisible} - ${optionalInteger "max-history" cfg.maxHistory} - ${optionalString "sort" cfg.sort} - ${optionalString "output" cfg.output} - ${optionalString "layer" cfg.layer} - ${optionalString "anchor" cfg.anchor} - - ${optionalString "font" cfg.font} - ${optionalString "background-color" cfg.backgroundColor} - ${optionalString "text-color" cfg.textColor} - ${optionalInteger "width" cfg.width} - ${optionalInteger "height" cfg.height} - ${optionalString "margin" cfg.margin} - ${optionalString "padding" cfg.padding} - ${optionalInteger "border-size" cfg.borderSize} - ${optionalString "border-color" cfg.borderColor} - ${optionalInteger "border-radius" cfg.borderRadius} - ${optionalString "progress-color" cfg.progressColor} - ${optionalBoolean "icons" cfg.icons} - ${optionalInteger "max-icon-size" cfg.maxIconSize} - ${optionalString "icon-path" cfg.iconPath} - ${optionalBoolean "markup" cfg.markup} - ${optionalBoolean "actions" cfg.actions} - ${optionalString "format" cfg.format} - ${optionalInteger "default-timeout" cfg.defaultTimeout} - ${optionalBoolean "ignore-timeout" cfg.ignoreTimeout} - ${optionalString "group-by" cfg.groupBy} - - ${cfg.extraConfig} - ''; + xdg.configFile."mako/config" = mkIf (cfg.settings != { } || cfg.criterias != { }) { + onChange = "${cfg.package}/bin/makoctl reload || true"; + text = generateConfig { + globalSection = cfg.settings; + sections = cfg.criterias; }; }; + }; } diff --git a/tests/default.nix b/tests/default.nix index e4171bbf0..f4f7c6867 100644 --- a/tests/default.nix +++ b/tests/default.nix @@ -442,6 +442,7 @@ import nmtSrc { ./modules/services/lieer ./modules/services/linux-wallpaperengine ./modules/services/lxqt-policykit-agent + ./modules/services/mako ./modules/services/mopidy ./modules/services/mpd ./modules/services/mpd-mpris diff --git a/tests/modules/services/mako/config b/tests/modules/services/mako/config new file mode 100644 index 000000000..8cfda5eb9 --- /dev/null +++ b/tests/modules/services/mako/config @@ -0,0 +1,23 @@ +actions=true +anchor=top-right +backgroundColor=#000000 +borderColor=#FFFFFF +borderRadius=0 +defaultTimeout=0 +font=monospace 10 +height=100 +icons=true +ignoreTimeout=false +layer=top +margin=10 +markup=true +width=300 + +[actionable=true] +anchor=top-left + +[app-name=Google\ Chrome] +max-visible=5 + +[field1=value field2=value] +text-alignment=left diff --git a/tests/modules/services/mako/default.nix b/tests/modules/services/mako/default.nix new file mode 100644 index 000000000..b839429b4 --- /dev/null +++ b/tests/modules/services/mako/default.nix @@ -0,0 +1 @@ +{ mako-example-config = ./example-config.nix; } diff --git a/tests/modules/services/mako/example-config.nix b/tests/modules/services/mako/example-config.nix new file mode 100644 index 000000000..137a3b7bf --- /dev/null +++ b/tests/modules/services/mako/example-config.nix @@ -0,0 +1,41 @@ +{ + services.mako = { + enable = true; + settings = { + actions = "true"; + anchor = "top-right"; + backgroundColor = "#000000"; + borderColor = "#FFFFFF"; + borderRadius = "0"; + defaultTimeout = "0"; + font = "monospace 10"; + height = "100"; + width = "300"; + icons = "true"; + ignoreTimeout = "false"; + layer = "top"; + margin = "10"; + markup = "true"; + }; + + criterias = { + "actionable=true" = { + anchor = "top-left"; + }; + + "app-name=Google\\ Chrome" = { + max-visible = "5"; + }; + + "field1=value field2=value" = { + text-alignment = "left"; + }; + }; + }; + + nmt.script = '' + assertFileExists home-files/.config/mako/config + assertFileContent home-files/.config/mako/config \ + ${./config} + ''; +}