From 1dd6b9c0eed5a596711340cbf48456ac003f8e7c Mon Sep 17 00:00:00 2001 From: Case Duckworth Date: Mon, 29 Mar 2021 17:52:23 -0500 Subject: [PATCH] Switch to using `setup.el' for customizations setup (https://git.sr.ht/~zge/setup) does everything I tried to do with `acdw/pkg', et al., but better. --- early-init.el | 111 +++--- init.el | 913 +++++++++++++++++++++++++------------------------- lisp/acdw.el | 384 +++++++++++---------- 3 files changed, 715 insertions(+), 693 deletions(-) diff --git a/early-init.el b/early-init.el index 4037ef8..adc876a 100644 --- a/early-init.el +++ b/early-init.el @@ -27,64 +27,53 @@ ;;; Speed up init ;; see doom-emacs, et al. -(defconst gc-cons-threshold-basis (* 800 1000) - "The basis value for `gc-cons-threshold' to return to after a jump. -800 KB is Emacs's default `gc-cons-threshold'.") - -(defconst gc-cons-percentage-basis 0.1 - "The basis value for `gc-cons-percentage' to return to after init. -0.1 is Emacs's default `gc-cons-percentage'.") - (defvar orig-file-name-handler-alist file-name-handler-alist "The original value of `file-name-handler-alist' will be restored after init.") -(setq gc-cons-threshold most-positive-fixnum - gc-cons-percentage 0.6 - file-name-handler-alist nil) +(setq file-name-handler-alist nil) +(acdw/gc-disable) -(defun hook--post-init-reset () - "Reset `gc-cons-threshold', `gc-cons-percentage', and +(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." - (setq gc-cons-threshold gc-cons-threshold-basis - gc-cons-percentage gc-cons-percentage-basis) - (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)) - -(add-hook 'after-init-hook #'hook--post-init-reset) + (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 - (vertical-scroll-bars) ; No scroll bars - (horizontal-scroll-bars) ; ... at all - (width . 84) ; A /little/ wider than - ; `fill-column' (set later) - (height . 30) - (left-fringe . 8) ; Width of fringes - (right-fringe . 8) ; (8 is default) - (font . ,(pcase acdw/system - (:home "DejaVu Sans Mono 10") - (:work "Consolas 10")))) - frame-inhibit-implied-resize t ; Don't resize randomly - frame-resize-pixelwise t ; Resize by pixels, not chars - ) + (menu-bar-lines . 0) ; No menu bar + (vertical-scroll-bars) ; No scroll bars + (horizontal-scroll-bars) ; ... at all + (width . 84) ; A /little/ wider than + ; `fill-column' (set later) + (height . 30) + (left-fringe . 8) ; Width of fringes + (right-fringe . 8) ; (8 is default) + (font . ,(pcase acdw/system + (:home "DejaVu Sans Mono 10") + (:work "Consolas 10")))) + frame-inhibit-implied-resize t ; Don't resize randomly + frame-resize-pixelwise t ; Resize by pixels, not chars + ) (defun hook--disable-ui-modes () "Disable frame UI using modes, for toggling later." (dolist (mode ;; each mode is of the form (MODE . FRAME-ALIST-VAR) - '((tool-bar-mode . tool-bar-lines) - (menu-bar-mode . menu-bar-lines) - (scroll-bar-mode . vertical-scroll-bars) - (horizontal-scroll-bar-mode . horizontal-scroll-bars) - )) + '((tool-bar-mode . tool-bar-lines) + (menu-bar-mode . menu-bar-lines) + (scroll-bar-mode . vertical-scroll-bars) + (horizontal-scroll-bar-mode . horizontal-scroll-bars) + )) (let ((setting (alist-get (cdr mode) default-frame-alist))) (when (or (not setting) - (= 0 setting)) - (funcall (car mode) -1))))) + (= 0 setting)) + (funcall (car mode) -1))))) (add-hook 'after-init-hook #'hook--disable-ui-modes) @@ -92,11 +81,11 @@ ;; 1. Update `exec-path'. (dolist (path (list (expand-file-name "bin" user-emacs-directory) - (expand-file-name "~/bin") - (expand-file-name "~/.local/bin") - (expand-file-name "~/usr/bin") - (expand-file-name "~/cmd") - (expand-file-name "~/mingw64/bin"))) + (expand-file-name "~/bin") + (expand-file-name "~/.local/bin") + (expand-file-name "~/usr/bin") + (expand-file-name "~/cmd") + (expand-file-name "~/mingw64/bin"))) (when (file-exists-p path) (add-to-list 'exec-path path :append))) @@ -104,27 +93,25 @@ (setenv "PATH" (mapconcat #'identity exec-path path-separator)) ;; 2. Set `package' and `straight' variables. -(setq package-enable-at-startup nil ; not sure if strictly - ; necessary - package-quickstart nil ; ditto +(setq package-enable-at-startup nil + package-quickstart nil straight-host-usernames '((github . "duckwork") - (gitlab . "acdw")) - straight-base-dir acdw/dir ; don't clutter ~/.emacs.d - ) + (gitlab . "acdw")) + straight-base-dir acdw/dir) ;; 3. Bootstrap `straight'. (defvar bootstrap-version) (let ((bootstrap-file (expand-file-name - "straight/repos/straight.el/bootstrap.el" - straight-base-dir)) + "straight/repos/straight.el/bootstrap.el" + straight-base-dir)) (bootstrap-version 5)) (unless (file-exists-p bootstrap-file) (with-current-buffer - (url-retrieve-synchronously - (concat "https://raw.githubusercontent.com/" - "raxod502/straight.el/develop/install.el") - 'silent 'inhibit-cookies) + (url-retrieve-synchronously + (concat "https://raw.githubusercontent.com/" + "raxod502/straight.el/develop/install.el") + 'silent 'inhibit-cookies) (goto-char (point-max)) (eval-print-last-sexp))) (load bootstrap-file nil 'nomessage)) @@ -134,10 +121,10 @@ (defun hook--message-startup-time () "Show Emacs's startup time in the message buffer. For profiling." (message "Emacs ready in %s with %d garbage collections." - (format "%.2f seconds" - (float-time (time-subtract after-init-time - before-init-time))) - gcs-done)) + (format "%.2f seconds" + (float-time (time-subtract after-init-time + before-init-time))) + gcs-done)) (add-hook 'emacs-startup-hook #'hook--message-startup-time) diff --git a/init.el b/init.el index 8f2bc12..cec8777 100644 --- a/init.el +++ b/init.el @@ -3,7 +3,7 @@ ;; Created: Sometime during Covid-19, 2020 ;; Keywords: configuration ;; URL: https://tildegit.org/acdw/emacs -;; Bankruptcy: 5d +;; Bankruptcy: 6 ;; This file is NOT part of GNU Emacs. @@ -16,54 +16,113 @@ ;;; Code: +;;; `setup' -- configuration macro +(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'." + :repeatable t + :shorthand (lambda (sexp) + (let ((recipe (cadr sexp))) + (if (consp recipe) + (car recipe) + recipe)))) + +;; Bind keys to `acdw/map' +(setup-define :acdw/map + (lambda (key command) + `(define-key acdw/map + ,(if (stringp key) (kbd key) key) + #',command)) + :documentation "Bind KEY to COMMAND in `acdw/map'." + :debug '(form sexp) + :repeatable t) + +;; Bind keys to `acdw/leader' +(setup-define :acdw/leader + (lambda (key command) + `(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) + +;; 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) + ;;; About me -(acdw/set - '((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) - (calendar-date-style iso))) +(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) ;;; Good defaults ;; Lines -(acdw/set '((fill-column 80))) -(global-display-fill-column-indicator-mode +1) +(setc fill-column 80 + word-wrap t + truncate-lines nil) (add-hook 'text-mode-hook #'turn-on-auto-fill) (add-hook 'prog-mode-hook #'turn-on-auto-fill) +(global-display-fill-column-indicator-mode +1) (global-so-long-mode +1) -;; I don't want `visual-line-mode', because I really only want to wrap and -;; truncate lines. Believe me, I know what I'm doing. -(acdw/set '((word-wrap t) - (truncate-lines nil))) - ;; Whitespace -(acdw/set '((whitespace-style - (empty indentation space-before-tab space-after-tab)) - (indent-tabs-mode nil "We've lost this battle...") - (tab-width 4))) +(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) ;; Pairs -(add-hook 'prog-mode-hook #'electric-pair-local-mode) -(acdw/set '((show-paren-delay 0) - (show-paren-style mixed) - (show-paren-when-point-inside-paren t) - (show-paren-when-point-in-periphery t))) +(setc show-paren-delay 0 + show-paren-style 'mixed + show-paren-when-point-inside-paren t + show-paren-when-point-in-periphery t) (show-paren-mode +1) +(add-hook 'prog-mode-hook #'electric-pair-local-mode) -;; Killing & Yanking +;; 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) -(acdw/set '((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))) ;; 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) @@ -71,453 +130,387 @@ (set-terminal-coding-system 'utf-8-unix) (set-keyboard-coding-system 'utf-8-unix) (set-selection-coding-system 'utf-8-unix) -(acdw/set '((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) - (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)))) -;; Unique buffer names -(when (require 'uniquify) - (acdw/set '((uniquify-buffer-name-style forward) - (uniquify-separator "/") - (uniquify-after-kill-buffer-p t) - (uniquify-ignore-buffers-re "^\\*")))) +;; Uniquify +(setup (:require uniquify) + (:option uniquify-buffer-name-style 'forward + uniquify-separator path-separator + uniquify-after-kill-buffer-p t + uniquify-ignore-buffers-re "^\\*")) -;; Backups -(acdw/set `((backup-by-copying t) - (delete-old-versions -1) - (version-control t) - (vc-make-backup-files t) - (backup-directory-alist ((".*" . ,(acdw/in-dir "backup/" t)))))) -;; Autosaves -(acdw/set `((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)))) +;; 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) (auto-save-visited-mode +1) -(defun hook--auto-save-when-unfocused () - "Save all buffers when out of focus." - (acdw/when-unfocused #'save-some-buffers t)) (add-function :after after-focus-change-function - #'hook--auto-save-when-unfocused) + (defun hook--auto-save-when-unfocused () + "Save all buffers when out of focus." + (acdw/when-unfocused #'save-some-buffers t))) -;; Auto-revert -(when (require 'autorevert) - (global-auto-revert-mode +1)) -;; Save place -(when (require 'saveplace) - (acdw/set - `((save-place-file ,(acdw/in-dir "places.el")) - (save-place-forget-unreadable-files ,(eq acdw/system :home)))) +(setup (:require autorevert) + (global-auto-revert-mode +1)) + +(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)) -;; Recent files -(when (require 'recentf) - (acdw/set - `((recentf-save-file ,(acdw/in-dir "recentf.el")) - (recentf-max-menu-items 100) - (recentf-max-saved-items nil) - (recentf-auto-cleanup 60 "Cleanup the recentf list when idle for 60s."))) - (add-to-list 'recentf-exclude acdw/dir) + +(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)) -;; Move the custom file -(acdw/set `((custom-file ,(acdw/in-dir "custom.el")))) +;; 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) + +(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)) + +(setup (:require icomplete) + (: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)) + (fido-mode -1) + (icomplete-mode +1)) + +(setup imenu + (:option imenu-auto-rescan t)) ;; Cursor -(acdw/set '((cursor-type bar) - (cursor-in-non-selected-windows hollow))) - -;; (defun hook--overwrite-mode-change-cursor () -;; (setq cursor-type (if overwrite-mode 'hbar 'bar))) -;; (add-hook 'overwrite-mode-hook #'hook--overwrite-mode-change-cursor) +(setc cursor-type 'bar + cursor-in-non-selected-windows 'hollow) ;; Scrolling -(acdw/set '((auto-window-vscroll nil) - (fast-but-imprecise-scrolling t) - (scroll-margin 0) - (scroll-conservatively 101) - (scroll-preserve-screen-position 1))) +(setc auto-window-vscroll nil + fast-but-imprecise-scrolling t + scroll-margin 0 + scroll-conservatively 101 + scroll-preserve-screen-position 1) -;; Bindings -(acdw/binds (("C-h" ehelp-command :after ("ehelp" nil nil 'keymap)) - ([remap just-one-space] cycle-spacing) - ("M-/" hippie-expand) - ("M-=" count-words) - ("C-x C-b" ibuffer))) +;; MS Windows +(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) -;;; Startup -(acdw/set `((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")))) +;; Dired +(setup dired + (:option 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) + (:acdw/map "C-x C-j" dired-jump)) -;;; Windows settings -(when (eq acdw/system :work) - (acdw/set `((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)))) +;; Eshell +(setup eshell + (:option eshell-directory-name (acdw/in-dir "eshell/" t) + eshell-aliases-file (acdw/in-dir "eshell/aliases" t))) -(acdw/set '((default-directory (expand-file-name "~/")))) +;; 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))) + +;; 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") + +;; Etc. bindings +(autoload 'ehelp-command "ehelp" nil nil 'keymap) +(define-key acdw/map (kbd "C-h") 'ehelp-command) +(define-key acdw/map [remap just-one-space] #'cycle-spacing) +(define-key acdw/map (kbd "M-/") #'hippie-expand) +(define-key acdw/map (kbd "M-=") #'count-words) +(define-key acdw/map (kbd "C-x C-b") #'ibuffer) + +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;; Here ends the package-less configuration. Everything following requires a +;;; package to be downloaded. ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; + +;;; Interactivity + + +;;;; Begin-end +(setup (:straight beginend) + (beginend-global-mode +1)) + +;;;; Expand-region +(setup (:straight expand-region) + (:acdw/map "C-=" er/expand-region)) + +;;;; CRUX +(setup (:straight crux) + (:with-map acdw/map + (:bind "M-o" crux-other-window-or-switch-buffer) + (:bind "C-a" crux-move-beginning-of-line) + (:bind "C-k" crux-kill-and-join-forward)) + (crux-reopen-as-root-mode +1)) + +;;; Functionality + +;;;; Undo-fu +(setup (:straight undo-fu) + (:with-map acdw/map + (:bind "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/in-dir "undo/" t)) + (global-undo-fu-session-mode +1)) ;;; Minibuffer -(acdw/set '((minibuffer-prompt-properties (read-only t - cursor-intangible t - face minibuffer-prompt)) - (enable-recursive-minibuffers t) - (file-name-shadow-properties (invisible t)))) -(minibuffer-depth-indicate-mode +1) -(file-name-shadow-mode +1) +;;;; Icomplete-vertical +(setup (:straight icomplete-vertical) + (let ((map icomplete-minibuffer-map)) + (let ((command #'icomplete-forward-completions)) + (define-key map (kbd "") command) + (define-key map (kbd "C-n") command)) + (let ((command #'icomplete-backward-completions)) + (define-key map (kbd "") command) + (define-key map (kbd "C-p") command)) + (define-key map (kbd "RET") #'icomplete-force-complete-and-exit) + (define-key map (kbd "C-RET") #'minibuffer-complete-and-exit)) + (icomplete-vertical-mode +1)) -(acdw/pkg recursion-indicator - :set '((recursion-indicator-general "%") - (recursion-indicator-minibuffer "@")) - :now ((recursion-indicator-mode +1))) +;;;; Orderless +(setup (:straight orderless) + (:option (prepend completion-styles) 'orderless)) -;; Save history -(when (require 'savehist) - (acdw/set `((savehist-additional-variables - (kill-ring search-ring regexp-search-ring)) - (history-length t) - (history-delete-duplicates t) - (savehist-autosave-interval 6) - (savehist-file ,(acdw/in-dir "savehist.el")))) - (savehist-mode +1)) +;;;; Consult +(setup (:straight consult) + (:with-map acdw/map + (:bind-autoload + ;; C-c bindings (`mode-specific-map') + "C-c h" consult-history + "C-c m" consult-mode-command + ;; 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 + "C-x r x" consult-register + "C-x r b" consult-bookmark + ;; M-g bindings (`goto-map') + "M-g o" consult-outline + "M-g m" consult-mark + "M-g k" consult-global-mark + "M-g i" consult-imenu + "M-g e" consult-error + ;; M-s bindings (`search-map') + "M-s g" consult-grep ; alts: consult-git-grep, consult-ripgrep + "M-s f" consult-find ; alts: consult-locate + "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 + " a" consult-apropos + "C-h a" consult-apropos)) + (autoload 'consult-register-preview "consult") + (:option register-preview-delay 0 + register-preview-function #'consult-register-preview)) -;; God mode -(acdw/pkg god-mode - :binds (("" god-local-mode) - ("i" god-local-mode :map god-local-mode-map) - ("." repeat :map god-local-mode-map) - ("C-x C-1" delete-other-windows) - ("C-x C-2" split-window-below) - ("C-x C-3" split-window-right) - ("C-x C-0" delete-window)) - :now ((defun acdw/god-mode-update-cursor () - (setq cursor-type (if (or god-local-mode buffer-read-only) - 'box - 'bar))) - (defun acdw/god-mode-toggle-on-overwrite () - (if (bound-and-true-p overwrite-mode) - (progn - (setq cursor-type 'hbar) - (god-local-mode-pause)) - (god-local-mode-resume) - (acdw/god-mode-update-cursor))) - (require 'god-mode) - (god-mode)) - :hooks (((god-mode-enabled-hook god-mode-disabled-hook) - acdw/god-mode-update-cursor) - (overwrite-mode-hook acdw/god-mode-toggle-on-overwrite))) +;;;; Marginalia +(setup (:straight marginalia) + (:option marginalia-annotators '(marginalia-annotators-heavy + marginalia-annotators-light)) + (marginalia-mode +1)) -;; Icomplete (-vertical) -(when (require 'icomplete) - (acdw/set '((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))) - (acdw/pkg orderless - :set '((completion-styles (orderless)))) - (acdw/pkg icomplete-vertical - :binds (("" icomplete-forward-completions - :map icomplete-minibuffer-map) - ("C-n" icomplete-forward-completions - :map icomplete-minibuffer-map) - ("" icomplete-backward-completions - :map icomplete-minibuffer-map) - ("C-p" icomplete-backward-completions - :map icomplete-minibuffer-map) - ("C-v" icomplete-vertical-toggle - :map icomplete-minibuffer-map) - ("RET" icomplete-force-complete-and-exit - :map icomplete-minibuffer-map) - ("C-j" minibuffer-complete-and-exit - :map icomplete-minibuffer-map)) - :now ((fido-mode -1) - (icomplete-mode +1) - (icomplete-vertical-mode +1)))) +;;; UI -;; Consult -(acdw/pkg consult - :binds (;; C-c bindings (`mode-specific-map') - ("C-c h" consult-history) - ("C-c m" consult-mode-command) - ;; 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) - ("C-x r x" consult-register) - ("C-x r b" consult-bookmark) - ;; M-g bindings (`goto-map') - ("M-g o" consult-outline) - ("M-g m" consult-mark) - ("M-g k" consult-global-mark) - ("M-g i" consult-imenu) - ("M-g e" consult-error) - ;; M-s bindings (`search-map') - ("M-s g" consult-grep) ; alts: - ; consult-git-grep, - ; consult-ripgrep - ("M-s f" consult-find) ; alts: - ; consult-locate - ("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) - (" a" consult-apropos) - ("C-h a" consult-apropos)) - :now ((autoload 'consult-register-preview "consult")) - :set '((register-preview-delay 0) - (register-preview-function #'consult-register-preview))) +;;;; Modus themes +(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)) -;; begin-end -(acdw/pkg beginend - :now ((beginend-global-mode))) +;;;; Mode line +(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)) -;; Marginalia -(acdw/pkg marginalia - :set '((marginalia-annotators (marginalia-annotators-heavy - marginalia-annotators-light))) - :now ((marginalia-mode +1))) +;;; Utilities -;; Imenu -(when (require 'imenu) - (acdw/set '((imenu-auto-rescan t)))) +;;;; 0x0 -- upload files to a nullpointer +(setup (:straight (0x0 :host nil + :repo "https://git.sr.ht/~zge/nullpointer-emacs")) + (:option 0x0-default-host 'ttm)) -;; Fonts -(acdw/set-faces ((fixed-pitch . ((t (:inherit default)))))) +;;; Applications -;;; Packages - -;; Undo-fu -(acdw/pkg undo-fu - :binds (("C-/" undo-fu-only-undo) - ("C-?" undo-fu-only-redo))) -(acdw/pkg undo-fu-session - :set `((undo-fu-session-incompatible-files ("/COMMIT_EDITMSG\\'" - "/git-rebase-todo\\'")) - (undo-fu-session-directory ,(acdw/in-dir "undo/" t))) - :then ((global-undo-fu-session-mode +1))) - -;; Modus themes -(acdw/pkg (modus-themes - :host gitlab - :repo "protesilaos/modus-themes") - :set `((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-scale-headings nil) - (modus-themes-mode-line nil)) - :now ((acdw/sunrise-sunset #'modus-themes-load-operandi - #'modus-themes-load-vivendi))) - -;; Expand-region -(acdw/pkg expand-region - :binds (("C-=" er/expand-region))) - -;; CRUX -(acdw/pkg crux - :binds (("M-o" crux-other-window-or-switch-buffer) - ([remap move-beginning-of-line] crux-move-beginning-of-line) - ([remap kill-line] crux-kill-and-join-forward))) -;;; Frame title - -(acdw/set `((frame-title-format - "%b %+%* GNU Emacs"))) - -;;; Mode line - -;; Minions -(acdw/pkg minions) - -;; Simple mode line -(acdw/pkg simple-modeline - :set '((simple-modeline-segments - ((;; left - acdw-modeline/modified - acdw-modeline/buffer-name - acdw-modeline/vc-branch - simple-modeline-segment-position - simple-modeline-segment-word-count) - (;; right - simple-modeline-segment-misc-info - simple-modeline-segment-process - acdw-modeline/god-mode-indicator - acdw-modeline/minions - simple-modeline-segment-major-mode)))) - :now ((require 'acdw-modeline) - (simple-modeline-mode +1))) - -;;; Magit - -(acdw/pkg magit - :binds (("g" magit-status :map acdw/leader)) - :set `((magit-display-buffer-function - ,(defun magit-display-buffer-same-window (buffer) +;;;; Magit +(setup (:straight magit) + (:acdw/leader "g" magit-status) + (:option magit-display-buffer-function + (defun magit-display-buffer-same-window (buffer) "Display BUFFER in the selected window like God intended." - (display-buffer buffer - '(display-buffer-same-window)))) - (magit-popup-display-buffer-action - ((display-buffer-same-window))))) + (display-buffer buffer '(display-buffer-same-window))) + magit-popup-display-buffer-action '((display-buffer-same-window)))) -;;; Web browsing +;;;; File browsing +(setup (:straight dired-subtree) + (define-key dired-mode-map "i" #'dired-subtree-toggle)) -(acdw/set '((browse-url-browser-function browse-url-firefox) - (browse-url-new-window-flag t) - (browse-url-firefox-new-window-is-tab t) - (shr-max-width fill-column) - (shr-width fill-column))) +(setup (:straight dired-collapse) + (:hook-into dired-mode)) +;;;; Web browsing (when (eq acdw/system :work) (add-to-list 'exec-path "C:/Program Files/Mozilla Firefox")) -(acdw/hooks ((text-mode-hook goto-address-mode) - (prog-mode-hook goto-address-prog-mode))) +(setc browse-url-browser-function 'browse-url-firefox + browse-url-new-window-flag t + browse-url-firefox-new-window-is-tab t + shr-max-width fill-column + shr-width fill-column) -;;; Gemini/gopher browsing +(add-hook 'text-mode-hook #'goto-address-mode) +(add-hook 'prog-mode-hook #'goto-address-prog-mode) -(acdw/pkg (elpher - :repo "git://thelambdalab.xyz/elpher.git") - :set '((elpher-ipv4-always t) - (elpher-certificate-directory - (acdw/in-var "elpher/"))) - :now ((acdw/bind-after-map "elpher" elpher-mode-map - (("n" elpher-next-link :map-after "elpher") - ("p" elpher-prev-link :map-after "elpher") - ("o" elpher-follow-current-link :map-after "elpher") - ("G" elpher-go-current :map-after "elpher"))) - (when (boundp 'god-exempt-major-modes) - (add-to-list 'god-exempt-major-modes 'elpher-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/")) + (:bind "n" elpher-next-link + "p" elpher-prev-link + "o" elpher-follow-current-link + "G" elpher-go-current) + (:hook acdw/reading-mode) + (when (boundp 'god-exempt-major-modes) + (:option (append god-exempt-major-modes) 'elpher-mode))) -(acdw/pkg (gemini-mode - :repo "https://git.carcosa.net/jmcbray/gemini.el.git") - :now ((add-to-list 'auto-mode-alist - '("\\.\\(gemini\\|gmi\\)\\'" . gemini-mode)))) +(setup (:straight (gemini-mode + :host nil + :repo "https://git.carcosa.net/jmcbray/gemini.el.git")) + (:option (append auto-mode-alist) + '("\\.\\(gemini\\|gmi\\)\\'" . gemini-mode))) -;;; Dired -(acdw/pkg dired - :local t - :set `((dired-recursive-copies always) - (dired-recursive-deletes always) - (delete-by-moving-to-trash t) - (dired-listing-switches "-Al") - (ls-lisp-dirs-first t) - (dired-dwim-target t)) - :now ((autoload 'dired-mode-map "dired" nil nil 'keymap) - (acdw/pkg dired-subtree) - (acdw/pkg dired-x - :local t - :binds (("C-x C-j" dired-jump))) - (acdw/pkg dired-collapse - :hooks ((dired-mode-hook dired-collapse-mode))) - (defun hook--dired-mode () - (hl-line-mode +1) - (dired-hide-details-mode +1))) - :hooks ((dired-mode-hook hook--dired-mode)) - :binds (("i" dired-subtree-toggle :map dired-mode-map))) +;;;; Read e-books (nov.el) +(setup (:straight nov) + (:option nov-text-width fill-column + (append auto-mode-alist) '("\\.epub\\'" . nov-mode))) -;;; Eshell - -(acdw/set `((eshell-directory-name ,(acdw/in-dir "eshell/" t)) - (eshell-aliases-file ,(acdw/in-dir "eshell/aliases" t)))) - -;;; Org-mode -(acdw/pkg (org - :repo "https://code.orgmode.org/bzg/org-mode.git") - :now ((require 'acdw-org)) - :set `((org-directory "~/org") - (org-hide-emphasis-markers t) - (org-fontify-whole-heading-line t) - (org-fontify-done-headline t) - (org-fontify-quote-and-verse-blocks t) - (org-src-fontify-natively t) - (org-pretty-entities t) - (org-tags-column ,(- 0 fill-column -3)) - (org-src-tab-acts-natively t) - (org-src-window-setup current-window) - (org-confirm-babel-evaluate nil) - (org-adapt-indentation nil) - (org-catch-invisible-edits smart) - (org-special-ctrl-a/e t) - (org-special-ctrl-k t) - (org-imenu-depth 3) - (org-export-headline-levels 8) - (org-export-with-smart-quotes t) - (org-export-with-sub-superscripts t)) - :hooks ((before-save-hook acdw/hook--org-mode-fix-blank-lines)) - :binds (("RET" unpackaged/org-return-dwim - :map org-mode-map :map-after 'org))) - -;;; Nov.el -- ebook reader -(acdw/pkg nov - :now ((autoload #'nov-mode "nov") - (add-to-list 'auto-mode-alist '("\\.epub\\'" . nov-mode))) - :set `((nov-text-width ,fill-column))) - -;;; 0x0 -- upload files -(acdw/pkg (0x0 :repo "https://git.sr.ht/~zge/nullpointer-emacs") - :set '((0x0-default-host ttm))) +;;;; Org mode +(setup (:straight (org :host nil + :repo "https://code.orgmode.org/bzg/org-mode.git")) + (require 'acdw-org) + (:option org-directory "~/org" + org-hide-emphasis-markers t + org-fontify-whole-heading-line t + org-fontify-done-headline t + org-fontify-quote-and-verse-blocks t + org-src-fontify-natively t + org-pretty-entities t + org-tags-column (- 0 fill-column -3) + org-src-tab-acts-natively t + org-src-window-setup 'current-window + org-confirm-babel-evaluate nil + org-adapt-indentation nil + org-catch-invisible-edits 'smart + org-special-ctrl-a/e t + org-special-ctrl-k t + org-imenu-depth 3 + org-export-headline-levels 8 + org-export-with-smart-quotes t + org-export-with-sub-superscripts t) + (:bind "RET" unpackaged/org-return-dwim) + (add-hook 'before-save-hook #'acdw/hook--org-mode-fix-blank-lines)) ;;; Programming languages -;; General +;;;; Formatting +(setup (:straight (apheleia :host github + :repo "raxod502/apheleia")) + (apheleia-global-mode +1)) -(acdw/set `((smie-indent-basic ,tab-width))) - -;; Formatting - -(acdw/pkg (apheleia - :host github - :repo "raxod502/apheleia") - :now ((apheleia-global-mode +1)) - :then ((add-to-list 'apheleia-formatters - '(shfmt . ("shfmt"))) - (add-to-list 'apheleia-mode-alist - '(sh-mode . shfmt)))) - -;; Shell(s) -(when (executable-find "shellcheck") - (acdw/pkg flymake-shellcheck - :hooks ((sh-mode-hook (flymake-mode - flymake-shellcheck-load))))) - -(acdw/set `((sh-basic-offset ,tab-width) - (sh-indent-after-case 0) - (sh-indent-for-case-alt +) - (sh-indent-for-case-label 0))) - -(defun hook--sh-mode-indent-like-shfmt () - "Try to mirror `shfmt' formatting in shell scripts." - (setq indent-tabs-mode t)) -(add-hook 'sh-mode-hook #'hook--sh-mode-indent-like-shfmt) - -;; Emacs lisp -(acdw/set '((eval-expression-print-length nil) - (eval-expression-print-level nil))) - -(when (require 'cl-lib) - (setq-default lisp-indent-function #'common-lisp-indent-function) +;;;; Emacs lisp +(setup emacs-lisp + (require 'cl-lib) + (:option eval-expression-print-length nil + eval-expression-print-level nil + lisp-indent-function #'common-lisp-indent-function) (put 'cl-flet 'common-lisp-indent-function (get 'flet 'common-lisp-indent-function)) (put 'cl-labels 'common-lisp-indent-function @@ -526,34 +519,36 @@ (put 'dotimes-protect 'common-lisp-indent-function (get 'when 'common-lisp-indent-function))) -;; Racket -(acdw/pkg racket-mode) +;;;; Shell scripts +(setup sh + (: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") + (:option (append apheleia-formatters) '(shfmt . ("shfmt")) + (append apheleia-mode-alist) '(sh-mode . shfmt))) -;; Web stuff -(acdw/set '((css-indent-offset 2) - (js-indent-level 2) - (sgml-indent-offset 2))) + (when (executable-find "shellcheck") + (straight-use-package 'flymake-shellcheck) + (:hook flymake-mode + flymake-shellcheck-load))) -;;; Miscellaneous - -(acdw/set '((disabled-command-function nil) - (load-prefer-newer t) - (comp-async-report-warnings-errors nil))) - -(fset 'yes-or-no-p #'y-or-n-p) - -;; Garbage collection -(defun hook--gc-cons-maximize () - (setq gc-cons-threshold most-positive-fixnum)) -(add-hook 'minibuffer-setup-hook #'hook--gc-cons-maximize) - -(defun hook--gc-cons-baseline () - (setq gc-cons-threshold gc-cons-threshold-basis)) -(add-hook 'minibuffer-exit-hook #'hook--gc-cons-baseline) - -(defun hook--gc-when-unfocused () - (acdw/when-unfocused #'garbage-collect)) -(add-function :after after-focus-change-function - #'hook--gc-when-unfocused) +;;;; Web languages +(setup (:straight web-mode) + (:option css-level-offset 2 + js-indent-level 2 + sgml-indent-offset 2) + (dolist (extension '("\\(p\\|dj\\)?html" + "html?" + "\\(tpl\\.\\)?php" + "[agj]sp" + "as[cp]x" + "erb" + "mustache")) + (add-to-list 'auto-mode-alist + `(,(concat "\\." extension "\\'") . web-mode)))) ;;; init.el ends here diff --git a/lisp/acdw.el b/lisp/acdw.el index 62778e3..9aa0821 100644 --- a/lisp/acdw.el +++ b/lisp/acdw.el @@ -22,9 +22,9 @@ ;;; Utilities (defconst acdw/system (pcase system-type - ('gnu/linux :home) - ((or 'msdos 'windows-nt) :work) - (_ :other)) + ('gnu/linux :home) + ((or 'msdos 'windows-nt) :work) + (_ :other)) "Which system is currently being used.") (defun acdw/when-unfocused (func &rest args) @@ -37,220 +37,260 @@ Ready for use with `after-focus-change-function'." (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))) + (: (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))) +;;; Garbage collection hacks + +(defconst acdw/gc-cons-threshold-basis (* 800 1024 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)) + +(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)) + ;;; Directories (think `no-littering') (defvar acdw/dir (expand-file-name - (convert-standard-filename "var/") - user-emacs-directory) + (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))) + acdw/dir))) (when make-directory (make-directory (file-name-directory f) 'parents)) f)) ;;; Settings -(defun acdw/set (assignments) - "Perform `customize-set-variable' on each of ASSIGNMENTS. +;; (defun acdw/set (assignments) +;; "Perform `customize-set-variable' on each of ASSIGNMENTS. -ASSIGNMENTS is a list where each element is of the form -(VARIABLE VALUE [COMMENT])." - (let (setting) ; for return value - (dolist (assignment assignments setting) - (customize-set-variable (car assignment) - (cadr assignment) - (if (and (caddr assignment) - (stringp (caddr assignment))) - (caddr assignment) - "Customized by `acdw/set'.")) - (setq setting (car assignment))))) +;; ASSIGNMENTS is a list where each element is of the form +;; (VARIABLE VALUE [COMMENT])." +;; (let (setting) ; for return value +;; (dolist (assignment assignments setting) +;; (customize-set-variable (car assignment) +;; (cadr assignment) +;; (if (and (caddr assignment) +;; (stringp (caddr assignment))) +;; (caddr assignment) +;; "Customized by `acdw/set'.")) +;; (setq setting (car assignment))))) ;;; Faces -(defun acdw/set-face (face spec) - "Customize FACE according to SPEC, and register it with `customize'. -SPEC is as for `defface'." - (put face 'customized-face spec) - (face-spec-set face spec)) +;; (defun acdw/set-face (face spec) +;; "Customize FACE according to SPEC, and register it with `customize'. +;; SPEC is as for `defface'." +;; (put face 'customized-face spec) +;; (face-spec-set face spec)) -(defmacro acdw/set-faces (face-specs) - "Run `acdw/set-face' over each face in FACE-SPECS." - (let (face-list) - (dolist (face face-specs) - (push `(acdw/set-face ',(car face) ',(cdr face)) face-list)) - `(progn - ,@face-list))) +;; (defmacro acdw/set-faces (face-specs) +;; "Run `acdw/set-face' over each face in FACE-SPECS." +;; (let (face-list) +;; (dolist (face face-specs) +;; (push `(acdw/set-face ',(car face) ',(cdr face)) face-list)) +;; `(progn +;; ,@face-list))) ;;; Hooks -(defmacro acdw/hooks (hook-specs &rest args) - "Add functions to hooks, according to HOOK-SPECS. +;; (defmacro acdw/hooks (hook-specs &rest args) +;; "Add functions to hooks, according to HOOK-SPECS. -Each HOOK-SPEC is of the following format: (HOOKS FUNCS [DEPTH] [LOCAL]). -Either HOOKS or FUNCS can also be a list, in which case `add-hook' is called -over the Cartesian product of HOOKS and FUNCS. In each HOOK-SPEC, DEPTH and -LOCAL apply to all hooks defined; if finer control is needed, either pass the -same hooks and functions in different HOOK-SPECs, or just use `add-hook'. +;; Each HOOK-SPEC is of the following format: (HOOKS FUNCS [DEPTH] [LOCAL]). +;; Either HOOKS or FUNCS can also be a list, in which case `add-hook' is called +;; over the Cartesian product of HOOKS and FUNCS. In each HOOK-SPEC, DEPTH and +;; LOCAL apply to all hooks defined; if finer control is needed, either pass the +;; same hooks and functions in different HOOK-SPECs, or just use `add-hook'. -ARGS accept the following keywords: +;; ARGS accept the following keywords: -:after FEATURE .. `autoload' all functions after FEATURE." - (let ((after (plist-get args :after)) - (command-list)) - (dolist (spec hook-specs) - (let* ((hooks (car spec)) - (funcs (cadr spec)) - (depth (or (caddr spec) 0)) - (local (cadddr spec))) - (when (not (listp hooks)) (setq hooks (list hooks))) - (when (not (listp funcs)) (setq funcs (list funcs))) - (dolist (hook hooks) - (dolist (func funcs) - (push `(add-hook ',hook #',func ,depth ,local) command-list) - (when after - (push `(autoload #',func ,after) command-list)))))) - `(progn - ,@command-list))) +;; :after FEATURE .. `autoload' all functions after FEATURE." +;; (let ((after (plist-get args :after)) +;; (command-list)) +;; (dolist (spec hook-specs) +;; (let* ((hooks (car spec)) +;; (funcs (cadr spec)) +;; (depth (or (caddr spec) 0)) +;; (local (cadddr spec))) +;; (when (not (listp hooks)) (setq hooks (list hooks))) +;; (when (not (listp funcs)) (setq funcs (list funcs))) +;; (dolist (hook hooks) +;; (dolist (func funcs) +;; (push `(add-hook ',hook #',func ,depth ,local) command-list) +;; (when after +;; (push `(autoload #',func ,after) command-list)))))) +;; `(progn +;; ,@command-list))) ;;; Keybindings -(defvar acdw/bind-default-map 'acdw/map - "The default keymap to use with `acdw/bind'.") +;; (defvar acdw/bind-default-map 'acdw/map +;; "The default keymap to use with `acdw/bind'.") -(defmacro acdw/bind (key command &rest args) - "A simple key-binding macro to take care of the repetitive stuff -automatically. +;; (defmacro acdw/bind (key command &rest args) +;; "A simple key-binding macro to take care of the repetitive stuff +;; automatically. -If KEY is a vector, it's passed directly to `define-key', -otherwise it's wrapped in `kbd'. +;; If KEY is a vector, it's passed directly to `define-key', +;; otherwise it's wrapped in `kbd'. -The following keywords are recognized: +;; The following keywords are recognized: -:after ARGS .. call `autoload' on COMMAND using ARGS before - binding the key. ARGS can be just the filename to - load; in that case it's wrapped in a list. +;; :after ARGS .. call `autoload' on COMMAND using ARGS before +;; binding the key. ARGS can be just the filename to +;; load; in that case it's wrapped in a list. -:map KEYMAP .. define KEY in KEYMAP instead of the - default `acdw/bind-default-map'. If `:after' is also supplied, - run `autoload' on KEYMAP (except when using `:map-after', see). +;; :map KEYMAP .. define KEY in KEYMAP instead of the +;; default `acdw/bind-default-map'. If `:after' is also supplied, +;; run `autoload' on KEYMAP (except when using `:map-after', see). -:map-after FILE .. run the underlying `define-key' command in an - `with-eval-after-load'. For the rare occasion when the keymap is - defined in a different file than the command it binds (looking - at you, `org-mode')." - (let ((after (when-let (sym (plist-get args :after)) - (if (not (listp sym)) - (list sym) - sym))) - (map-after (plist-get args :map-after)) - (keymap (or (plist-get args :map) acdw/bind-default-map)) - (keycode (if (vectorp key) key (kbd key))) - (command-list)) - (let ((define-key-command `(define-key ,keymap ,keycode ',command))) - (if map-after - (push `(with-eval-after-load ,map-after - ,define-key-command) - command-list) - (push define-key-command command-list))) - (when after - (unless (fboundp command) - (push `(autoload ',command ,@after) command-list)) - (unless (or map-after - (eq keymap acdw/bind-default-map)) - (push `(autoload ',keymap ,(car after) nil nil 'keymap) command-list))) - `(progn - ,@command-list))) +;; :map-after FILE .. run the underlying `define-key' command in an +;; `with-eval-after-load'. For the rare occasion when the keymap is +;; defined in a different file than the command it binds (looking +;; at you, `org-mode')." +;; (let ((after (when-let (sym (plist-get args :after)) +;; (if (not (listp sym)) +;; (list sym) +;; sym))) +;; (map-after (plist-get args :map-after)) +;; (keymap (or (plist-get args :map) acdw/bind-default-map)) +;; (keycode (if (vectorp key) key (kbd key))) +;; (command-list)) +;; (let ((define-key-command `(define-key ,keymap ,keycode ',command))) +;; (if map-after +;; (push `(with-eval-after-load ,map-after +;; ,define-key-command) +;; command-list) +;; (push define-key-command command-list))) +;; (when after +;; (unless (fboundp command) +;; (push `(autoload ',command ,@after) command-list)) +;; (unless (or map-after +;; (eq keymap acdw/bind-default-map)) +;; (push `(autoload ',keymap ,(car after) nil nil 'keymap) command-list))) +;; `(progn +;; ,@command-list))) -(defmacro acdw/binds (bindings) - "Bind multiple keys at once." - (let (bind-list) - (dolist (bind bindings) - (push `(acdw/bind ,@bind) bind-list)) - `(progn - ,@bind-list))) +;; (defmacro acdw/binds (bindings) +;; "Bind multiple keys at once." +;; (let (bind-list) +;; (dolist (bind bindings) +;; (push `(acdw/bind ,@bind) bind-list)) +;; `(progn +;; ,@bind-list))) ;; convenience -(defmacro acdw/bind-after-map (file keymap bindings) - "Wrap multiple calls of `acdw/bind' after FILE and with KEYMAP. -KEYMAP can be nil." - (declare (indent 2)) - (let ((bind-list) - (extra-args (if keymap - `(:after ,file :map ,keymap) - `(:after ,file)))) - (dolist (binding bindings) - (push `(acdw/bind ,@binding ,@extra-args) bind-list)) - `(progn - ,@bind-list))) +;; (defmacro acdw/bind-after-map (file keymap bindings) +;; "Wrap multiple calls of `acdw/bind' after FILE and with KEYMAP. +;; KEYMAP can be nil." +;; (declare (indent 2)) +;; (let ((bind-list) +;; (extra-args (if keymap +;; `(:after ,file :map ,keymap) +;; `(:after ,file)))) +;; (dolist (binding bindings) +;; (push `(acdw/bind ,@binding ,@extra-args) bind-list)) +;; `(progn +;; ,@bind-list))) ;;; Packages -(defmacro acdw/pkg (package &rest args) - "Set up a package using `straight.el'. +;; (defmacro acdw/pkg (package &rest args) +;; "Set up a package using `straight.el'. -ARGS can include the following keywords: +;; ARGS can include the following keywords: -:local BOOL .. if BOOL is non-nil, don't run `straight-use-package' on - PACKAGE. Good for using `acdw/pkg' on local features. -:require BOOL .. if BOOL is non-nil, run `require' on PACKAGE before anything. -:now FORMS .. run FORMS immediately. -:then FORMS .. run FORMS after loading PACKAGE, using `with-eval-after-load'. -:set SETTINGS .. pass SETTINGS to `acdw/set', right after `:now' forms. - SETTINGS should be properly quoted, just like they'd be passed - to the function. -:binds BINDS .. run `acdw/bind-after-map' on BINDS. -:hooks HOOKS .. run `acdw/hooks' on HOOKS." - (declare (indent 1)) - (let ((local-pkg (plist-get args :local)) - (require-pkg (plist-get args :require)) - (now-forms (plist-get args :now)) - (settings (plist-get args :set)) - (binds (plist-get args :binds)) - (hooks (plist-get args :hooks)) - (then-forms (plist-get args :then)) - (requirement (if (listp package) - (car package) - package)) - (final-form)) - (when then-forms - (push `(with-eval-after-load ',requirement ,@then-forms) final-form)) - (when hooks - (push `(acdw/hooks ,hooks :after ,(symbol-name requirement)) final-form)) - (when binds - (push `(acdw/bind-after-map ,(symbol-name requirement) nil ,binds) - final-form)) - (when settings - (push `(acdw/set ,settings) final-form)) - (when now-forms - (push `(progn ,@now-forms) final-form)) - (unless local-pkg - (push `(straight-use-package ',package) final-form)) - (when require-pkg - (push `(require ',requirement) final-form)) - `(progn - ,@final-form))) +;; :local BOOL .. if BOOL is non-nil, don't run `straight-use-package' on +;; PACKAGE. Good for using `acdw/pkg' on local features. +;; :require BOOL .. if BOOL is non-nil, run `require' on PACKAGE before anything. +;; :now FORMS .. run FORMS immediately. +;; :then FORMS .. run FORMS after loading PACKAGE, using `with-eval-after-load'. +;; :set SETTINGS .. pass SETTINGS to `acdw/set', right after `:now' forms. +;; SETTINGS should be properly quoted, just like they'd be passed +;; to the function. +;; :binds BINDS .. run `acdw/bind-after-map' on BINDS. +;; :hooks HOOKS .. run `acdw/hooks' on HOOKS." +;; (declare (indent 1)) +;; (let ((local-pkg (plist-get args :local)) +;; (require-pkg (plist-get args :require)) +;; (now-forms (plist-get args :now)) +;; (settings (plist-get args :set)) +;; (binds (plist-get args :binds)) +;; (hooks (plist-get args :hooks)) +;; (then-forms (plist-get args :then)) +;; (requirement (if (listp package) +;; (car package) +;; package)) +;; (final-form)) +;; (when then-forms +;; (push `(with-eval-after-load ',requirement ,@then-forms) final-form)) +;; (when hooks +;; (push `(acdw/hooks ,hooks :after ,(symbol-name requirement)) final-form)) +;; (when binds +;; (push `(acdw/bind-after-map ,(symbol-name requirement) nil ,binds) +;; final-form)) +;; (when settings +;; (push `(acdw/set ,settings) final-form)) +;; (when now-forms +;; (push `(progn ,@now-forms) final-form)) +;; (unless local-pkg +;; (push `(straight-use-package ',package) final-form)) +;; (when require-pkg +;; (push `(require ',requirement) final-form)) +;; `(progn +;; ,@final-form))) + +;;; Reading mode + +(define-minor-mode acdw/reading-mode + "A mode for reading." + :init-value t + :lighter " Read" + (if acdw/reading-mode + (progn ;; turn on + (display-fill-column-indicator-mode -1) + (dolist (mode '(visual-fill-column-mode + iscroll-mode)) + (when (fboundp mode) + (funcall mode +1)))) + ;; turn off + (display-fill-column-indicator-mode +1) + (dolist (mode '(visual-fill-column-mode + iscroll-mode)) + (when (fboundp mode) + (funcall mode -1))))) ;;; Keymap & Mode @@ -273,7 +313,7 @@ ARGS can include the following keywords: ;; Set up a leader key for `acdw/mode' (defvar acdw/leader (let ((map (make-sparse-keymap)) - (c-z (global-key-binding "\C-z"))) + (c-z (global-key-binding "\C-z"))) (define-key acdw/map "\C-z" map) (define-key map "\C-z" c-z) map))