[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
[elpa] externals/compat a660d13326 75/84: Add while-let from Emacs 29
From: |
ELPA Syncer |
Subject: |
[elpa] externals/compat a660d13326 75/84: Add while-let from Emacs 29 |
Date: |
Tue, 3 Jan 2023 08:57:38 -0500 (EST) |
branch: externals/compat
commit a660d133266ed981fd165ad6e9b23fdd9dcd514f
Author: Philip Kaludercic <philipk@posteo.net>
Commit: Philip Kaludercic <philipk@posteo.net>
Add while-let from Emacs 29
---
compat-29.el | 19 +++++++++++++++++
compat-tests.el | 63 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++
compat.texi | 8 ++++++++
3 files changed, 90 insertions(+)
diff --git a/compat-29.el b/compat-29.el
index 493f75fa4e..a47037ec07 100644
--- a/compat-29.el
+++ b/compat-29.el
@@ -486,6 +486,25 @@ this defaults to the current buffer."
(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)
diff --git a/compat-tests.el b/compat-tests.el
index 5c5c4f2df0..38fcc724b9 100644
--- a/compat-tests.el
+++ b/compat-tests.el
@@ -2135,5 +2135,68 @@ being compared against."
(should (eq (lookup-key map "a") nil))
(should (eq (lookup-key super "a") nil))))
+(ert-deftest compat-ref-while-let ()
+ "Check if the real `while-let' behaves as expected."
+ (skip-unless (fboundp 'while-let))
+ ;; Basic test
+ (let ((list (list 1 2 3 4 5)))
+ (while-let ((one (pop list))
+ (two (pop list)))
+ (should one)
+ (should two)
+ (should (< one two)))
+ (should (null list)))
+ ;; Practical test
+ (with-temp-buffer
+ (insert "1 2 3 4 1 2 3 4 1 2 3 4")
+ (goto-char (point-min))
+ (let ((count 0))
+ (while-let (((search-forward-regexp "2" nil t))
+ (match (match-string 0))
+ ((string= match "2")))
+ (setq count (1+ count)))
+ (should (= count 3))))
+ ;; Edge cases
+ (catch 'break
+ (while-let ()
+ (throw 'break (should t))))
+ (while-let ((()))
+ (should nil))
+ (while-let ((test nil))
+ (should nil))
+ (while-let (((ignore)))
+ (should nil)))
+
+(ert-deftest compat-impl-while-let ()
+ "Check if the compat `while-let' behaves as expected."
+ ;; Basic test
+ (let ((list (list 1 2 3 4 5)))
+ (compat--while-let ((one (pop list))
+ (two (pop list)))
+ (should one)
+ (should two)
+ (should (< one two)))
+ (should (null list)))
+ ;; Practical test
+ (with-temp-buffer
+ (insert "1 2 3 4 1 2 3 4 1 2 3 4")
+ (goto-char (point-min))
+ (let ((count 0))
+ (compat--while-let (((search-forward-regexp "2" nil t))
+ (match (match-string 0))
+ ((string= match "2")))
+ (setq count (1+ count)))
+ (should (= count 3))))
+ ;; Edge cases
+ (catch 'break
+ (compat--while-let ()
+ (throw 'break (should t))))
+ (compat--while-let ((()))
+ (should nil))
+ (compat--while-let ((test nil))
+ (should nil))
+ (compat--while-let (((ignore)))
+ (should nil)))
+
(provide 'compat-tests)
;;; compat-tests.el ends here
diff --git a/compat.texi b/compat.texi
index da6cee008b..c488bb7d12 100644
--- a/compat.texi
+++ b/compat.texi
@@ -2825,6 +2825,14 @@ Here's an example:
@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:
- [elpa] externals/compat 68c6ccd5cc 68/84: Always load compat-macs, (continued)
- [elpa] externals/compat 68c6ccd5cc 68/84: Always load compat-macs, ELPA Syncer, 2023/01/03
- [elpa] externals/compat 54565a768c 73/84: Abbreviate Makefile by re-using BYTEC, ELPA Syncer, 2023/01/03
- [elpa] externals/compat 661ba3a441 74/84: Use 'equal' instead of 'file-equal-p', ELPA Syncer, 2023/01/03
- [elpa] externals/compat 55080acac2 82/84: Preliminary bump the version tag to 29.1.0.0-dev, ELPA Syncer, 2023/01/03
- [elpa] externals/compat 4bd1226048 59/84: Rewrite take to copy only as much as required, ELPA Syncer, 2023/01/03
- [elpa] externals/compat 835b4301b4 62/84: Add 'pure' and 'side-effect-free' properties to take, ELPA Syncer, 2023/01/03
- [elpa] externals/compat e7413bcf2b 63/84: Document additional missing functions from compat-29, ELPA Syncer, 2023/01/03
- [elpa] externals/compat 7e4533ab45 65/84: Add compatibility notices to the end of the docstring, ELPA Syncer, 2023/01/03
- [elpa] externals/compat 2ad7057293 70/84: Always load compat-macs.el while compiling, ELPA Syncer, 2023/01/03
- [elpa] externals/compat 59e50fc7f4 71/84: Remove compat-macs.el from the list of files to byte-compile, ELPA Syncer, 2023/01/03
- [elpa] externals/compat a660d13326 75/84: Add while-let from Emacs 29,
ELPA Syncer <=
- [elpa] externals/compat fcac0fa893 81/84: Update copyright years, ELPA Syncer, 2023/01/03
- [elpa] externals/compat 8fbc3b6ea6 69/84: Bump to version 28.1.2.2, ELPA Syncer, 2023/01/03
- [elpa] externals/compat f42ebfaf97 35/84: Use compat--directory-name-p instead of directory-name-p, ELPA Syncer, 2023/01/03
- [elpa] externals/compat b98e7cc868 39/84: Fix gv-expander for compat-alist-get, ELPA Syncer, 2023/01/03
- [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