]> git.eshelyaron.com Git - emacs.git/commitdiff
Inhibit buffer hooks in temporary buffers
authorBasil L. Contovounesios <contovob@tcd.ie>
Sat, 19 Dec 2020 12:39:45 +0000 (12:39 +0000)
committerBasil L. Contovounesios <contovob@tcd.ie>
Sun, 20 Dec 2020 17:32:24 +0000 (17:32 +0000)
Give get-buffer-create an optional argument to inhibit buffer hooks
in internal or temporary buffers for efficiency (bug#34765).

* etc/NEWS: Announce new parameter of get-buffer-create and
generate-new-buffer, and that with-temp-buffer and with-temp-file
now inhibit buffer hooks.

* doc/lispref/buffers.texi (Buffer Names): Fix typo.
(Creating Buffers): Document new parameter of get-buffer-create and
generate-new-buffer.
(Buffer List, Killing Buffers): Document when buffer hooks are
inhibited.
(Current Buffer):
* doc/lispref/files.texi (Writing to Files): Document that
with-temp-buffer and with-temp-file inhibit buffer hooks.
* doc/lispref/internals.texi (Buffer Internals): Document
inhibit_buffer_hooks flag.  Remove stale comment.
* doc/misc/gnus-faq.texi (FAQ 5-8):
* lisp/simple.el (shell-command-on-region): Fix indentation.

* lisp/files.el (kill-buffer-hook): Document when hook is inhibited.
(create-file-buffer):
* lisp/gnus/gnus-uu.el (gnus-uu-unshar-article):
* lisp/international/mule.el (load-with-code-conversion):
* lisp/mh-e/mh-xface.el (mh-x-image-url-fetch-image):
* lisp/net/imap.el (imap-open):
* lisp/net/mailcap.el (mailcap-maybe-eval):
* lisp/progmodes/flymake-proc.el
(flymake-proc--read-file-to-temp-buffer)
(flymake-proc--copy-buffer-to-temp-buffer): Simplify.

* lisp/subr.el (generate-new-buffer): Forward new optional argument
to inhibit buffer hooks to get-buffer-create.
(with-temp-file, with-temp-buffer, with-output-to-string):
* lisp/json.el (json-encode-string): Inhibit buffer hooks in buffer
used.

* src/buffer.c (run_buffer_list_update_hook): New helper function.
(Fget_buffer_create): Use it.  Add optional argument to set
inhibit_buffer_hooks flag instead of comparing the buffer name to
Vcode_conversion_workbuf_name.  All callers changed.
(Fmake_indirect_buffer, Frename_buffer, Fbury_buffer_internal)
(record_buffer): Use run_buffer_list_update_hook.
(Fkill_buffer): Document when buffer hooks are inhibited.  Use
run_buffer_list_update_hook.
(init_buffer_once): Inhibit buffer hooks in Vprin1_to_string_buffer.
(Vkill_buffer_query_functions, Vbuffer_list_update_hook): Document
when hooks are inhibited.
* src/buffer.h (struct buffer): Update inhibit_buffer_hooks
commentary.
* src/coding.h (Vcode_conversion_workbuf_name):
* src/coding.c (Vcode_conversion_workbuf_name): Make static again
since it is no longer needed in src/buffer.c.
(code_conversion_restore, code_conversion_save, syms_of_coding):
Prefer boolean over integer constants.
* src/fileio.c (Finsert_file_contents): Inhibit buffer hooks in
" *code-converting-work*" buffer.
* src/window.c (Fselect_window): Fix grammar.  Mention
window-selection-change-functions alongside buffer-list-update-hook.

* test/src/buffer-tests.el: Fix requires.
(buffer-tests-inhibit-buffer-hooks): New test.

30 files changed:
doc/lispref/buffers.texi
doc/lispref/files.texi
doc/lispref/internals.texi
doc/misc/gnus-faq.texi
etc/NEWS
lisp/files.el
lisp/gnus/gnus-uu.el
lisp/international/mule.el
lisp/json.el
lisp/mh-e/mh-xface.el
lisp/net/imap.el
lisp/net/mailcap.el
lisp/progmodes/flymake-proc.el
lisp/simple.el
lisp/subr.el
src/buffer.c
src/buffer.h
src/callproc.c
src/coding.c
src/coding.h
src/fileio.c
src/minibuf.c
src/print.c
src/process.c
src/w32fns.c
src/window.c
src/xdisp.c
src/xfns.c
src/xwidget.c
test/src/buffer-tests.el

index 28603436284eab48613217c431b5ce873c4b31ad..33eb23984dd3193668f2f0acbee14e0f384d0254 100644 (file)
@@ -225,13 +225,22 @@ current buffer is restored even in case of an abnormal exit via
 
 @defmac with-temp-buffer body@dots{}
 @anchor{Definition of with-temp-buffer}
-The @code{with-temp-buffer} macro evaluates the @var{body} forms
-with a temporary buffer as the current buffer.  It saves the identity of
+The @code{with-temp-buffer} macro evaluates the @var{body} forms with
+a temporary buffer as the current buffer.  It saves the identity of
 the current buffer, creates a temporary buffer and makes it current,
 evaluates the @var{body} forms, and finally restores the previous
-current buffer while killing the temporary buffer.  By default, undo
-information (@pxref{Undo}) is not recorded in the buffer created by
-this macro (but @var{body} can enable that, if needed).
+current buffer while killing the temporary buffer.
+
+@cindex undo in temporary buffers
+@cindex @code{kill-buffer-hook} in temporary buffers
+@cindex @code{kill-buffer-query-functions} in temporary buffers
+@cindex @code{buffer-list-update-hook} in temporary buffers
+By default, undo information (@pxref{Undo}) is not recorded in the
+buffer created by this macro (but @var{body} can enable that, if
+needed).  The temporary buffer also does not run the hooks
+@code{kill-buffer-hook}, @code{kill-buffer-query-functions}
+(@pxref{Killing Buffers}), and @code{buffer-list-update-hook}
+(@pxref{Buffer List}).
 
 The return value is the value of the last form in @var{body}.  You can
 return the contents of the temporary buffer by using
@@ -345,9 +354,9 @@ incrementing the number until it is not the name of an existing buffer.
 
 If the optional second argument @var{ignore} is non-@code{nil}, it
 should be a string, a potential buffer name.  It means to consider
-that potential buffer acceptable, if it is tried, even it is the name
-of an existing buffer (which would normally be rejected).  Thus, if
-buffers named @samp{foo}, @samp{foo<2>}, @samp{foo<3>} and
+that potential buffer acceptable, if it is tried, even if it is the
+name of an existing buffer (which would normally be rejected).  Thus,
+if buffers named @samp{foo}, @samp{foo<2>}, @samp{foo<3>} and
 @samp{foo<4>} exist,
 
 @example
@@ -932,13 +941,17 @@ window.
 @defvar buffer-list-update-hook
 This is a normal hook run whenever the buffer list changes.  Functions
 (implicitly) running this hook are @code{get-buffer-create}
-(@pxref{Creating Buffers}), @code{rename-buffer} (@pxref{Buffer Names}),
-@code{kill-buffer} (@pxref{Killing Buffers}), @code{bury-buffer} (see
-above) and @code{select-window} (@pxref{Selecting Windows}).
+(@pxref{Creating Buffers}), @code{rename-buffer} (@pxref{Buffer
+Names}), @code{kill-buffer} (@pxref{Killing Buffers}),
+@code{bury-buffer} (see above), and @code{select-window}
+(@pxref{Selecting Windows}).  This hook is not run for internal or
+temporary buffers created by @code{get-buffer-create} or
+@code{generate-new-buffer} with a non-@code{nil} argument
+@var{inhibit-buffer-hooks}.
 
 Functions run by this hook should avoid calling @code{select-window}
-with a nil @var{norecord} argument or @code{with-temp-buffer} since
-either may lead to infinite recursion.
+with a @code{nil} @var{norecord} argument since this may lead to
+infinite recursion.
 @end defvar
 
 @node Creating Buffers
@@ -951,12 +964,20 @@ either may lead to infinite recursion.
 with the specified name; @code{generate-new-buffer} always creates a new
 buffer and gives it a unique name.
 
+  Both functions accept an optional argument @var{inhibit-buffer-hooks}.
+If it is non-@code{nil}, the buffer they create does not run the hooks
+@code{kill-buffer-hook}, @code{kill-buffer-query-functions}
+(@pxref{Killing Buffers}), and @code{buffer-list-update-hook}
+(@pxref{Buffer List}).  This avoids slowing down internal or temporary
+buffers that are never presented to users or passed on to other
+applications.
+
   Other functions you can use to create buffers include
 @code{with-output-to-temp-buffer} (@pxref{Temporary Displays}) and
 @code{create-file-buffer} (@pxref{Visiting Files}).  Starting a
 subprocess can also create a buffer (@pxref{Processes}).
 
-@defun get-buffer-create buffer-or-name
+@defun get-buffer-create buffer-or-name &optional inhibit-buffer-hooks
 This function returns a buffer named @var{buffer-or-name}.  The buffer
 returned does not become the current buffer---this function does not
 change which buffer is current.
@@ -980,7 +1001,7 @@ level; see @ref{Auto Major Mode}.)  If the name begins with a space, the
 buffer initially disables undo information recording (@pxref{Undo}).
 @end defun
 
