*** empty log message ***
[bpt/emacs.git] / lisp / vc-hooks.el
index 67843d9..674d906 100644 (file)
@@ -6,8 +6,6 @@
 ;; Author:     FSF (see vc.el for full credits)
 ;; Maintainer: Andre Spiegel <spiegel@gnu.org>
 
-;; $Id$
-
 ;; This file is part of GNU Emacs.
 
 ;; GNU Emacs is free software; you can redistribute it and/or modify
@@ -325,17 +323,22 @@ non-nil if FILE exists and its contents were successfully inserted."
     (set-buffer-modified-p nil)
     t))
 
-(defun vc-find-root (file witness)
+(defun vc-find-root (file witness &optional invert)
   "Find the root of a checked out project.
 The function walks up the directory tree from FILE looking for WITNESS.
-If WITNESS if not found, return nil, otherwise return the root."
+If WITNESS if not found, return nil, otherwise return the root.
+Optional arg INVERT non-nil reverses the sense of the check;
+the root is the last directory for which WITNESS *is* found."
   ;; Represent /home/luser/foo as ~/foo so that we don't try to look for
   ;; witnesses in /home or in /.
-  (while (not (file-directory-p file))
-    (setq file (file-name-directory (directory-file-name file))))
   (setq file (abbreviate-file-name file))
   (let ((root nil)
-        (user (nth 2 (file-attributes file))))
+        (prev-file file)
+        ;; `user' is not initialized outside the loop because
+        ;; `file' may not exist, so we may have to walk up part of the
+        ;; hierarchy before we find the "initial UID".
+        (user nil)
+        try)
     (while (not (or root
                     (null file)
                     ;; As a heuristic, we stop looking up the hierarchy of
@@ -343,13 +346,21 @@ If WITNESS if not found, return nil, otherwise return the root."
                     ;; to another user.  This should save us from looking in
                     ;; things like /net and /afs.  This assumes that all the
                     ;; files inside a project belong to the same user.
-                    (not (equal user (nth 2 (file-attributes file))))
+                    (let ((prev-user user))
+                      (setq user (nth 2 (file-attributes file)))
+                      (and prev-user (not (equal user prev-user))))
                     (string-match vc-ignore-dir-regexp file)))
-      (if (file-exists-p (expand-file-name witness file))
-          (setq root file)
-        (if (equal file
-                   (setq file (file-name-directory (directory-file-name file))))
-            (setq file nil))))
+      (setq try (file-exists-p (expand-file-name witness file)))
+      (cond ((and invert (not try)) (setq root prev-file))
+            ((and (not invert) try) (setq root file))
+            ((equal file (setq prev-file file
+                               file (file-name-directory
+                                     (directory-file-name file))))
+             (setq file nil))))
+    ;; Handle the case where ~/WITNESS exists and the original FILE is "~".
+    ;; (This occurs, for example, when placing dotfiles under RCS.)
+    (when (and (not root) invert prev-file)
+      (setq root prev-file))
     root))
 
 ;; Access functions to file properties
@@ -506,6 +517,9 @@ For registered files, the value returned is one of:
 
   'removed           Scheduled to be deleted from the repository on next commit.
 
