Subject: bug#25493: 26.0.50; ediff merge should (optionally) show ancestor in fourth window

From: Tino Calancha <[email-masked]>
Date: Mon, 06 Mar 2017 23:06:44 +0900

[email-masked] writes:

Thanks again for looking on this.  I must admit the previous patch
was terrible.
> Could you perhaps explain more in the commit messages about how the
> patch works, at a high level?  It's long enough that I get lost while
> reading it.
OK.  I have simplified the patch a lot.  I have restricted to the problem
in hands: to show the buffer ancestor in 3way merges.  The refinement of
this buffer must keep in the TODO list (see below).
> As a user, I noticed that `ediff-scroll-vertically' doesn't scroll the
> ancestor buffer.
Good catch! Fixed in the new patch.
> Also, I want diff refining in buffer A and B against the ancestor, not
> each other.  This might be more of an addtional feature request that
> doesn't necessarily need to addressed in your patch though.
It sounds like a nice idea.  We should open a new bug report once we
finish this one: there we can implement those refinements with the
ancestor.

--8<-----------------------------cut here---------------start------------->8---
>From e86a53982794f421c393cd2d6f935cd4bb666852 Mon Sep 17 00:00:00 2001
From: Tino Calancha <[email-masked]>
Date: Mon, 6 Mar 2017 13:24:07 +0900
Subject: [PATCH 1/2] diff-mode: Improve default faces for buffer ancestor

* lisp/vc/ediff-init.el (ediff-current-diff-Ancestor)
(ediff-fine-diff-Ancestor): Use defaults consistent with
faces for 'ediff-buffer-A' and 'ediff-buffer-B'.
---
 lisp/vc/ediff-init.el | 36 ++++++++++++++++++++++--------------
 1 file changed, 22 insertions(+), 14 deletions(-)

diff --git a/lisp/vc/ediff-init.el b/lisp/vc/ediff-init.el
index 0235926fbe..535fdbfc90 100644
--- a/lisp/vc/ediff-init.el
+++ b/lisp/vc/ediff-init.el
@@ -942,13 +942,17 @@ ediff-current-diff-face-C
 
 (defface ediff-current-diff-Ancestor
   (if (featurep 'emacs)
-      '((((class color) (min-colors 88))
-	 (:background "VioletRed"))
-	(((class color) (min-colors 16))
-	 (:foreground "Black" :background "VioletRed"))
-	(((class color))
-	 (:foreground "black" :background "magenta3"))
-	(t (:inverse-video t)))
+      '((((class color) (min-colors 88) (background light))
+         :background "#cfdeee")
+        (((class color) (min-colors 88) (background dark))
+         :background "#004151")
+        (((class color) (min-colors 16) (background light))
+         :background "#cfdeee")
+        (((class color) (min-colors 16) (background dark))
+         :background "#004151")
+        (((class color))
+         (:foreground "black" :background "magenta3"))
+        (t (:inverse-video t)))
     '((((type tty))    (:foreground "black" :background "magenta3"))
       (((class color)) (:foreground "Black" :background "VioletRed"))
       (t (:inverse-video t))))
@@ -1052,13 +1056,17 @@ ediff-fine-diff-face-C
 
 (defface ediff-fine-diff-Ancestor
   (if (featurep 'emacs)
-      '((((class color) (min-colors 88))
-	 (:background "Green"))
-	(((class color) (min-colors 16))
-	 (:foreground "Black" :background "Green"))
-	(((class color))
-	 (:foreground "red3" :background "green"))
-	(t		     (:underline t :stipple "gray3")))
+      '((((class color) (min-colors 88) (background light))
+         :background "#00c5c0")
+        (((class color) (min-colors 88) (background dark))
+         :background "#009591")
+        (((class color) (min-colors 16) (background light))
+         :background "#00c5c0")
+        (((class color) (min-colors 16) (background dark))
+         :background "#009591")
+        (((class color))
+         (:foreground "red3" :background "green"))
+        (t		     (:underline t :stipple "gray3")))
     '((((type tty))    (:foreground "red3" :background "green"))
       (((class color)) (:foreground "Black" :background "Green"))
       (t	     	     (:underline t :stipple "gray3"))))
-- 
2.11.0

>From a67907ba3166b3bcc22504c099b056c072fd1d09 Mon Sep 17 00:00:00 2001
From: Tino Calancha <[email-masked]>
Date: Mon, 6 Mar 2017 22:47:09 +0900
Subject: [PATCH 2/2] Show ancestor buffer in 3way merges

Add an option ediff-show-ancestor', to control if the ancestor buffer
must be shown in 3way merges (Bug#25493);  set it non-nil by default.
Add a toggle to change this option interactively; the original
value of the option is restored on exit.

Update the window setup so that the ancestor buffer is
shown in 3way merges when ediff-show-ancestor is non-nil.

Any operation on ediff windows must take in account the
ancestor window as well, when this is shown.

* lisp/vc/ediff-init.el (ediff-show-ancestor): New option.
(ediff--show-ancestor-orig): New defvar.
* lisp/vc/ediff-wind.el (ediff-window-Ancestor): New defvar.
(ediff-setup-windows-plain-merge, ediff-setup-windows-multiframe-merge):
Display ancestor buffer if ediff-show-ancestor is non-nil.
(ediff-keep-window-config): Expect ancestor window in
ediff-window-config-saved.
(ediff-window-alist): Add entry for the ancestor window.
* lisp/vc/ediff-util.el (ediff-setup-control-buffer):
ediff-window-config-saved contains ancestor window.
(ediff-show-ancestor): Delete this command.
(ediff-setup-keymap): Bind ediff-toggle-show-ancestor to '/' for merge jobs.
(ediff-update-diffs): Compute new diffs using ancestor buffer.
(ediff-recenter): Update doc string.  Consider the ancestor buffer.
(ediff--check-ancestor-exists): New defun.
(ediff-toggle-show-ancestor): New command; toggle ediff-show-ancestor.
(ediff--restore-options-on-exit): Restore ediff-show-ancestor on exit.
(ediff-scroll-vertically, ediff-scroll-horizontally)
(ediff-operate-on-windows): Consider the ancestor as well.
* lisp/vc/ediff-help.el (ediff-long-help-message-merge):
List ediff-toggle-show-ancestor.
* doc/misc/ediff.texi (Introduction, Quick Help Commands): Update manual.
; * etc/NEWS: Announce these changes.
---
 doc/misc/ediff.texi   |   8 ++-
 etc/NEWS              |   5 ++
 lisp/vc/ediff-help.el |   2 +-
 lisp/vc/ediff-init.el |  10 ++++
 lisp/vc/ediff-util.el | 155 ++++++++++++++++++++++++++++++++------------------
 lisp/vc/ediff-wind.el |  86 ++++++++++++++++++++++++----
 6 files changed, 197 insertions(+), 69 deletions(-)

diff --git a/doc/misc/ediff.texi b/doc/misc/ediff.texi
index 19b7adbd66..87d3dfd6ed 100644
--- a/doc/misc/ediff.texi
+++ b/doc/misc/ediff.texi
@@ -99,7 +99,8 @@ Introduction
 another (and recover old differences if you change your mind).
 
 Another powerful feature is the ability to merge a pair of files into a
-third buffer.  Merging with an ancestor file is also supported.
+third buffer.  Merging with an ancestor file, (a.k.a. 3way merges)
+is also supported.
 Furthermore, Ediff is equipped with directory-level capabilities that
 allow the user to conveniently launch browsing or merging sessions on
 groups of files in two (or three) different directories.
@@ -828,7 +829,10 @@ Quick Help Commands
 
 @item /
 @kindex /
-Displays the ancestor file during merges.
+@vindex ediff-show-ancestor
+Toggle to display the ancestor file in 3way merges.
+You can enable permanently this setting customizing the variable
+@code{ediff-show-ancestor}.
 @item &
 @kindex &
 In some situations, such as when one of the files agrees with the ancestor file
diff --git a/etc/NEWS b/etc/NEWS
index 8f7356f3e0..9dd3fe2053 100644
--- a/etc/NEWS
+++ b/etc/NEWS
@@ -361,6 +361,11 @@ words where first character is upper rather than title case, e.g.,
 
 * Changes in Specialized Modes and Packages in Emacs 26.1
 
++++
+*** The ancestor buffer is shown by default in 3way merges.
+A new option ediff-show-ancestor and a new toggle
+ediff-toggle-show-ancestor.
+
 ** TeX: Add luatex and xetex as alternatives to pdftex
 
 ** Electric-Buffer-menu
diff --git a/lisp/vc/ediff-help.el b/lisp/vc/ediff-help.el
index 3292b4d939..52a4825207 100644
--- a/lisp/vc/ediff-help.el
+++ b/lisp/vc/ediff-help.el
@@ -112,7 +112,7 @@ ediff-long-help-message-merge
   C-l -recenter      | #f/#h -focus/hide regions |  + -combine diff regions
   v/V -scroll up/dn  |     X -read-only in buf X | wx -save buf X
   </> -scroll lt/rt  |     m -wide display       | wd -save diff output
-    ~ -swap variants |     s -shrink window C    |  / -show ancestor buff
+    ~ -swap variants |     s -shrink window C    |  / -show/hide ancestor buff
                      |  $$ -show clashes only    |  & -merge w/new default
                      |  $* -skip changed regions |
 "
diff --git a/lisp/vc/ediff-init.el b/lisp/vc/ediff-init.el
index 535fdbfc90..e054268859 100644
--- a/lisp/vc/ediff-init.el
+++ b/lisp/vc/ediff-init.el
@@ -1363,6 +1363,16 @@ ediff-make-buffers-readonly-at-startup
 ;; if nil, this silences some messages
 (defvar ediff-verbose-p t)
 
+(defcustom ediff-show-ancestor t
+"If non-nil, show ancestor buffer in 3way merges and refine it."
+  :type 'boolean
+  :group 'ediff-merge
+  :version "26.1")
+
+;; Store orig value of `ediff-show-ancestor'  when changed in
+;; `ediff-toggle-show-ancestor' and restore it on exit.
+(ediff-defvar-local ediff--show-ancestor-orig nil "")
+
 (defcustom ediff-autostore-merges  'group-jobs-only
   "Save the results of merge jobs automatically.
 With value nil, don't save automatically.  With value t, always
diff --git a/lisp/vc/ediff-util.el b/lisp/vc/ediff-util.el
index f81397950d..549066e1ec 100644
--- a/lisp/vc/ediff-util.el
+++ b/lisp/vc/ediff-util.el
@@ -178,7 +178,7 @@ ediff-setup-keymap
   (define-key ediff-mode-map "r"  nil)
   (cond (ediff-merge-job
 	 ;; Will barf if no ancestor
-	 (define-key ediff-mode-map "/" 'ediff-show-ancestor)
+	 (define-key ediff-mode-map "/" 'ediff-toggle-show-ancestor)
 	 ;; In merging, we allow only A->C and B->C copying.
 	 (define-key ediff-mode-map "a" 'ediff-copy-A-to-C)
 	 (define-key ediff-mode-map "b" 'ediff-copy-B-to-C)
@@ -553,11 +553,12 @@ ediff-setup-control-buffer
     (ediff-refresh-mode-lines)
     (setq ediff-control-window (selected-window))
     (setq ediff-window-config-saved
-	  (format "%S%S%S%S%S%S%S"
+	  (format "%S%S%S%S%S%S%S%S"
 		  ediff-control-window
 		  ediff-window-A
 		  ediff-window-B
 		  ediff-window-C
+		  ediff-window-Ancestor
 		  ediff-split-window-function
 		  (ediff-multiframe-setup-p)
 		  ediff-wide-display-p))
@@ -600,12 +601,6 @@ ediff-update-diffs
 if necessary."
   (interactive)
   (ediff-barf-if-not-control-buffer)
-  (if (and (ediff-buffer-live-p ediff-ancestor-buffer)
-	   (not
-	    (y-or-n-p
-	     "Ancestor buffer will not be used.  Recompute diffs anyway? ")))
-      (error "Recomputation of differences canceled"))
-
   (let ((point-A (ediff-with-current-buffer ediff-buffer-A (point)))
 	;;(point-B (ediff-with-current-buffer ediff-buffer-B (point)))
 	(tmp-buffer (get-buffer-create ediff-tmp-buffer))
@@ -614,14 +609,17 @@ ediff-update-diffs
 	;; (null ediff-buffer-C) is no problem, as we later check if
 	;; ediff-buffer-C is alive
 	(buf-C-file-name (buffer-file-name ediff-buffer-C))
+	(buf-ancestor-file-name (buffer-file-name ediff-ancestor-buffer))
 	(overl-A (ediff-get-value-according-to-buffer-type
 		  'A ediff-narrow-bounds))
 	(overl-B (ediff-get-value-according-to-buffer-type
 		  'B ediff-narrow-bounds))
 	(overl-C (ediff-get-value-according-to-buffer-type
 		  'C ediff-narrow-bounds))
-	beg-A end-A beg-B end-B beg-C end-C
-	file-A file-B file-C)
+        (overl-Ancestor (ediff-get-value-according-to-buffer-type
+                         'Ancestor ediff-narrow-bounds))
+	beg-A end-A beg-B end-B beg-C end-C beg-Ancestor end-Ancestor
+	file-A file-B file-C file-Ancestor)
 
     (if (stringp buf-A-file-name)
 	(setq buf-A-file-name (file-name-nondirectory buf-A-file-name)))
@@ -629,15 +627,19 @@ ediff-update-diffs
 	(setq buf-B-file-name (file-name-nondirectory buf-B-file-name)))
     (if (stringp buf-C-file-name)
 	(setq buf-C-file-name (file-name-nondirectory buf-C-file-name)))
+    (if (stringp buf-ancestor-file-name)
+        (setq buf-ancestor-file-name (file-name-nondirectory buf-ancestor-file-name)))
 
     (ediff-unselect-and-select-difference -1)
 
     (setq beg-A (ediff-overlay-start overl-A)
 	  beg-B (ediff-overlay-start overl-B)
 	  beg-C (ediff-overlay-start overl-C)
+	  beg-Ancestor (ediff-overlay-start overl-Ancestor)
 	  end-A (ediff-overlay-end overl-A)
 	  end-B (ediff-overlay-end overl-B)
-	  end-C (ediff-overlay-end overl-C))
+	  end-C (ediff-overlay-end overl-C)
+          end-Ancestor (ediff-overlay-end overl-Ancestor))
 
     (if ediff-word-mode
 	(progn
@@ -645,51 +647,37 @@ ediff-update-diffs
 	  (setq file-A (ediff-make-temp-file tmp-buffer "regA"))
 	  (ediff-wordify beg-B end-B ediff-buffer-B tmp-buffer)
 	  (setq file-B (ediff-make-temp-file tmp-buffer "regB"))
-	  (if ediff-3way-job
-	      (progn
-		(ediff-wordify beg-C end-C ediff-buffer-C tmp-buffer)
-		(setq file-C (ediff-make-temp-file tmp-buffer "regC"))))
+	  (when ediff-3way-job
+            (ediff-wordify beg-C end-C ediff-buffer-C tmp-buffer)
+            (setq file-C (ediff-make-temp-file tmp-buffer "regC")))
+          (when ediff-merge-with-ancestor-job
+            (ediff-wordify beg-Ancestor end-Ancestor ediff-ancestor-buffer tmp-buffer)
+            (setq file-Ancestor (ediff-make-temp-file tmp-buffer "regAncestor")))
 	  )
       ;; not word-mode
       (setq file-A (ediff-make-temp-file ediff-buffer-A buf-A-file-name))
       (setq file-B (ediff-make-temp-file ediff-buffer-B buf-B-file-name))
       (if ediff-3way-job
 	  (setq file-C (ediff-make-temp-file ediff-buffer-C buf-C-file-name)))
+      (when ediff-merge-with-ancestor-job
+        (setq file-Ancestor
+              (ediff-make-temp-file
+               ediff-ancestor-buffer
+               buf-ancestor-file-name)))
       )
-
     (ediff-clear-diff-vector 'ediff-difference-vector-A 'fine-diffs-also)
     (ediff-clear-diff-vector 'ediff-difference-vector-B 'fine-diffs-also)
     (ediff-clear-diff-vector 'ediff-difference-vector-C 'fine-diffs-also)
     (ediff-clear-diff-vector
      'ediff-difference-vector-Ancestor 'fine-diffs-also)
-    ;; let them garbage collect.  we can't use the ancestor after recomputing
-    ;; the diffs.
-    (setq ediff-difference-vector-Ancestor nil
-	  ediff-ancestor-buffer nil
-	  ediff-state-of-merge nil)
-
     (setq ediff-killed-diffs-alist nil) ; invalidate saved killed diff regions
-
-    ;; In case of merge job, fool it into thinking that it is just doing
-    ;; comparison
-    (let ((ediff-setup-diff-regions-function ediff-setup-diff-regions-function)
-	  (ediff-3way-comparison-job ediff-3way-comparison-job)
-	  (ediff-merge-job ediff-merge-job)
-	  (ediff-merge-with-ancestor-job ediff-merge-with-ancestor-job)
-	  (ediff-job-name ediff-job-name))
-      (if ediff-merge-job
-	  (setq ediff-setup-diff-regions-function 'ediff-setup-diff-regions3
-		ediff-3way-comparison-job t
-		ediff-merge-job nil
-		ediff-merge-with-ancestor-job nil
-		ediff-job-name 'ediff-files3))
-      (funcall ediff-setup-diff-regions-function file-A file-B file-C))
-
+    (funcall ediff-setup-diff-regions-function file-A file-B
+             (if ediff-merge-with-ancestor-job file-Ancestor file-C))
     (setq ediff-number-of-differences (length ediff-difference-vector-A))
     (delete-file file-A)
     (delete-file file-B)
-    (if file-C
-	(delete-file file-C))
+    (and file-C (delete-file file-C))
+    (and file-Ancestor (delete-file file-Ancestor))
 
     (if ediff-3way-job
 	(ediff-set-state-of-all-diffs-in-all-buffers ediff-control-buffer))
@@ -737,14 +725,16 @@ ediff-revert-buffers-then-recompute-diffs
 ;; optional NO-REHIGHLIGHT says to not rehighlight buffers
 (defun ediff-recenter (&optional no-rehighlight)
   "Bring the highlighted region of all buffers being compared into view.
-Reestablish the default three-window display."
+Reestablish the default window display."
   (interactive)
   (ediff-barf-if-not-control-buffer)
   (let (buffer-read-only)
     (if (and (ediff-buffer-live-p ediff-buffer-A)
 	     (ediff-buffer-live-p ediff-buffer-B)
 	     (or (not ediff-3way-job)
-		 (ediff-buffer-live-p ediff-buffer-C)))
+		 (ediff-buffer-live-p ediff-buffer-C))
+             (or (not ediff-merge-with-ancestor-job)
+		 (ediff-buffer-live-p ediff-ancestor-buffer)))
 	(ediff-setup-windows
 	 ediff-buffer-A ediff-buffer-B ediff-buffer-C ediff-control-buffer)
       (or (eq this-command 'ediff-quit)
@@ -963,18 +953,43 @@ ediff-toggle-autorefine
 	 (setq ediff-auto-refine 'nix))
 	))
 
-(defun ediff-show-ancestor ()
-  "Show the ancestor buffer in a suitable window."
-  (interactive)
-  (ediff-recenter)
+(defun ediff--check-ancestor-exists ()
   (or (ediff-buffer-live-p ediff-ancestor-buffer)
       (if ediff-merge-with-ancestor-job
-	  (error "Lost connection to ancestor buffer...sorry")
-	(error "Not merging with ancestor")))
-  (let (wind)
-    (cond ((setq wind (ediff-get-visible-buffer-window ediff-ancestor-buffer))
-	   (raise-frame (window-frame wind)))
-	  (t (set-window-buffer ediff-window-C ediff-ancestor-buffer)))))
+	  (error "Lost connection to ancestor buffer.  This shouldn't happen.  \
+Please report this bug to [email-masked]")
+	(error "Not merging with ancestor"))))
+
+;; Restore `ediff-show-ancestor' on exit.
+(defun ediff--restore-options-on-exit ()
+  (message "Restoring ediff-show-ancestor to %S..." ediff--show-ancestor-orig)
+  (setq ediff-show-ancestor ediff--show-ancestor-orig
+        ediff--show-ancestor-orig nil)
+  (remove-hook 'ediff-quit-hook #'ediff--restore-options-on-exit))
+
+(defun ediff-toggle-show-ancestor ()
+  "Toggle to show/hide the ancestor buffer."
+  (interactive)
+  (ediff--check-ancestor-exists)
+  ;; Save original value if not yet, and add hook to restore it on exit.
+  (unless ediff--show-ancestor-orig
+    (setq ediff--show-ancestor-orig ediff-show-ancestor)
+    (add-hook 'ediff-quit-hook #'ediff--restore-options-on-exit))
+  (setq ediff-show-ancestor (not ediff-show-ancestor))
+  ;; If equal than orig, then nothing to restore on exit.
+  (when (eq ediff-show-ancestor ediff--show-ancestor-orig)
+    (setq ediff--show-ancestor-orig nil)
+    (remove-hook 'ediff-quit-hook #'ediff--restore-options-on-exit))
+  (if (not ediff-show-ancestor)
+      (progn
+        (delete-window ediff-window-Ancestor)
+        (ediff-recenter)
+        (message "Ancestor buffer is hidden"))
+    (let ((wind
+           (ediff-get-visible-buffer-window ediff-ancestor-buffer)))
+      (when wind (raise-frame (window-frame wind))))
+    (ediff-recenter)
+    (message "Showing ancestor buffer")))
 
 (defun ediff-make-or-kill-fine-diffs (arg)
   "Compute fine diffs.  With negative prefix arg, kill fine diffs.
@@ -1468,7 +1483,10 @@ ediff-operate-on-windows
       (ediff-recenter 'no-rehighlight))
   (if (not (and (ediff-buffer-live-p ediff-buffer-A)
 		(ediff-buffer-live-p ediff-buffer-B)
-		(or (not ediff-3way-job) ediff-buffer-C)
+		(or (not ediff-3way-job) (ediff-buffer-live-p ediff-buffer-C))
+		(or (not ediff-merge-with-ancestor-job)
+                    (not ediff-show-ancestor)
+                    (ediff-buffer-live-p ediff-ancestor-buffer))
 		))
       (error ediff-KILLED-VITAL-BUFFER))
 
@@ -1476,11 +1494,15 @@ ediff-operate-on-windows
 	 (wind-A ediff-window-A)
 	 (wind-B ediff-window-B)
 	 (wind-C ediff-window-C)
+	 (wind-Anc ediff-window-Ancestor)
 	 (coefA (ediff-get-region-size-coefficient 'A operation))
 	 (coefB (ediff-get-region-size-coefficient 'B operation))
 	 (three-way ediff-3way-job)
+         (with-Ancestor (and ediff-merge-with-ancestor-job ediff-show-ancestor))
 	 (coefC (if three-way
-		    (ediff-get-region-size-coefficient 'C operation))))
+		    (ediff-get-region-size-coefficient 'C operation)))
+         (coefAnc (if with-Ancestor
+                      (ediff-get-region-size-coefficient 'Ancestor operation))))
 
     (select-window wind-A)
     (condition-case nil
@@ -1496,6 +1518,11 @@ ediff-operate-on-windows
 	  (condition-case nil
 	      (funcall operation (round (* coefC arg)))
 	    (error))))
+    (when with-Ancestor
+      (select-window wind-Anc)
+      (condition-case nil
+          (funcall operation (round (* coefAnc arg)))
+        (error)))
     (select-window wind)))
 
 (defun ediff-scroll-vertically (&optional arg)
@@ -1512,6 +1539,9 @@ ediff-scroll-vertically
 		(ediff-buffer-live-p ediff-buffer-B)
 		(or (not ediff-3way-job)
 		    (ediff-buffer-live-p ediff-buffer-C))
+                (or (not ediff-merge-with-ancestor-job)
+                    (not ediff-show-ancestor)
+		    (ediff-buffer-live-p ediff-ancestor-buffer))
 		))
       (error ediff-KILLED-VITAL-BUFFER))
 
@@ -1531,6 +1561,10 @@ ediff-scroll-vertically
 			(window-height ediff-window-B)
 			(if ediff-3way-job
 			    (window-height ediff-window-C)
+			  500) ; some large number
+                        (if (and ediff-merge-with-ancestor-job
+                                 ediff-show-ancestor)
+			    (window-height ediff-window-Ancestor)
 			  500)) ; some large number
 		   2)
 		1 next-screen-context-lines))
@@ -1556,6 +1590,9 @@ ediff-scroll-horizontally
 		(ediff-buffer-live-p ediff-buffer-B)
 		(or (not ediff-3way-job)
 		    (ediff-buffer-live-p ediff-buffer-C))
+                (or (not ediff-merge-with-ancestor-job)
+                    (not ediff-show-ancestor)
+		    (ediff-buffer-live-p ediff-ancestor-buffer))
 		))
       (error ediff-KILLED-VITAL-BUFFER))
 
@@ -1587,7 +1624,10 @@ ediff-scroll-horizontally
 			  (if ediff-3way-comparison-job
 			      (window-width ediff-window-C)
 			    500) ; some large number
-			  )
+                          (if (and ediff-merge-with-ancestor-job
+                                   ediff-show-ancestor)
+                              (window-height ediff-window-Ancestor)
+                            500)) ; some large number
 		     2)
 		  3)))
 	 ;; window found
