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