"Compat" Manual
***************

This manual documents the usage of the "Compat" Emacs lisp library, the
forward-compatibility library for Emacs Lisp, corresponding to version
28.1.2.2.

   Copyright © 2022 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.”

— The Detailed Node Listing —

Introduction

Usage

Support

1 Introduction
**************

1.1 Overview
============

The objective of Compat is to provide "forwards compatibility" library
for Emacs Lisp.  That is to say 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.

   Version 24.3 is chosen as the oldest version, because this is the
newest version on CentOS 7.  It is intended to preserve compatibility
for at least as the Centos 7 reaches EOL
(https://wiki.centos.org/About/Product), 2024.

   If you are developing a package with Compat in mind, consider loading
‘compat-help‘ (on your system, not in a package) to get relevant notes
inserted into the help buffers of functions that are implemented or
advised in Compat.

   Note that Compat provides a few prefixed function, ie.  functions
with a ‘compat-’ prefix.  These are used to provide extended
functionality for commands that are already defined (‘sort’, ‘assoc’,
‘seq’, ...).  It might be possible to transform these into advised
functions later on, so that the modified functionality is accessible
without a prefix.  Feedback on this point is appreciated.

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.3") (compat "28.1.2.2"))

   There is no need to depend on ‘emacs’ 24.3 specifically.  One can
choose to any newer version, if features not provided by Compat
necessitate it.

   In any file where compatibility forms are used, a

     (require 'compat)

   should be added early on.

   This will load all non-prefixed definitions (functions and macros
with a leading ‘compat-‘).  To load these, an additional

     (require 'compat-XY) ; e.g. 26

   will be necessary, to load compatibility code for Emacs version XY.

   It is recommended 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.

1.2.1 Additional libraries
--------------------------

These libraries are packages with Compat, but are disabled by default.
To use them you can use ‘M-x load-library’:

compat-help
     Add notes to ‘*Help*’ buffer, if a compatibility definition has
     something to warn you about.
compat-font-lock
     Highlight functions that are implemented as compatibility
     definitions.

1.3 Intentions
==============

The library intends to provide support back until Emacs 24.3.  The
intended audience are package developers that are interested in using
newer developments, without having to break compatibility.

   Sadly, total backwards compatibility cannot be provided for technical
reasons.  These might include:

   • An existing function or macro was extended by some new
     functionality.  To support these cases, the function or macro would
     have to be advised.  As this is usually regarded as invasive and is
     shown to be a significant overhead, even when the new feature is
     not used, this approach is not used.

     As a compromise, prefixed functions and macros (starting with a
     ‘compat-’ prefix) can be provided.

   • New functionality was implemented in the core, and depends on
     external libraries that cannot be reasonably duplicated in the
     scope of a compatibility library.

   • New functionality depends on an entire new, non-trivial library.
     Sometimes these are provided via ELPA (xref, project, ...), but
     other times it would be infeasible to duplicate an entire library
     within Compat while also providing the necessary backwards
     compatibility.

   • It just wasn’t added, and there is no good reason (though good
     excuses might exist).  If you happen to find such a function, see
     reporting it would be much appreciated.

     Always begin by assuming that this might be the case, unless proven
     otherwise.

2 Support
*********

This section goes into the features that Compat manages and doesn’t
manage to provide for each Emacs version.

2.1 Emacs 24.4
==============

2.1.1 Unprefixed Definitions
----------------------------

The following functions and macros implemented in 24.4, and are provided
by Compat by default:

 -- Macro: with-eval-after-load library body...
     This macro arranges to evaluate BODY at the end of loading the file
     LIBRARY, each time LIBRARY is loaded.  If LIBRARY is already
     loaded, it evaluates BODY right away.

     You don’t need to give a directory or extension in the file name
     LIBRARY.  Normally, you just give a bare file name, like this:

          (with-eval-after-load "js" (keymap-set js-mode-map "C-c C-c" 'js-eval))

     To restrict which files can trigger the evaluation, include a
     directory or an extension or both in LIBRARY.  Only a file whose
     absolute true name (i.e., the name with all symbolic links chased
     out) matches all the given name components will match.  In the
     following example, ‘my_inst.elc’ or ‘my_inst.elc.gz’ in some
     directory ‘..../foo/bar’ will trigger the evaluation, but not
     ‘my_inst.el’:

          (with-eval-after-load "foo/bar/my_inst.elc" ...)

     LIBRARY can also be a feature (i.e., a symbol), in which case BODY
     is evaluated at the end of any file where ‘(provide LIBRARY)’ is
     called.

     An error in BODY does not undo the load, but does prevent execution
     of the rest of BODY.

     See Hooks for Loading (elisp).

 -- Function: special-form-p object
     This predicate tests whether its argument is a special form, and
     returns ‘t’ if so, ‘nil’ otherwise.

     See Special Forms (elisp).

 -- Function: macrop object
     This predicate tests whether its argument is a macro, and returns
     ‘t’ if so, ‘nil’ otherwise.

     See Simple Macro (elisp).

 -- Function: string-suffix-p suffix string &optional ignore-case
     This function returns non-‘nil’ if SUFFIX is a suffix of STRING;
     i.e., if STRING ends with SUFFIX.  If the optional argument
     IGNORE-CASE is non-‘nil’, the comparison ignores case differences.

     See Text Comparison (elisp).

 -- Function: delete-consecutive-dups list &optional circular
     Destructively remove ‘equal’ consecutive duplicates from LIST.
     First and last elements are considered consecutive if CIRCULAR is
     non-nil.

 -- Function: define-error name message &optional parent
     In order for a symbol to be an error symbol, it must be defined
     with ‘define-error’ which takes a parent condition (defaults to
     ‘error’).  This parent defines the conditions that this kind of
     error belongs to.  The transitive set of parents always includes
     the error symbol itself, and the symbol ‘error’.  Because quitting
     is not considered an error, the set of parents of ‘quit’ is just
     ‘(quit)’.

     See Error Symbols (elisp).

 -- Function: bool-vector-exclusive-or a b &optional c
     Return “bitwise exclusive or” of bool vectors A and B.  If optional
     argument C is given, the result of this operation is stored into C.
     All arguments should be bool vectors of the same length.

     See Bool-Vectors (elisp).

 -- Function: bool-vector-union a b &optional c
     Return “bitwise or” of bool vectors A and B.  If optional argument
     C is given, the result of this operation is stored into C.  All
     arguments should be bool vectors of the same length.

     See Bool-Vectors (elisp).

 -- Function: bool-vector-intersection a b &optional c
     Return “bitwise and” of bool vectors A and B.  If optional argument
     C is given, the result of this operation is stored into C.  All
     arguments should be bool vectors of the same length.

     See Bool-Vectors (elisp).

 -- Function: bool-vector-set-difference a b &optional c
     Return “set difference” of bool vectors A and B.  If optional
     argument C is given, the result of this operation is stored into C.
     All arguments should be bool vectors of the same length.

     See Bool-Vectors (elisp).

 -- Function: bool-vector-not a &optional b
     Return “set complement” of bool vector A.  If optional argument B
     is given, the result of this operation is stored into B.  All
     arguments should be bool vectors of the same length.

     See Bool-Vectors (elisp).

 -- Function: bool-vector-subsetp a b
     Return ‘t’ if every ‘t’ value in A is also ‘t’ in B, ‘nil’
     otherwise.  All arguments should be bool vectors of the same
     length.

     See Bool-Vectors (elisp).

 -- Function: bool-vector-count-consecutive a b i
     Return the number of consecutive elements in A equal B starting at
     I.  ‘a’ is a bool vector, B is ‘t’ or ‘nil’, and I is an index into
     ‘a’.

     See Bool-Vectors (elisp).

 -- Function: bool-vector-count-population a
     Return the number of elements that are ‘t’ in bool vector A.

     See Bool-Vectors (elisp).

 -- Function: completion-table-with-cache function &optional ignore-case
     This is a wrapper for ‘completion-table-dynamic’ that saves the
     last argument-result pair.  This means that multiple lookups with
     the same argument only need to call FUNCTION once.  This can be
     useful when a slow operation is involved, such as calling an
     external process.

     See Programmed Completion (elisp).

 -- Function: face-spec-set face spec &optional spec-type
     This function applies SPEC as a face spec for ‘face’.  SPEC should
     be a face spec, as described in the above documentation for
     ‘defface’.

     This function also defines FACE as a valid face name if it is not
     already one, and (re)calculates its attributes on existing frames.

     The optional argument SPEC-TYPE determines which spec to set.  If
     it is omitted or ‘nil’ or ‘face-override-spec’, this function sets
     the “override spec”, which overrides face specs on FACE of all the
     other types mentioned below.  This is useful when calling this
     function outside of Custom code.  If SPEC-TYPE is ‘customized-face’
     or ‘saved-face’, this function sets the customized spec or the
     saved custom spec, respectively.  If it is ‘face-defface-spec’,
     this function sets the default face spec (the same one set by
     ‘defface’).  If it is ‘reset’, this function clears out all
     customization specs and override specs from FACE (in this case, the
     value of SPEC is ignored).  The effect of any other value of
     SPEC-TYPE on the face specs is reserved for internal use, but the
     function will still define FACE itself and recalculate its
     attributes, as described above.

     See Defining Faces (elisp).

2.1.2 Prefixed Definitions
--------------------------

These functions are prefixed with ‘compat’ prefix, and are only loaded
when ‘compat-24’ is required:

 -- Function: compat-= number-or-marker &rest number-or-markers
     This function tests whether all its arguments are numerically
     equal, and returns ‘t’ if so, ‘nil’ otherwise.

     See Comparison of Numbers (elisp).
 -- Function: compat-< number-or-marker &rest number-or-markers
     This function tests whether each argument is strictly less than the
     following argument.  It returns ‘t’ if so, ‘nil’ otherwise.

     See Comparison of Numbers (elisp).
 -- Function: compat-> number-or-marker &rest number-or-markers
     This function tests whether each argument is strictly greater than
     the following argument.  It returns ‘t’ if so, ‘nil’ otherwise.

     See Comparison of Numbers (elisp).
 -- Function: compat-<= number-or-marker &rest number-or-markers
     This function tests whether each argument is less than or equal to
     the following argument.  It returns ‘t’ if so, ‘nil’ otherwise.

     See Comparison of Numbers (elisp).
 -- Function: compat->= number-or-marker &rest number-or-markers
     This function tests whether each argument is greater than or equal
     to the following argument.  It returns ‘t’ if so, ‘nil’ otherwise.

     See Comparison of Numbers (elisp).

   These functions differ from the previous implementation in that they
allow for more than two argument to be compared.

 -- Function: compat-split-string string &optional separators omit-nulls
          trim
     This function splits STRING into substrings based on the regular
     expression SEPARATORS (see Regular Expressions (elisp)).  Each
     match for SEPARATORS defines a splitting point; the substrings
     between splitting points are made into a list, which is returned.

     Creating Strings (elisp) for more details.

     This version handles the optional argument TRIM.  If it is
     non-‘nil’, it should be a regular expression to match text to trim
     from the beginning and end of each substring.  If trimming makes
     the substring empty, it is treated as null.

2.1.3 Missing Definitions
-------------------------

Compat does not provide support for the following Lisp features
implemented in 24.4:

   • Allowing the second optional argument to ‘eval’ to specify a
     lexical environment.
   • The ‘define-alternatives’ macro.
   • Support for the ‘defalias-fset-function’ symbol property.
   • The ‘group-gid’ and ‘groupd-read-gid’ functions.
   • The ‘pre-redisplay-function’ hook.
   • Allowing for ‘with-demoted-errors’ to take a additional argument
     ‘format’.
   • The ‘add-face-text-property’ function.
   • No ‘tty-setup-hook’ hook.
   • The ‘get-pos-property’ function.
   • The ‘define-advice’ macro.
   • Support for generators.
   • The ‘string-trim’, ‘string-trim-left’ and ‘string-trim-right’
     functions.  These are instead provided as prefixed function as part
     of Emacs 26.1 support.

2.2 Emacs 25.1
==============

2.2.1 Unprefixed Definitions
----------------------------

The following functions and macros implemented in 25.1, and are provided
by Compat by default:

 -- 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’".  See Text Quoting Style (elisp), for how to
     influence or inhibit this translation.

     See Formatting Strings (elisp).

 -- 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.

     See Directory Names (elisp).

 -- 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)’.

     See Text Comparison (elisp).

 -- 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.

     See Changing Files (elisp).

 -- Function: alist-get key alist &optional default remove testfn
     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’.

     This is a generalized variable (see Generalized Variables (elisp))
     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.

     See Association Lists (elisp).

 -- 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*’.

 -- 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.

     See Expansion (elisp).

 -- Function: directory-files-recursively directory regexp &optional
          include-directories predicate follow-symlinks
     Return all files under DIRECTORY whose names match REGEXP.  This
     function searches the specified DIRECTORY and its sub-directories,
     recursively, for files whose basenames (i.e., without the leading
     directories) match the specified REGEXP, and returns a list of the
     absolute file names of the matching files (see absolute file names (elisp)).
     The file names are returned
     in depth-first order, meaning that files in some sub-directory are
     returned before the files in its parent directory.  In addition,
     matching files found in each subdirectory are sorted alphabetically
     by their basenames.  By default, directories whose names match
     REGEXP are omitted from the list, but if the optional argument
     INCLUDE-DIRECTORIES is non-‘nil’, they are included.

     By default, all subdirectories are descended into.  If PREDICATE is
     ‘t’, errors when trying to descend into a subdirectory (for
     instance, if it’s not readable by this user) are ignored.  If it’s
     neither ‘nil’ nor ‘t’, it should be a function that takes one
     parameter (the subdirectory name) and should return non-‘nil’ if
     the directory is to be descended into.

     Symbolic links to subdirectories are not followed by default, but
     if FOLLOW-SYMLINKS is non-‘nil’, they are followed.

     See Contents of Directories (elisp).

 -- Function: bool-vector &rest objects
     This function creates and returns a bool-vector whose elements are
     the arguments, OBJECTS.

     See Bool-Vectors (elisp).

2.2.2 Prefixed Definitions
--------------------------

These functions are prefixed with ‘compat’ prefix, and are only loaded
when ‘compat-25’ is required:

 -- Function: compat-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.

     See Sequence Functions (elisp).

     The compatibility version adds support for vectors to be sorted,
     not just lists.

2.2.3 Missing Definitions
-------------------------

Compat does not provide support for the following Lisp features
implemented in 25.1:

   • 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-interactivly’.
   • 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’.

2.3 Emacs 26.1
==============

2.3.1 Unprefixed Definitions
----------------------------

The following functions and macros implemented in 26.1, and are provided
by Compat by default:

 -- Function: func-arity function
     This function provides information about the argument list of the
     specified FUNCTION.  The returned value is a cons cell of the form
     ‘(MIN . MAX)’, where MIN is the minimum number of arguments, and
     MAX is either the maximum number of arguments, or the symbol ‘many’
     for functions with ‘&rest’ arguments, or the symbol ‘unevalled’ if
     FUNCTION is a special form.

     Note that this function might return inaccurate results in some
     situations, such as the following:

        − Functions defined using ‘apply-partially’ (see
          apply-partially (elisp)).

        − Functions that are advised using ‘advice-add’ (see
          Advising Named Functions (elisp)).

        − Functions that determine the argument list dynamically, as
          part of their code.

     See What Is a Function (elisp).

 -- 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’; see
     Rearrangement (elisp)).  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)

     See Mapping Functions (elisp).

 -- Function: cXXXr
 -- Function: cXXXXr
     See List Elements (elisp).

 -- 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: 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.

     See Unique File Names (elisp).

 -- 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 (see
     Asynchronous Processes (elisp), and Synchronous Processes (elisp)),
     and as the program to run on the remote host.  If
     FILENAME is local, this function returns it unchanged.

     See Magic File Names (elisp).

 -- Macro: 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.

     See File Name Expansion (elisp).

 -- Macro: 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 (see Magic File Names (elisp))
     is quoted.  If NAME is already a quoted file name, NAME is returned
     unchanged.

          (substitute-in-file-name (file-name-quote "bar/~/foo")) ⇒
               "/:bar/~/foo"

          (substitute-in-file-name (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 (see Magic File Names (elisp)).

     See File Name Expansion (elisp).

 -- Function: read-multiple-choice prompt choices &optional help-string
          show-help long-form
     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.

     If optional argument LONG-FORM is non-‘nil’, the user will have to
     type in long-form answers (using ‘completing-read’) instead of
     hitting a single key.  The answers must be among the second
     elements of the values in the CHOICES list.

     Note: The Compat implementation of this function ignores the
     optional arguments HELP-STRING and SHOW-HELP.  Therefore the
     optional third element in each CHOICES entry will also be
     disregarded.

     See Reading One Event (elisp).

 -- Function: image-property
     Defined in ‘image.el’.

     This function can also be used as a generalised variable.  To use
     this you need to explicitly require ‘compat-26’.

 -- Function: file-attribute-type
     Return the field _type_ as generated by ‘file-attributes’.

     See File Attributes (elisp).

 -- Function: file-attribute-link-number
     Return the field _link-number_ as generated by ‘file-attributes’.

     See File Attributes (elisp).

 -- Function: file-attribute-user-id
     Return the field _user-id_ as generated by ‘file-attributes’.

     See File Attributes (elisp).

 -- Function: file-attribute-group-id
     Return the field _group-id_ as generated by ‘file-attributes’.

     See File Attributes (elisp).

 -- Function: file-attribute-access-time
     Return the field _access-time_ as generated by ‘file-attributes’.

     See File Attributes (elisp).

 -- Function: file-attribute-modification-time
     Return the field _modification-time_ as generated by
     ‘file-attributes’.

     See File Attributes (elisp).

 -- Function: file-attribute-status-change-time
     Return the field _modification-time_ as generated by
     ‘file-attributes’.

     See File Attributes (elisp).

 -- Function: file-attribute-size
     Return the field _size_ as generated by ‘file-attributes’.

     See File Attributes (elisp).

 -- Function: file-attribute-modes
     Return the field _modes_ as generated by ‘file-attributes’.

     See File Attributes (elisp).

 -- Function: file-attribute-inode-number
     Return the field _inode-number_ as generated by ‘file-attributes’.

     See File Attributes (elisp).

 -- Function: file-attribute-device-number
     Return the field _device-number_ as generated by ‘file-attributes’.

     See File Attributes (elisp).

 -- 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.3.2 Prefixed Definitions
--------------------------

These functions are prefixed with ‘compat’ prefix, and are only loaded
when ‘compat-26’ is required:

 -- Function: compat-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 (see Equality Predicates (elisp)).
     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.

     See Association Lists (elisp).

     The compatibility version adds support for handling the optional
     argument TESTFN.

 -- Function: compat-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

     See Text Lines (elisp).

     The compatibility version adds support for handling the optional
     argument ABSOLUTE.

 -- Function: compat-alist-get key alist &optional default remove testfn
     See Association Lists (elisp).  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’.

     See Association Lists (elisp).

     The compatibility version handles the optional argument TESTFN.  It
     can also be used as a Generalized Variables (elisp).

 -- Function: compat-string-trim-left string &optional regexp
     Remove the leading text that matches REGEXP from STRING.  REGEXP
     defaults to ‘[ \t\n\r]+’.

     See Creating Strings (elisp).

     The compatibility version handles the optional argument REGEXP.

 -- Function: compat-string-trim-right string &optional regexp
     Remove the trailing text that matches REGEXP from STRING.  REGEXP
     defaults to ‘[ \t\n\r]+’.

     See Creating Strings (elisp).

     The compatibility version handles the optional argument REGEXP.

 -- Function: compat-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]+’.

     See Creating Strings (elisp).

     The compatibility version handles the optional arguments TRIM-LEFT
     and TRIM-RIGHT.

2.3.3 Missing Definitions
-------------------------

Compat does not provide support for the following Lisp features
implemented in 26.1:

   • The function ‘secure-hash-algorithms’.
   • The function ‘gnutls-avalaible-p’.
   • Support for records and record functions.
   • The function ‘mapbacktrace’.
   • The function ‘file-name-case-insensitive-p’.
   • The file-attributes constructors.
   • 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’.
   • Support for side windows and atomic windows.
   • All changes related to ‘display-buffer’.
   • The function ‘window-swap-states’.

2.4 Emacs 27.1
==============

2.4.1 Unprefixed Definitions
----------------------------

The following functions and macros implemented in 27.1, and are provided
by Compat by default:

 -- Function: proper-list-p object
     This function returns the length of OBJECT if it is a proper list,
     ‘nil’ otherwise (see Cons Cells (elisp)).  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

     See List-related Predicates (elisp).

 -- 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 (see Text Representations (elisp)); make the
     strings unibyte by encoding them (see Explicit Encoding (elisp))
     if you need accurate results with raw bytes.

     See Text Comparison (elisp).

 -- Function: json-serialize object &rest args
     This function returns a new Lisp string which contains the JSON
     representation of OBJECT.  The argument ARGS is a list of
     keyword/argument pairs.  The following keywords are accepted:

     ‘:null-object’
          The value decides which Lisp object to use to represent the
          JSON keyword ‘null’.  It defaults to the symbol ‘:null’.

     ‘:false-object’
          The value decides which Lisp object to use to represent the
          JSON keyword ‘false’.  It defaults to the symbol ‘:false’.

     See Parsing JSON (elisp).

 -- Function: json-insert object &rest args
     This function inserts the JSON representation of OBJECT into the
     current buffer before point.  The argument ARGS are interpreted as
     in ‘json-parse-string’.

     See Parsing JSON (elisp).

 -- Function: json-parse-string string &rest args
     This function parses the JSON value in STRING, which must be a Lisp
     string.  If STRING doesn’t contain a valid JSON object, this
     function signals the ‘json-parse-error’ error.

     The argument ARGS is a list of keyword/argument pairs.  The
     following keywords are accepted:

     ‘:object-type’
          The value decides which Lisp object to use for representing
          the key-value mappings of a JSON object.  It can be either
          ‘hash-table’, the default, to make hashtables with strings as
          keys; ‘alist’ to use alists with symbols as keys; or ‘plist’
          to use plists with keyword symbols as keys.

     ‘:array-type’
          The value decides which Lisp object to use for representing a
          JSON array.  It can be either ‘array’, the default, to use
          Lisp arrays; or ‘list’ to use lists.

     ‘:null-object’
          The value decides which Lisp object to use to represent the
          JSON keyword ‘null’.  It defaults to the symbol ‘:null’.

     ‘:false-object’
          The value decides which Lisp object to use to represent the
          JSON keyword ‘false’.  It defaults to the symbol ‘:false’.

     See Parsing JSON (elisp).

 -- Function: json-parse-buffer &rest args
     This function reads the next JSON value from the current buffer,
     starting at point.  It moves point to the position immediately
     after the value if contains a valid JSON object; otherwise it
     signals the ‘json-parse-error’ error and doesn’t move point.  The
     arguments ARGS are interpreted as in ‘json-parse-string’.

     See Parsing JSON (elisp).

 -- 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))

     See Handling Errors (elisp).

 -- 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))

     See Progress (elisp).

 -- 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)

     See Building Lists (elisp).

 -- 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.

     See Combining Conditions (elisp).

 -- 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.

     See Regexp Functions (elisp)

 -- Function: decoded-time-second time
     Return the SECONDS field of a ‘decoded-time’ record TIME.

 -- Function: decoded-time-minute time
     Return the MINUTE field of a ‘decoded-time’ record TIME.

 -- Function: decoded-time-hour time
     Return the HOUR field of a ‘decoded-time’ record TIME.

 -- Function: decoded-time-day time
     Return the DAY field of a ‘decoded-time’ record TIME.

 -- Function: decoded-time-month time
     Return the MONTH field of a ‘decoded-time’ record TIME.

 -- Function: decoded-time-year time
     Return the YEAR field of a ‘decoded-time’ record TIME.

 -- Function: decoded-time-weekday time
     Return the WEEKDAY field of a ‘decoded-time’ record TIME.

 -- Function: decoded-time-dst time
     Return the DST (daylight saving time indicator) field of a
     ‘decoded-time’ record TIME.

 -- Function: decoded-time-zone time
     Return the ZONE field of a ‘decoded-time’ record TIME.

 -- 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.

     See Time Calculations (elisp).

 -- Function: date-days-in-month year month
     Return the number of days in MONTH in YEAR.  For instance, February
     2020 has 29 days.

     See Time Calculations (elisp).  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’).
     See executable-find (elisp), 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.

     See Subprocess Creation (elisp).

 -- 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: derived-mode-p &rest modes
     This function returns non-‘nil’ if the current major mode is
     derived from any of the major modes given by the symbols MODES.

     See Derived Modes (elisp).

