From 1e93daa67d87ea7c4e85d076da3b3a85eaab2da9 Mon Sep 17 00:00:00 2001 From: Daniel Mendler Date: Wed, 1 Jan 2025 11:23:50 +0100 Subject: Drop support for 24.x in upcoming Compat 31 - Emacs 24.4 has been released over ten years ago. - seq and cl-defgeneric have been introduced in 25.1. - Emacs follows a major.minor versioning scheme from 25.1 on, where new APIs are only introduced at major version bumps, which fits to the Compat development model. - Python.el in Emacs, which depends on Compat, requires Emacs 26.1 now (commit eff5a3e43ba886074c3a2e007a2bced9bcb85f17). - Packages which want to support 24.4 can depend on Compat 30 or older. --- .github/workflows/makefile.yml | 5 +- .github/workflows/seq-24.el | 496 ----------------------------------------- Makefile | 3 +- NEWS.org | 2 + README.md | 2 +- compat-25.el | 260 --------------------- compat-26.el | 8 +- compat-30.el | 24 +- compat-macs.el | 2 +- compat-tests.el | 28 +-- compat.el | 2 +- compat.texi | 287 +----------------------- 12 files changed, 33 insertions(+), 1086 deletions(-) delete mode 100644 .github/workflows/seq-24.el delete mode 100644 compat-25.el diff --git a/.github/workflows/makefile.yml b/.github/workflows/makefile.yml index f74d357..5c80dc7 100644 --- a/.github/workflows/makefile.yml +++ b/.github/workflows/makefile.yml @@ -19,15 +19,12 @@ jobs: strategy: matrix: # See https://github.com/purcell/setup-emacs/blob/master/.github/workflows/test.yml - emacs-version: [24.4, 24.5, 25.1, 25.2, 25.3, 26.1, 26.2, 26.3, 27.1, 27.2, 28.1, 28.2, 29.1, 29.2, 29.3, 29.4, 30.1] # release-snapshot, snapshot + emacs-version: [25.1, 25.2, 25.3, 26.1, 26.2, 26.3, 27.1, 27.2, 28.1, 28.2, 29.1, 29.2, 29.3, 29.4, 30.1] # release-snapshot, snapshot steps: - uses: actions/checkout@v4 - uses: purcell/setup-emacs@master with: version: ${{ matrix.emacs-version }} - - name: Provide seq.el on Emacs 24 - if: ${{ startsWith(matrix.emacs-version, '24.') }} - run: mv .github/workflows/seq-24.el seq.el - name: Basic checks run: make check - name: Run interpreted tests diff --git a/.github/workflows/seq-24.el b/.github/workflows/seq-24.el deleted file mode 100644 index 78dfe4b..0000000 --- a/.github/workflows/seq-24.el +++ /dev/null @@ -1,496 +0,0 @@ -;;; seq.el --- seq.el implementation for Emacs 24.x -*- lexical-binding: t -*- - -;; Copyright (C) 2014-2020 Free Software Foundation, Inc. - -;; Author: Nicolas Petton -;; Keywords: sequences - -;; Maintainer: emacs-devel@gnu.org - -;; This file is part of GNU Emacs. - -;; GNU Emacs 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. - -;; GNU Emacs 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 GNU Emacs. If not, see . - -;;; Commentary: - -;; Sequence-manipulation functions that complement basic functions -;; provided by subr.el. -;; -;; All functions are prefixed with "seq-". -;; -;; All provided functions work on lists, strings and vectors. -;; -;; Functions taking a predicate or iterating over a sequence using a -;; function as argument take the function as their first argument and -;; the sequence as their second argument. All other functions take -;; the sequence as their first argument. - -;;; Code: - -(defmacro seq-doseq (spec &rest body) - "Loop over a sequence. -Similar to `dolist' but can be applied to lists, strings, and vectors. - -Evaluate BODY with VAR bound to each element of SEQ, in turn. - -\(fn (VAR SEQ) BODY...)" - (declare (indent 1) (debug ((symbolp form &optional form) body))) - (let ((length (make-symbol "length")) - (seq (make-symbol "seq")) - (index (make-symbol "index"))) - `(let* ((,seq ,(cadr spec)) - (,length (if (listp ,seq) nil (seq-length ,seq))) - (,index (if ,length 0 ,seq))) - (while (if ,length - (< ,index ,length) - (consp ,index)) - (let ((,(car spec) (if ,length - (prog1 (seq-elt ,seq ,index) - (setq ,index (+ ,index 1))) - (pop ,index)))) - ,@body))))) - -;; Implementation of `seq-let' compatible with Emacs<25.1. -(defmacro seq-let (args sequence &rest body) - "Bind the variables in ARGS to the elements of SEQUENCE then evaluate BODY. - -ARGS can also include the `&rest' marker followed by a variable -name to be bound to the rest of SEQUENCE." - (declare (indent 2) (debug t)) - (let ((seq-var (make-symbol "seq"))) - `(let* ((,seq-var ,sequence) - ,@(seq--make-bindings args seq-var)) - ,@body))) - -(defun seq-drop (sequence n) - "Return a subsequence of SEQUENCE without its first N elements. -The result is a sequence of the same type as SEQUENCE. - -If N is a negative integer or zero, SEQUENCE is returned." - (if (<= n 0) - sequence - (if (listp sequence) - (seq--drop-list sequence n) - (let ((length (seq-length sequence))) - (seq-subseq sequence (min n length) length))))) - -(defun seq-take (sequence n) - "Return a subsequence of SEQUENCE with its first N elements. -The result is a sequence of the same type as SEQUENCE. - -If N is a negative integer or zero, an empty sequence is -returned." - (if (listp sequence) - (seq--take-list sequence n) - (seq-subseq sequence 0 (min (max n 0) (seq-length sequence))))) - -(defun seq-drop-while (predicate sequence) - "Return a sequence from the first element for which (PREDICATE element) is nil in SEQUENCE. -The result is a sequence of the same type as SEQUENCE." - (if (listp sequence) - (seq--drop-while-list predicate sequence) - (seq-drop sequence (seq--count-successive predicate sequence)))) - -(defun seq-take-while (predicate sequence) - "Return the successive elements for which (PREDICATE element) is non-nil in SEQUENCE. -The result is a sequence of the same type as SEQUENCE." - (if (listp sequence) - (seq--take-while-list predicate sequence) - (seq-take sequence (seq--count-successive predicate sequence)))) - -(defun seq-filter (predicate sequence) - "Return a list of all the elements for which (PREDICATE element) is non-nil in SEQUENCE." - (let ((exclude (make-symbol "exclude"))) - (delq exclude (seq-map (lambda (elt) - (if (funcall predicate elt) - elt - exclude)) - sequence)))) - -(defun seq-map-indexed (function sequence) - "Return the result of applying FUNCTION to each element of SEQUENCE. -Unlike `seq-map', FUNCTION takes two arguments: the element of -the sequence, and its index within the sequence." - (let ((index 0)) - (seq-map (lambda (elt) - (prog1 - (funcall function elt index) - (setq index (1+ index)))) - sequence))) - -(defun seq-remove (predicate sequence) - "Return a list of all the elements for which (PREDICATE element) is nil in SEQUENCE." - (seq-filter (lambda (elt) (not (funcall predicate elt))) - sequence)) - -(defun seq-reduce (function sequence initial-value) - "Reduce the function FUNCTION across SEQUENCE, starting with INITIAL-VALUE. - -Return the result of calling FUNCTION with INITIAL-VALUE and the -first element of SEQUENCE, then calling FUNCTION with that result and -the second element of SEQUENCE, then with that result and the third -element of SEQUENCE, etc. - -If SEQUENCE is empty, return INITIAL-VALUE and FUNCTION is not called." - (if (seq-empty-p sequence) - initial-value - (let ((acc initial-value)) - (seq-doseq (elt sequence) - (setq acc (funcall function acc elt))) - acc))) - -(defun seq-some (predicate sequence) - "Return the first value for which if (PREDICATE element) is non-nil for in SEQUENCE." - (catch 'seq--break - (seq-doseq (elt sequence) - (let ((result (funcall predicate elt))) - (when result - (throw 'seq--break result)))) - nil)) - -(defun seq-find (predicate sequence &optional default) - "Return the first element for which (PREDICATE element) is non-nil in SEQUENCE. -If no element is found, return DEFAULT. - -Note that `seq-find' has an ambiguity if the found element is -identical to DEFAULT, as it cannot be known if an element was -found or not." - (catch 'seq--break - (seq-doseq (elt sequence) - (when (funcall predicate elt) - (throw 'seq--break elt))) - default)) - -(defun seq-every-p (predicate sequence) - "Return non-nil if (PREDICATE element) is non-nil for all elements of the sequence SEQUENCE." - (catch 'seq--break - (seq-doseq (elt sequence) - (or (funcall predicate elt) - (throw 'seq--break nil))) - t)) - -(defun seq-count (predicate sequence) - "Return the number of elements for which (PREDICATE element) is non-nil in SEQUENCE." - (let ((count 0)) - (seq-doseq (elt sequence) - (when (funcall predicate elt) - (setq count (+ 1 count)))) - count)) - -(defun seq-empty-p (sequence) - "Return non-nil if the sequence SEQUENCE is empty, nil otherwise." - (if (listp sequence) - (null sequence) - (= 0 (seq-length sequence)))) - -(defun seq-sort (predicate sequence) - "Return a sorted sequence comparing using PREDICATE the elements of SEQUENCE. -The result is a sequence of the same type as SEQUENCE." - (if (listp sequence) - (sort (seq-copy sequence) predicate) - (let ((result (seq-sort predicate (append sequence nil)))) - (seq-into result (type-of sequence))))) - -(defun seq-sort-by (function pred sequence) - "Sort SEQUENCE using PRED as a comparison function. -Elements of SEQUENCE are transformed by FUNCTION before being -sorted. FUNCTION must be a function of one argument." - (seq-sort (lambda (a b) - (funcall pred - (funcall function a) - (funcall function b))) - sequence)) - -(defun seq-contains (sequence elt &optional testfn) - "Return the first element in SEQUENCE that equals to ELT. -Equality is defined by TESTFN if non-nil or by `equal' if nil." - (seq-some (lambda (e) - (funcall (or testfn #'equal) elt e)) - sequence)) - -(defun seq-set-equal-p (sequence1 sequence2 &optional testfn) - "Return non-nil if SEQUENCE1 and SEQUENCE2 contain the same elements, regardless of order. -Equality is defined by TESTFN if non-nil or by `equal' if nil." - (and (seq-every-p (lambda (item1) (seq-contains sequence2 item1 testfn)) sequence1) - (seq-every-p (lambda (item2) (seq-contains sequence1 item2 testfn)) sequence2))) - -(defun seq-position (sequence elt &optional testfn) - "Return the index of the first element in SEQUENCE that is equal to ELT. -Equality is defined by TESTFN if non-nil or by `equal' if nil." - (let ((index 0)) - (catch 'seq--break - (seq-doseq (e sequence) - (when (funcall (or testfn #'equal) e elt) - (throw 'seq--break index)) - (setq index (1+ index))) - nil))) - -(defun seq-uniq (sequence &optional testfn) - "Return a list of the elements of SEQUENCE with duplicates removed. -TESTFN is used to compare elements, or `equal' if TESTFN is nil." - (let ((result '())) - (seq-doseq (elt sequence) - (unless (seq-contains result elt testfn) - (setq result (cons elt result)))) - (nreverse result))) - -(defun seq-subseq (sequence start &optional end) - "Return the subsequence of SEQUENCE from START to END. -If END is omitted, it defaults to the length of the sequence. -If START or END is negative, it counts from the end." - (cond ((or (stringp sequence) (vectorp sequence)) (substring sequence start end)) - ((listp sequence) - (let (len (errtext (format "Bad bounding indices: %s, %s" start end))) - (and end (< end 0) (setq end (+ end (setq len (seq-length sequence))))) - (if (< start 0) (setq start (+ start (or len (setq len (seq-length sequence)))))) - (when (> start 0) - (setq sequence (nthcdr (1- start) sequence)) - (or sequence (error "%s" errtext)) - (setq sequence (cdr sequence))) - (if end - (let ((res nil)) - (while (and (>= (setq end (1- end)) start) sequence) - (push (pop sequence) res)) - (or (= (1+ end) start) (error "%s" errtext)) - (nreverse res)) - (seq-copy sequence)))) - (t (error "Unsupported sequence: %s" sequence)))) - -(defun seq-concatenate (type &rest seqs) - "Concatenate, into a sequence of type TYPE, the sequences SEQS. -TYPE must be one of following symbols: vector, string or list. - -\n(fn TYPE SEQUENCE...)" - (pcase type - (`vector (apply #'vconcat seqs)) - (`string (apply #'concat seqs)) - (`list (apply #'append (append seqs '(nil)))) - (_ (error "Not a sequence type name: %S" type)))) - -(defun seq-mapcat (function sequence &optional type) - "Concatenate the result of applying FUNCTION to each element of SEQUENCE. -The result is a sequence of type TYPE, or a list if TYPE is nil." - (apply #'seq-concatenate (or type 'list) - (seq-map function sequence))) - -(defun seq-mapn (function sequence &rest seqs) - "Like `seq-map' but FUNCTION is mapped over all SEQS. -The arity of FUNCTION must match the number of SEQS, and the -mapping stops on the shortest sequence. -Return a list of the results. - -\(fn FUNCTION SEQS...)" - (let ((result nil) - (seqs (seq-map (lambda (s) - (seq-into s 'list)) - (cons sequence seqs)))) - (while (not (memq nil seqs)) - (push (apply function (seq-map #'car seqs)) result) - (setq seqs (seq-map #'cdr seqs))) - (nreverse result))) - -(defun seq-partition (sequence n) - "Return a list of the elements of SEQUENCE grouped into sub-sequences of length N. -The last sequence may contain less than N elements. If N is a -negative integer or 0, nil is returned." - (unless (< n 1) - (let ((result '())) - (while (not (seq-empty-p sequence)) - (push (seq-take sequence n) result) - (setq sequence (seq-drop sequence n))) - (nreverse result)))) - -(defun seq-intersection (seq1 seq2 &optional testfn) - "Return a list of the elements that appear in both SEQ1 and SEQ2. -Equality is defined by TESTFN if non-nil or by `equal' if nil." - (seq-reduce (lambda (acc elt) - (if (seq-contains seq2 elt testfn) - (cons elt acc) - acc)) - (seq-reverse seq1) - '())) - -(defun seq-difference (seq1 seq2 &optional testfn) - "Return a list of the elements that appear in SEQ1 but not in SEQ2. -Equality is defined by TESTFN if non-nil or by `equal' if nil." - (seq-reduce (lambda (acc elt) - (if (not (seq-contains seq2 elt testfn)) - (cons elt acc) - acc)) - (seq-reverse seq1) - '())) - -(defun seq-group-by (function sequence) - "Apply FUNCTION to each element of SEQUENCE. -Separate the elements of SEQUENCE into an alist using the results as -keys. Keys are compared using `equal'." - (seq-reduce - (lambda (acc elt) - (let* ((key (funcall function elt)) - (cell (assoc key acc))) - (if cell - (setcdr cell (push elt (cdr cell))) - (push (list key elt) acc)) - acc)) - (seq-reverse sequence) - nil)) - -(defalias 'seq-reverse - (if (ignore-errors (reverse [1 2])) - #'reverse - (lambda (sequence) - "Return the reversed copy of list, vector, or string SEQUENCE. -See also the function `nreverse', which is used more often." - (let ((result '())) - (seq-map (lambda (elt) (push elt result)) - sequence) - (if (listp sequence) - result - (seq-into result (type-of sequence))))))) - -(defun seq-into (sequence type) - "Convert the sequence SEQUENCE into a sequence of type TYPE. -TYPE can be one of the following symbols: vector, string or list." - (pcase type - (`vector (seq--into-vector sequence)) - (`string (seq--into-string sequence)) - (`list (seq--into-list sequence)) - (_ (error "Not a sequence type name: %S" type)))) - -(defun seq-min (sequence) - "Return the smallest element of SEQUENCE. -SEQUENCE must be a sequence of numbers or markers." - (apply #'min (seq-into sequence 'list))) - -(defun seq-max (sequence) - "Return the largest element of SEQUENCE. -SEQUENCE must be a sequence of numbers or markers." - (apply #'max (seq-into sequence 'list))) - -(defun seq-random-elt (sequence) - "Return a random element from SEQUENCE. -Signal an error if SEQUENCE is empty." - (if (seq-empty-p sequence) - (error "Sequence cannot be empty") - (seq-elt sequence (random (seq-length sequence))))) - -(defun seq--drop-list (list n) - "Return a list from LIST without its first N elements. -This is an optimization for lists in `seq-drop'." - (nthcdr n list)) - -(defun seq--take-list (list n) - "Return a list from LIST made of its first N elements. -This is an optimization for lists in `seq-take'." - (let ((result '())) - (while (and list (> n 0)) - (setq n (1- n)) - (push (pop list) result)) - (nreverse result))) - -(defun seq--drop-while-list (predicate list) - "Return a list from the first element for which (PREDICATE element) is nil in LIST. -This is an optimization for lists in `seq-drop-while'." - (while (and list (funcall predicate (car list))) - (setq list (cdr list))) - list) - -(defun seq--take-while-list (predicate list) - "Return the successive elements for which (PREDICATE element) is non-nil in LIST. -This is an optimization for lists in `seq-take-while'." - (let ((result '())) - (while (and list (funcall predicate (car list))) - (push (pop list) result)) - (nreverse result))) - -(defun seq--count-successive (predicate sequence) - "Return the number of successive elements for which (PREDICATE element) is non-nil in SEQUENCE." - (let ((n 0) - (len (seq-length sequence))) - (while (and (< n len) - (funcall predicate (seq-elt sequence n))) - (setq n (+ 1 n))) - n)) - -;; Helper function for the Backward-compatible version of `seq-let' -;; for Emacs<25.1. -(defun seq--make-bindings (args sequence &optional bindings) - "Return a list of bindings of the variables in ARGS to the elements of a sequence. -if BINDINGS is non-nil, append new bindings to it, and return -BINDINGS." - (let ((index 0) - (rest-marker nil)) - (seq-doseq (name args) - (unless rest-marker - (pcase name - ((pred seqp) - (setq bindings (seq--make-bindings (seq--elt-safe args index) - `(seq--elt-safe ,sequence ,index) - bindings))) - (`&rest - (progn (push `(,(seq--elt-safe args (1+ index)) - (seq-drop ,sequence ,index)) - bindings) - (setq rest-marker t))) - (_ - (push `(,name (seq--elt-safe ,sequence ,index)) bindings)))) - (setq index (1+ index))) - bindings)) - -(defun seq--elt-safe (sequence n) - "Return element of SEQUENCE at the index N. -If no element is found, return nil." - (when (or (listp sequence) - (and (sequencep sequence) - (> (seq-length sequence) n))) - (seq-elt sequence n))) - -(defun seq--activate-font-lock-keywords () - "Activate font-lock keywords for some symbols defined in seq." - (font-lock-add-keywords 'emacs-lisp-mode - '("\\" "\\"))) - -(defalias 'seq-copy #'copy-sequence) -(defalias 'seq-elt #'elt) -(defalias 'seq-length #'length) -(defalias 'seq-do #'mapc) -(defalias 'seq-each #'seq-do) -(defalias 'seq-map #'mapcar) -(defalias 'seqp #'sequencep) - -(defun seq--into-list (sequence) - "Concatenate the elements of SEQUENCE into a list." - (if (listp sequence) - sequence - (append sequence nil))) - -(defun seq--into-vector (sequence) - "Concatenate the elements of SEQUENCE into a vector." - (if (vectorp sequence) - sequence - (vconcat sequence))) - -(defun seq--into-string (sequence) - "Concatenate the elements of SEQUENCE into a string." - (if (stringp sequence) - sequence - (concat sequence))) - -(unless (fboundp 'elisp--font-lock-flush-elisp-buffers) - ;; In Emacs≥25, (via elisp--font-lock-flush-elisp-buffers and a few others) - ;; we automatically highlight macros. - (add-hook 'emacs-lisp-mode-hook #'seq--activate-font-lock-keywords)) - -(provide 'seq) -;;; seq.el ends here diff --git a/Makefile b/Makefile index 9da028f..8982558 100644 --- a/Makefile +++ b/Makefile @@ -40,8 +40,7 @@ endif EMACS = emacs MAKEINFO = makeinfo -BYTEC = compat-25.elc \ - compat-26.elc \ +BYTEC = compat-26.elc \ compat-27.elc \ compat-28.elc \ compat-29.elc \ diff --git a/NEWS.org b/NEWS.org index cc3f2bf..6145d6b 100644 --- a/NEWS.org +++ b/NEWS.org @@ -8,6 +8,8 @@ - compat-31: New functions =minusp= and =plusp=. - compat-31: New macros =incf= and =decf=. - compat-31: New function =color-blend=. +- Drop support for Emacs 24.x. Emacs 25.1 is required now. In case + Emacs 24.x support is still needed, Compat 30 can be used. * Release of "Compat" Version 30.0.2.0 diff --git a/README.md b/README.md index 8c1eff2..4fd69db 100644 --- a/README.md +++ b/README.md @@ -1,7 +1,7 @@ COMPATibility Library for Emacs =============================== This is the source of compat.el, the forwards-compatibility library for (GNU) -Emacs Lisp, versions 24.4 and newer. The intended audience are package +Emacs Lisp, versions 25.1 and newer. The intended audience are package developers that are interested in using newer developments, without having to break compatibility. diff --git a/compat-25.el b/compat-25.el deleted file mode 100644 index 51c4f06..0000000 --- a/compat-25.el +++ /dev/null @@ -1,260 +0,0 @@ -;;; compat-25.el --- Functionality added in Emacs 25.1 -*- lexical-binding: t; -*- - -;; Copyright (C) 2021-2025 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 . - -;;; Commentary: - -;; Functionality added in Emacs 25.1, needed by older Emacs versions. - -;;; Code: - -(eval-when-compile (load "compat-macs.el" nil t t)) - -(compat-version "25.1") - -;;;; Defined in alloc.c - -(compat-defun bool-vector (&rest objects) ;; - "Return a new bool-vector with specified arguments as elements. -Allows any number of arguments, including zero. -usage: (bool-vector &rest OBJECTS)" - (let ((vec (make-bool-vector (length objects) nil)) - (i 0)) - (while objects - (when (car objects) - (aset vec i t)) - (setq objects (cdr objects) - i (1+ i))) - vec)) - -;;;; Defined in editfns.c - -(compat-defalias format-message format) ;; - -;;;; Defined in fileio.c - -(compat-defun directory-name-p (name) ;; - "Return non-nil if NAME ends with a directory separator character." - (eq (eval-when-compile - (if (memq system-type '(cygwin windows-nt ms-dos)) - ?\\ ?/)) - (aref name (1- (length name))))) - -;;;; Defined in doc.c - -(compat-defvar text-quoting-style nil ;; - "Style to use for single quotes in help and messages. - -The value of this variable determines substitution of grave accents -and apostrophes in help output (but not for display of Info -manuals) and in functions like `message' and `format-message', but not -in `format'. - -The value should be one of these symbols: - `curve': quote with curved single quotes ‘like this’. - `straight': quote with straight apostrophes \\='like this\\='. - `grave': quote with grave accent and apostrophe \\=`like this\\='; - i.e., do not alter the original quote marks. - nil: like `curve' if curved single quotes are displayable, - and like `grave' otherwise. This is the default. - -You should never read the value of this variable directly from a Lisp -program. Use the function `text-quoting-style' instead, as that will -compute the correct value for the current terminal in the nil case.") - -;;;; Defined in simple.el - -;; `save-excursion' behaved like `save-mark-and-excursion' before 25.1. -(compat-defalias save-mark-and-excursion save-excursion) ;; - -(declare-function region-bounds nil) ;; Defined in compat-26.el -(compat-defun region-noncontiguous-p () ;; - "Return non-nil if the region contains several pieces. -An example is a rectangular region handled as a list of -separate contiguous regions for each line." - (let ((bounds (region-bounds))) (and (cdr bounds) bounds))) - -;;;; Defined in subr.el - -(compat-defun string-greaterp (string1 string2) ;; - "Return non-nil if STRING1 is greater than STRING2 in lexicographic order. -Case is significant. -Symbols are also allowed; their print names are used instead." - (string-lessp string2 string1)) - -(compat-defmacro with-file-modes (modes &rest body) ;; - "Execute BODY with default file permissions temporarily set to MODES. -MODES is as for `set-default-file-modes'." - (declare (indent 1) (debug t)) - (let ((umask (make-symbol "umask"))) - `(let ((,umask (default-file-modes))) - (unwind-protect - (progn - (set-default-file-modes ,modes) - ,@body) - (set-default-file-modes ,umask))))) - -(compat-defmacro if-let (spec then &rest else) ;; - "Bind variables according to SPEC and evaluate THEN or ELSE. -Evaluate each binding in turn, as in `let*', stopping if a -binding value is nil. If all are non-nil return the value of -THEN, otherwise the last form in ELSE. - -Each element of SPEC is a list (SYMBOL VALUEFORM) that binds -SYMBOL to the value of VALUEFORM. An element can additionally be -of the form (VALUEFORM), which is evaluated and checked for nil; -i.e. SYMBOL can be omitted if only the test result is of -interest. It can also be of the form SYMBOL, then the binding of -SYMBOL is checked for nil. - -As a special case, interprets a SPEC of the form \(SYMBOL SOMETHING) -like \((SYMBOL SOMETHING)). This exists for backward compatibility -with an old syntax that accepted only one binding." - (declare (indent 2) - (debug ([&or (symbolp form) - (&rest [&or symbolp (symbolp form) (form)])] - body))) - (when (and (<= (length spec) 2) (not (listp (car spec)))) - ;; Adjust the single binding case - (setq spec (list spec))) - (let ((empty (make-symbol "s")) - (last t) list) - (dolist (var spec) - (push `(,(if (cdr var) (car var) empty) - (and ,last ,(if (cdr var) (cadr var) (car var)))) - list) - (when (or (cdr var) (consp (car var))) - (setq last (caar list)))) - `(let* ,(nreverse list) - (if ,(caar list) ,then ,@else)))) - -(compat-defmacro when-let (spec &rest body) ;; - "Bind variables according to SPEC and conditionally evaluate BODY. -Evaluate each binding in turn, stopping if a binding value is nil. -If all are non-nil, return the value of the last form in BODY. - -The variable list SPEC is the same as in `if-let'." - (declare (indent 1) (debug if-let)) - (list 'if-let spec (macroexp-progn body))) - -;;;; Defined in subr-x.el - -(compat-defun hash-table-empty-p (hash-table) ;; - "Check whether HASH-TABLE is empty (has 0 elements)." - (zerop (hash-table-count hash-table))) - -(compat-defmacro thread-first (&rest forms) ;; - "Thread FORMS elements as the first argument of their successor. -Example: - (thread-first - 5 - (+ 20) - (/ 25) - - - (+ 40)) -Is equivalent to: - (+ (- (/ (+ 5 20) 25)) 40) -Note how the single `-' got converted into a list before -threading." - (declare (indent 1) - (debug (form &rest [&or symbolp (sexp &rest form)]))) - (let ((body (car forms))) - (dolist (form (cdr forms)) - (when (symbolp form) - (setq form (list form))) - (setq body (append (list (car form)) - (list body) - (cdr form)))) - body)) - -(compat-defmacro thread-last (&rest forms) ;; - "Thread FORMS elements as the last argument of their successor. -Example: - (thread-last - 5 - (+ 20) - (/ 25) - - - (+ 40)) -Is equivalent to: - (+ 40 (- (/ 25 (+ 20 5)))) -Note how the single `-' got converted into a list before -threading." - (declare (indent 1) (debug thread-first)) - (let ((body (car forms))) - (dolist (form (cdr forms)) - (when (symbolp form) - (setq form (list form))) - (setq body (append form (list body)))) - body)) - -;;;; Defined in macroexp.el - -(compat-defun macroexp-parse-body (body) ;; - "Parse a function BODY into (DECLARATIONS . EXPS)." - (let ((decls ())) - (while (and (cdr body) - (let ((e (car body))) - (or (stringp e) - (memq (car-safe e) - '(:documentation declare interactive cl-declare))))) - (push (pop body) decls)) - (cons (nreverse decls) body))) - -(compat-defun macroexp-quote (v) ;; - "Return an expression E such that `(eval E)' is V. - -E is either V or (quote V) depending on whether V evaluates to -itself or not." - (if (and (not (consp v)) - (or (keywordp v) - (not (symbolp v)) - (memq v '(nil t)))) - v - (list 'quote v))) - -(compat-defun macroexpand-1 (form &optional environment) ;; - "Perform (at most) one step of macro expansion." - (cond - ((consp form) - (let* ((head (car form)) - (env-expander (assq head environment))) - (if env-expander - (if (cdr env-expander) - (apply (cdr env-expander) (cdr form)) - form) - (if (not (and (symbolp head) (fboundp head))) - form - (let ((def (autoload-do-load (symbol-function head) head 'macro))) - (cond - ;; Follow alias, but only for macros, otherwise we may end up - ;; skipping an important compiler-macro (e.g. cl--block-wrapper). - ((and (symbolp def) (macrop def)) (cons def (cdr form))) - ((not (consp def)) form) - (t - (if (eq 'macro (car def)) - (apply (cdr def) (cdr form)) - form)))))))) - (t form))) - -;;;; Defined in minibuffer.el - -(compat-defun completion--category-override (category tag) ;; - "Return completion category override for CATEGORY and TAG." - (assq tag (cdr (assq category completion-category-overrides)))) - -(provide 'compat-25) -;;; compat-25.el ends here diff --git a/compat-26.el b/compat-26.el index 9f5e199..92d1519 100644 --- a/compat-26.el +++ b/compat-26.el @@ -67,11 +67,7 @@ SEQUENCE may be a list, a vector, a boolean vector, or a string." Value is a list of one or more cons cells of the form (START . END). It will have more than one cons cell when the region is non-contiguous, see `region-noncontiguous-p' and `extract-rectangle-bounds'." - (if (eval-when-compile (< emacs-major-version 25)) - ;; FIXME: The `region-extract-function' of Emacs 24 has no support for the - ;; bounds argument. - (list (cons (region-beginning) (region-end))) - (funcall region-extract-function 'bounds))) + (funcall region-extract-function 'bounds)) ;;;; Defined in subr.el @@ -108,7 +104,7 @@ If you just want to check `major-mode', use `derived-mode-p'." (compat-defun alist-get (key alist &optional default remove testfn) ;; "Handle optional argument TESTFN." - :extended "25.1" + :extended t (ignore remove) (let ((x (if (not testfn) (assq key alist) diff --git a/compat-30.el b/compat-30.el index 938cbcb..489ced7 100644 --- a/compat-30.el +++ b/compat-30.el @@ -387,7 +387,7 @@ The following arguments are defined: For compatibility, the calling convention (sort SEQ LESSP) can also be used; in this case, sorting is always done in-place." :extended t - (let ((in-place t) (reverse nil) (orig-seq seq)) + (let ((in-place t) (reverse nil)) (when (or (not lessp) rest) (setq rest (if lessp (cons lessp rest) rest) @@ -398,24 +398,10 @@ in this case, sorting is always done in-place." (if key (lambda (a b) (funcall < (funcall key a) (funcall key b))) <)) - seq (if (or (and (eval-when-compile (< emacs-major-version 25)) (vectorp orig-seq)) - in-place) - seq - (copy-sequence seq)))) - ;; Emacs 24 does not support vectors. Convert to list. - (when (and (eval-when-compile (< emacs-major-version 25)) (vectorp orig-seq)) - (setq seq (append seq nil))) - (setq seq (if reverse - (nreverse (sort (nreverse seq) lessp)) - (sort seq lessp))) - ;; Emacs 24: Convert back to vector. - (if (and (eval-when-compile (< emacs-major-version 25)) (vectorp orig-seq)) - (if in-place - (cl-loop for i from 0 for x in seq - do (aset orig-seq i x) - finally return orig-seq) - (apply #'vector seq)) - seq))) + seq (if in-place seq (copy-sequence seq)))) + (if reverse + (nreverse (sort (nreverse seq) lessp)) + (sort seq lessp)))) ;;;; Defined in mule-cmds.el diff --git a/compat-macs.el b/compat-macs.el index c5567da..94f1806 100644 --- a/compat-macs.el +++ b/compat-macs.el @@ -103,7 +103,7 @@ REST are attributes and the function BODY." (lambda (extended obsolete body) (when (stringp extended) (compat-macs--assert - (and (version< extended compat-macs--version) (version< "24.4" extended)) + (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)) diff --git a/compat-tests.el b/compat-tests.el index 7c67dc0..4c4b0c3 100644 --- a/compat-tests.el +++ b/compat-tests.el @@ -44,9 +44,8 @@ ;; calling convention or behavior changed between Emacs versions. ;; The functions tested here are guaranteed to work on the Emacs versions -;; tested by continuous integration. This includes 24.4, 24.5, 25.1, 25.2, -;; 25.3, 26.1, 26.2, 26.3, 27.1, 27.2, 28.1, 28.2, 29.1 and the current -;; Emacs master branch. +;; tested by continuous integration. This includes the versions 25.x, +;; 26.x, 27.x, 28.x, 29.x, 30.x and the current Emacs master branch. ;;; Code: @@ -2890,12 +2889,10 @@ (ert-deftest compat-region-bounds () (should-error (region-bounds)) - ;; FIXME: On Emacs 24 `region-bounds' always returns a continuous region. - (when (> emacs-major-version 24) - (let ((region-extract-function #'ignore)) - (should-not (region-bounds))) - (let ((region-extract-function (lambda (_) '((2 . 3) (6 . 7))))) - (should-equal (region-bounds) '((2 . 3) (6 . 7))))) + (let ((region-extract-function #'ignore)) + (should-not (region-bounds))) + (let ((region-extract-function (lambda (_) '((2 . 3) (6 . 7))))) + (should-equal (region-bounds) '((2 . 3) (6 . 7)))) (with-temp-buffer (insert "abc\ndef\n") (set-mark 2) @@ -2903,9 +2900,8 @@ (should-equal (region-bounds) '((2 . 7))))) (ert-deftest compat-region-noncontiguous-p () - (when (> emacs-major-version 24) - (let ((region-extract-function (lambda (_) '((2 . 3) (6 . 7))))) - (should (region-noncontiguous-p)))) + (let ((region-extract-function (lambda (_) '((2 . 3) (6 . 7))))) + (should (region-noncontiguous-p))) (with-temp-buffer (insert "abc\ndef\n") (set-mark 2) @@ -2914,11 +2910,9 @@ (should-not (region-noncontiguous-p)) (should-not (use-region-noncontiguous-p)) (should (use-region-p)) - ;; FIXME: On Emacs 24 `region-bounds' always returns a continuous region. - (when (> emacs-major-version 24) - (let ((region-extract-function (lambda (_) '((2 . 3) (6 . 7))))) - (should (region-noncontiguous-p)) - (should (use-region-noncontiguous-p)))))) + (let ((region-extract-function (lambda (_) '((2 . 3) (6 . 7))))) + (should (region-noncontiguous-p)) + (should (use-region-noncontiguous-p))))) (ert-deftest compat-get-scratch-buffer-create () (should-equal "*scratch*" (buffer-name (get-scratch-buffer-create))) diff --git a/compat.el b/compat.el index 15af46c..def9869 100644 --- a/compat.el +++ b/compat.el @@ -6,7 +6,7 @@ ;; Maintainer: Compat Development <~pkal/compat-devel@lists.sr.ht> ;; Version: 30.0.2.0 ;; URL: https://github.com/emacs-compat/compat -;; Package-Requires: ((emacs "24.4") (seq "2.23")) +;; Package-Requires: ((emacs "25.1")) ;; Keywords: lisp, maint ;; This program is free software; you can redistribute it and/or modify diff --git a/compat.texi b/compat.texi index 55d05d1..6bb79ee 100644 --- a/compat.texi +++ b/compat.texi @@ -69,7 +69,6 @@ Introduction Support -* Emacs 25.1:: Compatibility support for Emacs 25.1 * Emacs 26.1:: Compatibility support for Emacs 26.1 * Emacs 27.1:: Compatibility support for Emacs 27.1 * Emacs 28.1:: Compatibility support for Emacs 28.1 @@ -97,7 +96,7 @@ for Emacs Lisp. By using Compat, an Elisp package does not have to make the decision to either use new and useful functionality or support old versions of Emacs. -The library provides support back until Emacs 24.4. The intended +The library provides support back until Emacs 25.1. The intended audience are package developers that are interested in using newer developments, without having to break compatibility. @@ -110,10 +109,10 @@ mirrors the version of Emacs releases. The current version of Compat corresponds to the current Emacs release. @example -;; Package-Requires: ((emacs "24.4") (compat "30.0.2.0")) +;; Package-Requires: ((emacs "25.1") (compat "30.0.2.0")) @end example -There is no need to depend on @code{emacs 24.4} specifically. One can +There is no need to depend on @code{emacs 25.1} specifically. One can choose any newer version, if features not provided by Compat necessitate it, for example bug fixes or UI improvements. @@ -207,11 +206,11 @@ technical reasons. The scope is intentionally restricted in order to limit the size of Compat and to ensure that the library stays maintainable. -Emacs version 24.4 is chosen as the oldest version supported by -Compat, since Elisp has seen significant changes at that version. -Since 24.4 Emacs major versions consistently bump the major version -number. On the library level, subr-x was introduced in 24.4. Most -popular Emacs packages already require 24.4 or even newer versions of +Emacs version 25.1 is chosen as the oldest version supported by Compat, +since Elisp has seen significant changes at that version. Since 25.1 +Emacs major versions consistently bump the major version number. On the +library level, seq and generics were introduced in 25.1. Most popular +Emacs packages already require 25.1 or even newer versions of Emacs. Supporting for more historical Emacs versions would complicate maintenance while only few packages and users would benefit. @@ -306,7 +305,6 @@ This section goes into the features that Compat manages and doesn't manage to provide for each Emacs version. @menu -* Emacs 25.1:: Compatibility support for Emacs 25.1 * Emacs 26.1:: Compatibility support for Emacs 26.1 * Emacs 27.1:: Compatibility support for Emacs 27.1 * Emacs 28.1:: Compatibility support for Emacs 28.1 @@ -315,275 +313,6 @@ manage to provide for each Emacs version. * Emacs 31.1:: Compatibility support for Emacs 31.1 @end menu -@node Emacs 25.1 -@section Emacs 25.1 - -@subsection Added Definitions -The following functions and macros are implemented in Emacs -25.1. These functions are made available by Compat on Emacs versions -older than 25.1. - -@c copied from lispref/help.texi -@defopt text-quoting-style -The value of this user option is a symbol that specifies the style -Emacs should use for single quotes in the wording of help and -messages. If the option's value is @code{curve}, the style is -@t{‘like this’} with curved single quotes. If the value is -@code{straight}, the style is @t{'like this'} with straight -apostrophes. If the value is @code{grave}, quotes are not translated -and the style is @t{`like this'} with grave accent and apostrophe, the -standard style before Emacs version 25. The default value @code{nil} -acts like @code{curve} if curved single quotes seem to be displayable, -and like @code{grave} otherwise. - -This option is useful on platforms that have problems with curved -quotes. You can customize it freely according to your personal -preference. -@end defopt - -@c based on lisp/simple.el -@defun region-bounds -Return the boundaries of the region. Value is a list of one or more -cons cells of the form @code{(start . end)}. It will have more than -one cons cell when the region is non-contiguous, see -@code{region-noncontiguous-p} and @code{extract-rectangle-bounds}. -@end defun - -@c based on lisp/simple.el -@defun region-noncontiguous-p -Return non-nil if the region contains several pieces. An example is a -rectangular region handled as a list of separate contiguous regions -for each line. -@end defun - -@c copied from lispref/positions.texi -@defmac save-mark-and-excursion body@dots{} -This macro is like @code{save-excursion}, but also saves and restores -the mark location and @code{mark-active}. This macro does what -@code{save-excursion} did before Emacs 25.1. -@end defmac - -@c copied from lispref/strings.texi -@defun format-message string &rest objects -This function acts like @code{format}, except it also converts any -grave accents (@t{`}) and apostrophes (@t{'}) in @var{string} as per -the value of @code{text-quoting-style}. - -Typically grave accent and apostrophe in the format translate to -matching curved quotes, e.g., @t{"Missing `%s'"} might result in -@t{"Missing ‘foo’"}. @xref{Text Quoting Style,,,elisp}, for how to -influence or inhibit this translation. - -@ref{Formatting Strings,,,elisp}. -@end defun - -@c copied from lispref/files.texi -@defun directory-name-p filename -This function returns non-@code{nil} if @var{filename} ends with a -directory separator character. This is the forward slash @samp{/} on -GNU and other POSIX-like systems; MS-Windows and MS-DOS recognize both -the forward slash and the backslash @samp{\} as directory separators. - -@xref{Directory Names,,,elisp}. -@end defun - -@c copied from lispref/strings.texi -@defun string-greaterp string1 string2 -This function returns the result of comparing @var{string1} and -@var{string2} in the opposite order, i.e., it is equivalent to calling -@code{(string-lessp @var{string2} @var{string1})}. - -@xref{Text Comparison,,,elisp}. -@end defun - -@c copied from lispref/files.texi -@defmac with-file-modes mode body@dots{} -This macro evaluates the @var{body} forms with the default permissions -for new files temporarily set to @var{modes} (whose value is as for -@code{set-file-modes} above). When finished, it restores the original -default file permissions, and returns the value of the last form in -@var{body}. - -This is useful for creating private files, for example. - -@xref{Changing Files,,,elisp}. -@end defmac - -@c copied from lispref/lists.texi -@defun alist-get key alist &optional default remove -This function is similar to @code{assq}. It finds the first association -@w{@code{(@var{key} . @var{value})}} by comparing @var{key} with -@var{alist} elements, and, if found, returns the @var{value} of that -association. If no association is found, the function returns -@var{default}. - -This is a generalized variable (@pxref{Generalized Variables,,,elisp}) -that can be used to change a value with @code{setf}. When using it to -set a value, optional argument @var{remove} non-@code{nil} means to -remove @var{key}'s association from @var{alist} if the new value is -@code{eql} to @var{default}. - -@ref{Association Lists,,,elisp}. -@end defun - -@defmac if-let (bindings@dots{}) then &rest else@dots{} -As with @code{let*}, @var{bindings} will consist of -@code{(@var{symbol} @var{value-form})} entries that are evaluated and -bound sequentially. If all @var{value-form} evaluate to -non-@code{nil} values, then @var{then} is evaluated as were the case -with a regular @code{let*} expression, with all the variables bound. -If any @var{value-form} evaluates to @code{nil}, @var{else} is -evaluated, without any bound variables. - -A binding may also optionally drop the @var{symbol}, and simplify to -@code{(@var{value-form})} if only the test is of interest. - -For the sake of backwards compatibility, it is possible to write a -single binding without a binding list: - -@example -@group -(if-let* (@var{symbol} (test)) foo bar) -@equiv{} -(if-let* ((@var{symbol} (test))) foo bar) -@end group -@end example -@end defmac - -@defmac when-let (bindings@dots{}) &rest body -As with @code{when}, if one is only interested in the case where all -@var{bindings} are non-nil. Otherwise @var{bindings} are interpreted -just as they are by @code{if-let*}. -@end defmac - -@c based on lisp/subr-x.el -@defun hash-table-empty hash-table -Check whether @var{hash-table} is empty (has 0 elements). -@end defun - -@c based on lisp/subr-x.el -@defmac thread-first &rest forms -Combine @var{forms} into a single expression by ``threading'' each -element as the @emph{first} argument of their successor. Elements of -@var{forms} can either be an list of an atom. - -For example, consider the threading expression and it's equivalent -macro expansion: - -@example -(thread-first - 5 - (+ 20) - (/ 25) - - - (+ 40)) -@equiv{} -(+ (- (/ (+ 5 20) 25)) 40) -@end example - -Note how the single @code{-} got converted into a list before threading. -This example uses arithmetic functions, but @code{thread-first} is not -restricted to arithmetic or side-effect free code. -@end defmac - -@defmac thread-last &rest forms -Combine @var{forms} into a single expression by ``threading'' each -element as the @emph{last} argument of their successor. Elements of -@var{forms} can either be an list of an atom. - -For example, consider the threading expression and it's equivalent -macro expansion: - -@example -(thread-first - 5 - (+ 20) - (/ 25) - - - (+ 40)) -@equiv{} -(+ 40 (- (/ 25 (+ 20 5)))) -@end example - -Note how the single @code{-} got converted into a list before threading. -This example uses arithmetic functions, but @code{thread-last} is not -restricted to arithmetic or side-effect free code. -@end defmac - -@c copied from lispref/macros.texi -@defun macroexpand-1 form &optional environment -This function expands macros like @code{macroexpand}, but it only -performs one step of the expansion: if the result is another macro call, -@code{macroexpand-1} will not expand it. - -@xref{Expansion,Expansion,,elisp}. -@end defun - -@c based on lisp/emacs-lisp/macroexp.el -@defun macroexp-quote e -Return an expression @var{e} such that @code{(eval e)} is @var{v}. -@end defun - -@c based on lisp/emacs-lisp/macroexp.el -@defun macroexp-parse body -Parse a function @var{body} into @code{(declarations . exps)}. -@end defun - -@defun bool-vector &rest objects -This function creates and returns a bool-vector whose elements are the -arguments, @var{objects}. - -@xref{Bool-Vectors,,,elisp}. -@end defun - -@subsection Missing Definitions -Compat does not provide support for the following Lisp features -implemented in 25.1: - -@itemize -@item -The function @code{macroexp-macroexpand}. -@item -The macro @code{macroexp-let2*}. -@item -The function @code{directory-files-recursively}. -@item -New @code{pcase} patterns. -@item -The hook @code{prefix-command-echo-keystrokes-functions} and -@code{prefix-command-preserve-state-hook}. -@item -The hook @code{pre-redisplay-functions}. -@item -The function @code{make-process}. -@item -Support for the variable @code{inhibit-message}. -@item -The @code{define-inline} functionality. -@item -The functions @code{string-collate-lessp} and -@code{string-collate-equalp}. -@item -The function @code{funcall-interactively}. -@item -The function @code{buffer-substring-with-bidi-context}. -@item -The function @code{font-info}. -@item -The function @code{default-font-width}. -@item -The function @code{window-font-height} and @code{window-font-width}. -@item -The function @code{window-max-chars-per-line}. -@item -The function @code{set-binary-mode}. -@item -The functions @code{bufferpos-to-filepos} and -@code{filepos-to-bufferpos}. -@item -The @code{thunk} library. -@end itemize - @node Emacs 26.1 @section Emacs 26.1 -- cgit v1.0