emacs-elpa-diffs
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[elpa] externals/compat 62ec50bdd1 83/84: Merge branch 'emacs-29.1'


From: ELPA Syncer
Subject: [elpa] externals/compat 62ec50bdd1 83/84: Merge branch 'emacs-29.1'
Date: Tue, 3 Jan 2023 08:57:49 -0500 (EST)

branch: externals/compat
commit 62ec50bdd121baf8edc460ab5f7888da7c702eab
Merge: 1573aa2e6d 55080acac2
Author: Philip Kaludercic <philipk@posteo.net>
Commit: Philip Kaludercic <philipk@posteo.net>

    Merge branch 'emacs-29.1'
---
 .dir-locals.el      |    1 -
 Makefile            |    9 +-
 compat-24.el        |    4 +-
 compat-25.el        |   44 ++-
 compat-26.el        |  116 +++---
 compat-27.el        |   10 +-
 compat-28.el        |    4 +-
 compat-29.el        | 1049 +++++++++++++++++++++++++++++++++++++++++++++++++++
 compat-font-lock.el |    2 +-
 compat-help.el      |    2 +-
 compat-macs.el      |   27 +-
 compat-tests.el     |    2 +-
 compat.el           |   14 +-
 compat.texi         |  666 +++++++++++++++++++++++++++++++-
 14 files changed, 1842 insertions(+), 108 deletions(-)

diff --git a/.dir-locals.el b/.dir-locals.el
index 900dee5f90..6d22de33f5 100644
--- a/.dir-locals.el
+++ b/.dir-locals.el
@@ -2,6 +2,5 @@
 ;;; For more information see (info "(emacs) Directory Variables")
 
 ((emacs-lisp-mode
-  (byte-compile-docstring-max-column . 100)
   (show-trailing-whitespace . t)
   (indent-tabs-mode . nil)))
diff --git a/Makefile b/Makefile
index 776c125027..36c6635f68 100644
--- a/Makefile
+++ b/Makefile
@@ -6,12 +6,12 @@ EMACS = emacs
 MAKEINFO = makeinfo
 BYTEC = compat-help.elc \
        compat-font-lock.elc \
-       compat-macs.elc \
        compat-24.elc \
        compat-25.elc \
        compat-26.elc \
        compat-27.elc \
        compat-28.elc \
+       compat-29.elc \
        compat.elc
 
 all: compile
@@ -25,12 +25,7 @@ test: compile
 clean:
        $(RM) $(BYTEC) compat.info
 
-compat-24.el:  compat-macs.el
-compat-25.el:  compat-macs.el
-compat-26.el:  compat-macs.el
-compat-27.el:  compat-macs.el
-compat-28.el:  compat-macs.el
-compat-font-lock.el: compat-macs.el
+$(BYTEC): compat-macs.el
 
 .el.elc:
        $(EMACS) -Q --batch -L . -f batch-byte-compile $<
diff --git a/compat-24.el b/compat-24.el
index 51bd31e279..2a4e8a8a75 100644
--- a/compat-24.el
+++ b/compat-24.el
@@ -1,6 +1,6 @@
 ;;; compat-24.el --- Compatibility Layer for Emacs 24.4  -*- lexical-binding: 
t; -*-
 
-;; Copyright (C) 2021, 2022 Free Software Foundation, Inc.
+;; Copyright (C) 2021, 2022, 2023 Free Software Foundation, Inc.
 
 ;; Author: Philip Kaludercic <philipk@posteo.net>
 ;; Maintainer: Compat Development <~pkal/compat-devel@lists.sr.ht>
@@ -37,7 +37,7 @@
 
 ;;; Code:
 
-(require 'compat-macs "compat-macs.el")
+(eval-when-compile (load "compat-macs.el" nil t t))
 
 (compat-declare-version "24.4")
 
diff --git a/compat-25.el b/compat-25.el
index 471fbee8b2..181dada278 100644
--- a/compat-25.el
+++ b/compat-25.el
@@ -1,6 +1,6 @@
 ;;; compat-25.el --- Compatibility Layer for Emacs 25.1  -*- lexical-binding: 
t; -*-
 
-;; Copyright (C) 2021, 2022 Free Software Foundation, Inc.
+;; Copyright (C) 2021, 2022, 2023 Free Software Foundation, Inc.
 
 ;; Author: Philip Kaludercic <philipk@posteo.net>
 ;; Maintainer: Compat Development <~pkal/compat-devel@lists.sr.ht>
@@ -32,7 +32,7 @@
 
 ;;; Code:
 
-(require 'compat-macs "compat-macs.el")
+(eval-when-compile (load "compat-macs.el" nil t t))
 
 (compat-declare-version "25.1")
 
@@ -130,8 +130,6 @@ Equality with KEY is tested by TESTFN, defaulting to `eq'."
         default)))
     (if entry (cdr entry) default)))
 
-;;;; Defined in subr-x.el
-
 (compat-defmacro if-let (spec then &rest else)
   "Bind variables according to SPEC and evaluate THEN or ELSE.
 Evaluate each binding in turn, as in `let*', stopping if a
@@ -148,8 +146,6 @@ 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."
-  :realname compat--if-let
-  :feature 'subr-x
   (declare (indent 2)
            (debug ([&or (symbolp form)
                         (&rest [&or symbolp (symbolp form) (form)])]
@@ -158,7 +154,16 @@ with an old syntax that accepted only one binding."
              (not (listp (car spec))))
     ;; Adjust the single binding case
     (setq spec (list spec)))
-  `(compat--if-let* ,spec ,then ,(macroexp-progn else)))
+  (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)
   "Bind variables according to SPEC and conditionally evaluate BODY.
@@ -166,9 +171,26 @@ 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'."
-  :feature 'subr-x
-  (declare (indent 1) (debug if-let))
-  `(compat--if-let ,spec ,(macroexp-progn body)))
+  (declare (indent 1)
+           (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) ,(macroexp-progn body)))))
+
+;;;; Defined in subr-x.el
 
 (compat-defmacro thread-first (&rest forms)
   "Thread FORMS elements as the first argument of their successor.
@@ -289,7 +311,7 @@ recursion."
     (dolist (file (sort (file-name-all-completions "" dir)
                         'string<))
       (unless (member file '("./" "../"))
-        (if (directory-name-p file)
+        (if (compat--directory-name-p file)
             (let* ((leaf (substring file 0 (1- (length file))))
                    (full-file (concat dir "/" leaf)))
               ;; Don't follow symlinks to other directories.
diff --git a/compat-26.el b/compat-26.el
index 98f7b2fb43..127777cad8 100644
--- a/compat-26.el
+++ b/compat-26.el
@@ -1,6 +1,6 @@
 ;;; compat-26.el --- Compatibility Layer for Emacs 26.1  -*- lexical-binding: 
t; -*-
 
-;; Copyright (C) 2021, 2022 Free Software Foundation, Inc.
+;; Copyright (C) 2021, 2022, 2023 Free Software Foundation, Inc.
 
 ;; Author: Philip Kaludercic <philipk@posteo.net>
 ;; Maintainer: Compat Development <~pkal/compat-devel@lists.sr.ht>
@@ -37,7 +37,7 @@
 
 ;;; Code:
 
-(require 'compat-macs "compat-macs.el")
+(eval-when-compile (load "compat-macs.el" nil t t))
 
 (compat-declare-version "26.1")
 
@@ -155,6 +155,7 @@ from the absolute start of the buffer, disregarding the 
narrowing."
 
 (declare-function compat--alist-get-full-elisp "compat-25"
                   (key alist &optional default remove testfn))
+(declare-function alist-get nil (key alist &optional default remove))
 (compat-defun alist-get (key alist &optional default remove testfn)
   "Handle TESTFN manually."
   :realname compat--alist-get-handle-testfn
@@ -361,6 +362,61 @@ PREFIX is a string, and defaults to \"g\"."
                      (1+ gensym-counter)))))
     (make-symbol (format "%s%d" (or prefix "g") num))))
 
+(compat-defmacro if-let* (varlist then &rest else)
+  "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)
+  "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 ((&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)
+       (when ,(caar list) ,@body))))
+
+(compat-defmacro and-let* (varlist &rest body)
+  "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."
+  :feature 'subr-x
+  (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
 
 (declare-function temporary-file-directory nil)
@@ -534,62 +590,6 @@ inode-number and device-number."
           (error "Wrong attribute name '%S'" attr))))
     (nreverse result)))
 
