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>
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
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
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.
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.
35 ;; Load this file and apply `M-x py2texi'. You will be asked for name of a
36 ;; file to be converted.
39 ;; New versions of this code might be found at
40 ;; http://www.zamazal.org/software/python/py2texi/ .
50 (defvar py2texi-python-version
"2.2"
51 "What to substitute for the \\version macro.")
53 (defvar py2texi-python-short-version
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")
74 (progn (setq findex t
)
75 "\n@table @code\n@item \\1 \\2(\\3)\n@findex \\2\n")
78 "\n@table @code\n@item \\2 \\3\n"
81 (progn (setq obindex t
)
82 "\n@table @code\n@item \\1(\\2)\n@obindex \\1\n")
85 (progn (setq obindex t
)
86 "\n@table @code\n@item \\1\n@obindex \\1\n")
88 ("comment" 0 "\n@ignore\n" "\n@end ignore\n")
90 (progn (setq cindex t
)
91 "\n@table @code\n@item \\1\n@cindex \\1\n")
94 (progn (setq cindex t
)
95 "\n@table @code\n@item \\1\n@cindex \\1\n")
98 (progn (setq findex t
)
99 "\n@table @code\n@item \\1 \\2\n@findex \\2\n")
102 (progn (setq findex t
)
103 "\n@table @code\n@item \\1\n@findex \\1\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 "" "")
110 (concat "@defcodeindex mo\n"
113 (format "@title " title
"\n")
114 (format "@author " author
"\n")
118 "@node Top, , , (dir)\n")
122 ("enumerate" 0 "@enumerate" "@end enumerate")
123 ("envdesc" 2 (concat "\n@table @code"
124 "\n@item @backslash{}begin@{\\1@}\\2")
127 (progn (setq obindex t
)
128 "\n@table @code\n@item \\1\n@obindex \\1\n")
131 (progn (setq obindex t
)
132 "\n@table @code\n@item \\1(\\2)\n@obindex \\1\n")
134 ("flushleft" 0 "" "")
135 ("fulllineitems" 0 "\n@table @code\n" "@end table\n")
137 (progn (setq findex t
)
138 "\n@table @code\n@item \\1(\\2)\n@findex \\1\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")
147 ("longtableiii" 5 (concat "@multitable @columnfractions .33 .33 .33\n"
148 "@item \\3 @tab \\4 @tab \\5\n"
149 "@item ------- @tab ------ @tab ------\n")
151 ("macrodesc" 2 (concat "\n@table @code"
152 "\n@item \\1@{\\2@}")
155 (progn (setq findex t
)
156 "\n@table @code\n@item \\1\n@findex \\1\n")
158 ("memberdescni" 1 "\n@table @code\n@item \\1\n" "@end table\n")
160 (progn (setq findex t
)
161 "\n@table @code\n@item \\1(\\2)\n@findex \\1\n")
163 ("methoddescni" 2 "\n@table @code\n@item \\1(\\2)\n" "@end table\n")
164 ("notice" 0 "@emph{Notice:} " "")
166 (progn (setq findex t
)
167 "\n@table @code\n@item \\1 \\2\n@findex \\1\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 "" "")
175 ("tableii" 4 (concat "@multitable @columnfractions .5 .5\n"
176 "@item \\3 @tab \\4\n"
177 "@item ------- @tab ------ \n")
179 ("tableiii" 5 (concat "@multitable @columnfractions .33 .33 .33\n"
180 "@item \\3 @tab \\4 @tab \\5\n"
181 "@item ------- @tab ------ @tab ------\n")
184 "@multitable @columnfractions .25 .25 .25 .25\n"
185 "@item \\3 @tab \\4 @tab \\5 @tab \\6\n"
186 "@item ------- @tab ------- @tab ------- @tab -------\n")
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")
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
208 ("appendix" 0 (progn (setq appendix t
) ""))
210 ("author" 1 (progn (setq author
(match-string 1 string
)) ""))
212 (progn (setq author-address
(match-string 1 string
)) ""))
214 ("backslash" 0 "@backslash{}")
216 ("bifuncindex" 1 (progn (setq findex t
) "@findex{\\1}\x01"))
220 ("cdata" 1 "@code{\\1}")
221 ("centerline" 1 "@center \\1")
222 ("cfuncline" 3 "@itemx \\1 \\2(\\3)\n@findex \\2")
223 ("cfunction" 1 "@code{\\1}")
224 ("chapter" 1 (format "@node \\1\n@%s \\1\n"
225 (if appendix
"appendix" "chapter")))
226 ("chapter*" 1 "@node \\1\n@unnumbered \\1\n")
227 ("character" 1 "@samp{\\1}")
228 ("citetitle" 1 "@ref{Top,,,\\1}")
229 ("class" 1 "@code{\\1}")
230 ("cmemberline" 3 "@itemx \\2 \\3\n")
231 ("code" 1 "@code{\\1}")
232 ("command" 1 "@command{\\1}")
233 ("constant" 1 "@code{\\1}")
234 ("copyright" 1 "@copyright{}")
236 ("csimplemacro" 1 "@code{\\1}")
237 ("ctype" 1 "@code{\\1}")
238 ("dataline" 1 (progn (setq findex t
) "@item \\1\n@findex \\1\n"))
240 ("declaremodule" 2 (progn (setq cindex t
) "@label{\\2}@cindex{\\2}\x01"))
241 ("deprecated" 2 "@emph{This is deprecated in Python \\1. \\2}\n\n")
242 ("dfn" 1 "@dfn{\\1}")
243 ("documentclass" 1 py2texi-magic
)
244 ("e" 0 "@backslash{}")
245 ("else" 0 (concat "@end ifinfo\n@" (setq last-if
"iftex")))
246 ("env" 1 "@code{\\1}")
247 ("EOF" 0 "@code{EOF}")
248 ("email" 1 "@email{\\1}")
249 ("emph" 1 "@emph{\\1}")
250 ("envvar" 1 "@env{\\1}")
251 ("exception" 1 "@code{\\1}")
252 ("exindex" 1 (progn (setq obindex t
) "@obindex{\\1}\x01"))
253 ("fi" 0 (concat "@end " last-if
))
254 ("file" 1 "@file{\\1}")
255 ("filenq" 1 "@file{\\1}")
256 ("filevar" 1 "@file{@var{\\1}}")
257 ("footnote" 1 "@footnote{\\1}")
259 ("funcline" 2 (progn (setq findex t
) "@item \\1 \\2\n@findex \\1\x01"))
260 ("funclineni" 2 "@item \\1 \\2")
261 ("function" 1 "@code{\\1}")
262 ("grammartoken" 1 "@code{\\1}")
263 ("guilabel" 1 "@strong{\\1}")
265 ("ifhtml" 0 (concat "@" (setq last-if
"ifinfo")))
266 ("iftexi" 0 (concat "@" (setq last-if
"ifinfo")))
267 ("index" 1 (progn (setq cindex t
) "@cindex{\\1}\x01"))
268 ("indexii" 2 (progn (setq cindex t
) "@cindex{\\1 \\2}\x01"))
269 ("indexiii" 3 (progn (setq cindex t
) "@cindex{\\1 \\2 \\3}\x01"))
270 ("indexiv" 3 (progn (setq cindex t
) "@cindex{\\1 \\2 \\3 \\4}\x01"))
271 ("infinity" 0 "@emph{infinity}")
273 ("kbd" 1 "@key{\\1}")
274 ("keyword" 1 "@code{\\1}")
275 ("kwindex" 1 (progn (setq cindex t
) "@cindex{\\1}\x01"))
276 ("label" 1 "@label{\\1}")
278 ("LaTeX" 0 "La@TeX{}")
280 ("ldots" 0 "@dots{}")
283 ("lineii" 2 "@item \\1 @tab \\2")
284 ("lineiii" 3 "@item \\1 @tab \\2 @tab \\3")
285 ("lineiv" 4 "@item \\1 @tab \\2 @tab \\3 @tab \\4")
286 ("linev" 5 "@item \\1 @tab \\2 @tab \\3 @tab \\4 @tab \\5")
287 ("localmoduletable" 0 "")
288 ("longprogramopt" 1 "@option{--\\1}")
289 ("macro" 1 "@code{@backslash{}\\1}")
290 ("mailheader" 1 "@code{\\1}")
292 ("makemodindex" 0 "")
293 ("maketitle" 0 (concat "@top " title
"\n"))
294 ("makevar" 1 "@code{\\1}")
295 ("manpage" 2 "@samp{\\1(\\2)}")
297 ("member" 1 "@code{\\1}")
298 ("memberline" 1 "@item \\1\n@findex \\1\n")
299 ("menuselection" 1 "@samp{\\1}")
300 ("method" 1 "@code{\\1}")
301 ("methodline" 2 (progn (setq moindex t
) "@item \\1(\\2)\n@moindex \\1\n"))
302 ("methodlineni" 2 "@item \\1(\\2)\n")
303 ("mimetype" 1 "@samp{\\1}")
304 ("module" 1 "@samp{\\1}")
305 ("moduleauthor" 2 "")
306 ("modulesynopsis" 1 "\\1")
307 ("moreargs" 0 "@dots{}")
308 ("n" 0 "@backslash{}n")
310 ("newsgroup" 1 "@samp{\\1}")
314 (re-search-backward "^@node "))
315 (delete-region (point) (save-excursion (end-of-line) (point)))
316 (insert "@node " (match-string 1 string
))
318 ("noindent" 0 "@noindent ")
319 ("note" 1 "@emph{Note:} \\1")
320 ("NULL" 0 "@code{NULL}")
321 ("obindex" 1 (progn (setq obindex t
) "@obindex{\\1}\x01"))
322 ("opindex" 1 (progn (setq cindex t
) "@cindex{\\1}\x01"))
323 ("option" 1 "@option{\\1}")
324 ("optional" 1 "[\\1]")
325 ("pep" 1 (progn (setq cindex t
) "PEP@ \\1@cindex PEP \\1\n"))
330 ("production" 2 "@item \\1 \\2")
331 ("productioncont" 1 "@item @w{} \\1")
332 ("program" 1 "@command{\\1}")
333 ("programopt" 1 "@option{\\1}")
335 ("pytype" 1 "@code{\\1}")
336 ("ref" 1 "@ref{\\1}")
337 ("refbimodindex" 1 (progn (setq moindex t
) "@moindex{\\1}\x01"))
338 ("refmodindex" 1 (progn (setq moindex t
) "@moindex{\\1}\x01"))
339 ("refmodule" 1 "@samp{\\1}")
340 ("refstmodindex" 1 (progn (setq moindex t
) "@moindex{\\1}\x01"))
341 ("regexp" 1 "\"\\1\"")
343 (progn (setq py2texi-python-version
(match-string 1 string
)) ""))
344 ("renewcommand" 2 "")
345 ("rfc" 1 (progn (setq cindex t
) "RFC@ \\1@cindex RFC \\1\n"))
347 ("samp" 1 "@samp{\\1}")
348 ("section" 1 (let ((str (match-string 1 string
)))
350 (if (string-match "\\(.*\\)[ \t\n]*---[ \t\n]*\\(.*\\)"
353 "@node %s\n@section %s\n"
354 (py2texi-backslash-quote (match-string 1 str
))
355 (py2texi-backslash-quote (match-string 2 str
)))
356 "@node \\1\n@section \\1\n"))))
357 ("sectionauthor" 2 "")
358 ("seelink" 3 "\n@table @url\n@item @strong{\\1}\n(\\2)\n\\3\n@end table\n")
359 ("seemodule" 2 "@ref{\\1} \\2")
360 ("seepep" 3 "\n@table @strong\n@item PEP\\1 \\2\n\\3\n@end table\n")
361 ("seerfc" 3 "\n@table @strong\n@item RFC\\1 \\2\n\\3\n@end table\n")
363 ("seetitle" 1 "@cite{\\1}")
364 ("seeurl" 2 "\n@table @url\n@item \\1\n\\2\n@end table\n")
365 ("setindexsubitem" 1 (progn (setq cindex t
) "@cindex \\1\x01"))
366 ("setreleaseinfo" 1 (progn (setq py2texi-releaseinfo
"")))
368 (progn (setq py2texi-python-short-version
(match-string 1 string
)) ""))
369 ("shortversion" 0 py2texi-python-short-version
)
371 ("stindex" 1 (progn (setq cindex t
) "@cindex{\\1}\x01"))
372 ("stmodindex" 1 (progn (setq moindex t
) "@moindex{\\1}\x01"))
373 ("strong" 1 "@strong{\\1}")
375 ("subsection" 1 "@node \\1\n@subsection \\1\n")
376 ("subsubsection" 1 "@node \\1\n@subsubsection \\1\n")
378 ("tableofcontents" 0 "")
379 ("term" 1 "@item \\1")
381 ("textasciitilde" 0 "~")
382 ("textasciicircum" 0 "^")
383 ("textbackslash" 0 "@backslash{}")
385 ; Some common versions of Texinfo don't support @euro yet:
386 ; ("texteuro" 0 "@euro{}")
387 ; Unfortunately, this alternate spelling doesn't actually apply to
388 ; the usage found in Python Tutorial, which actually requires a
389 ; Euro symbol to make sense, so this is commented out as well.
390 ; ("texteuro" 0 "Euro ")
391 ("textgreater" 0 ">")
392 ("textit" 1 "@i{\\1}")
395 ("texttt" 1 "@code{\\1}")
396 ("textunderscore" 0 "_")
397 ("title" 1 (progn (setq title
(match-string 1 string
)) "@settitle \\1"))
398 ("today" 0 "@today{}")
399 ("token" 1 "@code{\\1}")
401 ("ttindex" 1 (progn (setq cindex t
) "@cindex{\\1}\x01"))
402 ("u" 0 "@backslash{}u")
405 ("unspecified" 0 "@dots{}")
406 ("url" 1 "@url{\\1}")
408 ("var" 1 "@var{\\1}")
409 ("verbatiminput" 1 "@code{\\1}")
410 ("version" 0 py2texi-python-version
)
411 ("versionadded" 1 "@emph{Added in Python version \\1}")
412 ("versionchanged" 1 "@emph{Changed in Python version \\1}")
415 ("warning" 1 "@emph{\\1}")
416 ("withsubitem" 2 "\\2")
417 ("XXX" 1 "@strong{\\1}"))
418 "Associative list of command substitutions.
419 Each list item is of the form (COMMAND ARGNUM SUBSTITUTION) where:
420 - COMMAND is LaTeX command name
421 - ARGNUM is number of (required) command arguments
422 - SUBSTITUTION substitution for the command. It is evaled and you can
423 reference command arguments through the \\N regexp notation in strings.")
425 (defvar py2texi-magic
"@documentclass\n"
426 "\"Magic\" string for auxiliary insertion at the beginning of document.")
428 (defvar py2texi-dirs
'("./" "../texinputs/")
429 "Where to search LaTeX input files.")
431 (defvar py2texi-buffer
"*py2texi*"
432 "The name of a buffer where Texinfo is generated.")
434 (defconst py2texi-xemacs
(string-match "^XEmacs" (emacs-version))
435 "Running under XEmacs?")
438 (defmacro py2texi-search
(regexp &rest body
)
440 (goto-char (point-min))
441 (while (re-search-forward ,regexp nil t
)
444 (defmacro py2texi-search-safe
(regexp &rest body
)
445 `(py2texi-search ,regexp
446 (unless (py2texi-protected)
450 (defun py2texi-message (message)
451 "Report message and stop if `py2texi-stop-on-problems' is non-nil."
452 (if py2texi-stop-on-problems
457 (defun py2texi-backslash-quote (string)
458 "Double backslahes in STRING."
461 (while (setq i
(string-match "\\\\" string i
))
462 (setq string
(replace-match "\\\\\\\\" t nil string
))
467 (defun py2texi (file)
468 "Convert Python LaTeX documentation FILE to Texinfo."
469 (interactive "fFile to convert: ")
470 (switch-to-buffer (get-buffer-create py2texi-buffer
))
473 (let ((case-fold-search nil
)
483 (py2texi-process-verbatims)
484 (py2texi-process-comments)
485 (py2texi-process-includes)
486 (py2texi-process-funnyas)
487 (py2texi-process-environments)
488 (py2texi-process-commands)
489 (py2texi-fix-indentation)
491 (py2texi-fix-references)
492 (py2texi-fix-indices)
493 (py2texi-process-simple-commands)
496 (py2texi-fix-backslashes)
497 (py2texi-destroy-empties)
498 (py2texi-fix-newlines)
499 (py2texi-adjust-level))
500 (let* ((texi-file-name (or py2texi-texi-file-name
501 (py2texi-texi-file-name file
)))
502 (info-file-name (or py2texi-info-file-name
503 (py2texi-info-file-name texi-file-name
))))
504 (goto-char (point-min))
505 (when (looking-at py2texi-magic
)
506 (delete-region (point) (progn (beginning-of-line 2) (point)))
507 (insert "\\input texinfo @c -*-texinfo-*-\n")
508 (insert "@setfilename " info-file-name
))
509 (when (re-search-forward "@chapter" nil t
)
510 (texinfo-all-menus-update t
))
511 (goto-char (point-min))
512 (write-file texi-file-name
)
513 (message (format "You can apply `makeinfo %s' now." texi-file-name
))))
516 (defun py2texi-texi-file-name (filename)
517 "Generate name of Texinfo file from original file name FILENAME."
519 (if (string-match "\\.tex$" filename
) "i" ".texi")))
522 (defun py2texi-info-file-name (filename)
523 "Generate name of info file from original file name FILENAME."
524 (setq filename
(expand-file-name filename
))
525 (let ((directory (file-name-directory filename
))
526 (basename (file-name-nondirectory filename
)))
527 (concat directory
"python-"
528 (substring basename
0 (- (length basename
) 4)) "info")))
531 (defun py2texi-process-verbatims ()
532 "Process and protect verbatim environments."
536 (py2texi-search-safe "\\\\begin{\\(verbatim\\|displaymath\\)}"
537 (replace-match "@example")
538 (setq beg
(copy-marker (point) nil
))
539 (re-search-forward "\\\\end{\\(verbatim\\|displaymath\\)}")
540 (setq end
(copy-marker (match-beginning 0) nil
))
541 (replace-match "@end example")
542 (py2texi-texinfo-escape beg end
)
543 (put-text-property (- beg
(length "@example"))
544 (+ end
(length "@end example"))
545 'py2texi-protected t
))
546 (py2texi-search-safe "\\\\verb\\([^a-z]\\)"
547 (setq delimiter
(match-string 1))
548 (replace-match "@code{")
549 (setq beg
(copy-marker (point) nil
))
550 (re-search-forward (regexp-quote delimiter
))
551 (setq end
(copy-marker (match-beginning 0) nil
))
553 (put-text-property (- beg
(length "@code{")) (+ end
(length "}"))
554 'py2texi-protected t
)
555 (py2texi-texinfo-escape beg end
))))
558 (defun py2texi-process-comments ()
561 (py2texi-search-safe "%"
563 (when (save-excursion
564 (re-search-backward "\\(^\\|[^\\]\\(\\\\\\\\\\)*\\)%\\=" nil t
))
565 (delete-region (1- point
)
566 (save-excursion (beginning-of-line 2) (point)))))))
569 (defun py2texi-process-includes ()
570 "Include LaTeX input files.
571 Do not include .ind files."
572 (let ((path (file-name-directory file
))
576 (py2texi-search-safe "\\\\input{\\([^}]+\\)}"
577 (setq filename
(match-string 1))
578 (unless (save-match-data (string-match "\\.tex$" filename
))
579 (setq filename
(concat filename
".tex")))
580 (setq includefile
(save-match-data
581 (string-match "\\.ind\\.tex$" filename
)))
582 (setq dirs py2texi-dirs
)
583 (while (and (not includefile
) dirs
)
585 (concat (file-name-as-directory (car dirs
)) filename
))
586 (if (not (file-name-absolute-p includefile
))
588 (concat (file-name-as-directory path
) includefile
)))
589 (unless (file-exists-p includefile
)
590 (setq includefile nil
)
591 (setq dirs
(cdr dirs
))))
594 (narrow-to-region (match-beginning 0) (match-end 0))
595 (delete-region (point-min) (point-max))
596 (when (stringp includefile
)
597 (insert-file-contents includefile
)
598 (goto-char (point-min))
600 (py2texi-process-verbatims)
601 (py2texi-process-comments)
602 (py2texi-process-includes)))
603 (replace-match (format "\\\\emph{Included file %s}" filename
))
604 (py2texi-message (format "Input file %s not found" filename
))))))
607 (defun py2texi-process-funnyas ()
609 (py2texi-search-safe "@"
610 (replace-match "@@")))
613 (defun py2texi-process-environments ()
614 "Process LaTeX environments."
623 (py2texi-search-safe (concat "\\\\\\(begin\\|end\\|item\\)"
624 "\\({\\([^}]*\\)}\\|[[]\\([^]]*\\)[]]\\|\\)")
625 (setq kind
(match-string 1)
626 environment
(match-string 3)
627 parameter
(match-string 4))
630 ((string= kind
"begin")
631 (setq description
(assoc environment py2texi-environments
))
634 (setq n
(cadr description
))
635 (setq description
(cddr description
))
636 (setq string
(py2texi-tex-arguments n
))
637 (string-match (py2texi-regexp n
) string
)
638 ; incorrect but sufficient
639 (insert (replace-match (eval (car description
))
641 (setq stack
(cons (cadr description
) stack
)))
642 (py2texi-message (format "Unknown environment: %s" environment
))
643 (setq stack
(cons "" stack
))))
644 ((string= kind
"end")
645 (insert (eval (car stack
)))
646 (setq stack
(cdr stack
)))
647 ((string= kind
"item")
648 (insert "\n@item " (or parameter
"") "\n"))))
650 (py2texi-message (format "Unclosed environment: %s" (car stack
))))))
653 (defun py2texi-process-commands ()
654 "Process LaTeX commands."
662 (py2texi-search-safe "\\\\\\([a-zA-Z*]+\\)\\(\\[[^]]*\\]\\)?"
663 (setq command
(match-string 1))
664 (setq command-info
(assoc command py2texi-commands
))
669 (setq command-info
(cdr command-info
))
670 (setq n
(car command-info
))
671 (setq string
(py2texi-tex-arguments n
))
672 (string-match (py2texi-regexp n
) string
)
673 ; incorrect but sufficient
674 (insert (replace-match (eval (cadr command-info
))
676 (py2texi-message (format "Unknown command: %s (not processed)"
680 (defun py2texi-argument-pattern (count)
681 (let ((filler "\\(?:[^{}]\\|\\\\{\\|\\\\}\\)*"))
684 (concat filler
"\\(?:{"
685 (py2texi-argument-pattern (1- count
))
686 "}" filler
"\\)*" filler
))))
687 (defconst py2texi-tex-argument
690 (py2texi-argument-pattern 10) ;really at least 10!
692 "Regexp describing LaTeX command argument including argument separators.")
695 (defun py2texi-regexp (n)
696 "Make regexp matching N LaTeX command arguments."
699 (let ((regexp "^[^{]*"))
701 (setq regexp
(concat regexp py2texi-tex-argument
))
706 (defun py2texi-tex-arguments (n)
707 "Remove N LaTeX command arguments and return them as a string."
708 (let ((point (point))
714 (when (re-search-forward "\\=\\({}\\| *\\)" nil t
)
718 (unless (re-search-forward
719 "\\(\\=\\|[^\\\\]\\)\\(\\\\\\\\\\)*\\([{}]\\)" nil t
)
721 (if (string= (match-string 3) "{")
726 (setq result
(buffer-substring-no-properties point
(point)))
727 (while (string-match "\n[ \t]*" result
)
728 (setq result
(replace-match " " t nil result
)))
729 (delete-region point
(point))
733 (defun py2texi-process-simple-commands ()
734 "Replace single character LaTeX commands."
736 (py2texi-search-safe "\\\\\\([^a-z]\\)"
737 (setq char
(match-string 1))
738 (replace-match (format "%s%s"
739 (if (or (string= char
"{")
744 (if (string= char
"\\")
749 (defun py2texi-fix-indentation ()
750 "Remove white space at the beginning of lines."
751 (py2texi-search-safe "^[ \t]+"
755 (defun py2texi-fix-nodes ()
756 "Remove unwanted characters from nodes and make nodes unique."
757 (let ((nodes (make-hash-table :test
'equal
))
763 (py2texi-search "^@node +\\(.*\\)$"
764 (setq string
(match-string 1))
766 (replace-match "@node " t
)
767 (replace-match "" t nil nil
1))
768 (while (string-match "@label{[^}]*}" string
)
769 (setq label
(match-string 0 string
))
770 (setq string
(replace-match "" t nil string
)))
771 (while (string-match "@..?index{[^}]*}\x01" string
)
772 (setq index
(match-string 0 string
))
773 (setq string
(replace-match "" t nil string
)))
774 (while (string-match "@[a-zA-Z]+\\|[{}():]\\|``\\|''" string
)
775 (setq string
(replace-match "" t nil string
)))
776 (while (string-match " -- " string
)
777 (setq string
(replace-match " - " t nil string
)))
778 (while (string-match "\\." string
)
779 (setq string
(replace-match "" t nil string
)))
780 (when (string-match " +$" string
)
781 (setq string
(replace-match "" t nil string
)))
782 (when (string-match "^\\(Built-in\\|Standard\\) Module \\|The " string
)
783 (setq string
(replace-match "" t nil string
)))
784 (string-match "^[^,]+" string
)
785 (setq id
(match-string 0 string
))
786 (setq counter
(gethash id nodes
))
789 (setq counter
(1+ counter
))
790 (setq string
(replace-match (format "\\& %d" counter
)
793 (setf (gethash id nodes
) counter
)
795 (beginning-of-line 3)
799 (insert index
"\n")))))
802 (defun py2texi-fix-references ()
803 "Process labels and make references to point to appropriate nodes."
806 (py2texi-search-safe "@label{\\([^}]*\\)}"
807 (setq node
(save-excursion
809 (and (re-search-backward "@node +\\([^,\n]+\\)" nil t
)
812 (setq labels
(cons (cons (match-string 1) node
) labels
)))
814 (py2texi-search-safe "@ref{\\([^}]*\\)}"
815 (setq node
(assoc (match-string 1) labels
))
818 (insert (format "@ref{%s}" (cdr node
)))))))
821 (defun py2texi-fix-indices ()
822 "Remove unwanted characters from @*index commands and create final indices."
823 (py2texi-search-safe "@..?index\\>[^\n\x01]*\\(\x01\\)\n"
824 (replace-match "" t nil nil
1))
825 (py2texi-search-safe "@..?index\\>[^\n\x01]*\\(\x01\\)"
826 (replace-match "\n" t nil nil
1))
827 (py2texi-search-safe "@..?index\\({\\)\\([^}]+\\)\\(}+\\)"
828 (replace-match " " t nil nil
1)
829 (replace-match "" t nil nil
3)
830 (let ((string (match-string 2)))
832 (while (string-match "@[a-z]+{" string
)
833 (setq string
(replace-match "" nil nil string
)))
834 (while (string-match "{" string
)
835 (setq string
(replace-match "" nil nil string
))))
836 (replace-match string t t nil
2)))
837 (py2texi-search-safe "@..?index\\>.*\\([{}]\\|@[a-z]*\\)"
838 (replace-match "" t nil nil
1)
839 (goto-char (match-beginning 0)))
840 (py2texi-search-safe "[^\n]\\(\\)@..?index\\>"
841 (replace-match "\n" t nil nil
1))
842 (goto-char (point-max))
843 (re-search-backward "@indices")
846 (concat "@node Module Index\n"
847 "@unnumbered Module Index\n"
851 (concat "@node Class-Exception-Object Index\n"
852 "@unnumbered Class, Exception, and Object Index\n"
856 (concat "@node Function-Method-Variable Index\n"
857 "@unnumbered Function, Method, and Variable Index\n"
861 (concat "@node Miscellaneous Index\n"
862 "@unnumbered Miscellaneous Index\n"
867 (defun py2texi-fix-backslashes ()
868 "Make backslashes from auxiliary commands."
869 (py2texi-search-safe "@backslash{}"
870 (replace-match "\\\\")))
873 (defun py2texi-fix-fonts ()
874 "Remove garbage after unstructured font commands."
876 (py2texi-search-safe "@destroy"
878 (when (eq (preceding-char) ?
{)
880 (setq string
(py2texi-tex-arguments 1))
881 (insert (substring string
1 (1- (length string
))))))))
884 (defun py2texi-fix-braces ()
885 "Escape braces for Texinfo."
888 (unless (or (py2texi-protected)
891 "@\\([a-zA-Z]*\\|multitable.*\\){\\=" nil t
)))
893 (setq string
(py2texi-tex-arguments 1))
894 (insert "@" (substring string
0 (1- (length string
))) "@}")))))
897 (defun py2texi-fix-newlines ()
898 "Remove extra newlines."
899 (py2texi-search "\n\n\n+"
900 (replace-match "\n\n"))
901 (py2texi-search-safe "@item.*\n\n"
902 (delete-backward-char 1))
903 (py2texi-search "@end example"
904 (unless (looking-at "\n\n")
908 (defun py2texi-destroy-empties ()
909 "Remove all comments.
910 This avoids some makeinfo errors."
911 (py2texi-search "@c\\>"
912 (unless (eq (py2texi-protected) t
)
913 (delete-region (- (point) 2) (save-excursion (end-of-line) (point)))
917 ((save-excursion (re-search-backward "^[ \t]*\\=" nil t
))
918 (delete-region (save-excursion (beginning-of-line) (point))
922 (defun py2texi-adjust-level ()
923 "Increase heading level to @chapter, if needed.
924 This is only needed for distutils, so it has a very simple form only."
925 (goto-char (point-min))
926 (unless (re-search-forward "@chapter\\>" nil t
)
927 (py2texi-search-safe "@section\\>"
928 (replace-match "@chapter" t
))
929 (py2texi-search-safe "@\\(sub\\)\\(sub\\)?section\\>"
930 (replace-match "" nil nil nil
1))))
933 (defun py2texi-texinfo-escape (beg end
)
934 "Escape Texinfo special characters in region."
937 (while (re-search-forward "[@{}]" end t
)
938 (replace-match "@\\&"))))
941 (defun py2texi-protected ()
942 "Return protection status of the point before current point."
943 (get-text-property (1- (point)) 'py2texi-protected
))
951 ;;; py2texi.el ends here