+++ /dev/null
-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
+++ /dev/null
-#+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>)
+++ /dev/null
-;;; 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
+++ /dev/null
-;;; 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
+++ /dev/null
-;;; 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
+++ /dev/null
-;;; 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
+++ /dev/null
-;;; 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
+++ /dev/null
-;;; 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
+++ /dev/null
-;;; 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
+++ /dev/null
-;; 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")
+++ /dev/null
-;;; 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
+++ /dev/null
-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:
+++ /dev/null
-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.
--- /dev/null
+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
--- /dev/null
+#+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>)
--- /dev/null
+;;; 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
--- /dev/null
+;;; 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
--- /dev/null
+;;; 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
--- /dev/null
+;;; 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
--- /dev/null
+;;; 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
--- /dev/null
+;;; 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
--- /dev/null
+;;; 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
--- /dev/null
+;; 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")
--- /dev/null
+;;; 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
--- /dev/null
+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:
--- /dev/null
+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.