diff options
author | Yuan Fu <casouri@gmail.com> | 2022-10-05 14:22:03 -0700 |
---|---|---|
committer | Yuan Fu <casouri@gmail.com> | 2022-10-05 14:22:03 -0700 |
commit | 7ebbd4efc3d45403cf845d35c36c21756baeeba8 (patch) | |
tree | f53223ce7dbd64c079aced6e1a77964d1a8eaa3f /lisp/emacs-lisp | |
parent | cb183f6467401fb5ed2b7fc98ca75be9d943cbe3 (diff) | |
parent | 95efafb72664049f8ac825047df3645656cf76f4 (diff) | |
download | emacs-7ebbd4efc3d45403cf845d35c36c21756baeeba8.tar.gz emacs-7ebbd4efc3d45403cf845d35c36c21756baeeba8.tar.bz2 emacs-7ebbd4efc3d45403cf845d35c36c21756baeeba8.zip |
Merge branch 'master' into feature/tree-sitter
Diffstat (limited to 'lisp/emacs-lisp')
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)))) |