Remove ivy, related packages, and my configs for it
[~bandali/configs] / .emacs.d / init.el
CommitLineData
33b1a7ea 1;;; init.el --- bandali's emacs configuration -*- lexical-binding: t -*-
41d290a2 2
4c05c418 3;; Copyright (C) 2018-2020 Amin Bandali <bandali@gnu.org>
41d290a2
AB
4
5;; This program is free software: you can redistribute it and/or modify
6;; it under the terms of the GNU General Public License as published by
7;; the Free Software Foundation, either version 3 of the License, or
8;; (at your option) any later version.
9
10;; This program is distributed in the hope that it will be useful,
11;; but WITHOUT ANY WARRANTY; without even the implied warranty of
12;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13;; GNU General Public License for more details.
14
15;; You should have received a copy of the GNU General Public License
16;; along with this program. If not, see <https://www.gnu.org/licenses/>.
17
18;;; Commentary:
19
33b1a7ea 20;; GNU Emacs configuration of Amin Bandali, computer scientist,
92ad9675 21;; Free Software activist, and GNU maintainer & webmaster. Packages
f7910e3d 22;; are installed through using Borg for a fully reproducible setup.
b57457b2
AB
23
24;; Over the years, I've taken inspiration from configurations of many
25;; great people. Some that I can remember off the top of my head are:
26;;
27;; - https://github.com/dieggsy/dotfiles
28;; - https://github.com/dakra/dmacs
29;; - http://pages.sachachua.com/.emacs.d/Sacha.html
30;; - https://github.com/dakrone/eos
31;; - http://doc.rix.si/cce/cce.html
32;; - https://github.com/jwiegley/dot-emacs
33;; - https://github.com/wasamasa/dotemacs
34;; - https://github.com/hlissner/doom-emacs
41d290a2 35
49e9503b
AB
36;;; Code:
37
b57457b2
AB
38;;; Emacs initialization
39
dca50cf5 40(defvar b/before-user-init-time (current-time)
41d290a2 41 "Value of `current-time' when Emacs begins loading `user-init-file'.")
83364e5b
AB
42(defvar b/emacs-initialized nil
43 "Whether Emacs has been initialized.")
44
45(when (not (bound-and-true-p b/emacs-initialized))
46 (message "Loading Emacs...done (%.3fs)"
47 (float-time (time-subtract b/before-user-init-time
48 before-init-time))))
41d290a2 49
b57457b2
AB
50;; temporarily increase `gc-cons-threshhold' and `gc-cons-percentage'
51;; during startup to reduce garbage collection frequency. clearing
52;; `file-name-handler-alist' seems to help reduce startup time too.
dca50cf5
AB
53(defvar b/gc-cons-threshold gc-cons-threshold)
54(defvar b/gc-cons-percentage gc-cons-percentage)
55(defvar b/file-name-handler-alist file-name-handler-alist)
bc58e70a 56(setq gc-cons-threshold (* 30 1024 1024) ; 30 MiB
41d290a2
AB
57 gc-cons-percentage 0.6
58 file-name-handler-alist nil
59 ;; sidesteps a bug when profiling with esup
60 esup-child-profile-require-level 0)
61
b57457b2 62;; set them back to their defaults once we're done initializing
dca50cf5 63(defun b/post-init ()
83364e5b
AB
64 "My post-initialize function, run after loading `user-init-file'."
65 (setq b/emacs-initialized t
66 gc-cons-threshold b/gc-cons-threshold
67 gc-cons-percentage b/gc-cons-percentage
e8a3b8f7 68 file-name-handler-alist b/file-name-handler-alist)
c84be134 69 (when (featurep 'exwm-workspace)
8b1a2f32
AB
70 (with-eval-after-load 'exwm-workspace
71 (setq-default
72 mode-line-format
73 (append
74 mode-line-format
75 '((:eval
76 (format
77 "[%s]" (number-to-string
8c4704d0
AB
78 exwm-workspace-current-index))))))))
79
80 ;; make some mode-line spaces smaller
927b50b7 81 (setq-default
8c4704d0
AB
82 mode-line-format
83 (mapcar
84 (lambda (x)
85 (if (and (stringp x) (or (string= x " ") (string= x " ")))
86 " "
87 x))
88 mode-line-format)
89 mode-line-buffer-identification
90 (propertized-buffer-identification "%10b")))
dca50cf5 91(add-hook 'after-init-hook #'b/post-init)
41d290a2 92
b57457b2 93;; increase number of lines kept in *Messages* log
41d290a2
AB
94(setq message-log-max 20000)
95
b57457b2
AB
96;; optionally, uncomment to supress some byte-compiler warnings
97;; (see C-h v byte-compile-warnings RET for more info)
41d290a2
AB
98;; (setq byte-compile-warnings
99;; '(not free-vars unresolved noruntime lexical make-local))
100
b57457b2
AB
101\f
102;;; whoami
103
41d290a2 104(setq user-full-name "Amin Bandali"
33b1a7ea 105 user-mail-address "bandali@gnu.org")
41d290a2 106
b57457b2 107\f
927b50b7
AB
108;;; csetq (`custom' setq)
109
110(require 'cl-lib)
111
112(defmacro csetq (&rest args)
113 "Set the value of user option VAR to VALUE.
114
115More generally, you can use multiple variables and values, as in
116 (csetq VAR VALUE VAR VALUE...)
117This sets each user option VAR's value to the corresponding VALUE.
118
119\(fn [VAR VALUE]...)"
120 (declare (debug setq))
121 `(progn
122 ,@(cl-loop for (var value) on args by 'cddr
123 collect
124 `(funcall (or (get ',var 'custom-set) #'set-default)
125 ',var ,value))))
126
127\f
33273849
AB
128;;; Package management
129
8c4704d0
AB
130;; variables of interest:
131;; package-archive-priorities
132;; package-load-list
133;; package-pinned-packages
134
135;; (let* ((b (find-file-noselect "refinery-theme.el"))
136;; (d (with-current-buffer b (package-buffer-info))))
137;; (package-generate-description-file d "refinery-theme-pkg.el"))
138(run-with-idle-timer 0.01 nil #'require 'package)
139(with-eval-after-load 'package
140 (when (= (length package-archives) 1)
141 (csetq
142 package-archives
143 `(,@package-archives
514148d8
AB
144 ;; ("bndl" . "https://p.bndl.org/elpa/")
145 ("org" . "https://orgmode.org/elpa/"))
146 package-load-list
147 '(;; GNU ELPA
514148d8
AB
148 (debbugs "0.26")
149 (delight "1.7")
150 (ebdb "0.6.19")
927b50b7 151 (orgalist "1.13")
514148d8
AB
152 (rt-liberation "1.31")
153 (yasnippet "0.14.0")
655d9048 154 (expand-region "0.11.0")
514148d8 155 ;; bndl
1f5c92ff 156 ;; (refinery-theme "0.1.1")
514148d8 157 ;; Org ELPA
1f5c92ff 158 (org-plus-contrib "20201012"))))
8c4704d0
AB
159 (package-initialize))
160
161(csetq package-archive-upload-base "/ssh:caffeine:~/www/p/elpa")
41d290a2 162
b57457b2
AB
163\f
164;;; Initial setup
165
166;; keep ~/.emacs.d clean
0596e3cf
AB
167(defvar b/etc-dir
168 (expand-file-name
169 (convert-standard-filename "etc/") user-emacs-directory)
170 "The directory where packages place their configuration files.")
171(defvar b/var-dir
172 (expand-file-name
173 (convert-standard-filename "var/") user-emacs-directory)
174 "The directory where packages place their persistent data files.")
8c4704d0
AB
175(defvar b/lisp-dir
176 (expand-file-name
177 (convert-standard-filename "lisp/") user-emacs-directory)
178 "The directory where packages place their persistent data files.")
0596e3cf
AB
179(defun b/etc (file)
180 "Expand filename FILE relative to `b/etc-dir'."
181 (expand-file-name (convert-standard-filename file) b/etc-dir))
182(defun b/var (file)
183 "Expand filename FILE relative to `b/var-dir'."
184 (expand-file-name (convert-standard-filename file) b/var-dir))
8c4704d0
AB
185(defun b/lisp (file)
186 "Expand filename FILE relative to `b/lisp-dir'."
187 (expand-file-name (convert-standard-filename file) b/lisp-dir))
0596e3cf
AB
188
189(csetq
190 auto-save-list-file-prefix (b/var "auto-save/sessions/")
191 nsm-settings-file (b/var "nsm-settings.el"))
c84be134 192
b57457b2 193;; separate custom file (don't want it mixing with init.el)
c84be134 194(with-eval-after-load 'custom
dca50cf5 195 (setq custom-file (b/etc "custom.el"))
41d290a2
AB
196 (when (file-exists-p custom-file)
197 (load custom-file))
b57457b2 198 ;; while at it, treat themes as safe
8c4704d0 199 ;; (setf custom-safe-themes t)
60ff805e 200 ;; only one custom theme at a time
927b50b7
AB
201 ;; (defadvice load-theme (before clear-previous-themes activate)
202 ;; "Clear existing theme settings instead of layering them"
203 ;; (mapc #'disable-theme custom-enabled-themes))
204 )
41d290a2 205
b57457b2 206;; load the secrets file if it exists, otherwise show a warning
927b50b7
AB
207;; (with-demoted-errors
208;; (load (b/etc "secrets")))
41d290a2 209
b57457b2
AB
210;; start up emacs server. see
211;; https://www.gnu.org/software/emacs/manual/html_node/emacs/Emacs-Server.html#Emacs-Server
c84be134
AB
212(run-with-idle-timer 0.5 nil #'require 'server)
213(with-eval-after-load 'server
2087ae39 214 (declare-function server-edit "server")
0596e3cf 215 (global-set-key (kbd "C-c F D") #'server-edit)
2087ae39
AB
216 (declare-function server-running-p "server")
217 (or (server-running-p) (server-mode)))
41d290a2 218
60ff805e 219\f
60ff805e
AB
220;;; Defaults
221
222;;;; C-level customizations
223
c84be134 224(csetq
60ff805e
AB
225 ;; minibuffer
226 enable-recursive-minibuffers t
227 resize-mini-windows t
228 ;; more useful frame titles
7c558c9b
AB
229 ;; frame-title-format '("" invocation-name " - "
230 ;; (:eval
231 ;; (if (buffer-file-name)
232 ;; (abbreviate-file-name (buffer-file-name))
233 ;; "%b")))
60ff805e
AB
234 ;; i don't feel like jumping out of my chair every now and again; so
235 ;; don't BEEP! at me, emacs
236 ring-bell-function 'ignore
237 ;; better scrolling
238 ;; scroll-margin 1
239 ;; scroll-conservatively 10000
240 scroll-step 1
bdd3a0bb 241 scroll-conservatively 101
60ff805e
AB
242 scroll-preserve-screen-position 1
243 ;; focus follows mouse
39cc9c96 244 mouse-autoselect-window t)
60ff805e
AB
245
246(setq-default
247 ;; always use space for indentation
248 indent-tabs-mode nil
249 tab-width 4
7682baf8
AB
250 ;; case-sensitive search (and `dabbrev-expand')
251 ;; case-fold-search nil
60ff805e 252 ;; cursor shape
567440fa 253 cursor-type t)
60ff805e 254
7c558c9b
AB
255(set-fontset-font t 'arabic "Vazir")
256
b57457b2 257;; unicode support
927b50b7
AB
258;; (dolist (ft (fontset-list))
259;; (set-fontset-font
260;; ft
261;; 'unicode
262;; (font-spec :name "Source Code Pro" :size 14))
263;; (set-fontset-font
264;; ft
265;; 'unicode
266;; (font-spec :name "DejaVu Sans Mono")
267;; nil
268;; 'append)
269;; ;; (set-fontset-font
270;; ;; ft
271;; ;; 'unicode
272;; ;; (font-spec
273;; ;; :name "Symbola monospacified for DejaVu Sans Mono")
274;; ;; nil
275;; ;; 'append)
276;; ;; (set-fontset-font
277;; ;; ft
278;; ;; #x2115 ; ℕ
279;; ;; (font-spec :name "DejaVu Sans Mono")
280;; ;; nil
281;; ;; 'append)
282;; (set-fontset-font
283;; ft
284;; (cons ?Α ?ω)
285;; (font-spec :name "DejaVu Sans Mono" :size 14)
286;; nil
287;; 'prepend))
b57457b2 288
60ff805e 289;;;; Elisp-level customizations
41d290a2 290
c84be134
AB
291;; startup
292;; don't need to see the startup echo area message
293(advice-add #'display-startup-echo-area-message :override #'ignore)
294(csetq
295 ;; i want *scratch* as my startup buffer
296 initial-buffer-choice t
297 ;; i don't need the default hint
298 initial-scratch-message nil
299 ;; use customizable text-mode as major mode for *scratch*
300 ;; (initial-major-mode 'text-mode)
301 ;; inhibit buffer list when more than 2 files are loaded
302 inhibit-startup-buffer-menu t
303 ;; don't need to see the startup screen or echo area message
304 inhibit-startup-screen t
305 inhibit-startup-echo-area-message user-login-name)
306
307;; files
308(csetq
309 ;; backups (C-h v make-backup-files RET)
310 backup-by-copying t
0596e3cf 311 backup-directory-alist (list (cons "." (b/var "backup/")))
c84be134
AB
312 version-control t
313 delete-old-versions t
314 ;; auto-save
315 auto-save-file-name-transforms `((".*" ,(b/var "auto-save/") t))
316 ;; insert newline at the end of files
317 require-final-newline t
318 ;; open read-only file buffers in view-mode
319 ;; (enables niceties like `q' for quit)
320 view-read-only t)
321
322;; novice
60ff805e 323;; disable disabled commands
c84be134 324(csetq disabled-command-function nil)
41d290a2 325
60ff805e
AB
326;; lazy-person-friendly yes/no prompts
327(defalias 'yes-or-no-p #'y-or-n-p)
b57457b2 328
8c4704d0
AB
329;; autorevert: enable automatic reloading of changed buffers and files
330(csetq auto-revert-verbose nil
331 global-auto-revert-non-file-buffers nil)
332(require 'autorevert)
333(global-auto-revert-mode 1)
b57457b2
AB
334
335;; time and battery in mode-line
c84be134
AB
336(csetq
337 display-time-default-load-average nil
338 display-time-format " %a %b %-e %-l:%M%P"
339 display-time-mail-icon '(image :type xpm
340 :file "gnus/gnus-pointer.xpm"
341 :ascent center)
342 display-time-use-mail-icon t)
343(require 'time)
344(display-time-mode)
345
8c4704d0 346(csetq battery-mode-line-format " %p%% %t")
c84be134
AB
347(require 'battery)
348(display-battery-mode)
349
350(require 'fringe)
351;; smaller fringe
352;; (fringe-mode '(3 . 1))
353(fringe-mode nil)
354
355(require 'winner)
356;; enable winner-mode (C-h f winner-mode RET)
357(winner-mode 1)
358
359(with-eval-after-load 'compile
60ff805e
AB
360 ;; don't display *compilation* buffer on success. based on
361 ;; https://stackoverflow.com/a/17788551, with changes to use `cl-letf'
362 ;; instead of the now obsolete `flet'.
dca50cf5 363 (defun b/compilation-finish-function (buffer outstr)
41d290a2
AB
364 (unless (string-match "finished" outstr)
365 (switch-to-buffer-other-window buffer))
366 t)
367
dca50cf5 368 (setq compilation-finish-functions #'b/compilation-finish-function)
41d290a2
AB
369
370 (require 'cl-macs)
371
372 (defadvice compilation-start
373 (around inhibit-display
374 (command &optional mode name-function highlight-regexp))
375 (if (not (string-match "^\\(find\\|grep\\)" command))
376 (cl-letf (((symbol-function 'display-buffer) #'ignore))
377 (save-window-excursion ad-do-it))
378 ad-do-it))
379 (ad-activate 'compilation-start))
380
c84be134
AB
381;; isearch
382(csetq
383 ;; allow scrolling in Isearch
384 isearch-allow-scroll t
385 ;; search for non-ASCII characters: i’d like non-ASCII characters such
386 ;; as ‘’“”«»‹›áⓐ𝒶 to be selected when i search for their ASCII
387 ;; counterpart. shoutout to
388 ;; http://endlessparentheses.com/new-in-emacs-25-1-easily-search-non-ascii-characters.html
389 search-default-mode #'char-fold-to-regexp)
390
391;; replace
60ff805e 392;; uncomment to extend the above behaviour to query-replace
c84be134
AB
393;; (csetq replace-char-fold t)
394
395;; vc
396(global-set-key (kbd "C-x v C-=") #'vc-ediff)
397
398(with-eval-after-load 'vc-git
514148d8
AB
399 (csetq vc-git-print-log-follow t
400 vc-git-show-stash 0))
c84be134
AB
401
402(csetq ediff-window-setup-function 'ediff-setup-windows-plain
403 ediff-split-window-function 'split-window-horizontally)
404(with-eval-after-load 'ediff
405 (add-hook 'ediff-after-quit-hook-internal #'winner-undo))
406
407;; face-remap
408(csetq
409 ;; gentler font resizing
410 text-scale-mode-step 1.05)
411
412(run-with-idle-timer 0.4 nil #'require 'mwheel)
413(csetq mouse-wheel-scroll-amount '(1 ((shift) . 1)) ; one line at a time
414 mouse-wheel-progressive-speed nil ; don't accelerate scrolling
415 mouse-wheel-follow-mouse t) ; scroll window under mouse
416
417(run-with-idle-timer 0.4 nil #'require 'pixel-scroll)
418(with-eval-after-load 'pixel-scroll
419 (pixel-scroll-mode 1))
420
421;; epg-config
422(csetq
423 epg-gpg-program (executable-find "gpg")
424 ;; ask for GPG passphrase in minibuffer
425 ;; this will fail if gpg>=2.1 is not available
426 epg-pinentry-mode 'loopback)
427
428;; (require 'pinentry)
429;; workaround for systemd-based distros:
430;; (setq pinentry--socket-dir server-socket-dir)
431;; (pinentry-start)
432
433;; auth-source
434(csetq
435 auth-sources '("~/.authinfo.gpg")
436 authinfo-hidden (regexp-opt '("password" "client-secret" "token")))
b98dbb3d 437
b57457b2 438\f
927b50b7
AB
439;;; Useful utilities
440
441(defun b/add-elisp-section ()
442 (interactive)
443 (insert "\n")
444 (forward-line -1)
445 (insert "\n\f\n;;; "))
446
447(defun b/insert-asterism ()
448 "Insert a centred asterism."
449 (interactive)
450 (let ((asterism "* * *"))
451 (insert
452 (concat
453 "\n"
454 (make-string
455 (floor (/ (- fill-column (length asterism)) 2))
456 ?\s)
457 asterism
458 "\n"))))
459
460(defun b/start-process (program &rest args)
461 "Same as `start-process', but doesn't bother about name and buffer."
462 (let ((process-name (concat program "_process"))
463 (buffer-name (generate-new-buffer-name
464 (concat program "_output"))))
465 (apply #'start-process
466 process-name buffer-name program args)))
467
468(defun b/no-mouse-autoselect-window ()
469 "Conveniently disable `focus-follows-mouse'.
470For disabling the behaviour for certain buffers and/or modes."
471 (make-local-variable 'mouse-autoselect-window)
472 (setq mouse-autoselect-window nil))
473
474(defun b/kill-current-buffer ()
475 "Kill the current buffer."
476 ;; also see https://redd.it/64xb3q
477 (interactive)
478 (kill-buffer (current-buffer)))
479
480(defun b/move-indentation-or-beginning-of-line (arg)
481 "Move to the indentation or to the beginning of line."
482 (interactive "^p")
483 ;; (if (bolp)
484 ;; (back-to-indentation)
485 ;; (move-beginning-of-line arg))
486 (if (= (point)
487 (progn (back-to-indentation)
488 (point)))
489 (move-beginning-of-line arg)))
490
491(defun b/join-line-top ()
492 "Like `join-line', but join next line to the current line."
493 (interactive)
494 (join-line 1))
495
496(defun b/duplicate-line-or-region (&optional n)
497 "Duplicate the current line, or region (if active).
498Make N (default: 1) copies of the current line or region."
499 (interactive "*p")
500 (let ((u-r-p (use-region-p)) ; if region is active
501 (n1 (or n 1)))
502 (save-excursion
503 (let ((text
504 (if u-r-p
505 (buffer-substring (region-beginning) (region-end))
506 (prog1 (thing-at-point 'line)
507 (end-of-line)
508 (if (eobp)
509 (newline)
510 (forward-line 1))))))
511 (dotimes (_ (abs n1))
512 (insert text))))))
513
514\f
c84be134 515;;; General key bindings
b57457b2 516
c84be134
AB
517(global-set-key (kbd "C-a") #'b/move-indentation-or-beginning-of-line)
518(global-set-key (kbd "C-c a i") #'ielm)
519(global-set-key (kbd "C-c d") #'b/duplicate-line-or-region)
520(global-set-key (kbd "C-S-j") #'b/join-line-top)
521(global-set-key (kbd "C-c x") #'execute-extended-command)
41d290a2 522
c84be134
AB
523;; evaling and macro-expanding
524(global-set-key (kbd "C-c e b") #'eval-buffer)
525(global-set-key (kbd "C-c e e") #'eval-last-sexp)
526(global-set-key (kbd "C-c e p") #'pp-macroexpand-last-sexp)
527(global-set-key (kbd "C-c e r") #'eval-region)
41d290a2 528
c84be134
AB
529;; emacs things
530(global-set-key (kbd "C-c e i") #'emacs-init-time)
531(global-set-key (kbd "C-c e u") #'emacs-uptime)
532(global-set-key (kbd "C-c e v") #'emacs-version)
41d290a2 533
c84be134
AB
534;; finding
535(global-set-key (kbd "C-c f .") #'find-file)
536(global-set-key (kbd "C-c f d") #'find-name-dired)
537(global-set-key (kbd "C-c f l") #'find-library)
567440fa 538
c84be134
AB
539;; frames
540(global-set-key (kbd "C-c F m") #'make-frame-command)
541(global-set-key (kbd "C-c F d") #'delete-frame)
41d290a2 542
c84be134
AB
543;; help/describe
544(global-set-key (kbd "C-S-h C") #'describe-char)
545(global-set-key (kbd "C-S-h F") #'describe-face)
41d290a2 546
c84be134
AB
547;; (global-set-key (kbd "C-x k") #'b/kill-current-buffer)
548;; (global-set-key (kbd "C-x K") #'kill-buffer)
549;; (global-set-key (kbd "C-x s") #'save-buffer)
550;; (global-set-key (kbd "C-x S") #'save-some-buffers)
e5c2d147 551
c84be134 552(define-key emacs-lisp-mode-map (kbd "<C-return>") #'b/add-elisp-section)
41d290a2
AB
553
554(when (display-graphic-p)
c84be134 555 (global-unset-key (kbd "C-z")))
500004f4 556
b57457b2
AB
557\f
558;;; Essential packages
559
927b50b7
AB
560(add-to-list
561 'load-path
562 (expand-file-name
563 (convert-standard-filename "lisp") user-emacs-directory))
564
1f5c92ff 565(require 'bandali-exwm)
33273849 566
f7910e3d 567(require 'bandali-org)
41d290a2 568
9c48decc
AB
569(require 'bandali-theme)
570
291690c4 571;; (require 'bandali-magit)
7c558c9b 572
b57457b2 573;; recently opened files
8c4704d0
AB
574(csetq recentf-max-saved-items 2000
575 recentf-save-file (b/var "recentf-save.el"))
c84be134
AB
576(run-with-idle-timer 0.2 nil #'require 'recentf)
577(with-eval-after-load 'recentf
8c4704d0 578 ;; (add-to-list 'recentf-keep #'file-remote-p)
c84be134 579 (recentf-mode))
41d290a2 580
b85d4b36 581(fido-mode 1)
41d290a2 582
679463c6 583(require 'bandali-eshell)
41d290a2 584
679463c6 585(require 'bandali-ibuffer)
41d290a2 586
c84be134
AB
587;; outline
588;; (with-eval-after-load 'outline
589;; (when (featurep 'which-key)
590;; (which-key-add-key-based-replacements
591;; "C-c @" "outline"
592;; "s-O" "outline"))
593;; (define-key outline-minor-mode-map (kbd "<s-tab>")
594;; #'outline-toggle-children)
595;; (define-key outline-minor-mode-map (kbd "M-p")
596;; #'outline-previous-visible-heading)
597;; (define-key outline-minor-mode-map (kbd "M-n")
598;; #'outline-next-visible-heading)
599;; (defvar b/outline-prefix-map)
600;; (define-prefix-command 'b/outline-prefix-map)
601;; (define-key outline-minor-mode-map (kbd "s-O")
602;; 'b/outline-prefix-map)
603;; (define-key b/outline-prefix-map (kbd "TAB")
604;; #'outline-toggle-children)
605;; (define-key b/outline-prefix-map (kbd "a")
606;; #'outline-hide-body)
607;; (define-key b/outline-prefix-map (kbd "H")
608;; #'outline-hide-body)
609;; (define-key b/outline-prefix-map (kbd "S")
610;; #'outline-show-all)
611;; (define-key b/outline-prefix-map (kbd "h")
612;; #'outline-hide-subtree)
613;; (define-key b/outline-prefix-map (kbd "s")
614;; #'outline-show-subtree))
615;; (add-hook 'prog-mode-hook #'outline-minor-mode)
41d290a2 616
679463c6 617(require 'bandali-dired)
41d290a2 618
c84be134 619(with-eval-after-load 'help
41d290a2 620 (temp-buffer-resize-mode)
8c4704d0 621 (csetq help-window-select t))
41d290a2 622
8c4704d0 623(with-eval-after-load 'help-mode
c84be134
AB
624 ;; local key bindings
625 (define-key help-mode-map (kbd "p") #'backward-button)
626 (define-key help-mode-map (kbd "n") #'forward-button))
627
628(with-eval-after-load 'tramp
0596e3cf
AB
629 (csetq tramp-auto-save-directory (b/var "tramp/auto-save/")
630 tramp-persistency-file-name (b/var "tramp/persistency.el"))
41d290a2
AB
631 (add-to-list 'tramp-default-proxies-alist '(nil "\\`root\\'" "/ssh:%h:"))
632 (add-to-list 'tramp-default-proxies-alist '("localhost" nil nil))
633 (add-to-list 'tramp-default-proxies-alist
634 (list (regexp-quote (system-name)) nil nil)))
635
c84be134
AB
636(with-eval-after-load 'doc-view
637 (define-key doc-view-mode-map (kbd "M-RET") #'image-previous-line))
41d290a2 638
c84be134 639(csetq shr-max-width 80)
7c558c9b 640
e2178fd3 641;; Email (with Gnus, message, and EBDB)
2087ae39 642(require 'bandali-gnus)
c84be134
AB
643(with-eval-after-load 'sendmail
644 (csetq sendmail-program (executable-find "msmtp")
645 ;; message-sendmail-extra-arguments '("-v" "-d")
646 mail-specify-envelope-from t
647 mail-envelope-from 'header))
2087ae39 648(require 'bandali-message)
e2178fd3 649(require 'bandali-ebdb)
2087ae39 650
8c4704d0 651;; IRC (with ERC)
39c1c073
AB
652(require 'bandali-erc)
653
927b50b7 654;; 'paste' service (aka scp + web server)
8c4704d0 655(add-to-list 'load-path (b/lisp "scpaste"))
c84be134
AB
656(with-eval-after-load 'scpaste
657 (csetq scpaste-http-destination "https://p.bndl.org"
658 scpaste-scp-destination "p:~"))
8c4704d0
AB
659(autoload 'scpaste "scpaste" nil t)
660(autoload 'scpaste-region "scpaste" nil t)
0596e3cf
AB
661(global-set-key (kbd "C-c a p p") #'scpaste)
662(global-set-key (kbd "C-c a p r") #'scpaste-region)
2331b5a0 663
b57457b2
AB
664\f
665;;; Editing
5750405c 666
b57457b2 667;; display Lisp objects at point in the echo area
c84be134
AB
668(when (version< "25" emacs-version)
669 (with-eval-after-load 'eldoc
8c4704d0
AB
670 (csetq eldoc-minor-mode-string " eldoc")
671 (global-eldoc-mode)))
41d290a2 672
b57457b2 673;; highlight matching parens
c84be134
AB
674(require 'paren)
675(show-paren-mode)
676
677;; (require 'elec-pair)
678;; (electric-pair-mode)
679
680(csetq
681 ;; Save what I copy into clipboard from other applications into Emacs'
682 ;; kill-ring, which would allow me to still be able to easily access
683 ;; it in case I kill (cut or copy) something else inside Emacs before
684 ;; yanking (pasting) what I'd originally intended to.
685 save-interprogram-paste-before-kill t)
686(with-eval-after-load 'simple
8c4704d0 687 (column-number-mode 1))
41d290a2 688
b57457b2 689;; save minibuffer history
c84be134 690(require 'savehist)
0596e3cf 691(csetq savehist-file (b/var "savehist.el"))
c84be134
AB
692(savehist-mode)
693(add-to-list 'savehist-additional-variables 'kill-ring)
41d290a2 694
b57457b2 695;; automatically save place in files
c84be134 696(when (version< "25" emacs-version)
0596e3cf 697 (csetq save-place-file (b/var "save-place.el"))
c84be134
AB
698 (save-place-mode))
699
700(defun indicate-buffer-boundaries-left ()
701 (csetq indicate-buffer-boundaries 'left))
702(with-eval-after-load 'prog-mode
703 (global-prettify-symbols-mode))
704(add-hook 'prog-mode-hook #'indicate-buffer-boundaries-left)
705
8c4704d0 706(define-key text-mode-map (kbd "C-<return>") #'b/insert-asterism)
c84be134
AB
707(add-hook 'text-mode-hook #'indicate-buffer-boundaries-left)
708(add-hook 'text-mode-hook #'flyspell-mode)
709
710(add-to-list 'auto-mode-alist '("\\.*rc$" . conf-mode))
711
712(add-to-list 'auto-mode-alist '("\\.bashrc$" . sh-mode))
713
8c4704d0
AB
714(with-eval-after-load 'flyspell
715 (csetq flyspell-mode-line-string " fly"))
716
c84be134
AB
717;; flycheck
718;; (run-with-idle-timer 0.6 nil #'require 'flycheck)
719;; (with-eval-after-load 'flycheck
720;; (csetq
721;; ;; Use the load-path from running Emacs when checking elisp files
722;; flycheck-emacs-lisp-load-path 'inherit
723;; ;; Only flycheck when I actually save the buffer
724;; flycheck-check-syntax-automatically '(mode-enabled save)
725;; flycheck-mode-line-prefix "flyc"))
726;; (define-key flycheck-mode-map (kbd "M-P") #'flycheck-previous-error)
727;; (define-key flycheck-mode-map (kbd "M-N") #'flycheck-next-error)
728;; (add-hook 'prog-mode-hook #'flycheck-mode)
729
730;; ispell
41d290a2 731;; http://endlessparentheses.com/ispell-and-apostrophes.html
c84be134
AB
732;; (run-with-idle-timer 0.6 nil #'require 'ispell)
733;; (with-eval-after-load 'ispell
734;; ;; ’ can be part of a word
735;; (csetq ispell-local-dictionary-alist
736;; `((nil "[[:alpha:]]" "[^[:alpha:]]"
737;; "['\x2019]" nil ("-B") nil utf-8))
738;; ispell-program-name (executable-find "hunspell"))
739;; ;; don't send ’ to the subprocess
740;; (defun endless/replace-apostrophe (args)
741;; (cons (replace-regexp-in-string
742;; "’" "'" (car args))
743;; (cdr args)))
744;; (advice-add #'ispell-send-string :filter-args
745;; #'endless/replace-apostrophe)
746;; ;; convert ' back to ’ from the subprocess
747;; (defun endless/replace-quote (args)
748;; (if (not (derived-mode-p 'org-mode))
749;; args
750;; (cons (replace-regexp-in-string
751;; "'" "’" (car args))
752;; (cdr args))))
753;; (advice-add #'ispell-parse-output :filter-args
754;; #'endless/replace-quote))
755
0596e3cf 756;; abbrev
8c4704d0 757(csetq abbrev-file-name (b/etc "abbrev.el"))
c84be134 758(add-hook 'text-mode-hook #'abbrev-mode)
54209e74 759
b57457b2
AB
760\f
761;;; Programming modes
762
c84be134 763(with-eval-after-load 'lisp-mode
41d290a2
AB
764 (defun indent-spaces-mode ()
765 (setq indent-tabs-mode nil))
766 (add-hook 'lisp-interaction-mode-hook #'indent-spaces-mode))
767
8c4704d0
AB
768;; alloy
769(add-to-list 'load-path (b/lisp "alloy-mode"))
770(autoload 'alloy-mode "alloy-mode" nil t)
c84be134
AB
771(with-eval-after-load 'alloy-mode
772 (csetq alloy-basic-offset 2)
fac1032c
AB
773 ;; (defun b/alloy-simple-indent (start end)
774 ;; (interactive "r")
775 ;; ;; (if (region-active-p)
776 ;; ;; (indent-rigidly start end alloy-basic-offset)
777 ;; ;; (if (bolp)
778 ;; ;; (indent-rigidly (line-beginning-position)
779 ;; ;; (line-end-position)
780 ;; ;; alloy-basic-offset)))
781 ;; (indent-to (+ (current-column) alloy-basic-offset)))
c84be134
AB
782 ;; local key bindings
783 (define-key alloy-mode-map (kbd "RET") #'electric-newline-and-maybe-indent)
784 ;; (define-key alloy-mode-map (kbd "TAB") #'b/alloy-simple-indent)
785 (define-key alloy-mode-map (kbd "TAB") #'indent-for-tab-command))
786(add-to-list 'auto-mode-alist '("\\.\\(als\\|dsh\\)\\'" . alloy-mode))
787(add-hook 'alloy-mode-hook (lambda nil (setq-local indent-tabs-mode nil)))
788
789;; lean
790;; (eval-when-compile (defvar lean-mode-map))
791;; (run-with-idle-timer 0.4 nil #'require 'lean-mode)
792;; (with-eval-after-load 'lean-mode
793;; (require 'lean-input)
794;; (csetq default-input-method "Lean"
795;; lean-input-tweak-all '(lean-input-compose
796;; (lean-input-prepend "/")
797;; (lean-input-nonempty))
798;; lean-input-user-translations '(("/" "/")))
799;; (lean-input-setup)
800;; ;; local key bindings
801;; (define-key lean-mode-map (kbd "S-SPC") #'company-complete))
802
803(with-eval-after-load 'sgml-mode
804 (csetq sgml-basic-offset 0))
805
806(with-eval-after-load 'css-mode
807 (csetq css-indent-offset 2))
808
809;; po-mode
810;; (add-hook 'po-mode-hook (lambda nil (run-with-timer 0.1 nil 'View-exit)))
811
812;; auctex
813;; (csetq font-latex-fontify-sectioning 'color)
814
815(with-eval-after-load 'tex-mode
748bd8ac
AB
816 (cl-delete-if
817 (lambda (p) (string-match "^---?" (car p)))
c84be134
AB
818 tex--prettify-symbols-alist))
819(add-hook 'tex-mode-hook #'auto-fill-mode)
820(add-hook 'tex-mode-hook #'flyspell-mode)
1d01c927 821
b57457b2 822\f
b57457b2 823;;; Emacs enhancements & auxiliary packages
1eb20313 824
c84be134
AB
825(with-eval-after-load 'man
826 (csetq Man-width 80))
827
8c4704d0
AB
828(defun b/*scratch* ()
829 "Switch to `*scratch*' buffer, creating it if it does not exist."
830 (interactive)
831 (switch-to-buffer
832 (or (get-buffer "*scratch*")
833 (with-current-buffer (get-buffer-create "*scratch*")
834 (set-buffer-major-mode (current-buffer))
835 (current-buffer)))))
836(global-set-key (kbd "C-c s") #'b/*scratch*)
41d290a2 837
5b10d879
AB
838;; ,----
839;; | make pretty boxed quotes like this
840;; `----
8c4704d0 841(add-to-list 'load-path (b/lisp "boxquote"))
c84be134
AB
842(run-with-idle-timer 0.6 nil #'require 'boxquote)
843(with-eval-after-load 'boxquote
844 (defvar b/boxquote-prefix-map)
845 (define-prefix-command 'b/boxquote-prefix-map)
846 (global-set-key (kbd "C-c q") 'b/boxquote-prefix-map)
847 (define-key b/boxquote-prefix-map (kbd "b") #'boxquote-buffer)
848 (define-key b/boxquote-prefix-map (kbd "B") #'boxquote-insert-buffer)
849 (define-key b/boxquote-prefix-map (kbd "d") #'boxquote-defun)
850 (define-key b/boxquote-prefix-map (kbd "F") #'boxquote-insert-file)
851 (define-key b/boxquote-prefix-map (kbd "hf") #'boxquote-describe-function)
852 (define-key b/boxquote-prefix-map (kbd "hk") #'boxquote-describe-key)
853 (define-key b/boxquote-prefix-map (kbd "hv") #'boxquote-describe-variable)
854 (define-key b/boxquote-prefix-map (kbd "hw") #'boxquote-where-is)
855 (define-key b/boxquote-prefix-map (kbd "k") #'boxquote-kill)
856 (define-key b/boxquote-prefix-map (kbd "p") #'boxquote-paragraph)
857 (define-key b/boxquote-prefix-map (kbd "q") #'boxquote-boxquote)
858 (define-key b/boxquote-prefix-map (kbd "r") #'boxquote-region)
859 (define-key b/boxquote-prefix-map (kbd "s") #'boxquote-shell-command)
860 (define-key b/boxquote-prefix-map (kbd "t") #'boxquote-text)
861 (define-key b/boxquote-prefix-map (kbd "T") #'boxquote-title)
862 (define-key b/boxquote-prefix-map (kbd "u") #'boxquote-unbox)
863 (define-key b/boxquote-prefix-map (kbd "U") #'boxquote-unbox-region)
864 (define-key b/boxquote-prefix-map (kbd "y") #'boxquote-yank)
865 (define-key b/boxquote-prefix-map (kbd "M-q") #'boxquote-fill-paragraph)
866 (define-key b/boxquote-prefix-map (kbd "M-w") #'boxquote-kill-ring-save))
867
8c4704d0 868(add-to-list 'load-path (b/lisp "hl-todo"))
c84be134
AB
869(run-with-idle-timer 0.5 nil #'require 'hl-todo)
870(with-eval-after-load 'hl-todo
1eb20313 871 ;; highlight TODOs in buffers
41d290a2
AB
872 (global-hl-todo-mode))
873
8c4704d0 874(add-to-list 'load-path (b/lisp "page-break-lines"))
c84be134
AB
875(run-with-idle-timer 0.5 nil #'require 'page-break-lines)
876(with-eval-after-load 'page-break-lines
877 (csetq page-break-lines-max-width fill-column)
41d290a2
AB
878 (global-page-break-lines-mode))
879
c84be134
AB
880;; expand-region
881(global-set-key (kbd "C-=") #'er/expand-region)
882
883(run-with-idle-timer 0.6 nil #'require 'yasnippet)
884(with-eval-after-load 'yasnippet
885 (declare-function yas-reload-all
886 "yasnippet" (&optional no-jit interactive))
887 (declare-function yas-maybe-expand-abbrev-key-filter
888 "yasnippet" (cmd))
889
890 (defconst yas-verbosity-cur yas-verbosity)
891 (setq yas-verbosity 2)
0596e3cf 892 (csetq yas-snippet-dirs `(,(b/etc "yasnippet/snippets")))
5df34463 893 ;; (add-to-list 'yas-snippet-dirs "~/src/git/guix/etc/snippets" t)
c84be134
AB
894 (yas-reload-all)
895 (setq yas-verbosity yas-verbosity-cur)
896
897 (defun b/yas-maybe-expand-abbrev-key-filter (cmd)
898 (when (and (yas-maybe-expand-abbrev-key-filter cmd)
899 (not (bound-and-true-p git-commit-mode)))
900 cmd))
901 (defconst b/yas-maybe-expand
902 '(menu-item "" yas-expand
903 :filter b/yas-maybe-expand-abbrev-key-filter))
904 (define-key yas-minor-mode-map (kbd "SPC") b/yas-maybe-expand)
905
906 (yas-global-mode))
907
908;; debbugs
909(global-set-key (kbd "C-c D d") #'debbugs-gnu)
910(global-set-key (kbd "C-c D b") #'debbugs-gnu-bugs)
911(global-set-key (kbd "C-c D e") ; bug-gnu-emacs
912 (lambda ()
913 (interactive)
914 (setq debbugs-gnu-current-suppress t)
915 (debbugs-gnu debbugs-gnu-default-severities
916 '("emacs"))))
917(global-set-key (kbd "C-c D g") ; bug-gnuzilla
918 (lambda ()
919 (interactive)
920 (setq debbugs-gnu-current-suppress t)
921 (debbugs-gnu debbugs-gnu-default-severities
922 '("gnuzilla"))))
923(global-set-key (kbd "C-c D G b") ; bug-guix
924 (lambda ()
925 (interactive)
926 (setq debbugs-gnu-current-suppress t)
927 (debbugs-gnu debbugs-gnu-default-severities
928 '("guix"))))
929(global-set-key (kbd "C-c D G p") ; guix-patches
930 (lambda ()
931 (interactive)
932 (setq debbugs-gnu-current-suppress t)
933 (debbugs-gnu debbugs-gnu-default-severities
934 '("guix-patches"))))
935
0596e3cf
AB
936;; url and url-cache
937(csetq
938 url-configuration-directory (b/var "url/configuration/")
939 url-cache-directory (b/var "url/cache/"))
940
c84be134
AB
941;; eww
942(csetq eww-download-directory (file-name-as-directory
943 (getenv "XDG_DOWNLOAD_DIR")))
944(global-set-key (kbd "C-c a e w") #'eww)
41d290a2 945
8c4704d0
AB
946;; ;; org-ref
947;; (csetq
948;; reftex-default-bibliography '("~/usr/org/references.bib")
949;; org-ref-default-bibliography '("~/usr/org/references.bib")
950;; org-ref-bibliography-notes "~/usr/org/notes.org"
951;; org-ref-pdf-directory "~/usr/org/bibtex-pdfs/")
c84be134
AB
952
953;; fill-column-indicator ?
954
955;; window
956(csetq split-width-threshold 150)
957(global-set-key (kbd "C-c w s l")
958 (lambda ()
959 (interactive)
960 (split-window-right)
961 (other-window 1)))
962(global-set-key (kbd "C-c w s j")
963 (lambda ()
964 (interactive)
965 (split-window-below)
966 (other-window 1)))
967(global-set-key (kbd "C-c w q") #'quit-window)
968
c84be134 969;; pass
8c4704d0
AB
970;; (global-set-key (kbd "C-c a p") #'pass)
971;; (add-hook 'pass-mode-hook #'View-exit)
c84be134
AB
972
973;; reftex
974;; uncomment to disable reftex-cite's default choice of previous word
975;; (with-eval-after-load 'reftex
976;; (require 'reftex-cite)
977;; (defun reftex-get-bibkey-default ()
978;; "If the cursor is in a citation macro, return the word before the macro."
979;; (let* ((macro (reftex-what-macro 1)))
980;; (save-excursion
981;; (when (and macro (string-match "cite" (car macro)))
982;; (goto-char (cdr macro)))
983;; (reftex-this-word)))))
984(add-hook 'latex-mode-hook #'reftex-mode)
985
986;; dmenu
1f5c92ff
AB
987(add-to-list 'load-path (b/lisp "dmenu"))
988(with-eval-after-load 'dmenu
989 (csetq dmenu-prompt-string "run: "
990 dmenu-save-file (b/var "dmenu-items")))
991(autoload 'dmenu "dmenu" nil t)
c84be134
AB
992
993;; eosd ?
9ed5410e 994
8c4704d0
AB
995;; delight
996(run-with-idle-timer 0.5 nil #'require 'delight)
997(with-eval-after-load 'delight
998 (delight 'auto-fill-function " f" "simple")
999 (delight 'abbrev-mode "" "abbrev")
1000 (delight 'page-break-lines-mode "" "page-break-lines")
8c4704d0
AB
1001 (delight 'mml-mode " mml" "mml")
1002 (delight 'yas-minor-mode "" "yasnippet"))
1003
b57457b2 1004\f
b57457b2
AB
1005;;; Post initialization
1006
41d290a2
AB
1007(message "Loading %s...done (%.3fs)" user-init-file
1008 (float-time (time-subtract (current-time)
dca50cf5 1009 b/before-user-init-time)))
41d290a2
AB
1010
1011;;; init.el ends here