9a420d08d54406d2191c3520183c3acf69f5d5b2
[~bandali/configs] / init.org
1 #+title: =aminb='s Literate Emacs Configuration
2 #+author: Amin Bandali
3 #+babel: :cache yes
4 #+property: header-args :tangle yes
5
6 * About
7 :PROPERTIES:
8 :CUSTOM_ID: about
9 :END:
10
11 This org file is my literate configuration for GNU Emacs, and is
12 tangled to [[./init.el][init.el]]. Packages are installed and managed using
13 [[https://github.com/emacscollective/borg][Borg]]. Over the years, I've taken inspiration from configurations of
14 many different people. Some of the configurations that I can remember
15 off the top of my head are:
16
17 - [[https://github.com/dieggsy/dotfiles][dieggsy/dotfiles]]: literate Emacs and dotfiles configuration, uses
18 straight.el for managing packages
19 - [[https://github.com/dakra/dmacs][dakra/dmacs]]: literate Emacs configuration, using Borg for managing
20 packages
21 - [[http://pages.sachachua.com/.emacs.d/Sacha.html][Sacha Chua's literate Emacs configuration]]
22 - [[https://github.com/dakrone/eos][dakrone/eos]]
23 - Ryan Rix's [[http://doc.rix.si/cce/cce.html][Complete Computing Environment]] ([[http://doc.rix.si/projects/fsem.html][about cce]])
24 - [[https://github.com/jwiegley/dot-emacs][jwiegley/dot-emacs]]: nix-based configuration
25 - [[https://github.com/wasamasa/dotemacs][wasamasa/dotemacs]]
26 - [[https://github.com/hlissner/doom-emacs][Doom Emacs]]
27
28 I'd like to have a fully reproducible Emacs setup (part of the reason
29 why I store my configuration in this repository) but unfortunately out
30 of the box, that's not achievable with =package.el=, not currently
31 anyway. So, I've opted to use Borg. For what it's worth, I briefly
32 experimented with [[https://github.com/raxod502/straight.el][straight.el]], but found that it added about 2 seconds
33 to my init time; which is unacceptable for me: I use Emacs as my
34 window manager (via EXWM) and coming from bspwm, I'm too used to
35 having fast startup times.
36
37 ** Installation
38
39 To use this config for your Emacs, first you need to clone this repo,
40 then bootstrap Borg, tell Borg to retrieve package submodules, and
41 byte-compiled the packages. Something along these lines should work:
42
43 #+begin_src sh :tangle no
44 git clone https://github.com/aminb/dotfiles ~/.emacs.d
45 cd ~/.emacs.d
46 make bootstrap-borg
47 make bootstrap
48 make build
49 #+end_src
50
51 * Contents :toc_1:noexport:
52
53 - [[#about][About]]
54 - [[#header][Header]]
55 - [[#initial-setup][Initial setup]]
56 - [[#core][Core]]
57 - [[#borg-essentials][Borg's =layer/essentials=]]
58 - [[#editing][Editing]]
59 - [[#syntax-spell-checking][Syntax and spell checking]]
60 - [[#programming-modes][Programming modes]]
61 - [[#emacs-enhancements][Emacs enhancements]]
62 - [[#email][Email]]
63 - [[#blogging][Blogging]]
64 - [[#post-initialization][Post initialization]]
65 - [[#footer][Footer]]
66
67 * Header
68 :PROPERTIES:
69 :CUSTOM_ID: header
70 :END:
71
72 ** First line
73
74 #+begin_src emacs-lisp :comments none
75 ;;; init.el --- Amin Bandali's Emacs config -*- lexical-binding: t; eval: (view-mode 1) -*-
76 #+end_src
77
78 Enable =view-mode=, which both makes the file read-only (as a reminder
79 that =init.el= is an auto-generated file, not supposed to be edited),
80 and provides some convenient key bindings for browsing through the
81 file.
82
83 ** License
84
85 #+begin_src emacs-lisp :comments none
86 ;; Copyright (C) 2018 Amin Bandali <bandali@gnu.org>
87
88 ;; This program is free software: you can redistribute it and/or modify
89 ;; it under the terms of the GNU General Public License as published by
90 ;; the Free Software Foundation, either version 3 of the License, or
91 ;; (at your option) any later version.
92
93 ;; This program is distributed in the hope that it will be useful,
94 ;; but WITHOUT ANY WARRANTY; without even the implied warranty of
95 ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
96 ;; GNU General Public License for more details.
97
98 ;; You should have received a copy of the GNU General Public License
99 ;; along with this program. If not, see <https://www.gnu.org/licenses/>.
100 #+end_src
101
102 ** Commentary
103
104 #+begin_src emacs-lisp :comments none
105 ;;; Commentary:
106
107 ;; Emacs configuration of Amin Bandali, computer scientist, functional
108 ;; programmer, and free software advocate.
109
110 ;; THIS FILE IS AUTO-GENERATED FROM `init.org'.
111 #+end_src
112
113 * Initial setup
114 :PROPERTIES:
115 :CUSTOM_ID: initial-setup
116 :END:
117
118 ** Emacs initialization
119
120 I'd like to do a couple of measurements of Emacs' startup time. First,
121 let's see how long Emacs takes to start up, before even loading
122 =init.el=, i.e. =user-init-file=:
123
124 #+begin_src emacs-lisp
125 (defvar a/before-user-init-time (current-time)
126 "Value of `current-time' when Emacs begins loading `user-init-file'.")
127 (message "Loading Emacs...done (%.3fs)"
128 (float-time (time-subtract a/before-user-init-time
129 before-init-time)))
130 #+end_src
131
132 Also, temporarily increase ~gc-cons-threshhold~ and
133 ~gc-cons-percentage~ during startup to reduce garbage collection
134 frequency. Clearing the ~file-name-handler-alist~ seems to help reduce
135 startup time as well.
136
137 #+begin_src emacs-lisp
138 (defvar a/gc-cons-threshold gc-cons-threshold)
139 (defvar a/gc-cons-percentage gc-cons-percentage)
140 (defvar a/file-name-handler-alist file-name-handler-alist)
141 (setq gc-cons-threshold (* 400 1024 1024) ; 400 MiB
142 gc-cons-percentage 0.6
143 file-name-handler-alist nil
144 ;; sidesteps a bug when profiling with esup
145 esup-child-profile-require-level 0)
146 #+end_src
147
148 Of course, we'd like to set them back to their defaults once we're
149 done initializing.
150
151 #+begin_src emacs-lisp
152 (add-hook
153 'after-init-hook
154 (lambda ()
155 (setq gc-cons-threshold a/gc-cons-threshold
156 gc-cons-percentage a/gc-cons-percentage
157 file-name-handler-alist a/file-name-handler-alist)))
158 #+end_src
159
160 Increase the number of lines kept in message logs (the =*Messages*=
161 buffer).
162
163 #+begin_src emacs-lisp
164 (setq message-log-max 20000)
165 #+end_src
166
167 Optionally, we could suppress some byte compiler warnings like below,
168 but for now I've decided to keep them enabled. See documentation for
169 ~byte-compile-warnings~ for more details.
170
171 #+begin_src emacs-lisp
172 ;; (setq byte-compile-warnings
173 ;; '(not free-vars unresolved noruntime lexical make-local))
174 #+end_src
175
176 ** whoami
177
178 #+begin_src emacs-lisp
179 (setq user-full-name "Amin Bandali"
180 user-mail-address "amin@aminb.org")
181 #+end_src
182
183 ** Package management
184
185 *** No =package.el=
186
187 I can do all my package management things with Borg, and don't need
188 Emacs' built-in =package.el=. Emacs 27 lets us disable =package.el= in
189 the =early-init-file= (see [[https://git.savannah.gnu.org/cgit/emacs.git/commit/?id=24acb31c04b4048b85311d794e600ecd7ce60d3b][here]]).
190
191 #+begin_src emacs-lisp :tangle early-init.el
192 (setq package-enable-at-startup nil)
193 #+end_src
194
195 But since Emacs 27 isn't out yet (Emacs 26 is just around the corner
196 right now), and even when released it'll be long before most distros
197 ship in their repos, I'll still put the old workaround with the
198 commented call to ~package-initialize~ here anyway.
199
200 #+begin_src emacs-lisp
201 (setq package-enable-at-startup nil)
202 ;; (package-initialize)
203 #+end_src
204
205 *** Borg
206
207 #+begin_quote
208 Assimilate Emacs packages as Git submodules
209 #+end_quote
210
211 [[https://github.com/emacscollective/borg][Borg]] is at the heart of package management of my Emacs setup. In
212 short, it creates a git submodule in =lib/= for each package, which
213 can then be managed with the help of Magit or other tools.
214
215 #+begin_src emacs-lisp
216 (setq user-init-file (or load-file-name buffer-file-name)
217 user-emacs-directory (file-name-directory user-init-file))
218 (add-to-list 'load-path
219 (expand-file-name "lib/borg" user-emacs-directory))
220 (require 'borg)
221 (borg-initialize)
222
223 ;; (require 'borg-nix-shell)
224 ;; (setq borg-build-shell-command 'borg-nix-shell-build-command)
225
226 (with-eval-after-load 'bind-key
227 (bind-keys
228 :package borg
229 ("C-c b A" . borg-activate)
230 ("C-c b a" . borg-assimilate)
231 ("C-c b b" . borg-build)
232 ("C-c b c" . borg-clone)
233 ("C-c b r" . borg-remove)))
234 #+end_src
235
236 *** =use-package=
237
238 #+begin_quote
239 A use-package declaration for simplifying your .emacs
240 #+end_quote
241
242 [[https://github.com/jwiegley/use-package][use-package]] is an awesome utility for managing and configuring
243 packages (in our case especially the latter) in a neatly organized way
244 and without compromising on performance.
245
246 #+begin_src emacs-lisp
247 (require 'use-package)
248 (if nil ; set to t when need to debug init
249 (setq use-package-verbose t
250 use-package-expand-minimally nil
251 use-package-compute-statistics t
252 debug-on-error t)
253 (setq use-package-verbose nil
254 use-package-expand-minimally t))
255 #+end_src
256
257 *** Epkg
258
259 #+begin_quote
260 Browse the Emacsmirror package database
261 #+end_quote
262
263 Epkg provides access to a local copy of the [[https://emacsmirror.net][Emacsmirror]] package
264 database, low-level functions for querying the database, and a
265 =package.el=-like user interface for browsing the available packages.
266
267 #+begin_src emacs-lisp
268 (use-package epkg
269 :defer t
270 :bind
271 (("C-c b d" . epkg-describe-package)
272 ("C-c b p" . epkg-list-packages)
273 ("C-c b u" . epkg-update))
274 :config
275 (eval-when-compile (defvar ivy-initial-inputs-alist))
276 (with-eval-after-load 'ivy
277 (add-to-list
278 'ivy-initial-inputs-alist '(epkg-describe-package . "^") t)))
279 #+end_src
280
281 ** No littering in =~/.emacs.d=
282
283 #+begin_quote
284 Help keeping ~/.emacs.d clean
285 #+end_quote
286
287 By default, even for Emacs' built-in packages, the configuration files
288 and persistent data are all over the place. Use =no-littering= to help
289 contain the mess.
290
291 #+begin_src emacs-lisp
292 (use-package no-littering
293 :demand t
294 :config
295 (savehist-mode 1)
296 (add-to-list 'savehist-additional-variables 'kill-ring)
297 (save-place-mode 1)
298 (setq auto-save-file-name-transforms
299 `((".*" ,(no-littering-expand-var-file-name "auto-save/") t))))
300 #+end_src
301
302 ** Custom file (=custom.el=)
303
304 I'm not planning on using the custom file much, but even so, I
305 definitely don't want it mixing with =init.el=. So, here; let's give
306 it it's own file. While at it, treat themes as safe.
307
308 #+begin_src emacs-lisp
309 (use-package custom
310 :no-require t
311 :config
312 (setq custom-file (no-littering-expand-etc-file-name "custom.el"))
313 (when (file-exists-p custom-file)
314 (load custom-file))
315 (setf custom-safe-themes t))
316 #+end_src
317
318 ** Secrets file
319
320 Load the secrets file if it exists, otherwise show a warning.
321
322 #+begin_src emacs-lisp
323 (with-demoted-errors
324 (load (no-littering-expand-etc-file-name "secrets")))
325 #+end_src
326
327 ** Better =$PATH= handling
328
329 Let's use [[https://github.com/purcell/exec-path-from-shell][exec-path-from-shell]] to make Emacs use the =$PATH= as set up
330 in my shell.
331
332 #+begin_src emacs-lisp
333 (use-package exec-path-from-shell
334 :defer 1
335 :init
336 (setq exec-path-from-shell-check-startup-files nil)
337 :config
338 (exec-path-from-shell-initialize)
339 ;; while we're at it, let's fix access to our running ssh-agent
340 (exec-path-from-shell-copy-env "SSH_AGENT_PID")
341 (exec-path-from-shell-copy-env "SSH_AUTH_SOCK"))
342 #+end_src
343
344 ** COMMENT Only one custom theme at a time
345
346 #+begin_src emacs-lisp
347 (defadvice load-theme (before clear-previous-themes activate)
348 "Clear existing theme settings instead of layering them"
349 (mapc #'disable-theme custom-enabled-themes))
350 #+end_src
351
352 ** Server
353
354 Start server if not already running. Alternatively, can be done by
355 issuing =emacs --daemon= in the terminal, which can be automated with
356 a systemd service or using =brew services start emacs= on macOS. I use
357 Emacs as my window manager (via EXWM), so I always start Emacs on
358 login; so starting the server from inside Emacs is good enough for me.
359
360 See [[https://www.gnu.org/software/emacs/manual/html_node/emacs/Emacs-Server.html#Emacs-Server][Using Emacs as a Server]].
361
362 #+begin_src emacs-lisp
363 (use-package server
364 :defer 1
365 :config (or (server-running-p) (server-mode)))
366 #+end_src
367
368 ** COMMENT Unicode support
369
370 Font stack with better unicode support, around =Ubuntu Mono= and
371 =Hack=.
372
373 #+begin_src emacs-lisp
374 (dolist (ft (fontset-list))
375 (set-fontset-font
376 ft
377 'unicode
378 (font-spec :name "Source Code Pro" :size 14))
379 (set-fontset-font
380 ft
381 'unicode
382 (font-spec :name "DejaVu Sans Mono")
383 nil
384 'append)
385 ;; (set-fontset-font
386 ;; ft
387 ;; 'unicode
388 ;; (font-spec
389 ;; :name "Symbola monospacified for DejaVu Sans Mono")
390 ;; nil
391 ;; 'append)
392 ;; (set-fontset-font
393 ;; ft
394 ;; #x2115 ; ℕ
395 ;; (font-spec :name "DejaVu Sans Mono")
396 ;; nil
397 ;; 'append)
398 (set-fontset-font
399 ft
400 (cons ?Α ?ω)
401 (font-spec :name "DejaVu Sans Mono" :size 14)
402 nil
403 'prepend))
404 #+end_src
405
406 ** Gentler font resizing
407
408 #+begin_src emacs-lisp
409 (setq text-scale-mode-step 1.05)
410 #+end_src
411
412 ** Focus follows mouse
413
414 I’d like focus to follow the mouse when I move the cursor from one
415 window to the next.
416
417 #+begin_src emacs-lisp
418 (setq mouse-autoselect-window t)
419 #+end_src
420
421 Let’s define a function to conveniently disable this for certain
422 buffers and/or modes.
423
424 #+begin_src emacs-lisp
425 (defun a/no-mouse-autoselect-window ()
426 (make-local-variable 'mouse-autoselect-window)
427 (setq mouse-autoselect-window nil))
428 #+end_src
429
430 ** Libraries
431
432 #+begin_src emacs-lisp
433 (require 'cl-lib)
434 (require 'subr-x)
435 #+end_src
436
437 ** Useful utilities
438
439 Convenience macro for =setq='ing multiple variables to the same value:
440
441 #+begin_src emacs-lisp
442 (defmacro a/setq-every (value &rest vars)
443 "Set all the variables from VARS to value VALUE."
444 (declare (indent defun) (debug t))
445 `(progn ,@(mapcar (lambda (x) (list 'setq x value)) vars)))
446 #+end_src
447
448 * Core
449 :PROPERTIES:
450 :CUSTOM_ID: core
451 :END:
452
453 ** Defaults
454
455 *** Time and battery in mode-line
456
457 Enable displaying time and battery in the mode-line, since I'm not
458 using the Xfce panel anymore. Also, I don't need to see the load
459 average on a regular basis, so disable that.
460
461 Note: using =i3status= on sway at the moment, so disabling this.
462
463 #+begin_src emacs-lisp :tangle no
464 (use-package time
465 :init
466 (setq display-time-default-load-average nil)
467 :config
468 (display-time-mode))
469
470 (use-package battery
471 :config
472 (display-battery-mode))
473 #+end_src
474
475 *** Smaller fringe
476
477 Might want to set the fringe to a smaller value, especially if using
478 EXWM. I'm fine with the default for now.
479
480 #+begin_src emacs-lisp
481 ;; (fringe-mode '(3 . 1))
482 (fringe-mode nil)
483 #+end_src
484
485 *** Disable disabled commands
486
487 Emacs disables some commands by default that could persumably be
488 confusing for novice users. Let's disable that.
489
490 #+begin_src emacs-lisp
491 (setq disabled-command-function nil)
492 #+end_src
493
494 *** Kill-ring
495
496 Save what I copy into clipboard from other applications into Emacs'
497 kill-ring, which would allow me to still be able to easily access it
498 in case I kill (cut or copy) something else inside Emacs before
499 yanking (pasting) what I'd originally intended to.
500
501 #+begin_src emacs-lisp
502 (setq save-interprogram-paste-before-kill t)
503 #+end_src
504
505 *** Minibuffer
506
507 #+begin_src emacs-lisp
508 (setq enable-recursive-minibuffers t
509 resize-mini-windows t)
510 #+end_src
511
512 *** Lazy-person-friendly yes/no prompts
513
514 Lazy people would prefer to type fewer keystrokes, especially for yes
515 or no questions. I'm lazy.
516
517 #+begin_src emacs-lisp
518 (defalias 'yes-or-no-p #'y-or-n-p)
519 #+end_src
520
521 *** Startup screen and =*scratch*=
522
523 Firstly, let Emacs know that I'd like to have =*scratch*= as my
524 startup buffer.
525
526 #+begin_src emacs-lisp
527 (setq initial-buffer-choice t)
528 #+end_src
529
530 Now let's customize the =*scratch*= buffer a bit. First off, I don't
531 need the default hint.
532
533 #+begin_src emacs-lisp
534 (setq initial-scratch-message nil)
535 #+end_src
536
537 Also, let's use Text mode as the major mode, in case I want to
538 customize it (=*scratch*='s default major mode, Fundamental mode,
539 can't really be customized).
540
541 #+begin_src emacs-lisp
542 (setq initial-major-mode 'text-mode)
543 #+end_src
544
545 Inhibit the buffer list when more than 2 files are loaded.
546
547 #+begin_src emacs-lisp
548 (setq inhibit-startup-buffer-menu t)
549 #+end_src
550
551 I don't really need to see the startup screen or echo area message
552 either.
553
554 #+begin_src emacs-lisp
555 (advice-add #'display-startup-echo-area-message :override #'ignore)
556 (setq inhibit-startup-screen t
557 inhibit-startup-echo-area-message user-login-name)
558 #+end_src
559
560 *** More useful frame titles
561
562 Show either the file name or the buffer name (in case the buffer isn't
563 visiting a file). Borrowed from Emacs Prelude.
564
565 #+begin_src emacs-lisp
566 (setq frame-title-format
567 '("" invocation-name " - "
568 (:eval (if (buffer-file-name)
569 (abbreviate-file-name (buffer-file-name))
570 "%b"))))
571 #+end_src
572
573 *** Backups
574
575 Emacs' default backup settings aren't that great. Let's use more
576 sensible options. See documentation for the ~make-backup-file~
577 variable.
578
579 #+begin_src emacs-lisp
580 (setq backup-by-copying t
581 version-control t
582 delete-old-versions t)
583 #+end_src
584
585 *** Auto revert
586
587 Enable automatic reloading of changed buffers and files.
588
589 #+begin_src emacs-lisp
590 (global-auto-revert-mode 1)
591 (setq auto-revert-verbose nil
592 global-auto-revert-non-file-buffers nil)
593 #+end_src
594
595 *** Always use space for indentation
596
597 #+begin_src emacs-lisp
598 (setq-default
599 indent-tabs-mode nil
600 require-final-newline t
601 tab-width 4)
602 #+end_src
603
604 *** Winner mode
605
606 Enable =winner-mode=.
607
608 #+begin_src emacs-lisp
609 (winner-mode 1)
610 #+end_src
611
612 *** Don’t display =*compilation*= on success
613
614 Based on https://stackoverflow.com/a/17788551, with changes to use
615 =cl-letf= instead of the now obsolete =flet=.
616
617 #+begin_src emacs-lisp
618 (with-eval-after-load 'compile
619 (defun a/compilation-finish-function (buffer outstr)
620 (unless (string-match "finished" outstr)
621 (switch-to-buffer-other-window buffer))
622 t)
623
624 (setq compilation-finish-functions #'a/compilation-finish-function)
625
626 (require 'cl-macs)
627
628 (defadvice compilation-start
629 (around inhibit-display
630 (command &optional mode name-function highlight-regexp))
631 (if (not (string-match "^\\(find\\|grep\\)" command))
632 (cl-letf (((symbol-function 'display-buffer) #'ignore))
633 (save-window-excursion ad-do-it))
634 ad-do-it))
635 (ad-activate 'compilation-start))
636 #+end_src
637
638 *** Search for non-ASCII characters
639
640 I’d like non-ASCII characters such as ‘’“”«»‹›áⓐ𝒶 to be selected when
641 I search for their ASCII counterpart. Shoutout to [[http://endlessparentheses.com/new-in-emacs-25-1-easily-search-non-ascii-characters.html][endlessparentheses]]
642 for this.
643
644 #+begin_src emacs-lisp
645 (setq search-default-mode #'char-fold-to-regexp)
646
647 ;; uncomment to extend this behaviour to query-replace
648 ;; (setq replace-char-fold t)
649 #+end_src
650
651 *** Cursor shape
652
653 #+begin_src emacs-lisp
654 (setq-default cursor-type 'bar)
655 #+end_src
656
657 ** Bindings
658
659 #+begin_src emacs-lisp
660 (bind-keys
661 ("C-c a i" . ielm)
662
663 ("C-c e b" . eval-buffer)
664 ("C-c e r" . eval-region)
665
666 ("C-c F m" . make-frame-command)
667 ("C-c F d" . delete-frame)
668 ("C-c F D" . delete-other-frames)
669
670 ("C-c o" . other-window)
671
672 ("C-c Q" . save-buffers-kill-terminal)
673
674 ("C-S-h C" . describe-char)
675 ("C-S-h F" . describe-face)
676
677 ("C-x K" . kill-this-buffer)
678
679 ("s-p" . beginning-of-buffer)
680 ("s-n" . end-of-buffer))
681 #+end_src
682
683 ** Packages
684
685 The packages in this section are absolutely essential to my everyday
686 workflow, and they play key roles in how I do my computing. They
687 immensely enhance the Emacs experience for me; both using Emacs, and
688 customizing it.
689
690 *** [[https://github.com/emacscollective/auto-compile][auto-compile]]
691
692 #+begin_src emacs-lisp
693 (use-package auto-compile
694 :demand t
695 :config
696 (auto-compile-on-load-mode)
697 (auto-compile-on-save-mode)
698 (setq auto-compile-display-buffer nil
699 auto-compile-mode-line-counter t
700 auto-compile-source-recreate-deletes-dest t
701 auto-compile-toggle-deletes-nonlib-dest t
702 auto-compile-update-autoloads t)
703 (add-hook 'auto-compile-inhibit-compile-hook
704 'auto-compile-inhibit-compile-detached-git-head))
705 #+end_src
706
707 *** [[https://orgmode.org/][Org mode]]
708
709 #+begin_quote
710 Org mode is for keeping notes, maintaining TODO lists, planning
711 projects, and authoring documents with a fast and effective plain-text
712 system.
713 #+end_quote
714
715 In short, my favourite way of life.
716
717 #+begin_src emacs-lisp
718 (use-package org
719 :defer 1
720 :config
721 (setq org-src-tab-acts-natively t
722 org-src-preserve-indentation nil
723 org-edit-src-content-indentation 0
724 org-email-link-description-format "Email %c: %s" ; %.30s
725 org-highlight-latex-and-related '(entities)
726 org-use-speed-commands t
727 org-startup-folded 'content
728 org-catch-invisible-edits 'show-and-error
729 org-log-done 'time)
730 (add-to-list 'org-structure-template-alist '("L" . "src emacs-lisp") t)
731 (font-lock-add-keywords
732 'org-mode
733 '(("[ \t]*\\(#\\+\\(BEGIN\\|END\\|begin\\|end\\)_\\(\\S-+\\)\\)[ \t]*\\([^\n:]*\\)"
734 (1 '(:foreground "#5a5b5a" :background "#292b2b") t) ; directive
735 (3 '(:foreground "#81a2be" :background "#292b2b") t) ; kind
736 (4 '(:foreground "#c5c8c6") t))) ; title
737 t)
738 :bind (:map org-mode-map ("M-L" . org-insert-last-stored-link))
739 :hook ((org-mode . org-indent-mode)
740 (org-mode . auto-fill-mode)
741 (org-mode . flyspell-mode))
742 :custom
743 (org-latex-packages-alist '(("" "listings") ("" "color")))
744 :custom-face
745 '(org-block-begin-line ((t (:foreground "#5a5b5a" :background "#1d1f21"))))
746 '(org-block ((t (:background "#1d1f21"))))
747 '(org-latex-and-related ((t (:foreground "#b294bb")))))
748
749 (use-package ox-latex
750 :after ox
751 :config
752 (setq org-latex-listings 'listings
753 ;; org-latex-prefer-user-labels t
754 )
755 (add-to-list 'org-latex-packages-alist '("" "listings"))
756 (add-to-list 'org-latex-packages-alist '("" "color"))
757 (add-to-list 'org-latex-classes
758 '("IEEEtran" "\\documentclass[11pt]{IEEEtran}"
759 ("\\section{%s}" . "\\section*{%s}")
760 ("\\subsection{%s}" . "\\subsection*{%s}")
761 ("\\subsubsection{%s}" . "\\subsubsection*{%s}")
762 ("\\paragraph{%s}" . "\\paragraph*{%s}")
763 ("\\subparagraph{%s}" . "\\subparagraph*{%s}"))
764 t))
765
766 (use-package ox-beamer
767 :after ox)
768
769 (use-package orgalist
770 :after message
771 :hook (message-mode . orgalist-mode))
772 #+end_src
773
774 **** asynchronous tangle
775
776 =a/async-babel-tangle= is a function closely inspired by [[https://github.com/dieggsy/dotfiles/tree/cc10edf7701958eff1cd94d4081da544d882a28c/emacs.d#dotfiles][dieggsy's
777 d/async-babel-tangle]] which uses [[https://github.com/jwiegley/emacs-async][async]] to asynchronously tangle an org
778 file.
779
780 #+begin_src emacs-lisp
781 (with-eval-after-load 'org
782 (defvar a/show-async-tangle-results nil
783 "Keep *emacs* async buffers around for later inspection.")
784
785 (defvar a/show-async-tangle-time nil
786 "Show the time spent tangling the file.")
787
788 (defvar a/async-tangle-post-compile "make ti"
789 "If non-nil, pass to `compile' after successful tangle.")
790
791 (defun a/async-babel-tangle ()
792 "Tangle org file asynchronously."
793 (interactive)
794 (let* ((file-tangle-start-time (current-time))
795 (file (buffer-file-name))
796 (file-nodir (file-name-nondirectory file))
797 ;; (async-quiet-switch "-q")
798 )
799 (async-start
800 `(lambda ()
801 (require 'org)
802 (org-babel-tangle-file ,file))
803 (unless a/show-async-tangle-results
804 `(lambda (result)
805 (if result
806 (progn
807 (message "Tangled %s%s"
808 ,file-nodir
809 (if a/show-async-tangle-time
810 (format " (%.3fs)"
811 (float-time (time-subtract (current-time)
812 ',file-tangle-start-time)))
813 ""))
814 (when a/async-tangle-post-compile
815 (compile a/async-tangle-post-compile)))
816 (message "Tangling %s failed" ,file-nodir))))))))
817
818 (add-to-list
819 'safe-local-variable-values
820 '(eval add-hook 'after-save-hook #'a/async-babel-tangle 'append 'local))
821 #+end_src
822
823 *** [[https://magit.vc/][Magit]]
824
825 #+begin_quote
826 It's Magit! A Git porcelain inside Emacs.
827 #+end_quote
828
829 Not just how I do git, but /the/ way to do git.
830
831 #+begin_src emacs-lisp
832 (use-package magit
833 :defer 1
834 :bind (("C-x g" . magit-status)
835 ("s-g s" . magit-status)
836 ("s-g l" . magit-log-buffer-file))
837 :config
838 (magit-add-section-hook 'magit-status-sections-hook
839 'magit-insert-modules
840 'magit-insert-stashes
841 'append)
842 (setq
843 magit-repository-directories '(("~/.emacs.d/" . 0)
844 ("~/src/git/" . 1)))
845 (nconc magit-section-initial-visibility-alist
846 '(([unpulled status] . show)
847 ([unpushed status] . show)))
848 :custom-face (magit-diff-file-heading ((t (:weight normal)))))
849 #+end_src
850
851 *** [[https://github.com/abo-abo/swiper][Ivy]] (and friends)
852
853 #+begin_quote
854 Ivy - a generic completion frontend for Emacs, Swiper - isearch with
855 an overview, and more. Oh, man!
856 #+end_quote
857
858 There's no way I could top that, so I won't attempt to.
859
860 **** Ivy
861
862 #+begin_src emacs-lisp
863 (use-package ivy
864 :defer 1
865 :bind
866 (:map ivy-minibuffer-map
867 ([escape] . keyboard-escape-quit)
868 ([S-up] . ivy-previous-history-element)
869 ([S-down] . ivy-next-history-element)
870 ("DEL" . ivy-backward-delete-char))
871 :config
872 (setq ivy-wrap t)
873 (ivy-mode 1)
874 ;; :custom-face
875 ;; (ivy-minibuffer-match-face-2 ((t (:background "#e99ce8" :weight semi-bold))))
876 ;; (ivy-minibuffer-match-face-3 ((t (:background "#bbbbff" :weight semi-bold))))
877 ;; (ivy-minibuffer-match-face-4 ((t (:background "#ffbbff" :weight semi-bold))))
878 )
879 #+end_src
880
881 **** Swiper
882
883 #+begin_src emacs-lisp
884 (use-package swiper
885 :bind (("C-s" . swiper)
886 ("C-r" . swiper)
887 ("C-S-s" . isearch-forward)))
888 #+end_src
889
890 **** Counsel
891
892 #+begin_src emacs-lisp
893 (use-package counsel
894 :defer 1
895 :bind (([remap execute-extended-command] . counsel-M-x)
896 ([remap find-file] . counsel-find-file)
897 ("s-r" . counsel-recentf)
898 ("C-c x" . counsel-M-x)
899 ("C-c f ." . counsel-find-file)
900 :map minibuffer-local-map
901 ("C-r" . counsel-minibuffer-history))
902 :config
903 (counsel-mode 1)
904 (defalias 'locate #'counsel-locate))
905 #+end_src
906
907 *** eshell
908
909 #+begin_src emacs-lisp
910 (use-package eshell
911 :defer 1
912 :commands eshell
913 :bind ("C-c a s e" . eshell)
914 :config
915 (eval-when-compile (defvar eshell-prompt-regexp))
916 (defun a/eshell-quit-or-delete-char (arg)
917 (interactive "p")
918 (if (and (eolp) (looking-back eshell-prompt-regexp nil))
919 (eshell-life-is-too-much)
920 (delete-char arg)))
921
922 (defun a/eshell-clear ()
923 (interactive)
924 (let ((inhibit-read-only t))
925 (erase-buffer))
926 (eshell-send-input))
927
928 (defun a/eshell-setup ()
929 (make-local-variable 'company-idle-delay)
930 (defvar company-idle-delay nil)
931 (bind-keys :map eshell-mode-map
932 ("C-d" . a/eshell-quit-or-delete-char)
933 ("C-S-l" . a/eshell-clear)
934 ("M-r" . counsel-esh-history)
935 ([tab] . company-complete)))
936
937 :hook (eshell-mode . a/eshell-setup)
938 :custom
939 (eshell-hist-ignoredups t)
940 (eshell-input-filter 'eshell-input-filter-initial-space))
941 #+end_src
942
943 *** Ibuffer
944
945 #+begin_src emacs-lisp
946 (use-package ibuffer
947 :defer t
948 :bind
949 (("C-x C-b" . ibuffer-other-window)
950 :map ibuffer-mode-map
951 ("P" . ibuffer-backward-filter-group)
952 ("N" . ibuffer-forward-filter-group)
953 ("M-p" . ibuffer-do-print)
954 ("M-n" . ibuffer-do-shell-command-pipe-replace))
955 :config
956 ;; Use human readable Size column instead of original one
957 (define-ibuffer-column size-h
958 (:name "Size" :inline t)
959 (cond
960 ((> (buffer-size) 1000000) (format "%7.1fM" (/ (buffer-size) 1000000.0)))
961 ((> (buffer-size) 100000) (format "%7.0fk" (/ (buffer-size) 1000.0)))
962 ((> (buffer-size) 1000) (format "%7.1fk" (/ (buffer-size) 1000.0)))
963 (t (format "%8d" (buffer-size)))))
964 :custom
965 (ibuffer-saved-filter-groups
966 '(("default"
967 ("dired" (mode . dired-mode))
968 ("org" (mode . org-mode))
969 ("gnus"
970 (or
971 (mode . gnus-group-mode)
972 (mode . gnus-summary-mode)
973 (mode . gnus-article-mode)
974 ;; not really, but...
975 (mode . message-mode)))
976 ("web"
977 (or
978 (mode . web-mode)
979 (mode . css-mode)
980 (mode . scss-mode)
981 (mode . js2-mode)))
982 ("shell"
983 (or
984 (mode . eshell-mode)
985 (mode . shell-mode)
986 (mode . term-mode)))
987 ("programming"
988 (or
989 (mode . python-mode)
990 (mode . c-mode)
991 (mode . c++-mode)
992 (mode . emacs-lisp-mode)
993 (mode . scheme-mode)
994 (mode . haskell-mode)
995 (mode . lean-mode)))
996 ("emacs"
997 (or
998 (name . "^\\*scratch\\*$")
999 (name . "^\\*Messages\\*$"))))))
1000 (ibuffer-formats
1001 '((mark modified read-only locked " "
1002 (name 18 18 :left :elide)
1003 " "
1004 (size-h 9 -1 :right)
1005 " "
1006 (mode 16 16 :left :elide)
1007 " " filename-and-process)
1008 (mark " "
1009 (name 16 -1)
1010 " " filename)))
1011 :hook (ibuffer . (lambda () (ibuffer-switch-to-saved-filter-groups "default"))))
1012 #+end_src
1013
1014 *** Outline
1015
1016 #+begin_src emacs-lisp
1017 (use-package outline
1018 :defer t
1019 :hook (prog-mode . outline-minor-mode)
1020 :bind
1021 (:map
1022 outline-minor-mode-map
1023 ("<s-tab>" . outline-toggle-children)
1024 ("M-p" . outline-previous-visible-heading)
1025 ("M-n" . outline-next-visible-heading)
1026 :prefix-map a/outline-prefix-map
1027 :prefix "s-o"
1028 ("TAB" . outline-toggle-children)
1029 ("a" . outline-hide-body)
1030 ("H" . outline-hide-body)
1031 ("S" . outline-show-all)
1032 ("h" . outline-hide-subtree)
1033 ("s" . outline-show-subtree)))
1034 #+end_src
1035
1036 * Borg's =layer/essentials=
1037 :PROPERTIES:
1038 :CUSTOM_ID: borg-essentials
1039 :END:
1040
1041 TODO: break this giant source block down into individual org sections.
1042
1043 #+begin_src emacs-lisp
1044 (use-package dash
1045 :config (dash-enable-font-lock))
1046
1047 (use-package diff-hl
1048 :config
1049 (setq diff-hl-draw-borders nil)
1050 (global-diff-hl-mode)
1051 (add-hook 'magit-post-refresh-hook 'diff-hl-magit-post-refresh t))
1052
1053 (use-package dired
1054 :defer t
1055 :config (setq dired-listing-switches "-alh"))
1056
1057 (use-package eldoc
1058 :when (version< "25" emacs-version)
1059 :config (global-eldoc-mode))
1060
1061 (use-package help
1062 :defer t
1063 :config
1064 (temp-buffer-resize-mode)
1065 (setq help-window-select t))
1066
1067 (progn ; `isearch'
1068 (setq isearch-allow-scroll t))
1069
1070 (use-package lisp-mode
1071 :config
1072 (add-hook 'emacs-lisp-mode-hook 'outline-minor-mode)
1073 (add-hook 'emacs-lisp-mode-hook 'reveal-mode)
1074 (defun indent-spaces-mode ()
1075 (setq indent-tabs-mode nil))
1076 (add-hook 'lisp-interaction-mode-hook #'indent-spaces-mode))
1077
1078 (use-package man
1079 :defer t
1080 :config (setq Man-width 80))
1081
1082 (use-package paren
1083 :config (show-paren-mode))
1084
1085 (use-package prog-mode
1086 :config (global-prettify-symbols-mode)
1087 (defun indicate-buffer-boundaries-left ()
1088 (setq indicate-buffer-boundaries 'left))
1089 (add-hook 'prog-mode-hook #'indicate-buffer-boundaries-left))
1090
1091 (use-package recentf
1092 :defer 0.5
1093 :config
1094 (add-to-list 'recentf-exclude "^/\\(?:ssh\\|su\\|sudo\\)?:")
1095 (setq recentf-max-saved-items 40))
1096
1097 (use-package savehist
1098 :config (savehist-mode))
1099
1100 (use-package saveplace
1101 :when (version< "25" emacs-version)
1102 :config (save-place-mode))
1103
1104 (use-package simple
1105 :config (column-number-mode))
1106
1107 (progn ; `text-mode'
1108 (add-hook 'text-mode-hook #'indicate-buffer-boundaries-left)
1109 (add-hook 'text-mode-hook #'abbrev-mode))
1110
1111 (use-package tramp
1112 :defer t
1113 :config
1114 (add-to-list 'tramp-default-proxies-alist '(nil "\\`root\\'" "/ssh:%h:"))
1115 (add-to-list 'tramp-default-proxies-alist '("localhost" nil nil))
1116 (add-to-list 'tramp-default-proxies-alist
1117 (list (regexp-quote (system-name)) nil nil)))
1118
1119 #+end_src
1120
1121 * Editing
1122 :PROPERTIES:
1123 :CUSTOM_ID: editing
1124 :END:
1125
1126 ** Company
1127
1128 #+begin_src emacs-lisp
1129 (use-package company
1130 :defer 1
1131 :bind
1132 (:map company-active-map
1133 ([tab] . company-complete-common-or-cycle)
1134 ([escape] . company-abort))
1135 :custom
1136 (company-minimum-prefix-length 1)
1137 (company-selection-wrap-around t)
1138 (company-dabbrev-char-regexp "\\sw\\|\\s_\\|[-_]")
1139 (company-dabbrev-downcase nil)
1140 (company-dabbrev-ignore-case nil)
1141 :config
1142 (global-company-mode t))
1143 #+end_src
1144
1145 * Syntax and spell checking
1146 :PROPERTIES:
1147 :CUSTOM_ID: syntax-spell-checking
1148 :END:
1149
1150 #+begin_src emacs-lisp
1151 (use-package flycheck
1152 :defer 3
1153 :hook (prog-mode . flycheck-mode)
1154 :bind
1155 (:map flycheck-mode-map
1156 ("M-P" . flycheck-previous-error)
1157 ("M-N" . flycheck-next-error))
1158 :config
1159 ;; Use the load-path from running Emacs when checking elisp files
1160 (setq flycheck-emacs-lisp-load-path 'inherit)
1161
1162 ;; Only flycheck when I actually save the buffer
1163 (setq flycheck-check-syntax-automatically '(mode-enabled save)))
1164
1165 ;; http://endlessparentheses.com/ispell-and-apostrophes.html
1166 (use-package ispell
1167 :defer 3
1168 :config
1169 ;; ’ can be part of a word
1170 (setq ispell-local-dictionary-alist
1171 `((nil "[[:alpha:]]" "[^[:alpha:]]"
1172 "['\x2019]" nil ("-B") nil utf-8)))
1173 ;; don't send ’ to the subprocess
1174 (defun endless/replace-apostrophe (args)
1175 (cons (replace-regexp-in-string
1176 "’" "'" (car args))
1177 (cdr args)))
1178 (advice-add #'ispell-send-string :filter-args
1179 #'endless/replace-apostrophe)
1180
1181 ;; convert ' back to ’ from the subprocess
1182 (defun endless/replace-quote (args)
1183 (if (not (derived-mode-p 'org-mode))
1184 args
1185 (cons (replace-regexp-in-string
1186 "'" "’" (car args))
1187 (cdr args))))
1188 (advice-add #'ispell-parse-output :filter-args
1189 #'endless/replace-quote))
1190 #+end_src
1191
1192 * Programming modes
1193 :PROPERTIES:
1194 :CUSTOM_ID: programming-modes
1195 :END:
1196
1197 ** [[http://alloytools.org][Alloy]] (with [[https://github.com/dwwmmn/alloy-mode][alloy-mode]])
1198
1199 #+begin_src emacs-lisp
1200 (use-package alloy-mode
1201 :defer t
1202 :config (setq alloy-basic-offset 2))
1203 #+end_src
1204
1205 ** [[https://coq.inria.fr][Coq]] (with [[https://github.com/ProofGeneral/PG][Proof General]])
1206
1207 #+begin_src emacs-lisp
1208 (use-package proof-site ; Proof General
1209 :defer t
1210 :load-path "lib/proof-site/generic/")
1211 #+end_src
1212
1213 ** [[https://leanprover.github.io][Lean]] (with [[https://github.com/leanprover/lean-mode][lean-mode]])
1214
1215 #+begin_src emacs-lisp
1216 (eval-when-compile (defvar lean-mode-map))
1217 (use-package lean-mode
1218 :defer 1
1219 :bind (:map lean-mode-map
1220 ("S-SPC" . company-complete))
1221 :config
1222 (require 'lean-input)
1223 (setq default-input-method "Lean"
1224 lean-input-tweak-all '(lean-input-compose
1225 (lean-input-prepend "/")
1226 (lean-input-nonempty))
1227 lean-input-user-translations '(("/" "/")))
1228 (lean-input-setup))
1229 #+end_src
1230
1231 ** Haskell
1232
1233 *** [[https://github.com/haskell/haskell-mode][haskell-mode]]
1234
1235 #+begin_src emacs-lisp
1236 (use-package haskell-mode
1237 :defer t
1238 :config
1239 (setq haskell-indentation-layout-offset 4
1240 haskell-indentation-left-offset 4
1241 flycheck-checker 'haskell-hlint
1242 flycheck-disabled-checkers '(haskell-stack-ghc haskell-ghc)))
1243 #+end_src
1244
1245 *** [[https://github.com/jyp/dante][dante]]
1246
1247 #+begin_src emacs-lisp
1248 (use-package dante
1249 :after haskell-mode
1250 :commands dante-mode
1251 :hook (haskell-mode . dante-mode))
1252 #+end_src
1253
1254 *** [[https://github.com/mpickering/hlint-refactor-mode][hlint-refactor]]
1255
1256 Emacs bindings for [[https://github.com/ndmitchell/hlint][hlint]]'s refactor option. This requires the refact
1257 executable from [[https://github.com/mpickering/apply-refact][apply-refact]].
1258
1259 #+begin_src emacs-lisp
1260 (use-package hlint-refactor
1261 :after haskell-mode
1262 :bind (:map hlint-refactor-mode-map
1263 ("C-c l b" . hlint-refactor-refactor-buffer)
1264 ("C-c l r" . hlint-refactor-refactor-at-point))
1265 :hook (haskell-mode . hlint-refactor-mode))
1266 #+end_src
1267
1268 *** [[https://github.com/flycheck/flycheck-haskell][flycheck-haskell]]
1269
1270 #+begin_src emacs-lisp
1271 (use-package flycheck-haskell
1272 :after haskell-mode)
1273 #+end_src
1274
1275 *** [[https://github.com/ndmitchell/hlint/blob/20e116a043f2073c57b17b24ae6364b5e433ba7e/data/hs-lint.el][hs-lint.el]]
1276 :PROPERTIES:
1277 :header-args+: :tangle lisp/hs-lint.el :mkdirp yes
1278 :END:
1279
1280 Currently using =flycheck-haskell= with the =haskell-hlint= checker
1281 instead.
1282
1283 #+begin_src emacs-lisp :tangle no
1284 ;;; hs-lint.el --- minor mode for HLint code checking
1285
1286 ;; Copyright 2009 (C) Alex Ott
1287 ;;
1288 ;; Author: Alex Ott <alexott@gmail.com>
1289 ;; Keywords: haskell, lint, HLint
1290 ;; Requirements:
1291 ;; Status: distributed under terms of GPL2 or above
1292
1293 ;; Typical message from HLint looks like:
1294 ;;
1295 ;; /Users/ott/projects/lang-exp/haskell/test.hs:52:1: Eta reduce
1296 ;; Found:
1297 ;; count1 p l = length (filter p l)
1298 ;; Why not:
1299 ;; count1 p = length . filter p
1300
1301
1302 (require 'compile)
1303
1304 (defgroup hs-lint nil
1305 "Run HLint as inferior of Emacs, parse error messages."
1306 :group 'tools
1307 :group 'haskell)
1308
1309 (defcustom hs-lint-command "hlint"
1310 "The default hs-lint command for \\[hlint]."
1311 :type 'string
1312 :group 'hs-lint)
1313
1314 (defcustom hs-lint-save-files t
1315 "Save modified files when run HLint or no (ask user)"
1316 :type 'boolean
1317 :group 'hs-lint)
1318
1319 (defcustom hs-lint-replace-with-suggestions nil
1320 "Replace user's code with suggested replacements"
1321 :type 'boolean
1322 :group 'hs-lint)
1323
1324 (defcustom hs-lint-replace-without-ask nil
1325 "Replace user's code with suggested replacements automatically"
1326 :type 'boolean
1327 :group 'hs-lint)
1328
1329 (defun hs-lint-process-setup ()
1330 "Setup compilation variables and buffer for `hlint'."
1331 (run-hooks 'hs-lint-setup-hook))
1332
1333 ;; regex for replace suggestions
1334 ;;
1335 ;; ^\(.*?\):\([0-9]+\):\([0-9]+\): .*
1336 ;; Found:
1337 ;; \s +\(.*\)
1338 ;; Why not:
1339 ;; \s +\(.*\)
1340
1341 (defvar hs-lint-regex
1342 "^\\(.*?\\):\\([0-9]+\\):\\([0-9]+\\): .*[\n\C-m]Found:[\n\C-m]\\s +\\(.*\\)[\n\C-m]Why not:[\n\C-m]\\s +\\(.*\\)[\n\C-m]"
1343 "Regex for HLint messages")
1344
1345 (defun make-short-string (str maxlen)
1346 (if (< (length str) maxlen)
1347 str
1348 (concat (substring str 0 (- maxlen 3)) "...")))
1349
1350 (defun hs-lint-replace-suggestions ()
1351 "Perform actual replacement of suggestions"
1352 (goto-char (point-min))
1353 (while (re-search-forward hs-lint-regex nil t)
1354 (let* ((fname (match-string 1))
1355 (fline (string-to-number (match-string 2)))
1356 (old-code (match-string 4))
1357 (new-code (match-string 5))
1358 (msg (concat "Replace '" (make-short-string old-code 30)
1359 "' with '" (make-short-string new-code 30) "'"))
1360 (bline 0)
1361 (eline 0)
1362 (spos 0)
1363 (new-old-code ""))
1364 (save-excursion
1365 (switch-to-buffer (get-file-buffer fname))
1366 (goto-char (point-min))
1367 (forward-line (1- fline))
1368 (beginning-of-line)
1369 (setf bline (point))
1370 (when (or hs-lint-replace-without-ask
1371 (yes-or-no-p msg))
1372 (end-of-line)
1373 (setf eline (point))
1374 (beginning-of-line)
1375 (setf old-code (regexp-quote old-code))
1376 (while (string-match "\\\\ " old-code spos)
1377 (setf new-old-code (concat new-old-code
1378 (substring old-code spos (match-beginning 0))
1379 "\\ *"))
1380 (setf spos (match-end 0)))
1381 (setf new-old-code (concat new-old-code (substring old-code spos)))
1382 (remove-text-properties bline eline '(composition nil))
1383 (when (re-search-forward new-old-code eline t)
1384 (replace-match new-code nil t)))))))
1385
1386 (defun hs-lint-finish-hook (buf msg)
1387 "Function, that is executed at the end of HLint execution"
1388 (if hs-lint-replace-with-suggestions
1389 (hs-lint-replace-suggestions)
1390 (next-error 1 t)))
1391
1392 (define-compilation-mode hs-lint-mode "HLint"
1393 "Mode for check Haskell source code."
1394 (set (make-local-variable 'compilation-process-setup-function)
1395 'hs-lint-process-setup)
1396 (set (make-local-variable 'compilation-disable-input) t)
1397 (set (make-local-variable 'compilation-scroll-output) nil)
1398 (set (make-local-variable 'compilation-finish-functions)
1399 (list 'hs-lint-finish-hook))
1400 )
1401
1402 (defun hs-lint ()
1403 "Run HLint for current buffer with haskell source"
1404 (interactive)
1405 (save-some-buffers hs-lint-save-files)
1406 (compilation-start (concat hs-lint-command " \"" buffer-file-name "\"")
1407 'hs-lint-mode))
1408
1409 (provide 'hs-lint)
1410 ;;; hs-lint.el ends here
1411 #+end_src
1412
1413 #+begin_src emacs-lisp :tangle no
1414 (use-package hs-lint
1415 :load-path "lisp/"
1416 :bind (:map haskell-mode-map
1417 ("C-c l l" . hs-lint)))
1418 #+end_src
1419
1420 ** Web dev
1421
1422 *** SGML and HTML
1423
1424 #+begin_src emacs-lisp
1425 (use-package sgml-mode
1426 :defer t
1427 :config
1428 (setq sgml-basic-offset 2))
1429 #+end_src
1430
1431 *** CSS and SCSS
1432
1433 #+begin_src emacs-lisp
1434 (use-package css-mode
1435 :defer t
1436 :config
1437 (setq css-indent-offset 2))
1438 #+end_src
1439
1440 *** Web mode
1441
1442 #+begin_src emacs-lisp
1443 (use-package web-mode
1444 :defer t
1445 :mode "\\.html\\'"
1446 :config
1447 (a/setq-every 2
1448 web-mode-code-indent-offset
1449 web-mode-css-indent-offset
1450 web-mode-markup-indent-offset))
1451 #+end_src
1452
1453 *** Emmet mode
1454
1455 #+begin_src emacs-lisp
1456 (use-package emmet-mode
1457 :after (:any web-mode css-mode sgml-mode)
1458 :bind* (("C-)" . emmet-next-edit-point)
1459 ("C-(" . emmet-prev-edit-point))
1460 :config
1461 (unbind-key "C-j" emmet-mode-keymap)
1462 (setq emmet-move-cursor-between-quotes t)
1463 :hook (web-mode css-mode html-mode sgml-mode))
1464 #+end_src
1465
1466 ** COMMENT Java
1467
1468 *** meghanada
1469
1470 #+begin_src emacs-lisp
1471 (use-package meghanada
1472 :bind
1473 (:map meghanada-mode-map
1474 (("C-M-o" . meghanada-optimize-import)
1475 ("C-M-t" . meghanada-import-all)))
1476 :hook (java-mode . meghanada-mode))
1477 #+end_src
1478
1479 *** lsp-java
1480
1481 #+begin_comment
1482 dependencies:
1483
1484 ace-window
1485 avy
1486 bui
1487 company-lsp
1488 dap-mode
1489 lsp-java
1490 lsp-mode
1491 lsp-ui
1492 pfuture
1493 tree-mode
1494 treemacs
1495 #+end_comment
1496
1497 #+begin_src emacs-lisp
1498 (use-package treemacs
1499 :config (setq treemacs-never-persist t))
1500
1501 (use-package yasnippet
1502 :config
1503 ;; (yas-global-mode)
1504 )
1505
1506 (use-package lsp-mode
1507 :init (setq lsp-eldoc-render-all nil
1508 lsp-highlight-symbol-at-point nil)
1509 )
1510
1511 (use-package hydra)
1512
1513 (use-package company-lsp
1514 :after company
1515 :config
1516 (setq company-lsp-cache-candidates t
1517 company-lsp-async t))
1518
1519 (use-package lsp-ui
1520 :config
1521 (setq lsp-ui-sideline-update-mode 'point))
1522
1523 (use-package lsp-java
1524 :config
1525 (add-hook 'java-mode-hook
1526 (lambda ()
1527 (setq-local company-backends (list 'company-lsp))))
1528
1529 (add-hook 'java-mode-hook 'lsp-java-enable)
1530 (add-hook 'java-mode-hook 'flycheck-mode)
1531 (add-hook 'java-mode-hook 'company-mode)
1532 (add-hook 'java-mode-hook 'lsp-ui-mode))
1533
1534 (use-package dap-mode
1535 :after lsp-mode
1536 :config
1537 (dap-mode t)
1538 (dap-ui-mode t))
1539
1540 (use-package dap-java
1541 :after (lsp-java))
1542
1543 (use-package lsp-java-treemacs
1544 :after (treemacs))
1545 #+end_src
1546
1547 ** geiser
1548
1549 #+begin_src emacs-lisp
1550 (use-package geiser)
1551
1552 (use-package geiser-guile
1553 :config
1554 (setq geiser-guile-load-path "~/src/git/guix"))
1555 #+end_src
1556
1557 ** guix
1558
1559 #+begin_src emacs-lisp
1560 (use-package guix
1561 :load-path "lib/guix/elisp")
1562 #+end_src
1563
1564 * Emacs enhancements
1565 :PROPERTIES:
1566 :CUSTOM_ID: emacs-enhancements
1567 :END:
1568
1569 ** [[https://github.com/justbur/emacs-which-key][which-key]]
1570
1571 #+begin_quote
1572 Emacs package that displays available keybindings in popup
1573 #+end_quote
1574
1575 #+begin_src emacs-lisp
1576 (use-package which-key
1577 :defer 1
1578 :config (which-key-mode))
1579 #+end_src
1580
1581 ** theme
1582
1583 #+begin_src emacs-lisp
1584 (add-to-list 'custom-theme-load-path "~/.emacs.d/lisp")
1585 (load-theme 'tangomod t)
1586 #+end_src
1587
1588 ** smart-mode-line
1589
1590 #+begin_src emacs-lisp
1591 (use-package smart-mode-line
1592 :config
1593 (sml/setup))
1594 #+end_src
1595
1596 ** doom-themes
1597
1598 #+begin_src emacs-lisp
1599 (use-package doom-themes)
1600 #+end_src
1601
1602 ** theme helper functions
1603
1604 #+begin_src emacs-lisp
1605 (defun a/lights-on ()
1606 "Enable my favourite light theme."
1607 (interactive)
1608 (mapc #'disable-theme custom-enabled-themes)
1609 (load-theme 'tangomod t)
1610 (sml/apply-theme 'automatic))
1611
1612 (defun a/lights-off ()
1613 "Go dark."
1614 (interactive)
1615 (mapc #'disable-theme custom-enabled-themes)
1616 (load-theme 'doom-tomorrow-night t)
1617 (sml/apply-theme 'automatic))
1618
1619 (bind-keys
1620 ("s-t d" . a/lights-off)
1621 ("s-t l" . a/lights-on))
1622 #+end_src
1623
1624 ** [[https://github.com/bbatsov/crux][crux]]
1625
1626 #+begin_src emacs-lisp
1627 (use-package crux
1628 :defer 1
1629 :bind (("C-c b k" . crux-kill-other-buffers)
1630 ("C-c d" . crux-duplicate-current-line-or-region)
1631 ("C-c D" . crux-duplicate-and-comment-current-line-or-region)
1632 ("C-c f c" . crux-copy-file-preserve-attributes)
1633 ("C-c f d" . crux-delete-file-and-buffer)
1634 ("C-c f r" . crux-rename-file-and-buffer)
1635 ("C-c j" . crux-top-join-line)
1636 ("C-S-j" . crux-top-join-line)))
1637 #+end_src
1638
1639 ** [[https://github.com/alezost/mwim.el][mwim]]
1640
1641 #+begin_src emacs-lisp
1642 (use-package mwim
1643 :bind (("C-a" . mwim-beginning-of-code-or-line)
1644 ("C-e" . mwim-end-of-code-or-line)
1645 ("<home>" . mwim-beginning-of-line-or-code)
1646 ("<end>" . mwim-end-of-line-or-code)))
1647 #+end_src
1648
1649 ** projectile
1650
1651 #+begin_src emacs-lisp
1652 (use-package projectile
1653 :defer t
1654 :bind-keymap ("C-c p" . projectile-command-map)
1655 :config
1656 (projectile-mode)
1657
1658 (defun my-projectile-invalidate-cache (&rest _args)
1659 ;; ignore the args to `magit-checkout'
1660 (projectile-invalidate-cache nil))
1661
1662 (eval-after-load 'magit-branch
1663 '(progn
1664 (advice-add 'magit-checkout
1665 :after #'my-projectile-invalidate-cache)
1666 (advice-add 'magit-branch-and-checkout
1667 :after #'my-projectile-invalidate-cache)))
1668 :custom (projectile-completion-system 'ivy))
1669 #+end_src
1670
1671 ** [[https://github.com/Wilfred/helpful][helpful]]
1672
1673 #+begin_src emacs-lisp
1674 (use-package helpful
1675 :defer 1
1676 :bind
1677 (("C-S-h c" . helpful-command)
1678 ("C-S-h f" . helpful-callable) ; helpful-function
1679 ("C-S-h v" . helpful-variable)
1680 ("C-S-h k" . helpful-key)
1681 ("C-S-h p" . helpful-at-point)))
1682 #+end_src
1683
1684 ** [[https://github.com/EricCrosson/unkillable-scratch][unkillable-scratch]]
1685
1686 Make =*scratch*= and =*Messages*= unkillable.
1687
1688 #+begin_src emacs-lisp
1689 (use-package unkillable-scratch
1690 :defer 3
1691 :config
1692 (unkillable-scratch 1)
1693 :custom
1694 (unkillable-scratch-behavior 'do-nothing)
1695 (unkillable-buffers '("^\\*scratch\\*$" "^\\*Messages\\*$")))
1696 #+end_src
1697
1698 ** [[https://github.com/davep/boxquote.el][boxquote.el]]
1699
1700 #+begin_example
1701 ,----
1702 | make pretty boxed quotes like this
1703 `----
1704 #+end_example
1705
1706 #+begin_src emacs-lisp
1707 (use-package boxquote
1708 :defer 3
1709 :bind
1710 (:prefix-map a/boxquote-prefix-map
1711 :prefix "C-c q"
1712 ("b" . boxquote-buffer)
1713 ("B" . boxquote-insert-buffer)
1714 ("d" . boxquote-defun)
1715 ("F" . boxquote-insert-file)
1716 ("hf" . boxquote-describe-function)
1717 ("hk" . boxquote-describe-key)
1718 ("hv" . boxquote-describe-variable)
1719 ("hw" . boxquote-where-is)
1720 ("k" . boxquote-kill)
1721 ("p" . boxquote-paragraph)
1722 ("q" . boxquote-boxquote)
1723 ("r" . boxquote-region)
1724 ("s" . boxquote-shell-command)
1725 ("t" . boxquote-text)
1726 ("T" . boxquote-title)
1727 ("u" . boxquote-unbox)
1728 ("U" . boxquote-unbox-region)
1729 ("y" . boxquote-yank)
1730 ("M-q" . boxquote-fill-paragraph)
1731 ("M-w" . boxquote-kill-ring-save)))
1732 #+end_src
1733
1734 Also see [[https://www.emacswiki.org/emacs/rebox2][rebox2]].
1735
1736 ** typo.el
1737
1738 #+begin_src emacs-lisp
1739 (use-package typo
1740 :defer 2
1741 :config
1742 (typo-global-mode 1)
1743 :hook (text-mode . typo-mode))
1744 #+end_src
1745
1746 ** hl-todo
1747
1748 #+begin_src emacs-lisp
1749 (use-package hl-todo
1750 :defer 4
1751 :config
1752 (global-hl-todo-mode))
1753 #+end_src
1754
1755 ** shrink-path
1756
1757 #+begin_src emacs-lisp
1758 (use-package shrink-path
1759 :after eshell
1760 :config
1761 (setq eshell-prompt-regexp "\\(.*\n\\)*λ "
1762 eshell-prompt-function #'+eshell/prompt)
1763
1764 (defun +eshell/prompt ()
1765 (let ((base/dir (shrink-path-prompt default-directory)))
1766 (concat (propertize (car base/dir)
1767 'face 'font-lock-comment-face)
1768 (propertize (cdr base/dir)
1769 'face 'font-lock-constant-face)
1770 (propertize (+eshell--current-git-branch)
1771 'face 'font-lock-function-name-face)
1772 "\n"
1773 (propertize "λ" 'face 'eshell-prompt-face)
1774 ;; needed for the input text to not have prompt face
1775 (propertize " " 'face 'default))))
1776
1777 (defun +eshell--current-git-branch ()
1778 (let ((branch (car (loop for match in (split-string (shell-command-to-string "git branch") "\n")
1779 when (string-match "^\*" match)
1780 collect match))))
1781 (if (not (eq branch nil))
1782 (concat " " (substring branch 2))
1783 ""))))
1784 #+end_src
1785
1786 ** [[https://github.com/peterwvj/eshell-up][eshell-up]]
1787
1788 #+begin_src emacs-lisp
1789 (use-package eshell-up
1790 :after eshell)
1791 #+end_src
1792
1793 ** multi-term
1794
1795 #+begin_src emacs-lisp
1796 (use-package multi-term
1797 :defer 1
1798 :bind (("C-c a s m m" . multi-term)
1799 ("C-c a s m p" . multi-term-dedicated-toggle)
1800 :map term-mode-map
1801 ("C-c C-j" . term-char-mode)
1802 :map term-raw-map
1803 ("C-c C-j" . term-line-mode))
1804 :config
1805 (setq multi-term-program "/bin/screen"
1806 ;; TODO: add separate bindings for connecting to existing
1807 ;; session vs. always creating a new one
1808 multi-term-dedicated-select-after-open-p t
1809 multi-term-dedicated-window-height 20
1810 multi-term-dedicated-max-window-height 30
1811 term-bind-key-alist
1812 '(("C-c C-c" . term-interrupt-subjob)
1813 ("C-c C-e" . term-send-esc)
1814 ("C-k" . kill-line)
1815 ("C-y" . term-paste)
1816 ("M-f" . term-send-forward-word)
1817 ("M-b" . term-send-backward-word)
1818 ("M-p" . term-send-up)
1819 ("M-n" . term-send-down)
1820 ("<C-backspace>" . term-send-backward-kill-word)
1821 ("<M-DEL>" . term-send-backward-kill-word)
1822 ("M-d" . term-send-delete-word)
1823 ("M-," . term-send-raw)
1824 ("M-." . comint-dynamic-complete))
1825 term-unbind-key-alist
1826 '("C-z" "C-x" "C-c" "C-h" "C-y" "<ESC>")))
1827 #+end_src
1828
1829 ** page-break-lines
1830
1831 #+begin_src emacs-lisp
1832 (use-package page-break-lines
1833 :config
1834 (global-page-break-lines-mode))
1835 #+end_src
1836
1837 ** expand-region
1838
1839 #+begin_src emacs-lisp
1840 (use-package expand-region
1841 :bind ("C-=" . er/expand-region))
1842 #+end_src
1843
1844 * Email
1845 :PROPERTIES:
1846 :CUSTOM_ID: email
1847 :END:
1848
1849 #+begin_src emacs-lisp
1850 (defvar a/maildir (expand-file-name "~/mail/"))
1851 (with-eval-after-load 'recentf
1852 (add-to-list 'recentf-exclude a/maildir))
1853 #+end_src
1854
1855 ** Gnus
1856
1857 #+begin_src emacs-lisp
1858 (setq
1859 a/gnus-init-file (no-littering-expand-etc-file-name "gnus")
1860 mail-user-agent 'gnus-user-agent
1861 read-mail-command 'gnus)
1862
1863 (use-package gnus
1864 :bind (("C-c m" . gnus)
1865 ("C-c M" . gnus-unplugged)
1866 ("s-m" . gnus)
1867 ("s-M" . gnus-unplugged))
1868 :init
1869 (setq
1870 gnus-select-method '(nnnil "")
1871 gnus-secondary-select-methods
1872 '((nnimap "amin"
1873 (nnimap-stream plain)
1874 (nnimap-address "127.0.0.1")
1875 (nnimap-server-port 143)
1876 (nnimap-authenticator plain)
1877 (nnimap-user "amin@aminb.org"))
1878 (nnimap "uwaterloo"
1879 (nnimap-stream plain)
1880 (nnimap-address "127.0.0.1")
1881 (nnimap-server-port 143)
1882 (nnimap-authenticator plain)
1883 (nnimap-user "abandali@uwaterloo.ca")))
1884 gnus-message-archive-group "nnimap+amin:Sent"
1885 gnus-parameters
1886 '(("gnu.*"
1887 (gcc-self . t)))
1888 gnus-large-newsgroup 50
1889 gnus-home-directory (no-littering-expand-var-file-name "gnus/")
1890 gnus-directory (concat gnus-home-directory "news/")
1891 message-directory (concat gnus-home-directory "mail/")
1892 nndraft-directory (concat gnus-home-directory "drafts/")
1893 gnus-save-newsrc-file nil
1894 gnus-read-newsrc-file nil
1895 gnus-interactive-exit nil
1896 gnus-gcc-mark-as-read t))
1897
1898 (use-package gnus-art
1899 :config
1900 (setq
1901 gnus-visible-headers
1902 (concat gnus-visible-headers "\\|^List-Id:\\|^X-RT-Originator:\\|^User-Agent:")
1903 gnus-sorted-header-list
1904 '("^From:" "^Subject:" "^Summary:" "^Keywords:"
1905 "^Followup-To:" "^To:" "^Cc:" "X-RT-Originator"
1906 "^Newsgroups:" "List-Id:" "^Organization:"
1907 "^User-Agent:" "^Date:")
1908 ;; local-lapsed article dates
1909 ;; from https://www.emacswiki.org/emacs/GnusFormatting#toc11
1910 gnus-article-date-headers '(user-defined)
1911 gnus-article-time-format
1912 (lambda (time)
1913 (let* ((date (format-time-string "%a, %d %b %Y %T %z" time))
1914 (local (article-make-date-line date 'local))
1915 (combined-lapsed (article-make-date-line date
1916 'combined-lapsed))
1917 (lapsed (progn
1918 (string-match " (.+" combined-lapsed)
1919 (match-string 0 combined-lapsed))))
1920 (concat local lapsed))))
1921 (bind-keys
1922 :map gnus-article-mode-map
1923 ("r" . gnus-article-reply-with-original)
1924 ("R" . gnus-article-wide-reply-with-original)
1925 ("M-L" . org-store-link)))
1926
1927 (use-package gnus-sum
1928 :bind (:map gnus-summary-mode-map
1929 :prefix-map a/gnus-summary-prefix-map
1930 :prefix "v"
1931 ("r" . gnus-summary-reply)
1932 ("w" . gnus-summary-wide-reply)
1933 ("v" . gnus-summary-show-raw-article))
1934 :config
1935 (bind-keys
1936 :map gnus-summary-mode-map
1937 ("r" . gnus-summary-reply-with-original)
1938 ("R" . gnus-summary-wide-reply-with-original)
1939 ("M-L" . org-store-link))
1940 :hook (gnus-summary-mode . a/no-mouse-autoselect-window))
1941
1942 (use-package gnus-msg
1943 :config
1944 (setq gnus-posting-styles
1945 '((".*"
1946 (address "amin@aminb.org")
1947 (body "\nBest,\namin\n")
1948 (eval (setq a/message-cite-say-hi t)))
1949 ("gnu.*"
1950 (address "bandali@gnu.org"))
1951 ((header "subject" "ThankCRM")
1952 (to "webmasters-comment@gnu.org")
1953 (body "\nAdded to 2018supporters.html.\n\nMoving to campaigns.\n\n-amin\n")
1954 (eval (setq a/message-cite-say-hi nil)))
1955 ("nnimap\\+uwaterloo:.*"
1956 (address "abandali@uwaterloo.ca")
1957 (gcc "\"nnimap+uwaterloo:Sent Items\"")))))
1958
1959 (use-package gnus-topic
1960 :hook (gnus-group-mode . gnus-topic-mode))
1961
1962 (use-package gnus-agent
1963 :config
1964 (setq gnus-agent-synchronize-flags 'ask)
1965 :hook (gnus-group-mode . gnus-agent-mode))
1966
1967 (use-package gnus-group
1968 :config
1969 (setq gnus-permanently-visible-groups "\\((INBOX\\|gnu$\\)"))
1970
1971 (use-package mm-decode
1972 :config
1973 (setq mm-discouraged-alternatives '("text/html" "text/richtext")))
1974 #+end_src
1975
1976 ** sendmail
1977
1978 #+begin_src emacs-lisp
1979 (use-package sendmail
1980 :config
1981 (setq sendmail-program "/usr/bin/msmtp"
1982 ;; message-sendmail-extra-arguments '("-v" "-d")
1983 mail-specify-envelope-from t
1984 mail-envelope-from 'header))
1985 #+end_src
1986
1987 ** message
1988
1989 #+begin_src emacs-lisp
1990 (use-package message
1991 :config
1992 (defconst a/message-cite-style-format "On %Y-%m-%d %l:%M %p, %N wrote:")
1993 (defconst message-cite-style-bandali
1994 '((message-cite-function 'message-cite-original)
1995 (message-citation-line-function 'message-insert-formatted-citation-line)
1996 (message-cite-reply-position 'traditional)
1997 (message-yank-prefix "> ")
1998 (message-yank-cited-prefix ">")
1999 (message-yank-empty-prefix ">")
2000 (message-citation-line-format
2001 (if a/message-cite-say-hi
2002 (concat "Hi %F,\n\n" a/message-cite-style-format)
2003 a/message-cite-style-format)))
2004 "Citation style based on Mozilla Thunderbird's. Use with message-cite-style.")
2005 (setq message-cite-style 'message-cite-style-bandali
2006 message-kill-buffer-on-exit t
2007 message-send-mail-function 'message-send-mail-with-sendmail
2008 message-sendmail-envelope-from 'header
2009 message-dont-reply-to-names
2010 "\\(\\(.*@aminb\\.org\\)\\|\\(amin@bandali\\.me\\)\\|\\(\\(aminb?\\|mab\\|bandali\\)@gnu\\.org\\)\\|\\(\\(m\\|a\\(min\\.\\)?\\)bandali@uwaterloo\\.ca\\)\\)"
2011 message-user-fqdn "aminb.org")
2012 :hook (;; (message-setup . mml-secure-message-sign-pgpmime)
2013 (message-mode . flyspell-mode)
2014 (message-mode . (lambda ()
2015 ;; (setq fill-column 65
2016 ;; message-fill-column 65)
2017 (make-local-variable 'company-idle-delay)
2018 (setq company-idle-delay 0.2))))
2019 ;; :custom-face
2020 ;; (message-header-subject ((t (:foreground "#111" :weight semi-bold))))
2021 ;; (message-header-to ((t (:foreground "#111" :weight normal))))
2022 ;; (message-header-cc ((t (:foreground "#333" :weight normal))))
2023 )
2024
2025 (with-eval-after-load 'mml-sec
2026 (setq mml-secure-openpgp-encrypt-to-self t
2027 mml-secure-openpgp-sign-with-sender t))
2028 #+end_src
2029
2030 ** footnote
2031
2032 Convenient footnotes in =message-mode=.
2033
2034 #+begin_src emacs-lisp
2035 (use-package footnote
2036 :after message
2037 :bind
2038 (:map message-mode-map
2039 :prefix-map a/footnote-prefix-map
2040 :prefix "C-c f"
2041 ("a" . footnote-add-footnote)
2042 ("b" . footnote-back-to-message)
2043 ("c" . footnote-cycle-style)
2044 ("d" . footnote-delete-footnote)
2045 ("g" . footnote-goto-footnote)
2046 ("r" . footnote-renumber-footnotes)
2047 ("s" . footnote-set-style))
2048 :config
2049 (setq footnote-start-tag ""
2050 footnote-end-tag ""
2051 footnote-style 'unicode))
2052 #+end_src
2053
2054 ** ebdb
2055
2056 #+begin_src emacs-lisp
2057 (use-package ebdb
2058 :defer 1
2059 :bind (:map gnus-group-mode-map ("e" . ebdb))
2060 :config
2061 (setq ebdb-sources (no-littering-expand-var-file-name "ebdb"))
2062 (with-eval-after-load 'swiper
2063 (add-to-list 'swiper-font-lock-exclude 'ebdb-mode t)))
2064
2065 (use-package ebdb-com
2066 :after ebdb)
2067
2068 ;; (use-package ebdb-complete
2069 ;; :after ebdb
2070 ;; :config
2071 ;; (ebdb-complete-enable))
2072
2073 (use-package company-ebdb
2074 :after (:all company message)
2075 :config
2076 (defun company-ebdb--post-complete (_) nil)
2077 :hook
2078 (message-mode . (lambda ()
2079 (add-to-list (make-local-variable 'company-backends)
2080 'company-ebdb))))
2081
2082 (use-package ebdb-gnus
2083 :after ebdb
2084 :custom
2085 (ebdb-gnus-window-configuration
2086 '(article
2087 (vertical 1.0
2088 (summary 0.25 point)
2089 (horizontal 1.0
2090 (article 1.0)
2091 (ebdb-gnus 0.3))))))
2092
2093 (use-package ebdb-mua
2094 :after ebdb
2095 ;; :custom (ebdb-mua-pop-up nil)
2096 )
2097
2098 ;; (use-package ebdb-message
2099 ;; :after ebdb)
2100
2101
2102 ;; (use-package ebdb-vcard
2103 ;; :after ebdb)
2104 #+end_src
2105
2106 ** COMMENT message-x
2107
2108 #+begin_src emacs-lisp
2109 (use-package message-x
2110 :custom
2111 (message-x-completion-alist
2112 (quote
2113 (("\\([rR]esent-\\|[rR]eply-\\)?[tT]o:\\|[bB]?[cC][cC]:" . gnus-harvest-find-address)
2114 ((if
2115 (boundp
2116 (quote message-newgroups-header-regexp))
2117 message-newgroups-header-regexp message-newsgroups-header-regexp)
2118 . message-expand-group)))))
2119 #+end_src
2120
2121 ** COMMENT gnus-harvest
2122
2123 #+begin_src emacs-lisp
2124 (use-package gnus-harvest
2125 :commands gnus-harvest-install
2126 :demand t
2127 :config
2128 (if (featurep 'message-x)
2129 (gnus-harvest-install 'message-x)
2130 (gnus-harvest-install)))
2131 #+end_src
2132
2133 * Blogging
2134 :PROPERTIES:
2135 :CUSTOM_ID: blogging
2136 :END:
2137
2138 ** [[https://ox-hugo.scripter.co][ox-hugo]]
2139
2140 #+begin_src emacs-lisp
2141 (use-package ox-hugo
2142 :after ox)
2143
2144 (use-package ox-hugo-auto-export
2145 :load-path "lib/ox-hugo")
2146 #+end_src
2147
2148 * Post initialization
2149 :PROPERTIES:
2150 :CUSTOM_ID: post-initialization
2151 :END:
2152
2153 Display how long it took to load the init file.
2154
2155 #+begin_src emacs-lisp
2156 (message "Loading %s...done (%.3fs)" user-init-file
2157 (float-time (time-subtract (current-time)
2158 a/before-user-init-time)))
2159 #+end_src
2160
2161 * Footer
2162 :PROPERTIES:
2163 :CUSTOM_ID: footer
2164 :END:
2165
2166 #+begin_src emacs-lisp :comments none
2167 ;;; init.el ends here
2168 #+end_src
2169
2170 * COMMENT Local Variables :ARCHIVE:
2171 # Local Variables:
2172 # eval: (add-hook 'after-save-hook #'a/async-babel-tangle 'append 'local)
2173 # eval: (typo-mode -1)
2174 # End: