Compare commits
32 Commits
f60f3655f9
...
v1
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
82659566ac | ||
|
|
994025f0c8 | ||
|
|
b0b2a4d732 | ||
|
|
964a5c98b7 | ||
|
|
c45fb80b79 | ||
|
|
0c668c2eb1 | ||
|
|
1f4bd3d5fa | ||
|
|
017bb1aa41 | ||
|
|
b856bb93e8 | ||
|
|
e0ee5b9e7e | ||
|
|
f68b245d92 | ||
|
|
fb748c217c | ||
|
|
8d3911de1a | ||
|
|
6ad80c045e | ||
|
|
54c6e100fb | ||
|
|
eb76bd61b4 | ||
|
|
71f37bfc30 | ||
|
|
69f959365e | ||
|
|
aef45b3c8d | ||
|
|
0897391cfb | ||
|
|
5c83b52727 | ||
|
|
0751102915 | ||
|
|
5c59da73e7 | ||
|
|
42801548b7 | ||
|
|
1b0eeeaf6c | ||
| a606c0d498 | |||
| cd495d1720 | |||
| dbcb8efd1e | |||
| 07e467027b | |||
| 9a5473e179 | |||
| db6a0ba455 | |||
| 8c47716f9a |
@@ -1,284 +0,0 @@
|
||||
{
|
||||
"permissions": {
|
||||
"allow": [
|
||||
"Bash(grep -i \"\\\\.nix$\")",
|
||||
"Bash(xargs ls *)",
|
||||
"Bash(nix --extra-experimental-features 'nix-command flakes' eval --raw .#homeConfigurations.nomarchy.activationPackage.outPath)",
|
||||
"Bash(git *)",
|
||||
"Bash(nix --extra-experimental-features 'nix-command flakes' eval --raw .#nixosConfigurations.default.config.system.activationScripts.home-manager-activate.text)",
|
||||
"Bash(nix --extra-experimental-features 'nix-command flakes' eval --raw .#nixosConfigurations.installerIsoGraphical.config.system.activationScripts.home-manager-activate.text)",
|
||||
"Bash(nix --extra-experimental-features 'nix-command flakes' eval .#nixosConfigurations.default.config.system.build.toplevel.drvPath)",
|
||||
"Bash(nix --extra-experimental-features 'nix-command flakes' eval .#nixosConfigurations.installerIsoGraphical.config.system.build.toplevel.drvPath)",
|
||||
"Bash(nix --extra-experimental-features 'nix-command flakes' eval .#homeConfigurations.nomarchy.activationPackage.drvPath)",
|
||||
"Bash(nix --extra-experimental-features 'nix-command flakes' eval --raw .#nixosConfigurations.default.config.systemd.services.\"home-manager-nomarchy\".serviceConfig.ExecStart)",
|
||||
"Bash(nix --extra-experimental-features 'nix-command flakes' build .#nixosConfigurations.default.config.system.build.vm --no-link --print-out-paths)",
|
||||
"Bash(nix --extra-experimental-features 'nix-command flakes' eval .#homeConfigurations.nomarchy.config.xdg.configFile.\"nomarchy/current/background\".source)",
|
||||
"Bash(nix --extra-experimental-features 'nix-command flakes' eval --raw .#homeConfigurations.nomarchy.config.home-files.outPath)",
|
||||
"Bash(nix --extra-experimental-features 'nix-command flakes' build .#homeConfigurations.nomarchy.config.home-files --no-link --print-out-paths)",
|
||||
"Bash(nix --extra-experimental-features 'nix-command flakes' eval .#homeConfigurations.nomarchy.config.systemd.user.startServices)",
|
||||
"Bash(xxd)",
|
||||
"Bash(nix --extra-experimental-features 'nix-command flakes' eval --raw .#packages.x86_64-linux.allThemeVariants.drvPath)",
|
||||
"Bash(chmod +x /home/bernardo/Projects/Coding/Nomarchy/themes/engine/scripts/nomarchy-themes-prebuild)",
|
||||
"Bash(nix --extra-experimental-features 'nix-command flakes' build .#homeConfigurations.nomarchy.activationPackage --no-link --print-out-paths)",
|
||||
"Bash(nix --extra-experimental-features 'nix-command flakes' build .#homeConfigurations.nomarchy.config.home.packages.outPath)",
|
||||
"Bash(nix --extra-experimental-features 'nix-command flakes' eval --raw .#homeConfigurations.nomarchy.config.home-path.outPath)",
|
||||
"Bash(nix --extra-experimental-features 'nix-command flakes' eval --impure --expr '\\(builtins.readDir ./themes/engine/scripts\\)' --json)",
|
||||
"Bash(nix-build -I nixpkgs=/nix/var/nix/profiles/per-user/root/channels/nixos /home/bernardo/Projects/Coding/Nomarchy/flake.nix --argstr attr nixosConfigurations.installerIsoGraphical)",
|
||||
"Bash(awk '{print $NF}')",
|
||||
"Bash(nix --extra-experimental-features 'nix-command flakes' eval .#nixosConfigurations.installerIsoGraphical.config.hardware.pulseaudio.enable .#nixosConfigurations.installerIsoGraphical.config.services.pipewire.enable .#nixosConfigurations.installerIsoGraphical.config.services.pipewire.pulse.enable)",
|
||||
"Bash(nix --extra-experimental-features 'nix-command flakes' eval .#nixosConfigurations.installerIsoGraphical.config.services.displayManager.sddm.enable .#nixosConfigurations.installerIsoGraphical.config.services.displayManager.defaultSession .#nixosConfigurations.installerIsoGraphical.config.programs.hyprland.enable)",
|
||||
"Bash(nix --extra-experimental-features 'nix-command flakes' eval --json .#nixosConfigurations.installerIsoGraphical.config.users.users.nixos.extraGroups)",
|
||||
"Bash(nix --extra-experimental-features 'nix-command flakes' eval .#nixosConfigurations.installerIsoGraphical.config.hardware.pulseaudio.enable)",
|
||||
"Bash(nix --extra-experimental-features 'nix-command flakes' eval .#nixosConfigurations.installerIsoGraphical.config.services.pipewire.enable)",
|
||||
"Bash(nix --extra-experimental-features 'nix-command flakes' eval .#nixosConfigurations.installerIsoGraphical.config.services.pipewire.pulse.enable)",
|
||||
"Bash(nix --extra-experimental-features 'nix-command flakes' eval .#nixosConfigurations.installerIsoGraphical.config.programs.hyprland.enable)",
|
||||
"Bash(nix --extra-experimental-features 'nix-command flakes' eval '.#nixosConfigurations.installerIsoGraphical.config.__TRACKED_VAR__')",
|
||||
"Bash(nix --extra-experimental-features 'nix-command flakes' eval .#nixosConfigurations.installerIsoGraphical.config.home-manager.users.nixos.home.packages --apply 'builtins.length')",
|
||||
"Bash(nix --extra-experimental-features 'nix-command flakes' eval .#nixosConfigurations.default.config.home-manager.users.nomarchy.home.packages --apply 'builtins.length')",
|
||||
"Bash(chmod +x /home/bernardo/Projects/Coding/Nomarchy/features/scripts/utils/nomarchy-test-live-iso)",
|
||||
"Bash(nix --extra-experimental-features 'nix-command flakes' eval --json .#nixosConfigurations.installerIsoGraphical.config.boot.initrd.kernelModules)",
|
||||
"Bash(nix --extra-experimental-features 'nix-command flakes' eval .#homeConfigurations.nomarchy.config.programs.waybar.systemd.enable)",
|
||||
"Bash(nix --extra-experimental-features 'nix-command flakes' eval --raw .#homeConfigurations.nomarchy.config.systemd.user.services --apply 'svcs: builtins.concatStringsSep \"\\\\n\" \\(builtins.attrNames svcs\\)')",
|
||||
"Bash(nix --extra-experimental-features 'nix-command flakes' eval --raw .#homeConfigurations.nomarchy.config.gtk.iconTheme.package.pname)",
|
||||
"Bash(nix --extra-experimental-features 'nix-command flakes' eval --raw nixpkgs#everforest-gtk-variant.pname)",
|
||||
"Bash(nix --extra-experimental-features 'nix-command flakes' search nixpkgs everforest)",
|
||||
"Bash(nix --extra-experimental-features 'nix-command flakes' eval .#nixosConfigurations.default.pkgs.everforest-gtk-variant.pname)",
|
||||
"Bash(nix --extra-experimental-features 'nix-command flakes' eval .#nixosConfigurations.default.pkgs.everforest-gtk-theme.pname)",
|
||||
"Bash(nix --extra-experimental-features 'nix-command flakes' eval .#nixosConfigurations.default.pkgs.everforest-gtk-variant)",
|
||||
"Bash(nix --extra-experimental-features 'nix-command flakes' eval --impure --expr 'let pkgs = import \\(builtins.getFlake \"/home/bernardo/Projects/Coding/Nomarchy\"\\).inputs.nixpkgs { system = \"x86_64-linux\"; config.allowUnfree = true; }; in builtins.attrNames \\(pkgs // {} \\)')",
|
||||
"Bash(nix --extra-experimental-features 'nix-command flakes' eval --impure --expr 'let pkgs = import \\(builtins.getFlake \"/home/bernardo/Projects/Coding/Nomarchy\"\\).inputs.nixpkgs { system = \"x86_64-linux\"; config.allowUnfree = true; }; in builtins.concatStringsSep \"\\\\n\" \\(builtins.filter \\(n: builtins.match \".*[Ee]verforest.*\" n != null\\) \\(builtins.attrNames pkgs\\)\\)' --raw)",
|
||||
"Bash(nix --extra-experimental-features 'nix-command flakes' eval --raw .#homeConfigurations.nomarchy.config.gtk.iconTheme.name)",
|
||||
"Bash(bash -n /home/bernardo/Projects/Coding/Nomarchy/installer/install.sh)",
|
||||
"Bash(bash -n /home/bernardo/Projects/Coding/Nomarchy/installer/hardware-db.sh)",
|
||||
"Read(//tmp/**)",
|
||||
"Bash(bash -c ' *)",
|
||||
"Bash(nix --extra-experimental-features 'nix-command flakes' eval --raw .#overlays.default --apply 'o: toString \\(builtins.typeOf o\\)')",
|
||||
"Bash(nix --extra-experimental-features 'nix-command flakes' eval .#overlays.default --apply 'o: \"overlay present: \" + builtins.typeOf o')",
|
||||
"Bash(nix --extra-experimental-features 'nix-command flakes' eval --raw .#nixosConfigurations.default.config.system.nixos.distroName)",
|
||||
"Bash(nix --extra-experimental-features 'nix-command flakes' eval --raw .#nixosConfigurations.default.config.system.nixos.distroId)",
|
||||
"Bash(nix-instantiate --parse /home/bernardo/Projects/Coding/Nomarchy/installer/disko-golden.nix)",
|
||||
"Bash(nix --extra-experimental-features 'nix-command flakes' build .#nixosConfigurations.installerIsoGraphical.config.system.build.toplevel --no-link --print-out-paths)",
|
||||
"Bash(bash /home/bernardo/Projects/Coding/Nomarchy/installer/install.sh --help)",
|
||||
"Bash(bash -c 'echo \"HOSTNAME=$HOSTNAME\"')",
|
||||
"Bash(bash -c 'echo \"HOSTNAME default=$HOSTNAME\"')",
|
||||
"Bash(nix --extra-experimental-features 'nix-command flakes' eval --raw .#nixosConfigurations.installerIsoGraphical.config.services.getty.helpLine)",
|
||||
"Bash(nix --extra-experimental-features 'nix-command flakes' eval .#nixosConfigurations.default.pkgs.voxtype.pname)",
|
||||
"Bash(nix --extra-experimental-features 'nix-command flakes' eval .#nixosConfigurations.default.pkgs.opencode.pname)",
|
||||
"Bash(nix --extra-experimental-features 'nix-command flakes' build .#nixosConfigurations.default.config.system.build.vm --no-link)",
|
||||
"Bash(nix log *)",
|
||||
"Bash(nix --extra-experimental-features 'nix-command flakes' eval --json --impure --expr ' *)",
|
||||
"Bash(cat)",
|
||||
"Bash(chmod +x /tmp/theme_comparison.sh)",
|
||||
"Bash(/tmp/theme_comparison.sh)",
|
||||
"Bash(xargs -I {} dirname {})",
|
||||
"Bash(xargs -I {} basename {})",
|
||||
"Bash(chmod +x /tmp/color_compare.sh)",
|
||||
"Bash(bash /tmp/color_compare.sh)",
|
||||
"Bash(nix --extra-experimental-features \"nix-command flakes\" eval --raw 'github:nix-community/disko/latest#packages.x86_64-linux.disko.outPath')",
|
||||
"Bash(find /nix/store/*disko*/lib/disko -name \"luks*\")",
|
||||
"Bash(nix flake *)",
|
||||
"Bash(nix-instantiate --parse /home/bernardo/Projects/Coding/Nomarchy/flake.nix)",
|
||||
"Bash(nix eval *)",
|
||||
"Bash(bash installer/install.sh --dry-run)",
|
||||
"Bash(sudo bash *)",
|
||||
"Bash(chmod +x /home/bernardo/Projects/Coding/Nomarchy/core/system/scripts/nomarchy-env-update)",
|
||||
"Bash(bash -n /home/bernardo/Projects/Coding/Nomarchy/core/system/scripts/nomarchy-env-update)",
|
||||
"Bash(sed -n '1450,1500p' /home/bernardo/Projects/Coding/Nomarchy/installer/install.sh)",
|
||||
"Bash(grep -A 5 'nixosConfigurations.$HOSTNAME' /home/bernardo/Projects/Coding/Nomarchy/installer/install.sh)",
|
||||
"Bash(mkdir -p /tmp/globtest)",
|
||||
"Bash(touch nvme0n1 *)",
|
||||
"Bash(shopt -s nullglob)",
|
||||
"Bash(bash -n installer/install.sh)",
|
||||
"Bash(nix --extra-experimental-features \"nix-command flakes\" eval .#nixosConfigurations.nomarchy-live.config.system.build.toplevel.outPath)",
|
||||
"Bash(nix --extra-experimental-features \"nix-command flakes\" eval --impure --expr 'let f = import ./core/system/impermanence.nix; in \\(f { config = { nomarchy.system.impermanence = { enable = true; mainLuksName = \"crypted_main\"; }; }; lib = \\(import <nixpkgs> {}\\).lib; pkgs = null; inputs = { impermanence.nixosModules.impermanence = {}; }; }\\).config.boot.initrd.postDeviceCommands')",
|
||||
"Bash(nix --extra-experimental-features \"nix-command flakes\" eval .#nixosConfigurations.nomarchy-installer.config.system.build.toplevel.outPath)",
|
||||
"Bash(nix --extra-experimental-features \"nix-command flakes\" eval .#nixosConfigurations.nomarchy-live.config.nomarchy.system.theme)",
|
||||
"Bash(chmod +x *)",
|
||||
"Bash(./bin/utils/nomarchy-docs-scripts --out docs/SCRIPTS.md)",
|
||||
"Bash(awk '/^## Missing references/,/^## Menu items/' docs/SCRIPTS.md)",
|
||||
"Bash(bash -n bin/utils/nomarchy-docs-scripts)",
|
||||
"Bash(bash -n features/scripts/utils/nomarchy-docs-scripts)",
|
||||
"Bash(bash -n themes/engine/scripts/nomarchy-theme-next)",
|
||||
"Bash(grep '`unused?`' docs/SCRIPTS.md)",
|
||||
"Bash(awk -F'|' '{print $2}')",
|
||||
"Bash(awk *)",
|
||||
"Bash(grep -c '`unused?`' docs/SCRIPTS.md)",
|
||||
"Bash(grep -n '`unused?`' docs/SCRIPTS.md)",
|
||||
"Bash(grep '^| `__TRACKED_VAR__` ' docs/SCRIPTS.md)",
|
||||
"Bash(nix --extra-experimental-features 'nix-command flakes' flake check --no-build)",
|
||||
"Bash(grep -c '`kept`' docs/SCRIPTS.md)",
|
||||
"Bash(nix shell *)",
|
||||
"Bash(nix shell 'nixpkgs#shellcheck' --command bash -c ' *)",
|
||||
"Bash(./bin/utils/nomarchy-docs-scripts --out /tmp/SCRIPTS.regen.md)",
|
||||
"Bash(nix --extra-experimental-features 'nix-command flakes' eval --impure --expr ' *)",
|
||||
"Bash(sed -n '100,108p' core/home/options.nix)",
|
||||
"Bash(sed -n '185,195p' core/system/options.nix)",
|
||||
"Bash(nix --extra-experimental-features 'nix-command flakes' eval --impure --json --expr ' *)",
|
||||
"Bash(bash -n *)",
|
||||
"Bash(nix --extra-experimental-features 'nix-command flakes' eval --impure --raw --expr ' *)",
|
||||
"Bash(grep '^| `nomarchy-manual`' docs/SCRIPTS.md)",
|
||||
"Bash(nix *)",
|
||||
"Bash(sudo -n cat /etc/environment)",
|
||||
"Bash(systemctl --user show-environment)",
|
||||
"Bash(./bin/utils/nomarchy-docs-keybindings --out /tmp/keybindings-fresh.md)",
|
||||
"Bash(bash bin/utils/nomarchy-docs-keybindings --out /tmp/keybindings-fresh.md)",
|
||||
"Bash(nix-shell -p shellcheck --run \"shellcheck --severity=error features/scripts/utils/nomarchy-menu features/scripts/utils/nomarchy-launch-screensaver\")",
|
||||
"Bash(./bin/utils/nomarchy-docs-keybindings --out docs/KEYBINDINGS.md)",
|
||||
"Bash(grep -rEho 'jq[^\"]*--arg [a-zA-Z]+|\\\\.[a-zA-Z][a-zA-Z_0-9]+ = \\\\$|jq -r .\\\\.[a-zA-Z]+' features/scripts core/system/scripts themes/engine/scripts)",
|
||||
"Read(//home/bernardo/.config/mako/**)",
|
||||
"Read(//home/bernardo/.config/nomarchy/default/hypr/**)",
|
||||
"Read(//home/bernardo/.config/nomarchy/current/theme/**)",
|
||||
"Read(//etc/nixos/**)",
|
||||
"Bash(sudo git -C /etc/nixos log --oneline -3)",
|
||||
"Bash(PATH=/home/bernardo/Projects/Coding/Nomarchy/features/scripts/utils:/home/bernardo/Projects/Coding/Nomarchy/themes/engine/scripts:__TRACKED_VAR__ bash /home/bernardo/Projects/Coding/Nomarchy/features/scripts/utils/nomarchy-installed-summary)",
|
||||
"Bash(grep *)",
|
||||
"Bash(python3 -c \"import json,sys; d=json.load\\(sys.stdin\\); r=d['results'][0]['extensions'][0]; print\\('version:', r['versions'][0]['version']\\); print\\('displayName:', r['displayName']\\); print\\('publisher:', r['publisher']['publisherName']\\); print\\('extName:', r['extensionName']\\)\")",
|
||||
"Bash(python3 -c \"import sys,json; d=json.load\\(sys.stdin\\); [print\\(x['file'],'=',x['value']\\) for x in d]\")",
|
||||
"Bash([ -f \"core/home/config/nomarchy/default/hypr/apps/$f.conf\" ])",
|
||||
"Bash([ -f \"core/home/config/nomarchy/default/hypr/bindings/$f.conf\" ])",
|
||||
"Bash([ -f \"core/home/config/nomarchy/default/hypr/$f.conf\" ])",
|
||||
"Bash([ -f \"features/desktop/hyprland/config/$f.conf\" ])",
|
||||
"Bash(timeout 580 ./bin/utils/nomarchy-eval-matrix)",
|
||||
"Bash(break)",
|
||||
"Bash(sed -n 1,45p __TRACKED_VAR__/nix/package.nix)",
|
||||
"Bash(sed -n 1,50p __TRACKED_VAR__/nix/modules/home-manager.nix)",
|
||||
"Bash(python3 -c 'import json,sys; d=json.load\\(sys.stdin\\); print\\('\\\\''top path:'\\\\'', d.get\\('\\\\''path'\\\\'','\\\\''?'\\\\''\\)\\); inp=d.get\\('\\\\''inputs'\\\\'',{}\\); print\\('\\\\''inputs:'\\\\'', list\\(inp.keys\\(\\)\\)\\); print\\('\\\\''walker present:'\\\\'', '\\\\''walker'\\\\'' in inp\\); *)",
|
||||
"Bash(echo \"exit: $?\")",
|
||||
"Bash(echo 'output: [__TRACKED_VAR__]')",
|
||||
"Bash(time ./bin/utils/nomarchy-eval-matrix)",
|
||||
"Bash(python3 -c \"import json,sys; [print\\(x\\) for x in sorted\\(json.load\\(sys.stdin\\)\\)]\")",
|
||||
"Read(//dev/**)",
|
||||
"Bash(command -v qemu-system-x86_64 qemu-kvm)",
|
||||
"Bash(echo \"BUILD_EXIT=$?\")",
|
||||
"Bash(rm -f /tmp/nomarchy-mon.sock)",
|
||||
"Bash(mkdir -p /tmp/nomarchy-vmrun)",
|
||||
"Bash(QEMU_OPTS='-display none -monitor unix:/tmp/nomarchy-mon.sock,server,nowait -vga none' /tmp/nomarchy-vm/bin/run-nomarchy-vm)",
|
||||
"Bash(echo \"VM_EXIT=$?\")",
|
||||
"Bash(magick /tmp/shot.png -crop 5120x130+0+0 +repage /tmp/shot-top.png)",
|
||||
"Bash(magick /tmp/shot.png -crop 1400x420+0+440 +repage /tmp/shot-term.png)",
|
||||
"Bash(/nix/store/wv8bpzriikv65xnd1vciqpq7rnr8h2q2-bash-5.3p3/bin/bash -c 'compgen -G \"/etc/*\" >/dev/null 2>&1 && echo \"compgen WORKS\" || echo \"compgen MISSING \\(progcomp disabled\\)\"')",
|
||||
"Bash(compgen -G \"/etc/*\")",
|
||||
"Bash(/nix/store/wv8bpzriikv65xnd1vciqpq7rnr8h2q2-bash-5.3p3/bin/bash -c 'shopt -s nullglob; a=\\(/etc/hos*\\); echo \"nullglob ok: ${#a[@]} match\\(es\\)\"')",
|
||||
"Bash(mkdir -p /tmp/nomarchy-vmrun2)",
|
||||
"Bash(pgrep -f qemu-system)",
|
||||
"Bash(rm -rf /tmp/nomarchy-vmrun3)",
|
||||
"Bash(mkdir -p /tmp/nomarchy-vmrun3)",
|
||||
"Bash(echo \"exit=$?\")",
|
||||
"Bash(socat - unix-connect:/tmp/nomarchy-mon.sock)",
|
||||
"Bash(magick /tmp/shot3.ppm /tmp/shot3.png)",
|
||||
"Bash(magick identify *)",
|
||||
"Bash(echo \"captured -> $\\(magick identify -format '%wx%h' /tmp/shot3.png\\)\")",
|
||||
"Bash(magick /tmp/shot3.png -crop 5120x150+0+0 +repage /tmp/shot3-top.png)",
|
||||
"Bash(pkill -x qemu-system-x86)",
|
||||
"Bash(pkill -f \"qemu-system-x86_64 -machine\")",
|
||||
"Bash(rm -rf /tmp/nomarchy-vmrun4)",
|
||||
"Bash(mkdir -p /tmp/nomarchy-vmrun4)",
|
||||
"Bash(echo \"boot-exit=$?\")",
|
||||
"Bash(magick /tmp/shot4.ppm /tmp/shot4.png)",
|
||||
"Bash(echo \"captured -> $\\(magick identify -format '%wx%h' /tmp/shot4.png\\)\")",
|
||||
"Bash(magick /tmp/shot4.png -crop 5120x160+0+0 +repage /tmp/shot4-top.png)",
|
||||
"Bash(rm -rf /tmp/vmrun_final)",
|
||||
"Bash(mkdir -p /tmp/vmrun_final)",
|
||||
"Bash(magick /tmp/shot5.ppm /tmp/shot5.png)",
|
||||
"Bash(echo \"captured -> $\\(magick identify -format '%wx%h' /tmp/shot5.png\\)\")",
|
||||
"Bash(magick /tmp/shot5.png -crop 5120x170+0+0 +repage /tmp/shot5-top.png)",
|
||||
"Bash(rm -rf /tmp/vmssh)",
|
||||
"Bash(mkdir -p /tmp/vmssh)",
|
||||
"Bash(QEMU_OPTS='-display none -monitor unix:/tmp/nomarchy-mon.sock,server,nowait -vga none' QEMU_NET_OPTS=hostfwd=tcp::2222-:22 /tmp/nomarchy-vm-ssh/bin/run-nixos-vm)",
|
||||
"Bash(command -v expect)",
|
||||
"Read(//home/bernardo/.ssh/**)",
|
||||
"Bash(QEMU_OPTS='-display none -monitor unix:/tmp/nomarchy-mon.sock,server,nowait -vga none' QEMU_NET_OPTS=hostfwd=tcp::2222-:22 /tmp/nomarchy-vm-ssh/bin/run-nomarchy-vm)",
|
||||
"Bash(echo \"vm-exited rc=$?\")",
|
||||
"Bash(pkill -f \"run-nomarchy-vm\")",
|
||||
"Bash(rm -rf /tmp/vmtheme)",
|
||||
"Bash(mkdir -p /tmp/vmtheme)",
|
||||
"Bash(echo \"vm exited rc=$?\")",
|
||||
"Bash(magick /tmp/latte.ppm -resize 1700 /tmp/latte.png)",
|
||||
"Bash(echo \"saved $\\(magick identify -format '%wx%h' /tmp/latte.png\\)\")",
|
||||
"Bash(./bin/utils/nomarchy-eval-matrix)",
|
||||
"Bash(rm -f /tmp/nomarchy.qcow2 /tmp/vm-boot.log)",
|
||||
"Bash(NIX_DISK_IMAGE=/tmp/nomarchy.qcow2 QEMU_OPTS='-display none -m 4096' /tmp/vm-verify-result/bin/run-nomarchy-vm)",
|
||||
"Bash(echo \"VM PID $!\")",
|
||||
"Bash(pkill -f 'qemu-system-x86_64 -machine accel=kvm.*nomarchy')",
|
||||
"Bash(rm -f /tmp/vm-verify.nix /tmp/nomarchy.qcow2 /tmp/vm-boot.log /tmp/vm-verify-result)",
|
||||
"Bash(pkill -9 -f 'qemu-system')",
|
||||
"Bash(rm -f /tmp/nomarchy.qcow2)",
|
||||
"Bash(python3 -)",
|
||||
"Bash(sed -n '206,228p' features/scripts/utils/nomarchy-menu)",
|
||||
"Bash(pkill -9 -f 'run-nixos-vm\\\\|qemu-system-x86_64.*nomarchy')",
|
||||
"Bash(rm -f /tmp/nomarchy.qcow2 /tmp/vm-verify.nix /tmp/vm-boot.log /tmp/menu-*.sh /tmp/layout-check.sh /tmp/validate-fixes.sh /tmp/menu-cmds.txt /tmp/shipped.txt)",
|
||||
"Bash(rm -f /tmp/vm-verify-result)",
|
||||
"Bash(kill -9 1285354)",
|
||||
"Bash(sed -n '1,30p' features/scripts/battery-monitor.nix)",
|
||||
"Bash(sed -n '40,75p' features/desktop/waybar/default.nix)",
|
||||
"Bash(sed -n '140,160p' features/desktop/waybar/themes/summer-night/config.jsonc)",
|
||||
"Bash(sed -n '10,20p' features/desktop/waybar/config/config.jsonc)",
|
||||
"Bash(python3 -m json.tool)",
|
||||
"Bash(/tmp/nomarchy-multidisk-test/run-vm.sh)",
|
||||
"Bash(socat - UNIX-CONNECT:mon.sock)",
|
||||
"Bash(/tmp/nomarchy-multidisk-test/boot-from-disk.sh)",
|
||||
"Bash(socat - UNIX-CONNECT:bootmon.sock)",
|
||||
"Bash(convert /tmp/nomarchy-multidisk-test/screen.ppm /tmp/nomarchy-multidisk-test/screen.png)",
|
||||
"Bash(magick /tmp/nomarchy-multidisk-test/screen.ppm /tmp/nomarchy-multidisk-test/screen.png)",
|
||||
"Bash(shellcheck --severity=error installer/install.sh)",
|
||||
"Bash(curl -s \"https://api.github.com/repos/nix-community/home-manager/contents/modules/programs/vscode?ref=0d02ec1d0a05f88ef9e74b516842900c41f0f2fe\")",
|
||||
"Bash(python3 -c \"import json,sys;[print\\(x['name']\\) for x in json.load\\(sys.stdin\\)]\")",
|
||||
"Bash(curl -s \"https://api.github.com/repos/nix-community/home-manager/contents/modules/programs/vscode?ref=release-25.11\")",
|
||||
"Bash(curl -s \"https://api.github.com/repos/nix-community/home-manager/contents/modules/programs/vscode?ref=49ca96b2714c5931e17401eff87f3edd42d2b0f2\")",
|
||||
"Bash(python3 -c \"import json,sys;d=json.load\\(sys.stdin\\);[print\\(x['name']\\) for x in d]\")",
|
||||
"Bash(curl -s -o /dev/null -w \"%{http_code}\\\\n\" \"https://raw.githubusercontent.com/nix-community/home-manager/49ca96b2714c5931e17401eff87f3edd42d2b0f2/modules/programs/vscode/each-config.nix\")",
|
||||
"Read(//nix/store/**)",
|
||||
"Bash(mkdir -p __TRACKED_VAR__/nomarchy-install-test)",
|
||||
"Bash(qemu-img create *)",
|
||||
"Read(//home/bernardo/.config/nomarchy/**)",
|
||||
"Read(//home/bernardo/.local/share/nomarchy/**)",
|
||||
"Read(//home/bernardo/.config/elephant/**)",
|
||||
"Read(//home/bernardo/.local/share/elephant/**)",
|
||||
"Read(//home/bernardo/.config/walker/**)",
|
||||
"WebFetch(domain:raw.githubusercontent.com)",
|
||||
"Bash(python3 -c ' *)",
|
||||
"Bash(nix-store -r /nix/store/hydnry53i2qbmqq0b0872wlbzdkpq1bd-source)",
|
||||
"Bash(echo \"EXIT=$?\")",
|
||||
"Bash(sed -n '44,50p' features/default.nix)",
|
||||
"Bash(sed -n '14,20p' features/scripts/default.nix)",
|
||||
"Bash(sed -n '11,17p' themes/engine/scripts.nix)",
|
||||
"WebSearch",
|
||||
"WebFetch(domain:github.com)",
|
||||
"Bash(curl -sL \"https://api.github.com/repos/hyprwm/Hyprland/commits?sha=v0.55.3&per_page=100\")",
|
||||
"Bash(curl -sL -o /tmp/hypr-fence-fix.patch \"https://github.com/hyprwm/Hyprland/commit/bdf0aaa5409fe2e4715e2796d669e16776de0233.patch\")",
|
||||
"Bash(rm -f /tmp/nomarchy-2605.qcow2 /tmp/nomarchy-mon.sock /tmp/nomarchy-serial.sock)",
|
||||
"Bash(NIX_DISK_IMAGE=/tmp/nomarchy-2605.qcow2 QEMU_OPTS=\"-display none -monitor unix:/tmp/nomarchy-mon.sock,server,nowait -serial unix:/tmp/nomarchy-serial.sock,server,nowait\" /tmp/nomarchy-vm-2605/bin/run-nomarchy-vm)",
|
||||
"Bash(python3 *)",
|
||||
"Bash(curl -sL https://raw.githubusercontent.com/hyprwm/Hyprland/v0.55.3/CMakeLists.txt)",
|
||||
"Bash(curl -sL https://raw.githubusercontent.com/hyprwm/Hyprland/v0.55.2/CMakeLists.txt)",
|
||||
"Bash(NIX_DISK_IMAGE=/tmp/nomarchy-2605.qcow2 QEMU_OPTS=\"-display none -monitor unix:/tmp/nomarchy-mon.sock,server,nowait -serial unix:/tmp/nomarchy-serial.sock,server,nowait\" /tmp/nomarchy-vm-2605-fixed/bin/run-nomarchy-vm)",
|
||||
"Bash(xargs du -sh)",
|
||||
"Bash(xargs du -csh)",
|
||||
"Bash(curl -s https://raw.githubusercontent.com/nix-community/stylix/release-26.05/flake.nix)",
|
||||
"Bash(nix build *)",
|
||||
"Bash(echo \"exit $?\")",
|
||||
"Bash(pkill -f \"test-install.sh\")",
|
||||
"Bash(pkill -f \"qemu-system-x86_64.*NOMARCHY\\\\|qemu-system-x86_64.*nomarchy\")",
|
||||
"Bash(NOMARCHY_PATH=__TRACKED_VAR__ python3 pkgs/nomarchy-theme-sync/nomarchy-theme-sync.py --quiet apply summer-night --no-switch)",
|
||||
"Bash(NOMARCHY_PATH=__TRACKED_VAR__ python3 pkgs/nomarchy-theme-sync/nomarchy-theme-sync.py --quiet apply summer-day --no-switch)",
|
||||
"Bash(xargs cat)",
|
||||
"Bash(nix-instantiate --parse modules/home/rofi.nix)",
|
||||
"Bash(nix-instantiate --parse modules/home/shell.nix)",
|
||||
"Bash(command -v nix)",
|
||||
"Bash(nix-instantiate --parse modules/home/keys.nix)",
|
||||
"Bash(cp /home/bernardo/Projects/Nomarchy/modules/nixos/plymouth/logo.png /tmp/logo-orig.png)",
|
||||
"Bash(nix run *)",
|
||||
"Bash(cp /tmp/logo-text.png /home/bernardo/Projects/Nomarchy/.tmp-logo-preview.png)",
|
||||
"Bash(cp /tmp/logo-text.png /home/bernardo/Projects/Nomarchy/preview-logo.png)",
|
||||
"Bash(nix-instantiate --parse modules/nixos/plymouth.nix)",
|
||||
"Bash(echo \"parse OK\")",
|
||||
"Bash(echo \"=== build the plymouth theme derivation directly ===\")",
|
||||
"Bash(nix-instantiate --parse modules/nixos/default.nix)",
|
||||
"Bash(cp /nix/store/f18ij42lmpg07fn1m29aplayakx7kqpz-splash-test.png/* preview-splash-built.png)",
|
||||
"Bash(cp /nix/store/f18ij42lmpg07fn1m29aplayakx7kqpz-splash-test.png preview-splash-built.png)",
|
||||
"Bash(nix-instantiate --parse hosts/live.nix)",
|
||||
"Bash(nix-instantiate --parse modules/home/stylix.nix)",
|
||||
"Bash(nix-shell -p fontconfig --run \"fc-scan --format '%{family}\\\\n' modules/nixos/branding/Nomarchy.ttf\")"
|
||||
]
|
||||
}
|
||||
}
|
||||
3
.gitignore
vendored
3
.gitignore
vendored
@@ -8,3 +8,6 @@ result-*
|
||||
|
||||
__pycache__/
|
||||
.DS_Store
|
||||
|
||||
# Claude Code machine-local settings (permissions etc.)
|
||||
.claude/settings.local.json
|
||||
|
||||
62
README.md
62
README.md
@@ -186,8 +186,11 @@ examples: **[docs/OVERRIDES.md](docs/OVERRIDES.md)**.
|
||||
|---|---|---|
|
||||
| `nomarchy.stateFile` | — (required) | Path to your theme-state.json |
|
||||
| `nomarchy.terminal` | `"ghostty"` | Terminal for keybinds and `$TERMINAL` |
|
||||
| `nomarchy.keyboard.layout` | `"us"` | XKB layout for the Hyprland session (installer writes it; pairs with xkb + `console.useXkbConfig` in system.nix) |
|
||||
| `nomarchy.keyboard.layout` | `"us"` | XKB layout for the Hyprland session (installer writes the matching `services.xserver.xkb` in system.nix; the console + LUKS prompt follow via the distro default) |
|
||||
| `nomarchy.keyboard.variant` | `""` | XKB variant for the session |
|
||||
| `nomarchy.keyboard.devices` | `{}` | Per-device layout overrides (Hyprland `device` blocks keyed by `hyprctl devices` name) — e.g. an external keyboard with its own layout/variant |
|
||||
| `nomarchy.keyboard.layouts` | `[]` | Extra candidate layouts; when set, a watcher prompts (rofi) for a layout on a newly-connected keyboard and remembers it per-device |
|
||||
| `nomarchy.nightlight.enable` | `false` | Scheduled blue-light filter (hyprsunset) — warm at night (`.temperature`, default 4000K) between `.sunset`/`.sunrise`, no shift by day |
|
||||
| `nomarchy.hyprland.enable` | `true` | Nomarchy's Hyprland config |
|
||||
| `nomarchy.waybar.enable` | `true` | Nomarchy's Waybar |
|
||||
| `nomarchy.rofi.enable` | `true` | Themed rofi launcher + `nomarchy-menu` dispatcher |
|
||||
@@ -201,6 +204,8 @@ examples: **[docs/OVERRIDES.md](docs/OVERRIDES.md)**.
|
||||
| `nomarchy.stylix.enable` | `true` | GTK/Qt/cursor theming |
|
||||
| `nomarchy.fastfetch.enable` | `true` | fastfetch fronted by the themed Nomarchy logo |
|
||||
| `nomarchy.keys.enable` | `true` | gpg-agent fronting SSH + pinentry-qt |
|
||||
| `nomarchy.displays.enable` | `true` | nwg-displays interactive monitor arranger (helper for `nomarchy.monitors`) |
|
||||
| `nomarchy.monitors` | `[]` | Declarative per-output layout → Hyprland `monitor` rules (applied on hotplug); `,preferred,auto,1` wildcard kept as fallback |
|
||||
| `nomarchy.themesDir` | Nomarchy's `themes/` | Where per-theme app overrides are probed |
|
||||
| `nomarchy.system.plymouth.enable` | `true` | Branded boot splash, background from the theme JSON (recolors on system rebuilds) |
|
||||
| `nomarchy.system.fileManager.enable` | `true` | Thunar GUI + gvfs/tumbler/udisks2 (the "open folder" handler) |
|
||||
@@ -214,6 +219,23 @@ examples: **[docs/OVERRIDES.md](docs/OVERRIDES.md)**.
|
||||
| `nomarchy.system.power.laptop` | `false` | Marks a laptop, gating battery-only features; the installer sets it when a battery is present |
|
||||
| `nomarchy.system.power.thermal.enable` | `false` | thermald (Intel-only); the installer enables it on a GenuineIntel CPU |
|
||||
| `nomarchy.system.power.batteryChargeLimit` | `null` | Stop charging at this % (e.g. `80`) where the hardware supports it; needs `power.laptop` |
|
||||
| `nomarchy.services.tailscale.enable` | `false` | Opt-in: Tailscale mesh VPN (then `sudo tailscale up`) |
|
||||
| `nomarchy.services.syncthing.enable` | `false` | Opt-in: Syncthing file sync as the login user (GUI at `127.0.0.1:8384`) |
|
||||
| `nomarchy.services.podman.enable` | `false` | Opt-in: rootless Podman (`docker` aliased to it) |
|
||||
| `nomarchy.services.flatpak.enable` | `false` | Opt-in: Flatpak + the Flathub remote |
|
||||
| `nomarchy.services.pika.enable` | `false` | Opt-in: Pika Backup (GUI Borg backups) |
|
||||
| `nomarchy.services.steam.enable` | `false` | Opt-in: Steam via `programs.steam` (32-bit libs, controller udev, Remote-Play ports) |
|
||||
| `nomarchy.services.libvirt.enable` | `false` | Opt-in: libvirt/KVM + virt-manager GUI (login user added to `libvirtd`) |
|
||||
| `nomarchy.services.obs.enable` | `false` | Opt-in: OBS Studio + a v4l2loopback virtual camera (selectable as a webcam in Zoom/Teams) |
|
||||
| `nomarchy.services.docker.enable` | `false` | Opt-in: rootful Docker (user in `docker` group); don't enable alongside podman |
|
||||
| `nomarchy.services.kdeconnect.enable` | `false` | Opt-in: KDE Connect phone integration (opens its firewall ports) |
|
||||
| `nomarchy.services.gamemode.enable` | `false` | Opt-in: Feral GameMode performance daemon (`gamemoderun`) |
|
||||
| `nomarchy.services.adb.enable` | `false` | Opt-in: Android adb/fastboot tools (systemd handles device udev rules) |
|
||||
| `nomarchy.services.wireshark.enable` | `false` | Opt-in: Wireshark Qt GUI (user in `wireshark` group, capture without root) |
|
||||
| `nomarchy.services.ollama.enable` | `false` | Opt-in: Ollama local LLM runtime on `127.0.0.1:11434` (CPU; GPU via `services.ollama.acceleration`) |
|
||||
| `nomarchy.services.printing.enable` | `false` | Opt-in: CUPS + Avahi/mDNS network printer discovery |
|
||||
| `nomarchy.services.openrgb.enable` | `false` | Opt-in: OpenRGB daemon for RGB peripheral/motherboard lighting |
|
||||
| `nomarchy.services.restic.enable` | `false` | Opt-in: scheduled daily restic backup (set `.repository` + `.passwordFile`; 7/4/6 retention; list/restore via the `restic-nomarchy` wrapper) |
|
||||
|
||||
Beyond the `nomarchy.*` surface, the system layer turns on the usual
|
||||
desktop services with `lib.mkDefault` (override natively). One worth
|
||||
@@ -286,6 +308,32 @@ picker · `SUPER+SHIFT+T` next wallpaper · `SUPER+X` power menu ·
|
||||
clipboard history · `SUPER+Q`
|
||||
close · `SUPER+1..9` workspaces · `Print` region screenshot.
|
||||
|
||||
Shell aliases (zsh, gated on `nomarchy.shell.enable`) — `alias` lists them
|
||||
all; the curated set:
|
||||
|
||||
```sh
|
||||
# navigation
|
||||
.. ... .... # cd up 1 / 2 / 3 levels
|
||||
|
||||
# git
|
||||
g gst # git · git status -sb
|
||||
ga gaa # git add · git add -A
|
||||
gc gcm # git commit · git commit -m
|
||||
gco gsw gb # checkout · switch · branch
|
||||
gd gds # diff · diff --staged
|
||||
gl glg # log graph (last 20 · all branches)
|
||||
gp gpl gf # push · pull · fetch --all --prune
|
||||
|
||||
# nix (system/home rebuilds keep their full sys-update / home-update names)
|
||||
ns nr # nix shell · nix run (e.g. ns nixpkgs#ripgrep)
|
||||
nfu nfc # nix flake update · check
|
||||
nsearch ngc # nix search nixpkgs · nix-collect-garbage -d
|
||||
|
||||
# misc
|
||||
path # print $PATH, one entry per line
|
||||
reload # exec zsh (reload the shell)
|
||||
```
|
||||
|
||||
## 6. Extending
|
||||
|
||||
- **New theme:** drop a JSON into `themes/` (schema = any existing preset),
|
||||
@@ -294,6 +342,18 @@ close · `SUPER+1..9` workspaces · `Print` region screenshot.
|
||||
the Nix modules. One place — there is no second renderer to keep in sync.
|
||||
- **Importing more old-distro palettes:**
|
||||
`tools/import-palettes.py <palettes-dir> themes/`.
|
||||
- **New opt-in feature (convention):** when a feature is off by default and
|
||||
needs the user to set `nomarchy.*` options (e.g. night light, per-device
|
||||
keyboard layouts, monitor layout, power management), ship a **commented**
|
||||
example of it in `templates/downstream/home.nix` or `system.nix`. New
|
||||
installs then enable it by uncommenting + tweaking, rather than hunting the
|
||||
docs for the option name.
|
||||
- **Applications:** the starter complete-workstation set (LibreOffice, VS
|
||||
Code, GIMP, Inkscape) lives in the `home.packages` list in your
|
||||
`home.nix` — it's a plain package list, so curate it directly: delete a
|
||||
line to slim the machine, uncomment an extra (a browser, email, full TeX
|
||||
Live), or add your own. No `nomarchy.apps.*` toggles — a package list is
|
||||
already its own opt-out, so the distro doesn't impose these or wrap them.
|
||||
|
||||
## Roadmap & known issues
|
||||
|
||||
|
||||
304
docs/ROADMAP.md
304
docs/ROADMAP.md
@@ -37,6 +37,20 @@ how to override it. Items marked ✓ are shipped.
|
||||
launcher, no second theming pipeline; the dispatcher owns the menu
|
||||
structure, so the renderer stays swappable (we moved fuzzel → rofi 2.0
|
||||
once mainline gained native Wayland, for its richer theming)
|
||||
- ✓ **Organize the picker into category submenus:** the root picker had grown
|
||||
into a long flat list of 16 entries. It's now six: **Apps · Theme · Tools ›
|
||||
· System › · Power · Keybindings**. `Tools` (Calculator, Clipboard, Emoji,
|
||||
Files, Web, Capture, Ask) and `System` (Network, Bluetooth, DND, and the
|
||||
self-gated Snapshots / Power-profile) are submenus the dispatcher routes via
|
||||
`nomarchy-menu tools|system`, each ending in a `← Back` entry that re-opens
|
||||
the root. The direct `SUPER+CTRL+<mnemonic>` binds still hit the leaves
|
||||
straight (bypassing the menu), and the self-gated entries still hide when
|
||||
unavailable. Remaining (optional): a **Look & Feel** category once there are
|
||||
more appearance toggles to group with Theme (night-light, wallpaper).
|
||||
**General pattern (ongoing):** the grouping is a standing convention, not a
|
||||
one-off — any new feature that earns a menu entry must be placed in the
|
||||
right submenu (don't let the root creep back to a flat list), with its
|
||||
direct `SUPER+CTRL+<mnemonic>` bind and self-gating as applicable.
|
||||
- ✓ **Menu modules from rofi plugins:** the old `calc` flow committed the
|
||||
expression blind (result only in the *next* menu's `-mesg`) and `qalc -t`
|
||||
misparsed common phrasings (`15% of 200` → `rem(15, 1 B)`, the natural-
|
||||
@@ -99,10 +113,15 @@ how to override it. Items marked ✓ are shipped.
|
||||
summer-day/night menu buttons now use its `U+F000` glyph with
|
||||
`font-family: Nomarchy` pinned in their CSS (Nerd Fonts also occupy
|
||||
U+F000, so the pin is required). The other themes have no logo button.
|
||||
- **Quality-of-life command aliases:** assemble a curated collection of
|
||||
shell aliases/abbreviations for common operations (git, nix, navigation,
|
||||
the nomarchy helpers, …), themed into the zsh shell experience
|
||||
(`modules/home/shell.nix`). Decide scope and which to ship on by default.
|
||||
- ✓ **Quality-of-life command aliases:** a curated set ships on by default in
|
||||
`modules/home/shell.nix` — navigation (`..`/`...`/`....`), a git block
|
||||
(`g`, `gst`, `ga`/`gaa`, `gc`/`gcm`, `gco`/`gsw`, `gb`, `gd`/`gds`,
|
||||
`gl`/`glg`, `gp`/`gpl`, `gf`), and a nix block (`ns`, `nr`, `nfu`, `nfc`,
|
||||
`nsearch`, `ngc`), plus `path` and `reload`. Scope decision: short where it
|
||||
helps but **never shadow a real binary** (same rule as rg/fd — the git block
|
||||
deliberately avoids `gs`/ghostscript); system/home rebuilds keep their full
|
||||
`sys-update`/`home-update` names rather than getting cryptic aliases. The set
|
||||
is documented in README §5 (Day-to-day), and `alias` lists them in-shell.
|
||||
- **Theme-switch feedback:** ✓ the "rebuilding…" notification is now
|
||||
persistent (timeout 0) and replaced in place by "applied ✓" / failure
|
||||
via a synchronous tag, so a multi-minute switch never reads as a failed
|
||||
@@ -119,11 +138,21 @@ how to override it. Items marked ✓ are shipped.
|
||||
tracks the palette), `ls`→eza, `cd`→zoxide, plus `lt`/`tree`.
|
||||
`nomarchy.shell.enable`. (Deliberately did NOT alias grep→rg / find→fd:
|
||||
their flags differ enough to surprise; `rg`/`fd` ship as themselves.)
|
||||
- **Default application suite:** install a complete-workstation set
|
||||
(vscode, libreoffice, gimp, inkscape, texlive-full, …) behind a
|
||||
`nomarchy.apps.*` option surface so each is individually opt-out for
|
||||
users who want a leaner machine. Watch closure size (texlive-full is
|
||||
multi-GB — likely default-off or a lighter scheme).
|
||||
- ✓ **Default application suite:** a starter complete-workstation set —
|
||||
`libreoffice-fresh`, `vscode`, `gimp`, `inkscape` — ships *active* in the
|
||||
downstream `templates/downstream/home.nix` `home.packages`, with the heavier
|
||||
opt-ins (`texliveFull` — multi-GB; `texliveMedium` is lighter — plus
|
||||
browser/email) commented just below. **Decision: no `nomarchy.apps.*` option
|
||||
surface.** Unlike `nomarchy.services.*` (real config behind each toggle —
|
||||
systemd units, subuid ranges, the Flathub oneshot), a bare package install
|
||||
has nothing behind the toggle: `mkIf x { environment.systemPackages = [p]; }`
|
||||
just reinholds what a package list already gives, and the honest opt-out for
|
||||
a package is *deleting the line*. So the suite is the user's own curated list
|
||||
(extending the existing `# firefox` convention), not a distro-module feature —
|
||||
which also keeps the apps out of the live ISO automatically (it never starts
|
||||
from the template) and respects that editor/office/graphics are personal-taste
|
||||
choices, not defaults to impose. Unfree `vscode` evaluates fine — `mkFlake`
|
||||
and the system both set `allowUnfree = true`.
|
||||
- ✓ **Plymouth logo contrast:** the shipped art was a fixed navy that
|
||||
vanished on dark bases. `modules/nixos/plymouth.nix` now recolors every
|
||||
element from the palette at build time (flat fill, alpha kept):
|
||||
@@ -131,13 +160,15 @@ how to override it. Items marked ✓ are shipped.
|
||||
accent. Reads on light and dark; follows the theme as of the last system
|
||||
rebuild (like the background tint).
|
||||
- ✓ **Hibernate double-unlock:** on resume from hibernate the LUKS
|
||||
passphrase already gates the machine, but hypridle's `before_sleep_cmd`
|
||||
also locked hyprlock, so the user typed a password twice. Fixed with a
|
||||
`nomarchy-hibernate-unlock` systemd unit (`modules/nixos/default.nix`)
|
||||
that dismisses hyprlock *after* a hibernate resume (`WantedBy
|
||||
hibernate.target`, `After systemd-hibernate.service` → runs post-resume),
|
||||
gated on the disk being LUKS-encrypted. Suspend (and the RAM-resume phase
|
||||
of suspend-then-hibernate) keep locking — they have no passphrase gate.
|
||||
passphrase already gates the machine, but locking hyprlock before sleep
|
||||
meant a second password. Fixed by *not locking* before an encrypted
|
||||
hibernate: a `nomarchy-lock-before-sleep` systemd unit
|
||||
(`modules/nixos/default.nix`) takes over from hypridle's `before_sleep_cmd`
|
||||
and locks on the RAM-resume sleeps (suspend / hybrid-sleep / suspend-then-
|
||||
hibernate) always, but skips `hibernate.target` when the disk is LUKS-
|
||||
encrypted. (A first attempt that dismissed hyprlock *after* resume was
|
||||
wrong — killing a Wayland session-lock client trips its "go to a tty"
|
||||
crash failsafe instead of unlocking, which is the error screen it caused.)
|
||||
- ✓ **Key agents & pinentry:** ships `modules/home/keys.nix`
|
||||
(`nomarchy.keys.enable`): one agent — `services.gpg-agent` with
|
||||
`enableSshSupport` fronts SSH, so a single `pinentry-qt` (native-Wayland,
|
||||
@@ -148,14 +179,31 @@ how to override it. Items marked ✓ are shipped.
|
||||
cache. Remaining (optional): a session-level `SSH_AUTH_SOCK` export so GUI
|
||||
clients launched outside a shell also see the agent.
|
||||
- **Sanitize & organize the repo:** a housekeeping pass for consistency
|
||||
and clarity. Candidate targets (scope still to be defined): prune
|
||||
now-redundant config (e.g. the installer still writes
|
||||
`console.useXkbConfig` / `boot.initrd.systemd.enable` into `system.nix`,
|
||||
which are distro-wide defaults as of the LUKS-keymap fix); reconcile the
|
||||
README option tables with the actual `nomarchy.*` surface; audit
|
||||
comments/docs for drift against the code; and re-check that every file
|
||||
still earns its place under the `modules`/`hosts`/`themes`/`pkgs`/`tools`
|
||||
rule of thumb.
|
||||
and clarity.
|
||||
- ✓ pruned now-redundant config: the installer no longer writes
|
||||
`console.useXkbConfig` / `boot.initrd.systemd.enable` into `system.nix`
|
||||
(distro-wide defaults since the LUKS-keymap fix), nor the offline-pin
|
||||
test fixture in `flake.nix`.
|
||||
- ✓ reconciled the README option tables with the live `nomarchy.*`
|
||||
surface (added keys/fastfetch/snapper/greeter.autoLogin).
|
||||
- ✓ untracked `.claude/settings.local.json` (machine-local) + gitignored.
|
||||
- ✓ **branch/release model:** `main` is the development default; `v1` is
|
||||
the release pointer downstreams pin (`?ref=v1`), advanced to main once
|
||||
a batch is tested — rolling, no tags. Brought `main` current (it was a
|
||||
stale legacy-merge), and deleted the dead `refactor` / `wave/nixos-26.05`
|
||||
branches (kept `legacy` for history). See the comment in `flake.nix`.
|
||||
- ✓ re-checked that every file earns its place under the
|
||||
`modules`/`hosts`/`themes`/`pkgs`/`tools` rule of thumb: no orphaned
|
||||
modules (`keybinds.nix` is a *data* module `import`-ed by hyprland/rofi,
|
||||
so correctly absent from `default.nix`), no dead-code markers, no
|
||||
editor/backup cruft, each `themes/<slug>.json` palette pairs with its
|
||||
optional `<slug>/` overrides dir, and `hosts/{default,live}` are the
|
||||
documented reference + ISO hosts. Structure is clean as-is.
|
||||
- Open decision (deferred): the repo declares **no formatter** (no flake
|
||||
`formatter`, no `.editorconfig`); `.nix` files use deliberate aligned
|
||||
hand-formatting, so `nixfmt-rfc-style --check` flags ~33 files. Adopting a
|
||||
formatter would be a one-time repo-wide reformat that flattens that
|
||||
alignment — a maintainer call, not a silent cleanup, so left untouched.
|
||||
- **Full docs review & restructure:** a dedicated pass over all the prose,
|
||||
not just the code-adjacent cleanup the repo-sanitize item covers. The
|
||||
README has grown to ~540 lines with a ~200-line roadmap inline — the
|
||||
@@ -195,47 +243,178 @@ how to override it. Items marked ✓ are shipped.
|
||||
idle behaviour.
|
||||
- Remaining: a boot-only→event-driven charge-limit re-apply (udev) if a
|
||||
firmware resets the threshold on unplug.
|
||||
- ✓ **Waybar parity:** the `custom/powerprofile` indicator now shows in the
|
||||
summer-day/night whole-swap themes too. `powerProfileStatus`/`Cycle` are
|
||||
named `writeShellScriptBin`s on PATH (`waybar.nix` home.packages), so the
|
||||
generated config and the static `waybar.jsonc` both exec them by bare
|
||||
name (the same parity the DND bell has). General pattern: any new
|
||||
generated-config module needs adding to the whole-swap themes too.
|
||||
- **Full hardware enablement (beyond nixos-hardware):** nixos-hardware
|
||||
profiles cover *basic* per-model functionality (quirks, drivers), but the
|
||||
*advanced* features of a machine — keyed more on the CPU/GPU generation
|
||||
than the model — are left for the user to wire up by hand. Close that gap
|
||||
without making it finnicky: extend the installer's existing autodetection
|
||||
(DMI → nixos-hardware profile today; add CPU vendor/arch, GPU, NPU,
|
||||
fingerprint reader, SSD) to switch on the *safe, broadly-beneficial*
|
||||
features automatically, and expose a small `nomarchy.hardware.*` surface
|
||||
(per-vendor where it helps, e.g. `nomarchy.hardware.amd.*`) for the heavy
|
||||
or experimental bits. Goal: full utilisation out of the box — opt-*out* for
|
||||
the safe defaults, opt-*in* for the multi-GB / experimental extras.
|
||||
Complements nixos-hardware (model quirks) rather than replacing it; keep
|
||||
the detection in the installer's `hardware-db` so an installed machine
|
||||
bakes the right defaults, all overridable through `nomarchy.hardware.*`.
|
||||
Worked example — ThinkPad T14s (Ryzen 7 PRO 7840U + Radeon 780M):
|
||||
- **GPU compute — ROCm:** the 780M is an RDNA3 iGPU (gfx1103) ROCm doesn't
|
||||
officially list, so it needs `HSA_OVERRIDE_GFX_VERSION=11.0.0`. Multi-GB
|
||||
closure → opt-in (`nomarchy.hardware.amd.rocm.enable`); unlocks GPU
|
||||
PyTorch / Ollama.
|
||||
- **Ryzen AI NPU (XDNA):** the `amdxdna` kernel driver (mainline 6.14+) +
|
||||
the XRT/xdna userspace runtime + firmware. Niche/experimental → opt-in.
|
||||
- **AMD P-State EPP (Zen 4 power):** `amd_pstate=active` for the EPP
|
||||
governor, which power-profiles-daemon (already shipped, `power.nix`)
|
||||
drives per profile. Broadly beneficial on Zen 2+ → default on when the
|
||||
installer sees an AMD CPU.
|
||||
- **Hardware video acceleration (VA-API):** mesa's radeonsi exposes VA-API
|
||||
on AMD (`LIBVA_DRIVER_NAME=radeonsi`, libva + drivers in
|
||||
`hardware.graphics.extraPackages`); Intel uses `intel-media-driver`.
|
||||
Broadly beneficial → default on, vendor-detected.
|
||||
- **LVFS firmware & biometrics:** fwupd already ships (✓, `services.fwupd`).
|
||||
Add fingerprint: `services.fprintd` when a reader is detected, with
|
||||
opt-in PAM integration for login/sudo (password-only stays the default
|
||||
for the cautious).
|
||||
- **SSD periodic TRIM:** `services.fstrim.enable` (weekly) — safe and
|
||||
beneficial, so default on (trivial enough it may warrant being
|
||||
distro-wide regardless).
|
||||
Sub-items here can graduate into their own roadmap entries as they're
|
||||
scoped; the unifying work is the detection + `nomarchy.hardware.*` surface.
|
||||
- **Opt-in services & integrations:** the counterpart to the opt-*out*
|
||||
application suite above — heavier or more personal integrations shipped
|
||||
**off by default**, each a `nomarchy.services.<name>.enable` toggle a
|
||||
downstream flips on in one line. Keeps the base lean while making common
|
||||
additions trivial. Candidates by area:
|
||||
- **cloud/sync:** Nextcloud client; Syncthing (`services.syncthing`)
|
||||
- **local AI:** LM Studio (`lmstudio`); Ollama (`services.ollama`, optional
|
||||
GPU accel) — pairs with the menu's Ask-Claude philosophy
|
||||
- **containers/VMs:** Docker/Podman; libvirt + virt-manager
|
||||
- **networking:** Tailscale (`services.tailscale`); WireGuard
|
||||
- **gaming/media:** Steam (`programs.steam`); OBS Studio
|
||||
- **devices:** printing (CUPS + Avahi); KDE Connect / phone integration;
|
||||
OpenRGB
|
||||
- **backup:** restic/borg (`services.restic`)
|
||||
- **escape hatch:** Flatpak (`services.flatpak`) for apps outside nixpkgs
|
||||
additions trivial. **✓ Seventeen shipped** in `modules/nixos/services.nix`
|
||||
(system-side), each with a commented example in the downstream `system.nix`
|
||||
template: `tailscale`, `syncthing` (runs as the login user, GUI on
|
||||
127.0.0.1:8384), `podman` (rootless, `docker` aliased, user subuid/subgid),
|
||||
`flatpak` (+ Flathub remote added by a oneshot), `pika` (Pika Backup GUI),
|
||||
`steam` (`programs.steam` — the 32-bit stack, controller udev, Remote-Play
|
||||
ports a bare package can't), `libvirt` (libvirtd + virt-manager, user added
|
||||
to the `libvirtd` group), `obs` (OBS Studio + a v4l2loopback virtual camera
|
||||
usable as a webcam in Zoom/Teams), `docker` (rootful; asserts against the
|
||||
podman docker-compat), `kdeconnect`, `gamemode`, `adb` (android-tools;
|
||||
systemd handles the udev rules), `wireshark` (Qt GUI + the `wireshark`
|
||||
group), `ollama` (local LLM API on 127.0.0.1:11434), `printing` (CUPS +
|
||||
Avahi mDNS), `openrgb` (RGB lighting daemon), and `restic` (scheduled
|
||||
daily backup — a small option surface: `repository`/`passwordFile`/`paths`,
|
||||
7/4/6 retention). More candidates by area:
|
||||
- ✓ **cloud/sync:** Syncthing (`services.syncthing`); Nextcloud client is a
|
||||
bare tray app (in the app-suite menu, not a service)
|
||||
- ✓ **local AI:** Ollama (`nomarchy.services.ollama`, optional GPU accel)
|
||||
ships; LM Studio is a (commented) app-suite package (a bare GUI, no
|
||||
service) — pairs with the menu's Ask-Claude philosophy
|
||||
- ✓ **containers/VMs:** Podman (`virtualisation.podman`); libvirt +
|
||||
virt-manager (`nomarchy.services.libvirt`); Docker (`nomarchy.services.docker`)
|
||||
- ✓ **networking:** Tailscale (`services.tailscale`); WireGuard needs no
|
||||
toggle — NetworkManager (on by default) imports `.conf` tunnels natively;
|
||||
the `wireguard-tools` CLI is in the app-suite menu
|
||||
- ✓ **gaming/media:** Steam (`nomarchy.services.steam`); OBS Studio
|
||||
(`nomarchy.services.obs`, with the v4l2loopback virtual camera); GameMode
|
||||
(`nomarchy.services.gamemode`)
|
||||
- ✓ **devices:** printing (CUPS + Avahi, `nomarchy.services.printing`); KDE
|
||||
Connect (`nomarchy.services.kdeconnect`); OpenRGB
|
||||
(`nomarchy.services.openrgb`). Plus dev tooling — Android `adb` and
|
||||
`wireshark` toggles
|
||||
- ✓ **backup:** Pika Backup (`pika-backup`, GUI over Borg); scheduled
|
||||
headless restic (`nomarchy.services.restic`)
|
||||
- ✓ **escape hatch:** Flatpak (`services.flatpak`) + Flathub, for apps
|
||||
outside nixpkgs
|
||||
|
||||
Decisions: the curated set; whether system services and GUI apps share one
|
||||
surface or split (`nomarchy.services.*` system-side vs home-side packages);
|
||||
and how it relates to `nomarchy.apps.*` (opt-out suite). Unfree entries are
|
||||
Surface decided: `nomarchy.services.*`, system-side for system services
|
||||
(home-side ones can extend the same prefix later). Remaining: curate the
|
||||
rest (Ollama, containers, Steam/OBS, printing, backups, Flatpak …). The
|
||||
opt-out application *suite* is deliberately **not** a parallel
|
||||
`nomarchy.apps.*` surface — it's a curated `home.packages` list in the
|
||||
downstream template (see "Default application suite" above), since a bare
|
||||
package install has no config to put behind a toggle. Unfree entries are
|
||||
already covered (`allowUnfree = true`).
|
||||
- **Display / monitor management:** today Hyprland just uses
|
||||
`monitor = ,preferred,auto,1` (mkDefault). Add a real external-monitor/dock
|
||||
story: declarative per-output config, hotplug profiles (kanshi-style, or
|
||||
Hyprland's own monitor rules), and optionally a GUI arranger (nwg-displays
|
||||
writes Hyprland monitor config). Decide declarative-only vs GUI, and the
|
||||
option shape (`nomarchy.monitors` vs plain Hyprland `monitor` lists).
|
||||
- **Night light / blue-light filter:** schedulable colour-temperature shift
|
||||
via `hyprsunset` (Hyprland-native; wlsunset/gammastep are alternatives) —
|
||||
sunset/sunrise or a fixed schedule, with a menu + Waybar toggle.
|
||||
- **Runtime keyboard-layout switching:** the session layout is a single
|
||||
`nomarchy.keyboard.layout` today. Support a list of layouts with a toggle
|
||||
bind (`hyprctl switchxkblayout` / xkb `grp:` options) and a Waybar
|
||||
indicator for the active layout. Natural follow-on to the LUKS-keymap work
|
||||
— keep the system (console/initrd) and session layouts in sync.
|
||||
- **Do-Not-Disturb:** a swaync DND toggle (`swaync-client -dn`) wired into
|
||||
the menu and a Waybar indicator, to silence notifications for
|
||||
presentations/focus.
|
||||
- **Snapshot browse/restore UX:** snapper already takes BTRFS timeline
|
||||
snapshots (`nomarchy.system.snapper`); surface them from the desktop — a
|
||||
rofi menu (or btrfs-assistant) to browse/diff/restore and boot-from-
|
||||
snapshot — so rollback isn't CLI-only.
|
||||
- ✓ **Display / monitor management:** declarative `nomarchy.monitors` (a
|
||||
per-output schema — name/resolution/position/scale/transform/mirror/
|
||||
bitdepth/vrr/disable) generates Hyprland `monitor` rules, keeping the
|
||||
`,preferred,auto,1` wildcard as the fallback; Hyprland applies them on
|
||||
hotplug, so a declared external/dock output arranges itself on connect
|
||||
(no kanshi — it fights Hyprland's own output management). `nwg-displays`
|
||||
ships behind `nomarchy.displays.enable` as an interactive arranger (a
|
||||
helper to find values; the declarative config stays the source of truth —
|
||||
its output file isn't sourced). Remaining: true docked/undocked **profile
|
||||
switching** of the *same* outputs (Hyprland's per-output rules cover the
|
||||
common "external connects → arrange" case, not multi-layout toggles), and
|
||||
optionally workspace-to-monitor binding.
|
||||
- ✓ **Night light / blue-light filter:** `nomarchy.nightlight` (opt-in) —
|
||||
a scheduled colour-temperature shift via `hyprsunset` (Hyprland-native),
|
||||
warm at night, identity (no shift) by day. `modules/home/nightlight.nix`
|
||||
drives the HM `services.hyprsunset` with two time-based profiles
|
||||
(`sunrise` → identity, `sunset` → `temperature`), so hyprsunset handles the
|
||||
schedule and the on-login state. Needs an on-hardware check that hyprsunset
|
||||
applies the active profile at session start. Remaining (optional): a menu +
|
||||
Waybar toggle to force it on/off, and geo (lat/long) auto sunset/sunrise
|
||||
(would mean wlsunset, which schedules by location).
|
||||
- **Keyboard layouts (per-device + switching):**
|
||||
- ✓ **Per-device declarative layout:** `nomarchy.keyboard.devices`
|
||||
(`{ "<hyprctl-device-name>" = { layout; variant; }; }`) generates Hyprland
|
||||
`device` blocks that override the session `nomarchy.keyboard.layout` for a
|
||||
named keyboard — e.g. an external board that's physically a different
|
||||
layout than the laptop's. Hyprland applies it whenever that device
|
||||
connects (the "external keyboard remembers its layout" case, done the
|
||||
declarative way). A Waybar `hyprland/language` indicator shows the active
|
||||
layout, gated on more than one layout being in play (comma in the session
|
||||
layout, or any per-device override) so single-layout bars stay clean.
|
||||
- ✓ **Interactive new-keyboard prompt (runtime + persist):** set
|
||||
`nomarchy.keyboard.layouts` (candidate layouts) and a `nomarchy-keyboard-
|
||||
watch` daemon runs (exec-once): it polls `hyprctl devices`, and when a
|
||||
keyboard connects *after* login that isn't in `keyboard.devices` and
|
||||
hasn't been chosen before, it pops a rofi layout picker, applies the
|
||||
choice with `hyprctl switchxkblayout` (an index into the candidate set,
|
||||
which `input.kb_layout` carries), and remembers it per-device in
|
||||
`~/.local/state/nomarchy/keyboard-layouts` — re-applied silently on later
|
||||
reconnects. The boot-time set (incl. the built-in keyboard) is never
|
||||
prompted. The runtime-remember complement to the declarative
|
||||
`keyboard.devices`; a stateful runtime piece by design. **Pending an
|
||||
on-hardware test** (hotplug isn't verifiable in CI). Remaining (bonus):
|
||||
offer to write a choice into `keyboard.devices` so it graduates to the
|
||||
reproducible config.
|
||||
- Remaining: a multi-layout cycle bind (`hyprctl switchxkblayout` / xkb
|
||||
`grp:` options) for switching layouts on one keyboard; add the
|
||||
`hyprland/language` module to the summer whole-swap themes for parity
|
||||
(the gating doesn't translate to their static JSON). Keep the system
|
||||
(console/initrd) and session layouts in sync (the LUKS-keymap work).
|
||||
- ✓ **Do-Not-Disturb:** swaync DND toggle wired into the menu
|
||||
(`nomarchy-menu dnd`, in the picker, SUPER+CTRL+D) and a Waybar bell
|
||||
indicator (`custom/notification` via `swaync-client -swb`: shows the
|
||||
notification count + DND state, left-click toggles the panel,
|
||||
right-click toggles DND). Turning DND off confirms with a toast; turning
|
||||
it on is silent (notifications are suppressed — the bell-off glyph is the
|
||||
cue).
|
||||
- ✓ **Snapshot browse/restore UX:** `nomarchy-menu snapshot` (in the SUPER+M
|
||||
picker, self-gated on snapper) launches **btrfs-assistant** — the
|
||||
desktop browse/diff/restore/rollback UI, elevating via polkit (the safe
|
||||
choice for a destructive, root-only op vs a fat-fingerable rofi rollback).
|
||||
Shipped system-side gated on `nomarchy.system.snapper`. Also extended
|
||||
snapper to snapshot **/home** by default (hourly 5 / daily 7 / weekly 4)
|
||||
when it's its own BTRFS subvolume; a boot oneshot creates the required
|
||||
`/home/.snapshots` subvolume if missing (covers existing installs, no disko
|
||||
change). **The backend is VM-verified** (a full BTRFS+LUKS install: both
|
||||
`root`+`home` configs, a `/home` timeline snapshot taken, `/home/.snapshots`
|
||||
a real subvolume, the oneshot `Result=success`).
|
||||
- ⚠ **Known bug — btrfs-assistant 2.2 segfaults on launch** in nixpkgs
|
||||
26.05: it crashes inside `libbtrfsutil.so.1.4.0` (a library ABI mismatch,
|
||||
confirmed in the VM regardless of GL/Qt platform — so it's not a VM/GL
|
||||
artifact and will crash on hardware too). The menu wiring is correct and
|
||||
the app is installed, but the GUI doesn't open. The snapshot *backend*
|
||||
(the actual snapshots) is unaffected. Fix path: a nixpkgs override aligning
|
||||
its libbtrfsutil, or wait for an upstream bump; meanwhile the menu entry
|
||||
is a no-op when the binary crashes. Fallback if it lingers: a rofi-based
|
||||
snapshot menu (no btrfs-assistant dependency).
|
||||
- Remaining (optional): a keyboard-driven rofi browse for quick glances;
|
||||
boot-from-snapshot needs a systemd-boot equivalent of grub-btrfs.
|
||||
- **Update awareness:** updates are manual today (`sys-update`/`home-update`);
|
||||
add a Waybar indicator / notification when flake inputs are stale or a new
|
||||
nixpkgs rev is available (optionally with a pending-change count). Augments,
|
||||
@@ -287,5 +466,8 @@ how to override it. Items marked ✓ are shipped.
|
||||
dark. `stylix.nix` now sets `dconf` `org/gnome/desktop/interface
|
||||
color-scheme` = `prefer-light`/`prefer-dark` from `t.mode`
|
||||
(xdg-desktop-portal-gtk already ships, and `programs.dconf` is on
|
||||
system-side), so libadwaita/Qt follow the palette. Needs a live session
|
||||
to confirm the portal picks it up for all apps.
|
||||
system-side), so libadwaita/Qt follow the palette. Confirmed in a live
|
||||
session (headless QEMU): the portal's `org.freedesktop.appearance`
|
||||
`color-scheme` reads `1` on a dark theme and flips to `2` after switching
|
||||
to a light one (catppuccin-latte) — so xdg-desktop-portal-gtk does relay
|
||||
the dconf value GTK4/Qt apps read.
|
||||
|
||||
13
flake.nix
13
flake.nix
@@ -51,8 +51,11 @@
|
||||
(nixpkgs.lib.concatStringsSep "\n"
|
||||
(builtins.attrNames nixos-hardware.nixosModules));
|
||||
nixpkgsPath = nixpkgs.outPath;
|
||||
# v1 is the release branch: installed machines track it on
|
||||
# `nix flake update` instead of the forge's default branch.
|
||||
# Branch model: `main` is the development default; `v1` is the
|
||||
# release pointer — the stable line for the NixOS 26.05 rewrite,
|
||||
# advanced to main once a batch is tested (rolling, no tags). A
|
||||
# future major bump would become `v2`. Installed machines track
|
||||
# `?ref=v1` on `nix flake update`, not the forge's default branch.
|
||||
flakeUrl = "git+${gitUrl}?ref=v1";
|
||||
# Future updates re-resolve from the forge (original); the install
|
||||
# itself resolves from the ISO store (locked = path) — fully
|
||||
@@ -252,12 +255,6 @@
|
||||
({ lib, ... }: {
|
||||
nomarchy.system.snapper.enable = true;
|
||||
nomarchy.system.greeter.autoLogin = username;
|
||||
# The installer writes these (keyboard-everywhere
|
||||
# incl. the LUKS prompt) — mirror them or the
|
||||
# initrd/vconsole pins don't match an offline
|
||||
# install's rebuild set.
|
||||
console.useXkbConfig = true;
|
||||
boot.initrd.systemd.enable = true;
|
||||
# nixos-generate-config keys microcode off
|
||||
# enableRedistributableFirmware (now on): the
|
||||
# real machine enables exactly one vendor —
|
||||
|
||||
@@ -17,6 +17,7 @@
|
||||
./idle.nix # hyprlock + hypridle, themed from the same JSON
|
||||
./yazi.nix # flagship TUI file manager, themed + plugins
|
||||
./osd.nix # swayosd volume/brightness OSD, themed
|
||||
./nightlight.nix # scheduled blue-light filter (hyprsunset), opt-in
|
||||
./shell.nix # zsh + starship + bat/eza/zoxide, themed
|
||||
./keys.nix # gpg-agent (fronts SSH) + pinentry-qt
|
||||
./fastfetch.nix # system info with the themed Nomarchy logo
|
||||
|
||||
@@ -41,6 +41,77 @@ let
|
||||
# (rofi.nix renders the same list). Edit them in ./keybinds.nix.
|
||||
keybinds = import ./keybinds.nix;
|
||||
mkBind = b: "${b.mods}, ${b.key}, ${b.action}";
|
||||
|
||||
# A nomarchy.monitors entry -> a Hyprland `monitor` rule. Unset optional
|
||||
# fields are omitted; `resolution = "disable"` collapses to the short form.
|
||||
monitorRule = m:
|
||||
if m.resolution == "disable" then "${m.name}, disable"
|
||||
else lib.concatStringsSep ", " (
|
||||
[ m.name m.resolution (toString m.position) (toString m.scale) ]
|
||||
++ lib.optionals (m.transform != null) [ "transform" (toString m.transform) ]
|
||||
++ lib.optionals (m.mirror != null) [ "mirror" m.mirror ]
|
||||
++ lib.optionals (m.bitdepth != null) [ "bitdepth" (toString m.bitdepth) ]
|
||||
++ lib.optionals (m.vrr != null) [ "vrr" (toString m.vrr) ]
|
||||
++ lib.optional (m.extra != "") m.extra
|
||||
);
|
||||
|
||||
# Keyboard layout candidates: the primary nomarchy.keyboard.layout (split on
|
||||
# commas) plus any nomarchy.keyboard.layouts. Drives input.kb_layout so all
|
||||
# of them are switchable, and feeds the watcher's picker.
|
||||
kbLayouts = lib.unique (
|
||||
(lib.splitString "," config.nomarchy.keyboard.layout)
|
||||
++ config.nomarchy.keyboard.layouts
|
||||
);
|
||||
kbAutoSwitch = config.nomarchy.keyboard.layouts != [ ];
|
||||
|
||||
# On a keyboard that connects after login (not declared in
|
||||
# keyboard.devices, not already remembered), ask for a layout and persist it
|
||||
# per-device, re-applying silently on later reconnects. Stateful runtime
|
||||
# piece — the complement to the declarative keyboard.devices. Reliable
|
||||
# primitives only: poll hyprctl devices, apply via switchxkblayout (an index
|
||||
# into kbLayouts). NOTE: needs an on-hardware test (hotplug isn't verifiable
|
||||
# in CI).
|
||||
keyboardWatch = pkgs.writeShellScriptBin "nomarchy-keyboard-watch" ''
|
||||
set -u
|
||||
layouts="${lib.concatStringsSep " " kbLayouts}"
|
||||
declared="${lib.concatStringsSep " " (builtins.attrNames config.nomarchy.keyboard.devices)}"
|
||||
state="''${XDG_STATE_HOME:-$HOME/.local/state}/nomarchy/keyboard-layouts"
|
||||
mkdir -p "$(dirname "$state")"; [ -f "$state" ] || : > "$state"
|
||||
|
||||
layout_index() { i=0; for l in $layouts; do [ "$l" = "$1" ] && { printf %s "$i"; return; }; i=$((i + 1)); done; printf %s -1; }
|
||||
apply() { idx=$(layout_index "$2"); [ "$idx" -ge 0 ] && hyprctl switchxkblayout "$1" "$idx" >/dev/null 2>&1; }
|
||||
keyboards() { hyprctl devices -j | jq -r '.keyboards[].name'; }
|
||||
is_declared() { case " $declared " in *" $1 "*) return 0 ;; *) return 1 ;; esac; }
|
||||
saved_for() { while IFS='=' read -r k v; do [ "$k" = "$1" ] && { printf '%s' "$v"; return; }; done < "$state"; }
|
||||
|
||||
# Startup: re-apply remembered layouts, never prompt — so the built-in
|
||||
# keyboard just stays on the session default.
|
||||
prev=" "
|
||||
for kb in $(keyboards); do
|
||||
prev="$prev$kb "
|
||||
is_declared "$kb" && continue
|
||||
s=$(saved_for "$kb"); [ -n "$s" ] && apply "$kb" "$s"
|
||||
done
|
||||
|
||||
# Watch for keyboards that connect later.
|
||||
while :; do
|
||||
sleep 3
|
||||
cur=" "
|
||||
for kb in $(keyboards); do
|
||||
cur="$cur$kb "
|
||||
case "$prev" in *" $kb "*) continue ;; esac
|
||||
is_declared "$kb" && continue
|
||||
s=$(saved_for "$kb")
|
||||
if [ -n "$s" ]; then
|
||||
apply "$kb" "$s"
|
||||
else
|
||||
choice=$(printf '%s\n' $layouts | rofi -dmenu -p "Layout · $kb")
|
||||
[ -n "$choice" ] && { printf '%s=%s\n' "$kb" "$choice" >> "$state"; apply "$kb" "$choice"; }
|
||||
fi
|
||||
done
|
||||
prev="$cur"
|
||||
done
|
||||
'';
|
||||
in
|
||||
{
|
||||
wayland.windowManager.hyprland = lib.mkIf config.nomarchy.hyprland.enable {
|
||||
@@ -59,9 +130,12 @@ in
|
||||
"$mod" = "SUPER";
|
||||
"$terminal" = config.nomarchy.terminal;
|
||||
|
||||
# mkDefault so a downstream `monitor = [...]` replaces it with a
|
||||
# plain assignment (the live ISO uses mkForce for the same reason).
|
||||
monitor = lib.mkDefault [ ",preferred,auto,1" ];
|
||||
# `,preferred,auto,1` is the wildcard fallback for any output not in
|
||||
# nomarchy.monitors; the generated rules are appended and win by name,
|
||||
# and Hyprland applies them on hotplug. mkDefault so a downstream
|
||||
# `monitor = [...]` replaces the lot (the live ISO uses mkForce too).
|
||||
monitor = lib.mkDefault
|
||||
([ ",preferred,auto,1" ] ++ map monitorRule config.nomarchy.monitors);
|
||||
|
||||
# exec-once is a list at normal priority, so downstream additions
|
||||
# CONCATENATE (your autostart runs alongside ours) rather than
|
||||
@@ -72,7 +146,7 @@ in
|
||||
# Paint the wallpaper as soon as the session is up (waits for
|
||||
# the daemon internally).
|
||||
"nomarchy-theme-sync wallpaper"
|
||||
];
|
||||
] ++ lib.optional kbAutoSwitch "${keyboardWatch}/bin/nomarchy-keyboard-watch";
|
||||
|
||||
# ── Theme-driven look ──────────────────────────────────────────
|
||||
# These flow from theme-state.json and stay at NORMAL priority:
|
||||
@@ -128,12 +202,20 @@ in
|
||||
input = {
|
||||
# kb_layout/variant come from nomarchy.keyboard.* — set that
|
||||
# option (the installer writes it; it also drives tty/LUKS).
|
||||
kb_layout = config.nomarchy.keyboard.layout;
|
||||
kb_layout = lib.concatStringsSep "," kbLayouts;
|
||||
kb_variant = config.nomarchy.keyboard.variant;
|
||||
follow_mouse = lib.mkDefault 1;
|
||||
touchpad.natural_scroll = lib.mkDefault true;
|
||||
};
|
||||
|
||||
# Per-device keyboard layouts (nomarchy.keyboard.devices): each
|
||||
# overrides the session kb_layout for one named keyboard — e.g. an
|
||||
# external board that's physically a different layout than the laptop's
|
||||
# built-in one. Hyprland applies them whenever the device connects.
|
||||
device = lib.mapAttrsToList
|
||||
(name: d: { inherit name; kb_layout = d.layout; kb_variant = d.variant; })
|
||||
config.nomarchy.keyboard.devices;
|
||||
|
||||
# dwindle:pseudotile was removed in Hyprland 0.55 (the `pseudo`
|
||||
# dispatcher still exists); setting it aborts config parsing.
|
||||
dwindle.preserve_split = lib.mkDefault true;
|
||||
@@ -183,4 +265,12 @@ in
|
||||
];
|
||||
};
|
||||
};
|
||||
|
||||
# nwg-displays: interactive monitor arranger (applies live via hyprctl and
|
||||
# writes a config file). A helper to find values for nomarchy.monitors —
|
||||
# the declarative config stays the source of truth (we don't source its
|
||||
# output). Gated on its toggle; pointless without the Hyprland session.
|
||||
home.packages = lib.optionals
|
||||
(config.nomarchy.hyprland.enable && config.nomarchy.displays.enable)
|
||||
[ pkgs.nwg-displays ];
|
||||
}
|
||||
|
||||
@@ -64,11 +64,13 @@ in
|
||||
settings = {
|
||||
general = {
|
||||
lock_cmd = "pidof hyprlock || hyprlock";
|
||||
# Locks before every sleep. For suspend that's exactly right; on an
|
||||
# encrypted hibernate the LUKS resume already gates the machine, so
|
||||
# the system side dismisses this lock post-resume to avoid a double
|
||||
# unlock — see nomarchy-hibernate-unlock in modules/nixos/default.nix.
|
||||
before_sleep_cmd = "loginctl lock-session";
|
||||
# No before_sleep_cmd here: locking before sleep is driven
|
||||
# system-side so it can fire for suspend but skip an encrypted
|
||||
# hibernate — whose LUKS resume already gates the machine, so a
|
||||
# hyprlock on top is a second password (and a Wayland session-lock
|
||||
# can't be safely dropped after the fact — killing the locker trips
|
||||
# its "go to a tty" crash failsafe). See nomarchy-lock-before-sleep
|
||||
# in modules/nixos/default.nix.
|
||||
after_sleep_cmd = "hyprctl dispatch dpms on";
|
||||
};
|
||||
listener = [
|
||||
|
||||
@@ -47,6 +47,7 @@
|
||||
{ mods = "$mod CTRL"; key = "B"; action = "exec, nomarchy-menu bluetooth"; desc = "Bluetooth"; }
|
||||
{ mods = "$mod CTRL"; key = "S"; action = "exec, nomarchy-menu capture"; desc = "Screenshot / capture"; }
|
||||
{ mods = "$mod CTRL"; key = "A"; action = "exec, nomarchy-menu ask"; desc = "Ask Claude"; }
|
||||
{ mods = "$mod CTRL"; key = "D"; action = "exec, nomarchy-menu dnd"; desc = "Do Not Disturb toggle"; }
|
||||
|
||||
# Focus
|
||||
{ mods = "$mod"; key = "H"; action = "movefocus, l"; desc = "Focus left"; }
|
||||
|
||||
25
modules/home/nightlight.nix
Normal file
25
modules/home/nightlight.nix
Normal file
@@ -0,0 +1,25 @@
|
||||
# Night light — a scheduled blue-light filter via hyprsunset (Hyprland's own
|
||||
# gamma/temperature tool). Warm at night, identity (no shift) by day;
|
||||
# hyprsunset's time-based `profile` entries handle the schedule and pick the
|
||||
# right state on session start. Opt-in via nomarchy.nightlight.enable.
|
||||
#
|
||||
# The hyprsunset HM service module is provided by home-manager; this only
|
||||
# configures it. Override anything with plain services.hyprsunset.* options.
|
||||
{ config, lib, ... }:
|
||||
|
||||
let
|
||||
cfg = config.nomarchy.nightlight;
|
||||
in
|
||||
{
|
||||
config = lib.mkIf cfg.enable {
|
||||
services.hyprsunset = {
|
||||
enable = true;
|
||||
settings.profile = [
|
||||
# Daytime: identity = no colour change.
|
||||
{ time = cfg.sunrise; identity = true; }
|
||||
# Night: shift to the warm temperature.
|
||||
{ time = cfg.sunset; temperature = cfg.temperature; }
|
||||
];
|
||||
};
|
||||
};
|
||||
}
|
||||
@@ -2,6 +2,60 @@
|
||||
# configure in their home.nix. Kept small on purpose.
|
||||
{ lib, pkgs, ... }:
|
||||
|
||||
let
|
||||
# One output's layout — turned into a Hyprland `monitor` rule in
|
||||
# hyprland.nix. Friendlier than raw positional CSV; unset optional fields
|
||||
# are omitted from the rule.
|
||||
monitorType = lib.types.submodule {
|
||||
options = {
|
||||
name = lib.mkOption {
|
||||
type = lib.types.str;
|
||||
example = "HDMI-A-1";
|
||||
description = "Output name (see `hyprctl monitors`), or a `desc:<…>` match.";
|
||||
};
|
||||
resolution = lib.mkOption {
|
||||
type = lib.types.str;
|
||||
default = "preferred";
|
||||
description = "`preferred` | `highres` | `highrr` | `<w>x<h>@<hz>` | `disable`.";
|
||||
};
|
||||
position = lib.mkOption {
|
||||
type = lib.types.str;
|
||||
default = "auto";
|
||||
description = "`auto` | `auto-right`/`auto-left`/… | `<x>x<y>`.";
|
||||
};
|
||||
scale = lib.mkOption {
|
||||
type = lib.types.oneOf [ lib.types.str lib.types.int lib.types.float ];
|
||||
default = 1;
|
||||
description = "Scale factor (1, 1.5, …) or `auto`.";
|
||||
};
|
||||
transform = lib.mkOption {
|
||||
type = lib.types.nullOr lib.types.int;
|
||||
default = null;
|
||||
description = "Rotation 0–7 (90°/180°/270° = 1/2/3).";
|
||||
};
|
||||
mirror = lib.mkOption {
|
||||
type = lib.types.nullOr lib.types.str;
|
||||
default = null;
|
||||
description = "Mirror another output by name.";
|
||||
};
|
||||
bitdepth = lib.mkOption {
|
||||
type = lib.types.nullOr lib.types.int;
|
||||
default = null;
|
||||
description = "Colour bit depth (8 or 10).";
|
||||
};
|
||||
vrr = lib.mkOption {
|
||||
type = lib.types.nullOr lib.types.int;
|
||||
default = null;
|
||||
description = "Variable refresh: 0 off, 1 on, 2 fullscreen-only.";
|
||||
};
|
||||
extra = lib.mkOption {
|
||||
type = lib.types.str;
|
||||
default = "";
|
||||
description = "Extra comma-separated Hyprland monitor args, appended verbatim.";
|
||||
};
|
||||
};
|
||||
};
|
||||
in
|
||||
{
|
||||
options.nomarchy = {
|
||||
# ── Required ───────────────────────────────────────────────────
|
||||
@@ -42,6 +96,49 @@
|
||||
description = "XKB variant for the Hyprland session.";
|
||||
};
|
||||
|
||||
keyboard.layouts = lib.mkOption {
|
||||
type = lib.types.listOf lib.types.str;
|
||||
default = [ ];
|
||||
example = [ "de" "fr" ];
|
||||
description = ''
|
||||
Extra candidate layouts offered by the interactive new-keyboard
|
||||
picker. When non-empty, a small watcher runs in the session: when a
|
||||
keyboard connects that isn't covered by nomarchy.keyboard.devices and
|
||||
hasn't been chosen before, it pops a rofi picker (these layouts plus
|
||||
the primary nomarchy.keyboard.layout), applies the choice, and
|
||||
remembers it per-device (~/.local/state) — re-applying automatically
|
||||
on later reconnects. The runtime-remember complement to the
|
||||
declarative keyboard.devices; a stateful runtime piece by design.
|
||||
'';
|
||||
};
|
||||
|
||||
keyboard.devices = lib.mkOption {
|
||||
type = lib.types.attrsOf (lib.types.submodule {
|
||||
options = {
|
||||
layout = lib.mkOption {
|
||||
type = lib.types.str;
|
||||
description = "XKB layout for this specific keyboard.";
|
||||
};
|
||||
variant = lib.mkOption {
|
||||
type = lib.types.str;
|
||||
default = "";
|
||||
description = "XKB variant for this keyboard.";
|
||||
};
|
||||
};
|
||||
});
|
||||
default = { };
|
||||
example = lib.literalExpression ''{ "keychron-keychron-k2" = { layout = "de"; }; }'';
|
||||
description = ''
|
||||
Per-device keyboard layout. The key is the device name from
|
||||
`hyprctl devices` (lower-case, hyphenated). Each entry generates a
|
||||
Hyprland `device` block that overrides the session-wide
|
||||
nomarchy.keyboard.layout for that keyboard only — e.g. an external
|
||||
keyboard that's physically a different layout than the laptop's
|
||||
built-in one. Hyprland applies it automatically whenever that
|
||||
keyboard is connected.
|
||||
'';
|
||||
};
|
||||
|
||||
package = lib.mkOption {
|
||||
type = lib.types.package;
|
||||
default = pkgs.nomarchy-theme-sync;
|
||||
@@ -60,6 +157,54 @@
|
||||
'';
|
||||
};
|
||||
|
||||
nightlight = {
|
||||
enable = lib.mkEnableOption ''
|
||||
a scheduled blue-light filter (hyprsunset): warm at night, no shift
|
||||
by day. Opt-in; tune the temperature + sunrise/sunset below'';
|
||||
|
||||
temperature = lib.mkOption {
|
||||
type = lib.types.int;
|
||||
default = 4000;
|
||||
example = 3500;
|
||||
description = "Warm colour temperature (K) applied at night — lower is warmer.";
|
||||
};
|
||||
|
||||
sunrise = lib.mkOption {
|
||||
type = lib.types.str;
|
||||
default = "07:00";
|
||||
example = "06:30";
|
||||
description = "Time (HH:MM) the filter turns OFF — daytime, no colour shift.";
|
||||
};
|
||||
|
||||
sunset = lib.mkOption {
|
||||
type = lib.types.str;
|
||||
default = "20:00";
|
||||
example = "21:00";
|
||||
description = "Time (HH:MM) the filter turns ON — warm.";
|
||||
};
|
||||
};
|
||||
|
||||
monitors = lib.mkOption {
|
||||
type = lib.types.listOf monitorType;
|
||||
default = [ ];
|
||||
example = lib.literalExpression ''
|
||||
[
|
||||
{ name = "eDP-1"; position = "0x0"; }
|
||||
{ name = "HDMI-A-1"; position = "auto-right"; scale = 1; }
|
||||
]
|
||||
'';
|
||||
description = ''
|
||||
Declarative per-output monitor layout. Each entry becomes a Hyprland
|
||||
`monitor` rule; Hyprland applies them on hotplug, so a declared
|
||||
external/dock output arranges itself when connected. The built-in
|
||||
`,preferred,auto,1` wildcard stays as the fallback for any output you
|
||||
don't list. For raw control set
|
||||
`wayland.windowManager.hyprland.settings.monitor` directly instead
|
||||
(it replaces this). Run `nwg-displays` (nomarchy.displays.enable) to
|
||||
find the right values interactively.
|
||||
'';
|
||||
};
|
||||
|
||||
# ── Component toggles ──────────────────────────────────────────
|
||||
hyprland.enable = lib.mkEnableOption "Nomarchy's Hyprland configuration" // { default = true; };
|
||||
waybar.enable = lib.mkEnableOption "Nomarchy's Waybar configuration" // { default = true; };
|
||||
@@ -74,6 +219,7 @@
|
||||
ghostty.enable = lib.mkEnableOption "Nomarchy's Ghostty configuration" // { default = true; };
|
||||
btop.enable = lib.mkEnableOption "btop with the per-theme nomarchy theme" // { default = true; };
|
||||
stylix.enable = lib.mkEnableOption "Stylix theming for the long tail of apps (GTK, Qt, cursors)" // { default = true; };
|
||||
displays.enable = lib.mkEnableOption "the nwg-displays interactive monitor arranger (a helper to find nomarchy.monitors values; the declarative config stays the source of truth)" // { default = true; };
|
||||
|
||||
# ── Computed (read-only) ───────────────────────────────────────
|
||||
theme = lib.mkOption {
|
||||
|
||||
@@ -41,9 +41,9 @@ let
|
||||
nomarchy-menu = pkgs.writeShellScriptBin "nomarchy-menu" ''
|
||||
# Nomarchy menu dispatcher — thin presentation layer over
|
||||
# `rofi -dmenu`; actions delegate to nomarchy-theme-sync, systemctl,
|
||||
# hyprctl and friends. Icons are nf-md glyphs (Pango falls back to a
|
||||
# Nerd Font for them). `nomarchy-menu` with no argument shows the
|
||||
# module picker.
|
||||
# hyprctl and friends. Menu entries carry real icons from the theme's
|
||||
# icon set (Papirus) via rofi's per-row icon protocol — see row() below.
|
||||
# `nomarchy-menu` with no argument shows the module picker.
|
||||
|
||||
urlencode() {
|
||||
local s="$1" out="" ch i
|
||||
@@ -58,16 +58,22 @@ let
|
||||
printf '%s' "$out"
|
||||
}
|
||||
|
||||
# Emit one dmenu row with a themed icon: `row "Label" icon-name`. The NUL
|
||||
# + 0x1f field separator is rofi's per-row icon protocol; printed straight
|
||||
# to the pipe because bash can't store NUL in a variable. Rendered when
|
||||
# rofi has show-icons (on globally; passed explicitly on the icon menus).
|
||||
row() { printf '%s\0icon\x1f%s\n' "$1" "$2"; }
|
||||
|
||||
case "''${1:-}" in
|
||||
power)
|
||||
choice=$(printf '%s\n' \
|
||||
" Lock" \
|
||||
" Logout" \
|
||||
" Suspend" \
|
||||
" Hibernate" \
|
||||
" Reboot" \
|
||||
" Shutdown" \
|
||||
| rofi -dmenu -p power) || exit 0
|
||||
choice=$( {
|
||||
row "Lock" system-lock-screen
|
||||
row "Logout" system-log-out
|
||||
row "Suspend" system-suspend
|
||||
row "Hibernate" system-hibernate
|
||||
row "Reboot" system-reboot
|
||||
row "Shutdown" system-shutdown
|
||||
} | rofi -dmenu -show-icons -p Power) || exit 0
|
||||
case "$choice" in
|
||||
*Lock) loginctl lock-session ;;
|
||||
*Logout) hyprctl dispatch exit ;;
|
||||
@@ -134,12 +140,12 @@ let
|
||||
exec blueman-manager ;;
|
||||
|
||||
capture)
|
||||
choice=$(printf '%s\n' \
|
||||
" Region → clipboard" \
|
||||
" Region → file" \
|
||||
" Full screen → clipboard" \
|
||||
" Full screen → file" \
|
||||
| rofi -dmenu -p capture) || exit 0
|
||||
choice=$( {
|
||||
row "Region → clipboard" applets-screenshooter
|
||||
row "Region → file" applets-screenshooter
|
||||
row "Full screen → clipboard" camera-photo
|
||||
row "Full screen → file" camera-photo
|
||||
} | rofi -dmenu -show-icons -p Capture) || exit 0
|
||||
dir="$HOME/Pictures/Screenshots"
|
||||
file="$dir/$(date +%Y%m%d-%H%M%S).png"
|
||||
case "$choice" in
|
||||
@@ -164,49 +170,93 @@ let
|
||||
[ -n "$q" ] || exit 0
|
||||
exec ${cfg.terminal} -e npx --yes @anthropic-ai/claude-code@latest "$q" ;;
|
||||
|
||||
"")
|
||||
entries=(
|
||||
" Apps"
|
||||
" Theme"
|
||||
" Clipboard"
|
||||
" Calculator"
|
||||
" Files"
|
||||
" Emoji"
|
||||
" Web search"
|
||||
" Network"
|
||||
" Bluetooth"
|
||||
" Capture"
|
||||
" Keybindings"
|
||||
" Ask Claude"
|
||||
)
|
||||
# Power-profile picker only when this is a laptop (battery present)
|
||||
# running power-profiles-daemon — matches the Waybar indicator's
|
||||
# self-gating; desktops and the TLP backend don't show it.
|
||||
bats=(/sys/class/power_supply/BAT*)
|
||||
if [ -e "''${bats[0]}" ] && command -v powerprofilesctl >/dev/null 2>&1; then
|
||||
entries+=(" Power profile")
|
||||
fi
|
||||
entries+=(" Power")
|
||||
choice=$(printf '%s\n' "''${entries[@]}" | rofi -dmenu -p menu) || exit 0
|
||||
dnd)
|
||||
# Toggle swaync Do-Not-Disturb (-d prints the new state). With DND
|
||||
# on, notifications are suppressed — the Waybar bell-off icon is the
|
||||
# cue — so only confirm with a toast when turning it back off.
|
||||
[ "$(swaync-client -d)" = "false" ] \
|
||||
&& notify-send "Do Not Disturb off" "Notifications resumed."
|
||||
exit 0 ;;
|
||||
|
||||
snapshot)
|
||||
# btrfs-assistant: snapshot browse / diff / restore / rollback over
|
||||
# snapper, elevating via polkit. Shipped system-side with
|
||||
# nomarchy.system.snapper; self-gate so the entry no-ops elsewhere.
|
||||
command -v btrfs-assistant >/dev/null 2>&1 \
|
||||
|| { notify-send "Snapshots" "btrfs-assistant isn't installed (BTRFS snapshots off?)."; exit 0; }
|
||||
exec btrfs-assistant ;;
|
||||
|
||||
tools)
|
||||
# Tools submenu — utilities you invoke. Each leaf is also reachable
|
||||
# directly (SUPER+CTRL+<mnemonic>); this just keeps the root short.
|
||||
choice=$( {
|
||||
row "Calculator" accessories-calculator
|
||||
row "Clipboard" edit-paste
|
||||
row "Emoji" face-smile-big
|
||||
row "Files" system-file-manager
|
||||
row "Web search" system-search
|
||||
row "Capture" applets-screenshooter
|
||||
row "Ask Claude" internet-chat
|
||||
row "Back" go-previous
|
||||
} | rofi -dmenu -show-icons -p Tools) || exit 0
|
||||
case "$choice" in
|
||||
*Apps*) exec rofi -show drun ;;
|
||||
*Theme*) exec "$0" theme ;;
|
||||
*Clipboard*) exec "$0" clipboard ;;
|
||||
*Calc*) exec "$0" calc ;;
|
||||
*Files*) exec "$0" files ;;
|
||||
*Clipboard*) exec "$0" clipboard ;;
|
||||
*Emoji*) exec "$0" emoji ;;
|
||||
*Files*) exec "$0" files ;;
|
||||
*Web*) exec "$0" web ;;
|
||||
*Network*) exec "$0" network ;;
|
||||
*Bluetooth*) exec "$0" bluetooth ;;
|
||||
*Capture*) exec "$0" capture ;;
|
||||
*Keybindings*) exec "$0" keybinds ;;
|
||||
*Ask*) exec "$0" ask ;;
|
||||
*"Power profile"*) exec "$0" power-profile ;;
|
||||
*Power*) exec "$0" power ;;
|
||||
*Back*) exec "$0" ;;
|
||||
esac ;;
|
||||
|
||||
system)
|
||||
# System submenu — connectivity and machine state. Snapshots and the
|
||||
# power-profile picker self-gate (BTRFS+snapper / laptop on ppd), so
|
||||
# the submenu shrinks to match the hardware, like the Waybar modules.
|
||||
bats=(/sys/class/power_supply/BAT*)
|
||||
choice=$( {
|
||||
row "Network" network-wireless
|
||||
row "Bluetooth" bluetooth
|
||||
row "Do Not Disturb" notification-disabled
|
||||
command -v btrfs-assistant >/dev/null 2>&1 && row "Snapshots" timeshift
|
||||
if [ -e "''${bats[0]}" ] && command -v powerprofilesctl >/dev/null 2>&1; then
|
||||
row "Power profile" preferences-system-power
|
||||
fi
|
||||
row "Back" go-previous
|
||||
} | rofi -dmenu -show-icons -p System) || exit 0
|
||||
case "$choice" in
|
||||
*Network*) exec "$0" network ;;
|
||||
*Bluetooth*) exec "$0" bluetooth ;;
|
||||
*"Do Not Disturb"*) exec "$0" dnd ;;
|
||||
*Snapshots*) exec "$0" snapshot ;;
|
||||
*"Power profile"*) exec "$0" power-profile ;;
|
||||
*Back*) exec "$0" ;;
|
||||
esac ;;
|
||||
|
||||
"")
|
||||
# Root picker — grouped into category submenus so the top level stays
|
||||
# short and scannable. Apps/Theme/Power/Keybindings are frequent enough
|
||||
# to keep at the top; everything else lives under Tools or System.
|
||||
choice=$( {
|
||||
row "Apps" applications-all
|
||||
row "Theme" preferences-desktop-theme
|
||||
row "Tools" applications-utilities
|
||||
row "System" preferences-system
|
||||
row "Power" system-shutdown
|
||||
row "Keybindings" preferences-desktop-keyboard
|
||||
} | rofi -dmenu -show-icons -p Menu) || exit 0
|
||||
case "$choice" in
|
||||
*Apps*) exec rofi -show drun ;;
|
||||
*Theme*) exec "$0" theme ;;
|
||||
*Tools*) exec "$0" tools ;;
|
||||
*System*) exec "$0" system ;;
|
||||
*Power*) exec "$0" power ;;
|
||||
*Keybindings*) exec "$0" keybinds ;;
|
||||
esac ;;
|
||||
|
||||
*)
|
||||
echo "usage: nomarchy-menu [power|power-profile|theme|clipboard|calc|files|emoji|web|network|bluetooth|capture|keybinds|ask]" >&2
|
||||
echo "usage: nomarchy-menu [tools|system|power|power-profile|theme|clipboard|calc|files|emoji|web|network|bluetooth|capture|keybinds|ask|dnd|snapshot]" >&2
|
||||
exit 64 ;;
|
||||
esac
|
||||
'';
|
||||
@@ -238,6 +288,10 @@ in
|
||||
drun-display-format = "{name}";
|
||||
display-drun = "apps";
|
||||
display-run = "run";
|
||||
# Size the window to the actual number of rows instead of always
|
||||
# reserving `lines` (8) — so a 6-entry menu doesn't leave empty space,
|
||||
# while the app launcher still fills + scrolls past `lines`.
|
||||
fixed-num-lines = false;
|
||||
};
|
||||
|
||||
# Whole-swap themes bring their own rofi.rasi; otherwise the theme
|
||||
@@ -290,22 +344,34 @@ in
|
||||
columns = 1;
|
||||
dynamic = true;
|
||||
scrollbar = false;
|
||||
spacing = px 2;
|
||||
spacing = px 4; # a little air so the rounded zebra rows separate
|
||||
padding = mkLiteral "8px 0px 0px 0px";
|
||||
};
|
||||
|
||||
# Rounded, roomy rows with subtle zebra striping: alternate rows
|
||||
# lift to @surface, the selected row to @accent. normal/alternate/
|
||||
# selected are rofi's row parities (the `.normal` suffix is the
|
||||
# match-state, untouched by our menus).
|
||||
"element" = {
|
||||
padding = mkLiteral "8px 12px";
|
||||
padding = mkLiteral "10px 14px";
|
||||
border-radius = px t.ui.rounding;
|
||||
spacing = px 8;
|
||||
spacing = px 12; # gap between the (larger) icon and the label
|
||||
};
|
||||
"element selected" = {
|
||||
"element normal.normal" = {
|
||||
background-color = mkLiteral "@bg";
|
||||
text-color = mkLiteral "@fg";
|
||||
};
|
||||
"element alternate.normal" = {
|
||||
background-color = mkLiteral "@surface";
|
||||
text-color = mkLiteral "@fg";
|
||||
};
|
||||
"element selected.normal" = {
|
||||
background-color = mkLiteral "@accent";
|
||||
text-color = mkLiteral "@bg";
|
||||
};
|
||||
"element-icon" = {
|
||||
background-color = mkLiteral "transparent";
|
||||
size = mkLiteral "1em";
|
||||
size = px t.ui.iconSize; # real icons (Papirus), not 1em font glyphs
|
||||
};
|
||||
"element-text" = {
|
||||
background-color = mkLiteral "transparent";
|
||||
|
||||
@@ -35,6 +35,9 @@ in
|
||||
ignoreSpace = true;
|
||||
expireDuplicatesFirst = true;
|
||||
};
|
||||
# Curated, on by default. The rule (same as rg/fd above): short where
|
||||
# it helps, but never shadow a real binary — so the git block keeps off
|
||||
# `gs` (ghostscript), and nothing here masks a coreutil.
|
||||
shellAliases = {
|
||||
cat = "bat --paging=never";
|
||||
less = "bat";
|
||||
@@ -42,8 +45,42 @@ in
|
||||
# eza enableZshIntegration aliases ls/ll/la; add a couple extras.
|
||||
lt = "eza --tree --level=2 --icons=auto --group-directories-first";
|
||||
tree = "eza --tree --icons=auto --group-directories-first";
|
||||
|
||||
# Navigation — climb without counting dots.
|
||||
".." = "cd ..";
|
||||
"..." = "cd ../..";
|
||||
"...." = "cd ../../..";
|
||||
|
||||
# Git — the verbs you retype all day.
|
||||
g = "git";
|
||||
gst = "git status -sb";
|
||||
ga = "git add";
|
||||
gaa = "git add -A";
|
||||
gc = "git commit";
|
||||
gcm = "git commit -m";
|
||||
gco = "git checkout";
|
||||
gsw = "git switch";
|
||||
gb = "git branch";
|
||||
gd = "git diff";
|
||||
gds = "git diff --staged";
|
||||
gl = "git log --oneline --graph --decorate -20";
|
||||
glg = "git log --oneline --graph --decorate --all";
|
||||
gp = "git push";
|
||||
gpl = "git pull";
|
||||
gf = "git fetch --all --prune";
|
||||
|
||||
# Nix — the flake/store verbs (system/home rebuilds already have the
|
||||
# sys-update / home-update commands, so they're not re-aliased here).
|
||||
ns = "nix shell"; # ns nixpkgs#ripgrep
|
||||
nr = "nix run"; # nr nixpkgs#cowsay
|
||||
nfu = "nix flake update";
|
||||
nfc = "nix flake check";
|
||||
nsearch = "nix search nixpkgs";
|
||||
ngc = "nix-collect-garbage -d"; # user generations; sudo for system roots
|
||||
|
||||
# Misc.
|
||||
path = "echo $PATH | tr ':' '\\n'";
|
||||
reload = "exec zsh";
|
||||
};
|
||||
};
|
||||
|
||||
|
||||
@@ -38,6 +38,7 @@ let
|
||||
gapsOut = 12;
|
||||
borderSize = 2;
|
||||
rounding = 10;
|
||||
iconSize = 36; # rofi launcher + menu icon size (px) for the generated theme
|
||||
activeOpacity = 1.0;
|
||||
inactiveOpacity = 0.95;
|
||||
terminalOpacity = 0.96;
|
||||
|
||||
@@ -12,12 +12,23 @@
|
||||
let
|
||||
t = config.nomarchy.theme;
|
||||
|
||||
# Show the active-keyboard-layout indicator only when more than one layout
|
||||
# is in play — multiple session layouts (comma-separated) or per-device
|
||||
# overrides (nomarchy.keyboard.devices) — so single-layout bars stay clean.
|
||||
showLanguage = lib.hasInfix "," config.nomarchy.keyboard.layout
|
||||
|| config.nomarchy.keyboard.layouts != [ ]
|
||||
|| config.nomarchy.keyboard.devices != { };
|
||||
|
||||
# Power-profile indicator (power-profiles-daemon). Both scripts self-
|
||||
# gate: they exit silently unless this is a laptop (a battery is
|
||||
# present) running PPD, so the module hides itself on desktops and
|
||||
# under the TLP backend — no system→home coupling. Speedometer glyphs
|
||||
# (slow/medium/fast) map to power-saver/balanced/performance.
|
||||
powerProfileStatus = pkgs.writeShellScript "nomarchy-powerprofile-status" ''
|
||||
#
|
||||
# Named writeShellScriptBins (put on PATH via home.packages below) rather
|
||||
# than bare writeShellScript store paths, so the whole-swap themes' static
|
||||
# waybar.jsonc can exec them by name too — same as the swaync bell.
|
||||
powerProfileStatus = pkgs.writeShellScriptBin "nomarchy-powerprofile-status" ''
|
||||
case "$(ls /sys/class/power_supply/ 2>/dev/null)" in *BAT*) ;; *) exit 0 ;; esac
|
||||
command -v powerprofilesctl >/dev/null 2>&1 || exit 0
|
||||
prof=$(powerprofilesctl get 2>/dev/null) || exit 0
|
||||
@@ -29,7 +40,7 @@ let
|
||||
printf '{"text":"%s","tooltip":"Power profile: %s","class":"%s"}\n' "$icon" "$prof" "$prof"
|
||||
'';
|
||||
# Cycle to the next profile this machine actually offers (wraps around).
|
||||
powerProfileCycle = pkgs.writeShellScript "nomarchy-powerprofile-cycle" ''
|
||||
powerProfileCycle = pkgs.writeShellScriptBin "nomarchy-powerprofile-cycle" ''
|
||||
command -v powerprofilesctl >/dev/null 2>&1 || exit 0
|
||||
cur=$(powerprofilesctl get 2>/dev/null) || exit 0
|
||||
avail=$(powerprofilesctl list 2>/dev/null | sed -nE 's/^[* ] ([a-z-]+):$/\1/p')
|
||||
@@ -66,7 +77,9 @@ let
|
||||
|
||||
modules-left = [ "hyprland/workspaces" "hyprland/window" ];
|
||||
modules-center = [ "clock" ];
|
||||
modules-right = [ "tray" "pulseaudio" "network" "cpu" "memory" "custom/powerprofile" "battery" ];
|
||||
modules-right = [ "tray" "pulseaudio" "network" "cpu" "memory" "custom/powerprofile" ]
|
||||
++ lib.optional showLanguage "hyprland/language"
|
||||
++ [ "battery" "custom/notification" ];
|
||||
|
||||
"hyprland/workspaces" = {
|
||||
format = "{icon}";
|
||||
@@ -84,6 +97,13 @@ let
|
||||
tooltip-format = "<tt><small>{calendar}</small></tt>";
|
||||
};
|
||||
|
||||
# Active keyboard layout (per focused device) — only placed in
|
||||
# modules-right when showLanguage (see above).
|
||||
"hyprland/language" = {
|
||||
format = " {short}";
|
||||
tooltip = false;
|
||||
};
|
||||
|
||||
pulseaudio = {
|
||||
format = "{icon} {volume}%";
|
||||
format-muted = "";
|
||||
@@ -112,10 +132,35 @@ let
|
||||
};
|
||||
|
||||
"custom/powerprofile" = {
|
||||
exec = "${powerProfileStatus}";
|
||||
exec = "nomarchy-powerprofile-status";
|
||||
return-type = "json";
|
||||
interval = 5;
|
||||
on-click = "${powerProfileCycle}";
|
||||
on-click = "nomarchy-powerprofile-cycle";
|
||||
};
|
||||
|
||||
# swaync notification bell + Do-Not-Disturb state. `-swb` streams JSON
|
||||
# (text/tooltip/class) on every change, so it tracks count and DND with
|
||||
# no polling. Left-click toggles the panel; right-click toggles DND.
|
||||
# The `dnd-*` classes (bell-off glyph) are styled muted below.
|
||||
"custom/notification" = {
|
||||
exec = "swaync-client -swb";
|
||||
return-type = "json";
|
||||
exec-if = "which swaync-client";
|
||||
format = "{icon}";
|
||||
format-icons = {
|
||||
none = "";
|
||||
notification = "";
|
||||
dnd-none = "";
|
||||
dnd-notification = "";
|
||||
inhibited-none = "";
|
||||
inhibited-notification = "";
|
||||
dnd-inhibited-none = "";
|
||||
dnd-inhibited-notification = "";
|
||||
};
|
||||
on-click = "swaync-client -t -sw";
|
||||
on-click-right = "swaync-client -d -sw";
|
||||
tooltip = true;
|
||||
escape = true;
|
||||
};
|
||||
|
||||
tray.spacing = 8;
|
||||
@@ -164,11 +209,16 @@ let
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
#tray, #pulseaudio, #network, #cpu, #memory, #custom-powerprofile, #battery {
|
||||
#tray, #pulseaudio, #network, #cpu, #memory, #custom-powerprofile, #language, #battery, #custom-notification {
|
||||
color: @subtext;
|
||||
padding: 0 10px;
|
||||
}
|
||||
|
||||
/* notifications waiting → accent; Do-Not-Disturb → muted bell-off */
|
||||
#custom-notification.notification { color: @accent; }
|
||||
#custom-notification.dnd-none,
|
||||
#custom-notification.dnd-notification { color: @muted; }
|
||||
|
||||
#pulseaudio.muted { color: @muted; }
|
||||
#battery.warning { color: @warn; }
|
||||
#battery.critical { color: @bad; }
|
||||
@@ -197,4 +247,9 @@ in
|
||||
else generatedStyle
|
||||
);
|
||||
};
|
||||
|
||||
# The power-profile helpers on PATH, so both the generated bar and the
|
||||
# whole-swap themes' static waybar.jsonc can exec them by name.
|
||||
home.packages = lib.optionals config.nomarchy.waybar.enable
|
||||
[ powerProfileStatus powerProfileCycle ];
|
||||
}
|
||||
|
||||
@@ -22,7 +22,7 @@ let
|
||||
'';
|
||||
in
|
||||
{
|
||||
imports = [ ./options.nix ./plymouth.nix ./file-manager.nix ./power.nix ];
|
||||
imports = [ ./options.nix ./plymouth.nix ./file-manager.nix ./power.nix ./services.nix ];
|
||||
|
||||
config = {
|
||||
# The safe half of distro branding: distroName flows into
|
||||
@@ -123,23 +123,32 @@ in
|
||||
|
||||
networking.networkmanager.enable = lib.mkDefault true;
|
||||
|
||||
# No double-unlock on hibernate. hypridle locks hyprlock before every
|
||||
# sleep (right for suspend), but a hibernate resume is already gated by
|
||||
# the LUKS passphrase entered at boot — so the user would type a password
|
||||
# twice. Once we're back from an *encrypted* hibernate, drop the now-
|
||||
# redundant hyprlock. Ordered After the hibernate service, so it runs
|
||||
# post-resume; pulled in only by hibernate.target (suspend, and the
|
||||
# RAM-resume phase of suspend-then-hibernate, stay locked — they have no
|
||||
# passphrase gate). Gated on LUKS: an unencrypted hibernate keeps its lock.
|
||||
systemd.services.nomarchy-hibernate-unlock =
|
||||
lib.mkIf (builtins.attrNames config.boot.initrd.luks.devices != [ ]) {
|
||||
description = "Dismiss hyprlock after resuming from an encrypted hibernate";
|
||||
after = [ "systemd-hibernate.service" ];
|
||||
wantedBy = [ "hibernate.target" ];
|
||||
# No double-unlock on hibernate. Locking the session before sleep is
|
||||
# right for suspend (resumes from RAM, no other gate), but an encrypted
|
||||
# hibernate already resumes through the LUKS passphrase — a hyprlock on
|
||||
# top is a second password. And we can't just drop the lock after the
|
||||
# resume: a Wayland session-lock whose client dies without releasing
|
||||
# trips hyprlock's "go to a tty" crash failsafe (the compositor keeps the
|
||||
# screen locked for safety). So don't lock before an encrypted hibernate
|
||||
# in the first place. hypridle can't tell suspend from hibernate, hence a
|
||||
# system unit hooked to the sleep targets: it locks on the RAM-resume
|
||||
# sleeps always, and on hibernate only when the disk is unencrypted (no
|
||||
# LUKS gate to rely on). Replaces hypridle's old before_sleep_cmd.
|
||||
systemd.services.nomarchy-lock-before-sleep =
|
||||
let
|
||||
encrypted = builtins.attrNames config.boot.initrd.luks.devices != [ ];
|
||||
# Sleeps whose normal resume is from RAM — always lock these.
|
||||
ramTargets = [ "suspend.target" "hybrid-sleep.target" "suspend-then-hibernate.target" ];
|
||||
ramServices = [ "systemd-suspend.service" "systemd-hybrid-sleep.service" "systemd-suspend-then-hibernate.service" ];
|
||||
in
|
||||
{
|
||||
description = "Lock the session before sleep (skipped for an encrypted hibernate)";
|
||||
before = ramServices ++ lib.optional (!encrypted) "systemd-hibernate.service";
|
||||
wantedBy = ramTargets ++ lib.optional (!encrypted) "hibernate.target";
|
||||
serviceConfig = {
|
||||
Type = "oneshot";
|
||||
# `-`: a missing hyprlock (idle disabled, or not locked) isn't a failure.
|
||||
ExecStart = "-${pkgs.procps}/bin/pkill -x hyprlock";
|
||||
# Plural: a system unit has no session of its own to lock.
|
||||
ExecStart = "${config.systemd.package}/bin/loginctl lock-sessions";
|
||||
};
|
||||
};
|
||||
|
||||
@@ -176,7 +185,7 @@ in
|
||||
# is a clean no-op rather than a failing timer.
|
||||
services.snapper.configs = lib.mkIf
|
||||
(cfg.snapper.enable && (config.fileSystems."/".fsType or "") == "btrfs")
|
||||
{
|
||||
({
|
||||
root = {
|
||||
SUBVOLUME = "/";
|
||||
TIMELINE_CREATE = true;
|
||||
@@ -187,6 +196,39 @@ in
|
||||
TIMELINE_LIMIT_MONTHLY = "0";
|
||||
TIMELINE_LIMIT_YEARLY = "0";
|
||||
};
|
||||
}
|
||||
# /home is user data — snapshot it too when it's its own BTRFS subvolume
|
||||
# (the installer's @home). Keep the recent hourlies for oops-recovery
|
||||
# plus dailies, and a month of weeklies; "at least daily" by default.
|
||||
// lib.optionalAttrs ((config.fileSystems."/home".fsType or "") == "btrfs") {
|
||||
home = {
|
||||
SUBVOLUME = "/home";
|
||||
TIMELINE_CREATE = true;
|
||||
TIMELINE_CLEANUP = true;
|
||||
TIMELINE_LIMIT_HOURLY = "5";
|
||||
TIMELINE_LIMIT_DAILY = "7";
|
||||
TIMELINE_LIMIT_WEEKLY = "4";
|
||||
TIMELINE_LIMIT_MONTHLY = "0";
|
||||
TIMELINE_LIMIT_YEARLY = "0";
|
||||
};
|
||||
});
|
||||
|
||||
# snapper needs a `.snapshots` subvolume inside each tracked subvolume.
|
||||
# The installer made one for / (@snapshots → /.snapshots) but not /home,
|
||||
# so create a nested one there if missing (idempotent via the condition;
|
||||
# excluded from /home snapshots since BTRFS snapshots are non-recursive).
|
||||
# Runs at boot so it also fixes already-installed machines — no disko
|
||||
# change needed.
|
||||
systemd.services.nomarchy-home-snapshots-subvol = lib.mkIf
|
||||
(cfg.snapper.enable && (config.fileSystems."/home".fsType or "") == "btrfs") {
|
||||
description = "Create /home/.snapshots for snapper if missing";
|
||||
wantedBy = [ "multi-user.target" ];
|
||||
before = [ "snapper-timeline.service" "snapper-cleanup.service" ];
|
||||
unitConfig.ConditionPathExists = "!/home/.snapshots";
|
||||
serviceConfig = {
|
||||
Type = "oneshot";
|
||||
ExecStart = "${pkgs.btrfs-progs}/bin/btrfs subvolume create /home/.snapshots";
|
||||
};
|
||||
};
|
||||
|
||||
# ── Fonts ────────────────────────────────────────────────────────
|
||||
@@ -276,7 +318,10 @@ in
|
||||
--cleanup-algorithm number
|
||||
echo "Rebuilding..."
|
||||
nixos-rebuild switch --flake /etc/nixos#default "$@"
|
||||
'');
|
||||
'')
|
||||
# The desktop snapshot manager (browse / diff / restore / rollback over
|
||||
# snapper, elevating via polkit) — what `nomarchy-menu snapshot` launches.
|
||||
++ lib.optional cfg.snapper.enable pkgs.btrfs-assistant;
|
||||
|
||||
# Don't let boot entries fill the ESP over the years.
|
||||
boot.loader.systemd-boot.configurationLimit = lib.mkDefault 10;
|
||||
@@ -291,6 +336,11 @@ in
|
||||
settings = {
|
||||
experimental-features = [ "nix-command" "flakes" ];
|
||||
auto-optimise-store = lib.mkDefault true;
|
||||
# The downstream flake (~/.nomarchy) is meant to be a live working
|
||||
# tree: nomarchy-theme-sync rewrites theme-state.json on every
|
||||
# switch (and you needn't commit each tweak), so the "Git tree is
|
||||
# dirty" warning fires on every rebuild and is pure noise here.
|
||||
warn-dirty = lib.mkDefault false;
|
||||
};
|
||||
gc = {
|
||||
automatic = lib.mkDefault true;
|
||||
|
||||
280
modules/nixos/services.nix
Normal file
280
modules/nixos/services.nix
Normal file
@@ -0,0 +1,280 @@
|
||||
# Opt-in services & integrations — off by default, one toggle each, enabled
|
||||
# in system.nix (see the commented examples in the downstream template).
|
||||
# These are system-side: their own `nomarchy.services.*` namespace, distinct
|
||||
# from the distro's core `nomarchy.system.*` toggles. `username` (from
|
||||
# specialArgs) is read lazily, only where a service needs it.
|
||||
{ config, lib, pkgs, ... }@args:
|
||||
|
||||
let
|
||||
cfg = config.nomarchy.services;
|
||||
in
|
||||
{
|
||||
options.nomarchy.services = {
|
||||
tailscale.enable = lib.mkEnableOption ''
|
||||
Tailscale, the mesh VPN — ships the daemon; authenticate once with
|
||||
`sudo tailscale up`'';
|
||||
|
||||
syncthing.enable = lib.mkEnableOption ''
|
||||
Syncthing continuous file sync, running as the login user — add
|
||||
folders and devices in the web UI at http://127.0.0.1:8384'';
|
||||
|
||||
podman.enable = lib.mkEnableOption ''
|
||||
Podman for rootless containers, with `docker` aliased to it and DNS on
|
||||
the default network; the login user gets a subuid/subgid range'';
|
||||
|
||||
flatpak.enable = lib.mkEnableOption ''
|
||||
Flatpak, with the Flathub remote added system-wide — install apps with
|
||||
`flatpak install flathub <app>`'';
|
||||
|
||||
pika.enable = lib.mkEnableOption ''
|
||||
Pika Backup, a friendly GUI for scheduled Borg backups (the app;
|
||||
configure repositories and schedules inside it)'';
|
||||
|
||||
steam.enable = lib.mkEnableOption ''
|
||||
Steam (Valve's game store/launcher) via programs.steam — which wires up
|
||||
the 32-bit graphics libraries, controller udev rules and Remote-Play
|
||||
firewall ports a bare package can't. Unfree'';
|
||||
|
||||
libvirt.enable = lib.mkEnableOption ''
|
||||
libvirt/KVM virtualisation with the virt-manager GUI — runs the
|
||||
libvirtd daemon and adds the login user to the `libvirtd` group, so VMs
|
||||
can be managed without root'';
|
||||
|
||||
obs.enable = lib.mkEnableOption ''
|
||||
OBS Studio for screen recording and streaming, plus a v4l2loopback
|
||||
virtual camera — so an OBS scene can be selected as a webcam in Zoom,
|
||||
Teams or a browser (screen capture itself already works over the
|
||||
desktop's PipeWire portal)'';
|
||||
|
||||
docker.enable = lib.mkEnableOption ''
|
||||
Docker (rootful) with the login user in the `docker` group. Mutually
|
||||
exclusive with the podman toggle's docker-compat (both provide the
|
||||
`docker` command) — enable only one'';
|
||||
|
||||
kdeconnect.enable = lib.mkEnableOption ''
|
||||
KDE Connect for phone integration — shared clipboard, notifications and
|
||||
file transfer with a paired phone; opens the firewall ports it needs'';
|
||||
|
||||
gamemode.enable = lib.mkEnableOption ''
|
||||
Feral GameMode — a daemon games ask to apply a performance CPU governor
|
||||
and IO/nice priorities while running (via `gamemoderun`)'';
|
||||
|
||||
adb.enable = lib.mkEnableOption ''
|
||||
the Android platform tools (adb/fastboot) for flashing/debugging phones.
|
||||
systemd ≥258 applies the device uaccess udev rules automatically, so the
|
||||
tools alone are enough — no group dance'';
|
||||
|
||||
wireshark.enable = lib.mkEnableOption ''
|
||||
Wireshark (the Qt GUI) for packet capture, with the login user in the
|
||||
`wireshark` group so capture works without root'';
|
||||
|
||||
ollama.enable = lib.mkEnableOption ''
|
||||
Ollama, a local LLM runtime serving an API on 127.0.0.1:11434 (pair it
|
||||
with the lmstudio/alpaca GUIs). CPU by default — set
|
||||
`services.ollama.acceleration` natively for GPU offload'';
|
||||
|
||||
printing.enable = lib.mkEnableOption ''
|
||||
CUPS printing with Avahi/mDNS, so network printers are auto-discovered
|
||||
(add vendor drivers via `services.printing.drivers`)'';
|
||||
|
||||
openrgb.enable = lib.mkEnableOption ''
|
||||
the OpenRGB daemon and GUI for controlling RGB lighting on peripherals
|
||||
and (where supported) motherboards — installs the udev rules for device
|
||||
access. Some motherboard controllers also need `hardware.i2c.enable`'';
|
||||
|
||||
restic = {
|
||||
enable = lib.mkEnableOption ''
|
||||
a scheduled (daily) restic backup — headless, complementing the Pika
|
||||
GUI. Backs up `paths` with sane retention (7 daily / 4 weekly /
|
||||
6 monthly); needs a `repository` and a `passwordFile` (below). List
|
||||
and restore with the generated `restic-nomarchy` wrapper (repo +
|
||||
password baked in), e.g. `restic-nomarchy snapshots`'';
|
||||
|
||||
repository = lib.mkOption {
|
||||
type = lib.types.str;
|
||||
default = "";
|
||||
example = "/mnt/backup/restic";
|
||||
description = ''
|
||||
The restic repository as a path or URL — e.g. `/mnt/backup/restic`,
|
||||
`sftp:user@host:/srv/restic`, `b2:bucket:/path`. Required when
|
||||
`restic.enable` is set.
|
||||
'';
|
||||
};
|
||||
|
||||
passwordFile = lib.mkOption {
|
||||
type = lib.types.nullOr lib.types.str;
|
||||
default = null;
|
||||
example = "/etc/nomarchy/restic-password";
|
||||
description = ''
|
||||
Path to a file holding the repository password. Give an absolute
|
||||
path that lives ON THE MACHINE — not a `./file` in the flake, which
|
||||
would copy the secret into the world-readable Nix store. Required
|
||||
when `restic.enable` is set.
|
||||
'';
|
||||
};
|
||||
|
||||
paths = lib.mkOption {
|
||||
type = lib.types.listOf lib.types.str;
|
||||
default = [ "/home" ];
|
||||
description = "Paths to include in the backup.";
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
config = lib.mkMerge [
|
||||
(lib.mkIf cfg.tailscale.enable {
|
||||
services.tailscale.enable = true;
|
||||
})
|
||||
|
||||
(lib.mkIf cfg.syncthing.enable {
|
||||
services.syncthing = {
|
||||
enable = true;
|
||||
user = args.username;
|
||||
# Manage folders/devices in the GUI; don't let the (empty) declarative
|
||||
# config wipe them on a rebuild.
|
||||
overrideDevices = false;
|
||||
overrideFolders = false;
|
||||
guiAddress = "127.0.0.1:8384";
|
||||
};
|
||||
})
|
||||
|
||||
(lib.mkIf cfg.podman.enable {
|
||||
virtualisation.podman = {
|
||||
enable = true;
|
||||
dockerCompat = lib.mkDefault true; # `docker` → podman (off if you run real docker)
|
||||
defaultNetwork.settings.dns_enabled = true; # DNS for rootless containers
|
||||
};
|
||||
# Rootless podman needs a subuid/subgid range for the user.
|
||||
users.users.${args.username}.autoSubUidGidRange = lib.mkDefault true;
|
||||
})
|
||||
|
||||
(lib.mkIf cfg.flatpak.enable {
|
||||
services.flatpak.enable = true;
|
||||
# Flatpak ships no remotes; add Flathub system-wide. Idempotent
|
||||
# (--if-not-exists), and it reads the .flatpakrepo over the network, so
|
||||
# it waits for connectivity and simply retries next boot if offline.
|
||||
systemd.services.nomarchy-flathub = {
|
||||
description = "Add the Flathub Flatpak remote";
|
||||
wantedBy = [ "multi-user.target" ];
|
||||
wants = [ "network-online.target" ];
|
||||
after = [ "network-online.target" ];
|
||||
path = [ pkgs.flatpak ];
|
||||
serviceConfig.Type = "oneshot";
|
||||
script = ''
|
||||
flatpak remote-add --system --if-not-exists flathub \
|
||||
https://dl.flathub.org/repo/flathub.flatpakrepo
|
||||
'';
|
||||
};
|
||||
})
|
||||
|
||||
(lib.mkIf cfg.pika.enable {
|
||||
environment.systemPackages = [ pkgs.pika-backup ];
|
||||
})
|
||||
|
||||
(lib.mkIf cfg.steam.enable {
|
||||
# The Steam package alone misses the system bits a game needs: the
|
||||
# 32-bit graphics stack, controller udev rules, Remote-Play ports.
|
||||
programs.steam.enable = true;
|
||||
})
|
||||
|
||||
(lib.mkIf cfg.libvirt.enable {
|
||||
virtualisation.libvirtd.enable = true;
|
||||
programs.virt-manager.enable = true;
|
||||
# Group membership lets the user reach the system libvirtd socket
|
||||
# (manage VMs) without sudo. Merges with the user's other extraGroups.
|
||||
users.users.${args.username}.extraGroups = [ "libvirtd" ];
|
||||
})
|
||||
|
||||
(lib.mkIf cfg.obs.enable {
|
||||
environment.systemPackages = [ pkgs.obs-studio ];
|
||||
# Virtual camera: OBS streams a scene into a v4l2 loopback device that
|
||||
# Zoom/Teams/browsers then pick up as a webcam. exclusive_caps=1 is the
|
||||
# bit that makes those apps actually list the device.
|
||||
boot.extraModulePackages = [ config.boot.kernelPackages.v4l2loopback ];
|
||||
boot.kernelModules = [ "v4l2loopback" ];
|
||||
boot.extraModprobeConfig = ''
|
||||
options v4l2loopback devices=1 video_nr=10 card_label="OBS Virtual Camera" exclusive_caps=1
|
||||
'';
|
||||
})
|
||||
|
||||
(lib.mkIf cfg.docker.enable {
|
||||
virtualisation.docker.enable = true;
|
||||
users.users.${args.username}.extraGroups = [ "docker" ];
|
||||
# Podman's docker-compat and real Docker both claim the `docker`
|
||||
# command — guard against enabling both (unless you turn that off).
|
||||
assertions = [{
|
||||
assertion = !(cfg.podman.enable && config.virtualisation.podman.dockerCompat);
|
||||
message = ''
|
||||
nomarchy.services: docker and podman both provide the `docker`
|
||||
command. Enable only one, or set
|
||||
`virtualisation.podman.dockerCompat = false`.
|
||||
'';
|
||||
}];
|
||||
})
|
||||
|
||||
(lib.mkIf cfg.kdeconnect.enable {
|
||||
programs.kdeconnect.enable = true; # installs the app and opens its ports
|
||||
})
|
||||
|
||||
(lib.mkIf cfg.gamemode.enable {
|
||||
programs.gamemode.enable = true;
|
||||
})
|
||||
|
||||
(lib.mkIf cfg.adb.enable {
|
||||
# `programs.adb` was removed — systemd ≥258 handles the device uaccess
|
||||
# udev rules, so the tools package is all that's needed now.
|
||||
environment.systemPackages = [ pkgs.android-tools ];
|
||||
})
|
||||
|
||||
(lib.mkIf cfg.wireshark.enable {
|
||||
programs.wireshark = {
|
||||
enable = true;
|
||||
package = pkgs.wireshark; # the Qt GUI (the module defaults to the CLI)
|
||||
};
|
||||
users.users.${args.username}.extraGroups = [ "wireshark" ];
|
||||
})
|
||||
|
||||
(lib.mkIf cfg.ollama.enable {
|
||||
services.ollama.enable = true;
|
||||
})
|
||||
|
||||
(lib.mkIf cfg.printing.enable {
|
||||
services.printing.enable = true;
|
||||
# mDNS so network printers show up without manual setup.
|
||||
services.avahi = {
|
||||
enable = true;
|
||||
nssmdns4 = true;
|
||||
openFirewall = true;
|
||||
};
|
||||
})
|
||||
|
||||
(lib.mkIf cfg.openrgb.enable {
|
||||
services.hardware.openrgb.enable = true;
|
||||
})
|
||||
|
||||
(lib.mkIf cfg.restic.enable {
|
||||
assertions = [
|
||||
{
|
||||
assertion = cfg.restic.repository != "";
|
||||
message = "nomarchy.services.restic.repository must be set when restic is enabled.";
|
||||
}
|
||||
{
|
||||
assertion = cfg.restic.passwordFile != null;
|
||||
message = "nomarchy.services.restic.passwordFile must be set when restic is enabled.";
|
||||
}
|
||||
];
|
||||
services.restic.backups.nomarchy = {
|
||||
repository = cfg.restic.repository;
|
||||
passwordFile = cfg.restic.passwordFile;
|
||||
paths = cfg.restic.paths;
|
||||
initialize = true; # create the repo on first run if it doesn't exist
|
||||
extraBackupArgs = [ "--exclude-caches" ];
|
||||
pruneOpts = [ "--keep-daily 7" "--keep-weekly 4" "--keep-monthly 6" ];
|
||||
timerConfig = {
|
||||
OnCalendar = "daily";
|
||||
Persistent = true; # catch up a missed run after downtime
|
||||
};
|
||||
};
|
||||
})
|
||||
];
|
||||
}
|
||||
@@ -444,15 +444,14 @@ cat > "$FLAKE_DIR/system.nix" <<EOF
|
||||
time.timeZone = "$TIMEZONE";
|
||||
i18n.defaultLocale = "$LOCALE";
|
||||
|
||||
# One keyboard layout everywhere: xkb is the source of truth, the
|
||||
# virtual console derives from it (greeter/ttys), and the systemd
|
||||
# initrd applies it to the LUKS passphrase prompt too (the classic
|
||||
# script initrd cannot). The Hyprland session reads the same layout
|
||||
# from nomarchy.keyboard.* in home.nix.
|
||||
# One keyboard layout everywhere: xkb is the source of truth, and the
|
||||
# distro defaults (console.useXkbConfig + the systemd initrd, set in
|
||||
# the nomarchy module) derive the virtual console and the LUKS
|
||||
# passphrase prompt from it — so only the chosen layout is written here.
|
||||
# The Hyprland session reads the same layout from nomarchy.keyboard.* in
|
||||
# home.nix.
|
||||
services.xserver.xkb.layout = "$KB_LAYOUT";
|
||||
services.xserver.xkb.variant = "$KB_VARIANT";
|
||||
console.useXkbConfig = true;
|
||||
boot.initrd.systemd.enable = true;
|
||||
|
||||
# Your login user — \`username\` flows in from flake.nix automatically.
|
||||
users.users.\${username} = {
|
||||
|
||||
@@ -5,15 +5,136 @@
|
||||
{ pkgs, ... }:
|
||||
|
||||
{
|
||||
# Examples:
|
||||
# ── Overrides (the desktop is on by default; tweak or opt out) ──────
|
||||
# nomarchy.terminal = "kitty"; # swap the default terminal
|
||||
# nomarchy.waybar.enable = false; # bring your own bar
|
||||
# nomarchy.stylix.enable = false; # opt out of GTK/Qt theming
|
||||
# nomarchy.keyboard.layout = "de"; # session keyboard (pair with
|
||||
# # xkb + console.useXkbConfig in
|
||||
# # system.nix for tty/LUKS)
|
||||
# nomarchy.keyboard.layout = "de"; # session keyboard (set the matching
|
||||
# # services.xserver.xkb.layout in
|
||||
# # system.nix too; the console + LUKS
|
||||
# # prompt follow it automatically)
|
||||
|
||||
# ── Opt-in features — uncomment and tweak to enable ─────────────────
|
||||
# nomarchy.nightlight = { # scheduled blue-light filter (hyprsunset)
|
||||
# enable = true;
|
||||
# temperature = 4000; # night warmth in K — lower is warmer
|
||||
# sunset = "20:00";
|
||||
# sunrise = "07:00";
|
||||
# };
|
||||
#
|
||||
# nomarchy.monitors = [ # declarative per-output layout, hotplug-applied
|
||||
# { name = "eDP-1"; position = "0x0"; }
|
||||
# { name = "HDMI-A-1"; position = "auto-right"; }
|
||||
# ]; # names from `hyprctl devices`
|
||||
#
|
||||
# nomarchy.keyboard.devices = { # a specific keyboard's own layout
|
||||
# "keychron-keychron-k2" = { layout = "de"; };
|
||||
# };
|
||||
#
|
||||
# nomarchy.keyboard.layouts = [ "de" "fr" ]; # rofi-prompt for a layout when a
|
||||
# # new keyboard connects + remember it
|
||||
|
||||
# ── Application suite ───────────────────────────────────────────────
|
||||
# A starter complete-workstation set, installed for your user — yours to
|
||||
# curate. Delete a line to slim the machine; uncomment a suggestion (or
|
||||
# add your own) to extend it. The desktop itself — terminal, editor
|
||||
# keybinds, theming — comes from the modules; these are the heavier
|
||||
# standalone apps the distro doesn't impose by default.
|
||||
#
|
||||
# Apps that need system setup beyond a package (Steam's 32-bit stack,
|
||||
# a daemon, group membership, a kernel module) are NOT here — they're
|
||||
# opt-in service toggles in system.nix instead (nomarchy.services.* —
|
||||
# steam, libvirt, obs, docker, gamemode, kdeconnect, adb, wireshark,
|
||||
# ollama, printing).
|
||||
home.packages = with pkgs; [
|
||||
libreoffice-fresh # office suite (documents, sheets, slides)
|
||||
vscode # code editor (unfree; allowUnfree is on)
|
||||
gimp # raster image editor
|
||||
inkscape # vector graphics
|
||||
mpv # media player
|
||||
amberol # music player (local library; streaming → spotify below)
|
||||
|
||||
# ── More apps — uncomment to add ─────────────────────────────────
|
||||
# Web browsers
|
||||
# firefox
|
||||
# chromium
|
||||
# ungoogled-chromium
|
||||
# brave # (unfree)
|
||||
# google-chrome # (unfree)
|
||||
|
||||
# Communication
|
||||
# signal-desktop
|
||||
# telegram-desktop
|
||||
# element-desktop # Matrix
|
||||
# vesktop # Discord (themeable client)
|
||||
# slack # (unfree)
|
||||
# zoom-us # (unfree)
|
||||
# teams-for-linux # community client (no official Linux app)
|
||||
# thunderbird # email
|
||||
|
||||
# Office & documents
|
||||
# onlyoffice-desktopeditors # stronger MS-Office fidelity
|
||||
# kdePackages.okular # PDF viewer
|
||||
# xournalpp # PDF annotation
|
||||
# pdfarranger
|
||||
# calibre # ebook library
|
||||
# texliveFull # full LaTeX toolchain — multi-GB (texliveMedium is lighter)
|
||||
|
||||
# Notes / research
|
||||
# logseq
|
||||
# obsidian # (unfree)
|
||||
# joplin-desktop
|
||||
# anki-bin # flashcards
|
||||
# zotero # reference manager
|
||||
|
||||
# Code & data
|
||||
# zed-editor
|
||||
# lazygit
|
||||
# dbeaver-bin # database GUI
|
||||
# bruno # API client
|
||||
# distrobox # containerized dev shells
|
||||
|
||||
# Graphics & design
|
||||
# krita # digital painting
|
||||
# blender # 3D
|
||||
# darktable # RAW photo
|
||||
|
||||
# Audio / video
|
||||
# audacity
|
||||
# shotcut # video editor
|
||||
# kdePackages.kdenlive # video editor (pulls in KDE libs)
|
||||
# handbrake # transcoder
|
||||
|
||||
# Media
|
||||
# vlc
|
||||
# spotify # (unfree)
|
||||
# newsflash # RSS reader
|
||||
|
||||
# Gaming (Steam + GameMode are service toggles in system.nix)
|
||||
# lutris
|
||||
# heroic # Epic/GOG launcher
|
||||
# bottles # Wine prefixes
|
||||
# prismlauncher # Minecraft
|
||||
# protonup-qt # Proton-GE manager
|
||||
# mangohud # in-game overlay
|
||||
|
||||
# Files, sync & torrents
|
||||
# nextcloud-client
|
||||
# localsend # AirDrop-like transfer
|
||||
# qbittorrent
|
||||
|
||||
# Security
|
||||
# keepassxc
|
||||
# bitwarden-desktop
|
||||
|
||||
# System
|
||||
# gnome-disk-utility
|
||||
# gparted
|
||||
# baobab # disk usage
|
||||
# wireguard-tools # WireGuard CLI (NetworkManager imports .conf tunnels natively)
|
||||
|
||||
# Local AI (Ollama is a service toggle in system.nix)
|
||||
# lmstudio # (unfree; large closure)
|
||||
# alpaca # GTK Ollama UI
|
||||
];
|
||||
}
|
||||
|
||||
@@ -18,9 +18,41 @@
|
||||
extraGroups = [ "wheel" "networkmanager" "video" "input" ];
|
||||
};
|
||||
|
||||
# Examples:
|
||||
# ── Overrides (uncomment to change) ─────────────────────────────────
|
||||
# nomarchy.system.greeter.enable = false; # bring your own login manager
|
||||
# environment.systemPackages = [ pkgs.htop ];
|
||||
|
||||
# ── Opt-in features — uncomment and tweak to enable ─────────────────
|
||||
# nomarchy.system.power = { # active power management (laptops)
|
||||
# enable = true;
|
||||
# backend = "ppd"; # "ppd" (default) or "tlp"
|
||||
# laptop = true; # required by batteryChargeLimit
|
||||
# batteryChargeLimit = 80; # cap charging for longevity
|
||||
# thermal.enable = true; # thermald (Intel CPUs)
|
||||
# };
|
||||
#
|
||||
# nomarchy.services.tailscale.enable = true; # mesh VPN — then `sudo tailscale up`
|
||||
# nomarchy.services.syncthing.enable = true; # file sync — GUI at http://127.0.0.1:8384
|
||||
# nomarchy.services.podman.enable = true; # rootless containers (docker → podman)
|
||||
# nomarchy.services.flatpak.enable = true; # Flatpak + the Flathub remote
|
||||
# nomarchy.services.pika.enable = true; # Pika Backup (GUI Borg backups)
|
||||
# nomarchy.services.steam.enable = true; # Steam (32-bit libs, controllers, ports)
|
||||
# nomarchy.services.libvirt.enable = true; # libvirt/KVM + virt-manager GUI
|
||||
# nomarchy.services.obs.enable = true; # OBS Studio + v4l2loopback virtual camera
|
||||
# nomarchy.services.docker.enable = true; # Docker rootful (not alongside podman)
|
||||
# nomarchy.services.kdeconnect.enable = true;# KDE Connect phone integration (opens ports)
|
||||
# nomarchy.services.gamemode.enable = true; # Feral GameMode performance daemon
|
||||
# nomarchy.services.adb.enable = true; # Android adb/fastboot tools
|
||||
# nomarchy.services.wireshark.enable = true; # Wireshark GUI (wireshark group, no root)
|
||||
# nomarchy.services.ollama.enable = true; # local LLM runtime (127.0.0.1:11434)
|
||||
# nomarchy.services.printing.enable = true; # CUPS + Avahi network printer discovery
|
||||
# nomarchy.services.openrgb.enable = true; # RGB peripheral/motherboard lighting daemon
|
||||
# nomarchy.services.restic = { # scheduled (daily) restic backup
|
||||
# enable = true;
|
||||
# repository = "/mnt/backup/restic"; # path or URL (sftp:/b2:/…)
|
||||
# passwordFile = "/etc/nomarchy/restic-password"; # absolute path, NOT in the flake
|
||||
# paths = [ "/home" ];
|
||||
# };
|
||||
|
||||
system.stateVersion = "26.05";
|
||||
}
|
||||
|
||||
@@ -29,7 +29,8 @@ window {
|
||||
border-color: @yellow;
|
||||
border-radius: 15px;
|
||||
width: 40%;
|
||||
height: 50%;
|
||||
/* No fixed height — size to content (fixed-num-lines:false) so every
|
||||
* entry shows without scrolling and there's no empty space below. */
|
||||
location: center;
|
||||
anchor: center;
|
||||
x-offset: 0;
|
||||
@@ -90,6 +91,12 @@ element {
|
||||
spacing: 15px;
|
||||
}
|
||||
|
||||
/* Zebra striping: every other row lifts with a faint light wash over the
|
||||
* dark window (bg0 at ~12% alpha). The selected row below still wins. */
|
||||
element alternate.normal {
|
||||
background-color: #fdf6e31f;
|
||||
}
|
||||
|
||||
element-icon {
|
||||
background-color: transparent;
|
||||
text-color: inherit;
|
||||
|
||||
@@ -48,8 +48,10 @@ window#waybar {
|
||||
#workspaces,
|
||||
#pulseaudio,
|
||||
#network,
|
||||
#custom-powerprofile,
|
||||
#battery,
|
||||
#tray,
|
||||
#custom-notification,
|
||||
#custom-powermenu {
|
||||
background-color: @bg0;
|
||||
color: @fg;
|
||||
|
||||
@@ -11,7 +11,7 @@
|
||||
|
||||
"modules-left": ["custom/launcher", "clock", "clock#date"],
|
||||
"modules-center": ["hyprland/workspaces"],
|
||||
"modules-right": ["pulseaudio", "network", "battery", "tray", "custom/powermenu"],
|
||||
"modules-right": ["pulseaudio", "network", "custom/powerprofile", "battery", "tray", "custom/notification", "custom/powermenu"],
|
||||
|
||||
"hyprland/workspaces": {
|
||||
"disable-scroll": true,
|
||||
@@ -80,6 +80,34 @@
|
||||
|
||||
"tray": { "spacing": 8 },
|
||||
|
||||
"custom/powerprofile": {
|
||||
"return-type": "json",
|
||||
"interval": 5,
|
||||
"exec": "nomarchy-powerprofile-status",
|
||||
"on-click": "nomarchy-powerprofile-cycle"
|
||||
},
|
||||
|
||||
"custom/notification": {
|
||||
"format": "{icon}",
|
||||
"return-type": "json",
|
||||
"exec": "swaync-client -swb",
|
||||
"exec-if": "which swaync-client",
|
||||
"escape": true,
|
||||
"tooltip": true,
|
||||
"on-click": "swaync-client -t -sw",
|
||||
"on-click-right": "swaync-client -d -sw",
|
||||
"format-icons": {
|
||||
"none": "",
|
||||
"notification": "",
|
||||
"dnd-none": "",
|
||||
"dnd-notification": "",
|
||||
"inhibited-none": "",
|
||||
"inhibited-notification": "",
|
||||
"dnd-inhibited-none": "",
|
||||
"dnd-inhibited-notification": ""
|
||||
}
|
||||
},
|
||||
|
||||
"custom/powermenu": {
|
||||
"format": "",
|
||||
"on-click": "nomarchy-menu power",
|
||||
|
||||
@@ -29,7 +29,8 @@ window {
|
||||
border-color: @yellow;
|
||||
border-radius: 15px;
|
||||
width: 40%;
|
||||
height: 50%;
|
||||
/* No fixed height — size to content (fixed-num-lines:false) so every
|
||||
* entry shows without scrolling and there's no empty space below. */
|
||||
location: center;
|
||||
anchor: center;
|
||||
x-offset: 0;
|
||||
@@ -90,6 +91,12 @@ element {
|
||||
spacing: 15px;
|
||||
}
|
||||
|
||||
/* Zebra striping: every other row lifts with a faint dark wash over the
|
||||
* cream window (bg0 at ~12% alpha). The selected row below still wins. */
|
||||
element alternate.normal {
|
||||
background-color: #2d353b1f;
|
||||
}
|
||||
|
||||
element-icon {
|
||||
background-color: transparent;
|
||||
text-color: inherit;
|
||||
|
||||
@@ -54,8 +54,10 @@ window#waybar {
|
||||
#workspaces,
|
||||
#pulseaudio,
|
||||
#network,
|
||||
#custom-powerprofile,
|
||||
#idle_inhibitor,
|
||||
#battery,
|
||||
#custom-notification,
|
||||
#custom-powermenu {
|
||||
background-color: @bg0;
|
||||
color: @fg;
|
||||
|
||||
@@ -11,7 +11,7 @@
|
||||
|
||||
"modules-left": ["custom/nomarchy", "clock", "clock#date"],
|
||||
"modules-center": ["hyprland/workspaces"],
|
||||
"modules-right": ["idle_inhibitor", "pulseaudio", "network", "battery", "tray", "custom/powermenu"],
|
||||
"modules-right": ["idle_inhibitor", "pulseaudio", "network", "custom/powerprofile", "battery", "tray", "custom/notification", "custom/powermenu"],
|
||||
|
||||
"hyprland/workspaces": {
|
||||
"disable-scroll": true,
|
||||
@@ -87,6 +87,34 @@
|
||||
|
||||
"tray": { "spacing": 8 },
|
||||
|
||||
"custom/powerprofile": {
|
||||
"return-type": "json",
|
||||
"interval": 5,
|
||||
"exec": "nomarchy-powerprofile-status",
|
||||
"on-click": "nomarchy-powerprofile-cycle"
|
||||
},
|
||||
|
||||
"custom/notification": {
|
||||
"format": "{icon}",
|
||||
"return-type": "json",
|
||||
"exec": "swaync-client -swb",
|
||||
"exec-if": "which swaync-client",
|
||||
"escape": true,
|
||||
"tooltip": true,
|
||||
"on-click": "swaync-client -t -sw",
|
||||
"on-click-right": "swaync-client -d -sw",
|
||||
"format-icons": {
|
||||
"none": "",
|
||||
"notification": "",
|
||||
"dnd-none": "",
|
||||
"dnd-notification": "",
|
||||
"inhibited-none": "",
|
||||
"inhibited-notification": "",
|
||||
"dnd-inhibited-none": "",
|
||||
"dnd-inhibited-notification": ""
|
||||
}
|
||||
},
|
||||
|
||||
"custom/powermenu": {
|
||||
"format": "",
|
||||
"on-click": "nomarchy-menu power",
|
||||
|
||||
Reference in New Issue
Block a user