summaryrefslogtreecommitdiff
path: root/lisp
diff options
context:
space:
mode:
Diffstat (limited to 'lisp')
-rw-r--r--lisp/allout-widgets.el3
-rw-r--r--lisp/ansi-color.el3
-rw-r--r--lisp/autoinsert.el10
-rw-r--r--lisp/cedet/ede/detect.el5
-rw-r--r--lisp/cedet/pulse.el4
-rw-r--r--lisp/cedet/semantic.el5
-rw-r--r--lisp/cedet/semantic/analyze.el14
-rw-r--r--lisp/cedet/semantic/analyze/refs.el3
-rw-r--r--lisp/cedet/semantic/lex.el7
-rw-r--r--lisp/cedet/semantic/symref/filter.el2
-rw-r--r--lisp/cedet/srecode/dictionary.el3
-rw-r--r--lisp/cedet/srecode/map.el3
-rw-r--r--lisp/desktop.el3
-rw-r--r--lisp/dired-aux.el20
-rw-r--r--lisp/dired.el6
-rw-r--r--lisp/electric.el27
-rw-r--r--lisp/emacs-lisp/benchmark.el8
-rw-r--r--lisp/emacs-lisp/byte-opt.el5
-rw-r--r--lisp/emacs-lisp/checkdoc.el132
-rw-r--r--lisp/emacs-lisp/debug.el24
-rw-r--r--lisp/emacs-lisp/easy-mmode.el2
-rw-r--r--lisp/emacs-lisp/edebug.el154
-rw-r--r--lisp/emacs-lisp/eieio-base.el2
-rw-r--r--lisp/emacs-lisp/eieio.el30
-rw-r--r--lisp/emacs-lisp/elp.el7
-rw-r--r--lisp/emacs-lisp/gv.el4
-rw-r--r--lisp/emacs-lisp/testcover.el713
-rw-r--r--lisp/epa.el2
-rw-r--r--lisp/erc/erc.el6
-rw-r--r--lisp/files.el53
-rw-r--r--lisp/gnus/gnus-agent.el6
-rw-r--r--lisp/gnus/gnus-art.el3
-rw-r--r--lisp/gnus/gnus-cloud.el4
-rw-r--r--lisp/gnus/gnus-group.el2
-rw-r--r--lisp/gnus/gnus-html.el6
-rw-r--r--lisp/gnus/gnus-score.el10
-rw-r--r--lisp/gnus/gnus-srvr.el6
-rw-r--r--lisp/gnus/gnus.el4
-rw-r--r--lisp/gnus/message.el2
-rw-r--r--lisp/gnus/nndiary.el2
-rw-r--r--lisp/gnus/nnmail.el2
-rw-r--r--lisp/gnus/nnmaildir.el2
-rw-r--r--lisp/gnus/score-mode.el2
-rw-r--r--lisp/help-fns.el32
-rw-r--r--lisp/ibuf-ext.el13
-rw-r--r--lisp/ibuf-macs.el16
-rw-r--r--lisp/ibuffer.el1
-rw-r--r--lisp/image/gravatar.el6
-rw-r--r--lisp/ldefs-boot.el121
-rw-r--r--lisp/mpc.el30
-rw-r--r--lisp/net/newst-backend.el4
-rw-r--r--lisp/net/trampver.el6
-rw-r--r--lisp/newcomment.el2
-rw-r--r--lisp/nxml/rng-maint.el5
-rw-r--r--lisp/org/org-agenda.el2
-rw-r--r--lisp/org/org-clock.el12
-rw-r--r--lisp/org/org-colview.el8
-rw-r--r--lisp/org/org-element.el4
-rw-r--r--lisp/org/org-habit.el4
-rw-r--r--lisp/org/org-indent.el4
-rw-r--r--lisp/org/org-timer.el14
-rw-r--r--lisp/org/org.el22
-rw-r--r--lisp/org/ox.el2
-rw-r--r--lisp/progmodes/cperl-mode.el2
-rw-r--r--lisp/progmodes/idlwave.el2
-rw-r--r--lisp/register.el7
-rw-r--r--lisp/subr.el4
-rw-r--r--lisp/svg.el16
-rw-r--r--lisp/term/xterm.el35
-rw-r--r--lisp/textmodes/css-mode.el2
-rw-r--r--lisp/textmodes/page-ext.el73
-rw-r--r--lisp/textmodes/reftex-ref.el2
-rw-r--r--lisp/textmodes/rst.el47
-rw-r--r--lisp/thingatpt.el30
-rw-r--r--lisp/time.el2
-rw-r--r--lisp/tooltip.el15
-rw-r--r--lisp/type-break.el8
-rw-r--r--lisp/url/url-cache.el2
-rw-r--r--lisp/url/url-cookie.el49
-rw-r--r--lisp/url/url.el3
-rw-r--r--lisp/xdg.el103
81 files changed, 1151 insertions, 870 deletions
diff --git a/lisp/allout-widgets.el b/lisp/allout-widgets.el
index 4338181c340..9fa927ddcb3 100644
--- a/lisp/allout-widgets.el
+++ b/lisp/allout-widgets.el
@@ -768,8 +768,7 @@ Optional RECURSING is for internal use, to limit recursion."
(if allout-widgets-time-decoration-activity
(setq allout-widgets-last-decoration-timing
- (list (allout-elapsed-time-seconds (current-time)
- start-time)
+ (list (allout-elapsed-time-seconds nil start-time)
allout-widgets-changes-record)))
(setq allout-widgets-changes-record nil)
diff --git a/lisp/ansi-color.el b/lisp/ansi-color.el
index 34e1daebb01..71b79223429 100644
--- a/lisp/ansi-color.el
+++ b/lisp/ansi-color.el
@@ -182,7 +182,7 @@ in shell buffers. You set this variable by calling one of:
:group 'ansi-colors
:version "23.2")
-(defvar ansi-color-apply-face-function 'ansi-color-apply-overlay-face
+(defvar ansi-color-apply-face-function #'ansi-color-apply-overlay-face
"Function for applying an Ansi Color face to text in a buffer.
This function should accept three arguments: BEG, END, and FACE,
and it should apply face FACE to the text between BEG and END.")
@@ -480,6 +480,7 @@ Emacs requires OBJECT to be a buffer."
;; In order to avoid this, we use the `insert-behind-hooks' overlay
;; property to make sure it works.
(let ((overlay (make-overlay from to object)))
+ (overlay-put overlay 'evaporate t)
(overlay-put overlay 'modification-hooks '(ansi-color-freeze-overlay))
(overlay-put overlay 'insert-behind-hooks '(ansi-color-freeze-overlay))
overlay)))
diff --git a/lisp/autoinsert.el b/lisp/autoinsert.el
index 2820c8a9afa..a43e068a4dc 100644
--- a/lisp/autoinsert.el
+++ b/lisp/autoinsert.el
@@ -141,14 +141,14 @@ If this contains a %s, that will be replaced by the matching rule."
"
.\\\" You may distribute this file under the terms of the GNU Free
.\\\" Documentation License.
-.TH " (file-name-base)
+.TH " (file-name-base (buffer-file-name))
" " (file-name-extension (buffer-file-name))
" " (format-time-string "%Y-%m-%d ")
"\n.SH NAME\n"
- (file-name-base)
+ (file-name-base (buffer-file-name))
" \\- " str
"\n.SH SYNOPSIS
-.B " (file-name-base)
+.B " (file-name-base (buffer-file-name))
"\n"
_
"
@@ -211,7 +211,7 @@ If this contains a %s, that will be replaced by the matching rule."
\(provide '"
- (file-name-base)
+ (file-name-base (buffer-file-name))
")
\;;; " (file-name-nondirectory (buffer-file-name)) " ends here\n")
(("\\.texi\\(nfo\\)?\\'" . "Texinfo file skeleton")
@@ -219,7 +219,7 @@ If this contains a %s, that will be replaced by the matching rule."
"\\input texinfo @c -*-texinfo-*-
@c %**start of header
@setfilename "
- (file-name-base) ".info\n"
+ (file-name-base (buffer-file-name)) ".info\n"
"@settitle " str "
@c %**end of header
@copying\n"
diff --git a/lisp/cedet/ede/detect.el b/lisp/cedet/ede/detect.el
index 6240d465982..25426dfeba6 100644
--- a/lisp/cedet/ede/detect.el
+++ b/lisp/cedet/ede/detect.el
@@ -195,11 +195,10 @@ Return a cons cell:
"Run a quick test for autodetecting on BUFFER."
(interactive)
(let ((start (current-time))
- (ans (ede-detect-directory-for-project default-directory))
- (end (current-time)))
+ (ans (ede-detect-directory-for-project default-directory)))
(if ans
(message "Project found in %d sec @ %s of type %s"
- (float-time (time-subtract end start))
+ (float-time (time-subtract nil start))
(car ans)
(eieio-object-name-string (cdr ans)))
(message "No Project found.") )))
diff --git a/lisp/cedet/pulse.el b/lisp/cedet/pulse.el
index 51df5e9ffe4..3554ee242b8 100644
--- a/lisp/cedet/pulse.el
+++ b/lisp/cedet/pulse.el
@@ -196,11 +196,11 @@ Optional argument FACE specifies the face to do the highlighting."
(pulse-reset-face face)
(setq pulse-momentary-timer
(run-with-timer 0 pulse-delay #'pulse-tick
- (time-add (current-time)
+ (time-add nil
(* pulse-delay pulse-iterations)))))))
(defun pulse-tick (stop-time)
- (if (time-less-p (current-time) stop-time)
+ (if (time-less-p nil stop-time)
(pulse-lighten-highlight)
(pulse-momentary-unhighlight)))
diff --git a/lisp/cedet/semantic.el b/lisp/cedet/semantic.el
index 682ac89978f..cae6e049f44 100644
--- a/lisp/cedet/semantic.el
+++ b/lisp/cedet/semantic.el
@@ -389,10 +389,9 @@ the output buffer."
(if clear (semantic-clear-toplevel-cache))
(if (eq clear '-) (setq clear -1))
(let* ((start (current-time))
- (out (semantic-fetch-tags))
- (end (current-time)))
+ (out (semantic-fetch-tags)))
(message "Retrieving tags took %.2f seconds."
- (semantic-elapsed-time start end))
+ (semantic-elapsed-time start nil))
(when (or (null clear) (not (listp clear))
(and (numberp clear) (< 0 clear)))
(pop-to-buffer "*Parser Output*")
diff --git a/lisp/cedet/semantic/analyze.el b/lisp/cedet/semantic/analyze.el
index 517e1be8eca..b528487887a 100644
--- a/lisp/cedet/semantic/analyze.el
+++ b/lisp/cedet/semantic/analyze.el
@@ -440,12 +440,11 @@ to provide a large number of non-cached analysis for filtering symbols."
(defun semantic-analyze-current-symbol-default (analyzehookfcn position)
"Call ANALYZEHOOKFCN on the analyzed symbol at POSITION."
(let* ((semantic-analyze-error-stack nil)
- (LLstart (current-time))
+ ;; (LLstart (current-time))
(prefixandbounds (semantic-ctxt-current-symbol-and-bounds (or position (point))))
(prefix (car prefixandbounds))
(bounds (nth 2 prefixandbounds))
(scope (semantic-calculate-scope position))
- (end nil)
)
;; Only do work if we have bounds (meaning a prefix to complete)
(when bounds
@@ -464,15 +463,13 @@ to provide a large number of non-cached analysis for filtering symbols."
prefix scope 'prefixtypes))
(error (semantic-analyze-push-error err))))
- (setq end (current-time))
- ;;(message "Analysis took %.2f sec" (semantic-elapsed-time LLstart end))
+ ;;(message "Analysis took %.2f sec" (semantic-elapsed-time LLstart nil))
)
(when prefix
(prog1
(funcall analyzehookfcn (car bounds) (cdr bounds) prefix)
- ;;(setq end (current-time))
- ;;(message "hookfcn took %.5f sec" (semantic-elapsed-time LLstart end))
+ ;;(message "hookfcn took %.5f sec" (semantic-elapsed-time LLstart nil))
)
)))
@@ -723,12 +720,11 @@ Optional argument CTXT is the context to show."
(interactive)
(require 'data-debug)
(let ((start (current-time))
- (ctxt (or ctxt (semantic-analyze-current-context)))
- (end (current-time)))
+ (ctxt (or ctxt (semantic-analyze-current-context))))
(if (not ctxt)
(message "No Analyzer Results")
(message "Analysis took %.2f seconds."
- (semantic-elapsed-time start end))
+ (semantic-elapsed-time start nil))
(semantic-analyze-pulse ctxt)
(if ctxt
(progn
diff --git a/lisp/cedet/semantic/analyze/refs.el b/lisp/cedet/semantic/analyze/refs.el
index 6ebf130d305..84c60e2dae8 100644
--- a/lisp/cedet/semantic/analyze/refs.el
+++ b/lisp/cedet/semantic/analyze/refs.el
@@ -317,9 +317,8 @@ Only works for tags in the global namespace."
(let* ((tag (semantic-current-tag))
(start (current-time))
(sac (semantic-analyze-tag-references tag))
- (end (current-time))
)
- (message "Analysis took %.2f seconds." (semantic-elapsed-time start end))
+ (message "Analysis took %.2f seconds." (semantic-elapsed-time start nil))
(if sac
(progn
(require 'eieio-datadebug)
diff --git a/lisp/cedet/semantic/lex.el b/lisp/cedet/semantic/lex.el
index eec6e6762f3..835888db2ad 100644
--- a/lisp/cedet/semantic/lex.el
+++ b/lisp/cedet/semantic/lex.el
@@ -657,10 +657,9 @@ If universal argument ARG, then try the whole buffer."
(let* ((start (current-time))
(result (semantic-lex
(if arg (point-min) (point))
- (point-max)))
- (end (current-time)))
+ (point-max))))
(message "Elapsed Time: %.2f seconds."
- (semantic-elapsed-time start end))
+ (semantic-elapsed-time start nil))
(pop-to-buffer "*Lexer Output*")
(require 'pp)
(erase-buffer)
@@ -810,7 +809,7 @@ analyzer which might mistake a number for as a symbol."
tmp-start (car semantic-lex-token-stream)))
(setq tmp-start semantic-lex-end-point)
(goto-char semantic-lex-end-point)
- ;;(when (> (semantic-elapsed-time starttime (current-time))
+ ;;(when (> (semantic-elapsed-time starttime nil)
;; semantic-lex-timeout)
;; (error "Timeout during lex at char %d" (point)))
(semantic-throw-on-input 'lex)
diff --git a/lisp/cedet/semantic/symref/filter.el b/lisp/cedet/semantic/symref/filter.el
index 53be5e0defb..d5766af9b6e 100644
--- a/lisp/cedet/semantic/symref/filter.el
+++ b/lisp/cedet/semantic/symref/filter.el
@@ -103,7 +103,7 @@ tag that contains point, and return that."
(when (called-interactively-p 'interactive)
(message "Found %d occurrences of %s in %.2f seconds"
Lcount (semantic-tag-name target)
- (semantic-elapsed-time start (current-time))))
+ (semantic-elapsed-time start nil)))
Lcount)))
(defun semantic-symref-rename-local-variable ()
diff --git a/lisp/cedet/srecode/dictionary.el b/lisp/cedet/srecode/dictionary.el
index 4507581621d..6c8fd655d7b 100644
--- a/lisp/cedet/srecode/dictionary.el
+++ b/lisp/cedet/srecode/dictionary.el
@@ -612,10 +612,9 @@ STATE is the current compiler state."
(srecode-get-mode-table modesym))
(error "No table found for mode %S" modesym)))
(dict (srecode-create-dictionary (current-buffer)))
- (end (current-time))
)
(message "Creating a dictionary took %.2f seconds."
- (semantic-elapsed-time start end))
+ (semantic-elapsed-time start nil))
(data-debug-new-buffer "*SRECODE ADEBUG*")
(data-debug-insert-object-slots dict "*")))
diff --git a/lisp/cedet/srecode/map.el b/lisp/cedet/srecode/map.el
index 10541f61a9e..5b5d1fdd47d 100644
--- a/lisp/cedet/srecode/map.el
+++ b/lisp/cedet/srecode/map.el
@@ -224,10 +224,9 @@ Optional argument RESET forces a reset of the current map."
(require 'data-debug)
(let ((start (current-time))
(p (srecode-get-maps t)) ;; Time the reset.
- (end (current-time))
)
(message "Updating the map took %.2f seconds."
- (semantic-elapsed-time start end))
+ (semantic-elapsed-time start nil))
(data-debug-new-buffer "*SRECODE ADEBUG*")
(data-debug-insert-stuff-list p "*")))
diff --git a/lisp/desktop.el b/lisp/desktop.el
index 73228ce040b..66e2aef9798 100644
--- a/lisp/desktop.el
+++ b/lisp/desktop.el
@@ -1554,8 +1554,7 @@ and try to load that."
(setq buffer-display-time
(if buffer-display-time
(time-add buffer-display-time
- (time-subtract (current-time)
- desktop-file-modtime))
+ (time-subtract nil desktop-file-modtime))
(current-time)))
(unless (< desktop-file-version 208) ; Don't misinterpret any old custom args
(dolist (record compacted-vars)
diff --git a/lisp/dired-aux.el b/lisp/dired-aux.el
index 03639f6b507..94938cf679e 100644
--- a/lisp/dired-aux.el
+++ b/lisp/dired-aux.el
@@ -1548,6 +1548,24 @@ Special value `always' suppresses confirmation."
(declare-function make-symbolic-link "fileio.c")
+(defcustom dired-create-destination-dirs nil
+ "Whether Dired should create destination dirs when copying/removing files.
+If nil, don't create them.
+If `always', create them without ask.
+If `ask', ask for user confirmation."
+ :type '(choice (const :tag "Never create non-existent dirs" nil)
+ (const :tag "Always create non-existent dirs" always)
+ (const :tag "Ask for user confirmation" ask))
+ :group 'dired
+ :version "27.1")
+
+(defun dired-maybe-create-dirs (dir)
+ "Create DIR if doesn't exist according to `dired-create-destination-dirs'."
+ (when (and dired-create-destination-dirs (not (file-exists-p dir)))
+ (if (or (eq dired-create-destination-dirs 'always)
+ (yes-or-no-p (format "Create destination dir `%s'? " dir)))
+ (dired-create-directory dir))))
+
(defun dired-copy-file-recursive (from to ok-flag &optional
preserve-time top recursive)
(when (and (eq t (car (file-attributes from)))
@@ -1564,6 +1582,7 @@ Special value `always' suppresses confirmation."
(if (stringp (car attrs))
;; It is a symlink
(make-symbolic-link (car attrs) to ok-flag)
+ (dired-maybe-create-dirs (file-name-directory to))
(copy-file from to ok-flag preserve-time))
(file-date-error
(push (dired-make-relative from)
@@ -1573,6 +1592,7 @@ Special value `always' suppresses confirmation."
;;;###autoload
(defun dired-rename-file (file newname ok-if-already-exists)
(dired-handle-overwrite newname)
+ (dired-maybe-create-dirs (file-name-directory newname))
(rename-file file newname ok-if-already-exists) ; error is caught in -create-files
;; Silently rename the visited file of any buffer visiting this file.
(and (get-file-buffer file)
diff --git a/lisp/dired.el b/lisp/dired.el
index 9e09d349f7c..1ec3ac4f99c 100644
--- a/lisp/dired.el
+++ b/lisp/dired.el
@@ -198,8 +198,10 @@ The target is used in the prompt for file copy, rename etc."
; These variables were deleted and the replacements are on files.el.
; We leave aliases behind for back-compatibility.
-(defvaralias 'dired-free-space-program 'directory-free-space-program)
-(defvaralias 'dired-free-space-args 'directory-free-space-args)
+(define-obsolete-variable-alias 'dired-free-space-program
+ 'directory-free-space-program "27.1")
+(define-obsolete-variable-alias 'dired-free-space-args
+ 'directory-free-space-args "27.1")
;;; Hook variables
diff --git a/lisp/electric.el b/lisp/electric.el
index d7929945db2..5f4304462dd 100644
--- a/lisp/electric.el
+++ b/lisp/electric.el
@@ -451,6 +451,14 @@ whitespace, opening parenthesis, or quote and leaves \\=` alone."
:version "26.1"
:type 'boolean :safe #'booleanp :group 'electricity)
+(defcustom electric-quote-replace-double nil
+ "Non-nil means to replace \" with an electric double quote.
+Emacs replaces \" with an opening double quote after a line
+break, whitespace, opening parenthesis, or quote, and with a
+closing double quote otherwise."
+ :version "26.1"
+ :type 'boolean :safe #'booleanp :group 'electricity)
+
(defvar electric-quote-inhibit-functions ()
"List of functions that should inhibit electric quoting.
When the variable `electric-quote-mode' is non-nil, Emacs will
@@ -461,13 +469,17 @@ substitution is inhibited. The functions are called after the
after the inserted character. The functions in this hook should
not move point or change the current buffer.")
+(defvar electric-pair-text-pairs)
+
(defun electric-quote-post-self-insert-function ()
"Function that `electric-quote-mode' adds to `post-self-insert-hook'.
This requotes when a quoting key is typed."
(when (and electric-quote-mode
(or (eq last-command-event ?\')
(and (not electric-quote-context-sensitive)
- (eq last-command-event ?\`)))
+ (eq last-command-event ?\`))
+ (and electric-quote-replace-double
+ (eq last-command-event ?\")))
(not (run-hook-with-args-until-success
'electric-quote-inhibit-functions))
(if (derived-mode-p 'text-mode)
@@ -488,7 +500,8 @@ This requotes when a quoting key is typed."
(save-excursion
(let ((backtick ?\`))
(if (or (eq last-command-event ?\`)
- (and electric-quote-context-sensitive
+ (and (or electric-quote-context-sensitive
+ electric-quote-replace-double)
(save-excursion
(backward-char)
(or (bobp) (bolp)
@@ -506,13 +519,19 @@ This requotes when a quoting key is typed."
(setq last-command-event q<<))
((search-backward (string backtick) (1- (point)) t)
(replace-match (string q<))
- (setq last-command-event q<)))
+ (setq last-command-event q<))
+ ((search-backward "\"" (1- (point)) t)
+ (replace-match (string q<<))
+ (setq last-command-event q<<)))
(cond ((search-backward (string q> ?') (- (point) 2) t)
(replace-match (string q>>))
(setq last-command-event q>>))
((search-backward "'" (1- (point)) t)
(replace-match (string q>))
- (setq last-command-event q>))))))))))
+ (setq last-command-event q>))
+ ((search-backward "\"" (1- (point)) t)
+ (replace-match (string q>>))
+ (setq last-command-event q>>))))))))))
(put 'electric-quote-post-self-insert-function 'priority 10)
diff --git a/lisp/emacs-lisp/benchmark.el b/lisp/emacs-lisp/benchmark.el
index 445e78b427c..02db21a7e53 100644
--- a/lisp/emacs-lisp/benchmark.el
+++ b/lisp/emacs-lisp/benchmark.el
@@ -34,13 +34,11 @@
(defmacro benchmark-elapse (&rest forms)
"Return the time in seconds elapsed for execution of FORMS."
(declare (indent 0) (debug t))
- (let ((t1 (make-symbol "t1"))
- (t2 (make-symbol "t2")))
- `(let (,t1 ,t2)
+ (let ((t1 (make-symbol "t1")))
+ `(let (,t1)
(setq ,t1 (current-time))
,@forms
- (setq ,t2 (current-time))
- (float-time (time-subtract ,t2 ,t1)))))
+ (float-time (time-subtract nil ,t1)))))
;;;###autoload
(defmacro benchmark-run (&optional repetitions &rest forms)
diff --git a/lisp/emacs-lisp/byte-opt.el b/lisp/emacs-lisp/byte-opt.el
index 69f03c51668..623985f44f9 100644
--- a/lisp/emacs-lisp/byte-opt.el
+++ b/lisp/emacs-lisp/byte-opt.el
@@ -1281,7 +1281,10 @@
;; errors to compile time.
(let ((pure-fns
- '(concat symbol-name regexp-opt regexp-quote string-to-syntax)))
+ '(concat symbol-name regexp-opt regexp-quote string-to-syntax
+ string-to-char
+ ash lsh logb lognot logior logxor
+ ceiling floor)))
(while pure-fns
(put (car pure-fns) 'pure t)
(setq pure-fns (cdr pure-fns)))
diff --git a/lisp/emacs-lisp/checkdoc.el b/lisp/emacs-lisp/checkdoc.el
index 72f82f26f6f..fe6cd4160ed 100644
--- a/lisp/emacs-lisp/checkdoc.el
+++ b/lisp/emacs-lisp/checkdoc.el
@@ -171,6 +171,7 @@
(defvar checkdoc-version "0.6.1"
"Release version of checkdoc you are currently running.")
+(eval-when-compile (require 'cl-lib))
(require 'help-mode) ;; for help-xref-info-regexp
(require 'thingatpt) ;; for handy thing-at-point-looking-at
@@ -436,23 +437,6 @@ be re-created.")
st)
"Syntax table used by checkdoc in document strings.")
-;;; Compatibility
-;;
-(defalias 'checkdoc-make-overlay
- (if (featurep 'xemacs) #'make-extent #'make-overlay))
-(defalias 'checkdoc-overlay-put
- (if (featurep 'xemacs) #'set-extent-property #'overlay-put))
-(defalias 'checkdoc-delete-overlay
- (if (featurep 'xemacs) #'delete-extent #'delete-overlay))
-(defalias 'checkdoc-overlay-start
- (if (featurep 'xemacs) #'extent-start #'overlay-start))
-(defalias 'checkdoc-overlay-end
- (if (featurep 'xemacs) #'extent-end #'overlay-end))
-(defalias 'checkdoc-mode-line-update
- (if (featurep 'xemacs) #'redraw-modeline #'force-mode-line-update))
-(defalias 'checkdoc-char=
- (if (featurep 'xemacs) #'char= #'=))
-
;;; User level commands
;;
;;;###autoload
@@ -475,32 +459,31 @@ the users will view as each check is completed."
tmp)
(checkdoc-display-status-buffer status)
;; check the comments
- (if (not buffer-file-name)
- (setcar status "Not checked")
- (if (checkdoc-file-comments-engine)
- (setcar status "Errors")
- (setcar status "Ok")))
- (setcar (cdr status) "Checking...")
+ (setf (nth 0 status)
+ (cond
+ ((not buffer-file-name) "Not checked")
+ ((checkdoc-file-comments-engine) "Errors")
+ (t "Ok")))
+ (setf (nth 1 status) "Checking...")
(checkdoc-display-status-buffer status)
;; Check the documentation
(setq tmp (checkdoc-interactive nil t))
- (if tmp
- (setcar (cdr status) (format "%d Errors" (length tmp)))
- (setcar (cdr status) "Ok"))
- (setcar (cdr (cdr status)) "Checking...")
+ (setf (nth 1 status)
+ (if tmp (format "%d Errors" (length tmp)) "Ok"))
+ (setf (nth 2 status) "Checking...")
(checkdoc-display-status-buffer status)
;; Check the message text
- (if (setq tmp (checkdoc-message-interactive nil t))
- (setcar (cdr (cdr status)) (format "%d Errors" (length tmp)))
- (setcar (cdr (cdr status)) "Ok"))
- (setcar (cdr (cdr (cdr status))) "Checking...")
+ (setf (nth 2 status)
+ (if (setq tmp (checkdoc-message-interactive nil t))
+ (format "%d Errors" (length tmp))
+ "Ok"))
+ (setf (nth 3 status) "Checking...")
(checkdoc-display-status-buffer status)
;; Rogue spacing
- (if (condition-case nil
- (checkdoc-rogue-spaces nil t)
- (error t))
- (setcar (cdr (cdr (cdr status))) "Errors")
- (setcar (cdr (cdr (cdr status))) "Ok"))
+ (setf (nth 3 status)
+ (if (ignore-errors (checkdoc-rogue-spaces nil t))
+ "Errors"
+ "Ok"))
(checkdoc-display-status-buffer status)))
(defun checkdoc-display-status-buffer (check)
@@ -592,16 +575,16 @@ style."
(while err-list
(goto-char (cdr (car err-list)))
;; The cursor should be just in front of the offending doc string
- (if (stringp (car (car err-list)))
- (setq cdo (save-excursion (checkdoc-make-overlay
+ (setq cdo (if (stringp (car (car err-list)))
+ (save-excursion (make-overlay
(point) (progn (forward-sexp 1)
- (point)))))
- (setq cdo (checkdoc-make-overlay
+ (point))))
+ (make-overlay
(checkdoc-error-start (car (car err-list)))
(checkdoc-error-end (car (car err-list))))))
(unwind-protect
(progn
- (checkdoc-overlay-put cdo 'face 'highlight)
+ (overlay-put cdo 'face 'highlight)
;; Make sure the whole doc string is visible if possible.
(sit-for 0)
(if (and (= (following-char) ?\")
@@ -627,10 +610,10 @@ style."
(if (not (integerp c)) (setq c ??))
(cond
;; Exit condition
- ((checkdoc-char= c ?\C-g) (signal 'quit nil))
+ ((eq c ?\C-g) (signal 'quit nil))
;; Request an auto-fix
- ((or (checkdoc-char= c ?y) (checkdoc-char= c ?f))
- (checkdoc-delete-overlay cdo)
+ ((memq c '(?y ?f))
+ (delete-overlay cdo)
(setq cdo nil)
(goto-char (cdr (car err-list)))
;; `automatic-then-never' tells the autofix function
@@ -659,7 +642,7 @@ style."
"No Additional style errors. Continuing...")
(sit-for 2))))))
;; Move to the next error (if available)
- ((or (checkdoc-char= c ?n) (checkdoc-char= c ?\s))
+ ((memq c '(?n ?\s))
(let ((ne (funcall findfunc nil)))
(if (not ne)
(if showstatus
@@ -671,7 +654,7 @@ style."
(sit-for 2))
(setq err-list (cons ne err-list)))))
;; Go backwards in the list of errors
- ((or (checkdoc-char= c ?p) (checkdoc-char= c ?\C-?))
+ ((memq c '(?p ?\C-?))
(if (/= (length err-list) 1)
(progn
(setq err-list (cdr err-list))
@@ -680,10 +663,10 @@ style."
(message "No Previous Errors.")
(sit-for 2)))
;; Edit the buffer recursively.
- ((checkdoc-char= c ?e)
+ ((eq c ?e)
(checkdoc-recursive-edit
(checkdoc-error-text (car (car err-list))))
- (checkdoc-delete-overlay cdo)
+ (delete-overlay cdo)
(setq err-list (cdr err-list)) ;back up the error found.
(beginning-of-defun)
(let ((ne (funcall findfunc nil)))
@@ -695,7 +678,7 @@ style."
(sit-for 2))
(setq err-list (cons ne err-list)))))
;; Quit checkdoc
- ((checkdoc-char= c ?q)
+ ((eq c ?q)
(setq returnme err-list
err-list nil
begin (point)))
@@ -723,7 +706,7 @@ style."
"C-h - Toggle this help buffer.")))
(shrink-window-if-larger-than-buffer
(get-buffer-window "*Checkdoc Help*"))))))
- (if cdo (checkdoc-delete-overlay cdo)))))
+ (if cdo (delete-overlay cdo)))))
(goto-char begin)
(if (get-buffer "*Checkdoc Help*") (kill-buffer "*Checkdoc Help*"))
(message "Checkdoc: Done.")
@@ -1147,6 +1130,15 @@ Prefix argument is the same as for `checkdoc-defun'"
;; features and behaviors, so we need some ways of specifying
;; them, and making them easier to use in the wacked-out interfaces
;; people are requesting
+
+(cl-defstruct (checkdoc-error
+ (:constructor nil)
+ (:constructor checkdoc--create-error (text start end &optional unfixable)))
+ (text nil :read-only t)
+ (start nil :read-only t)
+ (end nil :read-only t)
+ (unfixable nil :read-only t))
+
(defvar checkdoc-create-error-function #'checkdoc--create-error-for-checkdoc
"Function called when Checkdoc encounters an error.
Should accept as arguments (TEXT START END &optional UNFIXABLE).
@@ -1155,7 +1147,7 @@ TEXT is the descriptive text of the error. START and END define the region
it is sensible to highlight when describing the problem.
Optional argument UNFIXABLE means that the error has no auto-fix available.
-A list of the form (TEXT START END UNFIXABLE) is returned if we are not
+An object of type `checkdoc-error' is returned if we are not
generating a buffered list of errors.")
(defun checkdoc-create-error (text start end &optional unfixable)
@@ -1171,27 +1163,7 @@ TEXT, START, END and UNFIXABLE conform to
(if checkdoc-generate-compile-warnings-flag
(progn (checkdoc-error start text)
nil)
- (list text start end unfixable)))
-
-(defun checkdoc-error-text (err)
- "Return the text specified in the checkdoc ERR."
- ;; string-p part is for backwards compatibility
- (if (stringp err) err (car err)))
-
-(defun checkdoc-error-start (err)
- "Return the start point specified in the checkdoc ERR."
- ;; string-p part is for backwards compatibility
- (if (stringp err) nil (nth 1 err)))
-
-(defun checkdoc-error-end (err)
- "Return the end point specified in the checkdoc ERR."
- ;; string-p part is for backwards compatibility
- (if (stringp err) nil (nth 2 err)))
-
-(defun checkdoc-error-unfixable (err)
- "Return the t if we cannot autofix the error specified in the checkdoc ERR."
- ;; string-p part is for backwards compatibility
- (if (stringp err) nil (nth 3 err)))
+ (checkdoc--create-error text start end unfixable)))
;;; Minor Mode specification
;;
@@ -1342,7 +1314,7 @@ See the style guide in the Emacs Lisp manual for more details."
(if (and (not (nth 1 fp)) ; not a variable
(or (nth 2 fp) ; is interactive
checkdoc-force-docstrings-flag) ;or we always complain
- (not (checkdoc-char= (following-char) ?\"))) ; no doc string
+ (not (eq (following-char) ?\"))) ; no doc string
;; Sometimes old code has comments where the documentation should
;; be. Let's see if we can find the comment, and offer to turn it
;; into documentation for them.
@@ -1471,9 +1443,9 @@ regexp short cuts work. FP is the function defun information."
(if (> (point) e) (goto-char e)) ;of the form (defun n () "doc" nil)
(forward-char -1)
(cond
- ((and (checkdoc-char= (following-char) ?\")
+ ((and (eq (following-char) ?\")
;; A backslashed double quote at the end of a sentence
- (not (checkdoc-char= (preceding-char) ?\\)))
+ (not (eq (preceding-char) ?\\)))
;; We might have to add a period in this case
(forward-char -1)
(if (looking-at "[.!?]")
@@ -1796,7 +1768,7 @@ function,command,variable,option or symbol." ms1))))))
(let ((lim (save-excursion
(end-of-line)
;; check string-continuation
- (if (checkdoc-char= (preceding-char) ?\\)
+ (if (eq (preceding-char) ?\\)
(line-end-position 2)
(point))))
(rs nil) replace original (case-fold-search t))
@@ -2593,12 +2565,12 @@ This function returns non-nil if the text was replaced.
This function will not modify `match-data'."
(if (and checkdoc-autofix-flag
(not (eq checkdoc-autofix-flag 'never)))
- (let ((o (checkdoc-make-overlay start end))
+ (let ((o (make-overlay start end))
(ret nil)
(md (match-data)))
(unwind-protect
(progn
- (checkdoc-overlay-put o 'face 'highlight)
+ (overlay-put o 'face 'highlight)
(if (or (eq checkdoc-autofix-flag 'automatic)
(eq checkdoc-autofix-flag 'automatic-then-never)
(and (eq checkdoc-autofix-flag 'semiautomatic)
@@ -2615,9 +2587,9 @@ This function will not modify `match-data'."
(insert replacewith)
(if checkdoc-bouncy-flag (sit-for 0))
(setq ret t)))
- (checkdoc-delete-overlay o)
+ (delete-overlay o)
(set-match-data md))
- (checkdoc-delete-overlay o)
+ (delete-overlay o)
(set-match-data md))
(if (eq checkdoc-autofix-flag 'automatic-then-never)
(setq checkdoc-autofix-flag 'never))
diff --git a/lisp/emacs-lisp/debug.el b/lisp/emacs-lisp/debug.el
index 6c754615b00..53b8db81321 100644
--- a/lisp/emacs-lisp/debug.el
+++ b/lisp/emacs-lisp/debug.el
@@ -272,6 +272,12 @@ first will be printed into the backtrace buffer."
(setq debug-on-next-call debugger-step-after-exit)
debugger-value)))
+(defun debugger--print (obj &optional stream)
+ (condition-case err
+ (funcall debugger-print-function obj stream)
+ (error
+ (message "Error in debug printer: %S" err)
+ (prin1 obj stream))))
(defun debugger-insert-backtrace (frames do-xrefs)
"Format and insert the backtrace FRAMES at point.
@@ -286,10 +292,10 @@ Make functions into cross-reference buttons if DO-XREFS is non-nil."
(fun-pt (point)))
(cond
((and evald (not debugger-stack-frame-as-list))
- (funcall debugger-print-function fun)
- (if args (funcall debugger-print-function args) (princ "()")))
+ (debugger--print fun)
+ (if args (debugger--print args) (princ "()")))
(t
- (funcall debugger-print-function (cons fun args))
+ (debugger--print (cons fun args))
(cl-incf fun-pt)))
(when fun-file
(make-text-button fun-pt (+ fun-pt (length (symbol-name fun)))
@@ -335,7 +341,7 @@ That buffer should be current already."
(insert "--returning value: ")
(setq pos (point))
(setq debugger-value (nth 1 args))
- (funcall debugger-print-function debugger-value (current-buffer))
+ (debugger--print debugger-value (current-buffer))
(setf (cl-getf (nth 3 (car frames)) :debug-on-exit) nil)
(insert ?\n))
;; Watchpoint triggered.
@@ -360,7 +366,7 @@ That buffer should be current already."
(`error
(insert "--Lisp error: ")
(setq pos (point))
- (funcall debugger-print-function (nth 1 args) (current-buffer))
+ (debugger--print (nth 1 args) (current-buffer))
(insert ?\n))
;; debug-on-call, when the next thing is an eval.
(`t
@@ -370,7 +376,7 @@ That buffer should be current already."
(_
(insert ": ")
(setq pos (point))
- (funcall debugger-print-function
+ (debugger--print
(if (eq (car args) 'nil)
(cdr args) args)
(current-buffer))
@@ -416,7 +422,7 @@ will be used, such as in a debug on exit from a frame."
"from an error" "at function entrance")))
(setq debugger-value val)
(princ "Returning " t)
- (prin1 debugger-value)
+ (debugger--print debugger-value)
(save-excursion
;; Check to see if we've flagged some frame for debug-on-exit, in which
;; case we'll probably come back to the debugger soon.
@@ -531,7 +537,7 @@ The environment used is the one when entering the activation frame at point."
(debugger-env-macro
(let ((val (backtrace-eval exp nframe base)))
(prog1
- (prin1 val t)
+ (debugger--print val t)
(let ((str (eval-expression-print-format val)))
(if str (princ str t))))))))
@@ -553,7 +559,7 @@ The environment used is the one when entering the activation frame at point."
(insert "\n ")
(prin1 symbol (current-buffer))
(insert " = ")
- (prin1 value (current-buffer))))))))
+ (debugger--print value (current-buffer))))))))
(defun debugger--show-locals ()
"For the frame at point, insert locals and add text properties."
diff --git a/lisp/emacs-lisp/easy-mmode.el b/lisp/emacs-lisp/easy-mmode.el
index bf087fc2e9a..643a65f48d9 100644
--- a/lisp/emacs-lisp/easy-mmode.el
+++ b/lisp/emacs-lisp/easy-mmode.el
@@ -543,6 +543,7 @@ Valid keywords and arguments are:
"Define a constant M whose value is the result of `easy-mmode-define-keymap'.
The M, BS, and ARGS arguments are as per that function. DOC is
the constant's documentation."
+ (declare (indent 1))
`(defconst ,m
(easy-mmode-define-keymap ,bs nil (if (boundp ',m) ,m) ,(cons 'list args))
,doc))
@@ -569,6 +570,7 @@ the constant's documentation."
(defmacro easy-mmode-defsyntax (st css doc &rest args)
"Define variable ST as a syntax-table.
CSS contains a list of syntax specifications of the form (CHAR . SYNTAX)."
+ (declare (indent 1))
`(progn
(autoload 'easy-mmode-define-syntax "easy-mmode")
(defconst ,st (easy-mmode-define-syntax ,css ,(cons 'list args)) ,doc)))
diff --git a/lisp/emacs-lisp/edebug.el b/lisp/emacs-lisp/edebug.el
index d00b14e803e..77523de32c5 100644
--- a/lisp/emacs-lisp/edebug.el
+++ b/lisp/emacs-lisp/edebug.el
@@ -1065,6 +1065,31 @@ circular objects. Let `read' read everything else."
(defvar edebug-error-point nil)
(defvar edebug-best-error nil)
+;; Hooks which may be used to extend Edebug's functionality. See
+;; Testcover for an example.
+(defvar edebug-after-instrumentation-functions nil
+ "Abnormal hook run on code after instrumentation for debugging.
+Each function is called with one argument, a form which has just
+been instrumented for Edebugging.")
+
+(defvar edebug-new-definition-functions '(edebug-announce-definition)
+ "Abnormal hook run after Edebug wraps a new definition.
+After Edebug has initialized its own data, each hook function is
+called with one argument, the symbol associated with the
+definition, which may be the actual symbol defined or one
+generated by Edebug.")
+
+(defvar edebug-behavior-alist
+ '((edebug edebug-default-enter edebug-slow-before edebug-slow-after))
+ "Alist describing the runtime behavior of Edebug's instrumented code.
+Each definition instrumented by Edebug will have a
+`edebug-behavior' property which is a key to this alist. When
+the instrumented code is running, Edebug will look here for the
+implementations of `edebug-enter', `edebug-before', and
+`edebug-after'. Edebug's instrumentation may be used for a new
+purpose by adding an entry to this alist and a hook to
+`edebug-new-definition-functions' which sets `edebug-behavior'
+for the definition.")
(defun edebug-read-and-maybe-wrap-form ()
;; Read a form and wrap it with edebug calls, if the conditions are right.
@@ -1124,47 +1149,48 @@ circular objects. Let `read' read everything else."
(eq 'symbol (edebug-next-token-class)))
(read (current-buffer))))))
;;;(message "all defs: %s all forms: %s" edebug-all-defs edebug-all-forms)
- (cond
- (defining-form-p
- (if (or edebug-all-defs edebug-all-forms)
- ;; If it is a defining form and we are edebugging defs,
- ;; then let edebug-list-form start it.
- (let ((cursor (edebug-new-cursor
- (list (edebug-read-storing-offsets (current-buffer)))
- (list edebug-offsets))))
- (car
- (edebug-make-form-wrapper
- cursor
- (edebug-before-offset cursor)
- (1- (edebug-after-offset cursor))
- (list (cons (symbol-name def-kind) (cdr spec))))))
-
- ;; Not edebugging this form, so reset the symbol's edebug
- ;; property to be just a marker at the definition's source code.
- ;; This only works for defs with simple names.
- (put def-name 'edebug (point-marker))
- ;; Also nil out dependent defs.
- '(mapcar (function
- (lambda (def)
- (put def-name 'edebug nil)))
- (get def-name 'edebug-dependents))
- (edebug-read-sexp)))
-
- ;; If all forms are being edebugged, explicitly wrap it.
- (edebug-all-forms
- (let ((cursor (edebug-new-cursor
- (list (edebug-read-storing-offsets (current-buffer)))
- (list edebug-offsets))))
- (edebug-make-form-wrapper
- cursor
- (edebug-before-offset cursor)
- (edebug-after-offset cursor)
- nil)))
-
- ;; Not a defining form, and not edebugging.
- (t (edebug-read-sexp)))
- ))
-
+ (let ((result
+ (cond
+ (defining-form-p
+ (if (or edebug-all-defs edebug-all-forms)
+ ;; If it is a defining form and we are edebugging defs,
+ ;; then let edebug-list-form start it.
+ (let ((cursor (edebug-new-cursor
+ (list (edebug-read-storing-offsets (current-buffer)))
+ (list edebug-offsets))))
+ (car
+ (edebug-make-form-wrapper
+ cursor
+ (edebug-before-offset cursor)
+ (1- (edebug-after-offset cursor))
+ (list (cons (symbol-name def-kind) (cdr spec))))))
+
+ ;; Not edebugging this form, so reset the symbol's edebug
+ ;; property to be just a marker at the definition's source code.
+ ;; This only works for defs with simple names.
+ (put def-name 'edebug (point-marker))
+ ;; Also nil out dependent defs.
+ '(mapcar (function
+ (lambda (def)
+ (put def-name 'edebug nil)))
+ (get def-name 'edebug-dependents))
+ (edebug-read-sexp)))
+
+ ;; If all forms are being edebugged, explicitly wrap it.
+ (edebug-all-forms
+ (let ((cursor (edebug-new-cursor
+ (list (edebug-read-storing-offsets (current-buffer)))
+ (list edebug-offsets))))
+ (edebug-make-form-wrapper
+ cursor
+ (edebug-before-offset cursor)
+ (edebug-after-offset cursor)
+ nil)))
+
+ ;; Not a defining form, and not edebugging.
+ (t (edebug-read-sexp)))))
+ (run-hook-with-args 'edebug-after-instrumentation-functions result)
+ result)))
(defvar edebug-def-args) ; args of defining form.
(defvar edebug-def-interactive) ; is it an emacs interactive function?
@@ -1332,7 +1358,6 @@ expressions; a `progn' form will be returned enclosing these forms."
;; (message "defining: %s" edebug-def-name) (sit-for 2)
(edebug-make-top-form-data-entry form-data-entry)
- (message "Edebug: %s" edebug-def-name)
;;(debug edebug-def-name)
;; Destructively reverse edebug-offset-list and make vector from it.
@@ -1358,9 +1383,15 @@ expressions; a `progn' form will be returned enclosing these forms."
edebug-offset-list
edebug-top-window-data
))
+ (put edebug-def-name 'edebug-behavior 'edebug)
+ (run-hook-with-args 'edebug-new-definition-functions edebug-def-name)
result
)))
+(defun edebug-announce-definition (def-name)
+ "Announce Edebug's processing of DEF-NAME."
+ (message "Edebug: %s" def-name))
+
(defun edebug-clear-frequency-count (name)
;; Create initial frequency count vector.
@@ -2170,7 +2201,21 @@ error is signaled again."
;;; Entering Edebug
-(defun edebug-enter (function args body)
+(defun edebug-enter (func args body)
+ "Enter Edebug for a function.
+FUNC should be the symbol with the Edebug information, ARGS is
+the list of arguments and BODY is the code.
+
+Look up the `edebug-behavior' for FUNC in `edebug-behavior-alist'
+and run its entry function, and set up `edebug-before' and
+`edebug-after'."
+ (cl-letf* ((behavior (get func 'edebug-behavior))
+ (functions (cdr (assoc behavior edebug-behavior-alist)))
+ ((symbol-function #'edebug-before) (nth 1 functions))
+ ((symbol-function #'edebug-after) (nth 2 functions)))
+ (funcall (nth 0 functions) func args body)))
+
+(defun edebug-default-enter (function args body)
;; Entering FUNC. The arguments are ARGS, and the body is BODY.
;; Setup edebug variables and evaluate BODY. This function is called
;; when a function evaluated with edebug-eval-top-level-form is entered.
@@ -2201,7 +2246,7 @@ error is signaled again."
edebug-initial-mode
edebug-execution-mode)
edebug-next-execution-mode nil)
- (edebug-enter function args body))))
+ (edebug-default-enter function args body))))
(let* ((edebug-data (get function 'edebug))
(edebug-def-mark (car edebug-data)) ; mark at def start
@@ -2320,22 +2365,27 @@ MSG is printed after `::::} '."
value
(edebug-debugger after-index 'after value)
)))
-
(defun edebug-fast-after (_before-index _after-index value)
;; Do nothing but return the value.
value)
(defun edebug-run-slow ()
- (defalias 'edebug-before 'edebug-slow-before)
- (defalias 'edebug-after 'edebug-slow-after))
+ "Set up Edebug's normal behavior."
+ (setf (cdr (assq 'edebug edebug-behavior-alist))
+ '(edebug-default-enter edebug-slow-before edebug-slow-after)))
;; This is not used, yet.
(defun edebug-run-fast ()
- (defalias 'edebug-before 'edebug-fast-before)
- (defalias 'edebug-after 'edebug-fast-after))
-
-(edebug-run-slow)
-
+ "Disable Edebug without de-instrumenting code."
+ (setf (cdr (assq 'edebug edebug-behavior-alist))
+ '(edebug-default-enter edebug-fast-before edebug-fast-after)))
+
+(defalias 'edebug-before nil
+ "Function called by Edebug before a form is evaluated.
+See `edebug-behavior-alist' for implementations.")
+(defalias 'edebug-after nil
+ "Function called by Edebug after a form is evaluated.
+See `edebug-behavior-alist' for implementations.")
(defun edebug--update-coverage (after-index value)
(let ((old-result (aref edebug-coverage after-index)))
diff --git a/lisp/emacs-lisp/eieio-base.el b/lisp/emacs-lisp/eieio-base.el
index e3501be6c1d..8ad16038bca 100644
--- a/lisp/emacs-lisp/eieio-base.el
+++ b/lisp/emacs-lisp/eieio-base.el
@@ -464,7 +464,7 @@ instance."
(cl-defmethod eieio-object-name-string ((obj eieio-named))
"Return a string which is OBJ's name."
(or (slot-value obj 'object-name)
- (symbol-name (eieio-object-class obj))))
+ (cl-call-next-method)))
(cl-defmethod eieio-object-set-name-string ((obj eieio-named) name)
"Set the string which is OBJ's NAME."
diff --git a/lisp/emacs-lisp/eieio.el b/lisp/emacs-lisp/eieio.el
index 75f1097acf1..ca91c5a8711 100644
--- a/lisp/emacs-lisp/eieio.el
+++ b/lisp/emacs-lisp/eieio.el
@@ -377,9 +377,21 @@ is a shorthand for (NAME NAME)."
(define-obsolete-function-alias
'object-class-fast #'eieio-object-class "24.4")
+;; In the past, every EIEIO object had a `name' field, so we had the
+;; two methods `eieio-object-name-string' and
+;; `eieio-object-set-name-string' "for free". Since this field is
+;; very rarely used, we got rid of it and instead we keep it in a weak
+;; hash-tables, for those very rare objects that use it.
+;; Really, those rare objects should inherit from `eieio-named' instead!
+(defconst eieio--object-names (make-hash-table :test #'eq :weakness 'key))
+
(cl-defgeneric eieio-object-name-string (obj)
"Return a string which is OBJ's name."
- (declare (obsolete eieio-named "25.1")))
+ (or (gethash obj eieio--object-names)
+ (format "%s-%x" (eieio-object-class obj) (sxhash-eq obj))))
+
+(define-obsolete-function-alias
+ 'object-name-string #'eieio-object-name-string "24.4")
(defun eieio-object-name (obj &optional extra)
"Return a printed representation for object OBJ.
@@ -389,21 +401,9 @@ If EXTRA, include that in the string returned to represent the symbol."
(eieio-object-name-string obj) (or extra "")))
(define-obsolete-function-alias 'object-name #'eieio-object-name "24.4")
-(defconst eieio--object-names (make-hash-table :test #'eq :weakness 'key))
-
-;; In the past, every EIEIO object had a `name' field, so we had the two method
-;; below "for free". Since this field is very rarely used, we got rid of it
-;; and instead we keep it in a weak hash-tables, for those very rare objects
-;; that use it.
-(cl-defmethod eieio-object-name-string (obj)
- (or (gethash obj eieio--object-names)
- (symbol-name (eieio-object-class obj))))
-(define-obsolete-function-alias
- 'object-name-string #'eieio-object-name-string "24.4")
-
-(cl-defmethod eieio-object-set-name-string (obj name)
+(cl-defgeneric eieio-object-set-name-string (obj name)
"Set the string which is OBJ's NAME."
- (declare (obsolete eieio-named "25.1"))
+ (declare (obsolete "inherit from `eieio-named' and use (setf (slot-value OBJ 'object-name) NAME) instead" "25.1"))
(cl-check-type name string)
(setf (gethash obj eieio--object-names) name))
(define-obsolete-function-alias
diff --git a/lisp/emacs-lisp/elp.el b/lisp/emacs-lisp/elp.el
index 2be9c9da865..905718dad68 100644
--- a/lisp/emacs-lisp/elp.el
+++ b/lisp/emacs-lisp/elp.el
@@ -382,14 +382,13 @@ original definition, use \\[elp-restore-function] or \\[elp-restore-all]."
;; and return the results.
(setq result (apply func args))
;; we are recording times
- (let (enter-time exit-time)
+ (let (enter-time)
;; increment the call-counter
(cl-incf (aref info 0))
(setq enter-time (current-time)
- result (apply func args)
- exit-time (current-time))
+ result (apply func args))
;; calculate total time in function
- (cl-incf (aref info 1) (elp-elapsed-time enter-time exit-time))
+ (cl-incf (aref info 1) (elp-elapsed-time enter-time nil))
))
;; turn off recording if this is the master function
(if (and elp-master
diff --git a/lisp/emacs-lisp/gv.el b/lisp/emacs-lisp/gv.el
index 892d6e97167..777b955d90d 100644
--- a/lisp/emacs-lisp/gv.el
+++ b/lisp/emacs-lisp/gv.el
@@ -303,7 +303,9 @@ The return value is the last VAL in the list.
(lambda (do before index place)
(gv-letplace (getter setter) place
(funcall do `(edebug-after ,before ,index ,getter)
- setter))))
+ (lambda (store)
+ `(progn (edebug-after ,before ,index ,getter)
+ ,(funcall setter store)))))))
;;; The common generalized variables.
diff --git a/lisp/emacs-lisp/testcover.el b/lisp/emacs-lisp/testcover.el
index 691860bbd79..3628968974c 100644
--- a/lisp/emacs-lisp/testcover.el
+++ b/lisp/emacs-lisp/testcover.el
@@ -33,7 +33,9 @@
;; that has a splotch.
;; * Basic algorithm: use `edebug' to mark up the function text with
-;; instrumentation callbacks, then replace edebug's callbacks with ours.
+;; instrumentation callbacks, walk the instrumented code looking for
+;; forms which don't return or always return the same value, then use
+;; Edebug's before and after hooks to replace its code coverage with ours.
;; * To show good coverage, we want to see two values for every form, except
;; functions that always return the same value and `defconst' variables
;; need show only one value for good coverage. To avoid the brown
@@ -47,11 +49,10 @@
;; function being called is capable of returning in other cases.
;; Problems:
-;; * To detect different values, we store the form's result in a vector and
-;; compare the next result using `equal'. We don't copy the form's
-;; result, so if caller alters it (`setcar', etc.) we'll think the next
-;; call has the same value! Also, equal thinks two strings are the same
-;; if they differ only in properties.
+;; * `equal', which is used to compare the results of repeatedly executing
+;; a form, has a couple of shortcomings. It considers strings to be the same
+;; if they only differ in properties, and it raises an error when asked to
+;; compare circular lists.
;; * Because we have only a "1value" class and no "always nil" class, we have
;; to treat as potentially 1-valued any `and' whose last term is 1-valued,
;; in case the last term is always nil. Example:
@@ -89,16 +90,14 @@ these. This list is quite incomplete!"
buffer-disable-undo buffer-enable-undo current-global-map
deactivate-mark delete-backward-char delete-char delete-region ding
forward-char function* insert insert-and-inherit kill-all-local-variables
- kill-line kill-paragraph kill-region kill-sexp lambda
+ kill-line kill-paragraph kill-region kill-sexp
minibuffer-complete-and-exit narrow-to-region next-line push-mark
put-text-property run-hooks set-match-data signal
substitute-key-definition suppress-keymap undo use-local-map while widen
yank)
- "Functions that always return the same value. No brown splotch is shown
-for these. This list is quite incomplete! Notes: Nobody ever changes the
-current global map. The macro `lambda' is self-evaluating, hence always
-returns the same value (the function it defines may return varying values
-when called)."
+ "Functions that always return the same value, according to `equal'.
+No brown splotch is shown for these. This list is quite
+incomplete! Notes: Nobody ever changes the current global map."
:group 'testcover
:type '(repeat symbol))
@@ -111,7 +110,7 @@ them as having returned nil just before calling them."
(defcustom testcover-compose-functions
'(+ - * / = append length list make-keymap make-sparse-keymap
- mapcar message propertize replace-regexp-in-string
+ message propertize replace-regexp-in-string
run-with-idle-timer set-buffer-modified-p)
"Functions that are 1-valued if all their args are either constants or
calls to one of the `testcover-1value-functions', so if that's true then no
@@ -186,19 +185,21 @@ call to one of the `testcover-1value-functions'."
;;;###autoload
(defun testcover-start (filename &optional byte-compile)
- "Uses edebug to instrument all macros and functions in FILENAME, then
-changes the instrumentation from edebug to testcover--much faster, no
-problems with type-ahead or post-command-hook, etc. If BYTE-COMPILE is
-non-nil, byte-compiles each function after instrumenting."
+ "Use Edebug to instrument for coverage all macros and functions in FILENAME.
+If BYTE-COMPILE is non-nil, byte compile each function after instrumenting."
(interactive "fStart covering file: ")
- (let ((buf (find-file filename))
- (load-read-function load-read-function))
- (add-function :around load-read-function
- #'testcover--read)
- (setq edebug-form-data nil
- testcover-module-constants nil
- testcover-module-1value-functions nil)
- (eval-buffer buf))
+ (let ((buf (find-file filename)))
+ (setq edebug-form-data nil
+ testcover-module-constants nil
+ testcover-module-1value-functions nil
+ testcover-module-potentially-1value-functions nil)
+ (cl-letf ((edebug-all-defs t)
+ (edebug-after-instrumentation-functions)
+ (edebug-new-definition-functions))
+ (add-hook 'edebug-after-instrumentation-functions 'testcover-after-instrumentation)
+ (add-hook 'edebug-new-definition-functions 'testcover-init-definition)
+ (remove-hook 'edebug-new-definition-functions 'edebug-announce-definition)
+ (eval-buffer buf)))
(when byte-compile
(dolist (x (reverse edebug-form-data))
(when (fboundp (car x))
@@ -209,229 +210,13 @@ non-nil, byte-compiles each function after instrumenting."
(defun testcover-this-defun ()
"Start coverage on function under point."
(interactive)
- (let ((x (let ((edebug-all-defs t))
- (symbol-function (eval-defun nil)))))
- (testcover-reinstrument x)
- x))
-
-(defun testcover--read (orig &optional stream)
- "Read a form using edebug, changing edebug callbacks to testcover callbacks."
- (or stream (setq stream standard-input))
- (if (eq stream (current-buffer))
- (let ((x (let ((edebug-all-defs t))
- (edebug-read-and-maybe-wrap-form))))
- (testcover-reinstrument x)
- x)
- (funcall (or orig #'read) stream)))
-
-(defun testcover-reinstrument (form)
- "Reinstruments FORM to use testcover instead of edebug. This
-function modifies the list that FORM points to. Result is nil if
-FORM should return multiple values, t if should always return same
-value, `maybe' if either is acceptable."
- (let ((fun (car-safe form))
- id val)
- (cond
- ((not fun) ;Atom
- (when (or (not (symbolp form))
- (memq form testcover-constants)
- (memq form testcover-module-constants))
- t))
- ((consp fun) ;Embedded list
- (testcover-reinstrument fun)
- (testcover-reinstrument-list (cdr form))
- nil)
- ((or (memq fun testcover-1value-functions)
- (memq fun testcover-module-1value-functions))
- ;;Should always return same value
- (testcover-reinstrument-list (cdr form))
- t)
- ((or (memq fun testcover-potentially-1value-functions)
- (memq fun testcover-module-potentially-1value-functions))
- ;;Might always return same value
- (testcover-reinstrument-list (cdr form))
- 'maybe)
- ((memq fun testcover-progn-functions)
- ;;1-valued if last argument is
- (testcover-reinstrument-list (cdr form)))
- ((memq fun testcover-prog1-functions)
- ;;1-valued if first argument is
- (testcover-reinstrument-list (cddr form))
- (testcover-reinstrument (cadr form)))
- ((memq fun testcover-compose-functions)
- ;;1-valued if all arguments are. Potentially 1-valued if all
- ;;arguments are either definitely or potentially.
- (testcover-reinstrument-compose (cdr form) 'testcover-reinstrument))
- ((eq fun 'edebug-enter)
- ;;(edebug-enter 'SYM ARGS #'(lambda nil FORMS))
- ;; => (testcover-enter 'SYM #'(lambda nil FORMS))
- (setcar form 'testcover-enter)
- (setcdr (nthcdr 1 form) (nthcdr 3 form))
- (let ((testcover-vector (get (cadr (cadr form)) 'edebug-coverage)))
- (testcover-reinstrument-list (nthcdr 2 (cadr (nth 2 form))))))
- ((eq fun 'edebug-after)
- ;;(edebug-after (edebug-before XXX) YYY FORM)
- ;; => (testcover-after YYY FORM), mark XXX as ok-coverage
- (unless (eq (cadr form) 0)
- (aset testcover-vector (cadr (cadr form)) 'ok-coverage))
- (setq id (nth 2 form))
- (setcdr form (nthcdr 2 form))
- (setq val (testcover-reinstrument (nth 2 form)))
- (setcar form (if (eq val t)
- 'testcover-1value
- 'testcover-after))
- (when val
- ;;1-valued or potentially 1-valued
- (aset testcover-vector id '1value))
- (cond
- ((memq (car-safe (nth 2 form)) testcover-noreturn-functions)
- ;;This function won't return, so set the value in advance
- ;;(edebug-after (edebug-before XXX) YYY FORM)
- ;; => (progn (edebug-after YYY nil) FORM)
- (setcar (cdr form) `(,(car form) ,id nil))
- (setcar form 'progn)
- (aset testcover-vector id '1value)
- (setq val t))
- ((eq (car-safe (nth 2 form)) '1value)
- ;;This function is always supposed to return the same value
- (setq val t)
- (aset testcover-vector id '1value)
- (setcar form 'testcover-1value)))
- val)
- ((eq fun 'defun)
- (setq val (testcover-reinstrument-list (nthcdr 3 form)))
- (when (eq val t)
- (push (cadr form) testcover-module-1value-functions))
- (when (eq val 'maybe)
- (push (cadr form) testcover-module-potentially-1value-functions)))
- ((memq fun '(defconst defcustom))
- ;;Define this symbol as 1-valued
- (push (cadr form) testcover-module-constants)
- (testcover-reinstrument-list (cddr form)))
- ((memq fun '(dotimes dolist))
- ;;Always returns third value from SPEC
- (testcover-reinstrument-list (cddr form))
- (setq val (testcover-reinstrument-list (cadr form)))
- (if (nth 2 (cadr form))
- val
- ;;No third value, always returns nil
- t))
- ((memq fun '(let let*))
- ;;Special parsing for second argument
- (mapc 'testcover-reinstrument-list (cadr form))
- (testcover-reinstrument-list (cddr form)))
- ((eq fun 'if)
- ;;Potentially 1-valued if both THEN and ELSE clauses are
- (testcover-reinstrument (cadr form))
- (let ((then (testcover-reinstrument (nth 2 form)))
- (else (testcover-reinstrument-list (nthcdr 3 form))))
- (and then else 'maybe)))
- ((eq fun 'cond)
- ;;Potentially 1-valued if all clauses are
- (when (testcover-reinstrument-compose (cdr form)
- 'testcover-reinstrument-list)
- 'maybe))
- ((eq fun 'condition-case)
- ;;Potentially 1-valued if BODYFORM is and all HANDLERS are
- (let ((body (testcover-reinstrument (nth 2 form)))
- (errs (testcover-reinstrument-compose
- (mapcar #'cdr (nthcdr 3 form))
- 'testcover-reinstrument-list)))
- (and body errs 'maybe)))
- ((eq fun 'quote)
- ;;Don't reinstrument what's inside!
- ;;This doesn't apply within a backquote
- t)
- ((eq fun '\`)
- ;;Quotes are not special within backquotes
- (let ((testcover-1value-functions
- (cons 'quote testcover-1value-functions)))
- (testcover-reinstrument (cadr form))))
- ((eq fun '\,)
- ;;In commas inside backquotes, quotes are special again
- (let ((testcover-1value-functions
- (remq 'quote testcover-1value-functions)))
- (testcover-reinstrument (cadr form))))
- ((eq fun '1value)
- ;;Hack - pretend the arg is 1-valued here
- (cond
- ((symbolp (cadr form))
- ;;A pseudoconstant variable
- t)
- ((and (eq (car (cadr form)) 'edebug-after)
- (symbolp (nth 3 (cadr form))))
- ;;Reference to pseudoconstant
- (aset testcover-vector (nth 2 (cadr form)) '1value)
- (setcar (cdr form) `(testcover-1value ,(nth 2 (cadr form))
- ,(nth 3 (cadr form))))
- t)
- (t
- (setq id (car (if (eq (car (cadr form)) 'edebug-after)
- (nth 3 (cadr form))
- (cadr form))))
- (let ((testcover-1value-functions
- (cons id testcover-1value-functions)))
- (testcover-reinstrument (cadr form))))))
- ((eq fun 'noreturn)
- ;;Hack - pretend the arg has no return
- (cond
- ((symbolp (cadr form))
- ;;A pseudoconstant variable
- 'maybe)
- ((and (eq (car (cadr form)) 'edebug-after)
- (symbolp (nth 3 (cadr form))))
- ;;Reference to pseudoconstant
- (aset testcover-vector (nth 2 (cadr form)) '1value)
- (setcar (cdr form) `(progn (testcover-after ,(nth 2 (cadr form)) nil)
- ,(nth 3 (cadr form))))
- 'maybe)
- (t
- (setq id (car (if (eq (car (cadr form)) 'edebug-after)
- (nth 3 (cadr form))
- (cadr form))))
- (let ((testcover-noreturn-functions
- (cons id testcover-noreturn-functions)))
- (testcover-reinstrument (cadr form))))))
- ((and (eq fun 'apply)
- (eq (car-safe (cadr form)) 'quote)
- (symbolp (cadr (cadr form))))
- ;;Apply of a constant symbol. Process as 1value or noreturn
- ;;depending on symbol.
- (setq fun (cons (cadr (cadr form)) (cddr form))
- val (testcover-reinstrument fun))
- (setcdr (cdr form) (cdr fun))
- val)
- (t ;Some other function or weird thing
- (testcover-reinstrument-list (cdr form))
- nil))))
-
-(defun testcover-reinstrument-list (list)
- "Reinstruments each form in LIST to use testcover instead of edebug.
-This function modifies the forms in LIST. Result is `testcover-reinstrument's
-value for the last form in LIST. If the LIST is empty, its evaluation will
-always be nil, so we return t for 1-valued."
- (let ((result t))
- (while (consp list)
- (setq result (testcover-reinstrument (pop list))))
- result))
-
-(defun testcover-reinstrument-compose (list fun)
- "For a compositional function, the result is 1-valued if all
-arguments are, potentially 1-valued if all arguments are either
-definitely or potentially 1-valued, and multi-valued otherwise.
-FUN should be `testcover-reinstrument' for compositional functions,
- `testcover-reinstrument-list' for clauses in a `cond'."
- (let ((result t))
- (mapc #'(lambda (x)
- (setq x (funcall fun x))
- (cond
- ((eq result t)
- (setq result x))
- ((eq result 'maybe)
- (when (not x)
- (setq result nil)))))
- list)
- result))
+ (cl-letf ((edebug-all-defs t)
+ (edebug-after-instrumentation-functions)
+ (edebug-new-definition-functions))
+ (add-hook 'edebug-after-instrumentation-functions 'testcover-after-instrumentation)
+ (add-hook 'edebug-new-definition-functions 'testcover-init-definition)
+ (remove-hook 'edebug-new-definition-functions 'edebug-announce-definition)
+ (eval-defun nil)))
(defun testcover-end (filename)
"Turn off instrumentation of all macros and functions in FILENAME."
@@ -444,48 +229,107 @@ FUN should be `testcover-reinstrument' for compositional functions,
;;; Accumulate coverage data
;;;=========================================================================
-(defun testcover-enter (testcover-sym testcover-fun)
- "Internal function for coverage testing. Invokes TESTCOVER-FUN while
-binding `testcover-vector' to the code-coverage vector for TESTCOVER-SYM
-\(the name of the current function)."
- (let ((testcover-vector (get testcover-sym 'edebug-coverage)))
- (funcall testcover-fun)))
-
-(defun testcover-after (idx val)
- "Internal function for coverage testing. Returns VAL after installing it in
-`testcover-vector' at offset IDX."
- (declare (gv-expander (lambda (do)
- (gv-letplace (getter setter) val
- (funcall do getter
- (lambda (store)
- `(progn (testcover-after ,idx ,getter)
- ,(funcall setter store))))))))
- (cond
- ((eq (aref testcover-vector idx) 'unknown)
- (aset testcover-vector idx val))
- ((not (condition-case ()
- (equal (aref testcover-vector idx) val)
- ;; TODO: Actually check circular lists for equality.
- (circular-list nil)))
- (aset testcover-vector idx 'ok-coverage)))
- val)
-
-(defun testcover-1value (idx val)
- "Internal function for coverage testing. Returns VAL after installing it in
-`testcover-vector' at offset IDX. Error if FORM does not always return the
-same value during coverage testing."
- (cond
- ((eq (aref testcover-vector idx) '1value)
- (aset testcover-vector idx (cons '1value val)))
- ((not (and (eq (car-safe (aref testcover-vector idx)) '1value)
- (condition-case ()
- (equal (cdr (aref testcover-vector idx)) val)
- ;; TODO: Actually check circular lists for equality.
- (circular-list nil))))
- (error "Value of form marked with `1value' does vary: %s" val)))
- val)
-
-
+(defun testcover-after-instrumentation (form)
+ "Analyze FORM for code coverage."
+ (testcover-analyze-coverage form))
+
+(defun testcover-init-definition (sym)
+ "Mark SYM as under test coverage."
+ (message "Testcover: %s" edebug-def-name)
+ (put sym 'edebug-behavior 'testcover))
+
+(defun testcover-enter (func _args body)
+ "Begin execution of a function under coverage testing.
+Bind `testcover-vector' to the code-coverage vector for FUNC and
+return the result of evaluating BODY."
+ (let ((testcover-vector (get func 'edebug-coverage)))
+ (funcall body)))
+
+(defun testcover-before (before-index)
+ "Update code coverage before a form is evaluated.
+BEFORE-INDEX is the form's index into the code-coverage vector."
+ (let ((before-entry (aref testcover-vector before-index)))
+ (when (eq (car-safe before-entry) 'noreturn)
+ (let* ((after-index (cdr before-entry)))
+ (aset testcover-vector after-index 'ok-coverage)))))
+
+(defun testcover-after (_before-index after-index value)
+ "Update code coverage with the result of a form's evaluation.
+AFTER-INDEX is the form's index into the code-coverage
+vector. Return VALUE."
+ (let ((old-result (aref testcover-vector after-index)))
+ (cond
+ ((eq 'unknown old-result)
+ (aset testcover-vector after-index (testcover--copy-object value)))
+ ((eq 'maybe old-result)
+ (aset testcover-vector after-index 'ok-coverage))
+ ((eq '1value old-result)
+ (aset testcover-vector after-index
+ (cons old-result (testcover--copy-object value))))
+ ((and (eq (car-safe old-result) '1value)
+ (not (condition-case ()
+ (equal (cdr old-result) value)
+ (circular-list t))))
+ (error "Value of form expected to be constant does vary, from %s to %s"
+ old-result value))
+ ;; Test if a different result.
+ ((not (condition-case ()
+ (equal value old-result)
+ (circular-list nil)))
+ (aset testcover-vector after-index 'ok-coverage))))
+ value)
+
+;; Add these behaviors to Edebug.
+(unless (assoc 'testcover edebug-behavior-alist)
+ (push '(testcover testcover-enter testcover-before testcover-after)
+ edebug-behavior-alist))
+
+(defun testcover--copy-object (obj)
+ "Make a copy of OBJ.
+If OBJ is a cons cell, copy both its car and its cdr.
+Contrast to `copy-tree' which does the same but fails on circular
+structures, and `copy-sequence', which copies only along the
+cdrs. Copy vectors as well as conses."
+ (let ((ht (make-hash-table :test 'eq)))
+ (testcover--copy-object1 obj t ht)))
+
+(defun testcover--copy-object1 (obj vecp hash-table)
+ "Make a copy of OBJ, using a HASH-TABLE of objects already copied.
+If OBJ is a cons cell, this recursively copies its car and
+iteratively copies its cdr. When VECP is non-nil, copy
+vectors as well as conses."
+ (if (and (atom obj) (or (not vecp) (not (vectorp obj))))
+ obj
+ (let ((copy (gethash obj hash-table nil)))
+ (unless copy
+ (cond
+ ((consp obj)
+ (let* ((rest obj) current)
+ (setq copy (cons nil nil)
+ current copy)
+ (while
+ (progn
+ (puthash rest current hash-table)
+ (setf (car current)
+ (testcover--copy-object1 (car rest) vecp hash-table))
+ (setq rest (cdr rest))
+ (cond
+ ((atom rest)
+ (setf (cdr current)
+ (testcover--copy-object1 rest vecp hash-table))
+ nil)
+ ((gethash rest hash-table nil)
+ (setf (cdr current) (gethash rest hash-table nil))
+ nil)
+ (t (setq current
+ (setf (cdr current) (cons nil nil)))))))))
+ (t ; (and vecp (vectorp obj)) is true due to test in if above.
+ (setq copy (copy-sequence obj))
+ (puthash obj copy hash-table)
+ (dotimes (i (length copy))
+ (aset copy i
+ (testcover--copy-object1 (aref copy i) vecp hash-table))))))
+ copy)))
;;;=========================================================================
;;; Display the coverage data as color splotches on your code.
@@ -517,12 +361,13 @@ eliminated by adding more test cases."
(while (> len 0)
(setq len (1- len)
data (aref coverage len))
- (when (and (not (eq data 'ok-coverage))
- (not (eq (car-safe data) '1value))
- (setq j (+ def-mark (aref points len))))
+ (when (and (not (eq data 'ok-coverage))
+ (not (memq (car-safe data)
+ '(1value maybe noreturn)))
+ (setq j (+ def-mark (aref points len))))
(setq ov (make-overlay (1- j) j))
(overlay-put ov 'face
- (if (memq data '(unknown 1value))
+ (if (memq data '(unknown maybe 1value))
'testcover-nohits
'testcover-1value))))
(set-buffer-modified-p changed))))
@@ -553,4 +398,284 @@ coverage tests. This function creates many overlays."
(goto-char (next-overlay-change (point)))
(end-of-line))
+
+;;; Coverage Analysis
+
+;; The top level function for initializing code coverage is
+;; `testcover-analyze-coverage', which recursively walks the form it is
+;; passed, which should have already been instrumented by
+;; edebug-read-and-maybe-wrap-form, and initializes the associated
+;; code coverage vectors, which should have already been created by
+;; `edebug-clear-coverage'.
+;;
+;; The purpose of the analysis is to identify forms which can only
+;; ever return a single value. These forms can be considered to have
+;; adequate code coverage even if only executed once. In addition,
+;; forms which will never return, such as error signals, can be
+;; identified and treated correctly.
+;;
+;; The code coverage vector entries for the beginnings of forms will
+;; be changed to `ok-coverage.', except for the beginnings of forms
+;; which should never return, which will be changed to
+;; (noreturn . AFTER-INDEX) so that testcover-before can set the entry
+;; for the end of the form just before it is executed.
+;;
+;; Entries for the ends of forms may be changed to `1value' if
+;; analysis determines the form will only ever return a single value,
+;; or `maybe' if the form could potentially only ever return a single
+;; value.
+;;
+;; An example of a potentially 1-valued form is an `and' whose last
+;; term is 1-valued, in case the last term is always nil. Example:
+;;
+;; (and (< (point) 1000) (forward-char 10))
+;;
+;; This form always returns nil. Similarly, `or', `if', and `cond'
+;; are treated as potentially 1-valued if all clauses are, in case
+;; those values are always nil. Unlike truly 1-valued functions, it
+;; is not an error if these "potentially" 1-valued forms actually
+;; return differing values.
+
+(defun testcover-analyze-coverage (form)
+ "Analyze FORM and initialize coverage vectors for definitions found within.
+Return 1value, maybe or nil depending on if the form is determined
+to return only a single value, potentially return only a single value,
+or return multiple values."
+ (pcase form
+ (`(edebug-enter ',sym ,_ (function (lambda nil . ,body)))
+ (let ((testcover-vector (get sym 'edebug-coverage)))
+ (testcover-analyze-coverage-progn body)))
+
+ (`(edebug-after ,(and before-form
+ (or `(edebug-before ,before-id) before-id))
+ ,after-id ,wrapped-form)
+ (testcover-analyze-coverage-edebug-after
+ form before-form before-id after-id wrapped-form))
+
+ (`(defconst ,sym . ,args)
+ (push sym testcover-module-constants)
+ (testcover-analyze-coverage-progn args)
+ '1value)
+
+ (`(defun ,name ,_ . ,doc-and-body)
+ (let ((val (testcover-analyze-coverage-progn doc-and-body)))
+ (cl-case val
+ ((1value) (push name testcover-module-1value-functions))
+ ((maybe) (push name testcover-module-potentially-1value-functions)))
+ nil))
+
+ (`(quote . ,_)
+ ;; A quoted form is 1value. Edebug could have instrumented
+ ;; something inside the form if an Edebug spec contained a quote.
+ ;; It's also possible that the quoted form is a circular object.
+ ;; To avoid infinite recursion, don't examine quoted objects.
+ ;; This will cause the coverage marks on an instrumented quoted
+ ;; form to look odd. See bug#25316.
+ '1value)
+
+ (`(\` ,bq-form)
+ (testcover-analyze-coverage-backquote-form bq-form))
+
+ ((or 't 'nil (pred keywordp))
+ '1value)
+
+ ((pred vectorp)
+ (testcover-analyze-coverage-compose (append form nil)
+ #'testcover-analyze-coverage))
+
+ ((pred symbolp)
+ nil)
+
+ ((pred atom)
+ '1value)
+
+ (_
+ ;; Whatever we have here, it's not wrapped, so treat it as a list of forms.
+ (testcover-analyze-coverage-compose form #'testcover-analyze-coverage))))
+
+(defun testcover-analyze-coverage-progn (forms)
+ "Analyze FORMS, which should be a list of forms, for code coverage.
+Analyze all the forms in FORMS and return 1value, maybe or nil
+depending on the analysis of the last one. Find the coverage
+vectors referenced by `edebug-enter' forms nested within FORMS and
+update them with the results of the analysis."
+ (let ((result '1value))
+ (while (consp forms)
+ (setq result (testcover-analyze-coverage (pop forms))))
+ result))
+
+(defun testcover-analyze-coverage-edebug-after (_form before-form before-id
+ after-id wrapped-form
+ &optional wrapper)
+ "Analyze a _FORM wrapped by `edebug-after' for code coverage.
+_FORM should be either:
+ (edebug-after (edebug-before BEFORE-ID) AFTER-ID WRAPPED-FORM)
+or:
+ (edebug-after 0 AFTER-ID WRAPPED-FORM)
+
+where BEFORE-FORM is bound to either (edebug-before BEFORE-ID) or
+0. WRAPPER may be 1value or noreturn, and if so it forces the
+form to be treated accordingly."
+ (let (val)
+ (unless (eql before-form 0)
+ (aset testcover-vector before-id 'ok-coverage))
+
+ (setq val (testcover-analyze-coverage-wrapped-form wrapped-form))
+ (when (or (eq wrapper '1value) val)
+ ;; The form is 1-valued or potentially 1-valued.
+ (aset testcover-vector after-id (or val '1value)))
+
+ (cond
+ ((or (eq wrapper 'noreturn)
+ (memq (car-safe wrapped-form) testcover-noreturn-functions))
+ ;; This function won't return, so indicate to testcover-before that
+ ;; it should record coverage.
+ (aset testcover-vector before-id (cons 'noreturn after-id))
+ (aset testcover-vector after-id '1value)
+ (setq val '1value))
+
+ ((eq (car-safe wrapped-form) '1value)
+ ;; This function is always supposed to return the same value.
+ (setq val '1value)
+ (aset testcover-vector after-id '1value)))
+ val))
+
+(defun testcover-analyze-coverage-wrapped-form (form)
+ "Analyze a FORM for code coverage which was wrapped by `edebug-after'.
+FORM is treated as if it will be evaluated."
+ (pcase form
+ ((pred keywordp)
+ '1value)
+ ((pred symbolp)
+ (when (or (memq form testcover-constants)
+ (memq form testcover-module-constants))
+ '1value))
+ ((pred atom)
+ '1value)
+ (`(\` ,bq-form)
+ (testcover-analyze-coverage-backquote-form bq-form))
+ (`(defconst ,sym ,val . ,_)
+ (push sym testcover-module-constants)
+ (testcover-analyze-coverage val)
+ '1value)
+ (`(,(or 'dotimes 'dolist) (,_ ,expr . ,result) . ,body)
+ ;; These always return RESULT if provided.
+ (testcover-analyze-coverage expr)
+ (testcover-analyze-coverage-progn body)
+ (let ((val (testcover-analyze-coverage-progn result)))
+ ;; If the third value is not present, the loop always returns nil.
+ (if result val '1value)))
+ (`(,(or 'let 'let*) ,bindings . ,body)
+ (testcover-analyze-coverage-progn bindings)
+ (testcover-analyze-coverage-progn body))
+ (`(if ,test ,then-form . ,else-body)
+ ;; `if' is potentially 1-valued if both THEN and ELSE clauses are.
+ (testcover-analyze-coverage test)
+ (let ((then (testcover-analyze-coverage then-form))
+ (else (testcover-analyze-coverage else-body)))
+ (and then else 'maybe)))
+ (`(cond . ,clauses)
+ ;; `cond' is potentially 1-valued if all clauses are.
+ (when (testcover-analyze-coverage-compose clauses #'testcover-analyze-coverage-progn)
+ 'maybe))
+ (`(condition-case ,_ ,body-form . ,handlers)
+ ;; `condition-case' is potentially 1-valued if BODY-FORM is and all
+ ;; HANDLERS are.
+ (let ((body (testcover-analyze-coverage body-form))
+ (errs (testcover-analyze-coverage-compose
+ (mapcar #'cdr handlers)
+ #'testcover-analyze-coverage-progn)))
+ (and body errs 'maybe)))
+ (`(apply (quote ,(and func (pred symbolp))) . ,args)
+ ;; Process application of a constant symbol as 1value or noreturn
+ ;; depending on the symbol.
+ (let ((temp-form (cons func args)))
+ (testcover-analyze-coverage-wrapped-form temp-form)))
+ (`(,(and func (or '1value 'noreturn)) ,inner-form)
+ ;; 1value and noreturn change how the edebug-after they wrap is handled.
+ (let ((val (if (eq func '1value) '1value 'maybe)))
+ (pcase inner-form
+ (`(edebug-after ,(and before-form
+ (or `(edebug-before ,before-id) before-id))
+ ,after-id ,wrapped-form)
+ (testcover-analyze-coverage-edebug-after inner-form before-form
+ before-id after-id
+ wrapped-form func))
+ (_ (testcover-analyze-coverage inner-form)))
+ val))
+ (`(,func . ,args)
+ (testcover-analyze-coverage-wrapped-application func args))))
+
+(defun testcover-analyze-coverage-wrapped-application (func args)
+ "Analyze the application of FUNC to ARGS for code coverage."
+ (cond
+ ((eq func 'quote) '1value)
+ ((or (memq func testcover-1value-functions)
+ (memq func testcover-module-1value-functions))
+ ;; The function should always return the same value.
+ (testcover-analyze-coverage-progn args)
+ '1value)
+ ((or (memq func testcover-potentially-1value-functions)
+ (memq func testcover-module-potentially-1value-functions))
+ ;; The function might always return the same value.
+ (testcover-analyze-coverage-progn args)
+ 'maybe)
+ ((memq func testcover-progn-functions)
+ ;; The function is 1-valued if the last argument is.
+ (testcover-analyze-coverage-progn args))
+ ((memq func testcover-prog1-functions)
+ ;; The function is 1-valued if first argument is.
+ (testcover-analyze-coverage-progn (cdr args))
+ (testcover-analyze-coverage (car args)))
+ ((memq func testcover-compose-functions)
+ ;; The function is 1-valued if all arguments are, and potentially
+ ;; 1-valued if all arguments are either definitely or potentially.
+ (testcover-analyze-coverage-compose args #'testcover-analyze-coverage))
+ (t (testcover-analyze-coverage-progn args)
+ nil)))
+
+(defun testcover-coverage-combine (result val)
+ "Combine RESULT with VAL and return the new result.
+If either argument is nil, return nil, otherwise if either
+argument is maybe, return maybe. Return 1value only if both arguments
+are 1value."
+ (cl-case val
+ (1value result)
+ (maybe (and result 'maybe))
+ (nil nil)))
+
+(defun testcover-analyze-coverage-compose (forms func)
+ "Analyze a list of FORMS for code coverage using FUNC.
+The list is 1valued if all of its constituent elements are also 1valued."
+ (let ((result '1value))
+ (dolist (form forms)
+ (let ((val (funcall func form)))
+ (setq result (testcover-coverage-combine result val))))
+ result))
+
+(defun testcover-analyze-coverage-backquote (bq-list)
+ "Analyze BQ-LIST, the body of a backquoted list, for code coverage."
+ (let ((result '1value))
+ (while (consp bq-list)
+ (let ((form (car bq-list))
+ val)
+ (if (memq form (list '\, '\,@))
+ ;; Correctly handle `(foo bar . ,(baz).
+ (progn
+ (setq val (testcover-analyze-coverage (cdr bq-list)))
+ (setq bq-list nil))
+ (setq val (testcover-analyze-coverage-backquote-form form))
+ (setq bq-list (cdr bq-list)))
+ (setq result (testcover-coverage-combine result val))))
+ result))
+
+(defun testcover-analyze-coverage-backquote-form (form)
+ "Analyze a single FORM from a backquoted list for code coverage."
+ (cond
+ ((vectorp form) (testcover-analyze-coverage-backquote (append form nil)))
+ ((atom form) '1value)
+ ((memq (car form) (list '\, '\,@))
+ (testcover-analyze-coverage (cadr form)))
+ (t (testcover-analyze-coverage-backquote form))))
+
;; testcover.el ends here.
diff --git a/lisp/epa.el b/lisp/epa.el
index 6e908e1aa3b..aca9aaa7d22 100644
--- a/lisp/epa.el
+++ b/lisp/epa.el
@@ -561,7 +561,7 @@ If SECRET is non-nil, list secret keys instead of public keys."
(epg-sub-key-creation-time (car pointer)))
(error "????-??-??"))
(if (epg-sub-key-expiration-time (car pointer))
- (format (if (time-less-p (current-time)
+ (format (if (time-less-p nil
(epg-sub-key-expiration-time
(car pointer)))
"\n\tExpires: %s"
diff --git a/lisp/erc/erc.el b/lisp/erc/erc.el
index 0e56b732d81..fdc4a647777 100644
--- a/lisp/erc/erc.el
+++ b/lisp/erc/erc.el
@@ -2548,9 +2548,7 @@ consumption for long-lived IRC or Emacs sessions."
(maphash
(lambda (nick last-PRIVMSG-time)
(when
- (> (float-time (time-subtract
- (current-time)
- last-PRIVMSG-time))
+ (> (float-time (time-subtract nil last-PRIVMSG-time))
erc-lurker-threshold-time)
(remhash nick hash)))
hash)
@@ -2617,7 +2615,7 @@ server within `erc-lurker-threshold-time'. See also
(gethash server erc-lurker-state (make-hash-table)))))
(or (null last-PRIVMSG-time)
(> (float-time
- (time-subtract (current-time) last-PRIVMSG-time))
+ (time-subtract nil last-PRIVMSG-time))
erc-lurker-threshold-time))))
(defcustom erc-common-server-suffixes
diff --git a/lisp/files.el b/lisp/files.el
index 211457ac7d7..666654da2c9 100644
--- a/lisp/files.el
+++ b/lisp/files.el
@@ -4484,8 +4484,8 @@ extension, the value is \"\"."
"")))))
(defun file-name-base (&optional filename)
- "Return the base name of the FILENAME: no directory, no extension.
-FILENAME defaults to `buffer-file-name'."
+ "Return the base name of the FILENAME: no directory, no extension."
+ (declare (advertised-calling-convention (filename) "27.1"))
(file-name-sans-extension
(file-name-nondirectory (or filename (buffer-file-name)))))
@@ -6386,58 +6386,31 @@ if you want to specify options, use `directory-free-space-args'.
A value of nil disables this feature.
-If the function `file-system-info' is defined, it is always used in
-preference to the program given by this variable."
+This variable is obsolete; Emacs no longer uses it."
:type '(choice (string :tag "Program") (const :tag "None" nil))
:group 'dired)
+(make-obsolete-variable 'directory-free-space-program
+ "ignored, as Emacs uses `file-system-info' instead"
+ "27.1")
(defcustom directory-free-space-args
(purecopy (if (eq system-type 'darwin) "-k" "-Pk"))
"Options to use when running `directory-free-space-program'."
:type 'string
:group 'dired)
+(make-obsolete-variable 'directory-free-space-args
+ "ignored, as Emacs uses `file-system-info' instead"
+ "27.1")
(defun get-free-disk-space (dir)
"Return the amount of free space on directory DIR's file system.
The return value is a string describing the amount of free
space (normally, the number of free 1KB blocks).
-This function calls `file-system-info' if it is available, or
-invokes the program specified by `directory-free-space-program'
-and `directory-free-space-args'. If the system call or program
-is unsuccessful, or if DIR is a remote directory, this function
-returns nil."
- (unless (file-remote-p (expand-file-name dir))
- ;; Try to find the number of free blocks. Non-Posix systems don't
- ;; always have df, but might have an equivalent system call.
- (if (fboundp 'file-system-info)
- (let ((fsinfo (file-system-info dir)))
- (if fsinfo
- (format "%.0f" (/ (nth 2 fsinfo) 1024))))
- (setq dir (expand-file-name dir))
- (save-match-data
- (with-temp-buffer
- (when (and directory-free-space-program
- ;; Avoid failure if the default directory does
- ;; not exist (Bug#2631, Bug#3911).
- (let ((default-directory
- (locate-dominating-file dir 'file-directory-p)))
- (eq (process-file directory-free-space-program
- nil t nil
- directory-free-space-args
- (file-relative-name dir))
- 0)))
- ;; Assume that the "available" column is before the
- ;; "capacity" column. Find the "%" and scan backward.
- (goto-char (point-min))
- (forward-line 1)
- (when (re-search-forward
- "[[:space:]]+[^[:space:]]+%[^%]*$"
- (line-end-position) t)
- (goto-char (match-beginning 0))
- (let ((endpt (point)))
- (skip-chars-backward "^[:space:]")
- (buffer-substring-no-properties (point) endpt)))))))))
+If DIR's free space cannot be obtained, this function returns nil."
+ (let ((avail (nth 2 (file-system-info dir))))
+ (if avail
+ (format "%.0f" (/ avail 1024)))))
;; The following expression replaces `dired-move-to-filename-regexp'.
(defvar directory-listing-before-filename-regexp
diff --git a/lisp/gnus/gnus-agent.el b/lisp/gnus/gnus-agent.el
index daf578180f2..6e7cc57a4cc 100644
--- a/lisp/gnus/gnus-agent.el
+++ b/lisp/gnus/gnus-agent.el
@@ -1513,7 +1513,7 @@ downloaded into the agent."
(let* ((fetched-articles (list nil))
(tail-fetched-articles fetched-articles)
(dir (gnus-agent-group-pathname group))
- (date (time-to-days (current-time)))
+ (date (time-to-days nil))
(case-fold-search t)
pos crosses
(file-name-coding-system nnmail-pathname-coding-system))
@@ -3089,7 +3089,7 @@ FORCE is equivalent to setting the expiration predicates to true."
(nov-entries-deleted 0)
(info (gnus-get-info group))
(alist gnus-agent-article-alist)
- (day (- (time-to-days (current-time))
+ (day (- (time-to-days nil)
(gnus-agent-find-parameter group 'agent-days-until-old)))
(specials (if (and alist
(not force))
@@ -3824,7 +3824,7 @@ has been fetched."
;; be expired later.
(gnus-agent-load-alist group)
(gnus-agent-save-alist group (list article)
- (time-to-days (current-time))))))
+ (time-to-days nil)))))
(defun gnus-agent-regenerate-group (group &optional reread)
"Regenerate GROUP.
diff --git a/lisp/gnus/gnus-art.el b/lisp/gnus/gnus-art.el
index c130dc1b6c6..97aa878ab63 100644
--- a/lisp/gnus/gnus-art.el
+++ b/lisp/gnus/gnus-art.el
@@ -3628,8 +3628,7 @@ possible values."
(defun article-lapsed-string (time &optional max-segments)
;; If the date is seriously mangled, the timezone functions are
;; liable to bug out, so we ignore all errors.
- (let* ((now (current-time))
- (real-time (time-subtract now time))
+ (let* ((real-time (time-subtract nil time))
(real-sec (and real-time
(+ (* (float (car real-time)) 65536)
(cadr real-time))))
diff --git a/lisp/gnus/gnus-cloud.el b/lisp/gnus/gnus-cloud.el
index 5ea2d691f15..c57576cf3c7 100644
--- a/lisp/gnus/gnus-cloud.el
+++ b/lisp/gnus/gnus-cloud.el
@@ -219,7 +219,7 @@ easy interactive way to set this from the Server buffer."
Use old data if FORCE-OLDER is not nil."
(let* ((contents (plist-get elem :contents))
(date (or (plist-get elem :timestamp) "0"))
- (now (gnus-cloud-timestamp (current-time)))
+ (now (gnus-cloud-timestamp nil))
(newer (string-lessp date now))
(group-info (gnus-get-info group)))
(if (and contents
@@ -486,7 +486,7 @@ Otherwise, returns the Gnus Cloud data chunks."
(gnus-method-to-server
(gnus-find-method-for-group (gnus-info-group info))))
- (push `(:type :newsrc-data :name ,(gnus-info-group info) :contents ,info :timestamp ,(gnus-cloud-timestamp (current-time)))
+ (push `(:type :newsrc-data :name ,(gnus-info-group info) :contents ,info :timestamp ,(gnus-cloud-timestamp nil))
infos)))
infos))
diff --git a/lisp/gnus/gnus-group.el b/lisp/gnus/gnus-group.el
index 985efe6272f..1174f90e1ad 100644
--- a/lisp/gnus/gnus-group.el
+++ b/lisp/gnus/gnus-group.el
@@ -4560,7 +4560,7 @@ or `gnus-group-catchup-group-hook'."
"Return the offset in seconds from the timestamp for GROUP to the current time, as a floating point number."
(let* ((time (or (gnus-group-timestamp group)
(list 0 0)))
- (delta (time-subtract (current-time) time)))
+ (delta (time-subtract nil time)))
(+ (* (nth 0 delta) 65536.0)
(nth 1 delta))))
diff --git a/lisp/gnus/gnus-html.el b/lisp/gnus/gnus-html.el
index 6d529558f73..7fa36359f67 100644
--- a/lisp/gnus/gnus-html.el
+++ b/lisp/gnus/gnus-html.el
@@ -99,11 +99,7 @@ fit these criteria."
(not (file-exists-p (url-cache-create-filename url))))
(t (let ((cache-time (url-is-cached url)))
(if cache-time
- (time-less-p
- (time-add
- cache-time
- ttl)
- (current-time))
+ (time-less-p (time-add cache-time ttl) nil)
t)))))
;;;###autoload
diff --git a/lisp/gnus/gnus-score.el b/lisp/gnus/gnus-score.el
index 11a45dda9ad..bc11aa528fa 100644
--- a/lisp/gnus/gnus-score.el
+++ b/lisp/gnus/gnus-score.el
@@ -1238,7 +1238,7 @@ If FORMAT, also format the current score file."
(or (not decay)
(gnus-decay-scores alist decay)))
(gnus-score-set 'touched '(t) alist)
- (gnus-score-set 'decay (list (time-to-days (current-time))) alist))
+ (gnus-score-set 'decay (list (time-to-days nil)) alist))
;; We do not respect eval and files atoms from global score
;; files.
(when (and files (not global))
@@ -2731,8 +2731,10 @@ GROUP using BNews sys file syntax."
(insert (car sfiles))
(goto-char (point-min))
;; First remove the suffix itself.
- (when (re-search-forward (concat "." score-regexp) nil t)
- (replace-match "" t t)
+ (when (re-search-forward score-regexp nil t)
+ (unless (= (match-end 0) (match-beginning 0)) ; non-empty suffix
+ (replace-match "" t t)
+ (delete-char -1)) ; remove the "." before the suffix
(goto-char (point-min))
(if (looking-at (regexp-quote kill-dir))
;; If the file name was just "SCORE", `klen' is one character
@@ -3060,7 +3062,7 @@ If ADAPT, return the home adaptive file instead."
(defun gnus-decay-scores (alist day)
"Decay non-permanent scores in ALIST."
- (let ((times (- (time-to-days (current-time)) day))
+ (let ((times (- (time-to-days nil) day))
kill entry updated score n)
(unless (zerop times) ;Done decays today already?
(while (setq entry (pop alist))
diff --git a/lisp/gnus/gnus-srvr.el b/lisp/gnus/gnus-srvr.el
index 82056cf1653..8a91973e388 100644
--- a/lisp/gnus/gnus-srvr.el
+++ b/lisp/gnus/gnus-srvr.el
@@ -452,7 +452,8 @@ The following commands are available:
(if server (error "No such server: %s" server)
(error "No server on the current line")))
(unless (assoc server gnus-server-alist)
- (error "Read-only server %s" server))
+ (error "Server %s must be deleted from your configuration files"
+ server))
(gnus-dribble-touch)
(let ((buffer-read-only nil))
(gnus-delete-line))
@@ -642,7 +643,8 @@ The following commands are available:
(unless server
(error "No server on current line"))
(unless (assoc server gnus-server-alist)
- (error "This server can't be edited"))
+ (error "Server %s must be edited in your configuration files"
+ server))
(let ((info (cdr (assoc server gnus-server-alist))))
(gnus-close-server info)
(gnus-edit-form
diff --git a/lisp/gnus/gnus.el b/lisp/gnus/gnus.el
index 8c0846be9f7..ba4291a321a 100644
--- a/lisp/gnus/gnus.el
+++ b/lisp/gnus/gnus.el
@@ -2592,7 +2592,9 @@ a string, be sure to use a valid format, see RFC 2616."
(defvar gnus-group-history nil)
(defvar gnus-server-alist nil
- "List of available servers.")
+ "Servers created by Gnus, or via the server buffer.
+Servers defined in the user's config files do not appear here.
+This variable is persisted in the user's .newsrc.eld file.")
(defcustom gnus-cache-directory
(nnheader-concat gnus-directory "cache/")
diff --git a/lisp/gnus/message.el b/lisp/gnus/message.el
index 38aea31840f..acb55463f7f 100644
--- a/lisp/gnus/message.el
+++ b/lisp/gnus/message.el
@@ -4390,7 +4390,7 @@ This function could be useful in `message-setup-hook'."
(if (string= encoded bog)
""
(format " (%s)" encoded))))))
- (error "Bogus address"))))))))
+ (user-error "Bogus address"))))))))
(custom-add-option 'message-setup-hook 'message-check-recipients)
diff --git a/lisp/gnus/nndiary.el b/lisp/gnus/nndiary.el
index 2589fa80893..ca4dca4189d 100644
--- a/lisp/gnus/nndiary.el
+++ b/lisp/gnus/nndiary.el
@@ -1532,7 +1532,7 @@ all. This may very well take some time.")
;; past. A permanent schedule never expires.
(and sched
(setq sched (nndiary-last-occurrence sched))
- (time-less-p sched (current-time))))
+ (time-less-p sched nil)))
;; else
(nnheader-report 'nndiary "Could not read file %s" file)
nil)
diff --git a/lisp/gnus/nnmail.el b/lisp/gnus/nnmail.el
index db5415cf9f7..ad58d292082 100644
--- a/lisp/gnus/nnmail.el
+++ b/lisp/gnus/nnmail.el
@@ -1883,7 +1883,7 @@ If TIME is nil, then return the cutoff time for oldness instead."
(setq days (days-to-time days))
;; Compare the time with the current time.
(if (null time)
- (time-subtract (current-time) days)
+ (time-subtract nil days)
(ignore-errors (time-less-p days (time-since time)))))))))
(declare-function gnus-group-mark-article-read "gnus-group" (group article))
diff --git a/lisp/gnus/nnmaildir.el b/lisp/gnus/nnmaildir.el
index 272240f5a9f..708a3426af1 100644
--- a/lisp/gnus/nnmaildir.el
+++ b/lisp/gnus/nnmaildir.el
@@ -814,7 +814,7 @@ This variable is set by `nnmaildir-request-article'.")
(when (or isnew nattr)
(dolist (file (funcall ls ndir nil "\\`[^.]" 'nosort))
(setq x (concat ndir file))
- (and (time-less-p (nth 5 (file-attributes x)) (current-time))
+ (and (time-less-p (nth 5 (file-attributes x)) nil)
(rename-file x (concat cdir (nnmaildir--ensure-suffix file)))))
(setf (nnmaildir--grp-new group) nattr))
(setq cattr (nth 5 (file-attributes cdir)))
diff --git a/lisp/gnus/score-mode.el b/lisp/gnus/score-mode.el
index 098ecd5dc3d..3e7428493e4 100644
--- a/lisp/gnus/score-mode.el
+++ b/lisp/gnus/score-mode.el
@@ -85,7 +85,7 @@ This mode is an extended emacs-lisp mode.
(defun gnus-score-edit-insert-date ()
"Insert date in numerical format."
(interactive)
- (princ (time-to-days (current-time)) (current-buffer)))
+ (princ (time-to-days nil) (current-buffer)))
(defun gnus-score-pretty-print ()
"Format the current score file."
diff --git a/lisp/help-fns.el b/lisp/help-fns.el
index d75fec2b564..e509ce6e2a8 100644
--- a/lisp/help-fns.el
+++ b/lisp/help-fns.el
@@ -561,6 +561,8 @@ FILE is the file where FUNCTION was probably defined."
short))
(defun help-fns--analyse-function (function)
+ ;; FIXME: Document/explain the differences between FUNCTION,
+ ;; REAL-FUNCTION, DEF, and REAL-DEF.
"Return information about FUNCTION.
Returns a list of the form (REAL-FUNCTION DEF ALIASED REAL-DEF)."
(let* ((advised (and (symbolp function)
@@ -689,10 +691,15 @@ Returns a list of the form (REAL-FUNCTION DEF ALIASED REAL-DEF)."
(point))))
(terpri)(terpri)
- (pcase-let ((`(,real-function ,def ,_aliased ,real-def)
- (help-fns--analyse-function function))
- (doc-raw (documentation function t))
- (key-bindings-buffer (current-buffer)))
+ (pcase-let* ((`(,real-function ,def ,_aliased ,real-def)
+ (help-fns--analyse-function function))
+ (doc-raw (condition-case nil
+ ;; FIXME: Maybe `documentation' should return nil
+ ;; for invalid functions i.s.o. signaling an error.
+ (documentation function t)
+ ;; E.g. an alias for a not yet defined function.
+ (invalid-function nil)))
+ (key-bindings-buffer (current-buffer)))
;; If the function is autoloaded, and its docstring has
;; key substitution constructs, load the library.
@@ -703,12 +710,21 @@ Returns a list of the form (REAL-FUNCTION DEF ALIASED REAL-DEF)."
(help-fns--key-bindings function)
(with-current-buffer standard-output
- (let ((doc (help-fns--signature
- function doc-raw
- (if (subrp def) (indirect-function real-def) real-def)
- real-function key-bindings-buffer)))
+ (let ((doc (condition-case nil
+ ;; FIXME: Maybe `help-fns--signature' should return `doc'
+ ;; for invalid functions i.s.o. signaling an error.
+ (help-fns--signature
+ function doc-raw
+ (if (subrp def) (indirect-function real-def) real-def)
+ real-function key-bindings-buffer)
+ ;; E.g. an alias for a not yet defined function.
+ (invalid-function doc-raw))))
(run-hook-with-args 'help-fns-describe-function-functions function)
(insert "\n" (or doc "Not documented.")))
+ (when (or (function-get function 'pure)
+ (function-get function 'side-effect-free))
+ (insert "\nThis function does not change global state, "
+ "including the match data."))
;; Avoid asking the user annoying questions if she decides
;; to save the help buffer, when her locale's codeset
;; isn't UTF-8.
diff --git a/lisp/ibuf-ext.el b/lisp/ibuf-ext.el
index 686bc392b60..1ef7cb118cc 100644
--- a/lisp/ibuf-ext.el
+++ b/lisp/ibuf-ext.el
@@ -1033,8 +1033,11 @@ group definitions by setting `ibuffer-filter-groups' to nil."
(ibuffer-jump-to-buffer (buffer-name buf)))))
(defun ibuffer-push-filter (filter-specification)
- "Add FILTER-SPECIFICATION to `ibuffer-filtering-qualifiers'."
- (push filter-specification ibuffer-filtering-qualifiers))
+ "Add FILTER-SPECIFICATION to `ibuffer-filtering-qualifiers'.
+If FILTER-SPECIFICATION is already in the list then return nil. Otherwise,
+return the updated list."
+ (unless (member filter-specification ibuffer-filtering-qualifiers)
+ (push filter-specification ibuffer-filtering-qualifiers)))
;;;###autoload
(defun ibuffer-decompose-filter ()
@@ -1283,6 +1286,12 @@ currently used by buffers."
:reader (read-from-minibuffer "Filter by name (regexp): "))
(string-match qualifier (buffer-name buf)))
+;;;###autoload (autoload 'ibuffer-filter-by-process "ibuf-ext")
+(define-ibuffer-filter process
+ "Limit current view to buffers running a process."
+ (:description "process")
+ (get-buffer-process buf))
+
;;;###autoload (autoload 'ibuffer-filter-by-starred-name "ibuf-ext")
(define-ibuffer-filter starred-name
"Limit current view to buffers with name beginning and ending
diff --git a/lisp/ibuf-macs.el b/lisp/ibuf-macs.el
index e0c91e20edd..c30067f2f58 100644
--- a/lisp/ibuf-macs.el
+++ b/lisp/ibuf-macs.el
@@ -301,12 +301,16 @@ bound to the current value of the filter.
(defun ,fn-name (qualifier)
,(or documentation "This filter is not documented.")
(interactive (list ,reader))
- (ibuffer-push-filter (cons ',name qualifier))
- (message "%s"
- (format ,(concat (format "Filter by %s added: " description)
- " %s")
- qualifier))
- (ibuffer-update nil t))
+ (if (null (ibuffer-push-filter (cons ',name qualifier)))
+ (message "%s"
+ (format ,(concat (format "Filter by %s already applied: " description)
+ " %s")
+ qualifier))
+ (message "%s"
+ (format ,(concat (format "Filter by %s added: " description)
+ " %s")
+ qualifier))
+ (ibuffer-update nil t)))
(push (list ',name ,description
(lambda (buf qualifier)
(condition-case nil
diff --git a/lisp/ibuffer.el b/lisp/ibuffer.el
index fed9e75f177..7ed77d29921 100644
--- a/lisp/ibuffer.el
+++ b/lisp/ibuffer.el
@@ -522,6 +522,7 @@ directory, like `default-directory'."
(define-key map (kbd "/ m") 'ibuffer-filter-by-used-mode)
(define-key map (kbd "/ M") 'ibuffer-filter-by-derived-mode)
(define-key map (kbd "/ n") 'ibuffer-filter-by-name)
+ (define-key map (kbd "/ E") 'ibuffer-filter-by-process)
(define-key map (kbd "/ *") 'ibuffer-filter-by-starred-name)
(define-key map (kbd "/ f") 'ibuffer-filter-by-filename)
(define-key map (kbd "/ b") 'ibuffer-filter-by-basename)
diff --git a/lisp/image/gravatar.el b/lisp/image/gravatar.el
index 6628195cfa6..6173c8527eb 100644
--- a/lisp/image/gravatar.el
+++ b/lisp/image/gravatar.el
@@ -77,11 +77,7 @@
(not (file-exists-p (url-cache-create-filename url))))
(t (let ((cache-time (url-is-cached url)))
(if cache-time
- (time-less-p
- (time-add
- cache-time
- gravatar-cache-ttl)
- (current-time))
+ (time-less-p (time-add cache-time gravatar-cache-ttl) nil)
t)))))
(defun gravatar-get-data ()
diff --git a/lisp/ldefs-boot.el b/lisp/ldefs-boot.el
index 8a856c4ee0b..0dea176ab64 100644
--- a/lisp/ldefs-boot.el
+++ b/lisp/ldefs-boot.el
@@ -8099,12 +8099,16 @@ the constant's documentation.
\(fn M BS DOC &rest ARGS)" nil t)
+(function-put 'easy-mmode-defmap 'lisp-indent-function '1)
+
(autoload 'easy-mmode-defsyntax "easy-mmode" "\
Define variable ST as a syntax-table.
CSS contains a list of syntax specifications of the form (CHAR . SYNTAX).
\(fn ST CSS DOC &rest ARGS)" nil t)
+(function-put 'easy-mmode-defsyntax 'lisp-indent-function '1)
+
(if (fboundp 'register-definition-prefixes) (register-definition-prefixes "easy-mmode" '("easy-mmode-")))
;;;***
@@ -13076,87 +13080,31 @@ to get the effect of a C-q.
;;; Generated autoloads from progmodes/flymake.el
(push (purecopy '(flymake 0 3)) package--builtin-versions)
-(autoload 'flymake-log "flymake" "\
-Log, at level LEVEL, the message MSG formatted with ARGS.
-LEVEL is passed to `display-warning', which is used to display
-the warning. If this form is included in a byte-compiled file,
-the generated warning contains an indication of the file that
-generated it.
-
-\(fn LEVEL MSG &rest ARGS)" nil t)
-
-(autoload 'flymake-make-diagnostic "flymake" "\
-Make a Flymake diagnostic for BUFFER's region from BEG to END.
-TYPE is a key to `flymake-diagnostic-types-alist' and TEXT is a
-description of the problem detected in this region.
-
-\(fn BUFFER BEG END TYPE TEXT)" nil nil)
-
-(autoload 'flymake-diag-region "flymake" "\
-Compute BUFFER's region (BEG . END) corresponding to LINE and COL.
-If COL is nil, return a region just for LINE. Return nil if the
-region is invalid.
-
-\(fn BUFFER LINE &optional COL)" nil nil)
-
(autoload 'flymake-mode "flymake" "\
Toggle Flymake mode on or off.
With a prefix argument ARG, enable Flymake mode if ARG is
positive, and disable it otherwise. If called from Lisp, enable
the mode if ARG is omitted or nil, and toggle it if ARG is `toggle'.
-
-Flymake is an Emacs minor mode for on-the-fly syntax checking.
-Flymake collects diagnostic information from multiple sources,
-called backends, and visually annotates the buffer with the
-results.
-
-Flymake performs these checks while the user is editing. The
-customization variables `flymake-start-on-flymake-mode',
-`flymake-no-changes-timeout' and
-`flymake-start-syntax-check-on-newline' determine the exact
-circumstances whereupon Flymake decides to initiate a check of
-the buffer.
-
-The commands `flymake-goto-next-error' and
-`flymake-goto-prev-error' can be used to navigate among Flymake
-diagnostics annotated in the buffer.
-
-The visual appearance of each type of diagnostic can be changed
-in the variable `flymake-diagnostic-types-alist'.
-
-Activation or deactivation of backends used by Flymake in each
-buffer happens via the special hook
-`flymake-diagnostic-functions'.
-
-Some backends may take longer than others to respond or complete,
-and some may decide to disable themselves if they are not
-suitable for the current buffer. The commands
-`flymake-running-backends', `flymake-disabled-backends' and
-`flymake-reporting-backends' summarize the situation, as does the
-special *Flymake log* buffer.
+\\{flymake-mode-map}
\(fn &optional ARG)" t nil)
(autoload 'flymake-mode-on "flymake" "\
-Turn Flymake mode on.
+Turn flymake mode on.
\(fn)" nil nil)
(autoload 'flymake-mode-off "flymake" "\
-Turn Flymake mode off.
+Turn flymake mode off.
\(fn)" nil nil)
-(if (fboundp 'register-definition-prefixes) (register-definition-prefixes "flymake" '("flymake-")))
+(autoload 'flymake-find-file-hook "flymake" "\
-;;;***
-
-;;;### (autoloads nil "flymake-proc" "progmodes/flymake-proc.el"
-;;;;;; (0 0 0 0))
-;;; Generated autoloads from progmodes/flymake-proc.el
-(push (purecopy '(flymake-proc 0 3)) package--builtin-versions)
-(if (fboundp 'register-definition-prefixes) (register-definition-prefixes "flymake-proc" '("flymake-proc-")))
+\(fn)" nil nil)
+
+(if (fboundp 'register-definition-prefixes) (register-definition-prefixes "flymake" '("flymake-")))
;;;***
@@ -14617,7 +14565,8 @@ match any of the group-specified splitting rules. See
(autoload 'gnus-group-split-update "gnus-mlspl" "\
Computes nnmail-split-fancy from group params and CATCH-ALL.
-It does this by calling (gnus-group-split-fancy nil nil CATCH-ALL).
+It does this by calling by calling (gnus-group-split-fancy nil
+nil CATCH-ALL).
If CATCH-ALL is nil, `gnus-group-split-default-catch-all-group' is used
instead. This variable is set by `gnus-group-split-setup'.
@@ -28114,46 +28063,6 @@ than appending to it. Deletes the message after writing if
;;;***
-;;;### (autoloads nil "rmc" "emacs-lisp/rmc.el" (0 0 0 0))
-;;; Generated autoloads from emacs-lisp/rmc.el
-
-(autoload 'read-multiple-choice "rmc" "\
-Ask user a multiple choice question.
-PROMPT should be a string that will be displayed as the prompt.
-
-CHOICES is an alist where the first element in each entry is a
-character to be entered, the second element is a short name for
-the entry to be displayed while prompting (if there's room, it
-might be shortened), and the third, optional entry is a longer
-explanation that will be displayed in a help buffer if the user
-requests more help.
-
-This function translates user input into responses by consulting
-the bindings in `query-replace-map'; see the documentation of
-that variable for more information. In this case, the useful
-bindings are `recenter', `scroll-up', and `scroll-down'. If the
-user enters `recenter', `scroll-up', or `scroll-down' responses,
-perform the requested window recentering or scrolling and ask
-again.
-
-When `use-dialog-box' is t (the default), this function can pop
-up a dialog window to collect the user input. That functionality
-requires `display-popup-menus-p' to return t. Otherwise, a text
-dialog will be used.
-
-The return value is the matching entry from the CHOICES list.
-
-Usage example:
-
-\(read-multiple-choice \"Continue connecting?\"
- \\='((?a \"always\")
- (?s \"session only\")
- (?n \"no\")))
-
-\(fn PROMPT CHOICES)" nil nil)
-
-;;;***
-
;;;### (autoloads nil "rng-cmpct" "nxml/rng-cmpct.el" (0 0 0 0))
;;; Generated autoloads from nxml/rng-cmpct.el
@@ -31998,7 +31907,7 @@ Studlify-case the current buffer.
;;;### (autoloads nil "subr-x" "emacs-lisp/subr-x.el" (0 0 0 0))
;;; Generated autoloads from emacs-lisp/subr-x.el
-(if (fboundp 'register-definition-prefixes) (register-definition-prefixes "subr-x" '("string-" "hash-table-" "when-let" "internal--" "if-let" "and-let*" "thread-")))
+(if (fboundp 'register-definition-prefixes) (register-definition-prefixes "subr-x" '("read-multiple-choice" "string-" "hash-table-" "when-let" "internal--" "if-let" "and-let*" "thread-")))
;;;***
@@ -33557,7 +33466,7 @@ Return the Lisp list at point, or nil if none is found.
\(fn)" nil nil)
-(if (fboundp 'register-definition-prefixes) (register-definition-prefixes "thingatpt" '("form-at-point" "thing-at-point-" "sentence-at-point" "word-at-point" "in-string-p" "end-of-thing" "beginning-of-thing")))
+(if (fboundp 'register-definition-prefixes) (register-definition-prefixes "thingatpt" '("filename" "form-at-point" "thing-at-point-" "sentence-at-point" "word-at-point" "define-thing-chars" "in-string-p" "end-of-thing" "beginning-of-thing")))
;;;***
diff --git a/lisp/mpc.el b/lisp/mpc.el
index c23d8ced716..98f4a031834 100644
--- a/lisp/mpc.el
+++ b/lisp/mpc.el
@@ -2403,10 +2403,38 @@ This is used so that they can be compared with `eq', which is needed for
(interactive)
(mpc-cmd-pause "0"))
+(defun mpc-read-seek (prompt)
+ "Read a seek time.
+Returns a string suitable for MPD \"seekcur\" protocol command."
+ (let* ((str (read-from-minibuffer prompt nil nil nil nil nil t))
+ (seconds "\\(?1:[[:digit:]]+\\(?:\\.[[:digit:]]*\\)?\\)")
+ (minsec (concat "\\(?2:[[:digit:]]+\\):" seconds "?"))
+ (hrminsec (concat "\\(?3:[[:digit:]]+\\):\\(?:" minsec "?\\|:\\)"))
+ time sign)
+ (setq str (string-trim str))
+ (when (memq (string-to-char str) '(?+ ?-))
+ (setq sign (string (string-to-char str)))
+ (setq str (substring str 1)))
+ (setq time
+ ;; `string-to-number' returns 0 on failure
+ (cond
+ ((string-match (concat "^" hrminsec "$") str)
+ (+ (* 3600 (string-to-number (match-string 3 str)))
+ (* 60 (string-to-number (or (match-string 2 str) "")))
+ (string-to-number (or (match-string 1 str) ""))))
+ ((string-match (concat "^" minsec "$") str)
+ (+ (* 60 (string-to-number (match-string 2 str)))
+ (string-to-number (match-string 1 str))))
+ ((string-match (concat "^" seconds "$") str)
+ (string-to-number (match-string 1 str)))
+ (t (user-error "Invalid time"))))
+ (setq time (number-to-string time))
+ (if (null sign) time (concat sign time))))
+
(defun mpc-seek-current (pos)
"Seek within current track."
(interactive
- (list (read-string "Position to go ([+-]seconds): ")))
+ (list (mpc-read-seek "Position to go ([+-][[H:]M:]seconds): ")))
(mpc-cmd-seekcur pos))
(defun mpc-toggle-play ()
diff --git a/lisp/net/newst-backend.el b/lisp/net/newst-backend.el
index 5f68dea1be7..7a73d4688aa 100644
--- a/lisp/net/newst-backend.el
+++ b/lisp/net/newst-backend.el
@@ -1807,7 +1807,7 @@ If the file does no exist or if it is older than 24 hours
download it from URL first."
(let ((image-name (concat directory feed-name)))
(if (and (file-exists-p image-name)
- (time-less-p (current-time)
+ (time-less-p nil
(time-add (nth 5 (file-attributes image-name))
(seconds-to-time 86400))))
(newsticker--debug-msg "%s: Getting image for %s skipped"
@@ -2004,7 +2004,7 @@ older than TIME."
(when (eq (newsticker--age item) old-age)
(let ((exp-time (time-add (newsticker--time item)
(seconds-to-time time))))
- (when (time-less-p exp-time (current-time))
+ (when (time-less-p exp-time nil)
(newsticker--debug-msg
"Item `%s' from %s has expired on %s"
(newsticker--title item)
diff --git a/lisp/net/trampver.el b/lisp/net/trampver.el
index 318e3351237..51af455e635 100644
--- a/lisp/net/trampver.el
+++ b/lisp/net/trampver.el
@@ -7,7 +7,7 @@
;; Maintainer: Michael Albinus <michael.albinus@gmx.de>
;; Keywords: comm, processes
;; Package: tramp
-;; Version: 2.3.3.26.1
+;; Version: 2.3.3-pre
;; This file is part of GNU Emacs.
@@ -33,7 +33,7 @@
;; should be changed only there.
;;;###tramp-autoload
-(defconst tramp-version "2.3.3.26.1"
+(defconst tramp-version "2.3.3-pre"
"This version of Tramp.")
;;;###tramp-autoload
@@ -55,7 +55,7 @@
;; Check for Emacs version.
(let ((x (if (>= emacs-major-version 24)
"ok"
- (format "Tramp 2.3.3.26.1 is not fit for %s"
+ (format "Tramp 2.3.3-pre is not fit for %s"
(when (string-match "^.*$" (emacs-version))
(match-string 0 (emacs-version)))))))
(unless (string-match "\\`ok\\'" x) (error "%s" x)))
diff --git a/lisp/newcomment.el b/lisp/newcomment.el
index 2a0f8a8ae50..2e644c3a99c 100644
--- a/lisp/newcomment.el
+++ b/lisp/newcomment.el
@@ -524,7 +524,7 @@ Ensure that `comment-normalize-vars' has been called before you use this."
;; comment-search-backward is only used to find the comment-column (in
;; comment-set-column) and to find the comment-start string (via
;; comment-beginning) in indent-new-comment-line, it should be harmless.
- (if (not (re-search-backward comment-start-skip limit t))
+ (if (not (re-search-backward comment-start-skip limit 'move))
(unless noerror (error "No comment"))
(beginning-of-line)
(let* ((end (match-end 0))
diff --git a/lisp/nxml/rng-maint.el b/lisp/nxml/rng-maint.el
index 85614822be8..8d85f2ea06b 100644
--- a/lisp/nxml/rng-maint.el
+++ b/lisp/nxml/rng-maint.el
@@ -226,11 +226,10 @@
(defun rng-time-function (function &rest args)
(let* ((start (current-time))
- (val (apply function args))
- (end (current-time)))
+ (val (apply function args)))
(message "%s ran in %g seconds"
function
- (float-time (time-subtract end start)))
+ (float-time (time-subtract nil start)))
val))
(defun rng-time-tokenize-buffer ()
diff --git a/lisp/org/org-agenda.el b/lisp/org/org-agenda.el
index cf7a4dbf38b..49519471b38 100644
--- a/lisp/org/org-agenda.el
+++ b/lisp/org/org-agenda.el
@@ -10153,7 +10153,7 @@ to override `appt-message-warning-time'."
;; time and without date as argument, so it may pass wrong
;; information otherwise
(today (org-date-to-gregorian
- (time-to-days (current-time))))
+ (time-to-days nil)))
(org-agenda-restrict nil)
(files (org-agenda-files 'unrestricted)) entries file
(org-agenda-buffer nil))
diff --git a/lisp/org/org-clock.el b/lisp/org/org-clock.el
index 9dc501500b1..eb7080bb8be 100644
--- a/lisp/org/org-clock.el
+++ b/lisp/org/org-clock.el
@@ -950,7 +950,7 @@ If necessary, clock-out of the currently active clock."
(unless (org-is-active-clock clock)
(org-clock-clock-in clock t))))
- ((not (time-less-p resolve-to (current-time)))
+ ((not (time-less-p resolve-to nil))
(error "RESOLVE-TO must refer to a time in the past"))
(t
@@ -1052,7 +1052,7 @@ to be CLOCKED OUT."))))
(and (not (memq char-pressed '(?i ?q))) char-pressed)))))
(default
(floor (/ (float-time
- (time-subtract (current-time) last-valid)) 60)))
+ (time-subtract nil last-valid)) 60)))
(keep
(and (memq ch '(?k ?K))
(read-number "Keep how many minutes? " default)))
@@ -1089,8 +1089,7 @@ to be CLOCKED OUT."))))
(keep
(time-add last-valid (seconds-to-time (* 60 keep))))
(gotback
- (time-subtract (current-time)
- (seconds-to-time (* 60 gotback))))
+ (time-subtract nil (seconds-to-time (* 60 gotback))))
(t
(error "Unexpected, please report this as a bug")))
(and gotback last-valid)
@@ -1172,7 +1171,7 @@ so long."
org-clock-marker (marker-buffer org-clock-marker))
(let* ((org-clock-user-idle-seconds (org-user-idle-seconds))
(org-clock-user-idle-start
- (time-subtract (current-time)
+ (time-subtract nil
(seconds-to-time org-clock-user-idle-seconds)))
(org-clock-resolving-clocks-due-to-idleness t))
(if (> org-clock-user-idle-seconds (* 60 org-clock-idle-time))
@@ -1182,8 +1181,7 @@ so long."
(lambda (_)
(format "Clocked in & idle for %.1f mins"
(/ (float-time
- (time-subtract (current-time)
- org-clock-user-idle-start))
+ (time-subtract nil org-clock-user-idle-start))
60.0)))
org-clock-user-idle-start)))))
diff --git a/lisp/org/org-colview.el b/lisp/org/org-colview.el
index eac29c50f65..80f4929b95c 100644
--- a/lisp/org/org-colview.el
+++ b/lisp/org/org-colview.el
@@ -540,7 +540,7 @@ Where possible, use the standard interface for changing this line."
(eol (line-end-position))
(pom (or (get-text-property bol 'org-hd-marker) (point)))
(key (or key (get-char-property (point) 'org-columns-key)))
- (org-columns--time (float-time (current-time)))
+ (org-columns--time (float-time))
(action
(pcase key
("CLOCKSUM"
@@ -790,7 +790,7 @@ When COLUMNS-FMT-STRING is non-nil, use it as the column format."
(org-columns-goto-top-level)
;; Initialize `org-columns-current-fmt' and
;; `org-columns-current-fmt-compiled'.
- (let ((org-columns--time (float-time (current-time))))
+ (let ((org-columns--time (float-time)))
(org-columns-get-format columns-fmt-string)
(unless org-columns-inhibit-recalculation (org-columns-compute-all))
(save-excursion
@@ -1182,7 +1182,7 @@ column specification."
"Compute all columns that have operators defined."
(org-with-silent-modifications
(remove-text-properties (point-min) (point-max) '(org-summaries t)))
- (let ((org-columns--time (float-time (current-time)))
+ (let ((org-columns--time (float-time))
seen)
(dolist (spec org-columns-current-fmt-compiled)
(let ((property (car spec)))
@@ -1494,7 +1494,7 @@ PARAMS is a property list of parameters:
(if (markerp org-columns-begin-marker)
(move-marker org-columns-begin-marker (point))
(setq org-columns-begin-marker (point-marker)))
- (let* ((org-columns--time (float-time (current-time)))
+ (let* ((org-columns--time (float-time))
(fmt
(cond
((bound-and-true-p org-agenda-overriding-columns-format))
diff --git a/lisp/org/org-element.el b/lisp/org/org-element.el
index f2b3002f1fd..73012cd2681 100644
--- a/lisp/org/org-element.el
+++ b/lisp/org/org-element.el
@@ -5067,7 +5067,7 @@ Assume ELEMENT belongs to cache and that a cache is active."
TIME-LIMIT is a time value or nil."
(and time-limit
(or (input-pending-p)
- (time-less-p time-limit (current-time)))))
+ (time-less-p time-limit nil))))
(defsubst org-element--cache-shift-positions (element offset &optional props)
"Shift ELEMENT properties relative to buffer positions by OFFSET.
@@ -5121,7 +5121,7 @@ updated before current modification are actually submitted."
(and next (aref next 0))
threshold
(and (not threshold)
- (time-add (current-time)
+ (time-add nil
org-element-cache-sync-duration))
future-change)
;; Request processed. Merge current and next offsets and
diff --git a/lisp/org/org-habit.el b/lisp/org/org-habit.el
index 89b75e6f680..c867c840b0e 100644
--- a/lisp/org/org-habit.el
+++ b/lisp/org/org-habit.el
@@ -288,7 +288,7 @@ Habits are assigned colors on the following basis:
(deadline (if scheduled-days
(+ scheduled-days (- d-repeat s-repeat))
(org-habit-deadline habit)))
- (m-days (or now-days (time-to-days (current-time)))))
+ (m-days (or now-days (time-to-days nil))))
(cond
((< m-days scheduled)
'(org-habit-clear-face . org-habit-clear-future-face))
@@ -406,7 +406,7 @@ current time."
"Insert consistency graph for any habitual tasks."
(let ((inhibit-read-only t)
(buffer-invisibility-spec '(org-link))
- (moment (time-subtract (current-time)
+ (moment (time-subtract nil
(list 0 (* 3600 org-extend-today-until) 0))))
(save-excursion
(goto-char (if line (point-at-bol) (point-min)))
diff --git a/lisp/org/org-indent.el b/lisp/org/org-indent.el
index b34586e09ec..35c1f22719e 100644
--- a/lisp/org/org-indent.el
+++ b/lisp/org/org-indent.el
@@ -325,7 +325,7 @@ stopped."
(let* ((case-fold-search t)
(limited-re (org-get-limited-outline-regexp))
(level (or (org-current-level) 0))
- (time-limit (and delay (time-add (current-time) delay))))
+ (time-limit (and delay (time-add nil delay))))
;; For each line, set `line-prefix' and `wrap-prefix'
;; properties depending on the type of line (headline, inline
;; task, item or other).
@@ -338,7 +338,7 @@ stopped."
;; In asynchronous mode, take a break of
;; `org-indent-agent-resume-delay' every DELAY to avoid
;; blocking any other idle timer or process output.
- ((and delay (time-less-p time-limit (current-time)))
+ ((and delay (time-less-p time-limit nil))
(setq org-indent-agent-resume-timer
(run-with-idle-timer
(time-add (current-idle-time) org-indent-agent-resume-delay)
diff --git a/lisp/org/org-timer.el b/lisp/org/org-timer.el
index 5acf526f183..7617a3810f9 100644
--- a/lisp/org/org-timer.el
+++ b/lisp/org/org-timer.el
@@ -144,7 +144,7 @@ the region 0:00:00."
;; Pass `current-time' result to `float-time' (instead
;; of calling without arguments) so that only
;; `current-time' has to be overridden in tests.
- (- (float-time (current-time)) delta))))
+ (- (float-time) delta))))
(setq org-timer-pause-time nil)
(org-timer-set-mode-line 'on)
(message "Timer start time set to %s, current value is %s"
@@ -168,12 +168,12 @@ With prefix arg STOP, stop it entirely."
(org-timer--run-countdown-timer
new-secs org-timer-countdown-timer-title))
(setq org-timer-start-time
- (time-add (current-time) (seconds-to-time new-secs))))
+ (time-add nil (seconds-to-time new-secs))))
(setq org-timer-start-time
;; Pass `current-time' result to `float-time' (instead
;; of calling without arguments) so that only
;; `current-time' has to be overridden in tests.
- (seconds-to-time (- (float-time (current-time))
+ (seconds-to-time (- (float-time)
(- pause-secs start-secs)))))
(setq org-timer-pause-time nil)
(org-timer-set-mode-line 'on)
@@ -238,8 +238,8 @@ it in the buffer."
;; overridden in tests.
(if org-timer-countdown-timer
(- (float-time org-timer-start-time)
- (float-time (or org-timer-pause-time (current-time))))
- (- (float-time (or org-timer-pause-time (current-time)))
+ (float-time org-timer-pause-time))
+ (- (float-time org-timer-pause-time)
(float-time org-timer-start-time))))
;;;###autoload
@@ -400,7 +400,7 @@ VALUE can be `on', `off', or `paused'."
(message "No timer set")
(let* ((rtime (decode-time
(time-subtract (timer--time org-timer-countdown-timer)
- (current-time))))
+ nil)))
(rsecs (nth 0 rtime))
(rmins (nth 1 rtime)))
(message "%d minute(s) %d seconds left before next time out"
@@ -464,7 +464,7 @@ using three `C-u' prefix arguments."
secs org-timer-countdown-timer-title))
(run-hooks 'org-timer-set-hook)
(setq org-timer-start-time
- (time-add (current-time) (seconds-to-time secs)))
+ (time-add nil (seconds-to-time secs)))
(setq org-timer-pause-time nil)
(org-timer-set-mode-line 'on))))))
diff --git a/lisp/org/org.el b/lisp/org/org.el
index 35405b4bf81..569bc9f8ec1 100644
--- a/lisp/org/org.el
+++ b/lisp/org/org.el
@@ -227,7 +227,7 @@ file to byte-code before it is loaded."
(interactive "fFile to load: \nP")
(let* ((age (lambda (file)
(float-time
- (time-subtract (current-time)
+ (time-subtract nil
(nth 5 (or (file-attributes (file-truename file))
(file-attributes file)))))))
(base-name (file-name-sans-extension file))
@@ -5597,15 +5597,14 @@ the rounding returns a past time."
(apply 'encode-time
(append (list 0 (* r (floor (+ .5 (/ (float (nth 1 time)) r)))))
(nthcdr 2 time))))
- (if (and past (< (float-time (time-subtract (current-time) res)) 0))
+ (if (and past (< (float-time (time-subtract nil res)) 0))
(seconds-to-time (- (float-time res) (* r 60)))
res))))
(defun org-today ()
"Return today date, considering `org-extend-today-until'."
(time-to-days
- (time-subtract (current-time)
- (list 0 (* 3600 org-extend-today-until) 0))))
+ (time-subtract nil (list 0 (* 3600 org-extend-today-until) 0))))
;;;; Font-Lock stuff, including the activators
@@ -13057,8 +13056,7 @@ This function is run automatically after each state change to a DONE state."
(while (re-search-forward org-clock-line-re end t)
(when (org-at-clock-log-p) (throw :clock t))))))
(org-entry-put nil "LAST_REPEAT" (format-time-string
- (org-time-stamp-format t t)
- (current-time))))
+ (org-time-stamp-format t t))))
(when org-log-repeat
(if (or (memq 'org-add-log-note (default-value 'post-command-hook))
(memq 'org-add-log-note post-command-hook))
@@ -13117,7 +13115,7 @@ has been set"
(let ((nshiftmax 10)
(nshift 0))
(while (or (= nshift 0)
- (not (time-less-p (current-time) time)))
+ (not (time-less-p nil time)))
(when (= (cl-incf nshift) nshiftmax)
(or (y-or-n-p
(format "%d repeater intervals were not \
@@ -16904,7 +16902,7 @@ user."
;; overridden in tests.
(let ((org-def def)
(org-defdecode defdecode)
- (nowdecode (decode-time (current-time)))
+ (nowdecode (decode-time))
delta deltan deltaw deltadef year month day
hour minute second wday pm h2 m2 tl wday1
iso-year iso-weekday iso-week iso-date futurep kill-year)
@@ -17070,7 +17068,7 @@ user."
; (when (and org-read-date-prefer-future
; (not iso-year)
; (< (calendar-absolute-from-gregorian iso-date)
- ; (time-to-days (current-time))))
+ ; (time-to-days nil)))
; (setq year (1+ year)
; iso-date (calendar-gregorian-from-absolute
; (calendar-iso-to-absolute
@@ -17084,7 +17082,7 @@ user."
;; Pass `current-time' result to `decode-time' (instead of
;; calling without arguments) so that only `current-time' has
;; to be overridden in tests.
- (let ((now (decode-time (current-time))))
+ (let ((now (decode-time)))
(setq day (nth 3 now) month (nth 4 now) year (nth 5 now))))
(cond ((member deltaw '("d" "")) (setq day (+ day deltan)))
((equal deltaw "w") (setq day (+ day (* 7 deltan))))
@@ -17564,7 +17562,7 @@ signaled."
YEAR is expanded into one of the 30 next years, if possible, or
into a past one. Any year larger than 99 is returned unchanged."
(if (>= year 100) year
- (let* ((current (string-to-number (format-time-string "%Y" (current-time))))
+ (let* ((current (string-to-number (format-time-string "%Y")))
(century (/ current 100))
(offset (- year (% current 100))))
(cond ((> offset 30) (+ (* (1- century) 100) year))
@@ -18088,7 +18086,7 @@ A prefix ARG can be used to force the current date."
diff)
(when (or (org-at-timestamp-p 'lax)
(org-match-line (concat ".*" org-ts-regexp)))
- (let ((d1 (time-to-days (current-time)))
+ (let ((d1 (time-to-days nil))
(d2 (time-to-days (org-time-string-to-time (match-string 1)))))
(setq diff (- d2 d1))))
(calendar)
diff --git a/lisp/org/ox.el b/lisp/org/ox.el
index 1c43577cddf..820b1755624 100644
--- a/lisp/org/ox.el
+++ b/lisp/org/ox.el
@@ -3243,7 +3243,7 @@ locally for the subtree through node properties."
(let ((val (cond ((equal (car key) "DATE")
(or (cdr key)
(with-temp-buffer
- (org-insert-time-stamp (current-time)))))
+ (org-insert-time-stamp nil))))
((equal (car key) "TITLE")
(or (let ((visited-file
(buffer-file-name (buffer-base-buffer))))
diff --git a/lisp/progmodes/cperl-mode.el b/lisp/progmodes/cperl-mode.el
index 853604d1d79..1681922fa5a 100644
--- a/lisp/progmodes/cperl-mode.el
+++ b/lisp/progmodes/cperl-mode.el
@@ -2314,7 +2314,7 @@ to nil."
nil t)))) ; Only one
(progn
(forward-word-strictly 1)
- (setq name (file-name-base)
+ (setq name (file-name-base (buffer-file-name))
p (point))
(insert " NAME\n\n" name
" - \n\n=head1 SYNOPSIS\n\n\n\n"
diff --git a/lisp/progmodes/idlwave.el b/lisp/progmodes/idlwave.el
index 9231e118907..92a42b1cb94 100644
--- a/lisp/progmodes/idlwave.el
+++ b/lisp/progmodes/idlwave.el
@@ -5240,7 +5240,7 @@ Can run from `after-save-hook'."
class
(cond ((not (boundp 'idlwave-scanning-lib))
(list 'buffer (buffer-file-name)))
-; ((string= (downcase (file-name-base))
+; ((string= (downcase (file-name-base (buffer-file-name))
; (downcase name))
; (list 'lib))
; (t (cons 'lib (file-name-nondirectory (buffer-file-name))))
diff --git a/lisp/register.el b/lisp/register.el
index 913380763c6..23eefd08b88 100644
--- a/lisp/register.el
+++ b/lisp/register.el
@@ -182,8 +182,11 @@ Use \\[jump-to-register] to go to that location or restore that configuration.
Argument is a character, naming the register.
Interactively, reads the register using `register-read-with-preview'."
- (interactive (list (register-read-with-preview "Point to register: ")
- current-prefix-arg))
+ (interactive (list (register-read-with-preview
+ (if current-prefix-arg
+ "Frame configuration to register: "
+ "Point to register: "))
+ current-prefix-arg))
;; Turn the marker into a file-ref if the buffer is killed.
(add-hook 'kill-buffer-hook 'register-swap-out nil t)
(set-register register
diff --git a/lisp/subr.el b/lisp/subr.el
index c216877ce5f..a6c998e9be2 100644
--- a/lisp/subr.el
+++ b/lisp/subr.el
@@ -78,8 +78,8 @@ If FORM does return, signal an error."
(defmacro 1value (form)
"Evaluate FORM, expecting a constant return value.
-This is the global do-nothing version. There is also `testcover-1value'
-that complains if FORM ever does return differing values."
+If FORM returns differing values when running under Testcover,
+Testcover will raise an error."
(declare (debug t))
form)
diff --git a/lisp/svg.el b/lisp/svg.el
index 6a0c49b4698..42619ed3519 100644
--- a/lisp/svg.el
+++ b/lisp/svg.el
@@ -157,7 +157,21 @@ otherwise. IMAGE-TYPE should be a MIME image type, like
(dom-node
'text
`(,@(svg--arguments svg args))
- text)))
+ (svg--encode-text text))))
+
+(defun svg--encode-text (text)
+ ;; Apparently the SVG renderer needs to have all non-ASCII
+ ;; characters encoded.
+ (with-temp-buffer
+ (insert (xml-escape-string text))
+ (goto-char (point-min))
+ (while (not (eobp))
+ (let ((char (following-char)))
+ (if (< char 128)
+ (forward-char 1)
+ (delete-char 1)
+ (insert "&#" (format "%d" char) ";"))))
+ (buffer-string)))
(defun svg--append (svg node)
(let ((old (and (dom-attr node 'id)
diff --git a/lisp/term/xterm.el b/lisp/term/xterm.el
index 4f79703833d..b7d0cfb4792 100644
--- a/lisp/term/xterm.el
+++ b/lisp/term/xterm.el
@@ -68,6 +68,11 @@ string bytes that can be copied is 3/4 of this value."
:version "25.1"
:type 'integer)
+(defcustom xterm-set-window-title nil
+ "Whether Emacs should set window titles to an Emacs frame in an XTerm."
+ :version "27.1"
+ :type 'boolean)
+
(defconst xterm-paste-ending-sequence "\e[201~"
"Characters send by the terminal to end a bracketed paste.")
@@ -802,6 +807,8 @@ We run the first FUNCTION whose STRING matches the input events."
(when (memq 'setSelection xterm-extra-capabilities)
(xterm--init-activate-set-selection)))
+ (when xterm-set-window-title
+ (xterm--init-frame-title))
;; Unconditionally enable bracketed paste mode: terminals that don't
;; support it just ignore the sequence.
(xterm--init-bracketed-paste-mode)
@@ -828,6 +835,34 @@ We run the first FUNCTION whose STRING matches the input events."
"Terminal initialization for `gui-set-selection'."
(set-terminal-parameter nil 'xterm--set-selection t))
+(defun xterm--init-frame-title ()
+ "Terminal initialization for XTerm frame titles."
+ (xterm-set-window-title)
+ (add-hook 'after-make-frame-functions 'xterm-set-window-title-flag)
+ (add-hook 'window-configuration-change-hook 'xterm-unset-window-title-flag)
+ (add-hook 'post-command-hook 'xterm-set-window-title)
+ (add-hook 'minibuffer-exit-hook 'xterm-set-window-title))
+
+(defvar xterm-window-title-flag nil
+ "Whether a new frame has been created, calling for a title update.")
+
+(defun xterm-set-window-title-flag (_frame)
+ "Set `xterm-window-title-flag'.
+See `xterm--init-frame-title'"
+ (setq xterm-window-title-flag t))
+
+(defun xterm-unset-window-title-flag ()
+ (when xterm-window-title-flag
+ (setq xterm-window-title-flag nil)
+ (xterm-set-window-title)))
+
+(defun xterm-set-window-title (&optional terminal)
+ "Set the window title of the Xterm TERMINAL.
+The title is constructed from `frame-title-format'."
+ (send-string-to-terminal
+ (format "\e]2;%s\a" (format-mode-line frame-title-format))
+ terminal))
+
(defun xterm--selection-char (type)
(pcase type
('PRIMARY "p")
diff --git a/lisp/textmodes/css-mode.el b/lisp/textmodes/css-mode.el
index 39885c10860..e74efdc7a13 100644
--- a/lisp/textmodes/css-mode.el
+++ b/lisp/textmodes/css-mode.el
@@ -896,7 +896,7 @@ cannot be completed sensibly: `custom-ident',
;; No face.
nil)))
;; Variables.
- (,(concat "--" css-ident-re) (0 font-lock-variable-name-face))
+ (,(concat (rx symbol-start) "--" css-ident-re) (0 font-lock-variable-name-face))
;; Properties. Again, we don't limit ourselves to css-property-ids.
(,(concat "\\(?:[{;]\\|^\\)[ \t]*\\("
"\\(?:\\(" css-proprietary-nmstart-re "\\)\\|"
diff --git a/lisp/textmodes/page-ext.el b/lisp/textmodes/page-ext.el
index 94b68decfb7..bf1e33bf0f6 100644
--- a/lisp/textmodes/page-ext.el
+++ b/lisp/textmodes/page-ext.el
@@ -1,4 +1,4 @@
-;;; page-ext.el --- extended page handling commands
+;;; page-ext.el --- extended page handling commands -*- lexical-binding:t -*-
;; Copyright (C) 1990-1991, 1993-1994, 2001-2017 Free Software
;; Foundation, Inc.
@@ -243,18 +243,15 @@
(defcustom pages-directory-buffer-narrowing-p t
"If non-nil, `pages-directory-goto' narrows pages buffer to entry."
- :type 'boolean
- :group 'pages)
+ :type 'boolean)
(defcustom pages-directory-for-adding-page-narrowing-p t
"If non-nil, `add-new-page' narrows page buffer to new entry."
- :type 'boolean
- :group 'pages)
+ :type 'boolean)
(defcustom pages-directory-for-adding-new-page-before-current-page-p t
"If non-nil, `add-new-page' inserts new page before current page."
- :type 'boolean
- :group 'pages)
+ :type 'boolean)
;;; Addresses related variables
@@ -262,23 +259,19 @@
(defcustom pages-addresses-file-name "~/addresses"
"Standard name for file of addresses. Entries separated by page-delimiter.
Used by `pages-directory-for-addresses' function."
- :type 'file
- :group 'pages)
+ :type 'file)
(defcustom pages-directory-for-addresses-goto-narrowing-p t
"If non-nil, `pages-directory-goto' narrows addresses buffer to entry."
- :type 'boolean
- :group 'pages)
+ :type 'boolean)
(defcustom pages-directory-for-addresses-buffer-keep-windows-p t
"If nil, `pages-directory-for-addresses' deletes other windows."
- :type 'boolean
- :group 'pages)
+ :type 'boolean)
(defcustom pages-directory-for-adding-addresses-narrowing-p t
"If non-nil, `add-new-page' narrows addresses buffer to new entry."
- :type 'boolean
- :group 'pages)
+ :type 'boolean)
;;; Key bindings for page handling functions
@@ -415,9 +408,9 @@ Point is left in the body of page."
Called from a program, there are three arguments:
REVERSE (non-nil means reverse order), BEG and END (region to sort)."
-;;; This sort function handles ends of pages differently than
-;;; `sort-pages' and works better with lists of addresses and similar
-;;; files.
+ ;; This sort function handles ends of pages differently than
+ ;; `sort-pages' and works better with lists of addresses and similar
+ ;; files.
(interactive "P\nr")
(save-restriction
@@ -463,25 +456,27 @@ REVERSE (non-nil means reverse order), BEG and END (region to sort)."
\(This regular expression may be used to select only those pages that
contain matches to the regexp.)")
-(defvar pages-buffer nil
+(defvar-local pages-buffer nil
"The buffer for which the pages-directory function creates the directory.")
(defvar pages-directory-prefix "*Directory for:"
"Prefix of name of temporary buffer for pages-directory.")
-(defvar pages-pos-list nil
+(defvar-local pages-pos-list nil
"List containing the positions of the pages in the pages-buffer.")
(defvar pages-target-buffer)
+(define-obsolete-variable-alias 'pages-directory-map
+ 'pages-directory-mode-map "26.1")
(defvar pages-directory-mode-map
(let ((map (make-sparse-keymap)))
(define-key map "\C-c\C-c" 'pages-directory-goto)
+ (define-key map "\C-m" 'pages-directory-goto)
(define-key map "\C-c\C-p\C-a" 'add-new-page)
- (define-key map [mouse-2] 'pages-directory-goto-with-mouse)
+ (define-key map [mouse-2] 'pages-directory-goto)
map)
"Keymap for the pages-directory-buffer.")
-(defvaralias 'pages-directory-map 'pages-directory-mode-map)
(defvar original-page-delimiter "^\f"
"Default page delimiter.")
@@ -512,6 +507,9 @@ resets the page-delimiter to the original value."
;;; Pages directory main definitions
+(defvar pages-buffer-original-position)
+(defvar pages-buffer-original-page)
+
(defun pages-directory
(pages-list-all-headers-p count-lines-p &optional regexp)
"Display a directory of the page headers in a temporary buffer.
@@ -573,7 +571,6 @@ directory for only the accessible portion of the buffer."
(let ((pages-target-buffer (current-buffer))
(pages-directory-buffer
(concat pages-directory-prefix " " (buffer-name)))
- (linenum 1)
(pages-buffer-original-position (point))
(pages-buffer-original-page 0))
@@ -644,10 +641,6 @@ directory for only the accessible portion of the buffer."
1
pages-buffer-original-page))))
-(defvar pages-buffer-original-position)
-(defvar pages-buffer-original-page)
-(defvar pages-buffer-original-page)
-
(defun pages-copy-header-and-position (count-lines-p)
"Copy page header and its position to the Pages Directory.
Only arg non-nil, count lines in page and insert before header.
@@ -701,16 +694,13 @@ Used by `pages-directory' function."
Move point to one of the lines in this buffer, then use \\[pages-directory-goto] to go
to the same line in the pages buffer."
- (make-local-variable 'pages-buffer)
- (make-local-variable 'pages-pos-list)
(make-local-variable 'pages-directory-buffer-narrowing-p))
-(defun pages-directory-goto ()
+(defun pages-directory-goto (&optional event)
"Go to the corresponding line in the pages buffer."
-
-;;; This function is mostly a copy of `occur-mode-goto-occurrence'
-
- (interactive)
+ ;; This function is mostly a copy of `occur-mode-goto-occurrence'
+ (interactive "@e")
+ (if event (mouse-set-point event))
(if (or (not pages-buffer)
(not (buffer-name pages-buffer)))
(progn
@@ -724,18 +714,13 @@ to the same line in the pages buffer."
(narrowing-p pages-directory-buffer-narrowing-p))
(pop-to-buffer pages-buffer)
(widen)
- (if end-of-directory-p
- (goto-char (point-max))
- (goto-char (marker-position pos)))
+ (goto-char (if end-of-directory-p
+ (point-max)
+ (marker-position pos)))
(if narrowing-p (narrow-to-page))))
-(defun pages-directory-goto-with-mouse (event)
- "Go to the corresponding line under the mouse pointer in the pages buffer."
- (interactive "e")
- (with-current-buffer (window-buffer (posn-window (event-end event)))
- (save-excursion
- (goto-char (posn-point (event-end event)))
- (pages-directory-goto))))
+(define-obsolete-function-alias 'pages-directory-goto-with-mouse
+ #'pages-directory-goto "26.1")
;;; The `pages-directory-for-addresses' function and ancillary code
diff --git a/lisp/textmodes/reftex-ref.el b/lisp/textmodes/reftex-ref.el
index c2c5ca3de06..f9f23201b43 100644
--- a/lisp/textmodes/reftex-ref.el
+++ b/lisp/textmodes/reftex-ref.el
@@ -314,7 +314,7 @@ also applies `reftex-translate-to-ascii-function' to the string."
(save-match-data
(cond
((equal letter "f")
- (file-name-base))
+ (file-name-base (buffer-file-name)))
((equal letter "F")
(let ((masterdir (file-name-directory (reftex-TeX-master-file)))
(file (file-name-sans-extension (buffer-file-name))))
diff --git a/lisp/textmodes/rst.el b/lisp/textmodes/rst.el
index 315059e1107..393b679e4a1 100644
--- a/lisp/textmodes/rst.el
+++ b/lisp/textmodes/rst.el
@@ -112,27 +112,6 @@
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; Support for `testcover'
-(when (and (boundp 'testcover-1value-functions)
- (boundp 'testcover-compose-functions))
- ;; Below `lambda' is used in a loop with varying parameters and is thus not
- ;; 1valued.
- (setq testcover-1value-functions
- (delq 'lambda testcover-1value-functions))
- (add-to-list 'testcover-compose-functions 'lambda))
-
-(defun rst-testcover-defcustom ()
- "Remove all customized variables from `testcover-module-constants'.
-This seems to be a bug in `testcover': `defcustom' variables are
-considered constants. Revert it with this function after each `defcustom'."
- (when (boundp 'testcover-module-constants)
- (setq testcover-module-constants
- (delq nil
- (mapcar
- #'(lambda (sym)
- (if (not (plist-member (symbol-plist sym) 'standard-value))
- sym))
- testcover-module-constants)))))
-
(defun rst-testcover-add-compose (fun)
"Add FUN to `testcover-compose-functions'."
(when (boundp 'testcover-compose-functions)
@@ -1344,7 +1323,6 @@ This inherits from Text mode.")
The hook for `text-mode' is run before this one."
:group 'rst
:type '(hook))
-(rst-testcover-defcustom)
;; Pull in variable definitions silencing byte-compiler.
(require 'newcomment)
@@ -1541,7 +1519,6 @@ file."
(const :tag "Underline only" simple))
(integer :tag "Indentation for overline and underline type"
:value 0))))
-(rst-testcover-defcustom)
;; FIXME: Rename this to `rst-over-and-under-default-indent' and set default to
;; 0 because the effect of 1 is probably surprising in the few cases
@@ -1558,7 +1535,6 @@ found in the buffer are to be used but the indentation for
over-and-under adornments is inconsistent across the buffer."
:group 'rst-adjust
:type '(integer))
-(rst-testcover-defcustom)
(defun rst-new-preferred-hdr (seen prev)
;; testcover: ok.
@@ -1997,7 +1973,6 @@ b. a negative numerical argument, which generally inverts the
:group 'rst-adjust
:type '(hook)
:package-version '(rst . "1.1.0"))
-(rst-testcover-defcustom)
(defcustom rst-new-adornment-down nil
"Controls level of new adornment for section headers."
@@ -2006,7 +1981,6 @@ b. a negative numerical argument, which generally inverts the
(const :tag "Same level as previous one" nil)
(const :tag "One level down relative to the previous one" t))
:package-version '(rst . "1.1.0"))
-(rst-testcover-defcustom)
(defun rst-adjust-adornment (pfxarg)
"Call `rst-adjust-section' interactively.
@@ -2429,7 +2403,6 @@ also arranged by `rst-insert-list-new-tag'."
:tag (char-to-string char) char))
rst-bullets)))
:package-version '(rst . "1.1.0"))
-(rst-testcover-defcustom)
(defun rst-insert-list-continue (ind tag tab prefer-roman)
;; testcover: ok.
@@ -2666,7 +2639,6 @@ section headers at all."
Also used for formatting insertion, when numbering is disabled."
:type 'integer
:group 'rst-toc)
-(rst-testcover-defcustom)
(defcustom rst-toc-insert-style 'fixed
"Insertion style for table-of-contents.
@@ -2681,19 +2653,16 @@ indentation style:
(const aligned)
(const listed))
:group 'rst-toc)
-(rst-testcover-defcustom)
(defcustom rst-toc-insert-number-separator " "
"Separator that goes between the TOC number and the title."
:type 'string
:group 'rst-toc)
-(rst-testcover-defcustom)
(defcustom rst-toc-insert-max-level nil
"If non-nil, maximum depth of the inserted TOC."
:type '(choice (const nil) integer)
:group 'rst-toc)
-(rst-testcover-defcustom)
(defconst rst-toc-link-keymap
(let ((map (make-sparse-keymap)))
@@ -3158,35 +3127,30 @@ These indentation widths can be customized here."
"Indentation when there is no more indentation point given."
:group 'rst-indent
:type '(integer))
-(rst-testcover-defcustom)
(defcustom rst-indent-field 3
"Indentation for first line after a field or 0 to always indent for content."
:group 'rst-indent
:package-version '(rst . "1.1.0")
:type '(integer))
-(rst-testcover-defcustom)
(defcustom rst-indent-literal-normal 3
"Default indentation for literal block after a markup on an own line."
:group 'rst-indent
:package-version '(rst . "1.1.0")
:type '(integer))
-(rst-testcover-defcustom)
(defcustom rst-indent-literal-minimized 2
"Default indentation for literal block after a minimized markup."
:group 'rst-indent
:package-version '(rst . "1.1.0")
:type '(integer))
-(rst-testcover-defcustom)
(defcustom rst-indent-comment 3
"Default indentation for first line of a comment."
:group 'rst-indent
:package-version '(rst . "1.1.0")
:type '(integer))
-(rst-testcover-defcustom)
;; FIXME: Must consider other tabs:
;; * Line blocks
@@ -3636,7 +3600,6 @@ Region is from BEG to END. With WITH-EMPTY prefix empty lines too."
:version "24.1"
:group 'rst-faces
:type '(face))
-(rst-testcover-defcustom)
(make-obsolete-variable 'rst-block-face
"customize the face `rst-block' instead."
"24.1")
@@ -3651,7 +3614,6 @@ Region is from BEG to END. With WITH-EMPTY prefix empty lines too."
:version "24.1"
:group 'rst-faces
:type '(face))
-(rst-testcover-defcustom)
(make-obsolete-variable 'rst-external-face
"customize the face `rst-external' instead."
"24.1")
@@ -3666,7 +3628,6 @@ Region is from BEG to END. With WITH-EMPTY prefix empty lines too."
:version "24.1"
:group 'rst-faces
:type '(face))
-(rst-testcover-defcustom)
(make-obsolete-variable 'rst-definition-face
"customize the face `rst-definition' instead."
"24.1")
@@ -3683,7 +3644,6 @@ Region is from BEG to END. With WITH-EMPTY prefix empty lines too."
"Directives and roles."
:group 'rst-faces
:type '(face))
-(rst-testcover-defcustom)
(make-obsolete-variable 'rst-directive-face
"customize the face `rst-directive' instead."
"24.1")
@@ -3698,7 +3658,6 @@ Region is from BEG to END. With WITH-EMPTY prefix empty lines too."
:version "24.1"
:group 'rst-faces
:type '(face))
-(rst-testcover-defcustom)
(make-obsolete-variable 'rst-comment-face
"customize the face `rst-comment' instead."
"24.1")
@@ -3713,7 +3672,6 @@ Region is from BEG to END. With WITH-EMPTY prefix empty lines too."
:version "24.1"
:group 'rst-faces
:type '(face))
-(rst-testcover-defcustom)
(make-obsolete-variable 'rst-emphasis1-face
"customize the face `rst-emphasis1' instead."
"24.1")
@@ -3727,7 +3685,6 @@ Region is from BEG to END. With WITH-EMPTY prefix empty lines too."
"Double emphasis."
:group 'rst-faces
:type '(face))
-(rst-testcover-defcustom)
(make-obsolete-variable 'rst-emphasis2-face
"customize the face `rst-emphasis2' instead."
"24.1")
@@ -3742,7 +3699,6 @@ Region is from BEG to END. With WITH-EMPTY prefix empty lines too."
:version "24.1"
:group 'rst-faces
:type '(face))
-(rst-testcover-defcustom)
(make-obsolete-variable 'rst-literal-face
"customize the face `rst-literal' instead."
"24.1")
@@ -3757,7 +3713,6 @@ Region is from BEG to END. With WITH-EMPTY prefix empty lines too."
:version "24.1"
:group 'rst-faces
:type '(face))
-(rst-testcover-defcustom)
(make-obsolete-variable 'rst-reference-face
"customize the face `rst-reference' instead."
"24.1")
@@ -3840,7 +3795,6 @@ of your own."
(const :tag "transitions" t)
(const :tag "section title adornment" nil))
:value-type (face)))
-(rst-testcover-defcustom)
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
@@ -4337,7 +4291,6 @@ string)) to be used for converting the document."
(string :tag "Options"))))
:group 'rst-compile
:package-version "1.2.0")
-(rst-testcover-defcustom)
;; FIXME: Must be defcustom.
(defvar rst-compile-primary-toolset 'html
diff --git a/lisp/thingatpt.el b/lisp/thingatpt.el
index 485cc97555f..e3a4d4d7c1e 100644
--- a/lisp/thingatpt.el
+++ b/lisp/thingatpt.el
@@ -42,6 +42,9 @@
;; beginning-op Function to call to skip to the beginning of a "thing".
;; end-op Function to call to skip to the end of a "thing".
;;
+;; For simple things, defined as sequences of specific kinds of characters,
+;; use macro define-thing-chars.
+;;
;; Reliance on existing operators means that many `things' can be accessed
;; without further code: eg.
;; (thing-at-point 'line)
@@ -237,21 +240,28 @@ The bounds of THING are determined by `bounds-of-thing-at-point'."
(put 'defun 'end-op 'end-of-defun)
(put 'defun 'forward-op 'end-of-defun)
+;; Things defined by sets of characters
+
+(defmacro define-thing-chars (thing chars)
+ "Define THING as a sequence of CHARS.
+E.g.:
+\(define-thing-chars twitter-screen-name \"[:alnum:]_\")"
+ `(progn
+ (put ',thing 'end-op
+ (lambda ()
+ (re-search-forward (concat "\\=[" ,chars "]*") nil t)))
+ (put ',thing 'beginning-op
+ (lambda ()
+ (if (re-search-backward (concat "[^" ,chars "]") nil t)
+ (forward-char)
+ (goto-char (point-min)))))))
+
;; Filenames
(defvar thing-at-point-file-name-chars "-~/[:alnum:]_.${}#%,:"
"Characters allowable in filenames.")
-(put 'filename 'end-op
- (lambda ()
- (re-search-forward (concat "\\=[" thing-at-point-file-name-chars "]*")
- nil t)))
-(put 'filename 'beginning-op
- (lambda ()
- (if (re-search-backward (concat "[^" thing-at-point-file-name-chars "]")
- nil t)
- (forward-char)
- (goto-char (point-min)))))
+(define-thing-chars filename thing-at-point-file-name-chars)
;; URIs
diff --git a/lisp/time.el b/lisp/time.el
index c8726a9a1b0..6cd7320e72f 100644
--- a/lisp/time.el
+++ b/lisp/time.el
@@ -583,7 +583,7 @@ For example, the Unix uptime command format is \"%D, %z%2h:%.2m\"."
(let ((str
(format-seconds (or format "%Y, %D, %H, %M, %z%S")
(float-time
- (time-subtract (current-time) before-init-time)))))
+ (time-subtract nil before-init-time)))))
(if (called-interactively-p 'interactive)
(message "%s" str)
str)))
diff --git a/lisp/tooltip.el b/lisp/tooltip.el
index 18ddd25703c..44b6938a6fd 100644
--- a/lisp/tooltip.el
+++ b/lisp/tooltip.el
@@ -155,6 +155,18 @@ This variable is obsolete; instead of setting it to t, disable
(make-obsolete-variable 'tooltip-use-echo-area
"disable Tooltip mode instead" "24.1" 'set)
+(defcustom tooltip-resize-echo-area nil
+ "If non-nil, using the echo area for tooltips will resize the echo area.
+By default, when the echo area is used for displaying tooltips,
+the tooltip text is truncated if it exceeds a single screen line.
+When this variable is non-nil, the text is not truncated; instead,
+the echo area is resized as needed to accommodate the full text
+of the tooltip.
+This variable has effect only on GUI frames."
+ :type 'boolean
+ :group 'tooltip
+ :version "27.1")
+
;;; Variables that are not customizable.
@@ -347,7 +359,8 @@ It is also called if Tooltip mode is on, for text-only displays."
(current-message))))
(setq tooltip-previous-message (current-message)))
(setq tooltip-help-message help)
- (let ((message-truncate-lines t)
+ (let ((message-truncate-lines
+ (or (not (display-graphic-p)) (not tooltip-resize-echo-area)))
(message-log-max nil))
(message "%s" help)))
((stringp tooltip-previous-message)
diff --git a/lisp/type-break.el b/lisp/type-break.el
index faf44b3b875..35b0efe65b1 100644
--- a/lisp/type-break.el
+++ b/lisp/type-break.el
@@ -376,7 +376,7 @@ problems."
(if (and type-break-time-last-break
(< (setq diff (type-break-time-difference
type-break-time-last-break
- (current-time)))
+ nil))
type-break-interval))
;; Use the file's value.
(progn
@@ -563,7 +563,7 @@ as per the function `type-break-schedule'."
(cond
(good-interval
(let ((break-secs (type-break-time-difference
- start-time (current-time))))
+ start-time nil)))
(cond
((>= break-secs good-interval)
(setq continue nil))
@@ -624,7 +624,7 @@ INTERVAL is the full length of an interval (defaults to TIME)."
type-break-time-warning-intervals))
(or time
- (setq time (type-break-time-difference (current-time)
+ (setq time (type-break-time-difference nil
type-break-time-next-break)))
(while (and type-break-current-time-warning-interval
@@ -685,7 +685,7 @@ keystroke threshold has been exceeded."
(and type-break-good-rest-interval
(progn
(and (> (type-break-time-difference
- type-break-time-last-command (current-time))
+ type-break-time-last-command nil)
type-break-good-rest-interval)
(progn
(type-break-keystroke-reset)
diff --git a/lisp/url/url-cache.el b/lisp/url/url-cache.el
index 1cffc06d7c3..963dfd531e2 100644
--- a/lisp/url/url-cache.el
+++ b/lisp/url/url-cache.el
@@ -206,7 +206,7 @@ If `url-standalone-mode' is non-nil, cached items never expire."
(time-add
cache-time
(seconds-to-time (or expire-time url-cache-expire-time)))
- (current-time))))))
+ nil)))))
(defun url-cache-prune-cache (&optional directory)
"Remove all expired files from the cache.
diff --git a/lisp/url/url-cookie.el b/lisp/url/url-cookie.el
index 453d4fe5b6f..0a3103264d9 100644
--- a/lisp/url/url-cookie.el
+++ b/lisp/url/url-cookie.el
@@ -74,6 +74,55 @@ telling Microsoft that."
;; It's completely normal for the cookies file not to exist yet.
(load (or fname url-cookie-file) t t))
+(defun url-cookie-parse-file-netscape (filename &optional long-session)
+ "Load cookies from FILENAME in Netscape/Mozilla format.
+When LONG-SESSION is non-nil, session cookies (expiring at t=0
+i.e. 1970-1-1) are loaded as expiring one year from now instead."
+ (interactive "fLoad Netscape/Mozilla cookie file: ")
+ (let ((n 0))
+ (with-temp-buffer
+ (insert-file-contents-literally filename)
+ (goto-char (point-min))
+ (when (not (looking-at-p "# Netscape HTTP Cookie File\n"))
+ (error (format "File %s doesn't look like a netscape cookie file" filename)))
+ (while (not (eobp))
+ (when (not (looking-at-p (rx bol (* space) "#")))
+ (let* ((line (buffer-substring (point) (save-excursion (end-of-line) (point))))
+ (fields (split-string line "\t")))
+ (cond
+ ;;((>= 1 (length line) 0)
+ ;; (message "skipping empty line"))
+ ((= (length fields) 7)
+ (let ((dom (nth 0 fields))
+ ;; (match (nth 1 fields))
+ (path (nth 2 fields))
+ (secure (string= (nth 3 fields) "TRUE"))
+ ;; session cookies (expire time = 0) are supposed
+ ;; to be removed when the browser is closed, but
+ ;; the main point of loading external cookie is to
+ ;; reuse a browser session, so to prevent the
+ ;; cookie from being detected as expired straight
+ ;; away, make it expire a year from now
+ (expires (format-time-string
+ "%d %b %Y %T [GMT]"
+ (seconds-to-time
+ (let ((s (string-to-number (nth 4 fields))))
+ (if (and (= s 0) long-session)
+ (seconds-to-time (+ (* 365 24 60 60) (float-time)))
+ s)))))
+ (key (nth 5 fields))
+ (val (nth 6 fields)))
+ (cl-incf n)
+ ;;(message "adding <%s>=<%s> exp=<%s> dom=<%s> path=<%s> sec=%S" key val expires dom path secure)
+ (url-cookie-store key val expires dom path secure)
+ ))
+ (t
+ (message "ignoring malformed cookie line <%s>" line)))))
+ (forward-line))
+ (when (< 0 n)
+ (setq url-cookies-changed-since-last-save t))
+ (message "added %d cookies from file %s" n filename))))
+
(defun url-cookie-clean-up (&optional secure)
(let ((var (if secure 'url-cookie-secure-storage 'url-cookie-storage))
new new-cookies)
diff --git a/lisp/url/url.el b/lisp/url/url.el
index 9a6b732ca9c..36cd81bd70b 100644
--- a/lisp/url/url.el
+++ b/lisp/url/url.el
@@ -259,8 +259,7 @@ how long to wait for a response before giving up."
;; process output.
(while (and (not retrieval-done)
(or (not timeout)
- (< (float-time (time-subtract
- (current-time) start-time))
+ (< (float-time (time-subtract nil start-time))
timeout)))
(url-debug 'retrieval
"Spinning in url-retrieve-synchronously: %S (%S)"
diff --git a/lisp/xdg.el b/lisp/xdg.el
index 76106f42586..4250faaeb4b 100644
--- a/lisp/xdg.el
+++ b/lisp/xdg.el
@@ -34,6 +34,7 @@
;;; Code:
(eval-when-compile
+ (require 'cl-lib)
(require 'subr-x))
@@ -212,6 +213,108 @@ Optional argument GROUP defaults to the string \"Desktop Entry\"."
(when (null (string-match-p "[^[:blank:]]" (car res))) (pop res))
(nreverse res)))
+
+;; MIME apps specification
+;; https://standards.freedesktop.org/mime-apps-spec/mime-apps-spec-1.0.1.html
+
+(defvar xdg-mime-table nil
+ "Table of MIME type to desktop file associations.
+The table is an alist with keys being MIME major types (\"application\",
+\"audio\", etc.), and values being hash tables. Each hash table has
+MIME subtypes as keys and lists of desktop file absolute filenames.")
+
+(defun xdg-mime-apps-files ()
+ "Return a list of files containing MIME/Desktop associations.
+The list is in order of descending priority: user config, then
+admin config, and finally system cached associations."
+ (let ((xdg-data-dirs (xdg-data-dirs))
+ (desktop (getenv "XDG_CURRENT_DESKTOP"))
+ res)
+ (when desktop
+ (setq desktop (format "%s-mimeapps.list" desktop)))
+ (dolist (name (cons "mimeapps.list" desktop))
+ (push (expand-file-name name (xdg-config-home)) res)
+ (push (expand-file-name (format "applications/%s" name) (xdg-data-home))
+ res)
+ (dolist (dir (xdg-config-dirs))
+ (push (expand-file-name name dir) res))
+ (dolist (dir xdg-data-dirs)
+ (push (expand-file-name (format "applications/%s" name) dir) res)))
+ (dolist (dir xdg-data-dirs)
+ (push (expand-file-name "applications/mimeinfo.cache" dir) res))
+ (nreverse res)))
+
+(defun xdg-mime-collect-associations (mime files)
+ "Return a list of desktop file names associated with MIME.
+The associations are searched in the list of file names FILES,
+which is expected to be ordered by priority as in
+`xdg-mime-apps-files'."
+ (let ((regexp (concat (regexp-quote mime) "=\\([^[:cntrl:]]*\\)$"))
+ res sec defaults added removed cached)
+ (with-temp-buffer
+ (dolist (f (reverse files))
+ (when (file-readable-p f)
+ (insert-file-contents-literally f nil nil nil t)
+ (goto-char (point-min))
+ (let (end)
+ (while (not (or (eobp) end))
+ (if (= (following-char) ?\[)
+ (progn (setq sec (char-after (1+ (point))))
+ (forward-line))
+ (if (not (looking-at regexp))
+ (forward-line)
+ (dolist (str (xdg-desktop-strings (match-string 1)))
+ (cl-pushnew str
+ (cond ((eq sec ?D) defaults)
+ ((eq sec ?A) added)
+ ((eq sec ?R) removed)
+ ((eq sec ?M) cached))
+ :test #'equal))
+ (while (and (zerop (forward-line))
+ (/= (following-char) ?\[)))))))
+ ;; Accumulate results into res
+ (dolist (f cached)
+ (when (not (member f removed)) (cl-pushnew f res :test #'equal)))
+ (dolist (f added)
+ (when (not (member f removed)) (push f res)))
+ (dolist (f removed)
+ (setq res (delete f res)))
+ (dolist (f defaults)
+ (push f res))
+ (setq defaults nil added nil removed nil cached nil))))
+ (delete-dups res)))
+
+(defun xdg-mime-apps (mime)
+ "Return list of desktop files associated with MIME, otherwise nil.
+The list is in order of descending priority, and each element is
+an absolute file name of a readable file.
+Results are cached in `xdg-mime-table'."
+ (pcase-let ((`(,type ,subtype) (split-string mime "/"))
+ (xdg-data-dirs (xdg-data-dirs))
+ (caches (xdg-mime-apps-files))
+ (files ()))
+ (let ((mtim1 (get 'xdg-mime-table 'mtime))
+ (mtim2 (cl-loop for f in caches when (file-readable-p f)
+ maximize (float-time (nth 5 (file-attributes f))))))
+ ;; If one of the MIME/Desktop cache files has been modified:
+ (when (or (null mtim1) (time-less-p mtim1 mtim2))
+ (setq xdg-mime-table nil)))
+ (when (null (assoc type xdg-mime-table))
+ (push (cons type (make-hash-table :test #'equal)) xdg-mime-table))
+ (if (let ((def (make-symbol "def"))
+ (table (cdr (assoc type xdg-mime-table))))
+ (not (eq (setq files (gethash subtype table def)) def)))
+ files
+ (and files (setq files nil))
+ (let ((dirs (mapcar (lambda (dir) (expand-file-name "applications" dir))
+ (cons (xdg-data-home) xdg-data-dirs))))
+ ;; Not being particular about desktop IDs
+ (dolist (f (nreverse (xdg-mime-collect-associations mime caches)))
+ (push (locate-file f dirs) files))
+ (when files
+ (put 'xdg-mime-table 'mtime (current-time)))
+ (puthash subtype (delq nil files) (cdr (assoc type xdg-mime-table)))))))
+
(provide 'xdg)
;;; xdg.el ends here