emacs/init.el

587 lines
19 KiB
EmacsLisp
Raw Normal View History

;;; init.el -*- lexical-binding: t; coding: utf-8-unix -*-
2021-02-26 17:31:50 +00:00
;; Author: Case Duckworth <acdw@acdw.net>
2021-03-01 05:58:57 +00:00
;; Created: Sometime during Covid-19, 2020
2021-02-26 17:31:50 +00:00
;; Keywords: configuration
2021-03-08 04:14:38 +00:00
;; URL: https://tildegit.org/acdw/emacs
;; Bankruptcy: 6
2021-03-16 16:16:21 +00:00
2021-03-01 05:58:57 +00:00
;; This file is NOT part of GNU Emacs.
2021-03-16 16:16:21 +00:00
2021-03-01 05:58:57 +00:00
;;; 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.
2021-03-16 16:16:21 +00:00
2021-03-01 05:58:57 +00:00
;;; Code:
2021-02-26 17:31:50 +00:00
;;; `setup' -- configuration macro
(straight-use-package '(setup :host nil
2021-03-30 04:21:58 +00:00
:repo "https://git.sr.ht/~zge/setup"))
(require 'setup)
;; shorthand for `customize-set-variable' (via setup)
(defmacro setc (&rest args)
"Customize user options using ARGS like `setq'."
(declare (debug setq))
`(setup (:option ,@args)))
;; Install packages with `straight-use-package'
(setup-define :straight
(lambda (recipe)
`(straight-use-package ',recipe))
:documentation "Install RECIPE with `straight-use-package'."
:repeatable t
:shorthand (lambda (sexp)
(let ((recipe (cadr sexp)))
(if (consp recipe)
(car recipe)
recipe))))
;; Bind keys to `acdw/map'
(setup-define :acdw/map
(lambda (key command)
`(progn
(autoload #',command (symbol-name setup-name))
(define-key acdw/map
,(if (stringp key) (kbd key) key)
#',command)))
:documentation "Bind KEY to COMMAND in `acdw/map'."
:debug '(form sexp)
:repeatable t)
;; Bind keys to `acdw/leader'
(setup-define :acdw/leader
(lambda (key command)
`(progn
(autoload #',command (symbol-name setup-name))
(define-key acdw/leader
,(if (stringp key) (kbd key) key)
#',command)))
:documentation "Bind KEY to COMMAND in `acdw/leader' map."
:debug '(form sexp)
:repeatable t)
;; Bind keys, and autoload the functions they're bound to.
(setup-define :bind-autoload
(lambda (key command)
`(progn
(autoload #',command (symbol-name setup-name))
(define-key (symbol-value setup-map)
2021-03-30 04:21:58 +00:00
,(if (stringp key) (kbd key) key)
#',command)))
:documentation "Bind KEY to COMMAND, and autload COMMAND from FEATURE."
:debug '(form sexp)
:repeatable t)
2021-03-09 04:40:23 +00:00
;;; About me
(setc 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)
2021-03-09 04:40:23 +00:00
2021-03-08 22:58:18 +00:00
;;; Good defaults
;; Lines
(setc fill-column 80
word-wrap t
truncate-lines nil)
2021-03-08 22:58:18 +00:00
(add-hook 'text-mode-hook #'turn-on-auto-fill)
(add-hook 'prog-mode-hook #'turn-on-auto-fill)
(global-display-fill-column-indicator-mode +1)
2021-03-08 22:58:18 +00:00
(global-so-long-mode +1)
2021-03-11 18:08:23 +00:00
2021-03-08 22:58:18 +00:00
;; Whitespace
(setc whitespace-style
'(empty indentation space-before-tab space-after-tab)
indent-tabs-mode nil
tab-width 4
smie-indent-basic tab-width)
(add-hook 'before-save-hook #'whitespace-cleanup)
2021-03-08 22:58:18 +00:00
;; Pairs
(setc show-paren-delay 0
show-paren-style 'mixed
show-paren-when-point-inside-paren t
show-paren-when-point-in-periphery t)
2021-03-08 22:58:18 +00:00
(show-paren-mode +1)
(add-hook 'prog-mode-hook #'electric-pair-local-mode)
2021-03-08 22:58:18 +00:00
;; Killing and yanking
(setc 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)
2021-03-08 22:58:18 +00:00
(delete-selection-mode +1)
;; Encoding
(setc local-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))
2021-03-08 22:58:18 +00:00
(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)
;; Uniquify
(setup (:require uniquify)
2021-03-30 04:21:58 +00:00
(:option uniquify-buffer-name-style 'forward
uniquify-separator path-separator
uniquify-after-kill-buffer-p t
uniquify-ignore-buffers-re "^\\*"))
;; Files
(setc backup-directory-alist `((".*" . ,(acdw/in-dir "backup/" t)))
tramp-backup-directory-alist backup-directory-alist
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)
backup-by-copying t
delete-old-versions t
version-control t
vc-make-backup-files t)
2021-03-08 22:58:18 +00:00
(auto-save-visited-mode +1)
2021-03-11 14:24:54 +00:00
(add-function :after after-focus-change-function
(defun hook--auto-save-when-unfocused ()
"Save all buffers when out of focus."
(acdw/when-unfocused #'save-some-buffers t)))
(setup (:require autorevert)
2021-03-30 04:21:58 +00:00
(global-auto-revert-mode +1))
(setup (:require saveplace)
2021-03-30 04:21:58 +00:00
(:option save-place-file (acdw/in-dir "places.el")
save-place-forget-unreadable-files (eq acdw/system :home))
2021-03-09 04:40:23 +00:00
(save-place-mode +1))
(setup (:require recentf)
2021-03-30 04:21:58 +00:00
(:option recentf-save-file (acdw/in-dir "recentf.el")
recentf-max-menu-items 100
recentf-max-saved-items nil
recentf-auto-cleanup 60
(append recentf-exclude) acdw/dir)
(recentf-mode +1))
2021-03-09 04:40:23 +00:00
;; Minibuffer
(setc minibuffer-prompt-properties
2021-03-30 04:21:58 +00:00
'(read-only t cursor-intangible t face minibuffer-prompt)
enable-recursive-minibuffers t
file-name-shadow-properties '(invisible t intangible t)
read-answer-short t)
(minibuffer-depth-indicate-mode +1)
(file-name-shadow-mode +1)
(fset 'yes-or-no-p #'y-or-n-p)
(setup (:require savehist)
2021-03-30 04:21:58 +00:00
(:option (append savehist-additional-variables) 'kill-ring
(append savehist-additional-variables) 'search-ring
(append savehist-additional-variables) 'regexp-search-ring
history-length t
history-delete-duplicates t
savehist-autosave-interval 6
savehist-file (acdw/in-dir "savehist.el"))
(savehist-mode +1))
2021-03-08 22:58:18 +00:00
(setup (:require icomplete)
2021-03-30 04:21:58 +00:00
(:option 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
completion-styles '(partial-completion substring flex))
(fido-mode -1)
(icomplete-mode +1))
(setup imenu
2021-03-30 04:21:58 +00:00
(:option imenu-auto-rescan t))
2021-03-08 22:58:18 +00:00
;; Cursor
(setc cursor-type 'bar
cursor-in-non-selected-windows 'hollow)
2021-03-08 22:58:18 +00:00
2021-03-11 14:24:54 +00:00
;; Scrolling
(setc auto-window-vscroll nil
fast-but-imprecise-scrolling t
scroll-margin 0
scroll-conservatively 101
scroll-preserve-screen-position 1)
2021-03-30 17:30:51 +00:00
;; Fonts
(set-face-attribute 'default nil
:font (pcase acdw/system
(:home "DejaVu Sans Mono-10")
(:work "Consolas-10")
(:other "monospace-10")))
(set-face-attribute 'fixed-pitch nil
:inherit 'default)
(set-face-attribute 'variable-pitch nil
:font (pcase acdw/system
(:home "DejaVu Sans")
(:work "Calibri-11")
(:other "sans-serif")))
;; MS Windows
(setc w32-allow-system-shell t
w32-pass-lwindow-to-system nil
w32-lwindow-modifier 'super
w32-pass-rwindow-to-system nil
w32-rwindow-modifier 'super
w32-pass-apps-to-system nil
w32-apps-modifier 'hyper)
;; Dired
(setup dired
2021-03-30 04:21:58 +00:00
(:option dired-recursive-copies 'always
dired-recursive-deletes 'always
delete-by-moving-to-trash t
dired-listing-switches "-Al"
ls-lisp-dirs-first t
dired-ls-F-marks-symlinks t
dired-no-confirm '(byte-compile
chgrp chmod chown copy
hardlink load move
shell touch symlink)
dired-dwim-target t)
(:also-load dired-x)
(:hook dired-hide-details-mode
hl-line-mode)
(:acdw/map "C-x C-j" dired-jump))
2021-03-30 04:21:58 +00:00
;;;; Web browsing
(when (eq acdw/system :work)
(add-to-list 'exec-path "C:/Program Files/Mozilla Firefox"))
(setup browse-url
(:option browse-url-browser-function 'eww-browse-url
browse-url-secondary-browser-function (if (executable-find "firefox")
'browse-url-firefox
'browse-url-default-browser)
browse-url-new-window-flag t
browse-url-firefox-new-window-is-tab t))
(setup shr
2021-03-30 04:22:45 +00:00
(:option shr-width fill-column
shr-max-width fill-column
2021-03-30 04:21:58 +00:00
shr-max-image-proportion 0.6
shr-image-animate t
shr-discard-aria-hidden t))
(add-hook 'text-mode-hook #'goto-address-mode)
(add-hook 'prog-mode-hook #'goto-address-prog-mode)
;; Eshell
(setup eshell
2021-03-30 04:21:58 +00:00
(:option eshell-directory-name (acdw/in-dir "eshell/" t)
eshell-aliases-file (acdw/in-dir "eshell/aliases" t)))
2021-03-25 20:41:27 +00:00
;; Garbage collection
(add-hook 'minibuffer-setup-hook #'acdw/gc-disable)
(add-hook 'minibuffer-exit-hook #'acdw/gc-enable)
(add-function :after after-focus-change-function
(defun hook--gc-when-unfocused ()
(acdw/when-unfocused #'garbage-collect)))
;; Etc. good defaults
(setc custom-file (acdw/in-dir "custom.el")
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")
default-directory (expand-file-name "~/")
disabled-command-function nil
load-prefer-newer t
comp-async-report-warnings-errors nil
2021-03-30 04:21:58 +00:00
frame-title-format "%b %+%* GNU Emacs"
use-dialog-box nil
use-file-dialog nil
inhibit-startup-echo-area-message (pcase acdw/system
(:home "acdw")
(:work "aduckworth")
(:other (getenv "USER"))))
;; Etc. bindings
(autoload 'ehelp-command "ehelp" nil nil 'keymap)
(define-key acdw/map (kbd "C-h") 'ehelp-command)
(define-key acdw/map [remap just-one-space] #'cycle-spacing)
(define-key acdw/map (kbd "M-/") #'hippie-expand)
(define-key acdw/map (kbd "M-=") #'count-words)
(define-key acdw/map (kbd "C-x C-b") #'ibuffer)
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;; Here ends the package-less configuration. Everything following requires a
;;; package to be downloaded. ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;; Interactivity
;;;; Begin-end
(setup (:straight beginend)
2021-03-30 04:21:58 +00:00
(beginend-global-mode +1))
;;;; Expand-region
(setup (:straight expand-region)
2021-03-30 04:21:58 +00:00
(:acdw/map "C-=" er/expand-region))
;;;; CRUX
(setup (:straight crux)
2021-03-30 04:21:58 +00:00
(:with-map acdw/map
(:bind "M-o" crux-other-window-or-switch-buffer)
(:bind "C-a" crux-move-beginning-of-line)
(:bind "C-k" crux-kill-and-join-forward))
(crux-reopen-as-root-mode +1))
;;; Functionality
2021-03-30 04:21:58 +00:00
;;;; Async
(setup (:straight async)
(autoload 'dired-async-mode "dired-async.el" nil t)
(dired-async-mode +1))
;;;; Undo-fu
(setup (:straight undo-fu)
2021-03-30 04:21:58 +00:00
(:with-map acdw/map
(:bind "C-/" undo-fu-only-undo
"C-?" undo-fu-only-redo)))
(setup (:straight undo-fu-session)
2021-03-30 04:21:58 +00:00
(:option undo-fu-session-incompatible-files '("/COMMIT_EDITMSG\\'"
"/git-rebase-todo\\'")
undo-fu-session-directory (acdw/in-dir "undo/" t))
(global-undo-fu-session-mode +1))
2021-03-27 05:03:43 +00:00
2021-03-11 14:24:54 +00:00
;;; Minibuffer
;;;; Icomplete-vertical
(setup (:straight icomplete-vertical)
2021-03-30 04:21:58 +00:00
(let ((map icomplete-minibuffer-map))
(let ((command #'icomplete-forward-completions))
(define-key map (kbd "<down>") command)
(define-key map (kbd "C-n") command))
(let ((command #'icomplete-backward-completions))
(define-key map (kbd "<up>") command)
(define-key map (kbd "C-p") command))
(define-key map (kbd "RET") #'icomplete-force-complete-and-exit)
(define-key map (kbd "C-RET") #'minibuffer-complete-and-exit))
(icomplete-vertical-mode +1))
;;;; Orderless
(setup (:straight orderless)
2021-03-30 04:21:58 +00:00
(:option (prepend completion-styles) 'orderless))
;;;; Consult
(setup (:straight consult)
2021-03-30 04:21:58 +00:00
(:with-map acdw/map
(:bind-autoload
;; 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
"<f1> a" consult-apropos
"C-h a" consult-apropos))
(autoload 'consult-register-preview "consult")
(:option register-preview-delay 0
register-preview-function #'consult-register-preview))
;;;; Marginalia
(setup (:straight marginalia)
2021-03-30 04:21:58 +00:00
(:option marginalia-annotators '(marginalia-annotators-heavy
marginalia-annotators-light))
(marginalia-mode +1))
;;; UI
;;;; Modus themes
(setup (:straight (modus-themes
:host gitlab
:repo "protesilaos/modus-themes"))
2021-03-30 04:21:58 +00:00
(:option 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-mode-line nil)
(acdw/sunrise-sunset #'modus-themes-load-operandi
#'modus-themes-load-vivendi))
;;;; Mode line
(setup (:straight simple-modeline)
2021-03-30 04:21:58 +00:00
(setup (:straight minions))
(:option simple-modeline-segments
'((acdw-modeline/modified
acdw-modeline/buffer-name
acdw-modeline/vc-branch
simple-modeline-segment-position
simple-modeline-segment-word-count)
(simple-modeline-segment-misc-info
simple-modeline-segment-process
acdw-modeline/god-mode-indicator
acdw-modeline/minions
simple-modeline-segment-major-mode)))
(require 'acdw-modeline)
(simple-modeline-mode +1))
;;; Utilities
;;;; 0x0 -- upload files to a nullpointer
(setup (:straight (0x0 :host nil
:repo "https://git.sr.ht/~zge/nullpointer-emacs"))
2021-03-30 04:21:58 +00:00
(:option 0x0-default-host 'ttm))
;;; Applications
;;;; Magit
(setup (:straight magit)
2021-03-30 04:21:58 +00:00
(:acdw/leader "g" magit-status)
(:option magit-display-buffer-function
(defun magit-display-buffer-same-window (buffer)
"Display BUFFER in the selected window like God intended."
(display-buffer buffer '(display-buffer-same-window)))
magit-popup-display-buffer-action '((display-buffer-same-window))))
2021-03-11 14:24:54 +00:00
;;;; File browsing
(setup (:straight dired-subtree)
2021-03-30 04:21:58 +00:00
(define-key dired-mode-map "i" #'dired-subtree-toggle))
2021-03-11 18:10:54 +00:00
(setup (:straight dired-collapse)
2021-03-30 04:21:58 +00:00
(:hook-into dired-mode))
2021-03-30 04:21:58 +00:00
(setup (:straight trashed)
(:option trashed-action-confirmer 'y-or-n-p))
;;;; Gemini/gopher browsing
(setup (:straight (elpher :host nil
:repo "git://thelambdalab.xyz/elpher.git"))
2021-03-30 04:21:58 +00:00
(:option elpher-ipv4-always t
elpher-certificate-directory (acdw/in-dir "elpher/"))
(:bind "n" elpher-next-link
"p" elpher-prev-link
"o" elpher-follow-current-link
"G" elpher-go-current)
(:hook acdw/reading-mode)
(when (boundp 'god-exempt-major-modes)
(:option (append god-exempt-major-modes) 'elpher-mode)))
(setup (:straight (gemini-mode
:host nil
:repo "https://git.carcosa.net/jmcbray/gemini.el.git"))
2021-03-30 04:21:58 +00:00
(:option (append auto-mode-alist)
'("\\.\\(gemini\\|gmi\\)\\'" . gemini-mode)))
;;;; Read e-books (nov.el)
(setup (:straight nov)
2021-03-30 04:21:58 +00:00
(:option nov-text-width fill-column
(append auto-mode-alist) '("\\.epub\\'" . nov-mode)))
;;;; Org mode
(setup (:straight (org :host nil
:repo "https://code.orgmode.org/bzg/org-mode.git"))
2021-03-30 04:21:58 +00:00
(require 'acdw-org)
(:option 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)
(:bind "RET" unpackaged/org-return-dwim)
(add-hook 'before-save-hook #'acdw/hook--org-mode-fix-blank-lines))
2021-03-12 23:20:49 +00:00
2021-03-11 18:16:20 +00:00
;;; Programming languages
;;;; Formatting
(setup (:straight (apheleia :host github
:repo "raxod502/apheleia"))
2021-03-30 04:21:58 +00:00
(apheleia-global-mode +1))
;;;; Emacs lisp
(setup emacs-lisp
(:option eval-expression-print-length nil
eval-expression-print-level nil
2021-03-30 04:21:58 +00:00
lisp-indent-function #'lisp-indent-function))
2021-03-11 18:16:20 +00:00
;;;; Shell scripts
(setup sh
2021-03-30 04:21:58 +00:00
(:option sh-basic-offset tab-width
sh-indent-after-case 0
sh-indent-for-case-alt '+
sh-indent-for-case-label 0)
(:local-set indent-tabs-mode t)
(when (executable-find "shfmt")
2021-03-30 04:21:58 +00:00
(with-eval-after-load 'apheleia
(:option (append apheleia-formatters) '(shfmt . ("shfmt"))
(append apheleia-mode-alist) '(sh-mode . shfmt))))
(when (executable-find "shellcheck")
(straight-use-package 'flymake-shellcheck)
(:hook flymake-mode
flymake-shellcheck-load)))
;;;; Web languages
(setup (:straight web-mode)
2021-03-30 04:21:58 +00:00
(:option css-level-offset 2
js-indent-level 2
sgml-indent-offset 2)
(dolist (extension '("\\(p\\|dj\\)?html"
"html?"
"\\(tpl\\.\\)?php"
"[agj]sp"
"as[cp]x"
"erb"
"mustache"))
(add-to-list 'auto-mode-alist
`(,(concat "\\." extension "\\'") . web-mode))))
2021-03-11 18:16:50 +00:00
2021-03-11 14:24:54 +00:00
;;; init.el ends here