diff options
author | Case Duckworth | 2021-03-29 17:52:23 -0500 |
---|---|---|
committer | Case Duckworth | 2021-03-29 17:52:23 -0500 |
commit | 1dd6b9c0eed5a596711340cbf48456ac003f8e7c (patch) | |
tree | 6d671b1a9ca775f44c89213931057b2ece38a12c | |
parent | bleh (diff) | |
download | emacs-1dd6b9c0eed5a596711340cbf48456ac003f8e7c.tar.gz emacs-1dd6b9c0eed5a596711340cbf48456ac003f8e7c.zip |
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.
-rw-r--r-- | early-init.el | 111 | ||||
-rw-r--r-- | init.el | 961 | ||||
-rw-r--r-- | lisp/acdw.el | 412 |
3 files changed, 753 insertions, 731 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 @@ | |||
27 | ;;; Speed up init | 27 | ;;; Speed up init |
28 | ;; see doom-emacs, et al. | 28 | ;; see doom-emacs, et al. |
29 | 29 | ||
30 | (defconst gc-cons-threshold-basis (* 800 1000) | ||
31 | "The basis value for `gc-cons-threshold' to return to after a jump. | ||
32 | 800 KB is Emacs's default `gc-cons-threshold'.") | ||
33 | |||
34 | (defconst gc-cons-percentage-basis 0.1 | ||
35 | "The basis value for `gc-cons-percentage' to return to after init. | ||
36 | 0.1 is Emacs's default `gc-cons-percentage'.") | ||
37 | |||
38 | (defvar orig-file-name-handler-alist file-name-handler-alist | 30 | (defvar orig-file-name-handler-alist file-name-handler-alist |
39 | "The original value of `file-name-handler-alist' will be restored | 31 | "The original value of `file-name-handler-alist' will be restored |
40 | after init.") | 32 | after init.") |
41 | 33 | ||
42 | (setq gc-cons-threshold most-positive-fixnum | 34 | (setq file-name-handler-alist nil) |
43 | gc-cons-percentage 0.6 | 35 | (acdw/gc-disable) |
44 | file-name-handler-alist nil) | ||
45 | 36 | ||
46 | (defun hook--post-init-reset () | 37 | (add-hook 'after-init-hook |
47 | "Reset `gc-cons-threshold', `gc-cons-percentage', and | 38 | (defun hook--post-init-reset () |
39 | "Reset `gc-cons-threshold', `gc-cons-percentage', and | ||
48 | `file-name-handler-alist' to their defaults after init." | 40 | `file-name-handler-alist' to their defaults after init." |
49 | (setq gc-cons-threshold gc-cons-threshold-basis | 41 | (acdw/gc-enable) |
50 | gc-cons-percentage gc-cons-percentage-basis) | 42 | (dolist (handler file-name-handler-alist) |
51 | (dolist (handler file-name-handler-alist) | 43 | (add-to-list 'orig-file-name-handler-alist handler)) |
52 | (add-to-list 'orig-file-name-handler-alist handler)) | 44 | (setq file-name-handler-alist orig-file-name-handler-alist))) |
53 | (setq file-name-handler-alist orig-file-name-handler-alist)) | ||
54 | |||
55 | (add-hook 'after-init-hook #'hook--post-init-reset) | ||
56 | 45 | ||
57 | ;;; Frame settings | 46 | ;;; Frame settings |
58 | 47 | ||
59 | (setq default-frame-alist ; Remove most UI | 48 | (setq default-frame-alist ; Remove most UI |
60 | `((tool-bar-lines . 0) ; No tool bar | 49 | `((tool-bar-lines . 0) ; No tool bar |
61 | (menu-bar-lines . 0) ; No menu bar | 50 | (menu-bar-lines . 0) ; No menu bar |
62 | (vertical-scroll-bars) ; No scroll bars | 51 | (vertical-scroll-bars) ; No scroll bars |
63 | (horizontal-scroll-bars) ; ... at all | 52 | (horizontal-scroll-bars) ; ... at all |
64 | (width . 84) ; A /little/ wider than | 53 | (width . 84) ; A /little/ wider than |
65 | ; `fill-column' (set later) | 54 | ; `fill-column' (set later) |
66 | (height . 30) | 55 | (height . 30) |
67 | (left-fringe . 8) ; Width of fringes | 56 | (left-fringe . 8) ; Width of fringes |
68 | (right-fringe . 8) ; (8 is default) | 57 | (right-fringe . 8) ; (8 is default) |
69 | (font . ,(pcase acdw/system | 58 | (font . ,(pcase acdw/system |
70 | (:home "DejaVu Sans Mono 10") | 59 | (:home "DejaVu Sans Mono 10") |
71 | (:work "Consolas 10")))) | 60 | (:work "Consolas 10")))) |
72 | frame-inhibit-implied-resize t ; Don't resize randomly | 61 | frame-inhibit-implied-resize t ; Don't resize randomly |
73 | frame-resize-pixelwise t ; Resize by pixels, not chars | 62 | frame-resize-pixelwise t ; Resize by pixels, not chars |
74 | ) | 63 | ) |
75 | 64 | ||
76 | (defun hook--disable-ui-modes () | 65 | (defun hook--disable-ui-modes () |
77 | "Disable frame UI using modes, for toggling later." | 66 | "Disable frame UI using modes, for toggling later." |
78 | (dolist (mode ;; each mode is of the form (MODE . FRAME-ALIST-VAR) | 67 | (dolist (mode ;; each mode is of the form (MODE . FRAME-ALIST-VAR) |
79 | '((tool-bar-mode . tool-bar-lines) | 68 | '((tool-bar-mode . tool-bar-lines) |
80 | (menu-bar-mode . menu-bar-lines) | 69 | (menu-bar-mode . menu-bar-lines) |
81 | (scroll-bar-mode . vertical-scroll-bars) | 70 | (scroll-bar-mode . vertical-scroll-bars) |
82 | (horizontal-scroll-bar-mode . horizontal-scroll-bars) | 71 | (horizontal-scroll-bar-mode . horizontal-scroll-bars) |
83 | )) | 72 | )) |
84 | (let ((setting (alist-get (cdr mode) default-frame-alist))) | 73 | (let ((setting (alist-get (cdr mode) default-frame-alist))) |
85 | (when (or (not setting) | 74 | (when (or (not setting) |
86 | (= 0 setting)) | 75 | (= 0 setting)) |
87 | (funcall (car mode) -1))))) | 76 | (funcall (car mode) -1))))) |
88 | 77 | ||
89 | (add-hook 'after-init-hook #'hook--disable-ui-modes) | 78 | (add-hook 'after-init-hook #'hook--disable-ui-modes) |
90 | 79 | ||
@@ -92,11 +81,11 @@ | |||
92 | 81 | ||
93 | ;; 1. Update `exec-path'. | 82 | ;; 1. Update `exec-path'. |
94 | (dolist (path (list (expand-file-name "bin" user-emacs-directory) | 83 | (dolist (path (list (expand-file-name "bin" user-emacs-directory) |
95 | (expand-file-name "~/bin") | 84 | (expand-file-name "~/bin") |
96 | (expand-file-name "~/.local/bin") | 85 | (expand-file-name "~/.local/bin") |
97 | (expand-file-name "~/usr/bin") | 86 | (expand-file-name "~/usr/bin") |
98 | (expand-file-name "~/cmd") | 87 | (expand-file-name "~/cmd") |
99 | (expand-file-name "~/mingw64/bin"))) | 88 | (expand-file-name "~/mingw64/bin"))) |
100 | (when (file-exists-p path) | 89 | (when (file-exists-p path) |
101 | (add-to-list 'exec-path path :append))) | 90 | (add-to-list 'exec-path path :append))) |
102 | 91 | ||
@@ -104,27 +93,25 @@ | |||
104 | (setenv "PATH" (mapconcat #'identity exec-path path-separator)) | 93 | (setenv "PATH" (mapconcat #'identity exec-path path-separator)) |
105 | 94 | ||
106 | ;; 2. Set `package' and `straight' variables. | 95 | ;; 2. Set `package' and `straight' variables. |
107 | (setq package-enable-at-startup nil ; not sure if strictly | 96 | (setq package-enable-at-startup nil |
108 | ; necessary | 97 | package-quickstart nil |
109 | package-quickstart nil ; ditto | ||
110 | straight-host-usernames '((github . "duckwork") | 98 | straight-host-usernames '((github . "duckwork") |
111 | (gitlab . "acdw")) | 99 | (gitlab . "acdw")) |
112 | straight-base-dir acdw/dir ; don't clutter ~/.emacs.d | 100 | straight-base-dir acdw/dir) |
113 | ) | ||
114 | 101 | ||
115 | ;; 3. Bootstrap `straight'. | 102 | ;; 3. Bootstrap `straight'. |
116 | (defvar bootstrap-version) | 103 | (defvar bootstrap-version) |
117 | (let ((bootstrap-file | 104 | (let ((bootstrap-file |
118 | (expand-file-name | 105 | (expand-file-name |
119 | "straight/repos/straight.el/bootstrap.el" | 106 | "straight/repos/straight.el/bootstrap.el" |
120 | straight-base-dir)) | 107 | straight-base-dir)) |
121 | (bootstrap-version 5)) | 108 | (bootstrap-version 5)) |
122 | (unless (file-exists-p bootstrap-file) | 109 | (unless (file-exists-p bootstrap-file) |
123 | (with-current-buffer | 110 | (with-current-buffer |
124 | (url-retrieve-synchronously | 111 | (url-retrieve-synchronously |
125 | (concat "https://raw.githubusercontent.com/" | 112 | (concat "https://raw.githubusercontent.com/" |
126 | "raxod502/straight.el/develop/install.el") | 113 | "raxod502/straight.el/develop/install.el") |
127 | 'silent 'inhibit-cookies) | 114 | 'silent 'inhibit-cookies) |
128 | (goto-char (point-max)) | 115 | (goto-char (point-max)) |
129 | (eval-print-last-sexp))) | 116 | (eval-print-last-sexp))) |
130 | (load bootstrap-file nil 'nomessage)) | 117 | (load bootstrap-file nil 'nomessage)) |
@@ -134,10 +121,10 @@ | |||
134 | (defun hook--message-startup-time () | 121 | (defun hook--message-startup-time () |
135 | "Show Emacs's startup time in the message buffer. For profiling." | 122 | "Show Emacs's startup time in the message buffer. For profiling." |
136 | (message "Emacs ready in %s with %d garbage collections." | 123 | (message "Emacs ready in %s with %d garbage collections." |
137 | (format "%.2f seconds" | 124 | (format "%.2f seconds" |
138 | (float-time (time-subtract after-init-time | 125 | (float-time (time-subtract after-init-time |
139 | before-init-time))) | 126 | before-init-time))) |
140 | gcs-done)) | 127 | gcs-done)) |
141 | 128 | ||
142 | (add-hook 'emacs-startup-hook #'hook--message-startup-time) | 129 | (add-hook 'emacs-startup-hook #'hook--message-startup-time) |
143 | 130 | ||
diff --git a/init.el b/init.el index 8f2bc12..cec8777 100644 --- a/init.el +++ b/init.el | |||
@@ -3,7 +3,7 @@ | |||
3 | ;; Created: Sometime during Covid-19, 2020 | 3 | ;; Created: Sometime during Covid-19, 2020 |
4 | ;; Keywords: configuration | 4 | ;; Keywords: configuration |
5 | ;; URL: https://tildegit.org/acdw/emacs | 5 | ;; URL: https://tildegit.org/acdw/emacs |
6 | ;; Bankruptcy: 5d | 6 | ;; Bankruptcy: 6 |
7 | 7 | ||
8 | ;; This file is NOT part of GNU Emacs. | 8 | ;; This file is NOT part of GNU Emacs. |
9 | 9 | ||
@@ -16,54 +16,113 @@ | |||
16 | 16 | ||
17 | ;;; Code: | 17 | ;;; Code: |
18 | 18 | ||
19 | ;;; `setup' -- configuration macro | ||
20 | (straight-use-package '(setup :host nil | ||
21 | :repo "https://git.sr.ht/~zge/setup")) | ||
22 | (require 'setup) | ||
23 | |||
24 | ;; shorthand for `customize-set-variable' (via setup) | ||
25 | (defmacro setc (&rest args) | ||
26 | "Customize user options using ARGS like `setq'." | ||
27 | (declare (debug setq)) | ||
28 | `(setup (:option ,@args))) | ||
29 | |||
30 | ;; Install packages with `straight-use-package' | ||
31 | (setup-define :straight | ||
32 | (lambda (recipe) | ||
33 | `(straight-use-package ',recipe)) | ||
34 | :documentation "Install RECIPE with `straight-use-package'." | ||
35 | :repeatable t | ||
36 | :shorthand (lambda (sexp) | ||
37 | (let ((recipe (cadr sexp))) | ||
38 | (if (consp recipe) | ||
39 | (car recipe) | ||
40 | recipe)))) | ||
41 | |||
42 | ;; Bind keys to `acdw/map' | ||
43 | (setup-define :acdw/map | ||
44 | (lambda (key command) | ||
45 | `(define-key acdw/map | ||
46 | ,(if (stringp key) (kbd key) key) | ||
47 | #',command)) | ||
48 | :documentation "Bind KEY to COMMAND in `acdw/map'." | ||
49 | :debug '(form sexp) | ||
50 | :repeatable t) | ||
51 | |||
52 | ;; Bind keys to `acdw/leader' | ||
53 | (setup-define :acdw/leader | ||
54 | (lambda (key command) | ||
55 | `(define-key acdw/leader | ||
56 | ,(if (stringp key) (kbd key) key) | ||
57 | #',command)) | ||
58 | :documentation "Bind KEY to COMMAND in `acdw/leader' map." | ||
59 | :debug '(form sexp) | ||
60 | :repeatable t) | ||
61 | |||
62 | ;; Bind keys, and autoload the functions they're bound to. | ||
63 | (setup-define :bind-autoload | ||
64 | (lambda (key command) | ||
65 | `(progn | ||
66 | (autoload #',command (symbol-name setup-name)) | ||
67 | (define-key (symbol-value setup-map) | ||
68 | ,(if (stringp key) (kbd key) key) | ||
69 | #',command))) | ||
70 | :documentation "Bind KEY to COMMAND, and autload COMMAND from FEATURE." | ||
71 | :debug '(form sexp) | ||
72 | :repeatable t) | ||
73 | |||
19 | ;;; About me | 74 | ;;; About me |
20 | (acdw/set | 75 | (setc user-full-name "Case Duckworth" |
21 | '((user-full-name "Case Duckworth") | 76 | user-mail-address "acdw@acdw.net" |
22 | (user-mail-address "acdw@acdw.net") | 77 | calendar-location-name "Baton Rouge, LA" |
23 | (calendar-location-name "Baton Rouge, LA") | 78 | calendar-latitude 30.4 |
24 | (calendar-latitude 30.4) | 79 | calendar-longitude -91.1) |
25 | (calendar-longitude -91.1) | ||
26 | (calendar-date-style iso))) | ||
27 | 80 | ||
28 | ;;; Good defaults | 81 | ;;; Good defaults |
29 | 82 | ||
30 | ;; Lines | 83 | ;; Lines |
31 | (acdw/set '((fill-column 80))) | 84 | (setc fill-column 80 |
32 | (global-display-fill-column-indicator-mode +1) | 85 | word-wrap t |
86 | truncate-lines nil) | ||
33 | (add-hook 'text-mode-hook #'turn-on-auto-fill) | 87 | (add-hook 'text-mode-hook #'turn-on-auto-fill) |
34 | (add-hook 'prog-mode-hook #'turn-on-auto-fill) | 88 | (add-hook 'prog-mode-hook #'turn-on-auto-fill) |
89 | (global-display-fill-column-indicator-mode +1) | ||
35 | (global-so-long-mode +1) | 90 | (global-so-long-mode +1) |
36 | 91 | ||
37 | ;; I don't want `visual-line-mode', because I really only want to wrap and | ||
38 | ;; truncate lines. Believe me, I know what I'm doing. | ||
39 | (acdw/set '((word-wrap t) | ||
40 | (truncate-lines nil))) | ||
41 | |||
42 | ;; Whitespace | 92 | ;; Whitespace |
43 | (acdw/set '((whitespace-style | 93 | (setc whitespace-style |
44 | (empty indentation space-before-tab space-after-tab)) | 94 | '(empty indentation space-before-tab space-after-tab) |
45 | (indent-tabs-mode nil "We've lost this battle...") | 95 | indent-tabs-mode nil |
46 | (tab-width 4))) | 96 | tab-width 4 |
97 | smie-indent-basic tab-width) | ||
47 | (add-hook 'before-save-hook #'whitespace-cleanup) | 98 | (add-hook 'before-save-hook #'whitespace-cleanup) |
48 | 99 | ||
49 | ;; Pairs | 100 | ;; Pairs |
50 | (add-hook 'prog-mode-hook #'electric-pair-local-mode) | 101 | (setc show-paren-delay 0 |
51 | (acdw/set '((show-paren-delay 0) | 102 | show-paren-style 'mixed |
52 | (show-paren-style mixed) | 103 | show-paren-when-point-inside-paren t |
53 | (show-paren-when-point-inside-paren t) | 104 | show-paren-when-point-in-periphery t) |
54 | (show-paren-when-point-in-periphery t))) | ||
55 | (show-paren-mode +1) | 105 | (show-paren-mode +1) |
106 | (add-hook 'prog-mode-hook #'electric-pair-local-mode) | ||
56 | 107 | ||
57 | ;; Killing & Yanking | 108 | ;; Killing and yanking |
109 | (setc save-interprogram-paste-before-kill t | ||
110 | yank-pop-change-selection t | ||
111 | x-select-enable-clipboard t | ||
112 | x-select-enable-primary t | ||
113 | mouse-drag-copy-region t | ||
114 | kill-do-not-save-duplicates t) | ||
58 | (delete-selection-mode +1) | 115 | (delete-selection-mode +1) |
59 | (acdw/set '((save-interprogram-paste-before-kill t) | ||
60 | (yank-pop-change-selection t) | ||
61 | (x-select-enable-clipboard t) | ||
62 | (x-select-enable-primary t) | ||
63 | (mouse-drag-copy-region t) | ||
64 | (kill-do-not-save-duplicates t))) | ||
65 | 116 | ||
66 | ;; Encoding | 117 | ;; Encoding |
118 | (setc local-coding-system 'utf-8-unix | ||
119 | coding-system-for-read 'utf-8-unix | ||
120 | coding-system-for-write 'utf-8-unix | ||
121 | buffer-file-coding-system 'utf-8-unix | ||
122 | org-export-coding-system 'utf-8-unix | ||
123 | org-html-coding-system 'utf-8-unix | ||
124 | default-process-coding-system '(utf-8-unix . utf-8-unix) | ||
125 | x-select-request-type '(UTF8_STRING COMPOUND_TEXT TEXT STRING)) | ||
67 | (set-charset-priority 'unicode) | 126 | (set-charset-priority 'unicode) |
68 | (set-language-environment "UTF-8") | 127 | (set-language-environment "UTF-8") |
69 | (prefer-coding-system 'utf-8-unix) | 128 | (prefer-coding-system 'utf-8-unix) |
@@ -71,453 +130,387 @@ | |||
71 | (set-terminal-coding-system 'utf-8-unix) | 130 | (set-terminal-coding-system 'utf-8-unix) |
72 | (set-keyboard-coding-system 'utf-8-unix) | 131 | (set-keyboard-coding-system 'utf-8-unix) |
73 | (set-selection-coding-system 'utf-8-unix) | 132 | (set-selection-coding-system 'utf-8-unix) |
74 | (acdw/set '((locale-coding-system utf-8-unix) | 133 | |
75 | (coding-system-for-read utf-8-unix) | 134 | ;; Uniquify |
76 | (coding-system-for-write utf-8-unix) | 135 | (setup (:require uniquify) |
77 | (buffer-file-coding-system utf-8-unix) | 136 | (:option uniquify-buffer-name-style 'forward |
78 | (org-export-coding-system utf-8-unix) | 137 | uniquify-separator path-separator |
79 | (org-html-coding-system utf-8-unix) | 138 | uniquify-after-kill-buffer-p t |
80 | (default-process-coding-system (utf-8-unix . utf-8-unix)) | 139 | uniquify-ignore-buffers-re "^\\*")) |
81 | (x-select-request-type (UTF8_STRING COMPOUND_TEXT TEXT STRING)))) | 140 | |
82 | 141 | ;; Files | |
83 | ;; Unique buffer names | 142 | (setc backup-directory-alist `((".*" . ,(acdw/in-dir "backup/" t))) |
84 | (when (require 'uniquify) | 143 | tramp-backup-directory-alist backup-directory-alist |
85 | (acdw/set '((uniquify-buffer-name-style forward) | 144 | auto-save-file-name-transforms `((".*" ,(acdw/in-dir "auto-save/" t) t)) |
86 | (uniquify-separator "/") | 145 | auto-save-list-file-prefix (acdw/in-dir "auto-save-list/.saves-" t) |
87 | (uniquify-after-kill-buffer-p t) | 146 | backup-by-copying t |
88 | (uniquify-ignore-buffers-re "^\\*")))) | 147 | delete-old-versions t |
89 | 148 | version-control t | |
90 | ;; Backups | 149 | vc-make-backup-files t) |
91 | (acdw/set `((backup-by-copying t) | ||
92 | (delete-old-versions -1) | ||
93 | (version-control t) | ||
94 | (vc-make-backup-files t) | ||
95 | (backup-directory-alist ((".*" . ,(acdw/in-dir "backup/" t)))))) | ||
96 | ;; Autosaves | ||
97 | (acdw/set `((auto-save-file-name-transforms | ||
98 | ((".*" ,(acdw/in-dir "auto-save/" t) t))) | ||
99 | (auto-save-list-file-prefix | ||
100 | ,(acdw/in-dir "auto-save-list/.saves-" t)))) | ||
101 | (auto-save-visited-mode +1) | 150 | (auto-save-visited-mode +1) |
102 | 151 | ||
103 | (defun hook--auto-save-when-unfocused () | ||
104 | "Save all buffers when out of focus." | ||
105 | (acdw/when-unfocused #'save-some-buffers t)) | ||
106 | (add-function :after after-focus-change-function | 152 | (add-function :after after-focus-change-function |
107 | #'hook--auto-save-when-unfocused) | 153 | (defun hook--auto-save-when-unfocused () |
108 | 154 | "Save all buffers when out of focus." | |
109 | ;; Auto-revert | 155 | (acdw/when-unfocused #'save-some-buffers t))) |
110 | (when (require 'autorevert) | 156 | |
111 | (global-auto-revert-mode +1)) | 157 | (setup (:require autorevert) |
112 | ;; Save place | 158 | (global-auto-revert-mode +1)) |
113 | (when (require 'saveplace) | 159 | |
114 | (acdw/set | 160 | (setup (:require saveplace) |
115 | `((save-place-file ,(acdw/in-dir "places.el")) | 161 | (:option save-place-file (acdw/in-dir "places.el") |
116 | (save-place-forget-unreadable-files ,(eq acdw/system :home)))) | 162 | save-place-forget-unreadable-files (eq acdw/system :home)) |
117 | (save-place-mode +1)) | 163 | (save-place-mode +1)) |
118 | ;; Recent files | 164 | |
119 | (when (require 'recentf) | 165 | (setup (:require recentf) |
120 | (acdw/set | 166 | (:option recentf-save-file (acdw/in-dir "recentf.el") |
121 | `((recentf-save-file ,(acdw/in-dir "recentf.el")) | 167 | recentf-max-menu-items 100 |
122 | (recentf-max-menu-items 100) | 168 | recentf-max-saved-items nil |
123 | (recentf-max-saved-items nil) | 169 | recentf-auto-cleanup 60 |
124 | (recentf-auto-cleanup 60 "Cleanup the recentf list when idle for 60s."))) | 170 | (append recentf-exclude) acdw/dir) |
125 | (add-to-list 'recentf-exclude acdw/dir) | ||
126 | (recentf-mode +1)) | 171 | (recentf-mode +1)) |
127 | 172 | ||
128 | ;; Move the custom file | 173 | ;; Minibuffer |
129 | (acdw/set `((custom-file ,(acdw/in-dir "custom.el")))) | 174 | (setc minibuffer-prompt-properties |
175 | '(read-only t | ||
176 | cursor-intangible t | ||
177 | face minibuffer-prompt) | ||
178 | enable-recursive-minibuffers t | ||
179 | file-name-shadow-properties '(invisible t intangible t) | ||
180 | read-answer-short t) | ||
181 | (minibuffer-depth-indicate-mode +1) | ||
182 | (file-name-shadow-mode +1) | ||
183 | (fset 'yes-or-no-p #'y-or-n-p) | ||
184 | |||
185 | (setup (:require savehist) | ||
186 | (:option (append savehist-additional-variables) 'kill-ring | ||
187 | (append savehist-additional-variables) 'search-ring | ||
188 | (append savehist-additional-variables) 'regexp-search-ring | ||
189 | history-length t | ||
190 | history-delete-duplicates t | ||
191 | savehist-autosave-interval 6 | ||
192 | savehist-file (acdw/in-dir "savehist.el")) | ||
193 | (savehist-mode +1)) | ||
130 | 194 | ||
131 | ;; Cursor | 195 | (setup (:require icomplete) |
132 | (acdw/set '((cursor-type bar) | 196 | (:option completion-ignore-case t |
133 | (cursor-in-non-selected-windows hollow))) | 197 | read-buffer-completion-ignore-case t |
198 | icomplete-delay-completions-threshold 0 | ||
199 | icomplete-max-delay-chars 0 | ||
200 | icomplete-compute-delay 0 | ||
201 | icomplete-show-matches-on-no-input t | ||
202 | icomplete-with-buffer-completion-tables t | ||
203 | icomplete-in-buffer t | ||
204 | completion-styles '(partial-completion substring flex)) | ||
205 | (fido-mode -1) | ||
206 | (icomplete-mode +1)) | ||
207 | |||
208 | (setup imenu | ||
209 | (:option imenu-auto-rescan t)) | ||
134 | 210 | ||
135 | ;; (defun hook--overwrite-mode-change-cursor () | 211 | ;; Cursor |
136 | ;; (setq cursor-type (if overwrite-mode 'hbar 'bar))) | 212 | (setc cursor-type 'bar |
137 | ;; (add-hook 'overwrite-mode-hook #'hook--overwrite-mode-change-cursor) | 213 | cursor-in-non-selected-windows 'hollow) |
138 | 214 | ||
139 | ;; Scrolling | 215 | ;; Scrolling |
140 | (acdw/set '((auto-window-vscroll nil) | 216 | (setc auto-window-vscroll nil |
141 | (fast-but-imprecise-scrolling t) | 217 | fast-but-imprecise-scrolling t |
142 | (scroll-margin 0) | 218 | scroll-margin 0 |
143 | (scroll-conservatively 101) | 219 | scroll-conservatively 101 |
144 | (scroll-preserve-screen-position 1))) | 220 | scroll-preserve-screen-position 1) |
145 | 221 | ||
146 | ;; Bindings | 222 | ;; MS Windows |
147 | (acdw/binds (("C-h" ehelp-command :after ("ehelp" nil nil 'keymap)) | 223 | (setc w32-allow-system-shell t |
148 | ([remap just-one-space] cycle-spacing) | 224 | w32-pass-lwindow-to-system nil |
149 | ("M-/" hippie-expand) | 225 | w32-lwindow-modifier 'super |
150 | ("M-=" count-words) | 226 | w32-pass-rwindow-to-system nil |
151 | ("C-x C-b" ibuffer))) | 227 | w32-rwindow-modifier 'super |
152 | 228 | w32-pass-apps-to-system nil | |
153 | ;;; Startup | 229 | w32-apps-modifier 'hyper) |
154 | (acdw/set `((inhibit-startup-screen t) | 230 | |
155 | (initial-buffer-choice t) | 231 | ;; Dired |
156 | (initial-scratch-message | 232 | (setup dired |
157 | ,(concat ";; Howdy, " | 233 | (:option dired-recursive-copies 'always |
158 | (nth 0 (split-string user-full-name)) "!" | 234 | dired-recursive-deletes 'always |
159 | " Welcome to GNU Emacs.\n\n")))) | 235 | delete-by-moving-to-trash t |
160 | 236 | dired-listing-switches "-Al" | |
161 | ;;; Windows settings | 237 | ls-lisp-dirs-first t |
162 | (when (eq acdw/system :work) | 238 | dired-ls-F-marks-symlinks t |
163 | (acdw/set `((w32-allow-system-shell t) | 239 | dired-no-confirm '(byte-compile |
164 | (w32-pass-lwindow-to-system nil) | 240 | chgrp chmod chown copy |
165 | (w32-lwindow-modifier 'super) | 241 | hardlink load move |
166 | (w32-pass-rwindow-to-system nil) | 242 | shell touch symlink) |
167 | (w32-rwindow-modifier 'super) | 243 | dired-dwim-target t) |
168 | (w32-pass-apps-to-system nil) | 244 | (:also-load dired-x) |
169 | (w32-apps-modifier 'hyper)))) | 245 | (:hook dired-hide-details-mode |
246 | hl-line-mode) | ||
247 | (:acdw/map "C-x C-j" dired-jump)) | ||
248 | |||
249 | ;; Eshell | ||
250 | (setup eshell | ||
251 | (:option eshell-directory-name (acdw/in-dir "eshell/" t) | ||
252 | eshell-aliases-file (acdw/in-dir "eshell/aliases" t))) | ||
170 | 253 | ||
171 | (acdw/set '((default-directory (expand-file-name "~/")))) | 254 | ;; Garbage collection |
255 | (add-hook 'minibuffer-setup-hook #'acdw/gc-disable) | ||
256 | (add-hook 'minibuffer-exit-hook #'acdw/gc-enable) | ||
257 | (add-function :after after-focus-change-function | ||
258 | (defun hook--gc-when-unfocused () | ||
259 | (acdw/when-unfocused #'garbage-collect))) | ||
260 | |||
261 | ;; Etc. good defaults | ||
262 | (setc custom-file (acdw/in-dir "custom.el") | ||
263 | inhibit-startup-screen t | ||
264 | initial-buffer-choice t | ||
265 | initial-scratch-message (concat ";; Howdy, " (nth 0 (split-string | ||
266 | user-full-name)) | ||
267 | "! Welcome to GNU Emacs.\n\n") | ||
268 | default-directory (expand-file-name "~/") | ||
269 | disabled-command-function nil | ||
270 | load-prefer-newer t | ||
271 | comp-async-report-warnings-errors nil | ||
272 | frame-title-format "%b %+%* GNU Emacs") | ||
273 | |||
274 | ;; Etc. bindings | ||
275 | (autoload 'ehelp-command "ehelp" nil nil 'keymap) | ||
276 | (define-key acdw/map (kbd "C-h") 'ehelp-command) | ||
277 | (define-key acdw/map [remap just-one-space] #'cycle-spacing) | ||
278 | (define-key acdw/map (kbd "M-/") #'hippie-expand) | ||
279 | (define-key acdw/map (kbd "M-=") #'count-words) | ||
280 | (define-key acdw/map (kbd "C-x C-b") #'ibuffer) | ||
281 | |||
282 | ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; | ||
283 | ;;; Here ends the package-less configuration. Everything following requires a | ||
284 | ;;; package to be downloaded. ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; | ||
285 | ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; | ||
286 | |||
287 | ;;; Interactivity | ||
288 | |||
289 | |||
290 | ;;;; Begin-end | ||
291 | (setup (:straight beginend) | ||
292 | (beginend-global-mode +1)) | ||
293 | |||
294 | ;;;; Expand-region | ||
295 | (setup (:straight expand-region) | ||
296 | (:acdw/map "C-=" er/expand-region)) | ||
297 | |||
298 | ;;;; CRUX | ||
299 | (setup (:straight crux) | ||
300 | (:with-map acdw/map | ||
301 | (:bind "M-o" crux-other-window-or-switch-buffer) | ||
302 | (:bind "C-a" crux-move-beginning-of-line) | ||
303 | (:bind "C-k" crux-kill-and-join-forward)) | ||
304 | (crux-reopen-as-root-mode +1)) | ||
305 | |||
306 | ;;; Functionality | ||
307 | |||
308 | ;;;; Undo-fu | ||
309 | (setup (:straight undo-fu) | ||
310 | (:with-map acdw/map | ||
311 | (:bind "C-/" undo-fu-only-undo | ||
312 | "C-?" undo-fu-only-redo))) | ||
313 | |||
314 | (setup (:straight undo-fu-session) | ||
315 | (:option undo-fu-session-incompatible-files '("/COMMIT_EDITMSG\\'" | ||
316 | "/git-rebase-todo\\'") | ||
317 | undo-fu-session-directory (acdw/in-dir "undo/" t)) | ||
318 | (global-undo-fu-session-mode +1)) | ||
172 | 319 | ||
173 | ;;; Minibuffer | 320 | ;;; Minibuffer |
174 | 321 | ||
175 | (acdw/set '((minibuffer-prompt-properties (read-only t | 322 | ;;;; Icomplete-vertical |
176 | cursor-intangible t | 323 | (setup (:straight icomplete-vertical) |
177 | face minibuffer-prompt)) | 324 | (let ((map icomplete-minibuffer-map)) |
178 | (enable-recursive-minibuffers t) | 325 | (let ((command #'icomplete-forward-completions)) |
179 | (file-name-shadow-properties (invisible t)))) | 326 | (define-key map (kbd "<down>") command) |
180 | (minibuffer-depth-indicate-mode +1) | 327 | (define-key map (kbd "C-n") command)) |
181 | (file-name-shadow-mode +1) | 328 | (let ((command #'icomplete-backward-completions)) |
182 | 329 | (define-key map (kbd "<up>") command) | |
183 | (acdw/pkg recursion-indicator | 330 | (define-key map (kbd "C-p") command)) |
184 | :set '((recursion-indicator-general "%") | 331 | (define-key map (kbd "RET") #'icomplete-force-complete-and-exit) |
185 | (recursion-indicator-minibuffer "@")) | 332 | (define-key map (kbd "C-RET") #'minibuffer-complete-and-exit)) |
186 | :now ((recursion-indicator-mode +1))) | 333 | (icomplete-vertical-mode +1)) |
187 | 334 | ||
188 | ;; Save history | 335 | ;;;; Orderless |
189 | (when (require 'savehist) | 336 | (setup (:straight orderless) |
190 | (acdw/set `((savehist-additional-variables | 337 | (:option (prepend completion-styles) 'orderless)) |
191 | (kill-ring search-ring regexp-search-ring)) | 338 | |
192 | (history-length t) | 339 | ;;;; Consult |
193 | (history-delete-duplicates t) | 340 | (setup (:straight consult) |
194 | (savehist-autosave-interval 6) | 341 | (:with-map acdw/map |
195 | (savehist-file ,(acdw/in-dir "savehist.el")))) | 342 | (:bind-autoload |
196 | (savehist-mode +1)) | 343 | ;; C-c bindings (`mode-specific-map') |
197 | 344 | "C-c h" consult-history | |
198 | ;; God mode | 345 | "C-c m" consult-mode-command |
199 | (acdw/pkg god-mode | 346 | ;; C-x bindings (`ctl-x-map') |
200 | :binds (("<escape>" god-local-mode) | 347 | "C-x M-:" consult-complex-command |
201 | ("i" god-local-mode :map god-local-mode-map) | 348 | "C-x b" consult-buffer |
202 | ("." repeat :map god-local-mode-map) | 349 | "C-x 4 b" consult-buffer-other-window |
203 | ("C-x C-1" delete-other-windows) | 350 | "C-x 5 b" consult-buffer-other-frame |
204 | ("C-x C-2" split-window-below) | 351 | "C-x r x" consult-register |
205 | ("C-x C-3" split-window-right) | 352 | "C-x r b" consult-bookmark |
206 | ("C-x C-0" delete-window)) | 353 | ;; M-g bindings (`goto-map') |
207 | :now ((defun acdw/god-mode-update-cursor () | 354 | "M-g o" consult-outline |
208 | (setq cursor-type (if (or god-local-mode buffer-read-only) | 355 | "M-g m" consult-mark |
209 | 'box | 356 | "M-g k" consult-global-mark |
210 | 'bar))) | 357 | "M-g i" consult-imenu |
211 | (defun acdw/god-mode-toggle-on-overwrite () | 358 | "M-g e" consult-error |
212 | (if (bound-and-true-p overwrite-mode) | 359 | ;; M-s bindings (`search-map') |
213 | (progn | 360 | "M-s g" consult-grep ; alts: consult-git-grep, consult-ripgrep |
214 | (setq cursor-type 'hbar) | 361 | "M-s f" consult-find ; alts: consult-locate |
215 | (god-local-mode-pause)) | 362 | "M-s l" consult-line |
216 | (god-local-mode-resume) | 363 | "M-s m" consult-multi-occur |
217 | (acdw/god-mode-update-cursor))) | 364 | "M-s k" consult-keep-lines |
218 | (require 'god-mode) | 365 | "M-s u" consult-focus-lines |
219 | (god-mode)) | 366 | ;; Other bindings |
220 | :hooks (((god-mode-enabled-hook god-mode-disabled-hook) | 367 | "M-y" consult-yank-pop |
221 | acdw/god-mode-update-cursor) | 368 | "<f1> a" consult-apropos |
222 | (overwrite-mode-hook acdw/god-mode-toggle-on-overwrite))) | 369 | "C-h a" consult-apropos)) |
223 | 370 | (autoload 'consult-register-preview "consult") | |
224 | ;; Icomplete (-vertical) | 371 | (:option register-preview-delay 0 |
225 | (when (require 'icomplete) | 372 | register-preview-function #'consult-register-preview)) |
226 | (acdw/set '((completion-ignore-case t) | 373 | |
227 | (read-buffer-completion-ignore-case t) | 374 | ;;;; Marginalia |
228 | (icomplete-delay-completions-threshold 0) | 375 | (setup (:straight marginalia) |
229 | (icomplete-max-delay-chars 0) | 376 | (:option marginalia-annotators '(marginalia-annotators-heavy |
230 | (icomplete-compute-delay 0) | 377 | marginalia-annotators-light)) |
231 | (icomplete-show-matches-on-no-input t) | 378 | (marginalia-mode +1)) |
232 | (icomplete-with-buffer-completion-tables t) | 379 | |
233 | (icomplete-in-buffer t))) | 380 | ;;; UI |
234 | (acdw/pkg orderless | 381 | |
235 | :set '((completion-styles (orderless)))) | 382 | ;;;; Modus themes |
236 | (acdw/pkg icomplete-vertical | 383 | (setup (:straight (modus-themes |
237 | :binds (("<down>" icomplete-forward-completions | 384 | :host gitlab |
238 | :map icomplete-minibuffer-map) | 385 | :repo "protesilaos/modus-themes")) |
239 | ("C-n" icomplete-forward-completions | 386 | (:option modus-themes-slanted-constructs t |
240 | :map icomplete-minibuffer-map) | 387 | modus-themes-bold-constructs t |
241 | ("<up>" icomplete-backward-completions | 388 | modus-themes-region 'bg-only |
242 | :map icomplete-minibuffer-map) | 389 | modus-themes-org-blocks 'grayscale |
243 | ("C-p" icomplete-backward-completions | 390 | modus-themes-headings '((1 . section) |
244 | :map icomplete-minibuffer-map) | 391 | (t . no-color)) |
245 | ("C-v" icomplete-vertical-toggle | 392 | modus-themes-mode-line nil) |
246 | :map icomplete-minibuffer-map) | 393 | (acdw/sunrise-sunset #'modus-themes-load-operandi |
247 | ("RET" icomplete-force-complete-and-exit | 394 | #'modus-themes-load-vivendi)) |
248 | :map icomplete-minibuffer-map) | 395 | |
249 | ("C-j" minibuffer-complete-and-exit | 396 | ;;;; Mode line |
250 | :map icomplete-minibuffer-map)) | 397 | (setup (:straight simple-modeline) |
251 | :now ((fido-mode -1) | 398 | (setup (:straight minions)) |
252 | (icomplete-mode +1) | 399 | (:option simple-modeline-segments |
253 | (icomplete-vertical-mode +1)))) | 400 | '((acdw-modeline/modified |
254 | 401 | acdw-modeline/buffer-name | |
255 | ;; Consult | 402 | acdw-modeline/vc-branch |
256 | (acdw/pkg consult | 403 | simple-modeline-segment-position |
257 | :binds (;; C-c bindings (`mode-specific-map') | 404 | simple-modeline-segment-word-count) |
258 | ("C-c h" consult-history) | 405 | (simple-modeline-segment-misc-info |
259 | ("C-c m" consult-mode-command) | 406 | simple-modeline-segment-process |
260 | ;; C-x bindings (`ctl-x-map') | 407 | acdw-modeline/god-mode-indicator |
261 | ("C-x M-:" consult-complex-command) | 408 | acdw-modeline/minions |
262 | ("C-x b" consult-buffer) | 409 | simple-modeline-segment-major-mode))) |
263 | ("C-x 4 b" consult-buffer-other-window) | 410 | (require 'acdw-modeline) |
264 | ("C-x 5 b" consult-buffer-other-frame) | 411 | (simple-modeline-mode +1)) |
265 | ("C-x r x" consult-register) | 412 | |
266 | ("C-x r b" consult-bookmark) | 413 | ;;; Utilities |
267 | ;; M-g bindings (`goto-map') | 414 | |
268 | ("M-g o" consult-outline) | 415 | ;;;; 0x0 -- upload files to a nullpointer |
269 | ("M-g m" consult-mark) | 416 | (setup (:straight (0x0 :host nil |
270 | ("M-g k" consult-global-mark) | 417 | :repo "https://git.sr.ht/~zge/nullpointer-emacs")) |
271 | ("M-g i" consult-imenu) | 418 | (:option 0x0-default-host 'ttm)) |
272 | ("M-g e" consult-error) | 419 | |
273 | ;; M-s bindings (`search-map') | 420 | ;;; Applications |
274 | ("M-s g" consult-grep) ; alts: | 421 | |
275 | ; consult-git-grep, | 422 | ;;;; Magit |
276 | ; consult-ripgrep | 423 | (setup (:straight magit) |
277 | ("M-s f" consult-find) ; alts: | 424 | (:acdw/leader "g" magit-status) |
278 | ; consult-locate | 425 | (:option magit-display-buffer-function |
279 | ("M-s l" consult-line) | 426 | (defun magit-display-buffer-same-window (buffer) |
280 | ("M-s m" consult-multi-occur) | ||
281 | ("M-s k" consult-keep-lines) | ||
282 | ("M-s u" consult-focus-lines) | ||
283 | ;; Other bindings | ||
284 | ("M-y" consult-yank-pop) | ||
285 | ("<f1> a" consult-apropos) | ||
286 | ("C-h a" consult-apropos)) | ||
287 | :now ((autoload 'consult-register-preview "consult")) | ||
288 | :set '((register-preview-delay 0) | ||
289 | (register-preview-function #'consult-register-preview))) | ||
290 | |||
291 | ;; begin-end | ||
292 | (acdw/pkg beginend | ||
293 | :now ((beginend-global-mode))) | ||
294 | |||
295 | ;; Marginalia | ||
296 | (acdw/pkg marginalia | ||
297 | :set '((marginalia-annotators (marginalia-annotators-heavy | ||
298 | marginalia-annotators-light))) | ||
299 | :now ((marginalia-mode +1))) | ||
300 | |||
301 | ;; Imenu | ||
302 | (when (require 'imenu) | ||
303 | (acdw/set '((imenu-auto-rescan t)))) | ||
304 | |||
305 | ;; Fonts | ||
306 | (acdw/set-faces ((fixed-pitch . ((t (:inherit default)))))) | ||
307 | |||
308 | ;;; Packages | ||
309 | |||
310 | ;; Undo-fu | ||
311 | (acdw/pkg undo-fu | ||
312 | :binds (("C-/" undo-fu-only-undo) | ||
313 | ("C-?" undo-fu-only-redo))) | ||
314 | (acdw/pkg undo-fu-session | ||
315 | :set `((undo-fu-session-incompatible-files ("/COMMIT_EDITMSG\\'" | ||
316 | "/git-rebase-todo\\'")) | ||
317 | (undo-fu-session-directory ,(acdw/in-dir "undo/" t))) | ||
318 | :then ((global-undo-fu-session-mode +1))) | ||
319 | |||
320 | ;; Modus themes | ||
321 | (acdw/pkg (modus-themes | ||
322 | :host gitlab | ||
323 | :repo "protesilaos/modus-themes") | ||
324 | :set `((modus-themes-slanted-constructs t) | ||
325 | (modus-themes-bold-constructs t) | ||
326 | (modus-themes-region 'bg-only) | ||
327 | (modus-themes-org-blocks 'grayscale) | ||
328 | (modus-themes-headings ((1 . section) | ||
329 | (t . no-color))) | ||
330 | (modus-themes-scale-headings nil) | ||
331 | (modus-themes-mode-line nil)) | ||
332 | :now ((acdw/sunrise-sunset #'modus-themes-load-operandi | ||
333 | #'modus-themes-load-vivendi))) | ||
334 | |||
335 | ;; Expand-region | ||
336 | (acdw/pkg expand-region | ||
337 | :binds (("C-=" er/expand-region))) | ||
338 | |||
339 | ;; CRUX | ||
340 | (acdw/pkg crux | ||
341 | :binds (("M-o" crux-other-window-or-switch-buffer) | ||
342 | ([remap move-beginning-of-line] crux-move-beginning-of-line) | ||
343 | ([remap kill-line] crux-kill-and-join-forward))) | ||
344 | ;;; Frame title | ||
345 | |||
346 | (acdw/set `((frame-title-format | ||
347 | "%b %+%* GNU Emacs"))) | ||
348 | |||
349 | ;;; Mode line | ||
350 | |||
351 | ;; Minions | ||
352 | (acdw/pkg minions) | ||
353 | |||
354 | ;; Simple mode line | ||
355 | (acdw/pkg simple-modeline | ||
356 | :set '((simple-modeline-segments | ||
357 | ((;; left | ||
358 | acdw-modeline/modified | ||
359 | acdw-modeline/buffer-name | ||
360 | acdw-modeline/vc-branch | ||
361 | simple-modeline-segment-position | ||
362 | simple-modeline-segment-word-count) | ||
363 | (;; right | ||
364 | simple-modeline-segment-misc-info | ||
365 | simple-modeline-segment-process | ||
366 | acdw-modeline/god-mode-indicator | ||
367 | acdw-modeline/minions | ||
368 | simple-modeline-segment-major-mode)))) | ||
369 | :now ((require 'acdw-modeline) | ||
370 | (simple-modeline-mode +1))) | ||
371 | |||
372 | ;;; Magit | ||
373 | |||
374 | (acdw/pkg magit | ||
375 | :binds (("g" magit-status :map acdw/leader)) | ||
376 | :set `((magit-display-buffer-function | ||
377 | ,(defun magit-display-buffer-same-window (buffer) | ||
378 | "Display BUFFER in the selected window like God intended." | 427 | "Display BUFFER in the selected window like God intended." |
379 | (display-buffer buffer | 428 | (display-buffer buffer '(display-buffer-same-window))) |
380 | '(display-buffer-same-window)))) | 429 | magit-popup-display-buffer-action '((display-buffer-same-window)))) |
381 | (magit-popup-display-buffer-action | ||
382 | ((display-buffer-same-window))))) | ||
383 | 430 | ||
384 | ;;; Web browsing | 431 | ;;;; File browsing |
432 | (setup (:straight dired-subtree) | ||
433 | (define-key dired-mode-map "i" #'dired-subtree-toggle)) | ||
385 | 434 | ||
386 | (acdw/set '((browse-url-browser-function browse-url-firefox) | 435 | (setup (:straight dired-collapse) |
387 | (browse-url-new-window-flag t) | 436 | (:hook-into dired-mode)) |
388 | (browse-url-firefox-new-window-is-tab t) | ||
389 | (shr-max-width fill-column) | ||
390 | (shr-width fill-column))) | ||
391 | 437 | ||
438 | ;;;; Web browsing | ||
392 | (when (eq acdw/system :work) | 439 | (when (eq acdw/system :work) |
393 | (add-to-list 'exec-path "C:/Program Files/Mozilla Firefox")) | 440 | (add-to-list 'exec-path "C:/Program Files/Mozilla Firefox")) |
394 | 441 | ||
395 | (acdw/hooks ((text-mode-hook goto-address-mode) | 442 | (setc browse-url-browser-function 'browse-url-firefox |
396 | (prog-mode-hook goto-address-prog-mode))) | 443 | browse-url-new-window-flag t |
397 | 444 | browse-url-firefox-new-window-is-tab t | |
398 | ;;; Gemini/gopher browsing | 445 | shr-max-width fill-column |
399 | 446 | shr-width fill-column) | |
400 | (acdw/pkg (elpher | 447 | |
401 | :repo "git://thelambdalab.xyz/elpher.git") | 448 | (add-hook 'text-mode-hook #'goto-address-mode) |
402 | :set '((elpher-ipv4-always t) | 449 | (add-hook 'prog-mode-hook #'goto-address-prog-mode) |
403 | (elpher-certificate-directory | 450 | |
404 | (acdw/in-var "elpher/"))) | 451 | ;;;; Gemini/gopher browsing |
405 | :now ((acdw/bind-after-map "elpher" elpher-mode-map | 452 | (setup (:straight (elpher :host nil |
406 | (("n" elpher-next-link :map-after "elpher") | 453 | :repo "git://thelambdalab.xyz/elpher.git")) |
407 | ("p" elpher-prev-link :map-after "elpher") | 454 | (:option elpher-ipv4-always t |
408 | ("o" elpher-follow-current-link :map-after "elpher") | 455 | elpher-certificate-directory (acdw/in-dir "elpher/")) |
409 | ("G" elpher-go-current :map-after "elpher"))) | 456 | (:bind "n" elpher-next-link |
410 | (when (boundp 'god-exempt-major-modes) | 457 | "p" elpher-prev-link |
411 | (add-to-list 'god-exempt-major-modes 'elpher-mode)))) | 458 | "o" elpher-follow-current-link |
412 | 459 | "G" elpher-go-current) | |
413 | (acdw/pkg (gemini-mode | 460 | (:hook acdw/reading-mode) |
414 | :repo "https://git.carcosa.net/jmcbray/gemini.el.git") | 461 | (when (boundp 'god-exempt-major-modes) |
415 | :now ((add-to-list 'auto-mode-alist | 462 | (:option (append god-exempt-major-modes) 'elpher-mode))) |
416 | '("\\.\\(gemini\\|gmi\\)\\'" . gemini-mode)))) | 463 | |
417 | 464 | (setup (:straight (gemini-mode | |
418 | ;;; Dired | 465 | :host nil |
419 | (acdw/pkg dired | 466 | :repo "https://git.carcosa.net/jmcbray/gemini.el.git")) |
420 | :local t | 467 | (:option (append auto-mode-alist) |
421 | :set `((dired-recursive-copies always) | 468 | '("\\.\\(gemini\\|gmi\\)\\'" . gemini-mode))) |
422 | (dired-recursive-deletes always) | 469 | |
423 | (delete-by-moving-to-trash t) | 470 | ;;;; Read e-books (nov.el) |
424 | (dired-listing-switches "-Al") | 471 | (setup (:straight nov) |
425 | (ls-lisp-dirs-first t) | 472 | (:option nov-text-width fill-column |
426 | (dired-dwim-target t)) | 473 | (append auto-mode-alist) '("\\.epub\\'" . nov-mode))) |
427 | :now ((autoload 'dired-mode-map "dired" nil nil 'keymap) | 474 | |
428 | (acdw/pkg dired-subtree) | 475 | ;;;; Org mode |
429 | (acdw/pkg dired-x | 476 | (setup (:straight (org :host nil |
430 | :local t | 477 | :repo "https://code.orgmode.org/bzg/org-mode.git")) |
431 | :binds (("C-x C-j" dired-jump))) | 478 | (require 'acdw-org) |
432 | (acdw/pkg dired-collapse | 479 | (:option org-directory "~/org" |
433 | :hooks ((dired-mode-hook dired-collapse-mode))) | 480 | org-hide-emphasis-markers t |
434 | (defun hook--dired-mode () | 481 | org-fontify-whole-heading-line t |
435 | (hl-line-mode +1) | 482 | org-fontify-done-headline t |
436 | (dired-hide-details-mode +1))) | 483 | org-fontify-quote-and-verse-blocks t |
437 | :hooks ((dired-mode-hook hook--dired-mode)) | 484 | org-src-fontify-natively t |
438 | :binds (("i" dired-subtree-toggle :map dired-mode-map))) | 485 | org-pretty-entities t |
439 | 486 | org-tags-column (- 0 fill-column -3) | |
440 | ;;; Eshell | 487 | org-src-tab-acts-natively t |
441 | 488 | org-src-window-setup 'current-window | |
442 | (acdw/set `((eshell-directory-name ,(acdw/in-dir "eshell/" t)) | 489 | org-confirm-babel-evaluate nil |
443 | (eshell-aliases-file ,(acdw/in-dir "eshell/aliases" t)))) | 490 | org-adapt-indentation nil |
444 | 491 | org-catch-invisible-edits 'smart | |
445 | ;;; Org-mode | 492 | org-special-ctrl-a/e t |
446 | (acdw/pkg (org | 493 | org-special-ctrl-k t |
447 | :repo "https://code.orgmode.org/bzg/org-mode.git") | 494 | org-imenu-depth 3 |
448 | :now ((require 'acdw-org)) | 495 | org-export-headline-levels 8 |
449 | :set `((org-directory "~/org") | 496 | org-export-with-smart-quotes t |
450 | (org-hide-emphasis-markers t) | 497 | org-export-with-sub-superscripts t) |
451 | (org-fontify-whole-heading-line t) | 498 | (:bind "RET" unpackaged/org-return-dwim) |
452 | (org-fontify-done-headline t) | 499 | (add-hook 'before-save-hook #'acdw/hook--org-mode-fix-blank-lines)) |
453 | (org-fontify-quote-and-verse-blocks t) | ||
454 | (org-src-fontify-natively t) | ||
455 | (org-pretty-entities t) | ||
456 | (org-tags-column ,(- 0 fill-column -3)) | ||
457 | (org-src-tab-acts-natively t) | ||
458 | (org-src-window-setup current-window) | ||
459 | (org-confirm-babel-evaluate nil) | ||
460 | (org-adapt-indentation nil) | ||
461 | (org-catch-invisible-edits smart) | ||
462 | (org-special-ctrl-a/e t) | ||
463 | (org-special-ctrl-k t) | ||
464 | (org-imenu-depth 3) | ||
465 | (org-export-headline-levels 8) | ||
466 | (org-export-with-smart-quotes t) | ||
467 | (org-export-with-sub-superscripts t)) | ||
468 | :hooks ((before-save-hook acdw/hook--org-mode-fix-blank-lines)) | ||
469 | :binds (("RET" unpackaged/org-return-dwim | ||
470 | :map org-mode-map :map-after 'org))) | ||
471 | |||
472 | ;;; Nov.el -- ebook reader | ||
473 | (acdw/pkg nov | ||
474 | :now ((autoload #'nov-mode "nov") | ||
475 | (add-to-list 'auto-mode-alist '("\\.epub\\'" . nov-mode))) | ||
476 | :set `((nov-text-width ,fill-column))) | ||
477 | |||
478 | ;;; 0x0 -- upload files | ||
479 | (acdw/pkg (0x0 :repo "https://git.sr.ht/~zge/nullpointer-emacs") | ||
480 | :set '((0x0-default-host ttm))) | ||
481 | 500 | ||
482 | ;;; Programming languages | 501 | ;;; Programming languages |
483 | 502 | ||
484 | ;; General | 503 | ;;;; Formatting |
485 | 504 | (setup (:straight (apheleia :host github | |
486 | (acdw/set `((smie-indent-basic ,tab-width))) | 505 | :repo "raxod502/apheleia")) |
487 | 506 | (apheleia-global-mode +1)) | |
488 | ;; Formatting | 507 | |
489 | 508 | ;;;; Emacs lisp | |
490 | (acdw/pkg (apheleia | 509 | (setup emacs-lisp |
491 | :host github | 510 | (require 'cl-lib) |
492 | :repo "raxod502/apheleia") | 511 | (:option eval-expression-print-length nil |
493 | :now ((apheleia-global-mode +1)) | 512 | eval-expression-print-level nil |
494 | :then ((add-to-list 'apheleia-formatters | 513 | lisp-indent-function #'common-lisp-indent-function) |
495 | '(shfmt . ("shfmt"))) | ||
496 | (add-to-list 'apheleia-mode-alist | ||
497 | '(sh-mode . shfmt)))) | ||
498 | |||
499 | ;; Shell(s) | ||
500 | (when (executable-find "shellcheck") | ||
501 | (acdw/pkg flymake-shellcheck | ||
502 | :hooks ((sh-mode-hook (flymake-mode | ||
503 | flymake-shellcheck-load))))) | ||
504 | |||
505 | (acdw/set `((sh-basic-offset ,tab-width) | ||
506 | (sh-indent-after-case 0) | ||
507 | (sh-indent-for-case-alt +) | ||
508 | (sh-indent-for-case-label 0))) | ||
509 | |||
510 | (defun hook--sh-mode-indent-like-shfmt () | ||
511 | "Try to mirror `shfmt' formatting in shell scripts." | ||
512 | (setq indent-tabs-mode t)) | ||
513 | (add-hook 'sh-mode-hook #'hook--sh-mode-indent-like-shfmt) | ||
514 | |||
515 | ;; Emacs lisp | ||
516 | (acdw/set '((eval-expression-print-length nil) | ||
517 | (eval-expression-print-level nil))) | ||
518 | |||
519 | (when (require 'cl-lib) | ||
520 | (setq-default lisp-indent-function #'common-lisp-indent-function) | ||
521 | (put 'cl-flet 'common-lisp-indent-function | 514 | (put 'cl-flet 'common-lisp-indent-function |
522 | (get 'flet 'common-lisp-indent-function)) | 515 | (get 'flet 'common-lisp-indent-function)) |
523 | (put 'cl-labels 'common-lisp-indent-function | 516 | (put 'cl-labels 'common-lisp-indent-function |
@@ -526,34 +519,36 @@ | |||
526 | (put 'dotimes-protect 'common-lisp-indent-function | 519 | (put 'dotimes-protect 'common-lisp-indent-function |
527 | (get 'when 'common-lisp-indent-function))) | 520 | (get 'when 'common-lisp-indent-function))) |
528 | 521 | ||
529 | ;; Racket | 522 | ;;;; Shell scripts |
530 | (acdw/pkg racket-mode) | 523 | (setup sh |
531 | 524 | (:option sh-basic-offset tab-width | |
532 | ;; Web stuff | 525 | sh-indent-after-case 0 |
533 | (acdw/set '((css-indent-offset 2) | 526 | sh-indent-for-case-alt '+ |
534 | (js-indent-level 2) | 527 | sh-indent-for-case-label 0) |
535 | (sgml-indent-offset 2))) | 528 | (:local-set indent-tabs-mode t) |
536 | 529 | ||
537 | ;;; Miscellaneous | 530 | (when (executable-find "shfmt") |
538 | 531 | (:option (append apheleia-formatters) '(shfmt . ("shfmt")) | |
539 | (acdw/set '((disabled-command-function nil) | 532 | (append apheleia-mode-alist) '(sh-mode . shfmt))) |
540 | (load-prefer-newer t) | 533 | |
541 | (comp-async-report-warnings-errors nil))) | 534 | (when (executable-find "shellcheck") |
542 | 535 | (straight-use-package 'flymake-shellcheck) | |
543 | (fset 'yes-or-no-p #'y-or-n-p) | 536 | (:hook flymake-mode |
544 | 537 | flymake-shellcheck-load))) | |
545 | ;; Garbage collection | 538 | |
546 | (defun hook--gc-cons-maximize () | 539 | ;;;; Web languages |
547 | (setq gc-cons-threshold most-positive-fixnum)) | 540 | (setup (:straight web-mode) |
548 | (add-hook 'minibuffer-setup-hook #'hook--gc-cons-maximize) | 541 | (:option css-level-offset 2 |
549 | 542 | js-indent-level 2 | |
550 | (defun hook--gc-cons-baseline () | 543 | sgml-indent-offset 2) |
551 | (setq gc-cons-threshold gc-cons-threshold-basis)) | 544 | (dolist (extension '("\\(p\\|dj\\)?html" |
552 | (add-hook 'minibuffer-exit-hook #'hook--gc-cons-baseline) | 545 | "html?" |
553 | 546 | "\\(tpl\\.\\)?php" | |
554 | (defun hook--gc-when-unfocused () | 547 | "[agj]sp" |
555 | (acdw/when-unfocused #'garbage-collect)) | 548 | "as[cp]x" |
556 | (add-function :after after-focus-change-function | 549 | "erb" |
557 | #'hook--gc-when-unfocused) | 550 | "mustache")) |
551 | (add-to-list 'auto-mode-alist | ||
552 | `(,(concat "\\." extension "\\'") . web-mode)))) | ||
558 | 553 | ||
559 | ;;; init.el ends here | 554 | ;;; 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 @@ | |||
22 | ;;; Utilities | 22 | ;;; Utilities |
23 | 23 | ||
24 | (defconst acdw/system (pcase system-type | 24 | (defconst acdw/system (pcase system-type |
25 | ('gnu/linux :home) | 25 | ('gnu/linux :home) |
26 | ((or 'msdos 'windows-nt) :work) | 26 | ((or 'msdos 'windows-nt) :work) |
27 | (_ :other)) | 27 | (_ :other)) |
28 | "Which system is currently being used.") | 28 | "Which system is currently being used.") |
29 | 29 | ||
30 | (defun acdw/when-unfocused (func &rest args) | 30 | (defun acdw/when-unfocused (func &rest args) |
@@ -37,220 +37,260 @@ Ready for use with `after-focus-change-function'." | |||
37 | (defun acdw/sunrise-sunset (sunrise-command sunset-command) | 37 | (defun acdw/sunrise-sunset (sunrise-command sunset-command) |
38 | "Run commands at sunrise and sunset." | 38 | "Run commands at sunrise and sunset." |
39 | (let* ((times-regex (rx (* nonl) | 39 | (let* ((times-regex (rx (* nonl) |
40 | (: (any ?s ?S) "unrise") " " | 40 | (: (any ?s ?S) "unrise") " " |
41 | (group (repeat 1 2 digit) ":" | 41 | (group (repeat 1 2 digit) ":" |
42 | (repeat 1 2 digit) | 42 | (repeat 1 2 digit) |
43 | (: (any ?a ?A ?p ?P) (any ?m ?M))) | 43 | (: (any ?a ?A ?p ?P) (any ?m ?M))) |
44 | (* nonl) | 44 | (* nonl) |
45 | (: (any ?s ?S) "unset") " " | 45 | (: (any ?s ?S) "unset") " " |
46 | (group (repeat 1 2 digit) ":" | 46 | (group (repeat 1 2 digit) ":" |
47 | (repeat 1 2 digit) | 47 | (repeat 1 2 digit) |
48 | (: (any ?a ?A ?p ?P) (any ?m ?M))) | 48 | (: (any ?a ?A ?p ?P) (any ?m ?M))) |
49 | (* nonl))) | 49 | (* nonl))) |
50 | (ss (sunrise-sunset)) | 50 | (ss (sunrise-sunset)) |
51 | (_m (string-match times-regex ss)) | 51 | (_m (string-match times-regex ss)) |
52 | (sunrise-time (match-string 1 ss)) | 52 | (sunrise-time (match-string 1 ss)) |
53 | (sunset-time (match-string 2 ss))) | 53 | (sunset-time (match-string 2 ss))) |
54 | (run-at-time sunrise-time (* 60 60 24) sunrise-command) | 54 | (run-at-time sunrise-time (* 60 60 24) sunrise-command) |
55 | (run-at-time sunset-time (* 60 60 24) sunset-command) | 55 | (run-at-time sunset-time (* 60 60 24) sunset-command) |
56 | (run-at-time "12:00am" (* 60 60 24) sunset-command))) | 56 | (run-at-time "12:00am" (* 60 60 24) sunset-command))) |
57 | 57 | ||
58 | ;;; Garbage collection hacks | ||
59 | |||
60 | (defconst acdw/gc-cons-threshold-basis (* 800 1024 1024) | ||
61 | "Basis value for `gc-cons-threshold' to return to after jumping. | ||
62 | 800 KB is Emacs's default.") | ||
63 | |||
64 | (defconst acdw/gc-cons-percentage-basis 0.1 | ||
65 | "Basis value for `gc-cons-percentage' to return to after jumping. | ||
66 | 0.1 is Emacs's default.") | ||
67 | |||
68 | (defun acdw/gc-disable () | ||
69 | "Disable garbage collection by setting relevant variables to their maxima." | ||
70 | (setq gc-cons-threshold most-positive-fixnum | ||
71 | gc-cons-percentage 0.8)) | ||
72 | |||
73 | (defun acdw/gc-enable () | ||
74 | "Re-enable garbage collection by setting relevant variables back to bases." | ||
75 | (setq gc-cons-threshold acdw/gc-cons-threshold-basis | ||
76 | gc-cons-percentage acdw/gc-cons-percentage-basis)) | ||
77 | |||
58 | ;;; Directories (think `no-littering') | 78 | ;;; Directories (think `no-littering') |
59 | 79 | ||
60 | (defvar acdw/dir (expand-file-name | 80 | (defvar acdw/dir (expand-file-name |
61 | (convert-standard-filename "var/") | 81 | (convert-standard-filename "var/") |
62 | user-emacs-directory) | 82 | user-emacs-directory) |
63 | "A directory to hold extra configuration and emacs data.") | 83 | "A directory to hold extra configuration and emacs data.") |
64 | 84 | ||
65 | (defun acdw/in-dir (file &optional make-directory) | 85 | (defun acdw/in-dir (file &optional make-directory) |
66 | "Expand FILE relative to `acdw/dir', optionally creating its | 86 | "Expand FILE relative to `acdw/dir', optionally creating its |
67 | directory." | 87 | directory." |
68 | (let ((f (expand-file-name (convert-standard-filename file) | 88 | (let ((f (expand-file-name (convert-standard-filename file) |
69 | acdw/dir))) | 89 | acdw/dir))) |
70 | (when make-directory | 90 | (when make-directory |
71 | (make-directory (file-name-directory f) 'parents)) | 91 | (make-directory (file-name-directory f) 'parents)) |
72 | f)) | 92 | f)) |
73 | 93 | ||
74 | ;;; Settings | 94 | ;;; Settings |
75 | 95 | ||
76 | (defun acdw/set (assignments) | 96 | ;; (defun acdw/set (assignments) |
77 | "Perform `customize-set-variable' on each of ASSIGNMENTS. | 97 | ;; "Perform `customize-set-variable' on each of ASSIGNMENTS. |
78 | 98 | ||
79 | ASSIGNMENTS is a list where each element is of the form | 99 | ;; ASSIGNMENTS is a list where each element is of the form |
80 | (VARIABLE VALUE [COMMENT])." | 100 | ;; (VARIABLE VALUE [COMMENT])." |
81 | (let (setting) ; for return value | 101 | ;; (let (setting) ; for return value |
82 | (dolist (assignment assignments setting) | 102 | ;; (dolist (assignment assignments setting) |
83 | (customize-set-variable (car assignment) | 103 | ;; (customize-set-variable (car assignment) |
84 | (cadr assignment) | 104 | ;; (cadr assignment) |
85 | (if (and (caddr assignment) | 105 | ;; (if (and (caddr assignment) |
86 | (stringp (caddr assignment))) | 106 | ;; (stringp (caddr assignment))) |
87 | (caddr assignment) | 107 | ;; (caddr assignment) |
88 | "Customized by `acdw/set'.")) | 108 | ;; "Customized by `acdw/set'.")) |
89 | (setq setting (car assignment))))) | 109 | ;; (setq setting (car assignment))))) |
90 | 110 | ||
91 | ;;; Faces | 111 | ;;; Faces |
92 | 112 | ||
93 | (defun acdw/set-face (face spec) | 113 | ;; (defun acdw/set-face (face spec) |
94 | "Customize FACE according to SPEC, and register it with `customize'. | 114 | ;; "Customize FACE according to SPEC, and register it with `customize'. |
95 | SPEC is as for `defface'." | 115 | ;; SPEC is as for `defface'." |
96 | (put face 'customized-face spec) | 116 | ;; (put face 'customized-face spec) |
97 | (face-spec-set face spec)) | 117 | ;; (face-spec-set face spec)) |
98 | 118 | ||
99 | (defmacro acdw/set-faces (face-specs) | 119 | ;; (defmacro acdw/set-faces (face-specs) |
100 | "Run `acdw/set-face' over each face in FACE-SPECS." | 120 | ;; "Run `acdw/set-face' over each face in FACE-SPECS." |
101 | (let (face-list) | 121 | ;; (let (face-list) |
102 | (dolist (face face-specs) | 122 | ;; (dolist (face face-specs) |
103 | (push `(acdw/set-face ',(car face) ',(cdr face)) face-list)) | 123 | ;; (push `(acdw/set-face ',(car face) ',(cdr face)) face-list)) |
104 | `(progn | 124 | ;; `(progn |
105 | ,@face-list))) | 125 | ;; ,@face-list))) |
106 | 126 | ||
107 | ;;; Hooks | 127 | ;;; Hooks |
108 | (defmacro acdw/hooks (hook-specs &rest args) | 128 | ;; (defmacro acdw/hooks (hook-specs &rest args) |
109 | "Add functions to hooks, according to HOOK-SPECS. | 129 | ;; "Add functions to hooks, according to HOOK-SPECS. |
110 | 130 | ||
111 | Each HOOK-SPEC is of the following format: (HOOKS FUNCS [DEPTH] [LOCAL]). | 131 | ;; Each HOOK-SPEC is of the following format: (HOOKS FUNCS [DEPTH] [LOCAL]). |
112 | Either HOOKS or FUNCS can also be a list, in which case `add-hook' is called | 132 | ;; Either HOOKS or FUNCS can also be a list, in which case `add-hook' is called |
113 | over the Cartesian product of HOOKS and FUNCS. In each HOOK-SPEC, DEPTH and | 133 | ;; over the Cartesian product of HOOKS and FUNCS. In each HOOK-SPEC, DEPTH and |
114 | LOCAL apply to all hooks defined; if finer control is needed, either pass the | 134 | ;; LOCAL apply to all hooks defined; if finer control is needed, either pass the |
115 | same hooks and functions in different HOOK-SPECs, or just use `add-hook'. | 135 | ;; same hooks and functions in different HOOK-SPECs, or just use `add-hook'. |
116 | 136 | ||
117 | ARGS accept the following keywords: | 137 | ;; ARGS accept the following keywords: |
118 | 138 | ||
119 | :after FEATURE .. `autoload' all functions after FEATURE." | 139 | ;; :after FEATURE .. `autoload' all functions after FEATURE." |
120 | (let ((after (plist-get args :after)) | 140 | ;; (let ((after (plist-get args :after)) |
121 | (command-list)) | 141 | ;; (command-list)) |
122 | (dolist (spec hook-specs) | 142 | ;; (dolist (spec hook-specs) |
123 | (let* ((hooks (car spec)) | 143 | ;; (let* ((hooks (car spec)) |
124 | (funcs (cadr spec)) | 144 | ;; (funcs (cadr spec)) |
125 | (depth (or (caddr spec) 0)) | 145 | ;; (depth (or (caddr spec) 0)) |
126 | (local (cadddr spec))) | 146 | ;; (local (cadddr spec))) |
127 | (when (not (listp hooks)) (setq hooks (list hooks))) | 147 | ;; (when (not (listp hooks)) (setq hooks (list hooks))) |
128 | (when (not (listp funcs)) (setq funcs (list funcs))) | 148 | ;; (when (not (listp funcs)) (setq funcs (list funcs))) |
129 | (dolist (hook hooks) | 149 | ;; (dolist (hook hooks) |
130 | (dolist (func funcs) | 150 | ;; (dolist (func funcs) |
131 | (push `(add-hook ',hook #',func ,depth ,local) command-list) | 151 | ;; (push `(add-hook ',hook #',func ,depth ,local) command-list) |
132 | (when after | 152 | ;; (when after |
133 | (push `(autoload #',func ,after) command-list)))))) | 153 | ;; (push `(autoload #',func ,after) command-list)))))) |
134 | `(progn | 154 | ;; `(progn |
135 | ,@command-list))) | 155 | ;; ,@command-list))) |
136 | 156 | ||
137 | ;;; Keybindings | 157 | ;;; Keybindings |
138 | 158 | ||
139 | (defvar acdw/bind-default-map 'acdw/map | 159 | ;; (defvar acdw/bind-default-map 'acdw/map |
140 | "The default keymap to use with `acdw/bind'.") | 160 | ;; "The default keymap to use with `acdw/bind'.") |
141 | 161 | ||
142 | (defmacro acdw/bind (key command &rest args) | 162 | ;; (defmacro acdw/bind (key command &rest args) |
143 | "A simple key-binding macro to take care of the repetitive stuff | 163 | ;; "A simple key-binding macro to take care of the repetitive stuff |
144 | automatically. | 164 | ;; automatically. |
145 | 165 | ||
146 | If KEY is a vector, it's passed directly to `define-key', | 166 | ;; If KEY is a vector, it's passed directly to `define-key', |
147 | otherwise it's wrapped in `kbd'. | 167 | ;; otherwise it's wrapped in `kbd'. |
148 | 168 | ||
149 | The following keywords are recognized: | 169 | ;; The following keywords are recognized: |
150 | 170 | ||
151 | :after ARGS .. call `autoload' on COMMAND using ARGS before | 171 | ;; :after ARGS .. call `autoload' on COMMAND using ARGS before |
152 | binding the key. ARGS can be just the filename to | 172 | ;; binding the key. ARGS can be just the filename to |
153 | load; in that case it's wrapped in a list. | 173 | ;; load; in that case it's wrapped in a list. |
154 | 174 | ||
155 | :map KEYMAP .. define KEY in KEYMAP instead of the | 175 | ;; :map KEYMAP .. define KEY in KEYMAP instead of the |
156 | default `acdw/bind-default-map'. If `:after' is also supplied, | 176 | ;; default `acdw/bind-default-map'. If `:after' is also supplied, |
157 | run `autoload' on KEYMAP (except when using `:map-after', see). | 177 | ;; run `autoload' on KEYMAP (except when using `:map-after', see). |
158 | 178 | ||
159 | :map-after FILE .. run the underlying `define-key' command in an | 179 | ;; :map-after FILE .. run the underlying `define-key' command in an |
160 | `with-eval-after-load'. For the rare occasion when the keymap is | 180 | ;; `with-eval-after-load'. For the rare occasion when the keymap is |
161 | defined in a different file than the command it binds (looking | 181 | ;; defined in a different file than the command it binds (looking |
162 | at you, `org-mode')." | 182 | ;; at you, `org-mode')." |
163 | (let ((after (when-let (sym (plist-get args :after)) | 183 | ;; (let ((after (when-let (sym (plist-get args :after)) |
164 | (if (not (listp sym)) | 184 | ;; (if (not (listp sym)) |
165 | (list sym) | 185 | ;; (list sym) |
166 | sym))) | 186 | ;; sym))) |
167 | (map-after (plist-get args :map-after)) | 187 | ;; (map-after (plist-get args :map-after)) |
168 | (keymap (or (plist-get args :map) acdw/bind-default-map)) | 188 | ;; (keymap (or (plist-get args :map) acdw/bind-default-map)) |
169 | (keycode (if (vectorp key) key (kbd key))) | 189 | ;; (keycode (if (vectorp key) key (kbd key))) |
170 | (command-list)) | 190 | ;; (command-list)) |
171 | (let ((define-key-command `(define-key ,keymap ,keycode ',command))) | 191 | ;; (let ((define-key-command `(define-key ,keymap ,keycode ',command))) |
172 | (if map-after | 192 | ;; (if map-after |
173 | (push `(with-eval-after-load ,map-after | 193 | ;; (push `(with-eval-after-load ,map-after |
174 | ,define-key-command) | 194 | ;; ,define-key-command) |
175 | command-list) | 195 | ;; command-list) |
176 | (push define-key-command command-list))) | 196 | ;; (push define-key-command command-list))) |
177 | (when after | 197 | ;; (when after |
178 | (unless (fboundp command) | 198 | ;; (unless (fboundp command) |
179 | (push `(autoload ',command ,@after) command-list)) | 199 | ;; (push `(autoload ',command ,@after) command-list)) |
180 | (unless (or map-after | 200 | ;; (unless (or map-after |
181 | (eq keymap acdw/bind-default-map)) | 201 | ;; (eq keymap acdw/bind-default-map)) |
182 | (push `(autoload ',keymap ,(car after) nil nil 'keymap) command-list))) | 202 | ;; (push `(autoload ',keymap ,(car after) nil nil 'keymap) command-list))) |
183 | `(progn | 203 | ;; `(progn |
184 | ,@command-list))) | 204 | ;; ,@command-list))) |
185 | 205 | ||
186 | (defmacro acdw/binds (bindings) | 206 | ;; (defmacro acdw/binds (bindings) |
187 | "Bind multiple keys at once." | 207 | ;; "Bind multiple keys at once." |
188 | (let (bind-list) | 208 | ;; (let (bind-list) |
189 | (dolist (bind bindings) | 209 | ;; (dolist (bind bindings) |
190 | (push `(acdw/bind ,@bind) bind-list)) | 210 | ;; (push `(acdw/bind ,@bind) bind-list)) |
191 | `(progn | 211 | ;; `(progn |
192 | ,@bind-list))) | 212 | ;; ,@bind-list))) |
193 | 213 | ||
194 | ;; convenience | 214 | ;; convenience |
195 | (defmacro acdw/bind-after-map (file keymap bindings) | 215 | ;; (defmacro acdw/bind-after-map (file keymap bindings) |
196 | "Wrap multiple calls of `acdw/bind' after FILE and with KEYMAP. | 216 | ;; "Wrap multiple calls of `acdw/bind' after FILE and with KEYMAP. |
197 | KEYMAP can be nil." | 217 | ;; KEYMAP can be nil." |
198 | (declare (indent 2)) | 218 | ;; (declare (indent 2)) |
199 | (let ((bind-list) | 219 | ;; (let ((bind-list) |
200 | (extra-args (if keymap | 220 | ;; (extra-args (if keymap |
201 | `(:after ,file :map ,keymap) | 221 | ;; `(:after ,file :map ,keymap) |
202 | `(:after ,file)))) | 222 | ;; `(:after ,file)))) |
203 | (dolist (binding bindings) | 223 | ;; (dolist (binding bindings) |
204 | (push `(acdw/bind ,@binding ,@extra-args) bind-list)) | 224 | ;; (push `(acdw/bind ,@binding ,@extra-args) bind-list)) |
205 | `(progn | 225 | ;; `(progn |
206 | ,@bind-list))) | 226 | ;; ,@bind-list))) |
207 | 227 | ||
208 | ;;; Packages | 228 | ;;; Packages |
209 | 229 | ||
210 | (defmacro acdw/pkg (package &rest args) | 230 | ;; (defmacro acdw/pkg (package &rest args) |
211 | "Set up a package using `straight.el'. | 231 | ;; "Set up a package using `straight.el'. |
212 | 232 | ||
213 | ARGS can include the following keywords: | 233 | ;; ARGS can include the following keywords: |
214 | 234 | ||
215 | :local BOOL .. if BOOL is non-nil, don't run `straight-use-package' on | 235 | ;; :local BOOL .. if BOOL is non-nil, don't run `straight-use-package' on |
216 | PACKAGE. Good for using `acdw/pkg' on local features. | 236 | ;; PACKAGE. Good for using `acdw/pkg' on local features. |
217 | :require BOOL .. if BOOL is non-nil, run `require' on PACKAGE before anything. | 237 | ;; :require BOOL .. if BOOL is non-nil, run `require' on PACKAGE before anything. |
218 | :now FORMS .. run FORMS immediately. | 238 | ;; :now FORMS .. run FORMS immediately. |
219 | :then FORMS .. run FORMS after loading PACKAGE, using `with-eval-after-load'. | 239 | ;; :then FORMS .. run FORMS after loading PACKAGE, using `with-eval-after-load'. |
220 | :set SETTINGS .. pass SETTINGS to `acdw/set', right after `:now' forms. | 240 | ;; :set SETTINGS .. pass SETTINGS to `acdw/set', right after `:now' forms. |
221 | SETTINGS should be properly quoted, just like they'd be passed | 241 | ;; SETTINGS should be properly quoted, just like they'd be passed |
222 | to the function. | 242 | ;; to the function. |
223 | :binds BINDS .. run `acdw/bind-after-map' on BINDS. | 243 | ;; :binds BINDS .. run `acdw/bind-after-map' on BINDS. |
224 | :hooks HOOKS .. run `acdw/hooks' on HOOKS." | 244 | ;; :hooks HOOKS .. run `acdw/hooks' on HOOKS." |
225 | (declare (indent 1)) | 245 | ;; (declare (indent 1)) |
226 | (let ((local-pkg (plist-get args :local)) | 246 | ;; (let ((local-pkg (plist-get args :local)) |
227 | (require-pkg (plist-get args :require)) | 247 | ;; (require-pkg (plist-get args :require)) |
228 | (now-forms (plist-get args :now)) | 248 | ;; (now-forms (plist-get args :now)) |
229 | (settings (plist-get args :set)) | 249 | ;; (settings (plist-get args :set)) |
230 | (binds (plist-get args :binds)) | 250 | ;; (binds (plist-get args :binds)) |
231 | (hooks (plist-get args :hooks)) | 251 | ;; (hooks (plist-get args :hooks)) |
232 | (then-forms (plist-get args :then)) | 252 | ;; (then-forms (plist-get args :then)) |
233 | (requirement (if (listp package) | 253 | ;; (requirement (if (listp package) |
234 | (car package) | 254 | ;; (car package) |
235 | package)) | 255 | ;; package)) |
236 | (final-form)) | 256 | ;; (final-form)) |
237 | (when then-forms | 257 | ;; (when then-forms |
238 | (push `(with-eval-after-load ',requirement ,@then-forms) final-form)) | 258 | ;; (push `(with-eval-after-load ',requirement ,@then-forms) final-form)) |
239 | (when hooks | 259 | ;; (when hooks |
240 | (push `(acdw/hooks ,hooks :after ,(symbol-name requirement)) final-form)) | 260 | ;; (push `(acdw/hooks ,hooks :after ,(symbol-name requirement)) final-form)) |
241 | (when binds | 261 | ;; (when binds |
242 | (push `(acdw/bind-after-map ,(symbol-name requirement) nil ,binds) | 262 | ;; (push `(acdw/bind-after-map ,(symbol-name requirement) nil ,binds) |
243 | final-form)) | 263 | ;; final-form)) |
244 | (when settings | 264 | ;; (when settings |
245 | (push `(acdw/set ,settings) final-form)) | 265 | ;; (push `(acdw/set ,settings) final-form)) |
246 | (when now-forms | 266 | ;; (when now-forms |
247 | (push `(progn ,@now-forms) final-form)) | 267 | ;; (push `(progn ,@now-forms) final-form)) |
248 | (unless local-pkg | 268 | ;; (unless local-pkg |
249 | (push `(straight-use-package ',package) final-form)) | 269 | ;; (push `(straight-use-package ',package) final-form)) |
250 | (when require-pkg | 270 | ;; (when require-pkg |
251 | (push `(require ',requirement) final-form)) | 271 | ;; (push `(require ',requirement) final-form)) |
252 | `(progn | 272 | ;; `(progn |
253 | ,@final-form))) | 273 | ;; ,@final-form))) |
274 | |||
275 | ;;; Reading mode | ||
276 | |||
277 | (define-minor-mode acdw/reading-mode | ||
278 | "A mode for reading." | ||
279 | :init-value t | ||
280 | :lighter " Read" | ||
281 | (if acdw/reading-mode | ||
282 | (progn ;; turn on | ||
283 | (display-fill-column-indicator-mode -1) | ||
284 | (dolist (mode '(visual-fill-column-mode | ||
285 | iscroll-mode)) | ||
286 | (when (fboundp mode) | ||
287 | (funcall mode +1)))) | ||
288 | ;; turn off | ||
289 | (display-fill-column-indicator-mode +1) | ||
290 | (dolist (mode '(visual-fill-column-mode | ||
291 | iscroll-mode)) | ||
292 | (when (fboundp mode) | ||
293 | (funcall mode -1))))) | ||
254 | 294 | ||
255 | ;;; Keymap & Mode | 295 | ;;; Keymap & Mode |
256 | 296 | ||
@@ -273,7 +313,7 @@ ARGS can include the following keywords: | |||
273 | ;; Set up a leader key for `acdw/mode' | 313 | ;; Set up a leader key for `acdw/mode' |
274 | (defvar acdw/leader | 314 | (defvar acdw/leader |
275 | (let ((map (make-sparse-keymap)) | 315 | (let ((map (make-sparse-keymap)) |
276 | (c-z (global-key-binding "\C-z"))) | 316 | (c-z (global-key-binding "\C-z"))) |
277 | (define-key acdw/map "\C-z" map) | 317 | (define-key acdw/map "\C-z" map) |
278 | (define-key map "\C-z" c-z) | 318 | (define-key map "\C-z" c-z) |
279 | map)) | 319 | map)) |