├── .gitignore ├── README.md ├── android.nix ├── audio.nix ├── base.nix ├── config ├── compton-inverted ├── compton-noninverted ├── dunstrc ├── i3 ├── i3status ├── i3status-netns ├── init.el └── xresources ├── copied ├── dhcpcd.nix └── wpa_supplicant.nix ├── dev-tools.nix ├── entrypoints ├── gurney.nix └── thufir.nix ├── fonts.nix ├── games.nix ├── gui-tools.nix ├── inl-tools.nix ├── laptop-base.nix ├── networking.nix ├── nix.nix ├── nixpkgs.nix ├── rust-overlay.nix ├── syncthing.nix ├── sysadmin.nix ├── uefi.nix ├── utility-scripts.nix ├── virtualization.nix ├── wireguard-client.nix └── x.nix /.gitignore: -------------------------------------------------------------------------------- 1 | default.nix 2 | private 3 | hardware-configuration.nix -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | nixos-configuration 2 | =================== 3 | 4 | This is a decently modularized set of configuration files for a NixOS 5 | system, which I mainly use to configure my laptop. 6 | 7 | The entrypoint is `default.nix`, and the module system is used 8 | heavily. 9 | 10 | Private files/data are placed in a `private` subdirectory, which is 11 | hidden via `.gitignore`. 12 | 13 | I place this repository in `/etc/nixos`, next to my local checkout of 14 | nixpkgs, which I use instead of the channel mechanism. A suitably 15 | modified `NIX_PATH` allows this to work (see `nix.nix`). 16 | 17 | ```bash 18 | [anders@gurney:/etc/nixos] 19 | $ ls -la 20 | total 16 21 | drwxr-xr-x 4 root root 4096 Mar 21 22:30 . 22 | drwxr-xr-x 23 root root 4096 Mar 21 22:31 .. 23 | drwxr-xr-x 6 anders users 4096 Mar 21 22:34 configuration 24 | drwxrwxr-x 9 anders users 4096 Mar 21 19:31 nixpkgs 25 | [anders@gurney:/etc/nixos] 26 | $ echo $NIX_PATH 27 | /etc/nixos:nixos-config=/etc/nixos/configuration 28 | ``` 29 | -------------------------------------------------------------------------------- /android.nix: -------------------------------------------------------------------------------- 1 | { config, pkgs, ... }: 2 | 3 | { programs.adb = { 4 | enable = true; 5 | }; 6 | } 7 | -------------------------------------------------------------------------------- /audio.nix: -------------------------------------------------------------------------------- 1 | { config, pkgs, ... }: 2 | 3 | let pulse = pkgs.pulseaudioFull; 4 | in { 5 | boot = { 6 | kernelModules = [ "snd-seq" "snd-rawmidi" ]; 7 | }; 8 | 9 | hardware.pulseaudio = { 10 | enable = true; 11 | support32Bit = true; 12 | package = pulse; 13 | }; 14 | 15 | services.mpd = { 16 | enable = true; 17 | user = "anders"; 18 | group = "users"; 19 | musicDirectory = "/home/anders/Music"; 20 | dataDir = "/home/anders/.mpd"; 21 | extraConfig = '' 22 | audio_output { 23 | type "pulse" 24 | name "Local MPD" 25 | server "127.0.0.1" 26 | } 27 | ''; 28 | }; 29 | } 30 | -------------------------------------------------------------------------------- /base.nix: -------------------------------------------------------------------------------- 1 | { config, pkgs, ... }: 2 | 3 | { boot = { 4 | cleanTmpDir = true; 5 | kernelPackages = pkgs.linuxPackages_latest; 6 | kernel.sysctl = { 7 | "net.ipv4.ip_forward" = 1; 8 | "vm.overcommit_memory" = 1; 9 | }; 10 | kernelParams = [ 11 | "transparent_hugepage=never" 12 | ]; 13 | }; 14 | 15 | documentation.man.enable = true; 16 | 17 | environment.variables = { EDITOR = "editor"; }; 18 | 19 | networking = { 20 | firewall = { 21 | allowPing = true; 22 | }; 23 | }; 24 | 25 | programs = { 26 | bash = { 27 | interactiveShellInit = '' 28 | HISTCONTROL=ignoreboth:erasedups 29 | shopt -s histappend 30 | ''; 31 | promptInit = '' 32 | PS1="\[\033[1;32m\][\u@\h:\w]\n\$\[\033[0m\] " 33 | ''; 34 | shellAliases = { ssh = "TERM=xterm-256color ssh"; }; 35 | }; 36 | ssh.startAgent = false; 37 | }; 38 | 39 | services = { 40 | openssh.enable = true; 41 | nixosManual.showManual = true; 42 | }; 43 | 44 | security = { 45 | sudo.wheelNeedsPassword = false; 46 | pam.loginLimits = 47 | [ { domain = "*"; item = "nofile"; type = "-"; value = "999999"; } 48 | ]; 49 | }; 50 | 51 | time.timeZone = "America/Los_Angeles"; 52 | } 53 | -------------------------------------------------------------------------------- /config/compton-inverted: -------------------------------------------------------------------------------- 1 | backend = "glx" 2 | vsync = "opengl" 3 | 4 | opacity-rule = [ 5 | "0:_NET_WM_STATE@:32a *= '_NET_WM_STATE_HIDDEN'" 6 | ]; 7 | inactive-opacity = 0.7 8 | 9 | invert-color-include = [ "class_g ~?= '(Okular|Evince|Pavucontrol|Chromium|libprs500|Conkeror|scide|Audacious|Firefox|Tomahawk|KeePassX|Quassel|Clementine)' && name !~?= 'Facebook|Youtube|YouTube - Vimperator$|Card Game|[.]elm - Nightly$|localhost|NOINVERT'" ]; -------------------------------------------------------------------------------- /config/compton-noninverted: -------------------------------------------------------------------------------- 1 | backend = "glx" 2 | vsync = "opengl" 3 | 4 | opacity-rule = [ 5 | "0:_NET_WM_STATE@:32a *= '_NET_WM_STATE_HIDDEN'" 6 | ]; 7 | inactive-opacity = 0.7 8 | -------------------------------------------------------------------------------- /config/dunstrc: -------------------------------------------------------------------------------- 1 | [global] 2 | font = Monospace 8 3 | 4 | # Allow a small subset of html markup: 5 | # bold 6 | # italic 7 | # strikethrough 8 | # underline 9 | # 10 | # For a complete reference see 11 | # . 12 | # If markup is not allowed, those tags will be stripped out of the 13 | # message. 14 | allow_markup = yes 15 | 16 | # The format of the message. Possible variables are: 17 | # %a appname 18 | # %s summary 19 | # %b body 20 | # %i iconname (including its path) 21 | # %I iconname (without its path) 22 | # %p progress value if set ([ 0%] to [100%]) or nothing 23 | # Markup is allowed 24 | format = "%s\n%b %p" 25 | 26 | # Sort messages by urgency. 27 | sort = yes 28 | 29 | # Show how many messages are currently hidden (because of geometry). 30 | indicate_hidden = yes 31 | 32 | # Alignment of message text. 33 | # Possible values are "left", "center" and "right". 34 | alignment = center 35 | 36 | # The frequency with wich text that is longer than the notification 37 | # window allows bounces back and forth. 38 | # This option conflicts with "word_wrap". 39 | # Set to 0 to disable. 40 | bounce_freq = 0 41 | 42 | # Show age of message if message is older than show_age_threshold 43 | # seconds. 44 | # Set to -1 to disable. 45 | show_age_threshold = 60 46 | 47 | # Split notifications into multiple lines if they don't fit into 48 | # geometry. 49 | word_wrap = yes 50 | 51 | # Ignore newlines '\n' in notifications. 52 | ignore_newline = no 53 | 54 | 55 | # The geometry of the window: 56 | # [{width}]x{height}[+/-{x}+/-{y}] 57 | # The geometry of the message window. 58 | # The height is measured in number of notifications everything else 59 | # in pixels. If the width is omitted but the height is given 60 | # ("-geometry x2"), the message window expands over the whole screen 61 | # (dmenu-like). If width is 0, the window expands to the longest 62 | # message displayed. A positive x is measured from the left, a 63 | # negative from the right side of the screen. Y is measured from 64 | # the top and down respectevly. 65 | # The width can be negative. In this case the actual width is the 66 | # screen width minus the width defined in within the geometry option. 67 | geometry = "300x5-30+20" 68 | 69 | # Shrink window if it's smaller than the width. Will be ignored if 70 | # width is 0. 71 | shrink = no 72 | 73 | # The transparency of the window. Range: [0; 100]. 74 | # This option will only work if a compositing windowmanager is 75 | # present (e.g. xcompmgr, compiz, etc.). 76 | transparency = 0 77 | 78 | # Don't remove messages, if the user is idle (no mouse or keyboard input) 79 | # for longer than idle_threshold seconds. 80 | # Set to 0 to disable. 81 | idle_threshold = 120 82 | 83 | # Which monitor should the notifications be displayed on. 84 | monitor = 0 85 | 86 | # Display notification on focused monitor. Possible modes are: 87 | # mouse: follow mouse pointer 88 | # keyboard: follow window with keyboard focus 89 | # none: don't follow anything 90 | # 91 | # "keyboard" needs a windowmanager that exports the 92 | # _NET_ACTIVE_WINDOW property. 93 | # This should be the case for almost all modern windowmanagers. 94 | # 95 | # If this option is set to mouse or keyboard, the monitor option 96 | # will be ignored. 97 | follow = keyboard 98 | 99 | # Should a notification popped up from history be sticky or timeout 100 | # as if it would normally do. 101 | sticky_history = yes 102 | 103 | # Maximum amount of notifications kept in history 104 | history_length = 20 105 | 106 | # Display indicators for URLs (U) and actions (A). 107 | show_indicators = yes 108 | 109 | # The height of a single line. If the height is smaller than the 110 | # font height, it will get raised to the font height. 111 | # This adds empty space above and under the text. 112 | line_height = 0 113 | 114 | # Draw a line of "separatpr_height" pixel height between two 115 | # notifications. 116 | # Set to 0 to disable. 117 | separator_height = 2 118 | 119 | # Padding between text and separator. 120 | padding = 8 121 | 122 | # Horizontal padding. 123 | horizontal_padding = 8 124 | 125 | # Define a color for the separator. 126 | # possible values are: 127 | # * auto: dunst tries to find a color fitting to the background; 128 | # * foreground: use the same color as the foreground; 129 | # * frame: use the same color as the frame; 130 | # * anything else will be interpreted as a X color. 131 | separator_color = frame 132 | 133 | # Print a notification on startup. 134 | # This is mainly for error detection, since dbus (re-)starts dunst 135 | # automatically after a crash. 136 | startup_notification = false 137 | 138 | # dmenu path. 139 | dmenu = dmenu -p dunst: 140 | 141 | # Browser for opening urls in context menu. 142 | browser = browser 143 | 144 | # Align icons left/right/off 145 | icon_position = left 146 | 147 | # Paths to default icons. 148 | # icon_folders = /usr/share/icons/gnome/16x16/status/:/usr/share/icons/gnome/16x16/devices/ 149 | 150 | [frame] 151 | width = 3 152 | color = "#aaaaaa" 153 | 154 | [shortcuts] 155 | 156 | # Shortcuts are specified as [modifier+][modifier+]...key 157 | # Available modifiers are "ctrl", "mod1" (the alt-key), "mod2", 158 | # "mod3" and "mod4" (windows-key). 159 | # Xev might be helpful to find names for keys. 160 | 161 | # Close notification. 162 | close = mod4+space 163 | 164 | # Close all notifications. 165 | # close_all = mod4+shift+space 166 | 167 | # Redisplay last message(s). 168 | # On the US keyboard layout "grave" is normally above TAB and left 169 | # of "1". 170 | history = mod4+shift+space 171 | 172 | # Context menu. 173 | # context = ctrl+shift+period 174 | 175 | [urgency_low] 176 | # IMPORTANT: colors have to be defined in quotation marks. 177 | # Otherwise the "#" and following would be interpreted as a comment. 178 | background = "#222222" 179 | foreground = "#888888" 180 | timeout = 10 181 | 182 | [urgency_normal] 183 | background = "#285577" 184 | foreground = "#ffffff" 185 | timeout = 10 186 | 187 | [urgency_critical] 188 | background = "#900000" 189 | foreground = "#ffffff" 190 | timeout = 0 191 | 192 | 193 | # Every section that isn't one of the above is interpreted as a rules to 194 | # override settings for certain messages. 195 | # Messages can be matched by "appname", "summary", "body", "icon", "category", 196 | # "msg_urgency" and you can override the "timeout", "urgency", "foreground", 197 | # "background", "new_icon" and "format". 198 | # Shell-like globbing will get expanded. 199 | # 200 | # SCRIPTING 201 | # You can specify a script that gets run when the rule matches by 202 | # setting the "script" option. 203 | # The script will be called as follows: 204 | # script appname summary body icon urgency 205 | # where urgency can be "LOW", "NORMAL" or "CRITICAL". 206 | # 207 | # NOTE: if you don't want a notification to be displayed, set the format 208 | # to "". 209 | # NOTE: It might be helpful to run dunst -print in a terminal in order 210 | # to find fitting options for rules. 211 | 212 | #[espeak] 213 | # summary = "*" 214 | # script = dunst_espeak.sh 215 | 216 | #[script-test] 217 | # summary = "*script*" 218 | # script = dunst_test.sh 219 | 220 | #[ignore] 221 | # # This notification will not be displayed 222 | # summary = "foobar" 223 | # format = "" 224 | 225 | #[signed_on] 226 | # appname = Pidgin 227 | # summary = "*signed on*" 228 | # urgency = low 229 | # 230 | #[signed_off] 231 | # appname = Pidgin 232 | # summary = *signed off* 233 | # urgency = low 234 | # 235 | #[says] 236 | # appname = Pidgin 237 | # summary = *says* 238 | # urgency = critical 239 | # 240 | #[twitter] 241 | # appname = Pidgin 242 | # summary = *twitter.com* 243 | # urgency = normal 244 | # 245 | # vim: ft=cfg 246 | -------------------------------------------------------------------------------- /config/i3: -------------------------------------------------------------------------------- 1 | ########## 2 | # Behavior 3 | ########## 4 | 5 | workspace_layout tabbed 6 | 7 | no_focus [class="Chromium"] 8 | no_focus [class="Firefox"] 9 | focus_on_window_activation focus 10 | 11 | for_window [title="Org Select"] floating enable 12 | for_window [title="CAPTURE"] floating enable 13 | 14 | new_window none 15 | hide_edge_borders both 16 | force_focus_wrapping yes 17 | 18 | gaps inner 6 19 | gaps outer 6 20 | smart_gaps on 21 | 22 | ############# 23 | # Keybindings 24 | ############# 25 | 26 | set $mod Mod4 27 | 28 | bindsym $mod+Shift+Return exec anders-terminal 29 | bindsym $mod+Return exec alacritty 30 | 31 | bindsym $mod+d exec rofi -show run 32 | 33 | bindsym F1 exec anders-handle-keybind F1 34 | bindsym F2 exec anders-handle-keybind F2 35 | bindsym F3 exec anders-handle-keybind F3 36 | bindsym F7 exec anders-handle-keybind F7 37 | bindsym F9 exec anders-handle-keybind F9 38 | bindsym F10 exec anders-handle-keybind F10 39 | bindsym F11 exec anders-handle-keybind F11 40 | bindsym F12 exec anders-handle-keybind F12 41 | 42 | bindsym $mod+Shift+q kill 43 | 44 | bindsym $mod+comma workspace prev 45 | bindsym $mod+period workspace next 46 | 47 | bindsym $mod+j exec i3-focus down 48 | bindsym $mod+k exec i3-focus up 49 | bindsym $mod+h exec i3-focus left 50 | bindsym $mod+l exec i3-focus right 51 | 52 | bindsym $mod+Tab focus right 53 | bindsym $mod+grave focus left 54 | 55 | 56 | bindsym $mod+Shift+j move down 57 | bindsym $mod+Shift+k move up 58 | bindsym $mod+Shift+h move left 59 | bindsym $mod+Shift+l move right 60 | 61 | bindsym $mod+s split h 62 | bindsym $mod+v split v 63 | 64 | bindsym $mod+p focus parent 65 | bindsym $mod+c focus child 66 | 67 | # switch to workspace 68 | bindsym $mod+1 workspace 1 69 | bindsym $mod+2 workspace 2 70 | bindsym $mod+3 workspace 3 71 | bindsym $mod+4 workspace 4 72 | bindsym $mod+5 workspace 5 73 | bindsym $mod+6 workspace 6 74 | bindsym $mod+7 workspace 7 75 | bindsym $mod+8 workspace 8 76 | bindsym $mod+9 workspace 9 77 | bindsym $mod+0 workspace 10 78 | 79 | # move focused container to workspace 80 | bindsym $mod+Shift+1 move container to workspace 1 81 | bindsym $mod+Shift+2 move container to workspace 2 82 | bindsym $mod+Shift+3 move container to workspace 3 83 | bindsym $mod+Shift+4 move container to workspace 4 84 | bindsym $mod+Shift+5 move container to workspace 5 85 | bindsym $mod+Shift+6 move container to workspace 6 86 | bindsym $mod+Shift+7 move container to workspace 7 87 | bindsym $mod+Shift+8 move container to workspace 8 88 | bindsym $mod+Shift+9 move container to workspace 9 89 | bindsym $mod+Shift+0 move container to workspace 10 90 | 91 | ####### 92 | # Looks 93 | ####### 94 | 95 | # Font for window titles. Will also be used by the bar unless a different font 96 | # is used in the bar {} block below. 97 | # This font is widely installed, provides lots of unicode glyphs, right-to-left 98 | # text rendering and scalability on retina/hidpi displays (thanks to pango). 99 | font pango:DejaVu Sans Mono 11 100 | 101 | # Start i3bar to display a workspace bar (plus the system information i3status 102 | # finds out, if available) 103 | bar { 104 | status_command anders-i3status 105 | 106 | colors { 107 | background $bg 108 | statusline $fg 109 | separator $hi 110 | focused_workspace $gn $bg $ac 111 | active_workspace $gn $ac $tx 112 | inactive_workspace $bg $bg $ia 113 | urgent_workspace $rd $bg $ac 114 | } 115 | } 116 | 117 | # color defines for zenburn styled i3 118 | set $bg #2c2c2e 119 | set $fg #9f9f9f 120 | set $hi #efef8f 121 | set $ac #a0afa0 122 | set $tx #040404 123 | set $ia #8f8f8f 124 | set $be #8faf9f 125 | set $yw #ccdc90 126 | set $gn #88b090 127 | set $rd #e89393 128 | 129 | # set some nice colors border background text 130 | client.focused $bg $rd $tx 131 | client.focused_inactive $bg $yw $tx 132 | client.unfocused $bg $ac $tx 133 | client.urgent $bg $bg $ac 134 | # client.unfocused $bg $bg $ia 135 | # client.focused_inactive $bg $bg $ac 136 | # client.urgent $rd $rd $tx 137 | -------------------------------------------------------------------------------- /config/i3status: -------------------------------------------------------------------------------- 1 | general { 2 | output_format = i3bar 3 | colors = true 4 | interval = 1 5 | } 6 | 7 | order += "wireless wlp4s0" 8 | order += "volume pulse" 9 | order += "battery 0" 10 | order += "tztime local" 11 | 12 | wireless wlp4s0 { 13 | format_up = "W: (%quality at %essid) %ip" 14 | format_down = "W: down" 15 | } 16 | 17 | volume pulse { 18 | format = "♪: %volume" 19 | format_muted = "♪: muted (%volume)" 20 | device = "pulse" 21 | } 22 | 23 | disk "/" { 24 | format = "/ %avail" 25 | } 26 | 27 | disk "/nix/store" { 28 | format = "/nix/store %avail" 29 | } 30 | 31 | disk "/home" { 32 | format = "/home %avail" 33 | } 34 | 35 | battery 0 { 36 | format = "%status %percentage %remaining" 37 | last_full_capacity = true 38 | integer_battery_capacity = true 39 | low_threshold = 15 40 | threshold_type = percentage 41 | } 42 | 43 | tztime local { 44 | format = "%Y-%m-%d %H:%M:%S" 45 | } 46 | -------------------------------------------------------------------------------- /config/i3status-netns: -------------------------------------------------------------------------------- 1 | general { 2 | output_format = i3bar 3 | colors = true 4 | interval = 1 5 | } 6 | 7 | order += "wireless wlp4s0" 8 | 9 | wireless wlp4s0 { 10 | format_up = "W: (%quality at %essid) %ip" 11 | format_down = "W: down" 12 | } 13 | -------------------------------------------------------------------------------- /config/init.el: -------------------------------------------------------------------------------- 1 | ;;; bootstrap use-package 2 | 3 | (require 'package) 4 | (setq package-enable-at-startup nil) 5 | (add-to-list 'package-archives 6 | '("melpa-stable" . "https://stable.melpa.org/packages/") t) 7 | (add-to-list 'package-archives '("orgmode" . "http://orgmode.org/elpa/")) 8 | (package-initialize) 9 | 10 | (unless (package-installed-p 'use-package) 11 | (package-refresh-contents) 12 | (package-install 'use-package)) 13 | (require 'use-package) 14 | (setq use-package-always-ensure t) 15 | 16 | ;;; Elisp utilities 17 | 18 | (use-package f) 19 | (use-package s) 20 | 21 | ;;; Actual packages, except language-specific 22 | 23 | (use-package avy 24 | :bind ("C-t" . avy-goto-char)) 25 | 26 | (use-package company 27 | :bind (:map company-active-map 28 | ("RET" . nil) 29 | ("M-1" . company-complete-selection)) 30 | :init 31 | (setq company-global-modes '(not gud-mode)) 32 | (setq company-dabbrev-downcase nil) 33 | :config 34 | (global-company-mode)) 35 | 36 | (use-package compile 37 | :init 38 | (setq compilation-always-kill t) 39 | (setq compilation-ask-about-save nil) 40 | :config 41 | ;; Do to my particular windowing setup (only window-manager-level 42 | ;; splits), I want a drastically simpler version of 43 | ;; compilation-goto-locus. It's not really possible to do this from 44 | ;; the outside, so just override the function. 45 | (defun compilation-goto-locus (msg mk end-mk) 46 | "Jump to an error corresponding to MSG at MK. 47 | All arguments are markers. If END-MK is non-nil, mark is set there 48 | and overlay is highlighted between MK and END-MK." 49 | 50 | (display-buffer (marker-buffer msg) '(nil (allow-no-window . t))) 51 | (with-current-buffer (marker-buffer msg) 52 | (goto-char (marker-position msg)) 53 | (and w (compilation-set-window w msg))) 54 | 55 | (display-buffer (marker-buffer mk)) 56 | 57 | (with-current-buffer (marker-buffer mk) 58 | (unless (eq (goto-char mk) (point)) 59 | ;; If narrowing gets in the way of going to the right place, widen. 60 | (widen) 61 | (if next-error-move-function 62 | (funcall next-error-move-function msg mk) 63 | (goto-char mk))) 64 | (if end-mk 65 | (push-mark end-mk t) 66 | (if mark-active (setq mark-active))) 67 | ;; If hideshow got in the way of 68 | ;; seeing the right place, open permanently. 69 | (dolist (ov (overlays-at (point))) 70 | (when (eq 'hs (overlay-get ov 'invisible)) 71 | (delete-overlay ov) 72 | (goto-char mk)))))) 73 | 74 | (use-package expand-region 75 | :bind ("C-=" . er/expand-region)) 76 | 77 | (use-package flymake) 78 | 79 | (use-package god-mode 80 | :bind (("" . god-local-mode) 81 | :map god-local-mode-map 82 | ("i" . god-local-mode) 83 | ("." . repeat) 84 | :map isearch-mode-map 85 | ("" . god-mode-isearch-activate) 86 | :map god-mode-isearch-map 87 | ("" . god-mode-isearch-disable)) 88 | :init 89 | (setq god-mod-alist 90 | '((nil . "C-") 91 | ("t" . "M-") 92 | ("T" . "C-M-"))) 93 | (defun anders/update-cursor () 94 | (setq cursor-type (if god-local-mode 'box 'bar))) 95 | :hook 96 | ((god-mode-enabled god-mode-disabled) . anders/update-cursor) 97 | :config 98 | (require 'god-mode-isearch) 99 | 100 | ;; bugfix for https://github.com/chrisdone/god-mode/issues/110 101 | (defun god-mode-upper-p (char) 102 | "Is the given char upper case?" 103 | (and (>= char ?A) 104 | (<= char ?Z) 105 | (/= char ?T)))) 106 | 107 | (use-package ivy 108 | :init 109 | (setq ivy-initial-inputs-alist '()) 110 | :config 111 | (ivy-mode 0)) 112 | 113 | ;; Magit is awesome. 114 | (use-package magit 115 | :init 116 | (setq magit-commit-show-diff nil) 117 | (setq magit-delete-by-moving-to-trash nil) 118 | (setq magit-diff-expansion-threshold 2.0) 119 | (setq magit-diff-use-overlays nil) 120 | (setq magit-no-confirm 121 | '(abort-rebase 122 | delete-unmerged-branch 123 | drop-stashes 124 | stage-all-changes 125 | unstage-all-changes)) 126 | (setq magit-revert-buffers t) 127 | (setq magit-use-overlays nil)) 128 | 129 | (use-package man 130 | :init 131 | (setq Man-width 80) 132 | (setq Man-notify-method 'pushy)) 133 | 134 | (use-package multiple-cursors 135 | :bind (("C-S-c C-S-c" . mc/edit-lines) 136 | ("C->" . mc/mark-next-like-this) 137 | ("C-<" . mc/mark-previous-like-this) 138 | ("C-c C-<" . mc/mark-all-like-this))) 139 | 140 | (use-package org 141 | :bind (("C-c a" . org-agenda)) 142 | :hook 143 | ((org-mode) . real-auto-save-mode) 144 | ((org-mode) . auto-revert-mode) 145 | ((org-capture-after-finalize) . delete-frame) 146 | :init 147 | ;; Utility function so that I don't have to fix the set of org files 148 | ;; statically. 149 | (defun anders/dynamic-org-files (directory) 150 | (f-entries directory 151 | (lambda (filename) (s-ends-with-p ".org" filename)) 152 | t)) 153 | (defun anders/dynamic-all-org-files () 154 | (anders/dynamic-org-files "~/projects")) 155 | 156 | (setq org-agenda-window-setup 'current-window) 157 | 158 | ;; Set up the agenda for the particular things I want out of it. 159 | (setq org-agenda-compact-blocks t) 160 | (setq org-agenda-span 'day) 161 | (setq org-agenda-time-grid 162 | '((daily today require-timed) 163 | () 164 | "......")) 165 | (setq org-agenda-custom-commands 166 | '(("a" "Agenda" 167 | ((agenda "" 168 | ((org-agenda-files 169 | (anders/dynamic-org-files "~/projects")) 170 | (org-super-agenda-groups 171 | '((:discard (:tag "agenda_ignore")) 172 | (:name "Important" 173 | :priority "A") 174 | (:name "Appointments" 175 | :time-grid t) 176 | (:name "Tasks" 177 | :scheduled t) 178 | )))) 179 | (tags-todo "+project+active" 180 | ((org-agenda-files 181 | (anders/dynamic-org-files "~/projects")))) 182 | (tags "+project+ongoing" 183 | ((org-agenda-files 184 | (anders/dynamic-org-files "~/projects")) 185 | (org-use-tag-inheritance nil))))) 186 | ("c" "Captures" 187 | ((tags-todo "capture" 188 | ((org-agenda-files 189 | (anders/dynamic-org-files "~/projects/special")) 190 | (org-use-tag-inheritance t) 191 | (org-agenda-overriding-header "Capture"))))))) 192 | 193 | (setq org-capture-templates 194 | '(("t" "Todo" entry 195 | (file "~/projects/special/capture/capture.org") 196 | "* TODO %?\n %i"))) 197 | 198 | (setq org-goto-interface 'outline-path-completion) 199 | 200 | ;; I only refile from my capture files to the top (file) level of 201 | ;; other org files. 202 | ;; 203 | ;; Forcing level == 100 is a hack to perfomantly filter out all 204 | ;; headings and leave only file names. 205 | ;; 206 | ;; The argument to org-refile-targets must be a named function. 207 | (setq org-refile-use-outline-path 't) 208 | (setq org-refile-targets '((anders/dynamic-all-org-files . (:tag . "refile")))) 209 | (setq org-outline-path-complete-in-steps nil) 210 | 211 | ;; Miscellaneous 212 | (setq org-fast-tag-selection-single-key t) 213 | (setq org-from-is-user-regexp nil) 214 | (setq org-hide-leading-stars t) 215 | (setq org-read-date-force-compatible-dates nil) 216 | (setq org-read-date-popup-calendar nil)) 217 | 218 | (use-package org-super-agenda 219 | :config 220 | (org-super-agenda-mode)) 221 | 222 | (use-package projectile 223 | :init 224 | (defun anders/vc-or-dired () 225 | (interactive) 226 | (projectile-dired) 227 | (ignore-errors (projectile-vc))) 228 | (defun anders/ignore-project (project) 229 | (string-match-p "/nix/store" project)) 230 | (setq projectile-keymap-prefix (kbd "M-t")) 231 | (setq projectile-mode-line 232 | ''(:eval (format "Projectile[%s]" default-directory))) 233 | (setq projectile-switch-project-action 'anders/vc-or-dired) 234 | (setq projectile-completion-system 'ivy) 235 | (setq projectile-ignored-project-function 'anders/ignore-project) 236 | :config 237 | (projectile-global-mode) 238 | (ad-deactivate 'compilation-find-file)) 239 | 240 | (use-package projectile-ripgrep 241 | :bind ((:map projectile-command-map 242 | (("s g" . projectile-ripgrep))))) 243 | 244 | (use-package real-auto-save 245 | :init 246 | (setq real-auto-save-interval 30)) 247 | 248 | (use-package subword 249 | :config 250 | (global-subword-mode)) 251 | 252 | (use-package term 253 | :bind (("M-RET" . anders/get-term) 254 | :map term-mode-map 255 | (("M-i" . anders/term-toggle-mode)) 256 | :map term-raw-map 257 | (("M-i" . anders/term-toggle-mode) 258 | ("C-y" . term-paste))) 259 | :init 260 | (defun anders/new-term () 261 | (interactive) 262 | (term "bash") 263 | (rename-buffer "shell" t)) 264 | (defun anders/get-term () 265 | (interactive) 266 | (if (get-buffer "shell") 267 | (switch-to-buffer "shell") 268 | (anders/new-term))) 269 | (defun anders/expose-global-binding-in-term (binding) 270 | (define-key term-raw-map binding 271 | (lookup-key (current-global-map) binding))) 272 | (defun anders/term-toggle-mode () 273 | "Toggles term between line mode and char mode" 274 | (interactive) 275 | (if (term-in-line-mode) 276 | (term-char-mode) 277 | (term-line-mode))) 278 | :config 279 | (anders/expose-global-binding-in-term (kbd "M-x")) 280 | (anders/expose-global-binding-in-term (kbd "C-x")) 281 | (anders/expose-global-binding-in-term (kbd "C-c a"))) 282 | 283 | 284 | (use-package tramp 285 | :init 286 | (setq tramp-default-method "ssh") 287 | (setq tramp-use-ssh-controlmaster-options nil) 288 | :config 289 | (add-to-list 'tramp-remote-path "/run/current-system/sw/bin")) 290 | 291 | (use-package undo-tree 292 | :init 293 | (setq undo-tree-auto-save-history t) 294 | (setq undo-tree-history-directory-alist '(("." . "/tmp/undo-tree"))) 295 | :config 296 | (global-undo-tree-mode)) 297 | 298 | (use-package whitespace 299 | :bind ("C-x C-s" . anders/save-with-delete-trailing-whitespace) 300 | :hook ((prog-mode . whitespace-mode)) 301 | :init 302 | (setq-default indent-tabs-mode nil) 303 | (setq whitespace-style '(face tabs)) 304 | (defun anders/save-with-delete-trailing-whitespace () 305 | (interactive) 306 | (delete-trailing-whitespace) 307 | (save-buffer))) 308 | 309 | ;;; Programming-language specific packages 310 | 311 | (use-package cargo) 312 | 313 | (use-package elm-mode 314 | :init 315 | (setq elm-sort-imports-on-save t) 316 | (setq elm-format-on-save t)) 317 | 318 | (use-package haskell-mode) 319 | 320 | (use-package intero 321 | :init 322 | (defun anders/intero-mode-unless-global-project () 323 | "Run intero-mode iff we're in a project with a stack.yaml" 324 | (interactive) 325 | (let* ((stack-command "stack path --project-root --verbosity silent") 326 | (stack-path (ignore-errors (shell-command-to-string stack-command)))) 327 | (unless (or 328 | (string-match-p (regexp-quote "not found") stack-path) 329 | (string-match-p (regexp-quote "global") stack-path)) 330 | (intero-mode)))) 331 | :hook ((haskell-mode . anders/intero-mode-unless-global-project))) 332 | (setq haskell-mode-hook nil) 333 | 334 | (use-package lua-mode) 335 | 336 | (use-package markdown-mode 337 | :mode 338 | (("\\.markdown\\'" . markdown-mode) 339 | ("\\.md\\'" . markdown-mode))) 340 | 341 | (use-package nix-mode) 342 | 343 | (use-package protobuf-mode) 344 | 345 | (use-package rust-mode 346 | :init 347 | (eval-after-load 'compile 348 | (remove-hook 'next-error-hook 'rustc-scroll-down-after-next-error))) 349 | 350 | (use-package yaml-mode) 351 | 352 | ;;; Copy/paste 353 | 354 | (setq kill-do-not-save-duplicates t) 355 | (setq save-interprogram-paste-before-kill t) 356 | (setq select-enable-clipboard nil) 357 | (setq select-enable-primary t) 358 | 359 | ;;; Window management 360 | 361 | ;; gud mode is a bad actor 362 | (setq gdb-display-io-nopopup t) 363 | 364 | (setq frame-auto-hide-function 'delete-frame) 365 | (setq display-buffer-alist 366 | '(("shell.*" (display-buffer-same-window) ()) 367 | (".*" (display-buffer-reuse-window 368 | display-buffer-same-window 369 | display-buffer-pop-up-frame) 370 | (reusable-frames . t)))) 371 | 372 | (defun anders/same-window-instead 373 | (orig-fun buffer alist) 374 | (display-buffer-same-window buffer nil)) 375 | (advice-add 'display-buffer-pop-up-window :around 'anders/same-window-instead) 376 | 377 | (defun anders/do-select-frame (orig-fun buffer &rest args) 378 | (let* ((old-frame (selected-frame)) 379 | (window (apply orig-fun buffer args)) 380 | (frame (window-frame window))) 381 | (unless (eq frame old-frame) 382 | (select-frame-set-input-focus frame)) 383 | (select-window window) 384 | window)) 385 | (advice-add 'display-buffer :around 'anders/do-select-frame) 386 | 387 | ;; Dedicated windows are evil 388 | (advice-add 'set-window-dedicated-p :around 389 | (lambda (orig-fun &rest args) nil)) 390 | 391 | ;;; Luddite mode 392 | 393 | (set-scroll-bar-mode nil) 394 | (setq tool-bar-mode nil) 395 | (setq menu-bar-mode nil) 396 | (setq initial-scratch-message nil) 397 | 398 | ;;; Looks 399 | 400 | (setq-default truncate-lines t) 401 | (set-face-attribute 'default nil :height 110) 402 | (set-face-attribute 'default nil :family "Inconsolata") 403 | ;; (load-theme 'deeper-blue) 404 | (show-paren-mode 1) 405 | 406 | ;;; Miscellaneous 407 | 408 | (defun anders/switch-to-previous-buffer () 409 | "Switch to previously open buffer. 410 | Repeated invocations toggle between the two most recently open buffers." 411 | (interactive) 412 | (switch-to-buffer (other-buffer (current-buffer) 1))) 413 | (global-set-key "\M-o" 'anders/switch-to-previous-buffer) 414 | 415 | (global-set-key (kbd "C-z") nil) 416 | (global-set-key (kbd "C-x k") 'kill-this-buffer) 417 | (setq auto-save-file-name-transforms '((".*" "/tmp/" t))) 418 | (setq backup-directory-alist '((".*" . "/tmp/"))) 419 | (setq dired-auto-revert-buffer t) 420 | (setq recenter-positions '(bottom middle top)) 421 | (setq uniquify-buffer-name-style 'post-forward) 422 | 423 | ;;; various stuff that I just always want to have open 424 | 425 | (when (daemonp) 426 | (progn 427 | (find-file-noselect "/etc/nixos/configuration/config/init.el") 428 | (find-file-noselect "/etc/nixos/configuration/private/bad-hosts.nix") 429 | (man "configuration.nix"))) 430 | -------------------------------------------------------------------------------- /config/xresources: -------------------------------------------------------------------------------- 1 | # ! Solarized color scheme for the X Window System 2 | # ! 3 | # ! http://ethanschoonover.com/solarized 4 | # 5 | # 6 | # ! Common 7 | # 8 | # #define S_yellow #b58900 9 | # #define S_orange #cb4b16 10 | # #define S_red #dc322f 11 | # #define S_magenta #d33682 12 | # #define S_violet #6c71c4 13 | # #define S_blue #268bd2 14 | # #define S_cyan #2aa198 15 | # #define S_green #859900 16 | # 17 | # 18 | # ! Dark 19 | # 20 | # ! #define S_base03 #002b36 21 | # ! #define S_base02 #073642 22 | # ! #define S_base01 #586e75 23 | # ! #define S_base00 #657b83 24 | # ! #define S_base0 #839496 25 | # ! #define S_base1 #93a1a1 26 | # ! #define S_base2 #eee8d5 27 | # ! #define S_base3 #fdf6e3 28 | # 29 | # 30 | # ! Light 31 | # 32 | # #define S_base03 #fdf6e3 33 | # #define S_base02 #eee8d5 34 | # #define S_base01 #93a1a1 35 | # #define S_base00 #839496 36 | # #define S_base0 #657b83 37 | # #define S_base1 #586e75 38 | # #define S_base2 #073642 39 | # #define S_base3 #002b36 40 | # 41 | # 42 | # *background: S_base03 43 | # *foreground: S_base0 44 | # *cursorColor: S_base1 45 | # *pointerColorBackground: S_base01 46 | # *pointerColorForeground: S_base1 47 | # 48 | # *color0: S_base02 49 | # *color1: S_red 50 | # *color2: S_green 51 | # *color3: S_yellow 52 | # *color4: S_blue 53 | # *color5: S_magenta 54 | # *color6: S_cyan 55 | # *color7: S_base2 56 | # *color9: S_orange 57 | # *color8: S_base03 58 | # *color10: S_base01 59 | # *color11: S_base00 60 | # *color12: S_base0 61 | # *color13: S_violet 62 | # *color14: S_base1 63 | # *color15: S_base3 64 | -------------------------------------------------------------------------------- /copied/dhcpcd.nix: -------------------------------------------------------------------------------- 1 | { config, lib, pkgs, ... }: 2 | 3 | with lib; 4 | 5 | let 6 | 7 | dhcpcd = if !config.boot.isContainer then pkgs.dhcpcd else pkgs.dhcpcd.override { udev = null; }; 8 | 9 | cfg = config.networking.dhcpcd; 10 | 11 | interfaces = attrValues config.networking.interfaces; 12 | 13 | enableDHCP = config.networking.dhcpcd.enable && 14 | (config.networking.useDHCP || any (i: i.useDHCP == true) interfaces); 15 | 16 | # Don't start dhcpcd on explicitly configured interfaces or on 17 | # interfaces that are part of a bridge, bond or sit device. 18 | ignoredInterfaces = 19 | map (i: i.name) (filter (i: if i.useDHCP != null then !i.useDHCP else i.ipv4.addresses != [ ]) interfaces) 20 | ++ mapAttrsToList (i: _: i) config.networking.sits 21 | ++ concatLists (attrValues (mapAttrs (n: v: v.interfaces) config.networking.bridges)) 22 | ++ concatLists (attrValues (mapAttrs (n: v: v.interfaces) config.networking.vswitches)) 23 | ++ concatLists (attrValues (mapAttrs (n: v: v.interfaces) config.networking.bonds)) 24 | ++ config.networking.dhcpcd.denyInterfaces; 25 | 26 | arrayAppendOrNull = a1: a2: if a1 == null && a2 == null then null 27 | else if a1 == null then a2 else if a2 == null then a1 28 | else a1 ++ a2; 29 | 30 | # If dhcp is disabled but explicit interfaces are enabled, 31 | # we need to provide dhcp just for those interfaces. 32 | allowInterfaces = arrayAppendOrNull cfg.allowInterfaces 33 | (if !config.networking.useDHCP && enableDHCP then 34 | map (i: i.name) (filter (i: i.useDHCP == true) interfaces) else null); 35 | 36 | # Config file adapted from the one that ships with dhcpcd. 37 | dhcpcdConf = pkgs.writeText "dhcpcd.conf" 38 | '' 39 | # Inform the DHCP server of our hostname for DDNS. 40 | hostname 41 | 42 | # A list of options to request from the DHCP server. 43 | option domain_name_servers, domain_name, domain_search, host_name 44 | option classless_static_routes, ntp_servers, interface_mtu 45 | 46 | # A ServerID is required by RFC2131. 47 | # Commented out because of many non-compliant DHCP servers in the wild :( 48 | #require dhcp_server_identifier 49 | 50 | # A hook script is provided to lookup the hostname if not set by 51 | # the DHCP server, but it should not be run by default. 52 | nohook lookup-hostname 53 | 54 | # Ignore peth* devices; on Xen, they're renamed physical 55 | # Ethernet cards used for bridging. Likewise for vif* and tap* 56 | # (Xen) and virbr* and vnet* (libvirt). 57 | denyinterfaces ${toString ignoredInterfaces} lo peth* vif* tap* tun* virbr* vnet* vboxnet* sit* 58 | 59 | # Use the list of allowed interfaces if specified 60 | ${optionalString (allowInterfaces != null) "allowinterfaces ${toString allowInterfaces}"} 61 | 62 | ${cfg.extraConfig} 63 | ''; 64 | 65 | exitHook = pkgs.writeText "dhcpcd.exit-hook" 66 | '' 67 | if [ "$reason" = BOUND -o "$reason" = REBOOT ]; then 68 | # Restart ntpd. We need to restart it to make sure that it 69 | # will actually do something: if ntpd cannot resolve the 70 | # server hostnames in its config file, then it will never do 71 | # anything ever again ("couldn't resolve ..., giving up on 72 | # it"), so we silently lose time synchronisation. This also 73 | # applies to openntpd. 74 | ${config.systemd.package}/bin/systemctl try-reload-or-restart ntpd.service openntpd.service || true 75 | fi 76 | 77 | ${cfg.runHook} 78 | ''; 79 | 80 | in 81 | 82 | { 83 | 84 | ###### interface 85 | 86 | options = { 87 | 88 | networking.dhcpcd.enable = mkOption { 89 | type = types.bool; 90 | default = true; 91 | description = '' 92 | Whether to enable dhcpcd for device configuration. This is mainly to 93 | explicitly disable dhcpcd (for example when using networkd). 94 | ''; 95 | }; 96 | 97 | networking.dhcpcd.persistent = mkOption { 98 | type = types.bool; 99 | default = false; 100 | description = '' 101 | Whenever to leave interfaces configured on dhcpcd daemon 102 | shutdown. Set to true if you have your root or store mounted 103 | over the network or this machine accepts SSH connections 104 | through DHCP interfaces and clients should be notified when 105 | it shuts down. 106 | ''; 107 | }; 108 | 109 | networking.dhcpcd.denyInterfaces = mkOption { 110 | type = types.listOf types.str; 111 | default = []; 112 | description = '' 113 | Disable the DHCP client for any interface whose name matches 114 | any of the shell glob patterns in this list. The purpose of 115 | this option is to blacklist virtual interfaces such as those 116 | created by Xen, libvirt, LXC, etc. 117 | ''; 118 | }; 119 | 120 | networking.dhcpcd.allowInterfaces = mkOption { 121 | type = types.nullOr (types.listOf types.str); 122 | default = null; 123 | description = '' 124 | Enable the DHCP client for any interface whose name matches 125 | any of the shell glob patterns in this list. Any interface not 126 | explicitly matched by this pattern will be denied. This pattern only 127 | applies when non-null. 128 | ''; 129 | }; 130 | 131 | networking.dhcpcd.extraConfig = mkOption { 132 | type = types.lines; 133 | default = ""; 134 | description = '' 135 | Literal string to append to the config file generated for dhcpcd. 136 | ''; 137 | }; 138 | 139 | networking.dhcpcd.runHook = mkOption { 140 | type = types.lines; 141 | default = ""; 142 | example = "if [[ $reason =~ BOUND ]]; then echo $interface: Routers are $new_routers - were $old_routers; fi"; 143 | description = '' 144 | Shell code that will be run after all other hooks. See 145 | `man dhcpcd-run-hooks` for details on what is possible. 146 | ''; 147 | }; 148 | 149 | }; 150 | 151 | 152 | ###### implementation 153 | 154 | config = mkIf enableDHCP { 155 | 156 | systemd.services.dhcpcd = let 157 | cfgN = config.networking; 158 | hasDefaultGatewaySet = (cfgN.defaultGateway != null && cfgN.defaultGateway.address != "") 159 | && (!cfgN.enableIPv6 || (cfgN.defaultGateway6 != null && cfgN.defaultGateway6.address != "")); 160 | in 161 | { description = "DHCP Client"; 162 | 163 | wantedBy = [ "multi-user.target" ] ++ optional (!hasDefaultGatewaySet) "network-online.target"; 164 | wants = [ "network.target" "systemd-udev-settle.service" ]; 165 | before = [ "network.target" ]; 166 | after = [ "systemd-udev-settle.service" ]; 167 | 168 | # Stopping dhcpcd during a reconfiguration is undesirable 169 | # because it brings down the network interfaces configured by 170 | # dhcpcd. So do a "systemctl restart" instead. 171 | stopIfChanged = false; 172 | 173 | path = [ dhcpcd pkgs.nettools pkgs.openresolv ]; 174 | 175 | unitConfig.ConditionCapability = "CAP_NET_ADMIN"; 176 | 177 | serviceConfig = let 178 | phys-aware = pkgs.writeScript "phys-aware" '' 179 | #! ${pkgs.bash}/bin/bash 180 | if ${pkgs.iproute}/bin/ip link | ${pkgs.gnugrep}/bin/grep -q wgvpn0; 181 | then exec ${pkgs.iproute}/bin/ip netns exec physical "$@" 182 | else exec "$@" 183 | fi 184 | ''; 185 | in { Type = "forking"; 186 | PIDFile = "/run/dhcpcd.pid"; 187 | ExecStart = "@${phys-aware} dhcpcd ${dhcpcd}/sbin/dhcpcd -w --quiet ${optionalString cfg.persistent "--persistent"} --config ${dhcpcdConf} ${concatStringsSep " " config.networking.wireless.interfaces}"; 188 | ExecReload = "${dhcpcd}/sbin/dhcpcd --rebind"; 189 | Restart = "always"; 190 | }; 191 | }; 192 | 193 | environment.systemPackages = [ dhcpcd ]; 194 | 195 | environment.etc = 196 | [ { source = exitHook; 197 | target = "dhcpcd.exit-hook"; 198 | } 199 | ]; 200 | 201 | powerManagement.resumeCommands = mkIf config.systemd.services.dhcpcd.enable 202 | '' 203 | # Tell dhcpcd to rebind its interfaces if it's running. 204 | ${config.systemd.package}/bin/systemctl reload dhcpcd.service 205 | ''; 206 | 207 | }; 208 | 209 | } 210 | -------------------------------------------------------------------------------- /copied/wpa_supplicant.nix: -------------------------------------------------------------------------------- 1 | { config, lib, pkgs, ... }: 2 | 3 | with lib; 4 | 5 | let 6 | cfg = config.networking.wireless; 7 | configFile = if cfg.networks != {} then pkgs.writeText "wpa_supplicant.conf" '' 8 | ${optionalString cfg.userControlled.enable '' 9 | ctrl_interface=DIR=/var/run/wpa_supplicant GROUP=${cfg.userControlled.group} 10 | update_config=1''} 11 | ${cfg.extraConfig} 12 | ${concatStringsSep "\n" (mapAttrsToList (ssid: config: with config; let 13 | key = if psk != null 14 | then ''"${psk}"'' 15 | else pskRaw; 16 | baseAuth = if key != null 17 | then ''psk=${key}'' 18 | else ''key_mgmt=NONE''; 19 | in '' 20 | network={ 21 | ssid="${ssid}" 22 | ${optionalString (priority != null) ''priority=${toString priority}''} 23 | ${optionalString hidden "scan_ssid=1"} 24 | ${if (auth != null) then auth else baseAuth} 25 | ${extraConfig} 26 | } 27 | '') cfg.networks)} 28 | '' else "/etc/wpa_supplicant.conf"; 29 | in { 30 | options = { 31 | networking.wireless = { 32 | enable = mkEnableOption "wpa_supplicant"; 33 | 34 | interfaces = mkOption { 35 | type = types.listOf types.str; 36 | default = []; 37 | example = [ "wlan0" "wlan1" ]; 38 | description = '' 39 | The interfaces wpa_supplicant will use. If empty, it will 40 | automatically use all wireless interfaces. 41 | ''; 42 | }; 43 | 44 | driver = mkOption { 45 | type = types.str; 46 | default = "nl80211,wext"; 47 | description = "Force a specific wpa_supplicant driver."; 48 | }; 49 | 50 | networks = mkOption { 51 | type = types.attrsOf (types.submodule { 52 | options = { 53 | psk = mkOption { 54 | type = types.nullOr types.str; 55 | default = null; 56 | description = '' 57 | The network's pre-shared key in plaintext defaulting 58 | to being a network without any authentication. 59 | 60 | Be aware that these will be written to the nix store 61 | in plaintext! 62 | 63 | Mutually exclusive with pskRaw. 64 | ''; 65 | }; 66 | 67 | pskRaw = mkOption { 68 | type = types.nullOr types.str; 69 | default = null; 70 | description = '' 71 | The network's pre-shared key in hex defaulting 72 | to being a network without any authentication. 73 | 74 | Mutually exclusive with psk. 75 | ''; 76 | }; 77 | 78 | auth = mkOption { 79 | type = types.nullOr types.str; 80 | default = null; 81 | example = '' 82 | key_mgmt=WPA-EAP 83 | eap=PEAP 84 | identity="user@example.com" 85 | password="secret" 86 | ''; 87 | description = '' 88 | Use this option to configure advanced authentication methods like EAP. 89 | See wpa_supplicant.conf(5) for example configurations. 90 | 91 | Mutually exclusive with psk and pskRaw. 92 | ''; 93 | }; 94 | 95 | hidden = mkOption { 96 | type = types.bool; 97 | default = false; 98 | description = '' 99 | Set this to true if the SSID of the network is hidden. 100 | ''; 101 | }; 102 | 103 | priority = mkOption { 104 | type = types.nullOr types.int; 105 | default = null; 106 | description = '' 107 | By default, all networks will get same priority group (0). If some of the 108 | networks are more desirable, this field can be used to change the order in 109 | which wpa_supplicant goes through the networks when selecting a BSS. The 110 | priority groups will be iterated in decreasing priority (i.e., the larger the 111 | priority value, the sooner the network is matched against the scan results). 112 | Within each priority group, networks will be selected based on security 113 | policy, signal strength, etc. 114 | ''; 115 | }; 116 | 117 | extraConfig = mkOption { 118 | type = types.str; 119 | default = ""; 120 | example = '' 121 | bssid_blacklist=02:11:22:33:44:55 02:22:aa:44:55:66 122 | ''; 123 | description = '' 124 | Extra configuration lines appended to the network block. 125 | See wpa_supplicant.conf(5) for available options. 126 | ''; 127 | }; 128 | 129 | }; 130 | }); 131 | description = '' 132 | The network definitions to automatically connect to when 133 | wpa_supplicant is running. If this 134 | parameter is left empty wpa_supplicant will use 135 | /etc/wpa_supplicant.conf as the configuration file. 136 | ''; 137 | default = {}; 138 | example = literalExample '' 139 | { echelon = { 140 | psk = "abcdefgh"; 141 | }; 142 | "free.wifi" = {}; 143 | } 144 | ''; 145 | }; 146 | 147 | userControlled = { 148 | enable = mkOption { 149 | type = types.bool; 150 | default = false; 151 | description = '' 152 | Allow normal users to control wpa_supplicant through wpa_gui or wpa_cli. 153 | This is useful for laptop users that switch networks a lot and don't want 154 | to depend on a large package such as NetworkManager just to pick nearby 155 | access points. 156 | 157 | When using a declarative network specification you cannot persist any 158 | settings via wpa_gui or wpa_cli. 159 | ''; 160 | }; 161 | 162 | group = mkOption { 163 | type = types.str; 164 | default = "wheel"; 165 | example = "network"; 166 | description = "Members of this group can control wpa_supplicant."; 167 | }; 168 | }; 169 | extraConfig = mkOption { 170 | type = types.str; 171 | default = ""; 172 | example = '' 173 | p2p_disabled=1 174 | ''; 175 | description = '' 176 | Extra lines appended to the configuration file. 177 | See wpa_supplicant.conf(5) for available options. 178 | ''; 179 | }; 180 | }; 181 | }; 182 | 183 | config = mkIf cfg.enable { 184 | assertions = flip mapAttrsToList cfg.networks (name: cfg: { 185 | assertion = with cfg; count (x: x != null) [ psk pskRaw auth ] <= 1; 186 | message = ''options networking.wireless."${name}".{psk,pskRaw,auth} are mutually exclusive''; 187 | }); 188 | 189 | environment.systemPackages = [ pkgs.wpa_supplicant ]; 190 | 191 | services.dbus.packages = [ pkgs.wpa_supplicant ]; 192 | 193 | # FIXME: start a separate wpa_supplicant instance per interface. 194 | systemd.services.wpa_supplicant = let 195 | ifaces = cfg.interfaces; 196 | deviceUnit = interface: [ "sys-subsystem-net-devices-${interface}.device" ]; 197 | phys-aware = pkgs.writeScript "phys-aware" '' 198 | #! ${pkgs.bash}/bin/bash 199 | if ${pkgs.iproute}/bin/ip link | ${pkgs.gnugrep}/bin/grep -q wgvpn0; 200 | then exec ${pkgs.iproute}/bin/ip netns exec physical "$@" 201 | else exec "$@" 202 | fi 203 | ''; 204 | scriptCore = pkgs.writeScript "wpa-supplicant-start" '' 205 | #! ${pkgs.bash}/bin/bash 206 | ${if ifaces == [] then '' 207 | for i in $(cd /sys/class/net && echo *); do 208 | DEVTYPE= 209 | source /sys/class/net/$i/uevent 210 | if [ "$DEVTYPE" = "wlan" -o -e /sys/class/net/$i/wireless ]; then 211 | ifaces="$ifaces''${ifaces:+ -N} -i$i" 212 | fi 213 | done 214 | '' else '' 215 | ifaces="${concatStringsSep " -N " (map (i: "-i${i}") ifaces)}" 216 | ''} 217 | exec wpa_supplicant -s -u -D${cfg.driver} -c ${configFile} $ifaces 218 | ''; 219 | in { 220 | description = "WPA Supplicant"; 221 | 222 | after = lib.concatMap deviceUnit ifaces; 223 | before = [ "network.target" ]; 224 | wants = [ "network.target" ]; 225 | requires = lib.concatMap deviceUnit ifaces; 226 | wantedBy = [ "multi-user.target" ]; 227 | stopIfChanged = false; 228 | 229 | path = [ pkgs.wpa_supplicant ]; 230 | 231 | script = '' 232 | exec ${phys-aware} ${scriptCore} 233 | ''; 234 | }; 235 | 236 | powerManagement.resumeCommands = '' 237 | ${config.systemd.package}/bin/systemctl try-restart wpa_supplicant 238 | ''; 239 | 240 | # Restart wpa_supplicant when a wlan device appears or disappears. 241 | services.udev.extraRules = '' 242 | ACTION=="add|remove", SUBSYSTEM=="net", ENV{DEVTYPE}=="wlan", RUN+="${config.systemd.package}/bin/systemctl try-restart wpa_supplicant.service" 243 | ''; 244 | }; 245 | 246 | meta.maintainers = with lib.maintainers; [ globin ]; 247 | } 248 | -------------------------------------------------------------------------------- /dev-tools.nix: -------------------------------------------------------------------------------- 1 | { config, pkgs, ... }: 2 | 3 | { environment.systemPackages = with pkgs; [ 4 | (python3.buildEnv.override { extraLibs = [ python3Packages.ipython ]; }) 5 | (haskellPackages.ghcWithPackages (p: with p; [ turtle ])) 6 | # android-studio 7 | aspell 8 | aria2 9 | awscli 10 | cmake 11 | # coq 12 | gcc 13 | gdb 14 | go 15 | gnumake 16 | ispell 17 | jq 18 | patchelf 19 | sqlite 20 | valgrind 21 | vscode 22 | z3 23 | ]; 24 | 25 | environment.etc = { 26 | gitconfig.text = '' 27 | [user] 28 | email = anderspapitto@gmail.com 29 | name = Anders Papitto 30 | [pull] 31 | rebase = true 32 | [color] 33 | ui = auto 34 | [push] 35 | default = simple 36 | [merge] 37 | conflictstyle = diff3 38 | [core] 39 | excludesfile = /etc/gitignore 40 | ''; 41 | gitignore.text = '' 42 | *.org 43 | *.org_archive 44 | ''; 45 | "stack/config.yaml".text = '' 46 | templates: 47 | params: 48 | author-email: anderspapitto@gmail.com 49 | author-name: Anders Papitto 50 | github-username: anderspapitto 51 | nix: 52 | enable: false 53 | ''; 54 | }; 55 | 56 | # imports = [ ./rust-overlay.nix ]; 57 | } 58 | -------------------------------------------------------------------------------- /entrypoints/gurney.nix: -------------------------------------------------------------------------------- 1 | { config, pkgs, ... }: 2 | 3 | { imports = [ 4 | ./audio.nix 5 | ./android.nix 6 | ./base.nix 7 | ./dev-tools.nix 8 | ./fonts.nix 9 | ./games.nix 10 | ./gui-tools.nix 11 | ./hardware-configuration.nix 12 | ./inl-tools.nix 13 | ./laptop-base.nix 14 | ./networking.nix 15 | ./nix.nix 16 | ./nixpkgs.nix 17 | ./syncthing.nix 18 | ./sysadmin.nix 19 | ./uefi.nix 20 | ./utility-scripts.nix 21 | ./virtualization.nix 22 | ./wireguard-client.nix 23 | ./x.nix 24 | 25 | ./private/default.nix 26 | ]; 27 | 28 | networking = { 29 | hostName = "gurney"; 30 | hostId = "d9ebdbe0"; 31 | }; 32 | 33 | boot.initrd.luks.devices = [ 34 | { 35 | name = "root"; 36 | device = "/dev/disk/by-uuid/27cadee9-bc6c-4e62-9494-fa2f789bf98b"; 37 | preLVM = true; 38 | allowDiscards = true; 39 | } 40 | ]; 41 | } 42 | -------------------------------------------------------------------------------- /entrypoints/thufir.nix: -------------------------------------------------------------------------------- 1 | { config, pkgs, ... }: 2 | 3 | let gurney-pubkey = "ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQCt6axfh25SwAPkrTQlIJKqZkQ2zxxI6/a45Oa2uGclh2qjpic4egy4zQbHXCJOM8Baz9xfzmJDxWAhwckiiXYvG6W5bignIfx8F/z8P27Jganv9Np5GptG2E0tZKoSFXkCN7B3H4+/r4O6eWsx9mM8NzABIP6i+vqZ/5gaW1PUGBWX4yZRVKr9WbTGJp4R6txvW6aPaJKGOGqFCDqU9SzWC8uZFWOxcIMI/2gn0eW27cCL/ro1i4DDVMQsDnDqxJ6cHIKzNsQcGSGN8q67zPMFdxlrZ+9xnATkQxyRXuuU5xArusY+acWGUBa3lixfYTD9XFcgddctG3x6xwSHN9zx anders@gurney"; 4 | in { 5 | imports = 6 | [ # Include the results of the hardware scan. 7 | ./hardware-configuration.nix 8 | ./base.nix 9 | ./sysadmin.nix 10 | ./nix.nix 11 | ]; 12 | 13 | boot = { 14 | loader.grub = { 15 | enable = true; 16 | version = 2; 17 | device = "/dev/vda"; 18 | }; 19 | }; 20 | 21 | environment.systemPackages = with pkgs; [ wireguard ]; 22 | 23 | networking = { 24 | nat = { 25 | enable = true; 26 | externalInterface = "ens3"; 27 | internalInterfaces = [ "wg0" ]; 28 | }; 29 | wireguard.interfaces = { 30 | wg0 = { 31 | ips = [ "10.100.0.1/24" ]; 32 | listenPort = 51820; 33 | privateKeyFile = "/root/wireguard-keys/private"; 34 | peers = [ 35 | { publicKey = "qFE4Q7ieGRqUyEr2MDAd6rRhZkrJD3M3/dqSwwo+VTc="; 36 | allowedIPs = [ "10.100.0.2/32" ]; 37 | } 38 | { publicKey = "ouX/+4ozC49/9xWJ5OuuhSB8zy4298XVrwUoIgLrQV8="; 39 | allowedIPs = [ "10.100.0.3/32" ]; 40 | } 41 | ]; 42 | }; 43 | }; 44 | hostName = "thufir"; 45 | enableIPv6 = false; 46 | nameservers = [ "1.1.1.1" "8.8.8.8" ]; 47 | firewall = { 48 | enable = true; 49 | extraCommands = '' 50 | iptables -t nat -A POSTROUTING -s 10.8.0.0/24 -o ens3 -j MASQUERADE 51 | ''; 52 | extraStopCommands = '' 53 | iptables -t nat -D POSTROUTING -s 10.8.0.0/24 -o ens3 -j MASQUERADE 54 | ''; 55 | allowedUDPPortRanges = [ 56 | { from = 1194; to = 1195; } # openvpn 57 | { from = 60000; to = 61000; } # mosh 58 | { from = 51820; to = 51820; } # wireguard 59 | ]; 60 | allowedTCPPorts = [ 4242 ]; # quassel 61 | trustedInterfaces = [ "tun0" "tun1" ]; 62 | }; 63 | }; 64 | 65 | services = { 66 | fail2ban = { 67 | enable = true; 68 | }; 69 | openssh = { 70 | enable = true; 71 | permitRootLogin = "yes"; 72 | }; 73 | gitolite = { 74 | enable = true; 75 | adminPubkey = gurney-pubkey; 76 | dataDir = "/var/lib/gitolite/gitolite"; 77 | }; 78 | openvpn = { 79 | servers = { 80 | laptop = { 81 | config = '' 82 | ifconfig 10.8.0.1 10.8.0.2 83 | dev tun0 84 | port 1194 85 | secret /root/static.key 86 | ''; 87 | }; 88 | phone = { 89 | config = '' 90 | ifconfig 10.8.0.1 10.8.0.3 91 | dev tun1 92 | port 1195 93 | secret /root/static.key 94 | ''; 95 | }; 96 | }; 97 | }; 98 | quassel = { 99 | enable = true; 100 | interfaces = [ "0.0.0.0" ]; 101 | }; 102 | syncthing = { 103 | enable = true; 104 | openDefaultPorts = true; 105 | }; 106 | }; 107 | } 108 | -------------------------------------------------------------------------------- /fonts.nix: -------------------------------------------------------------------------------- 1 | { config, pkgs, ... }: 2 | 3 | { i18n = { 4 | consoleFont = "lat9w-16"; 5 | # consoleKeyMap = "colemak/en-latin9"; 6 | defaultLocale = "en_US.UTF-8"; 7 | }; 8 | 9 | fonts = { 10 | enableFontDir = true; 11 | enableGhostscriptFonts = true; 12 | fonts = with pkgs; [ 13 | corefonts 14 | inconsolata 15 | unifont 16 | ubuntu_font_family 17 | noto-fonts 18 | symbola 19 | ]; 20 | }; 21 | } 22 | -------------------------------------------------------------------------------- /games.nix: -------------------------------------------------------------------------------- 1 | { config, pkgs, ... }: 2 | 3 | { environment.systemPackages = with pkgs; [ 4 | crawlTiles 5 | ]; 6 | } 7 | -------------------------------------------------------------------------------- /gui-tools.nix: -------------------------------------------------------------------------------- 1 | { config, pkgs, ... }: 2 | 3 | { environment.systemPackages = with pkgs; [ 4 | alacritty 5 | anki 6 | arandr 7 | # chromium 8 | clerk 9 | clipit 10 | dmenu 11 | evince 12 | firefox 13 | ghostscriptX 14 | glxinfo 15 | haskellPackages.hledger 16 | haskellPackages.hledger-web 17 | i3lock 18 | i3status 19 | imagemagick 20 | jmtpfs 21 | quasselClient 22 | libnotify 23 | ncmpcpp 24 | okular 25 | pass 26 | pavucontrol 27 | pianobar 28 | rofi 29 | # rxvt_unicode_with-plugins 30 | signal-desktop 31 | spotify 32 | st 33 | tdesktop 34 | tuxguitar 35 | vlc 36 | xdotool 37 | xlibs.xev 38 | # xsane 39 | xsel 40 | youtube-dl 41 | ]; 42 | } 43 | -------------------------------------------------------------------------------- /inl-tools.nix: -------------------------------------------------------------------------------- 1 | { config, pkgs, ... }: 2 | 3 | with pkgs; 4 | 5 | let bluetoothScript = scriptName: regexPattern: 6 | (writeScriptBin scriptName '' 7 | #! ${bash}/bin/bash 8 | set -x 9 | 10 | export XDG_RUNTIME_DIR=/run/user/$UID 11 | 12 | TRIES=0 13 | until (bluetoothctl <<< show | grep -q 'Powered: yes') 14 | do 15 | bluetoothctl <<< 'power on' 16 | [[ $((TRIES++)) -eq 20 ]] && exit 1 17 | sleep 0.1 18 | done 19 | 20 | TRIES=0 21 | until [ -n "$DEVICE" ] 22 | do 23 | DEVICE=$(bluetoothctl <<< devices | egrep '^Device.*${regexPattern}' | awk '{ print $2 }') 24 | [[ $((TRIES++)) -eq 20 ]] && exit 1 25 | sleep 0.1 26 | done 27 | 28 | TRIES=0 29 | until bluetoothctl <<< "connect $DEVICE" 30 | do 31 | [[ $((TRIES++)) -eq 20 ]] && exit 1 32 | sleep 0.1 33 | done 34 | 35 | TRIES=0 36 | until [ -n "$TARGET_CARD" ] 37 | do 38 | TARGET_CARD=$(pacmd list-cards | grep 'name:' | egrep -o 'bluez.*[^>]') 39 | [[ $((TRIES++)) -eq 20 ]] && exit 1 40 | sleep 0.1 41 | done 42 | 43 | TRIES=0 44 | until pacmd list-cards | egrep -q 'active profile: ' 45 | do 46 | pacmd set-card-profile $TARGET_CARD a2dp_sink 47 | [[ $((TRIES++)) -eq 20 ]] && exit 1 48 | sleep 0.1 49 | done 50 | 51 | TRIES=0 52 | until [ -n "$TARGET_SINK" ] 53 | do 54 | TARGET_SINK=$(pacmd list-sinks | grep 'name:' | egrep -o 'bluez.*[^>]') 55 | [[ $((TRIES++)) -eq 20 ]] && exit 1 56 | sleep 0.1 57 | done 58 | 59 | pactl set-sink-volume $TARGET_SINK 50% 60 | pacmd set-default-sink $TARGET_SINK 61 | 62 | for index in $(pacmd list-sink-inputs $TARGET_SINK | grep index | awk '{ print $2 }') 63 | do 64 | pacmd move-sink-input $index $TARGET_SINK 65 | done 66 | ''); 67 | in 68 | { environment.systemPackages = [ 69 | (writeScriptBin "anders-handle-keybind" '' 70 | #! ${bash}/bin/bash 71 | 72 | case $1 in 73 | F1) 74 | pactl set-sink-mute @DEFAULT_SINK@ toggle 75 | killall -SIGUSR1 i3status 76 | ;; 77 | F2) 78 | pactl set-sink-volume @DEFAULT_SINK@ -5% 79 | killall -SIGUSR1 i3status 80 | ;; 81 | F3) 82 | pactl set-sink-volume @DEFAULT_SINK@ +5% 83 | killall -SIGUSR1 i3status 84 | ;; 85 | F7) 86 | exec systemctl suspend 87 | ;; 88 | F9) 89 | exec browser 90 | ;; 91 | F10) 92 | exec anders-capture 93 | ;; 94 | F11) 95 | exec i3-rename 96 | ;; 97 | F12) 98 | exec i3-switch 99 | ;; 100 | esac 101 | '') 102 | (writeScriptBin "i3-switch" '' 103 | #! ${bash}/bin/bash 104 | 105 | set -e 106 | 107 | list_workspaces() { 108 | ${i3}/bin/i3-msg -t get_workspaces | ${jq}/bin/jq -r '.[] | .name' 109 | } 110 | 111 | WORKSPACE=$( list_workspaces | rofi -dmenu -p "switch to workspace " ) 112 | 113 | i3-msg workspace "$WORKSPACE" 114 | '') 115 | (writeScriptBin "i3-rename" '' 116 | #! ${bash}/bin/bash 117 | 118 | set -e 119 | 120 | NAME=$( rofi -dmenu -p "rename workspace to " ) 121 | 122 | i3-msg "rename workspace to $NAME" 123 | '') 124 | (writeScriptBin "browser" '' 125 | #! ${bash}/bin/bash 126 | firefox "$@" 127 | exec i3-msg focus tiling 128 | '') 129 | (writeScriptBin "toggle-invert" '' 130 | #! ${bash}/bin/bash 131 | FOO=$( ${xdotool}/bin/xdotool getactivewindow getwindowname ) 132 | if [[ $FOO == *" NOINVERT" ]]; 133 | then 134 | FOO=''${FOO% NOINVERT}; 135 | else 136 | FOO="$FOO NOINVERT"; 137 | fi 138 | ${xdotool}/bin/xdotool getactivewindow set_window --name "$FOO" 139 | '') 140 | (writeScriptBin "global-toggle-invert" '' 141 | #! ${bash}/bin/bash 142 | . ${config.system.build.setEnvironment} 143 | 144 | if systemctl is-active compton-night > /dev/null 145 | then 146 | sudo systemctl start compton 147 | else 148 | sudo systemctl start compton-night 149 | fi 150 | '') 151 | (writeScriptBin "external-drive-mount" '' 152 | #! ${bash}/bin/bash 153 | set -x 154 | if [[ $EUID -ne 0 ]]; then 155 | echo "This script must be run as root" 1>&2 156 | exit 1 157 | fi 158 | ${cryptsetup}/bin/cryptsetup --type luks open /dev/sdb external 159 | mount -t ext4 /dev/mapper/external /mnt 160 | '') 161 | (writeScriptBin "external-drive-umount" '' 162 | #! ${bash}/bin/bash 163 | set -x 164 | if [[ $EUID -ne 0 ]]; then 165 | echo "This script must be run as root" 1>&2 166 | exit 1 167 | fi 168 | umount /mnt 169 | ${cryptsetup}/bin/cryptsetup close external 170 | '') 171 | (writeScriptBin "backup-homedir" '' 172 | #! ${bash}/bin/bash 173 | if [[ $EUID -eq 0 ]]; then 174 | echo "This script must not be run as root" 1>&2 175 | exit 1 176 | fi 177 | rsync -aAXHv $HOME/* /mnt 178 | '') 179 | # TODO remove my-pager in favor of anders-pager once i've rebooted 180 | (writeScriptBin "my-pager" '' 181 | #! ${bash}/bin/bash 182 | if [[ $TERM = dumb ]]; then 183 | exec cat "$@" 184 | else 185 | exec less -R "$@" 186 | fi 187 | '') 188 | (writeScriptBin "anders-pager" '' 189 | #! ${bash}/bin/bash 190 | if [[ $TERM = dumb ]]; then 191 | exec cat "$@" 192 | else 193 | exec less -R "$@" 194 | fi 195 | '') 196 | (writeScriptBin "editor" '' 197 | #! ${bash}/bin/bash 198 | exec nvim "$@" 199 | '') 200 | (writeScriptBin "disable-bluetooth" '' 201 | #! ${bash}/bin/bash 202 | set -x 203 | 204 | export XDG_RUNTIME_DIR=/run/user/$UID 205 | 206 | bluetoothctl <<< 'power off' 207 | '') 208 | (writeScriptBin "bluetooth-off" '' 209 | #! ${bash}/bin/bash 210 | set -x 211 | bluetoothctl <<< 'power off' 212 | '') 213 | (bluetoothScript "bluetooth-tranya" "T1-L") 214 | (bluetoothScript "bluetooth-oontz" "OontZ") 215 | (writeScriptBin "dark-mode" '' 216 | #! ${bash}/bin/bash 217 | set -x 218 | ${redshift}/bin/redshift -O 2000 219 | /run/wrappers/bin/sudo ${coreutils}/bin/tee /sys/class/backlight/intel_backlight/brightness <<< 250 220 | '') 221 | (writeScriptBin "twilight-mode" '' 222 | #! ${bash}/bin/bash 223 | set -x 224 | ${redshift}/bin/redshift -O 2500 225 | /run/wrappers/bin/sudo ${coreutils}/bin/tee /sys/class/backlight/intel_backlight/brightness <<< 500 226 | '') 227 | (writeScriptBin "bright-mode" '' 228 | #! ${bash}/bin/bash 229 | set -x 230 | ${redshift}/bin/redshift -x 231 | /run/wrappers/bin/sudo ${coreutils}/bin/tee /sys/class/backlight/intel_backlight/brightness <<< 852 232 | '') 233 | 234 | # (writeScriptBin "switch-to-headphones" '' 235 | # #! ${bash}/bin/bash 236 | # set -x 237 | # pacmd set-sink-port alsa_output.pci-0000_00_1b.0.analog-stereo analog-output-headphones 238 | # '') 239 | # (writeScriptBin "switch-to-speakers" '' 240 | # #! ${bash}/bin/bash 241 | # set -x 242 | # pacmd set-sink-port alsa_output.pci-0000_00_1b.0.analog-stereo analog-output-speaker 243 | # '') 244 | # (writeScriptBin "toggle-suspend-audio" '' 245 | # #! ${bash}/bin/bash 246 | # pacmd list-sinks | grep state: | grep -v -q SUSPENDED 247 | # if [[ $? -eq 0 ]] 248 | # then 249 | # pacmd suspend 1 250 | # else 251 | # pacmd suspend 0 252 | # fi 253 | # '') 254 | ]; 255 | 256 | environment.variables = { PAGER = "anders-pager"; }; 257 | } 258 | -------------------------------------------------------------------------------- /laptop-base.nix: -------------------------------------------------------------------------------- 1 | { config, pkgs, ... }: 2 | 3 | { hardware = { 4 | opengl.driSupport32Bit = true; # needed for steam and/or wine, i believe 5 | }; 6 | 7 | services = { 8 | acpid.enable = true; 9 | 10 | logind.extraConfig = '' 11 | HoldoffTimeoutSec=0 12 | ''; 13 | }; 14 | 15 | systemd.services.battery_check = { 16 | description = "Send notification if battery is low"; 17 | serviceConfig = { 18 | Type = "oneshot"; 19 | User = "anders"; 20 | ExecStart = pkgs.writeScript "battery_check" '' 21 | #!${pkgs.bash}/bin/bash --login 22 | . <(udevadm info -q property -p /sys/class/power_supply/BAT0 | 23 | grep -E 'POWER_SUPPLY_(CAPACITY|STATUS)=') 24 | if [[ $POWER_SUPPLY_STATUS = Discharging && $POWER_SUPPLY_CAPACITY -lt 15 ]]; 25 | then notify-send -u critical "Battery is low: $POWER_SUPPLY_CAPACITY"; 26 | fi 27 | ''; 28 | }; 29 | environment = { DISPLAY = ":0"; }; 30 | after = [ "display-manager.service" ]; 31 | startAt = "*:00/5"; 32 | }; 33 | 34 | users.extraUsers.anders = { 35 | isNormalUser = true; 36 | uid = 1000; 37 | extraGroups = [ "wheel" "audio" "docker" "redis" "adbusers" ]; 38 | }; 39 | } 40 | -------------------------------------------------------------------------------- /networking.nix: -------------------------------------------------------------------------------- 1 | { config, pkgs, ... }: 2 | 3 | { hardware.bluetooth.enable = true; 4 | 5 | networking = { 6 | extraHosts = '' 7 | 104.156.231.205 thufir 8 | ''; 9 | 10 | dhcpcd.extraConfig = '' 11 | nohook resolv.conf 12 | noipv4ll 13 | ''; 14 | enableIPv6 = false; 15 | 16 | nameservers = [ "1.1.1.1" "8.8.8.8" ]; 17 | wireless.enable = true; # I directly use wpa_supplicant and dhcpcd 18 | }; 19 | 20 | services.dnsmasq.enable = true; 21 | } 22 | -------------------------------------------------------------------------------- /nix.nix: -------------------------------------------------------------------------------- 1 | { config, pkgs, ... }: 2 | 3 | { nix = { 4 | buildCores = 0; 5 | daemonIONiceLevel = 4; 6 | daemonNiceLevel = 10; 7 | maxJobs = 8; 8 | extraOptions = '' 9 | auto-optimise-store = true 10 | gc-keep-outputs = true 11 | ''; 12 | nixPath = [ 13 | "/etc/nixos" 14 | "nixos-config=/etc/nixos/configuration" 15 | ]; 16 | useSandbox = true; 17 | binaryCaches = [ 18 | "https://cache.nixos.org" 19 | "https://nixcache.reflex-frp.org" 20 | "https://hie-nix.cachix.org" 21 | ]; 22 | binaryCachePublicKeys = [ 23 | "ryantrinkle.com-1:JJiAKaRv9mWgpVAz8dwewnZe0AzzEAzPkagE9SP5NWI=" 24 | "hie-nix.cachix.org-1:EjBSHzF6VmDnzqlldGXbi0RM3HdjfTU3yDRi9Pd0jTY=" 25 | ]; 26 | }; 27 | } 28 | -------------------------------------------------------------------------------- /nixpkgs.nix: -------------------------------------------------------------------------------- 1 | { config, pkgs, ... }: 2 | 3 | { nixpkgs.config = { 4 | allowUnfree = true; 5 | 6 | # chromium = { 7 | # enablePepperFlash = true; 8 | # }; 9 | }; 10 | } 11 | -------------------------------------------------------------------------------- /rust-overlay.nix: -------------------------------------------------------------------------------- 1 | { config, pkgs, ... }: 2 | 3 | { 4 | nixpkgs.overlays = [ 5 | (import /etc/nixos/overlays/nixpkgs-mozilla/rust-overlay.nix) 6 | ]; 7 | environment.systemPackages = with pkgs; [ 8 | rustChannels.beta.rust 9 | (llvm.override { enableSharedLibraries = true; }) 10 | ]; 11 | } 12 | -------------------------------------------------------------------------------- /syncthing.nix: -------------------------------------------------------------------------------- 1 | { config, pkgs, ... }: 2 | 3 | { services.syncthing = { 4 | enable = true; 5 | user = "anders"; 6 | dataDir = "/home/anders/.syncthing"; 7 | openDefaultPorts = true; 8 | }; 9 | } 10 | -------------------------------------------------------------------------------- /sysadmin.nix: -------------------------------------------------------------------------------- 1 | { config, pkgs, ... }: 2 | 3 | { 4 | boot = { 5 | # extraModulePackages = with config.boot.kernelPackages; [ sysdig ]; 6 | }; 7 | 8 | environment.systemPackages = with pkgs; [ 9 | bind # provides `dig` 10 | binutils 11 | cryptsetup 12 | dmidecode 13 | dstat 14 | file 15 | git 16 | gptfdisk 17 | gnupg # emacs wants the gpg2 binary? 18 | htop 19 | iftop 20 | iotop 21 | linuxPackages.perf 22 | lshw 23 | lsof 24 | mosh 25 | mtr 26 | neovim 27 | neovim-remote 28 | neovim-qt 29 | nftables 30 | numactl 31 | openssl 32 | pciutils 33 | psmisc 34 | ripgrep 35 | # sysdig 36 | tcpdump 37 | tmux 38 | tree 39 | unzip 40 | wget 41 | which 42 | wireshark 43 | ]; 44 | } 45 | -------------------------------------------------------------------------------- /uefi.nix: -------------------------------------------------------------------------------- 1 | { config, pkgs, ... }: 2 | 3 | { boot.loader = { 4 | systemd-boot.enable = true; 5 | efi.canTouchEfiVariables = true; 6 | }; 7 | } 8 | -------------------------------------------------------------------------------- /utility-scripts.nix: -------------------------------------------------------------------------------- 1 | { config, pkgs, ... }: 2 | 3 | let utility-scripts-src = pkgs.fetchFromGitHub { 4 | owner = "anderspapitto"; 5 | repo = "utility-scripts"; 6 | rev = "381f24ed1554561c929f96856b0c1e6c7cf4116c"; 7 | sha256 = "042s7bwm1jff195ilz2wmhrarlz2ia63m9biinhb2wlg7rjb82ay"; 8 | }; 9 | in { 10 | environment.systemPackages = [ 11 | (pkgs.callPackage "${utility-scripts-src}/nix-shell-wrapper" { }) 12 | (pkgs.callPackage "${utility-scripts-src}/i3-focus" { }) 13 | ]; 14 | } 15 | -------------------------------------------------------------------------------- /virtualization.nix: -------------------------------------------------------------------------------- 1 | { config, pkgs, ... }: 2 | 3 | { environment.systemPackages = with pkgs; [ 4 | # docker 5 | ]; 6 | 7 | networking.nat = { 8 | enable = true; 9 | internalInterfaces = ["ve-+"]; 10 | externalInterface = "wlp4s0"; 11 | }; 12 | 13 | virtualisation = { 14 | # docker.enable = true; 15 | }; 16 | } 17 | -------------------------------------------------------------------------------- /wireguard-client.nix: -------------------------------------------------------------------------------- 1 | { config, pkgs, ... }: 2 | 3 | let 4 | physexec = pkgs.writeScriptBin "physexec" '' 5 | #! ${pkgs.bash}/bin/bash 6 | exec sudo -E ${pkgs.iproute}/bin/ip netns exec physical \ 7 | sudo -E -u \#$(${pkgs.coreutils}/bin/id -u) \ 8 | -g \#$(${pkgs.coreutils}/bin/id -g) \ 9 | "$@" 10 | ''; 11 | anders-i3status = pkgs.writeScriptBin "anders-i3status" '' 12 | #! ${pkgs.python3}/bin/python -u 13 | 14 | import os 15 | import signal 16 | import subprocess 17 | 18 | # https://stackoverflow.com/questions/320232/ensuring-subprocesses-are-dead-on-exiting-python-program 19 | os.setpgrp() # create new process group, become its leader 20 | try: 21 | p1 = subprocess.Popen(['physexec', 'i3status', '-c', '/etc/i3/status-netns'], 22 | stdout=subprocess.PIPE) 23 | p2 = subprocess.Popen([ 'i3status', '-c', '/etc/i3/status'], 24 | stdout=subprocess.PIPE) 25 | 26 | for i in range(2): 27 | line1 = p1.stdout.readline().decode('utf-8').strip() 28 | line2 = p2.stdout.readline().decode('utf-8').strip() 29 | print(line1) 30 | while True: 31 | line1 = p1.stdout.readline().decode('utf-8').strip() 32 | line2 = p2.stdout.readline().decode('utf-8').strip() 33 | print(line1.split(']')[0] + ', ' + line2.split('[')[1]) 34 | finally: 35 | os.killpg(0, signal.SIGKILL) # kill all processes in my group 36 | ''; 37 | in { 38 | # There's not really a better way to do this. Override these two services to 39 | # be wg-aware 40 | imports = [ 41 | ./copied/dhcpcd.nix 42 | ./copied/wpa_supplicant.nix 43 | ]; 44 | disabledModules = [ 45 | "services/networking/dhcpcd.nix" 46 | "services/networking/wpa_supplicant.nix" 47 | ]; 48 | 49 | environment.systemPackages = [ pkgs.wireguard physexec anders-i3status ]; 50 | 51 | networking.wireless.interfaces = [ "wlp4s0" ]; 52 | 53 | systemd.services = { 54 | physical-netns = { 55 | description = "physical namespace, for use with wireguard"; 56 | wantedBy = [ "default.target" ]; 57 | before = [ "display-manager.service" "network.target" ]; 58 | serviceConfig = { 59 | Type = "oneshot"; 60 | RemainAfterExit = true; 61 | ExecStart = "${pkgs.iproute}/bin/ip netns add physical"; 62 | ExecStop = "${pkgs.iproute}/bin/ip netns del physical"; 63 | }; 64 | }; 65 | wg0 = { 66 | description = "Wireguard interface, and vpn"; 67 | requires = [ "physical-netns.service" ]; 68 | after = [ "physical-netns.service" ]; 69 | serviceConfig = { 70 | Type = "oneshot"; 71 | RemainAfterExit = true; 72 | ExecStart = pkgs.writeScript "wgup" '' 73 | #! ${pkgs.bash}/bin/bash 74 | 75 | ${pkgs.iproute}/bin/ip -n physical link add wgvpn0 type wireguard 76 | ${pkgs.iproute}/bin/ip -n physical link set wgvpn0 netns 1 77 | 78 | ${pkgs.wireguard}/bin/wg set wgvpn0 \ 79 | private-key /root/wireguard-keys/private \ 80 | peer ghK62ZFGd9zkRPfF6JehK7OMAW6HMdy68RNalq9FVUo= \ 81 | allowed-ips 0.0.0.0/0 \ 82 | endpoint thufir:51820 83 | ${pkgs.iproute}/bin/ip link set wgvpn0 up 84 | 85 | ${pkgs.iproute}/bin/ip addr add 10.100.0.2/24 dev wgvpn0 86 | ${pkgs.iproute}/bin/ip route add default dev wgvpn0 87 | 88 | ${pkgs.iproute}/bin/ip link set enp0s25 netns physical 89 | ${pkgs.iw}/bin/iw phy phy0 set netns name physical 90 | 91 | ${pkgs.systemd}/bin/systemctl restart --no-block wpa_supplicant dhcpcd 92 | ''; 93 | ExecStop = pkgs.writeScript "wgdown" '' 94 | #! ${pkgs.bash}/bin/bash 95 | 96 | ${pkgs.iproute}/bin/ip -n physical link set enp0s25 netns 1 97 | ${pkgs.iproute}/bin/ip netns exec physical ${pkgs.iw}/bin/iw phy phy0 set netns 1 98 | 99 | ${pkgs.iproute}/bin/ip link del wgvpn0 100 | 101 | ${pkgs.systemd}/bin/systemctl restart --no-block wpa_supplicant dhcpcd 102 | ''; 103 | }; 104 | }; 105 | 106 | }; 107 | } 108 | -------------------------------------------------------------------------------- /x.nix: -------------------------------------------------------------------------------- 1 | { config, pkgs, ... }: 2 | 3 | let dunstrc = builtins.toFile "dunstrc" (pkgs.lib.readFile ./config/dunstrc); 4 | background-image = pkgs.fetchurl { 5 | url = "http://orig01.deviantart.net/1810/f/2012/116/a/4/tranquility_by_andreewallin-d4xjtd0.jpg"; 6 | sha256 = "17jcvy268aqcix7hb8acn9m9x7dh8ymb07w4f7s9apcklimz63bq"; 7 | }; 8 | solarized-theme = pkgs.fetchFromGitHub { 9 | owner = "anderspapitto"; 10 | repo = "nixos-solarized-slim-theme"; 11 | rev = "2822b7cb7074cf9aa36afa9b5cabd54105b3306c"; 12 | sha256 = "0jp7qq02ly9wiqbgh5yamwd31ah1bbybida7mn1g6qpdijajf247"; 13 | }; 14 | simpleXService = name: description: execStart: { 15 | inherit description; 16 | environment = { 17 | DISPLAY = ":0"; 18 | }; 19 | serviceConfig = { 20 | Type = "simple"; 21 | User = "anders"; 22 | ExecStart = pkgs.writeScript name '' 23 | #! ${pkgs.bash}/bin/bash 24 | . ${config.system.build.setEnvironment} 25 | set -xe 26 | ${execStart} 27 | ''; 28 | RestartSec = 3; 29 | Restart = "always"; 30 | }; 31 | wantedBy = [ "display-manager.service" ]; 32 | after = [ "display-manager.service" ]; 33 | }; 34 | in { 35 | environment = { 36 | etc = { 37 | "compton/inverted" .source = ./config/compton-inverted; 38 | "compton/noninverted" .source = ./config/compton-noninverted; 39 | "dunst/dunstrc" .source = ./config/dunstrc; 40 | "i3/config" .source = ./config/i3; 41 | "i3/status" .source = ./config/i3status; 42 | "i3/status-netns" .source = ./config/i3status-netns; 43 | "X11/xresources" .source = ./config/xresources; 44 | }; 45 | systemPackages = with pkgs; [ dzen2 gnupg ]; 46 | }; 47 | 48 | services = { 49 | xserver = { 50 | enable = true; 51 | desktopManager.xterm.enable = false; 52 | displayManager.slim.theme = solarized-theme; 53 | windowManager = { 54 | i3 = { 55 | enable = true; 56 | package = pkgs.i3-gaps; 57 | extraSessionCommands = '' 58 | ${pkgs.gnupg}/bin/gpg-connect-agent /bye 59 | export GPG_TTY=$(tty) 60 | 61 | sudo systemctl start openvpn-thufir & 62 | ''; 63 | configFile = "/etc/i3/config"; 64 | }; 65 | default = "i3"; 66 | }; 67 | synaptics = { 68 | enable = true; 69 | tapButtons = false; 70 | twoFingerScroll = true; 71 | }; 72 | layout = "us"; 73 | # note typo in base.lst, where it says 'ctrl:ctrl_ralt' when it 74 | # means 'ctrl:ralt_rctrl' 75 | xkbOptions = "ctrl:ralt_rctrl, lv3:caps_switch"; 76 | xkbVariant = "altgr-intl"; 77 | }; 78 | }; 79 | 80 | systemd.services = { 81 | compton = simpleXService "compton" 82 | "lightweight compositing manager" 83 | "${pkgs.compton}/bin/compton -cCG --config /etc/compton/noninverted" 84 | ; 85 | compton-night = 86 | let base-service = simpleXService "compton-night" 87 | "lightweight compositing manager (night mode)" 88 | "${pkgs.compton}/bin/compton -cCG --config /etc/compton/inverted" 89 | ; 90 | in base-service // { 91 | conflicts = [ "compton.service" ]; 92 | wantedBy = [ ]; 93 | }; 94 | dunst = simpleXService "dunst" 95 | "Lightweight libnotify server" 96 | "exec ${pkgs.dunst}/bin/dunst -config /etc/dunst/dunstrc" 97 | ; 98 | feh = simpleXService "feh" 99 | "Set background" 100 | '' 101 | ${pkgs.feh}/bin/feh --bg-fill --no-fehbg ${background-image} 102 | exec sleep infinity 103 | '' 104 | ; 105 | xbanish = simpleXService "xbanish" 106 | "xbanish hides the mouse pointer" 107 | "exec ${pkgs.xbanish}/bin/xbanish" 108 | ; 109 | clipit = simpleXService "clipit" 110 | "clipboard manager" 111 | "exec ${pkgs.clipit}/bin/clipit" 112 | ; 113 | xrdb = simpleXService "xrdb" 114 | "set X resources" 115 | '' 116 | ${pkgs.xorg.xrdb}/bin/xrdb /etc/X11/xresources 117 | exec sleep infinity 118 | ''; 119 | }; 120 | } 121 | --------------------------------------------------------------------------------