(cvs-ignore-marks-modif): Use `rassoc' rather than `member*'.
[bpt/emacs.git] / lisp / pcvs.el
index 3db0eac..19d8773 100644 (file)
@@ -1,6 +1,6 @@
 ;;; pcvs.el -- A Front-end to CVS.
 
-;; Copyright (C) 1991-2000  Free Software Foundation, Inc.
+;; Copyright (C) 1991,92,93,94,95,95,97,98,99,2000  Free Software Foundation, Inc.
 
 ;; Author: (The PCL-CVS Trust) pcl-cvs@cyclic.com
 ;;     (Per Cederqvist) ceder@lysator.liu.se
@@ -13,8 +13,7 @@
 ;;     (Jari Aalto+mail.emacs) jari.aalto@poboxes.com
 ;; Maintainer: (Stefan Monnier) monnier+lists/cvs/pcl@flint.cs.yale.edu
 ;; Keywords: CVS, version control, release management
-;; Version: $Name:  $
-;; Revision: $Id: pcvs.el,v 1.14 2000/11/03 22:34:26 monnier Exp $
+;; Revision: $Id: pcvs.el,v 1.25 2001/01/29 20:22:28 monnier Exp $
 
 ;; This file is part of GNU Emacs.
 
 ;; To use PCL-CVS just use `M-x cvs-examine RET <dir> RET'.
 ;; There is a TeXinfo manual, which can be helpful to get started.
 
+;;; Bugs:
+
+;; - can somehow ignore important messages like `co aborted' or
+;;   or `co: output error: No space left on device'.
+
 ;;; Todo:
 
 ;; ******** FIX THE DOCUMENTATION *********
 ;; 
+;; - rework the displaying of error messages.
 ;; - use UP-TO-DATE rather than DEAD when cleaning before `examine'.
 ;; - allow to flush messages only
 ;; - allow to protect files like ChangeLog from flushing
@@ -65,7 +70,6 @@
 ;; - don't return the first (resp last) FI if the cursor is before
 ;;   (resp after) it.
 ;; - allow cvs-confirm-removals to force always confirmation.
-;;   also, use a fancier "temp buffer popup scheme".
 ;; - cvs-checkout should ask for a revision (with completion).
 ;; - removal confirmation should allow specifying another file name.
 ;; 
   (let ((cvs-minor-current-files
         (list (ewoc-data (ewoc-locate
                           cvs-cookies (posn-point (event-end e)))))))
-    (popup-menu cvs-menu-map e)))
+    (popup-menu cvs-menu e)))
 
 (defvar cvs-mode-line-process nil
   "Mode-line control for displaying info on cvs process status.")
@@ -863,7 +867,7 @@ With a prefix argument, prompt for cvs FLAGS to use."
 
 (defun-cvs-mode (cvs-mode-revert-buffer . SIMPLE)
                 (&optional ignore-auto noconfirm)
-  "Rerun `cvs-examine' on the current directory with the defauls flags."
+  "Rerun `cvs-examine' on the current directory with the default flags."
   (interactive)
   (cvs-examine default-directory t))
 
@@ -1053,7 +1057,7 @@ Full documentation is in the Texinfo file."
        (error "Inconsistent %s in buffer %s" check (buffer-name buf)))))
 
 
