'work-buffer--release' kill locals silently and reset the buffer (bug#81111)

This change helps ensure that work buffers are "clean" for reuse
by arbitrary callers.

* lisp/emacs-lisp/subr-x.el (work-buffer--release): Call
'kill-all-local-variables' with KILL-PERMANENT 'reset.
* src/buffer.c (Fkill_all_local_variables): If KILL-PERMANENT is
'permanent-local, kill all locals without prejudice.  If
KILL-PERMANENT is 'reset, also call 'reset_buffer'.
* test/lisp/emacs-lisp/subr-x-tests.el
(subr-x-with-work-buffer-locals-killed): New test.
* doc/lispref/variables.texi: Update 'kill-all-local-variables'
documentation.
* etc/NEWS: Announce the change to 'kill-all-local-variables'.
This commit is contained in:
Stéphane Marks 2026-06-10 14:45:52 -04:00 committed by Eli Zaretskii
parent 1c17d2a045
commit c6c4888ced
5 changed files with 60 additions and 6 deletions

View file

@ -1748,6 +1748,14 @@ local hook functions that have a non-@code{nil}
killed, but if the optional @var{kill-permanent} argument is killed, but if the optional @var{kill-permanent} argument is
non-@code{nil}, even those variables will be killed. non-@code{nil}, even those variables will be killed.
If @var{kill-permanent} is the symbol @code{permanent-local} the
function @code{kill-all-local-variables} kills local variables and
ignores any variable watchers. If it is the symbol @code{reset},
variable watchers are ignored and the buffer is reset as if the buffer
was newly created. Use the foregoing with caution: For example,
@code{reset} sets buffer variables such as @code{default-directory} to
@code{nil} and may result in unexpected behavior.
This function also resets certain other information pertaining to the This function also resets certain other information pertaining to the
buffer: it sets the local keymap to @code{nil}, the syntax table to the buffer: it sets the local keymap to @code{nil}, the syntax table to the
value of @code{(standard-syntax-table)}, the case table to value of @code{(standard-syntax-table)}, the case table to

View file

@ -137,6 +137,20 @@ To install the grammars, use 'M-x markdown-ts-mode-install-parsers'.
* Lisp Changes in Emacs 32.1 * Lisp Changes in Emacs 32.1
+++
** 'kill-all-local-variables' can kill locals silently and reset the buffer.
This function's KILL-PERMANENT argument now accepts 'permanent-local'
which kills all locals ignoring any variable watchers, and also 'reset'
which does what 'permanent-local' does and also resets the buffer as if
newly created. Use these with caution to avoid unexpected behavior such
as 'default-directory' being reset to nil.
---
** 'with-work-buffer' kills all locals silently and resets its buffers.
This macro, when returning a buffer to its share buffer pool, now kills
all buffer locals silently, ignoring any variable watchers, and resets
the buffer as if newly created.
+++ +++
** The new function 'markers-in' returns the set of markers in a region. ** The new function 'markers-in' returns the set of markers in a region.

View file

@ -334,10 +334,10 @@ automatically killed, which means that in a such case
(erase-buffer) (erase-buffer)
(delete-all-overlays)) (delete-all-overlays))
(let (change-major-mode-hook) (let (change-major-mode-hook)
;; `kill-all-local-variables' does not kill permanent locals ;; Ensure `kill-all-local-variables' kills *all* permanent locals
;; like `buffer-read-only'. ;; rather than exempting any, and resets the buffer to pristine
(setq buffer-read-only nil) ;; state.
(kill-all-local-variables t)) (kill-all-local-variables 'reset))
;; Make the buffer available again. ;; Make the buffer available again.
(push buffer work-buffer--list))) (push buffer work-buffer--list)))
;; If the maximum number of reusable work buffers is exceeded, kill ;; If the maximum number of reusable work buffers is exceeded, kill

View file

@ -3031,15 +3031,33 @@ As a special exception, local variables whose names have a non-nil
the optional KILL-PERMANENT argument is non-nil, clear out these local the optional KILL-PERMANENT argument is non-nil, clear out these local
variables, too. variables, too.
If KILL-PERMANENT is the symbol `permanent-local', kill local variables
and ignore variable watchers. If KILL-PERMANENT is the symbol `reset',
ignore variable watchers and reset the buffer as if newly created. Use
these with caution. For example, `reset' sets buffer variables such as
`default-directory' to nil and may result in unexpected behavior.
The first thing this function does is run The first thing this function does is run
the normal hook `change-major-mode-hook'. */) the normal hook `change-major-mode-hook'. */)
(Lisp_Object kill_permanent) (Lisp_Object kill_permanent)
{ {
run_hook (Qchange_major_mode_hook); run_hook (Qchange_major_mode_hook);
/* Actually eliminate all local bindings of this buffer. */ int permanent_too = 0;
if (!NILP (kill_permanent))
{
permanent_too = 2;
if (EQ (kill_permanent, Qpermanent_local))
permanent_too = 1;
else if (EQ (kill_permanent, Qreset))
{
permanent_too = 1;
reset_buffer (current_buffer);
}
}
reset_buffer_local_variables (current_buffer, !NILP (kill_permanent) ? 2 : 0); /* Actually eliminate all local bindings of this buffer. */
reset_buffer_local_variables (current_buffer, permanent_too);
/* Force mode-line redisplay. Useful here because all major mode /* Force mode-line redisplay. Useful here because all major mode
commands call this function. */ commands call this function. */

View file

@ -815,5 +815,19 @@
(should (equal (string-truncate-left "band" 2) "...d")) (should (equal (string-truncate-left "band" 2) "...d"))
(should (equal (string-truncate-left "longstring" 8) "...tring"))) (should (equal (string-truncate-left "longstring" 8) "...tring")))
(ert-deftest subr-x-with-work-buffer-locals-killed ()
(let (b)
(with-work-buffer
(setq b (current-buffer))
(setq-local test-buffer-local 123)
(setq mark-active t)
(setq buffer-read-only t))
(with-work-buffer
;; Sanity check `with-work-buffer' yields the same buffer.
(should (eq b (current-buffer)))
(should-not (buffer-local-boundp 'test-buffer-local (current-buffer)))
(should-not mark-active)
(should-not buffer-read-only))))
(provide 'subr-x-tests) (provide 'subr-x-tests)
;;; subr-x-tests.el ends here ;;; subr-x-tests.el ends here