This commit is contained in:
Case Duckworth 2021-04-06 17:59:45 -05:00
parent a55c158dc6
commit c05d1ba2c8
4 changed files with 373 additions and 569 deletions

3
.gitignore vendored
View File

@ -6,4 +6,5 @@ var/
etc/
straight/
transient/
racket-mode/
racket-mode/
*~

View File

@ -24,37 +24,21 @@
load-path)
(require 'acdw)
;;; Refresh Emacs easily
(defun refresh-emacs ()
"Reload Emacs's configuration files."
(interactive)
(dolist (file (list (locate-user-emacs-file "early-init.el")
(locate-user-emacs-file "init.el" ".emacs")))
(when (file-exists-p file)
(load-file file))))
;;; Speed up init
;; see doom-emacs, et al.
(defvar orig-file-name-handler-alist file-name-handler-alist
"The original value of `file-name-handler-alist' will be restored
after init.")
(setq file-name-handler-alist nil)
(setq gc-cons-threshold (* 800 1024 1024)
gc-cons-percentage 0.6)
(add-hook 'after-init-hook
(defun hook--post-init-reset ()
"Reset `gc-cons-threshold', `gc-cons-percentage', and
`file-name-handler-alist' to their defaults after init."
(acdw/gc-enable)
(dolist (handler file-name-handler-alist)
(add-to-list 'orig-file-name-handler-alist handler))
(setq file-name-handler-alist orig-file-name-handler-alist)))
(setq orig-file-name-handler-alist file-name-handler-alist
file-name-handler-alist nil)
(acdw/gc-disable)
(hook-defun post-init-reset after-init-hook
(acdw/gc-enable)
(dolist (handler file-name-handler-alist)
(add-to-list 'orig-file-name-handler-alist handler))
(setq file-name-handler-alist orig-file-name-handler-alist))
;;; Frame settings
(setq default-frame-alist ; Remove most UI
`((tool-bar-lines . 0) ; No tool bar
(menu-bar-lines . 0) ; No menu bar
@ -73,8 +57,7 @@
frame-resize-pixelwise t ; Resize by pixels, not chars
)
(defun hook--disable-ui-modes ()
"Disable frame UI using modes, for toggling later."
(hook-defun disable-ui-modes after-init-hook
(dolist (mode ;; each mode is of the form (MODE . FRAME-ALIST-VAR)
'((tool-bar-mode . tool-bar-lines)
(menu-bar-mode . menu-bar-lines)
@ -86,8 +69,25 @@
(= 0 setting))
(funcall (car mode) -1)))))
(add-hook 'after-init-hook #'hook--disable-ui-modes)
(add-function :after after-focus-change-function
(defun hook--setup-fonts ()
(dolist (face '(default fixed-pitch))
;; `default' and `fixed-pitch' should be the same.
(set-face-attribute face nil
:font (pcase acdw/system
(:home "DejaVu Sans Mono-10")
(:work "Consolas-10")
(:other "monospace-10"))))
;; `variable-pitch' is, of course, different.
(set-face-attribute 'variable-pitch nil
:font (pcase acdw/system
(:home "DejaVu Sans")
(:work "Calibri-11")
(:other "sans-serif")))
(remove-function after-focus-change-function
'hook--setup-fonts)))
;;; Bootstrap package manager (`straight.el')
;; 1. Update `exec-path'.
@ -108,7 +108,7 @@
package-quickstart nil
straight-host-usernames '((github . "duckwork")
(gitlab . "acdw"))
straight-base-dir acdw/dir)
straight-base-dir (acdw/dir))
;; 3. Bootstrap `straight'.
(defvar bootstrap-version)
@ -126,9 +126,10 @@
(goto-char (point-max))
(eval-print-last-sexp)))
(load bootstrap-file nil 'nomessage))
;;; Message startup time for profiling
;; This just redefines the Emacs function
;; `display-startup-echo-area-message', so no hooks needed.
(defun display-startup-echo-area-message ()
"Show Emacs's startup time in the message buffer. For profiling."
(message "Emacs ready in %s with %d garbage collections."
@ -136,11 +137,3 @@
(float-time (time-subtract after-init-time
before-init-time)))
gcs-done))
;;; Install `no-littering', pointing both directories at `acdw/dir'. This will
;;; take care of the packages I don't care about configuring.
(straight-use-package 'no-littering)
(setq no-littering-etc-directory acdw/dir
no-littering-var-directory acdw/dir)
(require 'no-littering)

683
init.el
View File

@ -15,23 +15,19 @@
;; - Make good choices.
;;;- Code:
;; Necessary packages
;;; `setup' -- configuration macro
(straight-use-package '(setup :host nil
:repo "https://git.sr.ht/~zge/setup"))
(require 'setup)
;; `setup'
(progn
(straight-use-package '(setup :host nil
:repo "https://git.sr.ht/~zge/setup"))
(require 'setup))
;;;; shorthand for `customize-set-variable' (via setup)
(defmacro setc (&rest args)
"Customize user options using ARGS like `setq'."
(declare (debug setq))
`(setup (:option ,@args)))
;;;; Install packages with `straight-use-package'
(setup-define :straight
(lambda (recipe)
`(straight-use-package ',recipe))
:documentation "Install RECIPE with `straight-use-package'."
:documenation "Install RECIPE with `straight-use-package'."
:repeatable t
:shorthand (lambda (sexp)
(let ((recipe (cadr sexp)))
@ -39,185 +35,112 @@
(car recipe)
recipe))))
;;;; Set options using `setq-default', instead of `customize-set-variable'
;; From what I can tell, `customize-set-variable' loads "all the dependencies
;; for each SYMBOL it sets (see `custom-load-symbol'). Since I don't want to do
;; that all the time, here's `:set'. DON'T USE THIS HARDLY EVER. Honestly, I
;; might want to do a `:option-after' instead (with `:after-loaded' set to t)...
(setup-define :setq-default
(lambda (variable value)
`(setq-default ,variable ,value))
:documentation "Set options with `setq-default'. USE SPARINGLY!"
:debug '(sexp form)
:repeatable t)
;;;; Bind keys to `acdw/leader'
(setup-define :acdw/leader
(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' map."
:debug '(form sexp)
:repeatable t)
#',command))))
;;;; Bind keys, and autoload the functions they're bound to.
(setup-define :bind-autoload
(lambda (key command)
`(progn
(autoload #',command (symbol-name setup-name))
(define-key (symbol-value setup-map)
,(if (stringp key) (kbd key) key)
#',command)))
:documentation "Bind KEY to COMMAND, and autload COMMAND from FEATURE."
:debug '(form sexp)
:repeatable t)
;; `no-littering'
(setup (:straight no-littering)
(:option no-littering-etc-directory (acdw/dir)
no-littering-var-directory (acdw/dir))
(require 'no-littering))
;;; Good defaults
;; Good defaults
;;;; About me
(setc 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)
(defmacro setc (&rest args)
"Customize user options using ARGS like `setq'."
(declare (debug setq))
`(setup (:option ,@args)))
;;;; Lines
(setc fill-column 80
word-wrap t
truncate-lines nil)
(add-hook 'text-mode-hook #'turn-on-auto-fill)
(global-display-fill-column-indicator-mode +1)
(global-so-long-mode +1)
(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 80
word-wrap t
truncate-lines nil)
;; Only fill comments in prog-mode.
(add-hook 'prog-mode-hook
(defun hook--auto-fill-prog-mode ()
(setq-local comment-auto-fill-only-comments t)
(turn-on-auto-fill)))
(global-display-fill-column-indicator-mode +1)
(global-so-long-mode +1)
;; Don't truncate lines in the minibuffer.
(add-hook 'minibuffer-setup-hook
(defun hook--minibuffer-enable-truncate-lines ()
(setq-local truncate-lines t)))
;; Whitespace
(:option whitespace-style
'(empty indentation space-before-tab space-after-tab)
indent-tabs-mode nil
tab-width 4)
(add-hook 'before-save-hook #'whitespace-cleanup)
;;;; Whitespace
(setc whitespace-style
'(empty indentation space-before-tab space-after-tab)
indent-tabs-mode nil
tab-width 4
smie-indent-basic tab-width)
(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)
;;;; Pairs
(setc show-paren-delay 0
show-paren-style 'mixed
show-paren-when-point-inside-paren t
show-paren-when-point-in-periphery t)
(add-hook 'prog-mode-hook #'electric-pair-local-mode)
(delete-selection-mode +1)
;;;; Killing and yanking
(setc 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 local-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
org-export-coding-system 'utf-8-unix
org-html-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))
;;;; Encoding
(setc local-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
org-export-coding-system 'utf-8-unix
org-html-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)
(set-selection-coding-system 'utf-8-unix)
(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)
(set-selection-coding-system 'utf-8-unix)
;;;; Uniquify
(setup (:require uniquify)
(:option uniquify-buffer-name-style 'forward
uniquify-separator path-separator
uniquify-after-kill-buffer-p t
uniquify-ignore-buffers-re "^\\*"))
;; Cursor
(:option cursor-type 'bar
cursor-in-non-selected-windows 'hollow)
;;;; Files
(setc backup-directory-alist `((".*" . ,(acdw/in-dir "backup/" t)))
tramp-backup-directory-alist backup-directory-alist
auto-save-file-name-transforms `((".*" ,(acdw/in-dir "auto-save/" t) t))
auto-save-list-file-prefix (acdw/in-dir "auto-save-list/.saves-" t)
backup-by-copying t
delete-old-versions t
version-control t
vc-make-backup-files t)
;; Scrolling
(:option auto-window-vscroll nil
fast-but-imprecise-scrolling t
scroll-margin 0
scroll-conservatively 101
scroll-preserve-screen-position 1)
(add-hook 'after-save-hook #'executable-make-buffer-file-executable-if-script-p)
;; 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)
;;;;; Auto-save files
(auto-save-visited-mode +1)
;; And /actually/ save all buffers when unfocused
(add-function :after after-focus-change-function
(defun hook--auto-save-when-unfocused ()
"Save all buffers when out of focus."
(acdw/when-unfocused #'save-some-buffers t)))
(add-hook 'minibuffer-setup-hook #'acdw/gc-disable)
(add-hook 'minibuffer-exit-hook #'acdw/gc-enable)
;;;;; Autorevert files
(setup (:require autorevert)
(global-auto-revert-mode +1))
(hook-defun minibuffer-enable-truncate-lines minibuffer-setup-hook
(setq-local truncate-lines t))
;;;;; Save place in files
(setup (:require saveplace)
(:option save-place-file (acdw/in-dir "places.el")
save-place-forget-unreadable-files (eq acdw/system :home))
(save-place-mode +1))
(minibuffer-depth-indicate-mode +1)
(file-name-shadow-mode +1)
(fset 'yes-or-no-p #'y-or-n-p)
;;;;; Keep track of recent files
(setup (:require recentf)
(:option recentf-save-file (acdw/in-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))
;;;; Windows
(winner-mode +1)
;;;; Minibuffer
(setc 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)
(minibuffer-depth-indicate-mode +1)
(file-name-shadow-mode +1)
(fset 'yes-or-no-p #'y-or-n-p)
;;;;; Save minibuffer command history (and others)
(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/in-dir "savehist.el"))
(savehist-mode +1))
;;;;; Completion framework
(setup (:require icomplete)
;; Completion
(:option completion-ignore-case t
read-buffer-completion-ignore-case t
icomplete-delay-completions-threshold 0
@ -230,134 +153,162 @@
completion-category-defaults nil
completion-category-overrides
'((file (styles . (partial-completion)))))
(fido-mode -1)
(icomplete-mode +1))
;;;;; `imenu'
;; Etc.
(:option custom-file (acdw/dir "custom.el")
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")
disabled-command-function nil
load-prefer-newer t
comp-async-report-warnings-errors nil
frame-title-format '("%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.25
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)
(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))
;; 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 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))
;;;; Cursor
(setc cursor-type 'bar
cursor-in-non-selected-windows 'hollow)
;;;; Scrolling
(setc auto-window-vscroll nil
fast-but-imprecise-scrolling t
scroll-margin 0
scroll-conservatively 101
scroll-preserve-screen-position 1)
;;;; Fonts
;; Load them /after/ the first frame comes into focus
(add-function :after after-focus-change-function
(defun hook--setup-fonts ()
(dolist (face '(default fixed-pitch))
;; `default' and `fixed-pitch' should be the same.
(set-face-attribute face nil
:font (pcase acdw/system
(:home "DejaVu Sans Mono-10")
(:work "Consolas-10")
(:other "monospace-10"))))
;; `variable-pitch' is, of course, different.
(set-face-attribute 'variable-pitch nil
:font (pcase acdw/system
(:home "DejaVu Sans")
(:work "Calibri-11")
(:other "sans-serif")))
(remove-function after-focus-change-function
'hook--setup-fonts)))
;;;; Debugger
(setup debugger
(:hook visual-line-mode)
(:acdw/leader "d" toggle-debug-on-error))
(:leader "d" toggle-debug-on-error))
;;;; Garbage collection
(add-hook 'minibuffer-setup-hook #'acdw/gc-disable)
(add-hook 'minibuffer-exit-hook #'acdw/gc-enable)
(add-function :after after-focus-change-function
(defun hook--gc-when-unfocused ()
(acdw/when-unfocused #'garbage-collect)))
(setup eldoc
(:option eldoc-idle-delay 0.1
eldoc-echo-area-use-multiline-p nil))
;;;; Spelling
(setup flyspell
(setenv "LANG" "en_US")
(:option ispell-program-name "hunspell"
ispell-dictionary "en_US"
ispell-personal-dictionary "~/.hunspell_personal")
(:needs ispell-program-name) ; don't proceed if not installed
(ispell-set-spellchecker-params)
(unless (file-exists-p ispell-personal-dictionary)
(write-region "" nil ispell-personal-dictionary nil 0))
(:needs ispell-program-name)
;; add hooks
(add-hook 'text-mode-hook #'flyspell-mode)
(add-hook 'prog-mode-hook #'flyspell-prog-mode))
;;;; MS Windows
(when (eq acdw/system :work)
(setc 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))
;;;; Set up non-special modes
;; Great idea from brause.cc
(defun-with-hooks '(text-mode-hook prog-mode-hook diff-mode-hook)
(defun hook--setup-regular-modes ()
(setq indicate-empty-lines t
indicate-buffer-boundaries '((top . right) (bottom . right)))
(goto-address-mode +1)
(show-paren-mode +1)))
;;;; Etc. good defaults
(setc custom-file (acdw/in-dir "custom.el")
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")
default-directory (expand-file-name "~/")
disabled-command-function nil
load-prefer-newer t
comp-async-report-warnings-errors nil
frame-title-format '("%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.25
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)))
;;;; Etc. modes
(tooltip-mode -1)
;;;; Etc. bindings
(global-set-key [remap just-one-space] #'cycle-spacing)
(global-set-key (kbd "M-/") #'hippie-expand)
(global-set-key (kbd "M-=") #'count-words)
(global-set-key (kbd "C-x C-b") #'ibuffer)
(add-hook 'prog-mode-hook #'flyepell-prog-mode))
;;; Applications
;; Some of these are built-in, some are packages; all are "extra" functionality
;; in Emacs (i.e., they're not /just/ editing text)
;;;; Org mode
;; Applications
(setup (:straight (org :host nil
:repo "https://code.orgmode.org/bzg/org-mode.git"))
(require 'acdw-org)
@ -383,38 +334,35 @@
(:bind "RET" unpackaged/org-return-dwim)
(add-hook 'before-save-hook #'acdw/hook--org-mode-fix-blank-lines))
;;;; Eshell
(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)))
(:option eshell-directory-name (acdw/in-dir "eshell/" t)
eshell-aliases-file (acdw/in-dir "eshell/aliases" t))
(add-hook 'eshell-mode-hook
(defun hook--eshell-setup ()
"Stuff to do after eshell is done setting up."
(define-key eshell-mode-map (kbd "C-d")
#'eshell-quit-or-delete-char)
(setq mode-line-format '(:eval simple-modeline--mode-line)))))
(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)))))
;;;; Ediff
(setup ediff
(:option ediff-window-setup-function 'ediff-setup-windows-plain
ediff-split-window-function 'split-window-horizontally))
;;;; Web browsing
(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)
(:option 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")))
@ -428,11 +376,10 @@
(setup eww
(:hook acdw/reading-mode))
;;;; Gemini/gopher browsing
(setup (:straight (elpher :host nil
:repo "git://thelambdalab.xyz/elpher.git"))
(:option elpher-ipv4-always t
elpher-certificate-directory (acdw/in-dir "elpher/")
elpher-certificate-directory (acdw/dir "elpher/")
elpher-gemini-max-fill-width fill-column)
(:bind "n" elpher-next-link
"p" elpher-prev-link
@ -455,7 +402,6 @@
(:option (append auto-mode-alist)
'("\\.\\(gemini\\|gmi\\)\\'" . gemini-mode)))
;;;; File browsing
(setup dired
(:setq-default dired-recursive-copies 'always
dired-recursive-deletes 'always
@ -486,7 +432,6 @@
(setup (:straight trashed)
(:option trashed-action-confirmer 'y-or-n-p))))
;;;; Magit
(setup (:straight magit)
(:acdw/leader "g" magit-status)
(:option magit-display-buffer-function
@ -495,39 +440,30 @@
(display-buffer buffer '(display-buffer-same-window)))
magit-popup-display-buffer-action '((display-buffer-same-window))))
;;;; Read e-books (nov.el)
(setup (:straight nov)
(:option nov-text-width fill-column
(append auto-mode-alist) '("\\.epub\\'" . nov-mode)))
;;;; PDF Tools
(when (eq acdw/system :home)
(setup (:straight pdf-tools)
(pdf-loader-install)))
;;;; VTerm
(when (eq acdw/system :home)
(setup (:straight vterm)))
;;; Packages
;; Extra packages
;;;; Interactivity
;;;;; Begin-end
(setup (:straight beginend)
(beginend-global-mode +1))
;;;;; MWIM
(setup (:straight mwim)
(:global "C-a" mwim-beginning
"C-e" mwim-end))
;;;;; Expand-region
(setup (:straight expand-region)
(:global "C-=" er/expand-region))
;;;;; CRUX
(setup (:straight crux)
(:global "M-o" crux-other-window-or-switch-buffer
"C-k" crux-kill-and-join-forward
@ -537,7 +473,6 @@
"C-c i" crux-find-user-init-file)
(crux-reopen-as-root-mode +1))
;;;;; AVY ... & friends
(setup (:straight avy)
(:global "C-:" avy-goto-char
"C-'" avy-goto-char-timer
@ -547,7 +482,6 @@
(eval-after-load "isearch"
'(define-key isearch-mode-map (kbd "C-'") #'avy-isearch)))
;;;;; zzz-to-char
(setup (:straight zzz-to-char)
(defun acdw/zzz-up-to-char (prefix)
"Call `zzz-up-to-char', unless issued a PREFIX, in which case
@ -556,9 +490,9 @@ call `zzz-to-char'."
(if prefix
(call-interactively #'zzz-to-char)
(call-interactively #'zzz-up-to-char)))
(:global "M-z" acdw/zzz-up-to-char))
;;;;; anzu
(setup (:straight anzu)
(:option anzu-replace-to-string-separator ""
anzu-cons-mode-line-p nil)
@ -573,20 +507,10 @@ call `zzz-to-char'."
(global-anzu-mode +1))
;;;;; smart hungry delete
(setup (:straight smart-hungry-delete)
(:global "<backspace>" smart-hungry-delete-backward-char
"C-d" smart-hungry-delete-forward-char)
(smart-hungry-delete-add-default-hooks))
;;;; Functionality
;;;;; Async
(setup (:straight async)
(autoload 'dired-async-mode "dired-async.el" nil t)
(dired-async-mode +1))
;;;;; Undo-fu
(setup (:straight undo-fu)
(:global "C-/" undo-fu-only-undo
"C-?" undo-fu-only-redo))
@ -594,25 +518,24 @@ call `zzz-to-char'."
(setup (:straight undo-fu-session)
(:option undo-fu-session-incompatible-files '("/COMMIT_EDITMSG\\'"
"/git-rebase-todo\\'")
undo-fu-session-directory (acdw/in-dir "undo/" t)
undo-fu-session-directory (acdw/dir "undo/" t)
undo-fu-session-compression (eq acdw/system :home))
(global-undo-fu-session-mode +1))
;;;; Minibuffer
(setup (:straight (vertico
:host github
:repo "minad/vertico"))
(advice-add #'completing-read-multiple :filter-args
(defun crm-indicator (args)
(cons (concat "[CRM] " (car args)) (cdr args))))
(icomplete-mode -1)
(vertico-mode +1))
;;;;; Orderless
(setup (:straight orderless)
(:option (prepend completion-styles) 'orderless))
;;;;; Consult
(setup (:straight consult)
;; "Sensible" functions
@ -625,6 +548,7 @@ if ripgrep is installed, otherwise `consult-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")
@ -686,15 +610,11 @@ if ripgrep is installed, otherwise `consult-grep'."
;; Projects
(:option consult-project-root-function #'vc-root-dir))
;;;;; Marginalia
(setup (:straight marginalia)
(:option marginalia-annotators '(marginalia-annotators-heavy
marginalia-annotators-light))
(marginalia-mode +1))
;;;; UI
;;;;; Modus themes
(setup (:straight (modus-themes
:host gitlab
:repo "protesilaos/modus-themes"))
@ -708,7 +628,6 @@ if ripgrep is installed, otherwise `consult-grep'."
(acdw/sunrise-sunset #'modus-themes-load-operandi
#'modus-themes-load-vivendi))
;;;;; Mode line
(setup (:straight simple-modeline)
(setup (:straight minions))
(:option simple-modeline-segments
@ -725,22 +644,13 @@ if ripgrep is installed, otherwise `consult-grep'."
(require 'acdw-modeline)
(simple-modeline-mode +1))
;;;;; Olivetti
;; also useful for `acdw/reading-mode'
(setup (:straight olivetti)
(:option olivetti-body-width (+ fill-column 4)
olivetti-minimum-body-width fill-column))
;;;;; Outshine
(setup (:straight outshine)
(:option outline-minor-mode-prefix "")
(:hook-into emacs-lisp-mode))
;;;;; Form-feed
(setup (:straight form-feed)
(global-form-feed-mode +1))
;;;;; Which-key
(setup (:straight which-key)
(:option which-key-show-early-on-C-h t
which-key-idle-delay 10000
@ -748,7 +658,6 @@ if ripgrep is installed, otherwise `consult-grep'."
(which-key-setup-side-window-bottom)
(which-key-mode +1))
;;;;; Helpful
(setup (:straight helpful)
(:global "<help> f" helpful-callable
"<help> v" helpful-variable
@ -756,73 +665,48 @@ if ripgrep is installed, otherwise `consult-grep'."
"<help> o" helpful-symbol
"C-c C-d" helpful-at-point))
;;;; Utilities
;;;;; 0x0 -- upload files to a nullpointer
(setup (:straight (0x0 :host nil
:repo "https://git.sr.ht/~zge/nullpointer-emacs"))
(:option 0x0-default-host 'ttm))
;;;;; Flyspell-correct
(with-eval-after-load 'flyspell
(setup (:straight flyspell-correct)
(define-key flyspell-mode-map (kbd "C-;") #'flyspell-correct-wrapper)))
;;;; System tie-ins
;; Insctead of using `setup''s `:needs', I'm going to wrap these in
;; `executable-find' forms. I don't want to waste time with pulling packages
;; that won't work on a machine.
;;;;; PKGBUILDs
(when (eq acdw/system :home)
(setup (:straight pkgbuild-mode)))
;;; Programming languages
;; This section includes packages and other settings, because most languages'
;; packages aren't packaged with Emacs.
;;;; Formatting
(setup (:straight (apheleia :host github
:repo "raxod502/apheleia"))
(apheleia-global-mode +1)
;; Use a dumb formatter on modes that `apheleia' doesn't work for.
(add-hook 'before-save-hook
(defun dumb-auto-format ()
"Run `indent-region' in buffers that don't have an `apheleia'
formatter set."
(unless (and (fboundp 'apheleia--get-formatter-command)
(apheleia--get-formatter-command))
(indent-region (point-min) (point-max))))))
(hook-defun dumb-auto-format before-save-hook
(unless (and (fboundp 'apheleia--get-formatter-command)
(apheleia--get-formatter-command))
(indent-region (point-min) (point-max)))))
;;;; Eldoc
(setup eldoc
(:option eldoc-idle-delay 0.1
eldoc-echo-area-use-multiline-p nil))
;;;; Lisps
(setup (:straight paren-face)
(global-paren-face-mode +1))
;;;;; Paredit mode
(setup (:straight paredit)
(autoload 'enable-paredit-mode "paredit" nil t)
(dolist (hook '(emacs-lisp-mode-hook
eval-expression-minibuffer-setup-hook
ielm-mode-hook
lisp-mode-hook
lisp-interaction-mode-hook
scheme-mode-hook))
(add-hook hook #'enable-paredit-mode))
(add-hook 'paredit-mode-hook
(defun hook--paredit-disable-electric-pair ()
(electric-pair-local-mode -1)))
(require 'eldoc)
(eldoc-add-command 'paredit-backward-delete 'paredit-close-round)
(:bind "<backspace>" paredit-backward-delete))
;;;;; Emacs lisp
(:hook-into emacs-lisp-mode
eval-expression-minibuffer
ielm-mode
lisp-mode
lisp-interaction-mode
scheme-mode)
(defun disable-electric-pair-local-mode ()
(electric-pair-local-mode -1))
(:hook disable-electric-pair-local-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
@ -839,34 +723,25 @@ if ripgrep is installed, otherwise `consult-grep'."
"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-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 macrostep)
(define-key emacs-lisp-mode-map (kbd "C-c e") #'macrostep-expand))
(setup (:straight eros)
(:hook-into emacs-lisp-mode))
(setup (:straight eros)
(:hook-into emacs-lisp-mode)))
;;;;; Fennel
(when (executable-find "fennel")
(setup (:straight fennel-mode)
(autoload 'fennel-mode "fennel-mode" nil t)
(:option (append auto-mode-alist) '("\\.fnl\\'" . fennel-mode))
(:bind "C-c C-c" )))
;;;;; Scheme
(when (or (executable-find "guile")
(executable-find "csi")
(executable-find "racket"))
(setup (:straight geiser)
(:with-mode geiser-repl-mode
(:hook enable-paredit-mode))))
(setup (:straight geiser))
;;;; Lua
(setup (:straight lua-mode)
(:option (append auto-mode-alist) '("\\.lua\\'" . lua-mode)))
;;;; Shell scripts
(setup sh-mode
(:option sh-basic-offset tab-width
sh-indent-after-case 0
@ -884,7 +759,6 @@ if ripgrep is installed, otherwise `consult-grep'."
(:hook flymake-mode
flymake-shellcheck-load)))
;;;; Web languages
(setup (:straight web-mode)
(:option css-level-offset 2
js-indent-level 2
@ -899,11 +773,8 @@ if ripgrep is installed, otherwise `consult-grep'."
(add-to-list 'auto-mode-alist
`(,(concat "\\." extension "\\'") . web-mode))))
;;;; FORTH
(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)))
;;;- init.el ends here

View File

@ -18,139 +18,79 @@
;; functions for me, acdw.
;;; Code:
;; Utility constants
;;; Utilities
;;;; Determine the system I'm on
(defconst acdw/system (pcase system-type
('gnu/linux :home)
((or 'msdos 'windows-nt) :work)
(_ :other))
"Which system is currently being used.")
('gnu/linux :home)
((or 'msdos 'windows-nt) :work)
(_ :other))
"Which computer system is currently being used.")
;;;; Run commands only when unfocused
(defun acdw/when-unfocused (func &rest args)
"Call FUNC, with ARGS, iff all Emacs frames are out of focus.
;; Utility functions
Ready for use with `after-focus-change-function'."
(when (seq-every-p #'null (mapcar #'frame-focus-state (frame-list)))
(apply func args)))
(defmacro when-unfocused (name &rest forms)
"Define a function NAME, executing FORMS, that fires when Emacs
is unfocused."
(declare (indent 1))
(let ((func-name (intern (concat "when-unfocused-" (symbol-name name)))))
`(progn
(defun ,func-name () "Defined by `when-unfocused'."
(when (seq-every-p #'null
(mapcar #'frame-focus-state (frame-list)))
,@forms))
(add-function :after after-focus-change-function #',func-name))))
;;;; Run commands at sunrise and sunset
(defun acdw/sunrise-sunset (sunrise-command sunset-command)
"Run commands at sunrise and sunset."
(let* ((times-regex (rx (* nonl)
(: (any ?s ?S) "unrise") " "
(group (repeat 1 2 digit) ":"
(repeat 1 2 digit)
(: (any ?a ?A ?p ?P) (any ?m ?M)))
(* nonl)
(: (any ?s ?S) "unset") " "
(group (repeat 1 2 digit) ":"
(repeat 1 2 digit)
(: (any ?a ?A ?p ?P) (any ?m ?M)))
(* nonl)))
(ss (sunrise-sunset))
(_m (string-match times-regex ss))
(sunrise-time (match-string 1 ss))
(sunset-time (match-string 2 ss)))
(run-at-time sunrise-time (* 60 60 24) sunrise-command)
(run-at-time sunset-time (* 60 60 24) sunset-command)
(run-at-time "12:00am" (* 60 60 24) sunset-command)))
(defmacro hook-defun (name hooks &rest forms)
"Define a function NAME that executes FORMS, and add it to
each hook in HOOKS."
(declare (indent 2))
(let ((func-name (intern (concat "hook-defun-" (symbol-name name))))
(hook-list (if (consp hooks) hooks (list hooks)))
(hook-defun-add-hook-list))
`(progn
(defun ,func-name () "Defined by `hook-defun'." ,@forms)
,@(dolist (hook hook-list hook-defun-add-hook-list)
(push `(add-hook ',hook #',func-name) hook-defun-add-hook-list)))))
;;;; Define a function and add it to hooks
(defun defun-with-hooks (hooks function-def)
"Add FUNCTION-DEF to HOOKS.
(defun refresh-emacs ()
"Reload Emacs's configuration files."
(interactive)
(dolist (file (list (locate-user-emacs-file "early-init.el")
(locate-user-emacs-file "init.el" ".emacs")))
(when (file-exists-p file)
(load-file file))))
FUNCTION-DEF should be a `defun' form. This function is just to
put functions that only exist for hooks closer to the hooks
they bind to."
(let ((func function-def))
(dolist (hook hooks)
(add-hook hook func))))
(defun acdw/dir (&optional file make-directory)
"Place Emacs files in one place.
;;; Garbage collection hacks
(defconst acdw/gc-cons-threshold-basis (* 800 1024)
"Basis value for `gc-cons-threshold' to return to after jumping.
800 KB is Emacs's default.")
(defconst acdw/gc-cons-percentage-basis 0.1
"Basis value for `gc-cons-percentage' to return to after jumping.
0.1 is Emacs's default.")
(defun acdw/gc-disable ()
"Disable garbage collection by setting relevant variables to their maxima."
(setq gc-cons-threshold most-positive-fixnum
gc-cons-percentage 0.8))
If called without parameters, `acdw/dir' expands to
~/.emacs.d/var or similar. If called with FILE, `acdw/dir'
expands FILE to ~/.emacs.d/var, optionally making its directory
if MAKE-DIRECTORY is non-nil."
(let ((dir (expand-file-name (convert-standard-filename "var/")
user-emacs-directory)))
(if file
(let ((file-name (expand-file-name (convert-standard-filename file)
dir)))
(when make-directory
(make-directory (file-name-directory file-name) 'parents))
file-name)
dir)))
(defun acdw/gc-enable ()
"Re-enable garbage collection by setting relevant variables back to bases."
(setq gc-cons-threshold acdw/gc-cons-threshold-basis
gc-cons-percentage acdw/gc-cons-percentage-basis))
"Enable the Garbage collector."
(setq gc-cons-threshold (* 800 1024 1024)
gc-cons-percentage 0.1))
;;; Directories (think `no-littering')
(defun acdw/gc-disable ()
"Functionally disable the Garbage collector."
(setq gc-cons-threshold most-positive-fixnum
gc-cons-percentage 0.8))
(defvar acdw/dir (expand-file-name
(convert-standard-filename "var/")
user-emacs-directory)
"A directory to hold extra configuration and emacs data.")
(defun acdw/in-dir (file &optional make-directory)
"Expand FILE relative to `acdw/dir', optionally creating its
directory."
(let ((f (expand-file-name (convert-standard-filename file)
acdw/dir)))
(when make-directory
(make-directory (file-name-directory f) 'parents))
f))
;;; Reading mode
(define-minor-mode acdw/reading-mode
"A mode for reading."
:init-value t
:lighter " Read"
(if acdw/reading-mode
(progn ;; turn on
;; settings
(setq-local mode-line-format
'(:eval
(let* ((fmt " Reading %b (%m) ")
(len (length (format-mode-line fmt))))
(concat
(propertize " "
'display `((space :align-to (- right
,len)))
'face '(:inherit italic))
fmt))))
;; modes to disable
(dolist (mode '(display-fill-column-indicator-mode))
(when (fboundp mode)
(funcall mode -1)))
;; modes to enable
(dolist (mode '(iscroll-mode
olivetti-mode))
(when (fboundp mode)
(funcall mode +1))))
;; turn off
;; settings
(kill-local-variable 'mode-line-format)
;; modes to re-enable
(dolist (mode '(display-fill-column-indicator-mode
simple-modeline-mode))
(when (fboundp mode)
(funcall mode +1)))
;; modes to re-disable
(dolist (mode '(olivetti-mode
iscroll-mode))
(when (fboundp mode)
(funcall mode -1)))
(force-mode-line-update)))
;;; Keymap & Mode
;; Set up a leader key for `acdw/mode'
;; Make `C-z' more useful
(defvar acdw/leader
(let ((map (make-sparse-keymap))
(c-z (global-key-binding "\C-z")))
@ -159,5 +99,4 @@ directory."
map))
(provide 'acdw)
;;; acdw.el ends here