1
0
Fork 0
mirror of https://github.com/nix-community/home-manager synced 2024-11-30 06:59:45 +01:00

bspwm: various improvements (#2095)

* bspwm: various improvements

- fixes shell escaping issues and general style issues
- allow reloading the config on-the-fly by exposing bspwmrc to the user

* bspwm: add configuration test
This commit is contained in:
Naïm Favier 2021-06-20 00:40:17 +02:00 committed by GitHub
parent 2f6d5c90f4
commit e70524cd2b
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
7 changed files with 126 additions and 59 deletions

3
.github/CODEOWNERS vendored
View file

@ -293,6 +293,9 @@
/modules/services/unison.nix @pacien /modules/services/unison.nix @pacien
/modules/services/window-managers/bspwm @ncfavier
/tests/modules/services/window-managers/bspwm @ncfavier
/modules/services/window-managers/i3-sway/i3.nix @sumnerevans /modules/services/window-managers/i3-sway/i3.nix @sumnerevans
/tests/modules/services/window-managers/i3 @sumnerevans /tests/modules/services/window-managers/i3 @sumnerevans

View file

@ -5,70 +5,72 @@ with lib;
let let
cfg = config.xsession.windowManager.bspwm; cfg = config.xsession.windowManager.bspwm;
bspwm = cfg.package;
camelToSnake = s: camelToSnake =
builtins.replaceStrings lib.upperChars (map (c: "_${c}") lib.lowerChars) s; builtins.replaceStrings upperChars (map (c: "_${c}") lowerChars);
formatConfig = n: v: formatMonitor = monitor: desktops:
"bspc monitor ${strings.escapeShellArg monitor} -d ${
strings.escapeShellArgs desktops
}";
formatSetting = n: v:
let let
formatList = x: vStr = if isBool v then
if isList x then boolToString v
throw "can not convert 2-dimensional lists to bspwm format" else if isInt v || isFloat v then
else toString v
formatValue x;
formatValue = v:
if isBool v then
(if v then "true" else "false")
else if isList v then
concatMapStringsSep ", " formatList v
else if isString v then else if isString v then
"${lib.strings.escapeShellArg v}" strings.escapeShellArg v
else else
toString v; throw "unsupported setting type for ${n}";
in "bspc config ${n} ${formatValue v}"; in "bspc config ${strings.escapeShellArg n} ${vStr}";
formatMonitors = n: v: "bspc monitor ${n} -d ${concatStringsSep " " v}"; formatRule = target: directives:
formatRules = target: directiveOptions:
let let
formatDirective = n: v: formatDirective = n: v:
if isBool v then let
(if v then "${camelToSnake n}=on" else "${camelToSnake n}=off") vStr = if isBool v then
else if (n == "desktop" || n == "node") then if v then "on" else "off"
"${camelToSnake n}='${v}'" else if isInt v || isFloat v then
toString v
else if isString v then
v
else else
"${camelToSnake n}=${lib.strings.escapeShellArg v}"; throw "unsupported rule attribute type for ${n}";
in "${camelToSnake n}=${vStr}";
directives = directivesStr = strings.escapeShellArgs (mapAttrsToList formatDirective
filterAttrs (n: v: v != null && !(lib.strings.hasPrefix "_" n)) (filterAttrs (n: v: v != null) directives));
directiveOptions; in "bspc rule -a ${strings.escapeShellArg target} ${directivesStr}";
directivesStr = builtins.concatStringsSep " "
(mapAttrsToList formatDirective directives);
in "bspc rule -a ${target} ${directivesStr}";
formatStartupPrograms = map (s: "${s} &"); formatStartupProgram = s: "${s} &";
in { in {
options = import ./options.nix { meta.maintainers = [ maintainers.ncfavier ];
inherit pkgs;
inherit lib; options = import ./options.nix { inherit pkgs lib; };
};
config = mkIf cfg.enable { config = mkIf cfg.enable {
home.packages = [ bspwm ]; home.packages = [ cfg.package ];
xsession.windowManager.command = let
configFile = pkgs.writeShellScript "bspwmrc" (concatStringsSep "\n" xdg.configFile."bspwm/bspwmrc".source = pkgs.writeShellScript "bspwmrc" ''
((mapAttrsToList formatMonitors cfg.monitors) ${concatStringsSep "\n" (mapAttrsToList formatMonitor cfg.monitors)}
++ (mapAttrsToList formatConfig cfg.settings)
++ (mapAttrsToList formatRules cfg.rules) ++ ['' ${concatStringsSep "\n" (mapAttrsToList formatSetting cfg.settings)}
bspc rule -r '*'
${concatStringsSep "\n" (mapAttrsToList formatRule cfg.rules)}
# java gui fixes # java gui fixes
export _JAVA_AWT_WM_NONREPARENTING=1 export _JAVA_AWT_WM_NONREPARENTING=1
bspc rule -a sun-awt-X11-XDialogPeer state=floating bspc rule -a sun-awt-X11-XDialogPeer state=floating
''] ++ [ cfg.extraConfig ]
++ (formatStartupPrograms cfg.startupPrograms))); ${cfg.extraConfig}
configCmdOpt = optionalString (cfg.settings != null) "-c ${configFile}"; ${concatMapStringsSep "\n" formatStartupProgram cfg.startupPrograms}
in "${cfg.package}/bin/bspwm ${configCmdOpt}"; '';
xsession.windowManager.command =
"${cfg.package}/bin/bspwm -c ${config.xdg.configHome}/bspwm/bspwmrc";
}; };
} }

