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/"))
152 (rt-liberation "1.31")
154 (expand-region "0.11.0")
157 ;; (refinery-theme "0.1.1")
159 (org-plus-contrib "20201109"))))
160 (package-initialize))
162 (csetq package-archive-upload-base
"/ssh:caffeine:~/www/p/elpa")
167 ;; keep ~/.emacs.d clean
170 (convert-standard-filename "etc/") user-emacs-directory
)
171 "The directory where packages place their configuration files.")
174 (convert-standard-filename "var/") user-emacs-directory
)
175 "The directory where packages place their persistent data files.")
178 (convert-standard-filename "lisp/") user-emacs-directory
)
179 "The directory where packages place their persistent data files.")
181 "Expand filename FILE relative to `b/etc-dir'."
182 (expand-file-name (convert-standard-filename file
) b
/etc-dir
))
184 "Expand filename FILE relative to `b/var-dir'."
185 (expand-file-name (convert-standard-filename file
) b
/var-dir
))
187 "Expand filename FILE relative to `b/lisp-dir'."
188 (expand-file-name (convert-standard-filename file
) b
/lisp-dir
))
191 auto-save-list-file-prefix
(b/var
"auto-save/sessions/")
192 nsm-settings-file
(b/var
"nsm-settings.el"))
194 ;; separate custom file (don't want it mixing with init.el)
195 (with-eval-after-load 'custom
196 (setq custom-file
(b/etc
"custom.el"))
197 (when (file-exists-p custom-file
)
199 ;; while at it, treat themes as safe
200 ;; (setf custom-safe-themes t)
201 ;; only one custom theme at a time
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))
207 ;; load the secrets file if it exists, otherwise show a warning
208 ;; (with-demoted-errors
209 ;; (load (b/etc "secrets")))
211 ;; start up emacs server. see
212 ;; https://www.gnu.org/software/emacs/manual/html_node/emacs/Emacs-Server.html#Emacs-Server
213 (run-with-idle-timer 0.5 nil
#'require
'server
)
214 (with-eval-after-load 'server
215 (declare-function server-edit
"server")
216 (global-set-key (kbd "C-c F D") #'server-edit
)
217 (declare-function server-running-p
"server")
218 (or (server-running-p) (server-mode)))
223 ;;;; C-level customizations
227 enable-recursive-minibuffers t
228 resize-mini-windows t
229 ;; more useful frame titles
230 ;; frame-title-format '("" invocation-name " - "
232 ;; (if (buffer-file-name)
233 ;; (abbreviate-file-name (buffer-file-name))
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
240 ;; scroll-conservatively 10000
242 scroll-conservatively
101
243 scroll-preserve-screen-position
1
244 ;; focus follows mouse
245 mouse-autoselect-window t
)
248 ;; always use space for indentation
251 ;; case-sensitive search (and `dabbrev-expand')
252 ;; case-fold-search nil
256 (set-fontset-font t
'arabic
"Vazir")
259 ;; (dolist (ft (fontset-list))
263 ;; (font-spec :name "Source Code Pro" :size 14))
267 ;; (font-spec :name "DejaVu Sans Mono")
270 ;; ;; (set-fontset-font
274 ;; ;; :name "Symbola monospacified for DejaVu Sans Mono")
277 ;; ;; (set-fontset-font
280 ;; ;; (font-spec :name "DejaVu Sans Mono")
286 ;; (font-spec :name "DejaVu Sans Mono" :size 14)
290 ;;;; Elisp-level customizations
292 ;; (define-key minibuffer-local-completion-map
293 ;; "\t" #'minibuffer-force-complete)
295 (with-eval-after-load 'icomplete
297 (setq icomplete-on-del-error-function
#'abort-recursive-edit
)
299 (defun b/icomplete-fido-backward-updir
()
300 "Delete char before or go up directory, like `ido-mode'."
302 (if (and (eq (char-before) ?
/)
303 (eq (icomplete--category) 'file
))
305 (goto-char (1- (point)))
306 (when (search-backward "/" (point-min) t
)
307 (delete-region (1+ (point)) (point-max))))
309 (call-interactively #'delete-backward-char
)
311 (when icomplete-on-del-error-function
312 (funcall icomplete-on-del-error-function
))))))
314 (define-key icomplete-fido-mode-map
315 (kbd "DEL") #'b
/icomplete-fido-backward-updir
))
318 ;; don't need to see the startup echo area message
319 (advice-add #'display-startup-echo-area-message
:override
#'ignore
)
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
)
335 ;; backups (C-h v make-backup-files RET)
337 backup-directory-alist
(list (cons "." (b/var
"backup/")))
339 delete-old-versions t
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)
349 ;; disable disabled commands
350 (csetq disabled-command-function nil
)
352 ;; lazy-person-friendly yes/no prompts
353 (defalias 'yes-or-no-p
#'y-or-n-p
)
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)
361 ;; time and battery in mode-line
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"
368 display-time-use-mail-icon t
)
372 (csetq battery-mode-line-format
" %p%% %t")
374 (display-battery-mode)
378 ;; (fringe-mode '(3 . 1))
382 ;; enable winner-mode (C-h f winner-mode RET)
385 (with-eval-after-load 'compile
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'.
389 (defun b/compilation-finish-function
(buffer outstr
)
390 (unless (string-match "finished" outstr
)
391 (switch-to-buffer-other-window buffer
))
394 (setq compilation-finish-functions
#'b
/compilation-finish-function
)
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
))
405 (ad-activate 'compilation-start
))
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
)
418 ;; uncomment to extend the above behaviour to query-replace
419 ;; (csetq replace-char-fold t)
422 (global-set-key (kbd "C-x v C-=") #'vc-ediff
)
424 (with-eval-after-load 'vc-git
425 (csetq vc-git-print-log-follow t
426 vc-git-show-stash
0))
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
))
435 ;; gentler font resizing
436 text-scale-mode-step
1.05)
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
443 (run-with-idle-timer 0.4 nil
#'require
'pixel-scroll
)
444 (with-eval-after-load 'pixel-scroll
445 (pixel-scroll-mode 1))
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
)
454 ;; (require 'pinentry)
455 ;; workaround for systemd-based distros:
456 ;; (setq pinentry--socket-dir server-socket-dir)
461 auth-sources
'("~/.authinfo.gpg")
462 authinfo-hidden
(regexp-opt '("password" "client-secret" "token")))
467 (defun b/add-elisp-section
()
471 (insert "\n\f\n;;; "))
473 (defun b/insert-asterism
()
474 "Insert a centred asterism."
476 (let ((asterism "* * *"))
481 (floor (/ (- fill-column
(length asterism
)) 2))
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
)))
494 (defun b/no-mouse-autoselect-window
()
495 "Conveniently disable `focus-follows-mouse'.
496 For disabling the behaviour for certain buffers and/or modes."
497 (make-local-variable 'mouse-autoselect-window
)
498 (setq mouse-autoselect-window nil
))
500 (defun b/kill-current-buffer
()
501 "Kill the current buffer."
502 ;; also see https://redd.it/64xb3q
504 (kill-buffer (current-buffer)))
506 (defun b/move-indentation-or-beginning-of-line
(arg)
507 "Move to the indentation or to the beginning of line."
510 ;; (back-to-indentation)
511 ;; (move-beginning-of-line arg))
513 (progn (back-to-indentation)
515 (move-beginning-of-line arg
)))
517 (defun b/join-line-top
()
518 "Like `join-line', but join next line to the current line."
522 (defun b/duplicate-line-or-region
(&optional n
)
523 "Duplicate the current line, or region (if active).
524 Make N (default: 1) copies of the current line or region."
526 (let ((u-r-p (use-region-p)) ; if region is active
531 (buffer-substring (region-beginning) (region-end))
532 (prog1 (thing-at-point 'line
)
536 (forward-line 1))))))
537 (dotimes (_ (abs n1
))
541 ;;; General key bindings
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
)
546 (global-set-key (kbd "C-c j") #'b
/join-line-top
)
547 (global-set-key (kbd "C-S-j") #'b
/join-line-top
)
548 (global-set-key (kbd "C-c x") #'execute-extended-command
)
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
)
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
)
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
)
567 (global-set-key (kbd "C-c F m") #'make-frame-command
)
568 (global-set-key (kbd "C-c F d") #'delete-frame
)
571 (global-set-key (kbd "C-S-h C") #'describe-char
)
572 (global-set-key (kbd "C-S-h F") #'describe-face
)
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)
579 (define-key emacs-lisp-mode-map
(kbd "<C-return>") #'b
/add-elisp-section
)
581 (when (display-graphic-p)
582 (global-unset-key (kbd "C-z")))
585 ;;; Essential packages
590 (convert-standard-filename "lisp") user-emacs-directory
))
592 (when (featurep 'exwm
)
593 (require 'bandali-exwm
))
595 (require 'bandali-org
)
597 (require 'bandali-theme
)
599 ;; recently opened files
600 (csetq recentf-max-saved-items
2000
601 recentf-save-file
(b/var
"recentf-save.el"))
602 (run-with-idle-timer 0.2 nil
#'require
'recentf
)
603 (with-eval-after-load 'recentf
604 ;; (add-to-list 'recentf-keep #'file-remote-p)
609 (require 'bandali-eshell
)
611 (require 'bandali-ibuffer
)
614 ;; (with-eval-after-load 'outline
615 ;; (when (featurep 'which-key)
616 ;; (which-key-add-key-based-replacements
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)
643 (require 'bandali-dired
)
645 (with-eval-after-load 'help
646 (temp-buffer-resize-mode)
647 (csetq help-window-select t
))
649 (with-eval-after-load 'help-mode
650 ;; local key bindings
651 (define-key help-mode-map
(kbd "p") #'backward-button
)
652 (define-key help-mode-map
(kbd "n") #'forward-button
))
654 (with-eval-after-load 'tramp
655 (csetq tramp-auto-save-directory
(b/var
"tramp/auto-save/")
656 tramp-persistency-file-name
(b/var
"tramp/persistency.el"))
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
)))
662 (with-eval-after-load 'doc-view
663 (define-key doc-view-mode-map
(kbd "M-RET") #'image-previous-line
))
665 (csetq shr-max-width
80)
667 ;; Email (with Gnus, message, and EBDB)
668 (require 'bandali-gnus
)
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
))
674 (require 'bandali-message
)
675 (require 'bandali-ebdb
)
678 (require 'bandali-erc
)
680 ;; 'paste' service (aka scp + web server)
681 (add-to-list 'load-path
(b/lisp
"scpaste"))
682 (with-eval-after-load 'scpaste
683 (csetq scpaste-http-destination
"https://p.bndl.org"
684 scpaste-scp-destination
"p:~"))
685 (autoload 'scpaste
"scpaste" nil t
)
686 (autoload 'scpaste-region
"scpaste" nil t
)
687 (global-set-key (kbd "C-c a p p") #'scpaste
)
688 (global-set-key (kbd "C-c a p r") #'scpaste-region
)
693 ;; display Lisp objects at point in the echo area
694 (when (version< "25" emacs-version
)
695 (with-eval-after-load 'eldoc
696 (csetq eldoc-minor-mode-string
" eldoc")
697 (global-eldoc-mode)))
699 ;; highlight matching parens
703 ;; (require 'elec-pair)
704 ;; (electric-pair-mode)
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
713 (column-number-mode 1))
715 ;; save minibuffer history
717 (csetq savehist-file
(b/var
"savehist.el"))
719 (add-to-list 'savehist-additional-variables
'kill-ring
)
721 ;; automatically save place in files
722 (when (version< "25" emacs-version
)
723 (csetq save-place-file
(b/var
"save-place.el"))
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
)
732 (define-key text-mode-map
(kbd "C-<return>") #'b
/insert-asterism
)
733 (add-hook 'text-mode-hook
#'indicate-buffer-boundaries-left
)
734 (add-hook 'text-mode-hook
#'flyspell-mode
)
736 (add-to-list 'auto-mode-alist
'("\\.*rc$" . conf-mode
))
738 (add-to-list 'auto-mode-alist
'("\\.bashrc$" . sh-mode
))
740 (with-eval-after-load 'flyspell
741 (csetq flyspell-mode-line-string
" fly"))
744 ;; (run-with-idle-timer 0.6 nil #'require 'flycheck)
745 ;; (with-eval-after-load 'flycheck
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)
757 ;; http://endlessparentheses.com/ispell-and-apostrophes.html
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))
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))
776 ;; (cons (replace-regexp-in-string
777 ;; "'" "’" (car args))
779 ;; (advice-add #'ispell-parse-output :filter-args
780 ;; #'endless/replace-quote))
783 (csetq abbrev-file-name
(b/etc
"abbrev.el"))
784 (add-hook 'text-mode-hook
#'abbrev-mode
)
787 ;;; Programming modes
789 (with-eval-after-load 'lisp-mode
790 (defun indent-spaces-mode ()
791 (setq indent-tabs-mode nil
))
792 (add-hook 'lisp-interaction-mode-hook
#'indent-spaces-mode
))
795 (add-to-list 'load-path
(b/lisp
"alloy-mode"))
796 (autoload 'alloy-mode
"alloy-mode" nil t
)
797 (with-eval-after-load 'alloy-mode
798 (csetq alloy-basic-offset
2)
799 ;; (defun b/alloy-simple-indent (start end)
801 ;; ;; (if (region-active-p)
802 ;; ;; (indent-rigidly start end alloy-basic-offset)
804 ;; ;; (indent-rigidly (line-beginning-position)
805 ;; ;; (line-end-position)
806 ;; ;; alloy-basic-offset)))
807 ;; (indent-to (+ (current-column) alloy-basic-offset)))
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
)))
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))
829 (with-eval-after-load 'sgml-mode
830 (csetq sgml-basic-offset
0))
832 (with-eval-after-load 'css-mode
833 (csetq css-indent-offset
2))
836 ;; (add-hook 'po-mode-hook (lambda nil (run-with-timer 0.1 nil 'View-exit)))
839 ;; (csetq font-latex-fontify-sectioning 'color)
841 (with-eval-after-load 'tex-mode
843 (lambda (p) (string-match "^---?" (car p
)))
844 tex--prettify-symbols-alist
))
845 (add-hook 'tex-mode-hook
#'auto-fill-mode
)
846 (add-hook 'tex-mode-hook
#'flyspell-mode
)
849 ;;; Emacs enhancements & auxiliary packages
851 (with-eval-after-load 'man
852 (csetq Man-width
80))
854 (defun b/*scratch
* ()
855 "Switch to `*scratch*' buffer, creating it if it does not exist."
858 (or (get-buffer "*scratch*")
859 (with-current-buffer (get-buffer-create "*scratch*")
860 (set-buffer-major-mode (current-buffer))
862 (global-set-key (kbd "C-c s") #'b
/*scratch
*)
865 ;; | make pretty boxed quotes like this
867 (add-to-list 'load-path
(b/lisp
"boxquote"))
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
))
894 (add-to-list 'load-path
(b/lisp
"hl-todo"))
895 (run-with-idle-timer 0.5 nil
#'require
'hl-todo
)
896 (with-eval-after-load 'hl-todo
897 ;; highlight TODOs in buffers
898 (global-hl-todo-mode))
900 (add-to-list 'load-path
(b/lisp
"page-break-lines"))
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
)
904 (global-page-break-lines-mode))
907 (global-set-key (kbd "C-=") #'er
/expand-region
)
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
916 (defconst yas-verbosity-cur yas-verbosity
)
917 (setq yas-verbosity
2)
918 (csetq yas-snippet-dirs
`(,(b/etc
"yasnippet/snippets")))
919 ;; (add-to-list 'yas-snippet-dirs "~/src/git/guix/etc/snippets" t)
921 (setq yas-verbosity yas-verbosity-cur
)
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
)))
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
)
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
940 (setq debbugs-gnu-current-suppress t
)
941 (debbugs-gnu debbugs-gnu-default-severities
943 (global-set-key (kbd "C-c D g") ; bug-gnuzilla
946 (setq debbugs-gnu-current-suppress t
)
947 (debbugs-gnu debbugs-gnu-default-severities
949 (global-set-key (kbd "C-c D G b") ; bug-guix
952 (setq debbugs-gnu-current-suppress t
)
953 (debbugs-gnu debbugs-gnu-default-severities
955 (global-set-key (kbd "C-c D G p") ; guix-patches
958 (setq debbugs-gnu-current-suppress t
)
959 (debbugs-gnu debbugs-gnu-default-severities
964 url-configuration-directory
(b/var
"url/configuration/")
965 url-cache-directory
(b/var
"url/cache/"))
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
)
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/")
979 ;; fill-column-indicator ?
982 (csetq split-width-threshold
150)
983 (global-set-key (kbd "C-c w s l")
988 (global-set-key (kbd "C-c w s j")
993 (global-set-key (kbd "C-c w q") #'quit-window
)
996 ;; (global-set-key (kbd "C-c a p") #'pass)
997 ;; (add-hook 'pass-mode-hook #'View-exit)
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)))
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
)
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
)
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")
1027 (delight 'mml-mode
" mml" "mml")
1028 (delight 'yas-minor-mode
"" "yasnippet"))
1031 ;;; Post initialization
1033 (message "Loading %s...done (%.3fs)" user-init-file
1034 (float-time (time-subtract (current-time)
1035 b
/before-user-init-time
)))
1037 ;;; init.el ends here