X-Git-Url: https://code.delx.au/gnu-emacs/blobdiff_plain/3af0304a614da0c7f9b049623c1d814926930f95..3c53a3cf83c218772d9bcfde4cd60c1face33e93:/lisp/ediff-mult.el diff --git a/lisp/ediff-mult.el b/lisp/ediff-mult.el index bb6f815f87..b8e576d72b 100644 --- a/lisp/ediff-mult.el +++ b/lisp/ediff-mult.el @@ -1,8 +1,8 @@ ;;; ediff-mult.el --- support for multi-file/multi-buffer processing in Ediff -;; Copyright (C) 1995, 1996, 1997 Free Software Foundation, Inc. +;; Copyright (C) 1995, 96, 97, 98, 99, 2000, 01, 02 Free Software Foundation, Inc. -;; Author: Michael Kifer +;; Author: Michael Kifer ;; This file is part of GNU Emacs. @@ -26,7 +26,7 @@ ;; Users are encouraged to add functionality to this file. ;; The present file contains all the infrastructure needed for that. ;; -;; Generally, to to implement a new multisession capability within Ediff, +;; Generally, to implement a new multisession capability within Ediff, ;; you need to tell it ;; ;; 1. How to display the session group buffer. @@ -49,7 +49,7 @@ ;; or string). The function ediff-redraw-registry-buffer displays the ;; second through last of these in the registry buffer. ;; Also, keep in mind that the function ediff-prepare-meta-buffer -;; (which see) prepends the session group buffer to the descriptor and +;; (which see) prepends the session group buffer to the descriptor, and ;; nil in front of each subsequent list (i.e., the above list ;; will become ;; ((meta-buf descriptor) (nil obj1 obj2 obj3) (nil ...) ...) @@ -187,7 +187,15 @@ This can be toggled with `ediff-toggle-filename-truncation'." "*Hooks run just after the registry control panel is set up." :type 'hook :group 'ediff-mult) -(defcustom ediff-session-group-setup-hook nil + +(defcustom ediff-before-session-group-setup-hooks nil + "*Hooks to run before Ediff arranges the window for group-level operations. +It is used by commands such as ediff-directories. +This hook can be used to save the previous window config, which can be restored +on ediff-quit, ediff-suspend, or ediff-quit-session-group-hook." + :type 'hook + :group 'ediff-hook) +(defcustom ediff-after-session-group-setup-hook nil "*Hooks run just after a meta-buffer controlling a session group, such as ediff-directories, is run." :type 'hook @@ -217,6 +225,13 @@ buffers." ;;; API for ediff-meta-list +;; Structure of the meta-list: +;; (HEADER SESSION1 SESSION2 ...) +;; HEADER: (GROUP-BUF REGEXP OBJA OBJB OBJC SAVE-DIR) +;; OBJA - first directory +;; OBJB - second directory +;; OBJC - third directory +;; SESSION1/2/... are described below ;; group buffer/regexp (defsubst ediff-get-group-buffer (meta-list) (nth 0 (car meta-list))) @@ -233,6 +248,13 @@ buffers." (defsubst ediff-get-group-merge-autostore-dir (meta-list) (nth 5 (car meta-list))) +;; ELT is a session meta descriptor (what is being preserved as +;; 'ediff-meta-info) +;; The structure is: (SESSION-CTL-BUFFER STATUS OBJA OBJB OBJC) +;; STATUS is ?I, ?*, ?H +;; OBJA/B/C is (FILENAME EQSTATUS) +;; EQSTATUS is ?= or nil (?= means that this file is equal to some other +;; file in this session) ;; session buffer (defsubst ediff-get-session-buffer (elt) (nth 0 elt)) @@ -706,7 +728,7 @@ behavior." (if (eq ediff-metajob-name 'ediff-registry) (run-hooks 'ediff-registry-setup-hook) - (run-hooks 'ediff-session-group-setup-hook)) + (run-hooks 'ediff-after-session-group-setup-hook)) ) ; eval in meta-buffer meta-buffer)) @@ -793,9 +815,10 @@ behavior." (erase-buffer) ;; delete phony overlays that used to represent sessions before the buff ;; was redrawn - (if ediff-emacs-p - (mapcar 'delete-overlay (overlays-in 1 1)) - (map-extents 'delete-extent)) + (ediff-cond-compile-for-xemacs-or-emacs + (map-extents 'delete-extent) ; xemacs + (mapcar 'delete-overlay (overlays-in 1 1)) ; emacs + ) (insert (format ediff-meta-buffer-message (ediff-abbrev-jobname ediff-metajob-name))) @@ -896,30 +919,32 @@ behavior." (defun ediff-update-session-marker-in-dir-meta-buffer (session-num) (let (buffer-meta-overlays session-info overl buffer-read-only) (setq overl - (if ediff-xemacs-p - (map-extents - (lambda (ext maparg) - (if (and - (ediff-overlay-get ext 'ediff-meta-info) - (eq (ediff-overlay-get ext 'ediff-meta-session-number) - session-num)) - ext))) + (ediff-cond-compile-for-xemacs-or-emacs + (map-extents ; xemacs + (lambda (ext maparg) + (if (and + (ediff-overlay-get ext 'ediff-meta-info) + (eq (ediff-overlay-get ext 'ediff-meta-session-number) + session-num)) + ext))) ;; Emacs doesn't have map-extents, so try harder ;; Splice overlay lists to get all buffer overlays - (setq buffer-meta-overlays (overlay-lists) - buffer-meta-overlays (append (car buffer-meta-overlays) - (cdr buffer-meta-overlays))) - (car - (delq nil - (mapcar - (lambda (overl) - (if (and - (ediff-overlay-get overl 'ediff-meta-info) - (eq (ediff-overlay-get - overl 'ediff-meta-session-number) - session-num)) - overl)) - buffer-meta-overlays))))) + (progn + (setq buffer-meta-overlays (overlay-lists) + buffer-meta-overlays (append (car buffer-meta-overlays) + (cdr buffer-meta-overlays))) + (car + (delq nil + (mapcar + (lambda (overl) + (if (and + (ediff-overlay-get overl 'ediff-meta-info) + (eq (ediff-overlay-get + overl 'ediff-meta-session-number) + session-num)) + overl)) + buffer-meta-overlays)))) + )) (or overl (error "Bug in ediff-update-session-marker-in-dir-meta-buffer: no overlay with given number %S" @@ -962,7 +987,7 @@ behavior." 500)) file-modtime file-size) (cond ((not (stringp fname)) (setq file-size -2)) ; file doesn't exits - ((not (ediff-file-remote-p fname)) + ((ediff-listable-file fname) (if (file-exists-p fname) ;; set real size and modtime (setq file-size (ediff-file-size fname) @@ -1157,9 +1182,10 @@ Useful commands: (erase-buffer) ;; delete phony overlays that used to represent sessions before the buff ;; was redrawn - (if ediff-emacs-p - (mapcar 'delete-overlay (overlays-in 1 1)) - (map-extents 'delete-extent)) + (ediff-cond-compile-for-xemacs-or-emacs + (map-extents 'delete-extent) ; xemacs + (mapcar 'delete-overlay (overlays-in 1 1)) ; emacs + ) (insert "This is a registry of all active Ediff sessions. @@ -1255,6 +1281,9 @@ Useful commands: ;; Sets overlay around a meta record with 'ediff-meta-info property PROP ;; If optional SESSION-NUMBER, make it a property of the overlay, ;; ediff-meta-session-number +;; PROP is either the ctl or meta buffer (used when we work with the registry) +;; or a session meta descriptor of the form +;; (SESSION-CTL-BUFFER STATUS OBJA OBJB OBJC) (defun ediff-set-meta-overlay (b e prop &optional session-number hidden) (let (overl) (setq overl (ediff-make-overlay b e)) @@ -1482,7 +1511,7 @@ all marked sessions must be active." ;; This function executes in meta buffer. It knows where event happened. (defun ediff-filegroup-action () - "Execute appropriate action for the selected session." + "Execute appropriate action for a selected session." (interactive) (let* ((pos (ediff-event-point last-command-event)) (meta-buf (ediff-event-buffer last-command-event)) @@ -1525,14 +1554,14 @@ all marked sessions must be active." ediff-session-action-function ediff-metajob-name ;; make it update (car info) after startup - (` (list (lambda () - ;; child session group should know its parent - (setq ediff-parent-meta-buffer - (quote (, ediff-meta-buffer)) - ediff-meta-session-number - (, session-number)) - ;; and parent will know its child - (setcar (quote (, info)) ediff-meta-buffer))))))) + `(list (lambda () + ;; child session group should know its parent + (setq ediff-parent-meta-buffer + (quote ,ediff-meta-buffer) + ediff-meta-session-number + ,session-number) + ;; and parent will know its child + (setcar (quote ,info) ediff-meta-buffer)))))) ;; Do ediff-revision on a subdirectory ((and (ediff-one-filegroup-metajob) @@ -1546,15 +1575,15 @@ all marked sessions must be active." file1 regexp ediff-session-action-function ediff-metajob-name ;; make it update (car info) after startup - (` (list (lambda () - ;; child session group should know its parent and - ;; its number - (setq ediff-parent-meta-buffer - (quote (, ediff-meta-buffer)) - ediff-meta-session-number - (, session-number)) - ;; and parent will know its child - (setcar (quote (, info)) ediff-meta-buffer))))))) + `(list (lambda () + ;; child session group should know its parent and + ;; its number + (setq ediff-parent-meta-buffer + (quote ,ediff-meta-buffer) + ediff-meta-session-number + ,session-number) + ;; and parent will know its child + (setcar (quote ,info) ediff-meta-buffer)))))) ;; From here on---only individual session handlers @@ -1571,124 +1600,121 @@ all marked sessions must be active." (ediff-merge-files file1 file2 ;; provide startup hooks - (` (list (lambda () + `(list (lambda () (add-hook 'ediff-after-quit-hook-internal (lambda () - (if (ediff-buffer-live-p (, (current-buffer))) + (if (ediff-buffer-live-p ,(current-buffer)) (ediff-show-meta-buffer - (, (current-buffer)) (, session-number)))) + ,(current-buffer) ,session-number))) nil 'local) - (setq ediff-meta-buffer (, (current-buffer)) + (setq ediff-meta-buffer ,(current-buffer) ediff-meta-session-number - (, session-number)) + ,session-number) (setq ediff-merge-store-file - (, (if (ediff-nonempty-string-p - merge-autostore-dir) - (concat - merge-autostore-dir - "merge_" - (file-name-nondirectory file1))) + ,(if (ediff-nonempty-string-p + merge-autostore-dir) + (concat + merge-autostore-dir + ediff-merge-filename-prefix + (file-name-nondirectory file1)) )) ;; make ediff-startup pass ;; ediff-control-buffer back to the meta ;; level; see below (setcar - (quote (, info)) ediff-control-buffer))))) + (quote ,info) ediff-control-buffer)))) (error "Aborted"))) ((ediff-one-filegroup-metajob) ; needs 1 file arg (funcall ediff-session-action-function file1 ;; provide startup hooks - (` (list (lambda () - (add-hook - 'ediff-after-quit-hook-internal - (lambda () - (if (ediff-buffer-live-p - (, (current-buffer))) - (ediff-show-meta-buffer - (, (current-buffer)) - (, session-number)))) - nil 'local) - (setq ediff-meta-buffer (, (current-buffer)) - ediff-meta-session-number - (, session-number)) - (setq ediff-merge-store-file - (, (if (ediff-nonempty-string-p - merge-autostore-dir) - (concat - merge-autostore-dir - "merge_" - (file-name-nondirectory file1))) - )) - ;; make ediff-startup pass - ;; ediff-control-buffer back to the meta - ;; level; see below - (setcar - (quote (, info)) ediff-control-buffer)))))) + `(list (lambda () + (add-hook + 'ediff-after-quit-hook-internal + (lambda () + (if (ediff-buffer-live-p + ,(current-buffer)) + (ediff-show-meta-buffer + ,(current-buffer) + ,session-number))) + nil 'local) + (setq ediff-meta-buffer ,(current-buffer) + ediff-meta-session-number + ,session-number) + (setq ediff-merge-store-file + ,(if (ediff-nonempty-string-p + merge-autostore-dir) + (concat + merge-autostore-dir + ediff-merge-filename-prefix + (file-name-nondirectory file1))) ) + ;; make ediff-startup pass + ;; ediff-control-buffer back to the meta + ;; level; see below + (setcar + (quote ,info) ediff-control-buffer))))) ((not (ediff-metajob3)) ; need 2 file args (funcall ediff-session-action-function file1 file2 ;; provide startup hooks - (` (list (lambda () - (add-hook - 'ediff-after-quit-hook-internal - (lambda () - (if (ediff-buffer-live-p - (, (current-buffer))) - (ediff-show-meta-buffer - (, (current-buffer)) - (, session-number)))) - nil 'local) - (setq ediff-meta-buffer (, (current-buffer)) - ediff-meta-session-number - (, session-number)) - (setq ediff-merge-store-file - (, (if (ediff-nonempty-string-p - merge-autostore-dir) - (concat - merge-autostore-dir - "merge_" - (file-name-nondirectory file1))) - )) - ;; make ediff-startup pass - ;; ediff-control-buffer back to the meta - ;; level; see below - (setcar - (quote (, info)) ediff-control-buffer)))))) + `(list (lambda () + (add-hook + 'ediff-after-quit-hook-internal + (lambda () + (if (ediff-buffer-live-p + ,(current-buffer)) + (ediff-show-meta-buffer + ,(current-buffer) + ,session-number))) + nil 'local) + (setq ediff-meta-buffer ,(current-buffer) + ediff-meta-session-number + ,session-number) + (setq ediff-merge-store-file + ,(if (ediff-nonempty-string-p + merge-autostore-dir) + (concat + merge-autostore-dir + ediff-merge-filename-prefix + (file-name-nondirectory file1))) ) + ;; make ediff-startup pass + ;; ediff-control-buffer back to the meta + ;; level; see below + (setcar + (quote ,info) ediff-control-buffer))))) ((ediff-metajob3) ; need 3 file args (funcall ediff-session-action-function file1 file2 file3 ;; arrange startup hooks - (` (list (lambda () - (add-hook - 'ediff-after-quit-hook-internal - (lambda () - (if (ediff-buffer-live-p - (, (current-buffer))) - (ediff-show-meta-buffer - (, (current-buffer)) - (, session-number)))) - nil 'local) - (setq ediff-merge-store-file - (, (if (ediff-nonempty-string-p - merge-autostore-dir) - (concat - merge-autostore-dir - "merge_" - (file-name-nondirectory file1))) - )) - (setq ediff-meta-buffer (, (current-buffer)) - ediff-meta-session-number - (, session-number)) - ;; this arranges that ediff-startup will pass - ;; the value of ediff-control-buffer back to - ;; the meta level, to the record in the meta - ;; list containing the information about the - ;; session associated with that - ;; ediff-control-buffer - (setcar - (quote (, info)) ediff-control-buffer)))))) + `(list (lambda () + (add-hook + 'ediff-after-quit-hook-internal + (lambda () + (if (ediff-buffer-live-p + ,(current-buffer)) + (ediff-show-meta-buffer + ,(current-buffer) + ,session-number))) + nil 'local) + (setq ediff-merge-store-file + ,(if (ediff-nonempty-string-p + merge-autostore-dir) + (concat + merge-autostore-dir + ediff-merge-filename-prefix + (file-name-nondirectory file1))) ) + (setq ediff-meta-buffer , (current-buffer) + ediff-meta-session-number + ,session-number) + ;; this arranges that ediff-startup will pass + ;; the value of ediff-control-buffer back to + ;; the meta level, to the record in the meta + ;; list containing the information about the + ;; session associated with that + ;; ediff-control-buffer + (setcar + (quote ,info) ediff-control-buffer))))) ) ; cond ) ; eval in meta-buf )) @@ -1722,6 +1748,7 @@ all marked sessions must be active." (defun ediff-show-meta-buffer (&optional meta-buf session-number) "Show the session group buffer." (interactive) + (run-hooks 'ediff-before-directory-setup-hooks) (let (wind frame silent) (if meta-buf (setq silent t)) @@ -1772,6 +1799,8 @@ all marked sessions must be active." (setq frame (window-frame wind)) (raise-frame frame) (ediff-reset-mouse frame))) + (sit-for 0) ; sometimes needed to synch the display and ensure that the + ; point ends up after the just completed session (run-hooks 'ediff-show-session-group-hook) )) @@ -1952,18 +1981,22 @@ If this is a session registry buffer then just bury it." (let (result olist tmp) (if (and point (ediff-buffer-live-p buf)) (ediff-with-current-buffer buf - (if ediff-xemacs-p - (setq result - (if (setq tmp (extent-at point buf 'ediff-meta-info)) - (ediff-overlay-get tmp 'ediff-meta-info))) - (setq olist (overlays-at point)) - (setq olist - (mapcar (lambda (elt) (overlay-get elt 'ediff-meta-info)) - olist)) - (while (and olist (null (car olist)) - (overlay-get (car olist) 'invisible)) - (setq olist (cdr olist))) - (setq result (car olist))))) + (ediff-cond-compile-for-xemacs-or-emacs + (setq result ; xemacs + (if (setq tmp (extent-at point buf 'ediff-meta-info)) + (ediff-overlay-get tmp 'ediff-meta-info))) + (progn ; emacs + (setq olist (overlays-at point)) + (setq olist + (mapcar (lambda (elt) + (unless (overlay-get elt 'invisible) + (overlay-get elt 'ediff-meta-info))) + olist)) + (while (and olist (null (car olist))) + (setq olist (cdr olist))) + (setq result (car olist))) + ) + )) (if result result (if noerror @@ -1973,14 +2006,17 @@ If this is a session registry buffer then just bury it." (defun ediff-get-meta-overlay-at-pos (point) - (if ediff-xemacs-p - (extent-at point (current-buffer) 'ediff-meta-info) - (let* ((overl-list (overlays-at point)) - (overl (car overl-list))) - (while (and overl (null (overlay-get overl 'ediff-meta-info))) - (setq overl-list (cdr overl-list) - overl (car overl-list))) - overl))) + (ediff-cond-compile-for-xemacs-or-emacs + (extent-at point (current-buffer) 'ediff-meta-info) ; xemacs + ;; emacs + (let* ((overl-list (overlays-at point)) + (overl (car overl-list))) + (while (and overl (null (overlay-get overl 'ediff-meta-info))) + (setq overl-list (cdr overl-list) + overl (car overl-list))) + overl) + ) + ) (defsubst ediff-get-session-number-at-pos (point &optional meta-buffer) (setq meta-buffer (if (ediff-buffer-live-p meta-buffer) @@ -1996,18 +2032,21 @@ If this is a session registry buffer then just bury it." (if (eobp) (goto-char (point-min)) (let ((overl (ediff-get-meta-overlay-at-pos point))) - (if ediff-xemacs-p - (progn - (if overl - (setq overl (next-extent overl)) - (setq overl (next-extent (current-buffer)))) - (if overl - (extent-start-position overl) - (point-max))) - (if overl - ;; note: end of current overlay is the beginning of the next one - (overlay-end overl) - (next-overlay-change point)))) + (ediff-cond-compile-for-xemacs-or-emacs + (progn ; xemacs + (if overl + (setq overl (next-extent overl)) + (setq overl (next-extent (current-buffer)))) + (if overl + (extent-start-position overl) + (point-max))) + ;; emacs + (if overl + ;; note: end of current overlay is the beginning of the next one + (overlay-end overl) + (next-overlay-change point)) + ) + ) )) @@ -2015,27 +2054,30 @@ If this is a session registry buffer then just bury it." (if (bobp) (goto-char (point-max)) (let ((overl (ediff-get-meta-overlay-at-pos point))) - (if ediff-xemacs-p - (progn - (if overl - (setq overl (previous-extent overl)) - (setq overl (previous-extent (current-buffer)))) - (if overl - (extent-start-position overl) - (point-min))) - (if overl (setq point (overlay-start overl))) - ;; to get to the beginning of prev overlay - (if (not (bobp)) - ;; trick to overcome an emacs bug--doesn't always find previous - ;; overlay change correctly - (setq point (1- point))) - (setq point (previous-overlay-change point)) - ;; If we are not over an overlay after subtracting 1, it means we are - ;; in the description area preceding session records. In this case, - ;; goto the top of the registry buffer. - (or (car (overlays-at point)) - (setq point (point-min))) - point)))) + (ediff-cond-compile-for-xemacs-or-emacs + (progn + (if overl + (setq overl (previous-extent overl)) + (setq overl (previous-extent (current-buffer)))) + (if overl + (extent-start-position overl) + (point-min))) + (progn + (if overl (setq point (overlay-start overl))) + ;; to get to the beginning of prev overlay + (if (not (bobp)) + ;; trick to overcome an emacs bug--doesn't always find previous + ;; overlay change correctly + (setq point (1- point))) + (setq point (previous-overlay-change point)) + ;; If we are not over an overlay after subtracting 1, it means we are + ;; in the description area preceding session records. In this case, + ;; goto the top of the registry buffer. + (or (car (overlays-at point)) + (setq point (point-min))) + point) + ) + ))) ;; this is the action invoked when the user selects a patch from the meta ;; buffer. @@ -2086,10 +2128,17 @@ If this is a session registry buffer then just bury it." (ediff-update-meta-buffer (current-buffer) 'must-redraw)) -(defun ediff-meta-mark-equal-files () - "Run though the session list and mark identical files. -This is used only for sessions that involve 2 or 3 files at the same time." +;; ACTION is ?h, ?m, ?=: to mark for hiding, mark for operation, or simply +;; indicate which are equal files +(defun ediff-meta-mark-equal-files (&optional action) + "Run through the session list and mark identical files. +This is used only for sessions that involve 2 or 3 files at the same time. +ACTION is an optional argument that can be ?h, ?m, ?=, to mark for hiding, mark +for operation, or simply indicate which are equal files. If it is nil, then +last-command-char is used to decide which action to take." (interactive) + (if (null action) + (setq action last-command-char)) (let ((list (cdr ediff-meta-list)) marked1 marked2 marked3 fileinfo1 fileinfo2 fileinfo3 elt) @@ -2114,9 +2163,9 @@ This is used only for sessions that involve 2 or 3 files at the same time." (or (ediff-mark-if-equal fileinfo2 fileinfo3) (setq marked3 nil)))) (if (and marked1 marked2 marked3) - (cond ((eq last-command-char ?h) + (cond ((eq action ?h) (ediff-mark-session-for-hiding elt 'mark)) - ((eq last-command-char ?m) + ((eq action ?m) (ediff-mark-session-for-operation elt 'mark)) )) (setq list (cdr list)))