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__/
|
__pycache__/
|
||||||
.DS_Store
|
.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.stateFile` | — (required) | Path to your theme-state.json |
|
||||||
| `nomarchy.terminal` | `"ghostty"` | Terminal for keybinds and `$TERMINAL` |
|
| `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.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.hyprland.enable` | `true` | Nomarchy's Hyprland config |
|
||||||
| `nomarchy.waybar.enable` | `true` | Nomarchy's Waybar |
|
| `nomarchy.waybar.enable` | `true` | Nomarchy's Waybar |
|
||||||
| `nomarchy.rofi.enable` | `true` | Themed rofi launcher + `nomarchy-menu` dispatcher |
|
| `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.stylix.enable` | `true` | GTK/Qt/cursor theming |
|
||||||
| `nomarchy.fastfetch.enable` | `true` | fastfetch fronted by the themed Nomarchy logo |
|
| `nomarchy.fastfetch.enable` | `true` | fastfetch fronted by the themed Nomarchy logo |
|
||||||
| `nomarchy.keys.enable` | `true` | gpg-agent fronting SSH + pinentry-qt |
|
| `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.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.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) |
|
| `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.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.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.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
|
Beyond the `nomarchy.*` surface, the system layer turns on the usual
|
||||||
desktop services with `lib.mkDefault` (override natively). One worth
|
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`
|
clipboard history · `SUPER+Q`
|
||||||
close · `SUPER+1..9` workspaces · `Print` region screenshot.
|
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
|
## 6. Extending
|
||||||
|
|
||||||
- **New theme:** drop a JSON into `themes/` (schema = any existing preset),
|
- **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.
|
the Nix modules. One place — there is no second renderer to keep in sync.
|
||||||
- **Importing more old-distro palettes:**
|
- **Importing more old-distro palettes:**
|
||||||
`tools/import-palettes.py <palettes-dir> themes/`.
|
`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
|
## 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
|
launcher, no second theming pipeline; the dispatcher owns the menu
|
||||||
structure, so the renderer stays swappable (we moved fuzzel → rofi 2.0
|
structure, so the renderer stays swappable (we moved fuzzel → rofi 2.0
|
||||||
once mainline gained native Wayland, for its richer theming)
|
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
|
- ✓ **Menu modules from rofi plugins:** the old `calc` flow committed the
|
||||||
expression blind (result only in the *next* menu's `-mesg`) and `qalc -t`
|
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-
|
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
|
summer-day/night menu buttons now use its `U+F000` glyph with
|
||||||
`font-family: Nomarchy` pinned in their CSS (Nerd Fonts also occupy
|
`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.
|
U+F000, so the pin is required). The other themes have no logo button.
|
||||||
- **Quality-of-life command aliases:** assemble a curated collection of
|
- ✓ **Quality-of-life command aliases:** a curated set ships on by default in
|
||||||
shell aliases/abbreviations for common operations (git, nix, navigation,
|
`modules/home/shell.nix` — navigation (`..`/`...`/`....`), a git block
|
||||||
the nomarchy helpers, …), themed into the zsh shell experience
|
(`g`, `gst`, `ga`/`gaa`, `gc`/`gcm`, `gco`/`gsw`, `gb`, `gd`/`gds`,
|
||||||
(`modules/home/shell.nix`). Decide scope and which to ship on by default.
|
`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
|
- **Theme-switch feedback:** ✓ the "rebuilding…" notification is now
|
||||||
persistent (timeout 0) and replaced in place by "applied ✓" / failure
|
persistent (timeout 0) and replaced in place by "applied ✓" / failure
|
||||||
via a synchronous tag, so a multi-minute switch never reads as a failed
|
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`.
|
tracks the palette), `ls`→eza, `cd`→zoxide, plus `lt`/`tree`.
|
||||||
`nomarchy.shell.enable`. (Deliberately did NOT alias grep→rg / find→fd:
|
`nomarchy.shell.enable`. (Deliberately did NOT alias grep→rg / find→fd:
|
||||||
their flags differ enough to surprise; `rg`/`fd` ship as themselves.)
|
their flags differ enough to surprise; `rg`/`fd` ship as themselves.)
|
||||||
- **Default application suite:** install a complete-workstation set
|
- ✓ **Default application suite:** a starter complete-workstation set —
|
||||||
(vscode, libreoffice, gimp, inkscape, texlive-full, …) behind a
|
`libreoffice-fresh`, `vscode`, `gimp`, `inkscape` — ships *active* in the
|
||||||
`nomarchy.apps.*` option surface so each is individually opt-out for
|
downstream `templates/downstream/home.nix` `home.packages`, with the heavier
|
||||||
users who want a leaner machine. Watch closure size (texlive-full is
|
opt-ins (`texliveFull` — multi-GB; `texliveMedium` is lighter — plus
|
||||||
multi-GB — likely default-off or a lighter scheme).
|
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
|
- ✓ **Plymouth logo contrast:** the shipped art was a fixed navy that
|
||||||
vanished on dark bases. `modules/nixos/plymouth.nix` now recolors every
|
vanished on dark bases. `modules/nixos/plymouth.nix` now recolors every
|
||||||
element from the palette at build time (flat fill, alpha kept):
|
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
|
accent. Reads on light and dark; follows the theme as of the last system
|
||||||
rebuild (like the background tint).
|
rebuild (like the background tint).
|
||||||
- ✓ **Hibernate double-unlock:** on resume from hibernate the LUKS
|
- ✓ **Hibernate double-unlock:** on resume from hibernate the LUKS
|
||||||
passphrase already gates the machine, but hypridle's `before_sleep_cmd`
|
passphrase already gates the machine, but locking hyprlock before sleep
|
||||||
also locked hyprlock, so the user typed a password twice. Fixed with a
|
meant a second password. Fixed by *not locking* before an encrypted
|
||||||
`nomarchy-hibernate-unlock` systemd unit (`modules/nixos/default.nix`)
|
hibernate: a `nomarchy-lock-before-sleep` systemd unit
|
||||||
that dismisses hyprlock *after* a hibernate resume (`WantedBy
|
(`modules/nixos/default.nix`) takes over from hypridle's `before_sleep_cmd`
|
||||||
hibernate.target`, `After systemd-hibernate.service` → runs post-resume),
|
and locks on the RAM-resume sleeps (suspend / hybrid-sleep / suspend-then-
|
||||||
gated on the disk being LUKS-encrypted. Suspend (and the RAM-resume phase
|
hibernate) always, but skips `hibernate.target` when the disk is LUKS-
|
||||||
of suspend-then-hibernate) keep locking — they have no passphrase gate.
|
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`
|
- ✓ **Key agents & pinentry:** ships `modules/home/keys.nix`
|
||||||
(`nomarchy.keys.enable`): one agent — `services.gpg-agent` with
|
(`nomarchy.keys.enable`): one agent — `services.gpg-agent` with
|
||||||
`enableSshSupport` fronts SSH, so a single `pinentry-qt` (native-Wayland,
|
`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
|
cache. Remaining (optional): a session-level `SSH_AUTH_SOCK` export so GUI
|
||||||
clients launched outside a shell also see the agent.
|
clients launched outside a shell also see the agent.
|
||||||
- **Sanitize & organize the repo:** a housekeeping pass for consistency
|
- **Sanitize & organize the repo:** a housekeeping pass for consistency
|
||||||
and clarity. Candidate targets (scope still to be defined): prune
|
and clarity.
|
||||||
now-redundant config (e.g. the installer still writes
|
- ✓ pruned now-redundant config: the installer no longer writes
|
||||||
`console.useXkbConfig` / `boot.initrd.systemd.enable` into `system.nix`,
|
`console.useXkbConfig` / `boot.initrd.systemd.enable` into `system.nix`
|
||||||
which are distro-wide defaults as of the LUKS-keymap fix); reconcile the
|
(distro-wide defaults since the LUKS-keymap fix), nor the offline-pin
|
||||||
README option tables with the actual `nomarchy.*` surface; audit
|
test fixture in `flake.nix`.
|
||||||
comments/docs for drift against the code; and re-check that every file
|
- ✓ reconciled the README option tables with the live `nomarchy.*`
|
||||||
still earns its place under the `modules`/`hosts`/`themes`/`pkgs`/`tools`
|
surface (added keys/fastfetch/snapper/greeter.autoLogin).
|
||||||
rule of thumb.
|
- ✓ 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,
|
- **Full docs review & restructure:** a dedicated pass over all the prose,
|
||||||
not just the code-adjacent cleanup the repo-sanitize item covers. The
|
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
|
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.
|
idle behaviour.
|
||||||
- Remaining: a boot-only→event-driven charge-limit re-apply (udev) if a
|
- Remaining: a boot-only→event-driven charge-limit re-apply (udev) if a
|
||||||
firmware resets the threshold on unplug.
|
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*
|
- **Opt-in services & integrations:** the counterpart to the opt-*out*
|
||||||
application suite above — heavier or more personal integrations shipped
|
application suite above — heavier or more personal integrations shipped
|
||||||
**off by default**, each a `nomarchy.services.<name>.enable` toggle a
|
**off by default**, each a `nomarchy.services.<name>.enable` toggle a
|
||||||
downstream flips on in one line. Keeps the base lean while making common
|
downstream flips on in one line. Keeps the base lean while making common
|
||||||
additions trivial. Candidates by area:
|
additions trivial. **✓ Seventeen shipped** in `modules/nixos/services.nix`
|
||||||
- **cloud/sync:** Nextcloud client; Syncthing (`services.syncthing`)
|
(system-side), each with a commented example in the downstream `system.nix`
|
||||||
- **local AI:** LM Studio (`lmstudio`); Ollama (`services.ollama`, optional
|
template: `tailscale`, `syncthing` (runs as the login user, GUI on
|
||||||
GPU accel) — pairs with the menu's Ask-Claude philosophy
|
127.0.0.1:8384), `podman` (rootless, `docker` aliased, user subuid/subgid),
|
||||||
- **containers/VMs:** Docker/Podman; libvirt + virt-manager
|
`flatpak` (+ Flathub remote added by a oneshot), `pika` (Pika Backup GUI),
|
||||||
- **networking:** Tailscale (`services.tailscale`); WireGuard
|
`steam` (`programs.steam` — the 32-bit stack, controller udev, Remote-Play
|
||||||
- **gaming/media:** Steam (`programs.steam`); OBS Studio
|
ports a bare package can't), `libvirt` (libvirtd + virt-manager, user added
|
||||||
- **devices:** printing (CUPS + Avahi); KDE Connect / phone integration;
|
to the `libvirtd` group), `obs` (OBS Studio + a v4l2loopback virtual camera
|
||||||
OpenRGB
|
usable as a webcam in Zoom/Teams), `docker` (rootful; asserts against the
|
||||||
- **backup:** restic/borg (`services.restic`)
|
podman docker-compat), `kdeconnect`, `gamemode`, `adb` (android-tools;
|
||||||
- **escape hatch:** Flatpak (`services.flatpak`) for apps outside nixpkgs
|
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 decided: `nomarchy.services.*`, system-side for system services
|
||||||
surface or split (`nomarchy.services.*` system-side vs home-side packages);
|
(home-side ones can extend the same prefix later). Remaining: curate the
|
||||||
and how it relates to `nomarchy.apps.*` (opt-out suite). Unfree entries are
|
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`).
|
already covered (`allowUnfree = true`).
|
||||||
- **Display / monitor management:** today Hyprland just uses
|
- ✓ **Display / monitor management:** declarative `nomarchy.monitors` (a
|
||||||
`monitor = ,preferred,auto,1` (mkDefault). Add a real external-monitor/dock
|
per-output schema — name/resolution/position/scale/transform/mirror/
|
||||||
story: declarative per-output config, hotplug profiles (kanshi-style, or
|
bitdepth/vrr/disable) generates Hyprland `monitor` rules, keeping the
|
||||||
Hyprland's own monitor rules), and optionally a GUI arranger (nwg-displays
|
`,preferred,auto,1` wildcard as the fallback; Hyprland applies them on
|
||||||
writes Hyprland monitor config). Decide declarative-only vs GUI, and the
|
hotplug, so a declared external/dock output arranges itself on connect
|
||||||
option shape (`nomarchy.monitors` vs plain Hyprland `monitor` lists).
|
(no kanshi — it fights Hyprland's own output management). `nwg-displays`
|
||||||
- **Night light / blue-light filter:** schedulable colour-temperature shift
|
ships behind `nomarchy.displays.enable` as an interactive arranger (a
|
||||||
via `hyprsunset` (Hyprland-native; wlsunset/gammastep are alternatives) —
|
helper to find values; the declarative config stays the source of truth —
|
||||||
sunset/sunrise or a fixed schedule, with a menu + Waybar toggle.
|
its output file isn't sourced). Remaining: true docked/undocked **profile
|
||||||
- **Runtime keyboard-layout switching:** the session layout is a single
|
switching** of the *same* outputs (Hyprland's per-output rules cover the
|
||||||
`nomarchy.keyboard.layout` today. Support a list of layouts with a toggle
|
common "external connects → arrange" case, not multi-layout toggles), and
|
||||||
bind (`hyprctl switchxkblayout` / xkb `grp:` options) and a Waybar
|
optionally workspace-to-monitor binding.
|
||||||
indicator for the active layout. Natural follow-on to the LUKS-keymap work
|
- ✓ **Night light / blue-light filter:** `nomarchy.nightlight` (opt-in) —
|
||||||
— keep the system (console/initrd) and session layouts in sync.
|
a scheduled colour-temperature shift via `hyprsunset` (Hyprland-native),
|
||||||
- **Do-Not-Disturb:** a swaync DND toggle (`swaync-client -dn`) wired into
|
warm at night, identity (no shift) by day. `modules/home/nightlight.nix`
|
||||||
the menu and a Waybar indicator, to silence notifications for
|
drives the HM `services.hyprsunset` with two time-based profiles
|
||||||
presentations/focus.
|
(`sunrise` → identity, `sunset` → `temperature`), so hyprsunset handles the
|
||||||
- **Snapshot browse/restore UX:** snapper already takes BTRFS timeline
|
schedule and the on-login state. Needs an on-hardware check that hyprsunset
|
||||||
snapshots (`nomarchy.system.snapper`); surface them from the desktop — a
|
applies the active profile at session start. Remaining (optional): a menu +
|
||||||
rofi menu (or btrfs-assistant) to browse/diff/restore and boot-from-
|
Waybar toggle to force it on/off, and geo (lat/long) auto sunset/sunrise
|
||||||
snapshot — so rollback isn't CLI-only.
|
(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`);
|
- **Update awareness:** updates are manual today (`sys-update`/`home-update`);
|
||||||
add a Waybar indicator / notification when flake inputs are stale or a new
|
add a Waybar indicator / notification when flake inputs are stale or a new
|
||||||
nixpkgs rev is available (optionally with a pending-change count). Augments,
|
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
|
dark. `stylix.nix` now sets `dconf` `org/gnome/desktop/interface
|
||||||
color-scheme` = `prefer-light`/`prefer-dark` from `t.mode`
|
color-scheme` = `prefer-light`/`prefer-dark` from `t.mode`
|
||||||
(xdg-desktop-portal-gtk already ships, and `programs.dconf` is on
|
(xdg-desktop-portal-gtk already ships, and `programs.dconf` is on
|
||||||
system-side), so libadwaita/Qt follow the palette. Needs a live session
|
system-side), so libadwaita/Qt follow the palette. Confirmed in a live
|
||||||
to confirm the portal picks it up for all apps.
|
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"
|
(nixpkgs.lib.concatStringsSep "\n"
|
||||||
(builtins.attrNames nixos-hardware.nixosModules));
|
(builtins.attrNames nixos-hardware.nixosModules));
|
||||||
nixpkgsPath = nixpkgs.outPath;
|
nixpkgsPath = nixpkgs.outPath;
|
||||||
# v1 is the release branch: installed machines track it on
|
# Branch model: `main` is the development default; `v1` is the
|
||||||
# `nix flake update` instead of the forge's default branch.
|
# 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";
|
flakeUrl = "git+${gitUrl}?ref=v1";
|
||||||
# Future updates re-resolve from the forge (original); the install
|
# Future updates re-resolve from the forge (original); the install
|
||||||
# itself resolves from the ISO store (locked = path) — fully
|
# itself resolves from the ISO store (locked = path) — fully
|
||||||
@@ -252,12 +255,6 @@
|
|||||||
({ lib, ... }: {
|
({ lib, ... }: {
|
||||||
nomarchy.system.snapper.enable = true;
|
nomarchy.system.snapper.enable = true;
|
||||||
nomarchy.system.greeter.autoLogin = username;
|
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
|
# nixos-generate-config keys microcode off
|
||||||
# enableRedistributableFirmware (now on): the
|
# enableRedistributableFirmware (now on): the
|
||||||
# real machine enables exactly one vendor —
|
# real machine enables exactly one vendor —
|
||||||
|
|||||||
@@ -17,6 +17,7 @@
|
|||||||
./idle.nix # hyprlock + hypridle, themed from the same JSON
|
./idle.nix # hyprlock + hypridle, themed from the same JSON
|
||||||
./yazi.nix # flagship TUI file manager, themed + plugins
|
./yazi.nix # flagship TUI file manager, themed + plugins
|
||||||
./osd.nix # swayosd volume/brightness OSD, themed
|
./osd.nix # swayosd volume/brightness OSD, themed
|
||||||
|
./nightlight.nix # scheduled blue-light filter (hyprsunset), opt-in
|
||||||
./shell.nix # zsh + starship + bat/eza/zoxide, themed
|
./shell.nix # zsh + starship + bat/eza/zoxide, themed
|
||||||
./keys.nix # gpg-agent (fronts SSH) + pinentry-qt
|
./keys.nix # gpg-agent (fronts SSH) + pinentry-qt
|
||||||
./fastfetch.nix # system info with the themed Nomarchy logo
|
./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.
|
# (rofi.nix renders the same list). Edit them in ./keybinds.nix.
|
||||||
keybinds = import ./keybinds.nix;
|
keybinds = import ./keybinds.nix;
|
||||||
mkBind = b: "${b.mods}, ${b.key}, ${b.action}";
|
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
|
in
|
||||||
{
|
{
|
||||||
wayland.windowManager.hyprland = lib.mkIf config.nomarchy.hyprland.enable {
|
wayland.windowManager.hyprland = lib.mkIf config.nomarchy.hyprland.enable {
|
||||||
@@ -59,9 +130,12 @@ in
|
|||||||
"$mod" = "SUPER";
|
"$mod" = "SUPER";
|
||||||
"$terminal" = config.nomarchy.terminal;
|
"$terminal" = config.nomarchy.terminal;
|
||||||
|
|
||||||
# mkDefault so a downstream `monitor = [...]` replaces it with a
|
# `,preferred,auto,1` is the wildcard fallback for any output not in
|
||||||
# plain assignment (the live ISO uses mkForce for the same reason).
|
# nomarchy.monitors; the generated rules are appended and win by name,
|
||||||
monitor = lib.mkDefault [ ",preferred,auto,1" ];
|
# 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
|
# exec-once is a list at normal priority, so downstream additions
|
||||||
# CONCATENATE (your autostart runs alongside ours) rather than
|
# 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
|
# Paint the wallpaper as soon as the session is up (waits for
|
||||||
# the daemon internally).
|
# the daemon internally).
|
||||||
"nomarchy-theme-sync wallpaper"
|
"nomarchy-theme-sync wallpaper"
|
||||||
];
|
] ++ lib.optional kbAutoSwitch "${keyboardWatch}/bin/nomarchy-keyboard-watch";
|
||||||
|
|
||||||
# ── Theme-driven look ──────────────────────────────────────────
|
# ── Theme-driven look ──────────────────────────────────────────
|
||||||
# These flow from theme-state.json and stay at NORMAL priority:
|
# These flow from theme-state.json and stay at NORMAL priority:
|
||||||
@@ -128,12 +202,20 @@ in
|
|||||||
input = {
|
input = {
|
||||||
# kb_layout/variant come from nomarchy.keyboard.* — set that
|
# kb_layout/variant come from nomarchy.keyboard.* — set that
|
||||||
# option (the installer writes it; it also drives tty/LUKS).
|
# 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;
|
kb_variant = config.nomarchy.keyboard.variant;
|
||||||
follow_mouse = lib.mkDefault 1;
|
follow_mouse = lib.mkDefault 1;
|
||||||
touchpad.natural_scroll = lib.mkDefault true;
|
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`
|
# dwindle:pseudotile was removed in Hyprland 0.55 (the `pseudo`
|
||||||
# dispatcher still exists); setting it aborts config parsing.
|
# dispatcher still exists); setting it aborts config parsing.
|
||||||
dwindle.preserve_split = lib.mkDefault true;
|
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 = {
|
settings = {
|
||||||
general = {
|
general = {
|
||||||
lock_cmd = "pidof hyprlock || hyprlock";
|
lock_cmd = "pidof hyprlock || hyprlock";
|
||||||
# Locks before every sleep. For suspend that's exactly right; on an
|
# No before_sleep_cmd here: locking before sleep is driven
|
||||||
# encrypted hibernate the LUKS resume already gates the machine, so
|
# system-side so it can fire for suspend but skip an encrypted
|
||||||
# the system side dismisses this lock post-resume to avoid a double
|
# hibernate — whose LUKS resume already gates the machine, so a
|
||||||
# unlock — see nomarchy-hibernate-unlock in modules/nixos/default.nix.
|
# hyprlock on top is a second password (and a Wayland session-lock
|
||||||
before_sleep_cmd = "loginctl lock-session";
|
# 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";
|
after_sleep_cmd = "hyprctl dispatch dpms on";
|
||||||
};
|
};
|
||||||
listener = [
|
listener = [
|
||||||
|
|||||||
@@ -47,6 +47,7 @@
|
|||||||
{ mods = "$mod CTRL"; key = "B"; action = "exec, nomarchy-menu bluetooth"; desc = "Bluetooth"; }
|
{ 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 = "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 = "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
|
# Focus
|
||||||
{ mods = "$mod"; key = "H"; action = "movefocus, l"; desc = "Focus left"; }
|
{ 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.
|
# configure in their home.nix. Kept small on purpose.
|
||||||
{ lib, pkgs, ... }:
|
{ 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 = {
|
options.nomarchy = {
|
||||||
# ── Required ───────────────────────────────────────────────────
|
# ── Required ───────────────────────────────────────────────────
|
||||||
@@ -42,6 +96,49 @@
|
|||||||
description = "XKB variant for the Hyprland session.";
|
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 {
|
package = lib.mkOption {
|
||||||
type = lib.types.package;
|
type = lib.types.package;
|
||||||
default = pkgs.nomarchy-theme-sync;
|
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 ──────────────────────────────────────────
|
# ── Component toggles ──────────────────────────────────────────
|
||||||
hyprland.enable = lib.mkEnableOption "Nomarchy's Hyprland configuration" // { default = true; };
|
hyprland.enable = lib.mkEnableOption "Nomarchy's Hyprland configuration" // { default = true; };
|
||||||
waybar.enable = lib.mkEnableOption "Nomarchy's Waybar 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; };
|
ghostty.enable = lib.mkEnableOption "Nomarchy's Ghostty configuration" // { default = true; };
|
||||||
btop.enable = lib.mkEnableOption "btop with the per-theme nomarchy theme" // { 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; };
|
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) ───────────────────────────────────────
|
# ── Computed (read-only) ───────────────────────────────────────
|
||||||
theme = lib.mkOption {
|
theme = lib.mkOption {
|
||||||
|
|||||||
@@ -41,9 +41,9 @@ let
|
|||||||
nomarchy-menu = pkgs.writeShellScriptBin "nomarchy-menu" ''
|
nomarchy-menu = pkgs.writeShellScriptBin "nomarchy-menu" ''
|
||||||
# Nomarchy menu dispatcher — thin presentation layer over
|
# Nomarchy menu dispatcher — thin presentation layer over
|
||||||
# `rofi -dmenu`; actions delegate to nomarchy-theme-sync, systemctl,
|
# `rofi -dmenu`; actions delegate to nomarchy-theme-sync, systemctl,
|
||||||
# hyprctl and friends. Icons are nf-md glyphs (Pango falls back to a
|
# hyprctl and friends. Menu entries carry real icons from the theme's
|
||||||
# Nerd Font for them). `nomarchy-menu` with no argument shows the
|
# icon set (Papirus) via rofi's per-row icon protocol — see row() below.
|
||||||
# module picker.
|
# `nomarchy-menu` with no argument shows the module picker.
|
||||||
|
|
||||||
urlencode() {
|
urlencode() {
|
||||||
local s="$1" out="" ch i
|
local s="$1" out="" ch i
|
||||||
@@ -58,16 +58,22 @@ let
|
|||||||
printf '%s' "$out"
|
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
|
case "''${1:-}" in
|
||||||
power)
|
power)
|
||||||
choice=$(printf '%s\n' \
|
choice=$( {
|
||||||
" Lock" \
|
row "Lock" system-lock-screen
|
||||||
" Logout" \
|
row "Logout" system-log-out
|
||||||
" Suspend" \
|
row "Suspend" system-suspend
|
||||||
" Hibernate" \
|
row "Hibernate" system-hibernate
|
||||||
" Reboot" \
|
row "Reboot" system-reboot
|
||||||
" Shutdown" \
|
row "Shutdown" system-shutdown
|
||||||
| rofi -dmenu -p power) || exit 0
|
} | rofi -dmenu -show-icons -p Power) || exit 0
|
||||||
case "$choice" in
|
case "$choice" in
|
||||||
*Lock) loginctl lock-session ;;
|
*Lock) loginctl lock-session ;;
|
||||||
*Logout) hyprctl dispatch exit ;;
|
*Logout) hyprctl dispatch exit ;;
|
||||||
@@ -134,12 +140,12 @@ let
|
|||||||
exec blueman-manager ;;
|
exec blueman-manager ;;
|
||||||
|
|
||||||
capture)
|
capture)
|
||||||
choice=$(printf '%s\n' \
|
choice=$( {
|
||||||
" Region → clipboard" \
|
row "Region → clipboard" applets-screenshooter
|
||||||
" Region → file" \
|
row "Region → file" applets-screenshooter
|
||||||
" Full screen → clipboard" \
|
row "Full screen → clipboard" camera-photo
|
||||||
" Full screen → file" \
|
row "Full screen → file" camera-photo
|
||||||
| rofi -dmenu -p capture) || exit 0
|
} | rofi -dmenu -show-icons -p Capture) || exit 0
|
||||||
dir="$HOME/Pictures/Screenshots"
|
dir="$HOME/Pictures/Screenshots"
|
||||||
file="$dir/$(date +%Y%m%d-%H%M%S).png"
|
file="$dir/$(date +%Y%m%d-%H%M%S).png"
|
||||||
case "$choice" in
|
case "$choice" in
|
||||||
@@ -164,49 +170,93 @@ let
|
|||||||
[ -n "$q" ] || exit 0
|
[ -n "$q" ] || exit 0
|
||||||
exec ${cfg.terminal} -e npx --yes @anthropic-ai/claude-code@latest "$q" ;;
|
exec ${cfg.terminal} -e npx --yes @anthropic-ai/claude-code@latest "$q" ;;
|
||||||
|
|
||||||
"")
|
dnd)
|
||||||
entries=(
|
# Toggle swaync Do-Not-Disturb (-d prints the new state). With DND
|
||||||
" Apps"
|
# on, notifications are suppressed — the Waybar bell-off icon is the
|
||||||
" Theme"
|
# cue — so only confirm with a toast when turning it back off.
|
||||||
" Clipboard"
|
[ "$(swaync-client -d)" = "false" ] \
|
||||||
" Calculator"
|
&& notify-send "Do Not Disturb off" "Notifications resumed."
|
||||||
" Files"
|
exit 0 ;;
|
||||||
" Emoji"
|
|
||||||
" Web search"
|
snapshot)
|
||||||
" Network"
|
# btrfs-assistant: snapshot browse / diff / restore / rollback over
|
||||||
" Bluetooth"
|
# snapper, elevating via polkit. Shipped system-side with
|
||||||
" Capture"
|
# nomarchy.system.snapper; self-gate so the entry no-ops elsewhere.
|
||||||
" Keybindings"
|
command -v btrfs-assistant >/dev/null 2>&1 \
|
||||||
" Ask Claude"
|
|| { notify-send "Snapshots" "btrfs-assistant isn't installed (BTRFS snapshots off?)."; exit 0; }
|
||||||
)
|
exec btrfs-assistant ;;
|
||||||
# Power-profile picker only when this is a laptop (battery present)
|
|
||||||
# running power-profiles-daemon — matches the Waybar indicator's
|
tools)
|
||||||
# self-gating; desktops and the TLP backend don't show it.
|
# Tools submenu — utilities you invoke. Each leaf is also reachable
|
||||||
bats=(/sys/class/power_supply/BAT*)
|
# directly (SUPER+CTRL+<mnemonic>); this just keeps the root short.
|
||||||
if [ -e "''${bats[0]}" ] && command -v powerprofilesctl >/dev/null 2>&1; then
|
choice=$( {
|
||||||
entries+=(" Power profile")
|
row "Calculator" accessories-calculator
|
||||||
fi
|
row "Clipboard" edit-paste
|
||||||
entries+=(" Power")
|
row "Emoji" face-smile-big
|
||||||
choice=$(printf '%s\n' "''${entries[@]}" | rofi -dmenu -p menu) || exit 0
|
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
|
case "$choice" in
|
||||||
*Apps*) exec rofi -show drun ;;
|
|
||||||
*Theme*) exec "$0" theme ;;
|
|
||||||
*Clipboard*) exec "$0" clipboard ;;
|
|
||||||
*Calc*) exec "$0" calc ;;
|
*Calc*) exec "$0" calc ;;
|
||||||
*Files*) exec "$0" files ;;
|
*Clipboard*) exec "$0" clipboard ;;
|
||||||
*Emoji*) exec "$0" emoji ;;
|
*Emoji*) exec "$0" emoji ;;
|
||||||
|
*Files*) exec "$0" files ;;
|
||||||
*Web*) exec "$0" web ;;
|
*Web*) exec "$0" web ;;
|
||||||
*Network*) exec "$0" network ;;
|
|
||||||
*Bluetooth*) exec "$0" bluetooth ;;
|
|
||||||
*Capture*) exec "$0" capture ;;
|
*Capture*) exec "$0" capture ;;
|
||||||
*Keybindings*) exec "$0" keybinds ;;
|
|
||||||
*Ask*) exec "$0" ask ;;
|
*Ask*) exec "$0" ask ;;
|
||||||
*"Power profile"*) exec "$0" power-profile ;;
|
*Back*) exec "$0" ;;
|
||||||
*Power*) exec "$0" power ;;
|
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 ;;
|
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 ;;
|
exit 64 ;;
|
||||||
esac
|
esac
|
||||||
'';
|
'';
|
||||||
@@ -238,6 +288,10 @@ in
|
|||||||
drun-display-format = "{name}";
|
drun-display-format = "{name}";
|
||||||
display-drun = "apps";
|
display-drun = "apps";
|
||||||
display-run = "run";
|
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
|
# Whole-swap themes bring their own rofi.rasi; otherwise the theme
|
||||||
@@ -290,22 +344,34 @@ in
|
|||||||
columns = 1;
|
columns = 1;
|
||||||
dynamic = true;
|
dynamic = true;
|
||||||
scrollbar = false;
|
scrollbar = false;
|
||||||
spacing = px 2;
|
spacing = px 4; # a little air so the rounded zebra rows separate
|
||||||
padding = mkLiteral "8px 0px 0px 0px";
|
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" = {
|
"element" = {
|
||||||
padding = mkLiteral "8px 12px";
|
padding = mkLiteral "10px 14px";
|
||||||
border-radius = px t.ui.rounding;
|
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";
|
background-color = mkLiteral "@accent";
|
||||||
text-color = mkLiteral "@bg";
|
text-color = mkLiteral "@bg";
|
||||||
};
|
};
|
||||||
"element-icon" = {
|
"element-icon" = {
|
||||||
background-color = mkLiteral "transparent";
|
background-color = mkLiteral "transparent";
|
||||||
size = mkLiteral "1em";
|
size = px t.ui.iconSize; # real icons (Papirus), not 1em font glyphs
|
||||||
};
|
};
|
||||||
"element-text" = {
|
"element-text" = {
|
||||||
background-color = mkLiteral "transparent";
|
background-color = mkLiteral "transparent";
|
||||||
|
|||||||
@@ -35,6 +35,9 @@ in
|
|||||||
ignoreSpace = true;
|
ignoreSpace = true;
|
||||||
expireDuplicatesFirst = 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 = {
|
shellAliases = {
|
||||||
cat = "bat --paging=never";
|
cat = "bat --paging=never";
|
||||||
less = "bat";
|
less = "bat";
|
||||||
@@ -42,8 +45,42 @@ in
|
|||||||
# eza enableZshIntegration aliases ls/ll/la; add a couple extras.
|
# eza enableZshIntegration aliases ls/ll/la; add a couple extras.
|
||||||
lt = "eza --tree --level=2 --icons=auto --group-directories-first";
|
lt = "eza --tree --level=2 --icons=auto --group-directories-first";
|
||||||
tree = "eza --tree --icons=auto --group-directories-first";
|
tree = "eza --tree --icons=auto --group-directories-first";
|
||||||
|
|
||||||
|
# Navigation — climb without counting dots.
|
||||||
".." = "cd ..";
|
".." = "cd ..";
|
||||||
"..." = "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;
|
gapsOut = 12;
|
||||||
borderSize = 2;
|
borderSize = 2;
|
||||||
rounding = 10;
|
rounding = 10;
|
||||||
|
iconSize = 36; # rofi launcher + menu icon size (px) for the generated theme
|
||||||
activeOpacity = 1.0;
|
activeOpacity = 1.0;
|
||||||
inactiveOpacity = 0.95;
|
inactiveOpacity = 0.95;
|
||||||
terminalOpacity = 0.96;
|
terminalOpacity = 0.96;
|
||||||
|
|||||||
@@ -12,12 +12,23 @@
|
|||||||
let
|
let
|
||||||
t = config.nomarchy.theme;
|
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-
|
# Power-profile indicator (power-profiles-daemon). Both scripts self-
|
||||||
# gate: they exit silently unless this is a laptop (a battery is
|
# gate: they exit silently unless this is a laptop (a battery is
|
||||||
# present) running PPD, so the module hides itself on desktops and
|
# present) running PPD, so the module hides itself on desktops and
|
||||||
# under the TLP backend — no system→home coupling. Speedometer glyphs
|
# under the TLP backend — no system→home coupling. Speedometer glyphs
|
||||||
# (slow/medium/fast) map to power-saver/balanced/performance.
|
# (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
|
case "$(ls /sys/class/power_supply/ 2>/dev/null)" in *BAT*) ;; *) exit 0 ;; esac
|
||||||
command -v powerprofilesctl >/dev/null 2>&1 || exit 0
|
command -v powerprofilesctl >/dev/null 2>&1 || exit 0
|
||||||
prof=$(powerprofilesctl get 2>/dev/null) || 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"
|
printf '{"text":"%s","tooltip":"Power profile: %s","class":"%s"}\n' "$icon" "$prof" "$prof"
|
||||||
'';
|
'';
|
||||||
# Cycle to the next profile this machine actually offers (wraps around).
|
# 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
|
command -v powerprofilesctl >/dev/null 2>&1 || exit 0
|
||||||
cur=$(powerprofilesctl get 2>/dev/null) || exit 0
|
cur=$(powerprofilesctl get 2>/dev/null) || exit 0
|
||||||
avail=$(powerprofilesctl list 2>/dev/null | sed -nE 's/^[* ] ([a-z-]+):$/\1/p')
|
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-left = [ "hyprland/workspaces" "hyprland/window" ];
|
||||||
modules-center = [ "clock" ];
|
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" = {
|
"hyprland/workspaces" = {
|
||||||
format = "{icon}";
|
format = "{icon}";
|
||||||
@@ -84,6 +97,13 @@ let
|
|||||||
tooltip-format = "<tt><small>{calendar}</small></tt>";
|
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 = {
|
pulseaudio = {
|
||||||
format = "{icon} {volume}%";
|
format = "{icon} {volume}%";
|
||||||
format-muted = "";
|
format-muted = "";
|
||||||
@@ -112,10 +132,35 @@ let
|
|||||||
};
|
};
|
||||||
|
|
||||||
"custom/powerprofile" = {
|
"custom/powerprofile" = {
|
||||||
exec = "${powerProfileStatus}";
|
exec = "nomarchy-powerprofile-status";
|
||||||
return-type = "json";
|
return-type = "json";
|
||||||
interval = 5;
|
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;
|
tray.spacing = 8;
|
||||||
@@ -164,11 +209,16 @@ let
|
|||||||
font-weight: bold;
|
font-weight: bold;
|
||||||
}
|
}
|
||||||
|
|
||||||
#tray, #pulseaudio, #network, #cpu, #memory, #custom-powerprofile, #battery {
|
#tray, #pulseaudio, #network, #cpu, #memory, #custom-powerprofile, #language, #battery, #custom-notification {
|
||||||
color: @subtext;
|
color: @subtext;
|
||||||
padding: 0 10px;
|
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; }
|
#pulseaudio.muted { color: @muted; }
|
||||||
#battery.warning { color: @warn; }
|
#battery.warning { color: @warn; }
|
||||||
#battery.critical { color: @bad; }
|
#battery.critical { color: @bad; }
|
||||||
@@ -197,4 +247,9 @@ in
|
|||||||
else generatedStyle
|
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
|
in
|
||||||
{
|
{
|
||||||
imports = [ ./options.nix ./plymouth.nix ./file-manager.nix ./power.nix ];
|
imports = [ ./options.nix ./plymouth.nix ./file-manager.nix ./power.nix ./services.nix ];
|
||||||
|
|
||||||
config = {
|
config = {
|
||||||
# The safe half of distro branding: distroName flows into
|
# The safe half of distro branding: distroName flows into
|
||||||
@@ -123,23 +123,32 @@ in
|
|||||||
|
|
||||||
networking.networkmanager.enable = lib.mkDefault true;
|
networking.networkmanager.enable = lib.mkDefault true;
|
||||||
|
|
||||||
# No double-unlock on hibernate. hypridle locks hyprlock before every
|
# No double-unlock on hibernate. Locking the session before sleep is
|
||||||
# sleep (right for suspend), but a hibernate resume is already gated by
|
# right for suspend (resumes from RAM, no other gate), but an encrypted
|
||||||
# the LUKS passphrase entered at boot — so the user would type a password
|
# hibernate already resumes through the LUKS passphrase — a hyprlock on
|
||||||
# twice. Once we're back from an *encrypted* hibernate, drop the now-
|
# top is a second password. And we can't just drop the lock after the
|
||||||
# redundant hyprlock. Ordered After the hibernate service, so it runs
|
# resume: a Wayland session-lock whose client dies without releasing
|
||||||
# post-resume; pulled in only by hibernate.target (suspend, and the
|
# trips hyprlock's "go to a tty" crash failsafe (the compositor keeps the
|
||||||
# RAM-resume phase of suspend-then-hibernate, stay locked — they have no
|
# screen locked for safety). So don't lock before an encrypted hibernate
|
||||||
# passphrase gate). Gated on LUKS: an unencrypted hibernate keeps its lock.
|
# in the first place. hypridle can't tell suspend from hibernate, hence a
|
||||||
systemd.services.nomarchy-hibernate-unlock =
|
# system unit hooked to the sleep targets: it locks on the RAM-resume
|
||||||
lib.mkIf (builtins.attrNames config.boot.initrd.luks.devices != [ ]) {
|
# sleeps always, and on hibernate only when the disk is unencrypted (no
|
||||||
description = "Dismiss hyprlock after resuming from an encrypted hibernate";
|
# LUKS gate to rely on). Replaces hypridle's old before_sleep_cmd.
|
||||||
after = [ "systemd-hibernate.service" ];
|
systemd.services.nomarchy-lock-before-sleep =
|
||||||
wantedBy = [ "hibernate.target" ];
|
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 = {
|
serviceConfig = {
|
||||||
Type = "oneshot";
|
Type = "oneshot";
|
||||||
# `-`: a missing hyprlock (idle disabled, or not locked) isn't a failure.
|
# Plural: a system unit has no session of its own to lock.
|
||||||
ExecStart = "-${pkgs.procps}/bin/pkill -x hyprlock";
|
ExecStart = "${config.systemd.package}/bin/loginctl lock-sessions";
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -176,7 +185,7 @@ in
|
|||||||
# is a clean no-op rather than a failing timer.
|
# is a clean no-op rather than a failing timer.
|
||||||
services.snapper.configs = lib.mkIf
|
services.snapper.configs = lib.mkIf
|
||||||
(cfg.snapper.enable && (config.fileSystems."/".fsType or "") == "btrfs")
|
(cfg.snapper.enable && (config.fileSystems."/".fsType or "") == "btrfs")
|
||||||
{
|
({
|
||||||
root = {
|
root = {
|
||||||
SUBVOLUME = "/";
|
SUBVOLUME = "/";
|
||||||
TIMELINE_CREATE = true;
|
TIMELINE_CREATE = true;
|
||||||
@@ -187,6 +196,39 @@ in
|
|||||||
TIMELINE_LIMIT_MONTHLY = "0";
|
TIMELINE_LIMIT_MONTHLY = "0";
|
||||||
TIMELINE_LIMIT_YEARLY = "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 ────────────────────────────────────────────────────────
|
# ── Fonts ────────────────────────────────────────────────────────
|
||||||
@@ -276,7 +318,10 @@ in
|
|||||||
--cleanup-algorithm number
|
--cleanup-algorithm number
|
||||||
echo "Rebuilding..."
|
echo "Rebuilding..."
|
||||||
nixos-rebuild switch --flake /etc/nixos#default "$@"
|
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.
|
# Don't let boot entries fill the ESP over the years.
|
||||||
boot.loader.systemd-boot.configurationLimit = lib.mkDefault 10;
|
boot.loader.systemd-boot.configurationLimit = lib.mkDefault 10;
|
||||||
@@ -291,6 +336,11 @@ in
|
|||||||
settings = {
|
settings = {
|
||||||
experimental-features = [ "nix-command" "flakes" ];
|
experimental-features = [ "nix-command" "flakes" ];
|
||||||
auto-optimise-store = lib.mkDefault true;
|
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 = {
|
gc = {
|
||||||
automatic = lib.mkDefault true;
|
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";
|
time.timeZone = "$TIMEZONE";
|
||||||
i18n.defaultLocale = "$LOCALE";
|
i18n.defaultLocale = "$LOCALE";
|
||||||
|
|
||||||
# One keyboard layout everywhere: xkb is the source of truth, the
|
# One keyboard layout everywhere: xkb is the source of truth, and the
|
||||||
# virtual console derives from it (greeter/ttys), and the systemd
|
# distro defaults (console.useXkbConfig + the systemd initrd, set in
|
||||||
# initrd applies it to the LUKS passphrase prompt too (the classic
|
# the nomarchy module) derive the virtual console and the LUKS
|
||||||
# script initrd cannot). The Hyprland session reads the same layout
|
# passphrase prompt from it — so only the chosen layout is written here.
|
||||||
# from nomarchy.keyboard.* in home.nix.
|
# The Hyprland session reads the same layout from nomarchy.keyboard.* in
|
||||||
|
# home.nix.
|
||||||
services.xserver.xkb.layout = "$KB_LAYOUT";
|
services.xserver.xkb.layout = "$KB_LAYOUT";
|
||||||
services.xserver.xkb.variant = "$KB_VARIANT";
|
services.xserver.xkb.variant = "$KB_VARIANT";
|
||||||
console.useXkbConfig = true;
|
|
||||||
boot.initrd.systemd.enable = true;
|
|
||||||
|
|
||||||
# Your login user — \`username\` flows in from flake.nix automatically.
|
# Your login user — \`username\` flows in from flake.nix automatically.
|
||||||
users.users.\${username} = {
|
users.users.\${username} = {
|
||||||
|
|||||||
@@ -5,15 +5,136 @@
|
|||||||
{ pkgs, ... }:
|
{ pkgs, ... }:
|
||||||
|
|
||||||
{
|
{
|
||||||
# Examples:
|
# ── Overrides (the desktop is on by default; tweak or opt out) ──────
|
||||||
# nomarchy.terminal = "kitty"; # swap the default terminal
|
# nomarchy.terminal = "kitty"; # swap the default terminal
|
||||||
# nomarchy.waybar.enable = false; # bring your own bar
|
# nomarchy.waybar.enable = false; # bring your own bar
|
||||||
# nomarchy.stylix.enable = false; # opt out of GTK/Qt theming
|
# nomarchy.stylix.enable = false; # opt out of GTK/Qt theming
|
||||||
# nomarchy.keyboard.layout = "de"; # session keyboard (pair with
|
# nomarchy.keyboard.layout = "de"; # session keyboard (set the matching
|
||||||
# # xkb + console.useXkbConfig in
|
# # services.xserver.xkb.layout in
|
||||||
# # system.nix for tty/LUKS)
|
# # 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; [
|
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
|
# 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" ];
|
extraGroups = [ "wheel" "networkmanager" "video" "input" ];
|
||||||
};
|
};
|
||||||
|
|
||||||
# Examples:
|
# ── Overrides (uncomment to change) ─────────────────────────────────
|
||||||
# nomarchy.system.greeter.enable = false; # bring your own login manager
|
# nomarchy.system.greeter.enable = false; # bring your own login manager
|
||||||
# environment.systemPackages = [ pkgs.htop ];
|
# 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";
|
system.stateVersion = "26.05";
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -29,7 +29,8 @@ window {
|
|||||||
border-color: @yellow;
|
border-color: @yellow;
|
||||||
border-radius: 15px;
|
border-radius: 15px;
|
||||||
width: 40%;
|
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;
|
location: center;
|
||||||
anchor: center;
|
anchor: center;
|
||||||
x-offset: 0;
|
x-offset: 0;
|
||||||
@@ -90,6 +91,12 @@ element {
|
|||||||
spacing: 15px;
|
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 {
|
element-icon {
|
||||||
background-color: transparent;
|
background-color: transparent;
|
||||||
text-color: inherit;
|
text-color: inherit;
|
||||||
|
|||||||
@@ -48,8 +48,10 @@ window#waybar {
|
|||||||
#workspaces,
|
#workspaces,
|
||||||
#pulseaudio,
|
#pulseaudio,
|
||||||
#network,
|
#network,
|
||||||
|
#custom-powerprofile,
|
||||||
#battery,
|
#battery,
|
||||||
#tray,
|
#tray,
|
||||||
|
#custom-notification,
|
||||||
#custom-powermenu {
|
#custom-powermenu {
|
||||||
background-color: @bg0;
|
background-color: @bg0;
|
||||||
color: @fg;
|
color: @fg;
|
||||||
|
|||||||
@@ -11,7 +11,7 @@
|
|||||||
|
|
||||||
"modules-left": ["custom/launcher", "clock", "clock#date"],
|
"modules-left": ["custom/launcher", "clock", "clock#date"],
|
||||||
"modules-center": ["hyprland/workspaces"],
|
"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": {
|
"hyprland/workspaces": {
|
||||||
"disable-scroll": true,
|
"disable-scroll": true,
|
||||||
@@ -80,6 +80,34 @@
|
|||||||
|
|
||||||
"tray": { "spacing": 8 },
|
"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": {
|
"custom/powermenu": {
|
||||||
"format": "",
|
"format": "",
|
||||||
"on-click": "nomarchy-menu power",
|
"on-click": "nomarchy-menu power",
|
||||||
|
|||||||
@@ -29,7 +29,8 @@ window {
|
|||||||
border-color: @yellow;
|
border-color: @yellow;
|
||||||
border-radius: 15px;
|
border-radius: 15px;
|
||||||
width: 40%;
|
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;
|
location: center;
|
||||||
anchor: center;
|
anchor: center;
|
||||||
x-offset: 0;
|
x-offset: 0;
|
||||||
@@ -90,6 +91,12 @@ element {
|
|||||||
spacing: 15px;
|
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 {
|
element-icon {
|
||||||
background-color: transparent;
|
background-color: transparent;
|
||||||
text-color: inherit;
|
text-color: inherit;
|
||||||
|
|||||||
@@ -54,8 +54,10 @@ window#waybar {
|
|||||||
#workspaces,
|
#workspaces,
|
||||||
#pulseaudio,
|
#pulseaudio,
|
||||||
#network,
|
#network,
|
||||||
|
#custom-powerprofile,
|
||||||
#idle_inhibitor,
|
#idle_inhibitor,
|
||||||
#battery,
|
#battery,
|
||||||
|
#custom-notification,
|
||||||
#custom-powermenu {
|
#custom-powermenu {
|
||||||
background-color: @bg0;
|
background-color: @bg0;
|
||||||
color: @fg;
|
color: @fg;
|
||||||
|
|||||||
@@ -11,7 +11,7 @@
|
|||||||
|
|
||||||
"modules-left": ["custom/nomarchy", "clock", "clock#date"],
|
"modules-left": ["custom/nomarchy", "clock", "clock#date"],
|
||||||
"modules-center": ["hyprland/workspaces"],
|
"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": {
|
"hyprland/workspaces": {
|
||||||
"disable-scroll": true,
|
"disable-scroll": true,
|
||||||
@@ -87,6 +87,34 @@
|
|||||||
|
|
||||||
"tray": { "spacing": 8 },
|
"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": {
|
"custom/powermenu": {
|
||||||
"format": "",
|
"format": "",
|
||||||
"on-click": "nomarchy-menu power",
|
"on-click": "nomarchy-menu power",
|
||||||
|
|||||||
Reference in New Issue
Block a user