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