Subject: Ediff 2.81.6; Window restoration with ediff-before-setup-hook doesn't work for ediff-regions-linewise

From: Aaron Zeng <[email-masked]>
Date: Wed, 25 Jun 2025 16:40:51 -0400

ediff-before-setup-hook's docstring suggests using it to save and
restore the window configuration prior to invoking an Ediff command.
Users at my site have an equivalent to the following hooks:

(defvar my-saved-window-configuration nil)
(add-hook 'ediff-before-setup-hook
          (lambda ()
            (setq my-saved-window-configuration (current-window-configuration))))
(add-hook 'ediff-quit-hook
          (lambda ()
            (set-window-configuration my-saved-window-configuration)
            (setq my-saved-window-configuration nil)))

This works fine for most Ediff commands but does not work correctly
with ediff-regions-linewise and ediff-regions-wordwise.  You can
reproduce the behavior from emacs -Q:

1. emacs -Q
2. Evaluate the above snippet
3. M-x ediff-regions-linewise (select an arbitrary pair of buffers and
   regions like selecting *scratch* twice)
4. Press q

After quitting, the original window configuration is not restored.  In
particular, the window is split vertically with a short window below
the selected taller one.

I believe this is because those commands use
ediff-clone-buffer-for-region-comparison to prompt for regions as diff
input, and that involves adjusting the window configuration a few
times.  The following patch seems to fix the behavior (edited to
remove the indentation diff for brevity):

diff --git a/lisp/vc/ediff-util.el b/lisp/vc/ediff-util.el
index a2c9b6f50ec..16878cf779f 100644
--- a/lisp/vc/ediff-util.el
+++ b/lisp/vc/ediff-util.el
@@ -3247,6 +3247,7 @@ ediff-save-buffer
 
 ;; idea suggested by Hannu Koivisto <[email-masked]>
 (defun ediff-clone-buffer-for-region-comparison (buff region-name)
+  (save-window-excursion
     (let ((cloned-buff (ediff-make-cloned-buffer buff region-name))
 	  (pop-up-windows t)
 	  wind
@@ -3285,7 +3286,7 @@ ediff-clone-buffer-for-region-comparison
 	  (quit
 	   (ediff-kill-buffer-carefully cloned-buff)))
         )
-    cloned-buff))
+      cloned-buff)))

 (defun ediff-clone-buffer-for-window-comparison (buff wind region-name)

The generated output below reflects my site's actual default config,
but the reproduction steps above work with Emacs's defaults.

Emacs  : GNU Emacs 30.1.90 (build 1, x86_64-pc-linux-gnu, X toolkit, cairo version 1.15.12, Xaw scroll bars)
 of 2025-06-25
Package: Ediff 2.81.6

current state:
==============
(setq
 ediff-diff-program "diff"
 ediff-diff-options ""
 ediff-diff3-program "diff3"
 ediff-diff3-options ""
 ediff-patch-program "patch"
 ediff-patch-options "-f"
 ediff-shell "sh"
 ediff-use-faces t
 ediff-auto-refine 'on
 ediff-highlighting-style 'face
 ediff-buffer-A nil
 ediff-buffer-B nil
 ediff-control-buffer nil
 ediff-forward-word-function 'ediff-forward-word
 ediff-control-frame nil
 ediff-control-frame-parameters '((name . "Ediff") (minibuffer) (user-position . t) (vertical-scroll-bars) (menu-bar-lines . 0)
                                  (tool-bar-lines . 0) (left-fringe . 0) (right-fringe . 0) (auto-lower) (auto-raise . t) (visibility)
                                  (width . 1) (height . 1) (fullscreen) (top . 4321) (left . 3841))
 ediff-control-frame-position-function 'ediff-make-frame-position
 ediff-prefer-iconified-control-frame nil
 ediff-window-setup-function 'ediff-setup-windows-plain
 ediff-split-window-function 'split-window-horizontally
 ediff-job-name nil
 ediff-word-mode nil
 ediff-buffer-name " *ediff-message*"
 window-system 'x
 )