diff --git a/modules/misc/news.nix b/modules/misc/news.nix
index 0791c0fd9..2809e83ae 100644
--- a/modules/misc/news.nix
+++ b/modules/misc/news.nix
@@ -1852,6 +1852,17 @@ in
A new module is available: 'programs.sbt'.
'';
}
+
+ {
+ time = "2021-02-20T00:00:00+00:00";
+ condition = config.services.polybar.enable;
+ message = ''
+ The polybar configuration can now be written in a more nix-friendly format.
+ The new 'services.polybar.settings' option is an alternative to
+ 'services.polybar.config' that supports nested keys and converts nix
+ lists to polybar-style 'foo-0, foo-1, ...' lists.
+ '';
+ }
];
};
}
diff --git a/modules/services/polybar.nix b/modules/services/polybar.nix
index 934a99063..720f9c6fb 100644
--- a/modules/services/polybar.nix
+++ b/modules/services/polybar.nix
@@ -9,6 +9,36 @@ let
eitherStrBoolIntList = with types;
either str (either bool (either int (listOf str)));
+ # Convert a key/val pair to the insane format that polybar uses.
+ # Each input key/val pair may return several output key/val pairs.
+ convertPolybarKeyVal = key: val:
+ # Convert { foo = [ "a" "b" ]; }
+ # to {
+ # foo-0 = "a";
+ # foo-1 = "b";
+ # }
+ if isList val then
+ concatLists (imap0 (i: convertPolybarKeyVal "${key}-${toString i}") val)
+ # Convert {
+ # foo.text = "a";
+ # foo.font = 1;
+ # } to {
+ # foo = "a";
+ # foo-font = 1;
+ # }
+ else if isAttrs val && !lib.isDerivation val then
+ concatLists (mapAttrsToList
+ (k: convertPolybarKeyVal (if k == "text" then key else "${key}-${k}"))
+ val)
+ # Base case
+ else
+ [ (nameValuePair key val) ];
+
+ convertPolybarSection = _: attrs:
+ listToAttrs (concatLists (mapAttrsToList convertPolybarKeyVal attrs));
+
+ # Converts an attrset to INI text, quoting values as expected by polybar.
+ # This does no more fancy conversion.
toPolybarIni = generators.toINI {
mkKeyValue = key: value:
let
@@ -24,8 +54,11 @@ let
in "${key}=${value'}";
};
- configFile = pkgs.writeText "polybar.conf"
- (toPolybarIni cfg.config + "\n" + cfg.extraConfig);
+ configFile = pkgs.writeText "polybar.conf" ''
+ ${toPolybarIni cfg.config}
+ ${toPolybarIni (mapAttrs convertPolybarSection cfg.settings)}
+ ${cfg.extraConfig}
+ '';
in {
options = {
@@ -54,6 +87,7 @@ in {
description = ''
Polybar configuration. Can be either path to a file, or set of attributes
that will be used to create the final configuration.
+ See also for a more nix-friendly format.
'';
default = { };
example = literalExample ''
@@ -77,6 +111,56 @@ in {
'';
};
+ settings = mkOption {
+ type = types.attrsOf types.attrs;
+ description = ''
+ Polybar configuration. This takes a nix attrset and converts it to the
+ strange data format that polybar uses.
+ Each entry will be converted to a section in the output file.
+ Several things are treated specially: nested keys are converted
+ to dash-separated keys; the special text key is ignored as a nested key,
+ to allow mixing different levels of nesting; and lists are converted to
+ polybar's foo-0, foo-1, ... format.
+
+ For example:
+
+ "module/volume" = {
+ type = "internal/pulseaudio";
+ format.volume = "<ramp-volume> <label-volume>";
+ label.muted.text = "🔇";
+ label.muted.foreground = "#666";
+ ramp.volume = ["🔈" "🔉" "🔊"];
+ click.right = "pavucontrol &";
+ }
+
+ becomes:
+
+ [module/volume]
+ type=internal/pulseaudio
+ format-volume=<ramp-volume> <label-volume>
+ label-muted=🔇
+ label-muted-foreground=#666
+ ramp-volume-0=🔈
+ ramp-volume-1=🔉
+ ramp-volume-2=🔊
+ click-right=pavucontrol &
+
+ '';
+ default = { };
+ example = literalExample ''
+ {
+ "module/volume" = {
+ type = "internal/pulseaudio";
+ format.volume = " ";
+ label.muted.text = "🔇";
+ label.muted.foreground = "#666";
+ ramp.volume = ["🔈" "🔉" "🔊"];
+ click.right = "pavucontrol &";
+ };
+ }
+ '';
+ };
+
extraConfig = mkOption {
type = types.lines;
description = "Additional configuration to add.";
diff --git a/tests/modules/services/polybar/basic-configuration.conf b/tests/modules/services/polybar/basic-configuration.conf
index 54448a705..10ea0f076 100644
--- a/tests/modules/services/polybar/basic-configuration.conf
+++ b/tests/modules/services/polybar/basic-configuration.conf
@@ -12,6 +12,16 @@ label=%time% %date%
time=%H:%M
type=internal/date
+[module/volume]
+click-right=pavucontrol &
+format-volume=
+label-muted=🔇
+label-muted-foreground=#666
+ramp-volume-0=🔈
+ramp-volume-1=🔉
+ramp-volume-2=🔊
+type=internal/pulseaudio
+
[module/date]
type = internal/date
interval = 5
@@ -19,3 +29,4 @@ date = "%d.%m.%y"
time = %H:%M
format-prefix-foreground = ${colors.foreground-alt}
label = %time% %date%
+
diff --git a/tests/modules/services/polybar/basic-configuration.nix b/tests/modules/services/polybar/basic-configuration.nix
index a8886dab6..fd23256c3 100644
--- a/tests/modules/services/polybar/basic-configuration.nix
+++ b/tests/modules/services/polybar/basic-configuration.nix
@@ -22,6 +22,16 @@
label = "%time% %date%";
};
};
+ settings = {
+ "module/volume" = {
+ type = "internal/pulseaudio";
+ format.volume = " ";
+ label.muted.text = "🔇";
+ label.muted.foreground = "#666";
+ ramp.volume = [ "🔈" "🔉" "🔊" ];
+ click.right = "pavucontrol &";
+ };
+ };
extraConfig = ''
[module/date]
type = internal/date