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