emacs-diffs
[Top][All Lists]
Advanced

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

master b13356487f: Add new helper macros for minor modes to restore vari


From: Lars Ingebrigtsen
Subject: master b13356487f: Add new helper macros for minor modes to restore variables
Date: Fri, 6 May 2022 07:10:59 -0400 (EDT)

branch: master
commit b13356487fc3eaf82bfe51bee24ddf70c27c5834
Author: Lars Ingebrigtsen <larsi@gnus.org>
Commit: Lars Ingebrigtsen <larsi@gnus.org>

    Add new helper macros for minor modes to restore variables
    
    * doc/lispref/modes.texi (Defining Minor Modes): Document it.
    
    * lisp/emacs-lisp/easy-mmode.el (buffer-local-set-state): New macro.
    (buffer-local-set-state--get): Helper function.
    (buffer-local-restore-state): New function.
    
    * lisp/textmodes/word-wrap-mode.el (word-wrap-whitespace-mode):
    Use it to simplify code.
---
 doc/lispref/modes.texi                   |  9 +++++++++
 etc/NEWS                                 |  6 ++++++
 lisp/emacs-lisp/easy-mmode.el            | 33 ++++++++++++++++++++++++++++++++
 lisp/textmodes/word-wrap-mode.el         | 25 +++++++-----------------
 test/lisp/emacs-lisp/easy-mmode-tests.el | 12 +++++++++++-
 5 files changed, 66 insertions(+), 19 deletions(-)

diff --git a/doc/lispref/modes.texi b/doc/lispref/modes.texi
index ff09a78749..bfd9724173 100644
--- a/doc/lispref/modes.texi
+++ b/doc/lispref/modes.texi
@@ -1912,6 +1912,15 @@ This means ``use in modes derived from @code{text-mode}, 
but nowhere
 else''.  (There's an implicit @code{nil} element at the end.)
 @end defmac
 
+@defmac buffer-local-set-state variable value...
+Minor modes often set buffer-local variables that alters some features
+in Emacs.  When a minor mode is switched off, the mode is expected to
+restore the previous state of these variables.  This convenience macro
+helps with doing that: It works much like @code{setq-local}, but
+returns an object that can be used to restore these values back to
+their previous values/states (with the
+@code{buffer-local-restore-state} function).
+@end defmac
 
 @node Mode Line Format
 @section Mode Line Format
diff --git a/etc/NEWS b/etc/NEWS
index 6637eda00c..fa7e2c4dcc 100644
--- a/etc/NEWS
+++ b/etc/NEWS
@@ -1636,6 +1636,12 @@ functions.
 
 * Lisp Changes in Emacs 29.1
 
++++
+** New macro 'buffer-local-set-state'.
+This is a helper macro to be used by minor modes that wish to restore
+buffer-local variables back to their original states when the mode is
+switched off.
+
 ---
 ** New macro 'with-buffer-unmodified-if-unchanged'.
 If the buffer is marked as unmodified, and code does modifications
diff --git a/lisp/emacs-lisp/easy-mmode.el b/lisp/emacs-lisp/easy-mmode.el
index 8a76eaf58c..33c0472ea8 100644
--- a/lisp/emacs-lisp/easy-mmode.el
+++ b/lisp/emacs-lisp/easy-mmode.el
@@ -825,6 +825,39 @@ Interactively, COUNT is the prefix numeric argument, and 
defaults to 1."
            ,@body))
        (put ',prev-sym 'definition-name ',base))))
 
+
+(defmacro buffer-local-set-state (&rest pairs)
+  "Like `setq-local', but return an object that allows restoring previous 
state.
+Use `buffer-local-restore-state' on the returned object to
+restore the state.
+
+\(fn [VARIABLE VALUE]...)"
+  (declare (debug setq))
+  (unless (zerop (mod (length pairs) 2))
+    (error "PAIRS must have an even number of variable/value members"))
+  `(prog1
+       (buffer-local-set-state--get ',pairs)
+     (setq-local ,@pairs)))
+
+(defun buffer-local-set-state--get (pairs)
+  (let ((states nil))
+    (while pairs
+      (push (list (car pairs)
+                  (and (boundp (car pairs))
+                       (local-variable-p (car pairs)))
+                  (and (boundp (car pairs))
+                       (symbol-value (car pairs))))
+            states)
+      (setq pairs (cddr pairs)))
+    (nreverse states)))
+
+(defun buffer-local-restore-state (states)
+  "Restore buffer local variable values in STATES.
+STATES is an object returned by `buffer-local-set-state'."
+  (pcase-dolist (`(,variable ,local ,value) states)
+    (if local
+        (set variable value)
+      (kill-local-variable variable))))
 
 (provide 'easy-mmode)
 
diff --git a/lisp/textmodes/word-wrap-mode.el b/lisp/textmodes/word-wrap-mode.el
index 1459a3395c..c354fc773a 100644
--- a/lisp/textmodes/word-wrap-mode.el
+++ b/lisp/textmodes/word-wrap-mode.el
@@ -60,26 +60,15 @@ The characters to break on are defined by 
`word-wrap-whitespace-characters'."
   (if word-wrap-whitespace-mode
       (progn
         (setq-local word-wrap-mode--previous-state
-                    (list (category-table)
-                          (local-variable-p 'word-wrap-by-category)
-                          word-wrap-by-category
-                          (local-variable-p 'word-wrap)
-                          word-wrap))
+                    (cons (category-table)
+                          (buffer-local-set-state
+                           word-wrap-by-category t
+                           word-wrap t)))
         (set-category-table (copy-category-table))
         (dolist (char word-wrap-whitespace-characters)
-          (modify-category-entry char ?|))
-        (setq-local word-wrap-by-category t
-                    word-wrap t))
-    (pcase-let ((`(,table ,lby-cat ,by-cat
-                          ,lwrap ,wrap)
-                 word-wrap-mode--previous-state))
-      (if lby-cat
-          (setq-local word-wrap-by-category by-cat)
-        (kill-local-variable 'word-wrap-by-category))
-      (if lwrap
-          (setq-local word-wrap wrap)
-        (kill-local-variable 'word-wrap))
-      (set-category-table table))))
+          (modify-category-entry char ?|)))
+    (set-category-table (car word-wrap-mode--previous-state))
+    (buffer-local-restore-state (cdr word-wrap-mode--previous-state))))
 
 ;;;###autoload
 (define-globalized-minor-mode global-word-wrap-whitespace-mode
diff --git a/test/lisp/emacs-lisp/easy-mmode-tests.el 
b/test/lisp/emacs-lisp/easy-mmode-tests.el
index 0a3bbb189b..697bf6c215 100644
--- a/test/lisp/emacs-lisp/easy-mmode-tests.el
+++ b/test/lisp/emacs-lisp/easy-mmode-tests.el
@@ -60,6 +60,16 @@
     (easy-mmode-test-mode 'toggle)
     (should (eq easy-mmode-test-mode t))))
 
-(provide 'easy-mmode-tests)
+(ert-deftest test-local-set-state ()
+  (setq global 1)
+  (with-temp-buffer
+    (setq-local local 2)
+    (let ((state (buffer-local-set-state global 10
+                                         local 20
+                                         unexist 30)))
+      (buffer-local-restore-state state)
+      (should (= global 1))
+      (should (= local 2))
+      (should-not (boundp 'unexist)))))
 
 ;;; easy-mmode-tests.el ends here



reply via email to

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