]> git.armaanb.net Git - config.org.git/blob - config.org
Simplify projectile configuration
[config.org.git] / config.org
1 #+TITLE: System Configuration
2 #+DESCRIPTION: Personal system configuration in org-mode format.
3 #+AUTHOR: Armaan Bhojwani
4 #+EMAIL: me@armaanb.net
5
6 * Welcome
7 Welcome to my system configuration! This file contains my Emacs configuration, but also my config files for many of the other programs on my system!
8 ** Compatability
9 I am currently using Emacs 27.2 on Linux, so some settings and packages may not be available for older versions of Emacs. This is a purely personal configuration, so while I can guarantee that it works on my setup, it might not work for you.
10 ** Choices
11 I chose to create a powerful, yet not overly heavy Emacs configuration. Things like a fancy modeline, icons, or LSP mode do not increase my productivity, and create visual clutter, and thus have been excluded.
12
13 Another important choice has been to integrate Emacs into a large part of my computing environment (see [[*Emacs OS]]). I use email, IRC, RSS, et cetera, all through Emacs which simplifies my workflow and creates an amazingly integrated environment.
14
15 Lastly, I use Evil mode. Modal keybindings are simpler and more ergonomic than standard Emacs style, and Vim keybindings are what I'm comfortable with and are pervasive throughout computing.
16 ** License
17 Released under the [[https://opensource.org/licenses/MIT][MIT license]] by Armaan Bhojwani, 2021. Note that many snippets are taken from online, and other sources, who are credited for their work near their contributions.
18 * Package management
19 ** Bootstrap straight.el
20 straight.el is really nice for managing package, and it integrates nicely with use-package. It uses the bootstrapping system defined here for installation.
21 #+begin_src emacs-lisp
22   (defvar native-comp-deferred-compilation-deny-list ())
23   (defvar bootstrap-version)
24   (let ((bootstrap-file
25          (expand-file-name "straight/repos/straight.el/bootstrap.el" user-emacs-directory))
26         (bootstrap-version 5))
27     (unless (file-exists-p bootstrap-file)
28       (with-current-buffer
29           (url-retrieve-synchronously
30            "https://raw.githubusercontent.com/raxod502/straight.el/develop/install.el"
31            'silent 'inhibit-cookies)
32         (goto-char (point-max))
33         (eval-print-last-sexp)))
34     (load bootstrap-file nil 'nomessage))
35 #+end_src
36 ** Replace package.el with straight
37 #+begin_src emacs-lisp
38   (straight-use-package 'use-package)
39   (setq straight-use-package-by-default t)
40 #+end_src
41 * Visual options
42 ** Theme
43 Use the Modus Operandi theme by Protesilaos Stavrou. Its the best theme for Emacs by far, because how clear and readable it is. It is highly customizable, but I just set a few options here.
44 #+begin_src emacs-lisp
45   (use-package modus-themes
46     :custom
47     (modus-themes-slanted-constructs t)
48     (modus-themes-bold-constructs t)
49     (modus-themes-mode-line '3d)
50     (modus-themes-scale-headings t)
51     (modus-themes-diffs 'desaturated)
52     :config (load-theme 'modus-vivendi t))
53 #+end_src
54 ** Typography
55 *** Font
56 JetBrains Mono is a great programming font with ligatures. The "NF" means that it has been patched with the [[https://www.nerdfonts.com/][Nerd Fonts]].
57 #+begin_src emacs-lisp
58   (add-to-list 'default-frame-alist '(font . "JetBrainsMonoNF-12"))
59 #+end_src
60 *** Ligatures
61 #+begin_src emacs-lisp
62   (use-package ligature
63     :straight (ligature :type git :host github :repo "mickeynp/ligature.el")
64     :config
65     (ligature-set-ligatures
66      '(prog-mode text-mode)
67      '("-|" "-~" "---" "-<<" "-<" "--" "->" "->>" "-->" "/=" "/=="
68        "/>" "//" "/*" "*>" "*/" "<-" "<<-" "<=>" "<=" "<|" "<||"
69        "<|||" "<|>" "<:" "<>" "<-<" "<<<" "<==" "<<=" "<=<" "<==>"
70        "<-|" "<<" "<~>" "<=|" "<~~" "<~" "<$>" "<$" "<+>" "<+" "</>"
71        "</" "<*" "<*>" "<->" "<!--" ":>" ":<" ":::" "::" ":?" ":?>"
72        ":=" "::=" "=>>" "==>" "=/=" "=!=" "=>" "===" "=:=" "==" "!=="
73        "!!" "!=" ">]" ">:" ">>-" ">>=" ">=>" ">>>" ">-" ">=" "&&&"
74        "&&" "|||>" "||>" "|>" "|]" "|}" "|=>" "|->" "|=" "||-" "|-"
75        "||=" "||" ".." ".?" ".=" ".-" "..<" "..." "+++" "+>" "++"
76        "[||]" "[<" "[|" "{|" "?." "?=" "?:" "##" "###" "####" "#["
77        "#{" "#=" "#!" "#:" "#_(" "#_" "#?" "#(" ";;" "_|_" "__" "~~"
78        "~~>" "~>" "~-" "~@" "$>" "^=" "]#"))
79     (global-ligature-mode t))
80 #+end_src
81 ** Line numbers
82 Display relative line numbers except in certain modes.
83 #+begin_src emacs-lisp
84   (global-display-line-numbers-mode)
85   (setq display-line-numbers-type 'relative)
86   (dolist (no-line-num '(term-mode-hook
87                          pdf-view-mode-hook
88                          shell-mode-hook
89                          org-mode-hook
90                          circe-mode-hook
91                          eshell-mode-hook))
92     (add-hook no-line-num (lambda () (display-line-numbers-mode 0))))
93 #+end_src
94 ** Highlight matching parenthesis
95 #+begin_src emacs-lisp
96   (use-package paren
97     :config (show-paren-mode)
98     :custom (show-paren-style 'parenthesis))
99 #+end_src
100 ** Modeline
101 *** Show current function
102 #+begin_src emacs-lisp
103   (which-function-mode)
104 #+end_src
105 *** Make position in file more descriptive
106 Show current column and file size.
107 #+begin_src emacs-lisp
108   (column-number-mode)
109   (size-indication-mode)
110 #+end_src
111 *** Hide minor modes
112 #+begin_src emacs-lisp
113   (use-package minions
114     :config (minions-mode))
115 #+end_src
116 ** Whitespace mode
117 Highlight whitespace and other bad text practices.
118 #+begin_src emacs-lisp
119   (use-package whitespace
120     :custom (whitespace-style '(face lines-tail)))
121   (dolist (hook '(prog-mode-hook))
122     (add-hook hook (lambda () (whitespace-mode 1))))
123 #+end_src
124 ** Highlight todo items in comments
125 +begin_src emacs-lisp
126   (use-package hl-todo
127     :straight (hl-todo :type git :host github :repo "tarsius/hl-todo")
128     :config (global-hl-todo-mode 1))
129 #+end_src
130 ** Blink cursor
131 #+begin_src emacs-lisp
132   (blink-cursor-mode)
133 #+end_src
134 ** Visual line mode
135 Soft wrap words and do operations by visual lines in some modes.
136 #+begin_src emacs-lisp
137   (dolist (hook '(text-mode-hook
138                   org-mode-hook
139                   markdown-mode-hook
140                   mu4e-view-mode-hook))
141     (add-hook hook (lambda () (visual-line-mode 1))))
142 #+end_src
143 ** Auto fill mode
144 #+begin_src emacs-lisp
145   (dolist (hook '(scdoc-mode-hook
146                   mu4e-compose-mode-hook))
147     (add-hook hook (lambda () (auto-fill-mode 1))))
148 #+end_src
149 ** Display number of matches in search
150 #+begin_src emacs-lisp
151   (use-package anzu
152     :config (global-anzu-mode)
153     :bind
154     ([remap query-replace] . anzu-query-replace)
155     ([remap query-replace-regexp] . anzu-query-replace-regexp))
156 #+end_src
157 *** TODO This config doesn't work right
158 ** Visual bell
159 Invert modeline color instead of audible bell or the standard visual bell.
160 #+begin_src emacs-lisp
161   (setq visible-bell nil
162         ring-bell-function
163         (lambda () (invert-face 'mode-line)
164           (run-with-timer 0.1 nil #'invert-face 'mode-line)))
165 #+end_src
166 * Evil mode
167 ** General
168 #+begin_src emacs-lisp
169   (use-package evil
170     :custom (select-enable-clipboard nil)
171     :config
172     (evil-mode)
173     (fset 'evil-visual-update-x-selection 'ignore) ;; Keep clipboard and register seperate
174     ;; Use visual line motions even outside of visual-line-mode buffers
175     (evil-global-set-key 'motion "j" 'evil-next-visual-line)
176     (evil-global-set-key 'motion "k" 'evil-previous-visual-line)
177     (global-set-key (kbd "<escape>") 'keyboard-escape-quit))
178 #+end_src
179 ** Evil collection
180 Evil bindings for tons of packages.
181 #+begin_src emacs-lisp
182   (use-package evil-collection
183     :after evil
184     :init (evil-collection-init)
185     :custom (evil-collection-setup-minibuffer t))
186 #+end_src
187 ** Surround
188 tpope prevails!
189 #+begin_src emacs-lisp
190   (use-package evil-surround
191     :config (global-evil-surround-mode))
192 #+end_src
193 ** Nerd commenter
194 Makes commenting super easy
195 #+begin_src emacs-lisp
196   (use-package evil-nerd-commenter
197     :bind (:map evil-normal-state-map
198                 ("gc" . evilnc-comment-or-uncomment-lines))
199     :custom (evilnc-invert-comment-line-by-line nil))
200 #+end_src
201 ** Undo redo
202 Fix the oopsies!
203 #+begin_src emacs-lisp
204   (use-package undo-fu
205     :config (evil-set-undo-system 'undo-fu))
206
207   (use-package undo-fu-session
208     :config (global-undo-fu-session-mode))
209 #+end_src
210 ** Number incrementing
211 Add back C-a/C-x bindings.
212 #+begin_src emacs-lisp
213   (use-package evil-numbers
214     :straight (evil-numbers :type git :host github :repo "juliapath/evil-numbers")
215     :bind (:map evil-normal-state-map
216                 ("C-M-a" . evil-numbers/inc-at-pt)
217                 ("C-M-x" . evil-numbers/dec-at-pt)))
218 #+end_src
219 ** Evil org
220 #+begin_src emacs-lisp
221   (use-package evil-org
222     :after org
223     :hook (org-mode . evil-org-mode)
224     :config
225     (evil-org-set-key-theme '(textobjects insert navigation shift todo)))
226
227   (use-package evil-org-agenda
228     :straight (:type built-in)
229     :after evil-org
230     :config (evil-org-agenda-set-keys))
231 #+end_src
232 * Org mode
233 ** General
234 #+begin_src emacs-lisp
235   (use-package org
236     :straight (:type built-in)
237     :commands (org-capture org-agenda)
238     :custom
239     (org-ellipsis " ▾")
240     (org-agenda-start-with-log-mode t)
241     (org-agenda-files (quote ("~/org/tasks.org")))
242     (org-log-done 'time)
243     (org-log-into-drawer t)
244     (org-src-tab-acts-natively t)
245     (org-src-fontify-natively t)
246     (org-startup-indented t)
247     (org-hide-emphasis-markers t)
248     (org-fontify-whole-block-delimiter-line nil)
249     (org-archive-default-command 'org-archive-to-archive-sibling)
250     :bind
251     ("C-c a" . org-agenda)
252     (:map evil-normal-state-map ("ga" . org-archive-subtree-default)))
253 #+end_src
254 ** Tempo
255 Define templates for lots of common structure elements. Mostly just used within this file.
256 #+begin_src emacs-lisp
257   (use-package org-tempo
258     :after org
259     :straight (:type built-in)
260     :config
261     (dolist (addition '(("el" . "src emacs-lisp")
262                         ("el" . "src emacs-lisp")
263                         ("sp" . "src conf :tangle ~/.spectrwm.conf")
264                         ("ash" . "src shell :tangle ~/.config/ash/ashrc")
265                         ("pi" . "src conf :tangle ~/.config/picom/picom.conf")
266                         ("git" . "src conf :tangle ~/.gitconfig")
267                         ("za" . "src conf :tangle ~/.config/zathura/zathurarc")
268                         ("xr" . "src conf :tangle ~/.Xresources")
269                         ("tm" . "src conf :tangle ~/.tmux.conf")
270                         ("gp" . "src conf :tangle ~/.gnupg/gpg.conf")
271                         ("ag" . "src conf :tangle ~/.gnupg/gpg-agent.conf")
272                         ("xm" . "src conf :tangle ~/.config/xmodmap")))
273       (add-to-list 'org-structure-template-alist addition)))
274 #+end_src
275 * Autocompletion
276 ** Ivy
277 A well balanced completion framework.
278 #+begin_src emacs-lisp
279   (use-package ivy
280     :bind (:map ivy-minibuffer-map
281            ("TAB" . ivy-alt-done))
282            (:map ivy-switch-buffer-map
283            ("M-d" . ivy-switch-buffer-kill))
284     :config (ivy-mode))
285 #+end_src
286 ** Ivy-rich
287 #+begin_src emacs-lisp
288   (use-package ivy-rich
289     :after (ivy counsel)
290     :config (ivy-rich-mode))
291 #+end_src
292 ** Counsel
293 Ivy everywhere.
294 #+begin_src emacs-lisp
295   (use-package counsel
296     :bind ("C-M-j" . 'counsel-switch-buffer)
297     :config (counsel-mode))
298 #+end_src
299 ** Remember frequent commands
300 #+begin_src emacs-lisp
301   (use-package ivy-prescient
302     :after counsel
303     :config
304     (prescient-persist-mode)
305     (ivy-prescient-mode))
306 #+end_src
307 * Emacs OS
308 ** RSS
309 Use elfeed for reading RSS. I have another file with all the feeds in it that I'd rather keep private.
310 #+begin_src emacs-lisp
311   (use-package elfeed
312     :bind (("C-c e" . elfeed))
313     :config (load "~/.emacs.d/feeds.el")
314     :bind (:map elfeed-search-mode-map ("C-c C-o" . 'elfeed-show-visit)))
315 #+end_src
316 ** Email
317 Use mu4e for reading emails.
318 Contexts are a not very well known feature of mu4e that makes it super easy to manage multiple accounts. Much better than some of the hacky methods and external packages that I've seen.
319 *** TODO Switch to mbsync
320 =offlineimap= really crappy (slow and requires python2), and I need to replace it with =mbsync=.
321 *** TODO Include mbsync/offlineimap config
322 *** TODO Split up and document this config a bit
323 *** Setup
324 #+begin_src emacs-lisp
325   (use-package smtpmail
326     :straight (:type built-in))
327   (use-package mu4e
328     :load-path "/usr/share/emacs/site-lisp/mu4e"
329     :straight (:build nil)
330     :bind (("C-c m" . mu4e))
331     :config
332     (setq user-full-name "Armaan Bhojwani"
333           smtpmail-local-domain "armaanb.net"
334           smtpmail-stream-type 'ssl
335           smtpmail-smtp-service '465
336           mu4e-change-filenames-when-moving t
337           mu4e-get-mail-command "offlineimap -q"
338           message-citation-line-format "On %a %d %b %Y at %R, %f wrote:\n"
339           message-citation-line-function 'message-insert-formatted-citation-line
340           mu4e-completing-read-function 'ivy-completing-read
341           mu4e-confirm-quit nil
342           mu4e-view-use-gnus t
343           mail-user-agent 'mu4e-user-agent
344           mu4e-context-policy 'pick-first
345           mu4e-contexts
346           `( ,(make-mu4e-context
347                :name "school"
348                :enter-func (lambda () (mu4e-message "Entering school context"))
349                :leave-func (lambda () (mu4e-message "Leaving school context"))
350                :match-func (lambda (msg)
351                              (when msg
352                                (string-match-p "^/school" (mu4e-message-field msg :maildir))))
353                :vars '((user-mail-address . "abhojwani22@nobles.edu")
354                        (mu4e-sent-folder . "/school/Sent")
355                        (mu4e-drafts-folder . "/school/Drafts")
356                        (mu4e-trash-folder . "/school/Trash")
357                        (mu4e-refile-folder . "/school/Archive")
358                        (message-cite-reply-position . above)
359                        (user-mail-address . "abhojwani22@nobles.edu")
360                        (smtpmail-smtp-user . "abhojwani22@nobles.edu")
361                        (smtpmail-smtp-server . "smtp.gmail.com")))
362              ,(make-mu4e-context
363                :name "personal"
364                :enter-func (lambda () (mu4e-message "Entering personal context"))
365                :leave-func (lambda () (mu4e-message "Leaving personal context"))
366                :match-func (lambda (msg)
367                              (when msg
368                                (string-match-p "^/personal" (mu4e-message-field msg :maildir))))
369                :vars '((mu4e-sent-folder . "/personal/Sent")
370                        (mu4e-drafts-folder . "/personal/Drafts")
371                        (mu4e-trash-folder . "/personal/Trash")
372                        (mu4e-refile-folder . "/personal/Archive")
373                        (user-mail-address . "me@armaanb.net")
374                        (message-cite-reply-position . below)
375                        (smtpmail-smtp-user . "me@armaanb.net")
376                        (smtpmail-smtp-server . "smtp.mailbox.org")))))
377     (add-to-list 'mu4e-bookmarks
378                  '(:name "Unified inbox"
379                          :query "maildir:\"/personal/INBOX\" or maildir:\"/school/INBOX\""
380                          :key ?b))
381     :hook ((mu4e-compose-mode . flyspell-mode)
382            (message-send-hook . (lambda () (unless (yes-or-no-p "Ya sure 'bout that?")
383                                              (signal 'quit nil))))))
384 #+end_src
385 *** Discourage Gnus from displaying HTML emails
386 #+begin_src emacs-lisp
387   (with-eval-after-load "mm-decode"
388     (add-to-list 'mm-discouraged-alternatives "text/html")
389     (add-to-list 'mm-discouraged-alternatives "text/richtext"))
390 #+end_src
391 ** Default browser
392 Set EWW as default browser except for multimedia which should open in MPV.
393 #+begin_src emacs-lisp
394   (defun browse-url-mpv (url &optional new-window)
395     "Ask MPV to load URL."
396     (interactive)
397     (start-process "mpv" "*mpv*" "mpv" url))
398
399   (setq browse-url-handlers
400         (quote
401          (("youtu\\.?be" . browse-url-mpv)
402           ("peertube.*" . browse-url-mpv)
403           ("vid.*" . browse-url-mpv)
404           ("vid.*" . browse-url-mpv)
405           ("*.mp4" . browse-url-mpv)
406           ("*.mp3" . browse-url-mpv)
407           ("*.ogg" . browse-url-mpv)
408           ("." . eww-browse-url)
409           )))
410 #+end_src
411 ** EWW
412 Some EWW enhancements.
413 *** Give buffer a useful name
414 #+begin_src emacs-lisp
415   ;; From https://protesilaos.com/dotemacs/
416   (defun prot-eww--rename-buffer ()
417     "Rename EWW buffer using page title or URL.
418         To be used by `eww-after-render-hook'."
419     (let ((name (if (eq "" (plist-get eww-data :title))
420                     (plist-get eww-data :url)
421                   (plist-get eww-data :title))))
422       (rename-buffer (format "*%s # eww*" name) t)))
423
424   (use-package eww
425     :straight (:type built-in)
426     :bind (("C-c w" . eww))
427     :hook (eww-after-render-hook prot-eww--rename-buffer))
428 #+end_src
429 *** Keybinding
430 #+begin_src emacs-lisp
431   (global-set-key (kbd "C-c w") 'eww)
432 #+end_src
433 ** IRC
434 Circe is a really nice IRC client that claims to be above RCIRC and below ERC in terms of features. ERC felt a bit messy and finicky to me, and Circe has all the features that I need. This setup gets the password for my bouncer (Pounce) instances via my =~/.authinfo.gpg= file.
435 #+begin_src emacs-lisp
436   (defun fetch-password (&rest params)
437     (require 'auth-source)
438     (let ((match (car (apply 'auth-source-search params))))
439       (if match
440           (let ((secret (plist-get match :secret)))
441             (if (functionp secret)
442                 (funcall secret)
443               secret))
444         (error "Password not found for %S" params))))
445
446   (use-package circe
447     :config
448     (enable-lui-track)
449     (enable-circe-color-nicks)
450     (setq circe-network-defaults '(("libera"
451                                     :host "irc.armaanb.net"
452                                     :nick "emacs"
453                                     :user "emacs"
454                                     :use-tls t
455                                     :port 6698
456                                     :pass (lambda (null) (fetch-password
457                                                           :login "emacs"
458                                                           :machine "irc.armaanb.net"
459                                                           :port 6698)))
460                                    ("oftc"
461                                     :host "irc.armaanb.net"
462                                     :nick "emacs"
463                                     :user "emacs"
464                                     :use-tls t
465                                     :port 6699
466                                     :pass (lambda (null) (fetch-password
467                                                           :login "emacs"
468                                                           :machine "irc.armaanb.net"
469                                                           :port 6699)))
470                                    ("tilde"
471                                     :host "irc.armaanb.net"
472                                     :nick "emacs"
473                                     :user "emacs"
474                                     :use-tls t
475                                     :port 6696
476                                     :pass (lambda (null) (fetch-password
477                                                           :login "emacs"
478                                                           :machine "irc.armaanb.net"
479                                                           :port 6696)))))
480     :custom (circe-default-part-message "goodbye!")
481     :bind (:map circe-mode-map ("C-c C-r" . circe-reconnect-all)))
482
483   (defun acheam-irc ()
484     "Open circe"
485     (interactive)
486     (if (get-buffer "irc.armaanb.net:6696")
487         (switch-to-buffer "irc.armaanb.net:6696")
488       (progn (switch-to-buffer "*scratch*")
489              (circe "libera")
490              (circe "oftc")
491              (circe "tilde"))))
492
493   (global-set-key (kbd "C-c i") 'acheam-irc)
494 #+end_src
495 ** Calendar
496 Still experimenting with this setup. Not sure if I will keep it, but it works well for seeing my calendar events. I use =vdirsyncer= to sync my calendar events which I'm really not happy with.
497 #+begin_src emacs-lisp
498   (defun sync-calendar ()
499     "Sync calendars with vdirsyncer"
500     (interactive)
501     (async-shell-command "vdirsyncer sync"))
502
503   (use-package calfw
504     :bind (:map cfw:calendar-mode-map ("C-S-u" . sync-calendar)))
505   (use-package calfw-ical)
506   (use-package calfw-org)
507
508   (defun acheam-calendar ()
509     "Open calendars"
510     (interactive)
511     (cfw:open-calendar-buffer
512      :contents-sources (list
513                         (cfw:org-create-source "Green")
514                         (cfw:ical-create-source
515                          "Personal"
516                          "~/.local/share/vdirsyncer/mailbox/Y2FsOi8vMC8zMQ.ics"
517                          "Gray")
518                         (cfw:ical-create-source
519                          "Personal"
520                          "~/.local/share/vdirsyncer/mailbox/Y2FsOi8vMC8zMQ.ics"
521                          "Red")
522                         (cfw:ical-create-source
523                          "School"
524                          "~/.local/share/vdirsyncer/school/abhojwani22@nobles.edu.ics"
525                          "Cyan"))
526      :view 'week))
527
528   (global-set-key (kbd "C-c c") 'acheam-calendar)
529 #+end_src
530 ** PDF reader
531 #+begin_src emacs-lisp
532   (use-package pdf-tools
533     :hook (pdf-view-mode . pdf-view-midnight-minor-mode))
534 #+end_src
535 * Emacs IDE
536 ** Python formatting
537 #+begin_src emacs-lisp
538   (use-package blacken
539     :hook (python-mode . blacken-mode)
540     :custom (blacken-line-length 79))
541
542 #+end_src
543 ** Strip trailing whitespace
544 #+begin_src emacs-lisp
545   (use-package ws-butler
546     :config (ws-butler-global-mode))
547 #+end_src
548 ** Flycheck
549 Automatic linting. I need to look into configuring this more.
550 #+begin_src emacs-lisp
551   (use-package flycheck
552     :config (global-flycheck-mode))
553 #+end_src
554 ** Project management
555 I never use this, but apparently its very powerful. Another item on my todo list.
556 #+begin_src emacs-lisp
557   (use-package projectile
558     :config (projectile-mode)
559     :custom ((projectile-completion-system 'ivy))
560     :bind-keymap ("C-c p" . projectile-command-map)
561     :init (setq projectile-switch-project-action #'projectile-dired))
562
563   (use-package counsel-projectile
564     :after projectile
565     :config (counsel-projectile-mode))
566 #+end_src
567 ** Dired
568 The best file manager!
569 #+begin_src emacs-lisp
570   (use-package dired
571     :straight (:type built-in)
572     :commands (dired dired-jump)
573     :custom ((dired-listing-switches "-agho --group-directories-first"))
574     :config (evil-collection-define-key 'normal 'dired-mode-map
575               "h" 'dired-single-up-directory
576               "l" 'dired-single-buffer))
577
578   (use-package dired-single
579     :commands (dired dired-jump))
580
581   (use-package dired-open
582     :commands (dired dired-jump)
583     :custom (dired-open-extensions '(("png" . "feh")
584                                      ("mkv" . "mpv"))))
585
586   (use-package dired-hide-dotfiles
587     :hook (dired-mode . dired-hide-dotfiles-mode)
588     :config
589     (evil-collection-define-key 'normal 'dired-mode-map
590       "H" 'dired-hide-dotfiles-mode))
591 #+end_src
592 ** Git
593 *** Magit
594 A very good Git interface.
595 #+begin_src emacs-lisp
596   (use-package magit)
597 #+end_src
598 *** Email
599 #+begin_src emacs-lisp
600   (use-package piem)
601   (use-package git-email
602     :straight (git-email :repo "https://git.sr.ht/~yoctocell/git-email")
603     :config (git-email-piem-mode))
604 #+end_src
605 ** C
606 Modified from https://eklitzke.org/smarter-emacs-clang-format.
607
608 Style is basically ddevault's style guide but with 4 spaces instead of 8 char tabs.
609 #+begin_src emacs-lisp
610   (use-package clang-format
611     :custom (clang-format-style "{
612         BasedOnStyle: llvm,
613         AlwaysBreakAfterReturnType: AllDefinitions,
614         IndentWidth: 4,
615         }"))
616
617   (defun clang-format-buffer-smart ()
618     "Reformat buffer if .clang-format exists in the projectile root."
619     (when (file-exists-p (expand-file-name ".clang-format" (projectile-project-root)))
620       (when (if (eq major-mode 'c-mode))
621         (message "Formatting with clang-format...")
622         (clang-format-buffer))))
623
624   (add-hook 'before-save-hook 'clang-format-buffer-smart nil)
625 #+end_src
626 * General text editing
627 ** Spell checking
628 Spell check in text mode, and in prog-mode comments.
629 #+begin_src emacs-lisp
630   (dolist (hook '(text-mode-hook
631                   markdown-mode-hook
632                   scdoc-mode-hook))
633     (add-hook hook (lambda () (flyspell-mode))))
634   (dolist (hook '(change-log-mode-hook log-edit-mode-hook))
635     (add-hook hook (lambda () (flyspell-mode -1))))
636   (add-hook 'prog-mode (lambda () (flyspell-prog mode)))
637   (setq ispell-silently-savep t)
638 #+end_src
639 ** Sane tab width
640 #+begin_src emacs-lisp
641   (setq-default tab-width 2)
642 #+end_src
643 ** Save place
644 Opens file where you left it.
645 #+begin_src emacs-lisp
646   (save-place-mode)
647 #+end_src
648 ** Writing mode
649 Distraction free writing a la junegunn/goyo.
650 #+begin_src emacs-lisp
651   (use-package olivetti
652     :bind ("C-c o" . olivetti-mode))
653 #+end_src
654 ** Abbreviations
655 Abbreviate things! I just use this for things like my email address and copyright notice.
656 #+begin_src emacs-lisp
657   (setq abbrev-file-name "~/.emacs.d/abbrevs.el")
658   (setq save-abbrevs 'silent)
659   (setq-default abbrev-mode t)
660 #+end_src
661 ** TRAMP
662 #+begin_src emacs-lisp
663   (setq tramp-default-method "ssh")
664 #+end_src
665 ** Follow version controlled symlinks
666 #+begin_src emacs-lisp
667   (setq vc-follow-symlinks t)
668 #+end_src
669 ** Open file as root
670 #+begin_src emacs-lisp
671   (defun doas-edit (&optional arg)
672     "Edit currently visited file as root.
673
674     With a prefix ARG prompt for a file to visit.
675     Will also prompt for a file to visit if current
676     buffer is not visiting a file.
677
678     Modified from Emacs Redux."
679     (interactive "P")
680     (if (or arg (not buffer-file-name))
681         (find-file (concat "/doas:root@localhost:"
682                            (ido-read-file-name "Find file(as root): ")))
683       (find-alternate-file (concat "/doas:root@localhost:" buffer-file-name))))
684
685     (global-set-key (kbd "C-x C-r") #'doas-edit)
686 #+end_src
687 ** Markdown mode
688 #+begin_src emacs-lisp
689   (use-package markdown-mode)
690 #+end_src
691 ** scdoc mode
692 Get it for yourself at https://git.armaanb.net/scdoc
693 #+begin_src emacs-lisp
694   (add-to-list 'load-path "~/src/scdoc-mode")
695   (autoload 'scdoc-mode "scdoc-mode" "Major mode for editing scdoc files" t)
696   (add-to-list 'auto-mode-alist '("\\.scd\\'" . scdoc-mode))
697 #+end_src
698 * Keybindings
699 ** Switch windows
700 #+begin_src emacs-lisp
701   (use-package ace-window
702     :bind ("M-o" . ace-window))
703 #+end_src
704 ** Kill current buffer
705 Makes "C-x k" binding faster.
706 #+begin_src emacs-lisp
707   (substitute-key-definition 'kill-buffer 'kill-buffer-and-window global-map)
708 #+end_src
709 * Other settings
710 ** OpenSCAD syntax
711 #+begin_src emacs-lisp
712   (use-package scad-mode)
713 #+end_src
714 ** Control backup and lock files
715 Stop backup files from spewing everywhere.
716 #+begin_src emacs-lisp
717   (setq backup-directory-alist `(("." . "~/.emacs.d/backups"))
718         create-lockfiles nil)
719 #+end_src
720 ** Make yes/no easier
721 #+begin_src emacs-lisp
722   (defalias 'yes-or-no-p 'y-or-n-p)
723 #+end_src
724 ** Move customize file
725 No more clogging up init.el.
726 #+begin_src emacs-lisp
727   (setq custom-file "~/.emacs.d/custom.el")
728   (load custom-file)
729 #+end_src
730 ** Better help
731 #+begin_src emacs-lisp
732   (use-package helpful
733     :commands (helpful-callable helpful-variable helpful-command helpful-key)
734     :custom
735     (counsel-describe-function-function #'helpful-callable)
736     (counsel-describe-variable-function #'helpful-variable)
737     :bind
738     ([remap describe-function] . counsel-describe-function)
739     ([remap describe-command] . helpful-command)
740     ([remap describe-variable] . counsel-describe-variable)
741     ([remap describe-key] . helpful-key))
742 #+end_src
743 ** GPG
744 #+begin_src emacs-lisp
745   (use-package epa-file
746     :straight (:type built-in)
747     :custom
748     (epa-file-select-keys nil)
749     (epa-file-encrypt-to '("me@armaanb.net"))
750     (password-cache-expiry (* 60 15)))
751
752   (use-package pinentry
753     :config (pinentry-start))
754 #+end_src
755 ** Pastebin
756 #+begin_src emacs-lisp
757   (use-package 0x0
758     :straight (0x0 :type git :repo "https://git.sr.ht/~zge/nullpointer-emacs")
759     :custom (0x0-default-service 'envs))
760 #+end_src
761 *** TODO Replace this with uploading to my own server
762 Similar to the ufile alias in my ashrc
763 ** Automatically clean buffers
764 Automatically close unused buffers (except those of Circe) at midnight.
765 #+begin_src emacs-lisp
766   (midnight-mode)
767   (add-to-list 'clean-buffer-list-kill-never-regexps (lambda (buffer-name)
768                                                        (with-current-buffer buffer-name
769                                                          (derived-mode-p 'lui-mode))))
770 #+end_src
771 * Tangles
772 ** Spectrwm
773 Spectrwm is a really awesome window manager! Would highly recommend.
774 *** General settings
775 #+begin_src conf :tangle ~/.spectrwm.conf
776   workspace_limit = 5
777   warp_pointer = 1
778   modkey = Mod4
779   autorun = ws[1]:/home/armaa/src/bin/autostart
780 #+end_src
781 *** Bar
782 Disable the bar by default (it can still be brought back up with MOD+b). The font just needs to be set to something that you have installed, otherwise spectrwm won't launch.
783 #+begin_src conf :tangle ~/.spectrwm.conf
784   bar_enabled = 0
785   bar_font = xos4 JetBrains Mono:pixelsize=14:antialias=true # any installed font
786 #+end_src
787 *** Keybindings
788 I'm not a huge fan of how spectrwm handles keybindings, probably my biggest gripe with it.
789 **** WM actions
790 #+begin_src conf :tangle ~/.spectrwm.conf
791   program[term] = st -e tmux
792   program[notif] = /home/armaa/src/bin/setter status
793   program[pass] = /home/armaa/src/bin/passmenu
794   program[lock] = slock
795
796   bind[notif] = MOD+n
797   bind[pass] = MOD+Shift+p
798 #+end_src
799 **** Media keys
800 #+begin_src conf :tangle ~/.spectrwm.conf
801   program[paup] = /home/armaa/src/bin/setter audio +5
802   program[padown] = /home/armaa/src/bin/setter audio -5
803   program[pamute] = /home/armaa/src/bin/setter audio
804   program[brigup] = /home/armaa/src/bin/setter brightness +10%
805   program[brigdown] = /home/armaa/src/bin/setter brightness 10%-
806
807   bind[padown] = XF86AudioLowerVolume
808   bind[paup] = XF86AudioRaiseVolume
809   bind[pamute] = XF86AudioMute
810   bind[brigdown] = XF86MonBrightnessDown
811   bind[brigup] = XF86MonBrightnessUp
812 #+end_src
813 **** HJKL
814 #+begin_src conf :tangle ~/.spectrwm.conf
815   program[h] = xdotool keyup h key --clearmodifiers Left
816   program[j] = xdotool keyup j key --clearmodifiers Down
817   program[k] = xdotool keyup k key --clearmodifiers Up
818   program[l] = xdotool keyup l key --clearmodifiers Right
819
820   bind[h] = MOD + Control + h
821   bind[j] = MOD + Control + j
822   bind[k] = MOD + Control + k
823   bind[l] = MOD + Control + l
824 #+end_src
825 **** Programs
826 #+begin_src conf :tangle ~/.spectrwm.conf
827   program[email] = emacsclient -ce '(progn (switch-to-buffer "*scratch*") (mu4e))'
828   program[irc] = emacsclient -ce '(acheam-irc)'
829   program[rss] = emacsclient -ce '(elfeed)'
830   program[calendar] = emacsclient -ce '(acheam-calendar)'
831   program[calc] = emacsclient -ce '(progn (calc) (windmove-up) (delete-window))'
832   program[emacs] = emacsclient -c
833   program[bookmarks] = /home/armaa/src/bin/bookmarks
834   program[browser] = chorizo
835
836   bind[email] = MOD+Control+1
837   bind[irc] = MOD+Control+2
838   bind[rss] = MOD+Control+3
839   bind[calendar] = MOD+Control+4
840   bind[calc] = MOD+Control+5
841   bind[emacs] = MOD+Control+Return
842   bind[bookmarks] = MOD+Control+o
843   bind[browser] = MOD+Control+p
844 #+end_src
845 *** Quirks
846 Float some specific programs by default.
847 #+begin_src conf :tangle ~/.spectrwm.conf
848   quirk[Castle Menu] = FLOAT
849   quirk[momen] = FLOAT
850   quirk[pinentry-fltk] = FLOAT
851 #+end_src
852 ** Ash
853 *** Options
854 Use the vi editing mode. I still haven't found a good way to show visual feedback of the current mode. Ideally the cursor would change to a beam when in insert mode, and a box when in normal mode.
855 #+begin_src conf :tangle ~/.config/ash/ashrc
856   set -o vi
857 #+end_src
858 *** Functions
859 **** Finger
860 #+begin_src shell :tangle ~/.config/ash/ashrc
861   finger() {
862       user=$(echo "$1" | cut -f 1 -d '@')
863       host=$(echo "$1" | cut -f 2 -d '@')
864       echo $user | nc "$host" 79
865   }
866 #+end_src
867 **** Upload to ftp.armaanb.net
868 #+begin_src shell :tangle ~/.config/ash/ashrc
869   _uprint() {
870       echo "https://l.armaanb.net/$(basename "$1")" | tee /dev/tty | xclip -sel c
871   }
872
873   _uup() {
874       rsync "$1" "armaa@armaanb.net:/srv/ftp/pub/$2" --chmod 644 --progress
875   }
876
877   ufile() {
878       _uup "$1" "$2"
879       _uprint "$1"
880   }
881
882   uclip() {
883       tmp=$(mktemp)
884       xclip -o -sel c >> "$tmp"
885       basetmp=$(echo "$tmp" | tail -c +5)
886       _uup "$tmp" "$basetmp"
887       _uprint "$basetmp"
888       rm -f "$tmp"
889   }
890 #+end_src
891 *** Exports
892 #+begin_src shell :tangle ~/.config/ash/ashrc
893   export EDITOR="emacsclient -c"
894   export VISUAL="$EDITOR"
895   export TERM=xterm-256color # for compatability
896
897   export GPG_TTY="$(tty)"
898   export MANPAGER='nvim +Man!'
899   export PAGER='less'
900   export GTK_USE_PORTAL=1
901   export CDPATH=:~
902
903   export PATH="/home/armaa/.local/bin:$PATH" # prioritize .local/bin
904   export PATH="/home/armaa/src/bin:$PATH" # prioritize my bin
905   export PATH="//home/armaa/src/bin/bin:$PATH" # prioritize my bins
906   export PATH="$PATH:/usr/sbin"
907
908   export LC_ALL="en_US.UTF-8"
909   export LC_CTYPE="en_US.UTF-8"
910   export LANGUAGE="en_US.UTF-8"
911   export TZ="America/New_York"
912
913   export KISS_PATH=""
914   export KISS_PATH="$KISS_PATH:$HOME/repos/personal"
915   export KISS_PATH="$KISS_PATH:$HOME/repos/bin/bin"
916   export KISS_PATH="$KISS_PATH:$HOME/repos/main/core"
917   export KISS_PATH="$KISS_PATH:$HOME/repos/main/extra"
918   export KISS_PATH="$KISS_PATH:$HOME/repos/main/xorg"
919   export KISS_PATH="$KISS_PATH:$HOME/repos/community/community"
920   export KISS_PATH="$KISS_PATH:$HOME/repos/mid/ports"
921
922   export CFLAGS="-O3 -pipe -march=native"
923   export CXXFLAGS="$CFLAGS"
924   export MAKEFLAGS="-j$(nproc)"
925   export PKG_CONFIG_PATH="$PKG_CONFIG_PATH:/usr/local/lib/pkgconfig"
926
927   export XDG_DESKTOP_DIR="/dev/null"
928   export XDG_DOCUMENTS_DIR="$HOME/documents"
929   export XDG_DOWNLOAD_DIR="$HOME/downloads"
930   export XDG_MUSIC_DIR="$HOME/music"
931   export XDG_PICTURES_DIR="$HOME/pictures"
932   export XDG_VIDEOS_DIR="$HOME/videos"
933 #+end_src
934 *** Aliases
935 **** SSH
936 #+begin_src shell :tangle ~/.config/ash/ashrc
937   alias poki='ssh armaanb.net'
938   alias irc='ssh root@armaanb.net -t abduco -A irc catgirl freenode'
939   alias union='ssh 192.168.1.18'
940   alias mine='ssh -p 23 root@pickupserver.cc'
941   alias tcf='ssh root@204.48.23.68'
942   alias ngmun='ssh root@157.245.89.25'
943   alias prox='ssh root@192.168.1.224'
944   alias ncq='ssh root@143.198.123.17'
945   alias envs='ssh acheam@envs.net'
946 #+end_src
947 **** File management
948 #+begin_src shell :tangle ~/.config/ash/ashrc
949   alias ls='LC_COLLATE=C ls -lh --group-directories-first'
950   alias la='ls -A'
951   alias df='df -h / /boot'
952   alias du='du -h'
953   alias free='free -m'
954   alias cp='cp -riv'
955   alias rm='rm -iv'
956   alias mv='mv -iv'
957   alias ln='ln -v'
958   alias grep='grep -in'
959   alias mkdir='mkdir -pv'
960   alias lanex='java -jar ~/.local/share/lxc/lanxchange.jar && rm lxc*'
961   emacs() { $EDITOR "$@" & }
962   alias vim="emacs"
963 #+end_src
964 **** System management
965 #+begin_src shell :tangle ~/.config/ash/ashrc
966   alias crontab='crontab-argh'
967   alias sudo='doas'
968   alias pasu='git -C ~/.password-store push'
969   alias yadu='yadm add -u && yadm commit -m "Updated `date -Iseconds`" && \
970     yadm push'
971 #+end_src
972 **** Networking
973 #+begin_src shell :tangle ~/.config/ash/ashrc
974   alias ping='ping -c 10'
975   alias gps='gpg --keyserver keyserver.ubuntu.com --search-keys'
976   alias gpp='gpg --keyserver keyserver.ubuntu.com --recv-key'
977   alias plan='T=$(mktemp) && \
978           rsync armaanb.net:/home/armaa/plan.txt "$T" && \
979           TT=$(mktemp) && \
980           head -n -2 $T > $TT && \
981           /bin/nvim $TT && \
982           echo >> "$TT" && \
983           echo "Last updated: $(date -R)" >> "$TT" && \
984           fold -sw 72 "$TT" > "$T"| \
985           rsync "$T" armaanb.net:/home/armaa/plan.txt && \
986           rm -f "$T"'
987 #+end_src
988 **** Virtual machines, chroots
989 #+begin_src shell :tangle ~/.config/ash/ashrc
990   alias ckiss="doas chrooter ~/Virtual/kiss"
991   alias cdebian="doas chrooter ~/Virtual/debian bash"
992   alias cwindows='devour qemu-system-x86_64 \
993     -smp 3 \
994     -cpu host \
995     -enable-kvm \
996     -m 3G \
997     -device VGA,vgamem_mb=64 \
998     -device intel-hda \
999     -device hda-duplex \
1000     -net nic \
1001     -net user,smb=/home/armaa/Public \
1002     -drive format=qcow2,file=/home/armaa/Virtual/windows.qcow2'
1003 #+end_src
1004 **** Latin
1005 #+begin_src shell :tangle ~/.config/ash/ashrc
1006   alias words='gen-shell -c "words"'
1007   alias words-e='gen-shell -c "words ~E"'
1008 #+end_src
1009 **** Other
1010 #+begin_src shell :tangle ~/.config/ash/ashrc
1011   alias bigrandomfile='dd if=/dev/urandom of=1GB-urandom bs=1M count=1024 \
1012     iflag=fullblock'
1013   alias bigboringfile='dd if=/dev/zero of=1GB-zero bs=1M count=1024 \
1014     iflag=fullblock'
1015   alias ytmusic="youtube-dl -x --add-metadata  --audio-format aac \
1016     --restrict-filenames -o '%(title)s.%(ext)s'"
1017   alias bc='bc -l'
1018 #+end_src
1019 ** MPV
1020 Make MPV play a little bit smoother.
1021 #+begin_src conf :tangle ~/.config/mpv/mpv.conf
1022   ytdl-format="bestvideo[height<=?1080]+bestaudio/best"
1023   hwdec=auto-copy
1024 #+end_src
1025 ** Inputrc
1026 This file is used for any GNU Readline programs. I use Emacs editing mode mostly because of one annoyance which is that to clear the screen using ^L, you have to be in normal mode which is a pain. If there is a way to rebind this, I'd love to know!.
1027 #+begin_src conf :tangle ~/.inputrc
1028   set editing-mode emacs
1029 #+end_src
1030 ** Git
1031 *** User
1032 #+begin_src conf :tangle ~/.gitconfig
1033   [user]
1034   name = Armaan Bhojwani
1035   email = me@armaanb.net
1036   signingkey = 0FEB9471E19C49C60CFBEB133C9ED82FFE788E4A
1037 #+end_src
1038 *** Init
1039 #+begin_src conf :tangle ~/.gitconfig
1040   [init]
1041   defaultBranch = main
1042 #+end_src
1043 *** GPG
1044 #+begin_src conf :tangle ~/.gitconfig
1045   [gpg]
1046   program = gpg
1047 #+end_src
1048 *** Sendemail
1049 #+begin_src conf :tangle ~/.gitconfig
1050   [sendemail]
1051   smtpserver = smtp.mailbox.org
1052   smtpuser = me@armaanb.net
1053   smtpencryption = ssl
1054   smtpserverport = 465
1055   confirm = auto
1056 #+end_src
1057 *** Submodule
1058 #+begin_src conf :tangle ~/.gitconfig
1059   [submodule]
1060   recurse = true
1061 #+end_src
1062 *** Aliases
1063 #+begin_src conf :tangle ~/.gitconfig
1064   [alias]
1065   stat = diff --stat
1066   sclone = clone --depth 1
1067   sclean = clean -dfX
1068   a = add
1069   aa = add .
1070   c = commit
1071   quickfix = commit . --amend --no-edit
1072   p = push
1073   subup = submodule update --remote
1074   loc = diff --stat 4b825dc642cb6eb9a060e54bf8d69288fbee4904 # Empty hash
1075   pushnc = push -o skip-ci
1076 #+end_src
1077 *** Commit
1078 #+begin_src conf :tangle ~/.gitconfig
1079   [commit]
1080   gpgsign = true
1081   verbose = true
1082 #+end_src
1083 *** Tag
1084 #+begin_src conf :tangle ~/.gitconfig
1085   [tag]
1086   gpgsign = true
1087 #+end_src
1088 ** Zathura
1089 The best document reader!
1090 *** Options
1091 #+begin_src conf :tangle ~/.config/zathura/zathurarc
1092   map <C-i> recolor
1093   map <A-b> toggle_statusbar
1094   set selection-clipboard clipboard
1095   set scroll-step 200
1096
1097   set window-title-basename "true"
1098   set selection-clipboard "clipboard"
1099 #+end_src
1100 *** Colors
1101 #+begin_src conf :tangle ~/.config/zathura/zathurarc
1102   set default-bg         "#000000"
1103   set default-fg         "#ffffff"
1104   set render-loading     true
1105   set render-loading-bg  "#000000"
1106   set render-loading-fg  "#ffffff"
1107
1108   set recolor-lightcolor "#000000" # bg
1109   set recolor-darkcolor  "#ffffff" # fg
1110   set recolor            "true"
1111 #+end_src
1112 ** Xresources
1113 Modus operandi theme. No program I use checks for anything beyond foreground and background, but hey, it can't hurt to have all the colors in there.
1114 #+begin_src conf :tangle ~/.Xresources
1115   ! special
1116   ,*.foreground:   #ffffff
1117   ,*.background:   #000000
1118   ,*.cursorColor:  #ffffff
1119
1120   ! black
1121   ,*.color0:       #000000
1122   ,*.color8:       #555555
1123
1124   ! red
1125   ,*.color1:       #ff8059
1126   ,*.color9:       #ffa0a0
1127
1128   ! green
1129   ,*.color2:       #00fc50
1130   ,*.color10:      #88cf88
1131
1132   ! yellow
1133   ,*.color3:       #eecc00
1134   ,*.color11:      #d2b580
1135
1136   ! blue
1137   ,*.color4:       #29aeff
1138   ,*.color12:      #92baff
1139
1140   ! magenta
1141   ,*.color5:       #feacd0
1142   ,*.color13:      #e0b2d6
1143
1144   ! cyan
1145   ,*.color6:       #00d3d0
1146   ,*.color14:      #a0bfdf
1147
1148   ! white
1149   ,*.color7:       #eeeeee
1150   ,*.color15:      #dddddd
1151 #+end_src
1152 ** Tmux
1153 I use tmux in order to keep my st build light. Still learning how it works.
1154 #+begin_src conf :tangle ~/.tmux.conf
1155   set -g status off
1156   set -g mouse on
1157   set-option -g history-limit 50000
1158   set-window-option -g mode-keys vi
1159   bind-key -T copy-mode-vi 'v' send -X begin-selection
1160   bind -T copy-mode-vi y send-keys -X copy-pipe-and-cancel 'xclip -in -selection clipboard'
1161 #+end_src
1162 ** GPG
1163 *** Config
1164 #+begin_src conf :tangle ~/.gnupg/gpg.conf
1165   default-key 3C9ED82FFE788E4A
1166   use-agent
1167 #+end_src
1168 *** Agent
1169 #+begin_src conf :tangle ~/.gnupg/gpg-agent.conf
1170   pinentry-program /sbin/pinentry
1171   max-cache-ttl 600
1172   default-cache-ttl 600
1173   allow-emacs-pinentry
1174 #+end_src
1175 ** Xmodmap
1176 #+begin_src conf (if (eq system-name "frost.armaanb.net") ":tangle ~/.config/xmodmap")
1177   ! Unmap left super
1178   clear mod4
1179
1180   ! Turn right alt into super
1181   remove mod1 = Alt_R
1182   add mod4 = Alt_R
1183
1184   ! Swap caps and control
1185   remove Lock = Caps_Lock
1186   remove Control = Control_L
1187   remove Lock = Control_L
1188   remove Control = Caps_Lock
1189   keysym Control_L = Caps_Lock
1190   keysym Caps_Lock = Control_L
1191   add Lock = Caps_Lock
1192   add Control = Control_L
1193 #+end_src