+(defun vc-annotate-prev-version (prefix)
+ "Visit the annotation of the version previous to this one.
+
+With a numeric prefix argument, annotate the version that many
+versions previous."
+ (interactive "p")
+ (vc-annotate-warp-version (- 0 prefix)))
+
+(defun vc-annotate-next-version (prefix)
+ "Visit the annotation of the version after this one.
+
+With a numeric prefix argument, annotate the version that many
+versions after."
+ (interactive "p")
+ (vc-annotate-warp-version prefix))
+
+(defun vc-annotate-workfile-version ()
+ "Visit the annotation of the workfile version of this file."
+ (interactive)
+ (if (not (equal major-mode 'vc-annotate-mode))
+ (message "Cannot be invoked outside of a vc annotate buffer")
+ (let ((warp-rev (vc-workfile-version vc-annotate-parent-file)))
+ (if (equal warp-rev vc-annotate-parent-rev)
+ (message "Already at version %s" warp-rev)
+ (vc-annotate-warp-version warp-rev)))))
+
+(defun vc-annotate-extract-revision-at-line ()
+ "Extract the revision number of the current line."
+ ;; This function must be invoked from a buffer in vc-annotate-mode
+ (save-window-excursion
+ (vc-ensure-vc-buffer)
+ (setq vc-annotate-backend (vc-backend buffer-file-name)))
+ (vc-call-backend vc-annotate-backend 'annotate-extract-revision-at-line))
+
+(defun vc-annotate-revision-at-line ()
+ "Visit the annotation of the version identified in the current line."
+ (interactive)
+ (if (not (equal major-mode 'vc-annotate-mode))
+ (message "Cannot be invoked outside of a vc annotate buffer")
+ (let ((rev-at-line (vc-annotate-extract-revision-at-line)))
+ (if (not rev-at-line)
+ (message "Cannot extract revision number from the current line")
+ (if (equal rev-at-line vc-annotate-parent-rev)
+ (message "Already at version %s" rev-at-line)
+ (vc-annotate-warp-version rev-at-line))))))
+
+(defun vc-annotate-revision-previous-to-line ()
+ "Visit the annotation of the version before the version at line."
+ (interactive)
+ (if (not (equal major-mode 'vc-annotate-mode))
+ (message "Cannot be invoked outside of a vc annotate buffer")
+ (let ((rev-at-line (vc-annotate-extract-revision-at-line))
+ (prev-rev nil))
+ (if (not rev-at-line)
+ (message "Cannot extract revision number from the current line")
+ (setq prev-rev
+ (vc-call previous-version vc-annotate-parent-file rev-at-line))
+ (vc-annotate-warp-version prev-rev)))))
+
+(defun vc-annotate-show-log-revision-at-line ()
+ "Visit the log of the version at line."
+ (interactive)
+ (if (not (equal major-mode 'vc-annotate-mode))
+ (message "Cannot be invoked outside of a vc annotate buffer")
+ (let ((rev-at-line (vc-annotate-extract-revision-at-line)))
+ (if (not rev-at-line)
+ (message "Cannot extract revision number from the current line")
+ (vc-print-log rev-at-line)))))
+
+(defun vc-annotate-show-diff-revision-at-line ()
+ "Visit the diff of the version at line from its previous version."
+ (interactive)
+ (if (not (equal major-mode 'vc-annotate-mode))
+ (message "Cannot be invoked outside of a vc annotate buffer")
+ (let ((rev-at-line (vc-annotate-extract-revision-at-line))
+ (prev-rev nil))
+ (if (not rev-at-line)
+ (message "Cannot extract revision number from the current line")
+ (setq prev-rev
+ (vc-call previous-version vc-annotate-parent-file rev-at-line))
+ (if (not prev-rev)
+ (message "Cannot diff from any version prior to %s" rev-at-line)
+ (save-window-excursion
+ (vc-version-diff vc-annotate-parent-file prev-rev rev-at-line))
+ (switch-to-buffer "*vc-diff*"))))))
+
+(defun vc-annotate-warp-version (revspec)
+ "Annotate the version described by REVSPEC.
+
+If REVSPEC is a positive integer, warp that many versions
+forward, if possible, otherwise echo a warning message. If
+REVSPEC is a negative integer, warp that many versions backward,
+if possible, otherwise echo a warning message. If REVSPEC is a
+string, then it describes a revision number, so warp to that
+revision."
+ (if (not (equal major-mode 'vc-annotate-mode))
+ (message "Cannot be invoked outside of a vc annotate buffer")
+ (let* ((oldline (line-number-at-pos))
+ (revspeccopy revspec)
+ (newrev nil))
+ (cond
+ ((and (integerp revspec) (> revspec 0))
+ (setq newrev vc-annotate-parent-rev)
+ (while (and (> revspec 0) newrev)
+ (setq newrev (vc-call next-version
+ vc-annotate-parent-file newrev))
+ (setq revspec (1- revspec)))
+ (if (not newrev)
+ (message "Cannot increment %d versions from version %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-version
+ vc-annotate-parent-file newrev))
+ (setq revspec (1+ revspec)))
+ (if (not newrev)
+ (message "Cannot decrement %d versions from version %s"
+ (- 0 revspeccopy) vc-annotate-parent-rev)))
+ ((stringp revspec) (setq newrev revspec))
+ (t (error "Invalid argument to vc-annotate-warp-version")))
+ (when newrev
+ (save-window-excursion
+ (find-file vc-annotate-parent-file)
+ (vc-annotate nil newrev vc-annotate-parent-display-mode))
+ (kill-buffer (current-buffer)) ;; kill the buffer we started from
+ (switch-to-buffer (car (car (last vc-annotate-buffers))))
+ (goto-line (min oldline (progn (goto-char (point-max))
+ (previous-line)
+ (line-number-at-pos))))))))
+