summaryrefslogtreecommitdiff
path: root/lisp/emacs-lisp
diff options
context:
space:
mode:
Diffstat (limited to 'lisp/emacs-lisp')
-rw-r--r--lisp/emacs-lisp/advice.el75
-rw-r--r--lisp/emacs-lisp/backquote.el2
-rw-r--r--lisp/emacs-lisp/benchmark.el2
-rw-r--r--lisp/emacs-lisp/bindat.el6
-rw-r--r--lisp/emacs-lisp/byte-opt.el44
-rw-r--r--lisp/emacs-lisp/byte-run.el14
-rw-r--r--lisp/emacs-lisp/bytecomp.el346
-rw-r--r--lisp/emacs-lisp/chart.el4
-rw-r--r--lisp/emacs-lisp/checkdoc.el3
-rw-r--r--lisp/emacs-lisp/cl-extra.el38
-rw-r--r--lisp/emacs-lisp/cl-generic.el14
-rw-r--r--lisp/emacs-lisp/cl-macs.el28
-rw-r--r--lisp/emacs-lisp/cl-print.el2
-rw-r--r--lisp/emacs-lisp/cl-seq.el15
-rw-r--r--lisp/emacs-lisp/copyright.el11
-rw-r--r--lisp/emacs-lisp/debug.el1
-rw-r--r--lisp/emacs-lisp/easy-mmode.el133
-rw-r--r--lisp/emacs-lisp/easymenu.el8
-rw-r--r--lisp/emacs-lisp/edebug.el39
-rw-r--r--lisp/emacs-lisp/eieio-custom.el10
-rw-r--r--lisp/emacs-lisp/eldoc.el412
-rw-r--r--lisp/emacs-lisp/elint.el23
-rw-r--r--lisp/emacs-lisp/ert-x.el41
-rw-r--r--lisp/emacs-lisp/ert.el27
-rw-r--r--lisp/emacs-lisp/lisp-mode.el23
-rw-r--r--lisp/emacs-lisp/lisp.el16
-rw-r--r--lisp/emacs-lisp/memory-report.el303
-rw-r--r--lisp/emacs-lisp/package.el80
-rw-r--r--lisp/emacs-lisp/pcase.el5
-rw-r--r--lisp/emacs-lisp/pp.el49
-rw-r--r--lisp/emacs-lisp/re-builder.el6
-rw-r--r--lisp/emacs-lisp/regi.el23
-rw-r--r--lisp/emacs-lisp/rx.el3
-rw-r--r--lisp/emacs-lisp/seq.el9
-rw-r--r--lisp/emacs-lisp/shadow.el5
-rw-r--r--lisp/emacs-lisp/shortdoc.el1254
-rw-r--r--lisp/emacs-lisp/smie.el4
-rw-r--r--lisp/emacs-lisp/syntax.el2
-rw-r--r--lisp/emacs-lisp/tabulated-list.el33
-rw-r--r--lisp/emacs-lisp/text-property-search.el12
-rw-r--r--lisp/emacs-lisp/thunk.el2
-rw-r--r--lisp/emacs-lisp/timer-list.el40
-rw-r--r--lisp/emacs-lisp/trace.el2
-rw-r--r--lisp/emacs-lisp/unsafep.el32
-rw-r--r--lisp/emacs-lisp/warnings.el2
45 files changed, 2532 insertions, 671 deletions
diff --git a/lisp/emacs-lisp/advice.el b/lisp/emacs-lisp/advice.el
index 0ebd2741d2e..c8a6676b665 100644
--- a/lisp/emacs-lisp/advice.el
+++ b/lisp/emacs-lisp/advice.el
@@ -1840,8 +1840,7 @@ function at point for which PREDICATE returns non-nil)."
(or default
;; Prefer func name at point, if it's an advised function etc.
(let ((function (progn
- (require 'help)
- (function-called-at-point))))
+ (function-called-at-point))))
(and function
(member (symbol-name function) ad-advised-functions)
(or (null predicate)
@@ -1894,8 +1893,8 @@ class of FUNCTION)."
"Read name of existing advice of CLASS for FUNCTION with completion.
An optional PROMPT is used to prompt for the name."
(let* ((name-completion-table
- (mapcar (function (lambda (advice)
- (list (symbol-name (ad-advice-name advice)))))
+ (mapcar (lambda (advice)
+ (list (symbol-name (ad-advice-name advice))))
(ad-get-advice-info-field function class)))
(default
(if (null name-completion-table)
@@ -2224,8 +2223,6 @@ For that it has to be fbound with a non-autoload definition."
(let ((byte-compile-warnings byte-compile-warnings)
;; Don't pop up windows showing byte-compiler warnings.
(warning-suppress-types '((bytecomp))))
- (if (featurep 'cl)
- (byte-compile-disable-warning 'cl-functions))
(byte-compile (ad-get-advice-info-field function 'advicefunname))))
;; @@@ Accessing argument lists:
@@ -2255,13 +2252,11 @@ element is its actual current value, and the third element is either
(let* ((parsed-arglist (ad-parse-arglist arglist))
(rest (nth 2 parsed-arglist)))
`(list
- ,@(mapcar (function
- (lambda (req)
- `(list ',req ,req 'required)))
+ ,@(mapcar (lambda (req)
+ `(list ',req ,req 'required))
(nth 0 parsed-arglist))
- ,@(mapcar (function
- (lambda (opt)
- `(list ',opt ,opt 'optional)))
+ ,@(mapcar (lambda (opt)
+ `(list ',opt ,opt 'optional))
(nth 1 parsed-arglist))
,@(if rest (list `(list ',rest ,rest 'rest))))))
@@ -2372,28 +2367,26 @@ The assignment starts at position INDEX."
(defun ad-insert-argument-access-forms (definition arglist)
"Expands arg-access text macros in DEFINITION according to ARGLIST."
(ad-substitute-tree
- (function
- (lambda (form)
- (or (eq form 'ad-arg-bindings)
- (and (memq (car-safe form)
- '(ad-get-arg ad-get-args ad-set-arg ad-set-args))
- (integerp (car-safe (cdr form)))))))
- (function
- (lambda (form)
- (if (eq form 'ad-arg-bindings)
- (ad-retrieve-args-form arglist)
- (let ((accessor (car form))
- (index (car (cdr form)))
- (val (car (cdr (ad-insert-argument-access-forms
- (cdr form) arglist)))))
- (cond ((eq accessor 'ad-get-arg)
- (ad-get-argument arglist index))
- ((eq accessor 'ad-set-arg)
- (ad-set-argument arglist index val))
- ((eq accessor 'ad-get-args)
- (ad-get-arguments arglist index))
- ((eq accessor 'ad-set-args)
- (ad-set-arguments arglist index val)))))))
+ (lambda (form)
+ (or (eq form 'ad-arg-bindings)
+ (and (memq (car-safe form)
+ '(ad-get-arg ad-get-args ad-set-arg ad-set-args))
+ (integerp (car-safe (cdr form))))))
+ (lambda (form)
+ (if (eq form 'ad-arg-bindings)
+ (ad-retrieve-args-form arglist)
+ (let ((accessor (car form))
+ (index (car (cdr form)))
+ (val (car (cdr (ad-insert-argument-access-forms
+ (cdr form) arglist)))))
+ (cond ((eq accessor 'ad-get-arg)
+ (ad-get-argument arglist index))
+ ((eq accessor 'ad-set-arg)
+ (ad-set-argument arglist index val))
+ ((eq accessor 'ad-get-args)
+ (ad-get-arguments arglist index))
+ ((eq accessor 'ad-set-args)
+ (ad-set-arguments arglist index val))))))
definition))
;; @@@ Mapping argument lists:
@@ -2623,8 +2616,8 @@ should be modified. The assembled function will be returned."
(defun ad-make-hook-form (function hook-name)
"Make hook-form from FUNCTION's advice bodies in class HOOK-NAME."
(let ((hook-forms
- (mapcar (function (lambda (advice)
- (ad-body-forms (ad-advice-definition advice))))
+ (mapcar (lambda (advice)
+ (ad-body-forms (ad-advice-definition advice)))
(ad-get-enabled-advices function hook-name))))
(if hook-forms
(macroexp-progn (apply 'append hook-forms)))))
@@ -3167,15 +3160,14 @@ usage: (defadvice FUNCTION (CLASS NAME [POSITION] [ARGLIST] FLAG...)
(setq args (cdr args)))))
(flags
(mapcar
- (function
- (lambda (flag)
+ (lambda (flag)
(let ((completion
(try-completion (symbol-name flag) ad-defadvice-flags)))
(cond ((eq completion t) flag)
((member completion ad-defadvice-flags)
(intern completion))
(t (error "defadvice: Invalid or ambiguous flag: %s"
- flag))))))
+ flag)))))
args))
(advice (ad-make-advice
name (memq 'protect flags)
@@ -3217,11 +3209,10 @@ undone on exit of this macro."
(let* ((index -1)
;; Make let-variables to store current definitions:
(current-bindings
- (mapcar (function
- (lambda (function)
+ (mapcar (lambda (function)
(setq index (1+ index))
(list (intern (format "ad-oRiGdEf-%d" index))
- `(symbol-function ',function))))
+ `(symbol-function ',function)))
functions)))
`(let ,current-bindings
(unwind-protect
diff --git a/lisp/emacs-lisp/backquote.el b/lisp/emacs-lisp/backquote.el
index 8567a3a44f3..5413022e341 100644
--- a/lisp/emacs-lisp/backquote.el
+++ b/lisp/emacs-lisp/backquote.el
@@ -1,4 +1,4 @@
-;;; backquote.el --- implement the ` Lisp construct
+;;; backquote.el --- implement the ` Lisp construct -*- lexical-binding: t -*-
;; Copyright (C) 1990, 1992, 1994, 2001-2020 Free Software Foundation,
;; Inc.
diff --git a/lisp/emacs-lisp/benchmark.el b/lisp/emacs-lisp/benchmark.el
index 2fa5a878801..8cf1f54411a 100644
--- a/lisp/emacs-lisp/benchmark.el
+++ b/lisp/emacs-lisp/benchmark.el
@@ -43,7 +43,7 @@
;;;###autoload
(defmacro benchmark-run (&optional repetitions &rest forms)
"Time execution of FORMS.
-If REPETITIONS is supplied as a number, run forms that many times,
+If REPETITIONS is supplied as a number, run FORMS that many times,
accounting for the overhead of the resulting loop. Otherwise run
FORMS once.
Return a list of the total elapsed time for execution, the number of
diff --git a/lisp/emacs-lisp/bindat.el b/lisp/emacs-lisp/bindat.el
index d168c255121..0fd273aa3e3 100644
--- a/lisp/emacs-lisp/bindat.el
+++ b/lisp/emacs-lisp/bindat.el
@@ -298,7 +298,7 @@
type field
field nil))
(if (and (consp len) (not (eq type 'eval)))
- (setq len (apply 'bindat-get-field struct len)))
+ (setq len (apply #'bindat-get-field struct len)))
(if (not len)
(setq len 1))
(cond
@@ -557,7 +557,7 @@ e.g. corresponding to STRUCT.FIELD1[INDEX2].FIELD3..."
type field
field nil))
(if (and (consp len) (not (eq type 'eval)))
- (setq len (apply 'bindat-get-field struct len)))
+ (setq len (apply #'bindat-get-field struct len)))
(if (not len)
(setq len 1))
(cond
@@ -624,7 +624,7 @@ only that many elements from VECT."
(while (> i 0)
(setq i (1- i)
s (cons (format (if (= i 0) fmt fmt2) (aref vect i)) s)))
- (apply 'concat s)))
+ (apply #'concat s)))
(defun bindat-vector-to-dec (vect &optional sep)
"Format vector VECT in decimal format separated by dots.
diff --git a/lisp/emacs-lisp/byte-opt.el b/lisp/emacs-lisp/byte-opt.el
index 65e4e446266..469bbe6c7c0 100644
--- a/lisp/emacs-lisp/byte-opt.el
+++ b/lisp/emacs-lisp/byte-opt.el
@@ -830,11 +830,13 @@
(defun byte-optimize-assoc (form)
;; Replace 2-argument `assoc' with `assq', `rassoc' with `rassq',
;; if the first arg is a symbol.
- (if (and (= (length form) 3)
- (byte-optimize--constant-symbol-p (nth 1 form)))
- (cons (if (eq (car form) 'assoc) 'assq 'rassq)
- (cdr form))
- form))
+ (cond
+ ((/= (length form) 3)
+ form)
+ ((byte-optimize--constant-symbol-p (nth 1 form))
+ (cons (if (eq (car form) 'assoc) 'assq 'rassq)
+ (cdr form)))
+ (t (byte-optimize-constant-args form))))
(defun byte-optimize-memq (form)
;; (memq foo '(bar)) => (and (eq foo 'bar) '(bar))
@@ -1144,13 +1146,15 @@
;; I wonder if I missed any :-\)
(let ((side-effect-free-fns
'(% * + - / /= 1+ 1- < <= = > >= abs acos append aref ash asin atan
- assoc assq
+ assq
+ bool-vector-count-consecutive bool-vector-count-population
+ bool-vector-subsetp
boundp buffer-file-name buffer-local-variables buffer-modified-p
buffer-substring byte-code-function-p
capitalize car-less-than-car car cdr ceiling char-after char-before
char-equal char-to-string char-width compare-strings
compare-window-configurations concat coordinates-in-window-p
- copy-alist copy-sequence copy-marker cos count-lines
+ copy-alist copy-sequence copy-marker copysign cos count-lines
current-time-string current-time-zone
decode-char
decode-time default-boundp default-value documentation downcase
@@ -1163,22 +1167,22 @@
frame-visible-p fround ftruncate
get gethash get-buffer get-buffer-window getenv get-file-buffer
hash-table-count
- int-to-string intern-soft
+ int-to-string intern-soft isnan
keymap-parent
- length line-beginning-position line-end-position
+ lax-plist-get ldexp length line-beginning-position line-end-position
local-variable-if-set-p local-variable-p locale-info
log log10 logand logb logcount logior lognot logxor lsh
make-byte-code make-list make-string make-symbol marker-buffer max
- member memq min minibuffer-selected-window minibuffer-window
+ member memq memql min minibuffer-selected-window minibuffer-window
mod multibyte-char-to-unibyte next-window nth nthcdr number-to-string
parse-colon-path plist-get plist-member
prefix-numeric-value previous-window prin1-to-string propertize
degrees-to-radians
- radians-to-degrees rassq rassoc read-from-string regexp-quote
- region-beginning region-end reverse round
+ radians-to-degrees rassq rassoc read-from-string regexp-opt
+ regexp-quote region-beginning region-end reverse round
sin sqrt string string< string= string-equal string-lessp
string-search string-to-char
- string-to-number substring
+ string-to-number string-to-syntax substring
sxhash sxhash-equal sxhash-eq sxhash-eql
symbol-function symbol-name symbol-plist symbol-value string-make-unibyte
string-make-multibyte string-as-multibyte string-as-unibyte
@@ -1228,7 +1232,7 @@
standard-case-table standard-syntax-table stringp subrp symbolp
syntax-table syntax-table-p
this-command-keys this-command-keys-vector this-single-command-keys
- this-single-command-raw-keys
+ this-single-command-raw-keys type-of
user-real-login-name user-real-uid user-uid
vector vectorp visible-frame-list
wholenump window-configuration-p window-live-p
@@ -1260,7 +1264,7 @@
'(concat regexp-opt regexp-quote
string-to-char string-to-syntax symbol-name
eq eql
- = /= < <= => > min max
+ = /= < <= >= > min max
+ - * / % mod abs ash 1+ 1- sqrt
logand logior lognot logxor logcount
copysign isnan ldexp float logb
@@ -1268,7 +1272,7 @@
ffloor fceiling fround ftruncate
string= string-equal string< string-lessp
string-search
- consp atom listp nlistp propert-list-p
+ consp atom listp nlistp proper-list-p
sequencep arrayp vectorp stringp bool-vector-p hash-table-p
null not
numberp integerp floatp natnump characterp
@@ -1455,10 +1459,10 @@
(setq rest (cdr rest))))
(if tags (error "optimizer error: missed tags %s" tags))
;; Remove addrs, lap = ( [ (op . arg) | (TAG tagno) ]* )
- (mapcar (function (lambda (elt)
- (if (numberp elt)
- elt
- (cdr elt))))
+ (mapcar (lambda (elt)
+ (if (numberp elt)
+ elt
+ (cdr elt)))
(nreverse lap))))
diff --git a/lisp/emacs-lisp/byte-run.el b/lisp/emacs-lisp/byte-run.el
index 5279a57cd0c..27f54d0ca2a 100644
--- a/lisp/emacs-lisp/byte-run.el
+++ b/lisp/emacs-lisp/byte-run.el
@@ -432,7 +432,16 @@ ACCESS-TYPE if non-nil should specify the kind of access that will trigger
(defmacro define-obsolete-variable-alias (obsolete-name current-name
&optional when docstring)
"Make OBSOLETE-NAME a variable alias for CURRENT-NAME and mark it obsolete.
-This uses `defvaralias' and `make-obsolete-variable' (which see).
+
+WHEN should be a string indicating when the variable was first
+made obsolete, for example a date or a release number.
+
+This macro evaluates all its parameters, and both OBSOLETE-NAME
+and CURRENT-NAME should be symbols, so a typical usage would look like:
+
+ (define-obsolete-variable-alias 'foo-thing 'bar-thing \"27.1\")
+
+This macro uses `defvaralias' and `make-obsolete-variable' (which see).
See the Info node `(elisp)Variable Aliases' for more details.
If CURRENT-NAME is a defcustom or a defvar (more generally, any variable
@@ -446,9 +455,6 @@ dumped with Emacs). This is so that any user customizations are
applied before the defcustom tries to initialize the
variable (this is due to the way `defvaralias' works).
-WHEN should be a string indicating when the variable was first
-made obsolete, for example a date or a release number.
-
For the benefit of Customize, if OBSOLETE-NAME has
any of the following properties, they are copied to
CURRENT-NAME, if it does not already have them:
diff --git a/lisp/emacs-lisp/bytecomp.el b/lisp/emacs-lisp/bytecomp.el
index 7c95c918009..e23bb9f5e6e 100644
--- a/lisp/emacs-lisp/bytecomp.el
+++ b/lisp/emacs-lisp/bytecomp.el
@@ -144,7 +144,7 @@ is hard-coded in various places in Emacs.)"
;; Eg is_elc in Fload.
:type 'regexp)
-(defcustom byte-compile-dest-file-function nil
+(defcustom byte-compile-dest-file-function #'byte-compile--default-dest-file
"Function for the function `byte-compile-dest-file' to call.
It should take one argument, the name of an Emacs Lisp source
file name, and return the name of the compiled file.
@@ -177,14 +177,16 @@ function to do the work. Otherwise, if FILENAME matches
`emacs-lisp-file-regexp' (by default, files with the extension \".el\"),
replaces the matching part (and anything after it) with \".elc\";
otherwise adds \".elc\"."
- (if byte-compile-dest-file-function
- (funcall byte-compile-dest-file-function filename)
- (setq filename (file-name-sans-versions
- (byte-compiler-base-file-name filename)))
- (cond ((string-match emacs-lisp-file-regexp filename)
- (concat (substring filename 0 (match-beginning 0)) ".elc"))
- (t (concat filename ".elc")))))
-)
+ (funcall (or byte-compile-dest-file-function
+ #'byte-compile--default-dest-file)
+ filename)))
+
+(defun byte-compile--default-dest-file (filename)
+ (setq filename (file-name-sans-versions
+ (byte-compiler-base-file-name filename)))
+ (cond ((string-match emacs-lisp-file-regexp filename)
+ (concat (substring filename 0 (match-beginning 0)) ".elc"))
+ (t (concat filename ".elc"))))
;; This can be the 'byte-compile property of any symbol.
(autoload 'byte-compile-inline-expand "byte-opt")
@@ -268,6 +270,13 @@ This option is enabled by default because it reduces Emacs memory usage."
(defconst byte-compile-log-buffer "*Compile-Log*"
"Name of the byte-compiler's log buffer.")
+(defvar byte-compile--known-dynamic-vars nil
+ "Variables known to be declared as dynamic, for warning purposes.
+Each element is (VAR . FILE), indicating that VAR is declared in FILE.")
+
+(defvar byte-compile--seen-defvars nil
+ "All dynamic variable declarations seen so far.")
+
(defcustom byte-optimize-log nil
"If non-nil, the byte-compiler will log its optimizations.
If this is `source', then only source-level optimizations will be logged.
@@ -284,13 +293,13 @@ The information is logged to `byte-compile-log-buffer'."
;; This needs to be autoloaded because it needs to be available to
;; Emacs before the byte compiler is loaded, otherwise Emacs will not
;; know that this variable is marked as safe until it is too late.
-;; (See https://lists.gnu.org/archive/html/emacs-devel/2018-01/msg00261.html )
+;; (See https://lists.gnu.org/r/emacs-devel/2018-01/msg00261.html )
;;;###autoload(put 'byte-compile-error-on-warn 'safe-local-variable 'booleanp)
(defconst byte-compile-warning-types
'(redefine callargs free-vars unresolved
- obsolete noruntime cl-functions interactive-only
- make-local mapcar constants suspicious lexical)
+ obsolete noruntime interactive-only
+ make-local mapcar constants suspicious lexical lexical-dynamic)
"The list of warning types used when `byte-compile-warnings' is t.")
(defcustom byte-compile-warnings t
"List of warnings that the byte-compiler should issue (t for all).
@@ -305,11 +314,11 @@ Elements of the list may be:
obsolete obsolete variables and functions.
noruntime functions that may not be defined at runtime (typically
defined only under `eval-when-compile').
- cl-functions calls to runtime functions (as distinguished from macros and
- aliases) from the old CL package (not the newer cl-lib).
interactive-only
commands that normally shouldn't be called from Lisp code.
lexical global/dynamic variables lacking a prefix.
+ lexical-dynamic
+ lexically bound variable declared dynamic elsewhere
make-local calls to make-variable-buffer-local that may be incorrect.
mapcar mapcar called for effect.
constants let-binding of, or assignment to, constants/nonvariables.
@@ -959,11 +968,6 @@ CONST2 may be evaluated multiple times."
;;; compile-time evaluation
-(defun byte-compile-cl-file-p (file)
- "Return non-nil if FILE is one of the CL files."
- (and (stringp file)
- (string-match "^cl\\.el" (file-name-nondirectory file))))
-
(defun byte-compile-eval (form)
"Eval FORM and mark the functions defined therein.
Each function's symbol gets added to `byte-compile-noruntime-functions'."
@@ -994,18 +998,7 @@ Each function's symbol gets added to `byte-compile-noruntime-functions'."
(when (and (symbolp s) (not (memq s old-autoloads)))
(push s byte-compile-noruntime-functions))
(when (and (consp s) (eq t (car s)))
- (push (cdr s) old-autoloads)))))))
- (when (byte-compile-warning-enabled-p 'cl-functions)
- (let ((hist-new load-history))
- ;; Go through load-history, looking for the cl files.
- ;; Since new files are added at the start of load-history,
- ;; we scan the new history until the tail matches the old.
- (while (and (not byte-compile-cl-functions)
- hist-new (not (eq hist-new hist-orig)))
- ;; We used to check if the file had already been loaded,
- ;; but it is better to check non-nil byte-compile-cl-functions.
- (and (byte-compile-cl-file-p (car (pop hist-new)))
- (byte-compile-find-cl-functions))))))))
+ (push (cdr s) old-autoloads))))))))))
(defun byte-compile-eval-before-compile (form)
"Evaluate FORM for `eval-and-compile'."
@@ -1016,9 +1009,7 @@ Each function's symbol gets added to `byte-compile-noruntime-functions'."
;; There are other ways to do this nowadays.
(let ((tem current-load-list))
(while (not (eq tem hist-nil-orig))
- (when (equal (car tem) '(require . cl))
- (byte-compile-disable-warning 'cl-functions))
- (setq tem (cdr tem)))))))
+ (setq tem (cdr tem)))))))
;;; byte compiler messages
@@ -1568,45 +1559,6 @@ extra args."
(if (equal sig1 '(1 . 1)) "argument" "arguments")
(byte-compile-arglist-signature-string sig2)))))))
-(defvar byte-compile-cl-functions nil
- "List of functions defined in CL.")
-
-;; Can't just add this to cl-load-hook, because that runs just before
-;; the forms from cl.el get added to load-history.
-(defun byte-compile-find-cl-functions ()
- (unless byte-compile-cl-functions
- (dolist (elt load-history)
- (and (byte-compile-cl-file-p (car elt))
- (dolist (e (cdr elt))
- ;; Includes the cl-foo functions that cl autoloads.
- (when (memq (car-safe e) '(autoload defun))
- (push (cdr e) byte-compile-cl-functions)))))))
-
-(defun byte-compile-cl-warn (form)
- "Warn if FORM is a call of a function from the CL package."
- (let ((func (car-safe form)))
- (if (and byte-compile-cl-functions
- (memq func byte-compile-cl-functions)
- ;; Aliases which won't have been expanded at this point.
- ;; These aren't all aliases of subrs, so not trivial to
- ;; avoid hardwiring the list.
- (not (memq func
- '(cl--block-wrapper cl--block-throw
- multiple-value-call nth-value
- copy-seq first second rest endp cl-member
- ;; These are included in generated code
- ;; that can't be called except at compile time
- ;; or unless cl is loaded anyway.
- cl--defsubst-expand cl-struct-setf-expander
- ;; These would sometimes be warned about
- ;; but such warnings are never useful,
- ;; so don't warn about them.
- macroexpand
- cl--compiling-file))))
- (byte-compile-warn "function `%s' from cl package called at runtime"
- func)))
- form)
-
(defun byte-compile-print-syms (str1 strn syms)
(when syms
(byte-compile-set-symbol-position (car syms) t))
@@ -1704,7 +1656,6 @@ extra args."
(and (markerp warning-series)
(eq (marker-buffer warning-series)
(get-buffer byte-compile-log-buffer)))))
- (byte-compile-find-cl-functions)
(if (or (eq warning-series 'byte-compile-warning-series)
warning-series-started)
;; warning-series does come from compilation,
@@ -1737,7 +1688,7 @@ Files in subdirectories of DIRECTORY are processed also."
(byte-recompile-directory directory nil t))
;;;###autoload
-(defun byte-recompile-directory (directory &optional arg force)
+(defun byte-recompile-directory (directory &optional arg force follow-symlinks)
"Recompile every `.el' file in DIRECTORY that needs recompilation.
This happens when a `.elc' file exists but is older than the `.el' file.
Files in subdirectories of DIRECTORY are processed also.
@@ -1750,7 +1701,11 @@ compile it. A nonzero ARG also means ask about each subdirectory
before scanning it.
If the third argument FORCE is non-nil, recompile every `.el' file
-that already has a `.elc' file."
+that already has a `.elc' file.
+
+This command will normally not follow symlinks when compiling
+files. If FOLLOW-SYMLINKS is non-nil, symlinked `.el' files will
+also be compiled."
(interactive "DByte recompile directory: \nP")
(if arg (setq arg (prefix-numeric-value arg)))
(if noninteractive
@@ -1783,7 +1738,8 @@ that already has a `.elc' file."
(if (file-directory-p source)
(and (not (member file '("RCS" "CVS")))
(not (eq ?\. (aref file 0)))
- (not (file-symlink-p source))
+ (or follow-symlinks
+ (not (file-symlink-p source)))
;; This file is a subdirectory. Handle them differently.
(or (null arg) (eq 0 arg)
(y-or-n-p (concat "Check " source "? ")))
@@ -1836,10 +1792,9 @@ compile FILENAME. If optional argument ARG is 0, it compiles
the input file even if the `.elc' file does not exist.
Any other non-nil value of ARG means to ask the user.
-If optional argument LOAD is non-nil, loads the file after compiling.
-
If compilation is needed, this functions returns the result of
`byte-compile-file'; otherwise it returns `no-byte-compile'."
+ (declare (advertised-calling-convention (filename &optional force arg) "28.1"))
(interactive
(let ((file buffer-file-name)
(file-name nil)
@@ -1856,22 +1811,34 @@ If compilation is needed, this functions returns the result of
(let ((dest (byte-compile-dest-file filename))
;; Expand now so we get the current buffer's defaults
(filename (expand-file-name filename)))
- (if (if (file-exists-p dest)
- ;; File was already compiled
- ;; Compile if forced to, or filename newer
- (or force
- (file-newer-than-file-p filename dest))
- (and arg
- (or (eq 0 arg)
- (y-or-n-p (concat "Compile "
- filename "? ")))))
- (progn
- (if (and noninteractive (not byte-compile-verbose))
- (message "Compiling %s..." filename))
- (byte-compile-file filename load))
+ (prog1
+ (if (if (and dest (file-exists-p dest))
+ ;; File was already compiled
+ ;; Compile if forced to, or filename newer
+ (or force
+ (file-newer-than-file-p filename dest))
+ (and arg
+ (or (eq 0 arg)
+ (y-or-n-p (concat "Compile "
+ filename "? ")))))
+ (progn
+ (if (and noninteractive (not byte-compile-verbose))
+ (message "Compiling %s..." filename))
+ (byte-compile-file filename))
+ 'no-byte-compile)
(when load
- (load (if (file-exists-p dest) dest filename)))
- 'no-byte-compile)))
+ (load (if (and dest (file-exists-p dest)) dest filename))))))
+
+(defun byte-compile--load-dynvars (file)
+ (and file (not (equal file ""))
+ (with-temp-buffer
+ (insert-file-contents file)
+ (goto-char (point-min))
+ (let ((vars nil)
+ var)
+ (while (ignore-errors (setq var (read (current-buffer))))
+ (push var vars))
+ vars))))
(defvar byte-compile-level 0 ; bug#13787
"Depth of a recursive byte compilation.")
@@ -1881,8 +1848,10 @@ If compilation is needed, this functions returns the result of
"Compile a file of Lisp code named FILENAME into a file of byte code.
The output file's name is generated by passing FILENAME to the
function `byte-compile-dest-file' (which see).
-With prefix arg (noninteractively: 2nd arg), LOAD the file after compiling.
-The value is non-nil if there were no errors, nil if errors."
+The value is non-nil if there were no errors, nil if errors.
+
+See also `emacs-lisp-byte-compile-and-load'."
+ (declare (advertised-calling-convention (filename) "28.1"))
;; (interactive "fByte compile file: \nP")
(interactive
(let ((file buffer-file-name)
@@ -1911,8 +1880,11 @@ The value is non-nil if there were no errors, nil if errors."
(let ((byte-compile-current-file filename)
(byte-compile-current-group nil)
(set-auto-coding-for-load t)
+ (byte-compile--seen-defvars nil)
+ (byte-compile--known-dynamic-vars
+ (byte-compile--load-dynvars (getenv "EMACS_DYNVARS_FILE")))
target-file input-buffer output-buffer
- byte-compile-dest-file)
+ byte-compile-dest-file byte-compiler-error-flag)
(setq target-file (byte-compile-dest-file filename))
(setq byte-compile-dest-file target-file)
(with-current-buffer
@@ -1965,7 +1937,7 @@ The value is non-nil if there were no errors, nil if errors."
;; (message "%s not compiled because of `no-byte-compile: %s'"
;; (byte-compile-abbreviate-file filename)
;; (with-current-buffer input-buffer no-byte-compile))
- (when (file-exists-p target-file)
+ (when (and target-file (file-exists-p target-file))
(message "%s deleted because of `no-byte-compile: %s'"
(byte-compile-abbreviate-file target-file)
(buffer-local-value 'no-byte-compile input-buffer))
@@ -1974,7 +1946,6 @@ The value is non-nil if there were no errors, nil if errors."
'no-byte-compile)
(when byte-compile-verbose
(message "Compiling %s..." filename))
- (setq byte-compiler-error-flag nil)
;; It is important that input-buffer not be current at this call,
;; so that the value of point set in input-buffer
;; within byte-compile-from-buffer lingers in that buffer.
@@ -1990,36 +1961,50 @@ The value is non-nil if there were no errors, nil if errors."
(with-current-buffer output-buffer
(goto-char (point-max))
(insert "\n") ; aaah, unix.
- (if (file-writable-p target-file)
- ;; We must disable any code conversion here.
- (progn
- (let* ((coding-system-for-write 'no-conversion)
- ;; Write to a tempfile so that if another Emacs
- ;; process is trying to load target-file (eg in a
- ;; parallel bootstrap), it does not risk getting a
- ;; half-finished file. (Bug#4196)
- (tempfile
- (make-temp-file (expand-file-name target-file)))
- (default-modes (default-file-modes))
- (temp-modes (logand default-modes #o600))
- (desired-modes (logand default-modes #o666))
- (kill-emacs-hook
- (cons (lambda () (ignore-errors
- (delete-file tempfile)))
- kill-emacs-hook)))
- (unless (= temp-modes desired-modes)
- (set-file-modes tempfile desired-modes 'nofollow))
- (write-region (point-min) (point-max) tempfile nil 1)
- ;; This has the intentional side effect that any
- ;; hard-links to target-file continue to
- ;; point to the old file (this makes it possible
- ;; for installed files to share disk space with
- ;; the build tree, without causing problems when
- ;; emacs-lisp files in the build tree are
- ;; recompiled). Previously this was accomplished by
- ;; deleting target-file before writing it.
- (rename-file tempfile target-file t))
- (or noninteractive (message "Wrote %s" target-file)))
+ (cond
+ ((null target-file) nil) ;We only wanted the warnings!
+ ((and (file-writable-p target-file)
+ ;; We attempt to create a temporary file in the
+ ;; target directory, so the target directory must be
+ ;; writable.
+ (file-writable-p (file-name-directory target-file)))
+ ;; We must disable any code conversion here.
+ (let* ((coding-system-for-write 'no-conversion)
+ ;; Write to a tempfile so that if another Emacs
+ ;; process is trying to load target-file (eg in a
+ ;; parallel bootstrap), it does not risk getting a
+ ;; half-finished file. (Bug#4196)
+ (tempfile
+ (make-temp-file (expand-file-name target-file)))
+ (default-modes (default-file-modes))
+ (temp-modes (logand default-modes #o600))
+ (desired-modes (logand default-modes #o666))
+ (kill-emacs-hook
+ (cons (lambda () (ignore-errors
+ (delete-file tempfile)))
+ kill-emacs-hook)))
+ (unless (= temp-modes desired-modes)
+ (set-file-modes tempfile desired-modes 'nofollow))
+ (write-region (point-min) (point-max) tempfile nil 1)
+ ;; This has the intentional side effect that any
+ ;; hard-links to target-file continue to
+ ;; point to the old file (this makes it possible
+ ;; for installed files to share disk space with
+ ;; the build tree, without causing problems when
+ ;; emacs-lisp files in the build tree are
+ ;; recompiled). Previously this was accomplished by
+ ;; deleting target-file before writing it.
+ (rename-file tempfile target-file t))
+ (or noninteractive (message "Wrote %s" target-file)))
+ ((file-writable-p target-file)
+ ;; In case the target directory isn't writable (see e.g. Bug#44631),
+ ;; try writing to the output file directly. We must disable any
+ ;; code conversion here.
+ (let ((coding-system-for-write 'no-conversion))
+ (with-file-modes (logand (default-file-modes) #o666)
+ (write-region (point-min) (point-max) target-file nil 1)))
+ (or noninteractive (message "Wrote %s" target-file)))
+ (t
;; This is just to give a better error message than write-region
(let ((exists (file-exists-p target-file)))
(signal (if exists 'file-error 'file-missing)
@@ -2027,7 +2012,7 @@ The value is non-nil if there were no errors, nil if errors."
(if exists
"Cannot overwrite file"
"Directory not writable or nonexistent")
- target-file))))
+ target-file)))))
(kill-buffer (current-buffer)))
(if (and byte-compile-generate-call-tree
(or (eq t byte-compile-generate-call-tree)
@@ -2035,8 +2020,17 @@ The value is non-nil if there were no errors, nil if errors."
filename))))
(save-excursion
(display-call-tree filename)))
+ (let ((gen-dynvars (getenv "EMACS_GENERATE_DYNVARS")))
+ (when (and gen-dynvars (not (equal gen-dynvars ""))
+ byte-compile--seen-defvars)
+ (let ((dynvar-file (concat target-file ".dynvars")))
+ (message "Generating %s" dynvar-file)
+ (with-temp-buffer
+ (dolist (var (delete-dups byte-compile--seen-defvars))
+ (insert (format "%S\n" (cons var filename))))
+ (write-region (point-min) (point-max) dynvar-file)))))
(if load
- (load target-file))
+ (load target-file))
t))))
;;; compiling a single function
@@ -2425,7 +2419,8 @@ list that represents a doc string reference.
(setq byte-compile-lexical-variables
(delq sym byte-compile-lexical-variables))
(byte-compile-warn "Variable `%S' declared after its first use" sym))
- (push sym byte-compile-bound-variables))
+ (push sym byte-compile-bound-variables)
+ (push sym byte-compile--seen-defvars))
(defun byte-compile-file-form-defvar (form)
(let ((sym (nth 1 form)))
@@ -2470,8 +2465,7 @@ list that represents a doc string reference.
(put 'require 'byte-hunk-handler 'byte-compile-file-form-require)
(defun byte-compile-file-form-require (form)
(let ((args (mapcar 'eval (cdr form)))
- (hist-orig load-history)
- hist-new prov-cons)
+ hist-new prov-cons)
(apply 'require args)
;; Record the functions defined by the require in `byte-compile-new-defuns'.
@@ -2484,21 +2478,7 @@ list that represents a doc string reference.
(dolist (x (car hist-new))
(when (and (consp x)
(memq (car x) '(defun t)))
- (push (cdr x) byte-compile-new-defuns))))
-
- (when (byte-compile-warning-enabled-p 'cl-functions)
- ;; Detect (require 'cl) in a way that works even if cl is already loaded.
- (if (member (car args) '("cl" cl))
- (progn
- (byte-compile-warn "cl package required at runtime")
- (byte-compile-disable-warning 'cl-functions))
- ;; We may have required something that causes cl to be loaded, eg
- ;; the uncompiled version of a file that requires cl when compiling.
- (setq hist-new load-history)
- (while (and (not byte-compile-cl-functions)
- hist-new (not (eq hist-new hist-orig)))
- (and (byte-compile-cl-file-p (car (pop hist-new)))
- (byte-compile-find-cl-functions))))))
+ (push (cdr x) byte-compile-new-defuns)))))
(byte-compile-keep-pending form 'byte-compile-normal-call))
(put 'progn 'byte-hunk-handler 'byte-compile-file-form-progn)
@@ -2535,7 +2515,8 @@ list that represents a doc string reference.
;; and similar macros cleaner.
(put 'eval 'byte-hunk-handler 'byte-compile-file-form-eval)
(defun byte-compile-file-form-eval (form)
- (if (eq (car-safe (nth 1 form)) 'quote)
+ (if (and (eq (car-safe (nth 1 form)) 'quote)
+ (equal (nth 2 form) lexical-binding))
(nth 1 (nth 1 form))
(byte-compile-keep-pending form)))
@@ -2831,6 +2812,16 @@ If FORM is a lambda or a macro, byte-compile it as a function."
(ash nonrest 8)
(ash rest 7)))))
+(defun byte-compile--warn-lexical-dynamic (var context)
+ (when (byte-compile-warning-enabled-p 'lexical-dynamic var)
+ (byte-compile-warn
+ "`%s' lexically bound in %s here but declared dynamic in: %s"
+ var context
+ (mapconcat #'identity
+ (mapcan (lambda (v) (and (eq var (car v))
+ (list (cdr v))))
+ byte-compile--known-dynamic-vars)
+ ", "))))
(defun byte-compile-lambda (fun &optional add-lambda reserved-csts)
"Byte-compile a lambda-expression and return a valid function.
@@ -2859,6 +2850,10 @@ for symbols generated by the byte compiler itself."
(if (cdr body)
(setq body (cdr body))))))
(int (assq 'interactive body)))
+ (when lexical-binding
+ (dolist (var arglistvars)
+ (when (assq var byte-compile--known-dynamic-vars)
+ (byte-compile--warn-lexical-dynamic var 'lambda))))
;; Process the interactive spec.
(when int
(byte-compile-set-symbol-position 'interactive)
@@ -3148,7 +3143,7 @@ for symbols generated by the byte compiler itself."
run-hook-with-args-until-failure))
(pcase (cdr form)
(`(',var . ,_)
- (when (assq var byte-compile-lexical-variables)
+ (when (memq var byte-compile-lexical-variables)
(byte-compile-report-error
(format-message "%s cannot use lexical var `%s'" fn var))))))
;; Warn about using obsolete hooks.
@@ -3184,9 +3179,7 @@ for symbols generated by the byte compiler itself."
;; differently now).
(not (eq handler 'cl-byte-compile-compiler-macro))))
(funcall handler form)
- (byte-compile-normal-call form))
- (if (byte-compile-warning-enabled-p 'cl-functions)
- (byte-compile-cl-warn form))))
+ (byte-compile-normal-call form))))
((and (byte-code-function-p (car form))
(memq byte-optimize '(t lap)))
(byte-compile-unfold-bcf form))
@@ -3377,6 +3370,27 @@ for symbols generated by the byte compiler itself."
(push var byte-compile-bound-variables)
(byte-compile-dynamic-variable-op 'byte-varbind var))
+(defun byte-compile-free-vars-warn (var &optional assignment)
+ "Warn if symbol VAR refers to a free variable.
+VAR must not be lexically bound.
+If optional argument ASSIGNMENT is non-nil, this is treated as an
+assignment (i.e. `setq'). "
+ (unless (or (not (byte-compile-warning-enabled-p 'free-vars var))
+ (boundp var)
+ (memq var byte-compile-bound-variables)
+ (memq var (if assignment
+ byte-compile-free-assignments
+ byte-compile-free-references)))
+ (let* ((varname (prin1-to-string var))
+ (desc (if assignment "assignment" "reference"))
+ (suggestions (help-uni-confusable-suggestions varname)))
+ (byte-compile-warn "%s to free variable `%s'%s"
+ desc varname
+ (if suggestions (concat "\n " suggestions) "")))
+ (push var (if assignment
+ byte-compile-free-assignments
+ byte-compile-free-references))))
+
(defun byte-compile-variable-ref (var)
"Generate code to push the value of the variable VAR on the stack."
(byte-compile-check-variable var 'reference)
@@ -3385,15 +3399,7 @@ for symbols generated by the byte compiler itself."
;; VAR is lexically bound
(byte-compile-stack-ref (cdr lex-binding))
;; VAR is dynamically bound
- (unless (or (not (byte-compile-warning-enabled-p 'free-vars var))
- (boundp var)
- (memq var byte-compile-bound-variables)
- (memq var byte-compile-free-references))
- (let* ((varname (prin1-to-string var))
- (suggestions (help-uni-confusable-suggestions varname)))
- (byte-compile-warn "reference to free variable `%s'%s" varname
- (if suggestions (concat "\n " suggestions) "")))
- (push var byte-compile-free-references))
+ (byte-compile-free-vars-warn var)
(byte-compile-dynamic-variable-op 'byte-varref var))))
(defun byte-compile-variable-set (var)
@@ -3404,15 +3410,7 @@ for symbols generated by the byte compiler itself."
;; VAR is lexically bound.
(byte-compile-stack-set (cdr lex-binding))
;; VAR is dynamically bound.
- (unless (or (not (byte-compile-warning-enabled-p 'free-vars var))
- (boundp var)
- (memq var byte-compile-bound-variables)
- (memq var byte-compile-free-assignments))
- (let* ((varname (prin1-to-string var))
- (suggestions (help-uni-confusable-suggestions varname)))
- (byte-compile-warn "assignment to free variable `%s'%s" varname
- (if suggestions (concat "\n " suggestions) "")))
- (push var byte-compile-free-assignments))
+ (byte-compile-free-vars-warn var t)
(byte-compile-dynamic-variable-op 'byte-varset var))))
(defmacro byte-compile-get-constant (const)
@@ -4379,6 +4377,8 @@ Return non-nil if the TOS value was popped."
;; VAR is a simple stack-allocated lexical variable.
(progn (push (assq var init-lexenv)
byte-compile--lexical-environment)
+ (when (assq var byte-compile--known-dynamic-vars)
+ (byte-compile--warn-lexical-dynamic var 'let))
nil)
;; VAR should be dynamically bound.
(while (assq var byte-compile--lexical-environment)
@@ -5207,6 +5207,8 @@ and corresponding effects."
byte-compile-variable-ref))))
nil)
+(make-obsolete-variable 'bytecomp-load-hook
+ "use `with-eval-after-load' instead." "28.1")
(run-hooks 'bytecomp-load-hook)
;;; bytecomp.el ends here
diff --git a/lisp/emacs-lisp/chart.el b/lisp/emacs-lisp/chart.el
index 964836a32ac..c1c6e3bf0fd 100644
--- a/lisp/emacs-lisp/chart.el
+++ b/lisp/emacs-lisp/chart.el
@@ -4,7 +4,7 @@
;; Software Foundation, Inc.
;; Author: Eric M. Ludlam <zappo@gnu.org>
-;; Version: 0.2
+;; Old-Version: 0.2
;; Keywords: OO, chart, graph
;; This file is part of GNU Emacs.
@@ -120,7 +120,7 @@ too much in text characters anyways.")
(define-derived-mode chart-mode special-mode "Chart"
"Define a mode in Emacs for displaying a chart."
(buffer-disable-undo)
- (set (make-local-variable 'font-lock-global-modes) nil)
+ (setq-local font-lock-global-modes nil)
(font-lock-mode -1) ;Isn't it off already? --Stef
)
diff --git a/lisp/emacs-lisp/checkdoc.el b/lisp/emacs-lisp/checkdoc.el
index 23121c245ef..61384c0e6fa 100644
--- a/lisp/emacs-lisp/checkdoc.el
+++ b/lisp/emacs-lisp/checkdoc.el
@@ -37,7 +37,6 @@
;; documentation whenever you evaluate Lisp code with C-M-x
;; or [menu-bar emacs-lisp eval-buffer]. Additional key-bindings
;; are also provided under C-c ? KEY
-;; (require 'checkdoc)
;; (add-hook 'emacs-lisp-mode-hook 'checkdoc-minor-mode)
;;
;; Using `checkdoc':
@@ -2589,7 +2588,7 @@ This function will not modify `match-data'."
;; going on.
(if checkdoc-bouncy-flag (message "%s -> done" question))
(delete-region start end)
- (insert replacewith)
+ (insert-before-markers replacewith)
(if checkdoc-bouncy-flag (sit-for 0))
(setq ret t)))
(delete-overlay o)
diff --git a/lisp/emacs-lisp/cl-extra.el b/lisp/emacs-lisp/cl-extra.el
index 5bf74792c08..a55d78de153 100644
--- a/lisp/emacs-lisp/cl-extra.el
+++ b/lisp/emacs-lisp/cl-extra.el
@@ -201,15 +201,18 @@ the elements themselves.
;;;###autoload
(defun cl-some (cl-pred cl-seq &rest cl-rest)
- "Return true if PREDICATE is true of any element of SEQ or SEQs.
-If so, return the true (non-nil) value returned by PREDICATE.
+ "Say whether PREDICATE is true for any element in the SEQ sequences.
+More specifically, the return value of this function will be the
+same as the first return value of PREDICATE where PREDICATE has a
+non-nil value.
+
\n(fn PREDICATE SEQ...)"
(if (or cl-rest (nlistp cl-seq))
(catch 'cl-some
- (apply 'cl-map nil
- (function (lambda (&rest cl-x)
- (let ((cl-res (apply cl-pred cl-x)))
- (if cl-res (throw 'cl-some cl-res)))))
+ (apply #'cl-map nil
+ (lambda (&rest cl-x)
+ (let ((cl-res (apply cl-pred cl-x)))
+ (if cl-res (throw 'cl-some cl-res))))
cl-seq cl-rest) nil)
(let ((cl-x nil))
(while (and cl-seq (not (setq cl-x (funcall cl-pred (pop cl-seq))))))
@@ -221,9 +224,9 @@ If so, return the true (non-nil) value returned by PREDICATE.
\n(fn PREDICATE SEQ...)"
(if (or cl-rest (nlistp cl-seq))
(catch 'cl-every
- (apply 'cl-map nil
- (function (lambda (&rest cl-x)
- (or (apply cl-pred cl-x) (throw 'cl-every nil))))
+ (apply #'cl-map nil
+ (lambda (&rest cl-x)
+ (or (apply cl-pred cl-x) (throw 'cl-every nil)))
cl-seq cl-rest) t)
(while (and cl-seq (funcall cl-pred (car cl-seq)))
(setq cl-seq (cdr cl-seq)))
@@ -246,14 +249,13 @@ If so, return the true (non-nil) value returned by PREDICATE.
(or cl-base
(setq cl-base (copy-sequence [0])))
(map-keymap
- (function
- (lambda (cl-key cl-bind)
- (aset cl-base (1- (length cl-base)) cl-key)
- (if (keymapp cl-bind)
- (cl--map-keymap-recursively
- cl-func-rec cl-bind
- (vconcat cl-base (list 0)))
- (funcall cl-func-rec cl-base cl-bind))))
+ (lambda (cl-key cl-bind)
+ (aset cl-base (1- (length cl-base)) cl-key)
+ (if (keymapp cl-bind)
+ (cl--map-keymap-recursively
+ cl-func-rec cl-bind
+ (vconcat cl-base (list 0)))
+ (funcall cl-func-rec cl-base cl-bind)))
cl-map))
;;;###autoload
@@ -910,6 +912,8 @@ Outputs to the current buffer."
(mapc #'cl--describe-class-slot cslots))))
+(make-obsolete-variable 'cl-extra-load-hook
+ "use `with-eval-after-load' instead." "28.1")
(run-hooks 'cl-extra-load-hook)
;; Local variables:
diff --git a/lisp/emacs-lisp/cl-generic.el b/lisp/emacs-lisp/cl-generic.el
index 02da07daaf4..b37b05b9a3a 100644
--- a/lisp/emacs-lisp/cl-generic.el
+++ b/lisp/emacs-lisp/cl-generic.el
@@ -410,8 +410,18 @@ the specializer used will be the one returned by BODY."
;;;###autoload
(defmacro cl-defmethod (name args &rest body)
"Define a new method for generic function NAME.
-I.e. it defines the implementation of NAME to use for invocations where the
-values of the dispatch arguments match the specified TYPEs.
+This it defines an implementation of NAME to use for invocations
+of specific types of arguments.
+
+ARGS is a list of dispatch arguments (see `cl-defun'), but where
+each variable element is either just a single variable name VAR,
+or a list on the form (VAR TYPE).
+
+For instance:
+
+ (cl-defmethod foo (bar (format-string string) &optional zot)
+ (format format-string bar))
+
The dispatch arguments have to be among the mandatory arguments, and
all methods of NAME have to use the same set of arguments for dispatch.
Each dispatch argument and TYPE are specified in ARGS where the corresponding
diff --git a/lisp/emacs-lisp/cl-macs.el b/lisp/emacs-lisp/cl-macs.el
index 147a0a8f5a4..14b65ef25bf 100644
--- a/lisp/emacs-lisp/cl-macs.el
+++ b/lisp/emacs-lisp/cl-macs.el
@@ -819,16 +819,15 @@ final clause, and matches if no other keys match.
(cons
'cond
(mapcar
- (function
- (lambda (c)
- (cons (cond ((eq (car c) 'otherwise) t)
- ((eq (car c) 'cl--ecase-error-flag)
- `(error "cl-etypecase failed: %s, %s"
- ,temp ',(reverse type-list)))
- (t
- (push (car c) type-list)
- `(cl-typep ,temp ',(car c))))
- (or (cdr c) '(nil)))))
+ (lambda (c)
+ (cons (cond ((eq (car c) 'otherwise) t)
+ ((eq (car c) 'cl--ecase-error-flag)
+ `(error "cl-etypecase failed: %s, %s"
+ ,temp ',(reverse type-list)))
+ (t
+ (push (car c) type-list)
+ `(cl-typep ,temp ',(car c))))
+ (or (cdr c) '(nil))))
clauses)))))
;;;###autoload
@@ -2763,7 +2762,7 @@ Supported keywords for slots are:
(unless (cl--struct-name-p name)
(signal 'wrong-type-argument (list 'cl-struct-name-p name 'name)))
(setq descs (cons '(cl-tag-slot)
- (mapcar (function (lambda (x) (if (consp x) x (list x))))
+ (mapcar (lambda (x) (if (consp x) x (list x)))
descs)))
(while opts
(let ((opt (if (consp (car opts)) (caar opts) (car opts)))
@@ -2790,9 +2789,8 @@ Supported keywords for slots are:
;; we include EIEIO classes rather than cl-structs!
(when include-name (error "Can't :include more than once"))
(setq include-name (car args))
- (setq include-descs (mapcar (function
- (lambda (x)
- (if (consp x) x (list x))))
+ (setq include-descs (mapcar (lambda (x)
+ (if (consp x) x (list x)))
(cdr args))))
((eq opt :print-function)
(setq print-func (car args)))
@@ -3430,6 +3428,8 @@ STRUCT and SLOT-NAME are symbols. INST is a structure instance."
(nth (cl-struct-slot-offset ,struct-type ,slot-name) ,inst)
(aref ,inst (cl-struct-slot-offset ,struct-type ,slot-name)))))))
+(make-obsolete-variable 'cl-macs-load-hook
+ "use `with-eval-after-load' instead." "28.1")
(run-hooks 'cl-macs-load-hook)
;; Local variables:
diff --git a/lisp/emacs-lisp/cl-print.el b/lisp/emacs-lisp/cl-print.el
index 1043cf7b175..0375c57f77d 100644
--- a/lisp/emacs-lisp/cl-print.el
+++ b/lisp/emacs-lisp/cl-print.el
@@ -33,8 +33,6 @@
;;; Code:
-(require 'button)
-
(defvar cl-print-readably nil
"If non-nil, try and make sure the result can be `read'.")
diff --git a/lisp/emacs-lisp/cl-seq.el b/lisp/emacs-lisp/cl-seq.el
index f90cce9b471..8cfdd140f8e 100644
--- a/lisp/emacs-lisp/cl-seq.el
+++ b/lisp/emacs-lisp/cl-seq.el
@@ -69,10 +69,9 @@
(list 'or (list 'memq '(car cl-keys-temp)
(list 'quote
(mapcar
- (function
- (lambda (x)
- (if (consp x)
- (car x) x)))
+ (lambda (x)
+ (if (consp x)
+ (car x) x))
(append kwords
other-keys))))
'(car (cdr (memq (quote :allow-other-keys)
@@ -668,9 +667,9 @@ This is a destructive function; it reuses the storage of SEQ if possible.
(cl--parsing-keywords (:key) ()
(if (memq cl-key '(nil identity))
(sort cl-seq cl-pred)
- (sort cl-seq (function (lambda (cl-x cl-y)
- (funcall cl-pred (funcall cl-key cl-x)
- (funcall cl-key cl-y)))))))))
+ (sort cl-seq (lambda (cl-x cl-y)
+ (funcall cl-pred (funcall cl-key cl-x)
+ (funcall cl-key cl-y))))))))
;;;###autoload
(defun cl-stable-sort (cl-seq cl-pred &rest cl-keys)
@@ -1042,6 +1041,8 @@ Atoms are compared by `eql'; cons cells are compared recursively.
(and (not (consp cl-x)) (not (consp cl-y)) (cl--check-match cl-x cl-y)))
+(make-obsolete-variable 'cl-seq-load-hook
+ "use `with-eval-after-load' instead." "28.1")
(run-hooks 'cl-seq-load-hook)
;; Local variables:
diff --git a/lisp/emacs-lisp/copyright.el b/lisp/emacs-lisp/copyright.el
index 6fa51c3f644..edeeb03c32a 100644
--- a/lisp/emacs-lisp/copyright.el
+++ b/lisp/emacs-lisp/copyright.el
@@ -1,4 +1,4 @@
-;;; copyright.el --- update the copyright notice in current buffer
+;;; copyright.el --- update the copyright notice in current buffer -*- lexical-binding: t -*-
;; Copyright (C) 1991-1995, 1998, 2001-2020 Free Software Foundation,
;; Inc.
@@ -37,14 +37,12 @@
(defcustom copyright-limit 2000
"Don't try to update copyright beyond this position unless interactive.
A value of nil means to search whole buffer."
- :group 'copyright
:type '(choice (integer :tag "Limit")
(const :tag "No limit")))
(defcustom copyright-at-end-flag nil
"Non-nil means to search backwards from the end of the buffer for copyright.
This is useful for ChangeLogs."
- :group 'copyright
:type 'boolean
:version "23.1")
;;;###autoload(put 'copyright-at-end-flag 'safe-local-variable 'booleanp)
@@ -56,7 +54,6 @@ This is useful for ChangeLogs."
\\([1-9]\\([-0-9, ';/*%#\n\t]\\|\\s<\\|\\s>\\)*[0-9]+\\)"
"What your copyright notice looks like.
The second \\( \\) construct must match the years."
- :group 'copyright
:type 'regexp)
(defcustom copyright-names-regexp ""
@@ -64,7 +61,6 @@ The second \\( \\) construct must match the years."
Only copyright lines where the name matches this regexp will be updated.
This allows you to avoid adding years to a copyright notice belonging to
someone else or to a group for which you do not work."
- :group 'copyright
:type 'regexp)
;; The worst that can happen is a malicious regexp that overflows in
@@ -76,7 +72,6 @@ someone else or to a group for which you do not work."
"\\(\\s *\\)\\([1-9]\\([-0-9, ';/*%#\n\t]\\|\\s<\\|\\s>\\)*[0-9]+\\)"
"Match additional copyright notice years.
The second \\( \\) construct must match the years."
- :group 'copyright
:type 'regexp)
;; See "Copyright Notices" in maintain.info.
@@ -87,7 +82,6 @@ The second \\( \\) construct must match the years."
For example: 2005, 2006, 2007, 2008 might be replaced with 2005-2008.
If you use ranges, you should add an explanatory note in a README file.
The function `copyright-fix-years' respects this variable."
- :group 'copyright
:type 'boolean
:version "24.1")
@@ -96,7 +90,6 @@ The function `copyright-fix-years' respects this variable."
(defcustom copyright-query 'function
"If non-nil, ask user before changing copyright.
When this is `function', only ask when called non-interactively."
- :group 'copyright
:type '(choice (const :tag "Do not ask")
(const :tag "Ask unless interactive" function)
(other :tag "Ask" t)))
@@ -263,7 +256,7 @@ interactively."
(match-string-no-properties 1)
copyright-current-gpl-version)))))
(replace-match copyright-current-gpl-version t t nil 1))))
- (set (make-local-variable 'copyright-update) nil)))
+ (setq-local copyright-update nil)))
;; If a write-file-hook returns non-nil, the file is presumed to be written.
nil))
diff --git a/lisp/emacs-lisp/debug.el b/lisp/emacs-lisp/debug.el
index 0e4135b253e..11ef836563d 100644
--- a/lisp/emacs-lisp/debug.el
+++ b/lisp/emacs-lisp/debug.el
@@ -29,7 +29,6 @@
(require 'cl-lib)
(require 'backtrace)
-(require 'button)
(defgroup debugger nil
"Debuggers and related commands for Emacs."
diff --git a/lisp/emacs-lisp/easy-mmode.el b/lisp/emacs-lisp/easy-mmode.el
index fdc1233540e..261f2508af7 100644
--- a/lisp/emacs-lisp/easy-mmode.el
+++ b/lisp/emacs-lisp/easy-mmode.el
@@ -84,10 +84,13 @@ replacing its case-insensitive matches with the literal string in LIGHTER."
(defconst easy-mmode--arg-docstring
"
-If called interactively, enable %s if ARG is positive, and
-disable it if ARG is zero or negative. If called from Lisp,
-also enable the mode if ARG is omitted or nil, and toggle it
-if ARG is `toggle'; disable the mode otherwise.
+If called interactively, toggle `%s'. If the prefix argument is
+positive, enable the mode, and if it is zero or negative, disable
+the mode.
+
+If called from Lisp, toggle the mode if ARG is `toggle'.
+Enable the mode if ARG is nil, omitted, or is a positive number.
+Disable the mode if ARG is a negative number.
The mode's hook is called both when the mode is enabled and when
it is disabled.")
@@ -137,6 +140,10 @@ appear in DOC, a paragraph is added to DOC explaining
usage of the mode argument.
Optional INIT-VALUE is the initial value of the mode's variable.
+ Note that the minor mode function won't be called by setting
+ this option, so the value *reflects* the minor mode's natural
+ initial state, rather than *setting* it.
+ In the vast majority of cases it should be nil.
Optional LIGHTER is displayed in the mode line when the mode is on.
Optional KEYMAP is the default keymap bound to the mode keymap.
If non-nil, it should be a variable name (whose value is a keymap),
@@ -297,13 +304,18 @@ or call the function `%s'."))))
,(easy-mmode--mode-docstring doc pretty-name keymap-sym)
;; Use `toggle' rather than (if ,mode 0 1) so that using
;; repeat-command still does the toggling correctly.
- (interactive (list (or current-prefix-arg 'toggle)))
+ (interactive (list (if current-prefix-arg
+ (prefix-numeric-value current-prefix-arg)
+ 'toggle)))
(let ((,last-message (current-message)))
(,@setter
- (if (eq arg 'toggle)
- (not ,getter)
- ;; A nil argument also means ON now.
- (> (prefix-numeric-value arg) 0)))
+ (cond ((eq arg 'toggle)
+ (not ,getter))
+ ((and (numberp arg)
+ (< arg 1))
+ nil)
+ (t
+ t)))
,@body
;; The on/off hooks are here for backward compatibility only.
(run-hooks ',hook (if ,getter ',hook-on ',hook-off))
@@ -371,18 +383,21 @@ No problems result if this variable is not bound.
(defmacro define-globalized-minor-mode (global-mode mode turn-on &rest body)
"Make a global mode GLOBAL-MODE corresponding to buffer-local minor MODE.
TURN-ON is a function that will be called with no args in every buffer
- and that should try to turn MODE on if applicable for that buffer.
-Each of KEY VALUE is a pair of CL-style keyword arguments. As
- the minor mode defined by this function is always global, any
- :global keyword is ignored. Other keywords have the same
- meaning as in `define-minor-mode', which see. In particular,
- :group specifies the custom group. The most useful keywords
- are those that are passed on to the `defcustom'. It normally
- makes no sense to pass the :lighter or :keymap keywords to
- `define-globalized-minor-mode', since these are usually passed
- to the buffer-local version of the minor mode.
+and that should try to turn MODE on if applicable for that buffer.
+
+Each of KEY VALUE is a pair of CL-style keyword arguments. :predicate
+specifies which major modes the globalized minor mode should be switched on
+in. As the minor mode defined by this function is always global, any
+:global keyword is ignored. Other keywords have the same meaning as in
+`define-minor-mode', which see. In particular, :group specifies the custom
+group. The most useful keywords are those that are passed on to the
+`defcustom'. It normally makes no sense to pass the :lighter or :keymap
+keywords to `define-globalized-minor-mode', since these are usually passed
+to the buffer-local version of the minor mode.
+
BODY contains code to execute each time the mode is enabled or disabled.
- It is executed after toggling the mode, and before running GLOBAL-MODE-hook.
+It is executed after toggling the mode, and before running
+GLOBAL-MODE-hook.
If MODE's set-up depends on the major mode in effect when it was
enabled, then disabling and reenabling MODE should make MODE work
@@ -411,7 +426,11 @@ on if the hook has explicitly disabled it.
(minor-MODE-hook (intern (concat mode-name "-hook")))
(MODE-set-explicitly (intern (concat mode-name "-set-explicitly")))
(MODE-major-mode (intern (concat (symbol-name mode) "-major-mode")))
- keyw)
+ (MODE-predicate (intern (concat (replace-regexp-in-string
+ "-mode\\'" "" global-mode-name)
+ "-modes")))
+ (turn-on-function `#',turn-on)
+ keyw predicate)
;; Check keys.
(while (keywordp (setq keyw (car body)))
@@ -419,6 +438,13 @@ on if the hook has explicitly disabled it.
(pcase keyw
(:group (setq group (nconc group (list :group (pop body)))))
(:global (pop body))
+ (:predicate
+ (setq predicate (list (pop body)))
+ (setq turn-on-function
+ `(lambda ()
+ (require 'easy-mmode)
+ (when (easy-mmode--globalized-predicate-p ,(car predicate))
+ (funcall ,turn-on-function)))))
(_ (push keyw extra-keywords) (push (pop body) extra-keywords))))
`(progn
@@ -438,10 +464,17 @@ ARG is omitted or nil.
%s is enabled in all buffers where
`%s' would do it.
-See `%s' for more information on %s."
+
+See `%s' for more information on
+%s.%s"
pretty-name pretty-global-name
- pretty-name turn-on mode pretty-name)
- :global t ,@group ,@(nreverse extra-keywords)
+ pretty-name turn-on mode pretty-name
+ (if predicate
+ (format "\n\n`%s' is used to control which modes
+this minor mode is used in."
+ MODE-predicate)
+ ""))
+ :global t ,@group ,@(nreverse extra-keywords)
;; Setup hook to handle future mode changes and new buffers.
(if ,global-mode
@@ -457,9 +490,28 @@ See `%s' for more information on %s."
;; Go through existing buffers.
(dolist (buf (buffer-list))
(with-current-buffer buf
- (if ,global-mode (funcall #',turn-on) (when ,mode (,mode -1)))))
+ (if ,global-mode (funcall ,turn-on-function)
+ (when ,mode (,mode -1)))))
,@body)
+ ,(when predicate
+ `(defcustom ,MODE-predicate ,(car predicate)
+ ,(format "Which major modes `%s' is switched on in.
+This variable can be either t (all major modes), nil (no major modes),
+or a list of modes and (not modes) to switch use this minor mode or
+not. For instance
+
+ (c-mode (not message-mode mail-mode) text-mode)
+
+means \"use this mode in all modes derived from `c-mode', don't use in
+modes derived from `message-mode' or `mail-mode', but do use in other
+modes derived from `text-mode'\". An element with value t means \"use\"
+and nil means \"don't use\". There's an implicit nil at the end of the
+list."
+ mode)
+ :type '(repeat sexp)
+ :group ,group))
+
;; Autoloading define-globalized-minor-mode autoloads everything
;; up-to-here.
:autoload-end
@@ -493,8 +545,8 @@ See `%s' for more information on %s."
(if ,mode
(progn
(,mode -1)
- (funcall #',turn-on))
- (funcall #',turn-on))))
+ (funcall ,turn-on-function))
+ (funcall ,turn-on-function))))
(setq ,MODE-major-mode major-mode))))))
(put ',MODE-enable-in-buffers 'definition-name ',global-mode)
@@ -509,6 +561,33 @@ See `%s' for more information on %s."
(add-hook 'post-command-hook ',MODE-check-buffers))
(put ',MODE-cmhh 'definition-name ',global-mode))))
+(defun easy-mmode--globalized-predicate-p (predicate)
+ (cond
+ ((eq predicate t)
+ t)
+ ((eq predicate nil)
+ nil)
+ ((listp predicate)
+ ;; Legacy support for (not a b c).
+ (when (eq (car predicate) 'not)
+ (setq predicate (nconc (mapcar (lambda (e) (list 'not e))
+ (cdr predicate))
+ (list t))))
+ (catch 'found
+ (dolist (elem predicate)
+ (cond
+ ((eq elem t)
+ (throw 'found t))
+ ((eq elem nil)
+ (throw 'found nil))
+ ((and (consp elem)
+ (eq (car elem) 'not))
+ (when (apply #'derived-mode-p (cdr elem))
+ (throw 'found nil)))
+ ((symbolp elem)
+ (when (derived-mode-p elem)
+ (throw 'found t)))))))))
+
;;;
;;; easy-mmode-defmap
;;;
diff --git a/lisp/emacs-lisp/easymenu.el b/lisp/emacs-lisp/easymenu.el
index 73dabef3fa5..7a24af7963f 100644
--- a/lisp/emacs-lisp/easymenu.el
+++ b/lisp/emacs-lisp/easymenu.el
@@ -488,17 +488,14 @@ To implement dynamic menus, either call this from
`menu-bar-update-hook' or use a menu filter."
(easy-menu-add-item map path (easy-menu-create-menu name items) before))
-;; XEmacs needs the following two functions to add and remove menus.
-;; In Emacs this is done automatically when switching keymaps, so
-;; here easy-menu-remove and easy-menu-add are a noops.
-(defalias 'easy-menu-remove 'ignore
+(define-obsolete-function-alias 'easy-menu-remove #'ignore "28.1"
"Remove MENU from the current menu bar.
Contrary to XEmacs, this is a nop on Emacs since menus are automatically
\(de)activated when the corresponding keymap is (de)activated.
\(fn MENU)")
-(defalias 'easy-menu-add #'ignore
+(define-obsolete-function-alias 'easy-menu-add #'ignore "28.1"
"Add the menu to the menubar.
On Emacs this is a nop, because menus are already automatically
activated when the corresponding keymap is activated. On XEmacs
@@ -514,6 +511,7 @@ completely and menu filter functions can be expected to work.
If BEFORE is non-nil, add before the item named BEFORE.
If IN-MENU is non-nil, follow MENU-PATH in IN-MENU.
This is a compatibility function; use `easy-menu-add-item'."
+ (declare (obsolete easy-menu-add-item "28.1"))
(easy-menu-add-item (or in-menu (current-global-map))
(cons "menu-bar" menu-path)
submenu before))
diff --git a/lisp/emacs-lisp/edebug.el b/lisp/emacs-lisp/edebug.el
index 7ff6d68c3ec..f242e922bde 100644
--- a/lisp/emacs-lisp/edebug.el
+++ b/lisp/emacs-lisp/edebug.el
@@ -309,9 +309,8 @@ A lambda list keyword is a symbol that starts with `&'."
(defun edebug-sort-alist (alist function)
;; Return the ALIST sorted with comparison function FUNCTION.
;; This uses 'sort so the sorting is destructive.
- (sort alist (function
- (lambda (e1 e2)
- (funcall function (car e1) (car e2))))))
+ (sort alist (lambda (e1 e2)
+ (funcall function (car e1) (car e2)))))
;; Not used.
'(defmacro edebug-save-restriction (&rest body)
@@ -407,14 +406,13 @@ Return the result of the last expression in BODY."
(if (listp window-info)
(mapcar (lambda (one-window-info)
(if one-window-info
- (apply (function
- (lambda (window buffer point start hscroll)
- (if (edebug-window-live-p window)
- (progn
- (set-window-buffer window buffer)
- (set-window-point window point)
- (set-window-start window start)
- (set-window-hscroll window hscroll)))))
+ (apply (lambda (window buffer point start hscroll)
+ (if (edebug-window-live-p window)
+ (progn
+ (set-window-buffer window buffer)
+ (set-window-point window point)
+ (set-window-start window start)
+ (set-window-hscroll window hscroll))))
one-window-info)))
window-info)
(set-window-configuration window-info)))
@@ -2665,9 +2663,6 @@ See `edebug-behavior-alist' for implementations.")
(defvar edebug-previous-result nil) ;; Last result returned.
-;; Emacs 19 adds an arg to mark and mark-marker.
-(defalias 'edebug-mark-marker 'mark-marker)
-
(defun edebug--display (value offset-index arg-mode)
;; edebug--display-1 is too big, we should split it. This function
;; here was just introduced to avoid making edebug--display-1
@@ -2895,8 +2890,8 @@ See `edebug-behavior-alist' for implementations.")
;; But don't restore point if edebug-buffer is current buffer.
(if (not (eq edebug-buffer edebug-outside-buffer))
(goto-char edebug-outside-point))
- (if (marker-buffer (edebug-mark-marker))
- (set-marker (edebug-mark-marker) edebug-outside-mark))
+ (if (marker-buffer (mark-marker))
+ (set-marker (mark-marker) edebug-outside-mark))
)) ; unwind-protect
;; None of the following is done if quit or signal occurs.
@@ -3153,8 +3148,8 @@ before returning. The default is one second."
(goto-char edebug-outside-point)
(message "Current buffer: %s Point: %s Mark: %s"
(current-buffer) (point)
- (if (marker-buffer (edebug-mark-marker))
- (marker-position (edebug-mark-marker)) "<not set>"))
+ (if (marker-buffer (mark-marker))
+ (marker-position (mark-marker)) "<not set>"))
(sit-for arg)
(edebug-pop-to-buffer edebug-buffer (car edebug-window-data)))))
@@ -3725,8 +3720,8 @@ Return the result of the last expression."
;; for us.
(with-current-buffer edebug-outside-buffer ; of edebug-buffer
(goto-char edebug-outside-point)
- (if (marker-buffer (edebug-mark-marker))
- (set-marker (edebug-mark-marker) edebug-outside-mark))
+ (if (marker-buffer (mark-marker))
+ (set-marker (mark-marker) edebug-outside-mark))
,@body)
;; Back to edebug-buffer. Restore rest of inside context.
@@ -4021,7 +4016,6 @@ Options:
`edebug-print-circle'
`edebug-on-error'
`edebug-on-quit'
-`edebug-on-signal'
`edebug-unwrap-results'
`edebug-global-break-condition'"
:lighter " *Debugging*"
@@ -4461,7 +4455,6 @@ reinstrument it."
(defun edebug-temp-display-freq-count ()
"Temporarily display the frequency count data for the current definition.
It is removed when you hit any char."
- ;; This seems not to work with Emacs 18.59. It undoes too far.
(interactive)
(let ((inhibit-read-only t))
(undo-boundary)
@@ -4668,5 +4661,7 @@ instrumentation for, defaulting to all functions."
(message "Removed edebug instrumentation from %s"
(mapconcat #'symbol-name functions ", ")))
+(define-obsolete-function-alias 'edebug-mark-marker #'mark-marker "28.1")
+
(provide 'edebug)
;;; edebug.el ends here
diff --git a/lisp/emacs-lisp/eieio-custom.el b/lisp/emacs-lisp/eieio-custom.el
index e26dc9e9a9c..c1378cbeb79 100644
--- a/lisp/emacs-lisp/eieio-custom.el
+++ b/lisp/emacs-lisp/eieio-custom.el
@@ -33,7 +33,6 @@
(require 'eieio)
(require 'widget)
(require 'wid-edit)
-(require 'custom)
;;; Compatibility
@@ -366,8 +365,7 @@ These groups are specified with the `:group' slot flag."
(widget-insert "\n\n")
(widget-insert "Edit object " (eieio-object-name obj) "\n\n")
;; Create the widget editing the object.
- (make-local-variable 'eieio-wo)
- (setq eieio-wo (eieio-custom-widget-insert obj :eieio-group g))
+ (setq-local eieio-wo (eieio-custom-widget-insert obj :eieio-group g))
;;Now generate the apply buttons
(widget-insert "\n")
(eieio-custom-object-apply-reset obj)
@@ -376,10 +374,8 @@ These groups are specified with the `:group' slot flag."
;;(widget-minor-mode)
(goto-char (point-min))
(widget-forward 3)
- (make-local-variable 'eieio-co)
- (setq eieio-co obj)
- (make-local-variable 'eieio-cog)
- (setq eieio-cog g)))
+ (setq-local eieio-co obj)
+ (setq-local eieio-cog g)))
(cl-defmethod eieio-custom-object-apply-reset ((_obj eieio-default-superclass))
"Insert an Apply and Reset button into the object editor.
diff --git a/lisp/emacs-lisp/eldoc.el b/lisp/emacs-lisp/eldoc.el
index 9e38e5908ed..c9d5521e502 100644
--- a/lisp/emacs-lisp/eldoc.el
+++ b/lisp/emacs-lisp/eldoc.el
@@ -5,7 +5,7 @@
;; Author: Noah Friedman <friedman@splode.com>
;; Keywords: extensions
;; Created: 1995-10-06
-;; Version: 1.10.0
+;; Version: 1.11.0
;; Package-Requires: ((emacs "26.3"))
;; This is a GNU ELPA :core package. Avoid functionality that is not
@@ -67,7 +67,7 @@ If this variable is set to 0, no idle time is required."
Changing the value requires toggling `eldoc-mode'."
:type 'boolean)
-(defcustom eldoc-display-truncation-message t
+(defcustom eldoc-echo-area-display-truncation-message t
"If non-nil, provide verbose help when a message has been truncated.
If nil, truncated messages will just have \"...\" appended."
:type 'boolean
@@ -96,19 +96,22 @@ Note that this variable has no effect, unless
If value is t, never attempt to truncate messages, even if the
echo area must be resized to fit.
-If value is a number (integer or floating point), it has the
-semantics of `max-mini-window-height', constraining the resizing
-for ElDoc purposes only.
+If the value is a positive number, it is used to calculate a
+number of logical lines of documentation that ElDoc is allowed to
+put in the echo area. If a positive integer, the number is used
+directly, while a float specifies the number of lines as a
+proporting of the echo area frame's height.
-Any resizing respects `max-mini-window-height'.
-
-If value is any non-nil symbol other than t, the part of the doc
-string that represents the symbol's name may be truncated if it
-will enable the rest of the doc string to fit on a single line,
-without resizing the echo area.
+If value is the symbol `truncate-sym-name-if-fit' t, the part of
+the doc string that represents a symbol's name may be truncated
+if it will enable the rest of the doc string to fit on a single
+line, without resizing the echo area.
If value is nil, a doc string is always truncated to fit in a
-single line of display in the echo area."
+single line of display in the echo area.
+
+Any resizing of the echo area additionally respects
+`max-mini-window-height'."
:type '(radio (const :tag "Always" t)
(float :tag "Fraction of frame height" 0.25)
(integer :tag "Number of lines" 5)
@@ -117,12 +120,13 @@ single line of display in the echo area."
symbol names if it will\ enable argument list to fit on one
line" truncate-sym-name-if-fit)))
-(defcustom eldoc-prefer-doc-buffer nil
+(defcustom eldoc-echo-area-prefer-doc-buffer nil
"Prefer ElDoc's documentation buffer if it is showing in some frame.
-If this variable's value is t and a piece of documentation needs
-to be truncated to fit in the echo area, do so if ElDoc's
-documentation buffer is not already showing, since the buffer
-always holds the full documentation."
+If this variable's value is t, ElDoc will skip showing
+documentation in the echo area if the dedicated documentation
+buffer (given by `eldoc-doc-buffer') is being displayed in some
+window. If the value is the symbol `maybe', then the echo area
+is only skipped if the documentation doesn't fit there."
:type 'boolean)
(defface eldoc-highlight-function-argument
@@ -237,8 +241,9 @@ expression point is on." :lighter eldoc-minor-mode-string
;; `emacs-lisp-mode' itself?
(cond ((<= emacs-major-version 27)
(declare-function elisp-eldoc-documentation-function "elisp-mode")
- (add-function :before-until (local 'eldoc-documentation-function)
- #'elisp-eldoc-documentation-function))
+ (with-no-warnings
+ (add-function :before-until (local 'eldoc-documentation-function)
+ #'elisp-eldoc-documentation-function)))
(t (add-hook 'eldoc-documentation-functions
#'elisp-eldoc-var-docstring nil t)
(add-hook 'eldoc-documentation-functions
@@ -350,40 +355,26 @@ Also store it in `eldoc-last-message' and return that value."
;; for us, but do note that the last-message will be gone.
(setq eldoc-last-message nil))))
-(defvar-local eldoc--last-request-state nil
+;; The point of `eldoc--request-state' is not to over-request, which
+;; can happen if the idle timer is restarted on execution of command
+;; which is guaranteed not to change the conditions that warrant a new
+;; request for documentation.
+(defvar eldoc--last-request-state nil
"Tuple containing information about last ElDoc request.")
(defun eldoc--request-state ()
"Compute information to store in `eldoc--last-request-state'."
(list (current-buffer) (buffer-modified-tick) (point)))
(defun eldoc-display-message-p ()
- (eldoc--request-docs-p (eldoc--request-state)))
+ "Tell if ElDoc can use the echo area."
+ (and (eldoc-display-message-no-interference-p)
+ (not this-command)
+ (eldoc--message-command-p last-command)))
+
(make-obsolete 'eldoc-display-message-p
"Use `eldoc-documentation-functions' instead."
"eldoc-1.6.0")
-(defun eldoc--request-docs-p (request-state)
- "Return non-nil when it is appropriate to request docs.
-REQUEST-STATE is a candidate for `eldoc--last-request-state'"
- (and
- ;; FIXME: The original idea behind this function is to protect the
- ;; Echo area from ElDoc interference, but since that is only one of
- ;; the possible outlets of ElDoc, this must soon be reworked.
- (eldoc-display-message-no-interference-p)
- (not (and eldoc--doc-buffer
- (get-buffer-window eldoc--doc-buffer)
- (equal request-state
- (with-current-buffer
- eldoc--doc-buffer
- eldoc--last-request-state))))
- ;; If this-command is non-nil while running via an idle
- ;; timer, we're still in the middle of executing a command,
- ;; e.g. a query-replace where it would be annoying to
- ;; overwrite the echo area.
- (not this-command)
- (eldoc--message-command-p last-command)))
-
-
;; Check various conditions about the current environment that might make
;; it undesirable to print eldoc messages right this instant.
(defun eldoc-display-message-no-interference-p ()
@@ -416,43 +407,158 @@ about the context around point.
To call the CALLBACK function, the hook function must pass it an
obligatory argument DOCSTRING, a string containing the
-documentation, followed by an optional list of keyword-value
-pairs of the form (:KEY VALUE :KEY2 VALUE2...). KEY can be:
-
-* `:thing', VALUE is a short string or symbol designating what is
- being reported on. The documentation display engine can elect
- to remove this information depending on space constraints;
-
-* `:face', VALUE is a symbol designating a face to use when
- displaying `:thing''s value.
-
-Major modes should modify this hook locally, for example:
+documentation, followed by an optional list of arbitrary
+keyword-value pairs of the form (:KEY VALUE :KEY2 VALUE2...).
+The information contained in these pairs is understood by members
+of `eldoc-display-functions', allowing the
+documentation-producing backend to cooperate with specific
+documentation-displaying frontends. For example, KEY can be:
+
+* `:thing', VALUE being a short string or symbol designating what
+ is being reported on. It can, for example be the name of the
+ function whose signature is being documented, or the name of
+ the variable whose docstring is being documented.
+ `eldoc-display-in-echo-area', a member of
+ `eldoc-display-functions', sometimes omits this information
+ depending on space constraints;
+
+* `:face', VALUE being a symbol designating a face which both
+ `eldoc-display-in-echo-area' and `eldoc-display-in-buffer' will
+ use when displaying `:thing''s value.
+
+Finally, major modes should modify this hook locally, for
+example:
(add-hook \\='eldoc-documentation-functions #\\='foo-mode-eldoc nil t)
so that the global value (i.e. the default value of the hook) is
taken into account if the major mode specific function does not
return any documentation.")
+(defvar eldoc-display-functions
+ '(eldoc-display-in-echo-area eldoc-display-in-buffer)
+ "Hook of functions tasked with displaying ElDoc results.
+Each function is passed two arguments: DOCS and INTERACTIVE. DOCS
+is a list (DOC ...) where DOC looks like (STRING :KEY VALUE :KEY2
+VALUE2 ...). STRING is a string containing the documentation's
+text and the remainder of DOC is an optional list of
+keyword-value pairs denoting additional properties of that
+documentation. For commonly recognized properties, see
+`eldoc-documentation-functions'.
+
+INTERACTIVE says if the request to display doc strings came
+directly from the user or from ElDoc's automatic mechanisms'.")
+
(defvar eldoc--doc-buffer nil "Buffer displaying latest ElDoc-produced docs.")
-(defun eldoc-doc-buffer (&optional interactive)
- "Get latest *eldoc* help buffer. Interactively, display it."
- (interactive (list t))
- (prog1
- (if (and eldoc--doc-buffer (buffer-live-p eldoc--doc-buffer))
- eldoc--doc-buffer
- (setq eldoc--doc-buffer (get-buffer-create "*eldoc*")))
- (when interactive (display-buffer eldoc--doc-buffer))))
-
-
-(defun eldoc--handle-docs (docs)
- "Display multiple DOCS in echo area.
-DOCS is a list of (STRING PLIST...). It is already sorted.
-Honor most of `eldoc-echo-area-use-multiline-p'."
- ;; If there's nothing to report clear the echo area, but don't erase
- ;; the last *eldoc* buffer.
- (if (null docs) (eldoc--message nil)
+(defvar eldoc--doc-buffer-docs nil "Documentation items in `eldoc--doc-buffer'.")
+
+(defun eldoc-doc-buffer ()
+ "Display ElDoc documentation buffer.
+
+This holds the results of the last documentation request."
+ (interactive)
+ (unless (buffer-live-p eldoc--doc-buffer)
+ (user-error (format
+ "ElDoc buffer doesn't exist, maybe `%s' to produce one."
+ (substitute-command-keys "\\[eldoc]"))))
+ (with-current-buffer eldoc--doc-buffer
+ (rename-buffer (replace-regexp-in-string "^ *" ""
+ (buffer-name)))
+ (display-buffer (current-buffer))))
+
+(defun eldoc--format-doc-buffer (docs)
+ "Ensure DOCS are displayed in an *eldoc* buffer."
+ (with-current-buffer (if (buffer-live-p eldoc--doc-buffer)
+ eldoc--doc-buffer
+ (setq eldoc--doc-buffer
+ (get-buffer-create " *eldoc*")))
+ (unless (eq docs eldoc--doc-buffer-docs)
+ (setq-local eldoc--doc-buffer-docs docs)
+ (let ((inhibit-read-only t)
+ (things-reported-on))
+ (erase-buffer) (setq buffer-read-only t)
+ (local-set-key "q" 'quit-window)
+ (cl-loop for (docs . rest) on docs
+ for (this-doc . plist) = docs
+ for thing = (plist-get plist :thing)
+ when thing do
+ (cl-pushnew thing things-reported-on)
+ (setq this-doc
+ (concat
+ (propertize (format "%s" thing)
+ 'face (plist-get plist :face))
+ ": "
+ this-doc))
+ do (insert this-doc)
+ when rest do (insert "\n")
+ finally (goto-char (point-min)))
+ ;; Rename the buffer, taking into account whether it was
+ ;; hidden or not
+ (rename-buffer (format "%s*eldoc%s*"
+ (if (string-match "^ " (buffer-name)) " " "")
+ (if things-reported-on
+ (format " for %s"
+ (mapconcat
+ (lambda (s) (format "%s" s))
+ things-reported-on
+ ", "))
+ ""))))))
+ eldoc--doc-buffer)
+
+(defun eldoc--echo-area-substring (available)
+ "Given AVAILABLE lines, get buffer substring to display in echo area.
+Helper for `eldoc-display-in-echo-area'."
+ (let ((start (prog1 (progn
+ (goto-char (point-min))
+ (skip-chars-forward " \t\n")
+ (point))
+ (goto-char (line-end-position available))
+ (skip-chars-backward " \t\n")))
+ (truncated (save-excursion
+ (skip-chars-forward " \t\n")
+ (not (eobp)))))
+ (cond ((eldoc--echo-area-prefer-doc-buffer-p truncated)
+ nil)
+ ((and truncated
+ (> available 1)
+ eldoc-echo-area-display-truncation-message)
+ (goto-char (line-end-position 0))
+ (concat (buffer-substring start (point))
+ (format
+ "\n(Documentation truncated. Use `%s' to see rest)"
+ (substitute-command-keys "\\[eldoc-doc-buffer]"))))
+ (t
+ (buffer-substring start (point))))))
+
+(defun eldoc--echo-area-prefer-doc-buffer-p (truncatedp)
+ "Tell if display in the echo area should be skipped.
+Helper for `eldoc-display-in-echo-area'. If TRUNCATEDP the
+documentation to potentially appear in the echo are is truncated."
+ (and (or (eq eldoc-echo-area-prefer-doc-buffer t)
+ (and truncatedp
+ (eq eldoc-echo-area-prefer-doc-buffer
+ 'maybe)))
+ (get-buffer-window eldoc--doc-buffer)))
+
+(defun eldoc-display-in-echo-area (docs _interactive)
+ "Display DOCS in echo area.
+Honor `eldoc-echo-area-use-multiline-p' and
+`eldoc-echo-area-prefer-doc-buffer'."
+ (cond
+ (;; Check if he wave permission to mess with echo area at all. For
+ ;; example, if this-command is non-nil while running via an idle
+ ;; timer, we're still in the middle of executing a command, e.g. a
+ ;; query-replace where it would be annoying to overwrite the echo
+ ;; area.
+ (or
+ (not (eldoc-display-message-no-interference-p))
+ this-command
+ (not (eldoc--message-command-p last-command))))
+ (;; If we do but nothing to report, clear the echo area.
+ (null docs)
+ (eldoc--message nil))
+ (t
+ ;; Otherwise, establish some parameters.
(let*
- ;; Otherwise, establish some parameters.
((width (1- (window-width (minibuffer-window))))
(val (if (and (symbolp eldoc-echo-area-use-multiline-p)
eldoc-echo-area-use-multiline-p)
@@ -461,44 +567,13 @@ Honor most of `eldoc-echo-area-use-multiline-p'."
(available (cl-typecase val
(float (truncate (* (frame-height) val)))
(integer val)
- (t 1)))
- (things-reported-on)
- (request eldoc--last-request-state)
+ (t 'just-one-line)))
single-doc single-doc-sym)
- ;; Then, compose the contents of the `*eldoc*' buffer.
- (with-current-buffer (eldoc-doc-buffer)
- ;; Set doc-buffer's `eldoc--last-request-state', too
- (setq eldoc--last-request-state request)
- (let ((inhibit-read-only t))
- (erase-buffer) (setq buffer-read-only t)
- (local-set-key "q" 'quit-window)
- (cl-loop for (docs . rest) on docs
- for (this-doc . plist) = docs
- for thing = (plist-get plist :thing)
- when thing do
- (cl-pushnew thing things-reported-on)
- (setq this-doc
- (concat
- (propertize (format "%s" thing)
- 'face (plist-get plist :face))
- ": "
- this-doc))
- do (insert this-doc)
- when rest do (insert "\n")))
- ;; Rename the buffer.
- (when things-reported-on
- (rename-buffer (format "*eldoc for %s*"
- (mapconcat (lambda (s) (format "%s" s))
- things-reported-on
- ", ")))))
- ;; Finally, output to the echo area. I'm pretty sure nicer
- ;; strategies can be used here, probably by splitting this
- ;; function into some `eldoc-display-functions' special hook.
(let ((echo-area-message
(cond
- (;; We handle the `truncate-sym-name-if-fit' special
- ;; case first, by checking if for a lot of special
- ;; conditions.
+ (;; To output to the echo area, we handle the
+ ;; `truncate-sym-name-if-fit' special case first, by
+ ;; checking for a lot of special conditions.
(and
(eq 'truncate-sym-name-if-fit eldoc-echo-area-use-multiline-p)
(null (cdr docs))
@@ -509,45 +584,33 @@ Honor most of `eldoc-echo-area-use-multiline-p'."
(not (string-match "\n" single-doc))
(> (+ (length single-doc) (length single-doc-sym) 2) width))
single-doc)
- ((> available 1)
- ;; The message takes one extra line, so if we don't
- ;; display that, we have one extra line to use.
- (unless eldoc-display-truncation-message
- (setq available (1+ available)))
- (with-current-buffer (eldoc-doc-buffer)
- (cl-loop
- initially
- (goto-char (point-min))
- (goto-char (line-end-position (1+ available)))
- for truncated = nil then t
- for needed
- = (let ((truncate-lines message-truncate-lines))
- (count-screen-lines (point-min) (point) t
- (minibuffer-window)))
- while (> needed (if truncated (1- available) available))
- do (goto-char (line-end-position (if truncated 0 -1)))
- (while (and (not (bobp)) (bolp)) (goto-char (line-end-position 0)))
- finally
- (unless (and truncated
- eldoc-prefer-doc-buffer
- (get-buffer-window eldoc--doc-buffer))
- (cl-return
- (concat
- (buffer-substring (point-min) (point))
- (and
- truncated
- (if eldoc-display-truncation-message
- (format
- "\n(Documentation truncated. Use `%s' to see rest)"
- (substitute-command-keys "\\[eldoc-doc-buffer]"))
- "..."))))))))
- ((= available 1)
- ;; Truncate "brutally." ; FIXME: use `eldoc-prefer-doc-buffer' too?
- (with-current-buffer (eldoc-doc-buffer)
- (truncate-string-to-width
- (buffer-substring (goto-char (point-min)) (line-end-position 1)) width))))))
+ ((and (numberp available)
+ (cl-plusp available))
+ ;; Else, given a positive number of logical lines, we
+ ;; format the *eldoc* buffer, using as most of its
+ ;; contents as we know will fit.
+ (with-current-buffer (eldoc--format-doc-buffer docs)
+ (save-excursion
+ (eldoc--echo-area-substring available))))
+ (t ;; this is the "truncate brutally" situation
+ (let ((string
+ (with-current-buffer (eldoc--format-doc-buffer docs)
+ (buffer-substring (goto-char (point-min))
+ (line-end-position 1)))))
+ (if (> (length string) width) ; truncation to happen
+ (unless (eldoc--echo-area-prefer-doc-buffer-p t)
+ (truncate-string-to-width string width))
+ (unless (eldoc--echo-area-prefer-doc-buffer-p nil)
+ string)))))))
(when echo-area-message
- (eldoc--message echo-area-message))))))
+ (eldoc--message echo-area-message)))))))
+
+(defun eldoc-display-in-buffer (docs interactive)
+ "Display DOCS in a dedicated buffer.
+If INTERACTIVE is t, also display the buffer."
+ (eldoc--format-doc-buffer docs)
+ (when interactive
+ (eldoc-doc-buffer)))
(defun eldoc-documentation-default ()
"Show first doc string for item at point.
@@ -709,19 +772,29 @@ have the following values:
strings so far, as soon as possible."
(funcall eldoc--make-callback method))
-(defun eldoc--invoke-strategy ()
+(defun eldoc--invoke-strategy (interactive)
"Invoke `eldoc-documentation-strategy' function.
+If INTERACTIVE is non-nil, the request came directly from a user
+command, otherwise it came from ElDoc's idle
+timer, `eldoc-timer'.
+
That function's job is to run the `eldoc-documentation-functions'
special hook, using the `run-hook' family of functions. ElDoc's
built-in strategy functions play along with the
-`eldoc--make-callback' protocol, using it to produce callback to
-feed to the functgions of `eldoc-documentation-functions'.
-
-Other third-party strategy functions do not use
-`eldoc--make-callback'. They must find some alternate way to
-produce callbacks to feed to `eldoc-documentation-function' and
-should endeavour to display the docstrings eventually produced."
+`eldoc--make-callback' protocol, using it to produce a callback
+argument to feed the functions that the user places in
+`eldoc-documentation-functions'. Whenever the strategy
+determines it has information to display to the user, this
+function passes responsibility to the functions in
+`eldoc-display-functions'.
+
+Other third-party values of `eldoc-documentation-strategy' should
+not use `eldoc--make-callback'. They must find some alternate
+way to produce callbacks to feed to
+`eldoc-documentation-function' and should endeavour to display
+the docstrings eventually produced, using
+`eldoc-display-functions'."
(let* (;; How many callbacks have been created by the strategy
;; function and passed to elements of
;; `eldoc-documentation-functions'.
@@ -739,11 +812,12 @@ should endeavour to display the docstrings eventually produced."
(push (cons pos (cons string plist)) docs-registered)))
(display-doc
()
- (eldoc--handle-docs
- (mapcar #'cdr
- (setq docs-registered
- (sort docs-registered
- (lambda (a b) (< (car a) (car b))))))))
+ (run-hook-with-args
+ 'eldoc-display-functions (mapcar #'cdr
+ (setq docs-registered
+ (sort docs-registered
+ (lambda (a b) (< (car a) (car b))))))
+ interactive))
(make-callback
(method)
(let ((pos (prog1 howmany (cl-incf howmany))))
@@ -786,22 +860,19 @@ should endeavour to display the docstrings eventually produced."
(defun eldoc-print-current-symbol-info (&optional interactive)
"Document thing at point."
(interactive '(t))
- (let ((token (eldoc--request-state)))
+ (let (token)
(cond (interactive
- (eldoc--invoke-strategy))
- ((not (eldoc--request-docs-p token))
- ;; Erase the last message if we won't display a new one.
- (when eldoc-last-message
- (eldoc--message nil)))
- (t
+ (eldoc--invoke-strategy t))
+ ((not (equal (setq token (eldoc--request-state))
+ eldoc--last-request-state))
(let ((non-essential t))
(setq eldoc--last-request-state token)
- ;; Only keep looking for the info as long as the user hasn't
- ;; requested our attention. This also locally disables
- ;; inhibit-quit.
- (while-no-input
- (eldoc--invoke-strategy)))))))
+ (eldoc--invoke-strategy nil))))))
+
+;; This section only affects ElDoc output to the echo area, as in
+;; `eldoc-display-in-echo-area'.
+;;
;; When point is in a sexp, the function args are not reprinted in the echo
;; area after every possible interactive command because some of them print
;; their own messages in the echo area; the eldoc functions would instantly
@@ -833,7 +904,6 @@ should endeavour to display the docstrings eventually produced."
(apply #'eldoc-remove-command
(all-completions name eldoc-message-commands))))
-
;; Prime the command list.
(eldoc-add-command-completions
"back-to-indentation"
diff --git a/lisp/emacs-lisp/elint.el b/lisp/emacs-lisp/elint.el
index e2cffedd45f..79b72ff969f 100644
--- a/lisp/emacs-lisp/elint.el
+++ b/lisp/emacs-lisp/elint.el
@@ -355,15 +355,14 @@ Returns the forms."
;; Env is up to date
elint-buffer-forms
;; Remake env
- (set (make-local-variable 'elint-buffer-forms) (elint-get-top-forms))
- (set (make-local-variable 'elint-features) nil)
- (set (make-local-variable 'elint-buffer-env)
- (elint-init-env elint-buffer-forms))
+ (setq-local elint-buffer-forms (elint-get-top-forms))
+ (setq-local elint-features nil)
+ (setq-local elint-buffer-env (elint-init-env elint-buffer-forms))
(if elint-preloaded-env
;; FIXME: This doesn't do anything! Should we setq the result to
;; elint-buffer-env?
(elint-env-add-env elint-preloaded-env elint-buffer-env))
- (set (make-local-variable 'elint-last-env-time) (buffer-modified-tick))
+ (setq-local elint-last-env-time (buffer-modified-tick))
elint-buffer-forms))
(defun elint-get-top-forms ()
@@ -456,8 +455,8 @@ Return nil if there are no more forms, t otherwise."
(= 4 (length form))
(eq (car-safe (cadr form)) 'quote)
(equal (nth 2 form) '(quote error-conditions)))
- (set (make-local-variable 'elint-extra-errors)
- (cons (cadr (cadr form)) elint-extra-errors)))
+ (setq-local elint-extra-errors
+ (cons (cadr (cadr form)) elint-extra-errors)))
((eq (car form) 'provide)
(add-to-list 'elint-features (eval (cadr form))))
;; Import variable definitions
@@ -559,7 +558,8 @@ Return nil if there are no more forms, t otherwise."
(when . elint-check-conditional-form)
(unless . elint-check-conditional-form)
(and . elint-check-conditional-form)
- (or . elint-check-conditional-form))
+ (or . elint-check-conditional-form)
+ (require . elint-require-form))
"Functions to call when some special form should be linted.")
(defun elint-form (form env &optional nohandler)
@@ -954,6 +954,13 @@ Does basic handling of `featurep' tests."
(elint-form form env t))))
env)
+(defun elint-require-form (form _env)
+ "Load `require'd files."
+ (pcase form
+ (`(require ',x)
+ (require x)))
+ nil)
+
;;;
;;; Message functions
;;;
diff --git a/lisp/emacs-lisp/ert-x.el b/lisp/emacs-lisp/ert-x.el
index 6569b8ccc87..a8da2c413e0 100644
--- a/lisp/emacs-lisp/ert-x.el
+++ b/lisp/emacs-lisp/ert-x.el
@@ -30,6 +30,7 @@
(eval-when-compile (require 'cl-lib))
(require 'ert)
+(require 'subr-x) ; string-trim
;;; Test buffers.
@@ -353,6 +354,46 @@ convert it to a string and pass it to COLLECTOR first."
(funcall func object)))
(funcall func object printcharfun))))
+(defvar ert-resource-directory-format "%s-resources/"
+ "Format for `ert-resource-directory'.")
+(defvar ert-resource-directory-trim-left-regexp ""
+ "Regexp for `string-trim' (left) used by `ert-resource-directory'.")
+(defvar ert-resource-directory-trim-right-regexp "\\(-tests?\\)?\\.el"
+ "Regexp for `string-trim' (right) used by `ert-resource-directory'.")
+
+;; Has to be a macro for `load-file-name'.
+(defmacro ert-resource-directory ()
+ "Return absolute file name of the resource (test data) directory.
+
+The path to the resource directory is the \"resources\" directory
+in the same directory as the test file this is called from.
+
+If that directory doesn't exist, find a directory based on the
+test file name. If the file is named \"foo-tests.el\", return
+the absolute file name for \"foo-resources\". If you want a
+different resource directory naming scheme, set the variable
+`ert-resource-directory-format'. Before formatting, the file
+name will be trimmed using `string-trim' with arguments
+`ert-resource-directory-trim-left-regexp' and
+`ert-resource-directory-trim-right-regexp'."
+ `(let* ((testfile ,(or (bound-and-true-p byte-compile-current-file)
+ (and load-in-progress load-file-name)
+ buffer-file-name))
+ (default-directory (file-name-directory testfile)))
+ (file-truename
+ (if (file-accessible-directory-p "resources/")
+ (expand-file-name "resources/")
+ (expand-file-name
+ (format ert-resource-directory-format
+ (string-trim testfile
+ ert-resource-directory-trim-left-regexp
+ ert-resource-directory-trim-right-regexp)))))))
+
+(defmacro ert-resource-file (file)
+ "Return file name of resource file named FILE.
+A resource file is in the resource directory as per
+`ert-resource-directory'."
+ `(expand-file-name ,file (ert-resource-directory)))
(provide 'ert-x)
diff --git a/lisp/emacs-lisp/ert.el b/lisp/emacs-lisp/ert.el
index ebb27e8a62c..25237feae2a 100644
--- a/lisp/emacs-lisp/ert.el
+++ b/lisp/emacs-lisp/ert.el
@@ -58,13 +58,11 @@
;;; Code:
(require 'cl-lib)
-(require 'button)
(require 'debug)
(require 'backtrace)
(require 'easymenu)
(require 'ewoc)
(require 'find-func)
-(require 'help)
(require 'pp)
;;; UI customization options.
@@ -276,7 +274,7 @@ DATA is displayed to the user and should state the reason for skipping."
It should only be stopped when ran from inside ert--run-test-internal."
(when (and (not (symbolp debugger)) ; only run on anonymous debugger
(memq error-symbol '(ert-test-failed ert-test-skipped)))
- (funcall debugger 'error data)))
+ (funcall debugger 'error (list error-symbol data))))
(defun ert--special-operator-p (thing)
"Return non-nil if THING is a symbol naming a special operator."
@@ -1305,7 +1303,8 @@ EXPECTEDP specifies whether the result was expected."
"Pretty-print OBJECT, indenting it to the current column of point.
Ensures a final newline is inserted."
(let ((begin (point))
- (pp-escape-newlines nil))
+ (pp-escape-newlines nil)
+ (print-escape-control-characters t))
(pp object (current-buffer))
(unless (bolp) (insert "\n"))
(save-excursion
@@ -1803,8 +1802,8 @@ Also sets `ert--results-progress-bar-button-begin'."
;; `progress-bar-button-begin' will be the right position
;; even in the results buffer.
(with-current-buffer results-buffer
- (set (make-local-variable 'ert--results-progress-bar-button-begin)
- progress-bar-button-begin))))
+ (setq-local ert--results-progress-bar-button-begin
+ progress-bar-button-begin))))
(insert "\n\n")
(buffer-string))
;; footer
@@ -1980,15 +1979,15 @@ BUFFER-NAME, if non-nil, is the buffer name to use."
;; from ert-results-mode to ert-results-mode when
;; font-lock-mode turns itself off in change-major-mode-hook.)
(erase-buffer)
- (set (make-local-variable 'font-lock-function)
- 'ert--results-font-lock-function)
+ (setq-local font-lock-function
+ 'ert--results-font-lock-function)
(let ((ewoc (ewoc-create 'ert--print-test-for-ewoc nil nil t)))
- (set (make-local-variable 'ert--results-ewoc) ewoc)
- (set (make-local-variable 'ert--results-stats) stats)
- (set (make-local-variable 'ert--results-progress-bar-string)
- (make-string (ert-stats-total stats)
- (ert-char-for-test-result nil t)))
- (set (make-local-variable 'ert--results-listener) listener)
+ (setq-local ert--results-ewoc ewoc)
+ (setq-local ert--results-stats stats)
+ (setq-local ert--results-progress-bar-string
+ (make-string (ert-stats-total stats)
+ (ert-char-for-test-result nil t)))
+ (setq-local ert--results-listener listener)
(cl-loop for test across (ert--stats-tests stats) do
(ewoc-enter-last ewoc
(make-ert--ewoc-entry :test test
diff --git a/lisp/emacs-lisp/lisp-mode.el b/lisp/emacs-lisp/lisp-mode.el
index 352210f859d..e477ef17000 100644
--- a/lisp/emacs-lisp/lisp-mode.el
+++ b/lisp/emacs-lisp/lisp-mode.el
@@ -38,7 +38,7 @@
(define-abbrev-table 'lisp-mode-abbrev-table ()
"Abbrev table for Lisp mode.")
-(defvar lisp--mode-syntax-table
+(defvar lisp-data-mode-syntax-table
(let ((table (make-syntax-table))
(i 0))
(while (< i ?0)
@@ -77,11 +77,13 @@
(modify-syntax-entry ?\\ "\\ " table)
(modify-syntax-entry ?\( "() " table)
(modify-syntax-entry ?\) ")( " table)
+ (modify-syntax-entry ?\[ "(]" table)
+ (modify-syntax-entry ?\] ")[" table)
table)
"Parent syntax table used in Lisp modes.")
(defvar lisp-mode-syntax-table
- (let ((table (make-syntax-table lisp--mode-syntax-table)))
+ (let ((table (make-syntax-table lisp-data-mode-syntax-table)))
(modify-syntax-entry ?\[ "_ " table)
(modify-syntax-entry ?\] "_ " table)
(modify-syntax-entry ?# "' 14" table)
@@ -178,13 +180,16 @@
(defun lisp--match-hidden-arg (limit)
(let ((res nil))
+ (forward-line 0)
(while
- (let ((ppss (parse-partial-sexp (line-beginning-position)
+ (let ((ppss (parse-partial-sexp (point)
(line-end-position)
-1)))
(skip-syntax-forward " )")
(if (or (>= (car ppss) 0)
- (looking-at ";\\|$"))
+ (eolp)
+ (looking-at ";")
+ (nth 8 (syntax-ppss))) ;Within a string or comment.
(progn
(forward-line 1)
(< (point) limit))
@@ -478,7 +483,8 @@ This will generate compile-time constants from BINDINGS."
(3 'font-lock-regexp-grouping-construct prepend))
(lisp--match-hidden-arg
(0 '(face font-lock-warning-face
- help-echo "Hidden behind deeper element; move to another line?")))
+ help-echo "Easy to misread; consider moving the element to the next line")
+ prepend))
(lisp--match-confusable-symbol-character
0 '(face font-lock-warning-face
help-echo "Confusable character"))
@@ -522,7 +528,8 @@ This will generate compile-time constants from BINDINGS."
(1 font-lock-keyword-face))
(lisp--match-hidden-arg
(0 '(face font-lock-warning-face
- help-echo "Hidden behind deeper element; move to another line?")))
+ help-echo "Easy to misread; consider moving the element to the next line")
+ prepend))
))
"Gaudy level highlighting for Lisp modes.")))
@@ -629,7 +636,7 @@ font-lock keywords will not be case sensitive."
;; and should make no difference for explicit fill
;; because lisp-fill-paragraph should do the job.
;; I believe that newcomment's auto-fill code properly deals with it -stef
- ;;(set (make-local-variable 'adaptive-fill-mode) nil)
+ ;;(setq-local adaptive-fill-mode nil)
(setq-local indent-line-function 'lisp-indent-line)
(setq-local indent-region-function 'lisp-indent-region)
(setq-local comment-indent-function #'lisp-comment-indent)
@@ -664,7 +671,7 @@ font-lock keywords will not be case sensitive."
(define-derived-mode lisp-data-mode prog-mode "Lisp-Data"
"Major mode for buffers holding data written in Lisp syntax."
:group 'lisp
- (lisp-mode-variables t t nil)
+ (lisp-mode-variables nil t nil)
(setq-local electric-quote-string t)
(setq imenu-case-fold-search nil))
diff --git a/lisp/emacs-lisp/lisp.el b/lisp/emacs-lisp/lisp.el
index 35590123ee6..124900168c3 100644
--- a/lisp/emacs-lisp/lisp.el
+++ b/lisp/emacs-lisp/lisp.el
@@ -784,9 +784,17 @@ This command assumes point is not in a string or comment."
(interactive "P")
(insert-pair arg ?\( ?\)))
+(defcustom delete-pair-blink-delay blink-matching-delay
+ "Time in seconds to delay after showing a paired character to delete.
+It's used by the command `delete-pair'. The value 0 disables blinking."
+ :type 'number
+ :group 'lisp
+ :version "28.1")
+
(defun delete-pair (&optional arg)
"Delete a pair of characters enclosing ARG sexps that follow point.
-A negative ARG deletes a pair around the preceding ARG sexps instead."
+A negative ARG deletes a pair around the preceding ARG sexps instead.
+The option `delete-pair-blink-delay' can disable blinking."
(interactive "P")
(if arg
(setq arg (prefix-numeric-value arg))
@@ -802,6 +810,9 @@ A negative ARG deletes a pair around the preceding ARG sexps instead."
(if (= (length p) 3) (cdr p) p))
insert-pair-alist))
(error "Not after matching pair"))
+ (when (and (numberp delete-pair-blink-delay)
+ (> delete-pair-blink-delay 0))
+ (sit-for delete-pair-blink-delay))
(delete-char 1)))
(delete-char -1))
(save-excursion
@@ -814,6 +825,9 @@ A negative ARG deletes a pair around the preceding ARG sexps instead."
(if (= (length p) 3) (cdr p) p))
insert-pair-alist))
(error "Not before matching pair"))
+ (when (and (numberp delete-pair-blink-delay)
+ (> delete-pair-blink-delay 0))
+ (sit-for delete-pair-blink-delay))
(delete-char -1)))
(delete-char 1))))
diff --git a/lisp/emacs-lisp/memory-report.el b/lisp/emacs-lisp/memory-report.el
new file mode 100644
index 00000000000..04ae87d9ea0
--- /dev/null
+++ b/lisp/emacs-lisp/memory-report.el
@@ -0,0 +1,303 @@
+;;; memory-report.el --- Short function summaries -*- lexical-binding: t -*-
+
+;; Copyright (C) 2020 Free Software Foundation, Inc.
+
+;; Keywords: lisp, help
+
+;; This file is part of GNU Emacs.
+
+;; GNU Emacs is free software: you can redistribute it and/or modify
+;; it under the terms of the GNU General Public License as published by
+;; the Free Software Foundation, either version 3 of the License, or
+;; (at your option) any later version.
+
+;; GNU Emacs is distributed in the hope that it will be useful,
+;; but WITHOUT ANY WARRANTY; without even the implied warranty of
+;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+;; GNU General Public License for more details.
+
+;; You should have received a copy of the GNU General Public License
+;; along with GNU Emacs. If not, see <https://www.gnu.org/licenses/>.
+
+;;; Commentary:
+
+;; Todo (possibly): Font cache, regexp cache, bidi cache, various
+;; buffer caches (newline cache, free_region_cache, etc), composition
+;; cache, face cache.
+
+;;; Code:
+
+(require 'seq)
+(require 'subr-x)
+(eval-when-compile (require 'cl-lib))
+
+(defvar memory-report--type-size (make-hash-table))
+
+;;;###autoload
+(defun memory-report ()
+ "Generate a report of how Emacs is using memory.
+
+This report is approximate, and will commonly over-count memory
+usage by variables, because shared data structures will usually
+by counted more than once."
+ (interactive)
+ (pop-to-buffer "*Memory Report*")
+ (special-mode)
+ (button-mode 1)
+ (setq truncate-lines t)
+ (message "Gathering data...")
+ (let ((reports (append (memory-report--garbage-collect)
+ (memory-report--image-cache)
+ (memory-report--buffers)
+ (memory-report--largest-variables)))
+ (inhibit-read-only t)
+ summaries details)
+ (message "Gathering data...done")
+ (erase-buffer)
+ (insert (propertize "Estimated Emacs Memory Usage\n\n" 'face 'bold))
+ (dolist (report reports)
+ (if (listp report)
+ (push report summaries)
+ (push report details)))
+ (dolist (summary (seq-sort (lambda (e1 e2)
+ (> (cdr e1) (cdr e2)))
+ summaries))
+ (insert (format "%s %s\n"
+ (memory-report--format (cdr summary))
+ (car summary))))
+ (insert "\n")
+ (dolist (detail (nreverse details))
+ (insert detail "\n")))
+ (goto-char (point-min)))
+
+(defun memory-report-object-size (object)
+ "Return the size of OBJECT in bytes."
+ (unless memory-report--type-size
+ (memory-report--garbage-collect))
+ (memory-report--object-size (make-hash-table :test #'eq) object))
+
+(defun memory-report--size (type)
+ (or (gethash type memory-report--type-size)
+ (gethash 'object memory-report--type-size)))
+
+(defun memory-report--set-size (elems)
+ (setf (gethash 'string memory-report--type-size)
+ (cadr (assq 'strings elems)))
+ (setf (gethash 'cons memory-report--type-size)
+ (cadr (assq 'conses elems)))
+ (setf (gethash 'symbol memory-report--type-size)
+ (cadr (assq 'symbols elems)))
+ (setf (gethash 'object memory-report--type-size)
+ (cadr (assq 'vectors elems)))
+ (setf (gethash 'float memory-report--type-size)
+ (cadr (assq 'floats elems)))
+ (setf (gethash 'buffer memory-report--type-size)
+ (cadr (assq 'buffers elems))))
+
+(defun memory-report--garbage-collect ()
+ (let ((elems (garbage-collect)))
+ (memory-report--set-size elems)
+ (let ((data (list
+ (list 'strings
+ (+ (memory-report--gc-elem elems 'strings)
+ (memory-report--gc-elem elems 'string-bytes)))
+ (list 'vectors
+ (+ (memory-report--gc-elem elems 'vectors)
+ (memory-report--gc-elem elems 'vector-slots)))
+ (list 'floats (memory-report--gc-elem elems 'floats))
+ (list 'conses (memory-report--gc-elem elems 'conses))
+ (list 'symbols (memory-report--gc-elem elems 'symbols))
+ (list 'intervals (memory-report--gc-elem elems 'intervals))
+ (list 'buffer-objects
+ (memory-report--gc-elem elems 'buffers)))))
+ (list (cons "Overall Object Memory Usage"
+ (seq-reduce #'+ (mapcar (lambda (elem)
+ (* (nth 1 elem) (nth 2 elem)))
+ elems)
+ 0))
+ (cons "Reserved (But Unused) Object Memory"
+ (seq-reduce #'+ (mapcar (lambda (elem)
+ (if (nth 3 elem)
+ (* (nth 1 elem) (nth 3 elem))
+ 0))
+ elems)
+ 0))
+ (with-temp-buffer
+ (insert (propertize "Object Storage\n\n" 'face 'bold))
+ (dolist (object (seq-sort (lambda (e1 e2)
+ (> (cadr e1) (cadr e2)))
+ data))
+ (insert (format "%s %s\n"
+ (memory-report--format (cadr object))
+ (capitalize (symbol-name (car object))))))
+ (buffer-string))))))
+
+(defun memory-report--largest-variables ()
+ (let ((variables nil))
+ (mapatoms
+ (lambda (symbol)
+ (when (boundp symbol)
+ (let ((size (memory-report--object-size
+ (make-hash-table :test #'eq)
+ (symbol-value symbol))))
+ (when (> size 1000)
+ (push (cons symbol size) variables)))))
+ obarray)
+ (list
+ (cons (propertize "Memory Used By Global Variables"
+ 'help-echo "Upper bound; mutually overlapping data from different variables are counted several times")
+ (seq-reduce #'+ (mapcar #'cdr variables) 0))
+ (with-temp-buffer
+ (insert (propertize "Largest Variables\n\n" 'face 'bold))
+ (cl-loop for i from 1 upto 20
+ for (symbol . size) in (seq-sort (lambda (e1 e2)
+ (> (cdr e1) (cdr e2)))
+ variables)
+ do (insert (memory-report--format size)
+ " "
+ (symbol-name symbol)
+ "\n"))
+ (buffer-string)))))
+
+(defun memory-report--object-size (counted value)
+ (if (gethash value counted)
+ 0
+ (setf (gethash value counted) t)
+ (memory-report--object-size-1 counted value)))
+
+(cl-defgeneric memory-report--object-size-1 (_counted _value)
+ 0)
+
+(cl-defmethod memory-report--object-size-1 (_ (value symbol))
+ ;; Don't count global symbols -- makes sizes of lists of symbols too
+ ;; heavey.
+ (if (intern-soft value obarray)
+ 0
+ (memory-report--size 'symbol)))
+
+(cl-defmethod memory-report--object-size-1 (_ (_value buffer))
+ (memory-report--size 'buffer))
+
+(cl-defmethod memory-report--object-size-1 (counted (value string))
+ (+ (memory-report--size 'string)
+ (string-bytes value)
+ (memory-report--interval-size counted (object-intervals value))))
+
+(defun memory-report--interval-size (counted intervals)
+ ;; We get a list back of intervals, but only count the "inner list"
+ ;; (i.e., the actual text properties), and add the size of the
+ ;; intervals themselves.
+ (+ (* (memory-report--size 'interval) (length intervals))
+ (seq-reduce #'+ (mapcar
+ (lambda (interval)
+ (memory-report--object-size counted (nth 2 interval)))
+ intervals)
+ 0)))
+
+(cl-defmethod memory-report--object-size-1 (counted (value list))
+ (let ((total 0)
+ (size (memory-report--size 'cons)))
+ (while value
+ (cl-incf total size)
+ (setf (gethash value counted) t)
+ (when (car value)
+ (cl-incf total (memory-report--object-size counted (car value))))
+ (if (cdr value)
+ (if (consp (cdr value))
+ (setq value (cdr value))
+ (cl-incf total (memory-report--object-size counted (cdr value)))
+ (setq value nil))
+ (setq value nil)))
+ total))
+
+(cl-defmethod memory-report--object-size-1 (counted (value vector))
+ (let ((total (+ (memory-report--size 'vector)
+ (* (memory-report--size 'object) (length value)))))
+ (cl-loop for elem across value
+ do (setf (gethash elem counted) t)
+ (cl-incf total (memory-report--object-size counted elem)))
+ total))
+
+(cl-defmethod memory-report--object-size-1 (counted (value hash-table))
+ (let ((total (+ (memory-report--size 'vector)
+ (* (memory-report--size 'object) (hash-table-size value)))))
+ (maphash
+ (lambda (key elem)
+ (setf (gethash key counted) t)
+ (setf (gethash elem counted) t)
+ (cl-incf total (memory-report--object-size counted key))
+ (cl-incf total (memory-report--object-size counted elem)))
+ value)
+ total))
+
+(defun memory-report--format (bytes)
+ (setq bytes (/ bytes 1024.0))
+ (let ((units '("kB" "MB" "GB" "TB")))
+ (while (>= bytes 1024)
+ (setq bytes (/ bytes 1024.0))
+ (setq units (cdr units)))
+ (format "%6.1f%s" bytes (car units))))
+
+(defun memory-report--gc-elem (elems type)
+ (* (nth 1 (assq type elems))
+ (nth 2 (assq type elems))))
+
+(defun memory-report--buffers ()
+ (let ((buffers (mapcar (lambda (buffer)
+ (cons buffer (memory-report--buffer buffer)))
+ (buffer-list))))
+ (list (cons "Total Buffer Memory Usage"
+ (seq-reduce #'+ (mapcar #'cdr buffers) 0))
+ (with-temp-buffer
+ (insert (propertize "Largest Buffers\n\n" 'face 'bold))
+ (cl-loop for i from 1 upto 20
+ for (buffer . size) in (seq-sort (lambda (e1 e2)
+ (> (cdr e1) (cdr e2)))
+ buffers)
+ do (insert (memory-report--format size)
+ " "
+ (button-buttonize
+ (buffer-name buffer)
+ #'memory-report--buffer-details buffer)
+ "\n"))
+ (buffer-string)))))
+
+(defun memory-report--buffer-details (buffer)
+ (with-current-buffer buffer
+ (apply
+ #'message
+ "Buffer text: %s; variables: %s; text properties: %s; overlays: %s"
+ (mapcar #'string-trim (mapcar #'memory-report--format
+ (memory-report--buffer-data buffer))))))
+
+(defun memory-report--buffer (buffer)
+ (seq-reduce #'+ (memory-report--buffer-data buffer) 0))
+
+(defun memory-report--buffer-data (buffer)
+ (with-current-buffer buffer
+ (list (save-restriction
+ (widen)
+ (+ (position-bytes (point-max))
+ (- (position-bytes (point-min)))
+ (gap-size)))
+ (seq-reduce #'+ (mapcar (lambda (elem)
+ (if (cdr elem)
+ (memory-report--object-size
+ (make-hash-table :test #'eq)
+ (cdr elem))
+ 0))
+ (buffer-local-variables buffer))
+ 0)
+ (memory-report--object-size (make-hash-table :test #'eq)
+ (object-intervals buffer))
+ (memory-report--object-size (make-hash-table :test #'eq)
+ (overlay-lists)))))
+
+(defun memory-report--image-cache ()
+ (list (cons "Total Image Cache Size" (if (fboundp 'image-cache-size)
+ (image-cache-size)
+ 0))))
+
+(provide 'memory-report)
+
+;;; memory-report.el ends here
diff --git a/lisp/emacs-lisp/package.el b/lisp/emacs-lisp/package.el
index 1f81e07754b..b7c48dfd3f5 100644
--- a/lisp/emacs-lisp/package.el
+++ b/lisp/emacs-lisp/package.el
@@ -982,7 +982,8 @@ untar into a directory named DIR; otherwise, signal an error."
(write-region
(concat
";;; Generated package description from "
- (replace-regexp-in-string "-pkg\\.el\\'" ".el" pkg-file)
+ (replace-regexp-in-string "-pkg\\.el\\'" ".el"
+ (file-name-nondirectory pkg-file))
" -*- no-byte-compile: t -*-\n"
(prin1-to-string
(nconc
@@ -1114,14 +1115,15 @@ boundaries."
;; Use some headers we've invented to drive the process.
(let* (;; Prefer Package-Version; if defined, the package author
;; probably wants us to use it. Otherwise try Version.
- (pkg-version
- (or (package-strip-rcs-id (lm-header "package-version"))
- (package-strip-rcs-id (lm-header "version"))))
+ (version-info
+ (or (lm-header "package-version") (lm-header "version")))
+ (pkg-version (package-strip-rcs-id version-info))
(keywords (lm-keywords-list))
(homepage (lm-homepage)))
(unless pkg-version
- (error
- "Package lacks a \"Version\" or \"Package-Version\" header"))
+ (if version-info
+ (error "Unrecognized package version: %s" version-info)
+ (error "Package lacks a \"Version\" or \"Package-Version\" header")))
(package-desc-from-define
file-name pkg-version desc
(and-let* ((require-lines (lm-header-multiline "package-requires")))
@@ -2111,8 +2113,10 @@ Otherwise return nil."
(when str
(when (string-match "\\`[ \t]*[$]Revision:[ \t]+" str)
(setq str (substring str (match-end 0))))
- (ignore-errors
- (if (version-to-list str) str))))
+ (let ((l (version-to-list str)))
+ ;; Don't return `str' but (package-version-join (version-to-list str))
+ ;; to make sure we use a "canonical name"!
+ (if l (package-version-join l)))))
(declare-function lm-homepage "lisp-mnt" (&optional file))
@@ -2152,6 +2156,7 @@ Downloads and installs required packages as needed."
(unless (package--user-selected-p name)
(package--save-selected-packages
(cons name package-selected-packages)))
+ (package--quickstart-maybe-refresh)
pkg-desc))
;;;###autoload
@@ -2630,8 +2635,7 @@ Used for the `action' property of buttons in the buffer created by
(when (y-or-n-p (format-message "Install package `%s'? "
(package-desc-full-name pkg-desc)))
(package-install pkg-desc nil)
- (revert-buffer nil t)
- (goto-char (point-min)))))
+ (describe-package (package-desc-name pkg-desc)))))
(defun package-delete-button-action (button)
"Run `package-delete' on the package BUTTON points to.
@@ -2641,8 +2645,7 @@ Used for the `action' property of buttons in the buffer created by
(when (y-or-n-p (format-message "Delete package `%s'? "
(package-desc-full-name pkg-desc)))
(package-delete pkg-desc)
- (revert-buffer nil t)
- (goto-char (point-min)))))
+ (describe-package (package-desc-name pkg-desc)))))
(defun package-keyword-button-action (button)
"Show filtered \"*Packages*\" buffer for BUTTON.
@@ -2704,11 +2707,14 @@ either a full name or nil, and EMAIL is a valid email address."
(define-key map "(" #'package-menu-toggle-hiding)
(define-key map (kbd "/ /") 'package-menu-clear-filter)
(define-key map (kbd "/ a") 'package-menu-filter-by-archive)
+ (define-key map (kbd "/ d") 'package-menu-filter-by-description)
(define-key map (kbd "/ k") 'package-menu-filter-by-keyword)
+ (define-key map (kbd "/ N") 'package-menu-filter-by-name-or-description)
(define-key map (kbd "/ n") 'package-menu-filter-by-name)
(define-key map (kbd "/ s") 'package-menu-filter-by-status)
(define-key map (kbd "/ v") 'package-menu-filter-by-version)
(define-key map (kbd "/ m") 'package-menu-filter-marked)
+ (define-key map (kbd "/ u") 'package-menu-filter-upgradable)
map)
"Local keymap for `package-menu-mode' buffers.")
@@ -2735,8 +2741,11 @@ either a full name or nil, and EMAIL is a valid email address."
"--"
("Filter Packages"
["Filter by Archive" package-menu-filter-by-archive :help "Filter packages by archive"]
+ ["Filter by Description" package-menu-filter-by-description :help "Filter packages by description"]
["Filter by Keyword" package-menu-filter-by-keyword :help "Filter packages by keyword"]
["Filter by Name" package-menu-filter-by-name :help "Filter packages by name"]
+ ["Filter by Name or Description" package-menu-filter-by-name-or-description
+ :help "Filter packages by name or description"]
["Filter by Status" package-menu-filter-by-status :help "Filter packages by status"]
["Filter by Version" package-menu-filter-by-version :help "Filter packages by version"]
["Filter Marked" package-menu-filter-marked :help "Filter packages marked for upgrade"]
@@ -3764,6 +3773,23 @@ packages."
(string-join archive ",")
archive)))))
+(defun package-menu-filter-by-description (description)
+ "Filter the \"*Packages*\" buffer by DESCRIPTION regexp.
+Display only packages with a description that matches regexp
+DESCRIPTION.
+
+When called interactively, prompt for DESCRIPTION.
+
+If DESCRIPTION is nil or the empty string, show all packages."
+ (interactive (list (read-regexp "Filter by description (regexp)")))
+ (package--ensure-package-menu-mode)
+ (if (or (not description) (string-empty-p description))
+ (package-menu--generate t t)
+ (package-menu--filter-by (lambda (pkg-desc)
+ (string-match description
+ (package-desc-summary pkg-desc)))
+ (format "desc:%s" description))))
+
(defun package-menu-filter-by-keyword (keyword)
"Filter the \"*Packages*\" buffer by KEYWORD.
Display only packages with specified KEYWORD.
@@ -3789,6 +3815,27 @@ packages."
(define-obsolete-function-alias
'package-menu-filter #'package-menu-filter-by-keyword "27.1")
+(defun package-menu-filter-by-name-or-description (name-or-description)
+ "Filter the \"*Packages*\" buffer by NAME-OR-DESCRIPTION regexp.
+Display only packages with a name-or-description that matches regexp
+NAME-OR-DESCRIPTION.
+
+When called interactively, prompt for NAME-OR-DESCRIPTION.
+
+If NAME-OR-DESCRIPTION is nil or the empty string, show all
+packages."
+ (interactive (list (read-regexp "Filter by name or description (regexp)")))
+ (package--ensure-package-menu-mode)
+ (if (or (not name-or-description) (string-empty-p name-or-description))
+ (package-menu--generate t t)
+ (package-menu--filter-by (lambda (pkg-desc)
+ (or (string-match name-or-description
+ (package-desc-summary pkg-desc))
+ (string-match name-or-description
+ (symbol-name
+ (package-desc-name pkg-desc)))))
+ (format "name-or-desc:%s" name-or-description))))
+
(defun package-menu-filter-by-name (name)
"Filter the \"*Packages*\" buffer by NAME regexp.
Display only packages with name that matches regexp NAME.
@@ -3905,6 +3952,15 @@ Unlike other filters, this leaves the marks intact."
(tabulated-list-put-tag (char-to-string mark) t)))
(user-error "No packages found")))))
+(defun package-menu-filter-upgradable ()
+ "Filter \"*Packages*\" buffer to show only upgradable packages."
+ (interactive)
+ (let ((pkgs (mapcar #'car (package-menu--find-upgrades))))
+ (package-menu--filter-by
+ (lambda (pkg)
+ (memql (package-desc-name pkg) pkgs))
+ "upgradable")))
+
(defun package-menu-clear-filter ()
"Clear any filter currently applied to the \"*Packages*\" buffer."
(interactive)
diff --git a/lisp/emacs-lisp/pcase.el b/lisp/emacs-lisp/pcase.el
index 09c48d095cc..206f0dd1a9d 100644
--- a/lisp/emacs-lisp/pcase.el
+++ b/lisp/emacs-lisp/pcase.el
@@ -3,7 +3,7 @@
;; Copyright (C) 2010-2020 Free Software Foundation, Inc.
;; Author: Stefan Monnier <monnier@iro.umontreal.ca>
-;; Keywords:
+;; Keywords: extensions
;; This file is part of GNU Emacs.
@@ -409,7 +409,8 @@ of the elements of LIST is performed as if by `pcase-let'.
(dolist (case cases)
(unless (or (memq case used-cases)
(memq (car case) pcase--dontwarn-upats))
- (message "Redundant pcase pattern: %S" (car case))))
+ (message "pcase pattern %S shadowed by previous pcase pattern"
+ (car case))))
(macroexp-let* defs main))))
(defun pcase--macroexpand (pat)
diff --git a/lisp/emacs-lisp/pp.el b/lisp/emacs-lisp/pp.el
index 3df7b0e368e..de7d2020ea8 100644
--- a/lisp/emacs-lisp/pp.el
+++ b/lisp/emacs-lisp/pp.el
@@ -94,33 +94,31 @@ after OUT-BUFFER-NAME."
;; This function either decides not to display it at all
;; or displays it in the usual way.
(temp-buffer-show-function
- (function
- (lambda (buf)
- (with-current-buffer buf
- (goto-char (point-min))
- (end-of-line 1)
- (if (or (< (1+ (point)) (point-max))
- (>= (- (point) (point-min)) (frame-width)))
- (let ((temp-buffer-show-function old-show-function)
- (old-selected (selected-window))
- (window (display-buffer buf)))
- (goto-char (point-min)) ; expected by some hooks ...
- (make-frame-visible (window-frame window))
- (unwind-protect
- (progn
- (select-window window)
- (run-hooks 'temp-buffer-show-hook))
- (when (window-live-p old-selected)
- (select-window old-selected))
- (message "See buffer %s." out-buffer-name)))
- (message "%s" (buffer-substring (point-min) (point)))
- ))))))
+ (lambda (buf)
+ (with-current-buffer buf
+ (goto-char (point-min))
+ (end-of-line 1)
+ (if (or (< (1+ (point)) (point-max))
+ (>= (- (point) (point-min)) (frame-width)))
+ (let ((temp-buffer-show-function old-show-function)
+ (old-selected (selected-window))
+ (window (display-buffer buf)))
+ (goto-char (point-min)) ; expected by some hooks ...
+ (make-frame-visible (window-frame window))
+ (unwind-protect
+ (progn
+ (select-window window)
+ (run-hooks 'temp-buffer-show-hook))
+ (when (window-live-p old-selected)
+ (select-window old-selected))
+ (message "See buffer %s." out-buffer-name)))
+ (message "%s" (buffer-substring (point-min) (point))))))))
(with-output-to-temp-buffer out-buffer-name
(pp expression)
(with-current-buffer standard-output
(emacs-lisp-mode)
(setq buffer-read-only nil)
- (set (make-local-variable 'font-lock-verbose) nil)))))
+ (setq-local font-lock-verbose nil)))))
;;;###autoload
(defun pp-eval-expression (expression)
@@ -164,8 +162,11 @@ With argument, pretty-print output into current buffer.
Ignores leading comment characters."
(interactive "P")
(if arg
- (insert (pp-to-string (eval (pp-last-sexp) lexical-binding)))
- (pp-eval-expression (pp-last-sexp))))
+ (insert (pp-to-string (eval (elisp--eval-defun-1
+ (macroexpand (pp-last-sexp)))
+ lexical-binding)))
+ (pp-eval-expression (elisp--eval-defun-1
+ (macroexpand (pp-last-sexp))))))
;;;###autoload
(defun pp-macroexpand-last-sexp (arg)
diff --git a/lisp/emacs-lisp/re-builder.el b/lisp/emacs-lisp/re-builder.el
index 78ae3a8c1e5..ffbf3b4b4dd 100644
--- a/lisp/emacs-lisp/re-builder.el
+++ b/lisp/emacs-lisp/re-builder.el
@@ -271,7 +271,7 @@ Except for Lisp syntax this is the same as `reb-regexp'.")
(define-derived-mode reb-mode nil "RE Builder"
"Major mode for interactively building Regular Expressions."
- (set (make-local-variable 'blink-matching-paren) nil)
+ (setq-local blink-matching-paren nil)
(reb-mode-common))
(defvar reb-lisp-mode-map
@@ -832,8 +832,8 @@ If SUBEXP is non-nil mark only the corresponding sub-expressions."
(let ((font-lock-is-on font-lock-mode))
(font-lock-mode -1)
(kill-local-variable 'font-lock-set-defaults)
- ;;(set (make-local-variable 'reb-re-syntax) 'string)
- ;;(set (make-local-variable 'reb-re-syntax) 'rx)
+ ;;(setq-local reb-re-syntax 'string)
+ ;;(setq-local reb-re-syntax 'rx)
(setq font-lock-defaults
(cond
((memq reb-re-syntax '(read string))
diff --git a/lisp/emacs-lisp/regi.el b/lisp/emacs-lisp/regi.el
index 61af5e51bda..2e6e2b75d6a 100644
--- a/lisp/emacs-lisp/regi.el
+++ b/lisp/emacs-lisp/regi.el
@@ -4,7 +4,7 @@
;; Author: 1993 Barry A. Warsaw, Century Computing, Inc. <bwarsaw@cen.com>
;; Created: 24-Feb-1993
-;; Version: 1.8
+;; Old-Version: 1.8
;; Last Modified: 1993/06/01 21:33:00
;; Keywords: extensions, matching
@@ -163,18 +163,15 @@ useful information:
;; let's find the special tags and remove them from the working
;; frame. note that only the last special tag is used.
(mapc
- (function
- (lambda (entry)
- (let ((pred (car entry))
- (func (car (cdr entry))))
- (cond
- ((eq pred 'begin) (setq begin-tag func))
- ((eq pred 'end) (setq end-tag func))
- ((eq pred 'every) (setq every-tag func))
- (t
- (setq working-frame (append working-frame (list entry))))
- ) ; end-cond
- )))
+ (lambda (entry)
+ (let ((pred (car entry))
+ (func (car (cdr entry))))
+ (cond
+ ((eq pred 'begin) (setq begin-tag func))
+ ((eq pred 'end) (setq end-tag func))
+ ((eq pred 'every) (setq every-tag func))
+ (t
+ (setq working-frame (append working-frame (list entry)))))))
frame) ; end-mapcar
;; execute the begin entry
diff --git a/lisp/emacs-lisp/rx.el b/lisp/emacs-lisp/rx.el
index 8d8d071031c..6d33299e202 100644
--- a/lisp/emacs-lisp/rx.el
+++ b/lisp/emacs-lisp/rx.el
@@ -1413,11 +1413,12 @@ into a plain rx-expression, collecting names into `rx--pcase-vars'."
(mapconcat #'symbol-name rx--pcase-vars " ")))
`(backref ,index)))
((and `(,head . ,rest)
- (guard (and (symbolp head)
+ (guard (and (or (symbolp head) (memq head '(?\s ??)))
(not (memq head '(literal regexp regex eval))))))
(cons head (mapcar #'rx--pcase-transform rest)))
(_ rx)))
+;;;###autoload
(pcase-defmacro rx (&rest regexps)
"A pattern that matches strings against `rx' REGEXPS in sexp form.
REGEXPS are interpreted as in `rx'. The pattern matches any
diff --git a/lisp/emacs-lisp/seq.el b/lisp/emacs-lisp/seq.el
index d60f974aee1..4656277ea16 100644
--- a/lisp/emacs-lisp/seq.el
+++ b/lisp/emacs-lisp/seq.el
@@ -336,9 +336,11 @@ list."
"Reduce the function FUNCTION across SEQUENCE, starting with INITIAL-VALUE.
Return the result of calling FUNCTION with INITIAL-VALUE and the
-first element of SEQUENCE, then calling FUNCTION with that result and
-the second element of SEQUENCE, then with that result and the third
-element of SEQUENCE, etc.
+first element of SEQUENCE, then calling FUNCTION with that result
+and the second element of SEQUENCE, then with that result and the
+third element of SEQUENCE, etc. FUNCTION will be called with
+INITIAL-VALUE (and then the accumulated value) as the first
+argument, and the elements from SEQUENCE as the second argument.
If SEQUENCE is empty, return INITIAL-VALUE and FUNCTION is not called."
(if (seq-empty-p sequence)
@@ -472,6 +474,7 @@ Equality is defined by TESTFN if non-nil or by `equal' if nil."
(seq-reverse sequence1)
'()))
+;;;###autoload
(cl-defgeneric seq-group-by (function sequence)
"Apply FUNCTION to each element of SEQUENCE.
Separate the elements of SEQUENCE into an alist using the results as
diff --git a/lisp/emacs-lisp/shadow.el b/lisp/emacs-lisp/shadow.el
index dd614dd792c..68f58f69f7b 100644
--- a/lisp/emacs-lisp/shadow.el
+++ b/lisp/emacs-lisp/shadow.el
@@ -177,13 +177,12 @@ See the documentation for `list-load-path-shadows' for further information."
(define-derived-mode load-path-shadows-mode fundamental-mode "LP-Shadows"
"Major mode for load-path shadows buffer."
- (set (make-local-variable 'font-lock-defaults)
- '((load-path-shadows-font-lock-keywords)))
+ (setq-local font-lock-defaults
+ '((load-path-shadows-font-lock-keywords)))
(setq buffer-undo-list t
buffer-read-only t))
;; TODO use text-properties instead, a la dired.
-(require 'button)
(define-button-type 'load-path-shadows-find-file
'follow-link t
;; 'face 'default
diff --git a/lisp/emacs-lisp/shortdoc.el b/lisp/emacs-lisp/shortdoc.el
new file mode 100644
index 00000000000..37d6170fee5
--- /dev/null
+++ b/lisp/emacs-lisp/shortdoc.el
@@ -0,0 +1,1254 @@
+;;; shortdoc.el --- Short function summaries -*- lexical-binding: t -*-
+
+;; Copyright (C) 2020 Free Software Foundation, Inc.
+
+;; Keywords: lisp, help
+;; Package: emacs
+
+;; This file is part of GNU Emacs.
+
+;; GNU Emacs is free software: you can redistribute it and/or modify
+;; it under the terms of the GNU General Public License as published by
+;; the Free Software Foundation, either version 3 of the License, or
+;; (at your option) any later version.
+
+;; GNU Emacs is distributed in the hope that it will be useful,
+;; but WITHOUT ANY WARRANTY; without even the implied warranty of
+;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+;; GNU General Public License for more details.
+
+;; You should have received a copy of the GNU General Public License
+;; along with GNU Emacs. If not, see <https://www.gnu.org/licenses/>.
+
+;;; Commentary:
+
+;;; Code:
+
+(require 'seq)
+(require 'text-property-search)
+(eval-when-compile (require 'cl-lib))
+
+(defgroup shortdoc nil
+ "Short documentation."
+ :group 'lisp)
+
+(defface shortdoc-separator
+ '((((class color) (background dark))
+ :height 0.1 :background "#505050" :extend t)
+ (((class color) (background light))
+ :height 0.1 :background "#a0a0a0" :extend t)
+ (t :height 0.1 :inverse-video t :extend t))
+ "Face used to separate sections.")
+
+(defface shortdoc-section
+ '((t :inherit variable-pitch))
+ "Face used for a section.")
+
+(defvar shortdoc--groups nil)
+
+(defmacro define-short-documentation-group (group &rest functions)
+ "Add GROUP to the list of defined documentation groups.
+FUNCTIONS is a list of elements on the form:
+
+ (fun
+ :no-manual BOOL
+ :args ARGS
+ :eval EXAMPLE-FORM
+ :no-eval EXAMPLE-FORM
+ :no-value EXAMPLE-FORM
+ :result RESULT-FORM
+ :eg-result RESULT-FORM
+ :eg-result-string RESULT-FORM)
+
+BOOL should be non-nil if the function isn't documented in the
+manual.
+
+ARGS is optional; the function's signature is displayed if ARGS
+is not present.
+
+If EVAL isn't a string, it will be printed with `prin1', and then
+evaluated to give a result, which is also printed. If it's a
+string, it'll be inserted as is, then the string will be `read',
+and then evaluated.
+
+There can be any number of :example/:result elements."
+ `(progn
+ (setq shortdoc--groups (delq (assq ',group shortdoc--groups)
+ shortdoc--groups))
+ (push (cons ',group ',functions) shortdoc--groups)))
+
+(define-short-documentation-group alist
+ "Alist Basics"
+ (assoc
+ :eval (assoc 'foo '((foo . bar) (zot . baz))))
+ (rassoc
+ :eval (rassoc 'bar '((foo . bar) (zot . baz))))
+ (assq
+ :eval (assq 'foo '((foo . bar) (zot . baz))))
+ (rassq
+ :eval (rassq 'bar '((foo . bar) (zot . baz))))
+ (assoc-string
+ :eval (assoc-string "foo" '(("foo" . "bar") ("zot" "baz"))))
+ "Manipulating Alists"
+ (assoc-delete-all
+ :eval (assoc-delete-all "foo" '(("foo" . "bar") ("zot" . "baz")) #'equal))
+ (assq-delete-all
+ :eval (assq-delete-all 'foo '((foo . bar) (zot . baz))))
+ (rassq-delete-all
+ :eval (rassq-delete-all 'bar '((foo . bar) (zot . baz))))
+ (alist-get
+ :eval (let ((foo '((bar . baz))))
+ (setf (alist-get 'bar foo) 'zot)
+ foo))
+ "Misc"
+ (assoc-default
+ :eval (assoc-default "foobar" '(("foo" . baz)) #'string-match))
+ (copy-alist
+ :eval (let* ((old '((foo . bar)))
+ (new (copy-alist old)))
+ (eq old new)))
+ ;; FIXME: Outputs "\.rose" for the symbol `.rose'.
+ ;; (let-alist
+ ;; :eval (let ((colors '((rose . red)
+ ;; (lily . white))))
+ ;; (let-alist colors
+ ;; (if (eq .rose 'red)
+ ;; .lily))))
+ )
+
+(define-short-documentation-group string
+ "Making Strings"
+ (make-string
+ :args (length init)
+ :eval "(make-string 5 ?x)")
+ (string
+ :eval "(string ?a ?b ?c)")
+ (concat
+ :eval (concat "foo" "bar" "zot"))
+ (string-join
+ :no-manual t
+ :eval (string-join '("foo" "bar" "zot") " "))
+ (mapconcat
+ :eval (mapconcat (lambda (a) (concat "[" a "]"))
+ '("foo" "bar" "zot") " "))
+ (mapcar
+ :eval (mapcar #'identity "123"))
+ (format
+ :eval (format "This number is %d" 4))
+ "Manipulating Strings"
+ (substring
+ :eval (substring "foobar" 0 3)
+ :eval (substring "foobar" 3))
+ (split-string
+ :eval (split-string "foo bar")
+ :eval (split-string "|foo|bar|" "|")
+ :eval (split-string "|foo|bar|" "|" t))
+ (string-replace
+ :eval (string-replace "foo" "bar" "foozot"))
+ (replace-regexp-in-string
+ :eval (replace-regexp-in-string "[a-z]+" "_" "*foo*"))
+ (string-trim
+ :no-manual t
+ :args (string)
+ :doc "Trim STRING of leading and trailing white space."
+ :eval (string-trim " foo "))
+ (string-trim-left
+ :no-manual t
+ :eval (string-trim-left "oofoo" "o+"))
+ (string-trim-right
+ :no-manual t
+ :eval (string-trim-right "barkss" "s+"))
+ (string-truncate-left
+ :no-manual t
+ :eval (string-truncate-left "longstring" 8))
+ (string-remove-suffix
+ :no-manual t
+ :eval (string-remove-suffix "bar" "foobar"))
+ (string-remove-prefix
+ :no-manual t
+ :eval (string-remove-prefix "foo" "foobar"))
+ (reverse
+ :eval (reverse "foo"))
+ (substring-no-properties
+ :eval (substring-no-properties (propertize "foobar" 'face 'bold) 0 3))
+ "Predicates for Strings"
+ (string-equal
+ :eval (string-equal "foo" "foo"))
+ (eq
+ :eval (eq "foo" "foo"))
+ (eql
+ :eval (eql "foo" "foo"))
+ (equal
+ :eval (equal "foo" "foo"))
+ (cl-equalp
+ :eval (cl-equalp "Foo" "foo"))
+ (stringp
+ :eval "(stringp ?a)")
+ (string-empty-p
+ :no-manual t
+ :eval (string-empty-p ""))
+ (string-blank-p
+ :no-manual t
+ :eval (string-blank-p " \n"))
+ (string-lessp
+ :eval (string-lessp "foo" "bar"))
+ (string-greaterp
+ :eval (string-greaterp "foo" "bar"))
+ (string-version-lessp
+ :eval (string-lessp "foo32.png" "bar4.png"))
+ (string-prefix-p
+ :eval (string-prefix-p "foo" "foobar"))
+ (string-suffix-p
+ :eval (string-suffix-p "bar" "foobar"))
+ "Case Manipulation"
+ (upcase
+ :eval (upcase "foo"))
+ (downcase
+ :eval (downcase "FOObar"))
+ (capitalize
+ :eval (capitalize "foo bar zot"))
+ (upcase-initials
+ :eval (upcase-initials "The CAT in the hAt"))
+ "Converting Strings"
+ (string-to-number
+ :eval (string-to-number "42")
+ :eval (string-to-number "deadbeef" 16))
+ (number-to-string
+ :eval (number-to-string 42))
+ "Data About Strings"
+ (length
+ :eval (length "foo"))
+ (string-search
+ :eval (string-search "bar" "foobarzot"))
+ (assoc-string
+ :eval (assoc-string "foo" '(("a" 1) (foo 2))))
+ (seq-position
+ :eval "(seq-position \"foobarzot\" ?z)"))
+
+(define-short-documentation-group file-name
+ "File Name Manipulation"
+ (file-name-directory
+ :eval (file-name-directory "/tmp/foo")
+ :eval (file-name-directory "/tmp/foo/"))
+ (file-name-nondirectory
+ :eval (file-name-nondirectory "/tmp/foo")
+ :eval (file-name-nondirectory "/tmp/foo/"))
+ (file-name-sans-versions
+ :args (filename)
+ :eval (file-name-sans-versions "/tmp/foo~"))
+ (file-name-extension
+ :eval (file-name-extension "/tmp/foo.txt"))
+ (file-name-sans-extension
+ :eval (file-name-sans-extension "/tmp/foo.txt"))
+ (file-name-base
+ :eval (file-name-base "/tmp/foo.txt"))
+ (file-relative-name
+ :eval (file-relative-name "/tmp/foo" "/tmp"))
+ (make-temp-name
+ :eval (make-temp-name "/tmp/foo-"))
+ (expand-file-name
+ :eval (expand-file-name "foo" "/tmp/"))
+ (substitute-in-file-name
+ :eval (substitute-in-file-name "$HOME/foo"))
+ "Directory Functions"
+ (file-name-as-directory
+ :eval (file-name-as-directory "/tmp/foo"))
+ (directory-file-name
+ :eval (directory-file-name "/tmp/foo/"))
+ (abbreviate-file-name
+ :no-eval (abbreviate-file-name "/home/some-user")
+ :eg-result "~some-user")
+ "Quoted File Names"
+ (file-name-quote
+ :args (name)
+ :eval (file-name-quote "/tmp/foo"))
+ (file-name-unquote
+ :args (name)
+ :eval (file-name-unquote "/:/tmp/foo"))
+ "Predicates"
+ (file-name-absolute-p
+ :eval (file-name-absolute-p "/tmp/foo")
+ :eval (file-name-absolute-p "foo"))
+ (directory-name-p
+ :eval (directory-name-p "/tmp/foo/"))
+ (file-name-quoted-p
+ :eval (file-name-quoted-p "/:/tmp/foo")))
+
+(define-short-documentation-group file
+ "Inserting Contents"
+ (insert-file-contents
+ :no-eval (insert-file-contents "/tmp/foo")
+ :eg-result ("/tmp/foo" 6))
+ (insert-file-contents-literally
+ :no-eval (insert-file-contents-literally "/tmp/foo")
+ :eg-result ("/tmp/foo" 6))
+ (find-file
+ :no-eval (find-file "/tmp/foo")
+ :eg-result-string "#<buffer foo>")
+ "Predicates"
+ (file-symlink-p
+ :no-eval (file-symlink-p "/tmp/foo")
+ :eg-result t)
+ (file-directory-p
+ :no-eval (file-directory-p "/tmp")
+ :eg-result t)
+ (file-regular-p
+ :no-eval (file-regular-p "/tmp/foo")
+ :eg-result t)
+ (file-exists-p
+ :no-eval (file-exists-p "/tmp/foo")
+ :eg-result t)
+ (file-readable-p
+ :no-eval (file-readable-p "/tmp/foo")
+ :eg-result t)
+ (file-writeable-p
+ :no-eval (file-writeable-p "/tmp/foo")
+ :eg-result t)
+ (file-accessible-directory-p
+ :no-eval (file-accessible-directory-p "/tmp")
+ :eg-result t)
+ (file-executable-p
+ :no-eval (file-executable-p "/bin/cat")
+ :eg-result t)
+ (file-newer-than-file-p
+ :no-eval (file-newer-than-file-p "/tmp/foo" "/tmp/bar")
+ :eg-result nil)
+ (file-equal-p
+ :no-eval (file-equal-p "/tmp/foo" "/tmp/bar")
+ :eg-result nil)
+ (file-in-directory-p
+ :no-eval (file-in-directory-p "/tmp/foo" "/tmp/")
+ :eg-result t)
+ (file-locked-p
+ :no-eval (file-locked-p "/tmp/foo")
+ :eg-result nil)
+ "Information"
+ (file-attributes
+ :no-eval* (file-attributes "/tmp"))
+ (file-truename
+ :no-eval (file-truename "/tmp/foo/bar")
+ :eg-result "/tmp/foo/zot")
+ (file-chase-links
+ :no-eval (file-chase-links "/tmp/foo/bar")
+ :eg-result "/tmp/foo/zot")
+ (vc-responsible-backend
+ :args (file &optional no-error)
+ :no-eval (vc-responsible-backend "/src/foo/bar.c")
+ :eg-result Git)
+ (file-acl
+ :no-eval (file-acl "/tmp/foo")
+ :eg-result "user::rw-\ngroup::r--\nother::r--\n")
+ (file-extended-attributes
+ :no-eval* (file-extended-attributes "/tmp/foo"))
+ (file-selinux-context
+ :no-eval* (file-selinux-context "/tmp/foo"))
+ (locate-file
+ :no-eval (locate-file "syslog" '("/var/log" "/usr/bin"))
+ :eg-result "/var/log/syslog")
+ (executable-find
+ :no-eval (executable-find "ls")
+ :eg-result "/usr/bin/ls")
+ "Creating"
+ (make-temp-file
+ :no-eval (make-temp-file "/tmp/foo-")
+ :eg-result "/tmp/foo-ZcXFMj")
+ (make-nearby-temp-file
+ :no-eval (make-nearby-temp-file "/tmp/foo-")
+ :eg-result "/tmp/foo-xe8iON")
+ (write-region
+ :no-value (write-region (point-min) (point-max) "/tmp/foo"))
+ "Directories"
+ (make-directory
+ :no-value (make-directory "/tmp/bar/zot/" t))
+ (directory-files
+ :no-eval (directory-files "/tmp/")
+ :eg-result ("." ".." ".ICE-unix" ".Test-unix"))
+ (directory-files-recursively
+ :no-eval (directory-files-recursively "/tmp/" "\\.png\\'")
+ :eg-result ("/tmp/foo.png" "/tmp/zot.png" "/tmp/bar/foobar.png"))
+ (directory-files-and-attributes
+ :no-eval* (directory-files-and-attributes "/tmp/foo"))
+ (file-expand-wildcards
+ :no-eval (file-expand-wildcards "/tmp/*.png")
+ :eg-result ("/tmp/foo.png" "/tmp/zot.png"))
+ (locate-dominating-file
+ :no-eval (locate-dominating-file "foo.png" "/tmp/foo/bar/zot")
+ :eg-result "/tmp/foo.png")
+ (copy-directory
+ :no-value (copy-directory "/tmp/bar/" "/tmp/barcopy"))
+ (delete-directory
+ :no-value (delete-directory "/tmp/bar/"))
+ "File Operations"
+ (rename-file
+ :no-value (rename-file "/tmp/foo" "/tmp/newname"))
+ (copy-file
+ :no-value (copy-file "/tmp/foo" "/tmp/foocopy"))
+ (delete-file
+ :no-value (delete-file "/tmp/foo"))
+ (make-empty-file
+ :no-value (make-empty-file "/tmp/foo"))
+ (make-symbolic-link
+ :no-value (make-symbolic-link "/tmp/foo" "/tmp/foosymlink"))
+ (add-name-to-file
+ :no-value (add-name-to-file "/tmp/foo" "/tmp/bar"))
+ (set-file-modes
+ :no-value "(set-file-modes \"/tmp/foo\" #o644)")
+ (set-file-times
+ :no-value (set-file-times "/tmp/foo" (current-time)))
+ "File Modes"
+ (set-default-file-modes
+ :no-value "(set-default-file-modes #o755)")
+ (default-file-modes
+ :no-eval (default-file-modes)
+ :eg-result-string "#o755")
+ (file-modes-symbolic-to-number
+ :no-eval (file-modes-symbolic-to-number "a+r")
+ :eg-result-string "#o444")
+ (file-modes-number-to-symbolic
+ :eval "(file-modes-number-to-symbolic #o444)")
+ (set-file-extended-attributes
+ :no-eval (set-file-extended-attributes
+ "/tmp/foo" '((acl . "group::rxx")))
+ :eg-result t)
+ (set-file-selinux-context
+ :no-eval (set-file-selinux-context
+ "/tmp/foo" '(unconfined_u object_r user_home_t s0))
+ :eg-result t)
+ (set-file-acl
+ :no-eval (set-file-acl "/tmp/foo" "group::rxx")
+ :eg-result t))
+
+(define-short-documentation-group hash-table
+ "Hash Table Basics"
+ (make-hash-table
+ :no-eval (make-hash-table)
+ :result-string "#s(hash-table ...)")
+ (puthash
+ :no-eval (puthash 'key "value" table))
+ (gethash
+ :no-eval (gethash 'key table)
+ :eg-result "value")
+ (remhash
+ :no-eval (remhash 'key table)
+ :result nil)
+ (clrhash
+ :no-eval (clrhash table)
+ :result-string "#s(hash-table ...)")
+ (maphash
+ :no-eval (maphash (lambda (key value) (message value)) table)
+ :result nil)
+ "Other Hash Table Functions"
+ (hash-table-p
+ :eval (hash-table-p 123))
+ (copy-hash-table
+ :no-eval (copy-hash-table table)
+ :result-string "#s(hash-table ...)")
+ (hash-table-count
+ :no-eval (hash-table-count table)
+ :eg-result 15)
+ (hash-table-size
+ :no-eval (hash-table-size table)
+ :eg-result 65))
+
+(define-short-documentation-group list
+ "Making Lists"
+ (make-list
+ :eval (make-list 5 'a))
+ (cons
+ :eval (cons 1 '(2 3 4)))
+ (list
+ :eval (list 1 2 3))
+ (number-sequence
+ :eval (number-sequence 5 8))
+ "Operations on Lists"
+ (append
+ :eval (append '("foo" "bar") '("zot")))
+ (copy-tree
+ :eval (copy-tree '(1 (2 3) 4)))
+ (flatten-tree
+ :eval (flatten-tree '(1 (2 3) 4)))
+ (car
+ :eval (car '(one two three)))
+ (cdr
+ :eval (cdr '(one two three)))
+ (last
+ :eval (last '(one two three)))
+ (butlast
+ :eval (butlast '(one two three)))
+ (nbutlast
+ :eval (nbutlast (list 'one 'two 'three)))
+ (nth
+ :eval (nth 1 '(one two three)))
+ (nthcdr
+ :eval (nthcdr 1 '(one two three)))
+ (elt
+ :eval (elt '(one two three) 1))
+ (car-safe
+ :eval (car-safe '(one two three)))
+ (cdr-safe
+ :eval (cdr-safe '(one two three)))
+ (push
+ :no-eval* (push 'a list))
+ (pop
+ :no-eval* (pop list))
+ (setcar
+ :no-eval (setcar list 'c)
+ :result c)
+ (setcdr
+ :no-eval (setcdr list (list c))
+ :result '(c))
+ (nconc
+ :eval (nconc (list 1) (list 2 3 4)))
+ (delq
+ :eval (delq 2 (list 1 2 3 4))
+ :eval (delq "a" (list "a" "b" "c" "d")))
+ (delete
+ :eval (delete 2 (list 1 2 3 4))
+ :eval (delete "a" (list "a" "b" "c" "d")))
+ (remove
+ :eval (remove 2 '(1 2 3 4))
+ :eval (remove "a" '("a" "b" "c" "d")))
+ (delete-dups
+ :eval (delete-dups (list 1 2 4 3 2 4)))
+ "Mapping Over Lists"
+ (mapcar
+ :eval (mapcar #'list '(1 2 3)))
+ (mapcan
+ :eval (mapcan #'list '(1 2 3)))
+ (mapc
+ :eval (mapc #'insert '("1" "2" "3")))
+ (reduce
+ :eval (reduce #'+ '(1 2 3)))
+ (mapconcat
+ :eval (mapconcat #'identity '("foo" "bar") "|"))
+ "Predicates"
+ (listp
+ :eval (listp '(1 2 3))
+ :eval (listp nil)
+ :eval (listp '(1 . 2)))
+ (consp
+ :eval (consp '(1 2 3))
+ :eval (consp nil))
+ (proper-list-p
+ :eval (proper-list-p '(1 2 3))
+ :eval (proper-list-p nil)
+ :eval (proper-list-p '(1 . 2)))
+ (null
+ :eval (null nil))
+ (atom
+ :eval (atom 'a))
+ (nlistp
+ :eval (nlistp '(1 2 3))
+ :eval (nlistp t)
+ :eval (nlistp '(1 . 2)))
+ "Finding Elements"
+ (memq
+ :eval (memq 2 '(1 2 3))
+ :eval (memq 2.0 '(1.0 2.0 3.0))
+ :eval (memq "b" '("a" "b" "c")))
+ (member
+ :eval (member 2 '(1 2 3))
+ :eval (member "b" '("a" "b" "c")))
+ (remq
+ :eval (remq 2 '(1 2 3 2 4 2))
+ :eval (remq "b" '("a" "b" "c")))
+ (memql
+ :eval (memql 2.0 '(1.0 2.0 3.0)))
+ (member-ignore-case
+ :eval (member-ignore-case "foo" '("bar" "Foo" "zot")))
+ "Association Lists"
+ (assoc
+ :eval (assoc 'b '((a 1) (b 2))))
+ (rassoc
+ :eval (rassoc '2 '((a . 1) (b . 2))))
+ (assq
+ :eval (assq 'b '((a 1) (b 2)))
+ :eval (assq "a" '(("a" 1) ("b" 2))))
+ (rassq
+ :eval (rassq '2 '((a . 1) (b . 2))))
+ (assoc-string
+ :eval (assoc-string "foo" '(("a" 1) (foo 2))))
+ (alist-get
+ :eval (alist-get 2 '((1 . a) (2 . b))))
+ (assoc-default
+ :eval (assoc-default 2 '((1 . a) (2 . b) #'=)))
+ (copy-alist
+ :eval (copy-alist '((1 . a) (2 . b))))
+ (assq-delete-all
+ :eval (assq-delete-all 2 (list '(1 . a) '(2 . b) '(2 . c))))
+ (assoc-delete-all
+ :eval (assoc-delete-all "b" (list '("a" . a) '("b" . b) '("b" . c))))
+ "Property Lists"
+ (plist-get
+ :eval (plist-get '(a 1 b 2 c 3) 'b))
+ (plist-put
+ :no-eval (setq plist (plist-put plist 'd 4))
+ :eq-result (a 1 b 2 c 3 d 4))
+ (lax-plist-get
+ :eval (lax-plist-get '("a" 1 "b" 2 "c" 3) "b"))
+ (lax-plist-put
+ :no-eval (setq plist (plist-put plist "d" 4))
+ :eq-result '("a" 1 "b" 2 "c" 3 "d" 4))
+ (plist-member
+ :eval (plist-member '(a 1 b 2 c 3) 'b))
+ "Data About Lists"
+ (length
+ :eval (length '(a b c)))
+ (safe-length
+ :eval (safe-length '(a b c))))
+
+
+(define-short-documentation-group vector
+ (make-vector
+ :eval (make-vector 5 "foo"))
+ (vector
+ :eval (vector 1 "b" 3))
+ (vectorp
+ :eval (vectorp [1])
+ :eval (vectorp "1"))
+ (vconcat
+ :eval (vconcat '(1 2) [3 4]))
+ (append
+ :eval (append [1 2] nil))
+ (length
+ :eval (length [1 2 3]))
+ (mapcar
+ :eval (mapcar #'identity [1 2 3]))
+ (reduce
+ :eval (reduce #'+ [1 2 3]))
+ (seq-subseq
+ :eval (seq-subseq [1 2 3 4 5] 1 3)
+ :eval (seq-subseq [1 2 3 4 5] 1)))
+
+(define-short-documentation-group regexp
+ "Matching Strings"
+ (replace-regexp-in-string
+ :eval (replace-regexp-in-string "[a-z]+" "_" "*foo*"))
+ (string-match-p
+ :eval (string-match-p "^[fo]+" "foobar"))
+ "Looking in Buffers"
+ (re-search-forward
+ :no-eval (re-search-forward "^foo$" nil t)
+ :eg-result 43)
+ (re-search-backward
+ :no-eval (re-search-backward "^foo$" nil t)
+ :eg-result 43)
+ (looking-at-p
+ :no-eval (looking-at "f[0-9]")
+ :eg-result t)
+ "Match Data"
+ (match-string
+ :eval (and (string-match "^\\([fo]+\\)b" "foobar")
+ (match-string 0 "foobar")))
+ (match-beginning
+ :no-eval (match-beginning 1)
+ :eg-result 0)
+ (match-end
+ :no-eval (match-end 1)
+ :eg-result 3)
+ (save-match-data
+ :no-eval (save-match-data ...))
+ "Replacing Match"
+ (replace-match
+ :no-eval (replace-match "new")
+ :eg-result nil)
+ (match-substitute-replacement
+ :no-eval (match-substitute-replacement "new")
+ :eg-result "new")
+ "Utilities"
+ (regexp-quote
+ :eval (regexp-quote "foo.*bar"))
+ (regexp-opt
+ :eval (regexp-opt '("foo" "bar")))
+ (regexp-opt-depth
+ :eval (regexp-opt-depth "\\(a\\(b\\)\\)"))
+ (regexp-opt-charset
+ :eval (regexp-opt-charset '(?a ?b ?c ?d ?e)))
+ "The `rx' Structured Regexp Notation"
+ (rx
+ :eval (rx "IP=" (+ digit) (= 3 "." (+ digit))))
+ (rx-to-string
+ :eval (rx-to-string '(| "foo" "bar")))
+ (rx-define
+ :no-eval "(and (rx-define haskell-comment (seq \"--\" (zero-or-more nonl)))
+ (rx haskell-comment))"
+ :result "--.*")
+ (rx-let
+ :eval "(rx-let ((comma-separated (item) (seq item (0+ \",\" item)))
+ (number (1+ digit))
+ (numbers (comma-separated number)))
+ (rx \"(\" numbers \")\"))"
+ :result "([[:digit:]]+\\(?:,[[:digit:]]+\\)*)")
+ (rx-let-eval
+ :eval "(rx-let-eval
+ '((ponder (x) (seq \"Where have all the \" x \" gone?\")))
+ (rx-to-string
+ '(ponder (or \"flowers\" \"cars\" \"socks\"))))"
+ :result "\\(?:Where have all the \\(?:\\(?:car\\|flower\\|sock\\)s\\) gone\\?\\)"))
+
+(define-short-documentation-group sequence
+ "Sequence Predicates"
+ (seq-contains-p
+ :eval (seq-contains-p '(a b c) 'b)
+ :eval (seq-contains-p '(a b c) 'd))
+ (seq-every-p
+ :eval (seq-every-p #'numberp '(1 2 3)))
+ (seq-empty-p
+ :eval (seq-empty-p []))
+ (seq-set-equal-p
+ :eval (seq-set-equal-p '(1 2 3) '(3 1 2)))
+ (seq-some
+ :eval (seq-some #'cl-evenp '(1 2 3)))
+ "Building Sequences"
+ (seq-concatenate
+ :eval (seq-concatenate 'vector '(1 2) '(c d)))
+ (seq-copy
+ :eval (seq-copy '(a 2)))
+ (seq-into
+ :eval (seq-into '(1 2 3) 'vector))
+ "Utility Functions"
+ (seq-count
+ :eval (seq-count #'numberp '(1 b c 4)))
+ (seq-elt
+ :eval (seq-elt '(a b c) 1))
+ (seq-random-elt
+ :no-eval (seq-random-elt '(a b c))
+ :eg-result c)
+ (seq-find
+ :eval (seq-find #'numberp '(a b 3 4 f 6)))
+ (seq-position
+ :eval (seq-position '(a b c) 'c))
+ (seq-length
+ :eval (seq-length "abcde"))
+ (seq-max
+ :eval (seq-max [1 2 3]))
+ (seq-min
+ :eval (seq-min [1 2 3]))
+ (seq-first
+ :eval (seq-first [a b c]))
+ (seq-rest
+ :eval (seq-rest '[1 2 3]))
+ (seq-reverse
+ :eval (seq-reverse '(1 2 3)))
+ (seq-sort
+ :eval (seq-sort #'> '(1 2 3)))
+ (seq-sort-by
+ :eval (seq-sort-by (lambda (a) (/ 1.0 a)) #'< '(1 2 3)))
+ "Mapping Over Sequences"
+ (seq-map
+ :eval (seq-map #'1+ '(1 2 3)))
+ (seq-map-indexed
+ :eval (seq-map-indexed (lambda (a i) (cons i a)) '(a b c)))
+ (seq-mapcat
+ :eval (seq-mapcat #'upcase '("a" "b" "c") 'string))
+ (seq-do
+ :no-eval (seq-do (lambda (a) (insert a)) '("foo" "bar"))
+ :eg-result ("foo" "bar"))
+ (seq-do-indexed
+ :no-eval (seq-do-indexed
+ (lambda (a index) (message "%s:%s" index a))
+ '("foo" "bar"))
+ :eg-result nil)
+ (seq-reduce
+ :eval (seq-reduce #'* [1 2 3] 2))
+ "Excerpting Sequences"
+ (seq-drop
+ :eval (seq-drop '(a b c) 2))
+ (seq-drop-while
+ :eval (seq-drop-while #'numberp '(1 2 c d 5)))
+ (seq-filter
+ :eval (seq-filter #'numberp '(a b 3 4 f 6)))
+ (seq-remove
+ :eval (seq-remove #'numberp '(1 2 c d 5)))
+ (seq-group-by
+ :eval (seq-group-by #'cl-plusp '(-1 2 3 -4 -5 6)))
+ (seq-difference
+ :eval (seq-difference '(1 2 3) '(2 3 4)))
+ (seq-intersection
+ :eval (seq-intersection '(1 2 3) '(2 3 4)))
+ (seq-partition
+ :eval (seq-partition '(a b c d e f g h) 3))
+ (seq-subseq
+ :eval (seq-subseq '(a b c d e) 2 4))
+ (seq-take
+ :eval (seq-take '(a b c d e) 3))
+ (seq-take-while
+ :eval (seq-take-while #'cl-evenp [2 4 9 6 5]))
+ (seq-uniq
+ :eval (seq-uniq '(a b d b a c))))
+
+(define-short-documentation-group buffer
+ "Buffer Basics"
+ (current-buffer
+ :no-eval (current-buffer)
+ :eg-result-string "#<buffer shortdoc.el>")
+ (bufferp
+ :eval (bufferp 23))
+ (buffer-live-p
+ :no-eval (buffer-live-p some-buffer)
+ :eg-result t)
+ (buffer-modified-p
+ :eval (buffer-modified-p (current-buffer)))
+ (buffer-name
+ :eval (buffer-name))
+ (window-buffer
+ :eval (window-buffer))
+ "Selecting Buffers"
+ (get-buffer-create
+ :no-eval (get-buffer-create "*foo*")
+ :eg-result-string "#<buffer *foo*>")
+ (pop-to-buffer
+ :no-eval (pop-to-buffer "*foo*")
+ :eg-result-string "#<buffer *foo*>")
+ (with-current-buffer
+ :no-eval* (with-current-buffer buffer (buffer-size)))
+ "Points and Positions"
+ (point
+ :eval (point))
+ (point-min
+ :eval (point-max))
+ (point-max
+ :eval (point-max))
+ (line-beginning-position
+ :eval (line-beginning-position))
+ (line-end-position
+ :eval (line-end-position))
+ (buffer-size
+ :eval (buffer-size))
+ "Moving Around"
+ (goto-char
+ :no-eval (goto-char (point-max))
+ :eg-result 342)
+ (search-forward
+ :no-eval (search-forward "some-string" nil t)
+ :eg-result 245)
+ (re-search-forward
+ :no-eval (re-search-forward "some-s.*g" nil t)
+ :eg-result 245)
+ (forward-line
+ :no-eval (forward-line 1)
+ :eg-result 0
+ :no-eval (forward-line -2)
+ :eg-result 0)
+ "Strings from Buffers"
+ (buffer-string
+ :no-eval* (buffer-string))
+ (buffer-substring
+ :eval (buffer-substring (point-min) (+ (point-min) 10)))
+ (buffer-substring-no-properties
+ :eval (buffer-substring-no-properties (point-min) (+ (point-min) 10)))
+ (following-char
+ :no-eval (following-char)
+ :eg-result 67)
+ (char-after
+ :eval (char-after 45))
+ "Altering Buffers"
+ (delete-region
+ :no-value (delete-region (point-min) (point-max)))
+ (erase-buffer
+ :no-value (erase-buffer))
+ (insert
+ :no-value (insert "This string will be inserted in the buffer\n"))
+ "Locking"
+ (lock-buffer
+ :no-value (lock-buffer "/tmp/foo"))
+ (unlock-buffer
+ :no-value (lock-buffer)))
+
+(define-short-documentation-group process
+ (make-process
+ :no-eval (make-process :name "foo" :command '("cat" "/tmp/foo"))
+ :eg-result-string "#<process foo>")
+ (processp
+ :eval (processp t))
+ (delete-process
+ :no-value (delete-process process))
+ (kill-process
+ :no-value (kill-process process))
+ (set-process-sentinel
+ :no-value (set-process-sentinel process (lambda (proc string))))
+ (process-buffer
+ :no-eval (process-buffer process)
+ :eg-result-string "#<buffer *foo*>")
+ (get-buffer-process
+ :no-eval (get-buffer-process buffer)
+ :eg-result-string "#<process foo>")
+ (process-live-p
+ :no-eval (process-live-p process)
+ :eg-result t))
+
+(define-short-documentation-group number
+ "Arithmetic"
+ (+
+ :args (&rest numbers)
+ :eval (+ 1 2)
+ :eval (+ 1 2 3 4))
+ (-
+ :args (&rest numbers)
+ :eval (- 3 2)
+ :eval (- 6 3 2))
+ (*
+ :args (&rest numbers)
+ :eval (* 3 4 5))
+ (/
+ :eval (/ 10 5)
+ :eval (/ 10 6)
+ :eval (/ 10.0 6)
+ :eval (/ 10.0 3 3))
+ (%
+ :eval (% 10 5)
+ :eval (% 10 6))
+ (mod
+ :eval (mod 10 5)
+ :eval (mod 10 6)
+ :eval (mod 10.5 6))
+ (1+
+ :eval (1+ 2))
+ (1-
+ :eval (1- 4))
+ "Predicates"
+ (=
+ :args (number &rest numbers)
+ :eval (= 4 4)
+ :eval (= 4.0 4.0)
+ :eval (= 4 5 6 7))
+ (eq
+ :eval (eq 4 4)
+ :eval (eq 4.0 4.0))
+ (eql
+ :eval (eql 4 4)
+ :eval (eql 4 "4")
+ :eval (eql 4.0 4.0))
+ (/=
+ :eval (/= 4 4))
+ (<
+ :args (number &rest numbers)
+ :eval (< 4 4)
+ :eval (< 1 2 3))
+ (<=
+ :args (number &rest numbers)
+ :eval (<= 4 4)
+ :eval (<= 1 2 3))
+ (>
+ :args (number &rest numbers)
+ :eval (> 4 4)
+ :eval (> 1 2 3))
+ (>=
+ :args (number &rest numbers)
+ :eval (>= 4 4)
+ :eval (>= 1 2 3))
+ (zerop
+ :eval (zerop 0))
+ (cl-plusp
+ :eval (cl-plusp 0)
+ :eval (cl-plusp 1))
+ (cl-minusp
+ :eval (cl-minusp 0)
+ :eval (cl-minusp -1))
+ (cl-oddp
+ :eval (cl-oddp 3))
+ (cl-evenp
+ :eval (cl-evenp 6))
+ (natnump
+ :eval (natnump -1)
+ :eval (natnump 23))
+ (bignump
+ :eval (bignump 4)
+ :eval (bignump (expt 2 90)))
+ (fixnump
+ :eval (fixnump 4)
+ :eval (fixnump (expt 2 90)))
+ (floatp
+ :eval (floatp 5.4))
+ (integerp
+ :eval (integerp 5.4))
+ (numberp
+ :eval (numberp "5.4"))
+ (cl-digit-char-p
+ :eval (cl-digit-char-p ?5 10)
+ :eval (cl-digit-char-p ?f 16))
+ "Operations"
+ (max
+ :args (number &rest numbers)
+ :eval (max 7 9 3))
+ (min
+ :args (number &rest numbers)
+ :eval (min 7 9 3))
+ (abs
+ :eval (abs -4))
+ (float
+ :eval (float 2))
+ (truncate
+ :eval (truncate 1.2)
+ :eval (truncate -1.2)
+ :eval (truncate 5.4 2))
+ (floor
+ :eval (floor 1.2)
+ :eval (floor -1.2)
+ :eval (floor 5.4 2))
+ (ceiling
+ :eval (ceiling 1.2)
+ :eval (ceiling -1.2)
+ :eval (ceiling 5.4 2))
+ (round
+ :eval (round 1.2)
+ :eval (round -1.2)
+ :eval (round 5.4 2))
+ (random
+ :eval (random 6))
+ "Bit Operations"
+ (ash
+ :eval (ash 1 4)
+ :eval (ash 16 -1))
+ (lsh
+ :eval (lsh 1 4)
+ :eval (lsh 16 -1))
+ (logand
+ :no-eval "(logand #b10 #b111)"
+ :result-string "#b10")
+ (logior
+ :eval (logior 4 16))
+ (logxor
+ :eval (logxor 4 16))
+ (lognot
+ :eval (lognot 5))
+ (logcount
+ :eval (logcount 5))
+ "Floating Point"
+ (isnan
+ :eval (isnan 5.0))
+ (frexp
+ :eval (frexp 5.7))
+ (ldexp
+ :eval (ldexp 0.7125 3))
+ (logb
+ :eval (logb 10.5))
+ (ffloor
+ :eval (floor 1.2))
+ (fceiling
+ :eval (fceiling 1.2))
+ (ftruncate
+ :eval (ftruncate 1.2))
+ (fround
+ :eval (fround 1.2))
+ "Standard Math Functions"
+ (sin
+ :eval (sin float-pi))
+ (cos
+ :eval (cos float-pi))
+ (tan
+ :eval (tan float-pi))
+ (asin
+ :eval (asin float-pi))
+ (acos
+ :eval (acos float-pi))
+ (atan
+ :eval (atan float-pi))
+ (exp
+ :eval (exp 4))
+ (log
+ :eval (log 54.59))
+ (expt
+ :eval (expt 2 16))
+ (sqrt
+ :eval (sqrt -1)))
+
+;;;###autoload
+(defun shortdoc-display-group (group)
+ "Pop to a buffer with short documentation summary for functions in GROUP."
+ (interactive (list (completing-read "Show summary for functions in: "
+ (mapcar #'car shortdoc--groups))))
+ (when (stringp group)
+ (setq group (intern group)))
+ (unless (assq group shortdoc--groups)
+ (error "No such documentation group %s" group))
+ (pop-to-buffer (format "*Shortdoc %s*" group))
+ (let ((inhibit-read-only t)
+ (prev nil))
+ (erase-buffer)
+ (shortdoc-mode)
+ (button-mode)
+ (mapc
+ (lambda (data)
+ (cond
+ ((stringp data)
+ (setq prev nil)
+ (unless (bobp)
+ (insert "\n"))
+ (insert (propertize
+ (concat (substitute-command-keys data) "\n\n")
+ 'face '(variable-pitch (:height 1.3 :weight bold))
+ 'shortdoc-section t)))
+ ;; There may be functions not yet defined in the data.
+ ((fboundp (car data))
+ (when prev
+ (insert (propertize "\n" 'face 'shortdoc-separator)))
+ (setq prev t)
+ (shortdoc--display-function data))))
+ (cdr (assq group shortdoc--groups))))
+ (goto-char (point-min)))
+
+(defun shortdoc--display-function (data)
+ (let ((function (pop data))
+ (start-section (point))
+ arglist-start)
+ ;; Function calling convention.
+ (insert (propertize "("
+ 'shortdoc-function t))
+ (if (plist-get data :no-manual)
+ (insert (symbol-name function))
+ (insert-text-button
+ (symbol-name function)
+ 'face 'button
+ 'action (lambda (_)
+ (info-lookup-symbol function 'emacs-lisp-mode))))
+ (setq arglist-start (point))
+ (insert ")\n")
+ ;; Doc string.
+ (insert " "
+ (or (plist-get data :doc)
+ (car (split-string (documentation function) "\n"))))
+ (insert "\n")
+ (add-face-text-property start-section (point) 'shortdoc-section t)
+ (let ((print-escape-newlines t)
+ (double-arrow (if (char-displayable-p ?⇒)
+ "⇒"
+ "=>"))
+ (single-arrow (if (char-displayable-p ?→)
+ "→"
+ "->")))
+ (cl-loop for (type value) on data by #'cddr
+ do
+ (cl-case type
+ (:eval
+ (if (stringp value)
+ (insert " " value "\n")
+ (insert " ")
+ (prin1 value (current-buffer))
+ (insert "\n")
+ (insert " " double-arrow " ")
+ (prin1 (eval value) (current-buffer))
+ (insert "\n")))
+ (:no-eval*
+ (if (stringp value)
+ (insert " " value "\n")
+ (insert " ")
+ (prin1 value (current-buffer)))
+ (insert "\n " single-arrow " "
+ (propertize "[it depends]"
+ 'face 'variable-pitch)
+ "\n"))
+ (:no-value
+ (if (stringp value)
+ (insert " " value)
+ (insert " ")
+ (prin1 value (current-buffer)))
+ (insert "\n"))
+ (:no-eval
+ (if (stringp value)
+ (insert " " value)
+ (insert " ")
+ (prin1 value (current-buffer)))
+ (insert "\n"))
+ (:result
+ (insert " " double-arrow " ")
+ (prin1 value (current-buffer))
+ (insert "\n"))
+ (:result-string
+ (insert " " double-arrow " ")
+ (princ value (current-buffer))
+ (insert "\n"))
+ (:eg-result
+ (insert " eg. " double-arrow " ")
+ (prin1 value (current-buffer))
+ (insert "\n"))
+ (:eg-result-string
+ (insert " eg. " double-arrow " ")
+ (princ value (current-buffer))
+ (insert "\n")))))
+ ;; Insert the arglist after doing the evals, in case that's pulled
+ ;; in the function definition.
+ (save-excursion
+ (goto-char arglist-start)
+ (dolist (param (or (plist-get data :args)
+ (help-function-arglist function t)))
+ (insert " " (symbol-name param)))
+ (add-face-text-property arglist-start (point) 'shortdoc-section t))))
+
+(defun shortdoc-function-groups (function)
+ "Return all shortdoc groups FUNCTION appears in."
+ (cl-loop for group in shortdoc--groups
+ when (assq function (cdr group))
+ collect (car group)))
+
+(defun shortdoc-add-function (group section elem)
+ "Add ELEM to shortdoc GROUP in SECTION.
+If GROUP doesn't exist, it will be created.
+If SECTION doesn't exist, it will be added.
+
+Example:
+
+ (shortdoc-add-function
+ 'file \"Predicates\"
+ '(file-locked-p :no-eval (file-locked-p \"/tmp\")))"
+ (let ((glist (assq group shortdoc--groups)))
+ (unless glist
+ (setq glist (list group))
+ (setq shortdoc--groups (append shortdoc--groups (list glist))))
+ (let ((slist (member section glist)))
+ (unless slist
+ (setq slist (list section))
+ (setq slist (append glist slist)))
+ (while (and (cdr slist)
+ (not (stringp (cadr slist))))
+ (setq slist (cdr slist)))
+ (setcdr slist (cons elem (cdr slist))))))
+
+(defvar shortdoc-mode-map
+ (let ((map (make-sparse-keymap)))
+ (define-key map (kbd "n") 'shortdoc-next)
+ (define-key map (kbd "p") 'shortdoc-previous)
+ (define-key map (kbd "C-c C-n") 'shortdoc-next-section)
+ (define-key map (kbd "C-c C-p") 'shortdoc-previous-section)
+ map)
+ "Keymap for `shortdoc-mode'")
+
+(define-derived-mode shortdoc-mode special-mode "shortdoc"
+ "Mode for shortdoc.")
+
+(defmacro shortdoc--goto-section (arg sym &optional reverse)
+ `(progn
+ (unless (natnump ,arg)
+ (setq ,arg 1))
+ (while (< 0 ,arg)
+ (,(if reverse
+ 'text-property-search-backward
+ 'text-property-search-forward)
+ ,sym t)
+ (setq ,arg (1- ,arg)))))
+
+(defun shortdoc-next (&optional arg)
+ "Move cursor to next function."
+ (interactive "p")
+ (shortdoc--goto-section arg 'shortdoc-function))
+
+(defun shortdoc-previous (&optional arg)
+ "Move cursor to previous function."
+ (interactive "p")
+ (shortdoc--goto-section arg 'shortdoc-function t)
+ (backward-char 1))
+
+(defun shortdoc-next-section (&optional arg)
+ "Move cursor to next section."
+ (interactive "p")
+ (shortdoc--goto-section arg 'shortdoc-section))
+
+(defun shortdoc-previous-section (&optional arg)
+ "Move cursor to previous section."
+ (interactive "p")
+ (shortdoc--goto-section arg 'shortdoc-section t)
+ (forward-line -2))
+
+(provide 'shortdoc)
+
+;;; shortdoc.el ends here
diff --git a/lisp/emacs-lisp/smie.el b/lisp/emacs-lisp/smie.el
index 1b700afd12d..355dd0f49e8 100644
--- a/lisp/emacs-lisp/smie.el
+++ b/lisp/emacs-lisp/smie.el
@@ -1891,9 +1891,9 @@ KEYWORDS are additional arguments, which can use the following keywords:
(v (pop keywords)))
(pcase k
(:forward-token
- (set (make-local-variable 'smie-forward-token-function) v))
+ (setq-local smie-forward-token-function v))
(:backward-token
- (set (make-local-variable 'smie-backward-token-function) v))
+ (setq-local smie-backward-token-function v))
(_ (message "smie-setup: ignoring unknown keyword %s" k)))))
(let ((ca (cdr (assq :smie-closer-alist grammar))))
(when ca
diff --git a/lisp/emacs-lisp/syntax.el b/lisp/emacs-lisp/syntax.el
index 62f1b16d75c..e35f9d89ded 100644
--- a/lisp/emacs-lisp/syntax.el
+++ b/lisp/emacs-lisp/syntax.el
@@ -353,7 +353,7 @@ set by `syntax-propertize'")
(setq syntax-propertize--done (max (point-max) pos))
;; (message "Needs to syntax-propertize from %s to %s"
;; syntax-propertize--done pos)
- (set (make-local-variable 'parse-sexp-lookup-properties) t)
+ (setq-local parse-sexp-lookup-properties t)
(when (< syntax-propertize--done (point-min))
;; *Usually* syntax-propertize is called via syntax-ppss which
;; takes care of adding syntax-ppss-flush-cache to b-c-f, but this
diff --git a/lisp/emacs-lisp/tabulated-list.el b/lisp/emacs-lisp/tabulated-list.el
index b13f609f882..ae3ed055c5d 100644
--- a/lisp/emacs-lisp/tabulated-list.el
+++ b/lisp/emacs-lisp/tabulated-list.el
@@ -269,42 +269,48 @@ Populated by `tabulated-list-init-header'.")
;; FIXME: Should share code with tabulated-list-print-col!
(let ((x (max tabulated-list-padding 0))
(button-props `(help-echo "Click to sort by column"
- mouse-face header-line-highlight
- keymap ,tabulated-list-sort-button-map))
+ mouse-face header-line-highlight
+ keymap ,tabulated-list-sort-button-map))
+ (len (length tabulated-list-format))
(cols nil))
(if display-line-numbers
(setq x (+ x (tabulated-list-line-number-width))))
(push (propertize " " 'display `(space :align-to ,x)) cols)
- (dotimes (n (length tabulated-list-format))
+ (dotimes (n len)
(let* ((col (aref tabulated-list-format n))
+ (not-last-col (< n (1- len)))
(label (nth 0 col))
+ (lablen (length label))
+ (pname label)
(width (nth 1 col))
(props (nthcdr 3 col))
(pad-right (or (plist-get props :pad-right) 1))
(right-align (plist-get props :right-align))
(next-x (+ x pad-right width)))
+ (when (and (>= lablen 3) (> lablen width) not-last-col)
+ (setq label (truncate-string-to-width label (- lablen 1) nil nil t)))
(push
(cond
;; An unsortable column
((not (nth 2 col))
- (propertize label 'tabulated-list-column-name label))
+ (propertize label 'tabulated-list-column-name pname))
;; The selected sort column
((equal (car col) (car tabulated-list-sort-key))
(apply 'propertize
- (concat label
- (cond
- ((> (+ 2 (length label)) width) "")
- ((cdr tabulated-list-sort-key)
+ (concat label
+ (cond
+ ((and (< lablen 3) not-last-col) "")
+ ((cdr tabulated-list-sort-key)
(format " %c"
tabulated-list-gui-sort-indicator-desc))
- (t (format " %c"
+ (t (format " %c"
tabulated-list-gui-sort-indicator-asc))))
- 'face 'bold
- 'tabulated-list-column-name label
- button-props))
+ 'face 'bold
+ 'tabulated-list-column-name pname
+ button-props))
;; Unselected sortable column.
(t (apply 'propertize label
- 'tabulated-list-column-name label
+ 'tabulated-list-column-name pname
button-props)))
cols)
(when right-align
@@ -761,6 +767,7 @@ as the ewoc pretty-printer."
(setq-local revert-buffer-function #'tabulated-list-revert)
(setq-local glyphless-char-display
(tabulated-list-make-glyphless-char-display-table))
+ (setq-local text-scale-remap-header-line t)
;; Avoid messing up the entries' display just because the first
;; column of the first entry happens to begin with a R2L letter.
(setq bidi-paragraph-direction 'left-to-right)
diff --git a/lisp/emacs-lisp/text-property-search.el b/lisp/emacs-lisp/text-property-search.el
index 61bd98d3cfe..d7dc7da7c18 100644
--- a/lisp/emacs-lisp/text-property-search.el
+++ b/lisp/emacs-lisp/text-property-search.el
@@ -34,11 +34,11 @@
"Search for the next region of text whose PROPERTY matches VALUE.
If not found, return nil and don't move point.
-If found, move point to end of the region and return a `prop-match'
-object describing the match. To access the details of the match,
-use `prop-match-beginning' and `prop-match-end' for the buffer
-positions that limit the region, and `prop-match-value' for the
-value of PROPERTY in the region.
+If found, move point to the start of the region and return a
+`prop-match' object describing the match. To access the details
+of the match, use `prop-match-beginning' and `prop-match-end' for
+the buffer positions that limit the region, and
+`prop-match-value' for the value of PROPERTY in the region.
PREDICATE is used to decide whether a value of PROPERTY should be
considered as matching VALUE.
@@ -125,7 +125,7 @@ that matches VALUE."
"Search for the previous region of text whose PROPERTY matches VALUE.
Like `text-property-search-forward', which see, but searches backward,
-and if a matching region is found, moves point to its beginning."
+and if a matching region is found, place point at its end."
(interactive
(list
(let ((string (completing-read "Search for property: " obarray)))
diff --git a/lisp/emacs-lisp/thunk.el b/lisp/emacs-lisp/thunk.el
index c8e483e9a4a..cd42152527e 100644
--- a/lisp/emacs-lisp/thunk.el
+++ b/lisp/emacs-lisp/thunk.el
@@ -122,7 +122,7 @@ Using `thunk-let' and `thunk-let*' requires `lexical-binding'."
(declare (indent 1) (debug let))
(cl-reduce
(lambda (expr binding) `(thunk-let (,binding) ,expr))
- (nreverse bindings)
+ (reverse bindings)
:initial-value (macroexp-progn body)))
;; (defalias 'lazy-let #'thunk-let)
diff --git a/lisp/emacs-lisp/timer-list.el b/lisp/emacs-lisp/timer-list.el
index 00d09696d2a..024f0030629 100644
--- a/lisp/emacs-lisp/timer-list.el
+++ b/lisp/emacs-lisp/timer-list.el
@@ -49,23 +49,25 @@
(let ((time (list (aref timer 1)
(aref timer 2)
(aref timer 3))))
- (format "%10.2f"
- (float-time
- (if (aref timer 7)
- time
- (time-subtract time nil)))))
- 'help-echo "Time in sec till next invocation")
+ (format "%12s"
+ (format-seconds "%dd %hh %mm %z%,1ss"
+ (float-time
+ (if (aref timer 7)
+ time
+ (time-subtract time nil))))))
+ 'help-echo "Time until next invocation")
;; Repeat.
- ,(propertize
- (let ((repeat (aref timer 4)))
- (cond
- ((numberp repeat)
- (format "%8.1f" repeat))
- ((null repeat)
- " -")
- (t
- (format "%8s" repeat))))
- 'help-echo "Symbol: repeat; number: repeat interval in sec")
+ ,(let ((repeat (aref timer 4)))
+ (cond
+ ((numberp repeat)
+ (propertize
+ (format "%12s" (format-seconds
+ "%dd %hh %mm %z%,1ss" repeat))
+ 'help-echo "Repeat interval"))
+ ((null repeat)
+ (propertize " -" 'help-echo "Runs once"))
+ (t
+ (format "%12s" repeat))))
;; Function.
,(propertize
(let ((cl-print-compiled 'static)
@@ -93,8 +95,8 @@
(setq-local revert-buffer-function #'list-timers)
(setq tabulated-list-format
'[("Idle" 6 timer-list--idle-predicate)
- (" Next" 12 timer-list--next-predicate)
- (" Repeat" 11 timer-list--repeat-predicate)
+ ("Next" 12 timer-list--next-predicate :right-align t :pad-right 1)
+ ("Repeat" 12 timer-list--repeat-predicate :right-align t :pad-right 1)
("Function" 10 timer-list--function-predicate)]))
(defun timer-list--idle-predicate (A B)
@@ -119,7 +121,7 @@
(string< rA rB)))
(defun timer-list--function-predicate (A B)
- "Predicate to sort Timer-List by the Next column."
+ "Predicate to sort Timer-List by the Function column."
(let ((fA (aref (cadr A) 3))
(fB (aref (cadr B) 3)))
(string< fA fB)))
diff --git a/lisp/emacs-lisp/trace.el b/lisp/emacs-lisp/trace.el
index 627305689c7..28e964ec4c2 100644
--- a/lisp/emacs-lisp/trace.el
+++ b/lisp/emacs-lisp/trace.el
@@ -225,7 +225,7 @@ be printed along with the arguments in the trace."
(ctx (funcall context)))
(unless inhibit-trace
(with-current-buffer trace-buffer
- (set (make-local-variable 'window-point-insertion-type) t)
+ (setq-local window-point-insertion-type t)
(unless background (trace--display-buffer trace-buffer))
(goto-char (point-max))
;; Insert a separator from previous trace output:
diff --git a/lisp/emacs-lisp/unsafep.el b/lisp/emacs-lisp/unsafep.el
index e7077140e54..c4db86a0db3 100644
--- a/lisp/emacs-lisp/unsafep.el
+++ b/lisp/emacs-lisp/unsafep.el
@@ -91,17 +91,41 @@
in the parse.")
(put 'unsafep-vars 'risky-local-variable t)
-;;Other safe functions
+;; Other safe forms.
+;;
+;; A function, macro or special form may be put here only if all of
+;; the following statements are true:
+;;
+;; * It is not already marked `pure' or `side-effect-free', or handled
+;; explicitly by `unsafep'.
+;;
+;; * It is not inherently unsafe; eg, would allow the execution of
+;; arbitrary code, interact with the file system, network or other
+;; processes, or otherwise exfiltrate information from the running
+;; Emacs process or manipulate the user's environment.
+;;
+;; * It does not have side-effects that can make other code behave in
+;; unsafe and/or unexpected ways; eg, set variables, mutate data, or
+;; change control flow.
+;; Any side effect must be innocuous; altering the match data is
+;; explicitly permitted.
+;;
+;; * It does not allow Emacs to behave deceptively to the user; eg,
+;; display arbitrary messages.
+;;
+;; * It does not present a potentially large attack surface; eg,
+;; play arbitrary audio files.
+
(dolist (x '(;;Special forms
- and catch if or prog1 prog2 progn while unwind-protect
+ and if or prog1 prog2 progn while unwind-protect
;;Safe subrs that have some side-effects
- ding error random signal sleep-for string-match throw
+ ding random sleep-for string-match
;;Defsubst functions from subr.el
caar cadr cdar cddr
;;Macros from subr.el
save-match-data unless when
;;Functions from subr.el that have side effects
- split-string replace-regexp-in-string play-sound-file))
+ split-string))
(put x 'safe-function t))
;;;###autoload
diff --git a/lisp/emacs-lisp/warnings.el b/lisp/emacs-lisp/warnings.el
index e10c149d89c..f525ea433ad 100644
--- a/lisp/emacs-lisp/warnings.el
+++ b/lisp/emacs-lisp/warnings.el
@@ -294,7 +294,7 @@ entirely by setting `warning-suppress-types' or
message)
;; Don't output the buttons when doing batch compilation
;; and similar.
- (unless noninteractive
+ (unless (or noninteractive (eq type 'bytecomp))
(insert " ")
(insert-button "Disable showing"
'type 'warning-suppress-warning