-@defun generate-new-buffer name
+@defun generate-new-buffer name &optional inhibit-buffer-hooks
 This function returns a newly created, empty buffer, but does not make
 it current.  The name of the buffer is generated by passing @var{name}
 to the function @code{generate-new-buffer-name} (@pxref{Buffer
@@ -1092,6 +1113,10 @@ with no arguments.  The buffer being killed is the current buffer when
 they are called.  The idea of this feature is that these functions will
 ask for confirmation from the user.  If any of them returns @code{nil},
 @code{kill-buffer} spares the buffer's life.
+
+This hook is not run for internal or temporary buffers created by
+@code{get-buffer-create} or @code{generate-new-buffer} with a
+non-@code{nil} argument @var{inhibit-buffer-hooks}.
 @end defvar
 
 @defvar kill-buffer-hook
@@ -1100,6 +1125,10 @@ questions it is going to ask, just before actually killing the buffer.
 The buffer to be killed is current when the hook functions run.
 @xref{Hooks}.  This variable is a permanent local, so its local binding
 is not cleared by changing major modes.
+
+This hook is not run for internal or temporary buffers created by
+@code{get-buffer-create} or @code{generate-new-buffer} with a
+non-@code{nil} argument @var{inhibit-buffer-hooks}.
 @end defvar
 
 @defopt buffer-offer-save
index d49ac42bb465ca9d786175555b82b4907d4aefb3..6949ca29c6ec32d657203ca07a0362e1ceb49671 100644 (file)
@@ -701,8 +701,11 @@ in @var{body}.
 The current buffer is restored even in case of an abnormal exit via
 @code{throw} or error (@pxref{Nonlocal Exits}).
 
-See also @code{with-temp-buffer} in @ref{Definition of
-with-temp-buffer,, The Current Buffer}.
+Like @code{with-temp-buffer} (@pxref{Definition of with-temp-buffer,,
+Current Buffer}), the temporary buffer used by this macro does not run
+the hooks @code{kill-buffer-hook}, @code{kill-buffer-query-functions}
+(@pxref{Killing Buffers}), and @code{buffer-list-update-hook}
+(@pxref{Buffer List}).
 @end defmac
 
 @node File Locks
index fa3dacbb7ae5d19b89cdbf606ec8d8dfc276726c..0adbef33cac9d79db7c5e8287e39ec88b30d9ca7 100644 (file)
@@ -2391,6 +2391,15 @@ This flag indicates that narrowing has changed in the buffer.
 This flag indicates that redisplay optimizations should not be used to
 display this buffer.
 
+@item inhibit_buffer_hooks
+This flag indicates that the buffer should not run the hooks
+@code{kill-buffer-hook}, @code{kill-buffer-query-functions}
+(@pxref{Killing Buffers}), and @code{buffer-list-update-hook}
+(@pxref{Buffer List}).  It is set at buffer creation (@pxref{Creating
+Buffers}), and avoids slowing down internal or temporary buffers, such
+as those created by @code{with-temp-buffer} (@pxref{Definition of
+with-temp-buffer,, Current Buffer}).
+
 @item overlay_center
 This field holds the current overlay center position.  @xref{Managing
 Overlays}.
@@ -2404,8 +2413,6 @@ after the current overlay center.  @xref{Managing Overlays}.
 and @code{overlays_after} is sorted in order of increasing beginning
 position.
 
-@c FIXME? the following are now all Lisp_Object BUFFER_INTERNAL_FIELD (foo).
-
 @item name
 A Lisp string that names the buffer.  It is guaranteed to be unique.
 @xref{Buffer Names}.  This and the following fields have their names
index adb812f57287655af6dffe10aa29940ebd37df07..c30e80ff56535bb987ae9195d61e608fa51cb0bf 100644 (file)
@@ -1523,10 +1523,10 @@ Now you only have to tell Gnus to include the X-face in your postings by saying
 
 @example
 (setq message-default-headers
-        (with-temp-buffer
-          (insert "X-Face: ")
-          (insert-file-contents "~/.xface")
-          (buffer-string)))
+      (with-temp-buffer
+        (insert "X-Face: ")
+        (insert-file-contents "~/.xface")
+        (buffer-string)))
 @end example
 @noindent
 
index 4a8e70e6a62a548da4142460d671554c29a5867f..1b4c21cb45000d72640e2caad6ef1634f3c8a33e 100644 (file)
--- a/etc/NEWS
+++ b/etc/NEWS
@@ -1821,6 +1821,13 @@ modifies the string's text properties; instead, it uses and returns
 a copy of the string.  This helps avoid trouble when strings are
 shared or constants.
 
++++
+** Temporary buffers no longer run certain buffer hooks.
+The macros 'with-temp-buffer' and 'with-temp-file' no longer run the
+hooks 'kill-buffer-hook', 'kill-buffer-query-functions', and
+'buffer-list-update-hook' for the temporary buffers they create.  This
+avoids slowing them down when a lot of these hooks are defined.
+
 ---
 ** The obsolete function 'thread-alive-p' has been removed.
 
@@ -2177,6 +2184,15 @@ Until it is solved you could ignore such errors by performing
 
 ** The error 'ftp-error' belongs also to category 'remote-file-error'.
 
++++
+** Buffers can now be created with certain hooks disabled.
+The functions 'get-buffer-create' and 'generate-new-buffer' accept a
+new optional argument 'inhibit-buffer-hooks'.  If non-nil, the new
+buffer does not run the hooks 'kill-buffer-hook',
+'kill-buffer-query-functions', and 'buffer-list-update-hook'.  This
+avoids slowing down internal or temporary buffers that are never
+presented to users or passed on to other applications.
+
 \f
 * Changes in Emacs 28.1 on Non-Free Operating Systems
 
index 093b5f92e58e1429c2172997dba0934b3c3721cf..70d451cccfa29a5f7b00dbe041bb05c7f38ee2fa 100644 (file)
@@ -1850,6 +1850,10 @@ expand wildcards (if any) and replace the file with multiple files."
 The buffer being killed is current while the hook is running.
 See `kill-buffer'.
 
+This hook is not run for internal or temporary buffers created by
+`get-buffer-create' or `generate-new-buffer' with argument
+INHIBIT-BUFFER-HOOKS non-nil.
+
 Note: Be careful with let-binding this hook considering it is
 frequently used for cleanup.")
 
@@ -1951,7 +1955,7 @@ this function prepends a \"|\" to the final result if necessary."
   (let ((lastname (file-name-nondirectory filename)))
     (if (string= lastname "")
        (setq lastname filename))
-    (generate-new-buffer (if (string-match-p "\\` " lastname)
+    (generate-new-buffer (if (string-prefix-p " " lastname)
                             (concat "|" lastname)
                           lastname))))
 
index 5980051ee451765482f6b86ed38df0cafc3c6e8e..db01fb135270e08573cf9882bb995026197fb655 100644 (file)
@@ -1587,8 +1587,7 @@ Gnus might fail to display all of it.")
          (save-excursion
            (switch-to-buffer (current-buffer))
            (delete-other-windows)
-           (let ((buffer (get-buffer-create (generate-new-buffer-name
-                                             "*Warning*"))))
+            (let ((buffer (generate-new-buffer "*Warning*")))
              (unless
                  (unwind-protect
                      (with-current-buffer buffer
index 212e7232b492da40430a8394cb8aa0d471f1ff6e..6571454dffed422ac232dd499b5cb8f317f11c1c 100644 (file)
@@ -307,12 +307,9 @@ Return t if file exists."
       (and (null noerror)
           (signal 'file-error (list "Cannot open load file" file)))
     ;; Read file with code conversion, and then eval.
-    (let* ((buffer
-            ;; We can't use `generate-new-buffer' because files.el
-            ;; is not yet loaded.
-            (get-buffer-create (generate-new-buffer-name " *load*")))
-          (load-in-progress t)
-          (source (save-match-data (string-match "\\.el\\'" fullname))))
+    (let ((buffer (generate-new-buffer " *load*"))
+          (load-in-progress t)
+          (source (string-suffix-p ".el" fullname)))
       (unless nomessage
        (if source
            (message "Loading %s (source)..." file)
index c2fc1574faa976c83222aae807abef0b7588f9f0..5f512b94cdc8b60954d0c8421be35ea9b9704fd5 100644 (file)
@@ -435,7 +435,7 @@ Initialized lazily by `json-encode-string'.")
       (concat "\"" (substring-no-properties string) "\"")
     (with-current-buffer
         (or json--string-buffer
-            (with-current-buffer (generate-new-buffer " *json-string*")
+            (with-current-buffer (generate-new-buffer " *json-string*" t)
               ;; This seems to afford decent performance gains.
               (setq-local inhibit-modification-hooks t)
               (setq json--string-buffer (current-buffer))))
index 909f1fe95d904e98f1141394b2025d18e12629ad..65039310e7b0824a1191e730b1e322332c98117c 100644 (file)
@@ -425,8 +425,7 @@ After the image is fetched, it is stored in CACHE-FILE. It will
 be displayed in a buffer and position specified by MARKER. The
 actual display is carried out by the SENTINEL function."
   (if mh-wget-executable
-      (let ((buffer (get-buffer-create (generate-new-buffer-name
-                                        mh-temp-fetch-buffer)))
+      (let ((buffer (generate-new-buffer mh-temp-fetch-buffer))
             (filename (or (mh-funcall-if-exists make-temp-file "mhe-fetch")
                           (expand-file-name (make-temp-name "~/mhe-fetch")))))
         (with-current-buffer buffer
index 27c2d869f6b49fb20f97dedf519320e9644806a3..fe895d7e23d1892eeb2df9ae8a409baece1a750b 100644 (file)
@@ -1033,8 +1033,7 @@ necessary.  If nil, the buffer name is generated."
            (when (funcall (nth 1 (assq stream imap-stream-alist)) buffer)
              ;; Stream changed?
              (if (not (eq imap-default-stream stream))
-                 (with-current-buffer (get-buffer-create
-                                       (generate-new-buffer-name " *temp*"))
+                  (with-current-buffer (generate-new-buffer " *temp*")
                    (mapc 'make-local-variable imap-local-variables)
                    (set-buffer-multibyte nil)
                    (buffer-disable-undo)
index d0f8c1272d783f22090622e6ee8d55a5ad136ed0..bc99f02fe33fe7e7595582841cb79e4ea58ba4f8 100644 (file)
@@ -386,8 +386,7 @@ Gnus might fail to display all of it.")
     (when
        (save-window-excursion
          (delete-other-windows)
-         (let ((buffer (get-buffer-create (generate-new-buffer-name
-                                           "*Warning*"))))
+          (let ((buffer (generate-new-buffer "*Warning*")))
            (unwind-protect
                (with-current-buffer buffer
                  (insert (substitute-command-keys
index 744c110f6b09ab418c13a07f4c207d77a3d1ad87..4975d4f35dd37eb684cd85dfc720860878ff5865 100644 (file)
@@ -431,16 +431,15 @@ instead of reading master file from disk."
 
 (defun flymake-proc--read-file-to-temp-buffer (file-name)
   "Insert contents of FILE-NAME into newly created temp buffer."
-  (let* ((temp-buffer (get-buffer-create (generate-new-buffer-name (concat "flymake:" (file-name-nondirectory file-name))))))
-    (with-current-buffer temp-buffer
-      (insert-file-contents file-name))
-    temp-buffer))
+  (with-current-buffer (generate-new-buffer
+                        (concat "flymake:" (file-name-nondirectory file-name)))
+    (insert-file-contents file-name)
+    (current-buffer)))
 
 (defun flymake-proc--copy-buffer-to-temp-buffer (buffer)
   "Copy contents of BUFFER into newly created temp buffer."
-  (with-current-buffer
-      (get-buffer-create (generate-new-buffer-name
-                          (concat "flymake:" (buffer-name buffer))))
+  (with-current-buffer (generate-new-buffer
+                        (concat "flymake:" (buffer-name buffer)))
     (insert-buffer-substring buffer)
     (current-buffer)))
 
index 9ed7a11de1997cbb4e68325100bd70f2ac1c8b20..b1c949d7c6d8ac12ee0f928832eb55318e954b45 100644 (file)
@@ -4307,8 +4307,7 @@ characters."
 (defun shell-command-to-string (command)
   "Execute shell command COMMAND and return its output as a string."
   (with-output-to-string
-    (with-current-buffer
-      standard-output
+    (with-current-buffer standard-output
       (shell-command command t))))
 
 (defun process-file (program &optional infile buffer display &rest args)
index 1b2d778454e215f90a50813937f5e2d00f845c89..7461fa2a15c015960cc65c7d5780bdbd810efd9c 100644 (file)
@@ -3701,10 +3701,11 @@ also `with-temp-buffer'."
   (when (window-live-p (nth 1 state))
     (select-window (nth 1 state) 'norecord)))
 
-(defun generate-new-buffer (name)
+(defun generate-new-buffer (name &optional inhibit-buffer-hooks)
   "Create and return a buffer with a name based on NAME.
-Choose the buffer's name using `generate-new-buffer-name'."
-  (get-buffer-create (generate-new-buffer-name name)))
+Choose the buffer's name using `generate-new-buffer-name'.
+See `get-buffer-create' for the meaning of INHIBIT-BUFFER-HOOKS."
+  (get-buffer-create (generate-new-buffer-name name) inhibit-buffer-hooks))
 
 (defmacro with-selected-window (window &rest body)
   "Execute the forms in BODY with WINDOW as the selected window.
@@ -3866,12 +3867,14 @@ See the related form `with-temp-buffer-window'."
 (defmacro with-temp-file (file &rest body)
   "Create a new buffer, evaluate BODY there, and write the buffer to FILE.
 The value returned is the value of the last form in BODY.
+The buffer does not run the hooks `kill-buffer-hook',
+`kill-buffer-query-functions', and `buffer-list-update-hook'.
 See also `with-temp-buffer'."
   (declare (indent 1) (debug t))
   (let ((temp-file (make-symbol "temp-file"))
        (temp-buffer (make-symbol "temp-buffer")))
     `(let ((,temp-file ,file)
-          (,temp-buffer (generate-new-buffer " *temp file*")))
+           (,temp-buffer (generate-new-buffer " *temp file*" t)))
        (unwind-protect
           (prog1
               (with-current-buffer ,temp-buffer
@@ -3906,10 +3909,12 @@ Use a MESSAGE of \"\" to temporarily clear the echo area."
 
 (defmacro with-temp-buffer (&rest body)
   "Create a temporary buffer, and evaluate BODY there like `progn'.
+The buffer does not run the hooks `kill-buffer-hook',
+`kill-buffer-query-functions', and `buffer-list-update-hook'.
 See also `with-temp-file' and `with-output-to-string'."
   (declare (indent 0) (debug t))
   (let ((temp-buffer (make-symbol "temp-buffer")))
-    `(let ((,temp-buffer (generate-new-buffer " *temp*")))
+    `(let ((,temp-buffer (generate-new-buffer " *temp*" t)))
        ;; `kill-buffer' can change current-buffer in some odd cases.
        (with-current-buffer ,temp-buffer
          (unwind-protect
@@ -3944,7 +3949,7 @@ of that nature."
 (defmacro with-output-to-string (&rest body)
   "Execute BODY, return the text it sent to `standard-output', as a string."
   (declare (indent 0) (debug t))
-  `(let ((standard-output (generate-new-buffer " *string-output*")))
+  `(let ((standard-output (generate-new-buffer " *string-output*" t)))
      (unwind-protect
         (progn
           (let ((standard-output standard-output))
index dfc34faf6e6e7121e87208490821a1275a6b304d..9e44345616e6d6a62521045e3cc378dbd932e982 100644 (file)
@@ -37,7 +37,6 @@ along with GNU Emacs.  If not, see <https://www.gnu.org/licenses/>.  */
 #include "window.h"
 #include "commands.h"
 #include "character.h"
-#include "coding.h"
 #include "buffer.h"
 #include "region-cache.h"
 #include "indent.h"
@@ -514,16 +513,33 @@ get_truename_buffer (register Lisp_Object filename)
   return Qnil;
 }
 
-DEFUN ("get-buffer-create", Fget_buffer_create, Sget_buffer_create, 1, 1, 0,
+/* Run buffer-list-update-hook if Vrun_hooks is non-nil, and BUF is NULL
+   or does not have buffer hooks inhibited.  BUF is NULL when called by
+   make-indirect-buffer, since it does not inhibit buffer hooks.  */
+
+static void
+run_buffer_list_update_hook (struct buffer *buf)
+{
+  if (! (NILP (Vrun_hooks) || (buf && buf->inhibit_buffer_hooks)))
+    call1 (Vrun_hooks, Qbuffer_list_update_hook);
+}
+
+DEFUN ("get-buffer-create", Fget_buffer_create, Sget_buffer_create, 1, 2, 0,
        doc: /* Return the buffer specified by BUFFER-OR-NAME, creating a new one if needed.
 If BUFFER-OR-NAME is a string and a live buffer with that name exists,
 return that buffer.  If no such buffer exists, create a new buffer with
-that name and return it.  If BUFFER-OR-NAME starts with a space, the new
-buffer does not keep undo information.
+that name and return it.
+
+If BUFFER-OR-NAME starts with a space, the new buffer does not keep undo
+information.  If optional argument INHIBIT-BUFFER-HOOKS is non-nil, the
+new buffer does not run the hooks `kill-buffer-hook',
+`kill-buffer-query-functions', and `buffer-list-update-hook'.  This
+avoids slowing down internal or temporary buffers that are never
+presented to users or passed on to other applications.
 
 If BUFFER-OR-NAME is a buffer instead of a string, return it as given,
 even if it is dead.  The return value is never nil.  */)
-  (register Lisp_Object buffer_or_name)
+  (register Lisp_Object buffer_or_name, Lisp_Object inhibit_buffer_hooks)
 {
   register Lisp_Object buffer, name;
   register struct buffer *b;
@@ -598,11 +614,7 @@ even if it is dead.  The return value is never nil.  */)
   set_string_intervals (name, NULL);
   bset_name (b, name);
 
-  b->inhibit_buffer_hooks
-    = (STRINGP (Vcode_conversion_workbuf_name)
-       && strncmp (SSDATA (name), SSDATA (Vcode_conversion_workbuf_name),
-                  SBYTES (Vcode_conversion_workbuf_name)) == 0);
-
+  b->inhibit_buffer_hooks = !NILP (inhibit_buffer_hooks);
   bset_undo_list (b, SREF (name, 0) != ' ' ? Qnil : Qt);
 
   reset_buffer (b);
@@ -614,9 +626,8 @@ even if it is dead.  The return value is never nil.  */)
   /* Put this in the alist of all live buffers.  */
   XSETBUFFER (buffer, b);
   Vbuffer_alist = nconc2 (Vbuffer_alist, list1 (Fcons (name, buffer)));
-  /* And run buffer-list-update-hook.  */
-  if (!NILP (Vrun_hooks) && !b->inhibit_buffer_hooks)
-    call1 (Vrun_hooks, Qbuffer_list_update_hook);
+
+  run_buffer_list_update_hook (b);
 
   return buffer;
 }
@@ -890,9 +901,7 @@ CLONE nil means the indirect buffer's state is reset to default values.  */)
       set_buffer_internal_1 (old_b);
     }
 
-  /* Run buffer-list-update-hook.  */
-  if (!NILP (Vrun_hooks))
-    call1 (Vrun_hooks, Qbuffer_list_update_hook);
+  run_buffer_list_update_hook (NULL);
 
   return buf;
 }
@@ -1536,9 +1545,7 @@ This does not change the name of the visited file (if any).  */)
       && !NILP (BVAR (current_buffer, auto_save_file_name)))
     call0 (intern ("rename-auto-save-file"));
 
-  /* Run buffer-list-update-hook.  */
-  if (!NILP (Vrun_hooks) && !current_buffer->inhibit_buffer_hooks)
-    call1 (Vrun_hooks, Qbuffer_list_update_hook);
+  run_buffer_list_update_hook (current_buffer);
 
   /* Refetch since that last call may have done GC.  */
   return BVAR (current_buffer, name);
@@ -1612,7 +1619,7 @@ exists, return the buffer `*scratch*' (creating it if necessary).  */)
       buf = Fget_buffer (scratch);
       if (NILP (buf))
        {
-         buf = Fget_buffer_create (scratch);
+         buf = Fget_buffer_create (scratch, Qnil);
          Fset_buffer_major_mode (buf);
        }
       return buf;
@@ -1636,7 +1643,7 @@ other_buffer_safely (Lisp_Object buffer)
   buf = Fget_buffer (scratch);
   if (NILP (buf))
     {
-      buf = Fget_buffer_create (scratch);
+      buf = Fget_buffer_create (scratch, Qnil);
       Fset_buffer_major_mode (buf);
     }
 
@@ -1713,7 +1720,9 @@ buffer to be killed as the current buffer.  If any of them returns nil,
 the buffer is not killed.  The hook `kill-buffer-hook' is run before the
 buffer is actually killed.  The buffer being killed will be current
 while the hook is running.  Functions called by any of these hooks are
-supposed to not change the current buffer.
+supposed to not change the current buffer.  Neither hook is run for
+internal or temporary buffers created by `get-buffer-create' or
+`generate-new-buffer' with argument INHIBIT-BUFFER-HOOKS non-nil.
 
 Any processes that have this buffer as the `process-buffer' are killed
 with SIGHUP.  This function calls `replace-buffer-in-windows' for
@@ -1973,9 +1982,7 @@ cleaning up all windows currently displaying the buffer to be killed. */)
   bset_width_table (b, Qnil);
   unblock_input ();
 
-  /* Run buffer-list-update-hook.  */
-  if (!NILP (Vrun_hooks) && !b->inhibit_buffer_hooks)
-    call1 (Vrun_hooks, Qbuffer_list_update_hook);
+  run_buffer_list_update_hook (b);
 
   return Qt;
 }
@@ -2015,9 +2022,7 @@ record_buffer (Lisp_Object buffer)
   fset_buffer_list (f, Fcons (buffer, Fdelq (buffer, f->buffer_list)));
   fset_buried_buffer_list (f, Fdelq (buffer, f->buried_buffer_list));
 
-  /* Run buffer-list-update-hook.  */
-  if (!NILP (Vrun_hooks) && !XBUFFER (buffer)->inhibit_buffer_hooks)
-    call1 (Vrun_hooks, Qbuffer_list_update_hook);
+  run_buffer_list_update_hook (XBUFFER (buffer));
 }
 
 
@@ -2054,9 +2059,7 @@ DEFUN ("bury-buffer-internal", Fbury_buffer_internal, Sbury_buffer_internal,
   fset_buried_buffer_list
     (f, Fcons (buffer, Fdelq (buffer, f->buried_buffer_list)));
 
-  /* Run buffer-list-update-hook.  */
-  if (!NILP (Vrun_hooks) && !XBUFFER (buffer)->inhibit_buffer_hooks)
-    call1 (Vrun_hooks, Qbuffer_list_update_hook);
+  run_buffer_list_update_hook (XBUFFER (buffer));
 
   return Qnil;
 }
@@ -5349,10 +5352,11 @@ init_buffer_once (void)
   Fput (Qkill_buffer_hook, Qpermanent_local, Qt);
 
   /* Super-magic invisible buffer.  */
-  Vprin1_to_string_buffer = Fget_buffer_create (build_pure_c_string (" prin1"));
+  Vprin1_to_string_buffer =
+    Fget_buffer_create (build_pure_c_string (" prin1"), Qt);
   Vbuffer_alist = Qnil;
 
-  Fset_buffer (Fget_buffer_create (build_pure_c_string ("*scratch*")));
+  Fset_buffer (Fget_buffer_create (build_pure_c_string ("*scratch*"), Qnil));
 
   inhibit_modification_hooks = 0;
 }
@@ -5397,7 +5401,7 @@ init_buffer (void)
 #endif /* USE_MMAP_FOR_BUFFERS */
 
   AUTO_STRING (scratch, "*scratch*");
-  Fset_buffer (Fget_buffer_create (scratch));
+  Fset_buffer (Fget_buffer_create (scratch, Qnil));
   if (NILP (BVAR (&buffer_defaults, enable_multibyte_characters)))
     Fset_buffer_multibyte (Qnil);
 
@@ -6300,9 +6304,14 @@ Use Custom to set this variable and update the display.  */);
   DEFVAR_LISP ("kill-buffer-query-functions", Vkill_buffer_query_functions,
               doc: /* List of functions called with no args to query before killing a buffer.
 The buffer being killed will be current while the functions are running.
+See `kill-buffer'.
 
 If any of them returns nil, the buffer is not killed.  Functions run by
-this hook are supposed to not change the current buffer.  */);
+this hook are supposed to not change the current buffer.
+
+This hook is not run for internal or temporary buffers created by
+`get-buffer-create' or `generate-new-buffer' with argument
+INHIBIT-BUFFER-HOOKS non-nil.  */);
   Vkill_buffer_query_functions = Qnil;
 
   DEFVAR_LISP ("change-major-mode-hook", Vchange_major_mode_hook,
@@ -6315,9 +6324,12 @@ The function `kill-all-local-variables' runs this before doing anything else.  *
               doc: /* Hook run when the buffer list changes.
 Functions (implicitly) running this hook are `get-buffer-create',
 `make-indirect-buffer', `rename-buffer', `kill-buffer', `bury-buffer'
-and `select-window'.  Functions run by this hook should avoid calling
-`select-window' with a nil NORECORD argument or `with-temp-buffer'
-since either may lead to infinite recursion.  */);
+and `select-window'.  This hook is not run for internal or temporary
+buffers created by `get-buffer-create' or `generate-new-buffer' with
+argument INHIBIT-BUFFER-HOOKS non-nil.
+
+Functions run by this hook should avoid calling `select-window' with a
+nil NORECORD argument since it may lead to infinite recursion.  */);
   Vbuffer_list_update_hook = Qnil;
   DEFSYM (Qbuffer_list_update_hook, "buffer-list-update-hook");
 
index fe549c5dac1deedf0f7ff0f258815a21dbc41f85..b8c5162be4a37f9c8e1b6246b09165ed924f74a1 100644 (file)
@@ -663,11 +663,11 @@ struct buffer
   /* Non-zero whenever the narrowing is changed in this buffer.  */
   bool_bf clip_changed : 1;
 
-  /* Non-zero for internally used temporary buffers that don't need to
-     run hooks kill-buffer-hook, buffer-list-update-hook, and
-     kill-buffer-query-functions.  This is used in coding.c to avoid
-     slowing down en/decoding when there are a lot of these hooks
-     defined.  */
+  /* Non-zero for internal or temporary buffers that don't need to
+     run hooks kill-buffer-hook, kill-buffer-query-functions, and
+     buffer-list-update-hook.  This is used in coding.c to avoid
+     slowing down en/decoding when a lot of these hooks are
+     defined, as well as by with-temp-buffer, for example.  */
   bool_bf inhibit_buffer_hooks : 1;
 
   /* List of overlays that end at or before the current center,
index e3346e2eabb886ad8ec4b92b53508faf6f01bf97..4bca1e5ebd3c42b7e9e9750e8d7daafb43eb2a76 100644 (file)
@@ -405,9 +405,8 @@ call_process (ptrdiff_t nargs, Lisp_Object *args, int filefd,
 
       if (! (NILP (buffer) || EQ (buffer, Qt) || FIXNUMP (buffer)))
        {
-         Lisp_Object spec_buffer;
-         spec_buffer = buffer;
-         buffer = Fget_buffer_create (buffer);
+         Lisp_Object spec_buffer = buffer;
+         buffer = Fget_buffer_create (buffer, Qnil);
          /* Mention the buffer name for a better error message.  */
          if (NILP (buffer))
            CHECK_BUFFER (spec_buffer);
index 2142e7fa518a908b727820d9f756d8ff14f8a0cf..1afa4aa47495a2d2b285da0c49e116a92c409aec 100644 (file)
@@ -7821,7 +7821,7 @@ encode_coding (struct coding_system *coding)
 
 /* A string that serves as name of the reusable work buffer, and as base
    name of temporary work buffers used for code-conversion operations.  */
-Lisp_Object Vcode_conversion_workbuf_name;
+static Lisp_Object Vcode_conversion_workbuf_name;
 
 /* The reusable working buffer, created once and never killed.  */
 static Lisp_Object Vcode_conversion_reused_workbuf;
@@ -7839,7 +7839,7 @@ code_conversion_restore (Lisp_Object arg)
   if (! NILP (workbuf))
     {
       if (EQ (workbuf, Vcode_conversion_reused_workbuf))
-       reused_workbuf_in_use = 0;
+       reused_workbuf_in_use = false;
       else
        Fkill_buffer (workbuf);
     }
@@ -7857,13 +7857,13 @@ code_conversion_save (bool with_work_buf, bool multibyte)
        {
          Lisp_Object name
            = Fgenerate_new_buffer_name (Vcode_conversion_workbuf_name, Qnil);
-         workbuf = Fget_buffer_create (name);
+         workbuf = Fget_buffer_create (name, Qt);
        }
       else
        {
          if (NILP (Fbuffer_live_p (Vcode_conversion_reused_workbuf)))
            Vcode_conversion_reused_workbuf
-             = Fget_buffer_create (Vcode_conversion_workbuf_name);
+             = Fget_buffer_create (Vcode_conversion_workbuf_name, Qt);
          workbuf = Vcode_conversion_reused_workbuf;
        }
     }
@@ -7881,7 +7881,7 @@ code_conversion_save (bool with_work_buf, bool multibyte)
       bset_undo_list (current_buffer, Qt);
       bset_enable_multibyte_characters (current_buffer, multibyte ? Qt : Qnil);
       if (EQ (workbuf, Vcode_conversion_reused_workbuf))
-       reused_workbuf_in_use = 1;
+       reused_workbuf_in_use = true;
       set_buffer_internal (current);
     }
 
@@ -11639,7 +11639,7 @@ syms_of_coding (void)
   staticpro (&Vcode_conversion_workbuf_name);
   Vcode_conversion_workbuf_name = build_pure_c_string (" *code-conversion-work*");
 
-  reused_workbuf_in_use = 0;
+  reused_workbuf_in_use = false;
   PDUMPER_REMEMBER_SCALAR (reused_workbuf_in_use);
 
   DEFSYM (Qcharset, "charset");
index 4973cf89eb1ebf4cc67c3ef95946a05189d85117..9ad1e954f8db1f69c1ccb21164b1011dd0566dd4 100644 (file)
@@ -97,9 +97,6 @@ enum define_coding_undecided_arg_index
 
 extern Lisp_Object Vcoding_system_hash_table;
 
-/* Name (or base name) of work buffer for code conversion.  */
-extern Lisp_Object Vcode_conversion_workbuf_name;
-
 /* Enumeration of index to an attribute vector of a coding system.  */
 
 enum coding_attr_index
index c97f4daf20c21e47fd550ed49b732b3f112d5d4e..51f12e104ef10725ab182fc2c5fa9f7c636aaf97 100644 (file)
@@ -4004,7 +4004,7 @@ by calling `format-decode', which see.  */)
 
                  record_unwind_current_buffer ();
 
-                 workbuf = Fget_buffer_create (name);
+                 workbuf = Fget_buffer_create (name, Qt);
                  buf = XBUFFER (workbuf);
 
                  delete_all_overlays (buf);
index fc3fd92a880c81c79a273e50bb8e25ba4ece10db..1940564a80ac6fc3e70e50ed6f9092af49e43853 100644 (file)
@@ -809,7 +809,7 @@ get_minibuffer (EMACS_INT depth)
       static char const name_fmt[] = " *Minibuf-%"pI"d*";
       char name[sizeof name_fmt + INT_STRLEN_BOUND (EMACS_INT)];
       AUTO_STRING_WITH_LEN (lname, name, sprintf (name, name_fmt, depth));
-      buf = Fget_buffer_create (lname);
+      buf = Fget_buffer_create (lname, Qnil);
 
       /* Although the buffer's name starts with a space, undo should be
         enabled in it.  */
index 008bf5e63913d92b1833a0065bb05fb00cabd551..ec271d914cc46d523c1c57e69da22a9d0fd0ad8f 100644 (file)
@@ -562,7 +562,7 @@ temp_output_buffer_setup (const char *bufname)
 
   record_unwind_current_buffer ();
 
-  Fset_buffer (Fget_buffer_create (build_string (bufname)));
+  Fset_buffer (Fget_buffer_create (build_string (bufname), Qnil));
 
   Fkill_all_local_variables ();
   delete_all_overlays (current_buffer);
index 4fe8ac7fc0c0f434d6eebf2cb1f40c44a7cd0bdc..9efefb1de73c3955be27feedc4fc543ac91898ab 100644 (file)
@@ -1731,7 +1731,7 @@ usage: (make-process &rest ARGS)  */)
 
   buffer = Fplist_get (contact, QCbuffer);
   if (!NILP (buffer))
-    buffer = Fget_buffer_create (buffer);
+    buffer = Fget_buffer_create (buffer, Qnil);
 
   /* Make sure that the child will be able to chdir to the current
      buffer's current directory, or its unhandled equivalent.  We
@@ -1768,7 +1768,7 @@ usage: (make-process &rest ARGS)  */)
                          QCname,
                          concat2 (name, build_string (" stderr")),
                          QCbuffer,
-                         Fget_buffer_create (xstderr),
+                         Fget_buffer_create (xstderr, Qnil),
                          QCnoquery,
                          query_on_exit ? Qnil : Qt);
     }
@@ -2443,7 +2443,7 @@ usage:  (make-pipe-process &rest ARGS)  */)
   buffer = Fplist_get (contact, QCbuffer);
   if (NILP (buffer))
     buffer = name;
-  buffer = Fget_buffer_create (buffer);
+  buffer = Fget_buffer_create (buffer, Qnil);
   pset_buffer (p, buffer);
 
   pset_childp (p, contact);
@@ -3173,7 +3173,7 @@ usage:  (make-serial-process &rest ARGS)  */)
   buffer = Fplist_get (contact, QCbuffer);
   if (NILP (buffer))
     buffer = name;
-  buffer = Fget_buffer_create (buffer);
+  buffer = Fget_buffer_create (buffer, Qnil);
   pset_buffer (p, buffer);
 
   pset_childp (p, contact);
@@ -4188,7 +4188,7 @@ usage: (make-network-process &rest ARGS)  */)
  open_socket:
 
   if (!NILP (buffer))
-    buffer = Fget_buffer_create (buffer);
+    buffer = Fget_buffer_create (buffer, Qnil);
 
   /* Unwind bind_polling_period.  */
   unbind_to (count, Qnil);
@@ -4961,7 +4961,7 @@ server_accept_connection (Lisp_Object server, int channel)
       if (!NILP (buffer))
        {
          args[1] = buffer;
-         buffer = Fget_buffer_create (Fformat (nargs, args));
+         buffer = Fget_buffer_create (Fformat (nargs, args), Qnil);
        }
     }
 
index a840f0e12271e905ec5f97191667852d61ae8755..36bee0676baa5ba5858fe3d0d9b7497d46b1689a 100644 (file)
@@ -7372,7 +7372,7 @@ DEFUN ("x-show-tip", Fx_show_tip, Sx_show_tip, 1, 6, 0,
 
   tip_f = XFRAME (tip_frame);
   window = FRAME_ROOT_WINDOW (tip_f);
-  tip_buf = Fget_buffer_create (tip);
+  tip_buf = Fget_buffer_create (tip, Qnil);
   /* We will mark the tip window a "pseudo-window" below, and such
      windows cannot have display margins.  */
   bset_left_margin_cols (XBUFFER (tip_buf), make_fixnum (0));
index bcc989b5a79aeccec21b8911bd2e2bb499c05970..5db166e345e16009ab60d0b620471eeef421a5c2 100644 (file)
@@ -617,11 +617,12 @@ equals the special symbol `mark-for-redisplay'.
 Run `buffer-list-update-hook' unless NORECORD is non-nil.  Note that
 applications and internal routines often select a window temporarily for
 various purposes; mostly, to simplify coding.  As a rule, such
-selections should be not recorded and therefore will not pollute
+selections should not be recorded and therefore will not pollute
 `buffer-list-update-hook'.  Selections that "really count" are those
 causing a visible change in the next redisplay of WINDOW's frame and
-should be always recorded.  So if you think of running a function each
-time a window gets selected put it on `buffer-list-update-hook'.
+should always be recorded.  So if you think of running a function each
+time a window gets selected, put it on `buffer-list-update-hook' or
+`window-selection-change-functions'.
 
 Also note that the main editor command loop sets the current buffer to
 the buffer of the selected window before each command.  */)
index 0fd5ec5ec56ca9cd86f410fb966a423462ead8e5..b5adee51055aabb528fd463a276860957195d1e9 100644 (file)
@@ -10880,7 +10880,7 @@ message_dolog (const char *m, ptrdiff_t nbytes, bool nlflag, bool multibyte)
       /* Ensure the Messages buffer exists, and switch to it.
          If we created it, set the major-mode.  */
       bool newbuffer = NILP (Fget_buffer (Vmessages_buffer_name));
-      Fset_buffer (Fget_buffer_create (Vmessages_buffer_name));
+      Fset_buffer (Fget_buffer_create (Vmessages_buffer_name, Qnil));
       if (newbuffer
          && !NILP (Ffboundp (intern ("messages-buffer-mode"))))
        call0 (intern ("messages-buffer-mode"));
@@ -11366,7 +11366,7 @@ ensure_echo_area_buffers (void)
        static char const name_fmt[] = " *Echo Area %d*";
        char name[sizeof name_fmt + INT_STRLEN_BOUND (int)];
        AUTO_STRING_WITH_LEN (lname, name, sprintf (name, name_fmt, i));
-       echo_buffer[i] = Fget_buffer_create (lname);
+       echo_buffer[i] = Fget_buffer_create (lname, Qnil);
        bset_truncate_lines (XBUFFER (echo_buffer[i]), Qnil);
        /* to force word wrap in echo area -
           it was decided to postpone this*/
index 46e4bd73a6b50aef006c60cd9189b58be21a8cc8..abe293e903e92feb63508057e63211ca13151552 100644 (file)
@@ -7041,7 +7041,7 @@ Text larger than the specified size is clipped.  */)
 
   tip_f = XFRAME (tip_frame);
   window = FRAME_ROOT_WINDOW (tip_f);
-  tip_buf = Fget_buffer_create (tip);
+  tip_buf = Fget_buffer_create (tip, Qnil);
   /* We will mark the tip window a "pseudo-window" below, and such
      windows cannot have display margins.  */
   bset_left_margin_cols (XBUFFER (tip_buf), make_fixnum (0));
index e078a28a35b987e34e170d102c2a7b39ade82eb8..accde65b52397bd9c373c1006b281af437378354 100644 (file)
@@ -100,7 +100,8 @@ Returns the newly constructed xwidget, or nil if construction fails.  */)
   Lisp_Object val;
   xw->type = type;
   xw->title = title;
-  xw->buffer = NILP (buffer) ? Fcurrent_buffer () : Fget_buffer_create (buffer);
+  xw->buffer = (NILP (buffer) ? Fcurrent_buffer ()
+               : Fget_buffer_create (buffer, Qnil));
   xw->height = XFIXNAT (height);
   xw->width = XFIXNAT (width);
   xw->kill_without_query = false;
index 0db66f97517930be8e22dc3c962951592e6b222a..dd8927457aeb4a08028d309fa8d627bd30591583 100644 (file)
@@ -19,9 +19,7 @@
 
 ;;; Code:
 
-(require 'ert)
-(require 'seq)
-(eval-when-compile (require 'cl-lib))
+(require 'cl-lib)
 
 (ert-deftest overlay-modification-hooks-message-other-buf ()
   "Test for bug#21824.
@@ -1334,4 +1332,33 @@ with parameters from the *Messages* buffer modification."
   (with-temp-buffer
     (should (assq 'buffer-undo-list (buffer-local-variables)))))
 
+(ert-deftest buffer-tests-inhibit-buffer-hooks ()
+  "Test `get-buffer-create' argument INHIBIT-BUFFER-HOOKS."
+  (let* (run-bluh (bluh (lambda () (setq run-bluh t))))
+    (unwind-protect
+        (let* ( run-kbh  (kbh  (lambda () (setq run-kbh  t)))
+                run-kbqf (kbqf (lambda () (setq run-kbqf t))) )
+
+          ;; Inhibited.
+          (add-hook 'buffer-list-update-hook bluh)
+          (with-current-buffer (generate-new-buffer " foo" t)
+            (add-hook 'kill-buffer-hook kbh nil t)
+            (add-hook 'kill-buffer-query-functions kbqf nil t)
+            (kill-buffer))
+          (with-temp-buffer)
+          (with-output-to-string)
+          (should-not run-bluh)
+          (should-not run-kbh)
+          (should-not run-kbqf)
+
+          ;; Not inhibited.
+          (with-current-buffer (generate-new-buffer " foo")
+            (should run-bluh)
+            (add-hook 'kill-buffer-hook kbh nil t)
+            (add-hook 'kill-buffer-query-functions kbqf nil t)
+            (kill-buffer))
+          (should run-kbh)
+          (should run-kbqf))
+      (remove-hook 'buffer-list-update-hook bluh))))
+
 ;;; buffer-tests.el ends here