commit cde5575767d44f9bfdb466004b7c2987931ae705 Author: eriedaberrie Date: Thu Jan 5 12:14:24 2023 -0800 Initial commit Note: not the actual initial commit. I swear I will stop repeatedly force pushing to this single commit eventually ok. diff --git a/assets/CatppuccinQuagsire.png b/assets/CatppuccinQuagsire.png new file mode 100644 index 0000000..977aa6d Binary files /dev/null and b/assets/CatppuccinQuagsire.png differ diff --git a/assets/DannyMyBrother.png b/assets/DannyMyBrother.png new file mode 100644 index 0000000..c817763 Binary files /dev/null and b/assets/DannyMyBrother.png differ diff --git a/assets/DannyMyBrotherNoText.png b/assets/DannyMyBrotherNoText.png new file mode 100644 index 0000000..2b5901e Binary files /dev/null and b/assets/DannyMyBrotherNoText.png differ diff --git a/assets/EmeraldOx.png b/assets/EmeraldOx.png new file mode 100644 index 0000000..76645a7 Binary files /dev/null and b/assets/EmeraldOx.png differ diff --git a/assets/EmeraldOxBlur.png b/assets/EmeraldOxBlur.png new file mode 100644 index 0000000..98a30a7 Binary files /dev/null and b/assets/EmeraldOxBlur.png differ diff --git a/assets/NeonBlack.jpg b/assets/NeonBlack.jpg new file mode 100644 index 0000000..e8628ff Binary files /dev/null and b/assets/NeonBlack.jpg differ diff --git a/assets/NeonColors.jpg b/assets/NeonColors.jpg new file mode 100644 index 0000000..ea03c27 Binary files /dev/null and b/assets/NeonColors.jpg differ diff --git a/assets/kevin-laminto-unsplash-catppuccin-edited.png b/assets/kevin-laminto-unsplash-catppuccin-edited.png new file mode 100644 index 0000000..37c7608 Binary files /dev/null and b/assets/kevin-laminto-unsplash-catppuccin-edited.png differ diff --git a/assets/kevin-laminto-unsplash-catppuccin.png b/assets/kevin-laminto-unsplash-catppuccin.png new file mode 100644 index 0000000..1d1b814 Binary files /dev/null and b/assets/kevin-laminto-unsplash-catppuccin.png differ diff --git a/assets/nerd.png b/assets/nerd.png new file mode 100644 index 0000000..fb96431 Binary files /dev/null and b/assets/nerd.png differ diff --git a/assets/pexels-artem-lysenko-catppuccin.jpg b/assets/pexels-artem-lysenko-catppuccin.jpg new file mode 100644 index 0000000..af98e86 Binary files /dev/null and b/assets/pexels-artem-lysenko-catppuccin.jpg differ diff --git a/assets/pexels-stephan-seeber.jpg b/assets/pexels-stephan-seeber.jpg new file mode 100644 index 0000000..a1d7ccd Binary files /dev/null and b/assets/pexels-stephan-seeber.jpg differ diff --git a/assets/pointingSoyjaks.png b/assets/pointingSoyjaks.png new file mode 100644 index 0000000..6d2f963 Binary files /dev/null and b/assets/pointingSoyjaks.png differ diff --git a/assets/quag-head.png b/assets/quag-head.png new file mode 100644 index 0000000..ae1292b Binary files /dev/null and b/assets/quag-head.png differ diff --git a/assets/searxng.svg b/assets/searxng.svg new file mode 100644 index 0000000..2624145 --- /dev/null +++ b/assets/searxng.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/assets/snowyMountain.jpg b/assets/snowyMountain.jpg new file mode 100644 index 0000000..c5f5bd9 Binary files /dev/null and b/assets/snowyMountain.jpg differ diff --git a/flake.lock b/flake.lock new file mode 100644 index 0000000..257371e --- /dev/null +++ b/flake.lock @@ -0,0 +1,1092 @@ +{ + "nodes": { + "agenix": { + "inputs": { + "darwin": "darwin", + "home-manager": "home-manager", + "nixpkgs": [ + "nixpkgs" + ], + "systems": "systems" + }, + "locked": { + "lastModified": 1723293904, + "narHash": "sha256-b+uqzj+Wa6xgMS9aNbX4I+sXeb5biPDi39VgvSFqFvU=", + "owner": "ryantm", + "repo": "agenix", + "rev": "f6291c5935fdc4e0bef208cfc0dcab7e3f7a1c41", + "type": "github" + }, + "original": { + "owner": "ryantm", + "repo": "agenix", + "type": "github" + } + }, + "aquamarine": { + "inputs": { + "hyprutils": [ + "hyprland", + "hyprutils" + ], + "hyprwayland-scanner": [ + "hyprland", + "hyprwayland-scanner" + ], + "nixpkgs": [ + "hyprland", + "nixpkgs" + ], + "systems": [ + "hyprland", + "systems" + ] + }, + "locked": { + "lastModified": 1724781866, + "narHash": "sha256-ItgACCJCwn8Rx7p8hJBpnU9eCtrdmkg4AbqMZL/rXlY=", + "owner": "hyprwm", + "repo": "aquamarine", + "rev": "7cc3d3179c06caf3769afb3eb0c69aa55676c96a", + "type": "github" + }, + "original": { + "owner": "hyprwm", + "repo": "aquamarine", + "type": "github" + } + }, + "cl-hyprland-ipc": { + "inputs": { + "nixpkgs": [ + "nixpkgs" + ], + "systems": "systems_2" + }, + "locked": { + "lastModified": 1719084187, + "narHash": "sha256-CPDgaFwExL5v7Y0IL6ID/wh9M7A0lGKOh1NS2CoglRM=", + "owner": "eriedaberrie", + "repo": "cl-hyprland-ipc", + "rev": "5be47ac54bf6ce9e6ff0948d2933ab8590d19db7", + "type": "github" + }, + "original": { + "owner": "eriedaberrie", + "repo": "cl-hyprland-ipc", + "type": "github" + } + }, + "crane": { + "inputs": { + "nixpkgs": [ + "lanzaboote", + "nixpkgs" + ] + }, + "locked": { + "lastModified": 1721842668, + "narHash": "sha256-k3oiD2z2AAwBFLa4+xfU+7G5fisRXfkvrMTCJrjZzXo=", + "owner": "ipetkov", + "repo": "crane", + "rev": "529c1a0b1f29f0d78fa3086b8f6a134c71ef3aaf", + "type": "github" + }, + "original": { + "owner": "ipetkov", + "repo": "crane", + "type": "github" + } + }, + "darwin": { + "inputs": { + "nixpkgs": [ + "agenix", + "nixpkgs" + ] + }, + "locked": { + "lastModified": 1700795494, + "narHash": "sha256-gzGLZSiOhf155FW7262kdHo2YDeugp3VuIFb4/GGng0=", + "owner": "lnl7", + "repo": "nix-darwin", + "rev": "4b9b83d5a92e8c1fbfd8eb27eda375908c11ec4d", + "type": "github" + }, + "original": { + "owner": "lnl7", + "ref": "master", + "repo": "nix-darwin", + "type": "github" + } + }, + "emacs-overlay": { + "inputs": { + "flake-utils": "flake-utils", + "nixpkgs": [ + "nixpkgs" + ], + "nixpkgs-stable": "nixpkgs-stable" + }, + "locked": { + "lastModified": 1724864303, + "narHash": "sha256-sqMEzW/hXisyiXUg62tm9YAHxhIIGHy23B2HM+WzxMY=", + "owner": "nix-community", + "repo": "emacs-overlay", + "rev": "fa49f2ee0f6b1567b03643f6378ec18e3c4aed8d", + "type": "github" + }, + "original": { + "owner": "nix-community", + "repo": "emacs-overlay", + "type": "github" + } + }, + "flake-compat": { + "flake": false, + "locked": { + "lastModified": 1696426674, + "narHash": "sha256-kvjfFW7WAETZlt09AgDn1MrtKzP7t90Vf7vypd3OL1U=", + "owner": "edolstra", + "repo": "flake-compat", + "rev": "0f9255e01c2351cc7d116c072cb317785dd33b33", + "type": "github" + }, + "original": { + "owner": "edolstra", + "repo": "flake-compat", + "type": "github" + } + }, + "flake-parts": { + "inputs": { + "nixpkgs-lib": [ + "lanzaboote", + "nixpkgs" + ] + }, + "locked": { + "lastModified": 1719994518, + "narHash": "sha256-pQMhCCHyQGRzdfAkdJ4cIWiw+JNuWsTX7f0ZYSyz0VY=", + "owner": "hercules-ci", + "repo": "flake-parts", + "rev": "9227223f6d922fee3c7b190b2cc238a99527bbb7", + "type": "github" + }, + "original": { + "owner": "hercules-ci", + "repo": "flake-parts", + "type": "github" + } + }, + "flake-parts_2": { + "inputs": { + "nixpkgs-lib": "nixpkgs-lib" + }, + "locked": { + "lastModified": 1722555600, + "narHash": "sha256-XOQkdLafnb/p9ij77byFQjDf5m5QYl9b2REiVClC+x4=", + "owner": "hercules-ci", + "repo": "flake-parts", + "rev": "8471fe90ad337a8074e957b69ca4d0089218391d", + "type": "github" + }, + "original": { + "owner": "hercules-ci", + "repo": "flake-parts", + "type": "github" + } + }, + "flake-utils": { + "inputs": { + "systems": "systems_3" + }, + "locked": { + "lastModified": 1710146030, + "narHash": "sha256-SZ5L6eA7HJ/nmkzGG7/ISclqe6oZdOZTNoesiInkXPQ=", + "owner": "numtide", + "repo": "flake-utils", + "rev": "b1d9ab70662946ef0850d488da1c9019f3a9752a", + "type": "github" + }, + "original": { + "owner": "numtide", + "repo": "flake-utils", + "type": "github" + } + }, + "flake-utils_2": { + "inputs": { + "systems": "systems_8" + }, + "locked": { + "lastModified": 1685518550, + "narHash": "sha256-o2d0KcvaXzTrPRIo0kOLV0/QXHhDQ5DTi+OxcjO8xqY=", + "owner": "numtide", + "repo": "flake-utils", + "rev": "a1720a10a6cfe8234c0e93907ffe81be440f4cef", + "type": "github" + }, + "original": { + "owner": "numtide", + "repo": "flake-utils", + "type": "github" + } + }, + "gitignore": { + "inputs": { + "nixpkgs": [ + "lanzaboote", + "pre-commit-hooks-nix", + "nixpkgs" + ] + }, + "locked": { + "lastModified": 1709087332, + "narHash": "sha256-HG2cCnktfHsKV0s4XW83gU3F57gaTljL9KNSuG6bnQs=", + "owner": "hercules-ci", + "repo": "gitignore.nix", + "rev": "637db329424fd7e46cf4185293b9cc8c88c95394", + "type": "github" + }, + "original": { + "owner": "hercules-ci", + "repo": "gitignore.nix", + "type": "github" + } + }, + "grim-hyprland": { + "inputs": { + "nixpkgs": [ + "nixpkgs" + ], + "systems": "systems_4" + }, + "locked": { + "lastModified": 1715315063, + "narHash": "sha256-TV+eQjZhV3ootsupQpj8SLo9pS502gnMwWmldiWmyY4=", + "owner": "eriedaberrie", + "repo": "grim-hyprland", + "rev": "e09bff076bdceae7695d5cc768935d5ce3ac460f", + "type": "github" + }, + "original": { + "owner": "eriedaberrie", + "repo": "grim-hyprland", + "type": "github" + } + }, + "home-manager": { + "inputs": { + "nixpkgs": [ + "agenix", + "nixpkgs" + ] + }, + "locked": { + "lastModified": 1703113217, + "narHash": "sha256-7ulcXOk63TIT2lVDSExj7XzFx09LpdSAPtvgtM7yQPE=", + "owner": "nix-community", + "repo": "home-manager", + "rev": "3bfaacf46133c037bb356193bd2f1765d9dc82c1", + "type": "github" + }, + "original": { + "owner": "nix-community", + "repo": "home-manager", + "type": "github" + } + }, + "home-manager_2": { + "inputs": { + "nixpkgs": [ + "nixpkgs" + ] + }, + "locked": { + "lastModified": 1724435763, + "narHash": "sha256-UNky3lJNGQtUEXT2OY8gMxejakSWPTfWKvpFkpFlAfM=", + "owner": "nix-community", + "repo": "home-manager", + "rev": "c2cd2a52e02f1dfa1c88f95abeb89298d46023be", + "type": "github" + }, + "original": { + "owner": "nix-community", + "repo": "home-manager", + "type": "github" + } + }, + "hyprcursor": { + "inputs": { + "hyprlang": [ + "hyprland", + "hyprlang" + ], + "nixpkgs": [ + "hyprland", + "nixpkgs" + ], + "systems": [ + "hyprland", + "systems" + ] + }, + "locked": { + "lastModified": 1722623071, + "narHash": "sha256-sLADpVgebpCBFXkA1FlCXtvEPu1tdEsTfqK1hfeHySE=", + "owner": "hyprwm", + "repo": "hyprcursor", + "rev": "912d56025f03d41b1ad29510c423757b4379eb1c", + "type": "github" + }, + "original": { + "owner": "hyprwm", + "repo": "hyprcursor", + "type": "github" + } + }, + "hyprland": { + "inputs": { + "aquamarine": "aquamarine", + "hyprcursor": "hyprcursor", + "hyprlang": "hyprlang", + "hyprutils": "hyprutils", + "hyprwayland-scanner": "hyprwayland-scanner", + "nixpkgs": "nixpkgs", + "systems": "systems_5", + "xdph": [ + "xdph" + ] + }, + "locked": { + "lastModified": 1724850433, + "narHash": "sha256-WSjYdnlg6Qq0xrjCgL/WJ7a+kEWQtQmYrw0TV4ykppY=", + "ref": "refs/heads/main", + "rev": "98e99cd03df5b4421f72f2a3f2d7de53f8261f1f", + "revCount": 5152, + "submodules": true, + "type": "git", + "url": "https://github.com/hyprwm/Hyprland" + }, + "original": { + "submodules": true, + "type": "git", + "url": "https://github.com/hyprwm/Hyprland" + } + }, + "hyprland-protocols": { + "inputs": { + "nixpkgs": [ + "xdph", + "nixpkgs" + ], + "systems": [ + "xdph", + "systems" + ] + }, + "locked": { + "lastModified": 1721326555, + "narHash": "sha256-zCu4R0CSHEactW9JqYki26gy8h9f6rHmSwj4XJmlHgg=", + "owner": "hyprwm", + "repo": "hyprland-protocols", + "rev": "5a11232266bf1a1f5952d5b179c3f4b2facaaa84", + "type": "github" + }, + "original": { + "owner": "hyprwm", + "repo": "hyprland-protocols", + "type": "github" + } + }, + "hyprlang": { + "inputs": { + "hyprutils": [ + "hyprland", + "hyprutils" + ], + "nixpkgs": [ + "hyprland", + "nixpkgs" + ], + "systems": [ + "hyprland", + "systems" + ] + }, + "locked": { + "lastModified": 1724174162, + "narHash": "sha256-fOOBLwil6M9QWMCiSULwjMQzrXhHXUnEqmjHX5ZHeVI=", + "owner": "hyprwm", + "repo": "hyprlang", + "rev": "16e5c9465f04477d8a3dd48a0a26bf437986336c", + "type": "github" + }, + "original": { + "owner": "hyprwm", + "repo": "hyprlang", + "type": "github" + } + }, + "hyprlang_2": { + "inputs": { + "hyprutils": [ + "hyprlock", + "hyprutils" + ], + "nixpkgs": [ + "hyprlock", + "nixpkgs" + ], + "systems": [ + "hyprlock", + "systems" + ] + }, + "locked": { + "lastModified": 1721324361, + "narHash": "sha256-BiJKO0IIdnSwHQBSrEJlKlFr753urkLE48wtt0UhNG4=", + "owner": "hyprwm", + "repo": "hyprlang", + "rev": "adbefbf49664a6c2c8bf36b6487fd31e3eb68086", + "type": "github" + }, + "original": { + "owner": "hyprwm", + "repo": "hyprlang", + "type": "github" + } + }, + "hyprlang_3": { + "inputs": { + "hyprutils": "hyprutils_3", + "nixpkgs": [ + "xdph", + "nixpkgs" + ], + "systems": "systems_9" + }, + "locked": { + "lastModified": 1721324361, + "narHash": "sha256-BiJKO0IIdnSwHQBSrEJlKlFr753urkLE48wtt0UhNG4=", + "owner": "hyprwm", + "repo": "hyprlang", + "rev": "adbefbf49664a6c2c8bf36b6487fd31e3eb68086", + "type": "github" + }, + "original": { + "owner": "hyprwm", + "repo": "hyprlang", + "type": "github" + } + }, + "hyprlock": { + "inputs": { + "hyprlang": "hyprlang_2", + "hyprutils": "hyprutils_2", + "nixpkgs": [ + "nixpkgs" + ], + "systems": "systems_6" + }, + "locked": { + "lastModified": 1724235914, + "narHash": "sha256-QEVuZNXkytS1lqAtRMBAriJREcCTOeprxBTisXxpe3s=", + "owner": "hyprwm", + "repo": "hyprlock", + "rev": "7bb4113a7e9cb62120e96d7c81066f0c055f0db4", + "type": "github" + }, + "original": { + "owner": "hyprwm", + "repo": "hyprlock", + "type": "github" + } + }, + "hyprutils": { + "inputs": { + "nixpkgs": [ + "hyprland", + "nixpkgs" + ], + "systems": [ + "hyprland", + "systems" + ] + }, + "locked": { + "lastModified": 1722869141, + "narHash": "sha256-0KU4qhyMp441qfwbirNg3+wbm489KnEjXOz2I/RbeFs=", + "owner": "hyprwm", + "repo": "hyprutils", + "rev": "0252fd13e78e60fb0da512a212e56007515a49f7", + "type": "github" + }, + "original": { + "owner": "hyprwm", + "repo": "hyprutils", + "type": "github" + } + }, + "hyprutils_2": { + "inputs": { + "nixpkgs": [ + "hyprlock", + "nixpkgs" + ], + "systems": [ + "hyprlock", + "systems" + ] + }, + "locked": { + "lastModified": 1721324102, + "narHash": "sha256-WAZ0X6yJW1hFG6otkHBfyJDKRpNP5stsRqdEuHrFRpk=", + "owner": "hyprwm", + "repo": "hyprutils", + "rev": "962582a090bc233c4de9d9897f46794280288989", + "type": "github" + }, + "original": { + "owner": "hyprwm", + "repo": "hyprutils", + "type": "github" + } + }, + "hyprutils_3": { + "inputs": { + "nixpkgs": [ + "xdph", + "hyprlang", + "nixpkgs" + ], + "systems": [ + "xdph", + "hyprlang", + "systems" + ] + }, + "locked": { + "lastModified": 1721324102, + "narHash": "sha256-WAZ0X6yJW1hFG6otkHBfyJDKRpNP5stsRqdEuHrFRpk=", + "owner": "hyprwm", + "repo": "hyprutils", + "rev": "962582a090bc233c4de9d9897f46794280288989", + "type": "github" + }, + "original": { + "owner": "hyprwm", + "repo": "hyprutils", + "type": "github" + } + }, + "hyprwayland-scanner": { + "inputs": { + "nixpkgs": [ + "hyprland", + "nixpkgs" + ], + "systems": [ + "hyprland", + "systems" + ] + }, + "locked": { + "lastModified": 1721324119, + "narHash": "sha256-SOOqIT27/X792+vsLSeFdrNTF+OSRp5qXv6Te+fb2Qg=", + "owner": "hyprwm", + "repo": "hyprwayland-scanner", + "rev": "a048a6cb015340bd82f97c1f40a4b595ca85cc30", + "type": "github" + }, + "original": { + "owner": "hyprwm", + "repo": "hyprwayland-scanner", + "type": "github" + } + }, + "lanzaboote": { + "inputs": { + "crane": "crane", + "flake-compat": "flake-compat", + "flake-parts": "flake-parts", + "nixpkgs": [ + "nixpkgs" + ], + "pre-commit-hooks-nix": "pre-commit-hooks-nix", + "rust-overlay": "rust-overlay" + }, + "locked": { + "lastModified": 1722329086, + "narHash": "sha256-e/fSi0WER06N8WCvpht62fkGtWfe5ckDxr6zNYkwkFw=", + "owner": "nix-community", + "repo": "lanzaboote", + "rev": "f5a3a7dff44d131807fc1a89fbd8576cd870334a", + "type": "github" + }, + "original": { + "owner": "nix-community", + "repo": "lanzaboote", + "type": "github" + } + }, + "my-nix-packages": { + "inputs": { + "nixpkgs": [ + "nixpkgs" + ], + "systems": "systems_7" + }, + "locked": { + "lastModified": 1722969852, + "narHash": "sha256-Jj06z6QjdC2lJYnnchNFfR+hECvzzlP0xIw8TSjLL8Q=", + "owner": "eriedaberrie", + "repo": "my-nix-packages", + "rev": "2c6cdbf2c5a4f9dcfc8a68a2b51868e2535bcb9d", + "type": "github" + }, + "original": { + "owner": "eriedaberrie", + "repo": "my-nix-packages", + "type": "github" + } + }, + "nix-gaming": { + "inputs": { + "flake-parts": "flake-parts_2", + "nixpkgs": "nixpkgs_2", + "umu": "umu" + }, + "locked": { + "lastModified": 1724549799, + "narHash": "sha256-F4lN1qmMJpJALwZ2ENb6MDSXG40om7ktZyAt7yh/DS8=", + "owner": "fufexan", + "repo": "nix-gaming", + "rev": "963803d3be8ed721b21326804513dec884e9d494", + "type": "github" + }, + "original": { + "owner": "fufexan", + "repo": "nix-gaming", + "type": "github" + } + }, + "nix-index-database": { + "inputs": { + "nixpkgs": [ + "nixpkgs" + ] + }, + "locked": { + "lastModified": 1724576102, + "narHash": "sha256-uM7n5nNL6fmA0bwMJBNll11f4cMWOFa2Ni6F5KeIldM=", + "owner": "nix-community", + "repo": "nix-index-database", + "rev": "e333d62b70b179da1dd78d94315e8a390f2d12e5", + "type": "github" + }, + "original": { + "owner": "nix-community", + "repo": "nix-index-database", + "type": "github" + } + }, + "nixpkgs": { + "locked": { + "lastModified": 1724224976, + "narHash": "sha256-Z/ELQhrSd7bMzTO8r7NZgi9g5emh+aRKoCdaAv5fiO0=", + "owner": "NixOS", + "repo": "nixpkgs", + "rev": "c374d94f1536013ca8e92341b540eba4c22f9c62", + "type": "github" + }, + "original": { + "owner": "NixOS", + "ref": "nixos-unstable", + "repo": "nixpkgs", + "type": "github" + } + }, + "nixpkgs-lib": { + "locked": { + "lastModified": 1722555339, + "narHash": "sha256-uFf2QeW7eAHlYXuDktm9c25OxOyCoUOQmh5SZ9amE5Q=", + "type": "tarball", + "url": "https://github.com/NixOS/nixpkgs/archive/a5d394176e64ab29c852d03346c1fc9b0b7d33eb.tar.gz" + }, + "original": { + "type": "tarball", + "url": "https://github.com/NixOS/nixpkgs/archive/a5d394176e64ab29c852d03346c1fc9b0b7d33eb.tar.gz" + } + }, + "nixpkgs-stable": { + "locked": { + "lastModified": 1724531977, + "narHash": "sha256-XROVLf9ti4rrNCFLr+DmXRZtPjCQTW4cYy59owTEmxk=", + "owner": "NixOS", + "repo": "nixpkgs", + "rev": "2527da1ef492c495d5391f3bcf9c1dd9f4514e32", + "type": "github" + }, + "original": { + "owner": "NixOS", + "ref": "nixos-24.05", + "repo": "nixpkgs", + "type": "github" + } + }, + "nixpkgs-stable_2": { + "locked": { + "lastModified": 1720386169, + "narHash": "sha256-NGKVY4PjzwAa4upkGtAMz1npHGoRzWotlSnVlqI40mo=", + "owner": "NixOS", + "repo": "nixpkgs", + "rev": "194846768975b7ad2c4988bdb82572c00222c0d7", + "type": "github" + }, + "original": { + "owner": "NixOS", + "ref": "nixos-24.05", + "repo": "nixpkgs", + "type": "github" + } + }, + "nixpkgs-stable_3": { + "locked": { + "lastModified": 1720535198, + "narHash": "sha256-zwVvxrdIzralnSbcpghA92tWu2DV2lwv89xZc8MTrbg=", + "owner": "NixOS", + "repo": "nixpkgs", + "rev": "205fd4226592cc83fd4c0885a3e4c9c400efabb5", + "type": "github" + }, + "original": { + "owner": "NixOS", + "ref": "nixos-23.11", + "repo": "nixpkgs", + "type": "github" + } + }, + "nixpkgs_2": { + "locked": { + "lastModified": 1724395761, + "narHash": "sha256-zRkDV/nbrnp3Y8oCADf5ETl1sDrdmAW6/bBVJ8EbIdQ=", + "owner": "NixOS", + "repo": "nixpkgs", + "rev": "ae815cee91b417be55d43781eb4b73ae1ecc396c", + "type": "github" + }, + "original": { + "owner": "NixOS", + "ref": "nixpkgs-unstable", + "repo": "nixpkgs", + "type": "github" + } + }, + "nixpkgs_3": { + "locked": { + "lastModified": 1724479785, + "narHash": "sha256-pP3Azj5d6M5nmG68Fu4JqZmdGt4S4vqI5f8te+E/FTw=", + "owner": "NixOS", + "repo": "nixpkgs", + "rev": "d0e1602ddde669d5beb01aec49d71a51937ed7be", + "type": "github" + }, + "original": { + "owner": "NixOS", + "ref": "nixos-unstable", + "repo": "nixpkgs", + "type": "github" + } + }, + "pre-commit-hooks-nix": { + "inputs": { + "flake-compat": [ + "lanzaboote", + "flake-compat" + ], + "gitignore": "gitignore", + "nixpkgs": [ + "lanzaboote", + "nixpkgs" + ], + "nixpkgs-stable": "nixpkgs-stable_2" + }, + "locked": { + "lastModified": 1721042469, + "narHash": "sha256-6FPUl7HVtvRHCCBQne7Ylp4p+dpP3P/OYuzjztZ4s70=", + "owner": "cachix", + "repo": "pre-commit-hooks.nix", + "rev": "f451c19376071a90d8c58ab1a953c6e9840527fd", + "type": "github" + }, + "original": { + "owner": "cachix", + "repo": "pre-commit-hooks.nix", + "type": "github" + } + }, + "root": { + "inputs": { + "agenix": "agenix", + "cl-hyprland-ipc": "cl-hyprland-ipc", + "emacs-overlay": "emacs-overlay", + "grim-hyprland": "grim-hyprland", + "home-manager": "home-manager_2", + "hyprland": "hyprland", + "hyprlock": "hyprlock", + "lanzaboote": "lanzaboote", + "my-nix-packages": "my-nix-packages", + "nix-gaming": "nix-gaming", + "nix-index-database": "nix-index-database", + "nixpkgs": "nixpkgs_3", + "nixpkgs-stable": "nixpkgs-stable_3", + "spicetify-nix": "spicetify-nix", + "xdph": "xdph" + } + }, + "rust-overlay": { + "inputs": { + "nixpkgs": [ + "lanzaboote", + "nixpkgs" + ] + }, + "locked": { + "lastModified": 1722219664, + "narHash": "sha256-xMOJ+HW4yj6e69PvieohUJ3dBSdgCfvI0nnCEe6/yVc=", + "owner": "oxalica", + "repo": "rust-overlay", + "rev": "a6fbda5d9a14fb5f7c69b8489d24afeb349c7bb4", + "type": "github" + }, + "original": { + "owner": "oxalica", + "repo": "rust-overlay", + "type": "github" + } + }, + "spicetify-nix": { + "inputs": { + "flake-utils": "flake-utils_2", + "nixpkgs": [ + "nixpkgs" + ] + }, + "locked": { + "lastModified": 1704167711, + "narHash": "sha256-kFDq+kf/Di/P8bq5sUP8pVwRkrSVrABksBjMPmLic3s=", + "owner": "the-argus", + "repo": "spicetify-nix", + "rev": "1325416f951d6a82cfddb1289864ad782e2b87c4", + "type": "github" + }, + "original": { + "owner": "the-argus", + "repo": "spicetify-nix", + "type": "github" + } + }, + "systems": { + "locked": { + "lastModified": 1681028828, + "narHash": "sha256-Vy1rq5AaRuLzOxct8nz4T6wlgyUR7zLU309k9mBC768=", + "owner": "nix-systems", + "repo": "default", + "rev": "da67096a3b9bf56a91d16901293e51ba5b49a27e", + "type": "github" + }, + "original": { + "owner": "nix-systems", + "repo": "default", + "type": "github" + } + }, + "systems_10": { + "locked": { + "lastModified": 1689347949, + "narHash": "sha256-12tWmuL2zgBgZkdoB6qXZsgJEH9LR3oUgpaQq2RbI80=", + "owner": "nix-systems", + "repo": "default-linux", + "rev": "31732fcf5e8fea42e59c2488ad31a0e651500f68", + "type": "github" + }, + "original": { + "owner": "nix-systems", + "repo": "default-linux", + "type": "github" + } + }, + "systems_2": { + "locked": { + "lastModified": 1689347949, + "narHash": "sha256-12tWmuL2zgBgZkdoB6qXZsgJEH9LR3oUgpaQq2RbI80=", + "owner": "nix-systems", + "repo": "default-linux", + "rev": "31732fcf5e8fea42e59c2488ad31a0e651500f68", + "type": "github" + }, + "original": { + "owner": "nix-systems", + "repo": "default-linux", + "type": "github" + } + }, + "systems_3": { + "locked": { + "lastModified": 1681028828, + "narHash": "sha256-Vy1rq5AaRuLzOxct8nz4T6wlgyUR7zLU309k9mBC768=", + "owner": "nix-systems", + "repo": "default", + "rev": "da67096a3b9bf56a91d16901293e51ba5b49a27e", + "type": "github" + }, + "original": { + "owner": "nix-systems", + "repo": "default", + "type": "github" + } + }, + "systems_4": { + "locked": { + "lastModified": 1689347949, + "narHash": "sha256-12tWmuL2zgBgZkdoB6qXZsgJEH9LR3oUgpaQq2RbI80=", + "owner": "nix-systems", + "repo": "default-linux", + "rev": "31732fcf5e8fea42e59c2488ad31a0e651500f68", + "type": "github" + }, + "original": { + "owner": "nix-systems", + "repo": "default-linux", + "type": "github" + } + }, + "systems_5": { + "locked": { + "lastModified": 1689347949, + "narHash": "sha256-12tWmuL2zgBgZkdoB6qXZsgJEH9LR3oUgpaQq2RbI80=", + "owner": "nix-systems", + "repo": "default-linux", + "rev": "31732fcf5e8fea42e59c2488ad31a0e651500f68", + "type": "github" + }, + "original": { + "owner": "nix-systems", + "repo": "default-linux", + "type": "github" + } + }, + "systems_6": { + "locked": { + "lastModified": 1689347949, + "narHash": "sha256-12tWmuL2zgBgZkdoB6qXZsgJEH9LR3oUgpaQq2RbI80=", + "owner": "nix-systems", + "repo": "default-linux", + "rev": "31732fcf5e8fea42e59c2488ad31a0e651500f68", + "type": "github" + }, + "original": { + "owner": "nix-systems", + "repo": "default-linux", + "type": "github" + } + }, + "systems_7": { + "locked": { + "lastModified": 1689347949, + "narHash": "sha256-12tWmuL2zgBgZkdoB6qXZsgJEH9LR3oUgpaQq2RbI80=", + "owner": "nix-systems", + "repo": "default-linux", + "rev": "31732fcf5e8fea42e59c2488ad31a0e651500f68", + "type": "github" + }, + "original": { + "owner": "nix-systems", + "repo": "default-linux", + "type": "github" + } + }, + "systems_8": { + "locked": { + "lastModified": 1681028828, + "narHash": "sha256-Vy1rq5AaRuLzOxct8nz4T6wlgyUR7zLU309k9mBC768=", + "owner": "nix-systems", + "repo": "default", + "rev": "da67096a3b9bf56a91d16901293e51ba5b49a27e", + "type": "github" + }, + "original": { + "owner": "nix-systems", + "repo": "default", + "type": "github" + } + }, + "systems_9": { + "locked": { + "lastModified": 1689347949, + "narHash": "sha256-12tWmuL2zgBgZkdoB6qXZsgJEH9LR3oUgpaQq2RbI80=", + "owner": "nix-systems", + "repo": "default-linux", + "rev": "31732fcf5e8fea42e59c2488ad31a0e651500f68", + "type": "github" + }, + "original": { + "owner": "nix-systems", + "repo": "default-linux", + "type": "github" + } + }, + "umu": { + "inputs": { + "nixpkgs": [ + "nix-gaming", + "nixpkgs" + ] + }, + "locked": { + "dir": "packaging/nix", + "lastModified": 1724179424, + "narHash": "sha256-2r2y1p9YQuaWCxuFj45MVRqJ/uWglhzY5O9BW1jRXcg=", + "ref": "refs/heads/main", + "rev": "dd3105e4ceef83bdc9d7437139f9475325e2a66d", + "revCount": 700, + "submodules": true, + "type": "git", + "url": "https://github.com/Open-Wine-Components/umu-launcher/?dir=packaging/nix" + }, + "original": { + "dir": "packaging/nix", + "submodules": true, + "type": "git", + "url": "https://github.com/Open-Wine-Components/umu-launcher/?dir=packaging/nix" + } + }, + "xdph": { + "inputs": { + "hyprland-protocols": "hyprland-protocols", + "hyprlang": "hyprlang_3", + "nixpkgs": [ + "nixpkgs" + ], + "systems": "systems_10" + }, + "locked": { + "lastModified": 1724073926, + "narHash": "sha256-nWlUL43jOFHf+KW6Hqrx+W/r1XdXuDyb0wC/SrHsOu4=", + "owner": "hyprwm", + "repo": "xdg-desktop-portal-hyprland", + "rev": "a08ecbbf33598924e93542f737fc6169a26b481e", + "type": "github" + }, + "original": { + "owner": "hyprwm", + "repo": "xdg-desktop-portal-hyprland", + "type": "github" + } + } + }, + "root": "root", + "version": 7 +} diff --git a/flake.nix b/flake.nix new file mode 100644 index 0000000..d222194 --- /dev/null +++ b/flake.nix @@ -0,0 +1,80 @@ +# Nixos System Configuration +{ + description = "Modules and configuration for my NixOS system"; + + inputs = { + nixpkgs.url = "github:NixOS/nixpkgs/nixos-unstable"; + nixpkgs-stable.url = "github:NixOS/nixpkgs/nixos-23.11"; + my-nix-packages = { + url = "github:eriedaberrie/my-nix-packages"; + inputs.nixpkgs.follows = "nixpkgs"; + }; + nix-index-database = { + url = "github:nix-community/nix-index-database"; + inputs.nixpkgs.follows = "nixpkgs"; + }; + home-manager = { + url = "github:nix-community/home-manager"; + inputs.nixpkgs.follows = "nixpkgs"; + }; + lanzaboote = { + url = "github:nix-community/lanzaboote"; + inputs.nixpkgs.follows = "nixpkgs"; + }; + cl-hyprland-ipc = { + url = "github:eriedaberrie/cl-hyprland-ipc"; + inputs.nixpkgs.follows = "nixpkgs"; + }; + # nur.url = github:nix-community/NUR; + xdph = { + url = "github:hyprwm/xdg-desktop-portal-hyprland"; + inputs.nixpkgs.follows = "nixpkgs"; + }; + hyprland = { + url = "git+https://github.com/hyprwm/Hyprland?submodules=1"; + inputs.xdph.follows = "xdph"; + }; + hyprlock = { + url = "github:hyprwm/hyprlock"; + inputs.nixpkgs.follows = "nixpkgs"; + }; + emacs-overlay = { + url = "github:nix-community/emacs-overlay"; + inputs.nixpkgs.follows = "nixpkgs"; + }; + agenix = { + url = "github:ryantm/agenix"; + inputs.nixpkgs.follows = "nixpkgs"; + }; + grim-hyprland = { + url = "github:eriedaberrie/grim-hyprland"; + inputs.nixpkgs.follows = "nixpkgs"; + }; + spicetify-nix = { + url = "github:the-argus/spicetify-nix"; + inputs.nixpkgs.follows = "nixpkgs"; + }; + nix-gaming.url = "github:fufexan/nix-gaming"; + }; + + outputs = inputs: { + nixosConfigurations = import ./hosts inputs; + lib = import ./lib inputs; + + homeManagerModules.default = import ./modules/home; + nixosModules.default = import ./modules/os; + }; + + nixConfig = { + extra-substituters = [ + "https://nix-community.cachix.org" + "https://hyprland.cachix.org" + "https://nix-gaming.cachix.org" + ]; + extra-trusted-public-keys = [ + "nix-community.cachix.org-1:mB9FSh9qf2dCimDSUo8Zy7bkq5CX+/rkCWyvRCYg3Fs=" + "hyprland.cachix.org-1:a7pgxzMz7+chwVL3/pzj6jIBMioiJM7ypFP8PwtkuGc=" + "nix-gaming.cachix.org-1:nbjlureqMbRAxR1gJ/f3hxemL9svXaZF/Ees8vCUUs4=" + ]; + }; +} diff --git a/hosts/default.nix b/hosts/default.nix new file mode 100644 index 0000000..975d2d2 --- /dev/null +++ b/hosts/default.nix @@ -0,0 +1,15 @@ +{ self, ... }: + +self.lib.mkSystems { + + msft-laptop = { + system = "x86_64-linux"; + module = ./msft-laptop; + }; + + groceries = { + system = "x86_64-linux"; + module = ./groceries; + }; + +} diff --git a/hosts/groceries/default.nix b/hosts/groceries/default.nix new file mode 100644 index 0000000..be9439e --- /dev/null +++ b/hosts/groceries/default.nix @@ -0,0 +1,89 @@ +{ pkgs, config, ... }: + +{ + imports = [ + ./services + ./hardware-configuration.nix + ]; + + time.timeZone = "America/Los_Angeles"; + + my = { + user = { + username = "serverie"; + homeModule = ./home; + }; + + fs.bootPartition = false; + + zram.writebackDevice = "/dev/sdb"; + + cli.fish.enable = true; + }; + + boot = { + initrd.availableKernelModules = [ + "virtio_pci" + "virtio_scsi" + "ahci" + "sd_mod" + ]; + + kernelParams = [ "console=ttyS0,19200n8" ]; + kernelModules = [ "virtio_net" ]; + + loader = { + timeout = 10; + grub = { + enable = true; + forceInstall = true; + device = "nodev"; + extraConfig = '' + serial --speed=19200 --unit=0 --word=8 --parity=no --stop=1; + terminal_input serial; + terminal_output serial + ''; + }; + }; + }; + + networking = { + usePredictableInterfaceNames = false; + useDHCP = false; + interfaces.eth0 = { + useDHCP = true; + tempAddress = "disabled"; + }; + }; + + environment.systemPackages = with pkgs; [ + inetutils + mtr + sysstat + + nil + ]; + + documentation.enable = false; + + services = { + openssh = { + enable = true; + settings = { + LoginGraceTime = 0; + PasswordAuthentication = false; + PermitRootLogin = "no"; + }; + }; + }; + + + users.users.${config.my.user.username} = { + openssh.authorizedKeys.keys = [ + "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIElnlmCCIRhwe7z/a4dpwNoPF65II8NsOHUWJIBdr2Rg errie@nix-laptop" + "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIFDWYERkHOqml1ntOUp8iZRTtvuAVUXcT4RRdqYtvxBy u0_a313@localhost" + ]; + }; + + system.stateVersion = "23.05"; +} diff --git a/hosts/groceries/hardware-configuration.nix b/hosts/groceries/hardware-configuration.nix new file mode 100644 index 0000000..c7fdd9f --- /dev/null +++ b/hosts/groceries/hardware-configuration.nix @@ -0,0 +1,28 @@ +# Do not modify this file! It was generated by ‘nixos-generate-config’ +# and may be overwritten by future invocations. Please make changes +# to /etc/nixos/configuration.nix instead. +{ config, lib, pkgs, modulesPath, ... }: + +{ + imports = + [ (modulesPath + "/profiles/qemu-guest.nix") + ]; + + boot.initrd.availableKernelModules = [ "virtio_pci" "virtio_scsi" "ahci" "sd_mod" ]; + boot.initrd.kernelModules = [ ]; + boot.kernelModules = [ ]; + boot.extraModulePackages = [ ]; + + fileSystems."/" = + { device = "/dev/sda"; + fsType = "ext4"; + autoResize = true; + }; + + # Enables DHCP on each ethernet and wireless interface. In case of scripted networking + # (the default) this is the recommended approach. When using systemd-networkd it's + # still possible to use this option, but it's recommended to use it in conjunction + # with explicit per-interface declarations with `networking.interfaces..useDHCP`. + networking.useDHCP = lib.mkDefault true; + # networking.interfaces.enp0s5.useDHCP = lib.mkDefault true; +} diff --git a/hosts/groceries/home/default.nix b/hosts/groceries/home/default.nix new file mode 100644 index 0000000..8b0247d --- /dev/null +++ b/hosts/groceries/home/default.nix @@ -0,0 +1,18 @@ +_: + +{ + imports = [ ./packages.nix ]; + + my = { + git.enable = true; + + shell = { + aliases.enable = true; + direnv.enable = true; + fish.enable = true; + globalNpmPackages.enable = true; + }; + }; + + home.stateVersion = "23.05"; +} diff --git a/hosts/groceries/home/packages.nix b/hosts/groceries/home/packages.nix new file mode 100644 index 0000000..abad641 --- /dev/null +++ b/hosts/groceries/home/packages.nix @@ -0,0 +1,6 @@ +{ pkgs, ... }: + +{ + home.packages = with pkgs; [ + ]; +} diff --git a/hosts/groceries/services/default.nix b/hosts/groceries/services/default.nix new file mode 100644 index 0000000..f7839c2 --- /dev/null +++ b/hosts/groceries/services/default.nix @@ -0,0 +1,38 @@ +{ config, ... }: + +{ + imports = [ + ./forgejo.nix + + ./sync + ]; + + networking.firewall.allowedTCPPorts = [ 80 443 ]; + + services.nginx = { + enable = true; + virtualHosts = { + "eriedaberrie.me" = { + forceSSL = true; + enableACME = true; + acmeRoot = null; + serverAliases = [ "www.eriedaberrie.me" ]; + locations."/".proxyPass = "http://127.0.0.1:8080/"; + }; + }; + }; + + security.acme = { + acceptTerms = true; + defaults.email = "eriedaberrie@gmail.com"; + certs = { + "eriedaberrie.me" = { + dnsProvider = "porkbun"; + credentialsFile = config.age.secrets.porkbun-auth.path; + extraDomainNames = [ + "www.eriedaberrie.me" + ]; + }; + }; + }; +} diff --git a/hosts/groceries/services/forgejo.nix b/hosts/groceries/services/forgejo.nix new file mode 100644 index 0000000..2fd5cbe --- /dev/null +++ b/hosts/groceries/services/forgejo.nix @@ -0,0 +1,70 @@ +{ pkgs, config, lib, ... }: + +let + cfg = config.services.forgejo; +in { + services.forgejo = { + enable = true; + appName = "Eriedaberrie's Forgejo"; + lfs.enable = true; + settings = { + server = { + PROTOCOL = "http+unix"; + ROOT_URL = "https://git.eriedaberrie.me/"; + }; + service = { + COOKIE_SECURE = true; + DISABLE_REGISTRATION = true; + }; + ui = { + DEFAULT_THEME = "catppuccin-mocha-lavender"; + THEMES = "catppuccin-mocha-lavender,forgejo-auto,forgejo-light,forgejo-dark,auto,gitea,arc-green"; + }; + "highlight.mapping" = { + ".lock" = "json"; + }; + }; + user = "git"; + }; + + # Because the module only autocreates the user if it's the default name + users.users = lib.mkIf (cfg.user != "forgejo") { + ${cfg.user} = { + inherit (cfg) group; + description = "Forgejo Service"; + home = cfg.stateDir; + useDefaultShell = true; + isSystemUser = true; + }; + }; + + systemd.tmpfiles.rules = let + inherit (cfg) customDir user group; + catppuccinSource = pkgs.fetchzip { + url = "https://github.com/catppuccin/gitea/releases/download/v0.4.1/catppuccin-gitea.tar.gz"; + hash = "sha256-14XqO1ZhhPS7VDBSzqW55kh6n5cFZGZmvRCtMEh8JPI="; + stripRoot = false; + }; + fileName = "theme-catppuccin-mocha-lavender.css"; + in [ + "d '${customDir}/public' 0750 ${user} ${group} - -" + "d '${customDir}/public/assets' 0750 ${user} ${group} - -" + "d '${customDir}/public/assets/css' 0750 ${user} ${group} - -" + "z '${customDir}/public' 0750 ${user} ${group} - -" + "z '${customDir}/public/assets' 0750 ${user} ${group} - -" + "z '${customDir}/public/assets/css' 0750 ${user} ${group} - -" + "L+ '${customDir}/public/assets/css/${fileName}' - - - - ${catppuccinSource}/${fileName}" + ]; + + services.nginx = { + virtualHosts."git.eriedaberrie.me" = { + forceSSL = true; + useACMEHost = "eriedaberrie.me"; + locations."/".proxyPass = "http://forgejo/"; + }; + + upstreams.forgejo.servers."unix:${cfg.settings.server.HTTP_ADDR}" = { }; + }; + + security.acme.certs."eriedaberrie.me".extraDomainNames = [ "git.eriedaberrie.me" ]; +} diff --git a/hosts/groceries/services/sync/default.nix b/hosts/groceries/services/sync/default.nix new file mode 100644 index 0000000..bf8aabd --- /dev/null +++ b/hosts/groceries/services/sync/default.nix @@ -0,0 +1,18 @@ +_: + +{ + imports = [ + ./syncthing.nix + ./syncyomi.nix + ]; + + services.nginx = { + virtualHosts."sync.eriedaberrie.me" = { + forceSSL = true; + useACMEHost = "eriedaberrie.me"; + locations."/".return = "301 $scheme://eriedaberrie.me$request_uri"; + }; + }; + + security.acme.certs."eriedaberrie.me".extraDomainNames = [ "sync.eriedaberrie.me" ]; +} diff --git a/hosts/groceries/services/sync/syncthing.nix b/hosts/groceries/services/sync/syncthing.nix new file mode 100644 index 0000000..3c84e63 --- /dev/null +++ b/hosts/groceries/services/sync/syncthing.nix @@ -0,0 +1,39 @@ +{ config, ... }: + +let + sockDir = "/run/syncthing"; + cfg = config.services.syncthing; +in { + my.syncthing.enable = true; + + services = { + nginx = let + upstream = "syncthing"; + in { + virtualHosts."sync.eriedaberrie.me" = { + locations."/syncthing/".proxyPass = "http://${upstream}/"; + }; + + upstreams.${upstream}.servers."unix:${cfg.guiAddress}" = { }; + }; + + syncthing = { + guiAddress = "${sockDir}/syncthing.sock"; + settings = { + gui = { + address = cfg.guiAddress; + unixSocketPermissions = "666"; + user = "serverie"; + password = "$2a$10$sSOgRCl5kB0ixakiVidWI.IH26tkoNZHqf9eUwoHmHxPEDRdYDZ06"; + }; + }; + }; + }; + + systemd.tmpfiles.rules = let + inherit (cfg) user group; + in [ + "d '${sockDir}' 0755 ${user} ${group} - -" + "z '${sockDir}' 0755 ${user} ${group} - -" + ]; +} diff --git a/hosts/groceries/services/sync/syncyomi.nix b/hosts/groceries/services/sync/syncyomi.nix new file mode 100644 index 0000000..fcdb13f --- /dev/null +++ b/hosts/groceries/services/sync/syncyomi.nix @@ -0,0 +1,21 @@ +{ config, ... }: + +let + cfg = config.services.syncyomi; + baseUrl = "/syncyomi/"; +in { + services = { + nginx = { + virtualHosts."sync.eriedaberrie.me" = { + locations.${baseUrl}.proxyPass = "http://127.0.0.1:${builtins.toString cfg.settings.port}/"; + }; + }; + + syncyomi = { + enable = true; + settings = { + inherit baseUrl; + }; + }; + }; +} diff --git a/hosts/groceries/services/wireguard.nix b/hosts/groceries/services/wireguard.nix new file mode 100644 index 0000000..65f0611 --- /dev/null +++ b/hosts/groceries/services/wireguard.nix @@ -0,0 +1,74 @@ +{ pkgs, config, ... }: + +let + interface = "wg0"; + listenPort = 51821; + tcpPort = 82; +in { + systemd.services."udp2raw-${interface}" = { + after = [ "network.target" ]; + before = [ "wg-quick-${interface}.service" ]; + wantedBy = [ "wg-quick-${interface}.service" ]; + serviceConfig = { + ExecStart = "${pkgs.udp2raw}/bin/udp2raw -s -l 0.0.0.0:${builtins.toString tcpPort} -r 127.0.0.1:${builtins.toString listenPort} -a"; + }; + }; + + services.dnsmasq = { + enable = true; + settings = { + inherit interface; + }; + }; + + networking = { + nat = { + enable = true; + externalInterface = "eth0"; + internalInterfaces = [ interface ]; + enableIPv6 = true; + }; + + firewall = { + allowedUDPPorts = [ listenPort ]; + allowedTCPPorts = [ tcpPort ]; + interfaces.${interface} = { + allowedUDPPorts = [ 53 ]; + allowedTCPPorts = [ 53 ]; + }; + }; + + wg-quick.interfaces = { + ${interface} = { + address = [ "10.0.0.1/24" "fdc9:281f:04d7:9ee9::1/64" ]; + inherit listenPort; + privateKeyFile = config.age.secrets.wg-groceries.path; + + postUp = '' + ${pkgs.iptables}/bin/iptables -A FORWARD -i wg0 -j ACCEPT + ${pkgs.iptables}/bin/iptables -t nat -A POSTROUTING -s 10.0.0.1/24 -o eth0 -j MASQUERADE + ${pkgs.iptables}/bin/ip6tables -A FORWARD -i wg0 -j ACCEPT + ${pkgs.iptables}/bin/ip6tables -t nat -A POSTROUTING -s fdc9:281f:04d7:9ee9::1/64 -o eth0 -j MASQUERADE + ''; + + preDown = '' + ${pkgs.iptables}/bin/iptables -D FORWARD -i wg0 -j ACCEPT + ${pkgs.iptables}/bin/iptables -t nat -D POSTROUTING -s 10.0.0.1/24 -o eth0 -j MASQUERADE + ${pkgs.iptables}/bin/ip6tables -D FORWARD -i wg0 -j ACCEPT + ${pkgs.iptables}/bin/ip6tables -t nat -D POSTROUTING -s fdc9:281f:04d7:9ee9::1/64 -o eth0 -j MASQUERADE + ''; + + peers = [ + { + publicKey = "mX5cMCXQbnovPOHDFdcV3egG3u9Xd3sci+mqUhFSz1Q="; + allowedIPs = [ "10.0.0.2/32" "fdc9:281f:04d7:9ee9::2/128" ]; + } + { + publicKey = "Hkk76wQQ3dYY31GYUSHMIOBgiKDPqm00cKBLMzwTO1s="; + allowedIPs = [ "10.0.0.3/32" "fdc9:281f:04d7:9ee9::3/128" ]; + } + ]; + }; + }; + }; +} diff --git a/hosts/groceries/services/wordpress.nix b/hosts/groceries/services/wordpress.nix new file mode 100644 index 0000000..b4469a6 --- /dev/null +++ b/hosts/groceries/services/wordpress.nix @@ -0,0 +1,22 @@ +_: + +{ + services = { + wordpress = { + sites."iclean.eriedaberrie.me" = { + settings = { + FORCE_SSL_ADMIN = true; + }; + }; + + webserver = "nginx"; + }; + + nginx.virtualHosts."iclean.eriedaberrie.me" = { + forceSSL = true; + useACMEHost = "eriedaberrie.me"; + }; + }; + + security.acme.certs."eriedaberrie.me".extraDomainNames = [ "iclean.eriedaberrie.me" ]; +} diff --git a/hosts/msft-laptop/default.nix b/hosts/msft-laptop/default.nix new file mode 100644 index 0000000..9a81f7f --- /dev/null +++ b/hosts/msft-laptop/default.nix @@ -0,0 +1,97 @@ +{ pkgs, lib, ... }: + +{ + imports = [ + ./hardware-configuration.nix + ]; + + time.timeZone = "America/Los_Angeles"; + + my = { + user = { + username = "errie"; + homeModule = ./home; + }; + + secure-boot.enable = true; + bootloader.type = "systemdBoot"; + + fs = { + luks.enable = true; + ssd.enable = true; + bootPartition = true; + snapshots = true; + type = "btrfs"; + }; + + laptop = { + enable = true; + amd.enable = true; + }; + + networking = { + networkManager.enable = true; + eddie = let + forwardedPorts = [ 14110 50459 ]; + in { + enable = true; + allowedTCPPorts = forwardedPorts; + allowedUDPPorts = forwardedPorts; + }; + }; + + bin-compat.enable = true; + docker.enable = true; + interception.enable = true; + location.enable = true; + virt-manager.enable = true; + wireshark.enable = true; + + syncthing = { + enable = true; + asUser = true; + }; + + cli = { + fish.enable = true; + nix-index.enable = true; + sudo.insults.enable = true; + }; + + desktop = { + enable = true; + audio.enable = true; + bluetooth.enable = true; + gaming.enable = true; + hyprland.enable = true; + printing.enable = true; + }; + }; + + environment.systemPackages = with pkgs; [ + dos2unix + amdgpu_top + (p7zip.override {enableUnfree = true;}) + ]; + + programs = { + git.package = pkgs.gitFull; + }; + + hardware.sensor.iio.enable = true; + + services = { + fwupd.enable = true; + + flatpak.enable = true; + + openssh = { + enable = true; + settings = { + PasswordAuthentication = false; + }; + }; + }; + + system.stateVersion = "23.11"; +} diff --git a/hosts/msft-laptop/hardware-configuration.nix b/hosts/msft-laptop/hardware-configuration.nix new file mode 100644 index 0000000..2e4a328 --- /dev/null +++ b/hosts/msft-laptop/hardware-configuration.nix @@ -0,0 +1,23 @@ +# Do not modify this file! It was generated by ‘nixos-generate-config’ +# and may be overwritten by future invocations. Please make changes +# to /etc/nixos/configuration.nix instead. +{ config, lib, pkgs, modulesPath, ... }: + +{ + imports = + [ (modulesPath + "/installer/scan/not-detected.nix") + ]; + + boot.initrd.availableKernelModules = [ "nvme" "xhci_pci" "thunderbolt" "usb_storage" "usbhid" "uas" "sd_mod" ]; + boot.initrd.kernelModules = [ ]; + boot.kernelModules = [ "kvm-amd" ]; + boot.extraModulePackages = [ ]; + + # Enables DHCP on each ethernet and wireless interface. In case of scripted networking + # (the default) this is the recommended approach. When using systemd-networkd it's + # still possible to use this option, but it's recommended to use it in conjunction + # with explicit per-interface declarations with `networking.interfaces..useDHCP`. + networking.useDHCP = lib.mkDefault true; + + hardware.cpu.amd.updateMicrocode = lib.mkDefault config.hardware.enableRedistributableFirmware; +} diff --git a/hosts/msft-laptop/home/default.nix b/hosts/msft-laptop/home/default.nix new file mode 100644 index 0000000..afbb347 --- /dev/null +++ b/hosts/msft-laptop/home/default.nix @@ -0,0 +1,68 @@ +{ ... }: + +{ + imports = [ ./packages.nix ]; + + my = { + email.enable = true; + git.enable = true; + + keepassxc.enable = true; + + cli = { + bat.enable = true; + btop.enable = true; + eza.enable = true; + }; + + fetch = { + fastfetch.enable = true; + others.enable = true; + }; + + graphical = { + enable = true; + dunst.enable = true; + emacs.enable = true; + firefox.enable = true; + mangohud.enable = true; + mpv.enable = true; + obs.enable = true; + zathura.enable = true; + + wayland = { + enable = true; + fuzzel.enable = true; + hyprland.enable = true; + eww.enable = true; + foot.enable = true; + gammastep.enable = true; + hyprlock.enable = true; + ydotool.enable = true; + }; + }; + + mpd = { + enable = true; + ncmpcpp.enable = true; + }; + + shell = { + aliases.enable = true; + direnv.enable = true; + fish.enable = true; + globalNpmPackages.enable = true; + starship.enable = true; + }; + }; + + programs = { + java.enable = true; + }; + + services = { + playerctld.enable = true; + }; + + home.stateVersion = "23.11"; +} diff --git a/hosts/msft-laptop/home/packages.nix b/hosts/msft-laptop/home/packages.nix new file mode 100644 index 0000000..38d4634 --- /dev/null +++ b/hosts/msft-laptop/home/packages.nix @@ -0,0 +1,37 @@ +{ pkgs, inputs, ... }: + +{ + home.packages = (with pkgs; [ + jaq + imagemagick + ffmpeg-full + python3 + ruby + lazygit + playerctl + cantata + socat + sway + imv + gimp + inkscape + xfce.thunar + yt-dlp + libqalculate + qalculate-gtk + libreoffice + (hunspellWithDicts [ hunspellDicts.en-us ]) + zoom-us + slack + remmina + winetricks + ripdrag + (vesktop.override {withSystemVencord = false;}) + aseprite + qbittorrent + nicotine-plus + r2modman + ]) ++ (with inputs.nix-gaming.packages.${pkgs.system}; [ + wine-ge + ]); +} diff --git a/hosts/nix-laptop/default.nix b/hosts/nix-laptop/default.nix new file mode 100644 index 0000000..efcd9d6 --- /dev/null +++ b/hosts/nix-laptop/default.nix @@ -0,0 +1,98 @@ +{ pkgs, lib, ... }: + +{ + imports = [ + ./hardware-configuration.nix + ./wireguard.nix + ]; + + time.timeZone = "America/Los_Angeles"; + + my = { + user = { + username = "errie"; + homeModule = ./home; + }; + + bootloader.type = "systemdBoot"; + + fs = { + bootPartition = true; + snapshots = true; + type = "btrfs"; + }; + + networking = { + networkManager.enable = true; + eddie = { + enable = true; + allowedTCPPorts = [ 50459 ]; + }; + }; + + bin-compat.enable = true; + interception.enable = true; + location.enable = true; + virt-manager.enable = true; + wireshark.enable = true; + + syncthing = { + enable = true; + asUser = true; + }; + + cli = { + fish.enable = true; + nix-index.enable = true; + }; + + desktop = { + enable = true; + audio.enable = true; + bluetooth.enable = true; + gaming.enable = true; + hyprland.enable = true; + printing.enable = true; + }; + }; + + systemd.services.nginx.wantedBy = lib.mkForce [ ]; + + environment.systemPackages = with pkgs; [ + gcc + dos2unix + ]; + + programs = { + zsh.enable = true; + git.package = pkgs.gitFull; + }; + + services = { + flatpak.enable = true; + + openssh.enable = true; + + mullvad-vpn = { + enable = true; + package = pkgs.mullvad-vpn; + }; + + nginx = { + enable = true; + virtualHosts."127.0.0.1" = { + listen = [ + { + addr = "127.0.0.1"; + port = 80; + } + ]; + locations."/" = { + proxyPass = "http://127.0.0.1:3000/"; + }; + }; + }; + }; + + system.stateVersion = "22.11"; +} diff --git a/hosts/nix-laptop/hardware-configuration.nix b/hosts/nix-laptop/hardware-configuration.nix new file mode 100644 index 0000000..d8b330e --- /dev/null +++ b/hosts/nix-laptop/hardware-configuration.nix @@ -0,0 +1,26 @@ +# Do not modify this file! It was generated by ‘nixos-generate-config’ +# and may be overwritten by future invocations. Please make changes +# to /etc/nixos/configuration.nix instead. +{ config, lib, pkgs, modulesPath, ... }: + +{ + imports = + [ (modulesPath + "/installer/scan/not-detected.nix") + ]; + + boot.initrd.availableKernelModules = [ "xhci_pci" "ahci" "nvme" "usbhid" "usb_storage" "sd_mod" ]; + boot.initrd.kernelModules = [ ]; + boot.kernelModules = [ "kvm-intel" ]; + boot.extraModulePackages = [ ]; + + # Enables DHCP on each ethernet and wireless interface. In case of scripted networking + # (the default) this is the recommended approach. When using systemd-networkd it's + # still possible to use this option, but it's recommended to use it in conjunction + # with explicit per-interface declarations with `networking.interfaces..useDHCP`. + networking.useDHCP = lib.mkDefault true; + # networking.interfaces.enp1s0.useDHCP = lib.mkDefault true; + # networking.interfaces.wlp2s0.useDHCP = lib.mkDefault true; + + powerManagement.cpuFreqGovernor = lib.mkDefault "powersave"; + hardware.cpu.intel.updateMicrocode = lib.mkDefault config.hardware.enableRedistributableFirmware; +} diff --git a/hosts/nix-laptop/home/default.nix b/hosts/nix-laptop/home/default.nix new file mode 100644 index 0000000..e28cf57 --- /dev/null +++ b/hosts/nix-laptop/home/default.nix @@ -0,0 +1,68 @@ +{ pkgs, ... }: + +{ + imports = [ ./packages.nix ]; + + my = { + email.enable = true; + git.enable = true; + + keepassxc.enable = true; + + cli = { + bat.enable = true; + btop.enable = true; + eza.enable = true; + }; + + fetch = { + fastfetch.enable = true; + others.enable = true; + }; + + graphical = { + enable = true; + dunst.enable = true; + emacs.enable = true; + firefox.enable = true; + mpv.enable = true; + obs.enable = true; + zathura.enable = true; + + wayland = { + enable = true; + fuzzel.enable = true; + hyprland.enable = true; + eww.enable = true; + foot.enable = true; + gammastep.enable = true; + swayidle.enable = true; + swaylock.enable = true; + ydotool.enable = true; + }; + }; + + shell = { + aliases.enable = true; + direnv.enable = true; + fish.enable = true; + globalNpmPackages.enable = true; + starship.enable = true; + zsh.enable = true; + }; + + spotify = { + spicetify.enable = true; + }; + }; + + programs = { + java.enable = true; + neovim = { + enable = true; + plugins = with pkgs.vimPlugins; [ packer-nvim ]; + }; + }; + + home.stateVersion = "22.11"; +} diff --git a/hosts/nix-laptop/home/packages.nix b/hosts/nix-laptop/home/packages.nix new file mode 100644 index 0000000..bc55b0b --- /dev/null +++ b/hosts/nix-laptop/home/packages.nix @@ -0,0 +1,45 @@ +{ pkgs, inputs, self, ... }: + +{ + home.packages = (with pkgs; [ + jaq + imagemagick + ffmpeg + nodejs + sbcl + racket + ghc + pyright + sumneko-lua-language-server + clang-tools + bear + rust-analyzer + cmake + meson + lazygit + fortune + neo-cowsay + lolcat + playerctl + socat + sway + imv + gimp + inkscape + xfce.thunar + libqalculate + qalculate-gtk + libreoffice + (hunspellWithDicts [ hunspellDicts.en-us ]) + zoom-us + slack + remmina + godot_4 + winetricks + ripdrag + aseprite + qbittorrent + ]) ++ (with inputs.nix-gaming.packages.${pkgs.system}; [ + wine-ge + ]); +} diff --git a/hosts/nix-laptop/wireguard.nix b/hosts/nix-laptop/wireguard.nix new file mode 100644 index 0000000..893d484 --- /dev/null +++ b/hosts/nix-laptop/wireguard.nix @@ -0,0 +1,72 @@ +{ pkgs, config, lib, ... }: + +let + interface = "wg0"; + listenPort = 51821; + tcpPort = 82; +in { + systemd.services = { + "wg-quick-${interface}".wantedBy = lib.mkForce [ ]; + + "udp2raw-${interface}" = { + after = [ "network.target" ]; + before = [ "wg-quick-${interface}.service" ]; + requires = [ "wg-quick-${interface}.service" ]; + wantedBy = [ "wg-quick-${interface}.service" ]; + serviceConfig = let + remoteIP = "66.175.222.204"; + in { + ExecStartPre = pkgs.writeShellScript "pre-udp2raw-${interface}" '' + eval "$( + ${pkgs.iproute2}/bin/ip route | ${pkgs.gawk}/bin/awk \ + '$1=="default" { + printf "%s", "${pkgs.iproute2}/bin/ip route add ${remoteIP}" + for (i=2; i<=NF; i+=2) { + if ($i=="via" || $i=="dev" || $i=="metric") { + printf " %s %s", $i, $(i+1) + } + } + print " proto static" + }' + )" + ''; + ExecStart = pkgs.writeShellScript "udp2raw-${interface}" '' + exec ${pkgs.udp2raw}/bin/udp2raw -c \ + -l "127.0.0.1:${builtins.toString listenPort}" \ + -r "${remoteIP}:${builtins.toString tcpPort}" \ + -a + ''; + ExecStopPost = "${pkgs.iproute2}/bin/ip route flush ${remoteIP} proto static"; + Restart = "on-failure"; + }; + }; + }; + + networking = { + firewall.checkReversePath = "loose"; + + wg-quick.interfaces = { + ${interface} = let + publicKey = "Awb1R2KZ3v4MArN/Lmxr4BTL0rdFm5dJID6ntifr4GQ="; + in { + address = [ "10.0.0.2/32" "fdc9:281f:04d7:9ee9::2/128" ]; + dns = [ "10.0.0.1" ]; + privateKeyFile = config.age.secrets.wg-nix-laptop.path; + + mtu = 1332; + + postUp = [ + "wg set wg0 peer ${publicKey} persistent-keepalive 25" + ]; + + peers = [ + { + inherit publicKey; + allowedIPs = [ "0.0.0.0/0" "::/0" ]; + endpoint = "127.0.0.1:${builtins.toString listenPort}"; + } + ]; + }; + }; + }; +} diff --git a/lib/default.nix b/lib/default.nix new file mode 100644 index 0000000..81708ad --- /dev/null +++ b/lib/default.nix @@ -0,0 +1,33 @@ +{ nixpkgs, self, ... } @ inputs: + +let + inherit (nixpkgs) lib; +in rec { + + mkSystems = builtins.mapAttrs (hostName: cfg: lib.nixosSystem { + inherit (cfg) system; + specialArgs = {inherit self inputs;}; + modules = [ + { + networking = {inherit hostName;}; + nixpkgs.hostPlatform = cfg.system; + } + + self.nixosModules.default + + cfg.module + ]; + }); + + recReadDir = startDir: dir: lib.concatMapAttrs (file: type: let + fullFile = "${dir}/${file}"; + in + if type == "directory" then recReadDir startDir fullFile + else {${fullFile} = "${startDir}/${fullFile}";} + ) (builtins.readDir "${startDir}/${dir}"); + + filterNixReadDir = dir: lib.filterAttrs (name: _: + builtins.match ".*\\.nix" name == null + ) (recReadDir dir "."); + +} diff --git a/modules/home/cli.nix b/modules/home/cli.nix new file mode 100644 index 0000000..67814aa --- /dev/null +++ b/modules/home/cli.nix @@ -0,0 +1,67 @@ +{ pkgs, config, lib, ... }: + +let + cfg = config.my.cli; +in { + options.my.cli = { + bat.enable = lib.mkEnableOption null; + btop.enable = lib.mkEnableOption null; + eza.enable = lib.mkEnableOption null // { + default = true; + }; + ranger.enable = lib.mkEnableOption null; + }; + + config = lib.mkMerge [ + (lib.mkIf cfg.bat.enable { + programs.bat = { + enable = true; + config = { + map-syntax = [ "flake.lock:JSON" ]; + theme = "catppuccinMocha"; + }; + themes = { + catppuccinMocha = { + src = pkgs.fetchFromGitHub { + owner = "catppuccin"; + repo = "bat"; + rev = "ba4d16880d63e656acced2b7d4e034e4a93f74b1"; + sha256 = "1g2r6j33f4zys853i1c5gnwcdbwb6xv5w6pazfdslxf69904lrg9"; + }; + file = "Catppuccin-mocha.tmTheme"; + }; + }; + }; + xdg.configFile."btop/themes/catppuccin_mocha.theme".source = pkgs.fetchFromGitHub { + owner = "catppuccin"; + repo = "btop"; + rev = "89ff712eb62747491a76a7902c475007244ff202"; + hash = "sha256-J3UezOQMDdxpflGax0rGBF/XMiKqdqZXuX4KMVGTxFk="; + } + "/themes/catppuccin_mocha.theme"; + }) + + (lib.mkIf cfg.btop.enable { + programs.btop = { + enable = true; + settings = { + vim_keys = true; + color_theme = "catppuccin_mocha"; + }; + }; + }) + + (lib.mkIf cfg.eza.enable { + programs.eza = { + enable = true; + }; + }) + + (lib.mkIf cfg.ranger.enable { + home.packages = [ pkgs.ranger ]; + xdg.configFile."ranger/rc.conf".text = '' + set preview_images true + set preview_images_method kitty + ''; + }) + ]; +} diff --git a/modules/home/default.nix b/modules/home/default.nix new file mode 100644 index 0000000..f258223 --- /dev/null +++ b/modules/home/default.nix @@ -0,0 +1,28 @@ +{ lib, osConfig, ... }: + +{ + imports = [ + # inputs.nur.hmModules.nur + ./graphical + ./themes + + ./cli.nix + ./email.nix + ./fetch.nix + ./git.nix + ./mpd.nix + ./nix.nix + ./packages.nix + ./shell.nix + ./spotify.nix + ]; + + xdg.enable = true; + + dconf.settings = lib.mkIf osConfig.my.virt-manager.enable { + "org/virt-manager/virt-manager/connections" = { + autoconnect = [ "qemu:///system" ]; + uris = [ "qemu:///system" ]; + }; + }; +} diff --git a/modules/home/email.nix b/modules/home/email.nix new file mode 100644 index 0000000..340e6e5 --- /dev/null +++ b/modules/home/email.nix @@ -0,0 +1,114 @@ +{ pkgs, config, lib, osConfig, ... }: + +let + cfg = config.my.email; +in { + options.my.email = { + enable = lib.mkEnableOption null; + git.enable = lib.mkEnableOption null // { + default = true; + }; + emacs.enable = lib.mkEnableOption null // { + default = config.my.git.enable; + }; + }; + + config = lib.mkIf cfg.enable (let + emailJson = osConfig.age.secrets.email.path; + anyConfigCmd = delim: t: k: + "${pkgs.jaq}/bin/jaq -r ${delim}.${t}.${k}${delim} ${emailJson}"; + in lib.mkMerge [ + (lib.mkIf cfg.emacs.enable { + accounts.email = { + maildirBasePath = "Mail"; + accounts = builtins.mapAttrs (type: address: { + inherit address; + realName = address; + passwordCommand = anyConfigCmd "" type "password"; + primary = type == "personal"; + flavor = "gmail.com"; + smtp.tls.useStartTls = true; + mbsync = { + enable = true; + create = "both"; + expunge = "both"; + }; + mu.enable = true; + imapnotify = let + mbsync = "${config.programs.mbsync.package}/bin/mbsync"; + mu = "${pkgs.mu}/bin/mu"; + in { + enable = true; + boxes = [ "Inbox" ]; + onNotify = "${mbsync} ${type} && ${mu} index"; + onNotifyPost = let + notify-send = "${pkgs.libnotify}/bin/notify-send"; + muFindEscape = f: let + sed = "${pkgs.gnused}/bin/sed"; + in "${mu} find \"l:$FILE\" -f ${f}" + + " | ${sed} 's//\\>/g'"; + in pkgs.writeScript "inbox-notify-latest-${type}" '' + FILE="$(${mu} find "m:/${type}/Inbox" -z -s d -n 1 -f l)" + exec ${notify-send} -i mail-unread-new \ + "[${address}] $(${muFindEscape "s"})" \ + "from: $(${muFindEscape "f"})" + ''; + extraConfig.wait = 3; + }; + }) { + personal = "erlic006@gmail.com"; + other = "eriedaberrie@gmail.com"; + }; + }; + programs = { + mbsync.enable = true; + mu.enable = true; + }; + services.imapnotify.enable = true; + home.sessionVariables.MAILDIR = config.accounts.email.maildirBasePath; + }) + + (lib.mkIf cfg.git.enable (let + gitSetEmail = pkgs.writeShellScriptBin "git-set-email" (let + git = "${config.programs.git.package}/bin/git"; + gitConfRep = "${git} config --replace-all --local"; + in '' + ${git} rev-parse --is-inside-work-tree > /dev/null || exit 1 + if [ -z "$1" ]; then + declare -a keys=("user.name" + "user.email" + "sendemail.from" + "sendemail.smtpUser" + "sendemail.smtpPass" + "sendemail.smtpEncryption" + "sendemail.smtpServer" + "sendemail.smtpServerPort" + "sendemail.smtpSslCertPath") + for key in "''${keys[@]}"; do + ${git} config --unset-all --local "$key" + done + else + [ "$(${pkgs.jaq}/bin/jaq "has(\"$1\")" ${emailJson})" = true ] || exit 1 + NAME="$(${anyConfigCmd "\"" "$1" "name"})" + ADDRESS="$(${anyConfigCmd "\"" "$1" "address"})" + ${gitConfRep} 'user.name' "$NAME" + ${gitConfRep} 'user.email' "$ADDRESS" + ${gitConfRep} 'sendemail.from' "$NAME <$ADDRESS>" + ${gitConfRep} 'sendemail.smtpPass' "$(${anyConfigCmd "\"" "$1" "password"})" + declare -a keys=("smtpEncryption" + "smtpServer" + "smtpServerPort" + "smtpSslCertPath" + "smtpUser") + for key in "''${keys[@]}"; do + ${gitConfRep} "sendemail.$key" \ + "$(${git} config --get --global "sendemail.$1.$key")" + done + fi + ''); + in { + home.packages = [ gitSetEmail]; + })) + ]); +} diff --git a/modules/home/fetch.nix b/modules/home/fetch.nix new file mode 100644 index 0000000..cec491b --- /dev/null +++ b/modules/home/fetch.nix @@ -0,0 +1,83 @@ +{ pkgs, config, lib, inputs, ... }: + +let + cfg = config.my.fetch; +in { + options.my.fetch = { + fastfetch.enable = lib.mkEnableOption null; + neofetch.enable = lib.mkEnableOption null; + others.enable = lib.mkEnableOption null; + }; + + config = lib.mkMerge [ + (lib.mkIf cfg.fastfetch.enable { + home.packages = [ + (inputs.my-nix-packages.packages.${pkgs.system}.fastfetch.overrideAttrs { + flashfetchModules = [ + "title" + "separator" + "os" + "kernel" + "uptime" + "shell" + "display" + "wm" + "theme" + "icons" + "font" + "cursor" + "terminal" + "terminalFont" + "cpu" + "gpu" + "memory" + "disk" + "battery" + "locale" + ]; + }) + ]; + }) + + (lib.mkIf cfg.neofetch.enable { + home.packages = [ pkgs.neofetch ]; + xdg.configFile = { + "neofetch/config.conf".text = '' + print_info() { + info title + info underline + info "OS" distro + info "Host" model + info "Kernel" kernel + info "Uptime" uptime + info "Shell" shell + info "Resolution" resolution + info "DE" de + info "Theme" theme + info "Icons" icons + info "Terminal" term + info "Terminal Font" term_font + info "CPU" cpu + info "GPU" gpu + info "Memory" memory + info cols + } + memory_percent="on" + shell_path="on" + speed_shorthand="off" + ''; + }; + }) + + (lib.mkIf cfg.others.enable { + home.packages = with pkgs; [ + nitch + (uwufetch.overrideAttrs (old: { + preBuild = old.preBuild or "" + '' + mkdir -p $out/include + ''; + })) + ]; + }) + ]; +} diff --git a/modules/home/git.nix b/modules/home/git.nix new file mode 100644 index 0000000..39ed2d6 --- /dev/null +++ b/modules/home/git.nix @@ -0,0 +1,43 @@ +{ pkgs, config, lib, osConfig, ... }: + +let + cfg = config.my.git; +in { + options.my.git = { + enable = lib.mkEnableOption null; + }; + + config = lib.mkIf cfg.enable { + home = { + sessionVariables.FILTER_BRANCH_SQUELCH_WARNING = 1; + shellAliases = { + g = "git"; + lg = "lazygit"; + }; + packages = with pkgs; [ + git-absorb + ]; + }; + programs.git = { + enable = true; + inherit (osConfig.programs.git) package; + userName = "eriedaberrie"; + userEmail = "eriedaberrie@gmail.com"; + aliases = { + hardfetch = "!git fetch --progress $1 && git reset --hard $1 && :"; + pushf = "push --force-with-lease"; + syncdates = "filter-branch --env-filter 'export GIT_COMMITTER_DATE=\"$GIT_AUTHOR_DATE\"'"; + }; + extraConfig = { + commit.verbose = true; + init.defaultBranch = "main"; + pull.rebase = true; + push.autoSetupRemote = true; + rebase.autoStash = true; + rerere.enabled = true; + github.user = "eriedaberrie"; + gitlab.user = "eriedaberrie"; + }; + }; + }; +} diff --git a/modules/home/graphical/default.nix b/modules/home/graphical/default.nix new file mode 100644 index 0000000..8a2bb81 --- /dev/null +++ b/modules/home/graphical/default.nix @@ -0,0 +1,88 @@ +{ pkgs, config, lib, osConfig, ... }: + +let + cfg = config.my.graphical; +in { + imports = [ + ./wayland + ./dunst.nix + ./emacs.nix + ./firefox.nix + ./keepassxc.nix + ./kitty.nix + ./mangohud.nix + ./mpv.nix + ./obs.nix + ./qtk.nix + ./qutebrowser.nix + ./zathura.nix + ]; + + options.my.graphical = { + enable = lib.mkEnableOption null; + }; + + config = lib.mkIf cfg.enable { + fonts.fontconfig.enable = true; + + xdg = { + userDirs = { + enable = true; + createDirectories = true; + }; + mimeApps = { + enable = true; + defaultApplications = let + editor = "emacsclient.desktop"; + email = "emacsclient-mail.desktop"; + pdf = "org.pwmt.zathura.desktop"; + browser = "firefox.desktop"; + image = "imv.desktop"; + video = "mpv.desktop"; + explorer = "thunar.desktop"; + in { + "application/octet-stream" = editor; + "text/plain" = editor; + "x-scheme-handler/http" = browser; + "x-scheme-handler/https" = browser; + "x-scheme-handler/mailto" = email; + "application/pdf" = pdf; + "image/bmp" = image; + "image/jpeg" = image; + "image/gif" = image; + "image/png" = image; + "image/svg+xml" = image; + "image/webp" = image; + "inode/directory" = explorer; + "video/mp4" = video; + "video/mpeg" = video; + }; + }; + }; + + services = let + bluetooth = osConfig.my.desktop.bluetooth.enable; + networkManager = osConfig.my.networking.networkManager.enable; + in { + mpris-proxy.enable = bluetooth; + blueman-applet.enable = bluetooth; + network-manager-applet.enable = networkManager; + }; + + home = let + cursorSize = 36; + in { + pointerCursor = { + package = pkgs.catppuccin-cursors.mochaDark; + name = "catppuccin-mocha-dark-cursors"; + size = cursorSize; + gtk.enable = true; + }; + + sessionVariables = lib.mkIf config.my.graphical.wayland.hyprland.enable { + HYPRCURSOR_THEME = "catppuccin-mocha-dark"; + HYPRCURSOR_SIZE = cursorSize; + }; + }; + }; +} diff --git a/modules/home/graphical/dunst.nix b/modules/home/graphical/dunst.nix new file mode 100644 index 0000000..313a50e --- /dev/null +++ b/modules/home/graphical/dunst.nix @@ -0,0 +1,86 @@ +{ pkgs, config, lib, theme, inputs, self, ... }: + +let + cfg = config.my.graphical.dunst; +in { + options.my.graphical.dunst = { + enable = lib.mkEnableOption null; + }; + + config = lib.mkIf cfg.enable (let + volumeTag = "my-volume"; + brightnessTag = "my-brightness"; + dunstify = "${config.services.dunst.package}/bin/dunstify"; + dunstVolume = let + wpctl = "${pkgs.wireplumber}/bin/wpctl"; + in pkgs.writeShellScriptBin "dunst-volume" '' + SINK="''${3:-@DEFAULT_AUDIO_SINK@}" + ${wpctl} "$1" $SINK "$2" + VOLUME_DATA="$(${wpctl} get-volume $SINK)" + VOLUME="$(awk '{print 100*$2}' <<< "$VOLUME_DATA")" + if grep -q '\[MUTED\]' <<< "$VOLUME_DATA"; then + exec ${dunstify} -u low -t 1000 -i audio-volume-muted \ + -h "string:x-dunst-stack-tag:${volumeTag}" \ + -h "int:value:$VOLUME" \ + "Volume: $VOLUME%" "(muted)" + else + if (( "$VOLUME" >= 75 )); then + ICON=high + elif (( "$VOLUME" <= 25 )); then + ICON=low + else + ICON=medium + fi + exec ${dunstify} -u low -t 1000 -i "audio-volume-$ICON" \ + -h "string:x-dunst-stack-tag:${volumeTag}" \ + -h "int:value:$VOLUME" \ + "Volume: $VOLUME%" + fi + ''; + dunstBrightness = let + brightnessctl = "${pkgs.brightnessctl}/bin/brightnessctl"; + in pkgs.writeShellScriptBin "dunst-brightness" '' + ${brightnessctl} set "$1" + BRIGHTNESS="$(awk -F , '{print 100*$3/$5}' <<< "$(${brightnessctl} info -m)")" + exec ${dunstify} -u low -t 1000 \ + -h "string:x-dunst-stack-tag:${brightnessTag}" \ + -h "int:value:$BRIGHTNESS" \ + "Brightness: $BRIGHTNESS%" + ''; + in { + home.packages = [ + dunstVolume + dunstBrightness + ]; + services.dunst = { + enable = true; + iconTheme = { + inherit (config.gtk.iconTheme) name package; + size = "24x24"; + }; + settings = with theme; { + global = { + background = "#${base}"; + foreground = "#${text}"; + highlight = "#${lavender}"; + frame_color = "#${peach}"; + separator_color = "frame"; + corner_radius = 10; + offset = "10x50"; + font = "Inter 11"; + dmenu = "${pkgs.fuzzel}/bin/fuzzel -d"; + browser = "${pkgs.xdg-utils}/bin/xdg-open"; + }; + volume_tag = { + stack_tag = "${volumeTag}"; + history_ignore = true; + }; + brightness_tag = { + stack_tag = "${brightnessTag}"; + history_ignore = true; + }; + urgency_critical.frame_color = "#${yellow}"; + }; + }; + }); +} diff --git a/modules/home/graphical/emacs.nix b/modules/home/graphical/emacs.nix new file mode 100644 index 0000000..07eb19f --- /dev/null +++ b/modules/home/graphical/emacs.nix @@ -0,0 +1,212 @@ +{ pkgs, lib, config, inputs, ... }: + +let + cfg = config.my.graphical.emacs; +in { + options.my.graphical.emacs = { + enable = lib.mkEnableOption null; + }; + + config = lib.mkIf cfg.enable (let + inherit (inputs.emacs-overlay.overlays.package null pkgs) emacsPackagesFor; + extraEpkgsMap = epkgs: extraEpkgList: map (extraEpkg: extraEpkg epkgs) extraEpkgList; + org-modern-indent = epkgs: epkgs.trivialBuild rec { + pname = "org-modern-indent"; + version = "f2b859bc53107b2a1027b76dbf4aaebf14c03433"; + src = pkgs.fetchFromGitHub { + owner = "jdtsmith"; + repo = pname; + rev = version; + hash = "sha256-vtbaa3MURnAI1ypLueuSfgAno0l51y3Owb7g+jkK6JU="; + }; + propagatedUserEnvPkgs = with epkgs; [ compat ]; + buildInputs = propagatedUserEnvPkgs; + }; + eglot-booster = epkgs: epkgs.trivialBuild rec { + pname = "eglot-booster"; + version = "e19dd7ea81bada84c66e8bdd121408d9c0761fe6"; + src = pkgs.fetchFromGitHub { + owner = "jdtsmith"; + repo = pname; + rev = version; + hash = "sha256-vF34ZoUUj8RENyH9OeKGSPk34G6KXZhEZozQKEcRNhs="; + }; + propagatedUserEnvPkgs = []; + }; + extraPackages = epkgs: with epkgs; [ + f + dash + dashboard + undo-fu + god-mode + multiple-cursors + expand-region + avy + lispy + ace-window + goggles + dtrt-indent + aggressive-indent + rainbow-delimiters + highlight-indent-guides + which-key + eglot-java + yasnippet + yasnippet-snippets + consult + consult-yasnippet + embark + embark-consult + orderless + marginalia + vertico + corfu + cape + all-the-icons + all-the-icons-completion + treemacs + treemacs-all-the-icons + doom-modeline + minions + dirvish + pdf-tools + engrave-faces + org-modern + djvu + nov + org-pdftools + org-alert + editorconfig + envrc + sly + sly-asdf + sly-named-readtables + racket-mode + haskell-mode + lua-mode + nix-mode + gdscript-mode + markdown-mode + csv-mode + meson-mode + jinx + minimap + magit + forge + eat + mpv + lingva + mastodon + circe + circe-notifications + elfeed + xkcd + page-break-lines + hl-todo + ligature + gruvbox-theme + catppuccin-theme + solaire-mode + with-editor + nyan-mode + mu4e + org-msg + emacs-everywhere + treesit-grammars.with-all-grammars + ] ++ extraEpkgsMap epkgs [ + eglot-booster + org-modern-indent + ]; + alternateEmacsclient = pkgs.writeShellScript "alternate-emacsclient" '' + ${pkgs.systemd}/bin/systemctl --user start emacs.service && \ + exec ${config.programs.emacs.finalPackage}/bin/emacsclient -c -a "" "$@" + ''; + in { + programs.emacs = { + enable = true; + package = (emacsPackagesFor pkgs.emacs29-pgtk).emacsWithPackages extraPackages; + }; + services.emacs = { + enable = true; + startWithUserSession = "graphical"; + }; + home = { + sessionVariables.ALTERNATE_EDITOR = alternateEmacsclient; + packages = with pkgs; [ + emacs-lsp-booster + emacs-all-the-icons-fonts + gdb + clang-tools + nil + nodePackages.typescript-language-server + ghc + stylish-haskell + haskell-language-server + hunspellDicts.en-us + imagemagick + (texlive.combine { + inherit (texlive) scheme-basic + dvisvgm dvipng # Preview and export as html + wrapfig amsmath ulem hyperref capt-of + # Export code with engraved backend + fvextra etoolbox fancyvrb upquote lineno + tcolorbox pgf environ pdfcol + xcolor float + nopageno; + }) + pandoc + ]; + file.".clang-format".text = '' + --- + BasedOnStyle: LLVM + IndentWidth: 4 + TabWidth: 4 + UseTab: Always + ... + ''; + }; + xdg.desktopEntries = let + extendDefault = lib.recursiveUpdate { + icon = "emacs"; + terminal = false; + type = "Application"; + settings.Keywords = "emacsclient;"; + actions = { + new-window.name = "New Window"; + new-instance.name = "New Instance"; + }; + }; + in { + emacsclient = extendDefault rec { + name = "Emacs (Client)"; + exec = "${config.programs.emacs.finalPackage}/bin/emacsclient -a ${alternateEmacsclient} -c %F"; + genericName = "Text Editor"; + comment = "Edit text"; + mimeType = ["text/english" "text/plain" ]; + categories = [ "Development" "TextEditor" ]; + startupNotify = true; + settings.StartupWMClass = "Emacs"; + actions = { + new-window = {inherit exec;}; + new-instance.exec = "${config.programs.emacs.finalPackage}/bin/emacs %F"; + }; + }; + emacsclient-mail = extendDefault rec { + name = "Emacs (Mail, Client)"; + exec = (pkgs.writeShellScript "emacsclient-mail" '' + u=''${1//\\/\\\\} + u=''${u//\"/\\\"} + exec ${config.programs.emacs.finalPackage}/bin/emacsclient -a ${alternateEmacsclient} -c \ + --eval "(message-mailto \"$u\")" + '') + " %u"; + comment = "GNU Emacs is an extensible, customizable text editor - and more"; + mimeType = [ "x-scheme-handler/mailto" ]; + noDisplay = true; + actions = { + new-window = {inherit exec;}; + new-instance.exec = "${config.programs.emacs.finalPackage}/bin/emacs -f message-mailto %u"; + }; + }; + }; + }); +} diff --git a/modules/home/graphical/firefox.nix b/modules/home/graphical/firefox.nix new file mode 100644 index 0000000..d64fef2 --- /dev/null +++ b/modules/home/graphical/firefox.nix @@ -0,0 +1,140 @@ +{ pkgs, config, lib, self, ... }: + +let + cfg = config.my.graphical.firefox; +in { + options.my.graphical.firefox = { + enable = lib.mkEnableOption null; + }; + + config = lib.mkIf cfg.enable { + programs.firefox = { + enable = true; + policies = { + DisableFirefoxStudies = true; + DisablePocket = true; + DisableFirefoxAccounts = true; + DisableProfileImport = true; + DisplayBookmarksToolbar = "never"; + NoDefaultBookmarks = true; + OfferToSaveLogins = false; + DontCheckDefaultBrowser = true; + UserMessaging = { + ExtensionRecommendations = false; + SkipOnboarding = true; + }; + ExtensionSettings = let + mozillaExtensions = { + buster-captcha-solver = "{e58d3966-3d76-4cd9-8552-1582fbc800c1}"; + clearurls = "{74145f27-f039-47ce-a470-a662b129930a}"; + search_by_image = "{2e5ff8c8-32fe-46d0-9fc8-6b8986621f3c}"; + styl-us = "{7a7a4a92-a2a0-41d1-9fd7-1e92480d612d}"; + traduzir-paginas-web = "{036a55b4-5e72-4d05-a06c-cba2dfcc134a}"; + violentmonkey = "{aecec67f-0d10-4fa7-b7c7-609a2db280cf}"; + indie-wiki-buddy = "{cb31ec5d-c49a-4e5a-b240-16c767444f62}"; + sponsorblock = "sponsorBlocker@ajay.app"; + tabcenter-reborn = "tabcenter-reborn@ariasuni"; + ublock-origin = "uBlock0@raymondhill.net"; + firefox-color = "FirefoxColor@mozilla.com"; + } // lib.optionalAttrs config.my.keepassxc.enable { + keepassxc-browser = "keepassxc-browser@keepassxc.org"; + }; + in builtins.mapAttrs (_: url: { + install_url = url; + installation_mode = "force_installed"; + }) (lib.mapAttrs' (name: id: + lib.nameValuePair id "https://addons.mozilla.org/firefox/downloads/latest/${name}/latest.xpi" + ) mozillaExtensions); + }; + profiles.errie = { + settings = { + "browser.aboutConfig.showWarning" = false; + "browser.cache.disk.enable" = false; + "browser.cache.memory.capacity" = 2000000; + "browser.ctrlTab.sortByRecentlyUsed" = false; + "browser.newtabpage.activity-stream.feeds.section.topstories" = false; + "browser.newtabpage.activity-stream.feeds.topsites" = false; + "browser.newtabpage.pinned" = []; + "browser.startup.page" = 3; + "cookiebanners.service.mode" = 1; + "cookiebanners.service.mode.privateBrowsing" = 1; + "devtools.selfxss.count" = 100; + "media.ffmpeg.vaapi.enabled" = true; + "privacy.webrtc.legacyGlobalIndicator" = false; + "toolkit.legacyUserProfileCustomizations.stylesheets" = true; + "ui.key.menuAccessKeyFocuses" = false; + "widget.wayland.fractional-scale.enabled" = true; + }; + search = { + default = "DuckDuckGo"; + force = true; + order = [ "DuckDuckGo" "SearXNG" "Google" ]; + engines = { + "SearXNG" = { + definedAliases = [ "@searxng" ]; + icon = "${self}/assets/searxng.svg"; + urls = [{ + template = "https://etsi.me/search"; + params = [{ + name = "q"; + value = "{searchTerms}"; + }]; + }]; + }; + "Nix Packages" = { + definedAliases = [ "@pkgs" "@nixpkgs" ]; + icon = "${pkgs.nixos-icons}/share/icons/hicolor/scalable/apps/nix-snowflake.svg"; + urls = [{ + template = "https://search.nixos.org/packages"; + params = [ + { + name = "channel"; + value = "unstable"; + } + { + name = "type"; + value = "packages"; + } + { + name = "query"; + value = "{searchTerms}"; + } + ]; + }]; + }; + "Hoogle" = { + definedAliases = [ "@hoogle" ]; + urls = [{ + template = "https://hoogle.haskell.org/"; + params = [{ + name = "hoogle"; + value = "{searchTerms}"; + }]; + }]; + }; + } // lib.genAttrs [ "Bing" "Amazon.com" "eBay" ] (_: {metaData.hidden = true;}); + }; + userChrome = let + verticalTabs = pkgs.fetchzip { + url = "https://codeberg.org/ranmaru22/firefox-vertical-tabs/archive/v6.5.tar.gz"; + hash = "sha256-DHI8QFr4z00tlS8SlWrrNymP6pRQ55YHq6ZegDx5iYk="; + }; + in '' + @import url("file://${verticalTabs}/userChrome.css"); + + /* Hide the close button */ + .titlebar-buttonbox-container, + .titlebar-spacer[type="post-tabs"] + { + display: none !important; + } + + /* Remove padding on the right */ + #nav-bar { + --uc-navbar-padding: 0; + } + ''; + }; + }; + }; +} diff --git a/modules/home/graphical/keepassxc.nix b/modules/home/graphical/keepassxc.nix new file mode 100644 index 0000000..2d64d1f --- /dev/null +++ b/modules/home/graphical/keepassxc.nix @@ -0,0 +1,29 @@ +{ pkgs, config, lib, ... }: + +let + cfg = config.my.keepassxc; +in { + options.my.keepassxc = { + enable = lib.mkEnableOption null; + }; + + config = lib.mkIf cfg.enable { + home.packages = [ pkgs.keepassxc ]; + + systemd.user.services.keepassxc = { + Unit = { + Description = "KeePassXC password manager"; + After = [ "graphical-session-pre.target" "tray.target" "eww-bar.service" ]; + PartOf = [ "graphical-session.target" ]; + Requires = [ "tray.target" ]; + }; + Service = { + ExecStart = "${pkgs.keepassxc}/bin/keepassxc"; + Environment = "QT_QPA_PLATFORM=wayland"; + }; + Install = { + WantedBy = [ "graphical-session.target" ]; + }; + }; + }; +} diff --git a/modules/home/graphical/kitty.nix b/modules/home/graphical/kitty.nix new file mode 100644 index 0000000..b0e7ecd --- /dev/null +++ b/modules/home/graphical/kitty.nix @@ -0,0 +1,28 @@ +{ config, lib, ... }: + +let + cfg = config.my.graphical.kitty; +in { + options.my.graphical.kitty = { + enable = lib.mkEnableOption null; + }; + + config = lib.mkIf cfg.enable { + programs.kitty = { + enable = true; + theme = "Catppuccin-Mocha"; + font = { + name = "JetBrainsMono Nerd Font"; + size = 11; + }; + keybindings = { + "ctrl+backspace" = "send_text all \\x1b\\x7f"; + }; + settings = { + window_margin_width = 5; + focus_follows_mouse = "yes"; + shell_integration = "no-cursor"; + }; + }; + }; +} diff --git a/modules/home/graphical/mangohud.nix b/modules/home/graphical/mangohud.nix new file mode 100644 index 0000000..9fe27ee --- /dev/null +++ b/modules/home/graphical/mangohud.nix @@ -0,0 +1,23 @@ +{ config, lib, ... }: + +let + cfg = config.my.graphical.mangohud; +in { + options.my.graphical.mangohud = { + enable = lib.mkEnableOption null; + }; + + config = lib.mkIf cfg.enable { + programs.mangohud = { + enable = true; + enableSessionWide = true; + settings = { + no_display = true; + vsync = 0; + full = true; + output_folder = "${config.xdg.cacheHome}/mangohud"; + toggle_hud = "Shift_R+BackSpace"; + }; + }; + }; +} diff --git a/modules/home/graphical/mpv.nix b/modules/home/graphical/mpv.nix new file mode 100644 index 0000000..21e5e47 --- /dev/null +++ b/modules/home/graphical/mpv.nix @@ -0,0 +1,38 @@ +{ pkgs, config, lib, ... }: + +let + cfg = config.my.graphical.mpv; +in { + options.my.graphical.mpv = { + enable = lib.mkEnableOption null; + }; + + config = lib.mkIf cfg.enable { + programs.mpv = { + enable = true; + scripts = with pkgs.mpvScripts; [ + mpris + sponsorblock + thumbfast + uosc + ]; + bindings = { + tab = "script-binding uosc/flash-ui"; + }; + config = { + ao = "pipewire,"; + osd-bar = false; + border = false; + }; + scriptOpts = { + uosc = { + top_bar_controls = false; + top_bar_title = "\${media-title}"; + top_bar_alt_title = "\${filename}"; + top_bar_alt_title_place = "below"; + }; + thumbfast.hwdec = true; + }; + }; + }; +} diff --git a/modules/home/graphical/obs.nix b/modules/home/graphical/obs.nix new file mode 100644 index 0000000..d95e1bc --- /dev/null +++ b/modules/home/graphical/obs.nix @@ -0,0 +1,20 @@ +{ pkgs, config, lib, ... }: + +let + cfg = config.my.graphical.obs; +in { + options.my.graphical.obs = { + enable = lib.mkEnableOption null; + }; + + config = lib.mkIf cfg.enable { + programs.obs-studio = { + enable = true; + plugins = with pkgs.obs-studio-plugins; [ + wlrobs + obs-vkcapture + obs-vaapi + ]; + }; + }; +} diff --git a/modules/home/graphical/qtk.nix b/modules/home/graphical/qtk.nix new file mode 100644 index 0000000..4054620 --- /dev/null +++ b/modules/home/graphical/qtk.nix @@ -0,0 +1,67 @@ +{ pkgs, config, lib, ... }: + +let + cfg = config.my.graphical; +in { + options.my.graphical = { + qt.enable = lib.mkEnableOption null // { + default = true; + }; + gtk = { + enable = lib.mkEnableOption null // { + default = true; + }; + emacsKeys.enable = lib.mkEnableOption null; + }; + }; + + config = lib.mkIf cfg.enable (lib.mkMerge [ + (lib.mkIf cfg.qt.enable { + qt = { + enable = true; + platformTheme.name = "gtk3"; + }; + }) + + (lib.mkIf cfg.gtk.enable { + dconf.settings = { + "org/gnome/desktop/interface" = { + color-scheme = "prefer-dark"; + gtk-key-theme = lib.mkIf (cfg.gtk.emacsKeys.enable) "Emacs"; + }; + }; + + gtk = { + enable = true; + font = { + package = pkgs.inter; + name = "Inter"; + size = 11; + }; + iconTheme = { + package = pkgs.catppuccin-papirus-folders.override { + flavor = "mocha"; + accent = "lavender"; + }; + name = "Papirus-Dark"; + }; + theme = { + package = pkgs.catppuccin-gtk.override { + accents = [ "lavender" ]; + size = "compact"; + tweaks = [ "rimless" ]; + variant = "mocha"; + }; + name = "catppuccin-mocha-lavender-compact+rimless"; + }; + } // lib.optionalAttrs cfg.gtk.emacsKeys.enable { + gtk2.extraConfig = '' + gtk-key-theme-name = "Emacs" + ''; + gtk3.extraConfig = { + gtk-key-theme-name = "Emacs"; + }; + }; + }) + ]); +} diff --git a/modules/home/graphical/qutebrowser.nix b/modules/home/graphical/qutebrowser.nix new file mode 100644 index 0000000..c8b08b7 --- /dev/null +++ b/modules/home/graphical/qutebrowser.nix @@ -0,0 +1,90 @@ +{ pkgs, config, lib, ... }: + +let + cfg = config.my.graphical.qutebrowser; +in { + options.my.graphical.qutebrowser = { + enable = lib.mkEnableOption null; + }; + + config = lib.mkIf cfg.enable (let + mapLeader = ""; + in { + programs.qutebrowser = { + enable = true; + package = (pkgs.qutebrowser.override {enableWideVine = true;}).overrideAttrs (old: { + nativeBuildInputs = old.nativeBuildInputs or [] ++ [ pkgs.makeWrapper ]; + postInstall = old.postInstall or "" + '' + wrapProgram $out/bin/qutebrowser \ + --unset QT_QPA_PLATFORMTHEME + ''; + }); + aliases = { + bN = "tab-prev"; + bd = "tab-close"; + bn = "tab-next"; + bp = "tab-prev"; + h = "help"; + q = "close"; + qa = "quit"; + w = "session-save"; + wq = "quit --save"; + wqa = "quit --save"; + so = "config-source"; + "so%" = "config-source"; + }; + keyBindings = { + normal = { + "clc" = "set-cmd-text :open -t https://www.dl.cambridgescp.com/stage/clc/"; + "" = "tab-focus last"; + "" = "edit-text"; + "" = "fake-key "; + "" = "fake-key "; + "${mapLeader}" = '' + config-cycle statusbar.show in-mode always ;; \ + config-cycle tabs.show switching always \ + ''; + }; + insert = { + "" = "edit-text"; + "" = "fake-key "; + "" = "fake-key "; + }; + command."" = "rl-backward-kill-word"; + prompt."" = "rl-backward-kill-word"; + }; + settings = { + changelog_after_upgrade = "patch"; + auto_save = { + session = true; + interval = 15000; + }; + editor = { + command = [ + "/bin/sh" "-c" + '' + emacsclient -e '(require '\"'\"'emacs-everywhere nil :noerror)' && \ + emacsclient -c '+{line}:{column}' '{file}' \ + '' + ]; + remove_file = true; + }; + content.pdfjs = true; + scrolling.smooth = true; + colors.webpage.preferred_color_scheme = "dark"; + }; + extraConfig = '' + import catppuccin + catppuccin.setup(c, 'mocha') + config.unbind('') + config.unbind('') + ''; + }; + xdg.configFile."qutebrowser/catppuccin".source = pkgs.fetchFromGitHub { + owner = "catppuccin"; + repo = "qutebrowser"; + rev = "6737f1c36a9d05be05b7961945e7028c0f70831f"; + sha256 = "0nv214p0k292y2gr5afcjvxnjs1ai78vnxyb7qzj1r4vk7r3nh0k"; + }; + }); +} diff --git a/modules/home/graphical/wayland/default.nix b/modules/home/graphical/wayland/default.nix new file mode 100644 index 0000000..cf06be8 --- /dev/null +++ b/modules/home/graphical/wayland/default.nix @@ -0,0 +1,38 @@ +{ pkgs, config, lib, inputs, ... }: + +let + cfg = config.my.graphical.wayland; +in { + imports = [ + ./eww + ./hyprland.nix + ./hyprlock.nix + ./swaylock.nix + ./swayidle.nix + ./gammastep.nix + ./kanshi.nix + ./gestures.nix + ./ydotool.nix + ./foot.nix + ./fuzzel.nix + ]; + + options.my.graphical.wayland = { + enable = lib.mkEnableOption null; + }; + + config = lib.mkIf cfg.enable { + home = { + packages = (with pkgs; [ + wl-clipboard + grim + slurp + wev + gamescope + inputs.my-nix-packages.packages.${system}.geticons + ]); + + sessionVariables.NIXOS_OZONE_WL = "1"; + }; + }; +} diff --git a/modules/home/graphical/wayland/eww/default.nix b/modules/home/graphical/wayland/eww/default.nix new file mode 100644 index 0000000..6850536 --- /dev/null +++ b/modules/home/graphical/wayland/eww/default.nix @@ -0,0 +1,83 @@ +{ pkgs, config, lib, self, theme, ... }: + +let + cfg = config.my.graphical.wayland.eww; +in { + options.my.graphical.wayland.eww = { + enable = lib.mkEnableOption null; + }; + + config = let + inherit (pkgs) eww; + in lib.mkIf cfg.enable { + home.packages = [ eww ]; + + xdg.configFile = builtins.mapAttrs (name: src: { + source = pkgs.substituteAll ({ + inherit src; + acpi = "${pkgs.acpi}/bin/acpi"; + hyprctl = "${config.wayland.windowManager.hyprland.package}/bin/hyprctl"; + ruby = "${pkgs.ruby}/bin/ruby"; + soyjak = "${self}/assets/pointingSoyjaks.png"; + } // theme); + target = "eww/${name}"; + executable = builtins.match "\\./scripts/.*" name != null; + }) (self.lib.filterNixReadDir ./.) // { + "eww/_mocha.scss".text = builtins.concatStringsSep "\n" + (lib.mapAttrsToList (name: value: "\$${name}: #${value};") theme); + }; + + wayland.windowManager.hyprland.settings = let + inherit (config.my.graphical.wayland.hyprland) mainMod; + toggleSoyjaks = pkgs.writeShellScript "toggle-soyjaks" '' + if ${eww}/bin/eww active-windows | ${pkgs.gnugrep}/bin/grep -q 'soyjak-layer'; then + ${eww}/bin/eww close soyjak-layer + else + ${eww}/bin/eww open soyjak-layer + fi + ''; + in { + bind = [ + "${mainMod} CTRL, S, exec, ${toggleSoyjaks}" + ]; + }; + + systemd.user = { + services = { + eww = { + Unit = { + Description = "Eww background daemon"; + partOf = [ "tray.target" ]; + }; + Service = { + Environment = "PATH=${lib.makeBinPath (with pkgs; [ coreutils bash ])}"; + ExecStart = "${eww}/bin/eww daemon --no-daemonize"; + }; + Install = { + WantedBy = [ "tray.target" ]; + }; + }; + + eww-bar = { + Unit = { + Description = "Eww bar"; + After = "eww.service"; + }; + Service = { + Type = "oneshot"; + ExecStart = pkgs.writeShellScript "eww-bar-open" '' + # Lack of quotes intentional + exec ${eww}/bin/eww open-many \ + $(${config.wayland.windowManager.hyprland.package}/bin/hyprctl monitors -j | \ + ${pkgs.jaq}/bin/jaq -r '.[] | .id' | \ + ${pkgs.gnused}/bin/sed 's/^/bar/') + ''; + }; + Install = { + WantedBy = [ "eww.service" ]; + }; + }; + }; + }; + }; +} diff --git a/modules/home/graphical/wayland/eww/eww.scss b/modules/home/graphical/wayland/eww/eww.scss new file mode 100644 index 0000000..9487b7e --- /dev/null +++ b/modules/home/graphical/wayland/eww/eww.scss @@ -0,0 +1,98 @@ +@import "mocha"; + +button, menubar, menubar > menuitem { + all: unset; +} + +.bar-wrap > * { + border-radius: 10px; + margin: 10px; +} + +.bar-main { + font-family: "Jost"; + font-size: 16px; + background-color: $base; + color: $text; +} + +.workspaces > button { + border-style: solid; + border-width: 6px 0 0 0; + &:hover { + background-color: $surface0; + } + &.nonexistent { + border-color: transparent; + } + &.existing { + border-color: $surface1; + &:hover { + border-color: $overlay1; + } + } + &.active { + border-color: $rosewater; + } +} + +.title { + font-size: 14px; +} + +.bar-end > * { + margin-right: 30px; +} + +.tray > menuitem { + margin-right: 15px; + & menu { + background-color: $mantle; + } +} + +@mixin battery-color($property) { + #{$property}: $text; + .battery-low & { + #{$property}: $red; + } +} + +.battery-tip { + @include battery-color(background-color); +} + +.battery-box { + border-style: solid; + border-width: 2px; + @include battery-color(border-color); +} + +.battery-val { + margin: 2px; + @include battery-color(background-color); + .battery-charging & { + background-color: $green; + } +} + +.power { + font-family: "Jetbrains Mono Nerd Font"; + font-size: 30px; + color: $red; + transition: color, background-color 0.15s; + &:hover { + background-color: $red; + color: $base; + } +} + +tooltip { + color: $text; + background-color: rgba($crust, 1); + border-radius: 7px; +} + +.soyjak-layer { + background-color: transparent; +} diff --git a/modules/home/graphical/wayland/eww/eww.yuck b/modules/home/graphical/wayland/eww/eww.yuck new file mode 100644 index 0000000..f08eaea --- /dev/null +++ b/modules/home/graphical/wayland/eww/eww.yuck @@ -0,0 +1,149 @@ +;;; Eww config + +(defpoll time + :interval "5s" + "date '+%l:%M %p'") + +(defpoll date + :interval "1m" + "date '+%D'") + +(defpoll acpi + :interval "20s" + :initial "" + "@acpi@ -b") + +(deflisten hyprlisten + :initial "{ + \"workspaces\": ${jq(10, `[{active: false, existing: false, id: range(.) + 1}]`)}, + \"title\": \"\" +}" + "scripts/hyprlisten.rb") + +(defwindow bar0 + :monitor 0 + :geometry (geometry :height "42px" + :width "1920px" + :anchor "top center") + :stacking "fg" + (bar)) + +(defwindow bar1 + :monitor 1 + :geometry (geometry :height "42px" + :width "100%" + :anchor "top center") + :stacking "fg" + (bar)) + +(defwindow bar2 + :monitor 2 + :geometry (geometry :height "42px" + :width "100%" + :anchor "top center") + :stacking "fg" + (bar)) + +(defwidget bar-wrap [] + (box :class "bar-wrap" + :orientation "h" + (bar))) + +(defwidget bar [] + (box :class "bar-main" + :orientation "h" + (bar-start) + (bar-center) + (bar-end))) + +(defwidget bar-start [] + (box :class "bar-start" + :orientation "h" + :halign "start" + :space-evenly false + (workspaces))) + +(defwidget bar-center [] + (box :class "bar-center" + :orientation "h" + :halign "center" + (title))) + +(defwidget bar-end [] + (box :class "bar-end" + :orientation "h" + :halign "end" + :space-evenly false + (tray) + (battery) + (time))) + +(defwidget workspaces [] + (eventbox + :onscroll "@hyprctl@ dispatch focusworkspaceoncurrentmonitor e$([ \"{}\" = \"up\" ] && echo '-' || echo '+')1" + (box :class "workspaces" + :orientation "h" + :halign "start" + (for workspace in {hyprlisten.workspaces} + (button :class "${workspace.active ? 'active' : +(workspace.existing ? 'existing' : 'nonexistent')}" + :width 42 + :height 42 + :tooltip "Switch to Workspace ${workspace.id}" + :onclick "@hyprctl@ dispatch focusworkspaceoncurrentmonitor ${workspace.id}" + {workspace.id}))))) + +(defwidget title [] + (label :class "title" + :limit-width 70 + :text {hyprlisten.title})) + +(defwidget tray [] + (systray :class "tray" + :icon-size 24 + :prepend-new true + :spacing 6)) + +(defwidget battery [] + (box :class "battery ${EWW_BATTERY.BAT1.status == 'Charging' ? 'battery-charging' : +(EWW_BATTERY.BAT1.capacity <= 20 ? 'battery-low' : '')}" + :orientation "h" + :tooltip acpi + (box :class "battery-box" + :valign "center" + :width 28 + :height 14 + (box :class "battery-val" + :halign "start" + :width {4 + round (EWW_BATTERY.BAT1.capacity / 5 , 0)})) + (box :class "battery-tip" + :halign "start" + :valign "center" + :width 3 + :height 6))) + +(defwidget time [] + (box :class "time" + :tooltip date + time)) + +(defwidget power [] + (eventbox :class "power" + :width 42 + :cursor "pointer" + :onclick "wlogout -p layer-shell &" + :tooltip "Logout options" + "襤")) + +(defwindow soyjak-layer + :monitor 0 + :geometry (geometry :width "100%" + :height "100%" + :anchor "bottom left") + :stacking "overlay" + (soyjak)) + +(defwidget soyjak [] + (image :path "@soyjak@" + :image-width 1920 + :image-height 1080)) diff --git a/modules/home/graphical/wayland/eww/scripts/hyprlisten.rb b/modules/home/graphical/wayland/eww/scripts/hyprlisten.rb new file mode 100755 index 0000000..158cc1a --- /dev/null +++ b/modules/home/graphical/wayland/eww/scripts/hyprlisten.rb @@ -0,0 +1,75 @@ +#!@ruby@ +# frozen_string_literal: true + +require 'socket' +require 'json' + +$stdout.sync = true + +SOCK_DIR = "#{ENV['XDG_RUNTIME_DIR']}/hypr/#{ENV['HYPRLAND_INSTANCE_SIGNATURE']}" +SOCK1 = "#{SOCK_DIR}/.socket.sock" +SOCK2 = "#{SOCK_DIR}/.socket2.sock" + +def hyprctl(cmd) + Socket.unix(SOCK1) do |s| + s.print cmd + s.read.force_encoding('UTF-8') + end +end + +class Workspaces + attr_reader :data + + def initialize + @active = JSON.parse(hyprctl('j/monitors')).detect { |m| m['focused'] }['activeWorkspace']['id'] + existing = JSON.parse(hyprctl('j/workspaces')).to_h { |w| [w['id'], true] } + @data = (1..9).map { |id| {id: id, active: id == @active, existing: !!existing[id]} } + end + + def update_active(workspace) + workspace = workspace.to_i + update_val(@active, active: false) + update_val(workspace, active: true) + @active = workspace + end + + def update_val(workspace, **kwargs) + @data[workspace - 1].merge!(kwargs) if workspace.between?(1, 9) + end +end + +class State + def initialize(**kwargs) + @data = kwargs + end + + def update(**kwargs) + @data.merge!(kwargs) + end + + def to_s + JSON.fast_generate(@data) + end +end + +Socket.unix(SOCK2) do |socket| + ws = Workspaces.new + state = State.new( + title: JSON.parse(hyprctl('j/activewindow'))['title'] || '', + workspaces: ws.data, + ) + puts state + while (line = socket.gets) + event, data = line.split('>>', 2) + case event + when 'activewindow' then state.update(title: data.chomp.split(',', 2).last) + when 'closewindow' then state.update(title: '') + when 'workspace' then ws.update_active(data.chomp) + when 'focusedmon' then ws.update_active(data.chomp.split(',', 2).last) + when 'createworkspace' then ws.update_val(data.chomp.to_i, existing: true) + when 'destroyworkspace' then ws.update_val(data.chomp.to_i, existing: false) + else next + end + puts state + end +end diff --git a/modules/home/graphical/wayland/foot.nix b/modules/home/graphical/wayland/foot.nix new file mode 100644 index 0000000..e2a5b95 --- /dev/null +++ b/modules/home/graphical/wayland/foot.nix @@ -0,0 +1,51 @@ +{ config, lib, theme, ... }: + +let + cfg = config.my.graphical.wayland.foot; +in { + options.my.graphical.wayland.foot = { + enable = lib.mkEnableOption null; + }; + + config = lib.mkIf cfg.enable (let + loweredTheme = builtins.mapAttrs (_: lib.toLower) theme; + in { + programs.foot = { + enable = true; + settings = { + main = { + font = "JetbrainsMono Nerd Font:size=11"; + pad = "5x5 center"; + }; + scrollback = { + indicator-position = "fixed"; + indicator-format = "percentage"; + }; + cursor.color = with loweredTheme; "${base} ${rosewater}"; + text-bindings = { + "\\x1b\\x7f" = "Control+BackSpace"; + }; + colors = with loweredTheme; rec { + foreground = text; + background = base; + regular0 = surface1; + regular1 = red; + regular2 = green; + regular3 = yellow; + regular4 = blue; + regular5 = pink; + regular6 = teal; + regular7 = subtext1; + bright0 = regular0; + bright1 = regular1; + bright2 = regular2; + bright3 = regular3; + bright4 = regular4; + bright5 = regular5; + bright6 = regular6; + bright7 = regular7; + }; + }; + }; + }); +} diff --git a/modules/home/graphical/wayland/fuzzel.nix b/modules/home/graphical/wayland/fuzzel.nix new file mode 100644 index 0000000..709fb18 --- /dev/null +++ b/modules/home/graphical/wayland/fuzzel.nix @@ -0,0 +1,46 @@ +{ pkgs, config, lib, theme, ... }: + +let + cfg = config.my.graphical.wayland.fuzzel; +in { + options.my.graphical.wayland.fuzzel = { + enable = lib.mkEnableOption null; + }; + + config = lib.mkIf cfg.enable { + home.packages = [ pkgs.fuzzel ]; + xdg.configFile."fuzzel/fuzzel.ini".text = lib.generators.toINI { } { + main = { + font = "DejaVu Sans Mono:size=13"; + icon-theme = "Papirus-Dark"; + show-actions = true; + terminal = "${config.programs.foot.package}/bin/foot -e"; + width = 80; + horizontal-pad = 60; + vertical-pad = 30; + inner-pad = 20; + line-height = 24; + }; + colors = builtins.mapAttrs (_: val: "${val}FF") (with theme; { + background = mantle; + text = overlay2; + match = lavender; + selection = surface0; + selection-text = text; + selection-match = mauve; + border = mauve; + }); + key-bindings = { + cursor-left = "Left Control+b Mod1+h"; + cursor-right = "Right Control+f Mod1+l"; + delete-prev = "BackSpace Control+h"; + delete-prev-word = "Mod1+BackSpace Control+BackSpace Control+w"; + prev = "Up Control+p Mod1+k"; + prev-page = "KP_Prior Mod1+v"; + next = "Down Control+n Mod1+j"; + next-page = "KP_Next Control+v"; + }; + border.width = 3; + }; + }; +} diff --git a/modules/home/graphical/wayland/gammastep.nix b/modules/home/graphical/wayland/gammastep.nix new file mode 100644 index 0000000..371bb10 --- /dev/null +++ b/modules/home/graphical/wayland/gammastep.nix @@ -0,0 +1,26 @@ +{ config, lib, ... }: + +let + cfg = config.my.graphical.wayland.gammastep; +in { + options.my.graphical.wayland.gammastep = { + enable = lib.mkEnableOption null; + }; + + config = lib.mkIf cfg.enable { + services.gammastep = { + enable = true; + provider = "geoclue2"; + temperature = { + day = 6500; + night = 2750; + }; + settings = { + general = { + fade = 1; + adjustment-method = "wayland"; + }; + }; + }; + }; +} diff --git a/modules/home/graphical/wayland/gestures.nix b/modules/home/graphical/wayland/gestures.nix new file mode 100644 index 0000000..1d21b93 --- /dev/null +++ b/modules/home/graphical/wayland/gestures.nix @@ -0,0 +1,29 @@ +{ pkgs, config, lib, ... }: + +let + cfg = config.my.graphical.wayland.gestures; +in { + options.my.graphical.wayland.gestures = { + enable = lib.mkEnableOption null; + }; + + config = lib.mkIf cfg.enable { + xdg.configFile = let + serviceName = "libinput-gestures.service"; + service = "${pkgs.libinput-gestures}/share/systemd/user/${serviceName}"; + in { + "systemd/user/${serviceName}".source = service; + "systemd/user/hyprland-session.target.wants/${serviceName}".source = service; + "libinput-gestures.conf" = { + text = let + hyprctl = "${config.wayland.windowManager.hyprland.package}/bin/hyprctl"; + in '' + gesture pinch in 4 ${hyprctl} dispatch killactive + ''; + onChange = '' + ${pkgs.systemd}/bin/systemctl --user restart ${serviceName} + ''; + }; + }; + }; +} diff --git a/modules/home/graphical/wayland/hyprland.nix b/modules/home/graphical/wayland/hyprland.nix new file mode 100644 index 0000000..9d50717 --- /dev/null +++ b/modules/home/graphical/wayland/hyprland.nix @@ -0,0 +1,445 @@ +{ pkgs, inputs, config, lib, self, osConfig, theme, ... }: + +let + cfg = config.my.graphical.wayland.hyprland; +in { + options.my.graphical.wayland.hyprland = { + enable = lib.mkEnableOption null; + tearing = lib.mkEnableOption null; + mainMod = lib.mkOption { + type = lib.types.str; + default = "SUPER"; + }; + lockBinary = lib.mkOption { + type = lib.types.str; + }; + wallpaper = { + enable = lib.mkEnableOption null // { + default = true; + }; + backend = lib.mkOption { + type = lib.types.enum [ "hyprpaper" "swaybg" ]; + default = "swaybg"; + }; + image = lib.mkOption { + type = lib.types.pathInStore; + default = "${self}/assets/snowyMountain.jpg"; + }; + }; + }; + + config = lib.mkIf cfg.enable (let + toggleOption = pkgs.writeShellScriptBin "hypr-toggle-opt" '' + hyprctl keyword "$1" "$(hyprctl getoption "$1" -j | ${pkgs.jaq}/bin/jaq '1 - .int')" + ''; + copyOutput = pkgs.writeShellScript "hypr-copy-output" '' + MONITOR="$(hyprctl monitors -j | ${pkgs.jaq}/bin/jaq -r '.[] | select(.focused).name')" + grim -o "$MONITOR" - | wl-copy -t image/png + ''; + copyWindow = pkgs.writeShellScript "hypr-copy-window" '' + WINDOW="$(hyprctl activewindow -j | ${pkgs.jaq}/bin/jaq -r '.address')" + grim -w "$WINDOW" - | wl-copy -t image/png + ''; + winShiftS = with pkgs; writeShellScriptBin "win-shift-s" '' + FILENAME="/tmp/win-shift-s-$PPID.png" + MONITOR="$(hyprctl monitors -j | ${_ jaq} -r '.[] | select(.focused)')" + ${_ grim} -o "$(${_ jaq} -r '.name' <<< "$MONITOR")" "$FILENAME" + ${_ imv} -f "$FILENAME" & IMV_PROC=$! + DIMENSIONS="$(${_ slurp} -f '%wx%h+%X+%Y')" + [ "$?" -eq 0 ] && \ + ${_ imagemagick} "$FILENAME" -crop "$DIMENSIONS" - | \ + ${wl-clipboard}/bin/wl-copy -t image/png + kill $IMV_PROC + exec rm "$FILENAME" + ''; + timeWindow = let + inherit (inputs.cl-hyprland-ipc.packages.${pkgs.system}) cl-hyprland-ipc; + inherit (cl-hyprland-ipc) asdfFasl faslExt; + sbclWithPackages = pkgs.sbcl.withPackages (_: [ cl-hyprland-ipc ]); + in pkgs.runCommand "time-window" { } '' + ${sbclWithPackages}/bin/sbcl --load ${asdfFasl}/asdf.${faslExt} \ + --load ${../../scripts/time-window.lisp} \ + --eval '(setf uiop:*image-entry-point* #'\''\''time-window:main)' \ + --eval '(uiop:dump-image "time-window" :executable t :compression t)' + mkdir -p $out/bin + cp time-window $out/bin + ''; + in { + home.packages = [ + toggleOption + timeWindow + ]; + + wayland.windowManager.hyprland = let + c = builtins.mapAttrs (_: t: "0xFF${t}") theme; + inherit (cfg) mainMod; + activeBorder = "${c.peach} ${c.mauve} 45deg"; + transparent = "0x00000000"; + in { + enable = true; + package = osConfig.programs.hyprland.package; + settings = { + exec-once = lib.optional (!osConfig.my.fs.luks.enable) "${pkgs.writeShellScript "start-hyprland" '' + [ -n "$GREETD_SOCK" ] && ${pkgs.swaylock-effects}/bin/swaylock ${ + lib.optionalString cfg.wallpaper.enable "-i ${cfg.wallpaper.image}" + } & + ''}"; + + env = [ ] + ++ lib.optional config.my.graphical.emacs.enable "VISUAL, emacsclient -c"; + + monitor = [ + "eDP-1, preferred, 0x0, 1.33" + ", preferred, auto, 1" + + # Manually reserved area for bar + ", addreserved, 42, 0, 0, 0" + ]; + + input = { + kb_layout = "us"; + repeat_delay = 300; + repeat_rate = 20; + float_switch_override_focus = 2; + + touchpad = { + natural_scroll = true; + scroll_factor = 0.3; + }; + }; + + general = { + layout = "dwindle"; + allow_tearing = cfg.tearing; + gaps_in = 5; + gaps_out = 13; + border_size = 3; + "col.active_border" = activeBorder; + "col.inactive_border" = transparent; + }; + + dwindle = { + force_split = 2; + preserve_split = true; + no_gaps_when_only = 1; + special_scale_factor = 0.9; + }; + + decoration = { + rounding = 11; + dim_special = 0; + drop_shadow = false; + + blur = { + enabled = false; + size = 8; + passes = 2; + + ignore_opacity = true; + xray = true; + + noise = 0; + contrast = 1; + brightness = 1; + }; + }; + + group = { + "col.border_active" = activeBorder; + "col.border_inactive" = transparent; + "col.border_locked_active" = c.red; + "col.border_locked_inactive" = transparent; + + groupbar = { + render_titles = false; + height = 3; + "col.active" = c.green; + "col.inactive" = transparent; + "col.locked_active" = c.red; + "col.locked_inactive" = transparent; + }; + }; + + animations = { + enabled = true; + + bezier = [ + "easeInSine, 0.12, 0, 0.39, 0" + "easeOutSine, 0.61, 1, 0.88, 1" + ]; + + animation = [ + "windowsIn, 1, 3, easeOutSine, slide" + "windowsOut, 1, 3, easeInSine, slide" + "windowsMove, 1, 2.5, easeOutSine, slide" + + "workspaces, 1, 2.5, easeOutSine, slide" + "specialWorkspace, 1, 6, default, slidevert" + + "fade, 0" + ]; + }; + + gestures = { + workspace_swipe = true; + }; + + binds = { + allow_workspace_cycles = true; + }; + + xwayland = { + use_nearest_neighbor = false; + force_zero_scaling = true; + }; + + misc = { + vrr = 1; + + disable_hyprland_logo = true; + disable_splash_rendering = true; + background_color = c.crust; + + disable_autoreload = true; + focus_on_activate = true; + animate_manual_resizes = false; + animate_mouse_windowdragging = false; + new_window_takes_over_fullscreen = 2; + + enable_swallow = false; + swallow_regex = "^(foot(client)?|kitty)$"; + }; + + windowrule = [ + "tile, ^(Aseprite)$" + "fullscreen, ^(Baba Is You|ADanceOfFireAndIce)$" + "float, ^(EverestSplash-linux)$" + "float, title:^(emacs-everywhere)$" + ] ++ lib.optional cfg.tearing + "immediate, ^(ADanceOfFireAndIce|Celeste|hollow_knight\\.x86_64|portal2_linux)$"; + + windowrulev2 = [ + "float, class:^(firefox)$, title:^(Picture-in-Picture)$" + "pin, class:^(firefox)$, title:^(Picture-in-Picture)$" + + "tile, class:^(Spotify)$, title:^(?!Ozone X11$).*$" + "float, class:^(Spotify)$, title:^$" + ]; + + bind = [ + "${mainMod}, Return, exec, foot" + "${mainMod}, C, killactive," + "${mainMod} SHIFT, C, exec, hyprctl activewindow -j | ${pkgs.jaq}/bin/jaq -r '.pid' | xargs kill -9" + "${mainMod}, E, exec, thunar" + "${mainMod}, M, exec, emacsclient -c" + "${mainMod} SHIFT, M, exec, emacsclient -e '(emacs-everywhere)'" + "${mainMod} SHIFT, Return, togglefloating," + + "${mainMod}, Space, fullscreen, 1" + "${mainMod} SHIFT, Space, fullscreen, 0" + + "${mainMod}, I, exec, dunstctl action" + "${mainMod} SHIFT, I, exec, dunstctl context" + "${mainMod} ALT, I, exec, dunstctl history-pop" + "${mainMod} CTRL, I, exec, dunstctl close" + + "${mainMod}, Semicolon, exec, killall fuzzel || fuzzel" + + "${mainMod}, Y, pin," + + # Groups + "${mainMod}, F, changegroupactive, f" + "${mainMod} SHIFT, F, togglegroup," + "${mainMod} CTRL, F, lockactivegroup, toggle" + + # Directions + "${mainMod}, Period, layoutmsg, preselect r" + "${mainMod}, Comma, layoutmsg, preselect d" + "${mainMod}, S, layoutmsg, togglesplit" + + # Moving windows (with groups) + "${mainMod} SHIFT, left, movewindoworgroup, l" + "${mainMod} SHIFT, right, movewindoworgroup, r" + "${mainMod} SHIFT, up, movewindoworgroup, u" + "${mainMod} SHIFT, down, movewindoworgroup, d" + "${mainMod} SHIFT, H, movewindoworgroup, l" + "${mainMod} SHIFT, L, movewindoworgroup, r" + "${mainMod} SHIFT, K, movewindoworgroup, u" + "${mainMod} SHIFT, J, movewindoworgroup, d" + + # Moving windows (without groups) + "${mainMod} ALT, left, movewindow, l" + "${mainMod} ALT, right, movewindow, r" + "${mainMod} ALT, up, movewindow, u" + "${mainMod} ALT, down, movewindow, d" + "${mainMod} ALT, H, movewindow, l" + "${mainMod} ALT, L, movewindow, r" + "${mainMod} ALT, K, movewindow, u" + "${mainMod} ALT, J, movewindow, d" + + # Workspaces + "${mainMod} CTRL, P, focusworkspaceoncurrentmonitor, previous" + "${mainMod} CTRL, N, focusworkspaceoncurrentmonitor, empty" + "${mainMod} CTRL SHIFT, P, movetoworkspace, previous" + "${mainMod} CTRL SHIFT, N, movetoworkspace, empty" + + # Screenshot + ", Print, exec, ${copyOutput}" + "ALT, Print, exec, ${copyWindow}" + "${mainMod} SHIFT, S, exec, grim -g \"$(slurp)\" - | wl-copy -t image/png" + + # Move focus + "${mainMod}, left, movefocus, l" + "${mainMod}, right, movefocus, r" + "${mainMod}, up, movefocus, u" + "${mainMod}, down, movefocus, d" + "${mainMod}, H, movefocus, l" + "${mainMod}, L, movefocus, r" + "${mainMod}, K, movefocus, u" + "${mainMod}, J, movefocus, d" + + # Switch workspaces with mainMod + [1-9] + "${mainMod}, 1, focusworkspaceoncurrentmonitor, 1" + "${mainMod}, 2, focusworkspaceoncurrentmonitor, 2" + "${mainMod}, 3, focusworkspaceoncurrentmonitor, 3" + "${mainMod}, 4, focusworkspaceoncurrentmonitor, 4" + "${mainMod}, 5, focusworkspaceoncurrentmonitor, 5" + "${mainMod}, 6, focusworkspaceoncurrentmonitor, 6" + "${mainMod}, 7, focusworkspaceoncurrentmonitor, 7" + "${mainMod}, 8, focusworkspaceoncurrentmonitor, 8" + "${mainMod}, 9, focusworkspaceoncurrentmonitor, 9" + + # Switch workspaces with mainMod + N/P/O + "${mainMod}, N, focusworkspaceoncurrentmonitor, e+1" + "${mainMod}, P, focusworkspaceoncurrentmonitor, e-1" + "${mainMod} SHIFT, N, movetoworkspace, e+1" + "${mainMod} SHIFT, P, movetoworkspace, e-1" + + # Move active window to a workspace with mainMod + SHIFT + [1-9] + "${mainMod} SHIFT, 1, movetoworkspace, 1" + "${mainMod} SHIFT, 2, movetoworkspace, 2" + "${mainMod} SHIFT, 3, movetoworkspace, 3" + "${mainMod} SHIFT, 4, movetoworkspace, 4" + "${mainMod} SHIFT, 5, movetoworkspace, 5" + "${mainMod} SHIFT, 6, movetoworkspace, 6" + "${mainMod} SHIFT, 7, movetoworkspace, 7" + "${mainMod} SHIFT, 8, movetoworkspace, 8" + "${mainMod} SHIFT, 9, movetoworkspace, 9" + + # Scroll through existing workspaces with mainMod + scroll/side buttons + "${mainMod}, mouse_down, focusworkspaceoncurrentmonitor, e-1" + "${mainMod}, mouse_up, focusworkspaceoncurrentmonitor, e+1" + "${mainMod}, mouse:275, focusworkspaceoncurrentmonitor, e-1" + "${mainMod}, mouse:276, focusworkspaceoncurrentmonitor, e+1" + + # Scratchpads + "${mainMod} SHIFT, 0, movetoworkspace, special:a" + "${mainMod}, 0, togglespecialworkspace, a" + "${mainMod} SHIFT, minus, movetoworkspace, special:b" + "${mainMod}, minus, togglespecialworkspace, b" + "${mainMod} SHIFT, equal, movetoworkspace, special:c" + "${mainMod}, equal, togglespecialworkspace, c" + + "${mainMod}, T, exec, ${toggleOption}/bin/hypr-toggle-opt input:touchpad:disable_while_typing" + ]; + + bindl = [ + "${mainMod}, Q, exec, ${cfg.lockBinary}" + "${mainMod} ALT, Q, exec, killall ${cfg.lockBinary} .${cfg.lockBinary}-wrapped ; ${cfg.lockBinary}" + "${mainMod} SHIFT, Q, exit," + + ", XF86AudioMute, exec, dunst-volume set-mute toggle" + ]; + + binde = [ + # Resize windows + "${mainMod} CTRL ALT, left, resizeactive, -10 0" + "${mainMod} CTRL ALT, right, resizeactive, 10 0" + "${mainMod} CTRL ALT, up, resizeactive, 0 -10" + "${mainMod} CTRL ALT, down, resizeactive, 0 10" + "${mainMod} CTRL ALT, H, resizeactive, -10 0" + "${mainMod} CTRL ALT, L, resizeactive, 10 0" + "${mainMod} CTRL ALT, K, resizeactive, 0 -10" + "${mainMod} CTRL ALT, J, resizeactive, 0 10" + + # Move floating windows + "${mainMod} CTRL, left, moveactive, -50 0" + "${mainMod} CTRL, right, moveactive, 50 0" + "${mainMod} CTRL, up, moveactive, 0 -50" + "${mainMod} CTRL, down, moveactive, 0 50" + "${mainMod} CTRL, H, moveactive, -50 0" + "${mainMod} CTRL, L, moveactive, 50 0" + "${mainMod} CTRL, K, moveactive, 0 -50" + "${mainMod} CTRL, J, moveactive, 0 50" + ]; + + bindm = [ + # Move/resize windows with mainMod + LMB/RMB and dragging + "${mainMod}, mouse:272, movewindow" + "${mainMod}, mouse:273, resizewindow" + ]; + + bindel = [ + # Media keys + ", XF86AudioRaiseVolume, exec, dunst-volume set-volume 5%+" + ", XF86AudioLowerVolume, exec, dunst-volume set-volume 5%-" + + ", XF86MonBrightnessDown, exec, dunst-brightness 5%+" + ", XF86MonBrightnessUp, exec, dunst-brightness 5%-" + ]; + }; + + extraConfig = '' + # Passthrough mode + bind = ${mainMod}, Escape, submap, passthrough + submap = passthrough + bind = ${mainMod}, Escape, submap, reset + submap = reset + + # OBS + bind = ${mainMod} CTRL, O, submap, OBS + submap = OBS + bind = , Space, pass, ^(com\.obsproject\.Studio)$ + bind = , P, pass, ^(com\.obsproject\.Studio)$ + bind = , Escape, submap, reset + bind = ${mainMod}, Escape, submap, reset + submap = reset + ''; + }; + + systemd.user.services = lib.mkIf cfg.wallpaper.enable { + hyprpaper = lib.mkIf (cfg.wallpaper.backend == "hyprpaper") { + Unit = { + Description = "Background wallpaper image via hyprpaper"; + After = "hyprland-session.target"; + }; + Service = { + ExecStart = let + hyprpaperConfig = pkgs.writeText "hyprpaper.conf" '' + preload = ${cfg.wallpaper.image} + wallpaper = ,${cfg.wallpaper.image} + ipc = off + splash = off + ''; + in "${pkgs.hyprpaper}/bin/hyprpaper -c ${hyprpaperConfig}"; + }; + Install = { + WantedBy = [ "hyprland-session.target" ]; + }; + }; + + swaybg = lib.mkIf (cfg.wallpaper.backend == "swaybg") { + Unit = { + Description = "Background wallpaper image via swaybg"; + After = "hyprland-session.target"; + }; + Service = { + ExecStart = "${pkgs.swaybg}/bin/swaybg -i ${cfg.wallpaper.image} -m fill -o '*'"; + }; + Install = { + WantedBy = [ "hyprland-session.target" ]; + }; + }; + }; + }); +} diff --git a/modules/home/graphical/wayland/hyprlock.nix b/modules/home/graphical/wayland/hyprlock.nix new file mode 100644 index 0000000..26b1c42 --- /dev/null +++ b/modules/home/graphical/wayland/hyprlock.nix @@ -0,0 +1,66 @@ +{ pkgs, config, lib, self, theme, inputs, ... }: + +let + cfg = config.my.graphical.wayland.hyprlock; +in { + options.my.graphical.wayland.hyprlock = { + enable = lib.mkEnableOption null; + }; + + config = lib.mkIf cfg.enable { + programs.hyprlock = { + enable = true; + + package = inputs.hyprlock.packages.${pkgs.system}.hyprlock; + + settings = let + c = builtins.mapAttrs (_: t: "0xFF${t}") theme; + commaVals = x: y: "${builtins.toString x}, ${builtins.toString y}"; + in { + general = { + hide_cursor = true; + }; + + background = lib.singleton { + path = "screenshot"; + blur_size = 15; + blur_passes = 3; + }; + + input-field = lib.singleton { + fade_on_empty = false; + placeholder_text = ""; + size = commaVals 350 70; + dots_size= 0.33; + outline_thickness = 5; + position = commaVals 0 (-100); + outer_color = c.mauve; + inner_color = c.crust; + font_color = c.text; + check_color = c.blue; + fail_color = c.red; + capslock_color = c.yellow; + numlock_color = c.yellow; + bothlock_color = c.yellow; + }; + + image = lib.singleton { + path = "${self}/assets/quag-head.png"; + size = 180; + border_size = 5; + position = commaVals 0 80; + border_color = c.mauve; + }; + }; + }; + + + my.graphical.wayland = { + ydotool.enable = true; + swayidle.lockCommand = "${config.programs.hyprlock.package}/bin/hyprlock --no-fade-in & sleep 0.3"; + hyprland.lockBinary = "hyprlock"; + }; + + wayland.windowManager.hyprland.settings.misc.allow_session_lock_restore = true; + }; +} diff --git a/modules/home/graphical/wayland/kanshi.nix b/modules/home/graphical/wayland/kanshi.nix new file mode 100644 index 0000000..c9b28e1 --- /dev/null +++ b/modules/home/graphical/wayland/kanshi.nix @@ -0,0 +1,40 @@ +{ pkgs, config, lib, ... }: + +let + cfg = config.my.graphical.wayland.kanshi; +in { + options.my.graphical.wayland.kanshi = { + enable = lib.mkEnableOption null; + }; + + config = lib.mkIf cfg.enable { + services.kanshi = { + enable = true; + systemdTarget = "hyprland-session.target"; + profiles = { + undocked = { + outputs = [ + { + criteria = "eDP-1"; + status = "enable"; + scale = 1.0; + } + ]; + }; + docked = { + exec = "${pkgs.systemd}/bin/systemctl --user restart eww-bar.service"; + outputs = [ + { + criteria = "eDP-1"; + status = "disable"; + } + { + criteria = "HDMI-A-1"; + status = "enable"; + } + ]; + }; + }; + }; + }; +} diff --git a/modules/home/graphical/wayland/swayidle.nix b/modules/home/graphical/wayland/swayidle.nix new file mode 100644 index 0000000..e6dd2cd --- /dev/null +++ b/modules/home/graphical/wayland/swayidle.nix @@ -0,0 +1,41 @@ +{ pkgs, config, lib, osConfig, ... }: + +let + cfg = config.my.graphical.wayland.swayidle; +in { + options.my.graphical.wayland.swayidle = { + enable = lib.mkEnableOption null // { + default = osConfig.my.laptop.enable; + }; + lockCommand = lib.mkOption { + type = lib.types.str; + }; + }; + + config = lib.mkIf cfg.enable { + services.swayidle = { + enable = true; + systemdTarget = "hyprland-session.target"; + timeouts = let + inherit (pkgs) brightnessctl acpi gnugrep systemd; + withBat = command: "${acpi}/bin/acpi -b | ${gnugrep}/bin/grep -q 'Discharging' && ${command}"; + in [ + { + timeout = 60; + command = withBat "${brightnessctl}/bin/brightnessctl -s s 0"; + resumeCommand = withBat "${brightnessctl}/bin/brightnessctl -r"; + } + { + timeout = 300; + command = withBat "${systemd}/bin/systemctl suspend"; + } + ]; + events = [ + { + event = "before-sleep"; + command = cfg.lockCommand; + } + ]; + }; + }; +} diff --git a/modules/home/graphical/wayland/swaylock.nix b/modules/home/graphical/wayland/swaylock.nix new file mode 100644 index 0000000..dd7afd1 --- /dev/null +++ b/modules/home/graphical/wayland/swaylock.nix @@ -0,0 +1,75 @@ +{ pkgs, config, lib, theme, ... }: + +let + cfg = config.my.graphical.wayland.swaylock; +in { + options.my.graphical.wayland.swaylock = { + enable = lib.mkEnableOption null; + }; + + config = lib.mkIf cfg.enable { + programs.swaylock = { + enable = true; + package = with pkgs; symlinkJoin { + name = "swaylock-effects-blur-flags"; + paths = [ swaylock-effects ]; + nativeBuildInputs = [ makeWrapper ]; + postBuild = '' + wrapProgram $out/bin/swaylock \ + --add-flags -S \ + --add-flags --fade-in \ + --add-flags 0.3 \ + --add-flags --effect-blur \ + --add-flags 15x3 + ''; + }; + settings = with theme; { + indicator = true; + clock = true; + indicator-thickness = 6; + + ignore-empty-password = true; + show-failed-attempts = true; + show-keyboard-layout = true; + indicator-caps-lock = true; + + line-uses-inside = true; + key-hl-color = crust; + bs-hl-color = crust; + + inside-caps-lock-color = yellow; + caps-lock-key-hl-color = yellow; + caps-lock-bs-hl-color = yellow; + text-caps-lock-color = crust; + ring-caps-lock-color = crust; + + ring-ver-color = blue; + text-ver-color = blue; + + ring-clear-color = yellow; + text-clear-color = yellow; + + ring-wrong-color = red; + text-wrong-color = red; + + inside-color = crust; + inside-ver-color = crust; + inside-clear-color = crust; + inside-wrong-color = crust; + ring-color = mauve; + + text-color = rosewater; + + layout-bg-color = mauve; + layout-text-color = crust; + }; + }; + + my.graphical.wayland = { + swayidle.lockCommand = "${pkgs.swaylock-effects}/bin/swaylock -f -S --effect-blur 15x3"; + hyprland.lockBinary = "swaylock"; + }; + + wayland.windowManager.hyprland.settings.misc.allow_session_lock_restore = true; + }; +} diff --git a/modules/home/graphical/wayland/ydotool.nix b/modules/home/graphical/wayland/ydotool.nix new file mode 100644 index 0000000..fe6777a --- /dev/null +++ b/modules/home/graphical/wayland/ydotool.nix @@ -0,0 +1,20 @@ +{ pkgs, config, lib, ... }: + +let + cfg = config.my.graphical.wayland.ydotool; +in { + options.my.graphical.wayland.ydotool = { + enable = lib.mkEnableOption null; + }; + + config = lib.mkIf cfg.enable { + home.packages = [ pkgs.ydotool ]; + xdg.configFile = let + serviceName = "ydotool.service"; + service = "${pkgs.ydotool}/share/systemd/user/${serviceName}"; + in { + "systemd/user/${serviceName}".source = service; + "systemd/user/default.target.wants/${serviceName}".source = service; + }; + }; +} diff --git a/modules/home/graphical/zathura.nix b/modules/home/graphical/zathura.nix new file mode 100644 index 0000000..e7ce436 --- /dev/null +++ b/modules/home/graphical/zathura.nix @@ -0,0 +1,19 @@ +{ pkgs, config, lib, ... }: + +let + cfg = config.my.graphical.zathura; +in { + options.my.graphical.zathura = { + enable = lib.mkEnableOption null; + }; + + config = lib.mkIf cfg.enable { + home.packages = [ pkgs.zathura ]; + xdg.configFile."zathura/zathurarc".source = pkgs.fetchFromGitHub { + owner = "catppuccin"; + repo = "zathura"; + rev = "1bda9d8274dd327b7931886ef0c5c1eb33903814"; + hash = "sha256-HWOc5tnVgU/HUcVcIXACeuu3RDH1pHO/8DQRsWqumIA="; + } + "/src/catppuccin-mocha"; + }; +} diff --git a/modules/home/mpd.nix b/modules/home/mpd.nix new file mode 100644 index 0000000..23c48a1 --- /dev/null +++ b/modules/home/mpd.nix @@ -0,0 +1,44 @@ +{ pkgs, config, lib, osConfig, ... }: + +let + cfg = config.my.mpd; +in { + options.my.mpd = { + enable = lib.mkEnableOption null; + usePipewire = lib.mkEnableOption null // { + default = true; + }; + ncmpcpp = { + enable = lib.mkEnableOption null; + }; + }; + + config = lib.mkIf cfg.enable { + services.mpd = { + enable = true; + extraConfig = '' + restore_paused "yes" + zeroconf_enabled "no" + + ${lib.optionalString cfg.usePipewire '' + audio_output { + type "pipewire" + name "Pipewire Sound Server" + mixer_type "hardware" + replay_gain_handler "none" + } + ''} + ''; + }; + + home.packages = [ pkgs.mpc-cli ]; + + programs.ncmpcpp = lib.mkIf cfg.ncmpcpp.enable { + enable = true; + settings = { + mpd_host = "127.0.0.1"; + mpd_port = config.services.mpd.network.port; + }; + }; + }; +} diff --git a/modules/home/nix.nix b/modules/home/nix.nix new file mode 100644 index 0000000..90afbd9 --- /dev/null +++ b/modules/home/nix.nix @@ -0,0 +1,39 @@ +{ config, lib, osConfig, ... }: + +let + cfg = config.my.nix; +in { + options.my.nix = { + gc = lib.mkEnableOption null // { + default = true; + }; + }; + + config = { + xdg.configFile = { + "nixpkgs/config.nix".text = lib.generators.toPretty {multiline = true;} { + inherit (osConfig.nixpkgs.config) allowUnfree; + }; + }; + + systemd.user = lib.mkIf cfg.gc { + services.nix-gc = { + Unit = { + Description = "Nix User Garbage Collector"; + }; + Service = { + ExecStart = "${osConfig.nix.package}/bin/nix-collect-garbage ${osConfig.nix.gc.options}"; + }; + }; + + timers = { + nix-gc = lib.mkIf osConfig.nix.gc.automatic { + Timer = osConfig.systemd.timers.nix-gc.timerConfig; + Install = { + WantedBy = [ "timers.target" ]; + }; + }; + }; + }; + }; +} diff --git a/modules/home/packages.nix b/modules/home/packages.nix new file mode 100644 index 0000000..016e97d --- /dev/null +++ b/modules/home/packages.nix @@ -0,0 +1,10 @@ +{ pkgs, ... }: + +{ + home.packages = with pkgs; [ + xdg-utils + libnotify + pulsemixer + pavucontrol + ]; +} diff --git a/modules/home/scripts/listen-hyprland.rb b/modules/home/scripts/listen-hyprland.rb new file mode 100755 index 0000000..eaf3b59 --- /dev/null +++ b/modules/home/scripts/listen-hyprland.rb @@ -0,0 +1,52 @@ +#!/usr/bin/env ruby +# frozen_string_literal: true + +require 'socket' + +Thread.abort_on_exception = true + +SOCK_DIR = "#{ENV['XDG_RUNTIME_DIR']}/hypr/#{ENV['HYPRLAND_INSTANCE_SIGNATURE']}" +SOCK1 = "#{SOCK_DIR}/.socket.sock" +SOCK2 = "#{SOCK_DIR}/.socket2.sock" +SOCK_ = "#{SOCK_DIR}/.personal.sock" + +def hyprctl(cmd) + Socket.unix(SOCK1) do |s| + s.print cmd + s.read.force_encoding('UTF-8') + end +end + +def server_listen(server, sig_out) + while (socket = server.accept) + while (line = socket.gets) + case line.chomp + when 'group_next' + sig_out[:group_next] = true + end + end + end +ensure + File.unlink(SOCK_) +end + +signals = {} + +Thread.new do + server = UNIXServer.new(SOCK_) +rescue Errno::EADDRINUSE + puts 'personal sock address in use' rescue nil +else + server_listen(server, signals) +end + +Socket.unix(SOCK2) do |socket| + while (line = socket.gets) + event, _, data = line.partition('>>') + data = data.split(',') + case event + when 'openwindow' + hyprctl 'dispatch togglegroup' if signals.delete(:group_next) + end + end +end diff --git a/modules/home/scripts/sync-music.lisp b/modules/home/scripts/sync-music.lisp new file mode 100644 index 0000000..7d5dc33 --- /dev/null +++ b/modules/home/scripts/sync-music.lisp @@ -0,0 +1,29 @@ +(asdf:load-system :alexandria) +(asdf:load-system :cl-fad) + +(uiop:define-package #:sync-music + (:use #:cl #:alexandria) + (:export #:sync-music #:main)) + +(in-package #:sync-music) + +(defvar *dry-run-p* nil) +(defvar *cleanupp* nil) + +(defun translate-file-name (file) + (when (cl-fad:directory-pathname-p file) + (return file)) + (switch ((pathname-type file) :test #'string-equal) + ("flac" (make-pathname :name (pathname-name file) :type "ogg")) + (("mp3" "ogg" "cue" "m3u" "m3u8") file))) + +(defun sync-directory (directory destination) + (loop :for file :in (cl-fad:list-directory directory :follow-symlinks t) + :for file-destination := (merge-pathnames destination (translate-file-name file)) + :when file-destination + :collect file-destination :into destinations)) + +(defun sync-music (destination &key (music-directory #P"~/Music/")) + (unless (cl-fad:directory-exists-p music-directory) + (error "Music directory `~A` does not exist!" music-directory)) + (sync-directory music-directory destination)) diff --git a/modules/home/scripts/time-window.lisp b/modules/home/scripts/time-window.lisp new file mode 100644 index 0000000..6e36bc4 --- /dev/null +++ b/modules/home/scripts/time-window.lisp @@ -0,0 +1,31 @@ +(asdf:load-system :cl-hyprland-ipc) + +(uiop:define-package #:time-window + (:use #:cl) + (:export #:time-window #:main)) + +(in-package #:time-window) + +(defun time-window (argv use-pid) + (time + (let* ((process-info (uiop:launch-program argv)) + (pid (uiop:process-info-pid process-info))) + (format t "Started process via `~{~A~^ ~}` with PID ~A~%" argv pid) + (hyprland-ipc:handle-events + :return-on-non-nil-p t + :open-window (lambda (address workspace-name class title) + (declare (ignorable address workspace-name class title)) + (or (not use-pid) + (= pid + (gethash "pid" + (hyprland-ipc:find-client-data address))))))))) + +(defun main () + (let* ((argv (uiop:command-line-arguments)) + (use-pid (string= (first argv) "-p"))) + (when use-pid + (setf argv (rest argv))) + (unless argv + (format *error-output* "Needs command string!~%") + (uiop:quit 1 t)) + (time-window argv use-pid))) diff --git a/modules/home/shell.nix b/modules/home/shell.nix new file mode 100644 index 0000000..92651b5 --- /dev/null +++ b/modules/home/shell.nix @@ -0,0 +1,219 @@ +{ pkgs, config, lib, ... }: + +let + cfg = config.my.shell; +in { + options.my.shell = { + aliases.enable = lib.mkEnableOption null; + direnv.enable = lib.mkEnableOption null; + fish.enable = lib.mkEnableOption null; + globalNpmPackages.enable = lib.mkEnableOption null; + starship.enable = lib.mkEnableOption null; + zsh.enable = lib.mkEnableOption null; + }; + + config = lib.mkMerge [ + (lib.mkIf cfg.aliases.enable { + home.shellAliases = { + e = "emacsclient -n -c"; + et = "emacsclient -nw"; + v = lib.mkDefault "vim"; + jq = "jaq"; + java = "java -Dawt.useSystemAAFontSettings=lcd"; + j = "javac *.java && java Main"; + syu = "nh os switch --ask --update -- --accept-flake-config"; + nswitch = "nh os switch --ask -- --accept-flake-config"; + }; + }) + + (lib.mkIf cfg.direnv.enable { + programs.direnv = { + enable = true; + nix-direnv.enable = true; + }; + }) + + (lib.mkIf cfg.fish.enable { + programs.fish = { + enable = true; + interactiveShellInit = let + catppuccinMochaSrc = pkgs.fetchFromGitHub { + owner = "catppuccin"; + repo = "fish"; + rev = "91e6d6721362be05a5c62e235ed8517d90c567c9"; + hash = "sha256-l9V7YMfJWhKDL65dNbxaddhaM6GJ0CFZ6z+4R6MJwBA="; + }; + catppuccinMochaVars = pkgs.runCommandLocal "catppuccin-mocha-vars" { } '' + ${pkgs.ed}/bin/ed '${catppuccinMochaSrc}/themes/Catppuccin Mocha.theme' <<- EOF + v/^fish_/d + %s/^/set -g / + w $out + EOF + ''; + in '' + set -g fish_greeting + + ${lib.optionalString config.my.graphical.wayland.foot.enable '' + if [ "$TERM" = "foot" ] + function mark_prompt_start --on-event fish_prompt + echo -en "\e]133;A\e\\" + end + end + ''} + ''; + plugins = with pkgs.fishPlugins; [ + { + name = "autopair"; + src = autopair.src; + } + { + name = "sponge"; + src = sponge.src; + } + ]; + }; + }) + + (lib.mkIf cfg.globalNpmPackages.enable { + home = let + npmPackagesPath = "${config.home.homeDirectory}/.npm-packages"; + in { + file.".npmrc".text = '' + prefix = ${npmPackagesPath} + ''; + sessionPath = [ + "${npmPackagesPath}/bin" + ]; + sessionVariables.NODE_PATH = "${npmPackagesPath}/lib/node_modules"; + }; + }) + + (lib.mkIf cfg.zsh.enable { + programs.zsh = { + enable = true; + dotDir = ".config/zsh"; + autocd = true; + localVariables = { + ZVM_VI_HIGHLIGHT_FOREGROUND = "black"; + ZVM_VI_HIGHLIGHT_BACKGROUND = "red"; + }; + initExtraFirst = '' + if [[ -n $INSIDE_EMACS ]]; then + bindkey -e + else + AUTOPAIR_INHIBIT_INIT=true + fi + ''; + initExtra = '' + zstyle ':completion:*' menu select + zstyle ':completion:*' matcher-list ''\'' \ + 'm:{[:lower:][:upper:]}={[:upper:][:lower:]}' \ + '+r:|[._-]=* r:|=*' \ + '+l:|=* r:|=*' + zmodload zsh/complist + bindkey -M menuselect "''${terminfo[kcbt]}" reverse-menu-complete + if [[ -n $INSIDE_EMACS ]]; then + autoload -Uz add-zsh-hook + add-zsh-hook -d precmd zvm_init + bindkey "^W" vi-backward-kill-word + else + zle -N autopair-insert + zle -N autopair-close + zle -N autopair-delete + + zvm_after_init_commands+=(' + for p in ''${(@k)AUTOPAIR_PAIRS}; do + zvm_bindkey viins "$p" autopair-insert + bindkey -M isearch "$p" self-insert + + local rchar="$(_ap-get-pair $p)" + if [[ $p != $rchar ]]; then + zvm_bindkey viins "$rchar" autopair-close + bindkey -M isearch "$rchar" self-insert + fi + done + + zvm_bindkey viins "''${terminfo[kbs]}" autopair-delete + zvm_bindkey viins "^h" autopair-delete + bindkey -M isearch "''${terminfo[kbs]}" backward-delete-char + bindkey -M isearch "^h" backward-delete-char + zvm_bindkey viins "^[''${terminfo[kbs]}" vi-backward-kill-word + zvm_bindkey viins "^W" vi-backward-kill-word + ') + fi + ''; + plugins = with pkgs; [ + { + name = "zsh-autopair"; + src = zsh-autopair; + file = "share/zsh/zsh-autopair/autopair.zsh"; + } + { + name = "zsh-vi-mode"; + src = zsh-vi-mode; + file = "share/zsh-vi-mode/zsh-vi-mode.plugin.zsh"; + } + { + name = "fast-syntax-highlighting"; + src = zsh-fast-syntax-highlighting; + file = "share/zsh/site-functions/fast-syntax-highlighting.plugin.zsh"; + } + ]; + }; + }) + + (lib.mkIf cfg.starship.enable { + programs.starship = { + enable = true; + settings = { + add_newline = false; + continuation_prompt = "[>](bold green) "; + character = { + disabled = false; + success_symbol = "[%](bold green)"; + error_symbol = "[%](bold yellow)"; + vimcmd_symbol = "[%](bold blue)"; + }; + status = { + disabled = false; + format = "[$symbol$common_meaning$status]($style) "; + symbol = ""; + map_symbol = true; + not_executable_symbol = "+x "; + not_found_symbol = "?? "; + sigint_symbol = "XX "; + signal_symbol = "!! "; + pipestatus = true; + pipestatus_separator = "[|](bold yellow) "; + pipestatus_format = "[\\[](bold yellow) $pipestatus" + + "[\\] => ](bold yellow)" + + "[$symbol$common_meaning$status]($style) "; + }; + directory = { + style = "bold blue"; + truncation_length = 6; + truncate_to_repo = false; + truncation_symbol = ".../"; + }; + nix_shell.format = "[$state( \\($name\\))]($style) "; + git_branch.format = "[$symbol$branch(:$remote_branch)]($style) "; + line_break.disabled = true; + c.disabled = true; + cmake.disabled = true; + golang.disabled = true; + haskell.disabled = true; + java.disabled = false; # the only marginally useful one + nodejs.disabled = true; + lua.disabled = true; + nim.disabled = true; + package.disabled = true; + perl.disabled = true; + php.disabled = true; + python.disabled = true; + ruby.disabled = true; + rust.disabled = true; + }; + }; + }) + ]; +} diff --git a/modules/home/spotify.nix b/modules/home/spotify.nix new file mode 100644 index 0000000..da168fd --- /dev/null +++ b/modules/home/spotify.nix @@ -0,0 +1,74 @@ +{ pkgs, inputs, config, lib, osConfig, ... }: + +let + cfg = config.my.spotify; +in { + imports = [ inputs.spicetify-nix.homeManagerModule ]; + + options.my.spotify = { + spicetify.enable = lib.mkEnableOption null; + spotifyd.enable = lib.mkEnableOption null; + }; + + config = lib.mkMerge [ + (lib.mkIf cfg.spicetify.enable { + home.packages = [ + (pkgs.runCommandLocal "spicetify-desktop" { } '' + mkdir -p "$out/share/applications" + ${pkgs.ed}/bin/ed ${pkgs.spotify}/share/applications/spotify.desktop <<- EOF + %s/^Exec=spotify/Exec=spotifywm/ + w $out/share/applications/spotify.desktop + EOF + '') + ]; + + programs.spicetify = let + spicePkgs = inputs.spicetify-nix.packages.${pkgs.system}.default; + in { + enable = true; + theme = spicePkgs.themes.catppuccin; + colorScheme = "mocha"; + windowManagerPatch = true; + enabledExtensions = with spicePkgs.extensions; [ + fullAppDisplay + shuffle + ]; + }; + }) + + (lib.mkIf cfg.spotifyd.enable { + home.packages = [ pkgs.spotify-tui ]; + + services.spotifyd = { + enable = true; + package = pkgs.spotifyd.override { + withMpris = true; + withPulseAudio = true; + }; + settings.global = { + username_cmd = "head -1 ${osConfig.age.secrets.spotify.path}"; + password_cmd = "tail -1 ${osConfig.age.secrets.spotify.path}"; + device_name = "spotifyd"; + cache_path = "${config.xdg.cacheHome}/spotifyd"; + max_cache_size = 1000000000; + no_audio_cache = false; + bitrate = 320; + initial_volume = "60"; + volume_normalization = true; + normalisation_pregain = -10; + use_mpris = true; + backend = "pulseaudio"; + volume_controller = "softvol"; + zeroconf_port = 1234; + }; + }; + + xdg.configFile."spotify-tui/config.yml".source = pkgs.fetchFromGitHub { + owner = "catppuccin"; + repo = "spotify-tui"; + rev = "45a4ef12508784410c516746c9d84862d52e4567"; + sha256 = "1i9c30n20wq0mpvfd2ip19b1mp9ifiy2shxh16i6kfql9jr7wwj5"; + } + "/mocha.yml"; + }) + ]; +} diff --git a/modules/home/themes/catppuccin.nix b/modules/home/themes/catppuccin.nix new file mode 100644 index 0000000..ea1bec0 --- /dev/null +++ b/modules/home/themes/catppuccin.nix @@ -0,0 +1,31 @@ +{ + rosewater = "F5E0DC"; + flamingo = "F2CDCD"; + pink = "F5C2E7"; + mauve = "CBA6F7"; + red = "F38BA8"; + maroon = "EBA0AC"; + peach = "FAB387"; + yellow = "F9E2AF"; + green = "A6E3A1"; + teal = "94E2D5"; + sky = "89DCEB"; + sapphire = "74C7EC"; + blue = "89B4FA"; + lavender = "B4BEFE"; + + text = "CDD6F4"; + subtext1 = "BAC2DE"; + subtext0 = "A6ADC8"; + overlay2 = "9399B2"; + overlay1 = "7F849C"; + overlay0 = "6C7086"; + + surface2 = "585B70"; + surface1 = "45475A"; + surface0 = "313244"; + + base = "1E1E2E"; + mantle = "181825"; + crust = "11111B"; +} diff --git a/modules/home/themes/default.nix b/modules/home/themes/default.nix new file mode 100644 index 0000000..f0af2a8 --- /dev/null +++ b/modules/home/themes/default.nix @@ -0,0 +1,5 @@ +_: + +{ + _module.args.theme = import ./catppuccin.nix; +} diff --git a/modules/os/cli/applications.nix b/modules/os/cli/applications.nix new file mode 100644 index 0000000..7220985 --- /dev/null +++ b/modules/os/cli/applications.nix @@ -0,0 +1,44 @@ +{ pkgs, config, lib, ... }: + +let + cfg = config.my.cli.applications; +in { + options.my.cli.applications = { + enable = lib.mkEnableOption null // { + default = true; + }; + }; + + config = lib.mkIf cfg.enable { + environment = { + systemPackages = with pkgs; [ + vim + wget + gnumake + findutils + psmisc + file + file-rename + moreutils + pciutils + rlwrap + unzip + unar + bat + fd + ripgrep + eza + ]; + + sessionVariables = { + EDITOR = lib.mkDefault "ex"; + VISUAL = lib.mkDefault "vim"; + }; + }; + + programs = { + git.enable = true; + htop.enable = true; + }; + }; +} diff --git a/modules/os/cli/default.nix b/modules/os/cli/default.nix new file mode 100644 index 0000000..9534ad6 --- /dev/null +++ b/modules/os/cli/default.nix @@ -0,0 +1,12 @@ +_: + +{ + imports = [ + ./applications.nix + ./fish.nix + ./less.nix + ./nix-index.nix + ./sudo.nix + ./tmux.nix + ]; +} diff --git a/modules/os/cli/fish.nix b/modules/os/cli/fish.nix new file mode 100644 index 0000000..4651151 --- /dev/null +++ b/modules/os/cli/fish.nix @@ -0,0 +1,16 @@ +{ pkgs, config, lib, ... }: + +let + cfg = config.my.cli.fish; +in { + options.my.cli.fish = { + enable = lib.mkEnableOption null // { + default = true; + }; + }; + + config = lib.mkIf cfg.enable { + users.defaultUserShell = pkgs.fish; + programs.fish.enable = true; + }; +} diff --git a/modules/os/cli/less.nix b/modules/os/cli/less.nix new file mode 100644 index 0000000..afa9690 --- /dev/null +++ b/modules/os/cli/less.nix @@ -0,0 +1,19 @@ +{ config, lib, ... }: + +let + cfg = config.my.cli.less; +in { + options.my.cli.less = { + enable = lib.mkEnableOption null // { + default = true; + }; + }; + + config = lib.mkIf cfg.enable { + programs.less.enable = true; + environment.sessionVariables = { + MANPAGER = "less -R --use-color -Dd+r -Du+b"; + MANROFFOPT = "-P -c"; + }; + }; +} diff --git a/modules/os/cli/nix-index.nix b/modules/os/cli/nix-index.nix new file mode 100644 index 0000000..e375fde --- /dev/null +++ b/modules/os/cli/nix-index.nix @@ -0,0 +1,28 @@ +{ inputs, config, lib, ... }: + +let + cfg = config.my.cli.nix-index; +in { + imports = [ + inputs.nix-index-database.nixosModules.nix-index + ]; + + options.my.cli.nix-index = { + enable = lib.mkEnableOption null; + }; + + config = lib.mkIf cfg.enable { + programs = { + nix-index = { + enable = true; + enableBashIntegration = false; + enableFishIntegration = false; + enableZshIntegration = false; + }; + + nix-index-database = { + comma.enable = true; + }; + }; + }; +} diff --git a/modules/os/cli/sudo.nix b/modules/os/cli/sudo.nix new file mode 100644 index 0000000..2f25ab8 --- /dev/null +++ b/modules/os/cli/sudo.nix @@ -0,0 +1,20 @@ +{ pkgs, config, lib, ... }: + +let + cfg = config.my.cli.sudo; +in { + options.my.cli.sudo = { + insults.enable = lib.mkEnableOption null; + }; + + config = lib.mkMerge [ + (lib.mkIf cfg.insults.enable { + security.sudo = { + package = pkgs.sudo.override {withInsults = true;}; + extraConfig = '' + Defaults insults + ''; + }; + }) + ]; +} diff --git a/modules/os/cli/tmux.nix b/modules/os/cli/tmux.nix new file mode 100644 index 0000000..b80cb82 --- /dev/null +++ b/modules/os/cli/tmux.nix @@ -0,0 +1,15 @@ +{ config, lib, ... }: + +let + cfg = config.my.cli.tmux; +in { + options.my.cli.tmux = { + enable = lib.mkEnableOption null // { + default = true; + }; + }; + + config = lib.mkIf cfg.enable { + programs.tmux.enable = true; + }; +} diff --git a/modules/os/core/bootloader.nix b/modules/os/core/bootloader.nix new file mode 100644 index 0000000..603bd5c --- /dev/null +++ b/modules/os/core/bootloader.nix @@ -0,0 +1,23 @@ +{ config, lib, ... }: + +let + cfg = config.my.bootloader; +in { + options.my.bootloader = { + type = lib.mkOption { + type = with lib.types; nullOr (enum [ "systemdBoot" ]); + default = null; + }; + }; + + config = { + boot.loader = lib.mkIf (cfg.type != null) { + systemd-boot = lib.mkIf (cfg.type == "systemdBoot") { + enable = true; + editor = false; + }; + efi.canTouchEfiVariables = true; + timeout = lib.mkDefault 0; + }; + }; +} diff --git a/modules/os/core/default.nix b/modules/os/core/default.nix new file mode 100644 index 0000000..94a518d --- /dev/null +++ b/modules/os/core/default.nix @@ -0,0 +1,14 @@ +_: + +{ + imports = [ + ./shared + + ./fs + ./networking + ./bootloader.nix + ./secure-boot.nix + ./user.nix + ./zram.nix + ]; +} diff --git a/modules/os/core/fs/btrfs.nix b/modules/os/core/fs/btrfs.nix new file mode 100644 index 0000000..5746ce8 --- /dev/null +++ b/modules/os/core/fs/btrfs.nix @@ -0,0 +1,33 @@ +{ config, lib, ... }: + +let + cfg = config.my.fs; +in { + config = lib.mkIf (cfg.type == "btrfs") { + fileSystems = builtins.mapAttrs (_: options: { + inherit (cfg) device; + fsType = "btrfs"; + options = [ "noatime" "space_cache=v2" "compress=zstd:9" ] + ++ options + ++ lib.optional config.services.fstrim.enable "nodiscard"; + }) ({ + "/" = [ "subvol=root" ]; + "/nix" = [ "subvol=nix" ]; + "/home" = [ "subvol=home" ]; + } // lib.optionalAttrs cfg.snapshots { + "/home/${config.my.user.username}/.cache" = [ "subvol=misc/cache" ]; + "/home/${config.my.user.username}/no-snapshot" = [ "subvol=misc/other" ]; + }); + + services = { + snapper = lib.mkIf cfg.snapshots { + configs.home = { + SUBVOLUME = "/home"; + ALLOW_USERS = [ config.my.user.username ]; + TIMELINE_CREATE = true; + TIMELINE_CLEANUP = true; + }; + }; + }; + }; +} diff --git a/modules/os/core/fs/default.nix b/modules/os/core/fs/default.nix new file mode 100644 index 0000000..bb37850 --- /dev/null +++ b/modules/os/core/fs/default.nix @@ -0,0 +1,42 @@ +{ config, lib, ... }: + +let + cfg = config.my.fs; +in { + imports = [ + ./btrfs.nix + ./ext4.nix + ./luks.nix + ./ssd.nix + ]; + + options.my.fs = { + bootPartition = lib.mkEnableOption null // { + default = true; + }; + device = lib.mkOption { + type = lib.types.path; + default = "/dev/disk/by-label/nixos"; + }; + snapshots = lib.mkEnableOption null; + swapPartition = lib.mkEnableOption null; + type = lib.mkOption { + type = with lib.types; nullOr (enum [ "btrfs" "ext4" ]); + default = null; + }; + }; + + config = { + fileSystems = lib.mkIf cfg.bootPartition { + "/boot" = { + device = "/dev/disk/by-label/BOOT"; + fsType = "vfat"; + options = [ "umask=0077" ]; + }; + }; + + swapDevices = lib.mkIf cfg.swapPartition [ + {device = "/dev/disk/by-label/swap";} + ]; + }; +} diff --git a/modules/os/core/fs/ext4.nix b/modules/os/core/fs/ext4.nix new file mode 100644 index 0000000..15f6b8b --- /dev/null +++ b/modules/os/core/fs/ext4.nix @@ -0,0 +1,15 @@ +{ config, lib, ... }: + +let + cfg = config.my.fs; +in { + config = lib.mkIf (cfg.type == "ext4") { + fileSystems = { + "/" = { + inherit (cfg) device; + fsType = "ext4"; + options = [ "noatime" ]; + }; + }; + }; +} diff --git a/modules/os/core/fs/luks.nix b/modules/os/core/fs/luks.nix new file mode 100644 index 0000000..4d2859f --- /dev/null +++ b/modules/os/core/fs/luks.nix @@ -0,0 +1,23 @@ +{ config, lib, ... }: + +let + cfg = config.my.fs.luks; +in { + options.my.fs.luks = { + enable = lib.mkEnableOption null; + device = lib.mkOption { + type = lib.types.path; + default = "/dev/disk/by-label/nixos-crypt"; + }; + name = lib.mkOption { + type = lib.types.str; + default = "nixos"; + }; + }; + + config = lib.mkIf cfg.enable { + my.fs.device = lib.mkDefault "/dev/mapper/${cfg.name}"; + + boot.initrd.luks.devices.${cfg.name} = {inherit (cfg) device;}; + }; +} diff --git a/modules/os/core/fs/ssd.nix b/modules/os/core/fs/ssd.nix new file mode 100644 index 0000000..65c3ea8 --- /dev/null +++ b/modules/os/core/fs/ssd.nix @@ -0,0 +1,19 @@ +{ config, lib, ... }: + +let + cfg = config.my.fs.ssd; +in { + options.my.fs.ssd = { + enable = lib.mkEnableOption null; + enableLuksIntegration = lib.mkEnableOption null // { + default = true; + }; + }; + + config = lib.mkIf cfg.enable { + boot.initrd.luks.devices.${config.my.fs.luks.name} = lib.mkIf cfg.enableLuksIntegration { + allowDiscards = true; + bypassWorkqueues = true; + }; + }; +} diff --git a/modules/os/core/networking/cloudflare-warp.nix b/modules/os/core/networking/cloudflare-warp.nix new file mode 100644 index 0000000..89d620a --- /dev/null +++ b/modules/os/core/networking/cloudflare-warp.nix @@ -0,0 +1,106 @@ +{ pkgs, config, lib, ... }: + +let + cfg = config.my.networking.warp; +in { + options = { + my.networking.warp = { + enable = lib.mkEnableOption (lib.mdDoc "cloudflare-warp, a service that replaces the connection between your device and the Internet with a modern, optimized, protocol"); + + package = lib.mkOption { + type = lib.types.package; + default = pkgs.cloudflare-warp; + defaultText = lib.literalExpression "pkgs.cloudflare-warp"; + description = lib.mdDoc "The package to use for Cloudflare Warp."; + }; + + user = lib.mkOption { + type = lib.types.str; + default = "warp"; + description = lib.mdDoc "User account under which Cloudflare Warp runs."; + }; + + group = lib.mkOption { + type = lib.types.str; + default = "warp"; + description = lib.mdDoc "Group under which Cloudflare Warp runs."; + }; + + certificate = lib.mkOption { + type = with lib.types; nullOr path; + default = null; + description = lib.mdDoc '' + Path to the Cloudflare root certificate. There is a download link in the docs [here](https://developers.cloudflare.com/cloudflare-one/connections/connect-devices/warp/install-cloudflare-cert/). + ''; + }; + + udpPort = lib.mkOption { + type = lib.types.int; + default = 2408; + description = lib.mdDoc '' + The UDP port to open in the firewall. Warp uses port 2408 by default, but fallback ports can be used if that conflicts with another service. See the [firewall documentation](https://developers.cloudflare.com/cloudflare-one/connections/connect-devices/warp/deployment/firewall#warp-udp-ports) for the pre-configured available fallback ports. + ''; + }; + + openFirewall = lib.mkOption { + type = lib.types.bool; + default = false; + description = lib.mdDoc '' + Opens UDP port in the firewall. See `udpPort` configuration option, and [firewall documentation](https://developers.cloudflare.com/cloudflare-one/connections/connect-devices/warp/deployment/firewall#warp-udp-ports). + ''; + }; + }; + }; + + config = lib.mkIf cfg.enable { + environment.systemPackages = [ cfg.package ]; + + security.pki = lib.mkIf (cfg.certificate != null) { + certificateFiles = [ cfg.certificate ]; + }; + + networking.firewall = lib.mkIf cfg.openFirewall { + allowedUDPPorts = [ cfg.udpPort ]; + }; + + users.users = lib.mkIf (cfg.user == "warp") { + warp = { + isSystemUser = true; + group = "warp"; + description = "Cloudflare Warp user"; + home = "/var/lib/cloudflare-warp"; + }; + }; + users.groups = lib.mkIf (cfg.group == "warp") { + warp = { }; + }; + + systemd = { + packages = [ cfg.package ]; + services.warp-svc = { + after = [ "network-online.target" "systemd-resolved.service" ]; + wants = [ "network-online.target" ]; + wantedBy = [ "multi-user.target" ]; + serviceConfig = { + StateDirectory = "cloudflare-warp"; + User = "warp"; + Umask = "0077"; + # Hardening + LockPersonality = true; + PrivateMounts = true; + PrivateTmp = true; + ProtectControlGroups = true; + ProtectHostname = true; + ProtectKernelLogs = true; + ProtectKernelModules = true; + ProtectKernelTunables = true; + ProtectProc = "invisible"; + # Leaving on strict activates warp on plus + ProtectSystem = "full"; + RestrictNamespaces = true; + RestrictRealtime = true; + }; + }; + }; + }; +} diff --git a/modules/os/core/networking/default.nix b/modules/os/core/networking/default.nix new file mode 100644 index 0000000..f07eadf --- /dev/null +++ b/modules/os/core/networking/default.nix @@ -0,0 +1,26 @@ +{ config, lib, ... }: + +let + cfg = config.my.networking; +in { + imports = [ + ./cloudflare-warp.nix + ./eddie.nix + ]; + + options.my.networking = { + networkManager.enable = lib.mkEnableOption null; + }; + + config = lib.mkIf cfg.networkManager.enable { + networking.networkmanager = { + enable = true; + wifi = { + scanRandMacAddress = lib.mkDefault false; + }; + }; + + systemd.services.NetworkManager-wait-online.enable = lib.mkDefault false; + my.user.extraGroups = [ "networkmanager" ]; + }; +} diff --git a/modules/os/core/networking/eddie.nix b/modules/os/core/networking/eddie.nix new file mode 100644 index 0000000..717c5ec --- /dev/null +++ b/modules/os/core/networking/eddie.nix @@ -0,0 +1,64 @@ +{ pkgs, config, lib, inputs, ... }: + +let + cfg = config.my.networking.eddie; +in { + options.my.networking.eddie = { + enable = lib.mkEnableOption null; + package = lib.mkPackageOption inputs.my-nix-packages.packages.${pkgs.system} "eddie-ui" {}; + allowedTCPPorts = lib.mkOption { + type = with lib.types; listOf port; + default = [ ]; + }; + allowedUDPPorts = lib.mkOption { + type = with lib.types; listOf port; + default = [ ]; + }; + }; + + config = lib.mkIf cfg.enable { + boot.kernelModules = [ "tun" ]; + + environment.systemPackages = [ cfg.package ]; + + networking.iproute2.enable = true; + + networking.firewall = { + checkReversePath = "loose"; + + interfaces = rec { + tun0 = {inherit (cfg) allowedTCPPorts allowedUDPPorts;}; + Eddie = tun0; + }; + }; + + systemd.services.eddie-elevated = { + description = "Eddie Elevation"; + wantedBy = [ "multi-user.target" ]; + wants = [ "network.target" "network-online.target" ]; + after = [ + "network-online.target" + "NetworkManager.service" + "systemd-resolved.service" + ]; + path = (with pkgs; [ + iproute2 + procps + kmod + mono + ]) + ++ lib.optional config.services.nscd.enable + config.services.nscd.package + ++ lib.optional config.networking.firewall.enable + (if config.networking.nftables.enable + then pkgs.nftables + else pkgs.iptables); + serviceConfig = { + ExecStart = "${cfg.package}/lib/eddie-ui/eddie-cli-elevated mode=service"; + Restart = "always"; + RestartSec = 5; + TimeoutStopSec = 5; + }; + }; + }; +} diff --git a/modules/os/core/secure-boot.nix b/modules/os/core/secure-boot.nix new file mode 100644 index 0000000..787f109 --- /dev/null +++ b/modules/os/core/secure-boot.nix @@ -0,0 +1,26 @@ +{ pkgs, config, lib, inputs, ... }: + +let + cfg = config.my.secure-boot; +in { + imports = [ + inputs.lanzaboote.nixosModules.lanzaboote + ]; + + options.my.secure-boot = { + enable = lib.mkEnableOption null; + }; + + config = lib.mkIf cfg.enable { + environment.systemPackages = [ pkgs.sbctl ]; + + boot = { + loader.systemd-boot.enable = lib.mkForce false; + + lanzaboote = { + enable = true; + pkiBundle = "/etc/secureboot"; + }; + }; + }; +} diff --git a/modules/os/core/shared/default.nix b/modules/os/core/shared/default.nix new file mode 100644 index 0000000..a09ae90 --- /dev/null +++ b/modules/os/core/shared/default.nix @@ -0,0 +1,33 @@ +{ pkgs, ... }: + +{ + imports = [ + ./nix.nix + ./secrets.nix + # inputs.nur.nixosModules.nur + ]; + + boot = { + kernelPackages = pkgs.linuxPackages_latest; + tmp = { + useTmpfs = true; + tmpfsSize = "100%"; + }; + }; + + i18n.defaultLocale = "en_US.UTF-8"; + console = { + font = "Lat2-Terminus16"; + keyMap = "us"; + }; + + environment.localBinInPath = true; + + programs = { + command-not-found.enable = false; + gnupg.agent = { + enable = true; + enableSSHSupport = true; + }; + }; +} diff --git a/modules/os/core/shared/nix.nix b/modules/os/core/shared/nix.nix new file mode 100644 index 0000000..a11c96a --- /dev/null +++ b/modules/os/core/shared/nix.nix @@ -0,0 +1,53 @@ +{ config, pkgs, inputs, self, ... }: + +{ + nixpkgs = { + config = { + allowUnfree = true; + }; + overlays = [ + inputs.grim-hyprland.overlays.default + ]; + }; + + nix = { + settings = let + flakeConfig = (import "${self}/flake.nix").nixConfig; + in { + experimental-features = [ "nix-command" "flakes" "repl-flake" ]; + auto-optimise-store = true; + keep-outputs = true; + keep-derivations = true; + substituters = flakeConfig.extra-substituters; + trusted-public-keys = flakeConfig.extra-trusted-public-keys; + }; + # Make nix commands use config's flake lock + registry = { + nixpkgs.flake = inputs.nixpkgs; + stable.flake = inputs.nixpkgs-stable; + }; + nixPath = [ + "nixpkgs=/etc/nix/inputs/nixpkgs" + "stable=/etc/nix/inputs/stable" + ]; + extraOptions = '' + !include ${config.age.secrets.nix-tokens.path} + ''; + gc = { + automatic = true; + dates = "weekly"; + options = "--delete-older-than 7d"; + randomizedDelaySec = "30min"; + }; + }; + + environment = { + systemPackages = [ pkgs.nh ]; + sessionVariables.FLAKE = "${config.users.users.${config.my.user.username}.home}/.config/nixos"; + etc = { + "nix/inputs/nixpkgs".source = inputs.nixpkgs.outPath; + "nix/inputs/stable".source = inputs.nixpkgs-stable.outPath; + "current-flake".source = self; + }; + }; +} diff --git a/modules/os/core/shared/secrets.nix b/modules/os/core/shared/secrets.nix new file mode 100644 index 0000000..bcfc2c3 --- /dev/null +++ b/modules/os/core/shared/secrets.nix @@ -0,0 +1,44 @@ +{ pkgs, inputs, config, ... }: + +{ + imports = [ + inputs.agenix.nixosModules.age + ]; + + environment.systemPackages = [ inputs.agenix.packages.${pkgs.system}.default ]; + + age.secrets.spotify = { + file = ../../../../secrets/spotify.age; + owner = config.my.user.username; + group = "users"; + }; + age.secrets.nix-tokens = { + file = ../../../../secrets/nix-tokens.age; + mode = "440"; + owner = config.my.user.username; + group = "users"; + }; + age.secrets.authinfo = { + file = ../../../../secrets/authinfo.age; + owner = config.my.user.username; + group = "users"; + }; + age.secrets.email = { + file = ../../../../secrets/email.json.age; + name = "email.json"; + owner = config.my.user.username; + group = "users"; + }; + age.secrets.porkbun-auth = { + file = ../../../../secrets/porkbun-auth.age; + name = "porkbun-auth"; + }; + age.secrets.wg-groceries = { + file = ../../../../secrets/wg-groceries.age; + name = "wg-groceries"; + }; + age.secrets.wg-nix-laptop = { + file = ../../../../secrets/wg-nix-laptop.age; + name = "wg-nix-laptop"; + }; +} diff --git a/modules/os/core/user.nix b/modules/os/core/user.nix new file mode 100644 index 0000000..04b2756 --- /dev/null +++ b/modules/os/core/user.nix @@ -0,0 +1,57 @@ +{ config, lib, self, inputs, ... }: + +let + cfg = config.my.user; +in { + imports = [ inputs.home-manager.nixosModules.home-manager ]; + + options.my.user = { + username = lib.mkOption { + type = with lib.types; nullOr str; + default = null; + }; + + extraGroups = lib.mkOption { + type = with lib.types; listOf str; + default = [ ]; + }; + + useDefaultGroups = lib.mkEnableOption null // { + default = true; + }; + + homeModule = lib.mkOption { + type = with lib.types; nullOr pathInStore; + default = null; + }; + }; + + config = lib.mkIf (cfg.username != null) { + users.users.${cfg.username} = { + isNormalUser = true; + extraGroups = cfg.extraGroups ++ lib.optionals cfg.useDefaultGroups [ + "wheel" + "video" + "disk" + "input" + ]; + }; + + home-manager = lib.mkIf (cfg.homeModule != null) { + backupFileExtension = "hm-bak"; + useUserPackages = true; + useGlobalPkgs = true; + extraSpecialArgs = {inherit self inputs;}; + users.${cfg.username} = _: { + imports = [ + self.homeManagerModules.default + cfg.homeModule + ]; + home = { + inherit (cfg) username; + homeDirectory = "/home/${cfg.username}"; + }; + }; + }; + }; +} diff --git a/modules/os/core/zram.nix b/modules/os/core/zram.nix new file mode 100644 index 0000000..c432b23 --- /dev/null +++ b/modules/os/core/zram.nix @@ -0,0 +1,31 @@ +{ config, lib, ... }: + +let + cfg = config.my.zram; +in { + options.my.zram = { + enable = lib.mkEnableOption null // { + default = !config.my.fs.swapPartition; + }; + writebackDevice = lib.mkOption { + default = null; + type = with lib.types; nullOr path; + }; + }; + + config = lib.mkIf cfg.enable { + zramSwap = { + enable = true; + algorithm = "zstd"; + memoryPercent = 90; + inherit (cfg) writebackDevice; + }; + + boot.kernel.sysctl = { + "vm.swappiness" = 180; + "vm.watermark_boost_factor" = 0; + "vm.watermark_scale_factor" = 125; + "vm.page-cluster" = 1; + }; + }; +} diff --git a/modules/os/default.nix b/modules/os/default.nix new file mode 100644 index 0000000..acaba33 --- /dev/null +++ b/modules/os/default.nix @@ -0,0 +1,10 @@ +_: + +{ + imports = [ + ./cli + ./core + ./desktop + ./misc + ]; +} diff --git a/modules/os/desktop/applications.nix b/modules/os/desktop/applications.nix new file mode 100644 index 0000000..6baf3eb --- /dev/null +++ b/modules/os/desktop/applications.nix @@ -0,0 +1,19 @@ +{ pkgs, config, lib, ... }: + +let + cfg = config.my.desktop.applications; +in { + options.my.desktop.applications = { + enable = lib.mkEnableOption null // { + default = config.my.desktop.enable; + }; + }; + + config = lib.mkIf cfg.enable { + environment.systemPackages = with pkgs; [ + brightnessctl + acpi + powertop + ]; + }; +} diff --git a/modules/os/desktop/audio.nix b/modules/os/desktop/audio.nix new file mode 100644 index 0000000..1429867 --- /dev/null +++ b/modules/os/desktop/audio.nix @@ -0,0 +1,22 @@ +{ config, lib, ... }: + +let + cfg = config.my.desktop.audio; +in { + options.my.desktop.audio = { + enable = lib.mkEnableOption null; + }; + + config = lib.mkIf cfg.enable { + hardware.pulseaudio.enable = false; + security.rtkit.enable = true; + services.pipewire = { + enable = true; + alsa.enable = true; + alsa.support32Bit = true; + pulse.enable = true; + wireplumber.enable = true; + jack.enable = true; + }; + }; +} diff --git a/modules/os/desktop/bluetooth.nix b/modules/os/desktop/bluetooth.nix new file mode 100644 index 0000000..b2f7cad --- /dev/null +++ b/modules/os/desktop/bluetooth.nix @@ -0,0 +1,19 @@ +{ config, lib, ... }: + +let + cfg = config.my.desktop.bluetooth; +in { + options.my.desktop.bluetooth = { + enable = lib.mkEnableOption null; + }; + + config = lib.mkIf cfg.enable { + hardware.bluetooth = { + enable = true; + settings = { + General.Enable = "Source,Sink,Media,Socket"; + }; + }; + services.blueman.enable = true; + }; +} diff --git a/modules/os/desktop/default.nix b/modules/os/desktop/default.nix new file mode 100644 index 0000000..4aed58b --- /dev/null +++ b/modules/os/desktop/default.nix @@ -0,0 +1,78 @@ +{ pkgs, config, lib, ... }: + +let + cfg = config.my.desktop; +in { + imports = [ + ./applications.nix + ./audio.nix + ./bluetooth.nix + ./gaming.nix + ./hyprland.nix + ./printing.nix + ]; + + options.my.desktop = { + enable = lib.mkEnableOption null; + }; + + config = lib.mkIf cfg.enable { + boot = { + kernelParams = [ "nowatchdog" ]; + blacklistedKernelModules = [ + "iTCO_wdt" + "sp5100_tco" + ]; + }; + + programs.dconf.enable = true; + + services = { + # Stop auto suspending when connected to AC power + logind.lidSwitchExternalPower = "ignore"; + + # Thunar thumbnails + tumbler.enable = true; + }; + + fonts.packages = with pkgs; [ + corefonts + noto-fonts + noto-fonts-cjk + noto-fonts-emoji + liberation_ttf + font-awesome + dejavu_fonts + jost + inter + lmodern + roboto + (nerdfonts.override { + fonts = [ + "JetBrainsMono" + ]; + }) + ]; + + hardware.graphics = { + enable = true; + extraPackages = with pkgs; [ + libvdpau-va-gl + ]; + }; + + systemd.user.services.polkit-gnome-authentication-agent-1 = { + description = "polkit-gnome-authentication-agent-1"; + wantedBy = [ "graphical-session.target" ]; + wants = [ "graphical-session.target" ]; + after = [ "graphical-session.target" ]; + serviceConfig = { + Type = "simple"; + ExecStart = "${pkgs.polkit_gnome}/libexec/polkit-gnome-authentication-agent-1"; + Restart = "on-failure"; + RestartSec = 1; + TimeoutStopSec = 10; + }; + }; + }; +} diff --git a/modules/os/desktop/gaming.nix b/modules/os/desktop/gaming.nix new file mode 100644 index 0000000..4a627f1 --- /dev/null +++ b/modules/os/desktop/gaming.nix @@ -0,0 +1,48 @@ +{ pkgs, config, lib, inputs, ... }: + +let + cfg = config.my.desktop.gaming; +in { + imports = [ + inputs.nix-gaming.nixosModules.pipewireLowLatency + inputs.nix-gaming.nixosModules.platformOptimizations + ]; + + options.my.desktop.gaming = { + enable = lib.mkEnableOption null; + }; + + config = lib.mkIf cfg.enable { + programs = { + steam = { + enable = true; + package = pkgs.steam.override { + extraEnv = { + MANGOHUD = true; + OBS_VKCAPTURE = true; + }; + extraPkgs = pkgs: with pkgs; [ + zstd + openssl + ]; + }; + extraCompatPackages = with pkgs; [ + proton-ge-bin + ]; + remotePlay.openFirewall = true; + platformOptimizations.enable = true; + }; + + gamemode = { + enable = true; + settings = { + general = { + renice = 10; + }; + }; + }; + }; + + services.pipewire.lowLatency.enable = true; + }; +} diff --git a/modules/os/desktop/hyprland.nix b/modules/os/desktop/hyprland.nix new file mode 100644 index 0000000..1343cce --- /dev/null +++ b/modules/os/desktop/hyprland.nix @@ -0,0 +1,60 @@ +{ pkgs, inputs, config, lib, ... }: + +let + cfg = config.my.desktop.hyprland; +in { + imports = [ + inputs.hyprland.nixosModules.default + ]; + + options.my.desktop.hyprland = { + enable = lib.mkEnableOption null; + }; + + config = lib.mkIf cfg.enable { + programs.hyprland = { + enable = true; + portalPackage = inputs.xdph.packages.${pkgs.system}.default; + }; + + xdg.portal = { + enable = true; + extraPortals = [ pkgs.xdg-desktop-portal-gtk ]; + }; + + services.greetd = { + enable = true; + settings = let + session = rec { + user = config.my.user.username; + command = let + sessionVars = "/etc/profiles/per-user/${user}/etc/profile.d/hm-session-vars.sh"; + in pkgs.writeShellScript "hyprland-hm-session-vars" '' + [ -f ${sessionVars} ] && . ${sessionVars} + exec ${config.programs.hyprland.package}/bin/Hyprland + ''; + }; + in { + initial_session = session; + default_session = session; + }; + }; + environment.etc."greetd/environments".text = '' + Hyprland + ''; + + boot.extraModulePackages = with config.boot.kernelPackages; [ v4l2loopback ]; + + security = { + polkit.enable = lib.mkDefault true; + pam = { + services = { + greeetd.gnupg.enable = true; + login.enableGnomeKeyring = true; + swaylock = {}; + hyprlock = {}; + }; + }; + }; + }; +} diff --git a/modules/os/desktop/printing.nix b/modules/os/desktop/printing.nix new file mode 100644 index 0000000..5f0505e --- /dev/null +++ b/modules/os/desktop/printing.nix @@ -0,0 +1,24 @@ +{ pkgs, config, lib, ... }: + +let + cfg = config.my.desktop.printing; +in { + options.my.desktop.printing = { + enable = lib.mkEnableOption null; + }; + + config = lib.mkIf cfg.enable { + services = { + printing = { + enable = true; + cups-pdf.enable = true; + drivers = [ pkgs.gutenprint ]; + }; + avahi = { + enable = true; + nssmdns4 = true; + openFirewall = true; + }; + }; + }; +} diff --git a/modules/os/misc/bin-compat.nix b/modules/os/misc/bin-compat.nix new file mode 100644 index 0000000..8c7b80e --- /dev/null +++ b/modules/os/misc/bin-compat.nix @@ -0,0 +1,19 @@ +{ pkgs, config, lib, ... }: + +let + cfg = config.my.bin-compat; +in { + options.my.bin-compat = { + enable = lib.mkEnableOption null; + }; + + config = lib.mkIf cfg.enable { + environment.systemPackages = with pkgs; [ + appimage-run + ]; + + programs = { + nix-ld.enable = true; + }; + }; +} diff --git a/modules/os/misc/default.nix b/modules/os/misc/default.nix new file mode 100644 index 0000000..ca43f82 --- /dev/null +++ b/modules/os/misc/default.nix @@ -0,0 +1,16 @@ +_: + +{ + imports = [ + ./bin-compat.nix + ./docker.nix + ./interception.nix + ./ios.nix + ./laptop.nix + ./location.nix + ./syncthing.nix + ./syncyomi.nix + ./virt-manager.nix + ./wireshark.nix + ]; +} diff --git a/modules/os/misc/docker.nix b/modules/os/misc/docker.nix new file mode 100644 index 0000000..8465051 --- /dev/null +++ b/modules/os/misc/docker.nix @@ -0,0 +1,14 @@ +{ config, lib, ... }: + +let + cfg = config.my.docker; +in { + options.my.docker = { + enable = lib.mkEnableOption null; + }; + + config = lib.mkIf cfg.enable { + virtualisation.docker.enable = true; + my.user.extraGroups = [ "docker" ]; + }; +} diff --git a/modules/os/misc/interception.nix b/modules/os/misc/interception.nix new file mode 100644 index 0000000..b88d172 --- /dev/null +++ b/modules/os/misc/interception.nix @@ -0,0 +1,41 @@ +{ pkgs, config, lib, ... }: + +let + cfg = config.my.interception; +in { + options.my.interception = { + enable = lib.mkEnableOption null; + }; + + config = lib.mkIf cfg.enable { + # Swap caps lock and escape, CTRL -> BS on press + services.interception-tools = { + enable = true; + plugins = with pkgs.interception-tools-plugins; [ caps2esc dual-function-keys ]; + udevmonConfig = let + inherit (pkgs.interception-tools-plugins) caps2esc dual-function-keys; + _ = x: "${pkgs.interception-tools}/bin/${x}"; + dffConf = pkgs.writeText "dual-function-keys.yaml" '' + TIMING: + TAP_MILLISEC: 125 + DOUBLE_TAP_MILLISEC: 0 + MAPPINGS: + - KEY: KEY_LEFTSHIFT + TAP: KEY_KPLEFTPAREN + HOLD: KEY_LEFTSHIFT + - KEY: KEY_RIGHTSHIFT + TAP: KEY_KPRIGHTPAREN + HOLD: KEY_RIGHTSHIFT + - KEY: KEY_LEFTALT + TAP: [KEY_LEFTCTRL, KEY_BACKSPACE] + HOLD: KEY_LEFTALT + ''; + in '' + - JOB: "${_ "intercept"} -g $DEVNODE | ${dual-function-keys}/bin/dual-function-keys -c ${dffConf} | ${caps2esc}/bin/caps2esc | ${_ "uinput"} -d $DEVNODE" + DEVICE: + EVENTS: + EV_KEY: [KEY_CAPSLOCK, KEY_ESC, KEY_LEFTSHIFT, KEY_LEFTALT] + ''; + }; + }; +} diff --git a/modules/os/misc/ios.nix b/modules/os/misc/ios.nix new file mode 100644 index 0000000..d36341a --- /dev/null +++ b/modules/os/misc/ios.nix @@ -0,0 +1,17 @@ +{ pkgs, config, lib, ... }: + +let + cfg = config.my.ios; +in { + options.my.ios = { + enable = lib.mkEnableOption null; + }; + + config = lib.mkIf cfg.enable { + services.usbmuxd.enable = true; + environment.systemPackages = with pkgs; [ + libimobiledevice + ifuse + ]; + }; +} diff --git a/modules/os/misc/laptop.nix b/modules/os/misc/laptop.nix new file mode 100644 index 0000000..0fa5708 --- /dev/null +++ b/modules/os/misc/laptop.nix @@ -0,0 +1,49 @@ +{ config, lib, ... }: + +let + cfg = config.my.laptop; +in { + options.my.laptop = { + enable = lib.mkEnableOption null; + amd.enable = lib.mkEnableOption null; + intel.enable = lib.mkEnableOption null; + }; + + config = lib.mkIf cfg.enable { + boot.kernel.sysctl."vm.dirty_writeback_centisecs" = 1500; + + boot.extraModprobeConfig = '' + options snd_hda_intel power_save=1 + ''; + + services.upower.enable = true; + + services.power-profiles-daemon.enable = cfg.amd.enable; + + services.tlp = lib.mkIf cfg.intel.enable { + enable = true; + settings = { + DISK_IDLE_SECS_ON_AC = 0; + DISK_IDLE_SECS_ON_BAT = 3; + MAX_LOST_WORK_SECS_ON_AC = 15; + MAX_LOST_WORK_SECS_ON_BAT = 45; + CPU_SCALING_GOVERNOR_ON_AC = "performance"; + CPU_SCALING_GOVERNOR_ON_BAT = "powersave"; + CPU_ENERGY_PERF_POLICY_ON_AC = "balance_performance"; + CPU_ENERGY_PERF_POLICY_ON_BAT = "balance_power"; + CPU_MIN_PERF_ON_AC = 0; + CPU_MAX_PERF_ON_AC = 100; + CPU_MIN_PERF_ON_BAT = 0; + CPU_MAX_PERF_ON_BAT = 25; + INTEL_GPU_MIN_FREQ_ON_AC = 300; + INTEL_GPU_MIN_FREQ_ON_BAT = 300; + INTEL_GPU_MAX_FREQ_ON_AC = 1100; + INTEL_GPU_MAX_FREQ_ON_BAT = 1000; + INTEL_GPU_BOOST_FREQ_ON_AC = 1100; + INTEL_GPU_BOOST_FREQ_ON_BAT = 1000; + PCIE_ASPM_ON_AC = "default"; + PCIE_ASPM_ON_BAT = "powersave"; + }; + }; + }; +} diff --git a/modules/os/misc/location.nix b/modules/os/misc/location.nix new file mode 100644 index 0000000..6a427c1 --- /dev/null +++ b/modules/os/misc/location.nix @@ -0,0 +1,15 @@ +{ config, lib, ... }: + +let + cfg = config.my.location; +in { + options.my.location = { + enable = lib.mkEnableOption null; + }; + + config = lib.mkIf cfg.enable { + services.geoclue2.enable = true; + location.provider = "geoclue2"; + services.localtimed.enable = true; + }; +} diff --git a/modules/os/misc/syncthing.nix b/modules/os/misc/syncthing.nix new file mode 100644 index 0000000..06712e4 --- /dev/null +++ b/modules/os/misc/syncthing.nix @@ -0,0 +1,51 @@ +{ pkgs, config, lib, ... }: + +let + cfg = config.my.syncthing; +in { + options.my.syncthing = { + enable = lib.mkEnableOption null; + asUser = lib.mkEnableOption null; + }; + + config = lib.mkIf cfg.enable (lib.mkMerge [ + { + services.syncthing = { + enable = true; + openDefaultPorts = true; + overrideDevices = false; + overrideFolders = false; + }; + } + + (lib.mkIf cfg.asUser { + services.syncthing = { + user = config.my.user.username; + configDir = "/var/lib/syncthing"; + }; + + my.user.extraGroups = [ config.services.syncthing.group ]; + + systemd.tmpfiles.rules = let + inherit (config.services.syncthing) user group configDir; + in [ + "d '${configDir}' 0750 ${user} ${group} - -" + "z '${configDir}' 0750 ${user} ${group} - -" + ]; + }) + + (let + mullvadCfg = config.services.mullvad-vpn; + in lib.mkIf (mullvadCfg.enable && mullvadCfg.enableExcludeWrapper) { + services.syncthing.package = pkgs.writeShellScriptBin "syncthing" '' + exec /run/wrappers/bin/mullvad-exclude ${pkgs.syncthing}/bin/syncthing "$@" + ''; + # Setuid in mullvad-exclude to perform cgroup shenanigans + systemd.services.syncthing.serviceConfig = { + NoNewPrivileges = lib.mkForce false; + RestrictSUIDSGID = lib.mkForce false; + ProtectControlGroups = lib.mkForce false; + }; + }) + ]); +} diff --git a/modules/os/misc/syncyomi.nix b/modules/os/misc/syncyomi.nix new file mode 100644 index 0000000..4b49d0b --- /dev/null +++ b/modules/os/misc/syncyomi.nix @@ -0,0 +1,109 @@ +{ pkgs, config, lib, ... }: + +let + cfg = config.services.syncyomi; + defaultUser = "syncyomi"; + defaultGroup = defaultUser; + defaultStateDir = "/var/lib/syncyomi"; + settingsFormat = pkgs.formats.toml { }; +in { + options.services.syncyomi = { + enable = lib.mkEnableOption null; + package = lib.mkPackageOption pkgs "syncyomi" {}; + + user = lib.mkOption { + type = lib.types.str; + default = defaultUser; + }; + + group = lib.mkOption { + type = lib.types.str; + default = defaultGroup; + }; + + stateDir = lib.mkOption { + type = lib.types.str; + default = defaultStateDir; + }; + + settings = lib.mkOption { + type = settingsFormat.type; + default = { }; + }; + }; + + config = lib.mkIf cfg.enable { + services.syncyomi.settings = { + host = lib.mkDefault "127.0.0.1"; + port = lib.mkDefault 8282; + checkForUpdates = lib.mkDefault false; + }; + + users = { + users = lib.mkIf (cfg.user == defaultUser) { + ${defaultUser} = { + home = cfg.stateDir; + group = cfg.group; + isSystemUser = true; + description = "Syncyomi daemon user"; + }; + }; + + groups = lib.mkIf (cfg.group == defaultGroup) { + ${defaultGroup} = { }; + }; + }; + + systemd.services.syncyomi = { + description = "Syncyomi service"; + after = [ "network.target" ]; + wantedBy = [ "multi-user.target" ]; + + serviceConfig = { + Restart = "on-failure"; + User = cfg.user; + Group = cfg.group; + ExecStart = "${cfg.package}/bin/syncyomi --config ${cfg.stateDir}"; + ReadWritePaths = [ cfg.stateDir ]; + ProcSubset = "pid"; + ProtectProc = "invisible"; + CapabilityBoundingSet = ""; + NoNewPrivileges = true; + ProtectSystem = "strict"; + ProtectHome = true; + PrivateTmp = true; + PrivateDevices = true; + PrivateUsers = true; + PrivateMounts = true; + ProtectHostname = true; + ProtectClock = true; + ProtectKernelTunables = true; + ProtectKernelModules = true; + ProtectKernelLogs = true; + ProtectControlGroups = true; + RestrictAddressFamilies = [ "AF_UNIX" "AF_INET" "AF_INET6" ]; + RestrictNamespaces = true; + LockPersonality = true; + MemoryDenyWriteExecute = true; + RestrictRealtime = true; + RestrictSUIDSGID = true; + RemoveIPC = true; + SystemCallArchitectures = "native"; + SystemCallFilter = [ + "@system-service" + "~@keyring @privileged @resources" + "setrlimit" + ]; + }; + }; + + systemd.tmpfiles.rules = let + configToml = settingsFormat.generate "config.toml" cfg.settings; + in [ + "d '${cfg.stateDir}' 0750 ${cfg.user} ${cfg.group} - -" + "z '${cfg.stateDir}' 0750 ${cfg.user} ${cfg.group} - -" + + "L+ '${cfg.stateDir}/config.toml' - - - - ${configToml}" + ]; + }; +} diff --git a/modules/os/misc/virt-manager.nix b/modules/os/misc/virt-manager.nix new file mode 100644 index 0000000..4f62860 --- /dev/null +++ b/modules/os/misc/virt-manager.nix @@ -0,0 +1,17 @@ +{ pkgs, config, lib, ... }: + +let + cfg = config.my.virt-manager; +in { + options.my.virt-manager = { + enable = lib.mkEnableOption null; + }; + + config = lib.mkIf cfg.enable { + virtualisation.libvirtd.enable = true; + + environment.systemPackages = [ pkgs.virt-manager ]; + + my.user.extraGroups = [ "libvirtd" ]; + }; +} diff --git a/modules/os/misc/wireshark.nix b/modules/os/misc/wireshark.nix new file mode 100644 index 0000000..6ad11d4 --- /dev/null +++ b/modules/os/misc/wireshark.nix @@ -0,0 +1,18 @@ +{ pkgs, config, lib, ... }: + +let + cfg = config.my.wireshark; +in { + options.my.wireshark = { + enable = lib.mkEnableOption null; + }; + + config = lib.mkIf cfg.enable { + programs.wireshark = { + enable = true; + package = lib.mkIf config.my.desktop.enable pkgs.wireshark; + }; + + my.user.extraGroups = [ "wireshark" ]; + }; +} diff --git a/secrets/authinfo.age b/secrets/authinfo.age new file mode 100644 index 0000000..e3b784b Binary files /dev/null and b/secrets/authinfo.age differ diff --git a/secrets/email.json.age b/secrets/email.json.age new file mode 100644 index 0000000..30b097a Binary files /dev/null and b/secrets/email.json.age differ diff --git a/secrets/nix-tokens.age b/secrets/nix-tokens.age new file mode 100644 index 0000000..fb21cf9 Binary files /dev/null and b/secrets/nix-tokens.age differ diff --git a/secrets/porkbun-auth.age b/secrets/porkbun-auth.age new file mode 100644 index 0000000..0da8935 Binary files /dev/null and b/secrets/porkbun-auth.age differ diff --git a/secrets/secrets.nix b/secrets/secrets.nix new file mode 100644 index 0000000..ddb288c --- /dev/null +++ b/secrets/secrets.nix @@ -0,0 +1,19 @@ +let + errie = "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIElnlmCCIRhwe7z/a4dpwNoPF65II8NsOHUWJIBdr2Rg"; + serverie = "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIJmM1h4bv1sp1SUqJAwSNj7kVsjv2ePHu6gq5U+ph2Y8"; + users = [ errie serverie ]; + + msft-laptop = "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIEHK36iDfBlqYfgjH1OdmmGcaTYQAgMUfqa4FAGP6746"; + groceries = "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIGLm/4PyN12Xi/x8+2Y3dvGk2bnuOpETVkH3TK/ZqtuS"; + systems = [ msft-laptop groceries ]; + + keys = users ++ systems; +in { + "spotify.age".publicKeys = keys; + "nix-tokens.age".publicKeys = keys; + "authinfo.age".publicKeys = keys; + "email.json.age".publicKeys = keys; + "porkbun-auth.age".publicKeys = keys; + "wg-groceries.age".publicKeys = keys; + "wg-nix-laptop.age".publicKeys = keys; +} diff --git a/secrets/spotify.age b/secrets/spotify.age new file mode 100644 index 0000000..e502f50 Binary files /dev/null and b/secrets/spotify.age differ diff --git a/secrets/wg-groceries.age b/secrets/wg-groceries.age new file mode 100644 index 0000000..2ea792b Binary files /dev/null and b/secrets/wg-groceries.age differ diff --git a/secrets/wg-nix-laptop.age b/secrets/wg-nix-laptop.age new file mode 100644 index 0000000..30a5eac --- /dev/null +++ b/secrets/wg-nix-laptop.age @@ -0,0 +1,11 @@ +age-encryption.org/v1 +-> ssh-ed25519 BxKgLg FWhM3lEJ5FbJkLjwX+7EZqAs/FoE/j/OFbF54koGVRc +wLIme4VmiB3giJ9F7hUQPn/UnCiFdryZhqHZ8NWUPEY +-> ssh-ed25519 wzJ79w zPZrXFOYNRcriFcXxPDRO3UbHibnMHlxbJpkBYfhcg0 +VrDtxRZRY2c1xOqvdhp1wB65gZIChQ9M0sqmDvmX5k0 +-> ssh-ed25519 9OcGhw YO89PTC+9fb+KKA5QWFwq2/gyX4b/W1kbio/pn9aZjE +Q2GdHEgnDR+z3WQrCBZx1fgBIduFuJKv2om2Giv5P7Q +-> ssh-ed25519 JXeYqg UXDz0sWZRoxQ69/q74ncDHdbnlqwACpGbmL3P9Z1q38 +W5mD6CqomQBN3v/51ekqhplLKLi75ASI1jXrW3OvgCM +--- Mm3iVwuLG8Vgpn8P9Qb4KBIMJuL0aL8zxn6tz6/lp0s +:Zerx2OAZb2\I˲s")Fxy.{F9orEUN}z! \ No newline at end of file