]> git.bundesbrandschatzamt.de Git - emacsconfig.git/commitdiff
update compat
authorAndreas Gerler <baronNOSPAMbundesbrandschatzamt.de>
Thu, 18 Jul 2024 08:27:35 +0000 (10:27 +0200)
committerAndreas Gerler <baronNOSPAMbundesbrandschatzamt.de>
Thu, 18 Jul 2024 08:27:35 +0000 (10:27 +0200)
Signed-off-by: Andreas Gerler <baronNOSPAMbundesbrandschatzamt.de>
26 files changed:
elpa/compat-29.1.4.1.signed [deleted file]
elpa/compat-29.1.4.1/NEWS.org [deleted file]
elpa/compat-29.1.4.1/compat-25.el [deleted file]
elpa/compat-29.1.4.1/compat-26.el [deleted file]
elpa/compat-29.1.4.1/compat-27.el [deleted file]
elpa/compat-29.1.4.1/compat-28.el [deleted file]
elpa/compat-29.1.4.1/compat-29.el [deleted file]
elpa/compat-29.1.4.1/compat-autoloads.el [deleted file]
elpa/compat-29.1.4.1/compat-macs.el [deleted file]
elpa/compat-29.1.4.1/compat-pkg.el [deleted file]
elpa/compat-29.1.4.1/compat.el [deleted file]
elpa/compat-29.1.4.1/compat.info [deleted file]
elpa/compat-29.1.4.1/dir [deleted file]
elpa/compat-29.1.4.5.signed [new file with mode: 0644]
elpa/compat-29.1.4.5/NEWS.org [new file with mode: 0644]
elpa/compat-29.1.4.5/compat-25.el [new file with mode: 0644]
elpa/compat-29.1.4.5/compat-26.el [new file with mode: 0644]
elpa/compat-29.1.4.5/compat-27.el [new file with mode: 0644]
elpa/compat-29.1.4.5/compat-28.el [new file with mode: 0644]
elpa/compat-29.1.4.5/compat-29.el [new file with mode: 0644]
elpa/compat-29.1.4.5/compat-autoloads.el [new file with mode: 0644]
elpa/compat-29.1.4.5/compat-macs.el [new file with mode: 0644]
elpa/compat-29.1.4.5/compat-pkg.el [new file with mode: 0644]
elpa/compat-29.1.4.5/compat.el [new file with mode: 0644]
elpa/compat-29.1.4.5/compat.info [new file with mode: 0644]
elpa/compat-29.1.4.5/dir [new file with mode: 0644]

diff --git a/elpa/compat-29.1.4.1.signed b/elpa/compat-29.1.4.1.signed
deleted file mode 100644 (file)
index 2e67f96..0000000
+++ /dev/null
@@ -1 +0,0 @@
-Good signature from 066DAFCB81E42C40 GNU ELPA Signing Agent (2019) <elpasignNOSPAMelpa.gnu.org> (trust undefined) created at 2023-03-26T23:05:02+0200 using RSA
\ No newline at end of file
diff --git a/elpa/compat-29.1.4.1/NEWS.org b/elpa/compat-29.1.4.1/NEWS.org
deleted file mode 100644 (file)
index f7f1a1a..0000000
+++ /dev/null
@@ -1,289 +0,0 @@
-#+link:    compat-srht https://todo.sr.ht/~pkal/compat/
-#+link:    compat-gh   https://github.com/emacs-compat/compat/issues/
-#+options: toc:nil num:nil author:nil
-
-* Release of "Compat" Version 29.1.4.1
-
-- compat-29: Add ~directory-abbrev-apply~.
-- compat-29: Add ~directory-abbrev-make-regexp~.
-
-(Release <2023-03-26 Sun>)
-
-* Release of "Compat" Version 29.1.4.0
-
-- compat-27: Drop obsolete ~compat-call dired-get-marked-files~.
-- compat-28: Add support for ~defcustom~ type ~natnum~.
-- compat-29: Add ~with-restriction~ and ~without-restriction~.
-- compat-29: Add ~cl-constantly~.
-- compat-29: Drop ~with-narrowing~ which was renamed to ~with-restriction~.
-- compat-28: Add support for ~defcustom~ type ~key~.
-
-(Release <2023-03-05 Sun>)
-
-* Release of "Compat" Version 29.1.3.4
-
-- Ensure that ~seq~ is required properly both at compile time and runtime, such
-  that compilation of downstream packages works even if Compat itself is not
-  compiled. Magit uses a complex continuous integration system, where Magit is
-  compiled and tested, while the Compat dependency is not compiled.
-- compat-28: Add ~process-lines-handling-status~ and ~process-lines-ignore-status~.
-
-(Release <2023-02-11 Sat>)
-
-* Release of "Compat" Version 29.1.3.3
-
-- compat-27: Add ~with-suppressed-warnings~.
-- compat-29: Add ~cl-with-gensyms~ and ~cl-once-only~.
-- compat-29: Load ~seq~, which is preloaded on Emacs 29.
-
-(Release <2023-02-08 Wed>)
-
-* Release of "Compat" Version 29.1.3.2
-
-- compat-26: Add ~make-temp-file~ with optional argument TEXT.
-- compat-27: Mark ~compat-call dired-get-marked-files~ as obsolete. See the
-  section limitations in the Compat manual.
-- compat-29: Add ~funcall-with-delayed-message~ and ~with-delayed-message~.
-- compat-29: Add ~ert-with-temp-file~ and ~ert-with-temp-directory~.
-- compat-29: Add ~set-transient-map~ with optional arguments MESSAGE and TIMEOUT.
-
-(Release <2023-02-01 Wed>)
-
-* Release of "Compat" Version 29.1.3.1
-
-- Fix regression, which prevented loading Compat in interpreted mode. We ensure
-  that Compat works interpreted and byte compiled by running the entire test
-  suite twice in the CI. See https://github.com/magit/magit/issues/4858 for the
-  corresponding Magit issue.
-- compat-27: Add ~file-name-unquote~.
-- compat-28: Add ~mark-thing-at-mouse~.
-- compat-29: Replace ~string-lines~ with version from Emacs 29, support optional
-  KEEP-NEWLINES argument.
-
-(Release <2023-01-25 Wed>)
-
-* Release of "Compat" Version 29.1.3.0
-
-- compat-25: Add ~hash-table-empty-p~.
-- compat-25: Add ~macroexp-parse-body~ and ~macroexp-quote~.
-- compat-25: Add ~region-noncontiguous-p~.
-- compat-25: Add ~save-mark-and-excursion~.
-- compat-26: Add ~read-answer~.
-- compat-26: Add ~region-bounds~.
-- compat-27: Add ~date-ordinal-to-time~.
-- compat-27: Add ~file-size-human-readable-iec~.
-- compat-27: Add ~major-mode-suspend~ and ~major-mode-restore~.
-- compat-27: Add ~make-decoded-time~.
-- compat-27: Add ~minibuffer-history-value~.
-- compat-27: Add ~read-char-from-minibuffer~.
-- compat-27: Add ~ring-resize~.
-- compat-28: Add ~color-dark-p~.
-- compat-28: Add ~directory-files-and-attributes~ with COUNT argument.
-- compat-28: Add ~text-quoting-style~.
-- compat-28: Add ~with-window-non-dedicated~.
-- compat-29: Add ~buffer-local-set-state~ and ~buffer-local-restore-state~.
-- compat-29: Add ~compiled-function-p~.
-- compat-29: Add ~count-sentences~.
-- compat-29: Add ~delete-line~.
-- compat-29: Add ~get-scratch-buffer-create~.
-- compat-29: Add ~list-of-strings-p~.
-- compat-29: Add ~plist-get~ generalized variable.
-- compat-29: Add ~plistp~.
-- compat-29: Add ~read-multiple-choice~ with LONG-FORM argument.
-- compat-29: Add ~readablep~.
-- compat-29: Add ~substitute-quotes~.
-- compat-29: Add ~use-region-beginning~, ~use-region-end~ and ~use-region-noncontiguous-p~.
-- compat-29: Add ~with-narrowing~.
-
-(Release <2023-01-22 Sun>)
-
-* Release of "Compat" Version 29.1.2.0
-
-- All compatibility functions are covered by tests!
-- Add links from compatibility definitions to tests.
-- BREAKING: Drop JSON parsing support (libjansson API, unused downstream).
-- BREAKING: Drop ~null-device~ (unused downstream).
-- BREAKING: Drop ~unlock-buffer~ (unused downstream).
-- compat-26: Add ~buffer-hash~.
-- compat-27: Add ~fixnump~ and ~bignump~.
-- compat-27: Add ~with-minibuffer-selected-window~.
-- compat-27: Add generalized variables for ~decoded-time-*~.
-- compat-28: Add ~macroexp-warn-and-return~.
-- compat-28: Add ~subr-native-elisp-p~.
-- compat-28: Add ~bounds-of-thing-at-mouse~.
-- compat-29: Add ~with-buffer-unmodified-if-unchanged~.
-- compat-29: Fix and test ~define-key~ with REMOVE argument.
-
-(Release <2023-01-16 Mon>)
-
-* Release of "Compat" Version 29.1.1.1
-
-- Add tests, 167 out of 203 definitions tested (82%).
-- compat-25: Improve algorithmic complexity of ~sort~.
-- compat-28: Add ~make-separator-line~.
-- compat-29: Minor fixes to ~keymap-*~ functions.
-- compat-29: Add ~with-memoization~.
-- compat-29: Add ~buttonize~ and ~buttonize-region~.
-
-(Release <2023-01-14 Sat>)
-
-* Release of "Compat" Version 29.1.1.0
-
-- The macros in ~compat-macs.el~ have been rewritten and simplified. The
-  refactoring allows to further refine the criteria under which compatibility
-  aliases, functions, macros and variables are installed.
-- Remove deprecated, prefixed compatibility functions.
-- Remove deprecated features ~compat-help~, ~compat-font-lock~ and ~compat-24~.
-- Compat uses runtime checks (~boundp~, ~fboundp~) to ensure that existing
-  definitions are never overridden, when Compat is loaded on a newer Emacs than
-  it was compiled on.
-- Compat compiles without byte compilation warnings on all supported Emacs
-  versions. Warnings are treated as errors in the test suite.
-- Compat takes great care to remove unneeded definitions at compile time. On
-  recent Emacs 29 the byte compiled files are empty and not loaded, such that
-  Compat does not any cost to the Emacs process.
-- compat-26: Fix and test ~image-property~ setter.
-- compat-26: Fix and test ~read-multiple-choice~.
-- compat-28: Fix and test ~with-existing-directory~.
-- compat-28: Drop obsolete function ~make-directory-autoloads~.
-- compat-29: Drop broken functions ~string-pixel-width~ and
-  ~buffer-text-pixel-size~. These functions had poor performance which lead to a
-  downstream issue in the doom-modeline package. If a more efficient solution is
-  possible, the function will be added back. See [[compat-gh:8]] for the bug report.
-- compat-29: Drop broken function ~string-limit~.
-- compat-29: Drop broken macro ~with-buffer-unmodified-if-unchanged~, which relied
-  on ~buffer-hash~ which does not exist on all supported Emacs versions.
-- compat-29: Add ~pos-bol~ and ~pos-eol~.
-
-(Release <2023-01-07 Sat>)
-
-* Release of "Compat" Version 29.1.0.1
-
-- Add multiple new tests for existing APIs.
-- Fix bugs in compatibility functions: ~setq-local~, ~proper-list-p, prop-match-p~,
-  ~file-name-concat~, ~replace-regexp-in-region~, ~replace-string-in-region~.
-- Add new Emacs 29 APIs. Some of them are still untested and may change. If you
-  intend to use an Emacs 29 API please be careful and if possible contribute
-  test cases. All untested functions are marked in the Compat code. Over time
-  tests for all functions will be added gradually.
-- Add the macros ~compat-call~ and ~compat-function~ to call compatibility
-  functions. Since Compat avoids overwriting already existing functions, we must
-  define separate compatibility function definitions for functions which changed
-  their calling convention or behavior. These compatibility definitions can be
-  looked up using ~compat-function~ and called with ~compat-call~. For example ~assoc~
-  can be called with a ~TESTFN~ since Emacs 26. In Emacs 25 and older the calling
-  convention was ~(assoc KEY ALIST)~. In order to use the new calling convention
-  you can use ~(compat-call assoc KEY ALIST TESTFN)~.
-- Deprecate all ~compat-*~ prefixed functions. Instead use the aforementioned
-  ~compat-call~ or ~compat-function~ macros.
-- Deprecate ~compat-help.el~ and ~compat-font-lock.el.~
-- Development moved to GitHub.
-- BREAKING: Drop broken function ~func-arity~. Using ~func-arity~ is generally
-  discouraged and the function is hard to implement properly due to all the
-  various function types. There it is unlikely that the function will get
-  reintroduced in Compat.
-- BREAKING: Drop broken function ~directory-files-recursively~. In case you need
-  this function, a patch including tests is welcome.
-- BREAKING: Drop support for Emacs 24.3. Emacs 24.4 is required now. In case you
-  still need Emacs 24.3 support, you can rely on Compat 28.1.2.2.
-
-(Release <2023-01-05 Thu>)
-
-* Release of "Compat" Version 28.1.2.2
-
-This is a minor release that hopes to address [[compat-srht:7]].
-
-(Release <2022-08-25 Thu>)
-
-* Release of "Compat" Version 28.1.2.1
-
-This is a minor release adding the following changes:
-
-- Add =derived-mode-p= defined in Emacs 27
-- Add =provided-mode-derived-p= defined in Emacs 27
-- Add =read-multiple-choice= defined in Emacs 26
-- Add =file-name-absolute-p= defined in Emacs 28
-
-The only other notable change is that the manual has been rewritten to
-include much more documentation that had been the case previously.
-
-(Release <2022-08-24 Wed>)
-
-* Release of "Compat" Version 28.1.2.0
-
-The main change of this release has been the major simplification of
-Compat's initialisation system, improving the situation around issues
-people had been reporting ([[compat-srht:4]], once again) with unconventional
-or unpopular packaging systems.
-
-In addition to this, the following functional changes have been made:
-
-- Fix =format-prompt= of an empty string as "default" argument
-- Add =decoded-time-period= defined in Emacs 28
-- Add =subr-primitive-p= defined in Emacs 28
-
-Minor improvements to manual are also part of this release.
-
-(Release <2022-07-18 Mon>)
-
-* Release of "Compat" Version 28.1.1.3
-
-This release just contains a hot-fix for an issue introduced in the
-last version, where compat.el raises an error during byte compilation.
-See [[compat-srht:4]].
-
-(Release <2022-06-19 Sun>)
-
-* Release of "Compat" Version 28.1.1.2
-
-Two main changes have necessitated a new patch release:
-
-1. Fix issues related to the loading of compat when uncompiled.  See
-   [[https://lists.sr.ht/~pkal/compat-devel/%3C20220530191000.2183047-1-jonas%40bernoul.li%3E][this thread]] for more details on the problem.
-2. Fix issues related to the loading of compat on old pre-releases
-   (think of 28.0.50). See [[https://lists.sr.ht/~pkal/compat-devel/%3Cf8635d7d-e233-448f-b325-9e850363241c%40www.fastmail.com%3E][this thread]] for more details on the
-   problem.
-
-(Released <2022-06-22 Wed>)
-
-* Release of "Compat" Version 28.1.1.1
-
-This is a minor release fixing a bug in =json-serialize=, that could
-cause unintended side-effects, not related to packages using Compat
-directly (see [[compat-srht:2]]).
-
-(Released <2022-05-05 Thu>)
-
-* Release of "Compat" Version 28.1.1.0
-
-This release mostly fixes a number of smaller bugs that were not
-identified as of 28.1.0.0.  Nevertheless these warrent a version bump,
-as some of these changes a functional.  These include:
-
-- The addition of the =file-attribute-*= accessor functions.
-- The addition of =file-attribute-collect=.
-- Improvements to the Texinfo manual (via Jonas Bernoulli's recent
-  work on =ox-texinfo=).  For the time being, the Texinfo file is
-  maintained in the repository itself, next to the =MANUAL= file.
-  This might change in the future.
-- Adding a prefix to =string-trim=, =string-trim-left= and
-  =string-trim-right= (i.e. now =compat-string-trim=,
-  =compat-string-trim-left= and =compat-string-trim-right=)
-- Improving the version inference used in the =compat-*= macros.
-  This improves the compile-time optimisation that strips away
-  functions that are known to be defined for a specific version.
-- The addition of generalised variable (=setf=) support for
-  =compat-alist-get=.
-- The addition of =image-property= and generalised variable support
-  for =image-property=.
-- The addition of the function =compat-executable-find=.
-- The addition of the function =compat-dired-get-marked-files=.
-- The addition of the function =exec-path=.
-- The addition of the function =make-lock-file-name=.
-- The addition of the function =null-device=.
-- The addition of the function =time-equal-p=.
-- The addition of the function =date-days-in-month=.
-- Handling out-of-directory byte compilation better.
-- Fixing the usage and edge-cases of =and-let*=.
-
-(Released <2022-04-22 Fri>)
diff --git a/elpa/compat-29.1.4.1/compat-25.el b/elpa/compat-29.1.4.1/compat-25.el
deleted file mode 100644 (file)
index b393dc8..0000000
+++ /dev/null
@@ -1,271 +0,0 @@
-;;; compat-25.el --- Functionality added in Emacs 25.1 -*- lexical-binding: t; -*-
-
-;; Copyright (C) 2021-2023 Free Software Foundation, Inc.
-
-;; This program is free software; you can redistribute it and/or modify
-;; it under the terms of the GNU General Public License as published by
-;; the Free Software Foundation, either version 3 of the License, or
-;; (at your option) any later version.
-
-;; This program is distributed in the hope that it will be useful,
-;; but WITHOUT ANY WARRANTY; without even the implied warranty of
-;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-;; GNU General Public License for more details.
-
-;; You should have received a copy of the GNU General Public License
-;; along with this program.  If not, see <https://www.gnu.org/licenses/>.
-
-;;; Commentary:
-
-;; Functionality added in Emacs 25.1, needed by older Emacs versions.
-
-;;; Code:
-
-(eval-when-compile (load "compat-macs.el" nil t t))
-
-(compat-version "25.1")
-
-;;;; Defined in alloc.c
-
-(compat-defun bool-vector (&rest objects) ;; <compat-tests:bool-vector>
-  "Return a new bool-vector with specified arguments as elements.
-Allows any number of arguments, including zero.
-usage: (bool-vector &rest OBJECTS)"
-  (let ((vec (make-bool-vector (length objects) nil))
-        (i 0))
-    (while objects
-      (when (car objects)
-        (aset vec i t))
-      (setq objects (cdr objects)
-            i (1+ i)))
-    vec))
-
-;;;; Defined in fns.c
-
-(compat-defun sort (seq predicate) ;; <compat-tests:sort>
-  "Handle vector SEQ."
-  :extended t
-  (cond
-   ((listp seq)
-    (sort seq predicate))
-   ((vectorp seq)
-    (let* ((list (sort (append seq nil) predicate))
-           (p list) (i 0))
-      (while p
-        (aset seq i (car p))
-        (setq i (1+ i) p (cdr p)))
-      (apply #'vector list)))
-   ((signal 'wrong-type-argument 'list-or-vector-p))))
-
-;;;; Defined in editfns.c
-
-(compat-defalias format-message format) ;; <compat-tests:format-message>
-
-;;;; Defined in fileio.c
-
-(compat-defun directory-name-p (name) ;; <compat-tests:directory-name-p>
-  "Return non-nil if NAME ends with a directory separator character."
-  (eq (eval-when-compile
-        (if (memq system-type '(cygwin windows-nt ms-dos))
-            ?\\ ?/))
-      (aref name (1- (length name)))))
-
-;;;; Defined in doc.c
-
-(compat-defvar text-quoting-style nil ;; <compat-tests:text-quoting-style>
-  "Style to use for single quotes in help and messages.
-
-The value of this variable determines substitution of grave accents
-and apostrophes in help output (but not for display of Info
-manuals) and in functions like `message' and `format-message', but not
-in `format'.
-
-The value should be one of these symbols:
-  `curve':    quote with curved single quotes ‘like this’.
-  `straight': quote with straight apostrophes \\='like this\\='.
-  `grave':    quote with grave accent and apostrophe \\=`like this\\=';
-              i.e., do not alter the original quote marks.
-  nil:        like `curve' if curved single quotes are displayable,
-              and like `grave' otherwise.  This is the default.
-
-You should never read the value of this variable directly from a Lisp
-program.  Use the function `text-quoting-style' instead, as that will
-compute the correct value for the current terminal in the nil case.")
-
-;;;; Defined in simple.el
-
-;; `save-excursion' behaved like `save-mark-and-excursion' before 25.1.
-(compat-defalias save-mark-and-excursion save-excursion) ;; <compat-tests:save-mark-and-excursion>
-
-(declare-function region-bounds nil) ;; Defined in compat-26.el
-(compat-defun region-noncontiguous-p () ;; <compat-tests:region-noncontiguous-p>
-  "Return non-nil if the region contains several pieces.
-An example is a rectangular region handled as a list of
-separate contiguous regions for each line."
-  (let ((bounds (region-bounds))) (and (cdr bounds) bounds)))
-
-;;;; Defined in subr.el
-
-(compat-defun string-greaterp (string1 string2) ;; <compat-tests:string-greaterp>
-  "Return non-nil if STRING1 is greater than STRING2 in lexicographic order.
-Case is significant.
-Symbols are also allowed; their print names are used instead."
-  (string-lessp string2 string1))
-
-(compat-defmacro with-file-modes (modes &rest body) ;; <compat-tests:with-file-modes>
-  "Execute BODY with default file permissions temporarily set to MODES.
-MODES is as for `set-default-file-modes'."
-  (declare (indent 1) (debug t))
-  (let ((umask (make-symbol "umask")))
-    `(let ((,umask (default-file-modes)))
-       (unwind-protect
-           (progn
-             (set-default-file-modes ,modes)
-             ,@body)
-         (set-default-file-modes ,umask)))))
-
-(compat-defmacro if-let (spec then &rest else) ;; <compat-tests:if-let>
-  "Bind variables according to SPEC and evaluate THEN or ELSE.
-Evaluate each binding in turn, as in `let*', stopping if a
-binding value is nil.  If all are non-nil return the value of
-THEN, otherwise the last form in ELSE.
-
-Each element of SPEC is a list (SYMBOL VALUEFORM) that binds
-SYMBOL to the value of VALUEFORM.  An element can additionally be
-of the form (VALUEFORM), which is evaluated and checked for nil;
-i.e. SYMBOL can be omitted if only the test result is of
-interest.  It can also be of the form SYMBOL, then the binding of
-SYMBOL is checked for nil.
-
-As a special case, interprets a SPEC of the form \(SYMBOL SOMETHING)
-like \((SYMBOL SOMETHING)).  This exists for backward compatibility
-with an old syntax that accepted only one binding."
-  (declare (indent 2)
-           (debug ([&or (symbolp form)
-                        (&rest [&or symbolp (symbolp form) (form)])]
-                   body)))
-  (when (and (<= (length spec) 2) (not (listp (car spec))))
-    ;; Adjust the single binding case
-    (setq spec (list spec)))
-  (let ((empty (make-symbol "s"))
-        (last t) list)
-    (dolist (var spec)
-      (push `(,(if (cdr var) (car var) empty)
-              (and ,last ,(if (cdr var) (cadr var) (car var))))
-            list)
-      (when (or (cdr var) (consp (car var)))
-        (setq last (caar list))))
-    `(let* ,(nreverse list)
-       (if ,(caar list) ,then ,@else))))
-
-(compat-defmacro when-let (spec &rest body) ;; <compat-tests:when-let>
-  "Bind variables according to SPEC and conditionally evaluate BODY.
-Evaluate each binding in turn, stopping if a binding value is nil.
-If all are non-nil, return the value of the last form in BODY.
-
-The variable list SPEC is the same as in `if-let'."
-  (declare (indent 1) (debug if-let))
-  (list 'if-let spec (macroexp-progn body)))
-
-;;;; Defined in subr-x.el
-
-(compat-defun hash-table-empty-p (hash-table) ;; <compat-tests:hash-table-empty-p>
-  "Check whether HASH-TABLE is empty (has 0 elements)."
-  (zerop (hash-table-count hash-table)))
-
-(compat-defmacro thread-first (&rest forms) ;; <compat-tests:thread-first>
-  "Thread FORMS elements as the first argument of their successor.
-Example:
-    (thread-first
-      5
-      (+ 20)
-      (/ 25)
-      -
-      (+ 40))
-Is equivalent to:
-    (+ (- (/ (+ 5 20) 25)) 40)
-Note how the single `-' got converted into a list before
-threading."
-  (declare (indent 1)
-           (debug (form &rest [&or symbolp (sexp &rest form)])))
-  (let ((body (car forms)))
-    (dolist (form (cdr forms))
-      (when (symbolp form)
-        (setq form (list form)))
-      (setq body (append (list (car form))
-                         (list body)
-                         (cdr form))))
-    body))
-
-(compat-defmacro thread-last (&rest forms) ;; <compat-tests:thread-last>
-  "Thread FORMS elements as the last argument of their successor.
-Example:
-    (thread-last
-      5
-      (+ 20)
-      (/ 25)
-      -
-      (+ 40))
-Is equivalent to:
-    (+ 40 (- (/ 25 (+ 20 5))))
-Note how the single `-' got converted into a list before
-threading."
-  (declare (indent 1) (debug thread-first))
-  (let ((body (car forms)))
-    (dolist (form (cdr forms))
-      (when (symbolp form)
-        (setq form (list form)))
-      (setq body (append form (list body))))
-    body))
-
-;;;; Defined in macroexp.el
-
-(compat-defun macroexp-parse-body (body) ;; <compat-tests:macroexp-parse-body>
-  "Parse a function BODY into (DECLARATIONS . EXPS)."
-  (let ((decls ()))
-    (while (and (cdr body)
-                (let ((e (car body)))
-                  (or (stringp e)
-                      (memq (car-safe e)
-                            '(:documentation declare interactive cl-declare)))))
-      (push (pop body) decls))
-    (cons (nreverse decls) body)))
-
-(compat-defun macroexp-quote (v) ;; <compat-tests:macroexp-quote>
-  "Return an expression E such that `(eval E)' is V.
-
-E is either V or (quote V) depending on whether V evaluates to
-itself or not."
-  (if (and (not (consp v))
-           (or (keywordp v)
-               (not (symbolp v))
-               (memq v '(nil t))))
-      v
-    (list 'quote v)))
-
-(compat-defun macroexpand-1 (form &optional environment) ;; <compat-tests:macroexpand-1>
-  "Perform (at most) one step of macro expansion."
-  (cond
-   ((consp form)
-    (let* ((head (car form))
-           (env-expander (assq head environment)))
-      (if env-expander
-          (if (cdr env-expander)
-              (apply (cdr env-expander) (cdr form))
-            form)
-        (if (not (and (symbolp head) (fboundp head)))
-            form
-          (let ((def (autoload-do-load (symbol-function head) head 'macro)))
-            (cond
-             ;; Follow alias, but only for macros, otherwise we may end up
-             ;; skipping an important compiler-macro (e.g. cl--block-wrapper).
-             ((and (symbolp def) (macrop def)) (cons def (cdr form)))
-             ((not (consp def)) form)
-             (t
-              (if (eq 'macro (car def))
-                  (apply (cdr def) (cdr form))
-                form))))))))
-   (t form)))
-
-(provide 'compat-25)
-;;; compat-25.el ends here
diff --git a/elpa/compat-29.1.4.1/compat-26.el b/elpa/compat-29.1.4.1/compat-26.el
deleted file mode 100644 (file)
index 0c22fbf..0000000
+++ /dev/null
@@ -1,554 +0,0 @@
-;;; compat-26.el --- Functionality added in Emacs 26.1 -*- lexical-binding: t; -*-
-
-;; Copyright (C) 2021-2023 Free Software Foundation, Inc.
-
-;; This program is free software; you can redistribute it and/or modify
-;; it under the terms of the GNU General Public License as published by
-;; the Free Software Foundation, either version 3 of the License, or
-;; (at your option) any later version.
-
-;; This program is distributed in the hope that it will be useful,
-;; but WITHOUT ANY WARRANTY; without even the implied warranty of
-;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-;; GNU General Public License for more details.
-
-;; You should have received a copy of the GNU General Public License
-;; along with this program.  If not, see <https://www.gnu.org/licenses/>.
-
-;;; Commentary:
-
-;; Functionality added in Emacs 26.1, needed by older Emacs versions.
-
-;;; Code:
-
-(eval-when-compile (load "compat-macs.el" nil t t))
-(compat-require compat-25 "25.1")
-
-(compat-version "26.1")
-
-;;;; Defined in fns.c
-
-(compat-defun buffer-hash (&optional buffer-or-name) ;; <compat-tests:buffer-hash>
-   "Return a hash of the contents of BUFFER-OR-NAME.
-This hash is performed on the raw internal format of the buffer,
-disregarding any coding systems.  If nil, use the current buffer.
-
-This function is useful for comparing two buffers running in the same
-Emacs, but is not guaranteed to return the same hash between different
-Emacs versions.  It should be somewhat more efficient on larger
-buffers than `secure-hash' is, and should not allocate more memory.
-
-It should not be used for anything security-related.  See
-`secure-hash' for these applications."
-   (with-current-buffer (or buffer-or-name (current-buffer))
-     (save-restriction
-       (widen)
-       (sha1 (current-buffer) (point-min) (point-max)))))
-
-(compat-defun mapcan (func sequence) ;; <compat-tests:mapcan>
-  "Apply FUNC to each element of SEQUENCE.
-Concatenate the results by altering them (using `nconc').
-SEQUENCE may be a list, a vector, a boolean vector, or a string."
-  (apply #'nconc (mapcar func sequence)))
-
-(compat-defun line-number-at-pos (&optional position absolute) ;; <compat-tests:line-number-at-pos>
-  "Handle optional argument ABSOLUTE."
-  :extended t
-  (if absolute
-      (save-restriction
-        (widen)
-        (line-number-at-pos position))
-    (line-number-at-pos position)))
-
-;;;; Defined in simple.el
-
-(compat-defun region-bounds () ;; <compat-tests:region-bounds>
-  "Return the boundaries of the region.
-Value is a list of one or more cons cells of the form (START . END).
-It will have more than one cons cell when the region is non-contiguous,
-see `region-noncontiguous-p' and `extract-rectangle-bounds'."
-  (if (eval-when-compile (< emacs-major-version 25))
-      ;; FIXME: The `region-extract-function' of Emacs 24 has no support for the
-      ;; bounds argument.
-      (list (cons (region-beginning) (region-end)))
-    (funcall region-extract-function 'bounds)))
-
-;;;; Defined in subr.el
-
-(compat-defun provided-mode-derived-p (mode &rest modes) ;; <compat-tests:provided-derived-mode-p>
-  "Non-nil if MODE is derived from one of MODES.
-Uses the `derived-mode-parent' property of the symbol to trace backwards.
-If you just want to check `major-mode', use `derived-mode-p'."
-  ;; If MODE is an alias, then look up the real mode function first.
-  (let ((alias (symbol-function mode)))
-    (when (and alias (symbolp alias))
-      (setq mode alias)))
-  (while
-      (and
-       (not (memq mode modes))
-       (let* ((parent (get mode 'derived-mode-parent))
-              (parentfn (symbol-function parent)))
-         (setq mode (if (and parentfn (symbolp parentfn)) parentfn parent)))))
-  mode)
-
-(compat-defun assoc (key alist &optional testfn) ;; <compat-tests:assoc>
-  "Handle the optional TESTFN."
-  :extended t
-  (cond
-   ((or (eq testfn #'eq)
-        (and (not testfn) (or (symbolp key) (integerp key)))) ;; eq_comparable_value
-    (assq key alist))
-   ((or (eq testfn #'equal) (not testfn))
-    (assoc key alist))
-   (t
-    (catch 'found
-      (dolist (ent alist)
-        (when (funcall testfn (car ent) key)
-          (throw 'found ent)))))))
-
-(compat-defun alist-get (key alist &optional default remove testfn) ;; <compat-tests:alist-get>
-  "Handle optional argument TESTFN."
-  :extended "25.1"
-  (ignore remove)
-  (let ((x (if (not testfn)
-               (assq key alist)
-             (compat--assoc key alist testfn))))
-    (if x (cdr x) default)))
-
-(compat-guard t ;; <compat-tests:alist-get-gv>
-  (gv-define-expander compat--alist-get
-    (lambda (do key alist &optional default remove testfn)
-      (macroexp-let2 macroexp-copyable-p k key
-        (gv-letplace (getter setter) alist
-          (macroexp-let2 nil p `(compat--assoc ,k ,getter ,testfn)
-            (funcall do (if (null default) `(cdr ,p)
-                          `(if ,p (cdr ,p) ,default))
-                     (lambda (v)
-                       (macroexp-let2 nil v v
-                         (let ((set-exp
-                                `(if ,p (setcdr ,p ,v)
-                                   ,(funcall setter
-                                             `(cons (setq ,p (cons ,k ,v))
-                                                    ,getter)))))
-                           `(progn
-                              ,(cond
-                                ((null remove) set-exp)
-                                ((or (eql v default)
-                                     (and (eq (car-safe v) 'quote)
-                                          (eq (car-safe default) 'quote)
-                                          (eql (cadr v) (cadr default))))
-                                 `(if ,p ,(funcall setter `(delq ,p ,getter))))
-                                (t
-                                 `(cond
-                                   ((not (eql ,default ,v)) ,set-exp)
-                                   (,p ,(funcall setter
-                                                 `(delq ,p ,getter))))))
-                              ,v))))))))))
-    (unless (get 'alist-get 'gv-expander)
-      (put 'alist-get 'gv-expander (get 'compat--alist-get 'gv-expander))))
-
-(compat-defun string-trim-left (string &optional regexp) ;; <compat-tests:string-trim-left>
-  "Handle optional argument REGEXP."
-  :extended t
-  (if (string-match (concat "\\`\\(?:" (or regexp "[ \t\n\r]+") "\\)") string)
-      (substring string (match-end 0))
-    string))
-
-(compat-defun string-trim-right (string &optional regexp) ;; <compat-tests:string-trim-right>
-  "Handle optional argument REGEXP."
-  :extended t
-  (let ((i (string-match-p
-            (concat "\\(?:" (or regexp "[ \t\n\r]+") "\\)\\'")
-            string)))
-    (if i (substring string 0 i) string)))
-
-(compat-defun string-trim (string &optional trim-left trim-right) ;; <compat-tests:string-trim>
-  "Handle optional arguments TRIM-LEFT and TRIM-RIGHT."
-  :extended t
-  (compat--string-trim-left
-   (compat--string-trim-right
-    string
-    trim-right)
-   trim-left))
-
-(compat-defun caaar (x) ;; <compat-tests:cXXXr>
-  "Return the `car' of the `car' of the `car' of X."
-  (declare (pure t))
-  (car (car (car x))))
-
-(compat-defun caadr (x) ;; <compat-tests:cXXXr>
-  "Return the `car' of the `car' of the `cdr' of X."
-  (declare (pure t))
-  (car (car (cdr x))))
-
-(compat-defun cadar (x) ;; <compat-tests:cXXXr>
-  "Return the `car' of the `cdr' of the `car' of X."
-  (declare (pure t))
-  (car (cdr (car x))))
-
-(compat-defun caddr (x) ;; <compat-tests:cXXXr>
-  "Return the `car' of the `cdr' of the `cdr' of X."
-  (declare (pure t))
-  (car (cdr (cdr x))))
-
-(compat-defun cdaar (x) ;; <compat-tests:cXXXr>
-  "Return the `cdr' of the `car' of the `car' of X."
-  (declare (pure t))
-  (cdr (car (car x))))
-
-(compat-defun cdadr (x) ;; <compat-tests:cXXXr>
-  "Return the `cdr' of the `car' of the `cdr' of X."
-  (declare (pure t))
-  (cdr (car (cdr x))))
-
-(compat-defun cddar (x) ;; <compat-tests:cXXXr>
-  "Return the `cdr' of the `cdr' of the `car' of X."
-  (declare (pure t))
-  (cdr (cdr (car x))))
-
-(compat-defun cdddr (x) ;; <compat-tests:cXXXr>
-  "Return the `cdr' of the `cdr' of the `cdr' of X."
-  (declare (pure t))
-  (cdr (cdr (cdr x))))
-
-(compat-defun caaaar (x) ;; <compat-tests:cXXXXr>
-  "Return the `car' of the `car' of the `car' of the `car' of X."
-  (declare (pure t))
-  (car (car (car (car x)))))
-
-(compat-defun caaadr (x) ;; <compat-tests:cXXXXr>
-  "Return the `car' of the `car' of the `car' of the `cdr' of X."
-  (declare (pure t))
-  (car (car (car (cdr x)))))
-
-(compat-defun caadar (x) ;; <compat-tests:cXXXXr>
-  "Return the `car' of the `car' of the `cdr' of the `car' of X."
-  (declare (pure t))
-  (car (car (cdr (car x)))))
-
-(compat-defun caaddr (x) ;; <compat-tests:cXXXXr>
-  "Return the `car' of the `car' of the `cdr' of the `cdr' of X."
-  (declare (pure t))
-  (car (car (cdr (cdr x)))))
-
-(compat-defun cadaar (x) ;; <compat-tests:cXXXXr>
-  "Return the `car' of the `cdr' of the `car' of the `car' of X."
-  (declare (pure t))
-  (car (cdr (car (car x)))))
-
-(compat-defun cadadr (x) ;; <compat-tests:cXXXXr>
-  "Return the `car' of the `cdr' of the `car' of the `cdr' of X."
-  (declare (pure t))
-  (car (cdr (car (cdr x)))))
-
-(compat-defun caddar (x) ;; <compat-tests:cXXXXr>
-  "Return the `car' of the `cdr' of the `cdr' of the `car' of X."
-  (declare (pure t))
-  (car (cdr (cdr (car x)))))
-
-(compat-defun cadddr (x) ;; <compat-tests:cXXXXr>
-  "Return the `car' of the `cdr' of the `cdr' of the `cdr' of X."
-  (declare (pure t))
-  (car (cdr (cdr (cdr x)))))
-
-(compat-defun cdaaar (x) ;; <compat-tests:cXXXXr>
-  "Return the `cdr' of the `car' of the `car' of the `car' of X."
-  (declare (pure t))
-  (cdr (car (car (car x)))))
-
-(compat-defun cdaadr (x) ;; <compat-tests:cXXXXr>
-  "Return the `cdr' of the `car' of the `car' of the `cdr' of X."
-  (declare (pure t))
-  (cdr (car (car (cdr x)))))
-
-(compat-defun cdadar (x) ;; <compat-tests:cXXXXr>
-  "Return the `cdr' of the `car' of the `cdr' of the `car' of X."
-  (declare (pure t))
-  (cdr (car (cdr (car x)))))
-
-(compat-defun cdaddr (x) ;; <compat-tests:cXXXXr>
-  "Return the `cdr' of the `car' of the `cdr' of the `cdr' of X."
-  (declare (pure t))
-  (cdr (car (cdr (cdr x)))))
-
-(compat-defun cddaar (x) ;; <compat-tests:cXXXXr>
-  "Return the `cdr' of the `cdr' of the `car' of the `car' of X."
-  (declare (pure t))
-  (cdr (cdr (car (car x)))))
-
-(compat-defun cddadr (x) ;; <compat-tests:cXXXXr>
-  "Return the `cdr' of the `cdr' of the `car' of the `cdr' of X."
-  (declare (pure t))
-  (cdr (cdr (car (cdr x)))))
-
-(compat-defun cdddar (x) ;; <compat-tests:cXXXXr>
-  "Return the `cdr' of the `cdr' of the `cdr' of the `car' of X."
-  (declare (pure t))
-  (cdr (cdr (cdr (car x)))))
-
-(compat-defun cddddr (x) ;; <compat-tests:cXXXXr>
-  "Return the `cdr' of the `cdr' of the `cdr' of the `cdr' of X."
-  (declare (pure t))
-  (cdr (cdr (cdr (cdr x)))))
-
-(compat-defvar gensym-counter 0 ;; <compat-tests:gensym>
-  "Number used to construct the name of the next symbol created by `gensym'.")
-
-(compat-defun gensym (&optional prefix) ;; <compat-tests:gensym>
-  "Return a new uninterned symbol.
-The name is made by appending `gensym-counter' to PREFIX.
-PREFIX is a string, and defaults to \"g\"."
-  (let ((num (prog1 gensym-counter
-               (setq gensym-counter
-                     (1+ gensym-counter)))))
-    (make-symbol (format "%s%d" (or prefix "g") num))))
-
-(compat-defmacro if-let* (varlist then &rest else) ;; <compat-tests:if-let*>
-  "Bind variables according to VARLIST and evaluate THEN or ELSE.
-This is like `if-let' but doesn't handle a VARLIST of the form
-\(SYMBOL SOMETHING) specially."
-  (declare (indent 2)
-           (debug ((&rest [&or symbolp (symbolp form) (form)])
-                   body)))
-  (let ((empty (make-symbol "s"))
-        (last t) list)
-    (dolist (var varlist)
-      (push `(,(if (cdr var) (car var) empty)
-              (and ,last ,(if (cdr var) (cadr var) (car var))))
-            list)
-      (when (or (cdr var) (consp (car var)))
-        (setq last (caar list))))
-    `(let* ,(nreverse list)
-       (if ,(caar list) ,then ,@else))))
-
-(compat-defmacro when-let* (varlist &rest body) ;; <compat-tests:when-let*>
-  "Bind variables according to VARLIST and conditionally evaluate BODY.
-This is like `when-let' but doesn't handle a VARLIST of the form
-\(SYMBOL SOMETHING) specially."
-  (declare (indent 1) (debug if-let*))
-  (list 'if-let* varlist (macroexp-progn body)))
-
-(compat-defmacro and-let* (varlist &rest body) ;; <compat-tests:and-let*>
-  "Bind variables according to VARLIST and conditionally evaluate BODY.
-Like `when-let*', except if BODY is empty and all the bindings
-are non-nil, then the result is non-nil."
-  (declare (indent 1)
-           (debug ((&rest [&or symbolp (symbolp form) (form)])
-                   body)))
-  (let ((empty (make-symbol "s"))
-        (last t) list)
-    (dolist (var varlist)
-      (push `(,(if (cdr var) (car var) empty)
-              (and ,last ,(if (cdr var) (cadr var) (car var))))
-            list)
-      (when (or (cdr var) (consp (car var)))
-        (setq last (caar list))))
-    `(let* ,(nreverse list)
-       (if ,(caar list) ,(macroexp-progn (or body '(t)))))))
-
-;;;; Defined in files.el
-
-(compat-defvar mounted-file-systems ;; <compat-tests:mounted-file-systems>
-    (eval-when-compile
-      (if (memq system-type '(windows-nt cygwin))
-          "^//[^/]+/"
-        (concat
-         "^" (regexp-opt '("/afs/" "/media/" "/mnt" "/net/" "/tmp_mnt/")))))
-  "File systems that ought to be mounted.")
-
-(compat-defun file-local-name (file) ;; <compat-tests:file-local-name>
-  "Return the local name component of FILE.
-This function removes from FILE the specification of the remote host
-and the method of accessing the host, leaving only the part that
-identifies FILE locally on the remote system.
-The returned file name can be used directly as argument of
-`process-file', `start-file-process', or `shell-command'."
-  (or (file-remote-p file 'localname) file))
-
-(compat-defun temporary-file-directory () ;; <compat-tests:temporary-file-directory>
-  "The directory for writing temporary files.
-In case of a remote `default-directory', this is a directory for
-temporary files on that remote host.  If such a directory does
-not exist, or `default-directory' ought to be located on a
-mounted file system (see `mounted-file-systems'), the function
-returns `default-directory'.
-For a non-remote and non-mounted `default-directory', the value of
-the variable `temporary-file-directory' is returned."
-  ;; NOTE: The handler may fail with an error, since the
-  ;; `temporary-file-directory' handler was introduced in Emacs 26.
-  (let ((handler (find-file-name-handler
-                  default-directory 'temporary-file-directory)))
-    (or (and handler (ignore-errors (funcall handler 'temporary-file-directory)))
-        (if-let ((remote (file-remote-p default-directory)))
-            (concat remote "/tmp/") ;; FIXME: Guess /tmp on remote host
-          (if (string-match mounted-file-systems default-directory)
-              default-directory
-            temporary-file-directory)))))
-
-(compat-defun make-temp-file (prefix &optional dir-flag suffix text) ;; <compat-tests:make-temp-file>
-  "Handle optional argument TEXT."
-  :extended t
-  (let ((file (make-temp-file prefix dir-flag suffix)))
-    (when text
-      (with-temp-buffer
-        (insert text)
-        (write-region (point-min) (point-max) file)))
-    file))
-
-(compat-defun make-nearby-temp-file (prefix &optional dir-flag suffix) ;; <compat-tests:make-nearby-temp-file>
-  "Create a temporary file as close as possible to `default-directory'.
-If PREFIX is a relative file name, and `default-directory' is a
-remote file name or located on a mounted file systems, the
-temporary file is created in the directory returned by the
-function `temporary-file-directory'.  Otherwise, the function
-`make-temp-file' is used.  PREFIX, DIR-FLAG and SUFFIX have the
-same meaning as in `make-temp-file'."
-  ;; NOTE: The handler may fail with an error, since the
-  ;; `make-nearby-temp-file' handler was introduced in Emacs 26.
-  (let ((handler (and (not (file-name-absolute-p default-directory))
-                      (find-file-name-handler
-                       default-directory 'make-nearby-temp-file))))
-    (or (and handler (ignore-errors (funcall handler 'make-nearby-temp-file
-                                             prefix dir-flag suffix)))
-        (let ((temporary-file-directory (temporary-file-directory)))
-          (make-temp-file prefix dir-flag suffix)))))
-
-(compat-defun file-attribute-type (attributes) ;; <compat-tests:file-attribute-getters>
-  "The type field in ATTRIBUTES returned by `file-attributes'.
-The value is either t for directory, string (name linked to) for
-symbolic link, or nil."
-  (nth 0 attributes))
-
-(compat-defun file-attribute-link-number (attributes) ;; <compat-tests:file-attribute-getters>
-  "Return the number of links in ATTRIBUTES returned by `file-attributes'."
-  (nth 1 attributes))
-
-(compat-defun file-attribute-user-id (attributes) ;; <compat-tests:file-attribute-getters>
-  "The UID field in ATTRIBUTES returned by `file-attributes'.
-This is either a string or a number.  If a string value cannot be
-looked up, a numeric value, either an integer or a float, is
-returned."
-  (nth 2 attributes))
-
-(compat-defun file-attribute-group-id (attributes) ;; <compat-tests:file-attribute-getters>
-  "The GID field in ATTRIBUTES returned by `file-attributes'.
-This is either a string or a number.  If a string value cannot be
-looked up, a numeric value, either an integer or a float, is
-returned."
-  (nth 3 attributes))
-
-(compat-defun file-attribute-access-time (attributes) ;; <compat-tests:file-attribute-getters>
-  "The last access time in ATTRIBUTES returned by `file-attributes'.
-This a Lisp timestamp in the style of `current-time'."
-  (nth 4 attributes))
-
-(compat-defun file-attribute-modification-time (attributes) ;; <compat-tests:file-attribute-getters>
-  "The modification time in ATTRIBUTES returned by `file-attributes'.
-This is the time of the last change to the file's contents, and
-is a Lisp timestamp in the style of `current-time'."
-  (nth 5 attributes))
-
-(compat-defun file-attribute-status-change-time (attributes) ;; <compat-tests:file-attribute-getters>
-  "The status modification time in ATTRIBUTES returned by `file-attributes'.
-This is the time of last change to the file's attributes: owner
-and group, access mode bits, etc., and is a Lisp timestamp in the
-style of `current-time'."
-  (nth 6 attributes))
-
-(compat-defun file-attribute-size (attributes) ;; <compat-tests:file-attribute-getters>
-  "The integer size (in bytes) in ATTRIBUTES returned by `file-attributes'."
-  (nth 7 attributes))
-
-(compat-defun file-attribute-modes (attributes) ;; <compat-tests:file-attribute-getters>
-  "The file modes in ATTRIBUTES returned by `file-attributes'.
-This is a string of ten letters or dashes as in ls -l."
-  (nth 8 attributes))
-
-(compat-defun file-attribute-inode-number (attributes) ;; <compat-tests:file-attribute-getters>
-  "The inode number in ATTRIBUTES returned by `file-attributes'.
-It is a nonnegative integer."
-  (nth 10 attributes))
-
-(compat-defun file-attribute-device-number (attributes) ;; <compat-tests:file-attribute-getters>
-  "The file system device number in ATTRIBUTES returned by `file-attributes'.
-It is an integer."
-  (nth 11 attributes))
-
-(compat-defun file-attribute-collect (attributes &rest attr-names) ;; <compat-tests:file-attribute-collect>
-  "Return a sublist of ATTRIBUTES returned by `file-attributes'.
-ATTR-NAMES are symbols with the selected attribute names.
-
-Valid attribute names are: type, link-number, user-id, group-id,
-access-time, modification-time, status-change-time, size, modes,
-inode-number and device-number."
-  (let ((idx '((type . 0)
-               (link-number . 1)
-               (user-id . 2)
-               (group-id . 3)
-               (access-time . 4)
-               (modification-time . 5)
-               (status-change-time . 6)
-               (size . 7)
-               (modes . 8)
-               (inode-number . 10)
-               (device-number . 11)))
-        result)
-    (while attr-names
-      (let ((attr (pop attr-names)))
-        (if (assq attr idx)
-            (push (nth (cdr (assq attr idx))
-                       attributes)
-                  result)
-          (error "Wrong attribute name '%S'" attr))))
-    (nreverse result)))
-
-;;;; Defined in mouse.el
-
-(compat-defvar mouse-select-region-move-to-beginning nil ;; <compat-tests:thing-at-mouse>
-  "Effect of selecting a region extending backward from double click.
-Nil means keep point at the position clicked (region end);
-non-nil means move point to beginning of region.")
-
-;;;; Defined in image.el
-
-(compat-defun image-property (image property) ;; <compat-tests:image-property>
-  "Return the value of PROPERTY in IMAGE.
-Properties can be set with
-
-  (setf (image-property IMAGE PROPERTY) VALUE)
-
-If VALUE is nil, PROPERTY is removed from IMAGE."
-  :feature image
-  (plist-get (cdr image) property))
-
-;;;; Defined in rmc.el
-
-(compat-defun read-multiple-choice (prompt choices) ;; <compat-tests:read-multiple-choice>
-  "Ask user to select an entry from CHOICES, promting with PROMPT.
-This function allows to ask the user a multiple-choice question.
-
-CHOICES should be a list of the form (KEY NAME [DESCRIPTION]).
-KEY is a character the user should type to select the entry.
-NAME is a short name for the entry to be displayed while prompting
-\(if there's no room, it might be shortened).
-
-NOTE: This is a partial implementation of `read-multiple-choice', that
-among other things doesn't offer any help and ignores the
-optional DESCRIPTION field."
-  (let ((options
-         (mapconcat
-          (lambda (opt)
-            (format
-             "[%s] %s"
-             (key-description (string (car opt)))
-             (cadr opt)))
-          choices " "))
-        choice)
-    (setq prompt (concat prompt " (" options "): "))
-    (while (not (setq choice (assq (read-event prompt) choices)))
-      (message "Invalid choice")
-      (sit-for 1))
-    choice))
-
-(provide 'compat-26)
-;;; compat-26.el ends here
diff --git a/elpa/compat-29.1.4.1/compat-27.el b/elpa/compat-29.1.4.1/compat-27.el
deleted file mode 100644 (file)
index 3ff075d..0000000
+++ /dev/null
@@ -1,885 +0,0 @@
-;;; compat-27.el --- Functionality added in Emacs 27.1 -*- lexical-binding: t; -*-
-
-;; Copyright (C) 2021-2023 Free Software Foundation, Inc.
-
-;; This program is free software; you can redistribute it and/or modify
-;; it under the terms of the GNU General Public License as published by
-;; the Free Software Foundation, either version 3 of the License, or
-;; (at your option) any later version.
-
-;; This program is distributed in the hope that it will be useful,
-;; but WITHOUT ANY WARRANTY; without even the implied warranty of
-;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-;; GNU General Public License for more details.
-
-;; You should have received a copy of the GNU General Public License
-;; along with this program.  If not, see <https://www.gnu.org/licenses/>.
-
-;;; Commentary:
-
-;; Functionality added in Emacs 27.1, needed by older Emacs versions.
-
-;;; Code:
-
-(eval-when-compile (load "compat-macs.el" nil t t))
-(compat-require compat-26 "26.1")
-
-(compat-version "27.1")
-
-;;;; Defined in fns.c
-
-(compat-defun proper-list-p (object) ;; <compat-tests:proper-list-p>
-  "Return OBJECT's length if it is a proper list, nil otherwise.
-A proper list is neither circular nor dotted (i.e., its last cdr
-is nil)."
-  (if (eval-when-compile (< emacs-major-version 26))
-      ;; On older Emacs than 26.1 use Tortoise and Hare algorithm
-      (when (listp object)
-        (catch 'cycle
-          (let ((hare object) (tortoise object)
-                (max 2) (q 2))
-            (while (consp hare)
-              (setq hare (cdr hare))
-              (when (and (or (/= 0 (setq q (1- q)))
-                             (ignore
-                              (setq max (ash max 1)
-                                    q max
-                                    tortoise hare)))
-                         (eq hare tortoise))
-                (throw 'cycle nil)))
-            (and (null hare) (length object)))))
-    ;; Errors on 26.1 and newer
-    (and (listp object) (ignore-errors (length object)))))
-
-(compat-defun string-distance (string1 string2 &optional bytecompare) ;; <compat-tests:string-distance>
-  "Return Levenshtein distance between STRING1 and STRING2.
-The distance is the number of deletions, insertions, and substitutions
-required to transform STRING1 into STRING2.
-If BYTECOMPARE is nil or omitted, compute distance in terms of characters.
-If BYTECOMPARE is non-nil, compute distance in terms of bytes.
-Letter-case is significant, but text properties are ignored."
-  ;; https://en.wikipedia.org/wiki/Levenshtein_distance
-  (let ((s1 (if bytecompare
-                (encode-coding-string string1 'raw-text)
-              (concat string1 "")))
-        (s2 (if bytecompare
-                (encode-coding-string string2 'raw-text)
-              string2)))
-    (let* ((len1 (length s1))
-           (len2 (length s2))
-           (column (make-vector (1+ len1) 0)))
-      (dotimes (y len1)
-        (setf (aref column (1+ y)) y))
-      (dotimes (x len2)
-        (setf (aref column 0) (1+ x))
-        (let ((lastdiag x) olddiag)
-          (dotimes (y len1)
-            (setf olddiag (aref column (1+ y))
-                  (aref column (1+ y))
-                  (min (+ (if (= (aref s1 y) (aref s2 x)) 0 1)
-                          lastdiag)
-                       (1+ (aref column (1+ y)))
-                       (1+ (aref column y)))
-                  lastdiag olddiag))))
-      (aref column len1))))
-
-;;;; Defined in window.c
-
-(compat-defun recenter (&optional arg redisplay) ;; <compat-tests:recenter>
-  "Handle optional argument REDISPLAY."
-  :extended t
-  (recenter arg)
-  (when (and redisplay recenter-redisplay)
-    (redisplay)))
-
-;;;; Defined in keymap.c
-
-(compat-defun lookup-key (keymap key &optional accept-default) ;; <compat-tests:lookup-key>
-  "Allow for KEYMAP to be a list of keymaps."
-  :extended t
-  (cond
-   ((keymapp keymap)
-    (lookup-key keymap key accept-default))
-   ((listp keymap)
-    (catch 'found
-      (dolist (map keymap)
-        (when-let ((fn (lookup-key map key accept-default)))
-          (throw 'found fn)))))
-   ((signal 'wrong-type-argument (list 'keymapp keymap)))))
-
-;;;; Defined in timefns.c
-
-(compat-defun time-equal-p (t1 t2) ;; <compat-tests:time-equal-p>
-  "Return non-nil if time value T1 is equal to time value T2.
-A nil value for either argument stands for the current time.
-
-NOTE: This function is not as accurate as the actual `time-equal-p'."
-  (cond
-   ((eq t1 t2))
-   ((and (consp t1) (consp t2))
-    (equal t1 t2))
-   (t
-    ;; Due to inaccuracies and the relatively slow evaluating of
-    ;; Emacs Lisp compared to C, we allow for slight inaccuracies
-    ;; (less than a millisecond) when comparing time values.
-    (< (abs (- (float-time t1) (float-time t2)))
-       (if (and t1 t2) 1e-6 1e-5)))))
-
-;;;; Defined in subr.el
-
-(compat-defalias fixnump integerp) ;; <compat-tests:fixnump>
-(compat-defalias bignump ignore) ;; <compat-tests:bignump>
-
-(compat-defmacro setq-local (&rest pairs) ;; <compat-tests:setq-local>
-  "Handle multiple assignments."
-  :extended t
-  (unless (zerop (mod (length pairs) 2))
-    (error "PAIRS must have an even number of variable/value members"))
-  (let (body)
-    (while pairs
-      (let* ((sym (pop pairs))
-             (val (pop pairs)))
-        (unless (symbolp sym)
-          (error "Attempting to set a non-symbol: %s" (car pairs)))
-        (push `(set (make-local-variable ',sym) ,val)
-              body)))
-    (cons 'progn (nreverse body))))
-
-(compat-defmacro ignore-error (condition &rest body) ;; <compat-tests:ignore-error>
-  "Execute BODY; if the error CONDITION occurs, return nil.
-Otherwise, return result of last form in BODY.
-
-CONDITION can also be a list of error conditions."
-  (declare (debug t) (indent 1))
-  `(condition-case nil (progn ,@body) (,condition nil)))
-
-(compat-defmacro dolist-with-progress-reporter (spec reporter-or-message &rest body) ;; <compat-tests:dolist-with-progress-reporter>
-  "Loop over a list and report progress in the echo area.
-Evaluate BODY with VAR bound to each car from LIST, in turn.
-Then evaluate RESULT to get return value, default nil.
-
-REPORTER-OR-MESSAGE is a progress reporter object or a string.  In the latter
-case, use this string to create a progress reporter.
-
-At each iteration, print the reporter message followed by progress
-percentage in the echo area.  After the loop is finished,
-print the reporter message followed by the word \"done\".
-
-\(fn (VAR LIST [RESULT]) REPORTER-OR-MESSAGE BODY...)"
-  (declare (indent 2) (debug ((symbolp form &optional form) form body)))
-  (let ((prep (make-symbol "--dolist-progress-reporter--"))
-        (count (make-symbol "--dolist-count--"))
-        (list (make-symbol "--dolist-list--")))
-    `(let ((,prep ,reporter-or-message)
-           (,count 0)
-           (,list ,(cadr spec)))
-       (when (stringp ,prep)
-         (setq ,prep (make-progress-reporter ,prep 0 (length ,list))))
-       (dolist (,(car spec) ,list)
-         ,@body
-         (progress-reporter-update ,prep (setq ,count (1+ ,count))))
-       (progress-reporter-done ,prep)
-       (or ,@(cdr (cdr spec)) nil))))
-
-(compat-defun flatten-tree (tree) ;; <compat-tests:flatten-tree>
-  "Return a \"flattened\" copy of TREE.
-In other words, return a list of the non-nil terminal nodes, or
-leaves, of the tree of cons cells rooted at TREE.  Leaves in the
-returned list are in the same order as in TREE.
-
-\(flatten-tree \\='(1 (2 . 3) nil (4 5 (6)) 7))
-=> (1 2 3 4 5 6 7)"
-  (let (elems)
-    (while (consp tree)
-      (let ((elem (pop tree)))
-        (while (consp elem)
-          (push (cdr elem) tree)
-          (setq elem (car elem)))
-        (if elem (push elem elems))))
-    (if tree (push tree elems))
-    (nreverse elems)))
-
-(compat-defun xor (cond1 cond2) ;; <compat-tests:xor>
-  "Return the boolean exclusive-or of COND1 and COND2.
-If only one of the arguments is non-nil, return it; otherwise
-return nil."
-  (declare (pure t) (side-effect-free error-free))
-  (cond ((not cond1) cond2)
-        ((not cond2) cond1)))
-
-(compat-defvar regexp-unmatchable "\\`a\\`" ;; <compat-tests:regexp-unmatchable>
-  "Standard regexp guaranteed not to match any string at all."
-  :constant t)
-
-(compat-defun assoc-delete-all (key alist &optional test) ;; <compat-tests:assoc-delete-all>
-  "Handle optional argument TEST."
-  :extended "26.2"
-  (unless test (setq test #'equal))
-  (while (and (consp (car alist))
-              (funcall test (caar alist) key))
-    (setq alist (cdr alist)))
-  (let ((tail alist) tail-cdr)
-    (while (setq tail-cdr (cdr tail))
-      (if (and (consp (car tail-cdr))
-               (funcall test (caar tail-cdr) key))
-          (setcdr tail (cdr tail-cdr))
-        (setq tail tail-cdr))))
-  alist)
-
-(compat-defvar major-mode--suspended nil ;; <compat-tests:major-mode-suspend>
-  "Suspended major mode."
-  :local permanent)
-
-(compat-defun major-mode-suspend () ;; <compat-tests:major-mode-suspend>
-  "Exit current major mode, remembering it."
-  (let* ((prev-major-mode (or major-mode--suspended
-                              (unless (eq major-mode 'fundamental-mode)
-                                major-mode))))
-    (kill-all-local-variables)
-    (setq-local major-mode--suspended prev-major-mode)))
-
-(compat-defun major-mode-restore (&optional avoided-modes) ;; <compat-tests:major-mode-suspend>
-  "Restore major mode earlier suspended with `major-mode-suspend'.
-If there was no earlier suspended major mode, then fallback to `normal-mode',
-though trying to avoid AVOIDED-MODES."
-  (if major-mode--suspended
-      (funcall (prog1 major-mode--suspended
-                 (kill-local-variable 'major-mode--suspended)))
-    (let ((auto-mode-alist
-           (let ((alist (copy-sequence auto-mode-alist)))
-             (dolist (mode avoided-modes)
-               (setq alist (rassq-delete-all mode alist)))
-             alist))
-          (magic-fallback-mode-alist
-           (let ((alist (copy-sequence magic-fallback-mode-alist)))
-             (dolist (mode avoided-modes)
-               (setq alist (rassq-delete-all mode alist)))
-             alist)))
-      (normal-mode))))
-
-(compat-defun read-char-from-minibuffer-insert-char () ;; <compat-tests:read-char-from-minibuffer>
-  "Insert the character you type into the minibuffer and exit minibuffer.
-Discard all previous input before inserting and exiting the minibuffer."
-  (interactive)
-  (when (minibufferp)
-    (delete-minibuffer-contents)
-    (insert last-command-event)
-    (exit-minibuffer)))
-
-(compat-defun read-char-from-minibuffer-insert-other () ;; <compat-tests:read-char-from-minibuffer>
-  "Reject a disallowed character typed into the minibuffer.
-This command is intended to be bound to keys that users are not
-allowed to type into the minibuffer.  When the user types any
-such key, this command discard all minibuffer input and displays
-an error message."
-  (interactive)
-  (when (minibufferp)
-    (delete-minibuffer-contents)
-    (ding)
-    (discard-input)
-    (minibuffer-message "Wrong answer")
-    (sit-for 2)))
-
-(compat-defvar read-char-history nil ;; <compat-tests:read-char-from-minibuffer>
-  "The default history for the `read-char-from-minibuffer' function.")
-
-(compat-defvar read-char-from-minibuffer-map ;; <compat-tests:read-char-from-minibuffer>
-  (let ((map (make-sparse-keymap)))
-    (set-keymap-parent map minibuffer-local-map)
-    (define-key map [remap self-insert-command] #'read-char-from-minibuffer-insert-char)
-    (define-key map [remap exit-minibuffer] #'read-char-from-minibuffer-insert-other)
-    map)
-  "Keymap for the `read-char-from-minibuffer' function.")
-
-(compat-defvar read-char-from-minibuffer-map-hash  ;; <compat-tests:read-char-from-minibuffer>
-  (make-hash-table :test 'equal)
-  "Hash table of keymaps used by `read-char-from-minibuffer'."
-  :constant t)
-
-(compat-defun read-char-from-minibuffer (prompt &optional chars history) ;; <compat-tests:read-char-from-minibuffer>
-  "Read a character from the minibuffer, prompting for it with PROMPT.
-Like `read-char', but uses the minibuffer to read and return a character.
-Optional argument CHARS, if non-nil, should be a list of characters;
-the function will ignore any input that is not one of CHARS.
-Optional argument HISTORY, if non-nil, should be a symbol that
-specifies the history list variable to use for navigating in input
-history using \\`M-p' and \\`M-n', with \\`RET' to select a character from
-history.
-If you bind the variable `help-form' to a non-nil value
-while calling this function, then pressing `help-char'
-causes it to evaluate `help-form' and display the result.
-There is no need to explicitly add `help-char' to CHARS;
-`help-char' is bound automatically to `help-form-show'."
-  (let* ((map (if (consp chars)
-                  (or (gethash (list help-form (cons help-char chars))
-                               read-char-from-minibuffer-map-hash)
-                      (let ((map (make-sparse-keymap))
-                            (msg help-form))
-                        (set-keymap-parent map read-char-from-minibuffer-map)
-                        ;; If we have a dynamically bound `help-form'
-                        ;; here, then the `C-h' (i.e., `help-char')
-                        ;; character should output that instead of
-                        ;; being a command char.
-                        (when help-form
-                          (define-key map (vector help-char)
-                            (lambda ()
-                              (interactive)
-                              (let ((help-form msg)) ; lexically bound msg
-                                (help-form-show)))))
-                        (dolist (char chars)
-                          (define-key map (vector char)
-                            #'read-char-from-minibuffer-insert-char))
-                        (define-key map [remap self-insert-command]
-                          #'read-char-from-minibuffer-insert-other)
-                        (puthash (list help-form (cons help-char chars))
-                                 map read-char-from-minibuffer-map-hash)
-                        map))
-                read-char-from-minibuffer-map))
-         ;; Protect this-command when called from pre-command-hook (bug#45029)
-         (this-command this-command)
-         (result (read-from-minibuffer prompt nil map nil (or history t)))
-         (char
-          (if (> (length result) 0)
-              ;; We have a string (with one character), so return the first one.
-              (elt result 0)
-            ;; The default value is RET.
-            (when history (push "\r" (symbol-value history)))
-            ?\r)))
-    ;; Display the question with the answer.
-    (message "%s%s" prompt (char-to-string char))
-    char))
-
-;;;; Defined in simple.el
-
-(compat-guard (not (fboundp 'decoded-time-second)) ;; <compat-tests:decoded-time>
-  (cl-defstruct (decoded-time
-                 (:constructor nil)
-                 (:copier nil)
-                 (:type list))
-    (second nil :documentation "\
-This is an integer or a Lisp timestamp (TICKS . HZ) representing a nonnegative
-number of seconds less than 61.  (If not less than 60, it is a leap second,
-which only some operating systems support.)")
-    (minute nil :documentation "This is an integer between 0 and 59 (inclusive).")
-    (hour nil :documentation "This is an integer between 0 and 23 (inclusive).")
-    (day nil :documentation "This is an integer between 1 and 31 (inclusive).")
-    (month nil :documentation "\
-This is an integer between 1 and 12 (inclusive).  January is 1.")
-    (year nil :documentation "This is a four digit integer.")
-    (weekday nil :documentation "\
-This is a number between 0 and 6, and 0 is Sunday.")
-    (dst -1 :documentation "\
-This is t if daylight saving time is in effect, nil if it is not
-in effect, and -1 if daylight saving information is not available.
-Also see `decoded-time-dst'.")
-    (zone nil :documentation "\
-This is an integer indicating the UTC offset in seconds, i.e.,
-the number of seconds east of Greenwich.")))
-
-(compat-defun minibuffer-history-value () ;; <compat-tests:minibuffer-history-value>
-  "Return the value of the minibuffer input history list.
-If `minibuffer-history-variable' points to a buffer-local variable and
-the minibuffer is active, return the buffer-local value for the buffer
-that was current when the minibuffer was activated."
-  (buffer-local-value minibuffer-history-variable
-                      (window-buffer (minibuffer-selected-window))))
-
-;;;; Defined in minibuffer.el
-
-(compat-defmacro with-minibuffer-selected-window (&rest body) ;; <compat-tests:with-minibuffer-selected-window>
-  "Execute the forms in BODY from the minibuffer in its original window.
-When used in a minibuffer window, select the window selected just before
-the minibuffer was activated, and execute the forms."
-  (declare (indent 0) (debug t))
-  `(when-let ((window (minibuffer-selected-window)))
-     (with-selected-window window
-       ,@body)))
-
-;;;; Defined in byte-run.el
-
-(compat-defmacro with-suppressed-warnings (_warnings &rest body) ;; <compat-tests:with-suppressed-warnings>
-  "Like `progn', but prevents compiler WARNINGS in BODY.
-NOTE: The compatibility version behaves like `with-no-warnings'."
-  `(with-no-warnings ,@body))
-
-;;;; Defined in image.el
-
-(compat-defun image--set-property (image property value) ;; <compat-tests:image-property>
-  "Set PROPERTY in IMAGE to VALUE, internal use only."
-  :extended "26.1"
-  :feature image
-  (if (null value)
-      (while (cdr image)
-        (if (eq (cadr image) property)
-            (setcdr image (cdddr image))
-          (setq image (cddr image))))
-    (setcdr image (plist-put (cdr image) property value)))
-  value)
-
-;; HACK: image--set-property was broken with an off-by-one error on Emacs 26.
-;; The bug was fixed in a4ad7bed187493c1c230f223b52c71f5c34f7c89. Therefore we
-;; override the gv expander until Emacs 27.1.
-(compat-guard ;; <compat-tests:image-property>
-    (or (= emacs-major-version 26) (not (get 'image-property 'gv-expander)))
-  :feature image
-  (gv-define-setter image-property (value image prop)
-    `(,(if (< emacs-major-version 26) 'image--set-property 'compat--image--set-property)
-      ,image ,prop ,value)))
-
-;;;; Defined in files.el
-
-(compat-defun file-name-quoted-p (name &optional top) ;; <compat-tests:file-name-quoted-p>
-  "Handle optional argument TOP."
-  :extended "26.1"
-  (let ((file-name-handler-alist (unless top file-name-handler-alist)))
-    (string-prefix-p "/:" (file-local-name name))))
-
-(compat-defun file-name-quote (name &optional top) ;; <compat-tests:file-name-quote>
-  "Handle optional argument TOP."
-  :extended "26.1"
-  (let* ((file-name-handler-alist (unless top file-name-handler-alist))
-         (localname (file-local-name name)))
-    (if (string-prefix-p "/:" localname)
-        name
-      (concat (file-remote-p name) "/:" localname))))
-
-(compat-defun file-name-unquote (name &optional top) ;; <compat-tests:file-name-unquote>
-  "Handle optional argument TOP."
-  :extended "26.1"
-  (let* ((file-name-handler-alist (unless top file-name-handler-alist))
-         (localname (file-local-name name)))
-    (when (string-prefix-p "/:" localname)
-      (setq localname (if (= (length localname) 2) "/" (substring localname 2))))
-    (concat (file-remote-p name) localname)))
-
-(compat-defun file-size-human-readable (file-size &optional flavor space unit) ;; <compat-tests:file-size-human-readable>
-  "Handle the optional arguments SPACE and UNIT."
-  :extended t
-  (let ((power (if (or (null flavor) (eq flavor 'iec))
-                   1024.0
-                 1000.0))
-        (prefixes '("" "k" "M" "G" "T" "P" "E" "Z" "Y")))
-    (while (and (>= file-size power) (cdr prefixes))
-      (setq file-size (/ file-size power)
-            prefixes (cdr prefixes)))
-    (let* ((prefix (car prefixes))
-           (prefixed-unit (if (eq flavor 'iec)
-                              (concat
-                               (if (string= prefix "k") "K" prefix)
-                               (if (string= prefix "") "" "i")
-                               (or unit "B"))
-                            (concat prefix unit))))
-      (format (if (and (>= (mod file-size 1.0) 0.05)
-                       (< (mod file-size 1.0) 0.95))
-                  "%.1f%s%s"
-                "%.0f%s%s")
-              file-size
-              (if (string= prefixed-unit "") "" (or space ""))
-              prefixed-unit))))
-
-(compat-defun file-size-human-readable-iec (size) ;; <compat-tests:file-size-human-readable-iec>
-  "Human-readable string for SIZE bytes, using IEC prefixes."
-  (compat--file-size-human-readable size 'iec " "))
-
-(compat-defun exec-path () ;; <compat-tests:exec-path>
-  "Return list of directories to search programs to run in remote subprocesses.
-The remote host is identified by `default-directory'.  For remote
-hosts that do not support subprocesses, this returns nil.
-If `default-directory' is a local directory, this function returns
-the value of the variable `exec-path'."
-  (let ((handler (find-file-name-handler default-directory 'exec-path)))
-    ;; NOTE: The handler may fail since it was added in 27.1.
-    (or (and handler (ignore-errors (funcall handler 'exec-path)))
-        (if (file-remote-p default-directory)
-            ;; FIXME: Just return some standard path on remote
-            '("/bin" "/usr/bin" "/sbin" "/usr/sbin" "/usr/local/bin" "/usr/local/sbin")
-          exec-path))))
-
-(compat-defun executable-find (command &optional remote) ;; <compat-tests:executable-find>
-  "Handle optional argument REMOTE."
-  :extended t
-  (if (and remote (file-remote-p default-directory))
-      (let ((res (locate-file
-                  command
-                  (mapcar
-                   (apply-partially
-                    #'concat (file-remote-p default-directory))
-                   (exec-path))
-                  exec-suffixes 'file-executable-p)))
-        (when (stringp res) (file-local-name res)))
-    (executable-find command)))
-
-(compat-defun make-empty-file (filename &optional parents) ;; <compat-tests:make-empty-file>
-  "Create an empty file FILENAME.
-Optional arg PARENTS, if non-nil then creates parent dirs as needed."
-  (when (and (file-exists-p filename) (null parents))
-    (signal 'file-already-exists (list "File exists" filename)))
-  (let ((paren-dir (file-name-directory filename)))
-    (when (and paren-dir (not (file-exists-p paren-dir)))
-      (make-directory paren-dir parents)))
-  (write-region "" nil filename nil 0))
-
-;;;; Defined in regexp-opt.el
-
-(compat-defun regexp-opt (strings &optional paren) ;; <compat-tests:regexp-opt>
-  "Handle an empty list of STRINGS."
-  :extended t
-  (if (null strings)
-      (let ((re "\\`a\\`"))
-        (cond ((null paren)
-               (concat "\\(?:" re "\\)"))
-              ((stringp paren)
-               (concat paren re "\\)"))
-              ((eq paren 'words)
-               (concat "\\<\\(" re "\\)\\>"))
-              ((eq paren 'symbols)
-               (concat "\\_\\(<" re "\\)\\_>"))
-              ((concat "\\(" re "\\)"))))
-    (regexp-opt strings paren)))
-
-;;;; Defined in package.el
-
-(declare-function lm-header "lisp-mnt")
-(declare-function macroexp-file-name nil)
-
-(compat-defun package-get-version () ;; <compat-tests:package-get-version>
-  "Return the version number of the package in which this is used.
-Assumes it is used from an Elisp file placed inside the top-level directory
-of an installed ELPA package.
-The return value is a string (or nil in case we can’t find it)."
-  ;; No :feature since the function is autoloaded.
-  ;; In a sense, this is a lie, but it does just what we want: precompute
-  ;; the version at compile time and hardcodes it into the .elc file!
-  (declare (pure t))
-  ;; Hack alert!
-  (let ((file (or (macroexp-file-name) buffer-file-name)))
-    (cond
-     ((null file) nil)
-     ;; Packages are normally installed into directories named "<pkg>-<vers>",
-     ;; so get the version number from there.
-     ((string-match
-       "/[^/]+-\\([0-9]\\(?:[0-9.]\\|pre\\|beta\\|alpha\\|snapshot\\)+\\)/[^/]+\\'"
-       file)
-      (match-string 1 file))
-     ;; For packages run straight from the an elpa.git clone, there's no
-     ;; "-<vers>" in the directory name, so we have to fetch the version
-     ;; the hard way.
-     ((let* ((pkgdir (file-name-directory file))
-             (pkgname (file-name-nondirectory (directory-file-name pkgdir)))
-             (mainfile (expand-file-name (concat pkgname ".el") pkgdir)))
-        (when (file-readable-p mainfile)
-          (require 'lisp-mnt)
-          (with-temp-buffer
-            (insert-file-contents mainfile)
-            (or (lm-header "package-version")
-                (lm-header "version")))))))))
-
-;;;; Defined in time-date.el
-
-(compat-defun make-decoded-time ;; <compat-tests:make-decoded-time>
-              (&key second minute hour day month year (dst -1) zone)
-  "Return a `decoded-time' structure with only the keywords given filled out."
-  :feature time-date
-  (list second minute hour day month year nil dst zone))
-
-(compat-defun date-days-in-month (year month) ;; <compat-tests:date-days-in-month>
-  "The number of days in MONTH in YEAR."
-  :feature time-date
-  (unless (and (numberp month)
-               (<= 1 month)
-               (<= month 12))
-    (error "Month %s is invalid" month))
-  (if (= month 2)
-      (if (date-leap-year-p year)
-          29
-        28)
-    (if (memq month '(1 3 5 7 8 10 12))
-        31
-      30)))
-
-(compat-defun date-ordinal-to-time (year ordinal) ;; <compat-tests:date-ordinal-to-time>
-  "Convert a YEAR/ORDINAL to the equivalent `decoded-time' structure.
-ORDINAL is the number of days since the start of the year, with
-January 1st being 1."
-  (let ((month 1))
-    (while (> ordinal (date-days-in-month year month))
-      (setq ordinal (- ordinal (date-days-in-month year month))
-            month (1+ month)))
-    (list nil nil nil ordinal month year nil nil nil)))
-
-;;;; Defined in text-property-search.el
-
-(declare-function make-prop-match nil)
-(compat-guard (not (fboundp 'make-prop-match)) ;; <compat-tests:prop-match>
-  (cl-defstruct (prop-match) beginning end value))
-
-(compat-defun text-property-search-forward ;; <compat-tests:text-property-search-forward>
-    (property &optional value predicate not-current)
-  "Search for the next region of text where PREDICATE is true.
-PREDICATE is used to decide whether a value of PROPERTY should be
-considered as matching VALUE.
-
-If PREDICATE is a function, it will be called with two arguments:
-VALUE and the value of PROPERTY.  The function should return
-non-nil if these two values are to be considered a match.
-
-Two special values of PREDICATE can also be used:
-If PREDICATE is t, that means a value must `equal' VALUE to be
-considered a match.
-If PREDICATE is nil (which is the default value), a value will
-match if is not `equal' to VALUE.  Furthermore, a nil PREDICATE
-means that the match region is ended if the value changes.  For
-instance, this means that if you loop with
-
-  (while (setq prop (text-property-search-forward \\='face))
-    ...)
-
-you will get all distinct regions with non-nil `face' values in
-the buffer, and the `prop' object will have the details about the
-match.  See the manual for more details and examples about how
-VALUE and PREDICATE interact.
-
-If NOT-CURRENT is non-nil, the function will search for the first
-region that doesn't include point and has a value of PROPERTY
-that matches VALUE.
-
-If no matches can be found, return nil and don't move point.
-If found, move point to the end of the region and return a
-`prop-match' object describing the match.  To access the details
-of the match, use `prop-match-beginning' and `prop-match-end' for
-the buffer positions that limit the region, and
-`prop-match-value' for the value of PROPERTY in the region."
-  (let* ((match-p
-          (lambda (prop-value)
-            (funcall
-             (cond
-              ((eq predicate t)
-               #'equal)
-              ((eq predicate nil)
-               (lambda (val p-val)
-                 (not (equal val p-val))))
-              (predicate))
-             value prop-value)))
-         (find-end
-          (lambda (start)
-            (let (end)
-              (if (and value
-                       (null predicate))
-                  ;; This is the normal case: We're looking for areas where the
-                  ;; values aren't, so we aren't interested in sub-areas where the
-                  ;; property has different values, all non-matching value.
-                  (let ((ended nil))
-                    (while (not ended)
-                      (setq end (next-single-property-change (point) property))
-                      (if (not end)
-                          (progn
-                            (goto-char (point-max))
-                            (setq end (point)
-                                  ended t))
-                        (goto-char end)
-                        (unless (funcall match-p (get-text-property (point) property))
-                          (setq ended t)))))
-                ;; End this at the first place the property changes value.
-                (setq end (next-single-property-change (point) property nil (point-max)))
-                (goto-char end))
-              (make-prop-match
-               :beginning start
-               :end end
-               :value (get-text-property start property))))))
-    (cond
-     ;; No matches at the end of the buffer.
-     ((eobp)
-      nil)
-     ;; We're standing in the property we're looking for, so find the
-     ;; end.
-     ((and (funcall match-p (get-text-property (point) property))
-           (not not-current))
-      (funcall find-end (point)))
-     (t
-      (let ((origin (point))
-            (ended nil)
-            pos)
-        ;; Find the next candidate.
-        (while (not ended)
-          (setq pos (next-single-property-change (point) property))
-          (if (not pos)
-              (progn
-                (goto-char origin)
-                (setq ended t))
-            (goto-char pos)
-            (if (funcall match-p (get-text-property (point) property))
-                (setq ended (funcall find-end (point)))
-              ;; Skip past this section of non-matches.
-              (setq pos (next-single-property-change (point) property))
-              (unless pos
-                (goto-char origin)
-                (setq ended t)))))
-        (and (not (eq ended t))
-             ended))))))
-
-(compat-defun text-property-search-backward ;; <compat-tests:text-property-search-backward>
-    (property &optional value predicate not-current)
-  "Search for the previous region of text whose PROPERTY matches VALUE.
-
-Like `text-property-search-forward', which see, but searches backward,
-and if a matching region is found, place point at the start of the region."
-  (let* ((match-p
-          (lambda (prop-value)
-            (funcall
-             (cond
-              ((eq predicate t)
-               #'equal)
-              ((eq predicate nil)
-               (lambda (val p-val)
-                 (not (equal val p-val))))
-              (predicate))
-             value prop-value)))
-         (find-end
-          (lambda (start)
-            (let (end)
-              (if (and value
-                       (null predicate))
-                  ;; This is the normal case: We're looking for areas where the
-                  ;; values aren't, so we aren't interested in sub-areas where the
-                  ;; property has different values, all non-matching value.
-                  (let ((ended nil))
-                    (while (not ended)
-                      (setq end (previous-single-property-change (point) property))
-                      (if (not end)
-                          (progn
-                            (goto-char (point-min))
-                            (setq end (point)
-                                  ended t))
-                        (goto-char (1- end))
-                        (unless (funcall match-p (get-text-property (point) property))
-                          (goto-char end)
-                          (setq ended t)))))
-                ;; End this at the first place the property changes value.
-                (setq end (previous-single-property-change
-                           (point) property nil (point-min)))
-                (goto-char end))
-              (make-prop-match
-               :beginning end
-               :end (1+ start)
-               :value (get-text-property end property))))))
-    (cond
-     ;; We're at the start of the buffer; no previous matches.
-     ((bobp)
-      nil)
-     ;; We're standing in the property we're looking for, so find the
-     ;; end.
-     ((funcall match-p (get-text-property (1- (point)) property))
-      (let ((origin (point))
-            (match (funcall find-end (1- (point)) property value predicate)))
-        ;; When we want to ignore the current element, then repeat the
-        ;; search if we haven't moved out of it yet.
-        (if (and not-current
-                 (equal (get-text-property (point) property)
-                        (get-text-property origin property)))
-            (text-property-search-backward property value predicate)
-          match)))
-     (t
-      (let ((origin (point))
-            (ended nil)
-            pos)
-        ;; Find the previous candidate.
-        (while (not ended)
-          (setq pos (previous-single-property-change (point) property))
-          (if (not pos)
-              (progn
-                (goto-char origin)
-                (setq ended t))
-            (goto-char (1- pos))
-            (if (funcall match-p (get-text-property (point) property))
-                (setq ended
-                      (funcall find-end (point)))
-              ;; Skip past this section of non-matches.
-              (setq pos (previous-single-property-change (point) property))
-              (unless pos
-                (goto-char origin)
-                (setq ended t)))))
-        (and (not (eq ended t))
-             ended))))))
-
-;;;; Defined in ring.el
-
-(compat-defun ring-resize (ring size) ;; <compat-tests:ring-resize>
-  "Set the size of RING to SIZE.
-If the new size is smaller, then the oldest items in the ring are
-discarded."
-  :feature ring
-  (when (integerp size)
-    (let ((length (ring-length ring))
-          (new-vec (make-vector size nil)))
-      (if (= length 0)
-          (setcdr ring (cons 0 new-vec))
-        (let* ((hd (car ring))
-               (old-size (ring-size ring))
-               (old-vec (cddr ring))
-               (copy-length (min size length))
-               (copy-hd (mod (+ hd (- length copy-length)) length)))
-          (setcdr ring (cons copy-length new-vec))
-          ;; If the ring is wrapped, the existing elements must be written
-          ;; out in the right order.
-          (dotimes (j copy-length)
-            (aset new-vec j (aref old-vec (mod (+ copy-hd j) old-size))))
-          (setcar ring 0))))))
-
-;;;; Defined in map-ynp.el
-
-(compat-version "26.2")
-
-(compat-defvar read-answer-short 'auto ;; <compat-tests:read-answer>
-  "If non-nil, the `read-answer' function accepts single-character answers.
-If t, accept short (single key-press) answers to the question.
-If nil, require long answers.  If `auto', accept short answers if
-`use-short-answers' is non-nil, or the function cell of `yes-or-no-p'
-is set to `y-or-n-p'.
-
-Note that this variable does not affect calls to the more
-commonly-used `yes-or-no-p' function; it only affects calls to
-the `read-answer' function.  To control whether `yes-or-no-p'
-requires a long or a short answer, see the `use-short-answers'
-variable.")
-
-(compat-defun read-answer (question answers) ;; <compat-tests:read-answer>
-  "Read an answer either as a complete word or its character abbreviation.
-Ask user a question and accept an answer from the list of possible answers.
-
-QUESTION should end in a space; this function adds a list of answers to it.
-
-ANSWERS is an alist with elements in the following format:
-  (LONG-ANSWER SHORT-ANSWER HELP-MESSAGE)
-where
-  LONG-ANSWER is a complete answer,
-  SHORT-ANSWER is an abbreviated one-character answer,
-  HELP-MESSAGE is a string describing the meaning of the answer.
-
-SHORT-ANSWER is not necessarily a single character answer.  It can be
-also a function key like F1, a character event such as C-M-h, or
-a control character like C-h.
-
-Example:
-  \\='((\"yes\"  ?y \"perform the action\")
-    (\"no\"   ?n \"skip to the next\")
-    (\"all\"  ?! \"accept all remaining without more questions\")
-    (\"help\" ?h \"show help\")
-    (\"quit\" ?q \"exit\"))
-
-When `read-answer-short' is non-nil, accept short answers.
-
-Return a long answer even in case of accepting short ones.
-
-When `use-dialog-box' is t, pop up a dialog window to get user input."
-  ;; NOTE: For simplicity we provide a primitive implementation based on
-  ;; `read-multiple-choice', which does neither support long answers nor the the
-  ;; gui dialog box.
-  (cadr (read-multiple-choice
-         (string-trim-right question)
-         (delq nil
-               (mapcar (lambda (x) (unless (equal "help" (car x))
-                                     (list (cadr x) (car x) (caddr x))))
-                       answers)))))
-
-(provide 'compat-27)
-;;; compat-27.el ends here
diff --git a/elpa/compat-29.1.4.1/compat-28.el b/elpa/compat-29.1.4.1/compat-28.el
deleted file mode 100644 (file)
index 4cca3c2..0000000
+++ /dev/null
@@ -1,848 +0,0 @@
-;;; compat-28.el --- Functionality added in Emacs 28.1 -*- lexical-binding: t; -*-
-
-;; Copyright (C) 2021-2023 Free Software Foundation, Inc.
-
-;; This program is free software; you can redistribute it and/or modify
-;; it under the terms of the GNU General Public License as published by
-;; the Free Software Foundation, either version 3 of the License, or
-;; (at your option) any later version.
-
-;; This program is distributed in the hope that it will be useful,
-;; but WITHOUT ANY WARRANTY; without even the implied warranty of
-;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-;; GNU General Public License for more details.
-
-;; You should have received a copy of the GNU General Public License
-;; along with this program.  If not, see <https://www.gnu.org/licenses/>.
-
-;;; Commentary:
-
-;; Functionality added in Emacs 28.1, needed by older Emacs versions.
-
-;;; Code:
-
-(eval-when-compile (load "compat-macs.el" nil t t))
-(compat-require compat-27 "27.1")
-
-(compat-version "28.1")
-
-;;;; Defined in fns.c
-
-;; FIXME Should handle multibyte regular expressions
-(compat-defun string-search (needle haystack &optional start-pos) ;; <compat-tests:string-search>
-  "Search for the string NEEDLE in the strign HAYSTACK.
-
-The return value is the position of the first occurrence of
-NEEDLE in HAYSTACK, or nil if no match was found.
-
-The optional START-POS argument says where to start searching in
-HAYSTACK and defaults to zero (start at the beginning).
-It must be between zero and the length of HAYSTACK, inclusive.
-
-Case is always significant and text properties are ignored.
-
-NOTE: Prior to Emacs 27 `string-match' has issues handling
-multibyte regular expressions.  As the compatibility function
-for `string-search' is implemented via `string-match', these
-issues are inherited."
-  (when (and start-pos (or (< (length haystack) start-pos)
-                           (< start-pos 0)))
-    (signal 'args-out-of-range (list start-pos)))
-  (save-match-data
-    (let ((case-fold-search nil))
-      (string-match (regexp-quote needle) haystack start-pos))))
-
-(compat-defun length= (sequence length) ;; [[compat-tests:length=]]
-  "Returns non-nil if SEQUENCE has a length equal to LENGTH."
-  (cond
-   ((null sequence) (zerop length))
-   ((consp sequence)
-    (and (null (nthcdr length sequence))
-         (nthcdr (1- length) sequence)
-         t))
-   ((arrayp sequence)
-    (= (length sequence) length))
-   ((signal 'wrong-type-argument sequence))))
-
-(compat-defun length< (sequence length) ;; [[compat-tests:length<]]
-  "Returns non-nil if SEQUENCE is shorter than LENGTH."
-  (cond
-   ((null sequence) (not (zerop length)))
-   ((listp sequence)
-    (null (nthcdr (1- length) sequence)))
-   ((arrayp sequence)
-    (< (length sequence) length))
-   ((signal 'wrong-type-argument sequence))))
-
-(compat-defun length> (sequence length) ;; [[compat-tests:length>]]
-  "Returns non-nil if SEQUENCE is longer than LENGTH."
-  (cond
-   ((listp sequence)
-    (and (nthcdr length sequence) t))
-   ((arrayp sequence)
-    (> (length sequence) length))
-   ((signal 'wrong-type-argument sequence))))
-
-;;;; Defined in fileio.c
-
-(compat-defun file-name-concat (directory &rest components) ;; <compat-tests:file-name-concat>
-  "Append COMPONENTS to DIRECTORY and return the resulting string.
-Elements in COMPONENTS must be a string or nil.
-DIRECTORY or the non-final elements in COMPONENTS may or may not end
-with a slash -- if they don’t end with a slash, a slash will be
-inserted before contatenating."
-  (let ((separator (eval-when-compile
-                     (if (memq system-type '(ms-dos windows-nt cygwin))
-                         "\\" "/")))
-        (components (delq nil
-                          (mapcar (lambda (x) (and (not (equal "" x)) x))
-                                  (cons directory components))))
-        (result ""))
-    (while components
-      (let ((c (pop components)))
-        (setq result (concat result c
-                             (and components
-                                  (not (string-suffix-p separator c))
-                                  separator)))))
-    result))
-
-;;;; Defined in alloc.c
-
-(compat-defalias garbage-collect-maybe ignore) ;; <compat-tests:garbage-collect-maybe>
-
-;;;; Defined in characters.c
-
-(compat-defun string-width (string &optional from to) ;; <compat-tests:string-width>
-  "Handle optional arguments FROM and TO."
-  :extended t
-  (let* ((len (length string))
-         (from (or from 0))
-         (to (or to len)))
-    (if (and (= from 0) (= to len))
-        (string-width string)
-      (string-width (substring string from to)))))
-
-;;;; Defined in dired.c
-
-(compat-defun directory-files (directory &optional full match nosort count) ;; <compat-tests:directory-files>
-  "Handle additional optional argument COUNT."
-  :extended t
-  (let ((files (directory-files directory full match nosort)))
-    (when (natnump count)
-      (setf (nthcdr count files) nil))
-    files))
-
-(compat-defun directory-files-and-attributes (directory &optional full match nosort id-format count) ;; <compat-tests:directory-files-and-attributs>
-  "Handle additional optional argument COUNT."
-  :extended t
-  (let ((files (directory-files-and-attributes directory full match nosort id-format)))
-    (when (natnump count)
-      (setf (nthcdr count files) nil))
-    files))
-
-;;;; xfaces.c
-
-(compat-defun color-values-from-color-spec (spec) ;; <compat-tests:color-values-from-color-spec>
-  "Parse color SPEC as a numeric color and return (RED GREEN BLUE).
-This function recognises the following formats for SPEC:
-
- #RGB, where R, G and B are hex numbers of equal length, 1-4 digits each.
- rgb:R/G/B, where R, G, and B are hex numbers, 1-4 digits each.
- rgbi:R/G/B, where R, G and B are floating-point numbers in [0,1].
-
-If SPEC is not in one of the above forms, return nil.
-
-Each of the 3 integer members of the resulting list, RED, GREEN,
-and BLUE, is normalized to have its value in [0,65535]."
-  (let ((case-fold-search nil))
-    (save-match-data
-      (cond
-       ((string-match
-         ;; (rx bos "#"
-         ;;     (or (: (group-n 1 (= 1 hex)) (group-n 2 (= 1 hex)) (group-n 3 (= 1 hex)))
-         ;;         (: (group-n 1 (= 2 hex)) (group-n 2 (= 2 hex)) (group-n 3 (= 2 hex)))
-         ;;         (: (group-n 1 (= 3 hex)) (group-n 2 (= 3 hex)) (group-n 3 (= 3 hex)))
-         ;;         (: (group-n 1 (= 4 hex)) (group-n 2 (= 4 hex)) (group-n 3 (= 4 hex))))
-         ;;     eos)
-         "\\`#\\(?:\\(?1:[[:xdigit:]]\\{1\\}\\)\\(?2:[[:xdigit:]]\\{1\\}\\)\\(?3:[[:xdigit:]]\\{1\\}\\)\\|\\(?1:[[:xdigit:]]\\{2\\}\\)\\(?2:[[:xdigit:]]\\{2\\}\\)\\(?3:[[:xdigit:]]\\{2\\}\\)\\|\\(?1:[[:xdigit:]]\\{3\\}\\)\\(?2:[[:xdigit:]]\\{3\\}\\)\\(?3:[[:xdigit:]]\\{3\\}\\)\\|\\(?1:[[:xdigit:]]\\{4\\}\\)\\(?2:[[:xdigit:]]\\{4\\}\\)\\(?3:[[:xdigit:]]\\{4\\}\\)\\)\\'"
-         spec)
-        (let ((max (1- (ash 1 (* (- (match-end 1) (match-beginning 1)) 4)))))
-          (list (/ (* (string-to-number (match-string 1 spec) 16) 65535) max)
-                (/ (* (string-to-number (match-string 2 spec) 16) 65535) max)
-                (/ (* (string-to-number (match-string 3 spec) 16) 65535) max))))
-       ((string-match
-         ;; (rx bos "rgb:"
-         ;;     (group (** 1 4 hex)) "/"
-         ;;     (group (** 1 4 hex)) "/"
-         ;;     (group (** 1 4 hex))
-         ;;     eos)
-         "\\`rgb:\\([[:xdigit:]]\\{1,4\\}\\)/\\([[:xdigit:]]\\{1,4\\}\\)/\\([[:xdigit:]]\\{1,4\\}\\)\\'"
-         spec)
-        (list (/ (* (string-to-number (match-string 1 spec) 16) 65535)
-                 (1- (ash 1 (* (- (match-end 1) (match-beginning 1)) 4))))
-              (/ (* (string-to-number (match-string 2 spec) 16) 65535)
-                 (1- (ash 1 (* (- (match-end 2) (match-beginning 2)) 4))))
-              (/ (* (string-to-number (match-string 3 spec) 16) 65535)
-                 (1- (ash 1 (* (- (match-end 3) (match-beginning 3)) 4))))))
-       ;; The "RGBi" (RGB Intensity) specification is defined by
-       ;; XCMS[0], see [1] for the implementation in Xlib.
-       ;;
-       ;; [0] http://www.nic.funet.fi/pub/X11/X11R4/DOCS/color/Xcms.text
-       ;; [1] https://gitlab.freedesktop.org/xorg/lib/libx11/-/blob/master/src/xcms/LRGB.c#L1392
-       ((string-match
-         ;; (rx bos "rgbi:" (* space)
-         ;;     (group (? (or "-" "+"))
-         ;;            (or (: (+ digit) (? "." (* digit)))
-         ;;                (: "." (+ digit)))
-         ;;            (? "e" (? (or "-" "+")) (+ digit)))
-         ;;     "/" (* space)
-         ;;     (group (? (or "-" "+"))
-         ;;            (or (: (+ digit) (? "." (* digit)))
-         ;;                (: "." (+ digit)))
-         ;;            (? "e" (? (or "-" "+")) (+ digit)))
-         ;;     "/" (* space)
-         ;;     (group (? (or "-" "+"))
-         ;;            (or (: (+ digit) (? "." (* digit)))
-         ;;                (: "." (+ digit)))
-         ;;            (? "e" (? (or "-" "+")) (+ digit)))
-         ;;     eos)
-         "\\`rgbi:[[:space:]]*\\([+-]?\\(?:[[:digit:]]+\\(?:\\.[[:digit:]]*\\)?\\|\\.[[:digit:]]+\\)\\(?:e[+-]?[[:digit:]]+\\)?\\)/[[:space:]]*\\([+-]?\\(?:[[:digit:]]+\\(?:\\.[[:digit:]]*\\)?\\|\\.[[:digit:]]+\\)\\(?:e[+-]?[[:digit:]]+\\)?\\)/[[:space:]]*\\([+-]?\\(?:[[:digit:]]+\\(?:\\.[[:digit:]]*\\)?\\|\\.[[:digit:]]+\\)\\(?:e[+-]?[[:digit:]]+\\)?\\)\\'"
-         spec)
-        (let ((r (round (* (string-to-number (match-string 1 spec)) 65535)))
-              (g (round (* (string-to-number (match-string 2 spec)) 65535)))
-              (b (round (* (string-to-number (match-string 3 spec)) 65535))))
-          (when (and (<= 0 r) (<= r 65535)
-                     (<= 0 g) (<= g 65535)
-                     (<= 0 b) (<= b 65535))
-            (list r g b))))))))
-
-;;;; Defined in simple.el
-
-(compat-defun make-separator-line (&optional length) ;; <compat-tests:make-separator-line>
-  "Make a string appropriate for usage as a visual separator line.
-If LENGTH is nil, use the window width."
-    (concat (propertize (make-string (or length (1- (window-width))) ?-)
-                        'face 'separator-line)
-            "\n"))
-
-;;;; Defined in subr.el
-
-(compat-defun process-lines-handling-status (program status-handler &rest args) ;; <compat-tests:process-lines-handling-status>
-  "Execute PROGRAM with ARGS, returning its output as a list of lines.
-If STATUS-HANDLER is non-nil, it must be a function with one
-argument, which will be called with the exit status of the
-program before the output is collected.  If STATUS-HANDLER is
-nil, an error is signaled if the program returns with a non-zero
-exit status."
-  (with-temp-buffer
-    (let ((status (apply #'call-process program nil (current-buffer) nil args)))
-      (if status-handler
-          (funcall status-handler status)
-        (unless (eq status 0)
-          (error "%s exited with status %s" program status)))
-      (goto-char (point-min))
-      (let (lines)
-        (while (not (eobp))
-          (setq lines (cons (buffer-substring-no-properties
-                             (line-beginning-position)
-                             (line-end-position))
-                            lines))
-          (forward-line 1))
-        (nreverse lines)))))
-
-(compat-defun process-lines-ignore-status (program &rest args) ;; <compat-tests:process-lines-ignore-status>
-  "Execute PROGRAM with ARGS, returning its output as a list of lines.
-The exit status of the program is ignored.
-Also see `process-lines'."
-  (apply 'process-lines-handling-status program #'ignore args))
-
-;; FIXME Should handle multibyte regular expressions
-(compat-defun string-replace (fromstring tostring instring) ;; <compat-tests:string-replace>
-  "Replace FROMSTRING with TOSTRING in INSTRING each time it occurs."
-  (when (equal fromstring "")
-    (signal 'wrong-length-argument '(0)))
-  (let ((case-fold-search nil))
-    (replace-regexp-in-string
-     (regexp-quote fromstring)
-     tostring instring
-     t t)))
-
-(compat-defun always (&rest _arguments) ;; <compat-tests:always>
-  "Do nothing and return t.
-This function accepts any number of ARGUMENTS, but ignores them.
-Also see `ignore'."
-  t)
-
-(compat-defun insert-into-buffer (buffer &optional start end) ;; <compat-tests:insert-into-buffer>
-  "Insert the contents of the current buffer into BUFFER.
-If START/END, only insert that region from the current buffer.
-Point in BUFFER will be placed after the inserted text."
-  (let ((current (current-buffer)))
-    (with-current-buffer buffer
-      (insert-buffer-substring current start end))))
-
-(compat-defun replace-string-in-region (string replacement &optional start end) ;; <compat-tests:replace-string-in-region>
-  "Replace STRING with REPLACEMENT in the region from START to END.
-The number of replaced occurrences are returned, or nil if STRING
-doesn't exist in the region.
-
-If START is nil, use the current point.  If END is nil, use `point-max'.
-
-Comparisons and replacements are done with fixed case."
-  (if start
-      (when (< start (point-min))
-        (error "Start before start of buffer"))
-    (setq start (point)))
-  (if end
-      (when (> end (point-max))
-        (error "End after end of buffer"))
-    (setq end (point-max)))
-  (save-excursion
-    (goto-char start)
-    (save-restriction
-      (narrow-to-region start end)
-      (let ((matches 0)
-            (case-fold-search nil))
-        (while (search-forward string nil t)
-          (delete-region (match-beginning 0) (match-end 0))
-          (insert replacement)
-          (setq matches (1+ matches)))
-        (and (not (zerop matches))
-             matches)))))
-
-(compat-defun replace-regexp-in-region (regexp replacement &optional start end) ;; <compat-tests:replace-regexp-in-region>
-  "Replace REGEXP with REPLACEMENT in the region from START to END.
-The number of replaced occurrences are returned, or nil if REGEXP
-doesn't exist in the region.
-
-If START is nil, use the current point.  If END is nil, use `point-max'.
-
-Comparisons and replacements are done with fixed case.
-
-REPLACEMENT can use the following special elements:
-
-  `\\&' in NEWTEXT means substitute original matched text.
-  `\\N' means substitute what matched the Nth `\\(...\\)'.
-       If Nth parens didn't match, substitute nothing.
-  `\\\\' means insert one `\\'.
-  `\\?' is treated literally."
-  (if start
-      (when (< start (point-min))
-        (error "Start before start of buffer"))
-    (setq start (point)))
-  (if end
-      (when (> end (point-max))
-        (error "End after end of buffer"))
-    (setq end (point-max)))
-  (save-excursion
-    (goto-char start)
-    (save-restriction
-      (narrow-to-region start end)
-      (let ((matches 0)
-            (case-fold-search nil))
-          (while (re-search-forward regexp nil t)
-          (replace-match replacement t)
-          (setq matches (1+ matches)))
-        (and (not (zerop matches))
-             matches)))))
-
-(compat-defun buffer-local-boundp (symbol buffer) ;; <compat-tests:buffer-local-boundp>
-  "Return non-nil if SYMBOL is bound in BUFFER.
-Also see `local-variable-p'."
-  (catch 'fail
-    (condition-case nil
-        (buffer-local-value symbol buffer)
-      (void-variable nil (throw 'fail nil)))
-    t))
-
-(compat-defmacro with-existing-directory (&rest body) ;; <compat-tests:with-existing-directory>
-  "Execute BODY with `default-directory' bound to an existing directory.
-If `default-directory' is already an existing directory, it's not changed."
-  (declare (indent 0) (debug t))
-  `(let ((default-directory
-          (or (catch 'quit
-                (dolist (dir (list default-directory
-                                   (expand-file-name "~/")
-                                   temporary-file-directory
-                                   (getenv "TMPDIR")
-                                   "/tmp/"))
-                  (when (and dir (file-exists-p dir))
-                    (throw 'quit dir))))
-              "/")))
-     ,@body))
-
-(compat-defmacro dlet (binders &rest body) ;; <compat-tests:dlet>
-  "Like `let' but using dynamic scoping."
-  (declare (indent 1) (debug let))
-  `(let (_)
-     ,@(mapcar (lambda (binder)
-                 `(defvar ,(if (consp binder) (car binder) binder)))
-               binders)
-     (let ,binders ,@body)))
-
-(compat-defun ensure-list (object) ;; <compat-tests:ensure-list>
-  "Return OBJECT as a list.
-If OBJECT is already a list, return OBJECT itself.  If it's
-not a list, return a one-element list containing OBJECT."
-  (if (listp object)
-      object
-    (list object)))
-
-(compat-defalias subr-primitive-p subrp) ;; <compat-tests:subr-primitive-p>
-
-;;;; Defined in data.c
-
-(compat-defalias subr-native-elisp-p ignore) ;; <compat-tests:subr-native-elisp-p>
-
-;;;; Defined in subr-x.el
-
-(compat-defun string-clean-whitespace (string) ;; <compat-tests:string-clean-whitespace>
-  "Clean up whitespace in STRING.
-All sequences of whitespaces in STRING are collapsed into a
-single space character, and leading/trailing whitespace is
-removed."
-  (let ((blank "[[:blank:]\r\n]+"))
-    (replace-regexp-in-string
-     "^[[:blank:]\r\n]+\\|[[:blank:]\r\n]+$"
-     ""
-     (replace-regexp-in-string
-      blank " " string))))
-
-(compat-defun string-fill (string length) ;; <compat-tests:string-fill>
-  "Clean up whitespace in STRING.
-All sequences of whitespaces in STRING are collapsed into a
-single space character, and leading/trailing whitespace is
-removed."
-  (with-temp-buffer
-    (insert string)
-    (goto-char (point-min))
-    (let ((fill-column length)
-          (adaptive-fill-mode nil))
-      (fill-region (point-min) (point-max)))
-    (buffer-string)))
-
-(compat-defun string-pad (string length &optional padding start) ;; <compat-tests:string-pad>
-  "Pad STRING to LENGTH using PADDING.
-If PADDING is nil, the space character is used.  If not nil, it
-should be a character.
-
-If STRING is longer than the absolute value of LENGTH, no padding
-is done.
-
-If START is nil (or not present), the padding is done to the end
-of the string, and if non-nil, padding is done to the start of
-the string."
-  (unless (natnump length)
-    (signal 'wrong-type-argument (list 'natnump length)))
-  (let ((pad-length (- length (length string))))
-    (if (< pad-length 0)
-        string
-      (concat (and start
-                   (make-string pad-length (or padding ?\s)))
-              string
-              (and (not start)
-                   (make-string pad-length (or padding ?\s)))))))
-
-(compat-defun string-chop-newline (string) ;; <compat-tests:string-chop-newline>
-  "Remove the final newline (if any) from STRING."
-  (if (and (>= (length string) 1) (= (aref string (1- (length string))) ?\n))
-      (substring string 0 -1)
-    string))
-
-(compat-defmacro named-let (name bindings &rest body) ;; <compat-tests:named-let>
-  "Looping construct taken from Scheme.
-Like `let', bind variables in BINDINGS and then evaluate BODY,
-but with the twist that BODY can evaluate itself recursively by
-calling NAME, where the arguments passed to NAME are used
-as the new values of the bound variables in the recursive invocation."
-  (declare (indent 2) (debug (symbolp (&rest (symbolp form)) body)))
-  (let ((fargs (mapcar (lambda (b)
-                         (let ((var (if (consp b) (car b) b)))
-                           (make-symbol (symbol-name var))))
-                       bindings))
-        (aargs (mapcar (lambda (b) (if (consp b) (cadr b))) bindings))
-        rargs)
-    (dotimes (i (length bindings))
-      (let ((b (nth i bindings)))
-        (push (list (if (consp b) (car b) b) (nth i fargs))
-              rargs)
-        (setf (if (consp b) (car b) b)
-              (nth i fargs))))
-    (letrec
-        ((quit (make-symbol "quit")) (self (make-symbol "self"))
-         (total-tco t)
-         (macro (lambda (&rest args)
-                  (setq total-tco nil)
-                  `(funcall ,self . ,args)))
-         ;; Based on `cl--self-tco':
-         (tco-progn (lambda (exprs)
-                      (append
-                       (butlast exprs)
-                       (list (funcall tco (car (last exprs)))))))
-         (tco (lambda (expr)
-                (cond
-                 ((eq (car-safe expr) 'if)
-                  (append (list 'if
-                                (cadr expr)
-                                (funcall tco (nth 2 expr)))
-                          (funcall tco-progn (nthcdr 3 expr))))
-                 ((eq (car-safe expr) 'cond)
-                  (let ((conds (cdr expr)) body)
-                    (while conds
-                      (let ((branch (pop conds)))
-                        (push (cond
-                               ((cdr branch) ;has tail
-                                (funcall tco-progn branch))
-                               ((null conds) ;last element
-                                (list t (funcall tco (car branch))))
-                               ((progn
-                                  branch)))
-                              body)))
-                    (cons 'cond (nreverse body))))
-                 ((eq (car-safe expr) 'or)
-                  (if (cddr expr)
-                      (let ((var (make-symbol "var")))
-                        `(let ((,var ,(cadr expr)))
-                           (if ,var ,(funcall tco var)
-                             ,(funcall tco (cons 'or (cddr expr))))))
-                    (funcall tco (cadr expr))))
-                 ((eq (car-safe expr) 'condition-case)
-                  (append (list 'condition-case (cadr expr) (nth 2 expr))
-                          (mapcar
-                           (lambda (handler)
-                             (cons (car handler)
-                                   (funcall tco-progn (cdr handler))))
-                           (nthcdr 3 expr))))
-                 ((memq (car-safe expr) '(and progn))
-                  (cons (car expr) (funcall tco-progn (cdr expr))))
-                 ((memq (car-safe expr) '(let let*))
-                  (append (list (car expr) (cadr expr))
-                          (funcall tco-progn (cddr expr))))
-                 ((eq (car-safe expr) name)
-                  (let (sets (args (cdr expr)))
-                    (dolist (farg fargs)
-                      (push (list farg (pop args))
-                            sets))
-                    (cons 'setq (apply #'nconc (nreverse sets)))))
-                 (`(throw ',quit ,expr))))))
-      (when-let ((tco-body (funcall tco (macroexpand-all (macroexp-progn body)))))
-        (setq body `((catch ',quit
-                       (while t (let ,rargs ,@(macroexp-unprogn tco-body)))))))
-      (let ((expand (macroexpand-all (macroexp-progn body) (list (cons name macro)))))
-        (if total-tco
-            `(let ,bindings ,expand)
-          `(funcall
-            (letrec ((,self (lambda ,fargs ,expand))) ,self)
-            ,@aargs))))))
-
-;;;; Defined in files.el
-
-(compat-defun file-name-with-extension (filename extension) ;; <compat-tests:file-name-with-extension>
-  "Set the EXTENSION of a FILENAME.
-The extension (in a file name) is the part that begins with the last \".\".
-
-Trims a leading dot from the EXTENSION so that either \"foo\" or
-\".foo\" can be given.
-
-Errors if the FILENAME or EXTENSION are empty, or if the given
-FILENAME has the format of a directory.
-
-See also `file-name-sans-extension'."
-  (let ((extn (string-remove-prefix "." extension)))
-    (cond
-     ((string= filename "")
-      (error "Empty filename"))
-     ((string= extn "")
-      (error "Malformed extension: %s" extension))
-     ((directory-name-p filename)
-      (error "Filename is a directory: %s" filename))
-     (t
-      (concat (file-name-sans-extension filename) "." extn)))))
-
-(compat-defun directory-empty-p (dir) ;; <compat-tests:directory-empty-p>
-  "Return t if DIR names an existing directory containing no other files.
-Return nil if DIR does not name a directory, or if there was
-trouble determining whether DIR is a directory or empty.
-
-Symbolic links to directories count as directories.
-See `file-symlink-p' to distinguish symlinks."
-  (and (file-directory-p dir)
-       (null (directory-files dir nil directory-files-no-dot-files-regexp t))))
-
-(compat-defun file-modes-number-to-symbolic (mode &optional filetype) ;; <compat-tests:file-modes-number-to-symbolic>
-  "Return a string describing a file's MODE.
-For instance, if MODE is #o700, then it produces `-rwx------'.
-FILETYPE if provided should be a character denoting the type of file,
-such as `?d' for a directory, or `?l' for a symbolic link and will override
-the leading `-' char."
-  (string
-   (or filetype
-       (pcase (ash mode -12)
-         ;; POSIX specifies that the file type is included in st_mode
-         ;; and provides names for the file types but values only for
-         ;; the permissions (e.g., S_IWOTH=2).
-
-         ;; (#o017 ??) ;; #define S_IFMT  00170000
-         (#o014 ?s)    ;; #define S_IFSOCK 0140000
-         (#o012 ?l)    ;; #define S_IFLNK  0120000
-         ;; (8  ??)    ;; #define S_IFREG  0100000
-         (#o006  ?b)   ;; #define S_IFBLK  0060000
-         (#o004  ?d)   ;; #define S_IFDIR  0040000
-         (#o002  ?c)   ;; #define S_IFCHR  0020000
-         (#o001  ?p)   ;; #define S_IFIFO  0010000
-         (_ ?-)))
-   (if (zerop (logand   256 mode)) ?- ?r)
-   (if (zerop (logand   128 mode)) ?- ?w)
-   (if (zerop (logand    64 mode))
-       (if (zerop (logand  2048 mode)) ?- ?S)
-     (if (zerop (logand  2048 mode)) ?x ?s))
-   (if (zerop (logand    32 mode)) ?- ?r)
-   (if (zerop (logand    16 mode)) ?- ?w)
-   (if (zerop (logand     8 mode))
-       (if (zerop (logand  1024 mode)) ?- ?S)
-     (if (zerop (logand  1024 mode)) ?x ?s))
-   (if (zerop (logand     4 mode)) ?- ?r)
-   (if (zerop (logand     2 mode)) ?- ?w)
-   (if (zerop (logand 512 mode))
-       (if (zerop (logand   1 mode)) ?- ?x)
-     (if (zerop (logand   1 mode)) ?T ?t))))
-
-(compat-defun file-backup-file-names (filename) ;; <compat-tests:file-backup-file-names>
-  "Return a list of backup files for FILENAME.
-The list will be sorted by modification time so that the most
-recent files are first."
-  ;; `make-backup-file-name' will get us the right directory for
-  ;; ordinary or numeric backups.  It might create a directory for
-  ;; backups as a side-effect, according to `backup-directory-alist'.
-  (let* ((filename (file-name-sans-versions
-                    (make-backup-file-name (expand-file-name filename))))
-         (dir (file-name-directory filename))
-         files)
-    (dolist (file (file-name-all-completions
-                   (file-name-nondirectory filename) dir))
-      (let ((candidate (concat dir file)))
-        (when (and (backup-file-name-p candidate)
-                   (string= (file-name-sans-versions candidate) filename))
-          (push candidate files))))
-    (sort files #'file-newer-than-file-p)))
-
-(compat-defun make-lock-file-name (filename) ;; <compat-tests:make-lock-file-name>
-  "Make a lock file name for FILENAME.
-This prepends \".#\" to the non-directory part of FILENAME, and
-doesn't respect `lock-file-name-transforms', as Emacs 28.1 and
-onwards does."
-  (expand-file-name
-   (concat
-    ".#" (file-name-nondirectory filename))
-   (file-name-directory filename)))
-
-;;;; Defined in minibuffer.el
-
-(compat-defun format-prompt (prompt default &rest format-args) ;; <compat-tests:format-prompt>
-  "Format PROMPT with DEFAULT.
-If FORMAT-ARGS is nil, PROMPT is used as a plain string.  If
-FORMAT-ARGS is non-nil, PROMPT is used as a format control
-string, and FORMAT-ARGS are the arguments to be substituted into
-it.  See `format' for details.
-
-If DEFAULT is a list, the first element is used as the default.
-If not, the element is used as is.
-
-If DEFAULT is nil or an empty string, no \"default value\" string
-is included in the return value."
-  (concat
-   (if (null format-args)
-       prompt
-     (apply #'format prompt format-args))
-   (and default
-        (or (not (stringp default))
-            (> (length default) 0))
-        (format " (default %s)"
-                (if (consp default)
-                    (car default)
-                  default)))
-   ": "))
-
-;;;; Defined in faces.el
-
-(compat-defvar color-luminance-dark-limit 0.325 ;; <compat-tests:color-dark-p>
-  "The relative luminance below which a color is considered \"dark\".
-A \"dark\" color in this sense provides better contrast with white
-than with black; see `color-dark-p'.
-This value was determined experimentally."
-  :constant t)
-
-(compat-defun color-dark-p (rgb) ;; <compat-tests:color-dark-p>
-  "Whether RGB is more readable against white than black.
-RGB is a 3-element list (R G B), each component in the range [0,1].
-This predicate can be used both for determining a suitable (black or white)
-contrast color with RGB as background and as foreground."
-  (unless (<= 0 (apply #'min rgb) (apply #'max rgb) 1)
-    (error "RGB components %S not in [0,1]" rgb))
-  ;; Compute the relative luminance after gamma-correcting (assuming sRGB),
-  ;; and compare to a cut-off value determined experimentally.
-  ;; See https://en.wikipedia.org/wiki/Relative_luminance for details.
-  (let* ((sr (nth 0 rgb))
-         (sg (nth 1 rgb))
-         (sb (nth 2 rgb))
-         ;; Gamma-correct the RGB components to linear values.
-         ;; Use the power 2.2 as an approximation to sRGB gamma;
-         ;; it should be good enough for the purpose of this function.
-         (r (expt sr 2.2))
-         (g (expt sg 2.2))
-         (b (expt sb 2.2))
-         (y (+ (* r 0.2126) (* g 0.7152) (* b 0.0722))))
-    (< y color-luminance-dark-limit)))
-
-;;;; Defined in window.el
-
-(compat-defmacro with-window-non-dedicated (window &rest body) ;; <compat-tests:with-window-non-dedicated>
-  "Evaluate BODY with WINDOW temporarily made non-dedicated.
-If WINDOW is nil, use the selected window.  Return the value of
-the last form in BODY."
-  (declare (indent 1) (debug t))
-  (let ((window-dedicated-sym (gensym))
-        (window-sym (gensym)))
-    `(let* ((,window-sym (window-normalize-window ,window t))
-            (,window-dedicated-sym (window-dedicated-p ,window-sym)))
-       (set-window-dedicated-p ,window-sym nil)
-       (unwind-protect
-           (progn ,@body)
-         (set-window-dedicated-p ,window-sym ,window-dedicated-sym)))))
-
-(compat-defun count-windows (&optional minibuf all-frames) ;; <compat-tests:count-windows>
-  "Handle optional argument ALL-FRAMES."
-  :extended t
-  (if all-frames
-      (let ((sum 0))
-        (dolist (frame (frame-list))
-          (with-selected-frame frame
-            (setq sum (+ (count-windows minibuf) sum))))
-        sum)
-    (count-windows minibuf)))
-
-;;;; Defined in thingatpt.el
-
-(compat-defun thing-at-mouse (event thing &optional no-properties) ;; <compat-tests:thing-at-mouse>
-  "Return the THING at mouse click.
-Like `thing-at-point', but tries to use the event
-where the mouse button is clicked to find a thing nearby."
-  ;; No :feature specified, since the function is autoloaded.
-  (save-excursion
-    (mouse-set-point event)
-    (thing-at-point thing no-properties)))
-
-(compat-defun bounds-of-thing-at-mouse (event thing) ;; <compat-tests:thing-at-mouse>
-  "Determine start and end locations for THING at mouse click given by EVENT.
-Like `bounds-of-thing-at-point', but tries to use the position in EVENT
-where the mouse button is clicked to find the thing nearby."
-  ;; No :feature specified, since the function is autoloaded.
-  (save-excursion
-    (mouse-set-point event)
-    (bounds-of-thing-at-point thing)))
-
-;;;; Defined in mouse.el
-
-(compat-defun mark-thing-at-mouse (click thing) ;; <compat-tests:thing-at-mouse>
-  "Activate the region around THING found near the mouse CLICK."
-  (when-let ((bounds (bounds-of-thing-at-mouse click thing)))
-    (goto-char (if mouse-select-region-move-to-beginning
-                   (car bounds) (cdr bounds)))
-    (push-mark (if mouse-select-region-move-to-beginning
-                   (cdr bounds) (car bounds))
-               t 'activate)))
-
-;;;; Defined in macroexp.el
-
-(compat-defun macroexp-warn-and-return (msg form &optional _category _compile-only _arg) ;; <compat-tests:macroexp-warn-and-return>
-  "Return code equivalent to FORM labeled with warning MSG.
-CATEGORY is the category of the warning, like the categories that
-can appear in `byte-compile-warnings'.
-COMPILE-ONLY non-nil means no warning should be emitted if the code
-is executed without being compiled first.
-ARG is a symbol (or a form) giving the source code position for the message.
-It should normally be a symbol with position and it defaults to FORM."
-  (macroexp--warn-and-return msg form))
-
-(compat-defun macroexp-file-name () ;; <compat-tests:macroexp-file-name>
-  "Return the name of the file from which the code comes.
-Returns nil when we do not know.
-A non-nil result is expected to be reliable when called from a macro in order
-to find the file in which the macro's call was found, and it should be
-reliable as well when used at the top-level of a file.
-Other uses risk returning non-nil value that point to the wrong file."
-  (let ((file (car (last current-load-list))))
-    (or (if (stringp file) file)
-        (bound-and-true-p byte-compile-current-file))))
-
-;;;; Defined in env.el
-
-(compat-defmacro with-environment-variables (variables &rest body) ;; <compat-tests:with-environment-variables>
-  "Set VARIABLES in the environent and execute BODY.
-VARIABLES is a list of variable settings of the form (VAR VALUE),
-where VAR is the name of the variable (a string) and VALUE
-is its value (also a string).
-
-The previous values will be be restored upon exit."
-  (declare (indent 1) (debug (sexp body)))
-  (unless (consp variables)
-    (error "Invalid VARIABLES: %s" variables))
-  `(let ((process-environment (copy-sequence process-environment)))
-     ,@(mapcar (lambda (elem)
-                 `(setenv ,(car elem) ,(cadr elem)))
-               variables)
-     ,@body))
-
-;;;; Defined in time-data.el
-
-(compat-defun decoded-time-period (time) ;; <compat-tests:decoded-time-period>
-  "Interpret DECODED as a period and return its length in seconds.
-For computational purposes, years are 365 days long and months
-are 30 days long."
-  :feature time-date
-  (+ (if (consp (decoded-time-second time))
-         (/ (float (car (decoded-time-second time)))
-            (cdr (decoded-time-second time)))
-       (or (decoded-time-second time) 0))
-     (* (or (decoded-time-minute time) 0) 60)
-     (* (or (decoded-time-hour time) 0) 60 60)
-     (* (or (decoded-time-day time) 0) 60 60 24)
-     (* (or (decoded-time-month time) 0) 60 60 24 30)
-     (* (or (decoded-time-year time) 0) 60 60 24 365)))
-
-;;;; Defined in doc.c
-
-(compat-defun text-quoting-style () ;; <compat-tests:text-quoting-style>
-  "Return the current effective text quoting style.
-If the variable `text-quoting-style' is `grave', `straight' or
-`curve', just return that value.  If it is nil (the default), return
-`grave' if curved quotes cannot be displayed (for instance, on a
-terminal with no support for these characters), otherwise return
-`quote'.  Any other value is treated as `grave'.
-
-Note that in contrast to the variable `text-quoting-style', this
-function will never return nil."
-  (cond
-   ((memq text-quoting-style '(grave straight curve))
-    text-quoting-style)
-   ((not text-quoting-style) 'grave)
-   (t 'curve)))
-
-;;;; Defined in button.el
-
-;; Obsolete Alias since 29
-(compat-defalias button-buttonize buttonize :obsolete t) ;; <compat-tests:button-buttonize>
-
-;;;; Defined in wid-edit.el
-
-(compat-guard t ;; <compat-tests:widget-natnum>
-  :feature wid-edit
-  (define-widget 'natnum 'restricted-sexp
-    "A nonnegative integer."
-    :tag "Integer (positive)"
-    :value 0
-    :type-error "This field should contain a nonnegative integer"
-    :match-alternatives '(natnump)))
-
-(provide 'compat-28)
-;;; compat-28.el ends here
diff --git a/elpa/compat-29.1.4.1/compat-29.el b/elpa/compat-29.1.4.1/compat-29.el
deleted file mode 100644 (file)
index 8a22639..0000000
+++ /dev/null
@@ -1,1579 +0,0 @@
-;;; compat-29.el --- Functionality added in Emacs 29.1 -*- lexical-binding: t; -*-
-
-;; Copyright (C) 2021-2023 Free Software Foundation, Inc.
-
-;; This program is free software; you can redistribute it and/or modify
-;; it under the terms of the GNU General Public License as published by
-;; the Free Software Foundation, either version 3 of the License, or
-;; (at your option) any later version.
-
-;; This program is distributed in the hope that it will be useful,
-;; but WITHOUT ANY WARRANTY; without even the implied warranty of
-;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-;; GNU General Public License for more details.
-
-;; You should have received a copy of the GNU General Public License
-;; along with this program.  If not, see <https://www.gnu.org/licenses/>.
-
-;;; Commentary:
-
-;; Functionality added in Emacs 29.1, needed by older Emacs versions.
-
-;;; Code:
-
-(eval-when-compile (load "compat-macs.el" nil t t))
-(compat-require compat-28 "28.1")
-
-;; Preloaded in loadup.el
-;; TODO Update to 29.1 as soon as the Emacs emacs-29 branch version bumped
-(compat-require seq "29.0") ;; <compat-tests:seq>
-
-;; TODO Update to 29.1 as soon as the Emacs emacs-29 branch version bumped
-(compat-version "29.0")
-
-;;;; Defined in xdisp.c
-
-(compat-defun get-display-property (position prop &optional object properties) ;; <compat-tests:get-display-property>
-  "Get the value of the `display' property PROP at POSITION.
-If OBJECT, this should be a buffer or string where the property is
-fetched from.  If omitted, OBJECT defaults to the current buffer.
-
-If PROPERTIES, look for value of PROP in PROPERTIES instead of
-the properties at POSITION."
-  (if properties
-      (unless (listp properties)
-        (signal 'wrong-type-argument (list 'listp properties)))
-    (setq properties (get-text-property position 'display object)))
-  (cond
-   ((vectorp properties)
-    (catch 'found
-      (dotimes (i (length properties))
-        (let ((ent (aref properties i)))
-          (when (eq (car ent) prop)
-            (throw 'found (cadr ent )))))))
-   ((consp (car properties))
-    (condition-case nil
-        (cadr (assq prop properties))
-      ;; Silently handle improper lists:
-      (wrong-type-argument nil)))
-   ((and (consp (cdr properties))
-         (eq (car properties) prop))
-    (cadr properties))))
-
-;;;; Defined in fns.c
-
-(compat-defun ntake (n list) ;; <compat-tests:ntake>
-  "Modify LIST to keep only the first N elements.
-If N is zero or negative, return nil.
-If N is greater or equal to the length of LIST, return LIST unmodified.
-Otherwise, return LIST after truncating it."
-  (and (> n 0) (let ((cons (nthcdr (1- n) list)))
-                 (when cons (setcdr cons nil))
-                 list)))
-
-(compat-defun take (n list) ;; <compat-tests:take>
-  "Return the first N elements of LIST.
-If N is zero or negative, return nil.
-If N is greater or equal to the length of LIST, return LIST (or a copy)."
-  (declare (pure t) (side-effect-free t))
-  (let (copy)
-    (while (and (< 0 n) list)
-      (push (pop list) copy)
-      (setq n (1- n)))
-    (nreverse copy)))
-
-(compat-defun string-equal-ignore-case (string1 string2) ;; <compat-tests:string-equal-ignore-case>
-  "Like `string-equal', but case-insensitive.
-Upper-case and lower-case letters are treated as equal.
-Unibyte strings are converted to multibyte for comparison."
-  (declare (pure t) (side-effect-free t))
-  (eq t (compare-strings string1 0 nil string2 0 nil t)))
-
-(compat-defun plist-get (plist prop &optional predicate) ;; <compat-tests:plist-get>
-  "Handle optional argument PREDICATE."
-  :extended t
-  (if (or (null predicate) (eq predicate 'eq))
-      (plist-get plist prop)
-    (catch 'found
-      (while (consp plist)
-        (when (funcall predicate prop (car plist))
-          (throw 'found (cadr plist)))
-        (setq plist (cddr plist))))))
-
-(compat-defun plist-put (plist prop val &optional predicate) ;; <compat-tests:plist-get>
-  "Handle optional argument PREDICATE."
-  :extended t
-  (if (or (null predicate) (eq predicate 'eq))
-      (plist-put plist prop val)
-    (catch 'found
-      (let ((tail plist))
-        (while (consp tail)
-          (when (funcall predicate prop (car tail))
-            (setcar (cdr tail) val)
-            (throw 'found plist))
-          (setq tail (cddr tail))))
-      (nconc plist (list prop val)))))
-
-(compat-defun plist-member (plist prop &optional predicate) ;; <compat-tests:plist-get>
-  "Handle optional argument PREDICATE."
-  :extended t
-  (if (or (null predicate) (eq predicate 'eq))
-      (plist-member plist prop)
-    (catch 'found
-      (while (consp plist)
-        (when (funcall predicate prop (car plist))
-          (throw 'found plist))
-        (setq plist (cddr plist))))))
-
-;;;; Defined in gv.el
-
-(compat-guard t ;; <compat-tests:plist-get-gv>
-  (gv-define-expander compat--plist-get
-    (lambda (do plist prop &optional predicate)
-      (macroexp-let2 macroexp-copyable-p key prop
-        (gv-letplace (getter setter) plist
-          (macroexp-let2 nil p `(cdr (compat--plist-member ,getter ,key ,predicate))
-            (funcall do
-                     `(car ,p)
-                     (lambda (val)
-                       `(if ,p
-                            (setcar ,p ,val)
-                          ,(funcall setter
-                                    `(cons ,key (cons ,val ,getter)))))))))))
-  (unless (get 'plist-get 'gv-expander)
-    (put 'plist-get 'gv-expander (get 'compat--plist-get 'gv-expander))))
-
-;;;; Defined in editfns.c
-
-(compat-defun pos-bol (&optional n) ;; <compat-tests:pos-bol>
-  "Return the position of the first character on the current line.
-With optional argument N, scan forward N - 1 lines first.
-If the scan reaches the end of the buffer, return that position.
-
-This function ignores text display directionality; it returns the
-position of the first character in logical order, i.e. the smallest
-character position on the logical line.  See `vertical-motion' for
-movement by screen lines.
-
-This function does not move point.  Also see `line-beginning-position'."
-  (declare (side-effect-free t))
-  (let ((inhibit-field-text-motion t))
-    (line-beginning-position n)))
-
-(compat-defun pos-eol (&optional n) ;; <compat-tests:pos-bol>
-  "Return the position of the last character on the current line.
-With argument N not nil or 1, move forward N - 1 lines first.
-If scan reaches end of buffer, return that position.
-
-This function ignores text display directionality; it returns the
-position of the last character in logical order, i.e. the largest
-character position on the line.
-
-This function does not move point.  Also see `line-end-position'."
-  (declare (side-effect-free t))
-  (let ((inhibit-field-text-motion t))
-    (line-end-position n)))
-
-;;;; Defined in subr.el
-
-(compat-defmacro with-delayed-message (_args &rest body) ;; <compat-tests:with-delayed-message>
-  "Like `progn', but display MESSAGE if BODY takes longer than TIMEOUT seconds.
-The MESSAGE form will be evaluated immediately, but the resulting
-string will be displayed only if BODY takes longer than TIMEOUT seconds.
-
-NOTE: The compatibility function never displays the message,
-which is not problematic since the only effect of the function is
-to display a progress message to the user.  Backporting this
-feature is not possible, since the implementation is directly
-baked into the Elisp interpreter.
-
-\(fn (timeout message) &rest body)"
-  (declare (indent 1))
-  (macroexp-progn body))
-
-(compat-defun funcall-with-delayed-message (timeout message function) ;; <compat-tests:with-delayed-message>
-  "Like `funcall', but display MESSAGE if FUNCTION takes longer than TIMEOUT.
-TIMEOUT is a number of seconds, and can be an integer or a
-floating point number.  If FUNCTION takes less time to execute
-than TIMEOUT seconds, MESSAGE is not displayed.
-
-NOTE: The compatibility function never displays the message,
-which is not problematic since the only effect of the function is
-to display a progress message to the user.  Backporting this
-feature is not possible, since the implementation is directly
-baked into the Elisp interpreter."
-  (ignore timeout message)
-  (funcall function))
-
-(compat-defun string-lines (string &optional omit-nulls keep-newlines) ;; <compat-tests:string-lines>
-  "Handle additional KEEP-NEWLINES argument."
-  :extended "28.1"
-  (if (equal string "")
-      (if omit-nulls
-          nil
-        (list ""))
-    (let ((lines nil)
-          (start 0))
-      (while (< start (length string))
-        (let ((newline (string-search "\n" string start)))
-          (if newline
-              (progn
-                (when (or (not omit-nulls)
-                          (not (= start newline)))
-                  (let ((line (substring string start
-                                         (if keep-newlines
-                                             (1+ newline)
-                                           newline))))
-                    (when (not (and keep-newlines omit-nulls
-                                    (equal line "\n")))
-                      (push line lines))))
-                (setq start (1+ newline)))
-            (if (zerop start)
-                (push string lines)
-              (push (substring string start) lines))
-            (setq start (length string)))))
-      (nreverse lines))))
-
-(compat-defun readablep (object) ;; <compat-tests:readablep>
-  "Say whether OBJECT has a readable syntax.
-This means that OBJECT can be printed out and then read back
-again by the Lisp reader.  This function returns nil if OBJECT is
-unreadable, and the printed representation (from `prin1') of
-OBJECT if it is readable."
-  (declare (side-effect-free error-free))
-  (ignore-errors (equal object (read (prin1-to-string object)))))
-
-(compat-defun buffer-local-restore-state (states) ;; <compat-tests:buffer-local-set-state>
-  "Restore values of buffer-local variables recorded in STATES.
-STATES should be an object returned by `buffer-local-set-state'."
-  (dolist (state states)
-    (if (cadr state)
-        (set (car state) (caddr state))
-      (kill-local-variable (car state)))))
-
-(compat-defun buffer-local-set-state--get (pairs) ;; <compat-tests:buffer-local-set-state>
-  "Internal helper function."
-  (let ((states nil))
-    (while pairs
-      (push (list (car pairs)
-                  (and (boundp (car pairs))
-                       (local-variable-p (car pairs)))
-                  (and (boundp (car pairs))
-                       (symbol-value (car pairs))))
-            states)
-      (setq pairs (cddr pairs)))
-    (nreverse states)))
-
-(compat-defmacro buffer-local-set-state (&rest pairs) ;; <compat-tests:buffer-local-set-state>
-  "Like `setq-local', but allow restoring the previous state of locals later.
-This macro returns an object that can be passed to `buffer-local-restore-state'
-in order to restore the state of the local variables set via this macro.
-
-\(fn [VARIABLE VALUE]...)"
-  (declare (debug setq))
-  (unless (zerop (mod (length pairs) 2))
-    (error "PAIRS must have an even number of variable/value members"))
-  `(prog1
-       (buffer-local-set-state--get ',pairs)
-     (,(if (fboundp 'compat--setq-local) 'compat--setq-local 'setq-local)
-      ,@pairs)))
-
-(compat-defun list-of-strings-p (object) ;; <compat-tests:lists-of-strings-p>
-  "Return t if OBJECT is nil or a list of strings."
-  (declare (pure t) (side-effect-free t))
-  (while (and (consp object) (stringp (car object)))
-    (setq object (cdr object)))
-  (null object))
-
-(compat-defun plistp (object) ;; <compat-tests:plistp>
-  "Non-nil if and only if OBJECT is a valid plist."
-  (let ((len (proper-list-p object)))
-    (and len (zerop (% len 2)))))
-
-(compat-defun delete-line () ;; <compat-tests:delete-line>
-  "Delete the current line."
-  (delete-region (pos-bol) (pos-bol 2)))
-
-(compat-defmacro with-restriction (start end &rest rest) ;; <compat-tests:with-restriction>
-  "Execute BODY with restrictions set to START and END.
-
-The current restrictions, if any, are restored upon return.
-
-When the optional :label LABEL argument is present, in which
-LABEL is a symbol, inside BODY, `narrow-to-region' and `widen'
-can be used only within the START and END limits.  To gain access
-to other portions of the buffer, use `without-restriction' with the
-same LABEL argument.
-
-\(fn START END [:label LABEL] BODY)"
-  (declare (indent 0) (debug t))
-  `(save-restriction
-     (narrow-to-region ,start ,end)
-     ;; Locking is ignored
-     ,@(if (eq (car rest) :label) (cddr rest) rest)))
-
-(compat-defmacro without-restriction (&rest rest) ;; <compat-tests:without-restriction>
-  "Execute BODY without restrictions.
-
-The current restrictions, if any, are restored upon return.
-
-When the optional :label LABEL argument is present, the
-restrictions set by `with-restriction' with the same LABEL argument
-are lifted.
-
-\(fn [:label LABEL] BODY)"
-  (declare (indent 0) (debug t))
-  `(save-restriction
-     (widen)
-     ;; Locking is ignored
-     ,@(if (eq (car rest) :label) (cddr rest) rest)))
-
-(compat-defmacro with-memoization (place &rest code) ;; <compat-tests:with-memoization>
-  "Return the value of CODE and stash it in PLACE.
-If PLACE's value is non-nil, then don't bother evaluating CODE
-and return the value found in PLACE instead."
-  (declare (indent 1))
-  (gv-letplace (getter setter) place
-    `(or ,getter
-         ,(macroexp-let2 nil val (macroexp-progn code)
-            `(progn
-               ,(funcall setter val)
-               ,val)))))
-
-(compat-defalias string-split split-string) ;; <compat-tests:string-split>
-
-(compat-defun compiled-function-p (object) ;; <compat-tests:compiled-function-p>
-  "Return non-nil if OBJECT is a function that has been compiled.
-Does not distinguish between functions implemented in machine code
-or byte-code."
-  (or (subrp object) (byte-code-function-p object)))
-
-(compat-defun function-alias-p (func &optional noerror) ;; <compat-tests:function-alias-p>
-  "Return nil if FUNC is not a function alias.
-If FUNC is a function alias, return the function alias chain.
-
-If the function alias chain contains loops, an error will be
-signalled.  If NOERROR, the non-loop parts of the chain is returned."
-  (declare (side-effect-free t))
-  (let ((chain nil)
-        (orig-func func))
-    (nreverse
-     (catch 'loop
-       (while (and (symbolp func)
-                   (setq func (symbol-function func))
-                   (symbolp func))
-         (when (or (memq func chain)
-                   (eq func orig-func))
-           (if noerror
-               (throw 'loop chain)
-             (signal 'cyclic-function-indirection (list orig-func))))
-         (push func chain))
-       chain))))
-
-(compat-defun buffer-match-p (condition buffer-or-name &optional arg) ;; <compat-tests:buffer-match-p>
-  "Return non-nil if BUFFER-OR-NAME matches CONDITION.
-CONDITION is either:
-- the symbol t, to always match,
-- the symbol nil, which never matches,
-- a regular expression, to match a buffer name,
-- a predicate function that takes a buffer object and ARG as
-  arguments, and returns non-nil if the buffer matches,
-- a cons-cell, where the car describes how to interpret the cdr.
-  The car can be one of the following:
-  * `derived-mode': the buffer matches if the buffer's major mode
-    is derived from the major mode in the cons-cell's cdr.
-  * `major-mode': the buffer matches if the buffer's major mode
-    is eq to the cons-cell's cdr.  Prefer using `derived-mode'
-    instead when both can work.
-  * `not': the cadr is interpreted as a negation of a condition.
-  * `and': the cdr is a list of recursive conditions, that all have
-    to be met.
-  * `or': the cdr is a list of recursive condition, of which at
-    least one has to be met."
-  (letrec
-      ((buffer (get-buffer buffer-or-name))
-       (match
-        (lambda (conditions)
-          (catch 'match
-            (dolist (condition conditions)
-              (when (cond
-                     ((eq condition t))
-                     ((stringp condition)
-                      (string-match-p condition (buffer-name buffer)))
-                     ((functionp condition)
-                      (condition-case nil
-                          (funcall condition buffer)
-                        (wrong-number-of-arguments
-                         (funcall condition buffer arg))))
-                     ((eq (car-safe condition) 'major-mode)
-                      (eq
-                       (buffer-local-value 'major-mode buffer)
-                       (cdr condition)))
-                     ((eq (car-safe condition) 'derived-mode)
-                      (provided-mode-derived-p
-                       (buffer-local-value 'major-mode buffer)
-                       (cdr condition)))
-                     ((eq (car-safe condition) 'not)
-                      (not (funcall match (cdr condition))))
-                     ((eq (car-safe condition) 'or)
-                      (funcall match (cdr condition)))
-                     ((eq (car-safe condition) 'and)
-                      (catch 'fail
-                        (dolist (c (cdr condition))
-                          (unless (funcall match (list c))
-                            (throw 'fail nil)))
-                        t)))
-                (throw 'match t)))))))
-    (funcall match (list condition))))
-
-(compat-defun match-buffers (condition &optional buffers arg) ;; <compat-tests:match-buffers>
-  "Return a list of buffers that match CONDITION.
-See `buffer-match' for details on CONDITION.  By default all
-buffers are checked, this can be restricted by passing an
-optional argument BUFFERS, set to a list of buffers to check.
-ARG is passed to `buffer-match', for predicate conditions in
-CONDITION."
-  (let (bufs)
-    (dolist (buf (or buffers (buffer-list)))
-      (when (buffer-match-p condition (get-buffer buf) arg)
-        (push buf bufs)))
-    bufs))
-
-(compat-defvar set-transient-map-timeout nil ;; <compat-tests:set-transient-map>
-  "Timeout in seconds for deactivation of a transient keymap.
-If this is a number, it specifies the amount of idle time
-after which to deactivate the keymap set by `set-transient-map',
-thus overriding the value of the TIMEOUT argument to that function.")
-
-(compat-defvar set-transient-map-timer nil ;; <compat-tests:set-transient-map>
-  "Timer for `set-transient-map-timeout'.")
-
-(declare-function format-spec "format-spec")
-(compat-defun set-transient-map (map &optional keep-pred on-exit message timeout) ;; <compat-tests:set-transient-map>
-  "Handle the optional arguments MESSAGE and TIMEOUT."
-  :extended t
-  (unless (fboundp 'format-spec)
-    (require 'format-spec))
-  (let* ((timeout (or set-transient-map-timeout timeout))
-         (message
-          (when message
-            (let (keys)
-              (map-keymap (lambda (key cmd) (and cmd (push key keys))) map)
-              (format-spec (if (stringp message) message "Repeat with %k")
-                           `((?k . ,(mapconcat
-                                     (lambda (key)
-                                       (substitute-command-keys
-                                        (format "\\`%s'"
-                                                (key-description (vector key)))))
-                                     keys ", ")))))))
-         (clearfun (make-symbol "clear-transient-map"))
-         (exitfun
-          (lambda ()
-            (internal-pop-keymap map 'overriding-terminal-local-map)
-            (remove-hook 'pre-command-hook clearfun)
-            (when message (message ""))
-            (when set-transient-map-timer (cancel-timer set-transient-map-timer))
-            (when on-exit (funcall on-exit)))))
-    (fset clearfun
-          (lambda ()
-            (with-demoted-errors "set-transient-map PCH: %S"
-              (if (cond
-                       ((null keep-pred) nil)
-                       ((and (not (eq map (cadr overriding-terminal-local-map)))
-                             (memq map (cddr overriding-terminal-local-map)))
-                        t)
-                       ((eq t keep-pred)
-                        (let ((mc (lookup-key map (this-command-keys-vector))))
-                          (when (and mc (symbolp mc))
-                            (setq mc (or (command-remapping mc) mc)))
-                          (and mc (eq this-command mc))))
-                       (t (funcall keep-pred)))
-                  (when message (message "%s" message))
-                (funcall exitfun)))))
-    (add-hook 'pre-command-hook clearfun)
-    (internal-push-keymap map 'overriding-terminal-local-map)
-    (when timeout
-      (when set-transient-map-timer (cancel-timer set-transient-map-timer))
-      (setq set-transient-map-timer (run-with-idle-timer timeout nil exitfun)))
-    (when message (message "%s" message))
-    exitfun))
-
-;;;; Defined in simple.el
-
-(compat-defun use-region-noncontiguous-p () ;; <compat-tests:region-noncontiguous-p>
-  "Return non-nil for a non-contiguous region if `use-region-p'."
-  (and (use-region-p) (region-noncontiguous-p)))
-
-(compat-defun use-region-beginning () ;; <compat-tests:use-region>
-  "Return the start of the region if `use-region-p'."
-  (and (use-region-p) (region-beginning)))
-
-(compat-defun use-region-end () ;; <compat-tests:use-region>
-  "Return the end of the region if `use-region-p'."
-  (and (use-region-p) (region-end)))
-
-(compat-defun get-scratch-buffer-create () ;; <compat-tests:get-scratch-buffer-create>
-  "Return the *scratch* buffer, creating a new one if needed."
-  (or (get-buffer "*scratch*")
-      (let ((scratch (get-buffer-create "*scratch*")))
-        ;; Don't touch the buffer contents or mode unless we know that
-        ;; we just created it.
-        (with-current-buffer scratch
-          (when initial-scratch-message
-            (insert (substitute-command-keys initial-scratch-message))
-            (set-buffer-modified-p nil))
-          (funcall initial-major-mode))
-        scratch)))
-
-;;;; Defined in subr-x.el
-
-(compat-defmacro with-buffer-unmodified-if-unchanged (&rest body) ;; <compat-tests:with-buffer-unmodified-if-unchanged>
-  "Like `progn', but change buffer-modified status only if buffer text changes.
-If the buffer was unmodified before execution of BODY, and
-buffer text after execution of BODY is identical to what it was
-before, ensure that buffer is still marked unmodified afterwards.
-For example, the following won't change the buffer's modification
-status:
-
-  (with-buffer-unmodified-if-unchanged
-    (insert \"a\")
-    (delete-char -1))
-
-Note that only changes in the raw byte sequence of the buffer text,
-as stored in the internal representation, are monitored for the
-purpose of detecting the lack of changes in buffer text.  Any other
-changes that are normally perceived as \"buffer modifications\", such
-as changes in text properties, `buffer-file-coding-system', buffer
-multibyteness, etc. -- will not be noticed, and the buffer will still
-be marked unmodified, effectively ignoring those changes."
-  (declare (debug t) (indent 0))
-  (let ((hash (gensym))
-        (buffer (gensym)))
-    `(let ((,hash (and (not (buffer-modified-p))
-                       (buffer-hash)))
-           (,buffer (current-buffer)))
-       (prog1
-           (progn
-             ,@body)
-         ;; If we didn't change anything in the buffer (and the buffer
-         ;; was previously unmodified), then flip the modification status
-         ;; back to "unchanged".
-         (when (and ,hash (buffer-live-p ,buffer))
-           (with-current-buffer ,buffer
-             (when (and (buffer-modified-p)
-                        (equal ,hash (buffer-hash)))
-               (restore-buffer-modified-p nil))))))))
-
-(compat-defun add-display-text-property (start end prop value ;; <compat-tests:add-display-text-property>
-                                               &optional object)
-  "Add display property PROP with VALUE to the text from START to END.
-If any text in the region has a non-nil `display' property, those
-properties are retained.
-
-If OBJECT is non-nil, it should be a string or a buffer.  If nil,
-this defaults to the current buffer."
-  (let ((sub-start start)
-        (sub-end 0)
-        disp)
-    (while (< sub-end end)
-      (setq sub-end (next-single-property-change sub-start 'display object
-                                                 (if (stringp object)
-                                                     (min (length object) end)
-                                                   (min end (point-max)))))
-      (if (not (setq disp (get-text-property sub-start 'display object)))
-          ;; No old properties in this range.
-          (put-text-property sub-start sub-end 'display (list prop value)
-                             object)
-        ;; We have old properties.
-        (let ((vector nil))
-          ;; Make disp into a list.
-          (setq disp
-                (cond
-                 ((vectorp disp)
-                  (setq vector t)
-                  (append disp nil))
-                 ((not (consp (car disp)))
-                  (list disp))
-                 (t
-                  disp)))
-          ;; Remove any old instances.
-          (when-let ((old (assoc prop disp)))
-            (setq disp (delete old disp)))
-          (setq disp (cons (list prop value) disp))
-          (when vector
-            (setq disp (vconcat disp)))
-          ;; Finally update the range.
-          (put-text-property sub-start sub-end 'display disp object)))
-      (setq sub-start sub-end))))
-
-(compat-defmacro while-let (spec &rest body) ;; <compat-tests:while-let>
-  "Bind variables according to SPEC and conditionally evaluate BODY.
-Evaluate each binding in turn, stopping if a binding value is nil.
-If all bindings are non-nil, eval BODY and repeat.
-
-The variable list SPEC is the same as in `if-let*'."
-  (declare (indent 1) (debug if-let))
-  (let ((done (gensym "done")))
-    `(catch ',done
-       (while t
-         (if-let* ,spec
-             (progn
-               ,@body)
-           (throw ',done nil))))))
-
-;;;; Defined in files.el
-
-(compat-defun directory-abbrev-make-regexp (directory) ;; <compat-tests:directory-abbrev-make-regexp>
-  "Create a regexp to match DIRECTORY for `directory-abbrev-alist'."
-  (let ((regexp
-         ;; We include a slash at the end, to avoid spurious
-         ;; matches such as `/usr/foobar' when the home dir is
-         ;; `/usr/foo'.
-         (concat "\\`" (regexp-quote directory) "\\(/\\|\\'\\)")))
-    ;; The value of regexp could be multibyte or unibyte.  In the
-    ;; latter case, we need to decode it.
-    (if (multibyte-string-p regexp)
-        regexp
-      (decode-coding-string regexp
-                            (if (eq system-type 'windows-nt)
-                                'utf-8
-                              locale-coding-system)))))
-
-(compat-defun directory-abbrev-apply (filename) ;; <compat-tests:directory-abbrev-apply>
-  "Apply the abbreviations in `directory-abbrev-alist' to FILENAME.
-Note that when calling this, you should set `case-fold-search' as
-appropriate for the filesystem used for FILENAME."
-  (dolist (dir-abbrev directory-abbrev-alist filename)
-    (when (string-match (car dir-abbrev) filename)
-         (setq filename (concat (cdr dir-abbrev)
-                                (substring filename (match-end 0)))))))
-
-(compat-defun file-name-split (filename) ;; <compat-tests:file-name-split>
-  "Return a list of all the components of FILENAME.
-On most systems, this will be true:
-
-  (equal (string-join (file-name-split filename) \"/\") filename)"
-  (let ((components nil))
-    ;; If this is a directory file name, then we have a null file name
-    ;; at the end.
-    (when (directory-name-p filename)
-      (push "" components)
-      (setq filename (directory-file-name filename)))
-    ;; Loop, chopping off components.
-    (while (length> filename 0)
-      (push (file-name-nondirectory filename) components)
-      (let ((dir (file-name-directory filename)))
-        (setq filename (and dir (directory-file-name dir)))
-        ;; If there's nothing left to peel off, we're at the root and
-        ;; we can stop.
-        (when (and dir (equal dir filename))
-          (push (if (equal dir "") ""
-                  ;; On Windows, the first component might be "c:" or
-                  ;; the like.
-                  (substring dir 0 -1))
-                components)
-          (setq filename nil))))
-    components))
-
-(compat-defun file-attribute-file-identifier (attributes) ;; <compat-tests:file-attribute-getters>
-  "The inode and device numbers in ATTRIBUTES returned by `file-attributes'.
-The value is a list of the form (INODENUM DEVICE), where DEVICE could be
-either a single number or a cons cell of two numbers.
-This tuple of numbers uniquely identifies the file."
-  (nthcdr 10 attributes))
-
-(compat-defun file-name-parent-directory (filename) ;; <compat-tests:file-name-parent-directory>
-  "Return the directory name of the parent directory of FILENAME.
-If FILENAME is at the root of the filesystem, return nil.
-If FILENAME is relative, it is interpreted to be relative
-to `default-directory', and the result will also be relative."
-  (let* ((expanded-filename (expand-file-name filename))
-         (parent (file-name-directory (directory-file-name expanded-filename))))
-    (cond
-     ;; filename is at top-level, therefore no parent
-     ((or (null parent)
-          ;; `equal' is enough, we don't need to resolve symlinks here
-          ;; with `file-equal-p', also for performance
-          (equal parent expanded-filename))
-      nil)
-     ;; filename is relative, return relative parent
-     ((not (file-name-absolute-p filename))
-      (file-relative-name parent))
-     (t
-      parent))))
-
-(compat-defvar file-has-changed-p--hash-table ;; <compat-tests:file-has-changed-p>
-               (make-hash-table :test #'equal)
-  "Internal variable used by `file-has-changed-p'.")
-
-(compat-defun file-has-changed-p (file &optional tag) ;; <compat-tests:file-has-changed-p>
-  "Return non-nil if FILE has changed.
-The size and modification time of FILE are compared to the size
-and modification time of the same FILE during a previous
-invocation of `file-has-changed-p'.  Thus, the first invocation
-of `file-has-changed-p' always returns non-nil when FILE exists.
-The optional argument TAG, which must be a symbol, can be used to
-limit the comparison to invocations with identical tags; it can be
-the symbol of the calling function, for example."
-  (let* ((file (directory-file-name (expand-file-name file)))
-         (remote-file-name-inhibit-cache t)
-         (fileattr (file-attributes file 'integer))
-         (attr (and fileattr
-                    (cons (file-attribute-size fileattr)
-                          (file-attribute-modification-time fileattr))))
-         (sym (concat (symbol-name tag) "@" file))
-         (cachedattr (gethash sym file-has-changed-p--hash-table)))
-    (unless (equal attr cachedattr)
-      (puthash sym attr file-has-changed-p--hash-table))))
-
-;;;; Defined in keymap.el
-
-(compat-defun key-valid-p (keys) ;; <compat-tests:key-valid-p>
-  "Say whether KEYS is a valid key.
-A key is a string consisting of one or more key strokes.
-The key strokes are separated by single space characters.
-
-Each key stroke is either a single character, or the name of an
-event, surrounded by angle brackets.  In addition, any key stroke
-may be preceded by one or more modifier keys.  Finally, a limited
-number of characters have a special shorthand syntax.
-
-Here's some example key sequences.
-
-  \"f\"           (the key `f')
-  \"S o m\"       (a three key sequence of the keys `S', `o' and `m')
-  \"C-c o\"       (a two key sequence of the keys `c' with the control modifier
-                 and then the key `o')
-  \"H-<left>\"    (the key named \"left\" with the hyper modifier)
-  \"M-RET\"       (the \"return\" key with a meta modifier)
-  \"C-M-<space>\" (the \"space\" key with both the control and meta modifiers)
-
-These are the characters that have shorthand syntax:
-NUL, RET, TAB, LFD, ESC, SPC, DEL.
-
-Modifiers have to be specified in this order:
-
-   A-C-H-M-S-s
-
-which is
-
-   Alt-Control-Hyper-Meta-Shift-super"
-  (declare (pure t) (side-effect-free t))
-  (let ((case-fold-search nil))
-    (and
-     (stringp keys)
-     (string-match-p "\\`[^ ]+\\( [^ ]+\\)*\\'" keys)
-     (save-match-data
-       (catch 'exit
-         (let ((prefixes
-                "\\(A-\\)?\\(C-\\)?\\(H-\\)?\\(M-\\)?\\(S-\\)?\\(s-\\)?"))
-           (dolist (key (split-string keys " "))
-             ;; Every key might have these modifiers, and they should be
-             ;; in this order.
-             (when (string-match (concat "\\`" prefixes) key)
-               (setq key (substring key (match-end 0))))
-             (unless (or (and (= (length key) 1)
-                              ;; Don't accept control characters as keys.
-                              (not (< (aref key 0) ?\s))
-                              ;; Don't accept Meta'd characters as keys.
-                              (or (multibyte-string-p key)
-                                  (not (<= 127 (aref key 0) 255))))
-                         (and (string-match-p "\\`<[-_A-Za-z0-9]+>\\'" key)
-                              ;; Don't allow <M-C-down>.
-                              (= (progn
-                                   (string-match
-                                    (concat "\\`<" prefixes) key)
-                                   (match-end 0))
-                                 1))
-                         (string-match-p
-                          "\\`\\(NUL\\|RET\\|TAB\\|LFD\\|ESC\\|SPC\\|DEL\\)\\'"
-                          key))
-               ;; Invalid.
-               (throw 'exit nil)))
-           t))))))
-
-(compat-defun keymap--check (key) ;; <compat-tests:keymap--check>
-  "Signal an error if KEY doesn't have a valid syntax."
-  (unless (key-valid-p key)
-    (error "%S is not a valid key definition; see `key-valid-p'" key)))
-
-(compat-defun key-parse (keys) ;; <compat-tests:key-parse>
-  "Convert KEYS to the internal Emacs key representation.
-See `kbd' for a descripion of KEYS."
-  (declare (pure t) (side-effect-free t))
-  ;; A pure function is expected to preserve the match data.
-  (save-match-data
-    (let ((case-fold-search nil)
-          (len (length keys)) ; We won't alter keys in the loop below.
-          (pos 0)
-          (res []))
-      (while (and (< pos len)
-                  (string-match "[^ \t\n\f]+" keys pos))
-        (let* ((word-beg (match-beginning 0))
-               (word-end (match-end 0))
-               (word (substring keys word-beg len))
-               (times 1)
-               key)
-          ;; Try to catch events of the form "<as df>".
-          (if (string-match "\\`<[^ <>\t\n\f][^>\t\n\f]*>" word)
-              (setq word (match-string 0 word)
-                    pos (+ word-beg (match-end 0)))
-            (setq word (substring keys word-beg word-end)
-                  pos word-end))
-          (when (string-match "\\([0-9]+\\)\\*." word)
-            (setq times (string-to-number (substring word 0 (match-end 1))))
-            (setq word (substring word (1+ (match-end 1)))))
-          (cond ((string-match "^<<.+>>$" word)
-                 (setq key (vconcat (if (eq (key-binding [?\M-x])
-                                            'execute-extended-command)
-                                        [?\M-x]
-                                      (or (car (where-is-internal
-                                                'execute-extended-command))
-                                          [?\M-x]))
-                                    (substring word 2 -2) "\r")))
-                ((and (string-match "^\\(\\([ACHMsS]-\\)*\\)<\\(.+\\)>$" word)
-                      (progn
-                        (setq word (concat (match-string 1 word)
-                                           (match-string 3 word)))
-                        (not (string-match
-                              "\\<\\(NUL\\|RET\\|LFD\\|ESC\\|SPC\\|DEL\\)$"
-                              word))))
-                 (setq key (list (intern word))))
-                ((or (equal word "REM") (string-match "^;;" word))
-                 (setq pos (string-match "$" keys pos)))
-                (t
-                 (let ((orig-word word) (prefix 0) (bits 0))
-                   (while (string-match "^[ACHMsS]-." word)
-                     (setq bits (+ bits
-                                   (cdr
-                                    (assq (aref word 0)
-                                          '((?A . ?\A-\0) (?C . ?\C-\0)
-                                            (?H . ?\H-\0) (?M . ?\M-\0)
-                                            (?s . ?\s-\0) (?S . ?\S-\0))))))
-                     (setq prefix (+ prefix 2))
-                     (setq word (substring word 2)))
-                   (when (string-match "^\\^.$" word)
-                     (setq bits (+ bits ?\C-\0))
-                     (setq prefix (1+ prefix))
-                     (setq word (substring word 1)))
-                   (let ((found (assoc word '(("NUL" . "\0") ("RET" . "\r")
-                                              ("LFD" . "\n") ("TAB" . "\t")
-                                              ("ESC" . "\e") ("SPC" . " ")
-                                              ("DEL" . "\177")))))
-                     (when found (setq word (cdr found))))
-                   (when (string-match "^\\\\[0-7]+$" word)
-                     (let ((n 0))
-                       (dolist (ch (cdr (string-to-list word)))
-                         (setq n (+ (* n 8) ch -48)))
-                       (setq word (vector n))))
-                   (cond ((= bits 0)
-                          (setq key word))
-                         ((and (= bits ?\M-\0) (stringp word)
-                               (string-match "^-?[0-9]+$" word))
-                          (setq key (mapcar (lambda (x) (+ x bits))
-                                            (append word nil))))
-                         ((/= (length word) 1)
-                          (error "%s must prefix a single character, not %s"
-                                 (substring orig-word 0 prefix) word))
-                         ((and (/= (logand bits ?\C-\0) 0) (stringp word)
-                               ;; We used to accept . and ? here,
-                               ;; but . is simply wrong,
-                               ;; and C-? is not used (we use DEL instead).
-                               (string-match "[@-_a-z]" word))
-                          (setq key (list (+ bits (- ?\C-\0)
-                                             (logand (aref word 0) 31)))))
-                         (t
-                          (setq key (list (+ bits (aref word 0)))))))))
-          (when key
-            (dolist (_ (number-sequence 1 times))
-              (setq res (vconcat res key))))))
-      res)))
-
-(compat-defun keymap-set (keymap key definition) ;; <compat-tests:defvar-keymap>
-  "Set KEY to DEFINITION in KEYMAP.
-KEY is a string that satisfies `key-valid-p'.
-
-DEFINITION is anything that can be a key's definition:
- nil (means key is undefined in this keymap),
- a command (a Lisp function suitable for interactive calling),
- a string (treated as a keyboard macro),
- a keymap (to define a prefix key),
- a symbol (when the key is looked up, the symbol will stand for its
-    function definition, which should at that time be one of the above,
-    or another symbol whose function definition is used, etc.),
- a cons (STRING . DEFN), meaning that DEFN is the definition
-    (DEFN should be a valid definition in its own right) and
-    STRING is the menu item name (which is used only if the containing
-    keymap has been created with a menu name, see `make-keymap'),
- or a cons (MAP . CHAR), meaning use definition of CHAR in keymap MAP,
- or an extended menu item definition.
- (See info node `(elisp)Extended Menu Items'.)"
-  (keymap--check key)
-  (when (stringp definition)
-    (keymap--check definition)
-    (setq definition (key-parse definition)))
-  (define-key keymap (key-parse key) definition))
-
-(compat-defun keymap-unset (keymap key &optional remove) ;; <compat-tests:keymap-unset>
-  "Remove key sequence KEY from KEYMAP.
-KEY is a string that satisfies `key-valid-p'.
-
-If REMOVE, remove the binding instead of unsetting it.  This only
-makes a difference when there's a parent keymap.  When unsetting
-a key in a child map, it will still shadow the same key in the
-parent keymap.  Removing the binding will allow the key in the
-parent keymap to be used."
-  (keymap--check key)
-  (compat--define-key keymap (key-parse key) nil remove))
-
-(compat-defun keymap-global-set (key command) ;; <compat-tests:keymap-global-set>
-  "Give KEY a global binding as COMMAND.
-COMMAND is the command definition to use; usually it is
-a symbol naming an interactively-callable function.
-
-KEY is a string that satisfies `key-valid-p'.
-
-Note that if KEY has a local binding in the current buffer,
-that local binding will continue to shadow any global binding
-that you make with this function.
-
-NOTE: The compatibility version is not a command."
-  (keymap-set (current-global-map) key command))
-
-(compat-defun keymap-local-set (key command) ;; <compat-tests:keymap-local-set>
-  "Give KEY a local binding as COMMAND.
-COMMAND is the command definition to use; usually it is
-a symbol naming an interactively-callable function.
-
-KEY is a string that satisfies `key-valid-p'.
-
-The binding goes in the current buffer's local map, which in most
-cases is shared with all other buffers in the same major mode.
-
-NOTE: The compatibility version is not a command."
-  (let ((map (current-local-map)))
-    (unless map
-      (use-local-map (setq map (make-sparse-keymap))))
-    (keymap-set map key command)))
-
-(compat-defun keymap-global-unset (key &optional remove) ;; <compat-tests:keymap-global-unset>
-  "Remove global binding of KEY (if any).
-KEY is a string that satisfies `key-valid-p'.
-
-If REMOVE (interactively, the prefix arg), remove the binding
-instead of unsetting it.  See `keymap-unset' for details.
-
-NOTE: The compatibility version is not a command."
-  (keymap-unset (current-global-map) key remove))
-
-(compat-defun keymap-local-unset (key &optional remove) ;; <compat-tests:keymap-local-unset>
-  "Remove local binding of KEY (if any).
-KEY is a string that satisfies `key-valid-p'.
-
-If REMOVE (interactively, the prefix arg), remove the binding
-instead of unsetting it.  See `keymap-unset' for details.
-
-NOTE: The compatibility version is not a command."
-  (when (current-local-map)
-    (keymap-unset (current-local-map) key remove)))
-
-(compat-defun keymap-substitute (keymap olddef newdef &optional oldmap prefix) ;; <compat-tests:keymap-substitute>
-  "Replace OLDDEF with NEWDEF for any keys in KEYMAP now defined as OLDDEF.
-In other words, OLDDEF is replaced with NEWDEF wherever it appears.
-Alternatively, if optional fourth argument OLDMAP is specified, we redefine
-in KEYMAP as NEWDEF those keys that are defined as OLDDEF in OLDMAP.
-
-If you don't specify OLDMAP, you can usually get the same results
-in a cleaner way with command remapping, like this:
-  (define-key KEYMAP [remap OLDDEF] NEWDEF)
-\n(fn OLDDEF NEWDEF KEYMAP &optional OLDMAP)"
-  ;; Don't document PREFIX in the doc string because we don't want to
-  ;; advertise it.  It's meant for recursive calls only.  Here's its
-  ;; meaning
-
-  ;; If optional argument PREFIX is specified, it should be a key
-  ;; prefix, a string.  Redefined bindings will then be bound to the
-  ;; original key, with PREFIX added at the front.
-  (unless prefix
-    (setq prefix ""))
-  (let* ((scan (or oldmap keymap))
-         (prefix1 (vconcat prefix [nil]))
-         (key-substitution-in-progress
-          (cons scan key-substitution-in-progress)))
-    ;; Scan OLDMAP, finding each char or event-symbol that
-    ;; has any definition, and act on it with hack-key.
-    (map-keymap
-     (lambda (char defn)
-       (aset prefix1 (length prefix) char)
-       (substitute-key-definition-key defn olddef newdef prefix1 keymap))
-     scan)))
-
-(compat-defun keymap-set-after (keymap key definition &optional after) ;; <compat-tests:keymap-set-after>
-  "Add binding in KEYMAP for KEY => DEFINITION, right after AFTER's binding.
-This is like `keymap-set' except that the binding for KEY is placed
-just after the binding for the event AFTER, instead of at the beginning
-of the map.  Note that AFTER must be an event type (like KEY), NOT a command
-\(like DEFINITION).
-
-If AFTER is t or omitted, the new binding goes at the end of the keymap.
-AFTER should be a single event type--a symbol or a character, not a sequence.
-
-Bindings are always added before any inherited map.
-
-The order of bindings in a keymap matters only when it is used as
-a menu, so this function is not useful for non-menu keymaps."
-  (keymap--check key)
-  (when (eq after t) (setq after nil)) ; nil and t are treated the same
-  (when (stringp after)
-    (keymap--check after)
-    (setq after (key-parse after)))
-  ;; If we're binding this key to another key, then parse that other
-  ;; key, too.
-  (when (stringp definition)
-    (keymap--check definition)
-    (setq definition (key-parse definition)))
-  (define-key-after keymap (key-parse key) definition
-    after))
-
-(compat-defun keymap-lookup ;; <compat-tests:keymap-lookup>
-    (keymap key &optional accept-default no-remap position)
-  "Return the binding for command KEY.
-KEY is a string that satisfies `key-valid-p'.
-
-If KEYMAP is nil, look up in the current keymaps.  If non-nil, it
-should either be a keymap or a list of keymaps, and only these
-keymap(s) will be consulted.
-
-The binding is probably a symbol with a function definition.
-
-Normally, `keymap-lookup' ignores bindings for t, which act as
-default bindings, used when nothing else in the keymap applies;
-this makes it usable as a general function for probing keymaps.
-However, if the optional second argument ACCEPT-DEFAULT is
-non-nil, `keymap-lookup' does recognize the default bindings,
-just as `read-key-sequence' does.
-
-Like the normal command loop, `keymap-lookup' will remap the
-command resulting from looking up KEY by looking up the command
-in the current keymaps.  However, if the optional third argument
-NO-REMAP is non-nil, `keymap-lookup' returns the unmapped
-command.
-
-If KEY is a key sequence initiated with the mouse, the used keymaps
-will depend on the clicked mouse position with regard to the buffer
-and possible local keymaps on strings.
-
-If the optional argument POSITION is non-nil, it specifies a mouse
-position as returned by `event-start' and `event-end', and the lookup
-occurs in the keymaps associated with it instead of KEY.  It can also
-be a number or marker, in which case the keymap properties at the
-specified buffer position instead of point are used."
-  (keymap--check key)
-  (when (and keymap position)
-    (error "Can't pass in both keymap and position"))
-  (if keymap
-      (let ((value (lookup-key keymap (key-parse key) accept-default)))
-        (if (and (not no-remap)
-                   (symbolp value))
-            (or (command-remapping value) value)
-          value))
-    (key-binding (key-parse key) accept-default no-remap position)))
-
-(compat-defun keymap-local-lookup (keys &optional accept-default) ;; <compat-tests:keymap-local-lookup>
-  "Return the binding for command KEYS in current local keymap only.
-KEY is a string that satisfies `key-valid-p'.
-
-The binding is probably a symbol with a function definition.
-
-If optional argument ACCEPT-DEFAULT is non-nil, recognize default
-bindings; see the description of `keymap-lookup' for more details
-about this."
-  (when-let ((map (current-local-map)))
-    (keymap-lookup map keys accept-default)))
-
-(compat-defun keymap-global-lookup (keys &optional accept-default _message) ;; <compat-tests:keymap-global-lookup>
-  "Return the binding for command KEYS in current global keymap only.
-KEY is a string that satisfies `key-valid-p'.
-
-The binding is probably a symbol with a function definition.
-This function's return values are the same as those of `keymap-lookup'
-\(which see).
-
-If optional argument ACCEPT-DEFAULT is non-nil, recognize default
-bindings; see the description of `keymap-lookup' for more details
-about this.
-
-NOTE: The compatibility version is not a command."
-  (keymap-lookup (current-global-map) keys accept-default))
-
-(compat-defun define-keymap (&rest definitions) ;; <compat-tests:defvar-keymap>
-  "Create a new keymap and define KEY/DEFINITION pairs as key bindings.
-The new keymap is returned.
-
-Options can be given as keywords before the KEY/DEFINITION
-pairs.  Available keywords are:
-
-:full      If non-nil, create a chartable alist (see `make-keymap').
-             If nil (i.e., the default), create a sparse keymap (see
-             `make-sparse-keymap').
-
-:suppress  If non-nil, the keymap will be suppressed (see `suppress-keymap').
-             If `nodigits', treat digits like other chars.
-
-:parent    If non-nil, this should be a keymap to use as the parent
-             (see `set-keymap-parent').
-
-:keymap    If non-nil, instead of creating a new keymap, the given keymap
-             will be destructively modified instead.
-
-:name      If non-nil, this should be a string to use as the menu for
-             the keymap in case you use it as a menu with `x-popup-menu'.
-
-:prefix    If non-nil, this should be a symbol to be used as a prefix
-             command (see `define-prefix-command').  If this is the case,
-             this symbol is returned instead of the map itself.
-
-KEY/DEFINITION pairs are as KEY and DEF in `keymap-set'.  KEY can
-also be the special symbol `:menu', in which case DEFINITION
-should be a MENU form as accepted by `easy-menu-define'.
-
-\(fn &key FULL PARENT SUPPRESS NAME PREFIX KEYMAP &rest [KEY DEFINITION]...)"
-  (declare (indent defun))
-  (let (full suppress parent name prefix keymap)
-    ;; Handle keywords.
-    (while (and definitions
-                (keywordp (car definitions))
-                (not (eq (car definitions) :menu)))
-      (let ((keyword (pop definitions)))
-        (unless definitions
-          (error "Missing keyword value for %s" keyword))
-        (let ((value (pop definitions)))
-          (pcase keyword
-            (:full (setq full value))
-            (:keymap (setq keymap value))
-            (:parent (setq parent value))
-            (:suppress (setq suppress value))
-            (:name (setq name value))
-            (:prefix (setq prefix value))
-            (_ (error "Invalid keyword: %s" keyword))))))
-
-    (when (and prefix
-               (or full parent suppress keymap))
-      (error "A prefix keymap can't be defined with :full/:parent/:suppress/:keymap keywords"))
-
-    (when (and keymap full)
-      (error "Invalid combination: :keymap with :full"))
-
-    (let ((keymap (cond
-                   (keymap keymap)
-                   (prefix (define-prefix-command prefix nil name))
-                   (full (make-keymap name))
-                   (t (make-sparse-keymap name))))
-          seen-keys)
-      (when suppress
-        (suppress-keymap keymap (eq suppress 'nodigits)))
-      (when parent
-        (set-keymap-parent keymap parent))
-
-      ;; Do the bindings.
-      (while definitions
-        (let ((key (pop definitions)))
-          (unless definitions
-            (error "Uneven number of key/definition pairs"))
-          (let ((def (pop definitions)))
-            (if (eq key :menu)
-                (easy-menu-define nil keymap "" def)
-              (if (member key seen-keys)
-                  (error "Duplicate definition for key: %S %s" key keymap)
-                (push key seen-keys))
-              (keymap-set keymap key def)))))
-      keymap)))
-
-(compat-defmacro defvar-keymap (variable-name &rest defs) ;; <compat-tests:defvar-keymap>
-  "Define VARIABLE-NAME as a variable with a keymap definition.
-See `define-keymap' for an explanation of the keywords and KEY/DEFINITION.
-
-In addition to the keywords accepted by `define-keymap', this
-macro also accepts a `:doc' keyword, which (if present) is used
-as the variable documentation string.
-
-The `:repeat' keyword can also be specified; it controls the
-`repeat-mode' behavior of the bindings in the keymap.  When it is
-non-nil, all commands in the map will have the `repeat-map'
-symbol property.
-
-More control is available over which commands are repeatable; the
-value can also be a property list with properties `:enter' and
-`:exit', for example:
-
-     :repeat (:enter (commands ...) :exit (commands ...))
-
-`:enter' specifies the list of additional commands that only
-enter `repeat-mode'.  When the list is empty, then only the
-commands defined in the map enter `repeat-mode'.  Specifying a
-list of commands is useful when there are commands that have the
-`repeat-map' symbol property, but don't exist in this specific
-map.
-
-`:exit' is a list of commands that exit `repeat-mode'.  When the
-list is empty, no commands in the map exit `repeat-mode'.
-Specifying a list of commands is useful when those commands exist
-in this specific map, but should not have the `repeat-map' symbol
-property.
-
-\(fn VARIABLE-NAME &key DOC FULL PARENT SUPPRESS NAME PREFIX KEYMAP REPEAT &rest [KEY DEFINITION]...)"
-  (declare (indent 1))
-  (let ((opts nil)
-        doc repeat props)
-    (while (and defs
-                (keywordp (car defs))
-                (not (eq (car defs) :menu)))
-      (let ((keyword (pop defs)))
-        (unless defs
-          (error "Uneven number of keywords"))
-        (cond
-         ((eq keyword :doc) (setq doc (pop defs)))
-         ((eq keyword :repeat) (setq repeat (pop defs)))
-         (t (push keyword opts)
-            (push (pop defs) opts)))))
-    (unless (zerop (% (length defs) 2))
-      (error "Uneven number of key/definition pairs: %s" defs))
-
-    (let ((defs defs)
-          key seen-keys)
-      (while defs
-        (setq key (pop defs))
-        (pop defs)
-        (unless (eq key :menu)
-          (if (member key seen-keys)
-              (error "Duplicate definition for key '%s' in keymap '%s'"
-                     key variable-name)
-            (push key seen-keys)))))
-
-    (when repeat
-      (let ((defs defs)
-            def)
-        (dolist (def (plist-get repeat :enter))
-          (push `(put ',def 'repeat-map ',variable-name) props))
-        (while defs
-          (pop defs)
-          (setq def (pop defs))
-          (when (and (memq (car def) '(function quote))
-                     (not (memq (cadr def) (plist-get repeat :exit))))
-            (push `(put ,def 'repeat-map ',variable-name) props)))))
-
-    (let ((defvar-form
-           `(defvar ,variable-name
-              (define-keymap ,@(nreverse opts) ,@defs)
-              ,@(and doc (list doc)))))
-      (if props
-          `(progn
-             ,defvar-form
-             ,@(nreverse props))
-        defvar-form))))
-
-;;;; Defined in keymap.c
-
-(compat-defun define-key (keymap key def &optional remove) ;; <compat-tests:define-key>
-  "Handle optional argument REMOVE."
-  :extended t
-  (if (not remove)
-      (define-key keymap key def)
-    ;; Canonicalize key
-    (setq key (key-parse (key-description key)))
-    (define-key keymap key nil)
-    ;; Split M-key in ESC key
-    (setq key (mapcan (lambda (k)
-                        (if (and (integerp k) (/= (logand k ?\M-\0) 0))
-                            (list ?\e (logxor k ?\M-\0))
-                          (list k)))
-                      key))
-    ;; Delete single keys directly
-    (if (length= key 1)
-        (delete key keymap)
-      ;; Lookup submap and delete key from there
-      (let ((submap (lookup-key keymap (vconcat (butlast key)))))
-        (unless (keymapp submap)
-          (error "Not a keymap for %s" key))
-        (when (symbolp submap)
-          (setq submap (symbol-function submap)))
-        (delete (last key) submap)))
-    def))
-
-;;;; Defined in help.el
-
-(compat-defun substitute-quotes (string) ;; <compat-tests:substitute-quotes>
-  "Substitute quote characters for display.
-Each grave accent \\=` is replaced by left quote, and each
-apostrophe \\=' is replaced by right quote.  Left and right quote
-characters are specified by `text-quoting-style'."
-  (cond ((eq (text-quoting-style) 'curve)
-         (string-replace "`" "‘"
-                         (string-replace "'" "’" string)))
-        ((eq (text-quoting-style) 'straight)
-         (string-replace "`" "'" string))
-        (t string)))
-
-;;;; Defined in button.el
-
-(compat-defun button--properties (callback data help-echo) ;; <compat-tests:buttonize>
-  "Helper function."
-  (list 'font-lock-face 'button
-        'mouse-face 'highlight
-        'help-echo help-echo
-        'button t
-        'follow-link t
-        'category t
-        'button-data data
-        'keymap button-map
-        'action callback))
-
-(compat-defun buttonize (string callback &optional data help-echo) ;; <compat-tests:buttonize>
-  "Make STRING into a button and return it.
-When clicked, CALLBACK will be called with the DATA as the
-function argument.  If DATA isn't present (or is nil), the button
-itself will be used instead as the function argument.
-
-If HELP-ECHO, use that as the `help-echo' property.
-
-Also see `buttonize-region'."
-  (let ((string
-         (apply #'propertize string
-                (button--properties callback data help-echo))))
-    ;; Add the face to the end so that it can be overridden.
-    (add-face-text-property 0 (length string) 'button t string)
-    string))
-
-(compat-defun buttonize-region (start end callback &optional data help-echo) ;; <compat-tests:buttonize-region>
-  "Make the region between START and END into a button.
-When clicked, CALLBACK will be called with the DATA as the
-function argument.  If DATA isn't present (or is nil), the button
-itself will be used instead as the function argument.
-
-If HELP-ECHO, use that as the `help-echo' property.
-
-Also see `buttonize'."
-  (add-text-properties start end (button--properties callback data help-echo))
-  (add-face-text-property start end 'button t))
-
-;;;; Defined in rmc.el
-
-(compat-defun read-multiple-choice  ;; <compat-tests:read-multiple-choice>
-    (prompt choices &optional _help-str _show-help long-form)
-    "Handle LONG-FORM argument."
-  :extended t
-  (if (not long-form)
-      (read-multiple-choice prompt choices)
-    (let ((answer
-           (completing-read
-            (concat prompt " ("
-                    (mapconcat #'identity (mapcar #'cadr choices) "/")
-                    ") ")
-            (mapcar #'cadr choices) nil t)))
-      (catch 'found
-        (dolist (c choices)
-          (when (equal answer (cadr c))
-            (throw 'found c)))))))
-
-;;;; Defined in paragraphs.el
-
-(compat-defun count-sentences (start end) ;; <compat-tests:count-sentences>
-  "Count sentences in current buffer from START to END."
-  (let ((sentences 0)
-        (inhibit-field-text-motion t))
-    (save-excursion
-      (save-restriction
-        (narrow-to-region start end)
-        (goto-char (point-min))
-        (while (ignore-errors (forward-sentence))
-          (setq sentences (1+ sentences)))
-        (when (/= (skip-chars-backward " \t\n") 0)
-          (setq sentences (1- sentences)))
-        sentences))))
-
-;;;; Defined in cl-lib.el
-
-(compat-defun cl-constantly (value) ;; <compat-tests:cl-constantly>
-  "Return a function that takes any number of arguments, but returns VALUE."
-  :feature cl-lib
-  (lambda (&rest _) value))
-
-;;;; Defined in cl-macs.el
-
-(compat-defmacro cl-with-gensyms (names &rest body) ;; <compat-tests:cl-with-gensyms>
-  "Bind each of NAMES to an uninterned symbol and evaluate BODY."
-  ;; No :feature since macro is autoloaded
-  (declare (debug (sexp body)) (indent 1))
-  `(let ,(cl-loop for name in names collect
-                  `(,name (gensym (symbol-name ',name))))
-     ,@body))
-
-(compat-defmacro cl-once-only (names &rest body) ;; <compat-tests:cl-once-only>
-  "Generate code to evaluate each of NAMES just once in BODY.
-
-This macro helps with writing other macros.  Each of names is
-either (NAME FORM) or NAME, which latter means (NAME NAME).
-During macroexpansion, each NAME is bound to an uninterned
-symbol.  The expansion evaluates each FORM and binds it to the
-corresponding uninterned symbol.
-
-For example, consider this macro:
-
-    (defmacro my-cons (x)
-      (cl-once-only (x)
-        \\=`(cons ,x ,x)))
-
-The call (my-cons (pop y)) will expand to something like this:
-
-    (let ((g1 (pop y)))
-      (cons g1 g1))
-
-The use of `cl-once-only' ensures that the pop is performed only
-once, as intended.
-
-See also `macroexp-let2'."
-  ;; No :feature since macro is autoloaded
-  (declare (debug (sexp body)) (indent 1))
-  (setq names (mapcar #'ensure-list names))
-  (let ((our-gensyms (cl-loop for _ in names collect (gensym))))
-    `(let ,(cl-loop for sym in our-gensyms collect `(,sym (gensym)))
-       `(let ,(list
-               ,@(cl-loop for name in names for gensym in our-gensyms
-                          for to-eval = (or (cadr name) (car name))
-                          collect ``(,,gensym ,,to-eval)))
-          ,(let ,(cl-loop for name in names for gensym in our-gensyms
-                          collect `(,(car name) ,gensym))
-             ,@body)))))
-
-;;;; Defined in ert-x.el
-
-(compat-defmacro ert-with-temp-file (name &rest body) ;; <compat-tests:ert-with-temp-file>
-  "Bind NAME to the name of a new temporary file and evaluate BODY.
-Delete the temporary file after BODY exits normally or
-non-locally.  NAME will be bound to the file name of the temporary
-file.
-
-The following keyword arguments are supported:
-
-:prefix STRING  If non-nil, pass STRING to `make-temp-file' as
-                the PREFIX argument.  Otherwise, use the value of
-                `ert-temp-file-prefix'.
-
-:suffix STRING  If non-nil, pass STRING to `make-temp-file' as the
-                SUFFIX argument.  Otherwise, use the value of
-                `ert-temp-file-suffix'; if the value of that
-                variable is nil, generate a suffix based on the
-                name of the file that `ert-with-temp-file' is
-                called from.
-
-:text STRING    If non-nil, pass STRING to `make-temp-file' as
-                the TEXT argument.
-
-:buffer SYMBOL  Open the temporary file using `find-file-noselect'
-                and bind SYMBOL to the buffer.  Kill the buffer
-                after BODY exits normally or non-locally.
-
-:coding CODING  If non-nil, bind `coding-system-for-write' to CODING
-                when executing BODY.  This is handy when STRING includes
-                non-ASCII characters or the temporary file must have a
-                specific encoding or end-of-line format.
-
-See also `ert-with-temp-directory'."
-  :feature ert-x
-  (declare (indent 1) (debug (symbolp body)))
-  (cl-check-type name symbol)
-  (let (keyw prefix suffix directory text extra-keywords buffer coding)
-    (while (keywordp (setq keyw (car body)))
-      (setq body (cdr body))
-      (pcase keyw
-        (:prefix (setq prefix (pop body)))
-        (:suffix (setq suffix (pop body)))
-        ;; This is only for internal use by `ert-with-temp-directory'
-        ;; and is therefore not documented.
-        (:directory (setq directory (pop body)))
-        (:text (setq text (pop body)))
-        (:buffer (setq buffer (pop body)))
-        (:coding (setq coding (pop body)))
-        (_ (push keyw extra-keywords) (pop body))))
-    (when extra-keywords
-      (error "Invalid keywords: %s" (mapconcat #'symbol-name extra-keywords " ")))
-    (let ((temp-file (make-symbol "temp-file"))
-          (prefix (or prefix "emacs-test-"))
-          (suffix (or suffix
-                      (thread-last
-                        (file-name-base (or (macroexp-file-name) buffer-file-name))
-                        (replace-regexp-in-string (rx string-start
-                                                      (group (+? not-newline))
-                                                      (regexp "-?tests?")
-                                                      string-end)
-                                                  "\\1")
-                        (concat "-")))))
-      `(let* ((coding-system-for-write ,(or coding coding-system-for-write))
-              (,temp-file (,(if directory 'file-name-as-directory 'identity)
-                           (,(if (fboundp 'compat--make-temp-file)
-                                 'compat--make-temp-file 'make-temp-file)
-                            ,prefix ,directory ,suffix ,text)))
-              (,name ,(if directory
-                          `(file-name-as-directory ,temp-file)
-                        temp-file))
-              ,@(when buffer
-                  (list `(,buffer (find-file-literally ,temp-file)))))
-         (unwind-protect
-             (progn ,@body)
-           (ignore-errors
-             ,@(when buffer
-                 (list `(with-current-buffer ,buffer
-                          (set-buffer-modified-p nil))
-                       `(kill-buffer ,buffer))))
-           (ignore-errors
-             ,(if directory
-                  `(delete-directory ,temp-file :recursive)
-                `(delete-file ,temp-file))))))))
-
-(compat-defmacro ert-with-temp-directory (name &rest body) ;; <compat-tests:ert-with-temp-directory>
-  "Bind NAME to the name of a new temporary directory and evaluate BODY.
-Delete the temporary directory after BODY exits normally or
-non-locally.
-
-NAME is bound to the directory name, not the directory file
-name.  (In other words, it will end with the directory delimiter;
-on Unix-like systems, it will end with \"/\".)
-
-The same keyword arguments are supported as in
-`ert-with-temp-file' (which see), except for :text."
-  :feature ert-x
-  (declare (indent 1) (debug (symbolp body)))
-  (let ((tail body) keyw)
-    (while (keywordp (setq keyw (car tail)))
-      (setq tail (cddr tail))
-      (pcase keyw (:text (error "Invalid keyword for directory: :text")))))
-  `(ert-with-temp-file ,name
-     :directory t
-     ,@body))
-
-;;;; Defined in wid-edit.el
-
-(compat-guard (not (fboundp 'widget-key-validate)) ;; <compat-tests:widget-key>
-  :feature wid-edit
-  (defvar widget-key-prompt-value-history nil
-    "History of input to `widget-key-prompt-value'.")
-  (define-widget 'key 'editable-field
-    "A key sequence."
-    :prompt-value 'widget-field-prompt-value
-    :match 'widget-key-valid-p
-    :format "%{%t%}: %v"
-    :validate 'widget-key-validate
-    :keymap widget-key-sequence-map
-    :help-echo "C-q: insert KEY, EVENT, or CODE; RET: enter value"
-    :tag "Key")
-  (defun widget-key-valid-p (_widget value)
-    (key-valid-p value))
-  (defun widget-key-validate (widget)
-    (unless (and (stringp (widget-value widget))
-                 (key-valid-p (widget-value widget)))
-      (widget-put widget :error (format "Invalid key: %S"
-                                        (widget-value widget)))
-      widget)))
-
-(provide 'compat-29)
-;;; compat-29.el ends here
diff --git a/elpa/compat-29.1.4.1/compat-autoloads.el b/elpa/compat-29.1.4.1/compat-autoloads.el
deleted file mode 100644 (file)
index 2044a1b..0000000
+++ /dev/null
@@ -1,34 +0,0 @@
-;;; compat-autoloads.el --- automatically extracted autoloads  -*- lexical-binding: t -*-
-;;
-;;; Code:
-
-(add-to-list 'load-path (directory-file-name
-                         (or (file-name-directory #$) (car load-path))))
-
-\f
-;;;### (autoloads nil "compat" "compat.el" (0 0 0 0))
-;;; Generated autoloads from compat.el
-
-(register-definition-prefixes "compat" '("compat-"))
-
-;;;***
-\f
-;;;### (autoloads nil "compat-macs" "compat-macs.el" (0 0 0 0))
-;;; Generated autoloads from compat-macs.el
-
-(register-definition-prefixes "compat-macs" '("compat-"))
-
-;;;***
-\f
-;;;### (autoloads nil nil ("compat-25.el" "compat-26.el" "compat-27.el"
-;;;;;;  "compat-28.el" "compat-29.el" "compat-pkg.el") (0 0 0 0))
-
-;;;***
-\f
-;; Local Variables:
-;; version-control: never
-;; no-byte-compile: t
-;; no-update-autoloads: t
-;; coding: utf-8
-;; End:
-;;; compat-autoloads.el ends here
diff --git a/elpa/compat-29.1.4.1/compat-macs.el b/elpa/compat-29.1.4.1/compat-macs.el
deleted file mode 100644 (file)
index f34cb0d..0000000
+++ /dev/null
@@ -1,266 +0,0 @@
-;;; compat-macs.el --- Compatibility Macros -*- lexical-binding: t; no-byte-compile: t; -*-
-
-;; Copyright (C) 2021-2023 Free Software Foundation, Inc.
-
-;; This program is free software; you can redistribute it and/or modify
-;; it under the terms of the GNU General Public License as published by
-;; the Free Software Foundation, either version 3 of the License, or
-;; (at your option) any later version.
-
-;; This program is distributed in the hope that it will be useful,
-;; but WITHOUT ANY WARRANTY; without even the implied warranty of
-;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-;; GNU General Public License for more details.
-
-;; You should have received a copy of the GNU General Public License
-;; along with this program.  If not, see <https://www.gnu.org/licenses/>.
-
-;;; Commentary:
-
-;; This file provides *internal* macros, which are used by Compat to
-;; facilitate the definition of compatibility functions, macros and
-;; variables.  The `compat-macs' feature should never be loaded at
-;; runtime in your Emacs and will only be used during byte
-;; compilation.  Every definition provided here should be considered
-;; internal and may change any time between Compat releases.
-
-;;; Code:
-
-;; We always require subr-x at compile time for the fboundp check
-;; since definitions have been moved around. The cl-lib macros are
-;; needed by compatibility definitions.
-(require 'subr-x)
-(require 'cl-lib)
-
-(defvar compat-macs--version nil
-  "Version of the currently defined compatibility definitions.")
-
-(defun compat-macs--strict (cond &rest error)
-  "Assert strict COND, otherwise fail with ERROR."
-  (when (bound-and-true-p compat-strict)
-    (apply #'compat-macs--assert cond error)))
-
-(defun compat-macs--assert (cond &rest error)
-  "Assert COND, otherwise fail with ERROR."
-  (unless cond (apply #'error error)))
-
-(defun compat-macs--docstring (type name docstring)
-  "Format DOCSTRING for NAME of TYPE.
-Prepend compatibility notice to the actual documentation string."
-  (with-temp-buffer
-    (insert
-     (format
-      "[Compatibility %s for `%s', defined in Emacs %s. \
-See (compat) Emacs %s' for more details.]\n\n%s"
-      type name compat-macs--version compat-macs--version docstring))
-    (let ((fill-column 80))
-      (fill-region (point-min) (point-max)))
-    (buffer-string)))
-
-(defun compat-macs--check-attributes (attrs preds)
-  "Check ATTRS given PREDS predicate plist and return rest."
-  (while (keywordp (car attrs))
-    (compat-macs--assert (cdr attrs) "Attribute list length is odd")
-    (compat-macs--assert (let ((p (plist-get preds (car attrs))))
-                           (and p (or (eq p t) (funcall p (cadr attrs)))))
-                         "Invalid attribute %s" (car attrs))
-    (setq attrs (cddr attrs)))
-  attrs)
-
-(defun compat-macs--guard (attrs preds fun)
-  "Guard compatibility definition generation.
-The version constraints specified by ATTRS are checked.  PREDS is
-a plist of predicates for arguments which are passed to FUN."
-  (declare (indent 2))
-  (compat-macs--assert compat-macs--version "No `compat-version' was declared")
-  (let* ((body (compat-macs--check-attributes
-                attrs `(,@preds :feature symbolp)))
-         (feature (plist-get attrs :feature))
-         (attrs `(:body ,body ,@attrs))
-         args)
-    ;; Require feature at compile time
-    (when feature
-      (compat-macs--assert (not (eq feature 'subr-x)) "Invalid feature subr-x")
-      (require feature))
-    ;; The current Emacs must be older than the currently declared version.
-    (when (version< emacs-version compat-macs--version)
-      (while preds
-        (push (plist-get attrs (car preds)) args)
-        (setq preds (cddr preds)))
-      (setq body (apply fun (nreverse args)))
-      (if (and feature body)
-          `(with-eval-after-load ',feature ,@body)
-        (macroexp-progn body)))))
-
-(defun compat-macs--defun (type name arglist docstring rest)
-  "Define function NAME of TYPE with ARGLIST and DOCSTRING.
-REST are attributes and the function BODY."
-  (compat-macs--guard
-     rest (list :extended (lambda (x) (or (booleanp x) (version-to-list x)))
-                :obsolete (lambda (x) (or (booleanp x) (stringp x)))
-                :body t)
-    (lambda (extended obsolete body)
-      (when (stringp extended)
-        (compat-macs--assert
-         (and (version< extended compat-macs--version) (version< "24.4" extended))
-         "Invalid :extended version %s for %s %s" extended type name)
-        (setq extended (version<= extended emacs-version)))
-      (compat-macs--strict (eq extended (fboundp name))
-                           "Wrong :extended flag for %s %s" type name)
-      ;; Remove unsupported declares.  It might be possible to set these
-      ;; properties otherwise.  That should be looked into and implemented
-      ;; if it is the case.
-      (when (and (listp (car-safe body)) (eq (caar body) 'declare))
-        (when (<= emacs-major-version 25)
-          (delq (assq 'side-effect-free (car body)) (car body))
-          (delq (assq 'pure (car body)) (car body))))
-      ;; Use `:extended' name if the function is already defined.
-      (let* ((defname (if (and extended (fboundp name))
-                          (intern (format "compat--%s" name))
-                        name))
-             (def `(,(if (memq '&key arglist)
-                         (if (eq type 'macro) 'cl-defmacro 'cl-defun)
-                       (if (eq type 'macro) 'defmacro 'defun))
-                    ,defname ,arglist
-                    ,(compat-macs--docstring type name docstring)
-                    ,@body)))
-        `(,@(if (eq defname name)
-                ;; An additional fboundp check is performed at runtime to make
-                ;; sure that we never redefine an existing definition if Compat
-                ;; is loaded on a newer Emacs version.  Declare the function,
-                ;; such that the byte compiler does not complain about possibly
-                ;; missing functions at runtime. The warnings are generated due
-                ;; to the fboundp check.
-                `((declare-function ,name nil)
-                  (unless (fboundp ',name) ,def))
-              (list def))
-          ,@(when obsolete
-              `((make-obsolete
-                 ',defname ,(if (stringp obsolete) obsolete "No substitute")
-                 ,compat-macs--version))))))))
-
-(defmacro compat-guard (cond &rest rest)
-  "Guard definition with a runtime COND and a version check.
-The runtime condition must make sure that no definition is
-overriden.  REST is an attribute plist followed by the definition
-body.  The attributes specify the conditions under which the
-definition is generated.
-
-- :feature :: Wrap the definition with `with-eval-after-load' for
-  the given feature."
-  (declare (debug ([&rest keywordp sexp] def-body))
-           (indent 1))
-  (compat-macs--guard rest '(:body t)
-    (lambda (body)
-      (compat-macs--assert body "The guarded body is empty")
-      (if (eq cond t)
-          body
-        (compat-macs--strict (eval cond t) "Guard %S failed" cond)
-        `((when ,cond ,@body))))))
-
-(defmacro compat-defalias (name def &rest attrs)
-  "Define compatibility alias NAME as DEF.
-ATTRS is a plist of attributes, which specify the conditions
-under which the definition is generated.
-
-- :obsolete :: Mark the alias as obsolete if t.
-
-- :feature :: See `compat-guard'."
-  (declare (debug (name symbolp [&rest keywordp sexp])))
-  (compat-macs--guard attrs '(:obsolete booleanp)
-    (lambda (obsolete)
-      (compat-macs--strict (not (fboundp name)) "%s already defined" name)
-      ;; The fboundp check is performed at runtime to make sure that we never
-      ;; redefine an existing definition if Compat is loaded on a newer Emacs
-      ;; version.
-      `((unless (fboundp ',name)
-          (defalias ',name ',def
-            ,(compat-macs--docstring 'function name
-                                (get name 'function-documentation)))
-          ,@(when obsolete
-              `((make-obsolete ',name ',def ,compat-macs--version))))))))
-
-(defmacro compat-defun (name arglist docstring &rest rest)
-  "Define compatibility function NAME with arguments ARGLIST.
-The function must be documented in DOCSTRING.  REST is an
-attribute plist followed by the function body.  The attributes
-specify the conditions under which the definition is generated.
-
-- :extended :: Mark the function as extended if t.  The function
-  must be called explicitly via `compat-call'.  This attribute
-  should be used for functions which extend already existing
-  functions, e.g., functions which changed their calling
-  convention or their behavior.  The value can also be a version
-  string, which specifies the Emacs version when the original
-  version of the function was introduced.
-
-- :obsolete :: Mark the function as obsolete if t, can be a
-  string describing the obsoletion.
-
-- :feature :: See `compat-guard'."
-  (declare (debug (&define name (&rest symbolp)
-                           stringp
-                           [&rest keywordp sexp]
-                           def-body))
-           (doc-string 3) (indent 2))
-  (compat-macs--defun 'function name arglist docstring rest))
-
-(defmacro compat-defmacro (name arglist docstring &rest rest)
-  "Define compatibility macro NAME with arguments ARGLIST.
-The macro must be documented in DOCSTRING.  REST is an attribute
-plist followed by the macro body.  See `compat-defun' for
-details."
-  (declare (debug compat-defun) (doc-string 3) (indent 2))
-  (compat-macs--defun 'macro name arglist docstring rest))
-
-(defmacro compat-defvar (name initval docstring &rest attrs)
-  "Define compatibility variable NAME with initial value INITVAL.
-The variable must be documented in DOCSTRING.  ATTRS is a plist
-of attributes, which specify the conditions under which the
-definition is generated.
-
-- :constant :: Mark the variable as constant if t.
-
-- :local :: Make the variable buffer-local if t.  If the value is
-  `permanent' make the variable additionally permanently local.
-
-- :obsolete :: Mark the variable as obsolete if t, can be a
-  string describing the obsoletion.
-
-- :feature :: See `compat-guard'."
-  (declare (debug (name form stringp [&rest keywordp sexp]))
-           (doc-string 3) (indent 2))
-  (compat-macs--guard
-      attrs (list :constant #'booleanp
-                  :local (lambda (x) (memq x '(nil t permanent)))
-                  :obsolete (lambda (x) (or (booleanp x) (stringp x))))
-    (lambda (constant local obsolete)
-      (compat-macs--strict (not (boundp name)) "%s already defined" name)
-      (compat-macs--assert (not (and constant local)) "Both :constant and :local")
-      ;; The boundp check is performed at runtime to make sure that we never
-      ;; redefine an existing definition if Compat is loaded on a newer Emacs
-      ;; version.
-      `((unless (boundp ',name)
-          (,(if constant 'defconst 'defvar)
-           ,name ,initval
-           ,(compat-macs--docstring 'variable name docstring))
-          ,@(when obsolete
-              `((make-obsolete-variable
-                 ',name ,(if (stringp obsolete) obsolete "No substitute")
-                 ,compat-macs--version))))
-        ,@(and local `((make-variable-buffer-local ',name)))
-        ,@(and (eq local 'permanent) `((put ',name 'permanent-local t)))))))
-
-(defmacro compat-version (version)
-  "Set the Emacs version that is currently being handled to VERSION."
-  (setq compat-macs--version version)
-  nil)
-
-(defmacro compat-require (feature version)
-  "Require FEATURE if the Emacs version is less than VERSION."
-  (when (version< emacs-version version)
-    (require feature)
-    `(require ',feature)))
-
-(provide 'compat-macs)
-;;; compat-macs.el ends here
diff --git a/elpa/compat-29.1.4.1/compat-pkg.el b/elpa/compat-29.1.4.1/compat-pkg.el
deleted file mode 100644 (file)
index ce297f2..0000000
+++ /dev/null
@@ -1,2 +0,0 @@
-;; Generated package description from compat.el  -*- no-byte-compile: t -*-
-(define-package "compat" "29.1.4.1" "Emacs Lisp Compatibility Library" '((emacs "24.4") (seq "2.3")) :commit "cb09942868d50e654f159f9614fe3f22af96e547" :authors '(("Philip Kaludercic <philipkNOSPAMposteo.net>, Daniel Mendler" . "mailNOSPAMdaniel-mendler.de")) :maintainer '("Daniel Mendler <mailNOSPAMdaniel-mendler.de>, Compat Development" . "~pkal/compat-develNOSPAMlists.sr.ht") :keywords '("lisp") :url "https://github.com/emacs-compat/compat")
diff --git a/elpa/compat-29.1.4.1/compat.el b/elpa/compat-29.1.4.1/compat.el
deleted file mode 100644 (file)
index d318489..0000000
+++ /dev/null
@@ -1,93 +0,0 @@
-;;; compat.el --- Emacs Lisp Compatibility Library -*- lexical-binding: t; -*-
-
-;; Copyright (C) 2021-2023 Free Software Foundation, Inc.
-
-;; Author: Philip Kaludercic <philipkNOSPAMposteo.net>, Daniel Mendler <mailNOSPAMdaniel-mendler.de>
-;; Maintainer: Daniel Mendler <mailNOSPAMdaniel-mendler.de>, Compat Development <~pkal/compat-develNOSPAMlists.sr.ht>
-;; Version: 29.1.4.1
-;; URL: https://github.com/emacs-compat/compat
-;; Package-Requires: ((emacs "24.4") (seq "2.3"))
-;; Keywords: lisp
-
-;; This program is free software; you can redistribute it and/or modify
-;; it under the terms of the GNU General Public License as published by
-;; the Free Software Foundation, either version 3 of the License, or
-;; (at your option) any later version.
-
-;; This program is distributed in the hope that it will be useful,
-;; but WITHOUT ANY WARRANTY; without even the implied warranty of
-;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-;; GNU General Public License for more details.
-
-;; You should have received a copy of the GNU General Public License
-;; along with this program.  If not, see <https://www.gnu.org/licenses/>.
-
-;;; Commentary:
-
-;; Compat is the Elisp forwards compatibility library, which provides
-;; definitions introduced in newer Emacs versions.  The definitions
-;; are only installed if necessary for your current Emacs version.  If
-;; Compat is compiled on a recent version of Emacs, all of the
-;; definitions are disabled at compile time, such that no negative
-;; performance impact is incurred.  The provided compatibility
-;; implementations of functions and macros are at least subsets of the
-;; actual implementations.  Be sure to read the documentation string
-;; and the Compat manual.
-;;
-;; Not every function provided in newer versions of Emacs is provided
-;; here.  Some depend on new features from the C core, others cannot
-;; be implemented to a meaningful degree.  Please consult the Compat
-;; manual for details regarding the usage of the Compat library and
-;; the provided functionality.
-
-;; The main audience for this library are not regular users, but
-;; package maintainers.  Therefore no commands, user-facing modes or
-;; user options are implemented here.
-
-;;; Code:
-
-;; Ensure that the newest compatibility layer is required at compile
-;; time and runtime, but only if needed.
-(eval-when-compile
-  (defmacro compat--maybe-require-29 ()
-    (when (< emacs-major-version 29)
-      (require 'compat-29)
-      '(require 'compat-29))))
-(compat--maybe-require-29)
-
-;;;; Macros for extended compatibility function calls
-
-(defmacro compat-function (fun)
-  "Return compatibility function symbol for FUN.
-
-If the Emacs version provides a sufficiently recent version of
-FUN, the symbol FUN is returned itself.  Otherwise the macro
-returns the symbol of a compatibility function which supports the
-behavior and calling convention of the current stable Emacs
-version.  For example Compat 29.1 will provide compatibility
-functions which implement the behavior and calling convention of
-Emacs 29.1.
-
-See also `compat-call' to directly call compatibility functions."
-  (let ((compat (intern (format "compat--%s" fun))))
-    `#',(if (fboundp compat) compat fun)))
-
-(defmacro compat-call (fun &rest args)
-  "Call compatibility function or macro FUN with ARGS.
-
-A good example function is `plist-get' which was extended with an
-additional predicate argument in Emacs 29.1.  The compatibility
-function, which supports this additional argument, can be
-obtained via (compat-function plist-get) and called
-via (compat-call plist-get plist prop predicate).  It is not
-possible to directly call (plist-get plist prop predicate) on
-Emacs older than 29.1, since the original `plist-get' function
-does not yet support the predicate argument.  Note that the
-Compat library never overrides existing functions.
-
-See also `compat-function' to lookup compatibility functions."
-  (let ((compat (intern (format "compat--%s" fun))))
-    `(,(if (fboundp compat) compat fun) ,@args)))
-
-(provide 'compat)
-;;; compat.el ends here
diff --git a/elpa/compat-29.1.4.1/compat.info b/elpa/compat-29.1.4.1/compat.info
deleted file mode 100644 (file)
index fcd83e1..0000000
+++ /dev/null
@@ -1,2951 +0,0 @@
-This is doc0jZUSv.info, produced by makeinfo version 6.7 from
-compat.texi.
-
-Copyright © 2022-2023 Free Software Foundation, Inc.
-
-     Permission is granted to copy, distribute and/or modify this
-     document under the terms of the GNU Free Documentation License,
-     Version 1.3 or any later version published by the Free Software
-     Foundation; with no Invariant Sections, with the Front-Cover Texts
-     being “A GNU Manual,” and with the Back-Cover Texts as in (a)
-     below.  A copy of the license is included in the section entitled
-     “GNU Free Documentation License.”
-
-     (a) The FSF’s Back-Cover Text is: “You have the freedom to copy and
-     modify this GNU manual.”
-
-INFO-DIR-SECTION Emacs
-START-INFO-DIR-ENTRY
-* Compat: (compat).     Compatibility Library for Emacs Lisp.
-END-INFO-DIR-ENTRY
-
-\1f
-File: doc0jZUSv.info,  Node: Top,  Next: Introduction,  Up: (dir)
-
-"Compat" Manual
-***************
-
-This manual documents the usage of the "Compat" Emacs lisp library, the
-forward-compatibility library for Emacs Lisp, corresponding to version
-29.1.4.1.
-
-   Copyright © 2022-2023 Free Software Foundation, Inc.
-
-     Permission is granted to copy, distribute and/or modify this
-     document under the terms of the GNU Free Documentation License,
-     Version 1.3 or any later version published by the Free Software
-     Foundation; with no Invariant Sections, with the Front-Cover Texts
-     being “A GNU Manual,” and with the Back-Cover Texts as in (a)
-     below.  A copy of the license is included in the section entitled
-     “GNU Free Documentation License.”
-
-     (a) The FSF’s Back-Cover Text is: “You have the freedom to copy and
-     modify this GNU manual.”
-
-* Menu:
-
-* Introduction::
-* Support::
-* Development::
-* Function Index::
-* Variable Index::
-
-— The Detailed Node Listing —
-
-Introduction
-
-* Overview::
-* Usage::
-* Limitations::
-
-Support
-
-* Emacs 25.1::                   Compatibility support for Emacs 25.1
-* Emacs 26.1::                   Compatibility support for Emacs 26.1
-* Emacs 27.1::                   Compatibility support for Emacs 27.1
-* Emacs 28.1::                   Compatibility support for Emacs 28.1
-* Emacs 29.1::                   Compatibility support for Emacs 29.1
-
-
-\1f
-File: doc0jZUSv.info,  Node: Introduction,  Next: Support,  Prev: Top,  Up: Top
-
-1 Introduction
-**************
-
-* Menu:
-
-* Overview::
-* Usage::
-* Limitations::
-
-\1f
-File: doc0jZUSv.info,  Node: Overview,  Next: Usage,  Up: Introduction
-
-1.1 Overview
-============
-
-The objective of Compat is to provide "forwards compatibility" library
-for Emacs Lisp.  By using Compat, an Elisp package does not have to make
-the decision to either use new and useful functionality or support old
-versions of Emacs.
-
-   The library provides support back until Emacs 24.4.  The intended
-audience are package developers that are interested in using newer
-developments, without having to break compatibility.
-
-\1f
-File: doc0jZUSv.info,  Node: Usage,  Next: Limitations,  Prev: Overview,  Up: Introduction
-
-1.2 Usage
-=========
-
-The intended use-case for this library is for package developers to add
-as a dependency in the header:
-
-     ;; Package-Requires: ((emacs "24.4") (compat "29.1.4.1"))
-
-   There is no need to depend on ‘emacs’ 24.4 specifically.  One can
-choose to any newer version, if features not provided by Compat
-necessitate it, for example bug fixes or UI improvements.
-
-   In any file where compatibility forms are used, a
-
-     (require 'compat)
-
-   should be added early on.  In packages which are part of Emacs itself
-and which want to take advantage of Compat, the ‘noerror’ flag should be
-specified: ‘(require 'compat nil 'noerror)’.  In the future a minimal
-version of Compat may be added to the Emacs core, such that the
-‘noerror’ flag will not be necessary anymore.
-
-   This will load all necessary Compat definitions.  Compat also loads
-the ‘seq’ library which is preloaded by default on Emacs 29.  Note that
-if Compat is installed on a recent version of Emacs, all of the
-definitions are disabled at compile time, such that no negative
-performance impact is incurred.
-
-   Note that Compat provides replacement functions with extended
-functionality for functions that are already defined (‘sort’, ‘assoc’,
-...).  These functions may have changed their calling convention
-(additional optional arguments) or may have changed their behavior.
-These functions must be looked up explicitly with ‘compat-function’ or
-called explicitly with ‘compat-call’.  We call them “Extended
-Definitions”.  In contrast, newly “Added Definitions” can be called as
-usual.
-
-     (compat-call assoc key alist testfn) ;; Call extended `assoc'
-     (mapcan fun seq)                     ;; Call newly added `mapcan'
-
- -- Macro: compat-call fun &rest args
-     This macro calls the compatibility function FUN with ARGS.  Many
-     functions provided by Compat can be called directly without this
-     macro.  However in the case where Compat provides an alternative
-     version of an existing function, the function call has to go
-     through ‘compat-call’.  This happens for example when the calling
-     convention of a function has changed.
-
- -- Macro: compat-function fun
-     This macro returns the compatibility function symbol for FUN.  See
-     ‘compat-call’ for a more convenient macro to directly call
-     compatibility functions.
-
-   If Compat is used in core packages, where Compat must be required
-currently with the ‘noerror’ flag, the macros ‘compat-call’ and
-‘compat-function’ ar not available.  In the future the macros could be
-added to subr.  Alternatively a minimal version of compat.el could be
-added to the core.  For now it is necessary to replicate the definition
-of the macros within core packages.  For example the package ERC defines
-its own macro ‘erc-compat-call’, which replicates the Compat definition
-precisely.
-
-   This design has been chosen since Compat does not advise or override
-existing functions.  Generally Compat is written in defensive style
-which is supposed to reduce potential breakage, and to increase the
-chances of staying binary compatible across releases.  The extensive
-test coverage ensures that we can maintain high quality, which is
-crucial for Compat which is not restricted to a namespace like usual
-libraries.
-
-   If you intend to use a compatibility function in your code it is
-recommended that you take a look at the test suite ‘compat-tests.el’.
-There you can see the supported calling conventions, which are
-guaranteed to work on the supported Emacs versions.  We ensure this
-using continuous integration.  All functions provided by Compat are
-covered by the test suite.  There is a link to the corresponding test on
-the first line of each definition.
-
-   You may want to subscribe to the compat-announce
-(https://lists.sr.ht/~pkal/compat-announce) mailing list to be notified
-when new versions are released or relevant changes are made.  We also
-provide a development mailing list
-(https://lists.sr.ht/~pkal/compat-devel) (~pkal/compat-develNOSPAMlists.sr.ht
-<~pkal/compat-develNOSPAMlists.sr.ht>).
-
-\1f
-File: doc0jZUSv.info,  Node: Limitations,  Prev: Usage,  Up: Introduction
-
-1.3 Limitations
-===============
-
-The Compat library has a number of limitations.  Complete backwards
-compatibility cannot be provided due to the scope of Compat and for
-technical reasons.  The scope is intentionally restricted in order to
-limit the size of Compat and to ensure that the library stays
-maintainable.
-
-   Emacs version 24.4 is chosen as the oldest version supported by
-Compat, since Elisp has seen significant changes at that version.  On
-the library level, subr-x was introduced in 24.4.  Most popular Emacs
-packages already require 24.4 or even newer versions of Emacs.
-Supporting for more historical Emacs versions would complicate
-maintainance significantly while only few packages and users would
-benefit.
-
-   Below we list a number of reasons why certain functionality cannot be
-provided.  Note that in some special cases exceptions can be made and
-functions can still be added to Compat even if they satisfy the criteria
-from the list.  In case you miss functionality which you think should
-belong here, a *note report: Development. would be much appreciated.
-
-   • The additional functionality is a command or a user-facing minor or
-     major mode.  Compat is limited to functionality on the “library
-     level”.  Generally functions provided by Compat are
-     non-interactive, such that the user interface (M-x) is unaffected
-     by the presence of Compat.
-
-   • The function is not useful for package authors or not intended to
-     be used by packages, but is only useful on the configuration level.
-     The macro ‘setopt’ is such an example.
-
-   • Private (double dashed) functions are not ported back.  If Compat
-     includes some private functions, they are meant purely for internal
-     usage.
-
-   • The added or extended function belongs to the “application level”
-     and not the “library level”.  Features which are not preloaded
-     often belong to the “application level”.  Application examples are
-     programming modes or modes like Dired, IRC and Gnus.  If these
-     modes are extended with new functions, these are not ported back.
-
-   • An existing function or macro was extended by some new
-     functionality.  To support these cases, the function or macro would
-     have to be advised.  Since this is invasive and adds significant
-     overhead, even when the new feature is not used, Compat does not
-     use advices.  As a compromise, compatibility functions and macros
-     with a changed calling convention or behavior can be accessed via
-     the ‘compat-function’ and ‘compat-call’ macros.  In this manual we
-     call such definitions “Extended Definitions”.  An example is the
-     function ‘plist-get’.  Note that extended functions are subject to
-     closer scrutiny, since their usage via ‘compat-call’ is not
-     completely painless.  If a particular extended function does not
-     see much usage or the extension yields only marginal benefits, we
-     may not provide it as part of Compat.
-
-   • Bug fixes are usually not ported back as part of Compat.  Sometimes
-     library functions show wrong behavior for edge cases.  In those
-     cases Compat could in principle provide a compatibility function
-     which is invoked via ‘compat-call’.  Such extended definitions
-     would increase the maintainance burden of Compat.  At the same time
-     the benefits would be small given that Compat does not override
-     existing definitions.
-
-   • The definition belongs to an Emacs core package, which is also
-     distributed via ELPA. Compat does not have to provide backward
-     compatibility for core packages since the updated package can be
-     installed directly from ELPA. Examples include the libraries xref,
-     project, seq, map and transient.
-
-   • New functionality depends on an entire new, non-trivial core
-     library, which is infeasible to duplicate within Compat.  If a
-     backport of such a library is required, the preferred approach is
-     to either release the library separately on GNU ELPA as a core
-     package or as a separately maintained GNU ELPA package.  An example
-     is the iso8601 library.
-
-   • New functionality was implemented in the C core, or depends on
-     external libraries that cannot be reasonably duplicated in the
-     scope of a compatibility library.  Sometimes new functions on the C
-     level rely on internal data structures, which we cannot access,
-     rendering a backport impossible.  For example a missing libxml
-     cannot be emulated.
-
-   • The semantics of Elisp changed on a deep level.  For example the
-     addition of Bigint support in Emacs 27.1 cannot be replicated on
-     the level of Compat.
-
-\1f
-File: doc0jZUSv.info,  Node: Support,  Next: Development,  Prev: Introduction,  Up: Top
-
-2 Support
-*********
-
-This section goes into the features that Compat manages and doesn’t
-manage to provide for each Emacs version.
-
-* Menu:
-
-* Emacs 25.1::                   Compatibility support for Emacs 25.1
-* Emacs 26.1::                   Compatibility support for Emacs 26.1
-* Emacs 27.1::                   Compatibility support for Emacs 27.1
-* Emacs 28.1::                   Compatibility support for Emacs 28.1
-* Emacs 29.1::                   Compatibility support for Emacs 29.1
-
-\1f
-File: doc0jZUSv.info,  Node: Emacs 25.1,  Next: Emacs 26.1,  Up: Support
-
-2.1 Emacs 25.1
-==============
-
-2.1.1 Added Definitions
------------------------
-
-The following functions and macros are implemented in Emacs 25.1.  These
-functions are made available by Compat on Emacs versions older than
-25.1.
-
- -- User Option: text-quoting-style
-     The value of this user option is a symbol that specifies the style
-     Emacs should use for single quotes in the wording of help and
-     messages.  If the option’s value is ‘curve’, the style is ‘like
-     this’ with curved single quotes.  If the value is ‘straight’, the
-     style is 'like this' with straight apostrophes.  If the value is
-     ‘grave’, quotes are not translated and the style is `like this'
-     with grave accent and apostrophe, the standard style before Emacs
-     version 25.  The default value ‘nil’ acts like ‘curve’ if curved
-     single quotes seem to be displayable, and like ‘grave’ otherwise.
-
-     This option is useful on platforms that have problems with curved
-     quotes.  You can customize it freely according to your personal
-     preference.
-
- -- Function: region-bounds
-     Return the boundaries of the region.  Value is a list of one or
-     more cons cells of the form ‘(start . end)’.  It will have more
-     than one cons cell when the region is non-contiguous, see
-     ‘region-noncontiguous-p’ and ‘extract-rectangle-bounds’.
-
- -- Function: region-noncontiguous-p
-     Return non-nil if the region contains several pieces.  An example
-     is a rectangular region handled as a list of separate contiguous
-     regions for each line.
-
- -- Macro: save-mark-and-excursion body...
-     This macro is like ‘save-excursion’, but also saves and restores
-     the mark location and ‘mark-active’.  This macro does what
-     ‘save-excursion’ did before Emacs 25.1.
-
- -- Function: format-message string &rest objects
-     This function acts like ‘format’, except it also converts any grave
-     accents (`) and apostrophes (') in STRING as per the value of
-     ‘text-quoting-style’.
-
-     Typically grave accent and apostrophe in the format translate to
-     matching curved quotes, e.g., "Missing `%s'" might result in
-     "Missing ‘foo’".  *Note (elisp)Text Quoting Style::, for how to
-     influence or inhibit this translation.
-
-     *note (elisp)Formatting Strings::.
-
- -- Function: directory-name-p filename
-     This function returns non-‘nil’ if FILENAME ends with a directory
-     separator character.  This is the forward slash ‘/’ on GNU and
-     other POSIX-like systems; MS-Windows and MS-DOS recognize both the
-     forward slash and the backslash ‘\’ as directory separators.
-
-     *Note (elisp)Directory Names::.
-
- -- Function: string-greaterp string1 string2
-     This function returns the result of comparing STRING1 and STRING2
-     in the opposite order, i.e., it is equivalent to calling
-     ‘(string-lessp STRING2 STRING1)’.
-
-     *Note (elisp)Text Comparison::.
-
- -- Macro: with-file-modes mode body...
-     This macro evaluates the BODY forms with the default permissions
-     for new files temporarily set to MODES (whose value is as for
-     ‘set-file-modes’ above).  When finished, it restores the original
-     default file permissions, and returns the value of the last form in
-     BODY.
-
-     This is useful for creating private files, for example.
-
-     *Note (elisp)Changing Files::.
-
- -- Function: alist-get key alist &optional default remove
-     This function is similar to ‘assq’.  It finds the first association
-     ‘(KEY . VALUE)’ by comparing KEY with ALIST elements, and, if
-     found, returns the VALUE of that association.  If no association is
-     found, the function returns DEFAULT.
-
-     This is a generalized variable (*note (elisp)Generalized
-     Variables::) that can be used to change a value with ‘setf’.  When
-     using it to set a value, optional argument REMOVE non-‘nil’ means
-     to remove KEY’s association from ALIST if the new value is ‘eql’ to
-     DEFAULT.
-
-     *note (elisp)Association Lists::.
-
- -- Macro: if-let (bindings...) then &rest else...
-     As with ‘let*’, BINDINGS will consist of ‘(SYMBOL VALUE-FORM)’
-     entries that are evaluated and bound sequentially.  If all
-     VALUE-FORM evaluate to non-‘nil’ values, then THEN is evaluated as
-     were the case with a regular ‘let*’ expression, with all the
-     variables bound.  If any VALUE-FORM evaluates to ‘nil’, ELSE is
-     evaluated, without any bound variables.
-
-     A binding may also optionally drop the SYMBOL, and simplify to
-     ‘(VALUE-FORM)’ if only the test is of interest.
-
-     For the sake of backwards compatibility, it is possible to write a
-     single binding without a binding list:
-
-          (if-let* (SYMBOL (test)) foo bar)
-          ≡
-          (if-let* ((SYMBOL (test))) foo bar)
-
- -- Macro: when-let (bindings...) &rest body
-     As with ‘when’, if one is only interested in the case where all
-     BINDINGS are non-nil.  Otherwise BINDINGS are interpreted just as
-     they are by ‘if-let*’.
-
- -- Function: hash-table-empty hash-table
-     Check whether HASH-TABLE is empty (has 0 elements).
-
- -- Macro: thread-first &rest forms
-     Combine FORMS into a single expression by “threading” each element
-     as the _first_ argument of their successor.  Elements of FORMS can
-     either be an list of an atom.
-
-     For example, consider the threading expression and it’s equivalent
-     macro expansion:
-
-          (thread-first
-            5
-            (+ 20)
-            (/ 25)
-            -
-            (+ 40))
-          ≡
-          (+ (- (/ (+ 5 20) 25)) 40)
-
-     Note how the single ‘-’ got converted into a list before threading.
-     This example uses arithmetic functions, but ‘thread-first’ is not
-     restricted to arithmetic or side-effect free code.
-
- -- Macro: thread-last &rest forms
-     Combine FORMS into a single expression by “threading” each element
-     as the _last_ argument of their successor.  Elements of FORMS can
-     either be an list of an atom.
-
-     For example, consider the threading expression and it’s equivalent
-     macro expansion:
-
-          (thread-first
-            5
-            (+ 20)
-            (/ 25)
-            -
-            (+ 40))
-          ≡
-          (+ 40 (- (/ 25 (+ 20 5))))
-
-     Note how the single ‘-’ got converted into a list before threading.
-     This example uses arithmetic functions, but ‘thread-last’ is not
-     restricted to arithmetic or side-effect free code.
-
- -- Function: macroexpand-1 form &optional environment
-     This function expands macros like ‘macroexpand’, but it only
-     performs one step of the expansion: if the result is another macro
-     call, ‘macroexpand-1’ will not expand it.
-
-     *Note Expansion: (elisp)Expansion.
-
- -- Function: macroexp-quote e
-     Return an expression E such that ‘(eval e)’ is V.
-
- -- Function: macroexp-parse body
-     Parse a function BODY into ‘(declarations . exps)’.
-
- -- Function: bool-vector &rest objects
-     This function creates and returns a bool-vector whose elements are
-     the arguments, OBJECTS.
-
-     *Note (elisp)Bool-Vectors::.
-
-2.1.2 Extended Definitions
---------------------------
-
-These functions must be called explicitly via ‘compat-call’, since their
-calling convention or behavior was extended in Emacs 25.1:
-
- -- Function: compat-call sort sequence predicate
-     This function sorts SEQUENCE stably.  Note that this function
-     doesn’t work for all sequences; it may be used only for lists and
-     vectors.  If SEQUENCE is a list, it is modified destructively.
-     This functions returns the sorted SEQUENCE and compares elements
-     using PREDICATE.  A stable sort is one in which elements with equal
-     sort keys maintain their relative order before and after the sort.
-     Stability is important when successive sorts are used to order
-     elements according to different criteria.
-
-     *Note (elisp)Sequence Functions::.
-
-     The compatibility version adds support for vectors to be sorted,
-     not just lists.
-
-2.1.3 Missing Definitions
--------------------------
-
-Compat does not provide support for the following Lisp features
-implemented in 25.1:
-
-   • The function ‘macroexp-macroexpand’.
-   • The macro ‘macroexp-let2*’.
-   • The function ‘directory-files-recursively’.
-   • New ‘pcase’ patterns.
-   • The hook ‘prefix-command-echo-keystrokes-functions’ and
-     ‘prefix-command-preserve-state-hook’.
-   • The hook ‘pre-redisplay-functions’.
-   • The function ‘make-process’.
-   • Support for the variable ‘inhibit-message’.
-   • The ‘define-inline’ functionality.
-   • The functions ‘string-collate-lessp’ and ‘string-collate-equalp’.
-   • The function ‘funcall-interactively’.
-   • The function ‘buffer-substring-with-bidi-context’.
-   • The function ‘font-info’.
-   • The function ‘default-font-width’.
-   • The function ‘window-font-height’ and ‘window-font-width’.
-   • The function ‘window-max-chars-per-line’.
-   • The function ‘set-binary-mode’.
-   • The functions ‘bufferpos-to-filepos’ and ‘filepos-to-bufferpos’.
-   • The ‘thunk’ library.
-
-\1f
-File: doc0jZUSv.info,  Node: Emacs 26.1,  Next: Emacs 27.1,  Prev: Emacs 25.1,  Up: Support
-
-2.2 Emacs 26.1
-==============
-
-2.2.1 Added Definitions
------------------------
-
-The following functions and macros are implemented in Emacs 26.1.  These
-functions are made available by Compat on Emacs versions older than
-26.1.
-
- -- Function: assoc-delete-all key alist
-     This function is like ‘assq-delete-all’ except that it uses ‘equal’
-     to compare elements.
-
- -- Function: read-answer question answers
-     This function prompts the user with text in QUESTION, which should
-     end in the ‘SPC’ character.  The function includes in the prompt
-     the possible responses in ANSWERS by appending them to the end of
-     QUESTION.  The possible responses are provided in ANSWERS as an
-     alist whose elements are of the following form:
-
-          (LONG-ANSWER SHORT-ANSWER HELP-MESSAGE)
-
-     where LONG-ANSWER is the complete text of the user response, a
-     string; SHORT-ANSWER is a short form of the same response, a single
-     character or a function key; and HELP-MESSAGE is the text that
-     describes the meaning of the answer.  If the variable
-     ‘read-answer-short’ is non-‘nil’, the prompt will show the short
-     variants of the possible answers and the user is expected to type
-     the single characters/keys shown in the prompt; otherwise the
-     prompt will show the long variants of the answers, and the user is
-     expected to type the full text of one of the answers and end by
-     pressing <RET>.  If ‘use-dialog-box’ is non-‘nil’, and this
-     function was invoked by mouse events, the question and the answers
-     will be displayed in a GUI dialog box.
-
-     The function returns the text of the LONG-ANSWER selected by the
-     user, regardless of whether long or short answers were shown in the
-     prompt and typed by the user.
-
-     Here is an example of using this function:
-
-          (let ((read-answer-short t))
-            (read-answer "Foo "
-               '(("yes"  ?y "perform the action")
-                 ("no"   ?n "skip to the next")
-                 ("all"  ?! "perform for the rest without more questions")
-                 ("help" ?h "show help")
-                 ("quit" ?q "exit"))))
-
- -- Function: mapcan function sequence
-     This function applies FUNCTION to each element of SEQUENCE, like
-     ‘mapcar’, but instead of collecting the results into a list, it
-     returns a single list with all the elements of the results (which
-     must be lists), by altering the results (using ‘nconc’; *note
-     (elisp)Rearrangement::).  Like with ‘mapcar’, SEQUENCE can be of
-     any type except a char-table.
-
-          ;; Contrast this: (mapcar #'list '(a b c d)) ⇒ ((a) (b) (c)
-          (d)) ;; with this: (mapcan #'list '(a b c d)) ⇒ (a b c d)
-
-     *Note (elisp)Mapping Functions::.
-
- -- Function: cXXXr
- -- Function: cXXXXr
-     *Note (elisp)List Elements::.
-
- -- Function: gensym &optional prefix
-     This function returns a symbol using ‘make-symbol’, whose name is
-     made by appending ‘gensym-counter’ to PREFIX and incrementing that
-     counter, guaranteeing that no two calls to this function will
-     generate a symbol with the same name.  The prefix defaults to
-     ‘"g"’.
-
- -- Variable: gensym-counter
-     See ‘gensym’.
-
- -- Function: buffer-hash &optional buffer-or-name
-     Return a hash of BUFFER-OR-NAME.  If ‘nil’, this defaults to the
-     current buffer.  As opposed to ‘secure-hash’, this function
-     computes the hash based on the internal representation of the
-     buffer, disregarding any coding systems.  It’s therefore only
-     useful when comparing two buffers running in the same Emacs, and is
-     not guaranteed to return the same hash between different Emacs
-     versions.  It should be somewhat more efficient on larger buffers
-     than ‘secure-hash’ is, and should not allocate more memory.
-
- -- Macro: file-name-unquote name
-     This macro removes the quotation prefix ‘/:’ from the file NAME, if
-     any.  If NAME is a remote file name, the local part of NAME is
-     unquoted.
-
- -- Function: file-name-quoted-p name
-     This macro returns non-‘nil’, when NAME is quoted with the prefix
-     ‘/:’.  If NAME is a remote file name, the local part of NAME is
-     checked.
-
-     *Note (elisp)File Name Expansion::.
-
- -- Function: file-name-quote name
-     This macro adds the quotation prefix ‘/:’ to the file NAME.  For a
-     local file NAME, it prefixes NAME with ‘/:’.  If NAME is a remote
-     file name, the local part of NAME (*note (elisp)Magic File Names::)
-     is quoted.  If NAME is already a quoted file name, NAME is returned
-     unchanged.
-
-          (substitute-in-file-name (compat-call file-name-quote "bar/~/foo")) ⇒
-               "/:bar/~/foo"
-
-          (substitute-in-file-name (compat-call file-name-quote "/ssh:host:bar/~/foo"))
-               ⇒ "/ssh:host:/:bar/~/foo"
-
-     The macro cannot be used to suppress file name handlers from magic
-     file names (*note (elisp)Magic File Names::).
-
-     *Note (elisp)File Name Expansion::.
-
- -- Function: make-nearby-temp-file prefix &optional dir-flag suffix
-     This function is similar to ‘make-temp-file’, but it creates a
-     temporary file as close as possible to ‘default-directory’.  If
-     PREFIX is a relative file name, and ‘default-directory’ is a remote
-     file name or located on a mounted file systems, the temporary file
-     is created in the directory returned by the function
-     ‘temporary-file-directory’.  Otherwise, the function
-     ‘make-temp-file’ is used.  PREFIX, DIR-FLAG and SUFFIX have the
-     same meaning as in ‘make-temp-file’.
-
-          (let ((default-directory "/ssh:remotehost:")) (make-nearby-temp-file
-            "foo")) ⇒ "/ssh:remotehost:/tmp/foo232J6v"
-
- -- Variable: mounted-file-systems
-     A regular expression matching files names that are probably on a
-     mounted file system.
-
- -- Function: temporary-file-directory
-     The directory for writing temporary files via
-     ‘make-nearby-temp-file’.  In case of a remote ‘default-directory’,
-     this is a directory for temporary files on that remote host.  If
-     such a directory does not exist, or ‘default-directory’ ought to be
-     located on a mounted file system (see ‘mounted-file-systems’), the
-     function returns ‘default-directory’.  For a non-remote and
-     non-mounted ‘default-directory’, the value of the variable
-     ‘temporary-file-directory’ is returned.
-
-     *Note (elisp)Unique File Names::.
-
- -- Macro: if-let* (bindings...) then &rest else
-     ‘if-let*’ is mostly equivalent to ‘if-let’, with the exception that
-     the legacy ‘(if (VAR (test)) foo bar)’ syntax is not permitted.
-
- -- Macro: when-let* (bindings...) then &rest else
-     ‘when-let*’ is mostly equivalent to ‘when-let’, with the exception
-     that the legacy ‘(when-let (VAR (test)) foo bar)’ syntax is not
-     permitted.
-
- -- Macro: and-let* (bindings...) &rest body
-     A combination of LET* and AND, analogous to ‘when-let*’.  If all
-     BINDINGS are non-‘nil’ and BODY is ‘nil’, then the result of the
-     ‘and-let*’ form will be the last value bound in BINDINGS.
-
-     **Please Note:** The implementation provided by Compat does not
-     include a bug that was observed with Emacs 26 (see
-     <https://debbugs.gnu.org/cgi/bugreport.cgi?bug=31840>).
-
- -- Function: file-local-name filename
-     This function returns the _local part_ of FILENAME.  This is the
-     part of the file’s name that identifies it on the remote host, and
-     is typically obtained by removing from the remote file name the
-     parts that specify the remote host and the method of accessing it.
-     For example:
-
-          (file-local-name "/ssh:USER@HOST:/foo/bar") ⇒
-               "/foo/bar"
-
-     For a remote FILENAME, this function returns a file name which
-     could be used directly as an argument of a remote process (*note
-     (elisp)Asynchronous Processes::, and *note (elisp)Synchronous
-     Processes::), and as the program to run on the remote host.  If
-     FILENAME is local, this function returns it unchanged.
-
-     *Note (elisp)Magic File Names::.
-
- -- Function: read-multiple-choice prompt choices
-     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.
-
-     See *note Reading One Event: (elisp)Reading One Event.
-
- -- Function: image-property
-     Defined in ‘image.el’.
-
-     This function can also be used as a generalised variable.
-
- -- Function: file-attribute-type
-     Return the field _type_ as generated by ‘file-attributes’.
-
-     *Note (elisp)File Attributes::.
-
- -- Function: file-attribute-link-number
-     Return the field _link-number_ as generated by ‘file-attributes’.
-
-     *Note (elisp)File Attributes::.
-
- -- Function: file-attribute-user-id
-     Return the field _user-id_ as generated by ‘file-attributes’.
-
-     *Note (elisp)File Attributes::.
-
- -- Function: file-attribute-group-id
-     Return the field _group-id_ as generated by ‘file-attributes’.
-
-     *Note (elisp)File Attributes::.
-
- -- Function: file-attribute-access-time
-     Return the field _access-time_ as generated by ‘file-attributes’.
-
-     *Note (elisp)File Attributes::.
-
- -- Function: file-attribute-modification-time
-     Return the field _modification-time_ as generated by
-     ‘file-attributes’.
-
-     *Note (elisp)File Attributes::.
-
- -- Function: file-attribute-status-change-time
-     Return the field _modification-time_ as generated by
-     ‘file-attributes’.
-
-     *Note (elisp)File Attributes::.
-
- -- Function: file-attribute-size
-     Return the field _size_ as generated by ‘file-attributes’.
-
-     *Note (elisp)File Attributes::.
-
- -- Function: file-attribute-modes
-     Return the field _modes_ as generated by ‘file-attributes’.
-
-     *Note (elisp)File Attributes::.
-
- -- Function: file-attribute-inode-number
-     Return the field _inode-number_ as generated by ‘file-attributes’.
-
-     *Note (elisp)File Attributes::.
-
- -- Function: file-attribute-device-number
-     Return the field _device-number_ as generated by ‘file-attributes’.
-
-     *Note (elisp)File Attributes::.
-
- -- Function: file-attribute-collect attributes &rest attr-names
-     Filter the file attributes ATTRIBUTES, as generated by
-     ‘file-attributes’, according to ATTR-NAMES.
-
-     Valid attribute names for ATTR-NAMES are: type, link-number,
-     user-id, group-id, access-time, modification-time,
-     status-change-time, size, modes, inode-number and device-number.
-
-          (file-attributes ".") ⇒ (t 1 1000 1000 (25329 18215 325481 96000) (25325 15364 530263 840000) (25325 15364 530263 840000) 788 "drwxr-xr-x" t 137819 40)
-          (file-attribute-collect (file-attributes ".") 'type 'modes
-          'inode-number) ⇒ (t "drwxr-xr-x" 137819)
-
-2.2.2 Extended Definitions
---------------------------
-
-These functions must be called explicitly via ‘compat-call’, since their
-calling convention or behavior was extended in Emacs 26.1:
-
- -- Function: compat-call make-temp-file prefix &optional dir-flag
-          suffix text
-     This function creates a temporary file and returns its name.  Emacs
-     creates the temporary file’s name by adding to PREFIX some random
-     characters that are different in each Emacs job.  The result is
-     guaranteed to be a newly created file, containing TEXT if that’s
-     given as a string and empty otherwise.  On MS-DOS, this function
-     can truncate PREFIX to fit into the 8+3 file-name limits.  If
-     PREFIX is a relative file name, it is expanded against
-     ‘temporary-file-directory’.
-
-     The compatibility version adds support for handling the optional
-     argument TEXT.
-
-          (make-temp-file "foo")
-               ⇒ "/tmp/foo232J6v"
-
-     When ‘make-temp-file’ returns, the file has been created and is
-     empty.  At that point, you should write the intended contents into
-     the file.
-
-     If DIR-FLAG is non-‘nil’, ‘make-temp-file’ creates an empty
-     directory instead of an empty file.  It returns the file name, not
-     the directory name, of that directory.  *Note (elisp)Directory
-     Names::.
-
-     If SUFFIX is non-‘nil’, ‘make-temp-file’ adds it at the end of the
-     file name.
-
-     If TEXT is a string, ‘make-temp-file’ inserts it in the file.
-
-     To prevent conflicts among different libraries running in the same
-     Emacs, each Lisp program that uses ‘make-temp-file’ should have its
-     own PREFIX.  The number added to the end of PREFIX distinguishes
-     between the same application running in different Emacs jobs.
-     Additional added characters permit a large number of distinct names
-     even in one Emacs job.
-
- -- Function: compat-call assoc key alist &optional testfn
-     This function returns the first association for KEY in ALIST,
-     comparing KEY against the alist elements using TESTFN if it is a
-     function, and ‘equal’ otherwise (*note (elisp)Equality
-     Predicates::).  If TESTFN is a function, it is called with two
-     arguments: the CAR of an element from ALIST and KEY.  The function
-     returns ‘nil’ if no association in ALIST has a CAR equal to KEY, as
-     tested by TESTFN.
-
-     *Note (elisp)Association Lists::.
-
-     The compatibility version adds support for handling the optional
-     argument TESTFN.
-
- -- Function: compat-call line-number-at-pos &optional pos absolute
-     This function returns the line number in the current buffer
-     corresponding to the buffer position POS.  If POS is ‘nil’ or
-     omitted, the current buffer position is used.  If ABSOLUTE is
-     ‘nil’, the default, counting starts at ‘(point-min)’, so the value
-     refers to the contents of the accessible portion of the
-     (potentially narrowed) buffer.  If ABSOLUTE is non-‘nil’, ignore
-     any narrowing and return
-
-     *Note (elisp)Text Lines::.
-
-     The compatibility version adds support for handling the optional
-     argument ABSOLUTE.
-
- -- Function: compat-call alist-get key alist &optional default remove
-          testfn
-     *Note (elisp)Association Lists::.  This function is similar to
-     ‘assq’.  It finds the first association ‘(KEY . VALUE)’ by
-     comparing KEY with ALIST elements, and, if found, returns the VALUE
-     of that association.  If no association is found, the function
-     returns DEFAULT.  Comparison of KEY against ALIST elements uses the
-     function specified by TESTFN, defaulting to ‘eq’.
-
-     *Note (elisp)Association Lists::.
-
-     The compatibility version handles the optional argument TESTFN.  It
-     can also be used as a *note Generalized Variables:
-     (elisp)generalised variable.
-
- -- Function: compat-call string-trim-left string &optional regexp
-     Remove the leading text that matches REGEXP from STRING.  REGEXP
-     defaults to ‘[ \t\n\r]+’.
-
-     *Note (elisp)Creating Strings::.
-
-     The compatibility version handles the optional argument REGEXP.
-
- -- Function: compat-call string-trim-right string &optional regexp
-     Remove the trailing text that matches REGEXP from STRING.  REGEXP
-     defaults to ‘[ \t\n\r]+’.
-
-     *Note (elisp)Creating Strings::.
-
-     The compatibility version handles the optional argument REGEXP.
-
- -- Function: compat-call string-trim string &optional trim-left
-          trim-right
-     Remove the leading text that matches TRIM-LEFT and trailing text
-     that matches TRIM-RIGHT from STRING.  Both regexps default to ‘[
-     \t\n\r]+’.
-
-     *Note (elisp)Creating Strings::.
-
-     The compatibility version handles the optional arguments TRIM-LEFT
-     and TRIM-RIGHT.
-
-2.2.3 Missing Definitions
--------------------------
-
-Compat does not provide support for the following Lisp features
-implemented in 26.1:
-
-   • The function ‘func-arity’.
-   • The function ‘secure-hash-algorithms’.
-   • The function ‘gnutls-available-p’.
-   • Support for records and record functions.
-   • The function ‘mapbacktrace’.
-   • The function ‘file-name-case-insensitive-p’.
-   • The additional elements of ‘parse-partial-sexp’.
-   • The function ‘add-variable-watcher’.
-   • The function ‘undo-amalgamate-change-group’.
-   • The function ‘char-from-name’
-   • Signalling errors when ‘length’ or ‘member’ deal with list cycles.
-   • The function ‘frame-list-z-order’.
-   • The function ‘frame-restack’.
-   • All changes related to ‘display-buffer’.
-   • The function ‘window-swap-states’.
-   • The function ‘string-version-lessp’.
-   • The ‘svg’ library.
-   • The ‘xdg’ library.
-
-\1f
-File: doc0jZUSv.info,  Node: Emacs 27.1,  Next: Emacs 28.1,  Prev: Emacs 26.1,  Up: Support
-
-2.3 Emacs 27.1
-==============
-
-2.3.1 Added Definitions
------------------------
-
-The following functions and macros are implemented in Emacs 27.1.  These
-functions are made available by Compat on Emacs versions older than
-27.1.
-
- -- Function: major-mode-suspend
-     This function works like ‘fundamental-mode’, in that it kills all
-     buffer-local variables, but it also records the major mode in
-     effect, so that it could subsequently be restored.  This function
-     and ‘major-mode-restore’ (described next) are useful when you need
-     to put a buffer under some specialized mode other than the one
-     Emacs chooses for it automatically, but would also like to be able
-     to switch back to the original mode later.
-
- -- Function: major-mode-restore &optional avoided-modes
-     This function restores the major mode recorded by
-     ‘major-mode-suspend’.  If no major mode was recorded, this function
-     calls ‘normal-mode’, but tries to force it not to choose any modes
-     in AVOIDED-MODES, if that argument is non-‘nil’.
-
- -- Function: ring-resize ring size
-     Set the size of RING to SIZE.  If the new size is smaller, then the
-     oldest items in the ring are discarded.
-
- -- Function: minibuffer-history-value
-     Return the value of the minibuffer input history list.  If
-     MINIBUFFER-HISTORY-VARIABLE points to a buffer-local variable and
-     the minibuffer is active, return the buffer-local value for the
-     buffer that was current when the minibuffer was activated."
-
- -- Macro: with-minibuffer-selected-window &rest body
-     Execute the forms in BODY from the minibuffer in its original
-     window.  When used in a minibuffer window, select the window
-     selected just before the minibuffer was activated, and execute the
-     forms.
-
- -- Function: read-char-from-minibuffer prompt &optional chars history
-     This function uses the minibuffer to read and return a single
-     character.  Optionally, it ignores any input that is not a member
-     of CHARS, a list of accepted characters.  The HISTORY argument
-     specifies the history list symbol to use; if it is omitted or
-     ‘nil’, this function doesn’t use the history.
-
-     If you bind ‘help-form’ to a non-‘nil’ value while calling
-     ‘read-char-from-minibuffer’, then pressing ‘help-char’ causes it to
-     evaluate ‘help-form’ and display the result.
-
- -- Function: bignump object
-     This predicate tests whether its argument is a large integer, and
-     returns ‘t’ if so, ‘nil’ otherwise.  Unlike small integers, large
-     integers can be ‘=’ or ‘eql’ even if they are not ‘eq’.
-
- -- Function: fixnump object
-     This predicate tests whether its argument is a small integer, and
-     returns ‘t’ if so, ‘nil’ otherwise.  Small integers can be compared
-     with ‘eq’.
-
- -- Special Form: with-suppressed-warnings warnings body...
-     In execution, this is equivalent to ‘(progn BODY...)’, but the
-     compiler does not issue warnings for the specified conditions in
-     BODY.  WARNINGS is an association list of warning symbols and
-     function/variable symbols they apply to.  For instance, if you wish
-     to call an obsolete function called ‘foo’, but want to suppress the
-     compilation warning, say:
-
-          (with-suppressed-warnings ((obsolete foo))
-            (foo ...))
-
- -- Function: proper-list-p object
-     This function returns the length of OBJECT if it is a proper list,
-     ‘nil’ otherwise (*note (elisp)Cons Cells::).  In addition to
-     satisfying ‘listp’, a proper list is neither circular nor dotted.
-
-          (proper-list-p '(a b c)) ⇒ 3
-          (proper-list-p '(a b . c)) ⇒ nil
-
-     *Note (elisp)List-related Predicates::.
-
- -- Function: string-distance string1 string2 &optional bytecompare
-     This function returns the _Levenshtein distance_ between the source
-     string STRING1 and the target string STRING2.  The Levenshtein
-     distance is the number of single-character changes—deletions,
-     insertions, or replacements—required to transform the source string
-     into the target string; it is one possible definition of the _edit
-     distance_ between strings.
-
-     Letter-case of the strings is significant for the computed
-     distance, but their text properties are ignored.  If the optional
-     argument BYTECOMPARE is non-‘nil’, the function calculates the
-     distance in terms of bytes instead of characters.  The byte-wise
-     comparison uses the internal Emacs representation of characters, so
-     it will produce inaccurate results for multibyte strings that
-     include raw bytes (*note (elisp)Text Representations::); make the
-     strings unibyte by encoding them (*note (elisp)Explicit Encoding::)
-     if you need accurate results with raw bytes.
-
-     *Note (elisp)Text Comparison::.
-
- -- Macro: ignore-errors body...
-     This construct executes BODY, ignoring any errors that occur during
-     its execution.  If the execution is without error, ‘ignore-errors’
-     returns the value of the last form in BODY; otherwise, it returns
-     ‘nil’.
-
-     Here’s the example at the beginning of this subsection rewritten
-     using ‘ignore-errors’:
-
-            (ignore-errors (delete-file filename))
-
-     *Note (elisp)Handling Errors::.
-
- -- Macro: dolist-with-progress-reporter (var count [result])
-          reporter-or-message body...
-     This is another convenience macro that works the same way as
-     ‘dolist’ does, but also reports loop progress using the functions
-     described above.  As in ‘dotimes-with-progress-reporter’,
-     ‘reporter-or-message’ can be a progress reporter or a string.  You
-     can rewrite the previous example with this macro as follows:
-
-          (dolist-with-progress-reporter (k (number-sequence 0 500)) "Collecting
-              some mana for Emacs..."  (sit-for 0.01))
-
-     *Note (elisp)Progress::.
-
- -- Function: flatten-tree tree
-     This function returns a “flattened” copy of TREE, that is, a list
-     containing all the non-‘nil’ terminal nodes, or leaves, of the tree
-     of cons cells rooted at TREE.  Leaves in the returned list are in
-     the same order as in TREE.
-
-          (flatten-tree '(1 (2 . 3) nil (4 5 (6)) 7)) ⇒(1 2 3 4 5 6 7)
-
-     *Note (elisp)Building Lists::.
-
- -- Function: xor condition1 condition2
-     This function returns the boolean exclusive-or of CONDITION1 and
-     CONDITION2.  That is, ‘xor’ returns ‘nil’ if either both arguments
-     are ‘nil’, or both are non-‘nil’.  Otherwise, it returns the value
-     of that argument which is non-‘nil’.
-
-     Note that in contrast to ‘or’, both arguments are always evaluated.
-
-     *Note (elisp)Combining Conditions::.
-
- -- Variable: regexp-unmatchable
-     This variable contains a regexp that is guaranteed not to match any
-     string at all.  It is particularly useful as default value for
-     variables that may be set to a pattern that actually matches
-     something.
-
-     *Note (elisp)Regexp Functions::
-
- -- Function: decoded-time-second time
-     Return the SECONDS field of a ‘decoded-time’ record TIME.  It can
-     also be used as a *note Generalized Variables: (elisp)generalised
-     variable.
-
- -- Function: decoded-time-minute time
-     Return the MINUTE field of a ‘decoded-time’ record TIME.  It can
-     also be used as a *note Generalized Variables: (elisp)generalised
-     variable.
-
- -- Function: decoded-time-hour time
-     Return the HOUR field of a ‘decoded-time’ record TIME.  It can also
-     be used as a *note Generalized Variables: (elisp)generalised
-     variable.
-
- -- Function: decoded-time-day time
-     Return the DAY field of a ‘decoded-time’ record TIME.  It can also
-     be used as a *note Generalized Variables: (elisp)generalised
-     variable.
-
- -- Function: decoded-time-month time
-     Return the MONTH field of a ‘decoded-time’ record TIME.  It can
-     also be used as a *note Generalized Variables: (elisp)generalised
-     variable.
-
- -- Function: decoded-time-year time
-     Return the YEAR field of a ‘decoded-time’ record TIME.  It can also
-     be used as a *note Generalized Variables: (elisp)generalised
-     variable.
-
- -- Function: decoded-time-weekday time
-     Return the WEEKDAY field of a ‘decoded-time’ record TIME.  It can
-     also be used as a *note Generalized Variables: (elisp)generalised
-     variable.
-
- -- Function: decoded-time-dst time
-     Return the DST (daylight saving time indicator) field of a
-     ‘decoded-time’ record TIME.  It can also be used as a *note
-     Generalized Variables: (elisp)generalised variable.
-
- -- Function: decoded-time-zone time
-     Return the ZONE field of a ‘decoded-time’ record TIME.  It can also
-     be used as a *note Generalized Variables: (elisp)generalised
-     variable.
-
- -- Function: package-get-version
-     Return the version number of the package in which this is used.
-
- -- Function: time-equal-p t1 t2
-     This returns ‘t’ if the two time values T1 and T2 are equal.
-
-     *Note (elisp)Time Calculations::.
-
- -- Function: date-days-in-month year month
-     Return the number of days in MONTH in YEAR.  For instance, February
-     2020 has 29 days.
-
-     *Note (elisp)Time Calculations::.  This function requires the
-     ‘time-date’ feature to be loaded.
-
- -- Function: date-ordinal-to-time year ordinal
-     Convert a YEAR/ORDINAL to the equivalent decoded-time structure.
-     ORDINAL is the number of days since the start of the year, with
-     January 1st being 1.
-
-     *Note (elisp)Time Calculations::.  This function requires the
-     ‘time-date’ feature to be loaded.
-
- -- User Option: exec-path
-     The value of this variable is a list of directories to search for
-     programs to run in subprocesses.  Each element is either the name
-     of a directory (i.e., a string), or ‘nil’, which stands for the
-     default directory (which is the value of ‘default-directory’).
-     *Note executable-find: (elisp)Locating Files, for the details of
-     this search.
-
-     The value of ‘exec-path’ is used by ‘call-process’ and
-     ‘start-process’ when the PROGRAM argument is not an absolute file
-     name.
-
-     Generally, you should not modify ‘exec-path’ directly.  Instead,
-     ensure that your ‘PATH’ environment variable is set appropriately
-     before starting Emacs.  Trying to modify ‘exec-path’ independently
-     of ‘PATH’ can lead to confusing results.
-
-     *Note (elisp)Subprocess Creation::.
-
- -- Function: provided-mode-derived-p mode &rest modes
-     This function returns non-‘nil’ if MODE is derived from any of the
-     major modes given by the symbols MODES.
-
- -- Function: file-size-human-readable-iec size
-     Human-readable string for SIZE bytes, using IEC prefixes.
-
- -- Function: make-empty-file filename &optional parents
-     This function creates an empty file named FILENAME.  As
-     ‘make-directory’, this function creates parent directories if
-     PARENTS is non-‘nil’.  If FILENAME already exists, this function
-     signals an error.
-
- -- Function: text-property-search-forward prop &optional value
-          predicate not-current
-     Search for the next region that has text property PROP set to VALUE
-     according to PREDICATE.
-
-     This function is modeled after ‘search-forward’ and friends in that
-     it moves point, but it returns a structure that describes the match
-     instead of returning it in ‘match-beginning’ and friends.
-
-     If the text property can’t be found, the function returns ‘nil’.
-     If it’s found, point is placed at the end of the region that has
-     this text property match, and a ‘prop-match’ structure is returned.
-
-     PREDICATE can either be ‘t’ (which is a synonym for ‘equal’), ‘nil’
-     (which means “not equal”), or a predicate that will be called with
-     two parameters: The first is VALUE, and the second is the value of
-     the text property we’re inspecting.
-
-     If NOT-CURRENT, if point is in a region where we have a match, then
-     skip past that and find the next instance instead.
-
-     The ‘prop-match’ structure has the following accessors:
-     ‘prop-match-beginning’ (the start of the match), ‘prop-match-end’
-     (the end of the match), and ‘prop-match-value’ (the value of
-     PROPERTY at the start of the match).
-
-     In the examples below, imagine that you’re in a buffer that looks
-     like this:
-
-          This is a bold and here's bolditalic and this is the end.
-
-     That is, the “bold” words are the ‘bold’ face, and the “italic”
-     word is in the ‘italic’ face.
-
-     With point at the start:
-
-          (while (setq match (text-property-search-forward 'face 'bold t))
-            (push (buffer-substring (prop-match-beginning match)
-                                    (prop-match-end match))
-                  words))
-
-     This will pick out all the words that use the ‘bold’ face.
-
-          (while (setq match (text-property-search-forward 'face nil t))
-            (push (buffer-substring (prop-match-beginning match)
-                                    (prop-match-end match))
-                  words))
-
-     This will pick out all the bits that have no face properties, which
-     will result in the list ‘("This is a " "and here's " "and this is
-     the end")’ (only reversed, since we used ‘push’).
-
-          (while (setq match (text-property-search-forward 'face nil nil))
-            (push (buffer-substring (prop-match-beginning match)
-                                    (prop-match-end match))
-                  words))
-
-     This will pick out all the regions where ‘face’ is set to
-     something, but this is split up into where the properties change,
-     so the result here will be ‘("bold" "bold" "italic")’.
-
-     For a more realistic example where you might use this, consider
-     that you have a buffer where certain sections represent URLs, and
-     these are tagged with ‘shr-url’.
-
-          (while (setq match (text-property-search-forward 'shr-url nil nil))
-            (push (prop-match-value match) urls))
-
-     This will give you a list of all those URLs.
-
-     *Note (Property Search)elisp::.
-
- -- Function: text-property-search-backward prop &optional value
-          predicate not-current
-     This is just like ‘text-property-search-forward’, but searches
-     backward instead.  Point is placed at the beginning of the matched
-     region instead of the end, though.
-
-     *Note (Property Search)elisp::.
-
-2.3.2 Extended Definitions
---------------------------
-
-These functions must be called explicitly via ‘compat-call’, since their
-calling convention or behavior was extended in Emacs 27.1:
-
- -- Function: compat-call recenter &optional count redisplay
-     This function scrolls the text in the selected window so that point
-     is displayed at a specified vertical position within the window.
-     It does not move point with respect to the text.
-
-     *Note (elisp)Textual Scrolling::.
-
-     This compatibility version adds support for the optional argument
-     REDISPLAY.
-
- -- Function: compat-call lookup-key keymap key &optional
-          accept-defaults
-     This function returns the definition of KEY in KEYMAP.  If the
-     string or vector KEY is not a valid key sequence according to the
-     prefix keys specified in KEYMAP, it must be too long and have extra
-     events at the end that do not fit into a single key sequence.  Then
-     the value is a number, the number of events at the front of KEY
-     that compose a complete key.
-
-     *Note (elisp)Low-Level Key Binding::.
-
-     This compatibility version allows for KEYMAP to be a list of
-     keymaps, instead of just a singular keymap.
-
- -- Macro: compat-call setq-local &rest pairs
-     PAIRS is a list of variable and value pairs.  This macro creates a
-     buffer-local binding in the current buffer for each of the
-     variables, and gives them a buffer-local value.  It is equivalent
-     to calling ‘make-local-variable’ followed by ‘setq’ for each of the
-     variables.  The variables should be unquoted symbols.
-
-          (setq-local var1 "value1"
-                      var2 "value2")
-
-     *Note (elisp)Creating Buffer-Local::.
-
-     This compatibility version allows for more than one variable to be
-     set at once, as can be done with ‘setq’.
-
- -- Function: compat-call regexp-opt strings &optional paren
-     This function returns an efficient regular expression that will
-     match any of the strings in the list STRINGS.  This is useful when
-     you need to make matching or searching as fast as possible—for
-     example, for Font Lock mode.
-
-     *Note (elisp)Regexp Functions::.
-
-     The compatibility version of this functions handles the case where
-     STRINGS in an empty list.  In that case, a regular expression is
-     generated that never matches anything (see ‘regexp-unmatchable’).
-
- -- Function: compat-call file-size-human-readable file-size &optional
-          flavor space unit
-     Return a string with a human readable representation of FILE-SIZE.
-
-     The optional second argument FLAVOR controls the units and the
-     display format.  If FLAVOR is...
-
-        • ‘si’, each kilobyte is 1000 bytes and the produced suffixes
-          are ‘k’, ‘M’, ‘G’, ‘T’, etc.
-        • ‘iec’, each kilobyte is 1024 bytes and the produced suffixes
-          are ‘KiB’, ‘MiB’, ‘GiB’, ‘TiB’, etc.
-        • ‘nil’ or omitted, each kilobyte is 1024 bytes and the produced
-          suffixes are ‘k’, ‘M’, ‘G’, ‘T’, etc.
-
-     The compatibility version handles the optional third (SPACE) and
-     forth (UNIT) arguments.  The argument SPACE can be a string that is
-     placed between the number and the unit.  The argument UNIT
-     determines the unit to use.  By default it will be an empty string,
-     unless FLAVOR is ‘iec’, in which case it will be ‘B’.
-
- -- Function: compat-call assoc-delete-all key alist &optional test
-     This function is like ‘assq-delete-all’ except that it accepts an
-     optional argument TEST, a predicate function to compare the keys in
-     ALIST.  If omitted or ‘nil’, TEST defaults to ‘equal’.  As
-     ‘assq-delete-all’, this function often modifies the original list
-     structure of ALIST.
-
-     *Note (elisp)Association Lists::.
-
-     This compatibility version handles the optional third (TESTFN)
-     argument.
-
- -- Function: compat-call executable-find program &optional remote
-     This function searches for the executable file of the named PROGRAM
-     and returns the absolute file name of the executable, including its
-     file-name extensions, if any.  It returns ‘nil’ if the file is not
-     found.  The function searches in all the directories in
-     ‘exec-path’, and tries all the file-name extensions in
-     ‘exec-suffixes’ (*note (elisp)Subprocess Creation::).
-
-     If REMOTE is non-‘nil’, and ‘default-directory’ is a remote
-     directory, PROGRAM is searched on the respective remote host.
-
-     *Note (elisp)Locating Files::.
-
-     This compatibility version adds support to handle the optional
-     second (REMOTE) argument.
-
-2.3.3 Missing Definitions
--------------------------
-
-Compat does not provide support for the following Lisp features
-implemented in 27.1:
-
-   • The functions ‘base64url-encode-*’.
-   • The function ‘decoded-time-add’.
-   • The function ‘decoded-time-set-defaults’.
-   • The function ‘time-convert’.
-   • The macro ‘benchmark-progn’.
-   • Support for ‘condition-case’ to handle t.
-   • The function ‘file-system-info’.
-   • The function ‘group-name’.
-   • The function ‘face-extend-p’ and ‘set-face-extend’.
-   • Additional ‘format-spec’ modifiers.
-   • Support for additional body forms for
-     ‘define-globalized-minor-mode’.
-   • The macro ‘with-connection-local-variables’ and related
-     functionality.
-   • The ‘iso8601’ library.
-   • The ‘exif’ library.
-   • The ‘image-converter’ library.
-
-\1f
-File: doc0jZUSv.info,  Node: Emacs 28.1,  Next: Emacs 29.1,  Prev: Emacs 27.1,  Up: Support
-
-2.4 Emacs 28.1
-==============
-
-2.4.1 Added Definitions
------------------------
-
-The following functions and macros are implemented in Emacs 28.1.  These
-functions are made available by Compat on Emacs versions older than
-28.1.
-
-   The ‘defcustom’ type ‘natnum’ introduced in Emacs 28.1 is made
-available by Compat.
-
- -- Function: process-lines-ignore-status program &rest args
-     This function is just like ‘process-lines’, but does not signal an
-     error if PROGRAM exits with a non-zero exit status.
-
- -- Function: process-lines-handling-status program status-handler &rest
-          args
-     Execute PROGRAM with ARGS, returning its output as a list of lines.
-     If STATUS-HANDLER is non-nil, it must be a function with one
-     argument, which will be called with the exit status of the program
-     before the output is collected.  If STATUS-HANDLER is nil, an error
-     is signaled if the program returns with a non-zero exit status.
-
- -- Function: text-quoting-style
-     You should not read the value of the variable ‘text-quoting-style’
-     directly.  Instead, use this function with the same name to
-     dynamically compute the correct quoting style on the current
-     terminal in the ‘nil’ case described above.
-
- -- Function: string-search needle haystack &optional start-pos
-     Return the position of the first instance of NEEDLE in HAYSTACK,
-     both of which are strings.  If START-POS is non-‘nil’, start
-     searching from that position in NEEDLE.  Return ‘nil’ if no match
-     was found.  This function only considers the characters in the
-     strings when doing the comparison; text properties are ignored.
-     Matching is always case-sensitive.
-
- -- Function: length= sequence length
-     Return non-‘nil’ if the length of SEQUENCE is equal to LENGTH.
-
- -- Function: length< sequence length
-     Return non-‘nil’ if SEQUENCE is shorter than LENGTH.  This may be
-     more efficient than computing the length of SEQUENCE if SEQUENCE is
-     a long list.
-
- -- Function: length> sequence length
-     Return non-‘nil’ if SEQUENCE is longer than LENGTH.
-
- -- Function: file-name-concat directory &rest components
-     Concatenate COMPONENTS to DIRECTORY, inserting a slash before the
-     components if DIRECTORY or the preceding component didn’t end with
-     a slash.
-
-          (file-name-concat "/tmp" "foo") ⇒ "/tmp/foo"
-
-     A DIRECTORY or components that are ‘nil’ or the empty string are
-     ignored—they are filtered out first and do not affect the results
-     in any way.
-
-     This is almost the same as using ‘concat’, but DIRNAME (and the
-     non-final components) may or may not end with slash characters, and
-     this function will not double those characters.
-
- -- Function: garbage-collect-maybe factor
-     Suggest to run garbage collection, if _enough_ data has been
-     allocated.  This is determined by the positive numerical argument
-     FACTOR, that would proportionally increase the likelihood of
-     garbage collection taking place.
-
-     This compatibility function does nothing and ignores any
-     suggestion.
-
- -- Function: string-replace from-string to-string in-string
-     This function replaces all occurrences of FROM-STRING with
-     TO-STRING in IN-STRING and returns the result.  It may return one
-     of its arguments unchanged, a constant string or a new string.
-     Case is significant, and text properties are ignored.
-
- -- Function: always &rest arguments
-     This function ignores any ARGUMENTS and returns ‘t’.
-
-     *Note (elisp)Calling Functions::.
-
- -- Function: make-separator-line &optional length
-     Make a string appropriate for usage as a visual separator line.  If
-     LENGTH is nil, use the window width.
-
- -- Function: insert-into-buffer to-buffer &optional start end
-     This is like ‘insert-buffer-substring’, but works in the opposite
-     direction: The text is copied from the current buffer into
-     TO-BUFFER.  The block of text is copied to the current point in
-     TO-BUFFER, and point (in that buffer) is advanced to after the end
-     of the copied text.  Is ‘start’/‘end’ is ‘nil’, the entire text in
-     the current buffer is copied over.
-
-     *Note (elisp)Insertion::.
-
- -- Function: replace-string-in-region regexp replacement &optional
-          start end
-     This function replaces all the occurrences of REGEXP with
-     REPLACEMENT in the region of buffer text between START and END;
-     START defaults to position of point, and END defaults to the last
-     accessible position of the buffer.  The search for REGEXP is
-     case-sensitive, and REPLACEMENT is inserted without changing its
-     letter-case.  The REPLACEMENT string can use the same special
-     elements starting with ‘\’ as ‘replace-match’ does.  The function
-     returns the number of replaced occurrences, or ‘nil’ if REGEXP is
-     not found.  The function preserves the position of point.
-
-          (replace-regexp-in-region "foo[ \t]+bar" "foobar")
-     *Note (elisp)Search and Replace::.
-
- -- Function: replace-regexp-in-string string replacement &optional
-          start end
-     This function works similarly to ‘replace-regexp-in-region’, but
-     searches for, and replaces, literal STRINGs instead of regular
-     expressions.
-
-     *Note (elisp)Search and Replace::.
-
- -- Function: buffer-local-boundp variable buffer
-     This returns non-‘nil’ if there’s either a buffer-local binding of
-     VARIABLE (a symbol) in buffer BUFFER, or VARIABLE has a global
-     binding.
-
-     *Note (elisp)Creating Buffer-Local::.
-
- -- Macro: with-existing-directory body...
-     This macro ensures that ‘default-directory’ is bound to an existing
-     directory before executing BODY.  If ‘default-directory’ already
-     exists, that’s preferred, and otherwise some other directory is
-     used.  This macro can be useful, for instance, when calling an
-     external command that requires that it’s running in a directory
-     that exists.  The chosen directory is not guaranteed to be
-     writable.
-
-     *Note (elisp)Testing Accessibility::.
-
- -- Macro: dlet (bindings...) forms...
-     This special form is like ‘let’, but it binds all variables
-     dynamically.  This is rarely useful—you usually want to bind normal
-     variables lexically, and special variables (i.e., variables that
-     are defined with ‘defvar’) dynamically, and this is what ‘let’
-     does.
-
-     ‘dlet’ can be useful when interfacing with old code that assumes
-     that certain variables are dynamically bound (*note (elisp)Dynamic
-     Binding::), but it’s impractical to ‘defvar’ these variables.
-     ‘dlet’ will temporarily make the bound variables special, execute
-     the forms, and then make the variables non-special again.
-
-     *Note (elisp)Local Variables::.
-
- -- Function: ensure-list object
-     This function returns OBJECT as a list.  If OBJECT is already a
-     list, the function returns it; otherwise, the function returns a
-     one-element list containing OBJECT.
-
-     This is usually useful if you have a variable that may or may not
-     be a list, and you can then say, for instance:
-
-          (dolist (elem (ensure-list foo))
-            (princ elem))
-
-     *Note (elisp)Building Lists::.
-
- -- Function: string-clean-whitespace string
-     Clean up the whitespace in STRING by collapsing stretches of
-     whitespace to a single space character, as well as removing all
-     whitespace from the start and the end of STRING.
-
-     *Note (elisp)Creating Strings::.
-
- -- Function: string-fill string length
-     Attempt to Word-wrap STRING so that no lines are longer than
-     LENGTH.  Filling is done on whitespace boundaries only.  If there
-     are individual words that are longer than LENGTH, these will not be
-     shortened.
-
-     *Note (elisp)Creating Strings::.
-
- -- Function: string-lines string &optional omit-nulls
-     Split STRING into a list of strings on newline boundaries.  If the
-     optional argument OMIT-NULLS is non-‘nil’, remove empty lines from
-     the results.  Note that this function returns trailing newlines on
-     Emacs 28, use ‘compat-call string-lines’ instead if you want
-     consistent behavior.
-
- -- Function: string-pad string length &optional padding start
-     Pad STRING to be of the given LENGTH using PADDING as the padding
-     character.  PADDING defaults to the space character.  If STRING is
-     longer than LENGTH, no padding is done.  If START is ‘nil’ or
-     omitted, the padding is appended to the characters of STRING, and
-     if it’s non-‘nil’, the padding is prepended to STRING’s characters.
-
-     *Note (elisp)Creating Strings::.
-
- -- Function: string-chop-newline string
-     Remove the final newline, if any, from STRING.
-
-     *Note (elisp)Creating Strings::.
-
- -- Macro: named-let name bindings &rest body
-     This special form is a looping construct inspired from the Scheme
-     language.  It is similar to ‘let’: It binds the variables in
-     BINDINGS, and then evaluates BODY.  However, ‘named-let’ also binds
-     NAME to a local function whose formal arguments are the variables
-     in BINDINGS and whose body is BODY.  This allows BODY to call
-     itself recursively by calling NAME, where the arguments passed to
-     NAME are used as the new values of the bound variables in the
-     recursive invocation.
-
-     Recursive calls to NAME that occur in _tail positions_ in BODY are
-     guaranteed to be optimized as _tail calls_, which means that they
-     will not consume any additional stack space no matter how deeply
-     the recursion runs.  Such recursive calls will effectively jump to
-     the top of the loop with new values for the variables.
-
-     *Note (elisp)Local Variables::.
-
- -- Function: file-name-with-extension filename extension
-     This function returns FILENAME with its extension set to EXTENSION.
-     A single leading dot in the EXTENSION will be stripped if there is
-     one.  For example:
-
-          (file-name-with-extension "file" "el")
-               ⇒ "file.el"
-          (file-name-with-extension "file" ".el")
-               ⇒ "file.el"
-          (file-name-with-extension "file.c" "el")
-               ⇒ "file.el"
-
-     Note that this function will error if FILENAME or EXTENSION are
-     empty, or if the FILENAME is shaped like a directory (i.e., if
-     ‘directory-name-p’ returns non-‘nil’).
-
-     *Note File Name Components: (elisp)File Name Components.
-
- -- Function: directory-empty-p directory
-     This utility function returns ‘t’ if given DIRECTORY is an
-     accessible directory and it does not contain any files, i.e., is an
-     empty directory.  It will ignore ‘.’ and ‘..’ on systems that
-     return them as files in a directory.
-
-     Symbolic links to directories count as directories.  See
-     FILE-SYMLINK-P to distinguish symlinks.
-
-     *Note (elisp)Contents of Directories::.
-
- -- Function: format-prompt prompt default &rest format-args
-     Format PROMPT with default value DEFAULT according to the
-     ‘minibuffer-default-prompt-format’ variable.
-
-     ‘minibuffer-default-prompt-format’ is a format string (defaulting
-     to ‘" (default %s)"’ that says how the “default” bit in prompts
-     like ‘"Local filename (default somefile): "’ are to be formatted.
-
-     To allow the users to customize how this is displayed, code that
-     prompts the user for a value (and has a default) should look
-     something along the lines of this code snippet:
-
-          (read-file-name
-           (format-prompt "Local filename" file)
-           nil file)
-
-     If FORMAT-ARGS is ‘nil’, PROMPT is used as a literal string.  If
-     FORMAT-ARGS is non-‘nil’, PROMPT is used as a format control
-     string, and PROMPT and FORMAT-ARGS are passed to ‘format’ (*note
-     (elisp)Formatting Strings::).
-
-     ‘minibuffer-default-prompt-format’ can be ‘""’, in which case no
-     default values are displayed.
-
-     If DEFAULT is ‘nil’, there is no default value, and therefore no
-     “default value” string is included in the result value.  If DEFAULT
-     is a non-‘nil’ list, the first element of the list is used in the
-     prompt.
-
-     *Note (elisp)Text from Minibuffer::.
-
- -- Function: thing-at-mouse event thing &optional no-properties
-     Mouse-EVENT equivalent of ‘thing-at-point’.  THING can be ‘symbol’,
-     ‘list’, ‘sexp’, ‘filename’, ‘url’, ... among other things.
-
-     When NO-PROPERTIES has a non-‘nil’ value, any text properties that
-     might have been present in the buffer are stripped away.
-
- -- Function: bounds-of-thing-at-mouse event thing
-     Determine start and end locations for THING at mouse click given by
-     EVENT.  Like ‘bounds-of-thing-at-point’, but tries to use the
-     position in EVENT where the mouse button is clicked to find the
-     thing nearby.
-
- -- Function: mark-thing-at-mouse click thing
-     Activate the region around THING found near the mouse CLICK.
-
- -- Function: macroexp-file-name
-     Return the name of the file in which the code is currently being
-     evaluated, or ‘nil’ if it cannot be determined.
-
- -- Function: macroexp-warn-and-return msg form &optional category
-          compile-only arg
-     Return code equivalent to ‘form’ labeled with warning ‘msg’.
-
- -- Macro: with-environment-variables variables body...
-     This macro sets the environment variables according to VARIABLES
-     temporarily when executing BODY.  The previous values are restored
-     when the form finishes.  The argument VARIABLES should be a list of
-     pairs of strings of the form ‘(VAR VALUE)’, where VAR is the name
-     of the environment variable and VALUE is that variable’s value.
-
-          (with-environment-variables (("LANG" "C")
-                                       ("LANGUAGE" "en_US:en"))
-            (call-process "ls" nil t))
-
-     *Note System Environment: (elisp)System Environment.
-
- -- Function: color-dark-p rgb
-     Whether RGB is more readable against white than black.  RGB is a
-     3-element list (R G B), each component in the range [0,1].  This
-     predicate can be used both for determining a suitable (black or
-     white) contrast color with RGB as background and as foreground.
-
- -- Function: color-values-from-color-spec spec
-     Convert the textual color specification SPEC to a color triple
-     ‘(RED GREEN blue)’.  Each of RED, GREEN and ‘blue’ is a integer
-     value between 0 and 65535.
-
-     The specification SPEC can be one of the following
-        • ‘#RGB’, where R, G and B are hex numbers of equal length, 1-4
-          digits each.
-        • ‘rgb:R/G/B’, where R, G, and B are hex numbers, 1-4 digits
-          each.
-        • ‘rgbi:R/G/B’, where R, G and B are floating-point numbers in
-          [0,1].
-
- -- Function: file-modes-number-to-symbolic modes
-     This function converts a numeric file mode specification in MODES
-     into the equivalent symbolic form.
-
-     *Note Changing Files: (elisp)Changing Files.
-
- -- Function: file-backup-file-names filename
-     This function returns a list of all the backup file names for
-     FILENAME, or ‘nil’ if there are none.  The files are sorted by
-     modification time, descending, so that the most recent files are
-     first.
-
-     *Note (elisp)Backup Names::.
-
- -- Function: make-lock-file-name filename
-     Return a string containing a lock file name for FILENAME, obeying
-     ‘lock-file-name-transforms’.
-
- -- Function: decoded-time-period time
-     Interpret TIME as a period and return its length in seconds.  For
-     computational purposes, years are 365 days long and months are 30
-     days long.
-
- -- Function: subr-primitive-p object
-     Return ‘t’ if OBJECT is a primitive, built-in function.  On systems
-     with native compilation ‘subrp’ does not distinguish between
-     built-in functions and functions that have been compiled.  If
-     native compilation is not available, this function behaves
-     identically to ‘subrp’.
-
- -- Function: subr-native-elisp-p object
-     Return ‘t’ if OBJECT if the object is native compiled lisp.  If
-     native compilation is not available, this function always returns
-     ‘nil’.
-
- -- Macro: with-window-non-dedicated window &rest body
-     Evaluate BODY with WINDOW temporarily made non-dedicated.  If
-     WINDOW is nil, use the selected window.  Return the value of the
-     last form in BODY.
-
-2.4.2 Extended Definitions
---------------------------
-
-These functions must be called explicitly via ‘compat-call’, since their
-calling convention or behavior was extended in Emacs 28.1:
-
- -- Function: compat-call string-width string &optional from to
-     This function returns the width in columns of the string STRING, if
-     it were displayed in the current buffer and the selected window.
-     Optional arguments FROM and TO specify the substring of STRING to
-     consider, and are interpreted as in ‘substring’ (*note
-     (elisp)Creating Strings::).
-
-     The return value is an approximation: it only considers the values
-     returned by ‘char-width’ for the constituent characters, always
-     takes a tab character as taking ‘tab-width’ columns, ignores
-     display properties and fonts, etc.
-
-     *Note (elisp)Size of Displayed Text::.
-
-     This compatibility version handles the optional arguments FROM and
-     TO.
-
- -- Function: compat-call count-windows
-     Return the number of live windows on the selected frame.
-
-     The optional argument MINIBUF specifies whether the minibuffer
-     window is included in the count.
-
-     If ALL-FRAMES is non-‘nil’, count the windows in all frames instead
-     just the selected frame.
-
-     This compatibility version handles the optional argument
-     ALL-FRAMES.
-
-2.4.3 Missing Definitions
--------------------------
-
-Compat does not provide support for the following Lisp features
-implemented in 28.1:
-
-   • Support for ‘interactive’ or ‘declare’ to list applicable modes.
-   • Support for ‘:interactive’ argument to ‘define-minor-mode’ and
-     ‘define-derived-mode’.
-   • Support for ‘:predicate’ argument to
-     ‘define-globalized-minor-mode’.
-   • Support for the ‘:success’ handler of ‘condition-case’.
-   • The function ‘benchmark-call’.
-   • Additional Edebug keywords.
-   • The libjansson JSON APIs, e.g., ‘json-parse-string’.
-   • The macro ‘pcase-setq’.
-   • The function ‘custom-add-choice’.
-   • The functions ‘dom-print’ and ‘dom-remove-attribute’.
-   • The function ‘dns-query-asynchronous’.
-   • The function ‘get-locale-names’.
-   • The functions ‘mail-header-parse-addresses-lax’ and
-     ‘mail-header-parse-address-lax’.
-   • The function ‘num-processors’.
-   • The function ‘object-intervals’.
-   • The function ‘require-theme’.
-   • The function ‘syntax-class-to-char’.
-   • The function ‘path-separator’.
-   • The function ‘null-device’.
-   • The function ‘macroexp-compiling-p’.
-   • The function ‘split-string-shell-command’.
-   • The function ‘string-limit’.
-   • The functions ‘innermost-minibuffer-p’ and
-     ‘minibuffer-innermost-command-loop-p’.
-   • The function ‘max-mini-window-lines’.
-   • The function ‘lock-file’ and ‘unlock-file’.
-   • The ‘multisession’ library.
-
-\1f
-File: doc0jZUSv.info,  Node: Emacs 29.1,  Prev: Emacs 28.1,  Up: Support
-
-2.5 Emacs 29.1
-==============
-
-2.5.1 Added Definitions
------------------------
-
-The following functions and macros are implemented in Emacs 29.1.  These
-functions are made available by Compat on Emacs versions older than
-29.1.  Note that due to upstream changes, it might happen that there
-will be the need for changes, so use these functions with care.
-
-   The ‘defcustom’ type ‘key’ introduced in Emacs 28.1 is made available
-by Compat.
-
- -- Function: count-sentences start end
-     Count sentences in current buffer from START to END.
-
- -- Function: readablep object
-     This predicate says whether OBJECT has “readable syntax”, i.e., it
-     can be written out and then read back by the Emacs Lisp reader.  If
-     it can’t, this function returns ‘nil’; if it can, this function
-     returns a printed representation (via ‘prin1’).
-
- -- Function: substitute-quotes string
-     This function works like ‘substitute-command-keys’, but only
-     replaces quote characters.
-
- -- Function: get-scratch-buffer-create
-     Return the *scratch* buffer, creating a new one if needed.
-
- -- Function: use-region-noncontiguous-p
-     Return non-nil for a non-contiguous region if ‘use-region-p’.
-
- -- Function: use-region-end
-     Return the end of the region if ‘use-region-p’.
-
- -- Function: use-region-beginning
-     Return the start of the region if ‘use-region-p’.
-
- -- Macro: buffer-local-set-state variable value...
-     Minor modes often set buffer-local variables that affect some
-     features in Emacs.  When a minor mode is switched off, the mode is
-     expected to restore the previous state of these variables.  This
-     convenience macro helps with doing that: It works much like
-     ‘setq-local’, but returns an object that can be used to restore
-     these values back to their previous values/states (using the
-     companion function ‘buffer-local-restore-state’).
-
- -- Function: delete-line
-     Delete the current line.
-
- -- Function: list-of-strings-p object
-     Return ‘t’ if OBJECT is ‘nil’ or a list of strings.
-
- -- Function: plistp object
-     Non-nil if and only if OBJECT is a valid plist.
-
- -- Macro: with-memoization PLACE CODE...
-     This macro provides a simple way to do memoization.  CODE is
-     evaluated and then stashed in PLACE.  If PLACE’s value is
-     non-‘nil’, return that value instead of evaluating CODE.
-
- -- Special Form: with-restriction start end [:label label] body
-     This special form saves the current bounds of the accessible
-     portion of the buffer, sets the accessible portion to start at
-     START and end at END, evaluates the BODY forms, and restores the
-     saved bounds.  In that case it is equivalent to
-
-          (save-restriction
-            (narrow-to-region start end)
-            body)
-
-     When the optional argument LABEL, a symbol, is present, the
-     narrowing is “labeled”.  A labeled narrowing differs from a
-     non-labeled one in several ways:
-
-        • During the evaluation of the BODY form, ‘narrow-to-region’ and
-          ‘widen’ can be used only within the START and END limits.
-
-        • To lift the restriction introduced by ‘with-restriction’ and
-          gain access to other portions of the buffer, use
-          ‘without-restriction’ with the same LABEL argument.  (Another
-          way to gain access to other portions of the buffer is to use
-          an indirect buffer (*note (elisp)Indirect Buffers::).)
-
-        • Labeled narrowings can be nested.
-
-        • Labeled narrowings can only be used in Lisp programs: they are
-          never visible on display, and never interfere with narrowings
-          set by the user.
-
-     If you use ‘with-restriction’ with the optional LABEL argument, we
-     recommend documenting the LABEL in the doc strings of the functions
-     which use it, so that other Lisp programs your code calls could
-     lift the labeled narrowing if and when it needs.
-
- -- Special Form: without-restriction [:label label] body
-     This special form saves the current bounds of the accessible
-     portion of the buffer, widens the buffer, evaluates the BODY forms,
-     and restores the saved bounds.  In that case it is equivalent to
-
-          (save-restriction
-            (widen)
-            body)
-
-     When the optional argument LABEL is present, the narrowing set by
-     ‘with-restriction’ with the same LABEL argument is lifted.
-
- -- Function: pos-bol &optional count
-     Like ‘line-beginning-position’, but ignores fields (and is more
-     efficient).
-
- -- Function: pos-eol &optional count
-     Like ‘line-end-position’, but ignores fields (and is more
-     efficient).
-
- -- Macro: with-delayed-message (timeout message) body...
-     Sometimes it’s unclear whether an operation will take a long time
-     to execute or not, or it can be inconvenient to implement a
-     progress reporter.  This macro can be used in those situations.
-
-          (with-delayed-message (2 (format "Gathering data for %s" entry))
-            (setq data (gather-data entry)))
-
-     In this example, if the body takes more than two seconds to
-     execute, the message will be displayed.  If it takes a shorter time
-     than that, the message won’t be displayed.  In either case, the
-     body is evaluated as normally, and the return value of the final
-     element in the body is the return value of the macro.
-
-     The MESSAGE element is evaluated before BODY, and is always
-     evaluated, whether the message is displayed or not.
-
- -- Function: funcall-with-delayed-message timeout message function
-     Like ‘funcall’, but display MESSAGE if FUNCTION takes longer than
-     TIMEOUT.  TIMEOUT is a number of seconds, and can be an integer or
-     a floating point number.
-
-     If FUNCTION takes less time to execute than TIMEOUT seconds,
-     MESSAGE is not displayed.
-
- -- Function: buttonize string callback &optional data help-echo
-     Sometimes it’s more convenient to make a string into a button
-     without inserting it into a buffer immediately, for instance when
-     creating data structures that may then, later, be inserted into a
-     buffer.  This function makes STRING into such a string, and
-     CALLBACK will be called when the user clicks on the button.  The
-     optional DATA parameter will be used as the parameter when CALLBACK
-     is called.  If ‘nil’, the button is used as the parameter instead.
-
- -- Function: buttonize-region start end callback &optional data
-          help-echo
-     Make the region between START and END into a button.  When clicked,
-     CALLBACK will be called with the DATA as the function argument.  If
-     DATA isn’t present (or is nil), the button itself will be used
-     instead as the function argument.  If HELP-ECHO, use that as the
-     help-echo property.
-
- -- Function: get-display-property position prop &optional object
-          properties
-     This convenience function can be used to get a specific display
-     property, no matter whether the ‘display’ property is a vector, a
-     list or a simple property.  This is like ‘get-text-property’ (*note
-     Examining Properties: (elisp)Examining Properties.), but works on
-     the ‘display’ property only.
-
-     POSITION is the position in the buffer or string to examine, and
-     PROP is the ‘display’ property to return.  The optional OBJECT
-     argument should be either a string or a buffer, and defaults to the
-     current buffer.  If the optional PROPERTIES argument is non-‘nil’,
-     it should be a ‘display’ property, and in that case, POSITION and
-     OBJECT are ignored.  (This can be useful if you’ve already gotten
-     the ‘display’ property with ‘get-char-property’, for instance
-     (*note Examining Properties: (elisp)Examining Properties.).
-
- -- Function: add-display-text-property start end prop value &optional
-          object
-     Add display property PROP with VALUE to the text from START to END.
-     If any text in the region has a non-nil ‘display’ property, those
-     properties are retained.
-
-     If OBJECT is non-‘nil’, it should be a string or a buffer.  If
-     ‘nil’, this defaults to the current buffer.
-
- -- Function: take n list
-     This function returns the N first elements of LIST.  Essentially,
-     it returns the part of LIST that ‘nthcdr’ skips.
-
-     ‘take’ returns LIST if shorter than N elements; it returns ‘nil’ if
-     N is zero or negative.
-
-          (take 3 '(a b c d))
-               ⇒ (a b c)
-          (take 10 '(a b c d))
-               ⇒ (a b c d)
-          (take 0 '(a b c d))
-               ⇒ nil
-
- -- Function: ntake n list
-     This is a version of ‘take’ that works by destructively modifying
-     the list structure of the argument.  That makes it faster, but the
-     original value of LIST may be lost.
-
-     ‘ntake’ returns LIST unmodified if shorter than N elements; it
-     returns ‘nil’ if N is zero or negative.  Otherwise, it returns LIST
-     truncated to its first N elements.
-
-     This means that it is usually a good idea to use the return value
-     and not just rely on the truncation effect unless N is known to be
-     positive.
-
- -- Function: compiled-function-p object
-     This function returns ‘t’ if OBJECT is a function object that is
-     not in the form of ELisp source code but something like machine
-     code or byte code instead.  More specifically it returns ‘t’ if the
-     function is built-in, or byte-compiled, or natively-compiled, or a
-     function loaded from a dynamic module.
-
- -- Function: function-alias-p object &optional noerror
-     Checks whether OBJECT is a function alias.  If it is, it returns a
-     list of symbols representing the function alias chain, else ‘nil’.
-     For instance, if ‘a’ is an alias for ‘b’, and ‘b’ is an alias for
-     ‘c’:
-
-          (function-alias-p 'a)
-              ⇒ (b c)
-
-     If there’s a loop in the definitions, an error will be signalled.
-     If NOERROR is non-‘nil’, the non-looping parts of the chain is
-     returned instead.
-
- -- Function: string-equal-ignore-case string1 string2
-     ‘string-equal-ignore-case’ compares strings ignoring case
-     differences, like ‘char-equal’ when ‘case-fold-search’ is ‘t’.
-
-     *Note (elisp)Text Comparison::.
-
- -- Function: string-split string &optional separators omit-nulls trim
-     ‘string-split’ is an alias for the function ‘split-string’.  The
-     name follows the convention of other string functions.
-
-     *Note (elisp)Creating Strings::.
-
- -- Function: buffer-match-p condition buffer-or-name &optional arg
-     This function checks if a buffer designated by ‘buffer-or-name’
-     satisfies a ‘condition’.  Optional third argument ARG is passed to
-     the predicate function in CONDITION.  A condition can be one of the
-     following:
-        • A string, interpreted as a regular expression.  The buffer
-          satisfies the condition if the regular expression matches the
-          buffer name.
-        • A predicate function, which should return non-‘nil’ if the
-          buffer matches.  If the function expects one argument, it is
-          called with BUFFER-OR-NAME as the argument; if it expects 2
-          arguments, the first argument is BUFFER-OR-NAME and the second
-          is ARG (or ‘nil’ if ARG is omitted).
-        • A cons-cell ‘(OPER . EXPR)’ where OPER is one of
-          ‘not’
-               Satisfied if EXPR doesn’t satisfy ‘buffer-match-p’ with
-               the same buffer and ‘arg’.
-          ‘or’
-               Satisfied if EXPR is a list and _any_ condition in EXPR
-               satisfies ‘buffer-match-p’, with the same buffer and
-               ‘arg’.
-          ‘and’
-               Satisfied if EXPR is a list and _all_ conditions in EXPR
-               satisfy ‘buffer-match-p’, with the same buffer and ‘arg’.
-          ‘derived-mode’
-               Satisfied if the buffer’s major mode derives from EXPR.
-          ‘major-mode’
-               Satisfied if the buffer’s major mode is equal to EXPR.
-               Prefer using ‘derived-mode’ instead when both can work.
-        • t Satisfied by any buffer.  A convenient alternative to ‘""’
-          (empty string), ‘(and)’ (empty conjunction) or ‘always’.
-
-     *Note (elisp)Buffer List::.
-
- -- Function: match-buffers condition &optional buffers arg
-     This function returns a list of all buffers that satisfy a
-     ‘condition’, as defined for ‘buffer-match-p’.  By default all
-     buffers are considered, but this can be restricted via the second
-     optional ‘buffer-list’ argument.  Optional third argument ARG will
-     be used by CONDITION in the same way as ‘buffer-match-p’ does.
-
-     *Note (elisp)Buffer List::.
-
- -- Function: string-glyph-split string
-     When character compositions are in effect, sequence of characters
-     can be composed for display to form _grapheme clusters_, for
-     example to display accented characters, or ligatures, or Emoji, or
-     when complex text shaping requires that for some scripts.  When
-     that happens, characters no longer map in a simple way to display
-     columns, and display layout decisions with such strings, such as
-     truncating too wide strings, can be a complex job.  This function
-     helps in performing suvh jobs: it splits up its argument STRING
-     into a list of substrings, where each substring produces a single
-     grapheme cluster that should be displayed as a unit.  Lisp programs
-     can then use this list to construct visually-valid substrings of
-     STRING which will look correctly on display, or compute the width
-     of any substring of STRING by adding the width of its constituents
-     in the returned list, etc.
-
-     For instance, if you want to display a string without the first
-     glyph, you can say:
-
-          (apply #'insert (cdr (string-glyph-split string))))
-
-     *Note (elisp)Size of Displayed Text::.
-
- -- Macro: with-buffer-unmodified-if-unchanged &rest body...
-     Evaluate BODY like ‘progn’, but change buffer-modified status only
-     if buffer text changes.  If the buffer was unmodified before
-     execution of BODY, and buffer text after execution of BODY is
-     identical to what it was before, ensure that buffer is still marked
-     unmodified afterwards.
-
-     Note that only changes in the raw byte sequence of the buffer text,
-     as stored in the internal representation, are monitored for the
-     purpose of detecting the lack of changes in buffer text.  Any other
-     changes that are normally perceived as "buffer modifications", such
-     as changes in text properties, ‘buffer-file-coding-system’, buffer
-     multibyteness, etc.  – will not be noticed, and the buffer will
-     still be marked unmodified, effectively ignoring those changes.
-
- -- Function: file-attribute-file-identifier
-     Return the fields ‘(inodenum device)’ as a list from attributes
-     generated by ‘file-attributes’.
-
-     *Note (elisp)File Attributes::.
-
- -- Function: file-name-split filename
-     This function splits a file name into its components, and can be
-     thought of as the inverse of ‘string-join’ with the appropriate
-     directory separator.  For example,
-
-          (file-name-split "/tmp/foo.txt")
-              ⇒ ("" "tmp" "foo.txt")
-          (string-join (file-name-split "/tmp/foo.txt") "/")
-              ⇒ "/tmp/foo.txt"
-
- -- Function: file-name-parent-directory filename
-     This function returns the directory name of the parent directory of
-     FILENAME.  If FILENAME is at the root directory of the filesystem,
-     it returns ‘nil’.  A relative FILENAME is assumed to be relative to
-     ‘default-directory’, and the return value will also be relative in
-     that case.  If the return value is non-‘nil’, it ends in a slash.
-
-     *Note (elisp)Directory Names::.
-
- -- Function: file-has-changed-p file &optional tag
-     This function returns non-‘nil’ if the time stamp of FILENAME has
-     changed since the last call.  When called for the first time for
-     some FILENAME, it records the last modification time and size of
-     the file, and returns non-‘nil’ when FILENAME exists.  Thereafter,
-     when called for the same FILENAME, it compares the current time
-     stamp and size with the recorded ones, and returns non-‘nil’ only
-     if either the time stamp or the size (or both) are different.  This
-     is useful when a Lisp program wants to re-read a file whenever it
-     changes.  With an optional argument TAG, which must be a symbol,
-     the size and modification time comparisons are limited to calls
-     with the same tag.
-
-     *Note (elisp)File Attributes::.
-
- -- Function: directory-abbrev-make-regexp directory
-     Create a regexp to match DIRECTORY for ‘directory-abbrev-alist’.
-
- -- Function: directory-abbrev-apply filename
-     Apply the abbreviations in ‘directory-abbrev-alist’ to FILENAME.
-     Note that when calling this, you should set ‘case-fold-search’ as
-     appropriate for the filesystem used for FILENAME.
-
- -- Function: key-valid-p keys
-     Say whether KEYS is a valid key.  A key is a string consisting of
-     one or more key strokes.  The key strokes are separated by single
-     space characters.
-
-     Each key stroke is either a single character, or the name of an
-     event, surrounded by angle brackets.  In addition, any key stroke
-     may be preceded by one or more modifier keys.  Finally, a limited
-     number of characters have a special shorthand syntax.
-
-     Here’s some example key sequences.
-
-     ‘f’
-          The key ‘f’.
-     ‘S o m’
-          A three key sequence of the keys ‘S’, ‘o’ and ‘m’.
-     ‘C-c o’
-          A two key sequence of the keys ‘c’ with the control modifier
-          and then the key ‘o’.
-     ‘H-<left>’
-          The key named "left" with the hyper modifier.
-     ‘M-RET’
-          The "return" key with a meta modifier.
-     ‘C-M-<space>’
-          The "space" key with both the control and meta modifiers.
-
-     These are the characters that have shorthand syntax: ‘NUL’, ‘RET’,
-     ‘TAB’, ‘LFD’, ‘ESC’, ‘SPC’, ‘DEL’.
-
-     Modifiers have to be specified in this order
-     Alt (A)-Control (C)-Hyper (H)-Meta (M)-Shift (s)-Super (s)
-
- -- Function: key-parse keys
-     Convert KEYS to the internal Emacs key representation.  See
-     ‘key-valid-p’ for a description of valid key sequences.  Examples
-     include ‘f’, ‘C-c C-c’, ‘H-<left>’, ‘M-RET’ or ‘C-M-<return>’.
-
- -- Function: keymap-set keymap key definition
-     This function sets the binding for KEY in KEYMAP.  (If KEY is more
-     than one event long, the change is actually made in another keymap
-     reached from KEYMAP.)  The argument BINDING can be any Lisp object,
-     but only certain types are meaningful.  (For a list of meaningful
-     types, see *note (elisp)Key Lookup::.)  The value returned by
-     ‘keymap-set’ is BINDING.
-
-     If KEY is ‘<t>’, this sets the default binding in KEYMAP.  When an
-     event has no binding of its own, the Emacs command loop uses the
-     keymap’s default binding, if there is one.
-
-     Every prefix of KEY must be a prefix key (i.e., bound to a keymap)
-     or undefined; otherwise an error is signaled.  If some prefix of
-     KEY is undefined, then ‘keymap-set’ defines it as a prefix key so
-     that the rest of KEY can be defined as specified.
-
-     If there was previously no binding for KEY in KEYMAP, the new
-     binding is added at the beginning of KEYMAP.  The order of bindings
-     in a keymap makes no difference for keyboard input, but it does
-     matter for menu keymaps (*note (elisp)Menu Keymaps::).
-
-     *Note (elisp)Changing Key Bindings::.
-
- -- Function: keymap-global-set key command
-     This function sets the binding of KEY in the current global map to
-     BINDING.
-
-          (keymap-global-set KEY BINDING)
-          ≡
-          (keymap-set (current-global-map) KEY BINDING)
-
-     *Note (elisp)Key Binding Commands::.
-
- -- Function: keymap-local-set key command
-     This function sets the binding of KEY in the current local keymap
-     to BINDING.
-
-          (keymap-local-set KEY BINDING)
-          ≡
-          (keymap-set (current-local-map) KEY BINDING)
-
-     *Note (elisp)Key Binding Commands::.
-
- -- Function: keymap-global-unset key &optional remove
-     This function removes the binding of KEY from the current global
-     map.
-
-     One use of this function is in preparation for defining a longer
-     key that uses KEY as a prefix—which would not be allowed if KEY has
-     a non-prefix binding.  For example:
-
-          (keymap-global-unset "C-l")
-              ⇒ nil
-          (keymap-global-set "C-l C-l" 'redraw-display)
-              ⇒ nil
-
-     *Note (elisp)Key Binding Commands::.
-
- -- Function: keymap-local-unset key &optional remove
-     This function removes the binding of KEY from the current local
-     map.
-
-     *Note (elisp)Key Binding Commands::.
-
- -- Function: keymap-substitute keymap olddef newdef &optional oldmap
-          prefix
-     Replace OLDDEF with NEWDEF for any keys in KEYMAP now defined as
-     OLDDEF.  In other words, OLDDEF is replaced with NEWDEF wherever it
-     appears.  Alternatively, if optional fourth argument OLDMAP is
-     specified, we redefine in KEYMAP as NEWDEF those keys that are
-     defined as OLDDEF in OLDMAP.
-
- -- Function: keymap-lookup keymap key &optional accept-default no-remap
-          position
-     This function returns the definition of KEY in KEYMAP.  All the
-     other functions described in this chapter that look up keys use
-     ‘keymap-lookup’.  Here are examples:
-
-          (keymap-lookup (current-global-map) "C-x C-f")
-              ⇒ find-file
-          (keymap-lookup (current-global-map) "C-x C-f 1 2 3 4 5")
-              ⇒ 2
-
-     *Note (elisp)Functions for Key Lookup::.
-
- -- Function: keymap-local-lookup keys &optional accept-default
-     Like ‘keymap-lookup’, but restricting the search for commands bound
-     to KEYS to the current local keymap.
-
- -- Function: keymap-global-lookup keys &optional accept-default
-     Like ‘keymap-lookup’, but restricting the search for commands bound
-     to KEYS to the current global keymap.
-
- -- Function: define-keymap &rest definitions
-     You can create a keymap with the functions described above, and
-     then use ‘keymap-set’ (*note (elisp)Changing Key Bindings::) to
-     specify key bindings in that map.  When writing modes, however, you
-     frequently have to bind a large number of keys at once, and using
-     ‘keymap-set’ on them all can be tedious and error-prone.  Instead
-     you can use ‘define-keymap’, which creates a keymap and binds a
-     number of keys.  Here’s a very basic example:
-
-          (define-keymap
-            "n" #'forward-line
-            "f" #'previous-line
-            "C-c C-c" #'quit-window)
-
-     This function creates a new sparse keymap, defines the keystrokes
-     in PAIRS, and returns the new keymap.
-
-     PAIRS is a list of alternating key bindings and key definitions, as
-     accepted by ‘keymap-set’.  In addition, the key can be the special
-     symbol ‘:menu’, in which case the definition should be a menu
-     definition as accepted by ‘easy-menu-define’ (*note (elisp)Easy
-     Menu::).  Here’s a brief example of this usage:
-
-          (define-keymap :full t
-            "g" #'eww-reload
-            :menu '("Eww"
-                    ["Exit" quit-window t]
-                    ["Reload" eww-reload t]))
-
-     A number of keywords can be used before the key/definition pairs to
-     change features of the new keymap.  If any of the feature keywords
-     is missing from the ‘define-keymap’ call, the default value for
-     that feature is ‘nil’.  Here’s a list of the available feature
-     keywords:
-
-     ‘:full’
-          If non-‘nil’, create a char-table keymap (as from
-          ‘make-keymap’) instead of a sparse keymap (as from
-          ‘make-sparse-keymap’ (*note (elisp)Creating Keymaps::).  A
-          sparse keymap is the default.
-
-     ‘:parent’
-          If non-‘nil’, the value should be a keymap to use as the
-          parent (*note (elisp)Inheritance and Keymaps::).
-
-     ‘:keymap’
-          If non-‘nil’, the value should be a keymap.  Instead of
-          creating a new keymap, the specified keymap is modified
-          instead.
-
-     ‘:suppress’
-          If non-‘nil’, the keymap will be suppressed with
-          ‘suppress-keymap’ (*note (elisp)Changing Key Bindings::).  By
-          default, digits and the minus sign are exempt from
-          suppressing, but if the value is ‘nodigits’, this suppresses
-          digits and minus-sign like it does with other characters.
-
-     ‘:name’
-          If non-‘nil’, the value should be a string to use as the menu
-          for the keymap if you use it as a menu with ‘x-popup-menu’
-          (*note (elisp)Pop-Up Menus::).
-
-     ‘:prefix’
-          If non-‘nil’, the value should be a symbol to be used as a
-          prefix command (*note (elisp)Prefix Keys::).  If this is the
-          case, this symbol is returned by ‘define-keymap’ instead of
-          the map itself.
-
- -- Function: defvar-keymap (variable-name &rest defs)
-     By far, the most common thing to do with a keymap is to bind it to
-     a variable.  This is what virtually all modes do—a mode called
-     ‘foo’ almost always has a variable called ‘foo-mode-map’.
-
-     This macro defines NAME as a variable, passes OPTIONS and PAIRS to
-     ‘define-keymap’, and uses the result as the default value for the
-     variable.
-
-     OPTIONS is like the keywords in ‘define-keymap’, but there’s an
-     additional ‘:doc’ keyword that provides the doc string for the
-     defined variable.
-
-     Here’s an example:
-
-          (defvar-keymap eww-textarea-map
-            :parent text-mode-map
-            "RET" #'forward-line
-            "TAB" #'shr-next-link)
-
- -- Macro: while-let spec then-forms...
-     Like ‘when-let’, but repeat until a binding in SPEC is ‘nil’.  The
-     return value is always ‘nil’.
-
-     This is comparable to ‘and-let*’.
-
- -- Macro: ert-with-temp-file name &rest body
-     Bind NAME to the name of a new temporary file and evaluate BODY.
-     Delete the temporary file after BODY exits normally or non-locally.
-     NAME will be bound to the file name of the temporary file.  See the
-     docstring for supported keyword arguments.
-
- -- Macro: ert-with-temp-directory name &rest body
-     Bind NAME to the name of a new temporary directory and evaluate
-     BODY.  Delete the temporary directory after BODY exits normally or
-     non-locally.
-
-     NAME is bound to the directory name, not the directory file name.
-     (In other words, it will end with the directory delimiter; on
-     Unix-like systems, it will end with "/".)
-
-     The same keyword arguments are supported as in ‘ert-with-temp-file’
-     (which see), except for ‘:text’.
-
- -- Function: cl-constantly value
-     Return a function that takes any number of arguments, but returns
-     VALUE.
-
- -- Macro: cl-with-gensyms names... body
-     This macro expands to code that executes BODY with each of the
-     variables in NAMES bound to a fresh uninterned symbol, or “gensym”,
-     in Common Lisp parlance.  For macros requiring more than one
-     gensym, use of ‘cl-with-gensyms’ shortens the code and renders
-     one’s intentions clearer.  Compare:
-
-          (defmacro my-macro (foo)
-            (let ((bar (gensym "bar"))
-                  (baz (gensym "baz"))
-                  (quux (gensym "quux")))
-              `(let ((,bar (+ ...)))
-                 ...)))
-
-          (defmacro my-macro (foo)
-            (cl-with-gensyms (bar baz quux)
-              `(let ((,bar (+ ...)))
-                 ...)))
-
- -- Macro: cl-once-only ((variable form)...) body
-     This macro is primarily to help the macro programmer ensure that
-     forms supplied by the user of the macro are evaluated just once by
-     its expansion even though the result of evaluating the form is to
-     occur more than once.  Less often, this macro is used to ensure
-     that forms supplied by the macro programmer are evaluated just
-     once.
-
-     Each VARIABLE may be used to refer to the result of evaluating FORM
-     in BODY.  ‘cl-once-only’ binds each VARIABLE to a fresh uninterned
-     symbol during the evaluation of BODY.  Then, ‘cl-once-only’ wraps
-     the final expansion in code to evaluate each FORM and bind the
-     result to the corresponding uninterned symbol.  Thus, when the
-     macro writer substitutes the value for VARIABLE into the expansion
-     they are effectively referring to the result of evaluating FORM,
-     rather than FORM itself.  Another way to put this is that each
-     VARIABLE is bound to an expression for the (singular) result of
-     evaluating FORM.
-
-     The most common case is where VARIABLE is one of the arguments to
-     the macro being written, so ‘(variable variable)’ may be
-     abbreviated to just ‘variable’.
-
-     For example, consider this macro:
-
-          (defmacro my-list (x y &rest forms)
-            (let ((x-result (gensym))
-                  (y-result (gensym)))
-              `(let ((,x-result ,x)
-                     (,y-result ,y))
-                 (list ,x-result ,y-result ,x-result ,y-result
-                       (progn ,@forms))))
-
-     In a call like ‘(my-list (pop foo) ...)’ the intermediate binding
-     to ‘x-result’ ensures that the ‘pop’ is not done twice.  But as a
-     result the code is rather complex: the reader must keep track of
-     how ‘x-result’ really just means the first parameter of the call to
-     the macro, and the required use of multiple gensyms to avoid
-     variable capture by ‘(progn ,@forms)’ obscures things further.
-     ‘cl-once-only’ takes care of these details:
-
-          (defmacro my-list (x y &rest forms)
-            (cl-once-only (x y)
-              `(list ,x ,y ,x ,y
-                     (progn ,@forms))))
-
-2.5.2 Extended Definitions
---------------------------
-
-These functions must be called explicitly via ‘compat-call’, since their
-calling convention or behavior was extended in Emacs 29.1:
-
- -- Function: compat-call set-transient-map keymap &optional keep-pred
-          on-exit message timeout
-     This function adds KEYMAP as a “transient” keymap, which takes
-     precedence over other keymaps for one (or more) subsequent keys.
-
-     Normally, KEYMAP is used just once, to look up the very next key.
-     If the optional argument KEEP-PRED is ‘t’, the map stays active as
-     long as the user types keys defined in KEYMAP; when the user types
-     a key that is not in KEYMAP, the transient keymap is deactivated
-     and normal key lookup continues for that key.
-
-     The KEEP-PRED argument can also be a function.  In that case, the
-     function is called with no arguments, prior to running each
-     command, while KEYMAP is active; it should return non-‘nil’ if
-     KEYMAP should stay active.
-
-     The optional argument ON-EXIT, if non-‘nil’, specifies a function
-     that is called, with no arguments, after KEYMAP is deactivated.
-
-     The optional argument MESSAGE specifies the message to display
-     after activating the transient map.  If MESSAGE is a string, it is
-     the format string for the message, and any ‘%k’ specifier in that
-     string is replaced with the list of keys from the transient map.
-     Any other non-‘nil’ value of MESSAGE stands for the default message
-     format ‘Repeat with %k’.
-
-     If the optional argument TIMEOUT is non-‘nil’, it should be a
-     number that specifies how many seconds of idle time to wait before
-     deactivating KEYMAP.  The value of the variable
-     ‘set-transient-map-timeout’, if non-‘nil’, overrides the value of
-     this argument.
-
-     This function works by adding and removing KEYMAP from the variable
-     ‘overriding-terminal-local-map’, which takes precedence over all
-     other active keymaps (*note (Searching Keymaps)elisp::).
-
- -- Function: compat-call string-lines string &optional omit-nulls
-          keep-newlines
-     Split STRING into a list of strings on newline boundaries.  If the
-     optional argument OMIT-NULLS is non-‘nil’, remove empty lines from
-     the results.  If the optional argument KEEP-NEWLINES is non-‘nil’,
-     don’t remove the trailing newlines from the result strings.
-
-     *Note (elisp)Creating Strings::.
-
- -- Function: compat-call define-key
-     This function is like ‘keymap-set’ (*note (elisp)Changing Key
-     Bindings::, but understands only the legacy key syntaxes.
-
-     In addition, this function also has a REMOVE argument.  If it is
-     non-‘nil’, the definition will be removed.  This is almost the same
-     as setting the definition to ‘nil’, but makes a difference if the
-     KEYMAP has a parent, and KEY is shadowing the same binding in the
-     parent.  With REMOVE, subsequent lookups will return the binding in
-     the parent, whereas with a ‘nil’ definition the lookups will return
-     ‘nil’.
-
-     *Note (elisp)Low-Level Key Binding::.
-
-     This compatibility version handles the optional argument REMOVE.
-
- -- Function: compat-call plist-get plist prop &optional predicate
-     This returns the value of the PROPERTY property stored in the
-     property list PLIST.  Comparisons are done with PREDICATE, and
-     defaults to ‘eq’.  It accepts a malformed PLIST argument.  If
-     PROPERTY is not found in the PLIST, it returns ‘nil’.
-
-     *Note (elisp)Plist Access::.
-
-     This compatibility version handles the optional argument PREDICATE.
-     This is a generalized variable (*note (elisp)Generalized
-     Variables::) that can be used to change a value with ‘setf’.
-
- -- Function: compat-call plist-put plist prop val &optional predicate
-     This stores VALUE as the value of the PROPERTY property in the
-     property list PLIST.  Comparisons are done with PREDICATE, and
-     defaults to ‘eq’.  It may modify PLIST destructively, or it may
-     construct a new list structure without altering the old.  The
-     function returns the modified property list, so you can store that
-     back in the place where you got PLIST.
-
-     *Note (elisp)Plist Access::.
-
-     This compatibility version handles the optional argument PREDICATE.
-
- -- Function: compat-call plist-member plist prop &optional predicate
-     This returns non-‘nil’ if PLIST contains the given PROPERTY.
-     Comparisons are done with PREDICATE, and defaults to ‘eq’.  Unlike
-     ‘plist-get’, this allows you to distinguish between a missing
-     property and a property with the value ‘nil’.  The value is
-     actually the tail of PLIST whose ‘car’ is PROPERTY.
-
-     *Note (elisp)Plist Access::.
-
-     This compatibility version handles the optional argument PREDICATE.
-
-2.5.3 Missing Definitions
--------------------------
-
-Compat does not provide support for the following Lisp features
-implemented in 29.1:
-
-   • The function ‘imagep’.
-   • The function ‘image-at-point-p’.
-   • The function ‘function-documentation’.
-   • The macro ‘with-undo-amalgamate’.
-   • The function ‘string-glyph-split’.
-   • The function ‘string-limit’.
-   • The function ‘string-pixel-width’ and ‘buffer-text-pixel-size’.
-   • The function ‘minibuffer-lazy-highlight-setup’.
-   • The function ‘pp-emacs-lisp-code’.
-   • The functions ‘xdg-state-home’, ‘xdg-current-desktop’ and
-     ‘xdg-session-type’.
-   • The macro ‘setopt’.
-   • The ‘oclosure’ library.
-   • The ‘textsec’ library.
-   • The ‘range’ library.
-   • The ‘string-edit’ library.
-   • The ‘vtable’ library.
-   • The ‘pixel-fill’ library.
-
-\1f
-File: doc0jZUSv.info,  Node: Development,  Next: Function Index,  Prev: Support,  Up: Top
-
-3 Development
-*************
-
-Compat is developed on GitHub.
-
-   Bug reports, patches and comments are best sent to the issue tracker
-(https://github.com/emacs-compat/compat/issues).  These may include
-issues in the compatibility code, missing definitions or performance
-issues.  We also provide a development mailing list
-(https://lists.sr.ht/~pkal/compat-devel) (~pkal/compat-develNOSPAMlists.sr.ht
-<~pkal/compat-develNOSPAMlists.sr.ht>).
-
-   Please note that as a GNU ELPA package, Compat requires contributors
-to have signed the FSF copyright assignment
-(https://www.gnu.org/software/emacs/manual/html_node/emacs/Copyright-Assignment.html),
-before any non-trivial contribution (roughly 15 lines of code) can be
-applied.  It is important that you provide tests when you contribute new
-functionality.  Compat has 100% test coverage by the test suite.  We use
-continuous integration to check if patches preserve existing
-functionality.
-
-\1f
-File: doc0jZUSv.info,  Node: Function Index,  Next: Variable Index,  Prev: Development,  Up: Top
-
-Appendix A Function Index
-*************************
-
-\0\b[index\0\b]
-* Menu:
-
-* add-display-text-property:             Emacs 29.1.          (line 178)
-* alist-get:                             Emacs 25.1.          (line  82)
-* always:                                Emacs 28.1.          (line  83)
-* and-let*:                              Emacs 26.1.          (line 158)
-* assoc-delete-all:                      Emacs 26.1.          (line  13)
-* bignump:                               Emacs 27.1.          (line  55)
-* bool-vector:                           Emacs 25.1.          (line 178)
-* bounds-of-thing-at-mouse:              Emacs 28.1.          (line 292)
-* buffer-hash:                           Emacs 26.1.          (line  80)
-* buffer-local-boundp:                   Emacs 28.1.          (line 125)
-* buffer-local-restore-state:            Emacs 29.1.          (line  42)
-* buffer-local-set-state:                Emacs 29.1.          (line  42)
-* buffer-match-p:                        Emacs 29.1.          (line 246)
-* buttonize:                             Emacs 29.1.          (line 144)
-* buttonize-region:                      Emacs 29.1.          (line 153)
-* cl-constantly:                         Emacs 29.1.          (line 618)
-* cl-once-only:                          Emacs 29.1.          (line 641)
-* cl-with-gensyms:                       Emacs 29.1.          (line 622)
-* color-dark-p:                          Emacs 28.1.          (line 323)
-* color-values-from-color-spec:          Emacs 28.1.          (line 329)
-* compat-call:                           Usage.               (line  43)
-* compat-call <1>:                       Emacs 26.1.          (line 278)
-* compat-call alist-get:                 Emacs 26.1.          (line 344)
-* compat-call assoc:                     Emacs 26.1.          (line 316)
-* compat-call assoc-delete-all:          Emacs 27.1.          (line 417)
-* compat-call count-windows:             Emacs 28.1.          (line 405)
-* compat-call define-key:                Emacs 29.1.          (line 738)
-* compat-call executable-find:           Emacs 27.1.          (line 429)
-* compat-call file-size-human-readable:  Emacs 27.1.          (line 397)
-* compat-call line-number-at-pos:        Emacs 26.1.          (line 330)
-* compat-call lookup-key:                Emacs 27.1.          (line 356)
-* compat-call plist-get:                 Emacs 29.1.          (line 754)
-* compat-call plist-member:              Emacs 29.1.          (line 778)
-* compat-call plist-put:                 Emacs 29.1.          (line 766)
-* compat-call recenter:                  Emacs 27.1.          (line 346)
-* compat-call regexp-opt:                Emacs 27.1.          (line 385)
-* compat-call set-transient-map:         Emacs 29.1.          (line 693)
-* compat-call setq-local:                Emacs 27.1.          (line 370)
-* compat-call sort:                      Emacs 25.1.          (line 190)
-* compat-call string-lines:              Emacs 29.1.          (line 729)
-* compat-call string-trim:               Emacs 26.1.          (line 375)
-* compat-call string-trim-left:          Emacs 26.1.          (line 359)
-* compat-call string-trim-right:         Emacs 26.1.          (line 367)
-* compat-call string-width:              Emacs 28.1.          (line 388)
-* compat-function:                       Usage.               (line  51)
-* compiled-function-p:                   Emacs 29.1.          (line 214)
-* count-sentences:                       Emacs 29.1.          (line  17)
-* cXXXr:                                 Emacs 26.1.          (line  66)
-* cXXXXr:                                Emacs 26.1.          (line  67)
-* date-days-in-month:                    Emacs 27.1.          (line 213)
-* date-ordinal-to-time:                  Emacs 27.1.          (line 220)
-* decoded-time-day:                      Emacs 27.1.          (line 175)
-* decoded-time-dst:                      Emacs 27.1.          (line 195)
-* decoded-time-hour:                     Emacs 27.1.          (line 170)
-* decoded-time-minute:                   Emacs 27.1.          (line 165)
-* decoded-time-month:                    Emacs 27.1.          (line 180)
-* decoded-time-period:                   Emacs 28.1.          (line 360)
-* decoded-time-second:                   Emacs 27.1.          (line 160)
-* decoded-time-weekday:                  Emacs 27.1.          (line 190)
-* decoded-time-year:                     Emacs 27.1.          (line 185)
-* decoded-time-zone:                     Emacs 27.1.          (line 200)
-* define-keymap:                         Emacs 29.1.          (line 506)
-* defvar-keymap:                         Emacs 29.1.          (line 574)
-* delete-line:                           Emacs 29.1.          (line  51)
-* directory-abbrev-apply:                Emacs 29.1.          (line 370)
-* directory-abbrev-make-regexp:          Emacs 29.1.          (line 367)
-* directory-empty-p:                     Emacs 28.1.          (line 243)
-* directory-name-p:                      Emacs 25.1.          (line  56)
-* dlet:                                  Emacs 28.1.          (line 143)
-* dolist-with-progress-reporter:         Emacs 27.1.          (line 119)
-* ensure-list:                           Emacs 28.1.          (line 158)
-* ert-with-temp-directory:               Emacs 29.1.          (line 606)
-* ert-with-temp-file:                    Emacs 29.1.          (line 600)
-* file-attribute-access-time:            Emacs 26.1.          (line 223)
-* file-attribute-collect:                Emacs 26.1.          (line 260)
-* file-attribute-device-number:          Emacs 26.1.          (line 255)
-* file-attribute-file-identifier:        Emacs 29.1.          (line 327)
-* file-attribute-group-id:               Emacs 26.1.          (line 218)
-* file-attribute-inode-number:           Emacs 26.1.          (line 250)
-* file-attribute-link-number:            Emacs 26.1.          (line 208)
-* file-attribute-modes:                  Emacs 26.1.          (line 245)
-* file-attribute-modification-time:      Emacs 26.1.          (line 228)
-* file-attribute-size:                   Emacs 26.1.          (line 240)
-* file-attribute-status-change-time:     Emacs 26.1.          (line 234)
-* file-attribute-type:                   Emacs 26.1.          (line 203)
-* file-attribute-user-id:                Emacs 26.1.          (line 213)
-* file-backup-file-names:                Emacs 28.1.          (line 348)
-* file-has-changed-p:                    Emacs 29.1.          (line 352)
-* file-local-name:                       Emacs 26.1.          (line 167)
-* file-modes-number-to-symbolic:         Emacs 28.1.          (line 342)
-* file-name-concat:                      Emacs 28.1.          (line  53)
-* file-name-parent-directory:            Emacs 29.1.          (line 343)
-* file-name-quote:                       Emacs 26.1.          (line 102)
-* file-name-quoted-p:                    Emacs 26.1.          (line  95)
-* file-name-split:                       Emacs 29.1.          (line 333)
-* file-name-unquote:                     Emacs 26.1.          (line  90)
-* file-name-with-extension:              Emacs 28.1.          (line 225)
-* file-size-human-readable-iec:          Emacs 27.1.          (line 251)
-* fixnump:                               Emacs 27.1.          (line  60)
-* flatten-tree:                          Emacs 27.1.          (line 132)
-* format-message:                        Emacs 25.1.          (line  44)
-* format-prompt:                         Emacs 28.1.          (line 254)
-* funcall-with-delayed-message:          Emacs 29.1.          (line 136)
-* function-alias-p:                      Emacs 29.1.          (line 221)
-* garbage-collect-maybe:                 Emacs 28.1.          (line  68)
-* gensym:                                Emacs 26.1.          (line  70)
-* get-display-property:                  Emacs 29.1.          (line 161)
-* get-scratch-buffer-create:             Emacs 29.1.          (line  30)
-* hash-table-empty:                      Emacs 25.1.          (line 120)
-* if-let:                                Emacs 25.1.          (line  97)
-* if-let*:                               Emacs 26.1.          (line 149)
-* ignore-errors:                         Emacs 27.1.          (line 106)
-* image-property:                        Emacs 26.1.          (line 198)
-* insert-into-buffer:                    Emacs 28.1.          (line  92)
-* key-parse:                             Emacs 29.1.          (line 407)
-* key-valid-p:                           Emacs 29.1.          (line 375)
-* keymap-global-lookup:                  Emacs 29.1.          (line 502)
-* keymap-global-set:                     Emacs 29.1.          (line 436)
-* keymap-global-unset:                   Emacs 29.1.          (line 456)
-* keymap-local-lookup:                   Emacs 29.1.          (line 498)
-* keymap-local-set:                      Emacs 29.1.          (line 446)
-* keymap-local-unset:                    Emacs 29.1.          (line 471)
-* keymap-lookup:                         Emacs 29.1.          (line 485)
-* keymap-set:                            Emacs 29.1.          (line 412)
-* keymap-substitute:                     Emacs 29.1.          (line 477)
-* length<:                               Emacs 28.1.          (line  45)
-* length=:                               Emacs 28.1.          (line  42)
-* length>:                               Emacs 28.1.          (line  50)
-* list-of-strings-p:                     Emacs 29.1.          (line  54)
-* macroexp-file-name:                    Emacs 28.1.          (line 301)
-* macroexp-parse:                        Emacs 25.1.          (line 175)
-* macroexp-quote:                        Emacs 25.1.          (line 172)
-* macroexp-warn-and-return:              Emacs 28.1.          (line 305)
-* macroexpand-1:                         Emacs 25.1.          (line 165)
-* major-mode-restore:                    Emacs 27.1.          (line  22)
-* major-mode-suspend:                    Emacs 27.1.          (line  13)
-* make-empty-file:                       Emacs 27.1.          (line 254)
-* make-lock-file-name:                   Emacs 28.1.          (line 356)
-* make-nearby-temp-file:                 Emacs 26.1.          (line 120)
-* make-separator-line:                   Emacs 28.1.          (line  88)
-* mapcan:                                Emacs 26.1.          (line  53)
-* mark-thing-at-mouse:                   Emacs 28.1.          (line 298)
-* match-buffers:                         Emacs 29.1.          (line 280)
-* minibuffer-history-value:              Emacs 27.1.          (line  32)
-* named-let:                             Emacs 28.1.          (line 207)
-* ntake:                                 Emacs 29.1.          (line 201)
-* package-get-version:                   Emacs 27.1.          (line 205)
-* plistp:                                Emacs 29.1.          (line  57)
-* pos-bol:                               Emacs 29.1.          (line 111)
-* pos-eol:                               Emacs 29.1.          (line 115)
-* process-lines-handling-status:         Emacs 28.1.          (line  20)
-* process-lines-ignore-status:           Emacs 28.1.          (line  16)
-* proper-list-p:                         Emacs 27.1.          (line  76)
-* provided-mode-derived-p:               Emacs 27.1.          (line 247)
-* read-answer:                           Emacs 26.1.          (line  17)
-* read-char-from-minibuffer:             Emacs 27.1.          (line  44)
-* read-multiple-choice:                  Emacs 26.1.          (line 185)
-* readablep:                             Emacs 29.1.          (line  20)
-* region-bounds:                         Emacs 25.1.          (line  28)
-* region-noncontiguous-p:                Emacs 25.1.          (line  34)
-* replace-regexp-in-string:              Emacs 28.1.          (line 117)
-* replace-string-in-region:              Emacs 28.1.          (line 102)
-* ring-resize:                           Emacs 27.1.          (line  28)
-* save-mark-and-excursion:               Emacs 25.1.          (line  39)
-* string-chop-newline:                   Emacs 28.1.          (line 202)
-* string-clean-whitespace:               Emacs 28.1.          (line 171)
-* string-distance:                       Emacs 27.1.          (line  86)
-* string-equal-ignore-case:              Emacs 29.1.          (line 234)
-* string-fill:                           Emacs 28.1.          (line 178)
-* string-glyph-split:                    Emacs 29.1.          (line 289)
-* string-greaterp:                       Emacs 25.1.          (line  64)
-* string-lines:                          Emacs 28.1.          (line 186)
-* string-pad:                            Emacs 28.1.          (line 193)
-* string-replace:                        Emacs 28.1.          (line  77)
-* string-search:                         Emacs 28.1.          (line  34)
-* string-split:                          Emacs 29.1.          (line 240)
-* subr-native-elisp-p:                   Emacs 28.1.          (line 372)
-* subr-primitive-p:                      Emacs 28.1.          (line 365)
-* substitute-quotes:                     Emacs 29.1.          (line  26)
-* take:                                  Emacs 29.1.          (line 187)
-* temporary-file-directory:              Emacs 26.1.          (line 137)
-* text-property-search-backward:         Emacs 27.1.          (line 332)
-* text-property-search-forward:          Emacs 27.1.          (line 260)
-* text-quoting-style:                    Emacs 28.1.          (line  28)
-* thing-at-mouse:                        Emacs 28.1.          (line 285)
-* thread-first:                          Emacs 25.1.          (line 123)
-* thread-last:                           Emacs 25.1.          (line 144)
-* time-equal-p:                          Emacs 27.1.          (line 208)
-* use-region-beginning:                  Emacs 29.1.          (line  39)
-* use-region-end:                        Emacs 29.1.          (line  36)
-* use-region-noncontiguous-p:            Emacs 29.1.          (line  33)
-* when-let:                              Emacs 25.1.          (line 115)
-* when-let*:                             Emacs 26.1.          (line 153)
-* while-let:                             Emacs 29.1.          (line 594)
-* with-buffer-unmodified-if-unchanged:   Emacs 29.1.          (line 312)
-* with-delayed-message:                  Emacs 29.1.          (line 119)
-* with-environment-variables:            Emacs 28.1.          (line 309)
-* with-existing-directory:               Emacs 28.1.          (line 132)
-* with-file-modes:                       Emacs 25.1.          (line  71)
-* with-memoization:                      Emacs 29.1.          (line  60)
-* with-minibuffer-selected-window:       Emacs 27.1.          (line  38)
-* with-restriction:                      Emacs 29.1.          (line  65)
-* with-suppressed-warnings:              Emacs 27.1.          (line  65)
-* with-window-non-dedicated:             Emacs 28.1.          (line 377)
-* without-restriction:                   Emacs 29.1.          (line  99)
-* xor:                                   Emacs 27.1.          (line 142)
-
-\1f
-File: doc0jZUSv.info,  Node: Variable Index,  Prev: Function Index,  Up: Top
-
-Appendix B Variable Index
-*************************
-
-\0\b[index\0\b]
-* Menu:
-
-* exec-path:                             Emacs 27.1.          (line 228)
-* gensym-counter:                        Emacs 26.1.          (line  77)
-* mounted-file-systems:                  Emacs 26.1.          (line 133)
-* regexp-unmatchable:                    Emacs 27.1.          (line 152)
-* set-transient-map-timeout:             Emacs 29.1.          (line 719)
-* text-quoting-style:                    Emacs 25.1.          (line  13)
-
-
-\1f
-Tag Table:
-Node: Top\7f829
-Node: Introduction\7f2258
-Node: Overview\7f2421
-Node: Usage\7f2947
-Node: Limitations\7f7161
-Node: Support\7f11945
-Node: Emacs 25.1\7f12530
-Node: Emacs 26.1\7f21932
-Node: Emacs 27.1\7f39184
-Node: Emacs 28.1\7f59581
-Node: Emacs 29.1\7f79251
-Node: Development\7f115649
-Node: Function Index\7f116669
-Node: Variable Index\7f131882
-\1f
-End Tag Table
-
-\1f
-Local Variables:
-coding: utf-8
-End:
diff --git a/elpa/compat-29.1.4.1/dir b/elpa/compat-29.1.4.1/dir
deleted file mode 100644 (file)
index de02c6e..0000000
+++ /dev/null
@@ -1,18 +0,0 @@
-This is the file .../info/dir, which contains the
-topmost node of the Info hierarchy, called (dir)Top.
-The first time you invoke Info you start off looking at this node.
-\1f
-File: dir,     Node: Top       This is the top of the INFO tree
-
-  This (the Directory node) gives a menu of major topics.
-  Typing "q" exits, "H" lists all Info commands, "d" returns here,
-  "h" gives a primer for first-timers,
-  "mEmacs<Return>" visits the Emacs manual, etc.
-
-  In Emacs, you can click mouse button 2 on a menu item or cross reference
-  to select it.
-
-* Menu:
-
-Emacs
-* Compat: (compat).             Compatibility Library for Emacs Lisp.
diff --git a/elpa/compat-29.1.4.5.signed b/elpa/compat-29.1.4.5.signed
new file mode 100644 (file)
index 0000000..e82e0d3
--- /dev/null
@@ -0,0 +1 @@
+Good signature from 645357D2883A0966 GNU ELPA Signing Agent (2023) <elpasignNOSPAMelpa.gnu.org> (trust undefined) created at 2024-03-31T11:15:02+0200 using EDDSA
\ No newline at end of file
diff --git a/elpa/compat-29.1.4.5/NEWS.org b/elpa/compat-29.1.4.5/NEWS.org
new file mode 100644 (file)
index 0000000..c466a00
--- /dev/null
@@ -0,0 +1,323 @@
+#+link:    compat-srht https://todo.sr.ht/~pkal/compat/
+#+link:    compat-gh   https://github.com/emacs-compat/compat/issues/
+#+options: toc:nil num:nil author:nil
+
+* Release of "Compat" Version 29.1.4.5
+
+- Minor optimization of ~plist-get~ and ~plist-put~.
+- Minor compatibility adjustments for the Emacs 30 development version.
+- A minimal version of =compat.el= will be part of Emacs 30. Emacs :core packages
+  can directly ~(require 'compat)~ without the ~NOERROR~ flag. Furthermore Compat
+  will not be installed unnecessarily. If a package depending on Emacs 25.1 and
+  Compat 29.1 is installed on Emacs 30.1, Compat 29.1 will not be installed from
+  ELPA, since Emacs 30.1 already provides the required functionality.
+
+(Release <2024-03-16 Sat>)
+
+* Release of "Compat" Version 29.1.4.4
+
+- Fix ~Package-Requires~ header in compat.el
+- Fix ~Maintainer~ header in compat.el
+
+(Release <2023-11-13 Mon>)
+
+* Release of "Compat" Version 29.1.4.3
+
+- compat-29: Add function =char-uppercase-p=.
+- compat-29: Add function =window-configuration-equal-p=.
+
+(Release <2023-11-04 Sat>)
+
+* Release of "Compat" Version 29.1.4.2
+
+- compat-28: Improve =make-separator-line= visuals on graphic displays.
+- compat-28: Add =native-comp-available-p=, which always returns nil.
+- compat-29: Add variable =lisp-directory=.
+
+(Release <2023-07-30 Sun>)
+
+* Release of "Compat" Version 29.1.4.1
+
+- compat-29: Add ~directory-abbrev-apply~.
+- compat-29: Add ~directory-abbrev-make-regexp~.
+
+(Release <2023-03-26 Sun>)
+
+* Release of "Compat" Version 29.1.4.0
+
+- compat-27: Drop obsolete ~compat-call dired-get-marked-files~.
+- compat-28: Add support for ~defcustom~ type ~natnum~.
+- compat-29: Add ~with-restriction~ and ~without-restriction~.
+- compat-29: Add ~cl-constantly~.
+- compat-29: Drop ~with-narrowing~ which was renamed to ~with-restriction~.
+- compat-28: Add support for ~defcustom~ type ~key~.
+
+(Release <2023-03-05 Sun>)
+
+* Release of "Compat" Version 29.1.3.4
+
+- Ensure that ~seq~ is required properly both at compile time and runtime, such
+  that compilation of downstream packages works even if Compat itself is not
+  compiled. Magit uses a complex continuous integration system, where Magit is
+  compiled and tested, while the Compat dependency is not compiled.
+- compat-28: Add ~process-lines-handling-status~ and ~process-lines-ignore-status~.
+
+(Release <2023-02-11 Sat>)
+
+* Release of "Compat" Version 29.1.3.3
+
+- compat-27: Add ~with-suppressed-warnings~.
+- compat-29: Add ~cl-with-gensyms~ and ~cl-once-only~.
+- compat-29: Load ~seq~, which is preloaded on Emacs 29.
+
+(Release <2023-02-08 Wed>)
+
+* Release of "Compat" Version 29.1.3.2
+
+- compat-26: Add ~make-temp-file~ with optional argument TEXT.
+- compat-27: Mark ~compat-call dired-get-marked-files~ as obsolete. See the
+  section limitations in the Compat manual.
+- compat-29: Add ~funcall-with-delayed-message~ and ~with-delayed-message~.
+- compat-29: Add ~ert-with-temp-file~ and ~ert-with-temp-directory~.
+- compat-29: Add ~set-transient-map~ with optional arguments MESSAGE and TIMEOUT.
+
+(Release <2023-02-01 Wed>)
+
+* Release of "Compat" Version 29.1.3.1
+
+- Fix regression, which prevented loading Compat in interpreted mode. We ensure
+  that Compat works interpreted and byte compiled by running the entire test
+  suite twice in the CI. See https://github.com/magit/magit/issues/4858 for the
+  corresponding Magit issue.
+- compat-27: Add ~file-name-unquote~.
+- compat-28: Add ~mark-thing-at-mouse~.
+- compat-29: Replace ~string-lines~ with version from Emacs 29, support optional
+  KEEP-NEWLINES argument.
+
+(Release <2023-01-25 Wed>)
+
+* Release of "Compat" Version 29.1.3.0
+
+- compat-25: Add ~hash-table-empty-p~.
+- compat-25: Add ~macroexp-parse-body~ and ~macroexp-quote~.
+- compat-25: Add ~region-noncontiguous-p~.
+- compat-25: Add ~save-mark-and-excursion~.
+- compat-26: Add ~read-answer~.
+- compat-26: Add ~region-bounds~.
+- compat-27: Add ~date-ordinal-to-time~.
+- compat-27: Add ~file-size-human-readable-iec~.
+- compat-27: Add ~major-mode-suspend~ and ~major-mode-restore~.
+- compat-27: Add ~make-decoded-time~.
+- compat-27: Add ~minibuffer-history-value~.
+- compat-27: Add ~read-char-from-minibuffer~.
+- compat-27: Add ~ring-resize~.
+- compat-28: Add ~color-dark-p~.
+- compat-28: Add ~directory-files-and-attributes~ with COUNT argument.
+- compat-28: Add ~text-quoting-style~.
+- compat-28: Add ~with-window-non-dedicated~.
+- compat-29: Add ~buffer-local-set-state~ and ~buffer-local-restore-state~.
+- compat-29: Add ~compiled-function-p~.
+- compat-29: Add ~count-sentences~.
+- compat-29: Add ~delete-line~.
+- compat-29: Add ~get-scratch-buffer-create~.
+- compat-29: Add ~list-of-strings-p~.
+- compat-29: Add ~plist-get~ generalized variable.
+- compat-29: Add ~plistp~.
+- compat-29: Add ~read-multiple-choice~ with LONG-FORM argument.
+- compat-29: Add ~readablep~.
+- compat-29: Add ~substitute-quotes~.
+- compat-29: Add ~use-region-beginning~, ~use-region-end~ and ~use-region-noncontiguous-p~.
+- compat-29: Add ~with-narrowing~.
+
+(Release <2023-01-22 Sun>)
+
+* Release of "Compat" Version 29.1.2.0
+
+- All compatibility functions are covered by tests!
+- Add links from compatibility definitions to tests.
+- BREAKING: Drop JSON parsing support (libjansson API, unused downstream).
+- BREAKING: Drop ~null-device~ (unused downstream).
+- BREAKING: Drop ~unlock-buffer~ (unused downstream).
+- compat-26: Add ~buffer-hash~.
+- compat-27: Add ~fixnump~ and ~bignump~.
+- compat-27: Add ~with-minibuffer-selected-window~.
+- compat-27: Add generalized variables for ~decoded-time-*~.
+- compat-28: Add ~macroexp-warn-and-return~.
+- compat-28: Add ~subr-native-elisp-p~.
+- compat-28: Add ~bounds-of-thing-at-mouse~.
+- compat-29: Add ~with-buffer-unmodified-if-unchanged~.
+- compat-29: Fix and test ~define-key~ with REMOVE argument.
+
+(Release <2023-01-16 Mon>)
+
+* Release of "Compat" Version 29.1.1.1
+
+- Add tests, 167 out of 203 definitions tested (82%).
+- compat-25: Improve algorithmic complexity of ~sort~.
+- compat-28: Add ~make-separator-line~.
+- compat-29: Minor fixes to ~keymap-*~ functions.
+- compat-29: Add ~with-memoization~.
+- compat-29: Add ~buttonize~ and ~buttonize-region~.
+
+(Release <2023-01-14 Sat>)
+
+* Release of "Compat" Version 29.1.1.0
+
+- The macros in ~compat-macs.el~ have been rewritten and simplified. The
+  refactoring allows to further refine the criteria under which compatibility
+  aliases, functions, macros and variables are installed.
+- Remove deprecated, prefixed compatibility functions.
+- Remove deprecated features ~compat-help~, ~compat-font-lock~ and ~compat-24~.
+- Compat uses runtime checks (~boundp~, ~fboundp~) to ensure that existing
+  definitions are never overridden, when Compat is loaded on a newer Emacs than
+  it was compiled on.
+- Compat compiles without byte compilation warnings on all supported Emacs
+  versions. Warnings are treated as errors in the test suite.
+- Compat takes great care to remove unneeded definitions at compile time. On
+  recent Emacs 29 the byte compiled files are empty and not loaded, such that
+  Compat does not any cost to the Emacs process.
+- compat-26: Fix and test ~image-property~ setter.
+- compat-26: Fix and test ~read-multiple-choice~.
+- compat-28: Fix and test ~with-existing-directory~.
+- compat-28: Drop obsolete function ~make-directory-autoloads~.
+- compat-29: Drop broken functions ~string-pixel-width~ and
+  ~buffer-text-pixel-size~. These functions had poor performance which lead to a
+  downstream issue in the doom-modeline package. If a more efficient solution is
+  possible, the function will be added back. See [[compat-gh:8]] for the bug report.
+- compat-29: Drop broken function ~string-limit~.
+- compat-29: Drop broken macro ~with-buffer-unmodified-if-unchanged~, which relied
+  on ~buffer-hash~ which does not exist on all supported Emacs versions.
+- compat-29: Add ~pos-bol~ and ~pos-eol~.
+
+(Release <2023-01-07 Sat>)
+
+* Release of "Compat" Version 29.1.0.1
+
+- Add multiple new tests for existing APIs.
+- Fix bugs in compatibility functions: ~setq-local~, ~proper-list-p, prop-match-p~,
+  ~file-name-concat~, ~replace-regexp-in-region~, ~replace-string-in-region~.
+- Add new Emacs 29 APIs. Some of them are still untested and may change. If you
+  intend to use an Emacs 29 API please be careful and if possible contribute
+  test cases. All untested functions are marked in the Compat code. Over time
+  tests for all functions will be added gradually.
+- Add the macros ~compat-call~ and ~compat-function~ to call compatibility
+  functions. Since Compat avoids overwriting already existing functions, we must
+  define separate compatibility function definitions for functions which changed
+  their calling convention or behavior. These compatibility definitions can be
+  looked up using ~compat-function~ and called with ~compat-call~. For example ~assoc~
+  can be called with a ~TESTFN~ since Emacs 26. In Emacs 25 and older the calling
+  convention was ~(assoc KEY ALIST)~. In order to use the new calling convention
+  you can use ~(compat-call assoc KEY ALIST TESTFN)~.
+- Deprecate all ~compat-*~ prefixed functions. Instead use the aforementioned
+  ~compat-call~ or ~compat-function~ macros.
+- Deprecate ~compat-help.el~ and ~compat-font-lock.el.~
+- Development moved to GitHub.
+- BREAKING: Drop broken function ~func-arity~. Using ~func-arity~ is generally
+  discouraged and the function is hard to implement properly due to all the
+  various function types. There it is unlikely that the function will get
+  reintroduced in Compat.
+- BREAKING: Drop broken function ~directory-files-recursively~. In case you need
+  this function, a patch including tests is welcome.
+- BREAKING: Drop support for Emacs 24.3. Emacs 24.4 is required now. In case you
+  still need Emacs 24.3 support, you can rely on Compat 28.1.2.2.
+
+(Release <2023-01-05 Thu>)
+
+* Release of "Compat" Version 28.1.2.2
+
+This is a minor release that hopes to address [[compat-srht:7]].
+
+(Release <2022-08-25 Thu>)
+
+* Release of "Compat" Version 28.1.2.1
+
+This is a minor release adding the following changes:
+
+- Add =derived-mode-p= defined in Emacs 27
+- Add =provided-mode-derived-p= defined in Emacs 27
+- Add =read-multiple-choice= defined in Emacs 26
+- Add =file-name-absolute-p= defined in Emacs 28
+
+The only other notable change is that the manual has been rewritten to
+include much more documentation that had been the case previously.
+
+(Release <2022-08-24 Wed>)
+
+* Release of "Compat" Version 28.1.2.0
+
+The main change of this release has been the major simplification of
+Compat's initialisation system, improving the situation around issues
+people had been reporting ([[compat-srht:4]], once again) with unconventional
+or unpopular packaging systems.
+
+In addition to this, the following functional changes have been made:
+
+- Fix =format-prompt= of an empty string as "default" argument
+- Add =decoded-time-period= defined in Emacs 28
+- Add =subr-primitive-p= defined in Emacs 28
+
+Minor improvements to manual are also part of this release.
+
+(Release <2022-07-18 Mon>)
+
+* Release of "Compat" Version 28.1.1.3
+
+This release just contains a hot-fix for an issue introduced in the
+last version, where compat.el raises an error during byte compilation.
+See [[compat-srht:4]].
+
+(Release <2022-06-19 Sun>)
+
+* Release of "Compat" Version 28.1.1.2
+
+Two main changes have necessitated a new patch release:
+
+1. Fix issues related to the loading of compat when uncompiled.  See
+   [[https://lists.sr.ht/~pkal/compat-devel/%3C20220530191000.2183047-1-jonas%40bernoul.li%3E][this thread]] for more details on the problem.
+2. Fix issues related to the loading of compat on old pre-releases
+   (think of 28.0.50). See [[https://lists.sr.ht/~pkal/compat-devel/%3Cf8635d7d-e233-448f-b325-9e850363241c%40www.fastmail.com%3E][this thread]] for more details on the
+   problem.
+
+(Released <2022-06-22 Wed>)
+
+* Release of "Compat" Version 28.1.1.1
+
+This is a minor release fixing a bug in =json-serialize=, that could
+cause unintended side-effects, not related to packages using Compat
+directly (see [[compat-srht:2]]).
+
+(Released <2022-05-05 Thu>)
+
+* Release of "Compat" Version 28.1.1.0
+
+This release mostly fixes a number of smaller bugs that were not
+identified as of 28.1.0.0.  Nevertheless these warrant a version bump,
+as some of these changes a functional.  These include:
+
+- The addition of the =file-attribute-*= accessor functions.
+- The addition of =file-attribute-collect=.
+- Improvements to the Texinfo manual (via Jonas Bernoulli's recent
+  work on =ox-texinfo=).  For the time being, the Texinfo file is
+  maintained in the repository itself, next to the =MANUAL= file.
+  This might change in the future.
+- Adding a prefix to =string-trim=, =string-trim-left= and
+  =string-trim-right= (i.e. now =compat-string-trim=,
+  =compat-string-trim-left= and =compat-string-trim-right=)
+- Improving the version inference used in the =compat-*= macros.
+  This improves the compile-time optimisation that strips away
+  functions that are known to be defined for a specific version.
+- The addition of generalised variable (=setf=) support for
+  =compat-alist-get=.
+- The addition of =image-property= and generalised variable support
+  for =image-property=.
+- The addition of the function =compat-executable-find=.
+- The addition of the function =compat-dired-get-marked-files=.
+- The addition of the function =exec-path=.
+- The addition of the function =make-lock-file-name=.
+- The addition of the function =null-device=.
+- The addition of the function =time-equal-p=.
+- The addition of the function =date-days-in-month=.
+- Handling out-of-directory byte compilation better.
+- Fixing the usage and edge-cases of =and-let*=.
+
+(Released <2022-04-22 Fri>)
diff --git a/elpa/compat-29.1.4.5/compat-25.el b/elpa/compat-29.1.4.5/compat-25.el
new file mode 100644 (file)
index 0000000..182f5a3
--- /dev/null
@@ -0,0 +1,271 @@
+;;; compat-25.el --- Functionality added in Emacs 25.1 -*- lexical-binding: t; -*-
+
+;; Copyright (C) 2021-2024 Free Software Foundation, Inc.
+
+;; This program is free software; you can redistribute it and/or modify
+;; it under the terms of the GNU General Public License as published by
+;; the Free Software Foundation, either version 3 of the License, or
+;; (at your option) any later version.
+
+;; This program is distributed in the hope that it will be useful,
+;; but WITHOUT ANY WARRANTY; without even the implied warranty of
+;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+;; GNU General Public License for more details.
+
+;; You should have received a copy of the GNU General Public License
+;; along with this program.  If not, see <https://www.gnu.org/licenses/>.
+
+;;; Commentary:
+
+;; Functionality added in Emacs 25.1, needed by older Emacs versions.
+
+;;; Code:
+
+(eval-when-compile (load "compat-macs.el" nil t t))
+
+(compat-version "25.1")
+
+;;;; Defined in alloc.c
+
+(compat-defun bool-vector (&rest objects) ;; <compat-tests:bool-vector>
+  "Return a new bool-vector with specified arguments as elements.
+Allows any number of arguments, including zero.
+usage: (bool-vector &rest OBJECTS)"
+  (let ((vec (make-bool-vector (length objects) nil))
+        (i 0))
+    (while objects
+      (when (car objects)
+        (aset vec i t))
+      (setq objects (cdr objects)
+            i (1+ i)))
+    vec))
+
+;;;; Defined in fns.c
+
+(compat-defun sort (seq predicate) ;; <compat-tests:sort>
+  "Handle vector SEQ."
+  :extended t
+  (cond
+   ((listp seq)
+    (sort seq predicate))
+   ((vectorp seq)
+    (let* ((list (sort (append seq nil) predicate))
+           (p list) (i 0))
+      (while p
+        (aset seq i (car p))
+        (setq i (1+ i) p (cdr p)))
+      (apply #'vector list)))
+   (t (signal 'wrong-type-argument (list 'list-or-vector-p seq)))))
+
+;;;; Defined in editfns.c
+
+(compat-defalias format-message format) ;; <compat-tests:format-message>
+
+;;;; Defined in fileio.c
+
+(compat-defun directory-name-p (name) ;; <compat-tests:directory-name-p>
+  "Return non-nil if NAME ends with a directory separator character."
+  (eq (eval-when-compile
+        (if (memq system-type '(cygwin windows-nt ms-dos))
+            ?\\ ?/))
+      (aref name (1- (length name)))))
+
+;;;; Defined in doc.c
+
+(compat-defvar text-quoting-style nil ;; <compat-tests:text-quoting-style>
+  "Style to use for single quotes in help and messages.
+
+The value of this variable determines substitution of grave accents
+and apostrophes in help output (but not for display of Info
+manuals) and in functions like `message' and `format-message', but not
+in `format'.
+
+The value should be one of these symbols:
+  `curve':    quote with curved single quotes ‘like this’.
+  `straight': quote with straight apostrophes \\='like this\\='.
+  `grave':    quote with grave accent and apostrophe \\=`like this\\=';
+              i.e., do not alter the original quote marks.
+  nil:        like `curve' if curved single quotes are displayable,
+              and like `grave' otherwise.  This is the default.
+
+You should never read the value of this variable directly from a Lisp
+program.  Use the function `text-quoting-style' instead, as that will
+compute the correct value for the current terminal in the nil case.")
+
+;;;; Defined in simple.el
+
+;; `save-excursion' behaved like `save-mark-and-excursion' before 25.1.
+(compat-defalias save-mark-and-excursion save-excursion) ;; <compat-tests:save-mark-and-excursion>
+
+(declare-function region-bounds nil) ;; Defined in compat-26.el
+(compat-defun region-noncontiguous-p () ;; <compat-tests:region-noncontiguous-p>
+  "Return non-nil if the region contains several pieces.
+An example is a rectangular region handled as a list of
+separate contiguous regions for each line."
+  (let ((bounds (region-bounds))) (and (cdr bounds) bounds)))
+
+;;;; Defined in subr.el
+
+(compat-defun string-greaterp (string1 string2) ;; <compat-tests:string-greaterp>
+  "Return non-nil if STRING1 is greater than STRING2 in lexicographic order.
+Case is significant.
+Symbols are also allowed; their print names are used instead."
+  (string-lessp string2 string1))
+
+(compat-defmacro with-file-modes (modes &rest body) ;; <compat-tests:with-file-modes>
+  "Execute BODY with default file permissions temporarily set to MODES.
+MODES is as for `set-default-file-modes'."
+  (declare (indent 1) (debug t))
+  (let ((umask (make-symbol "umask")))
+    `(let ((,umask (default-file-modes)))
+       (unwind-protect
+           (progn
+             (set-default-file-modes ,modes)
+             ,@body)
+         (set-default-file-modes ,umask)))))
+
+(compat-defmacro if-let (spec then &rest else) ;; <compat-tests:if-let>
+  "Bind variables according to SPEC and evaluate THEN or ELSE.
+Evaluate each binding in turn, as in `let*', stopping if a
+binding value is nil.  If all are non-nil return the value of
+THEN, otherwise the last form in ELSE.
+
+Each element of SPEC is a list (SYMBOL VALUEFORM) that binds
+SYMBOL to the value of VALUEFORM.  An element can additionally be
+of the form (VALUEFORM), which is evaluated and checked for nil;
+i.e. SYMBOL can be omitted if only the test result is of
+interest.  It can also be of the form SYMBOL, then the binding of
+SYMBOL is checked for nil.
+
+As a special case, interprets a SPEC of the form \(SYMBOL SOMETHING)
+like \((SYMBOL SOMETHING)).  This exists for backward compatibility
+with an old syntax that accepted only one binding."
+  (declare (indent 2)
+           (debug ([&or (symbolp form)
+                        (&rest [&or symbolp (symbolp form) (form)])]
+                   body)))
+  (when (and (<= (length spec) 2) (not (listp (car spec))))
+    ;; Adjust the single binding case
+    (setq spec (list spec)))
+  (let ((empty (make-symbol "s"))
+        (last t) list)
+    (dolist (var spec)
+      (push `(,(if (cdr var) (car var) empty)
+              (and ,last ,(if (cdr var) (cadr var) (car var))))
+            list)
+      (when (or (cdr var) (consp (car var)))
+        (setq last (caar list))))
+    `(let* ,(nreverse list)
+       (if ,(caar list) ,then ,@else))))
+
+(compat-defmacro when-let (spec &rest body) ;; <compat-tests:when-let>
+  "Bind variables according to SPEC and conditionally evaluate BODY.
+Evaluate each binding in turn, stopping if a binding value is nil.
+If all are non-nil, return the value of the last form in BODY.
+
+The variable list SPEC is the same as in `if-let'."
+  (declare (indent 1) (debug if-let))
+  (list 'if-let spec (macroexp-progn body)))
+
+;;;; Defined in subr-x.el
+
+(compat-defun hash-table-empty-p (hash-table) ;; <compat-tests:hash-table-empty-p>
+  "Check whether HASH-TABLE is empty (has 0 elements)."
+  (zerop (hash-table-count hash-table)))
+
+(compat-defmacro thread-first (&rest forms) ;; <compat-tests:thread-first>
+  "Thread FORMS elements as the first argument of their successor.
+Example:
+    (thread-first
+      5
+      (+ 20)
+      (/ 25)
+      -
+      (+ 40))
+Is equivalent to:
+    (+ (- (/ (+ 5 20) 25)) 40)
+Note how the single `-' got converted into a list before
+threading."
+  (declare (indent 1)
+           (debug (form &rest [&or symbolp (sexp &rest form)])))
+  (let ((body (car forms)))
+    (dolist (form (cdr forms))
+      (when (symbolp form)
+        (setq form (list form)))
+      (setq body (append (list (car form))
+                         (list body)
+                         (cdr form))))
+    body))
+
+(compat-defmacro thread-last (&rest forms) ;; <compat-tests:thread-last>
+  "Thread FORMS elements as the last argument of their successor.
+Example:
+    (thread-last
+      5
+      (+ 20)
+      (/ 25)
+      -
+      (+ 40))
+Is equivalent to:
+    (+ 40 (- (/ 25 (+ 20 5))))
+Note how the single `-' got converted into a list before
+threading."
+  (declare (indent 1) (debug thread-first))
+  (let ((body (car forms)))
+    (dolist (form (cdr forms))
+      (when (symbolp form)
+        (setq form (list form)))
+      (setq body (append form (list body))))
+    body))
+
+;;;; Defined in macroexp.el
+
+(compat-defun macroexp-parse-body (body) ;; <compat-tests:macroexp-parse-body>
+  "Parse a function BODY into (DECLARATIONS . EXPS)."
+  (let ((decls ()))
+    (while (and (cdr body)
+                (let ((e (car body)))
+                  (or (stringp e)
+                      (memq (car-safe e)
+                            '(:documentation declare interactive cl-declare)))))
+      (push (pop body) decls))
+    (cons (nreverse decls) body)))
+
+(compat-defun macroexp-quote (v) ;; <compat-tests:macroexp-quote>
+  "Return an expression E such that `(eval E)' is V.
+
+E is either V or (quote V) depending on whether V evaluates to
+itself or not."
+  (if (and (not (consp v))
+           (or (keywordp v)
+               (not (symbolp v))
+               (memq v '(nil t))))
+      v
+    (list 'quote v)))
+
+(compat-defun macroexpand-1 (form &optional environment) ;; <compat-tests:macroexpand-1>
+  "Perform (at most) one step of macro expansion."
+  (cond
+   ((consp form)
+    (let* ((head (car form))
+           (env-expander (assq head environment)))
+      (if env-expander
+          (if (cdr env-expander)
+              (apply (cdr env-expander) (cdr form))
+            form)
+        (if (not (and (symbolp head) (fboundp head)))
+            form
+          (let ((def (autoload-do-load (symbol-function head) head 'macro)))
+            (cond
+             ;; Follow alias, but only for macros, otherwise we may end up
+             ;; skipping an important compiler-macro (e.g. cl--block-wrapper).
+             ((and (symbolp def) (macrop def)) (cons def (cdr form)))
+             ((not (consp def)) form)
+             (t
+              (if (eq 'macro (car def))
+                  (apply (cdr def) (cdr form))
+                form))))))))
+   (t form)))
+
+(provide 'compat-25)
+;;; compat-25.el ends here
diff --git a/elpa/compat-29.1.4.5/compat-26.el b/elpa/compat-29.1.4.5/compat-26.el
new file mode 100644 (file)
index 0000000..c91a486
--- /dev/null
@@ -0,0 +1,554 @@
+;;; compat-26.el --- Functionality added in Emacs 26.1 -*- lexical-binding: t; -*-
+
+;; Copyright (C) 2021-2024 Free Software Foundation, Inc.
+
+;; This program is free software; you can redistribute it and/or modify
+;; it under the terms of the GNU General Public License as published by
+;; the Free Software Foundation, either version 3 of the License, or
+;; (at your option) any later version.
+
+;; This program is distributed in the hope that it will be useful,
+;; but WITHOUT ANY WARRANTY; without even the implied warranty of
+;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+;; GNU General Public License for more details.
+
+;; You should have received a copy of the GNU General Public License
+;; along with this program.  If not, see <https://www.gnu.org/licenses/>.
+
+;;; Commentary:
+
+;; Functionality added in Emacs 26.1, needed by older Emacs versions.
+
+;;; Code:
+
+(eval-when-compile (load "compat-macs.el" nil t t))
+(compat-require compat-25 "25.1")
+
+(compat-version "26.1")
+
+;;;; Defined in fns.c
+
+(compat-defun buffer-hash (&optional buffer-or-name) ;; <compat-tests:buffer-hash>
+   "Return a hash of the contents of BUFFER-OR-NAME.
+This hash is performed on the raw internal format of the buffer,
+disregarding any coding systems.  If nil, use the current buffer.
+
+This function is useful for comparing two buffers running in the same
+Emacs, but is not guaranteed to return the same hash between different
+Emacs versions.  It should be somewhat more efficient on larger
+buffers than `secure-hash' is, and should not allocate more memory.
+
+It should not be used for anything security-related.  See
+`secure-hash' for these applications."
+   (with-current-buffer (or buffer-or-name (current-buffer))
+     (save-restriction
+       (widen)
+       (sha1 (current-buffer) (point-min) (point-max)))))
+
+(compat-defun mapcan (func sequence) ;; <compat-tests:mapcan>
+  "Apply FUNC to each element of SEQUENCE.
+Concatenate the results by altering them (using `nconc').
+SEQUENCE may be a list, a vector, a boolean vector, or a string."
+  (apply #'nconc (mapcar func sequence)))
+
+(compat-defun line-number-at-pos (&optional position absolute) ;; <compat-tests:line-number-at-pos>
+  "Handle optional argument ABSOLUTE."
+  :extended t
+  (if absolute
+      (save-restriction
+        (widen)
+        (line-number-at-pos position))
+    (line-number-at-pos position)))
+
+;;;; Defined in simple.el
+
+(compat-defun region-bounds () ;; <compat-tests:region-bounds>
+  "Return the boundaries of the region.
+Value is a list of one or more cons cells of the form (START . END).
+It will have more than one cons cell when the region is non-contiguous,
+see `region-noncontiguous-p' and `extract-rectangle-bounds'."
+  (if (eval-when-compile (< emacs-major-version 25))
+      ;; FIXME: The `region-extract-function' of Emacs 24 has no support for the
+      ;; bounds argument.
+      (list (cons (region-beginning) (region-end)))
+    (funcall region-extract-function 'bounds)))
+
+;;;; Defined in subr.el
+
+(compat-defun provided-mode-derived-p (mode &rest modes) ;; <compat-tests:provided-mode-derived-p>
+  "Non-nil if MODE is derived from one of MODES.
+Uses the `derived-mode-parent' property of the symbol to trace backwards.
+If you just want to check `major-mode', use `derived-mode-p'."
+  ;; If MODE is an alias, then look up the real mode function first.
+  (let ((alias (symbol-function mode)))
+    (when (and alias (symbolp alias))
+      (setq mode alias)))
+  (while
+      (and
+       (not (memq mode modes))
+       (let* ((parent (get mode 'derived-mode-parent))
+              (parentfn (symbol-function parent)))
+         (setq mode (if (and parentfn (symbolp parentfn)) parentfn parent)))))
+  mode)
+
+(compat-defun assoc (key alist &optional testfn) ;; <compat-tests:assoc>
+  "Handle the optional TESTFN."
+  :extended t
+  (cond
+   ((or (eq testfn #'eq)
+        (and (not testfn) (or (symbolp key) (integerp key)))) ;; eq_comparable_value
+    (assq key alist))
+   ((or (eq testfn #'equal) (not testfn))
+    (assoc key alist))
+   (t
+    (catch 'found
+      (dolist (ent alist)
+        (when (funcall testfn (car ent) key)
+          (throw 'found ent)))))))
+
+(compat-defun alist-get (key alist &optional default remove testfn) ;; <compat-tests:alist-get>
+  "Handle optional argument TESTFN."
+  :extended "25.1"
+  (ignore remove)
+  (let ((x (if (not testfn)
+               (assq key alist)
+             (compat--assoc key alist testfn))))
+    (if x (cdr x) default)))
+
+(compat-guard t ;; <compat-tests:alist-get-gv>
+  (gv-define-expander compat--alist-get
+    (lambda (do key alist &optional default remove testfn)
+      (macroexp-let2 macroexp-copyable-p k key
+        (gv-letplace (getter setter) alist
+          (macroexp-let2 nil p `(compat--assoc ,k ,getter ,testfn)
+            (funcall do (if (null default) `(cdr ,p)
+                          `(if ,p (cdr ,p) ,default))
+                     (lambda (v)
+                       (macroexp-let2 nil v v
+                         (let ((set-exp
+                                `(if ,p (setcdr ,p ,v)
+                                   ,(funcall setter
+                                             `(cons (setq ,p (cons ,k ,v))
+                                                    ,getter)))))
+                           `(progn
+                              ,(cond
+                                ((null remove) set-exp)
+                                ((or (eql v default)
+                                     (and (eq (car-safe v) 'quote)
+                                          (eq (car-safe default) 'quote)
+                                          (eql (cadr v) (cadr default))))
+                                 `(if ,p ,(funcall setter `(delq ,p ,getter))))
+                                (t
+                                 `(cond
+                                   ((not (eql ,default ,v)) ,set-exp)
+                                   (,p ,(funcall setter
+                                                 `(delq ,p ,getter))))))
+                              ,v))))))))))
+    (unless (get 'alist-get 'gv-expander)
+      (put 'alist-get 'gv-expander (get 'compat--alist-get 'gv-expander))))
+
+(compat-defun string-trim-left (string &optional regexp) ;; <compat-tests:string-trim-left>
+  "Handle optional argument REGEXP."
+  :extended t
+  (if (string-match (concat "\\`\\(?:" (or regexp "[ \t\n\r]+") "\\)") string)
+      (substring string (match-end 0))
+    string))
+
+(compat-defun string-trim-right (string &optional regexp) ;; <compat-tests:string-trim-right>
+  "Handle optional argument REGEXP."
+  :extended t
+  (let ((i (string-match-p
+            (concat "\\(?:" (or regexp "[ \t\n\r]+") "\\)\\'")
+            string)))
+    (if i (substring string 0 i) string)))
+
+(compat-defun string-trim (string &optional trim-left trim-right) ;; <compat-tests:string-trim>
+  "Handle optional arguments TRIM-LEFT and TRIM-RIGHT."
+  :extended t
+  (compat--string-trim-left
+   (compat--string-trim-right
+    string
+    trim-right)
+   trim-left))
+
+(compat-defun caaar (x) ;; <compat-tests:cXXXr>
+  "Return the `car' of the `car' of the `car' of X."
+  (declare (pure t))
+  (car (car (car x))))
+
+(compat-defun caadr (x) ;; <compat-tests:cXXXr>
+  "Return the `car' of the `car' of the `cdr' of X."
+  (declare (pure t))
+  (car (car (cdr x))))
+
+(compat-defun cadar (x) ;; <compat-tests:cXXXr>
+  "Return the `car' of the `cdr' of the `car' of X."
+  (declare (pure t))
+  (car (cdr (car x))))
+
+(compat-defun caddr (x) ;; <compat-tests:cXXXr>
+  "Return the `car' of the `cdr' of the `cdr' of X."
+  (declare (pure t))
+  (car (cdr (cdr x))))
+
+(compat-defun cdaar (x) ;; <compat-tests:cXXXr>
+  "Return the `cdr' of the `car' of the `car' of X."
+  (declare (pure t))
+  (cdr (car (car x))))
+
+(compat-defun cdadr (x) ;; <compat-tests:cXXXr>
+  "Return the `cdr' of the `car' of the `cdr' of X."
+  (declare (pure t))
+  (cdr (car (cdr x))))
+
+(compat-defun cddar (x) ;; <compat-tests:cXXXr>
+  "Return the `cdr' of the `cdr' of the `car' of X."
+  (declare (pure t))
+  (cdr (cdr (car x))))
+
+(compat-defun cdddr (x) ;; <compat-tests:cXXXr>
+  "Return the `cdr' of the `cdr' of the `cdr' of X."
+  (declare (pure t))
+  (cdr (cdr (cdr x))))
+
+(compat-defun caaaar (x) ;; <compat-tests:cXXXXr>
+  "Return the `car' of the `car' of the `car' of the `car' of X."
+  (declare (pure t))
+  (car (car (car (car x)))))
+
+(compat-defun caaadr (x) ;; <compat-tests:cXXXXr>
+  "Return the `car' of the `car' of the `car' of the `cdr' of X."
+  (declare (pure t))
+  (car (car (car (cdr x)))))
+
+(compat-defun caadar (x) ;; <compat-tests:cXXXXr>
+  "Return the `car' of the `car' of the `cdr' of the `car' of X."
+  (declare (pure t))
+  (car (car (cdr (car x)))))
+
+(compat-defun caaddr (x) ;; <compat-tests:cXXXXr>
+  "Return the `car' of the `car' of the `cdr' of the `cdr' of X."
+  (declare (pure t))
+  (car (car (cdr (cdr x)))))
+
+(compat-defun cadaar (x) ;; <compat-tests:cXXXXr>
+  "Return the `car' of the `cdr' of the `car' of the `car' of X."
+  (declare (pure t))
+  (car (cdr (car (car x)))))
+
+(compat-defun cadadr (x) ;; <compat-tests:cXXXXr>
+  "Return the `car' of the `cdr' of the `car' of the `cdr' of X."
+  (declare (pure t))
+  (car (cdr (car (cdr x)))))
+
+(compat-defun caddar (x) ;; <compat-tests:cXXXXr>
+  "Return the `car' of the `cdr' of the `cdr' of the `car' of X."
+  (declare (pure t))
+  (car (cdr (cdr (car x)))))
+
+(compat-defun cadddr (x) ;; <compat-tests:cXXXXr>
+  "Return the `car' of the `cdr' of the `cdr' of the `cdr' of X."
+  (declare (pure t))
+  (car (cdr (cdr (cdr x)))))
+
+(compat-defun cdaaar (x) ;; <compat-tests:cXXXXr>
+  "Return the `cdr' of the `car' of the `car' of the `car' of X."
+  (declare (pure t))
+  (cdr (car (car (car x)))))
+
+(compat-defun cdaadr (x) ;; <compat-tests:cXXXXr>
+  "Return the `cdr' of the `car' of the `car' of the `cdr' of X."
+  (declare (pure t))
+  (cdr (car (car (cdr x)))))
+
+(compat-defun cdadar (x) ;; <compat-tests:cXXXXr>
+  "Return the `cdr' of the `car' of the `cdr' of the `car' of X."
+  (declare (pure t))
+  (cdr (car (cdr (car x)))))
+
+(compat-defun cdaddr (x) ;; <compat-tests:cXXXXr>
+  "Return the `cdr' of the `car' of the `cdr' of the `cdr' of X."
+  (declare (pure t))
+  (cdr (car (cdr (cdr x)))))
+
+(compat-defun cddaar (x) ;; <compat-tests:cXXXXr>
+  "Return the `cdr' of the `cdr' of the `car' of the `car' of X."
+  (declare (pure t))
+  (cdr (cdr (car (car x)))))
+
+(compat-defun cddadr (x) ;; <compat-tests:cXXXXr>
+  "Return the `cdr' of the `cdr' of the `car' of the `cdr' of X."
+  (declare (pure t))
+  (cdr (cdr (car (cdr x)))))
+
+(compat-defun cdddar (x) ;; <compat-tests:cXXXXr>
+  "Return the `cdr' of the `cdr' of the `cdr' of the `car' of X."
+  (declare (pure t))
+  (cdr (cdr (cdr (car x)))))
+
+(compat-defun cddddr (x) ;; <compat-tests:cXXXXr>
+  "Return the `cdr' of the `cdr' of the `cdr' of the `cdr' of X."
+  (declare (pure t))
+  (cdr (cdr (cdr (cdr x)))))
+
+(compat-defvar gensym-counter 0 ;; <compat-tests:gensym>
+  "Number used to construct the name of the next symbol created by `gensym'.")
+
+(compat-defun gensym (&optional prefix) ;; <compat-tests:gensym>
+  "Return a new uninterned symbol.
+The name is made by appending `gensym-counter' to PREFIX.
+PREFIX is a string, and defaults to \"g\"."
+  (let ((num (prog1 gensym-counter
+               (setq gensym-counter
+                     (1+ gensym-counter)))))
+    (make-symbol (format "%s%d" (or prefix "g") num))))
+
+(compat-defmacro if-let* (varlist then &rest else) ;; <compat-tests:if-let*>
+  "Bind variables according to VARLIST and evaluate THEN or ELSE.
+This is like `if-let' but doesn't handle a VARLIST of the form
+\(SYMBOL SOMETHING) specially."
+  (declare (indent 2)
+           (debug ((&rest [&or symbolp (symbolp form) (form)])
+                   body)))
+  (let ((empty (make-symbol "s"))
+        (last t) list)
+    (dolist (var varlist)
+      (push `(,(if (cdr var) (car var) empty)
+              (and ,last ,(if (cdr var) (cadr var) (car var))))
+            list)
+      (when (or (cdr var) (consp (car var)))
+        (setq last (caar list))))
+    `(let* ,(nreverse list)
+       (if ,(caar list) ,then ,@else))))
+
+(compat-defmacro when-let* (varlist &rest body) ;; <compat-tests:when-let*>
+  "Bind variables according to VARLIST and conditionally evaluate BODY.
+This is like `when-let' but doesn't handle a VARLIST of the form
+\(SYMBOL SOMETHING) specially."
+  (declare (indent 1) (debug if-let*))
+  (list 'if-let* varlist (macroexp-progn body)))
+
+(compat-defmacro and-let* (varlist &rest body) ;; <compat-tests:and-let*>
+  "Bind variables according to VARLIST and conditionally evaluate BODY.
+Like `when-let*', except if BODY is empty and all the bindings
+are non-nil, then the result is non-nil."
+  (declare (indent 1)
+           (debug ((&rest [&or symbolp (symbolp form) (form)])
+                   body)))
+  (let ((empty (make-symbol "s"))
+        (last t) list)
+    (dolist (var varlist)
+      (push `(,(if (cdr var) (car var) empty)
+              (and ,last ,(if (cdr var) (cadr var) (car var))))
+            list)
+      (when (or (cdr var) (consp (car var)))
+        (setq last (caar list))))
+    `(let* ,(nreverse list)
+       (if ,(caar list) ,(macroexp-progn (or body '(t)))))))
+
+;;;; Defined in files.el
+
+(compat-defvar mounted-file-systems ;; <compat-tests:mounted-file-systems>
+    (eval-when-compile
+      (if (memq system-type '(windows-nt cygwin))
+          "^//[^/]+/"
+        (concat
+         "^" (regexp-opt '("/afs/" "/media/" "/mnt" "/net/" "/tmp_mnt/")))))
+  "File systems that ought to be mounted.")
+
+(compat-defun file-local-name (file) ;; <compat-tests:file-local-name>
+  "Return the local name component of FILE.
+This function removes from FILE the specification of the remote host
+and the method of accessing the host, leaving only the part that
+identifies FILE locally on the remote system.
+The returned file name can be used directly as argument of
+`process-file', `start-file-process', or `shell-command'."
+  (or (file-remote-p file 'localname) file))
+
+(compat-defun temporary-file-directory () ;; <compat-tests:temporary-file-directory>
+  "The directory for writing temporary files.
+In case of a remote `default-directory', this is a directory for
+temporary files on that remote host.  If such a directory does
+not exist, or `default-directory' ought to be located on a
+mounted file system (see `mounted-file-systems'), the function
+returns `default-directory'.
+For a non-remote and non-mounted `default-directory', the value of
+the variable `temporary-file-directory' is returned."
+  ;; NOTE: The handler may fail with an error, since the
+  ;; `temporary-file-directory' handler was introduced in Emacs 26.
+  (let ((handler (find-file-name-handler
+                  default-directory 'temporary-file-directory)))
+    (or (and handler (ignore-errors (funcall handler 'temporary-file-directory)))
+        (if-let ((remote (file-remote-p default-directory)))
+            (concat remote "/tmp/") ;; FIXME: Guess /tmp on remote host
+          (if (string-match mounted-file-systems default-directory)
+              default-directory
+            temporary-file-directory)))))
+
+(compat-defun make-temp-file (prefix &optional dir-flag suffix text) ;; <compat-tests:make-temp-file>
+  "Handle optional argument TEXT."
+  :extended t
+  (let ((file (make-temp-file prefix dir-flag suffix)))
+    (when text
+      (with-temp-buffer
+        (insert text)
+        (write-region (point-min) (point-max) file)))
+    file))
+
+(compat-defun make-nearby-temp-file (prefix &optional dir-flag suffix) ;; <compat-tests:make-nearby-temp-file>
+  "Create a temporary file as close as possible to `default-directory'.
+If PREFIX is a relative file name, and `default-directory' is a
+remote file name or located on a mounted file systems, the
+temporary file is created in the directory returned by the
+function `temporary-file-directory'.  Otherwise, the function
+`make-temp-file' is used.  PREFIX, DIR-FLAG and SUFFIX have the
+same meaning as in `make-temp-file'."
+  ;; NOTE: The handler may fail with an error, since the
+  ;; `make-nearby-temp-file' handler was introduced in Emacs 26.
+  (let ((handler (and (not (file-name-absolute-p default-directory))
+                      (find-file-name-handler
+                       default-directory 'make-nearby-temp-file))))
+    (or (and handler (ignore-errors (funcall handler 'make-nearby-temp-file
+                                             prefix dir-flag suffix)))
+        (let ((temporary-file-directory (temporary-file-directory)))
+          (make-temp-file prefix dir-flag suffix)))))
+
+(compat-defun file-attribute-type (attributes) ;; <compat-tests:file-attribute-getters>
+  "The type field in ATTRIBUTES returned by `file-attributes'.
+The value is either t for directory, string (name linked to) for
+symbolic link, or nil."
+  (nth 0 attributes))
+
+(compat-defun file-attribute-link-number (attributes) ;; <compat-tests:file-attribute-getters>
+  "Return the number of links in ATTRIBUTES returned by `file-attributes'."
+  (nth 1 attributes))
+
+(compat-defun file-attribute-user-id (attributes) ;; <compat-tests:file-attribute-getters>
+  "The UID field in ATTRIBUTES returned by `file-attributes'.
+This is either a string or a number.  If a string value cannot be
+looked up, a numeric value, either an integer or a float, is
+returned."
+  (nth 2 attributes))
+
+(compat-defun file-attribute-group-id (attributes) ;; <compat-tests:file-attribute-getters>
+  "The GID field in ATTRIBUTES returned by `file-attributes'.
+This is either a string or a number.  If a string value cannot be
+looked up, a numeric value, either an integer or a float, is
+returned."
+  (nth 3 attributes))
+
+(compat-defun file-attribute-access-time (attributes) ;; <compat-tests:file-attribute-getters>
+  "The last access time in ATTRIBUTES returned by `file-attributes'.
+This a Lisp timestamp in the style of `current-time'."
+  (nth 4 attributes))
+
+(compat-defun file-attribute-modification-time (attributes) ;; <compat-tests:file-attribute-getters>
+  "The modification time in ATTRIBUTES returned by `file-attributes'.
+This is the time of the last change to the file's contents, and
+is a Lisp timestamp in the style of `current-time'."
+  (nth 5 attributes))
+
+(compat-defun file-attribute-status-change-time (attributes) ;; <compat-tests:file-attribute-getters>
+  "The status modification time in ATTRIBUTES returned by `file-attributes'.
+This is the time of last change to the file's attributes: owner
+and group, access mode bits, etc., and is a Lisp timestamp in the
+style of `current-time'."
+  (nth 6 attributes))
+
+(compat-defun file-attribute-size (attributes) ;; <compat-tests:file-attribute-getters>
+  "The integer size (in bytes) in ATTRIBUTES returned by `file-attributes'."
+  (nth 7 attributes))
+
+(compat-defun file-attribute-modes (attributes) ;; <compat-tests:file-attribute-getters>
+  "The file modes in ATTRIBUTES returned by `file-attributes'.
+This is a string of ten letters or dashes as in ls -l."
+  (nth 8 attributes))
+
+(compat-defun file-attribute-inode-number (attributes) ;; <compat-tests:file-attribute-getters>
+  "The inode number in ATTRIBUTES returned by `file-attributes'.
+It is a nonnegative integer."
+  (nth 10 attributes))
+
+(compat-defun file-attribute-device-number (attributes) ;; <compat-tests:file-attribute-getters>
+  "The file system device number in ATTRIBUTES returned by `file-attributes'.
+It is an integer."
+  (nth 11 attributes))
+
+(compat-defun file-attribute-collect (attributes &rest attr-names) ;; <compat-tests:file-attribute-collect>
+  "Return a sublist of ATTRIBUTES returned by `file-attributes'.
+ATTR-NAMES are symbols with the selected attribute names.
+
+Valid attribute names are: type, link-number, user-id, group-id,
+access-time, modification-time, status-change-time, size, modes,
+inode-number and device-number."
+  (let ((idx '((type . 0)
+               (link-number . 1)
+               (user-id . 2)
+               (group-id . 3)
+               (access-time . 4)
+               (modification-time . 5)
+               (status-change-time . 6)
+               (size . 7)
+               (modes . 8)
+               (inode-number . 10)
+               (device-number . 11)))
+        result)
+    (while attr-names
+      (let ((attr (pop attr-names)))
+        (if (assq attr idx)
+            (push (nth (cdr (assq attr idx))
+                       attributes)
+                  result)
+          (error "Wrong attribute name '%S'" attr))))
+    (nreverse result)))
+
+;;;; Defined in mouse.el
+
+(compat-defvar mouse-select-region-move-to-beginning nil ;; <compat-tests:thing-at-mouse>
+  "Effect of selecting a region extending backward from double click.
+Nil means keep point at the position clicked (region end);
+non-nil means move point to beginning of region.")
+
+;;;; Defined in image.el
+
+(compat-defun image-property (image property) ;; <compat-tests:image-property>
+  "Return the value of PROPERTY in IMAGE.
+Properties can be set with
+
+  (setf (image-property IMAGE PROPERTY) VALUE)
+
+If VALUE is nil, PROPERTY is removed from IMAGE."
+  :feature image
+  (plist-get (cdr image) property))
+
+;;;; Defined in rmc.el
+
+(compat-defun read-multiple-choice (prompt choices) ;; <compat-tests:read-multiple-choice>
+  "Ask user to select an entry from CHOICES, promting with PROMPT.
+This function allows to ask the user a multiple-choice question.
+
+CHOICES should be a list of the form (KEY NAME [DESCRIPTION]).
+KEY is a character the user should type to select the entry.
+NAME is a short name for the entry to be displayed while prompting
+\(if there's no room, it might be shortened).
+
+NOTE: This is a partial implementation of `read-multiple-choice', that
+among other things doesn't offer any help and ignores the
+optional DESCRIPTION field."
+  (let ((options
+         (mapconcat
+          (lambda (opt)
+            (format
+             "[%s] %s"
+             (key-description (string (car opt)))
+             (cadr opt)))
+          choices " "))
+        choice)
+    (setq prompt (concat prompt " (" options "): "))
+    (while (not (setq choice (assq (read-event prompt) choices)))
+      (message "Invalid choice")
+      (sit-for 1))
+    choice))
+
+(provide 'compat-26)
+;;; compat-26.el ends here
diff --git a/elpa/compat-29.1.4.5/compat-27.el b/elpa/compat-29.1.4.5/compat-27.el
new file mode 100644 (file)
index 0000000..3de78a4
--- /dev/null
@@ -0,0 +1,885 @@
+;;; compat-27.el --- Functionality added in Emacs 27.1 -*- lexical-binding: t; -*-
+
+;; Copyright (C) 2021-2024 Free Software Foundation, Inc.
+
+;; This program is free software; you can redistribute it and/or modify
+;; it under the terms of the GNU General Public License as published by
+;; the Free Software Foundation, either version 3 of the License, or
+;; (at your option) any later version.
+
+;; This program is distributed in the hope that it will be useful,
+;; but WITHOUT ANY WARRANTY; without even the implied warranty of
+;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+;; GNU General Public License for more details.
+
+;; You should have received a copy of the GNU General Public License
+;; along with this program.  If not, see <https://www.gnu.org/licenses/>.
+
+;;; Commentary:
+
+;; Functionality added in Emacs 27.1, needed by older Emacs versions.
+
+;;; Code:
+
+(eval-when-compile (load "compat-macs.el" nil t t))
+(compat-require compat-26 "26.1")
+
+(compat-version "27.1")
+
+;;;; Defined in fns.c
+
+(compat-defun proper-list-p (object) ;; <compat-tests:proper-list-p>
+  "Return OBJECT's length if it is a proper list, nil otherwise.
+A proper list is neither circular nor dotted (i.e., its last cdr
+is nil)."
+  (if (eval-when-compile (< emacs-major-version 26))
+      ;; On older Emacs than 26.1 use Tortoise and Hare algorithm
+      (when (listp object)
+        (catch 'cycle
+          (let ((hare object) (tortoise object)
+                (max 2) (q 2))
+            (while (consp hare)
+              (setq hare (cdr hare))
+              (when (and (or (/= 0 (setq q (1- q)))
+                             (ignore
+                              (setq max (ash max 1)
+                                    q max
+                                    tortoise hare)))
+                         (eq hare tortoise))
+                (throw 'cycle nil)))
+            (and (null hare) (length object)))))
+    ;; Errors on 26.1 and newer
+    (and (listp object) (ignore-errors (length object)))))
+
+(compat-defun string-distance (string1 string2 &optional bytecompare) ;; <compat-tests:string-distance>
+  "Return Levenshtein distance between STRING1 and STRING2.
+The distance is the number of deletions, insertions, and substitutions
+required to transform STRING1 into STRING2.
+If BYTECOMPARE is nil or omitted, compute distance in terms of characters.
+If BYTECOMPARE is non-nil, compute distance in terms of bytes.
+Letter-case is significant, but text properties are ignored."
+  ;; https://en.wikipedia.org/wiki/Levenshtein_distance
+  (let ((s1 (if bytecompare
+                (encode-coding-string string1 'raw-text)
+              (concat string1 "")))
+        (s2 (if bytecompare
+                (encode-coding-string string2 'raw-text)
+              string2)))
+    (let* ((len1 (length s1))
+           (len2 (length s2))
+           (column (make-vector (1+ len1) 0)))
+      (dotimes (y len1)
+        (setf (aref column (1+ y)) y))
+      (dotimes (x len2)
+        (setf (aref column 0) (1+ x))
+        (let ((lastdiag x) olddiag)
+          (dotimes (y len1)
+            (setf olddiag (aref column (1+ y))
+                  (aref column (1+ y))
+                  (min (+ (if (= (aref s1 y) (aref s2 x)) 0 1)
+                          lastdiag)
+                       (1+ (aref column (1+ y)))
+                       (1+ (aref column y)))
+                  lastdiag olddiag))))
+      (aref column len1))))
+
+;;;; Defined in window.c
+
+(compat-defun recenter (&optional arg redisplay) ;; <compat-tests:recenter>
+  "Handle optional argument REDISPLAY."
+  :extended t
+  (recenter arg)
+  (when (and redisplay recenter-redisplay)
+    (redisplay)))
+
+;;;; Defined in keymap.c
+
+(compat-defun lookup-key (keymap key &optional accept-default) ;; <compat-tests:lookup-key>
+  "Allow for KEYMAP to be a list of keymaps."
+  :extended t
+  (cond
+   ((keymapp keymap)
+    (lookup-key keymap key accept-default))
+   ((listp keymap)
+    (catch 'found
+      (dolist (map keymap)
+        (when-let ((fn (lookup-key map key accept-default)))
+          (throw 'found fn)))))
+   ((signal 'wrong-type-argument (list 'keymapp keymap)))))
+
+;;;; Defined in timefns.c
+
+(compat-defun time-equal-p (t1 t2) ;; <compat-tests:time-equal-p>
+  "Return non-nil if time value T1 is equal to time value T2.
+A nil value for either argument stands for the current time.
+
+NOTE: This function is not as accurate as the actual `time-equal-p'."
+  (cond
+   ((eq t1 t2))
+   ((and (consp t1) (consp t2))
+    (equal t1 t2))
+   (t
+    ;; Due to inaccuracies and the relatively slow evaluating of
+    ;; Emacs Lisp compared to C, we allow for slight inaccuracies
+    ;; (less than a millisecond) when comparing time values.
+    (< (abs (- (float-time t1) (float-time t2)))
+       (if (and t1 t2) 1e-6 1e-5)))))
+
+;;;; Defined in subr.el
+
+(compat-defalias fixnump integerp) ;; <compat-tests:fixnump>
+(compat-defalias bignump ignore) ;; <compat-tests:bignump>
+
+(compat-defmacro setq-local (&rest pairs) ;; <compat-tests:setq-local>
+  "Handle multiple assignments."
+  :extended t
+  (unless (zerop (mod (length pairs) 2))
+    (error "PAIRS must have an even number of variable/value members"))
+  (let (body)
+    (while pairs
+      (let* ((sym (pop pairs))
+             (val (pop pairs)))
+        (unless (symbolp sym)
+          (error "Attempting to set a non-symbol: %s" (car pairs)))
+        (push `(set (make-local-variable ',sym) ,val)
+              body)))
+    (cons 'progn (nreverse body))))
+
+(compat-defmacro ignore-error (condition &rest body) ;; <compat-tests:ignore-error>
+  "Execute BODY; if the error CONDITION occurs, return nil.
+Otherwise, return result of last form in BODY.
+
+CONDITION can also be a list of error conditions."
+  (declare (debug t) (indent 1))
+  `(condition-case nil (progn ,@body) (,condition nil)))
+
+(compat-defmacro dolist-with-progress-reporter (spec reporter-or-message &rest body) ;; <compat-tests:dolist-with-progress-reporter>
+  "Loop over a list and report progress in the echo area.
+Evaluate BODY with VAR bound to each car from LIST, in turn.
+Then evaluate RESULT to get return value, default nil.
+
+REPORTER-OR-MESSAGE is a progress reporter object or a string.  In the latter
+case, use this string to create a progress reporter.
+
+At each iteration, print the reporter message followed by progress
+percentage in the echo area.  After the loop is finished,
+print the reporter message followed by the word \"done\".
+
+\(fn (VAR LIST [RESULT]) REPORTER-OR-MESSAGE BODY...)"
+  (declare (indent 2) (debug ((symbolp form &optional form) form body)))
+  (let ((prep (make-symbol "--dolist-progress-reporter--"))
+        (count (make-symbol "--dolist-count--"))
+        (list (make-symbol "--dolist-list--")))
+    `(let ((,prep ,reporter-or-message)
+           (,count 0)
+           (,list ,(cadr spec)))
+       (when (stringp ,prep)
+         (setq ,prep (make-progress-reporter ,prep 0 (length ,list))))
+       (dolist (,(car spec) ,list)
+         ,@body
+         (progress-reporter-update ,prep (setq ,count (1+ ,count))))
+       (progress-reporter-done ,prep)
+       (or ,@(cdr (cdr spec)) nil))))
+
+(compat-defun flatten-tree (tree) ;; <compat-tests:flatten-tree>
+  "Return a \"flattened\" copy of TREE.
+In other words, return a list of the non-nil terminal nodes, or
+leaves, of the tree of cons cells rooted at TREE.  Leaves in the
+returned list are in the same order as in TREE.
+
+\(flatten-tree \\='(1 (2 . 3) nil (4 5 (6)) 7))
+=> (1 2 3 4 5 6 7)"
+  (let (elems)
+    (while (consp tree)
+      (let ((elem (pop tree)))
+        (while (consp elem)
+          (push (cdr elem) tree)
+          (setq elem (car elem)))
+        (if elem (push elem elems))))
+    (if tree (push tree elems))
+    (nreverse elems)))
+
+(compat-defun xor (cond1 cond2) ;; <compat-tests:xor>
+  "Return the boolean exclusive-or of COND1 and COND2.
+If only one of the arguments is non-nil, return it; otherwise
+return nil."
+  (declare (pure t) (side-effect-free error-free))
+  (cond ((not cond1) cond2)
+        ((not cond2) cond1)))
+
+(compat-defvar regexp-unmatchable "\\`a\\`" ;; <compat-tests:regexp-unmatchable>
+  "Standard regexp guaranteed not to match any string at all."
+  :constant t)
+
+(compat-defun assoc-delete-all (key alist &optional test) ;; <compat-tests:assoc-delete-all>
+  "Handle optional argument TEST."
+  :extended "26.2"
+  (unless test (setq test #'equal))
+  (while (and (consp (car alist))
+              (funcall test (caar alist) key))
+    (setq alist (cdr alist)))
+  (let ((tail alist) tail-cdr)
+    (while (setq tail-cdr (cdr tail))
+      (if (and (consp (car tail-cdr))
+               (funcall test (caar tail-cdr) key))
+          (setcdr tail (cdr tail-cdr))
+        (setq tail tail-cdr))))
+  alist)
+
+(compat-defvar major-mode--suspended nil ;; <compat-tests:major-mode-suspend>
+  "Suspended major mode."
+  :local permanent)
+
+(compat-defun major-mode-suspend () ;; <compat-tests:major-mode-suspend>
+  "Exit current major mode, remembering it."
+  (let* ((prev-major-mode (or major-mode--suspended
+                              (unless (eq major-mode 'fundamental-mode)
+                                major-mode))))
+    (kill-all-local-variables)
+    (setq-local major-mode--suspended prev-major-mode)))
+
+(compat-defun major-mode-restore (&optional avoided-modes) ;; <compat-tests:major-mode-suspend>
+  "Restore major mode earlier suspended with `major-mode-suspend'.
+If there was no earlier suspended major mode, then fallback to `normal-mode',
+though trying to avoid AVOIDED-MODES."
+  (if major-mode--suspended
+      (funcall (prog1 major-mode--suspended
+                 (kill-local-variable 'major-mode--suspended)))
+    (let ((auto-mode-alist
+           (let ((alist (copy-sequence auto-mode-alist)))
+             (dolist (mode avoided-modes)
+               (setq alist (rassq-delete-all mode alist)))
+             alist))
+          (magic-fallback-mode-alist
+           (let ((alist (copy-sequence magic-fallback-mode-alist)))
+             (dolist (mode avoided-modes)
+               (setq alist (rassq-delete-all mode alist)))
+             alist)))
+      (normal-mode))))
+
+(compat-defun read-char-from-minibuffer-insert-char () ;; <compat-tests:read-char-from-minibuffer>
+  "Insert the character you type into the minibuffer and exit minibuffer.
+Discard all previous input before inserting and exiting the minibuffer."
+  (interactive)
+  (when (minibufferp)
+    (delete-minibuffer-contents)
+    (insert last-command-event)
+    (exit-minibuffer)))
+
+(compat-defun read-char-from-minibuffer-insert-other () ;; <compat-tests:read-char-from-minibuffer>
+  "Reject a disallowed character typed into the minibuffer.
+This command is intended to be bound to keys that users are not
+allowed to type into the minibuffer.  When the user types any
+such key, this command discard all minibuffer input and displays
+an error message."
+  (interactive)
+  (when (minibufferp)
+    (delete-minibuffer-contents)
+    (ding)
+    (discard-input)
+    (minibuffer-message "Wrong answer")
+    (sit-for 2)))
+
+(compat-defvar read-char-history nil ;; <compat-tests:read-char-from-minibuffer>
+  "The default history for the `read-char-from-minibuffer' function.")
+
+(compat-defvar read-char-from-minibuffer-map ;; <compat-tests:read-char-from-minibuffer>
+  (let ((map (make-sparse-keymap)))
+    (set-keymap-parent map minibuffer-local-map)
+    (define-key map [remap self-insert-command] #'read-char-from-minibuffer-insert-char)
+    (define-key map [remap exit-minibuffer] #'read-char-from-minibuffer-insert-other)
+    map)
+  "Keymap for the `read-char-from-minibuffer' function.")
+
+(compat-defvar read-char-from-minibuffer-map-hash  ;; <compat-tests:read-char-from-minibuffer>
+  (make-hash-table :test 'equal)
+  "Hash table of keymaps used by `read-char-from-minibuffer'."
+  :constant t)
+
+(compat-defun read-char-from-minibuffer (prompt &optional chars history) ;; <compat-tests:read-char-from-minibuffer>
+  "Read a character from the minibuffer, prompting for it with PROMPT.
+Like `read-char', but uses the minibuffer to read and return a character.
+Optional argument CHARS, if non-nil, should be a list of characters;
+the function will ignore any input that is not one of CHARS.
+Optional argument HISTORY, if non-nil, should be a symbol that
+specifies the history list variable to use for navigating in input
+history using \\`M-p' and \\`M-n', with \\`RET' to select a character from
+history.
+If you bind the variable `help-form' to a non-nil value
+while calling this function, then pressing `help-char'
+causes it to evaluate `help-form' and display the result.
+There is no need to explicitly add `help-char' to CHARS;
+`help-char' is bound automatically to `help-form-show'."
+  (let* ((map (if (consp chars)
+                  (or (gethash (list help-form (cons help-char chars))
+                               read-char-from-minibuffer-map-hash)
+                      (let ((map (make-sparse-keymap))
+                            (msg help-form))
+                        (set-keymap-parent map read-char-from-minibuffer-map)
+                        ;; If we have a dynamically bound `help-form'
+                        ;; here, then the `C-h' (i.e., `help-char')
+                        ;; character should output that instead of
+                        ;; being a command char.
+                        (when help-form
+                          (define-key map (vector help-char)
+                            (lambda ()
+                              (interactive)
+                              (let ((help-form msg)) ; lexically bound msg
+                                (help-form-show)))))
+                        (dolist (char chars)
+                          (define-key map (vector char)
+                            #'read-char-from-minibuffer-insert-char))
+                        (define-key map [remap self-insert-command]
+                          #'read-char-from-minibuffer-insert-other)
+                        (puthash (list help-form (cons help-char chars))
+                                 map read-char-from-minibuffer-map-hash)
+                        map))
+                read-char-from-minibuffer-map))
+         ;; Protect this-command when called from pre-command-hook (bug#45029)
+         (this-command this-command)
+         (result (read-from-minibuffer prompt nil map nil (or history t)))
+         (char
+          (if (> (length result) 0)
+              ;; We have a string (with one character), so return the first one.
+              (elt result 0)
+            ;; The default value is RET.
+            (when history (push "\r" (symbol-value history)))
+            ?\r)))
+    ;; Display the question with the answer.
+    (message "%s%s" prompt (char-to-string char))
+    char))
+
+;;;; Defined in simple.el
+
+(compat-guard (not (fboundp 'decoded-time-second)) ;; <compat-tests:decoded-time>
+  (cl-defstruct (decoded-time
+                 (:constructor nil)
+                 (:copier nil)
+                 (:type list))
+    (second nil :documentation "\
+This is an integer or a Lisp timestamp (TICKS . HZ) representing a nonnegative
+number of seconds less than 61.  (If not less than 60, it is a leap second,
+which only some operating systems support.)")
+    (minute nil :documentation "This is an integer between 0 and 59 (inclusive).")
+    (hour nil :documentation "This is an integer between 0 and 23 (inclusive).")
+    (day nil :documentation "This is an integer between 1 and 31 (inclusive).")
+    (month nil :documentation "\
+This is an integer between 1 and 12 (inclusive).  January is 1.")
+    (year nil :documentation "This is a four digit integer.")
+    (weekday nil :documentation "\
+This is a number between 0 and 6, and 0 is Sunday.")
+    (dst -1 :documentation "\
+This is t if daylight saving time is in effect, nil if it is not
+in effect, and -1 if daylight saving information is not available.
+Also see `decoded-time-dst'.")
+    (zone nil :documentation "\
+This is an integer indicating the UTC offset in seconds, i.e.,
+the number of seconds east of Greenwich.")))
+
+(compat-defun minibuffer-history-value () ;; <compat-tests:minibuffer-history-value>
+  "Return the value of the minibuffer input history list.
+If `minibuffer-history-variable' points to a buffer-local variable and
+the minibuffer is active, return the buffer-local value for the buffer
+that was current when the minibuffer was activated."
+  (buffer-local-value minibuffer-history-variable
+                      (window-buffer (minibuffer-selected-window))))
+
+;;;; Defined in minibuffer.el
+
+(compat-defmacro with-minibuffer-selected-window (&rest body) ;; <compat-tests:with-minibuffer-selected-window>
+  "Execute the forms in BODY from the minibuffer in its original window.
+When used in a minibuffer window, select the window selected just before
+the minibuffer was activated, and execute the forms."
+  (declare (indent 0) (debug t))
+  `(when-let ((window (minibuffer-selected-window)))
+     (with-selected-window window
+       ,@body)))
+
+;;;; Defined in byte-run.el
+
+(compat-defmacro with-suppressed-warnings (_warnings &rest body) ;; <compat-tests:with-suppressed-warnings>
+  "Like `progn', but prevents compiler WARNINGS in BODY.
+NOTE: The compatibility version behaves like `with-no-warnings'."
+  `(with-no-warnings ,@body))
+
+;;;; Defined in image.el
+
+(compat-defun image--set-property (image property value) ;; <compat-tests:image-property>
+  "Set PROPERTY in IMAGE to VALUE, internal use only."
+  :extended "26.1"
+  :feature image
+  (if (null value)
+      (while (cdr image)
+        (if (eq (cadr image) property)
+            (setcdr image (cdddr image))
+          (setq image (cddr image))))
+    (setcdr image (plist-put (cdr image) property value)))
+  value)
+
+;; HACK: image--set-property was broken with an off-by-one error on Emacs 26.
+;; The bug was fixed in a4ad7bed187493c1c230f223b52c71f5c34f7c89. Therefore we
+;; override the gv expander until Emacs 27.1.
+(compat-guard ;; <compat-tests:image-property>
+    (or (= emacs-major-version 26) (not (get 'image-property 'gv-expander)))
+  :feature image
+  (gv-define-setter image-property (value image prop)
+    `(,(if (< emacs-major-version 26) 'image--set-property 'compat--image--set-property)
+      ,image ,prop ,value)))
+
+;;;; Defined in files.el
+
+(compat-defun file-name-quoted-p (name &optional top) ;; <compat-tests:file-name-quoted-p>
+  "Handle optional argument TOP."
+  :extended "26.1"
+  (let ((file-name-handler-alist (unless top file-name-handler-alist)))
+    (string-prefix-p "/:" (file-local-name name))))
+
+(compat-defun file-name-quote (name &optional top) ;; <compat-tests:file-name-quote>
+  "Handle optional argument TOP."
+  :extended "26.1"
+  (let* ((file-name-handler-alist (unless top file-name-handler-alist))
+         (localname (file-local-name name)))
+    (if (string-prefix-p "/:" localname)
+        name
+      (concat (file-remote-p name) "/:" localname))))
+
+(compat-defun file-name-unquote (name &optional top) ;; <compat-tests:file-name-unquote>
+  "Handle optional argument TOP."
+  :extended "26.1"
+  (let* ((file-name-handler-alist (unless top file-name-handler-alist))
+         (localname (file-local-name name)))
+    (when (string-prefix-p "/:" localname)
+      (setq localname (if (= (length localname) 2) "/" (substring localname 2))))
+    (concat (file-remote-p name) localname)))
+
+(compat-defun file-size-human-readable (file-size &optional flavor space unit) ;; <compat-tests:file-size-human-readable>
+  "Handle the optional arguments SPACE and UNIT."
+  :extended t
+  (let ((power (if (or (null flavor) (eq flavor 'iec))
+                   1024.0
+                 1000.0))
+        (prefixes '("" "k" "M" "G" "T" "P" "E" "Z" "Y")))
+    (while (and (>= file-size power) (cdr prefixes))
+      (setq file-size (/ file-size power)
+            prefixes (cdr prefixes)))
+    (let* ((prefix (car prefixes))
+           (prefixed-unit (if (eq flavor 'iec)
+                              (concat
+                               (if (string= prefix "k") "K" prefix)
+                               (if (string= prefix "") "" "i")
+                               (or unit "B"))
+                            (concat prefix unit))))
+      (format (if (and (>= (mod file-size 1.0) 0.05)
+                       (< (mod file-size 1.0) 0.95))
+                  "%.1f%s%s"
+                "%.0f%s%s")
+              file-size
+              (if (string= prefixed-unit "") "" (or space ""))
+              prefixed-unit))))
+
+(compat-defun file-size-human-readable-iec (size) ;; <compat-tests:file-size-human-readable-iec>
+  "Human-readable string for SIZE bytes, using IEC prefixes."
+  (compat--file-size-human-readable size 'iec " "))
+
+(compat-defun exec-path () ;; <compat-tests:exec-path>
+  "Return list of directories to search programs to run in remote subprocesses.
+The remote host is identified by `default-directory'.  For remote
+hosts that do not support subprocesses, this returns nil.
+If `default-directory' is a local directory, this function returns
+the value of the variable `exec-path'."
+  (let ((handler (find-file-name-handler default-directory 'exec-path)))
+    ;; NOTE: The handler may fail since it was added in 27.1.
+    (or (and handler (ignore-errors (funcall handler 'exec-path)))
+        (if (file-remote-p default-directory)
+            ;; FIXME: Just return some standard path on remote
+            '("/bin" "/usr/bin" "/sbin" "/usr/sbin" "/usr/local/bin" "/usr/local/sbin")
+          exec-path))))
+
+(compat-defun executable-find (command &optional remote) ;; <compat-tests:executable-find>
+  "Handle optional argument REMOTE."
+  :extended t
+  (if (and remote (file-remote-p default-directory))
+      (let ((res (locate-file
+                  command
+                  (mapcar
+                   (apply-partially
+                    #'concat (file-remote-p default-directory))
+                   (exec-path))
+                  exec-suffixes 'file-executable-p)))
+        (when (stringp res) (file-local-name res)))
+    (executable-find command)))
+
+(compat-defun make-empty-file (filename &optional parents) ;; <compat-tests:make-empty-file>
+  "Create an empty file FILENAME.
+Optional arg PARENTS, if non-nil then creates parent dirs as needed."
+  (when (and (file-exists-p filename) (null parents))
+    (signal 'file-already-exists (list "File exists" filename)))
+  (let ((paren-dir (file-name-directory filename)))
+    (when (and paren-dir (not (file-exists-p paren-dir)))
+      (make-directory paren-dir parents)))
+  (write-region "" nil filename nil 0))
+
+;;;; Defined in regexp-opt.el
+
+(compat-defun regexp-opt (strings &optional paren) ;; <compat-tests:regexp-opt>
+  "Handle an empty list of STRINGS."
+  :extended t
+  (if (null strings)
+      (let ((re "\\`a\\`"))
+        (cond ((null paren)
+               (concat "\\(?:" re "\\)"))
+              ((stringp paren)
+               (concat paren re "\\)"))
+              ((eq paren 'words)
+               (concat "\\<\\(" re "\\)\\>"))
+              ((eq paren 'symbols)
+               (concat "\\_\\(<" re "\\)\\_>"))
+              ((concat "\\(" re "\\)"))))
+    (regexp-opt strings paren)))
+
+;;;; Defined in package.el
+
+(declare-function lm-header "lisp-mnt")
+(declare-function macroexp-file-name nil)
+
+(compat-defun package-get-version () ;; <compat-tests:package-get-version>
+  "Return the version number of the package in which this is used.
+Assumes it is used from an Elisp file placed inside the top-level directory
+of an installed ELPA package.
+The return value is a string (or nil in case we can’t find it)."
+  ;; No :feature since the function is autoloaded.
+  ;; In a sense, this is a lie, but it does just what we want: precompute
+  ;; the version at compile time and hardcodes it into the .elc file!
+  (declare (pure t))
+  ;; Hack alert!
+  (let ((file (or (macroexp-file-name) buffer-file-name)))
+    (cond
+     ((null file) nil)
+     ;; Packages are normally installed into directories named "<pkg>-<vers>",
+     ;; so get the version number from there.
+     ((string-match
+       "/[^/]+-\\([0-9]\\(?:[0-9.]\\|pre\\|beta\\|alpha\\|snapshot\\)+\\)/[^/]+\\'"
+       file)
+      (match-string 1 file))
+     ;; For packages run straight from the an elpa.git clone, there's no
+     ;; "-<vers>" in the directory name, so we have to fetch the version
+     ;; the hard way.
+     ((let* ((pkgdir (file-name-directory file))
+             (pkgname (file-name-nondirectory (directory-file-name pkgdir)))
+             (mainfile (expand-file-name (concat pkgname ".el") pkgdir)))
+        (when (file-readable-p mainfile)
+          (require 'lisp-mnt)
+          (with-temp-buffer
+            (insert-file-contents mainfile)
+            (or (lm-header "package-version")
+                (lm-header "version")))))))))
+
+;;;; Defined in time-date.el
+
+(compat-defun make-decoded-time ;; <compat-tests:make-decoded-time>
+              (&key second minute hour day month year (dst -1) zone)
+  "Return a `decoded-time' structure with only the keywords given filled out."
+  :feature time-date
+  (list second minute hour day month year nil dst zone))
+
+(compat-defun date-days-in-month (year month) ;; <compat-tests:date-days-in-month>
+  "The number of days in MONTH in YEAR."
+  :feature time-date
+  (unless (and (numberp month)
+               (<= 1 month)
+               (<= month 12))
+    (error "Month %s is invalid" month))
+  (if (= month 2)
+      (if (date-leap-year-p year)
+          29
+        28)
+    (if (memq month '(1 3 5 7 8 10 12))
+        31
+      30)))
+
+(compat-defun date-ordinal-to-time (year ordinal) ;; <compat-tests:date-ordinal-to-time>
+  "Convert a YEAR/ORDINAL to the equivalent `decoded-time' structure.
+ORDINAL is the number of days since the start of the year, with
+January 1st being 1."
+  (let ((month 1))
+    (while (> ordinal (date-days-in-month year month))
+      (setq ordinal (- ordinal (date-days-in-month year month))
+            month (1+ month)))
+    (list nil nil nil ordinal month year nil nil nil)))
+
+;;;; Defined in text-property-search.el
+
+(declare-function make-prop-match nil)
+(compat-guard (not (fboundp 'make-prop-match)) ;; <compat-tests:prop-match>
+  (cl-defstruct (prop-match) beginning end value))
+
+(compat-defun text-property-search-forward ;; <compat-tests:text-property-search-forward>
+    (property &optional value predicate not-current)
+  "Search for the next region of text where PREDICATE is true.
+PREDICATE is used to decide whether a value of PROPERTY should be
+considered as matching VALUE.
+
+If PREDICATE is a function, it will be called with two arguments:
+VALUE and the value of PROPERTY.  The function should return
+non-nil if these two values are to be considered a match.
+
+Two special values of PREDICATE can also be used:
+If PREDICATE is t, that means a value must `equal' VALUE to be
+considered a match.
+If PREDICATE is nil (which is the default value), a value will
+match if is not `equal' to VALUE.  Furthermore, a nil PREDICATE
+means that the match region is ended if the value changes.  For
+instance, this means that if you loop with
+
+  (while (setq prop (text-property-search-forward \\='face))
+    ...)
+
+you will get all distinct regions with non-nil `face' values in
+the buffer, and the `prop' object will have the details about the
+match.  See the manual for more details and examples about how
+VALUE and PREDICATE interact.
+
+If NOT-CURRENT is non-nil, the function will search for the first
+region that doesn't include point and has a value of PROPERTY
+that matches VALUE.
+
+If no matches can be found, return nil and don't move point.
+If found, move point to the end of the region and return a
+`prop-match' object describing the match.  To access the details
+of the match, use `prop-match-beginning' and `prop-match-end' for
+the buffer positions that limit the region, and
+`prop-match-value' for the value of PROPERTY in the region."
+  (let* ((match-p
+          (lambda (prop-value)
+            (funcall
+             (cond
+              ((eq predicate t)
+               #'equal)
+              ((eq predicate nil)
+               (lambda (val p-val)
+                 (not (equal val p-val))))
+              (predicate))
+             value prop-value)))
+         (find-end
+          (lambda (start)
+            (let (end)
+              (if (and value
+                       (null predicate))
+                  ;; This is the normal case: We're looking for areas where the
+                  ;; values aren't, so we aren't interested in sub-areas where the
+                  ;; property has different values, all non-matching value.
+                  (let ((ended nil))
+                    (while (not ended)
+                      (setq end (next-single-property-change (point) property))
+                      (if (not end)
+                          (progn
+                            (goto-char (point-max))
+                            (setq end (point)
+                                  ended t))
+                        (goto-char end)
+                        (unless (funcall match-p (get-text-property (point) property))
+                          (setq ended t)))))
+                ;; End this at the first place the property changes value.
+                (setq end (next-single-property-change (point) property nil (point-max)))
+                (goto-char end))
+              (make-prop-match
+               :beginning start
+               :end end
+               :value (get-text-property start property))))))
+    (cond
+     ;; No matches at the end of the buffer.
+     ((eobp)
+      nil)
+     ;; We're standing in the property we're looking for, so find the
+     ;; end.
+     ((and (funcall match-p (get-text-property (point) property))
+           (not not-current))
+      (funcall find-end (point)))
+     (t
+      (let ((origin (point))
+            (ended nil)
+            pos)
+        ;; Find the next candidate.
+        (while (not ended)
+          (setq pos (next-single-property-change (point) property))
+          (if (not pos)
+              (progn
+                (goto-char origin)
+                (setq ended t))
+            (goto-char pos)
+            (if (funcall match-p (get-text-property (point) property))
+                (setq ended (funcall find-end (point)))
+              ;; Skip past this section of non-matches.
+              (setq pos (next-single-property-change (point) property))
+              (unless pos
+                (goto-char origin)
+                (setq ended t)))))
+        (and (not (eq ended t))
+             ended))))))
+
+(compat-defun text-property-search-backward ;; <compat-tests:text-property-search-backward>
+    (property &optional value predicate not-current)
+  "Search for the previous region of text whose PROPERTY matches VALUE.
+
+Like `text-property-search-forward', which see, but searches backward,
+and if a matching region is found, place point at the start of the region."
+  (let* ((match-p
+          (lambda (prop-value)
+            (funcall
+             (cond
+              ((eq predicate t)
+               #'equal)
+              ((eq predicate nil)
+               (lambda (val p-val)
+                 (not (equal val p-val))))
+              (predicate))
+             value prop-value)))
+         (find-end
+          (lambda (start)
+            (let (end)
+              (if (and value
+                       (null predicate))
+                  ;; This is the normal case: We're looking for areas where the
+                  ;; values aren't, so we aren't interested in sub-areas where the
+                  ;; property has different values, all non-matching value.
+                  (let ((ended nil))
+                    (while (not ended)
+                      (setq end (previous-single-property-change (point) property))
+                      (if (not end)
+                          (progn
+                            (goto-char (point-min))
+                            (setq end (point)
+                                  ended t))
+                        (goto-char (1- end))
+                        (unless (funcall match-p (get-text-property (point) property))
+                          (goto-char end)
+                          (setq ended t)))))
+                ;; End this at the first place the property changes value.
+                (setq end (previous-single-property-change
+                           (point) property nil (point-min)))
+                (goto-char end))
+              (make-prop-match
+               :beginning end
+               :end (1+ start)
+               :value (get-text-property end property))))))
+    (cond
+     ;; We're at the start of the buffer; no previous matches.
+     ((bobp)
+      nil)
+     ;; We're standing in the property we're looking for, so find the
+     ;; end.
+     ((funcall match-p (get-text-property (1- (point)) property))
+      (let ((origin (point))
+            (match (funcall find-end (1- (point)) property value predicate)))
+        ;; When we want to ignore the current element, then repeat the
+        ;; search if we haven't moved out of it yet.
+        (if (and not-current
+                 (equal (get-text-property (point) property)
+                        (get-text-property origin property)))
+            (text-property-search-backward property value predicate)
+          match)))
+     (t
+      (let ((origin (point))
+            (ended nil)
+            pos)
+        ;; Find the previous candidate.
+        (while (not ended)
+          (setq pos (previous-single-property-change (point) property))
+          (if (not pos)
+              (progn
+                (goto-char origin)
+                (setq ended t))
+            (goto-char (1- pos))
+            (if (funcall match-p (get-text-property (point) property))
+                (setq ended
+                      (funcall find-end (point)))
+              ;; Skip past this section of non-matches.
+              (setq pos (previous-single-property-change (point) property))
+              (unless pos
+                (goto-char origin)
+                (setq ended t)))))
+        (and (not (eq ended t))
+             ended))))))
+
+;;;; Defined in ring.el
+
+(compat-defun ring-resize (ring size) ;; <compat-tests:ring-resize>
+  "Set the size of RING to SIZE.
+If the new size is smaller, then the oldest items in the ring are
+discarded."
+  :feature ring
+  (when (integerp size)
+    (let ((length (ring-length ring))
+          (new-vec (make-vector size nil)))
+      (if (= length 0)
+          (setcdr ring (cons 0 new-vec))
+        (let* ((hd (car ring))
+               (old-size (ring-size ring))
+               (old-vec (cddr ring))
+               (copy-length (min size length))
+               (copy-hd (mod (+ hd (- length copy-length)) length)))
+          (setcdr ring (cons copy-length new-vec))
+          ;; If the ring is wrapped, the existing elements must be written
+          ;; out in the right order.
+          (dotimes (j copy-length)
+            (aset new-vec j (aref old-vec (mod (+ copy-hd j) old-size))))
+          (setcar ring 0))))))
+
+;;;; Defined in map-ynp.el
+
+(compat-version "26.2")
+
+(compat-defvar read-answer-short 'auto ;; <compat-tests:read-answer>
+  "If non-nil, the `read-answer' function accepts single-character answers.
+If t, accept short (single key-press) answers to the question.
+If nil, require long answers.  If `auto', accept short answers if
+`use-short-answers' is non-nil, or the function cell of `yes-or-no-p'
+is set to `y-or-n-p'.
+
+Note that this variable does not affect calls to the more
+commonly-used `yes-or-no-p' function; it only affects calls to
+the `read-answer' function.  To control whether `yes-or-no-p'
+requires a long or a short answer, see the `use-short-answers'
+variable.")
+
+(compat-defun read-answer (question answers) ;; <compat-tests:read-answer>
+  "Read an answer either as a complete word or its character abbreviation.
+Ask user a question and accept an answer from the list of possible answers.
+
+QUESTION should end in a space; this function adds a list of answers to it.
+
+ANSWERS is an alist with elements in the following format:
+  (LONG-ANSWER SHORT-ANSWER HELP-MESSAGE)
+where
+  LONG-ANSWER is a complete answer,
+  SHORT-ANSWER is an abbreviated one-character answer,
+  HELP-MESSAGE is a string describing the meaning of the answer.
+
+SHORT-ANSWER is not necessarily a single character answer.  It can be
+also a function key like F1, a character event such as C-M-h, or
+a control character like C-h.
+
+Example:
+  \\='((\"yes\"  ?y \"perform the action\")
+    (\"no\"   ?n \"skip to the next\")
+    (\"all\"  ?! \"accept all remaining without more questions\")
+    (\"help\" ?h \"show help\")
+    (\"quit\" ?q \"exit\"))
+
+When `read-answer-short' is non-nil, accept short answers.
+
+Return a long answer even in case of accepting short ones.
+
+When `use-dialog-box' is t, pop up a dialog window to get user input."
+  ;; NOTE: For simplicity we provide a primitive implementation based on
+  ;; `read-multiple-choice', which does neither support long answers nor the the
+  ;; gui dialog box.
+  (cadr (read-multiple-choice
+         (string-trim-right question)
+         (delq nil
+               (mapcar (lambda (x) (unless (equal "help" (car x))
+                                     (list (cadr x) (car x) (caddr x))))
+                       answers)))))
+
+(provide 'compat-27)
+;;; compat-27.el ends here
diff --git a/elpa/compat-29.1.4.5/compat-28.el b/elpa/compat-29.1.4.5/compat-28.el
new file mode 100644 (file)
index 0000000..b5730b1
--- /dev/null
@@ -0,0 +1,852 @@
+;;; compat-28.el --- Functionality added in Emacs 28.1 -*- lexical-binding: t; -*-
+
+;; Copyright (C) 2021-2024 Free Software Foundation, Inc.
+
+;; This program is free software; you can redistribute it and/or modify
+;; it under the terms of the GNU General Public License as published by
+;; the Free Software Foundation, either version 3 of the License, or
+;; (at your option) any later version.
+
+;; This program is distributed in the hope that it will be useful,
+;; but WITHOUT ANY WARRANTY; without even the implied warranty of
+;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+;; GNU General Public License for more details.
+
+;; You should have received a copy of the GNU General Public License
+;; along with this program.  If not, see <https://www.gnu.org/licenses/>.
+
+;;; Commentary:
+
+;; Functionality added in Emacs 28.1, needed by older Emacs versions.
+
+;;; Code:
+
+(eval-when-compile (load "compat-macs.el" nil t t))
+(compat-require compat-27 "27.1")
+
+(compat-version "28.1")
+
+;;;; Defined in comp.c
+
+(compat-defalias native-comp-available-p ignore) ;; <compat-tests:native-comp-available-p>
+
+;;;; Defined in fns.c
+
+;; FIXME Should handle multibyte regular expressions
+(compat-defun string-search (needle haystack &optional start-pos) ;; <compat-tests:string-search>
+  "Search for the string NEEDLE in the string HAYSTACK.
+
+The return value is the position of the first occurrence of
+NEEDLE in HAYSTACK, or nil if no match was found.
+
+The optional START-POS argument says where to start searching in
+HAYSTACK and defaults to zero (start at the beginning).
+It must be between zero and the length of HAYSTACK, inclusive.
+
+Case is always significant and text properties are ignored.
+
+NOTE: Prior to Emacs 27 `string-match' has issues handling
+multibyte regular expressions.  As the compatibility function
+for `string-search' is implemented via `string-match', these
+issues are inherited."
+  (when (and start-pos (or (< (length haystack) start-pos)
+                           (< start-pos 0)))
+    (signal 'args-out-of-range (list start-pos)))
+  (let (case-fold-search)
+    (string-match-p (regexp-quote needle) haystack start-pos)))
+
+(compat-defun length= (sequence length) ;; [[compat-tests:length=]]
+  "Returns non-nil if SEQUENCE has a length equal to LENGTH."
+  (cond
+   ((null sequence) (zerop length))
+   ((consp sequence)
+    (and (null (nthcdr length sequence))
+         (nthcdr (1- length) sequence)
+         t))
+   ((arrayp sequence)
+    (= (length sequence) length))
+   (t (signal 'wrong-type-argument (list 'sequencep sequence)))))
+
+(compat-defun length< (sequence length) ;; [[compat-tests:length<]]
+  "Returns non-nil if SEQUENCE is shorter than LENGTH."
+  (cond
+   ((null sequence) (not (zerop length)))
+   ((listp sequence)
+    (null (nthcdr (1- length) sequence)))
+   ((arrayp sequence)
+    (< (length sequence) length))
+   (t (signal 'wrong-type-argument (list 'sequencep sequence)))))
+
+(compat-defun length> (sequence length) ;; [[compat-tests:length>]]
+  "Returns non-nil if SEQUENCE is longer than LENGTH."
+  (cond
+   ((listp sequence)
+    (and (nthcdr length sequence) t))
+   ((arrayp sequence)
+    (> (length sequence) length))
+   (t (signal 'wrong-type-argument (list 'sequencep sequence)))))
+
+;;;; Defined in fileio.c
+
+(compat-defun file-name-concat (directory &rest components) ;; <compat-tests:file-name-concat>
+  "Append COMPONENTS to DIRECTORY and return the resulting string.
+Elements in COMPONENTS must be a string or nil.
+DIRECTORY or the non-final elements in COMPONENTS may or may not end
+with a slash -- if they don’t end with a slash, a slash will be
+inserted before contatenating."
+  (let ((separator (eval-when-compile
+                     (if (memq system-type '(ms-dos windows-nt cygwin))
+                         "\\" "/")))
+        (components (delq nil
+                          (mapcar (lambda (x) (and (not (equal "" x)) x))
+                                  (cons directory components))))
+        (result ""))
+    (while components
+      (let ((c (pop components)))
+        (setq result (concat result c
+                             (and components
+                                  (not (string-suffix-p separator c))
+                                  separator)))))
+    result))
+
+;;;; Defined in alloc.c
+
+(compat-defalias garbage-collect-maybe ignore) ;; <compat-tests:garbage-collect-maybe>
+
+;;;; Defined in characters.c
+
+(compat-defun string-width (string &optional from to) ;; <compat-tests:string-width>
+  "Handle optional arguments FROM and TO."
+  :extended t
+  (let* ((len (length string))
+         (from (or from 0))
+         (to (or to len)))
+    (if (and (= from 0) (= to len))
+        (string-width string)
+      (string-width (substring string from to)))))
+
+;;;; Defined in dired.c
+
+(compat-defun directory-files (directory &optional full match nosort count) ;; <compat-tests:directory-files>
+  "Handle additional optional argument COUNT."
+  :extended t
+  (let ((files (directory-files directory full match nosort)))
+    (when (natnump count)
+      (setf (nthcdr count files) nil))
+    files))
+
+(compat-defun directory-files-and-attributes (directory &optional full match nosort id-format count) ;; <compat-tests:directory-files-and-attributes>
+  "Handle additional optional argument COUNT."
+  :extended t
+  (let ((files (directory-files-and-attributes directory full match nosort id-format)))
+    (when (natnump count)
+      (setf (nthcdr count files) nil))
+    files))
+
+;;;; xfaces.c
+
+(compat-defun color-values-from-color-spec (spec) ;; <compat-tests:color-values-from-color-spec>
+  "Parse color SPEC as a numeric color and return (RED GREEN BLUE).
+This function recognises the following formats for SPEC:
+
+ #RGB, where R, G and B are hex numbers of equal length, 1-4 digits each.
+ rgb:R/G/B, where R, G, and B are hex numbers, 1-4 digits each.
+ rgbi:R/G/B, where R, G and B are floating-point numbers in [0,1].
+
+If SPEC is not in one of the above forms, return nil.
+
+Each of the 3 integer members of the resulting list, RED, GREEN,
+and BLUE, is normalized to have its value in [0,65535]."
+  (let ((case-fold-search nil))
+    (save-match-data
+      (cond
+       ((string-match
+         ;; (rx bos "#"
+         ;;     (or (: (group-n 1 (= 1 hex)) (group-n 2 (= 1 hex)) (group-n 3 (= 1 hex)))
+         ;;         (: (group-n 1 (= 2 hex)) (group-n 2 (= 2 hex)) (group-n 3 (= 2 hex)))
+         ;;         (: (group-n 1 (= 3 hex)) (group-n 2 (= 3 hex)) (group-n 3 (= 3 hex)))
+         ;;         (: (group-n 1 (= 4 hex)) (group-n 2 (= 4 hex)) (group-n 3 (= 4 hex))))
+         ;;     eos)
+         "\\`#\\(?:\\(?1:[[:xdigit:]]\\{1\\}\\)\\(?2:[[:xdigit:]]\\{1\\}\\)\\(?3:[[:xdigit:]]\\{1\\}\\)\\|\\(?1:[[:xdigit:]]\\{2\\}\\)\\(?2:[[:xdigit:]]\\{2\\}\\)\\(?3:[[:xdigit:]]\\{2\\}\\)\\|\\(?1:[[:xdigit:]]\\{3\\}\\)\\(?2:[[:xdigit:]]\\{3\\}\\)\\(?3:[[:xdigit:]]\\{3\\}\\)\\|\\(?1:[[:xdigit:]]\\{4\\}\\)\\(?2:[[:xdigit:]]\\{4\\}\\)\\(?3:[[:xdigit:]]\\{4\\}\\)\\)\\'"
+         spec)
+        (let ((max (1- (ash 1 (* (- (match-end 1) (match-beginning 1)) 4)))))
+          (list (/ (* (string-to-number (match-string 1 spec) 16) 65535) max)
+                (/ (* (string-to-number (match-string 2 spec) 16) 65535) max)
+                (/ (* (string-to-number (match-string 3 spec) 16) 65535) max))))
+       ((string-match
+         ;; (rx bos "rgb:"
+         ;;     (group (** 1 4 hex)) "/"
+         ;;     (group (** 1 4 hex)) "/"
+         ;;     (group (** 1 4 hex))
+         ;;     eos)
+         "\\`rgb:\\([[:xdigit:]]\\{1,4\\}\\)/\\([[:xdigit:]]\\{1,4\\}\\)/\\([[:xdigit:]]\\{1,4\\}\\)\\'"
+         spec)
+        (list (/ (* (string-to-number (match-string 1 spec) 16) 65535)
+                 (1- (ash 1 (* (- (match-end 1) (match-beginning 1)) 4))))
+              (/ (* (string-to-number (match-string 2 spec) 16) 65535)
+                 (1- (ash 1 (* (- (match-end 2) (match-beginning 2)) 4))))
+              (/ (* (string-to-number (match-string 3 spec) 16) 65535)
+                 (1- (ash 1 (* (- (match-end 3) (match-beginning 3)) 4))))))
+       ;; The "RGBi" (RGB Intensity) specification is defined by
+       ;; XCMS[0], see [1] for the implementation in Xlib.
+       ;;
+       ;; [0] https://www.nic.funet.fi/pub/X11/X11R4/DOCS/color/Xcms.text
+       ;; [1] https://gitlab.freedesktop.org/xorg/lib/libx11/-/blob/master/src/xcms/LRGB.c#L1392
+       ((string-match
+         ;; (rx bos "rgbi:" (* space)
+         ;;     (group (? (or "-" "+"))
+         ;;            (or (: (+ digit) (? "." (* digit)))
+         ;;                (: "." (+ digit)))
+         ;;            (? "e" (? (or "-" "+")) (+ digit)))
+         ;;     "/" (* space)
+         ;;     (group (? (or "-" "+"))
+         ;;            (or (: (+ digit) (? "." (* digit)))
+         ;;                (: "." (+ digit)))
+         ;;            (? "e" (? (or "-" "+")) (+ digit)))
+         ;;     "/" (* space)
+         ;;     (group (? (or "-" "+"))
+         ;;            (or (: (+ digit) (? "." (* digit)))
+         ;;                (: "." (+ digit)))
+         ;;            (? "e" (? (or "-" "+")) (+ digit)))
+         ;;     eos)
+         "\\`rgbi:[[:space:]]*\\([+-]?\\(?:[[:digit:]]+\\(?:\\.[[:digit:]]*\\)?\\|\\.[[:digit:]]+\\)\\(?:e[+-]?[[:digit:]]+\\)?\\)/[[:space:]]*\\([+-]?\\(?:[[:digit:]]+\\(?:\\.[[:digit:]]*\\)?\\|\\.[[:digit:]]+\\)\\(?:e[+-]?[[:digit:]]+\\)?\\)/[[:space:]]*\\([+-]?\\(?:[[:digit:]]+\\(?:\\.[[:digit:]]*\\)?\\|\\.[[:digit:]]+\\)\\(?:e[+-]?[[:digit:]]+\\)?\\)\\'"
+         spec)
+        (let ((r (round (* (string-to-number (match-string 1 spec)) 65535)))
+              (g (round (* (string-to-number (match-string 2 spec)) 65535)))
+              (b (round (* (string-to-number (match-string 3 spec)) 65535))))
+          (when (and (<= 0 r) (<= r 65535)
+                     (<= 0 g) (<= g 65535)
+                     (<= 0 b) (<= b 65535))
+            (list r g b))))))))
+
+;;;; Defined in simple.el
+
+(compat-defun make-separator-line (&optional length) ;; <compat-tests:make-separator-line>
+  "Make a string appropriate for usage as a visual separator line.
+If LENGTH is nil, use the window width."
+  (if (display-graphic-p)
+      (if length
+          (concat (propertize (make-string length ?\s) 'face '(:underline t)) "\n")
+        (propertize "\n" 'face '(:extend t :height 0.1 :inverse-video t)))
+    (concat (make-string (or length (1- (window-width))) ?-) "\n")))
+
+;;;; Defined in subr.el
+
+(compat-defun process-lines-handling-status (program status-handler &rest args) ;; <compat-tests:process-lines-handling-status>
+  "Execute PROGRAM with ARGS, returning its output as a list of lines.
+If STATUS-HANDLER is non-nil, it must be a function with one
+argument, which will be called with the exit status of the
+program before the output is collected.  If STATUS-HANDLER is
+nil, an error is signaled if the program returns with a non-zero
+exit status."
+  (with-temp-buffer
+    (let ((status (apply #'call-process program nil (current-buffer) nil args)))
+      (if status-handler
+          (funcall status-handler status)
+        (unless (eq status 0)
+          (error "%s exited with status %s" program status)))
+      (goto-char (point-min))
+      (let (lines)
+        (while (not (eobp))
+          (setq lines (cons (buffer-substring-no-properties
+                             (line-beginning-position)
+                             (line-end-position))
+                            lines))
+          (forward-line 1))
+        (nreverse lines)))))
+
+(compat-defun process-lines-ignore-status (program &rest args) ;; <compat-tests:process-lines-ignore-status>
+  "Execute PROGRAM with ARGS, returning its output as a list of lines.
+The exit status of the program is ignored.
+Also see `process-lines'."
+  (apply 'process-lines-handling-status program #'ignore args))
+
+;; FIXME Should handle multibyte regular expressions
+(compat-defun string-replace (fromstring tostring instring) ;; <compat-tests:string-replace>
+  "Replace FROMSTRING with TOSTRING in INSTRING each time it occurs."
+  (when (equal fromstring "")
+    (signal 'wrong-length-argument '(0)))
+  (let ((case-fold-search nil))
+    (replace-regexp-in-string
+     (regexp-quote fromstring)
+     tostring instring
+     t t)))
+
+(compat-defun always (&rest _arguments) ;; <compat-tests:always>
+  "Do nothing and return t.
+This function accepts any number of ARGUMENTS, but ignores them.
+Also see `ignore'."
+  t)
+
+(compat-defun insert-into-buffer (buffer &optional start end) ;; <compat-tests:insert-into-buffer>
+  "Insert the contents of the current buffer into BUFFER.
+If START/END, only insert that region from the current buffer.
+Point in BUFFER will be placed after the inserted text."
+  (let ((current (current-buffer)))
+    (with-current-buffer buffer
+      (insert-buffer-substring current start end))))
+
+(compat-defun replace-string-in-region (string replacement &optional start end) ;; <compat-tests:replace-string-in-region>
+  "Replace STRING with REPLACEMENT in the region from START to END.
+The number of replaced occurrences are returned, or nil if STRING
+doesn't exist in the region.
+
+If START is nil, use the current point.  If END is nil, use `point-max'.
+
+Comparisons and replacements are done with fixed case."
+  (if start
+      (when (< start (point-min))
+        (error "Start before start of buffer"))
+    (setq start (point)))
+  (if end
+      (when (> end (point-max))
+        (error "End after end of buffer"))
+    (setq end (point-max)))
+  (save-excursion
+    (goto-char start)
+    (save-restriction
+      (narrow-to-region start end)
+      (let ((matches 0)
+            (case-fold-search nil))
+        (while (search-forward string nil t)
+          (delete-region (match-beginning 0) (match-end 0))
+          (insert replacement)
+          (setq matches (1+ matches)))
+        (and (not (zerop matches))
+             matches)))))
+
+(compat-defun replace-regexp-in-region (regexp replacement &optional start end) ;; <compat-tests:replace-regexp-in-region>
+  "Replace REGEXP with REPLACEMENT in the region from START to END.
+The number of replaced occurrences are returned, or nil if REGEXP
+doesn't exist in the region.
+
+If START is nil, use the current point.  If END is nil, use `point-max'.
+
+Comparisons and replacements are done with fixed case.
+
+REPLACEMENT can use the following special elements:
+
+  `\\&' in NEWTEXT means substitute original matched text.
+  `\\N' means substitute what matched the Nth `\\(...\\)'.
+       If Nth parens didn't match, substitute nothing.
+  `\\\\' means insert one `\\'.
+  `\\?' is treated literally."
+  (if start
+      (when (< start (point-min))
+        (error "Start before start of buffer"))
+    (setq start (point)))
+  (if end
+      (when (> end (point-max))
+        (error "End after end of buffer"))
+    (setq end (point-max)))
+  (save-excursion
+    (goto-char start)
+    (save-restriction
+      (narrow-to-region start end)
+      (let ((matches 0)
+            (case-fold-search nil))
+          (while (re-search-forward regexp nil t)
+          (replace-match replacement t)
+          (setq matches (1+ matches)))
+        (and (not (zerop matches))
+             matches)))))
+
+(compat-defun buffer-local-boundp (symbol buffer) ;; <compat-tests:buffer-local-boundp>
+  "Return non-nil if SYMBOL is bound in BUFFER.
+Also see `local-variable-p'."
+  (condition-case nil
+      (progn (buffer-local-value symbol buffer)
+             t)
+    (void-variable nil)))
+
+(compat-defmacro with-existing-directory (&rest body) ;; <compat-tests:with-existing-directory>
+  "Execute BODY with `default-directory' bound to an existing directory.
+If `default-directory' is already an existing directory, it's not changed."
+  (declare (indent 0) (debug t))
+  `(let ((default-directory
+          (or (catch 'quit
+                (dolist (dir (list default-directory
+                                   (expand-file-name "~/")
+                                   temporary-file-directory
+                                   (getenv "TMPDIR")
+                                   "/tmp/"))
+                  (when (and dir (file-exists-p dir))
+                    (throw 'quit dir))))
+              "/")))
+     ,@body))
+
+(compat-defmacro dlet (binders &rest body) ;; <compat-tests:dlet>
+  "Like `let' but using dynamic scoping."
+  (declare (indent 1) (debug let))
+  `(let (_)
+     ,@(mapcar (lambda (binder)
+                 `(defvar ,(if (consp binder) (car binder) binder)))
+               binders)
+     (let ,binders ,@body)))
+
+(compat-defun ensure-list (object) ;; <compat-tests:ensure-list>
+  "Return OBJECT as a list.
+If OBJECT is already a list, return OBJECT itself.  If it's
+not a list, return a one-element list containing OBJECT."
+  (if (listp object)
+      object
+    (list object)))
+
+(compat-defalias subr-primitive-p subrp) ;; <compat-tests:subr-primitive-p>
+
+;;;; Defined in data.c
+
+(compat-defalias subr-native-elisp-p ignore) ;; <compat-tests:subr-native-elisp-p>
+
+;;;; Defined in subr-x.el
+
+(compat-defun string-clean-whitespace (string) ;; <compat-tests:string-clean-whitespace>
+  "Clean up whitespace in STRING.
+All sequences of whitespaces in STRING are collapsed into a
+single space character, and leading/trailing whitespace is
+removed."
+  (let ((blank "[[:blank:]\r\n]+"))
+    (replace-regexp-in-string
+     "^[[:blank:]\r\n]+\\|[[:blank:]\r\n]+$"
+     ""
+     (replace-regexp-in-string
+      blank " " string))))
+
+(compat-defun string-fill (string length) ;; <compat-tests:string-fill>
+  "Clean up whitespace in STRING.
+All sequences of whitespaces in STRING are collapsed into a
+single space character, and leading/trailing whitespace is
+removed."
+  (with-temp-buffer
+    (insert string)
+    (goto-char (point-min))
+    (let ((fill-column length)
+          (adaptive-fill-mode nil))
+      (fill-region (point-min) (point-max)))
+    (buffer-string)))
+
+(compat-defun string-pad (string length &optional padding start) ;; <compat-tests:string-pad>
+  "Pad STRING to LENGTH using PADDING.
+If PADDING is nil, the space character is used.  If not nil, it
+should be a character.
+
+If STRING is longer than the absolute value of LENGTH, no padding
+is done.
+
+If START is nil (or not present), the padding is done to the end
+of the string, and if non-nil, padding is done to the start of
+the string."
+  (unless (natnump length)
+    (signal 'wrong-type-argument (list 'natnump length)))
+  (let ((pad-length (- length (length string))))
+    (if (< pad-length 0)
+        string
+      (concat (and start
+                   (make-string pad-length (or padding ?\s)))
+              string
+              (and (not start)
+                   (make-string pad-length (or padding ?\s)))))))
+
+(compat-defun string-chop-newline (string) ;; <compat-tests:string-chop-newline>
+  "Remove the final newline (if any) from STRING."
+  (if (and (>= (length string) 1) (= (aref string (1- (length string))) ?\n))
+      (substring string 0 -1)
+    string))
+
+(compat-defmacro named-let (name bindings &rest body) ;; <compat-tests:named-let>
+  "Looping construct taken from Scheme.
+Like `let', bind variables in BINDINGS and then evaluate BODY,
+but with the twist that BODY can evaluate itself recursively by
+calling NAME, where the arguments passed to NAME are used
+as the new values of the bound variables in the recursive invocation."
+  (declare (indent 2) (debug (symbolp (&rest (symbolp form)) body)))
+  (let ((fargs (mapcar (lambda (b)
+                         (let ((var (if (consp b) (car b) b)))
+                           (make-symbol (symbol-name var))))
+                       bindings))
+        (aargs (mapcar (lambda (b) (if (consp b) (cadr b))) bindings))
+        rargs)
+    (dotimes (i (length bindings))
+      (let ((b (nth i bindings)))
+        (push (list (if (consp b) (car b) b) (nth i fargs))
+              rargs)
+        (setf (if (consp b) (car b) b)
+              (nth i fargs))))
+    (letrec
+        ((quit (make-symbol "quit")) (self (make-symbol "self"))
+         (total-tco t)
+         (macro (lambda (&rest args)
+                  (setq total-tco nil)
+                  `(funcall ,self . ,args)))
+         ;; Based on `cl--self-tco':
+         (tco-progn (lambda (exprs)
+                      (append
+                       (butlast exprs)
+                       (list (funcall tco (car (last exprs)))))))
+         (tco (lambda (expr)
+                (cond
+                 ((eq (car-safe expr) 'if)
+                  (append (list 'if
+                                (cadr expr)
+                                (funcall tco (nth 2 expr)))
+                          (funcall tco-progn (nthcdr 3 expr))))
+                 ((eq (car-safe expr) 'cond)
+                  (let ((conds (cdr expr)) body)
+                    (while conds
+                      (let ((branch (pop conds)))
+                        (push (cond
+                               ((cdr branch) ;has tail
+                                (funcall tco-progn branch))
+                               ((null conds) ;last element
+                                (list t (funcall tco (car branch))))
+                               ((progn
+                                  branch)))
+                              body)))
+                    (cons 'cond (nreverse body))))
+                 ((eq (car-safe expr) 'or)
+                  (if (cddr expr)
+                      (let ((var (make-symbol "var")))
+                        `(let ((,var ,(cadr expr)))
+                           (if ,var ,(funcall tco var)
+                             ,(funcall tco (cons 'or (cddr expr))))))
+                    (funcall tco (cadr expr))))
+                 ((eq (car-safe expr) 'condition-case)
+                  (append (list 'condition-case (cadr expr) (nth 2 expr))
+                          (mapcar
+                           (lambda (handler)
+                             (cons (car handler)
+                                   (funcall tco-progn (cdr handler))))
+                           (nthcdr 3 expr))))
+                 ((memq (car-safe expr) '(and progn))
+                  (cons (car expr) (funcall tco-progn (cdr expr))))
+                 ((memq (car-safe expr) '(let let*))
+                  (append (list (car expr) (cadr expr))
+                          (funcall tco-progn (cddr expr))))
+                 ((eq (car-safe expr) name)
+                  (let (sets (args (cdr expr)))
+                    (dolist (farg fargs)
+                      (push (list farg (pop args))
+                            sets))
+                    (cons 'setq (apply #'nconc (nreverse sets)))))
+                 (`(throw ',quit ,expr))))))
+      (when-let ((tco-body (funcall tco (macroexpand-all (macroexp-progn body)))))
+        (setq body `((catch ',quit
+                       (while t (let ,rargs ,@(macroexp-unprogn tco-body)))))))
+      (let ((expand (macroexpand-all (macroexp-progn body) (list (cons name macro)))))
+        (if total-tco
+            `(let ,bindings ,expand)
+          `(funcall
+            (letrec ((,self (lambda ,fargs ,expand))) ,self)
+            ,@aargs))))))
+
+;;;; Defined in files.el
+
+(compat-defun file-name-with-extension (filename extension) ;; <compat-tests:file-name-with-extension>
+  "Set the EXTENSION of a FILENAME.
+The extension (in a file name) is the part that begins with the last \".\".
+
+Trims a leading dot from the EXTENSION so that either \"foo\" or
+\".foo\" can be given.
+
+Errors if the FILENAME or EXTENSION are empty, or if the given
+FILENAME has the format of a directory.
+
+See also `file-name-sans-extension'."
+  (let ((extn (string-remove-prefix "." extension)))
+    (cond
+     ((string= filename "")
+      (error "Empty filename"))
+     ((string= extn "")
+      (error "Malformed extension: %s" extension))
+     ((directory-name-p filename)
+      (error "Filename is a directory: %s" filename))
+     (t
+      (concat (file-name-sans-extension filename) "." extn)))))
+
+(compat-defun directory-empty-p (dir) ;; <compat-tests:directory-empty-p>
+  "Return t if DIR names an existing directory containing no other files.
+Return nil if DIR does not name a directory, or if there was
+trouble determining whether DIR is a directory or empty.
+
+Symbolic links to directories count as directories.
+See `file-symlink-p' to distinguish symlinks."
+  (and (file-directory-p dir)
+       (null (directory-files dir nil directory-files-no-dot-files-regexp t))))
+
+(compat-defun file-modes-number-to-symbolic (mode &optional filetype) ;; <compat-tests:file-modes-number-to-symbolic>
+  "Return a string describing a file's MODE.
+For instance, if MODE is #o700, then it produces `-rwx------'.
+FILETYPE if provided should be a character denoting the type of file,
+such as `?d' for a directory, or `?l' for a symbolic link and will override
+the leading `-' char."
+  (string
+   (or filetype
+       (pcase (ash mode -12)
+         ;; POSIX specifies that the file type is included in st_mode
+         ;; and provides names for the file types but values only for
+         ;; the permissions (e.g., S_IWOTH=2).
+
+         ;; (#o017 ??) ;; #define S_IFMT  00170000
+         (#o014 ?s)    ;; #define S_IFSOCK 0140000
+         (#o012 ?l)    ;; #define S_IFLNK  0120000
+         ;; (8  ??)    ;; #define S_IFREG  0100000
+         (#o006  ?b)   ;; #define S_IFBLK  0060000
+         (#o004  ?d)   ;; #define S_IFDIR  0040000
+         (#o002  ?c)   ;; #define S_IFCHR  0020000
+         (#o001  ?p)   ;; #define S_IFIFO  0010000
+         (_ ?-)))
+   (if (zerop (logand   256 mode)) ?- ?r)
+   (if (zerop (logand   128 mode)) ?- ?w)
+   (if (zerop (logand    64 mode))
+       (if (zerop (logand  2048 mode)) ?- ?S)
+     (if (zerop (logand  2048 mode)) ?x ?s))
+   (if (zerop (logand    32 mode)) ?- ?r)
+   (if (zerop (logand    16 mode)) ?- ?w)
+   (if (zerop (logand     8 mode))
+       (if (zerop (logand  1024 mode)) ?- ?S)
+     (if (zerop (logand  1024 mode)) ?x ?s))
+   (if (zerop (logand     4 mode)) ?- ?r)
+   (if (zerop (logand     2 mode)) ?- ?w)
+   (if (zerop (logand 512 mode))
+       (if (zerop (logand   1 mode)) ?- ?x)
+     (if (zerop (logand   1 mode)) ?T ?t))))
+
+(compat-defun file-backup-file-names (filename) ;; <compat-tests:file-backup-file-names>
+  "Return a list of backup files for FILENAME.
+The list will be sorted by modification time so that the most
+recent files are first."
+  ;; `make-backup-file-name' will get us the right directory for
+  ;; ordinary or numeric backups.  It might create a directory for
+  ;; backups as a side-effect, according to `backup-directory-alist'.
+  (let* ((filename (file-name-sans-versions
+                    (make-backup-file-name (expand-file-name filename))))
+         (dir (file-name-directory filename))
+         files)
+    (dolist (file (file-name-all-completions
+                   (file-name-nondirectory filename) dir))
+      (let ((candidate (concat dir file)))
+        (when (and (backup-file-name-p candidate)
+                   (string= (file-name-sans-versions candidate) filename))
+          (push candidate files))))
+    (sort files #'file-newer-than-file-p)))
+
+(compat-defun make-lock-file-name (filename) ;; <compat-tests:make-lock-file-name>
+  "Make a lock file name for FILENAME.
+This prepends \".#\" to the non-directory part of FILENAME, and
+doesn't respect `lock-file-name-transforms', as Emacs 28.1 and
+onwards does."
+  (expand-file-name
+   (concat
+    ".#" (file-name-nondirectory filename))
+   (file-name-directory filename)))
+
+;;;; Defined in minibuffer.el
+
+(compat-defun format-prompt (prompt default &rest format-args) ;; <compat-tests:format-prompt>
+  "Format PROMPT with DEFAULT.
+If FORMAT-ARGS is nil, PROMPT is used as a plain string.  If
+FORMAT-ARGS is non-nil, PROMPT is used as a format control
+string, and FORMAT-ARGS are the arguments to be substituted into
+it.  See `format' for details.
+
+If DEFAULT is a list, the first element is used as the default.
+If not, the element is used as is.
+
+If DEFAULT is nil or an empty string, no \"default value\" string
+is included in the return value."
+  (concat
+   (if (null format-args)
+       prompt
+     (apply #'format prompt format-args))
+   (and default
+        (or (not (stringp default))
+            (> (length default) 0))
+        (format " (default %s)"
+                (if (consp default)
+                    (car default)
+                  default)))
+   ": "))
+
+;;;; Defined in faces.el
+
+(compat-defvar color-luminance-dark-limit 0.325 ;; <compat-tests:color-dark-p>
+  "The relative luminance below which a color is considered \"dark\".
+A \"dark\" color in this sense provides better contrast with white
+than with black; see `color-dark-p'.
+This value was determined experimentally."
+  :constant t)
+
+(compat-defun color-dark-p (rgb) ;; <compat-tests:color-dark-p>
+  "Whether RGB is more readable against white than black.
+RGB is a 3-element list (R G B), each component in the range [0,1].
+This predicate can be used both for determining a suitable (black or white)
+contrast color with RGB as background and as foreground."
+  (unless (<= 0 (apply #'min rgb) (apply #'max rgb) 1)
+    (error "RGB components %S not in [0,1]" rgb))
+  ;; Compute the relative luminance after gamma-correcting (assuming sRGB),
+  ;; and compare to a cut-off value determined experimentally.
+  ;; See https://en.wikipedia.org/wiki/Relative_luminance for details.
+  (let* ((sr (nth 0 rgb))
+         (sg (nth 1 rgb))
+         (sb (nth 2 rgb))
+         ;; Gamma-correct the RGB components to linear values.
+         ;; Use the power 2.2 as an approximation to sRGB gamma;
+         ;; it should be good enough for the purpose of this function.
+         (r (expt sr 2.2))
+         (g (expt sg 2.2))
+         (b (expt sb 2.2))
+         (y (+ (* r 0.2126) (* g 0.7152) (* b 0.0722))))
+    (< y color-luminance-dark-limit)))
+
+;;;; Defined in window.el
+
+(compat-defmacro with-window-non-dedicated (window &rest body) ;; <compat-tests:with-window-non-dedicated>
+  "Evaluate BODY with WINDOW temporarily made non-dedicated.
+If WINDOW is nil, use the selected window.  Return the value of
+the last form in BODY."
+  (declare (indent 1) (debug t))
+  (let ((window-dedicated-sym (gensym))
+        (window-sym (gensym)))
+    `(let* ((,window-sym (window-normalize-window ,window t))
+            (,window-dedicated-sym (window-dedicated-p ,window-sym)))
+       (set-window-dedicated-p ,window-sym nil)
+       (unwind-protect
+           (progn ,@body)
+         (set-window-dedicated-p ,window-sym ,window-dedicated-sym)))))
+
+(compat-defun count-windows (&optional minibuf all-frames) ;; <compat-tests:count-windows>
+  "Handle optional argument ALL-FRAMES."
+  :extended t
+  (if all-frames
+      (let ((sum 0))
+        (dolist (frame (frame-list))
+          (with-selected-frame frame
+            (setq sum (+ (count-windows minibuf) sum))))
+        sum)
+    (count-windows minibuf)))
+
+;;;; Defined in thingatpt.el
+
+(compat-defun thing-at-mouse (event thing &optional no-properties) ;; <compat-tests:thing-at-mouse>
+  "Return the THING at mouse click.
+Like `thing-at-point', but tries to use the event
+where the mouse button is clicked to find a thing nearby."
+  ;; No :feature specified, since the function is autoloaded.
+  (save-excursion
+    (mouse-set-point event)
+    (thing-at-point thing no-properties)))
+
+(compat-defun bounds-of-thing-at-mouse (event thing) ;; <compat-tests:thing-at-mouse>
+  "Determine start and end locations for THING at mouse click given by EVENT.
+Like `bounds-of-thing-at-point', but tries to use the position in EVENT
+where the mouse button is clicked to find the thing nearby."
+  ;; No :feature specified, since the function is autoloaded.
+  (save-excursion
+    (mouse-set-point event)
+    (bounds-of-thing-at-point thing)))
+
+;;;; Defined in mouse.el
+
+(compat-defun mark-thing-at-mouse (click thing) ;; <compat-tests:thing-at-mouse>
+  "Activate the region around THING found near the mouse CLICK."
+  (when-let ((bounds (bounds-of-thing-at-mouse click thing)))
+    (goto-char (if mouse-select-region-move-to-beginning
+                   (car bounds) (cdr bounds)))
+    (push-mark (if mouse-select-region-move-to-beginning
+                   (cdr bounds) (car bounds))
+               t 'activate)))
+
+;;;; Defined in macroexp.el
+
+(compat-defun macroexp-warn-and-return (msg form &optional _category _compile-only _arg) ;; <compat-tests:macroexp-warn-and-return>
+  "Return code equivalent to FORM labeled with warning MSG.
+CATEGORY is the category of the warning, like the categories that
+can appear in `byte-compile-warnings'.
+COMPILE-ONLY non-nil means no warning should be emitted if the code
+is executed without being compiled first.
+ARG is a symbol (or a form) giving the source code position for the message.
+It should normally be a symbol with position and it defaults to FORM."
+  (macroexp--warn-and-return msg form))
+
+(compat-defun macroexp-file-name () ;; <compat-tests:macroexp-file-name>
+  "Return the name of the file from which the code comes.
+Returns nil when we do not know.
+A non-nil result is expected to be reliable when called from a macro in order
+to find the file in which the macro's call was found, and it should be
+reliable as well when used at the top-level of a file.
+Other uses risk returning non-nil value that point to the wrong file."
+  (let ((file (car (last current-load-list))))
+    (or (if (stringp file) file)
+        (bound-and-true-p byte-compile-current-file))))
+
+;;;; Defined in env.el
+
+(compat-defmacro with-environment-variables (variables &rest body) ;; <compat-tests:with-environment-variables>
+  "Set VARIABLES in the environment and execute BODY.
+VARIABLES is a list of variable settings of the form (VAR VALUE),
+where VAR is the name of the variable (a string) and VALUE
+is its value (also a string).
+
+The previous values will be be restored upon exit."
+  (declare (indent 1) (debug (sexp body)))
+  (unless (consp variables)
+    (error "Invalid VARIABLES: %s" variables))
+  `(let ((process-environment (copy-sequence process-environment)))
+     ,@(mapcar (lambda (elem)
+                 `(setenv ,(car elem) ,(cadr elem)))
+               variables)
+     ,@body))
+
+;;;; Defined in time-data.el
+
+(compat-defun decoded-time-period (time) ;; <compat-tests:decoded-time-period>
+  "Interpret DECODED as a period and return its length in seconds.
+For computational purposes, years are 365 days long and months
+are 30 days long."
+  :feature time-date
+  (+ (if (consp (decoded-time-second time))
+         (/ (float (car (decoded-time-second time)))
+            (cdr (decoded-time-second time)))
+       (or (decoded-time-second time) 0))
+     (* (or (decoded-time-minute time) 0) 60)
+     (* (or (decoded-time-hour time) 0) 60 60)
+     (* (or (decoded-time-day time) 0) 60 60 24)
+     (* (or (decoded-time-month time) 0) 60 60 24 30)
+     (* (or (decoded-time-year time) 0) 60 60 24 365)))
+
+;;;; Defined in doc.c
+
+(compat-defun text-quoting-style () ;; <compat-tests:text-quoting-style>
+  "Return the current effective text quoting style.
+If the variable `text-quoting-style' is `grave', `straight' or
+`curve', just return that value.  If it is nil (the default), return
+`grave' if curved quotes cannot be displayed (for instance, on a
+terminal with no support for these characters), otherwise return
+`quote'.  Any other value is treated as `grave'.
+
+Note that in contrast to the variable `text-quoting-style', this
+function will never return nil."
+  (cond
+   ((memq text-quoting-style '(grave straight curve))
+    text-quoting-style)
+   ((not text-quoting-style) 'grave)
+   (t 'curve)))
+
+;;;; Defined in button.el
+
+;; Obsolete Alias since 29
+(compat-defalias button-buttonize buttonize :obsolete t) ;; <compat-tests:button-buttonize>
+
+;;;; Defined in wid-edit.el
+
+(compat-guard t ;; <compat-tests:widget-natnum>
+  :feature wid-edit
+  (define-widget 'natnum 'restricted-sexp
+    "A nonnegative integer."
+    :tag "Integer (positive)"
+    :value 0
+    :type-error "This field should contain a nonnegative integer"
+    :match-alternatives '(natnump)))
+
+(provide 'compat-28)
+;;; compat-28.el ends here
diff --git a/elpa/compat-29.1.4.5/compat-29.el b/elpa/compat-29.1.4.5/compat-29.el
new file mode 100644 (file)
index 0000000..5b0a4df
--- /dev/null
@@ -0,0 +1,1599 @@
+;;; compat-29.el --- Functionality added in Emacs 29.1 -*- lexical-binding: t; -*-
+
+;; Copyright (C) 2021-2024 Free Software Foundation, Inc.
+
+;; This program is free software; you can redistribute it and/or modify
+;; it under the terms of the GNU General Public License as published by
+;; the Free Software Foundation, either version 3 of the License, or
+;; (at your option) any later version.
+
+;; This program is distributed in the hope that it will be useful,
+;; but WITHOUT ANY WARRANTY; without even the implied warranty of
+;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+;; GNU General Public License for more details.
+
+;; You should have received a copy of the GNU General Public License
+;; along with this program.  If not, see <https://www.gnu.org/licenses/>.
+
+;;; Commentary:
+
+;; Functionality added in Emacs 29.1, needed by older Emacs versions.
+
+;;; Code:
+
+(eval-when-compile (load "compat-macs.el" nil t t))
+(compat-require compat-28 "28.1")
+
+;; Preloaded in loadup.el
+(compat-require seq "29.1") ;; <compat-tests:seq>
+
+(compat-version "29.1")
+
+;;;; Defined in startup.el
+
+(compat-defvar lisp-directory ;; <compat-tests:lisp-directory>
+    (file-truename
+     (file-name-directory
+      (locate-file "simple" load-path (get-load-suffixes))))
+  "Directory where Emacs's own *.el and *.elc Lisp files are installed.")
+
+;;;; Defined in window.c
+
+(compat-defalias window-configuration-equal-p compare-window-configurations) ;; <compat-tests:window-configuration-equal-p>
+
+;;;; Defined in xdisp.c
+
+(compat-defun get-display-property (position prop &optional object properties) ;; <compat-tests:get-display-property>
+  "Get the value of the `display' property PROP at POSITION.
+If OBJECT, this should be a buffer or string where the property is
+fetched from.  If omitted, OBJECT defaults to the current buffer.
+
+If PROPERTIES, look for value of PROP in PROPERTIES instead of
+the properties at POSITION."
+  (if properties
+      (unless (listp properties)
+        (signal 'wrong-type-argument (list 'listp properties)))
+    (setq properties (get-text-property position 'display object)))
+  (cond
+   ((vectorp properties)
+    (catch 'found
+      (dotimes (i (length properties))
+        (let ((ent (aref properties i)))
+          (when (eq (car ent) prop)
+            (throw 'found (cadr ent )))))))
+   ((consp (car properties))
+    (condition-case nil
+        (cadr (assq prop properties))
+      ;; Silently handle improper lists:
+      (wrong-type-argument nil)))
+   ((and (consp (cdr properties))
+         (eq (car properties) prop))
+    (cadr properties))))
+
+;;;; Defined in fns.c
+
+(compat-defun ntake (n list) ;; <compat-tests:ntake>
+  "Modify LIST to keep only the first N elements.
+If N is zero or negative, return nil.
+If N is greater or equal to the length of LIST, return LIST unmodified.
+Otherwise, return LIST after truncating it."
+  (and (> n 0) (let ((cons (nthcdr (1- n) list)))
+                 (when cons (setcdr cons nil))
+                 list)))
+
+(compat-defun take (n list) ;; <compat-tests:take>
+  "Return the first N elements of LIST.
+If N is zero or negative, return nil.
+If N is greater or equal to the length of LIST, return LIST (or a copy)."
+  (declare (pure t) (side-effect-free t))
+  (let (copy)
+    (while (and (< 0 n) list)
+      (push (pop list) copy)
+      (setq n (1- n)))
+    (nreverse copy)))
+
+(compat-defun string-equal-ignore-case (string1 string2) ;; <compat-tests:string-equal-ignore-case>
+  "Like `string-equal', but case-insensitive.
+Upper-case and lower-case letters are treated as equal.
+Unibyte strings are converted to multibyte for comparison."
+  (declare (pure t) (side-effect-free t))
+  (eq t (compare-strings string1 0 nil string2 0 nil t)))
+
+(compat-defun plist-get (plist prop &optional predicate) ;; <compat-tests:plist-get>
+  "Handle optional argument PREDICATE."
+  :extended t
+  (pcase predicate
+    ((or `nil `eq) (plist-get plist prop))
+    (`equal (lax-plist-get plist prop))
+    (_ (catch 'found
+         (while (consp plist)
+           (when (funcall predicate prop (car plist))
+             (throw 'found (cadr plist)))
+           (setq plist (cddr plist)))))))
+
+(compat-defun plist-put (plist prop val &optional predicate) ;; <compat-tests:plist-get>
+  "Handle optional argument PREDICATE."
+  :extended t
+  (pcase predicate
+    ((or `nil `eq) (plist-put plist prop val))
+    (`equal (lax-plist-put plist prop val))
+    (_ (catch 'found
+         (let ((tail plist))
+           (while (consp tail)
+             (when (funcall predicate prop (car tail))
+               (setcar (cdr tail) val)
+               (throw 'found plist))
+             (setq tail (cddr tail))))
+         (nconc plist (list prop val))))))
+
+(compat-defun plist-member (plist prop &optional predicate) ;; <compat-tests:plist-get>
+  "Handle optional argument PREDICATE."
+  :extended t
+  (pcase predicate
+    ((or `nil `eq) (plist-member plist prop))
+    (_ (catch 'found
+         (while (consp plist)
+           (when (funcall predicate prop (car plist))
+             (throw 'found plist))
+           (setq plist (cddr plist)))))))
+
+;;;; Defined in gv.el
+
+(compat-guard t ;; <compat-tests:plist-get-gv>
+  (gv-define-expander compat--plist-get
+    (lambda (do plist prop &optional predicate)
+      (macroexp-let2 macroexp-copyable-p key prop
+        (gv-letplace (getter setter) plist
+          (macroexp-let2 nil p `(cdr (compat--plist-member ,getter ,key ,predicate))
+            (funcall do
+                     `(car ,p)
+                     (lambda (val)
+                       `(if ,p
+                            (setcar ,p ,val)
+                          ,(funcall setter
+                                    `(cons ,key (cons ,val ,getter)))))))))))
+  (unless (get 'plist-get 'gv-expander)
+    (put 'plist-get 'gv-expander (get 'compat--plist-get 'gv-expander))))
+
+;;;; Defined in editfns.c
+
+(compat-defun pos-bol (&optional n) ;; <compat-tests:pos-bol>
+  "Return the position of the first character on the current line.
+With optional argument N, scan forward N - 1 lines first.
+If the scan reaches the end of the buffer, return that position.
+
+This function ignores text display directionality; it returns the
+position of the first character in logical order, i.e. the smallest
+character position on the logical line.  See `vertical-motion' for
+movement by screen lines.
+
+This function does not move point.  Also see `line-beginning-position'."
+  (declare (side-effect-free t))
+  (let ((inhibit-field-text-motion t))
+    (line-beginning-position n)))
+
+(compat-defun pos-eol (&optional n) ;; <compat-tests:pos-bol>
+  "Return the position of the last character on the current line.
+With argument N not nil or 1, move forward N - 1 lines first.
+If scan reaches end of buffer, return that position.
+
+This function ignores text display directionality; it returns the
+position of the last character in logical order, i.e. the largest
+character position on the line.
+
+This function does not move point.  Also see `line-end-position'."
+  (declare (side-effect-free t))
+  (let ((inhibit-field-text-motion t))
+    (line-end-position n)))
+
+;;;; Defined in subr.el
+
+(compat-defmacro with-delayed-message (_args &rest body) ;; <compat-tests:with-delayed-message>
+  "Like `progn', but display MESSAGE if BODY takes longer than TIMEOUT seconds.
+The MESSAGE form will be evaluated immediately, but the resulting
+string will be displayed only if BODY takes longer than TIMEOUT seconds.
+
+NOTE: The compatibility function never displays the message,
+which is not problematic since the only effect of the function is
+to display a progress message to the user.  Backporting this
+feature is not possible, since the implementation is directly
+baked into the Elisp interpreter.
+
+\(fn (timeout message) &rest body)"
+  (declare (indent 1))
+  (macroexp-progn body))
+
+(compat-defun funcall-with-delayed-message (timeout message function) ;; <compat-tests:with-delayed-message>
+  "Like `funcall', but display MESSAGE if FUNCTION takes longer than TIMEOUT.
+TIMEOUT is a number of seconds, and can be an integer or a
+floating point number.  If FUNCTION takes less time to execute
+than TIMEOUT seconds, MESSAGE is not displayed.
+
+NOTE: The compatibility function never displays the message,
+which is not problematic since the only effect of the function is
+to display a progress message to the user.  Backporting this
+feature is not possible, since the implementation is directly
+baked into the Elisp interpreter."
+  (ignore timeout message)
+  (funcall function))
+
+(compat-defun string-lines (string &optional omit-nulls keep-newlines) ;; <compat-tests:string-lines>
+  "Handle additional KEEP-NEWLINES argument."
+  :extended "28.1"
+  (if (equal string "")
+      (if omit-nulls
+          nil
+        (list ""))
+    (let ((lines nil)
+          (start 0))
+      (while (< start (length string))
+        (let ((newline (string-search "\n" string start)))
+          (if newline
+              (progn
+                (when (or (not omit-nulls)
+                          (not (= start newline)))
+                  (let ((line (substring string start
+                                         (if keep-newlines
+                                             (1+ newline)
+                                           newline))))
+                    (when (not (and keep-newlines omit-nulls
+                                    (equal line "\n")))
+                      (push line lines))))
+                (setq start (1+ newline)))
+            (if (zerop start)
+                (push string lines)
+              (push (substring string start) lines))
+            (setq start (length string)))))
+      (nreverse lines))))
+
+(compat-defun readablep (object) ;; <compat-tests:readablep>
+  "Say whether OBJECT has a readable syntax.
+This means that OBJECT can be printed out and then read back
+again by the Lisp reader.  This function returns nil if OBJECT is
+unreadable, and the printed representation (from `prin1') of
+OBJECT if it is readable."
+  (declare (side-effect-free error-free))
+  (ignore-errors (equal object (read (prin1-to-string object)))))
+
+(compat-defun buffer-local-restore-state (states) ;; <compat-tests:buffer-local-set-state>
+  "Restore values of buffer-local variables recorded in STATES.
+STATES should be an object returned by `buffer-local-set-state'."
+  (dolist (state states)
+    (if (cadr state)
+        (set (car state) (caddr state))
+      (kill-local-variable (car state)))))
+
+(compat-defun buffer-local-set-state--get (pairs) ;; <compat-tests:buffer-local-set-state>
+  "Internal helper function."
+  (let ((states nil))
+    (while pairs
+      (push (list (car pairs)
+                  (and (boundp (car pairs))
+                       (local-variable-p (car pairs)))
+                  (and (boundp (car pairs))
+                       (symbol-value (car pairs))))
+            states)
+      (setq pairs (cddr pairs)))
+    (nreverse states)))
+
+(compat-defmacro buffer-local-set-state (&rest pairs) ;; <compat-tests:buffer-local-set-state>
+  "Like `setq-local', but allow restoring the previous state of locals later.
+This macro returns an object that can be passed to `buffer-local-restore-state'
+in order to restore the state of the local variables set via this macro.
+
+\(fn [VARIABLE VALUE]...)"
+  (declare (debug setq))
+  (unless (zerop (mod (length pairs) 2))
+    (error "PAIRS must have an even number of variable/value members"))
+  `(prog1
+       (buffer-local-set-state--get ',pairs)
+     (,(if (fboundp 'compat--setq-local) 'compat--setq-local 'setq-local)
+      ,@pairs)))
+
+(compat-defun list-of-strings-p (object) ;; <compat-tests:list-of-strings-p>
+  "Return t if OBJECT is nil or a list of strings."
+  (declare (pure t) (side-effect-free t))
+  (while (and (consp object) (stringp (car object)))
+    (setq object (cdr object)))
+  (null object))
+
+(compat-defun plistp (object) ;; <compat-tests:plistp>
+  "Non-nil if and only if OBJECT is a valid plist."
+  (let ((len (proper-list-p object)))
+    (and len (zerop (% len 2)))))
+
+(compat-defun delete-line () ;; <compat-tests:delete-line>
+  "Delete the current line."
+  (delete-region (pos-bol) (pos-bol 2)))
+
+(compat-defmacro with-restriction (start end &rest rest) ;; <compat-tests:with-restriction>
+  "Execute BODY with restrictions set to START and END.
+
+The current restrictions, if any, are restored upon return.
+
+When the optional :label LABEL argument is present, in which
+LABEL is a symbol, inside BODY, `narrow-to-region' and `widen'
+can be used only within the START and END limits.  To gain access
+to other portions of the buffer, use `without-restriction' with the
+same LABEL argument.
+
+\(fn START END [:label LABEL] BODY)"
+  (declare (indent 0) (debug t))
+  `(save-restriction
+     (narrow-to-region ,start ,end)
+     ;; Locking is ignored
+     ,@(if (eq (car rest) :label) (cddr rest) rest)))
+
+(compat-defmacro without-restriction (&rest rest) ;; <compat-tests:without-restriction>
+  "Execute BODY without restrictions.
+
+The current restrictions, if any, are restored upon return.
+
+When the optional :label LABEL argument is present, the
+restrictions set by `with-restriction' with the same LABEL argument
+are lifted.
+
+\(fn [:label LABEL] BODY)"
+  (declare (indent 0) (debug t))
+  `(save-restriction
+     (widen)
+     ;; Locking is ignored
+     ,@(if (eq (car rest) :label) (cddr rest) rest)))
+
+(compat-defmacro with-memoization (place &rest code) ;; <compat-tests:with-memoization>
+  "Return the value of CODE and stash it in PLACE.
+If PLACE's value is non-nil, then don't bother evaluating CODE
+and return the value found in PLACE instead."
+  (declare (indent 1))
+  (gv-letplace (getter setter) place
+    `(or ,getter
+         ,(macroexp-let2 nil val (macroexp-progn code)
+            `(progn
+               ,(funcall setter val)
+               ,val)))))
+
+(compat-defalias string-split split-string) ;; <compat-tests:string-split>
+
+(compat-defun compiled-function-p (object) ;; <compat-tests:compiled-function-p>
+  "Return non-nil if OBJECT is a function that has been compiled.
+Does not distinguish between functions implemented in machine code
+or byte-code."
+  (or (subrp object) (byte-code-function-p object)))
+
+(compat-defun function-alias-p (func &optional noerror) ;; <compat-tests:function-alias-p>
+  "Return nil if FUNC is not a function alias.
+If FUNC is a function alias, return the function alias chain.
+
+If the function alias chain contains loops, an error will be
+signalled.  If NOERROR, the non-loop parts of the chain is returned."
+  (declare (side-effect-free t))
+  (let ((chain nil)
+        (orig-func func))
+    (nreverse
+     (catch 'loop
+       (while (and (symbolp func)
+                   (setq func (symbol-function func))
+                   (symbolp func))
+         (when (or (memq func chain)
+                   (eq func orig-func))
+           (if noerror
+               (throw 'loop chain)
+             (signal 'cyclic-function-indirection (list orig-func))))
+         (push func chain))
+       chain))))
+
+(compat-defun buffer-match-p (condition buffer-or-name &optional arg) ;; <compat-tests:buffer-match-p>
+  "Return non-nil if BUFFER-OR-NAME matches CONDITION.
+CONDITION is either:
+- the symbol t, to always match,
+- the symbol nil, which never matches,
+- a regular expression, to match a buffer name,
+- a predicate function that takes a buffer object and ARG as
+  arguments, and returns non-nil if the buffer matches,
+- a cons-cell, where the car describes how to interpret the cdr.
+  The car can be one of the following:
+  * `derived-mode': the buffer matches if the buffer's major mode
+    is derived from the major mode in the cons-cell's cdr.
+  * `major-mode': the buffer matches if the buffer's major mode
+    is eq to the cons-cell's cdr.  Prefer using `derived-mode'
+    instead when both can work.
+  * `not': the cadr is interpreted as a negation of a condition.
+  * `and': the cdr is a list of recursive conditions, that all have
+    to be met.
+  * `or': the cdr is a list of recursive condition, of which at
+    least one has to be met."
+  (letrec
+      ((buffer (get-buffer buffer-or-name))
+       (match
+        (lambda (conditions)
+          (catch 'match
+            (dolist (condition conditions)
+              (when (cond
+                     ((eq condition t))
+                     ((stringp condition)
+                      (string-match-p condition (buffer-name buffer)))
+                     ((functionp condition)
+                      (condition-case nil
+                          (funcall condition buffer)
+                        (wrong-number-of-arguments
+                         (funcall condition buffer arg))))
+                     ((eq (car-safe condition) 'major-mode)
+                      (eq
+                       (buffer-local-value 'major-mode buffer)
+                       (cdr condition)))
+                     ((eq (car-safe condition) 'derived-mode)
+                      (provided-mode-derived-p
+                       (buffer-local-value 'major-mode buffer)
+                       (cdr condition)))
+                     ((eq (car-safe condition) 'not)
+                      (not (funcall match (cdr condition))))
+                     ((eq (car-safe condition) 'or)
+                      (funcall match (cdr condition)))
+                     ((eq (car-safe condition) 'and)
+                      (catch 'fail
+                        (dolist (c (cdr condition))
+                          (unless (funcall match (list c))
+                            (throw 'fail nil)))
+                        t)))
+                (throw 'match t)))))))
+    (funcall match (list condition))))
+
+(compat-defun match-buffers (condition &optional buffers arg) ;; <compat-tests:match-buffers>
+  "Return a list of buffers that match CONDITION.
+See `buffer-match' for details on CONDITION.  By default all
+buffers are checked, this can be restricted by passing an
+optional argument BUFFERS, set to a list of buffers to check.
+ARG is passed to `buffer-match', for predicate conditions in
+CONDITION."
+  (let (bufs)
+    (dolist (buf (or buffers (buffer-list)))
+      (when (buffer-match-p condition (get-buffer buf) arg)
+        (push buf bufs)))
+    bufs))
+
+(compat-defvar set-transient-map-timeout nil ;; <compat-tests:set-transient-map>
+  "Timeout in seconds for deactivation of a transient keymap.
+If this is a number, it specifies the amount of idle time
+after which to deactivate the keymap set by `set-transient-map',
+thus overriding the value of the TIMEOUT argument to that function.")
+
+(compat-defvar set-transient-map-timer nil ;; <compat-tests:set-transient-map>
+  "Timer for `set-transient-map-timeout'.")
+
+(declare-function format-spec "format-spec")
+(compat-defun set-transient-map (map &optional keep-pred on-exit message timeout) ;; <compat-tests:set-transient-map>
+  "Handle the optional arguments MESSAGE and TIMEOUT."
+  :extended t
+  (unless (fboundp 'format-spec)
+    (require 'format-spec))
+  (let* ((timeout (or set-transient-map-timeout timeout))
+         (message
+          (when message
+            (let (keys)
+              (map-keymap (lambda (key cmd) (and cmd (push key keys))) map)
+              (format-spec (if (stringp message) message "Repeat with %k")
+                           `((?k . ,(mapconcat
+                                     (lambda (key)
+                                       (substitute-command-keys
+                                        (format "\\`%s'"
+                                                (key-description (vector key)))))
+                                     keys ", ")))))))
+         (clearfun (make-symbol "clear-transient-map"))
+         (exitfun
+          (lambda ()
+            (internal-pop-keymap map 'overriding-terminal-local-map)
+            (remove-hook 'pre-command-hook clearfun)
+            (when message (message ""))
+            (when set-transient-map-timer (cancel-timer set-transient-map-timer))
+            (when on-exit (funcall on-exit)))))
+    (fset clearfun
+          (lambda ()
+            (with-demoted-errors "set-transient-map PCH: %S"
+              (if (cond
+                       ((null keep-pred) nil)
+                       ((and (not (eq map (cadr overriding-terminal-local-map)))
+                             (memq map (cddr overriding-terminal-local-map)))
+                        t)
+                       ((eq t keep-pred)
+                        (let ((mc (lookup-key map (this-command-keys-vector))))
+                          (when (and mc (symbolp mc))
+                            (setq mc (or (command-remapping mc) mc)))
+                          (and mc (eq this-command mc))))
+                       (t (funcall keep-pred)))
+                  (when message (message "%s" message))
+                (funcall exitfun)))))
+    (add-hook 'pre-command-hook clearfun)
+    (internal-push-keymap map 'overriding-terminal-local-map)
+    (when timeout
+      (when set-transient-map-timer (cancel-timer set-transient-map-timer))
+      (setq set-transient-map-timer (run-with-idle-timer timeout nil exitfun)))
+    (when message (message "%s" message))
+    exitfun))
+
+;;;; Defined in simple.el
+
+(compat-defun char-uppercase-p (char) ;; <compat-tests:char-uppercase-p>
+  "Return non-nil if CHAR is an upper-case character.
+If the Unicode tables are not yet available, e.g. during bootstrap,
+then gives correct answers only for ASCII characters."
+  (cond ((unicode-property-table-internal 'lowercase)
+         (characterp (get-char-code-property char 'lowercase)))
+        ((and (>= char ?A) (<= char ?Z)))))
+
+(compat-defun use-region-noncontiguous-p () ;; <compat-tests:region-noncontiguous-p>
+  "Return non-nil for a non-contiguous region if `use-region-p'."
+  (and (use-region-p) (region-noncontiguous-p)))
+
+(compat-defun use-region-beginning () ;; <compat-tests:use-region>
+  "Return the start of the region if `use-region-p'."
+  (and (use-region-p) (region-beginning)))
+
+(compat-defun use-region-end () ;; <compat-tests:use-region>
+  "Return the end of the region if `use-region-p'."
+  (and (use-region-p) (region-end)))
+
+(compat-defun get-scratch-buffer-create () ;; <compat-tests:get-scratch-buffer-create>
+  "Return the *scratch* buffer, creating a new one if needed."
+  (or (get-buffer "*scratch*")
+      (let ((scratch (get-buffer-create "*scratch*")))
+        ;; Don't touch the buffer contents or mode unless we know that
+        ;; we just created it.
+        (with-current-buffer scratch
+          (when initial-scratch-message
+            (insert (substitute-command-keys initial-scratch-message))
+            (set-buffer-modified-p nil))
+          (funcall initial-major-mode))
+        scratch)))
+
+;;;; Defined in subr-x.el
+
+(compat-defmacro with-buffer-unmodified-if-unchanged (&rest body) ;; <compat-tests:with-buffer-unmodified-if-unchanged>
+  "Like `progn', but change buffer-modified status only if buffer text changes.
+If the buffer was unmodified before execution of BODY, and
+buffer text after execution of BODY is identical to what it was
+before, ensure that buffer is still marked unmodified afterwards.
+For example, the following won't change the buffer's modification
+status:
+
+  (with-buffer-unmodified-if-unchanged
+    (insert \"a\")
+    (delete-char -1))
+
+Note that only changes in the raw byte sequence of the buffer text,
+as stored in the internal representation, are monitored for the
+purpose of detecting the lack of changes in buffer text.  Any other
+changes that are normally perceived as \"buffer modifications\", such
+as changes in text properties, `buffer-file-coding-system', buffer
+multibyteness, etc. -- will not be noticed, and the buffer will still
+be marked unmodified, effectively ignoring those changes."
+  (declare (debug t) (indent 0))
+  (let ((hash (gensym))
+        (buffer (gensym)))
+    `(let ((,hash (and (not (buffer-modified-p))
+                       (buffer-hash)))
+           (,buffer (current-buffer)))
+       (prog1
+           (progn
+             ,@body)
+         ;; If we didn't change anything in the buffer (and the buffer
+         ;; was previously unmodified), then flip the modification status
+         ;; back to "unchanged".
+         (when (and ,hash (buffer-live-p ,buffer))
+           (with-current-buffer ,buffer
+             (when (and (buffer-modified-p)
+                        (equal ,hash (buffer-hash)))
+               (restore-buffer-modified-p nil))))))))
+
+(compat-defun add-display-text-property (start end prop value ;; <compat-tests:add-display-text-property>
+                                               &optional object)
+  "Add display property PROP with VALUE to the text from START to END.
+If any text in the region has a non-nil `display' property, those
+properties are retained.
+
+If OBJECT is non-nil, it should be a string or a buffer.  If nil,
+this defaults to the current buffer."
+  (let ((sub-start start)
+        (sub-end 0)
+        disp)
+    (while (< sub-end end)
+      (setq sub-end (next-single-property-change sub-start 'display object
+                                                 (if (stringp object)
+                                                     (min (length object) end)
+                                                   (min end (point-max)))))
+      (if (not (setq disp (get-text-property sub-start 'display object)))
+          ;; No old properties in this range.
+          (put-text-property sub-start sub-end 'display (list prop value)
+                             object)
+        ;; We have old properties.
+        (let ((vector nil))
+          ;; Make disp into a list.
+          (setq disp
+                (cond
+                 ((vectorp disp)
+                  (setq vector t)
+                  (append disp nil))
+                 ((not (consp (car disp)))
+                  (list disp))
+                 (t
+                  disp)))
+          ;; Remove any old instances.
+          (when-let ((old (assoc prop disp)))
+            (setq disp (delete old disp)))
+          (setq disp (cons (list prop value) disp))
+          (when vector
+            (setq disp (vconcat disp)))
+          ;; Finally update the range.
+          (put-text-property sub-start sub-end 'display disp object)))
+      (setq sub-start sub-end))))
+
+(compat-defmacro while-let (spec &rest body) ;; <compat-tests:while-let>
+  "Bind variables according to SPEC and conditionally evaluate BODY.
+Evaluate each binding in turn, stopping if a binding value is nil.
+If all bindings are non-nil, eval BODY and repeat.
+
+The variable list SPEC is the same as in `if-let*'."
+  (declare (indent 1) (debug if-let))
+  (let ((done (gensym "done")))
+    `(catch ',done
+       (while t
+         (if-let* ,spec
+             (progn
+               ,@body)
+           (throw ',done nil))))))
+
+;;;; Defined in files.el
+
+(compat-defun directory-abbrev-make-regexp (directory) ;; <compat-tests:directory-abbrev-make-regexp>
+  "Create a regexp to match DIRECTORY for `directory-abbrev-alist'."
+  (let ((regexp
+         ;; We include a slash at the end, to avoid spurious
+         ;; matches such as `/usr/foobar' when the home dir is
+         ;; `/usr/foo'.
+         (concat "\\`" (regexp-quote directory) "\\(/\\|\\'\\)")))
+    ;; The value of regexp could be multibyte or unibyte.  In the
+    ;; latter case, we need to decode it.
+    (if (multibyte-string-p regexp)
+        regexp
+      (decode-coding-string regexp
+                            (if (eq system-type 'windows-nt)
+                                'utf-8
+                              locale-coding-system)))))
+
+(compat-defun directory-abbrev-apply (filename) ;; <compat-tests:directory-abbrev-apply>
+  "Apply the abbreviations in `directory-abbrev-alist' to FILENAME.
+Note that when calling this, you should set `case-fold-search' as
+appropriate for the filesystem used for FILENAME."
+  (dolist (dir-abbrev directory-abbrev-alist filename)
+    (when (string-match (car dir-abbrev) filename)
+         (setq filename (concat (cdr dir-abbrev)
+                                (substring filename (match-end 0)))))))
+
+(compat-defun file-name-split (filename) ;; <compat-tests:file-name-split>
+  "Return a list of all the components of FILENAME.
+On most systems, this will be true:
+
+  (equal (string-join (file-name-split filename) \"/\") filename)"
+  (let ((components nil))
+    ;; If this is a directory file name, then we have a null file name
+    ;; at the end.
+    (when (directory-name-p filename)
+      (push "" components)
+      (setq filename (directory-file-name filename)))
+    ;; Loop, chopping off components.
+    (while (length> filename 0)
+      (push (file-name-nondirectory filename) components)
+      (let ((dir (file-name-directory filename)))
+        (setq filename (and dir (directory-file-name dir)))
+        ;; If there's nothing left to peel off, we're at the root and
+        ;; we can stop.
+        (when (and dir (equal dir filename))
+          (push (if (equal dir "") ""
+                  ;; On Windows, the first component might be "c:" or
+                  ;; the like.
+                  (substring dir 0 -1))
+                components)
+          (setq filename nil))))
+    components))
+
+(compat-defun file-attribute-file-identifier (attributes) ;; <compat-tests:file-attribute-getters>
+  "The inode and device numbers in ATTRIBUTES returned by `file-attributes'.
+The value is a list of the form (INODENUM DEVICE), where DEVICE could be
+either a single number or a cons cell of two numbers.
+This tuple of numbers uniquely identifies the file."
+  (nthcdr 10 attributes))
+
+(compat-defun file-name-parent-directory (filename) ;; <compat-tests:file-name-parent-directory>
+  "Return the directory name of the parent directory of FILENAME.
+If FILENAME is at the root of the filesystem, return nil.
+If FILENAME is relative, it is interpreted to be relative
+to `default-directory', and the result will also be relative."
+  (let* ((expanded-filename (expand-file-name filename))
+         (parent (file-name-directory (directory-file-name expanded-filename))))
+    (cond
+     ;; filename is at top-level, therefore no parent
+     ((or (null parent)
+          ;; `equal' is enough, we don't need to resolve symlinks here
+          ;; with `file-equal-p', also for performance
+          (equal parent expanded-filename))
+      nil)
+     ;; filename is relative, return relative parent
+     ((not (file-name-absolute-p filename))
+      (file-relative-name parent))
+     (t
+      parent))))
+
+(compat-defvar file-has-changed-p--hash-table ;; <compat-tests:file-has-changed-p>
+               (make-hash-table :test #'equal)
+  "Internal variable used by `file-has-changed-p'.")
+
+(compat-defun file-has-changed-p (file &optional tag) ;; <compat-tests:file-has-changed-p>
+  "Return non-nil if FILE has changed.
+The size and modification time of FILE are compared to the size
+and modification time of the same FILE during a previous
+invocation of `file-has-changed-p'.  Thus, the first invocation
+of `file-has-changed-p' always returns non-nil when FILE exists.
+The optional argument TAG, which must be a symbol, can be used to
+limit the comparison to invocations with identical tags; it can be
+the symbol of the calling function, for example."
+  (let* ((file (directory-file-name (expand-file-name file)))
+         (remote-file-name-inhibit-cache t)
+         (fileattr (file-attributes file 'integer))
+         (attr (and fileattr
+                    (cons (file-attribute-size fileattr)
+                          (file-attribute-modification-time fileattr))))
+         (sym (concat (symbol-name tag) "@" file))
+         (cachedattr (gethash sym file-has-changed-p--hash-table)))
+    (unless (equal attr cachedattr)
+      (puthash sym attr file-has-changed-p--hash-table))))
+
+;;;; Defined in keymap.el
+
+(compat-defun key-valid-p (keys) ;; <compat-tests:key-valid-p>
+  "Say whether KEYS is a valid key.
+A key is a string consisting of one or more key strokes.
+The key strokes are separated by single space characters.
+
+Each key stroke is either a single character, or the name of an
+event, surrounded by angle brackets.  In addition, any key stroke
+may be preceded by one or more modifier keys.  Finally, a limited
+number of characters have a special shorthand syntax.
+
+Here's some example key sequences.
+
+  \"f\"           (the key `f')
+  \"S o m\"       (a three key sequence of the keys `S', `o' and `m')
+  \"C-c o\"       (a two key sequence of the keys `c' with the control modifier
+                 and then the key `o')
+  \"H-<left>\"    (the key named \"left\" with the hyper modifier)
+  \"M-RET\"       (the \"return\" key with a meta modifier)
+  \"C-M-<space>\" (the \"space\" key with both the control and meta modifiers)
+
+These are the characters that have shorthand syntax:
+NUL, RET, TAB, LFD, ESC, SPC, DEL.
+
+Modifiers have to be specified in this order:
+
+   A-C-H-M-S-s
+
+which is
+
+   Alt-Control-Hyper-Meta-Shift-super"
+  (declare (pure t) (side-effect-free t))
+  (let ((case-fold-search nil))
+    (and
+     (stringp keys)
+     (string-match-p "\\`[^ ]+\\( [^ ]+\\)*\\'" keys)
+     (save-match-data
+       (catch 'exit
+         (let ((prefixes
+                "\\(A-\\)?\\(C-\\)?\\(H-\\)?\\(M-\\)?\\(S-\\)?\\(s-\\)?"))
+           (dolist (key (split-string keys " "))
+             ;; Every key might have these modifiers, and they should be
+             ;; in this order.
+             (when (string-match (concat "\\`" prefixes) key)
+               (setq key (substring key (match-end 0))))
+             (unless (or (and (= (length key) 1)
+                              ;; Don't accept control characters as keys.
+                              (not (< (aref key 0) ?\s))
+                              ;; Don't accept Meta'd characters as keys.
+                              (or (multibyte-string-p key)
+                                  (not (<= 127 (aref key 0) 255))))
+                         (and (string-match-p "\\`<[-_A-Za-z0-9]+>\\'" key)
+                              ;; Don't allow <M-C-down>.
+                              (= (progn
+                                   (string-match
+                                    (concat "\\`<" prefixes) key)
+                                   (match-end 0))
+                                 1))
+                         (string-match-p
+                          "\\`\\(NUL\\|RET\\|TAB\\|LFD\\|ESC\\|SPC\\|DEL\\)\\'"
+                          key))
+               ;; Invalid.
+               (throw 'exit nil)))
+           t))))))
+
+(compat-defun keymap--check (key) ;; <compat-tests:keymap--check>
+  "Signal an error if KEY doesn't have a valid syntax."
+  (unless (key-valid-p key)
+    (error "%S is not a valid key definition; see `key-valid-p'" key)))
+
+(compat-defun key-parse (keys) ;; <compat-tests:key-parse>
+  "Convert KEYS to the internal Emacs key representation.
+See `kbd' for a descripion of KEYS."
+  (declare (pure t) (side-effect-free t))
+  ;; A pure function is expected to preserve the match data.
+  (save-match-data
+    (let ((case-fold-search nil)
+          (len (length keys)) ; We won't alter keys in the loop below.
+          (pos 0)
+          (res []))
+      (while (and (< pos len)
+                  (string-match "[^ \t\n\f]+" keys pos))
+        (let* ((word-beg (match-beginning 0))
+               (word-end (match-end 0))
+               (word (substring keys word-beg len))
+               (times 1)
+               key)
+          ;; Try to catch events of the form "<as df>".
+          (if (string-match "\\`<[^ <>\t\n\f][^>\t\n\f]*>" word)
+              (setq word (match-string 0 word)
+                    pos (+ word-beg (match-end 0)))
+            (setq word (substring keys word-beg word-end)
+                  pos word-end))
+          (when (string-match "\\([0-9]+\\)\\*." word)
+            (setq times (string-to-number (substring word 0 (match-end 1))))
+            (setq word (substring word (1+ (match-end 1)))))
+          (cond ((string-match "^<<.+>>$" word)
+                 (setq key (vconcat (if (eq (key-binding [?\M-x])
+                                            'execute-extended-command)
+                                        [?\M-x]
+                                      (or (car (where-is-internal
+                                                'execute-extended-command))
+                                          [?\M-x]))
+                                    (substring word 2 -2) "\r")))
+                ((and (string-match "^\\(\\([ACHMsS]-\\)*\\)<\\(.+\\)>$" word)
+                      (progn
+                        (setq word (concat (match-string 1 word)
+                                           (match-string 3 word)))
+                        (not (string-match
+                              "\\<\\(NUL\\|RET\\|LFD\\|ESC\\|SPC\\|DEL\\)$"
+                              word))))
+                 (setq key (list (intern word))))
+                ((or (equal word "REM") (string-match "^;;" word))
+                 (setq pos (string-match "$" keys pos)))
+                (t
+                 (let ((orig-word word) (prefix 0) (bits 0))
+                   (while (string-match "^[ACHMsS]-." word)
+                     (setq bits (+ bits
+                                   (cdr
+                                    (assq (aref word 0)
+                                          '((?A . ?\A-\0) (?C . ?\C-\0)
+                                            (?H . ?\H-\0) (?M . ?\M-\0)
+                                            (?s . ?\s-\0) (?S . ?\S-\0))))))
+                     (setq prefix (+ prefix 2))
+                     (setq word (substring word 2)))
+                   (when (string-match "^\\^.$" word)
+                     (setq bits (+ bits ?\C-\0))
+                     (setq prefix (1+ prefix))
+                     (setq word (substring word 1)))
+                   (let ((found (assoc word '(("NUL" . "\0") ("RET" . "\r")
+                                              ("LFD" . "\n") ("TAB" . "\t")
+                                              ("ESC" . "\e") ("SPC" . " ")
+                                              ("DEL" . "\177")))))
+                     (when found (setq word (cdr found))))
+                   (when (string-match "^\\\\[0-7]+$" word)
+                     (let ((n 0))
+                       (dolist (ch (cdr (string-to-list word)))
+                         (setq n (+ (* n 8) ch -48)))
+                       (setq word (vector n))))
+                   (cond ((= bits 0)
+                          (setq key word))
+                         ((and (= bits ?\M-\0) (stringp word)
+                               (string-match "^-?[0-9]+$" word))
+                          (setq key (mapcar (lambda (x) (+ x bits))
+                                            (append word nil))))
+                         ((/= (length word) 1)
+                          (error "%s must prefix a single character, not %s"
+                                 (substring orig-word 0 prefix) word))
+                         ((and (/= (logand bits ?\C-\0) 0) (stringp word)
+                               ;; We used to accept . and ? here,
+                               ;; but . is simply wrong,
+                               ;; and C-? is not used (we use DEL instead).
+                               (string-match "[@-_a-z]" word))
+                          (setq key (list (+ bits (- ?\C-\0)
+                                             (logand (aref word 0) 31)))))
+                         (t
+                          (setq key (list (+ bits (aref word 0)))))))))
+          (when key
+            (dolist (_ (number-sequence 1 times))
+              (setq res (vconcat res key))))))
+      res)))
+
+(compat-defun keymap-set (keymap key definition) ;; <compat-tests:defvar-keymap>
+  "Set KEY to DEFINITION in KEYMAP.
+KEY is a string that satisfies `key-valid-p'.
+
+DEFINITION is anything that can be a key's definition:
+ nil (means key is undefined in this keymap),
+ a command (a Lisp function suitable for interactive calling),
+ a string (treated as a keyboard macro),
+ a keymap (to define a prefix key),
+ a symbol (when the key is looked up, the symbol will stand for its
+    function definition, which should at that time be one of the above,
+    or another symbol whose function definition is used, etc.),
+ a cons (STRING . DEFN), meaning that DEFN is the definition
+    (DEFN should be a valid definition in its own right) and
+    STRING is the menu item name (which is used only if the containing
+    keymap has been created with a menu name, see `make-keymap'),
+ or a cons (MAP . CHAR), meaning use definition of CHAR in keymap MAP,
+ or an extended menu item definition.
+ (See info node `(elisp)Extended Menu Items'.)"
+  (keymap--check key)
+  (when (stringp definition)
+    (keymap--check definition)
+    (setq definition (key-parse definition)))
+  (define-key keymap (key-parse key) definition))
+
+(compat-defun keymap-unset (keymap key &optional remove) ;; <compat-tests:keymap-unset>
+  "Remove key sequence KEY from KEYMAP.
+KEY is a string that satisfies `key-valid-p'.
+
+If REMOVE, remove the binding instead of unsetting it.  This only
+makes a difference when there's a parent keymap.  When unsetting
+a key in a child map, it will still shadow the same key in the
+parent keymap.  Removing the binding will allow the key in the
+parent keymap to be used."
+  (keymap--check key)
+  (compat--define-key keymap (key-parse key) nil remove))
+
+(compat-defun keymap-global-set (key command) ;; <compat-tests:keymap-global-set>
+  "Give KEY a global binding as COMMAND.
+COMMAND is the command definition to use; usually it is
+a symbol naming an interactively-callable function.
+
+KEY is a string that satisfies `key-valid-p'.
+
+Note that if KEY has a local binding in the current buffer,
+that local binding will continue to shadow any global binding
+that you make with this function.
+
+NOTE: The compatibility version is not a command."
+  (keymap-set (current-global-map) key command))
+
+(compat-defun keymap-local-set (key command) ;; <compat-tests:keymap-local-set>
+  "Give KEY a local binding as COMMAND.
+COMMAND is the command definition to use; usually it is
+a symbol naming an interactively-callable function.
+
+KEY is a string that satisfies `key-valid-p'.
+
+The binding goes in the current buffer's local map, which in most
+cases is shared with all other buffers in the same major mode.
+
+NOTE: The compatibility version is not a command."
+  (let ((map (current-local-map)))
+    (unless map
+      (use-local-map (setq map (make-sparse-keymap))))
+    (keymap-set map key command)))
+
+(compat-defun keymap-global-unset (key &optional remove) ;; <compat-tests:keymap-global-unset>
+  "Remove global binding of KEY (if any).
+KEY is a string that satisfies `key-valid-p'.
+
+If REMOVE (interactively, the prefix arg), remove the binding
+instead of unsetting it.  See `keymap-unset' for details.
+
+NOTE: The compatibility version is not a command."
+  (keymap-unset (current-global-map) key remove))
+
+(compat-defun keymap-local-unset (key &optional remove) ;; <compat-tests:keymap-local-unset>
+  "Remove local binding of KEY (if any).
+KEY is a string that satisfies `key-valid-p'.
+
+If REMOVE (interactively, the prefix arg), remove the binding
+instead of unsetting it.  See `keymap-unset' for details.
+
+NOTE: The compatibility version is not a command."
+  (when (current-local-map)
+    (keymap-unset (current-local-map) key remove)))
+
+(compat-defun keymap-substitute (keymap olddef newdef &optional oldmap prefix) ;; <compat-tests:keymap-substitute>
+  "Replace OLDDEF with NEWDEF for any keys in KEYMAP now defined as OLDDEF.
+In other words, OLDDEF is replaced with NEWDEF wherever it appears.
+Alternatively, if optional fourth argument OLDMAP is specified, we redefine
+in KEYMAP as NEWDEF those keys that are defined as OLDDEF in OLDMAP.
+
+If you don't specify OLDMAP, you can usually get the same results
+in a cleaner way with command remapping, like this:
+  (define-key KEYMAP [remap OLDDEF] NEWDEF)
+\n(fn OLDDEF NEWDEF KEYMAP &optional OLDMAP)"
+  ;; Don't document PREFIX in the doc string because we don't want to
+  ;; advertise it.  It's meant for recursive calls only.  Here's its
+  ;; meaning
+
+  ;; If optional argument PREFIX is specified, it should be a key
+  ;; prefix, a string.  Redefined bindings will then be bound to the
+  ;; original key, with PREFIX added at the front.
+  (unless prefix
+    (setq prefix ""))
+  (let* ((scan (or oldmap keymap))
+         (prefix1 (vconcat prefix [nil]))
+         (key-substitution-in-progress
+          (cons scan key-substitution-in-progress)))
+    ;; Scan OLDMAP, finding each char or event-symbol that
+    ;; has any definition, and act on it with hack-key.
+    (map-keymap
+     (lambda (char defn)
+       (aset prefix1 (length prefix) char)
+       (substitute-key-definition-key defn olddef newdef prefix1 keymap))
+     scan)))
+
+(compat-defun keymap-set-after (keymap key definition &optional after) ;; <compat-tests:keymap-set-after>
+  "Add binding in KEYMAP for KEY => DEFINITION, right after AFTER's binding.
+This is like `keymap-set' except that the binding for KEY is placed
+just after the binding for the event AFTER, instead of at the beginning
+of the map.  Note that AFTER must be an event type (like KEY), NOT a command
+\(like DEFINITION).
+
+If AFTER is t or omitted, the new binding goes at the end of the keymap.
+AFTER should be a single event type--a symbol or a character, not a sequence.
+
+Bindings are always added before any inherited map.
+
+The order of bindings in a keymap matters only when it is used as
+a menu, so this function is not useful for non-menu keymaps."
+  (keymap--check key)
+  (when (eq after t) (setq after nil)) ; nil and t are treated the same
+  (when (stringp after)
+    (keymap--check after)
+    (setq after (key-parse after)))
+  ;; If we're binding this key to another key, then parse that other
+  ;; key, too.
+  (when (stringp definition)
+    (keymap--check definition)
+    (setq definition (key-parse definition)))
+  (define-key-after keymap (key-parse key) definition
+    after))
+
+(compat-defun keymap-lookup ;; <compat-tests:keymap-lookup>
+    (keymap key &optional accept-default no-remap position)
+  "Return the binding for command KEY.
+KEY is a string that satisfies `key-valid-p'.
+
+If KEYMAP is nil, look up in the current keymaps.  If non-nil, it
+should either be a keymap or a list of keymaps, and only these
+keymap(s) will be consulted.
+
+The binding is probably a symbol with a function definition.
+
+Normally, `keymap-lookup' ignores bindings for t, which act as
+default bindings, used when nothing else in the keymap applies;
+this makes it usable as a general function for probing keymaps.
+However, if the optional second argument ACCEPT-DEFAULT is
+non-nil, `keymap-lookup' does recognize the default bindings,
+just as `read-key-sequence' does.
+
+Like the normal command loop, `keymap-lookup' will remap the
+command resulting from looking up KEY by looking up the command
+in the current keymaps.  However, if the optional third argument
+NO-REMAP is non-nil, `keymap-lookup' returns the unmapped
+command.
+
+If KEY is a key sequence initiated with the mouse, the used keymaps
+will depend on the clicked mouse position with regard to the buffer
+and possible local keymaps on strings.
+
+If the optional argument POSITION is non-nil, it specifies a mouse
+position as returned by `event-start' and `event-end', and the lookup
+occurs in the keymaps associated with it instead of KEY.  It can also
+be a number or marker, in which case the keymap properties at the
+specified buffer position instead of point are used."
+  (keymap--check key)
+  (when (and keymap position)
+    (error "Can't pass in both keymap and position"))
+  (if keymap
+      (let ((value (lookup-key keymap (key-parse key) accept-default)))
+        (if (and (not no-remap)
+                   (symbolp value))
+            (or (command-remapping value) value)
+          value))
+    (key-binding (key-parse key) accept-default no-remap position)))
+
+(compat-defun keymap-local-lookup (keys &optional accept-default) ;; <compat-tests:keymap-local-lookup>
+  "Return the binding for command KEYS in current local keymap only.
+KEY is a string that satisfies `key-valid-p'.
+
+The binding is probably a symbol with a function definition.
+
+If optional argument ACCEPT-DEFAULT is non-nil, recognize default
+bindings; see the description of `keymap-lookup' for more details
+about this."
+  (when-let ((map (current-local-map)))
+    (keymap-lookup map keys accept-default)))
+
+(compat-defun keymap-global-lookup (keys &optional accept-default _message) ;; <compat-tests:keymap-global-lookup>
+  "Return the binding for command KEYS in current global keymap only.
+KEY is a string that satisfies `key-valid-p'.
+
+The binding is probably a symbol with a function definition.
+This function's return values are the same as those of `keymap-lookup'
+\(which see).
+
+If optional argument ACCEPT-DEFAULT is non-nil, recognize default
+bindings; see the description of `keymap-lookup' for more details
+about this.
+
+NOTE: The compatibility version is not a command."
+  (keymap-lookup (current-global-map) keys accept-default))
+
+(compat-defun define-keymap (&rest definitions) ;; <compat-tests:defvar-keymap>
+  "Create a new keymap and define KEY/DEFINITION pairs as key bindings.
+The new keymap is returned.
+
+Options can be given as keywords before the KEY/DEFINITION
+pairs.  Available keywords are:
+
+:full      If non-nil, create a chartable alist (see `make-keymap').
+             If nil (i.e., the default), create a sparse keymap (see
+             `make-sparse-keymap').
+
+:suppress  If non-nil, the keymap will be suppressed (see `suppress-keymap').
+             If `nodigits', treat digits like other chars.
+
+:parent    If non-nil, this should be a keymap to use as the parent
+             (see `set-keymap-parent').
+
+:keymap    If non-nil, instead of creating a new keymap, the given keymap
+             will be destructively modified instead.
+
+:name      If non-nil, this should be a string to use as the menu for
+             the keymap in case you use it as a menu with `x-popup-menu'.
+
+:prefix    If non-nil, this should be a symbol to be used as a prefix
+             command (see `define-prefix-command').  If this is the case,
+             this symbol is returned instead of the map itself.
+
+KEY/DEFINITION pairs are as KEY and DEF in `keymap-set'.  KEY can
+also be the special symbol `:menu', in which case DEFINITION
+should be a MENU form as accepted by `easy-menu-define'.
+
+\(fn &key FULL PARENT SUPPRESS NAME PREFIX KEYMAP &rest [KEY DEFINITION]...)"
+  (declare (indent defun))
+  (let (full suppress parent name prefix keymap)
+    ;; Handle keywords.
+    (while (and definitions
+                (keywordp (car definitions))
+                (not (eq (car definitions) :menu)))
+      (let ((keyword (pop definitions)))
+        (unless definitions
+          (error "Missing keyword value for %s" keyword))
+        (let ((value (pop definitions)))
+          (pcase keyword
+            (:full (setq full value))
+            (:keymap (setq keymap value))
+            (:parent (setq parent value))
+            (:suppress (setq suppress value))
+            (:name (setq name value))
+            (:prefix (setq prefix value))
+            (_ (error "Invalid keyword: %s" keyword))))))
+
+    (when (and prefix
+               (or full parent suppress keymap))
+      (error "A prefix keymap can't be defined with :full/:parent/:suppress/:keymap keywords"))
+
+    (when (and keymap full)
+      (error "Invalid combination: :keymap with :full"))
+
+    (let ((keymap (cond
+                   (keymap keymap)
+                   (prefix (define-prefix-command prefix nil name))
+                   (full (make-keymap name))
+                   (t (make-sparse-keymap name))))
+          seen-keys)
+      (when suppress
+        (suppress-keymap keymap (eq suppress 'nodigits)))
+      (when parent
+        (set-keymap-parent keymap parent))
+
+      ;; Do the bindings.
+      (while definitions
+        (let ((key (pop definitions)))
+          (unless definitions
+            (error "Uneven number of key/definition pairs"))
+          (let ((def (pop definitions)))
+            (if (eq key :menu)
+                (easy-menu-define nil keymap "" def)
+              (if (member key seen-keys)
+                  (error "Duplicate definition for key: %S %s" key keymap)
+                (push key seen-keys))
+              (keymap-set keymap key def)))))
+      keymap)))
+
+(compat-defmacro defvar-keymap (variable-name &rest defs) ;; <compat-tests:defvar-keymap>
+  "Define VARIABLE-NAME as a variable with a keymap definition.
+See `define-keymap' for an explanation of the keywords and KEY/DEFINITION.
+
+In addition to the keywords accepted by `define-keymap', this
+macro also accepts a `:doc' keyword, which (if present) is used
+as the variable documentation string.
+
+The `:repeat' keyword can also be specified; it controls the
+`repeat-mode' behavior of the bindings in the keymap.  When it is
+non-nil, all commands in the map will have the `repeat-map'
+symbol property.
+
+More control is available over which commands are repeatable; the
+value can also be a property list with properties `:enter' and
+`:exit', for example:
+
+     :repeat (:enter (commands ...) :exit (commands ...))
+
+`:enter' specifies the list of additional commands that only
+enter `repeat-mode'.  When the list is empty, then only the
+commands defined in the map enter `repeat-mode'.  Specifying a
+list of commands is useful when there are commands that have the
+`repeat-map' symbol property, but don't exist in this specific
+map.
+
+`:exit' is a list of commands that exit `repeat-mode'.  When the
+list is empty, no commands in the map exit `repeat-mode'.
+Specifying a list of commands is useful when those commands exist
+in this specific map, but should not have the `repeat-map' symbol
+property.
+
+\(fn VARIABLE-NAME &key DOC FULL PARENT SUPPRESS NAME PREFIX KEYMAP REPEAT &rest [KEY DEFINITION]...)"
+  (declare (indent 1))
+  (let ((opts nil)
+        doc repeat props)
+    (while (and defs
+                (keywordp (car defs))
+                (not (eq (car defs) :menu)))
+      (let ((keyword (pop defs)))
+        (unless defs
+          (error "Uneven number of keywords"))
+        (cond
+         ((eq keyword :doc) (setq doc (pop defs)))
+         ((eq keyword :repeat) (setq repeat (pop defs)))
+         (t (push keyword opts)
+            (push (pop defs) opts)))))
+    (unless (zerop (% (length defs) 2))
+      (error "Uneven number of key/definition pairs: %s" defs))
+
+    (let ((defs defs)
+          key seen-keys)
+      (while defs
+        (setq key (pop defs))
+        (pop defs)
+        (unless (eq key :menu)
+          (if (member key seen-keys)
+              (error "Duplicate definition for key '%s' in keymap '%s'"
+                     key variable-name)
+            (push key seen-keys)))))
+
+    (when repeat
+      (let ((defs defs)
+            def)
+        (dolist (def (plist-get repeat :enter))
+          (push `(put ',def 'repeat-map ',variable-name) props))
+        (while defs
+          (pop defs)
+          (setq def (pop defs))
+          (when (and (memq (car def) '(function quote))
+                     (not (memq (cadr def) (plist-get repeat :exit))))
+            (push `(put ,def 'repeat-map ',variable-name) props)))))
+
+    (let ((defvar-form
+           `(defvar ,variable-name
+              (define-keymap ,@(nreverse opts) ,@defs)
+              ,@(and doc (list doc)))))
+      (if props
+          `(progn
+             ,defvar-form
+             ,@(nreverse props))
+        defvar-form))))
+
+;;;; Defined in keymap.c
+
+(compat-defun define-key (keymap key def &optional remove) ;; <compat-tests:define-key>
+  "Handle optional argument REMOVE."
+  :extended t
+  (if (not remove)
+      (define-key keymap key def)
+    ;; Canonicalize key
+    (setq key (key-parse (key-description key)))
+    (define-key keymap key nil)
+    ;; Split M-key in ESC key
+    (setq key (mapcan (lambda (k)
+                        (if (and (integerp k) (/= (logand k ?\M-\0) 0))
+                            (list ?\e (logxor k ?\M-\0))
+                          (list k)))
+                      key))
+    ;; Delete single keys directly
+    (if (length= key 1)
+        (delete key keymap)
+      ;; Lookup submap and delete key from there
+      (let ((submap (lookup-key keymap (vconcat (butlast key)))))
+        (unless (keymapp submap)
+          (error "Not a keymap for %s" key))
+        (when (symbolp submap)
+          (setq submap (symbol-function submap)))
+        (delete (last key) submap)))
+    def))
+
+;;;; Defined in help.el
+
+(compat-defun substitute-quotes (string) ;; <compat-tests:substitute-quotes>
+  "Substitute quote characters for display.
+Each grave accent \\=` is replaced by left quote, and each
+apostrophe \\=' is replaced by right quote.  Left and right quote
+characters are specified by `text-quoting-style'."
+  (cond ((eq (text-quoting-style) 'curve)
+         (string-replace "`" "‘"
+                         (string-replace "'" "’" string)))
+        ((eq (text-quoting-style) 'straight)
+         (string-replace "`" "'" string))
+        (t string)))
+
+;;;; Defined in button.el
+
+(compat-defun button--properties (callback data help-echo) ;; <compat-tests:buttonize>
+  "Helper function."
+  (list 'font-lock-face 'button
+        'mouse-face 'highlight
+        'help-echo help-echo
+        'button t
+        'follow-link t
+        'category t
+        'button-data data
+        'keymap button-map
+        'action callback))
+
+(compat-defun buttonize (string callback &optional data help-echo) ;; <compat-tests:buttonize>
+  "Make STRING into a button and return it.
+When clicked, CALLBACK will be called with the DATA as the
+function argument.  If DATA isn't present (or is nil), the button
+itself will be used instead as the function argument.
+
+If HELP-ECHO, use that as the `help-echo' property.
+
+Also see `buttonize-region'."
+  (let ((string
+         (apply #'propertize string
+                (button--properties callback data help-echo))))
+    ;; Add the face to the end so that it can be overridden.
+    (add-face-text-property 0 (length string) 'button t string)
+    string))
+
+(compat-defun buttonize-region (start end callback &optional data help-echo) ;; <compat-tests:buttonize-region>
+  "Make the region between START and END into a button.
+When clicked, CALLBACK will be called with the DATA as the
+function argument.  If DATA isn't present (or is nil), the button
+itself will be used instead as the function argument.
+
+If HELP-ECHO, use that as the `help-echo' property.
+
+Also see `buttonize'."
+  (add-text-properties start end (button--properties callback data help-echo))
+  (add-face-text-property start end 'button t))
+
+;;;; Defined in rmc.el
+
+(compat-defun read-multiple-choice  ;; <compat-tests:read-multiple-choice>
+    (prompt choices &optional _help-str _show-help long-form)
+    "Handle LONG-FORM argument."
+  :extended t
+  (if (not long-form)
+      (read-multiple-choice prompt choices)
+    (let ((answer
+           (completing-read
+            (concat prompt " ("
+                    (mapconcat #'identity (mapcar #'cadr choices) "/")
+                    ") ")
+            (mapcar #'cadr choices) nil t)))
+      (catch 'found
+        (dolist (c choices)
+          (when (equal answer (cadr c))
+            (throw 'found c)))))))
+
+;;;; Defined in paragraphs.el
+
+(compat-defun count-sentences (start end) ;; <compat-tests:count-sentences>
+  "Count sentences in current buffer from START to END."
+  (let ((sentences 0)
+        (inhibit-field-text-motion t))
+    (save-excursion
+      (save-restriction
+        (narrow-to-region start end)
+        (goto-char (point-min))
+        (while (ignore-errors (forward-sentence))
+          (setq sentences (1+ sentences)))
+        (when (/= (skip-chars-backward " \t\n") 0)
+          (setq sentences (1- sentences)))
+        sentences))))
+
+;;;; Defined in cl-lib.el
+
+(compat-defun cl-constantly (value) ;; <compat-tests:cl-constantly>
+  "Return a function that takes any number of arguments, but returns VALUE."
+  :feature cl-lib
+  (lambda (&rest _) value))
+
+;;;; Defined in cl-macs.el
+
+(compat-defmacro cl-with-gensyms (names &rest body) ;; <compat-tests:cl-with-gensyms>
+  "Bind each of NAMES to an uninterned symbol and evaluate BODY."
+  ;; No :feature since macro is autoloaded
+  (declare (debug (sexp body)) (indent 1))
+  `(let ,(cl-loop for name in names collect
+                  `(,name (gensym (symbol-name ',name))))
+     ,@body))
+
+(compat-defmacro cl-once-only (names &rest body) ;; <compat-tests:cl-once-only>
+  "Generate code to evaluate each of NAMES just once in BODY.
+
+This macro helps with writing other macros.  Each of names is
+either (NAME FORM) or NAME, which latter means (NAME NAME).
+During macroexpansion, each NAME is bound to an uninterned
+symbol.  The expansion evaluates each FORM and binds it to the
+corresponding uninterned symbol.
+
+For example, consider this macro:
+
+    (defmacro my-cons (x)
+      (cl-once-only (x)
+        \\=`(cons ,x ,x)))
+
+The call (my-cons (pop y)) will expand to something like this:
+
+    (let ((g1 (pop y)))
+      (cons g1 g1))
+
+The use of `cl-once-only' ensures that the pop is performed only
+once, as intended.
+
+See also `macroexp-let2'."
+  ;; No :feature since macro is autoloaded
+  (declare (debug (sexp body)) (indent 1))
+  (setq names (mapcar #'ensure-list names))
+  (let ((our-gensyms (cl-loop for _ in names collect (gensym))))
+    `(let ,(cl-loop for sym in our-gensyms collect `(,sym (gensym)))
+       `(let ,(list
+               ,@(cl-loop for name in names for gensym in our-gensyms
+                          for to-eval = (or (cadr name) (car name))
+                          collect ``(,,gensym ,,to-eval)))
+          ,(let ,(cl-loop for name in names for gensym in our-gensyms
+                          collect `(,(car name) ,gensym))
+             ,@body)))))
+
+;;;; Defined in ert-x.el
+
+(compat-defmacro ert-with-temp-file (name &rest body) ;; <compat-tests:ert-with-temp-file>
+  "Bind NAME to the name of a new temporary file and evaluate BODY.
+Delete the temporary file after BODY exits normally or
+non-locally.  NAME will be bound to the file name of the temporary
+file.
+
+The following keyword arguments are supported:
+
+:prefix STRING  If non-nil, pass STRING to `make-temp-file' as
+                the PREFIX argument.  Otherwise, use the value of
+                `ert-temp-file-prefix'.
+
+:suffix STRING  If non-nil, pass STRING to `make-temp-file' as the
+                SUFFIX argument.  Otherwise, use the value of
+                `ert-temp-file-suffix'; if the value of that
+                variable is nil, generate a suffix based on the
+                name of the file that `ert-with-temp-file' is
+                called from.
+
+:text STRING    If non-nil, pass STRING to `make-temp-file' as
+                the TEXT argument.
+
+:buffer SYMBOL  Open the temporary file using `find-file-noselect'
+                and bind SYMBOL to the buffer.  Kill the buffer
+                after BODY exits normally or non-locally.
+
+:coding CODING  If non-nil, bind `coding-system-for-write' to CODING
+                when executing BODY.  This is handy when STRING includes
+                non-ASCII characters or the temporary file must have a
+                specific encoding or end-of-line format.
+
+See also `ert-with-temp-directory'."
+  :feature ert-x
+  (declare (indent 1) (debug (symbolp body)))
+  (cl-check-type name symbol)
+  (let (keyw prefix suffix directory text extra-keywords buffer coding)
+    (while (keywordp (setq keyw (car body)))
+      (setq body (cdr body))
+      (pcase keyw
+        (:prefix (setq prefix (pop body)))
+        (:suffix (setq suffix (pop body)))
+        ;; This is only for internal use by `ert-with-temp-directory'
+        ;; and is therefore not documented.
+        (:directory (setq directory (pop body)))
+        (:text (setq text (pop body)))
+        (:buffer (setq buffer (pop body)))
+        (:coding (setq coding (pop body)))
+        (_ (push keyw extra-keywords) (pop body))))
+    (when extra-keywords
+      (error "Invalid keywords: %s" (mapconcat #'symbol-name extra-keywords " ")))
+    (let ((temp-file (make-symbol "temp-file"))
+          (prefix (or prefix "emacs-test-"))
+          (suffix (or suffix
+                      (thread-last
+                        (file-name-base (or (macroexp-file-name) buffer-file-name))
+                        (replace-regexp-in-string (rx string-start
+                                                      (group (+? not-newline))
+                                                      (regexp "-?tests?")
+                                                      string-end)
+                                                  "\\1")
+                        (concat "-")))))
+      `(let* ((coding-system-for-write ,(or coding coding-system-for-write))
+              (,temp-file (,(if directory 'file-name-as-directory 'identity)
+                           (,(if (fboundp 'compat--make-temp-file)
+                                 'compat--make-temp-file 'make-temp-file)
+                            ,prefix ,directory ,suffix ,text)))
+              (,name ,(if directory
+                          `(file-name-as-directory ,temp-file)
+                        temp-file))
+              ,@(when buffer
+                  (list `(,buffer (find-file-literally ,temp-file)))))
+         (unwind-protect
+             (progn ,@body)
+           (ignore-errors
+             ,@(when buffer
+                 (list `(with-current-buffer ,buffer
+                          (set-buffer-modified-p nil))
+                       `(kill-buffer ,buffer))))
+           (ignore-errors
+             ,(if directory
+                  `(delete-directory ,temp-file :recursive)
+                `(delete-file ,temp-file))))))))
+
+(compat-defmacro ert-with-temp-directory (name &rest body) ;; <compat-tests:ert-with-temp-directory>
+  "Bind NAME to the name of a new temporary directory and evaluate BODY.
+Delete the temporary directory after BODY exits normally or
+non-locally.
+
+NAME is bound to the directory name, not the directory file
+name.  (In other words, it will end with the directory delimiter;
+on Unix-like systems, it will end with \"/\".)
+
+The same keyword arguments are supported as in
+`ert-with-temp-file' (which see), except for :text."
+  :feature ert-x
+  (declare (indent 1) (debug (symbolp body)))
+  (let ((tail body) keyw)
+    (while (keywordp (setq keyw (car tail)))
+      (setq tail (cddr tail))
+      (pcase keyw (:text (error "Invalid keyword for directory: :text")))))
+  `(ert-with-temp-file ,name
+     :directory t
+     ,@body))
+
+;;;; Defined in wid-edit.el
+
+(compat-guard (not (fboundp 'widget-key-validate)) ;; <compat-tests:widget-key>
+  :feature wid-edit
+  (defvar widget-key-prompt-value-history nil
+    "History of input to `widget-key-prompt-value'.")
+  (define-widget 'key 'editable-field
+    "A key sequence."
+    :prompt-value 'widget-field-prompt-value
+    :match 'widget-key-valid-p
+    :format "%{%t%}: %v"
+    :validate 'widget-key-validate
+    :keymap widget-key-sequence-map
+    :help-echo "C-q: insert KEY, EVENT, or CODE; RET: enter value"
+    :tag "Key")
+  (defun widget-key-valid-p (_widget value)
+    (key-valid-p value))
+  (defun widget-key-validate (widget)
+    (unless (and (stringp (widget-value widget))
+                 (key-valid-p (widget-value widget)))
+      (widget-put widget :error (format "Invalid key: %S"
+                                        (widget-value widget)))
+      widget)))
+
+(provide 'compat-29)
+;;; compat-29.el ends here
diff --git a/elpa/compat-29.1.4.5/compat-autoloads.el b/elpa/compat-29.1.4.5/compat-autoloads.el
new file mode 100644 (file)
index 0000000..676fd32
--- /dev/null
@@ -0,0 +1,33 @@
+;;; compat-autoloads.el --- automatically extracted autoloads (do not edit)   -*- lexical-binding: t -*-
+;; Generated by the `loaddefs-generate' function.
+
+;; This file is part of GNU Emacs.
+
+;;; Code:
+
+(add-to-list 'load-path (or (and load-file-name (directory-file-name (file-name-directory load-file-name))) (car load-path)))
+
+
+\f
+;;; Generated autoloads from compat.el
+
+(register-definition-prefixes "compat" '("compat-"))
+
+\f
+;;; Generated autoloads from compat-macs.el
+
+(register-definition-prefixes "compat-macs" '("compat-"))
+\f
+;;; End of scraped data
+
+(provide 'compat-autoloads)
+
+;; Local Variables:
+;; version-control: never
+;; no-byte-compile: t
+;; no-update-autoloads: t
+;; no-native-compile: t
+;; coding: utf-8-emacs-unix
+;; End:
+
+;;; compat-autoloads.el ends here
diff --git a/elpa/compat-29.1.4.5/compat-macs.el b/elpa/compat-29.1.4.5/compat-macs.el
new file mode 100644 (file)
index 0000000..ffd5223
--- /dev/null
@@ -0,0 +1,267 @@
+;;; compat-macs.el --- Compatibility Macros -*- lexical-binding: t; no-byte-compile: t; -*-
+
+;; Copyright (C) 2021-2024 Free Software Foundation, Inc.
+
+;; This program is free software; you can redistribute it and/or modify
+;; it under the terms of the GNU General Public License as published by
+;; the Free Software Foundation, either version 3 of the License, or
+;; (at your option) any later version.
+
+;; This program is distributed in the hope that it will be useful,
+;; but WITHOUT ANY WARRANTY; without even the implied warranty of
+;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+;; GNU General Public License for more details.
+
+;; You should have received a copy of the GNU General Public License
+;; along with this program.  If not, see <https://www.gnu.org/licenses/>.
+
+;;; Commentary:
+
+;; WARNING: This file provides *internal* macros.  The macros are used
+;; by Compat to facilitate the definition of compatibility functions,
+;; compatibility macros and compatibility variables.  The
+;; `compat-macs' feature should never be loaded at runtime in your
+;; Emacs and will only be used during byte compilation.  Every
+;; definition provided here is internal, may change any time between
+;; Compat releases and must not be used by other packages.
+
+;;; Code:
+
+;; We always require subr-x at compile time for the fboundp check
+;; since definitions have been moved around. The cl-lib macros are
+;; needed by compatibility definitions.
+(require 'subr-x)
+(require 'cl-lib)
+
+(defvar compat-macs--version nil
+  "Version of the currently defined compatibility definitions.")
+
+(defun compat-macs--strict (cond &rest error)
+  "Assert strict COND, otherwise fail with ERROR."
+  (when (bound-and-true-p compat-strict)
+    (apply #'compat-macs--assert cond error)))
+
+(defun compat-macs--assert (cond &rest error)
+  "Assert COND, otherwise fail with ERROR."
+  (unless cond (apply #'error error)))
+
+(defun compat-macs--docstring (type name docstring)
+  "Format DOCSTRING for NAME of TYPE.
+Prepend compatibility notice to the actual documentation string."
+  (with-temp-buffer
+    (insert
+     (format
+      "[Compatibility %s for `%s', defined in Emacs %s. \
+See (compat) Emacs %s' for more details.]\n\n%s"
+      type name compat-macs--version compat-macs--version docstring))
+    (let ((fill-column 80))
+      (fill-region (point-min) (point-max)))
+    (buffer-string)))
+
+(defun compat-macs--check-attributes (attrs preds)
+  "Check ATTRS given PREDS predicate plist and return rest."
+  (while (keywordp (car attrs))
+    (compat-macs--assert (cdr attrs) "Attribute list length is odd")
+    (compat-macs--assert (let ((p (plist-get preds (car attrs))))
+                           (and p (or (eq p t) (funcall p (cadr attrs)))))
+                         "Invalid attribute %s" (car attrs))
+    (setq attrs (cddr attrs)))
+  attrs)
+
+(defun compat-macs--guard (attrs preds fun)
+  "Guard compatibility definition generation.
+The version constraints specified by ATTRS are checked.  PREDS is
+a plist of predicates for arguments which are passed to FUN."
+  (declare (indent 2))
+  (compat-macs--assert compat-macs--version "No `compat-version' was declared")
+  (let* ((body (compat-macs--check-attributes
+                attrs `(,@preds :feature symbolp)))
+         (feature (plist-get attrs :feature))
+         (attrs `(:body ,body ,@attrs))
+         args)
+    ;; Require feature at compile time
+    (when feature
+      (compat-macs--assert (not (eq feature 'subr-x)) "Invalid feature subr-x")
+      (require feature))
+    ;; The current Emacs must be older than the currently declared version.
+    (when (version< emacs-version compat-macs--version)
+      (while preds
+        (push (plist-get attrs (car preds)) args)
+        (setq preds (cddr preds)))
+      (setq body (apply fun (nreverse args)))
+      (if (and feature body)
+          `(with-eval-after-load ',feature ,@body)
+        (macroexp-progn body)))))
+
+(defun compat-macs--defun (type name arglist docstring rest)
+  "Define function NAME of TYPE with ARGLIST and DOCSTRING.
+REST are attributes and the function BODY."
+  (compat-macs--guard
+     rest (list :extended (lambda (x) (or (booleanp x) (version-to-list x)))
+                :obsolete (lambda (x) (or (booleanp x) (stringp x)))
+                :body t)
+    (lambda (extended obsolete body)
+      (when (stringp extended)
+        (compat-macs--assert
+         (and (version< extended compat-macs--version) (version< "24.4" extended))
+         "Invalid :extended version %s for %s %s" extended type name)
+        (setq extended (version<= extended emacs-version)))
+      (compat-macs--strict (eq extended (fboundp name))
+                           "Wrong :extended flag for %s %s" type name)
+      ;; Remove unsupported declares.  It might be possible to set these
+      ;; properties otherwise.  That should be looked into and implemented
+      ;; if it is the case.
+      (when (and (listp (car-safe body)) (eq (caar body) 'declare) (<= emacs-major-version 25))
+        (setcar body (assq-delete-all 'pure (assq-delete-all
+                                             'side-effect-free (car body)))))
+      ;; Use `:extended' name if the function is already defined.
+      (let* ((defname (if (and extended (fboundp name))
+                          (intern (format "compat--%s" name))
+                        name))
+             (def `(,(if (memq '&key arglist)
+                         (if (eq type 'macro) 'cl-defmacro 'cl-defun)
+                       (if (eq type 'macro) 'defmacro 'defun))
+                    ,defname ,arglist
+                    ,(compat-macs--docstring type name docstring)
+                    ,@body)))
+        `(,@(if (eq defname name)
+                ;; An additional fboundp check is performed at runtime to make
+                ;; sure that we never redefine an existing definition if Compat
+                ;; is loaded on a newer Emacs version.  Declare the function,
+                ;; such that the byte compiler does not complain about possibly
+                ;; missing functions at runtime. The warnings are generated due
+                ;; to the fboundp check.
+                `((declare-function ,name nil)
+                  (unless (fboundp ',name) ,def))
+              (list def))
+          ,@(when obsolete
+              `((make-obsolete
+                 ',defname ,(if (stringp obsolete) obsolete "No substitute")
+                 ,compat-macs--version))))))))
+
+(defmacro compat-guard (cond &rest rest)
+  "Guard definition with a runtime COND and a version check.
+The runtime condition must make sure that no definition is
+overridden.  REST is an attribute plist followed by the definition
+body.  The attributes specify the conditions under which the
+definition is generated.
+
+- :feature :: Wrap the definition with `with-eval-after-load' for
+  the given feature."
+  (declare (debug ([&rest keywordp sexp] def-body))
+           (indent 1))
+  (compat-macs--guard rest '(:body t)
+    (lambda (body)
+      (compat-macs--assert body "The guarded body is empty")
+      (if (eq cond t)
+          body
+        (compat-macs--strict (eval cond t) "Guard %S failed" cond)
+        `((when ,cond ,@body))))))
+
+(defmacro compat-defalias (name def &rest attrs)
+  "Define compatibility alias NAME as DEF.
+ATTRS is a plist of attributes, which specify the conditions
+under which the definition is generated.
+
+- :obsolete :: Mark the alias as obsolete if t.
+
+- :feature :: See `compat-guard'."
+  (declare (debug (name symbolp [&rest keywordp sexp])))
+  (compat-macs--guard attrs '(:obsolete booleanp)
+    (lambda (obsolete)
+      (compat-macs--strict (not (fboundp name)) "%s already defined" name)
+      ;; The fboundp check is performed at runtime to make sure that we never
+      ;; redefine an existing definition if Compat is loaded on a newer Emacs
+      ;; version.
+      `((unless (fboundp ',name)
+          (defalias ',name ',def
+            ,(compat-macs--docstring 'function name
+                                (get name 'function-documentation)))
+          ,@(when obsolete
+              `((make-obsolete ',name ',def ,compat-macs--version))))))))
+
+(defmacro compat-defun (name arglist docstring &rest rest)
+  "Define compatibility function NAME with arguments ARGLIST.
+The function must be documented in DOCSTRING.  REST is an
+attribute plist followed by the function body.  The attributes
+specify the conditions under which the definition is generated.
+
+- :extended :: Mark the function as extended if t.  The function
+  must be called explicitly via `compat-call'.  This attribute
+  should be used for functions which extend already existing
+  functions, e.g., functions which changed their calling
+  convention or their behavior.  The value can also be a version
+  string, which specifies the Emacs version when the original
+  version of the function was introduced.
+
+- :obsolete :: Mark the function as obsolete if t, can be a
+  string describing the obsoletion.
+
+- :feature :: See `compat-guard'."
+  (declare (debug (&define name (&rest symbolp)
+                           stringp
+                           [&rest keywordp sexp]
+                           def-body))
+           (doc-string 3) (indent 2))
+  (compat-macs--defun 'function name arglist docstring rest))
+
+(defmacro compat-defmacro (name arglist docstring &rest rest)
+  "Define compatibility macro NAME with arguments ARGLIST.
+The macro must be documented in DOCSTRING.  REST is an attribute
+plist followed by the macro body.  See `compat-defun' for
+details."
+  (declare (debug compat-defun) (doc-string 3) (indent 2))
+  (compat-macs--defun 'macro name arglist docstring rest))
+
+(defmacro compat-defvar (name initval docstring &rest attrs)
+  "Define compatibility variable NAME with initial value INITVAL.
+The variable must be documented in DOCSTRING.  ATTRS is a plist
+of attributes, which specify the conditions under which the
+definition is generated.
+
+- :constant :: Mark the variable as constant if t.
+
+- :local :: Make the variable buffer-local if t.  If the value is
+  `permanent' make the variable additionally permanently local.
+
+- :obsolete :: Mark the variable as obsolete if t, can be a
+  string describing the obsoletion.
+
+- :feature :: See `compat-guard'."
+  (declare (debug (name form stringp [&rest keywordp sexp]))
+           (doc-string 3) (indent 2))
+  (compat-macs--guard
+      attrs (list :constant #'booleanp
+                  :local (lambda (x) (memq x '(nil t permanent)))
+                  :obsolete (lambda (x) (or (booleanp x) (stringp x))))
+    (lambda (constant local obsolete)
+      (compat-macs--strict (not (boundp name)) "%s already defined" name)
+      (compat-macs--assert (not (and constant local)) "Both :constant and :local")
+      ;; The boundp check is performed at runtime to make sure that we never
+      ;; redefine an existing definition if Compat is loaded on a newer Emacs
+      ;; version.
+      `((defvar ,name)
+        (unless (boundp ',name)
+          (,(if constant 'defconst 'defvar)
+           ,name ,initval
+           ,(compat-macs--docstring 'variable name docstring))
+          ,@(when obsolete
+              `((make-obsolete-variable
+                 ',name ,(if (stringp obsolete) obsolete "No substitute")
+                 ,compat-macs--version))))
+        ,@(and local `((make-variable-buffer-local ',name)))
+        ,@(and (eq local 'permanent) `((put ',name 'permanent-local t)))))))
+
+(defmacro compat-version (version)
+  "Set the Emacs version that is currently being handled to VERSION."
+  (setq compat-macs--version version)
+  nil)
+
+(defmacro compat-require (feature version)
+  "Require FEATURE if the Emacs version is less than VERSION."
+  (when (version< emacs-version version)
+    (require feature)
+    `(require ',feature)))
+
+(provide 'compat-macs)
+;;; compat-macs.el ends here
diff --git a/elpa/compat-29.1.4.5/compat-pkg.el b/elpa/compat-29.1.4.5/compat-pkg.el
new file mode 100644 (file)
index 0000000..6b17264
--- /dev/null
@@ -0,0 +1,2 @@
+;; Generated package description from compat.el  -*- no-byte-compile: t -*-
+(define-package "compat" "29.1.4.5" "Emacs Lisp Compatibility Library" '((emacs "24.4") (seq "2.23")) :commit "8d4e8a366681def88751f5e9975738ecd3180deb" :authors '(("Philip Kaludercic" . "philipkNOSPAMposteo.net") ("Daniel Mendler" . "mailNOSPAMdaniel-mendler.de")) :maintainer '("Compat Development" . "~pkal/compat-develNOSPAMlists.sr.ht") :keywords '("lisp" "maint") :url "https://github.com/emacs-compat/compat")
diff --git a/elpa/compat-29.1.4.5/compat.el b/elpa/compat-29.1.4.5/compat.el
new file mode 100644 (file)
index 0000000..b2eb9fe
--- /dev/null
@@ -0,0 +1,93 @@
+;;; compat.el --- Emacs Lisp Compatibility Library -*- lexical-binding: t; -*-
+
+;; Copyright (C) 2021-2024 Free Software Foundation, Inc.
+
+;; Author: Philip Kaludercic <philipkNOSPAMposteo.net>, Daniel Mendler <mailNOSPAMdaniel-mendler.de>
+;; Maintainer: Compat Development <~pkal/compat-develNOSPAMlists.sr.ht>
+;; Version: 29.1.4.5
+;; URL: https://github.com/emacs-compat/compat
+;; Package-Requires: ((emacs "24.4") (seq "2.23"))
+;; Keywords: lisp, maint
+
+;; This program is free software; you can redistribute it and/or modify
+;; it under the terms of the GNU General Public License as published by
+;; the Free Software Foundation, either version 3 of the License, or
+;; (at your option) any later version.
+
+;; This program is distributed in the hope that it will be useful,
+;; but WITHOUT ANY WARRANTY; without even the implied warranty of
+;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+;; GNU General Public License for more details.
+
+;; You should have received a copy of the GNU General Public License
+;; along with this program.  If not, see <https://www.gnu.org/licenses/>.
+
+;;; Commentary:
+
+;; Compat is the Elisp forwards compatibility library, which provides
+;; definitions introduced in newer Emacs versions.  The definitions
+;; are only installed if necessary for your current Emacs version.  If
+;; Compat is compiled on a recent version of Emacs, all of the
+;; definitions are disabled at compile time, such that no negative
+;; performance impact is incurred.  The provided compatibility
+;; implementations of functions and macros are at least subsets of the
+;; actual implementations.  Be sure to read the documentation string
+;; and the Compat manual.
+;;
+;; Not every function provided in newer versions of Emacs is provided
+;; here.  Some depend on new features from the C core, others cannot
+;; be implemented to a meaningful degree.  Please consult the Compat
+;; manual for details regarding the usage of the Compat library and
+;; the provided functionality.
+
+;; The main audience for this library are not regular users, but
+;; package maintainers.  Therefore no commands, user-facing modes or
+;; user options are implemented here.
+
+;;; Code:
+
+;; Ensure that the newest compatibility layer is required at compile
+;; time and runtime, but only if needed.
+(eval-when-compile
+  (defmacro compat--maybe-require ()
+    (when (version< emacs-version "29.1")
+      (require 'compat-29)
+      '(require 'compat-29))))
+(compat--maybe-require)
+
+;;;; Macros for extended compatibility function calls
+
+(defmacro compat-function (fun)
+  "Return compatibility function symbol for FUN.
+
+If the Emacs version provides a sufficiently recent version of
+FUN, the symbol FUN is returned itself.  Otherwise the macro
+returns the symbol of a compatibility function which supports the
+behavior and calling convention of the current stable Emacs
+version.  For example Compat 29.1 will provide compatibility
+functions which implement the behavior and calling convention of
+Emacs 29.1.
+
+See also `compat-call' to directly call compatibility functions."
+  (let ((compat (intern (format "compat--%s" fun))))
+    `#',(if (fboundp compat) compat fun)))
+
+(defmacro compat-call (fun &rest args)
+  "Call compatibility function or macro FUN with ARGS.
+
+A good example function is `plist-get' which was extended with an
+additional predicate argument in Emacs 29.1.  The compatibility
+function, which supports this additional argument, can be
+obtained via (compat-function plist-get) and called
+via (compat-call plist-get plist prop predicate).  It is not
+possible to directly call (plist-get plist prop predicate) on
+Emacs older than 29.1, since the original `plist-get' function
+does not yet support the predicate argument.  Note that the
+Compat library never overrides existing functions.
+
+See also `compat-function' to lookup compatibility functions."
+  (let ((compat (intern (format "compat--%s" fun))))
+    `(,(if (fboundp compat) compat fun) ,@args)))
+
+(provide 'compat)
+;;; compat.el ends here
diff --git a/elpa/compat-29.1.4.5/compat.info b/elpa/compat-29.1.4.5/compat.info
new file mode 100644 (file)
index 0000000..04d96ed
--- /dev/null
@@ -0,0 +1,2997 @@
+This is docXccUUB.info, produced by makeinfo version 6.8 from
+compat.texi.
+
+Copyright © 2022-2024 Free Software Foundation, Inc.
+
+     Permission is granted to copy, distribute and/or modify this
+     document under the terms of the GNU Free Documentation License,
+     Version 1.3 or any later version published by the Free Software
+     Foundation; with no Invariant Sections, with the Front-Cover Texts
+     being “A GNU Manual,” and with the Back-Cover Texts as in (a)
+     below.  A copy of the license is included in the section entitled
+     “GNU Free Documentation License.”
+
+     (a) The FSF’s Back-Cover Text is: “You have the freedom to copy and
+     modify this GNU manual.”
+
+INFO-DIR-SECTION Emacs
+START-INFO-DIR-ENTRY
+* Compat: (compat).     Compatibility Library for Emacs Lisp.
+END-INFO-DIR-ENTRY
+
+\1f
+File: docXccUUB.info,  Node: Top,  Next: Introduction,  Up: (dir)
+
+"Compat" Manual
+***************
+
+This manual documents the usage of the "Compat" Emacs lisp library, the
+forward-compatibility library for Emacs Lisp, corresponding to version
+29.1.4.5.
+
+   Copyright © 2022-2024 Free Software Foundation, Inc.
+
+     Permission is granted to copy, distribute and/or modify this
+     document under the terms of the GNU Free Documentation License,
+     Version 1.3 or any later version published by the Free Software
+     Foundation; with no Invariant Sections, with the Front-Cover Texts
+     being “A GNU Manual,” and with the Back-Cover Texts as in (a)
+     below.  A copy of the license is included in the section entitled
+     “GNU Free Documentation License.”
+
+     (a) The FSF’s Back-Cover Text is: “You have the freedom to copy and
+     modify this GNU manual.”
+
+* Menu:
+
+* Introduction::
+* Support::
+* Development::
+* Function Index::
+* Variable Index::
+
+— The Detailed Node Listing —
+
+Introduction
+
+* Overview::
+* Usage::
+* Limitations::
+
+Support
+
+* Emacs 25.1::                   Compatibility support for Emacs 25.1
+* Emacs 26.1::                   Compatibility support for Emacs 26.1
+* Emacs 27.1::                   Compatibility support for Emacs 27.1
+* Emacs 28.1::                   Compatibility support for Emacs 28.1
+* Emacs 29.1::                   Compatibility support for Emacs 29.1
+
+
+\1f
+File: docXccUUB.info,  Node: Introduction,  Next: Support,  Prev: Top,  Up: Top
+
+1 Introduction
+**************
+
+* Menu:
+
+* Overview::
+* Usage::
+* Limitations::
+
+\1f
+File: docXccUUB.info,  Node: Overview,  Next: Usage,  Up: Introduction
+
+1.1 Overview
+============
+
+The objective of Compat is to provide "forwards compatibility" library
+for Emacs Lisp.  By using Compat, an Elisp package does not have to make
+the decision to either use new and useful functionality or support old
+versions of Emacs.
+
+   The library provides support back until Emacs 24.4.  The intended
+audience are package developers that are interested in using newer
+developments, without having to break compatibility.
+
+\1f
+File: docXccUUB.info,  Node: Usage,  Next: Limitations,  Prev: Overview,  Up: Introduction
+
+1.2 Usage
+=========
+
+The intended use-case for this library is for package developers to add
+as a dependency in the header.  The version of the Compat library
+mirrors the version of Emacs releases.  The current version of Compat
+corresponds to the current Emacs release.
+
+     ;; Package-Requires: ((emacs "24.4") (compat "29.1.4.5"))
+
+   There is no need to depend on ‘emacs 24.4’ specifically.  One can
+choose any newer version, if features not provided by Compat necessitate
+it, for example bug fixes or UI improvements.
+
+   In any file where compatibility forms are used, a
+
+     (require 'compat)
+
+   should be added early on.  This will load all necessary Compat
+definitions.  Compat loads the ‘seq’ library which is preloaded by
+default on Emacs 29.  Note that if Compat is installed on a recent
+version of Emacs, all of the definitions are disabled at compile time,
+such that no negative performance impact is incurred.
+
+   A minimal version of Compat will be present in Emacs version 30 and
+newer.  Packages which are part of Emacs itself and want to take
+advantage of Compat, can also use ‘(require 'compat)’.  The advantage of
+the inclusion of a minimal Compat in Emacs is that Compat will not be
+installed if you require a version newer or equal than the current Emacs
+version.  For example, if a package depending on Emacs 25.1 and Compat
+29.1 is installed on Emacs 30.1, Compat will not be pulled in as
+dependency, since Emacs 30.1 already provides the required
+functionality.
+
+   Compat provides replacement functions with extended functionality for
+functions that are already defined, e.g., ‘sort’ or ‘assoc’.  These
+functions may have changed their calling convention (additional optional
+arguments) or may have changed their behavior.  These functions must be
+looked up explicitly with ‘compat-function’ or called explicitly with
+‘compat-call’.  We call them “Extended Definitions”.  In contrast, newly
+“Added Definitions” can be called as usual.  The Compat manual
+explicitly documents the calling convention of each compatibility
+function.
+
+     (compat-call assoc key alist testfn) ;; Call extended `assoc'
+     (mapcan fun seq)                     ;; Call newly added `mapcan'
+
+ -- Macro: compat-call fun &rest args
+     This macro calls the compatibility function FUN with ARGS.  Many
+     functions provided by Compat can be called directly without this
+     macro.  However in the case where Compat provides an alternative
+     version of an existing function, the function call has to go
+     through ‘compat-call’.  This happens for example when the calling
+     convention of a function has changed.
+
+ -- Macro: compat-function fun
+     This macro returns the compatibility function symbol for FUN.  See
+     ‘compat-call’ for a more convenient macro to directly call
+     compatibility functions.
+
+   If Compat is used in Emacs core packages, the macros ‘compat-call’
+and ‘compat-function’ will be available in Emacs version 30 and newer.
+
+   The macros ‘compat-call’ and ‘compat-function’ are introduced by
+Compat, since Compat does not advise or override existing functions.
+Generally Compat is written in defensive style which is supposed to
+reduce potential breakage, and to increase the chances of staying binary
+compatible across releases.  The extensive test coverage ensures that we
+can maintain high quality, which is crucial for Compat which is not
+restricted to a namespace like usual libraries.
+
+   If you intend to use a compatibility function in your code it is
+recommended that you take a look at the test suite ‘compat-tests.el’.
+There you can see the supported calling conventions, which are
+guaranteed to work on the supported Emacs versions.  We ensure this
+using continuous integration.  All functions provided by Compat are
+covered by the test suite.  There is a link to the corresponding test on
+the first line of each definition.
+
+   You may want to subscribe to the compat-announce
+(https://lists.sr.ht/~pkal/compat-announce) mailing list to be notified
+when new versions are released or relevant changes are made.  We also
+provide a development mailing list
+(https://lists.sr.ht/~pkal/compat-devel) (~pkal/compat-develNOSPAMlists.sr.ht
+<~pkal/compat-develNOSPAMlists.sr.ht>).
+
+\1f
+File: docXccUUB.info,  Node: Limitations,  Prev: Usage,  Up: Introduction
+
+1.3 Limitations
+===============
+
+The Compat library has a number of limitations.  Complete backwards
+compatibility cannot be provided due to the scope of Compat and for
+technical reasons.  The scope is intentionally restricted in order to
+limit the size of Compat and to ensure that the library stays
+maintainable.
+
+   Emacs version 24.4 is chosen as the oldest version supported by
+Compat, since Elisp has seen significant changes at that version.  Since
+24.4 Emacs major versions consistently bump the major version number.
+On the library level, subr-x was introduced in 24.4.  Most popular Emacs
+packages already require 24.4 or even newer versions of Emacs.
+Supporting for more historical Emacs versions would complicate
+maintenance while only few packages and users would benefit.
+
+   Below we list a number of reasons why certain functionality cannot be
+provided.  Note that in some special cases exceptions can be made and
+functions can still be added to Compat even if they satisfy the criteria
+from the list.  In case you miss functionality which you think should
+belong here, a *note report: Development. would be much appreciated.
+
+   • The additional functionality is a command or a user-facing minor or
+     major mode.  Compat is limited to functionality on the “library
+     level”.  Generally functions provided by Compat are
+     non-interactive, such that the user interface (M-x) is unaffected
+     by the presence of Compat.
+
+   • The function is not useful for package authors or not intended to
+     be used by packages, but is only useful on the configuration level.
+     The macro ‘setopt’ is such an example.
+
+   • Private (double dashed) functions are not ported back.  If Compat
+     includes some private functions, they are meant purely for internal
+     usage.
+
+   • The added or extended function belongs to the “application level”
+     and not the “library level”.  Features which are not preloaded
+     often belong to the “application level”.  Application examples are
+     programming modes or modes like Dired, IRC and Gnus.  If these
+     modes are extended with new functions, these are not ported back.
+
+   • An existing function or macro was extended by some new
+     functionality.  To support these cases, the function or macro would
+     have to be advised.  Since this is invasive and adds significant
+     overhead, even when the new feature is not used, Compat does not
+     use advices.  As a compromise, compatibility functions and macros
+     with a changed calling convention or behavior can be accessed via
+     the ‘compat-function’ and ‘compat-call’ macros.  In this manual we
+     call such definitions “Extended Definitions”.  An example is the
+     function ‘plist-get’.  Note that extended functions are subject to
+     closer scrutiny, since their usage via ‘compat-call’ is not
+     completely painless.  If a particular extended function does not
+     see much usage or the extension yields only marginal benefits, we
+     may not provide it as part of Compat.
+
+   • Bug fixes are usually not ported back as part of Compat.  Sometimes
+     library functions show wrong behavior for edge cases.  In those
+     cases Compat could in principle provide a compatibility function
+     which is invoked via ‘compat-call’.  Such extended definitions
+     would increase the maintenance burden of Compat.  At the same time
+     the benefits would be small given that Compat does not override
+     existing definitions.
+
+   • The definition belongs to an Emacs core package, which is also
+     distributed via ELPA. Compat does not have to provide backward
+     compatibility for core packages since the updated package can be
+     installed directly from ELPA. Examples include the libraries xref,
+     project, seq, map and transient.
+
+   • New functionality depends on an entire new, non-trivial core
+     library, which is infeasible to duplicate within Compat.  If a
+     backport of such a library is required, the preferred approach is
+     to either release the library separately on GNU ELPA as a core
+     package or as a separately maintained GNU ELPA package.  An example
+     is the iso8601 library.
+
+   • New functionality was implemented in the C core, or depends on
+     external libraries that cannot be reasonably duplicated in the
+     scope of a compatibility library.  Sometimes new functions on the C
+     level rely on internal data structures, which we cannot access,
+     rendering a backport impossible.  For example a missing libxml or
+     libtreesitter cannot be emulated.
+
+   • The semantics of Elisp changed on a deep level.  For example the
+     addition of big integer support in Emacs 27.1 cannot be replicated
+     on the level of Compat.
+
+\1f
+File: docXccUUB.info,  Node: Support,  Next: Development,  Prev: Introduction,  Up: Top
+
+2 Support
+*********
+
+This section goes into the features that Compat manages and doesn’t
+manage to provide for each Emacs version.
+
+* Menu:
+
+* Emacs 25.1::                   Compatibility support for Emacs 25.1
+* Emacs 26.1::                   Compatibility support for Emacs 26.1
+* Emacs 27.1::                   Compatibility support for Emacs 27.1
+* Emacs 28.1::                   Compatibility support for Emacs 28.1
+* Emacs 29.1::                   Compatibility support for Emacs 29.1
+
+\1f
+File: docXccUUB.info,  Node: Emacs 25.1,  Next: Emacs 26.1,  Up: Support
+
+2.1 Emacs 25.1
+==============
+
+2.1.1 Added Definitions
+-----------------------
+
+The following functions and macros are implemented in Emacs 25.1.  These
+functions are made available by Compat on Emacs versions older than
+25.1.
+
+ -- User Option: text-quoting-style
+     The value of this user option is a symbol that specifies the style
+     Emacs should use for single quotes in the wording of help and
+     messages.  If the option’s value is ‘curve’, the style is ‘like
+     this’ with curved single quotes.  If the value is ‘straight’, the
+     style is 'like this' with straight apostrophes.  If the value is
+     ‘grave’, quotes are not translated and the style is `like this'
+     with grave accent and apostrophe, the standard style before Emacs
+     version 25.  The default value ‘nil’ acts like ‘curve’ if curved
+     single quotes seem to be displayable, and like ‘grave’ otherwise.
+
+     This option is useful on platforms that have problems with curved
+     quotes.  You can customize it freely according to your personal
+     preference.
+
+ -- Function: region-bounds
+     Return the boundaries of the region.  Value is a list of one or
+     more cons cells of the form ‘(start . end)’.  It will have more
+     than one cons cell when the region is non-contiguous, see
+     ‘region-noncontiguous-p’ and ‘extract-rectangle-bounds’.
+
+ -- Function: region-noncontiguous-p
+     Return non-nil if the region contains several pieces.  An example
+     is a rectangular region handled as a list of separate contiguous
+     regions for each line.
+
+ -- Macro: save-mark-and-excursion body...
+     This macro is like ‘save-excursion’, but also saves and restores
+     the mark location and ‘mark-active’.  This macro does what
+     ‘save-excursion’ did before Emacs 25.1.
+
+ -- Function: format-message string &rest objects
+     This function acts like ‘format’, except it also converts any grave
+     accents (`) and apostrophes (') in STRING as per the value of
+     ‘text-quoting-style’.
+
+     Typically grave accent and apostrophe in the format translate to
+     matching curved quotes, e.g., "Missing `%s'" might result in
+     "Missing ‘foo’".  *Note (elisp)Text Quoting Style::, for how to
+     influence or inhibit this translation.
+
+     *note (elisp)Formatting Strings::.
+
+ -- Function: directory-name-p filename
+     This function returns non-‘nil’ if FILENAME ends with a directory
+     separator character.  This is the forward slash ‘/’ on GNU and
+     other POSIX-like systems; MS-Windows and MS-DOS recognize both the
+     forward slash and the backslash ‘\’ as directory separators.
+
+     *Note (elisp)Directory Names::.
+
+ -- Function: string-greaterp string1 string2
+     This function returns the result of comparing STRING1 and STRING2
+     in the opposite order, i.e., it is equivalent to calling
+     ‘(string-lessp STRING2 STRING1)’.
+
+     *Note (elisp)Text Comparison::.
+
+ -- Macro: with-file-modes mode body...
+     This macro evaluates the BODY forms with the default permissions
+     for new files temporarily set to MODES (whose value is as for
+     ‘set-file-modes’ above).  When finished, it restores the original
+     default file permissions, and returns the value of the last form in
+     BODY.
+
+     This is useful for creating private files, for example.
+
+     *Note (elisp)Changing Files::.
+
+ -- Function: alist-get key alist &optional default remove
+     This function is similar to ‘assq’.  It finds the first association
+     ‘(KEY . VALUE)’ by comparing KEY with ALIST elements, and, if
+     found, returns the VALUE of that association.  If no association is
+     found, the function returns DEFAULT.
+
+     This is a generalized variable (*note (elisp)Generalized
+     Variables::) that can be used to change a value with ‘setf’.  When
+     using it to set a value, optional argument REMOVE non-‘nil’ means
+     to remove KEY’s association from ALIST if the new value is ‘eql’ to
+     DEFAULT.
+
+     *note (elisp)Association Lists::.
+
+ -- Macro: if-let (bindings...) then &rest else...
+     As with ‘let*’, BINDINGS will consist of ‘(SYMBOL VALUE-FORM)’
+     entries that are evaluated and bound sequentially.  If all
+     VALUE-FORM evaluate to non-‘nil’ values, then THEN is evaluated as
+     were the case with a regular ‘let*’ expression, with all the
+     variables bound.  If any VALUE-FORM evaluates to ‘nil’, ELSE is
+     evaluated, without any bound variables.
+
+     A binding may also optionally drop the SYMBOL, and simplify to
+     ‘(VALUE-FORM)’ if only the test is of interest.
+
+     For the sake of backwards compatibility, it is possible to write a
+     single binding without a binding list:
+
+          (if-let* (SYMBOL (test)) foo bar)
+          ≡
+          (if-let* ((SYMBOL (test))) foo bar)
+
+ -- Macro: when-let (bindings...) &rest body
+     As with ‘when’, if one is only interested in the case where all
+     BINDINGS are non-nil.  Otherwise BINDINGS are interpreted just as
+     they are by ‘if-let*’.
+
+ -- Function: hash-table-empty hash-table
+     Check whether HASH-TABLE is empty (has 0 elements).
+
+ -- Macro: thread-first &rest forms
+     Combine FORMS into a single expression by “threading” each element
+     as the _first_ argument of their successor.  Elements of FORMS can
+     either be an list of an atom.
+
+     For example, consider the threading expression and it’s equivalent
+     macro expansion:
+
+          (thread-first
+            5
+            (+ 20)
+            (/ 25)
+            -
+            (+ 40))
+          ≡
+          (+ (- (/ (+ 5 20) 25)) 40)
+
+     Note how the single ‘-’ got converted into a list before threading.
+     This example uses arithmetic functions, but ‘thread-first’ is not
+     restricted to arithmetic or side-effect free code.
+
+ -- Macro: thread-last &rest forms
+     Combine FORMS into a single expression by “threading” each element
+     as the _last_ argument of their successor.  Elements of FORMS can
+     either be an list of an atom.
+
+     For example, consider the threading expression and it’s equivalent
+     macro expansion:
+
+          (thread-first
+            5
+            (+ 20)
+            (/ 25)
+            -
+            (+ 40))
+          ≡
+          (+ 40 (- (/ 25 (+ 20 5))))
+
+     Note how the single ‘-’ got converted into a list before threading.
+     This example uses arithmetic functions, but ‘thread-last’ is not
+     restricted to arithmetic or side-effect free code.
+
+ -- Function: macroexpand-1 form &optional environment
+     This function expands macros like ‘macroexpand’, but it only
+     performs one step of the expansion: if the result is another macro
+     call, ‘macroexpand-1’ will not expand it.
+
+     *Note Expansion: (elisp)Expansion.
+
+ -- Function: macroexp-quote e
+     Return an expression E such that ‘(eval e)’ is V.
+
+ -- Function: macroexp-parse body
+     Parse a function BODY into ‘(declarations . exps)’.
+
+ -- Function: bool-vector &rest objects
+     This function creates and returns a bool-vector whose elements are
+     the arguments, OBJECTS.
+
+     *Note (elisp)Bool-Vectors::.
+
+2.1.2 Extended Definitions
+--------------------------
+
+These functions must be called explicitly via ‘compat-call’, since their
+calling convention or behavior was extended in Emacs 25.1:
+
+ -- Function: compat-call sort sequence predicate
+     This function sorts SEQUENCE stably.  Note that this function
+     doesn’t work for all sequences; it may be used only for lists and
+     vectors.  If SEQUENCE is a list, it is modified destructively.
+     This functions returns the sorted SEQUENCE and compares elements
+     using PREDICATE.  A stable sort is one in which elements with equal
+     sort keys maintain their relative order before and after the sort.
+     Stability is important when successive sorts are used to order
+     elements according to different criteria.
+
+     *Note (elisp)Sequence Functions::.
+
+     The compatibility version adds support for vectors to be sorted,
+     not just lists.
+
+2.1.3 Missing Definitions
+-------------------------
+
+Compat does not provide support for the following Lisp features
+implemented in 25.1:
+
+   • The function ‘macroexp-macroexpand’.
+   • The macro ‘macroexp-let2*’.
+   • The function ‘directory-files-recursively’.
+   • New ‘pcase’ patterns.
+   • The hook ‘prefix-command-echo-keystrokes-functions’ and
+     ‘prefix-command-preserve-state-hook’.
+   • The hook ‘pre-redisplay-functions’.
+   • The function ‘make-process’.
+   • Support for the variable ‘inhibit-message’.
+   • The ‘define-inline’ functionality.
+   • The functions ‘string-collate-lessp’ and ‘string-collate-equalp’.
+   • The function ‘funcall-interactively’.
+   • The function ‘buffer-substring-with-bidi-context’.
+   • The function ‘font-info’.
+   • The function ‘default-font-width’.
+   • The function ‘window-font-height’ and ‘window-font-width’.
+   • The function ‘window-max-chars-per-line’.
+   • The function ‘set-binary-mode’.
+   • The functions ‘bufferpos-to-filepos’ and ‘filepos-to-bufferpos’.
+   • The ‘thunk’ library.
+
+\1f
+File: docXccUUB.info,  Node: Emacs 26.1,  Next: Emacs 27.1,  Prev: Emacs 25.1,  Up: Support
+
+2.2 Emacs 26.1
+==============
+
+2.2.1 Added Definitions
+-----------------------
+
+The following functions and macros are implemented in Emacs 26.1.  These
+functions are made available by Compat on Emacs versions older than
+26.1.
+
+ -- Function: assoc-delete-all key alist
+     This function is like ‘assq-delete-all’ except that it uses ‘equal’
+     to compare elements.
+
+ -- Function: read-answer question answers
+     This function prompts the user with text in QUESTION, which should
+     end in the ‘SPC’ character.  The function includes in the prompt
+     the possible responses in ANSWERS by appending them to the end of
+     QUESTION.  The possible responses are provided in ANSWERS as an
+     alist whose elements are of the following form:
+
+          (LONG-ANSWER SHORT-ANSWER HELP-MESSAGE)
+
+     where LONG-ANSWER is the complete text of the user response, a
+     string; SHORT-ANSWER is a short form of the same response, a single
+     character or a function key; and HELP-MESSAGE is the text that
+     describes the meaning of the answer.  If the variable
+     ‘read-answer-short’ is non-‘nil’, the prompt will show the short
+     variants of the possible answers and the user is expected to type
+     the single characters/keys shown in the prompt; otherwise the
+     prompt will show the long variants of the answers, and the user is
+     expected to type the full text of one of the answers and end by
+     pressing <RET>.  If ‘use-dialog-box’ is non-‘nil’, and this
+     function was invoked by mouse events, the question and the answers
+     will be displayed in a GUI dialog box.
+
+     The function returns the text of the LONG-ANSWER selected by the
+     user, regardless of whether long or short answers were shown in the
+     prompt and typed by the user.
+
+     Here is an example of using this function:
+
+          (let ((read-answer-short t))
+            (read-answer "Foo "
+               '(("yes"  ?y "perform the action")
+                 ("no"   ?n "skip to the next")
+                 ("all"  ?! "perform for the rest without more questions")
+                 ("help" ?h "show help")
+                 ("quit" ?q "exit"))))
+
+ -- Function: mapcan function sequence
+     This function applies FUNCTION to each element of SEQUENCE, like
+     ‘mapcar’, but instead of collecting the results into a list, it
+     returns a single list with all the elements of the results (which
+     must be lists), by altering the results (using ‘nconc’; *note
+     (elisp)Rearrangement::).  Like with ‘mapcar’, SEQUENCE can be of
+     any type except a char-table.
+
+          ;; Contrast this: (mapcar #'list '(a b c d)) ⇒ ((a) (b) (c)
+          (d)) ;; with this: (mapcan #'list '(a b c d)) ⇒ (a b c d)
+
+     *Note (elisp)Mapping Functions::.
+
+ -- Function: cXXXr
+ -- Function: cXXXXr
+     *Note (elisp)List Elements::.
+
+ -- Function: gensym &optional prefix
+     This function returns a symbol using ‘make-symbol’, whose name is
+     made by appending ‘gensym-counter’ to PREFIX and incrementing that
+     counter, guaranteeing that no two calls to this function will
+     generate a symbol with the same name.  The prefix defaults to
+     ‘"g"’.
+
+ -- Variable: gensym-counter
+     See ‘gensym’.
+
+ -- Function: buffer-hash &optional buffer-or-name
+     Return a hash of BUFFER-OR-NAME.  If ‘nil’, this defaults to the
+     current buffer.  As opposed to ‘secure-hash’, this function
+     computes the hash based on the internal representation of the
+     buffer, disregarding any coding systems.  It’s therefore only
+     useful when comparing two buffers running in the same Emacs, and is
+     not guaranteed to return the same hash between different Emacs
+     versions.  It should be somewhat more efficient on larger buffers
+     than ‘secure-hash’ is, and should not allocate more memory.
+
+ -- Macro: file-name-unquote name
+     This macro removes the quotation prefix ‘/:’ from the file NAME, if
+     any.  If NAME is a remote file name, the local part of NAME is
+     unquoted.
+
+ -- Function: file-name-quoted-p name
+     This macro returns non-‘nil’, when NAME is quoted with the prefix
+     ‘/:’.  If NAME is a remote file name, the local part of NAME is
+     checked.
+
+     *Note (elisp)File Name Expansion::.
+
+ -- Function: file-name-quote name
+     This macro adds the quotation prefix ‘/:’ to the file NAME.  For a
+     local file NAME, it prefixes NAME with ‘/:’.  If NAME is a remote
+     file name, the local part of NAME (*note (elisp)Magic File Names::)
+     is quoted.  If NAME is already a quoted file name, NAME is returned
+     unchanged.
+
+          (substitute-in-file-name (compat-call file-name-quote "bar/~/foo")) ⇒
+               "/:bar/~/foo"
+
+          (substitute-in-file-name (compat-call file-name-quote "/ssh:host:bar/~/foo"))
+               ⇒ "/ssh:host:/:bar/~/foo"
+
+     The macro cannot be used to suppress file name handlers from magic
+     file names (*note (elisp)Magic File Names::).
+
+     *Note (elisp)File Name Expansion::.
+
+ -- Function: make-nearby-temp-file prefix &optional dir-flag suffix
+     This function is similar to ‘make-temp-file’, but it creates a
+     temporary file as close as possible to ‘default-directory’.  If
+     PREFIX is a relative file name, and ‘default-directory’ is a remote
+     file name or located on a mounted file systems, the temporary file
+     is created in the directory returned by the function
+     ‘temporary-file-directory’.  Otherwise, the function
+     ‘make-temp-file’ is used.  PREFIX, DIR-FLAG and SUFFIX have the
+     same meaning as in ‘make-temp-file’.
+
+          (let ((default-directory "/ssh:remotehost:")) (make-nearby-temp-file
+            "foo")) ⇒ "/ssh:remotehost:/tmp/foo232J6v"
+
+ -- Variable: mounted-file-systems
+     A regular expression matching files names that are probably on a
+     mounted file system.
+
+ -- Function: temporary-file-directory
+     The directory for writing temporary files via
+     ‘make-nearby-temp-file’.  In case of a remote ‘default-directory’,
+     this is a directory for temporary files on that remote host.  If
+     such a directory does not exist, or ‘default-directory’ ought to be
+     located on a mounted file system (see ‘mounted-file-systems’), the
+     function returns ‘default-directory’.  For a non-remote and
+     non-mounted ‘default-directory’, the value of the variable
+     ‘temporary-file-directory’ is returned.
+
+     *Note (elisp)Unique File Names::.
+
+ -- Macro: if-let* (bindings...) then &rest else
+     ‘if-let*’ is mostly equivalent to ‘if-let’, with the exception that
+     the legacy ‘(if (VAR (test)) foo bar)’ syntax is not permitted.
+
+ -- Macro: when-let* (bindings...) then &rest else
+     ‘when-let*’ is mostly equivalent to ‘when-let’, with the exception
+     that the legacy ‘(when-let (VAR (test)) foo bar)’ syntax is not
+     permitted.
+
+ -- Macro: and-let* (bindings...) &rest body
+     A combination of LET* and AND, analogous to ‘when-let*’.  If all
+     BINDINGS are non-‘nil’ and BODY is ‘nil’, then the result of the
+     ‘and-let*’ form will be the last value bound in BINDINGS.
+
+     **Please Note:** The implementation provided by Compat does not
+     include a bug that was observed with Emacs 26 (see
+     <https://debbugs.gnu.org/cgi/bugreport.cgi?bug=31840>).
+
+ -- Function: file-local-name filename
+     This function returns the _local part_ of FILENAME.  This is the
+     part of the file’s name that identifies it on the remote host, and
+     is typically obtained by removing from the remote file name the
+     parts that specify the remote host and the method of accessing it.
+     For example:
+
+          (file-local-name "/ssh:USER@HOST:/foo/bar") ⇒
+               "/foo/bar"
+
+     For a remote FILENAME, this function returns a file name which
+     could be used directly as an argument of a remote process (*note
+     (elisp)Asynchronous Processes::, and *note (elisp)Synchronous
+     Processes::), and as the program to run on the remote host.  If
+     FILENAME is local, this function returns it unchanged.
+
+     *Note (elisp)Magic File Names::.
+
+ -- Function: read-multiple-choice prompt choices
+     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.
+
+     See *note Reading One Event: (elisp)Reading One Event.
+
+ -- Function: image-property
+     Defined in ‘image.el’.
+
+     This function can also be used as a generalised variable.
+
+ -- Function: file-attribute-type
+     Return the field _type_ as generated by ‘file-attributes’.
+
+     *Note (elisp)File Attributes::.
+
+ -- Function: file-attribute-link-number
+     Return the field _link-number_ as generated by ‘file-attributes’.
+
+     *Note (elisp)File Attributes::.
+
+ -- Function: file-attribute-user-id
+     Return the field _user-id_ as generated by ‘file-attributes’.
+
+     *Note (elisp)File Attributes::.
+
+ -- Function: file-attribute-group-id
+     Return the field _group-id_ as generated by ‘file-attributes’.
+
+     *Note (elisp)File Attributes::.
+
+ -- Function: file-attribute-access-time
+     Return the field _access-time_ as generated by ‘file-attributes’.
+
+     *Note (elisp)File Attributes::.
+
+ -- Function: file-attribute-modification-time
+     Return the field _modification-time_ as generated by
+     ‘file-attributes’.
+
+     *Note (elisp)File Attributes::.
+
+ -- Function: file-attribute-status-change-time
+     Return the field _modification-time_ as generated by
+     ‘file-attributes’.
+
+     *Note (elisp)File Attributes::.
+
+ -- Function: file-attribute-size
+     Return the field _size_ as generated by ‘file-attributes’.
+
+     *Note (elisp)File Attributes::.
+
+ -- Function: file-attribute-modes
+     Return the field _modes_ as generated by ‘file-attributes’.
+
+     *Note (elisp)File Attributes::.
+
+ -- Function: file-attribute-inode-number
+     Return the field _inode-number_ as generated by ‘file-attributes’.
+
+     *Note (elisp)File Attributes::.
+
+ -- Function: file-attribute-device-number
+     Return the field _device-number_ as generated by ‘file-attributes’.
+
+     *Note (elisp)File Attributes::.
+
+ -- Function: file-attribute-collect attributes &rest attr-names
+     Filter the file attributes ATTRIBUTES, as generated by
+     ‘file-attributes’, according to ATTR-NAMES.
+
+     Valid attribute names for ATTR-NAMES are: type, link-number,
+     user-id, group-id, access-time, modification-time,
+     status-change-time, size, modes, inode-number and device-number.
+
+          (file-attributes ".") ⇒ (t 1 1000 1000 (25329 18215 325481 96000) (25325 15364 530263 840000) (25325 15364 530263 840000) 788 "drwxr-xr-x" t 137819 40)
+          (file-attribute-collect (file-attributes ".") 'type 'modes
+          'inode-number) ⇒ (t "drwxr-xr-x" 137819)
+
+2.2.2 Extended Definitions
+--------------------------
+
+These functions must be called explicitly via ‘compat-call’, since their
+calling convention or behavior was extended in Emacs 26.1:
+
+ -- Function: compat-call make-temp-file prefix &optional dir-flag
+          suffix text
+     This function creates a temporary file and returns its name.  Emacs
+     creates the temporary file’s name by adding to PREFIX some random
+     characters that are different in each Emacs job.  The result is
+     guaranteed to be a newly created file, containing TEXT if that’s
+     given as a string and empty otherwise.  On MS-DOS, this function
+     can truncate PREFIX to fit into the 8+3 file-name limits.  If
+     PREFIX is a relative file name, it is expanded against
+     ‘temporary-file-directory’.
+
+     The compatibility version adds support for handling the optional
+     argument TEXT.
+
+          (make-temp-file "foo")
+               ⇒ "/tmp/foo232J6v"
+
+     When ‘make-temp-file’ returns, the file has been created and is
+     empty.  At that point, you should write the intended contents into
+     the file.
+
+     If DIR-FLAG is non-‘nil’, ‘make-temp-file’ creates an empty
+     directory instead of an empty file.  It returns the file name, not
+     the directory name, of that directory.  *Note (elisp)Directory
+     Names::.
+
+     If SUFFIX is non-‘nil’, ‘make-temp-file’ adds it at the end of the
+     file name.
+
+     If TEXT is a string, ‘make-temp-file’ inserts it in the file.
+
+     To prevent conflicts among different libraries running in the same
+     Emacs, each Lisp program that uses ‘make-temp-file’ should have its
+     own PREFIX.  The number added to the end of PREFIX distinguishes
+     between the same application running in different Emacs jobs.
+     Additional added characters permit a large number of distinct names
+     even in one Emacs job.
+
+ -- Function: compat-call assoc key alist &optional testfn
+     This function returns the first association for KEY in ALIST,
+     comparing KEY against the alist elements using TESTFN if it is a
+     function, and ‘equal’ otherwise (*note (elisp)Equality
+     Predicates::).  If TESTFN is a function, it is called with two
+     arguments: the CAR of an element from ALIST and KEY.  The function
+     returns ‘nil’ if no association in ALIST has a CAR equal to KEY, as
+     tested by TESTFN.
+
+     *Note (elisp)Association Lists::.
+
+     The compatibility version adds support for handling the optional
+     argument TESTFN.
+
+ -- Function: compat-call line-number-at-pos &optional pos absolute
+     This function returns the line number in the current buffer
+     corresponding to the buffer position POS.  If POS is ‘nil’ or
+     omitted, the current buffer position is used.  If ABSOLUTE is
+     ‘nil’, the default, counting starts at ‘(point-min)’, so the value
+     refers to the contents of the accessible portion of the
+     (potentially narrowed) buffer.  If ABSOLUTE is non-‘nil’, ignore
+     any narrowing and return
+
+     *Note (elisp)Text Lines::.
+
+     The compatibility version adds support for handling the optional
+     argument ABSOLUTE.
+
+ -- Function: compat-call alist-get key alist &optional default remove
+          testfn
+     *Note (elisp)Association Lists::.  This function is similar to
+     ‘assq’.  It finds the first association ‘(KEY . VALUE)’ by
+     comparing KEY with ALIST elements, and, if found, returns the VALUE
+     of that association.  If no association is found, the function
+     returns DEFAULT.  Comparison of KEY against ALIST elements uses the
+     function specified by TESTFN, defaulting to ‘eq’.
+
+     *Note (elisp)Association Lists::.
+
+     The compatibility version handles the optional argument TESTFN.  It
+     can also be used as a *note Generalized Variables:
+     (elisp)generalised variable.
+
+ -- Function: compat-call string-trim-left string &optional regexp
+     Remove the leading text that matches REGEXP from STRING.  REGEXP
+     defaults to ‘[ \t\n\r]+’.
+
+     *Note (elisp)Creating Strings::.
+
+     The compatibility version handles the optional argument REGEXP.
+
+ -- Function: compat-call string-trim-right string &optional regexp
+     Remove the trailing text that matches REGEXP from STRING.  REGEXP
+     defaults to ‘[ \t\n\r]+’.
+
+     *Note (elisp)Creating Strings::.
+
+     The compatibility version handles the optional argument REGEXP.
+
+ -- Function: compat-call string-trim string &optional trim-left
+          trim-right
+     Remove the leading text that matches TRIM-LEFT and trailing text
+     that matches TRIM-RIGHT from STRING.  Both regexps default to ‘[
+     \t\n\r]+’.
+
+     *Note (elisp)Creating Strings::.
+
+     The compatibility version handles the optional arguments TRIM-LEFT
+     and TRIM-RIGHT.
+
+2.2.3 Missing Definitions
+-------------------------
+
+Compat does not provide support for the following Lisp features
+implemented in 26.1:
+
+   • The function ‘func-arity’.
+   • The function ‘secure-hash-algorithms’.
+   • The function ‘gnutls-available-p’.
+   • Support for records and record functions.
+   • The function ‘mapbacktrace’.
+   • The function ‘file-name-case-insensitive-p’.
+   • The additional elements of ‘parse-partial-sexp’.
+   • The function ‘add-variable-watcher’.
+   • The function ‘undo-amalgamate-change-group’.
+   • The function ‘char-from-name’
+   • Signalling errors when ‘length’ or ‘member’ deal with list cycles.
+   • The function ‘frame-list-z-order’.
+   • The function ‘frame-restack’.
+   • All changes related to ‘display-buffer’.
+   • The function ‘window-swap-states’.
+   • The function ‘string-version-lessp’.
+   • The ‘xdg’ library.
+   • The ‘svg’ library (published separately as a :core package).
+
+\1f
+File: docXccUUB.info,  Node: Emacs 27.1,  Next: Emacs 28.1,  Prev: Emacs 26.1,  Up: Support
+
+2.3 Emacs 27.1
+==============
+
+2.3.1 Added Definitions
+-----------------------
+
+The following functions and macros are implemented in Emacs 27.1.  These
+functions are made available by Compat on Emacs versions older than
+27.1.
+
+ -- Function: major-mode-suspend
+     This function works like ‘fundamental-mode’, in that it kills all
+     buffer-local variables, but it also records the major mode in
+     effect, so that it could subsequently be restored.  This function
+     and ‘major-mode-restore’ (described next) are useful when you need
+     to put a buffer under some specialized mode other than the one
+     Emacs chooses for it automatically, but would also like to be able
+     to switch back to the original mode later.
+
+ -- Function: major-mode-restore &optional avoided-modes
+     This function restores the major mode recorded by
+     ‘major-mode-suspend’.  If no major mode was recorded, this function
+     calls ‘normal-mode’, but tries to force it not to choose any modes
+     in AVOIDED-MODES, if that argument is non-‘nil’.
+
+ -- Function: ring-resize ring size
+     Set the size of RING to SIZE.  If the new size is smaller, then the
+     oldest items in the ring are discarded.
+
+ -- Function: minibuffer-history-value
+     Return the value of the minibuffer input history list.  If
+     MINIBUFFER-HISTORY-VARIABLE points to a buffer-local variable and
+     the minibuffer is active, return the buffer-local value for the
+     buffer that was current when the minibuffer was activated."
+
+ -- Macro: with-minibuffer-selected-window &rest body
+     Execute the forms in BODY from the minibuffer in its original
+     window.  When used in a minibuffer window, select the window
+     selected just before the minibuffer was activated, and execute the
+     forms.
+
+ -- Function: read-char-from-minibuffer prompt &optional chars history
+     This function uses the minibuffer to read and return a single
+     character.  Optionally, it ignores any input that is not a member
+     of CHARS, a list of accepted characters.  The HISTORY argument
+     specifies the history list symbol to use; if it is omitted or
+     ‘nil’, this function doesn’t use the history.
+
+     If you bind ‘help-form’ to a non-‘nil’ value while calling
+     ‘read-char-from-minibuffer’, then pressing ‘help-char’ causes it to
+     evaluate ‘help-form’ and display the result.
+
+ -- Function: bignump object
+     This predicate tests whether its argument is a large integer, and
+     returns ‘t’ if so, ‘nil’ otherwise.  Unlike small integers, large
+     integers can be ‘=’ or ‘eql’ even if they are not ‘eq’.
+
+ -- Function: fixnump object
+     This predicate tests whether its argument is a small integer, and
+     returns ‘t’ if so, ‘nil’ otherwise.  Small integers can be compared
+     with ‘eq’.
+
+ -- Special Form: with-suppressed-warnings warnings body...
+     In execution, this is equivalent to ‘(progn BODY...)’, but the
+     compiler does not issue warnings for the specified conditions in
+     BODY.  WARNINGS is an association list of warning symbols and
+     function/variable symbols they apply to.  For instance, if you wish
+     to call an obsolete function called ‘foo’, but want to suppress the
+     compilation warning, say:
+
+          (with-suppressed-warnings ((obsolete foo))
+            (foo ...))
+
+ -- Function: proper-list-p object
+     This function returns the length of OBJECT if it is a proper list,
+     ‘nil’ otherwise (*note (elisp)Cons Cells::).  In addition to
+     satisfying ‘listp’, a proper list is neither circular nor dotted.
+
+          (proper-list-p '(a b c)) ⇒ 3
+          (proper-list-p '(a b . c)) ⇒ nil
+
+     *Note (elisp)List-related Predicates::.
+
+ -- Function: string-distance string1 string2 &optional bytecompare
+     This function returns the _Levenshtein distance_ between the source
+     string STRING1 and the target string STRING2.  The Levenshtein
+     distance is the number of single-character changes—deletions,
+     insertions, or replacements—required to transform the source string
+     into the target string; it is one possible definition of the _edit
+     distance_ between strings.
+
+     Letter-case of the strings is significant for the computed
+     distance, but their text properties are ignored.  If the optional
+     argument BYTECOMPARE is non-‘nil’, the function calculates the
+     distance in terms of bytes instead of characters.  The byte-wise
+     comparison uses the internal Emacs representation of characters, so
+     it will produce inaccurate results for multibyte strings that
+     include raw bytes (*note (elisp)Text Representations::); make the
+     strings unibyte by encoding them (*note (elisp)Explicit Encoding::)
+     if you need accurate results with raw bytes.
+
+     *Note (elisp)Text Comparison::.
+
+ -- Macro: ignore-errors body...
+     This construct executes BODY, ignoring any errors that occur during
+     its execution.  If the execution is without error, ‘ignore-errors’
+     returns the value of the last form in BODY; otherwise, it returns
+     ‘nil’.
+
+     Here’s the example at the beginning of this subsection rewritten
+     using ‘ignore-errors’:
+
+            (ignore-errors (delete-file filename))
+
+     *Note (elisp)Handling Errors::.
+
+ -- Macro: dolist-with-progress-reporter (var count [result])
+          reporter-or-message body...
+     This is another convenience macro that works the same way as
+     ‘dolist’ does, but also reports loop progress using the functions
+     described above.  As in ‘dotimes-with-progress-reporter’,
+     ‘reporter-or-message’ can be a progress reporter or a string.  You
+     can rewrite the previous example with this macro as follows:
+
+          (dolist-with-progress-reporter (k (number-sequence 0 500)) "Collecting
+              some mana for Emacs..."  (sit-for 0.01))
+
+     *Note (elisp)Progress::.
+
+ -- Function: flatten-tree tree
+     This function returns a “flattened” copy of TREE, that is, a list
+     containing all the non-‘nil’ terminal nodes, or leaves, of the tree
+     of cons cells rooted at TREE.  Leaves in the returned list are in
+     the same order as in TREE.
+
+          (flatten-tree '(1 (2 . 3) nil (4 5 (6)) 7)) ⇒(1 2 3 4 5 6 7)
+
+     *Note (elisp)Building Lists::.
+
+ -- Function: xor condition1 condition2
+     This function returns the boolean exclusive-or of CONDITION1 and
+     CONDITION2.  That is, ‘xor’ returns ‘nil’ if either both arguments
+     are ‘nil’, or both are non-‘nil’.  Otherwise, it returns the value
+     of that argument which is non-‘nil’.
+
+     Note that in contrast to ‘or’, both arguments are always evaluated.
+
+     *Note (elisp)Combining Conditions::.
+
+ -- Variable: regexp-unmatchable
+     This variable contains a regexp that is guaranteed not to match any
+     string at all.  It is particularly useful as default value for
+     variables that may be set to a pattern that actually matches
+     something.
+
+     *Note (elisp)Regexp Functions::
+
+ -- Function: decoded-time-second time
+     Return the SECONDS field of a ‘decoded-time’ record TIME.  It can
+     also be used as a *note Generalized Variables: (elisp)generalised
+     variable.
+
+ -- Function: decoded-time-minute time
+     Return the MINUTE field of a ‘decoded-time’ record TIME.  It can
+     also be used as a *note Generalized Variables: (elisp)generalised
+     variable.
+
+ -- Function: decoded-time-hour time
+     Return the HOUR field of a ‘decoded-time’ record TIME.  It can also
+     be used as a *note Generalized Variables: (elisp)generalised
+     variable.
+
+ -- Function: decoded-time-day time
+     Return the DAY field of a ‘decoded-time’ record TIME.  It can also
+     be used as a *note Generalized Variables: (elisp)generalised
+     variable.
+
+ -- Function: decoded-time-month time
+     Return the MONTH field of a ‘decoded-time’ record TIME.  It can
+     also be used as a *note Generalized Variables: (elisp)generalised
+     variable.
+
+ -- Function: decoded-time-year time
+     Return the YEAR field of a ‘decoded-time’ record TIME.  It can also
+     be used as a *note Generalized Variables: (elisp)generalised
+     variable.
+
+ -- Function: decoded-time-weekday time
+     Return the WEEKDAY field of a ‘decoded-time’ record TIME.  It can
+     also be used as a *note Generalized Variables: (elisp)generalised
+     variable.
+
+ -- Function: decoded-time-dst time
+     Return the DST (daylight saving time indicator) field of a
+     ‘decoded-time’ record TIME.  It can also be used as a *note
+     Generalized Variables: (elisp)generalised variable.
+
+ -- Function: decoded-time-zone time
+     Return the ZONE field of a ‘decoded-time’ record TIME.  It can also
+     be used as a *note Generalized Variables: (elisp)generalised
+     variable.
+
+ -- Function: package-get-version
+     Return the version number of the package in which this is used.
+
+ -- Function: time-equal-p t1 t2
+     This returns ‘t’ if the two time values T1 and T2 are equal.
+
+     *Note (elisp)Time Calculations::.
+
+ -- Function: date-days-in-month year month
+     Return the number of days in MONTH in YEAR.  For instance, February
+     2020 has 29 days.
+
+     *Note (elisp)Time Calculations::.  This function requires the
+     ‘time-date’ feature to be loaded.
+
+ -- Function: date-ordinal-to-time year ordinal
+     Convert a YEAR/ORDINAL to the equivalent decoded-time structure.
+     ORDINAL is the number of days since the start of the year, with
+     January 1st being 1.
+
+     *Note (elisp)Time Calculations::.  This function requires the
+     ‘time-date’ feature to be loaded.
+
+ -- User Option: exec-path
+     The value of this variable is a list of directories to search for
+     programs to run in subprocesses.  Each element is either the name
+     of a directory (i.e., a string), or ‘nil’, which stands for the
+     default directory (which is the value of ‘default-directory’).
+     *Note executable-find: (elisp)Locating Files, for the details of
+     this search.
+
+     The value of ‘exec-path’ is used by ‘call-process’ and
+     ‘start-process’ when the PROGRAM argument is not an absolute file
+     name.
+
+     Generally, you should not modify ‘exec-path’ directly.  Instead,
+     ensure that your ‘PATH’ environment variable is set appropriately
+     before starting Emacs.  Trying to modify ‘exec-path’ independently
+     of ‘PATH’ can lead to confusing results.
+
+     *Note (elisp)Subprocess Creation::.
+
+ -- Function: provided-mode-derived-p mode &rest modes
+     This function returns non-‘nil’ if MODE is derived from any of the
+     major modes given by the symbols MODES.
+
+ -- Function: file-size-human-readable-iec size
+     Human-readable string for SIZE bytes, using IEC prefixes.
+
+ -- Function: make-empty-file filename &optional parents
+     This function creates an empty file named FILENAME.  As
+     ‘make-directory’, this function creates parent directories if
+     PARENTS is non-‘nil’.  If FILENAME already exists, this function
+     signals an error.
+
+ -- Function: text-property-search-forward prop &optional value
+          predicate not-current
+     Search for the next region that has text property PROP set to VALUE
+     according to PREDICATE.
+
+     This function is modeled after ‘search-forward’ and friends in that
+     it moves point, but it returns a structure that describes the match
+     instead of returning it in ‘match-beginning’ and friends.
+
+     If the text property can’t be found, the function returns ‘nil’.
+     If it’s found, point is placed at the end of the region that has
+     this text property match, and a ‘prop-match’ structure is returned.
+
+     PREDICATE can either be ‘t’ (which is a synonym for ‘equal’), ‘nil’
+     (which means “not equal”), or a predicate that will be called with
+     two parameters: The first is VALUE, and the second is the value of
+     the text property we’re inspecting.
+
+     If NOT-CURRENT, if point is in a region where we have a match, then
+     skip past that and find the next instance instead.
+
+     The ‘prop-match’ structure has the following accessors:
+     ‘prop-match-beginning’ (the start of the match), ‘prop-match-end’
+     (the end of the match), and ‘prop-match-value’ (the value of
+     PROPERTY at the start of the match).
+
+     In the examples below, imagine that you’re in a buffer that looks
+     like this:
+
+          This is a bold and here's bolditalic and this is the end.
+
+     That is, the “bold” words are the ‘bold’ face, and the “italic”
+     word is in the ‘italic’ face.
+
+     With point at the start:
+
+          (while (setq match (text-property-search-forward 'face 'bold t))
+            (push (buffer-substring (prop-match-beginning match)
+                                    (prop-match-end match))
+                  words))
+
+     This will pick out all the words that use the ‘bold’ face.
+
+          (while (setq match (text-property-search-forward 'face nil t))
+            (push (buffer-substring (prop-match-beginning match)
+                                    (prop-match-end match))
+                  words))
+
+     This will pick out all the bits that have no face properties, which
+     will result in the list ‘("This is a " "and here's " "and this is
+     the end")’ (only reversed, since we used ‘push’).
+
+          (while (setq match (text-property-search-forward 'face nil nil))
+            (push (buffer-substring (prop-match-beginning match)
+                                    (prop-match-end match))
+                  words))
+
+     This will pick out all the regions where ‘face’ is set to
+     something, but this is split up into where the properties change,
+     so the result here will be ‘("bold" "bold" "italic")’.
+
+     For a more realistic example where you might use this, consider
+     that you have a buffer where certain sections represent URLs, and
+     these are tagged with ‘shr-url’.
+
+          (while (setq match (text-property-search-forward 'shr-url nil nil))
+            (push (prop-match-value match) urls))
+
+     This will give you a list of all those URLs.
+
+     *Note (Property Search)elisp::.
+
+ -- Function: text-property-search-backward prop &optional value
+          predicate not-current
+     This is just like ‘text-property-search-forward’, but searches
+     backward instead.  Point is placed at the beginning of the matched
+     region instead of the end, though.
+
+     *Note (Property Search)elisp::.
+
+2.3.2 Extended Definitions
+--------------------------
+
+These functions must be called explicitly via ‘compat-call’, since their
+calling convention or behavior was extended in Emacs 27.1:
+
+ -- Function: compat-call recenter &optional count redisplay
+     This function scrolls the text in the selected window so that point
+     is displayed at a specified vertical position within the window.
+     It does not move point with respect to the text.
+
+     *Note (elisp)Textual Scrolling::.
+
+     This compatibility version adds support for the optional argument
+     REDISPLAY.
+
+ -- Function: compat-call lookup-key keymap key &optional
+          accept-defaults
+     This function returns the definition of KEY in KEYMAP.  If the
+     string or vector KEY is not a valid key sequence according to the
+     prefix keys specified in KEYMAP, it must be too long and have extra
+     events at the end that do not fit into a single key sequence.  Then
+     the value is a number, the number of events at the front of KEY
+     that compose a complete key.
+
+     *Note (elisp)Low-Level Key Binding::.
+
+     This compatibility version allows for KEYMAP to be a list of
+     keymaps, instead of just a singular keymap.
+
+ -- Macro: compat-call setq-local &rest pairs
+     PAIRS is a list of variable and value pairs.  This macro creates a
+     buffer-local binding in the current buffer for each of the
+     variables, and gives them a buffer-local value.  It is equivalent
+     to calling ‘make-local-variable’ followed by ‘setq’ for each of the
+     variables.  The variables should be unquoted symbols.
+
+          (setq-local var1 "value1"
+                      var2 "value2")
+
+     *Note (elisp)Creating Buffer-Local::.
+
+     This compatibility version allows for more than one variable to be
+     set at once, as can be done with ‘setq’.
+
+ -- Function: compat-call regexp-opt strings &optional paren
+     This function returns an efficient regular expression that will
+     match any of the strings in the list STRINGS.  This is useful when
+     you need to make matching or searching as fast as possible—for
+     example, for Font Lock mode.
+
+     *Note (elisp)Regexp Functions::.
+
+     The compatibility version of this functions handles the case where
+     STRINGS in an empty list.  In that case, a regular expression is
+     generated that never matches anything (see ‘regexp-unmatchable’).
+
+ -- Function: compat-call file-size-human-readable file-size &optional
+          flavor space unit
+     Return a string with a human readable representation of FILE-SIZE.
+
+     The optional second argument FLAVOR controls the units and the
+     display format.  If FLAVOR is...
+
+        • ‘si’, each kilobyte is 1000 bytes and the produced suffixes
+          are ‘k’, ‘M’, ‘G’, ‘T’, etc.
+        • ‘iec’, each kilobyte is 1024 bytes and the produced suffixes
+          are ‘KiB’, ‘MiB’, ‘GiB’, ‘TiB’, etc.
+        • ‘nil’ or omitted, each kilobyte is 1024 bytes and the produced
+          suffixes are ‘k’, ‘M’, ‘G’, ‘T’, etc.
+
+     The compatibility version handles the optional third (SPACE) and
+     forth (UNIT) arguments.  The argument SPACE can be a string that is
+     placed between the number and the unit.  The argument UNIT
+     determines the unit to use.  By default it will be an empty string,
+     unless FLAVOR is ‘iec’, in which case it will be ‘B’.
+
+ -- Function: compat-call assoc-delete-all key alist &optional test
+     This function is like ‘assq-delete-all’ except that it accepts an
+     optional argument TEST, a predicate function to compare the keys in
+     ALIST.  If omitted or ‘nil’, TEST defaults to ‘equal’.  As
+     ‘assq-delete-all’, this function often modifies the original list
+     structure of ALIST.
+
+     *Note (elisp)Association Lists::.
+
+     This compatibility version handles the optional third (TESTFN)
+     argument.
+
+ -- Function: compat-call executable-find program &optional remote
+     This function searches for the executable file of the named PROGRAM
+     and returns the absolute file name of the executable, including its
+     file-name extensions, if any.  It returns ‘nil’ if the file is not
+     found.  The function searches in all the directories in
+     ‘exec-path’, and tries all the file-name extensions in
+     ‘exec-suffixes’ (*note (elisp)Subprocess Creation::).
+
+     If REMOTE is non-‘nil’, and ‘default-directory’ is a remote
+     directory, PROGRAM is searched on the respective remote host.
+
+     *Note (elisp)Locating Files::.
+
+     This compatibility version adds support to handle the optional
+     second (REMOTE) argument.
+
+2.3.3 Missing Definitions
+-------------------------
+
+Compat does not provide support for the following Lisp features
+implemented in 27.1:
+
+   • The functions ‘base64url-encode-*’.
+   • The function ‘decoded-time-add’.
+   • The function ‘decoded-time-set-defaults’.
+   • The function ‘time-convert’.
+   • The macro ‘benchmark-progn’.
+   • Support for ‘condition-case’ to handle t.
+   • The function ‘file-system-info’.
+   • The function ‘group-name’.
+   • The function ‘face-extend-p’ and ‘set-face-extend’.
+   • Additional ‘format-spec’ modifiers.
+   • Support for additional body forms for
+     ‘define-globalized-minor-mode’.
+   • The macro ‘with-connection-local-variables’ and related
+     functionality.
+   • The ‘iso8601’ library.
+   • The ‘exif’ library.
+   • The ‘image-converter’ library.
+
+\1f
+File: docXccUUB.info,  Node: Emacs 28.1,  Next: Emacs 29.1,  Prev: Emacs 27.1,  Up: Support
+
+2.4 Emacs 28.1
+==============
+
+2.4.1 Added Definitions
+-----------------------
+
+The following functions and macros are implemented in Emacs 28.1.  These
+functions are made available by Compat on Emacs versions older than
+28.1.
+
+   The ‘defcustom’ type ‘natnum’ introduced in Emacs 28.1 is made
+available by Compat.
+
+ -- Function: process-lines-ignore-status program &rest args
+     This function is just like ‘process-lines’, but does not signal an
+     error if PROGRAM exits with a non-zero exit status.
+
+ -- Function: process-lines-handling-status program status-handler &rest
+          args
+     Execute PROGRAM with ARGS, returning its output as a list of lines.
+     If STATUS-HANDLER is non-nil, it must be a function with one
+     argument, which will be called with the exit status of the program
+     before the output is collected.  If STATUS-HANDLER is nil, an error
+     is signaled if the program returns with a non-zero exit status.
+
+ -- Function: text-quoting-style
+     You should not read the value of the variable ‘text-quoting-style’
+     directly.  Instead, use this function with the same name to
+     dynamically compute the correct quoting style on the current
+     terminal in the ‘nil’ case described above.
+
+ -- Function: string-search needle haystack &optional start-pos
+     Return the position of the first instance of NEEDLE in HAYSTACK,
+     both of which are strings.  If START-POS is non-‘nil’, start
+     searching from that position in NEEDLE.  Return ‘nil’ if no match
+     was found.  This function only considers the characters in the
+     strings when doing the comparison; text properties are ignored.
+     Matching is always case-sensitive.
+
+ -- Function: length= sequence length
+     Return non-‘nil’ if the length of SEQUENCE is equal to LENGTH.
+
+ -- Function: length< sequence length
+     Return non-‘nil’ if SEQUENCE is shorter than LENGTH.  This may be
+     more efficient than computing the length of SEQUENCE if SEQUENCE is
+     a long list.
+
+ -- Function: length> sequence length
+     Return non-‘nil’ if SEQUENCE is longer than LENGTH.
+
+ -- Function: file-name-concat directory &rest components
+     Concatenate COMPONENTS to DIRECTORY, inserting a slash before the
+     components if DIRECTORY or the preceding component didn’t end with
+     a slash.
+
+          (file-name-concat "/tmp" "foo") ⇒ "/tmp/foo"
+
+     A DIRECTORY or components that are ‘nil’ or the empty string are
+     ignored—they are filtered out first and do not affect the results
+     in any way.
+
+     This is almost the same as using ‘concat’, but DIRNAME (and the
+     non-final components) may or may not end with slash characters, and
+     this function will not double those characters.
+
+ -- Function: garbage-collect-maybe factor
+     Suggest to run garbage collection, if _enough_ data has been
+     allocated.  This is determined by the positive numerical argument
+     FACTOR, that would proportionally increase the likelihood of
+     garbage collection taking place.
+
+     This compatibility function does nothing and ignores any
+     suggestion.
+
+ -- Function: string-replace from-string to-string in-string
+     This function replaces all occurrences of FROM-STRING with
+     TO-STRING in IN-STRING and returns the result.  It may return one
+     of its arguments unchanged, a constant string or a new string.
+     Case is significant, and text properties are ignored.
+
+ -- Function: always &rest arguments
+     This function ignores any ARGUMENTS and returns ‘t’.
+
+     *Note (elisp)Calling Functions::.
+
+ -- Function: make-separator-line &optional length
+     Make a string appropriate for usage as a visual separator line.  If
+     LENGTH is nil, use the window width.
+
+ -- Function: insert-into-buffer to-buffer &optional start end
+     This is like ‘insert-buffer-substring’, but works in the opposite
+     direction: The text is copied from the current buffer into
+     TO-BUFFER.  The block of text is copied to the current point in
+     TO-BUFFER, and point (in that buffer) is advanced to after the end
+     of the copied text.  Is ‘start’/‘end’ is ‘nil’, the entire text in
+     the current buffer is copied over.
+
+     *Note (elisp)Insertion::.
+
+ -- Function: replace-string-in-region regexp replacement &optional
+          start end
+     This function replaces all the occurrences of REGEXP with
+     REPLACEMENT in the region of buffer text between START and END;
+     START defaults to position of point, and END defaults to the last
+     accessible position of the buffer.  The search for REGEXP is
+     case-sensitive, and REPLACEMENT is inserted without changing its
+     letter-case.  The REPLACEMENT string can use the same special
+     elements starting with ‘\’ as ‘replace-match’ does.  The function
+     returns the number of replaced occurrences, or ‘nil’ if REGEXP is
+     not found.  The function preserves the position of point.
+
+          (replace-regexp-in-region "foo[ \t]+bar" "foobar")
+     *Note (elisp)Search and Replace::.
+
+ -- Function: replace-regexp-in-string string replacement &optional
+          start end
+     This function works similarly to ‘replace-regexp-in-region’, but
+     searches for, and replaces, literal STRINGs instead of regular
+     expressions.
+
+     *Note (elisp)Search and Replace::.
+
+ -- Function: buffer-local-boundp variable buffer
+     This returns non-‘nil’ if there’s either a buffer-local binding of
+     VARIABLE (a symbol) in buffer BUFFER, or VARIABLE has a global
+     binding.
+
+     *Note (elisp)Creating Buffer-Local::.
+
+ -- Macro: with-existing-directory body...
+     This macro ensures that ‘default-directory’ is bound to an existing
+     directory before executing BODY.  If ‘default-directory’ already
+     exists, that’s preferred, and otherwise some other directory is
+     used.  This macro can be useful, for instance, when calling an
+     external command that requires that it’s running in a directory
+     that exists.  The chosen directory is not guaranteed to be
+     writable.
+
+     *Note (elisp)Testing Accessibility::.
+
+ -- Macro: dlet (bindings...) forms...
+     This special form is like ‘let’, but it binds all variables
+     dynamically.  This is rarely useful—you usually want to bind normal
+     variables lexically, and special variables (i.e., variables that
+     are defined with ‘defvar’) dynamically, and this is what ‘let’
+     does.
+
+     ‘dlet’ can be useful when interfacing with old code that assumes
+     that certain variables are dynamically bound (*note (elisp)Dynamic
+     Binding::), but it’s impractical to ‘defvar’ these variables.
+     ‘dlet’ will temporarily make the bound variables special, execute
+     the forms, and then make the variables non-special again.
+
+     *Note (elisp)Local Variables::.
+
+ -- Function: ensure-list object
+     This function returns OBJECT as a list.  If OBJECT is already a
+     list, the function returns it; otherwise, the function returns a
+     one-element list containing OBJECT.
+
+     This is usually useful if you have a variable that may or may not
+     be a list, and you can then say, for instance:
+
+          (dolist (elem (ensure-list foo))
+            (princ elem))
+
+     *Note (elisp)Building Lists::.
+
+ -- Function: string-clean-whitespace string
+     Clean up the whitespace in STRING by collapsing stretches of
+     whitespace to a single space character, as well as removing all
+     whitespace from the start and the end of STRING.
+
+     *Note (elisp)Creating Strings::.
+
+ -- Function: string-fill string length
+     Attempt to Word-wrap STRING so that no lines are longer than
+     LENGTH.  Filling is done on whitespace boundaries only.  If there
+     are individual words that are longer than LENGTH, these will not be
+     shortened.
+
+     *Note (elisp)Creating Strings::.
+
+ -- Function: string-lines string &optional omit-nulls
+     Split STRING into a list of strings on newline boundaries.  If the
+     optional argument OMIT-NULLS is non-‘nil’, remove empty lines from
+     the results.  Note that this function returns trailing newlines on
+     Emacs 28, use ‘compat-call string-lines’ instead if you want
+     consistent behavior.
+
+ -- Function: string-pad string length &optional padding start
+     Pad STRING to be of the given LENGTH using PADDING as the padding
+     character.  PADDING defaults to the space character.  If STRING is
+     longer than LENGTH, no padding is done.  If START is ‘nil’ or
+     omitted, the padding is appended to the characters of STRING, and
+     if it’s non-‘nil’, the padding is prepended to STRING’s characters.
+
+     *Note (elisp)Creating Strings::.
+
+ -- Function: string-chop-newline string
+     Remove the final newline, if any, from STRING.
+
+     *Note (elisp)Creating Strings::.
+
+ -- Macro: named-let name bindings &rest body
+     This special form is a looping construct inspired from the Scheme
+     language.  It is similar to ‘let’: It binds the variables in
+     BINDINGS, and then evaluates BODY.  However, ‘named-let’ also binds
+     NAME to a local function whose formal arguments are the variables
+     in BINDINGS and whose body is BODY.  This allows BODY to call
+     itself recursively by calling NAME, where the arguments passed to
+     NAME are used as the new values of the bound variables in the
+     recursive invocation.
+
+     Recursive calls to NAME that occur in _tail positions_ in BODY are
+     guaranteed to be optimized as _tail calls_, which means that they
+     will not consume any additional stack space no matter how deeply
+     the recursion runs.  Such recursive calls will effectively jump to
+     the top of the loop with new values for the variables.
+
+     *Note (elisp)Local Variables::.
+
+ -- Function: file-name-with-extension filename extension
+     This function returns FILENAME with its extension set to EXTENSION.
+     A single leading dot in the EXTENSION will be stripped if there is
+     one.  For example:
+
+          (file-name-with-extension "file" "el")
+               ⇒ "file.el"
+          (file-name-with-extension "file" ".el")
+               ⇒ "file.el"
+          (file-name-with-extension "file.c" "el")
+               ⇒ "file.el"
+
+     Note that this function will error if FILENAME or EXTENSION are
+     empty, or if the FILENAME is shaped like a directory (i.e., if
+     ‘directory-name-p’ returns non-‘nil’).
+
+     *Note File Name Components: (elisp)File Name Components.
+
+ -- Function: directory-empty-p directory
+     This utility function returns ‘t’ if given DIRECTORY is an
+     accessible directory and it does not contain any files, i.e., is an
+     empty directory.  It will ignore ‘.’ and ‘..’ on systems that
+     return them as files in a directory.
+
+     Symbolic links to directories count as directories.  See
+     FILE-SYMLINK-P to distinguish symlinks.
+
+     *Note (elisp)Contents of Directories::.
+
+ -- Function: format-prompt prompt default &rest format-args
+     Format PROMPT with default value DEFAULT according to the
+     ‘minibuffer-default-prompt-format’ variable.
+
+     ‘minibuffer-default-prompt-format’ is a format string (defaulting
+     to ‘" (default %s)"’ that says how the “default” bit in prompts
+     like ‘"Local filename (default somefile): "’ are to be formatted.
+
+     To allow the users to customize how this is displayed, code that
+     prompts the user for a value (and has a default) should look
+     something along the lines of this code snippet:
+
+          (read-file-name
+           (format-prompt "Local filename" file)
+           nil file)
+
+     If FORMAT-ARGS is ‘nil’, PROMPT is used as a literal string.  If
+     FORMAT-ARGS is non-‘nil’, PROMPT is used as a format control
+     string, and PROMPT and FORMAT-ARGS are passed to ‘format’ (*note
+     (elisp)Formatting Strings::).
+
+     ‘minibuffer-default-prompt-format’ can be ‘""’, in which case no
+     default values are displayed.
+
+     If DEFAULT is ‘nil’, there is no default value, and therefore no
+     “default value” string is included in the result value.  If DEFAULT
+     is a non-‘nil’ list, the first element of the list is used in the
+     prompt.
+
+     *Note (elisp)Text from Minibuffer::.
+
+ -- Function: thing-at-mouse event thing &optional no-properties
+     Mouse-EVENT equivalent of ‘thing-at-point’.  THING can be ‘symbol’,
+     ‘list’, ‘sexp’, ‘filename’, ‘url’, ... among other things.
+
+     When NO-PROPERTIES has a non-‘nil’ value, any text properties that
+     might have been present in the buffer are stripped away.
+
+ -- Function: bounds-of-thing-at-mouse event thing
+     Determine start and end locations for THING at mouse click given by
+     EVENT.  Like ‘bounds-of-thing-at-point’, but tries to use the
+     position in EVENT where the mouse button is clicked to find the
+     thing nearby.
+
+ -- Function: mark-thing-at-mouse click thing
+     Activate the region around THING found near the mouse CLICK.
+
+ -- Function: macroexp-file-name
+     Return the name of the file in which the code is currently being
+     evaluated, or ‘nil’ if it cannot be determined.
+
+ -- Function: macroexp-warn-and-return msg form &optional category
+          compile-only arg
+     Return code equivalent to ‘form’ labeled with warning ‘msg’.
+
+ -- Macro: with-environment-variables variables body...
+     This macro sets the environment variables according to VARIABLES
+     temporarily when executing BODY.  The previous values are restored
+     when the form finishes.  The argument VARIABLES should be a list of
+     pairs of strings of the form ‘(VAR VALUE)’, where VAR is the name
+     of the environment variable and VALUE is that variable’s value.
+
+          (with-environment-variables (("LANG" "C")
+                                       ("LANGUAGE" "en_US:en"))
+            (call-process "ls" nil t))
+
+     *Note System Environment: (elisp)System Environment.
+
+ -- Function: color-dark-p rgb
+     Whether RGB is more readable against white than black.  RGB is a
+     3-element list (R G B), each component in the range [0,1].  This
+     predicate can be used both for determining a suitable (black or
+     white) contrast color with RGB as background and as foreground.
+
+ -- Function: color-values-from-color-spec spec
+     Convert the textual color specification SPEC to a color triple
+     ‘(RED GREEN blue)’.  Each of RED, GREEN and ‘blue’ is a integer
+     value between 0 and 65535.
+
+     The specification SPEC can be one of the following
+        • ‘#RGB’, where R, G and B are hex numbers of equal length, 1-4
+          digits each.
+        • ‘rgb:R/G/B’, where R, G, and B are hex numbers, 1-4 digits
+          each.
+        • ‘rgbi:R/G/B’, where R, G and B are floating-point numbers in
+          [0,1].
+
+ -- Function: file-modes-number-to-symbolic modes
+     This function converts a numeric file mode specification in MODES
+     into the equivalent symbolic form.
+
+     *Note Changing Files: (elisp)Changing Files.
+
+ -- Function: file-backup-file-names filename
+     This function returns a list of all the backup file names for
+     FILENAME, or ‘nil’ if there are none.  The files are sorted by
+     modification time, descending, so that the most recent files are
+     first.
+
+     *Note (elisp)Backup Names::.
+
+ -- Function: make-lock-file-name filename
+     Return a string containing a lock file name for FILENAME, obeying
+     ‘lock-file-name-transforms’.
+
+ -- Function: decoded-time-period time
+     Interpret TIME as a period and return its length in seconds.  For
+     computational purposes, years are 365 days long and months are 30
+     days long.
+
+ -- Function: subr-primitive-p object
+     Return ‘t’ if OBJECT is a primitive, built-in function.  On systems
+     with native compilation ‘subrp’ does not distinguish between
+     built-in functions and functions that have been compiled.  If
+     native compilation is not available, this function behaves
+     identically to ‘subrp’.
+
+ -- Function: subr-native-elisp-p object
+     Return ‘t’ if OBJECT if the object is native compiled lisp.  If
+     native compilation is not available, this function always returns
+     ‘nil’.
+
+ -- Function: native-comp-available-p
+     This function returns non-‘nil’ if the running Emacs process has
+     the native-compilation support compiled into it.  On systems that
+     load ‘libgccjit’ dynamically, it also makes sure that library is
+     available and can be loaded.  Lisp programs that need to know up
+     front whether native-compilation is available should use this
+     predicate.
+
+ -- Macro: with-window-non-dedicated window &rest body
+     Evaluate BODY with WINDOW temporarily made non-dedicated.  If
+     WINDOW is nil, use the selected window.  Return the value of the
+     last form in BODY.
+
+2.4.2 Extended Definitions
+--------------------------
+
+These functions must be called explicitly via ‘compat-call’, since their
+calling convention or behavior was extended in Emacs 28.1:
+
+ -- Function: compat-call string-width string &optional from to
+     This function returns the width in columns of the string STRING, if
+     it were displayed in the current buffer and the selected window.
+     Optional arguments FROM and TO specify the substring of STRING to
+     consider, and are interpreted as in ‘substring’ (*note
+     (elisp)Creating Strings::).
+
+     The return value is an approximation: it only considers the values
+     returned by ‘char-width’ for the constituent characters, always
+     takes a tab character as taking ‘tab-width’ columns, ignores
+     display properties and fonts, etc.
+
+     *Note (elisp)Size of Displayed Text::.
+
+     This compatibility version handles the optional arguments FROM and
+     TO.
+
+ -- Function: compat-call count-windows
+     Return the number of live windows on the selected frame.
+
+     The optional argument MINIBUF specifies whether the minibuffer
+     window is included in the count.
+
+     If ALL-FRAMES is non-‘nil’, count the windows in all frames instead
+     just the selected frame.
+
+     This compatibility version handles the optional argument
+     ALL-FRAMES.
+
+2.4.3 Missing Definitions
+-------------------------
+
+Compat does not provide support for the following Lisp features
+implemented in 28.1:
+
+   • Support for ‘interactive’ or ‘declare’ to list applicable modes.
+   • Support for ‘:interactive’ argument to ‘define-minor-mode’ and
+     ‘define-derived-mode’.
+   • Support for ‘:predicate’ argument to
+     ‘define-globalized-minor-mode’.
+   • Support for the ‘:success’ handler of ‘condition-case’.
+   • The function ‘benchmark-call’.
+   • Additional Edebug keywords.
+   • The libjansson JSON APIs, e.g., ‘json-parse-string’.
+   • The macro ‘pcase-setq’.
+   • The function ‘custom-add-choice’.
+   • The functions ‘dom-print’ and ‘dom-remove-attribute’.
+   • The function ‘dns-query-asynchronous’.
+   • The function ‘get-locale-names’.
+   • The functions ‘mail-header-parse-addresses-lax’ and
+     ‘mail-header-parse-address-lax’.
+   • The function ‘num-processors’.
+   • The function ‘object-intervals’.
+   • The function ‘require-theme’.
+   • The function ‘syntax-class-to-char’.
+   • The function ‘path-separator’.
+   • The function ‘null-device’.
+   • The function ‘macroexp-compiling-p’.
+   • The function ‘split-string-shell-command’.
+   • The function ‘string-limit’.
+   • The functions ‘innermost-minibuffer-p’ and
+     ‘minibuffer-innermost-command-loop-p’.
+   • The function ‘max-mini-window-lines’.
+   • The function ‘lock-file’ and ‘unlock-file’.
+   • The ‘multisession’ library.
+
+\1f
+File: docXccUUB.info,  Node: Emacs 29.1,  Prev: Emacs 28.1,  Up: Support
+
+2.5 Emacs 29.1
+==============
+
+2.5.1 Added Definitions
+-----------------------
+
+The following functions and macros are implemented in Emacs 29.1.  These
+functions are made available by Compat on Emacs versions older than
+29.1.  Note that due to upstream changes, it might happen that there
+will be the need for changes, so use these functions with care.
+
+   The ‘defcustom’ type ‘key’ introduced in Emacs 29.1 is made available
+by Compat.
+
+ -- Variable: lisp-directory
+     This variable holds a string naming the directory which holds
+     Emacs’s own ‘*.el’ and ‘*.elc’ files.  This is usually the place
+     where those files are located in the Emacs installation tree,
+     unless Emacs is run from its build directory in which case it
+     points to the ‘lisp’ subdirectory in the source directory from
+     which Emacs was built.
+
+ -- Function: count-sentences start end
+     Count sentences in current buffer from START to END.
+
+ -- Function: readablep object
+     This predicate says whether OBJECT has “readable syntax”, i.e., it
+     can be written out and then read back by the Emacs Lisp reader.  If
+     it can’t, this function returns ‘nil’; if it can, this function
+     returns a printed representation (via ‘prin1’).
+
+ -- Function: substitute-quotes string
+     This function works like ‘substitute-command-keys’, but only
+     replaces quote characters.
+
+ -- Function: get-scratch-buffer-create
+     Return the *scratch* buffer, creating a new one if needed.
+
+ -- Function: use-region-noncontiguous-p
+     Return non-nil for a non-contiguous region if ‘use-region-p’.
+
+ -- Function: use-region-end
+     Return the end of the region if ‘use-region-p’.
+
+ -- Function: use-region-beginning
+     Return the start of the region if ‘use-region-p’.
+
+ -- Macro: buffer-local-set-state variable value...
+     Minor modes often set buffer-local variables that affect some
+     features in Emacs.  When a minor mode is switched off, the mode is
+     expected to restore the previous state of these variables.  This
+     convenience macro helps with doing that: It works much like
+     ‘setq-local’, but returns an object that can be used to restore
+     these values back to their previous values/states (using the
+     companion function ‘buffer-local-restore-state’).
+
+ -- Function: delete-line
+     Delete the current line.
+
+ -- Function: list-of-strings-p object
+     Return ‘t’ if OBJECT is ‘nil’ or a list of strings.
+
+ -- Function: plistp object
+     Non-nil if and only if OBJECT is a valid plist.
+
+ -- Macro: with-memoization PLACE CODE...
+     This macro provides a simple way to do memoization.  CODE is
+     evaluated and then stashed in PLACE.  If PLACE’s value is
+     non-‘nil’, return that value instead of evaluating CODE.
+
+ -- Special Form: with-restriction start end [:label label] body
+     This special form saves the current bounds of the accessible
+     portion of the buffer, sets the accessible portion to start at
+     START and end at END, evaluates the BODY forms, and restores the
+     saved bounds.  In that case it is equivalent to
+
+          (save-restriction
+            (narrow-to-region start end)
+            body)
+
+     When the optional argument LABEL, a symbol, is present, the
+     narrowing is “labeled”.  A labeled narrowing differs from a
+     non-labeled one in several ways:
+
+        • During the evaluation of the BODY form, ‘narrow-to-region’ and
+          ‘widen’ can be used only within the START and END limits.
+
+        • To lift the restriction introduced by ‘with-restriction’ and
+          gain access to other portions of the buffer, use
+          ‘without-restriction’ with the same LABEL argument.  (Another
+          way to gain access to other portions of the buffer is to use
+          an indirect buffer (*note (elisp)Indirect Buffers::).)
+
+        • Labeled narrowings can be nested.
+
+        • Labeled narrowings can only be used in Lisp programs: they are
+          never visible on display, and never interfere with narrowings
+          set by the user.
+
+     If you use ‘with-restriction’ with the optional LABEL argument, we
+     recommend documenting the LABEL in the doc strings of the functions
+     which use it, so that other Lisp programs your code calls could
+     lift the labeled narrowing if and when it needs.
+
+ -- Special Form: without-restriction [:label label] body
+     This special form saves the current bounds of the accessible
+     portion of the buffer, widens the buffer, evaluates the BODY forms,
+     and restores the saved bounds.  In that case it is equivalent to
+
+          (save-restriction
+            (widen)
+            body)
+
+     When the optional argument LABEL is present, the narrowing set by
+     ‘with-restriction’ with the same LABEL argument is lifted.
+
+ -- Function: pos-bol &optional count
+     Like ‘line-beginning-position’, but ignores fields (and is more
+     efficient).
+
+ -- Function: pos-eol &optional count
+     Like ‘line-end-position’, but ignores fields (and is more
+     efficient).
+
+ -- Function: char-uppercase-p char
+     Return non-‘nil’ if CHAR is an uppercase character according to
+     Unicode.
+
+ -- Macro: with-delayed-message (timeout message) body...
+     Sometimes it’s unclear whether an operation will take a long time
+     to execute or not, or it can be inconvenient to implement a
+     progress reporter.  This macro can be used in those situations.
+
+          (with-delayed-message (2 (format "Gathering data for %s" entry))
+            (setq data (gather-data entry)))
+
+     In this example, if the body takes more than two seconds to
+     execute, the message will be displayed.  If it takes a shorter time
+     than that, the message won’t be displayed.  In either case, the
+     body is evaluated as normally, and the return value of the final
+     element in the body is the return value of the macro.
+
+     The MESSAGE element is evaluated before BODY, and is always
+     evaluated, whether the message is displayed or not.
+
+ -- Function: funcall-with-delayed-message timeout message function
+     Like ‘funcall’, but display MESSAGE if FUNCTION takes longer than
+     TIMEOUT.  TIMEOUT is a number of seconds, and can be an integer or
+     a floating point number.
+
+     If FUNCTION takes less time to execute than TIMEOUT seconds,
+     MESSAGE is not displayed.
+
+ -- Function: buttonize string callback &optional data help-echo
+     Sometimes it’s more convenient to make a string into a button
+     without inserting it into a buffer immediately, for instance when
+     creating data structures that may then, later, be inserted into a
+     buffer.  This function makes STRING into such a string, and
+     CALLBACK will be called when the user clicks on the button.  The
+     optional DATA parameter will be used as the parameter when CALLBACK
+     is called.  If ‘nil’, the button is used as the parameter instead.
+
+ -- Function: buttonize-region start end callback &optional data
+          help-echo
+     Make the region between START and END into a button.  When clicked,
+     CALLBACK will be called with the DATA as the function argument.  If
+     DATA isn’t present (or is nil), the button itself will be used
+     instead as the function argument.  If HELP-ECHO, use that as the
+     help-echo property.
+
+ -- Function: get-display-property position prop &optional object
+          properties
+     This convenience function can be used to get a specific display
+     property, no matter whether the ‘display’ property is a vector, a
+     list or a simple property.  This is like ‘get-text-property’ (*note
+     Examining Properties: (elisp)Examining Properties.), but works on
+     the ‘display’ property only.
+
+     POSITION is the position in the buffer or string to examine, and
+     PROP is the ‘display’ property to return.  The optional OBJECT
+     argument should be either a string or a buffer, and defaults to the
+     current buffer.  If the optional PROPERTIES argument is non-‘nil’,
+     it should be a ‘display’ property, and in that case, POSITION and
+     OBJECT are ignored.  (This can be useful if you’ve already gotten
+     the ‘display’ property with ‘get-char-property’, for instance
+     (*note Examining Properties: (elisp)Examining Properties.).
+
+ -- Function: add-display-text-property start end prop value &optional
+          object
+     Add display property PROP with VALUE to the text from START to END.
+     If any text in the region has a non-nil ‘display’ property, those
+     properties are retained.
+
+     If OBJECT is non-‘nil’, it should be a string or a buffer.  If
+     ‘nil’, this defaults to the current buffer.
+
+ -- Function: take n list
+     This function returns the N first elements of LIST.  Essentially,
+     it returns the part of LIST that ‘nthcdr’ skips.
+
+     ‘take’ returns LIST if shorter than N elements; it returns ‘nil’ if
+     N is zero or negative.
+
+          (take 3 '(a b c d))
+               ⇒ (a b c)
+          (take 10 '(a b c d))
+               ⇒ (a b c d)
+          (take 0 '(a b c d))
+               ⇒ nil
+
+ -- Function: ntake n list
+     This is a version of ‘take’ that works by destructively modifying
+     the list structure of the argument.  That makes it faster, but the
+     original value of LIST may be lost.
+
+     ‘ntake’ returns LIST unmodified if shorter than N elements; it
+     returns ‘nil’ if N is zero or negative.  Otherwise, it returns LIST
+     truncated to its first N elements.
+
+     This means that it is usually a good idea to use the return value
+     and not just rely on the truncation effect unless N is known to be
+     positive.
+
+ -- Function: compiled-function-p object
+     This function returns ‘t’ if OBJECT is a function object that is
+     not in the form of ELisp source code but something like machine
+     code or byte code instead.  More specifically it returns ‘t’ if the
+     function is built-in, or byte-compiled, or natively-compiled, or a
+     function loaded from a dynamic module.
+
+ -- Function: function-alias-p object &optional noerror
+     Checks whether OBJECT is a function alias.  If it is, it returns a
+     list of symbols representing the function alias chain, else ‘nil’.
+     For instance, if ‘a’ is an alias for ‘b’, and ‘b’ is an alias for
+     ‘c’:
+
+          (function-alias-p 'a)
+              ⇒ (b c)
+
+     If there’s a loop in the definitions, an error will be signalled.
+     If NOERROR is non-‘nil’, the non-looping parts of the chain is
+     returned instead.
+
+ -- Function: string-equal-ignore-case string1 string2
+     ‘string-equal-ignore-case’ compares strings ignoring case
+     differences, like ‘char-equal’ when ‘case-fold-search’ is ‘t’.
+
+     *Note (elisp)Text Comparison::.
+
+ -- Function: string-split string &optional separators omit-nulls trim
+     ‘string-split’ is an alias for the function ‘split-string’.  The
+     name follows the convention of other string functions.
+
+     *Note (elisp)Creating Strings::.
+
+ -- Function: buffer-match-p condition buffer-or-name &optional arg
+     This function checks if a buffer designated by ‘buffer-or-name’
+     satisfies a ‘condition’.  Optional third argument ARG is passed to
+     the predicate function in CONDITION.  A condition can be one of the
+     following:
+        • A string, interpreted as a regular expression.  The buffer
+          satisfies the condition if the regular expression matches the
+          buffer name.
+        • A predicate function, which should return non-‘nil’ if the
+          buffer matches.  If the function expects one argument, it is
+          called with BUFFER-OR-NAME as the argument; if it expects 2
+          arguments, the first argument is BUFFER-OR-NAME and the second
+          is ARG (or ‘nil’ if ARG is omitted).
+        • A cons-cell ‘(OPER . EXPR)’ where OPER is one of
+          ‘not’
+               Satisfied if EXPR doesn’t satisfy ‘buffer-match-p’ with
+               the same buffer and ‘arg’.
+          ‘or’
+               Satisfied if EXPR is a list and _any_ condition in EXPR
+               satisfies ‘buffer-match-p’, with the same buffer and
+               ‘arg’.
+          ‘and’
+               Satisfied if EXPR is a list and _all_ conditions in EXPR
+               satisfy ‘buffer-match-p’, with the same buffer and ‘arg’.
+          ‘derived-mode’
+               Satisfied if the buffer’s major mode derives from EXPR.
+          ‘major-mode’
+               Satisfied if the buffer’s major mode is equal to EXPR.
+               Prefer using ‘derived-mode’ instead when both can work.
+        • t Satisfied by any buffer.  A convenient alternative to ‘""’
+          (empty string), ‘(and)’ (empty conjunction) or ‘always’.
+
+     *Note (elisp)Buffer List::.
+
+ -- Function: match-buffers condition &optional buffers arg
+     This function returns a list of all buffers that satisfy a
+     ‘condition’, as defined for ‘buffer-match-p’.  By default all
+     buffers are considered, but this can be restricted via the second
+     optional ‘buffer-list’ argument.  Optional third argument ARG will
+     be used by CONDITION in the same way as ‘buffer-match-p’ does.
+
+     *Note (elisp)Buffer List::.
+
+ -- Function: string-glyph-split string
+     When character compositions are in effect, sequence of characters
+     can be composed for display to form _grapheme clusters_, for
+     example to display accented characters, or ligatures, or Emoji, or
+     when complex text shaping requires that for some scripts.  When
+     that happens, characters no longer map in a simple way to display
+     columns, and display layout decisions with such strings, such as
+     truncating too wide strings, can be a complex job.  This function
+     helps in performing such jobs: it splits up its argument STRING
+     into a list of substrings, where each substring produces a single
+     grapheme cluster that should be displayed as a unit.  Lisp programs
+     can then use this list to construct visually-valid substrings of
+     STRING which will look correctly on display, or compute the width
+     of any substring of STRING by adding the width of its constituents
+     in the returned list, etc.
+
+     For instance, if you want to display a string without the first
+     glyph, you can say:
+
+          (apply #'insert (cdr (string-glyph-split string))))
+
+     *Note (elisp)Size of Displayed Text::.
+
+ -- Macro: with-buffer-unmodified-if-unchanged &rest body...
+     Evaluate BODY like ‘progn’, but change buffer-modified status only
+     if buffer text changes.  If the buffer was unmodified before
+     execution of BODY, and buffer text after execution of BODY is
+     identical to what it was before, ensure that buffer is still marked
+     unmodified afterwards.
+
+     Note that only changes in the raw byte sequence of the buffer text,
+     as stored in the internal representation, are monitored for the
+     purpose of detecting the lack of changes in buffer text.  Any other
+     changes that are normally perceived as "buffer modifications", such
+     as changes in text properties, ‘buffer-file-coding-system’, buffer
+     multibyteness, etc.  – will not be noticed, and the buffer will
+     still be marked unmodified, effectively ignoring those changes.
+
+ -- Function: file-attribute-file-identifier
+     Return the fields ‘(inodenum device)’ as a list from attributes
+     generated by ‘file-attributes’.
+
+     *Note (elisp)File Attributes::.
+
+ -- Function: file-name-split filename
+     This function splits a file name into its components, and can be
+     thought of as the inverse of ‘string-join’ with the appropriate
+     directory separator.  For example,
+
+          (file-name-split "/tmp/foo.txt")
+              ⇒ ("" "tmp" "foo.txt")
+          (string-join (file-name-split "/tmp/foo.txt") "/")
+              ⇒ "/tmp/foo.txt"
+
+ -- Function: file-name-parent-directory filename
+     This function returns the directory name of the parent directory of
+     FILENAME.  If FILENAME is at the root directory of the filesystem,
+     it returns ‘nil’.  A relative FILENAME is assumed to be relative to
+     ‘default-directory’, and the return value will also be relative in
+     that case.  If the return value is non-‘nil’, it ends in a slash.
+
+     *Note (elisp)Directory Names::.
+
+ -- Function: file-has-changed-p file &optional tag
+     This function returns non-‘nil’ if the time stamp of FILENAME has
+     changed since the last call.  When called for the first time for
+     some FILENAME, it records the last modification time and size of
+     the file, and returns non-‘nil’ when FILENAME exists.  Thereafter,
+     when called for the same FILENAME, it compares the current time
+     stamp and size with the recorded ones, and returns non-‘nil’ only
+     if either the time stamp or the size (or both) are different.  This
+     is useful when a Lisp program wants to re-read a file whenever it
+     changes.  With an optional argument TAG, which must be a symbol,
+     the size and modification time comparisons are limited to calls
+     with the same tag.
+
+     *Note (elisp)File Attributes::.
+
+ -- Function: directory-abbrev-make-regexp directory
+     Create a regexp to match DIRECTORY for ‘directory-abbrev-alist’.
+
+ -- Function: directory-abbrev-apply filename
+     Apply the abbreviations in ‘directory-abbrev-alist’ to FILENAME.
+     Note that when calling this, you should set ‘case-fold-search’ as
+     appropriate for the filesystem used for FILENAME.
+
+ -- Function: key-valid-p keys
+     Say whether KEYS is a valid key.  A key is a string consisting of
+     one or more key strokes.  The key strokes are separated by single
+     space characters.
+
+     Each key stroke is either a single character, or the name of an
+     event, surrounded by angle brackets.  In addition, any key stroke
+     may be preceded by one or more modifier keys.  Finally, a limited
+     number of characters have a special shorthand syntax.
+
+     Here’s some example key sequences.
+
+     ‘f’
+          The key ‘f’.
+     ‘S o m’
+          A three key sequence of the keys ‘S’, ‘o’ and ‘m’.
+     ‘C-c o’
+          A two key sequence of the keys ‘c’ with the control modifier
+          and then the key ‘o’.
+     ‘H-<left>’
+          The key named "left" with the hyper modifier.
+     ‘M-RET’
+          The "return" key with a meta modifier.
+     ‘C-M-<space>’
+          The "space" key with both the control and meta modifiers.
+
+     These are the characters that have shorthand syntax: ‘NUL’, ‘RET’,
+     ‘TAB’, ‘LFD’, ‘ESC’, ‘SPC’, ‘DEL’.
+
+     Modifiers have to be specified in this order
+     Alt (A)-Control (C)-Hyper (H)-Meta (M)-Shift (s)-Super (s)
+
+ -- Function: key-parse keys
+     Convert KEYS to the internal Emacs key representation.  See
+     ‘key-valid-p’ for a description of valid key sequences.  Examples
+     include ‘f’, ‘C-c C-c’, ‘H-<left>’, ‘M-RET’ or ‘C-M-<return>’.
+
+ -- Function: keymap-set keymap key definition
+     This function sets the binding for KEY in KEYMAP.  (If KEY is more
+     than one event long, the change is actually made in another keymap
+     reached from KEYMAP.)  The argument BINDING can be any Lisp object,
+     but only certain types are meaningful.  (For a list of meaningful
+     types, see *note (elisp)Key Lookup::.)  The value returned by
+     ‘keymap-set’ is BINDING.
+
+     If KEY is ‘<t>’, this sets the default binding in KEYMAP.  When an
+     event has no binding of its own, the Emacs command loop uses the
+     keymap’s default binding, if there is one.
+
+     Every prefix of KEY must be a prefix key (i.e., bound to a keymap)
+     or undefined; otherwise an error is signaled.  If some prefix of
+     KEY is undefined, then ‘keymap-set’ defines it as a prefix key so
+     that the rest of KEY can be defined as specified.
+
+     If there was previously no binding for KEY in KEYMAP, the new
+     binding is added at the beginning of KEYMAP.  The order of bindings
+     in a keymap makes no difference for keyboard input, but it does
+     matter for menu keymaps (*note (elisp)Menu Keymaps::).
+
+     *Note (elisp)Changing Key Bindings::.
+
+ -- Function: keymap-global-set key command
+     This function sets the binding of KEY in the current global map to
+     BINDING.
+
+          (keymap-global-set KEY BINDING)
+          ≡
+          (keymap-set (current-global-map) KEY BINDING)
+
+     *Note (elisp)Key Binding Commands::.
+
+ -- Function: keymap-local-set key command
+     This function sets the binding of KEY in the current local keymap
+     to BINDING.
+
+          (keymap-local-set KEY BINDING)
+          ≡
+          (keymap-set (current-local-map) KEY BINDING)
+
+     *Note (elisp)Key Binding Commands::.
+
+ -- Function: keymap-global-unset key &optional remove
+     This function removes the binding of KEY from the current global
+     map.
+
+     One use of this function is in preparation for defining a longer
+     key that uses KEY as a prefix—which would not be allowed if KEY has
+     a non-prefix binding.  For example:
+
+          (keymap-global-unset "C-l")
+              ⇒ nil
+          (keymap-global-set "C-l C-l" 'redraw-display)
+              ⇒ nil
+
+     *Note (elisp)Key Binding Commands::.
+
+ -- Function: keymap-local-unset key &optional remove
+     This function removes the binding of KEY from the current local
+     map.
+
+     *Note (elisp)Key Binding Commands::.
+
+ -- Function: keymap-substitute keymap olddef newdef &optional oldmap
+          prefix
+     Replace OLDDEF with NEWDEF for any keys in KEYMAP now defined as
+     OLDDEF.  In other words, OLDDEF is replaced with NEWDEF wherever it
+     appears.  Alternatively, if optional fourth argument OLDMAP is
+     specified, we redefine in KEYMAP as NEWDEF those keys that are
+     defined as OLDDEF in OLDMAP.
+
+ -- Function: keymap-lookup keymap key &optional accept-default no-remap
+          position
+     This function returns the definition of KEY in KEYMAP.  All the
+     other functions described in this chapter that look up keys use
+     ‘keymap-lookup’.  Here are examples:
+
+          (keymap-lookup (current-global-map) "C-x C-f")
+              ⇒ find-file
+          (keymap-lookup (current-global-map) "C-x C-f 1 2 3 4 5")
+              ⇒ 2
+
+     *Note (elisp)Functions for Key Lookup::.
+
+ -- Function: keymap-local-lookup keys &optional accept-default
+     Like ‘keymap-lookup’, but restricting the search for commands bound
+     to KEYS to the current local keymap.
+
+ -- Function: keymap-global-lookup keys &optional accept-default
+     Like ‘keymap-lookup’, but restricting the search for commands bound
+     to KEYS to the current global keymap.
+
+ -- Function: define-keymap &rest definitions
+     You can create a keymap with the functions described above, and
+     then use ‘keymap-set’ (*note (elisp)Changing Key Bindings::) to
+     specify key bindings in that map.  When writing modes, however, you
+     frequently have to bind a large number of keys at once, and using
+     ‘keymap-set’ on them all can be tedious and error-prone.  Instead
+     you can use ‘define-keymap’, which creates a keymap and binds a
+     number of keys.  Here’s a very basic example:
+
+          (define-keymap
+            "n" #'forward-line
+            "f" #'previous-line
+            "C-c C-c" #'quit-window)
+
+     This function creates a new sparse keymap, defines the keystrokes
+     in PAIRS, and returns the new keymap.
+
+     PAIRS is a list of alternating key bindings and key definitions, as
+     accepted by ‘keymap-set’.  In addition, the key can be the special
+     symbol ‘:menu’, in which case the definition should be a menu
+     definition as accepted by ‘easy-menu-define’ (*note (elisp)Easy
+     Menu::).  Here’s a brief example of this usage:
+
+          (define-keymap :full t
+            "g" #'eww-reload
+            :menu '("Eww"
+                    ["Exit" quit-window t]
+                    ["Reload" eww-reload t]))
+
+     A number of keywords can be used before the key/definition pairs to
+     change features of the new keymap.  If any of the feature keywords
+     is missing from the ‘define-keymap’ call, the default value for
+     that feature is ‘nil’.  Here’s a list of the available feature
+     keywords:
+
+     ‘:full’
+          If non-‘nil’, create a char-table keymap (as from
+          ‘make-keymap’) instead of a sparse keymap (as from
+          ‘make-sparse-keymap’ (*note (elisp)Creating Keymaps::).  A
+          sparse keymap is the default.
+
+     ‘:parent’
+          If non-‘nil’, the value should be a keymap to use as the
+          parent (*note (elisp)Inheritance and Keymaps::).
+
+     ‘:keymap’
+          If non-‘nil’, the value should be a keymap.  Instead of
+          creating a new keymap, the specified keymap is modified
+          instead.
+
+     ‘:suppress’
+          If non-‘nil’, the keymap will be suppressed with
+          ‘suppress-keymap’ (*note (elisp)Changing Key Bindings::).  By
+          default, digits and the minus sign are exempt from
+          suppressing, but if the value is ‘nodigits’, this suppresses
+          digits and minus-sign like it does with other characters.
+
+     ‘:name’
+          If non-‘nil’, the value should be a string to use as the menu
+          for the keymap if you use it as a menu with ‘x-popup-menu’
+          (*note (elisp)Pop-Up Menus::).
+
+     ‘:prefix’
+          If non-‘nil’, the value should be a symbol to be used as a
+          prefix command (*note (elisp)Prefix Keys::).  If this is the
+          case, this symbol is returned by ‘define-keymap’ instead of
+          the map itself.
+
+ -- Function: defvar-keymap (variable-name &rest defs)
+     By far, the most common thing to do with a keymap is to bind it to
+     a variable.  This is what virtually all modes do—a mode called
+     ‘foo’ almost always has a variable called ‘foo-mode-map’.
+
+     This macro defines NAME as a variable, passes OPTIONS and PAIRS to
+     ‘define-keymap’, and uses the result as the default value for the
+     variable.
+
+     OPTIONS is like the keywords in ‘define-keymap’, but there’s an
+     additional ‘:doc’ keyword that provides the doc string for the
+     defined variable.
+
+     Here’s an example:
+
+          (defvar-keymap eww-textarea-map
+            :parent text-mode-map
+            "RET" #'forward-line
+            "TAB" #'shr-next-link)
+
+ -- Macro: while-let spec then-forms...
+     Like ‘when-let’, but repeat until a binding in SPEC is ‘nil’.  The
+     return value is always ‘nil’.
+
+     This is comparable to ‘and-let*’.
+
+ -- Function: window-configuration-equal-p config1 config2
+     This function says whether two window configurations have the same
+     window layout, but ignores the values of point and the saved
+     scrolling positions—it can return ‘t’ even if those aspects differ.
+
+ -- Macro: ert-with-temp-file name &rest body
+     Bind NAME to the name of a new temporary file and evaluate BODY.
+     Delete the temporary file after BODY exits normally or non-locally.
+     NAME will be bound to the file name of the temporary file.  See the
+     docstring for supported keyword arguments.
+
+ -- Macro: ert-with-temp-directory name &rest body
+     Bind NAME to the name of a new temporary directory and evaluate
+     BODY.  Delete the temporary directory after BODY exits normally or
+     non-locally.
+
+     NAME is bound to the directory name, not the directory file name.
+     (In other words, it will end with the directory delimiter; on
+     Unix-like systems, it will end with "/".)
+
+     The same keyword arguments are supported as in ‘ert-with-temp-file’
+     (which see), except for ‘:text’.
+
+ -- Function: cl-constantly value
+     Return a function that takes any number of arguments, but returns
+     VALUE.
+
+ -- Macro: cl-with-gensyms names... body
+     This macro expands to code that executes BODY with each of the
+     variables in NAMES bound to a fresh uninterned symbol, or “gensym”,
+     in Common Lisp parlance.  For macros requiring more than one
+     gensym, use of ‘cl-with-gensyms’ shortens the code and renders
+     one’s intentions clearer.  Compare:
+
+          (defmacro my-macro (foo)
+            (let ((bar (gensym "bar"))
+                  (baz (gensym "baz"))
+                  (quux (gensym "quux")))
+              `(let ((,bar (+ ...)))
+                 ...)))
+
+          (defmacro my-macro (foo)
+            (cl-with-gensyms (bar baz quux)
+              `(let ((,bar (+ ...)))
+                 ...)))
+
+ -- Macro: cl-once-only ((variable form)...) body
+     This macro is primarily to help the macro programmer ensure that
+     forms supplied by the user of the macro are evaluated just once by
+     its expansion even though the result of evaluating the form is to
+     occur more than once.  Less often, this macro is used to ensure
+     that forms supplied by the macro programmer are evaluated just
+     once.
+
+     Each VARIABLE may be used to refer to the result of evaluating FORM
+     in BODY.  ‘cl-once-only’ binds each VARIABLE to a fresh uninterned
+     symbol during the evaluation of BODY.  Then, ‘cl-once-only’ wraps
+     the final expansion in code to evaluate each FORM and bind the
+     result to the corresponding uninterned symbol.  Thus, when the
+     macro writer substitutes the value for VARIABLE into the expansion
+     they are effectively referring to the result of evaluating FORM,
+     rather than FORM itself.  Another way to put this is that each
+     VARIABLE is bound to an expression for the (singular) result of
+     evaluating FORM.
+
+     The most common case is where VARIABLE is one of the arguments to
+     the macro being written, so ‘(variable variable)’ may be
+     abbreviated to just ‘variable’.
+
+     For example, consider this macro:
+
+          (defmacro my-list (x y &rest forms)
+            (let ((x-result (gensym))
+                  (y-result (gensym)))
+              `(let ((,x-result ,x)
+                     (,y-result ,y))
+                 (list ,x-result ,y-result ,x-result ,y-result
+                       (progn ,@forms))))
+
+     In a call like ‘(my-list (pop foo) ...)’ the intermediate binding
+     to ‘x-result’ ensures that the ‘pop’ is not done twice.  But as a
+     result the code is rather complex: the reader must keep track of
+     how ‘x-result’ really just means the first parameter of the call to
+     the macro, and the required use of multiple gensyms to avoid
+     variable capture by ‘(progn ,@forms)’ obscures things further.
+     ‘cl-once-only’ takes care of these details:
+
+          (defmacro my-list (x y &rest forms)
+            (cl-once-only (x y)
+              `(list ,x ,y ,x ,y
+                     (progn ,@forms))))
+
+2.5.2 Extended Definitions
+--------------------------
+
+These functions must be called explicitly via ‘compat-call’, since their
+calling convention or behavior was extended in Emacs 29.1:
+
+ -- Function: compat-call set-transient-map keymap &optional keep-pred
+          on-exit message timeout
+     This function adds KEYMAP as a “transient” keymap, which takes
+     precedence over other keymaps for one (or more) subsequent keys.
+
+     Normally, KEYMAP is used just once, to look up the very next key.
+     If the optional argument KEEP-PRED is ‘t’, the map stays active as
+     long as the user types keys defined in KEYMAP; when the user types
+     a key that is not in KEYMAP, the transient keymap is deactivated
+     and normal key lookup continues for that key.
+
+     The KEEP-PRED argument can also be a function.  In that case, the
+     function is called with no arguments, prior to running each
+     command, while KEYMAP is active; it should return non-‘nil’ if
+     KEYMAP should stay active.
+
+     The optional argument ON-EXIT, if non-‘nil’, specifies a function
+     that is called, with no arguments, after KEYMAP is deactivated.
+
+     The optional argument MESSAGE specifies the message to display
+     after activating the transient map.  If MESSAGE is a string, it is
+     the format string for the message, and any ‘%k’ specifier in that
+     string is replaced with the list of keys from the transient map.
+     Any other non-‘nil’ value of MESSAGE stands for the default message
+     format ‘Repeat with %k’.
+
+     If the optional argument TIMEOUT is non-‘nil’, it should be a
+     number that specifies how many seconds of idle time to wait before
+     deactivating KEYMAP.  The value of the variable
+     ‘set-transient-map-timeout’, if non-‘nil’, overrides the value of
+     this argument.
+
+     This function works by adding and removing KEYMAP from the variable
+     ‘overriding-terminal-local-map’, which takes precedence over all
+     other active keymaps (*note (Searching Keymaps)elisp::).
+
+ -- Function: compat-call string-lines string &optional omit-nulls
+          keep-newlines
+     Split STRING into a list of strings on newline boundaries.  If the
+     optional argument OMIT-NULLS is non-‘nil’, remove empty lines from
+     the results.  If the optional argument KEEP-NEWLINES is non-‘nil’,
+     don’t remove the trailing newlines from the result strings.
+
+     *Note (elisp)Creating Strings::.
+
+ -- Function: compat-call define-key
+     This function is like ‘keymap-set’ (*note (elisp)Changing Key
+     Bindings::, but understands only the legacy key syntaxes.
+
+     In addition, this function also has a REMOVE argument.  If it is
+     non-‘nil’, the definition will be removed.  This is almost the same
+     as setting the definition to ‘nil’, but makes a difference if the
+     KEYMAP has a parent, and KEY is shadowing the same binding in the
+     parent.  With REMOVE, subsequent lookups will return the binding in
+     the parent, whereas with a ‘nil’ definition the lookups will return
+     ‘nil’.
+
+     *Note (elisp)Low-Level Key Binding::.
+
+     This compatibility version handles the optional argument REMOVE.
+
+ -- Function: compat-call plist-get plist prop &optional predicate
+     This returns the value of the PROPERTY property stored in the
+     property list PLIST.  Comparisons are done with PREDICATE, and
+     defaults to ‘eq’.  It accepts a malformed PLIST argument.  If
+     PROPERTY is not found in the PLIST, it returns ‘nil’.
+
+     *Note (elisp)Plist Access::.
+
+     This compatibility version handles the optional argument PREDICATE.
+     This is a generalized variable (*note (elisp)Generalized
+     Variables::) that can be used to change a value with ‘setf’.
+
+ -- Function: compat-call plist-put plist prop val &optional predicate
+     This stores VALUE as the value of the PROPERTY property in the
+     property list PLIST.  Comparisons are done with PREDICATE, and
+     defaults to ‘eq’.  It may modify PLIST destructively, or it may
+     construct a new list structure without altering the old.  The
+     function returns the modified property list, so you can store that
+     back in the place where you got PLIST.
+
+     *Note (elisp)Plist Access::.
+
+     This compatibility version handles the optional argument PREDICATE.
+
+ -- Function: compat-call plist-member plist prop &optional predicate
+     This returns non-‘nil’ if PLIST contains the given PROPERTY.
+     Comparisons are done with PREDICATE, and defaults to ‘eq’.  Unlike
+     ‘plist-get’, this allows you to distinguish between a missing
+     property and a property with the value ‘nil’.  The value is
+     actually the tail of PLIST whose ‘car’ is PROPERTY.
+
+     *Note (elisp)Plist Access::.
+
+     This compatibility version handles the optional argument PREDICATE.
+
+2.5.3 Missing Definitions
+-------------------------
+
+Compat does not provide support for the following Lisp features
+implemented in 29.1:
+
+   • The function ‘imagep’.
+   • The function ‘image-at-point-p’.
+   • The function ‘function-documentation’.
+   • The macro ‘with-undo-amalgamate’.
+   • The function ‘string-glyph-split’.
+   • The function ‘string-limit’.
+   • The function ‘string-pixel-width’ and ‘buffer-text-pixel-size’.
+   • The function ‘minibuffer-lazy-highlight-setup’.
+   • The function ‘pp-emacs-lisp-code’.
+   • The function ‘bidi-string-strip-control-characters’.
+   • The native function ‘current-cpu-time’.
+   • The functions ‘xdg-state-home’, ‘xdg-current-desktop’ and
+     ‘xdg-session-type’.
+   • The macro ‘setopt’.
+   • The ‘oclosure’ library.
+   • The ‘textsec’ library.
+   • The ‘range’ library.
+   • The ‘string-edit’ library.
+   • The ‘vtable’ library.
+   • The ‘pixel-fill’ library.
+   • Support for symbols with position information.
+
+\1f
+File: docXccUUB.info,  Node: Development,  Next: Function Index,  Prev: Support,  Up: Top
+
+3 Development
+*************
+
+Compat is developed on GitHub.
+
+   Bug reports, patches and comments are best sent to the issue tracker
+(https://github.com/emacs-compat/compat/issues).  These may include
+issues in the compatibility code, missing definitions or performance
+issues.  We also provide a development mailing list
+(https://lists.sr.ht/~pkal/compat-devel) (~pkal/compat-develNOSPAMlists.sr.ht
+<~pkal/compat-develNOSPAMlists.sr.ht>).
+
+   Please note that as a GNU ELPA package, Compat requires contributors
+to have signed the FSF copyright assignment
+(https://www.gnu.org/software/emacs/manual/html_node/emacs/Copyright-Assignment.html),
+before any non-trivial contribution (roughly 15 lines of code) can be
+applied.
+
+   It is important that you provide tests when you contribute new
+functionality.  Compat has 100% test coverage by the test suite.  We use
+continuous integration to check if patches preserve existing
+functionality.
+
+   Development for the currently stable Emacs version happens in the
+main branch of the Compat Git repository.  ELPA-devel nightly builds are
+created from this branch.  New features, which are not yet ready to be
+merged directly into the main branch, are developed in feature branches.
+Furthermore the Git repository has a branch emacs-<version> where the
+development for the upcoming Emacs release takes place.  This branch is
+separate from the main branch since the new functionality should not be
+made available (neither via ELPA nor ELPA-devel) before the new Emacs
+version has been reasonably stabilized, e.g., around the time when the
+Emacs version branch is created in the Emacs repository on Savannah.
+
+\1f
+File: docXccUUB.info,  Node: Function Index,  Next: Variable Index,  Prev: Development,  Up: Top
+
+Appendix A Function Index
+*************************
+
+\0\b[index\0\b]
+* Menu:
+
+* add-display-text-property:             Emacs 29.1.          (line 190)
+* alist-get:                             Emacs 25.1.          (line  82)
+* always:                                Emacs 28.1.          (line  83)
+* and-let*:                              Emacs 26.1.          (line 158)
+* assoc-delete-all:                      Emacs 26.1.          (line  13)
+* bignump:                               Emacs 27.1.          (line  55)
+* bool-vector:                           Emacs 25.1.          (line 177)
+* bounds-of-thing-at-mouse:              Emacs 28.1.          (line 292)
+* buffer-hash:                           Emacs 26.1.          (line  80)
+* buffer-local-boundp:                   Emacs 28.1.          (line 125)
+* buffer-local-restore-state:            Emacs 29.1.          (line  50)
+* buffer-local-set-state:                Emacs 29.1.          (line  50)
+* buffer-match-p:                        Emacs 29.1.          (line 258)
+* buttonize:                             Emacs 29.1.          (line 156)
+* buttonize-region:                      Emacs 29.1.          (line 165)
+* char-uppercase-p:                      Emacs 29.1.          (line 127)
+* cl-constantly:                         Emacs 29.1.          (line 635)
+* cl-once-only:                          Emacs 29.1.          (line 658)
+* cl-with-gensyms:                       Emacs 29.1.          (line 639)
+* color-dark-p:                          Emacs 28.1.          (line 322)
+* color-values-from-color-spec:          Emacs 28.1.          (line 328)
+* compat-call:                           Usage.               (line  50)
+* compat-call alist-get:                 Emacs 26.1.          (line 344)
+* compat-call assoc:                     Emacs 26.1.          (line 316)
+* compat-call assoc-delete-all:          Emacs 27.1.          (line 417)
+* compat-call count-windows:             Emacs 28.1.          (line 412)
+* compat-call define-key:                Emacs 29.1.          (line 755)
+* compat-call executable-find:           Emacs 27.1.          (line 429)
+* compat-call file-size-human-readable:  Emacs 27.1.          (line 397)
+* compat-call line-number-at-pos:        Emacs 26.1.          (line 330)
+* compat-call lookup-key:                Emacs 27.1.          (line 356)
+* compat-call make-temp-file:            Emacs 26.1.          (line 278)
+* compat-call plist-get:                 Emacs 29.1.          (line 771)
+* compat-call plist-member:              Emacs 29.1.          (line 795)
+* compat-call plist-put:                 Emacs 29.1.          (line 783)
+* compat-call recenter:                  Emacs 27.1.          (line 346)
+* compat-call regexp-opt:                Emacs 27.1.          (line 385)
+* compat-call set-transient-map:         Emacs 29.1.          (line 710)
+* compat-call setq-local:                Emacs 27.1.          (line 370)
+* compat-call sort:                      Emacs 25.1.          (line 189)
+* compat-call string-lines:              Emacs 29.1.          (line 746)
+* compat-call string-trim:               Emacs 26.1.          (line 375)
+* compat-call string-trim-left:          Emacs 26.1.          (line 359)
+* compat-call string-trim-right:         Emacs 26.1.          (line 367)
+* compat-call string-width:              Emacs 28.1.          (line 395)
+* compat-function:                       Usage.               (line  58)
+* compiled-function-p:                   Emacs 29.1.          (line 226)
+* count-sentences:                       Emacs 29.1.          (line  25)
+* cXXXr:                                 Emacs 26.1.          (line  66)
+* cXXXXr:                                Emacs 26.1.          (line  67)
+* date-days-in-month:                    Emacs 27.1.          (line 213)
+* date-ordinal-to-time:                  Emacs 27.1.          (line 220)
+* decoded-time-day:                      Emacs 27.1.          (line 175)
+* decoded-time-dst:                      Emacs 27.1.          (line 195)
+* decoded-time-hour:                     Emacs 27.1.          (line 170)
+* decoded-time-minute:                   Emacs 27.1.          (line 165)
+* decoded-time-month:                    Emacs 27.1.          (line 180)
+* decoded-time-period:                   Emacs 28.1.          (line 359)
+* decoded-time-second:                   Emacs 27.1.          (line 160)
+* decoded-time-weekday:                  Emacs 27.1.          (line 190)
+* decoded-time-year:                     Emacs 27.1.          (line 185)
+* decoded-time-zone:                     Emacs 27.1.          (line 200)
+* define-keymap:                         Emacs 29.1.          (line 518)
+* defvar-keymap:                         Emacs 29.1.          (line 586)
+* delete-line:                           Emacs 29.1.          (line  59)
+* directory-abbrev-apply:                Emacs 29.1.          (line 382)
+* directory-abbrev-make-regexp:          Emacs 29.1.          (line 379)
+* directory-empty-p:                     Emacs 28.1.          (line 243)
+* directory-name-p:                      Emacs 25.1.          (line  56)
+* dlet:                                  Emacs 28.1.          (line 143)
+* dolist-with-progress-reporter:         Emacs 27.1.          (line 119)
+* ensure-list:                           Emacs 28.1.          (line 158)
+* ert-with-temp-directory:               Emacs 29.1.          (line 623)
+* ert-with-temp-file:                    Emacs 29.1.          (line 617)
+* file-attribute-access-time:            Emacs 26.1.          (line 223)
+* file-attribute-collect:                Emacs 26.1.          (line 260)
+* file-attribute-device-number:          Emacs 26.1.          (line 255)
+* file-attribute-file-identifier:        Emacs 29.1.          (line 339)
+* file-attribute-group-id:               Emacs 26.1.          (line 218)
+* file-attribute-inode-number:           Emacs 26.1.          (line 250)
+* file-attribute-link-number:            Emacs 26.1.          (line 208)
+* file-attribute-modes:                  Emacs 26.1.          (line 245)
+* file-attribute-modification-time:      Emacs 26.1.          (line 228)
+* file-attribute-size:                   Emacs 26.1.          (line 240)
+* file-attribute-status-change-time:     Emacs 26.1.          (line 234)
+* file-attribute-type:                   Emacs 26.1.          (line 203)
+* file-attribute-user-id:                Emacs 26.1.          (line 213)
+* file-backup-file-names:                Emacs 28.1.          (line 347)
+* file-has-changed-p:                    Emacs 29.1.          (line 364)
+* file-local-name:                       Emacs 26.1.          (line 167)
+* file-modes-number-to-symbolic:         Emacs 28.1.          (line 341)
+* file-name-concat:                      Emacs 28.1.          (line  53)
+* file-name-parent-directory:            Emacs 29.1.          (line 355)
+* file-name-quote:                       Emacs 26.1.          (line 102)
+* file-name-quoted-p:                    Emacs 26.1.          (line  95)
+* file-name-split:                       Emacs 29.1.          (line 345)
+* file-name-unquote:                     Emacs 26.1.          (line  90)
+* file-name-with-extension:              Emacs 28.1.          (line 225)
+* file-size-human-readable-iec:          Emacs 27.1.          (line 251)
+* fixnump:                               Emacs 27.1.          (line  60)
+* flatten-tree:                          Emacs 27.1.          (line 132)
+* format-message:                        Emacs 25.1.          (line  44)
+* format-prompt:                         Emacs 28.1.          (line 254)
+* funcall-with-delayed-message:          Emacs 29.1.          (line 148)
+* function-alias-p:                      Emacs 29.1.          (line 233)
+* garbage-collect-maybe:                 Emacs 28.1.          (line  68)
+* gensym:                                Emacs 26.1.          (line  70)
+* get-display-property:                  Emacs 29.1.          (line 173)
+* get-scratch-buffer-create:             Emacs 29.1.          (line  38)
+* hash-table-empty:                      Emacs 25.1.          (line 119)
+* if-let:                                Emacs 25.1.          (line  96)
+* if-let*:                               Emacs 26.1.          (line 149)
+* ignore-errors:                         Emacs 27.1.          (line 106)
+* image-property:                        Emacs 26.1.          (line 198)
+* insert-into-buffer:                    Emacs 28.1.          (line  92)
+* key-parse:                             Emacs 29.1.          (line 419)
+* key-valid-p:                           Emacs 29.1.          (line 387)
+* keymap-global-lookup:                  Emacs 29.1.          (line 514)
+* keymap-global-set:                     Emacs 29.1.          (line 448)
+* keymap-global-unset:                   Emacs 29.1.          (line 468)
+* keymap-local-lookup:                   Emacs 29.1.          (line 510)
+* keymap-local-set:                      Emacs 29.1.          (line 458)
+* keymap-local-unset:                    Emacs 29.1.          (line 483)
+* keymap-lookup:                         Emacs 29.1.          (line 497)
+* keymap-set:                            Emacs 29.1.          (line 424)
+* keymap-substitute:                     Emacs 29.1.          (line 489)
+* length<:                               Emacs 28.1.          (line  45)
+* length=:                               Emacs 28.1.          (line  42)
+* length>:                               Emacs 28.1.          (line  50)
+* list-of-strings-p:                     Emacs 29.1.          (line  62)
+* macroexp-file-name:                    Emacs 28.1.          (line 301)
+* macroexp-parse:                        Emacs 25.1.          (line 174)
+* macroexp-quote:                        Emacs 25.1.          (line 171)
+* macroexp-warn-and-return:              Emacs 28.1.          (line 305)
+* macroexpand-1:                         Emacs 25.1.          (line 164)
+* major-mode-restore:                    Emacs 27.1.          (line  22)
+* major-mode-suspend:                    Emacs 27.1.          (line  13)
+* make-empty-file:                       Emacs 27.1.          (line 254)
+* make-lock-file-name:                   Emacs 28.1.          (line 355)
+* make-nearby-temp-file:                 Emacs 26.1.          (line 120)
+* make-separator-line:                   Emacs 28.1.          (line  88)
+* mapcan:                                Emacs 26.1.          (line  53)
+* mark-thing-at-mouse:                   Emacs 28.1.          (line 298)
+* match-buffers:                         Emacs 29.1.          (line 292)
+* minibuffer-history-value:              Emacs 27.1.          (line  32)
+* named-let:                             Emacs 28.1.          (line 207)
+* native-comp-available-p:               Emacs 28.1.          (line 376)
+* ntake:                                 Emacs 29.1.          (line 213)
+* package-get-version:                   Emacs 27.1.          (line 205)
+* plistp:                                Emacs 29.1.          (line  65)
+* pos-bol:                               Emacs 29.1.          (line 119)
+* pos-eol:                               Emacs 29.1.          (line 123)
+* process-lines-handling-status:         Emacs 28.1.          (line  20)
+* process-lines-ignore-status:           Emacs 28.1.          (line  16)
+* proper-list-p:                         Emacs 27.1.          (line  76)
+* provided-mode-derived-p:               Emacs 27.1.          (line 247)
+* read-answer:                           Emacs 26.1.          (line  17)
+* read-char-from-minibuffer:             Emacs 27.1.          (line  44)
+* read-multiple-choice:                  Emacs 26.1.          (line 185)
+* readablep:                             Emacs 29.1.          (line  28)
+* region-bounds:                         Emacs 25.1.          (line  28)
+* region-noncontiguous-p:                Emacs 25.1.          (line  34)
+* replace-regexp-in-string:              Emacs 28.1.          (line 117)
+* replace-string-in-region:              Emacs 28.1.          (line 102)
+* ring-resize:                           Emacs 27.1.          (line  28)
+* save-mark-and-excursion:               Emacs 25.1.          (line  39)
+* string-chop-newline:                   Emacs 28.1.          (line 202)
+* string-clean-whitespace:               Emacs 28.1.          (line 171)
+* string-distance:                       Emacs 27.1.          (line  86)
+* string-equal-ignore-case:              Emacs 29.1.          (line 246)
+* string-fill:                           Emacs 28.1.          (line 178)
+* string-glyph-split:                    Emacs 29.1.          (line 301)
+* string-greaterp:                       Emacs 25.1.          (line  64)
+* string-lines:                          Emacs 28.1.          (line 186)
+* string-pad:                            Emacs 28.1.          (line 193)
+* string-replace:                        Emacs 28.1.          (line  77)
+* string-search:                         Emacs 28.1.          (line  34)
+* string-split:                          Emacs 29.1.          (line 252)
+* subr-native-elisp-p:                   Emacs 28.1.          (line 371)
+* subr-primitive-p:                      Emacs 28.1.          (line 364)
+* substitute-quotes:                     Emacs 29.1.          (line  34)
+* take:                                  Emacs 29.1.          (line 199)
+* temporary-file-directory:              Emacs 26.1.          (line 137)
+* text-property-search-backward:         Emacs 27.1.          (line 332)
+* text-property-search-forward:          Emacs 27.1.          (line 260)
+* text-quoting-style:                    Emacs 28.1.          (line  28)
+* thing-at-mouse:                        Emacs 28.1.          (line 285)
+* thread-first:                          Emacs 25.1.          (line 122)
+* thread-last:                           Emacs 25.1.          (line 143)
+* time-equal-p:                          Emacs 27.1.          (line 208)
+* use-region-beginning:                  Emacs 29.1.          (line  47)
+* use-region-end:                        Emacs 29.1.          (line  44)
+* use-region-noncontiguous-p:            Emacs 29.1.          (line  41)
+* when-let:                              Emacs 25.1.          (line 114)
+* when-let*:                             Emacs 26.1.          (line 153)
+* while-let:                             Emacs 29.1.          (line 606)
+* window-configuration-equal-p:          Emacs 29.1.          (line 612)
+* with-buffer-unmodified-if-unchanged:   Emacs 29.1.          (line 324)
+* with-delayed-message:                  Emacs 29.1.          (line 131)
+* with-environment-variables:            Emacs 28.1.          (line 309)
+* with-existing-directory:               Emacs 28.1.          (line 132)
+* with-file-modes:                       Emacs 25.1.          (line  71)
+* with-memoization:                      Emacs 29.1.          (line  68)
+* with-minibuffer-selected-window:       Emacs 27.1.          (line  38)
+* with-restriction:                      Emacs 29.1.          (line  73)
+* with-suppressed-warnings:              Emacs 27.1.          (line  65)
+* with-window-non-dedicated:             Emacs 28.1.          (line 384)
+* without-restriction:                   Emacs 29.1.          (line 107)
+* xor:                                   Emacs 27.1.          (line 142)
+
+\1f
+File: docXccUUB.info,  Node: Variable Index,  Prev: Function Index,  Up: Top
+
+Appendix B Variable Index
+*************************
+
+\0\b[index\0\b]
+* Menu:
+
+* exec-path:                             Emacs 27.1.          (line 228)
+* gensym-counter:                        Emacs 26.1.          (line  77)
+* lisp-directory:                        Emacs 29.1.          (line  17)
+* mounted-file-systems:                  Emacs 26.1.          (line 133)
+* regexp-unmatchable:                    Emacs 27.1.          (line 152)
+* set-transient-map-timeout:             Emacs 29.1.          (line 736)
+* text-quoting-style:                    Emacs 25.1.          (line  13)
+
+
+\1f
+Tag Table:
+Node: Top\7f829
+Node: Introduction\7f2258
+Node: Overview\7f2421
+Node: Usage\7f2947
+Node: Limitations\7f7326
+Node: Support\7f12192
+Node: Emacs 25.1\7f12777
+Node: Emacs 26.1\7f22179
+Node: Emacs 27.1\7f39473
+Node: Emacs 28.1\7f59870
+Node: Emacs 29.1\7f79951
+Node: Development\7f117330
+Node: Function Index\7f119064
+Node: Variable Index\7f134496
+\1f
+End Tag Table
+
+\1f
+Local Variables:
+coding: utf-8
+End:
diff --git a/elpa/compat-29.1.4.5/dir b/elpa/compat-29.1.4.5/dir
new file mode 100644 (file)
index 0000000..de02c6e
--- /dev/null
@@ -0,0 +1,18 @@
+This is the file .../info/dir, which contains the
+topmost node of the Info hierarchy, called (dir)Top.
+The first time you invoke Info you start off looking at this node.
+\1f
+File: dir,     Node: Top       This is the top of the INFO tree
+
+  This (the Directory node) gives a menu of major topics.
+  Typing "q" exits, "H" lists all Info commands, "d" returns here,
+  "h" gives a primer for first-timers,
+  "mEmacs<Return>" visits the Emacs manual, etc.
+
+  In Emacs, you can click mouse button 2 on a menu item or cross reference
+  to select it.
+
+* Menu:
+
+Emacs
+* Compat: (compat).             Compatibility Library for Emacs Lisp.