From 72e93853c2d16d1ce04a5e8eee6695e2493ca80d Mon Sep 17 00:00:00 2001 From: Nick Hu Date: Sun, 13 Oct 2024 12:52:55 +0100 Subject: [PATCH 1/2] module: add aerospace service --- modules/module-list.nix | 1 + modules/services/aerospace/default.nix | 156 +++++++++++++++++++++++++ release.nix | 1 + tests/services-aerospace.nix | 36 ++++++ 4 files changed, 194 insertions(+) create mode 100644 modules/services/aerospace/default.nix create mode 100644 tests/services-aerospace.nix diff --git a/modules/module-list.nix b/modules/module-list.nix index 3280682c..6604eb92 100644 --- a/modules/module-list.nix +++ b/modules/module-list.nix @@ -52,6 +52,7 @@ ./fonts ./launchd ./services/activate-system + ./services/aerospace ./services/autossh.nix ./services/buildkite-agents.nix ./services/chunkwm.nix diff --git a/modules/services/aerospace/default.nix b/modules/services/aerospace/default.nix new file mode 100644 index 00000000..efbe9a14 --- /dev/null +++ b/modules/services/aerospace/default.nix @@ -0,0 +1,156 @@ +{ + config, + lib, + pkgs, + ... +}: + +with lib; + +let + cfg = config.services.aerospace; + + format = pkgs.formats.toml { }; + configFile = format.generate "aerospace.toml" cfg.settings; +in + +{ + options = with types; { + services.aerospace = { + enable = mkEnableOption "AeroSpace window manager"; + + package = mkOption { + type = types.path; + default = pkgs.aerospace; + description = "The AeroSpace package to use."; + }; + + settings = mkOption { + type = submodule { + freeformType = format.type; + options = { + start-at-login = mkOption { + type = addCheck bool (b: !false || !cfg.enable); + default = false; + description = "Do not start AeroSpace at login. (Managed by launchd instead)"; + }; + after-login-command = mkOption { + type = addCheck (listOf str) (l: l == [ ] || !cfg.enable); + default = [ ]; + description = "Do not use AeroSpace to run commands after login. (Managed by launchd instead)"; + }; + after-startup-command = mkOption { + type = addCheck (listOf str) (l: l == [ ] || !cfg.enable); + default = [ ]; + description = "Do not use AeroSpace to run commands after startup. (Managed by launchd instead)"; + }; + enable-normalization-flatten-containers = mkOption { + type = bool; + default = true; + description = "Containers that have only one child are \"flattened\"."; + }; + enable-normalization-opposite-orientation-for-nested-containers = mkOption { + type = bool; + default = true; + description = "Containers that nest into each other must have opposite orientations."; + }; + accordion-padding = mkOption { + type = int; + default = 30; + description = "Padding between windows in an accordion container."; + }; + default-root-container-layout = mkOption { + type = enum [ + "tiles" + "accordion" + ]; + default = "tiles"; + description = "Default layout for the root container."; + }; + default-root-container-orientation = mkOption { + type = enum [ + "horizontal" + "vertical" + "auto" + ]; + default = "auto"; + description = "Default orientation for the root container."; + }; + on-window-detected = mkOption { + type = listOf str; + default = [ ]; + description = "Commands to run every time a new window is detected."; + }; + on-focus-changed = mkOption { + type = listOf str; + default = [ ]; + description = "Commands to run every time focused window or workspace changes."; + }; + on-focused-monitor-changed = mkOption { + type = listOf str; + default = [ "move-mouse monitor-lazy-center" ]; + description = "Commands to run every time focused monitor changes."; + }; + exec-on-workspace-change = mkOption { + type = listOf str; + default = [ ]; + example = [ + "/bin/bash" + "-c" + "sketchybar --trigger aerospace_workspace_change FOCUSED=$AEROSPACE_FOCUSED_WORKSPACE" + ]; + description = "Commands to run every time workspace changes."; + }; + key-mapping.preset = mkOption { + type = enum [ + "qwerty" + "dvorak" + ]; + default = "qwerty"; + description = "Keymapping preset."; + }; + }; + }; + default = { }; + example = literalExpression '' + { + gaps = { + outer.left = 8; + outer.bottom = 8; + outer.top = 8; + outer.right = 8; + }; + mode.main.binding = { + alt-h = "focus left"; + alt-j = "focus down"; + alt-k = "focus up"; + alt-l = "focus right"; + }; + } + ''; + description = '' + AeroSpace configuration, see + + for supported values. + ''; + }; + }; + }; + + config = mkMerge [ + (mkIf (cfg.enable) { + environment.systemPackages = [ cfg.package ]; + + launchd.user.agents.aerospace.serviceConfig = { + ProgramArguments = + [ "${cfg.package}/Applications/AeroSpace.app/Contents/MacOS/AeroSpace" ] + ++ optionals (cfg.settings != { }) [ + "--config-path" + "${configFile}" + ]; + KeepAlive = true; + RunAtLoad = true; + }; + }) + ]; +} diff --git a/release.nix b/release.nix index ac0e31a6..0d754fc0 100644 --- a/release.nix +++ b/release.nix @@ -129,6 +129,7 @@ let tests.services-lorri = makeTest ./tests/services-lorri.nix; tests.services-nix-daemon = makeTest ./tests/services-nix-daemon.nix; tests.sockets-nix-daemon = makeTest ./tests/sockets-nix-daemon.nix; + tests.services-aerospace = makeTest ./tests/services-aerospace.nix; tests.services-dnsmasq = makeTest ./tests/services-dnsmasq.nix; tests.services-eternal-terminal = makeTest ./tests/services-eternal-terminal.nix; tests.services-nix-gc = makeTest ./tests/services-nix-gc.nix; diff --git a/tests/services-aerospace.nix b/tests/services-aerospace.nix new file mode 100644 index 00000000..7656cafd --- /dev/null +++ b/tests/services-aerospace.nix @@ -0,0 +1,36 @@ +{ config, pkgs, ... }: + +let + aerospace = pkgs.runCommand "aerospace-0.0.0" { } "mkdir $out"; +in + +{ + services.aerospace.enable = true; + services.aerospace.package = aerospace; + services.aerospace.settings = { + gaps = { + outer.left = 8; + outer.bottom = 8; + outer.top = 8; + outer.right = 8; + }; + mode.main.binding = { + alt-h = "focus left"; + alt-j = "focus down"; + alt-k = "focus up"; + alt-l = "focus right"; + }; + }; + + test = '' + echo >&2 "checking aerospace service in ~/Library/LaunchAgents" + grep "org.nixos.aerospace" ${config.out}/user/Library/LaunchAgents/org.nixos.aerospace.plist + grep "${aerospace}/Applications/AeroSpace.app/Contents/MacOS/AeroSpace" ${config.out}/user/Library/LaunchAgents/org.nixos.aerospace.plist + + conf=`sed -En '/--config-path<\/string>/{n; s/\s+?<\/?string>//g; p;}' \ + ${config.out}/user/Library/LaunchAgents/org.nixos.aerospace.plist` + + echo >&2 "checking config in $conf" + if [ `cat $conf | wc -l` -eq "27" ]; then echo "aerospace.toml config correctly contains 27 lines"; else return 1; fi + ''; +} From 7ebf95a73e3b54e0f9c48f50fde29e96257417ac Mon Sep 17 00:00:00 2001 From: Nick Hu Date: Thu, 17 Oct 2024 23:30:31 +0100 Subject: [PATCH 2/2] style fixes --- modules/services/aerospace/default.nix | 89 ++++++++++++++------------ tests/services-aerospace.nix | 2 +- 2 files changed, 49 insertions(+), 42 deletions(-) diff --git a/modules/services/aerospace/default.nix b/modules/services/aerospace/default.nix index efbe9a14..50d47b3b 100644 --- a/modules/services/aerospace/default.nix +++ b/modules/services/aerospace/default.nix @@ -5,8 +5,6 @@ ... }: -with lib; - let cfg = config.services.aerospace; @@ -15,51 +13,47 @@ let in { - options = with types; { - services.aerospace = { - enable = mkEnableOption "AeroSpace window manager"; + options = { + services.aerospace = with lib.types; { + enable = lib.mkEnableOption "AeroSpace window manager"; - package = mkOption { - type = types.path; - default = pkgs.aerospace; - description = "The AeroSpace package to use."; - }; + package = lib.mkPackageOption pkgs "aerospace" { }; - settings = mkOption { + settings = lib.mkOption { type = submodule { freeformType = format.type; options = { - start-at-login = mkOption { - type = addCheck bool (b: !false || !cfg.enable); + start-at-login = lib.mkOption { + type = bool; default = false; description = "Do not start AeroSpace at login. (Managed by launchd instead)"; }; - after-login-command = mkOption { - type = addCheck (listOf str) (l: l == [ ] || !cfg.enable); + after-login-command = lib.mkOption { + type = listOf str; default = [ ]; description = "Do not use AeroSpace to run commands after login. (Managed by launchd instead)"; }; - after-startup-command = mkOption { - type = addCheck (listOf str) (l: l == [ ] || !cfg.enable); + after-startup-command = lib.mkOption { + type = listOf str; default = [ ]; description = "Do not use AeroSpace to run commands after startup. (Managed by launchd instead)"; }; - enable-normalization-flatten-containers = mkOption { + enable-normalization-flatten-containers = lib.mkOption { type = bool; default = true; description = "Containers that have only one child are \"flattened\"."; }; - enable-normalization-opposite-orientation-for-nested-containers = mkOption { + enable-normalization-opposite-orientation-for-nested-containers = lib.mkOption { type = bool; default = true; description = "Containers that nest into each other must have opposite orientations."; }; - accordion-padding = mkOption { + accordion-padding = lib.mkOption { type = int; default = 30; description = "Padding between windows in an accordion container."; }; - default-root-container-layout = mkOption { + default-root-container-layout = lib.mkOption { type = enum [ "tiles" "accordion" @@ -67,7 +61,7 @@ in default = "tiles"; description = "Default layout for the root container."; }; - default-root-container-orientation = mkOption { + default-root-container-orientation = lib.mkOption { type = enum [ "horizontal" "vertical" @@ -76,22 +70,22 @@ in default = "auto"; description = "Default orientation for the root container."; }; - on-window-detected = mkOption { + on-window-detected = lib.mkOption { type = listOf str; default = [ ]; description = "Commands to run every time a new window is detected."; }; - on-focus-changed = mkOption { + on-focus-changed = lib.mkOption { type = listOf str; default = [ ]; description = "Commands to run every time focused window or workspace changes."; }; - on-focused-monitor-changed = mkOption { + on-focused-monitor-changed = lib.mkOption { type = listOf str; default = [ "move-mouse monitor-lazy-center" ]; description = "Commands to run every time focused monitor changes."; }; - exec-on-workspace-change = mkOption { + exec-on-workspace-change = lib.mkOption { type = listOf str; default = [ ]; example = [ @@ -101,7 +95,7 @@ in ]; description = "Commands to run every time workspace changes."; }; - key-mapping.preset = mkOption { + key-mapping.preset = lib.mkOption { type = enum [ "qwerty" "dvorak" @@ -112,7 +106,7 @@ in }; }; default = { }; - example = literalExpression '' + example = lib.literalExpression '' { gaps = { outer.left = 8; @@ -137,20 +131,33 @@ in }; }; - config = mkMerge [ - (mkIf (cfg.enable) { + config = ( + lib.mkIf (cfg.enable) { + assertions = [ + { + assertion = !cfg.settings.start-at-login; + message = "AeroSpace started at login is managed by home-manager and launchd instead of itself via this option."; + } + { + assertion = cfg.settings.after-login-command == [ ]; + message = "AeroSpace will not run these commands as it does not start itself."; + } + { + assertion = cfg.settings.after-startup-command == [ ]; + message = "AeroSpace will not run these commands as it does not start itself."; + } + ]; environment.systemPackages = [ cfg.package ]; - launchd.user.agents.aerospace.serviceConfig = { - ProgramArguments = - [ "${cfg.package}/Applications/AeroSpace.app/Contents/MacOS/AeroSpace" ] - ++ optionals (cfg.settings != { }) [ - "--config-path" - "${configFile}" - ]; - KeepAlive = true; - RunAtLoad = true; + launchd.user.agents.aerospace = { + command = + "${cfg.package}/Applications/AeroSpace.app/Contents/MacOS/AeroSpace" + + (lib.optionalString (cfg.settings != { }) " --config-path ${configFile}"); + serviceConfig = { + KeepAlive = true; + RunAtLoad = true; + }; }; - }) - ]; + } + ); } diff --git a/tests/services-aerospace.nix b/tests/services-aerospace.nix index 7656cafd..8cbd292f 100644 --- a/tests/services-aerospace.nix +++ b/tests/services-aerospace.nix @@ -27,7 +27,7 @@ in grep "org.nixos.aerospace" ${config.out}/user/Library/LaunchAgents/org.nixos.aerospace.plist grep "${aerospace}/Applications/AeroSpace.app/Contents/MacOS/AeroSpace" ${config.out}/user/Library/LaunchAgents/org.nixos.aerospace.plist - conf=`sed -En '/--config-path<\/string>/{n; s/\s+?<\/?string>//g; p;}' \ + conf=`sed -En 's/^[[:space:]]*.*--config-path (.*)<\/string>$/\1/p' \ ${config.out}/user/Library/LaunchAgents/org.nixos.aerospace.plist` echo >&2 "checking config in $conf"