]> git.armaanb.net Git - config.org.git/blob - config.org
spectrwm: add browser and bookmarks keybinding
[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
561     ("C-c p" . projectile-command-map)
562     :init
563     (when (file-directory-p "~/src")
564       (setq projectile-project-search-path '("~/src")))
565     (setq projectile-switch-project-action #'projectile-dired))
566
567   (use-package counsel-projectile
568     :after projectile
569     :config (counsel-projectile-mode))
570 #+end_src
571 ** Dired
572 The best file manager!
573 #+begin_src emacs-lisp
574   (use-package dired
575     :straight (:type built-in)
576     :commands (dired dired-jump)
577     :custom ((dired-listing-switches "-agho --group-directories-first"))
578     :config (evil-collection-define-key 'normal 'dired-mode-map
579               "h" 'dired-single-up-directory
580               "l" 'dired-single-buffer))
581
582   (use-package dired-single
583     :commands (dired dired-jump))
584
585   (use-package dired-open
586     :commands (dired dired-jump)
587     :custom (dired-open-extensions '(("png" . "feh")
588                                      ("mkv" . "mpv"))))
589
590   (use-package dired-hide-dotfiles
591     :hook (dired-mode . dired-hide-dotfiles-mode)
592     :config
593     (evil-collection-define-key 'normal 'dired-mode-map
594       "H" 'dired-hide-dotfiles-mode))
595 #+end_src
596 ** Git
597 *** Magit
598 A very good Git interface.
599 #+begin_src emacs-lisp
600   (use-package magit)
601 #+end_src
602 *** Email
603 #+begin_src emacs-lisp
604   (use-package piem)
605   (use-package git-email
606     :straight (git-email :repo "https://git.sr.ht/~yoctocell/git-email")
607     :config (git-email-piem-mode))
608 #+end_src
609 * General text editing
610 ** Indentation
611 Automatically indent after every change. I'm not sure how much I like this. It slows down the editor and code sometimes ends up in a half-indented state meaning I have to manually reformat using "==" anyways.
612 #+begin_src emacs-lisp
613   (use-package aggressive-indent
614     :config (global-aggressive-indent-mode))
615 #+end_src
616 ** Spell checking
617 Spell check in text mode, and in prog-mode comments.
618 #+begin_src emacs-lisp
619   (dolist (hook '(text-mode-hook
620                   markdown-mode-hook
621                   scdoc-mode-hook))
622     (add-hook hook (lambda () (flyspell-mode))))
623   (dolist (hook '(change-log-mode-hook log-edit-mode-hook))
624     (add-hook hook (lambda () (flyspell-mode -1))))
625   (add-hook 'prog-mode (lambda () (flyspell-prog mode)))
626   (setq ispell-silently-savep t)
627 #+end_src
628 ** Sane tab width
629 #+begin_src emacs-lisp
630   (setq-default tab-width 2)
631 #+end_src
632 ** Save place
633 Opens file where you left it.
634 #+begin_src emacs-lisp
635   (save-place-mode)
636 #+end_src
637 ** Writing mode
638 Distraction free writing a la junegunn/goyo.
639 #+begin_src emacs-lisp
640   (use-package olivetti
641     :bind ("C-c o" . olivetti-mode))
642 #+end_src
643 ** Abbreviations
644 Abbreviate things! I just use this for things like my email address and copyright notice.
645 #+begin_src emacs-lisp
646   (setq abbrev-file-name "~/.emacs.d/abbrevs.el")
647   (setq save-abbrevs 'silent)
648   (setq-default abbrev-mode t)
649 #+end_src
650 ** TRAMP
651 #+begin_src emacs-lisp
652   (setq tramp-default-method "ssh")
653 #+end_src
654 ** Follow version controlled symlinks
655 #+begin_src emacs-lisp
656   (setq vc-follow-symlinks t)
657 #+end_src
658 ** Open file as root
659 #+begin_src emacs-lisp
660   (defun doas-edit (&optional arg)
661     "Edit currently visited file as root.
662
663     With a prefix ARG prompt for a file to visit.
664     Will also prompt for a file to visit if current
665     buffer is not visiting a file.
666
667     Modified from Emacs Redux."
668     (interactive "P")
669     (if (or arg (not buffer-file-name))
670         (find-file (concat "/doas:root@localhost:"
671                            (ido-read-file-name "Find file(as root): ")))
672       (find-alternate-file (concat "/doas:root@localhost:" buffer-file-name))))
673
674     (global-set-key (kbd "C-x C-r") #'doas-edit)
675 #+end_src
676 ** Markdown mode
677 #+begin_src emacs-lisp
678   (use-package markdown-mode)
679 #+end_src
680 ** scdoc mode
681 Get it for yourself at https://git.armaanb.net/scdoc
682 #+begin_src emacs-lisp
683   (add-to-list 'load-path "~/src/scdoc-mode")
684   (autoload 'scdoc-mode "scdoc-mode" "Major mode for editing scdoc files" t)
685   (add-to-list 'auto-mode-alist '("\\.scd\\'" . scdoc-mode))
686 #+end_src
687 * Keybindings
688 ** Switch windows
689 #+begin_src emacs-lisp
690   (use-package ace-window
691     :bind ("M-o" . ace-window))
692 #+end_src
693 ** Kill current buffer
694 Makes "C-x k" binding faster.
695 #+begin_src emacs-lisp
696   (substitute-key-definition 'kill-buffer 'kill-buffer-and-window global-map)
697 #+end_src
698 * Other settings
699 ** OpenSCAD syntax
700 #+begin_src emacs-lisp
701   (use-package scad-mode)
702 #+end_src
703 ** Control backup and lock files
704 Stop backup files from spewing everywhere.
705 #+begin_src emacs-lisp
706   (setq backup-directory-alist `(("." . "~/.emacs.d/backups"))
707         create-lockfiles nil)
708 #+end_src
709 ** Make yes/no easier
710 #+begin_src emacs-lisp
711   (defalias 'yes-or-no-p 'y-or-n-p)
712 #+end_src
713 ** Move customize file
714 No more clogging up init.el.
715 #+begin_src emacs-lisp
716   (setq custom-file "~/.emacs.d/custom.el")
717   (load custom-file)
718 #+end_src
719 ** Better help
720 #+begin_src emacs-lisp
721   (use-package helpful
722     :commands (helpful-callable helpful-variable helpful-command helpful-key)
723     :custom
724     (counsel-describe-function-function #'helpful-callable)
725     (counsel-describe-variable-function #'helpful-variable)
726     :bind
727     ([remap describe-function] . counsel-describe-function)
728     ([remap describe-command] . helpful-command)
729     ([remap describe-variable] . counsel-describe-variable)
730     ([remap describe-key] . helpful-key))
731 #+end_src
732 ** GPG
733 #+begin_src emacs-lisp
734   (use-package epa-file
735     :straight (:type built-in)
736     :custom
737     (epa-file-select-keys nil)
738     (epa-file-encrypt-to '("me@armaanb.net"))
739     (password-cache-expiry (* 60 15)))
740
741   (use-package pinentry
742     :config (pinentry-start))
743 #+end_src
744 ** Pastebin
745 #+begin_src emacs-lisp
746   (use-package 0x0
747     :straight (0x0 :type git :repo "https://git.sr.ht/~zge/nullpointer-emacs")
748     :custom (0x0-default-service 'envs))
749 #+end_src
750 *** TODO Replace this with uploading to my own server
751 Similar to the ufile alias in my ashrc
752 ** Automatically clean buffers
753 Automatically close unused buffers (except those of Circe) at midnight.
754 #+begin_src emacs-lisp
755   (midnight-mode)
756   (add-to-list 'clean-buffer-list-kill-never-regexps (lambda (buffer-name)
757                                                        (with-current-buffer buffer-name
758                                                          (derived-mode-p 'lui-mode))))
759 #+end_src
760 * Tangles
761 ** Spectrwm
762 Spectrwm is a really awesome window manager! Would highly recommend.
763 *** General settings
764 #+begin_src conf :tangle ~/.spectrwm.conf
765   workspace_limit = 5
766   warp_pointer = 1
767   modkey = Mod4
768   autorun = ws[1]:/home/armaa/src/bin/autostart
769 #+end_src
770 *** Bar
771 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.
772 #+begin_src conf :tangle ~/.spectrwm.conf
773   bar_enabled = 0
774   bar_font = xos4 JetBrains Mono:pixelsize=14:antialias=true # any installed font
775 #+end_src
776 *** Keybindings
777 I'm not a huge fan of how spectrwm handles keybindings, probably my biggest gripe with it.
778 **** WM actions
779 #+begin_src conf :tangle ~/.spectrwm.conf
780   program[term] = st -e tmux
781   program[notif] = /home/armaa/src/bin/setter status
782   program[pass] = /home/armaa/src/bin/passmenu
783   program[lock] = slock
784
785   bind[notif] = MOD+n
786   bind[pass] = MOD+Shift+p
787 #+end_src
788 **** Media keys
789 #+begin_src conf :tangle ~/.spectrwm.conf
790   program[paup] = /home/armaa/src/bin/setter audio +5
791   program[padown] = /home/armaa/src/bin/setter audio -5
792   program[pamute] = /home/armaa/src/bin/setter audio
793   program[brigup] = /home/armaa/src/bin/setter brightness +10%
794   program[brigdown] = /home/armaa/src/bin/setter brightness 10%-
795
796   bind[padown] = XF86AudioLowerVolume
797   bind[paup] = XF86AudioRaiseVolume
798   bind[pamute] = XF86AudioMute
799   bind[brigdown] = XF86MonBrightnessDown
800   bind[brigup] = XF86MonBrightnessUp
801 #+end_src
802 **** HJKL
803 #+begin_src conf :tangle ~/.spectrwm.conf
804   program[h] = xdotool keyup h key --clearmodifiers Left
805   program[j] = xdotool keyup j key --clearmodifiers Down
806   program[k] = xdotool keyup k key --clearmodifiers Up
807   program[l] = xdotool keyup l key --clearmodifiers Right
808
809   bind[h] = MOD + Control + h
810   bind[j] = MOD + Control + j
811   bind[k] = MOD + Control + k
812   bind[l] = MOD + Control + l
813 #+end_src
814 **** Programs
815 #+begin_src conf :tangle ~/.spectrwm.conf
816   program[email] = emacsclient -ce '(progn (switch-to-buffer "*scratch*") (mu4e))'
817   program[irc] = emacsclient -ce '(acheam-irc)'
818   program[rss] = emacsclient -ce '(elfeed)'
819   program[calendar] = emacsclient -ce '(acheam-calendar)'
820   program[calc] = emacsclient -ce '(progn (calc) (windmove-up) (delete-window))'
821   program[emacs] = emacsclient -c
822   program[bookmarks] = /home/armaa/src/bin/bookmarks
823   program[browser] = chorizo
824
825   bind[email] = MOD+Control+1
826   bind[irc] = MOD+Control+2
827   bind[rss] = MOD+Control+3
828   bind[calendar] = MOD+Control+4
829   bind[calc] = MOD+Control+5
830   bind[emacs] = MOD+Control+Return
831   bind[bookmarks] = MOD+Control+o
832   bind[browser] = MOD+Control+p
833 #+end_src
834 *** Quirks
835 Float some specific programs by default.
836 #+begin_src conf :tangle ~/.spectrwm.conf
837   quirk[Castle Menu] = FLOAT
838   quirk[momen] = FLOAT
839   quirk[pinentry-fltk] = FLOAT
840 #+end_src
841 ** Ash
842 *** Options
843 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.
844 #+begin_src conf :tangle ~/.config/ash/ashrc
845   set -o vi
846 #+end_src
847 *** Functions
848 **** Finger
849 #+begin_src shell :tangle ~/.config/ash/ashrc
850   finger() {
851       user=$(echo "$1" | cut -f 1 -d '@')
852       host=$(echo "$1" | cut -f 2 -d '@')
853       echo $user | nc "$host" 79
854   }
855 #+end_src
856 **** Upload to ftp.armaanb.net
857 #+begin_src shell :tangle ~/.config/ash/ashrc
858   _uprint() {
859       echo "https://l.armaanb.net/$(basename "$1")" | tee /dev/tty | xclip -sel c
860   }
861
862   _uup() {
863       rsync "$1" "armaa@armaanb.net:/srv/ftp/pub/$2" --chmod 644 --progress
864   }
865
866   ufile() {
867       _uup "$1" "$2"
868       _uprint "$1"
869   }
870
871   uclip() {
872       tmp=$(mktemp)
873       xclip -o -sel c >> "$tmp"
874       basetmp=$(echo "$tmp" | tail -c +5)
875       _uup "$tmp" "$basetmp"
876       _uprint "$basetmp"
877       rm -f "$tmp"
878   }
879 #+end_src
880 *** Exports
881 #+begin_src shell :tangle ~/.config/ash/ashrc
882   export EDITOR="emacsclient -c"
883   export VISUAL="$EDITOR"
884   export TERM=xterm-256color # for compatability
885
886   export GPG_TTY="$(tty)"
887   export MANPAGER='nvim +Man!'
888   export PAGER='less'
889   export GTK_USE_PORTAL=1
890   export CDPATH=:~
891
892   export PATH="/home/armaa/.local/bin:$PATH" # prioritize .local/bin
893   export PATH="/home/armaa/src/bin:$PATH" # prioritize my bin
894   export PATH="//home/armaa/src/bin/bin:$PATH" # prioritize my bins
895   export PATH="$PATH:/usr/sbin"
896
897   export LC_ALL="en_US.UTF-8"
898   export LC_CTYPE="en_US.UTF-8"
899   export LANGUAGE="en_US.UTF-8"
900   export TZ="America/New_York"
901
902   export KISS_PATH=""
903   export KISS_PATH="$KISS_PATH:$HOME/repos/personal"
904   export KISS_PATH="$KISS_PATH:$HOME/repos/bin/bin"
905   export KISS_PATH="$KISS_PATH:$HOME/repos/main/core"
906   export KISS_PATH="$KISS_PATH:$HOME/repos/main/extra"
907   export KISS_PATH="$KISS_PATH:$HOME/repos/main/xorg"
908   export KISS_PATH="$KISS_PATH:$HOME/repos/community/community"
909   export KISS_PATH="$KISS_PATH:$HOME/repos/mid/ports"
910
911   export CFLAGS="-O3 -pipe -march=native"
912   export CXXFLAGS="$CFLAGS"
913   export MAKEFLAGS="-j$(nproc)"
914   export PKG_CONFIG_PATH="$PKG_CONFIG_PATH:/usr/local/lib/pkgconfig"
915
916   export XDG_DESKTOP_DIR="/dev/null"
917   export XDG_DOCUMENTS_DIR="$HOME/documents"
918   export XDG_DOWNLOAD_DIR="$HOME/downloads"
919   export XDG_MUSIC_DIR="$HOME/music"
920   export XDG_PICTURES_DIR="$HOME/pictures"
921   export XDG_VIDEOS_DIR="$HOME/videos"
922 #+end_src
923 *** Aliases
924 **** SSH
925 #+begin_src shell :tangle ~/.config/ash/ashrc
926   alias poki='ssh armaanb.net'
927   alias irc='ssh root@armaanb.net -t abduco -A irc catgirl freenode'
928   alias union='ssh 192.168.1.18'
929   alias mine='ssh -p 23 root@pickupserver.cc'
930   alias tcf='ssh root@204.48.23.68'
931   alias ngmun='ssh root@157.245.89.25'
932   alias prox='ssh root@192.168.1.224'
933   alias ncq='ssh root@143.198.123.17'
934   alias envs='ssh acheam@envs.net'
935 #+end_src
936 **** File management
937 #+begin_src shell :tangle ~/.config/ash/ashrc
938   alias ls='LC_COLLATE=C ls -lh --group-directories-first'
939   alias la='ls -A'
940   alias df='df -h / /boot'
941   alias du='du -h'
942   alias free='free -m'
943   alias cp='cp -riv'
944   alias rm='rm -iv'
945   alias mv='mv -iv'
946   alias ln='ln -v'
947   alias grep='grep -in'
948   alias mkdir='mkdir -pv'
949   alias lanex='java -jar ~/.local/share/lxc/lanxchange.jar && rm lxc*'
950   emacs() { $EDITOR "$@" & }
951   alias vim="emacs"
952 #+end_src
953 **** System management
954 #+begin_src shell :tangle ~/.config/ash/ashrc
955   alias crontab='crontab-argh'
956   alias sudo='doas'
957   alias pasu='git -C ~/.password-store push'
958   alias yadu='yadm add -u && yadm commit -m "Updated `date -Iseconds`" && \
959     yadm push'
960 #+end_src
961 **** Networking
962 #+begin_src shell :tangle ~/.config/ash/ashrc
963   alias ping='ping -c 10'
964   alias gps='gpg --keyserver keyserver.ubuntu.com --search-keys'
965   alias gpp='gpg --keyserver keyserver.ubuntu.com --recv-key'
966   alias plan='T=$(mktemp) && \
967           rsync armaanb.net:/home/armaa/plan.txt "$T" && \
968           TT=$(mktemp) && \
969           head -n -2 $T > $TT && \
970           /bin/nvim $TT && \
971           echo >> "$TT" && \
972           echo "Last updated: $(date -R)" >> "$TT" && \
973           fold -sw 72 "$TT" > "$T"| \
974           rsync "$T" armaanb.net:/home/armaa/plan.txt && \
975           rm -f "$T"'
976 #+end_src
977 **** Virtual machines, chroots
978 #+begin_src shell :tangle ~/.config/ash/ashrc
979   alias ckiss="doas chrooter ~/Virtual/kiss"
980   alias cdebian="doas chrooter ~/Virtual/debian bash"
981   alias cwindows='devour qemu-system-x86_64 \
982     -smp 3 \
983     -cpu host \
984     -enable-kvm \
985     -m 3G \
986     -device VGA,vgamem_mb=64 \
987     -device intel-hda \
988     -device hda-duplex \
989     -net nic \
990     -net user,smb=/home/armaa/Public \
991     -drive format=qcow2,file=/home/armaa/Virtual/windows.qcow2'
992 #+end_src
993 **** Latin
994 #+begin_src shell :tangle ~/.config/ash/ashrc
995   alias words='gen-shell -c "words"'
996   alias words-e='gen-shell -c "words ~E"'
997 #+end_src
998 **** Other
999 #+begin_src shell :tangle ~/.config/ash/ashrc
1000   alias bigrandomfile='dd if=/dev/urandom of=1GB-urandom bs=1M count=1024 \
1001     iflag=fullblock'
1002   alias bigboringfile='dd if=/dev/zero of=1GB-zero bs=1M count=1024 \
1003     iflag=fullblock'
1004   alias ytmusic="youtube-dl -x --add-metadata  --audio-format aac \
1005     --restrict-filenames -o '%(title)s.%(ext)s'"
1006   alias bc='bc -l'
1007 #+end_src
1008 ** MPV
1009 Make MPV play a little bit smoother.
1010 #+begin_src conf :tangle ~/.config/mpv/mpv.conf
1011   ytdl-format="bestvideo[height<=?1080]+bestaudio/best"
1012   hwdec=auto-copy
1013 #+end_src
1014 ** Inputrc
1015 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!.
1016 #+begin_src conf :tangle ~/.inputrc
1017   set editing-mode emacs
1018 #+end_src
1019 ** Git
1020 *** User
1021 #+begin_src conf :tangle ~/.gitconfig
1022   [user]
1023   name = Armaan Bhojwani
1024   email = me@armaanb.net
1025   signingkey = 0FEB9471E19C49C60CFBEB133C9ED82FFE788E4A
1026 #+end_src
1027 *** Init
1028 #+begin_src conf :tangle ~/.gitconfig
1029   [init]
1030   defaultBranch = main
1031 #+end_src
1032 *** GPG
1033 #+begin_src conf :tangle ~/.gitconfig
1034   [gpg]
1035   program = gpg
1036 #+end_src
1037 *** Sendemail
1038 #+begin_src conf :tangle ~/.gitconfig
1039   [sendemail]
1040   smtpserver = smtp.mailbox.org
1041   smtpuser = me@armaanb.net
1042   smtpencryption = ssl
1043   smtpserverport = 465
1044   confirm = auto
1045 #+end_src
1046 *** Submodule
1047 #+begin_src conf :tangle ~/.gitconfig
1048   [submodule]
1049   recurse = true
1050 #+end_src
1051 *** Aliases
1052 #+begin_src conf :tangle ~/.gitconfig
1053   [alias]
1054   stat = diff --stat
1055   sclone = clone --depth 1
1056   sclean = clean -dfX
1057   a = add
1058   aa = add .
1059   c = commit
1060   quickfix = commit . --amend --no-edit
1061   p = push
1062   subup = submodule update --remote
1063   loc = diff --stat 4b825dc642cb6eb9a060e54bf8d69288fbee4904 # Empty hash
1064   pushnc = push -o skip-ci
1065 #+end_src
1066 *** Commit
1067 #+begin_src conf :tangle ~/.gitconfig
1068   [commit]
1069   gpgsign = true
1070   verbose = true
1071 #+end_src
1072 *** Tag
1073 #+begin_src conf :tangle ~/.gitconfig
1074   [tag]
1075   gpgsign = true
1076 #+end_src
1077 ** Zathura
1078 The best document reader!
1079 *** Options
1080 #+begin_src conf :tangle ~/.config/zathura/zathurarc
1081   map <C-i> recolor
1082   map <A-b> toggle_statusbar
1083   set selection-clipboard clipboard
1084   set scroll-step 200
1085
1086   set window-title-basename "true"
1087   set selection-clipboard "clipboard"
1088 #+end_src
1089 *** Colors
1090 #+begin_src conf :tangle ~/.config/zathura/zathurarc
1091   set default-bg         "#000000"
1092   set default-fg         "#ffffff"
1093   set render-loading     true
1094   set render-loading-bg  "#000000"
1095   set render-loading-fg  "#ffffff"
1096
1097   set recolor-lightcolor "#000000" # bg
1098   set recolor-darkcolor  "#ffffff" # fg
1099   set recolor            "true"
1100 #+end_src
1101 ** Xresources
1102 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.
1103 #+begin_src conf :tangle ~/.Xresources
1104   ! special
1105   ,*.foreground:   #ffffff
1106   ,*.background:   #000000
1107   ,*.cursorColor:  #ffffff
1108
1109   ! black
1110   ,*.color0:       #000000
1111   ,*.color8:       #555555
1112
1113   ! red
1114   ,*.color1:       #ff8059
1115   ,*.color9:       #ffa0a0
1116
1117   ! green
1118   ,*.color2:       #00fc50
1119   ,*.color10:      #88cf88
1120
1121   ! yellow
1122   ,*.color3:       #eecc00
1123   ,*.color11:      #d2b580
1124
1125   ! blue
1126   ,*.color4:       #29aeff
1127   ,*.color12:      #92baff
1128
1129   ! magenta
1130   ,*.color5:       #feacd0
1131   ,*.color13:      #e0b2d6
1132
1133   ! cyan
1134   ,*.color6:       #00d3d0
1135   ,*.color14:      #a0bfdf
1136
1137   ! white
1138   ,*.color7:       #eeeeee
1139   ,*.color15:      #dddddd
1140 #+end_src
1141 ** Tmux
1142 I use tmux in order to keep my st build light. Still learning how it works.
1143 #+begin_src conf :tangle ~/.tmux.conf
1144   set -g status off
1145   set -g mouse on
1146   set-option -g history-limit 50000
1147   set-window-option -g mode-keys vi
1148   bind-key -T copy-mode-vi 'v' send -X begin-selection
1149   bind -T copy-mode-vi y send-keys -X copy-pipe-and-cancel 'xclip -in -selection clipboard'
1150 #+end_src
1151 ** GPG
1152 *** Config
1153 #+begin_src conf :tangle ~/.gnupg/gpg.conf
1154   default-key 3C9ED82FFE788E4A
1155   use-agent
1156 #+end_src
1157 *** Agent
1158 #+begin_src conf :tangle ~/.gnupg/gpg-agent.conf
1159   pinentry-program /sbin/pinentry
1160   max-cache-ttl 600
1161   default-cache-ttl 600
1162   allow-emacs-pinentry
1163 #+end_src
1164 ** Xmodmap
1165 #+begin_src conf (if (eq system-name "frost.armaanb.net") ":tangle ~/.config/xmodmap")
1166   ! Unmap left super
1167   clear mod4
1168
1169   ! Turn right alt into super
1170   remove mod1 = Alt_R
1171   add mod4 = Alt_R
1172
1173   ! Swap caps and control
1174   remove Lock = Caps_Lock
1175   remove Control = Control_L
1176   remove Lock = Control_L
1177   remove Control = Caps_Lock
1178   keysym Control_L = Caps_Lock
1179   keysym Caps_Lock = Control_L
1180   add Lock = Caps_Lock
1181   add Control = Control_L
1182 #+end_src