xemacs-devel / patch-keywords.el

;;; patch-keywords.el --- Insert action keywords into patch followups.

;; Copyright (C) 2002 Steve Youngs

;; RCS: $Id$
;; Author:        Steve Youngs <>
;; Maintainer:    Steve Youngs <>
;; Created:       2002-01-14
;; Last-Modified: <2002-01-24 09:59:57 (steve)>
;; Keywords:      maint

;; This file is part of XEmacs

;; XEmacs 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 2 of the License, or
;; (at your option) any later version.

;; XEmacs is distributed in the hope that it will be useful,
;; but WITHOUT ANY WARRANTY; without even the implied warranty of
;; GNU General Public License for more details.

;; You should have received a copy of the GNU General Public License
;; along with this program; if not, write to the Free Software
;; Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA

;;; Commentary:
;;  This file is an aid to mailing followups to patches submitted via
;;  email.  It adds "Reviewer Action Keywords" to the message.  These
;;  "keywords" can later be used as an aid to patch tracking.

;;  At this stage, this file is probably only useful to anyone who
;;  reviews patches submitted to <> (and is
;;  using Gnus for email).

;;  To use: simply add '(require 'patch-keywords)' to your
;;  '~/.xemacs/init.el' and then when you are following up to a patch
;;  submission (in `message-mode') hitting 'M-p' will prompt you for
;;  the keywords you wish to add to the message.

;;  The keywords are added to 3 separate places in the message.
;;    - In abbreviated form (1st character of each keyword) enclosed
;;      in square brackets at the start of the subject header.
;;    - In a "X-Reviewer-Action:" header (full keywords).
;;    - At line 0, column 0 of the message body.

;;  To see how to setup a "X-Reviewer-Action:" header, see
;;  `gnus-posting-styles'

;;  Many thanks to Adrian Aichner <> for his ideas,
;;  code examples and testing.

;;; Code:
  (require 'message)
  (autoload 'gnus-continuum-version "gnus"))

(defgroup patch-review nil
  "Patch submission review."
  :group 'mail)

(defcustom patch-keywords
  "List of keywords used for reviewing patches.

The default values are the keywords currently used by the XEmacs
Review Board.  There is a slight inconsistency here because \"4\"
and \"5\" are not complete keywords.  They represent \"21.4\" and
\"21.5\" respectively.  They are cut down here for the convenience
of a `replace-match'."
  :group 'patch-review
  :type '(repeat (string :tag "Review Action Keyword"))
  :tag "Action Keywords")

(defcustom patch-review-mua 'gnus
  "The MUA (Mail User Agent) you use for reviewing patches.

Currently, the only MUA that is supported is Gnus.  VM isn't supported
yet, but hopefully soon.  Should we even bother with things like MEW
or Rmail?"
  :group 'patch-review
  :type '(choice
	  (item gnus)
	  (item vm\ \(Not\ Supported\))
	  (item mew\ \(Not\ Supported\))
	  (item rmail\ \(Not\ Supported\)))
  :tag "MUA")

(defcustom patch-keywords-followup-to "XEmacs Beta <>"
  "The address to put into the \"Mail-Followup-To:\" header.
This is so that any further discussions relating to the submitted
patch can take place in a separate forum."
  :group 'patch-review
  :type 'string
  :tag "Followups Address")

;; I use the bleeding edge Gnus (Oort 0.05), so consequently we have
;; to define a couple of functions that aren't in the XEmacs package
;; version of Gnus (5.8.8).  Later on they're wrapped in a version
;; test.
(defun patch-keywords-in-header-p ()
  "Return t if point is in the header.
Same as `message-point-in-header-p' which exists in Gnus Oort, but not
in Gnus 5.8.8"
    (let ((p (point)))
      (goto-char (point-min))
      (not (re-search-forward
 	    (concat "^" (regexp-quote mail-header-separator) "\n")
 	    p t)))))

(defun patch-keywords-message-beginning-of-line (&optional n)
  "Move point to beginning of header value or to beginning of line.
Optional argument N non-nil or 1, move forward N - 1 lines first.
Same as `message-beginning-of-line' which exists in Gnus Oort, but not
in Gnus 5.8.8."
  (interactive "p")
  (if (if (< (gnus-continuum-version gnus-version) 5.090004)
      (let* ((here (point))
	     (bol (progn (beginning-of-line n) (point)))
	     (eol (gnus-point-at-eol))
	     (eoh (re-search-forward ": *" eol t)))
	(if (or (not eoh) (equal here eoh))
	    (goto-char bol)
	  (goto-char eoh)))
    (beginning-of-line n)))

(defun patch-keywords-insert (patch-key)
  "Insert the action keywords into patch followups.

Argument PATCH-KEY A list of action keywords as defined in
`patch-keywords'.  They may be chosen interactively via the
history mechanism.

Insert abbreviated (1st char) keywords at the beginning of the subject
header.  Full keywords into the \"X-Reviewer-Action:\" header, if
present, and also at the start of the message body.

The \"X-Reviewer-Action:\" header can be easily inserted using

This function also sets followups to"
       ((hist patch-keywords)
     (while (not
              (setq key
		     "Enter patch keywords (or RET to finish): " "" 'hist))
       (setq keys (cons key keys)))
     (list (mapconcat 'identity (reverse keys) " "))))
  (if (string-equal patch-key "")
      (error "Choose at least one patch-key from %s"
             (mapconcat 'identity patch-keywords ", ")))
    ;; We need to preserve the original subject header so something
    ;; like "fix for 21.5 not for 21.4" doesn't turn into "fix for
    ;; 21.5not for 21.4"
    (if (< (gnus-continuum-version gnus-version) 5.090004)
    (re-search-forward ".*$" (eolp) t)
    (let ((oldsub (match-string 0))
	  (keywords (concat "\\("
			    (regexp-opt patch-keywords)
			    "\\) ")))
      ;; Clear the original subject (reinstate it later)
      (if (< (gnus-continuum-version gnus-version) 5.090004)
      (if (re-search-forward ".*$" (eolp) t)
	  (replace-match ""))
      ;; Insert the long patch keywords
       (concat "[" patch-key " ]"))
      (insert-string " ")
      ;; Convert to abbreviated patch keywords
      (if (< (gnus-continuum-version gnus-version) 5.090004)
        (narrow-to-region (point) (point-at-eol))
        (while (re-search-forward keywords (eolp) t)
          (let ((keyword (match-string 1)))
            (if (save-match-data
                  (string-match "\\`[.0-9]+\\'" keyword))
                (replace-match (match-string 1))
              (replace-match (substring (match-string 1) 0 1))))))
      ;; Reinstate the original subject header after the keywords
      (insert-string oldsub))
    ;; Insert keywords into the 'X-Reviewer-Action:' header
    (goto-line 0)
    (if (re-search-forward "^X-Reviewer-Action: " nil t)
	(insert-string patch-key))
    ;; Set followups to go to xemacs-beta
    (if (< (gnus-continuum-version gnus-version) 5.090004)
	(message-position-on-field "Mail-Followup-To" "From")
    (insert-string patch-keywords-followup-to)
    ;; Insert the keywords into the body of the message
    (insert-string patch-key)
    (insert-string "\n\n")))

;; Bind 'patch-keywords-insert' to M-p in 'message-mode'
(define-key message-mode-map "\M-p" 'patch-keywords-insert)

(provide 'patch-keywords)

;;; patch-keywords.el ends here

;Local Variables:
;time-stamp-start: "Last-Modified:[ 	]+\\\\?[\"<]+"
;time-stamp-end: "\\\\?[\">]"
;time-stamp-line-limit: 10
;time-stamp-format: "%4y-%02m-%02d %02H:%02M:%02S (%u)"