View file

@ -150,16 +150,16 @@ in {
type = types.package; type = types.package;
default = pkgs.bspwm; default = pkgs.bspwm;
defaultText = literalExample "pkgs.bspwm"; defaultText = literalExample "pkgs.bspwm";
description = "bspwm package to use."; description = "The bspwm package to use.";
example = literalExample "pkgs.bspwm-unstable"; example = literalExample "pkgs.bspwm-unstable";
}; };
settings = mkOption { settings = mkOption {
type = with types; type = with types;
let primitive = either bool (either int (either float str)); let primitive = either bool (either int (either float str));
in attrsOf (either primitive (listOf primitive)); in attrsOf primitive;
default = { }; default = { };
description = "bspwm configuration"; description = "General settings given to <literal>bspc config</literal>.";
example = { example = {
"border_width" = 2; "border_width" = 2;
"split_ratio" = 0.52; "split_ratio" = 0.52;
@ -170,7 +170,8 @@ in {
extraConfig = mkOption { extraConfig = mkOption {
type = types.lines; type = types.lines;
default = ""; default = "";
description = "Additional configuration to add."; description =
"Additional shell commands to be run at the end of the config file.";
example = '' example = ''
bspc subscribe all > ~/bspc-report.log & bspc subscribe all > ~/bspc-report.log &
''; '';
@ -179,14 +180,16 @@ in {
monitors = mkOption { monitors = mkOption {
type = types.attrsOf (types.listOf types.str); type = types.attrsOf (types.listOf types.str);
default = { }; default = { };
description = "bspc monitor configurations"; description =
"Specifies the names of desktops to create on each monitor.";
example = { "HDMI-0" = [ "web" "terminal" "III" "IV" ]; }; example = { "HDMI-0" = [ "web" "terminal" "III" "IV" ]; };
}; };
rules = mkOption { rules = mkOption {
type = types.attrsOf rule; type = types.attrsOf rule;
default = { }; default = { };
description = "bspc rules"; description =
"Rule configuration. The keys of the attribute set are the targets of the rules.";
example = literalExample '' example = literalExample ''
{ {
"Gimp" = { "Gimp" = {

View file

@ -123,6 +123,7 @@ import nmt {
./modules/services/redshift-gammastep ./modules/services/redshift-gammastep
./modules/services/sxhkd ./modules/services/sxhkd
./modules/services/syncthing ./modules/services/syncthing
./modules/services/window-managers/bspwm
./modules/services/window-managers/i3 ./modules/services/window-managers/i3
./modules/services/window-managers/sway ./modules/services/window-managers/sway
./modules/services/wlsunset ./modules/services/wlsunset

View file

@ -0,0 +1,18 @@
bspc monitor 'focused' -d 'desktop 1' 'd'\''esk top'
bspc config 'border_width' 2
bspc config 'external_rules_command' '/path/to/external rules command'
bspc config 'gapless_monocle' true
bspc config 'split_ratio' 0.520000
bspc rule -r '*'
bspc rule -a '*' 'center=off' 'desktop=d'\''esk top#next' 'split_dir=north' 'sticky=on'
# java gui fixes
export _JAVA_AWT_WM_NONREPARENTING=1
bspc rule -a sun-awt-X11-XDialogPeer state=floating
extra config
foo &
bar || qux &

View file

@ -0,0 +1,39 @@
{ lib, pkgs, ... }:
with lib;
{
config = {
xsession.windowManager.bspwm = {
enable = true;
monitors.focused =
[ "desktop 1" "d'esk top" ]; # pathological desktop names
settings = {
border_width = 2;
split_ratio = 0.52;
gapless_monocle = true;
external_rules_command = "/path/to/external rules command";
};
rules."*" = {
sticky = true;
center = false;
desktop = "d'esk top#next";
splitDir = "north";
border = null;
};
extraConfig = ''
extra config
'';
startupPrograms = [ "foo" "bar || qux" ];
};
nmt.script = ''
bspwmrc=home-files/.config/bspwm/bspwmrc
assertFileExists "$bspwmrc"
assertFileIsExecutable "$bspwmrc"
assertFileContent "$bspwmrc" ${
pkgs.writeShellScript "bspwmrc-expected" (readFile ./bspwmrc)
}
'';
};
}

View file

@ -0,0 +1 @@
{ bspwm-configuration = ./configuration.nix; }