diff options
author | Case Duckworth | 2021-03-08 18:00:13 -0600 |
---|---|---|
committer | Case Duckworth | 2021-03-08 18:00:13 -0600 |
commit | 767497ece4b06f12ad04b40131aeee57bcbc6bd4 (patch) | |
tree | e3087804f5702192eb5aad5aaeb5f992af072f23 /lisp | |
parent | Add functions (diff) | |
download | emacs-767497ece4b06f12ad04b40131aeee57bcbc6bd4.tar.gz emacs-767497ece4b06f12ad04b40131aeee57bcbc6bd4.zip |
Almost finished with `acdw/pkg'
Still some bugs to squash.
Diffstat (limited to 'lisp')
-rw-r--r-- | lisp/acdw.el | 135 |
1 files changed, 95 insertions, 40 deletions
diff --git a/lisp/acdw.el b/lisp/acdw.el index 7f0145c..927b083 100644 --- a/lisp/acdw.el +++ b/lisp/acdw.el | |||
@@ -22,6 +22,14 @@ | |||
22 | ;; | 22 | ;; |
23 | ;;; Code: | 23 | ;;; Code: |
24 | 24 | ||
25 | ;;; Utilities | ||
26 | (defun acdw/when-unfocused (func &rest args) | ||
27 | "Call FUNC, with ARGS, iff all Emacs frames are out of focus. | ||
28 | |||
29 | Ready for use with `after-focus-change-function'." | ||
30 | (when (seq-every-p #'null (mapcar #'frame-focus-state (frame-list))) | ||
31 | (apply func args))) | ||
32 | |||
25 | ;;; Directories (think `no-littering') | 33 | ;;; Directories (think `no-littering') |
26 | 34 | ||
27 | (defvar acdw/dir (expand-file-name | 35 | (defvar acdw/dir (expand-file-name |
@@ -71,26 +79,6 @@ SPEC is as for `defface'." | |||
71 | 79 | ||
72 | ;;; Hooks | 80 | ;;; Hooks |
73 | 81 | ||
74 | ;; XXX NOT WORKING | ||
75 | (defmacro acdw/defun-hook (hook docstring &optional depth local &rest forms) | ||
76 | "Add FORMS to a function described by DOCSTRING, then add that | ||
77 | function to HOOK. DOCSTRING is converted to a function name by | ||
78 | calling `docstring-to-symbol', if it's a string, or used as-is | ||
79 | otherwise. The optional DEPTH and LOCAL are passed to | ||
80 | `add-hook', if they're present (i.e., not a list). | ||
81 | |||
82 | This macro aims to split the difference between the syntax of | ||
83 | lambdas in hooks and the ability to easily disable hooks." | ||
84 | (declare (indent 2)) | ||
85 | (let ((name (if (stringp docstring) | ||
86 | (docstring-to-symbol docstring "hook-") | ||
87 | docstring))) | ||
88 | (when (listp local) (push local forms) (setq local nil)) | ||
89 | (when (listp depth) (push depth forms) (setq depth 0)) | ||
90 | `(progn | ||
91 | (defun ,name () ,@forms) | ||
92 | (add-hook ,hook #',name ,depth ,local)))) | ||
93 | |||
94 | (defmacro acdw/hooks (hooks funcs &optional depth local) | 82 | (defmacro acdw/hooks (hooks funcs &optional depth local) |
95 | "Add FUNCS to HOOKS. | 83 | "Add FUNCS to HOOKS. |
96 | 84 | ||
@@ -110,15 +98,15 @@ more fine-grained control, just use `add-hook'." | |||
110 | `(progn | 98 | `(progn |
111 | ,@hook-list))) | 99 | ,@hook-list))) |
112 | 100 | ||
113 | ;; Utilities | 101 | (defmacro acdw/hooks-after (file hooks funcs &optional depth local) |
114 | (defun docstring-to-symbol (docstring &optional prefix) | 102 | "Add FUNCS, from FILE, to HOOKS." |
115 | "Convert a DOCSTRING to a symbol by lowercasing the string, | 103 | (let ((funcs (if (listp funcs) funcs (list funcs))) |
116 | converting non-symbol-safe characters to '-', and calling | 104 | (autoload-list)) |
117 | `intern'. Returns the created symbol." | 105 | (dolist (func funcs) |
118 | (let ((str (split-string (downcase docstring) "[ \f\t\n\r\v'\"`,]+" | 106 | (add-to-list 'autoload-list `(autoload #',func ,file))) |
119 | :omit-nulls))) | 107 | `(progn |
120 | (when prefix (push prefix str)) | 108 | ,@autoload-list |
121 | (intern (mapconcat #'identity str "-")))) | 109 | (acdw/hooks ,hooks ,funcs ,depth ,local)))) |
122 | 110 | ||
123 | ;;; Keybindings | 111 | ;;; Keybindings |
124 | 112 | ||
@@ -134,12 +122,12 @@ otherwise it's wrapped in `read-kbd-macro'. | |||
134 | 122 | ||
135 | The following keywords are recognized: | 123 | The following keywords are recognized: |
136 | 124 | ||
137 | :autoload ARGS .. call `autoload' on COMMAND using ARGS before | 125 | :after ARGS .. call `autoload' on COMMAND using ARGS before |
138 | binding the key. ARGS can be just the filename to load; in | 126 | binding the key. ARGS can be just the filename to |
139 | that case it's wrapped in a list. | 127 | load; in that case it's wrapped in a list. |
140 | :map KEYMAP .. define KEY in KEYMAP instead of the | 128 | :map KEYMAP .. define KEY in KEYMAP instead of the |
141 | default `acdw/bind-default-map'." | 129 | default `acdw/bind-default-map'." |
142 | (let ((autoload (when-let (sym (plist-get args :autoload)) | 130 | (let ((after (when-let (sym (plist-get args :after)) |
143 | (if (not (listp sym)) | 131 | (if (not (listp sym)) |
144 | (list sym) | 132 | (list sym) |
145 | sym))) | 133 | sym))) |
@@ -147,24 +135,59 @@ The following keywords are recognized: | |||
147 | (keycode (if (vectorp key) key (kbd key))) | 135 | (keycode (if (vectorp key) key (kbd key))) |
148 | (command-list)) | 136 | (command-list)) |
149 | (push `(define-key ,keymap ,keycode ,command) command-list) | 137 | (push `(define-key ,keymap ,keycode ,command) command-list) |
150 | (when autoload | 138 | (when after |
151 | (push `(autoload ,command ,@autoload) command-list)) | 139 | (push `(autoload ,command ,@after) command-list)) |
152 | `(progn | 140 | `(progn |
153 | ,@command-list))) | 141 | ,@command-list))) |
154 | 142 | ||
155 | ;; convenience | 143 | ;; convenience |
156 | (defmacro acdw/bind-after-map (file keymap &rest bindings) | 144 | (defmacro acdw/bind-after-map (file keymap bindings) |
157 | "Wrap multiple calls of `acdw/bind' after FILE and with KEYMAP. | 145 | "Wrap multiple calls of `acdw/bind' after FILE and with KEYMAP. |
158 | KEYMAP can be nil." | 146 | KEYMAP can be nil." |
159 | (declare (indent 2)) | 147 | (declare (indent 2)) |
160 | (let (bind-list) | 148 | (let ((bind-list) |
149 | (extra-args (if keymap | ||
150 | `(:after ,file :map ,keymap) | ||
151 | `(:after ,file)))) | ||
161 | (dolist (binding bindings) | 152 | (dolist (binding bindings) |
162 | (if keymap | 153 | (push `(acdw/bind ,@binding ,@extra-args) bind-list)) |
163 | (push `(acdw/bind ,@binding :after ,file :map ,keymap) bind-list) | ||
164 | (push `(acdw/bind ,@binding :after ,file) bind-list))) | ||
165 | `(progn | 154 | `(progn |
166 | ,@bind-list))) | 155 | ,@bind-list))) |
167 | 156 | ||
157 | ;;; Packages | ||
158 | |||
159 | (defmacro acdw/pkg (package &rest args) | ||
160 | "Set up a package using `straight.el'. | ||
161 | |||
162 | ARGS can include the following keywords: | ||
163 | |||
164 | :now FORMS .. run forms immediately. | ||
165 | Good for settings and auxiliary functions. | ||
166 | :then FORMS .. run forms after loading PACKAGE, using `with-eval-after-load'. | ||
167 | :binds BINDS .. run `acdw/bind-after-map' on BINDS. | ||
168 | :hooks HOOKS .. run `acdw/hooks-after' on HOOKS." | ||
169 | (declare (indent 1)) | ||
170 | (let ((now-forms (plist-get args :now)) | ||
171 | (binds (plist-get args :binds)) | ||
172 | (hooks (plist-get args :hooks)) | ||
173 | (then-forms (plist-get args :then)) | ||
174 | (requirement (if (listp package) | ||
175 | (car package) | ||
176 | package)) | ||
177 | (final-form)) | ||
178 | (when then-forms | ||
179 | (push `(with-eval-after-load ',requirement ,@then-forms) final-form)) | ||
180 | (when hooks | ||
181 | (push `(acdw/hooks-after ,(symbol-name requirement) ,hooks) final-form)) | ||
182 | (when binds | ||
183 | (push `(acdw/bind-after-map ,(symbol-name requirement) nil ,binds) | ||
184 | final-form)) | ||
185 | (when now-forms | ||
186 | (push `(progn ,@now-forms) final-form)) | ||
187 | (push `(straight-use-package ',package) final-form) | ||
188 | `(progn | ||
189 | ,@final-form))) | ||
190 | |||
168 | ;;; Keymap & Mode | 191 | ;;; Keymap & Mode |
169 | 192 | ||
170 | (defvar acdw/map (make-sparse-keymap) | 193 | (defvar acdw/map (make-sparse-keymap) |
@@ -193,3 +216,35 @@ KEYMAP can be nil." | |||
193 | 216 | ||
194 | (provide 'acdw) | 217 | (provide 'acdw) |
195 | ;;; acdw.el ends here | 218 | ;;; acdw.el ends here |
219 | |||
220 | ;;; Elephant graveyard | ||
221 | |||
222 | ;; XXX NOT WORKING -- And is this even necessary? | ||
223 | ;; (defmacro acdw/defun-hook (hook docstring &optional depth local &rest forms) | ||
224 | ;; "Add FORMS to a function described by DOCSTRING, then add that | ||
225 | ;; function to HOOK. DOCSTRING is converted to a function name by | ||
226 | ;; calling `docstring-to-symbol', if it's a string, or used as-is | ||
227 | ;; otherwise. The optional DEPTH and LOCAL are passed to | ||
228 | ;; `add-hook', if they're present (i.e., not a list). | ||
229 | |||
230 | ;; This macro aims to split the difference between the syntax of | ||
231 | ;; lambdas in hooks and the ability to easily disable hooks." | ||
232 | ;; (declare (indent 2)) | ||
233 | ;; (let ((name (if (stringp docstring) | ||
234 | ;; (docstring-to-symbol docstring "hook-") | ||
235 | ;; docstring))) | ||
236 | ;; (when (listp local) (push local forms) (setq local nil)) | ||
237 | ;; (when (listp depth) (push depth forms) (setq depth 0)) | ||
238 | ;; `(progn | ||
239 | ;; (defun ,name () ,@forms) | ||
240 | ;; (add-hook ,hook #',name ,depth ,local)))) | ||
241 | |||
242 | ;; Utilities XXX related to `acdw/defun-hook' | ||
243 | ;; (defun docstring-to-symbol (docstring &optional prefix) | ||
244 | ;; "Convert a DOCSTRING to a symbol by lowercasing the string, | ||
245 | ;; converting non-symbol-safe characters to '-', and calling | ||
246 | ;; `intern'. Returns the created symbol." | ||
247 | ;; (let ((str (split-string (downcase docstring) "[ \f\t\n\r\v'\"`,]+" | ||
248 | ;; :omit-nulls))) | ||
249 | ;; (when prefix (push prefix str)) | ||
250 | ;; (intern (mapconcat #'identity str "-")))) | ||