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.
This commit is contained in:
parent
0bda1803bb
commit
b13356487f
5 changed files with 66 additions and 19 deletions
|
@ -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
|
||||
|
|
6
etc/NEWS
6
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
|
||||
|
|
|
@ -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)
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
Loading…
Add table
Reference in a new issue