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.nix233
-rw-r--r--accounts/gkleen@sif/emacs.el4
-rw-r--r--accounts/gkleen@sif/niri/default.nix242
-rw-r--r--accounts/gkleen@sif/niri/mako.nix56
-rw-r--r--accounts/gkleen@sif/niri/swayosd.nix7
-rw-r--r--accounts/gkleen@sif/niri/waybar.nix27
-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.nix32
-rw-r--r--accounts/gkleen@sif/utils/async-yt-dlp.nix57
-rw-r--r--accounts/gkleen@sif/utils/sieve-edit.nix24
-rw-r--r--accounts/gkleen@sif/zshrc132
-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
21 files changed, 684 insertions, 221 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 11f24f31..706eb241 100644
--- a/accounts/gkleen@sif/default.nix
+++ b/accounts/gkleen@sif/default.nix
@@ -50,9 +50,20 @@ let
50 }; 50 };
51 51
52 lockCommand = "${lib.getExe' config.systemd.package "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 };
53in { 64in {
54 imports = with flake.nixosModules.userProfiles.${userName}; [ 65 imports = with flake.nixosModules.userProfiles.${userName}; [
55 mpv yt-dlp (args: import ./xcompose.nix (inputs // args)) 66 zsh tmux mpv yt-dlp (args: import ./xcompose.nix (inputs // args))
56 ]; 67 ];
57 68
58 config = { 69 config = {
@@ -60,16 +71,17 @@ in {
60 imports = [ 71 imports = [
61 ./libvirt 72 ./libvirt
62 ./niri 73 ./niri
74 ./synadm
63 flakeInputs.nix-index-database.hmModules.nix-index 75 flakeInputs.nix-index-database.hmModules.nix-index
64 flakeInputs.impermanence.nixosModules.home-manager.impermanence 76 flakeInputs.impermanence.nixosModules.home-manager.impermanence
65 ]; 77 ];
66 78
67 home.stateVersion = "20.09"; 79 home.stateVersion = "20.09";
68 80
69 nixpkgs.config = { 81 # nixpkgs.config = {
70 allowUnfree = true; 82 # allowUnfree = true;
71 zathura.useMupdf = false; 83 # zathura.useMupdf = false;
72 }; 84 # };
73 85
74 nix.registry = { 86 nix.registry = {
75 "flk" = { 87 "flk" = {
@@ -175,13 +187,91 @@ in {
175 gpu-api = "vulkan"; 187 gpu-api = "vulkan";
176 }; 188 };
177 189
178 zsh.initExtra = '' 190 zsh.initContent = let
179 source ${./zshrc} 191 zshrc = pkgs.resholve.mkDerivation {
192 pname = "zshrc";
193 version = "0.0.0";
194
195 src = ./zshrc;
196
197 dontUnpack = true;
198 dontConfigure = true;
199 dontBuild = true;
200
201 installPhase = ''
202 mkdir -p $out/share
203 install "$src" $out/share/zshrc
204 '';
205
206 solutions = {
207 default = {
208 scripts = [ "share/zshrc" ];
209 interpreter = "none";
210 inputs = with pkgs; [
211 coreutils
212 rpm
213 binutils
214 squashfsTools
215 unzip
216 cfg.programs.git.package
217 magickWrapped
218 curl
219 file
220 gnutar
221 cpio
222 magic-wormhole
223 cfg.programs.zsh.package
224 fuse
225 util-linux
226 findutils
227 qrencode
228 tty-clock
229 cfg.programs.jq.package
230 eza
231 less
232 config.systemd.package
233 config.programs.ssh.package
234 gnused
235 miniserve
236 ];
237 execer = with pkgs; [
238 "cannot:${lib.getExe' rpm "rpm2cpio"}"
239 "cannot:${lib.getExe' squashfsTools "unsquashfs"}"
240 "cannot:${lib.getExe' unzip "unzip"}"
241 "cannot:${lib.getExe cfg.programs.git.package}"
242 "cannot:${lib.getExe cpio}"
243 "cannot:${lib.getExe' magic-wormhole "wormhole"}"
244 "cannot:${lib.getExe' fuse "fusermount"}"
245 "cannot:${lib.getExe less}"
246 "cannot:${lib.getExe' config.systemd.package "systemctl"}"
247 "cannot:${lib.getExe config.programs.ssh.package}"
248 ];
249 wrapper = with pkgs; [
250 "${lib.getExe' magickWrapped "magick"}:${lib.getExe' imagemagick "magick"}"
251 ];
252 fake = {
253 builtin = ["print"];
254 external = ["sudo" "umount"];
255 };
256 };
257 };
258 };
259 magickWrapped = pkgs.symlinkJoin {
260 inherit (pkgs.imagemagick) name;
261 paths = [ pkgs.imagemagick ];
262
263 buildInputs = with pkgs; [ makeWrapper ];
264 postBuild = ''
265 wrapProgram $out/bin/magick \
266 --prefix PATH : ${lib.makeBinPath (with pkgs; [ ghostscript ])}
267 '';
268 };
269 in ''
270 source ${zshrc}/share/zshrc
180 ''; 271 '';
181 zsh.dirHashes = let 272 zsh.dirHashes = let
182 flakeHashes = mapAttrs' (n: v: nameValuePair (inputNames.${n} or n) (toString v)) flakeInputs; 273 flakeHashes = mapAttrs' (n: v: nameValuePair (inputNames.${n} or n) (toString v)) flakeInputs;
183 inputNames = { 274 inputNames = {
184 "nixpkgs" = "nixos";
185 }; 275 };
186 in flakeHashes // { 276 in flakeHashes // {
187 u2w = "$HOME/projects/uni2work"; 277 u2w = "$HOME/projects/uni2work";
@@ -193,6 +283,16 @@ in {
193 pro = "$HOME/projects/pro"; 283 pro = "$HOME/projects/pro";
194 media = "$HOME/media"; 284 media = "$HOME/media";
195 }; 285 };
286 jq.colors = {
287 arrays = "1;37";
288 "false" = "0;37";
289 "null" = "2;37";
290 numbers = "0;37";
291 objectKeys = "1;34";
292 objects = "1;37";
293 strings = "0;32";
294 "true" = "0;37";
295 };
196 296
197 obs-studio = { 297 obs-studio = {
198 enable = true; 298 enable = true;
@@ -202,7 +302,7 @@ in {
202 gh = { 302 gh = {
203 enable = true; 303 enable = true;
204 settings = { 304 settings = {
205 editor = lib.getExe' config.home-manager.users.${userName}.programs.emacs.package "emacsclient"; 305 editor = lib.getExe' editor "emacsclient";
206 gitProtocol = "ssh"; 306 gitProtocol = "ssh";
207 }; 307 };
208 }; 308 };
@@ -228,16 +328,10 @@ in {
228 # notify_on_cmd_finish = "invisible 120"; 328 # notify_on_cmd_finish = "invisible 120";
229 }; 329 };
230 keybindings = { 330 keybindings = {
231 "kitty_mod+n" = "detach_window"; 331 "kitty_mod+n" = "new_os_window_with_cwd";
232 "kitty_mod+m" = "detach_window ask"; 332 "kitty_mod+m" = "detach_window ask";
233 }; 333 "kitty_mod+enter" = "new_window_with_cwd";
234 }; 334 "kitty_mod+t" = "new_tab_with_cwd";
235 wpaperd = {
236 enable = true;
237 settings.default = {
238 path = "~/.wallpapers";
239 duration = "15m";
240 mode = "center";
241 }; 335 };
242 }; 336 };
243 fuzzel = { 337 fuzzel = {
@@ -250,7 +344,7 @@ in {
250 font = "Fira Sans"; 344 font = "Fira Sans";
251 }; 345 };
252 colors = { 346 colors = {
253 background = "000000aa"; 347 background = "000000cc";
254 text = "cdd6f4ff"; 348 text = "cdd6f4ff";
255 match = "94e2d5ff"; 349 match = "94e2d5ff";
256 selection = "585b70ff"; 350 selection = "585b70ff";
@@ -267,15 +361,28 @@ in {
267 enable = true; 361 enable = true;
268 extraAbbreviations = ["i.A." "d.h." "D.h." "gdw."]; 362 extraAbbreviations = ["i.A." "d.h." "D.h." "gdw."];
269 }; 363 };
364 nushell = {
365 enable = true;
366 settings.show_banner = false;
367 };
368 fd.enable = true;
270 }; 369 };
271 370
272 services = { 371 services = {
372 wpaperd = {
373 enable = true;
374 settings.default = {
375 path = "~/.wallpapers";
376 duration = "15m";
377 mode = "center";
378 };
379 };
273 emacs = { 380 emacs = {
274 enable = true; 381 enable = true;
275 socketActivation.enable = true; 382 socketActivation.enable = true;
276 client = { 383 client = {
277 enable = true; 384 enable = true;
278 arguments = mkForce ["--reuse-frame" "--alternate-editor" "\"\""]; 385 arguments = mkForce ["--create-frame" "--alternate-editor" (lib.getExe cfg.services.emacs.package)];
279 }; 386 };
280 }; 387 };
281 gpg-agent = { 388 gpg-agent = {
@@ -384,6 +491,13 @@ in {
384 }; 491 };
385 }; 492 };
386 493
494 qt.kde.settings = {
495 kwalletrc = {
496 KSecretD.Enabled = false;
497 Wallet."Default Wallet" = "store";
498 };
499 };
500
387 xsession.preferStatusNotifierItems = true; 501 xsession.preferStatusNotifierItems = true;
388 502
389 xresources.properties = import ./xresources.nix; 503 xresources.properties = import ./xresources.nix;
@@ -392,20 +506,19 @@ in {
392 packages = with pkgs; [ 506 packages = with pkgs; [
393 fira fira-code pwvucontrol wrappedKeepassxc wl-clipboard-rs 507 fira fira-code pwvucontrol wrappedKeepassxc wl-clipboard-rs
394 mumble pulseaudio-ctl pamixer libnotify screen-message 508 mumble pulseaudio-ctl pamixer libnotify screen-message
395 wrappedYTMDesktop libsForQt5.qt5ct playerctl evince 509 wrappedYTMDesktop libsForQt5.qt5ct playerctl evince papers
396 thunderbird zoom-us xdg-desktop-portal steam steam-run 510 thunderbird zoom-us xdg-desktop-portal steam steam-run
397 wireshark virt-manager rclone cached-nix-shell worktime 511 wireshark virt-manager rclone cached-nix-shell worktime
398 fira-code-symbols libreoffice xournalpp google-chrome 512 fira-code-symbols libreoffice xournalpp google-chrome
399 nixos-shell virt-viewer freerdp gnome-icon-theme 513 nixos-shell virt-viewer freerdp gnome-icon-theme
400 paper-icon-theme sshpassSecret weechat element-desktop 514 paper-icon-theme sshpassSecret weechat element-desktop
401 flakeInputs.deploy-rs.packages.${config.nixpkgs.system}.deploy-rs 515 sieve-connect gimp3 inkscape udiskie glab nitrokey-app
402 sieve-connect gimp inkscape udiskie glab nitrokey-app
403 pynitrokey gtklock wlrctl remmina openscad spice-record 516 pynitrokey gtklock wlrctl remmina openscad spice-record
404 libguestfs-with-appliance nerd-fonts.fira-mono 517 libguestfs-with-appliance nerd-fonts.fira-mono
405 nerd-fonts.symbols-only nerd-fonts.fira-code powerline-fonts 518 nerd-fonts.symbols-only nerd-fonts.fira-code powerline-fonts
406 swtpm (hunspellWithDicts (with hunspellDicts; [en_GB-large de_DE])) 519 swtpm (hunspellWithDicts (with hunspellDicts; [en_GB-large de_DE]))
407 # synadm 520 libation libqalculate
408 ]; 521 ] ++ mapAttrsToList (_name: pkg: pkgs.callPackage pkg {}) (customUtils.nixImport { dir = ./utils; });
409 522
410 file = { 523 file = {
411 ".backup-munin".source = ./backup-patterns; 524 ".backup-munin".source = ./backup-patterns;
@@ -425,12 +538,9 @@ in {
425 QT_QPA_PLATFORMTHEME = "qt5ct"; 538 QT_QPA_PLATFORMTHEME = "qt5ct";
426 LIBVIRT_DEFAULT_URI = "qemu:///system"; 539 LIBVIRT_DEFAULT_URI = "qemu:///system";
427 STACK_XDG = 1; 540 STACK_XDG = 1;
428 EDITOR = pkgs.writeShellScript "editor" '' 541 EDITOR = lib.getExe' editor "emacsclient";
429 args=("--reuse-frame" "--alternate-editor" "")
430 args+=("$@")
431 exec -a emacsclient ${lib.getExe' cfg.services.emacs.package "emacsclient"} "''${args[@]}"
432 '';
433 RCLONE_PASSWORD_COMMAND = "${lib.getExe' pkgs.libsecret "secret-tool"} lookup service rclone"; 542 RCLONE_PASSWORD_COMMAND = "${lib.getExe' pkgs.libsecret "secret-tool"} lookup service rclone";
543 SYSTEMD_TINT_BACKGROUND = "false";
434 }; 544 };
435 545
436 extraProfileCommands = '' 546 extraProfileCommands = ''
@@ -467,9 +577,17 @@ in {
467 General = { 577 General = {
468 dot_as_separator = 0; 578 dot_as_separator = 0;
469 }; 579 };
580 Mode = {
581 calculate_as_you_type = 1;
582 };
470 }; 583 };
471 }; 584 };
472 "emacs/init.el".source = ./emacs.el; 585 "emacs/init.el".source = pkgs.substitute {
586 src = ./emacs.el;
587 substitutions = [
588 "--subst-var-by" "ksshaskpass" (lib.getExe pkgs.kdePackages.ksshaskpass)
589 ];
590 };
473 "systemd/user/xdg-desktop-portal.service.d/after-graphical-session.conf".text = '' 591 "systemd/user/xdg-desktop-portal.service.d/after-graphical-session.conf".text = ''
474 [Unit] 592 [Unit]
475 After=graphical-session.target 593 After=graphical-session.target
@@ -487,6 +605,8 @@ in {
487 xdg.dataFile = { 605 xdg.dataFile = {
488 "dbus-1/services/org.keepassxc.KeePassXC.service".source = "${wrappedKeepassxc}/share/dbus-1/services/org.keepassxc.KeePassXC.service"; 606 "dbus-1/services/org.keepassxc.KeePassXC.service".source = "${wrappedKeepassxc}/share/dbus-1/services/org.keepassxc.KeePassXC.service";
489 "dbus-1/services/org.freedesktop.secrets.service.service".source = "${wrappedKeepassxc}/share/dbus-1/services/org.freedesktop.secrets.service.service"; 607 "dbus-1/services/org.freedesktop.secrets.service.service".source = "${wrappedKeepassxc}/share/dbus-1/services/org.freedesktop.secrets.service.service";
608 "dbus-1/services/org.kde.kwalletd6.service".source = "${pkgs.kdePackages.kwallet}/share/dbus-1/services/org.kde.kwalletd6.service";
609 "dbus-1/services/org.kde.kwalletd5.service".source = "${pkgs.kdePackages.kwallet}/share/dbus-1/services/org.kde.kwalletd5.service";
490 "emoji-data/list.txt".source = pkgs.stdenv.mkDerivation { 610 "emoji-data/list.txt".source = pkgs.stdenv.mkDerivation {
491 inherit (sources.emoji-data) pname src; 611 inherit (sources.emoji-data) pname src;
492 version = lib.removePrefix "v" sources.emoji-data.version; 612 version = lib.removePrefix "v" sources.emoji-data.version;
@@ -574,10 +694,10 @@ in {
574 exec -- \ 694 exec -- \
575 ${lib.getExe' config.systemd.package "systemd-run"} --wait --user --slice-inherit \ 695 ${lib.getExe' config.systemd.package "systemd-run"} --wait --user --slice-inherit \
576 --property 'CPUAccounting=yes' --property 'CPUQuotaPeriodSec=50ms' \ 696 --property 'CPUAccounting=yes' --property 'CPUQuotaPeriodSec=50ms' \
577 --property 'Environment=DSCP=46' \ 697 -E DSCP=46 -E NIXOS_OZONE_WL \
578 -- ${lib.getExe pkgs.dscp} ${lib.getExe' pkgs.google-chrome "google-chrome-stable"} \ 698 -- ${lib.getExe pkgs.dscp} ${lib.getExe' pkgs.google-chrome "google-chrome-stable"} \
579 --class=Rainbow \ 699 --class=Rainbow \
580 --kiosk "https://web.openrainbow.com" \ 700 --app="https://web.openrainbow.com" \
581 --user-data-dir=''${HOME}/.config/google-chrome-rainbow 701 --user-data-dir=''${HOME}/.config/google-chrome-rainbow
582 ''); 702 '');
583 icon = pkgs.fetchurl { 703 icon = pkgs.fetchurl {
@@ -588,6 +708,53 @@ in {
588 StartupWMClass = "Rainbow"; 708 StartupWMClass = "Rainbow";
589 }; 709 };
590 }; 710 };
711 kimai = {
712 name = "Kimai";
713 exec = toString (pkgs.writeShellScript "kimai" ''
714 exec -- \
715 ${lib.getExe' pkgs.google-chrome "google-chrome-stable"} \
716 --class=Kimai \
717 --app="https://kimai.yggdrasil.li" \
718 --user-data-dir=''${HOME}/.config/google-chrome-kimai
719 '');
720 icon = pkgs.fetchurl {
721 url = "https://www.kimai.org/images/kimai_logo.png";
722 hash = "sha256-lnlOttzR2SwXA70R+egJUkeKr4U5V0avqTk8uX4bqfs=";
723 };
724 settings = {
725 StartupWMClass = "Kimai";
726 StartupNotify = "true";
727 };
728 };
729 audiobookshelf = {
730 name = "Audiobookshelf";
731 exec = toString (pkgs.writeShellScript "audiobookshelf" ''
732 exec -- \
733 ${lib.getExe' pkgs.google-chrome "google-chrome-stable"} \
734 --class=Audiobookshelf \
735 --app="https://audiobookshelf.yggdrasil.li" \
736 --user-data-dir=''${HOME}/.config/google-chrome-audiobookshelf
737 '');
738 icon = pkgs.fetchurl {
739 url = "https://www.audiobookshelf.org/Logo.png";
740 hash = "sha256-JGPk+WNT1C4DC4lSMb0K0YmAMT5LvmSOeO0QRzkc7Lk=";
741 };
742 settings = {
743 StartupWMClass = "Audiobookshelf";
744 StartupNotify = "true";
745 };
746 };
747 thunderbird-lmu = {
748 name = "Thunderbird (LMU)";
749 exec = "thunderbird --name thunderbird -P lmu %U";
750 icon = "thunderbird";
751 genericName = "Email Client";
752 categories = [ "Network" "Chat" "Email" "Feed" "GTK" "News" ];
753 settings = {
754 StartupWMClass = "thunderbird";
755 StartupNotify = "true";
756 };
757 };
591 }; 758 };
592 759
593 fonts = { 760 fonts = {
diff --git a/accounts/gkleen@sif/emacs.el b/accounts/gkleen@sif/emacs.el
index 5cee16b0..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)
@@ -254,3 +254,5 @@ necessarily running."
254(bind-key "C-x C-m" #'move-file) 254(bind-key "C-x C-m" #'move-file)
255 255
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)) 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/niri/default.nix b/accounts/gkleen@sif/niri/default.nix
index 216a98ea..8752f3e3 100644
--- a/accounts/gkleen@sif/niri/default.nix
+++ b/accounts/gkleen@sif/niri/default.nix
@@ -35,7 +35,11 @@ let
35 if jq -e '.is_focused' <<<"$window_json" >/dev/null; then 35 if jq -e '.is_focused' <<<"$window_json" >/dev/null; then
36 niri msg action focus-workspace-previous 36 niri msg action focus-workspace-previous
37 else 37 else
38 niri msg action focus-window --id "$(jq -r '.id' <<<"$window_json")" 38 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
39 niri msg action focus-workspace "$workspace_name"
40 else
41 niri msg action focus-window --id "$(jq -r '.id' <<<"$window_json")"
42 fi
39 fi 43 fi
40 exit 0 44 exit 0
41 fi 45 fi
@@ -45,7 +49,6 @@ let
45 ''; 49 '';
46 }; 50 };
47 focus-or-spawn-action = config.lib.niri.actions.spawn (lib.getExe focus_or_spawn); 51 focus-or-spawn-action = config.lib.niri.actions.spawn (lib.getExe focus_or_spawn);
48 focus-or-spawn-action-app_id = app_id: focus-or-spawn-action ''select(.app_id == "${app_id}")'';
49 52
50 with_adjacent_workspace = pkgs.writeShellApplication { 53 with_adjacent_workspace = pkgs.writeShellApplication {
51 name = "with-adjacent-workspace"; 54 name = "with-adjacent-workspace";
@@ -84,7 +87,7 @@ let
84 }; 87 };
85 with-adjacent-workspace-action = config.lib.niri.actions.spawn (lib.getExe with_adjacent_workspace) "^${lib.concatMapStringsSep "|" ({ name, ...}: name) cfg.scratchspaces}$"; 88 with-adjacent-workspace-action = config.lib.niri.actions.spawn (lib.getExe with_adjacent_workspace) "^${lib.concatMapStringsSep "|" ({ name, ...}: name) cfg.scratchspaces}$";
86 focus-adjacent-workspace = direction: with-adjacent-workspace-action direction ''{"Action":{"FocusWorkspace":{"reference":{"Id": .id}}}}''; 89 focus-adjacent-workspace = direction: with-adjacent-workspace-action direction ''{"Action":{"FocusWorkspace":{"reference":{"Id": .id}}}}'';
87 move-column-to-adjacent-workspace = direction: with-adjacent-workspace-action direction ''{"Action":{"MoveColumnToWorkspace":{"reference":{"Id": .id}}}}''; 90 move-column-to-adjacent-workspace = direction: with-adjacent-workspace-action direction ''{"Action":{"MoveColumnToWorkspace":{"reference":{"Id": .id}, "focus": true}}}'';
88 91
89 with_unnamed_workspace = pkgs.writeShellApplication { 92 with_unnamed_workspace = pkgs.writeShellApplication {
90 name = "with-unnamed-workspace"; 93 name = "with-unnamed-workspace";
@@ -131,7 +134,7 @@ let
131 134
132 windows_json="$(niri msg -j windows)" 135 windows_json="$(niri msg -j windows)"
133 active_workspace="$(jq -r '.[] | select(.is_focused) | .workspace_id' <<<"$windows_json")" 136 active_workspace="$(jq -r '.[] | select(.is_focused) | .workspace_id' <<<"$windows_json")"
134 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)" 137 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)"
135 # shellcheck disable=SC2016 138 # shellcheck disable=SC2016
136 window_json="$(gojq -rc --arg active_workspace "$active_workspace" --arg window_ix "$window_ix" 'map(select('"$window_select"')) | .[($window_ix | tonumber)]' <<<"$windows_json")" 139 window_json="$(gojq -rc --arg active_workspace "$active_workspace" --arg window_ix "$window_ix" 'map(select('"$window_select"')) | .[($window_ix | tonumber)]' <<<"$windows_json")"
137 140
@@ -141,6 +144,25 @@ let
141 ''; 144 '';
142 }; 145 };
143 with-select-window-action = config.lib.niri.actions.spawn (lib.getExe with_select_window); 146 with-select-window-action = config.lib.niri.actions.spawn (lib.getExe with_select_window);
147
148 with_predicate_window = pred: pkgs.writeShellApplication {
149 name = "with-predicate-window";
150 runtimeInputs = [ niri pkgs.gojq pkgs.socat ];
151 text = ''
152 action="$1"
153 shift
154
155 windows_json="$(niri msg -j windows)"
156 window_json="$(gojq -rc 'map(select(${pred})) | .[0]' <<<"$windows_json")"
157
158 [[ -z "$window_json" || $window_json = "null" ]] && exit 1
159
160 jq -c "$action" <<<"$window_json" | socat STDIO "$NIRI_SOCKET"
161 '';
162 };
163
164 with-urgent-window-action = config.lib.niri.actions.spawn (lib.getExe (with_predicate_window ".is_urgent"));
165 with-focused-window-action = config.lib.niri.actions.spawn (lib.getExe (with_predicate_window ".is_focused"));
144in { 166in {
145 imports = [ 167 imports = [
146 ./waybar.nix 168 ./waybar.nix
@@ -171,6 +193,17 @@ in {
171 type = lib.types.nullOr lib.types.str; 193 type = lib.types.nullOr lib.types.str;
172 default = null; 194 default = null;
173 }; 195 };
196 moveKey = lib.mkOption {
197 type = lib.types.nullOr lib.types.str;
198 default = let
199 keys = lib.splitString "+" config.key;
200 defMoveKey = lib.concatStringsSep "+" (lib.flatten [
201 (lib.take (lib.length keys - 1) keys)
202 ["Shift"]
203 (lib.takeEnd 1 keys)
204 ]);
205 in if config.key == null then null else defMoveKey;
206 };
174 spawn = lib.mkOption { 207 spawn = lib.mkOption {
175 type = lib.types.nullOr (lib.types.listOf lib.types.str); 208 type = lib.types.nullOr (lib.types.listOf lib.types.str);
176 default = null; 209 default = null;
@@ -245,11 +278,11 @@ in {
245 Service = { 278 Service = {
246 Type = "simple"; 279 Type = "simple";
247 Sockets = [ "niri-workspace-history.socket" ]; 280 Sockets = [ "niri-workspace-history.socket" ];
248 ExecStart = pkgs.writers.writePython3 "niri-workspace-history" {} '' 281 ExecStart = pkgs.writers.writePython3 "niri-workspace-history" { flakeIgnore = ["E501"]; } ''
249 import os 282 import os
250 import socket 283 import socket
251 import json 284 import json
252 import sys 285 # import sys
253 from collections import defaultdict 286 from collections import defaultdict
254 from threading import Thread, Lock 287 from threading import Thread, Lock
255 from socketserver import StreamRequestHandler, ThreadingTCPServer 288 from socketserver import StreamRequestHandler, ThreadingTCPServer
@@ -273,11 +306,9 @@ in {
273 workspaces = list() 306 workspaces = list()
274 307
275 def focus_workspace(output, workspace): 308 def focus_workspace(output, workspace):
276 global workspace_history, history_lock
277
278 with history_lock: 309 with history_lock:
279 workspace_history[output] = [workspace] + [ws for ws in workspace_history[output] if ws != workspace] # noqa: E501 310 workspace_history[output] = [workspace] + [ws for ws in workspace_history[output] if ws != workspace]
280 print(json.dumps(workspace_history), file=sys.stderr) 311 # print(json.dumps(workspace_history), file=sys.stderr)
281 312
282 sock = socket.socket(socket.AF_UNIX, socket.SOCK_STREAM) 313 sock = socket.socket(socket.AF_UNIX, socket.SOCK_STREAM)
283 sock.connect(os.environ["NIRI_SOCKET"]) 314 sock.connect(os.environ["NIRI_SOCKET"])
@@ -299,16 +330,14 @@ in {
299 330
300 class RequestHandler(StreamRequestHandler): 331 class RequestHandler(StreamRequestHandler):
301 def handle(self): 332 def handle(self):
302 global workspace_history, history_lock 333 with detaching(TextIOWrapper(self.wfile, encoding='utf-8', write_through=True)) as out:
303
304 with detaching(TextIOWrapper(self.wfile, encoding='utf-8', write_through=True)) as out: # noqa: E501
305 with history_lock: 334 with history_lock:
306 json.dump(workspace_history, out) 335 json.dump(workspace_history, out)
307 336
308 337
309 class Server(ThreadingTCPServer): 338 class Server(ThreadingTCPServer):
310 def __init__(self): 339 def __init__(self):
311 ThreadingTCPServer.__init__(self, ("", 8000), RequestHandler, bind_and_activate=False) # noqa: E501 340 ThreadingTCPServer.__init__(self, ("", 8000), RequestHandler, bind_and_activate=False)
312 self.socket = socket.fromfd(3, self.address_family, self.socket_type) 341 self.socket = socket.fromfd(3, self.address_family, self.socket_type)
313 342
314 343
@@ -334,6 +363,79 @@ in {
334 ''; 363 '';
335 }; 364 };
336 }; 365 };
366 systemd.user.services.niri-workspace-sort = {
367 Unit = {
368 BindsTo = [ "niri.service" ];
369 After = [ "niri.service" ];
370 };
371 Install = {
372 WantedBy = [ "niri.service" ];
373 };
374 Service = {
375 Type = "simple";
376 ExecStart = pkgs.writers.writePython3 "niri-workspace-sort" { flakeIgnore = ["E501"]; } ''
377 import os
378 import sys
379 import socket
380 import json
381
382 outputs = None
383 only = {'HDMI-A-1': {'bmr'}, 'eDP-1': {'vid'}}
384
385
386 class Niri(socket.socket):
387 def __init__(self):
388 super().__init__(socket.AF_UNIX, socket.SOCK_STREAM)
389 super().connect(os.environ["NIRI_SOCKET"])
390 self.fh = super().makefile(mode='rw', buffering=1, encoding='utf-8')
391
392 def cmd(self, obj):
393 print(json.dumps(obj, separators=(',', ':')), flush=True, file=self.fh)
394
395 def event_stream(self):
396 self.cmd("EventStream")
397 return self.fh
398
399
400 with Niri() as niri, Niri().event_stream() as niri_stream:
401 for line in niri_stream:
402 workspaces = None
403 if line_json := json.loads(line):
404 if "WorkspacesChanged" in line_json:
405 workspaces = line_json["WorkspacesChanged"]["workspaces"]
406
407 if workspaces is None:
408 continue
409
410 old_outputs = outputs
411 outputs = {ws["output"] for ws in workspaces}
412 if old_outputs is None:
413 print("Initial outputs: {}".format(outputs), file=sys.stderr)
414 continue
415
416 new_outputs = outputs - old_outputs
417 if not new_outputs:
418 continue
419 print("New outputs: {}".format(new_outputs), file=sys.stderr)
420
421 relevant_workspaces = list(filter(lambda ws: (ws["name"] is not None) or (ws["active_window_id"] is not None), workspaces))
422 target_output = next(iter(outputs - set(only.keys())))
423 if not target_output:
424 continue
425 for ws in relevant_workspaces:
426 ws_ident = ws["name"] if ws["name"] is not None else (ws["output"], ws["idx"])
427 if ws["output"] not in set(only.keys()):
428 continue
429 if ws_ident in only[ws["output"]]:
430 continue
431
432 print("{} -> {}".format(ws_ident, target_output), file=sys.stderr)
433 niri.cmd({"Action": {"MoveWorkspaceToMonitor": {"reference": {"Id": ws["id"]}, "output": target_output}}})
434 '';
435 Restart = "on-failure";
436 RestartSec = 10;
437 };
438 };
337 439
338 programs.niri.scratchspaces = [ 440 programs.niri.scratchspaces = [
339 { name = "pwctl"; 441 { name = "pwctl";
@@ -347,7 +449,7 @@ in {
347 { title = "^Access Request.*"; } 449 { title = "^Access Request.*"; }
348 { title = ".*Passkey credentials$"; } 450 { title = ".*Passkey credentials$"; }
349 ]; 451 ];
350 windowRuleExtra = [ 452 windowRuleExtra = with kdl; [
351 (kdl.leaf "open-focused" false) 453 (kdl.leaf "open-focused" false)
352 ]; 454 ];
353 key = "Mod+Control+P"; 455 key = "Mod+Control+P";
@@ -375,6 +477,20 @@ in {
375 app-id = "com.github.wwmm.easyeffects"; 477 app-id = "com.github.wwmm.easyeffects";
376 spawn = [ "easyeffects" ]; 478 spawn = [ "easyeffects" ];
377 } 479 }
480 { name = "time";
481 key = "Mod+Control+K";
482 app-id = "chrome-kimai.yggdrasil.li__-Default";
483 spawn = [ (toString (pkgs.resholve.writeScript "kimai" {
484 interpreter = pkgs.runtimeShell;
485 inputs = [ pkgs.dex ];
486 execer = [ "cannot:${lib.getExe pkgs.dex}" ];
487 } ''
488 exec dex $HOME/.local/state/nix/profile/share/applications/kimai.desktop
489 '')) ];
490 windowRuleExtra = with kdl; [
491 (leaf "block-out-from" "screencast")
492 ];
493 }
378 ]; 494 ];
379 programs.niri.config = 495 programs.niri.config =
380 let 496 let
@@ -419,6 +535,10 @@ in {
419 ]) 535 ])
420 ]) 536 ])
421 537
538 (plain "gestures" [
539 (plain "hot-corners" [(flag "off")])
540 ])
541
422 (plain "environment" (lib.mapAttrsToList leaf { 542 (plain "environment" (lib.mapAttrsToList leaf {
423 NIXOS_OZONE_WL = "1"; 543 NIXOS_OZONE_WL = "1";
424 QT_QPA_PLATFORM = "wayland"; 544 QT_QPA_PLATFORM = "wayland";
@@ -426,6 +546,10 @@ in {
426 GDK_BACKEND = "wayland"; 546 GDK_BACKEND = "wayland";
427 SDL_VIDEODRIVER = "wayland"; 547 SDL_VIDEODRIVER = "wayland";
428 DISPLAY = ":0"; 548 DISPLAY = ":0";
549 ELECTRON_OZONE_PLATFORM_HINT = "auto";
550 SSH_ASKPASS_REQUIRE = "prefer";
551 SSH_ASKPASS = lib.getExe pkgs.kdePackages.ksshaskpass;
552 SUDO_ASKPASS = lib.getExe pkgs.kdePackages.ksshaskpass;
429 })) 553 }))
430 554
431 (node "output" "eDP-1" [ 555 (node "output" "eDP-1" [
@@ -455,8 +579,8 @@ in {
455 (plain "layout" [ 579 (plain "layout" [
456 (leaf "gaps" 8) 580 (leaf "gaps" 8)
457 (plain "struts" [ 581 (plain "struts" [
458 (leaf "left" 0) 582 (leaf "left" 26)
459 (leaf "right" 0) 583 (leaf "right" 26)
460 (leaf "top" 0) 584 (leaf "top" 0)
461 (leaf "bottom" 0) 585 (leaf "bottom" 0)
462 ]) 586 ])
@@ -540,7 +664,7 @@ in {
540 (plain "window-rule" [ 664 (plain "window-rule" [
541 (map (title: 665 (map (title:
542 (leaf "match" { app-id = "^org\\.keepassxc\\.KeePassXC$"; inherit title; }) 666 (leaf "match" { app-id = "^org\\.keepassxc\\.KeePassXC$"; inherit title; })
543 ) ["^Unlock Database.*" "^Access Request.*" ".*Passkey credentials$"]) 667 ) ["^Unlock Database.*" "^Access Request.*" ".*Passkey credentials$" "Browser Access Request$"])
544 (leaf "open-focused" true) 668 (leaf "open-focused" true)
545 (leaf "open-floating" true) 669 (leaf "open-floating" true)
546 ]) 670 ])
@@ -569,7 +693,7 @@ in {
569 (plain "window-rule" [ 693 (plain "window-rule" [
570 (leaf "match" { app-id = "^thunderbird$"; }) 694 (leaf "match" { app-id = "^thunderbird$"; })
571 (leaf "match" { app-id = "^Element$"; }) 695 (leaf "match" { app-id = "^Element$"; })
572 (leaf "match" { app-id = "^Rainbow$"; }) 696 (leaf "match" { app-id = "^chrome-web\.openrainbow\.com__-Default$"; })
573 (leaf "open-on-workspace" "comm") 697 (leaf "open-on-workspace" "comm")
574 ]) 698 ])
575 (plain "window-rule" [ 699 (plain "window-rule" [
@@ -588,11 +712,16 @@ in {
588 (leaf "open-focused" false) 712 (leaf "open-focused" false)
589 ]) 713 ])
590 (plain "window-rule" [ 714 (plain "window-rule" [
715 (leaf "match" { app-id = "^chrome-audiobookshelf\.yggdrasil\.li__-Default$"; })
716 (leaf "match" { app-id = "^YouTube Music Desktop App$"; })
717 (leaf "open-on-workspace" "vid")
718 ])
719 (plain "window-rule" [
591 (leaf "match" { app-id = "^pdfpc$"; }) 720 (leaf "match" { app-id = "^pdfpc$"; })
592 (plain "default-column-width" [(leaf "proportion" 1.)]) 721 (plain "default-column-width" [(leaf "proportion" 1.)])
593 ]) 722 ])
594 (plain "window-rule" [ 723 (plain "window-rule" [
595 (leaf "match" { app-id = "^pdfpc$"; title = "^pdfpc - presentation$"; }) 724 (leaf "match" { app-id = "^pdfpc$"; title = "^.*presentation.*$"; })
596 (plain "default-column-width" [(leaf "proportion" 1.)]) 725 (plain "default-column-width" [(leaf "proportion" 1.)])
597 (leaf "open-fullscreen" true) 726 (leaf "open-fullscreen" true)
598 (leaf "open-on-workspace" "bmr") 727 (leaf "open-on-workspace" "bmr")
@@ -609,6 +738,7 @@ in {
609 (plain "window-rule" [ 738 (plain "window-rule" [
610 (leaf "match" { app-id = "^org\\.pwmt\\.zathura$"; }) 739 (leaf "match" { app-id = "^org\\.pwmt\\.zathura$"; })
611 (leaf "match" { app-id = "^evince$"; }) 740 (leaf "match" { app-id = "^evince$"; })
741 (leaf "match" { app-id = "^org\\.gnome\\.Papers$"; })
612 (leaf "default-column-display" "tabbed") 742 (leaf "default-column-display" "tabbed")
613 ]) 743 ])
614 744
@@ -636,6 +766,21 @@ in {
636 "Mod+Slash".action = show-hotkey-overlay; 766 "Mod+Slash".action = show-hotkey-overlay;
637 767
638 "Mod+Return".action = spawn terminal; 768 "Mod+Return".action = spawn terminal;
769 "Mod+Shift+Return".action =
770 let
771 nushellKitty = pkgs.symlinkJoin {
772 name = "nushell-kitty";
773 paths = [ config.programs.kitty.package ];
774 buildInputs = [ pkgs.makeWrapper ];
775 postBuild = ''
776 wrapProgram $out/bin/kitty \
777 --add-flags "--config ${pkgs.writeText "kitty.conf" ''
778 include $HOME/${config.xdg.configFile."kitty/kitty.conf".target}
779 shell ${lib.getExe config.programs.nushell.package}
780 ''}"
781 '';
782 };
783 in spawn (lib.getExe' nushellKitty "kitty");
639 "Mod+Q".action = close-window; 784 "Mod+Q".action = close-window;
640 "Mod+O".action = spawn (lib.getExe config.programs.fuzzel.package); 785 "Mod+O".action = spawn (lib.getExe config.programs.fuzzel.package);
641 "Mod+Shift+O".action = spawn (lib.getExe config.programs.fuzzel.package) "--list-executables-in-path"; 786 "Mod+Shift+O".action = spawn (lib.getExe config.programs.fuzzel.package) "--list-executables-in-path";
@@ -671,12 +816,12 @@ in {
671 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) 816 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)
672 $FOUND || echo 817 $FOUND || echo
673 } 818 }
674 FUZZEL_RES=$(prev | fuzzel --dmenu --prompt "qalc> ") || exit $? 819 FUZZEL_RES=$(prev | fuzzel --dmenu --prompt "qalc> " --width=60) || exit $?
675 if [[ "$FUZZEL_RES" =~ .*\ =\ .* ]]; then 820 if [[ "$FUZZEL_RES" =~ .*\ =\ .* ]]; then
676 QALC_RES="$FUZZEL_RES" 821 QALC_RES="$FUZZEL_RES"
677 QALC_RET=0 822 QALC_RET=0
678 else 823 else
679 QALC_RES=$(qalc "$FUZZEL_RES" 2>&1) 824 QALC_RES=$(qalc -set "autocalc off" "$FUZZEL_RES" 2>&1)
680 QALC_RET=$? 825 QALC_RET=$?
681 fi 826 fi
682 [[ -n "$QALC_RES" ]] || exit 1 827 [[ -n "$QALC_RES" ]] || exit 1
@@ -696,18 +841,33 @@ in {
696 notify-send "$QALC_RES" 841 notify-send "$QALC_RES"
697 ''; 842 '';
698 })); 843 }));
844 "Mod+Shift+U".action =
845 let
846 qalcKitty = pkgs.symlinkJoin {
847 name = "qalc-kitty";
848 paths = [ config.programs.kitty.package ];
849 buildInputs = [ pkgs.makeWrapper ];
850 postBuild = ''
851 wrapProgram $out/bin/kitty \
852 --add-flags "--config ${pkgs.writeText "kitty.conf" ''
853 include $HOME/${config.xdg.configFile."kitty/kitty.conf".target}
854 shell ${lib.getExe pkgs.libqalculate}
855 ''}"
856 '';
857 };
858 in spawn (lib.getExe' qalcKitty "kitty");
699 "Mod+E".action = spawn (lib.getExe (pkgs.writeShellApplication { 859 "Mod+E".action = spawn (lib.getExe (pkgs.writeShellApplication {
700 name = "emoji-fuzzel"; 860 name = "emoji-fuzzel";
701 runtimeInputs = with pkgs; [ config.programs.fuzzel.package wtype wl-clipboard-rs ]; 861 runtimeInputs = with pkgs; [ config.programs.fuzzel.package wtype wl-clipboard-rs ];
702 text = '' 862 text = ''
703 FUZZEL_RES=$(fuzzel --dmenu --prompt "emoji> " <"$HOME"/.local/share/emoji-data/list.txt) || exit $? 863 FUZZEL_RES=$(fuzzel --dmenu --prompt "emoji> " --cache "$HOME"/.cache/fuzzel-emoji --width=60 <"$HOME"/.local/share/emoji-data/list.txt) || exit $?
704 [[ -n "$FUZZEL_RES" ]] || exit 1 864 [[ -n "$FUZZEL_RES" ]] || exit 1
705 wl-copy "$(cut -d ':' -f 1 <<<"$FUZZEL_RES" | tr -d '\n')" && wtype -k XF86Paste 865 wl-copy "$(cut -d ':' -f 1 <<<"$FUZZEL_RES" | tr -d '\n')" && wtype -k XF86Paste
706 ''; 866 '';
707 })); 867 }));
708 "Print".action = screenshot; 868 "Print".action = screenshot;
709 "Control+Print".action = screenshot-window; 869 "Control+Print".action = screenshot-window;
710 # "Shift+Print".action = screenshot-screen; 870 "Shift+Print".action = kdl.magic-leaf "screenshot-screen";
711 "Mod+B".action = with-select-window-action ".workspace_id == ($active_workspace | tonumber)" "{\"Action\":{\"FocusWindow\":{\"id\": .id}}}"; 871 "Mod+B".action = with-select-window-action ".workspace_id == ($active_workspace | tonumber)" "{\"Action\":{\"FocusWindow\":{\"id\": .id}}}";
712 "Mod+Shift+B".action = with-select-window-action "true" "{\"Action\":{\"FocusWindow\":{\"id\": .id}}}"; 872 "Mod+Shift+B".action = with-select-window-action "true" "{\"Action\":{\"FocusWindow\":{\"id\": .id}}}";
713 873
@@ -746,22 +906,22 @@ in {
746 "Mod+Shift+Control+C".action = move-workspace-up; 906 "Mod+Shift+Control+C".action = move-workspace-up;
747 907
748 "Mod+ParenLeft".action = focus-workspace "comm"; 908 "Mod+ParenLeft".action = focus-workspace "comm";
749 "Mod+Shift+ParenLeft".action = move-column-to-workspace "comm"; 909 "Mod+Shift+ParenLeft".action = kdl.magic-leaf "move-column-to-workspace" "comm";
750 910
751 "Mod+ParenRight".action = focus-workspace "web"; 911 "Mod+ParenRight".action = focus-workspace "web";
752 "Mod+Shift+ParenRight".action = move-column-to-workspace "web"; 912 "Mod+Shift+ParenRight".action = kdl.magic-leaf "move-column-to-workspace" "web";
753 913
754 "Mod+BraceRight".action = focus-workspace "read"; 914 "Mod+BraceRight".action = focus-workspace "read";
755 "Mod+Shift+BraceRight".action = move-column-to-workspace "read"; 915 "Mod+Shift+BraceRight".action = kdl.magic-leaf "move-column-to-workspace" "read";
756 916
757 "Mod+BraceLeft".action = focus-workspace "mon"; 917 "Mod+BraceLeft".action = focus-workspace "mon";
758 "Mod+Shift+BraceLeft".action = move-column-to-workspace "mon"; 918 "Mod+Shift+BraceLeft".action = kdl.magic-leaf "move-column-to-workspace" "mon";
759 919
760 "Mod+Asterisk".action = focus-workspace "vid"; 920 "Mod+Asterisk".action = focus-workspace "vid";
761 "Mod+Shift+Asterisk".action = move-column-to-workspace "vid"; 921 "Mod+Shift+Asterisk".action = kdl.magic-leaf "move-column-to-workspace" "vid";
762 922
763 "Mod+Plus".action = with-unnamed-workspace-action ''{"Action":{"FocusWorkspace":{"reference":{"Id": .id}}}}''; 923 "Mod+Plus".action = with-unnamed-workspace-action ''{"Action":{"FocusWorkspace":{"reference":{"Id": .id}}}}'';
764 "Mod+Shift+Plus".action = with-unnamed-workspace-action ''{"Action":{"MoveColumnToWorkspace":{"reference":{"Id": .id}}}}''; 924 "Mod+Shift+Plus".action = with-unnamed-workspace-action ''{"Action":{"MoveColumnToWorkspace":{"reference":{"Id": .id}, "focus": true}}}'';
765 925
766 "Mod+M".action = consume-or-expel-window-left; 926 "Mod+M".action = consume-or-expel-window-left;
767 "Mod+W".action = consume-or-expel-window-right; 927 "Mod+W".action = consume-or-expel-window-right;
@@ -769,10 +929,11 @@ in {
769 "Mod+Shift+M".action = toggle-column-tabbed-display; 929 "Mod+Shift+M".action = toggle-column-tabbed-display;
770 930
771 "Mod+R".action = switch-preset-column-width; 931 "Mod+R".action = switch-preset-column-width;
772 "Mod+Shift+R".action = switch-preset-window-height; 932 "Mod+Shift+R".action = maximize-column;
933 "Mod+Shift+Ctrl+R".action = switch-preset-window-height;
773 "Mod+F".action = center-column; 934 "Mod+F".action = center-column;
774 "Mod+Shift+F".action = maximize-column; 935 "Mod+Shift+F".action = toggle-windowed-fullscreen;
775 "Mod+Shift+Ctrl+F".action = fullscreen-window; 936 "Mod+Ctrl+Shift+F".action = fullscreen-window;
776 937
777 "Mod+V".action = switch-focus-between-floating-and-tiling; 938 "Mod+V".action = switch-focus-between-floating-and-tiling;
778 "Mod+Shift+V".action = toggle-window-floating; 939 "Mod+Shift+V".action = toggle-window-floating;
@@ -828,13 +989,24 @@ in {
828 989
829 "Mod+Semicolon".action = spawn makoctl "dismiss" "--group"; 990 "Mod+Semicolon".action = spawn makoctl "dismiss" "--group";
830 "Mod+Shift+Semicolon".action = spawn makoctl "dismiss" "--all"; 991 "Mod+Shift+Semicolon".action = spawn makoctl "dismiss" "--all";
831 "Mod+Period".action = spawn makoctl "menu" (lib.getExe config.programs.fuzzel.package) "--dmenu"; 992 "Mod+Period".action = spawn makoctl "menu" "--" (lib.getExe config.programs.fuzzel.package) "--dmenu";
832 "Mod+Comma".action = spawn makoctl "restore"; 993 "Mod+Comma".action = spawn makoctl "restore";
833 994
834 "Mod+Control+W".action = with-empty-unnamed-workspace-action "{\"Action\":{\"FocusWorkspace\":{\"reference\":{\"Id\": $workspace_id}}}}"; 995 "Mod+Control+W".action = with-empty-unnamed-workspace-action "{\"Action\":{\"FocusWorkspace\":{\"reference\":{\"Id\": $workspace_id}}}}";
835 "Mod+Control+Shift+W".action = with-empty-unnamed-workspace-action "{\"Action\":{\"MoveColumnToWorkspace\":{\"reference\":{\"Id\": $workspace_id}}}}"; 996 "Mod+Control+Shift+W".action = with-empty-unnamed-workspace-action "{\"Action\":{\"MoveColumnToWorkspace\":{\"reference\":{\"Id\": $workspace_id}, \"focus\": true}}}";
997
998 "Mod+X".action = set-dynamic-cast-window;
999 "Mod+Shift+X".action = set-dynamic-cast-monitor;
1000 "Mod+Control+Shift+X".action = clear-dynamic-cast-target;
1001
1002 "Mod+D".action = with-urgent-window-action "{\"Action\":{\"FocusWindow\":{\"id\": .id}}}";
1003 "Mod+Shift+D".action = with-focused-window-action "{\"Action\":{\"UnsetUrgent\":{\"id\": .id}}}";
1004
1005 "Mod+K".action = spawn (lib.getExe' pkgs.worktime "worktime-ui");
1006 "Mod+Shift+K".action = spawn (lib.getExe' pkgs.worktime "worktime-stop");
836 })) 1007 }))
837 (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) 1008 (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)
1009 (map ({ name, moveKey, ...}: if moveKey != null then bind moveKey { action = kdl.magic-leaf "move-column-to-workspace" name; } else null) cfg.scratchspaces)
838 ] 1010 ]
839 )) 1011 ))
840 ]; 1012 ];
diff --git a/accounts/gkleen@sif/niri/mako.nix b/accounts/gkleen@sif/niri/mako.nix
index 2788fb82..eba26caa 100644
--- a/accounts/gkleen@sif/niri/mako.nix
+++ b/accounts/gkleen@sif/niri/mako.nix
@@ -3,37 +3,31 @@
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 criteria = {
19 format=<b>(%g)</b> <i>%s</i>\n%b 19 grouped.format = "<b>(%g)</b> <i>%s</i>\\n%b";
20 20 "urgency=low".text-color = "#999999ff";
21 [urgency=low] 21 "urgency=critical".background-color = "#900000dd";
22 text-color=#999999ff 22 "app-name=Element".group-by = "summary";
23 23 "app-name=poweralertd" = {
24 [urgency=critical] 24 history = false;
25 background-color=#900000dd 25 ignore-timeout = true;
26 26 default-timeout = 2000;
27 [app-name=Element] 27 };
28 group-by=summary 28 "app-name=worktime".history = false;
29 29 "mode=silent".invisible = true;
30 [app-name=poweralertd] 30 };
31 ignore-timeout=1
32 default-timeout=2000
33
34 [mode=silent]
35 invisible=1
36 '';
37 package = pkgs.symlinkJoin { 31 package = pkgs.symlinkJoin {
38 name = "${pkgs.mako.name}-wrapped"; 32 name = "${pkgs.mako.name}-wrapped";
39 paths = with pkgs; [ mako ]; 33 paths = with pkgs; [ mako ];
diff --git a/accounts/gkleen@sif/niri/swayosd.nix b/accounts/gkleen@sif/niri/swayosd.nix
index 984927c2..54ebb302 100644
--- a/accounts/gkleen@sif/niri/swayosd.nix
+++ b/accounts/gkleen@sif/niri/swayosd.nix
@@ -3,9 +3,10 @@
3 config = { 3 config = {
4 services.swayosd = { 4 services.swayosd = {
5 enable = true; 5 enable = true;
6 topMargin = 0.946154; 6 topMargin = 0.4769706078;
7 stylePath = pkgs.runCommand "style.css" { 7 stylePath = pkgs.runCommand "style.css" {
8 src = pkgs.writeText "style.scss" '' 8 passAsFile = [ "src" ];
9 src = ''
9 window#osd { 10 window#osd {
10 padding: 12px 20px; 11 padding: 12px 20px;
11 border-radius: 999px; 12 border-radius: 999px;
@@ -59,7 +60,7 @@
59 } 60 }
60 ''; 61 '';
61 buildInputs = with pkgs; [sass]; 62 buildInputs = with pkgs; [sass];
62 } "scss -C --sourcemap=none --style=compact $src $out"; 63 } "scss -C --sourcemap=none --style=compact $srcPath $out";
63 }; 64 };
64 }; 65 };
65} 66}
diff --git a/accounts/gkleen@sif/niri/waybar.nix b/accounts/gkleen@sif/niri/waybar.nix
index bae818f6..c02a9a76 100644
--- a/accounts/gkleen@sif/niri/waybar.nix
+++ b/accounts/gkleen@sif/niri/waybar.nix
@@ -20,15 +20,21 @@ in {
20 { 20 {
21 layer = "top"; 21 layer = "top";
22 position = "top"; 22 position = "top";
23 height = 14; 23 height = 21;
24 output = [ "eDP-1" "DP-2" "DP-3" ]; 24 output = [ "eDP-1" "DP-2" "DP-3" ];
25 modules-left = [ "niri/workspaces" ]; 25 modules-left = [ "niri/workspaces" ];
26 modules-center = [ "niri/window" ]; 26 modules-center = [ "niri/window" ];
27 modules-right = [ "custom/worktime" "custom/worktime-today" 27 modules-right = [ "custom/worktime" "custom/worktime-today"
28 "custom/weather" 28 "custom/weather"
29 "custom/keymap" 29 "custom/keymap"
30 "privacy" "tray" "wireplumber" "backlight" "battery" "idle_inhibitor" "custom/mako" "clock" ]; 30 "privacy" "tray" "wireplumber" "backlight" "battery" "idle_inhibitor" "custom/mako" "custom/lid_inhibitor" "clock" ];
31 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 };
32 "custom/mako" = { 38 "custom/mako" = {
33 format = "{}"; 39 format = "{}";
34 return-type = "json"; 40 return-type = "json";
@@ -211,7 +217,7 @@ in {
211 layer = "top"; 217 layer = "top";
212 position = "top"; 218 position = "top";
213 height = 14; 219 height = 14;
214 output = [ "!eDP-1" "!DP-2" "!DP-3" ]; 220 output = [ "!eDP-1" "!DP-2" "!DP-3" "*" ];
215 modules-left = [ "niri/workspaces" ]; 221 modules-left = [ "niri/workspaces" ];
216 modules-center = [ "niri/window" ]; 222 modules-center = [ "niri/window" ];
217 modules-right = [ "clock" ]; 223 modules-right = [ "clock" ];
@@ -254,10 +260,10 @@ in {
254 } 260 }
255 261
256 .modules-left { 262 .modules-left {
257 margin-left: 12px; 263 margin-left: 38px;
258 } 264 }
259 .modules-right { 265 .modules-right {
260 margin-right: 12px; 266 margin-right: 38px;
261 } 267 }
262 268
263 .module { 269 .module {
@@ -293,7 +299,7 @@ in {
293 #tray { 299 #tray {
294 margin: 0; 300 margin: 0;
295 } 301 }
296 #battery, #idle_inhibitor, #backlight, #wireplumber, #custom-mako { 302 #battery, #idle_inhibitor, #backlight, #wireplumber, #custom-mako, #custom-lid_inhibitor {
297 color: @grey; 303 color: @grey;
298 margin: 0 5px 0 2px; 304 margin: 0 5px 0 2px;
299 } 305 }
@@ -302,7 +308,11 @@ in {
302 margin-left: 6px; 308 margin-left: 6px;
303 } 309 }
304 #custom-mako { 310 #custom-mako {
305 margin-right: 2px; 311 margin-right: 4px;
312 margin-left: 3px;
313 }
314 #custom-lid_inhibitor {
315 margin-right: 3px;
306 margin-left: 3px; 316 margin-left: 3px;
307 } 317 }
308 #battery { 318 #battery {
@@ -330,7 +340,7 @@ in {
330 color: @orange; 340 color: @orange;
331 } 341 }
332 342
333 #idle_inhibitor { 343 #idle_inhibitor, #custom-lid_inhibitor {
334 padding-top: 1px; 344 padding-top: 1px;
335 } 345 }
336 346
@@ -340,6 +350,7 @@ in {
340 } 350 }
341 #clock { 351 #clock {
342 /* margin-right: 5px; */ 352 /* margin-right: 5px; */
353 font-feature-settings: "tnum";
343 } 354 }
344 ''; 355 '';
345 }; 356 };
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 2237b708..90cccc58 100644
--- a/accounts/gkleen@sif/systemd.nix
+++ b/accounts/gkleen@sif/systemd.nix
@@ -242,7 +242,7 @@ in {
242 "-${lib.getExe pkgs.playerctl} -a pause" 242 "-${lib.getExe pkgs.playerctl} -a pause"
243 "-${lib.getExe (pkgs.writeShellApplication { 243 "-${lib.getExe (pkgs.writeShellApplication {
244 name = "generate-css"; 244 name = "generate-css";
245 runtimeInputs = with pkgs; [cfg.programs.wpaperd.package jq coreutils imagemagick findutils]; 245 runtimeInputs = with pkgs; [cfg.services.wpaperd.package jq coreutils imagemagick findutils];
246 text = '' 246 text = ''
247 declare -A monitors 247 declare -A monitors
248 monitors=() 248 monitors=()
@@ -333,21 +333,21 @@ in {
333 ExecStopPost = "${pkgs.coreutils}/bin/rm -rfv \"$CACHE_DIRECTORY\""; 333 ExecStopPost = "${pkgs.coreutils}/bin/rm -rfv \"$CACHE_DIRECTORY\"";
334 }; 334 };
335 }; 335 };
336 wpaperd = { 336 # wpaperd = {
337 Install = { 337 # Install = {
338 WantedBy = ["graphical-session.target"]; 338 # WantedBy = ["graphical-session.target"];
339 }; 339 # };
340 Unit = { 340 # Unit = {
341 After = [ "graphical-session.target" ]; 341 # After = [ "graphical-session.target" ];
342 PartOf = [ "graphical-session.target" ]; 342 # PartOf = [ "graphical-session.target" ];
343 }; 343 # };
344 Service = { 344 # Service = {
345 ExecStart = lib.getExe cfg.programs.wpaperd.package; 345 # ExecStart = lib.getExe cfg.services.wpaperd.package;
346 Type = "simple"; 346 # Type = "simple";
347 Restart = "always"; 347 # Restart = "always";
348 RestartSec = "2s"; 348 # RestartSec = "2s";
349 }; 349 # };
350 }; 350 # };
351 xembed-sni-proxy = { 351 xembed-sni-proxy = {
352 Unit = { 352 Unit = {
353 PartOf = lib.mkForce ["tray.target"]; 353 PartOf = lib.mkForce ["tray.target"];
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/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 c628e2e9..abc200c6 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,7 +90,7 @@ 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 -L -o ${archiveFile} ${templateArchive}
@@ -91,14 +99,14 @@ dir() {
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,12 +123,12 @@ 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 ;;
@@ -134,25 +142,21 @@ dir() {
134 fi 142 fi
135 143
136 144
137 ${wormhole} && wormhole receive --accept-file 145 [[ $wormhole = "true" ]] && wormhole receive --accept-file
138 146
139 147
140 if ${quickserve}; then 148 if [[ ${#@} -gt 0 ]]; then
141 quickserve --root . --upload . --show-hidden --tar gz 149 ${@}
142 fi 150 fi
143 151
152 cd $(pwd) # Needed for mounting to work
144 153
145 if [[ ${#@} -eq 0 ]] || ${forceShell}; then 154 if [[ ${miniserve} = "true" ]]; then
146 if [[ ${#@} -gt 0 ]]; then 155 miniserve --random-route --hidden --enable-tar-gz --enable-zip . &
147 if [[ -z ${nixShell} ]]; then 156 echo $! > "${miniservePIDFile}"
148 ${@} 157 fi
149 else
150 nix-shell ${nixShell} --run "${@}"
151 fi
152 fi
153
154 cd $(pwd) # Needed for mounting to work
155 158
159 if [[ ${#@} -eq 0 ]] && [[ ${miniserve} != "true" ]] || [[ $forceShell = "true" ]]; then
156 isSingleDir() { 160 isSingleDir() {
157 typeset -a contents 161 typeset -a contents
158 contents=(*(N) .*(N)) 162 contents=(*(N) .*(N))
@@ -166,18 +170,9 @@ dir() {
166 } 170 }
167 while d=$(isSingleDir); do cd ${d}; done 171 while d=$(isSingleDir); do cd ${d}; done
168 172
169 173 zsh
170 if [[ -z ${nixShell} ]]; then 174 elif [[ ${miniserve} == "true" ]]; then
171 zsh 175 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 176 fi
182 ) 177 )
183} 178}
@@ -185,27 +180,30 @@ dir() {
185tmpdir() { 180tmpdir() {
186 cleanup() 181 cleanup()
187 { 182 {
188 cd / 183 cd /
189 unmount() { 184 unmount() {
190 printf "Unmounting %s\n" ${1} >&2 185 printf "Unmounting %s\n" ${1} >&2
191 fusermount -u ${1} || umount ${1} || sudo umount ${1} 186 fusermount -u ${1} || umount ${1} || sudo umount ${1}
192 } 187 }
193 188
194 if mountpoint -q -- ${dir}; then 189 if [[ -n ${dir} ]]; then
195 unmount ${dir} || return $? 190 if mountpoint -q -- ${dir}; then
196 else 191 unmount ${dir} || return $?
197 while read -d $'\0' subDir; do 192 else
198 mountpoint -q -- ${subDir} || continue 193 while read -d $'\0' subDir; do
199 unmount ${subDir} || return $? 194 mountpoint -q -- ${subDir} || continue
200 done <<<$(find ${dir} -xdev -type d -print0 | sort -zr) 195 unmount ${subDir} || return $?
201 fi 196 done <<<$(find ${dir} -xdev -type d -print0 | sort -zr)
202 197 fi
203 rm -rfv --one-file-system -- ${dir} 198
199 rm -rfv --one-file-system -- ${dir}
200 dir=""
201 fi
204 } 202 }
205 203
206 local tmpdir="" 204 local tmpdir=""
207 205
208 while getopts ':t:a:s:Sd:ir:wqg:p:' arg; do 206 while getopts ':t:a:d:ir:wg:p:m' arg; do
209 case $arg in 207 case $arg in
210 "t") tmpdir="=${OPTARG}" ;; 208 "t") tmpdir="=${OPTARG}" ;;
211 "?"|":") printf "Invalid option: %s\n" $arg >&2; exit 2 ;; 209 "?"|":") printf "Invalid option: %s\n" $arg >&2; exit 2 ;;
@@ -213,6 +211,8 @@ tmpdir() {
213 done 211 done
214 212
215 ( 213 (
214 set -o localoptions -o localtraps
215 trap 'return 1' INT TERM
216 trap cleanup EXIT 216 trap cleanup EXIT
217 217
218 218
@@ -234,16 +234,6 @@ public-ip() {
234 curl -s -H 'Accept: application/json' $@ ifconfig.co | jq -r '.ip' 234 curl -s -H 'Accept: application/json' $@ ifconfig.co | jq -r '.ip'
235} 235}
236 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}
246
247swap() { 237swap() {
248 f1=${1} 238 f1=${1}
249 f2=${2} 239 f2=${2}
@@ -271,14 +261,6 @@ l() {
271 ls --long --binary --git --time-style=iso --header $@ 261 ls --long --binary --git --time-style=iso --header $@
272} 262}
273 263
274re() {
275 systemctl restart $@
276}
277
278ure() {
279 systemctl --user restart $@
280}
281
282ssh-installer() { 264ssh-installer() {
283 ssh -o UserKnownHostsFile=/dev/null -o StrictHostKeyChecking=no -o IdentityFile=~/.ssh/gkleen@sif.midgard.yggdrasil $@ 265 ssh -o UserKnownHostsFile=/dev/null -o StrictHostKeyChecking=no -o IdentityFile=~/.ssh/gkleen@sif.midgard.yggdrasil $@
284} 266}
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 = {