;;; Todo:
+;;;; 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
;; 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-responsible-backend should not return RCS if no backend
-;; declares itself responsible.
-;;
-;; - 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-expand-dirs should take a backend parameter and only look for
-;; files managed by that backend.
-;;
;;; 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-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 observer))
+ (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."
(unless (vc-backend buffer-file-name)
(error "File %s is not under version control" buffer-file-name))))))
-(defun vc-buffer-sync (&optional not-urgent)
- "Make sure the current buffer and its working file are in sync.
-NOT-URGENT means it is ok to continue if the user says not to save."
- (when (buffer-modified-p)
- (if (or vc-suppress-confirm
- (y-or-n-p (format "Buffer %s modified; save it? " (buffer-name))))
- (save-buffer)
- (unless not-urgent
- (error "Aborted")))))
-
;;; Support for the C-x v v command.
;; This is where all the single-file-oriented code from before the fileset
;; rewrite lives.
(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"
"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
(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)
(interactive)
(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)))
(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)