;;; init.el --- bandali's emacs configuration -*- lexical-binding: t -*- ;; Copyright (C) 2018-2020 Amin Bandali ;; This program is free software: you can redistribute it and/or modify ;; it under the terms of the GNU General Public License as published by ;; the Free Software Foundation, either version 3 of the License, or ;; (at your option) any later version. ;; This program is distributed in the hope that it will be useful, ;; but WITHOUT ANY WARRANTY; without even the implied warranty of ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ;; GNU General Public License for more details. ;; You should have received a copy of the GNU General Public License ;; along with this program. If not, see . ;;; Commentary: ;; GNU Emacs configuration of Amin Bandali, computer scientist, ;; Free Software activist, and GNU maintainer & webmaster. Packages ;; are installed through using Borg for a fully reproducible setup. ;; Over the years, I've taken inspiration from configurations of many ;; great people. Some that I can remember off the top of my head are: ;; ;; - https://github.com/dieggsy/dotfiles ;; - https://github.com/dakra/dmacs ;; - http://pages.sachachua.com/.emacs.d/Sacha.html ;; - https://github.com/dakrone/eos ;; - http://doc.rix.si/cce/cce.html ;; - https://github.com/jwiegley/dot-emacs ;; - https://github.com/wasamasa/dotemacs ;; - https://github.com/hlissner/doom-emacs ;;; Code: ;;; Emacs initialization (defvar b/before-user-init-time (current-time) "Value of `current-time' when Emacs begins loading `user-init-file'.") (defvar b/emacs-initialized nil "Whether Emacs has been initialized.") (when (not (bound-and-true-p b/emacs-initialized)) (message "Loading Emacs...done (%.3fs)" (float-time (time-subtract b/before-user-init-time before-init-time)))) ;; temporarily increase `gc-cons-threshhold' and `gc-cons-percentage' ;; during startup to reduce garbage collection frequency. clearing ;; `file-name-handler-alist' seems to help reduce startup time too. (defvar b/gc-cons-threshold gc-cons-threshold) (defvar b/gc-cons-percentage gc-cons-percentage) (defvar b/file-name-handler-alist file-name-handler-alist) (setq gc-cons-threshold (* 30 1024 1024) ; 30 MiB gc-cons-percentage 0.6 file-name-handler-alist nil ;; sidesteps a bug when profiling with esup esup-child-profile-require-level 0) ;; set them back to their defaults once we're done initializing (defun b/post-init () "My post-initialize function, run after loading `user-init-file'." (setq b/emacs-initialized t gc-cons-threshold b/gc-cons-threshold gc-cons-percentage b/gc-cons-percentage file-name-handler-alist b/file-name-handler-alist) (when (featurep 'exwm-workspace) (with-eval-after-load 'exwm-workspace (setq-default mode-line-format (append mode-line-format '((:eval (format "[%s]" (number-to-string exwm-workspace-current-index))))))))) (add-hook 'after-init-hook #'b/post-init) ;; increase number of lines kept in *Messages* log (setq message-log-max 20000) ;; optionally, uncomment to supress some byte-compiler warnings ;; (see C-h v byte-compile-warnings RET for more info) ;; (setq byte-compile-warnings ;; '(not free-vars unresolved noruntime lexical make-local)) ;;; whoami (setq user-full-name "Amin Bandali" user-mail-address "bandali@gnu.org") ;;; Package management (progn ; `borg' (add-to-list 'load-path (expand-file-name "lib/borg" user-emacs-directory)) (require 'borg) (borg-initialize) (setq borg-rewrite-urls-alist '(("git@github.com:" . "https://github.com/") ("git@gitlab.com:" . "https://gitlab.com/")))) (defmacro csetq (&rest args) "Set the value of user option VAR to VALUE. More generally, you can use multiple variables and values, as in (csetq VAR VALUE VAR VALUE...) This sets each user option VAR's value to the corresponding VALUE. \(fn [VAR VALUE]...)" (declare (debug setq)) `(progn ,@(cl-loop for (var value) on args by 'cddr collect `(funcall (or (get ',var 'custom-set) #'set-default) ',var ,value)))) ;;; Initial setup ;; keep ~/.emacs.d clean (defvar b/etc-dir (expand-file-name (convert-standard-filename "etc/") user-emacs-directory) "The directory where packages place their configuration files.") (defvar b/var-dir (expand-file-name (convert-standard-filename "var/") user-emacs-directory) "The directory where packages place their persistent data files.") (defun b/etc (file) "Expand filename FILE relative to `b/etc-dir'." (expand-file-name (convert-standard-filename file) b/etc-dir)) (defun b/var (file) "Expand filename FILE relative to `b/var-dir'." (expand-file-name (convert-standard-filename file) b/var-dir)) (csetq auto-save-list-file-prefix (b/var "auto-save/sessions/") nsm-settings-file (b/var "nsm-settings.el")) (require 'auto-compile) (auto-compile-on-load-mode) (auto-compile-on-save-mode) (setq auto-compile-display-buffer nil) (setq auto-compile-mode-line-counter t) (setq auto-compile-source-recreate-deletes-dest t) (setq auto-compile-toggle-deletes-nonlib-dest t) (setq auto-compile-update-autoloads t) ;; separate custom file (don't want it mixing with init.el) (with-eval-after-load 'custom (setq custom-file (b/etc "custom.el")) (when (file-exists-p custom-file) (load custom-file)) ;; while at it, treat themes as safe (setf custom-safe-themes t) ;; only one custom theme at a time (comment (defadvice load-theme (before clear-previous-themes activate) "Clear existing theme settings instead of layering them" (mapc #'disable-theme custom-enabled-themes)))) ;; load the secrets file if it exists, otherwise show a warning (comment (with-demoted-errors (load (b/etc "secrets")))) ;; start up emacs server. see ;; https://www.gnu.org/software/emacs/manual/html_node/emacs/Emacs-Server.html#Emacs-Server (run-with-idle-timer 0.5 nil #'require 'server) (with-eval-after-load 'server (declare-function server-edit "server") (global-set-key (kbd "C-c F D") #'server-edit) (declare-function server-running-p "server") (or (server-running-p) (server-mode))) ;;; Defaults ;;;; C-level customizations (csetq ;; minibuffer enable-recursive-minibuffers t resize-mini-windows t ;; more useful frame titles ;; frame-title-format '("" invocation-name " - " ;; (:eval ;; (if (buffer-file-name) ;; (abbreviate-file-name (buffer-file-name)) ;; "%b"))) ;; i don't feel like jumping out of my chair every now and again; so ;; don't BEEP! at me, emacs ring-bell-function 'ignore ;; better scrolling ;; scroll-margin 1 ;; scroll-conservatively 10000 scroll-step 1 scroll-conservatively 101 scroll-preserve-screen-position 1 ;; focus follows mouse mouse-autoselect-window t) (setq-default ;; always use space for indentation indent-tabs-mode nil tab-width 4 ;; case-sensitive search (and `dabbrev-expand') ;; case-fold-search nil ;; cursor shape cursor-type t) (set-fontset-font t 'arabic "Vazir") ;; unicode support (comment (dolist (ft (fontset-list)) (set-fontset-font ft 'unicode (font-spec :name "Source Code Pro" :size 14)) (set-fontset-font ft 'unicode (font-spec :name "DejaVu Sans Mono") nil 'append) ;; (set-fontset-font ;; ft ;; 'unicode ;; (font-spec ;; :name "Symbola monospacified for DejaVu Sans Mono") ;; nil ;; 'append) ;; (set-fontset-font ;; ft ;; #x2115 ; ℕ ;; (font-spec :name "DejaVu Sans Mono") ;; nil ;; 'append) (set-fontset-font ft (cons ?Α ?ω) (font-spec :name "DejaVu Sans Mono" :size 14) nil 'prepend))) ;;;; Elisp-level customizations ;; startup ;; don't need to see the startup echo area message (advice-add #'display-startup-echo-area-message :override #'ignore) (csetq ;; i want *scratch* as my startup buffer initial-buffer-choice t ;; i don't need the default hint initial-scratch-message nil ;; use customizable text-mode as major mode for *scratch* ;; (initial-major-mode 'text-mode) ;; inhibit buffer list when more than 2 files are loaded inhibit-startup-buffer-menu t ;; don't need to see the startup screen or echo area message inhibit-startup-screen t inhibit-startup-echo-area-message user-login-name) ;; files (csetq ;; backups (C-h v make-backup-files RET) backup-by-copying t backup-directory-alist (list (cons "." (b/var "backup/"))) version-control t delete-old-versions t ;; auto-save auto-save-file-name-transforms `((".*" ,(b/var "auto-save/") t)) ;; insert newline at the end of files require-final-newline t ;; open read-only file buffers in view-mode ;; (enables niceties like `q' for quit) view-read-only t) ;; novice ;; disable disabled commands (csetq disabled-command-function nil) ;; lazy-person-friendly yes/no prompts (defalias 'yes-or-no-p #'y-or-n-p) ;; enable automatic reloading of changed buffers and files (progn ; autorevert (csetq auto-revert-verbose nil global-auto-revert-non-file-buffers nil) (require 'autorevert) (global-auto-revert-mode 1)) ;; time and battery in mode-line (csetq display-time-default-load-average nil display-time-format " %a %b %-e %-l:%M%P" display-time-mail-icon '(image :type xpm :file "gnus/gnus-pointer.xpm" :ascent center) display-time-use-mail-icon t) (require 'time) (display-time-mode) (csetq battery-mode-line-format "%p%% %t") (require 'battery) (display-battery-mode) (require 'fringe) ;; smaller fringe ;; (fringe-mode '(3 . 1)) (fringe-mode nil) (require 'winner) ;; enable winner-mode (C-h f winner-mode RET) (winner-mode 1) (with-eval-after-load 'compile ;; don't display *compilation* buffer on success. based on ;; https://stackoverflow.com/a/17788551, with changes to use `cl-letf' ;; instead of the now obsolete `flet'. (defun b/compilation-finish-function (buffer outstr) (unless (string-match "finished" outstr) (switch-to-buffer-other-window buffer)) t) (setq compilation-finish-functions #'b/compilation-finish-function) (require 'cl-macs) (defadvice compilation-start (around inhibit-display (command &optional mode name-function highlight-regexp)) (if (not (string-match "^\\(find\\|grep\\)" command)) (cl-letf (((symbol-function 'display-buffer) #'ignore)) (save-window-excursion ad-do-it)) ad-do-it)) (ad-activate 'compilation-start)) ;; isearch (csetq ;; allow scrolling in Isearch isearch-allow-scroll t ;; search for non-ASCII characters: i’d like non-ASCII characters such ;; as ‘’“”«»‹›áⓐ𝒶 to be selected when i search for their ASCII ;; counterpart. shoutout to ;; http://endlessparentheses.com/new-in-emacs-25-1-easily-search-non-ascii-characters.html search-default-mode #'char-fold-to-regexp) ;; replace ;; uncomment to extend the above behaviour to query-replace ;; (csetq replace-char-fold t) ;; vc (global-set-key (kbd "C-x v C-=") #'vc-ediff) (with-eval-after-load 'vc-git (csetq vc-git-print-log-follow t)) (csetq ediff-window-setup-function 'ediff-setup-windows-plain ediff-split-window-function 'split-window-horizontally) (with-eval-after-load 'ediff (add-hook 'ediff-after-quit-hook-internal #'winner-undo)) ;; face-remap (csetq ;; gentler font resizing text-scale-mode-step 1.05) (run-with-idle-timer 0.4 nil #'require 'mwheel) (csetq mouse-wheel-scroll-amount '(1 ((shift) . 1)) ; one line at a time mouse-wheel-progressive-speed nil ; don't accelerate scrolling mouse-wheel-follow-mouse t) ; scroll window under mouse (run-with-idle-timer 0.4 nil #'require 'pixel-scroll) (with-eval-after-load 'pixel-scroll (pixel-scroll-mode 1)) ;; epg-config (csetq epg-gpg-program (executable-find "gpg") ;; ask for GPG passphrase in minibuffer ;; this will fail if gpg>=2.1 is not available epg-pinentry-mode 'loopback) ;; (require 'pinentry) ;; workaround for systemd-based distros: ;; (setq pinentry--socket-dir server-socket-dir) ;; (pinentry-start) ;; auth-source (csetq auth-sources '("~/.authinfo.gpg") authinfo-hidden (regexp-opt '("password" "client-secret" "token"))) ;;; General key bindings (global-set-key (kbd "C-a") #'b/move-indentation-or-beginning-of-line) (global-set-key (kbd "C-c a i") #'ielm) (global-set-key (kbd "C-c d") #'b/duplicate-line-or-region) (global-set-key (kbd "C-S-j") #'b/join-line-top) (global-set-key (kbd "C-c x") #'execute-extended-command) ;; evaling and macro-expanding (global-set-key (kbd "C-c e b") #'eval-buffer) (global-set-key (kbd "C-c e e") #'eval-last-sexp) (global-set-key (kbd "C-c e p") #'pp-macroexpand-last-sexp) (global-set-key (kbd "C-c e r") #'eval-region) ;; emacs things (global-set-key (kbd "C-c e i") #'emacs-init-time) (global-set-key (kbd "C-c e u") #'emacs-uptime) (global-set-key (kbd "C-c e v") #'emacs-version) ;; finding (global-set-key (kbd "C-c f .") #'find-file) (global-set-key (kbd "C-c f d") #'find-name-dired) (global-set-key (kbd "C-c f l") #'find-library) ;; frames (global-set-key (kbd "C-c F m") #'make-frame-command) (global-set-key (kbd "C-c F d") #'delete-frame) ;; help/describe (global-set-key (kbd "C-S-h C") #'describe-char) (global-set-key (kbd "C-S-h F") #'describe-face) ;; (global-set-key (kbd "C-x k") #'b/kill-current-buffer) ;; (global-set-key (kbd "C-x K") #'kill-buffer) ;; (global-set-key (kbd "C-x s") #'save-buffer) ;; (global-set-key (kbd "C-x S") #'save-some-buffers) (define-key emacs-lisp-mode-map (kbd "") #'b/add-elisp-section) (when (display-graphic-p) (global-unset-key (kbd "C-z"))) ;;; Essential packages ;; (require 'bandali-exwm) (require 'bandali-org) (require 'bandali-theme) ;; magit, *the* right way to do git (csetq transient-history-file (b/var "transient/history.el") transient-levels-file (b/etc "transient/levels.el") transient-values-file (b/etc "transient/values.el")) (with-eval-after-load 'magit (declare-function magit-add-section-hook "magit-section" (hook function &optional at append local)) (magit-add-section-hook 'magit-status-sections-hook 'magit-insert-modules 'magit-insert-stashes 'append) ;; (magit-add-section-hook 'magit-status-sections-hook ;; 'magit-insert-ignored-files ;; 'magit-insert-untracked-files ;; 'append) (declare-function magit-display-buffer-fullframe-status-v1 "magit-mode" (buffer)) (csetq magit-diff-refine-hunk t magit-repository-directories '(("~/.emacs.d/" . 0) ("~/src/git/" . 2)) ;; magit-completing-read-function 'magit-ido-completing-read magit-display-buffer-function #'magit-display-buffer-fullframe-status-v1) (nconc magit-section-initial-visibility-alist '(([unpulled status] . show) ([unpushed status] . show))) (custom-set-faces '(magit-diff-file-heading ((t (:weight normal))))) (with-eval-after-load 'magit-extras (csetq magit-pop-revision-stack-format (pcase-let ((`(,pt ,_eob ,index-regexp) (default-value 'magit-pop-revision-stack-format))) `(,pt "[%N: %h]: %ci\n %s https://git.savannah.gnu.org/cgit/emacs.git/commit/?id=%H" ,index-regexp))))) ;; global key bindings (global-set-key (kbd "C-x g") #'magit-status) (global-set-key (kbd "C-c g b") #'magit-blame-addition) (global-set-key (kbd "C-c g l") #'magit-log-buffer-file) (global-set-key (kbd "C-c g y") #'magit-pop-revision-stack) ;; recently opened files (run-with-idle-timer 0.2 nil #'require 'recentf) (with-eval-after-load 'recentf (csetq recentf-max-saved-items 2000 recentf-save-file (b/var "recentf-save.el")) (add-to-list 'recentf-keep #'file-remote-p) (recentf-mode)) ;; needed for history for counsel (csetq amx-save-file (b/var "amx-save.el")) (run-with-idle-timer 0.3 nil #'require 'amx) (with-eval-after-load 'amx (amx-mode)) ;; (require 'bandali-ido) (require 'bandali-ivy) (require 'bandali-eshell) ;; (require 'bandali-multi-term) (require 'bandali-ibuffer) ;; outline ;; (with-eval-after-load 'outline ;; (when (featurep 'which-key) ;; (which-key-add-key-based-replacements ;; "C-c @" "outline" ;; "s-O" "outline")) ;; (define-key outline-minor-mode-map (kbd "") ;; #'outline-toggle-children) ;; (define-key outline-minor-mode-map (kbd "M-p") ;; #'outline-previous-visible-heading) ;; (define-key outline-minor-mode-map (kbd "M-n") ;; #'outline-next-visible-heading) ;; (defvar b/outline-prefix-map) ;; (define-prefix-command 'b/outline-prefix-map) ;; (define-key outline-minor-mode-map (kbd "s-O") ;; 'b/outline-prefix-map) ;; (define-key b/outline-prefix-map (kbd "TAB") ;; #'outline-toggle-children) ;; (define-key b/outline-prefix-map (kbd "a") ;; #'outline-hide-body) ;; (define-key b/outline-prefix-map (kbd "H") ;; #'outline-hide-body) ;; (define-key b/outline-prefix-map (kbd "S") ;; #'outline-show-all) ;; (define-key b/outline-prefix-map (kbd "h") ;; #'outline-hide-subtree) ;; (define-key b/outline-prefix-map (kbd "s") ;; #'outline-show-subtree)) ;; (add-hook 'prog-mode-hook #'outline-minor-mode) (require 'bandali-dired) (with-eval-after-load 'help (temp-buffer-resize-mode) (csetq help-window-select t) ;; local key bindings (define-key help-mode-map (kbd "p") #'backward-button) (define-key help-mode-map (kbd "n") #'forward-button)) (with-eval-after-load 'tramp (csetq tramp-auto-save-directory (b/var "tramp/auto-save/") tramp-persistency-file-name (b/var "tramp/persistency.el")) (add-to-list 'tramp-default-proxies-alist '(nil "\\`root\\'" "/ssh:%h:")) (add-to-list 'tramp-default-proxies-alist '("localhost" nil nil)) (add-to-list 'tramp-default-proxies-alist (list (regexp-quote (system-name)) nil nil))) (with-eval-after-load 'doc-view (define-key doc-view-mode-map (kbd "M-RET") #'image-previous-line)) (csetq shr-max-width 80) ;; Email (with Gnus, message, and EBDB) (require 'bandali-gnus) (with-eval-after-load 'sendmail (csetq sendmail-program (executable-find "msmtp") ;; message-sendmail-extra-arguments '("-v" "-d") mail-specify-envelope-from t mail-envelope-from 'header)) (require 'bandali-message) (require 'bandali-ebdb) ;; IRC (with ERC and ZNC) (require 'bandali-erc) (with-eval-after-load 'scpaste (csetq scpaste-http-destination "https://p.bndl.org" scpaste-scp-destination "p:~")) (global-set-key (kbd "C-c a p p") #'scpaste) (global-set-key (kbd "C-c a p r") #'scpaste-region) ;;; Editing ;; display Lisp objects at point in the echo area (when (version< "25" emacs-version) (with-eval-after-load 'eldoc (global-eldoc-mode))) ;; highlight matching parens (require 'paren) (show-paren-mode) ;; (require 'elec-pair) ;; (electric-pair-mode) (csetq ;; Save what I copy into clipboard from other applications into Emacs' ;; kill-ring, which would allow me to still be able to easily access ;; it in case I kill (cut or copy) something else inside Emacs before ;; yanking (pasting) what I'd originally intended to. save-interprogram-paste-before-kill t) (with-eval-after-load 'simple (column-number-mode)) ;; save minibuffer history (require 'savehist) (csetq savehist-file (b/var "savehist.el")) (savehist-mode) (add-to-list 'savehist-additional-variables 'kill-ring) ;; automatically save place in files (when (version< "25" emacs-version) (csetq save-place-file (b/var "save-place.el")) (save-place-mode)) (defun indicate-buffer-boundaries-left () (csetq indicate-buffer-boundaries 'left)) (with-eval-after-load 'prog-mode (global-prettify-symbols-mode)) (add-hook 'prog-mode-hook #'indicate-buffer-boundaries-left) (define-key text-mode-map (kbd "C-*") #'b/insert-asterism) (add-hook 'text-mode-hook #'indicate-buffer-boundaries-left) (add-hook 'text-mode-hook #'flyspell-mode) (add-to-list 'auto-mode-alist '("\\.*rc$" . conf-mode)) (add-to-list 'auto-mode-alist '("\\.bashrc$" . sh-mode)) ;; flycheck ;; (run-with-idle-timer 0.6 nil #'require 'flycheck) ;; (with-eval-after-load 'flycheck ;; (csetq ;; ;; Use the load-path from running Emacs when checking elisp files ;; flycheck-emacs-lisp-load-path 'inherit ;; ;; Only flycheck when I actually save the buffer ;; flycheck-check-syntax-automatically '(mode-enabled save) ;; flycheck-mode-line-prefix "flyc")) ;; (define-key flycheck-mode-map (kbd "M-P") #'flycheck-previous-error) ;; (define-key flycheck-mode-map (kbd "M-N") #'flycheck-next-error) ;; (add-hook 'prog-mode-hook #'flycheck-mode) ;; ispell ;; http://endlessparentheses.com/ispell-and-apostrophes.html ;; (run-with-idle-timer 0.6 nil #'require 'ispell) ;; (with-eval-after-load 'ispell ;; ;; ’ can be part of a word ;; (csetq ispell-local-dictionary-alist ;; `((nil "[[:alpha:]]" "[^[:alpha:]]" ;; "['\x2019]" nil ("-B") nil utf-8)) ;; ispell-program-name (executable-find "hunspell")) ;; ;; don't send ’ to the subprocess ;; (defun endless/replace-apostrophe (args) ;; (cons (replace-regexp-in-string ;; "’" "'" (car args)) ;; (cdr args))) ;; (advice-add #'ispell-send-string :filter-args ;; #'endless/replace-apostrophe) ;; ;; convert ' back to ’ from the subprocess ;; (defun endless/replace-quote (args) ;; (if (not (derived-mode-p 'org-mode)) ;; args ;; (cons (replace-regexp-in-string ;; "'" "’" (car args)) ;; (cdr args)))) ;; (advice-add #'ispell-parse-output :filter-args ;; #'endless/replace-quote)) ;; abbrev (csetq abbrev-file-name (b/var "abbrev.el")) (add-hook 'text-mode-hook #'abbrev-mode) ;;; Programming modes (with-eval-after-load 'lisp-mode (defun indent-spaces-mode () (setq indent-tabs-mode nil)) (add-hook 'lisp-interaction-mode-hook #'indent-spaces-mode)) (with-eval-after-load 'alloy-mode (csetq alloy-basic-offset 2) ;; (defun b/alloy-simple-indent (start end) ;; (interactive "r") ;; ;; (if (region-active-p) ;; ;; (indent-rigidly start end alloy-basic-offset) ;; ;; (if (bolp) ;; ;; (indent-rigidly (line-beginning-position) ;; ;; (line-end-position) ;; ;; alloy-basic-offset))) ;; (indent-to (+ (current-column) alloy-basic-offset))) ;; local key bindings (define-key alloy-mode-map (kbd "RET") #'electric-newline-and-maybe-indent) ;; (define-key alloy-mode-map (kbd "TAB") #'b/alloy-simple-indent) (define-key alloy-mode-map (kbd "TAB") #'indent-for-tab-command)) (add-to-list 'auto-mode-alist '("\\.\\(als\\|dsh\\)\\'" . alloy-mode)) (add-hook 'alloy-mode-hook (lambda nil (setq-local indent-tabs-mode nil))) ;; lean ;; (eval-when-compile (defvar lean-mode-map)) ;; (run-with-idle-timer 0.4 nil #'require 'lean-mode) ;; (with-eval-after-load 'lean-mode ;; (require 'lean-input) ;; (csetq default-input-method "Lean" ;; lean-input-tweak-all '(lean-input-compose ;; (lean-input-prepend "/") ;; (lean-input-nonempty)) ;; lean-input-user-translations '(("/" "/"))) ;; (lean-input-setup) ;; ;; local key bindings ;; (define-key lean-mode-map (kbd "S-SPC") #'company-complete)) (with-eval-after-load 'sgml-mode (csetq sgml-basic-offset 0)) (with-eval-after-load 'css-mode (csetq css-indent-offset 2)) ;; po-mode ;; (add-hook 'po-mode-hook (lambda nil (run-with-timer 0.1 nil 'View-exit))) ;; auctex ;; (csetq font-latex-fontify-sectioning 'color) (with-eval-after-load 'tex-mode (cl-delete-if (lambda (p) (string-match "^---?" (car p))) tex--prettify-symbols-alist)) (add-hook 'tex-mode-hook #'auto-fill-mode) (add-hook 'tex-mode-hook #'flyspell-mode) ;;; Emacs enhancements & auxiliary packages (with-eval-after-load 'man (csetq Man-width 80)) (run-with-idle-timer 0.4 nil #'require 'which-key) (with-eval-after-load 'which-key (csetq which-key-add-column-padding 5 which-key-idle-delay 10000 which-key-idle-secondary-delay 0.05 which-key-max-description-length 32 which-key-show-early-on-C-h t) (which-key-add-key-based-replacements ;; prefixes for global prefixes and minor modes "C-c !" "flycheck" "C-x RET" "coding system" "C-x 8" "unicode" "C-x @" "event modifiers" "C-x a" "abbrev/expand" "C-x r" "rectangle/register/bookmark" "C-x t" "tabs" "C-x v" "version control" "C-x X" "edebug" "C-x C-a" "edebug" "C-x C-k" "kmacro" ;; prefixes for my personal bindings "C-c &" "yasnippet" "C-c a" "applications" "C-c a e" "erc" "C-c a o" "org" "C-c a s" "shells" "C-c b" "buffers" "C-c c" "compile-and-comments" "C-c e" "eval" "C-c f" "files" "C-c F" "frames" "C-c g" "magit" "C-S-h" "help(ful)" "C-c q" "boxquote" "C-c t" "themes") ;; prefixes for major modes (which-key-add-major-mode-key-based-replacements 'org-mode "C-c C-v" "org-babel") (which-key-mode)) ;; (require 'bandali-projectile) (run-with-idle-timer 0.6 nil #'require 'unkillable-scratch) (with-eval-after-load 'unkillable-scratch (csetq unkillable-buffers '("^\\*scratch\\*$" "^\\*Messages\\*$")) (unkillable-scratch 1)) ;; ,---- ;; | make pretty boxed quotes like this ;; `---- (run-with-idle-timer 0.6 nil #'require 'boxquote) (with-eval-after-load 'boxquote (defvar b/boxquote-prefix-map) (define-prefix-command 'b/boxquote-prefix-map) (global-set-key (kbd "C-c q") 'b/boxquote-prefix-map) (define-key b/boxquote-prefix-map (kbd "b") #'boxquote-buffer) (define-key b/boxquote-prefix-map (kbd "B") #'boxquote-insert-buffer) (define-key b/boxquote-prefix-map (kbd "d") #'boxquote-defun) (define-key b/boxquote-prefix-map (kbd "F") #'boxquote-insert-file) (define-key b/boxquote-prefix-map (kbd "hf") #'boxquote-describe-function) (define-key b/boxquote-prefix-map (kbd "hk") #'boxquote-describe-key) (define-key b/boxquote-prefix-map (kbd "hv") #'boxquote-describe-variable) (define-key b/boxquote-prefix-map (kbd "hw") #'boxquote-where-is) (define-key b/boxquote-prefix-map (kbd "k") #'boxquote-kill) (define-key b/boxquote-prefix-map (kbd "p") #'boxquote-paragraph) (define-key b/boxquote-prefix-map (kbd "q") #'boxquote-boxquote) (define-key b/boxquote-prefix-map (kbd "r") #'boxquote-region) (define-key b/boxquote-prefix-map (kbd "s") #'boxquote-shell-command) (define-key b/boxquote-prefix-map (kbd "t") #'boxquote-text) (define-key b/boxquote-prefix-map (kbd "T") #'boxquote-title) (define-key b/boxquote-prefix-map (kbd "u") #'boxquote-unbox) (define-key b/boxquote-prefix-map (kbd "U") #'boxquote-unbox-region) (define-key b/boxquote-prefix-map (kbd "y") #'boxquote-yank) (define-key b/boxquote-prefix-map (kbd "M-q") #'boxquote-fill-paragraph) (define-key b/boxquote-prefix-map (kbd "M-w") #'boxquote-kill-ring-save)) (run-with-idle-timer 0.5 nil #'require 'hl-todo) (with-eval-after-load 'hl-todo ;; highlight TODOs in buffers (global-hl-todo-mode)) (run-with-idle-timer 0.5 nil #'require 'page-break-lines) (with-eval-after-load 'page-break-lines (csetq page-break-lines-max-width fill-column) (global-page-break-lines-mode)) ;; expand-region (global-set-key (kbd "C-=") #'er/expand-region) (run-with-idle-timer 0.6 nil #'require 'yasnippet) (with-eval-after-load 'yasnippet (declare-function yas-reload-all "yasnippet" (&optional no-jit interactive)) (declare-function yas-maybe-expand-abbrev-key-filter "yasnippet" (cmd)) (defconst yas-verbosity-cur yas-verbosity) (setq yas-verbosity 2) (csetq yas-snippet-dirs `(,(b/etc "yasnippet/snippets"))) (add-to-list 'yas-snippet-dirs "~/src/git/guix/etc/snippets" t) (yas-reload-all) (setq yas-verbosity yas-verbosity-cur) (defun b/yas-maybe-expand-abbrev-key-filter (cmd) (when (and (yas-maybe-expand-abbrev-key-filter cmd) (not (bound-and-true-p git-commit-mode))) cmd)) (defconst b/yas-maybe-expand '(menu-item "" yas-expand :filter b/yas-maybe-expand-abbrev-key-filter)) (define-key yas-minor-mode-map (kbd "SPC") b/yas-maybe-expand) (yas-global-mode)) ;; debbugs (global-set-key (kbd "C-c D d") #'debbugs-gnu) (global-set-key (kbd "C-c D b") #'debbugs-gnu-bugs) (global-set-key (kbd "C-c D e") ; bug-gnu-emacs (lambda () (interactive) (setq debbugs-gnu-current-suppress t) (debbugs-gnu debbugs-gnu-default-severities '("emacs")))) (global-set-key (kbd "C-c D g") ; bug-gnuzilla (lambda () (interactive) (setq debbugs-gnu-current-suppress t) (debbugs-gnu debbugs-gnu-default-severities '("gnuzilla")))) (global-set-key (kbd "C-c D G b") ; bug-guix (lambda () (interactive) (setq debbugs-gnu-current-suppress t) (debbugs-gnu debbugs-gnu-default-severities '("guix")))) (global-set-key (kbd "C-c D G p") ; guix-patches (lambda () (interactive) (setq debbugs-gnu-current-suppress t) (debbugs-gnu debbugs-gnu-default-severities '("guix-patches")))) ;; url and url-cache (csetq url-configuration-directory (b/var "url/configuration/") url-cache-directory (b/var "url/cache/")) ;; eww (csetq eww-download-directory (file-name-as-directory (getenv "XDG_DOWNLOAD_DIR"))) (global-set-key (kbd "C-c a e w") #'eww) (comment ;; org-ref (csetq reftex-default-bibliography '("~/usr/org/references.bib") org-ref-default-bibliography '("~/usr/org/references.bib") org-ref-bibliography-notes "~/usr/org/notes.org" org-ref-pdf-directory "~/usr/org/bibtex-pdfs/") ;; fill-column-indicator ? ;; window (csetq split-width-threshold 150) (global-set-key (kbd "C-c w s l") (lambda () (interactive) (split-window-right) (other-window 1))) (global-set-key (kbd "C-c w s j") (lambda () (interactive) (split-window-below) (other-window 1))) (global-set-key (kbd "C-c w q") #'quit-window) (run-with-idle-timer 0.6 nil #'require 'windmove) (global-set-key (kbd "C-c w h") #'windmove-left) (global-set-key (kbd "C-c w j") #'windmove-down) (global-set-key (kbd "C-c w k") #'windmove-up) (global-set-key (kbd "C-c w l") #'windmove-right) (global-set-key (kbd "C-c w H") #'windmove-swap-states-left) (global-set-key (kbd "C-c w J") #'windmove-swap-states-down) (global-set-key (kbd "C-c w K") #'windmove-swap-states-up) (global-set-key (kbd "C-c w L") #'windmove-swap-states-right) ;; pass (global-set-key (kbd "C-c a p") #'pass) (add-hook 'pass-mode-hook #'View-exit) ;; reftex ;; uncomment to disable reftex-cite's default choice of previous word ;; (with-eval-after-load 'reftex ;; (require 'reftex-cite) ;; (defun reftex-get-bibkey-default () ;; "If the cursor is in a citation macro, return the word before the macro." ;; (let* ((macro (reftex-what-macro 1))) ;; (save-excursion ;; (when (and macro (string-match "cite" (car macro))) ;; (goto-char (cdr macro))) ;; (reftex-this-word))))) (add-hook 'latex-mode-hook #'reftex-mode) ;; dmenu (csetq dmenu-prompt-string "run: " dmenu-save-file (b/var "dmenu-items")) ;; eosd ? ;;; Post initialization ) (message "Loading %s...done (%.3fs)" user-init-file (float-time (time-subtract (current-time) b/before-user-init-time))) ;;; init.el ends here