emacs-devel
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[patch] add interactive browse of revisions from vc *Annotate* buffers


From: Benjamin Rutt
Subject: [patch] add interactive browse of revisions from vc *Annotate* buffers
Date: Sun, 11 Jan 2004 21:54:25 -0500
User-agent: Gnus/5.1003 (Gnus v5.10.3) Emacs/21.3.50 (usg-unix-v)

I wrote this patch because I wanted to be able to browse forward and
backwards to prev and next revisions from vc.el *Annotate* buffers.
That way, I can see which member of my work group is responsible for
entering a particular line of a CVS-controlled file (it's sometimes
not enough to just vc-annotate a buffer, since sometimes users
reformat or reindent lines of source code that they didn't originally
write).  This patch allows you, from a vc-annotate-mode buffer, to
press C-c C-p to go to the previous revision and C-c C-n to go to the
next revision.  It's currently only implemented for CVS, since
vc-annotate is only implemented for CVS anyway.

The way I incremented (or decremented) a revision number for CVS was
to add (or subtract) one to the last number in the dotted revision
number.  So, it works for the CVS head files with revisions like
"1.23" or for branches with revisions like "1.2.1.3".

If this patch is accepted, I'll write a patch for info so this gets
into the docs as well.  I have signed papers for emacs, FYI.

The patch below patches both vc.el and vc-cvs.el, as I had to define a
backend function and route it through vc-cvs.el, since I didn't want
anything cvs-specific creeping into vc.el, even though no vc-annotate
functionality exists for any other backends at the moment.

Thanks, and let me know of any comments or feedback you may have.
Benjamin Rutt

