X-Git-Url: https://git.shemshak.org/~bandali/configs/blobdiff_plain/82ff3214f956e3dd33c0d63032f834d7757c361b..1dde553d9a6d52523575f41a560162c79f10c0a3:/init.org?ds=inline diff --git a/init.org b/init.org index 69ae88f..51cd9ca 100644 --- a/init.org +++ b/init.org @@ -105,20 +105,19 @@ file. ** 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 @@ -137,10 +136,10 @@ let's see how long Emacs takes to start up, before even loading =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 @@ -150,9 +149,9 @@ frequency. Clearing the ~file-name-handler-alist~ seems to help reduce 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 @@ -167,9 +166,9 @@ done initializing. (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*= @@ -234,6 +233,17 @@ can then be managed with the help of Magit or other tools. (expand-file-name "lib/borg" user-emacs-directory)) (require 'borg) (borg-initialize) + +(require 'borg-nix-shell) +(setq borg-build-shell-command 'borg-nix-shell-build-command) + +(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= @@ -269,7 +279,12 @@ database, low-level functions for querying the database, and a #+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= @@ -397,7 +412,7 @@ Font stack with better unicode support, around =Ubuntu Mono= and ** 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))) @@ -407,7 +422,7 @@ Font stack with better unicode support, around =Ubuntu Mono= and 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)))) @@ -442,16 +457,16 @@ Enable displaying time and battery in the mode-line, since I'm not 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 @@ -565,6 +580,45 @@ variable. 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 @@ -589,63 +643,6 @@ customizing it. '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 @@ -658,20 +655,12 @@ In short, my favourite way of life. #+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 @@ -686,11 +675,25 @@ Not just how I do git, but /the/ way to do git. #+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 @@ -713,14 +716,12 @@ There's no way I could top that, so I won't attempt to. (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)) @@ -730,9 +731,6 @@ There's no way I could top that, so I won't attempt to. #+begin_src emacs-lisp (use-package swiper - :ryo - ("SPC /" swiper) - ("s" swiper) :bind (([remap isearch-forward] . swiper) ([remap isearch-backward] . swiper))) #+end_src @@ -742,13 +740,12 @@ There's no way I could top that, so I won't attempt to. #+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 @@ -832,14 +829,12 @@ TODO: break this giant source block down into individual org sections. (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 @@ -891,6 +886,7 @@ TODO: break this giant source block down into individual org sections. ** [[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))) @@ -1118,33 +1114,62 @@ Emacs package that displays available keybindings in popup (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) + ("" . mwim-beginning-of-line-or-code) + ("" . 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)) @@ -1177,8 +1202,16 @@ See [[notmuch:id:87muuqsvci.fsf@fencepost.gnu.org][bug follow-up]]. (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 @@ -1191,17 +1224,27 @@ See [[notmuch:id:87muuqsvci.fsf@fencepost.gnu.org][bug follow-up]]. '("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) @@ -1211,26 +1254,23 @@ See [[notmuch:id:87muuqsvci.fsf@fencepost.gnu.org][bug follow-up]]. ;; :override #'kill-this-buffer) :bind (: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) @@ -1246,34 +1286,43 @@ See [[notmuch:id:87muuqsvci.fsf@fencepost.gnu.org][bug follow-up]]. "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 @@ -1345,7 +1394,7 @@ Display how long it took to load the init file. #+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