From e77ff984aa6d5c162cd6a9268ab15f83112a8a36 Mon Sep 17 00:00:00 2001 From: Jelle Licht Date: Mon, 22 Nov 2021 10:54:41 +0100 Subject: [PATCH 1/4] Remove unneeded progn. --- el-patch.el | 43 ++++++++++++++++++++----------------------- 1 file changed, 20 insertions(+), 23 deletions(-) diff --git a/el-patch.el b/el-patch.el index 58fd7b4..e721e70 100644 --- a/el-patch.el +++ b/el-patch.el @@ -536,37 +536,34 @@ patched. NAME and TYPE are as returned by `el-patch-get'." ;;;; Defining patch types -;; Use `progn' to cause the entire macro definition to be autoloaded -;; rather than just a stub. ;;;###autoload -(progn - (cl-defmacro el-patch-deftype - (type &rest kwargs &key classify locate declare macro-name) - "Allow `el-patch' to patch definitions of the given TYPE. +(cl-defmacro el-patch-deftype + (type &rest kwargs &key classify locate declare macro-name) + "Allow `el-patch' to patch definitions of the given TYPE. TYPE is a symbol like `defun', `define-minor-mode', etc. This updates `el-patch-deftype-alist' (which see for explanations of CLASSIFY, LOCATE, and DECLARE) with the provided KWARGS and defines a macro named like `el-patch-defun', `el-patch-define-minor-mode', etc. (which can be overridden by MACRO-NAME)." - (declare (indent defun)) - (ignore locate) - (unless classify - (error "You must specify `:classify' in calls to `el-patch-deftype'")) - `(progn - (setf (alist-get ',type el-patch-deftype-alist) - ;; Make sure we don't accidentally create self-modifying - ;; code if somebody decides to mutate - ;; `el-patch-deftype-alist'. - (copy-tree ',kwargs)) - (defmacro ,(or macro-name (intern (format "el-patch-%S" type))) - (name &rest args) - ,(format "Use `el-patch' to override a `%S' form. + (declare (indent defun)) + (ignore locate) + (unless classify + (error "You must specify `:classify' in calls to `el-patch-deftype'")) + `(progn + (setf (alist-get ',type el-patch-deftype-alist) + ;; Make sure we don't accidentally create self-modifying + ;; code if somebody decides to mutate + ;; `el-patch-deftype-alist'. + (copy-tree ',kwargs)) + (defmacro ,(or macro-name (intern (format "el-patch-%S" type))) + (name &rest args) + ,(format "Use `el-patch' to override a `%S' form. The ARGS are the same as for `%S'." - type type) - ,@(when declare - `((declare ,@declare))) - (list #'el-patch--definition (cl-list* ',type name args)))))) + type type) + ,@(when declare + `((declare ,@declare))) + (list #'el-patch--definition (cl-list* ',type name args))))) ;;;;; Classification functions From eafaa813a2415b61122d478e403cba0e646fbffb Mon Sep 17 00:00:00 2001 From: Jelle Licht Date: Mon, 22 Nov 2021 10:51:32 +0100 Subject: [PATCH 2/4] Add custom autoload cookie to prevent eager loading. --- el-patch.el | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/el-patch.el b/el-patch.el index e721e70..6ef4d90 100644 --- a/el-patch.el +++ b/el-patch.el @@ -664,56 +664,56 @@ DEFINITION is a list starting with `defun' or similar." ;; These are alphabetized. -;;;###autoload +;;;###autoload (autoload 'el-patch-cl-defun "el-patch") (el-patch-deftype cl-defun :classify el-patch-classify-function :locate el-patch-locate-function :declare ((doc-string 3) (indent defun))) -;;;###autoload +;;;###autoload (autoload 'el-patch-defconst "el-patch") (el-patch-deftype defconst :classify el-patch-classify-variable :locate el-patch-locate-variable :declare ((doc-string 3) (indent defun))) -;;;###autoload +;;;###autoload (autoload 'el-patch-defcustom "el-patch") (el-patch-deftype defcustom :classify el-patch-classify-variable :locate el-patch-locate-variable :declare ((doc-string 3) (indent defun))) -;;;###autoload +;;;###autoload (autoload 'el-patch-define-minor-mode "el-patch") (el-patch-deftype define-minor-mode :classify el-patch-classify-define-minor-mode :locate el-patch-locate-function :declare ((doc-string 2) (indent defun))) -;;;###autoload +;;;###autoload (autoload 'el-patch-defmacro "el-patch") (el-patch-deftype defmacro :classify el-patch-classify-function :locate el-patch-locate-function :declare ((doc-string 3) (indent defun))) -;;;###autoload +;;;###autoload (autoload 'el-patch-defsubst "el-patch") (el-patch-deftype defsubst :classify el-patch-classify-function :locate el-patch-locate-function :declare ((doc-string 3) (indent defun))) -;;;###autoload +;;;###autoload (autoload 'el-patch-defun "el-patch") (el-patch-deftype defun :classify el-patch-classify-function :locate el-patch-locate-function :declare ((doc-string 3) (indent defun))) -;;;###autoload +;;;###autoload (autoload 'el-patch-defvar "el-patch") (el-patch-deftype defvar :classify el-patch-classify-variable :locate el-patch-locate-variable From fea34842adf5c9432eb8eea613abd32aa3d1adfe Mon Sep 17 00:00:00 2001 From: Radon Rosborough Date: Tue, 21 Dec 2021 16:58:59 -0800 Subject: [PATCH 3/4] Remove unneeded autoload --- el-patch.el | 18 ++++++++---------- 1 file changed, 8 insertions(+), 10 deletions(-) diff --git a/el-patch.el b/el-patch.el index 6ef4d90..82b40c6 100644 --- a/el-patch.el +++ b/el-patch.el @@ -134,10 +134,6 @@ loaded. You can toggle the `use-package' integration later using ;;;; Internal variables -;; We autoload `el-patch--patches' so that patches can be defined at -;; runtime without having `el-patch' loaded. - -;;;###autoload (defvar el-patch--patches (make-hash-table :test 'equal) "Hash table of patches that have been defined. The keys are symbols naming the objects that have been patched. @@ -508,12 +504,14 @@ PATCH-DEFINITION is an unquoted list starting with `defun', ;; away so that if there is an error then at least the user ;; can undo the patch (as long as it is not too terribly ;; wrong). - (puthash ',type - ',patch-definition - (or (gethash ',name el-patch--patches) - (puthash ',name - (make-hash-table :test #'equal) - el-patch--patches))) + (let ((patches (or (bound-and-true-p el-patch--patches) + (make-hash-table :test #'equal)))) + (puthash ',type + ',patch-definition + (or (gethash ',name patches) + (puthash ',name + (make-hash-table :test #'equal) + patches)))) ;; Now we actually overwrite the current definition. (el-patch--stealthy-eval ,definition From 966e7e49e0b8074a137b413b34cf6e7555750236 Mon Sep 17 00:00:00 2001 From: Radon Rosborough Date: Tue, 21 Dec 2021 17:52:04 -0800 Subject: [PATCH 4/4] Devise novel solution, document in changelog --- CHANGELOG.md | 21 +++++++++++++++++++++ el-patch-stub.el | 46 ++++++++++++++++++++++++++++++++++++++++++++++ el-patch.el | 23 ++++++++++++++--------- 3 files changed, 81 insertions(+), 9 deletions(-) create mode 100644 el-patch-stub.el diff --git a/CHANGELOG.md b/CHANGELOG.md index c01da32..bf638a0 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -13,8 +13,29 @@ The format is based on [Keep a Changelog]. * Patch forms were not processed when they appeared inside a vector. This has been fixed ([#51]). +### Internal changes +* The autoloading mechanism used by `el-patch` has changed, reducing + the amount of work that is done at startup and simplifying the + implementation ([#56]). The user-facing impact is as follows: + * `el-patch--patches` and `el-patch-deftype-alist` are no longer + autoloaded. If you use a compiled init-file, you may need to + recompile it with the new version of `el-patch`; the code + compiled with the old version of `el-patch` will not work at + runtime with the new version of `el-patch`. However, evaluating + patches in a compiled init-file, even one that uses + `el-patch-deftype`, still does not load `el-patch`. + * `el-patch-defun` and analogous functions are now autoloaded, + rather than fully defined at init time. This should not matter + since a compiled init-file would have macroexpanded these into + smaller components that do not have runtime dependencies on + `el-patch`. + * There is a new file `el-patch-stub.el` that needs to be on the + `load-path` for autoloads to work. This should be taken care of + automatically by any of the popular Emacs package managers. + [#50]: https://github.com/raxod502/el-patch/issues/50 [#51]: https://github.com/raxod502/el-patch/issues/51 +[#56]: https://github.com/raxod502/el-patch/pull/56 ## 2.3.1 (released 2020-07-16) ### Bugs fixed diff --git a/el-patch-stub.el b/el-patch-stub.el new file mode 100644 index 0000000..3fe73dc --- /dev/null +++ b/el-patch-stub.el @@ -0,0 +1,46 @@ +;;; el-patch-stub.el --- Functions loaded separately -*- lexical-binding: t -*- + +;; Copyright (C) 2021 Radon Rosborough + +;; Author: Radon Rosborough +;; Created: 21 Dec 2021 +;; Homepage: https://github.com/raxod502/el-patch +;; Keywords: extensions +;; Package-Requires: ((emacs "25")) +;; SPDX-License-Identifier: MIT +;; Version: 2.3.1 + +;;; Commentary: + +;; `el-patch-stub' has some utility functions that are used to define +;; stubs that are used only in the middle of the autoloading process. +;; Basically, they allow us to conveniently set up syntax highlighting +;; and indentation correctly for a number of different functions all +;; at once, without a bunch of code duplication. + +;; Please see https://github.com/raxod502/el-patch for more +;; information. + +;;; Code: + +(defun el-patch--deftype-stub-setup () + "Define `el-patch-deftype' as a minimal version suitable for autoload time. +This temporary replacement for the real functionality just takes +care of the `declare' forms, and leaves everything else for +later." + (unless (fboundp 'el-patch-deftype) + (defmacro el-patch-deftype (type &rest kwargs) + (let ((name (intern (format "el-patch-%S" type))) + (props (plist-get kwargs :declare))) + `(progn + (autoload ',name "el-patch" nil nil t) + (put ',name 'doc-string-elt ',(alist-get 'doc-string props)) + (put ',name 'lisp-indent-function ',(alist-get 'indent props))))))) + +(provide 'el-patch-stub) + +;; Local Variables: +;; indent-tabs-mode: nil +;; End: + +;;; el-patch-stub.el ends here diff --git a/el-patch.el b/el-patch.el index 82b40c6..dfbfbc4 100644 --- a/el-patch.el +++ b/el-patch.el @@ -83,7 +83,6 @@ provided by lazy-installed packages, and those packages need to be installed before the features can be loaded." :type 'function) -;;;###autoload (defcustom el-patch-deftype-alist nil "Alist of types of definitions that can be patched with `el-patch'. The keys are definition types, like `defun', `define-minor-mode', @@ -549,6 +548,8 @@ MACRO-NAME)." (unless classify (error "You must specify `:classify' in calls to `el-patch-deftype'")) `(progn + (unless (bound-and-true-p el-patch-deftype-alist) + (setq el-patch-deftype-alist nil)) (setf (alist-get ',type el-patch-deftype-alist) ;; Make sure we don't accidentally create self-modifying ;; code if somebody decides to mutate @@ -562,6 +563,7 @@ The ARGS are the same as for `%S'." ,@(when declare `((declare ,@declare))) (list #'el-patch--definition (cl-list* ',type name args))))) +(put 'el-patch-deftype 'el-patch-defined-properly t) ;;;;; Classification functions @@ -660,58 +662,61 @@ DEFINITION is a list starting with `defun' or similar." ;;;;; Predefined patch types +;;;###autoload(require 'el-patch-stub) +;;;###autoload(el-patch--deftype-stub-setup) + ;; These are alphabetized. -;;;###autoload (autoload 'el-patch-cl-defun "el-patch") +;;;###autoload (el-patch-deftype cl-defun :classify el-patch-classify-function :locate el-patch-locate-function :declare ((doc-string 3) (indent defun))) -;;;###autoload (autoload 'el-patch-defconst "el-patch") +;;;###autoload (el-patch-deftype defconst :classify el-patch-classify-variable :locate el-patch-locate-variable :declare ((doc-string 3) (indent defun))) -;;;###autoload (autoload 'el-patch-defcustom "el-patch") +;;;###autoload (el-patch-deftype defcustom :classify el-patch-classify-variable :locate el-patch-locate-variable :declare ((doc-string 3) (indent defun))) -;;;###autoload (autoload 'el-patch-define-minor-mode "el-patch") +;;;###autoload (el-patch-deftype define-minor-mode :classify el-patch-classify-define-minor-mode :locate el-patch-locate-function :declare ((doc-string 2) (indent defun))) -;;;###autoload (autoload 'el-patch-defmacro "el-patch") +;;;###autoload (el-patch-deftype defmacro :classify el-patch-classify-function :locate el-patch-locate-function :declare ((doc-string 3) (indent defun))) -;;;###autoload (autoload 'el-patch-defsubst "el-patch") +;;;###autoload (el-patch-deftype defsubst :classify el-patch-classify-function :locate el-patch-locate-function :declare ((doc-string 3) (indent defun))) -;;;###autoload (autoload 'el-patch-defun "el-patch") +;;;###autoload (el-patch-deftype defun :classify el-patch-classify-function :locate el-patch-locate-function :declare ((doc-string 3) (indent defun))) -;;;###autoload (autoload 'el-patch-defvar "el-patch") +;;;###autoload (el-patch-deftype defvar :classify el-patch-classify-variable :locate el-patch-locate-variable