summaryrefslogtreecommitdiff
path: root/accounts
diff options
context:
space:
mode:
Diffstat (limited to 'accounts')
-rw-r--r--accounts/gkleen@sif/autorandr-profiles/bstr.nix21
-rw-r--r--accounts/gkleen@sif/autorandr-profiles/default.nix13
-rw-r--r--accounts/gkleen@sif/backup-patterns24
-rw-r--r--accounts/gkleen@sif/default.nix188
-rw-r--r--accounts/gkleen@sif/dunst-settings.nix64
-rw-r--r--accounts/gkleen@sif/emacs.el111
-rw-r--r--accounts/gkleen@sif/firefox-chrome.css25
-rw-r--r--accounts/gkleen@sif/firefox-content.css12
-rw-r--r--accounts/gkleen@sif/ssh-hosts.nix190
-rw-r--r--accounts/gkleen@sif/store.kdbx.lftp6
-rw-r--r--accounts/gkleen@sif/systemd.nix94
-rw-r--r--accounts/gkleen@sif/xmobar/default.nix7
-rw-r--r--accounts/gkleen@sif/xmobar/nixpkgs.nix9
-rw-r--r--accounts/gkleen@sif/xmobar/package.yaml13
-rw-r--r--accounts/gkleen@sif/xmobar/shell.nix28
-rw-r--r--accounts/gkleen@sif/xmobar/stack.nix17
-rw-r--r--accounts/gkleen@sif/xmobar/stack.yaml10
-rw-r--r--accounts/gkleen@sif/xmobar/stack.yaml.lock12
-rw-r--r--accounts/gkleen@sif/xmobar/stackage.nix31
-rw-r--r--accounts/gkleen@sif/xmobar/xmobar-yggdrasil.nix13
-rw-r--r--accounts/gkleen@sif/xmobar/xmobar.hs52
-rw-r--r--accounts/gkleen@sif/xmonad/.gitignore4
-rw-r--r--accounts/gkleen@sif/xmonad/default.nix7
-rw-r--r--accounts/gkleen@sif/xmonad/lib/XMonad/Mpv.hs127
-rw-r--r--accounts/gkleen@sif/xmonad/lib/XMonad/Prompt/MyPass.hs94
-rw-r--r--accounts/gkleen@sif/xmonad/lib/XMonad/Prompt/MyShell.hs105
-rw-r--r--accounts/gkleen@sif/xmonad/lib/XMonad/Prompt/MySsh.hs243
-rw-r--r--accounts/gkleen@sif/xmonad/package.yaml30
-rw-r--r--accounts/gkleen@sif/xmonad/stack.nix17
-rw-r--r--accounts/gkleen@sif/xmonad/stack.yaml10
-rw-r--r--accounts/gkleen@sif/xmonad/xmonad-yggdrasil.nix21
-rw-r--r--accounts/gkleen@sif/xmonad/xmonad.hs898
-rw-r--r--accounts/gkleen@sif/xresources.nix46
-rw-r--r--accounts/gkleen@sif/zshrc403
-rw-r--r--accounts/root@sif.nix18
35 files changed, 2963 insertions, 0 deletions
diff --git a/accounts/gkleen@sif/autorandr-profiles/bstr.nix b/accounts/gkleen@sif/autorandr-profiles/bstr.nix
new file mode 100644
index 00000000..527f8321
--- /dev/null
+++ b/accounts/gkleen@sif/autorandr-profiles/bstr.nix
@@ -0,0 +1,21 @@
1{
2 fingerprint = {
3 "eDP-1-1" = "00ffffffffffff004c83414100000000131d0104b5221378029491ae513eb7240b505400000001010101010101010101010101010101f0d40040f17018803020440058c21000001bf0d40040f17018803020440058c21000001b0000000f00ff093cff093c2c800000000000000000fe0041544e413536575230382d3020011502030f00e3058000e6060501736d0700000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000ab";
4 "DP-1.3" = "00ffffffffffff000469a3289bdd00000b190104a53e22783a1cb5a3574fa0270d5054bfef00d1c0814081809500b300714f81c0010122cc0050f0703e80181035006d552100001a04740030f2705a80b0588a006d552100001a000000fd001e5018a03c041100f0f838f03c000000fc0041535553205042323837510a2001a8020327714f0102031112130414051f900e0f1d1e23091707830100006a030c0010000078200000565e00a0a0a02950302035006d552100001ee26800a0a0402e60302036006d552100001a011d00bc52d01e20b82855406d552100001e8c0ad090204031200c4055006d55210000180000000000000000000000000000000064";
5 };
6 config = {
7 "DP-1.3" = {
8 enable = true;
9 primary = true;
10 position = "3840x0";
11 rate = "60";
12 mode = "3840x2160";
13 };
14 eDP-1-1 = {
15 enable = true;
16 primary = false;
17 position = "0x0";
18 mode = "3840x2160";
19 };
20 };
21}
diff --git a/accounts/gkleen@sif/autorandr-profiles/default.nix b/accounts/gkleen@sif/autorandr-profiles/default.nix
new file mode 100644
index 00000000..304b4afe
--- /dev/null
+++ b/accounts/gkleen@sif/autorandr-profiles/default.nix
@@ -0,0 +1,13 @@
1{
2 fingerprint = {
3 eDP-1-1 = "00ffffffffffff004c83414100000000131d0104b5221378029491ae513eb7240b505400000001010101010101010101010101010101f0d40040f17018803020440058c21000001bf0d40040f17018803020440058c21000001b0000000f00ff093cff093c2c800000000000000000fe0041544e413536575230382d3020011502030f00e3058000e6060501736d0700000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000ab";
4 };
5 config = {
6 eDP-1-1 = {
7 enable = true;
8 primary = true;
9 position = "0x0";
10 mode = "3840x2160";
11 };
12 };
13}
diff --git a/accounts/gkleen@sif/backup-patterns b/accounts/gkleen@sif/backup-patterns
new file mode 100644
index 00000000..d9d12f5b
--- /dev/null
+++ b/accounts/gkleen@sif/backup-patterns
@@ -0,0 +1,24 @@
1R .
2
3- pp:.cache
4- pp:.antigen
5+ pf:.cabal/config
6- pp:.cabal
7+ pf:.stack/config.yaml
8- pp:.stack
9- pp:.nox
10- pp:.local/share/Steam
11- sh:**/.stack-work
12- sh:**/.~lock.*
13- sh:**/.gup
14+ pf:.config/pulse/default.pa
15- pp:.config/pulse
16- pp:.zplug/log
17- pp:.zplug/cache
18- pp:.compose-cache
19- pp:.undo-tree
20- pp:.saves
21- pp:.mozilla
22- pp:Downloads/tmp
23- pp:secret
24- pp:mail \ No newline at end of file
diff --git a/accounts/gkleen@sif/default.nix b/accounts/gkleen@sif/default.nix
new file mode 100644
index 00000000..545d40b5
--- /dev/null
+++ b/accounts/gkleen@sif/default.nix
@@ -0,0 +1,188 @@
1{ flake, userName, pkgs, customUtils, lib, config, ... }@inputs:
2let
3 cfg = config.home-manager.users.${userName};
4 xmonad = import ./xmonad pkgs.haskellPackages;
5in {
6 imports = with flake.nixosModules.userProfiles.${userName}; [
7 mpv
8 ];
9
10 home-manager.users.${userName} = {
11 programs = {
12 ssh = {
13 matchBlocks = import ./ssh-hosts.nix; # customUtils.recImport { dir = ./ssh-hosts; };
14 extraConfig = ''
15 Match host uniworx3.ifi.lmu.de,uniworx4.ifi.lmu.de,uni2workgw.ifi.lmu.de,blackbeard.tcs.ifi.lmu.de,gitlab2.rz.ifi.lmu.de,oregon.tcs.ifi.lmu.de !exec "nc -z -w 1 %h %p &>/dev/null"
16 ProxyJump gate
17 '';
18 };
19
20 emacs = {
21 enable = true;
22 extraPackages = epkgs: with epkgs; [
23 evil evil-dvorak evil-magit undo-tree magit haskell-mode
24 nix-mode yaml-mode json-mode shakespeare-mode
25 smart-mode-line highlight-parentheses highlight-symbol
26 notmuch ag sass-mode lua-mode fira-code-mode
27 ];
28 };
29 firefox = {
30 enable = true;
31 profiles.default = {
32 settings = {
33 "layout.css.devPixelsPerPx" = "1.75";
34 "browser.tabs.drawInTitlebar" = false;
35 "toolkit.legacyUserProfileCustomizations.stylesheets" = true;
36 };
37 };
38 };
39
40 urxvt = {
41 enable = true;
42 package = pkgs.rxvt_unicode-with-plugins;
43 fonts = [ "xft:FiraCode Nerd Font Mono:style=Regular:pixelsize=21" ];
44 scroll = {
45 lines = 0;
46 bar.enable = false;
47 };
48 extraConfig = {
49 urgentOnBell = false;
50 print-pipe = "cat >/dev/null";
51 perl-ext-common = "52-osc,url-select";
52 "url-select.launcher" = "firefox";
53 "url-select.underline" = true;
54 };
55 keybindings = {
56 "M-u" = "perl:url-select:select_next";
57 };
58 };
59
60 zathura = {
61 enable = true;
62 package = pkgs.zathura.override { useMupdf = false; };
63 };
64
65 mpv.config = {
66 demuxer-max-bytes = 1073741824;
67 demuxer-max-back-bytes = 268435456;
68 };
69
70 autorandr = {
71 enable = true;
72 hooks.postswitch = {
73 # "restart-compton" = "${pkgs.systemd}/bin/systemctl --user try-restart picom";
74 "restart-trays" = ''
75 ${pkgs.coreutils}/bin/sleep 5
76 ${pkgs.systemd}/bin/systemctl --user try-restart trayer xmobar
77 '';
78 };
79 profiles = customUtils.recImport { dir = ./autorandr-profiles; };
80 };
81
82 zsh.initExtra = "source ${./zshrc}";
83 };
84
85 services = {
86 dunst = {
87 settings = import ./dunst-settings.nix;
88 iconTheme = cfg.gtk.iconTheme;
89 enable = true;
90 };
91 emacs.enable = true;
92 gpg-agent = {
93 enable = true;
94 enableSshSupport = true;
95 extraConfig = ''
96 pinentry-program ${pkgs.pinentry-gtk2}/bin/pinentry
97 grab
98 '';
99 };
100 pasystray.enable = true;
101 udiskie = {
102 enable = true;
103 automount = false;
104 };
105 unclutter = {
106 enable = true;
107 timeout = 5;
108 };
109 network-manager-applet.enable = true;
110 blueman-applet.enable = true;
111
112 sxhkd = {
113 enable = true;
114 keybindings = {
115 "button8" = "pacmd set-source-mute @DEFAULT_SOURCE@ 0";
116 "@button8" = "pacmd set-source-mute @DEFAULT_SOURCE@ 1";
117 "button9" = "pacmd set-sink-mute @DEFAULT_SINK@ 1";
118 "@button9" = "pacmd set-sink-mute @DEFAULT_SINK@ 0";
119 };
120 };
121 };
122
123 gtk = {
124 enable = true;
125 font.name = "DejaVu Sans 6";
126 theme = {
127 package = pkgs.equilux-theme;
128 name = "Equilux-compact";
129 };
130 iconTheme = {
131 package = pkgs.paper-icon-theme;
132 name = "Paper";
133 };
134 };
135
136 xsession = {
137 enable = true;
138
139 windowManager.command = "${xmonad}/bin/xmonad";
140
141 initExtra = let
142 lockScript = pkgs.writeScript "lock" ''
143 #!${pkgs.stdenv.shell}
144 ${pkgs.playerctl}/bin/playerctl -a pause
145 exec ${pkgs.xsecurelock}/bin/xsecurelock
146 '';
147 in ''
148 ${pkgs.coreutils}/bin/env XSECURELOCK_WANT_FIRST_KEYPRESS=1 XSECURELOCK_DIM_ALPHA=1 ${pkgs.xss-lock}/bin/xss-lock -l -n ${pkgs.xsecurelock}/libexec/xsecurelock/dimmer -- ${lockScript} &
149 ${pkgs.xorg.xinput}/bin/xinput disable 'SynPS/2 Synaptics TouchPad' # Synaptics TM3512-010
150 ${pkgs.xorg.xset}/bin/xset s 590 10
151 '';
152 };
153
154 xresources.properties = import ./xresources.nix;
155
156 home = {
157 packages = with pkgs; [
158 fira-code powerline-fonts nerdfonts pavucontrol keepassxc
159 youtube-dl sxiv xclip mumble pulseaudio-ctl libnotify synergy
160 xorg.xbacklight screen-message pidgin-with-plugins
161 google-play-music-desktop-player qt5ct playerctl evince
162 thunderbird zulip zoom-us steam steam-run wireshark skype
163 virt-manager rclone cached-nix-shell xournal discord xmonad
164 worktime fira-code-symbols
165 ];
166
167 file = {
168 ".emacs".source = ./emacs.el;
169 ".backup-munin".source = ./backup-patterns;
170 ".mozilla/firefox/default/chrome/userChrome.css".source = ./firefox-chrome.css;
171 ".mozilla/firefox/default/chrome/userContent.css".source = ./firefox-content.css;
172 };
173
174 sessionVariables = {
175 GDK_SCALE = 96.0 / 282.0;
176 XDG_DATA_DIRS = "${pkgs.gsettings-desktop-schemas}/share/gsettings-schemas/${pkgs.gsettings-desktop-schemas.name}:${pkgs.gtk3}/share/gsettings-schemas/${pkgs.gtk3.name}:$XDG_DATA_DIRS";
177 QT_AUTO_SCREEN_SCALE_FACTOR = 1;
178 QT_QPA_PLATFORMTHEME = "qt5ct";
179 };
180
181 stateVersion = "20.03";
182 };
183
184 fonts.fontconfig.enable = true;
185
186 systemd.user = import ./systemd.nix inputs;
187 };
188}
diff --git a/accounts/gkleen@sif/dunst-settings.nix b/accounts/gkleen@sif/dunst-settings.nix
new file mode 100644
index 00000000..8319da03
--- /dev/null
+++ b/accounts/gkleen@sif/dunst-settings.nix
@@ -0,0 +1,64 @@
1{
2 global = {
3 font = "Monospace 6";
4 markup = "full";
5 format = "<i>%s</i> %p\\n%b";
6 alignment = "left";
7 geometry = "1216x10-32+64";
8 shrink = true;
9 monitor = 0;
10 follow = "none";
11 padding = 6;
12 horizontal_padding = 6;
13 separator_height = 1;
14 separator_color = "frame";
15 idle_threshold = 0;
16
17 transparency = 10;
18
19 frame_width = 1;
20 frame_color = "#999999";
21
22 word_wrap = true;
23 show_age_threshold = 15;
24 show_indicators = false;
25 icon_position = "right";
26 sort = false;
27 sticky_history = false;
28 };
29 shortcuts = {
30 close = "ctrl+space";
31 close_all = "ctrl+shift+space";
32 history = "ctrl+comma";
33 context = "ctrl+period";
34 };
35 urgency_low = {
36 background = "#000000";
37 foreground = "#999999";
38 timeout = 5;
39 };
40 urgency_normal = {
41 background = "#000000";
42 foreground = "#ffffff";
43 timeout = 15;
44 };
45 urgency_critical = {
46 background = "#900000";
47 foreground = "#ffffff";
48 timeout = 0;
49 };
50 pulseaudio-ctl = {
51 summary = "Volume *";
52 body = "Current is *";
53 set_stack_tag = "volume";
54 history_ignore = true;
55 };
56 mail = {
57 appname = "notmuch";
58 timeout = 0;
59 };
60 zulip = {
61 appname = "Zulip";
62 timeout = 0;
63 };
64}
diff --git a/accounts/gkleen@sif/emacs.el b/accounts/gkleen@sif/emacs.el
new file mode 100644
index 00000000..92a79910
--- /dev/null
+++ b/accounts/gkleen@sif/emacs.el
@@ -0,0 +1,111 @@
1(menu-bar-mode -1)
2(scroll-bar-mode -1)
3(tool-bar-mode -1)
4
5(set-face-attribute 'default nil :font "FiraCode Nerd Font Mono" :height 49)
6
7(require 'evil)
8(evil-mode 1)
9(setq evil-undo-system 'undo-tree)
10
11(global-subword-mode)
12(global-undo-tree-mode)
13(global-fira-code-mode)
14
15(global-set-key (kbd "RET") 'newline-and-indent)
16(global-set-key (kbd "M-g") 'magit-status)
17(global-set-key (kbd "M-?") 'vc-git-grep)
18
19(setq backup-directory-alist `(("." . "~/.saves")))
20(setq delete-old-versions t
21 kept-new-versions 6
22 kept-old-versions 2
23 version-control t)
24
25(setq undo-tree-visualizer-timestamps t
26 undo-tree-visualizer-diff t
27 ;; 10X bump of the undo limits to avoid issues with premature
28 ;; Emacs GC which truncages the undo history very aggresively
29 undo-limit 800000
30 undo-strong-limit 12000000
31 undo-outer-limit 120000000)
32
33(add-hook 'haskell-mode-hook 'haskell-indentation-mode)
34(add-hook 'haskell-mode-hook 'subword-mode)
35(add-hook 'haskell-mode-hook 'highlight-symbol-mode)
36(add-hook 'haskell-mode-hook 'highlight-paretheses-mode)
37
38(add-hook 'js-mode-hook 'highlight-symbol-mode)
39(add-hook 'js-mode-hook 'highlight-parentheses-mode)
40(defun my-js-mode-hook ()
41 "Custom `js-mode' behaviours."
42 (setq js-indent-level 2)
43 )
44(add-hook 'js-mode-hook 'my-js-mode-hook)
45
46(setq undo-tree-auto-save-history t)
47
48(setq notmuch-address-internal-completion '(received nil))
49(setq notmuch-always-prompt-for-sender t)
50(setq notmuch-command "notmuch-ssh")
51(setq notmuch-crypto-process-mime t)
52(setq notmuch-draft-tags '("+draft" "-inbox"))
53(setq notmuch-fcc-dirs nil)
54(setq notmuch-hello-sections '(notmuch-hello-insert-header notmuch-hello-insert-saved-searches))
55(setq notmuch-hello-thousands-separator " ")
56(setq notmuch-identities '("gkleen@yggdrasil.li" "g@141.li" "kleen@cip.ifi.lmu.de" "Gregor.Kleen@stud.ifi.lmu.de" "G.Kleen@campus.lmu.de" "G.Kleen@lmu.de" "gregor.kleen@ifi.lmu.de" "uni2work@ifi.lmu.de" "gregor@kleen.li"))
57(setq notmuch-message-headers '("Subject" "To" "Cc" "Date"))
58(setq notmuch-message-replied-tags '("+replied" "-unread" "-inbox"))
59(setq notmuch-saved-searches
60 (quote
61 ((:name "inbox" :query "tag:inbox" :key "i")
62 (:name "unread" :query "tag:unread AND tag:inbox" :key "u")
63 (:name "drafts" :query "tag:draft" :key "d")
64 (:name "all mail" :query "date:month.." :key "a" :count-query "*")
65 (:name "sent" :query "is:sent" :key "s" :count-query "is:sent")
66 )))
67(setq notmuch-search-oldest-first nil)
68(setq notmuch-show-all-tags-list t)
69(setq notmuch-show-logo nil)
70
71(setq send-mail-function 'sendmail-send-it)
72(setq mail-envelope-from 'header)
73(setq mail-specify-envelope-from 't)
74(setq mail-default-headers nil)
75(setq message-default-headers "")
76(setq message-default-mail-headers "")
77(setq message-sendmail-envelope-from 'header)
78
79(setq highlight-symbol-idle-delay 0)
80
81(setq indent-tabs-mode nil)
82
83(setq ido-enable-flex-matching t)
84(setq ido-everywhere t)
85(ido-mode 1)
86
87(setq mail-host-address "sif.midgard.yggdrasil")
88(setq user-full-name "Gregor Kleen")
89
90(defun tell-emacsclients-for-buffer-to-die ()
91 "Sends error exit command to every client for the current buffer."
92 (interactive)
93 (dolist (proc server-buffer-clients)
94 (server-send-string proc "-error die")))
95
96(defun kill-buffer-with-special-emacsclient-handling ()
97 "Wrapper around kill-buffer that ensures tell-emacsclients-for-buffer-to-die is on the hooks"
98 (interactive)
99 (add-hook 'kill-buffer-hook 'tell-emacsclients-for-buffer-to-die nil t)
100 (kill-buffer))
101
102;; (global-set-key (kbd "C-x k") 'kill-buffer)
103
104(defun install-emacsclient-wrapped-kill-buffer ()
105 "Installs wrapped kill-buffer with special emacsclient handling.
106Best not to install it unconditionally because the server is not
107necessarily running."
108 (interactive)
109 (global-set-key (kbd "C-x k") 'kill-buffer-with-special-emacsclient-handling))
110
111(add-hook 'server-switch-hook 'install-emacsclient-wrapped-kill-buffer)
diff --git a/accounts/gkleen@sif/firefox-chrome.css b/accounts/gkleen@sif/firefox-chrome.css
new file mode 100644
index 00000000..2d359771
--- /dev/null
+++ b/accounts/gkleen@sif/firefox-chrome.css
@@ -0,0 +1,25 @@
1@namespace url("http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul");
2
3* {
4 font-size:12px;
5}
6
7#sidebar {
8 min-width:20em !important;
9 max-width:20em !important;
10 border-right:1px solid rgba(30,30,30) !important;
11}
12
13#sidebar-header:nth-last-child(2) > *:last-child {
14 visibility: collapse;
15}
16
17#sidebar-splitter {
18 visibility: collapse;
19}
20
21#toolbar-menubar[inactive="true"] + #TabsToolbar {
22 visibility: collapse !important;
23}
24
25#sidebar-box[sidebarcommand="tabcenter-reborn_ariasuni-sidebar-action"] #sidebar-header { visibility: collapse !important; }
diff --git a/accounts/gkleen@sif/firefox-content.css b/accounts/gkleen@sif/firefox-content.css
new file mode 100644
index 00000000..3ac53a9d
--- /dev/null
+++ b/accounts/gkleen@sif/firefox-content.css
@@ -0,0 +1,12 @@
1@-moz-document url("about:blank") {
2 html {
3 background-color: rgb(40,40,40);
4 }
5}
6
7@-moz-document url(about:newtab) {
8 body, #newtab-customize-overlay {
9 background-color: rgb(40,40,40) !important;
10 color: rgb(166,166,166) !important;
11 }
12}
diff --git a/accounts/gkleen@sif/ssh-hosts.nix b/accounts/gkleen@sif/ssh-hosts.nix
new file mode 100644
index 00000000..ffbd8c00
--- /dev/null
+++ b/accounts/gkleen@sif/ssh-hosts.nix
@@ -0,0 +1,190 @@
1{
2 "git.ymir" =
3 { hostname = "ymir.yggdrasil.li";
4 user = "gitolite";
5 identityFile = "~/.ssh/gkleen@sif.midgard.yggdrasil";
6 };
7 "git.yggdrasil.li" =
8 { user = "gitolite";
9 identityFile = "~/.ssh/gkleen@sif.midgard.yggdrasil";
10 };
11 "git.rheperire.org" =
12 { user = "gitolite";
13 identityFile = "~/.ssh/gkleen@sif.midgard.yggdrasil";
14 };
15 "borg.munin" =
16 { hostname = "u120515.your-storagebox.de";
17 user = "u120515";
18 identityFile = "~/.ssh/borg.munin";
19 port = 23;
20 };
21 "munin" =
22 { hostname = "u120515.your-storagebox.de";
23 user = "u120515";
24 identityFile = "~/.ssh/munin";
25 };
26 "ymir" =
27 { hostname = "ymir.yggdrasil.li";
28 identityFile = "~/.ssh/gkleen@sif.midgard.yggdrasil";
29 };
30 "odin" =
31 { hostname = "odin.asgard.yggdrasil";
32 identityFile = "~/.ssh/gkleen@sif.midgard.yggdrasil";
33 };
34 "init.odin" =
35 { hostname = "odin.asgard.yggdrasil";
36 user = "root";
37 identityFile = "~/.ssh/rsa.gkleen@hel.midgard.yggdrasil";
38 extraOptions = {
39 StrictHostKeyChecking = "off";
40 };
41 };
42 "heimdallr" =
43 { hostname = "heimdallr.asgard.yggdrasil";
44 user = "root";
45 identityFile = "~/.ssh/gkleen@sif.midgard.yggdrasil";
46 };
47 "gitlab2.rz.ifi.lmu.de" =
48 { user = "git";
49 identityFile = "~/.ssh/gkleen@gitlab2.rz.ifi.lmu.de";
50 };
51 "gitlab2.cip.ifi.lmu.de" =
52 { user = "git";
53 identityFile = "~/.ssh/gkleen@sif.midgard.yggdrasil";
54 };
55 "hel".hostname = "hel.midgard.yggdrasil";
56 "blackbeard" =
57 { hostname = "blackbeard.tcs.ifi.lmu.de";
58 user = "pi";
59 identityFile = "~/.ssh/blackbeard";
60 };
61 "github.com" =
62 { user = "git";
63 identityFile = "~/.ssh/gkleen@github.com";
64 };
65 "ullr.playat.ch" =
66 { hostname = "ullr.playat.ch";
67 user = "minecraft";
68 identityFile = "~/.ssh/minecraft@ullr.playat.ch";
69 };
70 "ullr" =
71 { hostname = "185.170.112.70";
72 identityFile = "~/.ssh/gkleen@sif.midgard.yggdrasil";
73 };
74 "testworx" =
75 { hostname = "testworx.tcs.ifi.lmu.de";
76 user = "root";
77 port = 30363;
78 identityFile = "~/.ssh/testworx";
79 };
80 "remote.cip.ifi.lmu.de".user = "kleen";
81 "uniworx3" =
82 { hostname = "uniworx3.ifi.lmu.de";
83 user = "root";
84 identityFile = "~/.ssh/uni2work";
85 };
86 "uniworx4" =
87 { hostname = "uniworx4.ifi.lmu.de";
88 user = "root";
89 identityFile = "~/.ssh/uni2work";
90 };
91 "uni2workgw" =
92 { hostname = "uni2workgw.ifi.lmu.de";
93 user = "root";
94 identityFile = "~/.ssh/uni2work";
95 };
96 "uniworxdb" =
97 { hostname = "uniworxdb";
98 proxyJump = "uniworx4";
99 user = "root";
100 identityFile = "~/.ssh/uni2work";
101 };
102 "uniworxdb2" =
103 { hostname = "uniworxdb2";
104 proxyJump = "uniworx4";
105 user = "root";
106 identityFile = "~/.ssh/uni2work";
107 };
108 "gate2" =
109 { hostname = "gate2.tcs.ifi.lmu.de";
110 user = "gkleen";
111 identityFile = "~/.ssh/tcs";
112 };
113 "proxy.gate2" =
114 { hostname = "gate2.tcs.ifi.lmu.de";
115 user = "gkleen";
116 identityFile = "~/.ssh/proxy.gkleen@tcs.ifi.lmu.de";
117 dynamicForwards = [ { port = 8118; } ];
118 extraOptions = {
119 ExitOnForwardFailure = "yes";
120 };
121 };
122 "jump.gate2" =
123 { hostname = "gate2.tcs.ifi.lmu.de";
124 user = "gkleen";
125 identityFile = "~/.ssh/proxy.gkleen@tcs.ifi.lmu.de";
126 extraOptions = {
127 ExitOnForwardFailure = "yes";
128 };
129 };
130 "gate" =
131 { hostname = "gate.tcs.ifi.lmu.de";
132 user = "gkleen";
133 identityFile = "~/.ssh/tcs";
134 };
135 "proxy.gate" =
136 { hostname = "gate.tcs.ifi.lmu.de";
137 user = "gkleen";
138 identityFile = "~/.ssh/proxy.gkleen@tcs.ifi.lmu.de";
139 dynamicForwards = [ { port = 8118; } ];
140 extraOptions = {
141 ExitOnForwardFailure = "yes";
142 };
143 };
144 "jump.gate" =
145 { hostname = "gate.tcs.ifi.lmu.de";
146 user = "gkleen";
147 identityFile = "~/.ssh/proxy.gkleen@tcs.ifi.lmu.de";
148 extraOptions = {
149 ExitOnForwardFailure = "yes";
150 };
151 };
152 "oregon" =
153 { hostname = "oregon.tcs.ifi.lmu.de";
154 user = "root";
155 identityFile = "~/.ssh/tcs";
156 };
157 "witbank" =
158 { hostname = "witbank.tcs.ifi.lmu.de";
159 user = "uni2work";
160 identityFile = "~/.ssh/letz";
161 };
162 "git.odin" =
163 { hostname = "odin.asgard.yggdrasil";
164 user = "gitolite";
165 };
166 "notmuch.odin" =
167 { hostname = "odin.asgard.yggdrasil";
168 identityFile = "~/.ssh/notmuch.odin.asgard.yggdrasil";
169 };
170 "status.odin" =
171 { hostname = "odin.asgard.yggdrasil";
172 identityFile = "~/.ssh/status.odin.asgard.yggdrasil";
173 extraOptions.ControlPath = "~/.ssh/status-%r@%n:%p";
174 };
175 "moden" =
176 { hostname = "oristano.tcs.ifi.lmu.de";
177 user = "gkleen";
178 port = 30363;
179 identityFile = "~/.ssh/gkleen@oristano.tcs.ifi.lmu.de";
180 };
181 "ubuntu1804" =
182 { hostname = "192.168.122.30";
183 identityFile = "~/.ssh/gkleen@sif.midgard.yggdrasil";
184 forwardAgent = true;
185 };
186 "gitlab.haskell.org" =
187 { hostname = "gitlab.haskell.org";
188 identityFile = "~/.ssh/gkleen@gitlab.haskell.org";
189 };
190}
diff --git a/accounts/gkleen@sif/store.kdbx.lftp b/accounts/gkleen@sif/store.kdbx.lftp
new file mode 100644
index 00000000..4447aded
--- /dev/null
+++ b/accounts/gkleen@sif/store.kdbx.lftp
@@ -0,0 +1,6 @@
1open ftp://gkleen.keepass@yggdrasil.li/
2
3lcd /home/gkleen
4
5mirror -v --only-newer -f store.kdbx
6mirror -v --reverse --only-newer -f store.kdbx \ No newline at end of file
diff --git a/accounts/gkleen@sif/systemd.nix b/accounts/gkleen@sif/systemd.nix
new file mode 100644
index 00000000..a5b71417
--- /dev/null
+++ b/accounts/gkleen@sif/systemd.nix
@@ -0,0 +1,94 @@
1{ pkgs, config, userName, ... }:
2let
3 xmobar = import ./xmobar pkgs.haskellPackages;
4 cfg = config.home-manager.users.${userName};
5in {
6 services = {
7 sync-keepass = {
8 Service = {
9 Type = "oneshot";
10 WorkingDirectory = "~";
11 ExecStart = "${pkgs.lftp}/bin/lftp -f ${./store.kdbx.lftp}";
12 };
13 };
14 urxvtd = {
15 Service = {
16 Type = "simple";
17 WorkingDirectory = "~";
18 ExecStart = "${cfg.programs.urxvt.package}/bin/urxvtd";
19 Restart = "always";
20 };
21 Unit = {
22 After = ["graphical-session.target"];
23 };
24 Install = {
25 WantedBy = ["graphical-session.target"];
26 };
27 };
28 emacs = {
29 Unit = {
30 After = ["graphical-session-pre.target"];
31 };
32 };
33 trayer = {
34 Service = {
35 Type = "simple";
36 WorkingDirectory = "~";
37 ExecStart = "${pkgs.trayer}/bin/trayer --edge top --align right --SetDockType true --SetPartialStrut true --expand true --width 8 --tint 0x000000 --alpha 0 --transparent true --height 32 --monitor primary";
38 Restart = "always";
39 };
40 Install = {
41 WantedBy = ["graphical-session.target"];
42 };
43 };
44 xmobar = {
45 Service = {
46 Type = "simple";
47 WorkingDirectory = "~";
48 ExecStart = "${xmobar}/bin/xmobar";
49 Restart = "always";
50 Environment = "PATH=${pkgs.worktime}/bin:${pkgs.openssh}/bin";
51
52 };
53 Install = {
54 WantedBy = ["graphical-session.target"];
55 };
56 };
57 dunst = {
58 Service = {
59 Restart = "always";
60 };
61 Install = {
62 WantedBy = ["graphical-session.target"];
63 };
64 };
65 xiccd = {
66 Service = {
67 Type = "simple";
68 WorkingDirectory = "~";
69 ExecStart = "${pkgs.xiccd}/bin/xiccd";
70 Restart = "always";
71 };
72 };
73 };
74 timers = {
75 sync-keepass = {
76 Timer = {
77 OnActiveSec = "1m";
78 OnUnitActiveSec = "1m";
79 };
80
81 Install = {
82 WantedBy = ["default.target"];
83 };
84 };
85 };
86 targets = {
87 graphical-session = {
88 Unit = {
89 BindsTo = ["default.target"];
90 After = ["basic.target"];
91 };
92 };
93 };
94}
diff --git a/accounts/gkleen@sif/xmobar/default.nix b/accounts/gkleen@sif/xmobar/default.nix
new file mode 100644
index 00000000..fcac5e60
--- /dev/null
+++ b/accounts/gkleen@sif/xmobar/default.nix
@@ -0,0 +1,7 @@
1argumentPackages@{ ... }:
2
3let
4 # defaultPackages = (import ./stackage.nix {});
5 # haskellPackages = defaultPackages // argumentPackages;
6 haskellPackages = argumentPackages;
7in haskellPackages.callPackage ./xmobar-yggdrasil.nix {}
diff --git a/accounts/gkleen@sif/xmobar/nixpkgs.nix b/accounts/gkleen@sif/xmobar/nixpkgs.nix
new file mode 100644
index 00000000..783ede00
--- /dev/null
+++ b/accounts/gkleen@sif/xmobar/nixpkgs.nix
@@ -0,0 +1,9 @@
1{ nixpkgs ? import <nixpkgs>
2}:
3
4import ((nixpkgs {}).fetchFromGitHub {
5 owner = "NixOS";
6 repo = "nixpkgs";
7 rev = "10e61bf5be57736035ec7a804cb0bf3d083bf2cf";
8 sha256 = "0fplfm2zx4vk7gs8bdcxnvzkdmpx2w0llqwf8475z9dz9cl132rm";
9})
diff --git a/accounts/gkleen@sif/xmobar/package.yaml b/accounts/gkleen@sif/xmobar/package.yaml
new file mode 100644
index 00000000..b638b6ac
--- /dev/null
+++ b/accounts/gkleen@sif/xmobar/package.yaml
@@ -0,0 +1,13 @@
1name: xmobar-yggdrasil
2
3executables:
4 xmobar:
5 dependencies:
6 - base
7 - xmobar
8
9 main: xmobar.hs
10 source-dirs:
11 - .
12
13 ghc-options: -threaded
diff --git a/accounts/gkleen@sif/xmobar/shell.nix b/accounts/gkleen@sif/xmobar/shell.nix
new file mode 100644
index 00000000..18188e78
--- /dev/null
+++ b/accounts/gkleen@sif/xmobar/shell.nix
@@ -0,0 +1,28 @@
1{ nixpkgs ? import ./nixpkgs.nix {} }:
2
3let
4 inherit (nixpkgs {}) pkgs;
5 haskellPackages = import ./stackage.nix { inherit nixpkgs; };
6
7 drv = haskellPackages.callPackage ./xmobar-yggdrasil.nix {};
8 override = oldAttrs: {
9 nativeBuildInputs = oldAttrs.nativeBuildInputs ++ (with pkgs; []) ++ (with haskellPackages; [ stack cabal-install cabal2nix ]);
10 shellHook = ''
11 export PROMPT_INFO="${oldAttrs.name}"
12
13 if [ -n "$ZSH_VERSION" ]; then
14 autoload -U +X compinit && compinit
15 autoload -U +X bashcompinit && bashcompinit
16 fi
17 eval "$(stack --bash-completion-script stack)"
18
19 ${oldAttrs.shellHook}
20 '';
21 };
22
23 dummy = pkgs.stdenv.mkDerivation {
24 name = "interactive-xmobar-environment";
25 shellHook = "";
26 };
27in pkgs.stdenv.lib.overrideDerivation dummy override
28 #pkgs.stdenv.lib.overrideDerivation drv.env override
diff --git a/accounts/gkleen@sif/xmobar/stack.nix b/accounts/gkleen@sif/xmobar/stack.nix
new file mode 100644
index 00000000..17a49e04
--- /dev/null
+++ b/accounts/gkleen@sif/xmobar/stack.nix
@@ -0,0 +1,17 @@
1{ ghc, nixpkgs ? import ./nixpkgs.nix {} }:
2
3let
4 haskellPackages = import ./stackage.nix { inherit nixpkgs; };
5 inherit (nixpkgs {}) pkgs;
6in pkgs.haskell.lib.buildStackProject {
7 inherit ghc;
8 inherit (haskellPackages) stack;
9 name = "stackenv";
10 buildInputs = (with pkgs;
11 [ xorg.libX11 xorg.libXrandr xorg.libXinerama xorg.libXScrnSaver xorg.libXext xorg.libXft
12 cairo
13 glib
14 ]) ++ (with haskellPackages;
15 [
16 ]);
17}
diff --git a/accounts/gkleen@sif/xmobar/stack.yaml b/accounts/gkleen@sif/xmobar/stack.yaml
new file mode 100644
index 00000000..b8ed1147
--- /dev/null
+++ b/accounts/gkleen@sif/xmobar/stack.yaml
@@ -0,0 +1,10 @@
1nix:
2 enable: true
3 shell-file: stack.nix
4
5resolver: lts-13.21
6
7packages:
8 - .
9
10extra-deps: []
diff --git a/accounts/gkleen@sif/xmobar/stack.yaml.lock b/accounts/gkleen@sif/xmobar/stack.yaml.lock
new file mode 100644
index 00000000..fcc2f5f3
--- /dev/null
+++ b/accounts/gkleen@sif/xmobar/stack.yaml.lock
@@ -0,0 +1,12 @@
1# This file was autogenerated by Stack.
2# You should not edit this file by hand.
3# For more information, please see the documentation at:
4# https://docs.haskellstack.org/en/stable/lock_files
5
6packages: []
7snapshots:
8- completed:
9 size: 498180
10 url: https://raw.githubusercontent.com/commercialhaskell/stackage-snapshots/master/lts/13/21.yaml
11 sha256: eff2de19a6d4691ccbf6edc1fba858f1918683047dce0f09adede874bbd2a8f3
12 original: lts-13.21
diff --git a/accounts/gkleen@sif/xmobar/stackage.nix b/accounts/gkleen@sif/xmobar/stackage.nix
new file mode 100644
index 00000000..c162ca2c
--- /dev/null
+++ b/accounts/gkleen@sif/xmobar/stackage.nix
@@ -0,0 +1,31 @@
1{ nixpkgs ? import ./nixpkgs.nix {}
2, snapshot ? "lts-13.21"
3}:
4
5let
6 stackage = import (fetchTarball {
7 url = "https://stackage.serokell.io/zb36jsy3r5h4ydz0pnp00g9vk94dvv03-stackage/default.nix.tar.gz";
8 sha256 = "0h6f80gds0ds77y51hhiadh2h2k8njqq8n0gayp729ana9m9agma";
9 });
10
11 overlays =
12 [ stackage."${snapshot}"
13 (self: super: {
14 haskell = super.haskell // {
15 packages = super.haskell.packages // {
16 "${snapshot}" = super.haskell.packages."${snapshot}".override {
17 overrides = hself: hsuper: {
18 zip-archive = self.haskell.lib.overrideCabal hsuper.zip-archive (old: {
19 testToolDepends = old.testToolDepends ++ (with self; [ unzip which ]);
20 });
21 alex = self.haskell.lib.dontCheck hsuper.alex;
22 };
23 };
24 };
25 };
26 }
27 )
28 ];
29
30 inherit (nixpkgs { inherit overlays; }) pkgs;
31in pkgs.haskell.packages."${snapshot}"
diff --git a/accounts/gkleen@sif/xmobar/xmobar-yggdrasil.nix b/accounts/gkleen@sif/xmobar/xmobar-yggdrasil.nix
new file mode 100644
index 00000000..1dfc619b
--- /dev/null
+++ b/accounts/gkleen@sif/xmobar/xmobar-yggdrasil.nix
@@ -0,0 +1,13 @@
1{ mkDerivation, base, hpack, stdenv, xmobar }:
2mkDerivation {
3 pname = "xmobar-yggdrasil";
4 version = "0.0.0";
5 src = ./.;
6 isLibrary = false;
7 isExecutable = true;
8 libraryToolDepends = [ hpack ];
9 executableHaskellDepends = [ base xmobar ];
10 preConfigure = "hpack";
11 license = "unknown";
12 hydraPlatforms = stdenv.lib.platforms.none;
13}
diff --git a/accounts/gkleen@sif/xmobar/xmobar.hs b/accounts/gkleen@sif/xmobar/xmobar.hs
new file mode 100644
index 00000000..ed1f6e55
--- /dev/null
+++ b/accounts/gkleen@sif/xmobar/xmobar.hs
@@ -0,0 +1,52 @@
1import Xmobar
2
3import Data.List (intercalate)
4
5
6main :: IO ()
7main = xmobar config
8 where
9 config = defaultConfig
10 { font = "xft:FiraCode Nerd Font Mono:style=Regular:pixelsize=21"
11 , position = OnScreen 0 $ TopP 0 307
12 , bgColor = "black"
13 , fgColor = "grey"
14 , overrideRedirect = False
15 , template =
16 let left = intercalate " | "
17 [ "%XMonadWorkspaces%"
18 , "%XMonadLayout%"
19 , "%XMonadTitle%"
20 ]
21 right = intercalate " | "
22 [ {- "%status%"
23 , -} "%battery%"
24 , "%kbd%"
25 , "%worktime%"
26 , "%worktime-today%"
27 , "%time%"
28 , "%date%"
29 ]
30 in left <> "}{" <> right
31 , commands =
32 [ Run $ NamedXPropertyLog "_XMONAD_WORKSPACES" "XMonadWorkspaces"
33 , Run $ NamedXPropertyLog "_XMONAD_LAYOUT" "XMonadLayout"
34 , Run $ NamedXPropertyLog "_XMONAD_TITLE" "XMonadTitle"
35 , Run $ Date "%H:%M" "time" 50
36 , Run $ Date "%a %b %_d" "date" 50
37 , Run $ Com "worktime" [] "worktime" 1500
38 , Run $ Com "worktime" ["today"] "worktime-today" 1500
39 , Run $ Com "ssh" ["status.odin"] "status" 600
40 , Run $ Kbd [("us(dvp)", "dvp")]
41 , Run $ Battery
42 [ "--template", "<watts> <left> (<timeleft>) AC <acstatus>"
43 , "--suffix", "On"
44 , "--Low", "10"
45 , "--High", "80"
46 , "--low", "darkred"
47 , "--normal", "darkorange"
48 , "--high", "darkgreen"
49 , "-p", "3"
50 ] 50
51 ]
52 }
diff --git a/accounts/gkleen@sif/xmonad/.gitignore b/accounts/gkleen@sif/xmonad/.gitignore
new file mode 100644
index 00000000..c11891cd
--- /dev/null
+++ b/accounts/gkleen@sif/xmonad/.gitignore
@@ -0,0 +1,4 @@
1**/#*#
2**/.stack-work/
3/stack.yaml.lock
4/*.cabal
diff --git a/accounts/gkleen@sif/xmonad/default.nix b/accounts/gkleen@sif/xmonad/default.nix
new file mode 100644
index 00000000..8790c12f
--- /dev/null
+++ b/accounts/gkleen@sif/xmonad/default.nix
@@ -0,0 +1,7 @@
1argumentPackages@{ ... }:
2
3let
4 # defaultPackages = (import ./stackage.nix {});
5 # haskellPackages = defaultPackages // argumentPackages;
6 haskellPackages = argumentPackages;
7in haskellPackages.callPackage ./xmonad-yggdrasil.nix {}
diff --git a/accounts/gkleen@sif/xmonad/lib/XMonad/Mpv.hs b/accounts/gkleen@sif/xmonad/lib/XMonad/Mpv.hs
new file mode 100644
index 00000000..e6accdcc
--- /dev/null
+++ b/accounts/gkleen@sif/xmonad/lib/XMonad/Mpv.hs
@@ -0,0 +1,127 @@
1{-# LANGUAGE DeriveGeneric, OverloadedLists, OverloadedStrings, ViewPatterns, ExistentialQuantification, MultiWayIf #-}
2
3module XMonad.Mpv
4 ( MpvCommand(..), MpvResponse(..), MpvException(..)
5 , mpv
6 , mpvDir
7 , mpvAll, mpvOne
8 , mpvResponse
9 ) where
10
11import Data.Aeson
12
13import Data.Monoid
14
15import Network.Socket hiding (recv)
16import Network.Socket.ByteString
17
18import qualified Data.ByteString as BS
19import qualified Data.ByteString.Char8 as CBS
20import qualified Data.ByteString.Lazy as LBS
21
22import GHC.Generics (Generic)
23import Data.Typeable (Typeable)
24import Data.String (IsString(..))
25
26import Control.Exception
27
28import System.IO.Temp (getCanonicalTemporaryDirectory)
29
30import Control.Monad
31import Control.Exception (bracket)
32import Control.Monad.IO.Class (MonadIO(..))
33
34import System.FilePath
35import System.Directory (getDirectoryContents)
36
37import Data.List
38import Data.Either
39import Data.Maybe
40
41import Debug.Trace
42
43
44data MpvCommand
45 = forall a. ToJSON a => MpvSetProperty String a
46 | MpvGetProperty String
47data MpvResponse
48 = MpvError String
49 | MpvSuccess (Maybe Value)
50 deriving (Read, Show, Generic, Eq)
51data MpvException = MpvException String
52 | MpvNoValue
53 | MpvNoParse String
54 deriving (Generic, Typeable, Read, Show)
55instance Exception MpvException
56
57
58instance ToJSON MpvCommand where
59 toJSON (MpvSetProperty name val) = Array ["set_property", fromString name, toJSON val]
60 toJSON (MpvGetProperty name) = Array ["get_property", fromString name]
61
62instance FromJSON MpvResponse where
63 parseJSON = withObject "response object" $ \obj -> do
64 mval <- obj .:? "data"
65 err <- obj .: "error"
66
67 let ret
68 | err == "success" = MpvSuccess mval
69 | otherwise = MpvError err
70
71 return ret
72
73mpvSocket :: FilePath -> (Socket -> IO a) -> IO a
74mpvSocket sockPath = withSocketsDo . bracket mkSock close
75 where
76 mkSock = do
77 sock <- socket AF_UNIX Stream defaultProtocol
78 connect sock $ SockAddrUnix (traceId sockPath)
79 return sock
80
81mpvResponse :: FromJSON v => MpvResponse -> IO v
82mpvResponse (MpvError str) = throwIO $ MpvException str
83mpvResponse (MpvSuccess Nothing) = throwIO MpvNoValue
84mpvResponse (MpvSuccess (Just v)) = case fromJSON v of
85 Success v' -> return v'
86 Error str -> throwIO $ MpvNoParse str
87
88mpv :: FilePath -> MpvCommand -> IO MpvResponse
89mpv sockPath cmd = mpvSocket sockPath $ \sock -> do
90 let message = (`BS.append` "\n") . LBS.toStrict . encode $ Object [("command", toJSON cmd)]
91 traceIO $ show message
92 sendAll sock message
93 let recvAll = do
94 prefix <- recv sock 4096
95 if
96 | (prefix', rest) <- CBS.break (== '\n') prefix
97 , not (BS.null rest) -> return prefix'
98 | BS.null prefix -> return prefix
99 | otherwise -> BS.append prefix <$> recvAll
100 response <- recvAll
101 traceIO $ show response
102 either (ioError . userError) return . traceShowId $ eitherDecodeStrict' response
103
104mpvDir :: Exception e => FilePath -> (FilePath -> [(FilePath, Either e MpvResponse)] -> Maybe MpvCommand) -> IO [(FilePath, Either e MpvResponse)]
105mpvDir dir step = do
106 socks <- filter (".sock" `isSuffixOf`) <$> getDirectoryContents dir
107 go [] socks
108 where
109 go acc [] = return acc
110 go acc (sock:socks)
111 | Just cmd <- step sock acc = do
112 res <- try $ mpv (dir </> sock) cmd
113 go ((sock, res) : acc) socks
114 | otherwise =
115 go acc socks
116
117mpvAll :: FilePath -> MpvCommand -> IO [MpvResponse]
118mpvAll dir cmd = do
119 results <- map snd <$> (mpvDir dir (\_ _ -> Just cmd) :: IO [(FilePath, Either SomeException MpvResponse)])
120 mapM (either throwIO return) results
121
122mpvOne :: FilePath -> MpvCommand -> IO (Maybe MpvResponse)
123mpvOne dir cmd = listToMaybe . snd . partitionEithers . map snd <$> (mpvDir dir step :: IO [(FilePath, Either SomeException MpvResponse)])
124 where
125 step _ results
126 | any (isRight . snd) results = Nothing
127 | otherwise = Just cmd
diff --git a/accounts/gkleen@sif/xmonad/lib/XMonad/Prompt/MyPass.hs b/accounts/gkleen@sif/xmonad/lib/XMonad/Prompt/MyPass.hs
new file mode 100644
index 00000000..1caefae5
--- /dev/null
+++ b/accounts/gkleen@sif/xmonad/lib/XMonad/Prompt/MyPass.hs
@@ -0,0 +1,94 @@
1module XMonad.Prompt.MyPass
2 (
3 -- * Usages
4 -- $usages
5 mkPassPrompt
6 ) where
7
8import Control.Monad (liftM)
9import XMonad.Core
10import XMonad.Prompt ( XPrompt
11 , showXPrompt
12 , commandToComplete
13 , nextCompletion
14 , getNextCompletion
15 , XPConfig
16 , mkXPrompt
17 , searchPredicate)
18import System.Directory (getHomeDirectory)
19import System.FilePath (takeExtension, dropExtension, combine)
20import System.Posix.Env (getEnv)
21import XMonad.Util.Run (runProcessWithInput)
22
23-- $usages
24-- You can use this module with the following in your @~\/.xmonad\/xmonad.hs@:
25--
26-- > import XMonad.Prompt.Pass
27--
28-- Then add a keybinding for 'passPrompt', 'passGeneratePrompt' or 'passRemovePrompt':
29--
30-- > , ((modMask x , xK_p) , passPrompt xpconfig)
31-- > , ((modMask x .|. controlMask, xK_p) , passGeneratePrompt xpconfig)
32-- > , ((modMask x .|. controlMask .|. shiftMask, xK_p), passRemovePrompt xpconfig)
33--
34-- For detailed instructions on:
35--
36-- - editing your key bindings, see "XMonad.Doc.Extending#Editing_key_bindings".
37--
38-- - how to setup the password storage, see <http://git.zx2c4.com/password-store/about/>
39--
40
41type Predicate = String -> String -> Bool
42
43getPassCompl :: [String] -> Predicate -> String -> IO [String]
44getPassCompl compls p s
45 | length s <= minL
46 , all ((> minL) . length) compls = return []
47 | otherwise = do return $ filter (p s) compls
48 where
49 minL = 3
50
51type PromptLabel = String
52
53data Pass = Pass PromptLabel
54
55instance XPrompt Pass where
56 showXPrompt (Pass prompt) = prompt ++ ": "
57 commandToComplete _ c = c
58 nextCompletion _ = getNextCompletion
59
60-- | Default password store folder in $HOME/.password-store
61--
62passwordStoreFolderDefault :: String -> String
63passwordStoreFolderDefault home = combine home ".password-store"
64
65-- | Compute the password store's location.
66-- Use the PASSWORD_STORE_DIR environment variable to set the password store.
67-- If empty, return the password store located in user's home.
68--
69passwordStoreFolder :: IO String
70passwordStoreFolder =
71 getEnv "PASSWORD_STORE_DIR" >>= computePasswordStoreDir
72 where computePasswordStoreDir Nothing = liftM passwordStoreFolderDefault getHomeDirectory
73 computePasswordStoreDir (Just storeDir) = return storeDir
74
75-- | A pass prompt factory
76--
77mkPassPrompt :: PromptLabel -> (String -> X ()) -> XPConfig -> X ()
78mkPassPrompt promptLabel passwordFunction xpconfig = do
79 passwords <- io (passwordStoreFolder >>= getPasswords)
80 mkXPrompt (Pass promptLabel) xpconfig (getPassCompl passwords $ searchPredicate xpconfig) passwordFunction
81
82-- | Retrieve the list of passwords from the password storage 'passwordStoreDir
83getPasswords :: FilePath -> IO [String]
84getPasswords passwordStoreDir = do
85 files <- runProcessWithInput "find" [
86 passwordStoreDir,
87 "-type", "f",
88 "-name", "*.gpg",
89 "-printf", "%P\n"] []
90 return $ map removeGpgExtension $ lines files
91
92removeGpgExtension :: String -> String
93removeGpgExtension file | takeExtension file == ".gpg" = dropExtension file
94 | otherwise = file
diff --git a/accounts/gkleen@sif/xmonad/lib/XMonad/Prompt/MyShell.hs b/accounts/gkleen@sif/xmonad/lib/XMonad/Prompt/MyShell.hs
new file mode 100644
index 00000000..c268f87d
--- /dev/null
+++ b/accounts/gkleen@sif/xmonad/lib/XMonad/Prompt/MyShell.hs
@@ -0,0 +1,105 @@
1module XMonad.Prompt.MyShell
2 ( Shell (..)
3 , shellPrompt
4 , prompt
5 , safePrompt
6 , unsafePrompt
7 , getCommands
8 , getShellCompl
9 , split
10 ) where
11
12import Codec.Binary.UTF8.String (encodeString)
13import Control.Exception as E
14import Control.Monad (forM)
15import Data.List (isPrefixOf)
16import System.Directory (doesDirectoryExist, getDirectoryContents)
17import System.Environment (getEnv)
18import System.Posix.Files (getFileStatus, isDirectory)
19
20import XMonad hiding (config)
21import XMonad.Prompt
22import XMonad.Util.Run
23
24econst :: Monad m => a -> IOException -> m a
25econst = const . return
26
27data Shell = Shell String
28
29instance XPrompt Shell where
30 showXPrompt (Shell q) = q
31 completionToCommand _ = escape
32
33shellPrompt :: String -> XPConfig -> X ()
34shellPrompt q c = do
35 cmds <- io getCommands
36 mkXPrompt (Shell q) c (getShellCompl cmds) spawn
37
38{- $spawns
39 See safe and unsafeSpawn in "XMonad.Util.Run".
40 prompt is an alias for safePrompt;
41 safePrompt and unsafePrompt work on the same principles, but will use
42 XPrompt to interactively query the user for input; the appearance is
43 set by passing an XPConfig as the second argument. The first argument
44 is the program to be run with the interactive input.
45 You would use these like this:
46
47 > , ((modm, xK_b), safePrompt "firefox" greenXPConfig)
48 > , ((modm .|. shiftMask, xK_c), prompt ("xterm" ++ " -e") greenXPConfig)
49
50 Note that you want to use safePrompt for Firefox input, as Firefox
51 wants URLs, and unsafePrompt for the XTerm example because this allows
52 you to easily start a terminal executing an arbitrary command, like
53 'top'. -}
54
55prompt, unsafePrompt, safePrompt :: String -> FilePath -> XPConfig -> X ()
56prompt = unsafePrompt
57safePrompt q c config = mkXPrompt (Shell q) config (getShellCompl [c]) run
58 where run = safeSpawn c . return
59unsafePrompt q c config = mkXPrompt (Shell q) config (getShellCompl [c]) run
60 where run a = unsafeSpawn $ c ++ " " ++ a
61
62getShellCompl :: [String] -> String -> IO [String]
63getShellCompl cmds s | s == "" || last s == ' ' = return []
64 | otherwise = do
65 f <- fmap lines $ runProcessWithInput "bash" [] ("compgen -A file -- "
66 ++ s ++ "\n")
67 files <- case f of
68 [x] -> do fs <- getFileStatus (encodeString x)
69 if isDirectory fs then return [x ++ "/"]
70 else return [x]
71 _ -> return f
72 return . uniqSort $ files ++ commandCompletionFunction cmds s
73
74commandCompletionFunction :: [String] -> String -> [String]
75commandCompletionFunction cmds str | '/' `elem` str = []
76 | otherwise = filter (isPrefixOf str) cmds
77
78getCommands :: IO [String]
79getCommands = do
80 p <- getEnv "PATH" `E.catch` econst []
81 let ds = filter (/= "") $ split ':' p
82 es <- forM ds $ \d -> do
83 exists <- doesDirectoryExist d
84 if exists
85 then getDirectoryContents d
86 else return []
87 return . uniqSort . filter ((/= '.') . head) . concat $ es
88
89split :: Eq a => a -> [a] -> [[a]]
90split _ [] = []
91split e l =
92 f : split e (rest ls)
93 where
94 (f,ls) = span (/=e) l
95 rest s | s == [] = []
96 | otherwise = tail s
97
98escape :: String -> String
99escape [] = ""
100escape (x:xs)
101 | isSpecialChar x = '\\' : x : escape xs
102 | otherwise = x : escape xs
103
104isSpecialChar :: Char -> Bool
105isSpecialChar = flip elem " &\\@\"'#?$*()[]{};"
diff --git a/accounts/gkleen@sif/xmonad/lib/XMonad/Prompt/MySsh.hs b/accounts/gkleen@sif/xmonad/lib/XMonad/Prompt/MySsh.hs
new file mode 100644
index 00000000..c85d0f92
--- /dev/null
+++ b/accounts/gkleen@sif/xmonad/lib/XMonad/Prompt/MySsh.hs
@@ -0,0 +1,243 @@
1module XMonad.Prompt.MySsh
2 ( -- * Usage
3 -- $usage
4 sshPrompt,
5 Ssh,
6 Override (..),
7 mkOverride,
8 Conn (..),
9 moshCmd,
10 moshCmd',
11 sshCmd,
12 inTmux,
13 withEnv
14 ) where
15
16import XMonad
17import XMonad.Util.Run
18import XMonad.Prompt
19
20import System.Directory
21import System.Environment
22import qualified Control.Exception as E
23
24import Control.Monad
25import Data.Maybe
26
27import Text.Parsec.String
28import Text.Parsec
29import Data.Char (isSpace)
30
31econst :: Monad m => a -> E.IOException -> m a
32econst = const . return
33
34-- $usage
35-- 1. In your @~\/.xmonad\/xmonad.hs@:
36--
37-- > import XMonad.Prompt
38-- > import XMonad.Prompt.Ssh
39--
40-- 2. In your keybindings add something like:
41--
42-- > , ((modm .|. controlMask, xK_s), sshPrompt defaultXPConfig)
43--
44-- Keep in mind, that if you want to use the completion you have to
45-- disable the "HashKnownHosts" option in your ssh_config
46--
47-- For detailed instruction on editing the key binding see
48-- "XMonad.Doc.Extending#Editing_key_bindings".
49
50data Override = Override
51 { oUser :: Maybe String
52 , oHost :: String
53 , oPort :: Maybe Int
54 , oCommand :: Conn -> String
55 }
56
57mkOverride = Override { oUser = Nothing, oHost = "", oPort = Nothing, oCommand = sshCmd }
58sshCmd c = concat
59 [ "ssh -t "
60 , if isJust $ cUser c then (fromJust $ cUser c) ++ "@" else ""
61 , cHost c
62 , if isJust $ cPort c then " -p " ++ (show $ fromJust $ cPort c) else ""
63 , " -- "
64 , cCommand c
65 ]
66moshCmd c = concat
67 [ "mosh "
68 , if isJust $ cUser c then (fromJust $ cUser c) ++ "@" else ""
69 , cHost c
70 , if isJust $ cPort c then " --ssh=\"ssh -p " ++ (show $ fromJust $ cPort c) ++ "\"" else ""
71 , " -- "
72 , cCommand c
73 ]
74moshCmd' p c = concat
75 [ "mosh "
76 , "--server=" ++ p ++ " "
77 , if isJust $ cUser c then (fromJust $ cUser c) ++ "@" else ""
78 , cHost c
79 , if isJust $ cPort c then " --ssh=\"ssh -p " ++ (show $ fromJust $ cPort c) ++ "\"" else ""
80 , " -- "
81 , cCommand c
82 ]
83inTmux c
84 | null $ cCommand c = c { cCommand = "tmux new-session" }
85 | otherwise = c { cCommand = "tmux new-session \"" ++ (cCommand c) ++ "\"" }
86withEnv :: [(String, String)] -> Conn -> Conn
87withEnv envs c = c { cCommand = "env" ++ (concat $ map (\(n, v) -> ' ' : (n ++ "=" ++ v)) envs) ++ " " ++ (cCommand c) }
88
89data Conn = Conn
90 { cUser :: Maybe String
91 , cHost :: String
92 , cPort :: Maybe Int
93 , cCommand :: String
94 } deriving (Eq, Show, Read)
95
96data Ssh = Ssh
97
98instance XPrompt Ssh where
99 showXPrompt Ssh = "SSH to: "
100 commandToComplete _ c = c
101 nextCompletion _ = getNextCompletion
102
103toConn :: String -> Maybe Conn
104toConn = toConn' . parse connParser "(unknown)"
105toConn' :: Either ParseError Conn -> Maybe Conn
106toConn' (Left _) = Nothing
107toConn' (Right a) = Just a
108
109connParser :: Parser Conn
110connParser = do
111 spaces
112 user' <- optionMaybe $ try $ do
113 str <- many1 $ satisfy (\c -> (not $ isSpace c) && (c /= '@'))
114 char '@'
115 return str
116 host' <- many1 $ satisfy (not . isSpace)
117 port' <- optionMaybe $ try $ do
118 space
119 string "-p"
120 spaces
121 int <- many1 digit
122 (space >> return ()) <|> eof
123 return $ (read int :: Int)
124 spaces
125 command' <- many anyChar
126 eof
127 return $ Conn
128 { cHost = host'
129 , cUser = user'
130 , cPort = port'
131 , cCommand = command'
132 }
133
134sshPrompt :: [Override] -> XPConfig -> X ()
135sshPrompt o c = do
136 sc <- io sshComplList
137 mkXPrompt Ssh c (mkComplFunFromList sc) $ ssh o
138
139ssh :: [Override] -> String -> X ()
140ssh overrides str = do
141 let cmd = applyOverrides overrides str
142 liftIO $ putStr "SSH Command: "
143 liftIO $ putStrLn cmd
144 runInTerm "" cmd
145
146applyOverrides :: [Override] -> String -> String
147applyOverrides [] str = "ssh " ++ str
148applyOverrides (o:os) str = case (applyOverride o str) of
149 Just str -> str
150 Nothing -> applyOverrides os str
151
152applyOverride :: Override -> String -> Maybe String
153applyOverride o str = let
154 conn = toConn str
155 in
156 if isNothing conn then Nothing else
157 case (fromJust conn) `matches` o of
158 True -> Just $ (oCommand o) (fromJust conn)
159 False -> Nothing
160
161matches :: Conn -> Override -> Bool
162a `matches` b = and
163 [ justBool (cUser a) (oUser b) (==)
164 , (cHost a) == (oHost b)
165 , justBool (cPort a) (oPort b) (==)
166 ]
167
168justBool :: Eq a => Maybe a -> Maybe a -> (a -> a -> Bool) -> Bool
169justBool Nothing _ _ = True
170justBool _ Nothing _ = True
171justBool (Just a) (Just b) match = a `match` b
172
173sshComplList :: IO [String]
174sshComplList = uniqSort `fmap` liftM2 (++) sshComplListLocal sshComplListGlobal
175
176sshComplListLocal :: IO [String]
177sshComplListLocal = do
178 h <- getEnv "HOME"
179 s1 <- sshComplListFile $ h ++ "/.ssh/known_hosts"
180 s2 <- sshComplListConf $ h ++ "/.ssh/config"
181 return $ s1 ++ s2
182
183sshComplListGlobal :: IO [String]
184sshComplListGlobal = do
185 env <- getEnv "SSH_KNOWN_HOSTS" `E.catch` econst "/nonexistent"
186 fs <- mapM fileExists [ env
187 , "/usr/local/etc/ssh/ssh_known_hosts"
188 , "/usr/local/etc/ssh_known_hosts"
189 , "/etc/ssh/ssh_known_hosts"
190 , "/etc/ssh_known_hosts"
191 ]
192 case catMaybes fs of
193 [] -> return []
194 (f:_) -> sshComplListFile' f
195
196sshComplListFile :: String -> IO [String]
197sshComplListFile kh = do
198 f <- doesFileExist kh
199 if f then sshComplListFile' kh
200 else return []
201
202sshComplListFile' :: String -> IO [String]
203sshComplListFile' kh = do
204 l <- readFile kh
205 return $ map (getWithPort . takeWhile (/= ',') . concat . take 1 . words)
206 $ filter nonComment
207 $ lines l
208
209sshComplListConf :: String -> IO [String]
210sshComplListConf kh = do
211 f <- doesFileExist kh
212 if f then sshComplListConf' kh
213 else return []
214
215sshComplListConf' :: String -> IO [String]
216sshComplListConf' kh = do
217 l <- readFile kh
218 return $ map (!!1)
219 $ filter isHost
220 $ map words
221 $ lines l
222 where
223 isHost ws = take 1 ws == ["Host"] && length ws > 1
224
225fileExists :: String -> IO (Maybe String)
226fileExists kh = do
227 f <- doesFileExist kh
228 if f then return $ Just kh
229 else return Nothing
230
231nonComment :: String -> Bool
232nonComment [] = False
233nonComment ('#':_) = False
234nonComment ('|':_) = False -- hashed, undecodeable
235nonComment _ = True
236
237getWithPort :: String -> String
238getWithPort ('[':str) = host ++ " -p " ++ port
239 where (host,p) = break (==']') str
240 port = case p of
241 ']':':':x -> x
242 _ -> "22"
243getWithPort str = str
diff --git a/accounts/gkleen@sif/xmonad/package.yaml b/accounts/gkleen@sif/xmonad/package.yaml
new file mode 100644
index 00000000..48de1a53
--- /dev/null
+++ b/accounts/gkleen@sif/xmonad/package.yaml
@@ -0,0 +1,30 @@
1name: xmonad-yggdrasil
2
3executables:
4 xmonad:
5 dependencies:
6 - base
7 - xmonad
8 - xmonad-contrib
9 - aeson
10 - bytestring
11 - text
12 - temporary
13 - filepath
14 - directory
15 - network
16 - unix
17 - utf8-string
18 - parsec
19 - process
20 - mtl
21 - X11
22 - transformers
23 - containers
24 - hostname
25 - libnotify
26
27 main: xmonad.hs
28 source-dirs:
29 - .
30 - lib
diff --git a/accounts/gkleen@sif/xmonad/stack.nix b/accounts/gkleen@sif/xmonad/stack.nix
new file mode 100644
index 00000000..17a49e04
--- /dev/null
+++ b/accounts/gkleen@sif/xmonad/stack.nix
@@ -0,0 +1,17 @@
1{ ghc, nixpkgs ? import ./nixpkgs.nix {} }:
2
3let
4 haskellPackages = import ./stackage.nix { inherit nixpkgs; };
5 inherit (nixpkgs {}) pkgs;
6in pkgs.haskell.lib.buildStackProject {
7 inherit ghc;
8 inherit (haskellPackages) stack;
9 name = "stackenv";
10 buildInputs = (with pkgs;
11 [ xorg.libX11 xorg.libXrandr xorg.libXinerama xorg.libXScrnSaver xorg.libXext xorg.libXft
12 cairo
13 glib
14 ]) ++ (with haskellPackages;
15 [
16 ]);
17}
diff --git a/accounts/gkleen@sif/xmonad/stack.yaml b/accounts/gkleen@sif/xmonad/stack.yaml
new file mode 100644
index 00000000..b8ed1147
--- /dev/null
+++ b/accounts/gkleen@sif/xmonad/stack.yaml
@@ -0,0 +1,10 @@
1nix:
2 enable: true
3 shell-file: stack.nix
4
5resolver: lts-13.21
6
7packages:
8 - .
9
10extra-deps: []
diff --git a/accounts/gkleen@sif/xmonad/xmonad-yggdrasil.nix b/accounts/gkleen@sif/xmonad/xmonad-yggdrasil.nix
new file mode 100644
index 00000000..e8786d35
--- /dev/null
+++ b/accounts/gkleen@sif/xmonad/xmonad-yggdrasil.nix
@@ -0,0 +1,21 @@
1{ mkDerivation, aeson, base, bytestring, containers, directory
2, filepath, hostname, hpack, mtl, network, parsec, process, stdenv
3, temporary, transformers, unix, utf8-string, X11, xmonad
4, xmonad-contrib, libnotify
5}:
6mkDerivation {
7 pname = "xmonad-yggdrasil";
8 version = "0.0.0";
9 src = ./.;
10 isLibrary = false;
11 isExecutable = true;
12 libraryToolDepends = [ hpack ];
13 executableHaskellDepends = [
14 aeson base bytestring containers directory filepath hostname mtl
15 network parsec process temporary transformers unix utf8-string X11
16 xmonad xmonad-contrib libnotify
17 ];
18 preConfigure = "hpack";
19 license = "unknown";
20 hydraPlatforms = stdenv.lib.platforms.none;
21}
diff --git a/accounts/gkleen@sif/xmonad/xmonad.hs b/accounts/gkleen@sif/xmonad/xmonad.hs
new file mode 100644
index 00000000..f3a59f34
--- /dev/null
+++ b/accounts/gkleen@sif/xmonad/xmonad.hs
@@ -0,0 +1,898 @@
1{-# LANGUAGE TupleSections, ViewPatterns, OverloadedStrings, FlexibleInstances, UndecidableInstances, MultiWayIf #-}
2
3import XMonad
4import XMonad.Hooks.DynamicLog
5import XMonad.Hooks.ManageDocks
6import XMonad.Util.Run
7import XMonad.Util.Loggers
8import XMonad.Util.EZConfig(additionalKeys)
9import System.IO
10import System.IO.Error
11import System.Environment
12import Data.Map (Map)
13import qualified Data.Map as Map
14import qualified XMonad.StackSet as W
15import System.Exit
16import Control.Monad.State (get)
17-- import XMonad.Layout.Spiral
18import Data.Ratio
19import Data.List
20import Data.Char
21import Data.Maybe (fromMaybe, listToMaybe, maybeToList, catMaybes, isJust)
22import XMonad.Layout.Tabbed
23import XMonad.Prompt
24import XMonad.Prompt.Input
25import XMonad.Util.Scratchpad
26import XMonad.Util.NamedScratchpad
27import Control.Monad (sequence, liftM, liftM2, join, void)
28import XMonad.Util.WorkspaceCompare
29import XMonad.Layout.NoBorders
30import XMonad.Layout.PerWorkspace
31import XMonad.Layout.SimplestFloat
32import XMonad.Layout.Renamed
33import XMonad.Layout.Reflect
34import XMonad.Layout.OnHost
35import XMonad.Layout.Combo
36import XMonad.Layout.ComboP
37import XMonad.Layout.Column
38import XMonad.Layout.TwoPane
39import XMonad.Layout.IfMax
40import XMonad.Layout.LayoutBuilder
41import XMonad.Layout.WindowNavigation
42import XMonad.Layout.Dwindle
43import XMonad.Layout.TrackFloating
44import System.Process
45import System.Directory (removeFile)
46import System.Posix.Files
47import System.FilePath ((</>))
48import Control.Concurrent
49import System.Posix.Process (getProcessID)
50import System.IO.Error
51import System.IO
52import XMonad.Hooks.ManageHelpers hiding (CW)
53import XMonad.Hooks.UrgencyHook as U
54import XMonad.Hooks.EwmhDesktops
55import XMonad.StackSet (RationalRect (..))
56import Control.Monad (when, filterM, (<=<))
57import Graphics.X11.ExtraTypes.XF86
58import XMonad.Util.Cursor
59import XMonad.Actions.Warp
60import XMonad.Actions.FloatKeys
61import XMonad.Util.SpawnOnce
62import System.Directory
63import System.FilePath
64import XMonad.Actions.CopyWindow
65import XMonad.Hooks.ServerMode
66import XMonad.Actions.Commands
67import XMonad.Actions.CycleWS
68import XMonad.Actions.RotSlaves
69import XMonad.Actions.UpdatePointer
70import XMonad.Prompt.Window
71import Data.IORef
72import Data.Monoid
73import Data.String
74import qualified XMonad.Actions.PhysicalScreens as P
75
76import XMonad.Layout.IM
77
78import XMonad.Prompt.MyShell
79import XMonad.Prompt.MyPass
80import XMonad.Prompt.MySsh
81
82import XMonad.Mpv
83
84import Network.HostName
85
86import Control.Applicative ((<$>))
87
88import Libnotify as Notify hiding (appName)
89import qualified Libnotify as Notify (appName)
90import Libnotify (Notification)
91-- import System.Information.Battery
92
93import Data.Int (Int32)
94
95import System.Posix.Process
96import System.Posix.Signals
97import System.Posix.IO as Posix
98import Control.Exception
99
100import System.IO.Unsafe
101
102import Control.Monad.Trans.Class
103import Control.Monad.Trans.Maybe
104
105import Data.Fixed (Micro)
106
107import qualified Data.Text as Text
108import Data.Ord (comparing)
109import Debug.Trace
110
111instance MonadIO m => IsString (m ()) where
112 fromString = spawn
113
114type KeyMap = Map (ButtonMask, KeySym) (X ())
115
116data Host = Host
117 { hName :: HostName
118 , hManageHook :: ManageHook
119 , hWsp :: Integer -> WorkspaceId
120 , hCoWsp :: String -> Maybe WorkspaceId
121 , hKeysMod :: XConfig Layout -> (KeyMap -> KeyMap)
122 , hScreens :: [P.PhysicalScreen]
123 , hKbLayouts :: [(String, Maybe String)]
124 , hCmds :: X [(String, X ())]
125 , hKeyUpKeys :: XConfig Layout -> KeyMap
126 }
127
128defaultHost = Host { hName = "unkown"
129 , hManageHook = composeOne [manageScratchTerm]
130 , hWsp = show
131 , hCoWsp = const Nothing
132 , hKeysMod = const id
133 , hScreens = [0,1..]
134 , hKbLayouts = [ ("us", Just "dvp")
135 , ("us", Nothing)
136 , ("de", Nothing)
137 ]
138 , hCmds = return []
139 , hKeyUpKeys = const Map.empty
140 }
141
142browser :: String
143browser = "env MOZ_USE_XINPUT2=1 firefox"
144
145hostFromName :: HostName -> Host
146hostFromName h@("vali") = defaultHost { hName = h
147 , hManageHook = composeOne $ catMaybes [ Just manageScratchTerm
148 , assign "web" $ className =? ".dwb-wrapped"
149 , assign "web" $ className =? "Chromium"
150 , assign "work" $ className =? "Emacs"
151 , assign "media" $ className =? "mpv"
152 ]
153 , hWsp = hWsp
154 , hCoWsp = hCoWsp
155 , hKeysMod = \conf -> Map.union $ (Map.fromList $ join $ map (spawnBindings conf) [ (xK_d, ["chromium", "chromium $(xclip -o)"])
156 , (xK_e, ["emacsclient -c"])
157 ])
158 `Map.union`
159 ( Map.fromList [ ((XMonad.modMask conf .|. controlMask, xK_Return), scratchpadSpawnActionCustom $ (XMonad.terminal conf) ++ " -name scratchpad -title scratchpad -e tmux new-session -D -s scratch")
160 ] )
161 , hScreens = hScreens defaultHost
162 }
163 where
164 workspaceNames = Map.fromList [ (2, "web")
165 , (3, "work")
166 , (10, "media")
167 ]
168 hWsp = wspFromMap workspaceNames
169 hCoWsp = coWspFromMap workspaceNames
170 assign wsp test = (\wsp -> test -?> doShift wsp) <$> hCoWsp wsp
171hostFromName h
172 | h `elem` ["hel", "sif"] = defaultHost { hName = h
173 , hManageHook = namedScratchpadManageHook scratchpads <+> composeOne (catMaybes
174 [ assign "mpv" $ className =? "mpv"
175 , assign "mpv" $ (className =? "URxvt" <&&> title =? "irssi")
176 , assign "mpv" $ (className =? "URxvt" <&&> resource =? "presentation")
177 , assign "mpv" $ stringProperty "WM_WINDOW_ROLE" =? "presentation"
178 , assign "read" $ stringProperty "WM_WINDOW_ROLE" =? "presenter"
179 , assign "mpv" $ className =? "factorio"
180 , assign "web" $ className =? "chromium-browser"
181 , assign "web" $ className =? "Google-chrome"
182 , assign "work" $ (appName =? "Devtools" <&&> className =? "Firefox")
183 , assign "work" $ className =? "Postman"
184 , assign "web" $ className =? "Firefox"
185 , assign "comm" $ (className =? "URxvt" <&&> resource =? "comm")
186 , assign "comm" $ (className =? "Emacs" <&&> title =? "Mail")
187 , assign "comm" $ className =? "Zulip"
188 , assign "comm" $ className =? "Discord"
189 , assign "media" $ (className =? "URxvt" <&&> resource =? "media")
190 , assign "media" $ (className =? "URxvt" <&&> title =? "streamlink")
191 , assign "media" $ (className =? "URxvt" <&&> title =? "mpv")
192 , assign "monitor" $ (className =? "URxvt" <&&> fmap ("monitor" `isInfixOf`) title)
193 , assign "monitor" $ className =? "Grafana"
194 , Just $ (className =? "URxvt" <&&> resource =? "htop") -?> centerFloat
195 , Just $ (className =? "Scp-dbus-service.py") -?> centerFloat
196 , Just $ (className =? "URxvt" <&&> resource =? "log") -?> centerFloat
197 , assign "work" $ className =? "URxvt"
198 , assign' ["work", "uni"] $ (className =? "Emacs" <&&> appName /=? "Edit_with_Emacs_FRAME")
199 , assign' ["work", "uni"] $ className =? "jetbrains-idea-ce"
200 , assign "read" $ className =? "llpp"
201 , assign "read" $ className =? "Evince"
202 , assign "read" $ fmap ("zathura" `isInfixOf`) title
203 , assign "read" $ className =? "MuPDF"
204 , assign "read" $ className =? "Xournal"
205 , assign "read" $ appName =? "com-trollworks-gcs-app-GCS"
206 , assign "read" $ appName =? "Tux.py"
207 , assign "read" $ className =? "Gnucash"
208 , assign "comm" $ className =? "Skype"
209 , assign "comm" $ className =? "Daily"
210 , assign "comm" $ className =? "Pidgin"
211 , assign "comm" $ className =? "Slack"
212 , Just $ (resource =? "xvkbd") -?> doRectFloat $ RationalRect (1 % 8) (3 % 8) (6 % 8) (4 % 8)
213 , Just $ (stringProperty "_NET_WM_WINDOW_TYPE" =? "_NET_WM_WINDOW_TYPE_DIALOG") -?> doFloat
214 , Just $ (className =? "Dunst") -?> doFloat
215 , Just $ (className =? "Xmessage") -?> doCenterFloat
216 , Just $ (className =? "Nm-openconnect-auth-dialog") -?> centerFloat
217 , Just $ (className =? "Pinentry") -?> doCenterFloat
218 , Just $ (className =? "pinentry") -?> doCenterFloat
219 , Just $ (appName =? "Edit_with_Emacs_FRAME") -?> centerFloat
220 , Just $ (stringProperty "WM_WINDOW_ROLE" =? "GtkFileChooseDialog") -?> centerFloatSmall
221 , Just $ (className =? "Nvidia-settings") -?> doCenterFloat
222 , Just $ fmap ("Minetest" `isInfixOf`) title -?> doIgnore
223 , Just $ fmap ("Automachef" `isInfixOf`) title -?> doIgnore
224 ])
225 , hWsp = hWsp
226 , hCoWsp = hCoWsp
227 , hKeysMod = \conf -> Map.union $ (Map.fromList $ join $ map (spawnBindings conf) [ (xK_e, ["emacsclient -c"])
228 , (xK_d, [fromString browser, fromString $ browser ++ " $(xclip -o)", fromString $ "notmuch-links"])
229 , (xK_f, ["urxvtc -name comm -title Feeds -e mosh odin -- tmux new-session -ADs comm"])
230 , (xK_c, [ inputPrompt xPConfig "dc" ?+ dc ])
231 , (xK_g, ["pidgin"])
232 , (xK_s, ["skype"])
233 -- , (xK_p, [mkPassPrompt "Type password" pwType xPConfig, mkPassPrompt "Show password" pwShow xPConfig, mkPassPrompt "Copy password" pwClip xPConfig])
234 , (xK_w, ["sudo rewacom"])
235 , (xK_y, [ "tmux new-window -dt media /var/media/link.hs $(xclip -o)"
236 , "urxvtc -name media -e tmuxp load /var/media"
237 ])
238 , (xK_l, [ "tmux new-window -dt media mpv $(xclip -o)"
239 , "tmux new-window -dt media streamlink --retry-open 10 $(xclip -o)"
240 ])
241 , (xK_m, [ "emacsclient -c -F \"'(title . \\\"Mail\\\")\" -e '(notmuch)'"
242 , "emacsclient -c -F \"'(title . \\\"Mail\\\")\" -e '(notmuch-mua-new-mail)'"
243 , "emacsclient -c -F \"'(title . \\\"Mail\\\")\" -e \"(browse-url-mail \"$(xclip -o)\")\""
244 ])
245 , (xK_Return, ["keynav start,windowzoom", "keynav start"])
246 , (xK_t, [inputPrompt xPConfig "fuzzytime timer" ?+ fuzzytime, fuzzytime "unset", work_fuzzytime])
247 , (xK_a, [inputPrompt xPConfig "adjmix" ?+ adjmix])
248 , (xK_s, [ inputPromptWithCompl xPConfig "start synergy" synergyCompl ?+ synergyStart
249 , inputPromptWithCompl xPConfig "stop synergy" synergyCompl ?+ synergyStop
250 ])
251 , (xK_h, [ "urxvtc -name htop -e htop"
252 , "urxvtc -name log -e journalctl -xef"
253 ])
254 , (xK_x, [ "autorandr -c"
255 , "autorandr -fl default"
256 ])
257 , (xK_z, [ "zulip -- --force-device-scale-factor=2"
258 ])
259 ])
260 `Map.union`
261 ( Map.fromList [ ((XMonad.modMask conf .|. controlMask, xK_Return), namedScratchpadAction scratchpads "term")
262 , ((XMonad.modMask conf .|. controlMask, xK_a), namedScratchpadAction scratchpads "pavucontrol")
263 , ((XMonad.modMask conf .|. controlMask, xK_w), namedScratchpadAction scratchpads "alarms")
264 , ((XMonad.modMask conf .|. controlMask, xK_b), namedScratchpadAction scratchpads "blueman")
265 , ((XMonad.modMask conf .|. controlMask, xK_p), namedScratchpadAction scratchpads "keepassxc")
266 , ((XMonad.modMask conf .|. controlMask, xK_t), namedScratchpadAction scratchpads "toggl")
267 , ((XMonad.modMask conf .|. controlMask, xK_e), namedScratchpadAction scratchpads "emacs")
268 , ((XMonad.modMask conf .|. controlMask, xK_m), namedScratchpadAction scratchpads "calendar")
269 , ((XMonad.modMask conf .|. controlMask, xK_f), namedScratchpadAction scratchpads "music")
270 , ((XMonad.modMask conf .|. mod1Mask, xK_Up), rotate U)
271 , ((XMonad.modMask conf .|. mod1Mask, xK_Down), rotate D)
272 , ((XMonad.modMask conf .|. mod1Mask, xK_Left), rotate L)
273 , ((XMonad.modMask conf .|. mod1Mask, xK_Right), rotate R)
274 -- , ((XMonad.modMask conf .|. shiftMask, xK_a), startMute "hel")
275 ] )
276 , hKeyUpKeys = \conf -> Map.fromList [ -- ((XMonad.modMask conf .|. shiftMask, xK_a), stopMute "hel")
277 ]
278 , hScreens = hScreens defaultHost
279 , hCmds = return [ ("prev-workspace", prevWS)
280 , ("next-workspace", nextWS)
281 , ("prev-window", rotAllDown)
282 , ("next-window", rotAllUp)
283 , ("banish", banishScreen LowerRight)
284 , ("update-gpg-tty", safeSpawn "gpg-connect-agent" ["UPDATESTARTUPTTY", "/bye"])
285 , ("rescreen", rescreen)
286 , ("repanel", do
287 spawn "nm-applet"
288 spawn "blueman-applet"
289 spawn "pasystray"
290 spawn "kdeconnect-indicator"
291 spawn "dunst -print"
292 spawn "udiskie"
293 spawn "autocutsel -s PRIMARY"
294 spawn "autocutsel -s CLIPBOARD"
295 )
296 , ("pause", mediaMpv $ MpvSetProperty "pause" True)
297 , ("unpause", mediaMpv $ MpvSetProperty "pause" False)
298 , ("exit", io $ exitWith ExitSuccess)
299 ]
300 }
301 where
302 withGdkScale act = void . xfork $ setEnv "GDK_SCALE" "2" >> act
303 workspaceNames = Map.fromList [ (1, "comm")
304 , (2, "web")
305 , (3, "work")
306 , (4, "read")
307 , (5, "monitor")
308 , (6, "uni")
309 , (9, "media")
310 , (10, "mpv")
311 ]
312 scratchpads = [ NS "term" "urxvtc -name scratchpad -title scratchpad -e tmux new-session -AD -s scratch" (resource =? "scratchpad") centerFloat
313 , NS "pavucontrol" "pavucontrol" (resource =? "pavucontrol") centerFloat
314 , NS "alarms" "alarm-clock-applet" (className =? "Alarm-clock-applet" <&&> title =? "Alarms") centerFloat
315 , NS "blueman" "blueman-manager" (className =? ".blueman-manager-wrapped") centerFloat
316 , NS "keepassxc" "keepassxc" (className =? "KeePassXC") centerFloat
317 , NS "toggl" "toggldesktop" (className =? "Toggl Desktop") centerFloat
318 , NS "calendar" "minetime -- --force-device-scale-factor=1.6" (className =? "MineTime") centerFloat
319 , NS "emacs" "emacsclient -c -F \"'(title . \\\"Scratchpad\\\")\"" (className =? "Emacs" <&&> title =? "Scratchpad") centerFloat
320 , NS "music" "google-play-music-desktop-player --force-device-scale-factor=1.6" (className =? "Google Play Music Desktop Player") centerFloat
321 ]
322 centerFloat = customFloating $ RationalRect (1 % 16) (1 % 16) (7 % 8) (7 % 8)
323 centerFloatSmall = customFloating $ RationalRect (1 % 4) (1 % 4) (1 % 2) (1 % 2)
324 hWsp = wspFromMap workspaceNames
325 hCoWsp = coWspFromMap workspaceNames
326 assign wsp test = (\wsp -> test -?> doShift wsp) <$> hCoWsp wsp
327 assign' :: [String] -> Query Bool -> Maybe MaybeManageHook
328 assign' wsps test = do
329 wsIds <- mapM hCoWsp wsps
330 return $ test -?> go wsIds
331 where
332 go :: [WorkspaceId] -> ManageHook
333 go wsps = do
334 visWsps <- liftX $ (\wset -> W.tag . W.workspace <$> W.current wset : W.visible wset) <$> gets windowset
335 case (filter (`elem` visWsps) wsps, wsps) of
336 (wsp : _, _) -> doShift wsp
337 (_, wsp : _) -> doShift wsp
338 ([], []) -> return mempty
339 rotate rot = do
340 safeSpawn "xrandr" ["--output", "eDP-1", "--rotate", xrandrDir]
341 mapM_ rotTouch touchscreens
342 where
343 xrandrDir = case rot of
344 U -> "normal"
345 L -> "left"
346 R -> "right"
347 D -> "inverted"
348 matrix = case rot of
349 U -> [ [ 1, 0, 0]
350 , [ 0, 1, 0]
351 , [ 0, 0, 1]
352 ]
353 L -> [ [ 0, -1, 1]
354 , [ 1, 0, 0]
355 , [ 0, 0, 1]
356 ]
357 R -> [ [ 0, 1, 0]
358 , [-1, 0, 1]
359 , [ 0, 0, 1]
360 ]
361 D -> [ [-1, 0, 1]
362 , [ 0, -1, 1]
363 , [ 0, 0, 1]
364 ]
365 touchscreens = [ "Wacom Co.,Ltd. Pen and multitouch sensor Finger touch"
366 , "Wacom Co.,Ltd. Pen and multitouch sensor Pen stylus"
367 , "Wacom Co.,Ltd. Pen and multitouch sensor Pen eraser"
368 ]
369 rotTouch screen = do
370 safeSpawn "xinput" $ ["set-prop", screen, "Coordinate Transformation Matrix"] ++ map (\n -> show n ++ ",") (concat matrix)
371 safeSpawn "xinput" ["map-to-output", screen, "eDP-1"]
372 withPw f label = io . void . forkProcess $ do
373 uninstallSignalHandlers
374 void $ createSession
375 (dropWhileEnd isSpace -> pw) <- readCreateProcess (proc "pass" ["show", label]) ""
376 void $ f pw
377 pwType :: String -> X ()
378 pwType = withPw $ readCreateProcess (proc "xdotool" ["type", "--clearmodifiers", "--file", "-"])
379 pwClip label = safeSpawn "pass" ["show", "--clip", label]
380 pwShow :: String -> X ()
381 pwShow = withPw $ \pw -> do
382 xmessage <- fromMaybe "xmessage" <$> liftIO (lookupEnv "XMONAD_XMESSAGE")
383 readCreateProcess (proc xmessage ["-file", "-"]) pw
384 fuzzytime str = safeSpawn "fuzzytime" $ "timer" : words str
385 work_fuzzytime = io . void . forkProcess $ do
386 readCreateProcess (proc "worktime" []) "" >>= safeSpawn "fuzzytime" . ("timer" : ) . pure
387 adjmix str = safeSpawn "adjmix" $ words str
388 dc expr = void . xfork $ do
389 result <- readProcess "dc" [] $ expr ++ "f"
390 let
391 (first : rest) = filter (not . null) $ lines result
392 notification = Notify.summary first <> Notify.body (unlines rest) <> Notify.timeout Infinite <> Notify.urgency Normal <> Notify.appName "dc"
393 void $ Notify.display notification
394 synergyCompl = mkComplFunFromList' ["mathw86"]
395 synergyStart host = safeSpawn "systemctl" ["--user", "start", "synergy-rtunnel@" ++ host ++ ".service"]
396 synergyStop host = safeSpawn "systemctl" ["--user", "stop", "synergy-rtunnel@" ++ host ++ ".service"]
397
398hostFromName _ = defaultHost
399
400-- muteRef :: IORef (Maybe (String, Notification))
401-- {-# NOINLINE muteRef #-}
402-- muteRef = unsafePerformIO $ newIORef Nothing
403
404-- startMute, stopMute :: String -> X ()
405-- startMute sink = liftIO $ do
406-- muted <- isJust <$> readIORef muteRef
407-- when (not muted) $ do
408-- let
409-- notification = Notify.summary "Muted" <> Notify.timeout Infinite <> Notify.urgency Normal
410-- level = "0.0dB"
411-- -- level <- runProcessWithInput "ssh" ["bragi", "cat", "/dev/shm/mix/" ++ sink ++ "/level"] ""
412-- -- callProcess "ssh" ["bragi", "adjmix", "-t", sink, "-o", "0"]
413-- hPutStrLn stderr "Mute"
414-- writeIORef muteRef . Just . (level, ) =<< Notify.display notification
415-- stopMute sink = liftIO $ do
416-- let
417-- unmute (Just (level, notification)) = do
418-- hPutStrLn stderr "Unmute"
419-- -- callProcess "ssh" ["bragi", "adjmix", "-t", sink, "-o", level]
420-- Notify.close notification
421-- unmute Nothing = return ()
422-- muted <- isJust <$> readIORef muteRef
423-- when muted . join . atomicModifyIORef muteRef $ (Nothing, ) . unmute
424
425wspFromMap workspaceNames = \i -> case Map.lookup i workspaceNames of
426 Just str -> show i ++ " " ++ str
427 Nothing -> show i
428
429coWspFromMap workspaceNames = \str -> case filter ((== str) . snd) $ Map.toList workspaceNames of
430 [] -> Nothing
431 [(i, _)] -> Just $ wspFromMap workspaceNames i
432 _ -> Nothing
433
434spawnModifiers = [0, controlMask, shiftMask .|. controlMask]
435spawnBindings :: XConfig layout -> (KeySym, [X ()]) -> [((KeyMask, KeySym), X ())]
436spawnBindings conf (k, cmds) = zipWith (\m cmd -> ((modm .|. mod1Mask .|. m, k), cmd)) spawnModifiers cmds
437 where
438 modm = XMonad.modMask conf
439
440manageScratchTerm = (resource =? "scratchpad" <||> resource =? "keysetup") -?> doRectFloat $ RationalRect (1 % 16) (1 % 16) (7 % 8) (7 % 8)
441
442tabbedLayout t = renamed [Replace "Tabbed"] $ reflectHoriz $ t CustomShrink $ tabbedTheme
443tabbedLayoutHoriz t = renamed [Replace "Tabbed Horiz"] $ reflectVert $ t CustomShrink $ tabbedTheme
444tabbedTheme = def
445 { activeColor = "black"
446 , inactiveColor = "black"
447 , urgentColor = "black"
448 , activeBorderColor = "grey"
449 , inactiveBorderColor = "#202020"
450 , urgentBorderColor = "#bb0000"
451 , activeTextColor = "grey"
452 , inactiveTextColor = "grey"
453 , urgentTextColor = "grey"
454 , decoHeight = 32
455 , fontName = "xft:Fira Mono for Powerline:style=Medium:pixelsize=22.5"
456 }
457
458main :: IO ()
459main = do
460 arguments <- either (const []) id <$> tryIOError getArgs
461 case arguments of
462 ["--command", s] -> do
463 d <- openDisplay ""
464 rw <- rootWindow d $ defaultScreen d
465 a <- internAtom d "XMONAD_COMMAND" False
466 m <- internAtom d s False
467 allocaXEvent $ \e -> do
468 setEventType e clientMessage
469 setClientMessageEvent e rw a 32 m currentTime
470 sendEvent d rw False structureNotifyMask e
471 sync d False
472 _ -> do
473 -- batteryMon <- xfork $ monitorBattery Nothing Nothing
474 hostname <- getHostName
475 let
476 host = hostFromName hostname
477 setEnv "HOST" hostname
478 let myConfig = withHostUrgency . ewmh $ docks def
479 { manageHook = hManageHook host
480 , terminal = "urxvtc"
481 , layoutHook = smartBorders . avoidStruts $ windowNavigation layout'
482 , logHook = do
483 dynamicLogString xmobarPP' >>= writeProps
484 updatePointer (99 % 100, 98 % 100) (0, 0)
485 , modMask = mod4Mask
486 , keys = \conf -> hKeysMod host conf $ myKeys' conf host
487 , workspaces = take (length numKeys) $ map wsp [1..]
488 , startupHook = setDefaultCursor xC_left_ptr
489 , normalBorderColor = "#202020"
490 , focusedBorderColor = "grey"
491 , handleEventHook = fullscreenEventHook <+> (serverModeEventHookCmd' $ hCmds host) <+> keyUpEventHook
492 }
493 writeProps str = do
494 let encodeCChar = map $ fromIntegral . fromEnum
495 atoms = [ "_XMONAD_WORKSPACES"
496 , "_XMONAD_LAYOUT"
497 , "_XMONAD_TITLE"
498 ]
499 (flip mapM_) (zip atoms (lines str)) $ \(atom', content) -> do
500 ustring <- getAtom "UTF8_STRING"
501 atom <- getAtom atom'
502 withDisplay $ \dpy -> io $ do
503 root <- rootWindow dpy $ defaultScreen dpy
504 changeProperty8 dpy root atom ustring propModeReplace $ encodeCChar content
505 sync dpy True
506 wsp = hWsp host
507 -- We can´t define per-host layout modifiers because we lack dependent types
508 layout' = onHost "skadhi" ( onWorkspace (wsp 1) (Full ||| withIM (1%5) (Title "Buddy List") tabbedLayout') $
509 onWorkspace (wsp 10) Full $
510 onWorkspace (wsp 2) (Full ||| tabbedLayout') $
511 onWorkspace (wsp 5) tabbedLayout' $
512 onWorkspace (wsp 8) (withIM (1%5) (Title "Friends") tabbedLayout') $
513 defaultLayouts
514 ) $
515 onHost "vali" ( onWorkspace (wsp 2) (Full ||| tabbedLayout' ||| combineTwo (TwoPane 0.01 0.57) Full tabbedLayout') $
516 onWorkspace (wsp 3) workLayouts $
517 defaultLayouts
518 ) $
519 onHost "hel" ( onWorkspace (wsp 1) (withIM (1 % 8) (Title "Buddy List") $ trackFloating tabbedLayout') $
520 onWorkspace (wsp 2) (tabbedLayout''' ||| Dwindle R CW 1 (5 % 100)) $
521 onWorkspace (wsp 3) workLayouts $
522 onWorkspace (wsp 6) workLayouts $
523 onWorkspace (wsp 4) (tabbedLayout' ||| tabbedLayoutHoriz' ||| Dwindle R CW 1 (5 % 100)) $
524 onWorkspace (wsp 5) (tabbedLayout''' ||| Dwindle R CW 1 (5 % 100)) $
525 onWorkspace (wsp 10) (tabbedLayout''' ||| combineTwoP (TwoPane (1 % 100) (3 % 4)) tabbedLayout''' tabbedLayout''' (ClassName "mpv") ||| Dwindle R CW 1 (5 % 100)) $
526 defaultLayouts
527 ) $
528 onHost "sif" ( onWorkspace (wsp 1) (withIM (1 % 8) (Title "Buddy List") $ trackFloating tabbedLayout') $
529 onWorkspace (wsp 2) (tabbedLayout''' ||| Dwindle R CW 1 (5 % 100)) $
530 onWorkspace (wsp 3) workLayouts $
531 onWorkspace (wsp 6) workLayouts $
532 onWorkspace (wsp 4) (tabbedLayout' ||| tabbedLayoutHoriz' ||| Dwindle R CW 1 (5 % 100)) $
533 onWorkspace (wsp 5) (tabbedLayout''' ||| Dwindle R CW 1 (5 % 100)) $
534 onWorkspace (wsp 10) (tabbedLayout''' ||| combineTwoP (TwoPane (1 % 100) (3 % 4)) tabbedLayout''' tabbedLayout''' (ClassName "mpv") ||| Dwindle R CW 1 (5 % 100)) $
535 defaultLayouts
536 ) $
537 defaultLayouts
538 -- tabbedLayout''' = renamed [Replace "Tabbed'"] $ IfMax 1 (noBorders Full) (tabbedLayout tabbedBottomAlways)
539 tabbedLayout''' = tabbedLayout tabbedBottom
540 tabbedLayout' = tabbedLayout tabbedBottomAlways
541 tabbedLayoutHoriz' = tabbedLayoutHoriz tabbedLeftAlways
542 defaultLayouts = {- spiralWithDir East CW (1 % 2) -} Dwindle R CW 1 (5 % 100) ||| tabbedLayout' ||| Full
543 -- workLayouts = {- spiralWithDir East CW (1 % 2) -} Dwindle R CW (2 % 1) (5 % 100) ||| tabbedLayout' ||| Full
544 workLayouts = tabbedLayout' ||| (renamed [Replace "Combined"] $ combineTwoP (TwoPane (1 % 100) (1891 % 2560)) tabbedLayout''' (Column 1.6) (ClassName "Postman" `Or` ClassName "Emacs" `Or` ClassName "jetbrains-idea-ce" `Or` (Resource "Devtools" `And` ClassName "Firefox"))) ||| Full ||| Dwindle R CW 1 (5 % 100)
545 sqrtTwo = approxRational (sqrt 2) (1 / 2560)
546 xmobarPP' = xmobarPP { ppTitle = shorten 80
547 , ppSort = (liftM2 (.)) getSortByIndex $ return scratchpadFilterOutWorkspace
548 , ppUrgent = wrap "(" ")" . xmobarColor "red" ""
549 , ppHiddenNoWindows = xmobarColor "#202020" "" . wrap "(" ")"
550 , ppVisible = wrap "(" ")" . xmobarColor "yellow" ""
551 , ppCurrent = wrap "(" ")" . xmobarColor "green" ""
552 , ppHidden = wrap "(" ")"
553 , ppWsSep = " "
554 , ppSep = "\n"
555 }
556 withHostUrgency = case hostname of
557 "hel" -> withUrgencyHookC urgencyHook' $ urgencyConfig { suppressWhen = U.Never, remindWhen = Dont }
558 "sif" -> withUrgencyHookC urgencyHook' $ urgencyConfig { suppressWhen = U.Never, remindWhen = Dont }
559 _ -> id
560 urgencyHook' window = do
561 runQuery ((resource =? "comm" <||> resource =? "Pidgin" <||> className =? "Gajim" <||> className =? "Skype") --> safeSpawn "thinklight" ["Blink", "100"]) window
562 urgencyHook (BorderUrgencyHook { urgencyBorderColor = "#bb0000" }) window
563 shutdown :: SomeException -> IO a
564 shutdown e = do
565 let pids = [ -- batteryMon
566 ]
567 mapM_ (signalProcess sigTERM) pids
568 mapM_ (getProcessStatus False False) pids
569 throw e
570 keyUpEventHook :: Event -> X All
571 keyUpEventHook event = handle event >> return (All True)
572 where
573 handle (KeyEvent { ev_event_type = t, ev_state = m, ev_keycode = code })
574 | t == keyRelease = withDisplay $ \dpy -> do
575 s <- io $ keycodeToKeysym dpy code 0
576 mClean <- cleanMask m
577 ks <- asks $ hKeyUpKeys host . config
578 userCodeDef () $ whenJust (Map.lookup (mClean, s) ks) id
579 | otherwise = return ()
580 handle _ = return ()
581 handle shutdown $ launch myConfig
582
583secs :: Int -> Int
584secs = (* 1000000)
585
586-- monitorBattery :: Maybe BatteryContext -> Maybe Notification -> IO ()
587-- monitorBattery Nothing n = do
588-- ctx <- batteryContextNew
589-- case ctx of
590-- Nothing -> threadDelay (secs 10) >> monitorBattery Nothing n
591-- Just _ -> monitorBattery ctx n
592-- monitorBattery ctx@(Just ctx') n = do
593-- batInfo <- getBatteryInfo ctx'
594-- case batInfo of
595-- Nothing -> threadDelay (secs 1) >> monitorBattery ctx n
596-- Just batInfo -> do
597-- let n'
598-- | batteryState batInfo == BatteryStateDischarging
599-- , timeLeft <= 1200
600-- , timeLeft > 0 = Just $ summary "Discharging" <> hint "value" percentage <> urgency u <> body (duz timeLeft ++ "left")
601-- | otherwise = Nothing
602-- u
603-- | timeLeft <= 600 = Critical
604-- | timeLeft <= 1800 = Normal
605-- | otherwise = Low
606-- timeLeft = batteryTimeToEmpty batInfo
607-- percentage :: Int32
608-- percentage = round $ batteryPercentage batInfo
609-- ts = [("s", 60), ("m", 60), ("h", 24), ("d", 365), ("y", 1)]
610-- duz ms = ss
611-- where (ss, _) = foldl (\(ss, x) (s, y) -> ((if rem x y > 0 then show (rem x y) ++ s ++ " " else "") ++ ss , quot x y)) ("", ms) ts
612-- case n' of
613-- Just n' -> Notify.display (maybe mempty reuse n <> Notify.appName "monitorBattery" <> n') >>= (\n -> threadDelay (secs 2) >> monitorBattery ctx (Just n))
614-- Nothing -> threadDelay (secs 30) >> monitorBattery ctx n
615
616disableTouchpad, disableTrackpoint, enableTrackpoint, enableTouchpad :: X ()
617enableTouchpad = safeSpawn "xinput" ["enable", "SynPS/2 Synaptics TouchPad"]
618disableTouchpad = safeSpawn "xinput" ["disable", "SynPS/2 Synaptics TouchPad"]
619enableTrackpoint = safeSpawn "xinput" ["enable", "TPPS/2 IBM TrackPoint"]
620disableTrackpoint = safeSpawn "xinput" ["disable", "TPPS/2 IBM TrackPoint"]
621
622isDisabled :: String -> X Bool
623isDisabled str = do
624 out <- runProcessWithInput "xinput" ["list", str] ""
625 return $ "disabled" `isInfixOf` out
626
627
628spawnKeychain :: X ()
629spawnKeychain = do
630 home <- liftIO getHomeDirectory
631 let keys = (map ((home </>) . (".ssh/" ++)) ["id", "id-rsa"]) ++ ["6B13AA67"]
632 liftIO (maybe (return ()) (setEnv "SSH_ASKPASS") =<< findAskpass)
633 safeSpawn "keychain" . (["--agents", "gpg,ssh"] ++)=<< liftIO (filterM doesFileExist keys)
634 where
635 findAskpass = filter `liftM` readFile "/etc/zshrc"
636 filter = listToMaybe . catMaybes . map (stripPrefix "export SSH_ASKPASS=") . lines
637
638assimilateKeychain :: X ()
639assimilateKeychain = liftIO $ assimilateKeychain' >> return ()
640assimilateKeychain' = tryIOError $ do
641 -- pid <- getProcessID
642 -- tmpDir <- lookupEnv "TMPDIR"
643 -- let tmpDir' = fromMaybe "/tmp" tmpDir
644 -- tmpFile = tmpDir' </> "xmonad-keychain" ++ (show pid) ++ ".env"
645 env <- runProcessWithInput "sh" ["-c", "eval $(keychain --eval --noask --agents gpg,ssh); env"] "" -- > " ++ tmpFile] ""
646 -- env <- readFile tmpFile
647 let envVars = Map.fromList $ map (\(k, v) -> (k, tail' v)) $ map (span (/= '=')) $ envLines
648 envVars' = Map.filterWithKey (\k _ -> k `elem` transfer) envVars
649 transfer = ["SSH_AUTH_SOCK", "SSH_AGENT_PID", "GPG_AGENT_INFO"]
650 envLines = filter (elem '=') $ lines env :: [String]
651 sequence $ map (\(k, c) -> setEnv k c) $ Map.toList envVars'
652 -- removeFile tmpFile
653 where
654 tail' [] = []
655 tail' (x:xs) = xs
656
657
658numKeys = [xK_parenleft, xK_parenright, xK_braceright, xK_plus, xK_braceleft, xK_bracketright, xK_bracketleft, xK_exclam, xK_equal, xK_asterisk]
659
660instance Shrinker CustomShrink where
661 shrinkIt _ "" = [""]
662 shrinkIt s cs
663 | length cs >= 4 = cs : shrinkIt s ((reverse . drop 4 . reverse $ cs) ++ "...")
664 | otherwise = cs : shrinkIt s (init cs)
665
666xPConfig :: XPConfig
667xPConfig = def
668 { font = "xft:Fira Mono for Powerline:style=Medium:pixelsize=22.5"
669 , height = 32
670 , bgColor = "black"
671 , fgColor = "grey"
672 , fgHLight = "green"
673 , bgHLight = "black"
674 , borderColor = "grey"
675 , searchPredicate = (\needle haystack -> all (`isInfixOf` map toLower haystack) . map (map toLower) $ words needle)
676 , position = Top
677 }
678
679sshOverrides = map (\h -> mkOverride { oHost = h, oCommand = moshCmd . inTmux } )
680 [
681 "odin", "odin.asgard.yggdrasil"
682 , "ymir", "ymir.yggdrasil.li", "ymir.niflheim.yggdrasil"
683 , "surtr", "yggdrasil.li", "surtr.yggdrasil.li", "praseodym.org", "surtr.praseodym.org", "surtr.141.li", "141.li"
684 , "vindler", "vindler.alfheim.yggdrasil"
685 , "ullr"
686 , "heimdallr", "heimdallr.asgard.yggdrasil"
687 , "testworx"
688 ]
689 ++
690 map (\h -> mkOverride { oHost = h, oCommand = moshCmd' "/run/current-system/sw/bin/mosh-server" . withEnv [("TERM", "xterm")] . inTmux} )
691 [ "bragi", "bragi.asgard.yggdrasil"
692 ]
693 ++
694 map (\h -> mkOverride { oHost = h, oCommand = sshCmd . withEnv [("TERM", "xterm")] . inTmux } )
695 [ "remote.cip.ifi.lmu.de"
696 , "uniworx3", "uniworx4", "uniworxdb"
697 ]
698
699backlight :: (Rational -> Rational) -> X ()
700backlight f = void . xfork . liftIO $ do
701 [ _device
702 , _class
703 , read . Text.unpack -> currentBright
704 , _currentPercentage
705 , read . Text.unpack -> maximumBright
706 ] <- Text.splitOn "," . Text.pack <$> readProcess "brightnessctl" ["-m"] ""
707 let current = currentBright % maximumBright
708 new' = f current * fromIntegral maximumBright
709 new :: Integer
710 new | floor new' < 0 = 0
711 | ceiling new' > maximumBright = maximumBright
712 | new' >= maximumBright % 2 = ceiling new'
713 | otherwise = floor new'
714 callProcess "brightnessctl" ["-m", "s", show new]
715
716cycleThrough :: [Rational] -> (Rational -> Rational)
717cycleThrough opts current = fromMaybe currentOpt $ listToMaybe next'
718 where currentOpt = minimumBy (comparing $ abs . subtract current) opts
719 (_, _ : next') = break (== currentOpt) opts
720
721cycleKbLayout :: [(String, Maybe String)] -> X ()
722cycleKbLayout [] = return ()
723cycleKbLayout layouts = liftIO $ do
724 next <- (getNext . extract) `liftM` runProcessWithInput "setxkbmap" ["-query"] ""
725 let
726 args = case next of
727 (l, Just v) -> [l, v]
728 (l, Nothing) -> [l]
729 safeSpawn "setxkbmap" args
730 where
731 extract :: String -> Maybe (String, Maybe String)
732 extract str = listToMaybe $ do
733 ["layout:", l] <- str'
734 [(l, Just v) | ["variant:", v] <- str'] ++ pure (l, Nothing)
735 where
736 str' = map words $ lines str
737 getNext :: Maybe (String, Maybe String) -> (String, Maybe String)
738 getNext = maybe (head layouts) getNext'
739 getNext' x = case elemIndex x layouts of
740 Nothing -> getNext Nothing
741 Just i -> layouts !! ((i + 1) `mod` length layouts)
742
743mpvAll' :: MpvCommand -> IO [MpvResponse]
744mpvAll' = mpvAll "/var/media/.mpv-ipc"
745
746mpvOne' :: MpvCommand -> IO (Maybe MpvResponse)
747mpvOne' = mpvOne "/var/media/.mpv-ipc"
748
749mediaMpv :: MpvCommand -> X ()
750mediaMpv cmd = void . xfork $ print =<< mpvAll' cmd
751
752mediaMpvTogglePause :: X ()
753mediaMpvTogglePause = void . xfork $ do
754 paused <- mapM mpvResponse <=< mpvAll' $ MpvGetProperty "pause"
755 if
756 | and paused -> print <=< mpvAll' $ MpvSetProperty "pause" False
757 | otherwise -> print <=< mpvOne' $ MpvSetProperty "pause" True
758
759myKeys' conf host = Map.fromList $
760 -- launch a terminal
761 [ ((modm, xK_Return), spawn $ (XMonad.terminal conf) ++ " -e tmux")
762 , ((modm .|. shiftMask, xK_Return), spawn $ XMonad.terminal conf)
763
764 -- launch dmenu
765 --, ((modm, xK_d ), spawn "exe=`dmenu_path | dmenu` && eval \"exec $exe\"")
766 , ((modm, xK_d ), shellPrompt "Run: " xPConfig)
767 , ((modm .|. shiftMask, xK_d ), prompt "Run in Terminal: " ("urxvtc" ++ " -e") xPConfig)
768 , ((modm, xK_at ), sshPrompt sshOverrides xPConfig)
769
770 -- close focused window
771 , ((modm .|. shiftMask, xK_q ), kill)
772 , ((modm .|. controlMask .|. shiftMask, xK_q ), spawn "xkill")
773
774 -- Rotate through the available layout algorithms
775 , ((modm, xK_space ), sendMessage NextLayout)
776
777 -- Reset the layouts on the current workspace to default
778 , ((modm .|. controlMask, xK_r ), (setLayout $ XMonad.layoutHook conf) >> refresh)
779
780 -- Resize viewed windows to the correct size
781 , ((modm, xK_r ), refresh)
782
783 -- Move focus to the next window
784 , ((modm, xK_t ), windows W.focusDown)
785
786 -- Move focus to the previous window
787 , ((modm, xK_n ), windows W.focusUp )
788
789 -- Move focus to the master window
790 , ((modm, xK_m ), windows W.focusMaster )
791
792 -- Swap the focused window and the master window
793 , ((modm .|. shiftMask, xK_m ), windows W.swapMaster)
794
795 -- Swap the focused window with the next window
796 , ((modm .|. shiftMask, xK_t ), windows W.swapDown )
797
798 -- Swap the focused window with the previous window
799 , ((modm .|. shiftMask, xK_n ), windows W.swapUp )
800
801 -- Swap the focused window with the previous window
802 , ((modm .|. shiftMask .|. controlMask, xK_m), sendMessage SwapWindow)
803
804 , ((modm, xK_Right), sendMessage $ Go R)
805 , ((modm, xK_Left ), sendMessage $ Go L)
806 , ((modm, xK_Up ), sendMessage $ Go U)
807 , ((modm, xK_Down ), sendMessage $ Go D)
808 , ((modm .|. shiftMask , xK_Right), sendMessage $ Move R)
809 , ((modm .|. shiftMask , xK_Left ), sendMessage $ Move L)
810 , ((modm .|. shiftMask , xK_Up ), sendMessage $ Move U)
811 , ((modm .|. shiftMask , xK_Down ), sendMessage $ Move D)
812 -- , ((modm .|. controlMask, xK_Right), withFocused $ keysMoveWindow (10, 0))
813 -- , ((modm .|. controlMask, xK_Left ), withFocused $ keysMoveWindow (-10, 0))
814 -- , ((modm .|. controlMask, xK_Up ), withFocused $ keysMoveWindow (0, -10))
815 -- , ((modm .|. controlMask, xK_Down ), withFocused $ keysMoveWindow (0, 10))
816 -- Shrink the master area
817 , ((modm, xK_h ), sendMessage Shrink)
818
819 -- Expand the master area
820 , ((modm, xK_s ), sendMessage Expand)
821
822 -- Push window back into tiling
823 , ((modm .|. shiftMask, xK_space ), withFocused $ windows . W.sink)
824 , ((modm, xK_BackSpace), focusUrgent)
825 , ((modm .|. shiftMask, xK_BackSpace), clearUrgents)
826
827 -- Increment the number of windows in the master area
828 , ((modm , xK_comma ), sendMessage (IncMasterN 1))
829
830 -- Deincrement the number of windows in the master area
831 , ((modm , xK_period), sendMessage (IncMasterN (-1)))
832
833 , ((0, xF86XK_AudioRaiseVolume), safeSpawn "pulseaudio-ctl" ["up", "2"])
834 , ((0, xF86XK_AudioLowerVolume), safeSpawn "pulseaudio-ctl" ["down", "2"])
835 , ((0, xF86XK_AudioMute), safeSpawn "pulseaudio-ctl" ["mute"])
836 , ((0, xF86XK_AudioPause), mediaMpv $ MpvSetProperty "pause" False)
837 , ((0, {-xF86XK_AudioMicMute-} 269025202), safeSpawn "pulseaudio-ctl" ["mute-input"])
838 , ((0, xF86XK_AudioPlay), mediaMpvTogglePause)
839 , ((modm .|. mod1Mask, xK_space), mediaMpvTogglePause)
840
841 , ((0, xF86XK_MonBrightnessDown), backlight (subtract 5))
842 , ((0, xF86XK_MonBrightnessUp), backlight (+ 5))
843
844 , ((modm , xK_Escape), cycleKbLayout (hKbLayouts host))
845 , ((modm .|. controlMask, xK_Escape), safeSpawn "setxkbmap" $ fst (head $ hKbLayouts host) : maybeToList (snd . head $ hKbLayouts host))
846
847 -- Toggle the status bar gap
848 -- Use this binding with avoidStruts from Hooks.ManageDocks.
849 -- See also the statusBar function from Hooks.DynamicLog.
850 --
851 , ((modm , xK_b ), sendMessage ToggleStruts)
852
853 , ((modm .|. shiftMask, xK_p ), safeSpawn "playerctl" ["-a", "pause"])
854
855 -- Quit xmonad
856 , ((modm .|. shiftMask, xK_e ), io (exitWith ExitSuccess))
857
858 -- Restart xmonad
859 -- , ((modm .|. shiftMask .|. controlMask, xK_r ), void . xfork $ recompile False >>= flip when (safeSpawn "xmonad" ["--restart"]))
860 , ((modm .|. shiftMask, xK_r ), void . liftIO $ executeFile "xmonad" True [] Nothing)
861 , ((modm .|. shiftMask, xK_l ), void . xfork $ do
862 sessId <- getEnv "XDG_SESSION_ID"
863 safeSpawn "loginctl" ["lock-session", sessId]
864 )
865 , ((modm .|. shiftMask, xK_s ), safeSpawn "systemctl" ["suspend"])
866 , ((modm .|. shiftMask, xK_h ), safeSpawn "systemctl" ["hibernate"])
867 , ((modm .|. shiftMask, xK_b ), backlight $ cycleThrough [1, 3 % 4, 1 % 2, 1 % 4, 1 % 10, 1 % 100, 0]
868 )
869 , ((modm .|. shiftMask .|. controlMask, xK_b), backlight $ cycleThrough [0, 1 % 100, 1 % 10, 1 % 4, 1 % 2, 3 % 4, 1]
870 )
871 , ((modm, xK_v ), windows copyToAll) -- @@ Make focused window always visible
872 , ((modm .|. shiftMask, xK_v ), killAllOtherCopies) -- @@ Toggle window state back
873 , ((modm .|. shiftMask, xK_g ), windowPrompt xPConfig Goto wsWindows)
874 , ((modm .|. shiftMask .|. controlMask, xK_g ), windowPrompt xPConfig Bring allWindows)
875 ]
876 ++
877
878 --
879 -- mod-[1..9], Switch to workspace N
880 --
881 -- mod-[1..9], Switch to workspace N
882 -- mod-shift-[1..9], Move client to workspace N
883 --
884 [((m .|. modm, k), windows $ f i)
885 | (i, k) <- zip (XMonad.workspaces conf) $ numKeys
886 , (f, m) <- [(W.greedyView, 0), (W.shift, shiftMask)]
887 ]
888 ++
889 [((m .|. modm .|. controlMask, k), void . runMaybeT $
890 MaybeT (P.getScreen def i) >>= MaybeT . screenWorkspace >>= lift . windows . f
891 )
892 | (i, k) <- zip (hScreens host) [xK_g, xK_c, xK_r, xK_l]
893 , (f, m) <- [(W.view, 0), (W.shift, shiftMask)]
894 ]
895 where
896 modm = XMonad.modMask conf
897
898
diff --git a/accounts/gkleen@sif/xresources.nix b/accounts/gkleen@sif/xresources.nix
new file mode 100644
index 00000000..3bd9af2c
--- /dev/null
+++ b/accounts/gkleen@sif/xresources.nix
@@ -0,0 +1,46 @@
1{
2 "Xft.dpi" = 282;
3 "Xft.autohint" = false;
4 "Xft.lcdfilter" = "lcddefault";
5 "Xft.hintstyle" = "hintfull";
6 "Xft.hinting" = true;
7 "Xft.antialias" = true;
8 "Xft.rgba" = "rgb";
9
10 # special
11 "*.foreground" = "#d9d9d9";
12 "*.background" = "#000000";
13 "*.cursorColor" = "#d9d9d9";
14
15 # black
16 "*.color0" = "#000000";
17 "*.color8" = "#757a80";
18
19 # red
20 "*.color1" = "#bf4949";
21 "*.color9" = "#e66e6e";
22
23 # green
24 "*.color2" = "#9fb346";
25 "*.color10" = "#cbd676";
26
27 # yellow
28 "*.color3" = "#e69650";
29 "*.color11" = "#ffa74f";
30
31 # blue
32 "*.color4" = "#759fbf";
33 "*.color12" = "#98b8d9";
34
35 # magenta
36 "*.color5" = "#9b79a6";
37 "*.color13" = "#ceadd9";
38
39 # cyan
40 "*.color6" = "#79a69b";
41 "*.color14" = "#a3d9ce";
42
43 # white
44 "*.color7" = "#d9d9d9";
45 "*.color15" = "#ffffff";
46} \ No newline at end of file
diff --git a/accounts/gkleen@sif/zshrc b/accounts/gkleen@sif/zshrc
new file mode 100644
index 00000000..f095ee21
--- /dev/null
+++ b/accounts/gkleen@sif/zshrc
@@ -0,0 +1,403 @@
1filebin() {
2 basePath=/srv/www/files
3 ssh ymir find "${basePath}" -type f -print0 \
4 | while IFS= read -r -d $'\0' p; do
5 printf "https://f.141.li/%s\n" "${p#${basePath}/}"
6 done
7}
8
9genmail() {
10 local baseName=""
11 local target=""
12 if [[ ${#@} -ge 1 ]]; then
13 target=${1}
14 shift
15 fi
16
17 if [[ ${#@} -ge 1 ]]; then
18 baseName=$(pwgen ${@})
19 else
20 baseName=$(pwgen -v -A -0 16 1)
21 fi
22 baseName=$(tr -cd $'[:alnum:]!#$%&*+-/=?^_{|}~.' <<<${baseName})
23 address=${baseName}@141.li
24 insertAddr() {
25 echo "${baseName} gkleen" | ssh ymir tee -a /srv/mail/spm 1>/dev/null \
26 }
27
28 printf "%s\n" ${address}
29 read -q 'cont?Continue [y/N]? ' || return
30
31 insertAddr
32}
33
34s() {
35 dir=$(pwd)
36 [[ ${#@} -ge 1 ]] && dir=$1
37
38 shellFile=$(findNix ${@})
39 [[ ${#@} -ge 1 ]] && shift
40
41 typeset -a cmd
42 if [[ -d ${dir}/.nix-gc-roots ]]; then
43 cmd=(persistent-nix-shell ${shellFile} ${S_EXTRA_ARGS} ${@})
44 else
45 cmd=(nix-shell ${shellFile} ${S_EXTRA_ARGS} ${@})
46 fi
47
48 if [[ -n "${S_SYSTEMD}" ]]; then
49 systemd-run --user --slice=development.slice --collect -E PATH=${PATH} -p WorkingDirectory=${dir} -- ${cmd}
50 else
51 (
52 cd ${dir}
53
54 exec ${cmd}
55 )
56 fi
57}
58
59sz() {
60 typeset -a S_EXTRA_ARGS
61 S_EXTRA_ARGS=(--run "env __ETC_ZSHENV_SOURCED=1 zsh") s ${@}
62}
63st() {
64 typeset -a S_EXTRA_ARGS
65 S_EXTRA_ARGS=(--run "tmux new-session env __ETC_ZSHENV_SOURCED=1 zsh") s ${@}
66}
67stt() {
68 typeset -a S_EXTRA_ARGS
69 S_SYSTEMD=true S_EXTRA_ARGS=(--run "urxvt -e tmux -S .tmux.sock new-session env __ETC_ZSHENV_SOURCED=1 zsh") s ${@}
70}
71se() {
72 typeset -a S_EXTRA_ARGS
73 S_SYSTEMD=true S_EXTRA_ARGS=(--run "emacs") s ${@}
74}
75
76findNix() {
77 if [[ $#@ -eq 0 ]]; then
78 findNix $(pwd)
79 elif [[ -f "$1" ]]; then
80 print ${1:a}
81 elif [[ -d "$1" && -f "$1"/shell.nix ]]; then
82 print ${1:a}/shell.nix
83 elif [[ -d "$1" && -f "$1"/default.nix ]]; then
84 print ${1:a}/default.nix
85 elif [[ -d "$1" && "$1" != "/" ]]; then
86 findNix ${1:h}
87 else
88 printf "Traversed directories to ‘/’ and found no shell specification\n" >&2
89 return 1
90 fi
91}
92
93dir() {
94 curlArchive=false
95 templateArchive=""
96 repoUrl=""
97 nixShell=""
98 findNix=false
99 dir=""
100 forceShell=false
101 wormhole=false
102 gitWorktree=""
103 notmuchMsg=""
104 quickserve=false
105
106 while getopts ':t:a:s:Sd:ir:wqg:n:' arg; do
107 case $arg in
108 "t") ;;
109 "a")
110 if [[ ${OPTARG} =~ "://" ]]; then
111 templateArchive=${OPTARG}
112 curlArchive=true
113 else
114 templateArchive=${OPTARG:a}
115 fi
116 ;;
117 "s") nixShell=${OPTARG:a} ;;
118 "S") findNix=true ;;
119 "d") dir=${OPTARG} ;;
120 "i") forceShell=true ;;
121 "r") repoUrl=${OPTARG} ;;
122 "w") wormhole=true ;;
123 "g") gitWorktree=${OPTARG} ;;
124 "n") notmuchMsg=${OPTARG} ;;
125 "q") quickserve=true ;;
126 *) printf "Invalid option: %s\n" $arg >&2; exit 2 ;;
127 esac
128 done
129
130 shift $((OPTIND - 1))
131
132 if [[ -z ${dir} && ${#@} -ge 1 ]]; then
133 dir=${1}
134 shift
135 fi
136
137 [[ -n ${dir} ]] || return 2;
138
139 if [[ ! -e ${dir} ]]; then
140 if [[ -z "${gitWorktree}" ]]; then
141 mkdir -vp ${dir}
142 else
143 git -C ${gitWorktree} worktree add ${dir}
144 fi
145 else
146 gitWorktree=""
147 fi
148
149 (
150 cd ${dir}
151 export dir;
152
153 ${findNix} && { nixShell=$(findNix) || return $? }
154
155 [[ -n ${repoUrl} ]] && git clone -- ${repoUrl} .
156
157 if [[ -n ${templateArchive} ]]; then
158 (
159 archiveFile=""
160 cleanup() {
161 [[ -n "${archiveFile}" ]] && rm -fv ${archiveFile}
162 }
163 trap cleanup EXIT
164
165 if ${curlArchive}; then
166 archiveFile=$(mktemp -t "archive.XXXXXXXXXX.${templateArchive:t}")
167
168 curl -L -o ${archiveFile} ${templateArchive}
169
170 templateArchive=${archiveFile}
171 fi
172
173 case $(file --brief --mime-type ${templateArchive}) in
174 application/zip) unzip ${templateArchive} ;;
175 *) tar -xvaf ${templateArchive} ;;
176 esac
177 )
178 fi
179
180
181 if [[ -n ${notmuchMsg} ]]; then
182 getMimeTypes() {
183 nix-shell -p mailcap --run "find \${buildInputs} -path '*/etc/mime.types' | head -n 1 | xargs -- cat"
184 }
185
186 typeset -a messages
187 messages=(${(z)$(notmuch search --output=messages ${notmuchMsg})})
188
189 for message (${messages}); do
190 typeset -A notmuchAtts
191 notmuchAtts=()
192
193 while IFS= read -r -d $'\n' line; do
194 [[ ${line} =~ '(attachment|part)\{ ID: ([0-9]+)' ]] || continue
195 attId=${match[2]}
196
197 [[ ${line} =~ 'Content-type: multipart/' ]] && continue
198
199 fName="part_${attId}"
200 [[ ${line} =~ 'Filename: (([^,]|,[^ ])+)' ]] && fName=${match[1]}
201
202 if [[ ${#messages} -gt 1 ]]; then
203 fName="${message}/${fName}"
204 fi
205
206 fExt="${fName:e}"
207 [[ -n "${fExt}" ]] && fName="${fName:r}"
208
209 if [[ -z "${fExt}" && ${line} =~ 'Content-type: (([^,]|,[^ ])+)$' ]]; then
210 fExt=$(getMimeTypes | grep ${match[1]}$'\t' | head -n 1 | awk '{ print $2; }')
211 fi
212
213 mkdir -p ${fName:h}
214 if [[ -n "${fExt}" ]]; then
215 fName=$(mktemp -p . "${fName}.XXXXXX.${fExt}")
216 else
217 fName=$(mktemp -p . "${fName}.XXXXXX")
218 fi
219
220 notmuchAtts[${attId}]=${fName}
221 done <<(notmuch show --decrypt=false -- ${message} | tr -d $'\f')
222
223 for attId fName in ${(kv)notmuchAtts}; do
224 [[ -d ${fName:h} ]] || mkdir -p ${fName:h}
225 printf "#%d → ‘%s’\n" "${attId}" "${fName}" >&2
226
227 notmuch show --decrypt=false --part=${attId} -- ${message} | pv -W -D 2 -i 0.1 >${fName}
228 done
229 done
230 fi
231
232
233 ${wormhole} && wormhole receive
234
235 if ${quickserve}; then
236 quickserve --root . --upload . --show-hidden --tar gz
237 fi
238
239
240 if [[ ${#@} -eq 0 ]] || ${forceShell}; then
241 if [[ ${#@} -gt 0 ]]; then
242 if [[ -z ${nixShell} ]]; then
243 ${@}
244 else
245 nix-shell ${nixShell} --run "${@}"
246 fi
247 fi
248
249 cd $(pwd) # Needed for mounting to work
250
251 isSingleDir() {
252 typeset -a contents
253 contents=(*(N) .*(N))
254
255 if [[ ${#contents} -eq 1 && -d ${contents[1]} ]]; then
256 print ${contents[1]}
257 return 0
258 else
259 return 1
260 fi
261 }
262 while d=$(isSingleDir); do cd ${d}; done
263
264
265 if [[ -z ${nixShell} ]]; then
266 exec -- zsh
267 else
268 exec -- nix-shell ${nixShell} --run zsh
269 fi
270 else
271 if [[ -z ${nixShell} ]]; then
272 exec -- ${@}
273 else
274 exec -- nix-shell ${nixShell} --run "${@}"
275 fi
276 fi
277 )
278}
279
280tmpdir() {
281 cleanup()
282 {
283 cd /
284 unmount() {
285 printf "Unmounting %s\n" ${1} >&2
286 fusermount -u ${1} || umount ${1} || sudo umount ${1}
287 }
288
289 if mountpoint -q -- ${dir}; then
290 unmount ${dir} || return $?
291 else
292 while read -d $'\0' subDir; do
293 mountpoint -q -- ${subDir} || continue
294 unmount ${subDir} || return $?
295 done <<<$(find ${dir} -xdev -type d -print0 | sort -zr)
296 fi
297
298 rm -rfv --one-file-system -- ${dir}
299 }
300
301 local tmpdir=""
302
303 while getopts ':t:a:s:Sd:ir:wqg:n:' arg; do
304 case $arg in
305 "t") tmpdir="=${OPTARG}" ;;
306 "?"|":") printf "Invalid option: %s\n" $arg >&2; exit 2 ;;
307 esac
308 done
309
310 (
311 trap cleanup EXIT
312
313
314 local dir=$(mktemp -ud --tmpdir${tmpdir} ${0}.XXXXXXXXXX || return $?)
315
316 dir -d ${dir} ${@}
317 )
318}
319
320inhibit-sleep() {
321 if systemctl --user is-active prevent-suspend.service 1>/dev/null; then
322 echo "Allowing suspend"
323 systemctl --user stop prevent-suspend.service
324 else
325 echo "Inhibiting suspend"
326 systemctl --user start prevent-suspend.service
327 fi
328}
329
330qr() {
331 qrencode -l M -o - -t ANSIUTF8 $@
332}
333
334clock() {
335 tty-clock -sSbc -C 7 -d 0 -a 100000000
336}
337
338public-ip() {
339 curl -s -H 'Accept: application/json' $@ ifconfig.co | jq -r '.ip'
340}
341
342nix-ghci() {
343 pkgExpr=""
344 if [[ ${#@} -gt 0 ]]; then
345 pkgExpr="${1}"
346 shift
347 fi
348
349 nix-shell -p "with (import <nixpkgs> {}); pkgs.haskellPackages.ghcWithPackages (p: with p; [${pkgExpr}])" --run "ghci ${@}"
350}
351
352swap() {
353 f1=${1}
354 f2=${2}
355
356 if [[ -z "${f1}" || ! -e "${f1}" ]]; then
357 printf "‘%s’ does not exist\n" "${f1}" >&2
358 return 2
359 fi
360 if [[ -z "${f2}" || ! -e "${f2}" ]]; then
361 printf "‘%s’ does not exist\n" "${f2}" >&2
362 return 2
363 fi
364
365 tmpfile=$(mktemp --dry-run --tmpdir=${f1:h} .swap.XXXXXXXXXX)
366 mv -v ${f1} ${tmpfile}
367 mv -v ${f2} ${f1}
368 mv -v ${tmpfile} ${f2}
369}
370
371l() {
372 exa --binary --git --time-style=iso --long --all --header --group-directories-first --colour=always $@
373}
374
375ll() {
376 l $@ | less --mouse -FR
377}
378
379alias '..'='cd ..'
380alias -g L='| less'
381alias -g S='&> /dev/null'
382alias -g G='| grep'
383alias -g B='&> /dev/null &'
384alias -g BB='&> /dev/null &!'
385
386fancy-ctrl-z () {
387 emulate -LR zsh
388 if [[ $#BUFFER -eq 0 ]]; then
389 [[ -n $(jobs -s) ]] && bg
390 zle redisplay
391 else
392 zle push-input
393 fi
394}
395zle -N fancy-ctrl-z
396bindkey '^Z' fancy-ctrl-z
397
398export DEFAULT_USER=gkleen
399export EDITOR=emacsclient
400
401bindkey -e
402bindkey ';5C' emacs-forward-word
403bindkey ';5D' emacs-backward-word \ No newline at end of file
diff --git a/accounts/root@sif.nix b/accounts/root@sif.nix
new file mode 100644
index 00000000..979463ba
--- /dev/null
+++ b/accounts/root@sif.nix
@@ -0,0 +1,18 @@
1{ userName, ... }:
2{
3 home-manager.users.${userName} = {
4 programs.ssh.matchBlocks = {
5 "git.yggdrasil.li" = {
6 user = "gitolite";
7 identityFile = "~/.ssh/sysconf";
8 };
9 "borg.munin" = {
10 hostname = "u120515.your-storagebox.de";
11 user = "u120515";
12 identityFile = "~/.ssh/borg.munin";
13 identitiesOnly = true;
14 port = 23;
15 };
16 };
17 };
18}