-;;;; Defined in subr-x.el
-
-(compat-defmacro if-let* (varlist then &rest else)
-  "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."
-  :realname compat--if-let*
-  :feature 'subr-x
-  (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 ,(or (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)
-  "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."
-  ;; :feature 'subr-x
-  (declare (indent 1) (debug if-let*))
-  (let ((empty (make-symbol "s"))
-        (last t) list)
-    (dolist (var varlist)
-      (push `(,(if (cdr var) (car var) empty)
-              (and ,last ,(or (cadr var) (car var))))
-            list)
-      (when (or (cdr var) (consp (car var)))
-        (setq last (caar list))))
-    `(let* ,(nreverse list)
-       (when ,(caar list) ,@body))))
-
-(compat-defmacro and-let* (varlist &rest body)
-  "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."
-  :feature 'subr-x
-  (declare (indent 1) (debug if-let*))
-  (let ((empty (make-symbol "s"))
-        (last t) list)
-    (dolist (var varlist)
-      (push `(,(if (cdr var) (car var) empty)
-              (and ,last ,(or (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 image.el
 
 ;;* UNTESTED
diff --git a/compat-27.el b/compat-27.el
index 714df89618..9202d5ccc3 100644
--- a/compat-27.el
+++ b/compat-27.el
@@ -1,6 +1,6 @@
 ;;; compat-27.el --- Compatibility Layer for Emacs 27.1  -*- lexical-binding: 
t; -*-
 
-;; Copyright (C) 2021, 2022 Free Software Foundation, Inc.
+;; Copyright (C) 2021, 2022, 2023 Free Software Foundation, Inc.
 
 ;; Author: Philip Kaludercic <philipk@posteo.net>
 ;; Maintainer: Compat Development <~pkal/compat-devel@lists.sr.ht>
@@ -39,7 +39,7 @@
 
 ;;; Code:
 
-(require 'compat-macs "compat-macs.el")
+(eval-when-compile (load "compat-macs.el" nil t t))
 
 (compat-declare-version "27.1")
 
@@ -352,11 +352,7 @@ On Unix, absolute file names start with `/'.  In Emacs, an 
absolute
 file name can also start with an initial `~' or `~USER' component,
 where USER is a valid login name."
   ;; See definitions in filename.h
-  (let ((seperator
-         (eval-when-compile
-           (if (memq system-type '(cygwin windows-nt ms-dos))
-               "[\\/]" "/")))
-        (drive
+  (let ((drive
          (eval-when-compile
            (cond
             ((memq system-type '(windows-nt ms-dos))
diff --git a/compat-28.el b/compat-28.el
index a3dc769341..fc877b47e3 100644
--- a/compat-28.el
+++ b/compat-28.el
@@ -1,6 +1,6 @@
 ;;; compat-28.el --- Compatibility Layer for Emacs 28.1  -*- lexical-binding: 
t; -*-
 
-;; Copyright (C) 2021, 2022 Free Software Foundation, Inc.
+;; Copyright (C) 2021, 2022, 2023 Free Software Foundation, Inc.
 
 ;; Author: Philip Kaludercic <philipk@posteo.net>
 ;; Maintainer: Compat Development <~pkal/compat-devel@lists.sr.ht>
@@ -39,7 +39,7 @@
 
 ;;; Code:
 
-(require 'compat-macs "compat-macs.el")
+(eval-when-compile (load "compat-macs.el" nil t t))
 
 (compat-declare-version "28.1")
 
diff --git a/compat-29.el b/compat-29.el
new file mode 100644
index 0000000000..20076ff5b6
--- /dev/null
+++ b/compat-29.el
@@ -0,0 +1,1049 @@
+;;; compat-29.el --- Compatibility Layer for Emacs 29.1  -*- lexical-binding: 
t; -*-
+
+;; Copyright (C) 2021, 2022, 2023 Free Software Foundation, Inc.
+
+;; Author: Philip Kaludercic <philipk@posteo.net>
+;; 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:
+
+;; Find here the functionality added in Emacs 29.1, needed by older
+;; versions.
+;;
+;; Only load this library if you need to use one of the following
+;; functions:
+;;
+;; - `plist-get'
+;; - `plist-put'
+;; - `plist-member'
+;; - `define-key'
+
+;;; Code:
+
+(eval-when-compile (load "compat-macs.el" nil t t))
+
+(compat-declare-version "29.1")
+
+;;;; Defined in xdisp.c
+
+(compat-defun get-display-property (position prop &optional object properties)
+  "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))))
+
+;;* UNTESTED
+(compat-defun buffer-text-pixel-size
+    (&optional buffer-or-name window x-limit y-limit)
+  "Return size of whole text of BUFFER-OR-NAME in WINDOW.
+BUFFER-OR-NAME must specify a live buffer or the name of a live buffer
+and defaults to the current buffer.  WINDOW must be a live window and
+defaults to the selected one.  The return value is a cons of the maximum
+pixel-width of any text line and the pixel-height of all the text lines
+of the buffer specified by BUFFER-OR-NAME.
+
+The optional arguments X-LIMIT and Y-LIMIT have the same meaning as with
+`window-text-pixel-size'.
+
+Do not use this function if the buffer specified by BUFFER-OR-NAME is
+already displayed in WINDOW.  `window-text-pixel-size' is cheaper in
+that case because it does not have to temporarily show that buffer in
+WINDOW."
+  :realname compat--buffer-text-pixel-size
+  (setq buffer-or-name (or buffer-or-name (current-buffer)))
+  (setq window (or window (selected-window)))
+  (save-window-excursion
+    (set-window-buffer window buffer-or-name)
+    (window-text-pixel-size window nil nil x-limit y-limit)))
+
+;;;; Defined in fns.c
+
+(compat-defun ntake (n list)
+  "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)
+  "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)
+  "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)
+  "Extract a value from a property list.
+PLIST is a property list, which is a list of the form
+\(PROP1 VALUE1 PROP2 VALUE2...).
+
+This function returns the value corresponding to the given PROP, or
+nil if PROP is not one of the properties on the list.  The comparison
+with PROP is done using PREDICATE, which defaults to `eq'.
+
+This function doesn't signal an error if PLIST is invalid."
+  :prefix 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)
+  "Change value in PLIST of PROP to VAL.
+PLIST is a property list, which is a list of the form
+\(PROP1 VALUE1 PROP2 VALUE2 ...).
+
+The comparison with PROP is done using PREDICATE, which defaults to `eq'.
+
+If PROP is already a property on the list, its value is set to VAL,
+otherwise the new PROP VAL pair is added.  The new plist is returned;
+use `(setq x (plist-put x prop val))' to be sure to use the new value.
+The PLIST is modified by side effects."
+  :prefix 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)
+  "Return non-nil if PLIST has the property PROP.
+PLIST is a property list, which is a list of the form
+\(PROP1 VALUE1 PROP2 VALUE2 ...).
+
+The comparison with PROP is done using PREDICATE, which 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 PROP."
+  :prefix 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 keymap.c
+
+(compat-defun define-key (keymap key def &optional remove)
+  "In KEYMAP, define key sequence KEY as DEF.
+This is a legacy function; see `keymap-set' for the recommended
+function to use instead.
+
+KEYMAP is a keymap.
+
+KEY is a string or a vector of symbols and characters, representing a
+sequence of keystrokes and events.  Non-ASCII characters with codes
+above 127 (such as ISO Latin-1) can be represented by vectors.
+Two types of vector have special meanings:
+ [remap COMMAND] remaps any key binding for COMMAND.
+ [t] creates a default definition, which applies to any event with no
+    other definition in KEYMAP.
+
+DEF 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'.)
+
+If REMOVE 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, and with a nil DEF, the lookups will return nil.
+
+If KEYMAP is a sparse keymap with a binding for KEY, the existing
+binding is altered.  If there is no binding for KEY, the new pair
+binding KEY to DEF is added at the front of KEYMAP."
+  :realname compat--define-key-with-remove
+  :prefix t
+  (if remove
+      (let ((prev (lookup-key keymap key))
+            (parent (memq 'key (cdr keymap)))
+            fresh entry)
+        (when prev
+          ;; IMPROVEME: Kind of a hack to avoid relying on the specific
+          ;; behaviour of how `define-key' changes KEY before inserting
+          ;; it into the map.
+          (define-key keymap key (setq fresh (make-symbol "fresh")))
+          (setq entry (rassq fresh (cdr keymap)))
+          (if (> (length (memq entry (cdr keymap)))
+                 (length parent))
+              ;; Ensure that we only remove an element in the current
+              ;; keymap and not a parent, by ensuring that `entry' is
+              ;; located before `parent'.
+              (ignore (setcdr keymap (delq entry (cdr keymap))))
+            (define-key keymap key prev))))
+    (define-key keymap key def)))
+
+;;;; Defined in subr.el
+
+(compat-defun function-alias-p (func &optional noerror)
+  "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))))
+
+(declare-function compat--provided-mode-derived-p
+                  "compat-27" (mode &rest modes))
+(declare-function compat--func-arity
+                  "compat-26" (func))
+
+;;* UNTESTED
+(compat-defun buffer-match-p (condition buffer-or-name &optional arg)
+  "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 cdr 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."
+  :realname compat--buffer-match-p
+  (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)
+                      (if (eq 1 (cdr (compat--func-arity condition)))
+                          (funcall condition buffer)
+                        (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)
+                      (compat--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 conditions))
+                          (unless (funcall match c)
+                            (throw 'fail nil)))
+                        t)))
+                (throw 'match t)))))))
+    (funcall match (list condition))))
+
+;;* UNTESTED
+(compat-defun match-buffers (condition &optional buffers arg)
+  "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 (compat--buffer-match-p condition (get-buffer buf) arg)
+        (push buf bufs)))
+    bufs))
+
+;;;; Defined in subr-x.el
+
+(compat-defun string-limit (string length &optional end coding-system)
+  "Return a substring of STRING that is (up to) LENGTH characters long.
+If STRING is shorter than or equal to LENGTH characters, return the
+entire string unchanged.
+
+If STRING is longer than LENGTH characters, return a substring
+consisting of the first LENGTH characters of STRING.  If END is
+non-nil, return the last LENGTH characters instead.
+
+If CODING-SYSTEM is non-nil, STRING will be encoded before
+limiting, and LENGTH is interpreted as the number of bytes to
+limit the string to.  The result will be a unibyte string that is
+shorter than LENGTH, but will not contain \"partial\" characters,
+even if CODING-SYSTEM encodes characters with several bytes per
+character.
+
+When shortening strings for display purposes,
+`truncate-string-to-width' is almost always a better alternative
+than this function."
+  :feature 'subr-x
+  (unless (natnump length)
+    (signal 'wrong-type-argument (list 'natnump length)))
+  (if coding-system
+      (let ((result nil)
+            (result-length 0)
+            (index (if end (1- (length string)) 0)))
+        (while (let ((encoded (encode-coding-char
+                               (aref string index) coding-system)))
+                 (and (<= (+ (length encoded) result-length) length)
+                      (progn
+                        (push encoded result)
+                        (setq result-length
+                              (+ result-length (length encoded)))
+                        (setq index (if end (1- index)
+                                      (1+ index))))
+                      (if end (> index -1)
+                        (< index (length string)))))
+          ;; No body.
+          )
+        (apply #'concat (if end result (nreverse result))))
+    (cond
+     ((<= (length string) length) string)
+     (end (substring string (- (length string) length)))
+     (t (substring string 0 length)))))
+
+;;* UNTESTED
+(compat-defun string-pixel-width (string)
+  "Return the width of STRING in pixels."
+  :feature 'subr-x
+  (if (zerop (length string))
+      0
+    ;; Keeping a work buffer around is more efficient than creating a
+    ;; new temporary buffer.
+    (with-current-buffer (get-buffer-create " *string-pixel-width*")
+      (delete-region (point-min) (point-max))
+      (insert string)
+      (car (compat--buffer-text-pixel-size nil nil t)))))
+
+;;* UNTESTED
+(compat-defmacro with-buffer-unmodified-if-unchanged (&rest 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.
+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."
+  :feature 'subr-x
+  (declare (debug t) (indent 0))
+  (let ((hash (make-symbol "hash"))
+        (buffer (make-symbol "buffer")))
+    `(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))))))))
+
+;;* UNTESTED
+(compat-defun 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."
+  :feature 'subr-x
+  (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))
+        ;; 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.
+          (let ((old (assoc prop disp)))
+            (when old (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)))
+      (setq sub-start sub-end))))
+
+(compat-defmacro while-let (spec &rest body)
+  "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 ((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))))
+    `(while (let* ,(nreverse list)
+              (and ,(caar list)
+                   (progn ,(macroexp-progn (or body '(t))) t))))))
+
+;;;; Defined in files.el
+
+(compat-defun file-parent-directory (filename)
+  "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 parent expanded-filename))
+      nil)
+     ;; filename is relative, return relative parent
+     ((not (file-name-absolute-p filename))
+      (file-relative-name parent))
+     (t
+      parent))))
+
+(defvar compat--file-has-changed-p--hash-table (make-hash-table :test #'equal)
+  "Internal variable used by `file-has-changed-p'.")
+
+;;* UNTESTED
+(compat-defun file-has-changed-p (file &optional tag)
+  "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 (nth 7 fileattr)
+                         (nth 5 fileattr))))
+        (sym (concat (symbol-name tag) "@" file))
+        (cachedattr (gethash sym compat--file-has-changed-p--hash-table)))
+     (when (not (equal attr cachedattr))
+       (puthash sym attr compat--file-has-changed-p--hash-table))))
+
+;;;; Defined in keymap.el
+
+(compat-defun 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:
+
+   A-C-H-M-S-s
+
+which is
+
+   Alt-Control-Hyper-Meta-Shift-super"
+  :realname compat--key-valid-p
+  (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 key-parse (keys)
+  "Convert KEYS to the internal Emacs key representation.
+See `kbd' for a descripion of KEYS."
+  :realname compat--key-parse
+  (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)))
+
+;;* UNTESTED
+(compat-defun keymap-set (keymap key definition)
+  "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'.)"
+  :realname compat--keymap-set
+  (unless (compat--key-valid-p key)
+    (error "%S is not a valid key definition; see `key-valid-p'" key))
+  ;; If we're binding this key to another key, then parse that other
+  ;; key, too.
+  (when (stringp definition)
+    (unless (compat--key-valid-p key)
+      (error "%S is not a valid key definition; see `key-valid-p'" key))
+    (setq definition (compat--key-parse definition)))
+  (define-key keymap (compat--key-parse key) definition))
+
+;;* UNTESTED
+(compat-defun keymap-unset (keymap key &optional remove)
+  "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."
+  :realname compat--keymap-unset
+  (unless (compat--key-valid-p key)
+    (error "%S is not a valid key definition; see `key-valid-p'" key))
+  (compat--define-key-with-remove keymap (compat--key-parse key) nil remove))
+
+;;* UNTESTED
+(compat-defun keymap-global-set (key command)
+  "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 of is not a command."
+  (compat--keymap-set (current-global-map) key command))
+
+;;* UNTESTED
+(compat-defun keymap-local-set (key command)
+  "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 of is not a command."
+  (let ((map (current-local-map)))
+    (unless map
+      (use-local-map (setq map (make-sparse-keymap))))
+    (compat--keymap-set map key command)))
+
+;;* UNTESTED
+(compat-defun keymap-global-unset (key &optional remove)
+  "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 of is not a command."
+  (compat--keymap-unset (current-global-map) key remove))
+
+;;* UNTESTED
+(compat-defun keymap-local-unset (key &optional remove)
+  "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 of is not a command."
+  (when (current-local-map)
+    (compat--keymap-unset (current-local-map) key remove)))
+
+;;* UNTESTED
+(compat-defun 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.
+
+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)))
+
+;;* UNTESTED
+(compat-defun keymap-set-after (keymap key definition &optional 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."
+  (unless (compat--key-valid-p key)
+    (error "%S is not a valid key definition; see `key-valid-p'" key))
+  (when after
+    (unless (compat--key-valid-p key)
+      (error "%S is not a valid key definition; see `key-valid-p'" key)))
+  (define-key-after keymap (compat--key-parse key) definition
+    (and after (compat--key-parse after))))
+
+(compat-defun 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."
+  :realname compat--keymap-lookup
+  (unless (compat--key-valid-p key)
+    (error "%S is not a valid key definition; see `key-valid-p'" key))
+  (when (and keymap position)
+    (error "Can't pass in both keymap and position"))
+  (if keymap
+      (let ((value (lookup-key keymap (compat--key-parse key) accept-default)))
+        (if (and (not no-remap)
+                   (symbolp value))
+            (or (command-remapping value) value)
+          value))
+    (key-binding (kbd key) accept-default no-remap position)))
+
+;;* UNTESTED
+(compat-defun keymap-local-lookup (keys &optional accept-default)
+  "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."
+  (let ((map (current-local-map)))
+    (when map
+      (compat--keymap-lookup map keys accept-default))))
+
+;;* UNTESTED
+(compat-defun keymap-global-lookup (keys &optional accept-default _message)
+  "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 of is not a command."
+  (compat--keymap-lookup (current-global-map) keys accept-default))
+
+;;* UNTESTED
+(compat-defun define-keymap (&rest definitions)
+  "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)))))
+      (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)
+              (compat--keymap-set keymap key def)))))
+      keymap)))
+
+;;* UNTESTED
+(compat-defmacro defvar-keymap (variable-name &rest defs)
+  "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.
+
+\(fn VARIABLE-NAME &key DOC FULL PARENT SUPPRESS NAME PREFIX KEYMAP &rest [KEY 
DEFINITION]...)"
+  (declare (indent 1))
+  (let ((opts nil)
+        doc)
+    (while (and defs
+                (keywordp (car defs))
+                (not (eq (car defs) :menu)))
+      (let ((keyword (pop defs)))
+        (unless defs
+          (error "Uneven number of keywords"))
+        (if (eq keyword :doc)
+            (setq doc (pop defs))
+          (push keyword opts)
+          (push (pop defs) opts))))
+    (unless (zerop (% (length defs) 2))
+      (error "Uneven number of key/definition pairs: %s" defs))
+    `(defvar ,variable-name
+       (define-keymap ,@(nreverse opts) ,@defs)
+       ,@(and doc (list doc)))))
+
+(provide 'compat-29)
+;;; compat-29.el ends here
diff --git a/compat-font-lock.el b/compat-font-lock.el
index 66a62e5522..5a8626fb99 100644
--- a/compat-font-lock.el
+++ b/compat-font-lock.el
@@ -1,6 +1,6 @@
 ;;; compat-font-lock.el ---                          -*- lexical-binding: t; 
-*-
 
-;; Copyright (C) 2022 Free Software Foundation, Inc.
+;; Copyright (C) 2022, 2023 Free Software Foundation, Inc.
 
 ;; Author: Philip Kaludercic <philipk@posteo.net>
 ;; Keywords:
diff --git a/compat-help.el b/compat-help.el
index 440e35f24c..a796d944d8 100644
--- a/compat-help.el
+++ b/compat-help.el
@@ -1,6 +1,6 @@
 ;;; compat-help.el --- Documentation for compat functions  -*- 
lexical-binding: t; -*-
 
-;; Copyright (C) 2022  Free Software Foundation, Inc.
+;; Copyright (C) 2022, 2023  Free Software Foundation, Inc.
 
 ;; Author: Philip Kaludercic <philipk@posteo.net>
 
diff --git a/compat-macs.el b/compat-macs.el
index cfd5d27600..75a2e9a3a8 100644
--- a/compat-macs.el
+++ b/compat-macs.el
@@ -1,6 +1,6 @@
 ;;; compat-macs.el --- Compatibility Macros           -*- lexical-binding: t; 
no-byte-compile: t; -*-
 
-;; Copyright (C) 2021, 2022 Free Software Foundation, Inc.
+;; Copyright (C) 2021, 2022, 2023 Free Software Foundation, Inc.
 
 ;; Author: Philip Kaludercic <philipk@posteo.net>
 ;; Keywords: lisp
@@ -195,13 +195,24 @@ attributes (see `compat-generate-common')."
                        ((eq type 'macro) "macro")
                        ((eq type 'advice) "advice")
                        ((error "Unknown type")))))
-            (if version
-                (format
-                 "[Compatibility %s for `%S', defined in Emacs %s]\n\n%s"
-                 type oldname version docstring)
-              (format
-               "[Compatibility %s for `%S']\n\n%s"
-               type oldname docstring)))
+            (with-temp-buffer
+              (insert docstring)
+              (newline 2)
+              (insert
+               "[Compatibility "
+               (if version
+                   (format
+                    "%s for `%S', defined in Emacs %s.  \
+If this is not documented on your system, you can check \
+`(compat) Emacs %s' for more details."
+                     type oldname version version)
+                 (format
+                  "code %s for `%S'"
+                  type oldname))
+               "]")
+              (let ((fill-column 80))
+                (fill-region (point-min) (point-max)))
+              (buffer-string)))
          ;; Advice may use the implicit variable `oldfun', but
          ;; to avoid triggering the byte compiler, we make
          ;; sure the argument is used at least once.
diff --git a/compat-tests.el b/compat-tests.el
index 4f15e41aef..8c48733b96 100644
--- a/compat-tests.el
+++ b/compat-tests.el
@@ -1,6 +1,6 @@
 ;;; compat-tests.el --- Tests for compat.el      -*- lexical-binding: t; -*-
 
-;; Copyright (C) 2021, 2022 Free Software Foundation, Inc.
+;; Copyright (C) 2021, 2022, 2023 Free Software Foundation, Inc.
 
 ;; Author: Philip Kaludercic <philipk@posteo.net>
 ;; Package-Requires: ((emacs "28.1"))
diff --git a/compat.el b/compat.el
index 921f4f8bd9..cfe3bf7e53 100644
--- a/compat.el
+++ b/compat.el
@@ -1,10 +1,10 @@
 ;;; compat.el --- Emacs Lisp Compatibility Library -*- lexical-binding: t; -*-
 
-;; Copyright (C) 2021, 2022 Free Software Foundation, Inc.
+;; Copyright (C) 2021, 2022, 2023 Free Software Foundation, Inc.
 
 ;; Author: Philip Kaludercic <philipk@posteo.net>
 ;; Maintainer: Compat Development <~pkal/compat-devel@lists.sr.ht>
-;; Version: 28.1.2.2
+;; Version: 29.1.0.0-dev
 ;; URL: https://sr.ht/~pkal/compat
 ;; Package-Requires: ((emacs "24.3") (nadvice "0.3"))
 ;; Keywords: lisp
@@ -47,12 +47,10 @@
   ;; the file (which is disabled by `compat--inhibit-prefixed', so
   ;; that the file can be loaded again at some later point when the
   ;; prefixed definitions are needed).
-  (dolist (vers '(24 25 26 27 28))
-    (unless (memq (intern (format "compat-%d" vers)) features)
-      (load (format "compat-%d%s" vers
-                    (if (bound-and-true-p compat-testing)
-                        ".el" ""))
-            nil t))))
+  (dolist (version '(24 25 26 27 28 29))
+    (let ((feature-name (format "compat-%d" version)))
+      (unless (memq (intern feature-name) features)
+        (load feature-name nil t)))))
 
 (provide 'compat)
 ;;; compat.el ends here
diff --git a/compat.texi b/compat.texi
index 9953269545..543e2ffa86 100644
--- a/compat.texi
+++ b/compat.texi
@@ -7,7 +7,7 @@
 @c %**end of header
 
 @copying
-Copyright @copyright{} 2022  Free Software Foundation, Inc.
+Copyright @copyright{} 2022, 2023  Free Software Foundation, Inc.
 
 @quotation
 Permission is granted to copy, distribute and/or modify this document
@@ -78,6 +78,7 @@ Support
 * 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
 
 @end detailmenu
 @end menu
@@ -2367,6 +2368,669 @@ The function @code{path-separator}.
 Any @code{multisession} functionality.
 @end itemize
 
+@node Emacs 29.1
+@section Emacs 29.1
+
+@subsection Unprefixed Definitions
+The following functions and macros implemented in 29.1, and are
+@b{not} provided by Compat by default.  You will need to require
+@code{compat-29} for these to be loaded.  Note that due to upstream
+changes, it might happen that there will be the need for changes, so use
+these functions with care.
+
+With the eventual release of Compat 29.1.0.0, these functions will be
+loaded by default:
+
+@c copied from lispref/display.texi
+@defun get-display-property position prop &optional object properties
+This convenience function can be used to get a specific display
+property, no matter whether the @code{display} property is a vector, a
+list or a simple property.  This is like @code{get-text-property}
+(@pxref{Examining Properties,Examining Properties,,elisp,}), but works
+on the @code{display} property only.
+
+@var{position} is the position in the buffer or string to examine, and
+@var{prop} is the @code{display} property to return.  The optional
+@var{object} argument should be either a string or a buffer, and
+defaults to the current buffer.  If the optional @var{properties}
+argument is non-@code{nil}, it should be a @code{display} property,
+and in that case, @var{position} and @var{object} are ignored.  (This
+can be useful if you've already gotten the @code{display} property
+with @code{get-char-property}, for instance (@pxref{Examining
+Properties,Examining
+Properties,,elisp,}).
+@end defun
+
+@c copied from lisp/subr-x.el
+@defun add-display-text-property start end prop value &optional object
+Add display property @var{prop} with @var{value} to the text from
+@var{start} to @var{end}.  If any text in the region has a non-nil
+@code{display} property, those properties are retained.
+
+If @var{object} is non-@code{nil}, it should be a string or a buffer.
+If @code{nil}, this defaults to the current buffer.
+@end defun
+
+@c copied from lispref/lists.texi
+@defun take n list
+This function returns the @var{n} first elements of @var{list}.  Essentially,
+it returns the part of @var{list} that @code{nthcdr} skips.
+
+@code{take} returns @var{list} if shorter than @var{n} elements;
+it returns @code{nil} if @var{n} is zero or negative.
+
+@example
+@group
+(take 3 '(a b c d))
+     @result{} (a b c)
+@end group
+@group
+(take 10 '(a b c d))
+     @result{} (a b c d)
+@end group
+@group
+(take 0 '(a b c d))
+     @result{} nil
+@end group
+@end example
+@end defun
+
+@c copied from lispref/lists.texi
+@defun ntake n list
+This is a version of @code{take} that works by destructively modifying
+the list structure of the argument.  That makes it faster, but the
+original value of @var{list} may be lost.
+
+@code{ntake} returns @var{list} unmodified if shorter than @var{n}
+elements; it returns @code{nil} if @var{n} is zero or negative.
+Otherwise, it returns @var{list} truncated to its first @var{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 @var{n} is known to be
+positive.
+@end defun
+
+@c copied from lispref/functions.texi
+@defun function-alias-p object &optional noerror
+Checks whether @var{object} is a function alias.  If it is, it returns
+a list of symbols representing the function alias chain, else
+@code{nil}.  For instance, if @code{a} is an alias for @code{b}, and
+@code{b} is an alias for @code{c}:
+
+@example
+(function-alias-p 'a)
+    @result{} (b c)
+@end example
+
+If there's a loop in the definitions, an error will be signalled.  If
+@var{noerror} is non-@code{nil}, the non-looping parts of the chain is
+returned instead.
+@end defun
+
+@c copied from lispref/strings.texi
+@defun string-limit string length &optional end coding-system
+If @var{string} is shorter than @var{length} characters, @var{string}
+is returned as is.  Otherwise, return a substring of @var{string}
+consisting of the first @var{length} characters.  If the optional
+@var{end} parameter is given, return a string of the @var{length} last
+characters instead.
+
+If @var{coding-system} is non-@code{nil}, @var{string} will be encoded
+before limiting, and the result will be a unibyte string that's
+shorter than @code{length} bytes.  If @var{string} contains characters
+that are encoded into several bytes (for instance, when using
+@code{utf-8}), the resulting unibyte string is never truncated in the
+middle of a character representation.
+
+This function measures the string length in characters or bytes, and
+thus is generally inappropriate if you need to shorten strings for
+display purposes; use @code{truncate-string-to-width} or
+@code{window-text-pixel-size} or @code{string-glyph-split} instead
+(@pxref{Size of Displayed Text,Size of Displayed Text,,elisp,}).
+@end defun
+
+@c copied from lispref/display.texi
+@defun buffer-text-pixel-size &optional buffer-or-name window x-limit y-limit
+This is much like @code{window-text-pixel-size}, but can be used when
+the buffer isn't shown in a window.  (@code{window-text-pixel-size} is
+faster when it is, so this function shouldn't be used in that case.)
+
+@var{buffer-or-name} must specify a live buffer or the name of a live
+buffer and defaults to the current buffer.  @var{window} must be a
+live window and defaults to the selected one; the function will
+compute the text dimensions as if @var{buffer} is displayed in
+@var{window}.  The return value is a cons of the maximum pixel-width
+of any text line and the pixel-height of all the text lines of the
+buffer specified by @var{buffer-or-name}.
+
+The optional arguments @var{x-limit} and @var{y-limit} have the same
+meaning as with @code{window-text-pixel-size}.
+
+@xref{Size of Displayed Text,,,elisp}.
+@end defun
+
+@c copied from lispref/strings.texi
+@defun string-equal-ignore-case string1 string2
+@code{string-equal-ignore-case} compares strings ignoring case
+differences, like @code{char-equal} when @code{case-fold-search} is
+@code{t}.
+
+@xref{Text Comparison,,,elisp}.
+@end defun
+
+@c copied from lispref/buffers.texi
+@defun buffer-match-p condition buffer-or-name &optional arg
+This function checks if a buffer designated by @code{buffer-or-name}
+satisfies a @code{condition}.  Optional third argument @var{arg} is
+passed to the predicate function in @var{condition}.  A condition can
+be one of the following:
+@itemize @bullet{}
+@item
+A string, interpreted as a regular expression.  The buffer
+satisfies the condition if the regular expression matches the buffer
+name.
+@item
+A predicate function, which should return non-@code{nil} if the buffer
+matches.  If the function expects one argument, it is called with
+@var{buffer-or-name} as the argument; if it expects 2 arguments, the
+first argument is @var{buffer-or-name} and the second is @var{arg}
+(or @code{nil} if @var{arg} is omitted).
+@item
+A cons-cell @code{(@var{oper} . @var{expr})} where @var{oper} is one
+of
+@table @code
+@item not
+Satisfied if @var{expr} doesn't satisfy @code{buffer-match-p} with
+the same buffer and @code{arg}.
+@item or
+Satisfied if @var{expr} is a list and @emph{any} condition in
+@var{expr} satisfies @code{buffer-match-p}, with the same buffer and
+@code{arg}.
+@item and
+Satisfied if @var{expr} is a list and @emph{all} conditions in
+@var{expr} satisfy @code{buffer-match-p}, with the same buffer and
+@code{arg}.
+@item derived-mode
+Satisfied if the buffer's major mode derives from @var{expr}.
+@item major-mode
+Satisfied if the buffer's major mode is equal to @var{expr}.  Prefer
+using @code{derived-mode} instead when both can work.
+@end table
+@item t
+Satisfied by any buffer.  A convenient alternative to @code{""} (empty
+string), @code{(and)} (empty conjunction) or @code{always}.
+@end itemize
+
+@xref{Buffer List,,,elisp}.
+@end defun
+
+@c copied from lispref/buffers.texi
+@defun match-buffers condition &optional buffers arg
+This function returns a list of all buffers that satisfy a
+@code{condition}, as defined for @code{buffer-match-p}.  By default
+all buffers are considered, but this can be restricted via the second
+optional @code{buffer-list} argument.  Optional third argument
+@var{arg} will be used by @var{condition} in the same way as
+@code{buffer-match-p} does.
+
+@xref{Buffer List,,,elisp}.
+@end defun
+
+@c copied from lispref/display.texi
+@defun string-pixel-width string
+This is a convenience function that uses @code{window-text-pixel-size}
+to compute the width of @var{string} (in pixels).
+
+@xref{Size of Displayed Text,,,elisp}.
+@end defun
+
+@c copied from lispref/display.texi
+@defun string-glyph-split string
+When character compositions are in effect, sequence of characters can
+be composed for display to form @emph{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 @var{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 @var{string} which will
+look correctly on display, or compute the width of any substring of
+@var{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:
+
+@example
+(apply #'insert (cdr (string-glyph-split string))))
+@end example
+
+@xref{Size of Displayed Text,,,elisp}.
+@end defun
+
+@c based on lisp/subr-x.el
+@defmac with-buffer-unmodified-if-unchanged &rest body@dots{}
+Evaluate @var{body} like @code{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, @code{buffer-file-coding-system}, buffer multibyteness,
+etc. -- will not be noticed, and the buffer will still be marked
+unmodified, effectively ignoring those changes.
+@end defmac
+
+@c copied from lispref/files.texi
+@defun file-parent-directory filename
+This function returns the directory name of the parent directory of
+@var{filename}.  If @var{filename} is at the root directory of the
+filesystem, it returns @code{nil}.  A relative @var{filename} is
+assumed to be relative to @code{default-directory}, and the return
+value will also be relative in that case.  If the return value is
+non-@code{nil}, it ends in a slash.
+
+@xref{Directory Names,,,elisp}.
+@end defun
+
+@c copied from lispref/files.texi
+@defun file-has-changed-p file &optional tag
+This function returns non-@code{nil} if the time stamp of
+@var{filename} has changed since the last call.  When called for the
+first time for some @var{filename}, it records the last modification
+time and size of the file, and returns non-@code{nil} when
+@var{filename} exists.  Thereafter, when called for the same
+@var{filename}, it compares the current time stamp and size with the
+recorded ones, and returns non-@code{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 @var{tag}, which must be a symbol, the size and modification
+time comparisons are limited to calls with the same tag.
+
+@xref{File Attributes,,,elisp}.
+@end defun
+
+@c based on lisp/keymap.el
+@defun key-valid-p keys
+Say whether @var{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.
+
+@table @kbd
+@item f
+The key @kbd{f}.
+@item S o m
+A three key sequence of the keys @kbd{S}, @kbd{o} and @kbd{m}.
+@item C-c o
+A two key sequence of the keys @kbd{c} with the control modifier and
+then the key @kbd{o}.
+@item H-<left>
+The key named "left" with the hyper modifier.
+@item M-RET
+The "return" key with a meta modifier.
+@item C-M-<space>
+The "space" key with both the control and meta modifiers.
+@end table
+
+These are the characters that have shorthand syntax:
+@kbd{NUL}, @kbd{RET}, @kbd{TAB}, @kbd{LFD}, @kbd{ESC}, @kbd{SPC}, @kbd{DEL}.
+
+Modifiers have to be specified in this order
+@verbatim
+Alt (A)-Control (C)-Hyper (H)-Meta (M)-Shift (s)-Super (s)
+@end verbatim
+@end defun
+
+@c based on lisp/keymap.el and lisp/subr.el
+@defun key-parse keys
+Convert @var{keys} to the internal Emacs key representation.  See
+@code{key-valid-p} for a description of valid key sequences.  Examples
+include @kbd{f}, @kbd{C-c C-c}, @kbd{H-<left>}, @kbd{M-RET} or
+@kbd{C-M-<return>}.
+
+@end defun
+
+@c copied from lispref/keymaps.texi
+@defun keymap-set keymap key definition
+This function sets the binding for @var{key} in @var{keymap}.  (If
+@var{key} is more than one event long, the change is actually made in
+another keymap reached from @var{keymap}.)  The argument @var{binding}
+can be any Lisp object, but only certain types are meaningful.  (For a
+list of meaningful types, see @ref{Key Lookup,,,elisp}.)  The value
+returned by @code{keymap-set} is @var{binding}.
+
+If @var{key} is @kbd{<t>}, this sets the default binding in
+@var{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 @var{key} must be a prefix key (i.e., bound to a keymap)
+or undefined; otherwise an error is signaled.  If some prefix of
+@var{key} is undefined, then @code{keymap-set} defines it as a prefix
+key so that the rest of @var{key} can be defined as specified.
+
+If there was previously no binding for @var{key} in @var{keymap}, the
+new binding is added at the beginning of @var{keymap}.  The order of
+bindings in a keymap makes no difference for keyboard input, but it
+does matter for menu keymaps (@pxref{Menu Keymaps,,,elisp}).
+
+@xref{Changing Key Bindings,,,elisp}.
+@end defun
+
+@c copied from lispref/keymaps.texi
+@defun keymap-global-set key command
+This function sets the binding of @var{key} in the current global map
+to @var{binding}.
+
+@smallexample
+@group
+(keymap-global-set @var{key} @var{binding})
+@equiv{}
+(keymap-set (current-global-map) @var{key} @var{binding})
+@end group
+@end smallexample
+
+@xref{Key Binding Commands,,,elisp}.
+@end defun
+
+@c copied from lispref/keymaps.texi
+@defun keymap-local-set key command
+This function sets the binding of @var{key} in the current local
+keymap to @var{binding}.
+
+@smallexample
+@group
+(keymap-local-set @var{key} @var{binding})
+@equiv{}
+(keymap-set (current-local-map) @var{key} @var{binding})
+@end group
+@end smallexample
+
+@xref{Key Binding Commands,,,elisp}.
+@end defun
+
+@c copied from lispref/keymaps.texi
+@defun keymap-global-unset key &optional remove
+This function removes the binding of @var{key} from the current
+global map.
+
+One use of this function is in preparation for defining a longer key
+that uses @var{key} as a prefix---which would not be allowed if
+@var{key} has a non-prefix binding.  For example:
+
+@smallexample
+@group
+(keymap-global-unset "C-l")
+    @result{} nil
+@end group
+@group
+(keymap-global-set "C-l C-l" 'redraw-display)
+    @result{} nil
+@end group
+@end smallexample
+
+@xref{Key Binding Commands,,,elisp}.
+@end defun
+
+@c copied from lispref/keymaps.texi
+@defun keymap-local-unset key &optional remove
+This function removes the binding of @var{key} from the current
+local map.
+
+@xref{Key Binding Commands,,,elisp}.
+@end defun
+
+@c based on from lisp/keymap.el
+@defun keymap-substitute keymap olddef newdef &optional oldmap prefix
+Replace @var{olddef} with @var{newdef} for any keys in @var{keymap} now
+defined as @var{olddef}.  In other words, @var{olddef} is replaced with
+@var{newdef} wherever it appears.  Alternatively, if optional fourth
+argument @var{oldmap} is specified, we redefine in @var{keymap} as
+@var{newdef} those keys that are defined as @var{olddef} in
+@var{oldmap}.
+@end defun
+
+@c copied from lispref/keymaps.texi
+@defun keymap-lookup keymap key &optional accept-default no-remap position
+This function returns the definition of @var{key} in @var{keymap}.  All
+the other functions described in this chapter that look up keys use
+@code{keymap-lookup}.  Here are examples:
+
+@example
+@group
+(keymap-lookup (current-global-map) "C-x C-f")
+    @result{} find-file
+@end group
+@group
+(keymap-lookup (current-global-map) "C-x C-f 1 2 3 4 5")
+    @result{} 2
+@end group
+@end example
+
+@xref{Functions for Key Lookup,,,elisp}.
+@end defun
+
+@c copied from lispref/keymaps.texi
+@defun keymap-local-lookup keys &optional accept-default
+Like @code{keymap-lookup}, but restricting the search for commands bound
+to @var{keys} to the current local keymap.
+@end defun
+
+@c copied from lispref/keymaps.texi
+@defun keymap-global-lookup keys &optional accept-default
+Like @code{keymap-lookup}, but restricting the search for commands bound
+to @var{keys} to the current global keymap.
+@end defun
+
+@c copied from lispref/keymaps.texi
+@defun define-keymap &rest definitions
+You can create a keymap with the functions described above, and then use
+@code{keymap-set} (@pxref{Changing Key Bindings,,,elisp}) 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 @code{keymap-set} on
+them all can be tedious and error-prone.  Instead you can use
+@code{define-keymap}, which creates a keymap and binds a number of keys.
+Here's a very basic example:
+
+@lisp
+(define-keymap
+  "n" #'forward-line
+  "f" #'previous-line
+  "C-c C-c" #'quit-window)
+@end lisp
+
+This function creates a new sparse keymap, defines the keystrokes in
+@var{pairs}, and returns the new keymap.
+
+@var{pairs} is a list of alternating key bindings and key definitions,
+as accepted by @code{keymap-set}.  In addition, the key can be the
+special symbol @code{:menu}, in which case the definition should be a
+menu definition as accepted by @code{easy-menu-define} (@pxref{Easy
+Menu,,,elisp}).  Here's a brief example of this usage:
+
+@lisp
+(define-keymap :full t
+  "g" #'eww-reload
+  :menu '("Eww"
+          ["Exit" quit-window t]
+          ["Reload" eww-reload t]))
+@end lisp
+
+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 @code{define-keymap} call, the default value for that
+feature is @code{nil}.  Here's a list of the available feature
+keywords:
+
+@table @code
+@item :full
+If non-@code{nil}, create a char-table keymap (as from
+@code{make-keymap}) instead of a sparse keymap (as from
+@code{make-sparse-keymap} (@pxref{Creating Keymaps,,,elisp}).  A sparse
+keymap is the default.
+
+@item :parent
+If non-@code{nil}, the value should be a keymap to use as the parent
+(@pxref{Inheritance and Keymaps,,,elisp}).
+
+@item :keymap
+If non-@code{nil}, the value should be a keymap.  Instead of creating
+a new keymap, the specified keymap is modified instead.
+
+@item :suppress
+If non-@code{nil}, the keymap will be suppressed with
+@code{suppress-keymap} (@pxref{Changing Key Bindings,,,elisp}).  By
+default, digits and the minus sign are exempt from suppressing, but if
+the value is @code{nodigits}, this suppresses digits and minus-sign like
+it does with other characters.
+
+@item :name
+If non-@code{nil}, the value should be a string to use as the menu for
+the keymap if you use it as a menu with @code{x-popup-menu}
+(@pxref{Pop-Up Menus,,,elisp}).
+
+@item :prefix
+If non-@code{nil}, the value should be a symbol to be used as a prefix
+command (@pxref{Prefix Keys,,,elisp}).  If this is the case, this symbol
+is returned by @code{define-keymap} instead of the map itself.
+@end table
+@end defun
+
+@c copied from lispref/keymaps.texi
+@defun 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
+@code{foo} almost always has a variable called @code{foo-mode-map}.
+
+This macro defines @var{name} as a variable, passes @var{options}
+and @var{pairs} to @code{define-keymap}, and uses the result as the
+default value for the variable.
+
+@var{options} is like the keywords in @code{define-keymap}, but
+there's an additional @code{:doc} keyword that provides the doc
+string for the defined variable.
+
+Here's an example:
+
+@lisp
+(defvar-keymap eww-textarea-map
+  :parent text-mode-map
+  "RET" #'forward-line
+  "TAB" #'shr-next-link)
+@end lisp
+@end defun
+
+@c copied from lispref/control.texi
+@defmac while-let spec then-forms...
+Like @code{when-let}, but repeat until a binding in @var{spec} is
+@code{nil}.  The return value is always @code{nil}.
+
+This is comparable to @code{and-let*}.
+@end defmac
+
+@subsection Prefixed Definitions
+These functions are prefixed with @code{compat} prefix, and will require
+manual loading even after the release of Compat 29.1.0.0:
+
+@c copied from lispref/keymaps.texi
+@defun compat-define-key
+This function is like @code{keymap-set} (@pxref{Changing Key
+Bindings,,,elisp}, but understands only the legacy key syntaxes.
+
+In addition, this function also has a @var{remove} argument.  If it is
+non-@code{nil}, the definition will be removed.  This is almost the
+same as setting the definition to @code{nil}, but makes a difference
+if the @var{keymap} has a parent, and @var{key} is shadowing the same
+binding in the parent.  With @var{remove}, subsequent lookups will
+return the binding in the parent, whereas with a @code{nil} definition the
+lookups will return @code{nil}.
+
+@xref{Low-Level Key Binding,,,elisp}.
+
+This compatibility version handles the optional argument
+@var{remove}.
+@end defun
+
+@c copied from lispref/lists.texi
+@defun compat-plist-get plist prop &optional predicate
+This returns the value of the @var{property} property stored in the
+property list @var{plist}.  Comparisons are done with @var{predicate},
+and defaults to @code{eq}.  It accepts a malformed @var{plist}
+argument.  If @var{property} is not found in the @var{plist}, it
+returns @code{nil}.
+
+@xref{Plist Access,,,elisp}.
+
+This compatibility version handles the optional argument
+@var{predicate}.
+@end defun
+
+@c copied from lispref/lists.texi
+@defun compat-plist-put plist prop val &optional predicate
+This stores @var{value} as the value of the @var{property} property in
+the property list @var{plist}.  Comparisons are done with @var{predicate},
+and defaults to @code{eq}.  It may modify @var{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 @var{plist}.
+
+@xref{Plist Access,,,elisp}.
+
+This compatibility version handles the optional argument
+@var{predicate}.
+@end defun
+
+@c copied from lispref/lists.texi
+@defun compat-plist-member plist prop &optional predicate
+This returns non-@code{nil} if @var{plist} contains the given
+@var{property}.  Comparisons are done with @var{predicate}, and
+defaults to @code{eq}.  Unlike @code{plist-get}, this allows you to
+distinguish between a missing property and a property with the value
+@code{nil}.  The value is actually the tail of @var{plist} whose
+@code{car} is @var{property}.
+
+@xref{Plist Access,,,elisp}.
+
+This compatibility version handles the optional argument
+@var{predicate}.
+@end defun
+
+@subsection Missing Definitions
+Compat does not provide support for the following Lisp features
+implemented in 29.1:
+
+@itemize
+@item
+The command @code{string-edit} and @code{read-string-from-buffer}.
+@item
+The function @code{readablep}.
+@item
+The macro @code{with-delayed-message} and the function
+@code{funcall-with-delayed-message}.
+@item
+The function @code{string-glyph-split}.
+@item
+The function @code{textsec-suspicious-p}.
+@item
+The function @code{minibuffer-lazy-highlight-setup}.
+@item
+The function @code{pp-emacs-lisp-code}.
+@end itemize
+
 @node Development
 @chapter Development
 



reply via email to

[Prev in Thread] Current Thread [Next in Thread]