summaryrefslogtreecommitdiff
path: root/accounts
diff options
context:
space:
mode:
Diffstat (limited to 'accounts')
-rw-r--r--accounts/gkleen@sif/default.nix96
-rw-r--r--accounts/gkleen@sif/emacs.el2
-rw-r--r--accounts/gkleen@sif/niri/default.nix414
-rw-r--r--accounts/gkleen@sif/niri/mako.nix7
-rw-r--r--accounts/gkleen@sif/niri/swayosd.nix7
-rw-r--r--accounts/gkleen@sif/niri/waybar.nix21
-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.nix2
-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/zshrc8
12 files changed, 495 insertions, 151 deletions
diff --git a/accounts/gkleen@sif/default.nix b/accounts/gkleen@sif/default.nix
index e07362fc..64434bb8 100644
--- a/accounts/gkleen@sif/default.nix
+++ b/accounts/gkleen@sif/default.nix
@@ -71,7 +71,8 @@ in {
71 imports = [ 71 imports = [
72 ./libvirt 72 ./libvirt
73 ./niri 73 ./niri
74 flakeInputs.nix-index-database.hmModules.nix-index 74 ./synadm
75 flakeInputs.nix-index-database.homeModules.nix-index
75 flakeInputs.impermanence.nixosModules.home-manager.impermanence 76 flakeInputs.impermanence.nixosModules.home-manager.impermanence
76 ]; 77 ];
77 78
@@ -171,6 +172,7 @@ in {
171 }; 172 };
172 }; 173 };
173 }; 174 };
175 chromium.enable = true;
174 176
175 zathura = { 177 zathura = {
176 enable = true; 178 enable = true;
@@ -232,6 +234,7 @@ in {
232 config.programs.ssh.package 234 config.programs.ssh.package
233 gnused 235 gnused
234 miniserve 236 miniserve
237 p7zip
235 ]; 238 ];
236 execer = with pkgs; [ 239 execer = with pkgs; [
237 "cannot:${lib.getExe' rpm "rpm2cpio"}" 240 "cannot:${lib.getExe' rpm "rpm2cpio"}"
@@ -244,6 +247,7 @@ in {
244 "cannot:${lib.getExe less}" 247 "cannot:${lib.getExe less}"
245 "cannot:${lib.getExe' config.systemd.package "systemctl"}" 248 "cannot:${lib.getExe' config.systemd.package "systemctl"}"
246 "cannot:${lib.getExe config.programs.ssh.package}" 249 "cannot:${lib.getExe config.programs.ssh.package}"
250 "cannot:${lib.getExe' p7zip "7z"}"
247 ]; 251 ];
248 wrapper = with pkgs; [ 252 wrapper = with pkgs; [
249 "${lib.getExe' magickWrapped "magick"}:${lib.getExe' imagemagick "magick"}" 253 "${lib.getExe' magickWrapped "magick"}:${lib.getExe' imagemagick "magick"}"
@@ -282,6 +286,16 @@ in {
282 pro = "$HOME/projects/pro"; 286 pro = "$HOME/projects/pro";
283 media = "$HOME/media"; 287 media = "$HOME/media";
284 }; 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 };
285 299
286 obs-studio = { 300 obs-studio = {
287 enable = true; 301 enable = true;
@@ -317,8 +331,10 @@ in {
317 # notify_on_cmd_finish = "invisible 120"; 331 # notify_on_cmd_finish = "invisible 120";
318 }; 332 };
319 keybindings = { 333 keybindings = {
320 "kitty_mod+n" = "detach_window"; 334 "kitty_mod+n" = "new_os_window_with_cwd";
321 "kitty_mod+m" = "detach_window ask"; 335 "kitty_mod+m" = "detach_window ask";
336 "kitty_mod+enter" = "new_window_with_cwd";
337 "kitty_mod+t" = "new_tab_with_cwd";
322 }; 338 };
323 }; 339 };
324 fuzzel = { 340 fuzzel = {
@@ -331,7 +347,7 @@ in {
331 font = "Fira Sans"; 347 font = "Fira Sans";
332 }; 348 };
333 colors = { 349 colors = {
334 background = "000000aa"; 350 background = "000000cc";
335 text = "cdd6f4ff"; 351 text = "cdd6f4ff";
336 match = "94e2d5ff"; 352 match = "94e2d5ff";
337 selection = "585b70ff"; 353 selection = "585b70ff";
@@ -352,6 +368,7 @@ in {
352 enable = true; 368 enable = true;
353 settings.show_banner = false; 369 settings.show_banner = false;
354 }; 370 };
371 fd.enable = true;
355 }; 372 };
356 373
357 services = { 374 services = {
@@ -477,6 +494,13 @@ in {
477 }; 494 };
478 }; 495 };
479 496
497 qt.kde.settings = {
498 kwalletrc = {
499 KSecretD.Enabled = false;
500 Wallet."Default Wallet" = "store";
501 };
502 };
503
480 xsession.preferStatusNotifierItems = true; 504 xsession.preferStatusNotifierItems = true;
481 505
482 xresources.properties = import ./xresources.nix; 506 xresources.properties = import ./xresources.nix;
@@ -488,16 +512,15 @@ in {
488 wrappedYTMDesktop libsForQt5.qt5ct playerctl evince papers 512 wrappedYTMDesktop libsForQt5.qt5ct playerctl evince papers
489 thunderbird zoom-us xdg-desktop-portal steam steam-run 513 thunderbird zoom-us xdg-desktop-portal steam steam-run
490 wireshark virt-manager rclone cached-nix-shell worktime 514 wireshark virt-manager rclone cached-nix-shell worktime
491 fira-code-symbols libreoffice xournalpp google-chrome 515 fira-code-symbols libreoffice xournalpp
492 nixos-shell virt-viewer freerdp gnome-icon-theme 516 nixos-shell virt-viewer freerdp gnome-icon-theme
493 paper-icon-theme sshpassSecret weechat element-desktop 517 paper-icon-theme sshpassSecret weechat element-desktop
494 sieve-connect gimp3 inkscape udiskie glab nitrokey-app 518 sieve-connect gimp3 inkscape udiskie glab nitrokey-app
495 pynitrokey gtklock wlrctl remmina openscad spice-record 519 pynitrokey gtklock wlrctl remmina openscad spice-record
496 libguestfs-with-appliance nerd-fonts.fira-mono 520 nerd-fonts.fira-mono
497 nerd-fonts.symbols-only nerd-fonts.fira-code powerline-fonts 521 nerd-fonts.symbols-only nerd-fonts.fira-code powerline-fonts
498 swtpm (hunspellWithDicts (with hunspellDicts; [en_GB-large de_DE])) 522 swtpm (hunspell.withDicts (dicts: with dicts; [en_GB-large de_DE]))
499 libation 523 libation libqalculate
500 # synadm
501 ] ++ mapAttrsToList (_name: pkg: pkgs.callPackage pkg {}) (customUtils.nixImport { dir = ./utils; }); 524 ] ++ mapAttrsToList (_name: pkg: pkgs.callPackage pkg {}) (customUtils.nixImport { dir = ./utils; });
502 525
503 file = { 526 file = {
@@ -520,6 +543,7 @@ in {
520 STACK_XDG = 1; 543 STACK_XDG = 1;
521 EDITOR = lib.getExe' editor "emacsclient"; 544 EDITOR = lib.getExe' editor "emacsclient";
522 RCLONE_PASSWORD_COMMAND = "${lib.getExe' pkgs.libsecret "secret-tool"} lookup service rclone"; 545 RCLONE_PASSWORD_COMMAND = "${lib.getExe' pkgs.libsecret "secret-tool"} lookup service rclone";
546 SYSTEMD_TINT_BACKGROUND = "false";
523 }; 547 };
524 548
525 extraProfileCommands = '' 549 extraProfileCommands = ''
@@ -556,9 +580,17 @@ in {
556 General = { 580 General = {
557 dot_as_separator = 0; 581 dot_as_separator = 0;
558 }; 582 };
583 Mode = {
584 calculate_as_you_type = 1;
585 };
559 }; 586 };
560 }; 587 };
561 "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 };
562 "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 = ''
563 [Unit] 595 [Unit]
564 After=graphical-session.target 596 After=graphical-session.target
@@ -576,6 +608,8 @@ in {
576 xdg.dataFile = { 608 xdg.dataFile = {
577 "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";
578 "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";
579 "emoji-data/list.txt".source = pkgs.stdenv.mkDerivation { 613 "emoji-data/list.txt".source = pkgs.stdenv.mkDerivation {
580 inherit (sources.emoji-data) pname src; 614 inherit (sources.emoji-data) pname src;
581 version = lib.removePrefix "v" sources.emoji-data.version; 615 version = lib.removePrefix "v" sources.emoji-data.version;
@@ -663,11 +697,11 @@ in {
663 exec -- \ 697 exec -- \
664 ${lib.getExe' config.systemd.package "systemd-run"} --wait --user --slice-inherit \ 698 ${lib.getExe' config.systemd.package "systemd-run"} --wait --user --slice-inherit \
665 --property 'CPUAccounting=yes' --property 'CPUQuotaPeriodSec=50ms' \ 699 --property 'CPUAccounting=yes' --property 'CPUQuotaPeriodSec=50ms' \
666 --property 'Environment=DSCP=46' \ 700 -E DSCP=46 -E NIXOS_OZONE_WL \
667 -- ${lib.getExe pkgs.dscp} ${lib.getExe' pkgs.google-chrome "google-chrome-stable"} \ 701 -- ${lib.getExe pkgs.dscp} ${lib.getExe cfg.programs.chromium.package} \
668 --class=Rainbow \ 702 --class=Rainbow \
669 --kiosk "https://web.openrainbow.com" \ 703 --app="https://web.openrainbow.com" \
670 --user-data-dir=''${HOME}/.config/google-chrome-rainbow 704 --user-data-dir=''${HOME}/.config/chromium-rainbow
671 ''); 705 '');
672 icon = pkgs.fetchurl { 706 icon = pkgs.fetchurl {
673 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";
@@ -677,6 +711,42 @@ in {
677 StartupWMClass = "Rainbow"; 711 StartupWMClass = "Rainbow";
678 }; 712 };
679 }; 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 };
680 thunderbird-lmu = { 750 thunderbird-lmu = {
681 name = "Thunderbird (LMU)"; 751 name = "Thunderbird (LMU)";
682 exec = "thunderbird --name thunderbird -P lmu %U"; 752 exec = "thunderbird --name thunderbird -P lmu %U";
diff --git a/accounts/gkleen@sif/emacs.el b/accounts/gkleen@sif/emacs.el
index 563c5d0b..3beefba6 100644
--- a/accounts/gkleen@sif/emacs.el
+++ b/accounts/gkleen@sif/emacs.el
@@ -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 803b3a0d..35a3d799 100644
--- a/accounts/gkleen@sif/niri/default.nix
+++ b/accounts/gkleen@sif/niri/default.nix
@@ -3,6 +3,7 @@ let
3 cfg = config.programs.niri; 3 cfg = config.programs.niri;
4 4
5 kdl = flakeInputs.niri-flake.lib.kdl; 5 kdl = flakeInputs.niri-flake.lib.kdl;
6 sleaf = name: arg: kdl.node name [arg] [];
6 7
7 niri = cfg.package; 8 niri = cfg.package;
8 terminal = lib.getExe config.programs.kitty.package; 9 terminal = lib.getExe config.programs.kitty.package;
@@ -35,7 +36,11 @@ let
35 if jq -e '.is_focused' <<<"$window_json" >/dev/null; then 36 if jq -e '.is_focused' <<<"$window_json" >/dev/null; then
36 niri msg action focus-workspace-previous 37 niri msg action focus-workspace-previous
37 else 38 else
38 niri msg action focus-window --id "$(jq -r '.id' <<<"$window_json")" 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
39 fi 44 fi
40 exit 0 45 exit 0
41 fi 46 fi
@@ -45,7 +50,6 @@ let
45 ''; 50 '';
46 }; 51 };
47 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);
48 focus-or-spawn-action-app_id = app_id: focus-or-spawn-action ''select(.app_id == "${app_id}")'';
49 53
50 with_adjacent_workspace = pkgs.writeShellApplication { 54 with_adjacent_workspace = pkgs.writeShellApplication {
51 name = "with-adjacent-workspace"; 55 name = "with-adjacent-workspace";
@@ -84,7 +88,7 @@ let
84 }; 88 };
85 with-adjacent-workspace-action = config.lib.niri.actions.spawn (lib.getExe with_adjacent_workspace) "^${lib.concatMapStringsSep "|" ({ name, ...}: name) cfg.scratchspaces}$"; 89 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}}}}''; 90 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}}}}''; 91 move-column-to-adjacent-workspace = direction: with-adjacent-workspace-action direction ''{"Action":{"MoveColumnToWorkspace":{"reference":{"Id": .id}, "focus": true}}}'';
88 92
89 with_unnamed_workspace = pkgs.writeShellApplication { 93 with_unnamed_workspace = pkgs.writeShellApplication {
90 name = "with-unnamed-workspace"; 94 name = "with-unnamed-workspace";
@@ -131,7 +135,7 @@ let
131 135
132 windows_json="$(niri msg -j windows)" 136 windows_json="$(niri msg -j windows)"
133 active_workspace="$(jq -r '.[] | select(.is_focused) | .workspace_id' <<<"$windows_json")" 137 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)" 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)"
135 # shellcheck disable=SC2016 139 # 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")" 140 window_json="$(gojq -rc --arg active_workspace "$active_workspace" --arg window_ix "$window_ix" 'map(select('"$window_select"')) | .[($window_ix | tonumber)]' <<<"$windows_json")"
137 141
@@ -141,6 +145,25 @@ let
141 ''; 145 '';
142 }; 146 };
143 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"));
144in { 167in {
145 imports = [ 168 imports = [
146 ./waybar.nix 169 ./waybar.nix
@@ -171,6 +194,17 @@ in {
171 type = lib.types.nullOr lib.types.str; 194 type = lib.types.nullOr lib.types.str;
172 default = null; 195 default = null;
173 }; 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 };
174 spawn = lib.mkOption { 208 spawn = lib.mkOption {
175 type = lib.types.nullOr (lib.types.listOf lib.types.str); 209 type = lib.types.nullOr (lib.types.listOf lib.types.str);
176 default = null; 210 default = null;
@@ -245,7 +279,7 @@ in {
245 Service = { 279 Service = {
246 Type = "simple"; 280 Type = "simple";
247 Sockets = [ "niri-workspace-history.socket" ]; 281 Sockets = [ "niri-workspace-history.socket" ];
248 ExecStart = pkgs.writers.writePython3 "niri-workspace-history" {} '' 282 ExecStart = pkgs.writers.writePython3 "niri-workspace-history" { flakeIgnore = ["E501"]; } ''
249 import os 283 import os
250 import socket 284 import socket
251 import json 285 import json
@@ -274,7 +308,7 @@ in {
274 308
275 def focus_workspace(output, workspace): 309 def focus_workspace(output, workspace):
276 with history_lock: 310 with history_lock:
277 workspace_history[output] = [workspace] + [ws for ws in workspace_history[output] if ws != workspace] # noqa: E501 311 workspace_history[output] = [workspace] + [ws for ws in workspace_history[output] if ws != workspace]
278 # print(json.dumps(workspace_history), file=sys.stderr) 312 # print(json.dumps(workspace_history), file=sys.stderr)
279 313
280 sock = socket.socket(socket.AF_UNIX, socket.SOCK_STREAM) 314 sock = socket.socket(socket.AF_UNIX, socket.SOCK_STREAM)
@@ -297,14 +331,14 @@ in {
297 331
298 class RequestHandler(StreamRequestHandler): 332 class RequestHandler(StreamRequestHandler):
299 def handle(self): 333 def handle(self):
300 with detaching(TextIOWrapper(self.wfile, encoding='utf-8', write_through=True)) as out: # noqa: E501 334 with detaching(TextIOWrapper(self.wfile, encoding='utf-8', write_through=True)) as out:
301 with history_lock: 335 with history_lock:
302 json.dump(workspace_history, out) 336 json.dump(workspace_history, out)
303 337
304 338
305 class Server(ThreadingTCPServer): 339 class Server(ThreadingTCPServer):
306 def __init__(self): 340 def __init__(self):
307 ThreadingTCPServer.__init__(self, ("", 8000), RequestHandler, bind_and_activate=False) # noqa: E501 341 ThreadingTCPServer.__init__(self, ("", 8000), RequestHandler, bind_and_activate=False)
308 self.socket = socket.fromfd(3, self.address_family, self.socket_type) 342 self.socket = socket.fromfd(3, self.address_family, self.socket_type)
309 343
310 344
@@ -330,6 +364,79 @@ in {
330 ''; 364 '';
331 }; 365 };
332 }; 366 };
367 systemd.user.services.niri-workspace-sort = {
368 Unit = {
369 BindsTo = [ "niri.service" ];
370 After = [ "niri.service" ];
371 };
372 Install = {
373 WantedBy = [ "niri.service" ];
374 };
375 Service = {
376 Type = "simple";
377 ExecStart = pkgs.writers.writePython3 "niri-workspace-sort" { flakeIgnore = ["E501"]; } ''
378 import os
379 import sys
380 import socket
381 import json
382
383 outputs = None
384 only = {'HDMI-A-1': {'bmr'}, 'eDP-1': {'vid'}}
385
386
387 class Niri(socket.socket):
388 def __init__(self):
389 super().__init__(socket.AF_UNIX, socket.SOCK_STREAM)
390 super().connect(os.environ["NIRI_SOCKET"])
391 self.fh = super().makefile(mode='rw', buffering=1, encoding='utf-8')
392
393 def cmd(self, obj):
394 print(json.dumps(obj, separators=(',', ':')), flush=True, file=self.fh)
395
396 def event_stream(self):
397 self.cmd("EventStream")
398 return self.fh
399
400
401 with Niri() as niri, Niri().event_stream() as niri_stream:
402 for line in niri_stream:
403 workspaces = None
404 if line_json := json.loads(line):
405 if "WorkspacesChanged" in line_json:
406 workspaces = line_json["WorkspacesChanged"]["workspaces"]
407
408 if workspaces is None:
409 continue
410
411 old_outputs = outputs
412 outputs = {ws["output"] for ws in workspaces}
413 if old_outputs is None:
414 print("Initial outputs: {}".format(outputs), file=sys.stderr)
415 continue
416
417 new_outputs = outputs - old_outputs
418 if not new_outputs:
419 continue
420 print("New outputs: {}".format(new_outputs), file=sys.stderr)
421
422 relevant_workspaces = list(filter(lambda ws: (ws["name"] is not None) or (ws["active_window_id"] is not None), workspaces))
423 target_output = next(iter(outputs - set(only.keys())))
424 if not target_output:
425 continue
426 for ws in relevant_workspaces:
427 ws_ident = ws["name"] if ws["name"] is not None else (ws["output"], ws["idx"])
428 if ws["output"] not in set(only.keys()):
429 continue
430 if ws_ident in only[ws["output"]]:
431 continue
432
433 print("{} -> {}".format(ws_ident, target_output), file=sys.stderr)
434 niri.cmd({"Action": {"MoveWorkspaceToMonitor": {"reference": {"Id": ws["id"]}, "output": target_output}}})
435 '';
436 Restart = "on-failure";
437 RestartSec = 10;
438 };
439 };
333 440
334 programs.niri.scratchspaces = [ 441 programs.niri.scratchspaces = [
335 { name = "pwctl"; 442 { name = "pwctl";
@@ -343,8 +450,8 @@ in {
343 { title = "^Access Request.*"; } 450 { title = "^Access Request.*"; }
344 { title = ".*Passkey credentials$"; } 451 { title = ".*Passkey credentials$"; }
345 ]; 452 ];
346 windowRuleExtra = [ 453 windowRuleExtra = with kdl; [
347 (kdl.leaf "open-focused" false) 454 (sleaf "open-focused" false)
348 ]; 455 ];
349 key = "Mod+Control+P"; 456 key = "Mod+Control+P";
350 app-id = "org.keepassxc.KeePassXC"; 457 app-id = "org.keepassxc.KeePassXC";
@@ -371,6 +478,20 @@ in {
371 app-id = "com.github.wwmm.easyeffects"; 478 app-id = "com.github.wwmm.easyeffects";
372 spawn = [ "easyeffects" ]; 479 spawn = [ "easyeffects" ];
373 } 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 }
374 ]; 495 ];
375 programs.niri.config = 496 programs.niri.config =
376 let 497 let
@@ -380,10 +501,12 @@ in {
380 then v 501 then v
381 else null; 502 else null;
382 opt-props = lib.filterAttrs (lib.const (value: value != null)); 503 opt-props = lib.filterAttrs (lib.const (value: value != null));
504 normalize-nodes = nodes: lib.remove null (lib.flatten nodes);
383 in 505 in
384 [ (flag "prefer-no-csd") 506 normalize-nodes [
507 (flag "prefer-no-csd")
385 508
386 (leaf "screenshot-path" "~/screenshots/%Y-%m-%dT%H:%M:%S.png") 509 (sleaf "screenshot-path" "~/screenshots/%Y-%m-%dT%H:%M:%S.png")
387 510
388 (plain "hotkey-overlay" [ 511 (plain "hotkey-overlay" [
389 (flag "skip-at-startup") 512 (flag "skip-at-startup")
@@ -391,80 +514,88 @@ in {
391 514
392 (plain "input" [ 515 (plain "input" [
393 (plain "keyboard" [ 516 (plain "keyboard" [
394 (leaf "repeat-delay" 300) 517 (sleaf "repeat-delay" 300)
395 (leaf "repeat-rate" 50) 518 (sleaf "repeat-rate" 50)
396 519
397 (plain "xkb" [ 520 (plain "xkb" [
398 (leaf "layout" "us,us") 521 (sleaf "layout" "us,us")
399 (leaf "variant" "dvp,") 522 (sleaf "variant" "dvp,")
400 (leaf "options" "compose:caps,grp:win_space_toggle") 523 (sleaf "options" "compose:caps,grp:win_space_toggle")
401 ]) 524 ])
402 ]) 525 ])
403 526
404 (flag "workspace-auto-back-and-forth") 527 (flag "workspace-auto-back-and-forth")
405 # (leaf "focus-follows-mouse" {}) 528 # (sleaf "focus-follows-mouse" {})
406 # (flag "warp-mouse-to-focus") 529 # (flag "warp-mouse-to-focus")
407 530
408 # (plain "touchpad" [ (flag "off") ]) 531 # (plain "touchpad" [ (flag "off") ])
409 (plain "trackball" [ 532 (plain "trackball" [
410 (leaf "scroll-method" "on-button-down") 533 (sleaf "scroll-method" "on-button-down")
411 (leaf "scroll-button" 278) 534 (sleaf "scroll-button" 278)
412 ]) 535 ])
413 (plain "touch" [ 536 (plain "touch" [
414 (leaf "map-to-output" "eDP-1") 537 (sleaf "map-to-output" "eDP-1")
415 ]) 538 ])
416 ]) 539 ])
417 540
418 (plain "environment" (lib.mapAttrsToList leaf { 541 (plain "gestures" [
542 (plain "hot-corners" [(flag "off")])
543 ])
544
545 (plain "environment" (lib.mapAttrsToList sleaf {
419 NIXOS_OZONE_WL = "1"; 546 NIXOS_OZONE_WL = "1";
420 QT_QPA_PLATFORM = "wayland"; 547 QT_QPA_PLATFORM = "wayland";
421 QT_WAYLAND_DISABLE_WINDOWDECORATION = "1"; 548 QT_WAYLAND_DISABLE_WINDOWDECORATION = "1";
422 GDK_BACKEND = "wayland"; 549 GDK_BACKEND = "wayland";
423 SDL_VIDEODRIVER = "wayland"; 550 SDL_VIDEODRIVER = "wayland";
424 DISPLAY = ":0"; 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;
425 })) 556 }))
426 557
427 (node "output" "eDP-1" [ 558 (node "output" ["eDP-1"] [
428 (leaf "scale" 1.5) 559 (sleaf "scale" 1.5)
429 (leaf "position" { x = 0; y = 0; }) 560 (sleaf "position" { x = 0; y = 0; })
430 ]) 561 ])
431 (node "output" "Ancor Communications Inc ASUS PB287Q 0x0000DD9B" [ 562 (node "output" ["Ancor Communications Inc ASUS PB287Q 0x0000DD9B"] [
432 (leaf "scale" 1.5) 563 (sleaf "scale" 1.5)
433 (leaf "position" { x = 2560; y = 0; }) 564 (sleaf "position" { x = 2560; y = 0; })
434 ]) 565 ])
435 (node "output" "HP Inc. HP 727pu CN4417143K" [ 566 (node "output" ["HP Inc. HP 727pu CN4417143K"] [
436 (leaf "mode" "2560x1440@119.998") 567 (sleaf "mode" "2560x1440@119.998")
437 (leaf "scale" 1) 568 (sleaf "scale" 1)
438 (leaf "position" { x = 2560; y = 0; }) 569 (sleaf "position" { x = 2560; y = 0; })
439 (flag "variable-refresh-rate") 570 (flag "variable-refresh-rate")
440 ]) 571 ])
441 572
442 (plain "debug" [ 573 (plain "debug" [
443 (leaf "render-drm-device" "/dev/dri/by-path/pci-0000:00:02.0-render") 574 (sleaf "render-drm-device" "/dev/dri/by-path/pci-0000:00:02.0-render")
444 ]) 575 ])
445 576
446 (plain "animations" [ 577 (plain "animations" [
447 (leaf "slowdown" 0.5) 578 (sleaf "slowdown" 0.5)
448 (plain "workspace-switch" [(flag "off")]) 579 (plain "workspace-switch" [(flag "off")])
449 ]) 580 ])
450 581
451 (plain "layout" [ 582 (plain "layout" [
452 (leaf "gaps" 8) 583 (sleaf "gaps" 8)
453 (plain "struts" [ 584 (plain "struts" [
454 (leaf "left" 26) 585 (sleaf "left" 26)
455 (leaf "right" 26) 586 (sleaf "right" 26)
456 (leaf "top" 0) 587 (sleaf "top" 0)
457 (leaf "bottom" 0) 588 (sleaf "bottom" 0)
458 ]) 589 ])
459 (plain "border" [ 590 (plain "border" [
460 (leaf "width" 2) 591 (sleaf "width" 2)
461 (leaf "active-gradient" { 592 (sleaf "active-gradient" {
462 from = "hsla(195 100% 45% 1)"; 593 from = "hsla(195 100% 45% 1)";
463 to = "hsla(155 100% 37.5% 1)"; 594 to = "hsla(155 100% 37.5% 1)";
464 angle = 29; 595 angle = 29;
465 relative-to = "workspace-view"; 596 relative-to = "workspace-view";
466 }) 597 })
467 (leaf "inactive-gradient" { 598 (sleaf "inactive-gradient" {
468 from = "hsla(0 0% 27.7% 1)"; 599 from = "hsla(0 0% 27.7% 1)";
469 to = "hsla(0 0% 23% 1)"; 600 to = "hsla(0 0% 23% 1)";
470 angle = 29; 601 angle = 29;
@@ -475,29 +606,29 @@ in {
475 (flag "off") 606 (flag "off")
476 ]) 607 ])
477 608
478 (plain "preset-column-widths" (map (prop: leaf "proportion" prop) [ 609 (plain "preset-column-widths" (map (prop: sleaf "proportion" prop) [
479 (1. / 4.) (1. / 3.) (1. / 2.) (2. / 3.) (3. / 4.) (1.) 610 (1. / 4.) (1. / 3.) (1. / 2.) (2. / 3.) (3. / 4.) (1.)
480 ])) 611 ]))
481 (plain "default-column-width" [ (leaf "proportion" (1. / 2.)) ]) 612 (plain "default-column-width" [ (sleaf "proportion" (1. / 2.)) ])
482 (plain "preset-window-heights" (map (prop: leaf "proportion" prop) [ 613 (plain "preset-window-heights" (map (prop: sleaf "proportion" prop) [
483 (1. / 3.) (1. / 2.) (2. / 3.) (1.) 614 (1. / 3.) (1. / 2.) (2. / 3.) (1.)
484 ])) 615 ]))
485 616
486 (flag "always-center-single-column") 617 (flag "always-center-single-column")
487 618
488 (plain "tab-indicator" [ 619 (plain "tab-indicator" [
489 (leaf "gap" 4) 620 (sleaf "gap" 4)
490 (leaf "width" 8) 621 (sleaf "width" 8)
491 (leaf "gaps-between-tabs" 4) 622 (sleaf "gaps-between-tabs" 4)
492 (flag "place-within-column") 623 (flag "place-within-column")
493 (leaf "length" { total-proportion = 1.; }) 624 (sleaf "length" { total-proportion = 1.; })
494 (leaf "active-gradient" { 625 (sleaf "active-gradient" {
495 from = "hsla(195 100% 60% 0.75)"; 626 from = "hsla(195 100% 60% 0.75)";
496 to = "hsla(155 100% 50% 0.75)"; 627 to = "hsla(155 100% 50% 0.75)";
497 angle = 29; 628 angle = 29;
498 relative-to = "workspace-view"; 629 relative-to = "workspace-view";
499 }) 630 })
500 (leaf "inactive-gradient" { 631 (sleaf "inactive-gradient" {
501 from = "hsla(0 0% 42% 0.66)"; 632 from = "hsla(0 0% 42% 0.66)";
502 to = "hsla(0 0% 35% 0.66)"; 633 to = "hsla(0 0% 35% 0.66)";
503 angle = 29; 634 angle = 29;
@@ -511,129 +642,140 @@ in {
511 ]) 642 ])
512 643
513 (map (name: 644 (map (name:
514 (node "workspace" name [ 645 (node "workspace" [name] [
515 (leaf "open-on-output" "eDP-1") 646 (sleaf "open-on-output" "eDP-1")
516 ]) 647 ])
517 ) (map ({name, ...}: name) cfg.scratchspaces)) 648 ) (map ({name, ...}: name) cfg.scratchspaces))
518 (map (name: 649 (map (name:
519 (leaf "workspace" name) 650 (sleaf "workspace" name)
520 ) ["comm" "web" "vid" "bmr"]) 651 ) ["comm" "web" "vid" "bmr"])
521 652
522 (plain "window-rule" [ 653 (plain "window-rule" [
523 (leaf "clip-to-geometry" true) 654 (sleaf "clip-to-geometry" true)
524 ]) 655 ])
525 656
526 (plain "window-rule" [ 657 (plain "window-rule" [
527 (leaf "match" { is-floating = true; }) 658 (sleaf "match" { is-floating = true; })
528 (leaf "geometry-corner-radius" 8) 659 (sleaf "geometry-corner-radius" 8)
529 (plain "shadow" [ (flag "on") ]) 660 (plain "shadow" [ (flag "on") ])
530 ]) 661 ])
531 662
532 (plain "window-rule" [ 663 (plain "window-rule" [
533 (leaf "match" { app-id = "^org\\.keepassxc\\.KeePassXC$"; }) 664 (sleaf "match" { app-id = "^org\\.keepassxc\\.KeePassXC$"; })
534 (leaf "block-out-from" "screencast") 665 (sleaf "block-out-from" "screencast")
535 ]) 666 ])
536 (plain "window-rule" [ 667 (plain "window-rule" (normalize-nodes [
537 (map (title: 668 (map (title:
538 (leaf "match" { app-id = "^org\\.keepassxc\\.KeePassXC$"; inherit title; }) 669 (sleaf "match" { app-id = "^org\\.keepassxc\\.KeePassXC$"; inherit title; })
539 ) ["^Unlock Database.*" "^Access Request.*" ".*Passkey credentials$"]) 670 ) ["^Unlock Database.*" "^Access Request.*" ".*Passkey credentials$" "Browser Access Request$"])
540 (leaf "open-focused" true) 671 (sleaf "open-focused" true)
541 (leaf "open-floating" true) 672 (sleaf "open-floating" true)
542 ]) 673 ]))
543 674
544 (map ({ name, match, exclude, windowRuleExtra, ... }: 675 (map ({ name, match, exclude, windowRuleExtra, ... }:
545 (optional-node (match != []) (plain "window-rule" [ 676 (optional-node (match != []) (plain "window-rule" (normalize-nodes [
546 (map (leaf "match") match) 677 (map (sleaf "match") match)
547 (map (leaf "exclude") exclude) 678 (map (sleaf "exclude") exclude)
548 (leaf "open-on-workspace" name) 679 (sleaf "open-on-workspace" name)
549 (leaf "open-maximized" true) 680 (sleaf "open-maximized" true)
550 windowRuleExtra 681 windowRuleExtra
551 ])) 682 ])))
552 ) cfg.scratchspaces) 683 ) cfg.scratchspaces)
553 684
554 (plain "window-rule" [ 685 (plain "window-rule" [
555 (leaf "match" { app-id = "^emacs$"; }) 686 (sleaf "match" { app-id = "^emacs$"; })
556 (leaf "match" { app-id = "^firefox$"; }) 687 (sleaf "match" { app-id = "^firefox$"; })
557 (plain "default-column-width" [(leaf "proportion" (2. / 3.))]) 688 (plain "default-column-width" [(sleaf "proportion" (2. / 3.))])
558 ]) 689 ])
559 (plain "window-rule" [ 690 (plain "window-rule" [
560 (leaf "match" { app-id = "^kitty$"; }) 691 (sleaf "match" { app-id = "^kitty$"; })
561 (leaf "match" { app-id = "^kitty-play$"; }) 692 (sleaf "match" { app-id = "^kitty-play$"; })
562 (plain "default-column-width" [(leaf "proportion" (1. / 3.))]) 693 (plain "default-column-width" [(sleaf "proportion" (1. / 3.))])
563 ]) 694 ])
564 695
565 (plain "window-rule" [ 696 (plain "window-rule" [
566 (leaf "match" { app-id = "^thunderbird$"; }) 697 (sleaf "match" { app-id = "^thunderbird$"; })
567 (leaf "match" { app-id = "^Element$"; }) 698 (sleaf "match" { app-id = "^Element$"; })
568 (leaf "match" { app-id = "^Rainbow$"; }) 699 (sleaf "match" { app-id = "^chrome-web\.openrainbow\.com__-Default$"; })
569 (leaf "open-on-workspace" "comm") 700 (sleaf "open-on-workspace" "comm")
570 ]) 701 ])
571 (plain "window-rule" [ 702 (plain "window-rule" [
572 (leaf "match" { app-id = "^firefox$"; }) 703 (sleaf "match" { app-id = "^firefox$"; })
573 (leaf "open-on-workspace" "web") 704 (sleaf "open-on-workspace" "web")
574 (leaf "open-maximized" true) 705 (sleaf "open-maximized" true)
575 ]) 706 ])
576 (plain "window-rule" [ 707 (plain "window-rule" [
577 (leaf "match" { app-id = "^mpv$"; }) 708 (sleaf "match" { app-id = "^mpv$"; })
578 (leaf "open-on-workspace" "vid") 709 (sleaf "open-on-workspace" "vid")
579 (plain "default-column-width" [(leaf "proportion" 1.)]) 710 (plain "default-column-width" [(sleaf "proportion" 1.)])
580 ]) 711 ])
581 (plain "window-rule" [ 712 (plain "window-rule" [
582 (leaf "match" { app-id = "^kitty-play$"; }) 713 (sleaf "match" { app-id = "^kitty-play$"; })
583 (leaf "open-on-workspace" "vid") 714 (sleaf "open-on-workspace" "vid")
584 (leaf "open-focused" false) 715 (sleaf "open-focused" false)
585 ]) 716 ])
586 (plain "window-rule" [ 717 (plain "window-rule" [
587 (leaf "match" { app-id = "^pdfpc$"; }) 718 (sleaf "match" { app-id = "^chrome-audiobookshelf\.yggdrasil\.li__-Default$"; })
588 (plain "default-column-width" [(leaf "proportion" 1.)]) 719 (sleaf "match" { app-id = "^YouTube Music Desktop App$"; })
720 (sleaf "open-on-workspace" "vid")
589 ]) 721 ])
590 (plain "window-rule" [ 722 (plain "window-rule" [
591 (leaf "match" { app-id = "^pdfpc$"; title = "^.*presentation.*$"; }) 723 (sleaf "match" { app-id = "^pdfpc$"; })
592 (plain "default-column-width" [(leaf "proportion" 1.)]) 724 (plain "default-column-width" [(sleaf "proportion" 1.)])
593 (leaf "open-fullscreen" true)
594 (leaf "open-on-workspace" "bmr")
595 (leaf "open-focused" false)
596 ]) 725 ])
597 (plain "window-rule" [ 726 (plain "window-rule" [
598 (map (leaf "match") [ 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") [
599 { app-id = "^Gimp-"; title = "^Quit GIMP$"; } 735 { app-id = "^Gimp-"; title = "^Quit GIMP$"; }
600 { app-id = "^org\\.kde\\.polkit-kde-authentication-agent-1$"; } 736 { app-id = "^org\\.kde\\.polkit-kde-authentication-agent-1$"; }
601 { app-id = "^xdg-desktop-portal-gtk$"; } 737 { app-id = "^xdg-desktop-portal-gtk$"; }
602 ]) 738 ])
603 (leaf "open-floating" true) 739 (sleaf "open-floating" true)
604 ]) 740 ]))
605 (plain "window-rule" [ 741 (plain "window-rule" [
606 (leaf "match" { app-id = "^org\\.pwmt\\.zathura$"; }) 742 (sleaf "match" { app-id = "^org\\.pwmt\\.zathura$"; })
607 (leaf "match" { app-id = "^evince$"; }) 743 (sleaf "match" { app-id = "^evince$"; })
608 (leaf "match" { app-id = "^org\\.gnome\\.Papers$"; }) 744 (sleaf "match" { app-id = "^org\\.gnome\\.Papers$"; })
609 (leaf "default-column-display" "tabbed") 745 (sleaf "default-column-display" "tabbed")
610 ]) 746 ])
611 747
612 (plain "layer-rule" [ 748 (plain "layer-rule" [
613 (leaf "match" { namespace = "^notifications$"; }) 749 (sleaf "match" { namespace = "^notifications$"; })
614 (leaf "match" { namespace = "^waybar$"; }) 750 (sleaf "match" { namespace = "^waybar$"; })
615 (leaf "match" { namespace = "^launcher$"; }) 751 (sleaf "match" { namespace = "^launcher$"; })
616 (leaf "block-out-from" "screencast") 752 (sleaf "block-out-from" "screencast")
617 ]) 753 ])
618 754
619 (plain "binds" 755 (plain "binds"
620 (let 756 (let
621 bind = name: cfg: node name (opt-props { 757 bind = name: cfg: node name [(lib.removeAttrs cfg ["action"])] (lib.mapAttrsToList leaf (lib.removeAttrs cfg.action ["__functor"]));
622 cooldown-ms = cfg.cooldown-ms or null;
623 }
624 // (lib.optionalAttrs (!(cfg.repeat or true)) {
625 repeat = false;
626 })
627 // (lib.optionalAttrs (cfg.allow-when-locked or false) {
628 allow-when-locked = true;
629 })) (lib.mapAttrsToList leaf (lib.removeAttrs cfg.action ["__functor"]));
630 in 758 in
631 [ 759 normalize-nodes [
632 (lib.mapAttrsToList bind (with config.lib.niri.actions; { 760 (lib.mapAttrsToList bind (with config.lib.niri.actions; {
633 "Mod+Slash".action = show-hotkey-overlay; 761 "Mod+Slash".action = show-hotkey-overlay;
634 762
635 "Mod+Return".action = spawn terminal; 763 "Mod+Return".action = spawn terminal;
636 "Mod+Shift+Return".action = spawn terminal (lib.getExe config.programs.nushell.package); 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");
637 "Mod+Q".action = close-window; 779 "Mod+Q".action = close-window;
638 "Mod+O".action = spawn (lib.getExe config.programs.fuzzel.package); 780 "Mod+O".action = spawn (lib.getExe config.programs.fuzzel.package);
639 "Mod+Shift+O".action = spawn (lib.getExe config.programs.fuzzel.package) "--list-executables-in-path"; 781 "Mod+Shift+O".action = spawn (lib.getExe config.programs.fuzzel.package) "--list-executables-in-path";
@@ -669,12 +811,12 @@ in {
669 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) 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)
670 $FOUND || echo 812 $FOUND || echo
671 } 813 }
672 FUZZEL_RES=$(prev | fuzzel --dmenu --prompt "qalc> ") || exit $? 814 FUZZEL_RES=$(prev | fuzzel --dmenu --prompt "qalc> " --width=60) || exit $?
673 if [[ "$FUZZEL_RES" =~ .*\ =\ .* ]]; then 815 if [[ "$FUZZEL_RES" =~ .*\ =\ .* ]]; then
674 QALC_RES="$FUZZEL_RES" 816 QALC_RES="$FUZZEL_RES"
675 QALC_RET=0 817 QALC_RET=0
676 else 818 else
677 QALC_RES=$(qalc "$FUZZEL_RES" 2>&1) 819 QALC_RES=$(qalc -set "autocalc off" "$FUZZEL_RES" 2>&1)
678 QALC_RET=$? 820 QALC_RET=$?
679 fi 821 fi
680 [[ -n "$QALC_RES" ]] || exit 1 822 [[ -n "$QALC_RES" ]] || exit 1
@@ -694,18 +836,33 @@ in {
694 notify-send "$QALC_RES" 836 notify-send "$QALC_RES"
695 ''; 837 '';
696 })); 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");
697 "Mod+E".action = spawn (lib.getExe (pkgs.writeShellApplication { 854 "Mod+E".action = spawn (lib.getExe (pkgs.writeShellApplication {
698 name = "emoji-fuzzel"; 855 name = "emoji-fuzzel";
699 runtimeInputs = with pkgs; [ config.programs.fuzzel.package wtype wl-clipboard-rs ]; 856 runtimeInputs = with pkgs; [ config.programs.fuzzel.package wtype wl-clipboard-rs ];
700 text = '' 857 text = ''
701 FUZZEL_RES=$(fuzzel --dmenu --prompt "emoji> " <"$HOME"/.local/share/emoji-data/list.txt) || exit $? 858 FUZZEL_RES=$(fuzzel --dmenu --prompt "emoji> " --cache "$HOME"/.cache/fuzzel-emoji --width=60 <"$HOME"/.local/share/emoji-data/list.txt) || exit $?
702 [[ -n "$FUZZEL_RES" ]] || exit 1 859 [[ -n "$FUZZEL_RES" ]] || exit 1
703 wl-copy "$(cut -d ':' -f 1 <<<"$FUZZEL_RES" | tr -d '\n')" && wtype -k XF86Paste 860 wl-copy "$(cut -d ':' -f 1 <<<"$FUZZEL_RES" | tr -d '\n')" && wtype -k XF86Paste
704 ''; 861 '';
705 })); 862 }));
706 "Print".action = screenshot; 863 "Print".action = screenshot;
707 "Control+Print".action = screenshot-window; 864 "Control+Print".action = screenshot-window;
708 # "Shift+Print".action = screenshot-screen; 865 "Shift+Print".action = kdl.magic-leaf "screenshot-screen";
709 "Mod+B".action = with-select-window-action ".workspace_id == ($active_workspace | tonumber)" "{\"Action\":{\"FocusWindow\":{\"id\": .id}}}"; 866 "Mod+B".action = with-select-window-action ".workspace_id == ($active_workspace | tonumber)" "{\"Action\":{\"FocusWindow\":{\"id\": .id}}}";
710 "Mod+Shift+B".action = with-select-window-action "true" "{\"Action\":{\"FocusWindow\":{\"id\": .id}}}"; 867 "Mod+Shift+B".action = with-select-window-action "true" "{\"Action\":{\"FocusWindow\":{\"id\": .id}}}";
711 868
@@ -759,7 +916,7 @@ in {
759 "Mod+Shift+Asterisk".action = kdl.magic-leaf "move-column-to-workspace" "vid"; 916 "Mod+Shift+Asterisk".action = kdl.magic-leaf "move-column-to-workspace" "vid";
760 917
761 "Mod+Plus".action = with-unnamed-workspace-action ''{"Action":{"FocusWorkspace":{"reference":{"Id": .id}}}}''; 918 "Mod+Plus".action = with-unnamed-workspace-action ''{"Action":{"FocusWorkspace":{"reference":{"Id": .id}}}}'';
762 "Mod+Shift+Plus".action = with-unnamed-workspace-action ''{"Action":{"MoveColumnToWorkspace":{"reference":{"Id": .id}}}}''; 919 "Mod+Shift+Plus".action = with-unnamed-workspace-action ''{"Action":{"MoveColumnToWorkspace":{"reference":{"Id": .id}, "focus": true}}}'';
763 920
764 "Mod+M".action = consume-or-expel-window-left; 921 "Mod+M".action = consume-or-expel-window-left;
765 "Mod+W".action = consume-or-expel-window-right; 922 "Mod+W".action = consume-or-expel-window-right;
@@ -831,13 +988,20 @@ in {
831 "Mod+Comma".action = spawn makoctl "restore"; 988 "Mod+Comma".action = spawn makoctl "restore";
832 989
833 "Mod+Control+W".action = with-empty-unnamed-workspace-action "{\"Action\":{\"FocusWorkspace\":{\"reference\":{\"Id\": $workspace_id}}}}"; 990 "Mod+Control+W".action = with-empty-unnamed-workspace-action "{\"Action\":{\"FocusWorkspace\":{\"reference\":{\"Id\": $workspace_id}}}}";
834 "Mod+Control+Shift+W".action = with-empty-unnamed-workspace-action "{\"Action\":{\"MoveColumnToWorkspace\":{\"reference\":{\"Id\": $workspace_id}}}}"; 991 "Mod+Control+Shift+W".action = with-empty-unnamed-workspace-action "{\"Action\":{\"MoveColumnToWorkspace\":{\"reference\":{\"Id\": $workspace_id}, \"focus\": true}}}";
835 992
836 "Mod+X".action = set-dynamic-cast-window; 993 "Mod+X".action = set-dynamic-cast-window;
837 "Mod+Shift+X".action = set-dynamic-cast-monitor; 994 "Mod+Shift+X".action = set-dynamic-cast-monitor;
838 "Mod+Control+Shift+X".action = clear-dynamic-cast-target; 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");
839 })) 1002 }))
840 (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) 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)
841 ] 1005 ]
842 )) 1006 ))
843 ]; 1007 ];
diff --git a/accounts/gkleen@sif/niri/mako.nix b/accounts/gkleen@sif/niri/mako.nix
index 9373dc21..703d5f7b 100644
--- a/accounts/gkleen@sif/niri/mako.nix
+++ b/accounts/gkleen@sif/niri/mako.nix
@@ -14,16 +14,17 @@
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 criteria = { 18 grouped.format = "<b>(%g)</b> <i>%s</i>\\n%b";
19 grouped.format = "<b>(%g)</b> <i>%s</i>\n%b";
20 "urgency=low".text-color = "#999999ff"; 19 "urgency=low".text-color = "#999999ff";
21 "urgency=critical".background-color = "#900000dd"; 20 "urgency=critical".background-color = "#900000dd";
22 "app-name=Element".group-by = "summary"; 21 "app-name=Element".group-by = "summary";
23 "app-name=poweralertd" = { 22 "app-name=poweralertd" = {
23 history = false;
24 ignore-timeout = true; 24 ignore-timeout = true;
25 default-timeout = 2000; 25 default-timeout = 2000;
26 }; 26 };
27 "app-name=worktime".history = false;
27 "mode=silent".invisible = true; 28 "mode=silent".invisible = true;
28 }; 29 };
29 package = pkgs.symlinkJoin { 30 package = pkgs.symlinkJoin {
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 cc131c08..c02a9a76 100644
--- a/accounts/gkleen@sif/niri/waybar.nix
+++ b/accounts/gkleen@sif/niri/waybar.nix
@@ -27,8 +27,14 @@ in {
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" ];
@@ -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 90cccc58..18c2315f 100644
--- a/accounts/gkleen@sif/systemd.nix
+++ b/accounts/gkleen@sif/systemd.nix
@@ -385,6 +385,8 @@ in {
385 }; 385 };
386 Service = { 386 Service = {
387 ExecStart = "${config.systemd.package}/lib/systemd/systemd-socket-proxyd --exit-idle-time=60s 127.0.0.1:${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";
388 }; 390 };
389 }) [{ host = "proxy.ssh.math.lmu.de"; port = 8118; } { host = "proxy.vidhar"; port = 8120; } { host = "proxy.mathw0h"; port = 8122; } { host = "proxy.mathw0e"; port = 8124; }]); 391 }) [{ host = "proxy.ssh.math.lmu.de"; port = 8118; } { host = "proxy.vidhar"; port = 8120; } { host = "proxy.mathw0h"; port = 8122; } { host = "proxy.mathw0e"; port = 8124; }]);
390 sockets = listToAttrs (map (port: nameValuePair "proxy-to-autossh-socks@${toString port}" { 392 sockets = listToAttrs (map (port: nameValuePair "proxy-to-autossh-socks@${toString port}" {
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/zshrc b/accounts/gkleen@sif/zshrc
index abc200c6..702990c3 100644
--- a/accounts/gkleen@sif/zshrc
+++ b/accounts/gkleen@sif/zshrc
@@ -93,7 +93,7 @@ dir() {
93 if [[ $curlArchive = "true" ]]; then 93 if [[ $curlArchive = "true" ]]; then
94 archiveFile=$(mktemp -t "archive.XXXXXXXXXX.${templateArchive:t}") 94 archiveFile=$(mktemp -t "archive.XXXXXXXXXX.${templateArchive:t}")
95 95
96 curl -L -o ${archiveFile} ${templateArchive} 96 curl -SfL -o ${archiveFile} ${templateArchive}
97 97
98 templateArchive=${archiveFile} 98 templateArchive=${archiveFile}
99 fi 99 fi
@@ -132,6 +132,10 @@ dir() {
132 unpack=false 132 unpack=false
133 fi 133 fi
134 ;; 134 ;;
135 application/x-iso9660-image)
136 7z x ${templateArchive}
137 unpack=false
138 ;;
135 *) 139 *)
136 tar -xvaf ${templateArchive} 140 tar -xvaf ${templateArchive}
137 unpack=false 141 unpack=false
@@ -231,7 +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} 239}
236 240
237swap() { 241swap() {