]> code.delx.au - gnu-emacs/blobdiff - lisp/vc.el
* term/ns-win.el (ns-insert-working-text, ns-put-working-text): Switch names and...
[gnu-emacs] / lisp / vc.el
index 600d432dad261bafa112ce9fefa4cd886cb3cc59..e9de682285ae6348a00af18a86a86cb4c103e099 100644 (file)
@@ -1,7 +1,7 @@
 ;;; vc.el --- drive a version-control system from within Emacs
 
 ;; Copyright (C) 1992, 1993, 1994, 1995, 1996, 1997, 1998, 2000,
-;;   2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008
+;;   2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009
 ;;   Free Software Foundation, Inc.
 
 ;; Author:     FSF (see below for full credits)
@@ -82,9 +82,6 @@
 ;; vc's back is turned, or move/rename master files while vc is running,
 ;; vc may get seriously confused.  Don't do these things!
 ;;
-;; Developer's notes on some concurrency issues are included at the end of
-;; the file.
-;;
 ;; ADDING SUPPORT FOR OTHER BACKENDS
 ;;
 ;; VC can use arbitrary version control systems as a backend.  To add
 ;;   and then do a (funcall UPDATE-FUNCTION RESULT nil)
 ;;   when all the results have been computed.
 ;;   To provide more backend specific functionality for `vc-dir'
-;;   the following functions might be needed: `status-extra-headers',
-;;   `status-printer', `extra-status-menu' and `dir-status-files'.
+;;   the following functions might be needed: `dir-extra-headers',
+;;   `dir-printer', `extra-dir-menu' and `dir-status-files'.
 ;;
 ;; - dir-status-files (dir files default-state update-function)
 ;;
 ;;   files. If not provided, the default is to consider that the files
 ;;   are in DEFAULT-STATE.
 ;;
-;; - status-extra-headers (dir)
+;; - dir-extra-headers (dir)
 ;;
 ;;   Return a string that will be added to the *vc-dir* buffer header.
 ;;
-;; - status-printer (fileinfo)
+;; - dir-printer (fileinfo)
 ;;
 ;;   Pretty print the `vc-dir-fileinfo' FILEINFO.
 ;;   If a backend needs to show more information than the default FILE
 ;;
 ;; MISCELLANEOUS
 ;;
-;; - root (dir)
-;;
-;;   Return DIR's "root" directory, that is, a parent directory of
-;;   DIR for which the same backend as used for DIR applies.  If no
-;;   such parent exists, this function should return DIR.
-;;
 ;; - make-version-backups-p (file)
 ;;
 ;;   Return non-nil if unmodified repository revisions of FILE should be
 ;;   to your backend and which does not map to any of the VC generic
 ;;   concepts.
 ;;
-;; - extra-status-menu ()
+;; - extra-dir-menu ()
 ;;
 ;;   Return a menu keymap, the items in the keymap will appear at the
 ;;   end of the VC Status menu.  The goal is to allow backends to
 ;;   `diff-add-change-log-entries-other-window' to create a detailed
 ;;   skeleton for the log...
 ;;
-;; - The *vc-dir* buffer needs to be updated properly after VC
-;;   operations on directories that change the file VC state.
-;;
 ;; - most vc-dir backends need more work.  They might need to
 ;;   provide custom headers, use the `extra' field and deal with all
 ;;   possible VC states.
 ;;   vc-dir, it is possible that these commands are called
 ;;   for unregistered/ignored files.
 ;;
