From mboxrd@z Thu Jan 1 00:00:00 1970 Path: news.gmane.org!.POSTED!not-for-mail From: Tino Calancha Newsgroups: gmane.emacs.bugs Subject: bug#25493: 26.0.50; ediff merge should (optionally) show ancestor in fourth window Date: Sun, 19 Feb 2017 19:47:32 +0900 Message-ID: <874lzqe9tn.fsf@calancha-pc> References: NNTP-Posting-Host: blaine.gmane.org Mime-Version: 1.0 Content-Type: text/plain X-Trace: blaine.gmane.org 1487501308 17253 195.159.176.226 (19 Feb 2017 10:48:28 GMT) X-Complaints-To: usenet@blaine.gmane.org NNTP-Posting-Date: Sun, 19 Feb 2017 10:48:28 +0000 (UTC) User-Agent: Gnus/5.13 (Gnus v5.13) Emacs/26.0.50 (gnu/linux) Cc: 25493@debbugs.gnu.org, tino.calancha@gmail.com To: Philipp Stephani Original-X-From: bug-gnu-emacs-bounces+geb-bug-gnu-emacs=m.gmane.org@gnu.org Sun Feb 19 11:48:17 2017 Return-path: Envelope-to: geb-bug-gnu-emacs@m.gmane.org Original-Received: from lists.gnu.org ([208.118.235.17]) by blaine.gmane.org with esmtp (Exim 4.84_2) (envelope-from ) id 1cfP2O-0003Py-13 for geb-bug-gnu-emacs@m.gmane.org; Sun, 19 Feb 2017 11:48:16 +0100 Original-Received: from localhost ([::1]:33152 helo=lists.gnu.org) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1cfP2T-0007l6-3V for geb-bug-gnu-emacs@m.gmane.org; Sun, 19 Feb 2017 05:48:21 -0500 Original-Received: from eggs.gnu.org ([2001:4830:134:3::10]:39045) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1cfP2F-0007cx-LV for bug-gnu-emacs@gnu.org; Sun, 19 Feb 2017 05:48:12 -0500 Original-Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) (envelope-from ) id 1cfP2A-0000za-BB for bug-gnu-emacs@gnu.org; Sun, 19 Feb 2017 05:48:07 -0500 Original-Received: from debbugs.gnu.org ([208.118.235.43]:47409) by eggs.gnu.org with esmtps (TLS1.0:RSA_AES_128_CBC_SHA1:16) (Exim 4.71) (envelope-from ) id 1cfP2A-0000zL-5L for bug-gnu-emacs@gnu.org; Sun, 19 Feb 2017 05:48:02 -0500 Original-Received: from Debian-debbugs by debbugs.gnu.org with local (Exim 4.84_2) (envelope-from ) id 1cfP29-0003WI-N0 for bug-gnu-emacs@gnu.org; Sun, 19 Feb 2017 05:48:01 -0500 X-Loop: help-debbugs@gnu.org Resent-From: Tino Calancha Original-Sender: "Debbugs-submit" Resent-CC: bug-gnu-emacs@gnu.org Resent-Date: Sun, 19 Feb 2017 10:48:01 +0000 Resent-Message-ID: Resent-Sender: help-debbugs@gnu.org X-GNU-PR-Message: followup 25493 X-GNU-PR-Package: emacs X-GNU-PR-Keywords: Original-Received: via spool by 25493-submit@debbugs.gnu.org id=B25493.148750127013513 (code B ref 25493); Sun, 19 Feb 2017 10:48:01 +0000 Original-Received: (at 25493) by debbugs.gnu.org; 19 Feb 2017 10:47:50 +0000 Original-Received: from localhost ([127.0.0.1]:45608 helo=debbugs.gnu.org) by debbugs.gnu.org with esmtp (Exim 4.84_2) (envelope-from ) id 1cfP1w-0003Vr-Ej for submit@debbugs.gnu.org; Sun, 19 Feb 2017 05:47:50 -0500 Original-Received: from mail-pf0-f193.google.com ([209.85.192.193]:35657) by debbugs.gnu.org with esmtp (Exim 4.84_2) (envelope-from ) id 1cfP1s-0003Vc-Gq for 25493@debbugs.gnu.org; Sun, 19 Feb 2017 05:47:46 -0500 Original-Received: by mail-pf0-f193.google.com with SMTP id 68so7496670pfx.2 for <25493@debbugs.gnu.org>; Sun, 19 Feb 2017 02:47:44 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20161025; h=from:to:cc:subject:references:date:in-reply-to:message-id :user-agent:mime-version; bh=qq9svwCQV0imT6NXC5BLkbhb4Qzo1RtZD5aww4iFRUA=; b=f2cRW/FtgMVLVzevG/gPf3H7drllNAlftB+J5tjdBnGdgVggL4eG4Sm6G0yHPEoshY QJnVkGm1moKF8pCAMaCV4zqa1RkKbxqvfvPJoKDF7wyVslZdTlSuviNLwZwwBQqN34aT u4ywEz0lVQ4MdX+qAe8mlNyHvS+KYXWjGA9oz7Bf2I6M1qf//XXubho8LcYXjiF4/eNX p1OIxqlE/Wqjtggxoltk9E955qEpvF4faMlcm73IpG3b+ulxLVKfzDQdUHODUUt3XiUx EbM6SYo7CL/S7JSP8UP2JZgM5GiyWds8KS6Nk8lLibKsC84XJrww3sMhBmip0sD/Ksro FpgQ== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:from:to:cc:subject:references:date:in-reply-to :message-id:user-agent:mime-version; bh=qq9svwCQV0imT6NXC5BLkbhb4Qzo1RtZD5aww4iFRUA=; b=tZcXsVkRZAHT2x8PT01Zjhv+7YPZuVlZmDaTDCQ3DdhNwt3gYOxPDgEReeVGckrs8t nq137YOSmP57M+q72W3OrujoaHPWeFDPx57AolwYhNkZ/7eDa0H42bxLN0seCgpHq6s4 hO8fXFcvAa2O9zsLVYt/I1Jpn91YEAEdSZCN58pVkz3jPGeq2V/wOrMFpP3y1nIbbpW9 mNWW8p30TxwhvvRBXkrMbL9+kY4Eldmta18L2ZHXjfWRlOObyUsnibncjv/gCOF6Q9aB XCgwI71qWjX9eCtp/S84O4YiQl1H5gh4NKpEvmg8WQhbS8SmBdktcd1QTFOMv7uDVZRn 1eSQ== X-Gm-Message-State: AMke39ksTzTbe8MPFO0lOyGjeU3QP8hXSxupyzuolE6cMigE37LG16/koGO8GIF8tLuBTg== X-Received: by 10.98.81.6 with SMTP id f6mr19254974pfb.180.1487501257953; Sun, 19 Feb 2017 02:47:37 -0800 (PST) Original-Received: from calancha-pc (104.81.147.124.dy.bbexcite.jp. [124.147.81.104]) by smtp.gmail.com with ESMTPSA id w75sm700836pfi.50.2017.02.19.02.47.35 (version=TLS1_2 cipher=ECDHE-RSA-CHACHA20-POLY1305 bits=256/256); Sun, 19 Feb 2017 02:47:37 -0800 (PST) In-Reply-To: (Philipp Stephani's message of "Fri, 20 Jan 2017 12:17:46 +0100") X-BeenThere: debbugs-submit@debbugs.gnu.org X-Mailman-Version: 2.1.18 Precedence: list X-detected-operating-system: by eggs.gnu.org: GNU/Linux 2.2.x-3.x [generic] X-Received-From: 208.118.235.43 X-BeenThere: bug-gnu-emacs@gnu.org List-Id: "Bug reports for GNU Emacs, the Swiss army knife of text editors" List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: bug-gnu-emacs-bounces+geb-bug-gnu-emacs=m.gmane.org@gnu.org Original-Sender: "bug-gnu-emacs" Xref: news.gmane.org gmane.emacs.bugs:129530 Archived-At: Philipp Stephani 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 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 bug-gnu-emacs@gnu.org") + (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 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 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