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