2.4.2 Prefixed Definitions
--------------------------

These functions are prefixed with ‘compat’ prefix, and are only loaded
when ‘compat-27’ is required:

 -- Function: compat-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.

     See Textual Scrolling (elisp).

     This compatibility version adds support for the optional argument
     REDISPLAY.

 -- Function: compat-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.

     See Low-Level Key Binding (elisp).

     This compatibility version allows for KEYMAP to be a list of
     keymaps, instead of just a singular keymap.

 -- Macro: 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")

     See Creating Buffer-Local (elisp).

     This compatibility version allows for more than one variable to be
     set at once, as can be done with ‘setq’.

 -- Function: compat-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.

     See Regexp Functions (elisp).

     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-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-assoc-delete-all
     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.

     See Association Lists (elisp).

     This compatibility version handles the optional third (TESTFN)
     argument.

 -- Function: compat-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’ (see Subprocess Creation (elisp)).

     If REMOTE is non-‘nil’, and ‘default-directory’ is a remote
     directory, PROGRAM is searched on the respective remote host.

     See Locating Files (elisp).

     This compatibility version adds support to handle the optional
     second (REMOTE) argument.

 -- Function: compat-dired-get-marked-files &optional localp arg filter
          distinguish-one-marked error
     Return a list of file names that are _marked_ in a Dired buffer.

     This compatibility version handles the optional fifth (ERROR)
     argument, which signals an error if the list of found files is
     empty.  ‘error’ can be a string with the error message.

