;;; 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, 2009
+;; 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010
;; Free Software Foundation, Inc.
;; Author: FSF (see below for full credits)
;;
;; HISTORY FUNCTIONS
;;
-;; * print-log (files buffer &optional shortlog limit)
+;; * print-log (files buffer &optional shortlog start-revision limit)
;;
;; Insert the revision log for FILES into BUFFER.
;; If SHORTLOG is true insert a short version of the log.
-;; If LIMIT is true insert only insert LIMIT log entries.
+;; If LIMIT is true insert only insert LIMIT log entries. If the
+;; backend does not support limiting the number of entries to show
+;; it should return `limit-unsupported'.
+;; If START-REVISION is given, then show the log starting from the
+;; revision. At this point START-REVISION is only required to work
+;; in conjunction with LIMIT = 1.
;;
;; - log-view-mode ()
;;
(require 'vc-dispatcher)
(eval-when-compile
- (require 'cl))
+ (require 'cl)
+ (require 'dired))
(unless (assoc 'vc-parent-buffer minor-mode-alist)
(setq minor-mode-alist
:type '(choice (const :tag "Work out" nil) (const yes) (const no))
:group 'vc)
-(defcustom vc-log-show-limit 0
+(defcustom vc-log-show-limit 2000
"Limit the number of items shown by the VC log commands.
Zero means unlimited.
Not all VC backends are able to support this feature."
(defmacro with-vc-properties (files form settings)
"Execute FORM, then maybe set per-file properties for FILES.
+If any of FILES is actually a directory, then do the same for all
+buffers for files in that directory.
SETTINGS is an association list of property/value pairs. After
executing FORM, set those properties from SETTINGS that have not yet
been updated to their corresponding values."
(declare (debug t))
- `(let ((vc-touched-properties (list t)))
- ,form
+ `(let ((vc-touched-properties (list t))
+ (flist nil))
(dolist (file ,files)
+ (if (file-directory-p file)
+ (dolist (buffer (buffer-list))
+ (let ((fname (buffer-file-name buffer)))
+ (when (and fname (vc-string-prefix-p file fname))
+ (push fname flist))))
+ (push file flist)))
+ ,form
+ (dolist (file flist)
(dolist (setting ,settings)
(let ((property (car setting)))
(unless (memq property vc-touched-properties)
(cond
((derived-mode-p 'vc-dir-mode)
(vc-dir-deduce-fileset state-model-only-files))
+ ((derived-mode-p 'dired-mode)
+ (if observer
+ (vc-dired-deduce-fileset)
+ (error "State changing VC operations not supported in `dired-mode'")))
((setq backend (vc-backend buffer-file-name))
(if state-model-only-files
(list backend (list buffer-file-name)
(list buffer-file-name))))
(t (error "No fileset is available here")))))
+(defun vc-dired-deduce-fileset ()
+ (let ((backend (vc-responsible-backend default-directory)))
+ (unless backend (error "Directory not under VC"))
+ (list backend
+ (dired-map-over-marks (dired-get-filename nil t) nil))))
+
(defun vc-ensure-vc-buffer ()
"Make sure that the current buffer visits a version-controlled file."
(cond
;;;###autoload
(defun vc-root-diff (historic &optional not-urgent)
- "Display diffs between file revisions.
-Normally this compares the currently selected fileset with their
-working revisions. With a prefix argument HISTORIC, it reads two revision
+ "Display diffs between VC-controlled whole tree revisions.
+Normally, this compares the tree corresponding to the current
+fileset with the working revision.
+With a prefix argument HISTORIC, prompt for two revision
designators specifying which revisions to compare.
The optional argument NOT-URGENT non-nil means it is ok to say no to
(when buffer-file-name (vc-buffer-sync not-urgent))
(let ((backend
(cond ((derived-mode-p 'vc-dir-mode) vc-dir-backend)
+ ((derived-mode-p 'dired-mode) (vc-responsible-backend default-directory))
(vc-mode (vc-backend buffer-file-name))))
rootdir working-revision)
(unless backend
If it contains `file' then show short logs for files.
Not all VC backends support short logs!")
-(defun vc-print-log-internal (backend files working-revision limit)
+(defvar log-view-vc-backend)
+(defvar log-view-vc-fileset)
+
+(defun vc-print-log-internal (backend files working-revision
+ &optional is-start-revision limit)
;; Don't switch to the output buffer before running the command,
;; so that any buffer-local settings in the vc-controlled
;; buffer can be accessed by the command.
(let ((dir-present nil)
- (vc-short-log nil))
+ (vc-short-log nil)
+ pl-return)
(dolist (file files)
(when (file-directory-p file)
(setq dir-present t)))
(not (null (if dir-present
(memq 'directory vc-log-short-style)
(memq 'file vc-log-short-style)))))
- (vc-call-backend backend 'print-log files "*vc-change-log*" vc-short-log limit)
+
+ (setq pl-return (vc-call-backend
+ backend 'print-log files "*vc-change-log*"
+ vc-short-log (when is-start-revision working-revision) limit))
(pop-to-buffer "*vc-change-log*")
+ (let ((inhibit-read-only t))
+ ;; log-view-mode used to be called with inhibit-read-only bound
+ ;; to t, so let's keep doing it, just in case.
+ (vc-call-backend backend 'log-view-mode))
+ (set (make-local-variable 'log-view-vc-backend) backend)
+ (set (make-local-variable 'log-view-vc-fileset) files)
+
(vc-exec-after
- `(let ((inhibit-read-only t)
- (vc-short-log ,vc-short-log))
- (vc-call-backend ',backend 'log-view-mode)
- (set (make-local-variable 'log-view-vc-backend) ',backend)
- (set (make-local-variable 'log-view-vc-fileset) ',files)
+ `(let ((inhibit-read-only t))
+ (when (and ,limit (not ,(eq 'limit-unsupported pl-return))
+ (not ,is-start-revision))
+ (goto-char (point-max))
+ (widget-create 'push-button
+ :notify (lambda (&rest ignore)
+ (vc-print-log-internal
+ ',backend ',files ',working-revision nil (* 2 ,limit)))
+ :help-echo "Show the log again, and double the number of log entries shown"
+ "Show 2X entries")
+ (widget-insert " ")
+ (widget-create 'push-button
+ :notify (lambda (&rest ignore)
+ (vc-print-log-internal
+ ',backend ',files ',working-revision nil nil))
+ :help-echo "Show the log again, showing all entries"
+ "Show unlimited entries")
+ (widget-setup))
(shrink-window-if-larger-than-buffer)
;; move point to the log entry for the working revision
;;;###autoload
(defun vc-print-log (&optional working-revision limit)
"List the change log of the current fileset in a window.
-If WORKING-REVISION is non-nil, leave the point at that revision."
+If WORKING-REVISION is non-nil, leave point at that revision.
+If LIMIT is non-nil, it should be a number specifying the maximum
+number of revisions to show; the default is `vc-log-show-limit'.
+
+When called interactively with a prefix argument, prompt for
+WORKING-REVISION and LIMIT."
(interactive
(cond
(current-prefix-arg
(when (<= lim 0) (setq lim nil))
(list rev lim)))
(t
- (list nil nil))))
+ (list nil (when (> vc-log-show-limit 0) vc-log-show-limit)))))
(let* ((vc-fileset (vc-deduce-fileset t)) ;FIXME: Why t? --Stef
(backend (car vc-fileset))
(files (cadr vc-fileset))
(working-revision (or working-revision (vc-working-revision (car files)))))
- (vc-print-log-internal backend files working-revision limit)))
+ (vc-print-log-internal backend files working-revision nil limit)))
;;;###autoload
(defun vc-print-root-log (&optional limit)
- "List the change log of for the current VC controlled tree in a window."
+ "List the change log for the current VC controlled tree in a window.
+If LIMIT is non-nil, it should be a number specifying the maximum
+number of revisions to show; the default is `vc-log-show-limit'.
+When called interactively with a prefix argument, prompt for LIMIT."
(interactive
(cond
(current-prefix-arg
(when (<= lim 0) (setq lim nil))
(list lim)))
(t
- (list nil))))
+ (list (when (> vc-log-show-limit 0) vc-log-show-limit)))))
(let ((backend
(cond ((derived-mode-p 'vc-dir-mode) vc-dir-backend)
+ ((derived-mode-p 'dired-mode) (vc-responsible-backend default-directory))
(vc-mode (vc-backend buffer-file-name))))
rootdir working-revision)
(unless backend
(error "Buffer is not version controlled"))
(setq rootdir (vc-call-backend backend 'root default-directory))
(setq working-revision (vc-working-revision rootdir))
- (vc-print-log-internal backend (list rootdir) working-revision limit)))
+ (vc-print-log-internal backend (list rootdir) working-revision nil limit)))
;;;###autoload
(defun vc-revert ()
(when (vc-diff-internal vc-allow-async-revert vc-fileset nil nil)
(unless (yes-or-no-p
(format "Discard changes in %s? "
- (let ((str (vc-delistify files)))
+ (let ((str (vc-delistify files))
+ (nfiles (length files)))
(if (< (length str) 50)
str
- (format "%d files" (length files))))))
+ (format "%d file%s" nfiles
+ (if (= nfiles 1) "" "s"))))))
(error "Revert canceled"))
(delete-windows-on "*vc-diff*")
(kill-buffer "*vc-diff*"))