blob: 969cdc62a66ce0cac0fa94aa94524d49d93ecc21 [file] [log] [blame]
Fred Drakebfc18bd2002-05-03 04:50:51 +00001;;; py2texi.el -- Conversion of Python LaTeX documentation to Texinfo
2
3;; Copyright (C) 1998, 1999, 2001, 2002 Milan Zamazal
4
5;; Author: Milan Zamazal <pdm@zamazal.org>
6;; Version: $Id$
7;; Keywords: python
8
9;; COPYRIGHT NOTICE
10;;
11;; This program is free software; you can redistribute it and/or modify it
12;; under the terms of the GNU General Public License as published by the Free
13;; Software Foundation; either version 2, or (at your option) any later
14;; version.
15;;
16;; This program is distributed in the hope that it will be useful, but
17;; WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
18;; or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
19;; for more details.
20;;
21;; You can find the GNU General Public License at
22;; http://www.gnu.org/copyleft/gpl.html
23;; or you can write to the Free Software Foundation, Inc., 59 Temple Place,
24;; Suite 330, Boston, MA 02111-1307, USA.
25
26;;; Commentary:
27
28;; This is a Q&D hack for conversion of Python manuals to on-line help format.
29;; I desperately needed usable online documenta for Python, so I wrote this.
30;; The result code is ugly and need not contain complete information from
31;; Python manuals. I apologize for my ignorance, especially ignorance to
32;; python.sty. Improvements of this convertor are welcomed.
33
34;; How to use it:
35;; Load this file and apply `M-x py2texi'. You will be asked for name of a
36;; file to be converted.
37
38;; Where to find it:
39;; New versions of this code might be found at
40;; http://www.zamazal.org/software/python/py2texi/ .
41
42;;; Code:
43
44
45(require 'texinfo)
46(eval-when-compile
47 (require 'cl))
48
49
50(defvar py2texi-python-version "2.2"
51 "What to substitute for the \\version macro.")
52
53(defvar py2texi-python-short-version
54 (progn
55 (string-match "[0-9]+\\.[0-9]+" py2texi-python-version)
56 (match-string 0 py2texi-python-version))
57 "Short version number, usually set by the LaTeX commands.")
58
Fred Drake66abcee2002-11-13 19:31:04 +000059(defvar py2texi-texi-file-name nil
60 "If non-nil, that string is used as the name of the Texinfo file.
61Otherwise a generated Texinfo file name is used.")
62
63(defvar py2texi-info-file-name nil
64 "If non-nil, that string is used as the name of the Info file.
65Otherwise a generated Info file name is used.")
66
Fred Drakebfc18bd2002-05-03 04:50:51 +000067(defvar py2texi-stop-on-problems nil
68 "*If non-nil, stop when you encouter soft problem.")
69
70(defconst py2texi-environments
71 '(("abstract" 0 "@quotation" "@end quotation\n")
72 ("center" 0 "" "")
73 ("cfuncdesc" 3
74 (progn (setq findex t)
75 "\n@table @code\n@item \\1 \\2(\\3)\n@findex \\2\n")
Fred Drake66abcee2002-11-13 19:31:04 +000076 "@end table\n")
77 ("cmemberdesc" 3
78 "\n@table @code\n@item \\2 \\3\n"
79 "@end table\n")
Fred Drakebfc18bd2002-05-03 04:50:51 +000080 ("classdesc" 2
81 (progn (setq obindex t)
82 "\n@table @code\n@item \\1(\\2)\n@obindex \\1\n")
Fred Drake66abcee2002-11-13 19:31:04 +000083 "@end table\n")
Fred Drakebfc18bd2002-05-03 04:50:51 +000084 ("classdesc*" 1
85 (progn (setq obindex t)
86 "\n@table @code\n@item \\1\n@obindex \\1\n")
Fred Drake66abcee2002-11-13 19:31:04 +000087 "@end table\n")
Fred Drakebfc18bd2002-05-03 04:50:51 +000088 ("csimplemacrodesc" 1
89 (progn (setq cindex t)
90 "\n@table @code\n@item \\1\n@cindex \\1\n")
Fred Drake66abcee2002-11-13 19:31:04 +000091 "@end table\n")
Fred Drakebfc18bd2002-05-03 04:50:51 +000092 ("ctypedesc" 1
93 (progn (setq cindex t)
94 "\n@table @code\n@item \\1\n@cindex \\1\n")
Fred Drake66abcee2002-11-13 19:31:04 +000095 "@end table\n")
Fred Drakebfc18bd2002-05-03 04:50:51 +000096 ("cvardesc" 2
97 (progn (setq findex t)
98 "\n@table @code\n@item \\1 \\2\n@findex \\2\n")
Fred Drake66abcee2002-11-13 19:31:04 +000099 "@end table\n")
Fred Drakebfc18bd2002-05-03 04:50:51 +0000100 ("datadesc" 1
101 (progn (setq findex t)
102 "\n@table @code\n@item \\1\n@findex \\1\n")
Fred Drake66abcee2002-11-13 19:31:04 +0000103 "@end table\n")
104 ("datadescni" 1 "\n@table @code\n@item \\1\n" "@end table\n")
Fred Drakebfc18bd2002-05-03 04:50:51 +0000105 ("definitions" 0 "@table @dfn" "@end table\n")
106 ("description" 0 "@table @samp" "@end table\n")
107 ("displaymath" 0 "" "")
108 ("document" 0
109 (concat "@defcodeindex mo\n"
110 "@defcodeindex ob\n"
111 "@titlepage\n"
112 (format "@title " title "\n")
113 (format "@author " author "\n")
114 "@page\n"
115 author-address
116 "@end titlepage\n"
117 "@node Top, , , (dir)\n")
118 (concat "@indices\n"
119 "@contents\n"
120 "@bye\n"))
121 ("enumerate" 0 "@enumerate" "@end enumerate")
Fred Drake3b095582003-07-02 14:22:48 +0000122 ("envdesc" 2 (concat "\n@table @code"
123 "\n@item @backslash{}begin@{\\1@}\\2")
124 "@end table\n")
Fred Drakebfc18bd2002-05-03 04:50:51 +0000125 ("excdesc" 1
126 (progn (setq obindex t)
127 "\n@table @code\n@item \\1\n@obindex \\1\n")
Fred Drake66abcee2002-11-13 19:31:04 +0000128 "@end table\n")
Fred Drakebfc18bd2002-05-03 04:50:51 +0000129 ("excclassdesc" 2
130 (progn (setq obindex t)
131 "\n@table @code\n@item \\1(\\2)\n@obindex \\1\n")
Fred Drake66abcee2002-11-13 19:31:04 +0000132 "@end table\n")
Fred Drakebfc18bd2002-05-03 04:50:51 +0000133 ("flushleft" 0 "" "")
Fred Drake66abcee2002-11-13 19:31:04 +0000134 ("fulllineitems" 0 "\n@table @code\n" "@end table\n")
Fred Drakebfc18bd2002-05-03 04:50:51 +0000135 ("funcdesc" 2
136 (progn (setq findex t)
137 "\n@table @code\n@item \\1(\\2)\n@findex \\1\n")
Fred Drake66abcee2002-11-13 19:31:04 +0000138 "@end table\n")
139 ("funcdescni" 2 "\n@table @code\n@item \\1(\\2)\n" "@end table\n")
Fred Drakebfc18bd2002-05-03 04:50:51 +0000140 ("itemize" 0 "@itemize @bullet" "@end itemize\n")
Fred Drake66abcee2002-11-13 19:31:04 +0000141 ("list" 2 "\n@table @code\n" "@end table\n")
Fred Drakebfc18bd2002-05-03 04:50:51 +0000142 ("longtableii" 4 (concat "@multitable @columnfractions .5 .5\n"
143 "@item \\3 @tab \\4\n"
144 "@item ------- @tab ------ \n")
145 "@end multitable\n")
146 ("longtableiii" 5 (concat "@multitable @columnfractions .33 .33 .33\n"
147 "@item \\3 @tab \\4 @tab \\5\n"
148 "@item ------- @tab ------ @tab ------\n")
149 "@end multitable\n")
Fred Drake3b095582003-07-02 14:22:48 +0000150 ("macrodesc" 2 (concat "\n@table @code"
151 "\n@item \\1@{\\2@}")
152 "@end table\n")
Fred Drakebfc18bd2002-05-03 04:50:51 +0000153 ("memberdesc" 1
154 (progn (setq findex t)
155 "\n@table @code\n@item \\1\n@findex \\1\n")
Fred Drake66abcee2002-11-13 19:31:04 +0000156 "@end table\n")
157 ("memberdescni" 1 "\n@table @code\n@item \\1\n" "@end table\n")
Fred Drakebfc18bd2002-05-03 04:50:51 +0000158 ("methoddesc" 2
159 (progn (setq findex t)
160 "\n@table @code\n@item \\1(\\2)\n@findex \\1\n")
Fred Drake66abcee2002-11-13 19:31:04 +0000161 "@end table\n")
162 ("methoddescni" 2 "\n@table @code\n@item \\1(\\2)\n" "@end table\n")
Fred Drakebfc18bd2002-05-03 04:50:51 +0000163 ("notice" 0 "@emph{Notice:} " "")
164 ("opcodedesc" 2
165 (progn (setq findex t)
166 "\n@table @code\n@item \\1 \\2\n@findex \\1\n")
Fred Drake66abcee2002-11-13 19:31:04 +0000167 "@end table\n")
168 ("productionlist" 0 "\n@table @code\n" "@end table\n")
Fred Drakebfc18bd2002-05-03 04:50:51 +0000169 ("quotation" 0 "@quotation" "@end quotation")
Fred Drake66abcee2002-11-13 19:31:04 +0000170 ("seealso" 0 "See also:\n@table @emph\n" "@end table\n")
171 ("seealso*" 0 "@table @emph\n" "@end table\n")
Fred Drakebfc18bd2002-05-03 04:50:51 +0000172 ("sloppypar" 0 "" "")
173 ("small" 0 "" "")
174 ("tableii" 4 (concat "@multitable @columnfractions .5 .5\n"
175 "@item \\3 @tab \\4\n"
176 "@item ------- @tab ------ \n")
177 "@end multitable\n")
178 ("tableiii" 5 (concat "@multitable @columnfractions .33 .33 .33\n"
179 "@item \\3 @tab \\4 @tab \\5\n"
180 "@item ------- @tab ------ @tab ------\n")
181 "@end multitable\n")
182 ("tableiv" 6 (concat
183 "@multitable @columnfractions .25 .25 .25 .25\n"
184 "@item \\3 @tab \\4 @tab \\5 @tab \\6\n"
185 "@item ------- @tab ------- @tab ------- @tab -------\n")
186 "@end multitable\n")
187 ("tablev" 7 (concat
188 "@multitable @columnfractions .20 .20 .20 .20 .20\n"
189 "@item \\3 @tab \\4 @tab \\5 @tab \\6 @tab \\7\n"
190 "@item ------- @tab ------- @tab ------- @tab ------- @tab -------\n")
191 "@end multitable\n"))
192 "Associative list defining substitutions for environments.
193Each list item is of the form (ENVIRONMENT ARGNUM BEGIN END) where:
194- ENVIRONMENT is LaTeX environment name
195- ARGNUM is number of (required) macro arguments
196- BEGIN is substitution for \begin{ENVIRONMENT}
197- END is substitution for \end{ENVIRONMENT}
198Both BEGIN and END are evaled. Moreover, you can reference arguments through
199\N regular expression notation in strings of BEGIN.")
200
201(defconst py2texi-commands
202 '(("ABC" 0 "ABC")
203 ("appendix" 0 (progn (setq appendix t) ""))
204 ("ASCII" 0 "ASCII")
205 ("author" 1 (progn (setq author (match-string 1 string)) ""))
206 ("authoraddress" 1
207 (progn (setq author-address (match-string 1 string)) ""))
208 ("b" 1 "@w{\\1}")
209 ("bf" 0 "@destroy")
210 ("bifuncindex" 1 (progn (setq findex t) "@findex{\\1}"))
211 ("C" 0 "C")
212 ("c" 0 "@,")
213 ("catcode" 0 "")
214 ("cdata" 1 "@code{\\1}")
215 ("centerline" 1 "@center \\1")
Fred Drake66abcee2002-11-13 19:31:04 +0000216 ("cfuncline" 3 "@itemx \\1 \\2(\\3)\n@findex \\2")
Fred Drakebfc18bd2002-05-03 04:50:51 +0000217 ("cfunction" 1 "@code{\\1}")
218 ("chapter" 1 (format "@node \\1\n@%s \\1\n"
219 (if appendix "appendix" "chapter")))
220 ("chapter*" 1 "@node \\1\n@unnumbered \\1\n")
221 ("character" 1 "@samp{\\1}")
222 ("citetitle" 1 "@ref{Top,,,\\1}")
223 ("class" 1 "@code{\\1}")
Fred Drake66abcee2002-11-13 19:31:04 +0000224 ("cmemberline" 3 "@itemx \\2 \\3\n")
Fred Drakebfc18bd2002-05-03 04:50:51 +0000225 ("code" 1 "@code{\\1}")
226 ("command" 1 "@command{\\1}")
227 ("constant" 1 "@code{\\1}")
228 ("copyright" 1 "@copyright{}")
229 ("Cpp" 0 "C++")
Fred Draked805fef2002-06-27 18:38:06 +0000230 ("csimplemacro" 1 "@code{\\1}")
Fred Drakebfc18bd2002-05-03 04:50:51 +0000231 ("ctype" 1 "@code{\\1}")
232 ("dataline" 1 (progn (setq findex t) "@item \\1\n@findex \\1\n"))
233 ("date" 1 "\\1")
234 ("declaremodule" 2 (progn (setq cindex t) "@label{\\2}@cindex{\\2}"))
235 ("deprecated" 2 "@emph{This is deprecated in Python \\1. \\2}")
236 ("dfn" 1 "@dfn{\\1}")
237 ("documentclass" 1 py2texi-magic)
238 ("e" 0 "@backslash{}")
239 ("else" 0 (concat "@end ifinfo\n@" (setq last-if "iftex")))
Fred Drake3b095582003-07-02 14:22:48 +0000240 ("env" 1 "@code{\\1}")
Fred Drakebfc18bd2002-05-03 04:50:51 +0000241 ("EOF" 0 "@code{EOF}")
242 ("email" 1 "@email{\\1}")
243 ("emph" 1 "@emph{\\1}")
244 ("envvar" 1 "@samp{\\1}")
245 ("exception" 1 "@code{\\1}")
246 ("exindex" 1 (progn (setq obindex t) "@obindex{\\1}"))
247 ("fi" 0 (concat "@end " last-if))
248 ("file" 1 "@file{\\1}")
Fred Drake3b095582003-07-02 14:22:48 +0000249 ("filenq" 1 "@file{\\1}")
Fred Drakebfc18bd2002-05-03 04:50:51 +0000250 ("filevar" 1 "@file{@var{\\1}}")
251 ("footnote" 1 "@footnote{\\1}")
252 ("frac" 0 "")
253 ("funcline" 2 (progn (setq findex t) "@item \\1 \\2\n@findex \\1"))
254 ("funclineni" 2 "@item \\1 \\2")
255 ("function" 1 "@code{\\1}")
256 ("grammartoken" 1 "@code{\\1}")
257 ("hline" 0 "")
258 ("ifhtml" 0 (concat "@" (setq last-if "ifinfo")))
259 ("iftexi" 0 (concat "@" (setq last-if "ifinfo")))
260 ("index" 1 (progn (setq cindex t) "@cindex{\\1}"))
261 ("indexii" 2 (progn (setq cindex t) "@cindex{\\1 \\2}"))
262 ("indexiii" 3 (progn (setq cindex t) "@cindex{\\1 \\2 \\3}"))
263 ("indexiv" 3 (progn (setq cindex t) "@cindex{\\1 \\2 \\3 \\4}"))
264 ("infinity" 0 "@emph{infinity}")
265 ("it" 0 "@destroy")
266 ("kbd" 1 "@key{\\1}")
267 ("keyword" 1 "@code{\\1}")
268 ("kwindex" 1 (progn (setq cindex t) "@cindex{\\1}"))
269 ("label" 1 "@label{\\1}")
270 ("Large" 0 "")
271 ("LaTeX" 0 "La@TeX{}")
272 ("large" 0 "")
273 ("ldots" 0 "@dots{}")
274 ("leftline" 1 "\\1")
275 ("lineii" 2 "@item \\1 @tab \\2")
276 ("lineiii" 3 "@item \\1 @tab \\2 @tab \\3")
277 ("lineiv" 4 "@item \\1 @tab \\2 @tab \\3 @tab \\4")
278 ("linev" 5 "@item \\1 @tab \\2 @tab \\3 @tab \\4 @tab \\5")
279 ("localmoduletable" 0 "")
280 ("longprogramopt" 1 "@option{--\\1}")
Fred Drake3b095582003-07-02 14:22:48 +0000281 ("macro" 1 "@code{@backslash{}\\1}")
Fred Drakebfc18bd2002-05-03 04:50:51 +0000282 ("mailheader" 1 "@code{\\1}")
283 ("makeindex" 0 "")
284 ("makemodindex" 0 "")
285 ("maketitle" 0 (concat "@top " title "\n"))
286 ("makevar" 1 "@code{\\1}")
287 ("manpage" 2 "@samp{\\1(\\2)}")
288 ("mbox" 1 "@w{\\1}")
289 ("member" 1 "@code{\\1}")
290 ("memberline" 1 "@item \\1\n@findex \\1\n")
291 ("menuselection" 1 "@samp{\\1}")
292 ("method" 1 "@code{\\1}")
293 ("methodline" 2 (progn (setq moindex t) "@item \\1(\\2)\n@moindex \\1\n"))
294 ("methodlineni" 2 "@item \\1(\\2)\n")
295 ("mimetype" 1 "@samp{\\1}")
296 ("module" 1 "@samp{\\1}")
Fred Drake66abcee2002-11-13 19:31:04 +0000297 ("moduleauthor" 2 "")
Fred Drakebfc18bd2002-05-03 04:50:51 +0000298 ("modulesynopsis" 1 "\\1")
299 ("moreargs" 0 "@dots{}")
300 ("n" 0 "@backslash{}n")
301 ("newcommand" 2 "")
302 ("newsgroup" 1 "@samp{\\1}")
303 ("nodename" 1
304 (save-excursion
305 (save-match-data
306 (re-search-backward "^@node "))
307 (delete-region (point) (save-excursion (end-of-line) (point)))
308 (insert "@node " (match-string 1 string))
309 ""))
310 ("noindent" 0 "@noindent ")
311 ("note" 1 "@emph{Note:} \\1")
312 ("NULL" 0 "@code{NULL}")
313 ("obindex" 1 (progn (setq obindex t) "@obindex{\\1}"))
314 ("opindex" 1 (progn (setq cindex t) "@cindex{\\1}"))
315 ("option" 1 "@option{\\1}")
316 ("optional" 1 "[\\1]")
317 ("pep" 1 (progn (setq cindex t) "PEP@ \\1@cindex PEP \\1\n"))
318 ("pi" 0 "pi")
319 ("platform" 1 "")
320 ("plusminus" 0 "+-")
321 ("POSIX" 0 "POSIX")
322 ("production" 2 "@item \\1 \\2")
Fred Drake66abcee2002-11-13 19:31:04 +0000323 ("productioncont" 1 "@item @w{} \\1")
Fred Drakebfc18bd2002-05-03 04:50:51 +0000324 ("program" 1 "@command{\\1}")
325 ("programopt" 1 "@option{\\1}")
326 ("protect" 0 "")
327 ("pytype" 1 "@code{\\1}")
328 ("ref" 1 "@ref{\\1}")
329 ("refbimodindex" 1 (progn (setq moindex t) "@moindex{\\1}"))
330 ("refmodindex" 1 (progn (setq moindex t) "@moindex{\\1}"))
331 ("refmodule" 1 "@samp{\\1}")
332 ("refstmodindex" 1 (progn (setq moindex t) "@moindex{\\1}"))
333 ("regexp" 1 "\"\\1\"")
334 ("release" 1
335 (progn (setq py2texi-python-version (match-string 1 string)) ""))
336 ("renewcommand" 2 "")
337 ("rfc" 1 (progn (setq cindex t) "RFC@ \\1@cindex RFC \\1\n"))
338 ("rm" 0 "@destroy")
339 ("samp" 1 "@samp{\\1}")
340 ("section" 1 (let ((str (match-string 1 string)))
341 (save-match-data
342 (if (string-match "\\(.*\\)[ \t\n]*---[ \t\n]*\\(.*\\)"
343 str)
344 (format
345 "@node %s\n@section %s\n"
346 (py2texi-backslash-quote (match-string 1 str))
347 (py2texi-backslash-quote (match-string 2 str)))
348 "@node \\1\n@section \\1\n"))))
Fred Drake66abcee2002-11-13 19:31:04 +0000349 ("sectionauthor" 2 "")
Fred Drakebfc18bd2002-05-03 04:50:51 +0000350 ("seemodule" 2 "@ref{\\1} \\2")
351 ("seepep" 3 "\n@table @strong\n@item PEP\\1 \\2\n\\3\n@end table\n")
352 ("seerfc" 3 "\n@table @strong\n@item RFC\\1 \\2\n\\3\n@end table\n")
353 ("seetext" 1 "\\1")
354 ("seetitle" 1 "@cite{\\1}")
355 ("seeurl" 2 "\n@table @url\n@item \\1\n\\2\n@end table\n")
356 ("setindexsubitem" 1 (progn (setq cindex t) "@cindex \\1"))
357 ("setreleaseinfo" 1 (progn (setq py2texi-releaseinfo "")))
358 ("setshortversion" 1
359 (progn (setq py2texi-python-short-version (match-string 1 string)) ""))
360 ("shortversion" 0 py2texi-python-short-version)
361 ("sqrt" 0 "")
362 ("stindex" 1 (progn (setq cindex t) "@cindex{\\1}"))
363 ("stmodindex" 1 (progn (setq moindex t) "@moindex{\\1}"))
364 ("strong" 1 "@strong{\\1}")
365 ("sub" 0 "/")
366 ("subsection" 1 "@node \\1\n@subsection \\1\n")
367 ("subsubsection" 1 "@node \\1\n@subsubsection \\1\n")
368 ("sum" 0 "")
369 ("tableofcontents" 0 "")
370 ("term" 1 "@item \\1")
Fred Drake3b095582003-07-02 14:22:48 +0000371 ("TeX" 0 "@TeX{}")
Fred Drakebfc18bd2002-05-03 04:50:51 +0000372 ("textasciitilde" 0 "~")
373 ("textasciicircum" 0 "^")
374 ("textbackslash" 0 "@backslash{}")
Fred Draked805fef2002-06-27 18:38:06 +0000375 ("textgreater" 0 ">")
376 ("textless" 0 "<")
Fred Drakebfc18bd2002-05-03 04:50:51 +0000377 ("textrm" 1 "\\1")
378 ("texttt" 1 "@code{\\1}")
379 ("textunderscore" 0 "_")
380 ("title" 1 (progn (setq title (match-string 1 string)) "@settitle \\1"))
381 ("today" 0 "@today{}")
382 ("token" 1 "@code{\\1}")
383 ("tt" 0 "@destroy")
384 ("ttindex" 1 (progn (setq cindex t) "@cindex{\\1}"))
385 ("u" 0 "@backslash{}u")
386 ("ulink" 2 "\\1")
387 ("UNIX" 0 "UNIX")
388 ("unspecified" 0 "@dots{}")
389 ("url" 1 "@url{\\1}")
390 ("usepackage" 1 "")
391 ("var" 1 "@var{\\1}")
392 ("verbatiminput" 1 "@code{\\1}")
393 ("version" 0 py2texi-python-version)
394 ("versionadded" 1 "@emph{Added in Python version \\1}")
395 ("versionchanged" 1 "@emph{Changed in Python version \\1}")
396 ("vskip" 1 "")
397 ("vspace" 1 "")
398 ("warning" 1 "@emph{\\1}")
399 ("withsubitem" 2 "\\2")
400 ("XXX" 1 "@strong{\\1}"))
401 "Associative list of command substitutions.
402Each list item is of the form (COMMAND ARGNUM SUBSTITUTION) where:
403- COMMAND is LaTeX command name
404- ARGNUM is number of (required) command arguments
405- SUBSTITUTION substitution for the command. It is evaled and you can
406 reference command arguments through the \\N regexp notation in strings.")
407
408(defvar py2texi-magic "@documentclass\n"
409 "\"Magic\" string for auxiliary insertion at the beginning of document.")
410
411(defvar py2texi-dirs '("./" "../texinputs/")
412 "Where to search LaTeX input files.")
413
414(defvar py2texi-buffer "*py2texi*"
415 "The name of a buffer where Texinfo is generated.")
416
417(defconst py2texi-xemacs (string-match "^XEmacs" (emacs-version))
418 "Running under XEmacs?")
419
420
421(defmacro py2texi-search (regexp &rest body)
422 `(progn
423 (goto-char (point-min))
424 (while (re-search-forward ,regexp nil t)
425 ,@body)))
426
427(defmacro py2texi-search-safe (regexp &rest body)
428 `(py2texi-search ,regexp
429 (unless (py2texi-protected)
430 ,@body)))
431
432
433(defun py2texi-message (message)
434 "Report message and stop if `py2texi-stop-on-problems' is non-nil."
435 (if py2texi-stop-on-problems
436 (error message)
437 (message message)))
438
439
440(defun py2texi-backslash-quote (string)
441 "Double backslahes in STRING."
442 (let ((i 0))
443 (save-match-data
444 (while (setq i (string-match "\\\\" string i))
445 (setq string (replace-match "\\\\\\\\" t nil string))
446 (setq i (+ i 2))))
447 string))
448
449
450(defun py2texi (file)
451 "Convert Python LaTeX documentation FILE to Texinfo."
452 (interactive "fFile to convert: ")
453 (switch-to-buffer (get-buffer-create py2texi-buffer))
454 (erase-buffer)
455 (insert-file file)
456 (let ((case-fold-search nil)
457 (title "")
458 (author "")
459 (author-address "")
460 (appendix nil)
461 (findex nil)
462 (obindex nil)
463 (cindex nil)
464 (moindex nil)
465 last-if)
466 (py2texi-process-verbatims)
467 (py2texi-process-comments)
468 (py2texi-process-includes)
469 (py2texi-process-funnyas)
470 (py2texi-process-environments)
471 (py2texi-process-commands)
472 (py2texi-fix-indentation)
473 (py2texi-fix-nodes)
474 (py2texi-fix-references)
475 (py2texi-fix-indices)
476 (py2texi-process-simple-commands)
477 (py2texi-fix-fonts)
478 (py2texi-fix-braces)
479 (py2texi-fix-backslashes)
480 (py2texi-destroy-empties)
481 (py2texi-fix-newlines)
482 (py2texi-adjust-level))
Fred Drake66abcee2002-11-13 19:31:04 +0000483 (let* ((texi-file-name (or py2texi-texi-file-name
484 (py2texi-texi-file-name file)))
485 (info-file-name (or py2texi-info-file-name
486 (py2texi-info-file-name texi-file-name))))
Fred Drakebfc18bd2002-05-03 04:50:51 +0000487 (goto-char (point-min))
488 (when (looking-at py2texi-magic)
489 (delete-region (point) (progn (beginning-of-line 2) (point)))
490 (insert "\\input texinfo @c -*-texinfo-*-\n")
Fred Drake66abcee2002-11-13 19:31:04 +0000491 (insert "@setfilename " info-file-name))
Fred Drakebfc18bd2002-05-03 04:50:51 +0000492 (when (re-search-forward "@chapter" nil t)
493 (texinfo-all-menus-update t))
494 (goto-char (point-min))
Fred Drake66abcee2002-11-13 19:31:04 +0000495 (write-file texi-file-name)
496 (message (format "You can apply `makeinfo %s' now." texi-file-name))))
497
498
499(defun py2texi-texi-file-name (filename)
500 "Generate name of Texinfo file from original file name FILENAME."
501 (concat filename
502 (if (string-match "\\.tex$" filename) "i" ".texi")))
Fred Drakebfc18bd2002-05-03 04:50:51 +0000503
504
505(defun py2texi-info-file-name (filename)
506 "Generate name of info file from original file name FILENAME."
507 (setq filename (expand-file-name filename))
508 (let ((directory (file-name-directory filename))
509 (basename (file-name-nondirectory filename)))
510 (concat directory "python-"
511 (substring basename 0 (- (length basename) 4)) "info")))
512
513
514(defun py2texi-process-verbatims ()
515 "Process and protect verbatim environments."
516 (let (delimiter
517 beg
518 end)
519 (py2texi-search-safe "\\\\begin{\\(verbatim\\|displaymath\\)}"
520 (replace-match "@example")
521 (setq beg (copy-marker (point) nil))
522 (re-search-forward "\\\\end{\\(verbatim\\|displaymath\\)}")
523 (setq end (copy-marker (match-beginning 0) nil))
524 (replace-match "@end example")
525 (py2texi-texinfo-escape beg end)
526 (put-text-property (- beg (length "@example"))
527 (+ end (length "@end example"))
528 'py2texi-protected t))
529 (py2texi-search-safe "\\\\verb\\([^a-z]\\)"
530 (setq delimiter (match-string 1))
531 (replace-match "@code{")
532 (setq beg (copy-marker (point) nil))
533 (re-search-forward (regexp-quote delimiter))
534 (setq end (copy-marker (match-beginning 0) nil))
535 (replace-match "}")
536 (put-text-property (- beg (length "@code{")) (+ end (length "}"))
537 'py2texi-protected t)
538 (py2texi-texinfo-escape beg end))))
539
540
541(defun py2texi-process-comments ()
542 "Remove comments."
543 (let (point)
544 (py2texi-search-safe "%"
545 (setq point (point))
546 (when (save-excursion
547 (re-search-backward "\\(^\\|[^\\]\\(\\\\\\\\\\)*\\)%\\=" nil t))
548 (delete-region (1- point)
549 (save-excursion (beginning-of-line 2) (point)))))))
550
551
552(defun py2texi-process-includes ()
553 "Include LaTeX input files.
554Do not include .ind files."
555 (let ((path (file-name-directory file))
556 filename
557 dirs
558 includefile)
559 (py2texi-search-safe "\\\\input{\\([^}]+\\)}"
560 (setq filename (match-string 1))
561 (unless (save-match-data (string-match "\\.tex$" filename))
562 (setq filename (concat filename ".tex")))
563 (setq includefile (save-match-data
564 (string-match "\\.ind\\.tex$" filename)))
565 (setq dirs py2texi-dirs)
566 (while (and (not includefile) dirs)
567 (setq includefile (concat path (car dirs) filename))
568 (unless (file-exists-p includefile)
569 (setq includefile nil)
570 (setq dirs (cdr dirs))))
571 (if includefile
572 (save-restriction
573 (narrow-to-region (match-beginning 0) (match-end 0))
574 (delete-region (point-min) (point-max))
575 (when (stringp includefile)
576 (insert-file-contents includefile)
577 (goto-char (point-min))
578 (insert "\n")
579 (py2texi-process-verbatims)
580 (py2texi-process-comments)
581 (py2texi-process-includes)))
582 (replace-match (format "\\\\emph{Included file %s}" filename))
583 (py2texi-message (format "Input file %s not found" filename))))))
584
585
586(defun py2texi-process-funnyas ()
587 "Convert @s."
588 (py2texi-search-safe "@"
589 (replace-match "@@")))
590
591
592(defun py2texi-process-environments ()
593 "Process LaTeX environments."
594 (let ((stack ())
595 kind
596 environment
597 parameter
598 arguments
599 n
600 string
601 description)
602 (py2texi-search-safe (concat "\\\\\\(begin\\|end\\|item\\)"
603 "\\({\\([^}]*\\)}\\|[[]\\([^]]*\\)[]]\\|\\)")
604 (setq kind (match-string 1)
605 environment (match-string 3)
606 parameter (match-string 4))
607 (replace-match "")
608 (cond
609 ((string= kind "begin")
610 (setq description (assoc environment py2texi-environments))
611 (if description
612 (progn
613 (setq n (cadr description))
614 (setq description (cddr description))
615 (setq string (py2texi-tex-arguments n))
616 (string-match (py2texi-regexp n) string)
617 ; incorrect but sufficient
618 (insert (replace-match (eval (car description))
619 t nil string))
620 (setq stack (cons (cadr description) stack)))
621 (py2texi-message (format "Unknown environment: %s" environment))
622 (setq stack (cons "" stack))))
623 ((string= kind "end")
624 (insert (eval (car stack)))
625 (setq stack (cdr stack)))
626 ((string= kind "item")
627 (insert "\n@item " (or parameter "") "\n"))))
628 (when stack
629 (py2texi-message (format "Unclosed environment: %s" (car stack))))))
630
631
632(defun py2texi-process-commands ()
633 "Process LaTeX commands."
634 (let (done
635 command
636 command-info
637 string
638 n)
639 (while (not done)
640 (setq done t)
641 (py2texi-search-safe "\\\\\\([a-zA-Z*]+\\)\\(\\[[^]]*\\]\\)?"
642 (setq command (match-string 1))
643 (setq command-info (assoc command py2texi-commands))
644 (if command-info
645 (progn
646 (setq done nil)
647 (replace-match "")
648 (setq command-info (cdr command-info))
649 (setq n (car command-info))
650 (setq string (py2texi-tex-arguments n))
651 (string-match (py2texi-regexp n) string)
652 ; incorrect but sufficient
653 (insert (replace-match (eval (cadr command-info))
654 t nil string)))
655 (py2texi-message (format "Unknown command: %s (not processed)"
656 command)))))))
657
658
659(defun py2texi-argument-pattern (count)
660 (let ((filler "\\(?:[^{}]\\|\\\\{\\|\\\\}\\)*"))
661 (if (<= count 0)
662 filler
663 (concat filler "\\(?:{"
664 (py2texi-argument-pattern (1- count))
665 "}" filler "\\)*" filler))))
666(defconst py2texi-tex-argument
667 (concat
668 "{\\("
669 (py2texi-argument-pattern 10) ;really at least 10!
670 "\\)}[ \t%@c\n]*")
671 "Regexp describing LaTeX command argument including argument separators.")
672
673
674(defun py2texi-regexp (n)
675 "Make regexp matching N LaTeX command arguments."
676 (if (= n 0)
677 ""
678 (let ((regexp "^[^{]*"))
679 (while (> n 0)
680 (setq regexp (concat regexp py2texi-tex-argument))
681 (setq n (1- n)))
682 regexp)))
683
684
685(defun py2texi-tex-arguments (n)
686 "Remove N LaTeX command arguments and return them as a string."
687 (let ((point (point))
688 (i 0)
689 result
690 match)
691 (if (= n 0)
692 (progn
693 (when (re-search-forward "\\=\\({}\\| *\\)" nil t)
694 (replace-match ""))
695 "")
696 (while (> n 0)
697 (unless (re-search-forward
698 "\\(\\=\\|[^\\\\]\\)\\(\\\\\\\\\\)*\\([{}]\\)" nil t)
699 (debug))
700 (if (string= (match-string 3) "{")
701 (setq i (1+ i))
702 (setq i (1- i))
703 (when (<= i 0)
704 (setq n (1- n)))))
705 (setq result (buffer-substring-no-properties point (point)))
706 (while (string-match "\n[ \t]*" result)
707 (setq result (replace-match " " t nil result)))
708 (delete-region point (point))
709 result)))
710
711
712(defun py2texi-process-simple-commands ()
713 "Replace single character LaTeX commands."
714 (let (char)
715 (py2texi-search-safe "\\\\\\([^a-z]\\)"
716 (setq char (match-string 1))
717 (replace-match (format "%s%s"
718 (if (or (string= char "{")
719 (string= char "}")
720 (string= char " "))
721 "@"
722 "")
723 (if (string= char "\\")
724 "\\\\"
725 char))))))
726
727
728(defun py2texi-fix-indentation ()
729 "Remove white space at the beginning of lines."
730 (py2texi-search-safe "^[ \t]+"
731 (replace-match "")))
732
733
734(defun py2texi-fix-nodes ()
735 "Remove unwanted characters from nodes and make nodes unique."
736 (let ((nodes (make-hash-table :test 'equal))
737 id
738 counter
739 string
Fred Drake66abcee2002-11-13 19:31:04 +0000740 label
741 index)
Fred Drakebfc18bd2002-05-03 04:50:51 +0000742 (py2texi-search "^@node +\\(.*\\)$"
743 (setq string (match-string 1))
744 (if py2texi-xemacs
745 (replace-match "@node " t)
746 (replace-match "" t nil nil 1))
Fred Drake66abcee2002-11-13 19:31:04 +0000747 (while (string-match "@label{[^}]*}" string)
Fred Drakebfc18bd2002-05-03 04:50:51 +0000748 (setq label (match-string 0 string))
749 (setq string (replace-match "" t nil string)))
Fred Drake66abcee2002-11-13 19:31:04 +0000750 (while (string-match "@..?index{[^}]*}" string)
751 (setq index (match-string 0 string))
752 (setq string (replace-match "" t nil string)))
Fred Drakebfc18bd2002-05-03 04:50:51 +0000753 (while (string-match "@[a-zA-Z]+\\|[{}():]\\|``\\|''" string)
754 (setq string (replace-match "" t nil string)))
755 (while (string-match " -- " string)
756 (setq string (replace-match " - " t nil string)))
Fred Drake66abcee2002-11-13 19:31:04 +0000757 (while (string-match "\\." string)
758 (setq string (replace-match "" t nil string)))
Fred Drakebfc18bd2002-05-03 04:50:51 +0000759 (when (string-match " +$" string)
760 (setq string (replace-match "" t nil string)))
761 (when (string-match "^\\(Built-in\\|Standard\\) Module \\|The " string)
762 (setq string (replace-match "" t nil string)))
763 (string-match "^[^,]+" string)
764 (setq id (match-string 0 string))
765 (setq counter (gethash id nodes))
766 (if counter
767 (progn
768 (setq counter (1+ counter))
769 (setq string (replace-match (format "\\& %d" counter)
770 t nil string)))
771 (setq counter 1))
772 (setf (gethash id nodes) counter)
773 (insert string)
Fred Drake66abcee2002-11-13 19:31:04 +0000774 (beginning-of-line 3)
Fred Drakebfc18bd2002-05-03 04:50:51 +0000775 (when label
Fred Drake66abcee2002-11-13 19:31:04 +0000776 (insert label "\n"))
777 (when index
778 (insert index "\n")))))
Fred Drakebfc18bd2002-05-03 04:50:51 +0000779
780
781(defun py2texi-fix-references ()
782 "Process labels and make references to point to appropriate nodes."
783 (let ((labels ())
784 node)
785 (py2texi-search-safe "@label{\\([^}]*\\)}"
786 (setq node (save-excursion
787 (save-match-data
788 (and (re-search-backward "@node +\\([^,\n]+\\)" nil t)
789 (match-string 1)))))
790 (when node
791 (setq labels (cons (cons (match-string 1) node) labels)))
792 (replace-match ""))
793 (py2texi-search-safe "@ref{\\([^}]*\\)}"
794 (setq node (assoc (match-string 1) labels))
795 (replace-match "")
796 (when node
797 (insert (format "@ref{%s}" (cdr node)))))))
798
799
800(defun py2texi-fix-indices ()
801 "Remove unwanted characters from @*index commands and create final indices."
802 (py2texi-search-safe "@..?index\\>[^\n]*\\(\\)\n"
803 (replace-match "" t nil nil 1))
804 (py2texi-search-safe "@..?index\\>[^\n]*\\(\\)"
805 (replace-match "\n" t nil nil 1))
806 (py2texi-search-safe "@..?index\\({\\)\\([^}]+\\)\\(}+\\)"
807 (replace-match " " t nil nil 1)
808 (replace-match "" t nil nil 3)
809 (let ((string (match-string 2)))
810 (save-match-data
811 (while (string-match "@[a-z]+{" string)
812 (setq string (replace-match "" nil nil string)))
813 (while (string-match "{" string)
814 (setq string (replace-match "" nil nil string))))
815 (replace-match string t t nil 2)))
816 (py2texi-search-safe "@..?index\\>.*\\([{}]\\|@[a-z]*\\)"
817 (replace-match "" t nil nil 1)
818 (goto-char (match-beginning 0)))
819 (py2texi-search-safe "[^\n]\\(\\)@..?index\\>"
820 (replace-match "\n" t nil nil 1))
821 (goto-char (point-max))
822 (re-search-backward "@indices")
823 (replace-match "")
824 (insert (if moindex
825 (concat "@node Module Index\n"
826 "@unnumbered Module Index\n"
827 "@printindex mo\n")
828 "")
829 (if obindex
830 (concat "@node Class-Exception-Object Index\n"
831 "@unnumbered Class, Exception, and Object Index\n"
832 "@printindex ob\n")
833 "")
834 (if findex
835 (concat "@node Function-Method-Variable Index\n"
836 "@unnumbered Function, Method, and Variable Index\n"
837 "@printindex fn\n")
838 "")
839 (if cindex
840 (concat "@node Miscellaneous Index\n"
841 "@unnumbered Miscellaneous Index\n"
842 "@printindex cp\n")
843 "")))
844
845
846(defun py2texi-fix-backslashes ()
847 "Make backslashes from auxiliary commands."
848 (py2texi-search-safe "@backslash{}"
849 (replace-match "\\\\")))
850
851
852(defun py2texi-fix-fonts ()
853 "Remove garbage after unstructured font commands."
854 (let (string)
855 (py2texi-search-safe "@destroy"
856 (replace-match "")
857 (when (eq (preceding-char) ?{)
858 (forward-char -1)
859 (setq string (py2texi-tex-arguments 1))
860 (insert (substring string 1 (1- (length string))))))))
861
862
863(defun py2texi-fix-braces ()
864 "Escape braces for Texinfo."
865 (let (string)
866 (py2texi-search "{"
867 (unless (or (py2texi-protected)
868 (save-excursion
869 (re-search-backward
870 "@\\([a-zA-Z]*\\|multitable.*\\){\\=" nil t)))
871 (forward-char -1)
872 (setq string (py2texi-tex-arguments 1))
873 (insert "@" (substring string 0 (1- (length string))) "@}")))))
874
875
876(defun py2texi-fix-newlines ()
877 "Remove extra newlines."
878 (py2texi-search "\n\n\n+"
879 (replace-match "\n\n"))
880 (py2texi-search-safe "@item.*\n\n"
881 (delete-backward-char 1))
882 (py2texi-search "@end example"
883 (unless (looking-at "\n\n")
884 (insert "\n"))))
885
886
887(defun py2texi-destroy-empties ()
888 "Remove all comments.
889This avoids some makeinfo errors."
890 (py2texi-search "@c\\>"
891 (unless (eq (py2texi-protected) t)
892 (delete-region (- (point) 2) (save-excursion (end-of-line) (point)))
893 (cond
894 ((looking-at "\n\n")
895 (delete-char 1))
896 ((save-excursion (re-search-backward "^[ \t]*\\=" nil t))
897 (delete-region (save-excursion (beginning-of-line) (point))
898 (1+ (point))))))))
899
900
901(defun py2texi-adjust-level ()
902 "Increase heading level to @chapter, if needed.
903This is only needed for distutils, so it has a very simple form only."
904 (goto-char (point-min))
905 (unless (re-search-forward "@chapter\\>" nil t)
906 (py2texi-search-safe "@section\\>"
907 (replace-match "@chapter" t))
908 (py2texi-search-safe "@\\(sub\\)\\(sub\\)?section\\>"
909 (replace-match "" nil nil nil 1))))
910
911
912(defun py2texi-texinfo-escape (beg end)
913 "Escape Texinfo special characters in region."
914 (save-excursion
915 (goto-char beg)
916 (while (re-search-forward "[@{}]" end t)
917 (replace-match "@\\&"))))
918
919
920(defun py2texi-protected ()
921 "Return protection status of the point before current point."
922 (get-text-property (1- (point)) 'py2texi-protected))
923
924
925;;; Announce
926
927(provide 'py2texi)
928
929
930;;; py2texi.el ends here