;;; init.el -*- lexical-binding: t; coding: utf-8-unix -*- ;; ;; Author: Case Duckworth ;; Created: Sometime during Covid-19, 2020 ;; Keywords: configuration ;; URL: https://tildegit.org/acdw/emacs ;; Bankruptcy: 5c ;; ;; This file is NOT part of GNU Emacs. ;; ;;; License: ;; ;; Everyone is permitted to do whatever with this software, without ;; limitation. This software comes without any warranty whatsoever, ;; but with two pieces of advice: ;; - Don't hurt yourself. ;; - Make good choices. ;; ;;; Code: ;;; Add `acdw.el' (push (expand-file-name "lisp/" user-emacs-directory) load-path) (require 'acdw) ;;; About me (acdw/set '((user-full-name "Case Duckworth") (user-mail-address "acdw@acdw.net") (calendar-location-name "Baton Rouge, LA") (calendar-latitude 30.4) (calendar-longitude -91.1) (calendar-date-style iso))) ;;; Good defaults ;; Lines (acdw/set '((fill-column 80))) (global-display-fill-column-indicator-mode +1) (add-hook 'text-mode-hook #'turn-on-auto-fill) (add-hook 'prog-mode-hook #'turn-on-auto-fill) (global-so-long-mode +1) ;; I don't want `visual-line-mode', because I really only want to wrap and ;; truncate lines. Believe me, I know what I'm doing. (acdw/set '((word-wrap t) (truncate-lines t))) ;; Whitespace (acdw/set '((whitespace-style (empty indentation space-before-tab space-after-tab)) (indent-tabs-mode t) (tab-width 8))) (add-hook 'before-save-hook #'whitespace-cleanup) ;; Pairs (add-hook 'prog-mode-hook #'electric-pair-local-mode) (acdw/set '((show-paren-delay 0) (show-paren-style mixed) (show-paren-when-point-inside-paren t) (show-paren-when-point-in-periphery t))) (show-paren-mode +1) ;; Killing & Yanking (delete-selection-mode +1) (acdw/set '((save-interprogram-paste-before-kill t) (yank-pop-change-selection t) (x-select-enable-clipboard t) (x-select-enable-primary t) (mouse-drag-copy-region t) (kill-do-not-save-duplicates t))) ;; Encoding (set-charset-priority 'unicode) (set-language-environment "UTF-8") (prefer-coding-system 'utf-8-unix) (set-default-coding-systems 'utf-8-unix) (set-terminal-coding-system 'utf-8-unix) (set-keyboard-coding-system 'utf-8-unix) (set-selection-coding-system 'utf-8-unix) (acdw/set '((locale-coding-system utf-8-unix) (coding-system-for-read utf-8-unix) (coding-system-for-write utf-8-unix) (buffer-file-coding-system utf-8-unix) (org-export-coding-system utf-8-unix) (org-html-coding-system utf-8-unix) (default-process-coding-system (utf-8-unix . utf-8-unix)) (x-select-request-type (UTF8_STRING COMPOUND_TEXT TEXT STRING)))) ;; Unique buffer names (when (require 'uniquify) (acdw/set '((uniquify-buffer-name-style forward) (uniquify-separator "/") (uniquify-after-kill-buffer-p t) (uniquify-ignore-buffers-re "^\\*")))) ;; Backups (acdw/set `((backup-by-copying t) (delete-old-versions -1) (version-control t) (vc-make-backup-files t) (backup-directory-alist ((".*" . ,(acdw/in-dir "backup/" t)))))) ;; Autosaves (acdw/set `((auto-save-file-name-transforms ((".*" ,(acdw/in-dir "auto-save/" t) t))) (auto-save-list-file-prefix ,(acdw/in-dir "auto-save-list/.saves-" t)))) (auto-save-visited-mode +1) (defun hook--auto-save-when-unfocused () "Save all buffers when out of focus." (acdw/when-unfocused #'save-some-buffers t)) (add-function :after after-focus-change-function #'hook--auto-save-when-unfocused) ;; Auto-revert (when (require 'autorevert) (global-auto-revert-mode +1)) ;; Save place (when (require 'saveplace) (acdw/set `((save-place-file ,(acdw/in-dir "places.el")) (save-place-forget-unreadable-files ,(eq acdw/system :home)))) (save-place-mode +1)) ;; Recent files (when (require 'recentf) (acdw/set `((recentf-save-file ,(acdw/in-dir "recentf.el")) (recentf-max-menu-items 100) (recentf-max-saved-items nil) (recentf-auto-cleanup 60 "Cleanup the recentf list when idle for 60s."))) (add-to-list 'recentf-exclude acdw/dir) (recentf-mode +1)) ;; Move the custom file (acdw/set `((custom-file ,(acdw/in-dir "custom.el")))) ;; Cursor (acdw/set '((cursor-type bar) (cursor-in-non-selected-windows hollow))) (defun hook--overwrite-mode-change-cursor () (setq cursor-type (if overwrite-mode 'hbar 'bar))) (add-hook 'overwrite-mode-hook #'hook--overwrite-mode-change-cursor) ;; Scrolling (acdw/set '((auto-window-vscroll nil) (fast-but-imprecise-scrolling t) (scroll-margin 0) (scroll-conservatively 101) (scroll-preserve-screen-position 1))) ;; Bindings (acdw/binds (("C-h" ehelp-command :after ("ehelp" nil nil 'keymap)) ([remap just-one-space] cycle-spacing) ("M-/" hippie-expand) ("M-=" count-words) ("C-x C-b" ibuffer))) ;;; Startup (acdw/set `((inhibit-startup-screen t) (initial-buffer-choice t) (initial-scratch-message ,(concat ";; Howdy, " (nth 0 (split-string user-full-name)) "!" " Welcome to GNU Emacs.\n\n")))) ;;; Minibuffer (acdw/set '((minibuffer-prompt-properties (read-only t cursor-intangible t face minibuffer-prompt)) (enable-recursive-minibuffers t) (file-name-shadow-properties (invisible t)))) (minibuffer-depth-indicate-mode +1) (file-name-shadow-mode +1) ;; Save history (when (require 'savehist) (acdw/set `((savehist-additional-variables (kill-ring search-ring regexp-search-ring)) (history-length t) (history-delete-duplicates t) (savehist-autosave-interval 6) (savehist-file ,(acdw/in-dir "savehist.el")))) (savehist-mode +1)) ;; Icomplete (-vertical) (when (require 'icomplete) (acdw/set '((completion-ignore-case t) (read-buffer-completion-ignore-case t) (icomplete-delay-completions-threshold 0) (icomplete-max-delay-chars 0) (icomplete-compute-delay 0) (icomplete-show-matches-on-no-input t) (icomplete-with-buffer-completion-tables t) (icomplete-in-buffer t))) (acdw/pkg orderless :set '((completion-styles (orderless)))) (acdw/pkg icomplete-vertical :binds (("" icomplete-forward-completions :map icomplete-minibuffer-map) ("C-n" icomplete-forward-completions :map icomplete-minibuffer-map) ("" icomplete-backward-completions :map icomplete-minibuffer-map) ("C-p" icomplete-backward-completions :map icomplete-minibuffer-map) ("C-v" icomplete-vertical-toggle :map icomplete-minibuffer-map)) :now ((fido-mode -1) (icomplete-mode +1) (icomplete-vertical-mode +1)))) ;; Consult (acdw/pkg consult :binds (;; C-c bindings (`mode-specific-map') ("C-c h" consult-history) ("C-c m" consult-mode-command) ;; C-x bindings (`ctl-x-map') ("C-x M-:" consult-complex-command) ("C-x b" consult-buffer) ("C-x 4 b" consult-buffer-other-window) ("C-x 5 b" consult-buffer-other-frame) ("C-x r x" consult-register) ("C-x r b" consult-bookmark) ;; M-g bindings (`goto-map') ("M-g o" consult-outline) ("M-g m" consult-mark) ("M-g k" consult-global-mark) ("M-g i" consult-imenu) ("M-g e" consult-error) ;; M-s bindings (`search-map') ("M-s g" consult-grep) ; alts: ; consult-git-grep, ; consult-ripgrep ("M-s f" consult-find) ; alts: ; consult-locate ("M-s l" consult-line) ("M-s m" consult-multi-occur) ("M-s k" consult-keep-lines) ("M-s u" consult-focus-lines) ;; Other bindings ("M-y" consult-yank-pop) (" a" consult-apropos) ("C-h a" consult-apropos)) :now ((autoload 'consult-register-preview "consult")) :set '((register-preview-delay 0) (register-preview-function #'consult-register-preview))) ;; Marginalia (acdw/pkg marginalia :set '((marginalia-annotators (marginalia-annotators-heavy marginalia-annotators-light))) :now ((marginalia-mode +1))) ;; Imenu (when (require 'imenu) (acdw/set '((imenu-auto-rescan t)))) ;;; Packages ;; Undo-fu (acdw/pkg undo-fu :binds (("C-/" undo-fu-only-undo) ("C-?" undo-fu-only-redo))) (acdw/pkg undo-fu-session :set `((undo-fu-session-incompatible-files ("/COMMIT_EDITMSG\\'" "/git-rebase-todo\\'")) (undo-fu-session-directory ,(acdw/in-dir "undo/" t))) :then ((global-undo-fu-session-mode +1))) ;; Modus themes (acdw/pkg (modus-themes :host gitlab :repo "protesilaos/modus-themes") :set `((modus-themes-slanted-constructs t) (modus-themes-bold-constructs t) (modus-themes-region 'bg-only) (modus-themes-org-blocks 'grayscale) (modus-themes-headings ((1 . section) (t . no-color))) (modus-themes-scale-headings nil) (modus-themes-mode-line nil)) :now ((acdw/sunrise-sunset #'modus-themes-load-operandi #'modus-themes-load-vivendi))) ;;; Mode line ;; Minions (acdw/pkg minions :now ((minions-mode +1))) ;; Simple mode line (acdw/pkg simple-modeline :set '((simple-modeline-segments ((;; left acdw/modeline-modified simple-modeline-segment-buffer-name simple-modeline-segment-position) (;; right simple-modeline-segment-vc simple-modeline-segment-misc-info simple-modeline-segment-process acdw/modeline-minions simple-modeline-segment-major-mode)))) :now ((defun acdw/modeline-modified () "Displays a color-coded buffer modification/read-only indicator in the mode-line." (if (not (string-match-p "\\*.*\\*" (buffer-name))) (let* ((read-only (and buffer-read-only (buffer-file-name))) (modified (buffer-modified-p))) (propertize (if read-only " ×" (if modified " ●" " ○")) 'face `(:inherit ,(if modified 'simple-modeline-status-modified (if read-only 'simple-modeline-status-error 'simple-modeline-unimportant))) 'help-echo (format (concat "Buffer is %s and %smodified\n" "mouse-1: Toggle read-only status.") (if read-only "read-only" "writable") (if modified "" "not ")) 'local-map (purecopy (simple-modeline-make-mouse-map 'mouse-1 (lambda (event) (interactive "e") (with-selected-window (posn-window (event-start event)) (read-only-mode 'toggle))))) 'mouse-face 'mode-line-highlight)))) (defun acdw/modeline-minions () "Display a button for `minions-minor-modes-menu'." (concat " " (propertize "ⱷ" 'help-echo (format "Minor modes menu\nmouse-1: show menu.") 'local-map (purecopy (simple-modeline-make-mouse-map 'mouse-1 (lambda (event) (interactive "e") (with-selected-window (posn-window (event-start event)) (minions-minor-modes-menu))))) 'mouse-face 'mode-line-highlight))) (simple-modeline-mode +1))) ;;; Magit (acdw/pkg magit :binds (("g" magit-status :map acdw/leader))) ;;; Web browsing (acdw/set '((browse-url-browser-function browse-url-firefox) (browse-url-new-window-flag t) (browse-url-firefox-new-window-is-tab t) (shr-max-width fill-column) (shr-width fill-column))) (when (eq acdw/system :work) (add-to-list 'exec-path "C:/Program Files/Mozilla Firefox")) (acdw/hooks ((text-mode-hook goto-address-mode) (prog-mode-hook goto-address-prog-mode))) ;;; Dired (acdw/set `((dired-recursive-copies always) (dired-recursive-deletes always) (delete-by-moving-to-trash t) (dired-listing-switches "-Al") (ls-lisp-dirs-first t) (dired-dwim-target t))) (defun hook--dired-mode () (hl-line-mode +1) (dired-hide-details-mode +1)) (add-hook 'dired-mode-hook #'hook--dired-mode) (acdw/bind "C-x C-j" dired-jump :after "dired-x") (with-eval-after-load 'dired ;; I tried `autoload'ing the keymap, and it just wouldn't work. I have no ;; idea what the issue was. (acdw/pkg dired-subtree :binds (("i" dired-subtree-toggle :map dired-mode-map)))) (acdw/pkg dired-collapse :hooks ((dired-mode-hook dired-collapse-mode))) ;;; Eshell (acdw/set `((eshell-directory-name ,(acdw/in-dir "eshell/" t)) (eshell-aliases-file ,(acdw/in-dir "eshell/aliases" t)))) ;;; Org-mode (acdw/pkg (org :repo "https://code.orgmode.org/bzg/org-mode.git") :now ((require 'acdw-org)) :set `((org-directory "~/org") (org-hide-emphasis-markers t) (org-fontify-whole-heading-line t) (org-fontify-done-headline t) (org-fontify-quote-and-verse-blocks t) (org-src-fontify-natively t) (org-pretty-entities t) (org-tags-column ,(- 0 fill-column -3)) (org-src-tab-acts-natively t) (org-src-window-setup current-window) (org-confirm-babel-evaluate nil) (org-adapt-indentation nil) (org-catch-invisible-edits smart) (org-special-ctrl-a/e t) (org-special-ctrl-k t) (org-imenu-depth 3) (org-export-headline-levels 8) (org-export-with-smart-quotes t) (org-export-with-sub-superscripts t)) :hooks ((before-save-hook acdw/hook--org-mode-fix-blank-lines))) ;;; Programming languages ;; Emacs lisp (acdw/set '((eval-expression-print-length nil) (eval-expression-print-level nil))) (when (require 'cl-lib) (setq-default lisp-indent-function #'common-lisp-indent-function) (put 'cl-flet 'common-lisp-indent-function (get 'flet 'common-lisp-indent-function)) (put 'cl-labels 'common-lisp-indent-function (get 'labels 'common-lisp-indent-function)) (put 'if 'common-lisp-indent-function 2) (put 'dotimes-protect 'common-lisp-indent-function (get 'when 'common-lisp-indent-function))) ;;; Miscellaneous (acdw/set '((disabled-command-function nil) (load-prefer-newer t) (comp-async-report-warnings-errors nil))) (fset 'yes-or-no-p #'y-or-n-p) ;; Garbage collection (defun hook--gc-cons-maximize () (setq gc-cons-threshold most-positive-fixnum)) (add-hook 'minibuffer-setup-hook #'hook--gc-cons-maximize) (defun hook--gc-cons-baseline () (setq gc-cons-threshold gc-cons-threshold-basis)) (add-hook 'minibuffer-exit-hook #'hook--gc-cons-baseline) (defun hook--gc-when-unfocused () (acdw/when-unfocused #'garbage-collect)) (add-function :after after-focus-change-function #'hook--gc-when-unfocused) ;;; init.el ends here