From da923602089501142855bbb3c276fbc36513eefb Mon Sep 17 00:00:00 2001 From: Nadrieril Date: Sat, 20 Feb 2021 17:34:59 +0000 Subject: [PATCH] polybar: allow config to be more nix-like (#1430) Polybar's config format is a bit strange, and lists in particular are annoying to handle. This enables using normal nix lists and nested attrsets instead. This change is not backwards-compatible, because the INI converter converts lists of strings to space-separated values, and this does something else. I expect that this is only relevant for the `modules-left` etc bar setting, but that's enough to break things :(. --- modules/misc/news.nix | 11 +++ modules/services/polybar.nix | 88 ++++++++++++++++++- .../services/polybar/basic-configuration.conf | 11 +++ .../services/polybar/basic-configuration.nix | 10 +++ 4 files changed, 118 insertions(+), 2 deletions(-) diff --git a/modules/misc/news.nix b/modules/misc/news.nix index 0791c0fd..2809e83a 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 934a9906..720f9c6f 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 54448a70..10ea0f07 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 a8886dab..fd23256c 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