b80e00f63573e2f7ebb299c1c158b01161c02f08
[~bandali/configs] / init.el
1 ;;; init.el --- Amin Bandali's Emacs config -*- lexical-binding: t -*-
2
3 ;; Copyright (C) 2018 Amin Bandali <bandali@gnu.org>
4
5 ;; This program is free software: you can redistribute it and/or modify
6 ;; it under the terms of the GNU General Public License as published by
7 ;; the Free Software Foundation, either version 3 of the License, or
8 ;; (at your option) any later version.
9
10 ;; This program is distributed in the hope that it will be useful,
11 ;; but WITHOUT ANY WARRANTY; without even the implied warranty of
12 ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 ;; GNU General Public License for more details.
14
15 ;; You should have received a copy of the GNU General Public License
16 ;; along with this program. If not, see <https://www.gnu.org/licenses/>.
17
18 ;;; Commentary:
19
20 ;; Emacs configuration of Amin Bandali, computer scientist and functional
21 ;; programmer.
22
23 ;; THIS FILE IS AUTO-GENERATED FROM `init.org'.
24
25 ;; Naming conventions:
26 ;;
27 ;; amin-... public variables or non-interactive functions
28 ;; amin--... private anything (non-interactive), not safe for direct use
29 ;; amin/... an interactive function; safe for M-x or keybinding
30 ;; amin|... a hook function
31 ;; amin*... an advising function
32 ;; amin@... a hydra command
33 ;; ...! a macro
34
35 ;;; Code:
36
37 \f
38 ;; * Initial setup
39
40 (defvar amin--before-user-init-time (current-time)
41 "Value of `current-time' when Emacs begins loading `user-init-file'.")
42 (message "Loading Emacs...done (%.3fs)"
43 (float-time (time-subtract amin--before-user-init-time
44 before-init-time)))
45
46 (defvar amin--gc-cons-threshold gc-cons-threshold)
47 (defvar amin--gc-cons-percentage gc-cons-percentage)
48 (defvar amin--file-name-handler-alist file-name-handler-alist)
49 (setq gc-cons-threshold (* 400 1024 1024) ; 400 MiB
50 gc-cons-percentage 0.6
51 file-name-handler-alist nil
52 ;; sidesteps a bug when profiling with esup
53 esup-child-profile-require-level 0)
54
55 (add-hook
56 'after-init-hook
57 (lambda ()
58 (setq gc-cons-threshold amin--gc-cons-threshold
59 gc-cons-percentage amin--gc-cons-percentage
60 file-name-handler-alist amin--file-name-handler-alist)))
61
62 (setq message-log-max 20000)
63
64 ;; (setq byte-compile-warnings
65 ;; '(not free-vars unresolved noruntime lexical make-local))
66
67 (setq user-full-name "Amin Bandali"
68 user-mail-address "amin@aminb.org")
69
70 (setq package-enable-at-startup nil)
71 ;; (package-initialize)
72
73 (setq user-init-file (or load-file-name buffer-file-name)
74 user-emacs-directory (file-name-directory user-init-file))
75 (add-to-list 'load-path
76 (expand-file-name "lib/borg" user-emacs-directory))
77 (require 'borg)
78 (borg-initialize)
79
80 ;; (require 'borg-nix-shell)
81 ;; (setq borg-build-shell-command 'borg-nix-shell-build-command)
82
83 (with-eval-after-load 'bind-key
84 (bind-keys
85 :package borg
86 ("C-c b A" . borg-activate)
87 ("C-c b a" . borg-assimilate)
88 ("C-c b b" . borg-build)
89 ("C-c b c" . borg-clone)
90 ("C-c b r" . borg-remove)))
91
92 (require 'use-package)
93 (if nil ; set to t when need to debug init
94 (setq use-package-verbose t
95 use-package-expand-minimally nil
96 use-package-compute-statistics t
97 debug-on-error t)
98 (setq use-package-verbose nil
99 use-package-expand-minimally t))
100
101 (use-package epkg
102 :defer t
103 :bind
104 (("C-c b d" . epkg-describe-package)
105 ("C-c b p" . epkg-list-packages)
106 ("C-c b u" . epkg-update)))
107
108 (use-package no-littering
109 :demand t
110 :config
111 (savehist-mode 1)
112 (add-to-list 'savehist-additional-variables 'kill-ring)
113 (save-place-mode 1)
114 (setq auto-save-file-name-transforms
115 `((".*" ,(no-littering-expand-var-file-name "auto-save/") t))))
116
117 (use-package custom
118 :no-require t
119 :config
120 (setq custom-file (no-littering-expand-etc-file-name "custom.el"))
121 (when (file-exists-p custom-file)
122 (load custom-file))
123 (setf custom-safe-themes t))
124
125 (with-demoted-errors
126 (load (no-littering-expand-etc-file-name "secrets")))
127
128 (use-package exec-path-from-shell
129 :defer 1
130 :init
131 (setq exec-path-from-shell-check-startup-files nil)
132 :config
133 (exec-path-from-shell-initialize)
134 ;; while we're at it, let's fix access to our running ssh-agent
135 (exec-path-from-shell-copy-env "SSH_AGENT_PID")
136 (exec-path-from-shell-copy-env "SSH_AUTH_SOCK"))
137
138 ;; only one custom theme at a time
139 ;;
140 ;; (defadvice load-theme (before clear-previous-themes activate)
141 ;; "Clear existing theme settings instead of layering them"
142 ;; (mapc #'disable-theme custom-enabled-themes))
143
144 (use-package server
145 :defer 1
146 :config (or (server-running-p) (server-mode)))
147
148 ;; unicode support
149 ;;
150 ;; (dolist (ft (fontset-list))
151 ;; (set-fontset-font
152 ;; ft
153 ;; 'unicode
154 ;; (font-spec :name "Source Code Pro" :size 14))
155 ;; (set-fontset-font
156 ;; ft
157 ;; 'unicode
158 ;; (font-spec :name "DejaVu Sans Mono")
159 ;; nil
160 ;; 'append)
161 ;; ;; (set-fontset-font
162 ;; ;; ft
163 ;; ;; 'unicode
164 ;; ;; (font-spec
165 ;; ;; :name "Symbola monospacified for DejaVu Sans Mono")
166 ;; ;; nil
167 ;; ;; 'append)
168 ;; ;; (set-fontset-font
169 ;; ;; ft
170 ;; ;; #x2115 ; ℕ
171 ;; ;; (font-spec :name "DejaVu Sans Mono")
172 ;; ;; nil
173 ;; ;; 'append)
174 ;; (set-fontset-font
175 ;; ft
176 ;; (cons ?Α ?ω)
177 ;; (font-spec :name "DejaVu Sans Mono" :size 14)
178 ;; nil
179 ;; 'prepend))
180
181 (setq text-scale-mode-step 1.05)
182
183 (setq mouse-autoselect-window t)
184
185 (defun amin--no-mouse-autoselect-window ()
186 (make-local-variable 'mouse-autoselect-window)
187 (setq mouse-autoselect-window nil))
188
189 (require 'cl-lib)
190 (require 'subr-x)
191
192 (defun amin-enlist (exp)
193 "Return EXP wrapped in a list, or as-is if already a list."
194 (if (listp exp) exp (list exp)))
195
196 ; from https://github.com/hlissner/doom-emacs/commit/589108fdb270f24a98ba6209f6955fe41530b3ef
197 (defmacro after! (features &rest body)
198 "A smart wrapper around `with-eval-after-load'. Supresses warnings during
199 compilation."
200 (declare (indent defun) (debug t))
201 (list (if (or (not (bound-and-true-p byte-compile-current-file))
202 (dolist (next (amin-enlist features))
203 (if (symbolp next)
204 (require next nil :no-error)
205 (load next :no-message :no-error))))
206 #'progn
207 #'with-no-warnings)
208 (cond ((symbolp features)
209 `(eval-after-load ',features '(progn ,@body)))
210 ((and (consp features)
211 (memq (car features) '(:or :any)))
212 `(progn
213 ,@(cl-loop for next in (cdr features)
214 collect `(after! ,next ,@body))))
215 ((and (consp features)
216 (memq (car features) '(:and :all)))
217 (dolist (next (cdr features))
218 (setq body `(after! ,next ,@body)))
219 body)
220 ((listp features)
221 `(after! (:all ,@features) ,@body)))))
222
223 (defmacro setq-every! (value &rest vars)
224 "Set all the variables from VARS to value VALUE."
225 (declare (indent defun) (debug t))
226 `(progn ,@(mapcar (lambda (x) (list 'setq x value)) vars)))
227
228 \f
229 ;; * Core
230
231 ;; (fringe-mode '(3 . 1))
232 (fringe-mode nil)
233
234 (setq disabled-command-function nil)
235
236 (setq save-interprogram-paste-before-kill t)
237
238 (setq enable-recursive-minibuffers t
239 resize-mini-windows t)
240
241 (defalias 'yes-or-no-p #'y-or-n-p)
242
243 (setq initial-buffer-choice t)
244
245 (setq initial-scratch-message nil)
246
247 (setq initial-major-mode 'text-mode)
248
249 (setq inhibit-startup-buffer-menu t)
250
251 (advice-add #'display-startup-echo-area-message :override #'ignore)
252 (setq inhibit-startup-screen t
253 inhibit-startup-echo-area-message user-login-name)
254
255 (setq frame-title-format
256 '("" invocation-name " - "
257 (:eval (if (buffer-file-name)
258 (abbreviate-file-name (buffer-file-name))
259 "%b"))))
260
261 (setq backup-by-copying t
262 version-control t
263 delete-old-versions t)
264
265 (global-auto-revert-mode 1)
266 (setq auto-revert-verbose nil
267 global-auto-revert-non-file-buffers nil)
268
269 (setq-default
270 indent-tabs-mode nil
271 require-final-newline t
272 tab-width 4)
273
274 (winner-mode 1)
275
276 (setq compilation-exit-message-function
277 (lambda (status code msg)
278 "Close the compilation window if successful."
279 ;; if M-x compile exits with 0
280 (when (and (eq status 'exit) (zerop code))
281 (bury-buffer)
282 (delete-window (get-buffer-window (get-buffer "*compilation*"))))
283 ;; return the result of compilation-exit-message-function
284 (cons msg code)))
285
286 (setq search-default-mode #'char-fold-to-regexp)
287
288 ;; uncomment to extend this behaviour to query-replace
289 ;; (setq replace-char-fold t)
290
291 (bind-keys
292 ("C-c a i" . ielm)
293
294 ("C-c e b" . eval-buffer)
295 ("C-c e r" . eval-region)
296
297 ("C-c F m" . make-frame-command)
298 ("C-c F d" . delete-frame)
299 ("C-c F D" . delete-other-frames)
300
301 ("C-c o" . other-window)
302
303 ("C-c Q" . save-buffers-kill-terminal)
304
305 ("C-S-h C" . describe-char)
306 ("C-S-h F" . describe-face)
307
308 ("C-x K" . kill-this-buffer)
309
310 ("s-p" . beginning-of-buffer)
311 ("s-n" . end-of-buffer))
312
313 (use-package auto-compile
314 :demand t
315 :config
316 (auto-compile-on-load-mode)
317 (auto-compile-on-save-mode)
318 (setq auto-compile-display-buffer nil
319 auto-compile-mode-line-counter t
320 auto-compile-source-recreate-deletes-dest t
321 auto-compile-toggle-deletes-nonlib-dest t
322 auto-compile-update-autoloads t)
323 (add-hook 'auto-compile-inhibit-compile-hook
324 'auto-compile-inhibit-compile-detached-git-head))
325
326 (use-package org
327 :defer 1
328 :config
329 (setq org-src-tab-acts-natively t
330 org-src-preserve-indentation nil
331 org-edit-src-content-indentation 0
332 org-email-link-description-format "Email %c: %s" ; %.30s
333 org-highlight-latex-and-related '(entities)
334 org-log-done 'time)
335 (add-to-list 'org-structure-template-alist '("L" . "src emacs-lisp") t)
336 (font-lock-add-keywords
337 'org-mode
338 '(("[ \t]*\\(#\\+\\(BEGIN\\|END\\|begin\\|end\\)_\\(\\S-+\\)\\)[ \t]*\\([^\n:]*\\)"
339 (1 '(:foreground "#5a5b5a" :background "#292b2b") t) ; directive
340 (3 '(:foreground "#81a2be" :background "#292b2b") t) ; kind
341 (4 '(:foreground "#c5c8c6") t))) ; title
342 t)
343 :bind (:map org-mode-map ("M-L" . org-insert-last-stored-link))
344 :hook ((org-mode . org-indent-mode)
345 (org-mode . auto-fill-mode)
346 (org-mode . flyspell-mode))
347 :custom
348 (org-latex-packages-alist '(("" "listings") ("" "color")))
349 :custom-face
350 '(org-block-begin-line ((t (:foreground "#5a5b5a" :background "#1d1f21"))))
351 '(org-block ((t (:background "#1d1f21"))))
352 '(org-latex-and-related ((t (:foreground "#b294bb")))))
353
354 (use-package ox-latex
355 :after ox
356 :config
357 (setq org-latex-listings 'listings
358 ;; org-latex-prefer-user-labels t
359 )
360 (add-to-list 'org-latex-packages-alist '("" "listings"))
361 (add-to-list 'org-latex-packages-alist '("" "color"))
362 (add-to-list 'org-latex-classes
363 '("IEEEtran" "\\documentclass[11pt]{IEEEtran}"
364 ("\\section{%s}" . "\\section*{%s}")
365 ("\\subsection{%s}" . "\\subsection*{%s}")
366 ("\\subsubsection{%s}" . "\\subsubsection*{%s}")
367 ("\\paragraph{%s}" . "\\paragraph*{%s}")
368 ("\\subparagraph{%s}" . "\\subparagraph*{%s}"))
369 t))
370
371 (use-package ox-beamer
372 :after ox)
373
374 (use-package orgalist
375 :after message
376 :hook (message-mode . orgalist-mode))
377
378 (after! org
379 (defvar amin-show-async-tangle-results nil
380 "Keep *emacs* async buffers around for later inspection.")
381
382 (defvar amin-show-async-tangle-time nil
383 "Show the time spent tangling the file.")
384
385 (defvar amin-async-tangle-post-compile "make ti"
386 "If non-nil, pass to `compile' after successful tangle.")
387
388 (defun amin/async-babel-tangle ()
389 "Tangle org file asynchronously."
390 (interactive)
391 (let* ((file-tangle-start-time (current-time))
392 (file (buffer-file-name))
393 (file-nodir (file-name-nondirectory file))
394 (async-quiet-switch "-q"))
395 (async-start
396 `(lambda ()
397 (require 'org)
398 (org-babel-tangle-file ,file))
399 (unless amin-show-async-tangle-results
400 `(lambda (result)
401 (if result
402 (progn
403 (message "Tangled %s%s"
404 ,file-nodir
405 (if amin-show-async-tangle-time
406 (format " (%.3fs)"
407 (float-time (time-subtract (current-time)
408 ',file-tangle-start-time)))
409 ""))
410 (when amin-async-tangle-post-compile
411 (compile amin-async-tangle-post-compile)))
412 (message "Tangling %s failed" ,file-nodir))))))))
413
414 (add-to-list
415 'safe-local-variable-values
416 '(eval add-hook 'after-save-hook #'amin/async-babel-tangle 'append 'local))
417
418 (use-package magit
419 :defer 1
420 :bind (("C-x g" . magit-status)
421 ("s-g s" . magit-status)
422 ("s-g l" . magit-log-buffer-file))
423 :config
424 (magit-add-section-hook 'magit-status-sections-hook
425 'magit-insert-modules
426 'magit-insert-stashes
427 'append)
428 (setq
429 magit-repository-directories '(("~/.emacs.d/" . 0)
430 ("~/src/git/" . 1)))
431 (nconc magit-section-initial-visibility-alist
432 '(([unpulled status] . show)
433 ([unpushed status] . show)))
434 :custom-face (magit-diff-file-heading ((t (:weight normal)))))
435
436 (use-package ivy
437 :defer 1
438 :bind
439 (:map ivy-minibuffer-map
440 ([escape] . keyboard-escape-quit)
441 ([S-up] . ivy-previous-history-element)
442 ([S-down] . ivy-next-history-element)
443 ("DEL" . ivy-backward-delete-char))
444 :config
445 (setq ivy-wrap t)
446 (ivy-mode 1)
447 ;; :custom-face
448 ;; (ivy-minibuffer-match-face-2 ((t (:background "#e99ce8" :weight semi-bold))))
449 ;; (ivy-minibuffer-match-face-3 ((t (:background "#bbbbff" :weight semi-bold))))
450 ;; (ivy-minibuffer-match-face-4 ((t (:background "#ffbbff" :weight semi-bold))))
451 )
452
453 (use-package swiper
454 :bind (("C-s" . swiper)
455 ("C-r" . swiper)))
456
457 (use-package counsel
458 :defer 1
459 :bind (([remap execute-extended-command] . counsel-M-x)
460 ([remap find-file] . counsel-find-file)
461 ("s-r" . counsel-recentf)
462 ("C-c x" . counsel-M-x)
463 ("C-c f ." . counsel-find-file)
464 :map minibuffer-local-map
465 ("C-r" . counsel-minibuffer-history))
466 :config
467 (counsel-mode 1)
468 (defalias 'locate #'counsel-locate))
469
470 (use-package eshell
471 :defer 1
472 :commands eshell
473 :config
474 (eval-when-compile (defvar eshell-prompt-regexp))
475 (defun amin/eshell-quit-or-delete-char (arg)
476 (interactive "p")
477 (if (and (eolp) (looking-back eshell-prompt-regexp nil))
478 (eshell-life-is-too-much)
479 (delete-char arg)))
480
481 (defun amin/eshell-clear ()
482 (interactive)
483 (let ((inhibit-read-only t))
484 (erase-buffer))
485 (eshell-send-input))
486
487 (defun amin|eshell-setup ()
488 (make-local-variable 'company-idle-delay)
489 (setq company-idle-delay nil)
490 (bind-keys :map eshell-mode-map
491 ("C-d" . amin/eshell-quit-or-delete-char)
492 ("C-S-l" . amin/eshell-clear)
493 ("M-r" . counsel-esh-history)
494 ([tab] . company-complete)))
495
496 :hook (eshell-mode . amin|eshell-setup)
497 :custom
498 (eshell-hist-ignoredups t)
499 (eshell-input-filter 'eshell-input-filter-initial-space))
500
501 (use-package ibuffer
502 :defer t
503 :bind
504 (("C-x C-b" . ibuffer-other-window)
505 :map ibuffer-mode-map
506 ("P" . ibuffer-backward-filter-group)
507 ("N" . ibuffer-forward-filter-group)
508 ("M-p" . ibuffer-do-print)
509 ("M-n" . ibuffer-do-shell-command-pipe-replace))
510 :config
511 ;; Use human readable Size column instead of original one
512 (define-ibuffer-column size-h
513 (:name "Size" :inline t)
514 (cond
515 ((> (buffer-size) 1000000) (format "%7.1fM" (/ (buffer-size) 1000000.0)))
516 ((> (buffer-size) 100000) (format "%7.0fk" (/ (buffer-size) 1000.0)))
517 ((> (buffer-size) 1000) (format "%7.1fk" (/ (buffer-size) 1000.0)))
518 (t (format "%8d" (buffer-size)))))
519 :custom
520 (ibuffer-saved-filter-groups
521 '(("default"
522 ("dired" (mode . dired-mode))
523 ("org" (mode . org-mode))
524 ("web"
525 (or
526 (mode . web-mode)
527 (mode . css-mode)
528 (mode . scss-mode)
529 (mode . js2-mode)))
530 ("shell"
531 (or
532 (mode . eshell-mode)
533 (mode . shell-mode)))
534 ("notmuch" (name . "\*notmuch\*"))
535 ("programming"
536 (or
537 (mode . python-mode)
538 (mode . c++-mode)
539 (mode . emacs-lisp-mode)))
540 ("emacs"
541 (or
542 (name . "^\\*scratch\\*$")
543 (name . "^\\*Messages\\*$")))
544 ("slack"
545 (or
546 (name . "^\\*Slack*"))))))
547 (ibuffer-formats
548 '((mark modified read-only locked " "
549 (name 18 18 :left :elide)
550 " "
551 (size-h 9 -1 :right)
552 " "
553 (mode 16 16 :left :elide)
554 " " filename-and-process)
555 (mark " "
556 (name 16 -1)
557 " " filename)))
558 :hook (ibuffer . (lambda () (ibuffer-switch-to-saved-filter-groups "default"))))
559
560 (use-package outline
561 :defer t
562 :hook (prog-mode . outline-minor-mode)
563 :bind
564 (:map
565 outline-minor-mode-map
566 ("<s-tab>" . outline-toggle-children)
567 ("M-p" . outline-previous-visible-heading)
568 ("M-n" . outline-next-visible-heading)
569 :prefix-map amin--outline-prefix-map
570 :prefix "s-o"
571 ("TAB" . outline-toggle-children)
572 ("a" . outline-hide-body)
573 ("H" . outline-hide-body)
574 ("S" . outline-show-all)
575 ("h" . outline-hide-subtree)
576 ("s" . outline-show-subtree)))
577
578 \f
579 ;; * Borg's `layer/essentials'
580
581 (use-package dash
582 :config (dash-enable-font-lock))
583
584 (use-package diff-hl
585 :config
586 (setq diff-hl-draw-borders nil)
587 (global-diff-hl-mode)
588 (add-hook 'magit-post-refresh-hook 'diff-hl-magit-post-refresh t))
589
590 (use-package dired
591 :defer t
592 :config (setq dired-listing-switches "-alh"))
593
594 (use-package eldoc
595 :when (version< "25" emacs-version)
596 :config (global-eldoc-mode))
597
598 (use-package help
599 :defer t
600 :config
601 (temp-buffer-resize-mode)
602 (setq help-window-select t))
603
604 (progn ; `isearch'
605 (setq isearch-allow-scroll t))
606
607 (use-package lisp-mode
608 :config
609 (add-hook 'emacs-lisp-mode-hook 'outline-minor-mode)
610 (add-hook 'emacs-lisp-mode-hook 'reveal-mode)
611 (defun indent-spaces-mode ()
612 (setq indent-tabs-mode nil))
613 (add-hook 'lisp-interaction-mode-hook #'indent-spaces-mode))
614
615 (use-package man
616 :defer t
617 :config (setq Man-width 80))
618
619 (use-package paren
620 :config (show-paren-mode))
621
622 (use-package prog-mode
623 :config (global-prettify-symbols-mode)
624 (defun indicate-buffer-boundaries-left ()
625 (setq indicate-buffer-boundaries 'left))
626 (add-hook 'prog-mode-hook #'indicate-buffer-boundaries-left))
627
628 (use-package recentf
629 :defer 0.5
630 :config
631 (add-to-list 'recentf-exclude "^/\\(?:ssh\\|su\\|sudo\\)?:")
632 (setq recentf-max-saved-items 40))
633
634 (use-package savehist
635 :config (savehist-mode))
636
637 (use-package saveplace
638 :when (version< "25" emacs-version)
639 :config (save-place-mode))
640
641 (use-package simple
642 :config (column-number-mode))
643
644 (progn ; `text-mode'
645 (add-hook 'text-mode-hook #'indicate-buffer-boundaries-left)
646 (add-hook 'text-mode-hook #'abbrev-mode))
647
648 (use-package tramp
649 :defer t
650 :config
651 (add-to-list 'tramp-default-proxies-alist '(nil "\\`root\\'" "/ssh:%h:"))
652 (add-to-list 'tramp-default-proxies-alist '("localhost" nil nil))
653 (add-to-list 'tramp-default-proxies-alist
654 (list (regexp-quote (system-name)) nil nil)))
655
656 (use-package undo-tree
657 :config
658 (global-undo-tree-mode -1))
659 ;; :bind (("C-?" . undo-tree-undo)
660 ;; ("M-_" . undo-tree-redo))
661 ;; :config
662 ;; (global-undo-tree-mode)
663 ;; (setq undo-tree-mode-lighter ""
664 ;; undo-tree-auto-save-history t))
665
666 \f
667 ;; * Editing
668
669 (use-package company
670 :defer 1
671 :bind
672 (:map company-active-map
673 ([tab] . company-complete-common-or-cycle)
674 ([escape] . company-abort))
675 :custom
676 (company-minimum-prefix-length 1)
677 (company-selection-wrap-around t)
678 (company-dabbrev-char-regexp "\\sw\\|\\s_\\|[-_]")
679 (company-dabbrev-downcase nil)
680 (company-dabbrev-ignore-case nil)
681 :config
682 (global-company-mode t))
683
684 \f
685 ;; * Syntax and spell checking
686
687 (use-package flycheck
688 :defer 3
689 :hook (prog-mode . flycheck-mode)
690 :bind
691 (:map flycheck-mode-map
692 ("M-P" . flycheck-previous-error)
693 ("M-N" . flycheck-next-error))
694 :config
695 ;; Use the load-path from running Emacs when checking elisp files
696 (setq flycheck-emacs-lisp-load-path 'inherit)
697
698 ;; Only flycheck when I actually save the buffer
699 (setq flycheck-check-syntax-automatically '(mode-enabled save)))
700
701 ;; http://endlessparentheses.com/ispell-and-apostrophes.html
702 (use-package ispell
703 :defer 3
704 :config
705 ;; ’ can be part of a word
706 (setq ispell-local-dictionary-alist
707 `((nil "[[:alpha:]]" "[^[:alpha:]]"
708 "['\x2019]" nil ("-B") nil utf-8)))
709 ;; don't send ’ to the subprocess
710 (defun endless/replace-apostrophe (args)
711 (cons (replace-regexp-in-string
712 "’" "'" (car args))
713 (cdr args)))
714 (advice-add #'ispell-send-string :filter-args
715 #'endless/replace-apostrophe)
716
717 ;; convert ' back to ’ from the subprocess
718 (defun endless/replace-quote (args)
719 (if (not (derived-mode-p 'org-mode))
720 args
721 (cons (replace-regexp-in-string
722 "'" "’" (car args))
723 (cdr args))))
724 (advice-add #'ispell-parse-output :filter-args
725 #'endless/replace-quote))
726
727 \f
728 ;; * Programming modes
729
730 (use-package alloy-mode
731 :defer t
732 :config (setq alloy-basic-offset 2))
733
734 (use-package proof-site ; Proof General
735 :defer t
736 :load-path "lib/proof-site/generic/")
737
738 (eval-when-compile (defvar lean-mode-map))
739 (use-package lean-mode
740 :defer 1
741 :bind (:map lean-mode-map
742 ("S-SPC" . company-complete))
743 :config
744 (require 'lean-input)
745 (setq default-input-method "Lean"
746 lean-input-tweak-all '(lean-input-compose
747 (lean-input-prepend "/")
748 (lean-input-nonempty))
749 lean-input-user-translations '(("/" "/")))
750 (lean-input-setup))
751
752 (use-package haskell-mode
753 :defer t
754 :config
755 (setq haskell-indentation-layout-offset 4
756 haskell-indentation-left-offset 4
757 flycheck-checker 'haskell-hlint
758 flycheck-disabled-checkers '(haskell-stack-ghc haskell-ghc)))
759
760 (use-package dante
761 :after haskell-mode
762 :commands dante-mode
763 :hook (haskell-mode . dante-mode))
764
765 (use-package hlint-refactor
766 :after haskell-mode
767 :bind (:map hlint-refactor-mode-map
768 ("C-c l b" . hlint-refactor-refactor-buffer)
769 ("C-c l r" . hlint-refactor-refactor-at-point))
770 :hook (haskell-mode . hlint-refactor-mode))
771
772 (use-package flycheck-haskell
773 :after haskell-mode)
774
775 (use-package sgml-mode
776 :defer t
777 :config
778 (setq sgml-basic-offset 2))
779
780 (use-package css-mode
781 :defer t
782 :config
783 (setq css-indent-offset 2))
784
785 (use-package web-mode
786 :defer t
787 :mode "\\.html\\'"
788 :config
789 (setq-every! 2
790 web-mode-code-indent-offset
791 web-mode-css-indent-offset
792 web-mode-markup-indent-offset))
793
794 (use-package emmet-mode
795 :after (:any web-mode css-mode sgml-mode)
796 :bind* (("C-)" . emmet-next-edit-point)
797 ("C-(" . emmet-prev-edit-point))
798 :config
799 (unbind-key "C-j" emmet-mode-keymap)
800 (setq emmet-move-cursor-between-quotes t)
801 :hook (web-mode css-mode html-mode sgml-mode))
802
803 (use-package nix-mode
804 :defer t
805 :mode "\\.nix\\'")
806
807 \f
808 ;; * Emacs Enhancements
809
810 (use-package which-key
811 :defer 1
812 :config (which-key-mode))
813
814 (add-to-list 'custom-theme-load-path "~/.emacs.d/lisp")
815 (load-theme 'tangomod t)
816
817 (use-package doom-modeline
818 :demand t
819 :config (setq doom-modeline-height 32)
820 :hook (after-init . doom-modeline-init))
821
822 (use-package doom-themes)
823
824 (defun amin/lights-on ()
825 "Enable my favourite light theme."
826 (interactive)
827 (progn
828 (mapc #'disable-theme custom-enabled-themes)
829 (load-theme 'tangomod t)))
830
831 (defun amin/lights-off ()
832 "Go dark."
833 (interactive)
834 (progn
835 (mapc #'disable-theme custom-enabled-themes)
836 (load-theme 'doom-tomorrow-night t)))
837
838 (bind-keys
839 ("s-t d" . amin/lights-off)
840 ("s-t l" . amin/lights-on))
841
842 (use-package crux
843 :defer 1
844 :bind (("C-c b k" . crux-kill-other-buffers)
845 ("C-c d" . crux-duplicate-current-line-or-region)
846 ("C-c D" . crux-duplicate-and-comment-current-line-or-region)
847 ("C-c f c" . crux-copy-file-preserve-attributes)
848 ("C-c f d" . crux-delete-file-and-buffer)
849 ("C-c f r" . crux-rename-file-and-buffer)
850 ("C-c j" . crux-top-join-line)
851 ("C-S-j" . crux-top-join-line)))
852
853 (use-package mwim
854 :bind (("C-a" . mwim-beginning-of-code-or-line)
855 ("C-e" . mwim-end-of-code-or-line)
856 ("<home>" . mwim-beginning-of-line-or-code)
857 ("<end>" . mwim-end-of-line-or-code)))
858
859 (use-package projectile
860 :defer t
861 :bind-keymap ("C-c p" . projectile-command-map)
862 :config
863 (projectile-mode)
864
865 (defun my-projectile-invalidate-cache (&rest _args)
866 ;; ignore the args to `magit-checkout'
867 (projectile-invalidate-cache nil))
868
869 (eval-after-load 'magit-branch
870 '(progn
871 (advice-add 'magit-checkout
872 :after #'my-projectile-invalidate-cache)
873 (advice-add 'magit-branch-and-checkout
874 :after #'my-projectile-invalidate-cache))))
875
876 (use-package helpful
877 :defer 1
878 :bind
879 (("C-S-h c" . helpful-command)
880 ("C-S-h f" . helpful-callable) ; helpful-function
881 ("C-S-h v" . helpful-variable)
882 ("C-S-h k" . helpful-key)
883 ("C-S-h p" . helpful-at-point)))
884
885 (use-package shell-toggle
886 :after eshell
887 :bind ("C-c a s e" . amin/shell-toggle)
888 :config
889 (defun amin/shell-toggle (make-cd)
890 "Toggle between the shell buffer and whatever buffer you are editing.
891 With a prefix argument MAKE-CD also insert a \"cd DIR\" command
892 into the shell, where DIR is the directory of the current buffer.
893
894 When called in the shell buffer returns you to the buffer you were editing
895 before calling this the first time.
896
897 Options: `shell-toggle-goto-eob'"
898 (interactive "P")
899 ;; Try to decide on one of three possibilities:
900 ;; If not in shell-buffer, switch to it.
901 ;; If in shell-buffer, return to state before going to the shell-buffer
902 (if (eq (current-buffer) shell-toggle-shell-buffer)
903 (shell-toggle-buffer-return-from-shell)
904 (progn
905 (shell-toggle-buffer-goto-shell make-cd)
906 (if shell-toggle-full-screen-window-only (delete-other-windows)))))
907
908 ;; override to split horizontally instead
909 (defun shell-toggle-buffer-switch-to-other-window ()
910 "Switch to other window.
911 If the current window is the only window in the current frame,
912 create a new window and switch to it.
913
914 \(This is less intrusive to the current window configuration than
915 `switch-buffer-other-window')"
916 (let ((this-window (selected-window)))
917 (other-window 1)
918 ;; If we did not switch window then we only have one window and need to
919 ;; create a new one.
920 (if (eq this-window (selected-window))
921 (progn
922 (split-window-horizontally)
923 (other-window 1)))))
924
925 :custom
926 (shell-toggle-launch-shell 'shell-toggle-eshell))
927
928 (use-package unkillable-scratch
929 :defer 3
930 :config
931 (unkillable-scratch 1)
932 :custom
933 (unkillable-scratch-behavior 'do-nothing)
934 (unkillable-buffers '("^\\*scratch\\*$" "^\\*Messages\\*$")))
935
936 (use-package boxquote
937 :defer 3
938 :bind
939 (:prefix-map amin--boxquote-prefix-map
940 :prefix "C-c q"
941 ("b" . boxquote-buffer)
942 ("B" . boxquote-insert-buffer)
943 ("d" . boxquote-defun)
944 ("F" . boxquote-insert-file)
945 ("hf" . boxquote-describe-function)
946 ("hk" . boxquote-describe-key)
947 ("hv" . boxquote-describe-variable)
948 ("hw" . boxquote-where-is)
949 ("k" . boxquote-kill)
950 ("p" . boxquote-paragraph)
951 ("q" . boxquote-boxquote)
952 ("r" . boxquote-region)
953 ("s" . boxquote-shell-command)
954 ("t" . boxquote-text)
955 ("T" . boxquote-title)
956 ("u" . boxquote-unbox)
957 ("U" . boxquote-unbox-region)
958 ("y" . boxquote-yank)
959 ("M-q" . boxquote-fill-paragraph)
960 ("M-w" . boxquote-kill-ring-save)))
961
962 (use-package highlight-indent-guides
963 :disabled t
964 :defer 3
965 :hook ((prog-mode . highlight-indent-guides-mode)
966 ;; (org-mode . highlight-indent-guides-mode)
967 )
968 :config
969 (setq highlight-indent-guides-character ?\|)
970 (setq highlight-indent-guides-auto-enabled nil)
971 (setq highlight-indent-guides-method 'character)
972 (setq highlight-indent-guides-responsive 'top)
973 (set-face-foreground 'highlight-indent-guides-character-face "gainsboro")
974 (set-face-foreground 'highlight-indent-guides-top-character-face "grey40")) ; grey13 is nice too
975
976 (use-package pdf-tools
977 :defer t
978 :magic ("%PDF" . pdf-view-mode)
979 :config
980 (setq pdf-view-resize-factor 1.05)
981 (pdf-tools-install)
982 :bind
983 (:map pdf-view-mode-map
984 ("C-s" . isearch-forward)
985 ("C-r" . isearch-backward)
986 ("j" . pdf-view-next-line-or-next-page)
987 ("k" . pdf-view-previous-line-or-previous-page)
988 ("h" . image-backward-hscroll)
989 ("l" . image-forward-hscroll)))
990
991 (use-package anzu)
992
993 (use-package typo
994 :defer 2
995 :config
996 (typo-global-mode 1)
997 :hook (text-mode . typo-mode))
998
999 (use-package hl-todo
1000 :defer 4
1001 :config
1002 (global-hl-todo-mode))
1003
1004 (use-package shrink-path
1005 :after eshell
1006 :config
1007 (setq eshell-prompt-regexp "\\(.*\n\\)*λ "
1008 eshell-prompt-function #'+eshell/prompt)
1009
1010 (defun +eshell/prompt ()
1011 (let ((base/dir (shrink-path-prompt default-directory)))
1012 (concat (propertize (car base/dir)
1013 'face 'font-lock-comment-face)
1014 (propertize (cdr base/dir)
1015 'face 'font-lock-constant-face)
1016 (propertize (+eshell--current-git-branch)
1017 'face 'font-lock-function-name-face)
1018 "\n"
1019 (propertize "λ" 'face 'eshell-prompt-face)
1020 ;; needed for the input text to not have prompt face
1021 (propertize " " 'face 'default))))
1022
1023 (defun +eshell--current-git-branch ()
1024 (let ((branch (car (loop for match in (split-string (shell-command-to-string "git branch") "\n")
1025 when (string-match "^\*" match)
1026 collect match))))
1027 (if (not (eq branch nil))
1028 (concat " " (substring branch 2))
1029 ""))))
1030
1031 (use-package slack
1032 :disabled t
1033 :commands (slack-start)
1034 :init
1035 (eval-when-compile ; silence the byte-compiler
1036 (defvar url-http-data nil)
1037 (defvar url-http-extra-headers nil)
1038 (defvar url-http-method nil)
1039 (defvar url-callback-function nil)
1040 (defvar url-callback-arguments nil)
1041 (defvar oauth--token-data nil))
1042 (setq slack-buffer-emojify t
1043 slack-prefer-current-team t)
1044 :config
1045 (slack-register-team
1046 :name "uw-apv"
1047 :default t
1048 :client-id uw-apv-client-id
1049 :client-secret uw-apv-client-secret
1050 :token uw-apv-token
1051 :subscribed-channels '(general)
1052 :full-and-display-names t)
1053 (slack-register-team
1054 :name "watform"
1055 :default nil
1056 :client-id watform-client-id
1057 :client-secret watform-client-secret
1058 :token watform-token
1059 :subscribed-channels '(general)
1060 :full-and-display-names t)
1061 (add-to-list 'swiper-font-lock-exclude 'slack-message-buffer-mode t)
1062 (setq lui-time-stamp-format "[%Y-%m-%d %H:%M:%S]"
1063 lui-time-stamp-only-when-changed-p t
1064 lui-time-stamp-position 'right)
1065 :bind
1066 (("C-c s s" . slack-start)
1067 ("C-c s u" . slack-select-unread-rooms)
1068 ("C-c s b" . slack-select-rooms)
1069 ("C-c s t" . slack-change-current-team)
1070 ("C-c s c" . slack-ws-close)
1071 :map slack-mode-map
1072 ("M-p" . slack-buffer-goto-prev-message)
1073 ("M-n" . slack-buffer-goto-next-message)
1074 ("C-c e" . slack-message-edit)
1075 ("C-c k" . slack-message-delete)
1076 ("C-c C-k" . slack-channel-leave)
1077 ("C-c r a" . slack-message-add-reaction)
1078 ("C-c r r" . slack-message-remove-reaction)
1079 ("C-c r s" . slack-message-show-reaction-users)
1080 ("C-c p l" . slack-room-pins-list)
1081 ("C-c p a" . slack-message-pins-add)
1082 ("C-c p r" . slack-message-pins-remove)
1083 ("@" . slack-message-embed-mention)
1084 ("#" . slack-message-embed-channel)))
1085
1086 (use-package alert
1087 :commands (alert)
1088 :init
1089 (setq alert-default-style 'notifier))
1090
1091 (use-package eshell-up
1092 :after eshell)
1093
1094 (use-package multi-term
1095 :defer 1
1096 :bind (("C-c C-j" . term-line-mode)
1097 ("C-c a s m m" . multi-term)
1098 ("C-c a s m p" . multi-term-dedicated-toggle))
1099 :config
1100 (setq multi-term-program "/bin/screen"
1101 ;; TODO: add separate bindings for connecting to existing
1102 ;; session vs. always creating a new one
1103 multi-term-dedicated-select-after-open-p t
1104 multi-term-dedicated-window-height 20
1105 multi-term-dedicated-max-window-height 30
1106 term-bind-key-alist
1107 '(("C-c C-c" . term-interrupt-subjob)
1108 ("C-c C-e" . term-send-esc)
1109 ("C-k" . kill-line)
1110 ("C-y" . term-paste)
1111 ("M-f" . term-send-forward-word)
1112 ("M-b" . term-send-backward-word)
1113 ("M-p" . term-send-up)
1114 ("M-n" . term-send-down)
1115 ("<C-backspace>" . term-send-backward-kill-word)
1116 ("<M-DEL>" . term-send-backward-kill-word)
1117 ("M-d" . term-send-delete-word)
1118 ("M-," . term-send-raw)
1119 ("M-." . comint-dynamic-complete))
1120 term-unbind-key-alist
1121 '("C-z" "C-x" "C-c" "C-h" "C-y" "<ESC>")))
1122
1123 (use-package page-break-lines
1124 :config
1125 (global-page-break-lines-mode))
1126
1127 \f
1128 ;; * Email
1129
1130 (defvar amin-maildir (expand-file-name "~/mail/"))
1131 (after! recentf
1132 (add-to-list 'recentf-exclude amin-maildir))
1133
1134 (setq
1135 amin-gnus-init-file (no-littering-expand-etc-file-name "gnus")
1136 mail-user-agent 'gnus-user-agent
1137 read-mail-command 'gnus)
1138
1139 (use-package gnus
1140 :bind (("s-m" . gnus)
1141 ("s-M" . gnus-unplugged))
1142 :init
1143 (setq
1144 gnus-select-method '(nnnil "")
1145 gnus-secondary-select-methods
1146 '((nnimap "amin"
1147 (nnimap-stream plain)
1148 (nnimap-address "127.0.0.1")
1149 (nnimap-server-port 143)
1150 (nnimap-authenticator plain)
1151 (nnimap-user "amin@aminb.org"))
1152 (nnimap "uwaterloo"
1153 (nnimap-stream plain)
1154 (nnimap-address "127.0.0.1")
1155 (nnimap-server-port 143)
1156 (nnimap-authenticator plain)
1157 (nnimap-user "abandali@uwaterloo.ca")))
1158 gnus-message-archive-group "nnimap+amin:Sent"
1159 gnus-parameters
1160 '(("gnu.*"
1161 (gcc-self . t)))
1162 gnus-large-newsgroup 50
1163 gnus-home-directory (no-littering-expand-var-file-name "gnus/")
1164 gnus-directory (concat gnus-home-directory "news/")
1165 message-directory (concat gnus-home-directory "mail/")
1166 nndraft-directory (concat gnus-home-directory "drafts/")
1167 gnus-save-newsrc-file nil
1168 gnus-read-newsrc-file nil
1169 gnus-interactive-exit nil
1170 gnus-gcc-mark-as-read t))
1171
1172 (use-package gnus-art
1173 :config
1174 (setq
1175 gnus-visible-headers
1176 (concat gnus-visible-headers "\\|^List-Id:\\|^X-RT-Originator:\\|^User-Agent:")
1177 gnus-sorted-header-list
1178 '("^From:" "^Subject:" "^Summary:" "^Keywords:"
1179 "^Followup-To:" "^To:" "^Cc:" "X-RT-Originator"
1180 "^Newsgroups:" "List-Id:" "^Organization:"
1181 "^User-Agent:" "^Date:")
1182 ;; local-lapsed article dates
1183 ;; from https://www.emacswiki.org/emacs/GnusFormatting#toc11
1184 gnus-article-date-headers '(user-defined)
1185 gnus-article-time-format
1186 (lambda (time)
1187 (let* ((date (format-time-string "%a, %d %b %Y %T %z" time))
1188 (local (article-make-date-line date 'local))
1189 (combined-lapsed (article-make-date-line date
1190 'combined-lapsed))
1191 (lapsed (progn
1192 (string-match " (.+" combined-lapsed)
1193 (match-string 0 combined-lapsed))))
1194 (concat local lapsed))))
1195 (bind-keys
1196 :map gnus-article-mode-map
1197 ("r" . gnus-article-reply-with-original)
1198 ("R" . gnus-article-wide-reply-with-original)
1199 ("M-L" . org-store-link)))
1200
1201 (use-package gnus-sum
1202 :bind (:map gnus-summary-mode-map
1203 :prefix-map amin--gnus-summary-prefix-map
1204 :prefix "v"
1205 ("r" . gnus-summary-reply)
1206 ("w" . gnus-summary-wide-reply)
1207 ("v" . gnus-summary-show-raw-article))
1208 :config
1209 (bind-keys
1210 :map gnus-summary-mode-map
1211 ("r" . gnus-summary-reply-with-original)
1212 ("R" . gnus-summary-wide-reply-with-original)
1213 ("M-L" . org-store-link))
1214 :hook (gnus-summary-mode . amin--no-mouse-autoselect-window))
1215
1216 (use-package gnus-msg
1217 :config
1218 (setq gnus-posting-styles
1219 '((".*"
1220 (address "amin@aminb.org")
1221 (body "\nBest,\namin\n")
1222 (eval (setq amin--message-cite-say-hi t)))
1223 ("gnu.*"
1224 (address "bandali@gnu.org"))
1225 ((header "subject" "ThankCRM")
1226 (to "webmasters-comment@gnu.org")
1227 (body "\nAdded to 2018supporters.html.\n\nMoving to campaigns.\n\n-amin\n")
1228 (eval (setq amin--message-cite-say-hi nil)))
1229 ("nnimap\\+uwaterloo:.*"
1230 (address "abandali@uwaterloo.ca")
1231 (gcc "\"nnimap+uwaterloo:Sent Items\"")))))
1232
1233 (use-package gnus-topic
1234 :hook (gnus-group-mode . gnus-topic-mode))
1235
1236 (use-package gnus-agent
1237 :config
1238 (setq gnus-agent-synchronize-flags 'ask)
1239 :hook (gnus-group-mode . gnus-agent-mode))
1240
1241 (use-package gnus-group
1242 :config
1243 (setq gnus-permanently-visible-groups "\\((INBOX\\|gnu$\\)"))
1244
1245 (use-package mm-decode
1246 :config
1247 (setq mm-discouraged-alternatives '("text/html" "text/richtext")))
1248
1249 (use-package sendmail
1250 :config
1251 (setq sendmail-program "/usr/bin/msmtp"
1252 ;; message-sendmail-extra-arguments '("-v" "-d")
1253 mail-specify-envelope-from t
1254 mail-envelope-from 'header))
1255
1256 (use-package message
1257 :config
1258 (defconst amin--message-cite-style-format "On %Y-%m-%d %l:%M %p, %N wrote:")
1259 (defconst message-cite-style-bandali
1260 '((message-cite-function 'message-cite-original)
1261 (message-citation-line-function 'message-insert-formatted-citation-line)
1262 (message-cite-reply-position 'traditional)
1263 (message-yank-prefix "> ")
1264 (message-yank-cited-prefix ">")
1265 (message-yank-empty-prefix ">")
1266 (message-citation-line-format
1267 (if amin--message-cite-say-hi
1268 (concat "Hi %F,\n\n" amin--message-cite-style-format)
1269 amin--message-cite-style-format)))
1270 "Citation style based on Mozilla Thunderbird's. Use with message-cite-style.")
1271 (setq message-cite-style 'message-cite-style-bandali
1272 message-kill-buffer-on-exit t
1273 message-send-mail-function 'message-send-mail-with-sendmail
1274 message-sendmail-envelope-from 'header
1275 message-dont-reply-to-names
1276 "\\(\\(.*@aminb\\.org\\)\\|\\(amin@bandali\\.me\\)\\|\\(\\(aminb?\\|mab\\|bandali\\)@gnu\\.org\\)\\|\\(\\(m\\|a\\(min\\.\\)?\\)bandali@uwaterloo\\.ca\\)\\)"
1277 message-user-fqdn "aminb.org")
1278 :hook (;; (message-setup . mml-secure-message-sign-pgpmime)
1279 (message-mode . flyspell-mode)
1280 (message-mode . (lambda ()
1281 ;; (setq fill-column 65
1282 ;; message-fill-column 65)
1283 (make-local-variable 'company-idle-delay)
1284 (setq company-idle-delay 0.2))))
1285 ;; :custom-face
1286 ;; (message-header-subject ((t (:foreground "#111" :weight semi-bold))))
1287 ;; (message-header-to ((t (:foreground "#111" :weight normal))))
1288 ;; (message-header-cc ((t (:foreground "#333" :weight normal))))
1289 )
1290
1291 (after! mml-sec
1292 (setq mml-secure-openpgp-encrypt-to-self t
1293 mml-secure-openpgp-sign-with-sender t))
1294
1295 (use-package footnote
1296 :after message
1297 :bind
1298 (:map message-mode-map
1299 :prefix-map amin--footnote-prefix-map
1300 :prefix "C-c f"
1301 ("a" . footnote-add-footnote)
1302 ("b" . footnote-back-to-message)
1303 ("c" . footnote-cycle-style)
1304 ("d" . footnote-delete-footnote)
1305 ("g" . footnote-goto-footnote)
1306 ("r" . footnote-renumber-footnotes)
1307 ("s" . footnote-set-style))
1308 :config
1309 (setq footnote-start-tag ""
1310 footnote-end-tag ""
1311 footnote-style 'unicode))
1312
1313 (use-package bbdb
1314 :load-path "lisp/bbdb"
1315 :init
1316 (load (expand-file-name "lisp/bbdb/bbdb-autoloads.el" user-emacs-directory))
1317 ;; (bbdb-mua-auto-update-init 'message)
1318 (setq bbdb-mua-auto-update-p 'query
1319 bbdb-complete-mail nil)
1320 (bbdb-initialize 'gnus 'message))
1321
1322 (use-package message-x
1323 :disabled t
1324 :custom
1325 (message-x-completion-alist
1326 (quote
1327 (("\\([rR]esent-\\|[rR]eply-\\)?[tT]o:\\|[bB]?[cC][cC]:" . gnus-harvest-find-address)
1328 ((if
1329 (boundp
1330 (quote message-newgroups-header-regexp))
1331 message-newgroups-header-regexp message-newsgroups-header-regexp)
1332 . message-expand-group)))))
1333
1334 (use-package gnus-harvest
1335 :disabled t
1336 :commands gnus-harvest-install
1337 :demand t
1338 :config
1339 (if (featurep 'message-x)
1340 (gnus-harvest-install 'message-x)
1341 (gnus-harvest-install)))
1342
1343 \f
1344 ;; * Blogging
1345
1346 (use-package ox-hugo
1347 :after ox)
1348
1349 (use-package ox-hugo-auto-export
1350 :load-path "lib/ox-hugo")
1351
1352 \f
1353 ;; * Post initialization
1354
1355 (message "Loading %s...done (%.3fs)" user-init-file
1356 (float-time (time-subtract (current-time)
1357 amin--before-user-init-time)))
1358
1359 ;;; init.el ends here