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