b07b76deb7978be1b9c92588e2435f96da618abd
[gnus] / texi / texi2latex.el
1 ;;; texi2latex.el --- convert a texi file into a LaTeX file.
2 ;; Copyright (C) 1996, 2004 Lars Magne Ingebrigtsen
3
4 (require 'cl)
5
6 (defun latexi-discard-until (string)
7   (let ((beg (match-beginning 0)))
8     (unless (re-search-forward (concat "^@end +" string "[ \t]*\n") nil t)
9       (error "No end: %s" string))
10     (delete-region beg (match-end 0))))
11
12 (defun latexi-strip-line ()
13   (delete-region (progn (beginning-of-line) (point))
14                  (progn (forward-line 1) (point))))
15
16 (defun latexi-switch-line (command arg)
17   (latexi-strip-line)
18   (insert (format "\\%s{%s}\n" command arg)))
19
20 (defun latexi-index-command (command arg)
21   (latexi-strip-line)
22   (insert (format "\\gnus%sindex{%s}\n" 
23                   (if (equal command "kindex") "k" "")
24                   arg)))
25
26 (defun latexi-begin-command (command)
27   (latexi-strip-line)
28   (insert (format "\\begin{%s}\n" command)))
29
30 (defun latexi-exchange-command (command arg)
31   (delete-region (match-beginning 0) (match-end 0))
32   (insert (format "\\%s{%s}" command arg)))
33
34 (defun latexi-translate ()
35   "Translate."
36   (interactive)
37   (latexi-translate-file "gnus")
38   (latexi-translate-file "gnus-faq")
39   (latexi-translate-file "message" t)
40   (latexi-translate-file "emacs-mime" t)
41   (latexi-translate-file "sieve" t)
42   (latexi-translate-file "pgg" t)
43   (latexi-translate-file "sasl" t)
44   (latexi-translate-file "gnus-news" t))
45
46 (defun latexi-translate-file (file &optional as-a-chapter)
47   "Translate file a LaTeX file."
48   (let ((item-string "")
49         (item-stack nil)
50         (list-stack nil)
51         (latexi-buffer (get-buffer-create "*LaTeXi*"))
52         verbatim
53         (regexp 
54          (concat 
55             "@\\([^{} \t\n]+\\)"
56             "\\(\\( +\\(.*$\\)\\|[ \t]*$\\)\\|{\\([^}]*\\)}\\)"))
57         (cur (find-file-noselect (concat (or (getenv "srcdir") ".") 
58                                          "/" file ".texi")))
59         (times 3)
60         (chapter 0)
61         command arg)
62     (pop-to-buffer latexi-buffer)
63     (buffer-disable-undo)
64     (erase-buffer)
65     (insert-buffer-substring cur)
66     (goto-char (point-min))
67     (latexi-strip-line)
68     (latexi-translate-string "@'e" "\\'{e}")
69     (latexi-translate-string "@`a" "\\`{a}")
70     (latexi-translate-string "@,{c}" "\\c{c}")
71     (latexi-translate-string "@aa{}" "{\\aa}")
72     (latexi-translate-string "@\"{@dotless{i}}" "ï")
73     (latexi-translate-string "%@{" "\\gnuspercent{}\\gnusbraceleft{}")
74     (latexi-translate-string "%@}" "\\gnuspercent{}\\gnusbraceright{}")
75     (latexi-translate-string "%1@{" "\\gnuspercent{}1\\gnusbraceright{}")
76     (latexi-translate-string "@*" "\\newline{}")
77     (latexi-translate-string "S@{" "S\\gnusbraceleft{}")
78     (latexi-translate-string "@code{\\222}" "@code{\\gnusbackslash{}222}")
79     (latexi-translate-string "@code{\\264}" "@code{\\gnusbackslash{}264}")
80     (latexi-translate-string "@samp{\\Deleted}" "@samp{\\gnusbackslash{}Deleted}")
81     (latexi-translate-string "@samp{\\Seen}" "@samp{\\gnusbackslash{}Seen}")
82     (latexi-translate-string "@file{c:\\myhome}" "@file{c:\\gnusbackslash{}myhome}")
83 ;    (while (re-search-forward "{\"[^\"]*\\(\\\\\\)[^\"]*\"}\\\\" nil t)
84 ;      (replace-match "\\verb+\\\\+ " t t))
85     (while (not (zerop (decf times)))
86       (goto-char (point-min))
87       (while (re-search-forward regexp nil t)
88         (setq command (match-string 1))
89         (if (match-beginning 3)
90             (progn
91               (setq arg (or (match-string 4) ""))
92               (save-match-data
93                 (when (string-match "[ \t]+$" arg)
94                   (setq arg (substring arg 0 (match-beginning 0)))))
95               (cond 
96                ((member command '("c" "comment"))
97                 (if (string-match "@icon" (or arg ""))
98                     (progn
99                       (beginning-of-line)
100                       (delete-region (point) (+ (point) 4))
101                       (insert "\\gnus"))
102                   (delete-region (match-beginning 0) 
103                                  (progn (end-of-line) (point))))
104                 (if (equal arg "@head")
105                     (insert "\\gnusinteresting")))
106                ((member command '("setfilename" "set"
107                                   "synindex" "setchapternewpage"
108                                   "summarycontents" "bye"
109                                   "top" "iftex" "cartouche" 
110                                   "iflatex" "finalout" "vskip"
111                                   "dircategory" "group" "syncodeindex"
112                                   "documentencoding"))
113                 (latexi-strip-line))
114                ((member command '("menu" "tex" "ifinfo" "ignore" 
115                                   "ifnottex" "direntry"))
116                 (latexi-discard-until command))
117                ((member command '("subsection" "subsubsection"))
118                 (if as-a-chapter
119                     (latexi-switch-line (format "sub%s" command) arg)
120                   (latexi-switch-line command arg)))
121                ((member command '("heading"))
122                 (if as-a-chapter
123                     (latexi-switch-line "subsection*" arg)
124                   (latexi-switch-line "section*" arg)))
125                ((member command '("subheading"))
126                 (if as-a-chapter
127                     (latexi-switch-line "subsubsection*" arg)
128                   (latexi-switch-line "subsection*" arg)))
129                ((member command '("subsubheading"))
130                 (if as-a-chapter
131                     (latexi-switch-line "subsubsubsection*" arg)
132                   (latexi-switch-line "subsubsection*" arg)))
133                ((member command '("chapter"))
134                 (if (string-match "Index" arg)
135                     (latexi-strip-line)
136                   (if as-a-chapter
137                       (latexi-switch-line "gnussection" arg)
138                     (latexi-switch-line 
139                      (format 
140                       "gnus%s{%s}" command
141                       (format "\\epsfig{figure=ps/new-herd-%d,scale=.5}"
142                               (if (> (incf chapter) 9) 9 chapter)))
143                      arg))))
144                ((member command '("section"))
145                 (if as-a-chapter
146                     (latexi-switch-line "subsection" arg)
147                   (latexi-switch-line (format "gnus%s" command) arg)))
148                ((member command '("cindex" "findex" "kindex" "vindex"))
149                 (latexi-index-command command arg))
150                ((member command '("*"))
151                 (delete-char -2)
152                 (insert "\\\\"))
153                ((equal command "sp")
154                 (replace-match "" t t))
155                ((equal command ":")
156                 (replace-match "" t t))
157                ((member command '("deffn" "defvar" "defun"))
158                 (replace-match "" t t))
159                ((equal command "node")
160                 (latexi-strip-line)
161                 (unless (string-match "Index" arg)
162                   (insert (format "\\label{%s}\n" arg))))
163                ((equal command "contents")
164                 (latexi-strip-line)
165                 ;;(insert (format "\\tableofcontents\n" arg))
166                 )
167                ((member command '("titlepage"))
168                 (latexi-begin-command command))
169                ((member command '("lisp" "example" "smallexample" "display"))
170                 (latexi-strip-line)
171                 (insert (format "\\begin{verbatim}\n"))
172                 (setq verbatim (point)))
173                ((member command '("center"))
174                 (latexi-strip-line)
175                 (insert (format "\\begin{%s}%s\\end{%s}\n"
176                                 command arg command)))
177                ((member command '("end"))
178                 (cond
179                  ((member arg '("titlepage"))
180                   (latexi-strip-line)
181                   (insert (format "\\end{%s}\n" arg)))
182                  ((equal arg "quotation")
183                   (latexi-strip-line)
184                   (insert (format "\\end{verse}\n")))
185                  ((member arg '("lisp" "example" "smallexample" "display"))
186                   (latexi-strip-line)
187                   (save-excursion
188                     (save-restriction
189                       (narrow-to-region verbatim (point))
190                       (goto-char (point-min))
191                       (while (search-forward "@{" nil t)
192                         (replace-match "{" t t))
193                       (goto-char (point-min))
194                       (while (search-forward "@}" nil t)
195                         (replace-match "}" t t))))
196                   (setq verbatim nil)
197                   (insert "\\end{verbatim}\n"))
198                  ((member arg '("table"))
199                   (setq item-string (pop item-stack))
200                   (latexi-strip-line)
201                   (insert (format "\\end{%slist}\n" (pop list-stack))))
202                  ((member arg '("itemize" "enumerate"))
203                   (setq item-string (pop item-stack))
204                   (latexi-strip-line)
205                   (insert (format "\\end{%s}\n" arg)))
206                  ((member arg '("iflatex" "iftex" "cartouche" "group"))
207                   (latexi-strip-line))
208                  ((member arg '("deffn" "defvar" "defun"))
209                   (latexi-strip-line))
210                  (t
211                   (error "Unknown end arg: %s" arg))))
212                ((member command '("table"))
213                 (push item-string item-stack)
214                 (push (substring arg 1) list-stack)
215                 (setq item-string 
216                       (format "[@%s{%%s}]" (car list-stack)))
217                 (latexi-strip-line)
218                 (insert (format "\\begin{%slist}\n" (car list-stack))))
219                ((member command '("itemize" "enumerate"))
220                 (push item-string item-stack)
221                 (cond 
222                  ((member arg '("@bullet"))
223                   (setq item-string "[\\gnusbullet]"))
224                  (t
225                   (setq item-string "")))
226                 (latexi-strip-line)
227                 (insert (format "\\begin{%s}\n" command)))
228                ((member command '("item"))
229                 (latexi-strip-line)
230                 (insert (format "\\%s%s\n" command (format item-string arg))))
231                ((equal command "itemx")
232                 (latexi-strip-line)
233                 (insert (format "\\gnusitemx{%s}\n" (format item-string arg))))
234                ((eq (aref command 0) ?@)
235                 (goto-char (match-beginning 0))
236                 (delete-char 2)
237                 (insert "duppat{}"))
238                ((equal command "settitle")
239                 (latexi-strip-line)
240                 (if (not as-a-chapter)
241                     (insert 
242                      (format "\\newcommand{\\gnustitlename}{%s}\n" arg))))
243                ((equal command "title")
244                 (latexi-strip-line)
245                 (insert (format "\\gnustitlename{%s}\n" arg)))
246                ((equal command "author")
247                 (latexi-strip-line)
248                 (insert (format "\\gnusauthor{%s}\n" arg)))
249                ((equal command "quotation")
250                 (latexi-begin-command "verse"))
251                ((equal command "page")
252                 (latexi-strip-line)
253                 (insert "\\newpage\n"))
254                ((equal command "'s")
255                 (goto-char (match-beginning 0))
256                 (delete-char 1))
257                ((equal command "include")
258                 (latexi-strip-line)
259                 (string-match "\\.texi" arg)
260                 (insert (format "\\input{%s.latexi}\n" 
261                                 (substring arg 0 (match-beginning 0)))))
262                ((equal command "noindent")
263                 (latexi-strip-line)
264                 (insert "\\noindent\n"))
265                ((equal command "printindex")
266                 (latexi-strip-line)
267                 ;;(insert 
268                 ;; (format 
269                 ;;  "\\begin{theindex}\\input{gnus.%s}\\end{theindex}\n" arg))
270                 )
271                (t
272                 (error "Unknown command (file %s line %d): %s"
273                        file
274                        (save-excursion
275                          (widen)
276                          (1+ (count-lines (point-min) (progn
277                                                         (beginning-of-line)
278                                                         (point)))))
279                        command))))
280           ;; These are commands with {}.
281           (setq arg (match-string 5))
282           (cond 
283            ((member command '("anchor"))
284             (latexi-strip-line))
285            ((member command '("ref" "xref" "pxref"))
286             (latexi-exchange-command (concat "gnus" command) arg))
287            ((member command '("sc" "file" "dfn" "emph" "kbd" "key" "uref"
288                               "code" "samp" "var" "strong" "i"
289                               "result" "email" "env" "r" "command" "asis"
290                               "url"))
291             (goto-char (match-beginning 0))
292             (delete-char 1)
293             (insert "\\gnus"))
294            ((member command '("acronym"))
295             (latexi-exchange-command (concat "gnus" command) (downcase arg)))
296            ((member command '("copyright" "footnote" "TeX"))
297             (goto-char (match-beginning 0))
298             (delete-char 1)
299             (insert "\\"))
300            ((member command '("dots"))
301             (goto-char (match-beginning 0))
302             (delete-region (match-beginning 0) (match-end 0))
303             (insert "..."))
304            ((eq (aref command 0) ?@)
305             (goto-char (match-beginning 0))
306             (delete-char 2)
307             (insert "duppat{}"))
308            (t
309             (error "Unknown command (file %s line %d): %s"
310                    file
311                    (save-excursion
312                      (widen)
313                      (1+ (count-lines (point-min) (progn
314                                                     (beginning-of-line)
315                                                     (point)))))
316                    command))))))
317     (latexi-translate-string "$" "\\gnusdollar{}")
318     (latexi-translate-string "&" "\\gnusampersand{}")
319     (latexi-translate-string "%" "\\gnuspercent{}")
320     (latexi-translate-string "#" "\\gnushash{}")
321     (latexi-translate-string "^" "\\gnushat{}")
322     (latexi-translate-string "~" "\\gnustilde{}")
323     (latexi-translate-string "_" "\\gnusunderline{}")
324     (latexi-translate-string "¬" "\\gnusnot{}")
325     (goto-char (point-min))
326     (while (search-forward "duppat{}" nil t)
327       (replace-match "@" t t))
328     (latexi-translate-string "@@" "@")
329     (latexi-translate-string "<" "\\gnusless{}")
330     (latexi-translate-string ">" "\\gnusgreater{}")
331     (goto-char (point-min))
332     (search-forward "label{Top}" nil t)
333     (while (re-search-forward "\\\\[ntr]\\b" nil t)
334       (when (save-match-data
335               (or (not (save-excursion
336                          (search-backward "begin{verbatim}" nil t)))
337                   (> (save-excursion
338                        (search-backward "end{verbatim"))
339                      (save-excursion
340                        (search-backward "begin{verbatim}")))))
341         (goto-char (match-beginning 0))
342         (delete-char 1)
343         (insert "\\gnusbackslash{}")))
344     (latexi-translate-string "\\\\" "\\gnusbackslash{}")
345     (goto-char (point-min))
346     (while (re-search-forward "\\\\[][{}]" nil t)
347       (goto-char (match-beginning 0))
348       (delete-char 1))
349     (latexi-contributors)
350     (let ((coding-system-for-write 'iso-8859-1))
351       (write-region (point-min) (point-max) (concat file ".latexi")))))
352
353 (defun latexi-translate-string (in out)
354   (let (yes)
355     (goto-char (point-min))
356     (search-forward "label{Top}" nil t)
357     (while (search-forward in nil t)
358       (when (save-match-data
359               (or (not (save-excursion
360                          (search-backward "begin{verbatim}" nil t)))
361                   (> (save-excursion
362                        (re-search-backward "end{verbatim}\\|end{verse}"))
363                      (save-excursion
364                        (re-search-backward
365                         "begin{verbatim}\\|begin{verse}")))))
366         (replace-match out t t)))))
367
368 (defun latexi-contributors ()
369   (goto-char (point-min))
370   (when (re-search-forward "^Also thanks to the following" nil t)
371     (forward-line 2)
372     (narrow-to-region
373      (point)
374      (1- (search-forward "\n\n")))
375     (when (re-search-backward "^and" nil t)
376       (latexi-strip-line))
377     (goto-char (point-min))
378     (while (re-search-forward "[.,] *$" nil t)
379       (replace-match "" t t))
380     (goto-char (point-min))
381     (let (names)
382       (while (not (eobp))
383         (push (buffer-substring (point) (progn (end-of-line) (point)))
384               names)
385         (forward-line 1))
386       (delete-region (point-min) (point-max))
387       (insert "\\begin{tabular}{lll}\n")
388       (setq names (nreverse (delete "" names)))
389       (while names
390         (insert (pop names) " & " (or (pop names) "\\mbox{}") 
391                 " & " (or (pop names) "\\mbox{}") 
392                 "\\\\\n"))
393       (insert "\\end{tabular}\n")
394       (widen))))
395