blob: f9d8b96b8d45dd1fa080fe413facf6d3566356a9 [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 Drake66758812003-07-02 14:44:08 +000088 ("comment" 0 "\n@ignore\n" "\n@end ignore\n")
Fred Drakebfc18bd2002-05-03 04:50:51 +000089 ("csimplemacrodesc" 1
90 (progn (setq cindex t)
91 "\n@table @code\n@item \\1\n@cindex \\1\n")
Fred Drake66abcee2002-11-13 19:31:04 +000092 "@end table\n")
Fred Drakebfc18bd2002-05-03 04:50:51 +000093 ("ctypedesc" 1
94 (progn (setq cindex t)
95 "\n@table @code\n@item \\1\n@cindex \\1\n")
Fred Drake66abcee2002-11-13 19:31:04 +000096 "@end table\n")
Fred Drakebfc18bd2002-05-03 04:50:51 +000097 ("cvardesc" 2
98 (progn (setq findex t)
99 "\n@table @code\n@item \\1 \\2\n@findex \\2\n")
Fred Drake66abcee2002-11-13 19:31:04 +0000100 "@end table\n")
Fred Drakebfc18bd2002-05-03 04:50:51 +0000101 ("datadesc" 1
102 (progn (setq findex t)
103 "\n@table @code\n@item \\1\n@findex \\1\n")
Fred Drake66abcee2002-11-13 19:31:04 +0000104 "@end table\n")
105 ("datadescni" 1 "\n@table @code\n@item \\1\n" "@end table\n")
Fred Drakebfc18bd2002-05-03 04:50:51 +0000106 ("definitions" 0 "@table @dfn" "@end table\n")
107 ("description" 0 "@table @samp" "@end table\n")
108 ("displaymath" 0 "" "")
109 ("document" 0
110 (concat "@defcodeindex mo\n"
111 "@defcodeindex ob\n"
112 "@titlepage\n"
113 (format "@title " title "\n")
114 (format "@author " author "\n")
115 "@page\n"
116 author-address
117 "@end titlepage\n"
118 "@node Top, , , (dir)\n")
119 (concat "@indices\n"
120 "@contents\n"
121 "@bye\n"))
122 ("enumerate" 0 "@enumerate" "@end enumerate")
Fred Drake3b095582003-07-02 14:22:48 +0000123 ("envdesc" 2 (concat "\n@table @code"
124 "\n@item @backslash{}begin@{\\1@}\\2")
125 "@end table\n")
Fred Drakebfc18bd2002-05-03 04:50:51 +0000126 ("excdesc" 1
127 (progn (setq obindex t)
128 "\n@table @code\n@item \\1\n@obindex \\1\n")
Fred Drake66abcee2002-11-13 19:31:04 +0000129 "@end table\n")
Fred Drakebfc18bd2002-05-03 04:50:51 +0000130 ("excclassdesc" 2
131 (progn (setq obindex t)
132 "\n@table @code\n@item \\1(\\2)\n@obindex \\1\n")
Fred Drake66abcee2002-11-13 19:31:04 +0000133 "@end table\n")
Fred Drakebfc18bd2002-05-03 04:50:51 +0000134 ("flushleft" 0 "" "")
Fred Drake66abcee2002-11-13 19:31:04 +0000135 ("fulllineitems" 0 "\n@table @code\n" "@end table\n")
Fred Drakebfc18bd2002-05-03 04:50:51 +0000136 ("funcdesc" 2
137 (progn (setq findex t)
138 "\n@table @code\n@item \\1(\\2)\n@findex \\1\n")
Fred Drake66abcee2002-11-13 19:31:04 +0000139 "@end table\n")
140 ("funcdescni" 2 "\n@table @code\n@item \\1(\\2)\n" "@end table\n")
Fred Drakebfc18bd2002-05-03 04:50:51 +0000141 ("itemize" 0 "@itemize @bullet" "@end itemize\n")
Fred Drake66abcee2002-11-13 19:31:04 +0000142 ("list" 2 "\n@table @code\n" "@end table\n")
Fred Drakebfc18bd2002-05-03 04:50:51 +0000143 ("longtableii" 4 (concat "@multitable @columnfractions .5 .5\n"
144 "@item \\3 @tab \\4\n"
145 "@item ------- @tab ------ \n")
146 "@end multitable\n")
147 ("longtableiii" 5 (concat "@multitable @columnfractions .33 .33 .33\n"
148 "@item \\3 @tab \\4 @tab \\5\n"
149 "@item ------- @tab ------ @tab ------\n")
150 "@end multitable\n")
Fred Drake3b095582003-07-02 14:22:48 +0000151 ("macrodesc" 2 (concat "\n@table @code"
152 "\n@item \\1@{\\2@}")
153 "@end table\n")
Fred Drakebfc18bd2002-05-03 04:50:51 +0000154 ("memberdesc" 1
155 (progn (setq findex t)
156 "\n@table @code\n@item \\1\n@findex \\1\n")
Fred Drake66abcee2002-11-13 19:31:04 +0000157 "@end table\n")
158 ("memberdescni" 1 "\n@table @code\n@item \\1\n" "@end table\n")
Fred Drakebfc18bd2002-05-03 04:50:51 +0000159 ("methoddesc" 2
160 (progn (setq findex t)
161 "\n@table @code\n@item \\1(\\2)\n@findex \\1\n")
Fred Drake66abcee2002-11-13 19:31:04 +0000162 "@end table\n")
163 ("methoddescni" 2 "\n@table @code\n@item \\1(\\2)\n" "@end table\n")
Fred Drakebfc18bd2002-05-03 04:50:51 +0000164 ("notice" 0 "@emph{Notice:} " "")
165 ("opcodedesc" 2
166 (progn (setq findex t)
167 "\n@table @code\n@item \\1 \\2\n@findex \\1\n")
Fred Drake66abcee2002-11-13 19:31:04 +0000168 "@end table\n")
169 ("productionlist" 0 "\n@table @code\n" "@end table\n")
Fred Drakebfc18bd2002-05-03 04:50:51 +0000170 ("quotation" 0 "@quotation" "@end quotation")
Fred Drake66abcee2002-11-13 19:31:04 +0000171 ("seealso" 0 "See also:\n@table @emph\n" "@end table\n")
172 ("seealso*" 0 "@table @emph\n" "@end table\n")
Fred Drakebfc18bd2002-05-03 04:50:51 +0000173 ("sloppypar" 0 "" "")
174 ("small" 0 "" "")
175 ("tableii" 4 (concat "@multitable @columnfractions .5 .5\n"
176 "@item \\3 @tab \\4\n"
177 "@item ------- @tab ------ \n")
178 "@end multitable\n")
179 ("tableiii" 5 (concat "@multitable @columnfractions .33 .33 .33\n"
180 "@item \\3 @tab \\4 @tab \\5\n"
181 "@item ------- @tab ------ @tab ------\n")
182 "@end multitable\n")
183 ("tableiv" 6 (concat
184 "@multitable @columnfractions .25 .25 .25 .25\n"
185 "@item \\3 @tab \\4 @tab \\5 @tab \\6\n"
186 "@item ------- @tab ------- @tab ------- @tab -------\n")
187 "@end multitable\n")
188 ("tablev" 7 (concat
189 "@multitable @columnfractions .20 .20 .20 .20 .20\n"
190 "@item \\3 @tab \\4 @tab \\5 @tab \\6 @tab \\7\n"
191 "@item ------- @tab ------- @tab ------- @tab ------- @tab -------\n")
192 "@end multitable\n"))
193 "Associative list defining substitutions for environments.
194Each list item is of the form (ENVIRONMENT ARGNUM BEGIN END) where:
195- ENVIRONMENT is LaTeX environment name
196- ARGNUM is number of (required) macro arguments
197- BEGIN is substitution for \begin{ENVIRONMENT}
198- END is substitution for \end{ENVIRONMENT}
199Both BEGIN and END are evaled. Moreover, you can reference arguments through
200\N regular expression notation in strings of BEGIN.")
201
202(defconst py2texi-commands
203 '(("ABC" 0 "ABC")
204 ("appendix" 0 (progn (setq appendix t) ""))
205 ("ASCII" 0 "ASCII")
206 ("author" 1 (progn (setq author (match-string 1 string)) ""))
207 ("authoraddress" 1
208 (progn (setq author-address (match-string 1 string)) ""))
209 ("b" 1 "@w{\\1}")
210 ("bf" 0 "@destroy")
211 ("bifuncindex" 1 (progn (setq findex t) "@findex{\\1}"))
212 ("C" 0 "C")
213 ("c" 0 "@,")
214 ("catcode" 0 "")
215 ("cdata" 1 "@code{\\1}")
216 ("centerline" 1 "@center \\1")
Fred Drake66abcee2002-11-13 19:31:04 +0000217 ("cfuncline" 3 "@itemx \\1 \\2(\\3)\n@findex \\2")
Fred Drakebfc18bd2002-05-03 04:50:51 +0000218 ("cfunction" 1 "@code{\\1}")
219 ("chapter" 1 (format "@node \\1\n@%s \\1\n"
220 (if appendix "appendix" "chapter")))
221 ("chapter*" 1 "@node \\1\n@unnumbered \\1\n")
222 ("character" 1 "@samp{\\1}")
223 ("citetitle" 1 "@ref{Top,,,\\1}")
224 ("class" 1 "@code{\\1}")
Fred Drake66abcee2002-11-13 19:31:04 +0000225 ("cmemberline" 3 "@itemx \\2 \\3\n")
Fred Drakebfc18bd2002-05-03 04:50:51 +0000226 ("code" 1 "@code{\\1}")
227 ("command" 1 "@command{\\1}")
228 ("constant" 1 "@code{\\1}")
229 ("copyright" 1 "@copyright{}")
230 ("Cpp" 0 "C++")
Fred Draked805fef2002-06-27 18:38:06 +0000231 ("csimplemacro" 1 "@code{\\1}")
Fred Drakebfc18bd2002-05-03 04:50:51 +0000232 ("ctype" 1 "@code{\\1}")
233 ("dataline" 1 (progn (setq findex t) "@item \\1\n@findex \\1\n"))
234 ("date" 1 "\\1")
235 ("declaremodule" 2 (progn (setq cindex t) "@label{\\2}@cindex{\\2}"))
236 ("deprecated" 2 "@emph{This is deprecated in Python \\1. \\2}")
237 ("dfn" 1 "@dfn{\\1}")
238 ("documentclass" 1 py2texi-magic)
239 ("e" 0 "@backslash{}")
240 ("else" 0 (concat "@end ifinfo\n@" (setq last-if "iftex")))
Fred Drake3b095582003-07-02 14:22:48 +0000241 ("env" 1 "@code{\\1}")
Fred Drakebfc18bd2002-05-03 04:50:51 +0000242 ("EOF" 0 "@code{EOF}")
243 ("email" 1 "@email{\\1}")
244 ("emph" 1 "@emph{\\1}")
245 ("envvar" 1 "@samp{\\1}")
246 ("exception" 1 "@code{\\1}")
247 ("exindex" 1 (progn (setq obindex t) "@obindex{\\1}"))
248 ("fi" 0 (concat "@end " last-if))
249 ("file" 1 "@file{\\1}")
Fred Drake3b095582003-07-02 14:22:48 +0000250 ("filenq" 1 "@file{\\1}")
Fred Drakebfc18bd2002-05-03 04:50:51 +0000251 ("filevar" 1 "@file{@var{\\1}}")
252 ("footnote" 1 "@footnote{\\1}")
253 ("frac" 0 "")
254 ("funcline" 2 (progn (setq findex t) "@item \\1 \\2\n@findex \\1"))
255 ("funclineni" 2 "@item \\1 \\2")
256 ("function" 1 "@code{\\1}")
257 ("grammartoken" 1 "@code{\\1}")
258 ("hline" 0 "")
259 ("ifhtml" 0 (concat "@" (setq last-if "ifinfo")))
260 ("iftexi" 0 (concat "@" (setq last-if "ifinfo")))
261 ("index" 1 (progn (setq cindex t) "@cindex{\\1}"))
262 ("indexii" 2 (progn (setq cindex t) "@cindex{\\1 \\2}"))
263 ("indexiii" 3 (progn (setq cindex t) "@cindex{\\1 \\2 \\3}"))
264 ("indexiv" 3 (progn (setq cindex t) "@cindex{\\1 \\2 \\3 \\4}"))
265 ("infinity" 0 "@emph{infinity}")
266 ("it" 0 "@destroy")
267 ("kbd" 1 "@key{\\1}")
268 ("keyword" 1 "@code{\\1}")
269 ("kwindex" 1 (progn (setq cindex t) "@cindex{\\1}"))
270 ("label" 1 "@label{\\1}")
271 ("Large" 0 "")
272 ("LaTeX" 0 "La@TeX{}")
273 ("large" 0 "")
274 ("ldots" 0 "@dots{}")
275 ("leftline" 1 "\\1")
276 ("lineii" 2 "@item \\1 @tab \\2")
277 ("lineiii" 3 "@item \\1 @tab \\2 @tab \\3")
278 ("lineiv" 4 "@item \\1 @tab \\2 @tab \\3 @tab \\4")
279 ("linev" 5 "@item \\1 @tab \\2 @tab \\3 @tab \\4 @tab \\5")
280 ("localmoduletable" 0 "")
281 ("longprogramopt" 1 "@option{--\\1}")
Fred Drake3b095582003-07-02 14:22:48 +0000282 ("macro" 1 "@code{@backslash{}\\1}")
Fred Drakebfc18bd2002-05-03 04:50:51 +0000283 ("mailheader" 1 "@code{\\1}")
284 ("makeindex" 0 "")
285 ("makemodindex" 0 "")
286 ("maketitle" 0 (concat "@top " title "\n"))
287 ("makevar" 1 "@code{\\1}")
288 ("manpage" 2 "@samp{\\1(\\2)}")
289 ("mbox" 1 "@w{\\1}")
290 ("member" 1 "@code{\\1}")
291 ("memberline" 1 "@item \\1\n@findex \\1\n")
292 ("menuselection" 1 "@samp{\\1}")
293 ("method" 1 "@code{\\1}")
294 ("methodline" 2 (progn (setq moindex t) "@item \\1(\\2)\n@moindex \\1\n"))
295 ("methodlineni" 2 "@item \\1(\\2)\n")
296 ("mimetype" 1 "@samp{\\1}")
297 ("module" 1 "@samp{\\1}")
Fred Drake66abcee2002-11-13 19:31:04 +0000298 ("moduleauthor" 2 "")
Fred Drakebfc18bd2002-05-03 04:50:51 +0000299 ("modulesynopsis" 1 "\\1")
300 ("moreargs" 0 "@dots{}")
301 ("n" 0 "@backslash{}n")
302 ("newcommand" 2 "")
303 ("newsgroup" 1 "@samp{\\1}")
304 ("nodename" 1
305 (save-excursion
306 (save-match-data
307 (re-search-backward "^@node "))
308 (delete-region (point) (save-excursion (end-of-line) (point)))
309 (insert "@node " (match-string 1 string))
310 ""))
311 ("noindent" 0 "@noindent ")
312 ("note" 1 "@emph{Note:} \\1")
313 ("NULL" 0 "@code{NULL}")
314 ("obindex" 1 (progn (setq obindex t) "@obindex{\\1}"))
315 ("opindex" 1 (progn (setq cindex t) "@cindex{\\1}"))
316 ("option" 1 "@option{\\1}")
317 ("optional" 1 "[\\1]")
318 ("pep" 1 (progn (setq cindex t) "PEP@ \\1@cindex PEP \\1\n"))
319 ("pi" 0 "pi")
320 ("platform" 1 "")
321 ("plusminus" 0 "+-")
322 ("POSIX" 0 "POSIX")
323 ("production" 2 "@item \\1 \\2")
Fred Drake66abcee2002-11-13 19:31:04 +0000324 ("productioncont" 1 "@item @w{} \\1")
Fred Drakebfc18bd2002-05-03 04:50:51 +0000325 ("program" 1 "@command{\\1}")
326 ("programopt" 1 "@option{\\1}")
327 ("protect" 0 "")
328 ("pytype" 1 "@code{\\1}")
329 ("ref" 1 "@ref{\\1}")
330 ("refbimodindex" 1 (progn (setq moindex t) "@moindex{\\1}"))
331 ("refmodindex" 1 (progn (setq moindex t) "@moindex{\\1}"))
332 ("refmodule" 1 "@samp{\\1}")
333 ("refstmodindex" 1 (progn (setq moindex t) "@moindex{\\1}"))
334 ("regexp" 1 "\"\\1\"")
335 ("release" 1
336 (progn (setq py2texi-python-version (match-string 1 string)) ""))
337 ("renewcommand" 2 "")
338 ("rfc" 1 (progn (setq cindex t) "RFC@ \\1@cindex RFC \\1\n"))
339 ("rm" 0 "@destroy")
340 ("samp" 1 "@samp{\\1}")
341 ("section" 1 (let ((str (match-string 1 string)))
342 (save-match-data
343 (if (string-match "\\(.*\\)[ \t\n]*---[ \t\n]*\\(.*\\)"
344 str)
345 (format
346 "@node %s\n@section %s\n"
347 (py2texi-backslash-quote (match-string 1 str))
348 (py2texi-backslash-quote (match-string 2 str)))
349 "@node \\1\n@section \\1\n"))))
Fred Drake66abcee2002-11-13 19:31:04 +0000350 ("sectionauthor" 2 "")
Fred Drakebfc18bd2002-05-03 04:50:51 +0000351 ("seemodule" 2 "@ref{\\1} \\2")
352 ("seepep" 3 "\n@table @strong\n@item PEP\\1 \\2\n\\3\n@end table\n")
353 ("seerfc" 3 "\n@table @strong\n@item RFC\\1 \\2\n\\3\n@end table\n")
354 ("seetext" 1 "\\1")
355 ("seetitle" 1 "@cite{\\1}")
356 ("seeurl" 2 "\n@table @url\n@item \\1\n\\2\n@end table\n")
357 ("setindexsubitem" 1 (progn (setq cindex t) "@cindex \\1"))
358 ("setreleaseinfo" 1 (progn (setq py2texi-releaseinfo "")))
359 ("setshortversion" 1
360 (progn (setq py2texi-python-short-version (match-string 1 string)) ""))
361 ("shortversion" 0 py2texi-python-short-version)
362 ("sqrt" 0 "")
363 ("stindex" 1 (progn (setq cindex t) "@cindex{\\1}"))
364 ("stmodindex" 1 (progn (setq moindex t) "@moindex{\\1}"))
365 ("strong" 1 "@strong{\\1}")
366 ("sub" 0 "/")
367 ("subsection" 1 "@node \\1\n@subsection \\1\n")
368 ("subsubsection" 1 "@node \\1\n@subsubsection \\1\n")
369 ("sum" 0 "")
370 ("tableofcontents" 0 "")
371 ("term" 1 "@item \\1")
Fred Drake3b095582003-07-02 14:22:48 +0000372 ("TeX" 0 "@TeX{}")
Fred Drakebfc18bd2002-05-03 04:50:51 +0000373 ("textasciitilde" 0 "~")
374 ("textasciicircum" 0 "^")
375 ("textbackslash" 0 "@backslash{}")
Fred Draked805fef2002-06-27 18:38:06 +0000376 ("textgreater" 0 ">")
377 ("textless" 0 "<")
Fred Drakebfc18bd2002-05-03 04:50:51 +0000378 ("textrm" 1 "\\1")
379 ("texttt" 1 "@code{\\1}")
380 ("textunderscore" 0 "_")
381 ("title" 1 (progn (setq title (match-string 1 string)) "@settitle \\1"))
382 ("today" 0 "@today{}")
383 ("token" 1 "@code{\\1}")
384 ("tt" 0 "@destroy")
385 ("ttindex" 1 (progn (setq cindex t) "@cindex{\\1}"))
386 ("u" 0 "@backslash{}u")
387 ("ulink" 2 "\\1")
388 ("UNIX" 0 "UNIX")
389 ("unspecified" 0 "@dots{}")
390 ("url" 1 "@url{\\1}")
391 ("usepackage" 1 "")
392 ("var" 1 "@var{\\1}")
393 ("verbatiminput" 1 "@code{\\1}")
394 ("version" 0 py2texi-python-version)
395 ("versionadded" 1 "@emph{Added in Python version \\1}")
396 ("versionchanged" 1 "@emph{Changed in Python version \\1}")
397 ("vskip" 1 "")
398 ("vspace" 1 "")
399 ("warning" 1 "@emph{\\1}")
400 ("withsubitem" 2 "\\2")
401 ("XXX" 1 "@strong{\\1}"))
402 "Associative list of command substitutions.
403Each list item is of the form (COMMAND ARGNUM SUBSTITUTION) where:
404- COMMAND is LaTeX command name
405- ARGNUM is number of (required) command arguments
406- SUBSTITUTION substitution for the command. It is evaled and you can
407 reference command arguments through the \\N regexp notation in strings.")
408
409(defvar py2texi-magic "@documentclass\n"
410 "\"Magic\" string for auxiliary insertion at the beginning of document.")
411
412(defvar py2texi-dirs '("./" "../texinputs/")
413 "Where to search LaTeX input files.")
414
415(defvar py2texi-buffer "*py2texi*"
416 "The name of a buffer where Texinfo is generated.")
417
418(defconst py2texi-xemacs (string-match "^XEmacs" (emacs-version))
419 "Running under XEmacs?")
420
421
422(defmacro py2texi-search (regexp &rest body)
423 `(progn
424 (goto-char (point-min))
425 (while (re-search-forward ,regexp nil t)
426 ,@body)))
427
428(defmacro py2texi-search-safe (regexp &rest body)
429 `(py2texi-search ,regexp
430 (unless (py2texi-protected)
431 ,@body)))
432
433
434(defun py2texi-message (message)
435 "Report message and stop if `py2texi-stop-on-problems' is non-nil."
436 (if py2texi-stop-on-problems
437 (error message)
438 (message message)))
439
440
441(defun py2texi-backslash-quote (string)
442 "Double backslahes in STRING."
443 (let ((i 0))
444 (save-match-data
445 (while (setq i (string-match "\\\\" string i))
446 (setq string (replace-match "\\\\\\\\" t nil string))
447 (setq i (+ i 2))))
448 string))
449
450
451(defun py2texi (file)
452 "Convert Python LaTeX documentation FILE to Texinfo."
453 (interactive "fFile to convert: ")
454 (switch-to-buffer (get-buffer-create py2texi-buffer))
455 (erase-buffer)
456 (insert-file file)
457 (let ((case-fold-search nil)
458 (title "")
459 (author "")
460 (author-address "")
461 (appendix nil)
462 (findex nil)
463 (obindex nil)
464 (cindex nil)
465 (moindex nil)
466 last-if)
467 (py2texi-process-verbatims)
468 (py2texi-process-comments)
469 (py2texi-process-includes)
470 (py2texi-process-funnyas)
471 (py2texi-process-environments)
472 (py2texi-process-commands)
473 (py2texi-fix-indentation)
474 (py2texi-fix-nodes)
475 (py2texi-fix-references)
476 (py2texi-fix-indices)
477 (py2texi-process-simple-commands)
478 (py2texi-fix-fonts)
479 (py2texi-fix-braces)
480 (py2texi-fix-backslashes)
481 (py2texi-destroy-empties)
482 (py2texi-fix-newlines)
483 (py2texi-adjust-level))
Fred Drake66abcee2002-11-13 19:31:04 +0000484 (let* ((texi-file-name (or py2texi-texi-file-name
485 (py2texi-texi-file-name file)))
486 (info-file-name (or py2texi-info-file-name
487 (py2texi-info-file-name texi-file-name))))
Fred Drakebfc18bd2002-05-03 04:50:51 +0000488 (goto-char (point-min))
489 (when (looking-at py2texi-magic)
490 (delete-region (point) (progn (beginning-of-line 2) (point)))
491 (insert "\\input texinfo @c -*-texinfo-*-\n")
Fred Drake66abcee2002-11-13 19:31:04 +0000492 (insert "@setfilename " info-file-name))
Fred Drakebfc18bd2002-05-03 04:50:51 +0000493 (when (re-search-forward "@chapter" nil t)
494 (texinfo-all-menus-update t))
495 (goto-char (point-min))
Fred Drake66abcee2002-11-13 19:31:04 +0000496 (write-file texi-file-name)
497 (message (format "You can apply `makeinfo %s' now." texi-file-name))))
498
499
500(defun py2texi-texi-file-name (filename)
501 "Generate name of Texinfo file from original file name FILENAME."
502 (concat filename
503 (if (string-match "\\.tex$" filename) "i" ".texi")))
Fred Drakebfc18bd2002-05-03 04:50:51 +0000504
505
506(defun py2texi-info-file-name (filename)
507 "Generate name of info file from original file name FILENAME."
508 (setq filename (expand-file-name filename))
509 (let ((directory (file-name-directory filename))
510 (basename (file-name-nondirectory filename)))
511 (concat directory "python-"
512 (substring basename 0 (- (length basename) 4)) "info")))
513
514
515(defun py2texi-process-verbatims ()
516 "Process and protect verbatim environments."
517 (let (delimiter
518 beg
519 end)
520 (py2texi-search-safe "\\\\begin{\\(verbatim\\|displaymath\\)}"
521 (replace-match "@example")
522 (setq beg (copy-marker (point) nil))
523 (re-search-forward "\\\\end{\\(verbatim\\|displaymath\\)}")
524 (setq end (copy-marker (match-beginning 0) nil))
525 (replace-match "@end example")
526 (py2texi-texinfo-escape beg end)
527 (put-text-property (- beg (length "@example"))
528 (+ end (length "@end example"))
529 'py2texi-protected t))
530 (py2texi-search-safe "\\\\verb\\([^a-z]\\)"
531 (setq delimiter (match-string 1))
532 (replace-match "@code{")
533 (setq beg (copy-marker (point) nil))
534 (re-search-forward (regexp-quote delimiter))
535 (setq end (copy-marker (match-beginning 0) nil))
536 (replace-match "}")
537 (put-text-property (- beg (length "@code{")) (+ end (length "}"))
538 'py2texi-protected t)
539 (py2texi-texinfo-escape beg end))))
540
541
542(defun py2texi-process-comments ()
543 "Remove comments."
544 (let (point)
545 (py2texi-search-safe "%"
546 (setq point (point))
547 (when (save-excursion
548 (re-search-backward "\\(^\\|[^\\]\\(\\\\\\\\\\)*\\)%\\=" nil t))
549 (delete-region (1- point)
550 (save-excursion (beginning-of-line 2) (point)))))))
551
552
553(defun py2texi-process-includes ()
554 "Include LaTeX input files.
555Do not include .ind files."
556 (let ((path (file-name-directory file))
557 filename
558 dirs
559 includefile)
560 (py2texi-search-safe "\\\\input{\\([^}]+\\)}"
561 (setq filename (match-string 1))
562 (unless (save-match-data (string-match "\\.tex$" filename))
563 (setq filename (concat filename ".tex")))
564 (setq includefile (save-match-data
565 (string-match "\\.ind\\.tex$" filename)))
566 (setq dirs py2texi-dirs)
567 (while (and (not includefile) dirs)
568 (setq includefile (concat path (car dirs) filename))
569 (unless (file-exists-p includefile)
570 (setq includefile nil)
571 (setq dirs (cdr dirs))))
572 (if includefile
573 (save-restriction
574 (narrow-to-region (match-beginning 0) (match-end 0))
575 (delete-region (point-min) (point-max))
576 (when (stringp includefile)
577 (insert-file-contents includefile)
578 (goto-char (point-min))
579 (insert "\n")
580 (py2texi-process-verbatims)
581 (py2texi-process-comments)
582 (py2texi-process-includes)))
583 (replace-match (format "\\\\emph{Included file %s}" filename))
584 (py2texi-message (format "Input file %s not found" filename))))))
585
586
587(defun py2texi-process-funnyas ()
588 "Convert @s."
589 (py2texi-search-safe "@"
590 (replace-match "@@")))
591
592
593(defun py2texi-process-environments ()
594 "Process LaTeX environments."
595 (let ((stack ())
596 kind
597 environment
598 parameter
599 arguments
600 n
601 string
602 description)
603 (py2texi-search-safe (concat "\\\\\\(begin\\|end\\|item\\)"
604 "\\({\\([^}]*\\)}\\|[[]\\([^]]*\\)[]]\\|\\)")
605 (setq kind (match-string 1)
606 environment (match-string 3)
607 parameter (match-string 4))
608 (replace-match "")
609 (cond
610 ((string= kind "begin")
611 (setq description (assoc environment py2texi-environments))
612 (if description
613 (progn
614 (setq n (cadr description))
615 (setq description (cddr description))
616 (setq string (py2texi-tex-arguments n))
617 (string-match (py2texi-regexp n) string)
618 ; incorrect but sufficient
619 (insert (replace-match (eval (car description))
620 t nil string))
621 (setq stack (cons (cadr description) stack)))
622 (py2texi-message (format "Unknown environment: %s" environment))
623 (setq stack (cons "" stack))))
624 ((string= kind "end")
625 (insert (eval (car stack)))
626 (setq stack (cdr stack)))
627 ((string= kind "item")
628 (insert "\n@item " (or parameter "") "\n"))))
629 (when stack
630 (py2texi-message (format "Unclosed environment: %s" (car stack))))))
631
632
633(defun py2texi-process-commands ()
634 "Process LaTeX commands."
635 (let (done
636 command
637 command-info
638 string
639 n)
640 (while (not done)
641 (setq done t)
642 (py2texi-search-safe "\\\\\\([a-zA-Z*]+\\)\\(\\[[^]]*\\]\\)?"
643 (setq command (match-string 1))
644 (setq command-info (assoc command py2texi-commands))
645 (if command-info
646 (progn
647 (setq done nil)
648 (replace-match "")
649 (setq command-info (cdr command-info))
650 (setq n (car command-info))
651 (setq string (py2texi-tex-arguments n))
652 (string-match (py2texi-regexp n) string)
653 ; incorrect but sufficient
654 (insert (replace-match (eval (cadr command-info))
655 t nil string)))
656 (py2texi-message (format "Unknown command: %s (not processed)"
657 command)))))))
658
659
660(defun py2texi-argument-pattern (count)
661 (let ((filler "\\(?:[^{}]\\|\\\\{\\|\\\\}\\)*"))
662 (if (<= count 0)
663 filler
664 (concat filler "\\(?:{"
665 (py2texi-argument-pattern (1- count))
666 "}" filler "\\)*" filler))))
667(defconst py2texi-tex-argument
668 (concat
669 "{\\("
670 (py2texi-argument-pattern 10) ;really at least 10!
671 "\\)}[ \t%@c\n]*")
672 "Regexp describing LaTeX command argument including argument separators.")
673
674
675(defun py2texi-regexp (n)
676 "Make regexp matching N LaTeX command arguments."
677 (if (= n 0)
678 ""
679 (let ((regexp "^[^{]*"))
680 (while (> n 0)
681 (setq regexp (concat regexp py2texi-tex-argument))
682 (setq n (1- n)))
683 regexp)))
684
685
686(defun py2texi-tex-arguments (n)
687 "Remove N LaTeX command arguments and return them as a string."
688 (let ((point (point))
689 (i 0)
690 result
691 match)
692 (if (= n 0)
693 (progn
694 (when (re-search-forward "\\=\\({}\\| *\\)" nil t)
695 (replace-match ""))
696 "")
697 (while (> n 0)
698 (unless (re-search-forward
699 "\\(\\=\\|[^\\\\]\\)\\(\\\\\\\\\\)*\\([{}]\\)" nil t)
700 (debug))
701 (if (string= (match-string 3) "{")
702 (setq i (1+ i))
703 (setq i (1- i))
704 (when (<= i 0)
705 (setq n (1- n)))))
706 (setq result (buffer-substring-no-properties point (point)))
707 (while (string-match "\n[ \t]*" result)
708 (setq result (replace-match " " t nil result)))
709 (delete-region point (point))
710 result)))
711
712
713(defun py2texi-process-simple-commands ()
714 "Replace single character LaTeX commands."
715 (let (char)
716 (py2texi-search-safe "\\\\\\([^a-z]\\)"
717 (setq char (match-string 1))
718 (replace-match (format "%s%s"
719 (if (or (string= char "{")
720 (string= char "}")
721 (string= char " "))
722 "@"
723 "")
724 (if (string= char "\\")
725 "\\\\"
726 char))))))
727
728
729(defun py2texi-fix-indentation ()
730 "Remove white space at the beginning of lines."
731 (py2texi-search-safe "^[ \t]+"
732 (replace-match "")))
733
734
735(defun py2texi-fix-nodes ()
736 "Remove unwanted characters from nodes and make nodes unique."
737 (let ((nodes (make-hash-table :test 'equal))
738 id
739 counter
740 string
Fred Drake66abcee2002-11-13 19:31:04 +0000741 label
742 index)
Fred Drakebfc18bd2002-05-03 04:50:51 +0000743 (py2texi-search "^@node +\\(.*\\)$"
744 (setq string (match-string 1))
745 (if py2texi-xemacs
746 (replace-match "@node " t)
747 (replace-match "" t nil nil 1))
Fred Drake66abcee2002-11-13 19:31:04 +0000748 (while (string-match "@label{[^}]*}" string)
Fred Drakebfc18bd2002-05-03 04:50:51 +0000749 (setq label (match-string 0 string))
750 (setq string (replace-match "" t nil string)))
Fred Drake66abcee2002-11-13 19:31:04 +0000751 (while (string-match "@..?index{[^}]*}" string)
752 (setq index (match-string 0 string))
753 (setq string (replace-match "" t nil string)))
Fred Drakebfc18bd2002-05-03 04:50:51 +0000754 (while (string-match "@[a-zA-Z]+\\|[{}():]\\|``\\|''" string)
755 (setq string (replace-match "" t nil string)))
756 (while (string-match " -- " string)
757 (setq string (replace-match " - " t nil string)))
Fred Drake66abcee2002-11-13 19:31:04 +0000758 (while (string-match "\\." string)
759 (setq string (replace-match "" t nil string)))
Fred Drakebfc18bd2002-05-03 04:50:51 +0000760 (when (string-match " +$" string)
761 (setq string (replace-match "" t nil string)))
762 (when (string-match "^\\(Built-in\\|Standard\\) Module \\|The " string)
763 (setq string (replace-match "" t nil string)))
764 (string-match "^[^,]+" string)
765 (setq id (match-string 0 string))
766 (setq counter (gethash id nodes))
767 (if counter
768 (progn
769 (setq counter (1+ counter))
770 (setq string (replace-match (format "\\& %d" counter)
771 t nil string)))
772 (setq counter 1))
773 (setf (gethash id nodes) counter)
774 (insert string)
Fred Drake66abcee2002-11-13 19:31:04 +0000775 (beginning-of-line 3)
Fred Drakebfc18bd2002-05-03 04:50:51 +0000776 (when label
Fred Drake66abcee2002-11-13 19:31:04 +0000777 (insert label "\n"))
778 (when index
779 (insert index "\n")))))
Fred Drakebfc18bd2002-05-03 04:50:51 +0000780
781
782(defun py2texi-fix-references ()
783 "Process labels and make references to point to appropriate nodes."
784 (let ((labels ())
785 node)
786 (py2texi-search-safe "@label{\\([^}]*\\)}"
787 (setq node (save-excursion
788 (save-match-data
789 (and (re-search-backward "@node +\\([^,\n]+\\)" nil t)
790 (match-string 1)))))
791 (when node
792 (setq labels (cons (cons (match-string 1) node) labels)))
793 (replace-match ""))
794 (py2texi-search-safe "@ref{\\([^}]*\\)}"
795 (setq node (assoc (match-string 1) labels))
796 (replace-match "")
797 (when node
798 (insert (format "@ref{%s}" (cdr node)))))))
799
800
801(defun py2texi-fix-indices ()
802 "Remove unwanted characters from @*index commands and create final indices."
803 (py2texi-search-safe "@..?index\\>[^\n]*\\(\\)\n"
804 (replace-match "" t nil nil 1))
805 (py2texi-search-safe "@..?index\\>[^\n]*\\(\\)"
806 (replace-match "\n" t nil nil 1))
807 (py2texi-search-safe "@..?index\\({\\)\\([^}]+\\)\\(}+\\)"
808 (replace-match " " t nil nil 1)
809 (replace-match "" t nil nil 3)
810 (let ((string (match-string 2)))
811 (save-match-data
812 (while (string-match "@[a-z]+{" string)
813 (setq string (replace-match "" nil nil string)))
814 (while (string-match "{" string)
815 (setq string (replace-match "" nil nil string))))
816 (replace-match string t t nil 2)))
817 (py2texi-search-safe "@..?index\\>.*\\([{}]\\|@[a-z]*\\)"
818 (replace-match "" t nil nil 1)
819 (goto-char (match-beginning 0)))
820 (py2texi-search-safe "[^\n]\\(\\)@..?index\\>"
821 (replace-match "\n" t nil nil 1))
822 (goto-char (point-max))
823 (re-search-backward "@indices")
824 (replace-match "")
825 (insert (if moindex
826 (concat "@node Module Index\n"
827 "@unnumbered Module Index\n"
828 "@printindex mo\n")
829 "")
830 (if obindex
831 (concat "@node Class-Exception-Object Index\n"
832 "@unnumbered Class, Exception, and Object Index\n"
833 "@printindex ob\n")
834 "")
835 (if findex
836 (concat "@node Function-Method-Variable Index\n"
837 "@unnumbered Function, Method, and Variable Index\n"
838 "@printindex fn\n")
839 "")
840 (if cindex
841 (concat "@node Miscellaneous Index\n"
842 "@unnumbered Miscellaneous Index\n"
843 "@printindex cp\n")
844 "")))
845
846
847(defun py2texi-fix-backslashes ()
848 "Make backslashes from auxiliary commands."
849 (py2texi-search-safe "@backslash{}"
850 (replace-match "\\\\")))
851
852
853(defun py2texi-fix-fonts ()
854 "Remove garbage after unstructured font commands."
855 (let (string)
856 (py2texi-search-safe "@destroy"
857 (replace-match "")
858 (when (eq (preceding-char) ?{)
859 (forward-char -1)
860 (setq string (py2texi-tex-arguments 1))
861 (insert (substring string 1 (1- (length string))))))))
862
863
864(defun py2texi-fix-braces ()
865 "Escape braces for Texinfo."
866 (let (string)
867 (py2texi-search "{"
868 (unless (or (py2texi-protected)
869 (save-excursion
870 (re-search-backward
871 "@\\([a-zA-Z]*\\|multitable.*\\){\\=" nil t)))
872 (forward-char -1)
873 (setq string (py2texi-tex-arguments 1))
874 (insert "@" (substring string 0 (1- (length string))) "@}")))))
875
876
877(defun py2texi-fix-newlines ()
878 "Remove extra newlines."
879 (py2texi-search "\n\n\n+"
880 (replace-match "\n\n"))
881 (py2texi-search-safe "@item.*\n\n"
882 (delete-backward-char 1))
883 (py2texi-search "@end example"
884 (unless (looking-at "\n\n")
885 (insert "\n"))))
886
887
888(defun py2texi-destroy-empties ()
889 "Remove all comments.
890This avoids some makeinfo errors."
891 (py2texi-search "@c\\>"
892 (unless (eq (py2texi-protected) t)
893 (delete-region (- (point) 2) (save-excursion (end-of-line) (point)))
894 (cond
895 ((looking-at "\n\n")
896 (delete-char 1))
897 ((save-excursion (re-search-backward "^[ \t]*\\=" nil t))
898 (delete-region (save-excursion (beginning-of-line) (point))
899 (1+ (point))))))))
900
901
902(defun py2texi-adjust-level ()
903 "Increase heading level to @chapter, if needed.
904This is only needed for distutils, so it has a very simple form only."
905 (goto-char (point-min))
906 (unless (re-search-forward "@chapter\\>" nil t)
907 (py2texi-search-safe "@section\\>"
908 (replace-match "@chapter" t))
909 (py2texi-search-safe "@\\(sub\\)\\(sub\\)?section\\>"
910 (replace-match "" nil nil nil 1))))
911
912
913(defun py2texi-texinfo-escape (beg end)
914 "Escape Texinfo special characters in region."
915 (save-excursion
916 (goto-char beg)
917 (while (re-search-forward "[@{}]" end t)
918 (replace-match "@\\&"))))
919
920
921(defun py2texi-protected ()
922 "Return protection status of the point before current point."
923 (get-text-property (1- (point)) 'py2texi-protected))
924
925
926;;; Announce
927
928(provide 'py2texi)
929
930
931;;; py2texi.el ends here