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: 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 (:require tramp)
;; thanks Irreal! https://irreal.org/blog/?p=895
(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
#'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)
(: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 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-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"
"mov" "MOV")
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"
"taskiq"))
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)
;; 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
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 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)
`("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)
(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.
(: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
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
#'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)
(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: 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))
(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)
(: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 "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 "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
#'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
;; 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\\'"
"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."
;; FINE alphapapa ;P
(seq-some (lambda (regexp)
(string-match regexp (or string "")))
regexp-list))
(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'."
;; 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
file-local-variables-alist))
(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 mu4e
(:load-from "/usr/share/emacs/site-lisp/mu4e")
(:autoload (mu4e :interactive t)
make-mu4e-context)
(: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
mu4e-contexts
(list
;; Work
(make-mu4e-context
:name "Work"
:match-func (lambda (msg)
(when msg
(string-prefix-p
work-mail-dir
(mu4e-message-field msg :maildir))))
:vars `((user-mail-address . ,work-email)
(smtpmail-smtp-server . ,work-smtp-server)
(mu4e-compose-format-flowed . nil)
(mu4e-drafts-folder
. ,(concat work-mail-dir "/[Gmail]/Drafts"))
(mu4e-sent-folder
. ,(concat work-mail-dir "/[Gmail]/Sent Mail"))
(mu4e-refile-dir
. ,(concat work-mail-dir "/[Gmail]/All Mail"))
(mu4e-trash-folder
. ,(concat work-mail-dir "/[Gmail]/Trash"))
(mu4e-maildir-shortcuts
. ,(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
(make-mu4e-context
:name "Home"
:match-func (lambda (msg)
(when msg
(string-prefix-p
home-mail-dir
(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)
(mu4e-drafts-folder
. ,(concat home-mail-dir "/Drafts"))
(mu4e-sent-folder
. ,(concat home-mail-dir "/Sent"))
(mu4e-refile-folder
. ,(concat home-mail-dir "/Archive"))
(mu4e-trash-folder
. ,(concat home-mail-dir "/Trash"))
(mu4e-maildir-shortcuts
. ,(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.
(file-exists-p
(expand-file-name
"systemd/user/mbsync.timer"
(getenv "XDG_CONFIG_HOME")))
(* 60 5))
sendmail-program (seq-some #'executable-find
'("msmtp"
"sendmail"))
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))
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
#'prettify-symbols-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)
;; 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
scroll-down-command
recenter-top-bottom
other-window
switch-to-buffer
redraw-frame))
(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
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-image-proportion 0.6
shr-image-animate t
shr-discard-aria-hidden 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 (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-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-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
#'enable-lui-track)
(: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 ()
(ignore-errors
(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
(split-window-horizontally
(- 0 clm-window-size))
(if (< (window-pixel-width) (window-pixel-height))
(split-window-vertically
(- (if (floatp clm-window-size)
(floor (* (window-height) clm-window-size))
clm-window-size)))
(split-window-horizontally
(- (if (floatp clm-window-size)
(floor (* (window-width) clm-window-size))
clm-window-size)))))))
(set-window-buffer new-win buffer)
(set-window-dedicated-p new-win t)
(el-patch-add
(with-current-buffer buffer
(setq-local mode-line-format nil)))))
buffer)))))
(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 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 "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
:host github
:repo "skeeto/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))))
elfeed-show-unique-buffers t)
(:autoload elfeed-set-timeout)
(elfeed-set-timeout 3600)
(elfeed-protocol-enable)
(: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 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-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"))
"*"))
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))
(exec-path-from-shell-copy-envs '("XDG_CONFIG_HOME"
"XDG_CONFIG_DIRS"
"XDG_DATA_HOME"
"XDG_DATA_DIRS"
"XDG_CACHE_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."
(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 (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
(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 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 "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 '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-annotators-light))
(marginalia-mode +1))
(setup (:straight markdown-mode)
(:file-match (rx ".md" eos)
(rx ".markdown" eos))
(:hook #'variable-pitch-mode
#'visual-fill-column-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 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
#'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 (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
comint-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-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 ; 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
"M-j")
(:local-set unfill-fill-function #'org-fill-paragraph
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-export
(:option (append org-export-filter-final-output-functions)
#'org-export-remove-zero-width-spaces))
(:local-hook before-save-hook
(defun org/before-save@prettify-buffer ()
(save-mark-and-excursion
(mark-whole-buffer)
(org-fill-paragraph nil t))
(acdw-org/fix-blank-lines t)
(org-align-tags :all)))
(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 "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
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 popper)
(:option popper-reference-buffers
`(,(rx "*Messages*")
,(rx "Output*" eol)
,(rx "*Async Shell Command*")
help-mode helpful-mode
compilation-mode)
popper-mode-line nil
popper-display-control t
popper-display-function
(defun popper/select-popup-smartly (buffer &optional _alist)
(let* ((widep (> (frame-pixel-width) (frame-pixel-height)))
(window (display-buffer-in-side-window
buffer
`((side . ,(if widep 'right 'bottom))
(slot . 1)
,(if widep
(cons 'window-width
popper-window-height)
(cons 'window-height
popper-window-height))))))
(select-window window)))
popper-window-height
(defun popper/figure-window-height (window)
(let* ((widep (> (frame-pixel-width) (frame-pixel-height)))
(fit-window-to-buffer-horizontally widep))
(fit-window-to-buffer
window
(floor (frame-pixel-height) 2)
(floor (frame-pixel-height) 4)
fill-column
fill-column))))
(: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 "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/nyan-cat
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 (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"
"xbps"))))
(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
(bound-and-true-p 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 (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)
(acdw/setup-fringes))))
(: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)
#'mwheel-scroll))))))
(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 "<