重现步骤:
把如下代码作为单独的init.el使用 然后打开emacs29 (最新master编译版本 (事实上这个问题在好几个月前的commit上就存在了))
(toggle-debug-on-quit)
;; (toggle-frame-maximized)
;; (package-initialize)
(require 'files)
(require 'help)
(with-temp-message
(substitute-command-keys
(format
"emacs %s is hang of `commandp' loop via advice to `find-file', \
please hint `\\[keyboard-quit]' to see the backtrace."
emacs-major-version))
(dotimes (cnt 20)
(let ((sym (intern (format "test-advice/cnt-%s" cnt))))
(eval
`(progn
(defun ,sym (&rest _)
nil)
(advice-add 'find-file :before ',sym)))))
(commandp 'find-file))
这个bug 可能是emacs29引入的oclosure包对advice相关的改动造成的。
emacs devel master: dd2973bf504
Stefan Monnier已经修复了这个bug (或许? 因为我测试没问题了)
Commit info:
@ dd2973bf5040d26d29a937d252eeaf2884dca9fb
Author: Stefan Monnier <[email protected]>
AuthorDate: Sat Aug 13 12:03:22 2022 -0400
Commit: Stefan Monnier <[email protected]>
CommitDate: Sat Aug 13 12:04:29 2022 -0400
Parent: a1cf3b96f84 ; Fix documentation of 'deactivate-mark'
nadvice.el: Avoid exponential blow up in interactive-form recursion
* lisp/emacs-lisp/nadvice.el (advice--interactive-form): Sink the call
to `commandp` into the autoloaded function case since it's redundant in
the other branch.
(advice--make-interactive-form): Take just the interactive forms rather
than the actual functions as arguments.
(oclosure-interactive-form): Use `advice--interactive-form` rather than
`commandp` since we'd call `advice--interactive-form` afterwards anyway.
1 file changed, 13 insertions(+), 13 deletions(-)
lisp/emacs-lisp/nadvice.el | 26 +++++++++++++-------------
modified lisp/emacs-lisp/nadvice.el
@@ -167,31 +167,31 @@ advice-eval-interactive-spec
(defun advice--interactive-form (function)
"Like `interactive-form' but tries to avoid autoloading functions."
- (when (commandp function)
- (if (not (and (symbolp function) (autoloadp (indirect-function function))))
- (interactive-form function)
- `(interactive (advice-eval-interactive-spec
+ (if (not (and (symbolp function) (autoloadp (indirect-function function))))
+ (interactive-form function)
+ (when (commandp function)
+ `(interactive (advice--eval-interactive-spec
(cadr (interactive-form ',function)))))))
-(defun advice--make-interactive-form (function main)
+(defun advice--make-interactive-form (iff ifm)
;; TODO: make it so that interactive spec can be a constant which
;; dynamically checks the advice--car/cdr to do its job.
;; For that, advice-eval-interactive-spec needs to be more faithful.
- (let* ((iff (advice--interactive-form function))
- (ifm (advice--interactive-form main))
- (fspec (cadr iff)))
+ (let* ((fspec (cadr iff)))
(when (eq 'function (car-safe fspec)) ;; Macroexpanded lambda?
- (setq fspec (nth 1 fspec)))
+ (setq fspec (eval fspec t)))
(if (functionp fspec)
`(funcall ',fspec ',(cadr ifm))
(cadr (or iff ifm)))))
(cl-defmethod oclosure-interactive-form ((ad advice) &optional _)
- (let ((car (advice--car ad))
- (cdr (advice--cdr ad)))
- (when (or (commandp car) (commandp cdr))
- `(interactive ,(advice--make-interactive-form car cdr)))))
+ (let* ((car (advice--car ad))
+ (cdr (advice--cdr ad))
+ (ifa (advice--interactive-form car))
+ (ifd (advice--interactive-form cdr)))
+ (when (or ifa ifd)
+ `(interactive ,(advice--make-interactive-form ifa ifd)))))
(cl-defmethod cl-print-object ((object advice) stream)
(cl-assert (advice--p object))
稍作调整 先close这个OP了。