rofi: add support to custom themes

If this commit now it is possible to define a custom theme directly
using Nix, like this:

```nix
{
   programs.rofi.theme = {
      "*" = {
         background-color = "#000000";
         border-color = "FFFFFF";
         width = 512;
      };
      listview = {
         cycle = true;
      };
   };
}
```

And this will be converted to the proper rasi format to be used in
rofi.
This commit is contained in:
Thiago Kenji Okada 2021-01-23 14:13:38 -03:00 committed by Robert Helgesson
parent 7313258b45
commit 98d030f723
No known key found for this signature in database
GPG key ID: 36BDAA14C2797E89
6 changed files with 156 additions and 32 deletions

View file

@ -1,7 +1,6 @@
{ config, lib, pkgs, ... }:
with lib;
with builtins;
let
@ -109,21 +108,31 @@ let
if value then "true" else "false"
else if isInt value then
toString value
else if value._type or "" == "literal" then
value.value
else if isString value then
''"${value}"''
else
''"${toString value}"'';
abort "Unhandled value type ${builtins.typeOf value}";
mkKeyValue = name: value: "${name}: ${mkValueString value};";
toRasi = section: config:
mkRasiSection = section: config:
let
toRasiKeyValue = generators.toKeyValue { inherit mkKeyValue; };
# Remove null values so the resulting config does not have empty lines
configStr = generators.toKeyValue { inherit mkKeyValue; }
(attrsets.filterAttrs (m: v: v != null) config);
configStr = toRasiKeyValue (filterAttrs (_: v: v != null) config);
in ''
${section} {
${configStr}}
'';
toRasi = attrsOfAttrs:
let
mkSection = mkRasiSection;
sections = mapAttrsToList mkSection attrsOfAttrs;
in concatStringsSep "\n" sections;
locationsMap = {
center = 0;
top-left = 1;
@ -136,14 +145,41 @@ let
left = 8;
};
configType = with types; attrsOf (oneOf [ str int bool rasiLiteral ]);
rasiLiteral = types.submodule {
options = {
_type = mkOption {
type = types.enum [ "literal" ];
internal = true;
};
value = mkOption {
type = types.str;
internal = true;
};
};
} // {
description = "Rasi literal string";
};
themeType = with types; attrsOf configType;
themeName = if (cfg.theme == null) then
null
else if (isString cfg.theme) then
cfg.theme
else if (isAttrs cfg.theme) then
"custom"
else
removeSuffix ".rasi" (baseNameOf cfg.theme);
themePath = if (isString cfg.theme) then null else cfg.theme;
themePath = if (isString cfg.theme) then
null
else if (isAttrs cfg.theme) then
"custom"
else
cfg.theme;
in {
options.programs.rofi = {
@ -293,11 +329,28 @@ in {
theme = mkOption {
default = null;
type = with types; nullOr (either str path);
example = "Arc";
type = with types; nullOr (oneOf [ str path themeType ]);
example = literalExample ''
with config.lib.formats.rasi; {
"*" = {
# config.lib.formats.rasi.mkLiteral unquotes the value
background-color = mkLiteral "#000000";
foreground-color = mkLiteral "rgba ( 250, 251, 252, 100 % )";
border-color = mkLiteral "#FFFFFF";
width = 512;
};
"#textbox-prompt-colon" = {
expand = false;
str = ":";
margin = mkLiteral "0px 0.3em 0em 0em";
text-color = mkLiteral "@foreground-color";
};
}
'';
description = ''
Name of theme or path to theme file in rasi format. Available
named themes can be viewed using the
Name of theme or path to theme file in rasi format or attribute set with
theme configuration. Available named themes can be viewed using the
<command>rofi-theme-selector</command> tool.
'';
};
@ -318,7 +371,7 @@ in {
kb-secondary-paste = "Control+v,Insert";
}
'';
type = with types; attrsOf (oneOf [ int str bool ]);
type = configType;
description = "Additional configuration to add.";
};
@ -332,9 +385,15 @@ in {
'';
}];
lib.formats.rasi.mkLiteral = value: {
_type = "literal";
inherit value;
};
home.packages = [ cfg.package ];
home.file."${cfg.configPath}".text = toRasi "configuration" ({
home.file."${cfg.configPath}".text = toRasi {
configuration = ({
width = cfg.width;
lines = cfg.lines;
font = cfg.font;
@ -352,10 +411,13 @@ in {
yoffset = cfg.yoffset;
theme = themeName;
} // (mkColorScheme cfg.colors) // cfg.extraConfig);
xdg.dataFile = mkIf (themePath != null) {
"rofi/themes/${themeName}.rasi".source = themePath;
};
xdg.dataFile = mkIf (themePath != null) (if themePath == "custom" then {
"rofi/themes/${themeName}.rasi".text = toRasi cfg.theme;
} else {
"rofi/themes/${themeName}.rasi".source = themePath;
});
};
meta.maintainers = with maintainers; [ thiagokokada ];

View file

@ -0,0 +1,6 @@
configuration {
location: 0;
theme: "custom";
xoffset: 0;
yoffset: 0;
}

View file

@ -0,0 +1,39 @@
{ config, lib, pkgs, ... }:
with lib;
{
config = {
programs.rofi = {
enable = true;
theme = with config.lib.formats.rasi; {
"*" = {
background-color = mkLiteral "#000000";
foreground-color = mkLiteral "rgba ( 250, 251, 252, 100 % )";
border-color = mkLiteral "#FFFFFF";
width = 512;
};
"#textbox-prompt-colon" = {
expand = false;
str = ":";
margin = mkLiteral "0px 0.3em 0em 0em";
text-color = mkLiteral "@foreground-color";
};
};
};
nixpkgs.overlays =
[ (self: super: { rofi = pkgs.writeScriptBin "dummy-rofi" ""; }) ];
nmt.script = ''
assertFileContent \
home-files/.config/rofi/config.rasi \
${./custom-theme-config.rasi}
assertFileContent \
home-files/.local/share/rofi/themes/custom.rasi \
${./custom-theme.rasi}
'';
};
}

View file

@ -0,0 +1,13 @@
#textbox-prompt-colon {
expand: false;
margin: 0px 0.3em 0em 0em;
str: ":";
text-color: @foreground-color;
}
* {
background-color: #000000;
border-color: #FFFFFF;
foreground-color: rgba ( 250, 251, 252, 100 % );
width: 512;
}

View file

@ -1,4 +1,5 @@
{
rofi-valid-config = ./valid-config.nix;
rofi-custom-theme = ./custom-theme.nix;
rofi-assert-on-both-theme-and-colors = ./assert-on-both-theme-and-colors.nix;
}

View file

@ -48,6 +48,9 @@ with lib;
};
};
nixpkgs.overlays =
[ (self: super: { rofi = pkgs.writeScriptBin "dummy-rofi" ""; }) ];
nmt.script = ''
assertFileContent \
home-files/.config/rofi/config.rasi \