2.4.3 Missing Definitions
-------------------------

Compat does not provide support for the following Lisp features
implemented in 27.1:

   • Bigint support.
   • The function ‘time-convert’.
   • All ‘iso8601-*’ functions.
   • The macro ‘benchmark-progn’.
   • The function ‘read-char-from-minibuffer’.
   • The minor mode ‘reveal-mode’.
   • The macro ‘with-suppressed-warnings’.
   • Support for ‘condition-case’ to handle t.
   • The functions ‘major-mode-suspend’ and ‘major-mode-restore’.
   • The function ‘provided-mode-derived-p’.
   • The function ‘file-system-info’.
   • The more consistent treatment of NaN values.
   • The function ‘ring-resize’.
   • The function ‘group-name’.
   • Additional ‘format-spec’ modifiers.
   • Support for additional body forms for
     ‘define-globalized-minor-mode’.
   • The macro ‘with-connection-local-variables’ and related
     functionality.

2.5 Emacs 28.1
==============

2.5.1 Unprefixed Definitions
----------------------------

The following functions and macros implemented in 28.1, and are provided
by Compat by default:

 -- 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’.

     See Calling Functions (elisp).

 -- 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.

     See Insertion (elisp).

 -- 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")
     Search and Replace (elisp).

 -- 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.

     See Search and Replace (elisp).

 -- 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.

     See Creating Buffer-Local (elisp).

 -- 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.

     See Testing Accessibility (elisp).

 -- 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 (see Dynamic Binding (elisp)),
     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.

     See Local Variables (elisp).

 -- 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))

     See Building Lists (elisp).

 -- 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.

     See Creating Strings (elisp).

 -- 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.

     See Creating Strings (elisp).

 -- Function: 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.

     See Creating Strings (elisp).

 -- 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.

     See Creating Strings (elisp).

 -- Function: string-chop-newline string
     Remove the final newline, if any, from STRING.

     See Creating Strings (elisp).

 -- 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.

     See Local Variables (elisp).

 -- 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’).

     See File Name Components (elisp).

 -- 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.

     See Contents of Directories (elisp).

 -- 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’ (see
     Formatting Strings (elisp)).

     ‘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.

     See Text from Minibuffer (elisp).

 -- 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: macroexp-file-name
     Return the name of the file in which the code is currently being
     evaluated, or ‘nil’ if it cannot be determined.

 -- 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))

     See System Environment (elisp).

 -- Function: button-buttonize string callback &optional data help-echo
     Return a button with STRING as its label.  When interacted on, the
     one-argument function in CALLBACK is called and DATA (or ‘nil’ is
     not present) will be passed as the argument.

     If non-‘nil’, the argument HELP-ECHO will be used to set the
     ‘help-echo’ text property.

 -- Function: make-directory-autoloads dir output-file
     Parse and search the directory DIR for autoload definitions, and
     write the processed results to the file OUTPUT-FILE.

 -- 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.

     See Changing Files (elisp).

 -- 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.

     See Backup Names (elisp).

 -- Function: make-lock-file-name filename
     Return a string containing a lock file name for FILENAME, obeying
     ‘lock-file-name-transforms’.

 -- Function: null-device
     Return the path to the null device (usually something like
     ‘/dev/null’) on the current system.

 -- 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 avaliable, this function behaves
     identically to ‘subrp’.

 -- Function: file-name-absolute-p filename
     This function returns ‘t’ if file FILENAME is an absolute file
     name, ‘nil’ otherwise.  A file name is considered to be absolute if
     its first component is ‘~’, or is ‘~USER’ where USER is a valid
     login name.  In the following examples, assume that there is a user
     named ‘rms’ but no user named ‘nosuchuser’.

          (file-name-absolute-p "~rms/foo")
               ⇒ t
          (file-name-absolute-p "~nosuchuser/foo")
               ⇒ nil
          (file-name-absolute-p "rms/foo")
               ⇒ nil
          (file-name-absolute-p "/user/rms/foo")
               ⇒ t

     See Absolute and Relative File Names (elisp).

