[emacs] Update helm to v3.0-79-g8433e877
[~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}"))
5fece105
AB
792 t))
793
794(use-package ox-beamer
6ce4ebba 795 :demand
5fece105 796 :after ox)
5fece105
AB
797#+end_src
798
799**** asynchronous tangle
800
c5d8bb25 801=a/async-babel-tangle= is a function closely inspired by [[https://github.com/dieggsy/dotfiles/tree/cc10edf7701958eff1cd94d4081da544d882a28c/emacs.d#dotfiles][dieggsy's
5fece105
AB
802d/async-babel-tangle]] which uses [[https://github.com/jwiegley/emacs-async][async]] to asynchronously tangle an org
803file.
804
805#+begin_src emacs-lisp
ab6781dd 806(with-eval-after-load 'org
c5d8bb25 807 (defvar a/show-async-tangle-results nil
5fece105
AB
808 "Keep *emacs* async buffers around for later inspection.")
809
c5d8bb25 810 (defvar a/show-async-tangle-time nil
5fece105
AB
811 "Show the time spent tangling the file.")
812
c5d8bb25 813 (defvar a/async-tangle-post-compile "make ti"
5fece105
AB
814 "If non-nil, pass to `compile' after successful tangle.")
815
6ce4ebba
AB
816 (defvar a/async-tangle-byte-recompile nil
817 "If non-nil, byte-recompile the file on successful tangle.")
818
c5d8bb25 819 (defun a/async-babel-tangle ()
5fece105
AB
820 "Tangle org file asynchronously."
821 (interactive)
822 (let* ((file-tangle-start-time (current-time))
823 (file (buffer-file-name))
824 (file-nodir (file-name-nondirectory file))
0571b240 825 ;; (async-quiet-switch "-q")
6ce4ebba 826 (file-noext (file-name-sans-extension file)))
5fece105
AB
827 (async-start
828 `(lambda ()
829 (require 'org)
830 (org-babel-tangle-file ,file))
c5d8bb25 831 (unless a/show-async-tangle-results
5fece105
AB
832 `(lambda (result)
833 (if result
834 (progn
6ce4ebba 835 ;; (setq byte-compile-warnings '(not noruntime unresolved))
5fece105
AB
836 (message "Tangled %s%s"
837 ,file-nodir
c5d8bb25 838 (if a/show-async-tangle-time
5fece105
AB
839 (format " (%.3fs)"
840 (float-time (time-subtract (current-time)
841 ',file-tangle-start-time)))
842 ""))
c5d8bb25 843 (when a/async-tangle-post-compile
6ce4ebba
AB
844 (compile a/async-tangle-post-compile))
845 (when a/async-tangle-byte-recompile
846 (byte-recompile-file (concat ,file-noext ".el"))))
5fece105
AB
847 (message "Tangling %s failed" ,file-nodir))))))))
848
849(add-to-list
850 'safe-local-variable-values
c5d8bb25 851 '(eval add-hook 'after-save-hook #'a/async-babel-tangle 'append 'local))
5fece105
AB
852#+end_src
853
854*** [[https://magit.vc/][Magit]]
855
856#+begin_quote
857It's Magit! A Git porcelain inside Emacs.
858#+end_quote
859
860Not just how I do git, but /the/ way to do git.
861
862#+begin_src emacs-lisp
863(use-package magit
864 :defer 1
865 :bind (("C-x g" . magit-status)
866 ("s-g s" . magit-status)
867 ("s-g l" . magit-log-buffer-file))
868 :config
869 (magit-add-section-hook 'magit-status-sections-hook
870 'magit-insert-modules
871 'magit-insert-stashes
872 'append)
873 (setq
874 magit-repository-directories '(("~/.emacs.d/" . 0)
875 ("~/src/git/" . 1)))
876 (nconc magit-section-initial-visibility-alist
877 '(([unpulled status] . show)
878 ([unpushed status] . show)))
879 :custom-face (magit-diff-file-heading ((t (:weight normal)))))
880#+end_src
881
6ce4ebba
AB
882*** recentf
883
884Recently opened files.
885
886#+begin_src emacs-lisp
887(use-package recentf
888 :defer 0.5
889 :config
890 (add-to-list 'recentf-exclude "^/\\(?:ssh\\|su\\|sudo\\)?:")
891 (setq recentf-max-saved-items 40))
892#+end_src
893
894*** smex
895
896#+begin_quote
897A smart M-x enhancement for Emacs.
898#+end_quote
899
900Mostly because =counsel= needs it to remember history.
901
902#+begin_src emacs-lisp
903(use-package smex)
904#+end_src
905
5fece105
AB
906*** [[https://github.com/abo-abo/swiper][Ivy]] (and friends)
907
908#+begin_quote
909Ivy - a generic completion frontend for Emacs, Swiper - isearch with
910an overview, and more. Oh, man!
911#+end_quote
912
913There's no way I could top that, so I won't attempt to.
914
915**** Ivy
916
917#+begin_src emacs-lisp
918(use-package ivy
919 :defer 1
920 :bind
921 (:map ivy-minibuffer-map
922 ([escape] . keyboard-escape-quit)
923 ([S-up] . ivy-previous-history-element)
924 ([S-down] . ivy-next-history-element)
925 ("DEL" . ivy-backward-delete-char))
926 :config
927 (setq ivy-wrap t)
928 (ivy-mode 1)
929 ;; :custom-face
930 ;; (ivy-minibuffer-match-face-2 ((t (:background "#e99ce8" :weight semi-bold))))
931 ;; (ivy-minibuffer-match-face-3 ((t (:background "#bbbbff" :weight semi-bold))))
932 ;; (ivy-minibuffer-match-face-4 ((t (:background "#ffbbff" :weight semi-bold))))
933)
934#+end_src
935
936**** Swiper
937
938#+begin_src emacs-lisp
939(use-package swiper
6ce4ebba 940 :after ivy
f2a57944
AB
941 :bind (("C-s" . swiper)
942 ("C-r" . swiper)
943 ("C-S-s" . isearch-forward)))
5fece105
AB
944#+end_src
945
946**** Counsel
947
948#+begin_src emacs-lisp
949(use-package counsel
950 :defer 1
6ce4ebba 951 :after ivy
5fece105
AB
952 :bind (([remap execute-extended-command] . counsel-M-x)
953 ([remap find-file] . counsel-find-file)
954 ("s-r" . counsel-recentf)
955 ("C-c x" . counsel-M-x)
956 ("C-c f ." . counsel-find-file)
957 :map minibuffer-local-map
958 ("C-r" . counsel-minibuffer-history))
959 :config
960 (counsel-mode 1)
961 (defalias 'locate #'counsel-locate))
962#+end_src
963
964*** eshell
965
966#+begin_src emacs-lisp
967(use-package eshell
968 :defer 1
969 :commands eshell
23cd3185 970 :bind ("C-c a s e" . eshell)
5fece105
AB
971 :config
972 (eval-when-compile (defvar eshell-prompt-regexp))
c5d8bb25 973 (defun a/eshell-quit-or-delete-char (arg)
5fece105
AB
974 (interactive "p")
975 (if (and (eolp) (looking-back eshell-prompt-regexp nil))
976 (eshell-life-is-too-much)
977 (delete-char arg)))
978
c5d8bb25 979 (defun a/eshell-clear ()
5fece105
AB
980 (interactive)
981 (let ((inhibit-read-only t))
982 (erase-buffer))
983 (eshell-send-input))
984
c5d8bb25 985 (defun a/eshell-setup ()
5fece105 986 (make-local-variable 'company-idle-delay)
59ff41b6
AB
987 (defvar company-idle-delay)
988 (setq company-idle-delay nil)
5fece105 989 (bind-keys :map eshell-mode-map
c5d8bb25
AB
990 ("C-d" . a/eshell-quit-or-delete-char)
991 ("C-S-l" . a/eshell-clear)
5fece105
AB
992 ("M-r" . counsel-esh-history)
993 ([tab] . company-complete)))
994
c5d8bb25 995 :hook (eshell-mode . a/eshell-setup)
5fece105
AB
996 :custom
997 (eshell-hist-ignoredups t)
998 (eshell-input-filter 'eshell-input-filter-initial-space))
999#+end_src
1000
1001*** Ibuffer
1002
1003#+begin_src emacs-lisp
1004(use-package ibuffer
5fece105
AB
1005 :bind
1006 (("C-x C-b" . ibuffer-other-window)
1007 :map ibuffer-mode-map
1008 ("P" . ibuffer-backward-filter-group)
1009 ("N" . ibuffer-forward-filter-group)
1010 ("M-p" . ibuffer-do-print)
1011 ("M-n" . ibuffer-do-shell-command-pipe-replace))
1012 :config
1013 ;; Use human readable Size column instead of original one
1014 (define-ibuffer-column size-h
1015 (:name "Size" :inline t)
1016 (cond
1017 ((> (buffer-size) 1000000) (format "%7.1fM" (/ (buffer-size) 1000000.0)))
1018 ((> (buffer-size) 100000) (format "%7.0fk" (/ (buffer-size) 1000.0)))
1019 ((> (buffer-size) 1000) (format "%7.1fk" (/ (buffer-size) 1000.0)))
1020 (t (format "%8d" (buffer-size)))))
1021 :custom
1022 (ibuffer-saved-filter-groups
1023 '(("default"
1024 ("dired" (mode . dired-mode))
1025 ("org" (mode . org-mode))
4e0afb99
AB
1026 ("gnus"
1027 (or
1028 (mode . gnus-group-mode)
1029 (mode . gnus-summary-mode)
1030 (mode . gnus-article-mode)
1031 ;; not really, but...
1032 (mode . message-mode)))
5fece105
AB
1033 ("web"
1034 (or
1035 (mode . web-mode)
1036 (mode . css-mode)
1037 (mode . scss-mode)
1038 (mode . js2-mode)))
1039 ("shell"
1040 (or
1041 (mode . eshell-mode)
4e0afb99
AB
1042 (mode . shell-mode)
1043 (mode . term-mode)))
5fece105
AB
1044 ("programming"
1045 (or
1046 (mode . python-mode)
4e0afb99 1047 (mode . c-mode)
5fece105 1048 (mode . c++-mode)
4e0afb99
AB
1049 (mode . emacs-lisp-mode)
1050 (mode . scheme-mode)
1051 (mode . haskell-mode)
1052 (mode . lean-mode)))
5fece105
AB
1053 ("emacs"
1054 (or
1055 (name . "^\\*scratch\\*$")
4e0afb99 1056 (name . "^\\*Messages\\*$"))))))
5fece105
AB
1057 (ibuffer-formats
1058 '((mark modified read-only locked " "
1059 (name 18 18 :left :elide)
1060 " "
1061 (size-h 9 -1 :right)
1062 " "
1063 (mode 16 16 :left :elide)
1064 " " filename-and-process)
1065 (mark " "
1066 (name 16 -1)
1067 " " filename)))
1068 :hook (ibuffer . (lambda () (ibuffer-switch-to-saved-filter-groups "default"))))
1069#+end_src
1070
1071*** Outline
1072
1073#+begin_src emacs-lisp
1074(use-package outline
5fece105
AB
1075 :hook (prog-mode . outline-minor-mode)
1076 :bind
1077 (:map
1078 outline-minor-mode-map
1079 ("<s-tab>" . outline-toggle-children)
1080 ("M-p" . outline-previous-visible-heading)
1081 ("M-n" . outline-next-visible-heading)
c5d8bb25 1082 :prefix-map a/outline-prefix-map
5fece105
AB
1083 :prefix "s-o"
1084 ("TAB" . outline-toggle-children)
1085 ("a" . outline-hide-body)
1086 ("H" . outline-hide-body)
1087 ("S" . outline-show-all)
1088 ("h" . outline-hide-subtree)
1089 ("s" . outline-show-subtree)))
1090#+end_src
1091
6ce4ebba 1092*** Dired
5fece105
AB
1093
1094#+begin_src emacs-lisp
3b8e0d03
AB
1095(use-package ls-lisp
1096 :custom (ls-lisp-dirs-first t))
1097
5fece105 1098(use-package dired
cb0c13d0 1099 :config
3b8e0d03
AB
1100 (setq dired-listing-switches "-alh"
1101 ls-lisp-use-insert-directory-program nil)
cb0c13d0
AB
1102
1103 ;; easily diff 2 marked files
1104 ;; https://oremacs.com/2017/03/18/dired-ediff/
1105 (defun dired-ediff-files ()
1106 (interactive)
6ce4ebba 1107 (require 'dired-aux)
7bd8b3a2 1108 (defvar ediff-after-quit-hook-internal)
cb0c13d0
AB
1109 (let ((files (dired-get-marked-files))
1110 (wnd (current-window-configuration)))
1111 (if (<= (length files) 2)
1112 (let ((file1 (car files))
1113 (file2 (if (cdr files)
1114 (cadr files)
1115 (read-file-name
1116 "file: "
1117 (dired-dwim-target-directory)))))
1118 (if (file-newer-than-file-p file1 file2)
1119 (ediff-files file2 file1)
1120 (ediff-files file1 file2))
1121 (add-hook 'ediff-after-quit-hook-internal
1122 (lambda ()
1123 (setq ediff-after-quit-hook-internal nil)
1124 (set-window-configuration wnd))))
1125 (error "no more than 2 files should be marked"))))
1126 :bind (:map dired-mode-map
6ce4ebba 1127 ("b" . dired-up-directory)
0884b63b
AB
1128 ("e" . dired-ediff-files)
1129 ("E" . dired-toggle-read-only)
1130 ("\\" . dired-hide-details-mode)
1131 ("z" . (lambda ()
1132 (interactive)
1133 (a/dired-start-process "zathura"))))
1134 :hook (dired-mode . dired-hide-details-mode))
6ce4ebba 1135#+end_src
5fece105 1136
6ce4ebba 1137*** Help
5fece105 1138
6ce4ebba 1139#+begin_src emacs-lisp
5fece105 1140(use-package help
5fece105
AB
1141 :config
1142 (temp-buffer-resize-mode)
1143 (setq help-window-select t))
6ce4ebba 1144#+end_src
5fece105 1145
6ce4ebba 1146*** Tramp
5fece105 1147
6ce4ebba
AB
1148#+begin_src emacs-lisp
1149(use-package tramp
5fece105 1150 :config
6ce4ebba
AB
1151 (add-to-list 'tramp-default-proxies-alist '(nil "\\`root\\'" "/ssh:%h:"))
1152 (add-to-list 'tramp-default-proxies-alist '("localhost" nil nil))
1153 (add-to-list 'tramp-default-proxies-alist
1154 (list (regexp-quote (system-name)) nil nil)))
1155#+end_src
5fece105 1156
6ce4ebba
AB
1157*** Dash
1158
1159#+begin_src emacs-lisp
1160(use-package dash
1161 :config (dash-enable-font-lock))
1162#+end_src
1163
1164* Editing
1165:PROPERTIES:
1166:CUSTOM_ID: editing
1167:END:
1168
1169** =diff-hl=
1170
1171Highlight uncommitted changes in the left fringe.
1172
1173#+begin_src emacs-lisp
1174(use-package diff-hl
1175 :config
1176 (setq diff-hl-draw-borders nil)
1177 (global-diff-hl-mode)
1178 :hook (magit-post-refresh . diff-hl-magit-post-refresh))
1179#+end_src
1180
1181** ElDoc
1182
1183Display Lisp objects at point in the echo area.
1184
1185#+begin_src emacs-lisp
1186(use-package eldoc
1187 :when (version< "25" emacs-version)
1188 :config (global-eldoc-mode))
1189#+end_src
1190
1191** paren
1192
1193Highlight matching parens.
5fece105 1194
6ce4ebba 1195#+begin_src emacs-lisp
5fece105 1196(use-package paren
6ce4ebba 1197 :demand
5fece105 1198 :config (show-paren-mode))
6ce4ebba 1199#+end_src
5fece105 1200
6ce4ebba 1201** simple (for column numbers)
5fece105 1202
6ce4ebba
AB
1203#+begin_src emacs-lisp
1204(use-package simple
1205 :config (column-number-mode))
1206#+end_src
1207
1208** =savehist=
1209
1210Save minibuffer history.
5fece105 1211
6ce4ebba 1212#+begin_src emacs-lisp
5fece105
AB
1213(use-package savehist
1214 :config (savehist-mode))
6ce4ebba
AB
1215#+end_src
1216
1217** =saveplace=
5fece105 1218
6ce4ebba
AB
1219Automatically save place in each file.
1220
1221#+begin_src emacs-lisp
5fece105
AB
1222(use-package saveplace
1223 :when (version< "25" emacs-version)
1224 :config (save-place-mode))
6ce4ebba 1225#+end_src
5fece105 1226
6ce4ebba 1227** =prog-mode=
5fece105 1228
6ce4ebba
AB
1229#+begin_src emacs-lisp
1230(use-package prog-mode
1231 :config (global-prettify-symbols-mode)
1232 (defun indicate-buffer-boundaries-left ()
1233 (setq indicate-buffer-boundaries 'left))
1234 (add-hook 'prog-mode-hook #'indicate-buffer-boundaries-left))
1235#+end_src
5fece105 1236
6ce4ebba 1237** =text-mode=
5fece105 1238
6ce4ebba
AB
1239#+begin_src emacs-lisp
1240(use-package text-mode
1241 :hook ((text-mode . indicate-buffer-boundaries-left)
1242 (text-mode . abbrev-mode)))
5fece105
AB
1243#+end_src
1244
5fece105
AB
1245** Company
1246
1247#+begin_src emacs-lisp
1248(use-package company
1249 :defer 1
1250 :bind
1251 (:map company-active-map
1252 ([tab] . company-complete-common-or-cycle)
1253 ([escape] . company-abort))
1254 :custom
1255 (company-minimum-prefix-length 1)
1256 (company-selection-wrap-around t)
1257 (company-dabbrev-char-regexp "\\sw\\|\\s_\\|[-_]")
1258 (company-dabbrev-downcase nil)
1259 (company-dabbrev-ignore-case nil)
1260 :config
1261 (global-company-mode t))
1262#+end_src
1263
6ce4ebba 1264** Flycheck
5fece105 1265
5fece105
AB
1266#+begin_src emacs-lisp
1267(use-package flycheck
1268 :defer 3
1269 :hook (prog-mode . flycheck-mode)
1270 :bind
1271 (:map flycheck-mode-map
1272 ("M-P" . flycheck-previous-error)
1273 ("M-N" . flycheck-next-error))
1274 :config
1275 ;; Use the load-path from running Emacs when checking elisp files
1276 (setq flycheck-emacs-lisp-load-path 'inherit)
1277
1278 ;; Only flycheck when I actually save the buffer
1279 (setq flycheck-check-syntax-automatically '(mode-enabled save)))
1280
1281;; http://endlessparentheses.com/ispell-and-apostrophes.html
1282(use-package ispell
1283 :defer 3
1284 :config
1285 ;; ’ can be part of a word
1286 (setq ispell-local-dictionary-alist
1287 `((nil "[[:alpha:]]" "[^[:alpha:]]"
1288 "['\x2019]" nil ("-B") nil utf-8)))
1289 ;; don't send ’ to the subprocess
1290 (defun endless/replace-apostrophe (args)
1291 (cons (replace-regexp-in-string
1292 "’" "'" (car args))
1293 (cdr args)))
1294 (advice-add #'ispell-send-string :filter-args
1295 #'endless/replace-apostrophe)
1296
1297 ;; convert ' back to ’ from the subprocess
1298 (defun endless/replace-quote (args)
1299 (if (not (derived-mode-p 'org-mode))
1300 args
1301 (cons (replace-regexp-in-string
1302 "'" "’" (car args))
1303 (cdr args))))
1304 (advice-add #'ispell-parse-output :filter-args
1305 #'endless/replace-quote))
1306#+end_src
9678e6da 1307
5fece105 1308* Programming modes
673d5faa
AB
1309:PROPERTIES:
1310:CUSTOM_ID: programming-modes
1311:END:
5fece105 1312
6ce4ebba
AB
1313** Lisp
1314
1315#+begin_src emacs-lisp
1316(use-package lisp-mode
1317 :config
1318 (add-hook 'emacs-lisp-mode-hook 'outline-minor-mode)
1319 (add-hook 'emacs-lisp-mode-hook 'reveal-mode)
1320 (defun indent-spaces-mode ()
1321 (setq indent-tabs-mode nil))
1322 (add-hook 'lisp-interaction-mode-hook #'indent-spaces-mode))
1323#+end_src
1324
5fece105
AB
1325** [[http://alloytools.org][Alloy]] (with [[https://github.com/dwwmmn/alloy-mode][alloy-mode]])
1326
1327#+begin_src emacs-lisp
1328(use-package alloy-mode
5fece105
AB
1329 :config (setq alloy-basic-offset 2))
1330#+end_src
1331
1332** [[https://coq.inria.fr][Coq]] (with [[https://github.com/ProofGeneral/PG][Proof General]])
1333
1334#+begin_src emacs-lisp
1335(use-package proof-site ; Proof General
5fece105
AB
1336 :load-path "lib/proof-site/generic/")
1337#+end_src
1338
1339** [[https://leanprover.github.io][Lean]] (with [[https://github.com/leanprover/lean-mode][lean-mode]])
1340
1341#+begin_src emacs-lisp
1342(eval-when-compile (defvar lean-mode-map))
1343(use-package lean-mode
1344 :defer 1
1345 :bind (:map lean-mode-map
1346 ("S-SPC" . company-complete))
1347 :config
1348 (require 'lean-input)
1349 (setq default-input-method "Lean"
1350 lean-input-tweak-all '(lean-input-compose
1351 (lean-input-prepend "/")
1352 (lean-input-nonempty))
1353 lean-input-user-translations '(("/" "/")))
1354 (lean-input-setup))
1355 #+end_src
1356
1357** Haskell
1358
1359*** [[https://github.com/haskell/haskell-mode][haskell-mode]]
1360
1361#+begin_src emacs-lisp
1362(use-package haskell-mode
5fece105
AB
1363 :config
1364 (setq haskell-indentation-layout-offset 4
1365 haskell-indentation-left-offset 4
1366 flycheck-checker 'haskell-hlint
1367 flycheck-disabled-checkers '(haskell-stack-ghc haskell-ghc)))
1368#+end_src
1369
1370*** [[https://github.com/jyp/dante][dante]]
1371
1372#+begin_src emacs-lisp
1373(use-package dante
1374 :after haskell-mode
1375 :commands dante-mode
1376 :hook (haskell-mode . dante-mode))
1377#+end_src
1378
1379*** [[https://github.com/mpickering/hlint-refactor-mode][hlint-refactor]]
1380
1381Emacs bindings for [[https://github.com/ndmitchell/hlint][hlint]]'s refactor option. This requires the refact
1382executable from [[https://github.com/mpickering/apply-refact][apply-refact]].
1383
1384#+begin_src emacs-lisp
1385(use-package hlint-refactor
1386 :after haskell-mode
1387 :bind (:map hlint-refactor-mode-map
1388 ("C-c l b" . hlint-refactor-refactor-buffer)
1389 ("C-c l r" . hlint-refactor-refactor-at-point))
1390 :hook (haskell-mode . hlint-refactor-mode))
1391#+end_src
1392
1393*** [[https://github.com/flycheck/flycheck-haskell][flycheck-haskell]]
1394
1395#+begin_src emacs-lisp
1396(use-package flycheck-haskell
1397 :after haskell-mode)
1398#+end_src
1399
1400*** [[https://github.com/ndmitchell/hlint/blob/20e116a043f2073c57b17b24ae6364b5e433ba7e/data/hs-lint.el][hs-lint.el]]
1401:PROPERTIES:
1402:header-args+: :tangle lisp/hs-lint.el :mkdirp yes
1403:END:
1404
1405Currently using =flycheck-haskell= with the =haskell-hlint= checker
1406instead.
1407
1408#+begin_src emacs-lisp :tangle no
1409;;; hs-lint.el --- minor mode for HLint code checking
1410
1411;; Copyright 2009 (C) Alex Ott
1412;;
1413;; Author: Alex Ott <alexott@gmail.com>
1414;; Keywords: haskell, lint, HLint
1415;; Requirements:
1416;; Status: distributed under terms of GPL2 or above
1417
1418;; Typical message from HLint looks like:
1419;;
1420;; /Users/ott/projects/lang-exp/haskell/test.hs:52:1: Eta reduce
1421;; Found:
1422;; count1 p l = length (filter p l)
1423;; Why not:
1424;; count1 p = length . filter p
1425
1426
1427(require 'compile)
1428
1429(defgroup hs-lint nil
1430 "Run HLint as inferior of Emacs, parse error messages."
1431 :group 'tools
1432 :group 'haskell)
1433
1434(defcustom hs-lint-command "hlint"
1435 "The default hs-lint command for \\[hlint]."
1436 :type 'string
1437 :group 'hs-lint)
1438
1439(defcustom hs-lint-save-files t
1440 "Save modified files when run HLint or no (ask user)"
1441 :type 'boolean
1442 :group 'hs-lint)
1443
1444(defcustom hs-lint-replace-with-suggestions nil
1445 "Replace user's code with suggested replacements"
1446 :type 'boolean
1447 :group 'hs-lint)
1448
1449(defcustom hs-lint-replace-without-ask nil
1450 "Replace user's code with suggested replacements automatically"
1451 :type 'boolean
1452 :group 'hs-lint)
1453
1454(defun hs-lint-process-setup ()
1455 "Setup compilation variables and buffer for `hlint'."
1456 (run-hooks 'hs-lint-setup-hook))
1457
1458;; regex for replace suggestions
1459;;
1460;; ^\(.*?\):\([0-9]+\):\([0-9]+\): .*
1461;; Found:
1462;; \s +\(.*\)
1463;; Why not:
1464;; \s +\(.*\)
1465
1466(defvar hs-lint-regex
1467 "^\\(.*?\\):\\([0-9]+\\):\\([0-9]+\\): .*[\n\C-m]Found:[\n\C-m]\\s +\\(.*\\)[\n\C-m]Why not:[\n\C-m]\\s +\\(.*\\)[\n\C-m]"
1468 "Regex for HLint messages")
1469
1470(defun make-short-string (str maxlen)
1471 (if (< (length str) maxlen)
1472 str
1473 (concat (substring str 0 (- maxlen 3)) "...")))
1474
1475(defun hs-lint-replace-suggestions ()
1476 "Perform actual replacement of suggestions"
1477 (goto-char (point-min))
1478 (while (re-search-forward hs-lint-regex nil t)
1479 (let* ((fname (match-string 1))
1480 (fline (string-to-number (match-string 2)))
1481 (old-code (match-string 4))
1482 (new-code (match-string 5))
1483 (msg (concat "Replace '" (make-short-string old-code 30)
1484 "' with '" (make-short-string new-code 30) "'"))
1485 (bline 0)
1486 (eline 0)
1487 (spos 0)
1488 (new-old-code ""))
1489 (save-excursion
1490 (switch-to-buffer (get-file-buffer fname))
1491 (goto-char (point-min))
1492 (forward-line (1- fline))
1493 (beginning-of-line)
1494 (setf bline (point))
1495 (when (or hs-lint-replace-without-ask
1496 (yes-or-no-p msg))
1497 (end-of-line)
1498 (setf eline (point))
1499 (beginning-of-line)
1500 (setf old-code (regexp-quote old-code))
1501 (while (string-match "\\\\ " old-code spos)
1502 (setf new-old-code (concat new-old-code
1503 (substring old-code spos (match-beginning 0))
1504 "\\ *"))
1505 (setf spos (match-end 0)))
1506 (setf new-old-code (concat new-old-code (substring old-code spos)))
1507 (remove-text-properties bline eline '(composition nil))
1508 (when (re-search-forward new-old-code eline t)
1509 (replace-match new-code nil t)))))))
1510
1511(defun hs-lint-finish-hook (buf msg)
1512 "Function, that is executed at the end of HLint execution"
1513 (if hs-lint-replace-with-suggestions
1514 (hs-lint-replace-suggestions)
1515 (next-error 1 t)))
1516
1517(define-compilation-mode hs-lint-mode "HLint"
1518 "Mode for check Haskell source code."
1519 (set (make-local-variable 'compilation-process-setup-function)
1520 'hs-lint-process-setup)
1521 (set (make-local-variable 'compilation-disable-input) t)
1522 (set (make-local-variable 'compilation-scroll-output) nil)
1523 (set (make-local-variable 'compilation-finish-functions)
1524 (list 'hs-lint-finish-hook))
1525 )
1526
1527(defun hs-lint ()
1528 "Run HLint for current buffer with haskell source"
1529 (interactive)
1530 (save-some-buffers hs-lint-save-files)
1531 (compilation-start (concat hs-lint-command " \"" buffer-file-name "\"")
1532 'hs-lint-mode))
1533
1534(provide 'hs-lint)
1535;;; hs-lint.el ends here
1536#+end_src
1537
1538#+begin_src emacs-lisp :tangle no
1539(use-package hs-lint
1540 :load-path "lisp/"
1541 :bind (:map haskell-mode-map
1542 ("C-c l l" . hs-lint)))
1543#+end_src
1544
6ce4ebba 1545** Web
5fece105
AB
1546
1547*** SGML and HTML
1548
1549#+begin_src emacs-lisp
1550(use-package sgml-mode
5fece105
AB
1551 :config
1552 (setq sgml-basic-offset 2))
1553#+end_src
1554
1555*** CSS and SCSS
1556
1557#+begin_src emacs-lisp
1558(use-package css-mode
5fece105
AB
1559 :config
1560 (setq css-indent-offset 2))
1561#+end_src
1562
1563*** Web mode
1564
1565#+begin_src emacs-lisp
1566(use-package web-mode
5fece105
AB
1567 :mode "\\.html\\'"
1568 :config
c5d8bb25 1569 (a/setq-every 2
5fece105
AB
1570 web-mode-code-indent-offset
1571 web-mode-css-indent-offset
1572 web-mode-markup-indent-offset))
1573#+end_src
1574
1575*** Emmet mode
1576
1577#+begin_src emacs-lisp
1578(use-package emmet-mode
1579 :after (:any web-mode css-mode sgml-mode)
1580 :bind* (("C-)" . emmet-next-edit-point)
1581 ("C-(" . emmet-prev-edit-point))
1582 :config
1583 (unbind-key "C-j" emmet-mode-keymap)
1584 (setq emmet-move-cursor-between-quotes t)
1585 :hook (web-mode css-mode html-mode sgml-mode))
1586#+end_src
1587
9cebbd53 1588** COMMENT Java
5fece105
AB
1589
1590*** meghanada
1591
9cebbd53 1592#+begin_src emacs-lisp
5fece105
AB
1593(use-package meghanada
1594 :bind
1595 (:map meghanada-mode-map
1596 (("C-M-o" . meghanada-optimize-import)
1597 ("C-M-t" . meghanada-import-all)))
1598 :hook (java-mode . meghanada-mode))
1599#+end_src
1600
1601*** lsp-java
1602
1603#+begin_comment
1604dependencies:
1605
1606ace-window
1607avy
1608bui
1609company-lsp
1610dap-mode
1611lsp-java
1612lsp-mode
1613lsp-ui
1614pfuture
1615tree-mode
1616treemacs
1617#+end_comment
1618
9cebbd53 1619#+begin_src emacs-lisp
5fece105
AB
1620(use-package treemacs
1621 :config (setq treemacs-never-persist t))
1622
1623(use-package yasnippet
1624 :config
1625 ;; (yas-global-mode)
1626 )
1627
1628(use-package lsp-mode
1629 :init (setq lsp-eldoc-render-all nil
1630 lsp-highlight-symbol-at-point nil)
1631 )
1632
1633(use-package hydra)
1634
1635(use-package company-lsp
1636 :after company
1637 :config
1638 (setq company-lsp-cache-candidates t
1639 company-lsp-async t))
1640
1641(use-package lsp-ui
1642 :config
1643 (setq lsp-ui-sideline-update-mode 'point))
1644
1645(use-package lsp-java
1646 :config
1647 (add-hook 'java-mode-hook
1648 (lambda ()
1649 (setq-local company-backends (list 'company-lsp))))
1650
1651 (add-hook 'java-mode-hook 'lsp-java-enable)
1652 (add-hook 'java-mode-hook 'flycheck-mode)
1653 (add-hook 'java-mode-hook 'company-mode)
1654 (add-hook 'java-mode-hook 'lsp-ui-mode))
1655
1656(use-package dap-mode
1657 :after lsp-mode
1658 :config
1659 (dap-mode t)
1660 (dap-ui-mode t))
1661
1662(use-package dap-java
1663 :after (lsp-java))
1664
1665(use-package lsp-java-treemacs
1666 :after (treemacs))
1667#+end_src
1668
5492a3dc
AB
1669** geiser
1670
1671#+begin_src emacs-lisp
1672(use-package geiser)
1673
1674(use-package geiser-guile
1675 :config
1676 (setq geiser-guile-load-path "~/src/git/guix"))
1677#+end_src
1678
1679** guix
1680
1681#+begin_src emacs-lisp
1682(use-package guix
1683 :load-path "lib/guix/elisp")
1684#+end_src
1685
673d5faa
AB
1686* Emacs enhancements
1687:PROPERTIES:
1688:CUSTOM_ID: emacs-enhancements
1689:END:
5fece105 1690
6ce4ebba
AB
1691** man
1692
1693#+begin_src emacs-lisp
1694(use-package man
1695 :config (setq Man-width 80))
1696#+end_src
1697
5fece105
AB
1698** [[https://github.com/justbur/emacs-which-key][which-key]]
1699
1700#+begin_quote
1701Emacs package that displays available keybindings in popup
1702#+end_quote
1703
1704#+begin_src emacs-lisp
1705(use-package which-key
1706 :defer 1
169947ac
AB
1707 :config
1708 (which-key-add-key-based-replacements
1709 ;; prefixes for global prefixes and minor modes
1710 "C-c @" "outline"
1711 "C-c !" "flycheck"
1712 "C-c 8" "typo"
1713 "C-c 8 -" "typo/dashes"
1714 "C-c 8 <" "typo/left-brackets"
1715 "C-c 8 >" "typo/right-brackets"
1716 "C-x 8" "unicode"
1717 "C-x a" "abbrev/expand"
1718 "C-x r" "rectangle/register/bookmark"
1719 "C-x v" "version control"
1720 ;; prefixes for my personal bindings
1721 "C-c a" "applications"
1722 "C-c a s" "shells"
1723 "C-c b" "borg"
1724 "C-c c" "compile-and-comments"
1725 "C-c e" "eval"
1726 "C-c f" "files"
1727 "C-c F" "frames"
1728 "C-S-h" "help(ful)"
1729 "C-c m" "multiple-cursors"
1730 "C-c p" "projectile"
1731 "C-c p s" "projectile/search"
1732 "C-c p x" "projectile/execute"
1733 "C-c p 4" "projectile/other-window"
1734 "C-c q" "boxquote"
1735 "s-g" "magit"
1736 "s-o" "outline"
1737 "s-t" "themes")
1738
1739 ;; prefixes for major modes
1740 (which-key-add-major-mode-key-based-replacements 'message-mode
1741 "C-c f" "footnote")
1742 (which-key-add-major-mode-key-based-replacements 'org-mode
1743 "C-c C-v" "org-babel")
1744 (which-key-add-major-mode-key-based-replacements 'web-mode
1745 "C-c C-a" "web/attributes"
1746 "C-c C-b" "web/blocks"
1747 "C-c C-d" "web/dom"
1748 "C-c C-e" "web/element"
1749 "C-c C-t" "web/tags")
1750
1751 (which-key-mode))
5fece105
AB
1752#+end_src
1753
1754** theme
1755
1756#+begin_src emacs-lisp
1757(add-to-list 'custom-theme-load-path "~/.emacs.d/lisp")
1758(load-theme 'tangomod t)
1759#+end_src
1760
21ad71fa 1761** smart-mode-line
5fece105
AB
1762
1763#+begin_src emacs-lisp
21ad71fa 1764(use-package smart-mode-line
6ce4ebba 1765 :demand
21ad71fa
AB
1766 :config
1767 (sml/setup))
5fece105
AB
1768#+end_src
1769
1770** doom-themes
1771
1772#+begin_src emacs-lisp
1773(use-package doom-themes)
1774#+end_src
1775
1776** theme helper functions
1777
1778#+begin_src emacs-lisp
c5d8bb25 1779(defun a/lights-on ()
5fece105
AB
1780 "Enable my favourite light theme."
1781 (interactive)
21ad71fa
AB
1782 (mapc #'disable-theme custom-enabled-themes)
1783 (load-theme 'tangomod t)
1784 (sml/apply-theme 'automatic))
5fece105 1785
c5d8bb25 1786(defun a/lights-off ()
5fece105
AB
1787 "Go dark."
1788 (interactive)
21ad71fa
AB
1789 (mapc #'disable-theme custom-enabled-themes)
1790 (load-theme 'doom-tomorrow-night t)
1791 (sml/apply-theme 'automatic))
5fece105
AB
1792
1793(bind-keys
c5d8bb25
AB
1794 ("s-t d" . a/lights-off)
1795 ("s-t l" . a/lights-on))
5fece105
AB
1796#+end_src
1797
1798** [[https://github.com/bbatsov/crux][crux]]
1799
1800#+begin_src emacs-lisp
1801(use-package crux
1802 :defer 1
1803 :bind (("C-c b k" . crux-kill-other-buffers)
1804 ("C-c d" . crux-duplicate-current-line-or-region)
1805 ("C-c D" . crux-duplicate-and-comment-current-line-or-region)
1806 ("C-c f c" . crux-copy-file-preserve-attributes)
1807 ("C-c f d" . crux-delete-file-and-buffer)
1808 ("C-c f r" . crux-rename-file-and-buffer)
1809 ("C-c j" . crux-top-join-line)
1810 ("C-S-j" . crux-top-join-line)))
1811#+end_src
1812
1813** [[https://github.com/alezost/mwim.el][mwim]]
1814
1815#+begin_src emacs-lisp
1816(use-package mwim
1817 :bind (("C-a" . mwim-beginning-of-code-or-line)
1818 ("C-e" . mwim-end-of-code-or-line)
1819 ("<home>" . mwim-beginning-of-line-or-code)
1820 ("<end>" . mwim-end-of-line-or-code)))
1821#+end_src
1822
1823** projectile
1824
1825#+begin_src emacs-lisp
1826(use-package projectile
5fece105
AB
1827 :bind-keymap ("C-c p" . projectile-command-map)
1828 :config
1829 (projectile-mode)
1830
1831 (defun my-projectile-invalidate-cache (&rest _args)
1832 ;; ignore the args to `magit-checkout'
1833 (projectile-invalidate-cache nil))
1834
1835 (eval-after-load 'magit-branch
1836 '(progn
1837 (advice-add 'magit-checkout
1838 :after #'my-projectile-invalidate-cache)
1839 (advice-add 'magit-branch-and-checkout
c371adda
AB
1840 :after #'my-projectile-invalidate-cache)))
1841 :custom (projectile-completion-system 'ivy))
5fece105
AB
1842#+end_src
1843
1844** [[https://github.com/Wilfred/helpful][helpful]]
1845
1846#+begin_src emacs-lisp
1847(use-package helpful
1848 :defer 1
1849 :bind
1850 (("C-S-h c" . helpful-command)
1851 ("C-S-h f" . helpful-callable) ; helpful-function
1852 ("C-S-h v" . helpful-variable)
1853 ("C-S-h k" . helpful-key)
1854 ("C-S-h p" . helpful-at-point)))
1855#+end_src
1856
5fece105
AB
1857** [[https://github.com/EricCrosson/unkillable-scratch][unkillable-scratch]]
1858
1859Make =*scratch*= and =*Messages*= unkillable.
1860
1861#+begin_src emacs-lisp
1862(use-package unkillable-scratch
1863 :defer 3
1864 :config
1865 (unkillable-scratch 1)
1866 :custom
1867 (unkillable-scratch-behavior 'do-nothing)
1868 (unkillable-buffers '("^\\*scratch\\*$" "^\\*Messages\\*$")))
1869#+end_src
1870
1871** [[https://github.com/davep/boxquote.el][boxquote.el]]
1872
1873#+begin_example
1874,----
1875| make pretty boxed quotes like this
1876`----
1877#+end_example
1878
1879#+begin_src emacs-lisp
1880(use-package boxquote
1881 :defer 3
1882 :bind
c5d8bb25 1883 (:prefix-map a/boxquote-prefix-map
5fece105
AB
1884 :prefix "C-c q"
1885 ("b" . boxquote-buffer)
1886 ("B" . boxquote-insert-buffer)
1887 ("d" . boxquote-defun)
1888 ("F" . boxquote-insert-file)
1889 ("hf" . boxquote-describe-function)
1890 ("hk" . boxquote-describe-key)
1891 ("hv" . boxquote-describe-variable)
1892 ("hw" . boxquote-where-is)
1893 ("k" . boxquote-kill)
1894 ("p" . boxquote-paragraph)
1895 ("q" . boxquote-boxquote)
1896 ("r" . boxquote-region)
1897 ("s" . boxquote-shell-command)
1898 ("t" . boxquote-text)
1899 ("T" . boxquote-title)
1900 ("u" . boxquote-unbox)
1901 ("U" . boxquote-unbox-region)
1902 ("y" . boxquote-yank)
1903 ("M-q" . boxquote-fill-paragraph)
1904 ("M-w" . boxquote-kill-ring-save)))
1905#+end_src
1906
1907Also see [[https://www.emacswiki.org/emacs/rebox2][rebox2]].
1908
6ce4ebba
AB
1909** orgalist
1910
1911#+begin_src emacs-lisp
1912(use-package orgalist
1913 :after message
1914 :hook (message-mode . orgalist-mode))
1915#+end_src
1916
5fece105
AB
1917** typo.el
1918
1919#+begin_src emacs-lisp
1920(use-package typo
1921 :defer 2
1922 :config
1923 (typo-global-mode 1)
1924 :hook (text-mode . typo-mode))
1925#+end_src
1926
1927** hl-todo
1928
1929#+begin_src emacs-lisp
1930(use-package hl-todo
1931 :defer 4
1932 :config
1933 (global-hl-todo-mode))
1934#+end_src
1935
1936** shrink-path
1937
1938#+begin_src emacs-lisp
1939(use-package shrink-path
6ce4ebba 1940 :defer 2
5fece105
AB
1941 :after eshell
1942 :config
5fece105
AB
1943 (defun +eshell/prompt ()
1944 (let ((base/dir (shrink-path-prompt default-directory)))
1945 (concat (propertize (car base/dir)
1946 'face 'font-lock-comment-face)
1947 (propertize (cdr base/dir)
1948 'face 'font-lock-constant-face)
1949 (propertize (+eshell--current-git-branch)
1950 'face 'font-lock-function-name-face)
1951 "\n"
1952 (propertize "λ" 'face 'eshell-prompt-face)
1953 ;; needed for the input text to not have prompt face
1954 (propertize " " 'face 'default))))
1955
1956 (defun +eshell--current-git-branch ()
1957 (let ((branch (car (loop for match in (split-string (shell-command-to-string "git branch") "\n")
1958 when (string-match "^\*" match)
1959 collect match))))
1960 (if (not (eq branch nil))
1961 (concat " " (substring branch 2))
6ce4ebba
AB
1962 "")))
1963 (setq eshell-prompt-regexp "\\(.*\n\\)*λ "
1964 eshell-prompt-function #'+eshell/prompt))
5fece105
AB
1965#+end_src
1966
5fece105
AB
1967** [[https://github.com/peterwvj/eshell-up][eshell-up]]
1968
1969#+begin_src emacs-lisp
1970(use-package eshell-up
6ce4ebba
AB
1971 :after eshell
1972 :commands eshell-up)
5fece105
AB
1973#+end_src
1974
1975** multi-term
1976
1977#+begin_src emacs-lisp
1978(use-package multi-term
1979 :defer 1
169947ac 1980 :bind (("C-c a s m" . multi-term-dedicated-toggle)
a219024e
AB
1981 :map term-mode-map
1982 ("C-c C-j" . term-char-mode)
1983 :map term-raw-map
1984 ("C-c C-j" . term-line-mode))
5fece105
AB
1985 :config
1986 (setq multi-term-program "/bin/screen"
1987 ;; TODO: add separate bindings for connecting to existing
1988 ;; session vs. always creating a new one
1989 multi-term-dedicated-select-after-open-p t
1990 multi-term-dedicated-window-height 20
1991 multi-term-dedicated-max-window-height 30
1992 term-bind-key-alist
1993 '(("C-c C-c" . term-interrupt-subjob)
1994 ("C-c C-e" . term-send-esc)
1995 ("C-k" . kill-line)
1996 ("C-y" . term-paste)
1997 ("M-f" . term-send-forward-word)
1998 ("M-b" . term-send-backward-word)
1999 ("M-p" . term-send-up)
2000 ("M-n" . term-send-down)
2001 ("<C-backspace>" . term-send-backward-kill-word)
2002 ("<M-DEL>" . term-send-backward-kill-word)
2003 ("M-d" . term-send-delete-word)
2004 ("M-," . term-send-raw)
2005 ("M-." . comint-dynamic-complete))
2006 term-unbind-key-alist
2007 '("C-z" "C-x" "C-c" "C-h" "C-y" "<ESC>")))
2008#+end_src
2009
2010** page-break-lines
2011
2012#+begin_src emacs-lisp
2013(use-package page-break-lines
2014 :config
2015 (global-page-break-lines-mode))
2016#+end_src
2017
f2a57944
AB
2018** expand-region
2019
2020#+begin_src emacs-lisp
2021(use-package expand-region
2022 :bind ("C-=" . er/expand-region))
2023#+end_src
2024
64e429b5
AB
2025** multiple-cursors
2026
2027#+begin_src emacs-lisp
2028(use-package multiple-cursors
1bbc615c
AB
2029 :bind
2030 (("C-S-<mouse-1>" . mc/add-cursor-on-click)
2031 (:prefix-map a/mc-prefix-map
2032 :prefix "C-c m"
2033 ("c" . mc/edit-lines)
2034 ("n" . mc/mark-next-like-this)
2035 ("p" . mc/mark-previous-like-this)
2036 ("a" . mc/mark-all-like-this))))
64e429b5 2037#+end_src
0884b63b 2038
5fece105 2039* Email
673d5faa
AB
2040:PROPERTIES:
2041:CUSTOM_ID: email
2042:END:
5fece105 2043
5fece105 2044#+begin_src emacs-lisp
c5d8bb25 2045(defvar a/maildir (expand-file-name "~/mail/"))
ab6781dd 2046(with-eval-after-load 'recentf
c5d8bb25 2047 (add-to-list 'recentf-exclude a/maildir))
5fece105
AB
2048#+end_src
2049
2050** Gnus
2051
2052#+begin_src emacs-lisp
2053(setq
c5d8bb25
AB
2054 a/gnus-init-file (no-littering-expand-etc-file-name "gnus")
2055 mail-user-agent 'gnus-user-agent
2056 read-mail-command 'gnus)
5fece105
AB
2057
2058(use-package gnus
1bbc615c 2059 :bind (("s-m" . gnus)
a0801748 2060 ("s-M" . gnus-unplugged))
5fece105
AB
2061 :init
2062 (setq
2063 gnus-select-method '(nnnil "")
2064 gnus-secondary-select-methods
2065 '((nnimap "amin"
2066 (nnimap-stream plain)
2067 (nnimap-address "127.0.0.1")
2068 (nnimap-server-port 143)
2069 (nnimap-authenticator plain)
2070 (nnimap-user "amin@aminb.org"))
2071 (nnimap "uwaterloo"
2072 (nnimap-stream plain)
2073 (nnimap-address "127.0.0.1")
2074 (nnimap-server-port 143)
2075 (nnimap-authenticator plain)
2076 (nnimap-user "abandali@uwaterloo.ca")))
2077 gnus-message-archive-group "nnimap+amin:Sent"
2078 gnus-parameters
2079 '(("gnu.*"
2080 (gcc-self . t)))
2081 gnus-large-newsgroup 50
2082 gnus-home-directory (no-littering-expand-var-file-name "gnus/")
2083 gnus-directory (concat gnus-home-directory "news/")
2084 message-directory (concat gnus-home-directory "mail/")
2085 nndraft-directory (concat gnus-home-directory "drafts/")
2086 gnus-save-newsrc-file nil
2087 gnus-read-newsrc-file nil
2088 gnus-interactive-exit nil
2089 gnus-gcc-mark-as-read t))
2090
2091(use-package gnus-art
2092 :config
2093 (setq
2094 gnus-visible-headers
2095 (concat gnus-visible-headers "\\|^List-Id:\\|^X-RT-Originator:\\|^User-Agent:")
2096 gnus-sorted-header-list
2097 '("^From:" "^Subject:" "^Summary:" "^Keywords:"
2098 "^Followup-To:" "^To:" "^Cc:" "X-RT-Originator"
2099 "^Newsgroups:" "List-Id:" "^Organization:"
2100 "^User-Agent:" "^Date:")
2101 ;; local-lapsed article dates
2102 ;; from https://www.emacswiki.org/emacs/GnusFormatting#toc11
2103 gnus-article-date-headers '(user-defined)
2104 gnus-article-time-format
2105 (lambda (time)
2106 (let* ((date (format-time-string "%a, %d %b %Y %T %z" time))
2107 (local (article-make-date-line date 'local))
2108 (combined-lapsed (article-make-date-line date
2109 'combined-lapsed))
2110 (lapsed (progn
2111 (string-match " (.+" combined-lapsed)
2112 (match-string 0 combined-lapsed))))
2113 (concat local lapsed))))
2114 (bind-keys
2115 :map gnus-article-mode-map
2116 ("r" . gnus-article-reply-with-original)
2117 ("R" . gnus-article-wide-reply-with-original)
2118 ("M-L" . org-store-link)))
2119
2120(use-package gnus-sum
2121 :bind (:map gnus-summary-mode-map
c5d8bb25 2122 :prefix-map a/gnus-summary-prefix-map
5fece105
AB
2123 :prefix "v"
2124 ("r" . gnus-summary-reply)
2125 ("w" . gnus-summary-wide-reply)
2126 ("v" . gnus-summary-show-raw-article))
2127 :config
2128 (bind-keys
2129 :map gnus-summary-mode-map
2130 ("r" . gnus-summary-reply-with-original)
2131 ("R" . gnus-summary-wide-reply-with-original)
2132 ("M-L" . org-store-link))
c5d8bb25 2133 :hook (gnus-summary-mode . a/no-mouse-autoselect-window))
5fece105
AB
2134
2135(use-package gnus-msg
2136 :config
2137 (setq gnus-posting-styles
2138 '((".*"
2139 (address "amin@aminb.org")
2140 (body "\nBest,\namin\n")
c5d8bb25 2141 (eval (setq a/message-cite-say-hi t)))
5fece105
AB
2142 ("gnu.*"
2143 (address "bandali@gnu.org"))
2144 ((header "subject" "ThankCRM")
2145 (to "webmasters-comment@gnu.org")
2146 (body "\nAdded to 2018supporters.html.\n\nMoving to campaigns.\n\n-amin\n")
c5d8bb25 2147 (eval (setq a/message-cite-say-hi nil)))
5fece105
AB
2148 ("nnimap\\+uwaterloo:.*"
2149 (address "abandali@uwaterloo.ca")
2150 (gcc "\"nnimap+uwaterloo:Sent Items\"")))))
2151
2152(use-package gnus-topic
2153 :hook (gnus-group-mode . gnus-topic-mode))
2154
2155(use-package gnus-agent
2156 :config
2157 (setq gnus-agent-synchronize-flags 'ask)
2158 :hook (gnus-group-mode . gnus-agent-mode))
2159
2160(use-package gnus-group
2161 :config
2162 (setq gnus-permanently-visible-groups "\\((INBOX\\|gnu$\\)"))
2163
2164(use-package mm-decode
2165 :config
2166 (setq mm-discouraged-alternatives '("text/html" "text/richtext")))
2167#+end_src
2168
2169** sendmail
2170
2171#+begin_src emacs-lisp
2172(use-package sendmail
2173 :config
2174 (setq sendmail-program "/usr/bin/msmtp"
2175 ;; message-sendmail-extra-arguments '("-v" "-d")
2176 mail-specify-envelope-from t
2177 mail-envelope-from 'header))
2178#+end_src
2179
2180** message
2181
2182#+begin_src emacs-lisp
2183(use-package message
2184 :config
c5d8bb25 2185 (defconst a/message-cite-style-format "On %Y-%m-%d %l:%M %p, %N wrote:")
5fece105
AB
2186 (defconst message-cite-style-bandali
2187 '((message-cite-function 'message-cite-original)
2188 (message-citation-line-function 'message-insert-formatted-citation-line)
2189 (message-cite-reply-position 'traditional)
2190 (message-yank-prefix "> ")
2191 (message-yank-cited-prefix ">")
2192 (message-yank-empty-prefix ">")
2193 (message-citation-line-format
c5d8bb25
AB
2194 (if a/message-cite-say-hi
2195 (concat "Hi %F,\n\n" a/message-cite-style-format)
2196 a/message-cite-style-format)))
5fece105
AB
2197 "Citation style based on Mozilla Thunderbird's. Use with message-cite-style.")
2198 (setq message-cite-style 'message-cite-style-bandali
2199 message-kill-buffer-on-exit t
2200 message-send-mail-function 'message-send-mail-with-sendmail
2201 message-sendmail-envelope-from 'header
2202 message-dont-reply-to-names
2203 "\\(\\(.*@aminb\\.org\\)\\|\\(amin@bandali\\.me\\)\\|\\(\\(aminb?\\|mab\\|bandali\\)@gnu\\.org\\)\\|\\(\\(m\\|a\\(min\\.\\)?\\)bandali@uwaterloo\\.ca\\)\\)"
2204 message-user-fqdn "aminb.org")
2205 :hook (;; (message-setup . mml-secure-message-sign-pgpmime)
2206 (message-mode . flyspell-mode)
2207 (message-mode . (lambda ()
2208 ;; (setq fill-column 65
2209 ;; message-fill-column 65)
2210 (make-local-variable 'company-idle-delay)
2211 (setq company-idle-delay 0.2))))
2212 ;; :custom-face
2213 ;; (message-header-subject ((t (:foreground "#111" :weight semi-bold))))
2214 ;; (message-header-to ((t (:foreground "#111" :weight normal))))
2215 ;; (message-header-cc ((t (:foreground "#333" :weight normal))))
2216 )
2217
ab6781dd 2218(with-eval-after-load 'mml-sec
5fece105
AB
2219 (setq mml-secure-openpgp-encrypt-to-self t
2220 mml-secure-openpgp-sign-with-sender t))
2221#+end_src
2222
2223** footnote
2224
2225Convenient footnotes in =message-mode=.
2226
2227#+begin_src emacs-lisp
2228(use-package footnote
2229 :after message
2230 :bind
2231 (:map message-mode-map
c5d8bb25 2232 :prefix-map a/footnote-prefix-map
5fece105
AB
2233 :prefix "C-c f"
2234 ("a" . footnote-add-footnote)
2235 ("b" . footnote-back-to-message)
2236 ("c" . footnote-cycle-style)
2237 ("d" . footnote-delete-footnote)
2238 ("g" . footnote-goto-footnote)
2239 ("r" . footnote-renumber-footnotes)
2240 ("s" . footnote-set-style))
2241 :config
2242 (setq footnote-start-tag ""
2243 footnote-end-tag ""
2244 footnote-style 'unicode))
2245#+end_src
2246
490554d3
AB
2247** ebdb
2248
2249#+begin_src emacs-lisp
2250(use-package ebdb
6ce4ebba 2251 :after gnus
490554d3
AB
2252 :bind (:map gnus-group-mode-map ("e" . ebdb))
2253 :config
2254 (setq ebdb-sources (no-littering-expand-var-file-name "ebdb"))
ab6781dd 2255 (with-eval-after-load 'swiper
490554d3
AB
2256 (add-to-list 'swiper-font-lock-exclude 'ebdb-mode t)))
2257
2258(use-package ebdb-com
2259 :after ebdb)
2260
2261;; (use-package ebdb-complete
2262;; :after ebdb
2263;; :config
2264;; (ebdb-complete-enable))
2265
2266(use-package company-ebdb
2267 :after (:all company message)
2268 :config
2269 (defun company-ebdb--post-complete (_) nil)
2270 :hook
2271 (message-mode . (lambda ()
2272 (add-to-list (make-local-variable 'company-backends)
2273 'company-ebdb))))
2274
2275(use-package ebdb-gnus
6ce4ebba 2276 :demand
490554d3
AB
2277 :after ebdb
2278 :custom
2279 (ebdb-gnus-window-configuration
2280 '(article
2281 (vertical 1.0
2282 (summary 0.25 point)
2283 (horizontal 1.0
2284 (article 1.0)
2285 (ebdb-gnus 0.3))))))
2286
2287(use-package ebdb-mua
6ce4ebba 2288 :demand
490554d3
AB
2289 :after ebdb
2290 ;; :custom (ebdb-mua-pop-up nil)
2291 )
2292
2293;; (use-package ebdb-message
2294;; :after ebdb)
2295
2296
2297;; (use-package ebdb-vcard
2298;; :after ebdb)
2299#+end_src
2300
9cebbd53 2301** COMMENT message-x
5fece105
AB
2302
2303#+begin_src emacs-lisp
2304(use-package message-x
5fece105
AB
2305 :custom
2306 (message-x-completion-alist
2307 (quote
2308 (("\\([rR]esent-\\|[rR]eply-\\)?[tT]o:\\|[bB]?[cC][cC]:" . gnus-harvest-find-address)
2309 ((if
2310 (boundp
2311 (quote message-newgroups-header-regexp))
2312 message-newgroups-header-regexp message-newsgroups-header-regexp)
2313 . message-expand-group)))))
2314#+end_src
2315
9cebbd53 2316** COMMENT gnus-harvest
5fece105
AB
2317
2318#+begin_src emacs-lisp
2319(use-package gnus-harvest
5fece105
AB
2320 :commands gnus-harvest-install
2321 :demand t
2322 :config
2323 (if (featurep 'message-x)
2324 (gnus-harvest-install 'message-x)
2325 (gnus-harvest-install)))
2326#+end_src
2327
2328* Blogging
673d5faa
AB
2329:PROPERTIES:
2330:CUSTOM_ID: blogging
2331:END:
5fece105 2332
5fece105
AB
2333** [[https://ox-hugo.scripter.co][ox-hugo]]
2334
2335#+begin_src emacs-lisp
2336(use-package ox-hugo
2337 :after ox)
2338
2339(use-package ox-hugo-auto-export
2340 :load-path "lib/ox-hugo")
2341#+end_src
2342
2343* Post initialization
2344:PROPERTIES:
2345:CUSTOM_ID: post-initialization
2346:END:
2347
5fece105
AB
2348Display how long it took to load the init file.
2349
2350#+begin_src emacs-lisp
2351(message "Loading %s...done (%.3fs)" user-init-file
2352 (float-time (time-subtract (current-time)
c5d8bb25 2353 a/before-user-init-time)))
5fece105
AB
2354#+end_src
2355
2356* Footer
2357:PROPERTIES:
2358:CUSTOM_ID: footer
2359:END:
2360
2361#+begin_src emacs-lisp :comments none
2362;;; init.el ends here
2363#+end_src
2364
2365* COMMENT Local Variables :ARCHIVE:
2366# Local Variables:
c5d8bb25 2367# eval: (add-hook 'after-save-hook #'a/async-babel-tangle 'append 'local)
6ce4ebba 2368# eval: (when (featurep 'typo (typo-mode -1)))
5fece105 2369# End: