Maintain backwards compatibility with python < 2.3 by dynamically
[python/dscho.git] / Doc / tools / py2texi.el
blobb117cad174416453566abce784400dd911220a70
1 ;;; py2texi.el -- Conversion of Python LaTeX documentation to Texinfo
3 ;; Copyright (C) 1998, 1999, 2001, 2002 Milan Zamazal
5 ;; Author: Milan Zamazal <pdm@zamazal.org>
6 ;; Version: $Id$
7 ;; Keywords: python
9 ;; COPYRIGHT NOTICE
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.
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.
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.
26 ;;; Commentary:
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.
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.
38 ;; Where to find it:
39 ;; New versions of this code might be found at
40 ;; http://www.zamazal.org/software/python/py2texi/ .
42 ;;; Code:
45 (require 'texinfo)
46 (eval-when-compile
47 (require 'cl))
50 (defvar py2texi-python-version "2.2"
51 "What to substitute for the \\version macro.")
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.")
59 (defvar py2texi-texi-file-name nil
60 "If non-nil, that string is used as the name of the Texinfo file.
61 Otherwise a generated Texinfo file name is used.")
63 (defvar py2texi-info-file-name nil
64 "If non-nil, that string is used as the name of the Info file.
65 Otherwise a generated Info file name is used.")
67 (defvar py2texi-stop-on-problems nil
68 "*If non-nil, stop when you encouter soft problem.")
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")
76 "@end table\n")
77 ("cmemberdesc" 3
78 "\n@table @code\n@item \\2 \\3\n"
79 "@end table\n")
80 ("classdesc" 2
81 (progn (setq obindex t)
82 "\n@table @code\n@item \\1(\\2)\n@obindex \\1\n")
83 "@end table\n")
84 ("classdesc*" 1
85 (progn (setq obindex t)
86 "\n@table @code\n@item \\1\n@obindex \\1\n")
87 "@end table\n")
88 ("comment" 0 "\n@ignore\n" "\n@end ignore\n")
89 ("csimplemacrodesc" 1
90 (progn (setq cindex t)
91 "\n@table @code\n@item \\1\n@cindex \\1\n")
92 "@end table\n")
93 ("ctypedesc" 1
94 (progn (setq cindex t)
95 "\n@table @code\n@item \\1\n@cindex \\1\n")
96 "@end table\n")
97 ("cvardesc" 2
98 (progn (setq findex t)
99 "\n@table @code\n@item \\1 \\2\n@findex \\2\n")
100 "@end table\n")
101 ("datadesc" 1
102 (progn (setq findex t)
103 "\n@table @code\n@item \\1\n@findex \\1\n")
104 "@end table\n")
105 ("datadescni" 1 "\n@table @code\n@item \\1\n" "@end table\n")
106 ("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")
123 ("envdesc" 2 (concat "\n@table @code"
124 "\n@item @backslash{}begin@{\\1@}\\2")
125 "@end table\n")
126 ("excdesc" 1
127 (progn (setq obindex t)
128 "\n@table @code\n@item \\1\n@obindex \\1\n")
129 "@end table\n")
130 ("excclassdesc" 2
131 (progn (setq obindex t)
132 "\n@table @code\n@item \\1(\\2)\n@obindex \\1\n")
133 "@end table\n")
134 ("flushleft" 0 "" "")
135 ("fulllineitems" 0 "\n@table @code\n" "@end table\n")
136 ("funcdesc" 2
137 (progn (setq findex t)
138 "\n@table @code\n@item \\1(\\2)\n@findex \\1\n")
139 "@end table\n")
140 ("funcdescni" 2 "\n@table @code\n@item \\1(\\2)\n" "@end table\n")
141 ("itemize" 0 "@itemize @bullet" "@end itemize\n")
142 ("list" 2 "\n@table @code\n" "@end table\n")
143 ("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")
151 ("macrodesc" 2 (concat "\n@table @code"
152 "\n@item \\1@{\\2@}")
153 "@end table\n")
154 ("memberdesc" 1
155 (progn (setq findex t)
156 "\n@table @code\n@item \\1\n@findex \\1\n")
157 "@end table\n")
158 ("memberdescni" 1 "\n@table @code\n@item \\1\n" "@end table\n")
159 ("methoddesc" 2
160 (progn (setq findex t)
161 "\n@table @code\n@item \\1(\\2)\n@findex \\1\n")
162 "@end table\n")
163 ("methoddescni" 2 "\n@table @code\n@item \\1(\\2)\n" "@end table\n")
164 ("notice" 0 "@emph{Notice:} " "")
165 ("opcodedesc" 2
166 (progn (setq findex t)
167 "\n@table @code\n@item \\1 \\2\n@findex \\1\n")
168 "@end table\n")
169 ("productionlist" 0 "\n@table @code\n" "@end table\n")
170 ("quotation" 0 "@quotation" "@end quotation")
171 ("seealso" 0 "See also:\n@table @emph\n" "@end table\n")
172 ("seealso*" 0 "@table @emph\n" "@end table\n")
173 ("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 ("alltt" 0 "@example" "@end example")
195 "Associative list defining substitutions for environments.
196 Each list item is of the form (ENVIRONMENT ARGNUM BEGIN END) where:
197 - ENVIRONMENT is LaTeX environment name
198 - ARGNUM is number of (required) macro arguments
199 - BEGIN is substitution for \begin{ENVIRONMENT}
200 - END is substitution for \end{ENVIRONMENT}
201 Both BEGIN and END are evaled. Moreover, you can reference arguments through
202 \N regular expression notation in strings of BEGIN.")
204 (defconst py2texi-commands
205 '(("AA" 0 "@AA{}")
206 ("aa" 0 "@aa{}")
207 ("ABC" 0 "ABC")
208 ("appendix" 0 (progn (setq appendix t) ""))
209 ("ASCII" 0 "ASCII")
210 ("author" 1 (progn (setq author (match-string 1 string)) ""))
211 ("authoraddress" 1
212 (progn (setq author-address (match-string 1 string)) ""))
213 ("b" 1 "@w{\\1}")
214 ("bf" 0 "@destroy")
215 ("bifuncindex" 1 (progn (setq findex t) "@findex{\\1}\x01"))
216 ("C" 0 "C")
217 ("c" 0 "@,")
218 ("catcode" 0 "")
219 ("cdata" 1 "@code{\\1}")
220 ("centerline" 1 "@center \\1")
221 ("cfuncline" 3 "@itemx \\1 \\2(\\3)\n@findex \\2")
222 ("cfunction" 1 "@code{\\1}")
223 ("chapter" 1 (format "@node \\1\n@%s \\1\n"
224 (if appendix "appendix" "chapter")))
225 ("chapter*" 1 "@node \\1\n@unnumbered \\1\n")
226 ("character" 1 "@samp{\\1}")
227 ("citetitle" 1 "@ref{Top,,,\\1}")
228 ("class" 1 "@code{\\1}")
229 ("cmemberline" 3 "@itemx \\2 \\3\n")
230 ("code" 1 "@code{\\1}")
231 ("command" 1 "@command{\\1}")
232 ("constant" 1 "@code{\\1}")
233 ("copyright" 1 "@copyright{}")
234 ("Cpp" 0 "C++")
235 ("csimplemacro" 1 "@code{\\1}")
236 ("ctype" 1 "@code{\\1}")
237 ("dataline" 1 (progn (setq findex t) "@item \\1\n@findex \\1\n"))
238 ("date" 1 "\\1")
239 ("declaremodule" 2 (progn (setq cindex t) "@label{\\2}@cindex{\\2}\x01"))
240 ("deprecated" 2 "@emph{This is deprecated in Python \\1. \\2}")
241 ("dfn" 1 "@dfn{\\1}")
242 ("documentclass" 1 py2texi-magic)
243 ("e" 0 "@backslash{}")
244 ("else" 0 (concat "@end ifinfo\n@" (setq last-if "iftex")))
245 ("env" 1 "@code{\\1}")
246 ("EOF" 0 "@code{EOF}")
247 ("email" 1 "@email{\\1}")
248 ("emph" 1 "@emph{\\1}")
249 ("envvar" 1 "@env{\\1}")
250 ("exception" 1 "@code{\\1}")
251 ("exindex" 1 (progn (setq obindex t) "@obindex{\\1}\x01"))
252 ("fi" 0 (concat "@end " last-if))
253 ("file" 1 "@file{\\1}")
254 ("filenq" 1 "@file{\\1}")
255 ("filevar" 1 "@file{@var{\\1}}")
256 ("footnote" 1 "@footnote{\\1}")
257 ("frac" 0 "")
258 ("funcline" 2 (progn (setq findex t) "@item \\1 \\2\n@findex \\1\x01"))
259 ("funclineni" 2 "@item \\1 \\2")
260 ("function" 1 "@code{\\1}")
261 ("grammartoken" 1 "@code{\\1}")
262 ("hline" 0 "")
263 ("ifhtml" 0 (concat "@" (setq last-if "ifinfo")))
264 ("iftexi" 0 (concat "@" (setq last-if "ifinfo")))
265 ("index" 1 (progn (setq cindex t) "@cindex{\\1}\x01"))
266 ("indexii" 2 (progn (setq cindex t) "@cindex{\\1 \\2}\x01"))
267 ("indexiii" 3 (progn (setq cindex t) "@cindex{\\1 \\2 \\3}\x01"))
268 ("indexiv" 3 (progn (setq cindex t) "@cindex{\\1 \\2 \\3 \\4}\x01"))
269 ("infinity" 0 "@emph{infinity}")
270 ("it" 0 "@destroy")
271 ("kbd" 1 "@key{\\1}")
272 ("keyword" 1 "@code{\\1}")
273 ("kwindex" 1 (progn (setq cindex t) "@cindex{\\1}\x01"))
274 ("label" 1 "@label{\\1}")
275 ("Large" 0 "")
276 ("LaTeX" 0 "La@TeX{}")
277 ("large" 0 "")
278 ("ldots" 0 "@dots{}")
279 ("leftline" 1 "\\1")
280 ("lineii" 2 "@item \\1 @tab \\2")
281 ("lineiii" 3 "@item \\1 @tab \\2 @tab \\3")
282 ("lineiv" 4 "@item \\1 @tab \\2 @tab \\3 @tab \\4")
283 ("linev" 5 "@item \\1 @tab \\2 @tab \\3 @tab \\4 @tab \\5")
284 ("localmoduletable" 0 "")
285 ("longprogramopt" 1 "@option{--\\1}")
286 ("macro" 1 "@code{@backslash{}\\1}")
287 ("mailheader" 1 "@code{\\1}")
288 ("makeindex" 0 "")
289 ("makemodindex" 0 "")
290 ("maketitle" 0 (concat "@top " title "\n"))
291 ("makevar" 1 "@code{\\1}")
292 ("manpage" 2 "@samp{\\1(\\2)}")
293 ("mbox" 1 "@w{\\1}")
294 ("member" 1 "@code{\\1}")
295 ("memberline" 1 "@item \\1\n@findex \\1\n")
296 ("menuselection" 1 "@samp{\\1}")
297 ("method" 1 "@code{\\1}")
298 ("methodline" 2 (progn (setq moindex t) "@item \\1(\\2)\n@moindex \\1\n"))
299 ("methodlineni" 2 "@item \\1(\\2)\n")
300 ("mimetype" 1 "@samp{\\1}")
301 ("module" 1 "@samp{\\1}")
302 ("moduleauthor" 2 "")
303 ("modulesynopsis" 1 "\\1")
304 ("moreargs" 0 "@dots{}")
305 ("n" 0 "@backslash{}n")
306 ("newcommand" 2 "")
307 ("newsgroup" 1 "@samp{\\1}")
308 ("nodename" 1
309 (save-excursion
310 (save-match-data
311 (re-search-backward "^@node "))
312 (delete-region (point) (save-excursion (end-of-line) (point)))
313 (insert "@node " (match-string 1 string))
314 ""))
315 ("noindent" 0 "@noindent ")
316 ("note" 1 "@emph{Note:} \\1")
317 ("NULL" 0 "@code{NULL}")
318 ("obindex" 1 (progn (setq obindex t) "@obindex{\\1}\x01"))
319 ("opindex" 1 (progn (setq cindex t) "@cindex{\\1}\x01"))
320 ("option" 1 "@option{\\1}")
321 ("optional" 1 "[\\1]")
322 ("pep" 1 (progn (setq cindex t) "PEP@ \\1@cindex PEP \\1\n"))
323 ("pi" 0 "pi")
324 ("platform" 1 "")
325 ("plusminus" 0 "+-")
326 ("POSIX" 0 "POSIX")
327 ("production" 2 "@item \\1 \\2")
328 ("productioncont" 1 "@item @w{} \\1")
329 ("program" 1 "@command{\\1}")
330 ("programopt" 1 "@option{\\1}")
331 ("protect" 0 "")
332 ("pytype" 1 "@code{\\1}")
333 ("ref" 1 "@ref{\\1}")
334 ("refbimodindex" 1 (progn (setq moindex t) "@moindex{\\1}\x01"))
335 ("refmodindex" 1 (progn (setq moindex t) "@moindex{\\1}\x01"))
336 ("refmodule" 1 "@samp{\\1}")
337 ("refstmodindex" 1 (progn (setq moindex t) "@moindex{\\1}\x01"))
338 ("regexp" 1 "\"\\1\"")
339 ("release" 1
340 (progn (setq py2texi-python-version (match-string 1 string)) ""))
341 ("renewcommand" 2 "")
342 ("rfc" 1 (progn (setq cindex t) "RFC@ \\1@cindex RFC \\1\n"))
343 ("rm" 0 "@destroy")
344 ("samp" 1 "@samp{\\1}")
345 ("section" 1 (let ((str (match-string 1 string)))
346 (save-match-data
347 (if (string-match "\\(.*\\)[ \t\n]*---[ \t\n]*\\(.*\\)"
348 str)
349 (format
350 "@node %s\n@section %s\n"
351 (py2texi-backslash-quote (match-string 1 str))
352 (py2texi-backslash-quote (match-string 2 str)))
353 "@node \\1\n@section \\1\n"))))
354 ("sectionauthor" 2 "")
355 ("seemodule" 2 "@ref{\\1} \\2")
356 ("seepep" 3 "\n@table @strong\n@item PEP\\1 \\2\n\\3\n@end table\n")
357 ("seerfc" 3 "\n@table @strong\n@item RFC\\1 \\2\n\\3\n@end table\n")
358 ("seetext" 1 "\\1")
359 ("seetitle" 1 "@cite{\\1}")
360 ("seeurl" 2 "\n@table @url\n@item \\1\n\\2\n@end table\n")
361 ("setindexsubitem" 1 (progn (setq cindex t) "@cindex \\1\x01"))
362 ("setreleaseinfo" 1 (progn (setq py2texi-releaseinfo "")))
363 ("setshortversion" 1
364 (progn (setq py2texi-python-short-version (match-string 1 string)) ""))
365 ("shortversion" 0 py2texi-python-short-version)
366 ("sqrt" 0 "")
367 ("stindex" 1 (progn (setq cindex t) "@cindex{\\1}\x01"))
368 ("stmodindex" 1 (progn (setq moindex t) "@moindex{\\1}\x01"))
369 ("strong" 1 "@strong{\\1}")
370 ("sub" 0 "/")
371 ("subsection" 1 "@node \\1\n@subsection \\1\n")
372 ("subsubsection" 1 "@node \\1\n@subsubsection \\1\n")
373 ("sum" 0 "")
374 ("tableofcontents" 0 "")
375 ("term" 1 "@item \\1")
376 ("TeX" 0 "@TeX{}")
377 ("textasciitilde" 0 "~")
378 ("textasciicircum" 0 "^")
379 ("textbackslash" 0 "@backslash{}")
380 ("textgreater" 0 ">")
381 ("textless" 0 "<")
382 ("textrm" 1 "\\1")
383 ("texttt" 1 "@code{\\1}")
384 ("textunderscore" 0 "_")
385 ("title" 1 (progn (setq title (match-string 1 string)) "@settitle \\1"))
386 ("today" 0 "@today{}")
387 ("token" 1 "@code{\\1}")
388 ("tt" 0 "@destroy")
389 ("ttindex" 1 (progn (setq cindex t) "@cindex{\\1}\x01"))
390 ("u" 0 "@backslash{}u")
391 ("ulink" 2 "\\1")
392 ("UNIX" 0 "UNIX")
393 ("unspecified" 0 "@dots{}")
394 ("url" 1 "@url{\\1}")
395 ("usepackage" 1 "")
396 ("var" 1 "@var{\\1}")
397 ("verbatiminput" 1 "@code{\\1}")
398 ("version" 0 py2texi-python-version)
399 ("versionadded" 1 "@emph{Added in Python version \\1}")
400 ("versionchanged" 1 "@emph{Changed in Python version \\1}")
401 ("vskip" 1 "")
402 ("vspace" 1 "")
403 ("warning" 1 "@emph{\\1}")
404 ("withsubitem" 2 "\\2")
405 ("XXX" 1 "@strong{\\1}"))
406 "Associative list of command substitutions.
407 Each list item is of the form (COMMAND ARGNUM SUBSTITUTION) where:
408 - COMMAND is LaTeX command name
409 - ARGNUM is number of (required) command arguments
410 - SUBSTITUTION substitution for the command. It is evaled and you can
411 reference command arguments through the \\N regexp notation in strings.")
413 (defvar py2texi-magic "@documentclass\n"
414 "\"Magic\" string for auxiliary insertion at the beginning of document.")
416 (defvar py2texi-dirs '("./" "../texinputs/")
417 "Where to search LaTeX input files.")
419 (defvar py2texi-buffer "*py2texi*"
420 "The name of a buffer where Texinfo is generated.")
422 (defconst py2texi-xemacs (string-match "^XEmacs" (emacs-version))
423 "Running under XEmacs?")
426 (defmacro py2texi-search (regexp &rest body)
427 `(progn
428 (goto-char (point-min))
429 (while (re-search-forward ,regexp nil t)
430 ,@body)))
432 (defmacro py2texi-search-safe (regexp &rest body)
433 `(py2texi-search ,regexp
434 (unless (py2texi-protected)
435 ,@body)))
438 (defun py2texi-message (message)
439 "Report message and stop if `py2texi-stop-on-problems' is non-nil."
440 (if py2texi-stop-on-problems
441 (error message)
442 (message message)))
445 (defun py2texi-backslash-quote (string)
446 "Double backslahes in STRING."
447 (let ((i 0))
448 (save-match-data
449 (while (setq i (string-match "\\\\" string i))
450 (setq string (replace-match "\\\\\\\\" t nil string))
451 (setq i (+ i 2))))
452 string))
455 (defun py2texi (file)
456 "Convert Python LaTeX documentation FILE to Texinfo."
457 (interactive "fFile to convert: ")
458 (switch-to-buffer (get-buffer-create py2texi-buffer))
459 (erase-buffer)
460 (insert-file file)
461 (let ((case-fold-search nil)
462 (title "")
463 (author "")
464 (author-address "")
465 (appendix nil)
466 (findex nil)
467 (obindex nil)
468 (cindex nil)
469 (moindex nil)
470 last-if)
471 (py2texi-process-verbatims)
472 (py2texi-process-comments)
473 (py2texi-process-includes)
474 (py2texi-process-funnyas)
475 (py2texi-process-environments)
476 (py2texi-process-commands)
477 (py2texi-fix-indentation)
478 (py2texi-fix-nodes)
479 (py2texi-fix-references)
480 (py2texi-fix-indices)
481 (py2texi-process-simple-commands)
482 (py2texi-fix-fonts)
483 (py2texi-fix-braces)
484 (py2texi-fix-backslashes)
485 (py2texi-destroy-empties)
486 (py2texi-fix-newlines)
487 (py2texi-adjust-level))
488 (let* ((texi-file-name (or py2texi-texi-file-name
489 (py2texi-texi-file-name file)))
490 (info-file-name (or py2texi-info-file-name
491 (py2texi-info-file-name texi-file-name))))
492 (goto-char (point-min))
493 (when (looking-at py2texi-magic)
494 (delete-region (point) (progn (beginning-of-line 2) (point)))
495 (insert "\\input texinfo @c -*-texinfo-*-\n")
496 (insert "@setfilename " info-file-name))
497 (when (re-search-forward "@chapter" nil t)
498 (texinfo-all-menus-update t))
499 (goto-char (point-min))
500 (write-file texi-file-name)
501 (message (format "You can apply `makeinfo %s' now." texi-file-name))))
504 (defun py2texi-texi-file-name (filename)
505 "Generate name of Texinfo file from original file name FILENAME."
506 (concat filename
507 (if (string-match "\\.tex$" filename) "i" ".texi")))
510 (defun py2texi-info-file-name (filename)
511 "Generate name of info file from original file name FILENAME."
512 (setq filename (expand-file-name filename))
513 (let ((directory (file-name-directory filename))
514 (basename (file-name-nondirectory filename)))
515 (concat directory "python-"
516 (substring basename 0 (- (length basename) 4)) "info")))
519 (defun py2texi-process-verbatims ()
520 "Process and protect verbatim environments."
521 (let (delimiter
523 end)
524 (py2texi-search-safe "\\\\begin{\\(verbatim\\|displaymath\\)}"
525 (replace-match "@example")
526 (setq beg (copy-marker (point) nil))
527 (re-search-forward "\\\\end{\\(verbatim\\|displaymath\\)}")
528 (setq end (copy-marker (match-beginning 0) nil))
529 (replace-match "@end example")
530 (py2texi-texinfo-escape beg end)
531 (put-text-property (- beg (length "@example"))
532 (+ end (length "@end example"))
533 'py2texi-protected t))
534 (py2texi-search-safe "\\\\verb\\([^a-z]\\)"
535 (setq delimiter (match-string 1))
536 (replace-match "@code{")
537 (setq beg (copy-marker (point) nil))
538 (re-search-forward (regexp-quote delimiter))
539 (setq end (copy-marker (match-beginning 0) nil))
540 (replace-match "}")
541 (put-text-property (- beg (length "@code{")) (+ end (length "}"))
542 'py2texi-protected t)
543 (py2texi-texinfo-escape beg end))))
546 (defun py2texi-process-comments ()
547 "Remove comments."
548 (let (point)
549 (py2texi-search-safe "%"
550 (setq point (point))
551 (when (save-excursion
552 (re-search-backward "\\(^\\|[^\\]\\(\\\\\\\\\\)*\\)%\\=" nil t))
553 (delete-region (1- point)
554 (save-excursion (beginning-of-line 2) (point)))))))
557 (defun py2texi-process-includes ()
558 "Include LaTeX input files.
559 Do not include .ind files."
560 (let ((path (file-name-directory file))
561 filename
562 dirs
563 includefile)
564 (py2texi-search-safe "\\\\input{\\([^}]+\\)}"
565 (setq filename (match-string 1))
566 (unless (save-match-data (string-match "\\.tex$" filename))
567 (setq filename (concat filename ".tex")))
568 (setq includefile (save-match-data
569 (string-match "\\.ind\\.tex$" filename)))
570 (setq dirs py2texi-dirs)
571 (while (and (not includefile) dirs)
572 (setq includefile (concat path (car dirs) filename))
573 (unless (file-exists-p includefile)
574 (setq includefile nil)
575 (setq dirs (cdr dirs))))
576 (if includefile
577 (save-restriction
578 (narrow-to-region (match-beginning 0) (match-end 0))
579 (delete-region (point-min) (point-max))
580 (when (stringp includefile)
581 (insert-file-contents includefile)
582 (goto-char (point-min))
583 (insert "\n")
584 (py2texi-process-verbatims)
585 (py2texi-process-comments)
586 (py2texi-process-includes)))
587 (replace-match (format "\\\\emph{Included file %s}" filename))
588 (py2texi-message (format "Input file %s not found" filename))))))
591 (defun py2texi-process-funnyas ()
592 "Convert @s."
593 (py2texi-search-safe "@"
594 (replace-match "@@")))
597 (defun py2texi-process-environments ()
598 "Process LaTeX environments."
599 (let ((stack ())
600 kind
601 environment
602 parameter
603 arguments
605 string
606 description)
607 (py2texi-search-safe (concat "\\\\\\(begin\\|end\\|item\\)"
608 "\\({\\([^}]*\\)}\\|[[]\\([^]]*\\)[]]\\|\\)")
609 (setq kind (match-string 1)
610 environment (match-string 3)
611 parameter (match-string 4))
612 (replace-match "")
613 (cond
614 ((string= kind "begin")
615 (setq description (assoc environment py2texi-environments))
616 (if description
617 (progn
618 (setq n (cadr description))
619 (setq description (cddr description))
620 (setq string (py2texi-tex-arguments n))
621 (string-match (py2texi-regexp n) string)
622 ; incorrect but sufficient
623 (insert (replace-match (eval (car description))
624 t nil string))
625 (setq stack (cons (cadr description) stack)))
626 (py2texi-message (format "Unknown environment: %s" environment))
627 (setq stack (cons "" stack))))
628 ((string= kind "end")
629 (insert (eval (car stack)))
630 (setq stack (cdr stack)))
631 ((string= kind "item")
632 (insert "\n@item " (or parameter "") "\n"))))
633 (when stack
634 (py2texi-message (format "Unclosed environment: %s" (car stack))))))
637 (defun py2texi-process-commands ()
638 "Process LaTeX commands."
639 (let (done
640 command
641 command-info
642 string
644 (while (not done)
645 (setq done t)
646 (py2texi-search-safe "\\\\\\([a-zA-Z*]+\\)\\(\\[[^]]*\\]\\)?"
647 (setq command (match-string 1))
648 (setq command-info (assoc command py2texi-commands))
649 (if command-info
650 (progn
651 (setq done nil)
652 (replace-match "")
653 (setq command-info (cdr command-info))
654 (setq n (car command-info))
655 (setq string (py2texi-tex-arguments n))
656 (string-match (py2texi-regexp n) string)
657 ; incorrect but sufficient
658 (insert (replace-match (eval (cadr command-info))
659 t nil string)))
660 (py2texi-message (format "Unknown command: %s (not processed)"
661 command)))))))
664 (defun py2texi-argument-pattern (count)
665 (let ((filler "\\(?:[^{}]\\|\\\\{\\|\\\\}\\)*"))
666 (if (<= count 0)
667 filler
668 (concat filler "\\(?:{"
669 (py2texi-argument-pattern (1- count))
670 "}" filler "\\)*" filler))))
671 (defconst py2texi-tex-argument
672 (concat
673 "{\\("
674 (py2texi-argument-pattern 10) ;really at least 10!
675 "\\)}[ \t%@c\n]*")
676 "Regexp describing LaTeX command argument including argument separators.")
679 (defun py2texi-regexp (n)
680 "Make regexp matching N LaTeX command arguments."
681 (if (= n 0)
683 (let ((regexp "^[^{]*"))
684 (while (> n 0)
685 (setq regexp (concat regexp py2texi-tex-argument))
686 (setq n (1- n)))
687 regexp)))
690 (defun py2texi-tex-arguments (n)
691 "Remove N LaTeX command arguments and return them as a string."
692 (let ((point (point))
693 (i 0)
694 result
695 match)
696 (if (= n 0)
697 (progn
698 (when (re-search-forward "\\=\\({}\\| *\\)" nil t)
699 (replace-match ""))
701 (while (> n 0)
702 (unless (re-search-forward
703 "\\(\\=\\|[^\\\\]\\)\\(\\\\\\\\\\)*\\([{}]\\)" nil t)
704 (debug))
705 (if (string= (match-string 3) "{")
706 (setq i (1+ i))
707 (setq i (1- i))
708 (when (<= i 0)
709 (setq n (1- n)))))
710 (setq result (buffer-substring-no-properties point (point)))
711 (while (string-match "\n[ \t]*" result)
712 (setq result (replace-match " " t nil result)))
713 (delete-region point (point))
714 result)))
717 (defun py2texi-process-simple-commands ()
718 "Replace single character LaTeX commands."
719 (let (char)
720 (py2texi-search-safe "\\\\\\([^a-z]\\)"
721 (setq char (match-string 1))
722 (replace-match (format "%s%s"
723 (if (or (string= char "{")
724 (string= char "}")
725 (string= char " "))
728 (if (string= char "\\")
729 "\\\\"
730 char))))))
733 (defun py2texi-fix-indentation ()
734 "Remove white space at the beginning of lines."
735 (py2texi-search-safe "^[ \t]+"
736 (replace-match "")))
739 (defun py2texi-fix-nodes ()
740 "Remove unwanted characters from nodes and make nodes unique."
741 (let ((nodes (make-hash-table :test 'equal))
743 counter
744 string
745 label
746 index)
747 (py2texi-search "^@node +\\(.*\\)$"
748 (setq string (match-string 1))
749 (if py2texi-xemacs
750 (replace-match "@node " t)
751 (replace-match "" t nil nil 1))
752 (while (string-match "@label{[^}]*}" string)
753 (setq label (match-string 0 string))
754 (setq string (replace-match "" t nil string)))
755 (while (string-match "@..?index{[^}]*}\x01" string)
756 (setq index (match-string 0 string))
757 (setq string (replace-match "" t nil string)))
758 (while (string-match "@[a-zA-Z]+\\|[{}():]\\|``\\|''" string)
759 (setq string (replace-match "" t nil string)))
760 (while (string-match " -- " string)
761 (setq string (replace-match " - " t nil string)))
762 (while (string-match "\\." string)
763 (setq string (replace-match "" t nil string)))
764 (when (string-match " +$" string)
765 (setq string (replace-match "" t nil string)))
766 (when (string-match "^\\(Built-in\\|Standard\\) Module \\|The " string)
767 (setq string (replace-match "" t nil string)))
768 (string-match "^[^,]+" string)
769 (setq id (match-string 0 string))
770 (setq counter (gethash id nodes))
771 (if counter
772 (progn
773 (setq counter (1+ counter))
774 (setq string (replace-match (format "\\& %d" counter)
775 t nil string)))
776 (setq counter 1))
777 (setf (gethash id nodes) counter)
778 (insert string)
779 (beginning-of-line 3)
780 (when label
781 (insert label "\n"))
782 (when index
783 (insert index "\n")))))
786 (defun py2texi-fix-references ()
787 "Process labels and make references to point to appropriate nodes."
788 (let ((labels ())
789 node)
790 (py2texi-search-safe "@label{\\([^}]*\\)}"
791 (setq node (save-excursion
792 (save-match-data
793 (and (re-search-backward "@node +\\([^,\n]+\\)" nil t)
794 (match-string 1)))))
795 (when node
796 (setq labels (cons (cons (match-string 1) node) labels)))
797 (replace-match ""))
798 (py2texi-search-safe "@ref{\\([^}]*\\)}"
799 (setq node (assoc (match-string 1) labels))
800 (replace-match "")
801 (when node
802 (insert (format "@ref{%s}" (cdr node)))))))
805 (defun py2texi-fix-indices ()
806 "Remove unwanted characters from @*index commands and create final indices."
807 (py2texi-search-safe "@..?index\\>[^\n\x01]*\\(\x01\\)\n"
808 (replace-match "" t nil nil 1))
809 (py2texi-search-safe "@..?index\\>[^\n\x01]*\\(\x01\\)"
810 (replace-match "\n" t nil nil 1))
811 (py2texi-search-safe "@..?index\\({\\)\\([^}]+\\)\\(}+\\)"
812 (replace-match " " t nil nil 1)
813 (replace-match "" t nil nil 3)
814 (let ((string (match-string 2)))
815 (save-match-data
816 (while (string-match "@[a-z]+{" string)
817 (setq string (replace-match "" nil nil string)))
818 (while (string-match "{" string)
819 (setq string (replace-match "" nil nil string))))
820 (replace-match string t t nil 2)))
821 (py2texi-search-safe "@..?index\\>.*\\([{}]\\|@[a-z]*\\)"
822 (replace-match "" t nil nil 1)
823 (goto-char (match-beginning 0)))
824 (py2texi-search-safe "[^\n]\\(\\)@..?index\\>"
825 (replace-match "\n" t nil nil 1))
826 (goto-char (point-max))
827 (re-search-backward "@indices")
828 (replace-match "")
829 (insert (if moindex
830 (concat "@node Module Index\n"
831 "@unnumbered Module Index\n"
832 "@printindex mo\n")
834 (if obindex
835 (concat "@node Class-Exception-Object Index\n"
836 "@unnumbered Class, Exception, and Object Index\n"
837 "@printindex ob\n")
839 (if findex
840 (concat "@node Function-Method-Variable Index\n"
841 "@unnumbered Function, Method, and Variable Index\n"
842 "@printindex fn\n")
844 (if cindex
845 (concat "@node Miscellaneous Index\n"
846 "@unnumbered Miscellaneous Index\n"
847 "@printindex cp\n")
848 "")))
851 (defun py2texi-fix-backslashes ()
852 "Make backslashes from auxiliary commands."
853 (py2texi-search-safe "@backslash{}"
854 (replace-match "\\\\")))
857 (defun py2texi-fix-fonts ()
858 "Remove garbage after unstructured font commands."
859 (let (string)
860 (py2texi-search-safe "@destroy"
861 (replace-match "")
862 (when (eq (preceding-char) ?{)
863 (forward-char -1)
864 (setq string (py2texi-tex-arguments 1))
865 (insert (substring string 1 (1- (length string))))))))
868 (defun py2texi-fix-braces ()
869 "Escape braces for Texinfo."
870 (let (string)
871 (py2texi-search "{"
872 (unless (or (py2texi-protected)
873 (save-excursion
874 (re-search-backward
875 "@\\([a-zA-Z]*\\|multitable.*\\){\\=" nil t)))
876 (forward-char -1)
877 (setq string (py2texi-tex-arguments 1))
878 (insert "@" (substring string 0 (1- (length string))) "@}")))))
881 (defun py2texi-fix-newlines ()
882 "Remove extra newlines."
883 (py2texi-search "\n\n\n+"
884 (replace-match "\n\n"))
885 (py2texi-search-safe "@item.*\n\n"
886 (delete-backward-char 1))
887 (py2texi-search "@end example"
888 (unless (looking-at "\n\n")
889 (insert "\n"))))
892 (defun py2texi-destroy-empties ()
893 "Remove all comments.
894 This avoids some makeinfo errors."
895 (py2texi-search "@c\\>"
896 (unless (eq (py2texi-protected) t)
897 (delete-region (- (point) 2) (save-excursion (end-of-line) (point)))
898 (cond
899 ((looking-at "\n\n")
900 (delete-char 1))
901 ((save-excursion (re-search-backward "^[ \t]*\\=" nil t))
902 (delete-region (save-excursion (beginning-of-line) (point))
903 (1+ (point))))))))
906 (defun py2texi-adjust-level ()
907 "Increase heading level to @chapter, if needed.
908 This is only needed for distutils, so it has a very simple form only."
909 (goto-char (point-min))
910 (unless (re-search-forward "@chapter\\>" nil t)
911 (py2texi-search-safe "@section\\>"
912 (replace-match "@chapter" t))
913 (py2texi-search-safe "@\\(sub\\)\\(sub\\)?section\\>"
914 (replace-match "" nil nil nil 1))))
917 (defun py2texi-texinfo-escape (beg end)
918 "Escape Texinfo special characters in region."
919 (save-excursion
920 (goto-char beg)
921 (while (re-search-forward "[@{}]" end t)
922 (replace-match "@\\&"))))
925 (defun py2texi-protected ()
926 "Return protection status of the point before current point."
927 (get-text-property (1- (point)) 'py2texi-protected))
930 ;;; Announce
932 (provide 'py2texi)
935 ;;; py2texi.el ends here