1 ;;; init.el --- bandali's emacs configuration -*- lexical-binding: t -*-
3 ;; Copyright (C) 2018-2020 Amin Bandali <bandali@gnu.org>
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.
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.
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/>.
20 ;; GNU Emacs configuration of Amin Bandali, computer scientist,
21 ;; Free Software activist, and GNU maintainer & webmaster. Packages
22 ;; are installed through using Borg for a fully reproducible setup.
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:
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
38 ;;; Emacs initialization
40 (defvar b
/before-user-init-time
(current-time)
41 "Value of `current-time' when Emacs begins loading `user-init-file'.")
42 (defvar b
/emacs-initialized nil
43 "Whether Emacs has been initialized.")
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
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.
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
)
56 (setq gc-cons-threshold
(* 30 1024 1024) ; 30 MiB
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)
62 ;; set them back to their defaults once we're done initializing
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
68 file-name-handler-alist b
/file-name-handler-alist
)
69 (when (featurep 'exwm-workspace
)
70 (with-eval-after-load 'exwm-workspace
77 "[%s]" (number-to-string
78 exwm-workspace-current-index
))))))))
80 ;; make some mode-line spaces smaller
85 (if (and (stringp x
) (or (string= x
" ") (string= x
" ")))
89 mode-line-buffer-identification
90 (propertized-buffer-identification "%10b")))
91 (add-hook 'after-init-hook
#'b
/post-init
)
93 ;; increase number of lines kept in *Messages* log
94 (setq message-log-max
20000)
96 ;; optionally, uncomment to supress some byte-compiler warnings
97 ;; (see C-h v byte-compile-warnings RET for more info)
98 ;; (setq byte-compile-warnings
99 ;; '(not free-vars unresolved noruntime lexical make-local))
104 (setq user-full-name
"Amin Bandali"
105 user-mail-address
"bandali@gnu.org")
108 ;;; csetq (`custom' setq)
112 (defmacro csetq
(&rest args
)
113 "Set the value of user option VAR to VALUE.
115 More generally, you can use multiple variables and values, as in
116 (csetq VAR VALUE VAR VALUE...)
117 This sets each user option VAR's value to the corresponding VALUE.
119 \(fn [VAR VALUE]...)"
120 (declare (debug setq
))
122 ,@(cl-loop for
(var value
) on args by
'cddr
124 `(funcall (or (get ',var
'custom-set
) #'set-default
)
128 ;;; Package management
130 ;; variables of interest:
131 ;; package-archive-priorities
133 ;; package-pinned-packages
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)
144 ;; ("bndl" . "https://p.bndl.org/elpa/")
145 ("org" .
"https://orgmode.org/elpa/"))
155 (rt-liberation "1.31")
158 (refinery-theme "0.1.1")
160 (org-plus-contrib "20201005"))))
161 (package-initialize))
163 (csetq package-archive-upload-base
"/ssh:caffeine:~/www/p/elpa")
168 ;; keep ~/.emacs.d clean
171 (convert-standard-filename "etc/") user-emacs-directory
)
172 "The directory where packages place their configuration files.")
175 (convert-standard-filename "var/") user-emacs-directory
)
176 "The directory where packages place their persistent data files.")
179 (convert-standard-filename "lisp/") user-emacs-directory
)
180 "The directory where packages place their persistent data files.")
182 "Expand filename FILE relative to `b/etc-dir'."
183 (expand-file-name (convert-standard-filename file
) b
/etc-dir
))
185 "Expand filename FILE relative to `b/var-dir'."
186 (expand-file-name (convert-standard-filename file
) b
/var-dir
))
188 "Expand filename FILE relative to `b/lisp-dir'."
189 (expand-file-name (convert-standard-filename file
) b
/lisp-dir
))
192 auto-save-list-file-prefix
(b/var
"auto-save/sessions/")
193 nsm-settings-file
(b/var
"nsm-settings.el"))
195 ;; separate custom file (don't want it mixing with init.el)
196 (with-eval-after-load 'custom
197 (setq custom-file
(b/etc
"custom.el"))
198 (when (file-exists-p custom-file
)
200 ;; while at it, treat themes as safe
201 ;; (setf custom-safe-themes t)
202 ;; only one custom theme at a time
203 ;; (defadvice load-theme (before clear-previous-themes activate)
204 ;; "Clear existing theme settings instead of layering them"
205 ;; (mapc #'disable-theme custom-enabled-themes))
208 ;; load the secrets file if it exists, otherwise show a warning
209 ;; (with-demoted-errors
210 ;; (load (b/etc "secrets")))
212 ;; start up emacs server. see
213 ;; https://www.gnu.org/software/emacs/manual/html_node/emacs/Emacs-Server.html#Emacs-Server
214 (run-with-idle-timer 0.5 nil
#'require
'server
)
215 (with-eval-after-load 'server
216 (declare-function server-edit
"server")
217 (global-set-key (kbd "C-c F D") #'server-edit
)
218 (declare-function server-running-p
"server")
219 (or (server-running-p) (server-mode)))
224 ;;;; C-level customizations
228 enable-recursive-minibuffers t
229 resize-mini-windows t
230 ;; more useful frame titles
231 ;; frame-title-format '("" invocation-name " - "
233 ;; (if (buffer-file-name)
234 ;; (abbreviate-file-name (buffer-file-name))
236 ;; i don't feel like jumping out of my chair every now and again; so
237 ;; don't BEEP! at me, emacs
238 ring-bell-function
'ignore
241 ;; scroll-conservatively 10000
243 scroll-conservatively
101
244 scroll-preserve-screen-position
1
245 ;; focus follows mouse
246 mouse-autoselect-window t
)
249 ;; always use space for indentation
252 ;; case-sensitive search (and `dabbrev-expand')
253 ;; case-fold-search nil
257 (set-fontset-font t
'arabic
"Vazir")
260 ;; (dolist (ft (fontset-list))
264 ;; (font-spec :name "Source Code Pro" :size 14))
268 ;; (font-spec :name "DejaVu Sans Mono")
271 ;; ;; (set-fontset-font
275 ;; ;; :name "Symbola monospacified for DejaVu Sans Mono")
278 ;; ;; (set-fontset-font
281 ;; ;; (font-spec :name "DejaVu Sans Mono")
287 ;; (font-spec :name "DejaVu Sans Mono" :size 14)
291 ;;;; Elisp-level customizations
294 ;; don't need to see the startup echo area message
295 (advice-add #'display-startup-echo-area-message
:override
#'ignore
)
297 ;; i want *scratch* as my startup buffer
298 initial-buffer-choice t
299 ;; i don't need the default hint
300 initial-scratch-message nil
301 ;; use customizable text-mode as major mode for *scratch*
302 ;; (initial-major-mode 'text-mode)
303 ;; inhibit buffer list when more than 2 files are loaded
304 inhibit-startup-buffer-menu t
305 ;; don't need to see the startup screen or echo area message
306 inhibit-startup-screen t
307 inhibit-startup-echo-area-message user-login-name
)
311 ;; backups (C-h v make-backup-files RET)
313 backup-directory-alist
(list (cons "." (b/var
"backup/")))
315 delete-old-versions t
317 auto-save-file-name-transforms
`((".*" ,(b/var
"auto-save/") t
))
318 ;; insert newline at the end of files
319 require-final-newline t
320 ;; open read-only file buffers in view-mode
321 ;; (enables niceties like `q' for quit)
325 ;; disable disabled commands
326 (csetq disabled-command-function nil
)
328 ;; lazy-person-friendly yes/no prompts
329 (defalias 'yes-or-no-p
#'y-or-n-p
)
331 ;; autorevert: enable automatic reloading of changed buffers and files
332 (csetq auto-revert-verbose nil
333 global-auto-revert-non-file-buffers nil
)
334 (require 'autorevert
)
335 (global-auto-revert-mode 1)
337 ;; time and battery in mode-line
339 display-time-default-load-average nil
340 display-time-format
" %a %b %-e %-l:%M%P"
341 display-time-mail-icon
'(image :type xpm
342 :file
"gnus/gnus-pointer.xpm"
344 display-time-use-mail-icon t
)
348 (csetq battery-mode-line-format
" %p%% %t")
350 (display-battery-mode)
354 ;; (fringe-mode '(3 . 1))
358 ;; enable winner-mode (C-h f winner-mode RET)
361 (with-eval-after-load 'compile
362 ;; don't display *compilation* buffer on success. based on
363 ;; https://stackoverflow.com/a/17788551, with changes to use `cl-letf'
364 ;; instead of the now obsolete `flet'.
365 (defun b/compilation-finish-function
(buffer outstr
)
366 (unless (string-match "finished" outstr
)
367 (switch-to-buffer-other-window buffer
))
370 (setq compilation-finish-functions
#'b
/compilation-finish-function
)
374 (defadvice compilation-start
375 (around inhibit-display
376 (command &optional mode name-function highlight-regexp
))
377 (if (not (string-match "^\\(find\\|grep\\)" command
))
378 (cl-letf (((symbol-function 'display-buffer
) #'ignore
))
379 (save-window-excursion ad-do-it
))
381 (ad-activate 'compilation-start
))
385 ;; allow scrolling in Isearch
386 isearch-allow-scroll t
387 ;; search for non-ASCII characters: i’d like non-ASCII characters such
388 ;; as ‘’“”«»‹›áⓐ𝒶 to be selected when i search for their ASCII
389 ;; counterpart. shoutout to
390 ;; http://endlessparentheses.com/new-in-emacs-25-1-easily-search-non-ascii-characters.html
391 search-default-mode
#'char-fold-to-regexp
)
394 ;; uncomment to extend the above behaviour to query-replace
395 ;; (csetq replace-char-fold t)
398 (global-set-key (kbd "C-x v C-=") #'vc-ediff
)
400 (with-eval-after-load 'vc-git
401 (csetq vc-git-print-log-follow t
402 vc-git-show-stash
0))
404 (csetq ediff-window-setup-function
'ediff-setup-windows-plain
405 ediff-split-window-function
'split-window-horizontally
)
406 (with-eval-after-load 'ediff
407 (add-hook 'ediff-after-quit-hook-internal
#'winner-undo
))
411 ;; gentler font resizing
412 text-scale-mode-step
1.05)
414 (run-with-idle-timer 0.4 nil
#'require
'mwheel
)
415 (csetq mouse-wheel-scroll-amount
'(1 ((shift) .
1)) ; one line at a time
416 mouse-wheel-progressive-speed nil
; don't accelerate scrolling
417 mouse-wheel-follow-mouse t
) ; scroll window under mouse
419 (run-with-idle-timer 0.4 nil
#'require
'pixel-scroll
)
420 (with-eval-after-load 'pixel-scroll
421 (pixel-scroll-mode 1))
425 epg-gpg-program
(executable-find "gpg")
426 ;; ask for GPG passphrase in minibuffer
427 ;; this will fail if gpg>=2.1 is not available
428 epg-pinentry-mode
'loopback
)
430 ;; (require 'pinentry)
431 ;; workaround for systemd-based distros:
432 ;; (setq pinentry--socket-dir server-socket-dir)
437 auth-sources
'("~/.authinfo.gpg")
438 authinfo-hidden
(regexp-opt '("password" "client-secret" "token")))
443 (defun b/add-elisp-section
()
447 (insert "\n\f\n;;; "))
449 (defun b/insert-asterism
()
450 "Insert a centred asterism."
452 (let ((asterism "* * *"))
457 (floor (/ (- fill-column
(length asterism
)) 2))
462 (defun b/start-process
(program &rest args
)
463 "Same as `start-process', but doesn't bother about name and buffer."
464 (let ((process-name (concat program
"_process"))
465 (buffer-name (generate-new-buffer-name
466 (concat program
"_output"))))
467 (apply #'start-process
468 process-name buffer-name program args
)))
470 (defun b/no-mouse-autoselect-window
()
471 "Conveniently disable `focus-follows-mouse'.
472 For disabling the behaviour for certain buffers and/or modes."
473 (make-local-variable 'mouse-autoselect-window
)
474 (setq mouse-autoselect-window nil
))
476 (defun b/kill-current-buffer
()
477 "Kill the current buffer."
478 ;; also see https://redd.it/64xb3q
480 (kill-buffer (current-buffer)))
482 (defun b/move-indentation-or-beginning-of-line
(arg)
483 "Move to the indentation or to the beginning of line."
486 ;; (back-to-indentation)
487 ;; (move-beginning-of-line arg))
489 (progn (back-to-indentation)
491 (move-beginning-of-line arg
)))
493 (defun b/join-line-top
()
494 "Like `join-line', but join next line to the current line."
498 (defun b/duplicate-line-or-region
(&optional n
)
499 "Duplicate the current line, or region (if active).
500 Make N (default: 1) copies of the current line or region."
502 (let ((u-r-p (use-region-p)) ; if region is active
507 (buffer-substring (region-beginning) (region-end))
508 (prog1 (thing-at-point 'line
)
512 (forward-line 1))))))
513 (dotimes (_ (abs n1
))
517 ;;; General key bindings
519 (global-set-key (kbd "C-a") #'b
/move-indentation-or-beginning-of-line
)
520 (global-set-key (kbd "C-c a i") #'ielm
)
521 (global-set-key (kbd "C-c d") #'b
/duplicate-line-or-region
)
522 (global-set-key (kbd "C-S-j") #'b
/join-line-top
)
523 (global-set-key (kbd "C-c x") #'execute-extended-command
)
525 ;; evaling and macro-expanding
526 (global-set-key (kbd "C-c e b") #'eval-buffer
)
527 (global-set-key (kbd "C-c e e") #'eval-last-sexp
)
528 (global-set-key (kbd "C-c e p") #'pp-macroexpand-last-sexp
)
529 (global-set-key (kbd "C-c e r") #'eval-region
)
532 (global-set-key (kbd "C-c e i") #'emacs-init-time
)
533 (global-set-key (kbd "C-c e u") #'emacs-uptime
)
534 (global-set-key (kbd "C-c e v") #'emacs-version
)
537 (global-set-key (kbd "C-c f .") #'find-file
)
538 (global-set-key (kbd "C-c f d") #'find-name-dired
)
539 (global-set-key (kbd "C-c f l") #'find-library
)
542 (global-set-key (kbd "C-c F m") #'make-frame-command
)
543 (global-set-key (kbd "C-c F d") #'delete-frame
)
546 (global-set-key (kbd "C-S-h C") #'describe-char
)
547 (global-set-key (kbd "C-S-h F") #'describe-face
)
549 ;; (global-set-key (kbd "C-x k") #'b/kill-current-buffer)
550 ;; (global-set-key (kbd "C-x K") #'kill-buffer)
551 ;; (global-set-key (kbd "C-x s") #'save-buffer)
552 ;; (global-set-key (kbd "C-x S") #'save-some-buffers)
554 (define-key emacs-lisp-mode-map
(kbd "<C-return>") #'b
/add-elisp-section
)
556 (when (display-graphic-p)
557 (global-unset-key (kbd "C-z")))
560 ;;; Essential packages
565 (convert-standard-filename "lisp") user-emacs-directory
))
567 ;; (require 'bandali-exwm)
569 (require 'bandali-org
)
571 (require 'bandali-theme
)
573 ;; (require 'bandali-magit)
575 ;; recently opened files
576 (csetq recentf-max-saved-items
2000
577 recentf-save-file
(b/var
"recentf-save.el"))
578 (run-with-idle-timer 0.2 nil
#'require
'recentf
)
579 (with-eval-after-load 'recentf
580 ;; (add-to-list 'recentf-keep #'file-remote-p)
583 ;; needed for history for counsel
584 (csetq amx-save-file
(b/var
"amx-save.el"))
585 (add-to-list 'load-path
(b/lisp
"s"))
586 (add-to-list 'load-path
(b/lisp
"amx"))
587 (run-with-idle-timer 0.3 nil
#'require
'amx
)
588 (with-eval-after-load 'amx
591 (require 'bandali-ivy
)
593 (require 'bandali-eshell
)
595 (require 'bandali-ibuffer
)
598 ;; (with-eval-after-load 'outline
599 ;; (when (featurep 'which-key)
600 ;; (which-key-add-key-based-replacements
603 ;; (define-key outline-minor-mode-map (kbd "<s-tab>")
604 ;; #'outline-toggle-children)
605 ;; (define-key outline-minor-mode-map (kbd "M-p")
606 ;; #'outline-previous-visible-heading)
607 ;; (define-key outline-minor-mode-map (kbd "M-n")
608 ;; #'outline-next-visible-heading)
609 ;; (defvar b/outline-prefix-map)
610 ;; (define-prefix-command 'b/outline-prefix-map)
611 ;; (define-key outline-minor-mode-map (kbd "s-O")
612 ;; 'b/outline-prefix-map)
613 ;; (define-key b/outline-prefix-map (kbd "TAB")
614 ;; #'outline-toggle-children)
615 ;; (define-key b/outline-prefix-map (kbd "a")
616 ;; #'outline-hide-body)
617 ;; (define-key b/outline-prefix-map (kbd "H")
618 ;; #'outline-hide-body)
619 ;; (define-key b/outline-prefix-map (kbd "S")
620 ;; #'outline-show-all)
621 ;; (define-key b/outline-prefix-map (kbd "h")
622 ;; #'outline-hide-subtree)
623 ;; (define-key b/outline-prefix-map (kbd "s")
624 ;; #'outline-show-subtree))
625 ;; (add-hook 'prog-mode-hook #'outline-minor-mode)
627 (require 'bandali-dired
)
629 (with-eval-after-load 'help
630 (temp-buffer-resize-mode)
631 (csetq help-window-select t
))
633 (with-eval-after-load 'help-mode
634 ;; local key bindings
635 (define-key help-mode-map
(kbd "p") #'backward-button
)
636 (define-key help-mode-map
(kbd "n") #'forward-button
))
638 (with-eval-after-load 'tramp
639 (csetq tramp-auto-save-directory
(b/var
"tramp/auto-save/")
640 tramp-persistency-file-name
(b/var
"tramp/persistency.el"))
641 (add-to-list 'tramp-default-proxies-alist
'(nil "\\`root\\'" "/ssh:%h:"))
642 (add-to-list 'tramp-default-proxies-alist
'("localhost" nil nil
))
643 (add-to-list 'tramp-default-proxies-alist
644 (list (regexp-quote (system-name)) nil nil
)))
646 (with-eval-after-load 'doc-view
647 (define-key doc-view-mode-map
(kbd "M-RET") #'image-previous-line
))
649 (csetq shr-max-width
80)
651 ;; Email (with Gnus, message, and EBDB)
652 (require 'bandali-gnus
)
653 (with-eval-after-load 'sendmail
654 (csetq sendmail-program
(executable-find "msmtp")
655 ;; message-sendmail-extra-arguments '("-v" "-d")
656 mail-specify-envelope-from t
657 mail-envelope-from
'header
))
658 (require 'bandali-message
)
659 (require 'bandali-ebdb
)
662 (require 'bandali-erc
)
664 ;; 'paste' service (aka scp + web server)
665 (add-to-list 'load-path
(b/lisp
"scpaste"))
666 (with-eval-after-load 'scpaste
667 (csetq scpaste-http-destination
"https://p.bndl.org"
668 scpaste-scp-destination
"p:~"))
669 (autoload 'scpaste
"scpaste" nil t
)
670 (autoload 'scpaste-region
"scpaste" nil t
)
671 (global-set-key (kbd "C-c a p p") #'scpaste
)
672 (global-set-key (kbd "C-c a p r") #'scpaste-region
)
677 ;; display Lisp objects at point in the echo area
678 (when (version< "25" emacs-version
)
679 (with-eval-after-load 'eldoc
680 (csetq eldoc-minor-mode-string
" eldoc")
681 (global-eldoc-mode)))
683 ;; highlight matching parens
687 ;; (require 'elec-pair)
688 ;; (electric-pair-mode)
691 ;; Save what I copy into clipboard from other applications into Emacs'
692 ;; kill-ring, which would allow me to still be able to easily access
693 ;; it in case I kill (cut or copy) something else inside Emacs before
694 ;; yanking (pasting) what I'd originally intended to.
695 save-interprogram-paste-before-kill t
)
696 (with-eval-after-load 'simple
697 (column-number-mode 1))
699 ;; save minibuffer history
701 (csetq savehist-file
(b/var
"savehist.el"))
703 (add-to-list 'savehist-additional-variables
'kill-ring
)
705 ;; automatically save place in files
706 (when (version< "25" emacs-version
)
707 (csetq save-place-file
(b/var
"save-place.el"))
710 (defun indicate-buffer-boundaries-left ()
711 (csetq indicate-buffer-boundaries
'left
))
712 (with-eval-after-load 'prog-mode
713 (global-prettify-symbols-mode))
714 (add-hook 'prog-mode-hook
#'indicate-buffer-boundaries-left
)
716 (define-key text-mode-map
(kbd "C-<return>") #'b
/insert-asterism
)
717 (add-hook 'text-mode-hook
#'indicate-buffer-boundaries-left
)
718 (add-hook 'text-mode-hook
#'flyspell-mode
)
720 (add-to-list 'auto-mode-alist
'("\\.*rc$" . conf-mode
))
722 (add-to-list 'auto-mode-alist
'("\\.bashrc$" . sh-mode
))
724 (with-eval-after-load 'flyspell
725 (csetq flyspell-mode-line-string
" fly"))
728 ;; (run-with-idle-timer 0.6 nil #'require 'flycheck)
729 ;; (with-eval-after-load 'flycheck
731 ;; ;; Use the load-path from running Emacs when checking elisp files
732 ;; flycheck-emacs-lisp-load-path 'inherit
733 ;; ;; Only flycheck when I actually save the buffer
734 ;; flycheck-check-syntax-automatically '(mode-enabled save)
735 ;; flycheck-mode-line-prefix "flyc"))
736 ;; (define-key flycheck-mode-map (kbd "M-P") #'flycheck-previous-error)
737 ;; (define-key flycheck-mode-map (kbd "M-N") #'flycheck-next-error)
738 ;; (add-hook 'prog-mode-hook #'flycheck-mode)
741 ;; http://endlessparentheses.com/ispell-and-apostrophes.html
742 ;; (run-with-idle-timer 0.6 nil #'require 'ispell)
743 ;; (with-eval-after-load 'ispell
744 ;; ;; ’ can be part of a word
745 ;; (csetq ispell-local-dictionary-alist
746 ;; `((nil "[[:alpha:]]" "[^[:alpha:]]"
747 ;; "['\x2019]" nil ("-B") nil utf-8))
748 ;; ispell-program-name (executable-find "hunspell"))
749 ;; ;; don't send ’ to the subprocess
750 ;; (defun endless/replace-apostrophe (args)
751 ;; (cons (replace-regexp-in-string
752 ;; "’" "'" (car args))
754 ;; (advice-add #'ispell-send-string :filter-args
755 ;; #'endless/replace-apostrophe)
756 ;; ;; convert ' back to ’ from the subprocess
757 ;; (defun endless/replace-quote (args)
758 ;; (if (not (derived-mode-p 'org-mode))
760 ;; (cons (replace-regexp-in-string
761 ;; "'" "’" (car args))
763 ;; (advice-add #'ispell-parse-output :filter-args
764 ;; #'endless/replace-quote))
767 (csetq abbrev-file-name
(b/etc
"abbrev.el"))
768 (add-hook 'text-mode-hook
#'abbrev-mode
)
771 ;;; Programming modes
773 (with-eval-after-load 'lisp-mode
774 (defun indent-spaces-mode ()
775 (setq indent-tabs-mode nil
))
776 (add-hook 'lisp-interaction-mode-hook
#'indent-spaces-mode
))
779 (add-to-list 'load-path
(b/lisp
"alloy-mode"))
780 (autoload 'alloy-mode
"alloy-mode" nil t
)
781 (with-eval-after-load 'alloy-mode
782 (csetq alloy-basic-offset
2)
783 ;; (defun b/alloy-simple-indent (start end)
785 ;; ;; (if (region-active-p)
786 ;; ;; (indent-rigidly start end alloy-basic-offset)
788 ;; ;; (indent-rigidly (line-beginning-position)
789 ;; ;; (line-end-position)
790 ;; ;; alloy-basic-offset)))
791 ;; (indent-to (+ (current-column) alloy-basic-offset)))
792 ;; local key bindings
793 (define-key alloy-mode-map
(kbd "RET") #'electric-newline-and-maybe-indent
)
794 ;; (define-key alloy-mode-map (kbd "TAB") #'b/alloy-simple-indent)
795 (define-key alloy-mode-map
(kbd "TAB") #'indent-for-tab-command
))
796 (add-to-list 'auto-mode-alist
'("\\.\\(als\\|dsh\\)\\'" . alloy-mode
))
797 (add-hook 'alloy-mode-hook
(lambda nil
(setq-local indent-tabs-mode nil
)))
800 ;; (eval-when-compile (defvar lean-mode-map))
801 ;; (run-with-idle-timer 0.4 nil #'require 'lean-mode)
802 ;; (with-eval-after-load 'lean-mode
803 ;; (require 'lean-input)
804 ;; (csetq default-input-method "Lean"
805 ;; lean-input-tweak-all '(lean-input-compose
806 ;; (lean-input-prepend "/")
807 ;; (lean-input-nonempty))
808 ;; lean-input-user-translations '(("/" "/")))
809 ;; (lean-input-setup)
810 ;; ;; local key bindings
811 ;; (define-key lean-mode-map (kbd "S-SPC") #'company-complete))
813 (with-eval-after-load 'sgml-mode
814 (csetq sgml-basic-offset
0))
816 (with-eval-after-load 'css-mode
817 (csetq css-indent-offset
2))
820 ;; (add-hook 'po-mode-hook (lambda nil (run-with-timer 0.1 nil 'View-exit)))
823 ;; (csetq font-latex-fontify-sectioning 'color)
825 (with-eval-after-load 'tex-mode
827 (lambda (p) (string-match "^---?" (car p
)))
828 tex--prettify-symbols-alist
))
829 (add-hook 'tex-mode-hook
#'auto-fill-mode
)
830 (add-hook 'tex-mode-hook
#'flyspell-mode
)
833 ;;; Emacs enhancements & auxiliary packages
835 (with-eval-after-load 'man
836 (csetq Man-width
80))
838 (defun b/*scratch
* ()
839 "Switch to `*scratch*' buffer, creating it if it does not exist."
842 (or (get-buffer "*scratch*")
843 (with-current-buffer (get-buffer-create "*scratch*")
844 (set-buffer-major-mode (current-buffer))
846 (global-set-key (kbd "C-c s") #'b
/*scratch
*)
849 ;; | make pretty boxed quotes like this
851 (add-to-list 'load-path
(b/lisp
"boxquote"))
852 (run-with-idle-timer 0.6 nil
#'require
'boxquote
)
853 (with-eval-after-load 'boxquote
854 (defvar b
/boxquote-prefix-map
)
855 (define-prefix-command 'b
/boxquote-prefix-map
)
856 (global-set-key (kbd "C-c q") 'b
/boxquote-prefix-map
)
857 (define-key b
/boxquote-prefix-map
(kbd "b") #'boxquote-buffer
)
858 (define-key b
/boxquote-prefix-map
(kbd "B") #'boxquote-insert-buffer
)
859 (define-key b
/boxquote-prefix-map
(kbd "d") #'boxquote-defun
)
860 (define-key b
/boxquote-prefix-map
(kbd "F") #'boxquote-insert-file
)
861 (define-key b
/boxquote-prefix-map
(kbd "hf") #'boxquote-describe-function
)
862 (define-key b
/boxquote-prefix-map
(kbd "hk") #'boxquote-describe-key
)
863 (define-key b
/boxquote-prefix-map
(kbd "hv") #'boxquote-describe-variable
)
864 (define-key b
/boxquote-prefix-map
(kbd "hw") #'boxquote-where-is
)
865 (define-key b
/boxquote-prefix-map
(kbd "k") #'boxquote-kill
)
866 (define-key b
/boxquote-prefix-map
(kbd "p") #'boxquote-paragraph
)
867 (define-key b
/boxquote-prefix-map
(kbd "q") #'boxquote-boxquote
)
868 (define-key b
/boxquote-prefix-map
(kbd "r") #'boxquote-region
)
869 (define-key b
/boxquote-prefix-map
(kbd "s") #'boxquote-shell-command
)
870 (define-key b
/boxquote-prefix-map
(kbd "t") #'boxquote-text
)
871 (define-key b
/boxquote-prefix-map
(kbd "T") #'boxquote-title
)
872 (define-key b
/boxquote-prefix-map
(kbd "u") #'boxquote-unbox
)
873 (define-key b
/boxquote-prefix-map
(kbd "U") #'boxquote-unbox-region
)
874 (define-key b
/boxquote-prefix-map
(kbd "y") #'boxquote-yank
)
875 (define-key b
/boxquote-prefix-map
(kbd "M-q") #'boxquote-fill-paragraph
)
876 (define-key b
/boxquote-prefix-map
(kbd "M-w") #'boxquote-kill-ring-save
))
878 (add-to-list 'load-path
(b/lisp
"hl-todo"))
879 (run-with-idle-timer 0.5 nil
#'require
'hl-todo
)
880 (with-eval-after-load 'hl-todo
881 ;; highlight TODOs in buffers
882 (global-hl-todo-mode))
884 (add-to-list 'load-path
(b/lisp
"page-break-lines"))
885 (run-with-idle-timer 0.5 nil
#'require
'page-break-lines
)
886 (with-eval-after-load 'page-break-lines
887 (csetq page-break-lines-max-width fill-column
)
888 (global-page-break-lines-mode))
891 (global-set-key (kbd "C-=") #'er
/expand-region
)
893 (run-with-idle-timer 0.6 nil
#'require
'yasnippet
)
894 (with-eval-after-load 'yasnippet
895 (declare-function yas-reload-all
896 "yasnippet" (&optional no-jit interactive
))
897 (declare-function yas-maybe-expand-abbrev-key-filter
900 (defconst yas-verbosity-cur yas-verbosity
)
901 (setq yas-verbosity
2)
902 (csetq yas-snippet-dirs
`(,(b/etc
"yasnippet/snippets")))
903 (add-to-list 'yas-snippet-dirs
"~/src/git/guix/etc/snippets" t
)
905 (setq yas-verbosity yas-verbosity-cur
)
907 (defun b/yas-maybe-expand-abbrev-key-filter
(cmd)
908 (when (and (yas-maybe-expand-abbrev-key-filter cmd
)
909 (not (bound-and-true-p git-commit-mode
)))
911 (defconst b
/yas-maybe-expand
912 '(menu-item "" yas-expand
913 :filter b
/yas-maybe-expand-abbrev-key-filter
))
914 (define-key yas-minor-mode-map
(kbd "SPC") b
/yas-maybe-expand
)
919 (global-set-key (kbd "C-c D d") #'debbugs-gnu
)
920 (global-set-key (kbd "C-c D b") #'debbugs-gnu-bugs
)
921 (global-set-key (kbd "C-c D e") ; bug-gnu-emacs
924 (setq debbugs-gnu-current-suppress t
)
925 (debbugs-gnu debbugs-gnu-default-severities
927 (global-set-key (kbd "C-c D g") ; bug-gnuzilla
930 (setq debbugs-gnu-current-suppress t
)
931 (debbugs-gnu debbugs-gnu-default-severities
933 (global-set-key (kbd "C-c D G b") ; bug-guix
936 (setq debbugs-gnu-current-suppress t
)
937 (debbugs-gnu debbugs-gnu-default-severities
939 (global-set-key (kbd "C-c D G p") ; guix-patches
942 (setq debbugs-gnu-current-suppress t
)
943 (debbugs-gnu debbugs-gnu-default-severities
948 url-configuration-directory
(b/var
"url/configuration/")
949 url-cache-directory
(b/var
"url/cache/"))
952 (csetq eww-download-directory
(file-name-as-directory
953 (getenv "XDG_DOWNLOAD_DIR")))
954 (global-set-key (kbd "C-c a e w") #'eww
)
958 ;; reftex-default-bibliography '("~/usr/org/references.bib")
959 ;; org-ref-default-bibliography '("~/usr/org/references.bib")
960 ;; org-ref-bibliography-notes "~/usr/org/notes.org"
961 ;; org-ref-pdf-directory "~/usr/org/bibtex-pdfs/")
963 ;; fill-column-indicator ?
966 (csetq split-width-threshold
150)
967 (global-set-key (kbd "C-c w s l")
972 (global-set-key (kbd "C-c w s j")
977 (global-set-key (kbd "C-c w q") #'quit-window
)
979 (run-with-idle-timer 0.6 nil
#'require
'windmove
)
980 (global-set-key (kbd "C-c w h") #'windmove-left
)
981 (global-set-key (kbd "C-c w j") #'windmove-down
)
982 (global-set-key (kbd "C-c w k") #'windmove-up
)
983 (global-set-key (kbd "C-c w l") #'windmove-right
)
984 (global-set-key (kbd "C-c w H") #'windmove-swap-states-left
)
985 (global-set-key (kbd "C-c w J") #'windmove-swap-states-down
)
986 (global-set-key (kbd "C-c w K") #'windmove-swap-states-up
)
987 (global-set-key (kbd "C-c w L") #'windmove-swap-states-right
)
990 ;; (global-set-key (kbd "C-c a p") #'pass)
991 ;; (add-hook 'pass-mode-hook #'View-exit)
994 ;; uncomment to disable reftex-cite's default choice of previous word
995 ;; (with-eval-after-load 'reftex
996 ;; (require 'reftex-cite)
997 ;; (defun reftex-get-bibkey-default ()
998 ;; "If the cursor is in a citation macro, return the word before the macro."
999 ;; (let* ((macro (reftex-what-macro 1)))
1001 ;; (when (and macro (string-match "cite" (car macro)))
1002 ;; (goto-char (cdr macro)))
1003 ;; (reftex-this-word)))))
1004 (add-hook 'latex-mode-hook
#'reftex-mode
)
1008 ;; dmenu-prompt-string "run: "
1009 ;; dmenu-save-file (b/var "dmenu-items"))
1014 (run-with-idle-timer 0.5 nil
#'require
'delight
)
1015 (with-eval-after-load 'delight
1016 (delight 'auto-fill-function
" f" "simple")
1017 (delight 'abbrev-mode
"" "abbrev")
1018 (delight 'page-break-lines-mode
"" "page-break-lines")
1019 (delight 'ivy-mode
"" "ivy")
1020 (delight 'counsel-mode
"" "counsel")
1021 (delight 'mml-mode
" mml" "mml")
1022 (delight 'yas-minor-mode
"" "yasnippet"))
1025 ;;; Post initialization
1027 (message "Loading %s...done (%.3fs)" user-init-file
1028 (float-time (time-subtract (current-time)
1029 b
/before-user-init-time
)))
1031 ;;; init.el ends here