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 58fd7b4..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', @@ -134,10 +133,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 +503,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 @@ -536,37 +533,37 @@ 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 + (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 + ;; `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))))) +(put 'el-patch-deftype 'el-patch-defined-properly t) ;;;;; Classification functions @@ -665,6 +662,9 @@ 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