Initial Commit
[packages] / xemacs-packages / w3 / lisp / w3-latex.el
1 ;;; w3-latex.el --- Emacs-W3 printing via LaTeX
2 ;; Author: wmperry
3 ;; Created: 1996/06/30 18:08:34
4 ;; Version: 1.3
5 ;; Keywords: hypermedia, printing, typesetting
6
7 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
8 ;;; Copyright (c) 1996, 1997 by Stephen Peters <speters@cygnus.com>
9 ;;;
10 ;;; This file is part of GNU Emacs.
11 ;;;
12 ;;; GNU Emacs is free software; you can redistribute it and/or modify
13 ;;; it under the terms of the GNU General Public License as published by
14 ;;; the Free Software Foundation; either version 2, or (at your option)
15 ;;; any later version.
16 ;;;
17 ;;; GNU Emacs is distributed in the hope that it will be useful,
18 ;;; but WITHOUT ANY WARRANTY; without even the implied warranty of
19 ;;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
20 ;;; GNU General Public License for more details.
21 ;;;
22 ;;; You should have received a copy of the GNU General Public License
23 ;;; along with GNU Emacs; see the file COPYING.  If not, write to the
24 ;;; Free Software Foundation, Inc., 59 Temple Place - Suite 330,
25 ;;; Boston, MA 02111-1307, USA.
26 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
27 ;;; Elisp code to convert a W3 parse tree into a LaTeX buffer.
28 ;;;
29 ;;; Heavily hacked upon by William Perry <wmperry@cs.indiana.edu> to add more
30 ;;; bells and whistles.
31 ;;;
32 ;;; KNOWN BUGS:
33 ;;; 1) This does not use stylesheets to get the formatting information
34 ;;; 2) This means that the new drawing routines need to be abstracted
35 ;;;    further so that the same main engine can be used for either
36 ;;;    text-output (standard stuff in w3-draw), LaTeX output (this file),
37 ;;;    Postscript (to-be-implemented), etc., etc.
38 ;;; 3) This still doesn't handle tables.
39 ;;;
40 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
41 (require 'w3-cus)
42 (require 'w3-print)
43
44 ;; Internal variables - do not touch!
45 (defvar w3-latex-current-url nil "What URL we are formatting")
46 (defvar w3-latex-verbatim nil "Whether we are in a {verbatim} block or not")
47 (defvar w3-latex-links-list nil "List of links for endnote usage")
48
49 (defvar w3-latex-entities
50   '((nbsp . "~")
51     (iexcl . "!`")
52 ;   (cent . "")
53     (pound . "\\pounds ")
54 ;   (curren . "")
55 ;   (yen . "")
56     (brvbar . "|")
57     (sect . "\\S")
58     (uml . "\\\"{ }")
59     (copy . "\\copyright ")
60 ;   (ordf . "")
61     (laquo . "$\\ll$")
62     (not . "\\neg")
63     (shy . "-")
64     (reg . "(R)")
65     (macr . "\\={ }")
66     (deg . "$\\deg$")
67     (plusmn . "$\\pm$")
68     (sup2 . "$^{2}$")
69     (sup3 . "$^{3}$")
70     (acute . "\\'{ }")
71     (micro . "$\\mu$")
72     (para . "\\P ")
73     (middot . "$\\cdot$")
74     (cedil . "\\c{ }")
75     (sup1 . "$^{1}$")
76 ;   (ordm . "")
77     (raquo . "$\\gg$")
78     (frac14 . "$\frac{1}{4}$")
79     (frac12 . "$\frac{1}{2}$")
80     (frac34 . "$\frac{3}{4}$")
81     (iquest . "?`")
82     (Agrave . "\\`{A}")
83     (Aacute . "\\'{A}")
84     (Acirc . "\\^{A}")
85     (Atilde . "\\~{A}")
86     (Auml . "\\\"{A}")
87     (Aring . "\\AA ")
88     (AElig . "\\AE ")
89     (Ccedil . "\\c{C}")
90     (Egrave . "\\`{E}")
91     (Eacute . "\\'{E}")
92     (Ecirc . "\\^{E}")
93     (Euml . "\\\"{E}")
94     (Igrave . "\\`{I}")
95     (Iacute . "\\'{I}")
96     (Icirc . "\\^{I}")
97     (Iuml . "\\\"{I}")
98 ;   (ETH . "")
99     (Ntilde . "\\~{N}")
100     (Ograve . "\\`{O}")
101     (Oacute . "\\'{O}")
102     (Ocirc . "\\^{O}")
103     (Otilde . "\\~{O}")
104     (Ouml . "\\\"{O}")
105     (times . "$\\times$")
106     (Oslash . "\\O")
107     (Ugrave . "\\`{U}")
108     (Uacute . "\\'{U}")
109     (Ucirc . "\\^{U}")
110     (Uuml . "\\\"{U}")
111     (Yacute . "\\'{Y}")
112 ;   (THORN . "")
113     (szlig . "\\ss ")
114     (agrave . "\\`{a}")
115     (aacute . "\\'{a}")
116     (acirc . "\\^{a}")
117     (atilde . "\\~{a}")
118     (auml . "\\\"{a}")
119     (aring . "\\aa ")
120     (aelig . "\\ae ")
121     (ccedil . "\\c{c}")
122     (egrave . "\\`{e}")
123     (eacute . "\\'{e}")
124     (ecirc . "\\^{e}")
125     (euml . "\\\"{e}")
126     (igrave . "\\`{i}")
127     (iacute . "\\'{i}")
128     (icirc . "\\^{i}")
129     (iuml . "\\\"{i}")
130 ;   (eth . "")
131     (ntilde . "\\~{n}")
132     (ograve . "\\`{o}")
133     (oacute . "\\'{o}")
134     (ocirc . "\\^{o}")
135     (otilde . "\\~{o}")
136     (ouml . "\\\"{o}")
137     (divide . "$\\div$")
138     (oslash . "\\o")
139     (ugrave . "\\`{u}")
140     (uacute . "\\'{u}")
141     (ucirc . "\\^{u}")
142     (uuml . "\\\"{u}")
143     (yacute . "\\'{y}")
144 ;   (thorn . "")
145     (yuml . "\\\"{y}"))
146   "Defines mappings between `w3-html-entities' and LaTeX characters.") 
147
148 (defun w3-latex-replace-entities (str)
149   (let ((start 0))
150     (while (string-match "[\200-\377]" str start)
151       ; get the character code, and then search for a match in
152       ; w3-html-entities.  If one is found, use it to perform a lookup
153       ; in w3-latex-entities, and use the resulting match to replace
154       ; the character.
155       (let* ((match (rassq (aref str (match-beginning 0))
156                            w3-html-entities))
157              (replace (and match
158                            (assq (car match) w3-latex-entities))))
159         (if replace
160             (setq str (replace-match (cdr replace) t t str)))
161         (setq start (match-end 0))))
162     str))
163
164 (defun w3-latex-insert-string (str)
165   ;;; convert string to a LaTeX-compatible one.
166   (let ((todo (list (cons "\\\\"          "-BaCkSlAsH-")
167                     (cons "[%&#_{}$]"     "\\\\\\&")
168                     (cons "\\^"           "{\\\\textasciicircum}")
169                     (cons "~"             "{\\\\textasciitilde}")
170                     (cons "[*]"           "{\\&}")
171                     (cons "[><|]"         "$\\&$")
172                     (cons "-BaCkSlAsH-"   "$\\\\backslash$"))))
173     (if w3-latex-verbatim
174         (setq todo (append todo '(("\n" . "\\\\newline\\\\nullspace\n")
175                                   (" " . "\\\\ ")))))
176     (save-excursion
177       (set-buffer (get-buffer-create " *w3-latex-munging*"))
178       (erase-buffer)
179       (insert str)
180       (while todo
181         (goto-char (point-min))
182         (while (re-search-forward (caar todo) nil t)
183           (replace-match (cdar todo)))
184         (setq todo (cdr todo)))
185       (setq str (w3-latex-replace-entities (buffer-string))))
186     (insert str)))
187
188 (defun w3-latex-ignore (tree)
189   ;;; ignores any contents of this tree.
190   nil)
191
192 (defun w3-latex-contents (tree)
193   ;;; passes contents of subtree through to the latex-subtree
194   (let ((contents (car (cdr (cdr tree)))))
195     (while contents
196       (w3-latex-subtree (car contents))
197       (setq contents (cdr contents)))))
198
199 (defun w3-latex-html (tree)
200   (insert "% This document automatically generated by Emacs-W3 v"
201           w3-version-number "\n")
202   (if w3-latex-current-url
203       (insert "% from <URL:" w3-latex-current-url ">\n"))
204   (insert "%\n"
205           "\\batchmode\n\\begin{document}\n")
206   (insert "\\setlength{\\parindent}{0pt}\n"
207           "\\setlength{\\parskip}{1.5ex}\n")
208   (insert "\\newcommand{\\nullspace}{\\rule{0pt}{0pt}}")
209   (w3-latex-contents tree)
210   (if w3-latex-links-list (w3-latex-endnotes))
211   (insert "\\end{document}\n"))
212
213 (defun w3-latex-title (tree)
214   (if w3-latex-use-maketitle
215       (insert "\\title{")
216     (insert "\\section*{\\centering "))
217   (w3-latex-contents tree)
218   (insert "}\n")
219   (if w3-latex-use-maketitle
220       (insert "\\author{}\\date{}\n\\maketitle")))
221
222 (defun w3-latex-heading (tree)
223   ;; look through the additional markup to see if an align=right or
224   ;; align=center is in here...
225   (let ((align (assq 'align (car (cdr tree))))
226         (sym (car tree)))
227     (insert "\n\n")
228     (cond ((and align (string-equal (cdr align) "center"))
229            (insert "\\begin{center}\n"))
230           ((and align (string-equal (cdr align) "right"))
231            (insert "\\begin{flushright}\n")))
232     (cond ((eq sym 'h1) (insert "\\section*{"))
233           ((eq sym 'h2) (insert "\\subsection*{"))
234           ((eq sym 'h3) (insert "\\subsubsection*{"))
235           ((eq sym 'h4) (insert "\\subsubsection*{"))
236           ((eq sym 'h5) (insert "\\paragraph*{"))
237           ((eq sym 'h6) (insert "\\subparagraph*{")))
238     (w3-latex-contents tree)
239     (insert "}\n")
240     (cond ((and align (string-equal (cdr align) "center"))
241            (insert "\\end{center}\n"))
242           ((and align (string-equal (cdr align) "right"))
243            (insert "\\end{flushright}\n")))))
244
245 (defun w3-latex-bold (tree)
246   (insert "{\\bf ")
247   (w3-latex-contents tree)
248   (insert "}"))
249 (defun w3-latex-italic (tree)
250   (insert "{\\em ")
251   (w3-latex-contents tree)
252   (insert "}"))
253 (defun w3-latex-typewriter (tree)
254   (insert "{\\tt ")
255   (w3-latex-contents tree)
256   (insert "}"))
257
258 (defun w3-latex-list (tree)
259   (let* ((sym (car tree))
260          (list-type (cond ((eq sym 'ol) "enumerate")
261                           ((eq sym 'dl) "description")
262                           (t "itemize"))))
263     (insert (concat "\n\\begin{" list-type "}\n"))
264     (w3-latex-contents tree)
265     (insert (concat "\n\\end{" list-type "}\n"))))
266
267 (defun w3-latex-list-item (tree)
268   (let ((sym (car tree)))
269     (cond ((eq sym 'dt)
270            (insert "\n\\item["))
271           ((eq sym 'dd)
272            ;; don't do anything for dd -- the item is handled by dt.
273            nil)
274           (t (insert "\n\\item")))
275     (w3-latex-contents tree)
276     (if (eq sym 'dt)
277         (insert "]"))))
278
279 (defun w3-latex-center (tree)
280   (insert "\\begin{center}")
281   (w3-latex-contents tree)
282   (insert "\\end{center}"))
283
284 (defun w3-latex-rule (tree)
285   ; use \par to make paragraph division clear.
286   (insert "\n\\par\\noindent\\rule{\\textwidth}{.01in}\n"))
287
288 (defun w3-latex-para (tree)
289   ;; look through the additional markup to see if an align=right or
290   ;; align=center is in here...
291   (let ((align (assq 'align (car (cdr tree)))))
292     (cond ((and align
293                 (string-equal (cdr align) "center"))
294            (w3-latex-center tree))
295           ((and align
296                 (string-equal (cdr align) "right"))
297            (insert "\\begin{flushright}")
298            (w3-latex-contents tree)
299            (insert "\\end{flushright}"))
300           (t (insert "\\par ")
301              (w3-latex-contents tree)))))
302
303 (defun w3-latex-quote (tree)
304   (insert "\\begin{quote}\n")
305   (w3-latex-contents tree)
306   (insert "\\end{quote}\n"))
307
308 (defun w3-latex-break (tree)
309   ;; no content allowed
310   (insert "\\newline "))
311
312 (defun w3-latex-endnotes ()
313   (let ((i 1))
314     (insert "\\begin{thebibliography}{99}\n")
315     (while w3-latex-links-list
316       (insert (concat "\\bibitem{ref" (number-to-string i) "}"))
317       (w3-latex-insert-string (car w3-latex-links-list))
318       (insert "\n")
319       (setq w3-latex-links-list (cdr w3-latex-links-list))
320       (setq i (1+ i)))
321     (insert "\\end{thebibliography}\n")))
322
323 (defun w3-latex-href (tree)
324   (let ((href (cdr-safe (assq 'href (cadr tree))))
325         (name (cdr-safe (assq 'name (cadr tree)))))
326     (cond
327      ((not w3-latex-print-links)        ; No special treatment
328       (w3-latex-contents tree))
329      (name
330       (w3-latex-contents tree)
331       (insert (concat "\\label{" name "}")))
332      (href                              ; Special treatment requested
333 ;      (insert "\\underline{")          ; and we have a URL - underline
334       (w3-latex-contents tree)          ; it.
335 ;      (insert "}")
336       (cond 
337        ((char-equal ?# (aref href 0))
338         (insert (concat " (see page~\\pageref{"
339                         (substring href 1)
340                         "})")))
341        ((eq w3-latex-print-links 'footnote)
342         (insert "\\footnote{")          ; Request to prepare footnote 
343         (w3-latex-insert-string href)
344         (insert "}"))
345        (t                               ; Otherwise, prepare endnotes
346         (let ((mem (member href w3-latex-links-list))
347               (i (1+ (length w3-latex-links-list))))
348           (if mem
349               (setq i (- i (length mem)))
350             (setq w3-latex-links-list
351                   (append w3-latex-links-list (cons href nil))))
352           (insert (concat "~\\cite{ref" (number-to-string i) "}"))))))
353      (t                                 ; Special treatment requested, but
354       (w3-latex-contents tree)))))      ; no URL - do nothing.
355
356 (defun w3-latex-preformatted (tree)
357   (let ((w3-latex-verbatim t))
358     (insert "\\par\\noindent\\begin{tt}")
359     (w3-latex-contents tree)
360     (insert "\\end{tt}\\par")
361     ))
362
363 (defun w3-latex-xmp (tree)
364   (insert "\\begin{verbatim}")
365   (w3-latex-contents tree)
366   (insert "\\end{verbatim}"))
367
368 (let ((todo '((title . w3-latex-title)
369               (html . w3-latex-html)
370               (pre . w3-latex-preformatted)
371               (xmp . w3-latex-xmp)
372               (h1 . w3-latex-heading)
373               (h2 . w3-latex-heading)
374               (h3 . w3-latex-heading)
375               (h4 . w3-latex-heading)
376               (h5 . w3-latex-heading)
377               (h6 . w3-latex-heading)
378               (a  . w3-latex-href)
379               (strong . w3-latex-bold)
380               (b . w3-latex-bold)
381               (dfn . w3-latex-bold)
382               (em . w3-latex-italic)
383               (i . w3-latex-italic)
384               (address . w3-latex-italic)
385               (code . w3-latex-typewriter)
386               (samp . w3-latex-typewriter) 
387               (tt . w3-latex-typewriter)
388               (kbd . w3-latex-typewriter) 
389               (var . w3-latex-typewriter)
390               (ol . w3-latex-list)
391               (dl . w3-latex-list)
392               (ul . w3-latex-list) 
393               (menu . w3-latex-list)
394               (dir . w3-latex-list)
395               (li . w3-latex-list-item)
396               (dt . w3-latex-list-item) 
397               (dd . w3-latex-list-item)
398               (center . w3-latex-center)
399               (hr . w3-latex-rule)
400               (p . w3-latex-para)
401               (br . w3-latex-break)
402               (blockquote . w3-latex-quote))))
403   (while todo
404     (put (caar todo) 'w3-latex-formatter (cdar todo))
405     (setq todo (cdr todo))))
406
407 (defun w3-latex-subtree (tree)
408   (cond
409    ((stringp tree)
410     (w3-latex-insert-string tree))
411    ((stringp (car-safe tree))
412     (while tree
413       (w3-latex-insert-string (car tree))
414       (setq tree (cdr tree))))
415    ((symbolp (car tree))
416     (let ((proc (get (car tree) 'w3-latex-formatter)))
417       (if (and proc (fboundp proc))
418           (funcall proc tree)
419         ;; anything else gets passed through unchanged
420         (w3-latex-contents tree))))
421    (t
422     (w3-latex-contents tree))))
423
424 ;; Fixme: url-working-buffer is never defined.
425 ;;;###autoload
426 (defun w3-parse-tree-to-latex (tree &optional url)
427   ; assumes that url-working-buffer exists.
428   (set-buffer (get-buffer-create url-working-buffer))
429   (setq w3-latex-current-url url)
430   (erase-buffer)
431   (goto-char (point-min))
432   (if w3-latex-use-latex2e
433       (insert (concat "\\documentclass" w3-latex-docstyle "\n"))
434     (insert (concat "\\documentstyle" w3-latex-docstyle "\n")))
435   (if (and w3-latex-use-latex2e
436            w3-latex-packages)
437       (insert (apply 'concat
438                      (mapcar (lambda (x) (concat "\\usepackage{" x "}\n"))
439                              w3-latex-packages))))
440   (while tree
441     (w3-latex-subtree (car tree))
442     (setq tree (cdr tree))))
443
444 ;;;###autoload
445 (defun w3-show-dvi ()
446   "Uses xdvi to show DVI file created from `w3-parse-tree-to-latex'."
447   (interactive)
448   (w3-parse-tree-to-latex w3-current-parse)
449   (save-window-excursion
450     (set-buffer url-working-buffer)
451     (let ((coding-system-for-write 'binary))
452       (write-region
453      (point-min) (point-max)
454      (expand-file-name "w3-tmp.latex"
455                          w3-temporary-directory) nil 5))
456     (shell-command
457      (format 
458       "(cd %s ; latex w3-tmp.latex ; latex w3-tmp.latex ; xdvi w3-tmp.dvi ; rm -f w3-tmp*) &"
459       w3-temporary-directory))))
460
461 (provide 'w3-latex)