[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
- [elpa] externals/compat 0e4da35d72 46/84: Add functions and macros from keymap.el, (continued)
- [elpa] externals/compat 0e4da35d72 46/84: Add functions and macros from keymap.el, ELPA Syncer, 2023/01/03
- [elpa] externals/compat 11c9917215 51/84: Declare alist-get for usage in compat-alist-get, ELPA Syncer, 2023/01/03
- [elpa] externals/compat 145d344d37 45/84: Add prefixed define-key from Emacs 29.1, ELPA Syncer, 2023/01/03
- [elpa] externals/compat faeeebe50b 52/84: Remove unused local variable in file-name-absolute-p, ELPA Syncer, 2023/01/03
- [elpa] externals/compat 97cecbc1c0 54/84: Replace seq-into with concrete implementations in compat-29, ELPA Syncer, 2023/01/03
- [elpa] externals/compat 518067a7d6 58/84: Copy edebug specification for and-let* from if-let*, ELPA Syncer, 2023/01/03
- [elpa] externals/compat 8e397fee78 66/84: Ignore all .patch files, ELPA Syncer, 2023/01/03
- [elpa] externals/compat 18152ca068 76/84: Fix edge-case of binding nil in if-let* and related macros, ELPA Syncer, 2023/01/03
- [elpa] externals/compat bb25d50b6c 78/84: Fix test skip condition for 'compat-ref-define-key', ELPA Syncer, 2023/01/03
- [elpa] externals/compat 043e3d71b5 79/84: Always load compat-29, ELPA Syncer, 2023/01/03
- [elpa] externals/compat 62ec50bdd1 83/84: Merge branch 'emacs-29.1',
ELPA Syncer <=
- [elpa] externals/compat accc689c7e 20/84: Remove nonsensical file-parent-directory test comment, ELPA Syncer, 2023/01/03
- [elpa] externals/compat 8b3d3ea5c8 32/84: Merge branch 'master' into emacs-29.1, ELPA Syncer, 2023/01/03
- [elpa] externals/compat 5c0c55c20d 47/84: Document missing functionality from compat-29, ELPA Syncer, 2023/01/03
- [elpa] externals/compat 26cf72e36a 49/84: Explicitly denote subr-x functions with :feature, ELPA Syncer, 2023/01/03
- [elpa] externals/compat b4f38aa5ab 55/84: Copy if-let/if-let* definitions into if-let/when-let, ELPA Syncer, 2023/01/03
- [elpa] externals/compat 9e14c2f2df 56/84: Remove realname for if-let, ELPA Syncer, 2023/01/03
- [elpa] externals/compat c96aa66fb4 57/84: Remove realname for if-let*, ELPA Syncer, 2023/01/03
- [elpa] externals/compat 3bd425a0d6 67/84: Prevent compat-macs.el from being byte compiled, ELPA Syncer, 2023/01/03
- [elpa] externals/compat e96cd14210 72/84: Have Makefile targets rebuild .elc files not .el, ELPA Syncer, 2023/01/03
- [elpa] externals/compat c0d5634570 80/84: Simplify loading procedure, ELPA Syncer, 2023/01/03