-;; - Using multiple backends needs work.  Given a CVS directory with some
-;;   files checked into git (but not all), using C-x v l to get a log file
-;;   from a file only present in git, and then typing RET on some log entry,
-;;   vc will bombs out because it wants to see the file being in CVS.
-;;   Those logs should likely use a local variable to hardware the VC they
-;;   are supposed to work with.
+;; - vc-next-action needs work in order to work with multiple
+;;   backends: `vc-state' returns the state for the default backend,
+;;   not for the backend in the current *vc-dir* buffer.
 ;;
-;;;; Problems:
+;; - vc-dir-kill-dir-status-process should not be specific to dir-status,
+;;   it should work for other async commands done through vc-do-command
+;;   as well,
 ;;
-;; - the *vc-dir* buffer is not updated correctly anymore after VC
-;;   operations that change the file state.
+;; - vc-dir toolbar needs more icons.
+;;
+;; - The backends should avoid using `vc-file-setprop' and `vc-file-getprop'.
 ;;
 ;;; Code:
 
 (require 'vc-hooks)
 (require 'vc-dispatcher)
-(require 'tool-bar)
-(require 'ewoc)
 
 (eval-when-compile
   (require 'cl))
@@ -711,21 +697,22 @@ These are passed to the checkin program by \\[vc-register]."
 
 (defcustom vc-diff-switches nil
   "A string or list of strings specifying switches for diff under VC.
-When running diff under a given BACKEND, VC concatenates the values of
-`diff-switches', `vc-diff-switches', and `vc-BACKEND-diff-switches' to
-get the switches for that command.  Thus, `vc-diff-switches' should
-contain switches that are specific to version control, but not
-specific to any particular backend."
-  :type '(choice (const :tag "None" nil)
+When running diff under a given BACKEND, VC uses the first
+non-nil value of `vc-BACKEND-diff-switches', `vc-diff-switches',
+and `diff-switches', in that order.  Since nil means to check the
+next variable in the sequence, either of the first two may use
+the value t to mean no switches at all.  `vc-diff-switches'
+should contain switches that are specific to version control, but
+not specific to any particular backend."
+  :type '(choice (const :tag "Unspecified" nil)
+                (const :tag "None" t)
                 (string :tag "Argument String")
-                (repeat :tag "Argument List"
-                        :value ("")
-                        string))
+                (repeat :tag "Argument List" :value ("") string))
   :group 'vc
   :version "21.1")
 
 (defcustom vc-diff-knows-L nil
-  "*Indicates whether diff understands the -L option.
+  "Indicates whether diff understands the -L option.
 The value is either `yes', `no', or nil.  If it is nil, VC tries
 to use -L and sets this variable to remember whether it worked."
   :type '(choice (const :tag "Work out" nil) (const yes) (const no))
@@ -768,7 +755,7 @@ See `run-hooks'."
 (defcustom vc-static-header-alist
   '(("\\.c\\'" .
      "\n#ifndef lint\nstatic char vcid[] = \"\%s\";\n#endif /* lint */\n"))
-  "*Associate static header string templates with file types.
+  "Associate static header string templates with file types.
 A \%s in the template is replaced with the first string associated with
 the file's version control type in `vc-header-alist'."
   :type '(repeat (cons :format "%v"
@@ -778,7 +765,7 @@ the file's version control type in `vc-header-alist'."
 
 (defcustom vc-comment-alist
   '((nroff-mode ".\\\"" ""))
-  "*Special comment delimiters for generating VC headers.
+  "Special comment delimiters for generating VC headers.
 Add an entry in this list if you need to override the normal `comment-start'
 and `comment-end' variables.  This will only be necessary if the mode language
 is sensitive to blank lines."
@@ -789,7 +776,7 @@ is sensitive to blank lines."
   :group 'vc)
 
 (defcustom vc-checkout-carefully (= (user-uid) 0)
-  "*Non-nil means be extra-careful in checkout.
+  "Non-nil means be extra-careful in checkout.
 Verify that the file really is not locked
 and that its contents match what the master file says."
   :type 'boolean
@@ -886,8 +873,7 @@ Within directories, only files already under version control are noticed."
          (vc-parent-buffer (vc-derived-from-dir-mode vc-parent-buffer))
          (t nil))))
 
-(defvar vc-dir-backend nil
-  "The backend used by the current *vc-dir* buffer.")
+(defvar vc-dir-backend)
 
 ;; FIXME: this is not functional, commented out.
 ;; (defun vc-deduce-fileset (&optional observer)
@@ -906,33 +892,39 @@ Within directories, only files already under version control are noticed."
 ;;                     (vc-backend (car cooked)))))
 ;;     (cons backend selection)))
 
