emacs/init.el

889 lines
29 KiB
EmacsLisp
Raw Blame History

This file contains invisible Unicode characters

This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

;;; init.el -*- lexical-binding: t; coding: utf-8-unix -*-
;; Author: Case Duckworth <acdw@acdw.net>
;; 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:
;; - Don't hurt yourself.
;; - Make good choices.
;;; Code:
;; Let's use lexical binding by default, shall we?
(setq-default lexical-binding t)
;;; Necessary packages
;;; `setup'
(progn
(straight-use-package '(setup :host nil
:repo "https://git.sr.ht/~zge/setup"))
(require 'setup))
(setup-define :straight
(lambda (recipe)
`(straight-use-package ',recipe))
:documentation "Install RECIPE with `straight-use-package'."
:repeatable t
:shorthand (lambda (sexp)
(let ((recipe (cadr sexp)))
(if (consp recipe)
(car recipe)
recipe))))
(setup-define :leader
(lambda (key command)
`(progn
(autoload #',command (symbol-name setup-name))
(define-key acdw/leader
,(if (stringp key) (kbd key) key)
#',command)))
:documentation "Bind KEY to COMMAND in `acdw/leader' (C-z) map."
:repeatable t)
(setup-define :mode
(lambda (ext)
`(add-to-list 'auto-mode-alist (cons ,ext setup-mode)))
:documentation "Add SETUP-MODE to `auto-mode-alist' for EXTENSION."
:repeatable t)
;;; `no-littering'
(setup (:straight no-littering)
(:option no-littering-etc-directory (acdw/dir)
no-littering-var-directory (acdw/dir))
(require 'no-littering))
;;; My packages
(let ((default-directory (expand-file-name "pkg/" user-emacs-directory)))
(normal-top-level-add-subdirs-to-load-path))
;;; Good defaults
(defmacro setc (&rest args)
"Customize user options using ARGS like `setq'."
(declare (debug setq))
`(setup (:option ,@args)))
(setup emacs
;; Me
(:option user-full-name "Case Duckworth"
user-mail-address "acdw@acdw.net"
calendar-location-name "Baton Rouge, LA"
calendar-latitude 30.4
calendar-longitude -91.1)
;; Lines
(:option fill-column 79
word-wrap t
truncate-lines nil)
(global-display-fill-column-indicator-mode +1)
(global-so-long-mode +1)
;; 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)
(add-hook 'before-save-hook #'whitespace-cleanup)
;; Killing and yanking
(:option save-interprogram-paste-before-kill t
yank-pop-change-selection t
x-select-enable-clipboard t
x-select-enable-primary t
mouse-drag-copy-region t
kill-do-not-save-duplicates t)
(delete-selection-mode +1)
;; Encoding
(:option locale-coding-system 'utf-8-unix
coding-system-for-read 'utf-8-unix
coding-system-for-write 'utf-8-unix
buffer-file-coding-system 'utf-8-unix
default-process-coding-system '(utf-8-unix . utf-8-unix)
x-select-request-type '(UTF8_STRING
COMPOUND_TEXT
TEXT
STRING))
(set-charset-priority 'unicode)
(set-language-environment "UTF-8")
(prefer-coding-system 'utf-8-unix)
(set-default-coding-systems 'utf-8-unix)
(set-terminal-coding-system 'utf-8-unix)
(set-keyboard-coding-system 'utf-8-unix)
(pcase acdw/system
(:work (set-clipboard-coding-system 'utf-16-le)
(set-selection-coding-system 'utf-16-le))
(_ (set-selection-coding-system 'utf-8)
(set-clipboard-coding-system 'utf-8)))
;; Cursor
(:option cursor-type 'bar
cursor-in-non-selected-windows 'hollow
blink-cursor-blinks 1)
(blink-cursor-mode +1)
;; Scrolling
(:option auto-window-vscroll nil
fast-but-imprecise-scrolling t
scroll-margin 0
scroll-conservatively 101
scroll-preserve-screen-position 1)
;; Minibuffer
(:option minibuffer-prompt-properties
'(read-only t cursor-intangible t face minibuffer-prompt)
enable-recursive-minibuffers t
file-name-shadow-properties '(invisible t intangible t)
read-answer-short t)
(add-hook 'minibuffer-setup-hook #'acdw/gc-disable)
(add-hook 'minibuffer-exit-hook #'acdw/gc-enable)
(minibuffer-depth-indicate-mode +1)
(file-name-shadow-mode +1)
(minibuffer-electric-default-mode +1)
(fset 'yes-or-no-p #'y-or-n-p)
;; Completion
(:option completion-ignore-case t
read-buffer-completion-ignore-case t
icomplete-delay-completions-threshold 0
icomplete-max-delay-chars 0
icomplete-compute-delay 0
icomplete-show-matches-on-no-input t
icomplete-with-buffer-completion-tables t
icomplete-in-buffer t
completion-styles '(partial-completion substring flex)
completion-category-defaults nil
completion-category-overrides
'((file (styles . (partial-completion)))))
(icomplete-mode +1)
;; Etc.
(:option inhibit-startup-screen t
initial-buffer-choice t
initial-scratch-message (concat ";; Howdy, "
(nth 0 (split-string
user-full-name))
"! "
"Welcome to GNU Emacs.\n\n")
initial-major-mode 'emacs-lisp-mode
disabled-command-function nil
load-prefer-newer t
comp-async-report-warnings-errors nil
frame-title-format '((:eval (if-let ((bn buffer-file-name))
(abbreviate-file-name bn)
"%b"))
" %+%* GNU Emacs"
(:eval (when (frame-parameter
nil 'client)
" Client")))
tab-bar-show 1
use-dialog-box nil
use-file-dialog nil
echo-keystrokes 0.01
recenter-positions '(top middle bottom)
attempt-stack-overflow-recovery nil
attempt-orderly-shutdown-on-fatal-signal nil
window-resize-pixelwise t
find-function-C-source-directory
(pcase acdw/system
(:work (expand-file-name (concat "~/src/emacs-"
emacs-version
"/src")))
(:home (expand-file-name
"~/src/pkg/emacs/src/emacs-git/src"))
(:other nil))
w32-allow-system-shell t
w32-pass-lwindow-to-system nil
w32-lwindow-modifier 'super
w32-pass-rwindow-to-system nil
w32-rwindow-modifier 'super
w32-pass-apps-to-system nil
w32-apps-modifier 'hyper
visible-bell nil
ring-bell-function #'flash-mode-line)
(defun flash-mode-line ()
"Flash the modeline as a bell."
(when (eq acdw/system :home)
(beep))
(invert-face 'mode-line)
(run-with-timer 0.1 nil #'invert-face 'mode-line))
(when-unfocused garbage-collect
(garbage-collect))
(tooltip-mode -1)
(winner-mode +1)
;; Bindings
(:global "M-SPC" cycle-spacing
"M-/" hippie-expand
"M-=" count-words
"C-x C-b" ibuffer
"C-c i" acdw/find-emacs-dotfiles))
;; Regular modes (`text-mode', `prog-mode', etc.)
(defun acdw/setup-regular-modes ()
(setq-local indicate-empty-lines t
indicate-buffer-boundaries '((top . right)
(bottom . right))))
(setup text
(:hook turn-on-auto-fill
acdw/setup-regular-modes))
(setup prog
(:option smie-indent-basic tab-width)
(hook-defun auto-fill-prog-mode prog-mode-hook
(setq-local comment-auto-fill-only-comments t)
(turn-on-auto-fill))
(:option show-paren-delay 0
show-paren-style 'mixed
show-paren-when-point-inside-paren t
show-paren-when-point-in-periphery t)
(:hook show-paren-mode
electric-pair-local-mode
acdw/setup-regular-modes)
(add-hook 'after-save-hook
#'executable-make-buffer-file-executable-if-script-p))
(setup cus-edit
(:option custom-file (acdw/dir "custom.el")
custom-magic-show nil
custom-magic-show-button t
custom-unlispify-tag-names nil
custom-variable-default-form 'edit))
(setup uniquify
(:option uniquify-buffer-name-style 'forward
uniquify-separator path-separator
uniquify-after-kill-buffer-p t
uniquify-ignore-buffers-re "^\\*"))
(setup files
(:option backup-directory-alist `((".*" . ,(acdw/dir "backup/" t)))
tramp-backup-directory-alist backup-directory-alist
auto-save-file-name-transforms `((".*" ,(acdw/dir "auto-save/" t) t))
auto-save-list-file-prefix (acdw/dir "auto-save-list/.saves-" t)
backup-by-copying t
delete-old-versions t
version-control t
vc-make-backup-files t)
(auto-save-visited-mode +1)
(when-unfocused save-some-buffers
(save-some-buffers t)))
(setup autorevert
(global-auto-revert-mode +1))
(setup saveplace
(:option save-place-file (acdw/dir "places.el")
save-place-forget-unreadable-files (eq acdw/system :home))
(save-place-mode +1))
(setup (:require recentf)
(:option recentf-save-file (acdw/dir "recentf.el")
recentf-max-menu-items 100
recentf-max-saved-items nil
recentf-auto-cleanup 60
(append recentf-exclude) (acdw/dir))
(recentf-mode +1))
(setup (:require savehist)
(:option (append savehist-additional-variables) 'kill-ring
(append savehist-additional-variables) 'search-ring
(append savehist-additional-variables) 'regexp-search-ring
history-length t
history-delete-duplicates t
savehist-autosave-interval 6
savehist-file (acdw/dir "savehist.el"))
(savehist-mode +1))
(setup imenu
(:option imenu-auto-rescan t))
(setup isearch
(:option search-default-mode t))
(setup debugger
(:hook visual-line-mode)
(:leader "d" toggle-debug-on-error))
(setup eldoc
(:option eldoc-idle-delay 0.1
eldoc-echo-area-use-multiline-p nil))
(setup flyspell
(setq-default ispell-program-name "hunspell"
ispell-dictionary "en_US"
ispell-personal-dictionary "~/.hunspell_personal")
(:needs ispell-program-name) ; don't proceed if not installed
(unless (file-exists-p ispell-personal-dictionary)
(write-region "" nil ispell-personal-dictionary nil 0))
(defun flyspell-start ()
"Start `flyspell-mode' or `flyspell-prog-mode', depending on current mode."
(interactive)
(cond ((derived-mode-p 'text-mode)
(flyspell-mode))
((derived-mode-p 'prog-mode)
(flyspell-prog-mode))
(t (message "Non-text or -prog mode. Run `flyspell-mode'."))))
(:leader "s" flyspell-start))
(setup scratch
(hook-defun immortal-scratch kill-buffer-query-functions
(if (eq (current-buffer) (get-buffer "*scratch*"))
(progn (bury-buffer)
nil)
t)))
;; Applications
(setup (:straight (org :host nil
:repo "https://code.orgmode.org/bzg/org-mode.git"))
(require 'acdw-org)
(:option org-adapt-indentation nil
org-catch-invisible-edits 'smart
org-confirm-babel-evaluate nil
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-imenu-depth 3
org-pretty-entities t
org-special-ctrl-a/e t
org-special-ctrl-k t
org-src-fontify-natively t
org-src-tab-acts-natively t
org-src-window-setup 'current-window
org-startup-truncated nil
org-tags-column (- 0 fill-column -3)
org-directory "~/org")
(:bind "RET" unpackaged/org-return-dwim)
(add-hook 'before-save-hook #'acdw/hook--org-mode-fix-blank-lines)
(advice-add 'org-delete-backward-char :override #'acdw-org/delete-backward-char))
(setup eshell
(:option eshell-directory-name (acdw/dir "eshell/" t)
eshell-aliases-file (acdw/dir "eshell/aliases" t))
(defun eshell-quit-or-delete-char (arg)
"Delete the character to the right, or quit eshell on an empty line."
(interactive "p")
(if (and (eolp) (looking-back eshell-prompt-regexp))
(eshell-life-is-too-much)
(delete-forward-char arg)))
(hook-defun eshell-setup 'eshell-mode-hook
(define-key eshell-mode-map (kbd "C-d")
#'eshell-quit-or-delete-char)
(when (fboundp simple-modeline--mode-line)
(setq mode-line-format '(:eval simple-modeline--mode-line)))))
(setup ediff
(:option ediff-window-setup-function 'ediff-setup-windows-plain
ediff-split-window-function 'split-window-horizontally))
(setup browse-url
(setq-default browse-url-browser-function 'eww-browse-url
browse-url-secondary-browser-function
(if (executable-find "firefox")
'browse-url-firefox
'browse-url-default-browser)
browse-url-new-window-flag t
browse-url-firefox-new-window-is-tab t)
(when (eq acdw/system :work)
(add-to-list 'exec-path "C:/Program Files/Mozilla Firefox")))
(setup shr
(:option shr-width fill-column
shr-max-width fill-column
shr-max-image-proportion 0.6
shr-image-animate t
shr-discard-aria-hidden t))
(setup eww
(:hook acdw/reading-mode))
(setup (:straight (elpher :host nil
:repo "git://thelambdalab.xyz/elpher.git"))
(:option elpher-ipv4-always t
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)
;; Make `eww' gemini/gopher aware. From Emacswiki.
(advice-add 'eww-browse-url :around
(defun elpher:eww-browse-url (original url &optional new-window)
"Handle gemini and gopher links."
(cond ((string-match-p "\\`\\(gemini\\|gopher\\)://" url)
(require 'elpher)
(elpher-go url))
(t (funcall original url new-window))))))
(setup (:straight (gemini-mode
:host nil
:repo "https://git.carcosa.net/jmcbray/gemini.el.git"))
(:mode "\\.\\(gemini\\|gmi\\)\\'"))
(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)
(:also-load dired-x)
(:hook dired-hide-details-mode
hl-line-mode)
(:global "C-x C-j" dired-jump)
(:bind "RET" dired-find-alternate-file)
(with-eval-after-load 'dired
(setup (:straight dired-subtree)
(:with-map dired-mode-map
(:bind "i" dired-subtree-toggle
"TAB" dired-subtree-cycle)))
(setup (:straight dired-collapse)
(:hook-into dired-mode))
(setup (:straight trashed)
(setq-default trashed-action-confirmer 'y-or-n-p))))
(setup (:straight magit)
(:leader "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 nov)
(:option nov-text-width fill-column)
(:mode "\\.epub\\'"))
(setup gnus
(:option gnus-home-directory (expand-file-name "gnus" user-emacs-directory)
gnus-directory (expand-file-name "gnus/News" user-emacs-directory)
gnus-init-file (expand-file-name "gnus.el" user-emacs-directory))
(when (not (file-exists-p gnus-directory))
(make-directory gnus-directory :parents)))
(when (eq acdw/system :home)
(setup (:straight pdf-tools)
(pdf-loader-install))
(setup (:straight vterm)))
;; Extra packages
(setup (:straight beginend)
(beginend-global-mode +1))
(setup (:straight mwim)
(:global "C-a" mwim-beginning
"C-e" mwim-end))
(setup (:straight expand-region)
(:global "C-=" er/expand-region))
(setup (:straight crux)
(:global "M-o" crux-other-window-or-switch-buffer
"C-k" crux-kill-and-join-forward
"C-o" crux-smart-open-line-above
"C-S-o" crux-smart-open-line
"C-M-\\" crux-cleanup-buffer-or-region)
(crux-reopen-as-root-mode +1))
(setup (:straight avy)
(:global "C-:" avy-goto-char
"C-'" avy-goto-char-timer
"M-g f" avy-goto-line
"M-g w" avy-goto-word-1
"C-c C-j" avy-resume)
(eval-after-load "isearch"
'(define-key isearch-mode-map (kbd "C-'") #'avy-isearch)))
(setup (:straight zzz-to-char)
(defun acdw/zzz-up-to-char (prefix)
"Call `zzz-up-to-char', unless issued a PREFIX, in which case
call `zzz-to-char'."
(interactive "P")
(if prefix
(call-interactively #'zzz-to-char)
(call-interactively #'zzz-up-to-char)))
(:global "M-z" acdw/zzz-up-to-char))
(setup (:straight anzu)
(:option anzu-replace-to-string-separator ""
anzu-cons-mode-line-p nil)
(add-to-list 'mode-line-misc-info '(:eval (anzu--update-mode-line)))
(:global [remap query-replace] anzu-query-replace
[remap query-replace-regexp] anzu-query-replace-regexp)
(:with-map isearch-mode-map
(:bind [remap isearch-query-replace] anzu-isearch-query-replace
[remap isearch-query-replace-regexp]
anzu-isearch-query-replace-regexp))
(global-anzu-mode +1))
(setup (:straight async)
(autoload 'dired-async-mode "dired-async.el" nil t)
(dired-async-mode +1))
(setup (:straight undo-fu)
(:global "C-/" undo-fu-only-undo
"C-?" undo-fu-only-redo))
(setup (:straight undo-fu-session)
(:option undo-fu-session-incompatible-files '("/COMMIT_EDITMSG\\'"
"/git-rebase-todo\\'")
undo-fu-session-directory (acdw/dir "undo/" t)
undo-fu-session-compression (eq acdw/system :home))
(global-undo-fu-session-mode +1))
(setup (:straight (vertico
:host github
:repo "minad/vertico"))
(setq resize-mini-windows t)
(if (boundp 'comp-deferred-compilation-deny-list)
(add-to-list 'comp-deferred-compilation-deny-list "vertico"))
(icomplete-mode -1)
(vertico-mode +1))
(setup (:straight (orderless
:host github
:repo "oantolin/orderless"))
(require 'orderless)
(:option (prepend completion-styles) 'orderless))
(setup (:straight (consult
:host github
:repo "minad/consult"))
;; "Sensible" functions
(defun consult-sensible-grep ()
"Perform `consult-git-grep' if in a git project, otherwise `consult-ripgrep'
if ripgrep is installed, otherwise `consult-grep'."
(interactive "P")
(cond ((= (vc-backend buffer-file-name) "Git")
(call-interactively #'consult-git-grep))
((executable-find "rg")
(call-interactively #'consult-ripgrep))
(t (call-interactively #'consult-grep))))
(defun consult-sensible-find ()
"Peform `consult-locate' if locate is installed, otehrwise `consult-find'."
(interactive "P")
(cond ((executable-find "locate") (call-interactively #'consult-locate))
(t (call-interactively #'consult-find))))
;; Bindings
(:global
;; C-c bindings (`mode-specific-map')
"C-c h" consult-history
"C-c m" consult-mode-command
"C-c b" consult-bookmark
"C-c k" consult-kmacro
;; C-x bindings (`ctl-x-map')
"C-x M-:" consult-complex-command
"C-x b" consult-buffer
"C-x 4 b" consult-buffer-other-window
"C-x 5 b" consult-buffer-other-frame
;; Custom M-# bindings for fast register access
"M-#" consult-register-load
"M-'" consult-register-store
"C-M-#" consult-register
;; M-g bindings (`goto-map')
"M-g e" consult-compile-error
"M-g g" consult-goto-line
"M-g M-g" consult-goto-line
"M-g o" consult-outline
"M-g m" consult-mark
"M-g k" consult-global-mark
"M-g i" consult-imenu
"M-g I" consult-project-imenu
;; M-s bindings (`search-map')
"M-s g" consult-sensible-grep
"M-s f" consult-sensible-find
"M-s l" consult-line
"M-s m" consult-multi-occur
"M-s k" consult-keep-lines
"M-s u" consult-focus-lines
;; Other bindings
"M-y" consult-yank-pop
"<help> a" consult-apropos
;; Isearch integration
"M-s e" consult-isearch)
(:with-map isearch-mode-map
(:bind "M-e" consult-isearch
"M-s e" consult-isearch
"M-s l" consult-line))
;; Registers
(autoload 'consult-register-preview "consult")
(:option register-preview-delay 0
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))
(setup (:straight marginalia)
(:option marginalia-annotators '(marginalia-annotators-heavy
marginalia-annotators-light))
(marginalia-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-region 'bg-only
modus-themes-org-blocks 'grayscale
modus-themes-headings '((1 . section)
(t . no-color))
modus-themes-mode-line nil)
(acdw/sunrise-sunset #'modus-themes-load-operandi
#'modus-themes-load-vivendi))
(setup (:straight simple-modeline)
(setup (:straight minions))
(:option simple-modeline-segments
'((acdw-modeline/modified
acdw-modeline/buffer-name
acdw-modeline/vc-branch
simple-modeline-segment-position
simple-modeline-segment-word-count)
(simple-modeline-segment-misc-info
simple-modeline-segment-process
acdw-modeline/god-mode-indicator
acdw-modeline/minions
simple-modeline-segment-major-mode)))
(require 'acdw-modeline)
(simple-modeline-mode +1))
(setup (:straight olivetti)
(:option olivetti-body-width (+ fill-column 4)
olivetti-minimum-body-width fill-column))
(setup (:straight form-feed)
(global-form-feed-mode +1))
(setup (:straight which-key)
(:option which-key-show-early-on-C-h t
which-key-idle-delay 10000
which-key-idle-secondary-delay 0.05)
(which-key-setup-side-window-bottom)
(which-key-mode +1))
(setup (:straight helpful)
(:global "<help> f" helpful-callable
"<help> v" helpful-variable
"<help> k" helpful-key
"<help> o" helpful-symbol
"C-c C-d" helpful-at-point))
(setup (:straight (0x0 :host nil
:repo "https://git.sr.ht/~zge/nullpointer-emacs"))
(:option 0x0-default-host 'ttm))
(with-eval-after-load 'flyspell
(setup (:straight flyspell-correct)
(define-key flyspell-mode-map (kbd "C-;") #'flyspell-correct-wrapper)))
;;; Programming
;;; General tools
(setup (:straight (apheleia :host github
:repo "raxod502/apheleia"))
(apheleia-global-mode +1)
;; Use a dumb formatter on modes that `apheleia' doesn't work for.
(hook-defun dumb-auto-format before-save-hook
(setq stupid-modes '(makefile-mode))
;; If there's no apheleia formatter for the mode, just indent the buffer.
(unless (or (apply #'derived-mode-p stupid-modes)
(and (fboundp 'apheleia--get-formatter-command)
(apheleia--get-formatter-command)))
(indent-region (point-min) (point-max)))))
(setup (:straight (corfu
:host github
:repo "minad/corfu"))
(:option completion-cycle-threshold 3
tab-always-indent 'complete
corfu-cycle t)
(:with-map corfu-map
(:bind "TAB" corfu-next
"S-TAB" corfu-previous))
(:hook-into prog-mode
eshell-mode))
;;; Lisps
(defvar lispy-modes '(emacs-lisp-mode
eval-expression-minibuffer
ielm-mode
lisp-mode
lisp-interaction-mode
scheme-mode
slime-repl-mode)
"List of modes that are lisp-like enough to hook packages into.")
(setup (:straight paren-face)
(dolist (mode lispy-modes)
(add-hook (intern (concat (symbol-name mode) "-hook")) #'paren-face-mode)))
(setup (:straight paredit)
(dolist (mode lispy-modes)
(add-hook (intern (concat (symbol-name mode) "-hook")) #'paredit-mode))
(require 'eldoc)
(eldoc-add-command 'paredit-backward-delete 'paredit-close-round))
(setup elisp-mode
(:option eval-expression-print-length nil
eval-expression-print-level nil
lisp-indent-function #'lisp-indent-function)
(defun acdw/eval-region-or-buffer ()
(interactive)
(if (region-active-p)
(eval-region (region-beginning) (region-end))
(eval-buffer)))
(:with-map emacs-lisp-mode-map
(:bind "C-c C-c" 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)
(setup (:straight macrostep)
(define-key emacs-lisp-mode-map (kbd "C-c e") #'macrostep-expand))
(setup (:straight eros)
(:hook-into emacs-lisp-mode)))
(setup (:straight geiser))
(when-let (lisp-bin (or (executable-find "sbcl")
(executable-find "clisp")))
(setup (:straight slime)
(require 'slime-autoloads)
(:option inferior-lisp-program lisp-bin)
(when-let ((slime-helper (or (expand-file-name-exists-p
"~/quicklisp/slime-helper.el")
(expand-file-name-exists-p
"~/var/quicklisp/slime-helper.el"))))
(load slime-helper))
(with-eval-after-load 'company
(setup (:straight slime-company)
(:option slime-company-completion 'fuzzy
slime-company-after-completion nil)
(slime-setup '(slime-fancy slime-company))))))
(when (executable-find "fennel")
(setup (:straight fennel-mode)
(autoload 'fennel-repl "fennel-mode" nil t)
(:mode "\\.fnl\\'")))
(setup (:straight lua-mode)
(:mode "\\.lua\\'"))
(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-use-package 'flymake-shellcheck)
(:hook flymake-mode
flymake-shellcheck-load)))
(setup (:straight web-mode)
(:option css-level-offset 2
js-indent-level 2
sgml-indent-offset 2)
(:mode "\\.\\(p\\|dj\\)?html\\'"
"\\.html?\\'"
"\\.\\(tpl\\.\\)?php\\'"
"\\.[agj]sp\\'"
"\\.as[cp]x\\'"
"\\.erb\\'"
"\\.mustache\\'"))
(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)))
(when (eq acdw/system :home)
(setup (:straight pkgbuild-mode)))