You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

2758 lines
101 KiB

;;; 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:
;; 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")
(setup (:require goto-addr)
(if (fboundp #'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
(:option (append savehist-additional-variables) var))
(savehist-mode +1))
(setup (:require server)
(unless (server-running-p)
(setup (:require tramp)
;; thanks Irreal!
(add-to-list 'tramp-default-proxies-alist
'(nil "\\`root\\'" "/ssh:%h:"))
(add-to-list 'tramp-default-proxies-alist
'((regexp-quote (system-name)) nil nil)))
(setup Info
(:hook #'variable-pitch-mode
(setup abbrev
(:option abbrev-file-name "~/Sync/abbrev.el"
save-abbrevs 'silent)
(:hook-into text-mode
(setup acdw
(:also-load acdw-compat
(: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)))
(setup auto-fill
(:hook (defun auto-fill@truncate-lines ()
(setq-local truncate-lines t))))
(setup autoinsert
(require 'acdw-autoinsert)
(acdw/define-auto-insert '(:replace t)
;; This is my custom auto-insert for elisp files.
'("\\.el\\'" . "Emacs Lisp header (acdw)")
'("Short description: " ";;; "
(file-name-nondirectory (buffer-file-name))
" --- " str
(make-string (max 2 ( - fill-column (current-column) 27)) 32)
"-*- lexical-binding: t; -*-"
'(setq lexical-binding t)
"\n\n;; Copyright (C) " (format-time-string "%Y")
" " (getenv "ORGANIZATION") | (progn user-full-name)
"\n\n;; Author: " (user-full-name)
'(if (search-backward "&" (line-beginning-position) t)
(replace-match (capitalize (user-login-name)) t t))
'(end-of-line 1)
" <" (progn user-mail-address) ">"
& -2
"\n\n;;; License:"
"\n\n;; Everyone is permitted to do whatever with this software, without"
"\n;; limitation. This software comes without any warranty whatsoever,"
"\n;; but with two pieces of advice:"
"\n\n;; - Be kind to yourself."
"\n\n;; - Make good choices."
"\n\n;;; Commentary:"
"\n\n;; " _
"\n\n;;; Code:"
"\n\n\n\n(provide '" (file-name-base (buffer-file-name)) ")"
"\n;;; " (file-name-nondirectory (buffer-file-name)) " ends here\n"))
(auto-insert-mode +1))
(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-new-window-flag nil ; for eww
browse-url-firefox-arguments '("--new-tab") ; for firefox
browse-url-firefox-new-window-is-tab t)
(cons (rx (seq "." (or "jpeg" "jpg" ; images
(lambda (&rest args)
(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))
(message "Viewing %s in mpv..." url)
(apply #'start-process
(concat "mpv " url) nil
(append browse-url-mpv-arguments
(list "--image-display-duration=inf"
(t #'eww-browse-url))
(cons (rx (or "" ; videos
(seq "." (or "mp4"
"mov" "MOV")
(lambda (&rest args)
(apply (if (executable-find "mpv")
(cons (rx (or "" ; websites that don't work with eww
(cons "." ; everything else
;; 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.
(setq-default major-mode (lambda ()
(unless buffer-file-name
(let ((buffer-file-name (buffer-name)))
(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
'((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)
;; Don't load faces, since those are all set in init.el
(cl-letf (((symbol-function 'custom-set-faces) #'ignore))
(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
(: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
(:global "C-x C-j" #'dired-jump)
(with-eval-after-load 'dired
(: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
(put enable-sym 'disabled nil))
;; Now, disable symbols as I wish.
(dolist (disable-sym '(view-hello-file
(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)
(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 elec-pair
(electric-pair-mode +1))
(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)
,(rx (seq
(group bol (* space) "(setup" (+ space))
(? (group "(:" (+ graph) (* space) (? "(")))
(group (+ (any word ?+ ?-)))))
(:hook #'checkdoc-minor-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)
(let ((pulse-flag t))
(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.
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
kill-ring-max 500 ; RAM is cheap, right?
mark-ring-max 50
kmacro-ring-max 20
search-ring-max 200
global-mark-ring-max 100
regexp-search-ring-max 100
load-prefer-newer t
native-comp-async-report-warnings-errors nil
password-cache t
password-cache-expiry (* 60 5) ; seconds
set-mark-command-repeat-pop t
hscroll-step 1
scroll-step 1)
(when (fboundp 'command-completion-default-include-p)
(setq read-extended-command-predicate
(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)
(global-set-key (kbd "M-n") (kbd "C-u 1 C-v"))
(global-set-key (kbd "M-p") (kbd "C-u 1 M-v"))
;; inspo:
(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."
(setq lexical-binding (not lexical-binding))
(message "Lexical-binding is %sabled."
(if lexical-binding "en" "dis"))
(:with-map case-map
(require 'titlecase)
(require 'acdw)
(:bind "c" #'capitalize-dwim
"t" #'titlecase-dwim
"u" #'upcase-dwim
"l" #'downcase-dwim))
(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
(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)
(: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
(: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)
(:hook #'eshell-arg-hist-mode
(defun eshell-mode@setup ()
(require 'eshellrc (locate-user-emacs-file "eshell") :noerror)
(:bind "C-d" #'eshell-quit-or-delete-char))))
(setup eww
(:also-load acdw-eww)
(defvar-local eww-readable-p nil
"Whether current buffer is in readable-mode.")
(:option eww-search-prefix ""
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 "RET" (defun eww/browse-url (arg)
(interactive "P")
(if-let ((url (thing-at-point 'url)))
(browse-url url)
(call-interactively #'acdw/link-hint-open-link)))
"b" #'bookmark-set
"B" #'bookmark-jump
"M-n" nil
"M-p" nil))
(setup executable
(:option executable-prefix-env t)
(add-hook 'after-save-hook
(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
;; TODO: look at flycheck for ideas around `flycheck-disabled-checkers' and
;; `flycheck-emacs-lisp-load-path'... there must be a way to get flymake to
;; recognize new values in the load path.
(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\\'"
"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."
;; FINE alphapapa ;P
(seq-some (lambda (regexp)
(string-match regexp (or string "")))
(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-inhibit-file-name-regexps': a list of regexps to match
the filename against. If one of them matches, inhibit
- `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'."
;; The name of this hook tells you pretty much everything you need to know
;; for this little thing right here.
(add-hook 'hack-local-variables-hook
(defun flymake-unless@hack-local-variables ()
(unless (or (cdr (assoc 'flymake-inhibit
(apply #'derived-mode-p
(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@"
(or (file-remote-p default-directory 'host)
" %+%* 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
("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 ()
(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
'(read-only t cursor-intangible t face minibuffer-prompt)
read-answer-short t
read-extended-command-predicate ; used on >28
(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 mu4e
(:load-from "/usr/share/emacs/site-lisp/mu4e")
(:autoload (mu4e :interactive t)
(:option message-kill-buffer-on-exit t
message-send-mail-function #'smtpmail-send-it
mu4e-change-filenames-when-moving t
mu4e-completing-read-function 'completing-read
mu4e-compose-context-policy 'ask-if-none
mu4e-context-policy 'ask-if-none
;; Work
:name "Work"
:match-func (lambda (msg)
(when msg
(mu4e-message-field msg :maildir))))
:vars `((user-mail-address . ,work-email)
(smtpmail-smtp-server . ,work-smtp-server)
(mu4e-compose-format-flowed . nil)
. ,(concat work-mail-dir "/[Gmail]/Drafts"))
. ,(concat work-mail-dir "/[Gmail]/Sent Mail"))
. ,(concat work-mail-dir "/[Gmail]/All Mail"))
. ,(concat work-mail-dir "/[Gmail]/Trash"))
. ,(mapcar (lambda (cell)
(let ((dir (car cell))
(char (cdr cell)))
(cons (concat work-mail-dir dir) char)))
'(("/Inbox" . ?i)
("/[Gmail]/All Mail" . ?a)
("/[Gmail]/Sent" . ?s)
("/[Gmail]/Drafts" . ?d)
("/[Gmail]/Trash" . ?t))))))
;; Home
:name "Home"
:match-func (lambda (msg)
(when msg
(mu4e-message-field msg :maildir))))
:vars `((user-mail-address . ,home-email)
(smtpmail-smtp-server . ,home-smtp-server)
(mu4e-compose-signature . "~ Case")
(mu4e-compose-format-flowed . nil)
. ,(concat home-mail-dir "/Drafts"))
. ,(concat home-mail-dir "/Sent"))
. ,(concat home-mail-dir "/Archive"))
. ,(concat home-mail-dir "/Trash"))
. ,(mapcar (lambda (cell)
(let ((dir (car cell))
(char (cdr cell)))
(cons (concat home-mail-dir dir) char)))
'(("/INBOX" . ?i)
("/Archive" . ?a)
("/Sent" . ?s)
("/Drafts" . ?d)
("/Trash" . ?t)))))))
mu4e-get-mail-command "mbsync -a"
mu4e-maildir "~/mail"
mu4e-update-interval (unless
;; I just realized... there is probably a
;; /much/ better way to do this.
(getenv "XDG_CONFIG_HOME")))
(* 60 5))
sendmail-program (seq-some #'executable-find
message-sendmail-f-is-evil t
message-sendmail-extra-arguments '("--read-envelope-from")
message-send-mail-function #'smtpmail-send-it
send-mail-function #'smtpmail-send-it
smtpmail-smtp-service 465
smtpmail-stream-type 'ssl)
(:with-mode mu4e-view-mode
(:hook #'reading-mode)))
(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))
(: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
(defun prog-mode@auto-fill ()
(setq-local comment-auto-fill-only-comments t)
(setup pulse
(:option pulse-flag nil
pulse-delay 0.5
pulse-iterations 1)
;; XXX: this doesn't work yet. I only want to pulse the line in the active
;; window, so when I have the same buffer viewed in multiple windows I can
;; still see where my cursor is. To see the issue, C-x 2 then C-x o a few
;; times.
(defun pulse-line-current-window (&rest _)
"Pulse the current line, but only if this window is active."
(pulse-momentary-highlight-one-line (window-point (selected-window))))
(dolist (func '(scroll-up-command
(advice-add func :after #'pulse-line-current-window)))
(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
(concat ";; Howdy, "
(nth 0 (split-string
"! "
"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)
(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
(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-image-proportion 0.6
shr-image-animate t
shr-discard-aria-hidden t))
(setup text
(:hook turn-on-auto-fill
(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."
(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
indent-tabs-mode nil
tab-width 4
backward-delete-char-untabify-method 'hungry)
(:global "M-SPC" #'cycle-spacing)
(: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)
;; 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)
;; 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
(: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 (actually-selected-window
:host github
:repo "duckwork/actually-selected-window.el"))
(actually-selected-window-mode +1))
(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)
(defun acdw-circe/format-meta (string)
"Return a format string for `lui-format'."
(format "{nick:%1$d.%1$ds} *** %s" (- acdw-irc/left-margin 3) string))
(: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-format-server-part (acdw-circe/format-meta
"PART {channel}: {reason}")
circe-format-server-quit (acdw-circe/format-meta "QUIT: {reason}")
circe-format-server-quit-channel (acdw-circe/format-meta
"QUIT {channel}: {reason}")
circe-format-server-join (acdw-circe/format-meta "JOIN: {userinfo}")
circe-format-server-rejoin (acdw-circe/format-meta
(concat "REJOIN: {userinfo}"
" after {departuredelta}"))
circe-format-server-topic (acdw-circe/format-meta
"TOPIC: {new-topic}")
circe-prompt-string (format (format "%%%ds> "
(- acdw-irc/left-margin 2))
" ")
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))))
(with-eval-after-load 'topsy
(:option (append topsy-mode-functions)
'(circe-channel-mode . circe-current-topic)))
(:bind "C-c C-p" #'circe-command-PART
"C-c C-t" #'circe-current-topic ; in acdw-circe.el
"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-display-images
(:bind "C-c C-s" #'circe-command-SLAP)
(autoload 'circe-nick-color-reset "circe-color-nicks")
(add-hook 'modus-themes-after-theme-hook
(: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
(:face lui-time-stamp-face
((t :inherit font-lock-comment-face)))
(: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 " ")
nyan-mode nil
line-number-mode nil
column-number-mode nil
file-percentage-mode nil))
(add-hook 'kill-emacs-hook
(defun circe-quit-all ()
(advice-remove 'circe-command-GQUIT 'circe-gquit@kill-buffer)
(circe-command-GQUIT "Quitting Emacs, bye!")))))
(setup (:straight (command-log-mode
:host github
:repo "positron-solutions/command-log-mode"))
;; I have many ideas as to how to change this.
(:option clm-window-text-scale 0
clm-logging-shows-buffer t
clm-log-globally t
clm-exceptions '(self-insert-command)
clm-window-size 0.25)
(el-patch-feature command-log-mode)
(with-eval-after-load 'command-log-mode
(el-patch-defun clm--show-buffer (&optional clear)
"Displays the command log buffer in a window.
CLEAR will clear the buffer if it exists before returning it."
(let ((buffer (clm--setup-buffer clear)))
(let ((win (get-buffer-window buffer)))
(unless (windowp win)
(let ((new-win (el-patch-swap
(- 0 clm-window-size))
(if (< (window-pixel-width) (window-pixel-height))
(- (if (floatp clm-window-size)
(floor (* (window-height) clm-window-size))
(- (if (floatp clm-window-size)
(floor (* (window-width) clm-window-size))
(set-window-buffer new-win buffer)
(set-window-dedicated-p new-win t)
(with-current-buffer buffer
(setq-local mode-line-format nil)))))
(setup (:straight (consult
:host github
:repo "minad/consult"))
(:require acdw-consult)
(:autoload consult-register-preview)
;; Bindings
;; 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
(: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
(with-eval-after-loads (vertico consult)
(:with-map consult-crm-map
(:bind "RET" (defun +vertico-crm-exit ()
(run-at-time 0 nil #'vertico-exit)
(funcall #'vertico-exit))
"TAB" #'vertico-exit))))
(setup (:straight consult-dir)
(:with-feature project
(:autoload project--read-project-list))
(:global "C-x C-d" #'consult-dir)
(with-eval-after-load 'vertico
(:with-map vertico-map
(:bind "C-x C-d" #'consult-dir
"C-x C-j" #'consult-dir-jump-file))))
(setup (:straight crux)
(:global "C-o" #'crux-smart-open-line
"M-o" #'open-paragraph
"C-M-\\" #'crux-cleanup-buffer-or-region
"C-x 4 t" #'crux-transpose-windows)
(el-patch-feature crux)
(with-eval-after-load 'crux
(el-patch-defun crux-reopen-as-root ()
"Find file as root if necessary.
Meant to be used as `find-file-hook'.
See also `crux-reopen-as-root-mode'."
(unless (or
;; This helps fix for `nov-mode', and possibly others.
(el-patch-add (null buffer-file-name))
(tramp-tramp-file-p buffer-file-name)
(equal major-mode 'dired-mode)
(not (file-exists-p (file-name-directory buffer-file-name)))
(file-writable-p buffer-file-name)
(crux-file-owned-by-user-p buffer-file-name))
(crux-find-alternate-file-as-root buffer-file-name))))
(crux-reopen-as-root-mode +1))
;; (setup (:straight-when
;; (define-repeat-map
;; :host nil
;; :repo "")
;; (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
(:option (append dogears-ignore-modes) mode)))
(:global "M-g d" dogears-go)
(:autoload dogears-mode)
(dogears-mode +1))
(setup (:straight edit-indirect))
;; requires extension:
(setup (:straight edit-server)
(:require edit-server)
(:option edit-server-default-major-mode 'text-mode
(list (cons (rx (| ""
(cons (rx "")
(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
:host github
:repo "skeeto/elfeed")
(:option elfeed-use-curl t
elfeed-curl-extra-arguments '("--insecure")
elfeed-feeds `(("fever+"
:api-url ""
:password ,(acdw/make-password-fetcher
:host "")
:autotags ; do I want to use elfeed-org ?
'(("r/emacs" reddit social emacs)
("" emacs)
("" social)
("" comics)
("" comics)
("" emacs)
("" comics)
("" emacs)
("" lisp programming)
("" scheme programming)
("" comics)
("" video)
("" social)
("" comics))))
elfeed-show-unique-buffers t)
(:autoload elfeed-set-timeout)
(elfeed-set-timeout 3600)
(:advise elfeed :after
(defun elfeed@protocol-update (&rest _)
(elfeed-search-fetch nil)))
(:with-mode elfeed-search-mode
(:bind "G" (defun elfeed-protocol|update-first (arg)
(interactive "P")
(let ((first-proto (caar elfeed-feeds)))
(if arg
(call-interactively #'elfeed-protocol-fever-reinit)
(with-temp-message (format "Updating %s" first-proto)
(elfeed-protocol-fever-reinit first-proto)))))))
(:with-mode elfeed-show-mode
(:hook #'reading-mode)
(:local-set shr-max-image-proportion 0.9
visual-fill-column-width (+ fill-column 5))
;; see
(: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
(setup (:straight (elpher
:host nil
:repo "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-when emacs-everywhere
(and (executable-find "xclip")
(executable-find "xdotool")
(executable-find "xprop")
(executable-find "xwininfo"))))
(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"))
(window-parameters (mode-line-format . none)))
embark-prompter #'embark-keymap-prompter
'(display-buffer-at-bottom (window-height . fit-window-to-buffer))
(lambda (map _target)
(which-key--show-keymap "Embark" map nil nil 'no-paging)
embark-become-indicator embark-action-indicator)
(with-eval-after-loads (embark consult)
(:straight embark-consult)
(add-hook 'embark-collect-mode-hook
(setup (:straight epithet)
(dolist (hook '(Info-selection-hook
(add-hook hook #'epithet-rename-buffer)))
;; TODO: look into emms or something related for this
(setup (:straight-when eradio
(executable-find "mpv"))
eradio-player '("mpv" "--no-video" "--no-terminal")
eradio-channels `(("KLSU" .
("Soma FM Synphaera" .
("SomaFM BAGel Radio" .
("SomaFM Boot Liquor" .
("SomaFM Deep Space One" .
("SomaFM Fluid" .
("SomaFM Underground 80s" .
("WBRH: Jazz & More" .
("KBRH Blues & Rhythm Hits" .
("WRKF HD-2" .
,(concat ""
("WRKF: NPR for the Capital Region" .
,(concat ""
("BadRadio: 24/7 PHONK" .
("tilderadio" .
("vantaradio" .
(: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
(setup (:straight-when exec-path-from-shell
(acdw/system :home))
(when (daemonp)
(exec-path-from-shell-copy-envs '("XDG_CONFIG_HOME"
(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."
(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
'("" "" ""
(setup (:straight (frowny
:host github
:repo "duckwork/frowny.el"))
(:option frowny-eyes (rx (| ":" ":-" ":'" "="))
frowny-eyes-looking-back-limit 2)
(global-frowny-mode +1))
(setup (:straight gcmh)
(:option gcmh-idle-delay 'auto)
(gcmh-mode +1))
(setup (:straight-when geiser
(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)))
(:file-match (rx ".rkt" eos)
(rx ".scm" eos)))
(setup (:straight (gemini-mode
:host nil
:repo ""))
(:file-match (rx (seq "." (or "gemini" "gmi") eos)))
(:hook turn-off-auto-fill))
(setup (:straight (gemini-write
:host nil
:repo ""
:branch "main"))
(with-eval-after-load 'elpher
(require 'gemini-write)))
(setup (:straight git-modes))
(setup (:straight helpful)
(:require-after 3)
(:global "<help> f" #'helpful-callable
"<help> v" #'helpful-variable
"<help> k" #'helpful-key
"<help> o" #'helpful-symbol))
(setup (:straight (hippie-completing-read
:host github
:repo "duckwork/hippie-completing-read"))
(:global "M-/" #'hippie-completing-read))
(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 ""))
(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
(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
(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
(interactive "P")
(avy-with link-hint-open-multiple-links
(link-hint--multiple (if prefix :open-secondary :open))))
(:option link-hint-avy-style 'at-full)
(: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-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 "" 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 ""
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
(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 mode-line-bell)
(:option mode-line-bell-flash-time 0.1)
(mode-line-bell-mode +1))
(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
(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
((,class :inherit (modus-themes-heading-1 fixed-pitch)
:extend t)))
((,class :inherit (modus-themes-heading-2 fixed-pitch)
:extend t)))
((,class :inherit (modus-themes-heading-3 fixed-pitch)
:extend t)))
((,class :inherit (modus-themes-heading-4 fixed-pitch)
:extend t)))
((,class :inherit (modus-themes-heading-5 fixed-pitch)
:extend t)))
((,class :inherit (modus-themes-heading-6 fixed-pitch)
:extend t)))
((,class :inherit (modus-themes-heading-7 fixed-pitch)
:extend t)))
((,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 (nyan-mode
:host github :repo "TeMPOraL/nyan-mode"
:fork (:host github :repo "duckwork/nyan-mode")
:files ("nyan-mode.el" "img")))
(:option nyan-animate-nyancat nil
nyan-bar-length 20
nyan-minimum-window-width (+ fill-column (/ nyan-bar-length 2)))
(nyan-mode +1)
(defun disable-nyan-mode ()
"Disable `nyan-mode' in current buffer."
(setq-local nyan-mode -1))
(dolist (mode '(eshell-mode
(add-hook mode #'disable-nyan-mode)))
;; (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-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)
(defun acdw/orderless-dispatch (pattern _index _total)
"My custom dispatcher for `orderless'."
;; Ensure that $ works with Consult commands, which add disambiguation
;; suffixes -- see `fix-dollar'
((string-suffix-p "$" pattern)
`(orderless-regexp . ,(concat (substring pattern 0 -1)
;; File extensions
((string-match-p "\\`\\.." pattern)
`(orderless-regexp . ,(concat "\\." (substring pattern 1)
;; 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 ""
:local-repo "org"
:depth full
:pre-build (straight-recipes-org-elpa--build)
:build (:not autoloads)
:files (:defaults
("etc/styles/" "etc/styles/*")))
:type git
:repo ""))
(: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 ; just the clock bit
;; org-clock-string-limit 25 ; gives enough information
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-done 'time
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 (length org-ellipsis))))
(: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
(:local-set unfill-fill-function #'org-fill-paragraph
(lambda (start end) "Count words stupidly with a limit."
(acdw-org/count-words-stupidly start
(with-eval-after-load 'org-export
(:option (append org-export-filter-final-output-functions)
(:local-hook before-save-hook
(defun org/before-save@prettify-buffer ()
(org-fill-paragraph nil t))
(acdw-org/fix-blank-lines t)
(org-align-tags :all)))
(with-eval-after-load 'org
(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)
(or scope
(thread-last org-clock-history
(mapcar 'marker-buffer)
(mapcar 'buffer-file-name)
(delq nil))
(user-error "No recent clocked tasks")))
(org-clock-in nil (when resolve
(org-read-date t t)))))
(consult-customize consult-clock-in
:prompt "Clock in: "
:preview-key (kbd "M-.")
(lambda (cand transform)
(if transform
0 'consult-org--buffer cand))
(let ((m (car (get-text-property
0 'consult-org--heading cand))))
(if (member m org-clock-history)
(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)
(lambda (s) (replace-regexp-in-string "[ \t]+\\'" "" s))
(cl-loop for head in path
for n from 0
head nil 'face
(nth (% n org-n-level-faces)
(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)) "..")))
(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
(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 "C-j" ; paredit-newline
(:hook-into emacs-lisp-mode lisp-interaction-mode
ielm-mode sly-repl-mode
lisp-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
(setup (:straight-when (pdf-tools
:host github
:repo "vedang/pdf-tools")
(acdw/system :home))
(:file-match (rx ".pdf" eos))
(setup (:straight popper)
(:option popper-reference-buffers
`(,(rx "*Messages*")
,(rx "Output*" eol)
,(rx "*Async Shell Command*")
help-mode helpful-mode
popper-mode-line nil
popper-display-control t
(defun popper/select-popup-smartly (buffer &optional _alist)
(let* ((widep (> (frame-pixel-width) (frame-pixel-height)))
(window (display-buffer-in-side-window
`((side . ,(if widep 'right 'bottom))
(slot . 1)
,(if widep
(cons 'window-width
(cons 'window-height
(select-window window)))
(defun popper/figure-window-height (window)
(let* ((widep (> (frame-pixel-width) (frame-pixel-height)))
(fit-window-to-buffer-horizontally widep))
(floor (frame-pixel-height) 2)
(floor (frame-pixel-height) 4)
(:global "M-`" #'popper-toggle-latest
"C-`" #'popper-cycle)
(popper-mode +1)
(when (fboundp 'popper-echo-mode)
(popper-echo-mode +1)))
(setup (:straight-when (powershell
:host github
:repo "jschaf/powershell.el")
(acdw/system :work)))
(setup (:straight (shell-command+
:host nil
:repo ""))
(:option shell-command-prompt "$ ")
(:with-feature dired
(:bind "M-!" shell-command+))
(:global "M-!" shell-command+))
(setup (:straight sicp))
(setup (:straight simple-modeline
(: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
) (;; right
(: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)))
(propertize " "
'display (el-patch-swap
`((space :align-to (- right ,reserve)))
`((space :align-to
(- right
(- 1 right-fringe right-margin)
'face '(:inherit simple-modeline-space))
(simple-modeline-mode +1))
(setup (:straight-when sly
(defvar acdw/lisps
(let (lisps)
(dolist (lisp '("sbcl" ; TODO: add more lisps
(when-let (binary (executable-find lisp))
(push binary lisps)))
(nreverse 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 ()
(if (<= (point-max) (point))
(if (bound-and-true-p paredit-mode)
(dolist (key '("RET" "<return>"))
(:bind key #'sly-mrepl-return-at-end))
(:bind "C-c C-c" #'sly-mrepl-return)))
(setup (:straight (spongebob-case
:host github
:repo "duckwork/spongebob-case.el"))
(:global "C-c c s" #'spongebob-case-dwim))
(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 t
super-save-idle-duration 60
super-save-exclude '(".gpg")
super-save-remote-files nil)
(auto-save-visited-mode -1)
(super-save-mode +1))
(setup (:straight-when system-packages
(seq-some #'executable-find
;; I can't use `system-packages-supported-package-managers'
;; because, well, the package isn't installed yet. So
;; ... update this list if any package managers are added.
'("guix" "nix"
"brew" "macports"
"pacman" "emerge"
"zypper" "dnf"
"apt" "aptitude"
(setup (:straight-when systemd
(executable-find "systemd")))
(setup (:straight (topsy
:host github
:repo "alphapapa/topsy.el"))
(:hook-into prog-mode)
(:option topsy-header-line-format
(propertize " "
(bound-and-true-p visual-fill-column-mode)
(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\\'"
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-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 (1+ fill-column)
visual-fill-column-center-text t
(append reading-modes) '(visual-fill-column-mode . +1)
(append reading-modes) '(visual-line-mode . +1)
(append reading-vars) '(fill-column . 0))
(: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)
(:advise text-scale-adjust :after #'visual-fill-column-adjust)
;; Fix bindings
(when (bound-and-true-p mouse-wheel-mode)
(with-eval-after-load 'visual-fill-column
(dolist (margin '(right-margin left-margin))
(dolist (event '(wheel-down wheel-up))
(define-key visual-fill-column-mode-map
(vector margin event)
(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 "<