From mboxrd@z Thu Jan 1 00:00:00 1970 Path: main.gmane.org!not-for-mail From: Benjamin Rutt Newsgroups: gmane.emacs.devel Subject: [patch] add interactive browse of revisions from vc *Annotate* buffers Date: Sun, 11 Jan 2004 21:54:25 -0500 Sender: emacs-devel-bounces+emacs-devel=quimby.gnus.org@gnu.org Message-ID: NNTP-Posting-Host: deer.gmane.org Mime-Version: 1.0 Content-Type: text/plain; charset=us-ascii X-Trace: sea.gmane.org 1073876570 9863 80.91.224.253 (12 Jan 2004 03:02:50 GMT) X-Complaints-To: usenet@sea.gmane.org NNTP-Posting-Date: Mon, 12 Jan 2004 03:02:50 +0000 (UTC) Original-X-From: emacs-devel-bounces+emacs-devel=quimby.gnus.org@gnu.org Mon Jan 12 04:02:46 2004 Return-path: Original-Received: from quimby.gnus.org ([80.91.224.244]) by deer.gmane.org with esmtp (Exim 3.35 #1 (Debian)) id 1AfsLm-0007YP-00 for ; Mon, 12 Jan 2004 04:02:46 +0100 Original-Received: from monty-python.gnu.org ([199.232.76.173]) by quimby.gnus.org with esmtp (Exim 3.35 #1 (Debian)) id 1AfsLl-0004EM-00 for ; Mon, 12 Jan 2004 04:02:46 +0100 Original-Received: from localhost ([127.0.0.1] helo=monty-python.gnu.org) by monty-python.gnu.org with esmtp (Exim 4.24) id 1AftC8-0001pG-VW for emacs-devel@quimby.gnus.org; Sun, 11 Jan 2004 22:56:52 -0500 Original-Received: from list by monty-python.gnu.org with tmda-scanned (Exim 4.24) id 1AftBl-0001mu-Db for emacs-devel@gnu.org; Sun, 11 Jan 2004 22:56:29 -0500 Original-Received: from mail by monty-python.gnu.org with spam-scanned (Exim 4.24) id 1AftBE-0001h0-UZ for emacs-devel@gnu.org; Sun, 11 Jan 2004 22:56:28 -0500 Original-Received: from [164.107.123.5] (helo=cis.ohio-state.edu) by monty-python.gnu.org with esmtp (Exim 4.24) id 1AftBE-0001eQ-2F for emacs-devel@gnu.org; Sun, 11 Jan 2004 22:55:56 -0500 Original-Received: from mu.cis.ohio-state.edu (daemon@mu.cis.ohio-state.edu [164.107.112.41]) by cis.ohio-state.edu (8.11.6p2-20030924/8.11.6) with ESMTP id i0C2sPP22624 for ; Sun, 11 Jan 2004 21:54:25 -0500 (EST) Original-Received: (from rutt@localhost) by mu.cis.ohio-state.edu (8.11.6p2-20030924/8.11.6) id i0C2sPi29852; Sun, 11 Jan 2004 21:54:25 -0500 (EST) X-Authentication-Warning: mu.cis.ohio-state.edu: rutt set sender to rutt.4@osu.edu using -f Original-To: emacs-devel@gnu.org Mail-Followup-To: emacs-devel@gnu.org User-Agent: Gnus/5.1003 (Gnus v5.10.3) Emacs/21.3.50 (usg-unix-v) X-BeenThere: emacs-devel@gnu.org X-Mailman-Version: 2.1.2 Precedence: list List-Id: Emacs development discussions. List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: emacs-devel-bounces+emacs-devel=quimby.gnus.org@gnu.org Xref: main.gmane.org gmane.emacs.devel:19138 X-Report-Spam: http://spam.gmane.org/gmane.emacs.devel:19138 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 ;;;