-(defun-cvs-mode cvs-mode-quit ()
+(defun cvs-mode-quit ()
   "Quit PCL-CVS, killing the *cvs* buffer."
   (interactive)
   (and (y-or-n-p "Quit pcl-cvs? ") (kill-buffer (current-buffer))))
@@ -1064,7 +1068,7 @@ Full documentation is in the Texinfo file."
   "Display help for various PCL-CVS commands."
   (interactive)
   (if (eq last-command 'cvs-help)
-      (describe-function 'cvs-mode)   ; would need minor-mode for cvs-edit-mode
+      (describe-function 'cvs-mode)   ; would need minor-mode for log-edit-mode
     (message
      (substitute-command-keys
       "`\\[cvs-help]':help `\\[cvs-mode-add]':add `\\[cvs-mode-commit]':commit \
@@ -1072,18 +1076,6 @@ Full documentation is in the Texinfo file."
 `\\[cvs-mode-remove]':remove `\\[cvs-mode-status]':status \
 `\\[cvs-mode-undo]':undo"))))
 
-(defun cvs-mode-diff-help ()
-  "Display help for various PCL-CVS diff commands."
-  (interactive)
-  (if (eq last-command 'cvs-mode-diff-help)
-      (describe-function 'cvs-mode)    ; no better docs for diff stuff?
-    (message
-     (substitute-command-keys
-      "`\\[cvs-mode-diff]':diff `\\[cvs-mode-idiff]':idiff \
-`\\[cvs-mode-diff-head]':head `\\[cvs-mode-diff-vendor]':vendor \
-`\\[cvs-mode-diff-backup]':backup `\\[cvs-mode-idiff-other]':other \
-`\\[cvs-mode-imerge]':imerge"))))
-
 ;; Move around in the buffer
 
 (defun-cvs-mode cvs-mode-previous-line (arg)
@@ -1183,7 +1175,7 @@ they should always be unmarked."
   (mapcar 'cdr cvs-ignore-marks-alternatives)
   (cvs-qtypedesc-create
    (lambda (str) (cdr (assoc str cvs-ignore-marks-alternatives)))
-   (lambda (obj) (caar (member* obj cvs-ignore-marks-alternatives :key 'cdr)))
+   (lambda (obj) (car (rassoc obj cvs-ignore-marks-alternatives)))
    (lambda () cvs-ignore-marks-alternatives)
    nil t))
 
@@ -1244,13 +1236,12 @@ Args: &optional IGNORE-MARKS IGNORE-CONTENTS."
          (push fi fis)
        ;; If a directory is selected, return members, if any.
        (setq fis
-             (append (ewoc-collect cvs-cookies
-                                   'cvs-dir-member-p
-                                   (cvs-fileinfo->dir fi))
+             (append (ewoc-collect
+                      cvs-cookies 'cvs-dir-member-p (cvs-fileinfo->dir fi))
                      fis))))
     (nreverse fis)))
 
-(defun* cvs-mode-marked (filter &optional (cmd (symbol-name filter))
+(defun* cvs-mode-marked (filter &optional cmd
                                &key read-only one file noquery)
   "Get the list of marked FIS.
 CMD is used to determine whether to use the marks or not.
@@ -1258,6 +1249,7 @@ Only files for which FILTER is applicable are returned.
 If READ-ONLY is non-nil, the current toggling is left intact.
 If ONE is non-nil, marks are ignored and a single FI is returned.
 If FILE is non-nil, directory entries won't be selected."
+  (unless cmd (setq cmd (symbol-name filter)))
   (let* ((fis (cvs-get-marked (or one (cvs-ignore-marks-p cmd read-only))
                              (and (not file)
                                   (cvs-applicable-p 'DIRCHANGE filter))))
@@ -1269,14 +1261,14 @@ If FILE is non-nil, directory entries won't be selected."
       (message (if (null fis)
                   "`%s' is not applicable to any of the selected files."
                 "`%s' is only applicable to a single file.") cmd)
-      (sit-for 0.5)
+      (sit-for 1)
       (setq fis (list (cvs-insert-file
                       (read-file-name (format "File to %s: " cmd))))))
     (if one (car fis) fis)))
 
 (defun cvs-enabledp (filter)
   "Determine whether FILTER applies to at least one of the selected files."
-  (cvs-mode-marked filter nil :read-only t :noquery t))
+  (ignore-errors (cvs-mode-marked filter nil :read-only t :noquery t)))
 
 (defun cvs-mode-files (&rest -cvs-mode-files-args)
   (cvs-mode!
@@ -1285,7 +1277,7 @@ If FILE is non-nil, directory entries won't be selected."
             (apply 'cvs-mode-marked -cvs-mode-files-args)))))
 
 ;;;
-;;; Interface between CVS-Edit and PCL-CVS
+;;; Interface between Log-Edit and PCL-CVS
 ;;;
 
 (defun cvs-mode-commit-setup ()
@@ -1298,27 +1290,28 @@ If FILE is non-nil, directory entries won't be selected."
 The user will be asked for a log message in a buffer.
 The buffer's mode and name is determined by the \"message\" setting
   of `cvs-buffer-name-alist'.
-The POSTPROC specified there (typically `cvs-edit') is then called,
+The POSTPROC specified there (typically `log-edit') is then called,
   passing it the SETUP argument."
   (interactive "P")
   ;; It seems that the save-excursion that happens if I use the better
   ;; form of `(cvs-mode! (lambda ...))' screws up a couple things which
-  ;; end up being rather annoying (like cvs-edit-mode's message being
+  ;; end up being rather annoying (like log-edit-mode's message being
   ;; displayed in the wrong minibuffer).
   (cvs-mode!)
-  (pop-to-buffer (cvs-temp-buffer "message" 'normal 'nosetup))
-  (set (make-local-variable 'cvs-minor-wrap-function) 'cvs-commit-minor-wrap)
-  (let ((lbd list-buffers-directory)
+  (let ((buf (cvs-temp-buffer "message" 'normal 'nosetup))
+       (lbd list-buffers-directory)
        (setupfun (or (nth 2 (cdr (assoc "message" cvs-buffer-name-alist)))
-                     'cvs-edit)))
-    (funcall setupfun 'cvs-do-commit setup 'cvs-commit-filelist)
+                     'log-edit)))
+    (funcall setupfun 'cvs-do-commit setup 'cvs-commit-filelist buf)
+    (set (make-local-variable 'cvs-minor-wrap-function) 'cvs-commit-minor-wrap)
     (set (make-local-variable 'list-buffers-directory) lbd)))
 
 (defun cvs-commit-minor-wrap (buf f)
   (let ((cvs-ignore-marks-modif (cvs-mode-mark-get-modif "commit")))
     (funcall f)))
 
-(defun cvs-commit-filelist () (cvs-mode-files 'commit nil :read-only t :file t))
+(defun cvs-commit-filelist ()
+  (cvs-mode-files 'commit nil :read-only t :file t :noquery t))
 
 (defun cvs-do-commit (flags)
   "Do the actual commit, using the current buffer as the log message."
@@ -1340,9 +1333,10 @@ The POSTPROC specified there (typically `cvs-edit') is then called,
                         ;; Can't use ignore-errors here because interactive
                         ;; specs aren't byte-compiled.
                         (condition-case nil
-                            (expand-file-name
-                             (cvs-fileinfo->dir
-                              (car (cvs-mode-marked nil nil :read-only t))))
+                            (file-name-as-directory
+                             (expand-file-name
+                              (cvs-fileinfo->dir
+                               (car (cvs-mode-marked nil nil :read-only t)))))
                           (error nil)))))
   (cvs-insert-file file))
 
@@ -1355,6 +1349,11 @@ The POSTPROC specified there (typically `cvs-edit') is then called,
     (goto-char (ewoc-location last))
     (ewoc-data last)))
 
+(defun cvs-mark-fis-dead (fis)
+  ;; Helper function, introduced because of the need for macro-expansion.
+  (dolist (fi fis)
+    (setf (cvs-fileinfo->type fi) 'DEAD)))
+
 (defun-cvs-mode (cvs-mode-add . SIMPLE) (flags)
   "Add marked files to the cvs repository.
 With prefix argument, prompt for cvs flags."
@@ -1378,7 +1377,7 @@ With prefix argument, prompt for cvs flags."
              `((cvs-run-process (list "-n" "update")
                                 ',dirs
                                 '(cvs-parse-process t))
-               (dolist (fi ',dirs) (setf (cvs-fileinfo->type fi) 'DEAD))))))
+               (cvs-mark-fis-dead ',dirs)))))
       (cvs-mode-run "add" flags fis :postproc postproc))))
 
 (defun-cvs-mode (cvs-mode-diff . DOUBLE) (flags)
@@ -1415,7 +1414,7 @@ or \"Conflict\" in the *cvs* buffer."
   (let* ((filter 'diff)
         (marked (cvs-get-marked (cvs-ignore-marks-p "diff")))
         ;;(tins (cvs-filter-applicable filter marked))
-        (fis (delete-if-not 'cvs-fileinfo->backup-file marked)))
+        (fis (car (cvs-partition 'cvs-fileinfo->backup-file marked))))
     (unless (consp fis)
       (error "No files with a backup file selected!"))
     ;; let's extract some info into the environment for `buffer-name'
@@ -1433,7 +1432,7 @@ Signal an error if there is no backup file."
   (let ((backup-file (cvs-fileinfo->backup-file fileinfo)))
     (unless backup-file
       (error "%s has no backup file." (cvs-fileinfo->full-path fileinfo)))
-    (list backup-file (cvs-fileinfo->file fileinfo))))
+    (list backup-file (cvs-fileinfo->full-path fileinfo))))
 
 ;;
 ;; Emerge support
@@ -1846,21 +1845,25 @@ Empty directories are removed."
   "Remove files.
 Returns a list of FIS that should be `cvs remove'd."
   (let* ((files (cvs-mode-marked filter cmd :file t :read-only t))
-        (fis (delete-if (lambda (fi) (eq (cvs-fileinfo->type fi) 'UNKNOWN))
-                        (cvs-mode-marked filter cmd)))
+        (fis (cdr (cvs-partition (lambda (fi)
+                                   (eq (cvs-fileinfo->type fi) 'UNKNOWN))
+                                 (cvs-mode-marked filter cmd))))
         (silent (or (not cvs-confirm-removals)
                     (cvs-every (lambda (fi)
                                  (or (not (file-exists-p
                                            (cvs-fileinfo->full-path fi)))
                                      (cvs-applicable-p fi 'safe-rm)))
-                               files))))
+                               files)))
+        (tmpbuf (cvs-temp-buffer)))
     (when (and (not silent) (equal cvs-confirm-removals 'list))
-      (save-excursion
-       (pop-to-buffer (cvs-temp-buffer))
-       (dolist (fi fis)
-         (insert (cvs-fileinfo->full-path fi) "\n"))))
+      (with-current-buffer tmpbuf
+       (cvs-insert-strings (mapcar 'cvs-fileinfo->full-path fis))
+       (cvs-pop-to-buffer-same-frame (current-buffer))
+       (shrink-window-if-larger-than-buffer)))
     (if (not (or silent
-                (yes-or-no-p (format "Delete %d files? " (length files)))))
+                (unwind-protect
+                    (yes-or-no-p (format "Delete %d files? " (length files)))
+                  (cvs-bury-buffer tmpbuf cvs-buffer))))
        (progn (message "Aborting") nil)
       (dolist (fi files)
        (let* ((type (cvs-fileinfo->type fi))
@@ -1919,8 +1922,8 @@ With prefix argument, prompt for cvs flags."
   (interactive)
   (let* ((fi (cvs-mode-marked nil nil :one t))
         (default-directory (cvs-expand-dir-name (cvs-fileinfo->dir fi)))
-        (buffer-file-name (expand-file-name (cvs-fileinfo->file fi)))
-        change-log-default-name)
+        (buffer-file-name (expand-file-name (cvs-fileinfo->file fi))))
+    (kill-local-variable 'change-log-default-name)
     (add-change-log-entry-other-window)))
 
 ;; interactive commands to set optional flags
@@ -1949,17 +1952,15 @@ With prefix argument, prompt for cvs flags."
 
 (defun cvs-execute-single-file (fi extractor program constant-args)
   "Internal function for `cvs-execute-single-file-list'."
-  (let* ((cur-dir (cvs-fileinfo->dir fi))
-        (default-directory (cvs-expand-dir-name cur-dir))
-        (inhibit-read-only t)
-        (arg-list (funcall extractor fi)))
+  (let* ((arg-list (funcall extractor fi))
+        (inhibit-read-only t))
 
     ;; Execute the command unless extractor returned t.
     (when (listp arg-list)
       (let* ((args (append constant-args arg-list)))
 
-       (insert (format "=== cd %s\n=== %s %s\n\n"
-                       cur-dir program (cvs-strings->string args)))
+       (insert (format "=== %s %s\n\n"
+                       program (cvs-strings->string args)))
 
        ;; FIXME: return the exit status?
        (apply 'call-process program nil t t args)
@@ -1968,10 +1969,9 @@ With prefix argument, prompt for cvs flags."
 ;; FIXME: make this run in the background ala cvs-run-process...
 (defun cvs-execute-single-file-list (fis extractor program constant-args)
   "Run PROGRAM on all elements on FIS.
-The PROGRAM will be called with pwd set to the directory the files
-reside in.  CONSTANT-ARGS is a list of strings to pass as arguments to
-PROGRAM.  The arguments given to the program will be CONSTANT-ARGS
-followed by the list that EXTRACTOR returns.
+CONSTANT-ARGS is a list of strings to pass as arguments to PROGRAM.
+The arguments given to the program will be CONSTANT-ARGS followed by
+the list that EXTRACTOR returns.
 
 EXTRACTOR will be called once for each file on FIS.  It is given
 one argument, the cvs-fileinfo.  It can return t, which means ignore
@@ -2108,17 +2108,6 @@ The exact behavior is determined also by `cvs-dired-use-hook'."
 
 (add-hook 'after-save-hook 'cvs-mark-buffer-changed)
 
-;;
-;; hook into uniquify
-;;
-
-(defadvice uniquify-buffer-file-name (after pcl-cvs-uniquify activate)
-  (or ad-return-value
-      (save-excursion
-       (set-buffer (ad-get-arg 0))
-       (when (eq major-mode 'cvs-mode)
-         (setq ad-return-value list-buffers-directory)))))
-
 \f
 (provide 'pcvs)