From 98d030f723e0a4a446e56b276573efb8bef422f5 Mon Sep 17 00:00:00 2001 From: Thiago Kenji Okada Date: Sat, 23 Jan 2021 14:13:38 -0300 Subject: [PATCH] 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. --- modules/programs/rofi.nix | 126 +++++++++++++----- .../programs/rofi/custom-theme-config.rasi | 6 + tests/modules/programs/rofi/custom-theme.nix | 39 ++++++ tests/modules/programs/rofi/custom-theme.rasi | 13 ++ tests/modules/programs/rofi/default.nix | 1 + tests/modules/programs/rofi/valid-config.nix | 3 + 6 files changed, 156 insertions(+), 32 deletions(-) create mode 100644 tests/modules/programs/rofi/custom-theme-config.rasi create mode 100644 tests/modules/programs/rofi/custom-theme.nix create mode 100644 tests/modules/programs/rofi/custom-theme.rasi diff --git a/modules/programs/rofi.nix b/modules/programs/rofi.nix index f7b4682be..e59e14d42 100644 --- a/modules/programs/rofi.nix +++ b/modules/programs/rofi.nix @@ -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 rofi-theme-selector 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,30 +385,39 @@ in { ''; }]; + lib.formats.rasi.mkLiteral = value: { + _type = "literal"; + inherit value; + }; + home.packages = [ cfg.package ]; - home.file."${cfg.configPath}".text = toRasi "configuration" ({ - width = cfg.width; - lines = cfg.lines; - font = cfg.font; - bw = cfg.borderWidth; - eh = cfg.rowHeight; - padding = cfg.padding; - separator-style = cfg.separator; - hide-scrollbar = - if (cfg.scrollbar != null) then (!cfg.scrollbar) else null; - terminal = cfg.terminal; - cycle = cfg.cycle; - fullscreen = cfg.fullscreen; - location = (getAttr cfg.location locationsMap); - xoffset = cfg.xoffset; - yoffset = cfg.yoffset; - theme = themeName; - } // (mkColorScheme cfg.colors) // cfg.extraConfig); - - xdg.dataFile = mkIf (themePath != null) { - "rofi/themes/${themeName}.rasi".source = themePath; + home.file."${cfg.configPath}".text = toRasi { + configuration = ({ + width = cfg.width; + lines = cfg.lines; + font = cfg.font; + bw = cfg.borderWidth; + eh = cfg.rowHeight; + padding = cfg.padding; + separator-style = cfg.separator; + hide-scrollbar = + if (cfg.scrollbar != null) then (!cfg.scrollbar) else null; + terminal = cfg.terminal; + cycle = cfg.cycle; + fullscreen = cfg.fullscreen; + location = (getAttr cfg.location locationsMap); + xoffset = cfg.xoffset; + yoffset = cfg.yoffset; + theme = themeName; + } // (mkColorScheme cfg.colors) // cfg.extraConfig); }; + + 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 ]; diff --git a/tests/modules/programs/rofi/custom-theme-config.rasi b/tests/modules/programs/rofi/custom-theme-config.rasi new file mode 100644 index 000000000..639336d98 --- /dev/null +++ b/tests/modules/programs/rofi/custom-theme-config.rasi @@ -0,0 +1,6 @@ +configuration { +location: 0; +theme: "custom"; +xoffset: 0; +yoffset: 0; +} diff --git a/tests/modules/programs/rofi/custom-theme.nix b/tests/modules/programs/rofi/custom-theme.nix new file mode 100644 index 000000000..7c1ef81da --- /dev/null +++ b/tests/modules/programs/rofi/custom-theme.nix @@ -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} + ''; + }; +} diff --git a/tests/modules/programs/rofi/custom-theme.rasi b/tests/modules/programs/rofi/custom-theme.rasi new file mode 100644 index 000000000..870659c77 --- /dev/null +++ b/tests/modules/programs/rofi/custom-theme.rasi @@ -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; +} diff --git a/tests/modules/programs/rofi/default.nix b/tests/modules/programs/rofi/default.nix index 03b9049e6..057ef0039 100644 --- a/tests/modules/programs/rofi/default.nix +++ b/tests/modules/programs/rofi/default.nix @@ -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; } diff --git a/tests/modules/programs/rofi/valid-config.nix b/tests/modules/programs/rofi/valid-config.nix index 8fb66a7b8..efcb1acdc 100644 --- a/tests/modules/programs/rofi/valid-config.nix +++ b/tests/modules/programs/rofi/valid-config.nix @@ -48,6 +48,9 @@ with lib; }; }; + nixpkgs.overlays = + [ (self: super: { rofi = pkgs.writeScriptBin "dummy-rofi" ""; }) ]; + nmt.script = '' assertFileContent \ home-files/.config/rofi/config.rasi \