2022-11-27 01:17:28 +01:00
|
|
|
{ config, options, lib, pkgs, ... }:
|
2017-10-05 15:55:37 +02:00
|
|
|
|
|
|
|
with lib;
|
|
|
|
|
|
|
|
let
|
|
|
|
|
|
|
|
cfg = config.services.polybar;
|
2022-11-27 01:17:28 +01:00
|
|
|
opt = options.services.polybar;
|
2017-10-05 15:55:37 +02:00
|
|
|
|
2020-02-02 00:39:17 +01:00
|
|
|
eitherStrBoolIntList = with types;
|
|
|
|
either str (either bool (either int (listOf str)));
|
2018-12-05 11:54:52 +01:00
|
|
|
|
2021-02-20 18:34:59 +01:00
|
|
|
# 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.
|
2017-10-09 14:21:43 +02:00
|
|
|
toPolybarIni = generators.toINI {
|
|
|
|
mkKeyValue = key: value:
|
2018-08-29 21:46:11 +02:00
|
|
|
let
|
|
|
|
quoted = v:
|
2020-02-02 00:39:17 +01:00
|
|
|
if hasPrefix " " v || hasSuffix " " v then ''"${v}"'' else v;
|
|
|
|
|
|
|
|
value' = if isBool value then
|
|
|
|
(if value then "true" else "false")
|
|
|
|
else if (isString value && key != "include-file") then
|
|
|
|
quoted value
|
|
|
|
else
|
|
|
|
toString value;
|
|
|
|
in "${key}=${value'}";
|
2017-10-09 14:21:43 +02:00
|
|
|
};
|
|
|
|
|
2022-12-04 12:12:32 +01:00
|
|
|
configFile = let
|
|
|
|
isDeclarativeConfig = cfg.settings != opt.settings.default || cfg.config
|
|
|
|
!= opt.config.default || cfg.extraConfig != opt.extraConfig.default;
|
|
|
|
in if isDeclarativeConfig then
|
|
|
|
pkgs.writeText "polybar.conf" ''
|
|
|
|
${toPolybarIni cfg.config}
|
|
|
|
${toPolybarIni (mapAttrs convertPolybarSection cfg.settings)}
|
|
|
|
${cfg.extraConfig}
|
|
|
|
''
|
|
|
|
else
|
|
|
|
null;
|
2017-10-05 15:55:37 +02:00
|
|
|
|
2020-02-02 00:39:17 +01:00
|
|
|
in {
|
2017-10-05 15:55:37 +02:00
|
|
|
options = {
|
|
|
|
services.polybar = {
|
|
|
|
enable = mkEnableOption "Polybar status bar";
|
|
|
|
|
|
|
|
package = mkOption {
|
|
|
|
type = types.package;
|
|
|
|
default = pkgs.polybar;
|
2021-10-09 11:14:08 +02:00
|
|
|
defaultText = literalExpression "pkgs.polybar";
|
2017-10-05 15:55:37 +02:00
|
|
|
description = "Polybar package to install.";
|
2021-10-09 11:14:08 +02:00
|
|
|
example = literalExpression ''
|
2017-10-05 15:55:37 +02:00
|
|
|
pkgs.polybar.override {
|
|
|
|
i3GapsSupport = true;
|
|
|
|
alsaSupport = true;
|
|
|
|
iwSupport = true;
|
|
|
|
githubSupport = true;
|
|
|
|
}
|
|
|
|
'';
|
|
|
|
};
|
|
|
|
|
|
|
|
config = mkOption {
|
2020-02-02 00:39:17 +01:00
|
|
|
type = types.coercedTo types.path
|
2017-10-05 15:55:37 +02:00
|
|
|
(p: { "section/base" = { include-file = "${p}"; }; })
|
2018-12-05 11:54:52 +01:00
|
|
|
(types.attrsOf (types.attrsOf eitherStrBoolIntList));
|
2017-10-05 15:55:37 +02:00
|
|
|
description = ''
|
2018-10-02 08:17:34 +02:00
|
|
|
Polybar configuration. Can be either path to a file, or set of attributes
|
2017-10-05 15:55:37 +02:00
|
|
|
that will be used to create the final configuration.
|
2021-02-20 18:34:59 +01:00
|
|
|
See also <option>services.polybar.settings</option> for a more nix-friendly format.
|
2017-10-05 15:55:37 +02:00
|
|
|
'';
|
2020-02-02 00:39:17 +01:00
|
|
|
default = { };
|
2021-10-09 11:14:08 +02:00
|
|
|
example = literalExpression ''
|
2017-10-05 15:55:37 +02:00
|
|
|
{
|
|
|
|
"bar/top" = {
|
|
|
|
monitor = "\''${env:MONITOR:eDP1}";
|
|
|
|
width = "100%";
|
|
|
|
height = "3%";
|
|
|
|
radius = 0;
|
|
|
|
modules-center = "date";
|
|
|
|
};
|
|
|
|
|
|
|
|
"module/date" = {
|
|
|
|
type = "internal/date";
|
|
|
|
internal = 5;
|
|
|
|
date = "%d.%m.%y";
|
|
|
|
time = "%H:%M";
|
|
|
|
label = "%time% %date%";
|
|
|
|
};
|
|
|
|
}
|
|
|
|
'';
|
|
|
|
};
|
|
|
|
|
2021-02-20 18:34:59 +01:00
|
|
|
settings = mkOption {
|
2021-11-15 22:00:45 +01:00
|
|
|
type = with types;
|
|
|
|
let ty = oneOf [ bool int float str (listOf ty) (attrsOf ty) ];
|
|
|
|
in attrsOf (attrsOf ty // { description = "attribute sets"; });
|
2023-07-01 00:35:51 +02:00
|
|
|
description = lib.mdDoc ''
|
2021-02-20 18:34:59 +01:00
|
|
|
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
|
2023-07-01 00:35:51 +02:00
|
|
|
to dash-separated keys; the special `text` key is ignored as a nested key,
|
2021-02-20 18:34:59 +01:00
|
|
|
to allow mixing different levels of nesting; and lists are converted to
|
2023-07-01 00:35:51 +02:00
|
|
|
polybar's `foo-0, foo-1, ...` format.
|
|
|
|
|
2021-02-20 18:34:59 +01:00
|
|
|
For example:
|
2023-07-01 00:35:51 +02:00
|
|
|
```nix
|
2021-02-20 18:34:59 +01:00
|
|
|
"module/volume" = {
|
|
|
|
type = "internal/pulseaudio";
|
2023-07-01 00:35:51 +02:00
|
|
|
format.volume = "<ramp-volume> <label-volume>";
|
2021-02-20 18:34:59 +01:00
|
|
|
label.muted.text = "🔇";
|
|
|
|
label.muted.foreground = "#666";
|
|
|
|
ramp.volume = ["🔈" "🔉" "🔊"];
|
2023-07-01 00:35:51 +02:00
|
|
|
click.right = "pavucontrol &";
|
2021-02-20 18:34:59 +01:00
|
|
|
}
|
2023-07-01 00:35:51 +02:00
|
|
|
```
|
2021-02-20 18:34:59 +01:00
|
|
|
becomes:
|
2023-07-01 00:35:51 +02:00
|
|
|
```ini
|
2021-02-20 18:34:59 +01:00
|
|
|
[module/volume]
|
|
|
|
type=internal/pulseaudio
|
2023-07-01 00:35:51 +02:00
|
|
|
format-volume=<ramp-volume> <label-volume>
|
2021-02-20 18:34:59 +01:00
|
|
|
label-muted=🔇
|
|
|
|
label-muted-foreground=#666
|
|
|
|
ramp-volume-0=🔈
|
|
|
|
ramp-volume-1=🔉
|
|
|
|
ramp-volume-2=🔊
|
2023-07-01 00:35:51 +02:00
|
|
|
click-right=pavucontrol &
|
|
|
|
```
|
2021-02-20 18:34:59 +01:00
|
|
|
'';
|
|
|
|
default = { };
|
2021-10-09 11:14:08 +02:00
|
|
|
example = literalExpression ''
|
2021-02-20 18:34:59 +01:00
|
|
|
{
|
|
|
|
"module/volume" = {
|
|
|
|
type = "internal/pulseaudio";
|
|
|
|
format.volume = "<ramp-volume> <label-volume>";
|
|
|
|
label.muted.text = "🔇";
|
|
|
|
label.muted.foreground = "#666";
|
|
|
|
ramp.volume = ["🔈" "🔉" "🔊"];
|
|
|
|
click.right = "pavucontrol &";
|
|
|
|
};
|
|
|
|
}
|
|
|
|
'';
|
|
|
|
};
|
|
|
|
|
2017-10-05 15:55:37 +02:00
|
|
|
extraConfig = mkOption {
|
|
|
|
type = types.lines;
|
|
|
|
description = "Additional configuration to add.";
|
|
|
|
default = "";
|
|
|
|
example = ''
|
|
|
|
[module/date]
|
|
|
|
type = internal/date
|
|
|
|
interval = 5
|
|
|
|
date = "%d.%m.%y"
|
|
|
|
time = %H:%M
|
|
|
|
format-prefix-foreground = \''${colors.foreground-alt}
|
|
|
|
label = %time% %date%
|
|
|
|
'';
|
|
|
|
};
|
|
|
|
|
|
|
|
script = mkOption {
|
|
|
|
type = types.lines;
|
|
|
|
description = ''
|
|
|
|
This script will be used to start the polybars.
|
|
|
|
Set all necessary environment variables here and start all bars.
|
|
|
|
It can be assumed that <command>polybar</command> executable is in the <envar>PATH</envar>.
|
|
|
|
|
|
|
|
Note, this script must start all bars in the background and then terminate.
|
|
|
|
'';
|
|
|
|
example = "polybar bar &";
|
|
|
|
};
|
|
|
|
};
|
|
|
|
};
|
|
|
|
|
|
|
|
config = mkIf cfg.enable {
|
2021-07-07 23:24:27 +02:00
|
|
|
assertions = [
|
|
|
|
(lib.hm.assertions.assertPlatform "services.polybar" pkgs
|
|
|
|
lib.platforms.linux)
|
|
|
|
];
|
|
|
|
|
2022-11-27 01:17:28 +01:00
|
|
|
meta.maintainers = with maintainers; [ h7x4 ];
|
|
|
|
|
2017-10-05 15:55:37 +02:00
|
|
|
home.packages = [ cfg.package ];
|
2022-12-04 12:12:32 +01:00
|
|
|
xdg.configFile."polybar/config.ini" =
|
|
|
|
mkIf (configFile != null) { source = configFile; };
|
2017-10-05 15:55:37 +02:00
|
|
|
|
|
|
|
systemd.user.services.polybar = {
|
|
|
|
Unit = {
|
|
|
|
Description = "Polybar status bar";
|
2021-05-22 04:15:12 +02:00
|
|
|
PartOf = [ "tray.target" ];
|
2022-12-04 12:12:32 +01:00
|
|
|
X-Restart-Triggers = mkIf (configFile != null) "${configFile}";
|
2017-10-05 15:55:37 +02:00
|
|
|
};
|
|
|
|
|
|
|
|
Service = {
|
|
|
|
Type = "forking";
|
2018-12-31 13:01:48 +01:00
|
|
|
Environment = "PATH=${cfg.package}/bin:/run/wrappers/bin";
|
2019-03-21 00:39:36 +01:00
|
|
|
ExecStart =
|
2020-02-02 00:39:17 +01:00
|
|
|
let scriptPkg = pkgs.writeShellScriptBin "polybar-start" cfg.script;
|
|
|
|
in "${scriptPkg}/bin/polybar-start";
|
2019-09-03 23:51:23 +02:00
|
|
|
Restart = "on-failure";
|
2017-10-05 15:55:37 +02:00
|
|
|
};
|
|
|
|
|
2021-05-22 04:15:12 +02:00
|
|
|
Install = { WantedBy = [ "tray.target" ]; };
|
2017-10-05 15:55:37 +02:00
|
|
|
};
|
|
|
|
};
|
|
|
|
|
|
|
|
}
|