{ lib, ... }: let actionType = lib.types.addCheck (lib.types.attrsOf lib.types.anything) isAction; isAction = action: builtins.hasAttr "type" action && builtins.hasAttr action.type actionFields && ( let fields = builtins.getAttr action.type actionFields; allowedFields = [ "type" ] ++ fields; in lib.all (field: builtins.hasAttr field action) fields && lib.all (field: lib.elem field allowedFields) (builtins.attrNames action) && lib.all (field: actionFieldChecks.${field} action.${field}) fields ); actionFields = { exec = [ "command" ]; focus = [ "direction" ]; "move-window" = [ "direction" ]; "resize-window" = [ "x" "y" ]; "toggle-floating" = [ ]; fullscreen = [ ]; layout = [ "message" ]; "close-window" = [ ]; "kill-window" = [ ]; "focus-workspace" = [ "workspace" ]; "move-to-workspace" = [ "workspace" ]; }; actionFieldChecks = { command = builtins.isString; direction = direction: lib.elem direction [ "left" "down" "up" "right" ]; x = builtins.isInt; y = builtins.isInt; workspace = builtins.isInt; message = builtins.isString; }; in { checks = [ { assertion = entries: lib.all (entry: entry.value.keys != [ ]) entries; message = "Desktop keybinds must set at least one key."; } ]; type = lib.types.submodule { options = { keys = lib.mkOption { type = lib.types.listOf lib.types.str; example = [ "SUPER" "Return" ]; description = "Sets the ordered key parts for this desktop keybind."; }; action = lib.mkOption { type = actionType; description = "Declares the desktop action for this keybind."; }; }; }; }