--- vc.el.orig  2004-01-10 21:51:37.000000000 -0500
+++ vc.el       2004-01-11 21:53:20.000000000 -0500
@@ -628,6 +628,8 @@
 (defvar vc-annotate-mode-map
   (let ((m (make-sparse-keymap)))
     (define-key m [menu-bar] (make-sparse-keymap "VC-Annotate"))
+    (define-key m "\C-c\C-p" 'vc-annotate-prev-version)
+    (define-key m "\C-c\C-n" 'vc-annotate-next-version)
     m)
   "Local keymap used for VC-Annotate mode.")
 
@@ -2778,6 +2780,10 @@
 (defvar vc-annotate-ratio nil "Global variable.")
 (defvar vc-annotate-backend nil "Global variable.")
 
+(defvar vc-annotate-derived-from-info nil
+  "Internal variable tracking buffer-local info about the file
+  which caused the *Annotate* buffer to be formed .")
+
 (defconst vc-annotate-font-lock-keywords
   ;; The fontification is done by vc-annotate-lines instead of font-lock.
   '((vc-annotate-lines)))
@@ -2885,7 +2891,12 @@
                    (unless (eq vc-annotate-display-mode 'fullscale)
                      (vc-annotate-display-select nil 'fullscale))
                    :style toggle :selected
-                   (eq vc-annotate-display-mode 'fullscale)])))
+                   (eq vc-annotate-display-mode 'fullscale)])
+                 (list "--")
+                 (list ["Annotate previous revision"
+                        (vc-annotate-prev-version)])
+                 (list ["Annotate next revision"
+                        (vc-annotate-next-version)])))
     ;; Define the menu
     (if (or (featurep 'easymenu) (load "easymenu" t))
        (easy-menu-define vc-annotate-mode-menu vc-annotate-mode-map
@@ -2922,7 +2933,7 @@
 ;;;;  the contents in BUFFER.
 
 ;;;###autoload
-(defun vc-annotate (prefix)
+(defun vc-annotate (prefix &optional revision display-mode)
   "Display the edit history of the current file using colours.
 
 This command creates a buffer that shows, for each line of the current
@@ -2949,19 +2960,24 @@
 colors. `vc-annotate-background' specifies the background color."
   (interactive "P")
   (vc-ensure-vc-buffer)
-  (let* ((temp-buffer-name (concat "*Annotate " (buffer-name) "*"))
+  (let* ((temp-buffer-name nil)
          (temp-buffer-show-function 'vc-annotate-display-select)
-         (rev (vc-workfile-version buffer-file-name))
+        (rev (or revision (vc-workfile-version buffer-file-name)))
+        (bfn buffer-file-name)
          (vc-annotate-version
-          (if prefix (read-string
-                      (format "Annotate from version: (default %s) " rev)
-                      nil nil rev)
-            rev)))
-    (if prefix
-        (setq vc-annotate-display-mode
-              (float (string-to-number
-                      (read-string "Annotate span days: (default 20) "
-                                   nil nil "20")))))
+         (if prefix (read-string
+                     (format "Annotate from version: (default %s) " rev)
+                     nil nil rev)
+           rev)))
+    (if display-mode
+       (setq vc-annotate-display-mode display-mode)
+      (if prefix
+         (setq vc-annotate-display-mode
+               (float (string-to-number
+                       (read-string "Annotate span days: (default 20) "
+                                    nil nil "20"))))))
+    (setq temp-buffer-name (format "*Annotate %s (rev %s)*"
+                                  (buffer-name) vc-annotate-version))
     (setq vc-annotate-backend (vc-backend buffer-file-name))
     (message "Annotating...")
     (if (not (vc-find-backend-function vc-annotate-backend 'annotate-command))
@@ -2972,6 +2988,11 @@
                       buffer-file-name
                       (get-buffer temp-buffer-name)
                        vc-annotate-version))
+    (save-excursion
+      (set-buffer temp-buffer-name)
+      (set (make-local-variable 'vc-annotate-derived-from-info)
+          (list vc-annotate-version bfn vc-annotate-display-mode)))
+          
     ;; Don't use the temp-buffer-name until the buffer is created
     ;; (only after `with-output-to-temp-buffer'.)
     (setq vc-annotate-buffers
@@ -2979,6 +3000,70 @@
                  (list (cons (get-buffer temp-buffer-name) 
vc-annotate-backend))))
   (message "Annotating... done")))
 
+(defun vc-annotate-prev-version ()
+  (interactive)
+  (vc-annotate-warp-version t))
+
+(defun vc-annotate-next-version ()
+  (interactive)
+  (vc-annotate-warp-version nil))
+
+;; return the new revision as a string, or else return nil if it
+;; cannot be decremented any further.  This method is invoked from a
+;; buffer visiting the `filename' argument.
+(defun vc-annotate-decrement-revision (filename rev)
+  (setq vc-annotate-backend (vc-backend buffer-file-name))
+  (vc-call-backend vc-annotate-backend 'decrement-revision filename rev))
+
+;; return the new revision as a string, or else return nil if it
+;; cannot be incremented any further.  This method is invoked from a
+;; buffer visiting the `filename' argument.
+(defun vc-annotate-increment-revision (filename rev)
+  (setq vc-annotate-backend (vc-backend buffer-file-name))
+  (vc-call-backend vc-annotate-backend 'increment-revision filename rev))
+
+(defun vc-current-line ()
+  "Returns the current buffer's line number."
+  (let ((oldpoint (point)) start)
+    (save-excursion
+      (save-restriction
+       (goto-char (point-min))
+       (widen)
+       (forward-line 0)
+       (setq start (point))
+       (goto-char oldpoint)
+       (forward-line 0)
+       (1+ (count-lines (point-min) (point)))))))
+
+(defun vc-annotate-warp-version (backwards)
+  (if (not (equal major-mode 'vc-annotate-mode))
+      (message "Cannot be invoked outside of a vc annotate buffer!")
+    (let* ((oldline (vc-current-line))
+          (derived-from-rev (car vc-annotate-derived-from-info))
+          (derived-from-filename (cadr vc-annotate-derived-from-info))
+          (derived-from-display-mode (caddr vc-annotate-derived-from-info))
+          (newrev nil))
+
+      (save-window-excursion
+       (find-file derived-from-filename)
+       (setq newrev
+             (if backwards
+                 (vc-annotate-decrement-revision derived-from-filename
+                                                 derived-from-rev)
+               (vc-annotate-increment-revision derived-from-filename
+                                               derived-from-rev))))
+      (if (not newrev)
+         (message "Cannot locate any revision %s %s"
+                  (if backwards "before" "after") derived-from-rev)
+       (save-window-excursion
+         (find-file derived-from-filename)
+         (vc-annotate nil newrev derived-from-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)
+                                      (vc-current-line))))))))
+
 (defun vc-annotate-car-last-cons (a-list)
   "Return car of last cons in association list A-LIST."
   (if (not (eq nil (cdr a-list)))
--- vc-cvs.el.orig      2004-01-11 21:31:30.000000000 -0500
+++ vc-cvs.el   2004-01-11 21:30:28.000000000 -0500
@@ -625,6 +625,24 @@
          (beginning-of-line nil)
            (vc-cvs-annotate-time))))))
 
+(defun vc-cvs-decrement-revision (filename rev)
+  (let ((ls (split-string rev "\\.")))
+    (setq ls (nreverse ls))
+    (if (string= (car ls) "1")
+       nil ;; return nil if the revision cannot be decremented any further
+      (setq ls (cons (int-to-string (1- (string-to-int (car ls)))) (cdr ls)))
+      (setq ls (nreverse ls))
+      (mapconcat 'identity ls "."))))
+
+(defun vc-cvs-increment-revision (filename rev)
+  (if (string= rev (vc-workfile-version filename))
+      nil ;; return nil if the revision cannot be incremented any further
+    (let ((ls (split-string rev "\\.")))    
+      (setq ls (nreverse ls))
+      (setq ls (cons (int-to-string (1+ (string-to-int (car ls)))) (cdr ls)))
+      (setq ls (nreverse ls))
+      (mapconcat 'identity ls "."))))
+
 ;;;
 ;;; Snapshot system
 ;;;




reply via email to

[Prev in Thread] Current Thread [Next in Thread]