;; 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
;; 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-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, 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:
(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."
+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 ()
+(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* ((fileset (vc-dispatcher-selection-set))
+ (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 (derived-mode-p 'vc-dir-mode)
+ (backend (if (vc-derived-from-dir-mode (current-buffer))
(vc-responsible-backend default-directory)
- (assert (and (= 1 (length fileset))
- (not (file-directory-p (car fileset)))))
- (vc-backend (car fileset)))))
- (cons backend fileset)))
+ (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."
(interactive "P")
(let* ((vc-fileset (vc-deduce-fileset))
(backend (car vc-fileset))
- (files (cdr vc-fileset))
- (fileset-only-files (vc-expand-dirs 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'.
"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"
(defun vc-version-diff (files rev1 rev2)
"Report diffs between revisions of the fileset in the repository history."
(interactive
- (let* ((vc-fileset (vc-deduce-fileset))
- (files (cdr vc-fileset))
+ (let* ((vc-fileset (vc-deduce-fileset t))
+ (files (cadr vc-fileset))
(backend (car vc-fileset))
(first (car files))
(completion-table
(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)
;; 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
"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))
+ (let* ((vc-fileset (vc-deduce-fileset t))
(backend (car vc-fileset))
- (files (cdr 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
(interactive)
(let* ((vc-fileset (vc-deduce-fileset))
(backend (car vc-fileset))
- (files (cdr 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))
(interactive)
(let* ((vc-fileset (vc-deduce-fileset))
(backend (car vc-fileset))
- (files (cdr vc-fileset)))
+ (files (cadr vc-fileset)))
(dolist (file files)
(when (let ((buf (get-file-buffer file)))
(and buf (buffer-modified-p buf)))
(when (vc-find-backend-function backend 'print-log)
(with-current-buffer "*vc*"
(vc-call-backend backend 'print-log (list file))
- (vc-call-backend backend 'wash-log)
(buffer-string))))
(defun vc-default-receive-file (backend file rev)
(save-window-excursion
(vc-diff-internal
nil
- (cons (vc-backend vc-annotate-parent-file)
- (cons nil
- (list vc-annotate-parent-file)))
+ (cons vc-annotate-backend (list vc-annotate-parent-file))
prev-rev rev-at-line))
(switch-to-buffer "*vc-diff*"))))))
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)