X-Git-Url: https://code.delx.au/gnu-emacs/blobdiff_plain/c439fb3045f133f26a1aaeb8a9d789f5bf80ad12..fadbdfeafe838d0ce1ca3e713b05243cb8d6e296:/lisp/ediff-merg.el diff --git a/lisp/ediff-merg.el b/lisp/ediff-merg.el index 3280861efd..a8752ff52a 100644 --- a/lisp/ediff-merg.el +++ b/lisp/ediff-merg.el @@ -1,5 +1,6 @@ ;;; ediff-merg.el --- merging utilities -;;; Copyright (C) 1994, 1995 Free Software Foundation, Inc. + +;; Copyright (C) 1994, 1995, 1996, 1997 Free Software Foundation, Inc. ;; Author: Michael Kifer @@ -16,41 +17,143 @@ ;; GNU General Public License for more details. ;; You should have received a copy of the GNU General Public License -;; along with GNU Emacs; see the file COPYING. If not, write to -;; the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. +;; along with GNU Emacs; see the file COPYING. If not, write to the +;; Free Software Foundation, Inc., 59 Temple Place - Suite 330, +;; Boston, MA 02111-1307, USA. + +;;; Code: + +(provide 'ediff-merg) +;; compiler pacifier +(defvar ediff-window-A) +(defvar ediff-window-B) +(defvar ediff-window-C) +(defvar ediff-merge-window-share) +(defvar ediff-window-config-saved) + +(eval-when-compile + (let ((load-path (cons (expand-file-name ".") load-path))) + (or (featurep 'ediff-init) + (load "ediff-init.el" nil nil 'nosuffix)) + (or (featurep 'ediff-util) + (load "ediff-util.el" nil nil 'nosuffix)) + )) +;; end pacifier (require 'ediff-init) -(defvar ediff-default-variant 'default-A +(defcustom ediff-quit-merge-hook 'ediff-maybe-save-and-delete-merge + "*Hooks to run before quitting a merge job. +The most common use is to save and delete the merge buffer." + :type 'hook + :group 'ediff-merge) + + +(defcustom ediff-default-variant 'combined "*The variant to be used as a default for buffer C in merging. -Valid values are the symbols `default-A', `default-B', and `combined'.") +Valid values are the symbols `default-A', `default-B', and `combined'." + :type '(radio (const default-A) (const default-B) (const combined)) + :group 'ediff-merge) -(defvar ediff-combination-pattern - '("#ifdef NEW /* variant A */" "#else /* variant B */" "#endif /* NEW */") +(defcustom ediff-combination-pattern + '("<<<<<<< variant A" A ">>>>>>> variant B" B "####### Ancestor" Ancestor "======= end") "*Pattern to be used for combining difference regions in buffers A and B. -The value is (STRING1 STRING2 STRING3). The combined text will look like this: +The value must be a list of the form +(STRING1 bufspec1 STRING2 bufspec2 STRING3 bufspec3 STRING4) +where bufspec is the symbol A, B, or Ancestor. For instance, if the value is +'(STRING1 A STRING2 Ancestor STRING3 B STRING4) then the +combined text will look like this: STRING1 diff region from variant A STRING2 -diff region from variant B +diff region from the ancestor STRING3 -") +diff region from variant B +STRING4 +" + :type '(choice (list string symbol string symbol string) + (list string symbol string symbol string symbol string)) + :group 'ediff-merge) -(ediff-defvar-local ediff-show-clashes-only nil +(defcustom ediff-show-clashes-only nil "*If t, show only those diff regions where both buffers disagree with the ancestor. This means that regions that have status prefer-A or prefer-B will be -skiped over. Nil means show all regions.") +skiped over. Nil means show all regions." + :type 'boolean + :group 'ediff-merge + ) +(make-variable-buffer-local 'ediff-show-clashes-only) + +(defcustom ediff-skip-merge-regions-that-differ-from-default nil + "*If t, show only the regions that have not been changed by the user. +A region is considered to have been changed if it is different from the current +default (`default-A', `default-B', `combined') and it hasn't been marked as +`prefer-A' or `prefer-B'. +A region is considered to have been changed also when it is marked as +as `prefer-A', but is different from the corresponding difference region in +Buffer A or if it is marked as `prefer-B' and is different from the region in +Buffer B." + :type 'boolean + :group 'ediff-merge + ) +(make-variable-buffer-local 'ediff-skip-merge-regions-that-differ-from-default) + +;; If ediff-show-clashes-only, check if there is no clash between the ancestor +;; and one of the variants. +(defsubst ediff-merge-region-is-non-clash (n) + (and ediff-show-clashes-only + (string-match "prefer" (or (ediff-get-state-of-merge n) "")))) + +;; If ediff-skip-changed-regions, check if the merge region differs from +;; the current default. If a region is different from the default, it means +;; that the user has made determination as to how to merge for this particular +;; region. +(defsubst ediff-skip-merge-region-if-changed-from-default-p (n) + (and ediff-skip-merge-regions-that-differ-from-default + (ediff-merge-changed-from-default-p n 'prefers-too))) + + +(defun ediff-get-combined-region (n) + (let ((pattern-list ediff-combination-pattern) + (combo-region "") + (err-msg + "ediff-combination-pattern: Invalid format. Please consult the documentation") + diff-region region-delim region-spec) + + (if (< (length pattern-list) 5) + (error err-msg)) + + (while (> (length pattern-list) 2) + (setq region-delim (nth 0 pattern-list) + region-spec (nth 1 pattern-list)) + (or (and (stringp region-delim) (memq region-spec '(A B Ancestor))) + (error err-msg)) + + (condition-case err + (setq combo-region + (concat combo-region + region-delim "\n" + (ediff-get-region-contents + n region-spec ediff-control-buffer))) + (error "")) + (setq pattern-list (cdr (cdr pattern-list))) + ) + + (setq region-delim (nth 0 pattern-list)) + (or (stringp region-delim) + (error err-msg)) + (setq combo-region (concat combo-region region-delim "\n")) + )) + +;;(defsubst ediff-make-combined-diff (regA regB) +;; (concat (nth 0 ediff-combination-pattern) "\n" +;; regA +;; (nth 1 ediff-combination-pattern) "\n" +;; regB +;; (nth 2 ediff-combination-pattern) "\n")) - -(defsubst ediff-get-combined-region (n) - (concat (nth 0 ediff-combination-pattern) "\n" - (ediff-get-region-contents n 'A ediff-control-buffer) - (nth 1 ediff-combination-pattern) "\n" - (ediff-get-region-contents n 'B ediff-control-buffer) - (nth 2 ediff-combination-pattern) "\n")) - (defsubst ediff-set-state-of-all-diffs-in-all-buffers (ctl-buf) (let ((n 0)) (while (< n ediff-number-of-differences) @@ -87,7 +190,6 @@ skiped over. Nil means show all regions.") )) (defun ediff-set-merge-mode () - ;; by Stig@hackvan.com (normal-mode t) (remove-hook 'local-write-file-hooks 'ediff-set-merge-mode)) @@ -104,9 +206,10 @@ skiped over. Nil means show all regions.") (defun ediff-do-merge (diff-num &optional remerging) (if (< diff-num 0) (setq diff-num 0)) (let ((n diff-num) - (default-state-of-merge (format "%S" ediff-default-variant)) + ;;(default-state-of-merge (format "%S" ediff-default-variant)) do-not-copy state-of-merge) (while (< n ediff-number-of-differences) + (setq do-not-copy nil) ; reset after each cycle (if (= (mod n 10) 0) (message "%s buffers A & B into C ... region %d of %d" (if remerging "Re-merging" "Merging") @@ -120,18 +223,11 @@ skiped over. Nil means show all regions.") (reg-B (ediff-get-region-contents n 'B ediff-control-buffer)) (reg-C (ediff-get-region-contents n 'C ediff-control-buffer))) - ;;; was edited since first set by default - (if (or (and (string= state-of-merge "default-A") - (not (string= reg-A reg-C))) - ;; was edited since first set by default - (and (string= state-of-merge "default-B") - (not (string= reg-B reg-C))) - ;; was edited since first set by default - (and (string= state-of-merge "combined") - (not (string= - (ediff-make-combined-diff reg-A reg-B) reg-C))) - ;; was prefered--ignore + ;; if region was edited since it was first set by default + (if (or (ediff-merge-changed-from-default-p n) + ;; was preferred (string-match "prefer" state-of-merge)) + ;; then ignore (setq do-not-copy t)) ;; change state of merge for this diff, if necessary @@ -158,7 +254,7 @@ skiped over. Nil means show all regions.") (defun ediff-re-merge () - "Remerge unmodified diff regions using a new default. Start with the current region." + "Remerge unmodified diff regions using a new default. Start with the current region." (interactive) (let* ((default-variant-alist (list '("default-A") '("default-B") '("combined"))) @@ -168,7 +264,7 @@ skiped over. Nil means show all regions.") (setq ediff-default-variant (intern (completing-read - (format "Current merge default is `%S'. New default: " + (format "Current merge default is `%S'. New default: " ediff-default-variant) actual-alist nil 'must-match))) (ediff-do-merge ediff-current-difference 'remerge) @@ -200,63 +296,92 @@ Used only for merging jobs." (ediff-recenter 'no-rehighlight)))) -;; N here is the user's region number. It is 1+ what Ediff uses internally. +;; N here is the user's region number. It is 1+ what Ediff uses internally. (defun ediff-combine-diffs (n &optional batch-invocation) "Combine Nth diff regions of buffers A and B and place the combination in C. -Combining is done using the list in variable `ediff-combination-pattern'." +N is a prefix argument. If nil, combine the current difference regions. +Combining is done according to the specifications in variable +`ediff-combination-pattern'." (interactive "P") - (setq n (if n (1- n) ediff-current-difference)) + (setq n (if (numberp n) (1- n) ediff-current-difference)) (let (regA regB reg-combined) - (setq regA (ediff-get-region-contents n 'A ediff-control-buffer) - regB (ediff-get-region-contents n 'B ediff-control-buffer)) - - (setq reg-combined (ediff-make-combined-diff regA regB)) + ;;(setq regA (ediff-get-region-contents n 'A ediff-control-buffer) + ;; regB (ediff-get-region-contents n 'B ediff-control-buffer)) + ;;(setq reg-combined (ediff-make-combined-diff regA regB)) + (setq reg-combined (ediff-get-combined-region n)) (ediff-copy-diff n nil 'C batch-invocation reg-combined)) - (or batch-invocation (ediff-recenter))) + (or batch-invocation (ediff-jump-to-difference (1+ n)))) -(defsubst ediff-make-combined-diff (regA regB) - (concat (nth 0 ediff-combination-pattern) "\n" - regA - (nth 1 ediff-combination-pattern) "\n" - regB - (nth 2 ediff-combination-pattern) "\n")) - ;; Checks if the region in buff C looks like a combination of the regions -;; in buffers A and B. Returns a list (reg-a-beg reg-a-end reg-b-beg reg-b-end) -;; These refer to where the copies of region A and B start and end in buffer C +;; in buffers A and B. Return a list (reg-a-beg reg-a-end reg-b-beg reg-b-end) +;; These refer to where the delimiters for region A, B, Ancestor start and end +;; in buffer C (defun ediff-looks-like-combined-merge (region-num) (if ediff-merge-job (let ((combined (string-match (regexp-quote "(A+B)") (or (ediff-get-state-of-diff region-num 'C) ""))) - (reg-beg (ediff-get-diff-posn 'C 'beg region-num)) - (reg-end (ediff-get-diff-posn 'C 'end region-num)) - (pat1 (nth 0 ediff-combination-pattern)) - (pat2 (nth 1 ediff-combination-pattern)) - (pat3 (nth 2 ediff-combination-pattern)) - reg-a-beg reg-a-end reg-b-beg reg-b-end reg-c-beg reg-c-end) + (mrgreg-beg (ediff-get-diff-posn 'C 'beg region-num)) + (mrgreg-end (ediff-get-diff-posn 'C 'end region-num)) + (pattern-list ediff-combination-pattern) + delim reg-beg reg-end delim-regs-list) (if combined - (ediff-eval-in-buffer ediff-buffer-C - (goto-char reg-beg) - (search-forward pat1 reg-end 'noerror) - (setq reg-a-beg (match-beginning 0)) - (setq reg-a-end (match-end 0)) - (search-forward pat2 reg-end 'noerror) - (setq reg-b-beg (match-beginning 0)) - (setq reg-b-end (match-end 0)) - (search-forward pat3 reg-end 'noerror) - (setq reg-c-beg (match-beginning 0)) - (setq reg-c-end (match-end 0)))) + (ediff-with-current-buffer ediff-buffer-C + (while pattern-list + (goto-char mrgreg-beg) + (setq delim (nth 0 pattern-list)) + (search-forward delim mrgreg-end 'noerror) + (setq reg-beg (match-beginning 0)) + (setq reg-end (match-end 0)) + (if (and reg-beg reg-end) + (setq delim-regs-list + ;; in reverse + (cons reg-end (cons reg-beg delim-regs-list)))) + (if (> (length pattern-list) 1) + (setq pattern-list (cdr (cdr pattern-list))) + (setq pattern-list nil)) + ))) + + (reverse delim-regs-list) + ))) - (if (and reg-a-beg reg-a-end reg-b-beg reg-b-end) - (list reg-a-beg reg-a-end reg-b-beg reg-b-end reg-c-beg reg-c-end)) + +;; Check if the non-preferred merge has been modified since originally set. +;; This affects only the regions that are marked as default-A/B or combined. +;; If PREFERS-TOO is non-nil, then look at the regions marked as prefers-A/B as +;; well. +(defun ediff-merge-changed-from-default-p (diff-num &optional prefers-too) + (let ((reg-A (ediff-get-region-contents diff-num 'A ediff-control-buffer)) + (reg-B (ediff-get-region-contents diff-num 'B ediff-control-buffer)) + (reg-C (ediff-get-region-contents diff-num 'C ediff-control-buffer))) + + (setq state-of-merge (ediff-get-state-of-merge diff-num)) + + ;; if region was edited since it was first set by default + (or (and (string= state-of-merge "default-A") + (not (string= reg-A reg-C))) + (and (string= state-of-merge "default-B") + (not (string= reg-B reg-C))) + (and (string= state-of-merge "combined") + ;;(not (string= (ediff-make-combined-diff reg-A reg-B) reg-C))) + (not (string= (ediff-get-combined-region diff-num) reg-C))) + (and prefers-too + (string= state-of-merge "prefer-A") + (not (string= reg-A reg-C))) + (and prefers-too + (string= state-of-merge "prefer-B") + (not (string= reg-B reg-C))) ))) -(provide 'ediff-merg) +;;; Local Variables: +;;; eval: (put 'ediff-defvar-local 'lisp-indent-hook 'defun) +;;; eval: (put 'ediff-with-current-buffer 'lisp-indent-hook 1) +;;; eval: (put 'ediff-with-current-buffer 'edebug-form-spec '(form body)) +;;; End: ;; ediff-merg.el ends here