summaryrefslogtreecommitdiff
path: root/modules/services/aerospace/default.nix
diff options
context:
space:
mode:
authorMike Vink <59492084+ivi-vink@users.noreply.github.com>2025-01-16 22:22:34 +0100
committerGitHub <noreply@github.com>2025-01-16 22:22:34 +0100
commit8e7bd91f353caacc0bc4105f573eb3e17f09e03a (patch)
treec5059edcbebd9644290cad7c653c49a36d593021 /modules/services/aerospace/default.nix
parent6bd39d420578aacf7c0bab7de3e7027b952115ae (diff)
parentbd921223ba7cdac346477d7ea5204d6f4736fcc6 (diff)
Merge branch 'LnL7:master' into masterHEADmaster
Diffstat (limited to 'modules/services/aerospace/default.nix')
-rw-r--r--modules/services/aerospace/default.nix259
1 files changed, 259 insertions, 0 deletions
diff --git a/modules/services/aerospace/default.nix b/modules/services/aerospace/default.nix
new file mode 100644
index 0000000..3080579
--- /dev/null
+++ b/modules/services/aerospace/default.nix
@@ -0,0 +1,259 @@
+{
+ config,
+ lib,
+ pkgs,
+ ...
+}:
+
+let
+ cfg = config.services.aerospace;
+
+ format = pkgs.formats.toml { };
+ filterAttrsRecursive = pred: set:
+ lib.listToAttrs (
+ lib.concatMap (
+ name: let
+ v = set.${name};
+ in
+ if pred v
+ then [
+ (lib.nameValuePair name (
+ if lib.isAttrs v
+ then filterAttrsRecursive pred v
+ else if lib.isList v
+ then
+ (map (i:
+ if lib.isAttrs i
+ then filterAttrsRecursive pred i
+ else i) (lib.filter pred v))
+ else v
+ ))
+ ]
+ else []
+ ) (lib.attrNames set)
+ );
+ filterNulls = filterAttrsRecursive (v: v != null);
+ configFile = format.generate "aerospace.toml" (filterNulls cfg.settings);
+in
+
+{
+ options = {
+ services.aerospace = with lib.types; {
+ enable = lib.mkEnableOption "AeroSpace window manager";
+
+ package = lib.mkPackageOption pkgs "aerospace" { };
+
+ settings = lib.mkOption {
+ type = submodule {
+ freeformType = format.type;
+ options = {
+ start-at-login = lib.mkOption {
+ type = bool;
+ default = false;
+ description = "Do not start AeroSpace at login. (Managed by launchd instead)";
+ };
+ 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 = lib.mkOption {
+ type = listOf str;
+ default = [ ];
+ description = "Add commands that run after AeroSpace startup";
+ example = [ "layout tiles" ];
+ };
+ 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 = lib.mkOption {
+ type = bool;
+ default = true;
+ description = "Containers that nest into each other must have opposite orientations.";
+ };
+ accordion-padding = lib.mkOption {
+ type = int;
+ default = 30;
+ description = "Padding between windows in an accordion container.";
+ };
+ default-root-container-layout = lib.mkOption {
+ type = enum [
+ "tiles"
+ "accordion"
+ ];
+ default = "tiles";
+ description = "Default layout for the root container.";
+ };
+ default-root-container-orientation = lib.mkOption {
+ type = enum [
+ "horizontal"
+ "vertical"
+ "auto"
+ ];
+ default = "auto";
+ description = "Default orientation for the root container.";
+ };
+ on-window-detected = lib.mkOption {
+ type = listOf (submodule {
+ options = {
+ "if" = lib.mkOption {
+ type = submodule {
+ options = {
+ app-id = lib.mkOption {
+ type = nullOr str;
+ default = null;
+ description = "The application ID to match (optional).";
+ };
+ workspace = lib.mkOption {
+ type = nullOr str;
+ default = null;
+ description = "The workspace name to match (optional).";
+ };
+ window-title-regex-substring = lib.mkOption {
+ type = nullOr str;
+ default = null;
+ description = "Substring to match in the window title (optional).";
+ };
+ app-name-regex-substring = lib.mkOption {
+ type = nullOr str;
+ default = null;
+ description = "Regex substring to match the app name (optional).";
+ };
+ during-aerospace-startup = lib.mkOption {
+ type = nullOr bool;
+ default = null;
+ description = "Whether to match during aerospace startup (optional).";
+ };
+ };
+ };
+ default = { };
+ description = "Conditions for detecting a window.";
+ };
+ check-further-callbacks = lib.mkOption {
+ type = nullOr bool;
+ default = null;
+ description = "Whether to check further callbacks after this rule (optional).";
+ };
+ run = lib.mkOption {
+ type = oneOf [str (listOf str)];
+ example = ["move-node-to-workspace m" "resize-node"];
+ description = "Commands to execute when the conditions match (required).";
+ };
+ };
+ });
+ default = [ ];
+ example = [
+ {
+ "if" = {
+ app-id = "Another.Cool.App";
+ workspace = "cool-workspace";
+ window-title-regex-substring = "Title";
+ app-name-regex-substring = "CoolApp";
+ during-aerospace-startup = false;
+ };
+ check-further-callbacks = false;
+ run = ["move-node-to-workspace m" "resize-node"];
+ }
+ ];
+ description = "Commands to run every time a new window is detected with optional conditions.";
+ };
+ workspace-to-monitor-force-assignment = lib.mkOption {
+ type = attrsOf (oneOf [int str (listOf str)]);
+ default = { };
+ description = ''
+ Map workspaces to specific monitors.
+ Left-hand side is the workspace name, and right-hand side is the monitor pattern.
+ '';
+ example = {
+ "1" = 1; # First monitor from left to right.
+ "2" = "main"; # Main monitor.
+ "3" = "secondary"; # Secondary monitor (non-main).
+ "4" = "built-in"; # Built-in display.
+ "5" = "^built-in retina display$"; # Regex for the built-in retina display.
+ "6" = ["secondary" "dell"]; # Match first pattern in the list.
+ };
+ };
+ on-focus-changed = lib.mkOption {
+ type = listOf str;
+ default = [ ];
+ description = "Commands to run every time focused window or workspace changes.";
+ };
+ 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 = lib.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 = lib.mkOption {
+ type = enum [
+ "qwerty"
+ "dvorak"
+ ];
+ default = "qwerty";
+ description = "Keymapping preset.";
+ };
+ };
+ };
+ default = { };
+ example = lib.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
+ <link xlink:href="https://nikitabobko.github.io/AeroSpace/guide#configuring-aerospace"/>
+ for supported values.
+ '';
+ };
+ };
+ };
+
+ 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.";
+ }
+ ];
+ environment.systemPackages = [ cfg.package ];
+
+ 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;
+ };
+ };
+ }
+ );
+}