@@ -1689,6 +1729,11 @@ ediff-get-region-size-coefficient
 			       (funcall func 'B n ctl-buf)
 			       (if (ediff-buffer-live-p ediff-buffer-C)
 				   (funcall func 'C n ctl-buf)
+				 0)
+                               (if (and ediff-merge-with-ancestor-job
+                                        ediff-show-ancestor
+                                        (ediff-buffer-live-p ediff-ancestor-buffer))
+				   (funcall func 'Ancestor n ctl-buf)
 				 0))))
 	  ;; this covers the horizontal coefficient as well:
 	  ;; if max-lines = 0 then coef = 1
diff --git a/lisp/vc/ediff-wind.el b/lisp/vc/ediff-wind.el
index cd10288643..8516c11d13 100644
--- a/lisp/vc/ediff-wind.el
+++ b/lisp/vc/ediff-wind.el
@@ -115,6 +115,8 @@ ediff-window-setup-function
 (ediff-defvar-local ediff-window-B nil "")
 ;; Official window for buffer C
 (ediff-defvar-local ediff-window-C nil "")
+;; Official window for buffer Ancestor
+(ediff-defvar-local ediff-window-Ancestor nil "")
 ;; Ediff's window configuration.
 ;; Used to minimize the need to rearrange windows.
 (ediff-defvar-local ediff-window-config-saved "" "")
