emacs/init.el

1983 lines
70 KiB
EmacsLisp
Raw Normal View History

;;; init.el -*- lexical-binding: t; coding: utf-8-unix -*-
2021-02-26 17:31:50 +00:00
;; Author: Case Duckworth <acdw@acdw.net>
2021-03-01 05:58:57 +00:00
;; Created: Sometime during Covid-19, 2020
2021-02-26 17:31:50 +00:00
;; Keywords: configuration
2021-03-08 04:14:38 +00:00
;; URL: https://tildegit.org/acdw/emacs
2021-04-06 23:30:49 +00:00
;; Bankruptcy: 7
2021-03-16 16:16:21 +00:00
2021-03-01 05:58:57 +00:00
;; This file is NOT part of GNU Emacs.
2021-03-16 16:16:21 +00:00
;;; License:
2021-03-01 05:58:57 +00:00
;; Everyone is permitted to do whatever with this software, without
;; limitation. This software comes without any warranty whatsoever,
;; but with two pieces of advice:
;; - Don't hurt yourself.
;; - Make good choices.
2021-03-16 16:16:21 +00:00
;;; Code:
;;; Built-ins
;; NOTE that some of the names in `setup' forms are arbitrary.
(setup (:require auth-source)
(:option auth-sources '("~/.authinfo" "~/.authinfo.gpg")))
(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))
(advice-add '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))
(add-to-list 'savehist-additional-variables var))
(savehist-mode +1))
(setup (:require server)
(unless (server-running-p)
(server-start)))
(setup Info
(:hook variable-pitch-mode
acdw/reading-mode))
(setup acdw
(:also-load acdw-compat
acdw-lisp)
(acdw/require-private)
2021-04-06 22:59:45 +00:00
(:option user-full-name "Case Duckworth"
user-mail-address "acdw@acdw.net")
(when-let ((default-directory
(expand-file-name-exists-p "pkg/" user-emacs-directory)))
(normal-top-level-add-subdirs-to-load-path)))
2021-05-29 03:42:14 +00:00
(setup autorevert
2021-08-19 23:15:37 +00:00
(:option global-auto-revert-non-file-buffers t)
(global-auto-revert-mode +1))
(setup browse-url
(require 'acdw-browse-url)
2021-05-21 13:34:52 +00:00
(setq-default 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
2021-05-21 13:34:52 +00:00
browse-url-firefox-new-window-is-tab t)
(acdw/browse-url-set-handlers
2021-08-29 04:09:15 +00:00
(list
(cons (rx (seq "." (or "jpeg" "jpg" ; images
"png")
eos))
(lambda (&rest args)
(apply (if (executable-find "feh")
#'browse-url-feh
#'eww-browse-url)
args)))
(cons (rx (or "youtube.com" ; videos
"youtu.be"
(seq "." (or "mp4"
"gif")
eos)))
(lambda (&rest args)
(apply (if (executable-find "mpv")
#'browse-url-mpv
browse-url-secondary-browser-function)
args)))
(cons (rx (or "google.com" ; websites that don't work with eww
"reddit.com"
"twitter.com"))
browse-url-secondary-browser-function)
(cons "." ; everything else
#'eww-browse-url)))
;; Buttonize gemini:// links.
(acdw/add-button-url-regexp-protocol "gemini"))
(setup buffers
2021-05-05 17:33:20 +00:00
(:global "C-x k" acdw/kill-a-buffer))
2021-07-01 00:34:06 +00:00
(setup calendar
(:option calendar-week-start-day 1))
2021-07-01 00:34:06 +00:00
(setup completion
(:option completion-ignore-case t
read-buffer-completion-ignore-case t
2021-08-10 04:14:01 +00:00
completion-styles '(substring partial-completion)
completion-category-defaults nil
completion-category-overrides
'((file (styles . (partial-completion)))))
(:global "M-/" hippie-expand))
2021-04-06 22:59:45 +00:00
(setup cursor
(:option cursor-type 'bar
cursor-in-non-selected-windows 'hollow
blink-cursor-blinks 1)
(blink-cursor-mode +1))
2021-04-06 22:59:45 +00:00
(setup cus-edit
2021-08-22 20:04:48 +00:00
(:option custom-file null-device ; don't store customizations
custom-magic-show nil
custom-magic-show-button t
custom-raised-buttons nil
custom-unlispify-tag-names nil
custom-variable-default-form 'lisp)
;; `Custom-mode-hook' fires /before/ the widgets are built, so I have to
;; install advice after the widgets are made.
(advice-add
'custom-buffer-create :after
(defun custom-buffer@expand-widgets (&rest _)
"Expand descriptions and values of variables in `Custom-mode' buffers."
(interactive)
;; "More/Hide" widgets (thanks alphapapa!)
(widget-map-buttons (lambda (widget _)
(pcase (widget-get widget :off)
("More" (widget-apply-action widget)))
nil))
;; "Show Value" widgets (the little triangles)
(widget-map-buttons (lambda (widget _)
(pcase (widget-get widget :off)
("Show Value" (widget-apply-action widget)))
nil))))
(add-hook ; thanks u/oantolin!
'Custom-mode-hook
(defun custom-mode@imenu ()
"Build `imenu' for `Custom-mode'."
(setq imenu-generic-expression
'(("Faces" "^\\(?:Show\\|Hide\\) \\(.*\\) face: \\[sample\\]" 1)
("Variables" "^\\(?:Show Value\\|Hide\\) \\([^:\n]*\\)" 1))))))
(setup debugger
2021-08-30 13:51:21 +00:00
(:hook visual-line-mode))
(setup dired
(setq-default dired-recursive-copies 'always
dired-recursive-deletes 'always
delete-by-moving-to-trash t
dired-listing-switches "-Al"
ls-lisp-dirs-first t
dired-ls-F-marks-symlinks t
dired-no-confirm '(byte-compile
chgrp chmod chown copy
hardlink load move
shell touch symlink)
dired-dwim-target t)
2021-08-26 04:04:42 +00:00
(:hook dired-hide-details-mode
hl-line-mode)
(:global "C-x C-j" dired-jump)
2021-04-06 22:59:45 +00:00
(acdw/system
(:work (:straight w32-browser)
(autoload 'dired-w32-browser "w32-browser")
(:bind "RET" dired-w32-browser))
(:home (:straight dired-open)
(require 'dired-open)
2021-08-26 04:04:42 +00:00
(:bind "RET" dired-find-alternate-file)))
(with-eval-after-load 'dired
(require 'dired-x)
(:straight dired-subtree)
(:bind "i" dired-subtree-toggle
"TAB" dired-subtree-cycle)
2021-08-26 04:04:42 +00:00
(:straight dired-collapse)
(:hook dired-collapse-mode)
2021-08-26 04:04:42 +00:00
(:straight dired-git-info)
(:bind ")" dired-git-info-mode)
2021-08-26 04:04:42 +00:00
(:straight trashed)
(:option trashed-action-confirmer #'y-or-n-p)))
2021-08-25 22:38:32 +00:00
(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))
2021-08-25 22:38:32 +00:00
;; 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))
2021-08-25 22:38:32 +00:00
;; 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.
2021-08-25 22:38:32 +00:00
(setq disabled-command-function
(defun acdw/disabled-command-function (&optional cmd keys)
(let ((cmd (or cmd this-command))
(keys (or keys (this-command-keys))))
;; this logic stolen from original `disabled-command-function'
(if (or (eq (aref keys 0) (if (stringp keys)
(aref "\M-x" 0)
?\M-x))
(and (>= (length keys) 2)
(eq (aref keys 0) meta-prefix-char)
(eq (aref keys 1) ?x)))
;; it's been run as an M-x command, we want to do it
(call-interactively cmd)
;; else, tell the user it's disabled.
(message (substitute-command-keys
(concat "Command `%s' has been disabled. "
"Run with \\[execute-extended-command]."))
cmd))))))
2021-08-25 22:38:32 +00:00
(setup ediff
(:option ediff-window-setup-function 'ediff-setup-windows-plain
ediff-split-window-function 'split-window-horizontally))
(setup eldoc
(:option eldoc-idle-delay 0.1
eldoc-echo-area-use-multiline-p nil))
(setup elisp-mode
(:option eval-expression-print-length nil
eval-expression-print-level nil
lisp-indent-function #'lisp-indent-function)
2021-04-06 22:59:45 +00:00
(add-hook 'emacs-lisp-mode-hook #'checkdoc-minor-mode)
2021-05-29 01:45:53 +00:00
(add-hook 'emacs-lisp-mode-hook
(defun emacs-lisp@enforce-lexical-binding ()
2021-08-31 04:39:21 +00:00
(setq-local lexical-binding t)))
2021-04-06 22:59:45 +00:00
2021-05-29 03:42:24 +00:00
(add-hook 'emacs-lisp-mode-hook
(defun emacs-lisp@imenu-add-setup ()
(add-to-list 'imenu-generic-expression
'("Setup"
"\\(^\\s-*(setup +(?\\)\\(\\_<.+\\_>\\)" 2))))
;; Emulate slime's eval binds
(:with-map emacs-lisp-mode-map
(:bind "C-c C-c" eval-defun
"C-c C-k" acdw/eval-region-or-buffer
"C-c C-z" ielm))
(add-hook 'emacs-lisp-mode-hook #'turn-on-eldoc-mode)
(add-hook 'ielm-mode-hook #'turn-on-eldoc-mode)
;; Add advice to pulse evaluated regions
(define-advice eval-region (:around (fn start end &rest args) pulse-region)
(pulse-momentary-highlight-region start end)
(apply fn start end args)))
(setup encoding
(:option locale-coding-system 'utf-8-unix
2021-04-06 22:59:45 +00:00
coding-system-for-read 'utf-8-unix
coding-system-for-write 'utf-8-unix
buffer-file-coding-system 'utf-8-unix
default-process-coding-system '(utf-8-unix . utf-8-unix)
x-select-request-type '(UTF8_STRING
COMPOUND_TEXT
TEXT
STRING))
(set-charset-priority 'unicode)
(set-language-environment "UTF-8")
(prefer-coding-system 'utf-8-unix)
(set-default-coding-systems 'utf-8-unix)
(set-terminal-coding-system 'utf-8-unix)
(set-keyboard-coding-system 'utf-8-unix)
(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)
(:option eshell-aliases-file (acdw/dir "eshell/aliases" t)
eshell-directory-name (acdw/dir "eshell/" t)
eshell-kill-on-exit nil
eshell-review-quick-commands nil
eshell-smart-space-goes-to-end t
eshell-where-to-jump 'begin)
(:global "C-c s" eshell-pop-or-quit)
(defun eshell-mode@setup ()
"Set up `eshell' for use.
Most customizations must go in this function since `eshell' loads
like a dumbass."
;; Define keys
(dolist (spec '(("C-d" . eshell-quit-or-delete-char)))
2021-08-25 01:15:53 +00:00
(define-key eshell-mode-map (kbd (car spec)) (cdr spec)))
2021-08-12 03:04:22 +00:00
;; Fix modeline
(when (boundp 'simple-modeline--mode-line)
2021-08-12 03:04:22 +00:00
(setq mode-line-format '(:eval simple-modeline--mode-line)))
2021-08-25 01:16:11 +00:00
;; Make navigating amongst prompts easier
(setq-local outline-regexp eshell-prompt-regexp
page-delimiter eshell-prompt-regexp))
2021-08-09 03:45:50 +00:00
(defun eshell-buffer-name ()
(rename-buffer (concat "*eshell*<" (eshell/pwd) ">") t))
(add-hook 'eshell-directory-change-hook #'eshell-buffer-name)
(add-hook 'eshell-prompt-load-hook #'eshell-buffer-name)
(:hook eshell-mode@setup
eshell-arg-hist-mode))
(setup eww
2021-05-20 03:00:59 +00:00
(:option eww-search-prefix "https://duckduckgo.com/html?q="
url-privacy-level '(email agent cookies lastloc))
(:hook acdw/reading-mode))
(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)
(:global "C-c i" acdw/find-emacs-dotfiles)
(auto-save-visited-mode +1)
2021-05-05 04:25:35 +00:00
(add-hook 'unfocused-hook
(defun unfocused@save-buffers ()
(save-some-buffers t))))
2021-08-23 22:29:40 +00:00
(setup flyspell
(add-hook 'text-mode-hook #'flyspell-mode))
(setup frames
2021-05-29 01:50:58 +00:00
(:option frame-title-format '("%b@"
(:eval
(or (file-remote-p default-directory 'host)
system-name))
" %+%* GNU Emacs"
2021-05-29 01:50:58 +00:00
(:eval (when (frame-parameter nil 'client)
" Client")))
window-resize-pixelwise t)
2021-05-05 04:25:35 +00:00
(add-hook 'unfocused-hook #'garbage-collect))
2021-04-06 22:59:45 +00:00
(setup gnus
2021-05-05 22:56:31 +00:00
(:option gnus-home-directory (acdw/dir "gnus" t)
gnus-directory (acdw/dir "News" t)
gnus-init-file (expand-file-name "gnus.el" user-emacs-directory))
2021-06-02 03:29:47 +00:00
(:global "C-c n" gnus))
2021-06-10 02:48:42 +00:00
(setup goto-addr
2021-08-31 04:39:21 +00:00
(add-hook 'after-change-major-mode-hook #'goto-address-mode))
2021-06-10 02:48:42 +00:00
2021-05-05 17:33:20 +00:00
(setup ibuffer
2021-08-25 02:24:43 +00:00
(:also-load ibuf-ext)
2021-05-05 17:33:20 +00:00
(:option ibuffer-saved-filter-groups
'(("default"
("dired" (mode . dired-mode))
2021-05-27 13:13:14 +00:00
("customize" (mode . Custom-mode))
2021-05-05 17:33:20 +00:00
("emacs" (or (name . "^\\*scratch\\*$")
(name . "^\\*Messages\\*$")
2021-05-27 13:13:14 +00:00
(name . "^\\*Warnings\\*$")
(name . "^\\*straight-process\\*$")
(name . "^\\*Calendar\\*$")))
("git" (or (name . "^\*magit")
(name . "^\magit")))
2021-05-05 17:33:20 +00:00
("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))))))
2021-05-05 17:33:20 +00:00
(global-set-key (kbd "C-x C-b") #'ibuffer)
2021-08-25 02:24:43 +00:00
(add-hook 'ibuffer-mode-hook
2021-08-20 13:29:40 +00:00
(defun ibuffer@filter-to-default ()
(ibuffer-switch-to-saved-filter-groups "default")))
(:option ibuffer-show-empty-filter-groups nil
ibuffer-expert t))
2021-05-05 17:33:20 +00:00
(setup imenu
(:option imenu-auto-rescan t))
2021-04-06 22:59:45 +00:00
(setup isearch
(:option search-default-mode t))
(setup lines
(:option fill-column 79
word-wrap t
truncate-lines nil)
2021-04-21 16:50:18 +00:00
(global-display-fill-column-indicator-mode +1)
(global-so-long-mode +1)
(add-hook 'visual-line-mode-hook
(defun acdw/disable-fill-column-indicator ()
(display-fill-column-indicator-mode
(if visual-line-mode -1 +1))))
2021-04-22 17:53:19 +00:00
2021-04-21 16:50:18 +00:00
;; `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.
(define-advice kill-line (:around (fn &rest args) join-killed-line)
(if (and (eolp)
(not (bolp)))
(delete-indentation 1)
(apply fn args))))
2021-04-06 22:59:45 +00:00
(setup minibuffer
2021-08-26 21:03:50 +00:00
(:option enable-recursive-minibuffers t
file-name-shadow-properties '(invisible t intangible t)
2021-08-26 21:03:50 +00:00
minibuffer-eldef-shorten-default t
minibuffer-prompt-properties
'(read-only t cursor-intangible t face minibuffer-prompt)
2021-08-10 04:14:14 +00:00
read-answer-short t
read-extended-command-predicate ; used on >28
#'command-completion-default-include-p)
2021-04-06 22:59:45 +00:00
2021-08-10 04:14:14 +00:00
(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)
(fset 'yes-or-no-p #'y-or-n-p))
2021-04-06 22:59:45 +00:00
(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))
2021-04-06 22:59:45 +00:00
(setup prog
(:option smie-indent-basic tab-width)
(add-hook 'prog-mode-hook
(defun prog-mode@auto-fill ()
(setq-local comment-auto-fill-only-comments t)
;; (advice-add 'do-auto-fill :after
;; (defun auto-fill@set-comment-column (&rest _)
;; (save-excursion
;; (when (or (looking-back comment-start-skip)
;; (progn (backward-word)
;; (looking-back
;; comment-start-skip)))
;; (comment-set-column t)))))
;; If the above advice is enabled, the below advice also needs to
;; be set to make `comment-dwim' work... I think.
;; (advice-add 'comment-dwim :before
;; (defun comment-dwim@set-comment-column (&rest _)
;; (setq comment-column 0)))
(turn-on-auto-fill)))
2021-04-06 22:59:45 +00:00
(:option show-paren-delay 0
show-paren-style 'mixed
show-paren-when-point-inside-paren t
show-paren-when-point-in-periphery t)
(defun flymake-mode-except ()
"Turn on flymake mode, except in some modes."
(let ((no-flymake-modes '(emacs-lisp-mode)))
(unless (or (member major-mode no-flymake-modes)
(apply #'derived-mode-p no-flymake-modes))
(flymake-mode-on))))
2021-04-06 22:59:45 +00:00
(:hook show-paren-mode
electric-pair-local-mode
flymake-mode-except
acdw/setup-fringes)
2021-04-06 22:59:45 +00:00
(add-hook 'after-save-hook
#'executable-make-buffer-file-executable-if-script-p))
(setup re-builder
(require 'acdw-re)
(advice-add 're-builder :before #'acdw/re-builder-save-state)
2021-04-06 22:59:45 +00:00
2021-05-05 04:45:30 +00:00
(add-hook 'reb-mode-hook #'paredit-mode)
(:global "<f2>" re-builder)
(dolist (map '(reb-mode-map reb-lisp-mode-map))
(let ((setup-map map))
(:bind "RET" reb-replace-regexp
"M-n" reb-next-match
"M-p" reb-prev-match
2021-08-07 20:13:10 +00:00
"C-g" reb-quit
"C-c C-k" reb-quit))))
2021-05-29 01:51:07 +00:00
(setup repeat
2021-08-25 04:01:20 +00:00
;; new for Emacs 28!
2021-05-29 01:51:07 +00:00
(:only-if (fboundp #'repeat-mode))
2021-08-25 04:01:20 +00:00
(:option repeat-exit-key "g"
repeat-exit-timeout 5)
2021-05-29 01:51:07 +00:00
(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))
2021-04-07 05:14:08 +00:00
(setup scratch
(:option inhibit-startup-screen t
initial-buffer-choice t
2021-09-01 22:57:12 +00:00
initial-scratch-message ""
;; (concat ";; Howdy, "
;; (nth 0 (split-string
;; user-full-name))
;; "! "
;; "Welcome to GNU Emacs.\n\n")
initial-major-mode 'emacs-lisp-mode)
(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
2021-08-25 22:38:45 +00:00
scroll-margin 3
scroll-conservatively 101
scroll-preserve-screen-position 1))
2021-04-03 14:45:59 +00:00
(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)
2021-04-03 14:45:59 +00:00
(delete-selection-mode +1))
(setup sh-mode
(:option sh-basic-offset tab-width
sh-indent-after-case 0
sh-indent-for-case-alt '+
sh-indent-for-case-label 0)
(:local-set indent-tabs-mode t)
(when (executable-find "shfmt")
(with-eval-after-load 'apheleia
(:option (append apheleia-formatters) '(shfmt . ("shfmt"))
(append apheleia-mode-alist) '(sh-mode . shfmt))))
(when (executable-find "shellcheck")
(:straight flymake-shellcheck)
(:hook flymake-mode
flymake-shellcheck-load)))
(setup shell-command
(:option shell-command-switch (acdw/system
;; I should be testing on some variable
(:home "-csi")
(:work "-c"))
shell-command-prompt-show-cwd t
shell-command-default-error-buffer "*shell-command-errors*"))
(setup shr
(:option shr-width fill-column
shr-max-width fill-column
shr-max-image-proportion 0.6
shr-image-animate t
2021-05-20 03:00:59 +00:00
shr-discard-aria-hidden t
shr-folding-mode t))
(setup text
(:hook turn-on-auto-fill
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 "^\\*"))
2021-04-03 14:45:59 +00:00
(setup variable-pitch-mode
2021-08-23 22:29:40 +00:00
;; I might want to change this to `buffer-face-mode-hook'...
(advice-add '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)
(add-hook 'view-mode-hook
(defun acdw/read-view-mode ()
(acdw/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))
2021-04-18 04:02:11 +00:00
(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)
2021-05-05 17:34:44 +00:00
(:global "M-SPC" cycle-spacing))
2021-04-03 14:45:59 +00:00
2021-08-25 04:01:20 +00:00
(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 windows
(require 'acdw-bell)
(:option use-dialog-box nil
use-file-dialog nil
tab-bar-show 1
visible-bell nil
ring-bell-function (lambda ()
(acdw-bell/flash-mode-line
(acdw/system :home)))
recenter-positions '(top middle bottom))
(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))
2021-04-19 13:24:46 +00:00
(setup x-emacs
;; "Et cetera" settings
;; This should stay as /minimal/ as possible. Anything that can go somewhere
;; else /should/ go there.
(:option
attempt-orderly-shutdown-on-fatal-signal nil
attempt-stack-overflow-recovery nil
echo-keystrokes 0.01
find-function-C-source-directory (acdw/find-emacs-source)
kill-read-only-ok t
load-prefer-newer t
native-comp-async-report-warnings-errors nil
2021-08-30 13:51:46 +00:00
set-mark-command-repeat-pop t)
2021-04-03 14:45:59 +00:00
2021-08-18 23:21:31 +00:00
(when (fboundp 'command-completion-default-include-p)
(setq read-extended-command-predicate
#'command-completion-default-include-p))
2021-09-01 13:37:17 +00:00
(defvar case-map (make-sparse-keymap)
"A keymap for setting case in various ways.")
(global-set-key (kbd "C-c c") case-map)
(:global "M-=" count-words
2021-05-12 21:42:18 +00:00
"C-w" kill-region-or-backward-word
2021-09-01 13:37:17 +00:00
"C-c c c" capitalize-dwim
"C-c c t" titlecase-dwim
"C-c c u" upcase-dwim
"C-c c l" downcase-dwim
2021-08-30 13:51:21 +00:00
"C-c d" acdw/insert-iso-date
"M-`" nil)
;; toggle bindings
(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))
(defalias 'forward-word-with-case 'forward-word
"Alias for `forward-word' for use in `case-repeat-map'.")
(defalias 'backward-word-with-case 'backward-word
"Alias for `backward-word for use in `case-repeat-map'.")
2021-08-30 13:51:21 +00:00
(defvar case-repeat-map
(let ((map (make-sparse-keymap)))
(define-key map "c" #'capitalize-word)
(define-key map "u" #'upcase-word)
(define-key map "l" #'downcase-word)
;; movement
(define-key map "f" #'forward-word-with-case)
(define-key map "b" #'backward-word-with-case)
map)
"A map to repeat word-casing commands. For use with `repeat-mode'.")
2021-08-30 13:51:21 +00:00
(dolist (command '(capitalize-word
capitalize-dwim
upcase-word
upcase-dwim
downcase-word
downcase-dwim
forward-word-with-case
backward-word-with-case))
(put command 'repeat-map 'case-repeat-map))
(add-hook 'after-make-frame-functions
(defun after-make-frame@maximize (frame)
(unless (bound-and-true-p edit-server-frame-p)
(toggle-frame-maximized frame)))))
2021-04-03 14:45:59 +00:00
;;; Packages
2021-08-10 13:30:17 +00:00
(setup (:straight (0x0 :host gitlab
:repo "willvaughn/emacs-0x0"))
(:option 0x0-default-server 'ttm))
(setup (:straight (apheleia :host github
:repo "raxod502/apheleia"))
(apheleia-global-mode +1)
2021-03-31 17:46:14 +00:00
;; Use a dumb formatter on modes that `apheleia' doesn't work for.
(add-hook 'before-save-hook
(defun before-save@dumb-auto-format ()
(setq stupid-modes '(makefile-mode
org-mode))
;; If there's no apheleia formatter for the mode, just indent the
;; buffer.
(unless (or (apply #'derived-mode-p stupid-modes)
(and (fboundp 'apheleia--get-formatter-command)
(apheleia--get-formatter-command)))
(indent-region (point-min) (point-max))))))
(setup (:straight (beginend))
(beginend-global-mode +1))
(setup (:straight (consult
:host github
:repo "minad/consult"))
(require 'acdw-consult)
(setq consult--regexp-compiler #'consult--orderless-regexp-compiler)
2021-04-01 21:39:46 +00:00
;; Bindings
(:global
2021-04-01 21:39:46 +00:00
;; 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
2021-04-01 21:39:46 +00:00
;; 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
2021-04-01 21:39:46 +00:00
"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))
2021-08-20 12:57:35 +00:00
;; see https://github.com/oantolin/completing-history
(defmacro consult-history-to-modes (map-hook-alist)
(let (defuns)
(dolist (map-hook map-hook-alist)
(let ((map-name (symbol-name (car map-hook)))
(key-defs `(progn (define-key
,(car map-hook)
(kbd "M-r")
(function consult-history))
(define-key ,(car map-hook)
(kbd "M-s") nil))))
(push (if (cdr map-hook)
`(add-hook ',(cdr map-hook)
(defun
,(intern (concat map-name
"@consult-history-bind"))
nil
,(concat
"Bind `consult-history' to M-r in "
map-name ".\n"
"Defined by `consult-history-to-modes'.")
,key-defs))
key-defs)
defuns)))
`(progn ,@ (nreverse defuns))))
(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)))
2021-04-01 21:39:46 +00:00
;; Registers
(autoload 'consult-register-preview "consult")
(:option register-preview-delay 0
2021-04-01 21:39:46 +00:00
register-preview-function #'consult-register-format)
(:advise register-preview :override #'consult-register-window)
;; Xref
(:option xref-show-xrefs-function #'consult-xref
xref-show-definitions-function #'consult-xref)
;; Projects
(:option consult-project-root-function #'vc-root-dir)
;; Competion-at-point (complete-region)
(:option completion-in-region-function #'acdw-consult/complete-in-region
completion-cycle-threshold 3
tab-always-indent 'complete)
;; Completing-read-multple
(if (fboundp #'consult-completing-read-multiple)
(:advise completing-read-multple
:override #'consult-completing-read-multiple)
;; else
(defun crm-indicator (args)
(cons (concat "[CRM] " (car args)) (cdr args)))
(:advise completing-read-multiple
:filter-args #'crm-indicator))
(with-eval-after-loads (vertico consult)
(when (boundp 'consult-crm-map)
(define-key consult-crm-map "\r" #'+vertico-crm-exit)
(define-key consult-crm-map "\t" #'vertico-exit)
(defun +vertico-crm-exit ()
(interactive)
(run-at-time 0 nil #'vertico-exit)
(funcall #'vertico-exit)))))
(setup (:straight (electric-cursor
:host github
:repo "duckwork/electric-cursor"))
(electric-cursor-mode +1))
(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 acdw/reading-mode)
(autoload 'elpher-bookmarks "elpher" nil t)
(autoload 'elpher-go "elpher" nil 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 (gemini-mode
:host nil
:repo "https://git.carcosa.net/jmcbray/gemini.el.git"))
(add-to-list 'auto-mode-alist '("\\.\\(gemini\\|gmi\\)\\'" . gemini-mode))
(: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 (mastodon
:host github
:repo "mooseyboots/mastodon.el"))
(:straight request)
(:option mastodon-instance-url "https://writing.exchange"
mastodon-auth-source-file (car auth-sources)
mastodon-client--token-file (acdw/dir "mastodon.plstore"))
(:hook hl-line-mode
acdw/reading-mode))
(setup (:straight (modus-themes
:host gitlab
:repo "protesilaos/modus-themes"))
(:option modus-themes-slanted-constructs t
modus-themes-bold-constructs t
modus-themes-region 'bg-only
modus-themes-org-blocks 'grayscale
modus-themes-headings '((1 . section)
(t . no-color))
modus-themes-mode-line nil)
(acdw/sunrise-sunset #'modus-themes-load-operandi
#'modus-themes-load-vivendi))
(setup (:straight (orderless
:host github
:repo "oantolin/orderless"))
(require 'orderless)
(:option (append completion-styles) 'orderless
orderless-component-separator #'orderless-escapable-split-on-space
orderless-style-dispatchers '(acdw/orderless-dispatch))
(defun fix-dollar (args)
(if (string-suffix-p "$" (car args))
(list (concat (substring (car args) 0 -1) "[\x100000-\x10FFFD]*$"))
args))
(advice-add #'orderless-regexp :filter-args #'fix-dollar)
(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 (topsy
:host github
:repo "alphapapa/topsy.el"))
(:hook-into prog-mode))
(setup (:straight (unfocused
:host github
:repo "duckwork/unfocused"))
(unfocused-mode +1))
(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)
(defun up-directory (arg)
"Move up a directory (delete backwards to /)."
(interactive "p")
(if (string-match-p "/." (minibuffer-contents))
(zap-up-to-char (- arg) ?/)
(backward-kill-word arg)))
(with-eval-after-load 'vertico
(define-key vertico-map (kbd "<C-backspace>") #'up-directory))
(if (boundp 'comp-deferred-compilation-deny-list)
(add-to-list 'comp-deferred-compilation-deny-list "vertico"))
(vertico-mode +1)
;; Extensions!
(:also-load vertico-mouse)
(vertico-mouse-mode +1)
;; Prefix the current candidate with "> ". From Vertico wiki.
(defun vertico-format@add-arrow (orig cand prefix suffix index _start)
(setq cand (funcall orig cand prefix suffix index _start))
(concat
(if (= vertico--index index)
(propertize "> " 'face 'vertico-current)
" ")
cand))
(advice-add #'vertico--format-candidate :around #'vertico-format@add-arrow))
(setup (:straight alert)
(:option alert-default-style (acdw/system
(:home 'libnotify)
(_ 'message))))
(setup (:straight async)
(autoload 'dired-async-mode "dired-async.el" nil t)
(dired-async-mode +1)
(add-hook 'dired-mode
(defun dired@disable-dired-async-mode-line ()
(autoload 'dired-async--modeline-mode "dired-async.el" nil t)
(dired-async--modeline-mode -1))))
(setup (:straight avy)
2021-09-02 22:31:09 +00:00
(:global "C-:" avy-goto-char-timer
"C-c C-j" avy-resume)
(with-eval-after-load "isearch"
(define-key isearch-mode-map (kbd "C-'") #'avy-isearch)))
(setup (:straight circe)
(require 'circe)
(require 'acdw-irc)
2021-09-02 22:07:25 +00:00
(:option acdw-irc/post-my-nick "-> "
circe-color-nicks-everywhere t
circe-default-nick "acdw"
circe-default-part-message "See You, Space Cowpokes . . ."
circe-default-user "acdw"
circe-highlight-nick-type 'sender
circe-network-options
`(("Libera Chat"
:channels ("#emacs" "#systemcrafters" "##webpals")
:sasl-username "acdw"
:sasl-password ,(acdw/fetch-password :host "libera.chat"))
("Tilde Chat"
:channels ("#meta" "#bread" "#dadjokes" "#team")
:host "irc.tilde.chat" :port 6697 :use-tls t
:sasl-username "acdw"
:sasl-password ,(acdw/fetch-password :host "tilde.chat"))
("Casa"
:channels ("#basement")
:host "m455.casa" :port 6697 :use-tls t
:sasl-username "acdw"
:sasl-password ,(acdw/fetch-password :host "m455.casa")))
circe-reduce-lurker-spam t
circe-server-auto-join-default-type :after-auth)
(custom-set-faces '(circe-nick-highlight-face
((t (:inherit (modus-themes-hl-line))))
:now))
(defface highlight
'((t :inverse-video t))
"Basic face for highlighting."
:group 'basic-faces)
(add-hook 'circe-chat-mode-hook
(defun circe-chat@setup ()
(lui-set-prompt
(concat (propertize (acdw-irc/margin-format (buffer-name)
""
">")
'face 'circe-prompt-face
'read-only t 'intangible t
'cursor-intangible t)
" "))
(enable-circe-color-nicks)
(enable-circe-display-images)
(enable-circe-new-day-notifier)))
2021-04-20 21:25:31 +00:00
2021-09-02 22:07:25 +00:00
(add-hook 'circe-chat-mode-hook #'acdw/stop-paren-annoyances)
(autoload 'circe-nick-color-reset "circe-color-nicks")
(add-hook 'modus-themes-after-load-theme-hook
#'circe-nick-color-reset)
2021-08-10 04:14:01 +00:00
(let ((len (number-to-string (- acdw-irc/left-margin 1
(+ (length acdw-irc/pre-nick)
(length acdw-irc/post-nick)))))
(my-len (number-to-string (- acdw-irc/left-margin 1
(+ (length acdw-irc/pre-my-nick)
(length acdw-irc/post-my-nick))))))
(setq circe-format-say (concat acdw-irc/pre-nick
"{nick:" len "." len "s} "
acdw-irc/post-nick
"{body}")
circe-format-self-say (concat acdw-irc/pre-my-nick
"{nick:" my-len "." my-len "s} "
acdw-irc/post-my-nick
"{body}")
circe-format-action (concat "*"
(repeat-string
(- acdw-irc/left-margin 3)
" ")
"* {nick} {body}")
circe-format-self-action (concat "-*"
(repeat-string
(- acdw-irc/left-margin 4)
" ")
"* {nick} {body}")
lui-fill-type (concat
(repeat-string (- acdw-irc/left-margin 2)
" ")
" ")))
2021-09-02 22:07:25 +00:00
(:option lui-fill-column fill-column
lui-time-stamp-position 'right-margin
lui-time-stamp-format "%H:%M"
lui-track-behavior 'before-switch-to-buffer
lui-track-indicator 'fringe)
(add-hook 'lui-mode-hook
(defun lui-mode@setup ()
(setq-local fringes-outside-margins t
right-margin-width 5
scroll-margin 0
word-wrap t
wrap-prefix (repeat-string
2021-09-02 22:07:25 +00:00
acdw-irc/left-margin " ")))))
(setup (:straight crux)
2021-08-25 04:01:20 +00:00
(:global "C-x o" acdw/other-window-or-switch-buffer
"C-o" crux-smart-open-line
"M-o" crux-smart-open-line-above
"C-M-\\" crux-cleanup-buffer-or-region
2021-08-12 01:25:40 +00:00
"C-x 4 t" crux-transpose-windows)
2021-08-25 04:01:20 +00:00
(when (fboundp 'repeat-mode)
2021-08-25 22:39:55 +00:00
(unless (boundp 'other-window-repeat-map)
(defvar other-window-repeat-map (make-sparse-keymap)
"A map for repeating `other-window' keys."))
2021-08-25 04:01:20 +00:00
(define-key other-window-repeat-map "o"
#'acdw/other-window-or-switch-buffer)
(define-key other-window-repeat-map "O"
(defun acdw/other-window-or-switch-buffer-backward ()
(interactive)
(setq repeat-map 'other-window-repeat-map)
(acdw/other-window-or-switch-buffer -1)))
(put 'acdw/other-window-or-switch-buffer
'repeat-map 'other-window-repeat-map))
2021-08-12 01:25:40 +00:00
(crux-reopen-as-root-mode +1))
;; requires extension:
;; https://addons.mozilla.org/en-US/firefox/addon/edit-with-emacs1/
(setup (:straight edit-server)
(when (and (daemonp)
(require 'edit-server nil :noerror))
(edit-server-start)
2021-08-29 15:37:15 +00:00
(advice-add 'edit-server-make-frame :before
(defun edit-server@set-a-variable (&rest _)
2021-09-01 23:14:15 +00:00
(setq-local edit-server-frame-p t)))))
2021-09-01 22:15:20 +00:00
(setup (:straight elfeed
elfeed-protocol)
(:option elfeed-use-curl t
elfeed-feeds `(("fever+https://acdw@mf.acdw.net"
:api-url "https://mf.acdw.net/fever/"
:password ,(acdw/fetch-password
:host "mf.acdw.net"))))
(elfeed-protocol-enable)
(add-hook 'elfeed-show-mode-hook
(defun elfeed-show@setup ()
2021-09-02 02:23:00 +00:00
(acdw/reading-mode)))
2021-09-01 22:15:20 +00:00
;; see https://irreal.org/blog/?p=8885
2021-09-02 22:07:36 +00:00
;; Lazy Elfeed (karthinks)
(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)))))
(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)))))
;; Turns out, `scroll-up' and `scroll-down' are /backward/
(define-key elfeed-show-mode-map (kbd "SPC") 'elfeed-scroll-up-command)
(define-key elfeed-show-mode-map (kbd "S-SPC") 'elfeed-scroll-down-command))
2021-09-01 22:15:20 +00:00
(setup (:straight elisp-slime-nav)
(:hook-into emacs-lisp-mode
ielm-mode))
(setup (:straight embark)
2021-08-12 03:06:26 +00:00
(:global "C-." embark-act)
(:option prefix-help-command #'embark-prefix-help-command
(append display-buffer-alist)
'("\\`\\*Embark Collect \\(Live\\|Completions\\)\\*"
nil
2021-08-10 04:36:58 +00:00
(window-parameters (mode-line-format . none)))
embark-prompter #'embark-keymap-prompter
embark-verbose-indicator-display-action
2021-08-10 04:46:48 +00:00
'(display-buffer-at-bottom (window-height . fit-window-to-buffer)))
2021-08-10 04:41:26 +00:00
(setq embark-action-indicator
(lambda (map _target)
(which-key--show-keymap "Embark" map nil nil 'no-paging)
#'which-key--hide-popup-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)))
2021-05-29 01:51:21 +00:00
(setup (:straight epithet)
(add-hook 'Info-selection-hook #'epithet-rename-buffer)
(add-hook 'eww-after-render-hook #'epithet-rename-buffer)
(add-hook 'help-mode-hook #'epithet-rename-buffer)
(add-hook 'occur-mode-hook #'epithet-rename-buffer))
(setup (:straight eros)
(:hook-into emacs-lisp-mode))
2021-05-30 04:18:35 +00:00
(setup (:straight expand-region)
(defun acdw/set-mark-or-expand-region (arg)
"Set mark at point and activate, jump to mark, or expand region.
See `set-mark-command' and `expand-region'.
With no prefix argument, either run `set-mark-command' on first
invocation and `er/expand-region' on each successive invocation.
With any prefix argument
(e.g., \\[universal-argument] \\[set-mark-command]), act as with
`set-mark-command' (i.e., pop the mark). Don't care about
successive invocations."
(interactive "P")
(cond
((or arg
(and set-mark-command-repeat-pop
(eq last-command 'pop-to-mark-command)))
(setq this-command 'set-mark-command)
(set-mark-command arg))
((eq last-command 'acdw/set-mark-or-expand-region)
(er/expand-region 1))
(t (set-mark-command arg))))
(:global "C-=" er/expand-region
"C-SPC" acdw/set-mark-or-expand-region))
(setup (:straight flyspell-correct)
(add-hook 'flyspell-mode-hook
(defun flyspell-mode@flyspell-correct ()
(dolist (keybind '(("C-;" . flyspell-correct-wrapper)
("C-," . nil)
("C-." . nil)
("C-M-i" . nil)))
(define-key flyspell-mode-map
(kbd (car keybind)) (cdr keybind))))))
2021-08-20 12:57:35 +00:00
(setup (:straight gcmh)
(:option gcmh-idle-delay 'auto)
(gcmh-mode +1))
;; TODO: figure out a popper.el / shackle.el ... thing to fix this
(setup (:straight helpful)
(:option helpful-max-buffers 5)
(:global "<help> f" helpful-callable
"<help> v" helpful-variable
"<help> k" helpful-key
"<help> o" helpful-symbol
"C-c C-d" helpful-at-point))
2021-05-30 04:18:42 +00:00
(setup (:straight iscroll)
2021-09-02 22:31:19 +00:00
(:hook-into text-mode ; Ideally, everywhere..
prog-mode
special-mode))
2021-05-30 04:18:42 +00:00
(setup (:straight lacarte)
(:global "<f10>" lacarte-execute-menu-command))
2021-09-01 22:58:08 +00:00
(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))
(defun acdw/link-hint-open-link (arg)
"Open a link using `link-hint-open-link', but like `browse-url-at-point'.
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))))
2021-09-02 22:31:09 +00:00
(setq link-hint-avy-style 'at)
(:global "C-;" acdw/link-hint-open-link))
2021-09-01 22:58:08 +00:00
(setup (:straight lua-mode)
(add-to-list 'auto-mode-alist '("\\.lua\\'" . lua-mode)))
(setup (:straight macrostep)
(define-key emacs-lisp-mode-map (kbd "C-c e") #'macrostep-expand))
(setup (:straight magit)
(:global "C-c g" magit-status)
(defun magit-display-buffer-same-window (buffer)
"Display BUFFER in the selected window like God intended."
(display-buffer buffer '(display-buffer-same-window)))
(:option magit-display-buffer-function #'magit-display-buffer-same-window
magit-popup-display-buffer-action '((display-buffer-same-window))
magit-refresh-status-buffer nil))
(setup (:straight marginalia)
2021-03-30 04:21:58 +00:00
(:option marginalia-annotators '(marginalia-annotators-heavy
marginalia-annotators-light))
(marginalia-mode +1))
2021-08-29 15:37:28 +00:00
(setup (:straight markdown-mode))
(setup (:straight mwim)
(:global "C-a" mwim-beginning
"C-e" mwim-end))
(setup (:straight nov)
(:option nov-text-width fill-column)
(add-to-list 'auto-mode-alist '("\\.epub\\'" . nov-mode)))
(setup (:straight olivetti)
(:option olivetti-body-width (+ fill-column 4)
olivetti-minimum-body-width fill-column)
(add-hook 'olivetti-mode-hook
(defun acdw/olivetti-mode-hook ()
(if olivetti-mode
(setq-local indicate-empty-lines nil
indicate-buffer-boundaries nil)
(acdw/setup-fringes)))))
(setup (:straight org
org-contrib)
(require 'acdw-org) ; so I don't clutter up init.el
2021-08-16 02:10:48 +00:00
(:option
org-adapt-indentation nil
2021-08-23 22:29:40 +00:00
org-agenda-files nil ; only until I set this up
2021-08-16 02:10:48 +00:00
org-catch-invisible-edits 'smart
org-clock-clocked-in-display 'mode-line
org-clock-string-limit 7 ; gives time and not title
org-confirm-babel-evaluate nil
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-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 0 ; (- 0 fill-column -3)
)
(:bind "RET" acdw-org/return-dwim
2021-06-02 03:30:05 +00:00
"<S-return>" acdw-org/org-table-copy-down
"M-SPC M-SPC" insert-zero-width-space
"C-c C-l" org-insert-link-dwim
"M-w" acdw/copy-region-plain
"C-c C-n" acdw/org-next-heading-widen
"C-c C-p" acdw/org-previous-heading-widen)
2021-06-02 03:30:05 +00:00
(with-eval-after-load 'org-export
(add-to-list 'org-export-filter-final-output-functions
#'org-export-remove-zero-width-spaces))
(defun acdw/org-fix-lines-before-save ()
(add-hook 'before-save-hook #'acdw-org/fix-blank-lines-in-buffer 0 :local))
(:hook variable-pitch-mode
2021-08-27 23:01:38 +00:00
olivetti-mode
acdw/org-fix-lines-before-save)
(advice-add 'org-delete-backward-char
2021-08-16 02:10:48 +00:00
:override #'acdw-org/delete-backward-char)
(add-hook 'org-mode-hook
(defun org-mode@wc-stupid ()
(unless (and wc-mode
2021-08-17 22:26:53 +00:00
(> 0 (+ (or wc-orig-words 0)
(or wc-words-delta 0)))))
(setq-local
wc-count-words-function
(lambda (start end) "Count words stupidly with a limit."
(acdw-org/count-words-stupidly start
end
999))))))
(setup (:straight org-appear)
(:hook-into org-mode))
(setup (:straight package-lint))
(setup (:straight package-lint-flymake))
2021-04-03 14:47:58 +00:00
(setup (:straight page-break-lines)
(global-page-break-lines-mode +1))
(setup (:straight paredit)
2021-04-25 04:23:15 +00:00
;; I don't use paredit-splice-sexp much, and it stomps on isearch.
(:unbind "M-s")
2021-08-30 21:37:02 +00:00
(defun paredit@setup ()
2021-04-25 04:23:15 +00:00
"Correct weirdnesses and set up paredit mode."
2021-08-30 21:37:02 +00:00
(:with-map lisp-mode-shared-map
(:bind "DEL" paredit-backward-delete
"C-M-;" comment-or-uncomment-sexp
"C-<backspace>" paredit-backward-kill-word))
(paredit-mode +1))
2021-04-25 04:23:15 +00:00
(dolist (mode lispy-modes)
2021-04-25 04:23:15 +00:00
(add-hook (intern (concat (symbol-name mode) "-hook"))
2021-08-30 21:37:02 +00:00
#'paredit@setup))
2021-04-06 22:59:45 +00:00
(require 'eldoc)
2021-04-06 22:59:45 +00:00
(eldoc-add-command 'paredit-backward-delete 'paredit-close-round))
(setup (:straight paren-face)
(dolist (mode lispy-modes)
(add-hook (intern (concat (symbol-name mode) "-hook")) #'paren-face-mode)))
2021-08-30 13:51:54 +00:00
(setup (:straight persistent-scratch)
(:option persistent-scratch-backup-directory (acdw/dir "scratch" t)
2021-08-31 03:18:45 +00:00
persistent-scratch-keep-n-newest-backups 12)
(persistent-scratch-setup-default)
(mapc (lambda (buf)
(with-current-buffer buf
(when (funcall persistent-scratch-scratch-buffer-p-function)
(persistent-scratch-mode +1))))
(buffer-list)))
2021-08-30 13:51:54 +00:00
(setup (:straight restart-emacs)
2021-05-04 02:31:29 +00:00
(defun emacs-upgrade (&optional update-packages)
"Pull config, upgrade packages, restart Emacs."
2021-05-04 02:31:29 +00:00
(interactive "P")
(when update-packages
(straight-pull-all))
(emacs-git-pull-config)
(restart-emacs)))
2021-04-09 17:50:11 +00:00
(setup (:straight simple-modeline)
(setup (:straight minions))
(require 'acdw-modeline)
(:option
simple-modeline-segments '(;; left
(acdw-modeline/modified
acdw-modeline/buffer-name
acdw-modeline/vc-branch
2021-08-10 19:47:00 +00:00
acdw-modeline/position)
;; right
(simple-modeline-segment-misc-info
acdw-modeline/track
acdw-modeline/wc
acdw-modeline/text-scale
simple-modeline-segment-process
acdw-modeline/god-mode-indicator
acdw-modeline/winum
acdw-modeline/minions
2021-08-07 21:59:56 +00:00
acdw-modeline/narrowed
2021-08-28 05:23:56 +00:00
acdw-modeline/major-mode)))
;; I've put in a pull request to add the (- 0 right-margin) bit here.
(advice-add 'simple-modeline--format :override
(defun simple-modeline@format (lefts rights)
(let* ((left (simple-modeline--format-segments lefts))
(right (simple-modeline--format-segments rights))
(reserve (length right)))
(concat
left
(propertize " "
'display `((space :align-to
(- right
(- 0 right-margin)
,reserve)))
'face '(:inherit simple-modeline-space))
right))))
(simple-modeline-mode +1))
2021-04-03 14:47:19 +00:00
2021-06-03 04:38:30 +00:00
(setup (:straight ssh-config-mode)
(dolist (spec '(("/\\.ssh/config\\'" . ssh-config-mode)
("/sshd?_config\\'" . ssh-config-mode)
("/knownhosts\\'" . ssh-known-hosts-mode)
("/authorized_keys2?\\'" . ssh-authorized-keys-mode)))
(add-to-list 'auto-mode-alist spec))
2021-06-03 04:38:30 +00:00
(add-hook 'ssh-config-mode-hook #'turn-on-font-lock))
(setup (:straight typo)
2021-08-31 03:18:45 +00:00
;; Enable C-c 8 map in all buffers
(typo-global-mode +1)
(add-hook 'text-mode-hook
(defun text-mode@typo-unless ()
2021-08-30 21:37:34 +00:00
"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.
2021-08-31 03:18:45 +00:00
(unless (or ; predicates here
(string-match-p "COMMIT_EDITMSG"
(or (buffer-name) "")))
2021-08-31 03:18:45 +00:00
(typo-mode +1))))
(with-eval-after-load 'typo
;; 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.)
(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."
("`" ""))
(:bind "'" typo-cycle-apostrophe
"`" typo-cycle-backtick)))
(setup (:straight undo-fu)
(:global "C-/" undo-fu-only-undo
"C-?" undo-fu-only-redo))
2021-04-03 14:48:05 +00:00
(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))
(setup (:straight wc-mode) ; TODO: move some of this stuff around
(:option wc-modeline-format "[%tww]"
2021-08-16 14:13:14 +00:00
wc-idle-wait 2)
2021-05-27 13:13:08 +00:00
(:hook-into text-mode)
(defun acdw-modeline/wc ()
"Display current `wc-buffer-stats'."
(when (bound-and-true-p wc-mode)
2021-08-13 02:05:48 +00:00
(or wc-buffer-stats "[w]"))))
2021-05-27 13:13:08 +00:00
(setup (:straight web-mode)
2021-03-30 04:21:58 +00:00
(:option css-level-offset 2
js-indent-level 2
sgml-indent-offset 2)
(dolist (ext '("\\.\\(p\\|dj\\)?html\\'"
"\\.html?\\'"
"\\.\\(tpl\\.\\)?php\\'"
"\\.[agj]sp\\'"
"\\.as[cp]x\\'"
"\\.erb\\'"
"\\.mustache\\'"))
(add-to-list 'auto-mode-alist `(,ext . web-mode))))
2021-03-11 18:16:50 +00:00
(setup (:straight which-key)
(:option which-key-show-early-on-C-h t
which-key-idle-delay 1
2021-05-05 17:34:21 +00:00
which-key-idle-secondary-delay 0.5)
2021-05-05 00:58:30 +00:00
(which-key-setup-side-window-right-bottom)
(which-key-mode +1))
2021-04-10 22:30:58 +00:00
2021-05-05 17:34:44 +00:00
(setup (:straight whitespace-cleanup-mode)
(global-whitespace-cleanup-mode +1))
(setup (:straight winum)
(:option winum-scope 'frame-local
winum-auto-setup-mode-line nil
2021-05-22 21:41:42 +00:00
winum-ignored-buffers '(" *which-key*")
winum-format " %s")
(when-unfocused winum-map-keys
(defvar winum--keys-mapped nil
"Whether `winum' keys have been mapped already.")
(when (and (not winum--keys-mapped)
(display-graphic-p))
(:with-map winum-keymap
(:bind "M-0" winum-select-window-0-or-10
"M-1" winum-select-window-1
"M-2" winum-select-window-2
"M-3" winum-select-window-3
"M-4" winum-select-window-4
"M-5" winum-select-window-5
"M-6" winum-select-window-6
"M-7" winum-select-window-7
"M-8" winum-select-window-8
"M-9" winum-select-window-9))
(setq winum--keys-mapped t)))
(winum-mode +1))
2021-05-26 12:32:36 +00:00
(setup (:straight xr))
(setup (:straight zzz-to-char)
(defun acdw/zzz-up-to-char (prefix)
"Call `zzz-up-to-char', unless issued a PREFIX, in which case
call `zzz-to-char'."
(interactive "P")
(if prefix
(call-interactively #'zzz-to-char)
(call-interactively #'zzz-up-to-char)))
(:global "M-z" acdw/zzz-up-to-char))
(setup (:straight-if (pdf-tools
:host github
:repo "vedang/pdf-tools")
(acdw/system :home))
(add-to-list 'auto-mode-alist '("\\.pdf\\'" . pdf-view-mode))
(pdf-loader-install))
(setup (:straight-if affe
(and (or (executable-find "fd")
(executable-find "find"))
(executable-find "rg")))
;; Keys are bound in `acdw/sensible-grep' and `acdw/sensible-find'
(defun affe-orderless-regexp-compiler (input _type)
(setq input (orderless-pattern-compiler input))
(cons input (lambda (str) (orderless--highlight input str))))
(:option affe-regexp-compiler #'affe-orderless-regexp-compiler))
(setup (:straight-if ahk-mode
(acdw/system :work)))
;; TODO: look into emms or something related for this
(setup (:straight-if 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://radio.tildeverse.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-if exec-path-from-shell
(acdw/system :home))
(when (daemonp)
(exec-path-from-shell-initialize)))
(setup (:straight-if fennel-mode
(executable-find "fennel"))
(autoload 'fennel-repl "fennel-mode" nil t)
(add-to-list 'auto-mode-alist '("\\.fnl\\'" . fennel-mode)))
(setup (:straight-if geiser
(progn
(defvar acdw/schemes
(let (schemes) ; these binaries should be checked...
(dolist (scheme '(("scheme" . geiser-chez) ; chez
("petite" . geiser-chez) ; petite
("csi" . geiser-chez) ; chicken
("gsi" . geiser-gambit) ; gambit
("gosh" . geiser-gauche) ; 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)))
(setup (:straight-if ledger-mode
(executable-find "ledger")))
(setup (:straight-if pkgbuild-mode
(executable-find "makepkg")))
(setup (:straight-if sly
(progn (defvar acdw/lisp-bin
(or (executable-find "sbcl")
(executable-find "clisp")
""))
(executable-find acdw/lisp-bin)))
(:option inferior-lisp-program acdw/lisp-bin
sly-kill-without-query-p t)
(:also-load sly-autoloads)
(setup (:straight clhs))
(:with-feature sly-mrepl
(dolist (key '("RET" "<return>"))
(:bind key sly-mrepl-return-at-end))
(:bind "C-c C-c" sly-mrepl-return))
(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)))))
(setup (:straight-if systemd
(executable-find "systemd")))
2021-08-27 01:05:02 +00:00
(setup (:straight-if vterm
(acdw/system :home)))
2021-06-07 19:09:48 +00:00
(setup gforth
(when (locate-library "gforth")
(autoload 'forth-mode "gforth")
(add-to-list 'auto-mode-alist '("\\.fs\\'" . forth-mode))
(autoload 'forth-block-mode "gforth")
(add-to-list 'auto-mode-alist '("\\.fb\\'" . forth-block-mode))))
2021-07-14 21:59:13 +00:00
;;; init.el ends here