2.5.2 Prefixed Definitions
--------------------------

These functions are prefixed with ‘compat’ prefix, and are only loaded
when ‘compat-28’ is required:

 -- Function: compat-unlock-buffer
     This function unlocks the file being visited in the current buffer,
     if the buffer is modified.  If the buffer is not modified, then the
     file should not be locked, so this function does nothing.  It also
     does nothing if the current buffer is not visiting a file, or is
     not locked.  This function handles file system errors by calling
     ‘display-warning’ and otherwise ignores the error.

     See File Locks (elisp).

     This compatibility versions catches the ‘file-error’ condition,
     issuing a warning instead of propagating on the error.

 -- Function: compat-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’ (see
     Creating Strings (elisp)).

     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.

     See Size of Displayed Text (elisp).

     This compatibility version handles the optional arguments FROM and
     TO.

 -- Function: compat-json-serialize
     See Emacs 27.1.

     This compatibility version handles primitive, top-level JSON values
     (numbers, strings, booleans).

 -- Function: compat-json-insert
     See Emacs 27.1.

     This compatibility version handles primitive, top-level JSON values
     (numbers, strings, booleans).

 -- Function: compat-json-parse-string
     See Emacs 27.1.

     This compatibility version handles primitive, top-level JSON values
     (numbers, strings, booleans).

 -- Function: compat-json-parse-buffer
     See Emacs 27.1.

     This compatibility version handles primitive, top-level JSON values
     (numbers, strings, booleans).

 -- Function: compat-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.5.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’.
   • "Success handler" for ‘condition-case’.
   • The function ‘benchmark-call’.
   • Support for the ‘natnum’ defcustom type.
   • The function ‘macroexp-compiling-p’.
   • The function ‘macroexp-warn-and-return’.
   • Additional Edebug keywords.
   • Shorthand support.
   • The function ‘custom-add-choice’.
   • The function ‘decoded-time-period’.
   • The function ‘dom-print’.
   • The function ‘dom-remove-attribute’.
   • The function ‘dns-query-asynchronous’.
   • The function ‘get-locale-names’.
   • The function ‘json-avaliable-p’.
   • The function ‘mail-header-parse-addresses-lax’.
   • The function ‘mail-header-parse-address-lax’.
   • The function ‘make-separator-line’.
   • The function ‘num-processors’.
   • The function ‘object-intervals’.
   • The function ‘process-lines-ignore-status’.
   • The function ‘require-theme’.
   • The function ‘syntax-class-to-char’.
   • The function ‘path-separator’.

3 Development
*************

Compat is developed on SourceHut (https://sr.ht/~pkal/compat).  A
restricted GitHub mirror (https://github.com/phikal/compat.el) is also
maintained.

   Patches and comments can be sent to the development mailing list
(https://lists.sr.ht/~pkal/compat-devel) (~pkal/compat-devel@lists.sr.ht
<~pkal/compat-devel@lists.sr.ht>).  Bug reports are best sent to the
issue tracker (https://todo.sr.ht/~pkal/compat) (~pkal/compat@todo.sr.ht
<~pkal/compat@todo.sr.ht>).  The GitHub mirror can also be used to
submit patches.  These may include issues in the compatibility code,
missing definitions or performance issues.

   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.