summaryrefslogtreecommitdiff
path: root/accounts/gkleen@sif
diff options
context:
space:
mode:
Diffstat (limited to 'accounts/gkleen@sif')
-rw-r--r--accounts/gkleen@sif/alacritty.nix43
-rw-r--r--accounts/gkleen@sif/autorandr-profiles/bstr.nix21
-rw-r--r--accounts/gkleen@sif/autorandr-profiles/def.nix13
-rw-r--r--accounts/gkleen@sif/backup-patterns26
-rw-r--r--accounts/gkleen@sif/default.nix236
-rw-r--r--accounts/gkleen@sif/dunst-settings.nix67
-rw-r--r--accounts/gkleen@sif/emacs.el178
-rw-r--r--accounts/gkleen@sif/firefox-chrome.css25
-rw-r--r--accounts/gkleen@sif/firefox-content.css12
-rwxr-xr-xaccounts/gkleen@sif/scripts/mute.zsh18
-rw-r--r--accounts/gkleen@sif/ssh-hosts.nix237
-rw-r--r--accounts/gkleen@sif/store.kdbx.lftp6
-rw-r--r--accounts/gkleen@sif/systemd.nix80
-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.hs246
-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.hs895
-rw-r--r--accounts/gkleen@sif/xresources.nix46
-rw-r--r--accounts/gkleen@sif/zshrc410
36 files changed, 3166 insertions, 0 deletions
diff --git a/accounts/gkleen@sif/alacritty.nix b/accounts/gkleen@sif/alacritty.nix
new file mode 100644
index 00000000..3d69d292
--- /dev/null
+++ b/accounts/gkleen@sif/alacritty.nix
@@ -0,0 +1,43 @@
1{
2 font.size = 5.5;
3
4 window.dynamic_padding = true;
5
6 colors = {
7 primary.foreground = "#d9d9d9";
8 primary.background = "#000000";
9 cursor.text = "#000000";
10 cursor.cursor = "#d9d9d9";
11
12 normal = {
13 black = "#000000";
14 red = "#bf4949";
15 green = "#9fb346";
16 yellow = "#e69650";
17 blue = "#759fbf";
18 magenta = "#9b79a6";
19 cyan = "#79a69b";
20 white = "#d9d9d9";
21 };
22
23 bright = {
24 black = "#757a80";
25 red = "#e66e6e";
26 green = "#cbd676";
27 yellow = "#ffa74f";
28 blue = "#98b8d9";
29 magenta = "#ceadd9";
30 cyan = "#a3d9ce";
31 white = "#ffffff";
32 };
33 };
34
35 scrolling.history = 0;
36
37 bell = {
38 duration = 50;
39 color = "#000000";
40 };
41
42 hints.alphabet = "uhetonas";
43}
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/def.nix b/accounts/gkleen@sif/autorandr-profiles/def.nix
new file mode 100644
index 00000000..304b4afe
--- /dev/null
+++ b/accounts/gkleen@sif/autorandr-profiles/def.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..4436887b
--- /dev/null
+++ b/accounts/gkleen@sif/backup-patterns
@@ -0,0 +1,26 @@
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:.config/Zulip
17- pp:.config/discord
18- pp:.zplug/log
19- pp:.zplug/cache
20- pp:.compose-cache
21- pp:.undo-tree
22- pp:.saves
23- pp:.mozilla
24- pp:Downloads/tmp
25- pp:secret
26- 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..a318a8ee
--- /dev/null
+++ b/accounts/gkleen@sif/default.nix
@@ -0,0 +1,236 @@
1{ flake, userName, pkgs, customUtils, lib, config, ... }@inputs:
2let
3 cfg = config.home-manager.users.${userName};
4 xmonad = import ./xmonad pkgs.haskellPackages;
5 emacsclientDesktopItem = pkgs.makeDesktopItem {
6 name = "emacsclient";
7 genericName = "Text Editor";
8 desktopName = "emacsclient";
9 icon = "emacs";
10 mimeType = "text/english;text/plain;text/x-makefile;text/x-c++hdr;text/x-c++src;text/x-chdr;text/x-csrc;text/x-java;text/x-moc;text/x-pascal;text/x-tcl;text/x-tex;application/x-shellscript;text/x-c;text/x-c++;";
11 exec = "${config.home-manager.users.${userName}.programs.emacs.package}/bin/emacsclient -a \"\" %F";
12 };
13 emacsScratch = pkgs.stdenv.mkDerivation rec {
14 pname = "scratch";
15 version = "0077334cc299aa7885f804d88f52cdb1b35caf71";
16
17 src = pkgs.fetchFromGitHub {
18 owner = "ffevotte";
19 repo = "scratch.el";
20 rev = version;
21 sha256 = "sha256-FUkKJ+1COGzgllzzv51yUIjMZI6slOFVExdwWl2ZEBA=";
22 };
23
24 phases = [ "installPhase" ];
25
26 installPhase = ''
27 mkdir -p $out/share/emacs/site-lisp
28 cp $src/scratch.el $out/share/emacs/site-lisp/default.el
29 '';
30 };
31 muteScript = pkgs.stdenv.mkDerivation {
32 name = "mute";
33 src = ./scripts/mute.zsh;
34
35 buildInputs = with pkgs; [ makeWrapper ];
36
37 phases = [ "installPhase" ];
38
39 installPhase = ''
40 mkdir -p $out/bin
41 install -m 0755 $src $out/bin/mute
42 wrapProgram $out/bin/mute \
43 --prefix PATH : ${pkgs.zsh}/bin \
44 --prefix PATH : ${pkgs.findutils}/bin \
45 --prefix PATH : ${pkgs.util-linux}/bin \
46 --prefix PATH : ${pkgs.coreutils}/bin \
47 --prefix PATH : ${pkgs.pulseaudio}/bin
48 '';
49 };
50in {
51 imports = with flake.nixosModules.userProfiles.${userName}; [
52 mpv
53 ];
54
55 home-manager.users.${userName} = {
56 programs = {
57 ssh = {
58 matchBlocks = import ./ssh-hosts.nix; # customUtils.nixImport { dir = ./ssh-hosts; };
59 extraConfig = ''
60 Match host uniworx3.ifi.lmu.de,uniworx4.ifi.lmu.de,uniworx5.ifi.lmu.de,uni2workgw.ifi.lmu.de,blackbeard.tcs.ifi.lmu.de,gitlab2.rz.ifi.lmu.de,oregon.tcs.ifi.lmu.de !exec "nc -z -w 1 %h %p &>/dev/null"
61 ProxyJump remote.cip.ifi.lmu.de
62
63 Host *
64 '';
65 };
66
67 emacs = {
68 enable = true;
69 extraPackages = epkgs: with epkgs; [
70 evil evil-dvorak undo-tree magit haskell-mode
71 nix-mode yaml-mode json-mode shakespeare-mode
72 smart-mode-line highlight-parentheses highlight-symbol
73 notmuch ag sass-mode lua-mode fira-code-mode use-package
74 use-package-ensure-system-package git-gutter emacsScratch
75 ];
76 };
77 firefox = {
78 enable = true;
79 profiles.default = {
80 settings = {
81 "layout.css.devPixelsPerPx" = "1.75";
82 "browser.tabs.drawInTitlebar" = false;
83 "toolkit.legacyUserProfileCustomizations.stylesheets" = true;
84 "dom.security.https_only_mode" = true;
85 };
86 };
87 };
88
89 alacritty = {
90 enable = true;
91 settings = import ./alacritty.nix;
92 };
93
94 zathura = {
95 enable = true;
96 package = pkgs.zathura.override { useMupdf = false; };
97 };
98
99 mpv.config = {
100 demuxer-max-bytes = 1073741824;
101 demuxer-max-back-bytes = 268435456;
102 };
103
104 autorandr = {
105 enable = true;
106 hooks.postswitch = {
107 # "restart-compton" = "${pkgs.systemd}/bin/systemctl --user try-restart picom";
108 "restart-trays" = ''
109 ${pkgs.coreutils}/bin/sleep 5
110 ${pkgs.systemd}/bin/systemctl --user try-restart trayer xmobar
111 '';
112 };
113 profiles = customUtils.nixImport { dir = ./autorandr-profiles; };
114 };
115
116 zsh.initExtra = "source ${./zshrc}";
117 zsh.dirHashes = {
118 u2w = "$HOME/projects/uni2work";
119 docs = "$HOME/documents";
120 dl = "$HOME/Downloads";
121 flk = "$HOME/config/nixos-flakes";
122 fsk-timi = "$HOME/projects/21s/fsk-timi";
123 };
124
125 obs-studio = {
126 enable = true;
127 plugins = with pkgs; [obs-v4l2sink];
128 };
129 };
130
131 services = {
132 dunst = {
133 settings = import ./dunst-settings.nix inputs;
134 iconTheme = cfg.gtk.iconTheme;
135 enable = true;
136 };
137 emacs.enable = true;
138 gpg-agent = {
139 enable = true;
140 enableSshSupport = true;
141 extraConfig = ''
142 pinentry-program ${pkgs.pinentry-gtk2}/bin/pinentry
143 grab
144 '';
145 };
146 pasystray.enable = true;
147 udiskie = {
148 enable = true;
149 automount = false;
150 };
151 unclutter = {
152 enable = true;
153 timeout = 5;
154 };
155 network-manager-applet.enable = true;
156 blueman-applet.enable = true;
157
158 sxhkd = {
159 enable = true;
160 keybindings = {
161 "button8" = "${muteScript}/bin/mute unmute";
162 "@button8" = "${muteScript}/bin/mute mute";
163 "button9" = "${pkgs.pulseaudio}/bin/pacmd set-sink-mute @DEFAULT_SINK@ 1";
164 "@button9" = "${pkgs.pulseaudio}/bin/pacmd set-sink-mute @DEFAULT_SINK@ 0";
165 };
166 };
167 };
168
169 gtk = {
170 enable = true;
171 font.name = "DejaVu Sans 6";
172 theme = {
173 package = pkgs.equilux-theme;
174 name = "Equilux-compact";
175 };
176 iconTheme = {
177 package = pkgs.paper-icon-theme;
178 name = "Paper";
179 };
180 };
181
182 xsession = {
183 enable = true;
184
185 windowManager.command = "${xmonad}/bin/xmonad";
186
187 initExtra = let
188 lockScript = pkgs.writeScript "lock" ''
189 #!${pkgs.stdenv.shell}
190 ${pkgs.playerctl}/bin/playerctl -a pause
191 exec ${pkgs.xsecurelock}/bin/xsecurelock
192 '';
193 in ''
194 ${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} &
195 ${pkgs.xorg.xinput}/bin/xinput disable 'Synaptics TM3512-010'
196 ${pkgs.xorg.xset}/bin/xset s 590 10
197 '';
198 };
199
200 xresources.properties = import ./xresources.nix;
201
202 home = {
203 packages = with pkgs; [
204 fira-code powerline-fonts nerdfonts pavucontrol keepassxc
205 youtube-dl sxiv xclip mumble pulseaudio-ctl libnotify synergy
206 xorg.xbacklight screen-message pidgin-with-plugins
207 google-play-music-desktop-player qt5ct playerctl evince
208 thunderbird zulip zoom-us steam steam-run wireshark skype
209 virt-manager rclone cached-nix-shell xournal discord xmonad
210 worktime fira-code-symbols emacsclientDesktopItem libreoffice
211 xournalpp
212 ];
213
214 file = {
215 ".emacs".source = ./emacs.el;
216 ".backup-munin".source = ./backup-patterns;
217 ".mozilla/firefox/default/chrome/userChrome.css".source = ./firefox-chrome.css;
218 ".mozilla/firefox/default/chrome/userContent.css".source = ./firefox-content.css;
219 };
220
221 sessionVariables = {
222 GDK_SCALE = 96.0 / 282.0;
223 QT_AUTO_SCREEN_SCALE_FACTOR = 1;
224 QT_QPA_PLATFORMTHEME = "qt5ct";
225 };
226
227 extraProfileCommands = ''
228 export 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:+:''${XDG_DATA_DIRS}}"
229 '';
230 };
231
232 fonts.fontconfig.enable = true;
233
234 systemd.user = import ./systemd.nix inputs;
235 };
236}
diff --git a/accounts/gkleen@sif/dunst-settings.nix b/accounts/gkleen@sif/dunst-settings.nix
new file mode 100644
index 00000000..8abdfc5a
--- /dev/null
+++ b/accounts/gkleen@sif/dunst-settings.nix
@@ -0,0 +1,67 @@
1{ pkgs, ... }:
2{
3 global = {
4 font = "Monospace 6";
5 markup = "full";
6 format = "<i>%s</i> %p\\n%b";
7 alignment = "left";
8 geometry = "1216x10-32+64";
9 shrink = true;
10 monitor = 0;
11 follow = "none";
12 padding = 6;
13 horizontal_padding = 6;
14 separator_height = 1;
15 separator_color = "frame";
16 idle_threshold = 0;
17
18 transparency = 10;
19
20 frame_width = 1;
21 frame_color = "#999999";
22
23 word_wrap = true;
24 show_age_threshold = 15;
25 show_indicators = false;
26 icon_position = "right";
27 sort = false;
28 sticky_history = false;
29
30 dmenu = "${pkgs.dmenu}/bin/dmenu";
31 };
32 shortcuts = {
33 close = "ctrl+space";
34 close_all = "ctrl+shift+space";
35 history = "ctrl+comma";
36 context = "ctrl+period";
37 };
38 urgency_low = {
39 background = "#000000";
40 foreground = "#999999";
41 timeout = 5;
42 };
43 urgency_normal = {
44 background = "#000000";
45 foreground = "#ffffff";
46 timeout = 15;
47 };
48 urgency_critical = {
49 background = "#900000";
50 foreground = "#ffffff";
51 timeout = 0;
52 };
53 pulseaudio-ctl = {
54 summary = "Volume *";
55 body = "Current is *";
56 set_stack_tag = "volume";
57 history_ignore = true;
58 };
59 mail = {
60 appname = "notmuch";
61 timeout = 0;
62 };
63 zulip = {
64 appname = "Zulip";
65 timeout = 0;
66 };
67}
diff --git a/accounts/gkleen@sif/emacs.el b/accounts/gkleen@sif/emacs.el
new file mode 100644
index 00000000..b22c00f5
--- /dev/null
+++ b/accounts/gkleen@sif/emacs.el
@@ -0,0 +1,178 @@
1(menu-bar-mode -1)
2(scroll-bar-mode -1)
3(tool-bar-mode -1)
4
5(setq inhibit-startup-message t)
6(defalias 'yes-or-no-p 'y-or-n-p)
7
8(set-face-attribute 'default nil :font "FiraCode Nerd Font Mono" :height 49)
9
10(require 'package)
11(setq package-archives nil)
12(package-initialize)
13(require 'use-package)
14(use-package use-package-ensure-system-package :ensure t)
15
16(require 'evil)
17(evil-mode 1)
18
19(global-subword-mode)
20(global-undo-tree-mode)
21(global-fira-code-mode)
22
23(evil-set-undo-system 'undo-tree)
24
25(global-set-key (kbd "RET") 'newline-and-indent)
26(global-set-key (kbd "M-g") 'magit-status)
27(global-set-key (kbd "M-?") 'vc-git-grep)
28
29(require 'git-gutter)
30(global-git-gutter-mode t)
31(custom-set-variables '(git-gutter:update-interval 2))
32(custom-set-variables '(git-gutter:hide-gutter t))
33
34;; (require 'scratch)
35(global-set-key (kbd "C-x B") 'scratch-create)
36(setq initial-major-mode 'scratch-mode)
37(setq initial-scratch-message "")
38
39(global-set-key (kbd "C-x K") 'kill-current-buffer)
40
41(setq backup-directory-alist `(("." . "~/.saves")))
42(setq undo-tree-history-directory-alist `(("." . "~/.undo")))
43(setq delete-old-versions t
44 kept-new-versions 6
45 kept-old-versions 2
46 version-control t)
47
48(setq undo-tree-visualizer-timestamps t
49 undo-tree-visualizer-diff t
50 ;; 10X bump of the undo limits to avoid issues with premature
51 ;; Emacs GC which truncages the undo history very aggresively
52 undo-limit 800000
53 undo-strong-limit 12000000
54 undo-outer-limit 120000000)
55
56(add-hook 'haskell-mode-hook 'haskell-indentation-mode)
57(add-hook 'haskell-mode-hook 'subword-mode)
58(add-hook 'haskell-mode-hook 'highlight-symbol-mode)
59(add-hook 'haskell-mode-hook 'highlight-paretheses-mode)
60
61(add-hook 'js-mode-hook 'highlight-symbol-mode)
62(add-hook 'js-mode-hook 'highlight-parentheses-mode)
63(defun my-js-mode-hook ()
64 "Custom `js-mode' behaviours."
65 (setq js-indent-level 2)
66 )
67(add-hook 'js-mode-hook 'my-js-mode-hook)
68
69(setq undo-tree-auto-save-history t)
70
71(defvar expand-file-name-custom-tilde-alist '(("u2w-dev1" . "/ssh:uni2work-dev1:/home/gkleen/projects/uni2work")))
72(defun my/add-to-tilde-alist (hash)
73 (let* ((tilde:dir (split-string hash "="))
74 (tilde (car tilde:dir))
75 (dir (cadr tilde:dir)))
76 (push (cons tilde dir) expand-file-name-custom-tilde-alist)))
77(mapc #'my/add-to-tilde-alist
78 (split-string (with-output-to-string
79 (call-process "zsh" nil standard-output nil "-ic" "hash -d"))
80 "\n" t))
81
82(defadvice expand-file-name (before expand-file-name-custom-tilde
83 (name &optional default-directory)
84 activate compile)
85 "User-defined expansions for ~NAME in file names."
86 (save-match-data
87 (when (string-match "\\`\\(\\(.*/\\)?~\\([^:/]+\\)\\)/" name)
88 (let ((replacement (assoc (match-string 3 name) expand-file-name-custom-tilde-alist)))
89 (when replacement
90 (setq name (replace-match (cdr replacement) t t name 1)))))))
91
92(setq notmuch-address-internal-completion '(received nil))
93(setq notmuch-always-prompt-for-sender t)
94(setq notmuch-command "notmuch-ssh")
95(setq notmuch-crypto-process-mime t)
96(setq notmuch-draft-tags '("+draft" "-inbox"))
97(setq notmuch-fcc-dirs nil)
98(setq notmuch-hello-sections '(notmuch-hello-insert-header notmuch-hello-insert-saved-searches))
99(setq notmuch-hello-thousands-separator " ")
100(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"))
101(setq notmuch-message-headers '("Subject" "To" "Cc" "Date"))
102(setq notmuch-message-replied-tags '("+replied" "-unread" "-inbox"))
103(setq notmuch-saved-searches
104 (quote
105 ((:name "inbox" :query "tag:inbox" :key "i")
106 (:name "unread" :query "tag:unread AND tag:inbox" :key "u")
107 (:name "drafts" :query "tag:draft" :key "d")
108 (:name "all mail" :query "date:month.." :key "a" :count-query "*")
109 (:name "sent" :query "is:sent" :key "s" :count-query "is:sent")
110 )))
111(setq notmuch-search-oldest-first nil)
112(setq notmuch-show-all-tags-list t)
113(setq notmuch-show-logo nil)
114
115(setq send-mail-function 'sendmail-send-it)
116(setq mail-envelope-from 'header)
117(setq mail-specify-envelope-from 't)
118(setq mail-default-headers nil)
119(setq message-default-headers "")
120(setq message-default-mail-headers "")
121(setq message-sendmail-envelope-from 'header)
122
123(setq highlight-symbol-idle-delay 0)
124
125(setq indent-tabs-mode nil)
126
127(setq ido-enable-flex-matching t)
128(setq ido-everywhere t)
129(ido-mode 1)
130
131(setq tramp-default-method "ssh")
132(customize-set-variable 'tramp-use-ssh-controlmaster-options nil)
133
134(setq direnv-enabled-hosts '("uni2work-dev1"))
135
136(defun tramp-sh-handle-start-file-process@my-direnv (args)
137 "Enable Direnv for hosts in `direnv-enabled-hosts'."
138 (with-parsed-tramp-file-name (expand-file-name default-directory) nil
139 (if (member host direnv-enabled-hosts)
140 (pcase-let ((`(,name ,buffer ,program . ,args) args))
141 `(,name
142 ,buffer
143 "direnv"
144 "exec"
145 ,localname
146 ,program
147 ,@args))
148 args)))
149
150(with-eval-after-load "tramp-sh"
151 (advice-add 'tramp-sh-handle-start-file-process
152 :filter-args #'tramp-sh-handle-start-file-process@my-direnv))
153
154(setq mail-host-address "sif.midgard.yggdrasil")
155(setq user-full-name "Gregor Kleen")
156
157(defun tell-emacsclients-for-buffer-to-die ()
158 "Sends error exit command to every client for the current buffer."
159 (interactive)
160 (dolist (proc server-buffer-clients)
161 (server-send-string proc "-error die")))
162
163(defun kill-buffer-with-special-emacsclient-handling ()
164 "Wrapper around kill-buffer that ensures tell-emacsclients-for-buffer-to-die is on the hooks"
165 (interactive)
166 (add-hook 'kill-buffer-hook 'tell-emacsclients-for-buffer-to-die nil t)
167 (kill-buffer))
168
169;; (global-set-key (kbd "C-x k") 'kill-buffer)
170
171(defun install-emacsclient-wrapped-kill-buffer ()
172 "Installs wrapped kill-buffer with special emacsclient handling.
173Best not to install it unconditionally because the server is not
174necessarily running."
175 (interactive)
176 (global-set-key (kbd "C-x k") 'kill-buffer-with-special-emacsclient-handling))
177
178(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/scripts/mute.zsh b/accounts/gkleen@sif/scripts/mute.zsh
new file mode 100755
index 00000000..1b30ad67
--- /dev/null
+++ b/accounts/gkleen@sif/scripts/mute.zsh
@@ -0,0 +1,18 @@
1#!/usr/bin/env zsh
2
3lockFile=~/.mute.flock
4
5case $1 in
6 mute)
7 (
8 flock -n 9 || exit 1
9 sleep 0.2
10 pacmd set-source-mute @DEFAULT_SOURCE@ 1
11 ) 9<>${lockFile} &
12 ;;
13 unmute)
14 set -o pipefail
15 while fuser ${lockFile} 2>/dev/null | cut -d ':' -f 2- | xargs -r -- kill; do sleep 0.001; done
16 pacmd set-source-mute @DEFAULT_SOURCE@ 0
17 ;;
18esac
diff --git a/accounts/gkleen@sif/ssh-hosts.nix b/accounts/gkleen@sif/ssh-hosts.nix
new file mode 100644
index 00000000..1b9fb842
--- /dev/null
+++ b/accounts/gkleen@sif/ssh-hosts.nix
@@ -0,0 +1,237 @@
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 "surtr" =
31 { hostname = "surtr.yggdrasil.li";
32 identityFile = "~/.ssh/gkleen@sif.midgard.yggdrasil";
33 };
34 "odin" =
35 { hostname = "odin.asgard.yggdrasil";
36 identityFile = "~/.ssh/gkleen@sif.midgard.yggdrasil";
37 };
38 "init.odin" =
39 { hostname = "odin.asgard.yggdrasil";
40 user = "root";
41 identityFile = "~/.ssh/rsa.gkleen@hel.midgard.yggdrasil";
42 extraOptions = {
43 StrictHostKeyChecking = "off";
44 };
45 };
46 "heimdallr" =
47 { hostname = "heimdallr.asgard.yggdrasil";
48 user = "root";
49 identityFile = "~/.ssh/gkleen@sif.midgard.yggdrasil";
50 };
51 "gitlab2.rz.ifi.lmu.de" =
52 { user = "git";
53 identityFile = "~/.ssh/gkleen@gitlab2.rz.ifi.lmu.de";
54 };
55 "gitlab2.cip.ifi.lmu.de" =
56 { user = "git";
57 identityFile = "~/.ssh/gkleen@sif.midgard.yggdrasil";
58 };
59 "hel".hostname = "hel.midgard.yggdrasil";
60 "blackbeard" =
61 { hostname = "blackbeard.tcs.ifi.lmu.de";
62 user = "pi";
63 identityFile = "~/.ssh/blackbeard";
64 };
65 "github.com" =
66 { user = "git";
67 identityFile = "~/.ssh/gkleen@github.com";
68 };
69 "ullr.playat.ch" =
70 { hostname = "ullr.playat.ch";
71 user = "minecraft";
72 identityFile = "~/.ssh/minecraft@ullr.playat.ch";
73 };
74 "ullr" =
75 { hostname = "185.170.112.70";
76 identityFile = "~/.ssh/gkleen@sif.midgard.yggdrasil";
77 };
78 "testworx" =
79 { hostname = "testworx.tcs.ifi.lmu.de";
80 user = "root";
81 port = 30363;
82 identityFile = "~/.ssh/testworx";
83 };
84 "remote.cip.ifi.lmu.de" =
85 { user = "kleen";
86 identityFile = "~/.ssh/gkleen@sif.midgard.yggdrasil";
87 };
88 "uniworx3" =
89 { hostname = "uniworx3.ifi.lmu.de";
90 user = "root";
91 identityFile = "~/.ssh/uni2work";
92 };
93 "uniworx4" =
94 { hostname = "uniworx4.ifi.lmu.de";
95 user = "root";
96 identityFile = "~/.ssh/uni2work";
97 };
98 "jump.uniworx4" =
99 { hostname = "uniworx4.ifi.lmu.de";
100 user = "sshjump";
101 identityFile = "~/.ssh/sshjump.uni2work";
102 };
103 "uni2workgw" =
104 { hostname = "uni2workgw.ifi.lmu.de";
105 user = "root";
106 identityFile = "~/.ssh/uni2work";
107 };
108 "uniworxdb2" =
109 { hostname = "uniworxdb2";
110 proxyJump = "uniworx4";
111 user = "root";
112 identityFile = "~/.ssh/uni2work";
113 };
114 "uniworx5" =
115 { hostname = "uniworx5.ifi.lmu.de";
116 user = "root";
117 identityFile = "~/.ssh/uni2work";
118 };
119 "gate2" =
120 { hostname = "gate2.tcs.ifi.lmu.de";
121 user = "gkleen";
122 identityFile = "~/.ssh/tcs";
123 serverAliveInterval = 0;
124 };
125 "proxy.gate2" =
126 { hostname = "gate2.tcs.ifi.lmu.de";
127 user = "gkleen";
128 identityFile = "~/.ssh/proxy.gkleen@tcs.ifi.lmu.de";
129 dynamicForwards = [ { port = 8118; } ];
130 serverAliveInterval = 0;
131 extraOptions = {
132 ExitOnForwardFailure = "yes";
133 };
134 };
135 "jump.gate2" =
136 { hostname = "gate2.tcs.ifi.lmu.de";
137 user = "gkleen";
138 identityFile = "~/.ssh/proxy.gkleen@tcs.ifi.lmu.de";
139 serverAliveInterval = 0;
140 extraOptions = {
141 ExitOnForwardFailure = "yes";
142 };
143 };
144 "gate" =
145 { hostname = "gate.tcs.ifi.lmu.de";
146 user = "gkleen";
147 identityFile = "~/.ssh/tcs";
148 };
149 "proxy.gate" =
150 { hostname = "gate.tcs.ifi.lmu.de";
151 user = "gkleen";
152 identityFile = "~/.ssh/proxy.gkleen@tcs.ifi.lmu.de";
153 dynamicForwards = [ { port = 8118; } ];
154 extraOptions = {
155 ExitOnForwardFailure = "yes";
156 };
157 };
158 "jump.gate" =
159 { hostname = "gate.tcs.ifi.lmu.de";
160 user = "gkleen";
161 identityFile = "~/.ssh/proxy.gkleen@tcs.ifi.lmu.de";
162 extraOptions = {
163 ExitOnForwardFailure = "yes";
164 };
165 };
166 "oregon" =
167 { hostname = "oregon.tcs.ifi.lmu.de";
168 user = "root";
169 identityFile = "~/.ssh/tcs";
170 };
171 "proxy.oregon" =
172 { hostname = "oregon.tcs.ifi.lmu.de";
173 user = "root";
174 identityFile = "~/.ssh/tcs";
175 dynamicForwards = [ { port = 8113; } ];
176 extraOptions = {
177 ExitOnForwardFailure = "yes";
178 };
179 };
180 "witbank" =
181 { hostname = "witbank.tcs.ifi.lmu.de";
182 user = "uni2work";
183 identityFile = "~/.ssh/letz";
184 };
185 "git.odin" =
186 { hostname = "odin.asgard.yggdrasil";
187 user = "gitolite";
188 };
189 "notmuch.odin" =
190 { hostname = "odin.asgard.yggdrasil";
191 identityFile = "~/.ssh/notmuch.odin.asgard.yggdrasil";
192 };
193 "status.odin" =
194 { hostname = "odin.asgard.yggdrasil";
195 identityFile = "~/.ssh/status.odin.asgard.yggdrasil";
196 extraOptions.ControlPath = "~/.ssh/status-%r@%n:%p";
197 };
198 "moden" =
199 { hostname = "oristano.tcs.ifi.lmu.de";
200 user = "gkleen";
201 port = 30363;
202 identityFile = "~/.ssh/gkleen@oristano.tcs.ifi.lmu.de";
203 };
204 "ubuntu1804" =
205 { hostname = "192.168.122.30";
206 identityFile = "~/.ssh/gkleen@sif.midgard.yggdrasil";
207 forwardAgent = true;
208 };
209 "gitlab.haskell.org" =
210 { hostname = "gitlab.haskell.org";
211 identityFile = "~/.ssh/gkleen@gitlab.haskell.org";
212 };
213 "gitlab.lrz.de" =
214 { hostname = "gitlab.lrz.de";
215 user = "git";
216 identityFile = "~/.ssh/gkleen@gitlab.lrz.de";
217 };
218 "uni2work-dev1" =
219 { hostname = "uni2work-dev1.ifi.lmu.de";
220 user = "gkleen";
221 identityFile = "~/.ssh/uni2work";
222 proxyJump = "jump.uniworx4";
223 localForwards = [
224 { bind = { address = "localhost"; port = 3940; };
225 host = { address = "localhost"; port = 3940; };
226 }
227 { bind = { address = "localhost"; port = 9020; };
228 host = { address = "localhost"; port = 9020; };
229 }
230 ];
231 remoteForwards = [
232 { host = { address = "/run/user/1000/emacs/server"; };
233 bind = { address = "/home/gkleen/.ssh/emacs-server"; };
234 }
235 ];
236 };
237}
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..7faef31a
--- /dev/null
+++ b/accounts/gkleen@sif/systemd.nix
@@ -0,0 +1,80 @@
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 emacs = {
15 Unit = {
16 After = ["graphical-session-pre.target"];
17 };
18 };
19 trayer = {
20 Service = {
21 Type = "simple";
22 WorkingDirectory = "~";
23 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";
24 Restart = "always";
25 };
26 Install = {
27 WantedBy = ["graphical-session.target"];
28 };
29 };
30 xmobar = {
31 Service = {
32 Type = "simple";
33 WorkingDirectory = "~";
34 ExecStart = "${xmobar}/bin/xmobar";
35 Restart = "always";
36 Environment = "PATH=${pkgs.worktime}/bin:${pkgs.openssh}/bin";
37
38 };
39 Install = {
40 WantedBy = ["graphical-session.target"];
41 };
42 };
43 dunst = {
44 Service = {
45 Restart = "always";
46 };
47 Install = {
48 WantedBy = ["graphical-session.target"];
49 };
50 };
51 xiccd = {
52 Service = {
53 Type = "simple";
54 WorkingDirectory = "~";
55 ExecStart = "${pkgs.xiccd}/bin/xiccd";
56 Restart = "always";
57 };
58 };
59 };
60 timers = {
61 sync-keepass = {
62 Timer = {
63 OnActiveSec = "1m";
64 OnUnitActiveSec = "1m";
65 };
66
67 Install = {
68 WantedBy = ["default.target"];
69 };
70 };
71 };
72 targets = {
73 graphical-session = {
74 Unit = {
75 BindsTo = ["default.target"];
76 After = ["basic.target"];
77 };
78 };
79 };
80}
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..16beb322
--- /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.lib.overrideDerivation dummy override
28 #pkgs.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..852fb8e5
--- /dev/null
+++ b/accounts/gkleen@sif/xmobar/xmobar-yggdrasil.nix
@@ -0,0 +1,13 @@
1{ mkDerivation, base, hpack, lib, 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 = 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..74ce7347
--- /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 = "#808080"
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..729941aa
--- /dev/null
+++ b/accounts/gkleen@sif/xmonad/lib/XMonad/Prompt/MySsh.hs
@@ -0,0 +1,246 @@
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 Nothing c
84 | null $ cCommand c = c { cCommand = "tmux new-session" }
85 | otherwise = c { cCommand = "tmux new-session \"" ++ (cCommand c) ++ "\"" }
86inTmux (Just h) c
87 | null $ cCommand c = c { cCommand = "tmux new-session -As " <> h }
88 | otherwise = c { cCommand = "tmux new-session \"" ++ (cCommand c) ++ "\"" }
89withEnv :: [(String, String)] -> Conn -> Conn
90withEnv envs c = c { cCommand = "env" ++ (concat $ map (\(n, v) -> ' ' : (n ++ "=" ++ v)) envs) ++ " " ++ (cCommand c) }
91
92data Conn = Conn
93 { cUser :: Maybe String
94 , cHost :: String
95 , cPort :: Maybe Int
96 , cCommand :: String
97 } deriving (Eq, Show, Read)
98
99data Ssh = Ssh
100
101instance XPrompt Ssh where
102 showXPrompt Ssh = "SSH to: "
103 commandToComplete _ c = c
104 nextCompletion _ = getNextCompletion
105
106toConn :: String -> Maybe Conn
107toConn = toConn' . parse connParser "(unknown)"
108toConn' :: Either ParseError Conn -> Maybe Conn
109toConn' (Left _) = Nothing
110toConn' (Right a) = Just a
111
112connParser :: Parser Conn
113connParser = do
114 spaces
115 user' <- optionMaybe $ try $ do
116 str <- many1 $ satisfy (\c -> (not $ isSpace c) && (c /= '@'))
117 char '@'
118 return str
119 host' <- many1 $ satisfy (not . isSpace)
120 port' <- optionMaybe $ try $ do
121 space
122 string "-p"
123 spaces
124 int <- many1 digit
125 (space >> return ()) <|> eof
126 return $ (read int :: Int)
127 spaces
128 command' <- many anyChar
129 eof
130 return $ Conn
131 { cHost = host'
132 , cUser = user'
133 , cPort = port'
134 , cCommand = command'
135 }
136
137sshPrompt :: [Override] -> XPConfig -> X ()
138sshPrompt o c = do
139 sc <- io sshComplList
140 mkXPrompt Ssh c (mkComplFunFromList sc) $ ssh o
141
142ssh :: [Override] -> String -> X ()
143ssh overrides str = do
144 let cmd = applyOverrides overrides str
145 liftIO $ putStr "SSH Command: "
146 liftIO $ putStrLn cmd
147 runInTerm "" cmd
148
149applyOverrides :: [Override] -> String -> String
150applyOverrides [] str = "ssh " ++ str
151applyOverrides (o:os) str = case (applyOverride o str) of
152 Just str -> str
153 Nothing -> applyOverrides os str
154
155applyOverride :: Override -> String -> Maybe String
156applyOverride o str = let
157 conn = toConn str
158 in
159 if isNothing conn then Nothing else
160 case (fromJust conn) `matches` o of
161 True -> Just $ (oCommand o) (fromJust conn)
162 False -> Nothing
163
164matches :: Conn -> Override -> Bool
165a `matches` b = and
166 [ justBool (cUser a) (oUser b) (==)
167 , (cHost a) == (oHost b)
168 , justBool (cPort a) (oPort b) (==)
169 ]
170
171justBool :: Eq a => Maybe a -> Maybe a -> (a -> a -> Bool) -> Bool
172justBool Nothing _ _ = True
173justBool _ Nothing _ = True
174justBool (Just a) (Just b) match = a `match` b
175
176sshComplList :: IO [String]
177sshComplList = uniqSort `fmap` liftM2 (++) sshComplListLocal sshComplListGlobal
178
179sshComplListLocal :: IO [String]
180sshComplListLocal = do
181 h <- getEnv "HOME"
182 s1 <- sshComplListFile $ h ++ "/.ssh/known_hosts"
183 s2 <- sshComplListConf $ h ++ "/.ssh/config"
184 return $ s1 ++ s2
185
186sshComplListGlobal :: IO [String]
187sshComplListGlobal = do
188 env <- getEnv "SSH_KNOWN_HOSTS" `E.catch` econst "/nonexistent"
189 fs <- mapM fileExists [ env
190 , "/usr/local/etc/ssh/ssh_known_hosts"
191 , "/usr/local/etc/ssh_known_hosts"
192 , "/etc/ssh/ssh_known_hosts"
193 , "/etc/ssh_known_hosts"
194 ]
195 case catMaybes fs of
196 [] -> return []
197 (f:_) -> sshComplListFile' f
198
199sshComplListFile :: String -> IO [String]
200sshComplListFile kh = do
201 f <- doesFileExist kh
202 if f then sshComplListFile' kh
203 else return []
204
205sshComplListFile' :: String -> IO [String]
206sshComplListFile' kh = do
207 l <- readFile kh
208 return $ map (getWithPort . takeWhile (/= ',') . concat . take 1 . words)
209 $ filter nonComment
210 $ lines l
211
212sshComplListConf :: String -> IO [String]
213sshComplListConf kh = do
214 f <- doesFileExist kh
215 if f then sshComplListConf' kh
216 else return []
217
218sshComplListConf' :: String -> IO [String]
219sshComplListConf' kh = do
220 l <- readFile kh
221 return $ map (!!1)
222 $ filter isHost
223 $ map words
224 $ lines l
225 where
226 isHost ws = take 1 ws == ["Host"] && length ws > 1
227
228fileExists :: String -> IO (Maybe String)
229fileExists kh = do
230 f <- doesFileExist kh
231 if f then return $ Just kh
232 else return Nothing
233
234nonComment :: String -> Bool
235nonComment [] = False
236nonComment ('#':_) = False
237nonComment ('|':_) = False -- hashed, undecodeable
238nonComment _ = True
239
240getWithPort :: String -> String
241getWithPort ('[':str) = host ++ " -p " ++ port
242 where (host,p) = break (==']') str
243 port = case p of
244 ']':':':x -> x
245 _ -> "22"
246getWithPort 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..d3d72310
--- /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, lib
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 = 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..d21debdf
--- /dev/null
+++ b/accounts/gkleen@sif/xmonad/xmonad.hs
@@ -0,0 +1,895 @@
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" $ stringProperty "WM_WINDOW_ROLE" =? "presentation"
176 , assign "read" $ stringProperty "WM_WINDOW_ROLE" =? "presenter"
177 , assign "mpv" $ className =? "factorio"
178 , assign "web" $ className =? "chromium-browser"
179 , assign "web" $ className =? "Google-chrome"
180 , assign "work" $ (appName =? "Devtools" <&&> className =? "Firefox")
181 , assign "work" $ className =? "Postman"
182 , assign "web" $ className =? "Firefox"
183 , assign "comm" $ (className =? "Emacs" <&&> title =? "Mail")
184 , assign "comm" $ className =? "Zulip"
185 , assign "comm" $ className =? "Discord"
186 , assign "media" $ (className =? "Alacritty" <&&> resource =? "media")
187 , assign "monitor" $ className =? "Grafana"
188 , Just $ (className =? "Alacritty" <&&> resource =? "htop") -?> centerFloat
189 , Just $ (className =? "Scp-dbus-service.py") -?> centerFloat
190 , Just $ (className =? "Alacritty" <&&> resource =? "log") -?> centerFloat
191 , assign "work" $ className =? "Alacritty"
192 , assign' ["work", "uni"] $ (className =? "Emacs" <&&> appName /=? "Edit_with_Emacs_FRAME")
193 , assign' ["work", "uni"] $ className =? "jetbrains-idea-ce"
194 , assign "read" $ className =? "llpp"
195 , assign "read" $ className =? "Evince"
196 , assign "read" $ className =? "Zathura"
197 , assign "read" $ className =? "MuPDF"
198 , assign "read" $ className =? "Xournal"
199 , assign "read" $ appName =? "com-trollworks-gcs-app-GCS"
200 , assign "read" $ appName =? "Tux.py"
201 , assign "read" $ className =? "Gnucash"
202 , assign "comm" $ className =? "Skype"
203 , assign "comm" $ className =? "Daily"
204 , assign "comm" $ className =? "Pidgin"
205 , assign "comm" $ className =? "Slack"
206 , Just $ (resource =? "xvkbd") -?> doRectFloat $ RationalRect (1 % 8) (3 % 8) (6 % 8) (4 % 8)
207 , Just $ (stringProperty "_NET_WM_WINDOW_TYPE" =? "_NET_WM_WINDOW_TYPE_DIALOG") -?> doFloat
208 , Just $ (className =? "Dunst") -?> doFloat
209 , Just $ (className =? "Xmessage") -?> doCenterFloat
210 , Just $ (className =? "Nm-openconnect-auth-dialog") -?> centerFloat
211 , Just $ (className =? "Pinentry") -?> doCenterFloat
212 , Just $ (className =? "pinentry") -?> doCenterFloat
213 , Just $ (appName =? "Edit_with_Emacs_FRAME") -?> centerFloat
214 , Just $ (stringProperty "WM_WINDOW_ROLE" =? "GtkFileChooseDialog") -?> centerFloatSmall
215 , Just $ (className =? "Nvidia-settings") -?> doCenterFloat
216 , Just $ fmap ("Minetest" `isInfixOf`) title -?> doIgnore
217 , Just $ fmap ("Automachef" `isInfixOf`) title -?> doIgnore
218 , assign "call" $ className =? "zoom"
219 ])
220 , hWsp = hWsp
221 , hCoWsp = hCoWsp
222 , hKeysMod = \conf -> Map.union $ (Map.fromList $ join $ map (spawnBindings conf) [ (xK_e, ["emacsclient -c"])
223 , (xK_d, [fromString browser, fromString $ browser ++ " $(xclip -o)", fromString $ "notmuch-links"])
224 , (xK_c, [ inputPrompt xPConfig "dc" ?+ dc ])
225 , (xK_g, ["pidgin"])
226 , (xK_s, ["skype"])
227 -- , (xK_p, [mkPassPrompt "Type password" pwType xPConfig, mkPassPrompt "Show password" pwShow xPConfig, mkPassPrompt "Copy password" pwClip xPConfig])
228 , (xK_w, ["sudo rewacom"])
229 , (xK_y, [ "tmux new-window -dt media /var/media/link.hs $(xclip -o)"
230 , "tmux new-window -dt media /var/media/download.hs $(xclip -o)"
231 , "alacritty --class media -e tmuxp load /var/media"
232 ])
233 , (xK_l, [ "tmux new-window -dt media mpv $(xclip -o)"
234 , "tmux new-window -dt media streamlink --retry-open 10 $(xclip -o)"
235 ])
236 , (xK_m, [ "emacsclient -c -F \"'(title . \\\"Mail\\\")\" -e '(notmuch)'"
237 , "emacsclient -c -F \"'(title . \\\"Mail\\\")\" -e '(notmuch-mua-new-mail)'"
238 , "emacsclient -c -F \"'(title . \\\"Mail\\\")\" -e \"(browse-url-mail \"$(xclip -o)\")\""
239 ])
240 , (xK_Return, ["keynav start,windowzoom", "keynav start"])
241 , (xK_t, [inputPrompt xPConfig "fuzzytime timer" ?+ fuzzytime, fuzzytime "unset", work_fuzzytime])
242 , (xK_a, [inputPrompt xPConfig "adjmix" ?+ adjmix])
243 , (xK_s, [ inputPromptWithCompl xPConfig "start synergy" synergyCompl ?+ synergyStart
244 , inputPromptWithCompl xPConfig "stop synergy" synergyCompl ?+ synergyStop
245 ])
246 , (xK_h, [ "alacritty --class htop -e htop"
247 , "alacritty --class log -e journalctl -xef"
248 ])
249 , (xK_x, [ "autorandr -c"
250 , "autorandr -fl def"
251 ])
252 , (xK_z, [ "zulip -- --force-device-scale-factor=2"
253 ])
254 ])
255 `Map.union`
256 ( Map.fromList [ ((XMonad.modMask conf .|. controlMask, xK_Return), namedScratchpadAction scratchpads "term")
257 , ((XMonad.modMask conf .|. controlMask, xK_a), namedScratchpadAction scratchpads "pavucontrol")
258 , ((XMonad.modMask conf .|. controlMask, xK_w), namedScratchpadAction scratchpads "alarms")
259 , ((XMonad.modMask conf .|. controlMask, xK_b), namedScratchpadAction scratchpads "blueman")
260 , ((XMonad.modMask conf .|. controlMask, xK_p), namedScratchpadAction scratchpads "keepassxc")
261 , ((XMonad.modMask conf .|. controlMask, xK_t), namedScratchpadAction scratchpads "toggl")
262 , ((XMonad.modMask conf .|. controlMask, xK_e), namedScratchpadAction scratchpads "emacs")
263 , ((XMonad.modMask conf .|. controlMask, xK_m), namedScratchpadAction scratchpads "calendar")
264 , ((XMonad.modMask conf .|. controlMask, xK_f), namedScratchpadAction scratchpads "music")
265 , ((XMonad.modMask conf .|. mod1Mask, xK_Up), rotate U)
266 , ((XMonad.modMask conf .|. mod1Mask, xK_Down), rotate D)
267 , ((XMonad.modMask conf .|. mod1Mask, xK_Left), rotate L)
268 , ((XMonad.modMask conf .|. mod1Mask, xK_Right), rotate R)
269 -- , ((XMonad.modMask conf .|. shiftMask, xK_a), startMute "hel")
270 ] )
271 , hKeyUpKeys = \conf -> Map.fromList [ -- ((XMonad.modMask conf .|. shiftMask, xK_a), stopMute "hel")
272 ]
273 , hScreens = hScreens defaultHost
274 , hCmds = return [ ("prev-workspace", prevWS)
275 , ("next-workspace", nextWS)
276 , ("prev-window", rotAllDown)
277 , ("next-window", rotAllUp)
278 , ("banish", banishScreen LowerRight)
279 , ("update-gpg-tty", safeSpawn "gpg-connect-agent" ["UPDATESTARTUPTTY", "/bye"])
280 , ("rescreen", rescreen)
281 , ("repanel", do
282 spawn "nm-applet"
283 spawn "blueman-applet"
284 spawn "pasystray"
285 spawn "kdeconnect-indicator"
286 spawn "dunst -print"
287 spawn "udiskie"
288 spawn "autocutsel -s PRIMARY"
289 spawn "autocutsel -s CLIPBOARD"
290 )
291 , ("pause", mediaMpv $ MpvSetProperty "pause" True)
292 , ("unpause", mediaMpv $ MpvSetProperty "pause" False)
293 , ("exit", io $ exitWith ExitSuccess)
294 ]
295 }
296 where
297 withGdkScale act = void . xfork $ setEnv "GDK_SCALE" "2" >> act
298 workspaceNames = Map.fromList [ (1, "comm")
299 , (2, "web")
300 , (3, "work")
301 , (4, "read")
302 , (5, "monitor")
303 , (6, "uni")
304 , (8, "call")
305 , (9, "media")
306 , (10, "mpv")
307 ]
308 scratchpads = [ NS "term" "alacritty --class scratchpad --title scratchpad -e tmux new-session -AD -s scratch" (resource =? "scratchpad") centerFloat
309 , NS "pavucontrol" "pavucontrol" (resource =? "pavucontrol") centerFloat
310 , NS "alarms" "alarm-clock-applet" (className =? "Alarm-clock-applet" <&&> title =? "Alarms") centerFloat
311 , NS "blueman" "blueman-manager" (className =? ".blueman-manager-wrapped") centerFloat
312 , NS "keepassxc" "keepassxc" (className =? "KeePassXC") centerFloat
313 , NS "toggl" "toggldesktop" (className =? "Toggl Desktop") centerFloat
314 , NS "calendar" "minetime -- --force-device-scale-factor=1.6" (className =? "MineTime") centerFloat
315 , NS "emacs" "emacsclient -c -F \"'(title . \\\"Scratchpad\\\")\"" (className =? "Emacs" <&&> title =? "Scratchpad") centerFloat
316 , NS "music" "google-play-music-desktop-player --force-device-scale-factor=1.6" (className =? "Google Play Music Desktop Player") centerFloat
317 ]
318 centerFloat = customFloating $ RationalRect (1 % 16) (1 % 16) (7 % 8) (7 % 8)
319 centerFloatSmall = customFloating $ RationalRect (1 % 4) (1 % 4) (1 % 2) (1 % 2)
320 hWsp = wspFromMap workspaceNames
321 hCoWsp = coWspFromMap workspaceNames
322 assign wsp test = (\wsp -> test -?> doShift wsp) <$> hCoWsp wsp
323 assign' :: [String] -> Query Bool -> Maybe MaybeManageHook
324 assign' wsps test = do
325 wsIds <- mapM hCoWsp wsps
326 return $ test -?> go wsIds
327 where
328 go :: [WorkspaceId] -> ManageHook
329 go wsps = do
330 visWsps <- liftX $ (\wset -> W.tag . W.workspace <$> W.current wset : W.visible wset) <$> gets windowset
331 case (filter (`elem` visWsps) wsps, wsps) of
332 (wsp : _, _) -> doShift wsp
333 (_, wsp : _) -> doShift wsp
334 ([], []) -> return mempty
335 rotate rot = do
336 safeSpawn "xrandr" ["--output", "eDP-1", "--rotate", xrandrDir]
337 mapM_ rotTouch touchscreens
338 where
339 xrandrDir = case rot of
340 U -> "normal"
341 L -> "left"
342 R -> "right"
343 D -> "inverted"
344 matrix = case rot of
345 U -> [ [ 1, 0, 0]
346 , [ 0, 1, 0]
347 , [ 0, 0, 1]
348 ]
349 L -> [ [ 0, -1, 1]
350 , [ 1, 0, 0]
351 , [ 0, 0, 1]
352 ]
353 R -> [ [ 0, 1, 0]
354 , [-1, 0, 1]
355 , [ 0, 0, 1]
356 ]
357 D -> [ [-1, 0, 1]
358 , [ 0, -1, 1]
359 , [ 0, 0, 1]
360 ]
361 touchscreens = [ "Wacom Co.,Ltd. Pen and multitouch sensor Finger touch"
362 , "Wacom Co.,Ltd. Pen and multitouch sensor Pen stylus"
363 , "Wacom Co.,Ltd. Pen and multitouch sensor Pen eraser"
364 ]
365 rotTouch screen = do
366 safeSpawn "xinput" $ ["set-prop", screen, "Coordinate Transformation Matrix"] ++ map (\n -> show n ++ ",") (concat matrix)
367 safeSpawn "xinput" ["map-to-output", screen, "eDP-1"]
368 withPw f label = io . void . forkProcess $ do
369 uninstallSignalHandlers
370 void $ createSession
371 (dropWhileEnd isSpace -> pw) <- readCreateProcess (proc "pass" ["show", label]) ""
372 void $ f pw
373 pwType :: String -> X ()
374 pwType = withPw $ readCreateProcess (proc "xdotool" ["type", "--clearmodifiers", "--file", "-"])
375 pwClip label = safeSpawn "pass" ["show", "--clip", label]
376 pwShow :: String -> X ()
377 pwShow = withPw $ \pw -> do
378 xmessage <- fromMaybe "xmessage" <$> liftIO (lookupEnv "XMONAD_XMESSAGE")
379 readCreateProcess (proc xmessage ["-file", "-"]) pw
380 fuzzytime str = safeSpawn "fuzzytime" $ "timer" : words str
381 work_fuzzytime = io . void . forkProcess $ do
382 readCreateProcess (proc "worktime" []) "" >>= safeSpawn "fuzzytime" . ("timer" : ) . pure
383 adjmix str = safeSpawn "adjmix" $ words str
384 dc expr = void . xfork $ do
385 result <- readProcess "dc" [] $ expr ++ "f"
386 let
387 (first : rest) = filter (not . null) $ lines result
388 notification = Notify.summary first <> Notify.body (unlines rest) <> Notify.timeout Infinite <> Notify.urgency Normal <> Notify.appName "dc"
389 void $ Notify.display notification
390 synergyCompl = mkComplFunFromList' ["mathw86"]
391 synergyStart host = safeSpawn "systemctl" ["--user", "start", "synergy-rtunnel@" ++ host ++ ".service"]
392 synergyStop host = safeSpawn "systemctl" ["--user", "stop", "synergy-rtunnel@" ++ host ++ ".service"]
393
394hostFromName _ = defaultHost
395
396-- muteRef :: IORef (Maybe (String, Notification))
397-- {-# NOINLINE muteRef #-}
398-- muteRef = unsafePerformIO $ newIORef Nothing
399
400-- startMute, stopMute :: String -> X ()
401-- startMute sink = liftIO $ do
402-- muted <- isJust <$> readIORef muteRef
403-- when (not muted) $ do
404-- let
405-- notification = Notify.summary "Muted" <> Notify.timeout Infinite <> Notify.urgency Normal
406-- level = "0.0dB"
407-- -- level <- runProcessWithInput "ssh" ["bragi", "cat", "/dev/shm/mix/" ++ sink ++ "/level"] ""
408-- -- callProcess "ssh" ["bragi", "adjmix", "-t", sink, "-o", "0"]
409-- hPutStrLn stderr "Mute"
410-- writeIORef muteRef . Just . (level, ) =<< Notify.display notification
411-- stopMute sink = liftIO $ do
412-- let
413-- unmute (Just (level, notification)) = do
414-- hPutStrLn stderr "Unmute"
415-- -- callProcess "ssh" ["bragi", "adjmix", "-t", sink, "-o", level]
416-- Notify.close notification
417-- unmute Nothing = return ()
418-- muted <- isJust <$> readIORef muteRef
419-- when muted . join . atomicModifyIORef muteRef $ (Nothing, ) . unmute
420
421wspFromMap workspaceNames = \i -> case Map.lookup i workspaceNames of
422 Just str -> show i ++ " " ++ str
423 Nothing -> show i
424
425coWspFromMap workspaceNames = \str -> case filter ((== str) . snd) $ Map.toList workspaceNames of
426 [] -> Nothing
427 [(i, _)] -> Just $ wspFromMap workspaceNames i
428 _ -> Nothing
429
430spawnModifiers = [0, controlMask, shiftMask .|. controlMask]
431spawnBindings :: XConfig layout -> (KeySym, [X ()]) -> [((KeyMask, KeySym), X ())]
432spawnBindings conf (k, cmds) = zipWith (\m cmd -> ((modm .|. mod1Mask .|. m, k), cmd)) spawnModifiers cmds
433 where
434 modm = XMonad.modMask conf
435
436manageScratchTerm = (resource =? "scratchpad" <||> resource =? "keysetup") -?> doRectFloat $ RationalRect (1 % 16) (1 % 16) (7 % 8) (7 % 8)
437
438tabbedLayout t = renamed [Replace "Tabbed"] $ reflectHoriz $ t CustomShrink $ tabbedTheme
439tabbedLayoutHoriz t = renamed [Replace "Tabbed Horiz"] $ reflectVert $ t CustomShrink $ tabbedTheme
440tabbedTheme = def
441 { activeColor = "black"
442 , inactiveColor = "black"
443 , urgentColor = "black"
444 , activeBorderColor = "grey"
445 , inactiveBorderColor = "#202020"
446 , urgentBorderColor = "#bb0000"
447 , activeTextColor = "grey"
448 , inactiveTextColor = "grey"
449 , urgentTextColor = "grey"
450 , decoHeight = 32
451 , fontName = "xft:Fira Mono for Powerline:style=Medium:pixelsize=22.5"
452 }
453
454main :: IO ()
455main = do
456 arguments <- either (const []) id <$> tryIOError getArgs
457 case arguments of
458 ["--command", s] -> do
459 d <- openDisplay ""
460 rw <- rootWindow d $ defaultScreen d
461 a <- internAtom d "XMONAD_COMMAND" False
462 m <- internAtom d s False
463 allocaXEvent $ \e -> do
464 setEventType e clientMessage
465 setClientMessageEvent e rw a 32 m currentTime
466 sendEvent d rw False structureNotifyMask e
467 sync d False
468 _ -> do
469 -- batteryMon <- xfork $ monitorBattery Nothing Nothing
470 hostname <- getHostName
471 let
472 host = hostFromName hostname
473 setEnv "HOST" hostname
474 let myConfig = withHostUrgency . ewmh $ docks def
475 { manageHook = hManageHook host
476 , terminal = "alacritty"
477 , layoutHook = smartBorders . avoidStruts $ windowNavigation layout'
478 , logHook = do
479 dynamicLogString xmobarPP' >>= writeProps
480 updatePointer (99 % 100, 98 % 100) (0, 0)
481 , modMask = mod4Mask
482 , keys = \conf -> hKeysMod host conf $ myKeys' conf host
483 , workspaces = take (length numKeys) $ map wsp [1..]
484 , startupHook = setDefaultCursor xC_left_ptr
485 , normalBorderColor = "#202020"
486 , focusedBorderColor = "grey"
487 , handleEventHook = fullscreenEventHook <+> (serverModeEventHookCmd' $ hCmds host) <+> keyUpEventHook
488 }
489 writeProps str = do
490 let encodeCChar = map $ fromIntegral . fromEnum
491 atoms = [ "_XMONAD_WORKSPACES"
492 , "_XMONAD_LAYOUT"
493 , "_XMONAD_TITLE"
494 ]
495 (flip mapM_) (zip atoms (lines str)) $ \(atom', content) -> do
496 ustring <- getAtom "UTF8_STRING"
497 atom <- getAtom atom'
498 withDisplay $ \dpy -> io $ do
499 root <- rootWindow dpy $ defaultScreen dpy
500 changeProperty8 dpy root atom ustring propModeReplace $ encodeCChar content
501 sync dpy True
502 wsp = hWsp host
503 -- We can´t define per-host layout modifiers because we lack dependent types
504 layout' = onHost "skadhi" ( onWorkspace (wsp 1) (Full ||| withIM (1%5) (Title "Buddy List") tabbedLayout') $
505 onWorkspace (wsp 10) Full $
506 onWorkspace (wsp 2) (Full ||| tabbedLayout') $
507 onWorkspace (wsp 5) tabbedLayout' $
508 onWorkspace (wsp 8) (withIM (1%5) (Title "Friends") tabbedLayout') $
509 defaultLayouts
510 ) $
511 onHost "vali" ( onWorkspace (wsp 2) (Full ||| tabbedLayout' ||| combineTwo (TwoPane 0.01 0.57) Full tabbedLayout') $
512 onWorkspace (wsp 3) workLayouts $
513 defaultLayouts
514 ) $
515 onHost "hel" ( onWorkspace (wsp 1) (withIM (1 % 8) (Title "Buddy List") $ trackFloating tabbedLayout') $
516 onWorkspace (wsp 2) (tabbedLayout''' ||| Dwindle R CW 1 (5 % 100)) $
517 onWorkspace (wsp 3) workLayouts $
518 onWorkspace (wsp 6) workLayouts $
519 onWorkspace (wsp 4) (tabbedLayout' ||| tabbedLayoutHoriz' ||| Dwindle R CW 1 (5 % 100)) $
520 onWorkspace (wsp 5) (tabbedLayout''' ||| Dwindle R CW 1 (5 % 100)) $
521 onWorkspace (wsp 10) (tabbedLayout''' ||| combineTwoP (TwoPane (1 % 100) (3 % 4)) tabbedLayout''' tabbedLayout''' (ClassName "mpv") ||| Dwindle R CW 1 (5 % 100)) $
522 defaultLayouts
523 ) $
524 onHost "sif" ( onWorkspace (wsp 1) (withIM (1 % 8) (Title "Buddy List") $ trackFloating tabbedLayout') $
525 onWorkspace (wsp 2) (tabbedLayout''' ||| Dwindle R CW 1 (5 % 100)) $
526 onWorkspace (wsp 3) workLayouts $
527 onWorkspace (wsp 6) workLayouts $
528 onWorkspace (wsp 4) (tabbedLayout' ||| tabbedLayoutHoriz' ||| Dwindle R CW 1 (5 % 100)) $
529 onWorkspace (wsp 5) (tabbedLayout''' ||| Dwindle R CW 1 (5 % 100)) $
530 onWorkspace (wsp 8) tabbedLayout''' $
531 onWorkspace (wsp 10) (tabbedLayout''' ||| combineTwoP (TwoPane (1 % 100) (3 % 4)) tabbedLayout''' tabbedLayout''' (ClassName "mpv") ||| Dwindle R CW 1 (5 % 100)) $
532 defaultLayouts
533 ) $
534 defaultLayouts
535 -- tabbedLayout''' = renamed [Replace "Tabbed'"] $ IfMax 1 (noBorders Full) (tabbedLayout tabbedBottomAlways)
536 tabbedLayout''' = tabbedLayout tabbedBottom
537 tabbedLayout' = tabbedLayout tabbedBottomAlways
538 tabbedLayoutHoriz' = tabbedLayoutHoriz tabbedLeftAlways
539 defaultLayouts = {- spiralWithDir East CW (1 % 2) -} Dwindle R CW 1 (5 % 100) ||| tabbedLayout' ||| Full
540 -- workLayouts = {- spiralWithDir East CW (1 % 2) -} Dwindle R CW (2 % 1) (5 % 100) ||| tabbedLayout' ||| Full
541 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)
542 sqrtTwo = approxRational (sqrt 2) (1 / 2560)
543 xmobarPP' = xmobarPP { ppTitle = shorten 80
544 , ppSort = (liftM2 (.)) getSortByIndex $ return scratchpadFilterOutWorkspace
545 , ppUrgent = wrap "(" ")" . xmobarColor "#800000" ""
546 , ppHiddenNoWindows = xmobarColor "#202020" "" . wrap "(" ")"
547 , ppVisible = wrap "(" ")" . xmobarColor "#808000" ""
548 , ppCurrent = wrap "(" ")" . xmobarColor "#008000" ""
549 , ppHidden = wrap "(" ")"
550 , ppWsSep = " "
551 , ppSep = "\n"
552 }
553 withHostUrgency = case hostname of
554 "hel" -> withUrgencyHookC urgencyHook' $ urgencyConfig { suppressWhen = U.Never, remindWhen = Dont }
555 "sif" -> withUrgencyHookC urgencyHook' $ urgencyConfig { suppressWhen = U.Never, remindWhen = Dont }
556 _ -> id
557 urgencyHook' window = do
558 runQuery ((resource =? "comm" <||> resource =? "Pidgin" <||> className =? "Gajim" <||> className =? "Skype") --> safeSpawn "thinklight" ["Blink", "100"]) window
559 urgencyHook (BorderUrgencyHook { urgencyBorderColor = "#bb0000" }) window
560 shutdown :: SomeException -> IO a
561 shutdown e = do
562 let pids = [ -- batteryMon
563 ]
564 mapM_ (signalProcess sigTERM) pids
565 mapM_ (getProcessStatus False False) pids
566 throw e
567 keyUpEventHook :: Event -> X All
568 keyUpEventHook event = handle event >> return (All True)
569 where
570 handle (KeyEvent { ev_event_type = t, ev_state = m, ev_keycode = code })
571 | t == keyRelease = withDisplay $ \dpy -> do
572 s <- io $ keycodeToKeysym dpy code 0
573 mClean <- cleanMask m
574 ks <- asks $ hKeyUpKeys host . config
575 userCodeDef () $ whenJust (Map.lookup (mClean, s) ks) id
576 | otherwise = return ()
577 handle _ = return ()
578 handle shutdown $ launch myConfig
579
580secs :: Int -> Int
581secs = (* 1000000)
582
583-- monitorBattery :: Maybe BatteryContext -> Maybe Notification -> IO ()
584-- monitorBattery Nothing n = do
585-- ctx <- batteryContextNew
586-- case ctx of
587-- Nothing -> threadDelay (secs 10) >> monitorBattery Nothing n
588-- Just _ -> monitorBattery ctx n
589-- monitorBattery ctx@(Just ctx') n = do
590-- batInfo <- getBatteryInfo ctx'
591-- case batInfo of
592-- Nothing -> threadDelay (secs 1) >> monitorBattery ctx n
593-- Just batInfo -> do
594-- let n'
595-- | batteryState batInfo == BatteryStateDischarging
596-- , timeLeft <= 1200
597-- , timeLeft > 0 = Just $ summary "Discharging" <> hint "value" percentage <> urgency u <> body (duz timeLeft ++ "left")
598-- | otherwise = Nothing
599-- u
600-- | timeLeft <= 600 = Critical
601-- | timeLeft <= 1800 = Normal
602-- | otherwise = Low
603-- timeLeft = batteryTimeToEmpty batInfo
604-- percentage :: Int32
605-- percentage = round $ batteryPercentage batInfo
606-- ts = [("s", 60), ("m", 60), ("h", 24), ("d", 365), ("y", 1)]
607-- duz ms = ss
608-- 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
609-- case n' of
610-- Just n' -> Notify.display (maybe mempty reuse n <> Notify.appName "monitorBattery" <> n') >>= (\n -> threadDelay (secs 2) >> monitorBattery ctx (Just n))
611-- Nothing -> threadDelay (secs 30) >> monitorBattery ctx n
612
613disableTouchpad, disableTrackpoint, enableTrackpoint, enableTouchpad :: X ()
614enableTouchpad = safeSpawn "xinput" ["enable", "SynPS/2 Synaptics TouchPad"]
615disableTouchpad = safeSpawn "xinput" ["disable", "SynPS/2 Synaptics TouchPad"]
616enableTrackpoint = safeSpawn "xinput" ["enable", "TPPS/2 IBM TrackPoint"]
617disableTrackpoint = safeSpawn "xinput" ["disable", "TPPS/2 IBM TrackPoint"]
618
619isDisabled :: String -> X Bool
620isDisabled str = do
621 out <- runProcessWithInput "xinput" ["list", str] ""
622 return $ "disabled" `isInfixOf` out
623
624
625spawnKeychain :: X ()
626spawnKeychain = do
627 home <- liftIO getHomeDirectory
628 let keys = (map ((home </>) . (".ssh/" ++)) ["id", "id-rsa"]) ++ ["6B13AA67"]
629 liftIO (maybe (return ()) (setEnv "SSH_ASKPASS") =<< findAskpass)
630 safeSpawn "keychain" . (["--agents", "gpg,ssh"] ++)=<< liftIO (filterM doesFileExist keys)
631 where
632 findAskpass = filter `liftM` readFile "/etc/zshrc"
633 filter = listToMaybe . catMaybes . map (stripPrefix "export SSH_ASKPASS=") . lines
634
635assimilateKeychain :: X ()
636assimilateKeychain = liftIO $ assimilateKeychain' >> return ()
637assimilateKeychain' = tryIOError $ do
638 -- pid <- getProcessID
639 -- tmpDir <- lookupEnv "TMPDIR"
640 -- let tmpDir' = fromMaybe "/tmp" tmpDir
641 -- tmpFile = tmpDir' </> "xmonad-keychain" ++ (show pid) ++ ".env"
642 env <- runProcessWithInput "sh" ["-c", "eval $(keychain --eval --noask --agents gpg,ssh); env"] "" -- > " ++ tmpFile] ""
643 -- env <- readFile tmpFile
644 let envVars = Map.fromList $ map (\(k, v) -> (k, tail' v)) $ map (span (/= '=')) $ envLines
645 envVars' = Map.filterWithKey (\k _ -> k `elem` transfer) envVars
646 transfer = ["SSH_AUTH_SOCK", "SSH_AGENT_PID", "GPG_AGENT_INFO"]
647 envLines = filter (elem '=') $ lines env :: [String]
648 sequence $ map (\(k, c) -> setEnv k c) $ Map.toList envVars'
649 -- removeFile tmpFile
650 where
651 tail' [] = []
652 tail' (x:xs) = xs
653
654
655numKeys = [xK_parenleft, xK_parenright, xK_braceright, xK_plus, xK_braceleft, xK_bracketright, xK_bracketleft, xK_exclam, xK_equal, xK_asterisk]
656
657instance Shrinker CustomShrink where
658 shrinkIt _ "" = [""]
659 shrinkIt s cs
660 | length cs >= 4 = cs : shrinkIt s ((reverse . drop 4 . reverse $ cs) ++ "...")
661 | otherwise = cs : shrinkIt s (init cs)
662
663xPConfig :: XPConfig
664xPConfig = def
665 { font = "xft:Fira Mono for Powerline:style=Medium:pixelsize=22.5"
666 , height = 32
667 , bgColor = "black"
668 , fgColor = "grey"
669 , fgHLight = "green"
670 , bgHLight = "black"
671 , borderColor = "grey"
672 , searchPredicate = (\needle haystack -> all (`isInfixOf` map toLower haystack) . map (map toLower) $ words needle)
673 , position = Top
674 }
675
676sshOverrides host = map (\h -> mkOverride { oHost = h, oCommand = moshCmd . inTmux host} )
677 [ "odin"
678 , "ymir"
679 , "surtr"
680 ]
681 ++
682 map (\h -> mkOverride { oHost = h, oCommand = moshCmd' "/run/current-system/sw/bin/mosh-server" . withEnv [("TERM", "xterm")] . inTmux host} )
683 [ "bragi", "bragi.asgard.yggdrasil"
684 ]
685 ++
686 map (\h -> mkOverride { oHost = h, oCommand = sshCmd . inTmux host } )
687 [ "uni2work-dev1"
688 ]
689 ++
690 map (\h -> mkOverride { oHost = h, oCommand = sshCmd . withEnv [("TERM", "xterm")] . inTmux host } )
691 [ "remote.cip.ifi.lmu.de"
692 , "uniworx3", "uniworx4", "uniworx5", "uniworxdb2"
693 , "testworx"
694 ]
695
696backlight :: (Rational -> Rational) -> X ()
697backlight f = void . xfork . liftIO $ do
698 [ _device
699 , _class
700 , read . Text.unpack -> currentBright
701 , _currentPercentage
702 , read . Text.unpack -> maximumBright
703 ] <- Text.splitOn "," . Text.pack <$> readProcess "brightnessctl" ["-m"] ""
704 let current = currentBright % maximumBright
705 new' = f current * fromIntegral maximumBright
706 new :: Integer
707 new | floor new' < 0 = 0
708 | ceiling new' > maximumBright = maximumBright
709 | new' >= maximumBright % 2 = ceiling new'
710 | otherwise = floor new'
711 callProcess "brightnessctl" ["-m", "s", show new]
712
713cycleThrough :: [Rational] -> (Rational -> Rational)
714cycleThrough opts current = fromMaybe currentOpt $ listToMaybe next'
715 where currentOpt = minimumBy (comparing $ abs . subtract current) opts
716 (_, _ : next') = break (== currentOpt) opts
717
718cycleKbLayout :: [(String, Maybe String)] -> X ()
719cycleKbLayout [] = return ()
720cycleKbLayout layouts = liftIO $ do
721 next <- (getNext . extract) `liftM` runProcessWithInput "setxkbmap" ["-query"] ""
722 let
723 args = case next of
724 (l, Just v) -> [l, v]
725 (l, Nothing) -> [l]
726 safeSpawn "setxkbmap" args
727 where
728 extract :: String -> Maybe (String, Maybe String)
729 extract str = listToMaybe $ do
730 ["layout:", l] <- str'
731 [(l, Just v) | ["variant:", v] <- str'] ++ pure (l, Nothing)
732 where
733 str' = map words $ lines str
734 getNext :: Maybe (String, Maybe String) -> (String, Maybe String)
735 getNext = maybe (head layouts) getNext'
736 getNext' x = case elemIndex x layouts of
737 Nothing -> getNext Nothing
738 Just i -> layouts !! ((i + 1) `mod` length layouts)
739
740mpvAll' :: MpvCommand -> IO [MpvResponse]
741mpvAll' = mpvAll "/var/media/.mpv-ipc"
742
743mpvOne' :: MpvCommand -> IO (Maybe MpvResponse)
744mpvOne' = mpvOne "/var/media/.mpv-ipc"
745
746mediaMpv :: MpvCommand -> X ()
747mediaMpv cmd = void . xfork $ print =<< mpvAll' cmd
748
749mediaMpvTogglePause :: X ()
750mediaMpvTogglePause = void . xfork $ do
751 paused <- mapM mpvResponse <=< mpvAll' $ MpvGetProperty "pause"
752 if
753 | and paused -> print <=< mpvAll' $ MpvSetProperty "pause" False
754 | otherwise -> print <=< mpvOne' $ MpvSetProperty "pause" True
755
756myKeys' conf host = Map.fromList $
757 -- launch a terminal
758 [ ((modm, xK_Return), spawn $ (XMonad.terminal conf) ++ " -e tmux")
759 , ((modm .|. shiftMask, xK_Return), spawn $ XMonad.terminal conf)
760
761 -- launch dmenu
762 --, ((modm, xK_d ), spawn "exe=`dmenu_path | dmenu` && eval \"exec $exe\"")
763 , ((modm, xK_d ), shellPrompt "Run: " xPConfig)
764 , ((modm .|. shiftMask, xK_d ), prompt "Run in Terminal: " ("alacritty" ++ " -e") xPConfig)
765 , ((modm, xK_at ), sshPrompt (sshOverrides . Just $ hName host) xPConfig)
766
767 -- close focused window
768 , ((modm .|. shiftMask, xK_q ), kill)
769 , ((modm .|. controlMask .|. shiftMask, xK_q ), spawn "xkill")
770
771 -- Rotate through the available layout algorithms
772 , ((modm, xK_space ), sendMessage NextLayout)
773
774 -- Reset the layouts on the current workspace to default
775 , ((modm .|. controlMask, xK_r ), (setLayout $ XMonad.layoutHook conf) >> refresh)
776
777 -- Resize viewed windows to the correct size
778 , ((modm, xK_r ), refresh)
779
780 -- Move focus to the next window
781 , ((modm, xK_t ), windows W.focusDown)
782
783 -- Move focus to the previous window
784 , ((modm, xK_n ), windows W.focusUp )
785
786 -- Move focus to the master window
787 , ((modm, xK_m ), windows W.focusMaster )
788
789 -- Swap the focused window and the master window
790 , ((modm .|. shiftMask, xK_m ), windows W.swapMaster)
791
792 -- Swap the focused window with the next window
793 , ((modm .|. shiftMask, xK_t ), windows W.swapDown )
794
795 -- Swap the focused window with the previous window
796 , ((modm .|. shiftMask, xK_n ), windows W.swapUp )
797
798 -- Swap the focused window with the previous window
799 , ((modm .|. shiftMask .|. controlMask, xK_m), sendMessage SwapWindow)
800
801 , ((modm, xK_Right), sendMessage $ Go R)
802 , ((modm, xK_Left ), sendMessage $ Go L)
803 , ((modm, xK_Up ), sendMessage $ Go U)
804 , ((modm, xK_Down ), sendMessage $ Go D)
805 , ((modm .|. shiftMask , xK_Right), sendMessage $ Move R)
806 , ((modm .|. shiftMask , xK_Left ), sendMessage $ Move L)
807 , ((modm .|. shiftMask , xK_Up ), sendMessage $ Move U)
808 , ((modm .|. shiftMask , xK_Down ), sendMessage $ Move D)
809 -- , ((modm .|. controlMask, xK_Right), withFocused $ keysMoveWindow (10, 0))
810 -- , ((modm .|. controlMask, xK_Left ), withFocused $ keysMoveWindow (-10, 0))
811 -- , ((modm .|. controlMask, xK_Up ), withFocused $ keysMoveWindow (0, -10))
812 -- , ((modm .|. controlMask, xK_Down ), withFocused $ keysMoveWindow (0, 10))
813 -- Shrink the master area
814 , ((modm, xK_h ), sendMessage Shrink)
815
816 -- Expand the master area
817 , ((modm, xK_s ), sendMessage Expand)
818
819 -- Push window back into tiling
820 , ((modm .|. shiftMask, xK_space ), withFocused $ windows . W.sink)
821 , ((modm, xK_BackSpace), focusUrgent)
822 , ((modm .|. shiftMask, xK_BackSpace), clearUrgents)
823
824 -- Increment the number of windows in the master area
825 , ((modm , xK_comma ), sendMessage (IncMasterN 1))
826
827 -- Deincrement the number of windows in the master area
828 , ((modm , xK_period), sendMessage (IncMasterN (-1)))
829
830 , ((0, xF86XK_AudioRaiseVolume), safeSpawn "pulseaudio-ctl" ["up", "2"])
831 , ((0, xF86XK_AudioLowerVolume), safeSpawn "pulseaudio-ctl" ["down", "2"])
832 , ((0, xF86XK_AudioMute), safeSpawn "pulseaudio-ctl" ["mute"])
833 , ((0, xF86XK_AudioPause), mediaMpv $ MpvSetProperty "pause" False)
834 , ((0, {-xF86XK_AudioMicMute-} 269025202), safeSpawn "pulseaudio-ctl" ["mute-input"])
835 , ((0, xF86XK_AudioPlay), mediaMpvTogglePause)
836 , ((modm .|. mod1Mask, xK_space), mediaMpvTogglePause)
837
838 , ((0, xF86XK_MonBrightnessDown), backlight (subtract 5))
839 , ((0, xF86XK_MonBrightnessUp), backlight (+ 5))
840
841 , ((modm , xK_Escape), cycleKbLayout (hKbLayouts host))
842 , ((modm .|. controlMask, xK_Escape), safeSpawn "setxkbmap" $ fst (head $ hKbLayouts host) : maybeToList (snd . head $ hKbLayouts host))
843
844 -- Toggle the status bar gap
845 -- Use this binding with avoidStruts from Hooks.ManageDocks.
846 -- See also the statusBar function from Hooks.DynamicLog.
847 --
848 , ((modm , xK_b ), sendMessage ToggleStruts)
849
850 , ((modm .|. shiftMask, xK_p ), safeSpawn "playerctl" ["-a", "pause"])
851
852 -- Quit xmonad
853 , ((modm .|. shiftMask, xK_e ), io (exitWith ExitSuccess))
854
855 -- Restart xmonad
856 -- , ((modm .|. shiftMask .|. controlMask, xK_r ), void . xfork $ recompile False >>= flip when (safeSpawn "xmonad" ["--restart"]))
857 , ((modm .|. shiftMask, xK_r ), void . liftIO $ executeFile "xmonad" True [] Nothing)
858 , ((modm .|. shiftMask, xK_l ), void . xfork $ do
859 sessId <- getEnv "XDG_SESSION_ID"
860 safeSpawn "loginctl" ["lock-session", sessId]
861 )
862 , ((modm .|. shiftMask, xK_s ), safeSpawn "systemctl" ["suspend"])
863 , ((modm .|. shiftMask, xK_h ), safeSpawn "systemctl" ["hibernate"])
864 , ((modm .|. shiftMask, xK_b ), backlight $ cycleThrough [1, 3 % 4, 1 % 2, 1 % 4, 1 % 10, 1 % 100, 0]
865 )
866 , ((modm .|. shiftMask .|. controlMask, xK_b), backlight $ cycleThrough [0, 1 % 100, 1 % 10, 1 % 4, 1 % 2, 3 % 4, 1]
867 )
868 , ((modm, xK_v ), windows copyToAll) -- @@ Make focused window always visible
869 , ((modm .|. shiftMask, xK_v ), killAllOtherCopies) -- @@ Toggle window state back
870 , ((modm .|. shiftMask, xK_g ), windowPrompt xPConfig Goto wsWindows)
871 , ((modm .|. shiftMask .|. controlMask, xK_g ), windowPrompt xPConfig Bring allWindows)
872 ]
873 ++
874
875 --
876 -- mod-[1..9], Switch to workspace N
877 --
878 -- mod-[1..9], Switch to workspace N
879 -- mod-shift-[1..9], Move client to workspace N
880 --
881 [((m .|. modm, k), windows $ f i)
882 | (i, k) <- zip (XMonad.workspaces conf) $ numKeys
883 , (f, m) <- [(W.greedyView, 0), (W.shift, shiftMask)]
884 ]
885 ++
886 [((m .|. modm .|. controlMask, k), void . runMaybeT $
887 MaybeT (P.getScreen def i) >>= MaybeT . screenWorkspace >>= lift . windows . f
888 )
889 | (i, k) <- zip (hScreens host) [xK_g, xK_c, xK_r, xK_l]
890 , (f, m) <- [(W.view, 0), (W.shift, shiftMask)]
891 ]
892 where
893 modm = XMonad.modMask conf
894
895
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..d4d75073
--- /dev/null
+++ b/accounts/gkleen@sif/zshrc
@@ -0,0 +1,410 @@
1filebin() {
2 basePath=/srv/www/files
3 ssh ymir find /srv/www/files -type f -printf "$'%T@ %TY-%Tm-%TdT%TH:%TM %P\\\\0'" | sort -zn | cut -z -d ' ' -f 2- \
4 | while IFS= read -r -d $'\0' l; do
5 IFS=' ' read -r t p <<<"${l}"
6 printf "%s https://f.141.li/%s\n" "${t}" "${p}"
7 done
8}
9
10push2bin() {
11 if [[ ${#@} -eq 1 && ! -r ${1} ]]; then
12 uux -p 'ymir!push2bin' $(echo -n "${1:t}" | tr -c $'[:alnum:]+-=.' '_')
13 else
14 for f (${@}); do
15 uux -p 'ymir!push2bin' $(echo -n "${f:t}" | tr -c $'[:alnum:]+-=.' '_') <${f}
16 done
17 fi
18}
19
20genmail() {
21 local baseName=""
22 local target=""
23 if [[ ${#@} -ge 1 ]]; then
24 target=${1}
25 shift
26 fi
27
28 if [[ ${#@} -ge 1 ]]; then
29 baseName=$(pwgen ${@})
30 else
31 baseName=$(pwgen -v -A -0 16 1)
32 fi
33 baseName=$(tr -cd $'[:alnum:]!#$%&*+-/=?^_{|}~.' <<<${baseName})
34 address=${baseName}@141.li
35 insertAddr() {
36 echo "${baseName} gkleen" | ssh ymir tee -a /srv/mail/spm 1>/dev/null \
37 }
38
39 printf "%s\n" ${address}
40 read -q 'cont?Continue [y/N]? ' || return
41
42 insertAddr
43}
44
45s() {
46 dir=$(pwd)
47 [[ ${#@} -ge 1 ]] && dir=$1
48
49 shellFile=$(findNix ${@})
50 [[ ${#@} -ge 1 ]] && shift
51
52 typeset -a cmd
53 if [[ -d ${dir}/.nix-gc-roots ]]; then
54 cmd=(persistent-nix-shell ${shellFile} ${S_EXTRA_ARGS} ${@})
55 else
56 cmd=(nix-shell ${shellFile} ${S_EXTRA_ARGS} ${@})
57 fi
58
59 if [[ -n "${S_SYSTEMD}" ]]; then
60 systemd-run --user --slice=development.slice --collect -E PATH=${PATH} -p WorkingDirectory=${dir} -- ${cmd}
61 else
62 (
63 cd ${dir}
64
65 exec ${cmd}
66 )
67 fi
68}
69
70sz() {
71 typeset -a S_EXTRA_ARGS
72 S_EXTRA_ARGS=(--run "env __ETC_ZSHENV_SOURCED=1 zsh") s ${@}
73}
74st() {
75 typeset -a S_EXTRA_ARGS
76 S_EXTRA_ARGS=(--run "tmux new-session env __ETC_ZSHENV_SOURCED=1 zsh") s ${@}
77}
78stt() {
79 typeset -a S_EXTRA_ARGS
80 S_SYSTEMD=true S_EXTRA_ARGS=(--run "urxvt -e tmux -S .tmux.sock new-session env __ETC_ZSHENV_SOURCED=1 zsh") s ${@}
81}
82se() {
83 typeset -a S_EXTRA_ARGS
84 S_SYSTEMD=true S_EXTRA_ARGS=(--run "emacs") s ${@}
85}
86
87findNix() {
88 if [[ $#@ -eq 0 ]]; then
89 findNix $(pwd)
90 elif [[ -f "$1" ]]; then
91 print ${1:a}
92 elif [[ -d "$1" && -f "$1"/shell.nix ]]; then
93 print ${1:a}/shell.nix
94 elif [[ -d "$1" && -f "$1"/default.nix ]]; then
95 print ${1:a}/default.nix
96 elif [[ -d "$1" && "$1" != "/" ]]; then
97 findNix ${1:h}
98 else
99 printf "Traversed directories to ‘/’ and found no shell specification\n" >&2
100 return 1
101 fi
102}
103
104dir() {
105 curlArchive=false
106 templateArchive=""
107 repoUrl=""
108 nixShell=""
109 findNix=false
110 dir=""
111 forceShell=false
112 wormhole=false
113 gitWorktree=""
114 notmuchMsg=""
115 quickserve=false
116
117 while getopts ':t:a:s:Sd:ir:wqg:n:' arg; do
118 case $arg in
119 "t") ;;
120 "a")
121 if [[ ${OPTARG} =~ "://" ]]; then
122 templateArchive=${OPTARG}
123 curlArchive=true
124 else
125 templateArchive=${OPTARG:a}
126 fi
127 ;;
128 "s") nixShell=${OPTARG:a} ;;
129 "S") findNix=true ;;
130 "d") dir=${OPTARG} ;;
131 "i") forceShell=true ;;
132 "r") repoUrl=${OPTARG} ;;
133 "w") wormhole=true ;;
134 "g") gitWorktree=${OPTARG} ;;
135 "n") notmuchMsg=${OPTARG} ;;
136 "q") quickserve=true ;;
137 *) printf "Invalid option: %s\n" $arg >&2; exit 2 ;;
138 esac
139 done
140
141 shift $((OPTIND - 1))
142
143 if [[ -z ${dir} && ${#@} -ge 1 ]]; then
144 dir=${1}
145 shift
146 fi
147
148 [[ -n ${dir} ]] || return 2;
149
150 if [[ ! -e ${dir} ]]; then
151 if [[ -z "${gitWorktree}" ]]; then
152 mkdir -vp ${dir}
153 else
154 git -C ${gitWorktree} worktree add ${dir}
155 fi
156 else
157 gitWorktree=""
158 fi
159
160 (
161 cd ${dir}
162 export dir;
163
164 ${findNix} && { nixShell=$(findNix) || return $? }
165
166 [[ -n ${repoUrl} ]] && git clone -- ${repoUrl} .
167
168 if [[ -n ${templateArchive} ]]; then
169 (
170 archiveFile=""
171 cleanup() {
172 [[ -n "${archiveFile}" ]] && rm -fv ${archiveFile}
173 }
174 trap cleanup EXIT
175
176 if ${curlArchive}; then
177 archiveFile=$(mktemp -t "archive.XXXXXXXXXX.${templateArchive:t}")
178
179 curl -L -o ${archiveFile} ${templateArchive}
180
181 templateArchive=${archiveFile}
182 fi
183
184 case $(file --brief --mime-type ${templateArchive}) in
185 application/zip) unzip ${templateArchive} ;;
186 *) tar -xvaf ${templateArchive} ;;
187 esac
188 )
189 fi
190
191
192 if [[ -n ${notmuchMsg} ]]; then
193 getMimeTypes() {
194 nix-shell -p mailcap --run "find \${buildInputs} -path '*/etc/mime.types' | head -n 1 | xargs -- cat"
195 }
196
197 typeset -a messages
198 messages=(${(z)$(notmuch search --output=messages ${notmuchMsg})})
199
200 for message (${messages}); do
201 typeset -A notmuchAtts
202 notmuchAtts=()
203
204 while IFS= read -r -d $'\n' line; do
205 [[ ${line} =~ '(attachment|part)\{ ID: ([0-9]+)' ]] || continue
206 attId=${match[2]}
207
208 [[ ${line} =~ 'Content-type: multipart/' ]] && continue
209
210 fName="part_${attId}"
211 [[ ${line} =~ 'Filename: (([^,]|,[^ ])+)' ]] && fName=${match[1]}
212
213 if [[ ${#messages} -gt 1 ]]; then
214 fName="${message}/${fName}"
215 fi
216
217 fExt="${fName:e}"
218 [[ -n "${fExt}" ]] && fName="${fName:r}"
219
220 if [[ -z "${fExt}" && ${line} =~ 'Content-type: (([^,]|,[^ ])+)$' ]]; then
221 fExt=$(getMimeTypes | grep ${match[1]}$'\t' | head -n 1 | awk '{ print $2; }')
222 fi
223
224 mkdir -p ${fName:h}
225 if [[ -n "${fExt}" ]]; then
226 fName=$(mktemp -p . "${fName}.XXXXXX.${fExt}")
227 else
228 fName=$(mktemp -p . "${fName}.XXXXXX")
229 fi
230
231 notmuchAtts[${attId}]=${fName}
232 done <<(notmuch show --decrypt=false -- ${message} | tr -d $'\f')
233
234 for attId fName in ${(kv)notmuchAtts}; do
235 [[ -d ${fName:h} ]] || mkdir -p ${fName:h}
236 printf "#%d → ‘%s’\n" "${attId}" "${fName}" >&2
237
238 notmuch show --decrypt=false --part=${attId} -- ${message} | pv -W -D 2 -i 0.1 >${fName}
239 done
240 done
241 fi
242
243
244 ${wormhole} && wormhole receive
245
246 if ${quickserve}; then
247 quickserve --root . --upload . --show-hidden --tar gz
248 fi
249
250
251 if [[ ${#@} -eq 0 ]] || ${forceShell}; then
252 if [[ ${#@} -gt 0 ]]; then
253 if [[ -z ${nixShell} ]]; then
254 ${@}
255 else
256 nix-shell ${nixShell} --run "${@}"
257 fi
258 fi
259
260 cd $(pwd) # Needed for mounting to work
261
262 isSingleDir() {
263 typeset -a contents
264 contents=(*(N) .*(N))
265
266 if [[ ${#contents} -eq 1 && -d ${contents[1]} ]]; then
267 print ${contents[1]}
268 return 0
269 else
270 return 1
271 fi
272 }
273 while d=$(isSingleDir); do cd ${d}; done
274
275
276 if [[ -z ${nixShell} ]]; then
277 exec -- zsh
278 else
279 exec -- nix-shell ${nixShell} --run zsh
280 fi
281 else
282 if [[ -z ${nixShell} ]]; then
283 exec -- ${@}
284 else
285 exec -- nix-shell ${nixShell} --run "${@}"
286 fi
287 fi
288 )
289}
290
291tmpdir() {
292 cleanup()
293 {
294 cd /
295 unmount() {
296 printf "Unmounting %s\n" ${1} >&2
297 fusermount -u ${1} || umount ${1} || sudo umount ${1}
298 }
299
300 if mountpoint -q -- ${dir}; then
301 unmount ${dir} || return $?
302 else
303 while read -d $'\0' subDir; do
304 mountpoint -q -- ${subDir} || continue
305 unmount ${subDir} || return $?
306 done <<<$(find ${dir} -xdev -type d -print0 | sort -zr)
307 fi
308
309 rm -rfv --one-file-system -- ${dir}
310 }
311
312 local tmpdir=""
313
314 while getopts ':t:a:s:Sd:ir:wqg:n:' arg; do
315 case $arg in
316 "t") tmpdir="=${OPTARG}" ;;
317 "?"|":") printf "Invalid option: %s\n" $arg >&2; exit 2 ;;
318 esac
319 done
320
321 (
322 trap cleanup EXIT
323
324
325 local dir=$(mktemp -ud --tmpdir${tmpdir} ${0}.XXXXXXXXXX || return $?)
326
327 dir -d ${dir} ${@}
328 )
329}
330
331inhibit-sleep() {
332 if systemctl --user is-active prevent-suspend.service 1>/dev/null; then
333 echo "Allowing suspend"
334 systemctl --user stop prevent-suspend.service
335 else
336 echo "Inhibiting suspend"
337 systemctl --user start prevent-suspend.service
338 fi
339}
340
341qr() {
342 qrencode -l M -o - -t ANSIUTF8 $@
343}
344
345clock() {
346 tty-clock -sSbc -C 7 -d 0 -a 100000000
347}
348
349public-ip() {
350 curl -s -H 'Accept: application/json' $@ ifconfig.co | jq -r '.ip'
351}
352
353nix-ghci() {
354 pkgExpr=""
355 if [[ ${#@} -gt 0 ]]; then
356 pkgExpr="${1}"
357 shift
358 fi
359
360 nix-shell -p "with (import <nixpkgs> {}); pkgs.haskellPackages.ghcWithPackages (p: with p; [${pkgExpr}])" --run "ghci ${@}"
361}
362
363swap() {
364 f1=${1}
365 f2=${2}
366
367 if [[ -z "${f1}" || ! -e "${f1}" ]]; then
368 printf "‘%s’ does not exist\n" "${f1}" >&2
369 return 2
370 fi
371 if [[ -z "${f2}" || ! -e "${f2}" ]]; then
372 printf "‘%s’ does not exist\n" "${f2}" >&2
373 return 2
374 fi
375
376 tmpfile=$(mktemp --dry-run --tmpdir=${f1:h} .swap.XXXXXXXXXX)
377 mv -v ${f1} ${tmpfile}
378 mv -v ${f2} ${f1}
379 mv -v ${tmpfile} ${f2}
380}
381
382l() {
383 exa --binary --git --time-style=iso --long --all --header --group-directories-first --colour=always $@ | less --mouse -FR
384}
385
386re() {
387 systemctl --restart $@
388}
389
390ure() {
391 systemctl --user --restart $@
392}
393
394u2wdb() {
395 ssh -t postgres@uniworxdb2 psql uni2work
396}
397
398alias '..'='cd ..'
399alias -g L='| less'
400alias -g S='&> /dev/null'
401alias -g G='| grep'
402alias -g B='&> /dev/null &'
403alias -g BB='&> /dev/null &!'
404
405export DEFAULT_USER=gkleen
406export EDITOR=emacsclient
407
408bindkey -e
409bindkey ';5C' emacs-forward-word
410bindkey ';5D' emacs-backward-word \ No newline at end of file