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