@@ -126,7 +128,8 @@ ediff-window-alist
     (B . ediff-window-B)
     (?B . ediff-window-B)
     (C . ediff-window-C)
-    (?C . ediff-window-C)))
+    (?C . ediff-window-C)
+    (Ancestor . ediff-window-Ancestor)))

 (defcustom ediff-split-window-function 'split-window-vertically
@@ -363,9 +366,13 @@ ediff-setup-windows-plain-merge
   ;; skip dedicated and unsplittable frames
   (ediff-destroy-control-frame control-buffer)
   (let ((window-min-height 1)
+	(with-Ancestor-p (ediff-with-current-buffer control-buffer
+                           ediff-merge-with-ancestor-job))
 	split-window-function
 	merge-window-share merge-window-lines
-	wind-A wind-B wind-C)
+	(buf-Ancestor (ediff-with-current-buffer control-buffer
+                        ediff-ancestor-buffer))
+	wind-A wind-B wind-C wind-Ancestor)
     (ediff-with-current-buffer control-buffer
       (setq merge-window-share ediff-merge-window-share
 	    ;; this lets us have local versions of ediff-split-window-function
@@ -394,6 +401,14 @@ ediff-setup-windows-plain-merge
     (setq wind-C (selected-window))
     (switch-to-buffer buf-C)
 
+    (when (and ediff-show-ancestor with-Ancestor-p)
+      (select-window wind-C)
+      (funcall split-window-function)
+      (when (eq (selected-window) wind-C)
+        (other-window 1))
+      (switch-to-buffer buf-Ancestor)
+      (setq wind-Ancestor (selected-window)))
+
     (select-window wind-A)
     (funcall split-window-function)
 
@@ -405,7 +420,8 @@ ediff-setup-windows-plain-merge
     (ediff-with-current-buffer control-buffer
       (setq ediff-window-A wind-A
 	    ediff-window-B wind-B
-	    ediff-window-C wind-C))
+	    ediff-window-C wind-C
+            ediff-window-Ancestor wind-Ancestor))
 
     (ediff-select-lowest-window)
     (ediff-setup-control-buffer control-buffer)
@@ -516,9 +532,13 @@ ediff-setup-windows-multiframe-merge
 	 (wind-A (ediff-get-visible-buffer-window buf-A))
 	 (wind-B (ediff-get-visible-buffer-window buf-B))
 	 (wind-C (ediff-get-visible-buffer-window buf-C))
+	 (buf-Ancestor (ediff-with-current-buffer control-buf
+                         ediff-ancestor-buffer))
+	 (wind-Ancestor (ediff-get-visible-buffer-window buf-Ancestor))
 	 (frame-A (if wind-A (window-frame wind-A)))
 	 (frame-B (if wind-B (window-frame wind-B)))
 	 (frame-C (if wind-C (window-frame wind-C)))
+	 (frame-Ancestor (if wind-Ancestor (window-frame wind-Ancestor)))
 	 ;; on wide display, do things in one frame
 	 (force-one-frame
 	  (ediff-with-current-buffer control-buf ediff-wide-display-p))
@@ -549,7 +569,10 @@ ediff-setup-windows-multiframe-merge
 	 (merge-window-share (ediff-with-current-buffer control-buf
 			       ediff-merge-window-share))
 	 merge-window-lines
-	 designated-minibuffer-frame
+	 designated-minibuffer-frame ; ediff-merge-with-ancestor-job
+     (with-Ancestor-p (ediff-with-current-buffer control-buf
+                        ediff-merge-with-ancestor-job))
+     (done-Ancestor (not with-Ancestor-p))
 	 done-A done-B done-C)
 
     ;; buf-A on its own
