├── .gitignore ├── .sops.yaml ├── .vscode └── settings.json ├── LICENSE-MIT ├── flake.lock ├── flake.nix ├── home ├── blacksteel.nix ├── invar.nix └── modules │ ├── alacritty.nix │ ├── direnv.nix │ ├── firefox.nix │ ├── git.nix │ ├── gpg.nix │ ├── helix │ └── default.nix │ ├── lf.nix │ ├── mail.nix │ ├── nvim │ ├── default.nix │ └── vimrc.vim │ ├── programs.nix │ ├── rime-fcitx.nix │ ├── rust.nix │ ├── shell │ ├── cmds.zsh │ ├── completion.zsh │ ├── default.nix │ ├── key-bindings.zsh │ └── prompt.zsh │ ├── tmux.nix │ ├── user-dirs.nix │ ├── vscode │ └── default.nix │ └── xdgify.nix ├── lib.nix ├── my ├── default.nix └── gpg-pubkey.asc ├── nixos ├── blacksteel │ ├── configuration.nix │ ├── secret.yaml │ └── vm.nix ├── copper │ └── configuration.nix ├── invar │ ├── btrbk.nix │ ├── configuration.nix │ ├── game.nix │ ├── orb.nix │ ├── secret.yaml │ └── syncthing.nix ├── lithium │ ├── blah.nix │ ├── configuration.nix │ ├── ntfy.nix │ ├── secret.yaml │ └── webdav.nix ├── minimal-image │ └── configuration.nix ├── modules │ ├── console-env.nix │ ├── device-fix.nix │ ├── kde-desktop │ │ └── default.nix │ ├── l10n.nix │ ├── nix-binary-cache-mirror.nix │ ├── nix-cgroups.nix │ ├── nix-common.nix │ ├── nix-keep-flake-inputs.nix │ ├── nix-registry.nix │ ├── secure-boot.nix │ ├── server-env.nix │ ├── vultr-common.nix │ ├── vultr-image.nix │ └── zswap-enable.nix └── unmatched │ └── configuration.nix ├── pkgs ├── _sources │ ├── generated.json │ └── generated.nix ├── caddy-oxa │ ├── 0001-caddyauth-use-same-cost-for-users-and-fake-hash.patch │ └── default.nix ├── cargo-machete-no-spam.nix ├── coc-rust-analyzer-fix-snippet │ └── default.nix ├── colors.nix ├── default.nix ├── keystat │ ├── default.nix │ └── keystat.py ├── nixos-rebuild-shortcut │ ├── default.nix │ └── nixos.sh ├── nvfetcher.toml ├── prismlauncher-bwrap.nix ├── rime_latex.nix ├── show-headless-desktop.nix ├── systemd-run-app.nix ├── urw-base35-fonts.nix ├── wallpaper-blur.nix ├── wallpaper.nix └── zsh-comma.nix ├── secrets └── ssh.yaml ├── templates ├── ci-rust │ └── .github │ │ └── workflows │ │ ├── ci.yaml │ │ └── future_proof.yaml ├── rust-bin │ ├── .gitignore │ ├── Cargo.toml │ └── src │ │ └── main.rs ├── rust-criterion │ └── benches │ │ └── foo.rs └── rust-lib │ ├── .gitignore │ ├── Cargo.toml │ └── src │ └── lib.rs └── typos.toml /.gitignore: -------------------------------------------------------------------------------- 1 | *.tmp 2 | result 3 | result-* 4 | .envrc 5 | -------------------------------------------------------------------------------- /.sops.yaml: -------------------------------------------------------------------------------- 1 | keys: 2 | - &oxa F90FFD6D585C2BA1F13DE8A97571654CF88E31C2 3 | 4 | - &invar age157zcs4687hmsd834xhvt66apf6v93ss3tt2l23x72lhtvpl69ggqeejgky 5 | - &blacksteel age1l9qly5vlx20uzrqvq8qygvcrtff64mgvqchet5uvs989upy5lugq4krj2c 6 | - &lithium age1telu43gwg7fucnph6x5mgl46yvaj9z0cuj2v4e5d8fxhlsvduqas7psujn 7 | 8 | creation_rules: 9 | - path_regex: secrets/ssh\.yaml$ 10 | key_groups: 11 | - age: 12 | - *invar 13 | - *blacksteel 14 | pgp: 15 | - *oxa 16 | 17 | - path_regex: /invar/secret\.yaml$ 18 | key_groups: 19 | - age: 20 | - *invar 21 | pgp: 22 | - *oxa 23 | 24 | - path_regex: /blacksteel/secret\.yaml$ 25 | key_groups: 26 | - age: 27 | - *blacksteel 28 | pgp: 29 | - *oxa 30 | 31 | - path_regex: /lithium/secret\.yaml$ 32 | key_groups: 33 | - age: 34 | - *lithium 35 | pgp: 36 | - *oxa 37 | -------------------------------------------------------------------------------- /.vscode/settings.json: -------------------------------------------------------------------------------- 1 | { 2 | "files.trimTrailingWhitespace": true, 3 | "files.insertFinalNewline": true, 4 | "files.trimFinalNewlines": true, 5 | 6 | "editor.tabSize": 2, 7 | } 8 | -------------------------------------------------------------------------------- /LICENSE-MIT: -------------------------------------------------------------------------------- 1 | Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: 2 | 3 | The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. 4 | 5 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 6 | -------------------------------------------------------------------------------- /flake.lock: -------------------------------------------------------------------------------- 1 | { 2 | "nodes": { 3 | "blahrs": { 4 | "inputs": { 5 | "naersk": "naersk", 6 | "nixpkgs": [ 7 | "nixpkgs" 8 | ], 9 | "rust-overlay": [ 10 | "rust-overlay" 11 | ] 12 | }, 13 | "locked": { 14 | "lastModified": 1744763289, 15 | "narHash": "sha256-WVZoYSexN5TVmK69pLUq6yo8WJLze7wYipEMaWmg0fQ=", 16 | "owner": "Blah-IM", 17 | "repo": "blahrs", 18 | "rev": "40e4a538866cceb2735e4cb5a40d8b774d02329e", 19 | "type": "github" 20 | }, 21 | "original": { 22 | "owner": "Blah-IM", 23 | "repo": "blahrs", 24 | "type": "github" 25 | } 26 | }, 27 | "cargo-bloated": { 28 | "inputs": { 29 | "nixpkgs": [ 30 | "nixpkgs" 31 | ] 32 | }, 33 | "locked": { 34 | "lastModified": 1746944458, 35 | "narHash": "sha256-ZlzonxjZIksRSDYyEmhqJD82wpDo+GYEKoyw0C+TeQc=", 36 | "owner": "oxalica", 37 | "repo": "cargo-bloated", 38 | "rev": "58f86063efa7febba25ffc73d7d83f31afcb5e47", 39 | "type": "github" 40 | }, 41 | "original": { 42 | "owner": "oxalica", 43 | "repo": "cargo-bloated", 44 | "type": "github" 45 | } 46 | }, 47 | "crane": { 48 | "locked": { 49 | "lastModified": 1731098351, 50 | "narHash": "sha256-HQkYvKvaLQqNa10KEFGgWHfMAbWBfFp+4cAgkut+NNE=", 51 | "owner": "ipetkov", 52 | "repo": "crane", 53 | "rev": "ef80ead953c1b28316cc3f8613904edc2eb90c28", 54 | "type": "github" 55 | }, 56 | "original": { 57 | "owner": "ipetkov", 58 | "repo": "crane", 59 | "type": "github" 60 | } 61 | }, 62 | "flake-parts": { 63 | "inputs": { 64 | "nixpkgs-lib": [ 65 | "lanzaboote", 66 | "nixpkgs" 67 | ] 68 | }, 69 | "locked": { 70 | "lastModified": 1730504689, 71 | "narHash": "sha256-hgmguH29K2fvs9szpq2r3pz2/8cJd2LPS+b4tfNFCwE=", 72 | "owner": "hercules-ci", 73 | "repo": "flake-parts", 74 | "rev": "506278e768c2a08bec68eb62932193e341f55c90", 75 | "type": "github" 76 | }, 77 | "original": { 78 | "owner": "hercules-ci", 79 | "repo": "flake-parts", 80 | "type": "github" 81 | } 82 | }, 83 | "flake-utils": { 84 | "inputs": { 85 | "systems": "systems" 86 | }, 87 | "locked": { 88 | "lastModified": 1731533236, 89 | "narHash": "sha256-l0KFg5HjrsfsO/JpG+r7fRrqm12kzFHyUHqHCVpMMbI=", 90 | "owner": "numtide", 91 | "repo": "flake-utils", 92 | "rev": "11707dc2f618dd54ca8739b309ec4fc024de578b", 93 | "type": "github" 94 | }, 95 | "original": { 96 | "owner": "numtide", 97 | "repo": "flake-utils", 98 | "type": "github" 99 | } 100 | }, 101 | "home-manager": { 102 | "inputs": { 103 | "nixpkgs": [ 104 | "nixpkgs" 105 | ] 106 | }, 107 | "locked": { 108 | "lastModified": 1748925027, 109 | "narHash": "sha256-BJ0qRIdvt5aeqm3zg/5if7b5rruG05zrSX3UpLqjDRk=", 110 | "owner": "nix-community", 111 | "repo": "home-manager", 112 | "rev": "cb809ec1ff15cf3237c6592af9bbc7e4d983e98c", 113 | "type": "github" 114 | }, 115 | "original": { 116 | "owner": "nix-community", 117 | "repo": "home-manager", 118 | "type": "github" 119 | } 120 | }, 121 | "lanzaboote": { 122 | "inputs": { 123 | "crane": "crane", 124 | "flake-compat": [ 125 | "blank" 126 | ], 127 | "flake-parts": "flake-parts", 128 | "nixpkgs": [ 129 | "nixpkgs" 130 | ], 131 | "pre-commit-hooks-nix": [ 132 | "blank" 133 | ], 134 | "rust-overlay": [ 135 | "rust-overlay" 136 | ] 137 | }, 138 | "locked": { 139 | "lastModified": 1737639419, 140 | "narHash": "sha256-AEEDktApTEZ5PZXNDkry2YV2k6t0dTgLPEmAZbnigXU=", 141 | "owner": "nix-community", 142 | "repo": "lanzaboote", 143 | "rev": "a65905a09e2c43ff63be8c0e86a93712361f871e", 144 | "type": "github" 145 | }, 146 | "original": { 147 | "owner": "nix-community", 148 | "ref": "v0.4.2", 149 | "repo": "lanzaboote", 150 | "type": "github" 151 | } 152 | }, 153 | "meta-sifive": { 154 | "flake": false, 155 | "locked": { 156 | "lastModified": 1638461064, 157 | "narHash": "sha256-Toh80cXl+w1QFrbZnCP2Bjg2eN1V8vItACOO7/rWx0k=", 158 | "owner": "sifive", 159 | "repo": "meta-sifive", 160 | "rev": "dc0441b841dba14ead2cba8f6f7c086c11ad89b0", 161 | "type": "github" 162 | }, 163 | "original": { 164 | "owner": "sifive", 165 | "ref": "2021.11.00", 166 | "repo": "meta-sifive", 167 | "type": "github" 168 | } 169 | }, 170 | "naersk": { 171 | "inputs": { 172 | "nixpkgs": [ 173 | "blahrs", 174 | "nixpkgs" 175 | ] 176 | }, 177 | "locked": { 178 | "lastModified": 1739824009, 179 | "narHash": "sha256-fcNrCMUWVLMG3gKC5M9CBqVOAnJtyRvGPxptQFl5mVg=", 180 | "owner": "nix-community", 181 | "repo": "naersk", 182 | "rev": "e5130d37369bfa600144c2424270c96f0ef0e11d", 183 | "type": "github" 184 | }, 185 | "original": { 186 | "owner": "nix-community", 187 | "repo": "naersk", 188 | "type": "github" 189 | } 190 | }, 191 | "nixpkgs": { 192 | "locked": { 193 | "lastModified": 1748693115, 194 | "narHash": "sha256-StSrWhklmDuXT93yc3GrTlb0cKSS0agTAxMGjLKAsY8=", 195 | "owner": "NixOS", 196 | "repo": "nixpkgs", 197 | "rev": "910796cabe436259a29a72e8d3f5e180fc6dfacc", 198 | "type": "github" 199 | }, 200 | "original": { 201 | "owner": "NixOS", 202 | "ref": "nixos-unstable", 203 | "repo": "nixpkgs", 204 | "type": "github" 205 | } 206 | }, 207 | "nixpkgs-logseq": { 208 | "locked": { 209 | "lastModified": 1740560979, 210 | "narHash": "sha256-Vr3Qi346M+8CjedtbyUevIGDZW8LcA1fTG0ugPY/Hic=", 211 | "owner": "NixOS", 212 | "repo": "nixpkgs", 213 | "rev": "5135c59491985879812717f4c9fea69604e7f26f", 214 | "type": "github" 215 | }, 216 | "original": { 217 | "owner": "NixOS", 218 | "repo": "nixpkgs", 219 | "rev": "5135c59491985879812717f4c9fea69604e7f26f", 220 | "type": "github" 221 | } 222 | }, 223 | "nixpkgs-stable": { 224 | "locked": { 225 | "lastModified": 1720535198, 226 | "narHash": "sha256-zwVvxrdIzralnSbcpghA92tWu2DV2lwv89xZc8MTrbg=", 227 | "owner": "NixOS", 228 | "repo": "nixpkgs", 229 | "rev": "205fd4226592cc83fd4c0885a3e4c9c400efabb5", 230 | "type": "github" 231 | }, 232 | "original": { 233 | "owner": "NixOS", 234 | "ref": "nixos-23.11", 235 | "repo": "nixpkgs", 236 | "type": "github" 237 | } 238 | }, 239 | "nixpkgs-unmatched": { 240 | "locked": { 241 | "lastModified": 1640713360, 242 | "narHash": "sha256-MzrVpY1CvK5N60fW3ShYr/P7Gn2yxCBqlSLRJKjwAqs=", 243 | "owner": "oxalica", 244 | "repo": "nixpkgs", 245 | "rev": "68ffecb7b9ed47985dab86a7d7563ffb3f2a9155", 246 | "type": "github" 247 | }, 248 | "original": { 249 | "owner": "oxalica", 250 | "ref": "test/unmatched", 251 | "repo": "nixpkgs", 252 | "type": "github" 253 | } 254 | }, 255 | "nocargo": { 256 | "inputs": { 257 | "flake-utils": [ 258 | "flake-utils" 259 | ], 260 | "nixpkgs": [ 261 | "nixpkgs" 262 | ], 263 | "registry-crates-io": "registry-crates-io" 264 | }, 265 | "locked": { 266 | "lastModified": 1745995660, 267 | "narHash": "sha256-Cca7/uDRwfo4UnPhZX31+vQ7chKr9nJsMvwykGllDVA=", 268 | "owner": "oxalica", 269 | "repo": "nocargo", 270 | "rev": "089f487c2c123454c8b9a381a99999b63c53d1d6", 271 | "type": "github" 272 | }, 273 | "original": { 274 | "owner": "oxalica", 275 | "repo": "nocargo", 276 | "type": "github" 277 | } 278 | }, 279 | "orb": { 280 | "inputs": { 281 | "nixpkgs": [ 282 | "nixpkgs" 283 | ] 284 | }, 285 | "locked": { 286 | "lastModified": 1744512440, 287 | "narHash": "sha256-MaMhYiO+zM0seg6144/mI9WK4ARUzaCHE2ugUCO/IoA=", 288 | "owner": "oxalica", 289 | "repo": "orb", 290 | "rev": "0156bb182d1647f025f1128d096c88c5df78f63d", 291 | "type": "github" 292 | }, 293 | "original": { 294 | "owner": "oxalica", 295 | "repo": "orb", 296 | "type": "github" 297 | } 298 | }, 299 | "registry-crates-io": { 300 | "flake": false, 301 | "locked": { 302 | "lastModified": 1704732624, 303 | "narHash": "sha256-FWX5JX33ievm6JuIEp1lI5EPndYt8s6anU+fQBYuFKc=", 304 | "owner": "rust-lang", 305 | "repo": "crates.io-index", 306 | "rev": "4445fa0011e6ff9989985651bec57eb4cbefcadd", 307 | "type": "github" 308 | }, 309 | "original": { 310 | "owner": "rust-lang", 311 | "repo": "crates.io-index", 312 | "type": "github" 313 | } 314 | }, 315 | "root": { 316 | "inputs": { 317 | "blahrs": "blahrs", 318 | "blank": [ 319 | "nixpkgs" 320 | ], 321 | "cargo-bloated": "cargo-bloated", 322 | "flake-utils": "flake-utils", 323 | "home-manager": "home-manager", 324 | "lanzaboote": "lanzaboote", 325 | "meta-sifive": "meta-sifive", 326 | "nixpkgs": "nixpkgs", 327 | "nixpkgs-logseq": "nixpkgs-logseq", 328 | "nixpkgs-stable": "nixpkgs-stable", 329 | "nixpkgs-unmatched": "nixpkgs-unmatched", 330 | "nocargo": "nocargo", 331 | "orb": "orb", 332 | "rust-overlay": "rust-overlay", 333 | "secrets": "secrets", 334 | "sops-nix": "sops-nix" 335 | } 336 | }, 337 | "rust-overlay": { 338 | "inputs": { 339 | "nixpkgs": [ 340 | "nixpkgs" 341 | ] 342 | }, 343 | "locked": { 344 | "lastModified": 1748918260, 345 | "narHash": "sha256-KhXNXQ5IDLvwwYfJ0pXDjwIuisZ2qM6F7fcXjIGZy/4=", 346 | "owner": "oxalica", 347 | "repo": "rust-overlay", 348 | "rev": "c9736155bc1eb7c7cf3a925920850e61c07ab22a", 349 | "type": "github" 350 | }, 351 | "original": { 352 | "owner": "oxalica", 353 | "repo": "rust-overlay", 354 | "type": "github" 355 | } 356 | }, 357 | "secrets": { 358 | "locked": { 359 | "lastModified": 1744799127, 360 | "narHash": "sha256-5n/OSVBcfeJI9tNS+laFv5+mX8gloTuM8TTXdWJrngs=", 361 | "path": "/home/oxa/storage/repo/nixos-config-secrets", 362 | "type": "path" 363 | }, 364 | "original": { 365 | "path": "/home/oxa/storage/repo/nixos-config-secrets", 366 | "type": "path" 367 | } 368 | }, 369 | "sops-nix": { 370 | "inputs": { 371 | "nixpkgs": [ 372 | "nixpkgs" 373 | ] 374 | }, 375 | "locked": { 376 | "lastModified": 1747603214, 377 | "narHash": "sha256-lAblXm0VwifYCJ/ILPXJwlz0qNY07DDYdLD+9H+Wc8o=", 378 | "owner": "Mic92", 379 | "repo": "sops-nix", 380 | "rev": "8d215e1c981be3aa37e47aeabd4e61bb069548fd", 381 | "type": "github" 382 | }, 383 | "original": { 384 | "owner": "Mic92", 385 | "repo": "sops-nix", 386 | "type": "github" 387 | } 388 | }, 389 | "systems": { 390 | "locked": { 391 | "lastModified": 1681028828, 392 | "narHash": "sha256-Vy1rq5AaRuLzOxct8nz4T6wlgyUR7zLU309k9mBC768=", 393 | "owner": "nix-systems", 394 | "repo": "default", 395 | "rev": "da67096a3b9bf56a91d16901293e51ba5b49a27e", 396 | "type": "github" 397 | }, 398 | "original": { 399 | "owner": "nix-systems", 400 | "repo": "default", 401 | "type": "github" 402 | } 403 | } 404 | }, 405 | "root": "root", 406 | "version": 7 407 | } 408 | -------------------------------------------------------------------------------- /flake.nix: -------------------------------------------------------------------------------- 1 | { 2 | description = "oxalica's NixOS configuration"; 3 | 4 | inputs = { 5 | nixpkgs.url = "github:NixOS/nixpkgs/nixos-unstable"; 6 | nixpkgs-stable.url = "github:NixOS/nixpkgs/nixos-23.11"; 7 | nixpkgs-unmatched.url = "github:oxalica/nixpkgs/test/unmatched"; 8 | 9 | # WAIT: https://github.com/NixOS/nixpkgs/pull/389363 10 | nixpkgs-logseq.url = "github:NixOS/nixpkgs/5135c59491985879812717f4c9fea69604e7f26f"; 11 | 12 | # Placeholder. 13 | blank.follows = "nixpkgs"; 14 | 15 | flake-utils.url = "github:numtide/flake-utils"; 16 | home-manager = { 17 | url = "github:nix-community/home-manager"; 18 | inputs.nixpkgs.follows = "nixpkgs"; 19 | }; 20 | rust-overlay = { 21 | url = "github:oxalica/rust-overlay"; 22 | inputs.nixpkgs.follows = "nixpkgs"; 23 | }; 24 | nocargo = { 25 | url = "github:oxalica/nocargo"; 26 | inputs.nixpkgs.follows = "nixpkgs"; 27 | inputs.flake-utils.follows = "flake-utils"; 28 | }; 29 | sops-nix = { 30 | url = "github:Mic92/sops-nix"; 31 | inputs.nixpkgs.follows = "nixpkgs"; 32 | }; 33 | lanzaboote = { 34 | url = "github:nix-community/lanzaboote/v0.4.2"; 35 | inputs.pre-commit-hooks-nix.follows = "blank"; 36 | inputs.flake-compat.follows = "blank"; 37 | inputs.nixpkgs.follows = "nixpkgs"; 38 | inputs.rust-overlay.follows = "rust-overlay"; 39 | }; 40 | orb = { 41 | url = "github:oxalica/orb"; 42 | inputs.nixpkgs.follows = "nixpkgs"; 43 | }; 44 | blahrs = { 45 | url = "github:Blah-IM/blahrs"; 46 | inputs.nixpkgs.follows = "nixpkgs"; 47 | inputs.rust-overlay.follows = "rust-overlay"; 48 | }; 49 | cargo-bloated = { 50 | url = "github:oxalica/cargo-bloated"; 51 | inputs.nixpkgs.follows = "nixpkgs"; 52 | }; 53 | 54 | meta-sifive = { 55 | url = "github:sifive/meta-sifive/2021.11.00"; 56 | flake = false; 57 | }; 58 | 59 | # Optional. 60 | secrets.url = "/home/oxa/storage/repo/nixos-config-secrets"; 61 | }; 62 | 63 | outputs = { self, nixpkgs, flake-utils, ... }@inputs: let 64 | 65 | inherit (nixpkgs) lib; 66 | 67 | overlays = { 68 | }; 69 | 70 | nixosModules = { 71 | # Ref: https://github.com/dramforever/config/blob/63be844019b7ca675ea587da3b3ff0248158d9fc/flake.nix#L24-L28 72 | system-label = { 73 | system.configurationRevision = self.rev or null; 74 | system.nixos.label = 75 | if self.sourceInfo ? lastModifiedDate && self.sourceInfo ? shortRev 76 | then "${lib.substring 0 8 self.sourceInfo.lastModifiedDate}.${self.sourceInfo.shortRev}" 77 | else lib.warn "Repo is dirty, revision will not be available in system label" "dirty"; 78 | }; 79 | 80 | home-manager = { config, inputs, my, ... }: { 81 | imports = [ inputs.home-manager.nixosModules.home-manager ]; 82 | home-manager = { 83 | useGlobalPkgs = true; 84 | useUserPackages = true; 85 | verbose = true; 86 | extraSpecialArgs = { 87 | inherit inputs my; 88 | super = config; 89 | }; 90 | }; 91 | }; 92 | 93 | sops = { config, ... }: { 94 | imports = [ inputs.sops-nix.nixosModules.sops ]; 95 | sops.age.sshKeyPaths = [ "/etc/ssh/ssh_host_ed25519_key" ]; 96 | sops.gnupg.sshKeyPaths = []; 97 | sops.defaultSopsFile = ./nixos/${config.networking.hostName}/secret.yaml; 98 | }; 99 | }; 100 | 101 | mkSystem = name: system: nixpkgs: { extraModules ? [] }: nixpkgs.lib.nixosSystem { 102 | inherit system; 103 | specialArgs = { 104 | inputs = inputs // { inherit nixpkgs; }; 105 | my = import ./my // { 106 | pkgs = self.packages.${system}; 107 | }; 108 | }; 109 | modules = with nixosModules; [ 110 | system-label 111 | { networking.hostName = lib.mkDefault name; } 112 | { nixpkgs.overlays = builtins.attrValues overlays; } 113 | ./nixos/${name}/configuration.nix 114 | ] ++ extraModules; 115 | }; 116 | 117 | in { 118 | inherit overlays nixosModules; 119 | 120 | lib = import ./lib.nix { 121 | inherit (nixpkgs) lib; 122 | }; 123 | 124 | nixosSystems = lib.mapAttrs 125 | (name: conf: conf.config.system.build.toplevel) 126 | self.nixosConfigurations; 127 | 128 | nixosConfigurations = { 129 | invar = mkSystem "invar" "x86_64-linux" inputs.nixpkgs { 130 | extraModules = with nixosModules; [ home-manager sops inputs.orb.nixosModules.orb ]; 131 | }; 132 | 133 | blacksteel = mkSystem "blacksteel" "x86_64-linux" inputs.nixpkgs { 134 | extraModules = with nixosModules; [ home-manager sops ]; 135 | }; 136 | 137 | lithium = mkSystem "lithium" "x86_64-linux" inputs.nixpkgs { 138 | extraModules = with nixosModules; [ sops inputs.blahrs.nixosModules.blahd ]; 139 | }; 140 | 141 | copper = mkSystem "copper" "x86_64-linux" inputs.nixpkgs-stable { 142 | extraModules = with nixosModules; [ sops ]; 143 | }; 144 | 145 | unmatched = mkSystem "unmatched" "riscv64-linux" inputs.nixpkgs-unmatched { }; 146 | unmatched-cross = mkSystem "unmatched" "x86_64-linux" inputs.nixpkgs-unmatched { 147 | extraModules = [ 148 | { nixpkgs.crossSystem.config = "riscv64-unknown-linux-gnu"; } 149 | ]; 150 | }; 151 | 152 | minimal-image-stable = mkSystem "minimal-image" "x86_64-linux" inputs.nixpkgs-stable { }; 153 | minimal-image-unstable = mkSystem "minimal-image" "x86_64-linux" inputs.nixpkgs { }; 154 | }; 155 | 156 | images = { 157 | minimal-iso-stable = self.nixosConfigurations.minimal-image-stable.config.system.build.isoImage; 158 | minimal-iso-unstable = self.nixosConfigurations.minimal-image-unstable.config.system.build.isoImage; 159 | }; 160 | 161 | templates = { 162 | rust-bin = { 163 | description = "A simple Rust project for binaries"; 164 | path = ./templates/rust-bin; 165 | }; 166 | rust-lib = { 167 | description = "A simple Rust project for libraries"; 168 | path = ./templates/rust-lib; 169 | }; 170 | rust-criterion = { 171 | description = "Criterion benchmark templates"; 172 | path = ./templates/rust-criterion; 173 | }; 174 | ci-rust = { 175 | description = "A sample GitHub CI setup for Rust projects"; 176 | path = ./templates/ci-rust; 177 | }; 178 | }; 179 | 180 | } // flake-utils.lib.eachDefaultSystem (system: rec { 181 | packages = import ./pkgs { 182 | inherit lib inputs; 183 | pkgs = nixpkgs.legacyPackages.${system}; 184 | }; 185 | 186 | checks = packages; 187 | 188 | devShells.default = 189 | with nixpkgs.legacyPackages.${system}; 190 | mkShellNoCC { 191 | packages = [ nvfetcher packages.nixos-rebuild-shortcut ]; 192 | }; 193 | 194 | devShells.rust-nightly = 195 | let 196 | pkgs = nixpkgs.legacyPackages.${system}; 197 | now = inputs.rust-overlay.lastModifiedDate; 198 | date = "${lib.substring 0 4 now}-${lib.substring 4 2 now}-01"; 199 | toolchain = inputs.rust-overlay.packages.${system}."rust-nightly_${date}".override { 200 | extensions = [ 201 | "llvm-tools" 202 | "miri" 203 | "rust-src" 204 | ]; 205 | }; 206 | in pkgs.mkShellNoCC { 207 | packages = [ toolchain ]; 208 | env.CARGO_TARGET_DIR = "/tmp/cargo-nightly-target"; 209 | }; 210 | }); 211 | } 212 | -------------------------------------------------------------------------------- /home/blacksteel.nix: -------------------------------------------------------------------------------- 1 | { lib, config, ... }: 2 | 3 | { 4 | programs.home-manager.enable = true; 5 | 6 | imports = [ 7 | ./modules/alacritty.nix 8 | ./modules/direnv.nix 9 | ./modules/firefox.nix 10 | ./modules/git.nix 11 | ./modules/gpg.nix 12 | ./modules/lf.nix 13 | ./modules/mail.nix 14 | ./modules/nvim 15 | ./modules/programs.nix 16 | ./modules/rime-fcitx.nix 17 | ./modules/rust.nix 18 | ./modules/shell 19 | ./modules/tmux.nix 20 | ./modules/user-dirs.nix 21 | ./modules/vscode 22 | ]; 23 | 24 | programs.alacritty.settings.font.size = lib.mkForce 10; 25 | 26 | home.file = let 27 | home = config.home.homeDirectory; 28 | link = path: config.lib.file.mkOutOfStoreSymlink "${home}/${path}"; 29 | linkPersonal = path: link "storage/personal/${path}"; 30 | in { 31 | ".local/share/fcitx5/rime/sync".source = linkPersonal "rime-sync"; 32 | ".local/share/password-store".source = linkPersonal "password-store"; 33 | }; 34 | 35 | xdg.enable = true; 36 | 37 | home.stateVersion = "24.11"; 38 | } 39 | -------------------------------------------------------------------------------- /home/invar.nix: -------------------------------------------------------------------------------- 1 | { lib, pkgs, config, ... }: 2 | 3 | { 4 | programs.home-manager.enable = true; 5 | 6 | imports = [ 7 | ./modules/alacritty.nix 8 | ./modules/direnv.nix 9 | ./modules/firefox.nix 10 | ./modules/git.nix 11 | ./modules/gpg.nix 12 | ./modules/helix 13 | ./modules/lf.nix 14 | ./modules/mail.nix 15 | ./modules/nvim 16 | ./modules/programs.nix 17 | ./modules/rime-fcitx.nix 18 | ./modules/rust.nix 19 | ./modules/shell 20 | ./modules/tmux.nix 21 | ./modules/user-dirs.nix 22 | ./modules/vscode 23 | ]; 24 | 25 | # For Xwayland apps, ie. electron and steam. 26 | xresources.properties."Xft.dpi" = 120; 27 | # NB. The Xresources is not loaded automatically outside an X session. 28 | systemd.user.services."load-xresources" = { 29 | Unit.Description = "Load user X resources from '~/.Xresources'"; 30 | Service.Type = "oneshot"; 31 | Service.ExecStart = "${lib.getExe pkgs.xorg.xrdb} -load ${config.xresources.path}"; 32 | Unit.After = [ "plasma-kwin_wayland.service" ]; 33 | Install.WantedBy = [ "graphical-session.target" ]; 34 | }; 35 | 36 | xdg.enable = true; 37 | 38 | home.file = let 39 | link = path: config.lib.file.mkOutOfStoreSymlink "${config.home.homeDirectory}/${path}"; 40 | in { 41 | ".local/share/password-store".source = link "storage/5x-state/51-secret/51.10-password-store"; 42 | ".local/share/fcitx5/rime/sync".source = link "storage/5x-state/55-backup/55.06-rime-directory"; 43 | }; 44 | 45 | systemd.user.services."rime-sync" = { 46 | Unit.Description = "Export rime dictionary"; 47 | # https://github.com/fcitx/fcitx5-rime/issues/28#issuecomment-828484970 48 | Service.ExecStart = ''${pkgs.qt5.qttools.bin}/bin/qdbus org.fcitx.Fcitx5 /controller org.fcitx.Fcitx.Controller1.SetConfig "fcitx://config/addon/rime/sync" ""''; 49 | }; 50 | systemd.user.timers."rime-sync" = { 51 | Timer = { 52 | OnCalendar = "*-*-* 03:00:00"; 53 | Persistent = true; 54 | }; 55 | Install.WantedBy = [ "timers.target" ]; 56 | }; 57 | 58 | home.stateVersion = "24.11"; 59 | } 60 | -------------------------------------------------------------------------------- /home/modules/alacritty.nix: -------------------------------------------------------------------------------- 1 | { pkgs, ... }: 2 | { 3 | programs.alacritty = { 4 | enable = true; 5 | 6 | # https://alacritty.org/config-alacritty.html 7 | settings = { 8 | general.import = [ 9 | "${pkgs.vimPlugins.nightfox-nvim}/extra/nightfox/alacritty.toml" 10 | ]; 11 | 12 | window.padding = { x = 4; y = 0; }; 13 | # window.startup_mode = "Fullscreen"; 14 | window.startup_mode = "Maximized"; 15 | 16 | scrolling.history = 1000; # Should not matter since we have tmux. 17 | scrolling.multiplier = 5; 18 | 19 | font.size = 12; 20 | 21 | terminal.shell = { 22 | program = "${pkgs.tmux}/bin/tmux"; 23 | args = [ "new-session" "-t" "main" ]; 24 | }; 25 | 26 | mouse.hide_when_typing = true; 27 | }; 28 | }; 29 | } 30 | -------------------------------------------------------------------------------- /home/modules/direnv.nix: -------------------------------------------------------------------------------- 1 | { ... }: 2 | { 3 | programs.direnv = { 4 | enable = true; 5 | nix-direnv.enable = true; 6 | # bash 7 | stdlib = '' 8 | : ''${XDG_CACHE_HOME:=$HOME/.cache} 9 | declare -A direnv_layout_dirs 10 | direnv_layout_dir() { 11 | echo "''${direnv_layout_dirs[$PWD]:=$( 12 | echo -n "$XDG_CACHE_HOME"/direnv/layouts/ 13 | echo -n "$PWD" | sha1sum | cut -d ' ' -f 1 14 | )}" 15 | } 16 | ''; 17 | }; 18 | } 19 | 20 | -------------------------------------------------------------------------------- /home/modules/firefox.nix: -------------------------------------------------------------------------------- 1 | { pkgs, ... }: 2 | { 3 | programs.firefox = { 4 | enable = true; 5 | 6 | package = pkgs.firefox.overrideAttrs (old: { 7 | nativeBuildInputs = old.nativeBuildInputs or [] ++ [ pkgs.zip pkgs.unzip ]; 8 | 9 | # bash 10 | buildCommand = old.buildCommand + '' 11 | sed '/exec /i [[ "$XDG_SESSION_TYPE" == wayland ]] && export MOZ_ENABLE_WAYLAND=1' \ 12 | --in-place "$out/bin/firefox" 13 | 14 | # Rebind C-W to C-S-W for closing tab. 15 | from1='' 16 | to__1='' 17 | from2='' 18 | to__2=' ' 19 | file="$out/lib/firefox/browser/omni.ja" 20 | # The original file is a symlink. 21 | sed -E "s|$from1|$to__1|; s|$from2|$to__2|" "$file" >"$file.new" 22 | size1="$(stat -L -c '%s' "$file")" 23 | size2="$(stat -L -c '%s' "$file.new")" 24 | echo "$size1 $size2" 25 | [[ $size1 -eq $size2 ]] 26 | mv "$file.new" "$file" 27 | ''; 28 | }); 29 | 30 | profiles."main.profile" = { 31 | id = 0; 32 | isDefault = true; 33 | 34 | settings = { 35 | # Random config 36 | "browser.aboutConfig.showWarning" = false; 37 | "browser.toolbars.bookmarks.visibility" = "newtab"; 38 | "browser.quitShortcut.disabled" = true; # Prevent C-Q to exit browser. 39 | 40 | # 2 = Set "Referer" only when full host name match. 41 | # See: 42 | "network.http.referer.XOriginPolicy" = 2; 43 | 44 | # Theme. 45 | "devtools.theme" = "auto"; 46 | "extensions.activeThemeID" = "efault-theme@mozilla.org"; 47 | "browser.display.use_system_colors" = true; 48 | 49 | # Let our font-config choose final fonts. 50 | "font.language.group" = "zh-CN"; 51 | "font.name.monospace.zh-CN" = "monospace"; 52 | "font.name.sans-serif.zh-CN" = "sans-serif"; 53 | "font.name.serif.zh-CN" = "serif"; 54 | 55 | # Hardware video decoding support. 56 | # See: https://wiki.archlinux.org/index.php/Firefox#Hardware_video_acceleration 57 | "gfx.webrender.all" = true; 58 | "media.ffmpeg.vaapi.enabled" = true; 59 | 60 | # Enable user chrome, which is by default disabled. 61 | "toolkit.legacyUserProfileCustomizations.stylesheets" = true; 62 | 63 | # Site isolation. 64 | "fission.autostart" = true; 65 | }; 66 | 67 | # Hide tab 68 | userChrome = '' 69 | #main-window[tabsintitlebar="true"]:not([extradragspace="true"]) #TabsToolbar > .toolbar-items { 70 | opacity: 0; 71 | pointer-events: none; 72 | } 73 | #main-window:not([tabsintitlebar="true"]) #TabsToolbar { 74 | visibility: collapse !important; 75 | } 76 | ''; 77 | }; 78 | 79 | # For test. 80 | profiles."test.profile" = { 81 | id = 1; 82 | isDefault = false; 83 | }; 84 | }; 85 | 86 | # Host bridge for `pass` integration. 87 | programs.browserpass = { 88 | enable = true; 89 | browsers = [ "firefox" ]; 90 | }; 91 | 92 | # https://bugzilla.mozilla.org/show_bug.cgi?id=1699942 93 | home.packages = [ pkgs.arc-theme ]; 94 | } 95 | -------------------------------------------------------------------------------- /home/modules/git.nix: -------------------------------------------------------------------------------- 1 | { pkgs, my, ... }: 2 | { 3 | programs.git = { 4 | enable = true; 5 | 6 | ignores = [ 7 | # vim swap files. 8 | "*~" "*.swp" 9 | 10 | # Editor local settings. 11 | ".vim/coc-settings.json" 12 | ".vscode" 13 | 14 | # Environments 15 | ".envrc" 16 | ]; 17 | 18 | aliases = { 19 | br = "branch"; 20 | cmt = "commit"; 21 | co = "checkout"; 22 | cp = "cherry-pick"; 23 | d = "diff"; 24 | dc = "diff --cached"; 25 | dt = "difftool"; 26 | l = "log"; 27 | mt = "mergetool"; 28 | st = "status"; 29 | sub = "submodule"; 30 | }; 31 | 32 | extraConfig = { 33 | # User & signing. 34 | user.name = "oxalica"; 35 | user.email = "oxalicc@pm.me"; 36 | user.signingKey = my.gpg.fingerprint; 37 | tag.gpgSign = true; 38 | 39 | # Pull. 40 | pull.ff = "only"; 41 | 42 | # Rebase. 43 | rebase.autoSquash = true; 44 | rebase.abbreviateCommands = true; 45 | 46 | # Diff & merge. 47 | diff.external = "${pkgs.difftastic}/bin/difft"; 48 | diff.tool = "nvimdiff"; 49 | difftool.prompt = false; 50 | merge.tool = "nvimdiff"; 51 | merge.conflictstyle = "diff3"; 52 | mergetool.prompt = false; 53 | rerere.enabled = true; 54 | 55 | # Pager. 56 | core.pager = "less"; 57 | pager.branch = "less --quit-if-one-screen"; 58 | pager.stash = "less --quit-if-one-screen"; 59 | 60 | # Display. 61 | # Always show branches and tags for `git log` in `vim-fugitive`. 62 | # See: https://github.com/tpope/vim-fugitive/issues/1965 63 | log.decorate = true; 64 | # Show detailed diff by default for `git stash show`. 65 | stash.showPatch = true; 66 | 67 | # Misc. 68 | init.defaultBranch = "main"; 69 | push.autoSetupRemote = true; 70 | advice.detachedHead = false; 71 | }; 72 | }; 73 | } 74 | -------------------------------------------------------------------------------- /home/modules/gpg.nix: -------------------------------------------------------------------------------- 1 | { pkgs, my, ... }: 2 | { 3 | programs.gpg = { 4 | enable = true; 5 | settings = { 6 | default-key = my.gpg.fingerprint; 7 | personal-cipher-preferences = "AES256 AES192 AES TWOFISH"; 8 | personal-digest-preferences = "SHA512 SHA256"; 9 | personal-compress-preferences = "ZLIB BZIP2 Uncompressed"; 10 | keyserver = "hkps://keys.openpgp.org"; 11 | }; 12 | scdaemonSettings = { 13 | deny-admin = true; 14 | }; 15 | }; 16 | 17 | services.gpg-agent = { 18 | enable = true; 19 | enableScDaemon = true; 20 | enableSshSupport = true; 21 | 22 | pinentry.package = pkgs.pinentry-qt; 23 | defaultCacheTtl = 600; # Default 24 | maxCacheTtl = 1800; # Default 25 | }; 26 | 27 | programs.password-store = { 28 | enable = true; 29 | package = pkgs.pass.withExtensions (ps: [ ps.pass-audit ps.pass-import ps.pass-otp ]); 30 | }; 31 | 32 | home.packages = [ pkgs.qtpass ]; 33 | } 34 | -------------------------------------------------------------------------------- /home/modules/helix/default.nix: -------------------------------------------------------------------------------- 1 | { lib, pkgs, inputs, ... }: 2 | let 3 | inherit (inputs.self.lib) toTOML; 4 | in { 5 | home.packages = with pkgs; [ helix ]; 6 | 7 | xdg.configFile = { 8 | "helix/config.toml".text = toTOML { 9 | theme = "nightfox"; 10 | 11 | editor = { 12 | scrolloff = 5; 13 | scroll-lines = 5; 14 | shell = [ "${lib.getBin pkgs.zsh}/bin/zsh" "-c" ]; 15 | idle-timeout = 0; 16 | 17 | lsp.display-messages = true; 18 | auto-pairs = true; 19 | 20 | auto-format = false; 21 | 22 | cursor-shape = { 23 | normal = "block"; 24 | insert = "bar"; 25 | select = "block"; 26 | }; 27 | }; 28 | 29 | keys = { 30 | normal = { 31 | "g"."h" = [ "select_mode" "goto_line_start" "normal_mode" ]; 32 | "g"."l" = [ "select_mode" "goto_line_end" "normal_mode" ]; 33 | "x" = "extend_to_line_bounds"; 34 | "X" = "extend_line"; 35 | }; 36 | insert = { 37 | "C-space" = "completion"; 38 | }; 39 | }; 40 | }; 41 | 42 | "helix/themes/nightfox.toml".text = toTOML { 43 | palette = rec { 44 | black = "#393b44"; 45 | black_bright = "#575860"; 46 | black_dim = "#30323a"; 47 | blue = "#719cd6"; 48 | blue_bright = "#86abdc"; 49 | blue_dim = "#6085b6"; 50 | cyan = "#63cdcf"; 51 | cyan_bright = "#7ad4d6"; 52 | cyan_dim = "#54aeb0"; 53 | green = "#81b29a"; 54 | green_bright = "#8ebaa4"; 55 | green_dim = "#6e9783"; 56 | magenta = "#9d79d6"; 57 | magenta_bright = "#baa1e2"; 58 | magenta_dim = "#8567b6"; 59 | orange = "#f4a261"; 60 | orange_bright = "#f6b079"; 61 | orange_dim = "#cf8a52"; 62 | pink = "#d67ad2"; 63 | pink_bright = "#dc8ed9"; 64 | pink_dim = "#b668b2"; 65 | red = "#c94f6d"; 66 | red_bright = "#d16983"; 67 | red_dim = "#ab435d"; 68 | white = "#dfdfe0"; 69 | white_bright = "#e4e4e5"; 70 | white_dim = "#bebebe"; 71 | yellow = "#dbc074"; 72 | yellow_bright = "#e0c989"; 73 | yellow_dim = "#baa363"; 74 | 75 | comment = "#768390"; 76 | 77 | bg = "#192330"; 78 | bg_float = "#131a24"; 79 | bg_cursorline = "#29394e"; 80 | bg_border = "#415166"; 81 | bg_sel = "#223249"; 82 | bg_search = "#3a567d"; 83 | bg_incsearch = green; 84 | fg = "#cdcecf"; 85 | fg_status = "#aeafb0"; 86 | fg_linenr = "#71839b"; 87 | 88 | 89 | bracket = fg_status; # Brackets and Punctuation 90 | builtin_var = red; # Builtin variable 91 | builtin_type = cyan_bright; # Builtin type 92 | builtin_const = orange_bright; # Builtin const 93 | conditional = magenta_bright; # Conditional and loop 94 | const = orange_bright; # Constants, imports and booleans 95 | deprecated = fg_linenr; # Deprecated 96 | field = fg_status; # Field 97 | func = blue_bright; # Functions and Titles 98 | ident = cyan; # Identifiers 99 | keyword = magenta; # Keywords 100 | number = orange; # Numbers 101 | operator = fg_status; # Operators 102 | preproc = pink_bright; # PreProc 103 | regex = yellow_bright; # Regex 104 | statement = magenta; # Statements 105 | string = green; # Strings 106 | type = yellow; # Types 107 | variable = white; # Variables 108 | 109 | error = red; 110 | warning = yellow; 111 | info = blue; 112 | hint = green; 113 | 114 | added = green; 115 | removed = red; 116 | changed = yellow; 117 | }; 118 | 119 | "ui.text".fg = "fg"; 120 | "ui.text.focus".fg = "fg"; 121 | "ui.background".bg = "bg"; 122 | "ui.virtual.whitespace".fg = "bg_cursorline"; 123 | # "ui.virtual.ruler" = { bg = "gray" } 124 | 125 | "ui.cursor".bg = "bg_incsearch"; 126 | "ui.cursor.primary".modifiers = ["reversed"]; 127 | "ui.cursor.select".bg = "bg_incsearch"; 128 | "ui.cursor.match" = { fg = "yellow"; modifiers = ["bold"]; }; 129 | 130 | "ui.selection".bg = "bg_sel"; 131 | "ui.selection.primary".bg = "bg_search"; 132 | 133 | "ui.linenr".fg = "fg_linenr"; 134 | "ui.linenr.selected".fg = "yellow"; 135 | 136 | "ui.statusline" = { fg = "fg_status"; bg = "bg_float"; }; 137 | "ui.statusline.inactive" = { fg = "fg_linenr"; bg = "bg_float"; }; 138 | 139 | "ui.help".bg = "bg_sel"; 140 | "ui.popup".bg = "bg_sel"; 141 | "ui.menu".bg = "bg_sel"; 142 | "ui.menu.selected".bg = "bg_search"; 143 | "ui.window".fg = "fg_linenr"; 144 | 145 | "warning".fg = "warning"; 146 | "error".fg = "error"; 147 | "info".fg = "info"; 148 | "hint".fg = "hint"; 149 | "diagnostic".modifiers = ["underlined"]; 150 | 151 | "diff.plus".fg = "added"; 152 | "diff.minus".fg = "deleted"; 153 | "diff.delta".fg = "changed"; 154 | 155 | # "markup.heading" = 156 | 157 | "attribute".fg = "const"; 158 | "comment".fg = "comment"; 159 | "constant".fg = "const"; 160 | "constant.builtin".fg = "builtin_const"; 161 | "constant.character".fg = "string"; 162 | "constant.character.escape" = { fg = "regex"; modifiers = ["bold"]; }; 163 | "constant.numeric".fg = "number"; 164 | "constructor".fg = "keyword"; 165 | "function".fg = "func"; 166 | "function.builtin".fg = "builtin_var"; 167 | "function.macro".fg = "preproc"; 168 | "keyword".fg = "keyword"; 169 | "keyword.control".fg = "conditional"; 170 | "keyword.control.import".fg = "preproc"; 171 | "keyword.directive".fg = "constant"; 172 | "keyword.function".fg = "builtin_var"; 173 | "keyword.operator".fg = "operator"; 174 | "label".fg = "conditional"; 175 | "namespace".fg = "builtin_type"; 176 | "operator".fg = "operator"; 177 | "property".fg = "field"; 178 | "special".fg = "func"; 179 | "string".fg = "string"; 180 | "string.regexp".fg = "regex"; 181 | "string.special".fg = "func"; 182 | "type".fg = "type"; 183 | "variable".fg = "variable"; 184 | "variable.builtin".fg = "builtin_var"; 185 | "variable.other.member".fg = "field"; 186 | "variable.parameter".fg = "builtin_var"; 187 | 188 | # "markup.heading".fg = ""; 189 | }; 190 | }; 191 | } 192 | -------------------------------------------------------------------------------- /home/modules/lf.nix: -------------------------------------------------------------------------------- 1 | { 2 | programs.lf = { 3 | enable = true; 4 | 5 | settings = { 6 | scrolloff = 5; 7 | }; 8 | 9 | keybindings = { 10 | # Mouse. 11 | "" = "scroll-up"; 12 | "" = "scroll-down"; 13 | 14 | "" = "delete"; 15 | D = "delete"; 16 | x = "cut"; 17 | "" = "set hidden!"; 18 | }; 19 | 20 | extraConfig = '' 21 | set mouse 22 | set scrolloff 5 23 | ''; 24 | }; 25 | } 26 | -------------------------------------------------------------------------------- /home/modules/mail.nix: -------------------------------------------------------------------------------- 1 | { pkgs, ... }: 2 | { 3 | home.packages = with pkgs; [ 4 | (thunderbird.overrideAttrs (old: { 5 | # bash 6 | buildCommand = old.buildCommand + '' 7 | sed '/exec /i [[ "$XDG_SESSION_TYPE" == wayland ]] && export MOZ_ENABLE_WAYLAND=1' \ 8 | --in-place "$out/bin/thunderbird" 9 | ''; 10 | })) 11 | ]; 12 | } 13 | -------------------------------------------------------------------------------- /home/modules/nvim/default.nix: -------------------------------------------------------------------------------- 1 | { lib, config, pkgs, my, ... }: 2 | let 3 | inherit (pkgs) vimPlugins; 4 | 5 | vimrc = builtins.readFile ./vimrc.vim; 6 | 7 | vimrc' = builtins.replaceStrings 8 | ["@fcitx5-remote@"] 9 | ["${lib.getBin pkgs.fcitx5}/bin/fcitx5-remote"] 10 | vimrc; 11 | 12 | plugins = 13 | map (x: vimPlugins.${lib.elemAt x 0}) 14 | (lib.filter (x: lib.isList x) 15 | (builtins.split ''" plugin: ([A-Za-z_-]+)'' vimrc)) ++ 16 | cocPlugins ++ [ 17 | (pkgs.runCommandNoCC "koka-vim" { } '' 18 | cp -r ${pkgs.koka.src}/support/vim $out 19 | '') 20 | ]; 21 | 22 | coc-rust-analyzer = my.pkgs.coc-rust-analyzer-fix-snippet; 23 | 24 | cocPlugins = with vimPlugins; [ 25 | coc-eslint 26 | coc-json 27 | coc-pyright 28 | coc-rust-analyzer 29 | coc-sumneko-lua 30 | coc-tsserver 31 | ]; 32 | 33 | cocSettings = { 34 | "coc.preferences.currentFunctionSymbolAutoUpdate" = true; 35 | "coc.preferences.extensionUpdateCheck" = "never"; 36 | "diagnostic.errorSign" = "⮾ "; 37 | "diagnostic.hintSign" = "💡"; 38 | "diagnostic.infoSign" = "🛈 "; 39 | "diagnostic.warningSign" = "⚠"; 40 | "links.tooltip" = true; 41 | "semanticTokens.enable" = true; 42 | "workspace.ignoredFolders" = [ 43 | "${config.xdg.cacheHome}/cargo/**" 44 | "/nix/store/**" 45 | ]; 46 | 47 | "[rust]"."coc.preferences.formatOnSave" = true; 48 | 49 | "rust-analyzer.updates.checkOnStartup" = false; 50 | "rust-analyzer.server.path" = "rust-analyzer"; # Use relative path, so it prefers direnv if possible. 51 | "rust-analyzer.check.command" = "clippy"; 52 | "rust-analyzer.imports.granularity.group" = "module"; 53 | "rust-analyzer.semanticHighlighting.strings.enable" = false; 54 | "rust-analyzer.inlayHints.parameterHints.enable" = false; 55 | 56 | "sumneko-lua.checkUpdate" = false; 57 | # https://github.com/xiyaowong/coc-sumneko-lua/issues/22#issuecomment-1252284377 58 | "sumneko-lua.serverDir" = "${pkgs.sumneko-lua-language-server}/share/lua-language-server"; 59 | "Lua.misc.parameters" = [ 60 | "--metapath=${config.xdg.cacheHome}/sumneko_lua/meta" 61 | "--logpath=${config.xdg.cacheHome}/sumneko_lua/log" 62 | ]; 63 | 64 | languageserver = { 65 | nix = { 66 | # Use from PATH to allow overriding. 67 | command = "nil"; 68 | filetypes = [ "nix" ]; 69 | rootPatterns = [ "flake.nix" ".git" ]; 70 | settings.nil = { 71 | formatting.command = [ (lib.getExe pkgs.nixfmt-rfc-style) "-" ]; 72 | }; 73 | }; 74 | koka = { 75 | filetypes = [ "koka" ]; 76 | command = "koka"; 77 | args = [ "--language-server" "--lsstdio" ]; 78 | }; 79 | }; 80 | }; 81 | 82 | in 83 | { 84 | programs.neovim = { 85 | enable = true; 86 | withRuby = false; 87 | inherit plugins; 88 | extraConfig = vimrc'; 89 | 90 | coc = { 91 | enable = true; 92 | settings = cocSettings; 93 | }; 94 | }; 95 | 96 | home.sessionVariables.EDITOR = "nvim"; 97 | 98 | home.packages = with pkgs; [ 99 | nil 100 | rust-analyzer 101 | watchman # Required by coc.nvim for file watching. 102 | fzf bat # Required by fzf.vim. 103 | nodejs # FIXME: coc.nvim cannot find node executable 104 | ]; 105 | 106 | # Forbid some LSP (eg. pyright) from watching big directories. 107 | home.file.".watchman.json".text = builtins.toJSON { 108 | ignore_dirs = [ 109 | "/" "/nix" "/nix/store" 110 | "${config.home.homeDirectory}/storage" 111 | "${config.home.homeDirectory}/archive" 112 | ]; 113 | }; 114 | } 115 | -------------------------------------------------------------------------------- /home/modules/nvim/vimrc.vim: -------------------------------------------------------------------------------- 1 | " Settings. {{{1 2 | 3 | " Core. 4 | set fileencodings=ucs-bom,utf-8,gb18030,latin1 5 | set foldmethod=marker 6 | set lazyredraw 7 | set mouse=a 8 | set scrolloff=5 9 | set undofile 10 | 11 | " No undo for tmp files 12 | autocmd BufWritePre /tmp/*,/var/tmp/*,/dev/shm/* setlocal noundofile nobackup 13 | 14 | " Input. 15 | set shiftwidth=4 16 | set softtabstop=-1 " Follows shiftwidth 17 | set shiftround 18 | set expandtab 19 | set ttimeoutlen=1 20 | set updatetime=500 " coc.nvim relies on relatively fast CursorHold. 21 | 22 | " Render. 23 | set number 24 | set relativenumber 25 | set cursorline 26 | set hlsearch 27 | set signcolumn=yes " Always show. 28 | set list 29 | set listchars=tab:-->,extends:>,precedes:< 30 | 31 | " Highlight on yank. 32 | autocmd TextYankPost * silent! lua vim.highlight.on_yank {higroup="IncSearch", timeout=200} 33 | 34 | " TMUX takes precedence. Also enable OSC 52 clipboard via `-w`. 35 | if !empty($TMUX) 36 | let g:clipboard = { 37 | \ 'name': 'tmux', 38 | \ 'copy': { 39 | \ '+': ['tmux', 'load-buffer', '-w', '-'], 40 | \ '*': ['tmux', 'load-buffer', '-w', '-'], 41 | \ }, 42 | \ 'paste': { 43 | \ '+': ['tmux', 'save-buffer', '-'], 44 | \ '*': ['tmux', 'save-buffer', '-'], 45 | \ }, 46 | \ } 47 | endif 48 | 49 | " Status line. 50 | " Reference: https://github.com/lilydjwg/dotvim/blob/07c4467153f2f44264fdb0e23c085b56cad519db/vimrc#L548 51 | " "+y 72 | 73 | " Move lines. 74 | nmap :move+ 75 | nmap :move-2 76 | vmap :move'>+gv 77 | vmap :move'<-2gv 78 | 79 | " Mouse. 80 | nmap 81 | nmap 82 | imap 83 | imap 84 | 85 | " Options 86 | nmap set relativenumber!\|set relativenumber? 87 | nmap set wrap!\|set wrap? 88 | nmap nohlsearch 89 | 90 | " Commands. {{{1 91 | command! -nargs=0 Sudow w !sudo tee % >/dev/null 92 | command! -nargs=* W w 93 | 94 | " Plugins. {{{1 95 | 96 | " plugin: vim-repeat 97 | 98 | " plugin: plenary-nvim 99 | 100 | " plugin: vim-nix 101 | 102 | " plugin: editorconfig-vim 103 | let g:EditorConfig_exclude_patterns = ['fugitive://.*', 'scp://.*'] 104 | 105 | " plugin: fcitx-vim 106 | let g:fcitx5_remote = '@fcitx5-remote@' 107 | 108 | " plugin: fzf-vim {{{ 109 | let g:fzf_history_dir = stdpath('cache') . '/fzf_history' 110 | 111 | function! s:build_quickfix_list(lines) 112 | call setqflist(map(copy(a:lines), '{ "filename": v:val }')) 113 | copen 114 | cc 115 | endfunction 116 | let g:fzf_action = { 117 | \ 'ctrl-q': function('s:build_quickfix_list'), 118 | \ 'ctrl-t': 'tab split', 119 | \ 'ctrl-s': 'split', 120 | \ 'ctrl-v': 'vsplit', 121 | \ } 122 | 123 | function! FZFRg(pat, args, fullscreen) 124 | let args = "--column --line-number --no-heading --color=always " . a:args 125 | call fzf#vim#grep("rg " . args . " -- " . shellescape(a:pat), 1, fzf#vim#with_preview(), a:fullscreen) 126 | endfunction 127 | command -nargs=1 -bang RgF call FZFRg(, "--fixed-strings", 0) 128 | nmap ff call fzf#vim#files("", fzf#vim#with_preview(), 0) 129 | nmap f. call fzf#vim#files(expand('%:h'), fzf#vim#with_preview(), 0) 130 | nmap fp call fzf#vim#files(expand('%:h:h'), fzf#vim#with_preview(), 0) 131 | nmap fw call FZFRg(expand(''), '--fixed-strings --word-regexp', 0) 132 | nmap fb Buffers 133 | nmap fh Helptags 134 | nmap fr :Rg 135 | "}}} 136 | 137 | " plugin: gitgutter 138 | 139 | " plugin: leap-nvim 140 | lua require('leap').add_default_mappings() 141 | 142 | " plugin: markdown-preview-nvim 143 | 144 | " plugin: vim-commentary {{{ 145 | nmap c CommentaryLine 146 | xmap c Commentary 147 | "}}} 148 | 149 | " plugin: vim-better-whitespace {{{ 150 | let g:show_spaces_that_precede_tabs = 1 151 | "}}} 152 | 153 | " plugin: vim-fugitive {{{ 154 | " plugin: fugitive-gitlab-vim 155 | " plugin: vim-rhubarb 156 | 157 | nmap tab Git 158 | command -nargs=* GL tab Git log --max-count=500 159 | "}}} 160 | 161 | " plugin: vim-sandwich {{{ 162 | " Use vim-surround keymap. 163 | runtime PACK macros/sandwich/keymap/surround.vim 164 | " Use behavior of vim-surround for left parenthesis input. https://github.com/machakann/vim-sandwich/issues/44 165 | let g:sandwich#recipes += [ 166 | \ {'buns': ['{ ', ' }'], 'nesting': 1, 'match_syntax': 1, 'kind': ['add', 'replace'], 'action': ['add'], 'input': ['{']}, 167 | \ {'buns': ['[ ', ' ]'], 'nesting': 1, 'match_syntax': 1, 'kind': ['add', 'replace'], 'action': ['add'], 'input': ['[']}, 168 | \ {'buns': ['( ', ' )'], 'nesting': 1, 'match_syntax': 1, 'kind': ['add', 'replace'], 'action': ['add'], 'input': ['(']}, 169 | \ {'buns': ['{\s*', '\s*}'], 'nesting': 1, 'regex': 1, 'match_syntax': 1, 'kind': ['delete', 'replace', 'textobj'], 'action': ['delete'], 'input': ['{']}, 170 | \ {'buns': ['\[\s*', '\s*\]'], 'nesting': 1, 'regex': 1, 'match_syntax': 1, 'kind': ['delete', 'replace', 'textobj'], 'action': ['delete'], 'input': ['[']}, 171 | \ {'buns': ['(\s*', '\s*)'], 'nesting': 1, 'regex': 1, 'match_syntax': 1, 'kind': ['delete', 'replace', 'textobj'], 'action': ['delete'], 'input': ['(']}, 172 | \ ] 173 | "}}} 174 | 175 | " plugin: crates-nvim {{{ 176 | " Should be setup early, or it cannot trigger autocmd inside autocmd. 177 | lua require('crates').setup() 178 | "}}} 179 | 180 | " plugin: nightfox-nvim {{{ 181 | lua < call CocAction('diagnosticToggle') 212 | 213 | " Completion. 214 | inoremap coc#pum#visible() ? coc#pum#confirm() : "\" 215 | inoremap coc#refresh() 216 | inoremap "\u\\=coc#on_enter()\" 217 | 218 | 219 | " Motion. 220 | nmap gd (coc-definition) 221 | nmap gy (coc-type-definition) 222 | nmap gi (coc-implementation) 223 | nmap gr (coc-references) 224 | 225 | nmap [d (coc-diagnostic-prev) 226 | nmap ]d (coc-diagnostic-next) 227 | 228 | nmap (coc-range-select) 229 | xmap (coc-range-select) 230 | 231 | xmap if (coc-funcobj-i) 232 | omap if (coc-funcobj-i) 233 | xmap af (coc-funcobj-a) 234 | omap af (coc-funcobj-a) 235 | xmap ic (coc-classobj-i) 236 | omap ic (coc-classobj-i) 237 | xmap ac (coc-classobj-a) 238 | omap ac (coc-classobj-a) 239 | 240 | " Scrolling. 241 | nnoremap coc#float#has_scroll() ? coc#float#scroll(1) : "\" 242 | nnoremap coc#float#has_scroll() ? coc#float#scroll(0) : "\" 243 | inoremap coc#float#has_scroll() ? "\=coc#float#scroll(1)\" : "\" 244 | inoremap coc#float#has_scroll() ? "\=coc#float#scroll(0)\" : "\" 245 | vnoremap coc#float#has_scroll() ? coc#float#scroll(1) : "\" 246 | vnoremap coc#float#has_scroll() ? coc#float#scroll(0) : "\" 247 | 248 | " Actions. 249 | nmap r (coc-rename) 250 | nmap a (coc-codeaction-cursor) 251 | xmap a (coc-codeaction-selected) 252 | nmap q (coc-fix-current) 253 | nmap l (coc-codelens-action) 254 | 255 | nmap gl (coc-openlink) 256 | 257 | nmap F (coc-format) 258 | xmap F (coc-format-selected) 259 | 260 | " Hover. 261 | nnoremap call CocActionAsync('doHover') 262 | nnoremap d call CocActionAsync('definitionHover') 263 | 264 | " CoCList. 265 | nnoremap fd CocList diagnostics 266 | nnoremap fc CocList commands 267 | nnoremap fo CocList outline 268 | " Workspace symbols. 269 | nnoremap fs CocList -I symbols 270 | " Resume latest coc list. 271 | nnoremap fp CocListResume 272 | 273 | augroup coc_autocmd 274 | autocmd! 275 | " Highlight the symbol and its references when holding the cursor. 276 | autocmd CursorHold * silent call CocActionAsync('highlight') 277 | " Setup formatexpr specified filetype(s). 278 | autocmd FileType typescript,json setl formatexpr=CocAction('formatSelected') 279 | " Update signature help on jump placeholder. 280 | autocmd User CocJumpPlaceholder call CocActionAsync('showSignatureHelp') 281 | augroup end 282 | 283 | " Additional highlighting. 284 | highlight! link CocSemTypeAsync Conditional 285 | highlight! link CocSemTypeControlFlow Conditional 286 | highlight! link CocSemTypeDocumentation SpecialComment 287 | highlight! link CocSemTypeLifetime Label 288 | highlight! link CocSemTypeEnum Constant 289 | highlight! link CocSemTypeEnumMember Constant 290 | 291 | highlight! link CocSemModBuiltin @variable.builtin 292 | highlight! link CocSemTypeModBuiltinConstant @constant.builtin 293 | highlight! link CocSemTypeModBuiltinFunction @function.builtin 294 | highlight! link CocSemTypeModBuiltinNamespace @namespace.builtin 295 | highlight! link CocSemTypeBuiltinType @type.builtin 296 | highlight! link CocSemTypeConstant Constant 297 | 298 | if !empty(synIDattr(hlID('@field'), 'fg')) 299 | execute "highlight CocSemWithAttribute gui=underline guifg="..synIDattr(hlID('@field'), 'fg') 300 | endif 301 | 302 | " vim:shiftwidth=2:softtabstop=2:expandtab 303 | -------------------------------------------------------------------------------- /home/modules/programs.nix: -------------------------------------------------------------------------------- 1 | { lib, pkgs, super, my, inputs, ... }: 2 | 3 | let 4 | myPython = pkgs.python3.withPackages (ps: with ps; [ 5 | aiohttp 6 | numpy 7 | pylint 8 | pyyaml 9 | requests 10 | toml 11 | z3 12 | ]); 13 | 14 | obs = pkgs.wrapOBS { 15 | plugins = with pkgs.obs-studio-plugins; [ 16 | obs-pipewire-audio-capture 17 | obs-vaapi 18 | ]; 19 | }; 20 | 21 | prismlauncher = my.pkgs.prismlauncher-bwrap.override { 22 | jdks = [ pkgs.jdk21 pkgs.jdk17 ]; 23 | }; 24 | 25 | logseq = (import inputs.nixpkgs-logseq { 26 | inherit (pkgs) system; 27 | config.permittedInsecurePackages = [ "electron-27.3.11" ]; 28 | }).logseq; 29 | 30 | in { 31 | home.packages = with pkgs; [ 32 | # Console 33 | scc bubblewrap difftastic typos # Random stuff 34 | xsel wl-clipboard # CLI-Desktop 35 | beancount # Accounting 36 | tealdeer man-pages # Manual 37 | sops # Sops 38 | 39 | # GUI 40 | libreoffice mpv logseq lyx dwarfs # Files 41 | electron-cash 42 | electrum 43 | monero-gui 44 | # steam is enabled system-wide. 45 | prismlauncher # Games 46 | telegram-desktop nheko # Messaging 47 | obs # Recording 48 | my.pkgs.systemd-run-app 49 | syncplay 50 | 51 | # Dev 52 | cachix patchelf nixpkgs-review nix-update nix-output-monitor nixfmt-rfc-style # Nix utils 53 | gcc ghc myPython koka # Compiler & interpreters 54 | gdb # Debugger 55 | sqlite-interactive # sqlite 56 | super.boot.kernelPackages.perf hyperfine 57 | ]; 58 | 59 | programs.feh.enable = true; 60 | 61 | xdg.configFile = let 62 | gen = path: { 63 | name = "autostart/${builtins.unsafeDiscardStringContext (builtins.baseNameOf path)}"; 64 | value.source = path; 65 | }; 66 | in lib.listToAttrs (map gen [ 67 | "${pkgs.firefox}/share/applications/firefox.desktop" 68 | "${pkgs.telegram-desktop}/share/applications/org.telegram.desktop.desktop" 69 | "${pkgs.nheko}/share/applications/nheko.desktop" 70 | "${pkgs.thunderbird}/share/applications/thunderbird.desktop" 71 | ]); 72 | } 73 | -------------------------------------------------------------------------------- /home/modules/rime-fcitx.nix: -------------------------------------------------------------------------------- 1 | { lib, config, pkgs, ... }: 2 | let 3 | toYAML = builtins.toJSON; 4 | buildDir = "${config.xdg.cacheHome}/fcitx5-rime"; 5 | onChange = '' 6 | rimeSettingChanged=1 7 | ''; 8 | in { 9 | home.activation.setupRimeCacheDirectory = lib.hm.dag.entryAfter [ "writeBoundary" "onFilesChange" ] '' 10 | run mkdir -p "${buildDir}" 11 | if [[ -v rimeSettingChanged ]]; then 12 | run rm -rf "${buildDir}"/* 13 | fi 14 | if [[ -z "$(ls ${buildDir})" ]]; then 15 | run ${pkgs.qt5.qttools.bin}/bin/qdbus org.fcitx.Fcitx5 /controller org.fcitx.Fcitx.Controller1.SetConfig "fcitx://config/addon/rime/deploy" "" 16 | fi 17 | ''; 18 | 19 | xdg.dataFile = { 20 | "fcitx5/rime/build".source = config.lib.file.mkOutOfStoreSymlink buildDir; 21 | 22 | "fcitx5/rime/default.custom.yaml" = { 23 | inherit onChange; 24 | text = toYAML { 25 | patch = { 26 | "menu/page_size" = 9; 27 | schema_list = [ 28 | { schema = "double_pinyin"; } 29 | { schema = "latex"; } 30 | ]; 31 | }; 32 | }; 33 | }; 34 | 35 | "fcitx5/rime/double_pinyin.custom.yaml" = { 36 | inherit onChange; 37 | text = toYAML { 38 | __include = "emoji_suggestion:/"; 39 | "switches/@2/reset" = 1; 40 | }; 41 | }; 42 | }; 43 | } 44 | -------------------------------------------------------------------------------- /home/modules/rust.nix: -------------------------------------------------------------------------------- 1 | { 2 | config, 3 | lib, 4 | pkgs, 5 | inputs, 6 | my, 7 | ... 8 | }: 9 | 10 | let 11 | inherit (inputs.self.lib) toTOML; 12 | 13 | cargo-machete = my.pkgs.cargo-machete-no-spam; 14 | 15 | cargoConfig = { 16 | # Ref: https://doc.rust-lang.org/cargo/reference/registry-authentication.html#recommended-configuration 17 | registry.global-credential-providers = [ 18 | "cargo:token" 19 | "cargo:libsecret" 20 | ]; 21 | 22 | install.root = "${config.home.homeDirectory}/.local"; 23 | 24 | build.target-dir = "${config.xdg.cacheHome}/cargo/target"; 25 | 26 | # Prefer MSRV-compatible dependency versions. 27 | resolver.incompatible-rust-versions = "fallback"; 28 | 29 | target = { 30 | "${pkgs.hostPlatform.rust.rustcTarget}".linker = gcc-lld; 31 | "riscv64gc-unknown-linux-gnu".linker = "riscv64-unknown-linux-gnu-gcc"; 32 | "aarch64-unknown-linux-gnu".linker = "aarch64-unknown-linux-gnu-gcc"; 33 | }; 34 | }; 35 | 36 | # Seems it reject missing fields. 37 | # https://github.com/rustsec/rustsec/blob/5058319167c0a86eae7bf25ebc820a8eefeb1c55/cargo-audit/audit.toml.example 38 | cargoAudit = { 39 | database = { 40 | path = "${config.xdg.cacheHome}/cargo/advisory-db"; 41 | url = "https://github.com/RustSec/advisory-db.git"; 42 | fetch = true; 43 | stale = false; 44 | }; 45 | }; 46 | 47 | # `--no-rosegment` is required for flamegraph 48 | # https://github.com/flamegraph-rs/flamegraph#cargo-flamegraph 49 | gcc-lld = pkgs.writeShellScript "gcc-lld" '' 50 | export PATH="${pkgs.llvmPackages_latest.bintools}/bin''${PATH:+:}$PATH" 51 | exec ${lib.getExe pkgs.gcc} -fuse-ld=lld -Wl,--no-rosegment "$@" 52 | ''; 53 | 54 | rust-overlay-pkgs = inputs.rust-overlay.packages.${pkgs.system}; 55 | curDate = inputs.rust-overlay.lastModifiedDate; 56 | # Use nightly rustfmt from yyyy-mm-01. 57 | rustfmt = 58 | rust-overlay-pkgs."rust-nightly_${lib.substring 0 4 curDate}-${lib.substring 4 2 curDate}-01".availableComponents.rustfmt; 59 | 60 | rustToolchain = ( 61 | rust-overlay-pkgs.rust.override { 62 | extensions = [ 63 | "rust-src" 64 | "llvm-tools" # For cargo-llvm-cov 65 | ]; 66 | targets = [ 67 | "aarch64-unknown-linux-gnu" 68 | "riscv64gc-unknown-linux-gnu" 69 | "wasm32-unknown-unknown" 70 | "x86_64-pc-windows-msvc" 71 | ]; 72 | } 73 | ); 74 | 75 | in 76 | { 77 | home.packages = with pkgs; [ 78 | (lib.hiPrio rustfmt) 79 | rustToolchain 80 | 81 | cargo-audit 82 | inputs.cargo-bloated.packages.${pkgs.system}.default 83 | cargo-deny 84 | cargo-expand 85 | cargo-flamegraph 86 | cargo-hack 87 | cargo-insta 88 | cargo-license 89 | cargo-llvm-cov 90 | cargo-machete 91 | cargo-outdated 92 | cargo-show-asm 93 | ]; 94 | 95 | # Setup cargo directories. 96 | # https://doc.rust-lang.org/cargo/commands/cargo.html?highlight=cargo_home#files 97 | home.sessionVariables."CARGO_HOME" = "${pkgs.runCommandLocal "cargo-home" 98 | { 99 | cargoConfig = toTOML cargoConfig; 100 | cargoAudit = toTOML cargoAudit; 101 | } 102 | '' 103 | mkdir -p $out 104 | ln -st $out "${config.xdg.cacheHome}"/cargo/{registry,git,.global-cache,.package-cache,.package-cache-mutate,advisory-dbs} 105 | ln -st $out "${config.xdg.configHome}"/cargo/credentials.toml 106 | echo -n "$cargoConfig" >$out/config.toml 107 | echo -n "$cargoAudit" >$out/audit.toml 108 | '' 109 | }"; 110 | 111 | home.activation.setupCargoDirectories = lib.hm.dag.entryAfter [ "writeBoundary" ] '' 112 | run mkdir -p "${config.xdg.configHome}"/cargo "${config.xdg.cacheHome}"/cargo/{registry,git,advisory-dbs} 113 | if [[ ! -e "${config.xdg.configHome}"/cargo/credentials.toml ]]; then 114 | run touch -a "${config.xdg.configHome}"/cargo/credentials.toml 115 | fi 116 | for f in .global-cache .package-cache .package-cache-mutate; do 117 | if [[ ! -e "${config.xdg.cacheHome}"/cargo/"$f" ]]; then 118 | run touch -a "${config.xdg.cacheHome}"/cargo/"$f" 119 | fi 120 | done 121 | ''; 122 | } 123 | -------------------------------------------------------------------------------- /home/modules/shell/cmds.zsh: -------------------------------------------------------------------------------- 1 | local DEFAULT_LS_ARGS=( 2 | --escape 3 | --color=auto 4 | --classify 5 | --time-style=iso 6 | --human-readable 7 | --kibibytes 8 | ) 9 | alias l="command ls $DEFAULT_LS_ARGS" 10 | alias la="command ls $DEFAULT_LS_ARGS --almost-all" 11 | alias ll="command ls $DEFAULT_LS_ARGS -l" 12 | alias lla="command ls $DEFAULT_LS_ARGS -l --almost-all" 13 | 14 | alias n="nix" 15 | alias nb="nix build" 16 | alias nf="nix flake" 17 | alias nr="nix repl" 18 | alias nrp="nix repl -f ''" 19 | 20 | alias v="nvim" 21 | alias g="git" 22 | alias py="python" 23 | alias rl="readlink" 24 | alias rp="realpath" 25 | alias t="bsdtar" 26 | alias hex="hexdump -C" 27 | alias o="xdg-open" 28 | alias reset="tput reset" 29 | alias mv="mv --no-copy" 30 | 31 | # List tree. 32 | lt() { 33 | # `-C` for `color=always`. 34 | tree -C $@ | eval $PAGER 35 | } 36 | 37 | # Clipboard input/output. 38 | +() { 39 | local board 40 | if [[ "$XDG_SESSION_TYPE" == wayland ]]; then 41 | case $1 in 42 | p) board=--primary;; 43 | b|"") ;; 44 | *) echo "Invalid argument" >&2; return 1;; 45 | esac 46 | if [[ -t 0 ]]; then # stdin is tty, print clipboard 47 | wl-paste $board 48 | elif [[ -t 1 ]]; then # stdout is tty, put into clipboard 49 | wl-copy $board 50 | else 51 | echo "Cannot use '+' as pipe" >&2 52 | return 1 53 | fi 54 | else 55 | case $1 in 56 | p) board=--primary;; 57 | s) board=--secondary;; 58 | b|"") board=--clipboard;; 59 | *) echo "Invalid argument" >&2; return 1;; 60 | esac 61 | if [[ -t 0 ]]; then # stdin is tty, print clipboard 62 | xsel --output $board 63 | elif [[ -t 1 ]]; then # stdout is tty, put into clipboard 64 | xsel --input $board 65 | else 66 | echo "Cannot use '+' as pipe" >&2 67 | return 1 68 | fi 69 | fi 70 | } 71 | 72 | # Realpath of which. 73 | rwhich() { 74 | command which $@ | xargs realpath 75 | } 76 | 77 | # Binary diff. 78 | bdiff() { 79 | diff <(hexdump -C $1) <(hexdump -C $2) ${@:3} 80 | } 81 | 82 | # Length of stream, in human size. 83 | len() { 84 | wc -c | numfmt --to=iec-i 85 | } 86 | 87 | # mkdir && cd 88 | mkcd() { 89 | mkdir -p $1 && cd $1 90 | } 91 | 92 | # Run with limited memory. 93 | limitmem() { 94 | (( $# < 3 )) && { echo "USAGE: limitmem " >&2; return 1; } 95 | local cmd=(systemd-run --scope --user -p MemorySwapMax=0 -p MemoryHigh=$1 -p MemoryMax=$2 $argv[3,-1]) 96 | echo -E "+ ${(q)cmd[@]}" 97 | ${cmd[@]} 98 | } 99 | 100 | # Patch interpreter to the dynamic linker. 101 | patchinterp() { 102 | local interp glibc 103 | interp="$(patchelf --print-interpreter $1)" || return 1 104 | [[ $interp != /nix/store/* ]] || { echo "Already patched: $interp"; return 1; } 105 | linker="$(nix eval --raw nixpkgs#bintools.dynamicLinker)" && patchelf --set-interpreter $linker $1 106 | } 107 | 108 | closure() { 109 | nix path-info -Shr $@ | eval $PAGER 110 | } 111 | -------------------------------------------------------------------------------- /home/modules/shell/completion.zsh: -------------------------------------------------------------------------------- 1 | # Modified from: https://github.com/ohmyzsh/ohmyzsh/blob/706b2f3765d41bee2853b17724888d1a3f6f00d9/lib/completion.zsh 2 | 3 | ZSH_CACHE_DIR="${XDG_CACHE_HOME:-$HOME/.cache}/zsh" 4 | ZSH_COMPDUMP="$ZSH_CACHE_DIR/zcompdump" 5 | mkdir -p $ZSH_CACHE_DIR 6 | 7 | # fixme - the load process here seems a bit bizarre 8 | zmodload -i zsh/complist 9 | 10 | WORDCHARS='*?_-.[]~=&;!#$%^(){}<>' # remove '/' 11 | 12 | unsetopt menu_complete # do not autoselect the first completion entry 13 | unsetopt flowcontrol 14 | setopt auto_menu # show completion menu on successive tab press 15 | setopt complete_in_word 16 | setopt always_to_end 17 | 18 | # should this be in keybindings? 19 | bindkey -M menuselect '^o' accept-and-infer-next-history 20 | zstyle ':completion:*:*:*:*:*' menu select 21 | 22 | # Don't try to expand multiple partial paths. 23 | zstyle ':completion:*' path-completion false 24 | 25 | # 1. Prefix completion. 26 | # 2. Substring completion. 27 | zstyle ':completion:*' matcher-list 'r:|=*' 'l:|=* r:|=*' 28 | 29 | zstyle ':completion:*' list-colors "${(s.:.)LS_COLORS}" 30 | 31 | # Use caching so that commands like apt and dpkg complete are useable 32 | zstyle ':completion:*' use-cache yes 33 | zstyle ':completion:*' cache-path $ZSH_CACHE_DIR 34 | 35 | # Completing indicator. 36 | expand-or-complete-with-dots() { 37 | print -Pn "%F{blue}...%f" 38 | zle expand-or-complete 39 | zle redisplay 40 | } 41 | zle -N expand-or-complete-with-dots 42 | bindkey '^I' expand-or-complete-with-dots 43 | 44 | # Load bash completion functions. 45 | autoload -U +X bashcompinit && bashcompinit 46 | 47 | # Dump the current completion states. 48 | () { 49 | local fpath_real=${fpath:P} 50 | local fpath_line="# fpath: ${fpath_real[*]}" 51 | local need_init=0 52 | 53 | if [[ "$(tail -n1 $ZSH_COMPDUMP 2>/dev/null)" != "$fpath_line" ]]; then 54 | need_init=1 55 | rm -f $ZSH_COMPDUMP 56 | fi 57 | 58 | autoload -U compinit 59 | compinit -u -C -d $ZSH_COMPDUMP 60 | 61 | if (( $need_init )); then 62 | printf '\n%s' $fpath_line >>$ZSH_COMPDUMP 63 | fi 64 | } 65 | -------------------------------------------------------------------------------- /home/modules/shell/default.nix: -------------------------------------------------------------------------------- 1 | { lib, pkgs, config, my, ... }: 2 | { 3 | home.sessionVariables = { 4 | # Rust and python outputs. 5 | PATH = "$HOME/.local/bin\${PATH:+:}$PATH"; 6 | 7 | FZF_DEFAULT_COMMAND = "${lib.getBin pkgs.fd}/bin/fd --type=f --hidden --exclude=.git"; 8 | FZF_DEFAULT_OPTS = lib.concatStringsSep " " [ 9 | "--layout=reverse" # Top-first. 10 | "--color=16" # 16-color theme. 11 | "--info=inline" 12 | "--exact" # Substring matching by default, `'`-quote for subsequence matching. 13 | "--bind=alt-p:toggle-preview,alt-a:select-all" 14 | ]; 15 | 16 | BAT_THEME = "ansi"; 17 | }; 18 | 19 | # The default `command-not-found` relies on nix-channel. Use `nix-index` instead. 20 | programs.command-not-found.enable = false; 21 | programs.nix-index = { 22 | enable = true; 23 | # Don't install the hook. 24 | enableBashIntegration = false; 25 | enableZshIntegration = false; 26 | }; 27 | 28 | programs.zsh = { 29 | enable = true; 30 | dotDir = ".config/zsh"; 31 | 32 | dirHashes = { 33 | target = "${config.xdg.cacheHome}/cargo/target"; 34 | nixpkgs = "${config.home.homeDirectory}/repo/fork/nixpkgs"; 35 | }; 36 | 37 | # Disable /etc/{zshrc,zprofile} that contains the "sane-default" setup. 38 | # See `/etc/zshrc` for more info. 39 | envExtra = '' 40 | setopt no_global_rcs 41 | ''; 42 | 43 | autosuggestion.enable = true; 44 | enableCompletion = false; # We do it ourselves. 45 | enableVteIntegration = true; 46 | 47 | history = { 48 | ignoreDups = true; 49 | ignoreSpace = true; 50 | expireDuplicatesFirst = true; 51 | extended = true; 52 | share = false; 53 | path = "${config.xdg.stateHome}/zsh/history"; 54 | save = 1000000; 55 | size = 1000000; 56 | ignorePatterns = [ 57 | "rm *" "\\rm *" 58 | "sudo *rm*" 59 | "g* stash (clear|drop)*" 60 | ":" 61 | ]; 62 | }; 63 | 64 | # Ref: https://blog.quarticcat.com/zh/posts/how-do-i-make-my-zsh-smooth-as-fuck/ 65 | # 550 = Before compinit. 66 | initContent = lib.mkOrder 550 '' 67 | setopt auto_pushd 68 | setopt interactive_comments 69 | setopt multios 70 | setopt noextended_glob # Breaks flake path reference nixpkgs#foo. 71 | 72 | setopt hist_verify 73 | setopt inc_append_history_time 74 | 75 | LS_COLORS="$(dircolors --sh)" 76 | LS_COLORS="''${''${LS_COLORS#*\'}%\'*}" 77 | export LS_COLORS 78 | TIMEFMT=$'%J %uU user %uS system %uE/%*E elapsed %PCPU (%Xavgtext+%Davgdata %Mmaxresident)k\n%Iinputs+%Ooutputs (%Fmajor+%Rminor)pagefaults %Wswaps' 79 | 80 | source ${pkgs.git}/share/git/contrib/completion/git-prompt.sh 81 | source ${./prompt.zsh} 82 | source ${./cmds.zsh} 83 | source ${./key-bindings.zsh} 84 | source ${./completion.zsh} 85 | 86 | ZSH_AUTOSUGGEST_MANUAL_REBIND=1 87 | ZSH_AUTOSUGGEST_HISTORY_IGNORE=$'*\n*' 88 | source ${pkgs.zsh-autosuggestions}/share/zsh-autosuggestions/zsh-autosuggestions.zsh 89 | source ${pkgs.zsh-fast-syntax-highlighting}/share/zsh/site-functions/fast-syntax-highlighting.plugin.zsh 90 | source ${my.pkgs.zsh-comma}/share/zsh/comma/comma.zsh 91 | FAST_HIGHLIGHT[use_async]=1 # Improve paste delay for nix store paths. 92 | source <(${lib.getExe pkgs.fzf} --zsh) 93 | ''; 94 | }; 95 | 96 | programs.zoxide.enable = true; 97 | 98 | home.packages = with pkgs; [ 99 | nix-zsh-completions # Prefer nix's builtin completion. 100 | my.pkgs.colors 101 | my.pkgs.zsh-comma 102 | ]; 103 | } 104 | -------------------------------------------------------------------------------- /home/modules/shell/key-bindings.zsh: -------------------------------------------------------------------------------- 1 | # References: 2 | # - https://github.com/ohmyzsh/ohmyzsh/blob/706b2f3765d41bee2853b17724888d1a3f6f00d9/lib/key-bindings.zsh 3 | # - https://github.com/dramforever/config/blob/446e232cba4f3e05d83fb126516b1d9181fb7e67/home/zshrc 4 | # - `/etc/zinputrc` from NixOS. 5 | # - http://zsh.sourceforge.net/Doc/Release/Zsh-Line-Editor.html#Zle-Builtins 6 | # - http://zsh.sourceforge.net/Doc/Release/Zsh-Line-Editor.html#Standard-Widgets 7 | 8 | zmodload zsh/zle 9 | zmodload zsh/terminfo 10 | 11 | # Escape sequence timeout in 1/100s. 12 | KEYTIMEOUT=1 13 | 14 | # Make sure the terminal is in application mode, when zle is 15 | # active. Only then are the values from $terminfo valid. 16 | # From `/etc/zinputrc`. 17 | if (( ${+terminfo[smkx]} && ${+terminfo[rmkx]} )); then 18 | zle-line-init() echoti smkx 19 | zle-line-finish() echoti rmkx 20 | zle -N zle-line-init 21 | zle -N zle-line-finish 22 | fi 23 | 24 | # Mode indicator. 25 | zle-keymap-select() { 26 | RPS1=${KEYMAP/(main|viins)/} 27 | zle redisplay 28 | } 29 | zle -N zle-keymap-select 30 | 31 | # Use viins key bindings 32 | bindkey -v 33 | 34 | bind() { 35 | [[ -z $1 ]] || bindkey $1 $2 36 | } 37 | 38 | # [Delete] - Delete forward 39 | bind "${terminfo[kdch1]}" delete-char 40 | # [Home] 41 | bind "${terminfo[khome]}" beginning-of-line 42 | # [End] 43 | bind "${terminfo[kend]}" end-of-line 44 | # [PageUp] 45 | bind "${terminfo[kpp]}" beginning-of-buffer-or-history 46 | # [PageDown] 47 | bind "${terminfo[knp]}" end-of-buffer-or-history 48 | # [Ctrl-RightArrow] 49 | bind '^[[1;5C' forward-word 50 | # [Ctrl-LeftArrow] 51 | bind '^[[1;5D' backward-word 52 | 53 | 54 | # [Left] 55 | bind "${terminfo[kcub1]}" backward-char 56 | # [Right] 57 | bind "${terminfo[kcuf1]}" forward-char 58 | # [Up] 59 | bind "${terminfo[kcuu1]}" up-line-or-history 60 | # [Down] 61 | bind "${terminfo[kcud1]}" down-line-or-history 62 | 63 | # [Shift-Tab] 64 | bind "${terminfo[kcbt]}" reverse-menu-complete 65 | 66 | autoload -U up-line-or-beginning-search 67 | autoload -U down-line-or-beginning-search 68 | zle -N up-line-or-beginning-search 69 | zle -N down-line-or-beginning-search 70 | # [Ctrl-p] 71 | bind '^p' up-line-or-beginning-search 72 | # [Ctrl-n] 73 | bind '^n' down-line-or-beginning-search 74 | 75 | # [Space] 76 | bind ' ' magic-space 77 | 78 | unfunction bind 79 | 80 | preexec_load_history() { 81 | if [[ $1 == : ]]; then 82 | fc -RI 83 | fi 84 | } 85 | autoload -Uz add-zsh-hook 86 | add-zsh-hook -Uz preexec preexec_load_history 87 | -------------------------------------------------------------------------------- /home/modules/shell/prompt.zsh: -------------------------------------------------------------------------------- 1 | # AVIT ZSH Theme Simplified 2 | 3 | setopt promptsubst 4 | 5 | typeset +H _current_dir='%B%F{blue}%3~%f%b' 6 | typeset +H _return_status=' %(?..%B%F{red}[%?]%f%b)' 7 | typeset +H _shell_level='%(2L. <%L>.)' 8 | 9 | PROMPT=' 10 | $(_user_host)${_current_dir}$(_git_info)${_shell_level}${_return_status} 11 | %(!.%F{red}.)>%f ' 12 | 13 | PROMPT2='%(!.%F{red}.)|%f ' 14 | 15 | # Use an inverted space as NOEOL marker so it's easier to copy. 16 | PROMPT_EOL_MARK="%B%S %s%b" 17 | 18 | _user_host() { 19 | local me 20 | if [[ -n $SSH_CONNECTION ]]; then 21 | me="%n@%m" 22 | elif [[ $LOGNAME != $USER ]]; then 23 | me="%n" 24 | fi 25 | if [[ -n $me ]]; then 26 | echo -nE "%F{cyan}$me%f " 27 | fi 28 | } 29 | 30 | _git_info() { 31 | echo -nE "%F{green}$(__git_ps1)%f" 32 | } 33 | -------------------------------------------------------------------------------- /home/modules/tmux.nix: -------------------------------------------------------------------------------- 1 | { ... }: 2 | { 3 | programs.tmux = { 4 | enable = true; 5 | baseIndex = 1; 6 | clock24 = true; 7 | escapeTime = 1; 8 | historyLimit = 100000; 9 | keyMode = "vi"; 10 | prefix = "C-a"; 11 | terminal = "tmux-256color"; # Fix weird behaviors for dim colors. 12 | 13 | # tmux 14 | extraConfig = '' 15 | set -g mouse on 16 | set -g set-clipboard on 17 | set -g word-separators " ,\"'[](){}<>=:@" 18 | 19 | set -sa terminal-overrides "alacritty:Tc" 20 | # Hyperlinks. 21 | set -sa terminal-overrides '*:Hls=\E]8;id=%p1%s;%p2%s\E\\:Hlr=\E]8;;\E\\' 22 | # SGR 53 (Overline). 23 | set -sa terminal-overrides '*:Smol=\E[53m' 24 | # Styled underlines. 25 | set -sa terminal-overrides '*:Smulx=\E[4::%p1%dm' 26 | # Underline colors. 27 | set -sa terminal-overrides '*:Setulc=\E[58::2::%p1%{65536}%/%d::%p1%{256}%/%{255}%&%d::%p1%{255}%&%d%;m' 28 | 29 | # Colors 30 | set -g status-style fg=green 31 | set -g window-status-current-style reverse 32 | 33 | # Custom window title. 34 | set -g automatic-rename on 35 | set -g automatic-rename-format '#{b:pane_current_path}#{?#{!=:#{pane_current_command},zsh},:#{pane_current_command},}' 36 | set -g status-interval 1 37 | 38 | # Split panes. 39 | bind v split-window -h -c "#{pane_current_path}" 40 | bind s split-window -v -c "#{pane_current_path}" 41 | 42 | # Resize panes. 43 | bind -r H resize-pane -L 5 44 | bind -r J resize-pane -D 5 45 | bind -r K resize-pane -U 5 46 | bind -r L resize-pane -R 5 47 | 48 | # Move between panes. 49 | bind -r C-h select-pane -L 50 | bind -r C-j select-pane -D 51 | bind -r C-k select-pane -U 52 | bind -r C-l select-pane -R 53 | 54 | # Copy mode behaviors. 55 | # Ref: https://github.com/tmux/tmux/issues/140#issuecomment-474341833 56 | # Don't exit after selection. 57 | bind-key -T copy-mode-vi MouseDragEnd1Pane send-keys -X copy-selection-no-clear 58 | bind-key -T copy-mode-vi DoubleClick1Pane send-keys -X select-word \; send-keys -X copy-selection-no-clear 59 | bind-key -T copy-mode-vi TripleClick1Pane send-keys -X select-line \; send-keys -X copy-selection-no-clear 60 | # Clear selection on single-click. 61 | bind-key -T copy-mode-vi MouseDown1Pane select-pane \; send-keys -X clear-selection 62 | # Quick enter and leave. 63 | bind-key -n DoubleClick3Pane copy-mode -M \; send-keys -X select-word \; send-keys -X copy-selection-no-clear 64 | bind-key -n TripleClick3Pane copy-mode -M \; send-keys -X select-line \; send-keys -X copy-selection-no-clear 65 | bind-key -T copy-mode-vi MouseDown3Pane send-keys -X cancel 66 | ''; 67 | }; 68 | } 69 | -------------------------------------------------------------------------------- /home/modules/user-dirs.nix: -------------------------------------------------------------------------------- 1 | { ... }: 2 | { 3 | xdg.userDirs = { 4 | enable = true; 5 | desktop = "$HOME/Desktop"; 6 | download = "$HOME/Downloads"; 7 | pictures = "$HOME/Pictures"; 8 | documents = "$HOME"; 9 | music = "$HOME"; 10 | publicShare = "$HOME"; 11 | templates = "$HOME"; 12 | videos = "$HOME/Video"; 13 | }; 14 | } 15 | -------------------------------------------------------------------------------- /home/modules/vscode/default.nix: -------------------------------------------------------------------------------- 1 | { pkgs, ... }: 2 | { 3 | programs.vscode = { 4 | enable = true; 5 | package = pkgs.vscodium; 6 | }; 7 | } 8 | -------------------------------------------------------------------------------- /home/modules/xdgify.nix: -------------------------------------------------------------------------------- 1 | # Reference: https://gitlab.com/NickCao/flakes/-/blob/master/nixos/local/home.nix#L71 2 | { config, ... }: 3 | { 4 | home.sessionVariables = { 5 | HISTFILE = "${config.xdg.stateHome}/bash/history"; 6 | LESSHISTFILE = "${config.xdg.stateHome}/less/history"; 7 | SQLITE_HISTORY = "${config.xdg.stateHome}/sqlite/history"; 8 | }; 9 | 10 | # XDG Spec doesn't have BIN_HOME yet. 11 | home.xdg.configFile."go/env".text = '' 12 | GOPATH=${config.xdg.cacheHome}/go 13 | GOBIN=${config.homeDirectory}/.local/bin 14 | ''; 15 | } 16 | -------------------------------------------------------------------------------- /lib.nix: -------------------------------------------------------------------------------- 1 | { lib }: 2 | { 3 | toTOML = let 4 | inherit (builtins) toJSON concatStringsSep isAttrs isList isFloat; 5 | inherit (lib) isStringLike concatMapStringsSep mapAttrsToList; 6 | 7 | # We use `toJSON` for serialization of string, numbers and booleans. 8 | # The only incompatibility is that JSON allows `"\/"` while TOML does not. 9 | # But `builtins.toJSON` does not escape `/` anyway, so it's fine. 10 | 11 | inf = 1.0e308 * 10; 12 | 13 | toTopLevel = obj: 14 | concatStringsSep "" 15 | (mapAttrsToList 16 | (name: value: "${toJSON name}=${toInline value}\n") 17 | obj); 18 | 19 | toInline = obj: 20 | # Exclude drvs here, or we'll easily get infinite recursion. 21 | if isAttrs obj && !isStringLike obj then 22 | "{${concatStringsSep "," 23 | (mapAttrsToList 24 | (name: value: "${toJSON name}=${toInline value}") 25 | obj) 26 | }}" 27 | else if isList obj then 28 | "[${concatMapStringsSep "," toInline obj}]" 29 | else if obj == null then 30 | throw "“null” is not supported by TOML" 31 | else if !isFloat obj then 32 | # Strings, integers and booleans. 33 | toJSON obj 34 | # Sanitize +-inf and NaN. They'll produce "null", which is invalid for TOML. 35 | else if obj == inf then 36 | "inf" 37 | else if obj == -inf then 38 | "-inf" 39 | else if obj != obj then 40 | "nan" 41 | else 42 | toJSON obj; 43 | 44 | in 45 | toTopLevel; 46 | } 47 | -------------------------------------------------------------------------------- /my/default.nix: -------------------------------------------------------------------------------- 1 | { 2 | gpg = { 3 | fingerprint = "F90FFD6D585C2BA1F13DE8A97571654CF88E31C2"; 4 | publicKeyFile = ./gpg-pubkey.asc; 5 | }; 6 | 7 | ssh = rec { 8 | identities = { 9 | oxa = "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIHn7rLiEt5UHKNsX/uNam7679guLh4chbYdE2eoC00+p openpgp:0x4E59DAB9"; 10 | 11 | oxa-invar = "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIJYl9bIMoMrs8gWUmIAF42mGnKVxqY6c+g2gmE6u2E/B oxa@invar"; 12 | oxa-blacksteel = "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAICU0P/fbBnnPCVni+efxfl//NQ1jeOe4lUDH6okvLzr1 oxa@blacksteel"; 13 | shu-iwkr = "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIOtqhzrEH5VnSSxcLn7MJKbCw7QFhQmX8hkSmsEMq8/I shu@iwkr"; 14 | } // builtins.mapAttrs (name: value: value.publicKey) knownHosts; 15 | 16 | knownHosts = { 17 | invar.publicKey = "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIPp0GGkE81OeO1JUQ+T/DfsjzQSNRz1lzpNTU+UgpAv1"; 18 | blacksteel.publicKey = "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAICVBNvOEn0ncdylnKQIFKd75muElg5TBaMFWrbamAlx+"; 19 | iwkr.publicKey = "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIEmt0cK3uNWAtpK2k3BA+liaIKWFPa8mDtRh15GAjF3J"; 20 | 21 | copper = { 22 | extraHostNames = [ "|1|dBmAkr6d+gTzhvfiA8p7l+H34co=|3U8aEJXTtWbmM/j/c+qAGKb44d8=" ]; 23 | publicKey = "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIO1TnA8NpurpJFgf4xZZvJrgFpkaE9y6qRgFiFe1mX21"; 24 | }; 25 | lithium = { 26 | extraHostNames = [ "|1|yrXSPIhZYqHg3ii/siCoKs2PRU4=|uaJAOcFrhozPJsul0YF/+1CaAKw=" ]; 27 | publicKey = "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIMPG3JTJrW5kDTFXOftags+aWWjn2D1E5iIbU57ni9rH"; 28 | }; 29 | 30 | aluminum = { 31 | extraHostNames = [ "aluminum.lan.hexade.ca" ]; 32 | publicKey = "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIOqzykYcCVpDJqkayG8tzoh3AurOsilAsBTX7heF0h3u"; 33 | }; 34 | }; 35 | }; 36 | } 37 | -------------------------------------------------------------------------------- /my/gpg-pubkey.asc: -------------------------------------------------------------------------------- 1 | -----BEGIN PGP PUBLIC KEY BLOCK----- 2 | 3 | mDMEYdjEDRYJKwYBBAHaRw8BAQdA32pR8t7apbBFQrNpfh9jtsHPEIt1q4YpB42U 4 | b7mf0WW0F094YWxpY2EgPG94YWxpY2NAcG0ubWU+iJMEExYKADsWIQT5D/1tWFwr 5 | ofE96Kl1cWVM+I4xwgUCYdjEDQIbAwUJBaOagAQLCQgHBBUKCQgEFgIDAAIeAQIX 6 | gAAKCRB1cWVM+I4xwqqxAQDeaf8OvivYlLs0R17HrBqOUjr9BQOwuuzx+vLvdMEu 7 | kAEAyoB3yVDOlPw+TgQPaH3rCB4WPqF61fmk7VWnxbgvkg+4MwRh2YynFgkrBgEE 8 | AdpHDwEBB0DD1mzvFdANRKZ9FfCHxxMTwPH3luHSN12sxGGKA4izu4jvBBgWCAAg 9 | FiEE+Q/9bVhcK6HxPeipdXFlTPiOMcIFAmHZjKcCGwIAgQkQdXFlTPiOMcJ2IAQZ 10 | FggAHRYhBLvM58SqAv6vso1WUtQlyyPK3oLZBQJh2YynAAoJENQlyyPK3oLZQboA 11 | +gN6i5K8ei/tryPad1Zq7mNqdeK0H8slzryL3KRDdXuPAP9tBMo4C62rrVI1xm58 12 | jsr5Dwpl6JICUUHCsCeMF1+qB7siAP4hqe40v3RPMsXV9mvf3+T9+WrDXsTDjHCK 13 | 7UtQzggZqAEAwxxlFTY0b+65QpkI3hYVqvCq23/vPHAiQeulpi0E2Qe4OARh2Yy4 14 | EgorBgEEAZdVAQUBAQdA5mq6F/tOP0S2y4Lz9zX3lSNgnSQMwPrwNs/3lyozkzcD 15 | AQgHiHgEGBYIACAWIQT5D/1tWFwrofE96Kl1cWVM+I4xwgUCYdmMuAIbDAAKCRB1 16 | cWVM+I4xwsGsAQD0bVjp2nxwvA5sApuSJC1CKFXuNPfXZoLtmcbCWaCOvwEAzxfv 17 | OYEbfgpXOWjXdps6G32oM+ZJImwNwcgwxfwpRAu4MwRh2YzLFgkrBgEEAdpHDwEB 18 | B0B5+6y4hLeVByjbF/7jWpu+u/YLi4eHIW2HRNnqAtNPqYh4BBgWCAAgFiEE+Q/9 19 | bVhcK6HxPeipdXFlTPiOMcIFAmHZjMsCGyAACgkQdXFlTPiOMcL1NAEA7aayPPJ2 20 | 7YLdl2428pemnqcFlPMX1CqlB+LmEFAsgxQBALnjHJZqOwxF4IGEGy38Z8rr8YYW 21 | 5O7JW7TaoBs0rpwC 22 | =QQHt 23 | -----END PGP PUBLIC KEY BLOCK----- 24 | -------------------------------------------------------------------------------- /nixos/blacksteel/configuration.nix: -------------------------------------------------------------------------------- 1 | { lib, config, pkgs, inputs, my, ... }: 2 | 3 | { 4 | imports = [ 5 | ./vm.nix 6 | 7 | ../modules/console-env.nix 8 | ../modules/device-fix.nix 9 | ../modules/kde-desktop 10 | ../modules/nix-cgroups.nix 11 | ../modules/nix-common.nix 12 | ../modules/nix-keep-flake-inputs.nix 13 | ../modules/nix-registry.nix 14 | ../modules/secure-boot.nix 15 | ../modules/zswap-enable.nix 16 | ] ++ lib.optional (inputs ? secrets) (inputs.secrets.nixosModules.blacksteel); 17 | 18 | nixpkgs.config.allowUnfreePredicate = drv: 19 | lib.elem (lib.getName drv) [ 20 | "steam" 21 | "steam-unwrapped" 22 | ]; 23 | 24 | nixpkgs.config.permittedInsecurePackages = [ 25 | # FIXME: `nheko` depends on olm: https://github.com/Nheko-Reborn/nheko/issues/1786 26 | "olm-3.2.16" 27 | ]; 28 | 29 | # Boot. 30 | 31 | boot = { 32 | initrd = { 33 | systemd.enable = true; 34 | availableKernelModules = [ "xhci_pci" "nvme" "rtsx_pci_sdmmc" ]; 35 | kernelModules = [ ]; 36 | luks.devices."luksroot" = { 37 | device = "/dev/disk/by-uuid/8e445c05-75cc-45c7-bebd-46a73cf50a74"; 38 | allowDiscards = true; 39 | crypttabExtraOpts = [ "fido2-device=auto" ]; 40 | }; 41 | }; 42 | 43 | kernelPackages = pkgs.linuxPackages_latest; 44 | kernelModules = [ "kvm-intel" ]; 45 | extraModulePackages = [ ]; 46 | 47 | loader = { 48 | systemd-boot.consoleMode = "max"; # Don't clip boot menu. 49 | efi.canTouchEfiVariables = true; 50 | timeout = 1; 51 | }; 52 | 53 | kernel.sysctl = { 54 | "kernel.sysrq" = "1"; 55 | "net.ipv4.tcp_congestion_control" = "bbr"; 56 | }; 57 | }; 58 | 59 | fileSystems = { 60 | "/" = { 61 | device = "/dev/disk/by-uuid/fbfe849d-2d2f-415f-88d3-65ded870e46b"; 62 | fsType = "btrfs"; 63 | options = [ "noatime" "compress=zstd:1" "subvol=@" ]; 64 | }; 65 | 66 | "/boot" = { 67 | device = "/dev/disk/by-uuid/9C91-4441"; 68 | fsType = "vfat"; 69 | }; 70 | }; 71 | 72 | swapDevices = [ 73 | { device = "/var/swap/resume"; } 74 | ]; 75 | 76 | # Hardware. 77 | 78 | hardware = { 79 | cpu.intel.updateMicrocode = true; 80 | bluetooth.enable = true; 81 | logitech.wireless.enable = true; 82 | enableRedistributableFirmware = true; # Required for WIFI. 83 | graphics.extraPackages = with pkgs; [ intel-media-driver ]; # vaapi 84 | }; 85 | console = { 86 | font = "${pkgs.terminus_font}/share/consolefonts/ter-v28n.psf.gz"; 87 | useXkbConfig = true; 88 | earlySetup = true; 89 | }; 90 | networking = { 91 | hostName = "blacksteel"; 92 | firewall.logRefusedConnections = false; 93 | networkmanager.dns = "systemd-resolved"; 94 | }; 95 | services.resolved.enable = true; 96 | systemd.network.wait-online.enable = false; 97 | 98 | time.timeZone = "America/Toronto"; 99 | 100 | # KDE pulls in pipewire via xdg-desktop-portal anyways. 101 | services.pipewire = { 102 | enable = true; 103 | pulse.enable = true; 104 | alsa.enable = true; 105 | }; 106 | security.rtkit.enable = true; # pipewire expects this. 107 | 108 | # Swap capslock and leftctrl only for the builtin keyboard. 109 | # Ref: https://wiki.archlinux.org/title/Map_scancodes_to_keycodes 110 | services.udev.extraHwdb = '' 111 | evdev:atkbd:dmi:bvnLENOVO:*:pvrThinkPadX1Carbon5th* 112 | KEYBOARD_KEY_3a=leftctrl 113 | KEYBOARD_KEY_1d=capslock 114 | ''; 115 | 116 | # Users. 117 | 118 | sops.secrets.passwd.neededForUsers = true; 119 | programs.zsh.enable = true; 120 | users = { 121 | mutableUsers = false; 122 | users."oxa" = { 123 | isNormalUser = true; 124 | shell = pkgs.zsh; 125 | hashedPasswordFile = config.sops.secrets.passwd.path; 126 | uid = 1000; 127 | group = config.users.groups.oxa.name; 128 | extraGroups = [ "wheel" "kvm" "adbusers" "libvirtd" "wireshark" ]; 129 | 130 | openssh.authorizedKeys.keys = with my.ssh.identities; [ oxa ]; 131 | }; 132 | groups."oxa".gid = 1000; 133 | }; 134 | home-manager.users."oxa" = 135 | import ../../home/blacksteel.nix; 136 | 137 | # Services. 138 | 139 | services = { 140 | dbus.implementation = "broker"; 141 | openssh = { 142 | enable = true; 143 | authorizedKeysInHomedir = false; 144 | settings = { 145 | KbdInteractiveAuthentication = false; 146 | PasswordAuthentication = false; 147 | PermitRootLogin = "no"; 148 | }; 149 | }; 150 | fstrim = { 151 | enable = true; 152 | interval = "Wed,Sat 02:00"; 153 | }; 154 | timesyncd.enable = true; 155 | earlyoom = { 156 | enable = true; 157 | enableNotifications = true; 158 | }; 159 | btrbk.instances.snapshot = { 160 | onCalendar = "*:00,30"; 161 | settings = { 162 | timestamp_format = "long-iso"; 163 | preserve_day_of_week = "monday"; 164 | preserve_hour_of_day = "6"; 165 | snapshot_preserve_min = "6h"; 166 | volume."/" = { 167 | snapshot_dir = ".snapshots"; 168 | subvolume."home/oxa".snapshot_preserve = "48h 7d"; 169 | subvolume."home/oxa/storage".snapshot_preserve = "48h 7d 4w"; 170 | }; 171 | }; 172 | }; 173 | }; 174 | 175 | nix = { 176 | buildMachines = [ 177 | { 178 | hostName = "aluminum.lan.hexade.ca"; 179 | maxJobs = 24; 180 | protocol = "ssh-ng"; 181 | sshUser = "oxa"; 182 | sshKey = "/etc/ssh/ssh_host_ed25519_key"; 183 | systems = [ "x86_64-linux" "i686-linux" ]; 184 | supportedFeatures = [ "kvm" "big-parallel" "nixos-test" "benchmark" ]; 185 | } 186 | ]; 187 | }; 188 | 189 | # Global ssh settings. Also for remote builders. 190 | programs.ssh = { 191 | knownHosts = my.ssh.knownHosts; 192 | extraConfig = '' 193 | Include ${config.sops.secrets.ssh-hosts.path} 194 | ''; 195 | }; 196 | sops.secrets.ssh-hosts = { 197 | sopsFile = ../../secrets/ssh.yaml; 198 | mode = "0444"; 199 | }; 200 | 201 | programs.adb.enable = true; 202 | 203 | programs.steam.enable = true; 204 | 205 | programs.wireshark = { 206 | enable = true; 207 | package = pkgs.wireshark-qt; 208 | }; 209 | 210 | programs.virt-manager.enable = true; 211 | 212 | services.btrfs.autoScrub = { 213 | enable = true; 214 | fileSystems = [ "/" ]; 215 | interval = "monthly"; 216 | }; 217 | 218 | programs.gamemode = { 219 | enable = true; 220 | settings = { 221 | general.igpu_desiredgov = "performance"; 222 | gpu = { 223 | apply_gpu_optimisations = "accept-responsibility"; 224 | gpu_device = 1; 225 | }; 226 | custom = { 227 | start = "${lib.getExe pkgs.libnotify} 'Enter GameMode'"; 228 | end = "${lib.getExe pkgs.libnotify} 'Leave GameMode'"; 229 | }; 230 | }; 231 | }; 232 | users.groups."gamemode".members = [ config.users.users.oxa.name ]; 233 | 234 | environment.systemPackages = with pkgs; [ 235 | ltunify 236 | ]; 237 | 238 | system.stateVersion = "25.05"; 239 | } 240 | -------------------------------------------------------------------------------- /nixos/blacksteel/secret.yaml: -------------------------------------------------------------------------------- 1 | passwd: ENC[AES256_GCM,data:jMLYujz0zRIgWCCC3ysEDgM6ZkmJkXtIpkxOrKDi/hbHIkGkCzEzulvWIL5Ap70ntNUYt5wrLT6+oRdMJ0tIimVYKtApE4/54eXVNoVrtoCKpalEiEYMdDdkJKZn+gG/KKHGlJ3UB0VrOQ==,iv:2wT6/nM8uJqgF0wX9vbUX3xRl9b2d/Tpb6PltOvxAl8=,tag:H5LoAaaXqQK+/kS0cO+97w==,type:str] 2 | sops: 3 | kms: [] 4 | gcp_kms: [] 5 | azure_kv: [] 6 | hc_vault: [] 7 | age: 8 | - recipient: age1l9qly5vlx20uzrqvq8qygvcrtff64mgvqchet5uvs989upy5lugq4krj2c 9 | enc: | 10 | -----BEGIN AGE ENCRYPTED FILE----- 11 | YWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSAzZkFpMXFBa1hJRmpjVkxu 12 | dnBqMGpZcktORit2YWN6TzlyWDlCWmhnaFMwCmhsVmFteGRzeTRCQnRQbTd0by9Q 13 | N3JJWUZyNUtqYTI2WldSZS9HOWU5UHcKLS0tIHFDaFBEQ2VEQVlySnA3VU43QmtE 14 | NFBURVRVS0wvejBXcjF1VEVWSmJVNzQKAtChN2sLTatYhSrdPFxc9gkW1y0rwLP6 15 | 2Sx/5f38XVinmEsy63eNIzdwWCDtCa7/tHgwqIEXojA5OVg1pHQmVQ== 16 | -----END AGE ENCRYPTED FILE----- 17 | lastmodified: "2022-08-19T16:56:57Z" 18 | mac: ENC[AES256_GCM,data:SZ7RUJ/8qkKSbYjM72QCSsb6ZqJ3+OmtYiGjeZ8yMRd9cCN83bSMJTmynWGen/7+rrqQUVlC799dFBWcqSV5L0yih/ZnlkIeLiX8wns7SdUkAN0Y4KgmqGC/HSHGmgpj/UlTO4azJExnw0j+Fj2mtB3b2ulJm/FtLHBcJxlROp8=,iv:T4ZLd3vEDcb85+bfqMb8Ouv6fsJv7pUZSZ7T8Pc3YTQ=,tag:/Lzkfbc213KhgCnEWXOF3g==,type:str] 19 | pgp: 20 | - created_at: "2023-04-02T15:33:27Z" 21 | enc: |- 22 | -----BEGIN PGP MESSAGE----- 23 | 24 | wV4Dhs332B8tbXUSAQdAg2TKsM/gYOd4gbTIzIxrIXeHIE+c0RI53RGrSEg2GAkw 25 | lW1s/3ebnMfEODW17ukxoVeypCXvpKsm2Yn3khOEsqQ2xvafF533RJIgG7mWRRyP 26 | 0lEBb0yKOehSPZAYAVX2JJ06s+9wf9KhypqeyWsNjoTuJyYGQ42tpSnT1jxw4IGi 27 | KP6MeL3ZOdSE3mTnlM6zBiaGfm3UeO5t9SuFK5eEaRVo100= 28 | =T6VT 29 | -----END PGP MESSAGE----- 30 | fp: F90FFD6D585C2BA1F13DE8A97571654CF88E31C2 31 | unencrypted_suffix: _unencrypted 32 | version: 3.7.3 33 | -------------------------------------------------------------------------------- /nixos/blacksteel/vm.nix: -------------------------------------------------------------------------------- 1 | { pkgs, ... }: 2 | { 3 | virtualisation.libvirtd = { 4 | enable = true; 5 | qemu.package = pkgs.qemu_kvm; 6 | }; 7 | boot.kernel.sysctl."net.ipv4.ip_forward" = 1; 8 | virtualisation.kvmgt = { 9 | enable = true; 10 | # Random generated UUIDs. 11 | # vgpus."i915-GVTg_V5_4".uuid = "7dbe463d-94fc-425c-8ccd-55d0f9d5d26b"; # 1920x1200 12 | vgpus."i915-GVTg_V5_8".uuid = [ "89584099-86a4-4b77-b770-16c0a93c260a" ]; # 1024x768 13 | }; 14 | 15 | systemd.services."win10-hd-vm-disk" = let 16 | dmName = "win10-hd-vm-disk"; 17 | 18 | devWin = "/dev/disk/by-uuid/CE8A6B398A6B1D69"; 19 | secWin = 262047414; 20 | devGpt = "/dev/disk/by-partuuid/4f3131a2-ee06-425e-b3af-bbf35c00d192"; 21 | secGptBefore = 262144; # 128 MiB 22 | secGptAfter = 2048; # 1 MiB 23 | 24 | in { 25 | description = "Device mapper for Windows 10 VM"; 26 | unitConfig.RequiresMountsFor = "/home/oxa/vm/pool"; 27 | wantedBy = [ "multi-user.target" ]; 28 | serviceConfig.Type = "oneshot"; 29 | serviceConfig.RemainAfterExit = true; 30 | 31 | path = with pkgs; [ util-linux lvm2 ]; 32 | script = '' 33 | sec_win=$(blockdev --getsz ${devWin}) 34 | sec_gpt=$(blockdev --getsz ${devGpt}) 35 | echo "Windows partition has $sec_win sectors" 36 | echo "GPT partition has $sec_gpt sectors" 37 | if [[ "$sec_win" -ne ${toString secWin} || "$sec_gpt" -ne ${toString (secGptBefore + secGptAfter)} ]]; then 38 | echo "Size mismatch" 39 | exit 1 40 | fi 41 | 42 | dmsetup create ${dmName} <./config.json 85 | ${lib.getExe config.services.caddy.package} validate --config ./config.json 86 | ''; 87 | }); 88 | 89 | }; 90 | 91 | systemd.tmpfiles.settings."caddy-logs" = { 92 | ${logDir}.d = { 93 | group = config.users.groups.caddy.name; 94 | user = config.users.users.caddy.name; 95 | mode = "0755"; 96 | }; 97 | }; 98 | 99 | system.stateVersion = "25.05"; 100 | } 101 | -------------------------------------------------------------------------------- /nixos/lithium/ntfy.nix: -------------------------------------------------------------------------------- 1 | # Ref: https://github.com/NickCao/flakes/blob/3b03efb676ea602575c916b2b8bc9d9cd13b0d85/nixos/hcloud/iad1/ntfy.nix 2 | { lib, config, ... }: 3 | let 4 | inherit (lib) singleton; 5 | host = "ntfy.oxa.li"; 6 | in 7 | { 8 | 9 | services.ntfy-sh = { 10 | enable = true; 11 | settings = { 12 | base-url = "https://${host}"; 13 | listen-http = ""; 14 | listen-unix = "/run/ntfy-sh/ntfy.sock"; 15 | listen-unix-mode = 511; # 0777 16 | behind-proxy = true; 17 | }; 18 | }; 19 | 20 | systemd.services.ntfy-sh.serviceConfig.RuntimeDirectory = "ntfy-sh"; 21 | 22 | services.caddy.settings.apps.http.servers.default.routes = singleton { 23 | match = singleton { host = singleton host; }; 24 | terminal = true; 25 | handle = singleton { 26 | handler = "reverse_proxy"; 27 | upstreams = singleton { dial = "unix/${config.services.ntfy-sh.settings.listen-unix}"; }; 28 | }; 29 | }; 30 | } 31 | -------------------------------------------------------------------------------- /nixos/lithium/secret.yaml: -------------------------------------------------------------------------------- 1 | caddy-env: ENC[AES256_GCM,data:v7alrb5cDdLfAsbRLkA7wTjJ1j/XrUtwr159giQAC8F8s4fpf9/RihE/dmCY1P74EIAIOM+21PRaqBQowsFEMNd79U3ZZOufhKG5gJk3/7RvXStGLmfTUwJtbAk4qvbGFcTgZBA=,iv:cLZOHsjYnpSAQzYDaJ+01Wwyf6hZcWMaSbDuysu8bnI=,tag:KEFgVuLaQmZ3l0Epe8J/rQ==,type:str] 2 | sops: 3 | kms: [] 4 | gcp_kms: [] 5 | azure_kv: [] 6 | hc_vault: [] 7 | age: 8 | - recipient: age1telu43gwg7fucnph6x5mgl46yvaj9z0cuj2v4e5d8fxhlsvduqas7psujn 9 | enc: | 10 | -----BEGIN AGE ENCRYPTED FILE----- 11 | YWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSB6cnRMMERKQ3hvYjloWjl0 12 | bHYvQlVUcXNCYjRRay9KN0VlblV4NldiM2tJClNpNlpPZzRTVXZxZVcrYXZLOTQ0 13 | RUhHamxEazQ1bTgwM0tYTkI4QkdXWkEKLS0tIEdvM3pkVUlWa3ZPSUZRRzFuQTR3 14 | a1NPNlp6Wm1PTUk1WTlkUy8rUjFMRlUKayVPRf3VtInuMViUgZ6waBMy+ctRAiGi 15 | bipOcAvc+gjMceGvICeZa2+zw+LPvn3NvNn1Cz4DwrlWTW9/ElOAgg== 16 | -----END AGE ENCRYPTED FILE----- 17 | lastmodified: "2024-09-01T23:16:54Z" 18 | mac: ENC[AES256_GCM,data:XdSB+l63v7z++d7gj+nEcf9Mhr0j1pOt2bEKmAFTNSyFa6+Hx+amm9vu/WL81e1F9T08DzZ0bWSQ8pMNoQZYb6ZUw8h2RmXXFx5BhoSLgpp5uIxvWp6bRK1B4CvDw7je7d0aKGw6FkwgxaM6mjebOafBtUSqfJRufgCkR4bCx9k=,iv:ndgQLd3TBDAHukh4fpFBMh9NrC8Wv60NUTGn+0XdU4g=,tag:w0qkVtC/kg+Wro2YV0eFHA==,type:str] 19 | pgp: 20 | - created_at: "2024-09-07T04:43:35Z" 21 | enc: |- 22 | -----BEGIN PGP MESSAGE----- 23 | 24 | hF4Dhs332B8tbXUSAQdAue0uC50aYtAQKzcn3qkHxY8YA8ogooUvGuiXVlDW8nQw 25 | AnB7dC/TtD8lsmvb8yGga7MQLIJKaUs5GPLnIKlxLCQGw30pgY71h2Q+JKq59xH2 26 | 0l4Bo6fOGOrfBIc14T/yKho1b+AU2y0OpGbwG6DEj+HG4rUBFbEza+C3+8wWSM/j 27 | KnKF7A3ue2TRO3Dyf5HU98AQqmChuZsdOC9kVhXeLamlKzP23I/R6gR3SBnhnTnU 28 | =nrel 29 | -----END PGP MESSAGE----- 30 | fp: F90FFD6D585C2BA1F13DE8A97571654CF88E31C2 31 | unencrypted_suffix: _unencrypted 32 | version: 3.9.0 33 | -------------------------------------------------------------------------------- /nixos/lithium/webdav.nix: -------------------------------------------------------------------------------- 1 | { lib, config, ... }: 2 | let 3 | inherit (lib) singleton; 4 | 5 | route = "/webdav"; 6 | srvPath = "/srv/webdav"; 7 | 8 | in 9 | { 10 | # This requires service restart anyway. Leave it to human. 11 | sops.secrets.caddy-env = { }; 12 | systemd.services.caddy = { 13 | serviceConfig = { 14 | RuntimeDirectory = "caddy"; 15 | ReadWritePaths = singleton srvPath; 16 | EnvironmentFile = singleton config.sops.secrets.caddy-env.path; 17 | }; 18 | after = [ "systemd-tmpfiles-setup.service" ]; 19 | }; 20 | 21 | # NB. Limit can only be set manually. 22 | systemd.tmpfiles.settings."webdav" = { 23 | ${srvPath}.v = { 24 | group = config.users.groups.caddy.name; 25 | user = config.users.users.caddy.name; 26 | mode = "0755"; 27 | }; 28 | }; 29 | 30 | services.caddy.settings.apps.http.servers.default.routes = lib.singleton { 31 | match = singleton { 32 | host = singleton config.networking.fqdn; 33 | path = singleton "${route}/*"; 34 | }; 35 | handle = [ 36 | { 37 | handler = "authentication"; 38 | providers.http_basic.accounts = singleton { 39 | username = "{env.WEBDAV_USERNAME}"; 40 | password = "{env.WEBDAV_PASSWORD}"; 41 | }; 42 | } 43 | { 44 | handler = "webdav"; 45 | root = srvPath; 46 | # Workaround: prefix makes HEAD fail with 405 (Method Not Allowed) 47 | # See: https://github.com/mholt/caddy-webdav/issues/19 48 | # prefix = route; 49 | } 50 | ]; 51 | }; 52 | } 53 | -------------------------------------------------------------------------------- /nixos/minimal-image/configuration.nix: -------------------------------------------------------------------------------- 1 | # NB. systemd-initrd doesn't work for ISO yet. 2 | { lib, config, pkgs, modulesPath, my, ... }: 3 | { 4 | imports = [ 5 | (modulesPath + "/installer/cd-dvd/installation-cd-minimal-new-kernel-no-zfs.nix") 6 | ../modules/console-env.nix 7 | ../modules/nix-binary-cache-mirror.nix 8 | ]; 9 | 10 | isoImage = { 11 | isoBaseName = lib.mkForce "nixoxa"; 12 | volumeID = "NIXOXA"; 13 | # Worse compression but way faster. 14 | squashfsCompression = "zstd -Xcompression-level 6"; 15 | }; 16 | 17 | # Workaround: https://github.com/NixOS/nixpkgs/issues/254807 18 | boot.swraid.enable = lib.mkForce false; 19 | 20 | networking.hostName = "nixoxa"; 21 | networking.wireless.enable = true; 22 | 23 | nix = { 24 | settings = { 25 | experimental-features = [ 26 | "nix-command" 27 | "flakes" 28 | ]; 29 | 30 | flake-registry = ""; 31 | }; 32 | 33 | nixPath = [ "nixpkgs=${config.nix.registry.nixpkgs.to.path}" ]; 34 | }; 35 | 36 | environment.systemPackages = with pkgs; [ 37 | neofetch 38 | sbctl # Secure boot. 39 | ]; 40 | 41 | users.users.root.openssh.authorizedKeys.keys = with my.ssh.identities; [ oxa ]; 42 | services.openssh = { 43 | enable = true; 44 | settings = { 45 | PasswordAuthentication = false; 46 | KbdInteractiveAuthentication = false; 47 | PermitRootLogin = lib.mkForce "prohibit-password"; 48 | }; 49 | }; 50 | 51 | system.stateVersion = "24.11"; 52 | } 53 | -------------------------------------------------------------------------------- /nixos/modules/console-env.nix: -------------------------------------------------------------------------------- 1 | { lib, pkgs, my, ... }: 2 | { 3 | # Reduce the closure size. 4 | i18n.supportedLocales = lib.mkDefault [ "en_US.UTF-8/UTF-8" ]; 5 | i18n.defaultLocale = lib.mkDefault "en_US.UTF-8"; 6 | 7 | fonts.fontconfig.enable = lib.mkDefault false; 8 | 9 | # Default: 10 | # - perl # No. 11 | # - rsync strace # Already in systemPackages. 12 | environment.defaultPackages = [ ]; 13 | 14 | environment.systemPackages = with pkgs; [ 15 | cntr # Nix helpers. 16 | btdu procs ncdu swapview smartmontools pciutils usbutils # System info. 17 | moreutils curl git strace pv tree fd ripgrep lsof jq bc file rsync dnsutils # Utilities. 18 | compsize e2fsprogs # Filesystems. 19 | gnupg age pwgen sops ssh-to-age # Crypto. 20 | libarchive zstd # Compression. 21 | 22 | my.pkgs.nixos-rebuild-shortcut 23 | ]; 24 | 25 | programs.less = { 26 | enable = true; 27 | lessopen = null; 28 | }; 29 | environment.variables = let 30 | common = [ 31 | "--RAW-CONTROL-CHARS" # Only allow colors. 32 | "--mouse" 33 | "--wheel-lines=5" 34 | "--LONG-PROMPT" 35 | ]; 36 | in { 37 | PAGER = "less"; 38 | # Don't use `programs.less.envVariables.LESS`, which will be override by `LESS` set by `man`. 39 | LESS = lib.concatStringsSep " " common; 40 | SYSTEMD_LESS = lib.concatStringsSep " " (common ++ [ 41 | "--quit-if-one-screen" 42 | "--chop-long-lines" 43 | "--no-init" # Keep content after quit. 44 | ]); 45 | }; 46 | 47 | programs.tmux.enable = true; 48 | 49 | programs.htop.enable = true; 50 | programs.iotop.enable = true; 51 | programs.iftop.enable = true; 52 | 53 | programs.mtr.enable = true; 54 | 55 | # Don't stuck for searching missing commands. 56 | programs.command-not-found.enable = false; 57 | 58 | programs.vim = { 59 | enable = true; 60 | defaultEditor = true; 61 | }; 62 | 63 | programs.nano.enable = lib.mkDefault false; 64 | } 65 | -------------------------------------------------------------------------------- /nixos/modules/device-fix.nix: -------------------------------------------------------------------------------- 1 | { ... }: 2 | { 3 | # Fix Fn2 for MIIIW Keyboard. 4 | boot.extraModprobeConfig = '' 5 | options hid_apple fnmode=2 6 | ''; 7 | 8 | # Enable TRIM for the WD harddisk. 9 | services.udev.extraRules = '' 10 | ACTION=="add|change", ATTRS{idVendor}=="1058", ATTRS{idProduct}=="25a2", SUBSYSTEM=="scsi_disk", ATTR{provisioning_mode}="unmap" 11 | ''; 12 | } 13 | -------------------------------------------------------------------------------- /nixos/modules/kde-desktop/default.nix: -------------------------------------------------------------------------------- 1 | { pkgs, ... }: 2 | { 3 | imports = [ ../l10n.nix ]; 4 | 5 | environment.systemPackages = with pkgs.kdePackages; [ 6 | filelight 7 | kolourpaint 8 | okular 9 | gwenview 10 | pkgs.qpwgraph 11 | ]; 12 | 13 | programs = { 14 | partition-manager.enable = true; 15 | kdeconnect.enable = true; 16 | }; 17 | 18 | services.desktopManager.plasma6.enable = true; 19 | services.displayManager.sddm = { 20 | enable = true; 21 | wayland.enable = true; 22 | }; 23 | 24 | networking.networkmanager.enable = true; 25 | } 26 | -------------------------------------------------------------------------------- /nixos/modules/l10n.nix: -------------------------------------------------------------------------------- 1 | { lib, pkgs, my, ... }: 2 | { 3 | i18n = { 4 | supportedLocales = [ "all" ]; # Override console-env. 5 | defaultLocale = "en_CA.UTF-8"; 6 | inputMethod = { 7 | enable = true; 8 | type = "fcitx5"; 9 | fcitx5 = { 10 | addons = with pkgs; [ 11 | (fcitx5-rime.override { 12 | rimeDataPkgs = [ rime-data my.pkgs.rime_latex ]; 13 | }) 14 | ]; 15 | }; 16 | }; 17 | }; 18 | 19 | # Ref: https://catcat.cc/post/2021-03-07/ 20 | fonts = { 21 | enableDefaultPackages = false; 22 | fontDir.enable = true; 23 | 24 | packages = with pkgs; [ 25 | noto-fonts 26 | noto-fonts-cjk-sans 27 | noto-fonts-cjk-serif 28 | noto-fonts-color-emoji 29 | twemoji-color-font 30 | font-awesome 31 | hanazono 32 | # Use bin to save build time (~11min). 33 | (iosevka-bin.override { variant = "SGr-IosevkaFixed"; }) 34 | 35 | # Roman for PDF. 36 | liberation_ttf 37 | ]; 38 | 39 | fontconfig = { 40 | enable = true; 41 | 42 | defaultFonts = { 43 | monospace = [ "Iosevka Fixed" "Noto Sans CJK SC" "Font Awesome 6 Free" "Twemoji" ]; 44 | sansSerif = [ "Noto Sans" "Noto Sans CJK SC" "Twemoji" ]; 45 | serif = [ "Noto Serif" "Noto Serif CJK SC" "Twemoji" ]; 46 | emoji = [ "Twemoji" ]; 47 | }; 48 | 49 | localConf = '' 50 | 51 | 52 | 53 | 54 | ${lib.concatMapStringsSep "\n" ({ lang, variant }: 55 | let 56 | replace = from: to: '' 57 | 58 | 59 | ${lang} 60 | 61 | 62 | ${from} 63 | 64 | 65 | ${to} 66 | 67 | 68 | ''; 69 | in 70 | replace "sans-serif" "Noto Sans CJK ${variant}" + 71 | replace "serif" "Noto Serif CJK ${variant}" 72 | ) [ 73 | { lang = "zh"; variant = "SC"; } 74 | { lang = "zh-TW"; variant = "TC"; } 75 | { lang = "zh-HK"; variant = "HK"; } 76 | { lang = "ja"; variant = "JP"; } 77 | { lang = "ko"; variant = "KR"; } 78 | ]} 79 | 80 | ''; 81 | }; 82 | }; 83 | } 84 | -------------------------------------------------------------------------------- /nixos/modules/nix-binary-cache-mirror.nix: -------------------------------------------------------------------------------- 1 | { lib, ... }: 2 | let 3 | urls = [ 4 | # "https://mirror.sjtu.edu.cn/nix-channels/store" # Frequent download stall. 5 | "https://mirrors.bfsu.edu.cn/nix-channels/store" 6 | 7 | # Do no try to enable TUNA! Scary thing will happen! 8 | # "https://mirrors.tuna.tsinghua.edu.cn/nix-channels/store" # May suffer from download stalled issue. 9 | # "https://mirrors.ustc.edu.cn/nix-channels/store" 10 | ]; 11 | in 12 | { 13 | nix.settings.substituters = lib.mkBefore urls; 14 | } 15 | -------------------------------------------------------------------------------- /nixos/modules/nix-cgroups.nix: -------------------------------------------------------------------------------- 1 | { 2 | nix.settings = { 3 | experimental-features = [ 4 | "auto-allocate-uids" 5 | "cgroups" 6 | ]; 7 | auto-allocate-uids = true; 8 | use-cgroups = true; 9 | }; 10 | } 11 | -------------------------------------------------------------------------------- /nixos/modules/nix-common.nix: -------------------------------------------------------------------------------- 1 | { lib, pkgs, inputs, ... }: 2 | { 3 | # Ensure this is >= 2.22.1 with the following fix included, or it failes to eval. 4 | # https://github.com/NixOS/nix/pull/10456 5 | nix.package = lib.mkDefault pkgs.nixVersions.latest; 6 | 7 | nix.channel.enable = false; 8 | 9 | nix.gc = { 10 | automatic = true; 11 | dates = "Wed,Sat 01:00"; 12 | options = "--delete-older-than 8d"; 13 | persistent = false; 14 | }; 15 | systemd.services.nix-gc.serviceConfig = { 16 | Nice = 19; 17 | IOSchedulingClass = "idle"; 18 | MemorySwapMax = 0; 19 | }; 20 | 21 | nix.settings = { 22 | experimental-features = [ 23 | "nix-command" 24 | "flakes" 25 | "ca-derivations" 26 | ]; 27 | 28 | flake-registry = ""; 29 | 30 | allow-import-from-derivation = false; 31 | auto-optimise-store = true; 32 | trusted-users = [ "root" "@wheel" ]; 33 | 34 | connect-timeout = 10; 35 | download-attempts = 3; 36 | stalled-download-timeout = 10; 37 | 38 | # Workaround: https://github.com/NixOS/nixpkgs/pull/273170 39 | nix-path = "nixpkgs=${inputs.nixpkgs}"; 40 | }; 41 | 42 | nix.registry = { 43 | nixpkgs = { 44 | from = { id = "nixpkgs"; type = "indirect"; }; 45 | flake = inputs.nixpkgs; 46 | }; 47 | }; 48 | 49 | nix.nixPath = [ 50 | "nixpkgs=${inputs.nixpkgs}" 51 | ]; 52 | } 53 | -------------------------------------------------------------------------------- /nixos/modules/nix-keep-flake-inputs.nix: -------------------------------------------------------------------------------- 1 | { inputs, ... }: 2 | { 3 | system.extraDependencies = let 4 | collectFlakeInputs = 5 | input: [ input ] ++ builtins.concatMap collectFlakeInputs (builtins.attrValues (input.inputs or {})); 6 | in 7 | builtins.concatMap collectFlakeInputs (builtins.attrValues inputs); 8 | } 9 | -------------------------------------------------------------------------------- /nixos/modules/nix-registry.nix: -------------------------------------------------------------------------------- 1 | { lib, inputs, ... }: 2 | { 3 | nix.registry = lib.mapAttrs (name: value: { 4 | flake = value; 5 | }) inputs; 6 | } 7 | -------------------------------------------------------------------------------- /nixos/modules/secure-boot.nix: -------------------------------------------------------------------------------- 1 | # https://github.com/nix-community/lanzaboote/blob/master/docs/QUICK_START.md 2 | { pkgs, inputs, ... }: 3 | { 4 | imports = [ 5 | inputs.lanzaboote.nixosModules.lanzaboote 6 | ]; 7 | 8 | # This should already be here from switching to bootspec earlier. 9 | # It's not required anymore, but also doesn't do any harm. 10 | boot.bootspec.enable = true; 11 | 12 | environment.systemPackages = [ 13 | pkgs.sbctl 14 | ]; 15 | 16 | # Lanzaboote currently replaces the systemd-boot module. 17 | # This setting is usually set to true in configuration.nix 18 | # generated at installation time. So we force it to false 19 | # for now. 20 | boot.loader.systemd-boot.enable = false; 21 | 22 | boot.lanzaboote = { 23 | enable = true; 24 | # See: https://github.com/nix-community/lanzaboote/issues/413 25 | pkiBundle = "/var/lib/sbctl"; 26 | }; 27 | } 28 | -------------------------------------------------------------------------------- /nixos/modules/server-env.nix: -------------------------------------------------------------------------------- 1 | { lib, pkgs, ... }: 2 | { 3 | # Reduce the closure size. 4 | i18n.supportedLocales = [ "en_US.UTF-8/UTF-8" ]; 5 | i18n.defaultLocale = "en_US.UTF-8"; 6 | fonts.fontconfig.enable = false; 7 | documentation = { 8 | enable = false; 9 | man.enable = false; 10 | info.enable = lib.mkDefault false; 11 | }; 12 | 13 | # Partially copied from `nixos/modules/profiles/perlless.nix`. 14 | system.disableInstallerTools = lib.mkDefault true; 15 | boot.enableContainers = lib.mkDefault false; 16 | 17 | # Default: 18 | # - perl # No. 19 | # - rsync strace # Already in systemPackages. 20 | environment.defaultPackages = [ ]; 21 | 22 | environment.systemPackages = with pkgs; [ 23 | # Utilities. 24 | compsize 25 | curl 26 | dnsutils 27 | fd 28 | file 29 | jq 30 | libarchive 31 | lsof 32 | ncdu 33 | procs 34 | pv 35 | ripgrep 36 | rsync 37 | strace 38 | tree 39 | zstd 40 | 41 | # Cryptography. 42 | age 43 | gnupg 44 | ssh-to-age 45 | 46 | # Version control. 47 | gitMinimal 48 | ]; 49 | 50 | programs.less = { 51 | enable = true; 52 | lessopen = null; 53 | }; 54 | environment.variables = 55 | let 56 | common = [ 57 | "--RAW-CONTROL-CHARS" # Only allow colors. 58 | "--mouse" 59 | "--wheel-lines=5" 60 | "--LONG-PROMPT" 61 | ]; 62 | in 63 | { 64 | PAGER = "less"; 65 | # Don't use `programs.less.envVariables.LESS`, which will be override by `LESS` set by `man`. 66 | LESS = lib.concatStringsSep " " common; 67 | SYSTEMD_LESS = lib.concatStringsSep " " ( 68 | common 69 | ++ [ 70 | "--quit-if-one-screen" 71 | "--chop-long-lines" 72 | "--no-init" # Keep content after quit. 73 | ] 74 | ); 75 | }; 76 | 77 | programs.tmux.enable = true; 78 | 79 | programs.htop.enable = true; 80 | programs.iotop.enable = true; 81 | programs.iftop.enable = true; 82 | 83 | programs.mtr.enable = true; 84 | 85 | programs.command-not-found.enable = false; 86 | 87 | programs.vim = { 88 | enable = true; 89 | defaultEditor = true; 90 | }; 91 | 92 | programs.nano.enable = lib.mkDefault false; 93 | } 94 | -------------------------------------------------------------------------------- /nixos/modules/vultr-common.nix: -------------------------------------------------------------------------------- 1 | { lib, pkgs, modulesPath, my, ... }: 2 | { 3 | imports = [ 4 | "${modulesPath}/profiles/qemu-guest.nix" 5 | 6 | ../modules/nix-common.nix 7 | ../modules/server-env.nix 8 | ../modules/zswap-enable.nix 9 | ./vultr-image.nix 10 | ]; 11 | 12 | boot.loader.systemd-boot.enable = true; 13 | boot.loader.timeout = 1; 14 | 15 | boot.initrd.systemd.enable = true; 16 | boot.initrd.availableKernelModules = [ "ahci" "xhci_pci" "sr_mod" ]; 17 | boot.initrd.kernelModules = [ ]; 18 | boot.kernelModules = [ ]; 19 | boot.extraModulePackages = [ ]; 20 | 21 | boot.kernel.sysctl = { 22 | "net.ipv4.tcp_congestion_control" = "bbr"; 23 | }; 24 | 25 | fileSystems."/" = { 26 | device = "/dev/disk/by-label/nixos"; 27 | fsType = "btrfs"; 28 | options = [ "noatime" "compress=zstd" ]; 29 | }; 30 | fileSystems."/boot" = { 31 | device = "/dev/disk/by-label/ESP"; 32 | fsType = "vfat"; 33 | }; 34 | 35 | swapDevices = [ ]; 36 | 37 | networking.useNetworkd = true; 38 | networking.useDHCP = false; 39 | networking.interfaces.enp1s0.useDHCP = true; 40 | networking.firewall.enable = false; # Already have a hardware firewall. 41 | networking.nameservers = [ 42 | "1.1.1.1" "1.0.0.1" 43 | "2606:4700:4700::1111" "2606:4700:4700::1001" 44 | ]; 45 | 46 | systemd.sysusers.enable = lib.mkDefault true; 47 | users.mutableUsers = lib.mkDefault false; 48 | users.users.root.openssh.authorizedKeys.keys = with my.ssh.identities; [ oxa ]; 49 | services.getty.autologinUser = lib.mkDefault "root"; 50 | 51 | nix.package = pkgs.nix; 52 | nix.gc.options = lib.mkForce "--delete-older-than 3d"; 53 | # Avoid dependency to nixpkgs itself. 54 | nix.settings.nix-path = lib.mkForce ""; 55 | nix.registry = lib.mkForce { }; 56 | nix.nixPath = lib.mkForce [ ]; 57 | 58 | services.openssh = { 59 | enable = true; 60 | ports = [ 798 ]; 61 | settings = { 62 | PasswordAuthentication = false; 63 | KbdInteractiveAuthentication = false; 64 | PermitRootLogin = "prohibit-password"; 65 | }; 66 | }; 67 | } 68 | -------------------------------------------------------------------------------- /nixos/modules/vultr-image.nix: -------------------------------------------------------------------------------- 1 | # Ref: https://x86.lol/generic/2024/08/28/systemd-sysupdate.html 2 | { 3 | lib, 4 | config, 5 | pkgs, 6 | modulesPath, 7 | ... 8 | }: 9 | let 10 | inherit (lib) 11 | mkOption 12 | types 13 | ; 14 | 15 | inherit (pkgs.hostPlatform) efiArch; 16 | 17 | cfg = config.vultrImage; 18 | in 19 | { 20 | imports = [ 21 | (modulesPath + "/image/repart.nix") 22 | ]; 23 | 24 | options.vultrImage = { 25 | name = mkOption { 26 | type = types.str; 27 | description = "The name of the generated derivation"; 28 | default = "nixos-vultr-image-${config.system.nixos.label}-${pkgs.stdenv.hostPlatform.system}"; 29 | }; 30 | 31 | efiPartSize = mkOption { 32 | type = types.str; 33 | default = "128M"; 34 | example = "256M"; 35 | description = "The start offset of EFI partition."; 36 | }; 37 | }; 38 | 39 | config.image.repart = { 40 | name = cfg.name; 41 | compression.enable = true; 42 | mkfsOptions.btrfs = [ "--shrink" ]; 43 | partitions = { 44 | "10-esp" = { 45 | contents = { 46 | "/EFI/BOOT/BOOT${lib.toUpper efiArch}.EFI".source = "${pkgs.systemd}/lib/systemd/boot/efi/systemd-boot${efiArch}.efi"; 47 | "/EFI/Linux/${config.system.boot.loader.ukiFile}".source = "${config.system.build.uki}/${config.system.boot.loader.ukiFile}"; 48 | }; 49 | repartConfig = { 50 | Label = "ESP"; 51 | Type = "esp"; 52 | Format = "vfat"; 53 | SizeMinBytes = cfg.efiPartSize; 54 | SizeMaxBytes = cfg.efiPartSize; 55 | }; 56 | }; 57 | "20-root" = { 58 | storePaths = [ config.system.build.toplevel ]; 59 | repartConfig = { 60 | Label = "nixos"; 61 | Type = "root"; 62 | Format = "btrfs"; 63 | Minimize = "guess"; 64 | # WAIT: `Compression=` requires https://github.com/kdave/btrfs-progs/pull/882 65 | }; 66 | }; 67 | }; 68 | }; 69 | } 70 | -------------------------------------------------------------------------------- /nixos/modules/zswap-enable.nix: -------------------------------------------------------------------------------- 1 | { ... }: { 2 | systemd.tmpfiles.settings."zswap" = { 3 | "/sys/module/zswap/parameters/enabled"."w-".argument = "1"; 4 | "/sys/module/zswap/parameters/zpool"."w-".argument = "zsmalloc"; 5 | }; 6 | } 7 | -------------------------------------------------------------------------------- /nixos/unmatched/configuration.nix: -------------------------------------------------------------------------------- 1 | # From: https://github.com/NickCao/nixos-riscv/blob/720c8ee6fc8eee85f741e309a4e0291dc3a90f59/flake.nix#L82 2 | { pkgs, lib, inputs, my, ... }: 3 | { 4 | imports = [ 5 | # (modulesPath + "/installer/sd-card/sd-image.nix") 6 | # ../modules/console-env.nix 7 | ]; 8 | 9 | disabledModules = [ "profiles/all-hardware.nix" ]; 10 | 11 | # For firmware. 12 | nixpkgs.config.allowUnfree = true; 13 | 14 | nixpkgs.overlays = [ 15 | (final: prev: { 16 | boost = final.boost17x; 17 | }) 18 | ]; 19 | 20 | /* 21 | sdImage = { 22 | populateRootCommands = '' 23 | mkdir -p ./files/boot 24 | ${config.boot.loader.generic-extlinux-compatible.populateCmd} -c ${config.system.build.toplevel} -d ./files/boot 25 | ''; 26 | populateFirmwareCommands = ""; 27 | }; 28 | */ 29 | 30 | boot.loader = { 31 | grub.enable = false; 32 | generic-extlinux-compatible.enable = true; 33 | generic-extlinux-compatible.configurationLimit = 5; 34 | }; 35 | boot.initrd.kernelModules = [ "nvme" "mmc_block" "mmc_spi" "spi_sifive" "spi_nor" "uas" "sdhci_pci" ]; 36 | boot.kernelParams = [ "loglevel=7" ]; # DEBUG 37 | boot.kernelPackages = pkgs.linuxPackages_latest; 38 | boot.kernelPatches = map (patch: { name = patch; patch = inputs.meta-sifive + "/recipes-kernel/linux/files/${patch}"; }) [ 39 | "0001-riscv-sifive-fu740-cpu-1-2-3-4-set-compatible-to-sif.patch" 40 | "0002-riscv-sifive-unmatched-update-regulators-values.patch" 41 | "0003-riscv-sifive-unmatched-define-PWM-LEDs.patch" 42 | "0004-riscv-sifive-unmatched-add-gpio-poweroff-node.patch" 43 | "0005-SiFive-HiFive-Unleashed-Add-PWM-LEDs-D1-D2-D3-D4.patch" 44 | "0006-riscv-sifive-unleashed-define-opp-table-cpufreq.patch" 45 | "riscv-sbi-srst-support.patch" 46 | ] ++ [ 47 | { 48 | name = "sifive"; 49 | patch = null; 50 | extraConfig = '' 51 | SOC_SIFIVE y 52 | PCIE_FU740 y 53 | PWM_SIFIVE y 54 | EDAC_SIFIVE y 55 | SIFIVE_L2 y 56 | RISCV_ERRATA_ALTERNATIVE y 57 | ERRATA_SIFIVE y 58 | ERRATA_SIFIVE_CIP_453 y 59 | ERRATA_SIFIVE_CIP_1200 y 60 | ''; 61 | } 62 | # https://github.com/zhaofengli/unmatched-nixos/blob/e04fff15b62846d5151c0d98da79398e238b69f6/pkgs/linux/default.nix 63 | { 64 | name = "cpufreq"; 65 | patch = null; 66 | extraConfig = '' 67 | CPU_IDLE y 68 | CPU_FREQ y 69 | CPU_FREQ_DEFAULT_GOV_USERSPACE y 70 | CPU_FREQ_GOV_PERFORMANCE y 71 | CPU_FREQ_GOV_USERSPACE y 72 | CPU_FREQ_GOV_ONDEMAND y 73 | ''; 74 | } 75 | ]; 76 | 77 | fileSystems."/" = { 78 | device = "/dev/disk/by-uuid/27b822c9-7087-4f52-8b7e-88a0ac476808"; 79 | fsType = "ext4"; 80 | }; 81 | fileSystems."/boot" = { 82 | device = "/dev/disk/by-uuid/3A9E-9961"; 83 | fsType = "vfat"; 84 | }; 85 | swapDevices = [ 86 | { 87 | device = "/var/swapfile"; 88 | size = 4 * 1024; # 4G 89 | } 90 | ]; 91 | 92 | systemd.services."pwm-fan" = { 93 | description = "PWM fan control"; 94 | wantedBy = [ "basic.target" ]; 95 | after = [ "-.mount" ]; 96 | path = [ pkgs.coreutils ]; 97 | 98 | serviceConfig = { 99 | Type = "oneshot"; 100 | RemainAfterExit = true; 101 | Restart = "on-failure"; 102 | }; 103 | 104 | script = '' 105 | cd /sys/class/pwm/pwmchip4 106 | [[ -d pwm2 ]] || echo 2 >export 107 | cd pwm2 108 | echo 0 >duty_cycle || true 109 | echo 10000000 >period 110 | echo 800000 >duty_cycle 111 | echo 1 >enable 112 | ''; 113 | 114 | preStop = '' 115 | cd /sys/class/pwm/pwmchip4 116 | [[ ! -d pwm2 ]] || echo 0 >pwm2/enable 117 | ''; 118 | }; 119 | 120 | documentation.nixos.enable = false; 121 | services.udisks2.enable = false; 122 | security.polkit.enable = false; 123 | 124 | services.getty.autologinUser = "root"; 125 | services.openssh.enable = true; 126 | 127 | environment.systemPackages = with pkgs; [ 128 | neofetch 129 | lm_sensors 130 | pciutils 131 | htop 132 | git 133 | lsof 134 | btrfs-progs 135 | tmux 136 | ]; 137 | 138 | hardware.firmware = with pkgs; [ firmwareLinuxNonfree ]; 139 | # hardware.opengl.enable = true; 140 | # programs.sway.enable = true; 141 | 142 | i18n.supportedLocales = lib.mkDefault [ "en_US.UTF-8/UTF-8" ]; 143 | i18n.defaultLocale = lib.mkDefault "en_US.UTF-8"; 144 | fonts.fontconfig.enable = false; 145 | programs.command-not-found.enable = false; 146 | 147 | # Don't use vim_configurable. 148 | programs.vim = { 149 | enable = true; 150 | defaultEditor = true; 151 | }; 152 | 153 | nix = { 154 | extraOptions = '' 155 | experimental-features = nix-command flakes 156 | keep-outputs = true # Keep build-dependencies. 157 | flake-registry = /etc/nix/registry.json 158 | ''; 159 | 160 | registry = { 161 | nixpkgs = { 162 | from = { id = "nixpkgs"; type = "indirect"; }; 163 | flake = inputs.nixpkgs-unmatched; 164 | }; 165 | }; 166 | 167 | binaryCaches = lib.mkBefore [ 168 | "https://riscv64.cachix.org" 169 | ]; 170 | }; 171 | 172 | users = { 173 | mutableUsers = false; 174 | users.root.openssh.authorizedKeys.keys = with my.ssh.identities; [ oxa invar blacksteel ]; 175 | }; 176 | } 177 | -------------------------------------------------------------------------------- /pkgs/_sources/generated.json: -------------------------------------------------------------------------------- 1 | { 2 | "colors": { 3 | "cargoLocks": null, 4 | "date": null, 5 | "extract": null, 6 | "name": "colors", 7 | "passthru": null, 8 | "pinned": false, 9 | "src": { 10 | "name": null, 11 | "sha256": "sha256-l/RTPZp2v7Y4ffJRT5Fy5Z3TDB4dvWfE7wqMbquXdJA=", 12 | "type": "url", 13 | "url": "https://gist.githubusercontent.com/lilydjwg/fdeaf79e921c2f413f44b6f613f6ad53/raw/94d8b2be62657e96488038b0e547e3009ed87d40/colors.py" 14 | }, 15 | "version": "94d8b2be62657e96488038b0e547e3009ed87d40" 16 | }, 17 | "rime_latex": { 18 | "cargoLocks": null, 19 | "date": "2025-04-03", 20 | "extract": null, 21 | "name": "rime_latex", 22 | "passthru": null, 23 | "pinned": false, 24 | "src": { 25 | "deepClone": false, 26 | "fetchSubmodules": false, 27 | "leaveDotGit": false, 28 | "name": null, 29 | "owner": "shenlebantongying", 30 | "repo": "rime_latex", 31 | "rev": "858f2abc645f0e459e468e98122470ce20b16b30", 32 | "sha256": "sha256-i8Rgze+tQhbE+nl+JSj09ILXeUvf6MOS9Eqsuqis1n0=", 33 | "sparseCheckout": [], 34 | "type": "github" 35 | }, 36 | "version": "858f2abc645f0e459e468e98122470ce20b16b30" 37 | } 38 | } -------------------------------------------------------------------------------- /pkgs/_sources/generated.nix: -------------------------------------------------------------------------------- 1 | # This file was generated by nvfetcher, please do not modify it manually. 2 | { fetchgit, fetchurl, fetchFromGitHub, dockerTools }: 3 | { 4 | colors = { 5 | pname = "colors"; 6 | version = "94d8b2be62657e96488038b0e547e3009ed87d40"; 7 | src = fetchurl { 8 | url = "https://gist.githubusercontent.com/lilydjwg/fdeaf79e921c2f413f44b6f613f6ad53/raw/94d8b2be62657e96488038b0e547e3009ed87d40/colors.py"; 9 | sha256 = "sha256-l/RTPZp2v7Y4ffJRT5Fy5Z3TDB4dvWfE7wqMbquXdJA="; 10 | }; 11 | }; 12 | rime_latex = { 13 | pname = "rime_latex"; 14 | version = "858f2abc645f0e459e468e98122470ce20b16b30"; 15 | src = fetchFromGitHub { 16 | owner = "shenlebantongying"; 17 | repo = "rime_latex"; 18 | rev = "858f2abc645f0e459e468e98122470ce20b16b30"; 19 | fetchSubmodules = false; 20 | sha256 = "sha256-i8Rgze+tQhbE+nl+JSj09ILXeUvf6MOS9Eqsuqis1n0="; 21 | }; 22 | date = "2025-04-03"; 23 | }; 24 | } 25 | -------------------------------------------------------------------------------- /pkgs/caddy-oxa/0001-caddyauth-use-same-cost-for-users-and-fake-hash.patch: -------------------------------------------------------------------------------- 1 | From ffce3249f373dfc7f25b45cb99b3e7902df4dfcd Mon Sep 17 00:00:00 2001 2 | From: oxalica 3 | Date: Thu, 29 Aug 2024 12:55:30 -0400 4 | Subject: [PATCH] caddyauth: use same cost for users and fake hash 5 | 6 | This prevents timing attack when user provided hash is different than 7 | the fake hash. 8 | --- 9 | modules/caddyhttp/caddyauth/basicauth.go | 32 +++++++++++++++++++----- 10 | modules/caddyhttp/caddyauth/hashes.go | 6 ++--- 11 | 2 files changed, 28 insertions(+), 10 deletions(-) 12 | 13 | diff --git a/modules/caddyhttp/caddyauth/basicauth.go b/modules/caddyhttp/caddyauth/basicauth.go 14 | index 52a5a08c..8438c416 100644 15 | --- a/modules/caddyhttp/caddyauth/basicauth.go 16 | +++ b/modules/caddyhttp/caddyauth/basicauth.go 17 | @@ -24,6 +24,7 @@ import ( 18 | "strings" 19 | "sync" 20 | 21 | + "golang.org/x/crypto/bcrypt" 22 | "golang.org/x/sync/singleflight" 23 | 24 | "github.com/caddyserver/caddy/v2" 25 | @@ -92,15 +93,11 @@ func (hba *HTTPBasicAuth) Provision(ctx caddy.Context) error { 26 | return fmt.Errorf("hash is required") 27 | } 28 | 29 | - // if supported, generate a fake password we can compare against if needed 30 | - if hasher, ok := hba.Hash.(Hasher); ok { 31 | - hba.fakePassword = hasher.FakeHash() 32 | - } 33 | - 34 | repl := caddy.NewReplacer() 35 | 36 | // load account list 37 | hba.Accounts = make(map[string]Account) 38 | + hashCost := 0 39 | for i, acct := range hba.AccountList { 40 | if _, ok := hba.Accounts[acct.Username]; ok { 41 | return fmt.Errorf("account %d: username is not unique: %s", i, acct.Username) 42 | @@ -126,10 +123,33 @@ func (hba *HTTPBasicAuth) Provision(ctx caddy.Context) error { 43 | } 44 | } 45 | 46 | + // FIXME: Only support bcrypt here. 47 | + curHashCost, err := bcrypt.Cost(acct.password) 48 | + if err != nil { 49 | + return fmt.Errorf("account %d: invalid bcrypt hash, must be a bcrypt-2a hash"); 50 | + } 51 | + if hashCost != 0 && hashCost != curHashCost { 52 | + return fmt.Errorf("account %d: all bcrypt cost must be the same"); 53 | + } 54 | + hashCost = curHashCost 55 | + 56 | hba.Accounts[acct.Username] = acct 57 | } 58 | hba.AccountList = nil // allow GC to deallocate 59 | 60 | + if hashCost == 0 { 61 | + // FIXME: Hardcoded default cost. 62 | + hashCost = 14; 63 | + } 64 | + 65 | + // if supported, generate a fake password we can compare against if needed 66 | + if hasher, ok := hba.Hash.(Hasher); ok { 67 | + hba.fakePassword, err = hasher.FakeHash(hashCost) 68 | + if err != nil { 69 | + return fmt.Errorf("failed to generate fake hash"); 70 | + } 71 | + } 72 | + 73 | if hba.HashCache != nil { 74 | hba.HashCache.cache = make(map[string]bool) 75 | hba.HashCache.mu = new(sync.RWMutex) 76 | @@ -280,7 +300,7 @@ type Comparer interface { 77 | // can be used for timing side-channel mitigation. 78 | type Hasher interface { 79 | Hash(plaintext []byte) ([]byte, error) 80 | - FakeHash() []byte 81 | + FakeHash(cost int) ([]byte, error) 82 | } 83 | 84 | // Account contains a username and password. 85 | diff --git a/modules/caddyhttp/caddyauth/hashes.go b/modules/caddyhttp/caddyauth/hashes.go 86 | index ce3df901..c02f5f27 100644 87 | --- a/modules/caddyhttp/caddyauth/hashes.go 88 | +++ b/modules/caddyhttp/caddyauth/hashes.go 89 | @@ -53,10 +53,8 @@ func (BcryptHash) Hash(plaintext []byte) ([]byte, error) { 90 | } 91 | 92 | // FakeHash returns a fake hash. 93 | -func (BcryptHash) FakeHash() []byte { 94 | - // hashed with the following command: 95 | - // caddy hash-password --plaintext "antitiming" --algorithm "bcrypt" 96 | - return []byte("$2a$14$X3ulqf/iGxnf1k6oMZ.RZeJUoqI9PX2PM4rS5lkIKJXduLGXGPrt6") 97 | +func (BcryptHash) FakeHash(cost int) ([]byte, error) { 98 | + return bcrypt.GenerateFromPassword([]byte("antitiming"), cost) 99 | } 100 | 101 | // Interface guards 102 | -- 103 | 2.47.0 104 | 105 | -------------------------------------------------------------------------------- /pkgs/caddy-oxa/default.nix: -------------------------------------------------------------------------------- 1 | { 2 | lib, 3 | caddy, 4 | }: 5 | let 6 | caddy' = caddy.withPlugins { 7 | plugins = [ 8 | "github.com/mholt/caddy-webdav@v0.0.0-20241008162340-42168ba04c9d" 9 | ]; 10 | hash = "sha256-fURqPgMpZ17ubhvr+JmY8jBgDaKBb654wo9Z4izjlro="; 11 | }; 12 | 13 | caddy'' = caddy'.overrideAttrs (old: { 14 | # NB. Overriding `version` will break the build. Because it seems to be 15 | # popular to use `finalAttrs.version` in build steps. Sad. 16 | pname = old.pname + "-oxa"; 17 | prePatch = "pushd vendor/github.com/caddyserver/caddy/v2"; 18 | patches = 19 | assert old.patches or [ ] == [ ]; 20 | [ 21 | ./0001-caddyauth-use-same-cost-for-users-and-fake-hash.patch 22 | ]; 23 | postPatch = "popd"; 24 | }); 25 | 26 | in 27 | caddy'' 28 | -------------------------------------------------------------------------------- /pkgs/cargo-machete-no-spam.nix: -------------------------------------------------------------------------------- 1 | { cargo-machete, fetchpatch }: 2 | cargo-machete.overrideAttrs (old: { 3 | patches = old.patches or [ ] ++ [ 4 | # https://github.com/bnjbvr/cargo-machete/pull/134 5 | (fetchpatch { 6 | url = "https://github.com/oxalica/cargo-machete/commit/c70efceea0ee894c692da1e443da5da15703e609.patch"; 7 | hash = "sha256-q7Pd0MTQTs6h1hlyt2l1WwKadKpphXNVnGByQutoTq8="; 8 | excludes = [ "CHANGELOG.md" ]; 9 | }) 10 | ]; 11 | }) 12 | -------------------------------------------------------------------------------- /pkgs/coc-rust-analyzer-fix-snippet/default.nix: -------------------------------------------------------------------------------- 1 | # See: https://github.com/fannheyward/coc-rust-analyzer/issues/1279 2 | { 3 | lib, 4 | fetchFromGitHub, 5 | buildNpmPackage, 6 | vimPlugins, 7 | }: 8 | let 9 | nodePkg = buildNpmPackage rec { 10 | pname = "coc-rust-analyzer"; 11 | version = "0-unstable-2025-01-20"; 12 | 13 | src = fetchFromGitHub { 14 | owner = "fannheyward"; 15 | repo = pname; 16 | rev = "a4d6aa3a5d7fcf9e701a687f5a6953067ab55cb7"; 17 | hash = "sha256-/890Ns1LFc/OVN4ZxYf9Kr8etXooeK2YUZW1DdV/mrw="; 18 | }; 19 | npmDepsHash = "sha256-lowD4iS/5moizMHe9cFqX2h/2eAx2RIL/LaTq+IduvU="; 20 | 21 | meta.license = lib.licenses.mit; 22 | }; 23 | 24 | vimPkg = vimPlugins.coc-rust-analyzer.overrideAttrs { 25 | src = "${nodePkg}/lib/node_modules/coc-rust-analyzer"; 26 | }; 27 | 28 | in 29 | vimPkg 30 | -------------------------------------------------------------------------------- /pkgs/colors.nix: -------------------------------------------------------------------------------- 1 | { source, runCommand, python3 }: 2 | runCommand source.pname { 3 | inherit (source) src; 4 | nativeBuildInputs = [ python3 ]; 5 | } '' 6 | install -Dm555 $src $out/bin/colors 7 | patchShebangs $out/bin 8 | '' 9 | -------------------------------------------------------------------------------- /pkgs/default.nix: -------------------------------------------------------------------------------- 1 | { lib, pkgs, inputs }: 2 | let 3 | inherit (builtins) readDir; 4 | inherit (lib) mapAttrs' filterAttrs; 5 | 6 | sources = pkgs.callPackage ./_sources/generated.nix { }; 7 | entries = removeAttrs (readDir ./.) [ "_sources" "default.nix" "nvfetcher.toml" ]; 8 | 9 | self = mapAttrs' (file: _: rec { 10 | name = lib.removeSuffix ".nix" file; 11 | value = pkgs.newScope (self // { 12 | inherit inputs; 13 | source = sources.${name} or null; 14 | }) ./${file} { }; 15 | }) entries; 16 | in 17 | # Remove unsupported or broken packages. 18 | filterAttrs 19 | (name: drv: drv ? meta.platforms -> lib.meta.availableOn pkgs.hostPlatform drv) 20 | self 21 | -------------------------------------------------------------------------------- /pkgs/keystat/default.nix: -------------------------------------------------------------------------------- 1 | { writeTextFile, python3, showmethekey }: 2 | writeTextFile { 3 | name = "keystat"; 4 | destination = "/lib/systemd/system/keystat.service"; 5 | text = '' 6 | [Unit] 7 | Description=Keyboard statistics 8 | 9 | [Service] 10 | Type=exec 11 | ExecStart=${python3}/bin/python ${./keystat.py} ${showmethekey}/bin/showmethekey-cli 12 | DeviceAllow=char-input rw 13 | StateDirectory=keystat 14 | StateDirectoryMode=0700 15 | 16 | IPAddressDeny=any 17 | LockPersonality=yes 18 | MemoryDenyWriteExecute=yes 19 | NoNewPrivileges=yes 20 | PrivateMounts=yes 21 | ProtectClock=yes 22 | ProtectHostname=yes 23 | RestrictAddressFamilies=AF_UNIX AF_NETLINK AF_INET AF_INET6 24 | RestrictRealtime=yes 25 | RestrictSUIDSGID=yes 26 | SystemCallArchitectures=native 27 | SystemCallErrorNumber=EPERM 28 | SystemCallFilter=@system-service 29 | 30 | [Install] 31 | WantedBy=multi-user.target 32 | ''; 33 | } 34 | -------------------------------------------------------------------------------- /pkgs/keystat/keystat.py: -------------------------------------------------------------------------------- 1 | from pathlib import Path 2 | import datetime 3 | import json 4 | import os 5 | import subprocess 6 | import sys 7 | 8 | PERIOD = 256 9 | LOG_FILE = Path(os.environ['STATE_DIRECTORY']) / str(datetime.datetime.now()) 10 | KEYLOGGER_PATH = sys.argv[1] 11 | 12 | keyMap = { 'TOTAL': 0 } 13 | 14 | with subprocess.Popen(KEYLOGGER_PATH, text=True, stdout=subprocess.PIPE) as pipe: 15 | for line in pipe.stdout: 16 | record = json.loads(line) 17 | if record['state_name'] != 'PRESSED': 18 | continue 19 | key = f"{record['event_name']}-{record['key_name']}" 20 | keyMap[key] = keyMap.get(key, 0) + 1 21 | keyMap['TOTAL'] += 1 22 | 23 | if keyMap['TOTAL'] % PERIOD == 1: 24 | tmpFile = LOG_FILE.with_suffix('.tmp'); 25 | tmpFile.write_text(''.join(f'{k} {n}\n' for k, n in keyMap.items())) 26 | tmpFile.rename(LOG_FILE) 27 | 28 | print('Broken pipe', file=sys.stderr) 29 | exit(1) 30 | -------------------------------------------------------------------------------- /pkgs/nixos-rebuild-shortcut/default.nix: -------------------------------------------------------------------------------- 1 | { 2 | lib, 3 | stdenv, 4 | runCommand, 5 | runtimeShell, 6 | hostname, 7 | coreutils, 8 | nixos-rebuild-ng, 9 | git, 10 | nix, 11 | nix-output-monitor, 12 | ... 13 | }: 14 | runCommand "nixos-rebuild-shortcut" 15 | { 16 | preferLocalBuild = true; 17 | allowSubstitutes = false; 18 | 19 | inherit runtimeShell; 20 | paths = lib.escapeShellArg ( 21 | lib.makeBinPath [ 22 | coreutils 23 | git 24 | hostname 25 | nix 26 | nix-output-monitor 27 | nixos-rebuild-ng 28 | ] 29 | ); 30 | } 31 | '' 32 | mkdir -p $out/bin 33 | substituteAll ${./nixos.sh} $out/bin/nixos 34 | chmod +x $out/bin/nixos 35 | ${stdenv.shellDryRun} $out/bin/nixos 36 | '' 37 | -------------------------------------------------------------------------------- /pkgs/nixos-rebuild-shortcut/nixos.sh: -------------------------------------------------------------------------------- 1 | #!@runtimeShell@ 2 | set -eo pipefail 3 | export PATH="$PATH${PATH:+:}"@paths@ 4 | 5 | localname="$(hostname)" 6 | name="$localname" 7 | action=build 8 | if [[ "${1-}" == @* ]]; then 9 | name="${1:1}" 10 | shift 11 | fi 12 | if [[ "${1-}" = [^-]* ]]; then 13 | action="$1" 14 | shift 15 | fi 16 | 17 | # Simple local build. 18 | if [[ "$action" == build && "$name" == "$localname" ]]; then 19 | set -x 20 | exec nom build .#nixosSystems."$name" "$@" --keep-going 21 | fi 22 | 23 | if [[ "$action" =~ (boot|switch|test) && "$name" == "$localname" && "$(id -u)" != 0 ]]; then 24 | echo "'$action' expects root permission" >&2 25 | exit 1 26 | fi 27 | 28 | cmd=(nixos-rebuild "$action" --flake ".#$name" --keep-going) 29 | if [[ "$name" != "$localname" && "$action" != *build* ]]; then 30 | cmd+=( 31 | --use-remote-sudo 32 | --target-host "$name" 33 | ) 34 | fi 35 | 36 | cmd+=("$@") 37 | 38 | echo "+ ${cmd[*]}" 39 | "${cmd[@]}" 40 | 41 | newVer="$(nix eval ".#nixosConfigurations.$name.config.system.build.kernel.version" --raw)" 42 | curVer="$(uname --kernel-release)" 43 | if [[ "$newVer" != "$curVer" ]]; then 44 | echo -e "\e[32;1mnote\e[0m: built kernel $newVer is different than the current $curVer" 45 | fi 46 | -------------------------------------------------------------------------------- /pkgs/nvfetcher.toml: -------------------------------------------------------------------------------- 1 | [colors] 2 | src.manual = "94d8b2be62657e96488038b0e547e3009ed87d40" 3 | fetch.url = "https://gist.githubusercontent.com/lilydjwg/fdeaf79e921c2f413f44b6f613f6ad53/raw/$ver/colors.py" 4 | 5 | [rime_latex] 6 | src.git = "https://github.com/shenlebantongying/rime_latex" 7 | fetch.github = "shenlebantongying/rime_latex" 8 | -------------------------------------------------------------------------------- /pkgs/prismlauncher-bwrap.nix: -------------------------------------------------------------------------------- 1 | { 2 | bubblewrap, 3 | jdk17, 4 | jdk21, 5 | jdk8, 6 | kdePackages, 7 | makeWrapper, 8 | prismlauncher, 9 | prismlauncher-unwrapped, 10 | runCommandLocal, 11 | stdenv, 12 | 13 | additionalLibs ? [ ], 14 | additionalPrograms ? [ ], 15 | controllerSupport ? stdenv.hostPlatform.isLinux, 16 | gamemodeSupport ? stdenv.hostPlatform.isLinux, 17 | jdks ? [ 18 | jdk21 19 | jdk17 20 | jdk8 21 | ], 22 | msaClientID ? null, 23 | textToSpeechSupport ? stdenv.hostPlatform.isLinux, 24 | }: 25 | let 26 | prismlauncher-unwrapped' = prismlauncher-unwrapped.override { 27 | inherit msaClientID gamemodeSupport; 28 | }; 29 | 30 | prismlauncher' = prismlauncher.override { 31 | prismlauncher-unwrapped = prismlauncher-unwrapped'; 32 | 33 | inherit 34 | additionalLibs 35 | additionalPrograms 36 | controllerSupport 37 | gamemodeSupport 38 | jdks 39 | msaClientID 40 | textToSpeechSupport 41 | ; 42 | }; 43 | 44 | # Passthrough 45 | # Ref: https://github.com/NixOS/nixpkgs/blob/5e871d8aa6f57cc8e0dc087d1c5013f6e212b4ce/pkgs/build-support/build-fhsenv-bubblewrap/default.nix#L170 46 | wrapperPreExec = '' 47 | args=() 48 | if [[ "$DISPLAY" == :* ]]; then 49 | local_socket="/tmp/.X11-unix/X''${DISPLAY#?}" 50 | args+=(--ro-bind-try "$local_socket" "$local_socket") 51 | fi 52 | if [[ -n "$XAUTHORITY" ]]; then 53 | args+=(--ro-bind-try "$XAUTHORITY" "$XAUTHORITY") 54 | fi 55 | if [[ "$WAYLAND_DISPLAY" = /* ]]; then 56 | args+=(--ro-bind-try "$WAYLAND_DISPLAY" "$WAYLAND_DISPLAY") 57 | elif [[ -n "$WAYLAND_DISPLAY" ]]; then 58 | args+=(--ro-bind-try "$XDG_RUNTIME_DIR/$WAYLAND_DISPLAY" "/tmp/$WAYLAND_DISPLAY") 59 | fi 60 | ''; 61 | 62 | bwrapArgs = [ 63 | "--unshare-user" 64 | "--unshare-ipc" 65 | "--unshare-pid" 66 | "--unshare-uts" 67 | "--unshare-cgroup" 68 | "--die-with-parent" 69 | 70 | "--dev /dev" 71 | "--proc /proc" 72 | "--ro-bind /nix /nix" 73 | "--ro-bind /etc /etc" 74 | "--ro-bind /var /var" # Required for some symlinks under `/etc`, eg. `/etc/machine-id`. 75 | "--tmpfs /tmp" 76 | 77 | # Network is required. 78 | "--share-net" 79 | "--ro-bind /run/systemd/resolve /run/systemd/resolve" 80 | 81 | # Mesa & OpenGL. 82 | "--ro-bind /run/opengl-driver /run/opengl-driver" 83 | "--dev-bind-try /dev/dri /dev/dri" 84 | "--ro-bind-try /sys/class /sys/class" 85 | "--ro-bind-try /sys/dev/char /sys/dev/char" 86 | "--ro-bind-try /sys/devices/pci0000:00 /sys/devices/pci0000:00" 87 | "--ro-bind-try /sys/devices/system/cpu /sys/devices/system/cpu" 88 | 89 | # Audio. 90 | "--setenv XDG_RUNTIME_DIR /tmp" 91 | ''--ro-bind-try "$XDG_RUNTIME_DIR/pulse" /tmp/pulse'' 92 | ''--ro-bind-try "$XDG_RUNTIME_DIR/pipewire-0" /tmp/pipewire-0'' 93 | 94 | # Runtime args from `wrapperPreExec`. 95 | ''"''${args[@]}"'' 96 | 97 | # Data storage. 98 | ''--bind "''${XDG_DATA_HOME:+$HOME/.local/share}/PrismLauncher" $HOME/.local/share/PrismLauncher'' 99 | "--unsetenv XDG_DATA_HOME" 100 | 101 | # Block dangerous D-Bus. 102 | "--unsetenv DBUS_SESSION_BUS_ADDRESS" 103 | 104 | "--" 105 | "${prismlauncher-unwrapped'}/bin/prismlauncher" 106 | ]; 107 | 108 | in 109 | runCommandLocal "prismlauncher-bwrap-${prismlauncher-unwrapped'.version}" 110 | { 111 | nativeBuildInputs = [ 112 | kdePackages.wrapQtAppsHook 113 | 114 | # Force to use the shell wrapper instead of the binary wrapper. We have scripts. 115 | makeWrapper 116 | ]; 117 | 118 | inherit wrapperPreExec bwrapArgs; 119 | inherit (prismlauncher') buildInputs qtWrapperArgs; 120 | 121 | inherit (prismlauncher-unwrapped') meta; 122 | } 123 | '' 124 | qtWrapperArgs+=(--run "$wrapperPreExec" --add-flags "$bwrapArgs") 125 | makeQtWrapper ${bubblewrap}/bin/bwrap $out/bin/prismlauncher 126 | ln -s ${prismlauncher-unwrapped'}/share $out/share 127 | '' 128 | -------------------------------------------------------------------------------- /pkgs/rime_latex.nix: -------------------------------------------------------------------------------- 1 | { lib, source, runCommand }: 2 | runCommand "rime_latex" { 3 | inherit (source) version src; 4 | meta.license = with lib.licenses; [ gpl3Only ]; 5 | } '' 6 | install -Dm444 -t $out/share/rime-data $src/latex.{dict,schema}.yaml 7 | '' 8 | -------------------------------------------------------------------------------- /pkgs/show-headless-desktop.nix: -------------------------------------------------------------------------------- 1 | { lib, makeDesktopItem, wl-mirror }: 2 | makeDesktopItem { 3 | name = "show-headless1"; 4 | desktopName = "Show Headless Output 1"; 5 | comment = "Show content of headless output HEADLESS-1"; 6 | exec = "${lib.getBin wl-mirror}/bin/wl-mirror HEADLESS-1"; 7 | categories = [ "Utility" ]; 8 | } 9 | -------------------------------------------------------------------------------- /pkgs/systemd-run-app.nix: -------------------------------------------------------------------------------- 1 | # From https://github.com/NickCao/flakes/blob/67fac11e53d6ee0ff27a90fcaf9cab2e59a935a6/pkgs/systemd-run-app/default.nix 2 | { writeShellApplication, coreutils }: 3 | writeShellApplication { 4 | name = "systemd-run-app"; 5 | text = '' 6 | name="$(/run/current-system/systemd/bin/systemd-escape "$(${coreutils}/bin/basename "$1")")" 7 | unit="app-$name-$(printf %04x $RANDOM)" 8 | exec /run/current-system/systemd/bin/systemd-run \ 9 | --user \ 10 | --scope \ 11 | --unit="$unit" \ 12 | --slice=app \ 13 | --same-dir \ 14 | --collect \ 15 | --property PartOf=graphical-session.target \ 16 | --property After=graphical-session.target \ 17 | -- \ 18 | /run/current-system/systemd/bin/systemd-cat \ 19 | --identifier="$unit" \ 20 | -- \ 21 | "$@" 22 | ''; 23 | } 24 | -------------------------------------------------------------------------------- /pkgs/urw-base35-fonts.nix: -------------------------------------------------------------------------------- 1 | { lib, stdenvNoCC, fetchFromGitHub }: 2 | 3 | stdenvNoCC.mkDerivation { 4 | pname = "urw-base35-fonts"; 5 | version = "2020-09-10"; 6 | 7 | src = fetchFromGitHub { 8 | owner = "ArtifexSoftware"; 9 | repo = "urw-base35-fonts"; 10 | rev = "20200910"; 11 | hash = "sha256-YQl5IDtodcbTV3D6vtJi7CwxVtHHl58fG6qCAoSaP4U="; 12 | }; 13 | 14 | installPhase = '' 15 | runHook preInstall 16 | install -Dm644 -t $out/share/fonts/urw-base35-fonts fonts/*.{afm,otf,t1,ttf} 17 | runHook postInstall 18 | ''; 19 | 20 | meta = with lib; { 21 | description = "URW++ base 35 font set"; 22 | homepage = "https://github.com/ArtifexSoftware/urw-base35-fonts"; 23 | license = licenses.agpl3Only; 24 | maintainers = [ ]; 25 | platforms = platforms.all; 26 | }; 27 | } 28 | 29 | -------------------------------------------------------------------------------- /pkgs/wallpaper-blur.nix: -------------------------------------------------------------------------------- 1 | { runCommand, wallpaper, imagemagick }: 2 | runCommand "wallpaper-blur.jpg" { } '' 3 | ${imagemagick}/bin/convert -blur 14x5 ${wallpaper} $out 4 | '' 5 | -------------------------------------------------------------------------------- /pkgs/wallpaper.nix: -------------------------------------------------------------------------------- 1 | { fetchurl }: 2 | fetchurl { 3 | name = "wallpaper.jpg"; 4 | url = "https://pbs.twimg.com/media/E9irhxhVUAUaBCr?format=jpg"; 5 | hash = "sha256-Rhjj1K0FXKGzKswoLj1H0Yi/QHswzPcGW6aLMiekURA="; 6 | } 7 | -------------------------------------------------------------------------------- /pkgs/zsh-comma.nix: -------------------------------------------------------------------------------- 1 | # Ref: https://github.com/dramforever/config/blob/4ffe106a05cf38b5f776e0b7421efef0cdb80816/home/nixenv.zsh 2 | { lib, runCommandLocal, nix }: 3 | runCommandLocal "zsh-comma" { 4 | plugin = '' 5 | typeset -g -a comma_paths 6 | 7 | ,() { 8 | setopt local_options err_return pipefail 9 | if [[ $# = 0 ]]; then 10 | printf "%s\n" $comma_paths 11 | return 12 | fi 13 | local -a ps 14 | ps=( $(nix build --json --no-link $@ | jq -r '.[].outputs[]') ) 15 | ps=($^ps/bin) 16 | comma_paths+=($ps) 17 | path=($ps $path) 18 | export PATH 19 | printf "+%s paths, total %s paths\n" ''${#ps} ''${#comma_paths} 20 | } 21 | 22 | ,,() { 23 | path=(''${path:|comma_paths}) 24 | comma_paths=() 25 | export PATH 26 | } 27 | ''; 28 | 29 | completion = '' 30 | #compdef , 31 | _,() { 32 | words[1]=(nix build) 33 | CURRENT+=1 34 | _nix 35 | } 36 | ''; 37 | 38 | propagatedBuildInputs = [ nix.out ]; # Completion. 39 | 40 | meta.license = lib.licenses.mit; 41 | 42 | } '' 43 | mkdir -p $out/share/zsh/{comma,site-functions} 44 | cat <<<"$plugin" >$out/share/zsh/comma/comma.zsh 45 | cat <<<"$completion" >$out/share/zsh/site-functions/_, 46 | '' 47 | -------------------------------------------------------------------------------- /secrets/ssh.yaml: -------------------------------------------------------------------------------- 1 | ssh-hosts: ENC[AES256_GCM,data:RvwsG6aIJOfNKc66vU6d++WySVOdWiK0dC9XLCNJQPoAq9rHJZSv5KV6efVOojoIDtL58tLgwEoV8xSRmgaHccHC8hnSZH3gJJeHmVx6rMGBHx/GR7ExkbXOShgxWagC92wHz2t0KHJFOFHgyWOGKKHcdJHMBCCzAyCQMuhxWl/hjejVcNRP5BY/mrbNVkUBpOuQ7p/d5lx38f8WRvAnxFY8Dmy5B0j6jsql1p9adk4xPoN0hFIgYRGXMACfpfa4DZvDHP4yq48WY1qSek3vkJ76VOwoMRbNucnuIgKz1rAY2hgff8VS5mCV7+2aWwUy093sCPEwK4tWqzz1ZeVmlpJNpQi1kV1u5cRNopjQi+oyii3ImhkPBjMgV5a21wUYvXD/1x9za1OZ+zCl+u3PnzsTDa/zA58OpxM7d8a4rd8BobKDCvx8Q7PZmDBR95Le2T9ZcP5IS8lxkBUmzdIJeROfDXh6N1MiMCC0rZTj/mqkJekxhvoUu7nc1CDyGngdcHAkOklU/Yi3SV0RJVvVYKuezRNx2C2b1l2GMSZ2QjqBXY4ElBiLVOw7yQxzqgxcot7zDjBS3jsP+2y6N3qOA0A+Rp8K7v5cTIGO6EvwHODOBildpgNA9F0CCG1scodc/7cF2DArxKjNRbxgUFDfedcCYhKsfFu8SZzvIUWfST5P5hJcVIi5DwfeaXzbBWConRnufv+hALpXtyTRjD0oe8VAzrQY1ZenPkhczkoFaT2KLjKskWAd2/g3JlscRTOXavVQMKhG/nVn3zcIWx99YcfYb65no/WF98Id7FmPVPXHX+Z5KfCdY8oenSP3U+plRQ==,iv:uXOtFKLAaI4JP2DO4y04ZQeCjXWPAq7EN3YPuTKigPo=,tag:4UqFDDuX1xV2yFbmTf9PNA==,type:str] 2 | sops: 3 | kms: [] 4 | gcp_kms: [] 5 | azure_kv: [] 6 | hc_vault: [] 7 | age: 8 | - recipient: age157zcs4687hmsd834xhvt66apf6v93ss3tt2l23x72lhtvpl69ggqeejgky 9 | enc: | 10 | -----BEGIN AGE ENCRYPTED FILE----- 11 | YWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSBHd2dyOUQyU1NwOXY2ZXJJ 12 | WlNUTkNYUE9oWE1nUFhVNlUxMWRkbW10ZENvCnhpb1pHVkVrY1hGYVo0UWhLU2hV 13 | OEZ1OElWeWFsYzRzLzFqMld2cXNkV2sKLS0tIFZJbFZjcEVab1ZrNTNwQ21rNVFw 14 | dXVaMVdxN2s2dENPNWt1b1cydmdvVjQKfoRukSwy28LjPmUvWY40j8ltljGdsixU 15 | OkMe+8dGvfpzbWkbiR9FsEJCKRFtNm9dW73XZ3SPhDga3FiVWobfPQ== 16 | -----END AGE ENCRYPTED FILE----- 17 | - recipient: age1l9qly5vlx20uzrqvq8qygvcrtff64mgvqchet5uvs989upy5lugq4krj2c 18 | enc: | 19 | -----BEGIN AGE ENCRYPTED FILE----- 20 | YWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSBkRk9LTDRKNmVEdVFuZHVn 21 | UTFvVW52ZkIwN3UxcUk2L1JsdEc3elpUeWljCjI1OVg3N3paSnVFSFZoOEI5STN3 22 | RW9kWU5kQXR6SGVYYllIQ1d3SEJRK3MKLS0tIEVyZkFGdmhaYjFPeDlCalFUOUFn 23 | TVd5dC9ienVsNWJwOUc0OUlCVnBYWU0KcP1Z09UvH4LsuB/+M3WGfl+Bn2cm0BKy 24 | l5DfKDCZP7g9W28ccTGBu/NqpfGpzI4H6uJpupjwMEQLi6onxOzAiQ== 25 | -----END AGE ENCRYPTED FILE----- 26 | - recipient: age14z6h0yqmuymga4kxtvc78tmpyjdt7vh72c6awml2dfxjzxch5cqqt374sn 27 | enc: | 28 | -----BEGIN AGE ENCRYPTED FILE----- 29 | YWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSA0d2x0M2luMUpNVUNlbWVC 30 | aWZDT2dHaTBXWEJSV2JLa1QwcUQxd3BBUWxVClcwajdhbVRJdER0WC9IcDVCbHlN 31 | K2JTRzlGaU0zUkZNYmk3Y3hhTEc5Y1UKLS0tIFN6NjdXQXJIYUlIckRrazllZUY0 32 | eFJEZ0JtMVljRy9vU1VMUXBpbEt2QUUK8eF/kdt3EHkkj7y0BVM7NnEg0dpQAzS4 33 | SOFmkuuC5wsbHpxTmcPII2g+6Yq1FB3W3Tto4BP+Xra4MJB8Q+dp+w== 34 | -----END AGE ENCRYPTED FILE----- 35 | lastmodified: "2021-12-20T17:59:16Z" 36 | mac: ENC[AES256_GCM,data:66Iv2AlokQTFMI0kTOMibfu61jnKQCkYXwaLKG2tjFlKBOhcFeb+Va7mZ0P3wV1JVZd7hBrzwcM81usaCLWff8MYFoOoW4oNOdtoWegsSK1hqlYvxSHDykGmj/XkoclIAFzDb+KC2qUdg2mGo5wwPT42h6g5d4e38KPUg9U7U+s=,iv:nff2BDRG0s4A49xePWupRzO6EQCSREP+Xmc6KHHMsjA=,tag:8s3f4sueC9gPhMW36YinpQ==,type:str] 37 | pgp: 38 | - created_at: "2023-04-02T15:38:38Z" 39 | enc: |- 40 | -----BEGIN PGP MESSAGE----- 41 | 42 | wV4Dhs332B8tbXUSAQdAKqs40mpEe/m/QN/igGHey4oKTxDx+NCm45X+dsGVgzsw 43 | ZKSoLKtXZEoWYxs3RyRXQyE8YjJHeUbhLa6VXsyPWtxhxuZKHuCKYVEg/JCNA6Zh 44 | 0lEB2KseM2PqnrSzT4lA43XtRpdNasSU4xn1CRW3+w+VmX6b48qe41zvF10V0Xve 45 | J8A3WaPh65jox7sDqbbo1n+S+LdyYCubNCCoYbJ7kCgiKsI= 46 | =Mj0K 47 | -----END PGP MESSAGE----- 48 | fp: F90FFD6D585C2BA1F13DE8A97571654CF88E31C2 49 | unencrypted_suffix: _unencrypted 50 | version: 3.7.1 51 | -------------------------------------------------------------------------------- /templates/ci-rust/.github/workflows/ci.yaml: -------------------------------------------------------------------------------- 1 | name: CI 2 | on: 3 | pull_request: 4 | push: 5 | schedule: 6 | - cron: '42 1 * * *' # *-*-* 01:42:00 UTC 7 | 8 | permissions: 9 | contents: read 10 | 11 | env: 12 | RUST_BACKTRACE: full 13 | RUSTFLAGS: -Dwarnings 14 | 15 | jobs: 16 | test: 17 | timeout-minutes: 45 18 | strategy: 19 | fail-fast: false 20 | matrix: 21 | rust: [nightly, beta, stable] 22 | os: [ubuntu-latest, macos-latest, windows-latest] 23 | name: Test ${{matrix.rust}} on ${{ matrix.os }} 24 | runs-on: ${{ matrix.os }} 25 | steps: 26 | - name: Checkout 27 | uses: actions/checkout@v3 28 | - name: Install Rust 29 | uses: dtolnay/rust-toolchain@master 30 | with: 31 | toolchain: ${{ matrix.rust }} 32 | - name: Build 33 | run: cargo build --all-targets 34 | - name: Test 35 | run: cargo test 36 | 37 | clippy: 38 | name: Clippy 39 | runs-on: ubuntu-latest 40 | timeout-minutes: 45 41 | steps: 42 | - name: Checkout 43 | uses: actions/checkout@v3 44 | - name: Install Clippy 45 | uses: dtolnay/rust-toolchain@clippy 46 | - name: Clippy 47 | run: cargo clippy --all-targets 48 | -------------------------------------------------------------------------------- /templates/ci-rust/.github/workflows/future_proof.yaml: -------------------------------------------------------------------------------- 1 | name: Future proof tests 2 | on: 3 | schedule: 4 | - cron: '42 1 * * 0' # Sun *-*-* 01:42:00 UTC 5 | 6 | permissions: 7 | contents: read 8 | 9 | env: 10 | RUST_BACKTRACE: full 11 | 12 | jobs: 13 | outdated: 14 | name: Outdated 15 | runs-on: ubuntu-latest 16 | steps: 17 | - name: Checkout 18 | uses: actions/checkout@v3 19 | - name: Install cargo-outdated 20 | uses: dtolnay/install@cargo-outdated 21 | - name: cargo-outdated 22 | run: | 23 | rm -f Cargo.lock # Ignore trivially updatable compatible versions. 24 | cargo outdated --workspace --exit-code 1 25 | -------------------------------------------------------------------------------- /templates/rust-bin/.gitignore: -------------------------------------------------------------------------------- 1 | /target 2 | result 3 | result-* 4 | Cargo.lock 5 | -------------------------------------------------------------------------------- /templates/rust-bin/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "___" 3 | version = "0.0.0" 4 | edition = "2021" 5 | 6 | [dependencies] 7 | -------------------------------------------------------------------------------- /templates/rust-bin/src/main.rs: -------------------------------------------------------------------------------- 1 | fn main() {} 2 | -------------------------------------------------------------------------------- /templates/rust-criterion/benches/foo.rs: -------------------------------------------------------------------------------- 1 | use criterion::{black_box, criterion_group, criterion_main, Criterion}; 2 | 3 | fn foo(c: &mut Criterion) { 4 | c.bench_function("foo", |b| { 5 | let init = 42; 6 | b.iter(|| black_box(init) * 42); 7 | }); 8 | } 9 | 10 | criterion_group!(benches, foo); 11 | criterion_main!(benches); 12 | -------------------------------------------------------------------------------- /templates/rust-lib/.gitignore: -------------------------------------------------------------------------------- 1 | /target 2 | result 3 | result-* 4 | -------------------------------------------------------------------------------- /templates/rust-lib/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "___" 3 | version = "0.0.0" 4 | edition = "2021" 5 | 6 | [dependencies] 7 | -------------------------------------------------------------------------------- /templates/rust-lib/src/lib.rs: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/oxalica/nixos-config/afdeef03a861eb98c1cbf18fd471967a6884f631/templates/rust-lib/src/lib.rs -------------------------------------------------------------------------------- /typos.toml: -------------------------------------------------------------------------------- 1 | [files] 2 | extend-exclude = [ 3 | "home/modules/nvim/vimrc.vim", 4 | "my/gpg-pubkey.asc", 5 | "secrets", 6 | ] 7 | 8 | [default.extend-words] 9 | lazer = "lazer" # osu-lazer 10 | thumbnailers = "thumbnailers" # kdegraphics-thumbnailers 11 | --------------------------------------------------------------------------------