-(defun vc-deduce-fileset (&optional observer allow-unregistered only-files)
+(declare-function vc-dir-current-file "vc-dir" ())
+(declare-function vc-dir-deduce-fileset "vc-dir" (&optional state-model-only-files))
+
+(defun vc-deduce-fileset (&optional observer allow-unregistered
+                                   state-model-only-files)
   "Deduce a set of files and a backend to which to apply an operation.
 
-Return (BACKEND FILESET FILESET-ONLY-FILES).
+Return (BACKEND FILESET FILESET-ONLY-FILES STATE CHECKOUT-MODEL).
 If we're in VC-dir mode, the fileset is the list of marked files.
 Otherwise, if we're looking at a buffer visiting a version-controlled file,
 the fileset is a singleton containing this file.
 If none of these conditions is met, but ALLOW_UNREGISTERED is on and the
 visited file is not registered, return a singleton fileset containing it.
 Otherwise, throw an error.
-ONLY-FILES if non-nil, means that the caller needs to FILESET-ONLY-FILES
-info.  Otherwise, that part may be skipped.
-BEWARE: this function may change the current buffer."
+
+STATE-MODEL-ONLY-FILES if non-nil, means that the caller needs
+the FILESET-ONLY-FILES STATE and MODEL info.  Otherwise, that
+part may be skipped.
+BEWARE: this function may change the
+current buffer."
   ;; FIXME: OBSERVER is unused.  The name is not intuitive and is not
   ;; documented.  It's set to t when called from diff and print-log.
   (let (backend)
     (cond
      ((derived-mode-p 'vc-dir-mode)
-      (let ((marked (vc-dir-marked-files)))
-       (if marked
-           (list vc-dir-backend marked
-                  (if only-files (vc-dir-marked-only-files)))
-         (let ((crt (vc-dir-current-file)))
-           (list vc-dir-backend (list crt)
-                  (if only-files (vc-dir-child-files)))))))
+      (vc-dir-deduce-fileset state-model-only-files))
      ((setq backend (vc-backend buffer-file-name))
-      (list backend (list buffer-file-name) (list buffer-file-name)))
+      (if state-model-only-files
+       (list backend (list buffer-file-name)
+             (list buffer-file-name)
+             (vc-state buffer-file-name)
+             (vc-checkout-model backend buffer-file-name))
+       (list backend (list buffer-file-name))))
      ((and (buffer-live-p vc-parent-buffer)
            ;; FIXME: Why this test?  --Stef
            (or (buffer-file-name vc-parent-buffer)
@@ -940,19 +932,26 @@ BEWARE: this function may change the current buffer."
                                  (eq major-mode 'vc-dir-mode))))
       (progn                  ;FIXME: Why not `with-current-buffer'? --Stef.
        (set-buffer vc-parent-buffer)
-       (vc-deduce-fileset observer allow-unregistered only-files)))
+       (vc-deduce-fileset observer allow-unregistered state-model-only-files)))
      ((not buffer-file-name)
        (error "Buffer %s is not associated with a file" (buffer-name)))
      ((and allow-unregistered (not (vc-registered buffer-file-name)))
-      (list (vc-responsible-backend
-            (file-name-directory (buffer-file-name)))
-           (list buffer-file-name) (list buffer-file-name)))
+      (if state-model-only-files
+         (list (vc-responsible-backend
+                (file-name-directory (buffer-file-name)))
+               (list buffer-file-name)
+               (list buffer-file-name)
+               (when state-model-only-files 'unregistered)
+               nil)
+       (list (vc-responsible-backend
+              (file-name-directory (buffer-file-name)))
+             (list buffer-file-name))))
      (t (error "No fileset is available here.")))))
 
 (defun vc-ensure-vc-buffer ()
   "Make sure that the current buffer visits a version-controlled file."
   (cond
-   ((vc-dispatcher-browsing)
+   ((derived-mode-p 'vc-dir-mode)
     (set-buffer (find-file-noselect (vc-dir-current-file))))
    (t
     (while (and vc-parent-buffer
@@ -1017,27 +1016,17 @@ with the logmessage as change commentary.  A writable file is retained.
    If the repository file is changed, you are asked if you want to
 merge in the changes into your working copy."
   (interactive "P")
-  (let* ((vc-fileset (vc-deduce-fileset nil t 'only-files))
+  (let* ((vc-fileset (vc-deduce-fileset nil t 'state-model-only-files))
          (backend (car vc-fileset))
         (files (nth 1 vc-fileset))
          (fileset-only-files (nth 2 vc-fileset))
          ;; FIXME: We used to call `vc-recompute-state' here.
-         (state (vc-state (car fileset-only-files)))
+         (state (nth 3 vc-fileset))
          ;; The backend should check that the checkout-model is consistent
          ;; among all the `files'.
-        (model
-         ;; FIXME: This is not very elegant...
-         (when (and state (not (eq state 'unregistered)))
-           (vc-checkout-model backend files)))
+        (model (nth 4 vc-fileset))
         revision)
 
-    ;; Check that all files are in a consistent state, since we use that
-    ;; state to decide which operation to perform.
-    (dolist (file (cdr fileset-only-files))
-      (unless (vc-compatible-state (vc-state file) state)
-        (error "%s:%s clashes with %s:%s"
-               file (vc-state file) (car fileset-only-files) state)))
-
     ;; Do the right thing
     (cond
      ((eq state 'missing)
@@ -1091,7 +1080,7 @@ merge in the changes into your working copy."
                         ;; finishing the log entry and committing.
                         (not (and visited (buffer-modified-p))))
                (vc-revert-file file)
-               (delete file ready-for-commit)))))
+               (setq ready-for-commit (delete file ready-for-commit))))))
        ;; Remaining files need to be committed
        (if (not ready-for-commit)
            (message "No files remain to be committed")
@@ -1298,11 +1287,18 @@ After check-out, runs the normal hook `vc-checkout-hook'."
   (run-hooks 'vc-checkout-hook))
 
 (defun vc-mark-resolved (backend files)
-  (with-vc-properties
-   files
-   (vc-call-backend backend 'mark-resolved files)
-   ;; XXX: Is this TRTD?  Might not be.
-   `((vc-state . edited))))
+  (prog1 (with-vc-properties
+         files
+         (vc-call-backend backend 'mark-resolved files)
+         ;; FIXME: Is this TRTD?  Might not be.
+         `((vc-state . edited)))
+    (message
+     (substitute-command-keys
+      "Conflicts have been resolved in %s.  \
+Type \\[vc-next-action] to check in changes.")
+     (if (> (length files) 1)
+        (format "%d files" (length files))
+       "this file"))))
 
 (defun vc-steal-lock (file rev owner)
   "Steal the lock on FILE."
@@ -1403,6 +1399,18 @@ Runs the normal hooks `vc-before-checkin-hook' and `vc-checkin-hook'."
       'undecided))
 
 (defun vc-switches (backend op)
+  "Return a list of vc-BACKEND switches for operation OP.
+BACKEND is a symbol such as `CVS', which will be downcased.
+OP is a symbol such as `diff'.
+
+In decreasing order of preference, return the value of:
+vc-BACKEND-OP-switches (e.g. `vc-cvs-diff-switches');
+vc-OP-switches (e.g. `vc-diff-switches'); or, in the case of
+diff only, `diff-switches'.
+
+If the chosen value is not a string or a list, return nil.
+This is so that you may set, e.g. `vc-svn-diff-switches' to t in order
+to override the value of `vc-diff-switches' and `diff-switches'."
   (let ((switches
         (or (when backend
               (let ((sym (vc-make-backend-sym
@@ -1751,259 +1759,6 @@ See Info node `Merging'."
 ;;;###autoload
 (defalias 'vc-resolve-conflicts 'smerge-ediff)
 
-;; VC status implementation
-
-(defun vc-default-status-extra-headers (backend dir)
-  ;; Be loud by default to remind people to add code to display
-  ;; backend specific headers.
-  ;; XXX: change this to return nil before the release.
-  (concat
-   (propertize "Extra      : " 'face 'font-lock-type-face)
-   (propertize "Please add backend specific headers here.  It's easy!"
-              'face 'font-lock-warning-face)))
-
-(defun vc-dir-headers (backend dir)
-  "Display the headers in the *VC dir* buffer.
-It calls the `status-extra-headers' backend method to display backend
-specific headers."
-  (concat
-   (propertize "VC backend : " 'face 'font-lock-type-face)
-   (propertize (format "%s\n" backend) 'face 'font-lock-variable-name-face)
-   (propertize "Working dir: " 'face 'font-lock-type-face)
-   (propertize (format "%s\n" dir) 'face 'font-lock-variable-name-face)
-   (vc-call-backend backend 'status-extra-headers dir)
-   "\n"))
-
-(defun vc-default-status-printer (backend fileentry)
-  "Pretty print FILEENTRY."
-  ;; If you change the layout here, change vc-dir-move-to-goal-column.
-  (let* ((isdir (vc-dir-fileinfo->directory fileentry))
-       (state (if isdir 'DIRECTORY (vc-dir-fileinfo->state fileentry)))
-       (filename (vc-dir-fileinfo->name fileentry)))
-    ;; FIXME: Backends that want to print the state in a different way
-    ;; can do it by defining the `status-printer' function.  Using
-    ;; `prettify-state-info' adds two extra vc-calls per item, which
-    ;; is too expensive.
-    ;;(prettified (if isdir state (vc-call-backend backend 'prettify-state-info filename))))
-    (insert
-     (propertize
-      (format "%c" (if (vc-dir-fileinfo->marked fileentry) ?* ? ))
-      'face 'font-lock-type-face)
-     "   "
-     (propertize
-      (format "%-20s" state)
-      'face (cond ((eq state 'up-to-date) 'font-lock-builtin-face)
-                 ((memq state '(missing conflict)) 'font-lock-warning-face)
-                 (t 'font-lock-variable-name-face))
-      'mouse-face 'highlight)
-     " "
-     (propertize
-      (format "%s" filename)
-      'face 'font-lock-function-name-face
-      'mouse-face 'highlight))))
-
-(defun vc-default-extra-status-menu (backend)
-  nil)
-
-(defun vc-dir-refresh-files (files default-state)
-  "Refresh some files in the *VC-dir* buffer."
-  (let ((def-dir default-directory)
-       (backend vc-dir-backend))
-    (vc-set-mode-line-busy-indicator)
-    ;; Call the `dir-status-file' backend function.
-    ;; `dir-status-file' is supposed to be asynchronous.
-    ;; It should compute the results, and then call the function
-    ;; passed as an argument in order to update the vc-dir buffer
-    ;; with the results.
-    (unless (buffer-live-p vc-dir-process-buffer)
-      (setq vc-dir-process-buffer
-            (generate-new-buffer (format " *VC-%s* tmp status" backend))))
-    (lexical-let ((buffer (current-buffer)))
-      (with-current-buffer vc-dir-process-buffer
-        (cd def-dir)
-        (erase-buffer)
-        (vc-call-backend
-         backend 'dir-status-files def-dir files default-state
-         (lambda (entries &optional more-to-come)
-           ;; ENTRIES is a list of (FILE VC_STATE EXTRA) items.
-           ;; If MORE-TO-COME is true, then more updates will come from
-           ;; the asynchronous process.
-           (with-current-buffer buffer
-             (vc-dir-update entries buffer)
-             (unless more-to-come
-               (setq mode-line-process nil)
-               ;; Remove the ones that haven't been updated at all.
-               ;; Those not-updated are those whose state is nil because the
-               ;; file/dir doesn't exist and isn't versioned.
-               (ewoc-filter vc-ewoc
-                            (lambda (info)
-                             ;; The state for directory entries might
-                             ;; have been changed to 'up-to-date,
-                             ;; reset it, othewise it will be removed when doing 'x'
-                             ;; next time.
-                             ;; FIXME: There should be a more elegant way to do this.
-                             (when (and (vc-dir-fileinfo->directory info)
-                                        (eq (vc-dir-fileinfo->state info)
-                                            'up-to-date))
-                               (setf (vc-dir-fileinfo->state info) nil))
-
-                              (not (vc-dir-fileinfo->needs-update info))))))))))))
-
-(defun vc-dir-refresh ()
-  "Refresh the contents of the *VC-dir* buffer.
-Throw an error if another update process is in progress."
-  (interactive)
-  (if (vc-dir-busy)
-      (error "Another update process is in progress, cannot run two at a time")
-    (let ((def-dir default-directory)
-         (backend vc-dir-backend))
-      (vc-set-mode-line-busy-indicator)
-      ;; Call the `dir-status' backend function.
-      ;; `dir-status' is supposed to be asynchronous.
-      ;; It should compute the results, and then call the function
-      ;; passed as an argument in order to update the vc-dir buffer
-      ;; with the results.
-
-      ;; Create a buffer that can be used by `dir-status' and call
-      ;; `dir-status' with this buffer as the current buffer.  Use
-      ;; `vc-dir-process-buffer' to remember this buffer, so that
-      ;; it can be used later to kill the update process in case it
-      ;; takes too long.
-      (unless (buffer-live-p vc-dir-process-buffer)
-        (setq vc-dir-process-buffer
-              (generate-new-buffer (format " *VC-%s* tmp status" backend))))
-      ;; set the needs-update flag on all entries
-      (ewoc-map (lambda (info) (setf (vc-dir-fileinfo->needs-update info) t) nil)
-                vc-ewoc)
-      (lexical-let ((buffer (current-buffer)))
-        (with-current-buffer vc-dir-process-buffer
-          (cd def-dir)
-          (erase-buffer)
-          (vc-call-backend
-           backend 'dir-status def-dir
-           (lambda (entries &optional more-to-come)
-             ;; ENTRIES is a list of (FILE VC_STATE EXTRA) items.
-             ;; If MORE-TO-COME is true, then more updates will come from
-             ;; the asynchronous process.
-             (with-current-buffer buffer
-               (vc-dir-update entries buffer)
-               (unless more-to-come
-                 (let ((remaining
-                        (ewoc-collect
-                         vc-ewoc 'vc-dir-fileinfo->needs-update)))
-                   (if remaining
-                       (vc-dir-refresh-files
-                        (mapcar 'vc-dir-fileinfo->name remaining)
-                        'up-to-date)
-                     (setq mode-line-process nil))))))))))))
-
-(defun vc-dir-show-fileentry (file)
-  "Insert an entry for a specific file into the current *VC-dir* listing.
-This is typically used if the file is up-to-date (or has been added
-outside of VC) and one wants to do some operation on it."
-  (interactive "fShow file: ")
-  (vc-dir-update (list (list (file-relative-name file) (vc-state file))) (current-buffer)))
-
-(defun vc-dir-hide-up-to-date ()
-  "Hide up-to-date items from display."
-  (interactive)
-  (ewoc-filter
-   vc-ewoc
-   (lambda (crt) (not (eq (vc-dir-fileinfo->state crt) 'up-to-date)))))
-
-(defun vc-default-status-fileinfo-extra (backend file)
-  "Default absence of extra information returned for a file."
-  nil)
-
-;; FIXME: Replace these with a more efficient dispatch
-
-(defun vc-generic-status-printer (fileentry)
-  (vc-call-backend vc-dir-backend 'status-printer fileentry))
-
-(defun vc-generic-state (file)
-  (vc-call-backend vc-dir-backend 'state file))
-
-(defun vc-generic-status-fileinfo-extra (file)
-  (vc-call-backend vc-dir-backend 'status-fileinfo-extra file))
-
-(defun vc-dir-extra-menu ()
-  (vc-call-backend vc-dir-backend 'extra-status-menu))
-
-(defun vc-make-backend-object (file-or-dir)
-  "Create the backend capability object needed by vc-dispatcher."
-  (vc-create-client-object
-   "VC dir"
-   (vc-dir-headers vc-dir-backend file-or-dir)
-   #'vc-generic-status-printer
-   #'vc-generic-state
-   #'vc-generic-status-fileinfo-extra
-   #'vc-dir-refresh
-   #'vc-dir-extra-menu))
-
-;;;###autoload
-(defun vc-dir (dir)
-  "Show the VC status for DIR."
-  (interactive "DVC status for directory: ")
-  (pop-to-buffer (vc-dir-prepare-status-buffer "*vc-dir*" dir))
-  (if (and (derived-mode-p 'vc-dir-mode) (boundp 'client-object))
-      (vc-dir-refresh)
-    ;; Otherwise, initialize a new view using the dispatcher layer
-    (progn
-      (set (make-local-variable 'vc-dir-backend) (vc-responsible-backend dir))
-      ;; Build a capability object and hand it to the dispatcher initializer
-      (vc-dir-mode (vc-make-backend-object dir))
-      ;; FIXME: Make a derived-mode instead.
-      ;; Add VC-specific keybindings
-      (let ((map (current-local-map)))
-       (define-key map "v" 'vc-next-action) ;; C-x v v
-       (define-key map "=" 'vc-diff)        ;; C-x v =
-       (define-key map "i" 'vc-register)    ;; C-x v i
-       (define-key map "+" 'vc-update)      ;; C-x v +
-       (define-key map "l" 'vc-print-log)   ;; C-x v l
-       ;; More confusing than helpful, probably
-       ;(define-key map "R" 'vc-revert) ;; u is taken by dispatcher unmark.
-       ;(define-key map "A" 'vc-annotate) ;; g is taken by dispatcher refresh
-       (define-key map "x" 'vc-dir-hide-up-to-date))
-      )
-    ;; FIXME: Needs to alter a buffer-local map, otherwise clients may clash
-    (let ((map vc-dir-menu-map))
-    ;; VC info details
-    (define-key map [sepvcdet] '("--"))
-    (define-key map [remup]
-      '(menu-item "Hide up-to-date" vc-dir-hide-up-to-date
-                 :help "Hide up-to-date items from display"))
-    ;; FIXME: This needs a key binding.  And maybe a better name
-    ;; ("Insert" like PCL-CVS uses does not sound that great either)...
-    (define-key map [ins]
-      '(menu-item "Show File" vc-dir-show-fileentry
-                 :help "Show a file in the VC status listing even though it might be up to date"))
-    (define-key map [annotate]
-      '(menu-item "Annotate" vc-annotate
-                 :help "Display the edit history of the current file using colors"))
-    (define-key map [diff]
-      '(menu-item "Compare with Base Version" vc-diff
-                 :help "Compare file set with the base version"))
-    (define-key map [log]
-     '(menu-item "Show history" vc-print-log
-     :help "List the change log of the current file set in a window"))
-    ;; VC commands.
-    (define-key map [sepvccmd] '("--"))
-    (define-key map [update]
-      '(menu-item "Update to latest version" vc-update
-                 :help "Update the current fileset's files to their tip revisions"))
-    (define-key map [revert]
-      '(menu-item "Revert to base version" vc-revert
-                 :help "Revert working copies of the selected fileset to their repository contents."))
-    (define-key map [next-action]
-      ;; FIXME: This really really really needs a better name!
-      ;; And a key binding too.
-      '(menu-item "Check In/Out" vc-next-action
-                 :help "Do the next logical version control operation on the current fileset"))
-    (define-key map [register]
-      '(menu-item "Register" vc-dir-register
-                 :help "Register file set into the version control system"))
-    )))
-
 ;; Named-configuration entry points
 
 (defun vc-tag-precondition (dir)
@@ -2114,7 +1869,12 @@ to the working revision (except for keyword expansion)."
        (unless (yes-or-no-p (format "%s seems up-to-date.  Revert anyway? " file))
          (error "Revert canceled"))))
     (when (vc-diff-internal vc-allow-async-revert vc-fileset nil nil)
-      (unless (yes-or-no-p (format "Discard changes in %s? " (vc-delistify files)))
+      (unless (yes-or-no-p
+              (format "Discard changes in %s? "
+                      (let ((str (vc-delistify files)))
+                        (if (< (length str) 50)
+                            str
+                          (format "%d files" (length files))))))
        (error "Revert canceled"))
       (delete-windows-on "*vc-diff*")
       (kill-buffer "*vc-diff*"))
@@ -2502,6 +2262,9 @@ log entries should be gathered."
   (string-match "[0-9]+\\'" rev)
   (substring rev (match-beginning 0) (match-end 0)))
 
+(define-obsolete-function-alias
+  'vc-default-previous-version 'vc-default-previous-revision "23.1")
+
 (defun vc-default-previous-revision (backend file rev)
   "Return the revision number immediately preceding REV for FILE,
 or nil if there is no previous revision.  This default
@@ -2714,6 +2477,7 @@ to provide the `find-revision' operation instead."
       (message "Checking out %s...done" file))))
 
 (defalias 'vc-default-revision-completion-table 'ignore)
+(defalias 'vc-default-mark-resolved 'ignore)
 
 (defun vc-default-dir-status-files (backend dir files default-state update-function)
   (funcall update-function
@@ -2728,6 +2492,11 @@ to provide the `find-revision' operation instead."
 
 ;; These things should probably be generally available
 
+(defun vc-string-prefix-p (prefix string)
+  (let ((lpref (length prefix)))
+    (and (>= (length string) lpref)
+        (eq t (compare-strings prefix nil nil string nil lpref)))))
+
 (defun vc-file-tree-walk (dirname func &rest args)
   "Walk recursively through DIRNAME.
 Invoke FUNC f ARGS on each VC-managed file f underneath it."