* doc/lispref/files.texi (File Attributes): Document it.
* lisp/files.el (file-has-changed-p): New function.
(file-has-changed-p--hash-table): Internal variable used by the
new function (bug#51523).
* lisp/emacs-lisp/shortdoc.el (file): Mention it.
* lisp/net/mailcap.el (mailcap-parse-mailcaps): Read mailcaps again
only when at least one of the mailcap files has changed. Fixes
bug#51523.
@end example
@end defun
+@defun file-has-changed-p filename
+This convenience function is useful when, for instance, parsing files
+run-time, and you typically want to re-read a file when it has
+changed. This function returns non-@code{nil} the first time it's
+called on @var{filename} in an Emacs session, but will return
+@code{nil} on subsequent calls in that session (unless the file
+changes its modification time).
+@end defun
+
@defun file-attributes filename &optional id-format
@anchor{Definition of file-attributes}
This function returns a list of attributes of file @var{filename}. If
\f
* Lisp Changes in Emacs 29.1
+*** New function 'file-has-changed-p'.
+This convenience function is useful when writing code that parses
+files run-time, and allows you to easily re-parse files when they have
+changed (but not otherwise).
+
---
*** New function 'font-has-char-p'.
This can be used to check whether a specific font has a glyph for a
(file-newer-than-file-p
:no-eval (file-newer-than-file-p "/tmp/foo" "/tmp/bar")
:eg-result nil)
+ (file-has-changed-p
+ :no-eval (file-has-changed-p "/tmp/foo")
+ :eg-result t)
(file-equal-p
:no-eval (file-equal-p "/tmp/foo" "/tmp/bar")
:eg-result nil)
(unless mismatch
(file-equal-p root dir)))))))
+(defvar file-has-changed-p--hash-table (make-hash-table)
+ "Internal variable used by `file-has-changed-p'.")
+
+(defun file-has-changed-p (file)
+ "Return non-nil if FILE has changed.
+The modification time of FILE is compared to the modification
+time of FILE during a previous invocation of `file-has-changed-p'.
+Therefore the first invocation of `file-has-changed-p' always
+returns non-nil."
+ (let* ((attr (file-attributes file 'integer))
+ (mtime (file-attribute-modification-time attr))
+ (saved-mtime (gethash (intern file)
+ file-has-changed-p--hash-table)))
+ (when (not (equal mtime saved-mtime))
+ (puthash (intern file) mtime file-has-changed-p--hash-table))))
+
(defun copy-directory (directory newname &optional keep-time parents copy-contents)
"Copy DIRECTORY to NEWNAME. Both args must be strings.
This function always sets the file modes of the output files to match
("/etc/mailcap" system)
("/usr/etc/mailcap" system)
("/usr/local/etc/mailcap" system)))))
- ;; The ~/.mailcap entries will end up first in the resulting data.
- (dolist (spec (reverse
- (if (stringp path)
- (split-string path path-separator t)
- path)))
- (let ((source (and (consp spec) (cadr spec)))
- (file-name (if (stringp spec)
- spec
- (car spec))))
- (when (and (file-readable-p file-name)
- (file-regular-p file-name))
- (mailcap-parse-mailcap file-name source))))
+ (when (seq-some (lambda (f) (file-has-changed-p (car f))) path)
+ ;; The ~/.mailcap entries will end up first in the resulting data.
+ (dolist (spec (reverse
+ (if (stringp path)
+ (split-string path path-separator t)
+ path)))
+ (let ((source (and (consp spec) (cadr spec)))
+ (file-name (if (stringp spec)
+ spec
+ (car spec))))
+ (when (and (file-readable-p file-name)
+ (file-regular-p file-name))
+ (mailcap-parse-mailcap file-name source)))))
(setq mailcap-parsed-p t)))
(defun mailcap-parse-mailcap (fname &optional source)