[Top][All Lists]

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

master 297d3d2: * lisp/subr.el (dlet): New macro

From: Stefan Monnier
Subject: master 297d3d2: * lisp/subr.el (dlet): New macro
Date: Tue, 10 Mar 2020 12:00:57 -0400 (EDT)

branch: master
commit 297d3d2e0e17185387c47ad5a0ce4dd448ef7a29
Author: Stefan Monnier <address@hidden>
Commit: Stefan Monnier <address@hidden>

    * lisp/subr.el (dlet): New macro
    * lisp/calendar/calendar.el (calendar-dlet*): Use it.
 etc/NEWS                  |  2 ++
 lisp/calendar/calendar.el | 13 ++++++-------
 lisp/subr.el              | 30 ++++++++++++++++++++++++++----
 3 files changed, 34 insertions(+), 11 deletions(-)

diff --git a/etc/NEWS b/etc/NEWS
index 52ba1f6..87e634f 100644
--- a/etc/NEWS
+++ b/etc/NEWS
@@ -216,6 +216,8 @@ This is no longer supported, and setting this variable has 
no effect.
 * Lisp Changes in Emacs 28.1
+** New macro 'dlet' to dynamically bind variables
 ** The variable 'force-new-style-backquotes' has been removed.
 This removes the final remaining trace of old-style backquotes.
diff --git a/lisp/calendar/calendar.el b/lisp/calendar/calendar.el
index 1ae3944..1d5b947 100644
--- a/lisp/calendar/calendar.el
+++ b/lisp/calendar/calendar.el
@@ -136,14 +136,13 @@
 ;; - whatever is passed to diary-remind
 (defmacro calendar-dlet* (binders &rest body)
-  "Like `let*' but using dynamic scoping."
+  "Like `dlet' but without warnings about non-prefixed var names."
   (declare (indent 1) (debug let))
-  `(progn
-     (with-no-warnings                  ;Silence "lacks a prefix" warnings!
-       ,@(mapcar (lambda (binder)
-                   `(defvar ,(if (consp binder) (car binder) binder)))
-                 binders))
-     (let* ,binders ,@body)))
+  (let ((vars (mapcar (lambda (binder)
+                        (if (consp binder) (car binder) binder))
+                      binders)))
+    `(with-suppressed-warnings ((lexical ,@vars))
+       (dlet ,binders ,@body))))
 ;; Avoid recursive load of calendar when loading cal-menu.  Yuck.
 (provide 'calendar)
diff --git a/lisp/subr.el b/lisp/subr.el
index 13515ca..359f51c 100644
--- a/lisp/subr.el
+++ b/lisp/subr.el
@@ -1777,6 +1777,21 @@ all symbols are bound before any of the VALUEFORMs are 
      ,@(mapcar (lambda (binder) `(setq ,@binder)) binders)
+(defmacro dlet (binders &rest body)
+  "Like `let*' but using dynamic scoping."
+  (declare (indent 1) (debug let))
+  ;; (defvar FOO) only affects the current scope, but in order for
+  ;; this not to affect code after the `let*' we need to create a new scope,
+  ;; which is what the surrounding `let' is for.
+  ;; FIXME: (let () ...) currently doesn't actually create a new scope,
+  ;; which is why we use (let (_) ...).
+  `(let (_)
+     ,@(mapcar (lambda (binder)
+                 `(defvar ,(if (consp binder) (car binder) binder)))
+               binders)
+     (let* ,binders ,@body)))
 (defmacro with-wrapper-hook (hook args &rest body)
   "Run BODY, using wrapper functions from HOOK with additional ARGS.
 HOOK is an abnormal hook.  Each hook function in HOOK \"wraps\"
@@ -2972,13 +2987,14 @@ This finishes the change group by reverting all of its 
        ;; the body of `atomic-change-group' all changes can be undone.
        (let ((old-car (car-safe elt))
-             (old-cdr (cdr-safe elt)))
+             (old-cdr (cdr-safe elt))
+             (start-pul pending-undo-list))
                 ;; Temporarily truncate the undo log at ELT.
                 (when (consp elt)
                   (setcar elt nil) (setcdr elt nil))
-                (unless (eq last-command 'undo) (undo-start))
+                (setq pending-undo-list buffer-undo-list)
                 ;; Make sure there's no confusion.
                 (when (and (consp elt) (not (eq elt (last pending-undo-list))))
                   (error "Undoing to some unrelated state"))
@@ -2991,7 +3007,13 @@ This finishes the change group by reverting all of its 
             ;; Reset the modified cons cell ELT to its original content.
             (when (consp elt)
               (setcar elt old-car)
-              (setcdr elt old-cdr))))))))
+              (setcdr elt old-cdr)))
+          ;; Let's not break a sequence of undos just because we
+          ;; tried to make a change and then undid it: preserve
+          ;; the original `pending-undo-list' if it's still valid.
+          (if (eq (undo--last-change-was-undo-p buffer-undo-list)
+                  start-pul)
+              (setq pending-undo-list start-pul)))))))
 ;;;; Display-related functions.
@@ -3970,7 +3992,7 @@ the function `undo--wrap-and-run-primitive-undo'."
        (let (;; (inhibit-modification-hooks t)
                ;; Ugly Hack: if the body uses syntax-ppss/syntax-propertize
-               ;; (e.g. via a regexp-search or sexp-movement trigerring
+               ;; (e.g. via a regexp-search or sexp-movement triggering
                ;; on-the-fly syntax-propertize), make sure that this gets
                ;; properly refreshed after subsequent changes.
                (if (memq #'syntax-ppss-flush-cache before-change-functions)

reply via email to

[Prev in Thread] Current Thread [Next in Thread]