summaryrefslogtreecommitdiff
path: root/lisp/emacs-lisp
diff options
context:
space:
mode:
authorYuan Fu <casouri@gmail.com>2022-10-05 14:22:03 -0700
committerYuan Fu <casouri@gmail.com>2022-10-05 14:22:03 -0700
commit7ebbd4efc3d45403cf845d35c36c21756baeeba8 (patch)
treef53223ce7dbd64c079aced6e1a77964d1a8eaa3f /lisp/emacs-lisp
parentcb183f6467401fb5ed2b7fc98ca75be9d943cbe3 (diff)
parent95efafb72664049f8ac825047df3645656cf76f4 (diff)
downloademacs-7ebbd4efc3d45403cf845d35c36c21756baeeba8.tar.gz
emacs-7ebbd4efc3d45403cf845d35c36c21756baeeba8.tar.bz2
emacs-7ebbd4efc3d45403cf845d35c36c21756baeeba8.zip
Merge branch 'master' into feature/tree-sitter
Diffstat (limited to 'lisp/emacs-lisp')
-rw-r--r--lisp/emacs-lisp/backtrace.el1
-rw-r--r--lisp/emacs-lisp/benchmark.el2
-rw-r--r--lisp/emacs-lisp/byte-opt.el34
-rw-r--r--lisp/emacs-lisp/byte-run.el43
-rw-r--r--lisp/emacs-lisp/bytecomp.el8
-rw-r--r--lisp/emacs-lisp/cconv.el51
-rw-r--r--lisp/emacs-lisp/checkdoc.el10
-rw-r--r--lisp/emacs-lisp/cl-extra.el10
-rw-r--r--lisp/emacs-lisp/cl-generic.el32
-rw-r--r--lisp/emacs-lisp/cl-lib.el6
-rw-r--r--lisp/emacs-lisp/cl-macs.el300
-rw-r--r--lisp/emacs-lisp/comp.el51
-rw-r--r--lisp/emacs-lisp/debug.el8
-rw-r--r--lisp/emacs-lisp/easy-mmode.el12
-rw-r--r--lisp/emacs-lisp/edebug.el25
-rw-r--r--lisp/emacs-lisp/eieio-core.el18
-rw-r--r--lisp/emacs-lisp/eieio-opt.el2
-rw-r--r--lisp/emacs-lisp/eieio.el20
-rw-r--r--lisp/emacs-lisp/ert-x.el57
-rw-r--r--lisp/emacs-lisp/generate-lisp-file.el14
-rw-r--r--lisp/emacs-lisp/gv.el19
-rw-r--r--lisp/emacs-lisp/icons.el6
-rw-r--r--lisp/emacs-lisp/lisp-mode.el27
-rw-r--r--lisp/emacs-lisp/loaddefs-gen.el15
-rw-r--r--lisp/emacs-lisp/macroexp.el3
-rw-r--r--lisp/emacs-lisp/nadvice.el47
-rw-r--r--lisp/emacs-lisp/oclosure.el15
-rw-r--r--lisp/emacs-lisp/package.el62
-rw-r--r--lisp/emacs-lisp/re-builder.el3
-rw-r--r--lisp/emacs-lisp/regexp-opt.el1
-rw-r--r--lisp/emacs-lisp/seq.el69
-rw-r--r--lisp/emacs-lisp/shortdoc.el65
-rw-r--r--lisp/emacs-lisp/subr-x.el1
-rw-r--r--lisp/emacs-lisp/testcover.el3
-rw-r--r--lisp/emacs-lisp/vtable.el3
35 files changed, 623 insertions, 420 deletions
diff --git a/lisp/emacs-lisp/backtrace.el b/lisp/emacs-lisp/backtrace.el
index 70473770d16..4ffe6f573c6 100644
--- a/lisp/emacs-lisp/backtrace.el
+++ b/lisp/emacs-lisp/backtrace.el
@@ -209,7 +209,6 @@ frames where the source code location is known.")
"v" #'backtrace-toggle-locals
"#" #'backtrace-toggle-print-circle
":" #'backtrace-toggle-print-gensym
- "s" #'backtrace-goto-source
"RET" #'backtrace-help-follow-symbol
"+" #'backtrace-multi-line
"-" #'backtrace-single-line
diff --git a/lisp/emacs-lisp/benchmark.el b/lisp/emacs-lisp/benchmark.el
index 882b1d68c48..47bc3a45245 100644
--- a/lisp/emacs-lisp/benchmark.el
+++ b/lisp/emacs-lisp/benchmark.el
@@ -70,7 +70,7 @@ number of repetitions actually used."
(defun benchmark--adaptive (func time)
"Measure the run time of FUNC, calling it enough times to last TIME seconds.
-Result is (REPETITIONS . DATA) where DATA is as returned by `branchmark-call'."
+Result is (REPETITIONS . DATA) where DATA is as returned by `benchmark-call'."
(named-let loop ((repetitions 1)
(data (let ((x (list 0))) (setcdr x x) x)))
;; (message "Running %d iteration" repetitions)
diff --git a/lisp/emacs-lisp/byte-opt.el b/lisp/emacs-lisp/byte-opt.el
index 27b0d33d3ef..5ef2d7fe827 100644
--- a/lisp/emacs-lisp/byte-opt.el
+++ b/lisp/emacs-lisp/byte-opt.el
@@ -737,7 +737,7 @@ for speeding up processing.")
reverse nreverse sort))
(setq form (nth 1 form))
t)
- ((memq head '(mapc setq setcar setcdr puthash))
+ ((memq head '(mapc setq setcar setcdr puthash set))
(setq form (nth 2 form))
t)
((memq head '(aset put function-put))
@@ -793,6 +793,7 @@ for speeding up processing.")
sxhash sxhash-equal sxhash-eq sxhash-eql
sxhash-equal-including-properties
make-marker copy-marker point-marker mark-marker
+ set-marker
kbd key-description
always))
t)
@@ -811,7 +812,7 @@ for speeding up processing.")
(defun byte-compile-nilconstp (form)
"Return non-nil if FORM always evaluates to a nil value."
(setq form (byte-opt--bool-value-form form))
- (or (not form) ; assume (quote nil) always being normalised to nil
+ (or (not form) ; assume (quote nil) always being normalized to nil
(and (consp form)
(let ((head (car form)))
;; FIXME: There are many other expressions that are statically nil.
@@ -1183,7 +1184,7 @@ See Info node `(elisp) Integer Basics'."
(if (equal new-args (cdr form))
;; Input is unchanged: keep original form, and don't represent
;; a nil result explicitly because that would lead to infinite
- ;; growth when the optimiser is iterated.
+ ;; growth when the optimizer is iterated.
(setq nil-result nil)
(setq form (cons (car form) new-args)))
@@ -1531,15 +1532,16 @@ See Info node `(elisp) Integer Basics'."
(put 'set 'byte-optimizer #'byte-optimize-set)
(defun byte-optimize-set (form)
- (let ((var (car-safe (cdr-safe form))))
- (cond
- ((and (eq (car-safe var) 'quote) (consp (cdr var)))
- `(setq ,(cadr var) ,@(cddr form)))
- ((and (eq (car-safe var) 'make-local-variable)
- (eq (car-safe (setq var (car-safe (cdr var)))) 'quote)
- (consp (cdr var)))
- `(progn ,(cadr form) (setq ,(cadr var) ,@(cddr form))))
- (t form))))
+ (pcase (cdr form)
+ ;; Make sure we only turn `set' into `setq' for dynamic variables.
+ (`((quote ,(and var (guard (and (symbolp var)
+ (not (macroexp--const-symbol-p var))
+ (not (assq var byte-optimize--lexvars))))))
+ ,newval)
+ `(setq ,var ,newval))
+ (`(,(and ml `(make-local-variable ,(and v `(quote ,_)))) ,newval)
+ `(progn ,ml (,(car form) ,v ,newval)))
+ (_ form)))
;; enumerating those functions which need not be called if the returned
;; value is not used. That is, something like
@@ -1999,20 +2001,20 @@ If FOR-EFFECT is non-nil, the return value is assumed to be of no importance."
(setq keep-going t)
(setq tmp (aref byte-stack+-info (symbol-value (car lap0))))
(setq rest (cdr rest))
- (cond ((= tmp 1)
+ (cond ((eql tmp 1)
(byte-compile-log-lap
" %s discard\t-->\t<deleted>" lap0)
(setq lap (delq lap0 (delq lap1 lap))))
- ((= tmp 0)
+ ((eql tmp 0)
(byte-compile-log-lap
" %s discard\t-->\t<deleted> discard" lap0)
(setq lap (delq lap0 lap)))
- ((= tmp -1)
+ ((eql tmp -1)
(byte-compile-log-lap
" %s discard\t-->\tdiscard discard" lap0)
(setcar lap0 'byte-discard)
(setcdr lap0 0))
- ((error "Optimizer error: too much on the stack"))))
+ (t (error "Optimizer error: too much on the stack"))))
;;
;; goto*-X X: --> X:
;;
diff --git a/lisp/emacs-lisp/byte-run.el b/lisp/emacs-lisp/byte-run.el
index 9a56ba0f7ad..9db84c31b88 100644
--- a/lisp/emacs-lisp/byte-run.el
+++ b/lisp/emacs-lisp/byte-run.el
@@ -112,44 +112,6 @@ So far, FUNCTION can only be a symbol, not a lambda expression."
(function-put 'defmacro 'doc-string-elt 3)
(function-put 'defmacro 'lisp-indent-function 2)
-;; `macro-declaration-function' are both obsolete (as marked at the end of this
-;; file) but used in many .elc files.
-
-;; We don't use #' here, because it's an obsolete function, and we
-;; can't use `with-suppressed-warnings' here due to how this file is
-;; used in the bootstrapping process.
-(defvar macro-declaration-function 'macro-declaration-function
- "Function to process declarations in a macro definition.
-The function will be called with two args MACRO and DECL.
-MACRO is the name of the macro being defined.
-DECL is a list `(declare ...)' containing the declarations.
-The value the function returns is not used.")
-
-(defalias 'macro-declaration-function
- #'(lambda (macro decl)
- "Process a declaration found in a macro definition.
-This is set as the value of the variable `macro-declaration-function'.
-MACRO is the name of the macro being defined.
-DECL is a list `(declare ...)' containing the declarations.
-The return value of this function is not used."
- ;; We can't use `dolist' or `cadr' yet for bootstrapping reasons.
- (let (d)
- ;; Ignore the first element of `decl' (it's always `declare').
- (while (setq decl (cdr decl))
- (setq d (car decl))
- (if (and (consp d)
- (listp (cdr d))
- (null (cdr (cdr d))))
- (cond ((eq (car d) 'indent)
- (put macro 'lisp-indent-function (car (cdr d))))
- ((eq (car d) 'debug)
- (put macro 'edebug-form-spec (car (cdr d))))
- ((eq (car d) 'doc-string)
- (put macro 'doc-string-elt (car (cdr d))))
- (t
- (message "Unknown declaration %s" d)))
- (message "Invalid declaration %s" d))))))
-
;; We define macro-declaration-alist here because it is needed to
;; handle declarations in macro definitions and this is the first file
;; loaded by loadup.el that uses declarations in macros. We specify
@@ -771,9 +733,4 @@ type is. This defaults to \"INFO\"."
;; (file-format emacs19))"
;; nil)
-(make-obsolete-variable 'macro-declaration-function
- 'macro-declarations-alist "24.3")
-(make-obsolete 'macro-declaration-function
- 'macro-declarations-alist "24.3")
-
;;; byte-run.el ends here
diff --git a/lisp/emacs-lisp/bytecomp.el b/lisp/emacs-lisp/bytecomp.el
index a16486dc31c..03c45e44a56 100644
--- a/lisp/emacs-lisp/bytecomp.el
+++ b/lisp/emacs-lisp/bytecomp.el
@@ -1705,12 +1705,12 @@ URLs."
(+ " " (or
;; Arguments.
(+ (or (syntax symbol)
- (any word "-/:[]&=().?^\\#'")))
+ (any word "-/:[]&=()<>.,?^\\#*'\"")))
;; Argument that is a list.
(seq "(" (* (not ")")) ")")))
")")))
""
- ;; Heuristic: We can't reliably do `subsititute-command-keys'
+ ;; Heuristic: We can't reliably do `substitute-command-keys'
;; substitutions, since the value of a keymap in general can't be
;; known at compile time. So instead, we assume that these
;; substitutions are of some length N.
@@ -3104,8 +3104,8 @@ lambda-expression."
;; Check that the bit after the `interactive' spec is
;; just a list of symbols (i.e., modes).
(unless (seq-every-p #'symbolp (cdr (cdr int)))
- (byte-compile-warn-x int "malformed interactive specc: %s"
- int))
+ (byte-compile-warn-x
+ int "malformed `interactive' specification: %s" int))
(setq command-modes (cdr (cdr int)))
;; If the interactive spec is a call to `list', don't
;; compile it, because `call-interactively' looks at the
diff --git a/lisp/emacs-lisp/cconv.el b/lisp/emacs-lisp/cconv.el
index 7f95fa94fa1..23d0f121948 100644
--- a/lisp/emacs-lisp/cconv.el
+++ b/lisp/emacs-lisp/cconv.el
@@ -137,6 +137,11 @@ is less than this number.")
;; Alist associating to each function body the list of its free variables.
)
+(defvar cconv--interactive-form-funs
+ ;; Table used to hold the functions we create internally for
+ ;; interactive forms.
+ (make-hash-table :test #'eq :weakness 'key))
+
;;;###autoload
(defun cconv-closure-convert (form)
"Main entry point for closure conversion.
@@ -503,9 +508,23 @@ places where they originally did not directly appear."
cond-forms)))
(`(function (lambda ,args . ,body) . ,_)
- (let ((docstring (if (eq :documentation (car-safe (car body)))
- (cconv-convert (cadr (pop body)) env extend))))
- (cconv--convert-function args body env form docstring)))
+ (let* ((docstring (if (eq :documentation (car-safe (car body)))
+ (cconv-convert (cadr (pop body)) env extend)))
+ (bf (if (stringp (car body)) (cdr body) body))
+ (if (when (eq 'interactive (car-safe (car bf)))
+ (gethash form cconv--interactive-form-funs)))
+ (cif (when if (cconv-convert if env extend)))
+ (_ (pcase cif
+ (`#'(lambda () ,form) (setf (cadr (car bf)) form) (setq cif nil))
+ ('nil nil)
+ ;; The interactive form needs special treatment, so the form
+ ;; inside the `interactive' won't be used any further.
+ (_ (setf (cadr (car bf)) nil))))
+ (cf (cconv--convert-function args body env form docstring)))
+ (if (not cif)
+ ;; Normal case, the interactive form needs no special treatment.
+ cf
+ `(cconv--interactive-helper ,cf ,cif))))
(`(internal-make-closure . ,_)
(byte-compile-report-error
@@ -589,12 +608,12 @@ places where they originally did not directly appear."
(cconv-convert arg env extend))
(cons fun args)))))))
- (`(interactive . ,forms)
- `(,(car form) . ,(mapcar (lambda (form)
- (cconv-convert form nil nil))
- forms)))
+ ;; The form (if any) is converted beforehand as part of the `lambda' case.
+ (`(interactive . ,_) form)
- (`(declare . ,_) form) ;The args don't contain code.
+ ;; `declare' should now be macro-expanded away (and if they're not, we're
+ ;; in trouble because they *can* contain code nowadays).
+ ;; (`(declare . ,_) form) ;The args don't contain code.
(`(oclosure--fix-type (ignore . ,vars) ,exp)
(dolist (var vars)
@@ -739,6 +758,13 @@ This function does not return anything but instead fills the
(`(function (lambda ,vrs . ,body-forms))
(when (eq :documentation (car-safe (car body-forms)))
(cconv-analyze-form (cadr (pop body-forms)) env))
+ (let ((bf (if (stringp (car body-forms)) (cdr body-forms) body-forms)))
+ (when (eq 'interactive (car-safe (car bf)))
+ (let ((if (cadr (car bf))))
+ (unless (macroexp-const-p if) ;Optimize this common case.
+ (let ((f `#'(lambda () ,if)))
+ (setf (gethash form cconv--interactive-form-funs) f)
+ (cconv-analyze-form f env))))))
(cconv--analyze-function vrs body-forms env form))
(`(setq ,var ,expr)
@@ -803,13 +829,8 @@ This function does not return anything but instead fills the
(cconv-analyze-form fun env)))
(dolist (form args) (cconv-analyze-form form env)))
- (`(interactive . ,forms)
- ;; These appear within the function body but they don't have access
- ;; to the function's arguments.
- ;; We could extend this to allow interactive specs to refer to
- ;; variables in the function's enclosing environment, but it doesn't
- ;; seem worth the trouble.
- (dolist (form forms) (cconv-analyze-form form nil)))
+ ;; The form (if any) is converted beforehand as part of the `lambda' case.
+ (`(interactive . ,_) nil)
;; `declare' should now be macro-expanded away (and if they're not, we're
;; in trouble because they *can* contain code nowadays).
diff --git a/lisp/emacs-lisp/checkdoc.el b/lisp/emacs-lisp/checkdoc.el
index a5ab3a50ff2..3f9bc28e0b0 100644
--- a/lisp/emacs-lisp/checkdoc.el
+++ b/lisp/emacs-lisp/checkdoc.el
@@ -250,7 +250,7 @@ with these words enabled."
(defvar checkdoc-ispell-lisp-words
'("alist" "emacs" "etags" "keymap" "paren" "regexp" "sexp")
"List of words that are correct when spell-checking Lisp documentation.")
-;;;###autoload(put 'checkdoc-ispell-list-words 'safe-local-variable #'checkdoc-list-of-strings-p)
+;;;###autoload(put 'checkdoc-ispell-list-words 'safe-local-variable #'list-of-strings-p)
(defcustom checkdoc-max-keyref-before-warn nil
"If non-nil, number of \\\\=[command-to-keystroke] tokens allowed in a doc string.
@@ -281,8 +281,6 @@ Currently, all recognized keywords must be on `finder-known-keywords'."
:version "25.1"
:type 'boolean)
-(define-obsolete-variable-alias 'checkdoc-style-hooks
- 'checkdoc-style-functions "24.3")
(defvar checkdoc-style-functions nil
"Hook run after the standard style check is completed.
All functions must return nil or a string representing the error found.
@@ -292,8 +290,6 @@ Each hook is called with two parameters, (DEFUNINFO ENDPOINT).
DEFUNINFO is the return value of `checkdoc-defun-info'. ENDPOINT is the
location of end of the documentation string.")
-(define-obsolete-variable-alias 'checkdoc-comment-style-hooks
- 'checkdoc-comment-style-functions "24.3")
(defvar checkdoc-comment-style-functions nil
"Hook run after the standard comment style check is completed.
Must return nil if no errors are found, or a string describing the
@@ -324,7 +320,7 @@ These words are ignored when unquoted symbols are searched for.
This should be set in an Emacs Lisp file's local variables."
:type '(repeat (string :tag "Word"))
:version "28.1")
-;;;###autoload(put 'checkdoc-symbol-words 'safe-local-variable #'checkdoc-list-of-strings-p)
+;;;###autoload(put 'checkdoc-symbol-words 'safe-local-variable #'list-of-strings-p)
(defcustom checkdoc-column-zero-backslash-before-paren t
"Non-nil means to warn if there is no \"\\\" before \"(\" in column zero.
@@ -364,9 +360,9 @@ large number of libraries means it is impractical to fix all
of these warnings masse. In almost any other case, setting
this to anything but t is likely to be counter-productive.")
-;;;###autoload
(defun checkdoc-list-of-strings-p (obj)
"Return t when OBJ is a list of strings."
+ (declare (obsolete list-of-strings-p "29.1"))
;; this is a function so it might be shared by checkdoc-proper-noun-list
;; and/or checkdoc-ispell-lisp-words in the future
(and (listp obj)
diff --git a/lisp/emacs-lisp/cl-extra.el b/lisp/emacs-lisp/cl-extra.el
index 607810ee141..7c7f027d777 100644
--- a/lisp/emacs-lisp/cl-extra.el
+++ b/lisp/emacs-lisp/cl-extra.el
@@ -772,7 +772,7 @@ PROPLIST is a list of the sort returned by `symbol-plist'.
(help-insert-xref-button
(help-fns-short-filename location)
'cl-type-definition type location 'define-type)
- (insert (substitute-command-keys "'")))
+ (insert (substitute-quotes "'")))
(insert ".\n")
;; Parents.
@@ -782,7 +782,7 @@ PROPLIST is a list of the sort returned by `symbol-plist'.
(insert " Inherits from ")
(while (setq cur (pop pl))
(setq cur (cl--class-name cur))
- (insert (substitute-command-keys "`"))
+ (insert (substitute-quotes "`"))
(help-insert-xref-button (symbol-name cur)
'cl-help-type cur)
(insert (substitute-command-keys (if pl "', " "'"))))
@@ -796,7 +796,7 @@ PROPLIST is a list of the sort returned by `symbol-plist'.
(when ch
(insert " Children ")
(while (setq cur (pop ch))
- (insert (substitute-command-keys "`"))
+ (insert (substitute-quotes "`"))
(help-insert-xref-button (symbol-name cur)
'cl-help-type cur)
(insert (substitute-command-keys (if ch "', " "'"))))
@@ -815,10 +815,10 @@ PROPLIST is a list of the sort returned by `symbol-plist'.
(when generics
(insert (propertize "Specialized Methods:\n\n" 'face 'bold))
(dolist (generic generics)
- (insert (substitute-command-keys "`"))
+ (insert (substitute-quotes "`"))
(help-insert-xref-button (symbol-name generic)
'help-function generic)
- (insert (substitute-command-keys "'"))
+ (insert (substitute-quotes "'"))
(pcase-dolist (`(,qualifiers ,args ,doc)
(cl--generic-method-documentation generic type))
(insert (format " %s%S\n" qualifiers args)
diff --git a/lisp/emacs-lisp/cl-generic.el b/lisp/emacs-lisp/cl-generic.el
index 0560ddda268..b3ade3b8943 100644
--- a/lisp/emacs-lisp/cl-generic.el
+++ b/lisp/emacs-lisp/cl-generic.el
@@ -94,11 +94,6 @@
;; This second one is closely related to what we do here (and that's
;; the name "generalizer" comes from).
-;; The autoloads.el mechanism which adds package--builtin-versions
-;; maintenance to loaddefs.el doesn't work for preloaded packages (such
-;; as this one), so we have to do it by hand!
-(push (purecopy '(cl-generic 1 0)) package--builtin-versions)
-
;; Note: For generic functions that dispatch on several arguments (i.e. those
;; which use the multiple-dispatch feature), we always use the same "tagcodes"
;; and the same set of arguments on which to dispatch. This works, but is
@@ -425,11 +420,13 @@ the specializer used will be the one returned by BODY."
;; only called with explicit arguments.
(uses-cnm (macroexp--fgrep `((,cnm) (,nmp)) nbody))
(λ-lift (mapcar #'car uses-cnm)))
- (if (not uses-cnm)
- (cons nil
- `#'(lambda (,@args)
- ,@(car parsed-body)
- ,nbody))
+ (cond
+ ((not uses-cnm)
+ (cons nil
+ `#'(lambda (,@args)
+ ,@(car parsed-body)
+ ,nbody)))
+ (lexical-binding
(cons 'curried
`#'(lambda (,nm) ;Called when constructing the effective method.
(let ((,nmp (if (cl--generic-isnot-nnm-p ,nm)
@@ -465,7 +462,20 @@ the specializer used will be the one returned by BODY."
;; A destructuring-bind would do the trick
;; as well when/if it's more efficient.
(apply (lambda (,@λ-lift ,@args) ,nbody)
- ,@λ-lift ,arglist)))))))))
+ ,@λ-lift ,arglist)))))))
+ (t
+ (cons t
+ `#'(lambda (,cnm ,@args)
+ ,@(car parsed-body)
+ ,(macroexp-warn-and-return
+ "cl-defmethod used without lexical-binding"
+ (if (not (assq nmp uses-cnm))
+ nbody
+ `(let ((,nmp (lambda ()
+ (cl--generic-isnot-nnm-p ,cnm))))
+ ,nbody))
+ 'lexical t)))))
+ ))
(f (error "Unexpected macroexpansion result: %S" f))))))
(put 'cl-defmethod 'function-documentation
diff --git a/lisp/emacs-lisp/cl-lib.el b/lisp/emacs-lisp/cl-lib.el
index a54fa21fa96..b83b44974d3 100644
--- a/lisp/emacs-lisp/cl-lib.el
+++ b/lisp/emacs-lisp/cl-lib.el
@@ -90,12 +90,6 @@
(defvar cl--optimize-safety 1)
;;;###autoload
-(define-obsolete-variable-alias
- ;; This alias is needed for compatibility with .elc files that use defstruct
- ;; and were compiled with Emacs<24.3.
- 'custom-print-functions 'cl-custom-print-functions "24.3")
-
-;;;###autoload
(defvar cl-custom-print-functions nil
"This is a list of functions that format user objects for printing.
Each function is called in turn with three arguments: the object, the
diff --git a/lisp/emacs-lisp/cl-macs.el b/lisp/emacs-lisp/cl-macs.el
index 80ca43c902a..beafee1d631 100644
--- a/lisp/emacs-lisp/cl-macs.el
+++ b/lisp/emacs-lisp/cl-macs.el
@@ -775,14 +775,34 @@ compared by `eql'.
\(fn EXPR (KEYLIST BODY...)...)"
(declare (indent 1) (debug (form &rest (sexp body))))
(macroexp-let2 macroexp-copyable-p temp expr
- (let* ((head-list nil))
+ (let* ((head-list nil)
+ (has-otherwise nil))
`(cond
,@(mapcar
(lambda (c)
- (cons (cond ((memq (car c) '(t otherwise)) t)
+ (cons (cond (has-otherwise
+ (error "Misplaced t or `otherwise' clause"))
+ ((memq (car c) '(t otherwise))
+ (setq has-otherwise t)
+ t)
((eq (car c) 'cl--ecase-error-flag)
`(error "cl-ecase failed: %s, %s"
,temp ',(reverse head-list)))
+ ((null (car c))
+ (macroexp-warn-and-return
+ "Case nil will never match"
+ nil 'suspicious))
+ ((and (consp (car c)) (cdar c) (not (cddar c))
+ (memq (caar c) '(quote function)))
+ (macroexp-warn-and-return
+ (format-message
+ (concat "Case %s will match `%s'. If "
+ "that's intended, write %s "
+ "instead. Otherwise, don't "
+ "quote `%s'.")
+ (car c) (caar c) (list (cadar c) (caar c))
+ (cadar c))
+ `(cl-member ,temp ',(car c)) 'suspicious))
((listp (car c))
(setq head-list (append (car c) head-list))
`(cl-member ,temp ',(car c)))
@@ -2261,139 +2281,131 @@ This is like `cl-flet', but for macros instead of functions.
(eval `(function (lambda ,@res)) t))
macroexpand-all-environment))))))
-(defun cl--sm-macroexpand (orig-fun exp &optional env)
+(defun cl--sm-macroexpand (exp &optional env)
+ "Special macro expander used inside `cl-symbol-macrolet'."
+ ;; FIXME: Arguably, this should be the official definition of `macroexpand'.
+ (while (not (eq exp (setq exp (macroexpand-1 exp env)))))
+ exp)
+
+(defun cl--sm-macroexpand-1 (orig-fun exp &optional env)
"Special macro expander advice used inside `cl-symbol-macrolet'.
-This function extends `macroexpand' during macro expansion
+This function extends `macroexpand-1' during macro expansion
of `cl-symbol-macrolet' to additionally expand symbol macros."
- (let ((macroexpand-all-environment env)
+ (let ((exp (funcall orig-fun exp env))
(venv (alist-get :cl-symbol-macros env)))
- (while
- (progn
- (setq exp (funcall orig-fun exp env))
- (pcase exp
- ((pred symbolp)
- ;; Perform symbol-macro expansion.
- (let ((symval (assq exp venv)))
- (when symval
- (setq exp (cadr symval)))))
- (`(setq . ,args)
- ;; Convert setq to setf if required by symbol-macro expansion.
- (let ((convert nil)
- (rargs nil))
- (while args
- (let ((place (pop args)))
- ;; Here, we know `place' should be a symbol.
- (while
- (let ((symval (assq place venv)))
- (when symval
- (setq place (cadr symval))
- (if (symbolp place)
- t ;Repeat.
- (setq convert t)
- nil))))
- (push place rargs)
- (push (pop args) rargs)))
- (setq exp (cons (if convert 'setf 'setq)
- (nreverse rargs)))
- convert))
- ;; CL's symbol-macrolet used to treat re-bindings as candidates for
- ;; expansion (turning the let into a letf if needed), contrary to
- ;; Common-Lisp where such re-bindings hide the symbol-macro.
- ;; Not sure if there actually is code out there which depends
- ;; on this behavior (haven't found any yet).
- ;; Such code should explicitly use `cl-letf' instead, I think.
- ;;
- ;; (`(,(or `let `let*) . ,(or `(,bindings . ,body) pcase--dontcare))
- ;; (let ((letf nil) (found nil) (nbs ()))
- ;; (dolist (binding bindings)
- ;; (let* ((var (if (symbolp binding) binding (car binding)))
- ;; (sm (assq var venv)))
- ;; (push (if (not (cdr sm))
- ;; binding
- ;; (let ((nexp (cadr sm)))
- ;; (setq found t)
- ;; (unless (symbolp nexp) (setq letf t))
- ;; (cons nexp (cdr-safe binding))))
- ;; nbs)))
- ;; (when found
- ;; (setq exp `(,(if letf
- ;; (if (eq (car exp) 'let) 'cl-letf 'cl-letf*)
- ;; (car exp))
- ;; ,(nreverse nbs)
- ;; ,@body)))))
- ;;
- ;; We implement the Common-Lisp behavior, instead (see bug#26073):
- ;; The behavior of CL made sense in a dynamically scoped
- ;; language, but nowadays, lexical scoping semantics is more often
- ;; expected.
- (`(,(or 'let 'let*) . ,(or `(,bindings . ,body) pcase--dontcare))
- (let ((nbs ()) (found nil))
- (dolist (binding bindings)
- (let* ((var (if (symbolp binding) binding (car binding)))
- (val (and found (consp binding) (eq 'let* (car exp))
- (list (macroexpand-all (cadr binding)
- env)))))
- (push (if (assq var venv)
- ;; This binding should hide "its" surrounding
- ;; symbol-macro, but given the way macroexpand-all
- ;; works (i.e. the `env' we receive as input will
- ;; be (re)applied to the code we return), we can't
- ;; prevent application of `env' to the
- ;; sub-expressions, so we need to α-rename this
- ;; variable instead.
- (let ((nvar (make-symbol (symbol-name var))))
- (setq found t)
- (push (list var nvar) venv)
- (push (cons :cl-symbol-macros venv) env)
- (cons nvar (or val (cdr-safe binding))))
- (if val (cons var val) binding))
- nbs)))
- (when found
- (setq exp `(,(car exp)
- ,(nreverse nbs)
- ,@(macroexp-unprogn
- (macroexpand-all (macroexp-progn body)
- env)))))
- nil))
- ;; Do the same as for `let' but for variables introduced
- ;; via other means, such as `lambda' and `condition-case'.
- (`(function (lambda ,args . ,body))
- (let ((nargs ()) (found nil))
- (dolist (var args)
- (push (cond
- ((memq var '(&optional &rest)) var)
- ((assq var venv)
- (let ((nvar (make-symbol (symbol-name var))))
- (setq found t)
- (push (list var nvar) venv)
- (push (cons :cl-symbol-macros venv) env)
- nvar))
- (t var))
- nargs))
- (when found
- (setq exp `(function
- (lambda ,(nreverse nargs)
- . ,(mapcar (lambda (exp)
- (macroexpand-all exp env))
- body)))))
- nil))
- ((and `(condition-case ,var ,exp . ,clauses)
- (guard (assq var venv)))
- (let ((nvar (make-symbol (symbol-name var))))
- (push (list var nvar) venv)
- (push (cons :cl-symbol-macros venv) env)
- (setq exp
- `(condition-case ,nvar ,(macroexpand-all exp env)
- . ,(mapcar
- (lambda (clause)
- `(,(car clause)
- . ,(mapcar (lambda (exp)
- (macroexpand-all exp env))
- (cdr clause))))
- clauses)))
- nil))
- )))
- exp))
+ (pcase exp
+ ((pred symbolp)
+ ;; Try symbol-macro expansion.
+ (let ((symval (assq exp venv)))
+ (if symval (cadr symval) exp)))
+ (`(setq . ,args)
+ ;; Convert setq to setf if required by symbol-macro expansion.
+ (let ((convert nil))
+ (while args
+ (let* ((place (pop args))
+ ;; Here, we know `place' should be a symbol.
+ (symval (assq place venv)))
+ (pop args)
+ (when symval
+ (setq convert t))))
+ (if convert
+ (cons 'setf (cdr exp))
+ exp)))
+ ;; CL's symbol-macrolet used to treat re-bindings as candidates for
+ ;; expansion (turning the let into a letf if needed), contrary to
+ ;; Common-Lisp where such re-bindings hide the symbol-macro.
+ ;; Not sure if there actually is code out there which depends
+ ;; on this behavior (haven't found any yet).
+ ;; Such code should explicitly use `cl-letf' instead, I think.
+ ;;
+ ;; (`(,(or `let `let*) . ,(or `(,bindings . ,body) pcase--dontcare))
+ ;; (let ((letf nil) (found nil) (nbs ()))
+ ;; (dolist (binding bindings)
+ ;; (let* ((var (if (symbolp binding) binding (car binding)))
+ ;; (sm (assq var venv)))
+ ;; (push (if (not (cdr sm))
+ ;; binding
+ ;; (let ((nexp (cadr sm)))
+ ;; (setq found t)
+ ;; (unless (symbolp nexp) (setq letf t))
+ ;; (cons nexp (cdr-safe binding))))
+ ;; nbs)))
+ ;; (when found
+ ;; (setq exp `(,(if letf
+ ;; (if (eq (car exp) 'let) 'cl-letf 'cl-letf*)
+ ;; (car exp))
+ ;; ,(nreverse nbs)
+ ;; ,@body)))))
+ ;;
+ ;; We implement the Common-Lisp behavior, instead (see bug#26073):
+ ;; The behavior of CL made sense in a dynamically scoped
+ ;; language, but nowadays, lexical scoping semantics is more often
+ ;; expected.
+ (`(,(or 'let 'let*) . ,(or `(,bindings . ,body) pcase--dontcare))
+ (let ((nbs ()) (found nil))
+ (dolist (binding bindings)
+ (let* ((var (if (symbolp binding) binding (car binding)))
+ (val (and found (consp binding) (eq 'let* (car exp))
+ (list (macroexpand-all (cadr binding)
+ env)))))
+ (push (if (assq var venv)
+ ;; This binding should hide "its" surrounding
+ ;; symbol-macro, but given the way macroexpand-all
+ ;; works (i.e. the `env' we receive as input will
+ ;; be (re)applied to the code we return), we can't
+ ;; prevent application of `env' to the
+ ;; sub-expressions, so we need to α-rename this
+ ;; variable instead.
+ (let ((nvar (make-symbol (symbol-name var))))
+ (setq found t)
+ (push (list var nvar) venv)
+ (push (cons :cl-symbol-macros venv) env)
+ (cons nvar (or val (cdr-safe binding))))
+ (if val (cons var val) binding))
+ nbs)))
+ (if found
+ `(,(car exp)
+ ,(nreverse nbs)
+ ,@(macroexp-unprogn
+ (macroexpand-all (macroexp-progn body)
+ env)))
+ exp)))
+ ;; Do the same as for `let' but for variables introduced
+ ;; via other means, such as `lambda' and `condition-case'.
+ (`(function (lambda ,args . ,body))
+ (let ((nargs ()) (found nil))
+ (dolist (var args)
+ (push (cond
+ ((memq var '(&optional &rest)) var)
+ ((assq var venv)
+ (let ((nvar (make-symbol (symbol-name var))))
+ (setq found t)
+ (push (list var nvar) venv)
+ (push (cons :cl-symbol-macros venv) env)
+ nvar))
+ (t var))
+ nargs))
+ (if found
+ `(function
+ (lambda ,(nreverse nargs)
+ . ,(mapcar (lambda (exp)
+ (macroexpand-all exp env))
+ body)))
+ exp)))
+ ((and `(condition-case ,var ,exp . ,clauses)
+ (guard (assq var venv)))
+ (let ((nvar (make-symbol (symbol-name var))))
+ (push (list var nvar) venv)
+ (push (cons :cl-symbol-macros venv) env)
+ `(condition-case ,nvar ,(macroexpand-all exp env)
+ . ,(mapcar
+ (lambda (clause)
+ `(,(car clause)
+ . ,(mapcar (lambda (exp)
+ (macroexpand-all exp env))
+ (cdr clause))))
+ clauses))))
+ (_ exp))))
;;;###autoload
(defmacro cl-symbol-macrolet (bindings &rest body)
@@ -2412,7 +2424,8 @@ by EXPANSION, and (setq NAME ...) will act like (setf EXPANSION ...).
(unwind-protect
(progn
(unless advised
- (advice-add 'macroexpand :around #'cl--sm-macroexpand))
+ (advice-add 'macroexpand :override #'cl--sm-macroexpand)
+ (advice-add 'macroexpand-1 :around #'cl--sm-macroexpand-1))
(let* ((venv (cdr (assq :cl-symbol-macros
macroexpand-all-environment)))
(expansion
@@ -2428,7 +2441,8 @@ by EXPANSION, and (setq NAME ...) will act like (setf EXPANSION ...).
expansion nil nil rev-malformed-bindings))
expansion)))
(unless advised
- (advice-remove 'macroexpand #'cl--sm-macroexpand)))))
+ (advice-remove 'macroexpand #'cl--sm-macroexpand)
+ (advice-remove 'macroexpand-1 #'cl--sm-macroexpand-1)))))
;;;###autoload
(defmacro cl-with-gensyms (names &rest body)
@@ -2762,11 +2776,17 @@ Each PLACE may be a symbol, or any generalized variable allowed by `setf'.
(funcall setter vold)))
binds))))
(let* ((binding (car bindings))
- (place (macroexpand (car binding) macroexpand-all-environment)))
+ (place (car binding)))
(gv-letplace (getter setter) place
(macroexp-let2 nil vnew (cadr binding)
- (if (symbolp place)
+ (if (and (symbolp place)
+ ;; `place' could be some symbol-macro.
+ (eq place getter))
;; Special-case for simple variables.
+ ;; FIXME: We currently only use this special case when `place'
+ ;; is a simple var. Should we also use it when the
+ ;; macroexpansion of `place' is a simple var (i.e. when
+ ;; getter+setter is the same as that of a simple var)?
(cl--letf (cdr bindings)
(cons `(,getter ,(if (cdr binding) vnew getter))
simplebinds)
@@ -3105,7 +3125,7 @@ To see the documentation for a defined struct type, use
`(and ,pred-form t)))
forms)
(push `(eval-and-compile
- (put ',name 'cl-deftype-satisfies ',predicate))
+ (define-symbol-prop ',name 'cl-deftype-satisfies ',predicate))
forms))
(let ((pos 0) (descp descs))
(while descp
@@ -3570,7 +3590,7 @@ and then returning foo."
(cl-defun ,fname ,(if (memq '&whole args) (delq '&whole args)
(cons '_cl-whole-arg args))
,@body)
- (put ',func 'compiler-macro #',fname))))
+ (define-symbol-prop ',func 'compiler-macro #',fname))))
;;;###autoload
(defun cl-compiler-macroexpand (form)
@@ -3679,8 +3699,8 @@ macro that returns its `&whole' argument."
The type name can then be used in `cl-typecase', `cl-check-type', etc."
(declare (debug cl-defmacro) (doc-string 3) (indent 2))
`(cl-eval-when (compile load eval)
- (put ',name 'cl-deftype-handler
- (cl-function (lambda (&cl-defs ('*) ,@arglist) ,@body)))))
+ (define-symbol-prop ',name 'cl-deftype-handler
+ (cl-function (lambda (&cl-defs ('*) ,@arglist) ,@body)))))
(cl-deftype extended-char () '(and character (not base-char)))
;; Define fixnum so `cl-typep' recognize it and the type check emitted
diff --git a/lisp/emacs-lisp/comp.el b/lisp/emacs-lisp/comp.el
index e10443588e4..6656b7e57c1 100644
--- a/lisp/emacs-lisp/comp.el
+++ b/lisp/emacs-lisp/comp.el
@@ -178,14 +178,15 @@ and above."
:type '(repeat string)
:version "28.1")
-(defcustom native-comp-driver-options nil
+(defcustom native-comp-driver-options (when (eq system-type 'darwin)
+ '("-Wl,-w"))
"Options passed verbatim to the native compiler's back-end driver.
Note that not all options are meaningful; typically only the options
affecting the assembler and linker are likely to be useful.
Passing these options is only available in libgccjit version 9
and above."
- :type '(repeat string) ; FIXME is this right?
+ :type '(repeat string)
:version "28.1")
(defcustom comp-libgccjit-reproducer nil
@@ -462,7 +463,7 @@ Useful to hook into pass checkers.")
(marker-buffer (function (marker) (or buffer null)))
(markerp (function (t) boolean))
(max (function ((or number marker) &rest (or number marker)) number))
- (max-char (function () fixnum))
+ (max-char (function (&optional t) fixnum))
(member (function (t list) list))
(memory-limit (function () integer))
(memq (function (t list) list))
@@ -3800,22 +3801,25 @@ Return the trampoline if found or nil otherwise."
(lexical-binding t))
(comp--native-compile
form nil
- (cl-loop
- for dir in (if native-compile-target-directory
- (list (expand-file-name comp-native-version-dir
- native-compile-target-directory))
- (comp-eln-load-path-eff))
- for f = (expand-file-name
- (comp-trampoline-filename subr-name)
- dir)
- unless (file-exists-p dir)
- do (ignore-errors
- (make-directory dir t)
- (cl-return f))
- when (file-writable-p f)
- do (cl-return f)
- finally (error "Cannot find suitable directory for output in \
-`native-comp-eln-load-path'")))))
+ ;; If we've disabled nativecomp, don't write the trampolines to
+ ;; the eln cache (but create them).
+ (and (not inhibit-automatic-native-compilation)
+ (cl-loop
+ for dir in (if native-compile-target-directory
+ (list (expand-file-name comp-native-version-dir
+ native-compile-target-directory))
+ (comp-eln-load-path-eff))
+ for f = (expand-file-name
+ (comp-trampoline-filename subr-name)
+ dir)
+ unless (file-exists-p dir)
+ do (ignore-errors
+ (make-directory dir t)
+ (cl-return f))
+ when (file-writable-p f)
+ do (cl-return f)
+ finally (error "Cannot find suitable directory for output in \
+`native-comp-eln-load-path'"))))))
;; Some entry point support code.
@@ -3935,8 +3939,11 @@ display a message."
when (or native-comp-always-compile
load ; Always compile when the compilation is
; commanded for late load.
- (file-newer-than-file-p
- source-file (comp-el-to-eln-filename source-file)))
+ ;; Skip compilation if `comp-el-to-eln-filename' fails
+ ;; to find a writable directory.
+ (with-demoted-errors "Async compilation :%S"
+ (file-newer-than-file-p
+ source-file (comp-el-to-eln-filename source-file))))
do (let* ((expr `((require 'comp)
(setq comp-async-compilation t)
(setq warning-fill-column most-positive-fixnum)
@@ -4041,7 +4048,6 @@ the deferred compilation mechanism."
(list "Not a function symbol or file" function-or-file)))
(catch 'no-native-compile
(let* ((print-symbols-bare t)
- (max-specpdl-size (max max-specpdl-size 5000))
(data function-or-file)
(comp-native-compiling t)
(byte-native-qualities nil)
@@ -4104,6 +4110,7 @@ the deferred compilation mechanism."
comp-ctxt
(comp-ctxt-output comp-ctxt)
(file-exists-p (comp-ctxt-output comp-ctxt)))
+ (message "Deleting %s" (comp-ctxt-output comp-ctxt))
(delete-file (comp-ctxt-output comp-ctxt)))))))
(defun native-compile-async-skip-p (file load selector)
diff --git a/lisp/emacs-lisp/debug.el b/lisp/emacs-lisp/debug.el
index 460057b3afd..f78d44cf98e 100644
--- a/lisp/emacs-lisp/debug.el
+++ b/lisp/emacs-lisp/debug.el
@@ -110,10 +110,6 @@ The value used here is passed to `quit-restore-window'."
(defvar debugger-previous-window-height nil
"The last recorded height of `debugger-previous-window'.")
-(defvar debugger-previous-backtrace nil
- "The contents of the previous backtrace (including text properties).
-This is to optimize `debugger-make-xrefs'.")
-
(defvar debugger-outer-match-data)
(defvar debugger-will-be-back nil
"Non-nil if we expect to get back in the debugger soon.")
@@ -836,6 +832,10 @@ To specify a nil argument interactively, exit with an empty minibuffer."
;;;###autoload
(defalias 'cancel-debug-watch #'cancel-debug-on-variable-change)
+(make-obsolete-variable 'debugger-previous-backtrace
+ "no longer used." "29.1")
+(defvar debugger-previous-backtrace nil)
+
(provide 'debug)
;;; debug.el ends here
diff --git a/lisp/emacs-lisp/easy-mmode.el b/lisp/emacs-lisp/easy-mmode.el
index c3a4e9fc7ab..7d54a84687b 100644
--- a/lisp/emacs-lisp/easy-mmode.el
+++ b/lisp/emacs-lisp/easy-mmode.el
@@ -417,7 +417,12 @@ No problems result if this variable is not bound.
`(defvar ,keymap-sym
(let ((m ,keymap))
(cond ((keymapp m) m)
- ((listp m) (easy-mmode-define-keymap m))
+ ;; FIXME: `easy-mmode-define-keymap' is obsolete,
+ ;; so this form should also be obsolete somehow.
+ ((listp m)
+ (with-suppressed-warnings ((obsolete
+ easy-mmode-define-keymap))
+ (easy-mmode-define-keymap m)))
(t (error "Invalid keymap %S" m))))
,(format "Keymap for `%s'." mode-name)))
@@ -679,6 +684,7 @@ Valid keywords and arguments are:
:group Ignored.
:suppress Non-nil to call `suppress-keymap' on keymap,
`nodigits' to suppress digits as prefix arguments."
+ (declare (obsolete define-keymap "29.1"))
(let (inherit dense suppress)
(while args
(let ((key (pop args))
@@ -719,9 +725,7 @@ The M, BS, and ARGS arguments are as per that function. DOC is
the constant's documentation.
This macro is deprecated; use `defvar-keymap' instead."
- ;; FIXME: Declare obsolete in favor of `defvar-keymap'. It is still
- ;; used for `gud-menu-map' and `gud-minor-mode-map', so fix that first.
- (declare (doc-string 3) (indent 1))
+ (declare (doc-string 3) (indent 1) (obsolete defvar-keymap "29.1"))
`(defconst ,m
(easy-mmode-define-keymap ,bs nil (if (boundp ',m) ,m) ,(cons 'list args))
,doc))
diff --git a/lisp/emacs-lisp/edebug.el b/lisp/emacs-lisp/edebug.el
index 9de8999fdfd..67704bdb51c 100644
--- a/lisp/emacs-lisp/edebug.el
+++ b/lisp/emacs-lisp/edebug.el
@@ -129,7 +129,7 @@ contains an infinite loop. When Edebug is instrumenting code
containing very large quoted lists, it may reach this limit and give
the error message \"Too deep - perhaps infinite loop in spec?\".
Make this limit larger to countermand that, but you may also need to
-increase `max-lisp-eval-depth' and `max-specpdl-size'."
+increase `max-lisp-eval-depth'."
:type 'integer
:version "26.1")
@@ -1107,8 +1107,7 @@ purpose by adding an entry to this alist, and setting
edebug-best-error
edebug-error-point
;; Do this once here instead of several times.
- (max-lisp-eval-depth (+ 800 max-lisp-eval-depth))
- (max-specpdl-size (+ 2000 max-specpdl-size)))
+ (max-lisp-eval-depth (+ 800 max-lisp-eval-depth)))
(let ((no-match
(catch 'no-match
(setq result (edebug-read-and-maybe-wrap-form1))
@@ -2317,7 +2316,6 @@ and run its entry function, and set up `edebug-before' and
;; but not inside an unwind-protect.
;; Doing it here also keeps it from growing too large.
(max-lisp-eval-depth (+ 100 max-lisp-eval-depth)) ; too much??
- (max-specpdl-size (+ 200 max-specpdl-size))
(debugger edebug-debugger) ; only while edebug is active.
(edebug-outside-debug-on-error debug-on-error)
@@ -3791,9 +3789,6 @@ limited by `edebug-print-length' or `edebug-print-level'."
;;; Edebug Minor Mode
-(define-obsolete-variable-alias 'gud-inhibit-global-bindings
- 'edebug-inhibit-emacs-lisp-mode-bindings "24.3")
-
(defvar edebug-inhibit-emacs-lisp-mode-bindings nil
"If non-nil, inhibit Edebug bindings on the C-x C-a key.
By default, loading the `edebug' library causes these bindings to
@@ -4182,6 +4177,7 @@ from Edebug instrumentation found in the backtrace."
(backtrace-mode)
(add-hook 'backtrace-goto-source-functions
#'edebug--backtrace-goto-source nil t))
+ (edebug-backtrace-mode)
(setq edebug-instrumented-backtrace-frames
(backtrace-get-frames 'edebug-debugger
:constructor #'edebug--make-frame)
@@ -4258,6 +4254,14 @@ Save DEF-NAME, BEFORE-INDEX and AFTER-INDEX in FRAME."
(setf (edebug--frame-before-index frame) before-index)
(setf (edebug--frame-after-index frame) after-index))
+(defvar-keymap edebug-backtrace-mode-map
+ "s" #'backtrace-goto-source)
+
+(define-minor-mode edebug-backtrace-mode
+ "Minor mode for showing backtraces from edebug."
+ :lighter nil
+ :interactive nil)
+
(defun edebug--backtrace-goto-source ()
(let* ((index (backtrace-get-index))
(frame (nth index backtrace-frames)))
@@ -4567,6 +4571,12 @@ With prefix argument, make it a temporary breakpoint."
(was-macro `(macro . ,unwrapped))
(t unwrapped))))))
+(defun edebug--strip-plist (symbol)
+ "Remove edebug related properties from plist for SYMBOL."
+ (dolist (prop '( edebug edebug-behavior edebug-coverage
+ edebug-freq-count ghost-edebug))
+ (cl-remprop symbol prop)))
+
(defun edebug-remove-instrumentation (functions)
"Remove Edebug instrumentation from FUNCTIONS.
Interactively, the user is prompted for the function to remove
@@ -4598,6 +4608,7 @@ instrumentation for, defaulting to all functions."
(dolist (symbol functions)
(when-let ((unwrapped
(edebug--unwrap*-symbol-function symbol)))
+ (edebug--strip-plist symbol)
(defalias symbol unwrapped)))
(message "Removed edebug instrumentation from %s"
(mapconcat #'symbol-name functions ", ")))
diff --git a/lisp/emacs-lisp/eieio-core.el b/lisp/emacs-lisp/eieio-core.el
index 5e7b5cbfb2f..65aa6aa6df7 100644
--- a/lisp/emacs-lisp/eieio-core.el
+++ b/lisp/emacs-lisp/eieio-core.el
@@ -249,16 +249,22 @@ use '%s or turn off `eieio-backward-compatibility' instead" cname)
(defun eieio-make-class-predicate (class)
(lambda (obj)
(:documentation
- (format "Return non-nil if OBJ is an object of type `%S'.\n\n(fn OBJ)"
- class))
+ (concat
+ (internal--format-docstring-line
+ "Return non-nil if OBJ is an object of type `%S'."
+ class)
+ "\n\n(fn OBJ)"))
(and (eieio-object-p obj)
(same-class-p obj class))))
(defun eieio-make-child-predicate (class)
(lambda (obj)
(:documentation
- (format "Return non-nil if OBJ is an object of type `%S' or a subclass.
-\n(fn OBJ)" class))
+ (concat
+ (internal--format-docstring-line
+ "Return non-nil if OBJ is an object of type `%S' or a subclass."
+ class)
+ "\n\n(fn OBJ)"))
(and (eieio-object-p obj)
(object-of-class-p obj class))))
@@ -353,8 +359,8 @@ See `defclass' for more information."
(defalias csym
(lambda (obj)
(:documentation
- (format
- "Test OBJ to see if it a list of objects which are a child of type %s"
+ (internal--format-docstring-line
+ "Test OBJ to see if it a list of objects which are a child of type `%s'."
cname))
(when (listp obj)
(let ((ans t)) ;; nil is valid
diff --git a/lisp/emacs-lisp/eieio-opt.el b/lisp/emacs-lisp/eieio-opt.el
index 5f67263f177..b599aabb7f7 100644
--- a/lisp/emacs-lisp/eieio-opt.el
+++ b/lisp/emacs-lisp/eieio-opt.el
@@ -153,7 +153,7 @@ are not abstract."
(help-insert-xref-button
(help-fns-short-filename location)
'cl-type-definition ctr location 'define-type)
- (insert (substitute-command-keys "'")))
+ (insert (substitute-quotes "'")))
(insert ".\nCreates an object of class " (symbol-name ctr) ".")
(goto-char (point-max))
(if (autoloadp def)
diff --git a/lisp/emacs-lisp/eieio.el b/lisp/emacs-lisp/eieio.el
index 984166b593a..8351d97b13d 100644
--- a/lisp/emacs-lisp/eieio.el
+++ b/lisp/emacs-lisp/eieio.el
@@ -136,6 +136,7 @@ and reference them using the function `class-option'."
(accessors ()))
;; Collect the accessors we need to define.
+ (setq slots (mapcar (lambda (x) (if (consp x) x (list x))) slots))
(pcase-dolist (`(,sname . ,soptions) slots)
(let* ((acces (plist-get soptions :accessor))
(initarg (plist-get soptions :initarg))
@@ -217,10 +218,11 @@ and reference them using the function `class-option'."
(when (and eieio-backward-compatibility (eq alloc :class))
;; FIXME: How could I declare this *method* as obsolete.
(push `(cl-defmethod ,acces ((this (subclass ,name)))
- ,(format
- "Retrieve the class slot `%S' from a class `%S'.
-This method is obsolete."
- sname name)
+ ,(concat
+ (internal--format-docstring-line
+ "Retrieve the class slot `%S' from a class `%S'."
+ sname name)
+ "\nThis method is obsolete.")
(if (slot-boundp this ',sname)
(eieio-oref-default this ',sname)))
accessors)))
@@ -229,16 +231,18 @@ This method is obsolete."
;; name whose purpose is to set the value of the slot.
(if writer
(push `(cl-defmethod ,writer ((this ,name) value)
- ,(format "Set the slot `%S' of an object of class `%S'."
- sname name)
+ ,(internal--format-docstring-line
+ "Set the slot `%S' of an object of class `%S'."
+ sname name)
(setf (slot-value this ',sname) value))
accessors))
;; If a reader is defined, then create a generic method
;; of that name whose purpose is to access this slot value.
(if reader
(push `(cl-defmethod ,reader ((this ,name))
- ,(format "Access the slot `%S' from object of class `%S'."
- sname name)
+ ,(internal--format-docstring-line
+ "Access the slot `%S' from object of class `%S'."
+ sname name)
(slot-value this ',sname))
accessors))
))
diff --git a/lisp/emacs-lisp/ert-x.el b/lisp/emacs-lisp/ert-x.el
index 4436d0a4b16..a891f068a70 100644
--- a/lisp/emacs-lisp/ert-x.el
+++ b/lisp/emacs-lisp/ert-x.el
@@ -102,6 +102,43 @@ the name of the test and the result of NAME-FORM."
(indent 1))
`(ert--call-with-test-buffer ,name-form (lambda () ,@body)))
+(cl-defmacro ert-with-test-buffer-selected ((&key name)
+ &body body)
+ "Create a test buffer, switch to it, and run BODY.
+
+This extends `ert-with-test-buffer' by displaying the test
+buffer (whose name is derived from NAME) in a temporary window.
+The temporary window becomes the `selected-window' before BODY is
+evaluated. The modification hooks `before-change-functions' and
+`after-change-functions' are not inhibited during the evaluation
+of BODY, which makes it easier to use `execute-kbd-macro' to
+simulate user interaction. The window configuration is restored
+before returning, even if BODY exits nonlocally. The return
+value is the last form in BODY."
+ (declare (debug ((":name" form) def-body))
+ (indent 1))
+ (let ((ret (make-symbol "ert--with-test-buffer-selected-ret")))
+ `(save-window-excursion
+ (let (,ret)
+ (ert-with-test-buffer (:name ,name)
+ (with-current-buffer-window (current-buffer)
+ `(display-buffer-below-selected
+ (body-function
+ . ,(lambda (window)
+ (select-window window t)
+ ;; body-function is intended to initialize the
+ ;; contents of a temporary read-only buffer, so
+ ;; it is executed with some convenience
+ ;; changes. Undo those changes so that the
+ ;; test buffer behaves more like an ordinary
+ ;; buffer while the body executes.
+ (let ((inhibit-modification-hooks nil)
+ (inhibit-read-only nil)
+ (buffer-read-only nil))
+ (setq ,ret (progn ,@body))))))
+ nil))
+ ,ret))))
+
;;;###autoload
(defun ert-kill-all-test-buffers ()
"Kill all test buffers that are still live."
@@ -422,6 +459,10 @@ The following keyword arguments are supported:
:text STRING If non-nil, pass STRING to `make-temp-file' as
the TEXT argument.
+:buffer SYMBOL Open the temporary file using `find-file-noselect'
+ and bind SYMBOL to the buffer. Kill the buffer
+ after BODY exits normally or non-locally.
+
:coding CODING If non-nil, bind `coding-system-for-write' to CODING
when executing BODY. This is handy when STRING includes
non-ASCII characters or the temporary file must have a
@@ -430,14 +471,17 @@ The following keyword arguments are supported:
See also `ert-with-temp-directory'."
(declare (indent 1) (debug (symbolp body)))
(cl-check-type name symbol)
- (let (keyw prefix suffix directory text extra-keywords coding)
+ (let (keyw prefix suffix directory text extra-keywords buffer coding)
(while (keywordp (setq keyw (car body)))
(setq body (cdr body))
(pcase keyw
(:prefix (setq prefix (pop body)))
(:suffix (setq suffix (pop body)))
+ ;; This is only for internal use by `ert-with-temp-directory'
+ ;; and is therefore not documented.
(:directory (setq directory (pop body)))
(:text (setq text (pop body)))
+ (:buffer (setq buffer (pop body)))
(:coding (setq coding (pop body)))
(_ (push keyw extra-keywords) (pop body))))
(when extra-keywords
@@ -452,10 +496,17 @@ See also `ert-with-temp-directory'."
(make-temp-file ,prefix ,directory ,suffix ,text)))
(,name ,(if directory
`(file-name-as-directory ,temp-file)
- temp-file)))
+ temp-file))
+ ,@(when buffer
+ (list `(,buffer (find-file-literally ,temp-file)))))
(unwind-protect
(progn ,@body)
(ignore-errors
+ ,@(when buffer
+ (list `(with-current-buffer buf
+ (set-buffer-modified-p nil))
+ `(kill-buffer ,buffer))))
+ (ignore-errors
,(if directory
`(delete-directory ,temp-file :recursive)
`(delete-file ,temp-file))))))))
@@ -517,7 +568,7 @@ The same keyword arguments are supported as in
`("\\`mock\\'" nil ,(system-name)))
;; Emacs's Makefile sets $HOME to a nonexistent value. Needed
;; in batch mode only, therefore.
- (unless (and (null noninteractive) (file-directory-p "~/"))
+ (when (and noninteractive (not (file-directory-p "~/")))
(setenv "HOME" temporary-file-directory))
(format "/mock::%s" temporary-file-directory))))
"Temporary directory for remote file tests.")
diff --git a/lisp/emacs-lisp/generate-lisp-file.el b/lisp/emacs-lisp/generate-lisp-file.el
index 8896a3f7019..7b087a4ecbd 100644
--- a/lisp/emacs-lisp/generate-lisp-file.el
+++ b/lisp/emacs-lisp/generate-lisp-file.el
@@ -63,12 +63,12 @@ inserted."
(cl-defun generate-lisp-file-trailer (file &key version inhibit-provide
(coding 'utf-8-emacs-unix) autoloads
- compile provide)
+ compile provide inhibit-native-compile)
"Insert a standard trailer for FILE.
By default, this trailer inhibits version control, byte
compilation, updating autoloads, and uses a `utf-8-emacs-unix'
coding system. These can be inhibited by providing non-nil
-values to the VERSION, NO-PROVIDE, AUTOLOADS and COMPILE
+values to the VERSION, AUTOLOADS, COMPILE and NATIVE-COMPILE
keyword arguments.
CODING defaults to `utf-8-emacs-unix'. Use a nil value to
@@ -79,7 +79,11 @@ If PROVIDE is non-nil, use that in the `provide' statement
instead of using FILE as the basis.
If `standard-output' is bound to a buffer, insert in that buffer.
-If no, insert at point in the current buffer."
+If no, insert at point in the current buffer.
+
+If INHITBIT-NATIVE-COMPILE is non-nil, add a cookie to inhibit
+native compilation. (By default, a file will be native-compiled
+if it's also byte-compiled)."
(with-current-buffer (if (bufferp standard-output)
standard-output
(current-buffer))
@@ -96,9 +100,11 @@ If no, insert at point in the current buffer."
(unless version
(insert ";; version-control: never\n"))
(unless compile
- (insert ";; no-byte-" "compile: t\n")) ;; #$ is byte-compiled into nil.
+ (insert ";; no-byte-" "compile: t\n"))
(unless autoloads
(insert ";; no-update-autoloads: t\n"))
+ (when inhibit-native-compile
+ (insert ";; no-native-" "compile: t\n"))
(when coding
(insert (format ";; coding: %s\n"
(if (eq coding t)
diff --git a/lisp/emacs-lisp/gv.el b/lisp/emacs-lisp/gv.el
index eaab6439adb..a96fa19a3ff 100644
--- a/lisp/emacs-lisp/gv.el
+++ b/lisp/emacs-lisp/gv.el
@@ -87,7 +87,11 @@ with a (not necessarily copyable) Elisp expression that returns the value to
set it to.
DO must return an Elisp expression."
(cond
- ((symbolp place) (funcall do place (lambda (v) `(setq ,place ,v))))
+ ((symbolp place)
+ (let ((me (macroexpand-1 place macroexpand-all-environment)))
+ (if (eq me place)
+ (funcall do place (lambda (v) `(setq ,place ,v)))
+ (gv-get me do))))
((not (consp place)) (signal 'gv-invalid-place (list place)))
(t
(let* ((head (car place))
@@ -532,13 +536,15 @@ The return value is the last VAL in the list.
(funcall do `(error . ,args)
(lambda (v) `(progn ,v (error . ,args))))))
-(defmacro gv-synthetic-place (getter setter)
+(defun gv-synthetic-place (getter setter)
"Special place described by its setter and getter.
GETTER and SETTER (typically obtained via `gv-letplace') get and
-set that place. I.e. This macro allows you to do the \"reverse\" of what
-`gv-letplace' does.
-This macro only makes sense when used in a place."
- (declare (gv-expander funcall))
+set that place. I.e. this function allows you to do the
+\"reverse\" of what `gv-letplace' does.
+
+This function is only useful when used in conjunction with
+generalized variables in place forms."
+ (declare (gv-expander funcall) (compiler-macro (lambda (_) getter)))
(ignore setter)
getter)
@@ -806,6 +812,7 @@ REF must have been previously obtained with `gv-ref'."
`(cond
(,v ,(funcall setter val))
((eq ,getter ,val) ,(funcall setter `(not ,val))))))))))
+(make-obsolete-generalized-variable 'eq nil "29.1")
(gv-define-expander substring
(lambda (do place from &optional to)
diff --git a/lisp/emacs-lisp/icons.el b/lisp/emacs-lisp/icons.el
index 93749a3451e..a08ac7463ce 100644
--- a/lisp/emacs-lisp/icons.el
+++ b/lisp/emacs-lisp/icons.el
@@ -202,7 +202,11 @@ present if the icon is represented by an image."
:height (if (eq height 'line)
(window-default-line-height)
height)
- :scale 1)
+ :scale 1
+ :rotation (or (plist-get keywords :rotation) 0)
+ :ascent (if (plist-member keywords :ascent)
+ (plist-get keywords :ascent)
+ 'center))
(create-image file))))))
(cl-defmethod icons--create ((_type (eql 'emoji)) icon _keywords)
diff --git a/lisp/emacs-lisp/lisp-mode.el b/lisp/emacs-lisp/lisp-mode.el
index c906ee6e31d..7e39a77aed5 100644
--- a/lisp/emacs-lisp/lisp-mode.el
+++ b/lisp/emacs-lisp/lisp-mode.el
@@ -325,6 +325,20 @@ This will generate compile-time constants from BINDINGS."
(throw 'matched t)))
(throw 'matched nil)))))
+(defun lisp-mode--search-key (char bound)
+ (catch 'found
+ (while (re-search-forward
+ (concat "\\_<" char (rx lisp-mode-symbol) "\\_>")
+ bound t)
+ (when (or (< (match-beginning 0) (+ (point-min) 2))
+ ;; A quoted white space before the &/: means that this
+ ;; is not the start of a :keyword or an &option.
+ (not (eql (char-after (- (match-beginning 0) 2))
+ ?\\))
+ (not (memq (char-after (- (match-beginning 0) 1))
+ '(?\s ?\n ?\t))))
+ (throw 'found t)))))
+
(let-when-compile
((lisp-fdefs '("defmacro" "defun"))
(lisp-vdefs '("defvar"))
@@ -496,11 +510,11 @@ This will generate compile-time constants from BINDINGS."
(,(rx "\\\\=")
(0 font-lock-builtin-face prepend))
;; Constant values.
- (,(concat "\\_<:" (rx lisp-mode-symbol) "\\_>")
+ (,(lambda (bound) (lisp-mode--search-key ":" bound))
(0 font-lock-builtin-face))
;; ELisp and CLisp `&' keywords as types.
- (,(concat "\\_<&" (rx lisp-mode-symbol) "\\_>")
- . font-lock-type-face)
+ (,(lambda (bound) (lisp-mode--search-key "&" bound))
+ (0 font-lock-builtin-face))
;; ELisp regexp grouping constructs
(,(lambda (bound)
(catch 'found
@@ -549,11 +563,12 @@ This will generate compile-time constants from BINDINGS."
;; must come before keywords below to have effect
(,(concat "#:" (rx lisp-mode-symbol) "") 0 font-lock-builtin-face)
;; Constant values.
- (,(concat "\\_<:" (rx lisp-mode-symbol) "\\_>")
+ (,(lambda (bound) (lisp-mode--search-key ":" bound))
(0 font-lock-builtin-face))
;; ELisp and CLisp `&' keywords as types.
- (,(concat "\\_<&" (rx lisp-mode-symbol) "\\_>")
- . font-lock-type-face)
+ (,(lambda (bound) (lisp-mode--search-key "&" bound))
+ (0 font-lock-builtin-face))
+ ;; ELisp regexp grouping constructs
;; This is too general -- rms.
;; A user complained that he has functions whose names start with `do'
;; and that they get the wrong color.
diff --git a/lisp/emacs-lisp/loaddefs-gen.el b/lisp/emacs-lisp/loaddefs-gen.el
index e13b92bab8c..964d23c770e 100644
--- a/lisp/emacs-lisp/loaddefs-gen.el
+++ b/lisp/emacs-lisp/loaddefs-gen.el
@@ -287,10 +287,14 @@ expression, in which case we want to handle forms differently."
;; In Emacs this is normally handled separately by cus-dep.el, but for
;; third party packages, it can be convenient to explicitly autoload
;; a group.
- (let ((groupname (nth 1 form)))
+ (let ((groupname (nth 1 form))
+ (parent (eval (plist-get form :group) t)))
`(let ((loads (get ',groupname 'custom-loads)))
(if (member ',file loads) nil
- (put ',groupname 'custom-loads (cons ',file loads))))))
+ (put ',groupname 'custom-loads (cons ',file loads))
+ ,@(when parent
+ `((put ',parent 'custom-loads
+ (cons ',groupname (get ',parent 'custom-loads)))))))))
;; When processing a macro expansion, any expression
;; before a :autoload-end should be included. These are typically (put
@@ -504,6 +508,7 @@ If COMPILE, don't include a \"don't compile\" cookie."
(generate-lisp-file-trailer
file :provide (and (stringp feature) feature)
:compile compile
+ :inhibit-native-compile t
:inhibit-provide (not feature))
(buffer-string))))
@@ -511,7 +516,7 @@ If COMPILE, don't include a \"don't compile\" cookie."
(defun loaddefs-generate (dir output-file &optional excluded-files
extra-data include-package-version
generate-full)
- "Generate loaddefs files for Lisp files in the directories DIRS.
+ "Generate loaddefs files for Lisp files in one or more directories given by DIR.
DIR can be either a single directory or a list of directories.
The autoloads will be written to OUTPUT-FILE. If any Lisp file
@@ -519,7 +524,7 @@ binds `generated-autoload-file' as a file-local variable, write
its autoloads into the specified file instead.
The function does NOT recursively descend into subdirectories of the
-directory or directories specified by DIRS.
+directories specified by DIR.
Optional argument EXCLUDED-FILES, if non-nil, should be a list of
files, such as preloaded files, whose autoloads should not be written
@@ -627,7 +632,7 @@ instead of just updating them with the new/changed autoloads."
;; It's a new file; put the data at the end.
(progn
(goto-char (point-max))
- (search-backward "\f\n"))
+ (search-backward "\f\n" nil t))
;; Delete the old version of the section.
(delete-region (match-beginning 0)
(and (search-forward "\n\f\n;;;")
diff --git a/lisp/emacs-lisp/macroexp.el b/lisp/emacs-lisp/macroexp.el
index c3ba1b36d44..f4df40249de 100644
--- a/lisp/emacs-lisp/macroexp.el
+++ b/lisp/emacs-lisp/macroexp.el
@@ -110,7 +110,8 @@ each clause."
(let ((symbols-with-pos-enabled t))
(apply handler form (cdr form)))
(error
- (message "Compiler-macro error for %S: Handler: %S\n%S" (car form) handler err)
+ (message "Warning: Optimization failure for %S: Handler: %S\n%S"
+ (car form) handler err)
form)))
(defun macroexp--funcall-if-compiled (_form)
diff --git a/lisp/emacs-lisp/nadvice.el b/lisp/emacs-lisp/nadvice.el
index a9a20ab5abf..429052bfdf3 100644
--- a/lisp/emacs-lisp/nadvice.el
+++ b/lisp/emacs-lisp/nadvice.el
@@ -4,6 +4,7 @@
;; Author: Stefan Monnier <monnier@iro.umontreal.ca>
;; Keywords: extensions, lisp, tools
+;; Version: 1.0
;; This file is part of GNU Emacs.
@@ -37,11 +38,6 @@
;;; Code:
-;; The autoloads.el mechanism which adds package--builtin-versions
-;; maintenance to loaddefs.el doesn't work for preloaded packages (such
-;; as this one), so we have to do it by hand!
-(push (purecopy '(nadvice 1 0)) package--builtin-versions)
-
(oclosure-define (advice
(:predicate advice--p)
(:copier advice--cons (cdr))
@@ -108,19 +104,26 @@ DOC is a string where \"FUNCTION\" and \"OLDFUN\" are expected.")
(format "%s\n%s" name doc)
(format "%s" name))
(or doc "No documentation")))))
- "\n")))
+ "\n"
+ (and
+ (eq how :override)
+ (concat
+ (format-message
+ "\nThis is an :override advice, which means that `%s' isn't\n" function)
+ "run at all, and the documentation below may be irrelevant.\n")))))
(defun advice--make-docstring (function)
"Build the raw docstring for FUNCTION, presumably advised."
(let* ((flist (indirect-function function))
(docfun nil)
(macrop (eq 'macro (car-safe flist)))
- (docstring nil))
+ (before nil)
+ (after nil))
(when macrop
(setq flist (cdr flist)))
(if (and (autoloadp flist)
(get function 'advice--pending))
- (setq docstring
+ (setq after
(advice--make-single-doc (get function 'advice--pending)
function macrop))
(while (advice--p flist)
@@ -130,9 +133,13 @@ DOC is a string where \"FUNCTION\" and \"OLDFUN\" are expected.")
;; object instead! So here we try to undo the damage.
(when (integerp (aref flist 4))
(setq docfun flist))
- (setq docstring (concat docstring (advice--make-single-doc
- flist function macrop))
- flist (advice--cdr flist))))
+ (let ((doc-bit (advice--make-single-doc flist function macrop)))
+ ;; We want :overrides to go to the front, because they mean
+ ;; that the doc string may be irrelevant.
+ (if (eq (advice--how flist) :override)
+ (setq before (concat before doc-bit))
+ (setq after (concat after doc-bit))))
+ (setq flist (advice--cdr flist))))
(unless docfun
(setq docfun flist))
(let* ((origdoc (unless (eq function docfun) ;Avoid inf-loops.
@@ -145,12 +152,18 @@ DOC is a string where \"FUNCTION\" and \"OLDFUN\" are expected.")
(if (stringp arglist) t
(help--make-usage-docstring function arglist)))
(setq origdoc (cdr usage)) (car usage)))
- (help-add-fundoc-usage (concat origdoc
- (if (string-suffix-p "\n" origdoc)
- "\n"
- "\n\n")
- docstring)
- usage))))
+ (help-add-fundoc-usage
+ (with-temp-buffer
+ (when before
+ (insert before)
+ (ensure-empty-lines 1))
+ (when origdoc
+ (insert origdoc))
+ (when after
+ (ensure-empty-lines 1)
+ (insert after))
+ (buffer-string))
+ usage))))
(defun advice-eval-interactive-spec (spec)
"Evaluate the interactive spec SPEC."
diff --git a/lisp/emacs-lisp/oclosure.el b/lisp/emacs-lisp/oclosure.el
index 9775e8cc656..c77ac151d77 100644
--- a/lisp/emacs-lisp/oclosure.el
+++ b/lisp/emacs-lisp/oclosure.el
@@ -557,6 +557,21 @@ This has 2 uses:
(oclosure-define (save-some-buffers-function
(:predicate save-some-buffers-function--p)))
+;; This OClosure type is used internally by `cconv.el' to handle
+;; the case where we need to build a closure whose `interactive' spec
+;; captures variables from the context.
+;; It arguably belongs with `cconv.el' but is needed at runtime,
+;; so we placed it here.
+(oclosure-define (cconv--interactive-helper) fun if)
+(defun cconv--interactive-helper (fun if)
+ "Add interactive \"form\" IF to FUN.
+Returns a new command that otherwise behaves like FUN.
+IF should actually not be a form but a function of no arguments."
+ (oclosure-lambda (cconv--interactive-helper (fun fun) (if if))
+ (&rest args)
+ (apply (if (called-interactively-p 'any)
+ #'funcall-interactively #'funcall)
+ fun args)))
(provide 'oclosure)
;;; oclosure.el ends here
diff --git a/lisp/emacs-lisp/package.el b/lisp/emacs-lisp/package.el
index ed23ee5f221..4abee9d0538 100644
--- a/lisp/emacs-lisp/package.el
+++ b/lisp/emacs-lisp/package.el
@@ -2189,8 +2189,8 @@ to install it but still mark it as selected."
(assq (car elt) package-archive-contents)))
(and available
(version-list-<
- (package-desc-priority-version (cadr elt))
- (package-desc-priority-version (cadr available))))))
+ (package-desc-version (cadr elt))
+ (package-desc-version (cadr available))))))
package-alist)))
;;;###autoload
@@ -2648,7 +2648,7 @@ Helper function for `describe-package'."
"',\n shadowing a ")
(propertize "built-in package"
'font-lock-face 'package-status-built-in))
- (insert (substitute-command-keys "'")))
+ (insert (substitute-quotes "'")))
(if signed
(insert ".")
(insert " (unsigned)."))
@@ -3700,30 +3700,34 @@ objects removed."
`((delete . ,del) (install . ,ins) (upgrade . ,upg))))
(defun package-menu--perform-transaction (install-list delete-list)
- "Install packages in INSTALL-LIST and delete DELETE-LIST."
- (if install-list
- (let ((status-format (format ":Installing %%d/%d"
- (length install-list)))
- (i 0)
- (package-menu--transaction-status))
- (dolist (pkg install-list)
- (setq package-menu--transaction-status
- (format status-format (cl-incf i)))
- (force-mode-line-update)
- (redisplay 'force)
- ;; Don't mark as selected, `package-menu-execute' already
- ;; does that.
- (package-install pkg 'dont-select))))
- (let ((package-menu--transaction-status ":Deleting"))
- (force-mode-line-update)
- (redisplay 'force)
- (dolist (elt (package--sort-by-dependence delete-list))
- (condition-case-unless-debug err
- (let ((inhibit-message (or inhibit-message package-menu-async)))
- (package-delete elt nil 'nosave))
- (error (message "Error trying to delete `%s': %S"
- (package-desc-full-name elt)
- err))))))
+ "Install packages in INSTALL-LIST and delete DELETE-LIST.
+Return nil if there were no errors; non-nil otherwise."
+ (let ((errors nil))
+ (if install-list
+ (let ((status-format (format ":Installing %%d/%d"
+ (length install-list)))
+ (i 0)
+ (package-menu--transaction-status))
+ (dolist (pkg install-list)
+ (setq package-menu--transaction-status
+ (format status-format (cl-incf i)))
+ (force-mode-line-update)
+ (redisplay 'force)
+ ;; Don't mark as selected, `package-menu-execute' already
+ ;; does that.
+ (package-install pkg 'dont-select))))
+ (let ((package-menu--transaction-status ":Deleting"))
+ (force-mode-line-update)
+ (redisplay 'force)
+ (dolist (elt (package--sort-by-dependence delete-list))
+ (condition-case-unless-debug err
+ (let ((inhibit-message (or inhibit-message package-menu-async)))
+ (package-delete elt nil 'nosave))
+ (error
+ (push (package-desc-full-name elt) errors)
+ (message "Error trying to delete `%s': %S"
+ (package-desc-full-name elt) err)))))
+ errors))
(defun package--update-selected-packages (add remove)
"Update the `package-selected-packages' list according to ADD and REMOVE.
@@ -3796,8 +3800,8 @@ Optional argument NOQUERY non-nil means do not ask the user to confirm."
(message "Operation %s started" message-template)
;; Packages being upgraded are not marked as selected.
(package--update-selected-packages .install .delete)
- (package-menu--perform-transaction install-list delete-list)
- (when package-selected-packages
+ (unless (package-menu--perform-transaction install-list delete-list)
+ ;; If there weren't errors, output data.
(if-let* ((removable (package--removable-packages)))
(message "Operation finished. Packages that are no longer needed: %d. Type `%s' to remove them"
(length removable)
diff --git a/lisp/emacs-lisp/re-builder.el b/lisp/emacs-lisp/re-builder.el
index e6e8bb202da..897c35b5b19 100644
--- a/lisp/emacs-lisp/re-builder.el
+++ b/lisp/emacs-lisp/re-builder.el
@@ -369,7 +369,8 @@ provided in the Commentary section of this library."
(get-buffer-create reb-buffer)
`((display-buffer-in-direction)
(direction . ,dir)
- (dedicated . t))))))
+ (dedicated . t)
+ (window-height . fit-window-to-buffer))))))
(font-lock-mode 1)
(reb-initialize-buffer)))
diff --git a/lisp/emacs-lisp/regexp-opt.el b/lisp/emacs-lisp/regexp-opt.el
index cae5dd00d1d..4d5a39458d2 100644
--- a/lisp/emacs-lisp/regexp-opt.el
+++ b/lisp/emacs-lisp/regexp-opt.el
@@ -133,7 +133,6 @@ usually more efficient than that of a simplified version:
(save-match-data
;; Recurse on the sorted list.
(let* ((max-lisp-eval-depth 10000)
- (max-specpdl-size 10000)
(completion-ignore-case nil)
(completion-regexp-list nil)
(open (cond ((stringp paren) paren) (paren "\\(")))
diff --git a/lisp/emacs-lisp/seq.el b/lisp/emacs-lisp/seq.el
index b6f0f66e5b1..82ade0ac0c3 100644
--- a/lisp/emacs-lisp/seq.el
+++ b/lisp/emacs-lisp/seq.el
@@ -347,6 +347,20 @@ list."
sequence))
;;;###autoload
+(cl-defgeneric seq-remove-at-position (sequence n)
+ "Return a copy of SEQUENCE where the element at N got removed.
+
+N is the (zero-based) index of the element that should not be in
+the result.
+
+The result is a sequence of the same type as SEQUENCE."
+ (seq-concatenate
+ (let ((type (type-of sequence)))
+ (if (eq type 'cons) 'list type))
+ (seq-subseq sequence 0 n)
+ (seq-subseq sequence (1+ n))))
+
+;;;###autoload
(cl-defgeneric seq-reduce (function sequence initial-value)
"Reduce the function FUNCTION across SEQUENCE, starting with INITIAL-VALUE.
@@ -409,7 +423,7 @@ found or not."
(cl-defgeneric seq-contains (sequence elt &optional testfn)
"Return the first element in SEQUENCE that is equal to ELT.
-Equality is defined by TESTFN if non-nil or by `equal' if nil."
+Equality is defined by the function TESTFN, which defaults to `equal'."
(declare (obsolete seq-contains-p "27.1"))
(seq-some (lambda (e)
(when (funcall (or testfn #'equal) elt e)
@@ -418,7 +432,7 @@ Equality is defined by TESTFN if non-nil or by `equal' if nil."
(cl-defgeneric seq-contains-p (sequence elt &optional testfn)
"Return non-nil if SEQUENCE contains an element equal to ELT.
-Equality is defined by TESTFN if non-nil or by `equal' if nil."
+Equality is defined by the function TESTFN, which defaults to `equal'."
(catch 'seq--break
(seq-doseq (e sequence)
(let ((r (funcall (or testfn #'equal) e elt)))
@@ -429,14 +443,14 @@ Equality is defined by TESTFN if non-nil or by `equal' if nil."
(cl-defgeneric seq-set-equal-p (sequence1 sequence2 &optional testfn)
"Return non-nil if SEQUENCE1 and SEQUENCE2 contain the same elements.
This does not depend on the order of the elements.
-Equality is defined by TESTFN if non-nil or by `equal' if nil."
+Equality is defined by the function TESTFN, which defaults to `equal'."
(and (seq-every-p (lambda (item1) (seq-contains-p sequence2 item1 testfn)) sequence1)
(seq-every-p (lambda (item2) (seq-contains-p sequence1 item2 testfn)) sequence2)))
;;;###autoload
(cl-defgeneric seq-position (sequence elt &optional testfn)
- "Return the index of the first element in SEQUENCE that is equal to ELT.
-Equality is defined by TESTFN if non-nil or by `equal' if nil."
+ "Return the (zero-based) index of the first element in SEQUENCE equal to ELT.
+Equality is defined by the function TESTFN, which defaults to `equal'."
(let ((index 0))
(catch 'seq--break
(seq-doseq (e sequence)
@@ -446,6 +460,23 @@ Equality is defined by TESTFN if non-nil or by `equal' if nil."
nil)))
;;;###autoload
+(cl-defgeneric seq-positions (sequence elt &optional testfn)
+ "Return indices for which (TESTFN (seq-elt SEQUENCE index) ELT) is non-nil.
+
+TESTFN is a two-argument function which is passed each element of
+SEQUENCE as first argument and ELT as second. TESTFN defaults to
+`equal'.
+
+The result is a list of (zero-based) indices."
+ (let ((result '()))
+ (seq-do-indexed
+ (lambda (e index)
+ (when (funcall (or testfn #'equal) e elt)
+ (push index result)))
+ sequence)
+ (nreverse result)))
+
+;;;###autoload
(cl-defgeneric seq-uniq (sequence &optional testfn)
"Return a list of the elements of SEQUENCE with duplicates removed.
TESTFN is used to compare elements, or `equal' if TESTFN is nil."
@@ -502,7 +533,7 @@ negative integer or 0, nil is returned."
;;;###autoload
(cl-defgeneric seq-union (sequence1 sequence2 &optional testfn)
"Return a list of all elements that appear in either SEQUENCE1 or SEQUENCE2.
-Equality is defined by TESTFN if non-nil or by `equal' if nil."
+Equality is defined by the function TESTFN, which defaults to `equal'."
(let* ((accum (lambda (acc elt)
(if (seq-contains-p acc elt testfn)
acc
@@ -514,7 +545,7 @@ Equality is defined by TESTFN if non-nil or by `equal' if nil."
;;;###autoload
(cl-defgeneric seq-intersection (sequence1 sequence2 &optional testfn)
"Return a list of the elements that appear in both SEQUENCE1 and SEQUENCE2.
-Equality is defined by TESTFN if non-nil or by `equal' if nil."
+Equality is defined by the function TESTFN, which defaults to `equal'."
(seq-reduce (lambda (acc elt)
(if (seq-contains-p sequence2 elt testfn)
(cons elt acc)
@@ -524,7 +555,7 @@ Equality is defined by TESTFN if non-nil or by `equal' if nil."
(cl-defgeneric seq-difference (sequence1 sequence2 &optional testfn)
"Return a list of the elements that appear in SEQUENCE1 but not in SEQUENCE2.
-Equality is defined by TESTFN if non-nil or by `equal' if nil."
+Equality is defined by the function TESTFN, which defaults to `equal'."
(seq-reduce (lambda (acc elt)
(if (seq-contains-p sequence2 elt testfn)
acc
@@ -618,13 +649,7 @@ Signal an error if SEQUENCE is empty."
(cl-defmethod seq-take ((list list) n)
"Optimized implementation of `seq-take' for lists."
- (if (eval-when-compile (fboundp 'take))
- (take n list)
- (let ((result '()))
- (while (and list (> n 0))
- (setq n (1- n))
- (push (pop list) result))
- (nreverse result))))
+ (take n list))
(cl-defmethod seq-drop-while (pred (list list))
"Optimized implementation of `seq-drop-while' for lists."
@@ -655,16 +680,6 @@ Signal an error if SEQUENCE is empty."
sequence
(concat sequence)))
-(defun seq--activate-font-lock-keywords ()
- "Activate font-lock keywords for some symbols defined in seq."
- (font-lock-add-keywords 'emacs-lisp-mode
- '("\\<seq-doseq\\>" "\\<seq-let\\>")))
-
-(unless (fboundp 'elisp--font-lock-flush-elisp-buffers)
- ;; In Emacs≥25, (via elisp--font-lock-flush-elisp-buffers and a few others)
- ;; we automatically highlight macros.
- (add-hook 'emacs-lisp-mode-hook #'seq--activate-font-lock-keywords))
-
(defun seq-split (sequence length)
"Split SEQUENCE into a list of sub-sequences of at most LENGTH.
All the sub-sequences will be of LENGTH, except the last one,
@@ -680,5 +695,9 @@ which may be shorter."
result))
(nreverse result)))
+(defun seq-keep (function sequence)
+ "Apply FUNCTION to SEQUENCE and return all non-nil results."
+ (delq nil (seq-map function sequence)))
+
(provide 'seq)
;;; seq.el ends here
diff --git a/lisp/emacs-lisp/shortdoc.el b/lisp/emacs-lisp/shortdoc.el
index 990dabe351a..4cfd658e10d 100644
--- a/lisp/emacs-lisp/shortdoc.el
+++ b/lisp/emacs-lisp/shortdoc.el
@@ -22,6 +22,15 @@
;;; Commentary:
+;; This package lists functions based on various groupings.
+;;
+;; For instance, `string-trim' and `mapconcat' are `string' functions,
+;; so `M-x shortdoc RET string RET' will give an overview of functions
+;; that operate on strings.
+;;
+;; The documentation groups are created with the
+;; `define-short-documentation-group' macro.
+
;;; Code:
(require 'seq)
@@ -355,13 +364,11 @@ A FUNC form can have any number of `:no-eval' (or `:no-value'),
(abbreviate-file-name
:no-eval (abbreviate-file-name "/home/some-user")
:eg-result "~some-user")
- (file-parent-directory
- :eval (file-parent-directory "/foo/bar")
- :eval (file-parent-directory "~")
- :eval (file-parent-directory "/tmp/")
- :eval (file-parent-directory "foo/bar")
- :eval (file-parent-directory "foo")
- :eval (file-parent-directory "/"))
+ (file-name-parent-directory
+ :eval (file-name-parent-directory "/foo/bar")
+ :eval (file-name-parent-directory "/foo/")
+ :eval (file-name-parent-directory "foo/bar")
+ :eval (file-name-parent-directory "foo"))
"Quoted File Names"
(file-name-quote
:args (name)
@@ -846,6 +853,10 @@ A FUNC form can have any number of `:no-eval' (or `:no-value'),
:eval (seq-find #'numberp '(a b 3 4 f 6)))
(seq-position
:eval (seq-position '(a b c) 'c))
+ (seq-positions
+ :eval (seq-positions '(a b c a d) 'a)
+ :eval (seq-positions '(a b c a d) 'z)
+ :eval (seq-positions '(11 5 7 12 9 15) 10 #'>=))
(seq-length
:eval (seq-length "abcde"))
(seq-max
@@ -888,6 +899,9 @@ A FUNC form can have any number of `:no-eval' (or `:no-value'),
:eval (seq-filter #'numberp '(a b 3 4 f 6)))
(seq-remove
:eval (seq-remove #'numberp '(1 2 c d 5)))
+ (seq-remove-at-position
+ :eval (seq-remove-at-position '(a b c d e) 3)
+ :eval (seq-remove-at-position [a b c d e] 0))
(seq-group-by
:eval (seq-group-by #'cl-plusp '(-1 2 3 -4 -5 6)))
(seq-union
@@ -1507,8 +1521,11 @@ Example:
:doc "Keymap for `shortdoc-mode'."
"n" #'shortdoc-next
"p" #'shortdoc-previous
+ "N" #'shortdoc-next-section
+ "P" #'shortdoc-previous-section
"C-c C-n" #'shortdoc-next-section
- "C-c C-p" #'shortdoc-previous-section)
+ "C-c C-p" #'shortdoc-previous-section
+ "w" #'shortdoc-copy-function-as-kill)
(define-derived-mode shortdoc-mode special-mode "shortdoc"
"Mode for shortdoc."
@@ -1521,35 +1538,49 @@ Example:
(funcall
(if reverse 'text-property-search-backward
'text-property-search-forward)
- sym nil t t)
+ sym nil t)
(setq arg (1- arg))))
(defun shortdoc-next (&optional arg)
- "Move cursor to the next function.
-With ARG, do it that many times."
+ "Move point to the next function.
+With prefix numeric argument ARG, do it that many times."
(interactive "p" shortdoc-mode)
(shortdoc--goto-section arg 'shortdoc-function))
(defun shortdoc-previous (&optional arg)
- "Move cursor to the previous function.
-With ARG, do it that many times."
+ "Move point to the previous function.
+With prefix numeric argument ARG, do it that many times."
(interactive "p" shortdoc-mode)
(shortdoc--goto-section arg 'shortdoc-function t)
(backward-char 1))
(defun shortdoc-next-section (&optional arg)
- "Move cursor to the next section.
-With ARG, do it that many times."
+ "Move point to the next section.
+With prefix numeric argument ARG, do it that many times."
(interactive "p" shortdoc-mode)
(shortdoc--goto-section arg 'shortdoc-section))
(defun shortdoc-previous-section (&optional arg)
- "Move cursor to the previous section.
-With ARG, do it that many times."
+ "Move point to the previous section.
+With prefix numeric argument ARG, do it that many times."
(interactive "p" shortdoc-mode)
(shortdoc--goto-section arg 'shortdoc-section t)
(forward-line -2))
+(defun shortdoc-copy-function-as-kill ()
+ "Copy name of the function near point into the kill ring."
+ (interactive)
+ (save-excursion
+ (goto-char (pos-bol))
+ (when-let* ((re (rx bol "(" (group (+ (not (in " "))))))
+ (string
+ (and (or (looking-at re)
+ (re-search-backward re nil t))
+ (match-string 1))))
+ (set-text-properties 0 (length string) nil string)
+ (kill-new string)
+ (message string))))
+
(provide 'shortdoc)
;;; shortdoc.el ends here
diff --git a/lisp/emacs-lisp/subr-x.el b/lisp/emacs-lisp/subr-x.el
index bd7c3c82f97..6e4d88b4df3 100644
--- a/lisp/emacs-lisp/subr-x.el
+++ b/lisp/emacs-lisp/subr-x.el
@@ -97,6 +97,7 @@ threading."
(maphash (lambda (_ v) (push v values)) hash-table)
values))
+;;;###autoload
(defsubst string-join (strings &optional separator)
"Join all STRINGS using SEPARATOR.
Optional argument SEPARATOR must be a string, a vector, or a list of
diff --git a/lisp/emacs-lisp/testcover.el b/lisp/emacs-lisp/testcover.el
index cd2e388ce42..760063d1f9d 100644
--- a/lisp/emacs-lisp/testcover.el
+++ b/lisp/emacs-lisp/testcover.el
@@ -637,8 +637,7 @@ argument is maybe, return maybe. Return 1value only if both arguments
are 1value."
(cl-case val
(testcover-1value result)
- (maybe (and result 'maybe))
- (nil nil)))
+ (maybe (and result 'maybe))))
(defun testcover-analyze-coverage-compose (forms func)
"Analyze a list of FORMS for code coverage using FUNC.
diff --git a/lisp/emacs-lisp/vtable.el b/lisp/emacs-lisp/vtable.el
index 61265c97c28..9bdf90bf1d6 100644
--- a/lisp/emacs-lisp/vtable.el
+++ b/lisp/emacs-lisp/vtable.el
@@ -770,7 +770,8 @@ If NEXT, do the next column."
((string-match "\\([0-9.]+\\)px" spec)
(string-to-number (match-string 1 spec)))
((string-match "\\([0-9.]+\\)%" spec)
- (* (string-to-number (match-string 1 spec)) (window-width nil t)))
+ (/ (* (string-to-number (match-string 1 spec)) (window-width nil t))
+ 100))
(t
(error "Invalid spec: %s" spec))))