** Naming conventions
-The conventions below were inspired by [[https://github.com/hlissner/doom-emacs][Doom]]'s conventions, found
-[[https://github.com/hlissner/doom-emacs/blob/5dacbb7cb1c6ac246a9ccd15e6c4290def67757c/core/core.el#L3-L17][here]]. Naturally, I use my initials, =ab=, instead of =doom=.
+The conventions below were inspired by [[https://github.com/hlissner/doom-emacs][Doom]]'s, found [[https://github.com/hlissner/doom-emacs/blob/5dacbb7cb1c6ac246a9ccd15e6c4290def67757c/core/core.el#L3-L17][here]].
#+begin_src emacs-lisp :comments none
;; Naming conventions:
;;
-;; ab-... public variables or non-interactive functions
-;; ab--... private anything (non-interactive), not safe for direct use
-;; ab/... an interactive function; safe for M-x or keybinding
-;; ab:... an evil operator, motion, or command
-;; ab|... a hook function
-;; ab*... an advising function
-;; ab@... a hydra command
-;; ...! a macro
+;; amin-... public variables or non-interactive functions
+;; amin--... private anything (non-interactive), not safe for direct use
+;; amin/... an interactive function; safe for M-x or keybinding
+;; amin:... an evil operator, motion, or command
+;; amin|... a hook function
+;; amin*... an advising function
+;; amin@... a hydra command
+;; ...! a macro
#+end_src
* Initial setup
=init.el=, i.e. =user-init-file=:
#+begin_src emacs-lisp
-(defvar ab--before-user-init-time (current-time)
+(defvar amin--before-user-init-time (current-time)
"Value of `current-time' when Emacs begins loading `user-init-file'.")
(message "Loading Emacs...done (%.3fs)"
- (float-time (time-subtract ab--before-user-init-time
+ (float-time (time-subtract amin--before-user-init-time
before-init-time)))
#+end_src
startup time as well.
#+begin_src emacs-lisp
-(defvar ab--gc-cons-threshold gc-cons-threshold)
-(defvar ab--gc-cons-percentage gc-cons-percentage)
-(defvar ab--file-name-handler-alist file-name-handler-alist)
+(defvar amin--gc-cons-threshold gc-cons-threshold)
+(defvar amin--gc-cons-percentage gc-cons-percentage)
+(defvar amin--file-name-handler-alist file-name-handler-alist)
(setq gc-cons-threshold (* 400 1024 1024) ; 400 MiB
gc-cons-percentage 0.6
file-name-handler-alist nil
(add-hook
'after-init-hook
(lambda ()
- (setq gc-cons-threshold ab--gc-cons-threshold
- gc-cons-percentage ab--gc-cons-percentage
- file-name-handler-alist ab--file-name-handler-alist)))
+ (setq gc-cons-threshold amin--gc-cons-threshold
+ gc-cons-percentage amin--gc-cons-percentage
+ file-name-handler-alist amin--file-name-handler-alist)))
#+end_src
Increase the number of lines kept in message logs (the =*Messages*=
(expand-file-name "lib/borg" user-emacs-directory))
(require 'borg)
(borg-initialize)
+
+(with-eval-after-load 'bind-key
+ (bind-keys
+ :package borg
+ ("C-c B A" . borg-activate)
+ ("C-c B a" . borg-assimilate)
+ ("C-c B b" . borg-build)
+ ("C-c B c" . borg-clone)))
#+end_src
*** =use-package=
#+begin_src emacs-lisp
(use-package epkg
- :defer t)
+ :defer t
+ :bind
+ (("C-c B d" . epkg-describe-package)
+ ("C-c B p" . epkg-list-packages)
+ ("C-c B r" . borg-remove)
+ ("C-c B u" . epkg-update)))
#+end_src
** No littering in =~/.emacs.d=
** Useful utilities
#+begin_src emacs-lisp
-(defun ab-enlist (exp)
+(defun amin-enlist (exp)
"Return EXP wrapped in a list, or as-is if already a list."
(if (listp exp) exp (list exp)))
compilation."
(declare (indent defun) (debug t))
(list (if (or (not (bound-and-true-p byte-compile-current-file))
- (dolist (next (ab-enlist features))
+ (dolist (next (amin-enlist features))
(if (symbolp next)
(require next nil :no-error)
(load next :no-message :no-error))))
using the Xfce panel anymore. Also, I don't need to see the load
average on a regular basis, so disable that.
-#+begin_src emacs-lisp
+Note: using =i3status= on sway at the moment, so disabling this.
+
+#+begin_src emacs-lisp :tangle no
(use-package time
- :ensure nil
:init
(setq display-time-default-load-average nil)
:config
(display-time-mode))
(use-package battery
- :ensure nil
:config
(display-battery-mode))
#+end_src
version-control t)
#+end_src
+*** Auto revert
+
+Enable automatic reloading of changed buffers and files.
+
+#+begin_src emacs-lisp
+(global-auto-revert-mode 1)
+(setq auto-revert-verbose nil
+ global-auto-revert-non-file-buffers t)
+#+end_src
+
+*** Always use space for indentation
+
+#+begin_src emacs-lisp
+(setq-default
+ indent-tabs-mode nil
+ require-final-newline t
+ tab-width 4)
+#+end_src
+
+*** Winner mode
+
+Enable =winner-mode=.
+
+#+begin_src emacs-lisp
+(winner-mode 1)
+#+end_src
+
+** Bindings
+
+#+begin_src emacs-lisp
+(bind-keys
+ ("C-c b B" . ibuffer-list-buffers)
+ ("C-c b k" . kill-this-buffer)
+ ("C-c b s" . save-buffer)
+ ("C-c S" . save-buffer)
+ ("C-c o" . other-window)
+ ("C-c q q" . save-buffers-kill-terminal))
+#+end_src
+
** Packages
The packages in this section are absolutely essential to my everyday
'auto-compile-inhibit-compile-detached-git-head))
#+end_src
-*** [[https://github.com/Kungsgeten/ryo-modal][ryo-modal]]
-
-#+begin_quote
-Roll your own modal mode
-#+end_quote
-
-#+begin_src emacs-lisp
-(use-package ryo-modal
- :commands ryo-modal-mode
- :bind ("M-m" . ryo-modal-mode)
- :after which-key
- :config
- (push '((nil . "ryo:.*:") . (nil . "")) which-key-replacement-alist)
- (ryo-modal-keys
- ("," ryo-modal-repeat)
- ("b" backward-char)
- ("n" next-line)
- ("p" previous-line)
- ("f" forward-char)
- ("a" move-beginning-of-line)
- ("e" move-end-of-line)
- ("SPC" (("b" (("b" ibuffer-list-buffers)
- ("k" kill-this-buffer)
- ("o" other-window)
- ("s" save-buffer)))
- ("h" (("c" describe-char)
- ("f" describe-function)
- ("F" describe-face)
- ("i" info)
- ("k" describe-key)
- ("l" view-lossage)
- ("v" describe-variable)))
- ("q" (("q" save-buffers-kill-terminal)))))
- ("d" (("w" kill-word)
- ("d" kill-whole-line)
- ("b" backward-kill-word)))
- ("c" (("w" kill-word :exit t)
- ("c" kill-whole-line :exit t))))
-
- (ryo-modal-keys
- ;; First argyment to ryo-modal-keys may be a list of keywords.
- ;; These keywords will be applied to all keybindings.
- (:norepeat t)
- ("0" "M-0")
- ("1" "M-1")
- ("2" "M-2")
- ("3" "M-3")
- ("4" "M-4")
- ("5" "M-5")
- ("6" "M-6")
- ("7" "M-7")
- ("8" "M-8")
- ("9" "M-9"))
- :hook ((text-mode . ryo-modal-mode)
- (prog-mode . ryo-modal-mode)))
-#+end_src
-
*** [[https://orgmode.org/][Org mode]]
#+begin_quote
#+begin_src emacs-lisp
(use-package org
- :ryo ("SPC b t" org-babel-tangle)
:config
(setq org-src-tab-acts-natively t
org-src-preserve-indentation nil
- org-edit-src-content-indentation 0
- org-html-divs '((preamble "header" "preamble")
- (content "main" "content")
- (postamble "footer" "postamble"))
- org-html-doctype "html5"
- org-html-html5-fancy t
- org-html-postamble nil)
+ org-edit-src-content-indentation 0)
:hook (org-mode . org-indent-mode))
-(use-package htmlize
- :after org)
+
(use-package org-notmuch
:after (:any org notmuch))
#+end_src
#+begin_src emacs-lisp
(use-package magit
- :ryo ("SPC" (("g s" magit-status)))
:defer t
- :bind (("s-g" . magit-status)
- ("C-x g" . magit-status)
- ("C-x M-g" . magit-dispatch-popup))
+ :bind
+ (("s-g" . magit-dispatch-popup)
+ ("C-x g" . magit-status)
+ :prefix-map amin--magit-prefix-map
+ :prefix "C-c g"
+ ("SPC" . magit-status)
+ ("s" . magit-status)
+ ("S" . magit-status-prefix)
+ ("B" . magit-blame)
+ ("C" . magit-clone)
+ ("f" . magit-fetch)
+ ("F" . magit-pull)
+ ("P" . magit-push)
+ ("p" . magit-dispatch-popup)
+ ("c c" . magit-commit)
+ ("c a" . magit-commit-amend)
+ ("b b" . magit-checkout)
+ ("b c" . magit-branch))
:config
(magit-add-section-hook 'magit-status-sections-hook
'magit-insert-modules
(use-package ivy
:defer 1
:bind
- (:map ivy-minibuffer-map
- ([escape] . keyboard-escape-quit)
- ;; ("C-j" . ivy-next-line)
- ;; ("C-k" . ivy-previous-line)
- ([S-up] . ivy-previous-history-element)
- ([S-down] . ivy-next-history-element)
- ("DEL" . ivy-backward-delete-char))
- :ryo ("SPC ," ivy-switch-buffer)
+ (("C-c b b" . ivy-switch-buffer)
+ :map ivy-minibuffer-map
+ ([escape] . keyboard-escape-quit)
+ ([S-up] . ivy-previous-history-element)
+ ([S-down] . ivy-next-history-element)
+ ("DEL" . ivy-backward-delete-char))
:config
(setq ivy-wrap t)
(ivy-mode 1))
#+begin_src emacs-lisp
(use-package swiper
- :ryo
- ("SPC /" swiper)
- ("s" swiper)
:bind (([remap isearch-forward] . swiper)
([remap isearch-backward] . swiper)))
#+end_src
#+begin_src emacs-lisp
(use-package counsel
:defer 1
- :ryo
- ("SPC" (("f r" counsel-recentf)
- ("SPC" counsel-M-x)
- ("." counsel-find-file)))
:bind (([remap execute-extended-command] . counsel-M-x)
- ([remap find-file] . counsel-find-file)
- ("s-r" . counsel-recentf)
+ ([remap find-file] . counsel-find-file)
+ ("s-r" . counsel-recentf)
+ ("C-c x" . counsel-M-x)
+ ("C-c f ." . counsel-find-file)
+ ("C-c f r" . counsel-recentf)
:map minibuffer-local-map
("C-r" . counsel-minibuffer-history))
:config
(list (regexp-quote (system-name)) nil nil)))
(use-package undo-tree
- :ryo
- ("/" undo-tree-undo)
- ("_" undo-tree-redo)
- :bind (("C-/" . undo-tree-undo)
+ :bind (("C-?" . undo-tree-undo)
("M-_" . undo-tree-redo))
:config
(global-undo-tree-mode)
- (setq undo-tree-mode-lighter ""))
+ (setq undo-tree-mode-lighter ""
+ undo-tree-auto-save-history t))
#+end_src
* Editing
** [[https://leanprover.github.io][Lean]] (with [[https://github.com/leanprover/lean-mode][lean-mode]])
#+begin_src emacs-lisp
+(eval-when-compile (defvar lean-mode-map))
(use-package lean-mode
:bind (:map lean-mode-map
("S-SPC" . company-complete)))
(load-theme 'eink t)
#+end_src
-* Email
-** [[https://notmuchmail.org][notmuch]]
+** [[https://github.com/bbatsov/crux][crux]]
-See [[notmuch:id:87muuqsvci.fsf@fencepost.gnu.org][bug follow-up]].
+#+begin_src emacs-lisp
+(use-package crux
+ :bind (("C-c d" . crux-duplicate-current-line-or-region)
+ ("C-c M-d" . crux-duplicate-and-comment-current-line-or-region)
+ ("C-c b K" . crux-kill-other-buffers)
+ ("C-c f c" . crux-copy-file-preserve-attributes)
+ ("C-c f D" . crux-delete-file-and-buffer)
+ ("C-c f R" . crux-rename-file-and-buffer)))
+#+end_src
+
+** [[https://github.com/alezost/mwim.el][mwim]]
#+begin_src emacs-lisp
-(defun ab/notmuch ()
- "Delete other windows, then launch `notmuch'."
- (interactive)
- (require 'notmuch)
- (delete-other-windows)
- (notmuch))
+(use-package mwim
+ :bind (("C-a" . mwim-beginning-of-code-or-line)
+ ("C-e" . mwim-end-of-code-or-line)
+ ("<home>" . mwim-beginning-of-line-or-code)
+ ("<end>" . mwim-end-of-line-or-code)))
+#+end_src
+
+** projectile
+
+#+begin_src emacs-lisp
+(use-package projectile
+ :defer 5
+ :bind-keymap ("C-c p" . projectile-command-map)
+ :config
+ (projectile-mode)
+
+ (defun my-projectile-invalidate-cache (&rest _args)
+ ;; ignore the args to `magit-checkout'
+ (projectile-invalidate-cache nil))
-;; (map!
-;; :leader
-;; :desc "notmuch" :n "m" #'ab/notmuch
-;; (:desc "search" :prefix "/"
-;; :desc "notmuch" :n "m" #'counsel-notmuch))
+ (eval-after-load 'magit-branch
+ '(progn
+ (advice-add 'magit-checkout
+ :after #'my-projectile-invalidate-cache)
+ (advice-add 'magit-branch-and-checkout
+ :after #'my-projectile-invalidate-cache))))
#+end_src
+* Email
+** [[https://notmuchmail.org][notmuch]]
+
+See [[notmuch:id:87muuqsvci.fsf@fencepost.gnu.org][bug follow-up]].
+
#+begin_src emacs-lisp
-(defvar ab-maildir "~/mail")
+(defvar amin-maildir "~/mail")
(use-package sendmail
;; :ensure nil
:config
(setq sendmail-program "/usr/bin/msmtp"
+ ; message-sendmail-extra-arguments '("-v" "-d")
mail-specify-envelope-from t
mail-envelope-from 'header))
(setq mml-secure-openpgp-encrypt-to-self t
mml-secure-openpgp-sign-with-sender t))
+(defun amin/notmuch ()
+ "Delete other windows, then launch `notmuch'."
+ (interactive)
+ (delete-other-windows)
+ (notmuch))
+
(use-package notmuch
- :ryo ("SPC m" ab/notmuch)
+ :commands notmuch
+ :bind ("C-c m" . amin/notmuch)
+ :custom (notmuch-always-prompt-for-sender t)
:config
(setq notmuch-hello-sections
'(notmuch-hello-insert-header
'("Subject" "To" "Cc" "Date" "List-Id" "X-RT-Originator")
notmuch-hello-thousands-separator ","
notmuch-fcc-dirs
- '(("amin@aminb.org" . "amin/Sent")
- ("abandali@uwaterloo.ca" . "\"uwaterloo/Sent Items\"")
- ("amin.bandali@uwaterloo.ca" . "\"uwaterloo/Sent Items\"")
- ("aminb@gnu.org" . "gnu/Sent")
- (".*" . "sent"))
+ '(("amin@aminb.org" . "amin/Sent")
+ ("amin@gnu.org" . "gnu/Sent")
+ ("abandali@uwaterloo.ca" . "\"uwaterloo/Sent Items\"")
+ ("mab@gnu.org" . "gnu/Sent")
+ ("aminb@gnu.org" . "gnu/Sent")
+ (".*" . "sent"))
notmuch-search-result-format
- '(("date" . "%12s ")
- ("count" . "%-7s ")
+ '(("date" . "%12s ")
+ ("count" . "%-7s ")
("authors" . "%-40s ")
("subject" . "%s ")
- ("tags" . "(%s)")))
+ ("tags" . "(%s)"))
+ notmuch-saved-searches
+ '((:name "inbox" :query "tag:inbox" :key "i")
+ (:name "unread" :query "tag:unread" :key "u")
+ (:name "latest" :query "tag:latest" :key "l")
+ (:name "encrypted" :query "tag:encrypted" :key "e")
+ (:name "flagged" :query "tag:flagged" :key "f")
+ (:name "sent" :query "tag:sent" :key "s")
+ (:name "drafts" :query "tag:draft" :key "d")
+ (:name "all mail" :query "*" :key "a")))
;; (add-hook 'visual-fill-column-mode-hook
;; (lambda ()
;; (when (string= major-mode 'notmuch-message-mode)
;; (advice-add #'notmuch-bury-or-kill-this-buffer
;; :override #'kill-this-buffer)
:bind
+ (:map notmuch-common-keymap
+ ("g" . notmuch-poll-and-refresh-this-buffer))
(:map notmuch-hello-mode-map
- ("g" . notmuch-poll-and-refresh-this-buffer)
- ("i" . (lambda ()
- "Search for `inbox' tagged messages"
- (interactive)
- (notmuch-hello-search "tag:inbox")))
("u" . (lambda ()
- "Search for `unread' tagged messages"
+ "Search for `unread'-tagged messages"
(interactive)
(notmuch-hello-search "tag:unread")))
+ ("i" . (lambda ()
+ "Search for `inbox'-tagged messages"
+ (interactive)
+ (notmuch-hello-search "tag:inbox")))
("l" . (lambda ()
- "Search for `latest tagged messages"
+ "Search for `latest'-tagged messages"
(interactive)
(notmuch-hello-search "tag:latest")))
- ("M" . (lambda ()
- "Compose new mail and prompt for sender"
+ ("e" . (lambda ()
+ "Search for `encrypted'-tagged messages"
(interactive)
- (let ((current-prefix-arg t))
- (call-interactively #'notmuch-mua-new-mail)))))
+ (notmuch-hello-search "tag:encrypted"))))
(:map notmuch-search-mode-map
- ("g" . notmuch-poll-and-refresh-this-buffer)
("k" . (lambda ()
"Mark message read"
(interactive)
"Mark message deleted"
(interactive)
(notmuch-search-tag '("-unread" "-inbox" "+deleted"))
- (notmuch-search-archive-thread)))
+ (notmuch-search-next-thread)))
("S" . (lambda ()
"Mark message as spam"
(interactive)
(notmuch-search-tag '("-unread" "-inbox" "-webmasters" "+spam"))
- (notmuch-search-archive-thread))))
- (:map notmuch-tree-mode-map ; TODO: additional bindings
+ (notmuch-search-next-thread))))
+ (:map notmuch-tree-mode-map
+ ("k" . (lambda ()
+ "Mark message read"
+ (interactive)
+ (notmuch-tree-tag '("-unread"))
+ ;; (notmuch-tree-archive-thread)
+ (notmuch-tree-next-message)))
+ ("u" . (lambda ()
+ "Mark message unread"
+ (interactive)
+ (notmuch-tree-tag '("+unread"))
+ (notmuch-tree-next-message)))
+ ("K" . (lambda ()
+ "Mark message deleted"
+ (interactive)
+ (notmuch-tree-tag '("-unread" "-inbox" "+deleted"))
+ (notmuch-tree-next-message)))
("S" . (lambda ()
"Mark message as spam"
(interactive)
(notmuch-tree-tag '("-unread" "-inbox" "-webmasters" "+spam"))
- (notmuch-tree-archive-thread))))
-)
+ (notmuch-tree-next-message)))))
-;; (use-package counsel-notmuch
-;; :commands counsel-notmuch)
+(use-package counsel-notmuch
+ :bind ("C-c s m" . counsel-notmuch))
(after! notmuch-crypto
(setq notmuch-crypto-process-mime t))
-;; (after! evil
-;; (mapc (lambda (str) (evil-set-initial-state (car str) (cdr str)))
-;; '((notmuch-hello-mode . emacs)
-;; (notmuch-search-mode . emacs)
-;; (notmuch-tree-mode . emacs))))
-
(after! recentf
- (add-to-list 'recentf-exclude (expand-file-name ab-maildir)))
+ (add-to-list 'recentf-exclude (expand-file-name amin-maildir)))
#+end_src
** supercite
#+begin_src emacs-lisp
(message "Loading %s...done (%.3fs)" user-init-file
(float-time (time-subtract (current-time)
- ab--before-user-init-time)))
+ amin--before-user-init-time)))
#+end_src
* Footer