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

From: Tino Calancha <[email-masked]>
Date: Sun, 19 Feb 2017 19:47:32 +0900

Philipp Stephani <[email-masked]> writes:

> It would be very useful if ediff merge could optionally display the
> ancestor in a fourth window, like vimdiff or meld.  See
> https://lists.gnu.org/archive/html/emacs-devel/2017-01/msg00204.html.

Following patch, by default, display the ancestor buffer and auto refine
it in 3way merges.
This feature can be disabled by customizing a new option.

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; PATCH BEGINS
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

>From d1d0ef67e9d0a03ee5f60d56d13658f1a3d3a80a Mon Sep 17 00:00:00 2001
From: Tino Calancha <[email-masked]>
Date: Sun, 19 Feb 2017 19:15:04 +0900
Subject: [PATCH 1/3] Show ancestor buffer in 3way merges

Add an option to control if the ancestor buffer must
be shown in 3way merges (Bug#25493).
Add an option to control whether if show or ignore diffs with
ancestor that are equal in buffers A and B.
* lisp/vc/ediff-init.el (ediff-show-ancestor)
(ediff-hide-equal-diffs-with-ancestor): New options.
(ediff--restore-options-on-exit-alist): New defvar.
(ediff-get-value-according-to-buffer-type):
Add clause for the ancestor.
* lisp/vc/ediff-wind.el (ediff-window-Ancestor): New defvar.
(ediff-setup-windows-plain-merge, ediff-setup-windows-multiframe-merge):
Display ancestor buffer when ediff-show-ancestor is non-nil.
(ediff-keep-window-config): Expect ancestor window in
ediff-window-config-saved.
* lisp/vc/ediff-util.el (ediff-setup-control-buffer):
ediff-window-config-saved contains ancestor window.
(ediff-setup-keymap): New bindings for merge jobs:
bind ediff-toggle-show-ancestor to '\';
bind ediff-toggle-hide-equal-diffs-with-ancestor to '$%'.
(ediff-update-diffs): Compute new diffs using ancestor buffer.
(ediff--check-ancestor-exists): New defsubst extracted from
ediff-show-ancestor.
(ediff-swap-buffers): Take in account the ancestor.
(ediff-toggle-show-ancestor): New command; toggle ediff-show-ancestor.
(ediff-toggle-hide-equal-diffs-with-ancestor): New command; toggle
ediff-hide-equal-diffs-with-ancestor.
(ediff--restore-options-on-exit): Restore on exit option values changed
in previous toggles.
* lisp/vc/ediff-help.el (ediff-long-help-message-merge):
List the new toggles.
---
 lisp/vc/ediff-help.el |   2 +
 lisp/vc/ediff-init.el |  19 ++++++
 lisp/vc/ediff-util.el | 162 ++++++++++++++++++++++++++++++++++++--------------
 lisp/vc/ediff-wind.el |  83 ++++++++++++++++++++++----
 4 files changed, 210 insertions(+), 56 deletions(-)

diff --git a/lisp/vc/ediff-help.el b/lisp/vc/ediff-help.el
index 3292b4d939..89645d2f3b 100644
--- a/lisp/vc/ediff-help.el
+++ b/lisp/vc/ediff-help.el
@@ -115,6 +115,8 @@ ediff-long-help-message-merge
     ~ -swap variants |     s -shrink window C    |  / -show ancestor buff
                      |  $$ -show clashes only    |  & -merge w/new default
                      |  $* -skip changed regions |
+                     |  $% -all ancestor diffs   |
+                     |  \\ -show/hide ancestor    |
 "
   "Help message for merge sessions.
 Normally, not a user option.  See `ediff-help-message' for details.")
diff --git a/lisp/vc/ediff-init.el b/lisp/vc/ediff-init.el
index 0235926fbe..66a2a0f527 100644
--- a/lisp/vc/ediff-init.el
+++ b/lisp/vc/ediff-init.el
@@ -134,6 +134,7 @@ ediff-get-value-according-to-buffer-type
   `(cond ((eq ,buf-type 'A) (nth 0 ,list))
 	 ((eq ,buf-type 'B) (nth 1 ,list))
 	 ((eq ,buf-type 'C) (nth 2 ,list))
+	 ((eq ,buf-type 'Ancestor) (nth 3 ,list))
 	 ))
 
 (defmacro ediff-char-to-buftype (arg)
@@ -1355,6 +1356,24 @@ 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")
+
+(defcustom ediff-hide-equal-diffs-with-ancestor t
+  "If non-nil, hide diffs with ancestor that are equal in buffers A and B."
+  :type 'boolean
+  :group 'ediff-merge
+  :version "26.1")
+
+;; Store original values of options changed with
+;; `ediff-toggle-show-ancestor' or
+;; `ediff-toggle-hide-equal-diffs-with-ancestor'.  It's an alist
+;; (VAR . VALUE).
+(ediff-defvar-local ediff--restore-options-on-exit-alist 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..25dd2988bb 100644
--- a/lisp/vc/ediff-util.el
+++ b/lisp/vc/ediff-util.el
@@ -179,6 +179,7 @@ ediff-setup-keymap
   (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)
@@ -187,6 +188,7 @@ ediff-setup-keymap
 	 (define-key ediff-mode-map "+" 'ediff-combine-diffs)
 	 (define-key ediff-mode-map "$"  nil)
 	 (define-key ediff-mode-map "$$" 'ediff-toggle-show-clashes-only)
+	 (define-key ediff-mode-map "$%" 'ediff-toggle-hide-equal-diffs-with-ancestor)
 	 (define-key ediff-mode-map "$*" 'ediff-toggle-skip-changed-regions)
 	 (define-key ediff-mode-map "&" 'ediff-re-merge))
 	(ediff-3way-comparison-job
@@ -553,11 +555,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 +603,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 +611,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 +629,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 +649,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 +727,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,19 +955,92 @@ ediff-toggle-autorefine
 	 (setq ediff-auto-refine 'nix))
 	))
 
+(defsubst ediff--check-ancestor-exists ()
+  (or (ediff-buffer-live-p ediff-ancestor-buffer)
+      (if ediff-merge-with-ancestor-job
+	  (error "Lost connection to ancestor buffer.  This shouldn't happen.  \
+Please report this bug to [email-masked]")
+	(error "Not merging with ancestor"))))
+
 (defun ediff-show-ancestor ()
   "Show the ancestor buffer in a suitable window."
   (interactive)
   (ediff-recenter)
-  (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")))
+  (ediff--check-ancestor-exists)
   (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)))))
 
+;; Restore on exit the original values for options changed with
+;; `ediff-toggle-show-ancestor' or `ediff-toggle-hide-equal-diffs-with-ancestor'.
+(defun ediff--restore-options-on-exit ()
+  (when ediff--restore-options-on-exit-alist
+    (mapc (lambda (x)
+            (let ((var (car x))
+                  (value (cdr x)))
+              (message "Restoring %S to %S..." var value)
+              (set var value)))
+          ediff--restore-options-on-exit-alist)
+    (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)
+  (let ((alist ediff--restore-options-on-exit-alist))
+    ;; Save original value if not yet, and add hook to restore it on exit.
+    (unless (assq 'ediff-show-ancestor alist)
+      (push (cons 'ediff-show-ancestor ediff-show-ancestor)
+            alist)
+      (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
+              (alist-get 'ediff-show-ancestor alist))
+      (assq-delete-all 'ediff-show-ancestor alist)
+      (unless alist
+        (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)
+        (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))))
+      (ediff-recenter)
+      (message "Showing ancestor buffer"))
+    (setq ediff--restore-options-on-exit-alist alist)))
+
+(defun ediff-toggle-hide-equal-diffs-with-ancestor ()
+  "Toggle `ediff-hide-equal-diffs-with-ancestor'."
+  (interactive)
+  (let ((alist ediff--restore-options-on-exit-alist))
+    ;; Save original value if not yet, and add hook to restore it on exit.
+    (unless (assq 'ediff-hide-equal-diffs-with-ancestor
+                  alist)
+      (push (cons 'ediff-hide-equal-diffs-with-ancestor
+                  ediff-hide-equal-diffs-with-ancestor)
+            alist)
+      (add-hook 'ediff-quit-hook #'ediff--restore-options-on-exit))
+    (setq ediff-hide-equal-diffs-with-ancestor
+          (not ediff-hide-equal-diffs-with-ancestor))
+    ;; If equal than orig, then nothing to restore on exit.
+    (when (eq ediff-hide-equal-diffs-with-ancestor
+              (alist-get 'ediff-hide-equal-diffs-with-ancestor
+                         alist))
+      (assq-delete-all 'ediff-hide-equal-diffs-with-ancestor
+                       alist)
+      (unless alist
+        (remove-hook 'ediff-quit-hook #'ediff--restore-options-on-exit)))
+    (ediff-update-diffs)
+    (if (not ediff-hide-equal-diffs-with-ancestor)
+        (message "Showing all diffs with ancestor")
+      (message "Ignoring diffs with ancestor when they are equal in buffers A and B"))
+    (setq ediff--restore-options-on-exit-alist alist)))
+
 (defun ediff-make-or-kill-fine-diffs (arg)
   "Compute fine diffs.  With negative prefix arg, kill fine diffs.
 In both cases, operates on the current difference region."
@@ -1232,7 +1297,12 @@ ediff-swap-buffers
 		     (list (nth 2 ediff-narrow-bounds)
 			   (nth 0 ediff-narrow-bounds)
 			   (nth 1 ediff-narrow-bounds)))
-		    (ediff-3way-job
+		    (ediff-merge-with-ancestor-job
+		     (list (nth 1 ediff-narrow-bounds)
+			   (nth 0 ediff-narrow-bounds)
+			   (nth 2 ediff-narrow-bounds)
+                           (nth 3 ediff-narrow-bounds)))
+                    (ediff-3way-job
 		     (list (nth 1 ediff-narrow-bounds)
 			   (nth 0 ediff-narrow-bounds)
 			   (nth 2 ediff-narrow-bounds)))
diff --git a/lisp/vc/ediff-wind.el b/lisp/vc/ediff-wind.el
index cd10288643..560dc470a5 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 "" "")
@@ -363,9 +365,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 +400,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 +419,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 +531,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 +568,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 +607,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 +641,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 +659,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 +677,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 +712,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 +735,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 +1350,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 +1360,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

>From 2a1bc9b77c20153e2a1454bc1d20eb734ef41d15 Mon Sep 17 00:00:00 2001
From: Tino Calancha <[email-masked]>
Date: Sun, 19 Feb 2017 19:15:09 +0900
Subject: [PATCH 2/3] Auto refine ancestor buffer in 3way merges

* lisp/vc/ediff-diff.el (ediff-convert-diffs-to-overlays):
Prefer 'when' instead of 'if' here.
(ediff-make-fine-diffs, ediff-set-fine-diff-properties)
(ediff-set-fine-overlays-in-one-buffer)
(ediff-extract-diffs3, ediff-set-diff-overlays-in-one-buffer):
Consider ancestor buffer as well.
(ediff--set-right-faces): New defun.
* lisp/vc/ediff-init.el (ediff-state-of-merge): Update comment with new
state-of-merge 'A=B.
(ediff-fine-diff-face-Ancestor-A, ediff-fine-diff-face-Ancestor-B)
(ediff-fine-diff-face-AB, ediff-temp-file-Ancestor): New defvars.
(ediff-fine-diff-Ancestor-A, ediff-fine-diff-Ancestor-B)
(ediff-fine-diff-AB): New faces.
Add echo help for the new faces.
(ediff-clear-fine-differences): Clear ancestor diffs as well.
* lisp/vc/ediff-util.el (ediff-delete-temp-files): Delete ancestor
temporary file as well.
* doc/misc/ediff.texi (Quick Help Commands)
(Merging and diff3): Update manual.
; * etc/NEWS: Add entry for the new features.
---
 doc/misc/ediff.texi   |  55 +++++++--
 etc/NEWS              |   8 ++
 lisp/vc/ediff-diff.el | 332 ++++++++++++++++++++++++++++++--------------------
 lisp/vc/ediff-init.el |  62 +++++++++-
 lisp/vc/ediff-util.el |  14 +--
 5 files changed, 315 insertions(+), 156 deletions(-)

diff --git a/doc/misc/ediff.texi b/doc/misc/ediff.texi
index 19b7adbd66..2b3144f888 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.
@@ -810,6 +811,15 @@ Quick Help Commands
 of the variants clashes with the ancestor but the other variant agrees with
 it.  Typing @kbd{$$} again undoes this setting.
 
+@item $%
+@kindex $%
+When performing a 3way merge, any differences with the ancestor identical in
+both files, A and B are discarded.  Use this command in the control buffer
+if you want to see those differences as well.  Typing @kbd{$%} again
+undoes this setting.
+To enable this feature permanently, you might wish to customize the variable
+@code{ediff-hide-equal-diffs-with-ancestor}.
+
 @item $*
 @kindex $*
 When merging files with large number of differences, it is sometimes
@@ -828,7 +838,15 @@ Quick Help Commands
 
 @item /
 @kindex /
-Displays the ancestor file during merges.
+Displays the ancestor file during merges in the current difference.
+
+@item \
+@kindex \
+@vindex ediff-show-ancestor
+Displays the ancestor file during merges for all differences.
+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
@@ -1638,9 +1656,11 @@ Highlighting Difference Regions
 @item ediff-current-diff-face-A
 @itemx ediff-current-diff-face-B
 @itemx ediff-current-diff-face-C
+@itemx ediff-current-diff-face-Ancestor
 @vindex ediff-current-diff-face-A
 @vindex ediff-current-diff-face-B
 @vindex ediff-current-diff-face-C
+@vindex ediff-current-diff-face-Ancestor
 Ediff uses these faces to highlight current differences on devices where
 Emacs can display faces.  These and subsequently described faces can be set
 either in @file{.emacs} or in @file{.Xdefaults}.  The X resource for Ediff
@@ -1648,12 +1668,20 @@ Highlighting Difference Regions
 the information on how to set X resources.
 @item ediff-fine-diff-face-A
 @itemx ediff-fine-diff-face-B
+@itemx ediff-fine-diff-face-AB
 @itemx ediff-fine-diff-face-C
+@itemx ediff-fine-diff-face-Ancestor
+@itemx ediff-fine-diff-face-Ancestor-A
+@itemx ediff-fine-diff-face-Ancestor-B
 @vindex ediff-fine-diff-face-A
 @vindex ediff-fine-diff-face-B
+@vindex ediff-fine-diff-face-AB
 @vindex ediff-fine-diff-face-C
+@vindex ediff-fine-diff-face-Ancestor
+@vindex ediff-fine-diff-face-Ancestor-A
+@vindex ediff-fine-diff-face-Ancestor-B
 Ediff uses these faces to show the fine differences between the current
-differences regions in buffers A, B, and C, respectively.
+differences regions in buffers A, B, and C or Ancestor respectively.
 
 @item ediff-even-diff-face-A
 @itemx ediff-even-diff-face-B
@@ -2048,16 +2076,17 @@ Merging and diff3
 regions in buffers A or B are non-empty, this means that text was
 modified.  Otherwise, the original text was deleted.
 
-Although the ancestor buffer is normally invisible, Ediff maintains
-difference regions there and advances the current difference region
-accordingly.  All highlighting of difference regions is provided in the
-ancestor buffer, except for the fine differences.  Therefore, if desired, the
-user can put the ancestor buffer in a separate frame and watch it
-there.  However, on a TTY, only one frame can be visible at any given time,
-and Ediff doesn't support any single-frame window configuration where all
-buffers, including the ancestor buffer, would be visible.  However, the
-ancestor buffer can be displayed by typing @kbd{/} to the control
-window.  (Type @kbd{C-l} to hide it again.)
+@vindex ediff-hide-equal-diffs-with-ancestor
+The ancestor buffer is normally visible.  All highlighting of difference
+regions is provided on it, including the fine differences.
+By default, differences with the ancestor identical in the other two
+buffers are discarded.
+The option @code{ediff-hide-equal-diffs-with-ancestor} controls
+whether if those differences must be shown or not.  This option can be
+temporary disabled by typing @kbd{$%} to the control buffer.
+For those differences the state-of-difference indicator is @samp{A=B}.
+If desired, the ancestor buffer can be hidden by typing @kbd{\} to
+the control buffer.
 
 Note that the state-of-difference indicators @samp{=diff(A)} and
 @samp{=diff(B)} above are not redundant, even in the presence of a
diff --git a/etc/NEWS b/etc/NEWS
index 143e4655de..39940f0507 100644
--- a/etc/NEWS
+++ b/etc/NEWS
@@ -357,6 +357,14 @@ words where first character is upper rather than title case, e.g.,
 
 * Changes in Specialized Modes and Packages in Emacs 26.1
 
+** Ediff
+
++++
+*** The ancestor buffer is shown and refined by default in 3way merges.
+Two new options ediff-show-ancestor and
+ediff-hide-equal-diffs-with-ancestor and two new toggles
+ediff-toggle-show-ancestor, ediff-toggle-hide-equal-diffs-with-ancestor.
+
 ** TeX: Add luatex and xetex as alternatives to pdftex
 
 ** Electric-Buffer-menu
diff --git a/lisp/vc/ediff-diff.el b/lisp/vc/ediff-diff.el
index 37f22340d7..2e3bdc1475 100644
--- a/lisp/vc/ediff-diff.el
+++ b/lisp/vc/ediff-diff.el
@@ -509,8 +509,8 @@ ediff-convert-diffs-to-overlays
   (ediff-set-diff-overlays-in-one-buffer 'B diff-list)
   (if ediff-3way-job
       (ediff-set-diff-overlays-in-one-buffer 'C diff-list))
-  (if ediff-merge-with-ancestor-job
-      (ediff-set-diff-overlays-in-one-buffer 'Ancestor diff-list))
+  (when ediff-merge-with-ancestor-job
+    (ediff-set-diff-overlays-in-one-buffer 'Ancestor diff-list))
   ;; set up vector showing the status of merge regions
   (if ediff-merge-job
       (setq ediff-state-of-merge
@@ -613,6 +613,45 @@ ediff-set-diff-overlays-in-one-buffer
 	 (vconcat diff-overlay-list))
     ))
 
+
+;; Highlight with the same face overlays from different buffers
+;; with identical content.
+(defun ediff--set-right-faces (n)
+  (let ((ov-a (ediff-get-fine-diff-vector n 'A))
+        (ov-b (ediff-get-fine-diff-vector n 'B))
+        (ov-anc (ediff-get-fine-diff-vector n 'Ancestor))
+        (buf-A ediff-buffer-A)
+        (buf-B ediff-buffer-B)
+        (buf-anc ediff-ancestor-buffer))
+    (cl-flet ((set-faces-fn (overlays1 overlays2 buffer1 buffer2 face &optional setall)
+                (cl-mapc
+                 (lambda (ov1 ov2)
+                   (cl-flet ((fn (ov buf)
+                                 (with-current-buffer buf
+                                   (buffer-substring (ediff-overlay-start ov)
+                                                     (ediff-overlay-end ov)))))
+                     (when (string= (fn ov1 buffer1) (fn ov2 buffer2))
+                       (when setall
+                         (ediff-overlay-put ov1 'ediff-old-face face)
+                         (ediff-overlay-put ov1 'face face))
+                       (ediff-overlay-put ov2 'ediff-old-face face)
+                       (ediff-overlay-put ov2 'face face))))
+                 overlays1 overlays2)))
+      ;; Fine diffs common to A and B.
+      (set-faces-fn ov-a ov-b buf-A buf-B ediff-fine-diff-face-AB 'setall)
+      ;; Fine diffs common to A and Ancestor.
+      (set-faces-fn ov-a ov-anc buf-A buf-anc ediff-fine-diff-face-Ancestor-A)
+      ;; Fine diffs common to B and Ancestor.
+      (set-faces-fn ov-b ov-anc buf-B buf-anc ediff-fine-diff-face-Ancestor-B)
+      ;; Set `ediff-fine-diff-Ancestor' for fine diffs just present in Ancestor buffer.
+      (mapc (lambda (ov)
+              (unless (memq (ediff-overlay-get ov 'face)
+                            `(,ediff-fine-diff-face-Ancestor-A
+                              ,ediff-fine-diff-face-Ancestor-B))
+                (ediff-overlay-put ov 'ediff-old-face ediff-fine-diff-face-Ancestor)
+                (ediff-overlay-put ov 'face ediff-fine-diff-face-Ancestor)))
+            ov-anc))))
+
 ;; `n' is the diff region to work on.  Default is ediff-current-difference.
 ;; if `flag' is 'noforce then make fine-diffs only if this region's fine
 ;; diffs have not been computed before.
@@ -634,12 +673,17 @@ ediff-make-fine-diffs
 	    (file-A ediff-temp-file-A)
 	    (file-B ediff-temp-file-B)
 	    (file-C ediff-temp-file-C)
+	    (file-Ancestor ediff-temp-file-Ancestor)
 	    (empty-A (ediff-empty-diff-region-p n 'A))
 	    (empty-B (ediff-empty-diff-region-p n 'B))
 	    (empty-C (ediff-empty-diff-region-p n 'C))
+	    (empty-Ancestor (and ediff-merge-with-ancestor-job
+                                 (ediff-empty-diff-region-p n 'Ancestor)))
 	    (whitespace-A (ediff-whitespace-diff-region-p n 'A))
 	    (whitespace-B (ediff-whitespace-diff-region-p n 'B))
 	    (whitespace-C (ediff-whitespace-diff-region-p n 'C))
+	    (whitespace-Ancestor (and ediff-merge-with-ancestor-job
+                                      (ediff-whitespace-diff-region-p n 'Ancestor)))
 	    cumulative-fine-diff-length)
 
 	(cond ;; If one of the regions is empty (or 2 in 3way comparison)
@@ -727,10 +771,22 @@ ediff-make-fine-diffs
 			   (ediff-make-temp-file
 			    tmp-buffer "fineDiffC" file-C))))
 
-	       ;; save temp file names.
+               (when ediff-merge-with-ancestor-job
+                 (ediff-wordify
+                  (ediff-get-diff-posn 'Ancestor 'beg n)
+                  (ediff-get-diff-posn 'Ancestor 'end n)
+                  ediff-ancestor-buffer
+                  tmp-buffer
+                  ediff-control-buffer)
+                 (setq file-Ancestor
+                       (ediff-make-temp-file
+                        tmp-buffer "fineDiffAncestor" file-Ancestor)))
+
+               ;; save temp file names.
 	       (setq ediff-temp-file-A file-A
 		     ediff-temp-file-B file-B
-		     ediff-temp-file-C file-C)
+		     ediff-temp-file-C file-C
+		     ediff-temp-file-Ancestor file-Ancestor)
 
 	       ;; set the new vector of fine diffs, if none exists
 	       (cond ((and ediff-3way-job whitespace-A)
@@ -738,10 +794,13 @@ ediff-make-fine-diffs
 		     ((and ediff-3way-job whitespace-B)
 		      (ediff-setup-fine-diff-regions file-A nil file-C n))
 		     ((and ediff-3way-job
-			   ;; In merge-jobs, whitespace-C is t, since
-			   ;; ediff-empty-diff-region-p returns t in this case
-			   whitespace-C)
-		      (ediff-setup-fine-diff-regions file-A file-B nil n))
+		           ;; In merge-jobs, whitespace-C is t, since
+		           ;; ediff-empty-diff-region-p returns t in this case
+		           whitespace-C)
+                      (if (or (not ediff-merge-with-ancestor-job)
+                              (not ediff-show-ancestor))
+                          (ediff-setup-fine-diff-regions file-A file-B nil n)
+                        (ediff-setup-fine-diff-regions file-A file-B file-Ancestor n)))
 		     (t
 		      (ediff-setup-fine-diff-regions file-A file-B file-C n)))
 
@@ -779,6 +838,9 @@ ediff-make-fine-diffs
 	       )
 	      ) ; end cond
 	(ediff-set-fine-diff-properties n)
+        (when (and ediff-merge-with-ancestor-job
+                   ediff-show-ancestor)
+          (ediff--set-right-faces n))
 	)))
 
 ;; Interface to ediff-make-fine-diffs. Checks for auto-refine limit, etc.
@@ -812,7 +874,11 @@ ediff-set-fine-diff-properties
 	(ediff-set-fine-diff-properties-in-one-buffer 'A n default)
 	(ediff-set-fine-diff-properties-in-one-buffer 'B n default)
 	(if ediff-3way-job
-	    (ediff-set-fine-diff-properties-in-one-buffer 'C n default)))))
+	    (ediff-set-fine-diff-properties-in-one-buffer 'C n default))
+        (when (and ediff-merge-with-ancestor-job
+                   ediff-show-ancestor)
+          (ediff-set-fine-diff-properties-in-one-buffer 'Ancestor n default))
+)))
 
 (defun ediff-set-fine-diff-properties-in-one-buffer (buf-type
 						     n &optional default)
@@ -900,9 +966,11 @@ ediff-set-fine-overlays-in-one-buffer
 (defun ediff-convert-fine-diffs-to-overlays (diff-list region-num)
   (ediff-set-fine-overlays-in-one-buffer 'A diff-list region-num)
   (ediff-set-fine-overlays-in-one-buffer 'B diff-list region-num)
-  (if ediff-3way-job
-      (ediff-set-fine-overlays-in-one-buffer 'C diff-list region-num)
-    ))
+  (when ediff-3way-job
+    (ediff-set-fine-overlays-in-one-buffer 'C diff-list region-num)
+    (when (and ediff-merge-with-ancestor-job
+               ediff-show-ancestor)
+      (ediff-set-fine-overlays-in-one-buffer 'Ancestor diff-list region-num))))

 ;; Stolen from emerge.el
@@ -955,9 +1023,7 @@ ediff-extract-diffs3
 	(c-prev 1)
 	(c-prev-pt nil)
 	(anc-prev 1)
-	diff-list shift-A shift-B shift-C
-	)
-
+	diff-list shift-A shift-B shift-C)
     ;; diff list contains word numbers or points, depending on word-mode
     (setq diff-list (cons (if word-mode 'words 'points)
 			  diff-list))
@@ -989,125 +1055,123 @@ ediff-extract-diffs3
       (goto-char (point-min))
       (while (re-search-forward ediff-match-diff3-line nil t)
 	;; leave point after matched line
-       (beginning-of-line 2)
-       (let ((agreement (buffer-substring (match-beginning 1) (match-end 1))))
-	 ;; if the files A and B are the same and not 3way-comparison,
-	 ;; ignore the difference
-	 (if (or three-way-comp (not (string-equal agreement "3")))
-	     (let* ((a-begin (car (ediff-get-diff3-group "1")))
-		    (a-end  (nth 1 (ediff-get-diff3-group "1")))
-		    (b-begin (car (ediff-get-diff3-group "2")))
-		    (b-end (nth 1 (ediff-get-diff3-group "2")))
-		    (c-or-anc-begin (car (ediff-get-diff3-group "3")))
-		    (c-or-anc-end (nth 1 (ediff-get-diff3-group "3")))
-		    (state-of-merge
-		     (cond ((string-equal agreement "1") 'prefer-A)
-			   ((string-equal agreement "2") 'prefer-B)
-			   (t ediff-default-variant)))
-		    (state-of-diff-merge
-		     (if (memq state-of-merge '(default-A prefer-A)) 'B 'A))
-		    (state-of-diff-comparison
-		     (cond ((string-equal agreement "1") 'A)
-			   ((string-equal agreement "2") 'B)
-			   ((string-equal agreement "3") 'C)))
-		    state-of-ancestor
-		    c-begin c-end
-		    a-begin-pt a-end-pt
-		    b-begin-pt b-end-pt
-		    c-begin-pt c-end-pt
-		    anc-begin-pt anc-end-pt)
-
-	       (setq state-of-ancestor
-		     (= c-or-anc-begin c-or-anc-end))
-
-	       (cond (three-way-comp
-		      (setq c-begin c-or-anc-begin
-			    c-end c-or-anc-end))
-		     ((eq ediff-default-variant 'default-B)
-		      (setq c-begin b-begin
-			    c-end b-end))
-		     (t
-		      (setq c-begin a-begin
-			    c-end a-end)))
-
-	       ;; compute main diff vector
-	       (if word-mode
-		   ;; make diff-list contain word numbers
-		   (setq diff-list
-			 (nconc diff-list
-				(list (vector
-				       (- a-begin a-prev) (- a-end a-begin)
-				       (- b-begin b-prev) (- b-end b-begin)
-				       (- c-begin c-prev) (- c-end c-begin)
-				       nil nil ; dummy ancestor
-				       nil     ; state of diff
-				       nil     ; state of merge
-				       nil     ; state of ancestor
-				       )))
-			 a-prev a-end
-			 b-prev b-end
-			 c-prev c-end)
-		 ;; else convert lines to points
-		 (ediff-with-current-buffer A-buffer
-		   (goto-char (or a-prev-pt shift-A (point-min)))
-		   (forward-line (- a-begin a-prev))
-		   (setq a-begin-pt (point))
-		   (forward-line (- a-end a-begin))
-		   (setq a-end-pt (point)
-			 a-prev a-end
-			 a-prev-pt a-end-pt))
-		 (ediff-with-current-buffer B-buffer
-		   (goto-char (or b-prev-pt shift-B (point-min)))
-		   (forward-line (- b-begin b-prev))
-		   (setq b-begin-pt (point))
-		   (forward-line (- b-end b-begin))
-		   (setq b-end-pt (point)
-			 b-prev b-end
-			 b-prev-pt b-end-pt))
-		 (ediff-with-current-buffer C-buffer
-		   (goto-char (or c-prev-pt shift-C (point-min)))
-		   (forward-line (- c-begin c-prev))
-		   (setq c-begin-pt (point))
-		   (forward-line (- c-end c-begin))
-		   (setq c-end-pt (point)
-			 c-prev c-end
-			 c-prev-pt c-end-pt))
-		 (if (ediff-buffer-live-p anc-buffer)
-		     (ediff-with-current-buffer anc-buffer
-		       (forward-line (- c-or-anc-begin anc-prev))
-		       (setq anc-begin-pt (point))
-		       (forward-line (- c-or-anc-end c-or-anc-begin))
-		       (setq anc-end-pt (point)
-			     anc-prev c-or-anc-end)))
-		 (setq diff-list
-		       (nconc
-			diff-list
-			;; if comparing with ancestor, then there also is a
-			;; state-of-difference marker
-			(if three-way-comp
-			    (list (vector
-				   a-begin-pt a-end-pt
-				   b-begin-pt b-end-pt
-				   c-begin-pt c-end-pt
-				   nil nil ; ancestor begin/end
-				   state-of-diff-comparison
-				   nil	; state of merge
-				   nil  ; state of ancestor
-				   ))
-			  (list (vector a-begin-pt a-end-pt
-					b-begin-pt b-end-pt
-					c-begin-pt c-end-pt
-					anc-begin-pt anc-end-pt
-					state-of-diff-merge
-					state-of-merge
-					state-of-ancestor
-					)))
-			)))
-	       ))
-
-	 ))) ; end ediff-with-current-buffer
-    diff-list
-    ))
+        (beginning-of-line 2)
+        (let ((agreement (buffer-substring (match-beginning 1) (match-end 1))))
+          ;; Show diffs even if A and B are the same when
+          ;; ediff-hide-equal-diffs-with-ancestor is nil.
+          (unless (and (string-equal agreement "3")
+                       ediff-hide-equal-diffs-with-ancestor)
+            (let* ((a-begin (car (ediff-get-diff3-group "1")))
+                   (a-end  (nth 1 (ediff-get-diff3-group "1")))
+                   (b-begin (car (ediff-get-diff3-group "2")))
+                   (b-end (nth 1 (ediff-get-diff3-group "2")))
+                   (c-or-anc-begin (car (ediff-get-diff3-group "3")))
+                   (c-or-anc-end (nth 1 (ediff-get-diff3-group "3")))
+                   (state-of-merge
+                    (cond ((string-equal agreement "1") 'prefer-A)
+                          ((string-equal agreement "2") 'prefer-B)
+                          ((string-equal agreement "3") 'A=B)
+                          (t ediff-default-variant)))
+                   (state-of-diff-merge
+                    (if (memq state-of-merge '(default-A prefer-A)) 'B 'A))
+                   (state-of-diff-comparison
+                    (cond ((string-equal agreement "1") 'A)
+                          ((string-equal agreement "2") 'B)
+                          ((string-equal agreement "3") 'C)))
+                   state-of-ancestor
+                   c-begin c-end
+                   a-begin-pt a-end-pt
+                   b-begin-pt b-end-pt
+                   c-begin-pt c-end-pt
+                   anc-begin-pt anc-end-pt)
+
+              (setq state-of-ancestor
+                    (= c-or-anc-begin c-or-anc-end))
+
+              (cond (three-way-comp
+                     (setq c-begin c-or-anc-begin
+                           c-end c-or-anc-end))
+                    ((eq ediff-default-variant 'default-B)
+                     (setq c-begin b-begin
+                           c-end b-end))
+                    (t
+                     (setq c-begin a-begin
+                           c-end a-end)))
+
+              ;; compute main diff vector
+              (if word-mode
+                  ;; make diff-list contain word numbers
+                  (setq diff-list
+                        (nconc diff-list
+                               (list (vector
+                                      (- a-begin a-prev) (- a-end a-begin)
+                                      (- b-begin b-prev) (- b-end b-begin)
+                                      (- c-begin c-prev) (- c-end c-begin)
+                                      nil nil ; dummy ancestor
+                                      nil     ; state of diff
+                                      nil     ; state of merge
+                                      nil     ; state of ancestor
+                                      )))
+                        a-prev a-end
+                        b-prev b-end
+                        c-prev c-end)
+                ;; else convert lines to points
+                (ediff-with-current-buffer A-buffer
+                  (goto-char (or a-prev-pt shift-A (point-min)))
+                  (forward-line (- a-begin a-prev))
+                  (setq a-begin-pt (point))
+                  (forward-line (- a-end a-begin))
+                  (setq a-end-pt (point)
+                        a-prev a-end
+                        a-prev-pt a-end-pt))
+                (ediff-with-current-buffer B-buffer
+                  (goto-char (or b-prev-pt shift-B (point-min)))
+                  (forward-line (- b-begin b-prev))
+                  (setq b-begin-pt (point))
+                  (forward-line (- b-end b-begin))
+                  (setq b-end-pt (point)
+                        b-prev b-end
+                        b-prev-pt b-end-pt))
+                (ediff-with-current-buffer C-buffer
+                  (goto-char (or c-prev-pt shift-C (point-min)))
+                  (forward-line (- c-begin c-prev))
+                  (setq c-begin-pt (point))
+                  (forward-line (- c-end c-begin))
+                  (setq c-end-pt (point)
+                        c-prev c-end
+                        c-prev-pt c-end-pt))
+                (if (ediff-buffer-live-p anc-buffer)
+                    (ediff-with-current-buffer anc-buffer
+                      (forward-line (- c-or-anc-begin anc-prev))
+                      (setq anc-begin-pt (point))
+                      (forward-line (- c-or-anc-end c-or-anc-begin))
+                      (setq anc-end-pt (point)
+                            anc-prev c-or-anc-end)))
+                (setq diff-list
+                      (nconc
+                       diff-list
+                       ;; if comparing with ancestor, then there also is a
+                       ;; state-of-difference marker
+                       (if three-way-comp
+                           (list (vector
+                                  a-begin-pt a-end-pt
+                                  b-begin-pt b-end-pt
+                                  c-begin-pt c-end-pt
+                                  nil nil ; ancestor begin/end
+                                  state-of-diff-comparison
+                                  nil; state of merge
+                                  nil  ; state of ancestor
+                                  ))
+                         (list (vector a-begin-pt a-end-pt
+                                       b-begin-pt b-end-pt
+                                       c-begin-pt c-end-pt
+                                       anc-begin-pt anc-end-pt
+                                       state-of-diff-merge
+                                       state-of-merge
+                                       state-of-ancestor
+                                       ))))))))
+          ))) ; end ediff-with-current-buffer
+    diff-list))
 
 ;; Generate the difference vector and overlays for three files
 ;; File-C is either the third file to compare (in case of 3-way comparison)
diff --git a/lisp/vc/ediff-init.el b/lisp/vc/ediff-init.el
index 66a2a0f527..7e5291db5b 100644
--- a/lisp/vc/ediff-init.el
+++ b/lisp/vc/ediff-init.el
@@ -665,7 +665,7 @@ ediff-protected-variables
 
 ;; [ status status status ...]
 ;; Each status: [state-of-merge state-of-ancestor]
-;; state-of-merge is default-A, default-B, prefer-A, or prefer-B.  It
+;; state-of-merge is default-A, default-B, prefer-A, prefer-B or A=B.  It
 ;; indicates the way a diff region was created in buffer C.
 ;; state-of-ancestor says if the corresponding region in ancestor buffer is
 ;; empty.
@@ -1067,6 +1067,52 @@ ediff-fine-diff-Ancestor
 At present, this face is not used and no fine differences are computed for the
 ancestor buffer."
   :group 'ediff-highlighting)
+
+(defface ediff-fine-diff-Ancestor-A
+  '((t (:inherit ediff-fine-diff-A)))
+  "Face for highlighting refinement parts in Ancestor buffer due to buffer A."
+  :group 'ediff-highlighting
+  :version "26.1")
+
+;; An internal variable.  Ediff takes the face from here.  When unhighlighting,
+;; this variable is set to nil, then again to the appropriate face.
+(defvar ediff-fine-diff-face-Ancestor-A 'ediff-fine-diff-Ancestor-A
+  "Face for highlighting the fine differences in buffer Ancestor comming from buffer A.
+DO NOT CHANGE this variable.  Instead, use the customization
+widget to customize the actual face object `ediff-fine-diff-Ancestor-A'
+this variable represents.")
+(ediff-hide-face ediff-fine-diff-face-Ancestor-A)
+
+(defface ediff-fine-diff-Ancestor-B
+  '((t (:inherit ediff-fine-diff-B)))
+  "Face for highlighting refinement parts in Ancestor buffer due to buffer B."
+  :group 'ediff-highlighting
+  :version "26.1")
+
+;; An internal variable.  Ediff takes the face from here.  When unhighlighting,
+;; this variable is set to nil, then again to the appropriate face.
+(defvar ediff-fine-diff-face-Ancestor-B 'ediff-fine-diff-Ancestor-B
+  "Face for highlighting the fine differences in buffer Ancestor comming from buffer B.
+DO NOT CHANGE this variable.  Instead, use the customization
+widget to customize the actual face object `ediff-fine-diff-Ancestor-B'
+this variable represents.")
+(ediff-hide-face ediff-fine-diff-face-Ancestor-B)
+
+(defface ediff-fine-diff-AB
+  '((t (:inherit match)))
+  "Face for highlighting refinement parts common to buffers A and B."
+  :group 'ediff-highlighting
+  :version "26.1")
+
+;; An internal variable.  Ediff takes the face from here.  When unhighlighting,
+;; this variable is set to nil, then again to the appropriate face.
+(defvar ediff-fine-diff-face-AB 'ediff-fine-diff-AB
+  "Face for highlighting the fine differences common to buffers A and B.
+DO NOT CHANGE this variable.  Instead, use the customization
+widget to customize the actual face object `ediff-fine-diff-AB'
+this variable represents.")
+(ediff-hide-face ediff-fine-diff-face-AB)
+
 ;; An internal variable.  Ediff takes the face from here.  When unhighlighting,
 ;; this variable is set to nil, then again to the appropriate face.
 (defvar ediff-fine-diff-face-Ancestor 'ediff-fine-diff-Ancestor
@@ -1324,6 +1370,12 @@ ediff-fine-diff-face-alist
      "A `refinement' of the current difference region")
 (put ediff-fine-diff-face-Ancestor 'ediff-help-echo
      "A `refinement' of the current difference region")
+(put ediff-fine-diff-face-Ancestor-A 'ediff-help-echo
+     "Parts of `refinement' of the current difference region due to buffer A")
+(put ediff-fine-diff-face-Ancestor-B 'ediff-help-echo
+     "Parts of `refinement' of the current difference region due to buffer B")
+(put ediff-fine-diff-face-AB 'ediff-help-echo
+     "Parts of `refinement' of the current difference common to buffes A and B")
 
 (add-hook 'ediff-quit-hook 'ediff-cleanup-mess)
 (add-hook 'ediff-suspend-hook 'ediff-default-suspend-function)
@@ -1438,6 +1490,8 @@ ediff-H-glyph
 (ediff-defvar-local ediff-temp-file-B nil "")
 ;; Temporary file used for refining difference regions in buffer C.
 (ediff-defvar-local ediff-temp-file-C nil "")
+;; Temporary file used for refining difference regions in buffer Ancestor.
+(ediff-defvar-local ediff-temp-file-Ancestor nil "")

 (defun ediff-file-remote-p (file-name)
@@ -1520,7 +1574,11 @@ ediff-clear-fine-differences
   (ediff-clear-fine-differences-in-one-buffer n 'A)
   (ediff-clear-fine-differences-in-one-buffer n 'B)
   (if ediff-3way-job
-      (ediff-clear-fine-differences-in-one-buffer n 'C)))
+      (ediff-clear-fine-differences-in-one-buffer n 'C))
+  (when (and ediff-merge-with-ancestor-job
+             ediff-show-ancestor)
+    (ediff-clear-fine-differences-in-one-buffer n 'Ancestor))
+  )

 (defsubst ediff-mouse-event-p (event)
diff --git a/lisp/vc/ediff-util.el b/lisp/vc/ediff-util.el
index 25dd2988bb..fb3d85b758 100644
--- a/lisp/vc/ediff-util.el
+++ b/lisp/vc/ediff-util.el
@@ -2617,13 +2617,13 @@ ediff-good-frame-under-mouse

 (defun ediff-delete-temp-files ()
-  (if (and (stringp ediff-temp-file-A) (file-exists-p ediff-temp-file-A))
-      (delete-file ediff-temp-file-A))
-  (if (and (stringp ediff-temp-file-B) (file-exists-p ediff-temp-file-B))
-      (delete-file ediff-temp-file-B))
-  (if (and (stringp ediff-temp-file-C) (file-exists-p ediff-temp-file-C))
-      (delete-file ediff-temp-file-C)))
-
+  (mapc (lambda (x)
+          (when (and (stringp x) (file-exists-p x))
+            (delete-file x)))
+        (list ediff-temp-file-A
+              ediff-temp-file-B
+              ediff-temp-file-C
+              ediff-temp-file-Ancestor)))
 
 ;; Kill control buffer, other auxiliary Ediff buffers.
 ;; Leave one of the frames split between buffers A/B/C
-- 
2.11.0

>From 50b874fc64d8303ce7be71026e76fd28e5b1a91e Mon Sep 17 00:00:00 2001
From: Tino Calancha <[email-masked]>
Date: Sun, 19 Feb 2017 19:15:16 +0900
Subject: [PATCH 3/3] 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 7e5291db5b..6b5bdca347 100644
--- a/lisp/vc/ediff-init.el
+++ b/lisp/vc/ediff-init.el
@@ -943,13 +943,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))))
@@ -1053,13 +1057,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

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; PATCH ENDS
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

In GNU Emacs 26.0.50 (build 2, x86_64-pc-linux-gnu, GTK+ Version 3.22.7)
 of 2017-02-19
Repository revision: 938426d1ca0930b859c3e37b26513f5d74761284