@@ -585,6 +608,19 @@ ediff-setup-windows-multiframe-merge
 	  (setq wind-C (selected-window))
 	  (setq done-C t)))
 
+    ;; buf-Ancestor on its own
+    (if (and ediff-show-ancestor
+             with-Ancestor-p
+             (window-live-p wind-Ancestor)
+             (ediff-window-ok-for-display wind-Ancestor)
+             (null use-same-frame)) ; buf Ancestor on its own
+        (progn
+          ;; buffer buf-Ancestor is seen in live wind-Ancestor
+          (select-window wind-Ancestor)
+          (delete-other-windows)
+          (setq wind-Ancestor (selected-window))
+          (setq done-Ancestor t)))
+
     (if (and use-same-frame-for-AB  ; implies wind A and B are suitable
 	     (window-live-p wind-A))
 	(progn
@@ -606,6 +642,7 @@ ediff-setup-windows-multiframe-merge
 	(let ((window-min-height 1))
 	  (if (and (eq frame-A frame-B)
 		   (eq frame-B frame-C)
+		   (eq frame-C frame-Ancestor)
 		   (frame-live-p frame-A))
 	      (select-frame frame-A)
 	    ;; avoid dedicated and non-splittable windows
@@ -623,6 +660,14 @@ ediff-setup-windows-multiframe-merge
 	  (setq wind-C (selected-window))
 	  (switch-to-buffer buf-C)
 
+      (when (and ediff-show-ancestor with-Ancestor-p)
+        (select-window wind-C)
+        (funcall split-window-function)
+        (if (eq (selected-window) wind-C)
+            (other-window 1))
+        (switch-to-buffer buf-Ancestor)
+        (setq wind-Ancestor (selected-window)))
+
 	  (select-window wind-A)
 
 	  (funcall split-window-function)
@@ -633,8 +678,8 @@ ediff-setup-windows-multiframe-merge
 
 	  (setq done-A t
 		done-B t
-		done-C t)
-	  ))
+		done-C t
+        done-Ancestor t)))
 
     (or done-A  ; Buf A to be set in its own frame,
 	      ;;; or it was set before because use-same-frame = 1
@@ -668,10 +713,22 @@ ediff-setup-windows-multiframe-merge
 	  (setq wind-C (selected-window))
 	  ))
 
