Add arch tagline
[bpt/emacs.git] / lisp / ediff-mult.el
index 41a7699..5150261 100644 (file)
@@ -1,6 +1,7 @@
 ;;; ediff-mult.el --- support for multi-file/multi-buffer processing in Ediff
 
-;; Copyright (C) 1995, 96, 97, 98, 99, 2000, 01, 02, 05 Free Software Foundation, Inc.
+;; Copyright (C) 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002,
+;;   2003, 2004, 2005, 2006, 2007 Free Software Foundation, Inc.
 
 ;; Author: Michael Kifer <kifer@cs.stonybrook.edu>
 
@@ -8,7 +9,7 @@
 
 ;; GNU Emacs is free software; you can redistribute it and/or modify
 ;; it under the terms of the GNU General Public License as published by
-;; the Free Software Foundation; either version 2, or (at your option)
+;; the Free Software Foundation; either version 3, or (at your option)
 ;; any later version.
 
 ;; GNU Emacs is distributed in the hope that it will be useful,
@@ -18,8 +19,8 @@
 
 ;; 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, Inc., 59 Temple Place - Suite 330,
-;; Boston, MA 02111-1307, USA.
+;; Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+;; Boston, MA 02110-1301, USA.
 
 ;;; Commentary:
 
 
 ;;; Code:
 
