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