hyprland.nix (6850B)
1 # modules/home/hyprland.nix — Hyprland (Lua config) and the carried shortcuts. 2 # 3 # Hyprland 0.56 is configured in Lua (hyprland.lua, `hl.*` API); that is also 4 # the dialect the carried shortcuts and the toolbox helpers (dropterm, winsnap, 5 # vault-open, lid-control: `hyprctl dispatch 'hl.dsp…'`) already speak. The 6 # config is split like the vault's shortcuts/: 7 # hypr/omarchy.lua the `o` helpers the carried files were written against 8 # hypr/core.lua monitor, env, look, input, Caelestia layer rules 9 # hypr/looknfeel.lua the springy animations, shadows, snap, swallow (dotfiles looknfeel.lua) 10 # hypr/defaults.lua the stock Omarchy binds as captured in keybinds.txt 11 # hypr/bindings.lua shortcuts/bindings.lua (user overrides, window mode) 12 # hypr/lid.lua shortcuts/lid.lua 13 # hypr/caelestia.lua shortcuts/caelestia.lua (Caelestia keys, always on here) 14 { ... }: 15 { 16 flake.homeModules.hyprland = 17 { config, pkgs, lib, inputs, osConfig, ... }: 18 let 19 system = pkgs.stdenv.hostPlatform.system; 20 hyprPkg = inputs.hyprland.packages.${system}.hyprland; 21 shellCli = "${config.programs.caelestia.cli.package}/bin/caelestia"; 22 23 # Small helpers the stock Omarchy binds relied on. They exist only to serve 24 # this config, so they live here rather than in ~/.local/bin. 25 helpers = [ 26 # The picker the omarchy-menu-* cheat sheets (bin/) pipe into. Prints the chosen line. 27 (pkgs.writeShellScriptBin "omarchy-menu-select" '' 28 title=''${1:-Select} 29 exec ${pkgs.fuzzel}/bin/fuzzel --dmenu --prompt "$title › " --width 110 --lines 24 30 '') 31 # omarchy-not-ported "<bind description>" ["<what it did on Omarchy>"]: an 32 # honest notification instead of a key that silently does nothing. 33 (pkgs.writeShellScriptBin "omarchy-not-ported" '' 34 ${pkgs.libnotify}/bin/notify-send -a NixDaemon -t 4000 "$1" "Not set up on this NixOS build.''${2:+ Omarchy: $2}" 35 '') 36 (pkgs.writeShellScriptBin "nixdaemon-show" '' 37 # nixdaemon-show time|battery|calendar|kbd-backlight-cycle 38 n() { ${pkgs.libnotify}/bin/notify-send -a NixDaemon -t 5000 "$@"; } 39 case "''${1:-}" in 40 time) n "$(date '+%H:%M')" "$(date '+%A %-d %B %Y')" ;; 41 battery) b=/sys/class/power_supply/BAT0; n "Battery $(cat $b/capacity)%" "$(cat $b/status)" ;; 42 calendar) n "$(date '+%B %Y')" "$(cal | tail -n +2)" ;; 43 kbd-backlight-cycle) 44 d=$(ls -d /sys/class/leds/*kbd_backlight 2>/dev/null | head -1); [ -n "$d" ] || exit 0 45 max=$(cat "$d/max_brightness"); cur=$(cat "$d/brightness"); next=$(( (cur + 1) % (max + 1) )) 46 ${pkgs.brightnessctl}/bin/brightnessctl -q -d "$(basename "$d")" set "$next" ;; 47 *) echo "usage: nixdaemon-show time|battery|calendar|kbd-backlight-cycle" >&2; exit 2 ;; 48 esac 49 '') 50 # SUPER+K: searchable list of the live binds (what Omarchy's keybindings menu did). Enter copies the key. 51 (pkgs.writeShellScriptBin "keybinds-menu" '' 52 sel=$(hyprctl binds -j | ${pkgs.python3}/bin/python3 -I -c ' 53 import json, sys 54 M = {1: "SHIFT", 4: "CTRL", 8: "ALT", 64: "SUPER"} 55 rows = set() 56 for x in json.load(sys.stdin): 57 mods = "+".join(n for v, n in sorted(M.items()) if x["modmask"] & v) 58 key = x["key"] or ("code:%d" % x["keycode"]) 59 sub = x.get("submap", "") 60 rows.add(("%s%s%s %s" % (sub + ": " if sub else "", mods + " + " if mods else "", key, x.get("description", ""))).rstrip()) 61 print("\n".join(sorted(rows)))' | ${pkgs.fuzzel}/bin/fuzzel --dmenu --prompt "Keybindings › " --width 120 --lines 30) || exit 0 62 [ -n "$sel" ] && printf '%s' "''${sel%% *}" | ${pkgs.wl-clipboard}/bin/wl-copy 63 '') 64 # CTRL+SUPER+SPACE: what Omarchy's background switcher did, with Caelestia's 65 # own wallpaper grid. The launcher shows it when its search starts with 66 # ">wallpaper ", and there is no IPC for that, so the prefix is typed in. 67 (pkgs.writeShellScriptBin "wallpaper-picker" '' 68 c=${shellCli} 69 case "$($c shell drawers isOpen launcher 2>/dev/null)" in 70 1|true) exec $c shell drawers toggle launcher ;; 71 esac 72 $c shell drawers toggle launcher 73 sleep 0.25 74 exec ${pkgs.wtype}/bin/wtype '>wallpaper ' 75 '') 76 (pkgs.writeShellScriptBin "nightlight-toggle" '' 77 if pgrep -x hyprsunset >/dev/null; then 78 pkill -x hyprsunset; ${pkgs.libnotify}/bin/notify-send -a NixDaemon -t 2000 "Night light" "off" 79 else 80 ${pkgs.hyprsunset}/bin/hyprsunset --temperature 4000 >/dev/null 2>&1 & 81 ${pkgs.libnotify}/bin/notify-send -a NixDaemon -t 2000 "Night light" "on (4000 K)" 82 fi 83 '') 84 ]; 85 in 86 # Only when the Hyprland desktop is switched on (modules/features/desktop/options.nix). 87 lib.mkIf osConfig.daemon.desktop.hyprland.enable { 88 wayland.windowManager.hyprland = { 89 enable = true; 90 package = hyprPkg; # same derivation NixOS installs; no second copy 91 portalPackage = null; # programs.hyprland (NixOS) provides the portal 92 configType = "lua"; 93 systemd.enable = false; # uwsm owns graphical-session.target 94 xwayland.enable = true; 95 96 extraLuaFiles = { 97 omarchy = { content = ./hypr/omarchy.lua; autoLoad = false; }; 98 core = { content = ./hypr/core.lua; autoLoad = false; }; 99 looknfeel = { content = ./hypr/looknfeel.lua; autoLoad = false; }; 100 defaults = { content = ./hypr/defaults.lua; autoLoad = false; }; 101 bindings = { content = ./hypr/bindings.lua; autoLoad = false; }; 102 lid = { content = ./hypr/lid.lua; autoLoad = false; }; 103 caelestia = { content = ./hypr/caelestia.lua; autoLoad = false; }; 104 }; 105 106 # Explicit load order: look first, then the stock binds, then the carried files that 107 # unbind-and-rebind the keys they take over, Caelestia's keys last. 108 extraConfig = '' 109 local cfg = (os.getenv("XDG_CONFIG_HOME") or (os.getenv("HOME") .. "/.config")) .. "/hypr" 110 package.path = cfg .. "/?.lua;" .. package.path 111 require("omarchy") 112 require("core") 113 require("looknfeel") 114 require("defaults") 115 require("bindings") 116 require("lid") 117 require("caelestia") 118 ''; 119 }; 120 121 home.packages = helpers ++ (with pkgs; [ 122 hyprpicker # colour picker (SUPER+PRINT) 123 hyprsunset # night light 124 fuzzel # dmenu for the cheat sheets and keybinds-menu 125 nautilus # the file manager shell.json and the stock binds point at 126 brightnessctl 127 pamixer 128 ]); # grim, slurp, wl-clipboard, libnotify: session.nix (shared with Niri) 129 130 # The polkit agent, cliphist and udiskie (graphical-session.target) are in 131 # session.nix: both desktops need them. 132 } 133 ; 134 }