aboutsummaryrefslogtreecommitdiff
path: root/.config/emacs/lisp/libs/compat-macs.el
diff options
context:
space:
mode:
authorJack Jamison <jackqjamison@gmail.com>2026-07-05 01:19:30 -0400
committerJack Jamison <jackqjamison@gmail.com>2026-07-05 01:19:30 -0400
commitbdf9a71ab7baa2b1de9abcfd5df1a9107a55d141 (patch)
treec4524e6c41aa5107211103401dabfaefc81aa882 /.config/emacs/lisp/libs/compat-macs.el
parentfe3984f541bd32bdfa418afb305b614176b55ca0 (diff)
add a bunch of emacs packages HELP
Diffstat (limited to '.config/emacs/lisp/libs/compat-macs.el')
-rw-r--r--.config/emacs/lisp/libs/compat-macs.el272
1 files changed, 272 insertions, 0 deletions
diff --git a/.config/emacs/lisp/libs/compat-macs.el b/.config/emacs/lisp/libs/compat-macs.el
new file mode 100644
index 0000000..b3206f7
--- /dev/null
+++ b/.config/emacs/lisp/libs/compat-macs.el
@@ -0,0 +1,272 @@
+;;; compat-macs.el --- Compatibility Macros -*- lexical-binding: t; no-byte-compile: t; -*-
+
+;; Copyright (C) 2021-2026 Free Software Foundation, Inc.
+
+;; This program is free software; you can redistribute it and/or modify
+;; it under the terms of the GNU General Public License as published by
+;; the Free Software Foundation, either version 3 of the License, or
+;; (at your option) any later version.
+
+;; This program is distributed in the hope that it will be useful,
+;; but WITHOUT ANY WARRANTY; without even the implied warranty of
+;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+;; GNU General Public License for more details.
+
+;; You should have received a copy of the GNU General Public License
+;; along with this program. If not, see <https://www.gnu.org/licenses/>.
+
+;;; Commentary:
+
+;; WARNING: This file provides *internal* macros. The macros are used
+;; by Compat to facilitate the definition of compatibility functions,
+;; compatibility macros and compatibility variables. The
+;; `compat-macs' feature should never be loaded at runtime in your
+;; Emacs and will only be used during byte compilation. Every
+;; definition provided here is internal, may change any time between
+;; Compat releases and must not be used by other packages.
+
+;;; Code:
+
+;; We always require subr-x at compile time for the fboundp check
+;; since definitions have been moved around. The cl-lib macros are
+;; needed by compatibility definitions.
+(require 'subr-x)
+(require 'cl-lib)
+
+(defvar compat-macs--version nil
+ "Version of the currently defined compatibility definitions.")
+
+(defun compat-macs--strict (cond &rest error)
+ "Assert strict COND, otherwise fail with ERROR."
+ (when (bound-and-true-p compat-strict)
+ (apply #'compat-macs--assert cond error)))
+
+(defun compat-macs--assert (cond &rest error)
+ "Assert COND, otherwise fail with ERROR."
+ (unless cond (apply #'error error)))
+
+(defun compat-macs--docstring (type name docstring)
+ "Format DOCSTRING for NAME of TYPE.
+Prepend compatibility notice to the actual documentation string."
+ (with-temp-buffer
+ (insert
+ (format
+ "[Compatibility %s for `%s', defined in Emacs %s. \
+See (compat) Emacs %s' for more details.]\n\n%s"
+ type name compat-macs--version compat-macs--version docstring))
+ (let ((fill-column 80))
+ (fill-region (point-min) (point-max)))
+ (buffer-string)))
+
+(defun compat-macs--check-attributes (attrs preds)
+ "Check ATTRS given PREDS predicate plist and return rest."
+ (while (keywordp (car attrs))
+ (compat-macs--assert (cdr attrs) "Attribute list length is odd")
+ (compat-macs--assert (let ((p (plist-get preds (car attrs))))
+ (and p (or (eq p t) (funcall p (cadr attrs)))))
+ "Invalid attribute %s" (car attrs))
+ (setq attrs (cddr attrs)))
+ attrs)
+
+(defun compat-macs--guard (attrs preds fun)
+ "Guard compatibility definition generation.
+The version constraints specified by ATTRS are checked. PREDS is
+a plist of predicates for arguments which are passed to FUN."
+ (declare (indent 2))
+ (compat-macs--assert compat-macs--version "No `compat-version' was declared")
+ (let* ((body (compat-macs--check-attributes
+ attrs `(,@preds :feature symbolp)))
+ (feature (plist-get attrs :feature))
+ (attrs `(:body ,body ,@attrs))
+ args)
+ ;; Require feature at compile time
+ (when feature
+ (compat-macs--assert (not (eq feature 'subr-x)) "Invalid feature subr-x")
+ (require feature))
+ ;; The current Emacs must be older than the currently declared version.
+ (when (version< emacs-version compat-macs--version)
+ (while preds
+ (push (plist-get attrs (car preds)) args)
+ (setq preds (cddr preds)))
+ (setq body (apply fun (nreverse args)))
+ (if (and feature body)
+ `(with-eval-after-load ',feature ,@body)
+ (macroexp-progn body)))))
+
+(defun compat-macs--defun (type name arglist docstring rest)
+ "Define function NAME of TYPE with ARGLIST and DOCSTRING.
+REST are attributes and the function BODY."
+ (compat-macs--guard
+ rest (list :extended (lambda (x) (or (booleanp x) (version-to-list x)))
+ :obsolete (lambda (x) (or (booleanp x) (stringp x)))
+ :body t)
+ (lambda (extended obsolete body)
+ (when (stringp extended)
+ (compat-macs--assert
+ (and (version< extended compat-macs--version) (version< "25.1" extended))
+ "Invalid :extended version %s for %s %s" extended type name)
+ (setq extended (version<= extended emacs-version)))
+ (compat-macs--strict (eq extended (fboundp name))
+ "Wrong :extended flag for %s %s" type name)
+ ;; Remove unsupported declares. It might be possible to set these
+ ;; properties otherwise. That should be looked into and implemented
+ ;; if it is the case.
+ (when (and (listp (car-safe body)) (eq (caar body) 'declare) (<= emacs-major-version 25))
+ (setcar body (assq-delete-all 'pure (assq-delete-all
+ 'side-effect-free (car body)))))
+ ;; Use `:extended' name if the function is already defined.
+ (let* ((defname (if (and extended (fboundp name))
+ (intern (format "compat--%s" name))
+ name))
+ (def `(,(if (memq '&key arglist)
+ (if (eq type 'macro) 'cl-defmacro 'cl-defun)
+ (if (eq type 'macro) 'defmacro 'defun))
+ ,defname ,arglist
+ ,(compat-macs--docstring type name docstring)
+ ,@body)))
+ `(,@(if (eq defname name)
+ ;; An additional fboundp check is performed at runtime to make
+ ;; sure that we never redefine an existing definition if Compat
+ ;; is loaded on a newer Emacs version. Declare the function,
+ ;; such that the byte compiler does not complain about possibly
+ ;; missing functions at runtime. The warnings are generated due
+ ;; to the fboundp check.
+ `((declare-function ,name nil)
+ (unless (fboundp ',name) ,def))
+ (list def))
+ ,@(when obsolete
+ `((make-obsolete
+ ',defname ,(if (stringp obsolete) obsolete "No substitute")
+ ,compat-macs--version))))))))
+
+(defmacro compat-guard (cond &rest rest)
+ "Guard definition with a runtime COND and a version check.
+The runtime condition must make sure that no definition is
+overridden. REST is an attribute plist followed by the definition
+body. The attributes specify the conditions under which the
+definition is generated.
+
+- :feature :: Wrap the definition with `with-eval-after-load' for
+ the given feature."
+ (declare (debug ([&rest keywordp sexp] def-body))
+ (indent 1))
+ (compat-macs--guard rest '(:body t)
+ (lambda (body)
+ (compat-macs--assert body "The guarded body is empty")
+ (if (eq cond t)
+ body
+ (compat-macs--strict (eval cond t) "Guard %S failed" cond)
+ `((when ,cond ,@body))))))
+
+(defmacro compat-defalias (name def &rest attrs)
+ "Define compatibility alias NAME as DEF.
+ATTRS is a plist of attributes, which specify the conditions
+under which the definition is generated.
+
+- :obsolete :: Mark the alias as obsolete if t.
+
+- :feature :: See `compat-guard'."
+ (declare (debug (name symbolp [&rest keywordp sexp])))
+ (compat-macs--guard attrs '(:obsolete booleanp)
+ (lambda (obsolete)
+ (compat-macs--strict (not (fboundp name)) "%s already defined" name)
+ ;; The fboundp check is performed at runtime to make sure that we never
+ ;; redefine an existing definition if Compat is loaded on a newer Emacs
+ ;; version.
+ `((unless (fboundp ',name)
+ (defalias ',name ',def
+ ,(compat-macs--docstring 'function name
+ (get name 'function-documentation)))
+ ,@(when obsolete
+ `((make-obsolete ',name ',def ,compat-macs--version))))))))
+
+(defmacro compat-defun (name arglist docstring &rest rest)
+ "Define compatibility function NAME with arguments ARGLIST.
+The function must be documented in DOCSTRING. REST is an
+attribute plist followed by the function body. The attributes
+specify the conditions under which the definition is generated.
+
+- :extended :: Mark the function as extended if t. The function
+ must be called explicitly via `compat-call'. This attribute
+ should be used for functions which extend already existing
+ functions, e.g., functions which changed their calling
+ convention or their behavior. The value can also be a version
+ string, which specifies the Emacs version when the original
+ version of the function was introduced.
+
+- :obsolete :: Mark the function as obsolete if t, can be a
+ string describing the obsoletion.
+
+- :feature :: See `compat-guard'."
+ (declare (debug (&define name (&rest symbolp)
+ stringp
+ [&rest keywordp sexp]
+ def-body))
+ (doc-string 3) (indent 2))
+ (compat-macs--defun 'function name arglist docstring rest))
+
+(defmacro compat-defmacro (name arglist docstring &rest rest)
+ "Define compatibility macro NAME with arguments ARGLIST.
+The macro must be documented in DOCSTRING. REST is an attribute
+plist followed by the macro body. See `compat-defun' for
+details."
+ (declare (debug compat-defun) (doc-string 3) (indent 2))
+ (compat-macs--defun 'macro name arglist docstring rest))
+
+(defmacro compat-defvar (name initval docstring &rest attrs)
+ "Define compatibility variable NAME with initial value INITVAL.
+The variable must be documented in DOCSTRING. ATTRS is a plist
+of attributes, which specify the conditions under which the
+definition is generated.
+
+- :constant :: Mark the variable as constant if t.
+
+- :risky :: Mark the variable as risky if t.
+
+- :local :: Make the variable buffer-local if t. If the value is
+ `permanent' make the variable additionally permanently local.
+
+- :obsolete :: Mark the variable as obsolete if t, can be a
+ string describing the obsoletion.
+
+- :feature :: See `compat-guard'."
+ (declare (debug (name form stringp [&rest keywordp sexp]))
+ (doc-string 3) (indent 2))
+ (compat-macs--guard
+ attrs (list :constant #'booleanp
+ :risky #'booleanp
+ :local (lambda (x) (memq x '(nil t permanent)))
+ :obsolete (lambda (x) (or (booleanp x) (stringp x))))
+ (lambda (constant risky local obsolete)
+ (compat-macs--strict (not (boundp name)) "%s already defined" name)
+ (compat-macs--assert (not (and constant local)) "Both :constant and :local")
+ (compat-macs--assert (not (and local risky)) "Both :risky and :local")
+ ;; The boundp check is performed at runtime to make sure that we never
+ ;; redefine an existing definition if Compat is loaded on a newer Emacs
+ ;; version.
+ `((defvar ,name)
+ (unless (boundp ',name)
+ (,(if constant 'defconst 'defvar)
+ ,name ,initval
+ ,(compat-macs--docstring 'variable name docstring))
+ ,@(when obsolete
+ `((make-obsolete-variable
+ ',name ,(if (stringp obsolete) obsolete "No substitute")
+ ,compat-macs--version))))
+ ,@(and local `((make-variable-buffer-local ',name)))
+ ,@(and risky `((put ',name 'risky-local-variable t)))
+ ,@(and (eq local 'permanent) `((put ',name 'permanent-local t)))))))
+
+(defmacro compat-version (version)
+ "Set the Emacs version that is currently being handled to VERSION."
+ (setq compat-macs--version version)
+ nil)
+
+(defmacro compat-require (feature version)
+ "Require FEATURE if the Emacs version is less than VERSION."
+ (when (version< emacs-version version)
+ (require feature)
+ `(require ',feature)))
+
+(provide 'compat-macs)
+;;; compat-macs.el ends here