├── .envrc ├── .git-blame-ignore-revs ├── .gitea └── workflows │ └── .do-not-run-github-actions ├── .github ├── flake-module.nix └── workflows │ ├── build.yml │ └── mirror.yml ├── .gitignore ├── CHANGELOG.md ├── README.md ├── files ├── commands.py ├── init.vim ├── post-checkout ├── powermenu ├── rc.conf └── zshrc ├── flake.lock ├── flake.nix ├── flake.systems.nix ├── hosts ├── eris │ ├── configuration.nix │ ├── hardware-configuration.nix │ └── home.nix ├── flake-module.nix ├── hyperion │ ├── darwin-configuration.nix │ └── home.nix ├── phi │ ├── configuration.nix │ ├── hardware-configuration.nix │ └── home.nix └── sigma │ ├── configuration.nix │ ├── hardware-configuration.nix │ ├── home.nix │ └── terraform-configuration.nix ├── keys.nix ├── lib.nix ├── modules ├── acme.nix ├── alacritty.nix ├── android.nix ├── avahi.nix ├── base.nix ├── bluetooth.nix ├── builder.nix ├── cache.nix ├── clan.nix ├── deluge.nix ├── docker.nix ├── firefox.nix ├── flake-parts │ ├── checks.nix │ ├── clan.nix │ ├── configurations.nix │ ├── devShells.nix │ ├── flake-module.nix │ ├── formatter.nix │ ├── lib.nix │ ├── terraform.nix │ └── vm.nix ├── flakes.nix ├── fonts.nix ├── gaming.nix ├── ghostty.nix ├── graphical-minimal.nix ├── graphical.nix ├── greetd.nix ├── i18n.nix ├── i3-sway.nix ├── i3.nix ├── impermanence.nix ├── ios.nix ├── laptop.nix ├── linux-builder.nix ├── macos-vm.nix ├── mpv.nix ├── mullvad.nix ├── nextcloud.nix ├── personal.nix ├── pim.nix ├── printers.nix ├── reflector.nix ├── samba.nix ├── scanners.nix ├── sops.nix ├── sway.nix ├── syncthing.nix ├── termite.nix ├── vcs.nix ├── virt-manager.nix ├── vm.nix ├── vncserver.nix ├── vscode.nix ├── wayvnc.nix ├── wireless.nix └── xdg.nix ├── overlays ├── docker-compose.nix ├── firefox-addons │ └── flake.nix ├── firefox.nix ├── gramps.nix ├── i3-ws.nix ├── karabiner-elements.nix ├── neovim.nix ├── nixos-rebuild.nix ├── powermenu.nix ├── ranger.nix ├── remmina.nix ├── spotify-tray.nix ├── spotify.nix ├── thunar.nix ├── vim-plugins.nix └── vscode-extensions.nix ├── secrets ├── acme_zoneee.age ├── nextcloud.age ├── password-hash_enzime-sigma.age ├── secrets.nix ├── wireless.age └── zshrc_phi.age └── shell.nix /.envrc: -------------------------------------------------------------------------------- 1 | # shellcheck shell=bash 2 | use nix 3 | -------------------------------------------------------------------------------- /.git-blame-ignore-revs: -------------------------------------------------------------------------------- 1 | # Run `nixfmt` on the entire repo 2 | a019033eaefb4bfc7dc169e0dd9fa059cc62393b 3 | -------------------------------------------------------------------------------- /.gitea/workflows/.do-not-run-github-actions: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Enzime/dotfiles-nix/bafeccb6ffdc353179680d6a0b4031809e6eba0e/.gitea/workflows/.do-not-run-github-actions -------------------------------------------------------------------------------- /.github/flake-module.nix: -------------------------------------------------------------------------------- 1 | { self, ... }: { 2 | perSystem = { pkgs, lib, ... }: { 3 | packages.github-actions-nix-config = pkgs.writeTextFile { 4 | name = "github-actions-nix.conf"; 5 | text = let 6 | cfg = self.nixosConfigurations.eris.config.nix.settings; 7 | substituters = 8 | lib.filter (value: !lib.hasInfix "clan.lol" value) cfg.substituters; 9 | in '' 10 | substituters = ${toString substituters} 11 | trusted-public-keys = ${toString cfg.trusted-public-keys} 12 | ''; 13 | }; 14 | }; 15 | } 16 | -------------------------------------------------------------------------------- /.github/workflows/build.yml: -------------------------------------------------------------------------------- 1 | on: 2 | push: 3 | 4 | jobs: 5 | build: 6 | timeout-minutes: 7200 7 | 8 | strategy: 9 | fail-fast: true 10 | matrix: 11 | include: 12 | - name: hyperion-macos 13 | output: darwinConfigurations.hyperion-macos.config.system.build.toplevel 14 | runs-on: macos-latest 15 | - name: phi-nixos 16 | output: nixosConfigurations.phi-nixos.config.system.build.toplevel 17 | runs-on: ubuntu-latest 18 | - name: sigma 19 | output: nixosConfigurations.sigma.config.system.build.toplevel 20 | runs-on: ubuntu-latest 21 | - name: eris 22 | output: nixosConfigurations.eris.config.system.build.toplevel 23 | runs-on: ubuntu-latest 24 | 25 | name: ${{ matrix.name }} 26 | runs-on: ${{ matrix.runs-on }} 27 | steps: 28 | - name: Free space on GitHub-hosted Runner 29 | if: runner.environment == 'github-hosted' 30 | run: | 31 | # 13.5GiB 32 | sudo rm -rf /usr/local/lib/android 33 | # 8.6GiB 34 | sudo rm -rf "$AGENT_TOOLSDIRECTORY" 35 | # 4.7GiB 36 | sudo rm -rf /usr/local/.ghcup 37 | - uses: actions/checkout@v4.1.7 38 | - uses: cachix/install-nix-action@v31.1.0 39 | with: 40 | install_url: https://releases.nixos.org/nix/nix-2.28.3/install 41 | github_access_token: ${{ secrets.GITHUB_TOKEN }} 42 | extra_nix_config: | 43 | !include /etc/nix/nix.conf.extra 44 | - name: Run nix build --print-build-logs .#github-actions-nix-config --out-link /etc/nix/nix.conf.extra 45 | if: runner.environment == 'github-hosted' 46 | run: | 47 | nix build --print-build-logs .#github-actions-nix-config --out-link nix.conf.extra 48 | sudo mv nix.conf.extra /etc/nix 49 | - if: runner.environment == 'github-hosted' && runner.os == 'macOS' 50 | run: sudo launchctl kickstart -k system/org.nixos.nix-daemon 51 | - uses: cachix/cachix-action@v16 52 | with: 53 | name: enzime 54 | useDaemon: ${{ runner.environment == 'github-hosted' }} 55 | signingKey: '${{ secrets.CACHIX_SIGNING_KEY }}' 56 | skipAddingSubstituter: true 57 | - run: nix build --print-build-logs .#${{ matrix.output }} 58 | -------------------------------------------------------------------------------- /.github/workflows/mirror.yml: -------------------------------------------------------------------------------- 1 | on: [push, delete] 2 | 3 | jobs: 4 | to_gitea: 5 | runs-on: ubuntu-latest 6 | steps: 7 | - uses: actions/checkout@v4.2.2 8 | with: 9 | fetch-depth: 0 10 | - uses: pixta-dev/repository-mirroring-action@674e65a7d483ca28dafaacba0d07351bdcc8bd75 11 | with: 12 | target_repo_url: 13 | gitea@git.clan.lol:Enzime/hyperconfig.git 14 | ssh_username: gitea 15 | ssh_private_key: 16 | ${{ secrets.GITEA_SSH_PRIVATE_KEY }} 17 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | .direnv 2 | result 3 | /.pre-commit-config.yaml 4 | config.tf.json 5 | .terraform* 6 | *.tfstate* 7 | *.qcow2 8 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | I use Nix to declaratively manage and configure all of my systems everywhere all at once 2 | 3 | ## Getting started 4 | 5 | Due to subflakes being broken in Nix, before you can use this repo you'll need to run: 6 | 7 | ``` 8 | $ nix-shell --pure -I nixpkgs=flake:nixpkgs -p '(import ./shell.nix { }).packages.${builtins.currentSystem}.add-subflakes-to-store' --command add-subflakes-to-store 9 | ``` 10 | 11 | You can then run a NixOS VM on Linux with: 12 | 13 | ``` 14 | $ nix run .#phi-nixos-vm 15 | ``` 16 | 17 | All the possible hostnames are `eris`, `phi-nixos` and `sigma` 18 | 19 | ## See also 20 | 21 | - [Frequently Asked Questions about Nix](https://github.com/hlissner/dotfiles/tree/55194e703d1fe82e7e0ffd06e460f1897b6fc404?tab=readme-ov-file#frequently-asked-questions) 22 | -------------------------------------------------------------------------------- /files/commands.py: -------------------------------------------------------------------------------- 1 | import os 2 | import shutil 3 | 4 | from ranger.api.commands import Command 5 | from ranger.ext.safe_path import get_safe_path 6 | 7 | 8 | class backup_edit(Command): 9 | def execute(self): 10 | if self.arg(1): 11 | original_filename = self.rest(1) 12 | else: 13 | original_filename = self.fm.thisfile.path 14 | 15 | if not os.path.exists(original_filename): 16 | self.fm.notify(f"{original_filename} does not exist", bad=True) 17 | return 18 | 19 | if os.path.isdir(original_filename): 20 | self.fm.notify(f"{original_filename} is a directory", bad=True) 21 | return 22 | 23 | backup_ext = ".link" if os.path.islink(original_filename) else ".bak" 24 | 25 | new_filename = get_safe_path(original_filename + backup_ext) 26 | 27 | if not self.fm.rename(original_filename, new_filename): 28 | self.fm.notify(f"Failed to rename file") 29 | return 30 | 31 | shutil.copyfile(new_filename, original_filename, follow_symlinks=True) 32 | 33 | self.fm.edit_file(original_filename) 34 | 35 | def tab(self, tabnum): 36 | return self._tab_directory_content() 37 | -------------------------------------------------------------------------------- /files/init.vim: -------------------------------------------------------------------------------- 1 | let mapleader = "," 2 | 3 | if !exists('g:vscode') 4 | " Load optional vim plugins 5 | packadd! \* 6 | 7 | set modeline 8 | set number 9 | set relativenumber 10 | let g:strip_whitespace_on_save = 1 11 | 12 | " Support 24-bit colours in terminals 13 | set termguicolors 14 | 15 | " Lightline settings 16 | set noshowmode 17 | set laststatus=2 18 | 19 | " Show current git branch in lightline 20 | let g:lightline = { 21 | \ 'active': { 22 | \ 'left': [ [ 'mode', 'paste'], 23 | \ [ 'fugitive', 'readonly', 'filename', 'modified' ] ] 24 | \ }, 25 | \ 'component_function': { 26 | \ 'fugitive': 'FugitiveHead' 27 | \ }, 28 | \ } 29 | 30 | call denite#custom#var('file/rec', 'command', 31 | \ ['rg', '--files', '--glob', '!.git', '--color', 'never']) 32 | 33 | call denite#custom#var('grep', 'command', ['rg']) 34 | call denite#custom#var('grep', 'default_opts', 35 | \ ['--vimgrep', '--no-heading']) 36 | call denite#custom#var('grep', 'recursive_opts', []) 37 | call denite#custom#var('grep', 'pattern_opt', ['--regexp']) 38 | call denite#custom#var('grep', 'separator', ['--']) 39 | call denite#custom#var('grep', 'final_opts', []) 40 | 41 | nnoremap b :Denite -default-action=open buffer 42 | nnoremap f :Denite -default-action=open file/rec 43 | nnoremap F :Denite -default-action=tabopen file/rec 44 | nnoremap s :Denite -default-action=split file/rec 45 | nnoremap v :Denite -default-action=vsplit file/rec 46 | nnoremap t :Denite -default-action=open tab 47 | nnoremap / :Denite -default-action=open -no-empty grep:. 48 | 49 | map gs :Gstatus 50 | map gd :Gdiff 51 | map gb :Gblame 52 | map g :Git 53 | 54 | nnoremap G :UndotreeToggle 55 | endif 56 | 57 | if !exists('g:vscode') 58 | nmap cm Commentary 59 | else 60 | nmap cm VSCodeCommentary 61 | endif 62 | 63 | set background=dark 64 | colorscheme hybrid-krompus 65 | 66 | " Customize colour of vim-operator-flashy 67 | hi Flashy ctermbg=5 guibg=#ff0084 68 | 69 | " Illuminate matches like visual 70 | hi link illuminatedWord Visual 71 | 72 | syntax on 73 | set mouse=a 74 | set nowrap 75 | let g:terminal_scrollback_buffer_size = 100000 76 | 77 | " Defaults for if `sleuth.vim` fail 78 | set expandtab 79 | set softtabstop=4 80 | set shiftwidth=0 81 | set tabstop=4 82 | set autoindent 83 | 84 | " Show special whitespacing chars 85 | set list 86 | set listchars=tab:▸\ ,eol:¬,extends:❯,precedes:❮,trail:· 87 | 88 | " Lines before page starts scrolling 89 | set scrolloff=1 90 | set sidescroll=1 91 | 92 | " Remove find highlight 93 | nnoremap h :noh 94 | 95 | " Edit/Reload nvimrc 96 | nnoremap e :edit $MYVIMRC 97 | nnoremap E :tabedit $MYVIMRC 98 | nnoremap R :source $MYVIMRC 99 | 100 | " Operator remapping 101 | map y (operator-flashy) 102 | map Y "+(operator-flashy) 103 | 104 | " Beautify JSON 105 | map j :%!python -m json.tool 106 | 107 | " Confirm quit rather than :q! 108 | map ZQ :q 109 | 110 | " Disable Ex mode 111 | map Q 112 | 113 | if exists('g:vscode') 114 | autocmd CmdwinEnter * quit 115 | endif 116 | 117 | nnoremap a :ArgWrap 118 | 119 | set undofile 120 | set undodir=~/.config/nvim/undo 121 | -------------------------------------------------------------------------------- /files/post-checkout: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | if [[ -e $(git rev-parse --show-toplevel)/.git-blame-ignore-revs ]]; then 4 | echo ".git-blame-ignore-revs detected, setting blame.ignoreRevsFile" 5 | git config --local blame.ignoreRevsFile .git-blame-ignore-revs 6 | else 7 | echo "Unsetting blame.ignoreRevsFile" 8 | git config --local --unset blame.ignoreRevsFile 9 | fi 10 | -------------------------------------------------------------------------------- /files/powermenu: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | # 3 | # Use bemenu/rofi/zenity to change system runstate thanks to systemd. 4 | # 5 | # Note: this currently relies on associative array support in the shell. 6 | # 7 | # Inspired from i3pystatus wiki: 8 | # https://github.com/enkore/i3pystatus/wiki/Shutdown-Menu 9 | # 10 | # Copyright 2015 Benjamin Chrétien 11 | # 12 | # This program is free software: you can redistribute it and/or modify 13 | # it under the terms of the GNU General Public License as published by 14 | # the Free Software Foundation, either version 3 of the License, or 15 | # (at your option) any later version. 16 | 17 | # This program is distributed in the hope that it will be useful, 18 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 19 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 20 | # GNU General Public License for more details. 21 | 22 | # You should have received a copy of the GNU General Public License 23 | # along with this program. If not, see . 24 | 25 | ####################################################################### 26 | # BEGIN CONFIG # 27 | ####################################################################### 28 | 29 | # Use a custom lock script 30 | #LOCKSCRIPT="i3lock-extra -m pixelize" 31 | 32 | # Colors: FG (foreground), BG (background), HL (highlighted) 33 | FG_COLOR="#bbbbbb" 34 | BG_COLOR="#111111" 35 | HLFG_COLOR="#111111" 36 | HLBG_COLOR="#bbbbbb" 37 | BORDER_COLOR="#222222" 38 | 39 | # Options not related to colors 40 | ROFI_TEXT=":" 41 | #ROFI_OPTIONS=(-width -11 -location 0 -hide-scrollbar -bw 30 -color-window "#dd310027,#dd0310027,#dd310027" -padding 5) 42 | #ROFI_OPTIONS=(-width -18 -location 4 -hide-scrollbar -color-window "#cc310027,#00a0009a,#cc310027" -padding 5 -font "Sourcecode Pro Regular 10, FontAwesome 9") 43 | ROFI_OPTIONS=(-width -18 -location 4 -hide-scrollbar -padding 5 -font "Sourcecode Pro Regular 10, FontAwesome 10") 44 | # Zenity options 45 | ZENITY_TITLE="Power Menu" 46 | ZENITY_TEXT="Action:" 47 | ZENITY_OPTIONS=(--column= --hide-header) 48 | # bemenu options 49 | BEMENU_TEXT="Action" 50 | 51 | ####################################################################### 52 | # END CONFIG # 53 | ####################################################################### 54 | 55 | # Whether to ask for user's confirmation 56 | enable_confirmation=true 57 | 58 | # Preferred launcher if both are available 59 | preferred_launcher="bemenu" 60 | 61 | usage="$(basename "$0") [-h] [-c] [-p name] -- display a menu for shutdown, reboot, lock etc. 62 | 63 | where: 64 | -h show this help text 65 | -c ask for user confirmation 66 | -p preferred launcher (bemenu, rofi or zenity) 67 | 68 | This script depends on: 69 | - systemd, 70 | - i3 or sway, 71 | - rofi or zenity or bemenu" 72 | 73 | # Check whether the user-defined launcher is valid 74 | launcher_list=(bemenu rofi zenity) 75 | function check_launcher() { 76 | if [[ ! "${launcher_list[@]}" =~ (^|[[:space:]])"$1"($|[[:space:]]) ]]; then 77 | echo "Supported launchers: ${launcher_list[*]}" 78 | exit 1 79 | else 80 | # Get array with unique elements and preferred launcher first 81 | # Note: uniq expects a sorted list, so we cannot use it 82 | i=1 83 | launcher_list=($(for l in "$1" "${launcher_list[@]}"; do printf "%i %s\n" "$i" "$l"; let i+=1; done \ 84 | | sort -uk2 | sort -nk1 | cut -d' ' -f2- | tr '\n' ' ')) 85 | fi 86 | } 87 | 88 | # Parse CLI arguments 89 | while getopts "hcp:" option; do 90 | case "${option}" in 91 | h) echo "${usage}" 92 | exit 0 93 | ;; 94 | c) enable_confirmation=true 95 | ;; 96 | p) preferred_launcher="${OPTARG}" 97 | check_launcher "${preferred_launcher}" 98 | ;; 99 | *) exit 1 100 | ;; 101 | esac 102 | done 103 | 104 | # Check whether a command exists 105 | function command_exists() { 106 | command -v "$1" &> /dev/null 2>&1 107 | } 108 | 109 | # systemctl required 110 | if ! command_exists systemctl ; then 111 | exit 1 112 | fi 113 | 114 | messenger="" 115 | 116 | if command_exists "swaymsg"; then 117 | messenger="swaymsg" 118 | elif command_exists "i3-msg"; then 119 | messenger="i3-msg" 120 | else 121 | exit 1 122 | fi 123 | 124 | # menu defined as an associative array 125 | typeset -A menu 126 | 127 | # Menu with keys/commands 128 | 129 | menu=( 130 | [ Poweroff]="systemctl poweroff" 131 | [ Reboot]="systemctl reboot" 132 | [ Suspend]="systemctl suspend" 133 | [ Hibernate]="systemctl hibernate" 134 | [ Lock]="loginctl lock-session" 135 | [ Logout]="${messenger} exit" 136 | [ Cancel]="" 137 | ) 138 | 139 | menu_nrows=${#menu[@]} 140 | 141 | # Menu entries that may trigger a confirmation message 142 | menu_confirm="Poweroff Reboot Hibernate Suspend Halt Logout" 143 | 144 | launcher_exe="" 145 | launcher_options="" 146 | rofi_colors="" 147 | 148 | function prepare_launcher() { 149 | if [[ "$1" == "rofi" ]]; then 150 | rofi_colors=(-bc "${BORDER_COLOR}" -bg "${BG_COLOR}" -fg "${FG_COLOR}" \ 151 | -hlfg "${HLFG_COLOR}" -hlbg "${HLBG_COLOR}") 152 | launcher_exe="rofi" 153 | launcher_options=(-dmenu -i -lines "${menu_nrows}" -p "${ROFI_TEXT}" \ 154 | "${rofi_colors}" "${ROFI_OPTIONS[@]}") 155 | elif [[ "$1" == "zenity" ]]; then 156 | launcher_exe="zenity" 157 | launcher_options=(--list --title="${ZENITY_TITLE}" --text="${ZENITY_TEXT}" \ 158 | "${ZENITY_OPTIONS[@]}") 159 | elif [[ "$1" == "bemenu" ]]; then 160 | launcher_exe="bemenu" 161 | launcher_options=(--list 30 -p "${BEMENU_TEXT}" --ignorecase) 162 | fi 163 | } 164 | 165 | for l in "${launcher_list[@]}"; do 166 | if command_exists "${l}" ; then 167 | prepare_launcher "${l}" 168 | break 169 | fi 170 | done 171 | 172 | # No launcher available 173 | if [[ -z "${launcher_exe}" ]]; then 174 | exit 1 175 | fi 176 | 177 | launcher=(${launcher_exe} "${launcher_options[@]}") 178 | selection="$(printf '%s\n' "${!menu[@]}" | sort | "${launcher[@]}")" 179 | 180 | function ask_confirmation() { 181 | if [ "${launcher_exe}" == "rofi" ]; then 182 | confirmed=$(echo -e "Yes\nNo" | rofi -dmenu -i -lines 2 -p "${selection}?" \ 183 | "${rofi_colors}" "${ROFI_OPTIONS[@]}") 184 | [ "${confirmed}" == "Yes" ] && confirmed=0 185 | elif [ "${launcher_exe}" == "zenity" ]; then 186 | zenity --question --text "Are you sure you want to ${selection,,}?" 187 | confirmed=$? 188 | fi 189 | 190 | if [ "${confirmed}" == 0 ]; then 191 | ${messenger} "exec ${menu[${selection}]}" 192 | fi 193 | } 194 | 195 | if [[ $? -eq 0 && ! -z ${selection} ]]; then 196 | if [[ "${enable_confirmation}" = true && \ 197 | ${menu_confirm} =~ (^|[[:space:]])"${selection}"($|[[:space:]]) ]]; then 198 | ask_confirmation 199 | else 200 | ${messenger} "exec ${menu[${selection}]}" 201 | fi 202 | fi 203 | -------------------------------------------------------------------------------- /files/rc.conf: -------------------------------------------------------------------------------- 1 | set hidden_filter ^\.|\.(?:pyc|pyo|swp)$|^lost\+found$|^__(py)?cache__$ 2 | 3 | set preview_images true 4 | 5 | set dirname_in_tabs true 6 | 7 | map q eval fm.notify("Use ZQ to quit") 8 | map ZQ eval cmd("quitall") if not len(fm.loader.queue) else fm.notify("Use to cancel currently running task") 9 | copymap q Q ZZ 10 | 11 | map MF console touch%space 12 | map MD console mkdir%space 13 | map MM console mark%space 14 | 15 | map T tag_toggle 16 | map uT tag_remove 17 | 18 | unmap gL 19 | unmap gM 20 | unmap gR 21 | map ga cd -r . 22 | map gc cd ~/.config 23 | map gC eval fm.cd(ranger.CONFDIR) 24 | map gd cd /data 25 | map gD cd /dev 26 | map gH cd /home 27 | map gl cd ~/.local/share 28 | map gm cd /mnt 29 | map gn cd /etc/nix 30 | map gN cd /nix/var/nix 31 | 32 | map C eval fm.open_console('rename ') 33 | map cw bulkrename 34 | 35 | unmap 36 | map tab_move 1 37 | map tab_move -1 38 | map t draw_bookmarks 39 | map t eval fm.tab_new(path=fm.bookmarks[str(fm.ui.keybuffer)[-1]]) 40 | map t. tab_new . 41 | map dt tab_close 42 | map ut tab_restore 43 | 44 | # M A G I C 45 | # `tg` makes a new tab then goes to the folder specified by `g` 46 | eval -q [cmd("map tg{} eval fm.tab_new(path='{}')".format(chr(k), fm.ui.keymaps['browser'][103][k][3:]))for k in fm.ui.keymaps['browser'][103] if fm.ui.keymaps['browser'][103][k].startswith('cd ')] 47 | 48 | ### GNOME TERMINAL 49 | # = 50 | # = 51 | # 52 | ### TERMITE 53 | # = | 54 | 55 | # Use `zh` to toggle hidden 56 | unmap 57 | 58 | map zF filter 59 | map zz console flat%space 60 | 61 | map ,R source ~/.config/ranger/rc.conf 62 | 63 | map backup_edit 64 | copymap 65 | 66 | cmap eval fm.ui.console.move_word(left=1) 67 | cmap eval fm.ui.console.move_word(right=1) 68 | -------------------------------------------------------------------------------- /files/zshrc: -------------------------------------------------------------------------------- 1 | if [[ $- =~ i ]] && [[ -z "$TMUX" ]] && [[ -n "$SSH_TTY" ]]; then 2 | tmux attach-session -t ssh || tmux new-session -s ssh 3 | if ! tmux has-session -t ssh; then 4 | exit 5 | fi 6 | fi 7 | 8 | function agenix { 9 | $(which -p agenix) $@ -i =(op read "op://trimcmujfu5fjcx5u4u752yk2i/6gedf3cheamokyw47sq4wbxlsy/private key?ssh-format=openssh") 10 | } 11 | 12 | function ga { 13 | if [[ -z $1 ]]; then 14 | git add -p 15 | else 16 | git add $@ 17 | fi 18 | } 19 | 20 | function gbfm { 21 | if [[ ! -z $3 ]]; then 22 | start=$3 23 | elif [[ $(git rev-parse --abbrev-ref HEAD) == "HEAD" ]]; then 24 | start=HEAD 25 | elif git remote get-url upstream >/dev/null 2>&1; then 26 | start=upstream 27 | elif git remote get-url origin >/dev/null 2>&1; then 28 | start=origin 29 | else 30 | echo "Unknown start point" 31 | return 1 32 | fi 33 | 34 | git switch --no-track $1 $2 $start 35 | } 36 | 37 | function gfc { 38 | git clone $@ || return 1 39 | cd ./*(/om[1]) || return 1 40 | default_branch=$(git branch --show-current) 41 | git checkout origin || return 1 42 | git branch --delete $default_branch || return 1 43 | } 44 | 45 | function gps { 46 | branch=$(git rev-parse --abbrev-ref HEAD) || return 1 47 | 48 | if git remote get-url fork >/dev/null 2>&1; then 49 | remote=fork 50 | elif git remote get-url origin >/dev/null 2>&1; then 51 | remote=origin 52 | elif [[ -z $1 ]]; then 53 | remote=$1 54 | else 55 | echo "No remote specified" 56 | return 1 57 | fi 58 | 59 | if [[ $branch != "HEAD" ]]; then 60 | git push --set-upstream $remote $branch 61 | else 62 | echo "Not on a branch" 63 | return 1 64 | fi 65 | } 66 | 67 | # https://github.com/nix-community/nix-direnv#shell-integration 68 | function nixify { 69 | if [ ! -e ./.envrc ]; then 70 | echo "use nix" > .envrc 71 | direnv allow 72 | fi 73 | if [[ ! -e shell.nix ]]; then 74 | cat > shell.nix <<'EOF' 75 | with import {}; 76 | mkShell { 77 | nativeBuildInputs = [ 78 | bashInteractive 79 | ]; 80 | } 81 | EOF 82 | ${EDITOR:-vim} shell.nix 83 | fi 84 | } 85 | 86 | function flakify { 87 | if [ ! -e flake.nix ]; then 88 | nix flake new -t github:nix-community/nix-direnv . 89 | elif [ ! -e .envrc ]; then 90 | echo "use flake" > .envrc 91 | direnv allow 92 | fi 93 | ${EDITOR:-vim} flake.nix 94 | } 95 | 96 | function ranger-cd { 97 | tempfile=$(mktemp) 98 | ranger --choosedir="$tempfile" "${@:-$(pwd)}" < $TTY 99 | test -f "$tempfile" && 100 | if [[ "$(cat -- "$tempfile")" != "$(echo -n `pwd`)" ]]; then 101 | cd -- "$(cat "$tempfile")" 102 | fi 103 | rm -f -- "$tempfile" 104 | } 105 | 106 | function carry-ranger { 107 | ranger < $TTY 108 | zle push-line 109 | zle accept-line 110 | } 111 | 112 | function carry-ranger-cd { 113 | ranger-cd 114 | zle push-line 115 | zle accept-line 116 | } 117 | 118 | function peco_select_history { 119 | local tac 120 | 121 | if (( $+commands[tac] )); then 122 | tac="tac" 123 | else 124 | tac="tail -r" 125 | fi 126 | 127 | BUFFER=$(fc -l -n 1 | eval $tac | peco --query "$LBUFFER") 128 | zle end-of-line 129 | zle push-line 130 | zle accept-line 131 | } 132 | 133 | function source-zshrc { 134 | zle push-line 135 | BUFFER="source ~/.zshrc" 136 | zle accept-line 137 | } 138 | 139 | zle -N peco_select_history 140 | bindkey '^R' peco_select_history 141 | bindkey -r '^S' 142 | 143 | autoload -z edit-command-line 144 | zle -N edit-command-line 145 | 146 | zle -N source-zshrc 147 | zle -N carry-ranger 148 | zle -N carry-ranger-cd 149 | 150 | bindkey '^E^E' edit-command-line 151 | bindkey '^Er' carry-ranger 152 | bindkey '^Ec' carry-ranger-cd 153 | bindkey '^E^R' source-zshrc 154 | 155 | bindkey -r '^[OA' 156 | bindkey -r '^[OB' 157 | 158 | # Allow using `#`, `~` and `^` without escape 159 | unsetopt EXTENDED_GLOB 160 | 161 | unalias gcfS 2>/dev/null || true 162 | unalias gcF 2>/dev/null || true 163 | unalias gcFS 2>/dev/null || true 164 | unalias gfc 2>/dev/null || true 165 | unalias gr 2>/dev/null || true 166 | 167 | if [[ -e ~/.zshrc.secrets ]]; then 168 | source ~/.zshrc.secrets 169 | fi 170 | -------------------------------------------------------------------------------- /flake.lock: -------------------------------------------------------------------------------- 1 | { 2 | "nodes": { 3 | "agenix": { 4 | "inputs": { 5 | "darwin": [ 6 | "nix-darwin" 7 | ], 8 | "home-manager": [ 9 | "home-manager" 10 | ], 11 | "nixpkgs": [ 12 | "nixpkgs" 13 | ], 14 | "systems": [ 15 | "systems" 16 | ] 17 | }, 18 | "locked": { 19 | "lastModified": 1745630506, 20 | "narHash": "sha256-bHCFgGeu8XjWlVuaWzi3QONjDW3coZDqSHvnd4l7xus=", 21 | "owner": "ryantm", 22 | "repo": "agenix", 23 | "rev": "96e078c646b711aee04b82ba01aefbff87004ded", 24 | "type": "github" 25 | }, 26 | "original": { 27 | "owner": "ryantm", 28 | "repo": "agenix", 29 | "type": "github" 30 | } 31 | }, 32 | "clan-core": { 33 | "inputs": { 34 | "data-mesher": "data-mesher", 35 | "disko": [ 36 | "disko" 37 | ], 38 | "flake-parts": [ 39 | "flake-parts" 40 | ], 41 | "nix-darwin": [ 42 | "nix-darwin" 43 | ], 44 | "nix-select": "nix-select", 45 | "nixos-facter-modules": "nixos-facter-modules", 46 | "nixpkgs": [ 47 | "nixpkgs" 48 | ], 49 | "sops-nix": "sops-nix", 50 | "systems": [ 51 | "systems" 52 | ], 53 | "treefmt-nix": [ 54 | "flake-compat" 55 | ] 56 | }, 57 | "locked": { 58 | "lastModified": 1747412631, 59 | "narHash": "sha256-SmwaF8X4ReizzHaH3fl5OXaF7vcLTZWSgY96wheZmBs=", 60 | "ref": "refs/heads/main", 61 | "rev": "00eac81c2f034b4351a6c4d59ff85b24507fd08f", 62 | "revCount": 7000, 63 | "type": "git", 64 | "url": "https://git.clan.lol/clan/clan-core" 65 | }, 66 | "original": { 67 | "type": "git", 68 | "url": "https://git.clan.lol/clan/clan-core" 69 | } 70 | }, 71 | "data-mesher": { 72 | "inputs": { 73 | "flake-parts": [ 74 | "clan-core", 75 | "flake-parts" 76 | ], 77 | "nixpkgs": [ 78 | "clan-core", 79 | "nixpkgs" 80 | ], 81 | "systems": [ 82 | "clan-core", 83 | "systems" 84 | ], 85 | "treefmt-nix": [ 86 | "clan-core", 87 | "treefmt-nix" 88 | ] 89 | }, 90 | "locked": { 91 | "lastModified": 1747329636, 92 | "narHash": "sha256-mmyx5trq5ZQp6uShbHNfqgSxdg9OeArcZGdZKtHjhqw=", 93 | "rev": "7afcd6f322b9839699f6f31d5bed884c6dd412c4", 94 | "type": "tarball", 95 | "url": "https://git.clan.lol/api/v1/repos/clan/data-mesher/archive/7afcd6f322b9839699f6f31d5bed884c6dd412c4.tar.gz" 96 | }, 97 | "original": { 98 | "type": "tarball", 99 | "url": "https://git.clan.lol/clan/data-mesher/archive/main.tar.gz" 100 | } 101 | }, 102 | "disko": { 103 | "inputs": { 104 | "nixpkgs": [ 105 | "nixpkgs" 106 | ] 107 | }, 108 | "locked": { 109 | "lastModified": 1747274630, 110 | "narHash": "sha256-87RJwXbfOHyzTB9LYagAQ6vOZhszCvd8Gvudu+gf3qo=", 111 | "owner": "nix-community", 112 | "repo": "disko", 113 | "rev": "ec7c109a4f794fce09aad87239eab7f66540b888", 114 | "type": "github" 115 | }, 116 | "original": { 117 | "owner": "nix-community", 118 | "repo": "disko", 119 | "type": "github" 120 | } 121 | }, 122 | "firefox-addons": { 123 | "inputs": { 124 | "nixpkgs": [ 125 | "firefox-addons-overlay", 126 | "nixpkgs" 127 | ] 128 | }, 129 | "locked": { 130 | "dir": "pkgs/firefox-addons", 131 | "lastModified": 1747403139, 132 | "narHash": "sha256-GpldCFeC+YP9m2xm1POByfT3+9J9/nwst0CYxvR85I0=", 133 | "owner": "rycee", 134 | "repo": "nur-expressions", 135 | "rev": "1ebb2cf654110901889353440027993312e1aeb0", 136 | "type": "gitlab" 137 | }, 138 | "original": { 139 | "dir": "pkgs/firefox-addons", 140 | "owner": "rycee", 141 | "repo": "nur-expressions", 142 | "type": "gitlab" 143 | } 144 | }, 145 | "firefox-addons-overlay": { 146 | "inputs": { 147 | "firefox-addons": "firefox-addons", 148 | "nixpkgs": [ 149 | "nixpkgs" 150 | ] 151 | }, 152 | "locked": { 153 | "path": "overlays/firefox-addons", 154 | "type": "path" 155 | }, 156 | "original": { 157 | "path": "overlays/firefox-addons", 158 | "type": "path" 159 | }, 160 | "parent": [] 161 | }, 162 | "flake-compat": { 163 | "locked": { 164 | "lastModified": 1746162366, 165 | "narHash": "sha256-5SSSZ/oQkwfcAz/o/6TlejlVGqeK08wyREBQ5qFFPhM=", 166 | "owner": "nix-community", 167 | "repo": "flake-compat", 168 | "rev": "0f158086a2ecdbb138cd0429410e44994f1b7e4b", 169 | "type": "github" 170 | }, 171 | "original": { 172 | "owner": "nix-community", 173 | "repo": "flake-compat", 174 | "type": "github" 175 | } 176 | }, 177 | "flake-parts": { 178 | "inputs": { 179 | "nixpkgs-lib": [ 180 | "nixpkgs" 181 | ] 182 | }, 183 | "locked": { 184 | "lastModified": 1743550720, 185 | "narHash": "sha256-hIshGgKZCgWh6AYJpJmRgFdR3WUbkY04o82X05xqQiY=", 186 | "owner": "hercules-ci", 187 | "repo": "flake-parts", 188 | "rev": "c621e8422220273271f52058f618c94e405bb0f5", 189 | "type": "github" 190 | }, 191 | "original": { 192 | "owner": "hercules-ci", 193 | "repo": "flake-parts", 194 | "type": "github" 195 | } 196 | }, 197 | "flake-utils": { 198 | "inputs": { 199 | "systems": [ 200 | "systems" 201 | ] 202 | }, 203 | "locked": { 204 | "lastModified": 1731533236, 205 | "narHash": "sha256-l0KFg5HjrsfsO/JpG+r7fRrqm12kzFHyUHqHCVpMMbI=", 206 | "owner": "numtide", 207 | "repo": "flake-utils", 208 | "rev": "11707dc2f618dd54ca8739b309ec4fc024de578b", 209 | "type": "github" 210 | }, 211 | "original": { 212 | "owner": "numtide", 213 | "repo": "flake-utils", 214 | "type": "github" 215 | } 216 | }, 217 | "flake-utils-plus": { 218 | "inputs": { 219 | "flake-utils": [ 220 | "flake-utils" 221 | ] 222 | }, 223 | "locked": { 224 | "lastModified": 1738591040, 225 | "narHash": "sha256-4WNeriUToshQ/L5J+dTSWC5OJIwT39SEP7V7oylndi8=", 226 | "owner": "gytis-ivaskevicius", 227 | "repo": "flake-utils-plus", 228 | "rev": "afcb15b845e74ac5e998358709b2b5fe42a948d1", 229 | "type": "github" 230 | }, 231 | "original": { 232 | "owner": "gytis-ivaskevicius", 233 | "repo": "flake-utils-plus", 234 | "type": "github" 235 | } 236 | }, 237 | "home-manager": { 238 | "inputs": { 239 | "nixpkgs": [ 240 | "nixpkgs" 241 | ] 242 | }, 243 | "locked": { 244 | "lastModified": 1748391243, 245 | "narHash": "sha256-7sCuihzsTRZemtbTXaFUoGJUfuQErhKEcL9v7HKIo1k=", 246 | "owner": "nix-community", 247 | "repo": "home-manager", 248 | "rev": "f5b12be834874f7661db4ced969a621ab2d57971", 249 | "type": "github" 250 | }, 251 | "original": { 252 | "owner": "nix-community", 253 | "repo": "home-manager", 254 | "type": "github" 255 | } 256 | }, 257 | "impermanence": { 258 | "locked": { 259 | "lastModified": 1737831083, 260 | "narHash": "sha256-LJggUHbpyeDvNagTUrdhe/pRVp4pnS6wVKALS782gRI=", 261 | "owner": "nix-community", 262 | "repo": "impermanence", 263 | "rev": "4b3e914cdf97a5b536a889e939fb2fd2b043a170", 264 | "type": "github" 265 | }, 266 | "original": { 267 | "owner": "nix-community", 268 | "repo": "impermanence", 269 | "type": "github" 270 | } 271 | }, 272 | "nix-darwin": { 273 | "inputs": { 274 | "nixpkgs": [ 275 | "nixpkgs" 276 | ] 277 | }, 278 | "locked": { 279 | "lastModified": 1748352827, 280 | "narHash": "sha256-sNUUP6qxGkK9hXgJ+p362dtWLgnIWwOCmiq72LAWtYo=", 281 | "owner": "nix-darwin", 282 | "repo": "nix-darwin", 283 | "rev": "44a7d0e687a87b73facfe94fba78d323a6686a90", 284 | "type": "github" 285 | }, 286 | "original": { 287 | "owner": "nix-darwin", 288 | "repo": "nix-darwin", 289 | "type": "github" 290 | } 291 | }, 292 | "nix-index-database": { 293 | "inputs": { 294 | "nixpkgs": [ 295 | "nixpkgs" 296 | ] 297 | }, 298 | "locked": { 299 | "lastModified": 1746934494, 300 | "narHash": "sha256-3n6i+F0sDASjkhbvgFDpPDZGp7z19IrRtjfF9TwJpCA=", 301 | "owner": "nix-community", 302 | "repo": "nix-index-database", 303 | "rev": "e9b21b01e4307176b9718a29ac514838e7f6f4ff", 304 | "type": "github" 305 | }, 306 | "original": { 307 | "owner": "nix-community", 308 | "repo": "nix-index-database", 309 | "type": "github" 310 | } 311 | }, 312 | "nix-select": { 313 | "locked": { 314 | "lastModified": 1745005516, 315 | "narHash": "sha256-IVaoOGDIvAa/8I0sdiiZuKptDldrkDWUNf/+ezIRhyc=", 316 | "rev": "69d8bf596194c5c35a4e90dd02c52aa530caddf8", 317 | "type": "tarball", 318 | "url": "https://git.clan.lol/api/v1/repos/clan/nix-select/archive/69d8bf596194c5c35a4e90dd02c52aa530caddf8.tar.gz" 319 | }, 320 | "original": { 321 | "type": "tarball", 322 | "url": "https://git.clan.lol/clan/nix-select/archive/main.tar.gz" 323 | } 324 | }, 325 | "nixos-anywhere": { 326 | "inputs": { 327 | "disko": [ 328 | "disko" 329 | ], 330 | "flake-parts": [ 331 | "flake-parts" 332 | ], 333 | "nixos-images": "nixos-images", 334 | "nixos-stable": [], 335 | "nixpkgs": [ 336 | "nixpkgs" 337 | ], 338 | "treefmt-nix": [] 339 | }, 340 | "locked": { 341 | "lastModified": 1746713092, 342 | "narHash": "sha256-BeIAHEaKUeKmIED4GohPz7OWRBithENyAgCNxgSaQvM=", 343 | "owner": "nix-community", 344 | "repo": "nixos-anywhere", 345 | "rev": "a0fd2b7c603b92f8f57b38fe2f2b96cd39f4dfc0", 346 | "type": "github" 347 | }, 348 | "original": { 349 | "owner": "nix-community", 350 | "repo": "nixos-anywhere", 351 | "type": "github" 352 | } 353 | }, 354 | "nixos-facter-modules": { 355 | "locked": { 356 | "lastModified": 1743671943, 357 | "narHash": "sha256-7sYig0+RcrR3sOL5M+2spbpFUHyEP7cnUvCaqFOBjyU=", 358 | "owner": "nix-community", 359 | "repo": "nixos-facter-modules", 360 | "rev": "58ad9691670d293a15221d4a78818e0088d2e086", 361 | "type": "github" 362 | }, 363 | "original": { 364 | "owner": "nix-community", 365 | "repo": "nixos-facter-modules", 366 | "type": "github" 367 | } 368 | }, 369 | "nixos-images": { 370 | "inputs": { 371 | "nixos-stable": [ 372 | "nixos-anywhere", 373 | "nixos-stable" 374 | ], 375 | "nixos-unstable": [ 376 | "nixos-anywhere", 377 | "nixpkgs" 378 | ] 379 | }, 380 | "locked": { 381 | "lastModified": 1744853194, 382 | "narHash": "sha256-NBOdBdQdxb3FdM4Ywb4cATMLfFtkPqDYh0LIQMZ7eRY=", 383 | "owner": "nix-community", 384 | "repo": "nixos-images", 385 | "rev": "8f6f8060a13096934c2a502eb0508bdc3f1284a1", 386 | "type": "github" 387 | }, 388 | "original": { 389 | "owner": "nix-community", 390 | "repo": "nixos-images", 391 | "type": "github" 392 | } 393 | }, 394 | "nixpkgs": { 395 | "locked": { 396 | "lastModified": 1748190013, 397 | "narHash": "sha256-R5HJFflOfsP5FBtk+zE8FpL8uqE7n62jqOsADvVshhE=", 398 | "owner": "NixOS", 399 | "repo": "nixpkgs", 400 | "rev": "62b852f6c6742134ade1abdd2a21685fd617a291", 401 | "type": "github" 402 | }, 403 | "original": { 404 | "owner": "NixOS", 405 | "ref": "nixos-unstable", 406 | "repo": "nixpkgs", 407 | "type": "github" 408 | } 409 | }, 410 | "root": { 411 | "inputs": { 412 | "agenix": "agenix", 413 | "clan-core": "clan-core", 414 | "disko": "disko", 415 | "firefox-addons-overlay": "firefox-addons-overlay", 416 | "flake-compat": "flake-compat", 417 | "flake-parts": "flake-parts", 418 | "flake-utils": "flake-utils", 419 | "flake-utils-plus": "flake-utils-plus", 420 | "home-manager": "home-manager", 421 | "impermanence": "impermanence", 422 | "nix-darwin": "nix-darwin", 423 | "nix-index-database": "nix-index-database", 424 | "nixos-anywhere": "nixos-anywhere", 425 | "nixpkgs": "nixpkgs", 426 | "systems": "systems", 427 | "terranix": "terranix", 428 | "treefmt-nix": "treefmt-nix" 429 | } 430 | }, 431 | "sops-nix": { 432 | "inputs": { 433 | "nixpkgs": [ 434 | "clan-core", 435 | "nixpkgs" 436 | ] 437 | }, 438 | "locked": { 439 | "lastModified": 1746485181, 440 | "narHash": "sha256-PxrrSFLaC7YuItShxmYbMgSuFFuwxBB+qsl9BZUnRvg=", 441 | "owner": "Mic92", 442 | "repo": "sops-nix", 443 | "rev": "e93ee1d900ad264d65e9701a5c6f895683433386", 444 | "type": "github" 445 | }, 446 | "original": { 447 | "owner": "Mic92", 448 | "repo": "sops-nix", 449 | "type": "github" 450 | } 451 | }, 452 | "systems": { 453 | "flake": false, 454 | "locked": { 455 | "path": "./flake.systems.nix", 456 | "type": "path" 457 | }, 458 | "original": { 459 | "path": "./flake.systems.nix", 460 | "type": "path" 461 | }, 462 | "parent": [] 463 | }, 464 | "terranix": { 465 | "inputs": { 466 | "flake-parts": [ 467 | "flake-parts" 468 | ], 469 | "nixpkgs": [ 470 | "nixpkgs" 471 | ], 472 | "systems": [ 473 | "systems" 474 | ] 475 | }, 476 | "locked": { 477 | "lastModified": 1747386897, 478 | "narHash": "sha256-mShlhcRElxiuJ7/rpd2yduqsom21wB3GuZUYIVGolEE=", 479 | "owner": "terranix", 480 | "repo": "terranix", 481 | "rev": "b259af31a70c734db377a5b5a8ce3bf7f2c02fe4", 482 | "type": "github" 483 | }, 484 | "original": { 485 | "owner": "terranix", 486 | "repo": "terranix", 487 | "type": "github" 488 | } 489 | }, 490 | "treefmt-nix": { 491 | "inputs": { 492 | "nixpkgs": [ 493 | "nixpkgs" 494 | ] 495 | }, 496 | "locked": { 497 | "lastModified": 1747417995, 498 | "narHash": "sha256-3WY1yVTcS9Vi6vmBjWsNTG6IYDs/ybu2xAQykdeE22k=", 499 | "owner": "numtide", 500 | "repo": "treefmt-nix", 501 | "rev": "42dd9289571ae3c6884af9885b1a7432e3278f92", 502 | "type": "github" 503 | }, 504 | "original": { 505 | "owner": "numtide", 506 | "repo": "treefmt-nix", 507 | "type": "github" 508 | } 509 | } 510 | }, 511 | "root": "root", 512 | "version": 7 513 | } 514 | -------------------------------------------------------------------------------- /flake.nix: -------------------------------------------------------------------------------- 1 | { 2 | inputs.nixpkgs.url = "github:NixOS/nixpkgs/nixos-unstable"; 3 | 4 | inputs.nix-darwin.url = "github:nix-darwin/nix-darwin"; 5 | inputs.nix-darwin.inputs.nixpkgs.follows = "nixpkgs"; 6 | 7 | inputs.home-manager.url = "github:nix-community/home-manager"; 8 | inputs.home-manager.inputs.nixpkgs.follows = "nixpkgs"; 9 | 10 | inputs.systems.url = "path:./flake.systems.nix"; 11 | inputs.systems.flake = false; 12 | 13 | inputs.flake-compat.url = "github:nix-community/flake-compat"; 14 | 15 | inputs.flake-utils.url = "github:numtide/flake-utils"; 16 | inputs.flake-utils.inputs.systems.follows = "systems"; 17 | inputs.flake-utils-plus.url = "github:gytis-ivaskevicius/flake-utils-plus"; 18 | inputs.flake-utils-plus.inputs.flake-utils.follows = "flake-utils"; 19 | 20 | inputs.agenix.url = "github:ryantm/agenix"; 21 | inputs.agenix.inputs.darwin.follows = "nix-darwin"; 22 | inputs.agenix.inputs.home-manager.follows = "home-manager"; 23 | inputs.agenix.inputs.nixpkgs.follows = "nixpkgs"; 24 | inputs.agenix.inputs.systems.follows = "systems"; 25 | 26 | inputs.firefox-addons-overlay.url = "path:overlays/firefox-addons"; 27 | inputs.firefox-addons-overlay.inputs.nixpkgs.follows = "nixpkgs"; 28 | 29 | inputs.disko.url = "github:nix-community/disko"; 30 | inputs.disko.inputs.nixpkgs.follows = "nixpkgs"; 31 | 32 | inputs.flake-parts.url = "github:hercules-ci/flake-parts"; 33 | inputs.flake-parts.inputs.nixpkgs-lib.follows = "nixpkgs"; 34 | 35 | inputs.terranix.url = "github:terranix/terranix"; 36 | inputs.terranix.inputs.flake-parts.follows = "flake-parts"; 37 | inputs.terranix.inputs.nixpkgs.follows = "nixpkgs"; 38 | inputs.terranix.inputs.systems.follows = "systems"; 39 | 40 | inputs.nixos-anywhere.url = "github:nix-community/nixos-anywhere"; 41 | inputs.nixos-anywhere.inputs.disko.follows = "disko"; 42 | inputs.nixos-anywhere.inputs.flake-parts.follows = "flake-parts"; 43 | inputs.nixos-anywhere.inputs.nixos-stable.follows = ""; 44 | inputs.nixos-anywhere.inputs.nixpkgs.follows = "nixpkgs"; 45 | inputs.nixos-anywhere.inputs.treefmt-nix.follows = ""; 46 | 47 | inputs.impermanence.url = "github:nix-community/impermanence"; 48 | 49 | inputs.nix-index-database.url = "github:nix-community/nix-index-database"; 50 | inputs.nix-index-database.inputs.nixpkgs.follows = "nixpkgs"; 51 | 52 | inputs.clan-core.url = "git+https://git.clan.lol/clan/clan-core"; 53 | inputs.clan-core.inputs.disko.follows = "disko"; 54 | inputs.clan-core.inputs.flake-parts.follows = "flake-parts"; 55 | inputs.clan-core.inputs.nixpkgs.follows = "nixpkgs"; 56 | inputs.clan-core.inputs.nix-darwin.follows = "nix-darwin"; 57 | inputs.clan-core.inputs.systems.follows = "systems"; 58 | # This causes a stack overflow when set to empty string or relative path inputs 59 | inputs.clan-core.inputs.treefmt-nix.follows = "flake-compat"; 60 | 61 | inputs.treefmt-nix.url = "github:numtide/treefmt-nix"; 62 | inputs.treefmt-nix.inputs.nixpkgs.follows = "nixpkgs"; 63 | 64 | outputs = inputs: 65 | inputs.flake-parts.lib.mkFlake { 66 | inherit inputs; 67 | specialArgs = { 68 | self-lib = (import ./lib.nix) { inherit (inputs.nixpkgs) lib; }; 69 | }; 70 | } { 71 | imports = [ 72 | inputs.clan-core.flakeModules.default 73 | inputs.treefmt-nix.flakeModule 74 | 75 | ./hosts/flake-module.nix 76 | ./modules/flake-parts/flake-module.nix 77 | ./.github/flake-module.nix 78 | ]; 79 | systems = import inputs.systems; 80 | 81 | # Dirty hack to enable debug mode in `nix repl` 82 | debug = builtins ? currentSystem; 83 | }; 84 | } 85 | -------------------------------------------------------------------------------- /flake.systems.nix: -------------------------------------------------------------------------------- 1 | [ "x86_64-linux" "aarch64-darwin" "aarch64-linux" ] 2 | -------------------------------------------------------------------------------- /hosts/eris/configuration.nix: -------------------------------------------------------------------------------- 1 | { lib, ... }: 2 | 3 | { 4 | imports = [ ./hardware-configuration.nix ]; 5 | 6 | boot.loader.grub.enable = true; 7 | 8 | networking.hostId = "536c3bf5"; 9 | 10 | services.openssh.enable = lib.mkForce false; 11 | 12 | # `extraUpFlags` without `authKeyFile` isn't currently supported 13 | # services.tailscale.extraUpFlags = [ "--ssh" "--advertise-tags" "tag:eris" "--advertise-exit-node" ]; 14 | services.tailscale.useRoutingFeatures = "server"; 15 | 16 | zramSwap.enable = true; 17 | zramSwap.memoryPercent = 250; 18 | 19 | # Check that this can be bumped before changing it 20 | system.stateVersion = "23.11"; 21 | } 22 | -------------------------------------------------------------------------------- /hosts/eris/hardware-configuration.nix: -------------------------------------------------------------------------------- 1 | { modulesPath, ... }: 2 | 3 | { 4 | imports = [ (modulesPath + "/profiles/qemu-guest.nix") ]; 5 | 6 | boot.initrd.availableKernelModules = 7 | [ "ata_piix" "uhci_hcd" "virtio_pci" "virtio_scsi" "sd_mod" ]; 8 | boot.initrd.kernelModules = [ ]; 9 | boot.kernelModules = [ "kvm-intel" ]; 10 | boot.extraModulePackages = [ ]; 11 | 12 | disko.devices = { 13 | disk.primary = { 14 | type = "disk"; 15 | device = "/dev/sda"; 16 | content = { 17 | type = "gpt"; 18 | 19 | # for running GRUB on MBR 20 | partitions.grub = { 21 | size = "1M"; 22 | type = "EF02"; 23 | }; 24 | 25 | partitions.bpool = { 26 | size = "500M"; 27 | content = { 28 | type = "zfs"; 29 | pool = "bpool"; 30 | }; 31 | }; 32 | 33 | partitions.rpool = { 34 | size = "100%"; 35 | content = { 36 | type = "zfs"; 37 | pool = "rpool"; 38 | }; 39 | }; 40 | }; 41 | }; 42 | 43 | zpool.bpool = { 44 | type = "zpool"; 45 | options = { compatibility = "grub2"; }; 46 | rootFsOptions = { 47 | canmount = "off"; 48 | mountpoint = "none"; 49 | }; 50 | 51 | datasets.boot = { 52 | type = "zfs_fs"; 53 | 54 | mountpoint = "/boot"; 55 | options.mountpoint = "legacy"; 56 | }; 57 | }; 58 | 59 | zpool.rpool = { 60 | type = "zpool"; 61 | rootFsOptions = { 62 | canmount = "off"; 63 | mountpoint = "none"; 64 | 65 | compression = "zstd"; 66 | "com.sun:auto-snapshot" = "false"; 67 | relatime = "on"; 68 | }; 69 | 70 | datasets.root = { 71 | type = "zfs_fs"; 72 | 73 | mountpoint = "/"; 74 | options.mountpoint = "legacy"; 75 | 76 | options."com.sun:auto-snapshot" = "true"; 77 | postCreateHook = "zfs snapshot rpool/root@blank"; 78 | }; 79 | 80 | datasets.nix = { 81 | type = "zfs_fs"; 82 | 83 | mountpoint = "/nix"; 84 | options.mountpoint = "legacy"; 85 | }; 86 | 87 | datasets.logs = { 88 | type = "zfs_fs"; 89 | 90 | mountpoint = "/var/log"; 91 | options.mountpoint = "legacy"; 92 | 93 | options.acltype = "posixacl"; 94 | options.xattr = "sa"; 95 | }; 96 | }; 97 | }; 98 | } 99 | -------------------------------------------------------------------------------- /hosts/eris/home.nix: -------------------------------------------------------------------------------- 1 | { 2 | wayland.windowManager.sway.config.workspaceOutputAssign = [ 3 | { 4 | workspace = "1"; 5 | output = "HEADLESS-1"; 6 | } 7 | { 8 | workspace = "1"; 9 | output = "VGA-1"; 10 | } 11 | ]; 12 | 13 | wayland.windowManager.sway.config.startup = 14 | [ { command = "firefox"; } { command = "deluge"; } ]; 15 | } 16 | -------------------------------------------------------------------------------- /hosts/flake-module.nix: -------------------------------------------------------------------------------- 1 | { self-lib, ... }: 2 | let inherit (self-lib) modules; 3 | in { 4 | imports = map self-lib.mkConfiguration [ 5 | { 6 | host = "hyperion"; 7 | hostSuffix = "-macos"; 8 | user = "enzime"; 9 | system = "aarch64-darwin"; 10 | modules = 11 | builtins.attrNames { inherit (modules) android laptop personal; }; 12 | } 13 | { 14 | host = "phi"; 15 | hostSuffix = "-nixos"; 16 | user = "enzime"; 17 | system = "x86_64-linux"; 18 | modules = builtins.attrNames { 19 | inherit (modules) 20 | android bluetooth deluge nextcloud personal printers samba scanners 21 | sway wireless virt-manager; 22 | }; 23 | } 24 | { 25 | host = "sigma"; 26 | user = "enzime"; 27 | system = "x86_64-linux"; 28 | modules = builtins.attrNames { 29 | inherit (modules) impermanence laptop personal sway; 30 | }; 31 | } 32 | { 33 | host = "eris"; 34 | user = "human"; 35 | system = "x86_64-linux"; 36 | modules = 37 | builtins.attrNames { inherit (modules) deluge reflector vncserver; }; 38 | } 39 | ]; 40 | } 41 | -------------------------------------------------------------------------------- /hosts/hyperion/darwin-configuration.nix: -------------------------------------------------------------------------------- 1 | { user, config, pkgs, ... }: 2 | 3 | { 4 | networking.knownNetworkServices = [ "Wi-Fi" ]; 5 | 6 | nix.registry.ln.to = { 7 | type = "git"; 8 | url = "file://${config.users.users.${user}.home}/Code/nixpkgs"; 9 | }; 10 | nix.registry.lnd.to = { 11 | type = "git"; 12 | url = "file://${config.users.users.${user}.home}/Code/nix-darwin"; 13 | }; 14 | 15 | system.defaults.dock.persistent-apps = [ 16 | "/Applications/Firefox.app" 17 | "${pkgs.ghostty-bin}/Applications/Ghostty.app" 18 | "/Applications/1Password.app" 19 | "${pkgs.vscode}/Applications/Visual Studio Code.app" 20 | "${pkgs.spotify}/Applications/Spotify.app" 21 | "/System/Applications/Calendar.app" 22 | "${pkgs.joplin-desktop}/Applications/Joplin.app" 23 | "/System/Applications/System Settings.app" 24 | "/System/Applications/iPhone Mirroring.app" 25 | ]; 26 | 27 | nix.distributedBuilds = true; 28 | 29 | nix.buildMachines = [{ 30 | # Use ssh-ng for trustless remote building of input-addressed derivations 31 | # i.e. not requiring remote user to be a trusted-user 32 | protocol = "ssh-ng"; 33 | hostName = "clan.lol"; 34 | sshUser = "enzime"; 35 | sshKey = "/etc/ssh/ssh_host_ed25519_key"; 36 | system = "x86_64-linux"; 37 | supportedFeatures = [ "kvm" "benchmark" "big-parallel" ]; 38 | maxJobs = 96; 39 | }]; 40 | 41 | system.stateVersion = 6; 42 | } 43 | -------------------------------------------------------------------------------- /hosts/hyperion/home.nix: -------------------------------------------------------------------------------- 1 | { config, pkgs, ... }: 2 | let 3 | platformConfigDir = if pkgs.hostPlatform.isDarwin then 4 | "Library/Application Support" 5 | else 6 | config.xdg.configHome; 7 | in { 8 | home.file."${platformConfigDir}/sops/age/keys.txt".source = 9 | config.lib.file.mkOutOfStoreSymlink 10 | "${config.home.homeDirectory}/${platformConfigDir}/sops/age/keys.txt.native"; 11 | } 12 | -------------------------------------------------------------------------------- /hosts/phi/configuration.nix: -------------------------------------------------------------------------------- 1 | { config, user, keys, pkgs, lib, ... }: 2 | 3 | { 4 | imports = [ ./hardware-configuration.nix ]; 5 | 6 | boot.loader.systemd-boot.enable = true; 7 | boot.loader.efi.canTouchEfiVariables = true; 8 | boot.loader.systemd-boot.netbootxyz.enable = true; 9 | 10 | hardware.cpu.amd.updateMicrocode = 11 | lib.mkIf pkgs.stdenv.hostPlatform.isx86_64 true; 12 | 13 | networking.nameservers = [ "1.1.1.1" ]; 14 | networking.dhcpcd.extraConfig = '' 15 | nohook resolv.conf 16 | ''; 17 | 18 | networking.networkmanager.ensureProfiles.profiles.network-1.connection.autoconnect = 19 | false; 20 | networking.networkmanager.ensureProfiles.profiles.network-2.connection.autoconnect = 21 | false; 22 | 23 | nix.registry.ln.to = { 24 | type = "git"; 25 | url = "file:///home/${user}/nix/nixpkgs"; 26 | }; 27 | 28 | # Install firmware-linux-nonfree (includes Navi10 drivers) 29 | hardware.enableRedistributableFirmware = true; 30 | services.xserver.videoDrivers = [ "amdgpu" ]; 31 | 32 | # Enable FreeSync 33 | services.xserver.deviceSection = '' 34 | Option "VariableRefresh" "true" 35 | ''; 36 | 37 | # LWJGL 2 doesn't support modelines with text after WxH 38 | services.xserver.xrandrHeads = [{ 39 | output = "DisplayPort-0"; 40 | primary = true; 41 | monitorConfig = '' 42 | ModeLine "3440x1441" 1086.75 3440 3744 4128 4816 1440 1443 1453 1568 -hsync +vsync 43 | Option "PreferredMode" "3440x1441" 44 | ''; 45 | }]; 46 | 47 | services.udev.extraHwdb = '' 48 | evdev:name:USB-HID Keyboard:dmi:* 49 | KEYBOARD_KEY_70039=esc 50 | ''; 51 | 52 | security.pam.u2f.enable = true; 53 | security.pam.u2f.settings.cue = true; 54 | security.pam.u2f.settings.authfile = pkgs.writeText "u2f-mappings" '' 55 | enzime:aZod0R2utyFHotPvicvh1Kj1hcrGjT+5cHAFdnB7X8lJoDpiPDGqEvYXOCEaFsudXD3YFFjEvBiinXsj90jcXg==,mQCyOcbnehUfXRb2Jp/y40ixSeE69rhLnD66Q8bA209moCJmGMwShxT2SIwHJZPGutNTfyqaht2XRK9x27CpLg==,es256,+presence% 56 | ''; 57 | 58 | # For /mnt/phi on other systems 59 | users.users.${user} = { 60 | openssh.authorizedKeys.keys = 61 | builtins.attrValues { inherit (keys.hosts) sigma; }; 62 | }; 63 | 64 | services.nextcloud.home = "/data/Nextcloud"; 65 | 66 | services.tailscale.useRoutingFeatures = "both"; 67 | 68 | services.syncthing.dataDir = "${config.users.users.${user}.home}/sync"; 69 | 70 | # Check that this can be bumped before changing it 71 | system.stateVersion = "22.05"; 72 | } 73 | -------------------------------------------------------------------------------- /hosts/phi/hardware-configuration.nix: -------------------------------------------------------------------------------- 1 | { 2 | boot.initrd.availableKernelModules = 3 | [ "nvme" "xhci_pci" "ahci" "usbhid" "usb_storage" "sd_mod" ]; 4 | boot.initrd.kernelModules = [ ]; 5 | boot.kernelModules = [ "kvm-amd" ]; 6 | boot.extraModulePackages = [ ]; 7 | boot.supportedFilesystems = [ "ntfs" ]; 8 | 9 | fileSystems."/" = { 10 | device = "/dev/disk/by-label/nixos"; 11 | fsType = "ext4"; 12 | }; 13 | 14 | fileSystems."/boot" = { 15 | device = "/dev/disk/by-label/boot"; 16 | fsType = "vfat"; 17 | }; 18 | 19 | fileSystems."/os/windows" = { 20 | device = "/dev/disk/by-label/windows"; 21 | fsType = "ntfs"; 22 | options = [ "rw" ]; 23 | }; 24 | 25 | fileSystems."/data" = { 26 | device = "/dev/disk/by-label/data"; 27 | fsType = "ext4"; 28 | }; 29 | 30 | swapDevices = [{ device = "/dev/disk/by-label/swap"; }]; 31 | } 32 | -------------------------------------------------------------------------------- /hosts/phi/home.nix: -------------------------------------------------------------------------------- 1 | { 2 | wayland.windowManager.sway.config.output = { 3 | DP-1 = { 4 | mode = "3440x1440@144Hz"; 5 | adaptive_sync = "on"; 6 | }; 7 | }; 8 | 9 | wayland.windowManager.sway.config.workspaceOutputAssign = [{ 10 | workspace = "1"; 11 | output = "DP-1"; 12 | }]; 13 | } 14 | -------------------------------------------------------------------------------- /hosts/sigma/configuration.nix: -------------------------------------------------------------------------------- 1 | { user, pkgs, lib, ... }: 2 | 3 | { 4 | imports = [ ./hardware-configuration.nix ]; 5 | 6 | services.fwupd.enable = true; 7 | services.fwupd.extraRemotes = [ "lvfs-testing" ]; 8 | services.fwupd.uefiCapsuleSettings.DisableCapsuleUpdateOnDisk = true; 9 | 10 | boot.loader.systemd-boot.enable = true; 11 | boot.loader.efi.canTouchEfiVariables = true; 12 | 13 | networking.hostId = "215212b4"; 14 | 15 | hardware.cpu.intel.updateMicrocode = 16 | lib.mkIf pkgs.stdenv.hostPlatform.isx86_64 true; 17 | 18 | nix.registry.ln.to = { 19 | type = "git"; 20 | url = "file:///home/${user}/Code/nixpkgs"; 21 | }; 22 | 23 | services.tailscale.useRoutingFeatures = "client"; 24 | 25 | services.fprintd.enable = true; 26 | 27 | environment.persistence."/persist".directories = [ "/var/lib/fprint" ]; 28 | 29 | programs.captive-browser.interface = "wlp170s0"; 30 | 31 | # Check that this can be bumped before changing it 32 | system.stateVersion = "24.11"; 33 | } 34 | -------------------------------------------------------------------------------- /hosts/sigma/hardware-configuration.nix: -------------------------------------------------------------------------------- 1 | { config, ... }: 2 | 3 | { 4 | boot.initrd.availableKernelModules = [ "xhci_pci" "thunderbolt" "nvme" ]; 5 | boot.initrd.kernelModules = [ "dm-snapshot" ]; 6 | boot.kernelModules = [ "kvm-intel" ]; 7 | boot.extraModulePackages = [ ]; 8 | 9 | disko.devices = { 10 | disk.primary = { 11 | type = "disk"; 12 | device = "/dev/nvme0n1"; 13 | content = { 14 | type = "gpt"; 15 | 16 | partitions.esp = { 17 | size = "1G"; 18 | type = "EF00"; 19 | content = { 20 | type = "filesystem"; 21 | format = "vfat"; 22 | mountpoint = "/boot"; 23 | }; 24 | }; 25 | 26 | partitions.luks = { 27 | size = "100%"; 28 | content = { 29 | type = "luks"; 30 | name = "crypted"; 31 | passwordFile = "/tmp/secret.key"; 32 | askPassword = config.disko.testMode; 33 | content = { 34 | type = "zfs"; 35 | pool = "rpool"; 36 | }; 37 | }; 38 | }; 39 | }; 40 | }; 41 | 42 | zpool.rpool = { 43 | type = "zpool"; 44 | rootFsOptions = { 45 | canmount = "off"; 46 | mountpoint = "none"; 47 | 48 | compression = "zstd"; 49 | "com.sun:auto-snapshot" = "false"; 50 | relatime = "on"; 51 | }; 52 | 53 | datasets.root = { 54 | type = "zfs_fs"; 55 | mountpoint = "/"; 56 | 57 | postCreateHook = 58 | "zfs list -t snapshot -H -o name | grep -E '^rpool/root@blank$' || zfs snapshot rpool/root@blank"; 59 | }; 60 | 61 | datasets.nix = { 62 | type = "zfs_fs"; 63 | mountpoint = "/nix"; 64 | }; 65 | 66 | datasets.persist = { 67 | type = "zfs_fs"; 68 | mountpoint = "/persist"; 69 | }; 70 | 71 | datasets.logs = { 72 | type = "zfs_fs"; 73 | mountpoint = "/var/log"; 74 | 75 | options.acltype = "posixacl"; 76 | options.xattr = "sa"; 77 | }; 78 | }; 79 | }; 80 | 81 | fileSystems."/persist".neededForBoot = true; 82 | 83 | systemd.services.zfs-mount = { 84 | serviceConfig = { 85 | ExecStart = [ "${config.boot.zfs.package}/sbin/zfs mount -a -o remount" ]; 86 | }; 87 | }; 88 | } 89 | -------------------------------------------------------------------------------- /hosts/sigma/home.nix: -------------------------------------------------------------------------------- 1 | { config, ... }: 2 | 3 | { 4 | wayland.windowManager.sway.config.output = { eDP-1 = { scale = "1.5"; }; }; 5 | 6 | wayland.windowManager.sway.config.workspaceOutputAssign = [{ 7 | workspace = "1"; 8 | output = "eDP-1"; 9 | }]; 10 | 11 | xdg.userDirs.download = "$HOME/Downloads"; 12 | xdg.userDirs.pictures = "$HOME/Pictures"; 13 | 14 | home.persistence."/persist${config.home.homeDirectory}".directories = 15 | [ "Code" "Downloads" "Pictures" "Work" ]; 16 | } 17 | -------------------------------------------------------------------------------- /hosts/sigma/terraform-configuration.nix: -------------------------------------------------------------------------------- 1 | { config, inputs, hostname, keys, pkgs, lib, ... }: 2 | 3 | { 4 | terraform.required_providers.onepassword.source = "1Password/onepassword"; 5 | terraform.required_providers.local.source = "hashicorp/local"; 6 | terraform.required_providers.tailscale.source = "tailscale/tailscale"; 7 | 8 | provider.onepassword.account = "my.1password.com"; 9 | 10 | data.onepassword_item.tailscale_api_key = { 11 | vault = "r3fgka56ukyvdslqp3jxc37e3q"; 12 | uuid = "he4ygqtulfjb7dhhk3chvhrdge"; 13 | }; 14 | 15 | provider.tailscale.api_key = 16 | config.data.onepassword_item.tailscale_api_key "credential"; 17 | 18 | resource.tailscale_tailnet_key.terraform = { 19 | description = "Terraform"; 20 | expiry = 86400; # 1 day 21 | reusable = false; 22 | recreate_if_invalid = "always"; 23 | }; 24 | 25 | resource.onepassword_item.tailscale_auth_key = { 26 | vault = "r3fgka56ukyvdslqp3jxc37e3q"; 27 | title = "Tailscale Auth key"; 28 | category = "password"; 29 | password = config.resource.tailscale_tailnet_key.terraform "key"; 30 | }; 31 | 32 | module.install = { 33 | source = "${inputs.nixos-anywhere}/terraform/install"; 34 | target_host = hostname; 35 | flake = ".#${hostname}"; 36 | build_on_remote = pkgs.system 37 | != inputs.self.nixosConfigurations.${hostname}.pkgs.system; 38 | extra_environment = { 39 | TAILSCALE_AUTH_KEY_UUID = 40 | config.resource.onepassword_item.tailscale_auth_key "uuid"; 41 | }; 42 | disk_encryption_key_scripts = [{ 43 | path = "/tmp/secret.key"; 44 | script = lib.getExe (pkgs.writeShellApplication { 45 | name = "get-luks-passphrase"; 46 | text = '' 47 | askPassword() { 48 | IFS= read -r -e -p "Enter LUKS passphrase: " -s password < /dev/tty 49 | echo >&2 50 | IFS= read -r -e -p "Enter LUKS passphrase again: " -s password_check < /dev/tty 51 | [ "$password" = "$password_check" ] 52 | } 53 | 54 | until askPassword; do 55 | echo "Passwords did not match, please try again." >&2 56 | done 57 | 58 | echo "$password" 59 | ''; 60 | }); 61 | }]; 62 | extra_files_script = lib.getExe (pkgs.writeShellApplication { 63 | name = "extra-files"; 64 | # 1Password CLI requires setgid so we want to use the one from the system 65 | text = '' 66 | mkdir -p persist/etc/ssh 67 | op read "op://o3urqzwged2afsdmxqkjjazstq/cbhneyjvapzvchxywtz6xgrchq/private key?ssh-format=openssh" | sed 's/\r$//' > persist/etc/ssh/ssh_host_ed25519_key 68 | chmod 400 persist/etc/ssh/ssh_host_ed25519_key 69 | echo "${ 70 | keys.hosts.${hostname} 71 | }" > persist/etc/ssh/ssh_host_ed25519_key.pub 72 | chmod 444 persist/etc/ssh/ssh_host_ed25519_key.pub 73 | '' + (lib.optionalString (keys.signing ? ${hostname}) '' 74 | mkdir -p etc/nix 75 | op read "op://r3fgka56ukyvdslqp3jxc37e3q/kfbpbjzox2h2qapi74p5dzqld4/key" > etc/nix/key 76 | chmod 400 etc/nix/key 77 | echo "${keys.signing.${hostname}}" > etc/nix/key.pub 78 | chmod 444 etc/nix/key.pub 79 | '') + '' 80 | op read "op://r3fgka56ukyvdslqp3jxc37e3q/$TAILSCALE_AUTH_KEY_UUID/password" > persist/tailscale.key 81 | chmod 400 persist/tailscale.key 82 | ''; 83 | }); 84 | }; 85 | } 86 | -------------------------------------------------------------------------------- /keys.nix: -------------------------------------------------------------------------------- 1 | { 2 | users = { 3 | enzime = 4 | "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAINKZfejb9htpSB5K9p0RuEowErkba2BMKaze93ZVkQIE"; 5 | }; 6 | 7 | hosts = { 8 | phi = 9 | "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIMxOi/S1TLBg8/ZRX5XfCTlM8A+I0q0pQksrxtfjdYFP"; 10 | sigma = 11 | "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIDxRoznXzz/T6s5UeHG1uoHCXGfXSpy27eTEzC0/EUW+"; 12 | }; 13 | 14 | signing = { 15 | "enzime.cachix.org" = 16 | "enzime.cachix.org-1:RvUdpEy6SEXlqvKYOVHpn5lNsJRsAZs6vVK1MFqJ9k4="; 17 | "cache.clan.lol" = 18 | "cache.clan.lol-1:3KztgSAB5R1M+Dz7vzkBGzXdodizbgLXGXKXlcQLA28="; 19 | aether = "aether-1:fMOnq1aouEVTB6pz6TvszTrXQhrQAbPePlilPafmsHs="; 20 | chi-linux-builder = 21 | "chi-linux-builder-1:u0hwDFmxev8B65kKbSAjBP7nGR+it429j/UbsdZd3gs="; 22 | echo = "echo-1:B0HChd9IxG8P9V2NezeWCBsst8AdVTxesCiePZUaduc="; 23 | hermes-macos = 24 | "hermes-macos-1:H8qFV4OhrWSbfHsQV6R2VzE2t3N+3nzItt856oWG0Kc="; 25 | hermes-linux-builder = 26 | "hermes-linux-builder-1:tibNs5BpVb54V17EimjfobHDgut+y9cfHMD57vojLmo="; 27 | }; 28 | } 29 | -------------------------------------------------------------------------------- /lib.nix: -------------------------------------------------------------------------------- 1 | { lib }: 2 | let 3 | inherit (builtins) readDir; 4 | inherit (lib) 5 | attrNames concatMap filter filterAttrs getAttr getAttrFromPath hasAttr 6 | hasSuffix mapAttrs' mapAttrsToList nameValuePair optionalAttrs removeSuffix 7 | unique; 8 | inherit (lib.path) removePrefix; 9 | 10 | importFrom = path: filename: import (path + ("/" + filename)); 11 | 12 | pathTo = path: ./. + "/${removePrefix ./. path}"; 13 | 14 | importOverlay = filename: _: importFrom (pathTo ./overlays) filename; 15 | regularOverlays = 16 | filterAttrs (name: _: hasSuffix ".nix" name) (readDir (pathTo ./overlays)); 17 | importedRegularOverlays = mapAttrsToList importOverlay regularOverlays; 18 | 19 | modules' = mapAttrs' (filename: _: 20 | nameValuePair (removeSuffix ".nix" filename) 21 | (importFrom (pathTo ./modules) filename)) 22 | (filterAttrs (_: type: type == "regular") (readDir (pathTo ./modules))); 23 | 24 | getModuleList = a: 25 | let 26 | imports = 27 | if (modules'.${a} ? imports) then modules'.${a}.imports else [ ]; 28 | in if (imports == [ ]) then 29 | [ a ] 30 | else 31 | [ a ] ++ unique (concatMap getModuleList imports); 32 | 33 | mkConfiguration = { host, hostSuffix ? "", user, system 34 | , nixos ? hasSuffix "linux" system, modules }: 35 | { self, inputs, lib, ... }: 36 | let 37 | flakeOverlays = attrNames (filterAttrs (_: type: type == "directory") 38 | (readDir (pathTo ./overlays))); 39 | importedFlakeOverlays = 40 | map (name: getAttrFromPath [ "${name}-overlay" "overlay" ] inputs) 41 | flakeOverlays; 42 | 43 | pkgs = import inputs.nixpkgs { 44 | inherit system; 45 | config.allowUnfree = true; 46 | overlays = importedRegularOverlays ++ importedFlakeOverlays; 47 | }; 48 | 49 | moduleList = unique (concatMap getModuleList ([ "base" ] ++ modules)); 50 | modulesToImport = map (name: getAttr name modules') moduleList; 51 | 52 | hostname = "${host}${hostSuffix}"; 53 | nixosModules = map (getAttr "nixosModule") 54 | (filter (hasAttr "nixosModule") modulesToImport); 55 | homeModules = map (getAttr "homeModule") 56 | (filter (hasAttr "homeModule") modulesToImport); 57 | darwinModules = map (getAttr "darwinModule") 58 | (filter (hasAttr "darwinModule") modulesToImport); 59 | home = [ 60 | inputs.nix-index-database.hmModules.nix-index 61 | inputs.impermanence.nixosModules.home-manager.impermanence 62 | (pathTo ./hosts/${host}/home.nix) 63 | ] ++ homeModules; 64 | 65 | configRevision = { 66 | full = self.rev or self.dirtyRev or "dirty-inputs"; 67 | short = self.shortRev or self.dirtyShortRev or "dirty-inputs"; 68 | }; 69 | 70 | keys = import (pathTo ./keys.nix); 71 | 72 | extraHomeManagerArgs = { inherit inputs configRevision keys moduleList; }; 73 | in { 74 | # nix build ~/.config/home-manager#nixosConfigurations.phi-nixos.config.system.build.toplevel 75 | # OR 76 | # nixos-rebuild build --flake ~/.config/home-manager#phi-nixos 77 | flake.baseNixosConfigurations = optionalAttrs nixos { 78 | ${hostname} = inputs.nixpkgs.lib.nixosSystem { 79 | modules = [ 80 | { 81 | nixpkgs = { 82 | inherit (pkgs) config overlays; 83 | hostPlatform = system; 84 | }; 85 | } 86 | inputs.flake-utils-plus.nixosModules.autoGenFromInputs 87 | inputs.agenix.nixosModules.age 88 | inputs.disko.nixosModules.disko 89 | inputs.impermanence.nixosModules.impermanence 90 | inputs.nix-index-database.nixosModules.nix-index 91 | (pathTo ./hosts/${host}/configuration.nix) 92 | ] ++ nixosModules ++ [ 93 | inputs.home-manager.nixosModules.home-manager 94 | { 95 | home-manager.useGlobalPkgs = true; 96 | 97 | # `home-manager` uses `/etc/profiles/per-user/` instead of `~/.nix-profile` 98 | # Required for `fonts.fontconfig.enable = true;` 99 | home-manager.useUserPackages = true; 100 | 101 | home-manager.users.${user}.imports = home; 102 | home-manager.extraSpecialArgs = extraHomeManagerArgs; 103 | } 104 | ]; 105 | specialArgs = { 106 | inherit inputs configRevision user host hostname keys; 107 | }; 108 | }; 109 | }; 110 | 111 | # nix build ~/.config/home-manager#darwinConfigurations.hyperion-macos.system 112 | # OR 113 | # darwin-rebuild build --flake ~/.config/home-manager#hyperion-macos 114 | flake.baseDarwinConfigurations = 115 | optionalAttrs pkgs.stdenv.hostPlatform.isDarwin { 116 | ${hostname} = inputs.nix-darwin.lib.darwinSystem { 117 | inherit system pkgs inputs; 118 | modules = [ 119 | inputs.flake-utils-plus.darwinModules.autoGenFromInputs 120 | inputs.agenix.darwinModules.age 121 | inputs.nix-index-database.darwinModules.nix-index 122 | (pathTo ./hosts/${host}/darwin-configuration.nix) 123 | ] ++ darwinModules ++ [ 124 | inputs.home-manager.darwinModules.home-manager 125 | { 126 | home-manager.useGlobalPkgs = true; 127 | home-manager.useUserPackages = true; 128 | 129 | home-manager.users.${user}.imports = home; 130 | home-manager.extraSpecialArgs = extraHomeManagerArgs; 131 | } 132 | ]; 133 | specialArgs = { inherit configRevision user host hostname keys; }; 134 | }; 135 | }; 136 | 137 | # nix build ~/.config/home-manager#homeConfigurations.enzime@phi-nixos.activationPackage 138 | # OR 139 | # home-manager build --flake ~/.config/home-manager#enzime@phi-nixos 140 | flake.homeConfigurations."${user}@${hostname}" = 141 | inputs.home-manager.lib.homeManagerConfiguration { 142 | inherit pkgs; 143 | modules = [{ 144 | home.username = user; 145 | home.homeDirectory = if pkgs.stdenv.hostPlatform.isDarwin then 146 | "/Users/${user}" 147 | else 148 | "/home/${user}"; 149 | }] ++ home; 150 | extraSpecialArgs = extraHomeManagerArgs; 151 | }; 152 | 153 | flake.checks.${system} = (optionalAttrs nixos { 154 | "nixos-${hostname}" = 155 | self.nixosConfigurations.${hostname}.config.system.build.toplevel; 156 | }) // (optionalAttrs pkgs.stdenv.hostPlatform.isDarwin { 157 | "nix-darwin-${hostname}" = 158 | self.darwinConfigurations.${hostname}.config.system.build.toplevel; 159 | }) // { 160 | "home-manager-${user}@${hostname}" = 161 | self.homeConfigurations."${user}@${hostname}".activationPackage; 162 | }; 163 | 164 | perSystem = { system, self', pkgs, ... }: { 165 | terraformConfigurations = optionalAttrs (builtins.pathExists 166 | (pathTo ./hosts/${host}/terraform-configuration.nix)) { 167 | ${hostname} = inputs.terranix.lib.terranixConfiguration { 168 | inherit system; 169 | modules = 170 | [ (pathTo ./hosts/${host}/terraform-configuration.nix) ]; 171 | extraArgs = { inherit inputs hostname keys; }; 172 | }; 173 | }; 174 | 175 | packages = optionalAttrs (builtins.pathExists 176 | (pathTo ./hosts/${host}/terraform-configuration.nix)) (let 177 | inherit (self'.packages) terraform; 178 | inherit (terraform.meta) mainProgram; 179 | in { 180 | "${hostname}-apply" = pkgs.writeShellApplication { 181 | name = "${hostname}-apply"; 182 | runtimeInputs = [ terraform ]; 183 | text = '' 184 | if [[ -e config.tf.json ]]; then rm -f config.tf.json; fi 185 | cp ${self'.terraformConfigurations.${hostname}} config.tf.json \ 186 | && ${mainProgram} init \ 187 | && ${mainProgram} apply 188 | ''; 189 | }; 190 | 191 | "${hostname}-destroy" = pkgs.writeShellApplication { 192 | name = "${hostname}-destroy"; 193 | runtimeInputs = [ terraform ]; 194 | text = '' 195 | if [[ -e config.tf.json ]]; then rm -f config.tf.json; fi 196 | cp ${self'.terraformConfigurations.${hostname}} config.tf.json \ 197 | && ${mainProgram} init \ 198 | && ${mainProgram} destroy 199 | ''; 200 | }; 201 | }); 202 | }; 203 | }; 204 | in { 205 | inherit mkConfiguration; 206 | modules = modules'; 207 | } 208 | -------------------------------------------------------------------------------- /modules/acme.nix: -------------------------------------------------------------------------------- 1 | { 2 | nixosModule = { config, ... }: { 3 | # security.acme.defaults.server = "https://acme-staging-v02.api.letsencrypt.org/directory"; 4 | security.acme.defaults.email = "letsencrypt@enzim.ee"; 5 | security.acme.defaults.group = config.services.nginx.group; 6 | security.acme.acceptTerms = true; 7 | }; 8 | } 9 | -------------------------------------------------------------------------------- /modules/alacritty.nix: -------------------------------------------------------------------------------- 1 | { 2 | # OS modules are required for running `ranger` as `root` 3 | nixosModule = { pkgs, ... }: { 4 | environment.systemPackages = [ pkgs.alacritty.terminfo ]; 5 | }; 6 | 7 | darwinModule = { pkgs, ... }: { 8 | environment.systemPackages = [ pkgs.alacritty.terminfo ]; 9 | }; 10 | 11 | homeModule = { pkgs, ... }: { 12 | home.packages = [ pkgs.alacritty.terminfo ]; 13 | 14 | programs.alacritty.settings = { 15 | font.normal.family = "DejaVu Sans Mono"; 16 | font.size = 10; 17 | 18 | colors = { 19 | draw_bold_text_with_bright_colors = true; 20 | 21 | primary.background = "#0d0c0c"; 22 | primary.foreground = "#fff5ed"; 23 | 24 | cursor.cursor = "#00ccff"; 25 | 26 | normal.black = "#0a0a0a"; 27 | normal.red = "#e61f00"; 28 | normal.green = "#6dd200"; 29 | normal.yellow = "#fa6800"; 30 | normal.blue = "#255ae4"; 31 | normal.magenta = "#ff0084"; 32 | normal.cyan = "#36fcd3"; 33 | normal.white = "#b6afab"; 34 | 35 | bright.black = "#73645d"; 36 | bright.red = "#ff3f3d"; 37 | bright.green = "#c1ff05"; 38 | bright.yellow = "#ffa726"; 39 | bright.blue = "#00ccff"; 40 | bright.magenta = "#ff65a0"; 41 | bright.cyan = "#96ffe3"; 42 | bright.white = "#fff5ed"; 43 | }; 44 | }; 45 | }; 46 | } 47 | -------------------------------------------------------------------------------- /modules/android.nix: -------------------------------------------------------------------------------- 1 | { 2 | nixosModule = { user, ... }: { 3 | programs.adb.enable = true; 4 | 5 | users.users.${user}.extraGroups = [ "adbusers" ]; 6 | }; 7 | 8 | homeModule = { pkgs, ... }: { 9 | home.packages = 10 | builtins.attrValues { inherit (pkgs) android-tools scrcpy; }; 11 | }; 12 | } 13 | -------------------------------------------------------------------------------- /modules/avahi.nix: -------------------------------------------------------------------------------- 1 | { 2 | nixosModule = { 3 | services.avahi.enable = true; 4 | services.avahi.publish.enable = true; 5 | services.avahi.publish.userServices = true; 6 | services.avahi.nssmdns4 = true; 7 | }; 8 | } 9 | -------------------------------------------------------------------------------- /modules/base.nix: -------------------------------------------------------------------------------- 1 | let 2 | shared = { config, configRevision, inputs, user, host, hostname, keys, pkgs 3 | , lib, ... }: { 4 | # Add flake revision to `nixos-version --json` 5 | system.configurationRevision = configRevision.full; 6 | 7 | networking.hostName = hostname; 8 | 9 | time.timeZone = "Australia/Melbourne"; 10 | 11 | nix.channel.enable = false; 12 | 13 | environment.systemPackages = (builtins.attrValues { 14 | inherit (pkgs) killall wget ranger zip unzip sshfs; 15 | }) ++ [ 16 | inputs.home-manager.packages.${pkgs.system}.default 17 | inputs.agenix.packages.${pkgs.system}.default 18 | inputs.clan-core.packages.${pkgs.system}.default 19 | ]; 20 | 21 | users.users.root = { 22 | openssh.authorizedKeys.keys = 23 | builtins.attrValues { inherit (keys.users) enzime; }; 24 | }; 25 | 26 | users.users.${user} = { 27 | # WORKAROUND: Fixes alacritty's terminfo not being found on macOS over SSH 28 | shell = pkgs.zsh; 29 | openssh.authorizedKeys.keys = 30 | builtins.attrValues { inherit (keys.users) enzime; }; 31 | }; 32 | 33 | # Generate `/etc/nix/inputs/` and `/etc/nix/registry.json` using FUP 34 | nix.linkInputs = true; 35 | nix.generateNixPathFromInputs = true; 36 | nix.generateRegistryFromInputs = true; 37 | 38 | nix.registry.d.to = { 39 | type = "git"; 40 | url = "file://${config.users.users.${user}.home}/dotfiles"; 41 | }; 42 | nix.registry.n.to = { 43 | id = "nixpkgs"; 44 | type = "indirect"; 45 | }; 46 | 47 | # By default NixOS and nix-darwin oversubscribe a lot (max-jobs = auto, cores = 0) 48 | # instead we would rather only oversubscribe a little bit 49 | nix.settings.cores = 2; 50 | 51 | # Override Clan's default using mkDefault (1000) 52 | nix.settings.min-free = lib.mkOverride 500 (3 * 1024 * 1024 * 1024); 53 | nix.settings.max-free = lib.mkOverride 500 (10 * 1024 * 1024 * 1024); 54 | 55 | nix.settings.builders-use-substitutes = true; 56 | 57 | nix.settings.secret-key-files = 58 | lib.mkIf (keys.signing ? ${hostname}) [ "/etc/nix/key" ]; 59 | 60 | nix.settings.trusted-public-keys = builtins.attrValues 61 | (lib.optionalAttrs (keys.signing ? ${hostname}) { 62 | self = keys.signing.${hostname}; 63 | }); 64 | 65 | home-manager.users.root.home.stateVersion = "24.05"; 66 | 67 | # We don't use `programs.ssh.extraConfig` because the SSH module 68 | # sets a bunch of settings we don't necessarily want 69 | home-manager.users.root.home.file.".ssh/config".text = '' 70 | Host * 71 | IdentityFile /etc/ssh/ssh_host_ed25519_key 72 | ''; 73 | 74 | services.openssh.enable = true; 75 | 76 | services.tailscale.enable = true; 77 | 78 | programs.zsh.enable = true; 79 | 80 | age.secrets.zshrc = let file = ../secrets/zshrc_${host}.age; 81 | in lib.mkIf (builtins.pathExists file) { 82 | inherit file; 83 | path = "${config.users.users.${user}.home}/.zshrc.secrets"; 84 | owner = user; 85 | }; 86 | 87 | programs.nix-index-database.comma.enable = true; 88 | }; 89 | in { 90 | imports = [ 91 | "alacritty" 92 | "builder" 93 | "cache" 94 | "clan" 95 | "flakes" 96 | "ghostty" 97 | "sops" 98 | "syncthing" 99 | "termite" 100 | "vcs" 101 | "vm" 102 | "vscode" 103 | "xdg" 104 | ]; 105 | 106 | nixosModule = { config, user, ... }: { 107 | imports = [ shared ]; 108 | 109 | i18n.defaultLocale = "en_AU.UTF-8"; 110 | 111 | environment.etc."nixos".source = 112 | "${config.users.users.${user}.home}/dotfiles"; 113 | 114 | hardware.enableRedistributableFirmware = true; 115 | 116 | programs.neovim.enable = true; 117 | programs.neovim.vimAlias = true; 118 | programs.neovim.defaultEditor = true; 119 | 120 | networking.useDHCP = true; 121 | 122 | networking.firewall.trustedInterfaces = 123 | [ config.services.tailscale.interfaceName ]; 124 | 125 | services.openssh.settings.PermitRootLogin = "prohibit-password"; 126 | services.openssh.hostKeys = [{ 127 | path = "/etc/ssh/ssh_host_ed25519_key"; 128 | type = "ed25519"; 129 | }]; 130 | 131 | users.users.${user} = { 132 | isNormalUser = true; 133 | extraGroups = [ "wheel" ]; 134 | initialPassword = "apple"; 135 | }; 136 | 137 | system.activationScripts.expire-password = '' 138 | if [[ $(passwd -S ${user} | cut -d" " -f 3) == "1970-01-02" ]]; then 139 | passwd --expire ${user} 140 | fi 141 | ''; 142 | 143 | system.autoUpgrade.enable = true; 144 | system.autoUpgrade.flake = "github:Enzime/dotfiles-nix"; 145 | system.autoUpgrade.persistent = true; 146 | 147 | environment.persistence."/persist".enable = false; 148 | }; 149 | 150 | darwinModule = { user, host, inputs, config, pkgs, lib, ... }: { 151 | imports = [ shared ]; 152 | 153 | system.primaryUser = user; 154 | 155 | # Used for `system.nixpkgsRevision` 156 | nixpkgs.source = inputs.nixpkgs; 157 | 158 | # This already gets set by FUP 159 | nixpkgs.flake.setFlakeRegistry = false; 160 | nixpkgs.flake.setNixPath = false; 161 | 162 | networking.computerName = host; 163 | 164 | environment.etc."nix-darwin".source = 165 | "${config.users.users.${user}.home}/dotfiles"; 166 | 167 | environment.shells = [ pkgs.zsh ]; 168 | 169 | users.users.root = { 170 | uid = 0; 171 | # Necessary otherwise `home-manager` will error out 172 | home = "/var/root"; 173 | # WORKAROUND: Fixes alacritty's terminfo not being found over SSH 174 | shell = pkgs.zsh; 175 | }; 176 | 177 | users.users.${user} = { 178 | uid = 501; 179 | home = "/Users/${user}"; 180 | }; 181 | 182 | users.knownUsers = [ "root" user ]; 183 | 184 | services.tailscale.overrideLocalDns = lib.mkDefault true; 185 | }; 186 | 187 | homeModule = { config, inputs, moduleList, pkgs, lib, ... }: 188 | let inherit (pkgs.stdenv) hostPlatform; 189 | in { 190 | home.stateVersion = "22.11"; 191 | 192 | # Replace `with pkgs;` with `inherit (pkgs)` 193 | # https://nix.dev/anti-patterns/language#with-attrset-expression 194 | home.packages = builtins.attrValues { 195 | inherit (pkgs) 196 | peco ripgrep jq htop ranger tmux tree magic-wormhole-rs hishtory; 197 | 198 | reptyr = lib.mkIf hostPlatform.isLinux pkgs.reptyr; 199 | }; 200 | 201 | # Allow fonts to be specified in `home.packages` 202 | fonts.fontconfig.enable = true; 203 | 204 | xdg.configFile."home-manager".source = config.lib.file.mkOutOfStoreSymlink 205 | "${config.home.homeDirectory}/dotfiles"; 206 | 207 | # Remove this once we have autoGenFromInputs for home-manager 208 | home.extraBuilderCommands = assert (!(config.nix or { }) ? linkInputs); 209 | "ln -sv ${inputs.self} $out/dotfiles"; 210 | 211 | home.sessionVariables = { 212 | EDITOR = "vim"; 213 | VISUAL = "vim"; 214 | MANROFFOPT = "-P -c"; 215 | }; 216 | 217 | home.file.".ssh/config".text = lib.mkAfter '' 218 | Host phi 219 | HostName phi-nixos 220 | 221 | Host eris 222 | User human 223 | 224 | Include config.local 225 | ''; 226 | 227 | home.file.".wgetrc".text = '' 228 | content_disposition=on 229 | continue=on 230 | no_parent=on 231 | robots=off 232 | ''; 233 | 234 | programs.aria2.enable = true; 235 | programs.aria2.settings = { continue = true; }; 236 | 237 | programs.zsh = { 238 | enable = true; 239 | # If this option is not disabled 240 | # `home-manager` installs `nix-zsh-completions` 241 | # which conflicts with `nix` in `home.packages` 242 | enableCompletion = false; 243 | 244 | prezto = { 245 | enable = true; 246 | 247 | pmoduleDirs = [ "${pkgs.zsh-you-should-use}/share/zsh/plugins" ]; 248 | 249 | pmodules = [ 250 | "environment" 251 | "terminal" 252 | "you-should-use" 253 | "editor" 254 | "history" 255 | "directory" 256 | "spectrum" 257 | # `git` just needs to be before `completion` 258 | "git" 259 | "completion" 260 | "prompt" 261 | ]; 262 | }; 263 | 264 | history = { 265 | extended = true; 266 | save = 1000000; 267 | size = 1000000; 268 | 269 | ignoreSpace = true; 270 | 271 | ignoreDups = true; 272 | expireDuplicatesFirst = true; 273 | }; 274 | 275 | initContent = lib.readFile ../files/zshrc + '' 276 | if [[ -d ~/.hishtory ]]; then 277 | source ${pkgs.hishtory}/share/hishtory/config.zsh 278 | fi 279 | ''; 280 | 281 | shellAliases = { 282 | _ = "\\sudo "; 283 | sudo = ''printf "zsh: command not found: sudo\n"''; 284 | 285 | ls = "ls -F --color=auto"; 286 | 287 | arg = "alias | rg --"; 288 | l = "ls -lah"; 289 | nb = "nix build"; 290 | nbl = "nb -L"; 291 | sr = "_ ranger"; 292 | w = "where -s"; 293 | }; 294 | }; 295 | 296 | programs.nix-index-database.comma.enable = true; 297 | 298 | programs.direnv.enable = true; 299 | programs.direnv.nix-direnv.enable = true; 300 | 301 | programs.neovim.enable = true; 302 | programs.neovim.vimAlias = true; 303 | programs.neovim.plugins = [ 304 | # Plugins that are always loaded 305 | pkgs.vimPlugins.vim-surround 306 | pkgs.vimPlugins.vim-repeat 307 | pkgs.vimPlugins.clever-f-vim 308 | pkgs.vimPlugins.vim-better-whitespace 309 | pkgs.vimPlugins.vim-sleuth 310 | pkgs.vimPlugins.vim-operator-user 311 | pkgs.vimPlugins.vim-operator-flashy 312 | pkgs.vimPlugins.vim-illuminate 313 | pkgs.vimPlugins.vim-argwrap 314 | ] ++ map (plugin: { 315 | inherit plugin; 316 | optional = true; 317 | }) [ 318 | # Plugins for standalone Neovim 319 | pkgs.vimPlugins.hybrid-krompus-vim 320 | pkgs.vimPlugins.neovim-ranger 321 | 322 | pkgs.vimPlugins.denite-nvim 323 | pkgs.vimPlugins.editorconfig-nvim 324 | pkgs.vimPlugins.lightline-vim 325 | pkgs.vimPlugins.vim-commentary 326 | pkgs.vimPlugins.vim-css-color 327 | pkgs.vimPlugins.vim-fugitive 328 | pkgs.vimPlugins.vim-signature 329 | pkgs.vimPlugins.undotree 330 | 331 | pkgs.vimPlugins.ale 332 | pkgs.vimPlugins.vim-beancount 333 | pkgs.vimPlugins.vim-cpp-enhanced-highlight 334 | pkgs.vimPlugins.vim-javascript 335 | pkgs.vimPlugins.vim-jsx-pretty 336 | pkgs.vimPlugins.vim-nix 337 | ]; 338 | programs.neovim.extraConfig = lib.readFile ../files/init.vim; 339 | 340 | xdg.dataFile."nvim/rplugin.vim".source = 341 | pkgs.runCommand "update-remote-plugins" { } '' 342 | NVIM_RPLUGIN_MANIFEST=$out timeout 5s ${ 343 | lib.getExe config.programs.neovim.finalPackage 344 | } \ 345 | -i NONE \ 346 | -n \ 347 | -u ${ 348 | pkgs.writeText "init.lua" 349 | config.xdg.configFile."nvim/init.lua".text 350 | } \ 351 | -c UpdateRemotePlugins \ 352 | -c quit 353 | ''; 354 | 355 | xdg.configFile."ranger/rc.conf".source = ../files/rc.conf; 356 | xdg.configFile."ranger/commands.py".source = ../files/commands.py; 357 | 358 | systemd.user.startServices = lib.mkIf hostPlatform.isLinux "sd-switch"; 359 | 360 | home.persistence = 361 | lib.mkIf (!builtins.elem "impermanence" moduleList) (lib.mkForce { }); 362 | 363 | programs.home-manager.enable = true; 364 | }; 365 | } 366 | -------------------------------------------------------------------------------- /modules/bluetooth.nix: -------------------------------------------------------------------------------- 1 | { 2 | nixosModule = { 3 | hardware.bluetooth.enable = true; 4 | services.blueman.enable = true; 5 | }; 6 | } 7 | -------------------------------------------------------------------------------- /modules/builder.nix: -------------------------------------------------------------------------------- 1 | let 2 | shared = { keys, pkgs, ... }: { 3 | users.users.builder = { 4 | shell = pkgs.zsh; 5 | openssh.authorizedKeys.keys = builtins.attrValues { 6 | inherit (keys.users) enzime; 7 | inherit (keys.hosts) sigma; 8 | }; 9 | }; 10 | }; 11 | in { 12 | nixosModule = { ... }: { 13 | imports = [ shared ]; 14 | 15 | users.groups.builder = { }; 16 | 17 | users.users.builder.isNormalUser = true; 18 | users.users.builder.group = "builder"; 19 | }; 20 | 21 | darwinModule = { ... }: { 22 | imports = [ shared ]; 23 | 24 | users.knownUsers = [ "builder" ]; 25 | 26 | users.users.builder.uid = 550; 27 | users.users.builder.home = "/Users/builder"; 28 | }; 29 | } 30 | -------------------------------------------------------------------------------- /modules/cache.nix: -------------------------------------------------------------------------------- 1 | let 2 | shared = { keys, ... }: { 3 | nix.settings.substituters = 4 | [ "https://enzime.cachix.org" "https://cache.clan.lol" ]; 5 | nix.settings.trusted-public-keys = builtins.attrValues { 6 | inherit (keys.signing) aether chi-linux-builder echo; 7 | 8 | "enzime.cachix.org" = keys.signing."enzime.cachix.org"; 9 | "cache.clan.lol" = keys.signing."cache.clan.lol"; 10 | }; 11 | }; 12 | in { 13 | nixosModule = shared; 14 | 15 | darwinModule = shared; 16 | 17 | homeModule = { pkgs, ... }: { 18 | home.packages = builtins.attrValues { inherit (pkgs) cachix; }; 19 | }; 20 | } 21 | 22 | -------------------------------------------------------------------------------- /modules/clan.nix: -------------------------------------------------------------------------------- 1 | let 2 | shared = { options, hostname, lib, ... }: { 3 | config = lib.optionalAttrs (options ? clan) { 4 | clan.core.networking.targetHost = "root@${hostname}"; 5 | }; 6 | }; 7 | in { 8 | nixosModule = shared; 9 | 10 | darwinModule = shared; 11 | 12 | homeModule = { 13 | home.file.".ssh/config".text = '' 14 | Host build01 15 | ProxyJump tunnel@clan.lol 16 | Hostname fda9:b487:2919:3547:3699:9336:90ec:cb59 17 | 18 | Host build02 19 | ProxyJump tunnel@clan.lol 20 | Hostname build02.tailfc885e.ts.net 21 | 22 | Host storinator01 23 | ProxyJump tunnel@clan.lol 24 | Hostname fda9:b487:2919:3547:3699:9393:7f57:6e6b 25 | ''; 26 | }; 27 | } 28 | -------------------------------------------------------------------------------- /modules/deluge.nix: -------------------------------------------------------------------------------- 1 | { 2 | homeModule = { pkgs, ... }: { 3 | home.packages = builtins.attrValues { inherit (pkgs) deluge; }; 4 | }; 5 | } 6 | -------------------------------------------------------------------------------- /modules/docker.nix: -------------------------------------------------------------------------------- 1 | { 2 | darwinModule = { pkgs, ... }: { 3 | environment.systemPackages = builtins.attrValues { 4 | inherit (pkgs) colima docker-client docker-compose; 5 | }; 6 | }; 7 | 8 | nixosModule = { pkgs, ... }: { 9 | environment.systemPackages = builtins.attrValues { 10 | # Uses podman-compose instead of docker-compose 11 | inherit (pkgs) arion; 12 | }; 13 | 14 | virtualisation.podman.enable = true; 15 | virtualisation.podman.dockerCompat = true; 16 | }; 17 | } 18 | -------------------------------------------------------------------------------- /modules/firefox.nix: -------------------------------------------------------------------------------- 1 | { 2 | darwinModule = { pkgs, lib, ... }: { 3 | system.activationScripts.applications.text = lib.mkAfter '' 4 | install -o root -g wheel -m0555 -d "/Applications/Firefox.app" 5 | 6 | rsyncFlags=( 7 | # mtime is standardized in the nix store, which would leave only file size to distinguish files. 8 | # Thus we need checksums, despite the speed penalty. 9 | --checksum 10 | # Converts all symlinks pointing outside of the copied tree (thus unsafe) into real files and directories. 11 | # This neatly converts all the symlinks pointing to application bundles in the nix store into 12 | # real directories, without breaking any relative symlinks inside of application bundles. 13 | # This is good enough, because the make-symlinks-relative.sh setup hook converts all $out internal 14 | # symlinks to relative ones. 15 | --copy-unsafe-links 16 | --archive 17 | --delete 18 | --chmod=-w 19 | --no-group 20 | --no-owner 21 | ) 22 | 23 | ${lib.getExe pkgs.rsync} "''${rsyncFlags[@]}" \ 24 | ${pkgs.firefox-bin-unwrapped}/Applications/Firefox.app/ /Applications/Firefox.app 25 | ''; 26 | 27 | system.defaults.CustomUserPreferences."org.mozilla.firefox".EnterprisePoliciesEnabled = 28 | true; 29 | system.defaults.CustomUserPreferences."org.mozilla.firefox".DisableAppUpdate = 30 | true; 31 | }; 32 | 33 | homeModule = { config, pkgs, lib, ... }: 34 | let 35 | inherit (pkgs.stdenv) hostPlatform; 36 | 37 | cfg = config.programs.firefox; 38 | in { 39 | home.activation.setDefaultBrowser = 40 | lib.mkIf (cfg.enable && hostPlatform.isDarwin) 41 | (lib.hm.dag.entryAfter [ "writeBoundary" ] '' 42 | if ! ${lib.getExe pkgs.defaultbrowser} firefox; then 43 | /usr/bin/open ${pkgs.firefox-bin}/Applications/Firefox.app 44 | ${lib.getExe pkgs.defaultbrowser} firefox 45 | fi 46 | ''); 47 | 48 | programs.firefox.enable = lib.mkDefault true; 49 | programs.firefox.package = 50 | if hostPlatform.isDarwin then null else pkgs.firefox; 51 | programs.firefox.profiles.base = { 52 | id = 0; 53 | 54 | extensions.packages = [ 55 | pkgs.firefox-addons.onepassword-password-manager 56 | pkgs.firefox-addons.clearurls 57 | pkgs.firefox-addons.ublock-origin 58 | pkgs.firefox-addons.youtube-nonstop 59 | pkgs.firefox-addons.kagi-privacy-pass 60 | ]; 61 | 62 | search = { 63 | default = "kagi"; 64 | engines = { 65 | kagi = { 66 | name = "Kagi"; 67 | urls = 68 | [{ template = "https://kagi.com/search?q={searchTerms}"; }]; 69 | icon = "https://kagi.com/favicon.ico"; 70 | }; 71 | 72 | google.metaData.hidden = true; 73 | wikipedia.metaData.hidden = true; 74 | bing.metaData.hidden = true; 75 | amazondotcom-au.metaData.hidden = true; 76 | ebay.metaData.hidden = true; 77 | amazondotcom-us.metaData.hidden = true; 78 | }; 79 | force = true; 80 | }; 81 | 82 | settings = { 83 | "browser.privatebrowsing.vpnpromourl" = ""; 84 | "datareporting.healthreport.uploadEnabled" = false; 85 | "extensions.pocket.enabled" = false; 86 | "browser.newtabpage.activity-stream.showSponsoredTopSites" = false; 87 | "app.normandy.enabled" = false; 88 | "signon.firefoxRelay.feature" = "disabled"; 89 | 90 | "browser.aboutConfig.showWarning" = false; 91 | 92 | # Open previous windows and tabs 93 | "browser.startup.page" = 3; 94 | 95 | "browser.tabs.closeWindowWithLastTab" = false; 96 | # Warn when attempting to close a window with multiple tabs 97 | "browser.tabs.warnOnClose" = true; 98 | "signon.rememberSignons" = false; 99 | "dom.security.https_only_mode" = true; 100 | 101 | "extensions.update.enabled" = false; 102 | 103 | # Use userChrome.css 104 | "toolkit.legacyUserProfileCustomizations.stylesheets" = true; 105 | 106 | # Default to light mode on all websites 107 | "layout.css.prefers-color-scheme.content-override" = 1; 108 | }; 109 | }; 110 | 111 | home.sessionVariablesExtra = '' 112 | if [[ $XDG_SESSION_TYPE = "wayland" ]]; then 113 | export MOZ_ENABLE_WAYLAND=1 114 | fi 115 | ''; 116 | 117 | home.persistence."/persist${config.home.homeDirectory}".directories = 118 | map (name: ".mozilla/firefox/${name}") 119 | (builtins.attrNames cfg.profiles); 120 | }; 121 | } 122 | -------------------------------------------------------------------------------- /modules/flake-parts/checks.nix: -------------------------------------------------------------------------------- 1 | { 2 | perSystem = { self', lib, ... }: { 3 | checks = let 4 | packages = 5 | lib.mapAttrs' (n: lib.nameValuePair "package-${n}") self'.packages; 6 | devShells = 7 | lib.mapAttrs' (n: lib.nameValuePair "devShell-${n}") self'.devShells; 8 | in packages // devShells; 9 | }; 10 | } 11 | -------------------------------------------------------------------------------- /modules/flake-parts/clan.nix: -------------------------------------------------------------------------------- 1 | { self, inputs, ... }: { 2 | clan = { 3 | meta.name = "Enzime"; 4 | 5 | pkgsForSystem = system: inputs.nixpkgs.legacyPackages.${system}; 6 | 7 | machines = builtins.mapAttrs (hostname: configuration: { 8 | imports = configuration._module.args.modules; 9 | 10 | config = { _module.args = configuration._module.specialArgs; }; 11 | }) (self.baseNixosConfigurations // self.baseDarwinConfigurations); 12 | 13 | inventory.machines = 14 | builtins.mapAttrs (hostname: _: { machineClass = "darwin"; }) 15 | self.baseDarwinConfigurations; 16 | 17 | specialArgs = { inherit inputs; }; 18 | }; 19 | } 20 | -------------------------------------------------------------------------------- /modules/flake-parts/configurations.nix: -------------------------------------------------------------------------------- 1 | { lib, flake-parts-lib, ... }: { 2 | imports = [ 3 | (flake-parts-lib.mkTransposedPerSystemModule { 4 | name = "terraformConfigurations"; 5 | option = lib.mkOption { 6 | type = lib.types.lazyAttrsOf lib.types.raw; 7 | default = { }; 8 | }; 9 | file = ./configurations.nix; 10 | }) 11 | ]; 12 | 13 | options = { 14 | flake.baseDarwinConfigurations = lib.mkOption { 15 | type = lib.types.lazyAttrsOf lib.types.raw; 16 | default = { }; 17 | }; 18 | 19 | flake.baseNixosConfigurations = lib.mkOption { 20 | type = lib.types.lazyAttrsOf lib.types.raw; 21 | default = { }; 22 | }; 23 | 24 | flake.homeConfigurations = lib.mkOption { 25 | type = lib.types.lazyAttrsOf lib.types.raw; 26 | default = { }; 27 | }; 28 | }; 29 | } 30 | -------------------------------------------------------------------------------- /modules/flake-parts/devShells.nix: -------------------------------------------------------------------------------- 1 | { 2 | perSystem = { self', inputs', pkgs, ... }: { 3 | devShells.default = pkgs.mkShell { 4 | buildInputs = builtins.attrValues { 5 | inherit (inputs'.home-manager.packages) home-manager; 6 | inherit (inputs'.agenix.packages) agenix; 7 | inherit (inputs'.clan-core.packages) clan-cli; 8 | inherit (self'.packages) terraform; 9 | }; 10 | 11 | shellHook = '' 12 | POST_CHECKOUT_HOOK=$(git rev-parse --git-common-dir)/hooks/post-checkout 13 | TMPFILE=$(mktemp) 14 | if curl -o $TMPFILE --fail https://raw.githubusercontent.com/Enzime/dotfiles-nix/HEAD/files/post-checkout; then 15 | if [[ -e $POST_CHECKOUT_HOOK ]]; then 16 | echo "Removing existing $POST_CHECKOUT_HOOK" 17 | rm $POST_CHECKOUT_HOOK 18 | fi 19 | echo "Replacing $POST_CHECKOUT_HOOK with $TMPFILE" 20 | cp $TMPFILE $POST_CHECKOUT_HOOK 21 | chmod a+x $POST_CHECKOUT_HOOK 22 | fi 23 | 24 | if [[ -e $POST_CHECKOUT_HOOK ]]; then 25 | $POST_CHECKOUT_HOOK 26 | fi 27 | ''; 28 | }; 29 | }; 30 | } 31 | -------------------------------------------------------------------------------- /modules/flake-parts/flake-module.nix: -------------------------------------------------------------------------------- 1 | { 2 | imports = [ 3 | ./checks.nix 4 | ./clan.nix 5 | ./configurations.nix 6 | ./devShells.nix 7 | ./formatter.nix 8 | ./lib.nix 9 | ./terraform.nix 10 | ./vm.nix 11 | ]; 12 | } 13 | -------------------------------------------------------------------------------- /modules/flake-parts/formatter.nix: -------------------------------------------------------------------------------- 1 | { 2 | perSystem = { self', pkgs, lib, ... }: { 3 | treefmt = { 4 | programs.deadnix.enable = true; 5 | programs.deadnix.no-lambda-arg = true; 6 | 7 | programs.nixfmt-classic.enable = true; 8 | programs.statix.enable = true; 9 | programs.shellcheck.enable = true; 10 | 11 | settings.formatter.nil = { 12 | # https://github.com/cachix/git-hooks.nix/blob/fa466640195d38ec97cf0493d6d6882bc4d14969/modules/hooks.nix#L3242-L3261 13 | command = lib.getExe (pkgs.writeShellApplication { 14 | name = "nil"; 15 | runtimeInputs = [ pkgs.nil ]; 16 | text = '' 17 | errors=false 18 | echo "Checking: $*" 19 | for file in "$@"; do 20 | nil diagnostics "$file" 21 | exit_code=$? 22 | 23 | if [[ $exit_code -ne 0 ]]; then 24 | echo "\"$file\" failed with exit code: $exit_code" 25 | errors=true 26 | fi 27 | done 28 | if [[ $errors == true ]]; then 29 | exit 1 30 | fi 31 | ''; 32 | }); 33 | includes = [ "*.nix" ]; 34 | }; 35 | }; 36 | 37 | packages.cached-nix-fmt = pkgs.writeShellApplication { 38 | name = "cached-nix-fmt"; 39 | runtimeInputs = 40 | builtins.attrValues { inherit (pkgs) coreutils moreutils; }; 41 | text = 42 | assert lib.versionOlder pkgs.nixVersions.latest.version "2.29.0"; '' 43 | set -x 44 | 45 | TOPLEVEL=$(git rev-parse --show-toplevel) 46 | FORMATTER_DIR="$TOPLEVEL/.formatter" 47 | FORMATTER_BINARY="$FORMATTER_DIR/binary" 48 | 49 | if [[ ! -e "$FORMATTER_BINARY" || "$(stat -c %Y "$FORMATTER_BINARY")" -lt "$(date -d "7 days ago" +%s)" ]]; then 50 | rm -rf "$FORMATTER_DIR" 51 | mkdir -p "$FORMATTER_DIR" 52 | 53 | echo "/*" | sponge "$FORMATTER_DIR/.gitignore" 54 | 55 | if nix eval .#formatter."$(nix config show system)" > /dev/null; then 56 | FORMATTER=$(nix shell nix/latest-release -c nix formatter build --out-link "$FORMATTER_DIR/store-path") 57 | else 58 | FORMATTER="${lib.getExe self'.packages.noop-treefmt}" 59 | fi 60 | 61 | ln -sf "$FORMATTER" "$FORMATTER_BINARY" 62 | fi 63 | exec "$FORMATTER_BINARY" "$@" 64 | ''; 65 | }; 66 | 67 | packages.noop-treefmt = pkgs.writeShellApplication { 68 | name = "noop-treefmt"; 69 | text = '' 70 | stdin=false 71 | 72 | for arg in "$@"; do 73 | if [[ "$arg" == "--stdin" ]]; then 74 | stdin=true 75 | fi 76 | done 77 | 78 | if [[ "$stdin" == "true" ]]; then 79 | exec cat 80 | fi 81 | ''; 82 | }; 83 | }; 84 | } 85 | -------------------------------------------------------------------------------- /modules/flake-parts/lib.nix: -------------------------------------------------------------------------------- 1 | { self-lib, ... }: { flake.lib = self-lib; } 2 | -------------------------------------------------------------------------------- /modules/flake-parts/terraform.nix: -------------------------------------------------------------------------------- 1 | { 2 | perSystem = { pkgs, ... }: { 3 | packages.terraform = pkgs.opentofu.withPlugins (p: 4 | builtins.attrValues { 5 | inherit (p) external hcloud local null onepassword tailscale; 6 | }); 7 | }; 8 | } 9 | -------------------------------------------------------------------------------- /modules/flake-parts/vm.nix: -------------------------------------------------------------------------------- 1 | { self, ... }: { 2 | perSystem = { system, pkgs, lib, ... }: { 3 | packages = let 4 | vmWithNewHostPlatform = name: 5 | pkgs.writeShellApplication { 6 | name = "run-${name}-vm-on-${system}"; 7 | runtimeInputs = builtins.attrValues { inherit (pkgs) jq; }; 8 | text = '' 9 | set -x 10 | 11 | drv="$(nix eval --raw ${self}#nixosConfigurations.${name} \ 12 | --apply 'original: 13 | let configuration = original.extendModules { modules = [ ({ lib, ... }: { 14 | _file = ""; 15 | nixpkgs.hostPlatform = lib.mkForce "${system}"; 16 | }) ]; }; 17 | in configuration.config.system.build.vm.drvPath' )" 18 | vm=$(nix build --no-link "$drv^*" --json | jq -r '.[0].outputs.out') 19 | # shellcheck disable=SC2211 20 | "$vm"/bin/run-*-vm 21 | ''; 22 | }; 23 | in lib.mapAttrs' (hostname: configuration: 24 | lib.nameValuePair "${hostname}-vm" (vmWithNewHostPlatform hostname)) 25 | self.nixosConfigurations; 26 | }; 27 | } 28 | -------------------------------------------------------------------------------- /modules/flakes.nix: -------------------------------------------------------------------------------- 1 | let 2 | shared = { pkgs, ... }: { 3 | nix.package = pkgs.nixVersions.latest; 4 | 5 | nix.settings.experimental-features = [ "nix-command" "flakes" ]; 6 | nix.settings.warn-dirty = false; 7 | }; 8 | in { 9 | darwinModule = shared; 10 | 11 | nixosModule = shared; 12 | 13 | homeModule = { config, lib, ... }@args: { 14 | imports = [ shared ]; 15 | 16 | home.packages = builtins.attrValues 17 | (lib.optionalAttrs (!args ? osConfig) { inherit (config.nix) package; }); 18 | 19 | nix = lib.optionalAttrs (args ? osConfig) { 20 | package = lib.mkForce args.osConfig.nix.package; 21 | }; 22 | }; 23 | } 24 | -------------------------------------------------------------------------------- /modules/fonts.nix: -------------------------------------------------------------------------------- 1 | { 2 | homeModule = { pkgs, ... }: { 3 | home.packages = 4 | builtins.attrValues { inherit (pkgs) dejavu_fonts noto-fonts-cjk-sans; }; 5 | 6 | # Allow fonts to be specified in `home.packages` 7 | fonts.fontconfig.enable = true; 8 | }; 9 | } 10 | -------------------------------------------------------------------------------- /modules/gaming.nix: -------------------------------------------------------------------------------- 1 | { 2 | imports = [ "personal" ]; 3 | 4 | nixosModule = { 5 | services.xserver.inputClassSections = ['' 6 | Identifier "CTL-472" 7 | MatchProduct "Wacom One" 8 | Option "TransformationMatrix" "0.5381253317409767 0 0.02466001733346604 0 1.1986436400914755 0.11744785505874931 0 0 1" 9 | '']; 10 | 11 | programs.steam.enable = true; 12 | }; 13 | 14 | homeModule = { pkgs, ... }: { 15 | home.packages = 16 | builtins.attrValues { inherit (pkgs) lutris prismlauncher; }; 17 | }; 18 | } 19 | -------------------------------------------------------------------------------- /modules/ghostty.nix: -------------------------------------------------------------------------------- 1 | { 2 | # OS modules are required for running `ranger` as `root` 3 | nixosModule = { pkgs, ... }: { 4 | environment.systemPackages = [ pkgs.ghostty.terminfo ]; 5 | }; 6 | 7 | darwinModule = { pkgs, ... }: { 8 | environment.systemPackages = [ pkgs.ghostty-bin.terminfo ]; 9 | }; 10 | 11 | homeModule = { pkgs, lib, ... }: { 12 | programs.ghostty.package = if pkgs.stdenv.hostPlatform.isDarwin then 13 | pkgs.ghostty-bin 14 | else 15 | pkgs.ghostty; 16 | programs.ghostty.settings = { 17 | theme = "hybrid-krompus"; 18 | bold-is-bright = true; 19 | 20 | quit-after-last-window-closed = true; 21 | 22 | auto-update = lib.mkIf pkgs.stdenv.hostPlatform.isDarwin "off"; 23 | }; 24 | 25 | programs.ghostty.themes.hybrid-krompus = { 26 | palette = [ 27 | # black 28 | "0=#0a0a0a" 29 | "8=#73645d" 30 | 31 | # red 32 | "1=#e61f00" 33 | "9=#ff3f3d" 34 | 35 | # green 36 | "2=#6dd200" 37 | "10=#c1ff05" 38 | 39 | # yellow 40 | "3=#fa6800" 41 | "11=#ffa726" 42 | 43 | # blue 44 | "4=#255ae4" 45 | "12=#00ccff" 46 | 47 | # magenta 48 | "5=#ff0084" 49 | "13=#ff65a0" 50 | 51 | # cyan 52 | "6=#36fcd3" 53 | "14=#96ffe3" 54 | 55 | # white 56 | "7=#b6afab" 57 | "15=#fff5ed" 58 | ]; 59 | background = "0d0c0c"; 60 | foreground = "fff5ed"; 61 | cursor-color = "00ccff"; 62 | }; 63 | }; 64 | } 65 | -------------------------------------------------------------------------------- /modules/graphical-minimal.nix: -------------------------------------------------------------------------------- 1 | { 2 | imports = [ "firefox" "fonts" "greetd" ]; 3 | 4 | darwinModule = { user, pkgs, ... }: { 5 | environment.systemPackages = 6 | builtins.attrValues { inherit (pkgs) rectangle; }; 7 | 8 | launchd.user.agents.rectangle = { 9 | command = 10 | ''"/Applications/Nix Apps/Rectangle.app/Contents/MacOS/Rectangle"''; 11 | serviceConfig.RunAtLoad = true; 12 | }; 13 | 14 | # Close Terminal if shell exited cleanly 15 | system.activationScripts.extraActivation.text = '' 16 | if [[ -f ~${user}/Library/Preferences/com.apple.Terminal.plist ]]; then 17 | sudo -u ${user} plutil -replace "Window Settings.Basic.shellExitAction" -integer 1 ~${user}/Library/Preferences/com.apple.Terminal.plist 18 | fi 19 | ''; 20 | 21 | # WORKAROUND: Screensaver starts on the login screen and cannot be closed from VNC 22 | system.defaults.CustomSystemPreferences."/Library/Preferences/com.apple.screensaver".loginWindowIdleTime = 23 | 0; 24 | 25 | system.defaults.screencapture.location = "~/Pictures/Screenshots"; 26 | 27 | system.defaults.NSGlobalDomain.NSAutomaticCapitalizationEnabled = false; 28 | 29 | # disable `Add full stop with double-space` 30 | system.defaults.NSGlobalDomain.NSAutomaticPeriodSubstitutionEnabled = false; 31 | 32 | system.defaults.dock.autohide = true; 33 | }; 34 | 35 | nixosModule = { pkgs, ... }: { 36 | environment.systemPackages = 37 | builtins.attrValues { inherit (pkgs) gparted pavucontrol; }; 38 | 39 | services.xserver.enable = true; 40 | 41 | services.pulseaudio.enable = false; 42 | services.pipewire.enable = true; 43 | services.pipewire.alsa.enable = true; 44 | services.pipewire.alsa.support32Bit = true; 45 | services.pipewire.pulse.enable = true; 46 | }; 47 | } 48 | 49 | -------------------------------------------------------------------------------- /modules/graphical.nix: -------------------------------------------------------------------------------- 1 | let 2 | shared = { 3 | programs._1password-gui.enable = true; 4 | programs._1password.enable = true; 5 | }; 6 | in { 7 | imports = [ "graphical-minimal" "mpv" ]; 8 | 9 | darwinModule = { pkgs, lib, ... }: { 10 | imports = [ shared ]; 11 | 12 | environment.systemPackages = builtins.attrValues { 13 | inherit (pkgs) alt-tab-macos raycast utm zed-editor; 14 | }; 15 | 16 | launchd.user.agents.raycast = { 17 | command = ''"/Applications/Nix Apps/Raycast.app/Contents/MacOS/Raycast"''; 18 | serviceConfig.RunAtLoad = true; 19 | }; 20 | 21 | services.karabiner-elements.enable = true; 22 | 23 | launchd.user.agents.alt-tab = { 24 | command = ''"/Applications/Nix Apps/AltTab.app/Contents/MacOS/AltTab"''; 25 | serviceConfig.RunAtLoad = true; 26 | }; 27 | 28 | system.defaults.CustomUserPreferences."com.lwouis.alt-tab-macos" = { 29 | SUAutomaticallyUpdate = false; 30 | SUEnableAutomaticChecks = false; 31 | updatePolicy = 0; 32 | 33 | alignThumbnails = true; 34 | # Took a lot of debugging to figure this out 35 | # plutil -type hideSpaceNumberLabels ~/Library/Preferences/com.lwouis.alt-tab-macos.plist 36 | hideSpaceNumberLabels = "true"; 37 | # Only show windows from current space 38 | spacesToShow = 1; 39 | hideWindowlessApps = "true"; 40 | holdShortcut = "\\u2318"; 41 | startAtLogin = "false"; 42 | 43 | blacklist = lib.generators.toJSON { } [ 44 | { 45 | "bundleIdentifier" = "com.apple.finder"; 46 | "hide" = "2"; 47 | "ignore" = "0"; 48 | } 49 | { 50 | "bundleIdentifier" = "com.apple.ScreenSharing"; 51 | "hide" = "0"; 52 | "ignore" = "2"; 53 | } 54 | { 55 | "bundleIdentifier" = "com.utmapp.UTM"; 56 | "hide" = "0"; 57 | "ignore" = "2"; 58 | } 59 | { 60 | "bundleIdentifier" = "com.apple.Terminal"; 61 | "hide" = "2"; 62 | "ignore" = "0"; 63 | } 64 | ]; 65 | }; 66 | }; 67 | 68 | nixosModule = { user, pkgs, lib, ... }: { 69 | imports = [ shared ]; 70 | 71 | environment.systemPackages = lib.mkIf pkgs.stdenv.hostPlatform.isx86_64 72 | (builtins.attrValues { inherit (pkgs) spotify-tray; }); 73 | 74 | programs._1password-gui.polkitPolicyOwners = [ user ]; 75 | }; 76 | 77 | homeModule = { config, pkgs, lib, ... }: 78 | let 79 | inherit (pkgs.stdenv) hostPlatform; 80 | inherit (lib) optionalAttrs; 81 | in { 82 | home.packages = builtins.attrValues ({ 83 | inherit (pkgs) qalculate-gtk remmina signal-desktop-bin; 84 | } // optionalAttrs (!hostPlatform.isLinux || !hostPlatform.isAarch64) { 85 | # Works on every platform except `aarch64-linux` 86 | # Spotify is only necessary for the icons on Linux 87 | inherit (pkgs) spotify; 88 | }); 89 | 90 | home.persistence."/persist${config.home.homeDirectory}" = { 91 | directories = [ ".config/1Password" ]; 92 | }; 93 | 94 | programs.ghostty.enable = true; 95 | 96 | programs.vscode.package = pkgs.vscode; 97 | 98 | home.file.".ssh/config".text = let 99 | _1password-agent = if hostPlatform.isDarwin then 100 | "~/Library/Group Containers/2BUA8C4S2C.com.1password/t/agent.sock" 101 | else 102 | "~/.1password/agent.sock"; 103 | in '' 104 | Match host * exec "test -z $SSH_CONNECTION" 105 | IdentityAgent "${_1password-agent}" 106 | ForwardAgent yes 107 | 108 | Host * 109 | ServerAliveInterval 120 110 | ''; 111 | 112 | programs.firefox.profiles.base.isDefault = false; 113 | 114 | programs.firefox.profiles.personal = { 115 | id = 1; 116 | 117 | inherit (config.programs.firefox.profiles.base) settings; 118 | 119 | search = { 120 | inherit (config.programs.firefox.profiles.base.search) 121 | default engines force; 122 | }; 123 | 124 | extensions.packages = 125 | config.programs.firefox.profiles.base.extensions.packages ++ [ 126 | pkgs.firefox-addons.copy-selected-links 127 | pkgs.firefox-addons.ff2mpv 128 | pkgs.firefox-addons.hover-zoom-plus 129 | pkgs.firefox-addons.improved-tube 130 | pkgs.firefox-addons.multi-account-containers 131 | pkgs.firefox-addons.old-reddit-redirect 132 | pkgs.firefox-addons.reddit-enhancement-suite 133 | pkgs.firefox-addons.redirector 134 | pkgs.firefox-addons.sponsorblock 135 | pkgs.firefox-addons.tetrio-plus 136 | pkgs.firefox-addons.translate-web-pages 137 | pkgs.firefox-addons.tree-style-tab 138 | pkgs.firefox-addons.tst-wheel-and-double 139 | pkgs.firefox-addons.web-archives 140 | ]; 141 | 142 | # Disable tab bar when using vertical tabs 143 | userChrome = '' 144 | #TabsToolbar { visibility: collapse !important; } 145 | ''; 146 | }; 147 | 148 | programs.firefox.profiles.work = { 149 | id = 2; 150 | 151 | inherit (config.programs.firefox.profiles.base) settings; 152 | 153 | search = { 154 | inherit (config.programs.firefox.profiles.base.search) 155 | default engines force; 156 | }; 157 | 158 | extensions.packages = 159 | config.programs.firefox.profiles.base.extensions.packages ++ [ 160 | pkgs.firefox-addons.multi-account-containers 161 | pkgs.firefox-addons.open-url-in-container 162 | ]; 163 | }; 164 | }; 165 | } 166 | -------------------------------------------------------------------------------- /modules/greetd.nix: -------------------------------------------------------------------------------- 1 | { 2 | nixosModule = { pkgs, lib, ... }: { 3 | services.greetd.enable = true; 4 | programs.regreet.enable = true; 5 | 6 | programs.regreet.font.name = "DejaVu Sans"; 7 | programs.regreet.font.size = 12; 8 | programs.regreet.font.package = pkgs.dejavu_fonts; 9 | 10 | services.greetd.settings.default_session.command = 11 | "${lib.getExe' pkgs.dbus "dbus-run-session"} ${ 12 | lib.getExe pkgs.sway 13 | } --config ${ 14 | pkgs.writeText "greetd-sway-config" '' 15 | exec "${lib.getExe pkgs.wayvnc} &" 16 | exec "${lib.getExe pkgs.greetd.regreet}; swaymsg exit" 17 | 18 | include /etc/sway/config.d/* 19 | '' 20 | }"; 21 | 22 | users.users.greeter.home = "/var/greeter"; 23 | users.users.greeter.createHome = true; 24 | 25 | home-manager.users.greeter = { 26 | # As we don't open the firewall, it should only be accessible over Tailscale 27 | xdg.configFile."wayvnc/config".text = '' 28 | address=0.0.0.0 29 | ''; 30 | 31 | home.stateVersion = "24.11"; 32 | }; 33 | }; 34 | } 35 | -------------------------------------------------------------------------------- /modules/i18n.nix: -------------------------------------------------------------------------------- 1 | { 2 | homeModule = { pkgs, lib, ... }: 3 | lib.mkIf pkgs.stdenv.hostPlatform.isLinux { 4 | i18n.inputMethod.enable = true; 5 | i18n.inputMethod.type = "fcitx5"; 6 | i18n.inputMethod.fcitx5.addons = 7 | builtins.attrValues { inherit (pkgs) fcitx5-unikey; }; 8 | 9 | xdg.configFile."fcitx5/profile".force = true; 10 | xdg.configFile."fcitx5/profile".text = '' 11 | [Groups/0] 12 | Name=Default 13 | Default Layout=us 14 | DefaultIM=unikey 15 | 16 | [Groups/0/Items/0] 17 | Name=keyboard-us 18 | Layout= 19 | 20 | [Groups/0/Items/1] 21 | Name=unikey 22 | Layout= 23 | 24 | [GroupOrder] 25 | 0=Default 26 | ''; 27 | }; 28 | } 29 | -------------------------------------------------------------------------------- /modules/i3-sway.nix: -------------------------------------------------------------------------------- 1 | { 2 | imports = [ "graphical-minimal" ]; 3 | 4 | nixosModule = { 5 | # Allows storage devices to be controlled over D-Bus 6 | services.udisks2.enable = true; 7 | # Used as an abstraction over udisks2 by file managers 8 | services.gvfs.enable = true; 9 | 10 | services.gnome.gnome-keyring.enable = true; 11 | programs.seahorse.enable = true; 12 | programs.evince.enable = true; 13 | }; 14 | 15 | homeModule = { config, pkgs, lib, ... }: 16 | let 17 | sharedConfig = { 18 | bars = [ ]; 19 | 20 | window = { 21 | titlebar = false; 22 | border = 1; 23 | }; 24 | 25 | colors = { 26 | focused = { 27 | border = "#4c7899"; 28 | background = "#e61f00"; 29 | text = "#ffffff"; 30 | indicator = "#00ccff"; 31 | childBorder = "#e61f00"; 32 | }; 33 | focusedInactive = { 34 | border = "#333333"; 35 | background = "#0a0a0a"; 36 | text = "#ffffff"; 37 | indicator = "#484e50"; 38 | childBorder = "#0a0a0a"; 39 | }; 40 | unfocused = { 41 | border = "#333333"; 42 | background = "#0d0c0c"; 43 | text = "#888888"; 44 | indicator = "#292d2e"; 45 | childBorder = "#0d0c0c"; 46 | }; 47 | }; 48 | 49 | modifier = "Mod1"; 50 | 51 | keybindings = let mod = sharedConfig.modifier; 52 | in { 53 | "XF86AudioMute" = "exec ${lib.getExe pkgs.pamixer} -t"; 54 | "XF86AudioLowerVolume" = "exec ${lib.getExe pkgs.pamixer} -d 5"; 55 | "XF86AudioRaiseVolume" = "exec ${lib.getExe pkgs.pamixer} -i 5"; 56 | 57 | "${mod}+Return" = "exec ${lib.getExe pkgs.alacritty}"; 58 | 59 | "Mod4+e" = "exec ${lib.getExe pkgs.powermenu}"; 60 | 61 | "${mod}+Shift+q" = "kill"; 62 | "${mod}+d" = "exec ${lib.getExe' pkgs.bemenu "bemenu-run"} -l 30"; 63 | 64 | "Control+${mod}+Left" = "focus output left"; 65 | "Control+${mod}+Right" = "focus output right"; 66 | 67 | "${mod}+Left" = "focus left"; 68 | "${mod}+Down" = "focus down"; 69 | "${mod}+Up" = "focus up"; 70 | "${mod}+Right" = "focus right"; 71 | 72 | "Control+${mod}+h" = "focus output left"; 73 | "Control+${mod}+l" = "focus output right"; 74 | 75 | "${mod}+h" = "focus left"; 76 | "${mod}+j" = "focus down"; 77 | "${mod}+k" = "focus up"; 78 | "${mod}+l" = "focus right"; 79 | 80 | "Control+${mod}+Shift+Left" = 81 | "move container to output left; focus output left"; 82 | "Control+${mod}+Shift+Right" = 83 | "move container to output right; focus output right"; 84 | 85 | "${mod}+Shift+Left" = "move left"; 86 | "${mod}+Shift+Down" = "move down"; 87 | "${mod}+Shift+Up" = "move up"; 88 | "${mod}+Shift+Right" = "move right"; 89 | 90 | "Control+${mod}+Shift+h" = 91 | "move container to output left; focus output left"; 92 | "Control+${mod}+Shift+l" = 93 | "move container to output right; focus output right"; 94 | 95 | "${mod}+Shift+h" = "move left"; 96 | "${mod}+Shift+j" = "move down"; 97 | "${mod}+Shift+k" = "move up"; 98 | "${mod}+Shift+l" = "move right"; 99 | 100 | "${mod}+Shift+v" = "split h"; 101 | "${mod}+v" = "split v"; 102 | "${mod}+f" = "fullscreen toggle"; 103 | 104 | "${mod}+s" = "layout stacking"; 105 | "${mod}+w" = "layout tabbed"; 106 | "${mod}+e" = "layout toggle split"; 107 | 108 | "${mod}+Shift+space" = "floating toggle"; 109 | "${mod}+space" = "focus mode_toggle"; 110 | 111 | "${mod}+a" = "focus parent"; 112 | 113 | "${mod}+o" = "mode osu"; 114 | "${mod}+r" = "mode resize"; 115 | }; 116 | 117 | modes = { 118 | osu = { End = "mode default"; }; 119 | resize = { 120 | h = "resize shrink width 2 px or 2 ppt"; 121 | j = "resize grow height 2 px or 2 ppt"; 122 | k = "resize shrink height 2 px or 2 ppt"; 123 | l = "resize grow width 2 px or 2 ppt"; 124 | 125 | Left = "resize shrink width 2 px or 2 ppt"; 126 | Down = "resize grow height 2 px or 2 ppt"; 127 | Up = "resize shrink height 2 px or 2 ppt"; 128 | Right = "resize grow width 2 px or 2 ppt"; 129 | 130 | "Shift+h" = "resize shrink width 20 px or 20 ppt"; 131 | "Shift+j" = "resize grow height 20 px or 20 ppt"; 132 | "Shift+k" = "resize shrink height 20 px or 20 ppt"; 133 | "Shift+l" = "resize grow width 20 px or 20 ppt"; 134 | 135 | "Shift+Left" = "resize shrink width 20 px or 20 ppt"; 136 | "Shift+Down" = "resize grow height 20 px or 20 ppt"; 137 | "Shift+Up" = "resize shrink height 20 px or 20 ppt"; 138 | "Shift+Right" = "resize grow width 20 px or 20 ppt"; 139 | 140 | Escape = "mode default"; 141 | }; 142 | }; 143 | }; 144 | in { 145 | xsession.windowManager.i3.config = sharedConfig; 146 | wayland.windowManager.sway.config = sharedConfig; 147 | 148 | home.packages = builtins.attrValues { 149 | inherit (pkgs) bemenu powermenu; 150 | inherit (pkgs.xfce) thunar; 151 | }; 152 | 153 | programs.alacritty.enable = true; 154 | programs.feh.enable = true; 155 | services.udiskie.enable = true; 156 | 157 | programs.feh = { 158 | buttons = { 159 | zoom_in = 4; 160 | zoom_out = 5; 161 | }; 162 | 163 | keybindings = { 164 | save_image = null; 165 | delete = null; 166 | }; 167 | }; 168 | 169 | systemd.user.services.pantheon-polkit-agent = { 170 | Unit = { 171 | Description = "Pantheon Polkit Agent"; 172 | After = [ "graphical-session-pre.target" ]; 173 | PartOf = [ "graphical-session.target" ]; 174 | }; 175 | 176 | Install = { WantedBy = [ "graphical-session.target" ]; }; 177 | 178 | Service = { 179 | ExecStart = 180 | "${pkgs.pantheon.pantheon-agent-polkit}/libexec/policykit-1-pantheon/io.elementary.desktop.agent-polkit"; 181 | Restart = "on-failure"; 182 | }; 183 | }; 184 | 185 | home.persistence."/persist${config.home.homeDirectory}" = { 186 | directories = [ ".local/share/keyrings" ]; 187 | }; 188 | }; 189 | } 190 | -------------------------------------------------------------------------------- /modules/i3.nix: -------------------------------------------------------------------------------- 1 | { 2 | imports = [ "i3-sway" ]; 3 | 4 | nixosModule = { 5 | services.displayManager.defaultSession = "none+i3"; 6 | services.xserver.windowManager.i3.enable = true; 7 | 8 | # Some D-Bus errors were occuring on `switch` without this line 9 | programs.dconf.enable = true; 10 | }; 11 | 12 | homeModule = { config, pkgs, lib, configRevision, ... }: { 13 | home.packages = 14 | builtins.attrValues { inherit (pkgs) xclip fira-mono font-awesome_5; }; 15 | 16 | xsession.windowManager.i3.enable = true; 17 | services.redshift.enable = true; 18 | services.polybar.enable = true; 19 | services.screen-locker.enable = true; 20 | 21 | xsession.windowManager.i3.config = { 22 | startup = [ 23 | { 24 | command = "systemctl --user restart polybar"; 25 | always = true; 26 | notification = false; 27 | } 28 | { 29 | command = "1password"; 30 | notification = false; 31 | } 32 | { 33 | command = "systemctl --user start i3-session.target"; 34 | notification = false; 35 | } 36 | ]; 37 | 38 | floating.criteria = [{ "instance" = "^floating$"; }]; 39 | 40 | keybindings = let 41 | mod = config.xsession.windowManager.i3.config.modifier; 42 | screenshotFilename = 43 | "${config.xdg.userDirs.pictures}/Screenshots/$(date +%y-%m-%d_%H-%M-%S).png"; 44 | i3-ws = lib.getExe pkgs.i3-ws; 45 | maim = lib.getExe pkgs.maim; 46 | xdotool = lib.getExe pkgs.xdotool; 47 | in { 48 | "Control+Shift+2" = 49 | "exec bash -c '${maim} -i $(${xdotool} getactivewindow) ${screenshotFilename}'"; 50 | "Control+Shift+3" = "exec bash -c '${maim} ${screenshotFilename}'"; 51 | "Control+Shift+4" = "exec bash -c '${maim} -s ${screenshotFilename}'"; 52 | 53 | # `xkill` will fail to grab the cursor if executed on button press 54 | # WORKAROUND: https://www.reddit.com/r/i3wm/wiki/faq/screenshot_binding 55 | "Control+Mod4+${mod}+q" = 56 | "--release exec ${lib.getExe pkgs.xorg.xkill}"; 57 | 58 | # When pressing the keybinding too fast, `i3lock` will turn the screen back on 59 | "Mod4+l" = "--release exec ${lib.getExe pkgs.xorg.xset} dpms force off"; 60 | 61 | "${mod}+Shift+Return" = "exec ${ 62 | lib.getExe pkgs.alacritty 63 | } -o 'window.class.instance=\"floating\"'"; 64 | 65 | # switch between workspaces on the current monitor 66 | "${mod}+1" = "exec ${i3-ws} --ws 1"; 67 | "${mod}+2" = "exec ${i3-ws} --ws 2"; 68 | "${mod}+3" = "exec ${i3-ws} --ws 3"; 69 | "${mod}+4" = "exec ${i3-ws} --ws 4"; 70 | "${mod}+5" = "exec ${i3-ws} --ws 5"; 71 | "${mod}+6" = "exec ${i3-ws} --ws 6"; 72 | "${mod}+7" = "exec ${i3-ws} --ws 7"; 73 | "${mod}+8" = "exec ${i3-ws} --ws 8"; 74 | "${mod}+9" = "exec ${i3-ws} --ws 9"; 75 | "${mod}+0" = "exec ${i3-ws} --ws 10"; 76 | 77 | "${mod}+Shift+1" = "exec ${i3-ws} --ws --shift 1"; 78 | "${mod}+Shift+2" = "exec ${i3-ws} --ws --shift 2"; 79 | "${mod}+Shift+3" = "exec ${i3-ws} --ws --shift 3"; 80 | "${mod}+Shift+4" = "exec ${i3-ws} --ws --shift 4"; 81 | "${mod}+Shift+5" = "exec ${i3-ws} --ws --shift 5"; 82 | "${mod}+Shift+6" = "exec ${i3-ws} --ws --shift 6"; 83 | "${mod}+Shift+7" = "exec ${i3-ws} --ws --shift 7"; 84 | "${mod}+Shift+8" = "exec ${i3-ws} --ws --shift 8"; 85 | "${mod}+Shift+9" = "exec ${i3-ws} --ws --shift 9"; 86 | "${mod}+Shift+0" = "exec ${i3-ws} --ws --shift 10"; 87 | 88 | # switch monitors 89 | "Control+${mod}+1" = "exec ${i3-ws} 1"; 90 | "Control+${mod}+2" = "exec ${i3-ws} 2"; 91 | "Control+${mod}+3" = "exec ${i3-ws} 3"; 92 | "Control+${mod}+4" = "exec ${i3-ws} 4"; 93 | "Control+${mod}+5" = "exec ${i3-ws} 5"; 94 | "Control+${mod}+6" = "exec ${i3-ws} 6"; 95 | "Control+${mod}+7" = "exec ${i3-ws} 7"; 96 | "Control+${mod}+8" = "exec ${i3-ws} 8"; 97 | "Control+${mod}+9" = "exec ${i3-ws} 9"; 98 | "Control+${mod}+0" = "exec ${i3-ws} 10"; 99 | 100 | "Control+${mod}+Shift+1" = "exec ${i3-ws} --shift 1"; 101 | "Control+${mod}+Shift+2" = "exec ${i3-ws} --shift 2"; 102 | "Control+${mod}+Shift+3" = "exec ${i3-ws} --shift 3"; 103 | "Control+${mod}+Shift+4" = "exec ${i3-ws} --shift 4"; 104 | "Control+${mod}+Shift+5" = "exec ${i3-ws} --shift 5"; 105 | "Control+${mod}+Shift+6" = "exec ${i3-ws} --shift 6"; 106 | "Control+${mod}+Shift+7" = "exec ${i3-ws} --shift 7"; 107 | "Control+${mod}+Shift+8" = "exec ${i3-ws} --shift 8"; 108 | "Control+${mod}+Shift+9" = "exec ${i3-ws} --shift 9"; 109 | "Control+${mod}+Shift+0" = "exec ${i3-ws} --shift 10"; 110 | 111 | "${mod}+Shift+c" = "reload"; 112 | "${mod}+Shift+r" = "restart"; 113 | }; 114 | }; 115 | 116 | services.polybar.package = pkgs.polybar.override { i3Support = true; }; 117 | services.polybar.script = '' 118 | polybar centre & 119 | ''; 120 | services.polybar.config = { 121 | "bar/base" = { 122 | width = "100%"; 123 | height = 27; 124 | background = "#0d0c0c"; 125 | foreground = "#fff5ed"; 126 | 127 | font-0 = "Fira Mono:pixelsize=10;1"; 128 | font-1 = "Font Awesome 5 Free:style=Solid:pixelsize=10;1"; 129 | 130 | modules-left = "i3"; 131 | modules-right = "dotfiles wireless ethernet fs memory date"; 132 | 133 | module-margin-left = 2; 134 | module-margin-right = 2; 135 | 136 | scroll-up = "#i3.prev"; 137 | scroll-down = "#i3.next"; 138 | }; 139 | 140 | "bar/centre" = { 141 | "inherit" = "bar/base"; 142 | tray-position = "right"; 143 | }; 144 | 145 | "module/i3" = { 146 | type = "internal/i3"; 147 | pin-workspaces = true; 148 | wrapping-scroll = false; 149 | label-mode-padding = 2; 150 | label-mode-foreground = "#000000"; 151 | label-mode-background = "#ffb52a"; 152 | label-focused = "%index%"; 153 | label-focused-background = "#fff"; 154 | label-focused-foreground = "#000"; 155 | label-focused-padding = 2; 156 | 157 | label-unfocused = "%index%"; 158 | label-unfocused-padding = 2; 159 | 160 | label-visible = "%index%"; 161 | label-visible-background = "#292929"; 162 | label-visible-padding = 2; 163 | 164 | label-urgent = "%index%"; 165 | label-urgent-background = "#ff3f3d"; 166 | label-urgent-padding = 2; 167 | }; 168 | 169 | "module/memory" = { 170 | type = "internal/memory"; 171 | label = "RAM %percentage_used%% F%gb_free%"; 172 | }; 173 | 174 | "module/date" = { 175 | type = "internal/date"; 176 | date = "%a %b %d"; 177 | time = "%I:%M:%S %p"; 178 | label = "%date% %time%"; 179 | format-background = "#292929"; 180 | format-padding = 3; 181 | }; 182 | 183 | "module/fs" = { 184 | type = "internal/fs"; 185 | interval = 1; 186 | mount-0 = "/"; 187 | label-mounted = "%mountpoint% %percentage_used%% F%free%"; 188 | }; 189 | 190 | "module/ethernet" = { 191 | type = "internal/network"; 192 | interface = "enp34s0"; 193 | label-connected = "E:%downspeed% %upspeed%"; 194 | label-disconnected = "E: Disconnected"; 195 | }; 196 | 197 | "module/wireless" = { 198 | type = "internal/network"; 199 | interface = "wlo1"; 200 | }; 201 | 202 | "module/dotfiles" = { 203 | type = "custom/script"; 204 | exec = "${pkgs.writeShellScript "latest-dotfiles" '' 205 | # necessary for `nixos-version` to find `cat`... 206 | export PATH=${pkgs.coreutils}/bin:$PATH 207 | 208 | # get latest commit hash for dotfiles 209 | LATEST=$(${ 210 | lib.getExe pkgs.curl 211 | } -s https://github.com/Enzime/dotfiles-nix/commit/HEAD.patch | ${ 212 | lib.getExe' pkgs.coreutils "head" 213 | } -n 1 | ${lib.getExe' pkgs.coreutils "cut"} -d ' ' -f 2) 214 | 215 | # get commit hash of currently running dotfiles 216 | RUNNING=${configRevision.full} 217 | 218 | UPDATE_FOUND=false 219 | 220 | if [[ $RUNNING == "dirty-inputs" ]]; then 221 | echo  $RUNNING 222 | exit 223 | fi 224 | 225 | export GIT_DIR=~/.config/home-manager/.git 226 | if ! ${ 227 | lib.getExe pkgs.git 228 | } merge-base --is-ancestor $LATEST ''${RUNNING%-dirty} 2>/dev/null; then 229 | UPDATE_FOUND=true 230 | fi 231 | 232 | if [[ $UPDATE_FOUND == "true" ]]; then 233 | echo  $(echo $LATEST | cut -c -7) 234 | else 235 | echo  ${configRevision.short} 236 | fi 237 | ''}"; 238 | interval = 300; 239 | }; 240 | }; 241 | 242 | services.redshift = { 243 | temperature = { 244 | day = 5700; 245 | night = 3500; 246 | }; 247 | latitude = "-38.0"; 248 | longitude = "145.2"; 249 | }; 250 | 251 | services.screen-locker.lockCmd = "${lib.getExe pkgs.i3lock} -n -c 000000"; 252 | services.screen-locker.xautolock.enable = false; 253 | 254 | systemd.user.targets.tray = { 255 | Unit = { 256 | Description = "Home Manager System Tray"; 257 | Requires = [ "graphical-session-pre.target" ]; 258 | }; 259 | }; 260 | 261 | systemd.user.targets.i3-session = { 262 | Unit = { 263 | Description = "i3 window manager session"; 264 | Wants = [ "graphical-session-pre.target" ]; 265 | After = [ "graphical-session-pre.target" ]; 266 | BindsTo = [ "graphical-session.target" ]; 267 | }; 268 | }; 269 | 270 | systemd.user.services.xss-lock = 271 | assert !config.services.screen-locker ? systemdTarget; 272 | lib.mkIf config.services.screen-locker.enable (lib.mkForce { 273 | Unit.PartOf = [ "i3-session.target" ]; 274 | Install.WantedBy = [ "i3-session.target" ]; 275 | }); 276 | 277 | systemd.user.services.polybar.Unit.PartOf = 278 | assert !config.services.polybar ? systemdTarget; 279 | lib.mkForce [ "i3-session.target" ]; 280 | systemd.user.services.polybar.Install.WantedBy = 281 | assert !config.services.polybar ? systemdTarget; 282 | lib.mkForce [ "i3-session.target" ]; 283 | }; 284 | } 285 | -------------------------------------------------------------------------------- /modules/impermanence.nix: -------------------------------------------------------------------------------- 1 | { 2 | nixosModule = { config, user, host, pkgs, lib, ... }: { 3 | environment.persistence."/persist" = { 4 | enable = lib.mkForce true; 5 | hideMounts = true; 6 | directories = [ 7 | "/var/lib/nixos" 8 | "/var/lib/systemd" 9 | "/var/lib/alsa" 10 | "/var/lib/tailscale" 11 | ]; 12 | files = [ "/etc/machine-id" "/etc/zfs/zpool.cache" ]; 13 | # We need this to create `/persist/home/` for the home-manager module 14 | users.${user}.files = [ ".persist" ]; 15 | }; 16 | 17 | programs.fuse.userAllowOther = true; 18 | 19 | boot.initrd.systemd.enable = true; 20 | boot.initrd.systemd.services.rollback = { 21 | description = "Rollback ZFS datasets to a pristine state"; 22 | wantedBy = [ "initrd.target" ]; 23 | after = [ "zfs-import-rpool.service" ]; 24 | before = [ "sysroot.mount" ]; 25 | path = builtins.attrValues { inherit (pkgs) zfs; }; 26 | unitConfig.DefaultDependencies = "no"; 27 | serviceConfig.Type = "oneshot"; 28 | script = '' 29 | zfs rollback -r rpool/root@blank && echo "rollback complete" 30 | ''; 31 | }; 32 | 33 | services.openssh.hostKeys = lib.mkForce [{ 34 | path = "/persist/etc/ssh/ssh_host_ed25519_key"; 35 | type = "ed25519"; 36 | }]; 37 | 38 | services.tailscale.authKeyFile = "/persist/tailscale.key"; 39 | 40 | systemd.services.tailscaled-autoconnect.serviceConfig.ExecStartPost = 41 | lib.getExe (pkgs.writeShellApplication { 42 | name = "tailscaled-autoconnect-cleanup"; 43 | text = '' 44 | if [[ -f ${config.services.tailscale.authKeyFile} ]]; then 45 | rm -v ${config.services.tailscale.authKeyFile} 46 | fi 47 | ''; 48 | }); 49 | 50 | users.mutableUsers = false; 51 | 52 | age.secrets.password_hash.file = 53 | ../secrets/password-hash_${user}-${host}.age; 54 | 55 | users.users.${user} = { 56 | hashedPasswordFile = config.age.secrets.password_hash.path; 57 | password = lib.mkForce null; 58 | }; 59 | 60 | system.activationScripts.expire-password = lib.mkForce ""; 61 | 62 | services.syncthing.dataDir = 63 | "/persist${config.users.users.${user}.home}/Sync"; 64 | }; 65 | 66 | homeModule = { config, ... }: { 67 | home.persistence."/persist${config.home.homeDirectory}" = { 68 | directories = [ "dotfiles" "Sync" ]; 69 | files = [ ".ssh/known_hosts" ".zsh_history" ]; 70 | allowOther = true; 71 | }; 72 | 73 | # By default, zsh will use rename to atomically update `.zsh_history` 74 | # however this breaks our symlink-based persistence 75 | programs.zsh.initContent = '' 76 | setopt NO_HIST_SAVE_BY_COPY 77 | ''; 78 | }; 79 | } 80 | -------------------------------------------------------------------------------- /modules/ios.nix: -------------------------------------------------------------------------------- 1 | { 2 | nixosModule = { pkgs, ... }: { 3 | environment.systemPackages = 4 | builtins.attrValues { inherit (pkgs) libimobiledevice; }; 5 | 6 | # For connecting to iOS devices 7 | services.usbmuxd.enable = true; 8 | }; 9 | } 10 | -------------------------------------------------------------------------------- /modules/laptop.nix: -------------------------------------------------------------------------------- 1 | { 2 | imports = [ "wireless" ]; 3 | 4 | nixosModule = { config, user, pkgs, lib, ... }: { 5 | time.timeZone = lib.mkForce null; 6 | services.automatic-timezoned.enable = true; 7 | services.geoclue2.enableDemoAgent = lib.mkForce true; 8 | services.geoclue2.geoProviderUrl = "https://beacondb.net/v1/geolocate"; 9 | 10 | systemd.services.restore-timezone = 11 | lib.mkIf config.environment.persistence."/persist".enable { 12 | description = "Restore /etc/localtime from /persist"; 13 | wantedBy = [ "multi-user.target" ]; 14 | unitConfig.RequiresMountsFor = "/persist"; 15 | serviceConfig.Type = "oneshot"; 16 | # We want to run `ExecStop` when the computer is shutting down 17 | serviceConfig.RemainAfterExit = true; 18 | serviceConfig.ExecStart = lib.getExe (pkgs.writeShellApplication { 19 | name = "restore-timezone"; 20 | text = '' 21 | if [[ -L /persist/etc/localtime ]]; then 22 | cp -av /persist/etc/localtime /etc/localtime 23 | fi 24 | ''; 25 | }); 26 | serviceConfig.ExecStop = lib.getExe (pkgs.writeShellApplication { 27 | name = "persist-timezone"; 28 | text = '' 29 | mkdir -p /persist/etc 30 | cp -av /etc/localtime /persist/etc/localtime 31 | ''; 32 | }); 33 | }; 34 | 35 | services.libinput.enable = true; 36 | 37 | services.udev.extraHwdb = '' 38 | evdev:name:AT Translated Set 2 keyboard:dmi:* 39 | KEYBOARD_KEY_3a=esc 40 | ''; 41 | 42 | services.logind.extraConfig = '' 43 | HandlePowerKey=lock 44 | HandleLidSwitch=suspend-then-hibernate 45 | HandleLidSwitchExternalPower=lock 46 | ''; 47 | 48 | systemd.sleep.extraConfig = '' 49 | HibernateDelaySec=5m 50 | ''; 51 | 52 | programs.light.enable = true; 53 | users.users.${user}.extraGroups = [ "video" ]; 54 | 55 | programs.captive-browser.enable = true; 56 | }; 57 | 58 | darwinModule = { user, pkgs, lib, ... }: { 59 | time.timeZone = lib.mkForce null; 60 | 61 | environment.systemPackages = 62 | builtins.attrValues { inherit (pkgs) aldente ice-bar; }; 63 | 64 | launchd.user.agents.alDente = { 65 | command = ''"/Applications/Nix Apps/AlDente.app/Contents/MacOS/AlDente"''; 66 | serviceConfig.RunAtLoad = true; 67 | }; 68 | 69 | system.defaults.trackpad.Clicking = true; 70 | 71 | # WORKAROUND: Setting this via `system.defaults` won't check the checkbox 72 | # in System Preferences > Trackpad 73 | system.activationScripts.extraActivation.text = '' 74 | launchctl asuser "$(id -u ${user})" sudo -u ${user} defaults -currentHost write -g com.apple.mouse.tapBehavior -int 1 75 | 76 | nvram StartupMute=%01 77 | ''; 78 | 79 | security.pam.services.sudo_local.touchIdAuth = true; 80 | 81 | # WORKAROUND: Using Override Local DNS with tailscaled on macOS leads to 82 | # DNS not working for a long time after reconnecting to the internet. 83 | services.tailscale.overrideLocalDns = false; 84 | 85 | networking.dns = [ "1.1.1.1" ]; 86 | }; 87 | 88 | homeModule = { pkgs, lib, ... }: 89 | let 90 | inherit (lib) mkIf; 91 | inherit (pkgs.stdenv) hostPlatform; 92 | 93 | keybindings = { 94 | "XF86MonBrightnessDown" = "exec ${lib.getExe pkgs.light} -U 10"; 95 | "XF86MonBrightnessUp" = "exec ${lib.getExe pkgs.light} -A 10"; 96 | }; 97 | in mkIf hostPlatform.isLinux { 98 | wayland.windowManager.sway.config.input = { 99 | "type:touchpad" = { tap = "enabled"; }; 100 | }; 101 | 102 | xsession.windowManager.i3.config.keybindings = keybindings; 103 | wayland.windowManager.sway.config.keybindings = keybindings; 104 | 105 | services.polybar.config = { 106 | "bar/base" = { 107 | modules-right = 108 | lib.mkForce "dotfiles battery wireless ethernet fs memory date"; 109 | }; 110 | 111 | "module/battery" = { 112 | type = "internal/battery"; 113 | full-at = 98; 114 | 115 | time-format = "%H:%M"; 116 | 117 | label-discharging = "DIS %percentage%% %time% remaining"; 118 | label-charging = "CHG %percentage%% %time% till full"; 119 | label-full = "BAT FULL 100%"; 120 | }; 121 | }; 122 | }; 123 | } 124 | -------------------------------------------------------------------------------- /modules/linux-builder.nix: -------------------------------------------------------------------------------- 1 | { 2 | darwinModule = { host, keys, options, config, extendModules, pkgs, lib, ... }: 3 | let 4 | withoutLinuxBuilderVariant = extendModules { 5 | modules = [{ nix.linux-builder.enable = lib.mkForce false; }]; 6 | }; 7 | in { 8 | options = { 9 | withoutLinuxBuilder = lib.mkOption { 10 | inherit (withoutLinuxBuilderVariant) type; 11 | default = { }; 12 | visible = "shallow"; 13 | }; 14 | }; 15 | config = { 16 | nix.linux-builder.enable = true; 17 | nix.linux-builder.config = { lib, ... }: { 18 | imports = [ 19 | (import ./cache.nix).nixosModule 20 | (import ./flakes.nix).nixosModule 21 | (import ./ghostty.nix).nixosModule 22 | ]; 23 | 24 | system.build.bootstrap = pkgs.writeShellApplication { 25 | name = "bootstrap-${host}-linux-builder"; 26 | runtimeInputs = [ ]; 27 | text = '' 28 | set -x 29 | 30 | op read "op://trimcmujfu5fjcx5u4u752yk2i/${host}-linux-builder Nix signing key/key" | ssh root@linux-builder bash -c "cat > /etc/nix/key; chmod 400 /etc/nix/key" 31 | ssh root@linux-builder tailscale up 32 | ''; 33 | }; 34 | 35 | _module.args = { inherit keys; }; 36 | 37 | networking.hostName = "${host}-linux-builder"; 38 | 39 | services.tailscale.enable = true; 40 | 41 | users.users.enzime = { 42 | isNormalUser = true; 43 | extraGroups = [ "wheel" ]; 44 | 45 | openssh.authorizedKeys.keys = 46 | builtins.attrValues { inherit (keys.users) enzime; }; 47 | }; 48 | 49 | users.users.root.openssh.authorizedKeys.keys = 50 | builtins.attrValues { inherit (keys.users) enzime; }; 51 | 52 | nix.settings.secret-key-files = [ "/etc/nix/key" ]; 53 | 54 | nix.settings.trusted-users = lib.mkForce [ "root" ]; 55 | 56 | # By default NixOS and nix-darwin oversubscribe a lot (max-jobs = auto, cores = 0) 57 | # instead we would rather only oversubscribe a little bit 58 | nix.settings.cores = 2; 59 | }; 60 | 61 | nix.settings.trusted-public-keys = 62 | [ keys.signing."${host}-linux-builder" ]; 63 | }; 64 | }; 65 | } 66 | -------------------------------------------------------------------------------- /modules/macos-vm.nix: -------------------------------------------------------------------------------- 1 | { 2 | nixosModule = { inputs, pkgs, lib, modulesPath, ... }: { 3 | imports = [ (modulesPath + "/virtualisation/qemu-vm.nix") ]; 4 | 5 | virtualisation.memorySize = 3 * 1024; 6 | 7 | virtualisation.host.pkgs = import inputs.nixpkgs { 8 | system = builtins.replaceStrings [ "linux" ] [ "darwin" ] pkgs.system; 9 | inherit (pkgs) config overlays; 10 | }; 11 | 12 | services.displayManager.defaultSession = lib.mkForce "none+i3"; 13 | environment.variables.LIBGL_ALWAYS_SOFTWARE = "true"; 14 | }; 15 | } 16 | -------------------------------------------------------------------------------- /modules/mpv.nix: -------------------------------------------------------------------------------- 1 | { 2 | darwinModule = { pkgs, ... }: { 3 | environment.systemPackages = builtins.attrValues { inherit (pkgs) iina; }; 4 | }; 5 | 6 | homeModule = { pkgs, ... }: { 7 | programs.mpv.enable = true; 8 | programs.mpv.bindings = { 9 | "BS" = "cycle pause"; 10 | "SPACE" = "cycle pause"; 11 | 12 | "\\" = "set speed 1.0"; 13 | 14 | "UP" = "add volume 2"; 15 | "DOWN" = "add volume -2"; 16 | 17 | "PGUP" = "add chapter -1"; 18 | "PGDWN" = "add chapter 1"; 19 | 20 | "MOUSE_BTN3" = "add volume 2"; 21 | "MOUSE_BTN4" = "add volume -2"; 22 | 23 | "MOUSE_BTN7" = "add chapter -1"; 24 | "MOUSE_BTN8" = "add chapter 1"; 25 | 26 | "Alt+RIGHT" = "add video-rotate 90"; 27 | "Alt+LEFT" = "add video-rotate -90"; 28 | 29 | "h" = "seek -5"; 30 | "j" = "add volume -2"; 31 | "k" = "add volume 2"; 32 | "l" = "seek 5"; 33 | 34 | "Shift+LEFT" = "seek -60"; 35 | "Shift+RIGHT" = "seek +60"; 36 | 37 | "Z-Q" = "quit"; 38 | 39 | "Ctrl+h" = "add chapter -1"; 40 | "Ctrl+j" = "repeatable playlist-prev"; 41 | "Ctrl+k" = "repeatable playlist-next"; 42 | "Ctrl+l" = "add chapter 1"; 43 | 44 | "J" = "cycle sub"; 45 | "L" = "ab_loop"; 46 | 47 | "a" = "add audio-delay -0.001"; 48 | "s" = "add audio-delay +0.001"; 49 | 50 | "O" = "cycle osc; cycle osd-bar"; 51 | }; 52 | 53 | programs.mpv.config = { 54 | volume = 50; 55 | volume-max = 200; 56 | force-window = "yes"; 57 | keep-open = "yes"; 58 | osc = "no"; 59 | osd-bar = "no"; 60 | }; 61 | 62 | home.file.".mozilla/native-messaging-hosts/ff2mpv.json".source = 63 | "${pkgs.ff2mpv}/lib/mozilla/native-messaging-hosts/ff2mpv.json"; 64 | }; 65 | } 66 | -------------------------------------------------------------------------------- /modules/mullvad.nix: -------------------------------------------------------------------------------- 1 | { 2 | nixosModule = { pkgs, ... }: { 3 | services.mullvad-vpn.enable = true; 4 | # Install the GUI as well 5 | services.mullvad-vpn.package = pkgs.mullvad-vpn; 6 | }; 7 | } 8 | -------------------------------------------------------------------------------- /modules/nextcloud.nix: -------------------------------------------------------------------------------- 1 | { 2 | imports = [ "acme" ]; 3 | 4 | nixosModule = { user, config, pkgs, ... }: 5 | let hostname = "nextcloud.enzim.ee"; 6 | in { 7 | services.nextcloud.enable = true; 8 | services.nextcloud.package = pkgs.nextcloud31; 9 | services.nextcloud.hostName = hostname; 10 | services.nextcloud.settings.trusted_domains = [ "reflector.enzim.ee" ]; 11 | services.nextcloud.https = true; 12 | 13 | age.secrets.nextcloud.file = ../secrets/nextcloud.age; 14 | age.secrets.nextcloud.owner = "nextcloud"; 15 | 16 | services.nextcloud.config = { 17 | dbtype = "sqlite"; 18 | adminuser = "admin"; 19 | adminpassFile = config.age.secrets.nextcloud.path; 20 | }; 21 | 22 | age.secrets.acme_zoneee.file = ../secrets/acme_zoneee.age; 23 | 24 | security.acme.certs.${hostname} = { 25 | dnsProvider = "zoneee"; 26 | credentialsFile = config.age.secrets.acme_zoneee.path; 27 | }; 28 | 29 | services.nginx.virtualHosts.${hostname} = { 30 | forceSSL = true; 31 | useACMEHost = hostname; 32 | }; 33 | 34 | users.users.${user}.extraGroups = [ "nextcloud" ]; 35 | }; 36 | } 37 | -------------------------------------------------------------------------------- /modules/personal.nix: -------------------------------------------------------------------------------- 1 | { 2 | imports = [ "graphical" "i18n" "ios" "mullvad" "pim" ]; 3 | 4 | darwinModule = { pkgs, lib, ... }: { 5 | environment.systemPackages = 6 | builtins.attrValues { inherit (pkgs) apparency; }; 7 | 8 | launchd.user.agents.install-flighty = { 9 | command = "${lib.getExe pkgs.mas} install 1358823008"; 10 | serviceConfig.RunAtLoad = true; 11 | }; 12 | }; 13 | 14 | nixosModule = { host, lib, utils, ... }: 15 | lib.mkIf (host != "phi") { 16 | fileSystems."/mnt/phi" = { 17 | device = "enzime@phi:/"; 18 | fsType = "fuse.sshfs"; 19 | noCheck = true; 20 | options = [ 21 | "noauto" 22 | "x-systemd.automount" 23 | "_netdev" 24 | "IdentityFile=/etc/ssh/ssh_host_ed25519_key" 25 | "allow_other" 26 | "uid=1000" 27 | "gid=100" 28 | "ConnectTimeout=1" 29 | "x-systemd.mount-timeout=10s" 30 | "ServerAliveInterval=1" 31 | "ServerAliveCountMax=5" 32 | ]; 33 | }; 34 | 35 | systemd.units."${utils.escapeSystemdPath "/mnt/phi"}.mount" = { 36 | text = '' 37 | [Unit] 38 | StartLimitIntervalSec=0 39 | ''; 40 | overrideStrategy = "asDropin"; 41 | }; 42 | }; 43 | 44 | homeModule = { config, pkgs, lib, ... }: 45 | let 46 | inherit (pkgs.stdenv) hostPlatform; 47 | inherit (lib) optionalAttrs; 48 | in { 49 | home.packages = builtins.attrValues ({ 50 | inherit (pkgs) gramps; 51 | } // optionalAttrs ((hostPlatform.isLinux && hostPlatform.isx86_64) 52 | || hostPlatform.isDarwin) { 53 | # not currently built for `aarch64-linux` 54 | inherit (pkgs) joplin-desktop; 55 | } 56 | // optionalAttrs hostPlatform.isDarwin { inherit (pkgs) sequential; }); 57 | 58 | programs.firefox.profiles.personal.isDefault = true; 59 | 60 | home.persistence."/persist${config.home.homeDirectory}" = { 61 | directories = [ ".config/joplin-desktop" ".gramps" ]; 62 | }; 63 | }; 64 | } 65 | -------------------------------------------------------------------------------- /modules/pim.nix: -------------------------------------------------------------------------------- 1 | { 2 | darwinModule = { 3 | system.defaults.iCal.CalendarSidebarShown = true; 4 | system.defaults.iCal."first day of week" = "System Setting"; 5 | system.defaults.iCal."TimeZone support enabled" = true; 6 | }; 7 | 8 | nixosModule = { pkgs, ... }: { 9 | environment.systemPackages = builtins.attrValues { 10 | inherit (pkgs) gnome-calendar gnome-contacts gnome-control-center; 11 | }; 12 | 13 | services.gnome.gnome-online-accounts.enable = true; 14 | services.gnome.evolution-data-server.enable = true; 15 | }; 16 | } 17 | -------------------------------------------------------------------------------- /modules/printers.nix: -------------------------------------------------------------------------------- 1 | { 2 | imports = [ "avahi" ]; 3 | 4 | nixosModule = { 5 | services.printing.enable = true; 6 | services.printing.stateless = true; 7 | }; 8 | } 9 | -------------------------------------------------------------------------------- /modules/reflector.nix: -------------------------------------------------------------------------------- 1 | { 2 | imports = [ "acme" ]; 3 | 4 | nixosModule = { config, ... }: 5 | let hostname = "reflector.enzim.ee"; 6 | in { 7 | services.nginx.enable = true; 8 | services.nginx.recommendedTlsSettings = true; 9 | services.nginx.recommendedOptimisation = true; 10 | services.nginx.recommendedGzipSettings = true; 11 | 12 | # Forwards the Host header which is required for Nextcloud 13 | services.nginx.recommendedProxySettings = true; 14 | 15 | networking.firewall.allowedTCPPorts = [ 80 443 ]; 16 | 17 | services.nginx.virtualHosts.${hostname} = { 18 | forceSSL = true; 19 | enableACME = true; 20 | locations = { "/".proxyPass = "https://nextcloud.enzim.ee"; }; 21 | }; 22 | services.nginx.clientMaxBodySize = 23 | config.services.nextcloud.maxUploadSize; 24 | }; 25 | } 26 | -------------------------------------------------------------------------------- /modules/samba.nix: -------------------------------------------------------------------------------- 1 | { 2 | nixosModule = { user, hostname, ... }: { 3 | services.samba.enable = true; 4 | # Set password for user with `sudo smbpasswd -a ` 5 | services.samba.settings.${hostname} = { 6 | path = "/"; 7 | "read only" = "no"; 8 | "guest ok" = "no"; 9 | "create mask" = "0644"; 10 | "directory mask" = "0755"; 11 | "force user" = user; 12 | "force group" = "users"; 13 | }; 14 | }; 15 | } 16 | -------------------------------------------------------------------------------- /modules/scanners.nix: -------------------------------------------------------------------------------- 1 | { 2 | nixosModule = { user, pkgs, ... }: { 3 | hardware.sane.enable = true; 4 | 5 | users.users.${user}.extraGroups = [ "scanner" ]; 6 | 7 | environment.systemPackages = 8 | builtins.attrValues { inherit (pkgs) simple-scan; }; 9 | }; 10 | } 11 | -------------------------------------------------------------------------------- /modules/sops.nix: -------------------------------------------------------------------------------- 1 | { 2 | homeModule = { config, pkgs, lib, ... }: 3 | let 4 | platformConfigDir = if pkgs.hostPlatform.isDarwin then 5 | "Library/Application Support" 6 | else 7 | config.xdg.configHome; 8 | in { 9 | home.file."${platformConfigDir}/sops/age/keys.txt".source = lib.mkDefault 10 | (config.lib.file.mkOutOfStoreSymlink 11 | "${config.home.homeDirectory}/${platformConfigDir}/sops/age/keys.txt.1p"); 12 | 13 | home.file."${platformConfigDir}/sops/age/keys.txt.1p".text = '' 14 | # Recipient: ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAINKZfejb9htpSB5K9p0RuEowErkba2BMKaze93ZVkQIE 15 | AGE-PLUGIN-1P-1X2NELQ 16 | ''; 17 | }; 18 | } 19 | -------------------------------------------------------------------------------- /modules/sway.nix: -------------------------------------------------------------------------------- 1 | { 2 | imports = [ "i3-sway" "wayvnc" ]; 3 | 4 | nixosModule = { lib, ... }: { 5 | # Still overridable with mkForce 6 | services.displayManager.defaultSession = lib.mkOverride 75 "sway"; 7 | 8 | programs.sway.enable = true; 9 | programs.sway.extraSessionCommands = '' 10 | source /etc/profile 11 | if [[ -e /etc/profiles/per-user/$USER/etc/profile.d/hm-session-vars.sh ]]; then 12 | source /etc/profiles/per-user/$USER/etc/profile.d/hm-session-vars.sh 13 | fi 14 | ''; 15 | 16 | xdg.portal.wlr.enable = true; 17 | }; 18 | 19 | homeModule = { config, pkgs, lib, ... }: { 20 | home.packages = 21 | builtins.attrValues { inherit (pkgs) wl-clipboard font-awesome; }; 22 | 23 | home.sessionVariables = { NIXOS_OZONE_WL = 1; }; 24 | 25 | wayland.windowManager.sway.enable = true; 26 | wayland.windowManager.sway.package = null; 27 | services.swayidle.enable = true; 28 | programs.waybar.enable = true; 29 | 30 | wayland.windowManager.sway.config = { 31 | startup = [ 32 | { 33 | command = "systemctl --user restart waybar"; 34 | always = true; 35 | } 36 | { command = "1password"; } 37 | ]; 38 | 39 | floating.criteria = [{ "app_id" = "^floating$"; }]; 40 | 41 | input."type:keyboard".xkb_numlock = "enabled"; 42 | 43 | keybindings = let 44 | mod = config.wayland.windowManager.sway.config.modifier; 45 | screenshotFilename = 46 | "${config.xdg.userDirs.pictures}/Screenshots/$(date +%y-%m-%d_%H-%M-%S).png"; 47 | grim = lib.getExe pkgs.grim; 48 | swaymsg = lib.getExe' pkgs.sway "swaymsg"; 49 | jq = lib.getExe pkgs.jq; 50 | slurp = lib.getExe pkgs.slurp; 51 | in { 52 | "Control+Shift+2" = "exec ${ 53 | pkgs.writeShellScript "grim-current-window" '' 54 | REGION=$(${swaymsg} -t get_tree | ${jq} -j '.. | select(.type?) | select(.focused).rect | "\(.x),\(.y) \(.width)x\(.height)"') 55 | ${grim} -g "$REGION" ${screenshotFilename} 56 | '' 57 | }"; 58 | "Control+Shift+3" = "exec bash -c '${grim} ${screenshotFilename}'"; 59 | "Control+Shift+4" = "exec ${ 60 | pkgs.writeShellScript "grim-slurp" '' 61 | REGION=$(${swaymsg} -t get_tree | ${jq} -r '.. | select(.pid? and .visible?) | .rect | "\(.x),\(.y) \(.width)x\(.height)"' | ${slurp}) 62 | ${grim} -g "$REGION" ${screenshotFilename} 63 | '' 64 | }"; 65 | 66 | "${mod}+Shift+Return" = "exec ${ 67 | lib.getExe pkgs.alacritty 68 | } -o 'window.class.general=\"floating\"'"; 69 | 70 | "${mod}+1" = "workspace number 1"; 71 | "${mod}+2" = "workspace number 2"; 72 | "${mod}+3" = "workspace number 3"; 73 | "${mod}+4" = "workspace number 4"; 74 | "${mod}+5" = "workspace number 5"; 75 | "${mod}+6" = "workspace number 6"; 76 | "${mod}+7" = "workspace number 7"; 77 | "${mod}+8" = "workspace number 8"; 78 | "${mod}+9" = "workspace number 9"; 79 | "${mod}+0" = "workspace number 10"; 80 | 81 | "${mod}+Shift+1" = "move container to workspace number 1"; 82 | "${mod}+Shift+2" = "move container to workspace number 2"; 83 | "${mod}+Shift+3" = "move container to workspace number 3"; 84 | "${mod}+Shift+4" = "move container to workspace number 4"; 85 | "${mod}+Shift+5" = "move container to workspace number 5"; 86 | "${mod}+Shift+6" = "move container to workspace number 6"; 87 | "${mod}+Shift+7" = "move container to workspace number 7"; 88 | "${mod}+Shift+8" = "move container to workspace number 8"; 89 | "${mod}+Shift+9" = "move container to workspace number 9"; 90 | "${mod}+Shift+0" = "move container to workspace number 10"; 91 | 92 | "Mod4+l" = "exec loginctl lock-session"; 93 | 94 | "${mod}+Shift+r" = "reload"; 95 | 96 | "Ctrl+Shift+l" = "exec 1password --lock"; 97 | "Ctrl+Shift+space" = "exec 1password --quick-access"; 98 | }; 99 | }; 100 | 101 | services.swayidle.events = let 102 | loginctl = lib.getExe' pkgs.systemd "loginctl"; 103 | swaymsg = lib.getExe' pkgs.sway "swaymsg"; 104 | swaylock = lib.getExe pkgs.swaylock; 105 | # WORKAROUND: 1Password doesn't lock automatically when the screen lock is invoked under Wayland 106 | lock1Password = pkgs.writeShellScript "lock-1p" '' 107 | if ${lib.getExe' pkgs.procps "pidof"} 1password; then 108 | ${lib.getExe pkgs._1password-gui} --lock & 109 | fi 110 | ''; 111 | in [ 112 | { 113 | event = "before-sleep"; 114 | command = "${loginctl} lock-session"; 115 | } 116 | { 117 | event = "lock"; 118 | command = 119 | "${lock1Password} && ${swaylock} -f -c 000000 && ${swaymsg} output '*' dpms off"; 120 | } 121 | ]; 122 | services.swayidle.timeouts = let 123 | swaymsg = lib.getExe' pkgs.sway "swaymsg"; 124 | loginctl = lib.getExe' pkgs.systemd "loginctl"; 125 | in [ 126 | { 127 | timeout = 1; 128 | command = "exit 0"; 129 | resumeCommand = "${swaymsg} output '*' dpms on"; 130 | } 131 | { 132 | timeout = 180; 133 | command = "${loginctl} lock-session"; 134 | resumeCommand = "${swaymsg} output '*' dpms on"; 135 | } 136 | ]; 137 | services.swayidle.systemdTarget = "sway-session.target"; 138 | 139 | programs.waybar.settings = [{ 140 | modules-left = [ "sway/workspaces" "sway/mode" ]; 141 | modules-center = [ "sway/window" ]; 142 | modules-right = [ "idle_inhibitor" "battery" "clock" "tray" ]; 143 | "sway/window" = { max-length = 50; }; 144 | battery = { 145 | format = "{capacity}% {icon}"; 146 | format-icons = [ "" "" "" "" "" ]; 147 | }; 148 | clock = { 149 | format = "{:%a %b %d %I:%M:%S %p}"; 150 | interval = 1; 151 | }; 152 | idle_inhibitor = { 153 | format = "{icon}"; 154 | format-icons = { 155 | activated = ""; 156 | deactivated = ""; 157 | }; 158 | }; 159 | }]; 160 | 161 | programs.waybar.systemd.enable = true; 162 | programs.waybar.systemd.target = "sway-session.target"; 163 | 164 | systemd.user.services.polybar = lib.mkIf config.services.polybar.enable { 165 | Unit = { Conflicts = [ "sway-session.target" ]; }; 166 | }; 167 | 168 | services.mako.enable = true; 169 | services.mako.settings.default-timeout = 5000; 170 | services.mako.settings.background-color = "#0d0c0c"; 171 | services.mako.settings.border-color = "#e61f00"; 172 | services.mako.settings.padding = "10,5,10,10"; 173 | }; 174 | } 175 | -------------------------------------------------------------------------------- /modules/syncthing.nix: -------------------------------------------------------------------------------- 1 | { 2 | darwinModule = { user, hostname, pkgs, ... }: { 3 | environment.systemPackages = 4 | builtins.attrValues { inherit (pkgs) syncthing-macos; }; 5 | 6 | launchd.user.agents.syncthing = { 7 | command = 8 | ''"/Applications/Nix Apps/Syncthing.app/Contents/MacOS/Syncthing"''; 9 | serviceConfig.RunAtLoad = true; 10 | }; 11 | 12 | system.defaults.CustomUserPreferences."com.github.xor-gate.syncthing-macosx" = 13 | { 14 | SUEnableAutomaticChecks = false; 15 | SUSendProfileInfo = 0; 16 | StartAtLogin = 0; 17 | URI = "http://${hostname}:8384"; 18 | }; 19 | 20 | # Don't let Syncthing for macOS hardcode the path for `syncthing` 21 | system.activationScripts.extraActivation.text = '' 22 | if sudo -u ${user} defaults read com.github.xor-gate.syncthing-macosx Executable &>/dev/null; then 23 | sudo -u ${user} defaults delete com.github.xor-gate.syncthing-macosx Executable 24 | fi 25 | ''; 26 | }; 27 | 28 | nixosModule = { config, user, host, hostname, lib, ... }: { 29 | services.syncthing.enable = true; 30 | services.syncthing.user = user; 31 | services.syncthing.group = "users"; 32 | services.syncthing.dataDir = 33 | lib.mkDefault "${config.users.users.${user}.home}/Sync"; 34 | services.syncthing.guiAddress = "0.0.0.0:8384"; 35 | services.syncthing.overrideDevices = true; 36 | services.syncthing.overrideFolders = true; 37 | 38 | services.syncthing.settings = let 39 | mkDevice = { name, id, hostname ? name }: { 40 | ${name} = { 41 | inherit id; 42 | addresses = [ "tcp://${hostname}" ]; 43 | }; 44 | }; 45 | 46 | mkFolder = { name, devices, ... }@v: 47 | let 48 | defaultArgs = lib.recursiveUpdate { 49 | path = "${config.services.syncthing.dataDir}/${name}"; 50 | } v; 51 | mergedArgs = lib.recursiveUpdate defaultArgs devices.${hostname}; 52 | args = mergedArgs // { devices = builtins.attrNames devices; }; 53 | filteredArgs = builtins.removeAttrs args [ "name" ]; 54 | in lib.optionalAttrs (devices ? ${hostname}) { 55 | ${name} = filteredArgs; 56 | }; 57 | in { 58 | devices = lib.mkMerge (map mkDevice [ 59 | { 60 | name = "hyperion-macos"; 61 | id = 62 | "OEAWYP7-XUL5L4A-WH4PM4P-UNTIIXC-3C2LWFY-F2WPKNY-H4TFMWI-IFZSCQU"; 63 | } 64 | { 65 | name = "phi-nixos"; 66 | id = 67 | "2YEN2S7-JYISWE4-UGUF6N4-7ZNSDNX-IKLEDGT-4WLFFGV-CWB2VKG-SL3ALAP"; 68 | } 69 | { 70 | name = "sigma"; 71 | id = 72 | "MYUB4WO-KFBERW6-VC3VXYY-K32WL7S-CX7X5NP-5JZYCEE-NNLYRT5-UXWP6AP"; 73 | } 74 | { 75 | name = "eris"; 76 | id = 77 | "OSL7C3U-VQS2KVT-WRK3WTK-4XDJR2D-AGDAL3Q-PA2YPVB-QQ72LAR-EDBZPQL"; 78 | } 79 | { 80 | name = "pixel-6a"; 81 | id = 82 | "NURXDKI-MPMVCY3-24YQHHX-6PDTE47-YP6QVO3-PC47MAP-BJY6LO6-6HLJAAQ"; 83 | } 84 | ]); 85 | 86 | folders = lib.mkMerge (map mkFolder [ 87 | { 88 | id = "7y829-o47k9"; 89 | name = "Signal Backup"; 90 | devices = { 91 | phi-nixos = { 92 | path = "/data/Backup/Signal"; 93 | type = "receiveonly"; 94 | 95 | versioning = { 96 | type = "staggered"; 97 | # Keep old versions for 14 days 98 | params.maxAge = toString (14 * 24 * 60 * 60); 99 | }; 100 | }; 101 | pixel-6a = { }; 102 | }; 103 | } 104 | { 105 | id = "2odnx-6qz1l"; 106 | name = "Pictures.sigma"; 107 | devices = { 108 | phi-nixos = { 109 | path = "/data/Pictures/Pictures.sigma"; 110 | type = "receiveonly"; 111 | versioning = { 112 | type = "trashcan"; 113 | params.cleanoutDays = "14"; 114 | }; 115 | }; 116 | sigma = { 117 | path = "/persist${ 118 | config.users.users.${user}.home 119 | }/Pictures/Pictures.sigma"; 120 | }; 121 | }; 122 | } 123 | { 124 | id = "3fpud-18f7a"; 125 | name = "Screenshots.sigma"; 126 | devices = { 127 | phi-nixos = { 128 | path = "/data/Pictures/Screenshots.sigma"; 129 | type = "receiveonly"; 130 | versioning = { 131 | type = "trashcan"; 132 | params.cleanoutDays = "14"; 133 | }; 134 | }; 135 | sigma = { 136 | path = "/persist${ 137 | config.users.users.${user}.home 138 | }/Pictures/Screenshots.sigma"; 139 | }; 140 | }; 141 | } 142 | { 143 | id = "a2j2q-rjjju"; 144 | name = "Screenshots.hyperion"; 145 | devices = { 146 | # Managed manually currently 147 | hyperion-macos = { 148 | path = "${config.users.users.${user}.home}/Pictures/Screenshots"; 149 | }; 150 | phi-nixos = { 151 | path = "/data/Pictures/Screenshots.hyperion"; 152 | type = "receiveonly"; 153 | versioning = { 154 | type = "trashcan"; 155 | params.cleanoutDays = "14"; 156 | }; 157 | }; 158 | }; 159 | } 160 | { 161 | id = "dd8lo-8p1o4"; 162 | name = "Gramps"; 163 | devices = { 164 | # Managed manually currently 165 | hyperion-macos = { 166 | path = "${config.users.users.${user}.home}/.local/share/gramps"; 167 | }; 168 | phi-nixos = { 169 | path = "${config.users.users.${user}.home}/.local/share/gramps"; 170 | }; 171 | sigma = { 172 | path = "/persist${config.users.users.${user}.home}/.gramps"; 173 | }; 174 | }; 175 | versioning = { 176 | type = "simple"; 177 | # Only keep last 2 old versions 178 | params.keep = "2"; 179 | }; 180 | } 181 | ]); 182 | 183 | gui = { 184 | user = host; 185 | password = { 186 | phi = "$2a$10$CTnvJaVO1L.dluML7fTYde2bh7E5rluYCtcW5rptoabXD1U8JZZsq"; 187 | sigma = 188 | "$2a$10$wdfmhwbLNu9jSForuNG5pe2AAqL8d67G1TIa/Gk7DTO/SM6uuIZve"; 189 | eris = "$2a$10$pDw1ciPdbkXp3fhTqYBJGeO9JEcrF2EMZXVAXrn1q3cenn64lJPsO"; 190 | }.${host}; 191 | }; 192 | }; 193 | }; 194 | } 195 | -------------------------------------------------------------------------------- /modules/termite.nix: -------------------------------------------------------------------------------- 1 | { 2 | # OS modules are required for running `ranger` as `root` 3 | nixosModule = { pkgs, ... }: { 4 | environment.systemPackages = [ pkgs.termite.terminfo ]; 5 | }; 6 | 7 | darwinModule = { pkgs, ... }: { 8 | environment.systemPackages = [ pkgs.termite.terminfo ]; 9 | }; 10 | 11 | homeModule = { pkgs, ... }: { 12 | home.packages = [ pkgs.termite.terminfo ]; 13 | 14 | programs.termite = { 15 | font = "DejaVu Sans Mono 10"; 16 | scrollbackLines = -1; 17 | colorsExtra = '' 18 | # special 19 | foreground = #fff5ed 20 | foreground_bold = #fff5ed 21 | cursor = #00ccff 22 | background = #0d0c0c 23 | 24 | # black 25 | color0 = #0a0a0a 26 | color8 = #73645d 27 | 28 | # red 29 | color1 = #e61f00 30 | color9 = #ff3f3d 31 | 32 | # green 33 | color2 = #6dd200 34 | color10 = #c1ff05 35 | 36 | # yellow 37 | color3 = #fa6800 38 | color11 = #ffa726 39 | 40 | # blue 41 | color4 = #255ae4 42 | color12 = #00ccff 43 | 44 | # magenta 45 | color5 = #ff0084 46 | color13 = #ff65a0 47 | 48 | # cyan 49 | color6 = #36fcd3 50 | color14 = #96ffe3 51 | 52 | # white 53 | color7 = #b6afab 54 | color15 = #fff5ed 55 | ''; 56 | }; 57 | }; 58 | } 59 | -------------------------------------------------------------------------------- /modules/vcs.nix: -------------------------------------------------------------------------------- 1 | let 2 | shared = { config, user, ... }: { 3 | home-manager.users.root.programs.git.enable = true; 4 | home-manager.users.root.programs.git.extraConfig.safe.directory = 5 | "${config.users.users.${user}.home}/dotfiles"; 6 | }; 7 | in { 8 | nixosModule = shared; 9 | 10 | darwinModule = shared; 11 | 12 | homeModule = { pkgs, ... }: { 13 | home.packages = builtins.attrValues { inherit (pkgs) watchman; }; 14 | 15 | programs.git = { 16 | enable = true; 17 | userName = "Michael Hoang"; 18 | userEmail = "enzime@users.noreply.github.com"; 19 | 20 | ignores = [ "/worktrees" "result*" ".DS_Store" ]; 21 | 22 | delta.enable = true; 23 | 24 | extraConfig = { 25 | advice = { addIgnoredFile = false; }; 26 | am = { threeWay = true; }; 27 | core = { hooksPath = "~/.config/git/hooks"; }; 28 | diff = { colorMoved = "default"; }; 29 | fetch = { prune = true; }; 30 | init = { defaultBranch = "main"; }; 31 | merge = { conflictStyle = "zdiff3"; }; 32 | pull = { ff = "only"; }; 33 | rebase = { 34 | autoStash = true; 35 | autoSquash = true; 36 | }; 37 | url = { 38 | "https://github.com/" = { insteadOf = [ "gh:" "ghro:" ]; }; 39 | "https://bitbucket.org/" = { insteadOf = [ "bb:" "bbro:" ]; }; 40 | 41 | "ssh://git@github.com/" = { 42 | insteadOf = "ghp:"; 43 | pushInsteadOf = "gh:"; 44 | }; 45 | "ssh://git@bitbucket.org/" = { 46 | insteadOf = "bbp:"; 47 | pushInsteadOf = "bb:"; 48 | }; 49 | 50 | "___PUSH_DISABLED___" = { pushInsteadOf = [ "ghro:" "bbro:" ]; }; 51 | }; 52 | }; 53 | }; 54 | 55 | programs.zsh.shellAliases = { 56 | gai = "git add --interactive"; 57 | gaf = "git add --force"; 58 | gbc = "gbfm -c"; 59 | gbC = "gbfm -C"; 60 | gbu = "git branch --set-upstream-to"; 61 | gbv = "git branch -vv"; 62 | gca = "git commit --amend"; 63 | gcf = "git commit --fixup"; 64 | gco = "git checkout --patch"; 65 | gcpa = "git cherry-pick --abort"; 66 | gcpc = "git cherry-pick --continue"; 67 | gC = "git checkout"; 68 | gD = "git diff"; 69 | gDs = "gD --cached"; 70 | gf = "gfa --prune"; 71 | gF = "git fetch"; 72 | gln = "gl -n"; 73 | gpx = "gp --delete"; 74 | gRh = "git reset --hard"; 75 | gRs = "git reset --soft"; 76 | gRv = "gR -v"; 77 | gs = "git status"; 78 | gsc = "gfc --depth=1"; 79 | gss = "git stash save -p"; 80 | gsS = "git stash save --include-untracked"; 81 | gS = "git show --stat --patch"; 82 | gtx = "git tag --delete"; 83 | }; 84 | 85 | programs.jujutsu.enable = true; 86 | programs.jujutsu.settings = { 87 | user.name = "Michael Hoang"; 88 | user.email = "enzime@users.noreply.github.com"; 89 | 90 | ui.default-command = "log"; 91 | }; 92 | }; 93 | } 94 | -------------------------------------------------------------------------------- /modules/virt-manager.nix: -------------------------------------------------------------------------------- 1 | { 2 | nixosModule = { user, ... }: { 3 | virtualisation.libvirtd.enable = true; 4 | virtualisation.spiceUSBRedirection.enable = true; 5 | 6 | users.users.${user}.extraGroups = [ "libvirtd" ]; 7 | }; 8 | 9 | homeModule = { pkgs, ... }: { 10 | home.packages = builtins.attrValues { inherit (pkgs) virt-manager; }; 11 | }; 12 | } 13 | -------------------------------------------------------------------------------- /modules/vm.nix: -------------------------------------------------------------------------------- 1 | let 2 | homeModule = { lib, ... }: 3 | let inherit (lib) mkVMOverride; 4 | in { 5 | services.polybar.config."bar/centre".monitor = mkVMOverride "Virtual-1"; 6 | 7 | xsession.windowManager.i3.config.workspaceOutputAssign = mkVMOverride [{ 8 | workspace = "101"; 9 | output = "Virtual-1"; 10 | }]; 11 | 12 | wayland.windowManager.sway.config.workspaceOutputAssign = mkVMOverride [{ 13 | workspace = "1"; 14 | output = "Virtual-1"; 15 | }]; 16 | 17 | systemd.user.services.swayidle = mkVMOverride { }; 18 | 19 | wayland.windowManager.sway.config.output = { 20 | Virtual-1 = { scale = "2"; }; 21 | }; 22 | }; 23 | in { 24 | darwinModule = { options, hostname, lib, ... }: 25 | let inherit (lib) mkIf mkVMOverride; 26 | in mkIf (options ? virtualisation) { 27 | networking.hostName = mkVMOverride "${hostname}-vm"; 28 | }; 29 | 30 | nixosModule = { config, user, pkgs, lib, ... }: 31 | let 32 | inherit (lib) mkForce mkVMOverride; 33 | 34 | shared = { 35 | home-manager.sharedModules = [ homeModule ]; 36 | 37 | users.users.root.password = "apple"; 38 | users.users.${user} = { 39 | password = mkVMOverride "apple"; 40 | initialPassword = mkForce null; 41 | hashedPasswordFile = mkForce null; 42 | }; 43 | 44 | # WORKAROUND: home-manager for `root` will attempt to GC unless it is disabled 45 | nix.settings.min-free = 0; 46 | 47 | system.activationScripts.expire-password = mkForce ""; 48 | 49 | virtualisation.qemu.options = [ 50 | "-display gtk,grab-on-hover=true,gl=on" 51 | # Use a better fake GPU 52 | (lib.mkIf pkgs.stdenv.hostPlatform.isx86_64 53 | "-vga none -device virtio-vga-gl") 54 | ]; 55 | 56 | zramSwap.enable = true; 57 | zramSwap.memoryPercent = 250; 58 | 59 | programs.sway.extraSessionCommands = '' 60 | export WLR_NO_HARDWARE_CURSORS=1 61 | ''; 62 | }; 63 | in { 64 | virtualisation.vmVariant = shared; 65 | 66 | virtualisation.vmVariantWithDisko = { 67 | imports = [ shared ]; 68 | 69 | disko.testMode = true; 70 | 71 | virtualisation.fileSystems = 72 | lib.mkIf config.environment.persistence."/persist".enable { 73 | "/persist".neededForBoot = true; 74 | }; 75 | }; 76 | }; 77 | } 78 | -------------------------------------------------------------------------------- /modules/vncserver.nix: -------------------------------------------------------------------------------- 1 | { 2 | imports = [ "greetd" "sway" ]; 3 | 4 | nixosModule = { user, ... }: { users.users.${user}.linger = true; }; 5 | 6 | homeModule = { pkgs, lib, ... }@args: 7 | let 8 | vncEnvironment = [ 9 | "WLR_BACKENDS=headless" 10 | "WLR_LIBINPUT_NO_DEVICES=1" 11 | "WAYLAND_DISPLAY=wayland-1" 12 | ]; 13 | in { 14 | # Move regular wayvnc to another port 15 | xdg.configFile."wayvnc/config".text = '' 16 | port=5901 17 | ''; 18 | 19 | services.swayidle.enable = lib.mkForce false; 20 | 21 | systemd.user.services.import-path = { 22 | Unit = { Description = "Import PATH from zsh"; }; 23 | Service = { 24 | Environment = [ 25 | # Necessary for running interactive Zsh (`zsh -i` which sources `~/.zshrc`) which 26 | # is necessary for setting some components of the PATH 27 | "PATH=/run/current-system/sw/bin" 28 | # NixOS doesn't expose the PATH in the NixOS module system so we need to unset this 29 | # environment variable to get NixOS to set the default PATH for us 30 | "__NIXOS_SET_ENVIRONMENT_DONE=" 31 | ]; 32 | Type = "oneshot"; 33 | ExecStart = "${ 34 | lib.getExe pkgs.zsh 35 | } -ic 'systemctl --user import-environment PATH'"; 36 | RemainAfterExit = true; 37 | }; 38 | }; 39 | 40 | systemd.user.services.wayvnc-headless = lib.mkIf (args ? osConfig) { 41 | Unit = { 42 | Description = "VNC server for headless session"; 43 | Requires = [ "import-path.service" "sway-headless.service" ]; 44 | After = [ "import-path.service" "sway-headless.service" ]; 45 | }; 46 | Service = { 47 | Type = "exec"; 48 | ExecStart = "${lib.getExe pkgs.wayvnc} --config=${ 49 | pkgs.writeTextFile { 50 | name = "wayvnc-headless.conf"; 51 | text = '' 52 | address=0.0.0.0 53 | port=5900 54 | ''; 55 | } 56 | }"; 57 | Environment = vncEnvironment; 58 | }; 59 | Install = { WantedBy = [ "default.target" ]; }; 60 | }; 61 | 62 | systemd.user.services.sway-headless = { 63 | Unit = { 64 | Description = "Wayland compositor for headless session"; 65 | Requires = [ "import-path.service" ]; 66 | After = [ "import-path.service" ]; 67 | }; 68 | Service = { 69 | Environment = vncEnvironment; 70 | ExecStart = lib.getExe pkgs.sway; 71 | }; 72 | Install = { WantedBy = [ "default.target" ]; }; 73 | }; 74 | }; 75 | } 76 | -------------------------------------------------------------------------------- /modules/vscode.nix: -------------------------------------------------------------------------------- 1 | { 2 | darwinModule = { 3 | system.defaults.CustomUserPreferences."com.microsoft.VSCode"."ApplePressAndHoldEnabled" = 4 | false; 5 | }; 6 | 7 | homeModule = { config, inputs, pkgs, lib, ... }: 8 | let inherit (pkgs.stdenv) hostPlatform; 9 | in { 10 | home.file.".vscode-server/extensions".source = 11 | config.home.file.".vscode/extensions".source; 12 | 13 | programs.vscode.enable = true; 14 | # Don't install `vscode` unless `graphical` module is specified 15 | programs.vscode.package = lib.mkDefault (pkgs.emptyDirectory // { 16 | pname = "vscode"; 17 | # Required for version check to generate extensions.json 18 | version = "1.74.0"; 19 | }); 20 | programs.vscode.mutableExtensionsDir = false; 21 | programs.vscode.profiles.default.extensions = [ 22 | pkgs.vscode-extensions.asvetliakov.vscode-neovim 23 | pkgs.vscode-extensions.eamodio.gitlens 24 | (pkgs.vscode-extensions.ms-vscode-remote.remote-ssh.override { 25 | useLocalExtensions = true; 26 | }) 27 | 28 | pkgs.vscode-extensions.bierner.comment-tagged-templates 29 | pkgs.vscode-extensions.bierner.emojisense 30 | pkgs.vscode-extensions.bierner.markdown-checkbox 31 | pkgs.vscode-extensions.bierner.markdown-emoji 32 | pkgs.vscode-extensions.bierner.markdown-preview-github-styles 33 | pkgs.vscode-extensions.editorconfig.editorconfig 34 | pkgs.vscode-extensions.mkhl.direnv 35 | pkgs.vscode-extensions.shardulm94.trailing-spaces 36 | 37 | # Language support 38 | pkgs.vscode-extensions.dbaeumer.vscode-eslint 39 | pkgs.vscode-extensions.jnoortheen.nix-ide 40 | pkgs.vscode-extensions.xadillax.viml 41 | pkgs.vscode-extensions.nefrob.vscode-just-syntax 42 | pkgs.vscode-extensions.golang.go 43 | ] ++ lib.optionals (hostPlatform.isx86_64 || hostPlatform.isDarwin) [ 44 | (pkgs.vscode-extensions.ms-python.python.override { 45 | pythonUseFixed = true; 46 | }) 47 | ]; 48 | programs.vscode.profiles.default.keybindings = 49 | let mod = if hostPlatform.isDarwin then "cmd" else "ctrl"; 50 | in [ 51 | # Fix `C-e` not working in terminal 52 | { 53 | key = "ctrl+e"; 54 | command = "-workbench.action.quickOpen"; 55 | } 56 | # Disable opening external terminal with `C-S-c` 57 | { 58 | key = "ctrl+shift+c"; 59 | command = "-workbench.action.terminal.openNativeConsole"; 60 | when = "!terminalFocus"; 61 | } 62 | 63 | # Use `C-o` to open files 64 | { 65 | key = "ctrl+o"; 66 | command = "-vscode-neovim.send"; 67 | when = 68 | "editorTextFocus && neovim.ctrlKeysNormal && neovim.init && neovim.mode != 'insert'"; 69 | } 70 | 71 | # Use `C-,` as a leader key 72 | { 73 | key = "ctrl+,"; 74 | command = "-workbench.action.openSettings"; 75 | } 76 | # Use `openSettings2` instead to show as the keybinding for "Open Settings (UI)" 77 | { 78 | key = "ctrl+, ctrl+,"; 79 | command = "workbench.action.openSettings2"; 80 | } 81 | { 82 | key = "ctrl+, ctrl+."; 83 | command = "workbench.action.openGlobalKeybindings"; 84 | } 85 | 86 | # Use `C-r` solely for redoing in `neovim` 87 | { 88 | key = "ctrl+r"; 89 | command = "-workbench.action.openRecent"; 90 | } 91 | { 92 | key = "ctrl+, ctrl+r"; 93 | command = "workbench.action.openRecent"; 94 | } 95 | 96 | # Don't hide terminal when using "C-`" to switch back to editor 97 | { 98 | key = "ctrl+`"; 99 | command = "-workbench.action.terminal.toggleTerminal"; 100 | when = "terminal.active"; 101 | } 102 | { 103 | key = "ctrl+`"; 104 | command = "terminal.focus"; 105 | when = "!terminalFocus"; 106 | } 107 | { 108 | key = "ctrl+`"; 109 | command = "workbench.action.focusActiveEditorGroup"; 110 | when = "terminalFocus"; 111 | } 112 | 113 | # Disable closing tabs with `C-w` 114 | { 115 | key = "ctrl+w"; 116 | command = "-workbench.action.closeActiveEditor"; 117 | } 118 | { 119 | key = "ctrl+w"; 120 | command = "-workbench.action.terminal.killEditor"; 121 | when = 122 | "terminalEditorFocus && terminalFocus && terminalHasBeenCreated && resourceScheme == 'vscode-terminal' || terminalEditorFocus && terminalFocus && terminalProcessSupported && resourceScheme == 'vscode-terminal'"; 123 | } 124 | 125 | # Disable `C-k` passthrough as VS Code uses `C-k` as the starting chord extensively 126 | { 127 | key = "ctrl+k"; 128 | command = "-vscode-neovim.send"; 129 | when = 130 | "editorTextFocus && neovim.ctrlKeysNormal && neovim.init && neovim.mode != 'insert'"; 131 | } 132 | 133 | # Use `C-S-k` for clearing the terminal 134 | { 135 | key = "ctrl+shift+k"; 136 | command = "-editor.action.deleteLines"; 137 | when = "textInputFocus && !editorReadonly"; 138 | } 139 | { 140 | key = "ctrl+shift+k"; 141 | command = "workbench.action.terminal.clear"; 142 | } 143 | 144 | # Disable `C-S-n` to reinforce `C-, C-r C-Enter` workflow 145 | { 146 | key = "ctrl+shift+n"; 147 | command = "-workbench.action.newWindow"; 148 | } 149 | 150 | # `C-i` is for IntelliSense suggestions 151 | { 152 | key = "${mod}+i"; 153 | command = "-emojisense.quickEmoji"; 154 | when = "editorTextFocus"; 155 | } 156 | { 157 | key = "${mod}+shift+i"; 158 | command = "-emojisense.quickEmojitext"; 159 | when = "editorTextFocus"; 160 | } 161 | 162 | # Disable Tab Moves Focus mode 163 | { 164 | key = "ctrl+m"; 165 | command = "-editor.action.toggleTabFocusMode"; 166 | } 167 | ]; 168 | programs.vscode.profiles.default.userSettings = 169 | let nvimSystem = if hostPlatform.isDarwin then "darwin" else "linux"; 170 | in { 171 | "update.mode" = "manual"; 172 | "extensions.autoUpdate" = false; 173 | "extensions.autoCheckUpdates" = false; 174 | 175 | "telemetry.telemetryLevel" = "off"; 176 | "workbench.enableExperiments" = false; 177 | "workbench.settings.enableNaturalLanguageSearch" = false; 178 | 179 | "vscode-neovim.neovimExecutablePaths.${nvimSystem}" = 180 | lib.getExe config.programs.neovim.finalPackage; 181 | "nix.enableLanguageServer" = true; 182 | "nix.serverPath" = lib.getExe pkgs.nil; 183 | "nix.serverSettings".nil.formatting.command = [ 184 | (lib.getExe 185 | inputs.self.packages.${pkgs.hostPlatform.system}.cached-nix-fmt) 186 | "--stdin" 187 | "example.nix" 188 | ]; 189 | "nix.serverSettings".nil.nix.flake.autoArchive = true; 190 | "extensions.experimental.affinity" = { 191 | "asvetliakov.vscode-neovim" = 1; 192 | }; 193 | 194 | "workbench.colorTheme" = "Monokai"; 195 | "markdown-preview-github-styles.colorTheme" = "light"; 196 | 197 | "editor.formatOnSave" = true; 198 | # Primarily for ESLint 199 | "editor.codeActionsOnSave" = { "source.fixAll" = "explicit"; }; 200 | 201 | "editor.lineNumbers" = "relative"; 202 | "editor.renderFinalNewline" = "off"; 203 | "files.insertFinalNewline" = true; 204 | "diffEditor.diffAlgorithm" = "advanced"; 205 | "diffEditor.ignoreTrimWhitespace" = false; 206 | "trailing-spaces.trimOnSave" = true; 207 | "trailing-spaces.highlightCurrentLine" = false; 208 | 209 | "search.useGlobalIgnoreFiles" = true; 210 | "files.exclude" = { 211 | "**/.direnv" = true; 212 | "**/.jj" = true; 213 | }; 214 | 215 | # Don't use VS Code's 3 way merge editor 216 | "git.mergeEditor" = false; 217 | 218 | # Don't use GitLens to edit git rebase commands 219 | "workbench.editorAssociations" = { "git-rebase-todo" = "default"; }; 220 | 221 | "gitlens.remotes" = [{ 222 | domain = "git.clan.lol"; 223 | type = "Gitea"; 224 | }]; 225 | 226 | "editor.bracketPairColorization.enabled" = true; 227 | "editor.guides.bracketPairs" = true; 228 | 229 | "terminal.integrated.scrollback" = 1000000; 230 | 231 | "files.associations" = { 232 | "flake.lock" = "json"; 233 | "yarn.lock" = "yaml"; 234 | ".env.*" = "properties"; 235 | }; 236 | 237 | "workbench.colorCustomizations" = { 238 | "terminal.background" = "#0d0c0c"; 239 | "terminal.foreground" = "#fff5ed"; 240 | "terminalCursor.background" = "#F8F8F2"; 241 | "terminalCursor.foreground" = "#00ccff"; 242 | 243 | "terminal.ansiBlack" = "#0a0a0a"; 244 | "terminal.ansiBrightBlack" = "#73645d"; 245 | 246 | "terminal.ansiRed" = "#e61f00"; 247 | "terminal.ansiBrightRed" = "#ff3f3d"; 248 | 249 | "terminal.ansiGreen" = "#6dd200"; 250 | "terminal.ansiBrightGreen" = "#c1ff05"; 251 | 252 | "terminal.ansiYellow" = "#fa6800"; 253 | "terminal.ansiBrightYellow" = "#ffa726"; 254 | 255 | "terminal.ansiBlue" = "#255ae4"; 256 | "terminal.ansiBrightBlue" = "#00ccff"; 257 | 258 | "terminal.ansiMagenta" = "#ff0084"; 259 | "terminal.ansiBrightMagenta" = "#ff65a0"; 260 | 261 | "terminal.ansiCyan" = "#36fcd3"; 262 | "terminal.ansiBrightCyan" = "#96ffe3"; 263 | 264 | "terminal.ansiWhite" = "#b6afab"; 265 | "terminal.ansiBrightWhite" = "#fff5ed"; 266 | }; 267 | 268 | # WORKAROUND: VS Code crashes when running under Wayland 269 | # https://github.com/NixOS/nixpkgs/issues/246509 270 | "window.titleBarStyle" = "custom"; 271 | 272 | # Disable Copilot 273 | "chat.commandCenter.enabled" = false; 274 | }; 275 | 276 | home.persistence."/persist${config.home.homeDirectory}".directories = 277 | [ ".config/Code" ]; 278 | 279 | home.file.".vscode-server/data/Machine/settings.json".source = 280 | (pkgs.formats.json { }).generate "vscode-server-settings.json" { 281 | "nix.serverPath" = lib.getExe pkgs.nil; 282 | }; 283 | 284 | programs.git.extraConfig.core.editor = lib.getExe 285 | (pkgs.writeShellApplication { 286 | name = "use-vscode-sometimes"; 287 | text = '' 288 | if [[ $TERM_PROGRAM = "vscode" ]]; then 289 | code --wait "$@" 290 | else 291 | vim "$@" 292 | fi 293 | ''; 294 | }); 295 | 296 | programs.jujutsu.settings.ui.editor = 297 | config.programs.git.extraConfig.core.editor; 298 | }; 299 | } 300 | -------------------------------------------------------------------------------- /modules/wayvnc.nix: -------------------------------------------------------------------------------- 1 | { 2 | homeModule = { pkgs, lib, ... }: { 3 | systemd.user.services.wayvnc = { 4 | Unit = { 5 | Description = "VNC Server for Sway"; 6 | # Allow it to restart infinitely 7 | StartLimitIntervalSec = 0; 8 | }; 9 | 10 | Service = { 11 | ExecStart = "${pkgs.writeShellScript "wayvnc-start" '' 12 | if [[ $XDG_SESSION_TYPE = "wayland" ]]; then 13 | ${lib.getExe pkgs.wayvnc} && exit 1 14 | else 15 | exit 0 16 | fi 17 | ''}"; 18 | Restart = "on-failure"; 19 | RestartSec = "1m"; 20 | }; 21 | 22 | Install = { WantedBy = [ "graphical-session.target" ]; }; 23 | }; 24 | 25 | # As we don't open the firewall, it should only be accessible over Tailscale 26 | xdg.configFile."wayvnc/config".text = '' 27 | address=0.0.0.0 28 | ''; 29 | }; 30 | } 31 | -------------------------------------------------------------------------------- /modules/wireless.nix: -------------------------------------------------------------------------------- 1 | { 2 | nixosModule = { config, lib, ... }: { 3 | networking.networkmanager.enable = true; 4 | networking.networkmanager.plugins = 5 | assert !config.networking.networkmanager ? enableDefaultPlugins; 6 | lib.mkForce [ ]; 7 | networking.useDHCP = lib.mkForce false; 8 | 9 | age.secrets.wireless.file = ../secrets/wireless.age; 10 | 11 | networking.networkmanager.ensureProfiles.environmentFiles = 12 | [ config.age.secrets.wireless.path ]; 13 | 14 | networking.networkmanager.ensureProfiles.profiles = { 15 | network-1 = { 16 | connection = { 17 | id = "$NETWORK_1_SSID"; 18 | type = "wifi"; 19 | }; 20 | 21 | wifi = { 22 | mode = "infrastructure"; 23 | ssid = "$NETWORK_1_SSID"; 24 | }; 25 | 26 | wifi-security = { 27 | auth-alg = "open"; 28 | key-mgmt = "wpa-psk"; 29 | psk = "$NETWORK_1_KEY"; 30 | }; 31 | }; 32 | 33 | network-2 = { 34 | connection = { 35 | id = "$NETWORK_2_SSID"; 36 | type = "wifi"; 37 | }; 38 | 39 | wifi = { 40 | mode = "infrastructure"; 41 | ssid = "$NETWORK_2_SSID"; 42 | }; 43 | 44 | wifi-security = { 45 | auth-alg = "open"; 46 | key-mgmt = "wpa-psk"; 47 | psk = "$NETWORK_2_KEY"; 48 | }; 49 | }; 50 | }; 51 | 52 | environment.persistence."/persist".directories = [{ 53 | directory = "/etc/NetworkManager/system-connections"; 54 | mode = "0700"; 55 | }]; 56 | }; 57 | } 58 | -------------------------------------------------------------------------------- /modules/xdg.nix: -------------------------------------------------------------------------------- 1 | { 2 | homeModule = { pkgs, lib, ... }: 3 | let 4 | inherit (pkgs.stdenv) hostPlatform; 5 | inherit (lib) mkIf mkDefault; 6 | in mkIf hostPlatform.isLinux { 7 | xdg.userDirs = { 8 | enable = true; 9 | desktop = mkDefault "$HOME"; 10 | documents = mkDefault "$HOME"; 11 | download = mkDefault "/data/Downloads"; 12 | music = mkDefault "$HOME"; 13 | pictures = mkDefault "/data/Pictures"; 14 | publicShare = mkDefault "$HOME"; 15 | templates = mkDefault "$HOME"; 16 | videos = mkDefault "$HOME"; 17 | }; 18 | }; 19 | } 20 | -------------------------------------------------------------------------------- /overlays/docker-compose.nix: -------------------------------------------------------------------------------- 1 | self: super: { 2 | docker-compose_1 = 3 | super.runCommand "podman-compose-compat-${super.podman-compose.version}" { 4 | inherit (super.podman-compose) meta; 5 | } '' 6 | mkdir -p $out/bin 7 | ln -s ${super.podman-compose}/bin/podman-compose $out/bin/docker-compose 8 | ''; 9 | } 10 | -------------------------------------------------------------------------------- /overlays/firefox-addons/flake.nix: -------------------------------------------------------------------------------- 1 | { 2 | inputs.nixpkgs.url = "github:NixOS/nixpkgs/nixos-unstable"; 3 | 4 | inputs.firefox-addons.url = 5 | "gitlab:rycee/nur-expressions?dir=pkgs/firefox-addons"; 6 | inputs.firefox-addons.inputs.nixpkgs.follows = "nixpkgs"; 7 | 8 | outputs = { firefox-addons, ... }: { 9 | overlay = final: prev: 10 | let 11 | # We need to import default.nix to use buildFirefoxXpiAddon which doesn't get exported in flake.nix 12 | # WORKAROUND: In Nix 2.14+, firefox-addons.outPath points to the subdirectory rather than the root 13 | # so we need to use sourceInfo.outPath to maintain backwards compatibility 14 | addons = 15 | import "${firefox-addons.sourceInfo.outPath}/pkgs/firefox-addons" { 16 | inherit (prev) fetchurl lib stdenv; 17 | }; 18 | in { 19 | firefox-addons = addons // (let inherit (prev.lib) mapAttrs; 20 | in mapAttrs (name: addon: 21 | if addons ? ${name} then 22 | throw "firefox-addons.${name} already exists" 23 | else 24 | addon) { }); 25 | }; 26 | }; 27 | } 28 | -------------------------------------------------------------------------------- /overlays/firefox.nix: -------------------------------------------------------------------------------- 1 | self: super: { 2 | firefox-bin-unwrapped = super.firefox-bin-unwrapped.overrideAttrs 3 | (old: { dontFixup = assert !old ? dontFixup; true; }); 4 | } 5 | -------------------------------------------------------------------------------- /overlays/gramps.nix: -------------------------------------------------------------------------------- 1 | self: super: { 2 | gramps = super.gramps.overrideAttrs (old: { 3 | buildInputs = old.buildInputs ++ [ super.goocanvas3 ]; 4 | propagatedBuildInputs = (old.propagatedBuildInputs or [ ]) 5 | ++ [ super.graphviz ]; 6 | }); 7 | } 8 | -------------------------------------------------------------------------------- /overlays/i3-ws.nix: -------------------------------------------------------------------------------- 1 | self: super: { 2 | i3-ws = assert !super ? i3-ws; 3 | super.stdenv.mkDerivation (let 4 | pname = "i3-ws"; 5 | version = "git-2017-07-30"; 6 | in { 7 | inherit pname version; 8 | 9 | src = super.fetchFromGitHub { 10 | owner = "Enzime"; 11 | repo = pname; 12 | rev = "bca34b6b10509088ceac03fb9a1ef27808165ccb"; 13 | sha256 = "1i014hsi80wsaxmdpl8ccwhpvnclkl14w4r0mbci3yqap8a32wgn"; 14 | fetchSubmodules = true; 15 | }; 16 | 17 | buildInputs = 18 | builtins.attrValues { inherit (super) i3 jsoncpp libsigcxx; }; 19 | 20 | nativeBuildInputs = 21 | builtins.attrValues { inherit (super) cmake pkg-config; }; 22 | 23 | meta.mainProgram = pname; 24 | }); 25 | } 26 | -------------------------------------------------------------------------------- /overlays/karabiner-elements.nix: -------------------------------------------------------------------------------- 1 | self: super: { 2 | karabiner-elements = super.karabiner-elements.overrideAttrs (old: { 3 | version = "14.13.0"; 4 | 5 | src = super.fetchurl { 6 | inherit (old.src) url; 7 | hash = "sha256-gmJwoht/Tfm5qMecmq1N6PSAIfWOqsvuHU8VDJY8bLw="; 8 | }; 9 | 10 | dontFixup = true; 11 | }); 12 | } 13 | -------------------------------------------------------------------------------- /overlays/neovim.nix: -------------------------------------------------------------------------------- 1 | self: super: { neovim = super.neovim.override { vimAlias = true; }; } 2 | -------------------------------------------------------------------------------- /overlays/nixos-rebuild.nix: -------------------------------------------------------------------------------- 1 | self: super: { 2 | nixos-rebuild = super.nixos-rebuild.overrideAttrs (old: 3 | let 4 | patches = [ 5 | (super.fetchpatch { 6 | name = "fix-cross-building-flakes.patch"; 7 | url = 8 | "https://github.com/Enzime/nixpkgs/commit/8f7debeafaff06c2a5f039402d207712f2001770.patch"; 9 | sha256 = "sha256-7ZS6RLqrekftJVx4C/OSLcESAwS5kaIxw9tujkI4YXo="; 10 | }) 11 | ]; 12 | in { 13 | postInstall = builtins.concatStringsSep "\n" ((map (p: '' 14 | echo "applying patch ${p}" 15 | patch --no-backup-if-mismatch $target ${p}'') patches) 16 | ++ [ (old.postInstall or "") ]); 17 | }); 18 | } 19 | -------------------------------------------------------------------------------- /overlays/powermenu.nix: -------------------------------------------------------------------------------- 1 | self: super: { 2 | powermenu = 3 | super.writeScriptBin "powermenu" (builtins.readFile ../files/powermenu); 4 | } 5 | -------------------------------------------------------------------------------- /overlays/ranger.nix: -------------------------------------------------------------------------------- 1 | self: super: { 2 | ranger = super.ranger.overrideAttrs (old: 3 | let 4 | # (a == b) (a > b) 5 | # compareVersions a b = 0 | 1 6 | versionAtMost = a: b: builtins.compareVersions a b > -1; 7 | in { 8 | propagatedBuildInputs = assert ( 9 | # SEE: https://github.com/NixOS/nixpkgs/pull/141466#issuecomment-942185842 10 | # SEE ALSO: https://github.com/ranger/ranger/issues/2404 11 | versionAtMost "1.9.4" old.version); 12 | old.propagatedBuildInputs ++ [ super.xclip ]; 13 | 14 | patches = (old.patches or [ ]) ++ [ 15 | (super.fetchpatch { 16 | name = "fix-ctrl-arrows.patch"; 17 | url = 18 | "https://github.com/Enzime/ranger/commit/9e60541f3e360e2019d0b671852249771b843761.patch"; 19 | sha256 = "sha256-R3Qia9++n8SC/fG72GwLYbjwmx/oyEm5BfC2/6nziqI="; 20 | }) 21 | ]; 22 | }); 23 | } 24 | -------------------------------------------------------------------------------- /overlays/remmina.nix: -------------------------------------------------------------------------------- 1 | self: super: { 2 | remmina = super.remmina.overrideAttrs (old: { 3 | cmakeFlags = 4 | assert !super.lib.any (super.lib.hasPrefix "-DPYTHON_INCLUDE_DIR=") 5 | old.cmakeFlags; 6 | old.cmakeFlags ++ [ 7 | "-DPYTHON_INCLUDE_DIR=${super.python3}/include/${super.python3.libPrefix}" 8 | "-DPYTHON_LIBRARY=${super.python3}/lib/libpython${super.python3.pythonVersion}${super.hostPlatform.extensions.sharedLibrary}" 9 | ]; 10 | 11 | preFixup = assert !super.lib.hasInfix "--prefix PATH " old.preFixup; 12 | old.preFixup + '' 13 | gappsWrapperArgs+=( 14 | --prefix PATH : "${super.lib.makeBinPath [ super.python3 ]}" 15 | ) 16 | ''; 17 | }); 18 | } 19 | -------------------------------------------------------------------------------- /overlays/spotify-tray.nix: -------------------------------------------------------------------------------- 1 | self: super: { 2 | spotify-tray = super.spotify-tray.overrideAttrs (old: { 3 | nativeBuildInputs = (old.nativeBuildInputs or [ ]) ++ [ super.makeWrapper ]; 4 | 5 | postInstall = '' 6 | cp ${ 7 | super.writeShellScript "spotify-wrapper" '' 8 | if [[ $XDG_SESSION_TYPE = "wayland" ]]; then 9 | exec ${super.spotify}/bin/spotify "$@" 10 | else 11 | exec $out/bin/spotify-tray "$@" 12 | fi 13 | '' 14 | } $out/bin/spotify 15 | 16 | substituteInPlace $out/bin/spotify --replace \$out $out 17 | 18 | wrapProgram $out/bin/spotify-tray \ 19 | --set-default GDK_BACKEND x11 \ 20 | --add-flags "-c ${super.spotify}/bin/spotify" 21 | ''; 22 | 23 | meta = old.meta // { priority = (super.spotify.meta.priority or 0) - 1; }; 24 | }); 25 | } 26 | -------------------------------------------------------------------------------- /overlays/spotify.nix: -------------------------------------------------------------------------------- 1 | self: super: { 2 | spotify = super.spotify.overrideAttrs (finalAttrs: prevAttrs: 3 | if super.hostPlatform.isDarwin then { 4 | version = "1.2.64.408"; 5 | 6 | src = assert super.lib.versionOlder prevAttrs.version finalAttrs.version; 7 | super.fetchurl { 8 | url = 9 | "https://web.archive.org/web/20250522123639/https://download.scdn.co/SpotifyARM64.dmg"; 10 | hash = "sha256-28T+AxhnM1K6W50JUu9RdFRKsBRDTQulKK2+kk2RTMQ="; 11 | }; 12 | } else { 13 | version = "1.2.60.564.gcc6305cb"; 14 | rev = assert super.lib.versionOlder prevAttrs.version finalAttrs.version; 15 | "87"; 16 | 17 | src = assert !prevAttrs ? rev; 18 | super.fetchurl { 19 | name = "spotify-${finalAttrs.version}-${finalAttrs.rev}.snap"; 20 | url = 21 | "https://api.snapcraft.io/api/v1/snaps/download/pOBIoZ2LrCB3rDohMxoYGnbN14EHOgD7_${finalAttrs.rev}.snap"; 22 | hash = 23 | "sha512-hdJOko/0EHkPiNgWO+WB3nP+0MO9D2fxgM/X/Ri6fM1ODJxz3XYY84Xf2Ru6iGqdA9XUNRcd/qi+Gfaj9Ez0Ug=="; 24 | }; 25 | 26 | unpackPhase = assert !prevAttrs ? rev; '' 27 | runHook preUnpack 28 | unsquashfs "$src" '/usr/share/spotify' '/usr/bin/spotify' '/meta/snap.yaml' 29 | cd squashfs-root 30 | if ! grep -q 'grade: stable' meta/snap.yaml; then 31 | # Unfortunately this check is not reliable: At the moment (2018-07-26) the 32 | # latest version in the "edge" channel is also marked as stable. 33 | echo "The snap package is marked as unstable:" 34 | grep 'grade: ' meta/snap.yaml 35 | echo "You probably chose the wrong revision." 36 | exit 1 37 | fi 38 | if ! grep -q '${finalAttrs.version}' meta/snap.yaml; then 39 | echo "Package version differs from version found in snap metadata:" 40 | grep 'version: ' meta/snap.yaml 41 | echo "While the nix package specifies: ${finalAttrs.version}." 42 | echo "You probably chose the wrong revision or forgot to update the nix version." 43 | exit 1 44 | fi 45 | runHook postUnpack 46 | ''; 47 | }); 48 | } 49 | -------------------------------------------------------------------------------- /overlays/thunar.nix: -------------------------------------------------------------------------------- 1 | self: super: { 2 | xfce = super.lib.recursiveUpdate super.xfce { 3 | thunar = super.xfce.thunar.overrideAttrs (old: { 4 | # WORKAROUND: https://github.com/cachix/cachix/issues/675 5 | preFixup = (old.preFixup or "") + '' 6 | rm $out/bin/Thunar 7 | ''; 8 | }); 9 | }; 10 | } 11 | -------------------------------------------------------------------------------- /overlays/vim-plugins.nix: -------------------------------------------------------------------------------- 1 | self: super: 2 | let 3 | inherit (super) fetchFromGitHub; 4 | inherit (super.vimUtils) buildVimPlugin; 5 | in { 6 | vimPlugins = super.vimPlugins // super.lib.mapAttrs (name: plugin: 7 | if super.vimPlugins ? ${name} then 8 | throw "vimPlugins.${name} already exists" 9 | else 10 | plugin) { 11 | hybrid-krompus-vim = buildVimPlugin { 12 | pname = "hybrid-krompus.vim"; 13 | version = "2016-07-02"; 14 | src = fetchFromGitHub { 15 | owner = "airodactyl"; 16 | repo = "hybrid-krompus.vim"; 17 | rev = "1b008739e0fcc04c69f0a71e222949f38bf3fada"; 18 | sha256 = "sha256-ZOuuHeeZaIZVVdf1mh35Y4WaVTWVYXboG0+l/GscVUg="; 19 | }; 20 | meta.homepage = "https://github.com/airodactyl/hybrid-krompus.vim"; 21 | }; 22 | 23 | neovim-ranger = buildVimPlugin { 24 | pname = "neovim-ranger"; 25 | version = "2015-09-30"; 26 | src = fetchFromGitHub { 27 | owner = "airodactyl"; 28 | repo = "neovim-ranger"; 29 | rev = "8726761cb7582582e60f3b1ee6498acc6d3c03a7"; 30 | sha256 = "sha256-gHFO39R5/YdJ2wm5x3pjNZF30HOWLHmH/bcou920IwY="; 31 | }; 32 | meta.homepage = "https://github.com/airodactyl/neovim-ranger"; 33 | }; 34 | 35 | vim-operator-flashy = buildVimPlugin { 36 | pname = "vim-operator-flashy"; 37 | version = "2016-10-09"; 38 | src = fetchFromGitHub { 39 | owner = "haya14busa"; 40 | repo = "vim-operator-flashy"; 41 | rev = "b24673a9b0d5d60b26d202deb13d4ebf90d7a2ae"; 42 | sha256 = "sha256-CGU7wzr2SQHH0oT9S5Oj3K1XxznRNAA9qdi7QNlRW4A="; 43 | }; 44 | meta.homepage = "https://github.com/haya14busa/vim-operator-flashy"; 45 | }; 46 | }; 47 | } 48 | -------------------------------------------------------------------------------- /overlays/vscode-extensions.nix: -------------------------------------------------------------------------------- 1 | self: super: 2 | 3 | let 4 | inherit (super.lib) 5 | foldl getAttrFromPath getVersion hasAttrByPath recursiveUpdate splitString; 6 | inherit (super.vscode-utils) extensionsFromVscodeMarketplace; 7 | 8 | attrsetFromPathValue = { path, value, start ? 0 }: 9 | 10 | if start == builtins.length path then 11 | value 12 | else { 13 | ${builtins.elemAt path start} = attrsetFromPathValue { 14 | inherit path value; 15 | start = start + 1; 16 | }; 17 | }; 18 | 19 | attrsetFromDottedPathValue = path: value: 20 | attrsetFromPathValue { 21 | path = splitString "." path; 22 | inherit value; 23 | }; 24 | 25 | compareVersions = a: b: 26 | builtins.compareVersions (getVersion a) (getVersion b); 27 | 28 | ensureNotOutdatedExtension = ext: 29 | let 30 | path = splitString "." ext.vscodeExtUniqueId; 31 | 32 | alreadyInNixpkgs = hasAttrByPath path super.vscode-extensions; 33 | in if alreadyInNixpkgs 34 | && compareVersions ext (getAttrFromPath path super.vscode-extensions) 35 | != 1 then 36 | throw 37 | "vscode-extensions.${ext.vscodeExtUniqueId} is older than the version in Nixpkgs" 38 | else 39 | ext; 40 | 41 | extensionToAttrset = ext: 42 | attrsetFromDottedPathValue ext.vscodeExtUniqueId 43 | (ensureNotOutdatedExtension ext); 44 | 45 | extensionsAttrsetFromList = extensions: 46 | foldl recursiveUpdate { } (map extensionToAttrset extensions); 47 | fromMarketplaceRefs = mktplcRefs: 48 | extensionsAttrsetFromList (extensionsFromVscodeMarketplace mktplcRefs); 49 | in { 50 | vscode-extensions = recursiveUpdate (recursiveUpdate super.vscode-extensions { 51 | ms-vscode-remote.remote-ssh = 52 | super.vscode-extensions.ms-vscode-remote.remote-ssh.overrideAttrs (old: { 53 | postPatch = (old.postPatch or "") + '' 54 | substituteInPlace "out/extension.js" \ 55 | --replace "wget --no-proxy" "wget --no-proxy --no-continue" 56 | ''; 57 | }); 58 | }) (fromMarketplaceRefs [ ]); 59 | } 60 | -------------------------------------------------------------------------------- /secrets/acme_zoneee.age: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Enzime/dotfiles-nix/bafeccb6ffdc353179680d6a0b4031809e6eba0e/secrets/acme_zoneee.age -------------------------------------------------------------------------------- /secrets/nextcloud.age: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Enzime/dotfiles-nix/bafeccb6ffdc353179680d6a0b4031809e6eba0e/secrets/nextcloud.age -------------------------------------------------------------------------------- /secrets/password-hash_enzime-sigma.age: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Enzime/dotfiles-nix/bafeccb6ffdc353179680d6a0b4031809e6eba0e/secrets/password-hash_enzime-sigma.age -------------------------------------------------------------------------------- /secrets/secrets.nix: -------------------------------------------------------------------------------- 1 | let inherit (import ../keys.nix) users hosts; 2 | in { 3 | "acme_zoneee.age".publicKeys = builtins.attrValues { 4 | inherit (users) enzime; 5 | inherit (hosts) phi; 6 | }; 7 | 8 | "nextcloud.age".publicKeys = builtins.attrValues { 9 | inherit (users) enzime; 10 | inherit (hosts) phi; 11 | }; 12 | 13 | "password-hash_enzime-sigma.age".publicKeys = builtins.attrValues { 14 | inherit (users) enzime; 15 | inherit (hosts) sigma; 16 | }; 17 | 18 | "wireless.age".publicKeys = builtins.attrValues { 19 | inherit (users) enzime; 20 | inherit (hosts) phi sigma; 21 | }; 22 | 23 | "zshrc_phi.age".publicKeys = builtins.attrValues { 24 | inherit (users) enzime; 25 | inherit (hosts) phi; 26 | }; 27 | } 28 | -------------------------------------------------------------------------------- /secrets/wireless.age: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Enzime/dotfiles-nix/bafeccb6ffdc353179680d6a0b4031809e6eba0e/secrets/wireless.age -------------------------------------------------------------------------------- /secrets/zshrc_phi.age: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Enzime/dotfiles-nix/bafeccb6ffdc353179680d6a0b4031809e6eba0e/secrets/zshrc_phi.age -------------------------------------------------------------------------------- /shell.nix: -------------------------------------------------------------------------------- 1 | { system ? builtins.currentSystem }: 2 | let 3 | lock = builtins.fromJSON (builtins.readFile ./flake.lock); 4 | 5 | root = lock.nodes.${lock.root}; 6 | inherit (lock.nodes.${root.inputs.flake-compat}.locked) 7 | owner repo rev narHash; 8 | 9 | flake-compat = fetchTarball { 10 | url = "https://github.com/${owner}/${repo}/archive/${rev}.tar.gz"; 11 | sha256 = narHash; 12 | }; 13 | 14 | flake = import flake-compat { 15 | inherit system; 16 | src = ./.; 17 | }; 18 | in flake.shellNix 19 | --------------------------------------------------------------------------------