NixDaemon

NixOS pentest workstation as one flake — IceBreaker's successor
git clone https://git.daemon-sec.xyz/NixDaemon.git
Log | Files | Refs | README

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 }