+  'missing           The file is not present in the file system, but the VC 
+                     system still tracks it.
+
   'ignored           The file showed up in a dir-state listing with a flag
                      indicating the version-control system is ignoring it,
                      Note: This property is not set reliably (some VCSes
@@ -592,6 +606,8 @@ If FILE is not registered, this function always returns nil."
 ;; Backward compatibility.
 (define-obsolete-function-alias
   'vc-workfile-version 'vc-working-revision "23.1")
+(define-obsolete-function-alias
+  'vc-previous-version 'vc-previous-revision "23.1")
 (defun vc-default-working-revision (backend file)
   (message
    "`working-revision' not found: using the old `workfile-version' instead")
@@ -732,11 +748,12 @@ Before doing that, check if there are any old backups and get rid of them."
   ;; and version backups should be made, copy the file to
   ;; another name.  This enables local diffs and local reverting.
   (let ((file buffer-file-name))
-    (and (vc-backend file)
-        (vc-up-to-date-p file)
-        (eq (vc-checkout-model file) 'implicit)
-        (vc-call make-version-backups-p file)
-         (vc-make-version-backup file))))
+    (ignore-errors               ;Be careful not to prevent saving the file.
+      (and (vc-backend file)
+           (vc-up-to-date-p file)
+           (eq (vc-checkout-model file) 'implicit)
+           (vc-call make-version-backups-p file)
+           (vc-make-version-backup file)))))
 
 (declare-function vc-dired-resynch-file "vc" (file))
 
@@ -841,6 +858,15 @@ This function assumes that the file is registered."
           ((stringp state)
            (setq state-echo (concat "File locked by" state))
            (concat backend ":" state ":" rev))
+           ((eq state 'added)
+            (setq state-echo "Locally added file")
+            (concat backend "@" rev))
+           ((eq state 'removed)
+            (setq state-echo "File removed from the VC system")
+            (concat backend "!" rev))
+           ((eq state 'missing)
+            (setq state-echo "File tracked by the VC system, but missing from the file system")
+            (concat backend "?" rev))
           (t
            ;; Not just for the 'edited state, but also a fallback
            ;; for all other states.  Think about different symbols
@@ -984,28 +1010,28 @@ Used in `find-file-not-found-functions'."
     (define-key map [vc-create-snapshot]
       '(menu-item "Create Snapshot" vc-create-snapshot
                  :help "Create Snapshot"))
-    (define-key map [vc-directory] 
+    (define-key map [vc-directory]
       '(menu-item "VC Directory Listing"  vc-directory
                  :help "Show the VC status of files in a directory"))
     ;; `vc-status' is a not-quite-ready replacement for `vc-directory'
     ;; (define-key map [vc-status] '("VC Status" . vc-status))
     (define-key map [separator1] '("----"))
-    (define-key map [vc-annotate] 
+    (define-key map [vc-annotate]
       '(menu-item "Annotate" vc-annotate
                  :help "Display the edit history of the current file using colors"))
-    (define-key map [vc-rename-file] 
+    (define-key map [vc-rename-file]
       '(menu-item "Rename File" vc-rename-file
                  :help "Rename file"))
     (define-key map [vc-revision-other-window]
       '(menu-item "Show Other Version" vc-revision-other-window
                  :help "Visit another version of the current file in another window"))
-    (define-key map [vc-diff] 
+    (define-key map [vc-diff]
       '(menu-item "Compare with Base Version" vc-diff
                  :help "Compare file set with the base version"))
     (define-key map [vc-update-change-log]
       '(menu-item "Update ChangeLog" vc-update-change-log
                  :help "Find change log file and add entries from recent version control logs"))
-    (define-key map [vc-print-log] 
+    (define-key map [vc-print-log]
       '(menu-item "Show History" vc-print-log
                  :help "List the change log of the current file set in a window"))
     (define-key map [separator2] '("----"))
@@ -1013,7 +1039,7 @@ Used in `find-file-not-found-functions'."
       '(menu-item "Insert Header" vc-insert-headers
                  :help "Insert headers into a file for use with a version control system.
 "))
-    (define-key map [undo] 
+    (define-key map [undo]
       '(menu-item "Undo Last Check-In" vc-rollback
                  :help "Remove the most recent changeset committed to the repository"))
     (define-key map [vc-revert]
@@ -1022,22 +1048,28 @@ Used in `find-file-not-found-functions'."
     (define-key map [vc-update]
       '(menu-item "Update to Latest Version" vc-update
                  :help "Update the current fileset's files to their tip revisions"))
-    (define-key map [vc-next-action] 
+    (define-key map [vc-next-action]
       '(menu-item "Check In/Out"  vc-next-action
                  :help "Do the next logical version control operation on the current fileset"))
-    (define-key map [vc-register] 
+    (define-key map [vc-register]
       '(menu-item "Register" vc-register
                  :help "Register file set into a version control system"))
     map))
 
 (defalias 'vc-menu-map vc-menu-map)
 
+(declare-function vc-responsible-backend "vc" (file &optional register))
+
 (defun vc-menu-map-filter (orig-binding)
   (if (and (symbolp orig-binding) (fboundp orig-binding))
       (setq orig-binding (indirect-function orig-binding)))
   (let ((ext-binding
-         (if vc-mode (vc-call-backend (vc-backend buffer-file-name)
-                                      'extra-menu))))
+         (when vc-mode
+          (vc-call-backend
+           (if buffer-file-name
+               (vc-backend buffer-file-name)
+             (vc-responsible-backend default-directory))
+           'extra-menu))))
     ;; Give the VC backend a chance to add menu entries
     ;; specific for that backend.
     (if (null ext-binding)