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")
157 (expand-region "0.11.0")
159 ;; (refinery-theme "0.1.1")
161 (org-plus-contrib "20201012"))))
162 (package-initialize))
164 (csetq package-archive-upload-base
"/ssh:caffeine:~/www/p/elpa")
169 ;; keep ~/.emacs.d clean
172 (convert-standard-filename "etc/") user-emacs-directory
)
173 "The directory where packages place their configuration files.")
176 (convert-standard-filename "var/") user-emacs-directory
)
177 "The directory where packages place their persistent data files.")
180 (convert-standard-filename "lisp/") user-emacs-directory
)
181 "The directory where packages place their persistent data files.")
183 "Expand filename FILE relative to `b/etc-dir'."
184 (expand-file-name (convert-standard-filename file
) b
/etc-dir
))
186 "Expand filename FILE relative to `b/var-dir'."
187 (expand-file-name (convert-standard-filename file
) b
/var-dir
))
189 "Expand filename FILE relative to `b/lisp-dir'."
190 (expand-file-name (convert-standard-filename file
) b
/lisp-dir
))
193 auto-save-list-file-prefix
(b/var
"auto-save/sessions/")
194 nsm-settings-file
(b/var
"nsm-settings.el"))
196 ;; separate custom file (don't want it mixing with init.el)
197 (with-eval-after-load 'custom
198 (setq custom-file
(b/etc
"custom.el"))
199 (when (file-exists-p custom-file
)
201 ;; while at it, treat themes as safe
202 ;; (setf custom-safe-themes t)
203 ;; only one custom theme at a time
204 ;; (defadvice load-theme (before clear-previous-themes activate)
205 ;; "Clear existing theme settings instead of layering them"
206 ;; (mapc #'disable-theme custom-enabled-themes))
209 ;; load the secrets file if it exists, otherwise show a warning
210 ;; (with-demoted-errors
211 ;; (load (b/etc "secrets")))
213 ;; start up emacs server. see
214 ;; https://www.gnu.org/software/emacs/manual/html_node/emacs/Emacs-Server.html#Emacs-Server
215 (run-with-idle-timer 0.5 nil
#'require
'server
)
216 (with-eval-after-load 'server
217 (declare-function server-edit
"server")
218 (global-set-key (kbd "C-c F D") #'server-edit
)
219 (declare-function server-running-p
"server")
220 (or (server-running-p) (server-mode)))
225 ;;;; C-level customizations
229 enable-recursive-minibuffers t
230 resize-mini-windows t
231 ;; more useful frame titles
232 ;; frame-title-format '("" invocation-name " - "
234 ;; (if (buffer-file-name)
235 ;; (abbreviate-file-name (buffer-file-name))
237 ;; i don't feel like jumping out of my chair every now and again; so
238 ;; don't BEEP! at me, emacs
239 ring-bell-function
'ignore
242 ;; scroll-conservatively 10000
244 scroll-conservatively
101
245 scroll-preserve-screen-position
1
246 ;; focus follows mouse
247 mouse-autoselect-window t
)
250 ;; always use space for indentation
253 ;; case-sensitive search (and `dabbrev-expand')
254 ;; case-fold-search nil
258 (set-fontset-font t
'arabic
"Vazir")
261 ;; (dolist (ft (fontset-list))
265 ;; (font-spec :name "Source Code Pro" :size 14))
269 ;; (font-spec :name "DejaVu Sans Mono")
272 ;; ;; (set-fontset-font
276 ;; ;; :name "Symbola monospacified for DejaVu Sans Mono")
279 ;; ;; (set-fontset-font
282 ;; ;; (font-spec :name "DejaVu Sans Mono")
288 ;; (font-spec :name "DejaVu Sans Mono" :size 14)
292 ;;;; Elisp-level customizations
295 ;; don't need to see the startup echo area message
296 (advice-add #'display-startup-echo-area-message
:override
#'ignore
)
298 ;; i want *scratch* as my startup buffer
299 initial-buffer-choice t
300 ;; i don't need the default hint
301 initial-scratch-message nil
302 ;; use customizable text-mode as major mode for *scratch*
303 ;; (initial-major-mode 'text-mode)
304 ;; inhibit buffer list when more than 2 files are loaded
305 inhibit-startup-buffer-menu t
306 ;; don't need to see the startup screen or echo area message
307 inhibit-startup-screen t
308 inhibit-startup-echo-area-message user-login-name
)
312 ;; backups (C-h v make-backup-files RET)
314 backup-directory-alist
(list (cons "." (b/var
"backup/")))
316 delete-old-versions t
318 auto-save-file-name-transforms
`((".*" ,(b/var
"auto-save/") t
))
319 ;; insert newline at the end of files
320 require-final-newline t
321 ;; open read-only file buffers in view-mode
322 ;; (enables niceties like `q' for quit)
326 ;; disable disabled commands
327 (csetq disabled-command-function nil
)
329 ;; lazy-person-friendly yes/no prompts
330 (defalias 'yes-or-no-p
#'y-or-n-p
)
332 ;; autorevert: enable automatic reloading of changed buffers and files
333 (csetq auto-revert-verbose nil
334 global-auto-revert-non-file-buffers nil
)
335 (require 'autorevert
)
336 (global-auto-revert-mode 1)
338 ;; time and battery in mode-line
340 display-time-default-load-average nil
341 display-time-format
" %a %b %-e %-l:%M%P"
342 display-time-mail-icon
'(image :type xpm
343 :file
"gnus/gnus-pointer.xpm"
345 display-time-use-mail-icon t
)
349 (csetq battery-mode-line-format
" %p%% %t")
351 (display-battery-mode)
355 ;; (fringe-mode '(3 . 1))
359 ;; enable winner-mode (C-h f winner-mode RET)
362 (with-eval-after-load 'compile
363 ;; don't display *compilation* buffer on success. based on
364 ;; https://stackoverflow.com/a/17788551, with changes to use `cl-letf'
365 ;; instead of the now obsolete `flet'.
366 (defun b/compilation-finish-function
(buffer outstr
)
367 (unless (string-match "finished" outstr
)
368 (switch-to-buffer-other-window buffer
))
371 (setq compilation-finish-functions
#'b
/compilation-finish-function
)
375 (defadvice compilation-start
376 (around inhibit-display
377 (command &optional mode name-function highlight-regexp
))
378 (if (not (string-match "^\\(find\\|grep\\)" command
))
379 (cl-letf (((symbol-function 'display-buffer
) #'ignore
))
380 (save-window-excursion ad-do-it
))
382 (ad-activate 'compilation-start
))
386 ;; allow scrolling in Isearch
387 isearch-allow-scroll t
388 ;; search for non-ASCII characters: i’d like non-ASCII characters such
389 ;; as ‘’“”«»‹›áⓐ𝒶 to be selected when i search for their ASCII
390 ;; counterpart. shoutout to
391 ;; http://endlessparentheses.com/new-in-emacs-25-1-easily-search-non-ascii-characters.html
392 search-default-mode
#'char-fold-to-regexp
)
395 ;; uncomment to extend the above behaviour to query-replace
396 ;; (csetq replace-char-fold t)
399 (global-set-key (kbd "C-x v C-=") #'vc-ediff
)
401 (with-eval-after-load 'vc-git
402 (csetq vc-git-print-log-follow t
403 vc-git-show-stash
0))
405 (csetq ediff-window-setup-function
'ediff-setup-windows-plain
406 ediff-split-window-function
'split-window-horizontally
)
407 (with-eval-after-load 'ediff
408 (add-hook 'ediff-after-quit-hook-internal
#'winner-undo
))
412 ;; gentler font resizing
413 text-scale-mode-step
1.05)
415 (run-with-idle-timer 0.4 nil
#'require
'mwheel
)
416 (csetq mouse-wheel-scroll-amount
'(1 ((shift) .
1)) ; one line at a time
417 mouse-wheel-progressive-speed nil
; don't accelerate scrolling
418 mouse-wheel-follow-mouse t
) ; scroll window under mouse
420 (run-with-idle-timer 0.4 nil
#'require
'pixel-scroll
)
421 (with-eval-after-load 'pixel-scroll
422 (pixel-scroll-mode 1))
426 epg-gpg-program
(executable-find "gpg")
427 ;; ask for GPG passphrase in minibuffer
428 ;; this will fail if gpg>=2.1 is not available
429 epg-pinentry-mode
'loopback
)
431 ;; (require 'pinentry)
432 ;; workaround for systemd-based distros:
433 ;; (setq pinentry--socket-dir server-socket-dir)
438 auth-sources
'("~/.authinfo.gpg")
439 authinfo-hidden
(regexp-opt '("password" "client-secret" "token")))
444 (defun b/add-elisp-section
()
448 (insert "\n\f\n;;; "))
450 (defun b/insert-asterism
()
451 "Insert a centred asterism."
453 (let ((asterism "* * *"))
458 (floor (/ (- fill-column
(length asterism
)) 2))
463 (defun b/start-process
(program &rest args
)
464 "Same as `start-process', but doesn't bother about name and buffer."
465 (let ((process-name (concat program
"_process"))
466 (buffer-name (generate-new-buffer-name
467 (concat program
"_output"))))
468 (apply #'start-process
469 process-name buffer-name program args
)))
471 (defun b/no-mouse-autoselect-window
()
472 "Conveniently disable `focus-follows-mouse'.
473 For disabling the behaviour for certain buffers and/or modes."
474 (make-local-variable 'mouse-autoselect-window
)
475 (setq mouse-autoselect-window nil
))
477 (defun b/kill-current-buffer
()
478 "Kill the current buffer."
479 ;; also see https://redd.it/64xb3q
481 (kill-buffer (current-buffer)))
483 (defun b/move-indentation-or-beginning-of-line
(arg)
484 "Move to the indentation or to the beginning of line."
487 ;; (back-to-indentation)
488 ;; (move-beginning-of-line arg))
490 (progn (back-to-indentation)
492 (move-beginning-of-line arg
)))
494 (defun b/join-line-top
()
495 "Like `join-line', but join next line to the current line."
499 (defun b/duplicate-line-or-region
(&optional n
)
500 "Duplicate the current line, or region (if active).
501 Make N (default: 1) copies of the current line or region."
503 (let ((u-r-p (use-region-p)) ; if region is active
508 (buffer-substring (region-beginning) (region-end))
509 (prog1 (thing-at-point 'line
)
513 (forward-line 1))))))
514 (dotimes (_ (abs n1
))
518 ;;; General key bindings
520 (global-set-key (kbd "C-a") #'b
/move-indentation-or-beginning-of-line
)
521 (global-set-key (kbd "C-c a i") #'ielm
)
522 (global-set-key (kbd "C-c d") #'b
/duplicate-line-or-region
)
523 (global-set-key (kbd "C-S-j") #'b
/join-line-top
)
524 (global-set-key (kbd "C-c x") #'execute-extended-command
)
526 ;; evaling and macro-expanding
527 (global-set-key (kbd "C-c e b") #'eval-buffer
)
528 (global-set-key (kbd "C-c e e") #'eval-last-sexp
)
529 (global-set-key (kbd "C-c e p") #'pp-macroexpand-last-sexp
)
530 (global-set-key (kbd "C-c e r") #'eval-region
)
533 (global-set-key (kbd "C-c e i") #'emacs-init-time
)
534 (global-set-key (kbd "C-c e u") #'emacs-uptime
)
535 (global-set-key (kbd "C-c e v") #'emacs-version
)
538 (global-set-key (kbd "C-c f .") #'find-file
)
539 (global-set-key (kbd "C-c f d") #'find-name-dired
)
540 (global-set-key (kbd "C-c f l") #'find-library
)
543 (global-set-key (kbd "C-c F m") #'make-frame-command
)
544 (global-set-key (kbd "C-c F d") #'delete-frame
)
547 (global-set-key (kbd "C-S-h C") #'describe-char
)
548 (global-set-key (kbd "C-S-h F") #'describe-face
)
550 ;; (global-set-key (kbd "C-x k") #'b/kill-current-buffer)
551 ;; (global-set-key (kbd "C-x K") #'kill-buffer)
552 ;; (global-set-key (kbd "C-x s") #'save-buffer)
553 ;; (global-set-key (kbd "C-x S") #'save-some-buffers)
555 (define-key emacs-lisp-mode-map
(kbd "<C-return>") #'b
/add-elisp-section
)
557 (when (display-graphic-p)
558 (global-unset-key (kbd "C-z")))
561 ;;; Essential packages
566 (convert-standard-filename "lisp") user-emacs-directory
))
568 (require 'bandali-exwm
)
570 (require 'bandali-org
)
572 (require 'bandali-theme
)
574 ;; (require 'bandali-magit)
576 ;; recently opened files
577 (csetq recentf-max-saved-items
2000
578 recentf-save-file
(b/var
"recentf-save.el"))
579 (run-with-idle-timer 0.2 nil
#'require
'recentf
)
580 (with-eval-after-load 'recentf
581 ;; (add-to-list 'recentf-keep #'file-remote-p)
584 ;; needed for history for counsel
585 (csetq amx-save-file
(b/var
"amx-save.el"))
586 (add-to-list 'load-path
(b/lisp
"s"))
587 (add-to-list 'load-path
(b/lisp
"amx"))
588 (run-with-idle-timer 0.3 nil
#'require
'amx
)
589 (with-eval-after-load 'amx
592 (require 'bandali-ivy
)
594 (require 'bandali-eshell
)
596 (require 'bandali-ibuffer
)
599 ;; (with-eval-after-load 'outline
600 ;; (when (featurep 'which-key)
601 ;; (which-key-add-key-based-replacements
604 ;; (define-key outline-minor-mode-map (kbd "<s-tab>")
605 ;; #'outline-toggle-children)
606 ;; (define-key outline-minor-mode-map (kbd "M-p")
607 ;; #'outline-previous-visible-heading)
608 ;; (define-key outline-minor-mode-map (kbd "M-n")
609 ;; #'outline-next-visible-heading)
610 ;; (defvar b/outline-prefix-map)
611 ;; (define-prefix-command 'b/outline-prefix-map)
612 ;; (define-key outline-minor-mode-map (kbd "s-O")
613 ;; 'b/outline-prefix-map)
614 ;; (define-key b/outline-prefix-map (kbd "TAB")
615 ;; #'outline-toggle-children)
616 ;; (define-key b/outline-prefix-map (kbd "a")
617 ;; #'outline-hide-body)
618 ;; (define-key b/outline-prefix-map (kbd "H")
619 ;; #'outline-hide-body)
620 ;; (define-key b/outline-prefix-map (kbd "S")
621 ;; #'outline-show-all)
622 ;; (define-key b/outline-prefix-map (kbd "h")
623 ;; #'outline-hide-subtree)
624 ;; (define-key b/outline-prefix-map (kbd "s")
625 ;; #'outline-show-subtree))
626 ;; (add-hook 'prog-mode-hook #'outline-minor-mode)
628 (require 'bandali-dired
)
630 (with-eval-after-load 'help
631 (temp-buffer-resize-mode)
632 (csetq help-window-select t
))
634 (with-eval-after-load 'help-mode
635 ;; local key bindings
636 (define-key help-mode-map
(kbd "p") #'backward-button
)
637 (define-key help-mode-map
(kbd "n") #'forward-button
))
639 (with-eval-after-load 'tramp
640 (csetq tramp-auto-save-directory
(b/var
"tramp/auto-save/")
641 tramp-persistency-file-name
(b/var
"tramp/persistency.el"))
642 (add-to-list 'tramp-default-proxies-alist
'(nil "\\`root\\'" "/ssh:%h:"))
643 (add-to-list 'tramp-default-proxies-alist
'("localhost" nil nil
))
644 (add-to-list 'tramp-default-proxies-alist
645 (list (regexp-quote (system-name)) nil nil
)))
647 (with-eval-after-load 'doc-view
648 (define-key doc-view-mode-map
(kbd "M-RET") #'image-previous-line
))
650 (csetq shr-max-width
80)
652 ;; Email (with Gnus, message, and EBDB)
653 (require 'bandali-gnus
)
654 (with-eval-after-load 'sendmail
655 (csetq sendmail-program
(executable-find "msmtp")
656 ;; message-sendmail-extra-arguments '("-v" "-d")
657 mail-specify-envelope-from t
658 mail-envelope-from
'header
))
659 (require 'bandali-message
)
660 (require 'bandali-ebdb
)
663 (require 'bandali-erc
)
665 ;; 'paste' service (aka scp + web server)
666 (add-to-list 'load-path
(b/lisp
"scpaste"))
667 (with-eval-after-load 'scpaste
668 (csetq scpaste-http-destination
"https://p.bndl.org"
669 scpaste-scp-destination
"p:~"))
670 (autoload 'scpaste
"scpaste" nil t
)
671 (autoload 'scpaste-region
"scpaste" nil t
)
672 (global-set-key (kbd "C-c a p p") #'scpaste
)
673 (global-set-key (kbd "C-c a p r") #'scpaste-region
)
678 ;; display Lisp objects at point in the echo area
679 (when (version< "25" emacs-version
)
680 (with-eval-after-load 'eldoc
681 (csetq eldoc-minor-mode-string
" eldoc")
682 (global-eldoc-mode)))
684 ;; highlight matching parens
688 ;; (require 'elec-pair)
689 ;; (electric-pair-mode)
692 ;; Save what I copy into clipboard from other applications into Emacs'
693 ;; kill-ring, which would allow me to still be able to easily access
694 ;; it in case I kill (cut or copy) something else inside Emacs before
695 ;; yanking (pasting) what I'd originally intended to.
696 save-interprogram-paste-before-kill t
)
697 (with-eval-after-load 'simple
698 (column-number-mode 1))
700 ;; save minibuffer history
702 (csetq savehist-file
(b/var
"savehist.el"))
704 (add-to-list 'savehist-additional-variables
'kill-ring
)
706 ;; automatically save place in files
707 (when (version< "25" emacs-version
)
708 (csetq save-place-file
(b/var
"save-place.el"))
711 (defun indicate-buffer-boundaries-left ()
712 (csetq indicate-buffer-boundaries
'left
))
713 (with-eval-after-load 'prog-mode
714 (global-prettify-symbols-mode))
715 (add-hook 'prog-mode-hook
#'indicate-buffer-boundaries-left
)
717 (define-key text-mode-map
(kbd "C-<return>") #'b
/insert-asterism
)
718 (add-hook 'text-mode-hook
#'indicate-buffer-boundaries-left
)
719 (add-hook 'text-mode-hook
#'flyspell-mode
)
721 (add-to-list 'auto-mode-alist
'("\\.*rc$" . conf-mode
))
723 (add-to-list 'auto-mode-alist
'("\\.bashrc$" . sh-mode
))
725 (with-eval-after-load 'flyspell
726 (csetq flyspell-mode-line-string
" fly"))
729 ;; (run-with-idle-timer 0.6 nil #'require 'flycheck)
730 ;; (with-eval-after-load 'flycheck
732 ;; ;; Use the load-path from running Emacs when checking elisp files
733 ;; flycheck-emacs-lisp-load-path 'inherit
734 ;; ;; Only flycheck when I actually save the buffer
735 ;; flycheck-check-syntax-automatically '(mode-enabled save)
736 ;; flycheck-mode-line-prefix "flyc"))
737 ;; (define-key flycheck-mode-map (kbd "M-P") #'flycheck-previous-error)
738 ;; (define-key flycheck-mode-map (kbd "M-N") #'flycheck-next-error)
739 ;; (add-hook 'prog-mode-hook #'flycheck-mode)
742 ;; http://endlessparentheses.com/ispell-and-apostrophes.html
743 ;; (run-with-idle-timer 0.6 nil #'require 'ispell)
744 ;; (with-eval-after-load 'ispell
745 ;; ;; ’ can be part of a word
746 ;; (csetq ispell-local-dictionary-alist
747 ;; `((nil "[[:alpha:]]" "[^[:alpha:]]"
748 ;; "['\x2019]" nil ("-B") nil utf-8))
749 ;; ispell-program-name (executable-find "hunspell"))
750 ;; ;; don't send ’ to the subprocess
751 ;; (defun endless/replace-apostrophe (args)
752 ;; (cons (replace-regexp-in-string
753 ;; "’" "'" (car args))
755 ;; (advice-add #'ispell-send-string :filter-args
756 ;; #'endless/replace-apostrophe)
757 ;; ;; convert ' back to ’ from the subprocess
758 ;; (defun endless/replace-quote (args)
759 ;; (if (not (derived-mode-p 'org-mode))
761 ;; (cons (replace-regexp-in-string
762 ;; "'" "’" (car args))
764 ;; (advice-add #'ispell-parse-output :filter-args
765 ;; #'endless/replace-quote))
768 (csetq abbrev-file-name
(b/etc
"abbrev.el"))
769 (add-hook 'text-mode-hook
#'abbrev-mode
)
772 ;;; Programming modes
774 (with-eval-after-load 'lisp-mode
775 (defun indent-spaces-mode ()
776 (setq indent-tabs-mode nil
))
777 (add-hook 'lisp-interaction-mode-hook
#'indent-spaces-mode
))
780 (add-to-list 'load-path
(b/lisp
"alloy-mode"))
781 (autoload 'alloy-mode
"alloy-mode" nil t
)
782 (with-eval-after-load 'alloy-mode
783 (csetq alloy-basic-offset
2)
784 ;; (defun b/alloy-simple-indent (start end)
786 ;; ;; (if (region-active-p)
787 ;; ;; (indent-rigidly start end alloy-basic-offset)
789 ;; ;; (indent-rigidly (line-beginning-position)
790 ;; ;; (line-end-position)
791 ;; ;; alloy-basic-offset)))
792 ;; (indent-to (+ (current-column) alloy-basic-offset)))
793 ;; local key bindings
794 (define-key alloy-mode-map
(kbd "RET") #'electric-newline-and-maybe-indent
)
795 ;; (define-key alloy-mode-map (kbd "TAB") #'b/alloy-simple-indent)
796 (define-key alloy-mode-map
(kbd "TAB") #'indent-for-tab-command
))
797 (add-to-list 'auto-mode-alist
'("\\.\\(als\\|dsh\\)\\'" . alloy-mode
))
798 (add-hook 'alloy-mode-hook
(lambda nil
(setq-local indent-tabs-mode nil
)))
801 ;; (eval-when-compile (defvar lean-mode-map))
802 ;; (run-with-idle-timer 0.4 nil #'require 'lean-mode)
803 ;; (with-eval-after-load 'lean-mode
804 ;; (require 'lean-input)
805 ;; (csetq default-input-method "Lean"
806 ;; lean-input-tweak-all '(lean-input-compose
807 ;; (lean-input-prepend "/")
808 ;; (lean-input-nonempty))
809 ;; lean-input-user-translations '(("/" "/")))
810 ;; (lean-input-setup)
811 ;; ;; local key bindings
812 ;; (define-key lean-mode-map (kbd "S-SPC") #'company-complete))
814 (with-eval-after-load 'sgml-mode
815 (csetq sgml-basic-offset
0))
817 (with-eval-after-load 'css-mode
818 (csetq css-indent-offset
2))
821 ;; (add-hook 'po-mode-hook (lambda nil (run-with-timer 0.1 nil 'View-exit)))
824 ;; (csetq font-latex-fontify-sectioning 'color)
826 (with-eval-after-load 'tex-mode
828 (lambda (p) (string-match "^---?" (car p
)))
829 tex--prettify-symbols-alist
))
830 (add-hook 'tex-mode-hook
#'auto-fill-mode
)
831 (add-hook 'tex-mode-hook
#'flyspell-mode
)
834 ;;; Emacs enhancements & auxiliary packages
836 (with-eval-after-load 'man
837 (csetq Man-width
80))
839 (defun b/*scratch
* ()
840 "Switch to `*scratch*' buffer, creating it if it does not exist."
843 (or (get-buffer "*scratch*")
844 (with-current-buffer (get-buffer-create "*scratch*")
845 (set-buffer-major-mode (current-buffer))
847 (global-set-key (kbd "C-c s") #'b
/*scratch
*)
850 ;; | make pretty boxed quotes like this
852 (add-to-list 'load-path
(b/lisp
"boxquote"))
853 (run-with-idle-timer 0.6 nil
#'require
'boxquote
)
854 (with-eval-after-load 'boxquote
855 (defvar b
/boxquote-prefix-map
)
856 (define-prefix-command 'b
/boxquote-prefix-map
)
857 (global-set-key (kbd "C-c q") 'b
/boxquote-prefix-map
)
858 (define-key b
/boxquote-prefix-map
(kbd "b") #'boxquote-buffer
)
859 (define-key b
/boxquote-prefix-map
(kbd "B") #'boxquote-insert-buffer
)
860 (define-key b
/boxquote-prefix-map
(kbd "d") #'boxquote-defun
)
861 (define-key b
/boxquote-prefix-map
(kbd "F") #'boxquote-insert-file
)
862 (define-key b
/boxquote-prefix-map
(kbd "hf") #'boxquote-describe-function
)
863 (define-key b
/boxquote-prefix-map
(kbd "hk") #'boxquote-describe-key
)
864 (define-key b
/boxquote-prefix-map
(kbd "hv") #'boxquote-describe-variable
)
865 (define-key b
/boxquote-prefix-map
(kbd "hw") #'boxquote-where-is
)
866 (define-key b
/boxquote-prefix-map
(kbd "k") #'boxquote-kill
)
867 (define-key b
/boxquote-prefix-map
(kbd "p") #'boxquote-paragraph
)
868 (define-key b
/boxquote-prefix-map
(kbd "q") #'boxquote-boxquote
)
869 (define-key b
/boxquote-prefix-map
(kbd "r") #'boxquote-region
)
870 (define-key b
/boxquote-prefix-map
(kbd "s") #'boxquote-shell-command
)
871 (define-key b
/boxquote-prefix-map
(kbd "t") #'boxquote-text
)
872 (define-key b
/boxquote-prefix-map
(kbd "T") #'boxquote-title
)
873 (define-key b
/boxquote-prefix-map
(kbd "u") #'boxquote-unbox
)
874 (define-key b
/boxquote-prefix-map
(kbd "U") #'boxquote-unbox-region
)
875 (define-key b
/boxquote-prefix-map
(kbd "y") #'boxquote-yank
)
876 (define-key b
/boxquote-prefix-map
(kbd "M-q") #'boxquote-fill-paragraph
)
877 (define-key b
/boxquote-prefix-map
(kbd "M-w") #'boxquote-kill-ring-save
))
879 (add-to-list 'load-path
(b/lisp
"hl-todo"))
880 (run-with-idle-timer 0.5 nil
#'require
'hl-todo
)
881 (with-eval-after-load 'hl-todo
882 ;; highlight TODOs in buffers
883 (global-hl-todo-mode))
885 (add-to-list 'load-path
(b/lisp
"page-break-lines"))
886 (run-with-idle-timer 0.5 nil
#'require
'page-break-lines
)
887 (with-eval-after-load 'page-break-lines
888 (csetq page-break-lines-max-width fill-column
)
889 (global-page-break-lines-mode))
892 (global-set-key (kbd "C-=") #'er
/expand-region
)
894 (run-with-idle-timer 0.6 nil
#'require
'yasnippet
)
895 (with-eval-after-load 'yasnippet
896 (declare-function yas-reload-all
897 "yasnippet" (&optional no-jit interactive
))
898 (declare-function yas-maybe-expand-abbrev-key-filter
901 (defconst yas-verbosity-cur yas-verbosity
)
902 (setq yas-verbosity
2)
903 (csetq yas-snippet-dirs
`(,(b/etc
"yasnippet/snippets")))
904 (add-to-list 'yas-snippet-dirs
"~/src/git/guix/etc/snippets" t
)
906 (setq yas-verbosity yas-verbosity-cur
)
908 (defun b/yas-maybe-expand-abbrev-key-filter
(cmd)
909 (when (and (yas-maybe-expand-abbrev-key-filter cmd
)
910 (not (bound-and-true-p git-commit-mode
)))
912 (defconst b
/yas-maybe-expand
913 '(menu-item "" yas-expand
914 :filter b
/yas-maybe-expand-abbrev-key-filter
))
915 (define-key yas-minor-mode-map
(kbd "SPC") b
/yas-maybe-expand
)
920 (global-set-key (kbd "C-c D d") #'debbugs-gnu
)
921 (global-set-key (kbd "C-c D b") #'debbugs-gnu-bugs
)
922 (global-set-key (kbd "C-c D e") ; bug-gnu-emacs
925 (setq debbugs-gnu-current-suppress t
)
926 (debbugs-gnu debbugs-gnu-default-severities
928 (global-set-key (kbd "C-c D g") ; bug-gnuzilla
931 (setq debbugs-gnu-current-suppress t
)
932 (debbugs-gnu debbugs-gnu-default-severities
934 (global-set-key (kbd "C-c D G b") ; bug-guix
937 (setq debbugs-gnu-current-suppress t
)
938 (debbugs-gnu debbugs-gnu-default-severities
940 (global-set-key (kbd "C-c D G p") ; guix-patches
943 (setq debbugs-gnu-current-suppress t
)
944 (debbugs-gnu debbugs-gnu-default-severities
949 url-configuration-directory
(b/var
"url/configuration/")
950 url-cache-directory
(b/var
"url/cache/"))
953 (csetq eww-download-directory
(file-name-as-directory
954 (getenv "XDG_DOWNLOAD_DIR")))
955 (global-set-key (kbd "C-c a e w") #'eww
)
959 ;; reftex-default-bibliography '("~/usr/org/references.bib")
960 ;; org-ref-default-bibliography '("~/usr/org/references.bib")
961 ;; org-ref-bibliography-notes "~/usr/org/notes.org"
962 ;; org-ref-pdf-directory "~/usr/org/bibtex-pdfs/")
964 ;; fill-column-indicator ?
967 (csetq split-width-threshold
150)
968 (global-set-key (kbd "C-c w s l")
973 (global-set-key (kbd "C-c w s j")
978 (global-set-key (kbd "C-c w q") #'quit-window
)
980 (run-with-idle-timer 0.6 nil
#'require
'windmove
)
981 (global-set-key (kbd "C-c w h") #'windmove-left
)
982 (global-set-key (kbd "C-c w j") #'windmove-down
)
983 (global-set-key (kbd "C-c w k") #'windmove-up
)
984 (global-set-key (kbd "C-c w l") #'windmove-right
)
985 (global-set-key (kbd "C-c w H") #'windmove-swap-states-left
)
986 (global-set-key (kbd "C-c w J") #'windmove-swap-states-down
)
987 (global-set-key (kbd "C-c w K") #'windmove-swap-states-up
)
988 (global-set-key (kbd "C-c w L") #'windmove-swap-states-right
)
991 ;; (global-set-key (kbd "C-c a p") #'pass)
992 ;; (add-hook 'pass-mode-hook #'View-exit)
995 ;; uncomment to disable reftex-cite's default choice of previous word
996 ;; (with-eval-after-load 'reftex
997 ;; (require 'reftex-cite)
998 ;; (defun reftex-get-bibkey-default ()
999 ;; "If the cursor is in a citation macro, return the word before the macro."
1000 ;; (let* ((macro (reftex-what-macro 1)))
1002 ;; (when (and macro (string-match "cite" (car macro)))
1003 ;; (goto-char (cdr macro)))
1004 ;; (reftex-this-word)))))
1005 (add-hook 'latex-mode-hook
#'reftex-mode
)
1008 (add-to-list 'load-path
(b/lisp
"dmenu"))
1009 (with-eval-after-load 'dmenu
1010 (csetq dmenu-prompt-string
"run: "
1011 dmenu-save-file
(b/var
"dmenu-items")))
1012 (autoload 'dmenu
"dmenu" nil t
)
1017 (run-with-idle-timer 0.5 nil
#'require
'delight
)
1018 (with-eval-after-load 'delight
1019 (delight 'auto-fill-function
" f" "simple")
1020 (delight 'abbrev-mode
"" "abbrev")
1021 (delight 'page-break-lines-mode
"" "page-break-lines")
1022 (delight 'ivy-mode
"" "ivy")
1023 (delight 'counsel-mode
"" "counsel")
1024 (delight 'mml-mode
" mml" "mml")
1025 (delight 'yas-minor-mode
"" "yasnippet"))
1028 ;;; Post initialization
1030 (message "Loading %s...done (%.3fs)" user-init-file
1031 (float-time (time-subtract (current-time)
1032 b
/before-user-init-time
)))
1034 ;;; init.el ends here