+    (or done-Ancestor  ; Buf Ancestor to be set in its own frame,
+        (not ediff-show-ancestor)
+	      ;;; or it was set before because use-same-frame = 1
+        (progn
+          ;; Buf-Ancestor was not set up yet as it wasn't visible
+          ;; and use-same-frame = nil
+          (select-window orig-wind)
+          (delete-other-windows)
+          (switch-to-buffer buf-Ancestor)
+          (setq wind-Ancestor (selected-window))))
+
     (ediff-with-current-buffer control-buf
       (setq ediff-window-A wind-A
 	    ediff-window-B wind-B
-	    ediff-window-C wind-C)
+	    ediff-window-C wind-C
+            ediff-window-Ancestor wind-Ancestor)
       (setq frame-A (window-frame ediff-window-A)
 	    designated-minibuffer-frame
 	    (window-frame (minibuffer-window frame-A))))
@@ -679,7 +736,6 @@ ediff-setup-windows-multiframe-merge
     (ediff-setup-control-frame control-buf designated-minibuffer-frame)
     ))
 
-
 ;; Window setup for all comparison jobs, including 3way comparisons
 (defun ediff-setup-windows-multiframe-compare (buf-A buf-B buf-C control-buf)
 ;;; Algorithm:
@@ -1295,7 +1351,9 @@ ediff-keep-window-config
 	 (let ((ctl-wind ediff-control-window)
 	       (A-wind ediff-window-A)
 	       (B-wind ediff-window-B)
-	       (C-wind ediff-window-C))
+	       (C-wind ediff-window-C)
+               (ancestor-job ediff-merge-with-ancestor-job)
+               (Ancestor-wind ediff-window-Ancestor))
 
 	   (and
 	    (ediff-window-visible-p A-wind)
@@ -1303,13 +1361,19 @@ ediff-keep-window-config
 	    ;; if buffer C is defined then take it into account
 	    (or (not ediff-3way-job)
 		(ediff-window-visible-p C-wind))
+            (or (not ancestor-job)
+                (not ediff-show-ancestor)
+                (ediff-window-visible-p Ancestor-wind))
 	    (eq (window-buffer A-wind) ediff-buffer-A)
 	    (eq (window-buffer B-wind) ediff-buffer-B)
 	    (or (not ediff-3way-job)
 		(eq (window-buffer C-wind) ediff-buffer-C))
+            (or (not ancestor-job)
+                (not ediff-show-ancestor)
+                (eq (window-buffer Ancestor-wind) ediff-ancestor-buffer))
 	    (string= ediff-window-config-saved
-		     (format "%S%S%S%S%S%S%S"
-			     ctl-wind A-wind B-wind C-wind
+		     (format "%S%S%S%S%S%S%S%S"
+			     ctl-wind A-wind B-wind C-wind Ancestor-wind
 			     ediff-split-window-function
 			     (ediff-multiframe-setup-p)
 			     ediff-wide-display-p)))))))
-- 
2.11.0

--8<-----------------------------cut here---------------end--------------->8---
In GNU Emacs 26.0.50 (build 1, x86_64-pc-linux-gnu, GTK+ Version 3.22.8)
 of 2017-03-06
Repository revision: 0fae08d0072f74d97ca70b91a4d46d8d28a03952