Subject: CVS annotate in colour

From: Ian Lance Taylor <[email-masked]>
Date: Wed, 26 Feb 1997 14:48:26 -0500

Here's a cute hack which displays the results of cvs annotate in
colour.  Older lines are bluer.  I hacked this code a bit to work when
using client server.

Just ^X^F a file in a CVS working directory, and type M-x granny.

On my machine the lines come out in reverse video.  It would be great
if some emacs hacker could fix that.

Ian

;;; granny.el --- Colorful display of the `cvs annotate' command

;; Copyright (C) 1997 Martin Lorentzson.

;; Author:  Martin Lorentzson <[email-masked]>
;; Version: 1.0

;; This program is free software; you can redistribute it and/or modify
;; it under the terms of the GNU General Public License as published by
;; the Free Software Foundation; either version 1, or (at your option)
;; any later version.
;;
;; This program is distributed in the hope that it will be useful,
;; but WITHOUT ANY WARRANTY; without even the implied warranty of
;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
;; GNU General Public License for more details.
;;
;; A copy of the GNU General Public License can be obtained from this
;; program's author (send electronic mail to [email-masked]) or from
;; the Free Software Foundation, Inc., 675 Mass Ave, Cambridge, MA
;; 02139, USA.

;;; Commentary:

;; Running `granny' will display the result of the cvs command `cvs
;; annotate' using colors to enhance the age of the line. Red is new
;; (hot) and blue is old (cold).

;; This was inspired by Granny version 1.0 by J. Gabriel Foster
;; ([email-masked])

;;; Installation:

;; (cond (window-system (require 'granny)))

;;; Usage:

;; When in a CVS controlled file, use M-x granny.

;;; Code:

;;;###autoload
(defun granny()
  "Display the result of the cvs annotate command using colors.
New lines are displayed in red, old in blue. To use granny, press
\\[granny] in file controlled by CVS."
  (interactive)
  (message "granny...")
  (let ((tmp-buffer-name (concat "*cvs annotate " (buffer-name) "*"))
	(temp-buffer-show-function 'granny-display)
	(dir-name (file-name-directory (buffer-file-name)))
	(file-name (file-name-nondirectory (buffer-file-name))))
    (with-output-to-temp-buffer tmp-buffer-name
      (call-process "/bin/sh" nil (get-buffer tmp-buffer-name) nil
		    "-c" (concat "cd " dir-name "; cvs annotate " file-name))))
  (message "granny... done"))

(defun granny-display (buffer)
  "Do the granny display."

  ;; We need a list of months and their corresponding numbers.
  (let ((local-month-numbers 
	'(("Jan" . 1) ("Feb" .  2) ("Mar" .  3) ("Apr" .  4)
	  ("May" . 5) ("Jun" .  6) ("Jul" .  7) ("Aug" .  8) 
	  ("Sep" . 9) ("Oct" . 10) ("Nov" . 11) ("Dec" . 12))))

    (set-buffer buffer)
    (display-buffer buffer)
    (while (re-search-forward 
	    "^[0-9]+\\(\.[0-9]+\\)*\\s-+(\\sw+\\s-+\\([0-9]+\\)-\\(\\sw+\\)-\\([0-9]+\\)): "
	    nil t)

      (let* ((this-point (point))
	     (foo (forward-line 1))
	     (overlay (make-overlay this-point (point)))
	     (day (match-string 2))
             (month (cdr (assoc (match-string 3) local-month-numbers)))
             (year (concat "19" (match-string 4))) ; The millenium problem!!
	     (high (- (car (current-time))
		      (car (encode-time 0 0 0 
					(string-to-number day)
					month
					(string-to-number year)))))
	     (face-list
	      ;; There is a twenty-day increment.
	      (cond ((< high  24.9794) '(granny-face0 . "#FF0000"))
		    ((< high  49.9589) '(granny-face1 . "#FF3800"))
		    ((< high  74.9383) '(granny-face2 . "#FF7000"))
		    ((< high  99.9178) '(granny-face3 . "#FFA800"))
		    ((< high 124.8972) '(granny-face4 . "#FFE000"))
		    ((< high 149.8766) '(granny-face5 . "#E7FF00"))
		    ((< high 174.8561) '(granny-face6 . "#AFFF00"))
		    ((< high 199.8355) '(granny-face7 . "#77FF00"))
		    ((< high 224.8150) '(granny-face8 . "#3FFF00"))
		    ((< high 249.7944) '(granny-face9 . "#07FF00"))
		    ((< high 274.7738) '(granny-facea . "#00FF31"))
		    ((< high 299.7533) '(granny-faceb . "#00FF69"))
		    ((< high 324.7327) '(granny-facec . "#00FFA1"))
		    ((< high 349.7122) '(granny-faced . "#00FFD9"))
		    ((< high 374.6916) '(granny-facee . "#00EEFF"))
		    ((< high 399.6711) '(granny-facef . "#00B6FF"))
		    ((< high 424.6505) '(granny-faceg . "#007EFF"))
		    ((< high 449.6299) '(granny-faceh . "#0046FF"))
		    (t                 '(granny-facei . "#000EFF")))))

	;; Make the face if not done.
	(if (facep (car face-list))
	    ()
	  (make-face (car face-list))
	  (set-face-background (car face-list) "black")
	  (set-face-foreground (car face-list) (cdr face-list)))
	(overlay-put overlay
		       'face
		       (car face-list))))))

(provide 'granny)
;; granny ends here.