{ lib, config, pkgs, ... }: let inherit (lib) mkOption types concatStringsSep getExe dropEnd last mkEnableOption mapAttrs' nameValuePair splitString ; inherit (builtins) length; cfg = config.wm; bindCfg = cfg.keybinds; sep = bindCfg.separator; mod = bindCfg.mod; main-color = "#EBDBB2"; secondary-color = "#24273A"; mkHyprBind = keys: let len = length keys; prefix = if len > 1 then [ ] else [ "None" ]; finalKeys = prefix ++ keys; in (concatStringsSep "+" (dropEnd 1 finalKeys)) + ",${last finalKeys}"; mkBindOption = keys: let hypr-key = mkHyprBind keys; in mkOption { type = types.str; default = if bindCfg.hypr-type then hypr-key else (concatStringsSep sep keys); }; mkGradientColorOption = { from ? main-color, to ? secondary-color, angle ? 45, }: { from = mkOption { type = types.str; default = from; }; to = mkOption { type = types.str; default = to; }; angle = mkOption { type = types.int; default = angle; }; }; in { options.wm = { exec-once = mkOption { type = with types; nullOr lines; default = null; apply = v: if v != null then pkgs.writeShellScript "exec-once" v else null; }; app = { browser = { package = mkOption { type = with types; nullOr package; default = null; }; name = mkOption { type = with types; nullOr package; default = null; }; }; terminal = { package = mkOption { type = with types; nullOr package; default = null; }; name = mkOption { type = with types; nullOr str; default = null; }; run = mkOption { type = with types; nullOr str; default = "${getExe cfg.terminal.package} -e "; }; }; file-browser = { package = mkOption { type = with types; nullOr package; default = null; }; name = mkOption { type = with types; nullOr str; default = null; }; }; }; window = { opacity = mkOption { type = types.float; default = 0.85; }; }; input = { keyboard = { repeat-delay = mkOption { type = types.int; default = 250; }; repeat-rate = mkOption { type = types.int; default = 35; }; }; }; border = { active = mkGradientColorOption { }; inactive = mkGradientColorOption { from = secondary-color; to = secondary-color; }; radius = mkOption { type = types.int; default = 12; }; }; keybinds = { mod = mkOption { type = types.str; default = "Mod"; }; separator = mkOption { type = types.str; default = "+"; }; hypr-type = mkEnableOption "hyprland-like bind syntax" // { default = false; }; spawn = mkOption { type = types.attrs; default = { "${mod}${sep}ENTER" = "${getExe cfg.app.terminal.package}"; "${mod}${sep}F" = "${getExe cfg.app.browser.package}"; }; apply = binds: let hypr-binds = mapAttrs' (n: v: nameValuePair (mkHyprBind (splitString sep n)) v) binds; in if bindCfg.hypr-type then hypr-binds else binds; }; spawn-repeat = mkOption { type = types.attrs; default = { }; apply = binds: let hypr-binds = mapAttrs' (n: v: nameValuePair (mkHyprBind (splitString sep n)) v) binds; in if bindCfg.hypr-type then hypr-binds else binds; }; # ==== Movement ==== # switch-window-focus = mkBindOption [ mod "TAB" ]; move-window-focus = { left = mkBindOption [ mod "H" ]; right = mkBindOption [ mod "L" ]; up = mkBindOption [ mod "K" ]; down = mkBindOption [ mod "J" ]; }; move-monitor-focus = { left = mkBindOption [ mod "CTRL" "H" ]; right = mkBindOption [ mod "CTRL" "L" ]; }; move-workspace-focus = { # Workspace Focus next = mkBindOption [ mod "CTRL" "J" ]; prev = mkBindOption [ mod "CTRL" "k" ]; }; move-window = { left = mkBindOption [ mod "SHIFT" "H" ]; right = mkBindOption [ mod "SHIFT" "L" ]; up = mkBindOption [ mod "SHIFT" "K" ]; down = mkBindOption [ mod "SHIFT" "J" ]; }; consume-window = { left = mkBindOption [ mod "CTRL" "SHIFT" "H" ]; right = mkBindOption [ mod "CTRL" "SHIFT" "L" ]; }; switch-layout = mkBindOption [ mod "CTRL" "ALT" "SPACE" ]; # ==== Actions ==== # center-window = mkBindOption [ mod "C" ]; toggle-overview = mkBindOption [ mod "O" ]; close-window = mkBindOption [ mod "Q" ]; toggle-fullscreen = mkBindOption [ "F11" ]; # ==== Scrolling ==== # move-workspace = { down = mkBindOption [ mod "CTRL" "SHIFT" "J" ]; up = mkBindOption [ mod "CTRL" "SHIFT" "K" ]; }; switch-preset-column-width = mkBindOption [ mod "W" ]; switch-preset-window-height = mkBindOption [ mod "S" ]; expand-column-to-available-width = mkBindOption [ mod "P" ]; maximize-column = mkBindOption [ mod "M" ]; reset-window-height = mkBindOption [ mod "CTRL" "S" ]; # ==== Float ==== # toggle-float = mkBindOption [ mod "V" ]; switch-focus-between-floating-and-tiling = mkBindOption [ mod "CTRL" "V" ]; minimize = mkBindOption [ mod "I" ]; restore-minimize = mkBindOption [ mod "SHIFT" "I" ]; toggle-scratchpad = mkBindOption [ mod "Z" ]; # ==== Screenshot ==== # screenshot = { area = mkBindOption [ mod "SHIFT" "S" ]; window = mkBindOption [ "CTRL" "SHIFT" "S" ]; screen = mkBindOption [ mod "CTRL" "SHIFT" "S" ]; }; toggle-control-center = mkBindOption [ mod "SLASH" ]; toggle-launcher = mkBindOption [ "ALT" "SPACE" ]; lock-screen = mkBindOption [ mod "CTRL" "M" ]; clipboard-history = mkBindOption [ mod "COMMA" ]; emoji = mkBindOption [ mod "PERIOD" ]; screen-recorder = mkBindOption [ mod "F12" ]; notification-center = mkBindOption [ mod "N" ]; toggle-dont-disturb = mkBindOption [ mod "CTRL" "N" ]; wallpaper-selector = mkBindOption [ mod "CTRL" "W" ]; wallpaper-random = mkBindOption [ mod "CTRL" "SLASH" ]; calculator = mkBindOption [ mod "CTRL" "C" ]; media = { prev = mkBindOption [ mod "CTRL" "COMMA" ]; next = mkBindOption [ mod "CTRL" "PERIOD" ]; }; focus-workspace-prefix = mkBindOption [ mod ]; }; }; }