mirror of
https://github.com/nix-community/home-manager.git
synced 2026-06-05 21:02:51 +00:00
`literalExpression` is intended just to signify code that needs to stay a string that gets represented exactly as-is for docs. It has been misused heavily and people get confused repeatedly on when or not to use it because of the rampant misuse.
394 lines
9.3 KiB
Nix
394 lines
9.3 KiB
Nix
{
|
|
config,
|
|
lib,
|
|
pkgs,
|
|
...
|
|
}:
|
|
let
|
|
inherit (lib)
|
|
filterAttrs
|
|
isAttrs
|
|
isString
|
|
literalExpression
|
|
mkOption
|
|
types
|
|
;
|
|
|
|
cfg = config.programs.rofi;
|
|
|
|
mkValueString =
|
|
value:
|
|
if lib.isBool value then
|
|
if value then "true" else "false"
|
|
else if lib.isInt value then
|
|
toString value
|
|
else if (value._type or "") == "literal" then
|
|
value.value
|
|
else if isString value then
|
|
''"${value}"''
|
|
else if lib.isList value then
|
|
"[ ${lib.strings.concatStringsSep "," (map mkValueString value)} ]"
|
|
else
|
|
abort "Unhandled value type ${builtins.typeOf value}";
|
|
|
|
mkKeyValue =
|
|
{
|
|
sep ? ": ",
|
|
end ? ";",
|
|
}:
|
|
name: value: "${name}${sep}${mkValueString value}${end}";
|
|
|
|
isSection = value: isAttrs value && (value._type or "") != "literal";
|
|
|
|
toRasiKeyValue =
|
|
attrs:
|
|
lib.concatStringsSep "\n" (
|
|
lib.mapAttrsToList (
|
|
name: value:
|
|
if isSection value then
|
|
"${name} {\n${toRasiKeyValue (filterAttrs (_: v: v != null) value)}\n}"
|
|
else
|
|
mkKeyValue { } name value
|
|
) (filterAttrs (_: v: v != null) attrs)
|
|
);
|
|
|
|
mkRasiSection =
|
|
name: value:
|
|
if isSection value then
|
|
"${name} {\n${toRasiKeyValue value}\n}\n"
|
|
else
|
|
(mkKeyValue {
|
|
sep = " ";
|
|
end = "";
|
|
} name value)
|
|
+ "\n";
|
|
|
|
toRasi =
|
|
attrs:
|
|
lib.concatStringsSep "\n" (
|
|
lib.concatMap (lib.mapAttrsToList mkRasiSection) [
|
|
(filterAttrs (n: _: n == "@theme") attrs)
|
|
(filterAttrs (n: _: n == "@import") attrs)
|
|
(removeAttrs attrs [
|
|
"@theme"
|
|
"@import"
|
|
])
|
|
]
|
|
);
|
|
|
|
locationsMap = {
|
|
center = 0;
|
|
top-left = 1;
|
|
top = 2;
|
|
top-right = 3;
|
|
right = 4;
|
|
bottom-right = 5;
|
|
bottom = 6;
|
|
bottom-left = 7;
|
|
left = 8;
|
|
};
|
|
|
|
configValueType =
|
|
with types;
|
|
(oneOf [
|
|
str
|
|
int
|
|
bool
|
|
rasiLiteral
|
|
]);
|
|
|
|
sectionType = with types; attrsOf (either configValueType (listOf configValueType));
|
|
|
|
# Either a `section { foo: "bar"; }` or a `@import/@theme "some-text"`
|
|
configType = with types; either sectionType str;
|
|
|
|
extraConfigType =
|
|
with types;
|
|
attrsOf (either sectionType (either configValueType (listOf configValueType)));
|
|
|
|
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
|
|
lib.removeSuffix ".rasi" (baseNameOf cfg.theme);
|
|
|
|
themePath =
|
|
if (isString cfg.theme) then
|
|
null
|
|
else if (isAttrs cfg.theme) then
|
|
"custom"
|
|
else
|
|
cfg.theme;
|
|
|
|
modes = map (mode: if isString mode then mode else "${mode.name}:${mode.path}") cfg.modes;
|
|
in
|
|
{
|
|
meta.maintainers = [ ];
|
|
|
|
options.programs.rofi = {
|
|
enable = lib.mkEnableOption "Rofi: A window switcher, application launcher and dmenu replacement";
|
|
|
|
package = lib.mkPackageOption pkgs "rofi" {
|
|
example = "pkgs.rofi.override { plugins = [ pkgs.rofi-emoji ]; }";
|
|
};
|
|
|
|
finalPackage = mkOption {
|
|
type = types.package;
|
|
readOnly = true;
|
|
description = ''
|
|
Resulting customized rofi package.
|
|
'';
|
|
};
|
|
|
|
plugins = mkOption {
|
|
default = [ ];
|
|
type = types.listOf types.package;
|
|
description = ''
|
|
List of rofi plugins to be installed.
|
|
'';
|
|
example = literalExpression "[ pkgs.rofi-calc ]";
|
|
};
|
|
|
|
font = mkOption {
|
|
default = null;
|
|
type = types.nullOr types.str;
|
|
example = "Droid Sans Mono 14";
|
|
description = "Font to use.";
|
|
};
|
|
|
|
terminal = mkOption {
|
|
default = null;
|
|
type = types.nullOr types.str;
|
|
description = ''
|
|
Path to the terminal which will be used to run console applications
|
|
'';
|
|
example = "\${pkgs.gnome.gnome_terminal}/bin/gnome-terminal";
|
|
};
|
|
|
|
cycle = mkOption {
|
|
default = null;
|
|
type = types.nullOr types.bool;
|
|
description = "Whether to cycle through the results list.";
|
|
};
|
|
|
|
location = mkOption {
|
|
default = "center";
|
|
type = types.enum (lib.attrNames locationsMap);
|
|
description = "The location rofi appears on the screen.";
|
|
};
|
|
|
|
xoffset = mkOption {
|
|
default = 0;
|
|
type = types.int;
|
|
description = ''
|
|
Offset in the x-axis in pixels relative to the chosen location.
|
|
'';
|
|
};
|
|
|
|
yoffset = mkOption {
|
|
default = 0;
|
|
type = types.int;
|
|
description = ''
|
|
Offset in the y-axis in pixels relative to the chosen location.
|
|
'';
|
|
};
|
|
|
|
theme = mkOption {
|
|
default = null;
|
|
type =
|
|
with types;
|
|
nullOr (oneOf [
|
|
str
|
|
path
|
|
themeType
|
|
]);
|
|
example = literalExpression ''
|
|
let
|
|
# Use `mkLiteral` for string-like values that should show without
|
|
# quotes, e.g.:
|
|
# {
|
|
# foo = "abc"; => foo: "abc";
|
|
# bar = mkLiteral "abc"; => bar: abc;
|
|
# };
|
|
inherit (config.lib.formats.rasi) mkLiteral;
|
|
in {
|
|
"*" = {
|
|
background-color = mkLiteral "#000000";
|
|
foreground-color = mkLiteral "rgba ( 250, 251, 252, 100 % )";
|
|
border-color = mkLiteral "#FFFFFF";
|
|
width = 512;
|
|
};
|
|
|
|
"#inputbar" = {
|
|
children = map mkLiteral [ "prompt" "entry" ];
|
|
};
|
|
|
|
"#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 or attribute set with
|
|
theme configuration. Available named themes can be viewed using the
|
|
{command}`rofi-theme-selector` tool.
|
|
'';
|
|
};
|
|
|
|
configPath = mkOption {
|
|
default = "${config.xdg.configHome}/rofi/config.rasi";
|
|
defaultText = "$XDG_CONFIG_HOME/rofi/config.rasi";
|
|
type = types.nonEmptyStr;
|
|
description = "Path where to put generated configuration file.";
|
|
};
|
|
|
|
modes = mkOption {
|
|
default = [ ];
|
|
example = literalExpression ''
|
|
[
|
|
"drun"
|
|
"emoji"
|
|
"ssh"
|
|
{
|
|
name = "whatnot";
|
|
path = lib.getExe pkgs.rofi-whatnot;
|
|
}
|
|
]
|
|
'';
|
|
type =
|
|
with types;
|
|
listOf (
|
|
either str (submodule {
|
|
options = {
|
|
name = mkOption {
|
|
type = str;
|
|
description = "Name used to reference the custom mode in the mode list.";
|
|
};
|
|
path = mkOption {
|
|
type = str;
|
|
description = "Executable path for the custom rofi script mode.";
|
|
};
|
|
};
|
|
})
|
|
);
|
|
description = "Modes to enable. For custom modes see `man 5 rofi-script`.";
|
|
};
|
|
|
|
extraConfig = mkOption {
|
|
default = { };
|
|
example = {
|
|
kb-primary-paste = "Control+V,Shift+Insert";
|
|
kb-secondary-paste = "Control+v,Insert";
|
|
"run,drun" = {
|
|
display-name = "open:";
|
|
};
|
|
};
|
|
type = extraConfigType;
|
|
description = "Additional configuration to add.";
|
|
};
|
|
|
|
};
|
|
|
|
imports =
|
|
let
|
|
mkRemovedOptionRofi =
|
|
option: (lib.mkRemovedOptionModule [ "programs" "rofi" option ] "Please use a Rofi theme instead.");
|
|
in
|
|
map mkRemovedOptionRofi [
|
|
"width"
|
|
"lines"
|
|
"borderWidth"
|
|
"rowHeight"
|
|
"padding"
|
|
"separator"
|
|
"scrollbar"
|
|
"fullscreen"
|
|
"colors"
|
|
];
|
|
|
|
config = lib.mkIf cfg.enable {
|
|
assertions = [
|
|
(lib.hm.assertions.assertPlatform "programs.rofi" pkgs lib.platforms.linux)
|
|
];
|
|
|
|
lib.formats.rasi.mkLiteral = value: {
|
|
_type = "literal";
|
|
inherit value;
|
|
};
|
|
|
|
programs.rofi.finalPackage =
|
|
let
|
|
rofiWithPlugins = cfg.package.override (old: {
|
|
plugins = (old.plugins or [ ]) ++ cfg.plugins;
|
|
});
|
|
in
|
|
if builtins.hasAttr "override" cfg.package && cfg.plugins != [ ] then
|
|
rofiWithPlugins
|
|
else
|
|
cfg.package;
|
|
|
|
home.packages = [ cfg.finalPackage ];
|
|
|
|
home.file."${cfg.configPath}".text =
|
|
toRasi {
|
|
configuration = (
|
|
{
|
|
inherit (cfg)
|
|
cycle
|
|
font
|
|
terminal
|
|
xoffset
|
|
yoffset
|
|
;
|
|
location = (lib.getAttr cfg.location locationsMap);
|
|
}
|
|
// lib.optionalAttrs (modes != [ ]) { inherit modes; }
|
|
// cfg.extraConfig
|
|
);
|
|
}
|
|
# @theme must go after configuration but attrs are output in alphabetical order ('@' first)
|
|
|
|
+ (lib.optionalString (themeName != null) (toRasi {
|
|
"@theme" = themeName;
|
|
}));
|
|
|
|
xdg.dataFile = lib.mkIf (themePath != null) (
|
|
if themePath == "custom" then
|
|
{
|
|
"rofi/themes/${themeName}.rasi".text = toRasi cfg.theme;
|
|
}
|
|
else
|
|
{
|
|
"rofi/themes/${themeName}.rasi".source = themePath;
|
|
}
|
|
);
|
|
};
|
|
}
|