+(defvar temp-buffer-window-setup-hook nil
+ "Normal hook run by `with-temp-buffer-window' before buffer display.
+This hook is run by `with-temp-buffer-window' with the buffer to be
+displayed current.")
+
+(defvar temp-buffer-window-show-hook nil
+ "Normal hook run by `with-temp-buffer-window' after buffer display.
+This hook is run by `with-temp-buffer-window' with the buffer
+displayed and current and its window selected.")
+
+(defun temp-buffer-window-setup (buffer-or-name)
+ "Set up temporary buffer specified by BUFFER-OR-NAME
+Return the buffer."
+ (let ((old-dir default-directory)
+ (buffer (get-buffer-create buffer-or-name)))
+ (with-current-buffer buffer
+ (kill-all-local-variables)
+ (setq default-directory old-dir)
+ (delete-all-overlays)
+ (setq buffer-read-only nil)
+ (setq buffer-file-name nil)
+ (setq buffer-undo-list t)
+ (let ((inhibit-read-only t)
+ (inhibit-modification-hooks t))
+ (erase-buffer)
+ (run-hooks 'temp-buffer-window-setup-hook))
+ ;; Return the buffer.
+ buffer)))
+
+(defun temp-buffer-window-show (&optional buffer action)
+ "Show temporary buffer BUFFER in a window.
+Return the window showing BUFFER. Pass ACTION as action argument
+to `display-buffer'."
+ (let (window frame)
+ (with-current-buffer buffer
+ (set-buffer-modified-p nil)
+ (setq buffer-read-only t)
+ (goto-char (point-min))
+ (when (setq window (display-buffer buffer action))
+ (setq frame (window-frame window))
+ (unless (eq frame (selected-frame))
+ (raise-frame frame))
+ (setq minibuffer-scroll-window window)
+ (set-window-hscroll window 0)
+ (with-selected-window window
+ (run-hooks 'temp-buffer-window-show-hook)
+ (when temp-buffer-resize-mode
+ (resize-temp-buffer-window window)))
+ ;; Return the window.
+ window))))
+
+(defmacro with-temp-buffer-window (buffer-or-name action quit-function &rest body)
+ "Evaluate BODY and display buffer specified by BUFFER-OR-NAME.
+BUFFER-OR-NAME must specify either a live buffer or the name of a
+buffer. If no buffer with such a name exists, create one.
+
+Make sure the specified buffer is empty before evaluating BODY.
+Do not make that buffer current for BODY. Instead, bind
+`standard-output' to that buffer, so that output generated with
+`prin1' and similar functions in BODY goes into that buffer.
+
+After evaluating BODY, mark the specified buffer unmodified and
+read-only, and display it in a window via `display-buffer'. Pass
+ACTION as action argument to `display-buffer'. Automatically
+shrink the window used if `temp-buffer-resize-mode' is enabled.
+
+Return the value returned by BODY unless QUIT-FUNCTION specifies
+a function. In that case, run the function with two arguments -
+the window showing the specified buffer and the value returned by
+BODY - and return the value returned by that function.
+
+If the buffer is displayed on a new frame, the window manager may
+decide to select that frame. In that case, it's usually a good
+strategy if the function specified by QUIT-FUNCTION selects the
+window showing the buffer before reading a value from the
+minibuffer, for example, when asking a `yes-or-no-p' question.
+
+This construct is similar to `with-output-to-temp-buffer' but
+does neither put the buffer in help mode nor does it call
+`temp-buffer-show-function'. It also runs different hooks,
+namely `temp-buffer-window-setup-hook' (with the specified buffer
+current) and `temp-buffer-window-show-hook' (with the specified
+buffer current and the window showing it selected).
+
+Since this macro calls `display-buffer', the window displaying
+the buffer is usually not selected and the specified buffer
+usually not made current. QUIT-FUNCTION can override that."
+ (declare (debug t))
+ (let ((buffer (make-symbol "buffer"))
+ (window (make-symbol "window"))
+ (value (make-symbol "value")))
+ `(let* ((,buffer (temp-buffer-window-setup ,buffer-or-name))
+ (standard-output ,buffer)
+ ,window ,value)
+ (with-current-buffer ,buffer
+ (setq ,value (progn ,@body))
+ (setq ,window (temp-buffer-window-show ,buffer ,action)))
+
+ (if (functionp ,quit-function)
+ (funcall ,quit-function ,window ,value)
+ ,value))))
+