emacs/init.el

1033 lines
34 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
2021-04-06 23:30:49 +00:00
;; Bankruptcy: 7
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
;;; License:
2021-03-01 05:58:57 +00:00
;; 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
;;; Code:
2021-04-16 04:23:32 +00:00
2021-04-06 22:59:45 +00:00
;;; Necessary packages
2021-02-26 17:31:50 +00:00
;;; `setup'
2021-04-06 22:59:45 +00:00
(progn
(straight-use-package '(setup :host nil
:repo "https://git.sr.ht/~zge/setup"))
(require 'setup))
(setup-define :straight
(lambda (recipe)
2021-04-22 16:50:19 +00:00
`(or (ignore-errors (straight-use-package ',recipe))
(progn
(message "Straight error: %S" ',recipe)
(throw 'setup-exit nil))))
2021-04-10 22:24:08 +00:00
:documentation "Install RECIPE with `straight-use-package'."
:repeatable t
:shorthand (lambda (sexp)
(let ((recipe (cadr sexp)))
(if (consp recipe)
(car recipe)
recipe))))
2021-04-06 22:59:45 +00:00
(setup-define :leader
(lambda (key command)
`(progn
(autoload #',command (symbol-name setup-name))
(define-key acdw/leader
,(if (stringp key) (kbd key) key)
2021-04-10 22:24:08 +00:00
#',command)))
:documentation "Bind KEY to COMMAND in `acdw/leader' (C-z) map."
:repeatable t)
;;; `no-littering'
2021-04-06 22:59:45 +00:00
(setup (:straight no-littering)
(:option no-littering-etc-directory (acdw/dir)
no-littering-var-directory (acdw/dir))
(require 'no-littering))
;;; My packages
(when-let ((default-directory
2021-04-20 04:46:24 +00:00
(expand-file-name-exists-p "pkg/" user-emacs-directory)))
(normal-top-level-add-subdirs-to-load-path))
2021-04-03 14:46:48 +00:00
;;; Good defaults
2021-04-06 22:59:45 +00:00
(defmacro setc (&rest args)
"Customize user options using ARGS like `setq'."
(declare (debug setq))
`(setup (:option ,@args)))
(setup emacs
;; Me
(:option 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)
;; Lines
2021-04-07 05:14:08 +00:00
(:option fill-column 79
2021-04-06 22:59:45 +00:00
word-wrap t
truncate-lines nil)
(global-display-fill-column-indicator-mode +1)
(global-so-long-mode +1)
(add-hook 'visual-line-mode-hook
(defun acdw/disable-fill-column-indicator ()
(display-fill-column-indicator-mode
(if visual-line-mode -1 +1))))
2021-04-06 22:59:45 +00:00
;; Whitespace
(:option whitespace-style
'(empty indentation space-before-tab space-after-tab)
indent-tabs-mode nil
tab-width 4
backward-delete-char-untabify-method 'hungry)
2021-04-06 22:59:45 +00:00
(add-hook 'before-save-hook #'whitespace-cleanup)
;; Killing and yanking
(:option 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)
(delete-selection-mode +1)
;; Encoding
(:option locale-coding-system 'utf-8-unix
2021-04-06 22:59:45 +00:00
coding-system-for-read 'utf-8-unix
coding-system-for-write 'utf-8-unix
buffer-file-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))
(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)
(pcase acdw/system
(:work (set-clipboard-coding-system 'utf-16-le)
(set-selection-coding-system 'utf-16-le))
(_ (set-selection-coding-system 'utf-8)
(set-clipboard-coding-system 'utf-8)))
2021-04-06 22:59:45 +00:00
;; Cursor
(:option cursor-type 'bar
2021-04-06 23:30:49 +00:00
cursor-in-non-selected-windows 'hollow
2021-04-07 05:45:10 +00:00
blink-cursor-blinks 1)
2021-04-06 23:30:49 +00:00
(blink-cursor-mode +1)
2021-04-06 22:59:45 +00:00
;; Scrolling
(:option auto-window-vscroll nil
fast-but-imprecise-scrolling t
scroll-margin 0
scroll-conservatively 101
scroll-preserve-screen-position 1)
;; Minibuffer
(:option minibuffer-prompt-properties
'(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)
(add-hook 'minibuffer-setup-hook #'acdw/gc-disable)
(add-hook 'minibuffer-exit-hook #'acdw/gc-enable)
2021-04-06 22:59:45 +00:00
(minibuffer-depth-indicate-mode +1)
(file-name-shadow-mode +1)
(minibuffer-electric-default-mode +1)
2021-04-06 22:59:45 +00:00
(fset 'yes-or-no-p #'y-or-n-p)
;; Completion
(: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)
completion-category-defaults nil
completion-category-overrides
'((file (styles . (partial-completion)))))
;; (icomplete-mode +1)
2021-04-06 22:59:45 +00:00
;; Emoji
(let ((ffl (font-family-list)))
(dolist (emoji-font '("Segoe UI Emoji"
"Noto Color Emoji"
"Apple Color Emoji"
"Symbola"))
(when (member emoji-font ffl)
(set-fontset-font t 'symbol
(font-spec :family emoji-font) nil 'append))))
2021-04-06 22:59:45 +00:00
;; Etc.
2021-04-12 17:53:22 +00:00
(:option inhibit-startup-screen t
2021-04-06 22:59:45 +00:00
initial-buffer-choice t
initial-scratch-message (concat ";; Howdy, "
(nth 0 (split-string
user-full-name))
"! "
"Welcome to GNU Emacs.\n\n")
initial-major-mode 'emacs-lisp-mode
2021-04-06 22:59:45 +00:00
disabled-command-function nil
load-prefer-newer t
comp-async-report-warnings-errors nil
2021-04-14 15:03:47 +00:00
frame-title-format '((:eval (if-let ((bn buffer-file-name))
(abbreviate-file-name bn)
"%b"))
" %+%* GNU Emacs"
2021-04-06 22:59:45 +00:00
(:eval (when (frame-parameter
nil 'client)
" Client")))
tab-bar-show 1
use-dialog-box nil
use-file-dialog nil
2021-04-19 05:21:36 +00:00
echo-keystrokes 0.01
2021-04-06 22:59:45 +00:00
recenter-positions '(top middle bottom)
attempt-stack-overflow-recovery nil
attempt-orderly-shutdown-on-fatal-signal nil
window-resize-pixelwise t
find-function-C-source-directory
(pcase acdw/system
(:work (expand-file-name (concat "~/src/emacs-"
emacs-version
"/src")))
(:home (expand-file-name
"~/src/pkg/emacs/src/emacs-git/src"))
(:other nil))
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
visible-bell nil
ring-bell-function #'flash-mode-line
view-read-only t)
(defun flash-mode-line ()
"Flash the modeline as a bell."
(when (eq acdw/system :home)
(beep))
(invert-face 'mode-line)
(run-with-timer 0.1 nil #'invert-face 'mode-line))
2021-04-06 22:59:45 +00:00
(when-unfocused garbage-collect
(garbage-collect))
(tooltip-mode -1)
(winner-mode +1)
(add-hook 'view-mode-hook (defun acdw/read-view-mode ()
(acdw/reading-mode (if view-mode +1 -1))))
2021-04-21 16:50:18 +00:00
;;; Bindings
2021-04-06 22:59:45 +00:00
(:global "M-SPC" cycle-spacing
"M-/" hippie-expand
"M-=" count-words
2021-04-07 17:56:14 +00:00
"C-x C-b" ibuffer
"C-c i" acdw/find-emacs-dotfiles
2021-04-21 16:50:18 +00:00
"C-x k" acdw/kill-a-buffer)
(:leader "C-c" save-buffers-kill-emacs
"t" acdw/insert-iso-date)
2021-04-22 17:53:19 +00:00
2021-04-21 16:50:18 +00:00
;;; Advice
;; `acdw/kill-line-and-join-advice' cribs from `crux-kill-and-join-forward'.
;; I can't simply advise `kill-line' with an override from crux because crux
;; itself calls `kill-line', leading to a infinite nesting situation.
(advice-add 'kill-line :around
(defun acdw/kill-line-and-join-advice (orig &rest args)
"If at end of line, join with following; otherwise kill line."
(if (and (eolp) (not (bolp)))
(delete-indentation 1)
(apply orig args)))))
2021-04-06 22:59:45 +00:00
;; Regular modes (`text-mode', `prog-mode', etc.)
(defun acdw/setup-regular-modes ()
(setq-local indicate-empty-lines t
indicate-buffer-boundaries '((top . right)
(bottom . right))))
(setup text
(:hook turn-on-auto-fill
acdw/setup-regular-modes))
(setup prog
(:option smie-indent-basic tab-width)
(hook-defun auto-fill-prog-mode prog-mode-hook
(setq-local comment-auto-fill-only-comments t)
(turn-on-auto-fill))
(:option show-paren-delay 0
show-paren-style 'mixed
show-paren-when-point-inside-paren t
show-paren-when-point-in-periphery t)
(:hook show-paren-mode
electric-pair-local-mode
acdw/setup-regular-modes)
(add-hook 'after-save-hook
#'executable-make-buffer-file-executable-if-script-p))
2021-04-12 17:53:22 +00:00
(setup cus-edit
(:option custom-file (acdw/dir "custom.el")
custom-magic-show nil
custom-magic-show-button t
custom-unlispify-tag-names nil
custom-variable-default-form 'edit))
2021-04-06 22:59:45 +00:00
(setup 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 "^\\*"))
2021-04-06 22:59:45 +00:00
(setup files
(:option backup-directory-alist `((".*" . ,(acdw/dir "backup/" t)))
tramp-backup-directory-alist backup-directory-alist
auto-save-file-name-transforms `((".*" ,(acdw/dir "auto-save/" t) t))
auto-save-list-file-prefix (acdw/dir "auto-save-list/.saves-" t)
backup-by-copying t
delete-old-versions t
version-control t
vc-make-backup-files t)
(auto-save-visited-mode +1)
(when-unfocused save-some-buffers
(save-some-buffers t)))
(setup autorevert
2021-03-30 04:21:58 +00:00
(global-auto-revert-mode +1))
2021-04-06 22:59:45 +00:00
(setup saveplace
(:option save-place-file (acdw/dir "places.el")
2021-03-30 04:21:58 +00:00
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-04-06 22:59:45 +00:00
(:option recentf-save-file (acdw/dir "recentf.el")
2021-03-30 04:21:58 +00:00
recentf-max-menu-items 100
recentf-max-saved-items nil
recentf-auto-cleanup 60
2021-04-06 22:59:45 +00:00
(append recentf-exclude) (acdw/dir))
(recentf-mode +1))
2021-03-09 04:40:23 +00:00
(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
2021-04-06 22:59:45 +00:00
savehist-file (acdw/dir "savehist.el"))
(savehist-mode +1))
2021-03-08 22:58:18 +00:00
(setup imenu
2021-03-30 04:21:58 +00:00
(:option imenu-auto-rescan t))
2021-03-08 22:58:18 +00:00
(setup isearch
(:option search-default-mode t))
2021-03-31 22:59:49 +00:00
(setup debugger
(:hook visual-line-mode)
2021-04-06 22:59:45 +00:00
(:leader "d" toggle-debug-on-error))
2021-03-31 22:59:49 +00:00
2021-04-06 22:59:45 +00:00
(setup eldoc
(:option eldoc-idle-delay 0.1
eldoc-echo-area-use-multiline-p nil))
2021-04-01 21:35:26 +00:00
(setup flyspell
(setq-default ispell-program-name "hunspell"
ispell-dictionary "en_US"
ispell-personal-dictionary "~/.hunspell_personal")
2021-04-06 22:59:45 +00:00
(:needs ispell-program-name) ; don't proceed if not installed
2021-04-01 21:35:26 +00:00
(unless (file-exists-p ispell-personal-dictionary)
(write-region "" nil ispell-personal-dictionary nil 0))
(defun flyspell-start ()
"Start `flyspell-mode' or `flyspell-prog-mode', depending on current mode."
(interactive)
(cond ((derived-mode-p 'text-mode)
(flyspell-mode))
((derived-mode-p 'prog-mode)
(flyspell-prog-mode))
(t (message "Non-text or -prog mode. Run `flyspell-mode'."))))
(:leader "s" flyspell-start))
2021-04-07 05:14:08 +00:00
(setup scratch
(hook-defun immortal-scratch kill-buffer-query-functions
2021-04-07 05:45:10 +00:00
(if (eq (current-buffer) (get-buffer "*scratch*"))
2021-04-07 05:14:08 +00:00
(progn (bury-buffer)
nil)
t)))
(setup re-builder
;; https://karthinks.com/software/bridging-islands-in-emacs-1/
(defvar acdw/re-builder-positions nil
"Store point and region bounds before calling re-builder")
(advice-add 're-builder
:before
(defun acdw/re-builder-save-state (&rest _)
"Save into `acdw/re-builder-positions' the point and region
positions before calling `re-builder'."
(setq acdw/re-builder-positions
(cons (point)
(when (region-active-p)
(list (region-beginning)
(region-end)))))))
(defun reb-replace-regexp (&optional delimited)
"Run `query-replace-regexp' with the contents of re-builder. With
non-nil optional argument DELIMITED, only replace matches
surrounded by word boundaries."
(interactive "P")
(reb-update-regexp)
(let* ((re (reb-target-binding reb-regexp))
(replacement (query-replace-read-to
re
(concat "Query replace"
(if current-prefix-arg
(if (eq current-prefix-arg '-) " backward" " word")
"")
" regexp"
(if (with-selected-window reb-target-window
(region-active-p)) " in region" ""))
t))
(pnt (car acdw/re-builder-positions))
(beg (cadr acdw/re-builder-positions))
(end (caddr acdw/re-builder-positions)))
(with-selected-window reb-target-window
(goto-char pnt) ; replace with (goto-char (match-beginning 0)) if you want
; to control where in the buffer the replacement starts
; with re-builder
(setq acdw/re-builder-positions nil)
(reb-quit)
(query-replace-regexp re replacement delimited beg end))))
(:global "C-M-%" re-builder)
(dolist (map '(reb-mode-map reb-lisp-mode-map))
(let ((setup-map map))
(:bind "RET" reb-replace-regexp
"M-n" reb-next-match
"M-p" reb-prev-match
"M-q" reb-quit))))
2021-04-03 14:45:59 +00:00
2021-04-20 21:24:06 +00:00
;;; Applications
2021-04-06 22:59:45 +00:00
2021-04-03 14:45:59 +00:00
(setup (:straight (org :host nil
:repo "https://code.orgmode.org/bzg/org-mode.git"))
2021-04-19 21:16:46 +00:00
(require 'acdw-org) ; so I don't clutter up init.el
2021-04-18 04:01:42 +00:00
(:option org-adapt-indentation nil
2021-04-03 14:45:59 +00:00
org-catch-invisible-edits 'smart
2021-04-18 04:01:42 +00:00
org-confirm-babel-evaluate nil
org-export-coding-system 'utf-8-unix
2021-04-03 14:45:59 +00:00
org-export-headline-levels 8
2021-04-18 04:01:42 +00:00
org-export-with-section-numbers nil
2021-04-03 14:45:59 +00:00
org-export-with-smart-quotes t
2021-04-12 17:59:14 +00:00
org-export-with-sub-superscripts t
2021-04-18 04:01:42 +00:00
org-export-with-toc nil
org-fontify-done-headline t
org-fontify-quote-and-verse-blocks t
org-fontify-whole-heading-line t
org-hide-emphasis-markers t
2021-04-12 17:59:14 +00:00
org-html-coding-system 'utf-8-unix
2021-04-18 04:01:42 +00:00
org-imenu-depth 3
org-pretty-entities t
org-special-ctrl-a/e t
org-special-ctrl-k t
org-src-fontify-natively t
org-src-tab-acts-natively t
org-src-window-setup 'current-window
org-startup-truncated nil
org-tags-column (- 0 fill-column -3)
org-directory "~/org")
2021-04-19 21:16:46 +00:00
(:bind "RET" acdw-org/return-dwim
"<S-return>" acdw-org/org-table-copy-down)
2021-04-19 21:16:46 +00:00
(add-hook 'before-save-hook #'acdw-org/fix-blank-lines-in-buffer)
(advice-add 'org-delete-backward-char
:override #'acdw-org/delete-backward-char))
2021-04-03 14:45:59 +00:00
(setup eshell
2021-04-06 22:59:45 +00:00
(:option eshell-directory-name (acdw/dir "eshell/" t)
eshell-aliases-file (acdw/dir "eshell/aliases" t))
2021-04-03 14:45:59 +00:00
(defun eshell-quit-or-delete-char (arg)
"Delete the character to the right, or quit eshell on an empty line."
(interactive "p")
(if (and (eolp) (looking-back eshell-prompt-regexp))
(eshell-life-is-too-much)
(delete-forward-char arg)))
2021-04-22 22:15:32 +00:00
(global-set-key (kbd "<f12>") #'eshell)
2021-04-06 22:59:45 +00:00
(hook-defun eshell-setup 'eshell-mode-hook
2021-04-22 22:15:32 +00:00
(define-key eshell-mode-map (kbd "<f12>") #'bury-buffer)
(define-key eshell-mode-map (kbd "C-d") #'eshell-quit-or-delete-char)
2021-04-21 14:36:30 +00:00
(when (boundp 'simple-modeline--mode-line)
2021-04-06 22:59:45 +00:00
(setq mode-line-format '(:eval simple-modeline--mode-line)))))
2021-04-03 14:45:59 +00:00
(setup ediff
(:option ediff-window-setup-function 'ediff-setup-windows-plain
ediff-split-window-function 'split-window-horizontally))
(setup browse-url
(setq-default 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)
2021-04-03 14:45:59 +00:00
(when (eq acdw/system :work)
(add-to-list 'exec-path "C:/Program Files/Mozilla Firefox")))
(setup shr
(:option shr-width fill-column
shr-max-width fill-column
shr-max-image-proportion 0.6
shr-image-animate t
shr-discard-aria-hidden t))
(setup eww
(:hook acdw/reading-mode))
(setup (:straight (elpher :host nil
:repo "git://thelambdalab.xyz/elpher.git"))
(:option elpher-ipv4-always t
2021-04-06 22:59:45 +00:00
elpher-certificate-directory (acdw/dir "elpher/")
2021-04-03 14:45:59 +00:00
elpher-gemini-max-fill-width fill-column)
(:leader "e" elpher-bookmarks)
2021-04-03 14:45:59 +00:00
(:bind "n" elpher-next-link
"p" elpher-prev-link
"o" elpher-follow-current-link
"G" elpher-go-current)
(:hook acdw/reading-mode)
2021-04-18 04:01:54 +00:00
(autoload 'elpher-bookmarks "elpher" nil t)
2021-04-20 21:24:42 +00:00
(autoload 'elpher-go "elpher" nil t)
2021-04-03 14:45:59 +00:00
;; Make `eww' gemini/gopher aware. From Emacswiki.
(advice-add 'eww-browse-url :around
(defun elpher:eww-browse-url (original url &optional new-window)
"Handle gemini and gopher links."
(cond ((string-match-p "\\`\\(gemini\\|gopher\\)://" url)
(require 'elpher)
(elpher-go url))
(t (funcall original url new-window))))))
(setup (:straight (gemini-mode
:host nil
:repo "https://git.carcosa.net/jmcbray/gemini.el.git"))
(:file-match "\\.\\(gemini\\|gmi\\)\\'"))
2021-04-03 14:45:59 +00:00
(setup (:straight (gemini-write
:host nil
:repo "https://alexschroeder.ch/cgit/gemini-write"
:fork
(:repo "https://tildegit.org/acdw/gemini-write"
:branch "main")))
(with-eval-after-load 'elpher
(require 'gemini-write)))
2021-04-03 14:45:59 +00:00
(setup dired
(setq-default 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)
2021-04-03 14:45:59 +00:00
(:also-load dired-x)
(:hook dired-hide-details-mode
hl-line-mode)
(:global "C-x C-j" dired-jump)
(pcase acdw/system
(:work (:straight w32-browser)
(autoload 'dired-w32-browser "w32-browser")
(:bind "RET" dired-w32-browser))
(:home (:straight dired-open)
2021-04-25 04:23:43 +00:00
(require 'dired-open)
(:bind "RET" dired-find-alternate-file)
2021-04-25 04:23:43 +00:00
(:option (prepend dired-open-functions) #'dired-open-xdg)))
(:straight dired-subtree)
(:bind "i" dired-subtree-toggle
"TAB" dired-subtree-cycle)
(:straight dired-collapse)
(:hook dired-collapse-mode)
(:straight dired-git-info)
(:bind ")" dired-git-info-mode)
(:straight trashed)
(:option trashed-action-confirmer #'y-or-n-p))
2021-04-03 14:45:59 +00:00
(setup (:straight magit)
2021-04-07 05:14:08 +00:00
(:leader "g" magit-status)
2021-04-18 04:02:11 +00:00
(defun magit-display-buffer-same-window (buffer)
"Display BUFFER in the selected window like God intended."
(display-buffer buffer '(display-buffer-same-window)))
(:option magit-display-buffer-function #'magit-display-buffer-same-window
magit-popup-display-buffer-action '((display-buffer-same-window))
magit-refresh-status-buffer nil))
2021-04-03 14:45:59 +00:00
(setup (:straight nov)
(:option nov-text-width fill-column)
(:file-match "\\.epub\\'"))
2021-04-03 14:45:59 +00:00
2021-04-19 13:24:46 +00:00
(setup gnus
(:option gnus-home-directory (expand-file-name "gnus" user-emacs-directory)
gnus-directory (expand-file-name "gnus/News" user-emacs-directory)
gnus-init-file (expand-file-name "gnus.el" user-emacs-directory))
(when (not (file-exists-p gnus-directory))
2021-04-27 17:58:26 +00:00
(make-directory gnus-directory :parents))
(:leader "m" gnus))
2021-04-19 13:24:46 +00:00
2021-04-03 14:45:59 +00:00
(when (eq acdw/system :home)
2021-04-25 04:23:32 +00:00
;; Apparently the original repo is unmaintained, thus this fork.
(setup (:straight (pdf-tools
:host github
:repo "vedang/pdf-tools"))
2021-04-18 04:02:23 +00:00
(pdf-loader-install))
2021-04-03 14:45:59 +00:00
(setup (:straight vterm)))
2021-04-06 22:59:45 +00:00
;; Extra packages
(setup (:straight (beginend
:fork (:repo "duckwork/beginend")))
2021-03-30 04:21:58 +00:00
(beginend-global-mode +1))
2021-03-31 17:46:14 +00:00
(setup (:straight mwim)
(:global "C-a" mwim-beginning
"C-e" mwim-end))
2021-03-31 17:46:14 +00:00
(setup (:straight expand-region)
(:global "C-=" er/expand-region))
(setup (:straight crux)
2021-04-20 04:46:24 +00:00
(:global "M-`" crux-other-window-or-switch-buffer
"C-o" crux-smart-open-line
"M-o" crux-smart-open-line-above
"C-M-\\" crux-cleanup-buffer-or-region
"C-x 4 t" crux-transpose-windows)
(crux-reopen-as-root-mode +1))
2021-03-31 17:46:14 +00:00
(setup (:straight avy)
(:global "C-:" avy-goto-char
"C-'" avy-goto-char-timer
"M-g f" avy-goto-line
"M-g w" avy-goto-word-1
"C-c C-j" avy-resume)
2021-03-31 17:46:14 +00:00
(eval-after-load "isearch"
'(define-key isearch-mode-map (kbd "C-'") #'avy-isearch)))
(setup (:straight zzz-to-char)
(defun acdw/zzz-up-to-char (prefix)
"Call `zzz-up-to-char', unless issued a PREFIX, in which case
call `zzz-to-char'."
(interactive "P")
(if prefix
(call-interactively #'zzz-to-char)
(call-interactively #'zzz-up-to-char)))
2021-04-06 22:59:45 +00:00
(:global "M-z" acdw/zzz-up-to-char))
2021-03-31 17:46:14 +00:00
2021-03-30 04:21:58 +00:00
(setup (:straight async)
(autoload 'dired-async-mode "dired-async.el" nil t)
(dired-async-mode +1))
(setup (:straight undo-fu)
(:global "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\\'")
2021-04-06 22:59:45 +00:00
undo-fu-session-directory (acdw/dir "undo/" t)
undo-fu-session-compression (eq acdw/system :home))
2021-04-06 22:59:45 +00:00
(global-undo-fu-session-mode +1))
2021-03-27 05:03:43 +00:00
2021-04-16 04:23:50 +00:00
(setup (:straight (vertico
:host github
:repo "minad/vertico"))
(setq resize-mini-windows 'grow-only)
(if (boundp 'comp-deferred-compilation-deny-list)
(add-to-list 'comp-deferred-compilation-deny-list "vertico"))
(icomplete-mode -1)
(vertico-mode +1))
2021-04-16 04:23:50 +00:00
(setup (:straight (orderless
:host github
:repo "oantolin/orderless"))
(require 'orderless)
2021-03-30 04:21:58 +00:00
(:option (prepend completion-styles) 'orderless))
2021-04-16 04:23:50 +00:00
(setup (:straight (consult
:host github
:repo "minad/consult"))
2021-04-01 21:39:46 +00:00
;; "Sensible" functions
(defun consult-sensible-grep ()
"Perform `consult-git-grep' if in a git project, otherwise `consult-ripgrep'
if ripgrep is installed, otherwise `consult-grep'."
(interactive "P")
(cond ((= (vc-backend buffer-file-name) "Git")
(call-interactively #'consult-git-grep))
2021-04-05 21:59:35 +00:00
((executable-find "rg")
2021-04-01 21:39:46 +00:00
(call-interactively #'consult-ripgrep))
(t (call-interactively #'consult-grep))))
2021-04-06 22:59:45 +00:00
2021-04-01 21:39:46 +00:00
(defun consult-sensible-find ()
"Peform `consult-locate' if locate is installed, otehrwise `consult-find'."
(interactive "P")
(cond ((executable-find "locate") (call-interactively #'consult-locate))
(t (call-interactively #'consult-find))))
;; Bindings
(:global
2021-04-01 21:39:46 +00:00
;; C-c bindings (`mode-specific-map')
"C-c h" consult-history
"C-c m" consult-mode-command
"C-c b" consult-bookmark
"C-c k" consult-kmacro
;; 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
;; Custom M-# bindings for fast register access
"M-#" consult-register-load
"M-'" consult-register-store
"C-M-#" consult-register
;; M-g bindings (`goto-map')
"M-g e" consult-compile-error
"M-g g" consult-goto-line
"M-g M-g" consult-goto-line
"M-g o" consult-outline
"M-g m" consult-mark
"M-g k" consult-global-mark
"M-g i" consult-imenu
"M-g I" consult-project-imenu
;; M-s bindings (`search-map')
"M-s g" consult-sensible-grep
"M-s f" consult-sensible-find
"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
"<help> a" consult-apropos
;; Isearch integration
"M-s e" consult-isearch)
(:with-map isearch-mode-map
(:bind "M-e" consult-isearch
"M-s e" consult-isearch
"M-s l" consult-line))
;; Registers
(autoload 'consult-register-preview "consult")
(:option register-preview-delay 0
2021-04-01 21:39:46 +00:00
register-preview-function #'consult-register-format)
(:advise register-preview :override #'consult-register-window)
;; Xref
(:option xref-show-xrefs-function #'consult-xref
xref-show-definitions-function #'consult-xref)
;; Projects
2021-04-20 21:25:31 +00:00
(:option consult-project-root-function #'vc-root-dir)
;; Competion-at-point (complete-region)
(:global "M-/" completion-at-point)
(:option completion-in-region-function #'consult-completion-in-region
completion-cycle-threshold 3
tab-always-indent 'complete))
(setup (:straight marginalia)
2021-03-30 04:21:58 +00:00
(:option marginalia-annotators '(marginalia-annotators-heavy
marginalia-annotators-light))
(marginalia-mode +1))
(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))
(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))
(setup (:straight olivetti)
(:option olivetti-body-width (+ fill-column 4)
olivetti-minimum-body-width fill-column)
(add-hook 'olivetti-mode-hook
(defun acdw/olivetti-mode-hook ()
(if olivetti-mode
(setq-local indicate-empty-lines nil
indicate-buffer-boundaries nil)
(acdw/setup-regular-modes)))))
2021-04-03 14:46:48 +00:00
(setup (:straight form-feed)
(global-form-feed-mode +1))
2021-04-01 21:37:09 +00:00
(setup (:straight which-key)
(:option which-key-show-early-on-C-h t
which-key-idle-delay 10000
which-key-idle-secondary-delay 0.05)
(which-key-setup-side-window-bottom)
(which-key-mode +1))
(setup (:straight helpful)
2021-04-02 17:57:54 +00:00
(:global "<help> f" helpful-callable
"<help> v" helpful-variable
"<help> k" helpful-key
"<help> o" helpful-symbol
"C-c C-d" helpful-at-point))
(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))
(with-eval-after-load 'flyspell
(setup (:straight flyspell-correct)
(define-key flyspell-mode-map (kbd "C-;") #'flyspell-correct-wrapper)))
2021-04-01 21:35:26 +00:00
(setup (:straight (electric-cursor
:host github
:repo "duckwork/electric-cursor"))
(electric-cursor-mode +1))
2021-04-28 20:48:58 +00:00
(setup (:straight restart-emacs)
(defun upgrade-packages-and-restart ()
"Upgrade all packages and restart Emacs."
(interactive)
(straight-pull-all)
(restart-emacs)))
2021-04-10 22:30:58 +00:00
;;; Programming
2021-04-02 18:05:12 +00:00
2021-04-10 22:30:58 +00:00
;;; General tools
(setup (:straight (apheleia :host github
:repo "raxod502/apheleia"))
(apheleia-global-mode +1)
;; Use a dumb formatter on modes that `apheleia' doesn't work for.
2021-04-06 22:59:45 +00:00
(hook-defun dumb-auto-format before-save-hook
2021-04-14 23:40:05 +00:00
(setq stupid-modes '(makefile-mode))
;; If there's no apheleia formatter for the mode, just indent the buffer.
(unless (or (apply #'derived-mode-p stupid-modes)
(and (fboundp 'apheleia--get-formatter-command)
(apheleia--get-formatter-command)))
2021-04-06 22:59:45 +00:00
(indent-region (point-min) (point-max)))))
;;; Lisps
(defvar lispy-modes '(emacs-lisp-mode
eval-expression-minibuffer
ielm-mode
lisp-mode
lisp-interaction-mode
scheme-mode
slime-repl-mode)
"List of modes that are lisp-like enough to hook packages into.")
2021-04-03 14:47:58 +00:00
(setup (:straight paren-face)
(dolist (mode lispy-modes)
2021-04-12 22:57:06 +00:00
(add-hook (intern (concat (symbol-name mode) "-hook")) #'paren-face-mode)))
2021-04-03 14:47:58 +00:00
(setup (:straight paredit)
2021-04-25 04:23:15 +00:00
;; I don't use paredit-splice-sexp much, and it stomps on isearch.
(:unbind "M-s")
2021-04-25 04:23:15 +00:00
(defun setup-paredit-mode ()
"Correct weirdnesses and set up paredit mode."
(paredit-mode +1)
(define-key lisp-mode-shared-map (kbd "DEL") #'paredit-backward-delete))
(dolist (mode lispy-modes)
2021-04-25 04:23:15 +00:00
(add-hook (intern (concat (symbol-name mode) "-hook"))
#'setup-paredit-mode))
2021-04-06 22:59:45 +00:00
(require 'eldoc)
2021-04-06 22:59:45 +00:00
(eldoc-add-command 'paredit-backward-delete 'paredit-close-round))
(setup elisp-mode
(:option eval-expression-print-length nil
eval-expression-print-level nil
lisp-indent-function #'lisp-indent-function)
(defun acdw/enforce-lexical-binding ()
(setq lexical-binding t))
(add-hook 'emacs-lisp-mode-hook #'acdw/enforce-lexical-binding)
(defun acdw/eval-region-or-buffer ()
(interactive)
(if (region-active-p)
(let ((begin (region-beginning))
(end (region-end)))
(with-message (format "Evaluating %S -> %S" begin end)
(eval-region begin end)))
2021-04-21 22:54:29 +00:00
(with-message "Evaluating buffer"
(eval-buffer))))
;; Emulate slime's eval binds
(:with-map emacs-lisp-mode-map
(:bind "C-c C-c" eval-defun
"C-c C-k" acdw/eval-region-or-buffer
"C-c C-z" ielm))
(add-hook 'emacs-lisp-mode-hook 'turn-on-eldoc-mode)
2021-04-06 22:59:45 +00:00
(add-hook 'ielm-mode-hook 'turn-on-eldoc-mode)
2021-03-11 18:16:20 +00:00
2021-04-06 22:59:45 +00:00
(setup (:straight macrostep)
(define-key emacs-lisp-mode-map (kbd "C-c e") #'macrostep-expand))
2021-03-31 22:59:28 +00:00
2021-04-06 22:59:45 +00:00
(setup (:straight eros)
(:hook-into emacs-lisp-mode))
;; Add advice to pulse evaluated regions
(defun acdw/elisp-eval-region-advice (fn start end &rest args)
(pulse-momentary-highlight-region start end)
(apply fn start end args))
(advice-add 'eval-region :around #'acdw/elisp-eval-region-advice))
2021-04-09 17:50:11 +00:00
(setup (:straight geiser))
2021-04-14 23:40:05 +00:00
(when-let (lisp-bin (or (executable-find "sbcl")
(executable-find "clisp")))
2021-04-09 17:50:11 +00:00
(setup (:straight slime)
(require 'slime-autoloads)
(:option inferior-lisp-program lisp-bin)
(when-let ((slime-helper (or (expand-file-name-exists-p
"~/quicklisp/slime-helper.el")
(expand-file-name-exists-p
"~/var/quicklisp/slime-helper.el"))))
(load slime-helper))
(with-eval-after-load 'company
(setup (:straight slime-company)
(:option slime-company-completion 'fuzzy
slime-company-after-completion nil)
(slime-setup '(slime-fancy slime-company))))))
2021-04-09 17:50:11 +00:00
2021-04-03 14:47:19 +00:00
(when (executable-find "fennel")
(setup (:straight fennel-mode)
2021-04-07 05:14:08 +00:00
(autoload 'fennel-repl "fennel-mode" nil t)
(:file-match "\\.fnl\\'")))
2021-04-03 14:47:19 +00:00
(setup (:straight lua-mode)
(:file-match "\\.lua\\'"))
2021-04-03 14:48:05 +00:00
2021-03-31 22:59:28 +00:00
(setup sh-mode
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)))
(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)
(:file-match "\\.\\(p\\|dj\\)?html\\'"
"\\.html?\\'"
"\\.\\(tpl\\.\\)?php\\'"
"\\.[agj]sp\\'"
"\\.as[cp]x\\'"
"\\.erb\\'"
"\\.mustache\\'"))
2021-03-11 18:16:50 +00:00
(when (locate-library "gforth")
(autoload 'forth-mode "gforth")
(add-to-list 'auto-mode-alist '("\\.fs\\'" . forth-mode))
(autoload 'forth-block-mode "gforth")
(add-to-list 'auto-mode-alist '("\\.fb\\'" . forth-block-mode)))
2021-04-10 22:30:58 +00:00
(when (eq acdw/system :home)
(setup (:straight pkgbuild-mode)))
;;; Server
(require 'server)
(unless (server-running-p)
(server-start))