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