emacs/init.el

1066 lines
34 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:
;;; Setup
;;;; `setup'
(straight-use-package '(setup :host nil :repo "https://git.sr.ht/~zge/setup"))
(require 'setup)
(setup setup
(setup-define :straight
(lambda (recipe)
`(or (ignore-errors (straight-use-package ',recipe))
(progn
(message "Straight error: %S" ',recipe)
(throw 'setup-exit nil))))
: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))
;;;; `no-littering'
(setup (:straight no-littering)
(:option no-littering-etc-directory (acdw/dir)
no-littering-var-directory (acdw/dir))
(require 'no-littering))
;;;; My packages
(when-let ((default-directory
(expand-file-name-exists-p "pkg/" user-emacs-directory)))
(normal-top-level-add-subdirs-to-load-path))
;;;; Utility functions and variables
;; see also: `acdw' and friends. Functions here aren't big enough, or they're
;; too tightly bound to stuff here, to be placed in `acdw'.
;; Flash the 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))
(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.")
;;; Basics
;; NOTE that some of the names in `setup' forms are arbitrary.
(setup acdw
(: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))
(setup autorevert
(global-auto-revert-mode +1))
(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 buffers
(:global "C-x C-b" ibuffer
"C-x k" acdw/kill-a-buffer))
(setup 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)))))
(:global "M-/" hippie-expand)
(icomplete-mode +1))
(setup cursor
(:option cursor-type 'bar
cursor-in-non-selected-windows 'hollow
blink-cursor-blinks 1)
(blink-cursor-mode +1))
(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 debugger
(:hook visual-line-mode)
(:leader "d" toggle-debug-on-error))
(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)
(pcase acdw/system
(:work (:straight w32-browser)
(autoload 'dired-w32-browser "w32-browser")
(:bind "RET" dired-w32-browser))
(:home (:straight dired-open)
(require 'dired-open)
(:bind "RET" dired-find-alternate-file)
(:option (prepend dired-open-functions) #'dired-open-xdg)))
(:when-loaded
(:straight dired-subtree)
(:bind "i" dired-subtree-toggle
"TAB" dired-subtree-cycle)
(:straight dired-collapse)
(:hook dired-collapse-mode)
(:straight dired-git-info)
(:bind ")" dired-git-info-mode)
(:straight trashed)
(:option trashed-action-confirmer #'y-or-n-p)))
(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)
(defun acdw/enforce-lexical-binding ()
(setq lexical-binding t))
(add-hook 'emacs-lisp-mode-hook #'acdw/enforce-lexical-binding)
(defun acdw/eval-region-or-buffer ()
(interactive)
(if (region-active-p)
(let ((begin (region-beginning))
(end (region-end)))
(with-message (format "Evaluating %S -> %S" begin end)
(eval-region begin end)))
(with-message "Evaluating buffer"
(eval-buffer))))
;; 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)
(setup (:straight macrostep)
(define-key emacs-lisp-mode-map (kbd "C-c e") #'macrostep-expand))
(setup (:straight eros)
(:hook-into emacs-lisp-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
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))))
(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)))
(global-set-key (kbd "<f12>") #'eshell)
(hook-defun eshell-setup 'eshell-mode-hook
(define-key eshell-mode-map (kbd "<f12>") #'bury-buffer)
(define-key eshell-mode-map (kbd "C-d") #'eshell-quit-or-delete-char)
(when (boundp 'simple-modeline--mode-line)
(setq mode-line-format '(:eval simple-modeline--mode-line)))))
(setup eww
(:hook acdw/reading-mode))
(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)
(:global "C-c i" acdw/find-emacs-dotfiles)
(auto-save-visited-mode +1)
(when-unfocused save-some-buffers
(save-some-buffers t)))
(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)
(:when-loaded
(setup (:straight flyspell-correct)
(define-key flyspell-mode-map (kbd "C-;") #'flyspell-correct-wrapper))))
(setup frames
(:option frame-title-format '((:eval (if-let ((bn buffer-file-name))
(abbreviate-file-name bn)
"%b"))
" %+%* GNU Emacs"
(:eval (when (frame-parameter
nil 'client)
" Client")))
window-resize-pixelwise t)
(when-unfocused garbage-collect
(garbage-collect)))
(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))
(:leader "m" gnus))
(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.
(define-advice kill-line (:around (fn &rest args) join-killed-line)
(if (and (eolp)
(not (bolp)))
(delete-indentation 1)
(apply fn args))))
(setup 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))
(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-fringes)
(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)
(:global "C-M-%" 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
"M-q" reb-quit))))
(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 history-length t
history-delete-duplicates t
savehist-autosave-interval 6
savehist-file (acdw/dir "savehist.el"))
(dolist (var '(kill-ring
search-ring
regexp-search-ring))
(:option (append savehist-additional-variables) var))
(savehist-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 scratch
(: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)
(hook-defun immortal-scratch kill-buffer-query-functions
(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 0
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 (:require server)
(unless (server-running-p)
(server-start)))
(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 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 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 "^\\*"))
(setup view
(:option view-read-only t)
(defun acdw/read-view-mode ()
(acdw/reading-mode (if view-mode +1 -1)))
(:hook acdw/read-view-mode))
(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)
(add-hook 'before-save-hook #'whitespace-cleanup))
(setup windows
(:option use-dialog-box nil
use-file-dialog nil
tab-bar-show 1
visible-bell nil
ring-bell-function #'flash-mode-line
recenter-positions '(top middle bottom))
(tooltip-mode -1)
(winner-mode +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))
;;; "Et cetera" settings
;; This should stay as /minimal/ as possible. Anything that can go somewhere
;; else /should/ go there.
(setup emacs
(:option disabled-command-function nil
load-prefer-newer t
comp-async-report-warnings-errors nil
echo-keystrokes 0.01
attempt-stack-overflow-recovery nil
attempt-orderly-shutdown-on-fatal-signal nil
find-function-C-source-directory (acdw/find-emacs-source))
(:global "M-=" count-words
"C-w" acdw/kill-region-or-backward-word)
;; Remap C-h to DEL -- <f1> can be the "help" key
(define-key key-translation-map [?\C-h] [?\C-?])
(:leader "C-c" save-buffers-kill-emacs
"t" acdw/insert-iso-date))
;;; Packages
(setup (:straight (0x0 :host nil
:repo "https://git.sr.ht/~zge/nullpointer-emacs"))
(:option 0x0-default-host 'ttm))
(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 async)
(autoload 'dired-async-mode "dired-async.el" nil t)
(dired-async-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 (beginend))
(beginend-global-mode +1))
(setup common-lisp-ide
(defvar acdw/cl-ide :sly)
(defvar acdw/lisp-bin (or (executable-find "sbcl")
(executable-find "clisp")))
(:needs acdw/lisp-bin)
(:option inferior-lisp-program acdw/lisp-bin)
(setup (:straight clhs))
(pcase acdw/cl-ide
(:slime
(setup (:straight slime)
(:also-load slime-autoloads)
(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))
(define-key slime-repl-mode-map (kbd "RET") #'slime-repl-return-at-end)
(define-key slime-repl-mode-map (kbd "<return>")
#'slime-repl-return-at-end)
(defun slime-repl-return-at-end ()
(interactive)
(if (<= (point-max) (point))
(slime-repl-return)
(slime-repl-newline-and-indent)))
(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))))))
(:sly
(setup (:straight sly)
(:option sly-kill-without-query-p t)
(:also-load sly-autoloads)))))
(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)
;; Competion-at-point (complete-region)
(:global "M-/" completion-at-point)
(:option completion-in-region-function #'consult-completion-in-region
completion-cycle-threshold 3
tab-always-indent 'complete))
(setup (:straight crux)
(:global "M-`" crux-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
"C-x 4 t" crux-transpose-windows)
(crux-reopen-as-root-mode +1))
(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)
(:leader "e" elpher-bookmarks)
(: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))))
(:when-loaded
(setup (:straight (gemini-write
:host nil
:repo "https://alexschroeder.ch/cgit/gemini-write"
:fork
(:repo "https://tildegit.org/acdw/gemini-write"
:branch "main")))
(require 'gemini-write))))
(setup (:straight expand-region)
(:global "C-=" er/expand-region))
(setup (:straight fennel-mode)
(:needs "fennel")
(autoload 'fennel-repl "fennel-mode" nil t)
(:file-match "\\.fnl\\'"))
(setup (:straight form-feed)
(global-form-feed-mode +1))
(setup (:straight geiser))
(setup (:straight (gemini-mode
:host nil
:repo "https://git.carcosa.net/jmcbray/gemini.el.git"))
(:file-match "\\.\\(gemini\\|gmi\\)\\'"))
(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))))
(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 ledger-mode)
(:needs "ledger"))
(setup (:straight lua-mode)
(:file-match "\\.lua\\'"))
(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 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 mwim)
(:global "C-a" mwim-beginning
"C-e" mwim-end))
(setup (:straight nov)
(:option nov-text-width fill-column)
(:file-match "\\.epub\\'"))
(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 (orderless
:host github
:repo "oantolin/orderless"))
(require 'orderless)
(:option (prepend completion-styles) 'orderless))
(setup (:straight (org :host nil
:repo "https://code.orgmode.org/bzg/org-mode.git"))
(require 'acdw-org) ; so I don't clutter up init.el
(: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" acdw-org/return-dwim
"<S-return>" acdw-org/org-table-copy-down)
(add-hook 'before-save-hook #'acdw-org/fix-blank-lines-in-buffer)
(advice-add 'org-delete-backward-char
:override #'acdw-org/delete-backward-char))
(setup (:straight paredit)
;; I don't use paredit-splice-sexp much, and it stomps on isearch.
(:unbind "M-s")
(defun setup-paredit-mode ()
"Correct weirdnesses and set up paredit mode."
(paredit-mode +1)
(define-key lisp-mode-shared-map (kbd "DEL") #'paredit-backward-delete))
(dolist (mode lispy-modes)
(add-hook (intern (concat (symbol-name mode) "-hook"))
#'setup-paredit-mode))
(require 'eldoc)
(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)))
(setup (:straight restart-emacs)
(defun emacs-upgrade (&optional update-packages)
"Pull config, upgrade packages, restart Emacs."
(interactive "P")
(when update-packages
(straight-pull-all))
(emacs-git-pull-config)
(restart-emacs)))
(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
acdw-modeline/winum
acdw-modeline/text-scale
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 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 'grow-only)
(if (boundp 'comp-deferred-compilation-deny-list)
(add-to-list 'comp-deferred-compilation-deny-list "vertico"))
(icomplete-mode -1)
(vertico-mode +1))
(setup (:straight web-mode)
(:option css-level-offset 2
js-indent-level 2
sgml-indent-offset 2)
(:file-match "\\.\\(p\\|dj\\)?html\\'"
"\\.html?\\'"
"\\.\\(tpl\\.\\)?php\\'"
"\\.[agj]sp\\'"
"\\.as[cp]x\\'"
"\\.erb\\'"
"\\.mustache\\'"))
(setup (:straight which-key)
(:option which-key-show-early-on-C-h t
which-key-idle-delay 1
which-key-idle-secondary-delay 0.5
which-key-delay-functions '(acdw/which-key-delay-all-but))
(defun acdw/which-key-delay-all-but (seq len)
"Delay all `which-key' popups, /except/ the ones here."
(cond
;; With C-z binds (`acdw/leader'), pop up right away
((string-prefix-p "C-z" seq :ignore-case) 0)
;; Also pop up right away if we're already entering keys
((> len 1) which-key-idle-secondary-delay)
;; Otherwise, wait
(t which-key-idle-delay)))
(which-key-setup-minibuffer)
(which-key-mode +1))
(setup (:straight winum)
(:option winum-auto-setup-mode-line nil
winum-ignored-buffers '(" *which-key*"))
(when (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)))
(winum-mode +1))
(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))
;;; System-dependent
;;;; Home
(when (eq acdw/system :home)
(setup (:straight pkgbuild-mode))
(setup (:straight (pdf-tools
:host github
:repo "vedang/pdf-tools"))
(pdf-loader-install))
(setup (:straight vterm)))