From aa6adc711e990cf1ddeee01c4ffd8a0b37683d11 Mon Sep 17 00:00:00 2001 From: Stefan Kangas Date: Sat, 29 Aug 2020 15:55:51 +0200 Subject: [PATCH] ; Sync seq.el with Emacs master and bump version to 2.22 --- packages/seq/seq-25.el | 189 ++++++++++++++++++++++++++++------------- packages/seq/seq.el | 2 +- 2 files changed, 131 insertions(+), 60 deletions(-) diff --git a/packages/seq/seq-25.el b/packages/seq/seq-25.el index d26bde6ec..d3f827792 100644 --- a/packages/seq/seq-25.el +++ b/packages/seq/seq-25.el @@ -1,6 +1,6 @@ ;;; seq-25.el --- seq.el implementation for Emacs 25.x -*- lexical-binding: t -*- -;; Copyright (C) 2014-2016 Free Software Foundation, Inc. +;; Copyright (C) 2014-2020 Free Software Foundation, Inc. ;; Author: Nicolas Petton ;; Keywords: sequences @@ -20,7 +20,7 @@ ;; 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 . +;; along with GNU Emacs. If not, see . ;;; Commentary: @@ -60,8 +60,11 @@ (seq--when-emacs-25-p -(require 'cl-generic) -(require 'cl-lib) ;; for cl-subseq + (eval-when-compile (require 'cl-generic)) + +;; We used to use some sequence functions from cl-lib, but this +;; dependency was swapped around so that it will be easier to make +;; seq.el preloaded in the future. See also Bug#39761#26. (defmacro seq-doseq (spec &rest body) "Loop over a sequence. @@ -114,6 +117,14 @@ name to be bound to the rest of SEQUENCE." "Return the number of elements of SEQUENCE." (length sequence)) +(defun seq-first (sequence) + "Return the first element of SEQUENCE." + (seq-elt sequence 0)) + +(defun seq-rest (sequence) + "Return a sequence of the elements of SEQUENCE except the first one." + (seq-drop sequence 1)) + (cl-defgeneric seq-do (function sequence) "Apply FUNCTION to each element of SEQUENCE, presumably for side effects. Return SEQUENCE." @@ -121,9 +132,19 @@ Return SEQUENCE." (defalias 'seq-each #'seq-do) -(cl-defgeneric seqp (sequence) - "Return non-nil if SEQUENCE is a sequence, nil otherwise." - (sequencep sequence)) +(defun seq-do-indexed (function sequence) + "Apply FUNCTION to each element of SEQUENCE and return nil. +Unlike `seq-map', FUNCTION takes two arguments: the element of +the sequence, and its index within the sequence." + (let ((index 0)) + (seq-do (lambda (elt) + (funcall function elt index) + (setq index (1+ index))) + sequence))) + +(cl-defgeneric seqp (object) + "Return non-nil if OBJECT is a sequence, nil otherwise." + (sequencep object)) (cl-defgeneric seq-copy (sequence) "Return a shallow copy of SEQUENCE." @@ -137,7 +158,27 @@ If END is omitted, it defaults to the length of the sequence. If START or END is negative, it counts from the end. Signal an error if START or END are outside of the sequence (i.e too large if positive or too small if negative)." - (cl-subseq sequence start 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 (length sequence))))) + (if (< start 0) (setq start (+ start (or len (setq len (length sequence)))))) + (unless (>= start 0) + (error "%s" errtext)) + (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)) + (copy-sequence sequence)))) + (t (error "Unsupported sequence: %s" sequence)))) (cl-defgeneric seq-map (function sequence) @@ -159,6 +200,7 @@ the sequence, and its index within the sequence." (setq index (1+ index)))) sequence))) + ;; faster implementation for sequences (sequencep) (cl-defmethod seq-map (function (sequence sequence)) (mapcar function sequence)) @@ -219,6 +261,9 @@ The result is a sequence of the same type as SEQUENCE." (let ((result (seq-sort pred (append sequence nil)))) (seq-into result (type-of sequence)))) +(cl-defmethod seq-sort (pred (list list)) + (sort (seq-copy list) pred)) + (defun seq-sort-by (function pred sequence) "Sort SEQUENCE using PRED as a comparison function. Elements of SEQUENCE are transformed by FUNCTION before being @@ -229,9 +274,6 @@ sorted. FUNCTION must be a function of one argument." (funcall function b))) sequence)) -(cl-defmethod seq-sort (pred (list list)) - (sort (seq-copy list) pred)) - (cl-defgeneric seq-reverse (sequence) "Return a sequence with elements of SEQUENCE in reverse order." (let ((result '())) @@ -249,7 +291,11 @@ sorted. FUNCTION must be a function of one argument." TYPE must be one of following symbols: vector, string or list. \n(fn TYPE SEQUENCE...)" - (apply #'cl-concatenate type (seq-map #'seq-into-sequence sequences))) + (pcase type + ('vector (apply #'vconcat sequences)) + ('string (apply #'concat sequences)) + ('list (apply #'append (append sequences '(nil)))) + (_ (error "Not a sequence type name: %S" type)))) (cl-defgeneric seq-into-sequence (sequence) "Convert SEQUENCE into a sequence. @@ -310,7 +356,8 @@ If SEQUENCE is empty, return INITIAL-VALUE and FUNCTION is not called." t)) (cl-defgeneric seq-some (pred sequence) - "Return the first value for which if (PRED element) is non-nil for in SEQUENCE." + "Return non-nil if PRED is satisfied for at least one element of SEQUENCE. +If so, return the first non-nil value returned by PRED." (catch 'seq--break (seq-doseq (elt sequence) (let ((result (funcall pred elt))) @@ -340,17 +387,28 @@ found or not." count)) (cl-defgeneric seq-contains (sequence elt &optional testfn) + (declare (obsolete seq-contains-p "27.1")) "Return the first element in SEQUENCE that is equal 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)) + (when (funcall (or testfn #'equal) elt e) + e)) sequence)) +(cl-defgeneric seq-contains-p (sequence elt &optional testfn) + "Return non-nil if SEQUENCE contains an element equal to ELT. +Equality is defined by TESTFN if non-nil or by `equal' if nil." + (catch 'seq--break + (seq-doseq (e sequence) + (when (funcall (or testfn #'equal) e elt) + (throw 'seq--break t))) + nil)) + (cl-defgeneric 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))) + (and (seq-every-p (lambda (item1) (seq-contains-p sequence2 item1 testfn)) sequence1) + (seq-every-p (lambda (item2) (seq-contains-p sequence1 item2 testfn)) sequence2))) (cl-defgeneric seq-position (sequence elt &optional testfn) "Return the index of the first element in SEQUENCE that is equal to ELT. @@ -368,7 +426,7 @@ Equality is defined by TESTFN if non-nil or by `equal' if nil." TESTFN is used to compare elements, or `equal' if TESTFN is nil." (let ((result '())) (seq-doseq (elt sequence) - (unless (seq-contains result elt testfn) + (unless (seq-contains-p result elt testfn) (setq result (cons elt result)))) (nreverse result))) @@ -393,7 +451,7 @@ negative integer or 0, nil is returned." "Return a list of the elements that appear in both SEQUENCE1 and SEQUENCE2. Equality is defined by TESTFN if non-nil or by `equal' if nil." (seq-reduce (lambda (acc elt) - (if (seq-contains sequence2 elt testfn) + (if (seq-contains-p sequence2 elt testfn) (cons elt acc) acc)) (seq-reverse sequence1) @@ -403,9 +461,9 @@ Equality is defined by TESTFN if non-nil or by `equal' if nil." "Return a list of the elements that appear in SEQUENCE1 but not in SEQUENCE2. Equality is defined by TESTFN if non-nil or by `equal' if nil." (seq-reduce (lambda (acc elt) - (if (not (seq-contains sequence2 elt testfn)) - (cons elt acc) - acc)) + (if (seq-contains-p sequence2 elt testfn) + acc + (cons elt acc))) (seq-reverse sequence1) '())) @@ -443,6 +501,47 @@ SEQUENCE must be a sequence of numbers or markers." (setq n (+ 1 n))) n)) +(defun seq--make-pcase-bindings (args) + "Return a list of bindings of the variables in ARGS to the elements of a sequence." + (let ((bindings '()) + (index 0) + (rest-marker nil)) + (seq-doseq (name args) + (unless rest-marker + (pcase name + (`&rest + (progn (push `(app (pcase--flip seq-drop ,index) + ,(seq--elt-safe args (1+ index))) + bindings) + (setq rest-marker t))) + (_ + (push `(app (pcase--flip seq--elt-safe ,index) ,name) bindings)))) + (setq index (1+ index))) + bindings)) + +(defun seq--make-pcase-patterns (args) + "Return a list of `(seq ...)' pcase patterns from the argument list ARGS." + (cons 'seq + (seq-map (lambda (elt) + (if (seqp elt) + (seq--make-pcase-patterns elt) + elt)) + args))) + +;; TODO: make public? +(defun seq--elt-safe (sequence n) + "Return element of SEQUENCE at the index N. +If no element is found, return nil." + (ignore-errors (seq-elt sequence n))) + +(cl-defgeneric 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))))) + + ;;; Optimized implementations for lists (cl-defmethod seq-drop ((list list) n) @@ -466,8 +565,8 @@ SEQUENCE must be a sequence of numbers or markers." (cl-defmethod seq-empty-p ((list list)) "Optimized implementation of `seq-empty-p' for lists." (null list)) - + (defun seq--into-list (sequence) "Concatenate the elements of SEQUENCE into a list." (if (listp sequence) @@ -486,45 +585,17 @@ SEQUENCE must be a sequence of numbers or markers." sequence (concat sequence))) -(defun seq--make-pcase-bindings (args) - "Return a list of bindings of the variables in ARGS to the elements of a sequence." - (let ((bindings '()) - (index 0) - (rest-marker nil)) - (seq-doseq (name args) - (unless rest-marker - (pcase name - (`&rest - (progn (push `(app (pcase--flip seq-drop ,index) - ,(seq--elt-safe args (1+ index))) - bindings) - (setq rest-marker t))) - (_ - (push `(app (pcase--flip seq--elt-safe ,index) ,name) bindings)))) - (setq index (1+ index))) - bindings)) +(defun seq--activate-font-lock-keywords () + "Activate font-lock keywords for some symbols defined in seq." + (font-lock-add-keywords 'emacs-lisp-mode + '("\\" "\\"))) -(defun seq--make-pcase-patterns (args) - "Return a list of `(seq ...)' pcase patterns from the argument list ARGS." - (cons 'seq - (seq-map (lambda (elt) - (if (seqp elt) - (seq--make-pcase-patterns elt) - elt)) - args))) - -;; TODO: make public? -(defun seq--elt-safe (sequence n) - "Return element of SEQUENCE at the index N. -If no element is found, return nil." - (ignore-errors (seq-elt sequence n)))) +(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)) -(cl-defgeneric 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))))) +) ; end seq--when-emacs-25-p (provide 'seq-25) ;;; seq-25.el ends here diff --git a/packages/seq/seq.el b/packages/seq/seq.el index 83d43929a..2aa612851 100644 --- a/packages/seq/seq.el +++ b/packages/seq/seq.el @@ -4,7 +4,7 @@ ;; Author: Nicolas Petton ;; Keywords: sequences -;; Version: 2.20 +;; Version: 2.22 ;; Package: seq ;; Maintainer: emacs-devel@gnu.org -- 2.28.0