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