1

When I've launched vc-annotate and then type a (vc-annotate-revision-previous-to-line), emacs will show me the revision before the one on the current line.

From the docs:

a

Annotate the revision before the one indicated by the current line. This is useful to see the state the file was in before the change on the current line was made.

After doing this, I now want to go back to the previous revision of the file that I was viewing before I pressed a. How can I do this?

If emacs vc-annotate doesn't support it natively, are there any packages that can accomplish this? Or how would I go about coding this on my own? I imagine I could just use some sort of stack to store all the revisions visited in the current vc-annotate session, and then pop one off using an undo command.

I am using git, so would even be interested in an answer that applies only to git.

  • Using a stack seems like the best approach to me. Store the current revision in vc-annotate-warp-revision, and create a command that would pop the value off the stack and go to the top of what remains. Something like that. – Dmitry May 13 '17 at 10:56
1

Here an attempt at this. It uses an advise function on vc-annotate (maybe there's a better way, but I couldn't find one) to log the revisions annotated, storing then in stacks, one for each file annotated.

It then adds a function vc-annotate-previous-annotation to redisplay the last annotated revision of the file currently being annotated.

;;  A hash table mapping from file names to stacks of vc-annotate calls
(defvar vc-annotate-call-stacks (make-hash-table :test 'equal))

;; Define a structure type to store the details needed to redisplay a revision
;; rev: the revision annotated
;; point: the cursor point when the annotation was first displayed (perhaps this
;;        could be improved to be the last point moved to on the annotation)
(require 'cl-lib)
(cl-defstruct annotation-details rev point)

;; The vc-annotate-mode-hook can't be used because it is run before
;; the vc-annotate-parent-* variables are set.
;;
;; So instead use a advise function for vc-annotate, called before
;; vc-annotate, which stores the arguments on the appropriate stack.
(defun record-annotation-call (file rev &optional display-mode buf move-point-to vc-bk)
  (message "Recording annotation: file %S rev %S" file rev)
  (let ((annotation-stack (gethash file vc-annotate-call-stacks)))
    (push (make-annotation-details :rev rev
                                   :point move-point-to)
          annotation-stack)
    (puthash file annotation-stack vc-annotate-call-stacks)))

(advice-add 'vc-annotate :before #'record-annotation-call)

(defun vc-annotate-previous-annotation ()
  "Go back to showing the annotation of the previous displayed annotation"
  (interactive)
  (when (not (equal major-mode 'vc-annotate-mode))
    (error "Can only be used in vc-annotate-mode"))
  (let ((annotation-stack (gethash vc-annotate-parent-file vc-annotate-call-stacks)))
       (when (< (length annotation-stack) 2)
         (error "No previous vc-annotate calls"))
       ;; The entry at the top of the stack is the current annotation.
       ;; So need to pop two entries to get the previous annotation.
       (let
           ((curr-annotation (pop annotation-stack))
            (prev-annotation (pop annotation-stack)))
         ;; Update the annotation-stack in the hash table after removing the entries.
         ;; The entry for the one we're returning to will be re-added by
         ;; the advise function for vc-annotate.
         (puthash vc-annotate-parent-file annotation-stack vc-annotate-call-stacks)

         (vc-annotate vc-annotate-parent-file
                      (annotation-details-rev prev-annotation)
                      vc-annotate-parent-display-mode
                      (current-buffer)
                      (annotation-details-point prev-annotation)
                      vc-annotate-backend))))
  • how can I bind vc-annotate-previous-annotation to the key b during vc-annotate? – mark Sep 18 '17 at 18:56
0

This seems to work for me.

(defun vc-annotate-revision-next-to-line ()
  "Visit the annotation of the revision after the revision at line.
This is the dual to `vc-annotate-revision-previous-to-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))
       (next-rev nil)
       (rev (car rev-at-line))
       (fname (cdr rev-at-line)))
  (if (not rev-at-line)
      (message "Cannot extract revision number from the current line")
    (setq next-rev
      (vc-call-backend vc-annotate-backend 'next-revision
               fname rev))
    (vc-annotate-warp-revision next-rev fname)))))
;; vc-annotate-revision-previous-to-line is bound to "a"; use "e" for symmetry.
(eval-after-load "vc-annotate"
  '(define-key vc-annotate-mode-map "e" 'vc-annotate-revision-next-to-line))
  • This seems useful in general, but I don't believe it's answering the question. – phils Mar 14 '17 at 11:18
  • I'm not sure this is particularly useful either. j followed by n should do the same. – Dmitry Mar 14 '17 at 15:33

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.