emacs/init.el

2482 lines
88 KiB
EmacsLisp
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

;;; init.el -*- lexical-binding: t; coding: utf-8-unix -*-
;; Author: Case Duckworth <(rot13-string "npqj@npqj.arg")>
;; Created: Sometime during Covid-19, 2020
;; Keywords: configuration
;; URL: https://tildegit.org/acdw/emacs
;; Bankruptcy: 7
;; 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:
;; - Be kind to yourself.
;; - Make good choices.
;;; Commentary:
;; Some of the names in these `setup' forms are arbitrary.
;;; Code:
(setup (:require auth-source)
(:option auth-sources (list (acdw/sync-dir "authinfo")
(acdw/sync-dir "authinfo.gpg")
"~/.authinfo"
"~/.authinfo.gpg")))
(setup (:require goto-addr)
(if (fboundp #'global-goto-address-mode)
(global-goto-address-mode)
(add-hook 'after-change-major-mode-hook #'goto-address-mode)))
(setup (:require recentf)
(:option recentf-save-file (acdw/dir "recentf.el")
recentf-max-menu-items 100
recentf-max-saved-items nil
recentf-auto-cleanup 'mode
(append recentf-exclude) (acdw/dir))
(:advise dired-rename-file :after #'rjs/recentf-rename-notify)
(recentf-mode +1))
(setup (:require savehist)
(:option history-length t
history-delete-duplicates t
savehist-autosave-interval 60
savehist-file (acdw/dir "savehist.el"))
(dolist (var '(extended-command-history
global-mark-ring
kill-ring
regexp-search-ring
search-ring
mark-ring))
(:option (append savehist-additional-variables) var))
(savehist-mode +1))
(setup (:require server)
(unless (server-running-p)
(server-start)))
(setup Info
(:hook #'variable-pitch-mode
#'reading-mode))
(setup abbrev
(:option abbrev-file-name "~/Sync/abbrev.el"
save-abbrevs 'silent)
(:hook-into text-mode
circe-chat-mode))
(setup acdw
(:also-load acdw-compat
acdw-lisp
acdw-reading)
(acdw/require-private)
(:option user-full-name "Case Duckworth"
user-mail-address (rot13-string "npqj@npqj.arg"))
(when-let ((default-directory
(expand-file-name-exists-p "pkg/" user-emacs-directory)))
(normal-top-level-add-subdirs-to-load-path)))
(setup autorevert
(:option global-auto-revert-non-file-buffers t
auto-revert-verbose nil)
(global-auto-revert-mode +1))
(setup browse-url
(:require acdw-browse-url)
(:option browse-url-secondary-browser-function
(if (executable-find "firefox") ; prefer Firefox
#'browse-url-firefox
#'browse-url-default-browser)
browse-url-new-window-flag nil ; for eww
browse-url-firefox-arguments '("--new-tab") ; for firefox
browse-url-firefox-new-window-is-tab t)
(acdw/browse-url-set-handlers
(list
(cons (rx (seq "." (or "jpeg" "jpg" ; images
"png")
eos))
(lambda (&rest args)
(apply
(cond ((executable-find "feh") #'browse-url-feh)
((executable-find "mpv")
(defun browse-image-url-mpv (url &rest _args)
"View an image URL in mpv."
(let ((url (browse-url-encode-url url))
(process-environment
(browse-url-process-environment)))
(message "Viewing %s in mpv..." url)
(apply #'start-process
(concat "mpv " url) nil
"mpv"
(append browse-url-mpv-arguments
(list "--image-display-duration=inf"
url))))))
(t #'eww-browse-url))
args)))
(cons (rx (or "youtube.com" ; videos
"youtu.be"
(seq "." (or "mp4"
"gif")
eos)))
(lambda (&rest args)
(apply (if (executable-find "mpv")
#'browse-url-mpv
browse-url-secondary-browser-function)
args)))
(cons (rx (or "google.com" ; websites that don't work with eww
"reddit.com"
"twitter.com"
"imgur.com"
"pixelfed"))
browse-url-secondary-browser-function)
(cons "." ; everything else
#'eww-browse-url)))
;; Buttonize gemini:// links.
(acdw/add-button-url-regexp-protocol "gemini"))
(setup buffers
(:global "C-x k" #'acdw/kill-a-buffer)
;; Set the right major mode based on buffer name, if not visiting a file.
;; http://ruzkuku.com/emacs.d.html#orgeab93c3
(setq-default major-mode (lambda ()
(unless buffer-file-name
(let ((buffer-file-name (buffer-name)))
(set-auto-mode))))))
(setup calendar
(:option calendar-week-start-day 1))
(setup completion
(:option completion-ignore-case t
read-buffer-completion-ignore-case t
completion-styles '(substring partial-completion)
completion-category-defaults nil
completion-category-overrides
'((file (styles . (partial-completion)))))
(:global "M-/" #'hippie-expand))
(setup css-mode
(:bind "C-c C-h" #'css-lookup-symbol))
(setup cursor
(:option cursor-type 'bar
cursor-in-non-selected-windows 'hollow
blink-cursor-blinks 1)
(blink-cursor-mode +1))
(setup cus-edit
(:also-load acdw-cus-edit)
(:option custom-file (acdw/dir "custom.el")
custom-magic-show nil
custom-magic-show-button t
custom-raised-buttons nil
custom-unlispify-tag-names nil
custom-variable-default-form 'lisp)
;; I need this to save `safe-local-variables' between Emacs invocations. For
;; now, of course .... I would /love/ a better solution.
(when (file-exists-p custom-file)
(load custom-file nil nil))
;; `Custom-mode-hook' fires /before/ the widgets are built, so I have to
;; install advice after the widgets are made.
(:advise custom-buffer-create-internal :after #'acdw-cus/expand-widgets)
(:with-mode Custom-mode
(:local-set imenu-generic-expression acdw-cus/imenu-generic-expression)))
(setup debugger
(:hook visual-line-mode))
(setup dired
(:also-load dired-x)
(:straight dired-subtree
dired-collapse
dired-git-info)
(:option dired-recursive-copies 'top
dired-recursive-deletes 'top
dired-create-destination-dirs 'ask
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)
(:bind "TAB" #'dired-subtree-cycle
"i" #'dired-subtree-toggle
")" #'dired-git-info-mode)
(:hook dired-collapse-mode
dired-hide-details-mode
hl-line-mode)
(:global "C-x C-j" #'dired-jump)
(with-eval-after-load 'dired
(acdw/system
(:work (:straight w32-browser)
(autoload #'dired-w32-browser "w32-browser" nil t)
(:bind "RET" #'dired-w32-browser))
(:home (:straight dired-open)
(autoload #'dired-find-alternate-file "dired-open" nil t)
(:bind "RET" #'dired-find-alternate-file)))))
(setup disabled
;; While this stuff is defined in novice.el, I'm using 'disabled' as the name
;; for easy finding.
;; Enable all disabled commands.
;; This is an option, but I'm going to try /enabling/ just the ones that I
;; use instead.
;; (mapatoms (lambda (symbol)
;; (when (get symbol 'disabled)
;; (put symbol 'disabled nil))))
;; Enable /some/ disabled commands
(dolist (enable-sym '(narrow-to-region
dired-find-alternate-file
narrow-to-page))
(put enable-sym 'disabled nil))
;; Now, disable symbols as I wish.
(dolist (disable-sym '(view-hello-file
suspend-frame
scroll-left
scroll-right
comment-set-column
set-fill-column))
(put disable-sym 'disabled t))
;; And set the disabled function to something better than the default.
;; Now, I can run any disabled command, but I have to use M-x to do it.
(:option disabled-command-function #'acdw/disabled-command-function))
(setup ediff
(:option ediff-diff-options "-w" ; ignore whitespace
ediff-window-setup-function #'ediff-setup-windows-plain
ediff-split-window-function #'split-window-horizontally)
;; https://oremacs.com/2015/01/17/setting-up-ediff/
(add-hook 'ediff-after-quit-hook-internal #'winner-undo))
(setup eldoc
(:option eldoc-idle-delay 0.1
eldoc-echo-area-use-multiline-p nil))
(setup elisp-mode
(:with-mode emacs-lisp-mode ;; -_-
(:option eval-expression-print-length nil
eval-expression-print-level nil
print-length nil
print-level nil
lisp-indent-function #'lisp-indent-function)
(:local-set (append imenu-generic-expression)
`("Setup"
,(rx (seq
(group bol (* space) "(setup" (+ space))
(? (group "(:" (+ graph) (* space) (? "(")))
(group (+ (any word ?+ ?-)))))
3))
(:hook #'checkdoc-minor-mode
#'turn-on-eldoc-mode)
;; Emulate slime's eval binds
(:bind "C-c C-c" #'eval-defun
"C-c C-k" #'acdw/eval-region-or-buffer
"C-c C-z" #'ielm)
;; Add advice to pulse evaluated regions
(:advise eval-region :around
(defun eval-region@pulse (fn beg end &rest args)
(pulse-momentary-highlight-region beg end)
(apply fn beg end args))))
(:with-mode lisp-interaction-mode ;; -___-
(:bind "C-c C-c" #'eval-defun
"C-c C-k" #'acdw/eval-region-or-buffer
"C-c C-z" #'ielm)))
(setup emacs
;; "Et cetera" settings
;; This should stay as /minimal/ as possible. Anything that can go somewhere
;; else /should/ go there.
(:option
async-shell-command-display-buffer nil
async-shell-command-buffer #'new-buffer
attempt-orderly-shutdown-on-fatal-signal nil
auto-hscroll-mode 'current-line
attempt-stack-overflow-recovery nil
echo-keystrokes 0.01
find-function-C-source-directory (acdw/find-emacs-source)
image-use-external-converter (and (not (version< emacs-version "27"))
(or (executable-find "magick")
(executable-find "convert")))
kill-read-only-ok t
load-prefer-newer t
native-comp-async-report-warnings-errors nil
password-cache t
password-cache-expiry 3600 ; 5 minutes
set-mark-command-repeat-pop t)
(when (fboundp 'command-completion-default-include-p)
(setq read-extended-command-predicate
#'command-completion-default-include-p))
(defvar case-map (make-sparse-keymap)
"A keymap for setting case in various ways.")
(global-set-key (kbd "C-c c") case-map)
(defvar lookup-map (make-sparse-keymap)
"A keymap for looking up things.")
(global-set-key (kbd "C-c l") lookup-map)
(:global "M-=" #'count-words
"C-M-;" #'comment-or-uncomment-sexp
"C-w" #'kill-region-or-backward-word
"C-c d" #'acdw/insert-iso-date
"M-`" nil
"C-x o" #'acdw/other-window-or-switch-buffer
"C-x O" #'acdw/other-window-or-switch-buffer-backward
"C-c _" #'add-file-local-variable
"C-x C-c" #'acdw/fat-finger-exit)
;; inspo: https://github.com/zaeph/.emacs.d/blob/master/init.el#L479
(defvar toggle-map (make-sparse-keymap)
"A keymap for toggling!")
(global-set-key (kbd "C-c t") toggle-map)
(:with-map toggle-map
(:bind "c" #'column-number-mode
"l" #'display-line-numbers-mode
"d" #'toggle-debug-on-error
"s" #'so-long-mode
"S" #'scroll-bar-mode))
;; Toggle
(:with-map toggle-map
(:bind "b" (defun acdw/toggle-lexical-binding ()
"Toggle `lexical-binding' in the current buffer."
(interactive)
(setq lexical-binding (not lexical-binding))
(message "Lexical-binding is %sabled."
(if lexical-binding "en" "dis"))
(force-mode-line-update))))
(:with-map case-map
(require 'titlecase)
(require 'acdw)
(:bind "c" #'capitalize-dwim
"t" #'titlecase-dwim
"u" #'upcase-dwim
"l" #'downcase-dwim
"s" #'spongebob-case-dwim))
(add-hook 'after-make-frame-functions
(defun after-make-frame@maximize (frame)
(unless (bound-and-true-p edit-server-frame-p)
(toggle-frame-maximized frame))))
(column-number-mode +1))
(setup encoding
(:option 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
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)
(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))))
(setup eshell
(:also-load acdw-eshell
em-smart
em-tramp)
(:option eshell-aliases-file (acdw/dir "eshell/aliases" t)
eshell-destroy-buffer-when-process-dies t
eshell-directory-name (acdw/dir "eshell/" t)
eshell-error-if-no-glob t
eshell-hist-ignore-dups t
eshell-kill-on-exit nil
eshell-prefer-lisp-functions t ; I want to try using eshell
eshell-prefer-lisp-variables t ; as much as possible.
eshell-review-quick-commands nil
eshell-save-history-on-exit t
eshell-scroll-to-bottom-on-input 'all
eshell-smart-space-goes-to-end t
eshell-where-to-jump 'begin)
(:local-set outline-regexp eshell-prompt-regexp
page-delimiter eshell-prompt-regexp)
(:bind "C-d" #'eshell-quit-or-delete-char)
(:hook #'eshell-arg-hist-mode
(defun eshell-mode@setup ()
(unless (bound-and-true-p eshell-customizations-loaded)
(load (expand-file-name "eshell" user-emacs-directory))))))
(setup eww
(:also-load acdw-eww)
(defvar-local eww-readable-p nil
"Whether current buffer is in readable-mode.")
(:option eww-search-prefix "https://duckduckgo.com/html?q="
url-privacy-level '(email agent cookies lastloc))
(defun eww@is-readable (&rest _)
(setq-local eww-readable-p t))
(defun eww@is-not-readable (&rest _)
(setq-local eww-readable-p nil))
(advice-add 'eww-readable :after #'eww@is-readable)
(advice-add 'eww-render :after #'eww@is-not-readable)
(advice-add 'eww-back-url :after #'eww@is-not-readable)
(:hook #'reading-mode
(defun bookmark-eww--setup ()
"Setup eww bookmark integration."
(setq-local bookmark-make-record-function #'bookmark-eww--make)))
(:bind "b" #'bookmark-set
"B" #'bookmark-jump
"M-n" nil
"M-p" nil))
(setup executable
(:option executable-prefix-env t)
(add-hook 'after-save-hook
#'executable-make-buffer-file-executable-if-script-p))
(setup files
(:option auto-save-file-name-transforms `((".*" ,(acdw/dir "auto-save/" t) t))
auto-save-list-file-prefix (acdw/dir "auto-save-list/.saves-" t)
auto-save-interval 60
auto-save-timeout 60
auto-save-visited-interval auto-save-timeout
backup-by-copying t
backup-directory-alist `((".*" . ,(acdw/dir "backup/" t)))
delete-old-versions t
mode-require-final-newline 'visit-save
tramp-backup-directory-alist backup-directory-alist
vc-make-backup-files t
version-control t)
(auto-save-visited-mode +1))
(setup find-func
(:global "C-c l f" #'find-function
"C-c l l" #'find-library
"C-c l v" #'find-variable))
(setup flymake
(defvar-local flymake-inhibit nil
"Buffer-local variable to inhibit `flymake'.")
(add-to-list 'safe-local-variable-values '(flymake-inhibit . t))
(add-to-list 'safe-local-variable-values '(flymake-inhibit . nil))
(defvar flymake-inhibit-major-modes nil
"Which major-modes NOT to enable `flymake' in.")
(defvar flymake-inhibit-file-name-regexps '("init\\.el\\'"
"early-init\\.el\\'")
"List of file regexps NOT to enable `flymake' in.")
(defvar flymake-inhibit-buffer-name-regexps (list (rx "*scratch*"))
"List of buffer-name regexps NOT to enable `flymake' in.")
(defun list-string-match-p (string regexp-list)
"Return t if at least one regex in RETGEXP-LIST matches STRING, else nil."
(when string ; if STRING is nil, return nil.
(catch 'found
(dolist (regexp regexp-list)
(when (string-match regexp string)
(throw 'found t))))))
(defun flymake-unless ()
"Turn on `flymake-mode', UNLESS it's inhibited.
There are three methods to inhibit flymake in a file. From most
specific to most general, they are these:
- `flymake-inhibit': a file-local-variable
- `flymake-inhibit-buffer-name-regexps': a list of regexps to
match the buffer name against. If one of them matches, inhibit
`flymake-mode'.
- `flymake-inhibit-file-name-regexps': a list of regexps to match
the filename against. If one of them matches, inhibit
`flymake-mode'.
- `flymake-inhibit-major-modes': a list of major-modes in which
to inhibit `flymake-mode'. Really only useful if you want to
generally add `flymake-mode' to `prog-mode-hook'."
(unless (or (bound-and-true-p flymake-inhibit) ; file-local variable
(list-string-match-p (buffer-name)
flymake-inhibit-buffer-name-regexps)
(list-string-match-p (buffer-file-name)
flymake-inhibit-file-name-regexps)
(apply #'derived-mode-p flymake-inhibit-major-modes))
(flymake-mode-on)))
(add-hook 'prog-mode-hook #'flymake-unless)
(:bind "M-n" #'flymake-goto-next-error
"M-p" #'flymake-goto-prev-error))
(setup flyspell
(:hook-into text-mode))
(setup frames
(:option frame-title-format '("%b@"
(:eval
(or (file-remote-p default-directory 'host)
system-name))
" %+%* GNU Emacs"
(:eval (when (frame-parameter nil 'client)
" Client")))
window-resize-pixelwise t))
(setup ibuffer
(:also-load ibuf-ext)
(:option ibuffer-expert t
ibuffer-show-empty-filter-groups nil
ibuffer-saved-filter-groups
'(("default"
("dired" (mode . dired-mode))
("customize" (mode . Custom-mode))
("emacs" (or (name . "^\\*scratch\\*$")
(name . "^\\*Messages\\*$")
(name . "^\\*Warnings\\*$")
(name . "^\\*straight-process\\*$")
(name . "^\\*Calendar\\*$")))
("git" (or (name . "^\*magit")
(name . "^\magit")))
("help" (or (mode . help-mode)
(mode . Info-mode)
(mode . helpful-mode)))
("messaging" (or (mode . message-mode)
(mode . bbdb-mode)
(mode . mail-mode)
(mode . gnus-group-mode)
(mode . gnus-summary-mode)
(mode . gnus-article-mode)
(name . "^\\.bbdb$")
(name . "^\\.newsrc-dribble")
(mode . erc-mode)
(mode . circe-server-mode)
(mode . circe-channel-mode)))
("shell" (or (mode . eshell-mode)
(mode . shell-mode)
(mode . vterm-mode)))
("web" (or (mode . elpher-mode)
(mode . gemini-mode)
(mode . eww-mode))))))
(:global "C-x C-b" #'ibuffer)
(:hook (defun ibuffer@filter-to-default ()
(ibuffer-switch-to-saved-filter-groups "default"))))
(setup ielm
(:hook #'turn-on-eldoc-mode))
(setup imenu
(:option imenu-auto-rescan t))
(setup isearch
(:option search-default-mode t))
(setup lines
(:option fill-column 79
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))))
;; `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 kill-line@join (fn &rest args)
(if (and (eolp)
(not (bolp)))
(delete-indentation 1)
(apply fn args)))))
(setup minibuffer
(:option enable-recursive-minibuffers t
file-name-shadow-properties '(invisible t intangible t)
minibuffer-eldef-shorten-default t
minibuffer-prompt-properties
'(read-only t cursor-intangible t face minibuffer-prompt)
read-answer-short t
read-extended-command-predicate ; used on >28
#'command-completion-default-include-p)
(add-hook 'minibuffer-setup-hook #'cursor-intangible-mode)
(add-hook 'minibuffer-setup-hook #'acdw/gc-disable)
(add-hook 'minibuffer-exit-hook #'acdw/gc-enable)
(minibuffer-depth-indicate-mode +1)
(file-name-shadow-mode +1)
(minibuffer-electric-default-mode +1)
(if (version< emacs-version "28")
(fset 'yes-or-no-p #'y-or-n-p)
(setq use-short-answers t)))
(setup mouse
;; Unconditionally follow links when clicked.
;; This is because mouse-1 usually sets point.
;; Other options:
;; +[ms] -> perform mouse-2 until held for [ms], then mouse-1
;; -[ms] -> perform mouse-1 until held for [ms], then mouse-2
;; 'double -> mouse-2 on double click
;; nil -> mouse-1 never follows link
;; <anything> -> mouse-1 /always/ follows link
(:option mouse-1-click-follows-link t))
(setup mouse-avoidance
(mouse-avoidance-mode 'banish))
(setup page
(:option page-delimiter
(rx bol (or "\f" ";;;")
(not (any "#")) (* not-newline) "\n"
(* (* blank) (opt ";" (* not-newline)) "\n")))
(defun recenter-to-top (&rest _)
"Recenter the cursor to the top of the window."
(when (called-interactively-p 'any)
(recenter (if (or (null scroll-margin)
(zerop scroll-margin))
3
scroll-margin))))
(:advise forward-page :after #'recenter-to-top
backward-page :after #'recenter-to-top)
;; I'm not sure where this is in /my/ version of Emacs
;; (defvar page-navigation-repeat-map
;; (let ((map (make-sparse-keymap)))
;; (define-key map "]" #'forward-page)
;; (define-key map "[" #'backward-page)
;; map)
;; "Keymap to repeat page navigation key sequences. Used in `repeat-mode'.")
;; (put 'forward-page 'repeat-map 'page-navigation-repeat-map)
;; (put 'backward-page 'repeat-map 'page-navigation-repeat-map)
)
(setup prog
(:option show-paren-delay 0
show-paren-style 'mixed
show-paren-when-point-inside-paren t
show-paren-when-point-in-periphery t
smie-indent-basic tab-width)
(:hook #'show-paren-mode
;; #'electric-pair-local-mode
#'acdw/setup-fringes
#'display-fill-column-indicator-mode
(defun prog-mode@auto-fill ()
(setq-local comment-auto-fill-only-comments t)
(turn-on-auto-fill))))
(setup pulse
(:option pulse-flag nil
pulse-delay 0.5
pulse-iterations 1)
(defun pulse-line (&rest _)
"Pulse the current line."
(pulse-momentary-highlight-one-line (point)))
(dolist (func '(scroll-up-command
scroll-down-command
recenter-top-bottom other-window
switch-to-buffer
redraw-frame))
(advice-add func :after #'pulse-line)))
(setup re-builder
(require 'acdw-re)
(:global "C-M-5" #'re-builder
"C-M-%" #'re-builder)
(:with-map reb-mode-map
(:bind "C-c C-k" #'reb-quit
"RET" #'reb-replace-regexp))
(:with-map reb-lisp-mode-map
(:bind "RET" #'reb-replace-regexp)))
(setup repeat
;; new for Emacs 28!
(:only-if (fboundp #'repeat-mode))
(:option repeat-exit-key "g"
repeat-exit-timeout 5)
(repeat-mode +1))
(setup saveplace
(:option save-place-file (acdw/dir "places.el")
save-place-forget-unreadable-files (acdw/system :home))
(save-place-mode +1))
(setup scratch
(:option inhibit-startup-screen t
initial-buffer-choice t
initial-major-mode #'lisp-interaction-mode
lexical-binding t
initial-scratch-message
(concat ";; Howdy, "
(nth 0 (split-string
user-full-name))
"! "
"Welcome to GNU Emacs.\n\n"))
(add-hook 'kill-buffer-query-functions
(defun kill-buffer-query@immortal-scratch ()
(if (eq (current-buffer) (get-buffer "*scratch*"))
(progn (bury-buffer)
nil)
t))))
(setup scrolling
(:option auto-window-vscroll nil
fast-but-imprecise-scrolling t
scroll-margin 3
scroll-conservatively 101
scroll-preserve-screen-position 1))
(setup selection
(: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))
(setup sh-mode
(: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")
(with-eval-after-load 'apheleia
(:option (append apheleia-formatters) '(shfmt . ("shfmt"))
(append apheleia-mode-alist) '(sh-mode . shfmt))))
(when (executable-find "shellcheck")
(:straight flymake-shellcheck)
(:hook flymake-mode
flymake-shellcheck-load)))
(setup shell-command
(:option shell-command-switch (acdw/system
;; I should be testing on some variable
(:home "-csi")
(:work "-c"))
shell-command-prompt-show-cwd t
shell-command-default-error-buffer "*shell-command-errors*"))
(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
shr-folding-mode t))
(setup text
(:hook turn-on-auto-fill
tildify-mode
acdw/setup-fringes))
(setup uniquify
(:option uniquify-buffer-name-style 'forward
uniquify-separator path-separator
uniquify-after-kill-buffer-p t
uniquify-ignore-buffers-re "^\\*"))
(setup variable-pitch-mode
;; I might want to change this to `buffer-face-mode-hook'...
(:advise variable-pitch-mode :after
(defun variable-pitch-mode@setup (&rest _)
"Set up `variable-pitch-mode' with my customizations."
(display-fill-column-indicator-mode
(if buffer-face-mode -1 +1)))))
(setup view
(:option view-read-only t)
(:hook (defun acdw/read-view-mode ()
(reading-mode (if view-mode +1 -1)))))
(setup w32
(:option 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))
(setup 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)
(:global "M-SPC" #'cycle-spacing)
;; http://ruzkuku.com/emacs.d.html#orgc62eb58
(:advise cycle-spacing :around
(defun cycle-spacing@newlines-by-default (old arg &rest _)
(funcall old (if (numberp arg) (- arg) arg)))))
(setup windmove
(:option windmove-wrap-around t)
(:global
;; moving
"C-x 4 <left>" #'windmove-left
"C-x 4 <right>" #'windmove-right
"C-x 4 <up>" #'windmove-up
"C-x 4 <down>" #'windmove-down
;; swapping
"C-x 4 S-<left>" #'windmove-swap-states-left
"C-x 4 S-<right>" #'windmove-swap-states-right
"C-x 4 S-<up>" #'windmove-swap-states-up
"C-x 4 S-<down>" #'windmove-swap-states-down)
;; (when (fboundp 'repeat-mode)
;; (defvar windmove-repeat-map
;; (let ((map (make-sparse-keymap)))
;; ;; moving
;; (define-key map [left] #'windmove-left)
;; (define-key map [right] #'windmove-right)
;; (define-key map [up] #'windmove-up)
;; (define-key map [down] #'windmove-down)
;; ;; swapping
;; (define-key map [S-left] #'windmove-swap-states-left)
;; (define-key map [S-right] #'windmove-swap-states-right)
;; (define-key map [S-up] #'windmove-swap-states-up)
;; (define-key map [S-down] #'windmove-swap-states-down)
;; map)
;; "Keymap to repeat various `windmove' sequences. Used in `repeat-mode'.")
;; (dolist (sym '(windmove-left
;; windmove-right
;; windmove-up
;; windmove-down
;; windmove-swap-states-left
;; windmove-swap-states-right
;; windmove-swap-states-up
;; windmove-swap-states-down))
;; (put sym 'repeat-map 'windmove-repeat-map)))
)
(setup window
(require 'acdw-bell)
(:option
;; Man-notify-method 'pushy
;; display-buffer-alist ; from FrostyX
;; '(("shell.*" (display-buffer-same-window) ())
;; (".*" (display-buffer-reuse-window
;; display-buffer-same-window)
;; (reusable-frames . t)))
recenter-positions '(top middle bottom)
ring-bell-function (lambda ()
(acdw-bell/flash-mode-line
(acdw/system :home)))
use-dialog-box nil
use-file-dialog nil
visible-bell nil)
(tooltip-mode -1))
(setup winner
;; see https://lists.gnu.org/archive/html/emacs-devel/2021-08/msg00888.html
(:global "C-x 4 C-/" #'winner-undo
"C-x 4 /" #'winner-undo
"C-x 4 C-?" #'winner-redo
"C-x 4 ?" #'winner-redo)
;; add `winner-undo' and `winner-redo' to `repeat-mode'
;; (when (fboundp 'repeat-mode)
;; (defvar winner-mode-repeat-map
;; (let ((map (make-sparse-keymap)))
;; (define-key map "/" #'winner-undo)
;; (define-key map "?" #'winner-redo)
;; map)
;; "Keymap to repeat `winner-mode' sequences. Used in `repeat-mode'.")
;; (put 'winner-undo 'repeat-map 'winner-mode-repeat-map)
;; (put 'winner-redo 'repeat-map 'winner-mode-repeat-map))
(winner-mode +1))
(setup (:straight (0x0
:host gitlab
:repo "willvaughn/emacs-0x0"))
(:option 0x0-default-server 'ttm))
(setup (:straight-when affe
(and (or (executable-find "fd")
(executable-find "find"))
(executable-find "rg")))
;; Keys are bound in `acdw/sensible-grep' and `acdw/sensible-find'
(:option affe-regexp-compiler
(defun affe-orderless-regexp-compiler (input _type)
(setq input (orderless-pattern-compiler input))
(cons input (lambda (str) (orderless--highlight input str))))))
(setup (:straight-when ahk-mode
(acdw/system :work)))
(setup (:straight alert)
(:option alert-default-style (acdw/system
(:home 'libnotify)
(_ 'message))))
(setup (:straight (apheleia
:host github
:repo "raxod502/apheleia"))
(require 'acdw-apheleia)
(add-hook 'before-save-hook #'apheleia-dumb-auto-format)
;; Aphelia can't find prettier on Windows (though I
;; installed it, I think), and it keeps trying to start
;; new processes until Emacs runs out of subprocess space.
;; So I just enable it at home.
(unless (acdw/system :work)
(apheleia-global-mode +1)))
(setup (:straight async)
(dired-async-mode +1))
(setup (:straight avy)
(:global "M-j" #'avy-goto-char-timer
"C-c C-j" #'avy-resume)
(:with-feature isearch
(:bind "M-j" #'avy-isearch)))
(setup (:straight circe)
(require 'circe)
(require 'acdw-irc)
(:also-load acdw-circe)
(:option acdw-irc/left-margin 20
circe-channel-killed-confirmation nil
circe-color-nicks-everywhere t
circe-default-nick "acdw"
circe-default-part-message "See You, Space Cowpokes . . ."
circe-default-user "acdw"
circe-format-action (format
(format "%%%ds* {nick} {body}"
(- acdw-irc/left-margin 2)) " ")
circe-format-say (format
"{nick:%1$d.%1$ds} | {body}"
(- acdw-irc/left-margin 3))
circe-format-self-action circe-format-action
circe-format-self-say (format
"{nick:%1$d.%1$ds} > {body}"
(- acdw-irc/left-margin 3))
circe-network-inhibit-autoconnect '("Pissnet" "Twitch IRC")
circe-network-options
`(("Libera Chat"
:channels ("#emacs" "#systemcrafters" "##webpals"
"#emacsconf-org")
:sasl-username ,circe-default-nick
:sasl-password ,(acdw/make-password-fetcher
:host "libera.chat"))
("Tilde Chat" :host "irc.tilde.chat" :port 6697 :use-tls t
:channels ("#meta" "#bread" "#dadjokes" "#team"
"#emacs" "#nsfw")
:sasl-username ,circe-default-nick
:sasl-password ,(acdw/make-password-fetcher
:host "tilde.chat"))
("Casa" :host "m455.casa" :port 6697 :use-tls t
:channels ("#basement")
:sasl-username ,circe-default-nick
:sasl-password ,(acdw/make-password-fetcher
:host "m455.casa"))
("Pissnet" :host "piss.hmm.st" :port 6697 :use-tls t
:channels ("#i-just-peed")
:sasl-username ,circe-default-nick
:sasl-password ,(acdw/make-password-fetcher
:host "piss.hmm.st"))
("Twitch IRC" :host "irc.chat.twitch.tv" :port 6697 :use-tls t
:nick "caseofducks" :user "caseofducks"
:pass ,(acdw/make-password-fetcher :host "irc.chat.twitch.tv")))
circe-reduce-lurker-spam t
circe-server-auto-join-default-type :after-auth
circe-server-buffer-action (lambda (buf)
(message "Connected to %s" buf)))
(with-eval-after-load 'circe
(:face circe-nick-highlight-face
((t (:inherit (modus-themes-hl-line modus-themes-bold))))
circe-my-message-face
((t (:inherit (modus-themes-slant))))))
(:bind "C-c C-p" #'circe-command-PART
"C-l" #'lui-track-jump-to-indicator
"<C-return>" #'circe-chat@set-prompt)
(:advise circe-command-PART :after #'circe-part@kill-buffer
circe-command-QUIT :after #'circe-quit@kill-buffer
circe-command-GQUIT :after #'circe-gquit@kill-buffer)
(:with-mode circe-chat-mode
(:hook #'acdw/stop-paren-annoyances
#'enable-circe-color-nicks
;; #'enable-circe-display-images
#'enable-circe-new-day-notifier
#'circe-chat@set-prompt
#'topsy-mode))
(:bind "C-c C-s" #'circe-command-SLAP)
(autoload 'circe-nick-color-reset "circe-color-nicks")
(add-hook 'modus-themes-after-load-theme-hook
#'circe-nick-color-reset)
(:with-mode lui-mode
(:option lui-fill-column (+ fill-column acdw-irc/left-margin)
lui-fill-type nil ;;(repeat-string acdw-irc/left-margin " ")
lui-time-stamp-position 'right-margin
lui-time-stamp-format "%H:%M"
lui-track-behavior 'before-switch-to-buffer
lui-track-indicator 'fringe
lui-fill-remove-face-from-newline nil)
(:hook #'visual-fill-column-mode
#'visual-line-mode)
(:local-set visual-fill-column-extra-text-width (cons acdw-irc/left-margin
0)
fringes-outside-margins t
right-margin-width 5
scroll-margin 0
word-wrap t
wrap-prefix (repeat-string acdw-irc/left-margin " ")
line-number-mode nil
column-number-mode nil
file-percentage-mode nil)
(:hook #'enable-lui-track)))
(setup (:straight (consult
:host github
:repo "minad/consult"))
(:require acdw-consult)
(:autoload consult-register-preview)
;; Bindings
(:global
;; C-c bindings (`mode-specific-map')
;; I don't use any of these right now.
;; "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" #'acdw-consult/sensible-grep
"M-s f" #'acdw-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))
(:option (append consult-buffer-sources) #'circe-buffer-source)
(consult-history-to-modes ((minibuffer-local-map . nil)
(shell-mode-map . shell-mode-hook)
(term-mode-map . term-mode-hook)
(term-raw-map . term-mode-hook)
(comint-mode-map . comint-mode-hook)
(sly-mrepl-mode-map . sly-mrepl-hook)))
(:option register-preview-delay 0
register-preview-function #'consult-register-format
xref-show-xrefs-function #'consult-xref
xref-show-definitions-function #'consult-xref
consult-project-root-function #'vc-root-dir
completion-in-region-function #'acdw-consult/complete-in-region
completion-cycle-threshold 3
consult-preview-key (kbd "M-.")
tab-always-indent 'complete)
(:advise register-preview :override #'consult-register-window)
;; Completing-read-multple
(if (fboundp #'consult-completing-read-multiple)
(:advise completing-read-multple :override
#'consult-completing-read-multiple)
(:advise completing-read-multiple :filter-args
(defun crm-indicator (args)
(cons (concat "[CRM] " (car args)) (cdr args)))))
(with-eval-after-load 'orderless
(:option consult--regexp-compiler
#'consult--orderless-regexp-compiler))
(with-eval-after-loads (vertico consult)
(:with-map consult-crm-map
(:bind "RET" (defun +vertico-crm-exit ()
(interactive)
(run-at-time 0 nil #'vertico-exit)
(funcall #'vertico-exit))
"TAB" #'vertico-exit))))
(setup (:straight crux)
(:global "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))
(setup (:straight-when (define-repeat-map
:host nil
:repo "https://tildegit.org/acdw/define-repeat-map.el")
(acdw/system :home))
(require 'define-repeat-map ; just for me
(acdw/dir
"straight/build/define-repeat-map/define-repeat-map.el"))
(defun acdw/other-window-or-switch-buffer-backward ()
(interactive)
(setq repeat-map 'other-window-repeat-map)
(acdw/other-window-or-switch-buffer -1))
(define-repeat-map other-window
("o" acdw/other-window-or-switch-buffer
"O" acdw/other-window-or-switch-buffer-backward))
(define-repeat-map case
("c" capitalize-word
"u" upcase-dwim
"l" downcase-dwim)
(:continue "f" forward-word
"b" backward-word)
(:enter capitalize-dwim
upcase-dwim
downcase-dwim))
(define-repeat-map page-navigation
("]" forward-page
"[" backward-page))
(define-repeat-map windmove
(;; moving
"<left>" windmove-left
"<right>" windmove-right
"<up>" windmove-up
"<down>" windmove-down
;; swapping
"<S-left>" windmove-swap-states-left
"<S-right>" windmove-swap-states-right
"<S-up>" windmove-swap-states-up
"<S-down>" windmove-swap-states-down))
(define-repeat-map winner-mode
("/" winner-undo
"?" winner-redo)))
(setup (:straight dictionary)
(:option dictionary-use-single-buffer t)
(autoload 'dictionary-search "dictionary"
"Ask for a word and search it in all dictionaries" t)
(autoload 'dictionary-match-words "dictionary"
"Ask for a word and search all matching words in the dictionaries" t)
(autoload 'dictionary-lookup-definition "dictionary"
"Unconditionally lookup the word at point." t)
(autoload 'dictionary "dictionary"
"Create a new dictionary buffer" t)
(autoload 'dictionary-mouse-popup-matching-words "dictionary"
"Display entries matching the word at the cursor" t)
(autoload 'dictionary-popup-matching-words "dictionary"
"Display entries matching the word at the point" t)
(autoload 'dictionary-tooltip-mode "dictionary"
"Display tooltips for the current word" t)
(autoload 'global-dictionary-tooltip-mode "dictionary"
"Enable/disable dictionary-tooltip-mode for all buffers" t)
(define-key lookup-map "d" #'dictionary-search)
(:hook #'reading-mode))
(setup (:straight (dogears
:host github
:repo "alphapapa/dogears.el"
:files (:defaults
(:exclude "helm-dogears.el"))))
(:option (append savehist-additional-variables) 'dogears-list)
(with-eval-after-load 'dogears
(dolist (mode '(magit-status-mode
elfeed-show-mode
elfeed-search-mode))
(:option (append dogears-ignore-modes) mode)))
(:global "M-g d" dogears-go)
(:autoload dogears-mode)
(dogears-mode +1))
(setup (:straight edit-indirect))
;; requires extension:
;; https://addons.mozilla.org/en-US/firefox/addon/edit-with-emacs1/
(setup (:straight edit-server)
(:require edit-server)
(edit-server-start)
(:option edit-server-default-major-mode 'text-mode
edit-server-url-major-mode-alist
(list (cons (rx (| "reddit.com"
"tildes.net"))
'markdown-mode)
(cons (rx "github.com")
'gfm-mode)
(cons "." 'text-mode)))
(:advise edit-server-make-frame :before
(defun edit-server@set-a-variable (&rest _)
(setq-local edit-server-frame-p t))))
(setup (:straight (electric-cursor
:host github
:repo "duckwork/electric-cursor"))
(electric-cursor-mode +1))
(setup (:straight elfeed
elfeed-protocol)
(:option elfeed-use-curl t
elfeed-curl-extra-arguments '("--insecure")
elfeed-feeds `(("fever+https://acdw@mf.acdw.net"
:api-url "https://mf.acdw.net/fever/"
:password ,(acdw/make-password-fetcher
:host "mf.acdw.net")
:autotags ; do I want to use elfeed-org ?
'(("r/emacs" reddit social emacs)
("protesilaos.com/codelog.xml" emacs)
("tildes.net" social)
("catandgirl.com" comics)
("qwantz.com" comics)
("emacsninja.com" emacs)
("falseknees.com" comics)
("emacslife.com" emacs)
("lisp.org" lisp programming)
("scheme.org" scheme programming)
("smbc-comics.com" comics)
("youtube.com" video)
("tilde.news" social)
("xkcd.com" comics)))))
(:autoload elfeed-set-timeout)
(elfeed-set-timeout 3600)
(elfeed-protocol-enable)
(:advise elfeed :after
(defun elfeed@protocol-update (&rest _)
(elfeed-search-fetch nil)))
(:face message-header-subject
((t (:height 1.5))))
(:with-mode elfeed-show-mode
(:hook #'reading-mode)
;; see https://irreal.org/blog/?p=8885
(:bind "SPC" (defun elfeed-scroll-up-command (&optional arg)
"Scroll up or go to next feed item in Elfeed"
(interactive "^P")
(let ((scroll-error-top-bottom nil))
(condition-case-unless-debug nil
(scroll-up-command arg)
(error (elfeed-show-next)))))
"S-SPC" (defun elfeed-scroll-down-command (&optional arg)
"Scroll up or go to next feed item in Elfeed"
(interactive "^P")
(let ((scroll-error-top-bottom nil))
(condition-case-unless-debug nil
(scroll-down-command arg)
(error (elfeed-show-prev))))))))
(setup (:straight elisp-slime-nav)
(:hook-into emacs-lisp-mode
ielm-mode))
(setup (:straight (elpher
:host nil
:repo "git://thelambdalab.xyz/elpher.git"))
(:option elpher-ipv4-always t
elpher-certificate-directory (acdw/dir "elpher/")
elpher-gemini-max-fill-width fill-column)
(:bind "n" #'elpher-next-link
"p" #'elpher-prev-link
"o" #'elpher-follow-current-link
"G" #'elpher-go-current)
(:hook #'reading-mode)
(:autoload (elpher-bookmarks :interactive t)
(elpher-go :interactive t))
;; Make `eww' gemini/gopher aware. From Emacswiki.
;; (define-advice eww-browse-url (:around (fn url &rest args) gemini-elpher)
;; (cond ((string-match-p "\\`\\(gemini\\|gopher\\)://" url)
;; (require 'elpher)
;; (elpher-go url))
;; (t (apply fn url args))))
)
(setup (:straight (embark ; gotta git that fresh fresh
:host github
:repo "oantolin/embark"))
(:global "C-." #'embark-act)
(:option prefix-help-command #'embark-prefix-help-command
(append display-buffer-alist)
`(,(rx (seq bos "*Embark Collect "
(group (| "Live" "Completions"))
"*"))
nil
(window-parameters (mode-line-format . none)))
embark-prompter #'embark-keymap-prompter
embark-verbose-indicator-display-action
'(display-buffer-at-bottom (window-height . fit-window-to-buffer))
embark-action-indicator
(lambda (map _target)
(which-key--show-keymap "Embark" map nil nil 'no-paging)
#'which-key--hide--ignore-command)
embark-become-indicator embark-action-indicator)
(with-eval-after-loads (embark consult)
(:straight embark-consult)
(add-hook 'embark-collect-mode-hook
#'consult-preview-at-point-mode)))
(setup (:straight epithet)
(dolist (hook '(Info-selection-hook
eww-after-render-hook
help-mode-hook
occur-mode-hook))
(add-hook hook #'epithet-rename-buffer)))
;; TODO: look into emms or something related for this
(setup (:straight-when eradio
(executable-find "mpv"))
(:option
eradio-player '("mpv" "--no-video" "--no-terminal")
eradio-channels `(("KLSU" .
"http://130.39.238.143:8010/stream.mp3")
("Soma FM Synphaera" .
"https://somafm.com/synphaera256.pls")
("SomaFM BAGel Radio" .
"https://somafm.com/bagel.pls")
("SomaFM Boot Liquor" .
"https://somafm.com/bootliquor320.pls")
("SomaFM Deep Space One" .
"https://somafm.com/deepspaceone.pls")
("SomaFM Fluid" .
"https://somafm.com/fluid.pls")
("SomaFM Underground 80s" .
"https://somafm.com/u80s256.pls")
("WBRH: Jazz & More" .
"http://wbrh.streamguys1.com/wbrh-mp3")
("KBRH Blues & Rhythm Hits" .
"http://wbrh.streamguys1.com/kbrh-mp3")
("WRKF HD-2" .
,(concat "https://playerservices.streamtheworld.com/"
"api/livestream-redirect/WRKFHD2.mp3"))
("WRKF: NPR for the Capital Region" .
,(concat "https://playerservices.streamtheworld.com/"
"api/livestream-redirect/WRKFFM.mp3"))
("BadRadio: 24/7 PHONK" .
"https://s2.radio.co/s2b2b68744/listen")
("tilderadio" .
"https://azuracast.tilderadio.org/radio/8000/radio.ogg")
("vantaradio" .
"https://vantaa.black/radio")))
(:global "C-c r r" #'eradio-play ; mnemonic: radio
"C-c r s" #'eradio-stop ; mnemonic: stop
"C-c r p" #'eradio-toggle ; mnemonic: play/pause
))
(setup (:straight eros)
(:hook-into emacs-lisp-mode
lisp-interaction-mode))
(setup (:straight-when exec-path-from-shell
(acdw/system :home))
(when (daemonp)
(exec-path-from-shell-initialize)))
(setup (:straight expand-region)
(:global "C-=" #'er/expand-region))
(setup (:straight-when fennel-mode
(executable-find "fennel"))
(:autoload (fennel-repl :interactive t))
(:file-match (rx ".fnl" eos)))
(setup (:straight flyspell-correct)
(:option flyspell-correct-interface #'flyspell-correct-completing-read
flyspell-correct--cr-key ";")
(:with-feature flyspell
(:bind "C-." #'flyspell-correct-wrapper
"<f7>" (defun acdw/flyspell-correct-f7 ()
"Run a full spell correction on the current buffer."
(interactive)
(save-mark-and-excursion
(flyspell-correct-move 0 :forward :rapid))))
(:unbind "C-;" "C-," "C-." "C-M-i")))
(setup (:straight-when forge
(acdw/system :home))
;; make sure to read Info manual with Forge (and Ghub) for setup
;; instructions.
(with-eval-after-load 'magit
(require 'forge)
(add-to-list 'forge-alist ; tildegit is a gitea server
'("tildegit.org" "tildegit.org/api/v1" "tildegit.org"
forge-gitea-repository))))
(setup (:straight gcmh)
(:option gcmh-idle-delay 'auto)
(gcmh-mode +1))
(setup (:straight-when geiser
(progn
(defvar acdw/schemes
(let (schemes)
(dolist (scheme '(("scheme" . geiser-chez) ; chez
("petite" . geiser-chez) ; petite
("csi" . geiser-chez) ; chicken
("gsi" . geiser-gambit)
("gosh" . geiser-gauche)
("guile" . geiser-guile)
("kawa" . geiser-kawa)
("mit-scheme" . geiser-mit)
("racket" . geiser-racket)
("stklos" . geiser-stklos)))
(when-let (binary (executable-find (car scheme)))
(push binary schemes)
;; and install the proper helper package
(straight-use-package (cdr scheme))))
(nreverse schemes)))
acdw/schemes))
(:file-match (rx ".rkt" eos)
(rx ".scm" eos)))
(setup (:straight (gemini-mode
:host nil
:repo "https://git.carcosa.net/jmcbray/gemini.el.git"))
(:file-match (rx (seq "." (or "gemini" "gmi") eos)))
(:hook turn-off-auto-fill))
(setup (:straight (gemini-write
:host nil
:repo "https://alexschroeder.ch/cgit/gemini-write"
:branch "main"))
(with-eval-after-load 'elpher
(require 'gemini-write)))
(setup (:straight gitattributes-mode
gitconfig-mode
gitignore-mode))
(setup (:straight helpful)
(:require-after 3)
(defvar helpful-pre-windows nil
"Window configuration /before/ helpful was called.")
(:option helpful-switch-buffer-function #'pop-to-buffer)
(:global "<help> f" #'helpful-callable
"<help> v" #'helpful-variable
"<help> k" #'helpful-key
"<help> o" #'helpful-symbol)
;; (:bind "q" #'quit-window)
)
(setup (:straight hungry-delete)
(:option hungry-delete-chars-to-skip " \t"
hungry-delete-join-reluctantly nil)
(global-hungry-delete-mode +1)
(:with-feature paredit
(:bind [remap paredit-backward-delete]
(defun acdw/paredit-hungry-delete-backward (arg)
(interactive "P")
(if (looking-back "[ \t]" 1)
(hungry-delete-backward (or arg 1))
(paredit-backward-delete arg)))
[remap paredit-forward-delete]
(defun acdw/paredit-hungry-delete-forward (arg)
(interactive "P")
(if (looking-at "[ \t]")
(hungry-delete-forward (or arg 1))
(paredit-forward-delete arg))))))
(setup (:straight iscroll)
(define-globalized-minor-mode global-iscroll-mode iscroll-mode
(lambda () (iscroll-mode +1)))
(global-iscroll-mode +1))
(setup (:straight (kaomoji-insert
:host nil
:repo "https://tildegit.org/acdw/kaomoji-insert"))
(require 'kaomoji-insert)
(dolist (km '(("(Ծ‸ Ծ)" "suspicious")
("(¬‿¬)═ɜ ɛ═(⌐‿⌐ )" "pound it" "fist bump")
("▬▬▬▬▬▬▬▋ Ò╭╮Ó" "hammer")
("👁👄👁" "lewk")
("( ͡~ ͜ʖ ͡°)" "wink")
(" (づ ̄ ³ ̄)づ " "party")
("⊙﹏⊙" "uhhh" "unsure")))
(add-to-list 'kaomoji-insert-alist km))
(:global "C-x 8 k" #'kaomoji-insert))
;; (setup (:straight wrap-region)
;; (:hook-into org-mode)
;; (with-eval-after-load 'org
;; (dolist (punc '("=" "*" "/" "_" "+"))
;; (wrap-region-add-wrapper punc punc nil 'org-mode))))
(setup (:straight lacarte)
(:global "<f10>" #'lacarte-execute-menu-command))
(setup (:straight-when ledger-mode
(executable-find "ledger")))
(setup (:straight link-hint)
;; Browse web URLs with a browser with a prefix argument.
(dolist (type '(gnus-w3m-image-url
gnus-w3m-url
markdown-link
mu4e-attachment
mu4e-url
notmuch-hello
nov-link
org-link
shr-url
text-url
w3m-link
w3m-message-link))
(link-hint-define-type type
:open-secondary browse-url-secondary-browser-function
:open-secondary-multiple t))
(defun acdw/link-hint-open-all-links (prefix)
"Open all visible links.
When PREFIX is non-nil, open links with
`browse-url-secondary-browser-function'."
(interactive "P")
(avy-with link-hint-open-all-links
(link-hint--all (if prefix :open-secondary :open))))
(defun acdw/link-hint-open-multiple-links (prefix)
"Use `avy' to open multiple visible links at once.
When PREFIX is non-nil, open links with
`browse-url-secondary-browser-function'."
(interactive "P")
(avy-with link-hint-open-multiple-links
(link-hint--multiple (if prefix :open-secondary :open))))
(:option link-hint-avy-style 'post)
(:global "C-j"
(defun acdw/link-hint-open-link (arg)
"Open a link using `link-hint-open-link', prefix-aware.
That is, a prefix argument (\\[universal-argument]) will open the
browser defined in `browse-url-secondary-browser-function'."
(interactive "P")
(avy-with link-hint-open-link
(link-hint--one (if arg :open-secondary :open))))))
(setup (:straight lua-mode)
(:file-match (rx ".lua" eos)))
(setup (:straight macrostep)
(define-key emacs-lisp-mode-map (kbd "C-c e") #'macrostep-expand)
(define-key lisp-interaction-mode-map (kbd "C-c e") #'macrostep-expand))
(setup (:straight magit)
(:global "C-x 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))
magit-refresh-status-buffer nil))
(setup (:straight marginalia)
(:option marginalia-annotators '(marginalia-annotators-heavy
marginalia-annotators-light))
(marginalia-mode +1))
(setup (:straight markdown-mode)
(:file-match (rx ".md" eos)
(rx ".markdown" eos))
(:hook #'variable-pitch-mode)
(:with-mode gfm-mode
(:file-match (rx "README.md" eos))
(:hook #'variable-pitch-mode))
(when (executable-find "markdownfmt")
(with-eval-after-load 'apheleia
(:option (append apheleia-formatters) '(markdownfmt . ("markdownfmt"))
(append apheleia-mode-alist) '(markdown-mode . markdownfmt)
(append apheleia-mode-alist) '(gfm-mode . markdownfmt)))))
(setup (:straight (mastodon
:host github
:repo "mooseyboots/mastodon.el"))
(:option mastodon-instance-url "https://writing.exchange"
mastodon-auth-source-file (car auth-sources)
mastodon-client--token-file (acdw/dir "mastodon.plstore")
mastodon-tl--enable-proportional-fonts t
mastodon-tl--enable-relative-timestamps nil)
(:hook #'hl-line-mode
#'reading-mode)
(defun mastodon-goto-toot@recenter ()
"Recenter the current toot."
(recenter -1))
(:advise mastodon-tl--goto-next-toot :after #'mastodon-goto-toot@recenter
mastodon-tl--goto-prev-toot :after #'mastodon-goto-toot@recenter))
(setup (:straight (modus-themes
:host gitlab
:repo "protesilaos/modus-themes"))
(:option modus-themes-slanted-constructs t
modus-themes-bold-constructs t
modus-themes-fringes nil
modus-themes-mode-line '(borderless)
modus-themes-region '(bg-only)
modus-themes-org-blocks 'gray-background
modus-themes-headings '((t . (background)))
modus-themes-lang-checkers '(straight-underline)
modus-themes-scale-headings nil)
(acdw/sunrise-sunset #'modus-themes-load-operandi
#'modus-themes-load-vivendi)
(add-hook 'modus-themes-after-load-theme-hook
(defun modus-themes@customize-faces ()
"Customize faces of modus-themes."
;; (dolist (face '(font-lock-builtin-face
;; ;; font-lock-comment-delimiter-face
;; ;; font-lock-coment-face
;; font-lock-constant-face
;; ;; font-lock-doc-face
;; font-lock-function-name-face
;; font-lock-keyword-face
;; font-lock-negation-char-face
;; font-lock-preprocessor-face
;; font-lock-regexp-grouping-backslash
;; font-lock-regexp-goruping-construct
;; font-lock-string-face
;; font-lock-type-face
;; font-lock-variable-name-face
;; font-lock-warning-face))
;; (modus-themes-with-colors
;; (custom-set-faces
;; `(,face
;; ((,class :foreground ,fg-main
;; :weight normal
;; :slant normal))))))
;; Other faces
(modus-themes-with-colors
(custom-set-faces
`(org-level-1
((,class :inherit (modus-themes-heading-1 fixed-pitch)
:extend t)))
`(org-level-2
((,class :inherit (modus-themes-heading-2 fixed-pitch)
:extend t)))
`(org-level-3
((,class :inherit (modus-themes-heading-3 fixed-pitch)
:extend t)))
`(org-level-4
((,class :inherit (modus-themes-heading-4 fixed-pitch)
:extend t)))
`(org-level-5
((,class :inherit (modus-themes-heading-5 fixed-pitch)
:extend t)))
`(org-level-6
((,class :inherit (modus-themes-heading-6 fixed-pitch)
:extend t)))
`(org-level-7
((,class :inherit (modus-themes-heading-7 fixed-pitch)
:extend t)))
`(org-level-8
((,class :inherit (modus-themes-heading-8 fixed-pitch)
:extend t))))))))
(setup (:straight mwim)
(:global "C-a" #'mwim-beginning
"C-e" #'mwim-end))
(setup (:straight nov)
(:option nov-text-width fill-column)
(:file-match (rx ".epub" eos)))
;; (setup (:straight olivetti)
;; (:option olivetti-body-width (+ fill-column 4)
;; olivetti-minimum-body-width fill-column)
;; (:hook (defun olivetti-mode@setup ()
;; (if olivetti-mode
;; (setq-local indicate-empty-lines nil
;; indicate-buffer-boundaries nil)
;; (acdw/setup-fringes)))))
(setup (:straight (orderless
:host github
:repo "oantolin/orderless"))
(require 'orderless)
(:option (append completion-styles) 'orderless
orderless-component-separator #'orderless-escapable-split-on-space
orderless-matching-styles '(orderless-literal
orderless-regexp
orderless-flex)
orderless-style-dispatchers '(acdw/orderless-dispatch))
(:advise orderless-regexp :filter-args
(defun fix-dollar (args)
(if (string-suffix-p "$" (car args))
(list (concat (substring (car args) 0 -1)
"[\x100000-\x10FFFD]*$"))
args)))
(defun acdw/orderless-dispatch (pattern _index _total)
"My custom dispatcher for `orderless'."
(cond
;; Ensure that $ works with Consult commands, which add disambiguation
;; suffixes -- see `fix-dollar'
((string-suffix-p "$" pattern)
`(orderless-regexp . ,(concat (substring pattern 0 -1)
"[\x100000-\x10FFFD]*$")))
;; File extensions
((string-match-p "\\`\\.." pattern)
`(orderless-regexp . ,(concat "\\." (substring pattern 1)
"[\x100000-\x10FFFD]*$")))
;; Ignore single !
((string= "!" pattern)
`(orderless-literal . ""))
;; Character folding
((string-prefix-p "%" pattern)
`(char-fold-to-regexp . ,(substring pattern 1)))
((string-suffix-p "%" pattern)
`(char-fold-to-regexp . ,(substring pattern 0 -1)))
;; Without literal
((string-prefix-p "!" pattern)
`(orderless-without-literal . ,(substring pattern 1)))
((string-suffix-p "!" pattern)
`(orderless-without-literal . ,(substring pattern 0 -1)))
;; Initialism matching
((string-prefix-p "`" pattern)
`(orderless-initialism . ,(substring pattern 1)))
((string-suffix-p "`" pattern)
`(orderless-initialism . ,(substring pattern 0 -1)))
;; Literal matching
((string-prefix-p "=" pattern)
`(orderless-literal . ,(substring pattern 1)))
((string-suffix-p "=" pattern)
`(orderless-literal . ,(substring pattern 0 -1)))
;; Flex matching
((string-prefix-p "~" pattern)
`(orderless-flex . ,(substring pattern 1)))
((string-suffix-p "~" pattern)
`(orderless-flex . ,(substring pattern 0 -1))))))
(setup (:straight (org
:type git
:repo "https://git.savannah.gnu.org/git/emacs/org-mode.git"
:local-repo "org"
:depth full
:pre-build (straight-recipes-org-elpa--build)
:build (:not autoloads)
:files (:defaults
"lisp/*.el"
("etc/styles/" "etc/styles/*")))
(org-contrib
:type git
:repo "https://git.sr.ht/~bzg/org-contrib"))
(:also-load acdw-org)
(require 'chd nil 'noerror)
(:option org-adapt-indentation nil
org-agenda-files nil ; only until I set this up
org-catch-invisible-edits 'show-and-error
org-clock-clocked-in-display 'mode-line
org-clock-frame-title-format (cons '(t org-mode-line-string)
(cons " --- " frame-title-format))
;;org-clock-string-limit 7 ; gives time and not title
org-clock-persist t
org-confirm-babel-evaluate nil
org-cycle-separator-lines 0
org-directory "~/org"
org-ellipsis ""
org-export-coding-system 'utf-8-unix
org-export-headline-levels 8
org-export-with-section-numbers nil
org-export-with-smart-quotes t
org-export-with-sub-superscripts t
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
org-html-coding-system 'utf-8-unix
org-image-actual-width '(300)
org-imenu-depth 3
org-list-demote-modify-bullet '(("-" . "+")
("+" . "*")
("*" . "-"))
org-log-into-drawer t
org-outline-path-complete-in-steps nil
org-pretty-entities t
org-refile-use-outline-path 'file
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-startup-with-inline-images t
org-tags-column (- fill-column))
(:bind "RET" #'acdw-org/return-dwim
"<S-return>" #'acdw-org/org-table-copy-down
"M-SPC M-SPC" #'insert-zero-width-space
"C-c C-l" #'org-insert-link-dwim
"C-c w" #'chd/do-the-thing
"C-c C-n" #'acdw/org-next-heading-widen
"C-c C-p" #'acdw/org-previous-heading-widen
"C-x n t" #'org-narrow-to-task)
(:unbind "C-j" ; org-return-and-maybe-indent
"M-j")
(:local-set unfill-fill-function #'org-fill-paragraph)
(with-eval-after-load 'org-export
(:option (append org-export-filter-final-output-functions)
#'org-export-remove-zero-width-spaces))
(:hook ;; #'variable-pitch-mode
;; (defun org-mode@before-save@fill-buffer ()
;; (add-hook 'before-save-hook
;; (defun before-save@fill-buffer ()
;; (fill-region (point-min) (point-max)))
;; nil :local))
;; This is super ugly because I need to add a function to
;; `before-save-hook', but only in org-mode buffers. So I make a hook
;; to make a hook. I'm sure there's a better way to do this.
(defun org-mode@fix-blank-lines-on-save ()
(add-hook 'before-save-hook
(defun acdw-org/fix-blank-lines-in-buffer ()
(acdw-org/fix-blank-lines t))
0 :local))
(defun org-mode@wc-stupid ()
(unless (and wc-mode
(> 0 (+ (or wc-orig-words 0)
(or wc-words-delta 0)))))
(setq-local
wc-count-words-function
(lambda (start end) "Count words stupidly with a limit."
(acdw-org/count-words-stupidly start
end
999)))))
(with-eval-after-load 'org
(org-clock-persistence-insinuate))
(with-eval-after-load 'consult
(defun consult-clock-in (&optional match scope resolve)
"Clock into an Org heading."
(interactive (list nil nil current-prefix-arg))
(require 'org-clock)
(org-clock-load)
(save-window-excursion
(consult-org-heading
match
(or scope
(thread-last org-clock-history
(mapcar 'marker-buffer)
(mapcar 'buffer-file-name)
(delete-dups)
(delq nil))
(user-error "No recent clocked tasks")))
(org-clock-in nil (when resolve
(org-resolve-clocks)
(org-read-date t t)))))
(consult-customize consult-clock-in
:prompt "Clock in: "
:preview-key (kbd "M-.")
:group
(lambda (cand transform)
(if transform
(substring
cand
(next-single-property-change
0 'consult-org--buffer cand))
(let ((m (car (get-text-property
0 'consult-org--heading cand))))
(if (member m org-clock-history)
"*Recent*"
(buffer-name (marker-buffer m))))))))
(:advise org-delete-backward-char :override #'acdw-org/delete-backward-char)
(el-patch-feature org)
(with-eval-after-load 'org
(el-patch-defun org-format-outline-path (path &optional
width prefix separator)
"Format the outline path PATH for display.
WIDTH is the maximum number of characters that is available.
PREFIX is a prefix to be included in the returned string,
such as the file name.
SEPARATOR is inserted between the different parts of the path,
the default is \"/\"."
(setq width (or width 79))
(setq path (delq nil path))
(unless (> width 0)
(user-error "Argument `width' must be positive"))
(setq separator (or separator "/"))
(let* ((org-odd-levels-only nil)
(fpath (concat
prefix (and prefix path separator)
(mapconcat
(lambda (s) (replace-regexp-in-string "[ \t]+\\'" "" s))
(cl-loop for head in path
for n from 0
collect
(el-patch-swap
(org-add-props
head nil 'face
(nth (% n org-n-level-faces) org-level-faces))
head))
separator))))
(when (> (length fpath) width)
(if (< width 7)
;; It's unlikely that `width' will be this small, but don't
;; waste characters by adding ".." if it is.
(setq fpath (substring fpath 0 width))
(setf (substring fpath (- width 2)) "..")))
fpath))))
(setup (:straight org-appear)
(:option org-appear-autoemphasis t
org-appear-autoentities t
org-appear-autokeywords t
org-appear-autolinks nil
org-appear-autosubmarkers t
org-appear-delay 0)
(:hook-into org-mode))
(setup (:straight org-sticky-header)
(:hook-into org-mode))
(setup (:straight package-lint
package-lint-flymake))
(setup (:straight page-break-lines)
(global-page-break-lines-mode +1))
;; (setup (:straight paredit)
;; (:bind "DEL" #'paredit-backward-delete
;; "C-<backspace>" #'paredit-backward-kill-word
;; "M-w" #'paredit-copy-as-kill
;; "RET" #'paredit-newline)
;; (:unbind "M-s" ; paredit-splice-sexp
;; "C-j" ; paredit-newline (rebound to RET)
;; )
;; (:hook-into emacs-lisp-mode
;; ielm-mode sly-repl-mode
;; lisp-mode
;; lisp-interaction-mode
;; scheme-mode)
;; (:also-load eldoc)
;; (eldoc-add-command 'paredit-backward-delete 'paredit-close-round))
(setup (:straight paren-face)
(:hook-into emacs-lisp-mode
ielm-mode sly-repl-mode
lisp-mode
lisp-interaction-mode
scheme-mode))
(setup (:straight-when (pdf-tools
:host github
:repo "vedang/pdf-tools")
(acdw/system :home))
(:file-match (rx ".pdf" eos))
(pdf-loader-install))
;; (setup (:straight persistent-scratch)
;; (:option persistent-scratch-backup-directory (acdw/dir "scratch" t)
;; persistent-scratch-keep-n-newest-backups 12
;; persistent-scratch-what-to-save '(point))
;; (persistent-scratch-setup-default)
;; (mapc (lambda (buf)
;; (with-current-buffer buf
;; (when (funcall persistent-scratch-scratch-buffer-p-function)
;; (persistent-scratch-mode +1))))
;; (buffer-list)))
(setup (:straight restart-emacs)
(defun emacs-upgrade (&optional update-packages)
"Pull config, upgrade packages, restart Emacs."
(interactive "P")
(emacs-git-pull-config)
(when update-packages
(require 'straight-x)
(straight-x-pull-all))
(restart-emacs)))
(setup (:straight (shell-command+
:host nil
:repo "https://git.sr.ht/~pkal/shell-command-plus"))
(:option shell-command-prompt "$ ")
(:with-feature dired
(:bind "M-!" shell-command+))
(:global "M-!" shell-command+))
(setup (:straight sicp))
(setup (:straight simple-modeline
minions)
(:also-load acdw-modeline)
(:option simple-modeline-segments
;; Yeah this is laid out like poo. It's so I can easily change
;; things around if need be.
'((;; left
acdw-modeline/winum
acdw-modeline/modified
acdw-modeline/buffer-name
acdw-modeline/vc-branch
acdw-modeline/wc
acdw-modeline/position
) (;; right
acdw-modeline/track
simple-modeline-segment-misc-info
acdw-modeline/text-scale
simple-modeline-segment-process
acdw-modeline/god-mode-indicator
acdw-modeline/minions
acdw-modeline/reading-mode
acdw-modeline/narrowed
acdw-modeline/major-mode
)))
(:option tab-bar-mode t
tab-bar-show 1)
;; I've put in a pull request to add the (- 0 right-margin) bit here.
(el-patch-feature simple-modeline)
(with-eval-after-load 'simple-modeline
(el-patch-defun simple-modeline--format (left-segments right-segments)
"Return a string of `window-width' length containing LEFT-SEGMENTS and RIGHT-SEGMENTS, aligned respectively."
(let* ((left (simple-modeline--format-segments left-segments))
(right (simple-modeline--format-segments right-segments))
(reserve (length right)))
(concat
left
(propertize " "
'display (el-patch-swap
`((space :align-to (- right ,reserve)))
`((space :align-to
(- right
(- 1 right-fringe right-margin)
,reserve))))
'face '(:inherit simple-modeline-space))
right))))
(simple-modeline-mode +1))
(setup (:straight-when sly
(progn
(defvar acdw/lisps
(let (lisps)
(dolist (lisp '("sbcl" ; TODO: add more lisps
"clisp"))
(when-let (binary (executable-find lisp))
(push binary lisps)))
(nreverse lisps)))
acdw/lisps))
(:also-load sly-autoloads)
(:straight clhs)
(:option inferior-lisp-program acdw/lisp-bin
sly-kill-without-query-p t)
(:with-feature sly-mrepl
(defun sly-mrepl-return-at-end ()
(interactive)
(if (<= (point-max) (point))
(sly-mrepl-return)
(if (bound-and-true-p paredit-mode)
(paredit-newline)
(electric-newline-and-maybe-indent))))
(dolist (key '("RET" "<return>"))
(:bind key #'sly-mrepl-return-at-end))
(:bind "C-c C-c" #'sly-mrepl-return)))
(setup (:straight smartparens)
(require 'smartparens-config)
(sp-use-paredit-bindings)
(add-to-list 'sp-lisp-modes 'fennel-mode :append)
(dolist (mode '(cider-repl-mode-hook
clojure-mode-hook
common-lisp-mode-hook
emacs-lisp-mode-hook
fennel-mode-hook
geiser-repl-mode-hook
inferior-emacs-lisp-mode-hook
inferior-lisp-mode-hook
lisp-mode-hook
racket-mode-hook
racket-repl-mode-hook
scheme-mode-hook
sly-mrepl-mode-hook))
(add-hook mode #'smartparens-strict-mode))
(dolist (mode '(eval-expression-minibuffer-setup-hook
lisp-data-mode-hook))
(add-hook mode #'aorst/minibuffer-enable-sp))
(add-hook 'prog-mode #'smartparens-mode)
(defun aorst/minibuffer-enable-sp ()
"Enable `smartparens-strict-mode' in the minibuffer, during `eval-expression'."
(setq-local comment-start ";")
(sp-local-pair 'minibuffer-pairs "'" nil :actions nil)
(sp-local-pair 'minibuffer-pairs "`" nil :actions nil)
(sp-update-local-pairs 'minibuffer-pairs)
(smartparens-strict-mode 1))
(:bind "C-M-q" #'sp-indent-defun
"M-r" #'sp-rewrap-sexp)
(:unbind "M-j" ; sp-join-sexp
))
(setup (:straight ssh-config-mode)
(:file-match (rx "/.ssh/config" eos)
(rx "/ssh" (? "d") "_config" eos))
(:with-mode ssh-known-hosts-mode
(:file-match (rx "/knownhosts" eos)))
(:with-mode ssh-authorized-keys-mode
(:file-match (rx "/authorized_keys" (? "2") eos)))
(:hook #'turn-on-font-lock))
(setup (:straight super-save)
(:option auto-save-default nil
super-save-auto-save-when-idle nil
super-save-exclude '(".gpg")
super-save-remote-files nil)
(auto-save-visited-mode -1)
(super-save-mode +1))
(setup (:straight-when systemd
(executable-find "systemd")))
(setup (:straight (topsy
:host github
:repo "alphapapa/topsy.el"))
(:hook-into prog-mode)
(:when-loaded
(:option topsy-header-line-format
'(:eval
(list
(propertize " "
'display
'((space :align-to
,(unless visual-fill-column-mode 0))))
(funcall topsy-fn))))))
(setup (:straight trashed)
(:option trashed-action-confirmer #'y-or-n-p))
(setup (:straight typo)
;; Enable C-c 8 map in all buffers
(typo-global-mode +1)
(add-hook 'text-mode-hook
(defun text-mode@typo-unless ()
"Start `typo-mode' UNLESS the buffer matches a predicate."
;; I implement this instead of using
;; `typo-disable-electricity-functions' because the latter checks
;; on every pertinent keypress. I know I want /no/ typo-ing in
;; these certain buffers, so I won't even turn on the mode.
(unless (or ; predicates here
(string-match-p "COMMIT_EDITMSG"
(or (buffer-name) "")))
(typo-mode +1))))
;; jlf & cvandusen on #emacs make a great point: (RIGHT SINGLE QUOTATION
;; MARK) is /not/ an apostrophe. Making it curly is a typographical
;; consideration, not an input consideration. (I suppose you could make
;; the argument that all of these are typographical considerations, but
;; .. bleh.)
(:bind "'" (define-typo-cycle typo-cycle-apostrophe
"Cycle through apostrophe-like graphemes.
If used with a numeric prefix argument N, N apostrophes will be inserted."
("'" "" "" ""))
"`" (define-typo-cycle typo-cycle-backtick
"Cycle through backtick and left single quotation mark.
If used with a numeric prefix argument N, N backticks will be inserted."
("`" ""))))
(setup (:straight undo-fu)
(:global "C-/" #'undo-fu-only-undo
"C-?" #'undo-fu-only-redo))
(setup (:straight undo-fu-session)
(:option undo-fu-session-incompatible-files '("/COMMIT_EDITMSG\\'"
"/git-rebase-todo\\'")
undo-fu-session-directory (acdw/dir "undo/" t)
undo-fu-session-compression (acdw/system :home))
(global-undo-fu-session-mode +1))
(setup (:straight (unfill :host github :repo "purcell/unfill"
:fork (:host github :repo "duckwork/unfill")))
(:global "M-q" #'unfill-toggle))
(setup (:straight (unfocused
:host github
:repo "duckwork/unfocused"))
(unfocused-mode +1)
(:with-hook unfocused-hook
(:hook #'garbage-collect)))
(setup (:straight (vertico
:host github
:repo "minad/vertico"
:files ("*" "extensions/*"
(:exclude ".git"))))
(:option resize-mini-windows 'grow-only
vertico-count-format nil
vertico-cycle t)
(when (boundp 'native-comp-deferred-compilation-deny-list)
(add-to-list 'native-comp-deferred-compilation-deny-list "vertico"))
(vertico-mode +1)
;; Extensions!
(:also-load vertico-mouse
vertico-directory)
(vertico-mouse-mode +1)
(:with-map vertico-map
(:bind "RET" #'vertico-directory-enter
"DEL" #'vertico-directory-delete-char
"M-DEL" #'vertico-directory-delete-word))
(add-hook 'rfn-eshadow-update-overlay-hook #'vertico-directory-tidy))
(setup (:straight visual-fill-column)
(:option visual-fill-column-width (+ fill-column 4)
visual-fill-column-center-text t
(append reading-modes) '(visual-fill-column-mode . +1))
(:hook-into org-mode)
(:hook (defun visual-fill-column@setup ()
(if visual-fill-column-mode
(setq-local indicate-empty-lines nil
indicate-buffer-boundaries nil)
(acdw/setup-fringes))))
(:advise text-scale-adjust :after #'visual-fill-column-adjust))
(setup (:straight visual-regexp)
(:global "M-%" #'vr/query-replace))
(setup (:straight-when vterm
(acdw/system :home))
(:straight (eshell-vterm
:host github
:repo "iostapyshyn/eshell-vterm"))
(eshell-vterm-mode +1)
(defalias 'eshell/v 'eshell-exec-visual))
(setup (:straight wc-mode)
(:option wc-modeline-format "[%tww]"
wc-idle-wait 2)
(:hook-into text-mode)
(:unbind "C-c C-w a"
"C-c C-w c"
"C-c C-w l"
"C-c C-w w"
"C-c C-w"))
(setup (:straight web-mode)
(:option css-level-offset 2
js-indent-level 2
sgml-indent-offset 2)
(:file-match (rx ".htm" (? "l") eos)
(rx "." (? "tpl.") "php" eos)
(rx "." (| "asp" "gsp" "jsp") eos)
(rx "." (| "ascx" "aspx") eos)
(rx ".erb" eos)
(rx ".mustache" eos)))
(setup (:straight wgrep)
(wgrep-setup))
(setup (:straight which-key)
(:option which-key-show-early-on-C-h t
which-key-idle-delay 1
which-key-idle-secondary-delay 0.5
which-key-sort-order 'which-key-prefix-then-key-order)
(:global "C-h m" #'which-key-show-major-mode)
(which-key-setup-side-window-right-bottom)
(which-key-mode +1))
(setup (:straight whitespace-cleanup-mode)
(global-whitespace-cleanup-mode +1))
(setup (:straight winum)
(:option winum-scope 'frame-local
winum-auto-setup-mode-line nil
winum-ignored-buffers '(" *which-key*")
winum-format " %s")
(winum-mode +1))
(setup (:straight xr))
(setup (:straight-when ytel
(executable-find "mpv"))
(:also-load acdw-ytel)
;; This might need to be changed depending on whether the instance goes down.
(:option ytel-invidious-api-url "https://invidious.snopyta.org")
(:hook #'hl-line-mode)
(:bind "v" #'acdw/ytel-watch
"w" #'acdw/ytel-copy-link))
(setup (:straight zzz-to-char)
(:global "M-z"
(defun acdw/zzz-up-to-char (prefix)
"Call `zzz-up-to-char' or `zzz-to-char', PREFIX-depending."
(interactive "P")
(if prefix
(call-interactively #'zzz-to-char)
(call-interactively #'zzz-up-to-char)))))