;;; latexbug.el
;;;
;;; Version 0: `test of concept'
;;; Don't look to closely at my lisp coding style...
;;;
;;; David Carlisle
;;; Version 0.1 1994/11/23
;;; Version 0.2 1994/12/12
;;; Version 0.3 1995/03/17
;;; Version 0.4 1995/09/21
;;; Version 0.5 1995/10/17
;;; Version 0.6 1997/07/16
;;; Version 0.7 1997/12/17
;;; Version 0.8 1999/01/07
;;;
;;;
;;; LOADING
;;;;;;;;;;;
;;;
;;; To use this code, place the file in a directory searched by lisp
;;; Add
;;;
;;; (autoload 'report-latex-bug "latexbug"
;;; "LaTeX bug report generator" t)
;;;
;;; to your .emacs file (without the ;;;).
;;;
;;; Then if the impossible happens and you discover a bug in LaTeX,
;;; or wish to suggest a change to LaTeX, type
;;; M-x report-latex-bug
;;;
;;; and follow the instructions.
;;;
;;; A file latexbug.cfg can be used to customise
;;; latexbug.tex as described in the comments in latexbug.tex.
;;; or you can customise in your .emacs, as shown below.
;;;
;;; CUSTOMISATION
;;;;;;;;;;;;;;;;;;
;;;
;;; The following variables may be set in your .emacs to customise this
;;; file.
;;;
;;; (setq ltxbug-name "David Carlisle") ; your name
;;; (setq ltxbug-address "dpc@,,,") ; your email address
;;; If these two are not set here, or in the latexbug.cfg
;;; file. emacs will prompt for the values. The prompt
;;; will suggest default values based on standard emacs variables
;;; user-full-name and user-mail-address.
;;;
;;; (setq ltxbug-mail-headers "...") ; additional mail headers.
;;; For example (setq ltxbug-mail-headers "FCC: ~/Mail/sent")
;;; To log outgoing mail in a `sent' file.
;;;
;;; (setq ltxbug-latex-command "...") ; latex command
;;; Set this if LaTeX is not called latex, eg it may be latex2e.
;;;
;;;
;;; Perhaps I should have based this on gnat's send-pr.el but it seemed
;;; easier to write it from scratch to work in latexbug.tex at the
;;; required points.
;;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
(require 'sendmail)
(defvar ltxbug-latex-command "latex"
"Command name for Standard LaTeX (LaTeX2e)")
(defvar ltxbug-directory nil
"Directory in which to run LaTeX, should end with slash.
Default, nil, means inherit directory from current buffer.")
(defvar user-full-name nil); just needed on ancient emacs
(defvar ltxbug-name nil
"Your name.
If this is nil, will be prompted if not set in latexbug.cfg.")
(defvar user-mail-address nil); just needed on ancient emacs
(defvar ltxbug-address nil
"Your email-address.
If this is nil, will be prompted if not set in latexbug.cfg.")
(defvar ltxbug-mail-headers ""
"Extra mail headers that will be added to the mail message.
This is in addition to `To' and `Subject'.")
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
(defvar ltxbug-categories
'(("latex") ("tools") ("graphics")
("mfnfss") ("psnfss") ("amslatex") ("babel") ("expl3") ("cyrillic"))
"Valid GNATS categories")
(defun report-latex-bug ()
"LaTeX bug report generator"
(interactive)
;;
;; Locally turn off transient mark mode.
(let ((transient-mark-mode nil)
(current-default-directory default-directory))
;;
;; First produce one large window for the main message
;; and a smaller help window below.
(delete-other-windows)
;; (setq ltxbug-msg (switch-to-buffer "*latex-bugs*")); not emacs18
(switch-to-buffer
(setq ltxbug-msg (get-buffer-create "*latex-bugs*")))
(erase-buffer)
(setq default-directory
(or ltxbug-directory current-default-directory))
(setq major-mode 'ltxbug)
(setq mode-name "LaTeX Bug Report")
(use-local-map ltxbug-map)
(message "Running latex on latexbug.tex ....")
(split-window-vertically
;; -13 ;; old emacs's can't do this
(- (window-height) 13))
(switch-to-buffer-other-window
(setq ltxbug-help (get-buffer-create "latexbugs help")))
;;
;; Initially fill the message buffer with the output from running
;; latexbug.tex.
(erase-buffer)
;;
;; Use shell-command not start-process here so shell variables are
;; initialised before calling LaTeX.
;; Hope that is enough \\ to keep all the different shells happy...
;; {} replaced by \\{\\} in version 0.4 (fix for latex/1675)
;; Use \@@input (v0.5)
(shell-command (concat
ltxbug-latex-command
" \\\\nonstopmode\\\\makeatletter\
\\\\def\\\\batch\\{\\}\\\\@@input latexbug ") t)
(switch-to-buffer-other-window ltxbug-msg)
(goto-char (point-min))
;;
;; Change header to mention this latexbug.el file.
(if (re-search-forward "!" (point-max) t)
(ltxbug-error)
;; else
(ltxbug-do-report))))
(defun ltxbug-do-report ()
(erase-buffer)
;;
;; Grab the template produced by latexbug.tex
(insert-file "latexbug.msg")
;;
;; Change header to mention this latexbug.el file.
(goto-char (point-min))
(re-search-forward "\\(by latexbug.\\)\\(tex\\)" (point-max) t)
(replace-match "\\1el")
;;
;; Grab email address into mail field.
(re-search-forward "Re.*email to \\(.*\\)[^Z]*=$" (point-max) t)
;;
;; Put the synopsis template into the Subject field.
;; Add the delimiter used by the mail-send function.
(goto-char (point-min))
(let ((temp
(concat "To: "
(buffer-substring (match-beginning 1) (match-end 1)) "
Subject: < SYNOPSIS >
"
ltxbug-mail-headers
(if (not (equal "" ltxbug-mail-headers)) "
")
"--text follows this line--
" )))
;;
;; Remove the rest of the banner from latexbug.tex
(goto-char (point-min))
(delete-region (match-beginning 0) (match-end 0))
;;
;; insert the mail headers
(insert temp))
;;
;;
;; Get the required category using minibuffer completion.
(set-buffer ltxbug-help)
(erase-buffer)
(insert "
Several categories of files are supported,
corresponding to directories in the standard LaTeX distribution:
latex: The `base' format, and standard classes only (base).
tools: Packages supported by the LaTeX3 project team (tools).
graphics: The color and graphics packages (graphics).
mfnfss: Packages for using some MetaFont fonts (mfnfss).
psnfss: Packages for using PostScript fonts LaTeX (psnfss).
amslatex: AMS supported Classes and Packages (amsfonts and amslatex).
babel: Packages supporting many different languages (babel).
expl3: Experimental packages for TeX programmers (expl3).
cyrillic: Packages for using Cyrillic fonts (cyrillic).
")
(let* ((completion-ignore-case t)
(cat (completing-read "Which Category ? "
ltxbug-categories nil t )))
(set-buffer "*latex-bugs*")
(ltxbug-replace "< CATEGORY >" (if (equal cat "") "latex" cat)))
;;
;; Get the synopsis, make sure it is non empty, and not too long.
(set-buffer ltxbug-help)
(erase-buffer)
(insert "
Please enter a One line Synopsis of the report.
This should be < 50 characters.
This text will be used as the mail header on all
subsequent correspondence. Please use informative strings.
For example: \\mathit generates error in foobar environmenent
rather than just `LaTeX Bug' or similar strings.
")
(set-buffer ltxbug-msg)
(let ((syn (read-from-minibuffer "Synopsis ? " )))
(while (or (equal syn "") (> (length syn) 50))
(setq syn
(read-from-minibuffer "Synopsis (0 < length < 50) ? " syn)))
(set-buffer "*latex-bugs*")
(ltxbug-replace "< SYNOPSIS >" syn))
;;
;; If latexbug.cfg has not already defined the name
;; grab it from minibuffer
(goto-char (point-min))
(if (re-search-forward "< ENTER YOUR NAME >" (point-max) t)
(if ltxbug-name
(ltxbug-replace "< ENTER YOUR NAME >" ltxbug-name)
;; else
(set-buffer ltxbug-help)
(erase-buffer)
(insert "
Please enter Your Name
")
(set-buffer ltxbug-msg)
(let ((temp (read-from-minibuffer "Your Name ? " user-full-name)))
(set-buffer "*latex-bugs*")
(ltxbug-replace "< ENTER YOUR NAME >" temp))))
;;
;; If latexbug.cfg has not already defined the email address
;; grab it from minibuffer
(goto-char (point-min))
(if (re-search-forward "< ENTER YOUR EMAIL ADDRESS >" (point-max) t)
(if ltxbug-address
(ltxbug-replace "< ENTER YOUR EMAIL ADDRESS >" ltxbug-address)
;; else
(set-buffer ltxbug-help)
(erase-buffer)
(insert "
Please enter Your email address.
")
(set-buffer ltxbug-msg)
(let ((temp (read-from-minibuffer "Your email address ? "
user-mail-address)))
(set-buffer "*latex-bugs*")
(ltxbug-replace "< ENTER YOUR EMAIL ADDRESS >" temp))))
;;
;; Grab file name.
;; If this is empty, suggest changing the >Class
(set-buffer ltxbug-help)
(erase-buffer)
(insert "
A bug report should be accompanied by a test file
and a the log that the test generates.
If a test file is not appropriate for this report
Just hit <return>
Otherwise please specify the file to include.
")
(set-buffer ltxbug-msg)
(let ((temp (read-file-name "Test file ? " nil "" t)))
(if (equal temp "")
(progn
(ltxbug-update-field
"Class"
'(("sw-bug")("doc-bug")("change-request"))
"
You have not offered a test file.
Perhaps that this is not a bug report.
The default class for messages is sw-bug.
Possible classes of messages are:
sw-bug: Message reporting a Bug in the software.
doc-bug: Message reporting an error in the documentation.
change-request: Message requesting a change to some LaTeX feature.")
(re-search-forward ">How-to-repeat")
(delete-region (match-beginning 0) (point-max)))
;; else
(set-buffer ltxbug-msg)
(ltxbug-replace " < TEST FILE HERE " "")
(insert-file temp)
(let ((lines 0))
(while (re-search-forward "\n" (mark) t)
(setq lines (+ lines 1)))
(if (> lines 60)
(progn
(set-buffer ltxbug-help)
(erase-buffer)
(insert
(format "%s%d%s" "
!!!!
Your test file is " lines " lines long!!!
Test files should be as short as possible, while still showing
the behaviour. Please try to keep the file below 60 lines.
"))
(set-buffer ltxbug-msg))))
(let* ((log1
(concat
(substring temp 0 (string-match "\\.[^\\.]*$" temp))
".log"))
(log (read-file-name "Log file ? " "" log1 t log1)))
(if (equal log "")
(message "WHY NO LOG ???")
(ltxbug-replace " < LOG FROM TEST FILE HERE >" "")
(insert-file log)))))
;;
;; Prompt for the message text.
(set-buffer ltxbug-help)
(erase-buffer)
(insert "
Complete your bug report by giving the full descripition
below the `Description of bug:' header.
There are other database fields you may wish to add,
type C-c C-f to change or add an additional field.
Once the report is complete, type C-c C-c to send the message.
A saved copy of the report will be in the file
latexbug.msg.
")
(switch-to-buffer ltxbug-msg)
(ltxbug-replace " < ENTER BUG REPORT HERE >" "")
(auto-fill-mode 1)
(setq fill-column 72))
(defun ltxbug-error ()
(set-buffer ltxbug-help)
(erase-buffer)
(insert "
LaTeX did not succesfully produce a bug report template."))
(defun ltxbug-save-and-send ()
(interactive)
(write-file "latexbug.msg")
(mail-send-and-exit nil))
(defun ltxbug-replace (a b)
"Replace the regexp a by the string b everywhere in the current buffer"
(goto-char (point-min))
(while (re-search-forward a (point-max) t)
(replace-match b t t)))
(defvar ltxbug-map (make-sparse-keymap)
"Local keymap used in LaTeX bug buffer.")
(define-key ltxbug-map "\C-c\C-c" 'ltxbug-save-and-send)
(define-key ltxbug-map "\C-c\C-f" 'ltxbug-oneline-field)
(defun ltxbug-update-field (field values help)
"Update FIELD using completion list VALUES and help text HELP.
First entry in VALUES is the default."
(interactive)
(set-buffer ltxbug-help)
(erase-buffer)
(insert help)
(goto-char (point-min))
(set-buffer ltxbug-msg)
(goto-char (point-min))
(let ((temp ""))
(if (re-search-forward
(concat"\n>" field ":\\( *\\)\\(.*\\)$") (point-max) t)
;; if field already there
(progn
(setq temp (buffer-substring (match-beginning 2) (match-end 2)))
(delete-region (match-beginning 1) (match-end 2)))
;; else
(re-search-forward ">Category:.*$")
(insert (concat "\n>" field ":")))
(insert " ")
(let ((temp2
(completing-read (concat field " ? ") values nil t temp)))
(insert (if (equal temp2 "")
(car(car values)) temp2)))))
(defun ltxbug-responsible ()
(interactive)
(ltxbug-update-field
"Responsible"
;; Alphabetical order, which makes Alan the default...
'(("alan")("chris")("david")("frank")("johannes")
("michael")("rainer"))
"
You may set the >Responsible field to a particular person.
**Do not do this unless you have very good reason.**
We may not appreciate having jobs allocated to us in this way:-)
The possible values are:
alan (Alan Jeffrey)
chris (Chris Rowley)
david (David Carlisle)
frank (Frank Mittelbach)
johannes (Johannes Braams)
michael (Michael Downes)
rainer (Rainer Schoepf)
"))
(defun ltxbug-confidential ()
(interactive)
(ltxbug-update-field
"Confidential"
'(("no")("yes"))
"
You may set the >Confidential field to yes.
The report database is publicly searchable.
See bugs.txt for details.
Reports marked Confidential will not be made public.
Possible values:
no The default. Report may be made public.
yes Report should only be seen by LaTeX maintainers.
"))
(defun ltxbug-priority ()
(interactive)
(ltxbug-update-field
"Priority"
'(("low")("medium")("high"))
"
Change the priority of the report from `high'
Possible values:
low
medium
high
"))
(defun ltxbug-severity ()
(interactive)
(ltxbug-update-field
"Severity"
'(("non-critical")("serious")("critical"))
"
Classify the severity of the problem.'
Possible values:
non-critical
serious
critical
"))
(defun ltxbug-class ()
(interactive)
(ltxbug-update-field
"Class"
'(("sw-bug")("doc-bug")("change-request"))
"
Classify the type of report.
Possible values:
sw-bug: Message reporting a bug in the software.
doc-bug: Message reporting an error in the documentation.
change-request: Message requesting a change to some LaTeX feature.
"))
(defun ltxbug-window-setup ()
(interactive)
(delete-other-windows)
(split-window-vertically -13)
(switch-to-buffer-other-window ltxbug-help))
(defun ltxbug-oneline-field ()
(interactive)
(ltxbug-window-setup)
(erase-buffer)
(insert "
You may wish to add or alter the following fields:
Class Class of this report.
Confidential Confidential (or not).
Responsible Assign to a member of the LaTeX maintenance team
Severity Severity of the bug.
Priority Priority of the report.
")
(set-buffer ltxbug-msg)
(let* ((completion-ignore-case t)
(field (completing-read "Which field ? "
'(("Class")("Confidential")("Priority")("Severity")
("Responsible"))
nil t)))
(cond
((equal field "Class") (ltxbug-class))
((equal field "Confidential") (ltxbug-confidential))
((equal field "Responsible") (ltxbug-responsible))
((equal field "Severity") (ltxbug-severity))
((equal field "Priority") (ltxbug-priority)))))
|