-(provide 'ediff-mult)
 
 (defgroup ediff-mult nil
-  "Multi-file and multi-buffer processing in Ediff"
+  "Multi-file and multi-buffer processing in Ediff."
   :prefix "ediff-"
   :group 'ediff)
 
 ;; end pacifier
 
 (require 'ediff-init)
-(require 'ediff-util)
 
 ;; meta-buffer
 (ediff-defvar-local ediff-meta-buffer nil "")
 ;; the registry buffer
 (defvar ediff-registry-buffer nil)
 
-(defconst ediff-meta-buffer-message "This is an Ediff Session Group Panel: %s
+(defconst ediff-meta-buffer-brief-message "Ediff Session Group Panel: %s
 
-Useful commands:
+     Type ? to show useful commands in this buffer
+
+")
+
+(defconst ediff-meta-buffer-verbose-message "Ediff Session Group Panel: %s
+
+Useful commands (type ? to hide them and free up screen):
      button2, v, or RET over session record:   start that Ediff session
      M:\tin sessions invoked from here, brings back this group panel
      R:\tdisplay the registry of active Ediff sessions
@@ -175,7 +180,7 @@ directories.")
 
 (defcustom ediff-default-filtering-regexp nil
   "The default regular expression used as a filename filter in multifile comparisons.
-Should be a sexp. For instance (car ediff-filtering-regexp-history) or nil."
+Should be a sexp.  For instance (car ediff-filtering-regexp-history) or nil."
   :type 'sexp
   :group 'ediff-mult)
 
@@ -205,6 +210,12 @@ Should be a sexp. For instance (car ediff-filtering-regexp-history) or nil."
 This can be toggled with `ediff-toggle-filename-truncation'."
   :type 'boolean
   :group 'ediff-mult)
+
+(defcustom ediff-meta-mode-hook nil
+  "*Hooks run just after setting up meta mode."
+  :type 'hook
+  :group 'ediff-mult)
+
 (defcustom ediff-registry-setup-hook nil
   "*Hooks run just after the registry control panel is set up."
   :type 'hook
@@ -212,9 +223,9 @@ This can be toggled with `ediff-toggle-filename-truncation'."
 
 (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.
+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."
+on `ediff-quit', `ediff-suspend', or `ediff-quit-session-group-hook'."
   :type 'hook
   :group 'ediff-hook)
 (defcustom ediff-after-session-group-setup-hook nil
@@ -235,7 +246,7 @@ ediff-directories, is run."
   :type 'hook
   :group 'ediff-mult)
 (defcustom ediff-meta-buffer-keymap-setup-hook nil
-  "*Hooks run just after setting up the ediff-meta-buffer-map.
+  "*Hooks run just after setting up the `ediff-meta-buffer-map'.
 This keymap controls key bindings in the meta buffer and is a local variable.
 This means that you can set different bindings for different kinds of meta
 buffers."
@@ -355,10 +366,24 @@ buffers."
        (if (stringp (ediff-get-session-objC-name session-info))
           (file-directory-p (ediff-get-session-objC-name session-info)) t)))
 
+
+(ediff-defvar-local ediff-verbose-help-enabled nil
+  "If t, display redundant help in ediff-directories and other meta buffers.
+Toggled by ediff-toggle-verbose-help-meta-buffer" )
+
+;; Toggle verbose help in meta-buffers
+;; TODO: Someone who understands all this can make it better.
+(defun ediff-toggle-verbose-help-meta-buffer ()
+  "Toggle showing tediously verbose help in meta buffers."
+  (interactive)
+  (setq ediff-verbose-help-enabled (not ediff-verbose-help-enabled))
+  (ediff-update-meta-buffer (current-buffer) 'must-redraw))
+
 ;; set up the keymap in the meta buffer
-(defun ediff-setup-meta-map()
+(defun ediff-setup-meta-map ()
   (setq ediff-meta-buffer-map (make-sparse-keymap))
   (suppress-keymap ediff-meta-buffer-map)
+  (define-key ediff-meta-buffer-map "?" 'ediff-toggle-verbose-help-meta-buffer)
   (define-key ediff-meta-buffer-map "q" 'ediff-quit-meta-buffer)
   (define-key ediff-meta-buffer-map "T" 'ediff-toggle-filename-truncation)
   (define-key ediff-meta-buffer-map "R" 'ediff-show-registry)
@@ -379,7 +404,7 @@ buffers."
        (define-key ediff-meta-buffer-map "=h" 'ediff-meta-mark-equal-files)))
   (if ediff-no-emacs-help-in-control-buffer
       (define-key ediff-meta-buffer-map  "\C-h"  'ediff-previous-meta-item))
-  (if ediff-emacs-p
+  (if (featurep 'emacs)
       (define-key ediff-meta-buffer-map [mouse-2] ediff-meta-action-function)
     (define-key ediff-meta-buffer-map [button2] ediff-meta-action-function))
 
@@ -410,7 +435,9 @@ Commands:
 \\{ediff-meta-buffer-map}"
   (kill-all-local-variables)
   (setq major-mode 'ediff-meta-mode)
-  (setq mode-name "MetaEdiff"))
+  (setq mode-name "MetaEdiff")
+  ;; don't use run-mode-hooks here!
+  (run-hooks 'ediff-meta-mode-hook))
 
 
 ;; the keymap for the buffer showing directory differences
@@ -421,7 +448,7 @@ Commands:
 (define-key ediff-dir-diffs-buffer-map "\C-?" 'previous-line)
 (define-key ediff-dir-diffs-buffer-map "p" 'previous-line)
 (define-key ediff-dir-diffs-buffer-map "C" 'ediff-dir-diff-copy-file)
-(if ediff-emacs-p
+(if (featurep 'emacs)
     (define-key ediff-dir-diffs-buffer-map [mouse-2] 'ediff-dir-diff-copy-file)
   (define-key ediff-dir-diffs-buffer-map [button2] 'ediff-dir-diff-copy-file))
 (define-key ediff-dir-diffs-buffer-map [delete] 'previous-line)
@@ -560,17 +587,23 @@ behavior."
                           (ediff-add-slash-if-directory auxdir1 elt))
                         lis1)
          auxdir2       (file-name-as-directory dir2)
+         lis2          (directory-files auxdir2 nil regexp)
+         lis2          (delete "."  lis2)
+         lis2          (delete ".." lis2)
          lis2          (mapcar
                         (lambda (elt)
                           (ediff-add-slash-if-directory auxdir2 elt))
-                        (directory-files auxdir2 nil regexp)))
+                        lis2))
 
     (if (stringp dir3)
        (setq auxdir3   (file-name-as-directory dir3)
+             lis3      (directory-files auxdir3 nil regexp)
+             lis3      (delete "."  lis3)
+             lis3      (delete ".." lis3)
              lis3      (mapcar
                         (lambda (elt)
                           (ediff-add-slash-if-directory auxdir3 elt))
-                        (directory-files auxdir3 nil regexp))))
+                        lis3)))
 
     (if (ediff-nonempty-string-p merge-autostore-dir)
        (setq merge-autostore-dir
@@ -608,15 +641,15 @@ behavior."
     ;; If file belongs to dir 1 only, the membership code is 2.
     ;; If it is in dir1 and dir3, then the membership code is 2*5=10;
     ;; if it is in dir1 and dir2, then the membership code is 2*3=6, etc.
-    (mapcar (lambda (elt)
-             (if (member (car elt) lis1)
-                 (setcdr elt (* (cdr elt) ediff-membership-code1)))
-             (if (member (car elt) lis2)
-                 (setcdr elt (* (cdr elt) ediff-membership-code2)))
-             (if (member (car elt) lis3)
-                 (setcdr elt (* (cdr elt) ediff-membership-code3)))
-             )
-           difflist)
+    (mapc (lambda (elt)
+           (if (member (car elt) lis1)
+               (setcdr elt (* (cdr elt) ediff-membership-code1)))
+           (if (member (car elt) lis2)
+               (setcdr elt (* (cdr elt) ediff-membership-code2)))
+           (if (member (car elt) lis3)
+               (setcdr elt (* (cdr elt) ediff-membership-code3)))
+           )
+         difflist)
     (setq difflist (cons
                    ;; diff metalist header
                    (ediff-make-new-meta-list-header regexp
@@ -635,8 +668,8 @@ behavior."
           (mapcar
            (lambda (elt)
              (ediff-make-new-meta-list-element
-              (concat auxdir1 elt)
-              (concat auxdir2 elt)
+              (expand-file-name (concat auxdir1 elt))
+              (expand-file-name (concat auxdir2 elt))
               (if lis3
                   (progn
                     ;; The following is done because: In merging with
@@ -647,7 +680,7 @@ behavior."
                     ;; the second case, we insert nil.
                     (setq elt (ediff-add-slash-if-directory auxdir3 elt))
                     (if (file-exists-p (concat auxdir3 elt))
-                        (concat auxdir3 elt))))))
+                        (expand-file-name (concat auxdir3 elt)))))))
            common)))
     ;; return result
     (cons common-part difflist)
@@ -703,7 +736,7 @@ behavior."
                                      auxdir1 nil nil
                                      merge-autostore-dir nil)
      (mapcar (lambda (elt) (ediff-make-new-meta-list-element
-                           (concat auxdir1 elt) nil nil))
+                           (expand-file-name (concat auxdir1 elt)) nil nil))
             common))
     ))
 
@@ -850,7 +883,7 @@ behavior."
         (session-info (ediff-overlay-get overl 'ediff-meta-info))
         (activity-marker (ediff-get-session-activity-marker session-info))
         buffer-read-only)
-    (or new-marker activity-marker (setq new-marker ?\ ))
+    (or new-marker activity-marker (setq new-marker ?\s))
     (goto-char (ediff-overlay-start overl))
     (if (eq (char-after (point)) new-marker)
        () ; if marker shown in buffer is the same as new-marker, do nothing
@@ -865,7 +898,7 @@ behavior."
         (session-info (ediff-overlay-get overl 'ediff-meta-info))
         (status (ediff-get-session-status session-info))
         buffer-read-only)
-    (setq new-status (or new-status status ?\ ))
+    (setq new-status (or new-status status ?\s))
     (goto-char (ediff-overlay-start overl))
     (forward-char 1) ; status is the second char in session record
     (if (eq (char-after (point)) new-status)
@@ -908,30 +941,34 @@ behavior."
       ;; was redrawn
       (ediff-cond-compile-for-xemacs-or-emacs
        (map-extents 'delete-extent)   ; xemacs
-       (mapcar 'delete-overlay (overlays-in 1 1))  ; emacs
+       (mapc 'delete-overlay (overlays-in 1 1))  ; emacs
        )
 
-      (insert (format ediff-meta-buffer-message
-                     (ediff-abbrev-jobname ediff-metajob-name)))
-
       (setq regexp (ediff-get-group-regexp meta-list)
            merge-autostore-dir
            (ediff-get-group-merge-autostore-dir meta-list))
 
-      (cond ((ediff-collect-diffs-metajob)
-            (insert
-             "     P:\tcollect custom diffs of all marked sessions\n"))
-           ((ediff-patch-metajob)
-            (insert
-             "     P:\tshow patch appropriately for the context (session or group)\n")))
-      (insert
-       "     ^:\tshow parent session group\n")
-      (or (ediff-one-filegroup-metajob)
-         (insert
-          "     D:\tshow differences among directories\n"
-          "    ==:\tfor each session, show which files are identical\n"
-          "    =h:\tlike ==, but also marks those sessions for hiding\n"
-          "    =m:\tlike ==, but also marks those sessions for operation\n\n"))
+      (if ediff-verbose-help-enabled
+         (progn
+           (insert (format ediff-meta-buffer-verbose-message
+                           (ediff-abbrev-jobname ediff-metajob-name)))
+
+           (cond ((ediff-collect-diffs-metajob)
+                  (insert
+                   "     P:\tcollect custom diffs of all marked sessions\n"))
+                 ((ediff-patch-metajob)
+                  (insert
+                   "     P:\tshow patch appropriately for the context (session or group)\n")))
+           (insert
+            "     ^:\tshow parent session group\n")
+           (or (ediff-one-filegroup-metajob)
+               (insert
+                "     D:\tshow differences among directories\n"
+                "    ==:\tfor each session, show which files are identical\n"
+                "    =h:\tlike ==, but also marks sessions for hiding\n"
+                "    =m:\tlike ==, but also marks sessions for operation\n\n")))
+       (insert (format ediff-meta-buffer-brief-message
+                       (ediff-abbrev-jobname ediff-metajob-name))))
 
       (insert "\n")
       (if (and (stringp regexp) (> (length regexp) 0))
@@ -1292,14 +1329,14 @@ Useful commands:
 
     ;; copy file to directories where it doesn't exist, update
     ;; ediff-dir-difference-list and redisplay
-    (mapcar
+    (mapc
      (lambda (otherfile-struct)
        (let ((otherfile (car otherfile-struct))
             (file-mem-code (cdr otherfile-struct)))
         (if otherfile
             (or (file-exists-p otherfile)
                 (if (y-or-n-p
-                     (format "Copy %s to %s ? " file-abs otherfile))
+                     (format "Copy %s to %s? " file-abs otherfile))
                     (let* ((file-diff-record (assoc file-tail dir-diff-list))
                            (new-mem-code
                             (* (cdr file-diff-record) file-mem-code)))
@@ -1325,7 +1362,10 @@ Useful commands:
        ;; update ediff-meta-list by direct modification
        (nconc meta-list
               (list (ediff-make-new-meta-list-element
-                     otherfile1 otherfile2 otherfile3)))
+                     (expand-file-name otherfile1)
+                     (expand-file-name otherfile2)
+                     (if otherfile3
+                         (expand-file-name otherfile3)))))
       )
     (ediff-update-meta-buffer meta-buf 'must-redraw)
   ))
@@ -1350,7 +1390,7 @@ Useful commands:
       ;; was redrawn
       (ediff-cond-compile-for-xemacs-or-emacs
        (map-extents 'delete-extent) ; xemacs
-       (mapcar 'delete-overlay (overlays-in 1 1)) ; emacs
+       (mapc 'delete-overlay (overlays-in 1 1)) ; emacs
        )
 
       (insert "This is a registry of all active Ediff sessions.
@@ -1370,11 +1410,11 @@ Useful commands:
 
 ")
       ;; purge registry list from dead buffers
-      (mapcar (lambda (elt)
-               (if (not (ediff-buffer-live-p elt))
-                   (setq ediff-session-registry
-                         (delq elt ediff-session-registry))))
-             ediff-session-registry)
+      (mapc (lambda (elt)
+             (if (not (ediff-buffer-live-p elt))
+                 (setq ediff-session-registry
+                       (delq elt ediff-session-registry))))
+           ediff-session-registry)
 
       (if (null ediff-session-registry)
          (insert "       ******* No active Ediff sessions *******\n"))
@@ -1453,11 +1493,12 @@ Useful commands:
 (defun ediff-set-meta-overlay (b e prop &optional session-number hidden)
   (let (overl)
     (setq overl (ediff-make-overlay b e))
-    (if ediff-emacs-p
+    (if (featurep 'emacs)
        (ediff-overlay-put overl 'mouse-face 'highlight)
       (ediff-overlay-put overl 'highlight t))
     (ediff-overlay-put overl 'ediff-meta-info prop)
     (ediff-overlay-put overl 'invisible hidden)
+    (ediff-overlay-put overl 'follow-link t)
     (if (numberp session-number)
        (ediff-overlay-put overl 'ediff-meta-session-number session-number))))
 
@@ -1609,7 +1650,7 @@ Useful commands:
           (save-excursion
             (set-buffer meta-diff-buff)
             (goto-char (point-max))
-            (insert-buffer custom-diff-buf)
+            (insert-buffer-substring custom-diff-buf)
             (insert "\n")))
          ;; if ediff session is not live, run diff directly on the files
          ((memq metajob '(ediff-directories
@@ -1620,15 +1661,19 @@ Useful commands:
             (set-buffer (setq tmp-buf (get-buffer-create ediff-tmp-buffer)))
             (erase-buffer)
             (shell-command
-             (format "%s %s %s %s"
-                     ediff-custom-diff-program ediff-custom-diff-options
-                     (ediff-get-session-objA-name session)
-                     (ediff-get-session-objB-name session))
-             t))
+             (format
+              "%s %s %s %s"
+              (shell-quote-argument ediff-custom-diff-program)
+              ediff-custom-diff-options
+              (shell-quote-argument (ediff-get-session-objA-name session))
+              (shell-quote-argument (ediff-get-session-objB-name session))
+              )
+             t)
+            )
           (save-excursion
             (set-buffer meta-diff-buff)
             (goto-char (point-max))
-            (insert-buffer tmp-buf)
+            (insert-buffer-substring tmp-buf)
             (insert "\n")))
          (t
           (ediff-kill-buffer-carefully meta-diff-buff)
@@ -1642,22 +1687,26 @@ This operation is defined only for `ediff-directories' and
 multifile patches.  For `ediff-directory-revisions', we insist that
 all marked sessions must be active."
   (interactive)
-  (or (ediff-buffer-live-p ediff-meta-diff-buffer)
-      (setq ediff-meta-diff-buffer
-           (get-buffer-create
-            (ediff-unique-buffer-name "*Ediff Multifile Diffs" "*"))))
-  (ediff-with-current-buffer ediff-meta-diff-buffer
-    (setq buffer-read-only nil)
-    (erase-buffer))
-  (if (> (ediff-operate-on-marked-sessions 'ediff-append-custom-diff) 0)
-      ;; did something
-      (progn
-       (display-buffer ediff-meta-diff-buffer 'not-this-window)
-       (ediff-with-current-buffer ediff-meta-diff-buffer
-         (set-buffer-modified-p nil)
-         (setq buffer-read-only t)))
-    (beep)
-    (message "No marked sessions found")))
+  (let ((coding-system-for-read ediff-coding-system-for-read))
+    (or (ediff-buffer-live-p ediff-meta-diff-buffer)
+       (setq ediff-meta-diff-buffer
+             (get-buffer-create
+              (ediff-unique-buffer-name "*Ediff Multifile Diffs" "*"))))
+    (ediff-with-current-buffer ediff-meta-diff-buffer
+                              (setq buffer-read-only nil)
+                              (erase-buffer))
+    (if (> (ediff-operate-on-marked-sessions 'ediff-append-custom-diff) 0)
+       ;; did something
+       (progn
+         (display-buffer ediff-meta-diff-buffer 'not-this-window)
+         (ediff-with-current-buffer ediff-meta-diff-buffer
+                                    (set-buffer-modified-p nil)
+                                    (setq buffer-read-only t))
+         (if (fboundp 'diff-mode)
+             (with-current-buffer ediff-meta-diff-buffer
+               (diff-mode))))
+      (beep)
+      (message "No marked sessions found"))))
 
 (defun ediff-meta-show-patch ()
   "Show the multi-file patch associated with this group session."
@@ -1676,7 +1725,8 @@ all marked sessions must be active."
               (ediff-get-session-objC-name info)))
            (set-buffer (get-buffer-create ediff-tmp-buffer))
            (erase-buffer)
-           (insert-buffer patchbuffer)
+           (insert-buffer-substring patchbuffer)
+           (goto-char (point-min))
            (display-buffer ediff-tmp-buffer 'not-this-window)
            ))
       (error "The patch buffer wasn't found"))))
@@ -2316,8 +2366,8 @@ If this is a session registry buffer then just bury it."
   "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."
+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))
@@ -2368,6 +2418,8 @@ last-command-char is used to decide which action to take."
     ))
 
 
+(provide 'ediff-mult)
+
 
 ;;; Local Variables:
 ;;; eval: (put 'ediff-defvar-local 'lisp-indent-hook 'defun)