summaryrefslogtreecommitdiff
path: root/accounts
diff options
context:
space:
mode:
Diffstat (limited to 'accounts')
-rw-r--r--accounts/gkleen@eostre.nix8
-rw-r--r--accounts/gkleen@installer.nix8
-rw-r--r--accounts/gkleen@sif/default.nix398
-rw-r--r--accounts/gkleen@sif/emacs.el5
-rw-r--r--accounts/gkleen@sif/firefox-chrome.css30
-rw-r--r--accounts/gkleen@sif/niri/default.nix1313
-rw-r--r--accounts/gkleen@sif/niri/mako.nix59
-rw-r--r--accounts/gkleen@sif/niri/swayosd.nix66
-rw-r--r--accounts/gkleen@sif/niri/waybar.nix74
-rw-r--r--accounts/gkleen@sif/ssh-hosts.nix85
-rw-r--r--accounts/gkleen@sif/synadm/default.nix9
-rw-r--r--accounts/gkleen@sif/synadm/synadm_yaml15
-rw-r--r--accounts/gkleen@sif/systemd.nix123
-rw-r--r--accounts/gkleen@sif/utils/async-yt-dlp.nix57
-rw-r--r--accounts/gkleen@sif/utils/pdf2pdf.nix8
-rw-r--r--accounts/gkleen@sif/utils/sieve-edit.nix24
-rw-r--r--accounts/gkleen@sif/zshrc153
-rw-r--r--accounts/gkleen@surtr.nix8
-rw-r--r--accounts/gkleen@vidhar.nix4
-rw-r--r--accounts/mherold@eostre.nix6
-rw-r--r--accounts/root@installer.nix8
-rw-r--r--accounts/root@sif.nix8
-rw-r--r--accounts/root@surtr.nix8
-rw-r--r--accounts/root@vidhar.nix9
24 files changed, 1658 insertions, 828 deletions
diff --git a/accounts/gkleen@eostre.nix b/accounts/gkleen@eostre.nix
index 72818d44..28daf3fd 100644
--- a/accounts/gkleen@eostre.nix
+++ b/accounts/gkleen@eostre.nix
@@ -1,16 +1,16 @@
1{ flake, userName, pkgs, ... }: 1{ flake, userName, pkgs, ... }:
2{ 2{
3 imports = with flake.nixosModules.userProfiles.${userName}; [ 3 imports = with flake.nixosModules.userProfiles.${userName}; [
4 zsh utils tmux 4 utils
5 ]; 5 ];
6 6
7 config = { 7 config = {
8 home-manager.users.${userName} = { 8 home-manager.users.${userName} = {
9 home.stateVersion = "20.09"; 9 home.stateVersion = "20.09";
10 10
11 nixpkgs.config = { 11 # nixpkgs.config = {
12 allowUnfree = true; 12 # allowUnfree = true;
13 }; 13 # };
14 14
15 home.packages = with pkgs; [ 15 home.packages = with pkgs; [
16 thunderbird libreoffice element-desktop keepassxc vlc 16 thunderbird libreoffice element-desktop keepassxc vlc
diff --git a/accounts/gkleen@installer.nix b/accounts/gkleen@installer.nix
index c7a418f8..5fe1db38 100644
--- a/accounts/gkleen@installer.nix
+++ b/accounts/gkleen@installer.nix
@@ -1,7 +1,11 @@
1{ userName, ... }: 1{ flake, userName, ... }:
2 2
3{ 3{
4 home-manager.users.${userName} = { config, ... } : { 4 imports = with flake.nixosModules.userProfiles.${userName}; [
5 zsh tmux
6 ];
7
8 config.home-manager.users.${userName} = { config, ... } : {
5 home.stateVersion = config.home.version.release; 9 home.stateVersion = config.home.version.release;
6 }; 10 };
7} 11}
diff --git a/accounts/gkleen@sif/default.nix b/accounts/gkleen@sif/default.nix
index 0c0872cc..64434bb8 100644
--- a/accounts/gkleen@sif/default.nix
+++ b/accounts/gkleen@sif/default.nix
@@ -4,33 +4,6 @@ with lib;
4 4
5let 5let
6 cfg = config.home-manager.users.${userName}; 6 cfg = config.home-manager.users.${userName};
7 emacsScratch = pkgs.stdenv.mkDerivation (sources.emacs-scratch_el // rec {
8 phases = [ "installPhase" ];
9
10 installPhase = ''
11 mkdir -p $out/share/emacs/site-lisp
12 cp $src/scratch.el $out/share/emacs/site-lisp/default.el
13 '';
14 });
15 muteScript = pkgs.stdenv.mkDerivation {
16 name = "mute";
17 src = ./scripts/mute.zsh;
18
19 buildInputs = with pkgs; [ makeWrapper ];
20
21 phases = [ "installPhase" ];
22
23 installPhase = ''
24 mkdir -p $out/bin
25 install -m 0755 $src $out/bin/mute
26 wrapProgram $out/bin/mute \
27 --prefix PATH : ${pkgs.zsh}/bin \
28 --prefix PATH : ${pkgs.findutils}/bin \
29 --prefix PATH : ${pkgs.util-linux}/bin \
30 --prefix PATH : ${pkgs.coreutils}/bin \
31 --prefix PATH : ${pkgs.pulseaudio}/bin
32 '';
33 };
34 wrapElectron = { package, bin ? package.meta.mainProgram or package.pname or (pkgs.lib.strings.nameFromURL package.name "-"), outBin ? bin, sandbox ? true }: pkgs.symlinkJoin { 7 wrapElectron = { package, bin ? package.meta.mainProgram or package.pname or (pkgs.lib.strings.nameFromURL package.name "-"), outBin ? bin, sandbox ? true }: pkgs.symlinkJoin {
35 name = "${package.name}-wrapped"; 8 name = "${package.name}-wrapped";
36 buildInputs = with pkgs; [ makeWrapper ]; 9 buildInputs = with pkgs; [ makeWrapper ];
@@ -47,10 +20,6 @@ let
47 ''; 20 '';
48 }; 21 };
49 22
50 wrappedChrome = wrapElectron { package = pkgs.google-chrome; outBin = "google-chrome"; };
51 wrappedZulip = wrapElectron { package = pkgs.zulip; bin = "zulip"; outBin = "zulip"; };
52 wrappedElementDesktop = wrapElectron { package = pkgs.element-desktop; bin = "element-desktop"; };
53 wrappedRocketChatDesktop = wrapElectron { package = pkgs.rocketchat-desktop; bin = "rocketchat-desktop"; outBin = "rocketchat"; };
54 wrappedYTMDesktop = wrapElectron { package = pkgs.ytmdesktop; sandbox = false; }; 23 wrappedYTMDesktop = wrapElectron { package = pkgs.ytmdesktop; sandbox = false; };
55 24
56 wrappedKeepassxc = pkgs.symlinkJoin { 25 wrappedKeepassxc = pkgs.symlinkJoin {
@@ -63,7 +32,7 @@ let
63 text = '' 32 text = ''
64 [D-BUS Service] 33 [D-BUS Service]
65 Name=org.keepassxc.KeePassXC.MainWindow 34 Name=org.keepassxc.KeePassXC.MainWindow
66 Exec=${pkgs.coreutils}/bin/false 35 Exec=${lib.getExe' pkgs.coreutils "false"}
67 SystemdService=keepassxc.service 36 SystemdService=keepassxc.service
68 ''; 37 '';
69 }) 38 })
@@ -73,36 +42,46 @@ let
73 text = '' 42 text = ''
74 [D-BUS Service] 43 [D-BUS Service]
75 Name=org.freedesktop.secrets 44 Name=org.freedesktop.secrets
76 Exec=${pkgs.coreutils}/bin/false 45 Exec=${lib.getExe' pkgs.coreutils "false"}
77 SystemdService=keepassxc.service 46 SystemdService=keepassxc.service
78 ''; 47 '';
79 }) 48 })
80 ]; 49 ];
81 }; 50 };
82 51
83 lockCommand = "${config.systemd.package}/bin/systemctl --user start gtklock.service"; 52 lockCommand = "${lib.getExe' config.systemd.package "systemctl"} --user start gtklock.service";
53
54 editor = pkgs.symlinkJoin {
55 inherit (cfg.services.emacs.package) name;
56 buildInputs = with pkgs; [ makeWrapper ];
57 paths = [ cfg.services.emacs.package ];
58 postBuild = ''
59 wrapProgram $out/bin/emacsclient \
60 --inherit-argv0 \
61 --add-flags ${lib.escapeShellArg (lib.escapeShellArgs cfg.services.emacs.client.arguments)}
62 '';
63 };
84in { 64in {
85 imports = with flake.nixosModules.userProfiles.${userName}; [ 65 imports = with flake.nixosModules.userProfiles.${userName}; [
86 mpv yt-dlp (args: import ./xcompose.nix (inputs // args)) 66 zsh tmux mpv yt-dlp (args: import ./xcompose.nix (inputs // args))
87 ]; 67 ];
88 68
89 config = { 69 config = {
90 services.displayManager.defaultSession = "Hyprland"; # "none+xmonad";
91
92 home-manager.users.${userName} = { 70 home-manager.users.${userName} = {
93 imports = [ 71 imports = [
94 ./libvirt 72 ./libvirt
95 ./niri 73 ./niri
96 flakeInputs.nix-index-database.hmModules.nix-index 74 ./synadm
75 flakeInputs.nix-index-database.homeModules.nix-index
97 flakeInputs.impermanence.nixosModules.home-manager.impermanence 76 flakeInputs.impermanence.nixosModules.home-manager.impermanence
98 ]; 77 ];
99 78
100 home.stateVersion = "20.09"; 79 home.stateVersion = "20.09";
101 80
102 nixpkgs.config = { 81 # nixpkgs.config = {
103 allowUnfree = true; 82 # allowUnfree = true;
104 zathura.useMupdf = false; 83 # zathura.useMupdf = false;
105 }; 84 # };
106 85
107 nix.registry = { 86 nix.registry = {
108 "flk" = { 87 "flk" = {
@@ -112,14 +91,14 @@ in {
112 }; 91 };
113 to = { 92 to = {
114 type = "git"; 93 type = "git";
115 url = "file:///home/gkleen/config/nixos-flakes"; 94 url = "file:///home/gkleen/projects/machines";
116 }; 95 };
117 }; 96 };
118 }; 97 };
119 98
120 programs = { 99 programs = {
121 ssh = { 100 ssh = {
122 matchBlocks = import ./ssh-hosts.nix { inherit pkgs; }; # customUtils.nixImport { dir = ./ssh-hosts; }; 101 matchBlocks = import ./ssh-hosts.nix inputs; # customUtils.nixImport { dir = ./ssh-hosts; };
123 extraConfig = '' 102 extraConfig = ''
124 Match host uniworx3.ifi.lmu.de,uniworx4.ifi.lmu.de,uniworx5.ifi.lmu.de,uni2workgw.ifi.lmu.de,blackbeard.tcs.ifi.lmu.de,gitlab2.rz.ifi.lmu.de,oregon.tcs.ifi.lmu.de !exec "nc -z -w 1 %h %p &>/dev/null" 103 Match host uniworx3.ifi.lmu.de,uniworx4.ifi.lmu.de,uniworx5.ifi.lmu.de,uni2workgw.ifi.lmu.de,blackbeard.tcs.ifi.lmu.de,gitlab2.rz.ifi.lmu.de,oregon.tcs.ifi.lmu.de !exec "nc -z -w 1 %h %p &>/dev/null"
125 ProxyJump remote.cip.ifi.lmu.de 104 ProxyJump remote.cip.ifi.lmu.de
@@ -137,8 +116,8 @@ in {
137 ''} 116 ''}
138 117
139 Match host *.mathinst.loc,*.math.lmu.de !host ssh.math.lmu.de !exec "nc -z -w 1 %h %p &>/dev/null" 118 Match host *.mathinst.loc,*.math.lmu.de !host ssh.math.lmu.de !exec "nc -z -w 1 %h %p &>/dev/null"
140 # ProxyCommand ${pkgs.socat}/bin/socat - SOCKS4A:127.0.0.1:%h:%p,socksport=8118 119 ProxyCommand ${lib.getExe pkgs.socat} - SOCKS4A:127.0.0.1:%h:%p,socksport=8118
141 ProxyJump ssh.math.lmu.de 120 # ProxyJump ssh.math.lmu.de
142 121
143 Match host *.cipmath.loc !host cip04.cipmath.loc,mgmt-cls01.cipmath.loc !exec "nc -z -w 1 %h %p &>/dev/null" 122 Match host *.cipmath.loc !host cip04.cipmath.loc,mgmt-cls01.cipmath.loc !exec "nc -z -w 1 %h %p &>/dev/null"
144 ProxyJump cip04 123 ProxyJump cip04
@@ -155,22 +134,31 @@ in {
155 134
156 emacs = { 135 emacs = {
157 enable = true; 136 enable = true;
158 package = pkgs.emacs29-pgtk; 137 package = pkgs.emacs-pgtk;
159 extraPackages = epkgs: with epkgs; [ 138 extraPackages = epkgs: with epkgs; [
160 evil evil-dvorak undo-tree magit haskell-tng-mode nix-mode 139 evil evil-dvorak undo-tree magit haskell-tng-mode nix-mode
161 yaml-mode json-mode shakespeare-mode smart-mode-line 140 yaml-mode json-mode shakespeare-mode smart-mode-line
162 highlight-parentheses highlight-symbol ag sass-mode lua-mode 141 highlight-parentheses highlight-symbol ag sass-mode
163 fira-code-mode use-package wanderlust # notmuch 142 lua-mode fira-code-mode use-package wanderlust # notmuch
164 git-gutter emacsScratch 143 git-gutter scratch edit-server mediawiki editorconfig
165 edit-server mediawiki editorconfig typescript-mode 144 typescript-mode markdown-mode nftables-mode rustic
166 markdown-mode nftables-mode rustic lsp-mode lsp-ui 145 lsp-mode lsp-ui direnv company projectile
167 direnv company projectile tomorrow-night-paradise-theme 146 tomorrow-night-paradise-theme
168 treesit-grammars.with-all-grammars magit-delta scad-mode 147 treesit-grammars.with-all-grammars magit-delta scad-mode
169 ]; 148 ];
170 overrides = self: super: { 149 overrides = self: super: {
171 tomorrow-night-paradise-theme = super.trivialBuild { 150 tomorrow-night-paradise-theme = super.trivialBuild {
172 inherit (sources.tomorrow-night-paradise-theme) pname version src; 151 inherit (sources.tomorrow-night-paradise-theme) pname version src;
173 }; 152 };
153 scratch = pkgs.stdenv.mkDerivation {
154 inherit (sources.emacs-scratch_el) pname version src;
155
156 phases = [ "unpackPhase" "installPhase" ];
157
158 installPhase = ''
159 install -Dt $out/share/emacs/site-lisp scratch.el
160 '';
161 };
174 }; 162 };
175 }; 163 };
176 firefox = { 164 firefox = {
@@ -184,8 +172,14 @@ in {
184 }; 172 };
185 }; 173 };
186 }; 174 };
175 chromium.enable = true;
187 176
188 zathura.enable = true; 177 zathura = {
178 enable = true;
179 options = {
180 scroll-page-aware = true;
181 };
182 };
189 imv.enable = true; 183 imv.enable = true;
190 184
191 mpv.config = { 185 mpv.config = {
@@ -194,13 +188,93 @@ in {
194 gpu-api = "vulkan"; 188 gpu-api = "vulkan";
195 }; 189 };
196 190
197 zsh.initExtra = '' 191 zsh.initContent = let
198 source ${./zshrc} 192 zshrc = pkgs.resholve.mkDerivation {
193 pname = "zshrc";
194 version = "0.0.0";
195
196 src = ./zshrc;
197
198 dontUnpack = true;
199 dontConfigure = true;
200 dontBuild = true;
201
202 installPhase = ''
203 mkdir -p $out/share
204 install "$src" $out/share/zshrc
205 '';
206
207 solutions = {
208 default = {
209 scripts = [ "share/zshrc" ];
210 interpreter = "none";
211 inputs = with pkgs; [
212 coreutils
213 rpm
214 binutils
215 squashfsTools
216 unzip
217 cfg.programs.git.package
218 magickWrapped
219 curl
220 file
221 gnutar
222 cpio
223 magic-wormhole
224 cfg.programs.zsh.package
225 fuse
226 util-linux
227 findutils
228 qrencode
229 tty-clock
230 cfg.programs.jq.package
231 eza
232 less
233 config.systemd.package
234 config.programs.ssh.package
235 gnused
236 miniserve
237 p7zip
238 ];
239 execer = with pkgs; [
240 "cannot:${lib.getExe' rpm "rpm2cpio"}"
241 "cannot:${lib.getExe' squashfsTools "unsquashfs"}"
242 "cannot:${lib.getExe' unzip "unzip"}"
243 "cannot:${lib.getExe cfg.programs.git.package}"
244 "cannot:${lib.getExe cpio}"
245 "cannot:${lib.getExe' magic-wormhole "wormhole"}"
246 "cannot:${lib.getExe' fuse "fusermount"}"
247 "cannot:${lib.getExe less}"
248 "cannot:${lib.getExe' config.systemd.package "systemctl"}"
249 "cannot:${lib.getExe config.programs.ssh.package}"
250 "cannot:${lib.getExe' p7zip "7z"}"
251 ];
252 wrapper = with pkgs; [
253 "${lib.getExe' magickWrapped "magick"}:${lib.getExe' imagemagick "magick"}"
254 ];
255 fake = {
256 builtin = ["print"];
257 external = ["sudo" "umount"];
258 };
259 };
260 };
261 };
262 magickWrapped = pkgs.symlinkJoin {
263 inherit (pkgs.imagemagick) name;
264 paths = [ pkgs.imagemagick ];
265
266 buildInputs = with pkgs; [ makeWrapper ];
267 postBuild = ''
268 wrapProgram $out/bin/magick \
269 --prefix PATH : ${lib.makeBinPath (with pkgs; [ ghostscript ])}
270 '';
271 };
272 in ''
273 source ${zshrc}/share/zshrc
199 ''; 274 '';
200 zsh.dirHashes = let 275 zsh.dirHashes = let
201 flakeHashes = mapAttrs' (n: v: nameValuePair (inputNames.${n} or n) (toString v)) flakeInputs; 276 flakeHashes = mapAttrs' (n: v: nameValuePair (inputNames.${n} or n) (toString v)) flakeInputs;
202 inputNames = { 277 inputNames = {
203 "nixpkgs" = "nixos";
204 }; 278 };
205 in flakeHashes // { 279 in flakeHashes // {
206 u2w = "$HOME/projects/uni2work"; 280 u2w = "$HOME/projects/uni2work";
@@ -212,6 +286,16 @@ in {
212 pro = "$HOME/projects/pro"; 286 pro = "$HOME/projects/pro";
213 media = "$HOME/media"; 287 media = "$HOME/media";
214 }; 288 };
289 jq.colors = {
290 arrays = "1;37";
291 "false" = "0;37";
292 "null" = "2;37";
293 numbers = "0;37";
294 objectKeys = "1;34";
295 objects = "1;37";
296 strings = "0;32";
297 "true" = "0;37";
298 };
215 299
216 obs-studio = { 300 obs-studio = {
217 enable = true; 301 enable = true;
@@ -221,7 +305,7 @@ in {
221 gh = { 305 gh = {
222 enable = true; 306 enable = true;
223 settings = { 307 settings = {
224 editor = "${config.home-manager.users.${userName}.programs.emacs.package}/bin/emacsclient"; 308 editor = lib.getExe' editor "emacsclient";
225 gitProtocol = "ssh"; 309 gitProtocol = "ssh";
226 }; 310 };
227 }; 311 };
@@ -247,16 +331,10 @@ in {
247 # notify_on_cmd_finish = "invisible 120"; 331 # notify_on_cmd_finish = "invisible 120";
248 }; 332 };
249 keybindings = { 333 keybindings = {
250 "kitty_mod+n" = "detach_window"; 334 "kitty_mod+n" = "new_os_window_with_cwd";
251 "kitty_mod+m" = "detach_window ask"; 335 "kitty_mod+m" = "detach_window ask";
252 }; 336 "kitty_mod+enter" = "new_window_with_cwd";
253 }; 337 "kitty_mod+t" = "new_tab_with_cwd";
254 wpaperd = {
255 enable = true;
256 settings.default = {
257 path = "~/.wallpapers";
258 duration = "8h";
259 mode = "center";
260 }; 338 };
261 }; 339 };
262 fuzzel = { 340 fuzzel = {
@@ -269,7 +347,7 @@ in {
269 font = "Fira Sans"; 347 font = "Fira Sans";
270 }; 348 };
271 colors = { 349 colors = {
272 background = "000000aa"; 350 background = "000000cc";
273 text = "cdd6f4ff"; 351 text = "cdd6f4ff";
274 match = "94e2d5ff"; 352 match = "94e2d5ff";
275 selection = "585b70ff"; 353 selection = "585b70ff";
@@ -282,26 +360,46 @@ in {
282 }; 360 };
283 }; 361 };
284 }; 362 };
363 pandoc = {
364 enable = true;
365 extraAbbreviations = ["i.A." "d.h." "D.h." "gdw."];
366 };
367 nushell = {
368 enable = true;
369 settings.show_banner = false;
370 };
371 fd.enable = true;
285 }; 372 };
286 373
287 services = { 374 services = {
375 wpaperd = {
376 enable = true;
377 settings.default = {
378 path = "~/.wallpapers";
379 duration = "15m";
380 mode = "center";
381 };
382 };
288 emacs = { 383 emacs = {
289 enable = true; 384 enable = true;
290 socketActivation.enable = true; 385 socketActivation.enable = true;
291 client = { 386 client = {
292 enable = true; 387 enable = true;
293 arguments = mkForce ["--reuse-frame" "--alternate-editor" "\"\""]; 388 arguments = mkForce ["--create-frame" "--alternate-editor" (lib.getExe cfg.services.emacs.package)];
294 }; 389 };
295 }; 390 };
296 gpg-agent = { 391 gpg-agent = {
297 enable = true; 392 enable = true;
298 enableSshSupport = true; 393 enableSshSupport = true;
299 extraConfig = '' 394 extraConfig = ''
300 pinentry-program ${pkgs.pinentry-gtk2}/bin/pinentry 395 pinentry-program ${lib.getExe' pkgs.pinentry-gtk2 "pinentry"}
301 grab 396 grab
302 ''; 397 '';
303 }; 398 };
304 xembed-sni-proxy.enable = true; 399 xembed-sni-proxy = {
400 enable = true;
401 package = pkgs.kdePackages.plasma-workspace;
402 };
305 udiskie = { 403 udiskie = {
306 enable = true; 404 enable = true;
307 automount = false; 405 automount = false;
@@ -314,6 +412,7 @@ in {
314 }; 412 };
315 device_config = [ 413 device_config = [
316 { loop_file = "/nix/store/*-etc-metadata.erofs"; is_mounted = false; ignore = true; } 414 { loop_file = "/nix/store/*-etc-metadata.erofs"; is_mounted = false; ignore = true; }
415 { mount_path = "/run/nixos-etc-metadata"; ignore = true; }
317 { mount_path = "/run/nixos-etc-metadata.*"; ignore = true; } 416 { mount_path = "/run/nixos-etc-metadata.*"; ignore = true; }
318 ]; 417 ];
319 icon_names.media = ["drive-removable-media-symbolic"]; 418 icon_names.media = ["drive-removable-media-symbolic"];
@@ -333,7 +432,7 @@ in {
333 batch = "true"; 432 batch = "true";
334 log = "false"; 433 log = "false";
335 repeat = "watch"; 434 repeat = "watch";
336 sshcmd = "${pkgs.openssh}/bin/ssh"; 435 sshcmd = lib.getExe' pkgs.openssh "ssh";
337 ui = "text"; 436 ui = "text";
338 }; 437 };
339 }; 438 };
@@ -353,31 +452,17 @@ in {
353 enable = true; 452 enable = true;
354 events = [ 453 events = [
355 { event = "before-sleep"; command = lockCommand; } 454 { event = "before-sleep"; command = lockCommand; }
356 # { event = "after-resume"; command = "${cfg.wayland.windowManager.hyprland.package}/bin/hyprctl dispatch dpms on"; }
357 { event = "lock"; command = lockCommand; } 455 { event = "lock"; command = lockCommand; }
358 ]; 456 ];
359 timeouts = [ 457 timeouts = [
360 # { timeout = 300; 458 { timeout = 600; command = lockCommand; }
361 # command = "${cfg.wayland.windowManager.hyprland.package}/bin/hyprctl dispatch dpms off";
362 # }
363 { timeout = 330; command = lockCommand; }
364 ]; 459 ];
365 extraArgs = [ 460 extraArgs = [
461 "-w"
366 "idlehint" "30" 462 "idlehint" "30"
367 ]; 463 ];
368 }; 464 };
369 poweralertd.enable = true; 465 poweralertd.enable = true;
370 avizo = {
371 enable = true;
372 settings.default = {
373 time = "1.0";
374 background = "rgba(0, 0, 0, 0.8)";
375 border-color = "rgba(0, 0, 0, 1)";
376 bar-fg-color = "rgba(160, 160, 160, 1)";
377 bar-bg-color = "rgba(32, 32, 32, 0.96)";
378 # y-offset = "0.25";
379 };
380 };
381 }; 466 };
382 467
383 home.pointerCursor = { 468 home.pointerCursor = {
@@ -409,6 +494,13 @@ in {
409 }; 494 };
410 }; 495 };
411 496
497 qt.kde.settings = {
498 kwalletrc = {
499 KSecretD.Enabled = false;
500 Wallet."Default Wallet" = "store";
501 };
502 };
503
412 xsession.preferStatusNotifierItems = true; 504 xsession.preferStatusNotifierItems = true;
413 505
414 xresources.properties = import ./xresources.nix; 506 xresources.properties = import ./xresources.nix;
@@ -417,20 +509,19 @@ in {
417 packages = with pkgs; [ 509 packages = with pkgs; [
418 fira fira-code pwvucontrol wrappedKeepassxc wl-clipboard-rs 510 fira fira-code pwvucontrol wrappedKeepassxc wl-clipboard-rs
419 mumble pulseaudio-ctl pamixer libnotify screen-message 511 mumble pulseaudio-ctl pamixer libnotify screen-message
420 wrappedYTMDesktop libsForQt5.qt5ct playerctl evince 512 wrappedYTMDesktop libsForQt5.qt5ct playerctl evince papers
421 thunderbird zoom-us xdg-desktop-portal steam steam-run 513 thunderbird zoom-us xdg-desktop-portal steam steam-run
422 wireshark virt-manager rclone cached-nix-shell worktime 514 wireshark virt-manager rclone cached-nix-shell worktime
423 fira-code-symbols libreoffice xournalpp google-chrome 515 fira-code-symbols libreoffice xournalpp
424 nixos-shell virt-viewer freerdp gnome-icon-theme 516 nixos-shell virt-viewer freerdp gnome-icon-theme
425 paper-icon-theme sshpassSecret weechat element-desktop 517 paper-icon-theme sshpassSecret weechat element-desktop
426 matrix-synapse-tools.synadm 518 sieve-connect gimp3 inkscape udiskie glab nitrokey-app
427 flakeInputs.deploy-rs.packages.${config.nixpkgs.system}.deploy-rs
428 sieve-connect gimp inkscape udiskie glab nitrokey-app
429 pynitrokey gtklock wlrctl remmina openscad spice-record 519 pynitrokey gtklock wlrctl remmina openscad spice-record
430 libguestfs-with-appliance nerd-fonts.fira-mono 520 nerd-fonts.fira-mono
431 nerd-fonts.symbols-only nerd-fonts.fira-code powerline-fonts 521 nerd-fonts.symbols-only nerd-fonts.fira-code powerline-fonts
432 swtpm 522 swtpm (hunspell.withDicts (dicts: with dicts; [en_GB-large de_DE]))
433 ]; 523 libation libqalculate
524 ] ++ mapAttrsToList (_name: pkg: pkgs.callPackage pkg {}) (customUtils.nixImport { dir = ./utils; });
434 525
435 file = { 526 file = {
436 ".backup-munin".source = ./backup-patterns; 527 ".backup-munin".source = ./backup-patterns;
@@ -450,12 +541,9 @@ in {
450 QT_QPA_PLATFORMTHEME = "qt5ct"; 541 QT_QPA_PLATFORMTHEME = "qt5ct";
451 LIBVIRT_DEFAULT_URI = "qemu:///system"; 542 LIBVIRT_DEFAULT_URI = "qemu:///system";
452 STACK_XDG = 1; 543 STACK_XDG = 1;
453 EDITOR = pkgs.writeShellScript "editor" '' 544 EDITOR = lib.getExe' editor "emacsclient";
454 args=("--reuse-frame" "--alternate-editor" "") 545 RCLONE_PASSWORD_COMMAND = "${lib.getExe' pkgs.libsecret "secret-tool"} lookup service rclone";
455 args+=("$@") 546 SYSTEMD_TINT_BACKGROUND = "false";
456 exec -a emacsclient ${cfg.services.emacs.package}/bin/emacsclient "''${args[@]}"
457 '';
458 RCLONE_PASSWORD_COMMAND = "${pkgs.libsecret}/bin/secret-tool lookup service rclone";
459 }; 547 };
460 548
461 extraProfileCommands = '' 549 extraProfileCommands = ''
@@ -468,7 +556,7 @@ in {
468 source = ./wireplumber; 556 source = ./wireplumber;
469 recursive = true; 557 recursive = true;
470 onChange = '' 558 onChange = ''
471 ${pkgs.systemd}/bin/systemctl --user try-restart wireplumber 559 ${lib.getExe' config.systemd.package "systemctl"} --user try-restart wireplumber
472 ''; 560 '';
473 }; 561 };
474 "stack/config.yaml" = { 562 "stack/config.yaml" = {
@@ -492,41 +580,36 @@ in {
492 General = { 580 General = {
493 dot_as_separator = 0; 581 dot_as_separator = 0;
494 }; 582 };
583 Mode = {
584 calculate_as_you_type = 1;
585 };
495 }; 586 };
496 }; 587 };
497 "emacs/init.el".source = ./emacs.el; 588 "emacs/init.el".source = pkgs.substitute {
589 src = ./emacs.el;
590 substitutions = [
591 "--subst-var-by" "ksshaskpass" (lib.getExe pkgs.kdePackages.ksshaskpass)
592 ];
593 };
498 "systemd/user/xdg-desktop-portal.service.d/after-graphical-session.conf".text = '' 594 "systemd/user/xdg-desktop-portal.service.d/after-graphical-session.conf".text = ''
499 [Unit] 595 [Unit]
500 After=graphical-session.target 596 After=graphical-session.target
501 ''; 597 '';
598 "systemd/user/home-manager.service.d/before-graphical-session.conf".text = ''
599 [Unit]
600 Before=graphical-session-pre.target
601 '';
602 "pdfpc/pdfpcrc".text = ''
603 mouse 8 prev
604 mouse 9 next
605 '';
502 }; 606 };
503 607
504 xdg.dataFile = { 608 xdg.dataFile = {
505 "pandoc/abbreviations" = {
506 source = pkgs.runCommand "pandoc-abbreviations" {
507 buildInputs = [ pkgs.pandoc pkgs.coreutils ];
508 } (let
509 germanAbbrevs = pkgs.fetchFromGitHub {
510 owner = "jfilter";
511 repo = "german-abbreviations";
512 rev = "8eb9dae93b6f05d7c53374cd217ab2dc89558e0c";
513 sha256 = "SaD3tSqzen6Y3SPICe6/9vhe4iMHlArZ3kFQaEk7Hps=";
514 };
515 in ''
516 cat \
517 <(pandoc --print-default-data-file=abbreviations) \
518 <(grep -E '^[^ ]+\.$' ${germanAbbrevs}/german_abbreviations.txt) \
519 ${pkgs.writeText "abbrevs.txt" ''
520 i.A.
521 d.h.
522 D.h.
523 gdw.
524 ''} \
525 | sort | uniq >$out
526 '');
527 };
528 "dbus-1/services/org.keepassxc.KeePassXC.service".source = "${wrappedKeepassxc}/share/dbus-1/services/org.keepassxc.KeePassXC.service"; 609 "dbus-1/services/org.keepassxc.KeePassXC.service".source = "${wrappedKeepassxc}/share/dbus-1/services/org.keepassxc.KeePassXC.service";
529 "dbus-1/services/org.freedesktop.secrets.service.service".source = "${wrappedKeepassxc}/share/dbus-1/services/org.freedesktop.secrets.service.service"; 610 "dbus-1/services/org.freedesktop.secrets.service.service".source = "${wrappedKeepassxc}/share/dbus-1/services/org.freedesktop.secrets.service.service";
611 "dbus-1/services/org.kde.kwalletd6.service".source = "${pkgs.kdePackages.kwallet}/share/dbus-1/services/org.kde.kwalletd6.service";
612 "dbus-1/services/org.kde.kwalletd5.service".source = "${pkgs.kdePackages.kwallet}/share/dbus-1/services/org.kde.kwalletd5.service";
530 "emoji-data/list.txt".source = pkgs.stdenv.mkDerivation { 613 "emoji-data/list.txt".source = pkgs.stdenv.mkDerivation {
531 inherit (sources.emoji-data) pname src; 614 inherit (sources.emoji-data) pname src;
532 version = lib.removePrefix "v" sources.emoji-data.version; 615 version = lib.removePrefix "v" sources.emoji-data.version;
@@ -612,19 +695,68 @@ in {
612 name = "Rainbow"; 695 name = "Rainbow";
613 exec = toString (pkgs.writeShellScript "rainbow" '' 696 exec = toString (pkgs.writeShellScript "rainbow" ''
614 exec -- \ 697 exec -- \
615 ${config.systemd.package}/bin/systemd-run --wait --user --slice-inherit \ 698 ${lib.getExe' config.systemd.package "systemd-run"} --wait --user --slice-inherit \
616 --property 'CPUAccounting=yes' --property 'CPUQuotaPeriodSec=50ms' \ 699 --property 'CPUAccounting=yes' --property 'CPUQuotaPeriodSec=50ms' \
617 --property 'Environment=DSCP=46' \ 700 -E DSCP=46 -E NIXOS_OZONE_WL \
618 -- ${pkgs.dscp}/bin/dscp ${pkgs.google-chrome}/bin/google-chrome-stable \ 701 -- ${lib.getExe pkgs.dscp} ${lib.getExe cfg.programs.chromium.package} \
619 --force-device-scale-factor=1.5 \
620 --class=Rainbow \ 702 --class=Rainbow \
621 --kiosk "https://web.openrainbow.com" \ 703 --app="https://web.openrainbow.com" \
622 --user-data-dir=''${HOME}/.config/google-chrome-rainbow 704 --user-data-dir=''${HOME}/.config/chromium-rainbow
623 ''); 705 '');
624 icon = pkgs.fetchurl { 706 icon = pkgs.fetchurl {
625 url = "https://web.openrainbow.com/rb/2.139.17/assets/skins/rainbow/images/homepage/logo__rainbow.svg"; 707 url = "https://web.openrainbow.com/rb/2.139.17/assets/skins/rainbow/images/homepage/logo__rainbow.svg";
626 hash = "sha256-5fmo8rDqVDpzkGaPjk4Y+SsSZpAsY7VUQSFW6WdHwuU="; 708 hash = "sha256-5fmo8rDqVDpzkGaPjk4Y+SsSZpAsY7VUQSFW6WdHwuU=";
627 }; 709 };
710 settings = {
711 StartupWMClass = "Rainbow";
712 };
713 };
714 kimai = {
715 name = "Kimai";
716 exec = toString (pkgs.writeShellScript "kimai" ''
717 exec -- \
718 ${lib.getExe cfg.programs.chromium.package} \
719 --class=Kimai \
720 --app="https://kimai.yggdrasil.li" \
721 --user-data-dir=''${HOME}/.config/chromium-kimai
722 '');
723 icon = pkgs.fetchurl {
724 url = "https://www.kimai.org/images/kimai_logo.png";
725 hash = "sha256-lnlOttzR2SwXA70R+egJUkeKr4U5V0avqTk8uX4bqfs=";
726 };
727 settings = {
728 StartupWMClass = "Kimai";
729 StartupNotify = "true";
730 };
731 };
732 audiobookshelf = {
733 name = "Audiobookshelf";
734 exec = toString (pkgs.writeShellScript "audiobookshelf" ''
735 exec -- \
736 ${lib.getExe cfg.programs.chromium.package} \
737 --class=Audiobookshelf \
738 --app="https://audiobookshelf.yggdrasil.li" \
739 --user-data-dir=''${HOME}/.config/chromium-audiobookshelf
740 '');
741 icon = pkgs.fetchurl {
742 url = "https://www.audiobookshelf.org/Logo.png";
743 hash = "sha256-JGPk+WNT1C4DC4lSMb0K0YmAMT5LvmSOeO0QRzkc7Lk=";
744 };
745 settings = {
746 StartupWMClass = "Audiobookshelf";
747 StartupNotify = "true";
748 };
749 };
750 thunderbird-lmu = {
751 name = "Thunderbird (LMU)";
752 exec = "thunderbird --name thunderbird -P lmu %U";
753 icon = "thunderbird";
754 genericName = "Email Client";
755 categories = [ "Network" "Chat" "Email" "Feed" "GTK" "News" ];
756 settings = {
757 StartupWMClass = "thunderbird";
758 StartupNotify = "true";
759 };
628 }; 760 };
629 }; 761 };
630 762
diff --git a/accounts/gkleen@sif/emacs.el b/accounts/gkleen@sif/emacs.el
index 183cb322..3beefba6 100644
--- a/accounts/gkleen@sif/emacs.el
+++ b/accounts/gkleen@sif/emacs.el
@@ -51,7 +51,7 @@
51 51
52;; (require 'scratch) 52;; (require 'scratch)
53(global-set-key (kbd "C-x B") 'scratch-create) 53(global-set-key (kbd "C-x B") 'scratch-create)
54(setq initial-major-mode 'scratch-mode) 54;; (setq initial-major-mode 'scratch-mode)
55(setq initial-scratch-message "") 55(setq initial-scratch-message "")
56 56
57(global-set-key (kbd "C-x K") 'kill-current-buffer) 57(global-set-key (kbd "C-x K") 'kill-current-buffer)
@@ -228,6 +228,7 @@ necessarily running."
228 (global-set-key (kbd "C-x k") 'kill-buffer-with-special-emacsclient-handling)) 228 (global-set-key (kbd "C-x k") 'kill-buffer-with-special-emacsclient-handling))
229 229
230(add-hook 'server-switch-hook 'install-emacsclient-wrapped-kill-buffer) 230(add-hook 'server-switch-hook 'install-emacsclient-wrapped-kill-buffer)
231(add-hook 'server-switch-hook #'raise-frame)
231 232
232(defun move-file (new-location) 233(defun move-file (new-location)
233 "Write this file to NEW-LOCATION, and delete the old one." 234 "Write this file to NEW-LOCATION, and delete the old one."
@@ -253,3 +254,5 @@ necessarily running."
253(bind-key "C-x C-m" #'move-file) 254(bind-key "C-x C-m" #'move-file)
254 255
255(let ((ssh_auth_sock (string-chop-newline (shell-command-to-string "gpgconf --list-dirs agent-ssh-socket")))) (setenv "SSH_AUTH_SOCK" ssh_auth_sock)) 256(let ((ssh_auth_sock (string-chop-newline (shell-command-to-string "gpgconf --list-dirs agent-ssh-socket")))) (setenv "SSH_AUTH_SOCK" ssh_auth_sock))
257(setenv "SSH_ASKPASS_REQUIRE" "prefer")
258(setenv "SSH_ASKPASS" "@ksshaskpass@")
diff --git a/accounts/gkleen@sif/firefox-chrome.css b/accounts/gkleen@sif/firefox-chrome.css
index 8900e2b9..726f1e4b 100644
--- a/accounts/gkleen@sif/firefox-chrome.css
+++ b/accounts/gkleen@sif/firefox-chrome.css
@@ -4,6 +4,21 @@
4 font-size:12px; 4 font-size:12px;
5} 5}
6 6
7#sidebar-main:has([expanded]) {
8 min-width:20em !important;
9 max-width:20em !important;
10}
11
12#sidebar, #sidebar-box {
13 min-width:35em !important;
14 max-width:35em !important;
15}
16
17#sidebar-box {
18 margin-right: var(--space-small);
19}
20
21/*
7#sidebar { 22#sidebar {
8 min-width:20em !important; 23 min-width:20em !important;
9 max-width:20em !important; 24 max-width:20em !important;
@@ -19,8 +34,21 @@
19} 34}
20 35
21#toolbar-menubar[inactive="true"] + #TabsToolbar { 36#toolbar-menubar[inactive="true"] + #TabsToolbar {
22 visibility: collapse !important; 37 visibility: collapse !important;
23} 38}
24 39
25#sidebar-box[sidebarcommand="tabcenter-reborn_ariasuni-sidebar-action"] #sidebar-header { visibility: collapse !important; } 40#sidebar-box[sidebarcommand="tabcenter-reborn_ariasuni-sidebar-action"] #sidebar-header { visibility: collapse !important; }
26#sidebar-box[sidebarcommand="_3c078156-979c-498b-8990-85f7987dd929_-sidebar-action"] #sidebar-header { visibility: collapse !important; } 41#sidebar-box[sidebarcommand="_3c078156-979c-498b-8990-85f7987dd929_-sidebar-action"] #sidebar-header { visibility: collapse !important; }
42*/
43
44.titlebar-buttonbox-container{ display: none; }
45#vertical-spacer { display: none; }
46#tabbrowser-tabs[orient="vertical"] .tab-background {
47 border-radius: var(--border-radius-small) !important;
48}
49hbox:has(> #tabs-newtab-button) {
50 display: none;
51}
52#sidebar-main .tools-and-extensions {
53 justify-content: space-around !important;
54}
diff --git a/accounts/gkleen@sif/niri/default.nix b/accounts/gkleen@sif/niri/default.nix
index 2e9b6909..35a3d799 100644
--- a/accounts/gkleen@sif/niri/default.nix
+++ b/accounts/gkleen@sif/niri/default.nix
@@ -1,12 +1,16 @@
1{ config, hostConfig, pkgs, lib, ... }: 1{ config, hostConfig, pkgs, lib, flakeInputs, ... }:
2let 2let
3 niri = config.programs.niri.package; 3 cfg = config.programs.niri;
4
5 kdl = flakeInputs.niri-flake.lib.kdl;
6 sleaf = name: arg: kdl.node name [arg] [];
7
8 niri = cfg.package;
4 terminal = lib.getExe config.programs.kitty.package; 9 terminal = lib.getExe config.programs.kitty.package;
5 lightctl = lib.getExe' config.services.avizo.package "lightctl";
6 volumectl = lib.getExe' config.services.avizo.package "volumectl";
7 makoctl = lib.getExe' config.services.mako.package "makoctl"; 10 makoctl = lib.getExe' config.services.mako.package "makoctl";
8 loginctl = lib.getExe' hostConfig.systemd.package "loginctl"; 11 loginctl = lib.getExe' hostConfig.systemd.package "loginctl";
9 systemctl = lib.getExe' hostConfig.systemd.package "systemctl"; 12 systemctl = lib.getExe' hostConfig.systemd.package "systemctl";
13 swayosd-client = lib.getExe' config.services.swayosd.package "swayosd-client";
10 14
11 focus_or_spawn = pkgs.writeShellApplication { 15 focus_or_spawn = pkgs.writeShellApplication {
12 name = "focus-or-spawn"; 16 name = "focus-or-spawn";
@@ -19,17 +23,25 @@ let
19 23
20 workspaces_json="$(niri msg -j workspaces)" 24 workspaces_json="$(niri msg -j workspaces)"
21 workspace_output="$(jq -r --arg workspace_name "$workspace_name" '.[] | select(.name == $workspace_name) | .output' <<<"$workspaces_json")" 25 workspace_output="$(jq -r --arg workspace_name "$workspace_name" '.[] | select(.name == $workspace_name) | .output' <<<"$workspaces_json")"
22 active_workspace="$(jq -r --arg workspace_output "$workspace_output" '.[] | select(.output == $workspace_output and .is_active) | .id' <<<"$workspaces_json")" 26 # active_workspace="$(jq -r --arg workspace_output "$workspace_output" '.[] | select(.output == $workspace_output and .is_active) | .id' <<<"$workspaces_json")"
23 active_output="$(jq -r '.[] | select(.is_focused) | .output' <<<"$workspaces_json")" 27 active_output="$(jq -r '.[] | select(.is_focused) | .output' <<<"$workspaces_json")"
24 if [[ $workspace_output != "$active_output" ]]; then 28 if [[ $workspace_output != "$active_output" ]]; then
25 niri msg action move-workspace-to-monitor --output "$active_output" "$workspace_name" 29 niri msg action move-workspace-to-monitor --reference "$workspace_name" "$active_output"
26 socat STDIO "$NIRI_SOCKET" <<<'{"Action":{"FocusWorkspace":{"reference":{"Id":'"''${active_workspace}"'}}}}' 30 # socat STDIO "$NIRI_SOCKET" <<<'{"Action":{"FocusWorkspace":{"reference":{"Id":'"''${active_workspace}"'}}}}'
27 niri msg action move-workspace-to-index --index 1 "$workspace_name" 31 # niri msg action move-workspace-to-index --reference "$workspace_name" 1
28 fi 32 fi
29 33
30 while IFS=$'\n' read -r window_json; do 34 while IFS=$'\n' read -r window_json; do
31 if [[ -n $(jq -c "$window_select" <<<"$window_json") ]]; then 35 if [[ -n $(jq -c "$window_select" <<<"$window_json") ]]; then
32 niri msg action focus-window --id "$(jq -r '.id' <<<"$window_json")" 36 if jq -e '.is_focused' <<<"$window_json" >/dev/null; then
37 niri msg action focus-workspace-previous
38 else
39 if [[ $(jq -r --arg workspace_name "$workspace_name" 'map(select(.name == $workspace_name)) | .[0].is_focused' <<<"$workspaces_json") != "true" ]] && [[ $(jq -r --arg workspace_name "$workspace_name" 'map(select(.name == $workspace_name)) | .[0].id' <<<"$workspaces_json") = $(jq -r '.workspace_id' <<<"$window_json") ]]; then
40 niri msg action focus-workspace "$workspace_name"
41 else
42 niri msg action focus-window --id "$(jq -r '.id' <<<"$window_json")"
43 fi
44 fi
33 exit 0 45 exit 0
34 fi 46 fi
35 done < <(niri msg -j windows | jq -c '.[]') 47 done < <(niri msg -j windows | jq -c '.[]')
@@ -38,7 +50,6 @@ let
38 ''; 50 '';
39 }; 51 };
40 focus-or-spawn-action = config.lib.niri.actions.spawn (lib.getExe focus_or_spawn); 52 focus-or-spawn-action = config.lib.niri.actions.spawn (lib.getExe focus_or_spawn);
41 focus-or-spawn-action-app_id = app_id: focus-or-spawn-action ''select(.app_id == "${app_id}")'';
42 53
43 with_adjacent_workspace = pkgs.writeShellApplication { 54 with_adjacent_workspace = pkgs.writeShellApplication {
44 name = "with-adjacent-workspace"; 55 name = "with-adjacent-workspace";
@@ -75,9 +86,9 @@ let
75 jq --arg active_workspace "$active_workspace" -c "$action" <<<"$workspace_json" | tee /dev/stderr | socat STDIO "$NIRI_SOCKET" 86 jq --arg active_workspace "$active_workspace" -c "$action" <<<"$workspace_json" | tee /dev/stderr | socat STDIO "$NIRI_SOCKET"
76 ''; 87 '';
77 }; 88 };
78 with-adjacent-workspace-action = config.lib.niri.actions.spawn (lib.getExe with_adjacent_workspace) "^pwctl|kpxc|bmgr|edit|term$"; 89 with-adjacent-workspace-action = config.lib.niri.actions.spawn (lib.getExe with_adjacent_workspace) "^${lib.concatMapStringsSep "|" ({ name, ...}: name) cfg.scratchspaces}$";
79 focus-adjacent-workspace = direction: with-adjacent-workspace-action direction ''{"Action":{"FocusWorkspace":{"reference":{"Id": .id}}}}''; 90 focus-adjacent-workspace = direction: with-adjacent-workspace-action direction ''{"Action":{"FocusWorkspace":{"reference":{"Id": .id}}}}'';
80 move-column-to-adjacent-workspace = direction: with-adjacent-workspace-action direction ''{"Action":{"MoveColumnToWorkspace":{"reference":{"Id": .id}}}}''; 91 move-column-to-adjacent-workspace = direction: with-adjacent-workspace-action direction ''{"Action":{"MoveColumnToWorkspace":{"reference":{"Id": .id}, "focus": true}}}'';
81 92
82 with_unnamed_workspace = pkgs.writeShellApplication { 93 with_unnamed_workspace = pkgs.writeShellApplication {
83 name = "with-unnamed-workspace"; 94 name = "with-unnamed-workspace";
@@ -90,13 +101,29 @@ let
90 active_output="$(jq -r '.[] | select(.is_focused) | .output' <<<"$workspaces_json")" 101 active_output="$(jq -r '.[] | select(.is_focused) | .output' <<<"$workspaces_json")"
91 active_workspace="$(jq -r '.[] | select(.is_focused) | .id' <<<"$workspaces_json")" 102 active_workspace="$(jq -r '.[] | select(.is_focused) | .id' <<<"$workspaces_json")"
92 103
93 workspace_json="$(jq -c --arg active_output "$active_output" 'map(select(.output == $active_output and .name == null)) | sort_by(.idx) | .[0]' <<<"$workspaces_json")" 104 history_json="$(socat STDIO UNIX-CONNECT:"$XDG_RUNTIME_DIR"/niri-workspace-history.sock)"
105 workspace_json="$(jq -c --arg active_output "$active_output" --argjson history "$history_json" 'map(select(.output == $active_output and .name == null)) | map({"value": ., "history_idx": ((. as $workspace | ($history[$active_output] | index($workspace | .id))) as $active_idx | if $active_idx then $active_idx else ($history[$active_output] | length) + 1 end)}) | sort_by(.history_idx, .value.idx) | map(.value) | .[0]' <<<"$workspaces_json")"
94 [[ -n $workspace_json && $workspace_json != null ]] || exit 0 106 [[ -n $workspace_json && $workspace_json != null ]] || exit 0
95 jq --arg active_workspace "$active_workspace" -c "$action" <<<"$workspace_json" | tee /dev/stderr | socat STDIO "$NIRI_SOCKET" 107 jq --arg active_workspace "$active_workspace" -c "$action" <<<"$workspace_json" | tee /dev/stderr | socat STDIO "$NIRI_SOCKET"
96 ''; 108 '';
97 }; 109 };
98 with-unnamed-workspace-action = config.lib.niri.actions.spawn (lib.getExe with_unnamed_workspace); 110 with-unnamed-workspace-action = config.lib.niri.actions.spawn (lib.getExe with_unnamed_workspace);
99 111
112 with_empty_unnamed_workspace = pkgs.writeShellApplication {
113 name = "with-empty-unnamed-workspace";
114 runtimeInputs = [ niri pkgs.gojq pkgs.socat ];
115 text = ''
116 action="$1"
117 shift
118
119 workspaces_json="$(niri msg -j workspaces)"
120 active_output="$(jq '.[] | select(.is_focused) | .output' <<<"$workspaces_json")"
121 target_workspace_id="$(jq --argjson active_output "$active_output" 'map(select(.active_window_id == null and .name == null and .output == $active_output)) | sort_by(.idx) | .[0].id' <<<"$workspaces_json")"
122 jq --argjson workspace_id "$target_workspace_id" -nc "$action" | tee /dev/stderr | socat STDIO "$NIRI_SOCKET"
123 '';
124 };
125 with-empty-unnamed-workspace-action = config.lib.niri.actions.spawn (lib.getExe with_empty_unnamed_workspace);
126
100 with_select_window = pkgs.writeShellApplication { 127 with_select_window = pkgs.writeShellApplication {
101 name = "with-select-window"; 128 name = "with-select-window";
102 runtimeInputs = [ niri pkgs.gojq pkgs.socat config.programs.fuzzel.package pkgs.gawk ]; 129 runtimeInputs = [ niri pkgs.gojq pkgs.socat config.programs.fuzzel.package pkgs.gawk ];
@@ -108,7 +135,7 @@ let
108 135
109 windows_json="$(niri msg -j windows)" 136 windows_json="$(niri msg -j windows)"
110 active_workspace="$(jq -r '.[] | select(.is_focused) | .workspace_id' <<<"$windows_json")" 137 active_workspace="$(jq -r '.[] | select(.is_focused) | .workspace_id' <<<"$windows_json")"
111 window_ix="$(gojq -r --arg active_workspace "$active_workspace" '.[] | select('"$window_select"') | "\(.title)\u0000icon\u001f\(.app_id)"' <<<"$windows_json" | fuzzel --log-level=warning --dmenu --index)" 138 window_ix="$(gojq -r --arg active_workspace "$active_workspace" '.[] | select('"$window_select"') | "\(.title)\u0000icon\u001f\(.app_id)"' <<<"$windows_json" | fuzzel --width=60 --log-level=warning --dmenu --index)"
112 # shellcheck disable=SC2016 139 # shellcheck disable=SC2016
113 window_json="$(gojq -rc --arg active_workspace "$active_workspace" --arg window_ix "$window_ix" 'map(select('"$window_select"')) | .[($window_ix | tonumber)]' <<<"$windows_json")" 140 window_json="$(gojq -rc --arg active_workspace "$active_workspace" --arg window_ix "$window_ix" 'map(select('"$window_select"')) | .[($window_ix | tonumber)]' <<<"$windows_json")"
114 141
@@ -118,12 +145,91 @@ let
118 ''; 145 '';
119 }; 146 };
120 with-select-window-action = config.lib.niri.actions.spawn (lib.getExe with_select_window); 147 with-select-window-action = config.lib.niri.actions.spawn (lib.getExe with_select_window);
148
149 with_predicate_window = pred: pkgs.writeShellApplication {
150 name = "with-predicate-window";
151 runtimeInputs = [ niri pkgs.gojq pkgs.socat ];
152 text = ''
153 action="$1"
154 shift
155
156 windows_json="$(niri msg -j windows)"
157 window_json="$(gojq -rc 'map(select(${pred})) | .[0]' <<<"$windows_json")"
158
159 [[ -z "$window_json" || $window_json = "null" ]] && exit 1
160
161 jq -c "$action" <<<"$window_json" | socat STDIO "$NIRI_SOCKET"
162 '';
163 };
164
165 with-urgent-window-action = config.lib.niri.actions.spawn (lib.getExe (with_predicate_window ".is_urgent"));
166 with-focused-window-action = config.lib.niri.actions.spawn (lib.getExe (with_predicate_window ".is_focused"));
121in { 167in {
122 imports = [ 168 imports = [
123 ./waybar.nix 169 ./waybar.nix
124 ./mako.nix 170 ./mako.nix
171 ./swayosd.nix
125 ]; 172 ];
126 173
174 options = {
175 programs.niri.scratchspaces = lib.mkOption {
176 type = lib.types.listOf (lib.types.submodule ({ config, ... }: {
177 options = {
178 name = lib.mkOption {
179 type = lib.types.str;
180 };
181 match = lib.mkOption {
182 type = lib.types.listOf (lib.types.attrsOf kdl.types.kdl-args);
183 default = [];
184 };
185 exclude = lib.mkOption {
186 type = lib.types.listOf (lib.types.attrsOf kdl.types.kdl-args);
187 default = [];
188 };
189 windowRuleExtra = lib.mkOption {
190 type = kdl.types.kdl-nodes;
191 default = [];
192 };
193 key = lib.mkOption {
194 type = lib.types.nullOr lib.types.str;
195 default = null;
196 };
197 moveKey = lib.mkOption {
198 type = lib.types.nullOr lib.types.str;
199 default = let
200 keys = lib.splitString "+" config.key;
201 defMoveKey = lib.concatStringsSep "+" (lib.flatten [
202 (lib.take (lib.length keys - 1) keys)
203 ["Shift"]
204 (lib.takeEnd 1 keys)
205 ]);
206 in if config.key == null then null else defMoveKey;
207 };
208 spawn = lib.mkOption {
209 type = lib.types.nullOr (lib.types.listOf lib.types.str);
210 default = null;
211 };
212 app-id = lib.mkOption {
213 type = lib.types.nullOr lib.types.str;
214 default = null;
215 };
216 selector = lib.mkOption {
217 type = lib.types.nullOr lib.types.str;
218 default = null;
219 };
220 };
221
222 config = lib.mkMerge [
223 (lib.mkIf (config.app-id != null) {
224 match = lib.mkDefault [ { app-id = "^${lib.escapeRegex config.app-id}$"; } ];
225 selector = lib.mkDefault "select(.app_id == \"${config.app-id}\")";
226 })
227 ];
228 }));
229 default = [];
230 };
231 };
232
127 config = { 233 config = {
128 systemd.user.services.xwayland-satellite = { 234 systemd.user.services.xwayland-satellite = {
129 Unit = { 235 Unit = {
@@ -150,461 +256,754 @@ in {
150 { event = "after-resume"; command = "${lib.getExe niri} msg action power-on-monitors"; } 256 { event = "after-resume"; command = "${lib.getExe niri} msg action power-on-monitors"; }
151 ]; 257 ];
152 timeouts = [ 258 timeouts = [
153 { timeout = 300; 259 { timeout = 540;
154 command = "${lib.getExe niri} msg action power-off-monitors"; 260 command = "${lib.getExe niri} msg action power-off-monitors";
155 } 261 }
156 ]; 262 ];
157 }; 263 };
158 264
159 programs.niri.settings = { 265 systemd.user.sockets.niri-workspace-history = {
160 prefer-no-csd = true; 266 Socket = {
161 screenshot-path = "${config.home.homeDirectory}/screenshots"; 267 ListenStream = "%t/niri-workspace-history.sock";
162 268 SocketMode = "0600";
163 hotkey-overlay.skip-at-startup = true;
164
165 input = {
166 keyboard.xkb = {
167 layout = "us,us";
168 variant = "dvp,";
169 options = "compose:caps,grp:win_space_toggle";
170 };
171
172 workspace-auto-back-and-forth = true;
173 # focus-follows-mouse.enable = true;
174 warp-mouse-to-focus = true;
175 }; 269 };
176 270 };
177 outputs = { 271 systemd.user.services.niri-workspace-history = {
178 "eDP-1" = { 272 Unit = {
179 scale = 1.5; 273 BindsTo = [ "niri.service" ];
180 position = { x = 0; y = 0; }; 274 After = [ "niri.service" ];
181 };
182 "Ancor Communications Inc ASUS PB287Q 0x0000DD9B" = {
183 scale = 1.5;
184 position = { x = 2560; y = 0; };
185 };
186 "HP Inc. HP 727pu CN4417143K" = {
187 mode = { width = 2560; height = 1440; refresh = 119.998; };
188 scale = 1;
189 position = { x = 2560; y = 0; };
190 variable-refresh-rate = "on-demand";
191 };
192 }; 275 };
193 276 Install = {
194 environment = { 277 WantedBy = [ "niri.service" ];
195 NIXOS_OZONE_WL = "1";
196 QT_QPA_PLATFORM = "wayland";
197 QT_WAYLAND_DISABLE_WINDOWDECORATION = "1";
198 GDK_BACKEND = "wayland";
199 SDL_VIDEODRIVER = "wayland";
200 DISPLAY = ":0";
201 }; 278 };
202 279 Service = {
203 debug.render-drm-device = "/dev/dri/by-path/pci-0000:00:02.0-render"; 280 Type = "simple";
204 281 Sockets = [ "niri-workspace-history.socket" ];
205 layout = { 282 ExecStart = pkgs.writers.writePython3 "niri-workspace-history" { flakeIgnore = ["E501"]; } ''
206 gaps = 8; 283 import os
207 struts = { left = 0; right = 0; top = 0; bottom = 0; }; 284 import socket
208 focus-ring = { 285 import json
209 width = 2; 286 # import sys
210 active.gradient = { 287 from collections import defaultdict
211 from = "hsla(195 100% 60% 0.75)"; 288 from threading import Thread, Lock
212 to = "hsla(155 100% 50% 0.75)"; 289 from socketserver import StreamRequestHandler, ThreadingTCPServer
213 angle = 29; 290 from contextlib import contextmanager
214 relative-to = "workspace-view"; 291 from io import TextIOWrapper
215 }; 292
216 inactive.gradient = { 293
217 from = "hsla(0 0% 42% 0.66)"; 294 @contextmanager
218 to = "hsla(0 0% 35% 0.66)"; 295 def detaching(thing):
219 angle = 29; 296 try:
220 relative-to = "workspace-view"; 297 yield thing
221 }; 298 finally:
222 }; 299 thing.detach()
223 300
224 preset-column-widths = [ 301
225 { proportion = 1. / 4.; } 302 workspace_history = defaultdict(list)
226 { proportion = 1. / 3.; } 303 history_lock = Lock()
227 { proportion = 1. / 2.; } 304
228 { proportion = 2. / 3.; } 305
229 { proportion = 3. / 4.; } 306 def monitor_niri():
230 ]; 307 workspaces = list()
231 default-column-width.proportion = 1. / 2.; 308
232 preset-window-heights = [ 309 def focus_workspace(output, workspace):
233 { proportion = 1. / 3.; } 310 with history_lock:
234 { proportion = 1. / 2.; } 311 workspace_history[output] = [workspace] + [ws for ws in workspace_history[output] if ws != workspace]
235 { proportion = 2. / 3.; } 312 # print(json.dumps(workspace_history), file=sys.stderr)
236 { proportion = 1.; } 313
237 ]; 314 sock = socket.socket(socket.AF_UNIX, socket.SOCK_STREAM)
238 315 sock.connect(os.environ["NIRI_SOCKET"])
239 always-center-single-column = true; 316 sock.send(b"\"EventStream\"\n")
317 for line in sock.makefile(buffering=1, encoding='utf-8'):
318 if line_json := json.loads(line):
319 if "WorkspacesChanged" in line_json:
320 workspaces = line_json["WorkspacesChanged"]["workspaces"]
321 for ws in workspaces:
322 if ws["is_focused"]:
323 focus_workspace(ws["output"], ws["id"])
324 if "WorkspaceActivated" in line_json:
325 for ws in workspaces:
326 if ws["id"] != line_json["WorkspaceActivated"]["id"]:
327 continue
328 focus_workspace(ws["output"], ws["id"])
329 break
330
331
332 class RequestHandler(StreamRequestHandler):
333 def handle(self):
334 with detaching(TextIOWrapper(self.wfile, encoding='utf-8', write_through=True)) as out:
335 with history_lock:
336 json.dump(workspace_history, out)
337
338
339 class Server(ThreadingTCPServer):
340 def __init__(self):
341 ThreadingTCPServer.__init__(self, ("", 8000), RequestHandler, bind_and_activate=False)
342 self.socket = socket.fromfd(3, self.address_family, self.socket_type)
343
344
345 def run_server():
346 with Server() as server:
347 server.serve_forever()
348
349
350 niri = Thread(target=monitor_niri)
351 niri.daemon = True
352 niri.start()
353
354 server_thread = Thread(target=run_server)
355 server_thread.daemon = True
356 server_thread.start()
357
358 while True:
359 server_thread.join(timeout=0.5)
360 niri.join(timeout=0.5)
361
362 if not (niri.is_alive() and server_thread.is_alive()):
363 break
364 '';
240 }; 365 };
241 366 };
242 cursor.hide-when-typing = true; 367 systemd.user.services.niri-workspace-sort = {
243 368 Unit = {
244 input = { 369 BindsTo = [ "niri.service" ];
245 touchpad.enable = false; 370 After = [ "niri.service" ];
246 trackball = {
247 scroll-method = "on-button-down";
248 scroll-button = 278;
249 };
250 }; 371 };
251 372 Install = {
252 workspaces = { 373 WantedBy = [ "niri.service" ];
253 "001" = { name = "pwctl"; open-on-output = "eDP-1"; };
254 "002" = { name = "kpxc"; open-on-output = "eDP-1"; };
255 "003" = { name = "bmgr"; open-on-output = "eDP-1"; };
256 "004" = { name = "term"; open-on-output = "eDP-1"; };
257 "005" = { name = "edit"; open-on-output = "eDP-1"; };
258 "101".name = "comm";
259 "102".name = "web";
260 # "104".name = "read";
261 # "105".name = "mon";
262 "110".name = "vid";
263 "120".name = "bmr";
264 }; 374 };
265 375 Service = {
266 window-rules = [ 376 Type = "simple";
267 # { 377 ExecStart = pkgs.writers.writePython3 "niri-workspace-sort" { flakeIgnore = ["E501"]; } ''
268 # geometry-corner-radius = 378 import os
269 # let 379 import sys
270 # allCorners = r: { bottom-left = r; bottom-right = r; top-left = r; top-right = r; }; 380 import socket
271 # in allCorners 4.; 381 import json
272 # clip-to-geometry = true; 382
273 # } 383 outputs = None
274 { 384 only = {'HDMI-A-1': {'bmr'}, 'eDP-1': {'vid'}}
275 matches = [ { app-id = "^com\.saivert\.pwvucontrol$"; } ]; 385
276 open-on-workspace = "pwctl"; 386
277 open-maximized = true; 387 class Niri(socket.socket):
278 } 388 def __init__(self):
279 { 389 super().__init__(socket.AF_UNIX, socket.SOCK_STREAM)
280 matches = [ { app-id = "^\.blueman-manager-wrapped$"; } ]; 390 super().connect(os.environ["NIRI_SOCKET"])
281 open-on-workspace = "bmgr"; 391 self.fh = super().makefile(mode='rw', buffering=1, encoding='utf-8')
282 open-maximized = true; 392
283 } 393 def cmd(self, obj):
284 { 394 print(json.dumps(obj, separators=(',', ':')), flush=True, file=self.fh)
285 matches = [ { app-id = "^org\.keepassxc\.KeePassXC$"; } ]; 395
286 block-out-from = "screencast"; 396 def event_stream(self):
287 } 397 self.cmd("EventStream")
288 { 398 return self.fh
289 matches = [ { app-id = "^org\.keepassxc\.KeePassXC$"; } ]; 399
290 excludes = [ 400
291 { title = "^Unlock Database.*"; } 401 with Niri() as niri, Niri().event_stream() as niri_stream:
292 { title = "^Access Request.*"; } 402 for line in niri_stream:
293 { title = ".*Passkey credentials$"; } 403 workspaces = None
294 ]; 404 if line_json := json.loads(line):
295 open-on-workspace = "kpxc"; 405 if "WorkspacesChanged" in line_json:
296 open-maximized = true; 406 workspaces = line_json["WorkspacesChanged"]["workspaces"]
297 open-focused = false; 407
298 } 408 if workspaces is None:
299 { 409 continue
300 matches = [ 410
301 { app-id = "^org\.keepassxc\.KeePassXC$"; title = "^Unlock Database.*"; } 411 old_outputs = outputs
302 { app-id = "^org\.keepassxc\.KeePassXC$"; title = "^Access Request.*"; } 412 outputs = {ws["output"] for ws in workspaces}
303 { app-id = "^org\.keepassxc\.KeePassXC$"; title = ".*Passkey credentials$"; } 413 if old_outputs is None:
304 ]; 414 print("Initial outputs: {}".format(outputs), file=sys.stderr)
305 open-focused = true; 415 continue
306 } 416
307 { 417 new_outputs = outputs - old_outputs
308 matches = [ { app-id = "^kitty-scratch$"; } ]; 418 if not new_outputs:
309 open-on-workspace = "term"; 419 continue
310 open-maximized = true; 420 print("New outputs: {}".format(new_outputs), file=sys.stderr)
311 } 421
312 { 422 relevant_workspaces = list(filter(lambda ws: (ws["name"] is not None) or (ws["active_window_id"] is not None), workspaces))
313 matches = [ { title = "^scratch$"; app-id = "^emacs$"; } ]; 423 target_output = next(iter(outputs - set(only.keys())))
314 open-on-workspace = "edit"; 424 if not target_output:
315 open-maximized = true; 425 continue
316 } 426 for ws in relevant_workspaces:
317 { 427 ws_ident = ws["name"] if ws["name"] is not None else (ws["output"], ws["idx"])
318 matches = [ 428 if ws["output"] not in set(only.keys()):
319 { app-id = "^emacs$"; } 429 continue
320 { app-id = "^firefox$"; } 430 if ws_ident in only[ws["output"]]:
321 ]; 431 continue
322 default-column-width.proportion = 2. / 3.; 432
323 } 433 print("{} -> {}".format(ws_ident, target_output), file=sys.stderr)
324 { 434 niri.cmd({"Action": {"MoveWorkspaceToMonitor": {"reference": {"Id": ws["id"]}, "output": target_output}}})
325 matches = [ 435 '';
326 { app-id = "^kitty$"; } 436 Restart = "on-failure";
327 { app-id = "^kitty-play$"; } 437 RestartSec = 10;
328 ];
329 default-column-width.proportion = 1. / 3.;
330 }
331 {
332 matches = [
333 { app-id = "^thunderbird$"; }
334 { app-id = "^Element$"; }
335 ];
336 open-on-workspace = "comm";
337 }
338 {
339 matches = [ { app-id = "^firefox$"; } ];
340 open-on-workspace = "web";
341 open-maximized = true;
342 variable-refresh-rate = true;
343 }
344 # {
345 # matches = [
346 # { app-id = "^evince$"; }
347 # { app-id = "^imv$"; }
348 # { app-id = "^org\.pwmt\.zathura$"; }
349 # ];
350 # open-on-workspace = "read";
351 # }
352 {
353 matches = [ { app-id = "^mpv$"; } ];
354 open-on-workspace = "vid";
355 default-column-width.proportion = 1.;
356 variable-refresh-rate = true;
357 }
358 {
359 matches = [ { app-id = "^kitty-play$"; } ];
360 open-on-workspace = "vid";
361 open-focused = false;
362 }
363 # {
364 # matches = [
365 # { app-id = "^qemu$"; }
366 # { app-id = "^virt-manager$"; }
367 # ];
368 # open-on-workspace = "mon";
369 # }
370 {
371 matches = [ { app-id = "^pdfpc$"; } ];
372 default-column-width.proportion = 1.;
373 }
374 {
375 matches = [ { app-id = "^pdfpc$"; title = "^pdfpc - presentation"; } ];
376 open-on-workspace = "bmr";
377 open-fullscreen = true;
378 }
379 {
380 matches = [
381 { app-id = "^Gimp-"; title = "^Quit GIMP$"; }
382 { app-id = "^org\.kde\.polkit-kde-authentication-agent-1$"; }
383 ];
384 open-floating = true;
385 }
386 ];
387 layer-rules = [
388 { matches = [
389 { namespace = "^notifications$"; }
390 { namespace = "^waybar$"; }
391 ];
392 block-out-from = "screencast";
393 }
394 ];
395
396 binds = with config.lib.niri.actions; {
397 "Mod+Slash".action = show-hotkey-overlay;
398
399 "Mod+Return".action = spawn terminal;
400 "Mod+Q".action = close-window;
401 "Mod+O".action = spawn (lib.getExe config.programs.fuzzel.package);
402 "Mod+Shift+O".action = spawn (lib.getExe config.programs.fuzzel.package) "--list-executables-in-path";
403
404 "Mod+Alt+E".action = spawn (lib.getExe' config.services.emacs.package "emacsclient") "-c";
405 "Mod+Alt+Y".action = spawn (lib.getExe (pkgs.writeShellApplication {
406 name = "queue-yt-dlp";
407 runtimeInputs = with pkgs; [ wl-clipboard-rs socat ];
408 text = ''
409 socat STDIO UNIX-CONNECT:"$XDG_RUNTIME_DIR"/yt-dlp.sock <<<$'{ "urls": ["'"$(wl-paste)"$'"] }'
410 '';
411 }));
412 "Mod+Alt+L".action = spawn (lib.getExe (pkgs.writeShellApplication {
413 name = "queue-yt-dlp";
414 runtimeInputs = with pkgs; [ wl-clipboard-rs config.programs.kitty.package ];
415 text = ''
416 exec -- kitty --app-id kitty-play --directory "$HOME"/media mpv "$(wl-paste)"
417 '';
418 }));
419
420 "Mod+U".action = spawn (lib.getExe (pkgs.writeShellApplication {
421 name = "qalc-fuzzel";
422 runtimeInputs = with pkgs; [ wl-clipboard-rs libqalculate config.programs.fuzzel.package coreutils findutils libnotify gnugrep ];
423 text = ''
424 RESULTS_DIR="$HOME/.cache/qalc-fuzzel"
425 prev() {
426 FOUND=false
427 while IFS= read -r line; do
428 [[ -n "$line" ]] || continue
429 FOUND=true
430 echo "$line"
431 done < <(export LC_ALL=C.UTF-8; echo; find "$RESULTS_DIR" -type f -printf $'%T@ %p\n' | sort -n | cut -d' ' -f2- | xargs -r cat)
432 $FOUND || echo
433 }
434 FUZZEL_RES=$(prev | fuzzel --dmenu --prompt "qalc> ") || exit $?
435 if [[ "$FUZZEL_RES" =~ .*\ =\ .* ]]; then
436 QALC_RES="$FUZZEL_RES"
437 QALC_RET=0
438 else
439 QALC_RES=$(qalc "$FUZZEL_RES" 2>&1)
440 QALC_RET=$?
441 fi
442 [[ -n "$QALC_RES" ]] || exit 1
443 EXISTING=false
444 set +o pipefail
445 grep -Fxrl "$QALC_RES" "$RESULTS_DIR" | xargs -r touch
446 [[ ''${PIPESTATUS[0]} -eq 0 ]] && EXISTING=true
447 set -o pipefail
448 if [[ $QALC_RET -eq 0 ]] && ! $EXISTING; then
449 set +o pipefail
450 RES_FILE="$RESULTS_DIR"/$(date -uIs).$(tr -Cd 'a-zA-Z0-9' </dev/random | head -c 10)
451 set -o pipefail
452 cat >"$RES_FILE" <<<"$QALC_RES"
453 fi
454 [[ "$QALC_RES" =~ .*\ =\ (.*) ]] && QALC_RES="''${BASH_REMATCH[1]}"
455 [[ $QALC_RET -eq 0 ]] && wl-copy "$QALC_RES"
456 notify-send "$QALC_RES"
457 '';
458 }));
459 "Mod+E".action = spawn (lib.getExe (pkgs.writeShellApplication {
460 name = "emoji-fuzzel";
461 runtimeInputs = with pkgs; [ config.programs.fuzzel.package wtype wl-clipboard-rs ];
462 text = ''
463 FUZZEL_RES=$(fuzzel --dmenu --prompt "emoji> " <"$HOME"/.local/share/emoji-data/list.txt) || exit $?
464 [[ -n "$FUZZEL_RES" ]] || exit 1
465 wl-copy "$(cut -d ':' -f 1 <<<"$FUZZEL_RES" | tr -d '\n')" && wtype -k XF86Paste
466 '';
467 }));
468 "Print".action = spawn (lib.getExe (pkgs.writeShellApplication {
469 name = "screenshot";
470 runtimeInputs = with pkgs; [ grim slurp wl-clipboard-rs coreutils ];
471 text = ''
472 grim -g "$(slurp -b 00000080 -c FFFFFFFF -s 00000000 -w 1)" - \
473 | tee "$HOME/screenshots/$(date +"%Y-%m-%dT%H:%M:%S").png" \
474 | wl-copy --type image/png
475 '';
476 }));
477 "Shift+Print".action = spawn (lib.getExe (pkgs.writeShellApplication {
478 name = "screenshot";
479 runtimeInputs = with pkgs; [ grim niri gojq wl-clipboard-rs coreutils ];
480 text = ''
481 grim -o "$(niri msg -j workspaces | jq -r '.[] | select(.is_focused) | .output')" - \
482 | tee "$HOME/screenshots/$(date +"%Y-%m-%dT%H:%M:%S").png" \
483 | wl-copy --type image/png
484 '';
485 }));
486 "Mod+B".action = with-select-window-action ".workspace_id == ($active_workspace | tonumber)" "{\"Action\":{\"FocusWindow\":{\"id\": .id}}}";
487 "Mod+Shift+B".action = with-select-window-action "true" "{\"Action\":{\"FocusWindow\":{\"id\": .id}}}";
488
489 "Mod+H".action = focus-column-left;
490 "Mod+T".action = focus-window-down;
491 "Mod+N".action = focus-window-up;
492 "Mod+S".action = focus-column-right;
493
494 "Mod+Shift+H".action = move-column-left;
495 "Mod+Shift+T".action = move-window-down;
496 "Mod+Shift+N".action = move-window-up;
497 "Mod+Shift+S".action = move-column-right;
498
499 "Mod+Control+H".action = focus-monitor-left;
500 "Mod+Control+T".action = focus-monitor-down;
501 "Mod+Control+N".action = focus-monitor-up;
502 "Mod+Control+S".action = focus-monitor-right;
503
504 "Mod+Shift+Control+H".action = move-workspace-to-monitor-left;
505 "Mod+Shift+Control+T".action = move-workspace-to-monitor-down;
506 "Mod+Shift+Control+N".action = move-workspace-to-monitor-up;
507 "Mod+Shift+Control+S".action = move-workspace-to-monitor-right;
508
509 "Mod+G".action = focus-adjacent-workspace "down";
510 "Mod+C".action = focus-adjacent-workspace "up";
511
512 "Mod+Shift+G".action = move-column-to-adjacent-workspace "down";
513 "Mod+Shift+C".action = move-column-to-adjacent-workspace "up";
514
515 "Mod+Shift+Control+G".action = move-workspace-down;
516 "Mod+Shift+Control+C".action = move-workspace-up;
517
518 "Mod+ParenLeft".action = focus-workspace "comm";
519 "Mod+Shift+ParenLeft".action = move-column-to-workspace "comm";
520
521 "Mod+ParenRight".action = focus-workspace "web";
522 "Mod+Shift+ParenRight".action = move-column-to-workspace "web";
523
524 "Mod+BraceRight".action = focus-workspace "read";
525 "Mod+Shift+BraceRight".action = move-column-to-workspace "read";
526
527 "Mod+BraceLeft".action = focus-workspace "mon";
528 "Mod+Shift+BraceLeft".action = move-column-to-workspace "mon";
529
530 "Mod+Asterisk".action = focus-workspace "vid";
531 "Mod+Shift+Asterisk".action = move-column-to-workspace "vid";
532
533 "Mod+Plus".action = with-unnamed-workspace-action ''{"Action":{"FocusWorkspace":{"reference":{"Id": .id}}}}'';
534 "Mod+Shift+Plus".action = with-unnamed-workspace-action ''{"Action":{"MoveColumnToWorkspace":{"reference":{"Id": .id}}}}'';
535
536 "Mod+M".action = consume-or-expel-window-left;
537 "Mod+W".action = consume-or-expel-window-right;
538
539 "Mod+R".action = switch-preset-column-width;
540 "Mod+Shift+R".action = switch-preset-window-height;
541 "Mod+F".action = center-column;
542 "Mod+Shift+F".action = maximize-column;
543 "Mod+Shift+Ctrl+F".action = fullscreen-window;
544
545 "Mod+V".action = switch-focus-between-floating-and-tiling;
546 "Mod+Shift+V".action = toggle-window-floating;
547
548 "Mod+Left".action = set-column-width "-10%";
549 "Mod+Down".action = set-window-height "-10%";
550 "Mod+Up".action = set-window-height "+10%";
551 "Mod+Right".action = set-column-width "+10%";
552
553 "Mod+Shift+Z" = {
554 action = spawn (lib.getExe niri) "msg" "action" "power-off-monitors";
555 allow-when-locked = true;
556 };
557 "Mod+Shift+L".action = spawn loginctl "lock-session";
558 "Mod+Shift+E".action = quit;
559 "Mod+Shift+Minus" = {
560 action = spawn systemctl "suspend";
561 allow-when-locked = true;
562 };
563 "Mod+Shift+Control+Minus" = {
564 action = spawn systemctl "hibernate";
565 allow-when-locked = true;
566 };
567 "Mod+Shift+P" = {
568 action = spawn (lib.getExe pkgs.playerctl) "-a" "pause";
569 allow-when-locked = true;
570 };
571
572 "XF86MonBrightnessUp" = {
573 action = spawn lightctl "-d" "-e4" "-n1" "up";
574 allow-when-locked = true;
575 };
576 "XF86MonBrightnessDown" = {
577 action = spawn lightctl "-d" "-e4" "-n1" "down";
578 allow-when-locked = true;
579 };
580 "XF86AudioRaiseVolume" = {
581 action = spawn volumectl "-d" "-u" "up";
582 allow-when-locked = true;
583 };
584 "XF86AudioLowerVolume" = {
585 action = spawn volumectl "-d" "-u" "down";
586 allow-when-locked = true;
587 };
588 "XF86AudioMute" = {
589 action = spawn volumectl "-d" "toggle-mute";
590 allow-when-locked = true;
591 };
592 "XF86AudioMicMute" = {
593 action = spawn volumectl "-d" "-m" "toggle-mute";
594 allow-when-locked = true;
595 };
596
597 "Mod+Semicolon".action = spawn makoctl "dismiss" "--group";
598 "Mod+Shift+Semicolon".action = spawn makoctl "dismiss" "--all";
599 "Mod+Period".action = spawn makoctl "menu" (lib.getExe config.programs.fuzzel.package) "--dmenu";
600 "Mod+Comma".action = spawn makoctl "restore";
601
602 "Mod+Control+A".action = focus-or-spawn-action-app_id "com.saivert.pwvucontrol" "pwctl" "pwvucontrol";
603 "Mod+Control+P".action = focus-or-spawn-action-app_id "org.keepassxc.KeePassXC" "kpxc" "keepassxc";
604 "Mod+Control+B".action = focus-or-spawn-action-app_id ".blueman-manager-wrapped" "bmgr" "blueman-manager";
605 "Mod+Control+Return".action = focus-or-spawn-action-app_id "kitty-scratch" "term" "kitty" "--app-id" "kitty-scratch";
606 "Mod+Control+E".action = focus-or-spawn-action "select(.app_id == \"emacs\" and .title == \"scratch\")" "edit" "emacsclient" "-c" "--frame-parameters=(quote (name . \"scratch\"))";
607 }; 438 };
608 }; 439 };
440
441 programs.niri.scratchspaces = [
442 { name = "pwctl";
443 key = "Mod+Control+A";
444 spawn = ["pwvucontrol"];
445 app-id = "com.saivert.pwvucontrol";
446 }
447 { name = "kpxc";
448 exclude = [
449 { title = "^Unlock Database.*"; }
450 { title = "^Access Request.*"; }
451 { title = ".*Passkey credentials$"; }
452 ];
453 windowRuleExtra = with kdl; [
454 (sleaf "open-focused" false)
455 ];
456 key = "Mod+Control+P";
457 app-id = "org.keepassxc.KeePassXC";
458 spawn = [ "keepassxc" ];
459 }
460 { name = "bmgr";
461 key = "Mod+Control+B";
462 app-id = ".blueman-manager-wrapped";
463 spawn = [ "blueman-manager" ];
464 }
465 { name = "term";
466 key = "Mod+Control+Return";
467 app-id = "kitty-scratch";
468 spawn = [ "kitty" "--app-id" "kitty-scratch" ];
469 }
470 { name = "edit";
471 match = [ { title = "^scratch$"; app-id = "^emacs$"; } ];
472 key = "Mod+Control+E";
473 selector = "select(.app_id == \"emacs\" and .title == \"scratch\")";
474 spawn = [ "emacsclient" "-c" "--frame-parameters=(quote (name . \"scratch\"))" ];
475 }
476 { name = "eff";
477 key = "Mod+Control+O";
478 app-id = "com.github.wwmm.easyeffects";
479 spawn = [ "easyeffects" ];
480 }
481 { name = "time";
482 key = "Mod+Control+K";
483 app-id = "chrome-kimai.yggdrasil.li__-Default";
484 spawn = [ (toString (pkgs.resholve.writeScript "kimai" {
485 interpreter = pkgs.runtimeShell;
486 inputs = [ pkgs.dex ];
487 execer = [ "cannot:${lib.getExe pkgs.dex}" ];
488 } ''
489 exec dex $HOME/.local/state/nix/profile/share/applications/kimai.desktop
490 '')) ];
491 windowRuleExtra = with kdl; [
492 (sleaf "block-out-from" "screencast")
493 ];
494 }
495 ];
496 programs.niri.config =
497 let
498 inherit (kdl) node plain leaf flag;
499 optional-node = cond: v:
500 if cond
501 then v
502 else null;
503 opt-props = lib.filterAttrs (lib.const (value: value != null));
504 normalize-nodes = nodes: lib.remove null (lib.flatten nodes);
505 in
506 normalize-nodes [
507 (flag "prefer-no-csd")
508
509 (sleaf "screenshot-path" "~/screenshots/%Y-%m-%dT%H:%M:%S.png")
510
511 (plain "hotkey-overlay" [
512 (flag "skip-at-startup")
513 ])
514
515 (plain "input" [
516 (plain "keyboard" [
517 (sleaf "repeat-delay" 300)
518 (sleaf "repeat-rate" 50)
519
520 (plain "xkb" [
521 (sleaf "layout" "us,us")
522 (sleaf "variant" "dvp,")
523 (sleaf "options" "compose:caps,grp:win_space_toggle")
524 ])
525 ])
526
527 (flag "workspace-auto-back-and-forth")
528 # (sleaf "focus-follows-mouse" {})
529 # (flag "warp-mouse-to-focus")
530
531 # (plain "touchpad" [ (flag "off") ])
532 (plain "trackball" [
533 (sleaf "scroll-method" "on-button-down")
534 (sleaf "scroll-button" 278)
535 ])
536 (plain "touch" [
537 (sleaf "map-to-output" "eDP-1")
538 ])
539 ])
540
541 (plain "gestures" [
542 (plain "hot-corners" [(flag "off")])
543 ])
544
545 (plain "environment" (lib.mapAttrsToList sleaf {
546 NIXOS_OZONE_WL = "1";
547 QT_QPA_PLATFORM = "wayland";
548 QT_WAYLAND_DISABLE_WINDOWDECORATION = "1";
549 GDK_BACKEND = "wayland";
550 SDL_VIDEODRIVER = "wayland";
551 DISPLAY = ":0";
552 ELECTRON_OZONE_PLATFORM_HINT = "auto";
553 SSH_ASKPASS_REQUIRE = "prefer";
554 SSH_ASKPASS = lib.getExe pkgs.kdePackages.ksshaskpass;
555 SUDO_ASKPASS = lib.getExe pkgs.kdePackages.ksshaskpass;
556 }))
557
558 (node "output" ["eDP-1"] [
559 (sleaf "scale" 1.5)
560 (sleaf "position" { x = 0; y = 0; })
561 ])
562 (node "output" ["Ancor Communications Inc ASUS PB287Q 0x0000DD9B"] [
563 (sleaf "scale" 1.5)
564 (sleaf "position" { x = 2560; y = 0; })
565 ])
566 (node "output" ["HP Inc. HP 727pu CN4417143K"] [
567 (sleaf "mode" "2560x1440@119.998")
568 (sleaf "scale" 1)
569 (sleaf "position" { x = 2560; y = 0; })
570 (flag "variable-refresh-rate")
571 ])
572
573 (plain "debug" [
574 (sleaf "render-drm-device" "/dev/dri/by-path/pci-0000:00:02.0-render")
575 ])
576
577 (plain "animations" [
578 (sleaf "slowdown" 0.5)
579 (plain "workspace-switch" [(flag "off")])
580 ])
581
582 (plain "layout" [
583 (sleaf "gaps" 8)
584 (plain "struts" [
585 (sleaf "left" 26)
586 (sleaf "right" 26)
587 (sleaf "top" 0)
588 (sleaf "bottom" 0)
589 ])
590 (plain "border" [
591 (sleaf "width" 2)
592 (sleaf "active-gradient" {
593 from = "hsla(195 100% 45% 1)";
594 to = "hsla(155 100% 37.5% 1)";
595 angle = 29;
596 relative-to = "workspace-view";
597 })
598 (sleaf "inactive-gradient" {
599 from = "hsla(0 0% 27.7% 1)";
600 to = "hsla(0 0% 23% 1)";
601 angle = 29;
602 relative-to = "workspace-view";
603 })
604 ])
605 (plain "focus-ring" [
606 (flag "off")
607 ])
608
609 (plain "preset-column-widths" (map (prop: sleaf "proportion" prop) [
610 (1. / 4.) (1. / 3.) (1. / 2.) (2. / 3.) (3. / 4.) (1.)
611 ]))
612 (plain "default-column-width" [ (sleaf "proportion" (1. / 2.)) ])
613 (plain "preset-window-heights" (map (prop: sleaf "proportion" prop) [
614 (1. / 3.) (1. / 2.) (2. / 3.) (1.)
615 ]))
616
617 (flag "always-center-single-column")
618
619 (plain "tab-indicator" [
620 (sleaf "gap" 4)
621 (sleaf "width" 8)
622 (sleaf "gaps-between-tabs" 4)
623 (flag "place-within-column")
624 (sleaf "length" { total-proportion = 1.; })
625 (sleaf "active-gradient" {
626 from = "hsla(195 100% 60% 0.75)";
627 to = "hsla(155 100% 50% 0.75)";
628 angle = 29;
629 relative-to = "workspace-view";
630 })
631 (sleaf "inactive-gradient" {
632 from = "hsla(0 0% 42% 0.66)";
633 to = "hsla(0 0% 35% 0.66)";
634 angle = 29;
635 relative-to = "workspace-view";
636 })
637 ])
638 ])
639
640 (plain "cursor" [
641 (flag "hide-when-typing")
642 ])
643
644 (map (name:
645 (node "workspace" [name] [
646 (sleaf "open-on-output" "eDP-1")
647 ])
648 ) (map ({name, ...}: name) cfg.scratchspaces))
649 (map (name:
650 (sleaf "workspace" name)
651 ) ["comm" "web" "vid" "bmr"])
652
653 (plain "window-rule" [
654 (sleaf "clip-to-geometry" true)
655 ])
656
657 (plain "window-rule" [
658 (sleaf "match" { is-floating = true; })
659 (sleaf "geometry-corner-radius" 8)
660 (plain "shadow" [ (flag "on") ])
661 ])
662
663 (plain "window-rule" [
664 (sleaf "match" { app-id = "^org\\.keepassxc\\.KeePassXC$"; })
665 (sleaf "block-out-from" "screencast")
666 ])
667 (plain "window-rule" (normalize-nodes [
668 (map (title:
669 (sleaf "match" { app-id = "^org\\.keepassxc\\.KeePassXC$"; inherit title; })
670 ) ["^Unlock Database.*" "^Access Request.*" ".*Passkey credentials$" "Browser Access Request$"])
671 (sleaf "open-focused" true)
672 (sleaf "open-floating" true)
673 ]))
674
675 (map ({ name, match, exclude, windowRuleExtra, ... }:
676 (optional-node (match != []) (plain "window-rule" (normalize-nodes [
677 (map (sleaf "match") match)
678 (map (sleaf "exclude") exclude)
679 (sleaf "open-on-workspace" name)
680 (sleaf "open-maximized" true)
681 windowRuleExtra
682 ])))
683 ) cfg.scratchspaces)
684
685 (plain "window-rule" [
686 (sleaf "match" { app-id = "^emacs$"; })
687 (sleaf "match" { app-id = "^firefox$"; })
688 (plain "default-column-width" [(sleaf "proportion" (2. / 3.))])
689 ])
690 (plain "window-rule" [
691 (sleaf "match" { app-id = "^kitty$"; })
692 (sleaf "match" { app-id = "^kitty-play$"; })
693 (plain "default-column-width" [(sleaf "proportion" (1. / 3.))])
694 ])
695
696 (plain "window-rule" [
697 (sleaf "match" { app-id = "^thunderbird$"; })
698 (sleaf "match" { app-id = "^Element$"; })
699 (sleaf "match" { app-id = "^chrome-web\.openrainbow\.com__-Default$"; })
700 (sleaf "open-on-workspace" "comm")
701 ])
702 (plain "window-rule" [
703 (sleaf "match" { app-id = "^firefox$"; })
704 (sleaf "open-on-workspace" "web")
705 (sleaf "open-maximized" true)
706 ])
707 (plain "window-rule" [
708 (sleaf "match" { app-id = "^mpv$"; })
709 (sleaf "open-on-workspace" "vid")
710 (plain "default-column-width" [(sleaf "proportion" 1.)])
711 ])
712 (plain "window-rule" [
713 (sleaf "match" { app-id = "^kitty-play$"; })
714 (sleaf "open-on-workspace" "vid")
715 (sleaf "open-focused" false)
716 ])
717 (plain "window-rule" [
718 (sleaf "match" { app-id = "^chrome-audiobookshelf\.yggdrasil\.li__-Default$"; })
719 (sleaf "match" { app-id = "^YouTube Music Desktop App$"; })
720 (sleaf "open-on-workspace" "vid")
721 ])
722 (plain "window-rule" [
723 (sleaf "match" { app-id = "^pdfpc$"; })
724 (plain "default-column-width" [(sleaf "proportion" 1.)])
725 ])
726 (plain "window-rule" [
727 (sleaf "match" { app-id = "^pdfpc$"; title = "^.*presentation.*$"; })
728 (plain "default-column-width" [(sleaf "proportion" 1.)])
729 (sleaf "open-fullscreen" true)
730 (sleaf "open-on-workspace" "bmr")
731 (sleaf "open-focused" false)
732 ])
733 (plain "window-rule" (normalize-nodes [
734 (map (sleaf "match") [
735 { app-id = "^Gimp-"; title = "^Quit GIMP$"; }
736 { app-id = "^org\\.kde\\.polkit-kde-authentication-agent-1$"; }
737 { app-id = "^xdg-desktop-portal-gtk$"; }
738 ])
739 (sleaf "open-floating" true)
740 ]))
741 (plain "window-rule" [
742 (sleaf "match" { app-id = "^org\\.pwmt\\.zathura$"; })
743 (sleaf "match" { app-id = "^evince$"; })
744 (sleaf "match" { app-id = "^org\\.gnome\\.Papers$"; })
745 (sleaf "default-column-display" "tabbed")
746 ])
747
748 (plain "layer-rule" [
749 (sleaf "match" { namespace = "^notifications$"; })
750 (sleaf "match" { namespace = "^waybar$"; })
751 (sleaf "match" { namespace = "^launcher$"; })
752 (sleaf "block-out-from" "screencast")
753 ])
754
755 (plain "binds"
756 (let
757 bind = name: cfg: node name [(lib.removeAttrs cfg ["action"])] (lib.mapAttrsToList leaf (lib.removeAttrs cfg.action ["__functor"]));
758 in
759 normalize-nodes [
760 (lib.mapAttrsToList bind (with config.lib.niri.actions; {
761 "Mod+Slash".action = show-hotkey-overlay;
762
763 "Mod+Return".action = spawn terminal;
764 "Mod+Shift+Return".action =
765 let
766 nushellKitty = pkgs.symlinkJoin {
767 name = "nushell-kitty";
768 paths = [ config.programs.kitty.package ];
769 buildInputs = [ pkgs.makeWrapper ];
770 postBuild = ''
771 wrapProgram $out/bin/kitty \
772 --add-flags "--config ${pkgs.writeText "kitty.conf" ''
773 include $HOME/${config.xdg.configFile."kitty/kitty.conf".target}
774 shell ${lib.getExe config.programs.nushell.package}
775 ''}"
776 '';
777 };
778 in spawn (lib.getExe' nushellKitty "kitty");
779 "Mod+Q".action = close-window;
780 "Mod+O".action = spawn (lib.getExe config.programs.fuzzel.package);
781 "Mod+Shift+O".action = spawn (lib.getExe config.programs.fuzzel.package) "--list-executables-in-path";
782
783 "Mod+Alt+E".action = spawn (lib.getExe' config.services.emacs.package "emacsclient") "-c";
784 "Mod+Alt+Y".action = spawn (lib.getExe (pkgs.writeShellApplication {
785 name = "queue-yt-dlp";
786 runtimeInputs = with pkgs; [ wl-clipboard-rs socat ];
787 text = ''
788 socat STDIO UNIX-CONNECT:"$XDG_RUNTIME_DIR"/yt-dlp.sock <<<$'{ "urls": ["'"$(wl-paste)"$'"] }'
789 '';
790 }));
791 "Mod+Alt+L".action = spawn (lib.getExe (pkgs.writeShellApplication {
792 name = "queue-yt-dlp";
793 runtimeInputs = with pkgs; [ wl-clipboard-rs config.programs.kitty.package ];
794 text = ''
795 exec -- kitty --app-id kitty-play --directory "$HOME"/media mpv "$(wl-paste)"
796 '';
797 }));
798 "Mod+Alt+M".action = spawn (lib.getExe' pkgs.screen-message "sm") "-n" "Fira Mono" "-a" "1" "-f" "#fff" "-b" "#000";
799
800 "Mod+U".action = spawn (lib.getExe (pkgs.writeShellApplication {
801 name = "qalc-fuzzel";
802 runtimeInputs = with pkgs; [ wl-clipboard-rs libqalculate config.programs.fuzzel.package coreutils findutils libnotify gnugrep ];
803 text = ''
804 RESULTS_DIR="$HOME/.cache/qalc-fuzzel"
805 prev() {
806 FOUND=false
807 while IFS= read -r line; do
808 [[ -n "$line" ]] || continue
809 FOUND=true
810 echo "$line"
811 done < <(export LC_ALL=C.UTF-8; echo; find "$RESULTS_DIR" -type f -printf $'%T@ %p\n' | sort -n | cut -d' ' -f2- | xargs -r cat)
812 $FOUND || echo
813 }
814 FUZZEL_RES=$(prev | fuzzel --dmenu --prompt "qalc> " --width=60) || exit $?
815 if [[ "$FUZZEL_RES" =~ .*\ =\ .* ]]; then
816 QALC_RES="$FUZZEL_RES"
817 QALC_RET=0
818 else
819 QALC_RES=$(qalc -set "autocalc off" "$FUZZEL_RES" 2>&1)
820 QALC_RET=$?
821 fi
822 [[ -n "$QALC_RES" ]] || exit 1
823 EXISTING=false
824 set +o pipefail
825 grep -Fxrl "$QALC_RES" "$RESULTS_DIR" | xargs -r touch
826 [[ ''${PIPESTATUS[0]} -eq 0 ]] && EXISTING=true
827 set -o pipefail
828 if [[ $QALC_RET -eq 0 ]] && ! $EXISTING; then
829 set +o pipefail
830 RES_FILE="$RESULTS_DIR"/$(date -uIs).$(tr -Cd 'a-zA-Z0-9' </dev/random | head -c 10)
831 set -o pipefail
832 cat >"$RES_FILE" <<<"$QALC_RES"
833 fi
834 [[ "$QALC_RES" =~ .*\ =\ (.*) ]] && QALC_RES="''${BASH_REMATCH[1]}"
835 [[ $QALC_RET -eq 0 ]] && wl-copy "$QALC_RES"
836 notify-send "$QALC_RES"
837 '';
838 }));
839 "Mod+Shift+U".action =
840 let
841 qalcKitty = pkgs.symlinkJoin {
842 name = "qalc-kitty";
843 paths = [ config.programs.kitty.package ];
844 buildInputs = [ pkgs.makeWrapper ];
845 postBuild = ''
846 wrapProgram $out/bin/kitty \
847 --add-flags "--config ${pkgs.writeText "kitty.conf" ''
848 include $HOME/${config.xdg.configFile."kitty/kitty.conf".target}
849 shell ${lib.getExe pkgs.libqalculate}
850 ''}"
851 '';
852 };
853 in spawn (lib.getExe' qalcKitty "kitty");
854 "Mod+E".action = spawn (lib.getExe (pkgs.writeShellApplication {
855 name = "emoji-fuzzel";
856 runtimeInputs = with pkgs; [ config.programs.fuzzel.package wtype wl-clipboard-rs ];
857 text = ''
858 FUZZEL_RES=$(fuzzel --dmenu --prompt "emoji> " --cache "$HOME"/.cache/fuzzel-emoji --width=60 <"$HOME"/.local/share/emoji-data/list.txt) || exit $?
859 [[ -n "$FUZZEL_RES" ]] || exit 1
860 wl-copy "$(cut -d ':' -f 1 <<<"$FUZZEL_RES" | tr -d '\n')" && wtype -k XF86Paste
861 '';
862 }));
863 "Print".action = screenshot;
864 "Control+Print".action = screenshot-window;
865 "Shift+Print".action = kdl.magic-leaf "screenshot-screen";
866 "Mod+B".action = with-select-window-action ".workspace_id == ($active_workspace | tonumber)" "{\"Action\":{\"FocusWindow\":{\"id\": .id}}}";
867 "Mod+Shift+B".action = with-select-window-action "true" "{\"Action\":{\"FocusWindow\":{\"id\": .id}}}";
868
869 "Mod+Escape" = {
870 allow-inhibiting = false;
871 action = toggle-keyboard-shortcuts-inhibit;
872 };
873
874 "Mod+H".action = focus-column-left;
875 "Mod+T".action = focus-window-down;
876 "Mod+N".action = focus-window-up;
877 "Mod+S".action = focus-column-right;
878
879 "Mod+Shift+H".action = move-column-left;
880 "Mod+Shift+T".action = move-window-down;
881 "Mod+Shift+N".action = move-window-up;
882 "Mod+Shift+S".action = move-column-right;
883
884 "Mod+Control+H".action = focus-monitor-left;
885 "Mod+Control+T".action = focus-monitor-down;
886 "Mod+Control+N".action = focus-monitor-up;
887 "Mod+Control+S".action = focus-monitor-right;
888
889 "Mod+Shift+Control+H".action = move-workspace-to-monitor-left;
890 "Mod+Shift+Control+T".action = move-workspace-to-monitor-down;
891 "Mod+Shift+Control+N".action = move-workspace-to-monitor-up;
892 "Mod+Shift+Control+S".action = move-workspace-to-monitor-right;
893
894 "Mod+G".action = focus-adjacent-workspace "down";
895 "Mod+C".action = focus-adjacent-workspace "up";
896
897 "Mod+Shift+G".action = move-column-to-adjacent-workspace "down";
898 "Mod+Shift+C".action = move-column-to-adjacent-workspace "up";
899
900 "Mod+Shift+Control+G".action = move-workspace-down;
901 "Mod+Shift+Control+C".action = move-workspace-up;
902
903 "Mod+ParenLeft".action = focus-workspace "comm";
904 "Mod+Shift+ParenLeft".action = kdl.magic-leaf "move-column-to-workspace" "comm";
905
906 "Mod+ParenRight".action = focus-workspace "web";
907 "Mod+Shift+ParenRight".action = kdl.magic-leaf "move-column-to-workspace" "web";
908
909 "Mod+BraceRight".action = focus-workspace "read";
910 "Mod+Shift+BraceRight".action = kdl.magic-leaf "move-column-to-workspace" "read";
911
912 "Mod+BraceLeft".action = focus-workspace "mon";
913 "Mod+Shift+BraceLeft".action = kdl.magic-leaf "move-column-to-workspace" "mon";
914
915 "Mod+Asterisk".action = focus-workspace "vid";
916 "Mod+Shift+Asterisk".action = kdl.magic-leaf "move-column-to-workspace" "vid";
917
918 "Mod+Plus".action = with-unnamed-workspace-action ''{"Action":{"FocusWorkspace":{"reference":{"Id": .id}}}}'';
919 "Mod+Shift+Plus".action = with-unnamed-workspace-action ''{"Action":{"MoveColumnToWorkspace":{"reference":{"Id": .id}, "focus": true}}}'';
920
921 "Mod+M".action = consume-or-expel-window-left;
922 "Mod+W".action = consume-or-expel-window-right;
923
924 "Mod+Shift+M".action = toggle-column-tabbed-display;
925
926 "Mod+R".action = switch-preset-column-width;
927 "Mod+Shift+R".action = maximize-column;
928 "Mod+Shift+Ctrl+R".action = switch-preset-window-height;
929 "Mod+F".action = center-column;
930 "Mod+Shift+F".action = toggle-windowed-fullscreen;
931 "Mod+Ctrl+Shift+F".action = fullscreen-window;
932
933 "Mod+V".action = switch-focus-between-floating-and-tiling;
934 "Mod+Shift+V".action = toggle-window-floating;
935
936 "Mod+Left".action = set-column-width "-10%";
937 "Mod+Down".action = set-window-height "-10%";
938 "Mod+Up".action = set-window-height "+10%";
939 "Mod+Right".action = set-column-width "+10%";
940
941 "Mod+Shift+Z" = {
942 action = spawn (lib.getExe niri) "msg" "action" "power-off-monitors";
943 allow-when-locked = true;
944 };
945 "Mod+Shift+L".action = spawn loginctl "lock-session";
946 "Mod+Shift+E".action = quit;
947 "Mod+Shift+Minus" = {
948 action = spawn systemctl "suspend";
949 allow-when-locked = true;
950 };
951 "Mod+Shift+Control+Minus" = {
952 action = spawn systemctl "hibernate";
953 allow-when-locked = true;
954 };
955 "Mod+Shift+P" = {
956 action = spawn (lib.getExe pkgs.playerctl) "-a" "pause";
957 allow-when-locked = true;
958 };
959
960 "XF86MonBrightnessUp" = {
961 action = spawn swayosd-client "--brightness" "raise";
962 allow-when-locked = true;
963 };
964 "XF86MonBrightnessDown" = {
965 action = spawn swayosd-client "--brightness" "lower";
966 allow-when-locked = true;
967 };
968 "XF86AudioRaiseVolume" = {
969 action = spawn swayosd-client "--output-volume" "raise";
970 allow-when-locked = true;
971 };
972 "XF86AudioLowerVolume" = {
973 action = spawn swayosd-client "--output-volume" "lower";
974 allow-when-locked = true;
975 };
976 "XF86AudioMute" = {
977 action = spawn swayosd-client "--output-volume" "mute-toggle";
978 allow-when-locked = true;
979 };
980 "XF86AudioMicMute" = {
981 action = spawn swayosd-client "--input-volume" "mute-toggle";
982 allow-when-locked = true;
983 };
984
985 "Mod+Semicolon".action = spawn makoctl "dismiss" "--group";
986 "Mod+Shift+Semicolon".action = spawn makoctl "dismiss" "--all";
987 "Mod+Period".action = spawn makoctl "menu" "--" (lib.getExe config.programs.fuzzel.package) "--dmenu";
988 "Mod+Comma".action = spawn makoctl "restore";
989
990 "Mod+Control+W".action = with-empty-unnamed-workspace-action "{\"Action\":{\"FocusWorkspace\":{\"reference\":{\"Id\": $workspace_id}}}}";
991 "Mod+Control+Shift+W".action = with-empty-unnamed-workspace-action "{\"Action\":{\"MoveColumnToWorkspace\":{\"reference\":{\"Id\": $workspace_id}, \"focus\": true}}}";
992
993 "Mod+X".action = set-dynamic-cast-window;
994 "Mod+Shift+X".action = set-dynamic-cast-monitor;
995 "Mod+Control+Shift+X".action = clear-dynamic-cast-target;
996
997 "Mod+D".action = with-urgent-window-action "{\"Action\":{\"FocusWindow\":{\"id\": .id}}}";
998 "Mod+Shift+D".action = with-focused-window-action "{\"Action\":{\"UnsetUrgent\":{\"id\": .id}}}";
999
1000 "Mod+K".action = spawn (lib.getExe' pkgs.worktime "worktime-ui");
1001 "Mod+Shift+K".action = spawn (lib.getExe' pkgs.worktime "worktime-stop");
1002 }))
1003 (map ({ name, selector, spawn, key, ...}: if key != null && selector != null && spawn != null then bind key { action = focus-or-spawn-action selector name spawn; } else null) cfg.scratchspaces)
1004 (map ({ name, moveKey, ...}: if moveKey != null then bind moveKey { action = kdl.magic-leaf "move-column-to-workspace" name; } else null) cfg.scratchspaces)
1005 ]
1006 ))
1007 ];
609 }; 1008 };
610} 1009}
diff --git a/accounts/gkleen@sif/niri/mako.nix b/accounts/gkleen@sif/niri/mako.nix
index e06d3b3a..703d5f7b 100644
--- a/accounts/gkleen@sif/niri/mako.nix
+++ b/accounts/gkleen@sif/niri/mako.nix
@@ -1,35 +1,40 @@
1{ config, lib, ... }: 1{ config, lib, pkgs, ... }:
2{ 2{
3 config = { 3 config = {
4 services.mako = { 4 services.mako = {
5 enable = true; 5 enable = true;
6 font = "Fira Sans 10"; 6 settings = {
7 format = "<i>%s</i>\\n%b"; 7 font = "Fira Sans 10";
8 margin = "2"; 8 format = "<i>%s</i>\\n%b";
9 maxVisible = -1; 9 margin = "2";
10 backgroundColor = "#000000dd"; 10 max-visible = -1;
11 progressColor = "source #223544ff"; 11 background-color = "#000000dd";
12 width = 384; 12 progress-color = "source #223544ff";
13 extraConfig = '' 13 width = 384;
14 outer-margin=1 14 outer-margin = 1;
15 max-history=100 15 max-history = 100;
16 max-icon-size=48 16 max-icon-size = 48;
17 17
18 [grouped] 18 grouped.format = "<b>(%g)</b> <i>%s</i>\\n%b";
19 format=<b>(%g)</b> <i>%s</i>\n%b 19 "urgency=low".text-color = "#999999ff";
20 20 "urgency=critical".background-color = "#900000dd";
21 [urgency=low] 21 "app-name=Element".group-by = "summary";
22 text-color=#999999ff 22 "app-name=poweralertd" = {
23 23 history = false;
24 [urgency=critical] 24 ignore-timeout = true;
25 background-color=#900000dd 25 default-timeout = 2000;
26 26 };
27 [app-name=Element] 27 "app-name=worktime".history = false;
28 group-by=summary 28 "mode=silent".invisible = true;
29 29 };
30 [mode=silent] 30 package = pkgs.symlinkJoin {
31 invisible=1 31 name = "${pkgs.mako.name}-wrapped";
32 ''; 32 paths = with pkgs; [ mako ];
33 inherit (pkgs.mako) meta;
34 postBuild = ''
35 rm -r $out/share/dbus-1
36 '';
37 };
33 }; 38 };
34 systemd.user.services.mako = { 39 systemd.user.services.mako = {
35 Unit = { 40 Unit = {
diff --git a/accounts/gkleen@sif/niri/swayosd.nix b/accounts/gkleen@sif/niri/swayosd.nix
new file mode 100644
index 00000000..54ebb302
--- /dev/null
+++ b/accounts/gkleen@sif/niri/swayosd.nix
@@ -0,0 +1,66 @@
1{ pkgs, ... }:
2{
3 config = {
4 services.swayosd = {
5 enable = true;
6 topMargin = 0.4769706078;
7 stylePath = pkgs.runCommand "style.css" {
8 passAsFile = [ "src" ];
9 src = ''
10 window#osd {
11 padding: 12px 20px;
12 border-radius: 999px;
13 border: none;
14 background: rgba(0, 0, 0, 0.87);
15
16 #container {
17 margin: 16px;
18 }
19
20 image,
21 label {
22 color: rgb(255, 255, 255);
23
24 &:disabled {
25 opacity: 1;
26 color: rgb(84, 84, 84);
27 }
28 }
29
30 progressbar {
31 min-height: 6px;
32 border-radius: 999px;
33 background: transparent;
34 border: none;
35
36 trough, progress {
37 min-height: inherit;
38 border-radius: inherit;
39 border: none;
40 }
41
42 trough {
43 background: rgb(127, 127, 127);
44 }
45 progress {
46 background: rgb(255, 255, 255);
47 }
48
49 &:disabled {
50 opacity: 1;
51
52 trough {
53 background: rgb(19, 19, 19);
54 }
55 progress {
56 background: rgb(38, 38, 38);
57 }
58 }
59 }
60 }
61 '';
62 buildInputs = with pkgs; [sass];
63 } "scss -C --sourcemap=none --style=compact $srcPath $out";
64 };
65 };
66}
diff --git a/accounts/gkleen@sif/niri/waybar.nix b/accounts/gkleen@sif/niri/waybar.nix
index 79c429f8..c02a9a76 100644
--- a/accounts/gkleen@sif/niri/waybar.nix
+++ b/accounts/gkleen@sif/niri/waybar.nix
@@ -1,5 +1,7 @@
1{ lib, pkgs, ... }: 1{ lib, config, pkgs, ... }:
2{ 2let
3 swayosd-client = lib.getExe' config.services.swayosd.package "swayosd-client";
4in {
3 config = { 5 config = {
4 programs.waybar = { 6 programs.waybar = {
5 enable = true; 7 enable = true;
@@ -18,15 +20,21 @@
18 { 20 {
19 layer = "top"; 21 layer = "top";
20 position = "top"; 22 position = "top";
21 height = 14; 23 height = 21;
22 output = [ "eDP-1" "DP-2" "DP-3" ]; 24 output = [ "eDP-1" "DP-2" "DP-3" ];
23 modules-left = [ "niri/workspaces" ]; 25 modules-left = [ "niri/workspaces" ];
24 modules-center = [ "niri/window" ]; 26 modules-center = [ "niri/window" ];
25 modules-right = [ # "custom/worktime" "custom/worktime-today" 27 modules-right = [ "custom/worktime" "custom/worktime-today"
26 "custom/weather" 28 "custom/weather"
27 "custom/keymap" 29 "custom/keymap"
28 "privacy" "tray" "wireplumber" "backlight" "battery" "idle_inhibitor" "custom/mako" "clock" ]; 30 "privacy" "tray" "wireplumber" "backlight" "battery" "idle_inhibitor" "custom/mako" "custom/lid_inhibitor" "clock" ];
29 31
32 "custom/lid_inhibitor" = {
33 format = "{}";
34 return-type = "json";
35 exec = lib.getExe pkgs.waybar-systemd-inhibit;
36 on-click = lib.getExe' pkgs.waybar-systemd-inhibit "waybar-systemd-inhibit-toggle";
37 };
30 "custom/mako" = { 38 "custom/mako" = {
31 format = "{}"; 39 format = "{}";
32 return-type = "json"; 40 return-type = "json";
@@ -59,7 +67,7 @@
59 text = f"<span font=\"Symbols Nerd Font Mono\" size=\"90%\">{icon}</span>" # noqa: E501 67 text = f"<span font=\"Symbols Nerd Font Mono\" size=\"90%\">{icon}</span>" # noqa: E501
60 if is_silent: 68 if is_silent:
61 text = f"<span color=\"#ffffff\">{text}</span>" 69 text = f"<span color=\"#ffffff\">{text}</span>"
62 print(json.dumps({'text': text}, separators=(',', ':')), flush=True) # noqa: E501 70 print(json.dumps({'text': text, 'tooltip': ', '.join(modes)}, separators=(',', ':')), flush=True) # noqa: E501
63 71
64 async def on_properties_changed(interface_name, changed_properties, invalidated_properties): # noqa: E501 72 async def on_properties_changed(interface_name, changed_properties, invalidated_properties): # noqa: E501
65 if "Modes" not in invalidated_properties: 73 if "Modes" not in invalidated_properties:
@@ -120,16 +128,16 @@
120 }; 128 };
121 "custom/worktime" = { 129 "custom/worktime" = {
122 interval = 60; 130 interval = 60;
123 exec = lib.getExe pkgs.worktime; 131 exec = "${lib.getExe pkgs.worktime} time --waybar";
124 tooltip = false; 132 return-type = "json";
125 }; 133 };
126 "custom/worktime-today" = { 134 "custom/worktime-today" = {
127 interval = 60; 135 interval = 60;
128 exec = "${lib.getExe pkgs.worktime} today"; 136 exec = "${lib.getExe pkgs.worktime} today --waybar";
129 tooltip = false; 137 return-type = "json";
130 }; 138 };
131 "niri/workspaces" = { 139 "niri/workspaces" = {
132 ignore = ["pwctl" "kpxc" "bmgr" "edit" "term"]; 140 ignore = map ({ name, ... }: name) config.programs.niri.scratchspaces;
133 }; 141 };
134 "niri/window" = { 142 "niri/window" = {
135 separate-outputs = true; 143 separate-outputs = true;
@@ -190,8 +198,8 @@
190 icon-size = iconSize; 198 icon-size = iconSize;
191 tooltip-format = "{percent}%"; 199 tooltip-format = "{percent}%";
192 format-icons = ["&#xf00da;" "&#xf00db;" "&#xf00dc;" "&#xf00dd;" "&#xf00de;" "&#xf00df;" "&#xf00e0;"]; 200 format-icons = ["&#xf00da;" "&#xf00db;" "&#xf00dc;" "&#xf00dd;" "&#xf00de;" "&#xf00df;" "&#xf00e0;"];
193 on-scroll-up = "lightctl -d -e4 -n1 up"; 201 on-scroll-up = "${swayosd-client} --brightness raise";
194 on-scroll-down = "lightctl -d -e4 -n1 down"; 202 on-scroll-down = "${swayosd-client} --brightness lower";
195 }; 203 };
196 wireplumber = { 204 wireplumber = {
197 format = "<span font=\"Symbols Nerd Font Mono\" size=\"90%\">{icon}</span>"; 205 format = "<span font=\"Symbols Nerd Font Mono\" size=\"90%\">{icon}</span>";
@@ -200,22 +208,22 @@
200 format-icons = ["&#xf057f;" "&#xf0580;" "&#xf057e;"]; 208 format-icons = ["&#xf057f;" "&#xf0580;" "&#xf057e;"];
201 format-muted = "<span font=\"Symbols Nerd Font Mono\" size=\"90%\">&#xf075f;</span>"; 209 format-muted = "<span font=\"Symbols Nerd Font Mono\" size=\"90%\">&#xf075f;</span>";
202 # ignored-sinks = ["Easy Effects Sink"]; 210 # ignored-sinks = ["Easy Effects Sink"];
203 on-scroll-up = "volumectl -d -u up"; 211 on-scroll-up = "${swayosd-client} --output-volume raise";
204 on-scroll-down = "volumectl -d -u down"; 212 on-scroll-down = "${swayosd-client} --output-volume lower";
205 on-click = "volumectl -d toggle-mute"; 213 on-click = "${swayosd-client} --output-volume mute-toggle";
206 }; 214 };
207 } 215 }
208 { 216 {
209 layer = "top"; 217 layer = "top";
210 position = "top"; 218 position = "top";
211 height = 14; 219 height = 14;
212 output = [ "!eDP-1" "!DP-2" "!DP-3" ]; 220 output = [ "!eDP-1" "!DP-2" "!DP-3" "*" ];
213 modules-left = [ "niri/workspaces" ]; 221 modules-left = [ "niri/workspaces" ];
214 modules-center = [ "niri/window" ]; 222 modules-center = [ "niri/window" ];
215 modules-right = [ "clock" ]; 223 modules-right = [ "clock" ];
216 224
217 "niri/workspaces" = { 225 "niri/workspaces" = {
218 ignore = ["pwctl" "kpxc" "bmgr" "edit" "term"]; 226 ignore = map ({ name, ... }: name) config.programs.niri.scratchspaces;
219 }; 227 };
220 "niri/window" = { 228 "niri/window" = {
221 separate-outputs = true; 229 separate-outputs = true;
@@ -241,7 +249,7 @@
241 249
242 * { 250 * {
243 border: none; 251 border: none;
244 font-family: "Fira Sans Nerd Font"; 252 font-family: "Fira Sans";
245 font-size: 10pt; 253 font-size: 10pt;
246 min-height: 0; 254 min-height: 0;
247 } 255 }
@@ -252,10 +260,10 @@
252 } 260 }
253 261
254 .modules-left { 262 .modules-left {
255 margin-left: 8px; 263 margin-left: 38px;
256 } 264 }
257 .modules-right { 265 .modules-right {
258 margin-right: 8px; 266 margin-right: 38px;
259 } 267 }
260 268
261 .module { 269 .module {
@@ -280,17 +288,18 @@
280 color: @grey; 288 color: @grey;
281 margin: 0 5px; 289 margin: 0 5px;
282 } 290 }
283 #custom-weather, #custom-worktime-today { 291 #custom-weather {
284 margin-right: 3px; 292 margin-right: 3px;
285 } 293 }
286 #custom-keymap, #custom-weather { 294 #custom-keymap {
287 margin-left: 3px; 295 margin-left: 3px;
296 margin-right: 3px;
288 } 297 }
289 298
290 #tray { 299 #tray {
291 margin: 0; 300 margin: 0;
292 } 301 }
293 #battery, #idle_inhibitor, #backlight, #wireplumber, #custom-mako { 302 #battery, #idle_inhibitor, #backlight, #wireplumber, #custom-mako, #custom-lid_inhibitor {
294 color: @grey; 303 color: @grey;
295 margin: 0 5px 0 2px; 304 margin: 0 5px 0 2px;
296 } 305 }
@@ -299,7 +308,11 @@
299 margin-left: 6px; 308 margin-left: 6px;
300 } 309 }
301 #custom-mako { 310 #custom-mako {
302 margin-right: 2px; 311 margin-right: 4px;
312 margin-left: 3px;
313 }
314 #custom-lid_inhibitor {
315 margin-right: 3px;
303 margin-left: 3px; 316 margin-left: 3px;
304 } 317 }
305 #battery { 318 #battery {
@@ -320,17 +333,24 @@
320 #idle_inhibitor.activated { 333 #idle_inhibitor.activated {
321 color: @white; 334 color: @white;
322 } 335 }
336 #custom-worktime.running, #custom-worktime-today.running {
337 color: @white;
338 }
339 #custom-worktime.over, #custom-worktime-today.over {
340 color: @orange;
341 }
323 342
324 #idle_inhibitor { 343 #idle_inhibitor, #custom-lid_inhibitor {
325 padding-top: 1px; 344 padding-top: 1px;
326 } 345 }
327 346
328 #privacy { 347 #privacy {
329 color: @red; 348 color: @red;
330 margin: -1px 2px 0px 5px; 349 margin: -1px 4px 0px 3px;
331 } 350 }
332 #clock { 351 #clock {
333 /* margin-right: 5px; */ 352 /* margin-right: 5px; */
353 font-feature-settings: "tnum";
334 } 354 }
335 ''; 355 '';
336 }; 356 };
diff --git a/accounts/gkleen@sif/ssh-hosts.nix b/accounts/gkleen@sif/ssh-hosts.nix
index 107f1e76..a250509b 100644
--- a/accounts/gkleen@sif/ssh-hosts.nix
+++ b/accounts/gkleen@sif/ssh-hosts.nix
@@ -1,5 +1,12 @@
1{ pkgs, ... }: 1{ lib, pkgs, ... }:
2{ 2let
3 autosshProxyPorts = {
4 "ssh.math.lmu.de" = 8118;
5 "mathw0h" = 8122;
6 "mathw0e" = 8124;
7 };
8 autosshProxy = host: "${lib.getExe pkgs.socat} - SOCKS4A:127.0.0.1:%h:%p,socksport=${toString autosshProxyPorts.${host}}";
9in {
3 "git.ymir" = 10 "git.ymir" =
4 { hostname = "ymir.yggdrasil.li"; 11 { hostname = "ymir.yggdrasil.li";
5 user = "gitolite"; 12 user = "gitolite";
@@ -290,15 +297,15 @@
290 }; 297 };
291 "mathw0d" = 298 "mathw0d" =
292 { hostname = "mathw0d.mathinst.loc"; 299 { hostname = "mathw0d.mathinst.loc";
293 proxyJump = "mathw0h"; 300 proxyCommand = autosshProxy "mathw0h";
294 }; 301 };
295 "mathw0e" = 302 "mathw0e" =
296 { hostname = "mathw0e.mathinst.loc"; 303 { hostname = "mathw0e.mathinst.loc";
297 proxyJump = "mathw0h"; 304 proxyCommand = autosshProxy "mathw0h";
298 }; 305 };
299 "mathw0f" = 306 "mathw0f" =
300 { hostname = "mathw0f.mathinst.loc"; 307 { hostname = "mathw0f.mathinst.loc";
301 proxyJump = "mathw0h"; 308 proxyCommand = autosshProxy "mathw0h";
302 }; 309 };
303 "mathw0g" = 310 "mathw0g" =
304 { hostname = "mathw0g.mathinst.loc"; 311 { hostname = "mathw0g.mathinst.loc";
@@ -306,8 +313,8 @@
306 "mathw0h" = 313 "mathw0h" =
307 { hostname = "mathw0h.mathinst.loc"; 314 { hostname = "mathw0h.mathinst.loc";
308 }; 315 };
309 "proxy.mathw0g" = 316 "proxy.ssh.math.lmu.de" =
310 { hostname = "mathw0g.mathinst.loc"; 317 { hostname = "ssh.math.lmu.de";
311 extraOptions = { 318 extraOptions = {
312 ControlPath = "none"; 319 ControlPath = "none";
313 ExitOnForwardFailure = "yes"; 320 ExitOnForwardFailure = "yes";
@@ -317,7 +324,17 @@
317 }; 324 };
318 "proxy.mathw0h" = 325 "proxy.mathw0h" =
319 { hostname = "mathw0h.mathinst.loc"; 326 { hostname = "mathw0h.mathinst.loc";
320 proxyJump = "proxy.mathw0g"; 327 proxyCommand = autosshProxy "ssh.math.lmu.de";
328 extraOptions = {
329 ControlPath = "none";
330 ExitOnForwardFailure = "yes";
331 ServerAliveCountMax = "15";
332 ServerAliveInterval = "2";
333 };
334 };
335 "proxy.mathw0e" =
336 { hostname = "mathw0e.mathinst.loc";
337 proxyCommand = autosshProxy "mathw0h";
321 extraOptions = { 338 extraOptions = {
322 ControlPath = "none"; 339 ControlPath = "none";
323 ExitOnForwardFailure = "yes"; 340 ExitOnForwardFailure = "yes";
@@ -327,7 +344,7 @@
327 }; 344 };
328 "vrt-kvm06" = 345 "vrt-kvm06" =
329 { hostname = "vrt-kvm06"; 346 { hostname = "vrt-kvm06";
330 proxyJump = "mathw0e"; 347 proxyCommand = autosshProxy "mathw0e";
331 user = "root"; 348 user = "root";
332 extraOptions = { 349 extraOptions = {
333 PasswordAuthentication = "yes"; 350 PasswordAuthentication = "yes";
@@ -336,7 +353,7 @@
336 }; 353 };
337 "vrt-kvm05" = 354 "vrt-kvm05" =
338 { hostname = "vrt-kvm05"; 355 { hostname = "vrt-kvm05";
339 proxyJump = "mathw0e"; 356 proxyCommand = autosshProxy "mathw0e";
340 user = "root"; 357 user = "root";
341 extraOptions = { 358 extraOptions = {
342 PasswordAuthentication = "yes"; 359 PasswordAuthentication = "yes";
@@ -345,7 +362,7 @@
345 }; 362 };
346 "vrt-kvm04" = 363 "vrt-kvm04" =
347 { hostname = "vrt-kvm04"; 364 { hostname = "vrt-kvm04";
348 proxyJump = "mathw0e"; 365 proxyCommand = autosshProxy "mathw0e";
349 user = "root"; 366 user = "root";
350 extraOptions = { 367 extraOptions = {
351 PasswordAuthentication = "yes"; 368 PasswordAuthentication = "yes";
@@ -354,7 +371,7 @@
354 }; 371 };
355 "vrt-kvm02" = 372 "vrt-kvm02" =
356 { hostname = "vrt-kvm02"; 373 { hostname = "vrt-kvm02";
357 proxyJump = "mathw0e"; 374 proxyCommand = autosshProxy "mathw0e";
358 user = "root"; 375 user = "root";
359 extraOptions = { 376 extraOptions = {
360 PasswordAuthentication = "yes"; 377 PasswordAuthentication = "yes";
@@ -363,7 +380,7 @@
363 }; 380 };
364 "vrt-kvm03" = 381 "vrt-kvm03" =
365 { hostname = "vrt-kvm03"; 382 { hostname = "vrt-kvm03";
366 proxyJump = "mathw0e"; 383 proxyCommand = autosshProxy "mathw0e";
367 user = "root"; 384 user = "root";
368 extraOptions = { 385 extraOptions = {
369 PasswordAuthentication = "yes"; 386 PasswordAuthentication = "yes";
@@ -372,7 +389,7 @@
372 }; 389 };
373 "vrt-kvm01" = 390 "vrt-kvm01" =
374 { hostname = "vrt-kvm01"; 391 { hostname = "vrt-kvm01";
375 proxyJump = "mathw0e"; 392 proxyCommand = autosshProxy "mathw0e";
376 user = "root"; 393 user = "root";
377 extraOptions = { 394 extraOptions = {
378 PasswordAuthentication = "yes"; 395 PasswordAuthentication = "yes";
@@ -381,39 +398,44 @@
381 }; 398 };
382 "tts-www01" = 399 "tts-www01" =
383 { hostname = "tts-www01.mathinst.loc"; 400 { hostname = "tts-www01.mathinst.loc";
384 proxyJump = "mathw0h"; 401 proxyCommand = autosshProxy "mathw0h";
385 user = "root"; 402 user = "root";
386 }; 403 };
387 "vpn-wg01" = 404 "vpn-wg01" =
388 { hostname = "vpn-wg01.mathinst.loc"; 405 { hostname = "vpn-wg01.mathinst.loc";
389 proxyJump = "mathw0h"; 406 proxyCommand = autosshProxy "mathw0h";
390 user = "root"; 407 user = "root";
391 }; 408 };
392 "repo-apt01" = 409 "repo-apt01" =
393 { hostname = "repo-apt01.mathinst.loc"; 410 { hostname = "repo-apt01.mathinst.loc";
394 proxyJump = "mathw0h"; 411 proxyCommand = autosshProxy "mathw0h";
395 user = "root"; 412 user = "root";
396 }; 413 };
397 "ldap-lmumr01" = 414 "ldap-lmumr01" =
398 { hostname = "ldap-lmumr01.mathinst.loc"; 415 { hostname = "ldap-lmumr01.mathinst.loc";
399 proxyJump = "mathw0h"; 416 proxyCommand = autosshProxy "mathw0h";
400 user = "root"; 417 user = "root";
401 }; 418 };
402 "mail-mi01" = 419 "mail-mi01" =
403 { hostname = "mail-mi01.mathinst.loc"; 420 { hostname = "mail-mi01.mathinst.loc";
404 proxyJump = "mathw0h"; 421 proxyCommand = autosshProxy "mathw0h";
405 }; 422 };
406 "mail-www02" = 423 "mail-www02" =
407 { hostname = "mail-www02.mathinst.loc"; 424 { hostname = "mail-www02.mathinst.loc";
408 proxyJump = "mathw0h"; 425 proxyCommand = autosshProxy "mathw0h";
409 }; 426 };
410 "dpl-fai01" = 427 "dpl-fai01" =
411 { hostname = "dpl-fai01.mathinst.loc"; 428 { hostname = "dpl-fai01.mathinst.loc";
412 user = "root"; 429 user = "root";
413 }; 430 };
431 "dpl-fai02" =
432 { hostname = "dpl-fai02.mathinst.loc";
433 user = "root";
434 proxyJump = "mgmt01";
435 };
414 "math05" = 436 "math05" =
415 { hostname = "math05.mathinst.loc"; 437 { hostname = "math05.mathinst.loc";
416 proxyJump = "mathw0h"; 438 proxyCommand = autosshProxy "mathw0h";
417 extraOptions.KexAlgorithms = "+diffie-hellman-group1-sha1"; 439 extraOptions.KexAlgorithms = "+diffie-hellman-group1-sha1";
418 }; 440 };
419 "switch01" = 441 "switch01" =
@@ -439,20 +461,20 @@
439 }; 461 };
440 "www-mi01" = 462 "www-mi01" =
441 { hostname = "www-mi01.mathinst.loc"; 463 { hostname = "www-mi01.mathinst.loc";
442 proxyJump = "mathw0h"; 464 proxyCommand = autosshProxy "mathw0h";
443 }; 465 };
444 "cip04" = 466 "cip04" =
445 { hostname = "cip04.cipmath.loc"; 467 { hostname = "cip04.cipmath.loc";
446 proxyJump = "mathw0h"; 468 proxyCommand = autosshProxy "mathw0h";
447 }; 469 };
448 "mgmt-cls01" = 470 "mgmt-cls01" =
449 { user = "root"; 471 { user = "root";
450 hostname = "mgmt-cls01.cipmath.loc"; 472 hostname = "mgmt-cls01.cipmath.loc";
451 proxyJump = "ssh.math.lmu.de"; 473 proxyCommand = autosshProxy "ssh.math.lmu.de";
452 }; 474 };
453 "mgmt01" = 475 "mgmt01" =
454 { hostname = "mgmt01.mathinst.loc"; 476 { hostname = "mgmt01.mathinst.loc";
455 proxyJump = "mathw0h"; 477 proxyCommand = autosshProxy "mathw0h";
456 user = "root"; 478 user = "root";
457 }; 479 };
458 "ssh-lb01" = 480 "ssh-lb01" =
@@ -471,17 +493,17 @@
471 "rdlx02" = { hostname = "rdlx02.mathinst.loc"; proxyJump = "mgmt01"; }; 493 "rdlx02" = { hostname = "rdlx02.mathinst.loc"; proxyJump = "mgmt01"; };
472 "math0d" = 494 "math0d" =
473 { hostname = "math0d.mathinst.loc"; 495 { hostname = "math0d.mathinst.loc";
474 proxyJump = "mathw0h"; 496 proxyCommand = autosshProxy "mathw0h";
475 }; 497 };
476 "dhcp01" = 498 "dhcp01" =
477 { hostname = "dhcp01.mathinst.loc"; 499 { hostname = "dhcp01.mathinst.loc";
478 user = "root"; 500 user = "root";
479 proxyJump = "mathw0h"; 501 proxyCommand = autosshProxy "mathw0h";
480 }; 502 };
481 "dhcp02" = 503 "dhcp02" =
482 { hostname = "dhcp02.mathinst.loc"; 504 { hostname = "dhcp02.mathinst.loc";
483 user = "root"; 505 user = "root";
484 proxyJump = "mathw0h"; 506 proxyCommand = autosshProxy "mathw0h";
485 }; 507 };
486 "cc-gpu-l01" = 508 "cc-gpu-l01" =
487 { hostname = "cc-gpu-l01.mathinst.loc"; 509 { hostname = "cc-gpu-l01.mathinst.loc";
@@ -546,7 +568,7 @@
546 user = "root"; 568 user = "root";
547 }; 569 };
548 "nas*" = 570 "nas*" =
549 { proxyJump = "mathw0e"; 571 { proxyCommand = autosshProxy "mathw0e";
550 user = "admin"; 572 user = "admin";
551 extraOptions = { 573 extraOptions = {
552 PasswordAuthentication = "yes"; 574 PasswordAuthentication = "yes";
@@ -554,9 +576,4 @@
554 HostKeyAlgorithms = "+ecdsa-sha2-nistp256"; 576 HostKeyAlgorithms = "+ecdsa-sha2-nistp256";
555 }; 577 };
556 }; 578 };
557 "game01" =
558 { hostname = "game01.yggdrasil.li";
559 user = "factorio";
560 identityFile = "~/.ssh/gkleen@sif.midgard.yggdrasil";
561 };
562} 579}
diff --git a/accounts/gkleen@sif/synadm/default.nix b/accounts/gkleen@sif/synadm/default.nix
new file mode 100644
index 00000000..0a8e0d4c
--- /dev/null
+++ b/accounts/gkleen@sif/synadm/default.nix
@@ -0,0 +1,9 @@
1{ config, pkgs, ... }:
2{
3 home.packages = with pkgs; [ synadm ];
4 sops.secrets."synadm.yaml" = {
5 format = "binary";
6 sopsFile = ./synadm_yaml;
7 path = config.xdg.configHome + "/synadm.yaml";
8 };
9}
diff --git a/accounts/gkleen@sif/synadm/synadm_yaml b/accounts/gkleen@sif/synadm/synadm_yaml
new file mode 100644
index 00000000..8d951ccc
--- /dev/null
+++ b/accounts/gkleen@sif/synadm/synadm_yaml
@@ -0,0 +1,15 @@
1{
2 "data": "ENC[AES256_GCM,data:qJy4Pmbbxja4jmW7OaHsD0mQZ7anZwLhiVmAgkavb+CqwWGDnUBXdz22/MHCbxng5NshcFSpBoCBhgY6B9V2bUiES6bH9AtMlDcs9ebKGMArBTUTnQ2MjWQGfQTqraWdNgy+n327uj9swwCH8EZXdYH/Hlv0t/re470W+VOHeXhGghQ3Y9IGz2sgfvMGr8QxaJNydZz85rgs5QUP/PglCwWIOw2mY1EX2vYwnmiAo49LmIEaxWvRi++KHaeBveDt0nlkJwzUlipL2VOKWxkgpK3yGucQn2mz+FRe1btp+4KGm8H17eUI9FO9sBwq,iv:kgM921ovwCgDYHQj3c5Rupy/8JxHehxUD2jb1k9Ik2Y=,tag:3TLQkJbv679VWy8V2TMugw==,type:str]",
3 "sops": {
4 "age": [
5 {
6 "recipient": "age1rmmhetcmllq0ahl5qznlr0eya2zdxwl9h6y5wnl97d2wtyx5t99sm2u866",
7 "enc": "-----BEGIN AGE ENCRYPTED FILE-----\nYWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSB6bzVHUGNxZTF2WC9MYmZr\neGdVVzJXN3lGdEk3cTBER3J6UTFtcUJna2d3CjdNQmRXd2haZW1MYlJzNkk1dWVD\nVTFQc2gvS0JrejJ6SFh2MXpPWDZpRE0KLS0tIE0wTC85bEpvSnlGdGFkZVFhNjFZ\nbzRiZkxMWUg2ODNVUlBmNFlPNGRrZlkK1VXLJWcssv3ETyZSSM/Hhn5VIaI9iov9\nzShZA9Zx/FX6PYTuUMC29pJ57gKourcIxa/7HwSv/xYn1A6WcYfgSg==\n-----END AGE ENCRYPTED FILE-----\n"
8 }
9 ],
10 "lastmodified": "2025-05-18T11:03:42Z",
11 "mac": "ENC[AES256_GCM,data:yonJC68PhilAgEHNNJQ8nO53Qo3rx/LnfiOWfuMm24bOUIH9QM3WZZxpigd7bHI4eC4TqRb4LvcSi0nEURTRAhwiTqGNrWbpw2Iv3n5dhLEN9aTcetG5ZuhaXqfVUoML45/ovdBZG/0l8+XIHqxN2M/g/h4JwKoR/6lqzcrVhgo=,iv:xvxBJwy+E5zUdjhGPdZPdy7tnBIEj50hfiDJFsS3wNg=,tag:L4Fas36ZOg4h0QQwC4gjNA==,type:str]",
12 "unencrypted_suffix": "_unencrypted",
13 "version": "3.10.2"
14 }
15}
diff --git a/accounts/gkleen@sif/systemd.nix b/accounts/gkleen@sif/systemd.nix
index d3a1a4c7..18c2315f 100644
--- a/accounts/gkleen@sif/systemd.nix
+++ b/accounts/gkleen@sif/systemd.nix
@@ -6,7 +6,7 @@ let
6 cfg = config.home-manager.users.${userName}; 6 cfg = config.home-manager.users.${userName};
7 7
8 autossh-socks-script = pkgs.writeScript "autossh" '' 8 autossh-socks-script = pkgs.writeScript "autossh" ''
9 #!${pkgs.zsh}/bin/zsh -xe 9 #!${lib.getExe pkgs.zsh} -xe
10 10
11 host="''${1%:*}" 11 host="''${1%:*}"
12 port="''${1#*:}" 12 port="''${1#*:}"
@@ -15,31 +15,29 @@ let
15 cmd=() 15 cmd=()
16 16
17 if [[ -n "''${SSHPASS_SECRET}" ]]; then 17 if [[ -n "''${SSHPASS_SECRET}" ]]; then
18 cmd+=(${pkgs.sshpassSecret}/bin/sshpass-secret) 18 cmd+=(${lib.getExe' pkgs.sshpassSecret "sshpass-secret"})
19 cmd+=("''${(@s/:/)SSHPASS_SECRET}") 19 cmd+=("''${(@s/:/)SSHPASS_SECRET}")
20 cmd+=(--) 20 cmd+=(--)
21 fi 21 fi
22 22
23 cmd+=(${pkgs.openssh}/bin/ssh -vN -D localhost:''${port} "''${host}") 23 cmd+=(${lib.getExe' pkgs.openssh "ssh"} -vN -D 127.0.0.1:''${port} "''${host}")
24 24
25 ( exec -a "''${cmd[1]}" -- ''${cmd} ) & 25 ( exec -a "''${cmd[1]}" -- ''${cmd} ) &
26 pid=$! 26 pid=$!
27 27
28 newpid="" 28 newpid=""
29 i=200 29 i=200
30 while ! newpid=$(${pkgs.lsof}/bin/lsof -Pi @localhost:"''${port}" -sTCP:LISTEN -t); do 30 while ! newpid=$(${lib.getExe pkgs.lsof} -Pi @localhost:"''${port}" -sTCP:LISTEN -t); do
31 if ! kill -0 "''${pid}"; then 31 if ! kill -0 "''${pid}"; then
32 wait "''${pid}" 32 wait "''${pid}"
33 exit $? 33 exit $?
34 fi 34 fi
35 [[ "''${i}" -gt 0 ]] || exit 1 35 [[ "''${i}" -gt 0 ]] || exit 1
36 i=$((''${i} - 1)) 36 i=$((''${i} - 1))
37 ${pkgs.coreutils}/bin/sleep 0.1 37 ${lib.getExe' pkgs.coreutils "sleep"} 0.1
38 done 38 done
39 39
40 ${config.systemd.package}/bin/systemd-notify --ready 40 ${lib.getExe' config.systemd.package "systemd-notify"} --pid=''${newpid} --ready
41
42 wait "''${pid}" "''${newpid}"
43 ''; 41 '';
44in { 42in {
45 tmpfiles.rules = [ 43 tmpfiles.rules = [
@@ -48,11 +46,11 @@ in {
48 ]; 46 ];
49 47
50 services = { 48 services = {
51 sync-keepass = { 49 "sync-keepass@" = {
52 Service = { 50 Service = {
53 Type = "oneshot"; 51 Type = "oneshot";
54 WorkingDirectory = "~"; 52 WorkingDirectory = "~";
55 ExecStart = toString (pkgs.writers.writePython3 "sync-keepass" { 53 ExecStart = "${pkgs.writers.writePython3 "sync-keepass" {
56 libraries = with pkgs.python3Packages; [ python-dateutil ]; 54 libraries = with pkgs.python3Packages; [ python-dateutil ];
57 } '' 55 } ''
58 import json 56 import json
@@ -61,13 +59,13 @@ in {
61 from datetime import datetime 59 from datetime import datetime
62 from dateutil.tz import tzlocal 60 from dateutil.tz import tzlocal
63 from dateutil.parser import isoparse 61 from dateutil.parser import isoparse
64 from sys import stderr 62 from sys import stderr, argv
65 63
66 64
67 remote_fs = 'surtr' 65 remote_fs = 'surtr' if argv[1] == 'store.kdbx' else 'mathcloud'
68 remote_file = 'store.kdbx' 66 remote_file = argv[1]
69 target_file = expanduser('~/store.kdbx') 67 target_file = expanduser(f'~/{argv[1]}')
70 meta_file = expanduser('~/.store.kdbx.json') 68 meta_file = expanduser(f'~/.{argv[1]}.json')
71 69
72 upload_time = None 70 upload_time = None
73 our_last_upload_time = None 71 our_last_upload_time = None
@@ -117,7 +115,7 @@ in {
117 do_upload() 115 do_upload()
118 elif upload_time is not None and (mod_time is None or upload_time > mod_time) and (our_last_upload_time is None or upload_time > our_last_upload_time): # noqa: E501 116 elif upload_time is not None and (mod_time is None or upload_time > mod_time) and (our_last_upload_time is None or upload_time > our_last_upload_time): # noqa: E501
119 do_download() 117 do_download()
120 ''); 118 ''} \"%I\"";
121 Environment = [ "RCLONE_PASSWORD_COMMAND=\"${pkgs.coreutils}/bin/cat ${config.sops.secrets.gkleen-rclone.path}\"" "PATH=${pkgs.rclone}/bin" ]; 119 Environment = [ "RCLONE_PASSWORD_COMMAND=\"${pkgs.coreutils}/bin/cat ${config.sops.secrets.gkleen-rclone.path}\"" "PATH=${pkgs.rclone}/bin" ];
122 }; 120 };
123 }; 121 };
@@ -146,7 +144,7 @@ in {
146 Service.ExecStart = "${pkgs.bluez}/bin/mpris-proxy"; 144 Service.ExecStart = "${pkgs.bluez}/bin/mpris-proxy";
147 Install.WantedBy = [ "default.target" ]; 145 Install.WantedBy = [ "default.target" ];
148 }; 146 };
149 "autossh-socks@proxy.mathw0h:8119" = { 147 "autossh-socks@proxy.ssh.math.lmu.de:8119" = {
150 Service = { 148 Service = {
151 Type = "notify"; 149 Type = "notify";
152 NotifyAccess = "all"; 150 NotifyAccess = "all";
@@ -154,7 +152,7 @@ in {
154 Restart = "always"; 152 Restart = "always";
155 RestartSec = "23s"; 153 RestartSec = "23s";
156 ExecStart = "${autossh-socks-script} \"%I\""; 154 ExecStart = "${autossh-socks-script} \"%I\"";
157 Environment = [ "SSHPASS_SECRET=gkleen@mathw0g.math.lmu.de" ]; 155 Environment = [ "SSHPASS_SECRET=gkleen@ssh.math.lmu.de" ];
158 }; 156 };
159 Unit = { 157 Unit = {
160 StopWhenUnneeded = true; 158 StopWhenUnneeded = true;
@@ -175,6 +173,38 @@ in {
175 StopWhenUnneeded = true; 173 StopWhenUnneeded = true;
176 }; 174 };
177 }; 175 };
176 "autossh-socks@proxy.mathw0h:8123" = {
177 Service = {
178 Type = "notify";
179 NotifyAccess = "all";
180 WorkingDirectory = "~";
181 Restart = "always";
182 RestartSec = "23s";
183 ExecStart = "${autossh-socks-script} \"%I\"";
184 Environment = [ "SSHPASS_SECRET=gkleen@mathw0h.mathinst.loc" ];
185 };
186 Unit = {
187 StopWhenUnneeded = true;
188 StartLimitInterval = "180s";
189 StartLimitBurst = 7;
190 };
191 };
192 "autossh-socks@proxy.mathw0e:8125" = {
193 Service = {
194 Type = "notify";
195 NotifyAccess = "all";
196 WorkingDirectory = "~";
197 Restart = "always";
198 RestartSec = "23s";
199 ExecStart = "${autossh-socks-script} \"%I\"";
200 Environment = [ "SSHPASS_SECRET=gkleen@mathw0e.mathinst.loc" ];
201 };
202 Unit = {
203 StopWhenUnneeded = true;
204 StartLimitInterval = "180s";
205 StartLimitBurst = 7;
206 };
207 };
178 swayidle = { 208 swayidle = {
179 Service = { 209 Service = {
180 RuntimeDirectory = "swayidle"; 210 RuntimeDirectory = "swayidle";
@@ -212,7 +242,7 @@ in {
212 "-${lib.getExe pkgs.playerctl} -a pause" 242 "-${lib.getExe pkgs.playerctl} -a pause"
213 "-${lib.getExe (pkgs.writeShellApplication { 243 "-${lib.getExe (pkgs.writeShellApplication {
214 name = "generate-css"; 244 name = "generate-css";
215 runtimeInputs = with pkgs; [cfg.programs.wpaperd.package jq coreutils imagemagick findutils]; 245 runtimeInputs = with pkgs; [cfg.services.wpaperd.package jq coreutils imagemagick findutils];
216 text = '' 246 text = ''
217 declare -A monitors 247 declare -A monitors
218 monitors=() 248 monitors=()
@@ -303,21 +333,21 @@ in {
303 ExecStopPost = "${pkgs.coreutils}/bin/rm -rfv \"$CACHE_DIRECTORY\""; 333 ExecStopPost = "${pkgs.coreutils}/bin/rm -rfv \"$CACHE_DIRECTORY\"";
304 }; 334 };
305 }; 335 };
306 wpaperd = { 336 # wpaperd = {
307 Install = { 337 # Install = {
308 WantedBy = ["graphical-session.target"]; 338 # WantedBy = ["graphical-session.target"];
309 }; 339 # };
310 Unit = { 340 # Unit = {
311 After = [ "graphical-session.target" ]; 341 # After = [ "graphical-session.target" ];
312 PartOf = [ "graphical-session.target" ]; 342 # PartOf = [ "graphical-session.target" ];
313 }; 343 # };
314 Service = { 344 # Service = {
315 ExecStart = lib.getExe cfg.programs.wpaperd.package; 345 # ExecStart = lib.getExe cfg.services.wpaperd.package;
316 Type = "simple"; 346 # Type = "simple";
317 Restart = "always"; 347 # Restart = "always";
318 RestartSec = "2s"; 348 # RestartSec = "2s";
319 }; 349 # };
320 }; 350 # };
321 xembed-sni-proxy = { 351 xembed-sni-proxy = {
322 Unit = { 352 Unit = {
323 PartOf = lib.mkForce ["tray.target"]; 353 PartOf = lib.mkForce ["tray.target"];
@@ -344,16 +374,21 @@ in {
344 Unit = { 374 Unit = {
345 PartOf = lib.mkForce ["tray.target"]; 375 PartOf = lib.mkForce ["tray.target"];
346 }; 376 };
377 Install = {
378 WantedBy = lib.mkForce ["tray.target"];
379 };
347 }; 380 };
348 } // listToAttrs (map ({host, port}: nameValuePair "proxy-to-autossh-socks@${toString port}" { 381 } // listToAttrs (map ({host, port}: nameValuePair "proxy-to-autossh-socks@${toString port}" {
349 Unit = { 382 Unit = {
350 Requires = ["autossh-socks@${host}:${toString (port + 1)}.service" "proxy-to-autossh-socks@${toString port}.socket"]; 383 BindsTo = ["autossh-socks@${host}:${toString (port + 1)}.service" "proxy-to-autossh-socks@${toString port}.socket"];
351 After = ["autossh-socks@${host}:${toString (port + 1)}.service" "proxy-to-autossh-socks@${toString port}.socket"]; 384 After = ["autossh-socks@${host}:${toString (port + 1)}.service" "proxy-to-autossh-socks@${toString port}.socket"];
352 }; 385 };
353 Service = { 386 Service = {
354 ExecStart = "${config.systemd.package}/lib/systemd/systemd-socket-proxyd --exit-idle-time=10s localhost:${toString (port + 1)}"; 387 ExecStart = "${config.systemd.package}/lib/systemd/systemd-socket-proxyd --exit-idle-time=60s 127.0.0.1:${toString (port + 1)}";
388 Restart = "always";
389 RestartSec = "23s";
355 }; 390 };
356 }) [{ host = "proxy.mathw0h"; port = 8118; } { host = "proxy.vidhar"; port = 8120; }]); 391 }) [{ host = "proxy.ssh.math.lmu.de"; port = 8118; } { host = "proxy.vidhar"; port = 8120; } { host = "proxy.mathw0h"; port = 8122; } { host = "proxy.mathw0e"; port = 8124; }]);
357 sockets = listToAttrs (map (port: nameValuePair "proxy-to-autossh-socks@${toString port}" { 392 sockets = listToAttrs (map (port: nameValuePair "proxy-to-autossh-socks@${toString port}" {
358 Socket = { 393 Socket = {
359 ListenStream = "%I"; 394 ListenStream = "%I";
@@ -361,7 +396,7 @@ in {
361 Install = { 396 Install = {
362 WantedBy = ["default.target"]; 397 WantedBy = ["default.target"];
363 }; 398 };
364 }) [8118 8120]) // { 399 }) [8118 8120 8122 8124]) // {
365 "yt-dlp" = { 400 "yt-dlp" = {
366 Socket = { 401 Socket = {
367 SocketMode = "0600"; 402 SocketMode = "0600";
@@ -375,7 +410,7 @@ in {
375 }; 410 };
376 }; 411 };
377 timers = { 412 timers = {
378 sync-keepass = { 413 "sync-keepass@store.kdbx" = {
379 Timer = { 414 Timer = {
380 OnActiveSec = "1m"; 415 OnActiveSec = "1m";
381 OnUnitActiveSec = "1m"; 416 OnUnitActiveSec = "1m";
@@ -385,6 +420,16 @@ in {
385 WantedBy = ["default.target"]; 420 WantedBy = ["default.target"];
386 }; 421 };
387 }; 422 };
423 "sync-keepass@rz.kdbx" = {
424 Timer = {
425 OnActiveSec = "1d";
426 OnUnitActiveSec = "1d";
427 };
428
429 Install = {
430 WantedBy = ["default.target"];
431 };
432 };
388 }; 433 };
389 targets = { 434 targets = {
390 graphical-session = { 435 graphical-session = {
diff --git a/accounts/gkleen@sif/utils/async-yt-dlp.nix b/accounts/gkleen@sif/utils/async-yt-dlp.nix
new file mode 100644
index 00000000..c3b82ec5
--- /dev/null
+++ b/accounts/gkleen@sif/utils/async-yt-dlp.nix
@@ -0,0 +1,57 @@
1{ writers, python3Packages, ... }:
2
3writers.writePython3Bin "async-yt-dlp" {
4 libraries = with python3Packages; [ yt-dlp ];
5 flakeIgnore = ["E501"];
6} ''
7import sys
8import os
9
10import yt_dlp
11import yt_dlp.options
12from collections import namedtuple
13import socket
14from pathlib import Path
15import json
16
17create_parser = yt_dlp.options.create_parser
18
19
20def parse_patched_options(opts):
21 patched_parser = create_parser()
22 patched_parser.defaults.update({
23 'ignoreerrors': False,
24 'retries': 0,
25 'fragment_retries': 0,
26 'extract_flat': False,
27 'concat_playlist': 'never',
28 })
29 yt_dlp.options.create_parser = lambda: patched_parser
30 try:
31 return yt_dlp.parse_options(opts)
32 finally:
33 yt_dlp.options.create_parser = create_parser
34
35
36default_opts = parse_patched_options([]).ydl_opts
37
38
39def cli_to_api(opts):
40 opts = parse_patched_options(opts)
41 urls = opts.urls
42 opts = opts.ydl_opts
43
44 diff = {k: v for k, v in opts.items() if default_opts[k] != v}
45 if 'postprocessors' in diff:
46 diff['postprocessors'] = [pp for pp in diff['postprocessors']
47 if pp not in default_opts['postprocessors']]
48 return namedtuple('Options', ('params', 'urls'))(diff, urls)
49
50
51if __name__ == '__main__':
52 opts = cli_to_api(sys.argv[1:])
53 with socket.socket(socket.AF_UNIX, socket.SOCK_STREAM) as sock:
54 sock.connect(str(Path(os.environ["XDG_RUNTIME_DIR"]) / "yt-dlp.sock").encode('utf-8'))
55 with sock.makefile(mode='w', buffering=1, encoding='utf-8') as fh:
56 json.dump(opts._asdict(), fh)
57''
diff --git a/accounts/gkleen@sif/utils/pdf2pdf.nix b/accounts/gkleen@sif/utils/pdf2pdf.nix
new file mode 100644
index 00000000..9f4cbc3e
--- /dev/null
+++ b/accounts/gkleen@sif/utils/pdf2pdf.nix
@@ -0,0 +1,8 @@
1pkgs@{ lib, resholve, zsh, ghostscript_headless, ... }:
2
3resholve.writeScriptBin "pdf2pdf" {
4 inputs = with pkgs; [ghostscript_headless];
5 interpreter = lib.getExe zsh;
6} ''
7 exec gs -dPDFSETTINGS=/prepress -dNOPAUSE -dBATCH -sDEVICE=pdfwrite -dSAFER -dPreserveAnnots=false "-sOutputFile=''${2}" "''${1}"
8''
diff --git a/accounts/gkleen@sif/utils/sieve-edit.nix b/accounts/gkleen@sif/utils/sieve-edit.nix
new file mode 100644
index 00000000..f985a3f6
--- /dev/null
+++ b/accounts/gkleen@sif/utils/sieve-edit.nix
@@ -0,0 +1,24 @@
1pkgs@{ lib, resholve, zsh, sieve-connect, sops, ... }:
2
3resholve.writeScriptBin "sieve-edit" {
4 inputs = with pkgs; [sieve-connect sops];
5 interpreter = lib.getExe zsh;
6 execer = with pkgs; [
7 "cannot:${lib.getExe sieve-connect}"
8 "cannot:${lib.getExe sops}"
9 ];
10} ''
11 host=$1; shift
12 case "$host" in
13 surtr)
14 sieve-connect -s surtr.yggdrasil.li -m EXTERNAL --clientkey <(sops decrypt $HOME/projects/machines/hosts/surtr/email/ca/gkleen@sif.key) --clientcert $HOME/projects/machines/hosts/surtr/email/ca/gkleen@sif.crt --edit --remotesieve sieve
15 ;;
16 ymir)
17 sieve-connect -s ymir.yggdrasil.li -u gkleen --edit --remotesieve sieve
18 ;;
19 *)
20 echo "Unknown host: ‘$host’" >&2
21 return 2
22 ;;
23 esac
24''
diff --git a/accounts/gkleen@sif/zshrc b/accounts/gkleen@sif/zshrc
index e3f675a1..702990c3 100644
--- a/accounts/gkleen@sif/zshrc
+++ b/accounts/gkleen@sif/zshrc
@@ -2,17 +2,14 @@ dir() {
2 curlArchive=false 2 curlArchive=false
3 templateArchive="" 3 templateArchive=""
4 repoUrl="" 4 repoUrl=""
5 nixShell=""
6 findNix=false
7 dir="" 5 dir=""
8 forceShell=false 6 forceShell=false
9 wormhole=false 7 wormhole=false
10 gitWorktree="" 8 gitWorktree=""
11 # notmuchMsg=""
12 quickserve=false
13 modifyPDF="" 9 modifyPDF=""
10 miniserve=false
14 11
15 while getopts ':t:a:s:Sd:ir:wqg:p:' arg; do 12 while getopts ':t:a:d:ir:wg:p:m' arg; do
16 case $arg in 13 case $arg in
17 "t") ;; 14 "t") ;;
18 "a") 15 "a")
@@ -23,16 +20,13 @@ dir() {
23 templateArchive=${OPTARG:a} 20 templateArchive=${OPTARG:a}
24 fi 21 fi
25 ;; 22 ;;
26 "s") nixShell=${OPTARG:a} ;;
27 "S") findNix=true ;;
28 "d") dir=${OPTARG} ;; 23 "d") dir=${OPTARG} ;;
29 "i") forceShell=true ;; 24 "i") forceShell=true ;;
30 "r") repoUrl=${OPTARG} ;; 25 "r") repoUrl=${OPTARG} ;;
31 "w") wormhole=true ;; 26 "w") wormhole=true ;;
32 "g") gitWorktree=${OPTARG} ;; 27 "g") gitWorktree=${OPTARG} ;;
33 # "n") notmuchMsg=${OPTARG} ;;
34 "q") quickserve=true ;;
35 "p") modifyPDF=${OPTARG:a} ;; 28 "p") modifyPDF=${OPTARG:a} ;;
29 "m") miniserve=true ;;
36 *) printf "Invalid option: %s\n" $arg >&2; exit 2 ;; 30 *) printf "Invalid option: %s\n" $arg >&2; exit 2 ;;
37 esac 31 esac
38 done 32 done
@@ -56,20 +50,34 @@ dir() {
56 gitWorktree="" 50 gitWorktree=""
57 fi 51 fi
58 52
53 miniservePIDFile=""
54 if [[ ${miniserve} = "true" ]]; then
55 miniservePIDFile=$(mktemp --tmpdir --suffix=.pid)
56 fi
57
59 cleanup() 58 cleanup()
60 { 59 {
61 cd ${modifyPDF:h} 60 if [[ -n ${modifyPDF} ]]; then
62 [[ -n ${modifyPDF} ]] && nix shell nixos#imagemagick -c convert -verbose ${dir}/${modifyPDF:t:r}_*.png(on) ${modifyPDF} 61 cd ${modifyPDF:h}
62 typeset -a pages
63 eval 'pages=(${dir}/${modifyPDF:t:r}_*.png(on))'
64 magick -verbose "$pages" ${modifyPDF}
65 modifyPDF=""
66 fi
67 if [[ -n ${miniservePIDFile} ]]; then
68 command kill --verbose -- $(cat ${miniservePIDFile}) && wait $(cat ${miniservePIDFile})
69 miniservePIDFile=""
70 fi
63 } 71 }
64 72
65 ( 73 (
74 set -o localoptions -o localtraps
75 trap 'return 1' INT TERM
66 trap cleanup EXIT 76 trap cleanup EXIT
67 77
68 cd ${dir} 78 cd ${dir}
69 export dir; 79 export dir;
70 80
71 ${findNix} && { nixShell=$(findNix) || return $? }
72
73 [[ -n ${repoUrl} ]] && git clone -- ${repoUrl} . 81 [[ -n ${repoUrl} ]] && git clone -- ${repoUrl} .
74 82
75 [[ -n ${modifyPDF} ]] && templateArchive=${modifyPDF} 83 [[ -n ${modifyPDF} ]] && templateArchive=${modifyPDF}
@@ -82,23 +90,23 @@ dir() {
82 } 90 }
83 trap cleanup EXIT 91 trap cleanup EXIT
84 92
85 if ${curlArchive}; then 93 if [[ $curlArchive = "true" ]]; then
86 archiveFile=$(mktemp -t "archive.XXXXXXXXXX.${templateArchive:t}") 94 archiveFile=$(mktemp -t "archive.XXXXXXXXXX.${templateArchive:t}")
87 95
88 curl -L -o ${archiveFile} ${templateArchive} 96 curl -SfL -o ${archiveFile} ${templateArchive}
89 97
90 templateArchive=${archiveFile} 98 templateArchive=${archiveFile}
91 fi 99 fi
92 100
93 unpack=true 101 unpack=true
94 while ${unpack}; do 102 while [[ $unpack = "true" ]]; do
95 case $(file --brief --mime-type --dereference ${templateArchive}) in 103 case $(file --brief --mime-type --dereference ${templateArchive}) in
96 application/zip) 104 application/zip)
97 unzip ${templateArchive} 105 unzip ${templateArchive}
98 unpack=false 106 unpack=false
99 ;; 107 ;;
100 application/vnd.debian.binary-package) 108 application/vnd.debian.binary-package)
101 nix shell nixos#binutils --command ar x ${templateArchive} 109 ar x ${templateArchive}
102 mkdir control data 110 mkdir control data
103 tar -C control -xvaf control.* 111 tar -C control -xvaf control.*
104 tar -C data -xvaf data.* 112 tar -C data -xvaf data.*
@@ -106,7 +114,7 @@ dir() {
106 ;; 114 ;;
107 application/x-rpm) 115 application/x-rpm)
108 cpioArchive=$(mktemp -t "archive.XXXXXXXXXX.${templateArchive:t:r}.cpio") 116 cpioArchive=$(mktemp -t "archive.XXXXXXXXXX.${templateArchive:t:r}.cpio")
109 nix shell nixos#busybox --command rpm2cpio ${templateArchive} > ${cpioArchive} 117 rpm2cpio ${templateArchive} > ${cpioArchive}
110 templateArchive=${cpioArchive} 118 templateArchive=${cpioArchive}
111 unpack=true 119 unpack=true
112 ;; 120 ;;
@@ -115,15 +123,19 @@ dir() {
115 unpack=false 123 unpack=false
116 ;; 124 ;;
117 application/pdf) 125 application/pdf)
118 nix shell nixos#ghostscript nixos#imagemagick -c convert -verbose -density 400 ${templateArchive} ${modifyPDF:t:r}_%0d.png 126 magick -verbose -density 400 ${templateArchive} ${modifyPDF:t:r}_%0d.png
119 unpack=false 127 unpack=false
120 ;; 128 ;;
121 application/octet-stream) 129 application/octet-stream)
122 if [[ $(file --brief --dereferenc ${templateArchive}) =~ Squashfs ]]; then 130 if [[ $(file --brief --dereference ${templateArchive}) =~ Squashfs ]]; then
123 nix shell nixos#squashfsTools -c unsquashfs -d . ${templateArchive} 131 unsquashfs -d . ${templateArchive}
124 unpack=false 132 unpack=false
125 fi 133 fi
126 ;; 134 ;;
135 application/x-iso9660-image)
136 7z x ${templateArchive}
137 unpack=false
138 ;;
127 *) 139 *)
128 tar -xvaf ${templateArchive} 140 tar -xvaf ${templateArchive}
129 unpack=false 141 unpack=false
@@ -134,25 +146,21 @@ dir() {
134 fi 146 fi
135 147
136 148
137 ${wormhole} && wormhole receive --accept-file 149 [[ $wormhole = "true" ]] && wormhole receive --accept-file
138 150
139 151
140 if ${quickserve}; then 152 if [[ ${#@} -gt 0 ]]; then
141 quickserve --root . --upload . --show-hidden --tar gz 153 ${@}
142 fi 154 fi
143 155
156 cd $(pwd) # Needed for mounting to work
144 157
145 if [[ ${#@} -eq 0 ]] || ${forceShell}; then 158 if [[ ${miniserve} = "true" ]]; then
146 if [[ ${#@} -gt 0 ]]; then 159 miniserve --random-route --hidden --enable-tar-gz --enable-zip . &
147 if [[ -z ${nixShell} ]]; then 160 echo $! > "${miniservePIDFile}"
148 ${@} 161 fi
149 else
150 nix-shell ${nixShell} --run "${@}"
151 fi
152 fi
153
154 cd $(pwd) # Needed for mounting to work
155 162
163 if [[ ${#@} -eq 0 ]] && [[ ${miniserve} != "true" ]] || [[ $forceShell = "true" ]]; then
156 isSingleDir() { 164 isSingleDir() {
157 typeset -a contents 165 typeset -a contents
158 contents=(*(N) .*(N)) 166 contents=(*(N) .*(N))
@@ -166,18 +174,9 @@ dir() {
166 } 174 }
167 while d=$(isSingleDir); do cd ${d}; done 175 while d=$(isSingleDir); do cd ${d}; done
168 176
169 177 zsh
170 if [[ -z ${nixShell} ]]; then 178 elif [[ ${miniserve} == "true" ]]; then
171 zsh 179 wait $(cat "${miniservePIDFile}")
172 else
173 nix-shell ${nixShell} --run zsh
174 fi
175 else
176 if [[ -z ${nixShell} ]]; then
177 ${@}
178 else
179 nix-shell ${nixShell} --run "${@}"
180 fi
181 fi 180 fi
182 ) 181 )
183} 182}
@@ -185,27 +184,30 @@ dir() {
185tmpdir() { 184tmpdir() {
186 cleanup() 185 cleanup()
187 { 186 {
188 cd / 187 cd /
189 unmount() { 188 unmount() {
190 printf "Unmounting %s\n" ${1} >&2 189 printf "Unmounting %s\n" ${1} >&2
191 fusermount -u ${1} || umount ${1} || sudo umount ${1} 190 fusermount -u ${1} || umount ${1} || sudo umount ${1}
192 } 191 }
193 192
194 if mountpoint -q -- ${dir}; then 193 if [[ -n ${dir} ]]; then
195 unmount ${dir} || return $? 194 if mountpoint -q -- ${dir}; then
196 else 195 unmount ${dir} || return $?
197 while read -d $'\0' subDir; do 196 else
198 mountpoint -q -- ${subDir} || continue 197 while read -d $'\0' subDir; do
199 unmount ${subDir} || return $? 198 mountpoint -q -- ${subDir} || continue
200 done <<<$(find ${dir} -xdev -type d -print0 | sort -zr) 199 unmount ${subDir} || return $?
201 fi 200 done <<<$(find ${dir} -xdev -type d -print0 | sort -zr)
202 201 fi
203 rm -rfv --one-file-system -- ${dir} 202
203 rm -rfv --one-file-system -- ${dir}
204 dir=""
205 fi
204 } 206 }
205 207
206 local tmpdir="" 208 local tmpdir=""
207 209
208 while getopts ':t:a:s:Sd:ir:wqg:p:' arg; do 210 while getopts ':t:a:d:ir:wg:p:m' arg; do
209 case $arg in 211 case $arg in
210 "t") tmpdir="=${OPTARG}" ;; 212 "t") tmpdir="=${OPTARG}" ;;
211 "?"|":") printf "Invalid option: %s\n" $arg >&2; exit 2 ;; 213 "?"|":") printf "Invalid option: %s\n" $arg >&2; exit 2 ;;
@@ -213,6 +215,8 @@ tmpdir() {
213 done 215 done
214 216
215 ( 217 (
218 set -o localoptions -o localtraps
219 trap 'return 1' INT TERM
216 trap cleanup EXIT 220 trap cleanup EXIT
217 221
218 222
@@ -231,17 +235,7 @@ clock() {
231} 235}
232 236
233public-ip() { 237public-ip() {
234 curl -s -H 'Accept: application/json' $@ ifconfig.co | jq -r '.ip' 238 curl -sSf -H 'Accept: application/json' $@ ifconfig.co | jq -r '.ip'
235}
236
237nix-ghci() {
238 pkgExpr=""
239 if [[ ${#@} -gt 0 ]]; then
240 pkgExpr="${1}"
241 shift
242 fi
243
244 nix-shell -p "with (import <nixpkgs> {}); pkgs.haskellPackages.ghcWithPackages (p: with p; [${pkgExpr}])" --run "ghci ${@}"
245} 239}
246 240
247swap() { 241swap() {
@@ -271,14 +265,6 @@ l() {
271 ls --long --binary --git --time-style=iso --header $@ 265 ls --long --binary --git --time-style=iso --header $@
272} 266}
273 267
274re() {
275 systemctl --restart $@
276}
277
278ure() {
279 systemctl --user --restart $@
280}
281
282ssh-installer() { 268ssh-installer() {
283 ssh -o UserKnownHostsFile=/dev/null -o StrictHostKeyChecking=no -o IdentityFile=~/.ssh/gkleen@sif.midgard.yggdrasil $@ 269 ssh -o UserKnownHostsFile=/dev/null -o StrictHostKeyChecking=no -o IdentityFile=~/.ssh/gkleen@sif.midgard.yggdrasil $@
284} 270}
@@ -306,20 +292,7 @@ done < <(find ~/projects ~/uni -regextype posix-extended -maxdepth 2 -type d -re
306 sed -zr 's|(.*/([0-9]{2}[ws])/(.+))|\1 \2 \3|' | \ 292 sed -zr 's|(.*/([0-9]{2}[ws])/(.+))|\1 \2 \3|' | \
307 sort -z -r -k2 | sort -z -s -k3 | uniq -z -f 2) 293 sort -z -r -k2 | sort -z -s -k3 | uniq -z -f 2)
308 294
309alias '..'='cd ..'
310alias rzadm=$'tmpdir -i sh -c \'mkdir adm; sshfs gkleen@mgmt01:/adm adm\'' 295alias rzadm=$'tmpdir -i sh -c \'mkdir adm; sshfs gkleen@mgmt01:/adm adm\''
311alias mathcloud=$'tmpdir -i rclone mount --daemon mathcloud:// .' 296alias mathcloud=$'tmpdir -i rclone mount --daemon mathcloud:// .'
312alias -g L='| less'
313alias -g S='&> /dev/null'
314alias -g G='| grep'
315alias -g B='&> /dev/null &'
316alias -g BB='&> /dev/null &!'
317 297
318export DEFAULT_USER=gkleen 298export DEFAULT_USER=gkleen
319
320bindkey -e
321bindkey ';5C' emacs-forward-word
322bindkey ';5D' emacs-backward-word
323bindkey '^[[1;5C' emacs-forward-word
324bindkey '^[[1;5D' emacs-backward-word
325bindkey '^H' backward-kill-word
diff --git a/accounts/gkleen@surtr.nix b/accounts/gkleen@surtr.nix
index 58c4f21d..8f678ac9 100644
--- a/accounts/gkleen@surtr.nix
+++ b/accounts/gkleen@surtr.nix
@@ -1,3 +1,7 @@
1{ userName, ... }: { 1{ flake, userName, ... }: {
2 home-manager.users.${userName}.home.stateVersion = "20.09"; 2 imports = with flake.nixosModules.userProfiles.${userName}; [
3 zsh tmux
4 ];
5
6 config.home-manager.users.${userName}.home.stateVersion = "20.09";
3} 7}
diff --git a/accounts/gkleen@vidhar.nix b/accounts/gkleen@vidhar.nix
index 8509c2f4..3a37c4bd 100644
--- a/accounts/gkleen@vidhar.nix
+++ b/accounts/gkleen@vidhar.nix
@@ -1,4 +1,8 @@
1{ flake, pkgs, userName, config, ... }: { 1{ flake, pkgs, userName, config, ... }: {
2 imports = with flake.nixosModules.userProfiles.${userName}; [
3 zsh tmux
4 ];
5
2 config = { 6 config = {
3 users.users.${userName} = { 7 users.users.${userName} = {
4 uid = 1000; 8 uid = 1000;
diff --git a/accounts/mherold@eostre.nix b/accounts/mherold@eostre.nix
index 51e4529a..0e2f37aa 100644
--- a/accounts/mherold@eostre.nix
+++ b/accounts/mherold@eostre.nix
@@ -7,9 +7,9 @@
7 home-manager.users.${userName} = { 7 home-manager.users.${userName} = {
8 home.stateVersion = "20.09"; 8 home.stateVersion = "20.09";
9 9
10 nixpkgs.config = { 10 # nixpkgs.config = {
11 allowUnfree = true; 11 # allowUnfree = true;
12 }; 12 # };
13 13
14 home.packages = with pkgs; [ 14 home.packages = with pkgs; [
15 thunderbird libreoffice element-desktop keepassxc vlc 15 thunderbird libreoffice element-desktop keepassxc vlc
diff --git a/accounts/root@installer.nix b/accounts/root@installer.nix
index c7a418f8..5fe1db38 100644
--- a/accounts/root@installer.nix
+++ b/accounts/root@installer.nix
@@ -1,7 +1,11 @@
1{ userName, ... }: 1{ flake, userName, ... }:
2 2
3{ 3{
4 home-manager.users.${userName} = { config, ... } : { 4 imports = with flake.nixosModules.userProfiles.${userName}; [
5 zsh tmux
6 ];
7
8 config.home-manager.users.${userName} = { config, ... } : {
5 home.stateVersion = config.home.version.release; 9 home.stateVersion = config.home.version.release;
6 }; 10 };
7} 11}
diff --git a/accounts/root@sif.nix b/accounts/root@sif.nix
index c9e129a0..bb816230 100644
--- a/accounts/root@sif.nix
+++ b/accounts/root@sif.nix
@@ -1,6 +1,10 @@
1{ userName, ... }: 1{ flake, userName, ... }:
2{ 2{
3 home-manager.users.${userName} = { 3 imports = with flake.nixosModules.userProfiles.${userName}; [
4 zsh tmux
5 ];
6
7 config.home-manager.users.${userName} = {
4 home.stateVersion = "20.09"; 8 home.stateVersion = "20.09";
5 9
6 programs.ssh.matchBlocks = { 10 programs.ssh.matchBlocks = {
diff --git a/accounts/root@surtr.nix b/accounts/root@surtr.nix
index 58c4f21d..8f678ac9 100644
--- a/accounts/root@surtr.nix
+++ b/accounts/root@surtr.nix
@@ -1,3 +1,7 @@
1{ userName, ... }: { 1{ flake, userName, ... }: {
2 home-manager.users.${userName}.home.stateVersion = "20.09"; 2 imports = with flake.nixosModules.userProfiles.${userName}; [
3 zsh tmux
4 ];
5
6 config.home-manager.users.${userName}.home.stateVersion = "20.09";
3} 7}
diff --git a/accounts/root@vidhar.nix b/accounts/root@vidhar.nix
index e82414a8..0fc56633 100644
--- a/accounts/root@vidhar.nix
+++ b/accounts/root@vidhar.nix
@@ -1,6 +1,11 @@
1{ config, userName, ... }: 1{ flake, config, userName, ... }:
2
2{ 3{
3 home-manager.users.${userName} = { 4 imports = with flake.nixosModules.userProfiles.${userName}; [
5 zsh tmux
6 ];
7
8 config.home-manager.users.${userName} = {
4 home.stateVersion = "20.09"; 9 home.stateVersion = "20.09";
5 10
6 programs.ssh.matchBlocks = { 11 programs.ssh.matchBlocks = {