;; This mode is fully documented in the Emacs user's manual.
;;
;; Supported version-control systems presently include CVS, RCS, GNU
-;; Arch, Subversion, Bzr, Git, Mercurial, Meta-CVS, Monotone and SCCS
+;; Arch, Subversion, Bzr, Git, Mercurial, Monotone and SCCS
;; (or its free replacement, CSSC).
;;
;; Some features will not work with old RCS versions. Where
;; reliable state computation; it is usually called immediately after
;; C-x v v. If you want to use a faster heuristic when visiting a
;; file, put that into `state-heuristic' below. Note that under most
-;; VCSes this won't be called at all, dir-state or dir-stus is used instead.
+;; VCSes this won't be called at all, dir-status is used instead.
;;
;; - state-heuristic (file)
;;
;; than the implementation of `state'. For a list of possible values,
;; see the doc string of `vc-state'.
;;
-;; - dir-state (dir)
-;;
-;; If provided, this function is used to find the version control
-;; state of as many files as possible in DIR, and all subdirectories
-;; of DIR, in a fast way; it is used to avoid expensive indivitual
-;; vc-state calls. The function should not return anything, but
-;; rather store the files' states into the corresponding properties.
-;; Two properties are required: `vc-backend' and `vc-state'. (Note:
-;; in older versions this method was not required to recurse into
-;; subdirectories.)
-;;
;; - dir-status (dir update-function)
;;
;; Produce RESULT: a list of lists of the form (FILE VC-STATE EXTRA)
;; and make sure it is displayed in the buffer's window. The default
;; implementation of this function works for RCS-style logs.
;;
-;; - wash-log (file)
-;;
-;; Remove all non-comment information from the output of print-log.
-;;
;; - comment-history (file)
;;
;; Return a string containing all log entries that were made for FILE.
;; This is used for transferring a file from one backend to another,
-;; retaining comment information. The default implementation of this
-;; function does this by calling print-log and then wash-log, and
-;; returning the resulting buffer contents as a string.
+;; retaining comment information.
;;
;; - update-changelog (files)
;;
;;; Todo:
-;; - vc-update/vc-merge should deal with VC systems that don't
-;; update/merge on a file basis, but on a whole repository basis.
+;;;; New Primitives:
;;
;; - deal with push/pull operations.
;;
-;; - "snapshots" should be renamed to "branches", and thoroughly reworked.
+;; - add a mechanism for editing the underlying VCS's list of files
+;; to be ignored, when that's possible.
;;
-;; - when a file is in `conflict' state, turn on smerge-mode.
+;;;; Primitives that need changing:
;;
-;; - figure out what to do with conflicts that are not caused by the
-;; file contents, but by metadata or other causes. Example: File A
-;; gets renamed to B in one branch and to C in another and you merge
-;; the two branches. Or you locally add file FOO and then pull a
-;; change that also adds a new file FOO, ...
+;; - vc-update/vc-merge should deal with VC systems that don't
+;; update/merge on a file basis, but on a whole repository basis.
+;; vc-update and vc-merge assume the arguments are always files,
+;; they don't deal with directories. Make sure the *vc-dir* buffer
+;; is updated after these operations.
+;; At least bzr, git and hg should benefit from this.
+;;
+;;;; Improved branch and tag handling:
+;;
+;; - "snapshots" should be renamed to "tags", and thoroughly reworked.
;;
;; - add a generic mechanism for remembering the current branch names,
;; display the branch name in the mode-line. Replace
;; adapted accordingly. Also, it considers RCS and CVS to be the same,
;; which is pretty confusing.
;;
+;; - vc-create-snapshot and vc-retrieve-snapshot should update the
+;; buffers that might be visiting the affected files.
+;;
+;;;; Default Behavior:
+;;
+;; - do not default to RCS anymore when the current directory is not
+;; controlled by any VCS and the user does C-x v v
+;;
+;; - vc-responsible-backend should not return RCS if no backend
+;; declares itself responsible.
+;;
+;;;; Internal cleanups:
+;;
+;; - backends that care about vc-stay-local should try to take it into
+;; account for vc-dir. Is this likely to be useful???
+;;
+;; - vc-expand-dirs should take a backend parameter and only look for
+;; files managed by that backend.
+;;
+;; - Another important thing: merge all the status-like backend operations.
+;; We should remove dir-status, state, and dir-status-files, and
+;; replace them with just `status' which takes a fileset and a continuation
+;; (like dir-status) and returns a buffer in which the process(es) are run
+;; (or nil if it worked synchronously). Hopefully we can define the old
+;; 4 operations in term of this one.
+;;
+;;;; Other
+;;
+;; - when a file is in `conflict' state, turn on smerge-mode.
+;;
+;; - figure out what to do with conflicts that are not caused by the
+;; file contents, but by metadata or other causes. Example: File A
+;; gets renamed to B in one branch and to C in another and you merge
+;; the two branches. Or you locally add file FOO and then pull a
+;; change that also adds a new file FOO, ...
+;;
;; - vc-diff should be able to show the diff for all files in a
;; changeset, especially for VC systems that have per repository
;; version numbers. log-view should take advantage of this.
;; - make it easier to write logs. Maybe C-x 4 a should add to the log
;; buffer, if one is present, instead of adding to the ChangeLog.
;;
-;; - add a mechanism for editing the underlying VCS's list of files
-;; to be ignored, when that's possible.
-;;
;; - When vc-next-action calls vc-checkin it could pre-fill the
;; *VC-log* buffer with some obvious items: the list of files that
;; were added, the list of files that were removed. If the diff is
;; `diff-add-change-log-entries-other-window' to create a detailed
;; skeleton for the log...
;;
-;; - a way to do repository wide log (instead of just per
-;; file/fileset) is needed. Doing it per directory might be enough...
-;;
;; - 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.
;;
-;; - add function that calls vc-dir to `find-directory-functions'.
+;; - add a function that calls vc-dir to `find-directory-functions'.
;;
;; - vc-diff, vc-annotate, etc. need to deal better with unregistered
;; files. Now that unregistered and ignored files are shown in
-;; vc-dired/vc-dir, it is possible that these commands are called
+;; vc-dir, it is possible that these commands are called
;; for unregistered/ignored files.
;;
-;; - do not default to RCS anymore when the current directory is not
-;; controlled by any VCS and the user does C-x v v
-;;
-;; - vc-create-snapshot and vc-retrieve-snapshot should update the
-;; buffers that might be visiting the affected 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,
;; Those logs should likely use a local variable to hardware the VC they
;; are supposed to work with.
;;
-;; - Another important thing: merge all the status-like backend operations.
-;; We should remove dir-status, state, dir-state, and dir-status-files, and
-;; replace them with just `status' which takes a fileset and a continuation
-;; (like dir-status) and returns a buffer in which the process(es) are run
-;; (or nil if it worked synchronously). Hopefully we can define the old
-;; 4 operations in term of this one.
-;;
-;; - backends that care about vc-stay-local should try to take it into
-;; account for vc-dir. Is this likely to be useful???
-;;
-;; - vc-dir listing needs a footer generated when it's done to make it obvious
-;; that it has finished.
-;;
;;; Code:
(require 'ewoc)
(eval-when-compile
- (require 'dired)
- (require 'dired-aux)
(require 'cl))
(unless (assoc 'vc-parent-buffer minor-mode-alist)
(put (intern file vc-file-prop-obarray)
property (cdr setting))))))))
-;; Two macros for elisp programming
-
-;;;###autoload
-(defmacro with-vc-file (file comment &rest body)
- "Check out a writable copy of FILE if necessary, then execute BODY.
-Check in FILE with COMMENT (a string) after BODY has been executed.
-FILE is passed through `expand-file-name'; BODY executed within
-`save-excursion'. If FILE is not under version control, or you are
-using a locking version-control system and the file is locked by
-somebody else, signal error."
- (declare (debug t) (indent 2))
- (let ((filevar (make-symbol "file")))
- `(let ((,filevar (expand-file-name ,file)))
- (or (vc-backend ,filevar)
- (error "File not under version control: `%s'" file))
- (unless (vc-editable-p ,filevar)
- (let ((state (vc-state ,filevar)))
- (if (stringp state)
- (error "`%s' is locking `%s'" state ,filevar)
- (vc-checkout ,filevar t))))
- (save-excursion
- ,@body)
- (vc-checkin (list ,filevar) nil ,comment))))
-
-;;;###autoload
-(defmacro edit-vc-file (file comment &rest body)
- "Edit FILE under version control, executing body.
-Checkin with COMMENT after executing BODY.
-This macro uses `with-vc-file', passing args to it.
-However, before executing BODY, find FILE, and after BODY, save buffer."
- (declare (debug t) (indent 2))
- (let ((filevar (make-symbol "file")))
- `(let ((,filevar (expand-file-name ,file)))
- (with-vc-file
- ,filevar ,comment
- (set-buffer (find-file-noselect ,filevar))
- ,@body
- (save-buffer)))))
-
;;; Code for deducing what fileset and backend to assume
(defun vc-responsible-backend (file &optional register)
(defun vc-expand-dirs (file-or-dir-list)
"Expands directories in a file list specification.
-Only files already under version control are noticed."
- ;; FIXME: Kill this function.
+Within directories, only files already under version control are noticed."
(let ((flattened '()))
(dolist (node file-or-dir-list)
- (vc-file-tree-walk
- node (lambda (f) (when (vc-backend f) (push f flattened)))))
+ (if (file-directory-p node)
+ (vc-file-tree-walk
+ node (lambda (f) (when (vc-backend f) (push f flattened)))))
+ (push node flattened))
(nreverse flattened)))
-(defun vc-deduce-fileset (&optional allow-directory-wildcard allow-unregistered
- include-files-not-directories)
- "Deduce a set of files and a backend to which to apply an operation.
-Return (BACKEND . FILESET)."
- (let* ((fileset (vc-dispatcher-selection-set
- #'vc-registered
- allow-directory-wildcard
- allow-unregistered
- include-files-not-directories))
- (backend (vc-backend (car fileset))))
- ;; All members of the fileset must have the same backend
- (dolist (f (cdr fileset))
- (unless (eq (vc-backend f) backend)
- (error "All members of a fileset must be under the same version-control system.")))
- (cons backend fileset)))
+(defun vc-derived-from-dir-mode (&optional buffer)
+ "Are we in a VC-directory buffer, or do we have one as an ancestor?"
+ (let ((buffer (or buffer (current-buffer))))
+ (cond ((derived-mode-p 'vc-dir-mode) t)
+ (vc-parent-buffer (vc-derived-from-dir-mode vc-parent-buffer))
+ (t nil))))
+
+(defun vc-deduce-fileset (&optional observer)
+ "Deduce a set of files and a backend to which to apply an operation and
+the common state of the fileset. Return (BACKEND . FILESET)."
+ (let* ((selection (vc-dispatcher-selection-set observer))
+ (raw (car selection)) ;; Selection as user made it
+ (cooked (cdr selection)) ;; Files only
+ ;; FIXME: Store the backend in a buffer-local variable.
+ (backend (if (vc-derived-from-dir-mode (current-buffer))
+ (vc-responsible-backend default-directory)
+ (assert (and (= 1 (length raw))
+ (not (file-directory-p (car raw)))))
+ (vc-backend (car cooked)))))
+ (cons backend selection)))
(defun vc-ensure-vc-buffer ()
"Make sure that the current buffer visits a version-controlled file."
(cond
- (vc-dired-mode
- (set-buffer (find-file-noselect (dired-get-filename))))
- ((eq major-mode 'vc-dir-mode)
+ ((vc-dispatcher-browsing)
(set-buffer (find-file-noselect (vc-dir-current-file))))
(t
(while (and vc-parent-buffer
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))
- (vc-fileset-only-files (vc-deduce-fileset nil t t))
- (only-files (cdr vc-fileset-only-files))
+ (let* ((vc-fileset (vc-deduce-fileset))
(backend (car vc-fileset))
- (files (cdr vc-fileset))
- (state (vc-state (car only-files)))
+ (files (cadr vc-fileset))
+ (fileset-only-files (cddr vc-fileset))
+ ;; FIXME: We used to call `vc-recompute-state' here.
+ (state (vc-state (car fileset-only-files)))
+ ;; The backend should check that the checkout-model is consistent
+ ;; among all the `files'.
(model (vc-checkout-model backend files))
revision)
- ;; Verify that the fileset is homogeneous
- (dolist (file (cdr only-files))
- ;; Ignore directories, they are compatible with anything.
- (unless (file-directory-p file)
- (unless (vc-compatible-state (vc-state file) state)
- (error "%s:%s clashes with %s:%s"
- file (vc-state file) (car files) state))
- (unless (eq (vc-checkout-model backend (list file)) model)
- (error "Fileset has mixed checkout models"))))
+ ;; 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)
(error "Fileset files are missing, so cannot be operated on."))
- ;; Files aren't registered
- ((or (eq state 'unregistered)
- (eq state 'ignored))
+ ((eq state 'ignored)
+ (error "Fileset files are ignored by the version-control system."))
+ ((eq state 'unregistered)
(mapc (lambda (arg) (vc-register nil arg)) files))
;; Files are up-to-date, or need a merge and user specified a revision
((or (eq state 'up-to-date) (and verbose (eq state 'needs-update)))
state)))
;; conflict
((eq state 'conflict)
- (vc-mark-resolved files))
+ ;; FIXME: Is it really the UI we want to provide?
+ ;; In my experience, the conflicted files should be marked as resolved
+ ;; one-by-one when saving the file after resolving the conflicts.
+ ;; I.e. stating explicitly that the conflicts are resolved is done
+ ;; very rarely.
+ (vc-mark-resolved backend files))
;; needs-update
((eq state 'needs-update)
(dolist (file files)
(when (yes-or-no-p (format
"%s is not up-to-date. Merge in changes now? "
(file-name-nondirectory file)))
- (vc-maybe-resolve-conflicts file (vc-call merge-news file)))))
+ (vc-maybe-resolve-conflicts
+ file (vc-call-backend backend 'merge-news file)))))
;; unlocked-changes
((eq state 'unlocked-changes)
(when (not (equal buffer-file-name file))
(find-file-other-window file))
(if (save-window-excursion
- (vc-diff-internal nil (cons (car vc-fileset) (list file))
+ (vc-diff-internal nil
+ (cons (car vc-fileset) (cons (cadr vc-fileset) (list file)))
(vc-working-revision file) nil)
(goto-char (point-min))
(let ((inhibit-read-only t))
(not (beep))
(yes-or-no-p (concat "File has unlocked changes. "
"Claim lock retaining changes? ")))
- (progn (vc-call steal-lock file)
+ (progn (vc-call-backend backend 'steal-lock file)
(clear-visited-file-modtime)
;; Must clear any headers here because they wouldn't
;; show that the file is locked now.
(signal (car err) (cdr err))))
`((vc-state . ,(if (or (eq (vc-checkout-model backend (list file)) 'implicit)
(not writable))
- (if (vc-call latest-on-branch-p file)
+ (if (vc-call-backend backend 'latest-on-branch-p file)
'up-to-date
'needs-update)
'edited))
(vc-resynch-buffer file t t)
(run-hooks 'vc-checkout-hook))
-(defun vc-mark-resolved (files)
+(defun vc-mark-resolved (backend files)
(with-vc-properties
files
- (vc-call mark-resolved files)
+ (vc-call-backend backend 'mark-resolved files)
;; XXX: Is this TRTD? Might not be.
`((vc-state . edited))))
"Report diffs between two revisions of a fileset.
Diff output goes to the *vc-diff* buffer. The function
returns t if the buffer had changes, nil otherwise."
- (let* ((files (cdr vc-fileset))
+ (let* ((files (cadr vc-fileset))
(messages (cons (format "Finding changes in %s..."
(vc-delistify files))
(format "No changes between %s and %s"
"Report diffs between revisions of the fileset in the repository history."
(interactive
(let* ((vc-fileset (vc-deduce-fileset t))
- (files (cdr vc-fileset))
+ (files (cadr vc-fileset))
+ (backend (car vc-fileset))
(first (car files))
(completion-table
- (vc-call revision-completion-table files))
+ (vc-call-backend backend 'revision-completion-table files))
(rev1-default nil)
(rev2-default nil))
(cond
(setq rev1-default (vc-working-revision first)))
;; if the file is not locked, use last and previous revisions as defaults
(t
- (setq rev1-default (vc-call previous-revision first
- (vc-working-revision first)))
+ (setq rev1-default (vc-call-backend backend 'previous-revision first
+ (vc-working-revision first)))
(when (string= rev1-default "") (setq rev1-default nil))
(setq rev2-default (vc-working-revision first))))
;; construct argument list
(when (string= rev1 "") (setq rev1 nil))
(when (string= rev2 "") (setq rev2 nil))
(list files rev1 rev2))))
+ ;; All that was just so we could do argument completion!
(when (and (not rev1) rev2)
(error "Not a valid revision range."))
- (vc-diff-internal
- t (cons (car (vc-deduce-fileset t)) files) rev1 rev2 (interactive-p)))
+ ;; Yes, it's painful to call (vc-deduce-fileset) again. Alas, the
+ ;; placement rules for (interactive) don't actually leave us a choice.
+ (vc-diff-internal t (vc-deduce-fileset) rev1 rev2 (interactive-p)))
;; (defun vc-contains-version-controlled-file (dir)
;; "Return t if DIR contains a version-controlled file, nil otherwise."
working revisions. With a prefix argument HISTORIC, it reads two revision
designators specifying which revisions to compare.
-If no current fileset is available (that is, we are not in
-VC-Dired mode and the visited file of the current buffer is not
-under version control) and we're in a Dired buffer, use
-the current directory.
The optional argument NOT-URGENT non-nil means it is ok to say no to
saving the buffer."
(interactive (list current-prefix-arg t))
(if historic
(call-interactively 'vc-version-diff)
(when buffer-file-name (vc-buffer-sync not-urgent))
- (vc-diff-internal t (vc-deduce-fileset t) nil nil (interactive-p))))
-
+ (vc-diff-internal t (vc-deduce-fileset) nil nil (interactive-p))))
;;;###autoload
(defun vc-revision-other-window (rev)
(read-string (concat "Branch or revision to merge from "
"(default news on current branch): ")))
(if (string= first-revision "")
- (if (not (vc-find-backend-function backend 'merge-news))
- (error "Sorry, merging news is not implemented for %s" backend)
- (setq status (vc-call merge-news file)))
+ (setq status (vc-call-backend backend 'merge-news file))
(if (not (vc-find-backend-function backend 'merge))
(error "Sorry, merging is not implemented for %s" backend)
(if (not (vc-branch-p first-revision))
(setq second-revision first-revision)
;; first-revision must be the starting point of the branch
(setq first-revision (vc-branch-part first-revision)))
- (setq status (vc-call merge file first-revision second-revision))))
+ (setq status (vc-call-backend backend 'merge file
+ first-revision second-revision))))
(vc-maybe-resolve-conflicts file status "WORKFILE" "MERGE SOURCE")))
(defun vc-maybe-resolve-conflicts (file status &optional name-A name-B)
;;;###autoload
(defalias 'vc-resolve-conflicts 'smerge-ediff)
-;; VC Dired hook
-;; FIXME: Remove Dired support when vc-dir is ready.
-
-(defun vc-dired-hook ()
- "Reformat the listing according to version control.
-Called by dired after any portion of a vc-dired buffer has been read in."
- (message "Getting version information... ")
- ;; if the backend supports it, get the state
- ;; of all files in this directory at once
- (let ((backend (vc-responsible-backend default-directory)))
- ;; check `backend' can really handle `default-directory'.
- (if (and (vc-call-backend backend 'responsible-p default-directory)
- (vc-find-backend-function backend 'dir-state))
- (vc-call-backend backend 'dir-state default-directory)))
- (let (filename
- (inhibit-read-only t)
- (buffer-undo-list t))
- (goto-char (point-min))
- (while (not (eobp))
- (cond
- ;; subdir header line
- ((dired-get-subdir)
- (forward-line 1)
- ;; erase (but don't remove) the "total" line
- (delete-region (point) (line-end-position))
- (beginning-of-line)
- (forward-line 1))
- ;; file line
- ((setq filename (dired-get-filename nil t))
- (cond
- ;; subdir
- ((file-directory-p filename)
- (cond
- ((member (file-name-nondirectory filename)
- vc-directory-exclusion-list)
- (let ((pos (point)))
- (dired-kill-tree filename)
- (goto-char pos)
- (dired-kill-line)))
- (vc-dired-terse-mode
- ;; Don't show directories in terse mode. Don't use
- ;; dired-kill-line to remove it, because in recursive listings,
- ;; that would remove the directory contents as well.
- (delete-region (line-beginning-position)
- (progn (forward-line 1) (point))))
- ((string-match "\\`\\.\\.?\\'" (file-name-nondirectory filename))
- (dired-kill-line))
- (t
- (vc-dired-reformat-line nil)
- (forward-line 1))))
- ;; Try to head off calling the expensive state query -
- ;; ignore object files, TeX intermediate files, and so forth.
- ((vc-dired-ignorable-p filename)
- (dired-kill-line))
- ;; Ordinary file -- call the (possibly expensive) state query
- ;;
- ;; First case: unregistered or unknown. (Unknown shouldn't happen here)
- ((member (vc-state filename) '(nil unregistered))
- (if vc-dired-terse-mode
- (dired-kill-line)
- (vc-dired-reformat-line "?")
- (forward-line 1)))
- ;; Either we're in non-terse mode or it's out of date
- ((not (and vc-dired-terse-mode (vc-up-to-date-p filename)))
- (vc-dired-reformat-line (vc-call prettify-state-info filename))
- (forward-line 1))
- ;; Remaining cases are under version control but uninteresting
- (t
- (dired-kill-line))))
- ;; any other line
- (t (forward-line 1))))
- (vc-dired-purge))
- (message "Getting version information... done")
- (save-restriction
- (widen)
- (cond ((eq (count-lines (point-min) (point-max)) 1)
- (goto-char (point-min))
- (message "No changes pending under %s" default-directory)))))
-
;; VC status implementation
(defun vc-default-status-extra-headers (backend dir)
(defun vc-default-extra-status-menu (backend)
nil)
-;; This is used to that VC backends could add backend specific menu
-;; items to vc-dir-menu-map.
-(defun vc-dir-menu-map-filter (orig-binding)
- (when (and (symbolp orig-binding) (fboundp orig-binding))
- (setq orig-binding (indirect-function orig-binding)))
- (let ((ext-binding
- (vc-call-backend (vc-responsible-backend default-directory)
- 'extra-status-menu)))
- (if (null ext-binding)
- orig-binding
- (append orig-binding
- '("----")
- ext-binding))))
-
(defun vc-dir-refresh-files (files default-state)
"Refresh some files in the VC status buffer."
(let ((backend (vc-responsible-backend default-directory))
(let ((backend (vc-responsible-backend dir)))
(vc-dir-headers backend dir)))
+(defun vc-dir-extra-menu ()
+ (vc-call-backend (vc-responsible-backend default-directory) '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-generic-status-printer
#'vc-generic-state
#'vc-generic-status-fileinfo-extra
- #'vc-dir-refresh))
+ #'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 dir))
- (if (and (eq major-mode 'vc-dir-mode) (boundp 'client-object))
+ (if (and (derived-mode-p 'vc-dir-mode) (boundp 'client-object))
(vc-dir-refresh)
;; Otherwise, initialize a new view using the dispatcher layer
(progn
;; 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-diff) ;; C-x v v
(define-key map "=" 'vc-diff) ;; C-x v =
- (define-key map "a" 'vc-dir-register)
+ (define-key map "i" 'vc-dir-register) ;; C-x v i
(define-key map "+" 'vc-update) ;; C-x v +
- (define-key map "R" 'vc-revert) ;; u is taken by dispatcher unmark.
- (define-key map "A" 'vc-annotate) ;; g is taken by dispatcher referesh
(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
"List the change log of the current fileset in a window.
If WORKING-REVISION is non-nil, leave the point at that revision."
(interactive)
- (let* ((vc-fileset (vc-deduce-fileset))
- (files (cdr vc-fileset))
+ (let* ((vc-fileset (vc-deduce-fileset t))
(backend (car vc-fileset))
+ (files (cadr vc-fileset))
(working-revision (or working-revision (vc-working-revision (car files)))))
;; Don't switch to the output buffer before running the command,
;; so that any buffer-local settings in the vc-controlled
to the working revision (except for keyword expansion)."
(interactive)
(let* ((vc-fileset (vc-deduce-fileset))
- (files (cdr vc-fileset)))
+ (files (cadr vc-fileset)))
;; If any of the files is visited by the current buffer, make
;; sure buffer is saved. If the user says `no', abort since
;; we cannot show the changes and ask for confirmation to
depending on the underlying version-control system."
(interactive)
(let* ((vc-fileset (vc-deduce-fileset))
- (files (cdr vc-fileset))
(backend (car vc-fileset))
+ (files (cadr vc-fileset))
(granularity (vc-call-backend backend 'revision-granularity)))
(unless (vc-find-backend-function backend 'rollback)
(error "Rollback is not supported in %s" backend))
(when (and (not (eq granularity 'repository)) (/= (length files) 1))
(error "Rollback requires a singleton fileset or repository versioning"))
- (when (not (vc-call latest-on-branch-p (car files)))
+ ;; FIXME: latest-on-branch-p should take the fileset.
+ (when (not (vc-call-backend backend 'latest-on-branch-p (car files)))
(error "Rollback is only possible at the tip revision."))
;; If any of the files is visited by the current buffer, make
;; sure buffer is saved. If the user says `no', abort since
(not-modified)
(message "Finding changes...")
(let* ((tip (vc-working-revision (car files)))
- (previous (vc-call previous-revision (car files) tip)))
+ ;; FIXME: `previous-revision' should take the fileset.
+ (previous (vc-call-backend backend 'previous-revision
+ (car files) tip)))
(vc-diff-internal nil vc-fileset previous tip))
;; Display changes
(unless (yes-or-no-p "Discard these revisions? ")
changes from the current branch are merged into the working file."
(interactive)
(let* ((vc-fileset (vc-deduce-fileset))
- (files (cdr vc-fileset))
- (backend (car vc-fileset)))
+ (backend (car vc-fileset))
+ (files (cadr vc-fileset)))
(dolist (file files)
(when (let ((buf (get-file-buffer file)))
(and buf (buffer-modified-p buf)))
(vc-state file)
(substitute-command-keys
"\\[vc-next-action] to correct")))
- (if (not (vc-find-backend-function backend 'merge-news))
- (error "Sorry, merging news is not implemented for %s"
- backend)
- (vc-maybe-resolve-conflicts file (vc-call merge-news file))))))))
+ (vc-maybe-resolve-conflicts
+ file (vc-call-backend backend 'merge-news file)))))))
(defun vc-version-backup-file (file &optional rev)
"Return name of backup file for revision REV of FILE.
(vc-file-setprop file 'vc-checkout-time nil)))))
(when move
(vc-switch-backend file old-backend)
- (setq comment (vc-call comment-history file))
- (vc-call unregister file))
+ (setq comment (vc-call-backend old-backend 'comment-history file))
+ (vc-call-backend old-backend 'unregister file))
(vc-switch-backend file new-backend)
(when (or move edited)
(vc-file-setprop file 'vc-state 'edited)
;; command, kill the buffer created by the above
;; `find-file-noselect' call.
(unless buf (kill-buffer (current-buffer)))))
- (vc-call delete-file file)
+ (vc-call-backend backend 'delete-file file)
;; If the backend hasn't deleted the file itself, let's do it for him.
(when (file-exists-p file) (delete-file file))
;; Forget what VC knew about the file.
"Return a string with all log entries stored in BACKEND for FILE."
(when (vc-find-backend-function backend 'print-log)
(with-current-buffer "*vc*"
- (vc-call print-log (list file))
- (vc-call-backend backend 'wash-log)
+ (vc-call-backend backend 'print-log (list file))
(buffer-string))))
(defun vc-default-receive-file (backend file rev)
(vc-file-tree-walk
dir
(lambda (f)
- (vc-call assign-name f name))))))
+ (vc-call-backend backend 'assign-name f name))))))
(defun vc-default-retrieve-snapshot (backend dir name update)
(if (string= name "")
(lambda (f) (and
(vc-up-to-date-p f)
(vc-error-occurred
- (vc-call checkout f nil "")
+ (vc-call-backend backend 'checkout f nil "")
(when update (vc-resynch-buffer f t t)))))))
(let ((result (vc-snapshot-precondition dir)))
(if (stringp result)
(vc-file-tree-walk
dir
(lambda (f) (vc-error-occurred
- (vc-call checkout f nil name)
+ (vc-call-backend backend 'checkout f nil name)
(when update (vc-resynch-buffer f t t)))))))))
(defun vc-default-revert (backend file contents-done)
;; Change buffer to get local value of vc-checkout-switches.
(with-current-buffer file-buffer
(let ((default-directory (file-name-directory file)))
- (vc-call find-revision file rev outbuf)))))
+ (vc-call-backend backend 'find-revision
+ file rev outbuf)))))
(setq failed nil))
(when backup-name
(if failed
;; In case it had to be uniquified.
(setq temp-buffer-name (buffer-name))))
(with-output-to-temp-buffer temp-buffer-name
- (vc-call annotate-command file (get-buffer temp-buffer-name) rev)
- ;; we must setup the mode first, and then set our local
- ;; variables before the show-function is called at the exit of
- ;; with-output-to-temp-buffer
- (with-current-buffer temp-buffer-name
- (unless (equal major-mode 'vc-annotate-mode)
- (vc-annotate-mode))
- (set (make-local-variable 'vc-annotate-backend) (vc-backend file))
- (set (make-local-variable 'vc-annotate-parent-file) file)
- (set (make-local-variable 'vc-annotate-parent-rev) rev)
- (set (make-local-variable 'vc-annotate-parent-display-mode)
- display-mode)))
+ (let ((backend (vc-backend file)))
+ (vc-call-backend backend 'annotate-command file
+ (get-buffer temp-buffer-name) rev)
+ ;; we must setup the mode first, and then set our local
+ ;; variables before the show-function is called at the exit of
+ ;; with-output-to-temp-buffer
+ (with-current-buffer temp-buffer-name
+ (unless (equal major-mode 'vc-annotate-mode)
+ (vc-annotate-mode))
+ (set (make-local-variable 'vc-annotate-backend) backend)
+ (set (make-local-variable 'vc-annotate-parent-file) file)
+ (set (make-local-variable 'vc-annotate-parent-rev) rev)
+ (set (make-local-variable 'vc-annotate-parent-display-mode)
+ display-mode))))
(with-current-buffer temp-buffer-name
(vc-exec-after
(if (not rev-at-line)
(message "Cannot extract revision number from the current line")
(setq prev-rev
- (vc-call previous-revision vc-annotate-parent-file rev-at-line))
+ (vc-call-backend vc-annotate-backend 'previous-revision
+ vc-annotate-parent-file rev-at-line))
(vc-annotate-warp-revision prev-rev)))))
(defun vc-annotate-show-log-revision-at-line ()
(if (not rev-at-line)
(message "Cannot extract revision number from the current line")
(setq prev-rev
- (vc-call previous-revision vc-annotate-parent-file rev-at-line))
+ (vc-call-backend vc-annotate-backend 'previous-revision
+ vc-annotate-parent-file rev-at-line))
(if (not prev-rev)
(message "Cannot diff from any revision prior to %s" rev-at-line)
(save-window-excursion
(vc-diff-internal
nil
- (cons (vc-backend vc-annotate-parent-file)
- (list vc-annotate-parent-file))
+ (cons vc-annotate-backend (list vc-annotate-parent-file))
prev-rev rev-at-line))
(switch-to-buffer "*vc-diff*"))))))
((and (integerp revspec) (> revspec 0))
(setq newrev vc-annotate-parent-rev)
(while (and (> revspec 0) newrev)
- (setq newrev (vc-call next-revision
- vc-annotate-parent-file newrev))
- (setq revspec (1- revspec)))
+ (setq newrev (vc-call-backend vc-annotate-backend 'next-revision
+ vc-annotate-parent-file newrev))
+ (setq revspec (1- revspec)))
(unless newrev
(message "Cannot increment %d revisions from revision %s"
revspeccopy vc-annotate-parent-rev)))
((and (integerp revspec) (< revspec 0))
(setq newrev vc-annotate-parent-rev)
(while (and (< revspec 0) newrev)
- (setq newrev (vc-call previous-revision
- vc-annotate-parent-file newrev))
- (setq revspec (1+ revspec)))
+ (setq newrev (vc-call-backend vc-annotate-backend 'previous-revision
+ vc-annotate-parent-file newrev))
+ (setq revspec (1+ revspec)))
(unless newrev
(message "Cannot decrement %d revisions from revision %s"
(- 0 revspeccopy) vc-annotate-parent-rev)))
;; Pass the current line so that vc-annotate will
;; place the point in the line.
(min oldline (progn (goto-char (point-max))
- (forward-line -1)
- (line-number-at-pos))))))))
+ (forward-line -1)
+ (line-number-at-pos))))))))
(defun vc-annotate-compcar (threshold a-list)
"Test successive cons cells of A-LIST against THRESHOLD.
nil)
\f
-;; Set up key bindings for use while editing log messages
-
-(defun vc-log-edit (fileset)
- "Set up `log-edit' for use with VC on FILE."
- (setq default-directory
- (with-current-buffer vc-parent-buffer default-directory))
- (log-edit 'vc-finish-logentry
- nil
- `((log-edit-listfun . (lambda () ',fileset))
- (log-edit-diff-function . (lambda () (vc-diff nil)))))
- (set (make-local-variable 'vc-log-fileset) fileset)
- (make-local-variable 'vc-log-revision)
- (set-buffer-modified-p nil)
- (setq buffer-file-name nil))
-
;; These things should probably be generally available
(defun vc-file-tree-walk (dirname func &rest args)