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