1 ;;; init.el --- bandali's emacs configuration -*- lexical-binding: t -*-
3 ;; Copyright (C) 2018-2021 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 bandali, free software activist,
21 ;; computing scientist, and GNU maintainer and volunteer.
23 ;; Over the years, I've taken inspiration from configurations of many
24 ;; great people. Some that I can remember off the top of my head are:
26 ;; - https://github.com/dieggsy/dotfiles
27 ;; - https://github.com/dakra/dmacs
28 ;; - http://pages.sachachua.com/.emacs.d/Sacha.html
29 ;; - https://github.com/dakrone/eos
30 ;; - http://doc.rix.si/cce/cce.html
31 ;; - https://github.com/jwiegley/dot-emacs
32 ;; - https://github.com/wasamasa/dotemacs
33 ;; - https://github.com/hlissner/doom-emacs
37 ;;; Emacs initialization
39 (defvar b
/before-user-init-time
(current-time)
40 "Value of `current-time' when Emacs begins loading `user-init-file'.")
41 (defvar b
/emacs-initialized nil
42 "Whether Emacs has been initialized.")
44 (when (not (bound-and-true-p b
/emacs-initialized
))
45 (message "Loading Emacs...done (%.3fs)"
46 (float-time (time-subtract b
/before-user-init-time
49 ;; temporarily increase `gc-cons-threshhold' and `gc-cons-percentage'
50 ;; during startup to reduce garbage collection frequency. clearing
51 ;; `file-name-handler-alist' seems to help reduce startup time too.
52 (defvar b
/gc-cons-threshold gc-cons-threshold
)
53 (defvar b
/gc-cons-percentage gc-cons-percentage
)
54 (defvar b
/file-name-handler-alist file-name-handler-alist
)
55 (setq gc-cons-threshold
(* 30 1024 1024) ; 30 MiB
56 gc-cons-percentage
0.6
57 file-name-handler-alist nil
58 ;; sidesteps a bug when profiling with esup
59 esup-child-profile-require-level
0)
61 ;; set them back to their defaults once we're done initializing
63 "My post-initialize function, run after loading `user-init-file'."
64 (setq b
/emacs-initialized t
65 gc-cons-threshold b
/gc-cons-threshold
66 gc-cons-percentage b
/gc-cons-percentage
67 file-name-handler-alist b
/file-name-handler-alist
)
68 (when (featurep 'exwm-workspace
)
69 (with-eval-after-load 'exwm-workspace
76 "[%s]" (number-to-string
77 exwm-workspace-current-index
))))))))
78 (when (version< emacs-version
"28")
79 ;; manually make some mode-line spaces smaller
80 ;; (version<= "28" emacs-version) can do an awesome job at this
81 ;; out of the box if `mode-line-compact' is set to t (see below)
92 mode-line-buffer-identification
93 (propertized-buffer-identification "%10b"))))
94 (add-hook 'after-init-hook
#'b
/post-init
)
96 ;; increase number of lines kept in *Messages* log
97 (setq message-log-max
20000)
102 (setq ;; user-full-name "bandali"
103 user-mail-address
"bandali@gnu.org")
106 ;;; csetq (`custom' setq)
110 (defmacro csetq
(&rest args
)
111 "Set the value of user option VAR to VALUE.
113 More generally, you can use multiple variables and values, as in
114 (csetq VAR VALUE VAR VALUE...)
115 This sets each user option VAR's value to the corresponding VALUE.
117 \(fn [VAR VALUE]...)"
118 (declare (debug setq
))
120 ,@(cl-loop for
(var value
) on args by
'cddr
122 `(funcall (or (get ',var
'custom-set
) #'set-default
)
126 ;;; Package management
128 ;; variables of interest:
129 ;; package-archive-priorities
131 ;; package-pinned-packages
133 ;; (let* ((b (find-file-noselect "refinery-theme.el"))
134 ;; (d (with-current-buffer b (package-buffer-info))))
135 ;; (package-generate-description-file d "refinery-theme-pkg.el"))
136 (run-with-idle-timer 0.01 nil
#'require
'package
)
137 (with-eval-after-load 'package
138 (when (= (length package-archives
) 1)
142 ;; ("bndl" . "https://p.bndl.org/elpa/")
143 ("org" .
"https://orgmode.org/elpa/"))
149 (rt-liberation "1.31")
151 (expand-region "0.11.0")
154 ;; (refinery-theme "0.1.1")
156 (org-plus-contrib "20201109"))))
157 (package-initialize))
159 (csetq package-archive-upload-base
"/ssh:caffeine:~/www/p/elpa")
164 ;; keep ~/.emacs.d clean
167 (convert-standard-filename "etc/") user-emacs-directory
)
168 "The directory where packages place their configuration files.")
171 (convert-standard-filename "var/") user-emacs-directory
)
172 "The directory where packages place their persistent data files.")
175 (convert-standard-filename "lisp/") user-emacs-directory
)
176 "The directory where packages place their persistent data files.")
178 "Expand filename FILE relative to `b/etc-dir'."
179 (expand-file-name (convert-standard-filename file
) b
/etc-dir
))
181 "Expand filename FILE relative to `b/var-dir'."
182 (expand-file-name (convert-standard-filename file
) b
/var-dir
))
184 "Expand filename FILE relative to `b/lisp-dir'."
185 (expand-file-name (convert-standard-filename file
) b
/lisp-dir
))
188 auto-save-list-file-prefix
(b/var
"auto-save/sessions/")
189 nsm-settings-file
(b/var
"nsm-settings.el"))
191 ;; separate custom file (don't want it mixing with init.el)
192 (with-eval-after-load 'custom
193 (setq custom-file
(b/etc
"custom.el"))
194 (when (file-exists-p custom-file
)
196 ;; while at it, treat themes as safe
197 ;; (setf custom-safe-themes t)
198 ;; only one custom theme at a time
199 ;; (defadvice load-theme (before clear-previous-themes activate)
200 ;; "Clear existing theme settings instead of layering them"
201 ;; (mapc #'disable-theme custom-enabled-themes))
204 ;; load the secrets file if it exists, otherwise show a warning
205 ;; (with-demoted-errors
206 ;; (load (b/etc "secrets")))
208 ;; start up emacs server. see
209 ;; https://www.gnu.org/software/emacs/manual/html_node/emacs/Emacs-Server.html#Emacs-Server
210 (run-with-idle-timer 0.5 nil
#'require
'server
)
211 (with-eval-after-load 'server
212 (declare-function server-edit
"server")
213 (global-set-key (kbd "C-c F D") #'server-edit
)
214 (declare-function server-running-p
"server")
215 (or (server-running-p) (server-mode)))
220 ;;;; C-level customizations
224 ;; completion case sensitivity
225 completion-ignore-case t
226 read-buffer-completion-ignore-case t
228 enable-recursive-minibuffers t
229 resize-mini-windows t
232 ;; i don't feel like jumping out of my chair every now and again;
233 ;; so...don't *BEEP* at me, emacs =)
234 ring-bell-function
'ignore
236 ;; scroll-conservatively 101
237 scroll-conservatively
15
238 ;; scroll-preserve-screen-position 1
239 ;; focus follows mouse
240 ;; mouse-autoselect-window t
244 ;; case-sensitive search (and `dabbrev-expand')
245 ;; case-fold-search nil
246 ;; always use space for indentation
250 (when (display-graphic-p)
251 (set-fontset-font t
'arabic
"Vazir"))
252 ;; ;; (set-frame-font "Drafting Mono-14:weight=light" nil t)
253 ;; (set-frame-font "Drafting Mono:pixelsize=16" nil t)
254 ;; (set-face-attribute 'bold nil :weight 'semi-bold)
256 ;;;; Elisp-level customizations
258 ;; (define-key minibuffer-local-completion-map
259 ;; "\t" #'minibuffer-force-complete)
261 ;; (with-eval-after-load 'icomplete
263 ;; (setq icomplete-on-del-error-function #'abort-recursive-edit)
265 ;; (defun b/icomplete-fido-backward-updir ()
266 ;; "Delete char before or go up directory, like `ido-mode'."
268 ;; (if (and (eq (char-before) ?/)
269 ;; (eq (icomplete--category) 'file))
271 ;; (goto-char (1- (point)))
272 ;; (when (search-backward "/" (point-min) t)
273 ;; (delete-region (1+ (point)) (point-max))))
274 ;; (condition-case nil
275 ;; (call-interactively #'delete-backward-char)
277 ;; (when icomplete-on-del-error-function
278 ;; (funcall icomplete-on-del-error-function))))))
280 ;; (define-key icomplete-fido-mode-map
281 ;; (kbd "DEL") #'b/icomplete-fido-backward-updir))
283 ;; (with-eval-after-load 'subr
284 ;; (keyboard-translate ?\( ?\[)
285 ;; (keyboard-translate ?\) ?\])
286 ;; (keyboard-translate ?\[ ?\()
287 ;; (keyboard-translate ?\] ?\))
289 ;; ;; (keyboard-translate ?\( ?\()
290 ;; ;; (keyboard-translate ?\) ?\))
291 ;; ;; (keyboard-translate ?\[ ?\[)
292 ;; ;; (keyboard-translate ?\] ?\])
296 (csetq read-file-name-completion-ignore-case t
)
299 ;; don't need to see the startup echo area message
300 (advice-add #'display-startup-echo-area-message
:override
#'ignore
)
302 ;; i want *scratch* as my startup buffer
303 initial-buffer-choice t
304 ;; i don't need the default hint
305 initial-scratch-message nil
306 ;; use customizable text-mode as major mode for *scratch*
307 ;; (initial-major-mode 'text-mode)
308 ;; inhibit buffer list when more than 2 files are loaded
309 inhibit-startup-buffer-menu t
310 ;; don't need to see the startup screen or echo area message
311 inhibit-startup-screen t
312 inhibit-startup-echo-area-message user-login-name
)
316 ;; backups (C-h v make-backup-files RET)
318 backup-directory-alist
(list (cons "." (b/var
"backup/")))
320 delete-old-versions t
322 auto-save-file-name-transforms
`((".*" ,(b/var
"auto-save/") t
))
323 ;; insert newline at the end of files
324 ;; require-final-newline t
325 ;; open read-only file buffers in view-mode
326 ;; (enables niceties like `q' for quit)
330 ;; disable disabled commands
331 (csetq disabled-command-function nil
)
333 ;; lazy-person-friendly yes/no prompts
334 (defalias 'yes-or-no-p
#'y-or-n-p
)
336 ;; autorevert: enable automatic reloading of changed buffers and files
337 (csetq auto-revert-verbose nil
338 global-auto-revert-non-file-buffers nil
)
339 (require 'autorevert
)
340 (global-auto-revert-mode 1)
342 ;; time and battery in mode-line
343 (run-with-idle-timer 0.1 nil
#'require
'time
)
344 (with-eval-after-load 'time
346 display-time-default-load-average nil
347 display-time-format
" %a %b %-e %-l:%M%P"
348 display-time-mail-icon
'(image :type xpm
349 :file
"gnus/gnus-pointer.xpm"
351 display-time-use-mail-icon t
)
354 (run-with-idle-timer 0.1 nil
#'require
'battery
)
355 (with-eval-after-load 'battery
356 (csetq battery-mode-line-format
" %p%% %t")
357 (display-battery-mode))
359 ;; (with-eval-after-load 'fringe
361 ;; (fringe-mode '(3 . 1)))
363 ;; enable winner-mode (C-h f winner-mode RET)
367 (with-eval-after-load 'compile
368 ;; don't display *compilation* buffer on success. based on
369 ;; https://stackoverflow.com/a/17788551, with changes to use `cl-letf'
370 ;; instead of the now obsolete `flet'.
371 (defun b/compilation-finish-function
(buffer outstr
)
372 (unless (string-match "finished" outstr
)
373 (switch-to-buffer-other-window buffer
))
376 (setq compilation-finish-functions
#'b
/compilation-finish-function
)
380 (defadvice compilation-start
381 (around inhibit-display
382 (command &optional mode name-function highlight-regexp
))
383 (if (not (string-match "^\\(find\\|grep\\)" command
))
384 (cl-letf (((symbol-function 'display-buffer
) #'ignore
))
385 (save-window-excursion ad-do-it
))
387 (ad-activate 'compilation-start
))
391 ;; allow scrolling in Isearch
392 isearch-allow-scroll t
394 ;; search for non-ASCII characters: i’d like non-ASCII characters such
395 ;; as ‘’“”«»‹›áⓐ𝒶 to be selected when i search for their ASCII
396 ;; counterpart. shoutout to
397 ;; http://endlessparentheses.com/new-in-emacs-25-1-easily-search-non-ascii-characters.html
398 search-default-mode
#'char-fold-to-regexp
)
401 ;; uncomment to extend the above behaviour to query-replace
402 ;; (csetq replace-char-fold t)
405 (global-set-key (kbd "C-x v C-=") #'vc-ediff
)
407 (with-eval-after-load 'vc-git
408 (csetq vc-git-print-log-follow t
409 vc-git-show-stash
0))
411 (csetq ediff-window-setup-function
'ediff-setup-windows-plain
412 ediff-split-window-function
'split-window-horizontally
)
413 (with-eval-after-load 'ediff
414 (add-hook 'ediff-after-quit-hook-internal
#'winner-undo
))
418 ;; gentler font resizing
419 text-scale-mode-step
1.05)
421 (run-with-idle-timer 0.4 nil
#'require
'mwheel
)
422 (csetq mouse-wheel-scroll-amount
'(1 ((shift) .
1)) ; one line at a time
423 mouse-wheel-progressive-speed nil
; don't accelerate scrolling
424 mouse-wheel-follow-mouse t
) ; scroll window under mouse
426 (run-with-idle-timer 0.4 nil
#'require
'pixel-scroll
)
427 (with-eval-after-load 'pixel-scroll
428 (pixel-scroll-mode 1))
432 epg-gpg-program
(executable-find "gpg")
433 ;; ask for GPG passphrase in minibuffer
434 ;; this will fail if gpg>=2.1 is not available
435 epg-pinentry-mode
'loopback
)
437 ;; (require 'pinentry)
438 ;; workaround for systemd-based distros:
439 ;; (setq pinentry--socket-dir server-socket-dir)
444 auth-sources
'("~/.authinfo.gpg")
445 authinfo-hidden
(regexp-opt '("password" "client-secret" "token")))
448 (with-eval-after-load 'info
452 (convert-standard-filename "info/") source-directory
)))
455 (when (display-graphic-p)
456 (with-eval-after-load 'faces
457 (let* ((grey "#e7e7e7")
458 ;; (darker-grey "#d9d9d9")
459 ;; (box ;; 'unspecified
460 ;; `(;; :line-width -1
461 ;; :style released-button))
463 (set-face-attribute 'mode-line nil
464 :background grey
;; :box box
466 ;; (set-face-attribute 'mode-line-inactive nil
467 ;; :background darker-grey :box box)
473 (defun b/add-elisp-section
()
477 (insert "\n\f\n;;; "))
479 (defun b/insert-asterism
()
480 "Insert a centred asterism."
482 (let ((asterism "* * *"))
487 (floor (/ (- fill-column
(length asterism
)) 2))
492 (defun b/start-process
(program &rest args
)
493 "Same as `start-process', but doesn't bother about name and buffer."
494 (let ((process-name (concat program
"_process"))
495 (buffer-name (generate-new-buffer-name
496 (concat program
"_output"))))
497 (apply #'start-process
498 process-name buffer-name program args
)))
500 (defun b/no-mouse-autoselect-window
()
501 "Conveniently disable `focus-follows-mouse'.
502 For disabling the behaviour for certain buffers and/or modes."
503 (make-local-variable 'mouse-autoselect-window
)
504 (setq mouse-autoselect-window nil
))
506 (defun b/kill-current-buffer
()
507 "Kill the current buffer."
508 ;; also see https://redd.it/64xb3q
510 (kill-buffer (current-buffer)))
512 (defun b/move-indentation-or-beginning-of-line
(arg)
513 "Move to the indentation or to the beginning of line."
516 ;; (back-to-indentation)
517 ;; (move-beginning-of-line arg))
519 (progn (back-to-indentation)
521 (move-beginning-of-line arg
)))
523 (defun b/join-line-top
()
524 "Like `join-line', but join next line to the current line."
528 (defun b/duplicate-line-or-region
(&optional n
)
529 "Duplicate the current line, or region (if active).
530 Make N (default: 1) copies of the current line or region."
532 (let ((u-r-p (use-region-p)) ; if region is active
537 (buffer-substring (region-beginning) (region-end))
538 (prog1 (thing-at-point 'line
)
542 (forward-line 1))))))
543 (dotimes (_ (abs n1
))
547 ;;; General key bindings
549 (global-set-key (kbd "C-a") #'b
/move-indentation-or-beginning-of-line
)
550 (global-set-key (kbd "C-c a i") #'ielm
)
551 (global-set-key (kbd "C-c d") #'b
/duplicate-line-or-region
)
552 (global-set-key (kbd "C-c j") #'b
/join-line-top
)
553 (global-set-key (kbd "C-S-j") #'b
/join-line-top
)
554 (global-set-key (kbd "C-c x") #'execute-extended-command
)
556 ;; evaling and macro-expanding
557 (global-set-key (kbd "C-c e b") #'eval-buffer
)
558 (global-set-key (kbd "C-c e e") #'eval-last-sexp
)
559 (global-set-key (kbd "C-c e m") #'pp-macroexpand-last-sexp
)
560 (global-set-key (kbd "C-c e r") #'eval-region
)
563 (global-set-key (kbd "C-c e i") #'emacs-init-time
)
564 (global-set-key (kbd "C-c e u") #'emacs-uptime
)
565 (global-set-key (kbd "C-c e v") #'emacs-version
)
568 (global-set-key (kbd "C-c f .") #'find-file
)
569 (global-set-key (kbd "C-c f d") #'find-name-dired
)
570 (global-set-key (kbd "C-c f l") #'find-library
)
571 (global-set-key (kbd "C-c f p") #'find-file-at-point
)
574 (global-set-key (kbd "C-c F m") #'make-frame-command
)
575 (global-set-key (kbd "C-c F d") #'delete-frame
)
578 (global-set-key (kbd "C-S-h F") #'describe-face
)
580 ;; (global-set-key (kbd "C-x k") #'b/kill-current-buffer)
581 ;; (global-set-key (kbd "C-x K") #'kill-buffer)
583 (define-key emacs-lisp-mode-map
(kbd "C-<return>") #'b
/add-elisp-section
)
585 (when (display-graphic-p)
586 (global-unset-key (kbd "C-z")))
589 ;;; Essential packages
594 (convert-standard-filename "lisp") user-emacs-directory
))
596 ;; (require 'bandali-exwm)
598 (require 'bandali-org
)
600 ;; (require 'bandali-theme)
602 ;; recently opened files
603 (csetq recentf-max-saved-items
2000
604 recentf-save-file
(b/var
"recentf-save.el"))
605 (run-with-idle-timer 0.2 nil
#'require
'recentf
)
606 (with-eval-after-load 'recentf
607 ;; (add-to-list 'recentf-keep #'file-remote-p)
610 (defun b/recentf-open
()
611 "Use `completing-read' to \\[find-file] a recent file."
614 (completing-read "Find recent file: " recentf-list
)))
615 (global-set-key (kbd "C-c f r") #'b
/recentf-open
))
618 ;; (defun b/icomplete--fido-mode-setup ()
619 ;; "Customizations to `fido-mode''s minibuffer."
620 ;; (when (and icomplete-mode (icomplete-simple-completing-p))
622 ;; ;; icomplete-compute-delay 0.1
623 ;; ;; icomplete-hide-common-prefix t
624 ;; icomplete-separator " · "
625 ;; completion-styles '(basic substring partial-completion flex))))
626 ;; (add-hook 'minibuffer-setup-hook #'b/icomplete--fido-mode-setup 1)
628 (require 'bandali-eshell
)
630 (require 'bandali-ibuffer
)
632 (require 'bandali-dired
)
634 (with-eval-after-load 'help
635 (temp-buffer-resize-mode)
636 (csetq help-window-select t
))
638 (with-eval-after-load 'help-mode
639 ;; local key bindings
640 (define-key help-mode-map
(kbd "p") #'backward-button
)
641 (define-key help-mode-map
(kbd "n") #'forward-button
))
643 (with-eval-after-load 'tramp
644 (csetq tramp-auto-save-directory
(b/var
"tramp/auto-save/")
645 tramp-persistency-file-name
(b/var
"tramp/persistency.el"))
646 (add-to-list 'tramp-default-proxies-alist
'(nil "\\`root\\'" "/ssh:%h:"))
647 (add-to-list 'tramp-default-proxies-alist
'("localhost" nil nil
))
648 (add-to-list 'tramp-default-proxies-alist
649 (list (regexp-quote (system-name)) nil nil
)))
651 (with-eval-after-load 'doc-view
652 (define-key doc-view-mode-map
(kbd "M-RET") #'image-previous-line
))
654 (csetq shr-max-width
80)
656 ;; Email (with Gnus, message, and smtpmail)
657 (require 'bandali-gnus
)
658 (require 'bandali-message
)
659 ;; (with-eval-after-load 'smtpmail
660 ;; (csetq smtpmail-queue-mail t
661 ;; smtpmail-queue-dir (concat b/maildir "queue/")))
664 (require 'bandali-erc
)
666 ;; 'paste' service (aka scp + web server)
667 (add-to-list 'load-path
(b/lisp
"scpaste"))
668 (with-eval-after-load 'scpaste
669 (csetq scpaste-http-destination
"https://p.bndl.org"
670 scpaste-scp-destination
"p:~"))
671 (autoload 'scpaste
"scpaste" nil t
)
672 (autoload 'scpaste-region
"scpaste" nil t
)
673 (global-set-key (kbd "C-c a p p") #'scpaste
)
674 (global-set-key (kbd "C-c a p r") #'scpaste-region
)
679 ;; display Lisp objects at point in the echo area
680 (when (version< "25" emacs-version
)
681 (with-eval-after-load 'eldoc
682 (csetq eldoc-minor-mode-string
" eldoc")
683 (global-eldoc-mode)))
685 ;; highlight matching parens
689 ;; (require 'elec-pair)
690 ;; (electric-pair-mode)
693 ;; Save what I copy into clipboard from other applications into Emacs'
694 ;; kill-ring, which would allow me to still be able to easily access
695 ;; it in case I kill (cut or copy) something else inside Emacs before
696 ;; yanking (pasting) what I'd originally intended to.
697 save-interprogram-paste-before-kill t
)
698 (with-eval-after-load 'simple
699 (column-number-mode 1)
700 (line-number-mode 1))
702 ;; save minibuffer history
704 (csetq savehist-file
(b/var
"savehist.el"))
706 (add-to-list 'savehist-additional-variables
'kill-ring
)
708 ;; automatically save place in files
709 (when (version< "25" emacs-version
)
710 (csetq save-place-file
(b/var
"save-place.el"))
713 (defun indicate-buffer-boundaries-left ()
714 (csetq indicate-buffer-boundaries
'left
))
715 (with-eval-after-load 'prog-mode
716 (global-prettify-symbols-mode))
717 (add-hook 'prog-mode-hook
#'indicate-buffer-boundaries-left
)
719 (define-key text-mode-map
(kbd "C-<return>") #'b
/insert-asterism
)
720 (add-hook 'text-mode-hook
#'indicate-buffer-boundaries-left
)
721 (add-hook 'text-mode-hook
#'flyspell-mode
)
723 (add-to-list 'auto-mode-alist
'("\\.*rc$" . conf-mode
))
725 (add-to-list 'auto-mode-alist
'("\\.bashrc$" . sh-mode
))
727 (with-eval-after-load 'flyspell
728 (csetq flyspell-mode-line-string
" fly"))
731 ;; http://endlessparentheses.com/ispell-and-apostrophes.html
732 ;; (run-with-idle-timer 0.6 nil #'require 'ispell)
733 ;; (with-eval-after-load 'ispell
734 ;; ;; ’ can be part of a word
735 ;; (csetq ispell-local-dictionary-alist
736 ;; `((nil "[[:alpha:]]" "[^[:alpha:]]"
737 ;; "['\x2019]" nil ("-B") nil utf-8))
738 ;; ispell-program-name (executable-find "hunspell"))
739 ;; ;; don't send ’ to the subprocess
740 ;; (defun endless/replace-apostrophe (args)
741 ;; (cons (replace-regexp-in-string
742 ;; "’" "'" (car args))
744 ;; (advice-add #'ispell-send-string :filter-args
745 ;; #'endless/replace-apostrophe)
746 ;; ;; convert ' back to ’ from the subprocess
747 ;; (defun endless/replace-quote (args)
748 ;; (if (not (derived-mode-p 'org-mode))
750 ;; (cons (replace-regexp-in-string
751 ;; "'" "’" (car args))
753 ;; (advice-add #'ispell-parse-output :filter-args
754 ;; #'endless/replace-quote))
757 (csetq abbrev-file-name
(b/etc
"abbrev.el"))
758 (add-hook 'text-mode-hook
#'abbrev-mode
)
761 ;;; Programming modes
763 (with-eval-after-load 'lisp-mode
764 (defun indent-spaces-mode ()
765 (setq indent-tabs-mode nil
))
766 (add-hook 'lisp-interaction-mode-hook
#'indent-spaces-mode
))
769 (add-to-list 'load-path
(b/lisp
"alloy-mode"))
770 (autoload 'alloy-mode
"alloy-mode" nil t
)
771 (with-eval-after-load 'alloy-mode
772 (csetq alloy-basic-offset
2)
773 ;; (defun b/alloy-simple-indent (start end)
775 ;; ;; (if (region-active-p)
776 ;; ;; (indent-rigidly start end alloy-basic-offset)
778 ;; ;; (indent-rigidly (line-beginning-position)
779 ;; ;; (line-end-position)
780 ;; ;; alloy-basic-offset)))
781 ;; (indent-to (+ (current-column) alloy-basic-offset)))
782 ;; local key bindings
783 (define-key alloy-mode-map
(kbd "RET") #'electric-newline-and-maybe-indent
)
784 ;; (define-key alloy-mode-map (kbd "TAB") #'b/alloy-simple-indent)
785 (define-key alloy-mode-map
(kbd "TAB") #'indent-for-tab-command
))
786 (add-to-list 'auto-mode-alist
'("\\.\\(als\\|dsh\\)\\'" . alloy-mode
))
787 (add-hook 'alloy-mode-hook
(lambda nil
(setq-local indent-tabs-mode nil
)))
790 ;; (eval-when-compile (defvar lean-mode-map))
791 ;; (run-with-idle-timer 0.4 nil #'require 'lean-mode)
792 ;; (with-eval-after-load 'lean-mode
793 ;; (require 'lean-input)
794 ;; (csetq default-input-method "Lean"
795 ;; lean-input-tweak-all '(lean-input-compose
796 ;; (lean-input-prepend "/")
797 ;; (lean-input-nonempty))
798 ;; lean-input-user-translations '(("/" "/")))
799 ;; (lean-input-setup)
800 ;; ;; local key bindings
801 ;; (define-key lean-mode-map (kbd "S-SPC") #'company-complete))
803 (with-eval-after-load 'sgml-mode
804 (csetq sgml-basic-offset
0))
806 (with-eval-after-load 'css-mode
807 (csetq css-indent-offset
2))
810 ;; (csetq font-latex-fontify-sectioning 'color)
812 (with-eval-after-load 'tex-mode
814 (lambda (p) (string-match "^---?" (car p
)))
815 tex--prettify-symbols-alist
))
816 (add-hook 'tex-mode-hook
#'auto-fill-mode
)
817 (add-hook 'tex-mode-hook
#'flyspell-mode
)
820 ;;; Emacs enhancements & auxiliary packages
822 (with-eval-after-load 'man
823 (csetq Man-width
80))
825 (defun b/*scratch
* ()
826 "Switch to `*scratch*' buffer, creating it if it does not exist."
829 (or (get-buffer "*scratch*")
830 (with-current-buffer (get-buffer-create "*scratch*")
831 (set-buffer-major-mode (current-buffer))
833 (global-set-key (kbd "C-c s") #'b
/*scratch
*)
836 ;; | make pretty boxed quotes like this
838 (add-to-list 'load-path
(b/lisp
"boxquote"))
839 (run-with-idle-timer 0.6 nil
#'require
'boxquote
)
840 (with-eval-after-load 'boxquote
841 (defvar b
/boxquote-prefix-map
)
842 (define-prefix-command 'b
/boxquote-prefix-map
)
843 (global-set-key (kbd "C-c q") 'b
/boxquote-prefix-map
)
844 (define-key b
/boxquote-prefix-map
(kbd "b") #'boxquote-buffer
)
845 (define-key b
/boxquote-prefix-map
(kbd "B") #'boxquote-insert-buffer
)
846 (define-key b
/boxquote-prefix-map
(kbd "d") #'boxquote-defun
)
847 (define-key b
/boxquote-prefix-map
(kbd "F") #'boxquote-insert-file
)
848 (define-key b
/boxquote-prefix-map
(kbd "hf") #'boxquote-describe-function
)
849 (define-key b
/boxquote-prefix-map
(kbd "hk") #'boxquote-describe-key
)
850 (define-key b
/boxquote-prefix-map
(kbd "hv") #'boxquote-describe-variable
)
851 (define-key b
/boxquote-prefix-map
(kbd "hw") #'boxquote-where-is
)
852 (define-key b
/boxquote-prefix-map
(kbd "k") #'boxquote-kill
)
853 (define-key b
/boxquote-prefix-map
(kbd "p") #'boxquote-paragraph
)
854 (define-key b
/boxquote-prefix-map
(kbd "q") #'boxquote-boxquote
)
855 (define-key b
/boxquote-prefix-map
(kbd "r") #'boxquote-region
)
856 (define-key b
/boxquote-prefix-map
(kbd "s") #'boxquote-shell-command
)
857 (define-key b
/boxquote-prefix-map
(kbd "t") #'boxquote-text
)
858 (define-key b
/boxquote-prefix-map
(kbd "T") #'boxquote-title
)
859 (define-key b
/boxquote-prefix-map
(kbd "u") #'boxquote-unbox
)
860 (define-key b
/boxquote-prefix-map
(kbd "U") #'boxquote-unbox-region
)
861 (define-key b
/boxquote-prefix-map
(kbd "y") #'boxquote-yank
)
862 (define-key b
/boxquote-prefix-map
(kbd "M-q") #'boxquote-fill-paragraph
)
863 (define-key b
/boxquote-prefix-map
(kbd "M-w") #'boxquote-kill-ring-save
))
865 (add-to-list 'load-path
(b/lisp
"hl-todo"))
866 (run-with-idle-timer 0.5 nil
#'require
'hl-todo
)
867 (with-eval-after-load 'hl-todo
868 ;; highlight TODOs in buffers
869 (global-hl-todo-mode))
872 (global-set-key (kbd "C-=") #'er
/expand-region
)
874 (run-with-idle-timer 0.6 nil
#'require
'yasnippet
)
875 (with-eval-after-load 'yasnippet
876 (declare-function yas-reload-all
877 "yasnippet" (&optional no-jit interactive
))
878 (declare-function yas-maybe-expand-abbrev-key-filter
881 (defconst yas-verbosity-cur yas-verbosity
)
882 (setq yas-verbosity
2)
883 (csetq yas-snippet-dirs
`(,(b/etc
"yasnippet/snippets")))
884 ;; (add-to-list 'yas-snippet-dirs "~/src/git/guix/etc/snippets" t)
886 (setq yas-verbosity yas-verbosity-cur
)
888 (defun b/yas-maybe-expand-abbrev-key-filter
(cmd)
889 (when (and (yas-maybe-expand-abbrev-key-filter cmd
)
890 (not (bound-and-true-p git-commit-mode
)))
892 (defconst b
/yas-maybe-expand
893 '(menu-item "" yas-expand
894 :filter b
/yas-maybe-expand-abbrev-key-filter
))
895 (define-key yas-minor-mode-map
(kbd "SPC") b
/yas-maybe-expand
)
900 (global-set-key (kbd "C-c D d") #'debbugs-gnu
)
901 (global-set-key (kbd "C-c D b") #'debbugs-gnu-bugs
)
902 (global-set-key (kbd "C-c D e") ; bug-gnu-emacs
905 (setq debbugs-gnu-current-suppress t
)
906 (debbugs-gnu debbugs-gnu-default-severities
908 (global-set-key (kbd "C-c D g") ; bug-gnuzilla
911 (setq debbugs-gnu-current-suppress t
)
912 (debbugs-gnu debbugs-gnu-default-severities
917 url-configuration-directory
(b/var
"url/configuration/")
918 url-cache-directory
(b/var
"url/cache/"))
921 (csetq eww-download-directory
(file-name-as-directory
922 (getenv "XDG_DOWNLOAD_DIR")))
923 (global-set-key (kbd "C-c a e w") #'eww
)
927 ;; reftex-default-bibliography '("~/usr/org/references.bib")
928 ;; org-ref-default-bibliography '("~/usr/org/references.bib")
929 ;; org-ref-bibliography-notes "~/usr/org/notes.org"
930 ;; org-ref-pdf-directory "~/usr/org/bibtex-pdfs/")
932 ;; fill-column-indicator ?
935 (csetq split-width-threshold
150)
936 (global-set-key (kbd "C-c w s l")
941 (global-set-key (kbd "C-c w s j")
946 (global-set-key (kbd "C-c w q") #'quit-window
)
949 ;; (global-set-key (kbd "C-c a p") #'pass)
950 ;; (add-hook 'pass-mode-hook #'View-exit)
953 ;; uncomment to disable reftex-cite's default choice of previous word
954 ;; (with-eval-after-load 'reftex
955 ;; (require 'reftex-cite)
956 ;; (defun reftex-get-bibkey-default ()
957 ;; "If the cursor is in a citation macro, return the word before the macro."
958 ;; (let* ((macro (reftex-what-macro 1)))
960 ;; (when (and macro (string-match "cite" (car macro)))
961 ;; (goto-char (cdr macro)))
962 ;; (reftex-this-word)))))
963 (add-hook 'latex-mode-hook
#'reftex-mode
)
966 (add-to-list 'load-path
(b/lisp
"dmenu"))
967 (with-eval-after-load 'dmenu
968 (csetq dmenu-prompt-string
"run: "
969 dmenu-save-file
(b/var
"dmenu-items")))
970 (autoload 'dmenu
"dmenu" nil t
)
975 (run-with-idle-timer 0.5 nil
#'require
'delight
)
976 (with-eval-after-load 'delight
977 (delight 'auto-fill-function
" f" "simple")
978 (delight 'abbrev-mode
"" "abbrev")
979 (delight 'mml-mode
" mml" "mml")
980 (delight 'yas-minor-mode
"" "yasnippet"))
983 (require 'bandali-po
)
986 ;;; Post initialization
988 (message "Loading %s...done (%.3fs)" user-init-file
989 (float-time (time-subtract (current-time)
990 b
/before-user-init-time
)))
992 ;;; init.el ends here