GNU bug report logs -
#78995
[PATCH] ;;;autoload-expand for special macros
Previous Next
Reported by: JD Smith <jdtsmith <at> gmail.com>
Date: Fri, 11 Jul 2025 19:29:02 UTC
Severity: normal
Tags: patch
Fixed in version 31
Done: "J.D. Smith" <jdtsmith <at> gmail.com>
Full log
View this message in rfc822 format
Stefan Monnier <monnier <at> iro.umontreal.ca> writes:
>> A file-local variable, which extends the (1) list only for that file?
>
> I'm thinking we should replace the hardcoded list with a symbol
> property. When defining macros like `define-minor-mode` we'd set this
> `autoload-macroexpand` property to a non-nil value, and `autoload.el`
> would simply check the property instead of looking inside the hardcoded
> list with `memq`.
Oh, this is much better! It relieves the _user_ of the macro the burden
of remembering to "auto-load it correctly." For macros which are
defined in every session, you're done. No special autoload-expand magic
comment needed. It also makes it possible to entirely eliminate
hard-coded list #1. You'd just need to insert, e.g.:
(put 'defun 'autoload-macroexpand t)
where the special macros are _defined_. This would be a a bit more
self-documenting too.
We'd leave the "function-like operator" hard-coded list, but it could
probably be trimmed down with the new `autoload-macroexpand' feature.
For example, `transient-define-prefix' boils down to a defalias, which
is already supported.
> This would work only for predefined or autoloaded macros (where the
> `autoload-macroexpand` setting would be also pre-defined/loaded), so
> it wouldn't work conveniently for a locally-defined and locally-used
> macro, since you'd then need to somehow set the property and define or
> autoload the macro before `autoload.el` gets to the macro calls.
We could be aggressive about it. If the car of some form encountered
during file scanning (including expansion) is a macro, we check its
`autoload-macroexpand' property and act accordingly. But if it not
already a known special-form, function, or macro, we load the file to
see if that defines it. If it _remains_ undefined, we just include the
whole form in the autoload file, just as we do now (generating a
warning). But if loading the file _did_ define it as a macro, we check
its `autoload-macroexpand' property, and proceed as before.
I was curious how many existing ;;;###autoloads this would affect, since
I almost always see it used with `defun' or `define-minor-mode'. I
looked through the entire emacs-30 lisp codebase[1] and could only find
`define-erc-module' as the car of a top-level autoload form which wasn't
already a known function, macro, or special form. I repeated this
exercise among my 171 installed packages, and found only:
Unknown autoload car: cape-char--define
Unknown autoload car: define-erc-module
Importantly, in all of these cases, they are actually using adorned
magic comments, like:
;;;###autoload (autoload 'cape-tex "cape-char" nil t)
(cape-char--define tex "TeX" ?\\ ?^ ?_)
so not relevant to our proposal (except that they could be improved by
it.)
> I assume there's a concrete use-case which motivated your patch.
> Do you mind sharing it?
I have a large package in development which has a flexible extension
system. I'd like to enable "3rd-party" extensions with a convenience
`define-extension' macro. In addition to defining a minor mode, this
macro will generate various `(put some-extension-mode ...)' statements,
which themselves need to be auto-loaded, as they are used to determine
when to load the extension (including, possibly, at package load time).
[1] Here's the distribution of pure ;;;###autoload forms in the emacs-30
codebase:
defun: 3226
defcustom: 181
define-minor-mode: 173
define-derived-mode: 157
defmacro: 130
defalias: 101
put: 88
defvar: 74
define-obsolete-function-alias: 27
defvar-local: 20
define-overloadable-function: 19
cl-defgeneric: 19
defconst: 15
define-globalized-minor-mode: 15
progn: 12
defclass: 8
add-to-list: 8
cl-defun: 8
defsubst: 7
cl-defmacro: 5
define-mail-user-agent: 4
or: 3
pcase-defmacro: 3
define-global-minor-mode: 2
make-variable-buffer-local: 2
eval-after-load: 2
dolist: 2
define-key: 2
unless: 1
autoload: 1
def-edebug-elem-spec: 1
defvar-keymap: 1
define-inline: 1
when: 1
define-compilation-mode: 1
define-skeleton: 1
let: 1
fset: 1
setq: 1
Created with:
rg -IA 1 -t elisp '^;;;###autoload *$' | perl -ne '$AL{$1}++ if /^\(([^ ]+) /; END { foreach $k (reverse sort { $AL{$a} <=> $AL{$b} } keys %AL) {print "$k: $AL{$k}\n"}}'
This bug report was last modified 27 days ago.
Previous Next
GNU bug tracking system
Copyright (C) 1999 Darren O. Benham,
1997,2003 nCipher Corporation Ltd,
1994-97 Ian Jackson.