Files
home-manager/modules/services/window-managers/herbstluftwm.nix
Olmo Kramer 4767a9c719 herbstluftwm: Make herbstclient alias optional
The `herbstclient` alias in the generated `autostart` made it impossible
to use bash functions.

This makes the `herbstclient` alias optional by adding an extra
`herbstclientAlias` option on the herbstluftwm configuration. The new
option defaults to `false` as to not confuse newcomers to the
herbstluftwm module, which is not a breaking change because it was only
an optimization.
2025-12-12 23:53:36 -06:00

198 lines
5.2 KiB
Nix

{
config,
lib,
pkgs,
...
}:
let
cfg = config.xsession.windowManager.herbstluftwm;
renderValue =
val: if lib.isBool val then if val then "true" else "false" else lib.escapeShellArg val;
renderSettings =
settings:
lib.concatStringsSep "\n" (
lib.mapAttrsToList (name: value: "herbstclient set ${name} ${renderValue value}") settings
);
renderKeybinds =
keybinds:
lib.concatStringsSep "\n" (
lib.mapAttrsToList (key: cmd: "herbstclient keybind ${key} ${cmd}") keybinds
);
renderMousebinds =
mousebinds:
lib.concatStringsSep "\n" (
lib.mapAttrsToList (btn: cmd: "herbstclient mousebind ${btn} ${cmd}") mousebinds
);
renderRules = rules: lib.concatStringsSep "\n" (map (rule: "herbstclient rule ${rule}") rules);
settingType = lib.types.oneOf [
lib.types.bool
lib.types.int
lib.types.str
];
escapedTags = map lib.escapeShellArg cfg.tags;
in
{
meta.maintainers = [ lib.hm.maintainers.olmokramer ];
options.xsession.windowManager.herbstluftwm = {
enable = lib.mkEnableOption "herbstluftwm window manager";
package = lib.mkPackageOption pkgs "herbstluftwm" { };
settings = lib.mkOption {
type = lib.types.attrsOf settingType;
default = { };
example = lib.literalExpression ''
{
gapless_grid = false;
window_border_width = 1;
window_border_active_color = "#FF0000";
}
'';
description = "Herbstluftwm settings.";
};
keybinds = lib.mkOption {
type = lib.types.attrsOf lib.types.str;
default = { };
example = lib.literalExpression ''
{
Mod4-o = "split right";
Mod4-u = "split bottom";
}
'';
description = "Herbstluftwm keybinds.";
};
mousebinds = lib.mkOption {
type = lib.types.attrsOf lib.types.str;
default = { };
example = lib.literalExpression ''
{
Mod4-B1 = "move";
Mod4-B3 = "resize";
}
'';
description = "Herbstluftwm mousebinds.";
};
rules = lib.mkOption {
type = lib.types.listOf lib.types.str;
default = [ ];
example = lib.literalExpression ''
[
"windowtype~'_NET_WM_WINDOW_TYPE_(DIALOG|UTILITY|SPLASH)' focus=on pseudotile=on"
"windowtype~'_NET_WM_WINDOW_TYPE_(NOTIFICATION|DOCK|DESKTOP)' manage=off"
]
'';
description = "Herbstluftwm rules.";
};
tags = lib.mkOption {
type = lib.types.listOf lib.types.str;
default = [ ];
example = lib.literalExpression ''
[ "work" "browser" "music" "gaming" ]
'';
description = "Tags to create on startup.";
};
extraConfig = lib.mkOption {
type = lib.types.lines;
default = "";
example = ''
herbstclient set_layout max
herbstclient detect_monitors
'';
description = ''
Extra configuration lines to add verbatim to
{file}`$XDG_CONFIG_HOME/herbstluftwm/autostart`.
'';
};
enableAlias = lib.mkOption {
type = lib.types.bool;
default = true;
description = ''
Set an alias for the {command}`herbstclient` command in the
{file}`autostart` script that only stores its arguments and executes
them all at once at the end of the {file}`autostart` script.
This reduces the amount of flickering you get while all options are
being applied and improves the performance.
On the other hand, this makes it more difficult to write bash functions
that call {command}`herbstclient`. You can work around this by calling
{command}`command herbstclient` in your functions to still get some of
the benefits of enabling this alias.
'';
};
};
config = lib.mkIf cfg.enable {
assertions = [
(lib.hm.assertions.assertPlatform "xsession.windowManager.herbstluftwm" pkgs lib.platforms.linux)
];
home.packages = [ cfg.package ];
xsession.windowManager.command = "${cfg.package}/bin/herbstluftwm --locked";
xdg.configFile."herbstluftwm/autostart".source = pkgs.writeShellScript "herbstluftwm-autostart" ''
${lib.optionalString cfg.enableAlias ''
shopt -s expand_aliases
# shellcheck disable=SC2142
alias herbstclient='set -- "$@" ";"'
set --
''}
herbstclient emit_hook reload
# Reset everything.
herbstclient attr theme.tiling.reset 1
herbstclient attr theme.floating.reset 1
herbstclient keyunbind --all
herbstclient mouseunbind --all
herbstclient unrule --all
${renderSettings cfg.settings}
${lib.optionalString (cfg.tags != [ ]) ''
for tag in ${lib.concatStringsSep " " escapedTags}; do
herbstclient add "$tag"
done
if ${cfg.package}/bin/herbstclient object_tree tags.by-name.default &>/dev/null; then
herbstclient use ${lib.head escapedTags}
herbstclient merge_tag default ${lib.head escapedTags}
fi
''}
${renderKeybinds cfg.keybinds}
${renderMousebinds cfg.mousebinds}
${renderRules cfg.rules}
${cfg.extraConfig}
herbstclient unlock
${lib.optionalString cfg.enableAlias ''
${cfg.package}/bin/herbstclient chain ";" "$@"
''}
'';
};
}