cpython/Doc/tools/py2texi.el

940 lines
30 KiB
EmacsLisp
Raw Blame History

This file contains invisible Unicode characters

This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

;;; py2texi.el -- Conversion of Python LaTeX documentation to Texinfo
;; Copyright (C) 1998, 1999, 2001, 2002 Milan Zamazal
;; Author: Milan Zamazal <pdm@zamazal.org>
;; Version: $Id$
;; Keywords: python
;; COPYRIGHT NOTICE
;;
;; This program is free software; you can redistribute it and/or modify it
;; under the terms of the GNU General Public License as published by the Free
;; Software Foundation; either version 2, or (at your option) any later
;; version.
;;
;; This program is distributed in the hope that it will be useful, but
;; WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
;; or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
;; for more details.
;;
;; You can find the GNU General Public License at
;; http://www.gnu.org/copyleft/gpl.html
;; or you can write to the Free Software Foundation, Inc., 59 Temple Place,
;; Suite 330, Boston, MA 02111-1307, USA.
;;; Commentary:
;; This is a Q&D hack for conversion of Python manuals to on-line help format.
;; I desperately needed usable online documenta for Python, so I wrote this.
;; The result code is ugly and need not contain complete information from
;; Python manuals. I apologize for my ignorance, especially ignorance to
;; python.sty. Improvements of this convertor are welcomed.
;; How to use it:
;; Load this file and apply `M-x py2texi'. You will be asked for name of a
;; file to be converted.
;; Where to find it:
;; New versions of this code might be found at
;; http://www.zamazal.org/software/python/py2texi/ .
;;; Code:
(require 'texinfo)
(eval-when-compile
(require 'cl))
(defvar py2texi-python-version "2.2"
"What to substitute for the \\version macro.")
(defvar py2texi-python-short-version
(progn
(string-match "[0-9]+\\.[0-9]+" py2texi-python-version)
(match-string 0 py2texi-python-version))
"Short version number, usually set by the LaTeX commands.")
(defvar py2texi-texi-file-name nil
"If non-nil, that string is used as the name of the Texinfo file.
Otherwise a generated Texinfo file name is used.")
(defvar py2texi-info-file-name nil
"If non-nil, that string is used as the name of the Info file.
Otherwise a generated Info file name is used.")
(defvar py2texi-stop-on-problems nil
"*If non-nil, stop when you encouter soft problem.")
(defconst py2texi-environments
'(("abstract" 0 "@quotation" "@end quotation\n")
("center" 0 "" "")
("cfuncdesc" 3
(progn (setq findex t)
"\n@table @code\n@item \\1 \\2(\\3)\n@findex \\2\n")
"@end table\n")
("cmemberdesc" 3
"\n@table @code\n@item \\2 \\3\n"
"@end table\n")
("classdesc" 2
(progn (setq obindex t)
"\n@table @code\n@item \\1(\\2)\n@obindex \\1\n")
"@end table\n")
("classdesc*" 1
(progn (setq obindex t)
"\n@table @code\n@item \\1\n@obindex \\1\n")
"@end table\n")
("comment" 0 "\n@ignore\n" "\n@end ignore\n")
("csimplemacrodesc" 1
(progn (setq cindex t)
"\n@table @code\n@item \\1\n@cindex \\1\n")
"@end table\n")
("ctypedesc" 1
(progn (setq cindex t)
"\n@table @code\n@item \\1\n@cindex \\1\n")
"@end table\n")
("cvardesc" 2
(progn (setq findex t)
"\n@table @code\n@item \\1 \\2\n@findex \\2\n")
"@end table\n")
("datadesc" 1
(progn (setq findex t)
"\n@table @code\n@item \\1\n@findex \\1\n")
"@end table\n")
("datadescni" 1 "\n@table @code\n@item \\1\n" "@end table\n")
("definitions" 0 "@table @dfn" "@end table\n")
("description" 0 "@table @samp" "@end table\n")
("displaymath" 0 "" "")
("document" 0
(concat "@defcodeindex mo\n"
"@defcodeindex ob\n"
"@titlepage\n"
(format "@title " title "\n")
(format "@author " author "\n")
"@page\n"
author-address
"@end titlepage\n"
"@node Top, , , (dir)\n")
(concat "@indices\n"
"@contents\n"
"@bye\n"))
("enumerate" 0 "@enumerate" "@end enumerate")
("envdesc" 2 (concat "\n@table @code"
"\n@item @backslash{}begin@{\\1@}\\2")
"@end table\n")
("excdesc" 1
(progn (setq obindex t)
"\n@table @code\n@item \\1\n@obindex \\1\n")
"@end table\n")
("excclassdesc" 2
(progn (setq obindex t)
"\n@table @code\n@item \\1(\\2)\n@obindex \\1\n")
"@end table\n")
("flushleft" 0 "" "")
("fulllineitems" 0 "\n@table @code\n" "@end table\n")
("funcdesc" 2
(progn (setq findex t)
"\n@table @code\n@item \\1(\\2)\n@findex \\1\n")
"@end table\n")
("funcdescni" 2 "\n@table @code\n@item \\1(\\2)\n" "@end table\n")
("itemize" 0 "@itemize @bullet" "@end itemize\n")
("list" 2 "\n@table @code\n" "@end table\n")
("longtableii" 4 (concat "@multitable @columnfractions .5 .5\n"
"@item \\3 @tab \\4\n"
"@item ------- @tab ------ \n")
"@end multitable\n")
("longtableiii" 5 (concat "@multitable @columnfractions .33 .33 .33\n"
"@item \\3 @tab \\4 @tab \\5\n"
"@item ------- @tab ------ @tab ------\n")
"@end multitable\n")
("macrodesc" 2 (concat "\n@table @code"
"\n@item \\1@{\\2@}")
"@end table\n")
("memberdesc" 1
(progn (setq findex t)
"\n@table @code\n@item \\1\n@findex \\1\n")
"@end table\n")
("memberdescni" 1 "\n@table @code\n@item \\1\n" "@end table\n")
("methoddesc" 2
(progn (setq findex t)
"\n@table @code\n@item \\1(\\2)\n@findex \\1\n")
"@end table\n")
("methoddescni" 2 "\n@table @code\n@item \\1(\\2)\n" "@end table\n")
("notice" 0 "@emph{Notice:} " "")
("opcodedesc" 2
(progn (setq findex t)
"\n@table @code\n@item \\1 \\2\n@findex \\1\n")
"@end table\n")
("productionlist" 0 "\n@table @code\n" "@end table\n")
("quotation" 0 "@quotation" "@end quotation")
("seealso" 0 "See also:\n@table @emph\n" "@end table\n")
("seealso*" 0 "@table @emph\n" "@end table\n")
("sloppypar" 0 "" "")
("small" 0 "" "")
("tableii" 4 (concat "@multitable @columnfractions .5 .5\n"
"@item \\3 @tab \\4\n"
"@item ------- @tab ------ \n")
"@end multitable\n")
("tableiii" 5 (concat "@multitable @columnfractions .33 .33 .33\n"
"@item \\3 @tab \\4 @tab \\5\n"
"@item ------- @tab ------ @tab ------\n")
"@end multitable\n")
("tableiv" 6 (concat
"@multitable @columnfractions .25 .25 .25 .25\n"
"@item \\3 @tab \\4 @tab \\5 @tab \\6\n"
"@item ------- @tab ------- @tab ------- @tab -------\n")
"@end multitable\n")
("tablev" 7 (concat
"@multitable @columnfractions .20 .20 .20 .20 .20\n"
"@item \\3 @tab \\4 @tab \\5 @tab \\6 @tab \\7\n"
"@item ------- @tab ------- @tab ------- @tab ------- @tab -------\n")
"@end multitable\n")
("alltt" 0 "@example" "@end example")
)
"Associative list defining substitutions for environments.
Each list item is of the form (ENVIRONMENT ARGNUM BEGIN END) where:
- ENVIRONMENT is LaTeX environment name
- ARGNUM is number of (required) macro arguments
- BEGIN is substitution for \begin{ENVIRONMENT}
- END is substitution for \end{ENVIRONMENT}
Both BEGIN and END are evaled. Moreover, you can reference arguments through
\N regular expression notation in strings of BEGIN.")
(defconst py2texi-commands
'(("AA" 0 "@AA{}")
("aa" 0 "@aa{}")
("ABC" 0 "ABC")
("appendix" 0 (progn (setq appendix t) ""))
("ASCII" 0 "ASCII")
("author" 1 (progn (setq author (match-string 1 string)) ""))
("authoraddress" 1
(progn (setq author-address (match-string 1 string)) ""))
("b" 1 "@w{\\1}")
("bf" 0 "@destroy")
("bifuncindex" 1 (progn (setq findex t) "@findex{\\1}"))
("C" 0 "C")
("c" 0 "@,")
("catcode" 0 "")
("cdata" 1 "@code{\\1}")
("centerline" 1 "@center \\1")
("cfuncline" 3 "@itemx \\1 \\2(\\3)\n@findex \\2")
("cfunction" 1 "@code{\\1}")
("chapter" 1 (format "@node \\1\n@%s \\1\n"
(if appendix "appendix" "chapter")))
("chapter*" 1 "@node \\1\n@unnumbered \\1\n")
("character" 1 "@samp{\\1}")
("citetitle" 1 "@ref{Top,,,\\1}")
("class" 1 "@code{\\1}")
("cmemberline" 3 "@itemx \\2 \\3\n")
("code" 1 "@code{\\1}")
("command" 1 "@command{\\1}")
("constant" 1 "@code{\\1}")
("copyright" 1 "@copyright{}")
("Cpp" 0 "C++")
("csimplemacro" 1 "@code{\\1}")
("ctype" 1 "@code{\\1}")
("dataline" 1 (progn (setq findex t) "@item \\1\n@findex \\1\n"))
("date" 1 "\\1")
("declaremodule" 2 (progn (setq cindex t) "@label{\\2}@cindex{\\2}"))
("deprecated" 2 "@emph{This is deprecated in Python \\1. \\2}")
("dfn" 1 "@dfn{\\1}")
("documentclass" 1 py2texi-magic)
("e" 0 "@backslash{}")
("else" 0 (concat "@end ifinfo\n@" (setq last-if "iftex")))
("env" 1 "@code{\\1}")
("EOF" 0 "@code{EOF}")
("email" 1 "@email{\\1}")
("emph" 1 "@emph{\\1}")
("envvar" 1 "@env{\\1}")
("exception" 1 "@code{\\1}")
("exindex" 1 (progn (setq obindex t) "@obindex{\\1}"))
("fi" 0 (concat "@end " last-if))
("file" 1 "@file{\\1}")
("filenq" 1 "@file{\\1}")
("filevar" 1 "@file{@var{\\1}}")
("footnote" 1 "@footnote{\\1}")
("frac" 0 "")
("funcline" 2 (progn (setq findex t) "@item \\1 \\2\n@findex \\1"))
("funclineni" 2 "@item \\1 \\2")
("function" 1 "@code{\\1}")
("grammartoken" 1 "@code{\\1}")
("hline" 0 "")
("ifhtml" 0 (concat "@" (setq last-if "ifinfo")))
("iftexi" 0 (concat "@" (setq last-if "ifinfo")))
("index" 1 (progn (setq cindex t) "@cindex{\\1}"))
("indexii" 2 (progn (setq cindex t) "@cindex{\\1 \\2}"))
("indexiii" 3 (progn (setq cindex t) "@cindex{\\1 \\2 \\3}"))
("indexiv" 3 (progn (setq cindex t) "@cindex{\\1 \\2 \\3 \\4}"))
("infinity" 0 "@emph{infinity}")
("it" 0 "@destroy")
("kbd" 1 "@key{\\1}")
("keyword" 1 "@code{\\1}")
("kwindex" 1 (progn (setq cindex t) "@cindex{\\1}"))
("label" 1 "@label{\\1}")
("Large" 0 "")
("LaTeX" 0 "La@TeX{}")
("large" 0 "")
("ldots" 0 "@dots{}")
("leftline" 1 "\\1")
("lineii" 2 "@item \\1 @tab \\2")
("lineiii" 3 "@item \\1 @tab \\2 @tab \\3")
("lineiv" 4 "@item \\1 @tab \\2 @tab \\3 @tab \\4")
("linev" 5 "@item \\1 @tab \\2 @tab \\3 @tab \\4 @tab \\5")
("localmoduletable" 0 "")
("longprogramopt" 1 "@option{--\\1}")
("macro" 1 "@code{@backslash{}\\1}")
("mailheader" 1 "@code{\\1}")
("makeindex" 0 "")
("makemodindex" 0 "")
("maketitle" 0 (concat "@top " title "\n"))
("makevar" 1 "@code{\\1}")
("manpage" 2 "@samp{\\1(\\2)}")
("mbox" 1 "@w{\\1}")
("member" 1 "@code{\\1}")
("memberline" 1 "@item \\1\n@findex \\1\n")
("menuselection" 1 "@samp{\\1}")
("method" 1 "@code{\\1}")
("methodline" 2 (progn (setq moindex t) "@item \\1(\\2)\n@moindex \\1\n"))
("methodlineni" 2 "@item \\1(\\2)\n")
("mimetype" 1 "@samp{\\1}")
("module" 1 "@samp{\\1}")
("moduleauthor" 2 "")
("modulesynopsis" 1 "\\1")
("moreargs" 0 "@dots{}")
("n" 0 "@backslash{}n")
("newcommand" 2 "")
("newsgroup" 1 "@samp{\\1}")
("nodename" 1
(save-excursion
(save-match-data
(re-search-backward "^@node "))
(delete-region (point) (save-excursion (end-of-line) (point)))
(insert "@node " (match-string 1 string))
""))
("noindent" 0 "@noindent ")
("note" 1 "@emph{Note:} \\1")
("NULL" 0 "@code{NULL}")
("obindex" 1 (progn (setq obindex t) "@obindex{\\1}"))
("opindex" 1 (progn (setq cindex t) "@cindex{\\1}"))
("option" 1 "@option{\\1}")
("optional" 1 "[\\1]")
("pep" 1 (progn (setq cindex t) "PEP@ \\1@cindex PEP \\1\n"))
("pi" 0 "pi")
("platform" 1 "")
("plusminus" 0 "+-")
("POSIX" 0 "POSIX")
("production" 2 "@item \\1 \\2")
("productioncont" 1 "@item @w{} \\1")
("program" 1 "@command{\\1}")
("programopt" 1 "@option{\\1}")
("protect" 0 "")
("pytype" 1 "@code{\\1}")
("ref" 1 "@ref{\\1}")
("refbimodindex" 1 (progn (setq moindex t) "@moindex{\\1}"))
("refmodindex" 1 (progn (setq moindex t) "@moindex{\\1}"))
("refmodule" 1 "@samp{\\1}")
("refstmodindex" 1 (progn (setq moindex t) "@moindex{\\1}"))
("regexp" 1 "\"\\1\"")
("release" 1
(progn (setq py2texi-python-version (match-string 1 string)) ""))
("renewcommand" 2 "")
("rfc" 1 (progn (setq cindex t) "RFC@ \\1@cindex RFC \\1\n"))
("rm" 0 "@destroy")
("samp" 1 "@samp{\\1}")
("section" 1 (let ((str (match-string 1 string)))
(save-match-data
(if (string-match "\\(.*\\)[ \t\n]*---[ \t\n]*\\(.*\\)"
str)
(format
"@node %s\n@section %s\n"
(py2texi-backslash-quote (match-string 1 str))
(py2texi-backslash-quote (match-string 2 str)))
"@node \\1\n@section \\1\n"))))
("sectionauthor" 2 "")
("seemodule" 2 "@ref{\\1} \\2")
("seepep" 3 "\n@table @strong\n@item PEP\\1 \\2\n\\3\n@end table\n")
("seerfc" 3 "\n@table @strong\n@item RFC\\1 \\2\n\\3\n@end table\n")
("seetext" 1 "\\1")
("seetitle" 1 "@cite{\\1}")
("seeurl" 2 "\n@table @url\n@item \\1\n\\2\n@end table\n")
("setindexsubitem" 1 (progn (setq cindex t) "@cindex \\1"))
("setreleaseinfo" 1 (progn (setq py2texi-releaseinfo "")))
("setshortversion" 1
(progn (setq py2texi-python-short-version (match-string 1 string)) ""))
("shortversion" 0 py2texi-python-short-version)
("sqrt" 0 "")
("stindex" 1 (progn (setq cindex t) "@cindex{\\1}"))
("stmodindex" 1 (progn (setq moindex t) "@moindex{\\1}"))
("strong" 1 "@strong{\\1}")
("sub" 0 "/")
("subsection" 1 "@node \\1\n@subsection \\1\n")
("subsubsection" 1 "@node \\1\n@subsubsection \\1\n")
("sum" 0 "")
("tableofcontents" 0 "")
("term" 1 "@item \\1")
("TeX" 0 "@TeX{}")
("textasciitilde" 0 "~")
("textasciicircum" 0 "^")
("textbackslash" 0 "@backslash{}")
("textgreater" 0 ">")
("textless" 0 "<")
("textrm" 1 "\\1")
("texttt" 1 "@code{\\1}")
("textunderscore" 0 "_")
("title" 1 (progn (setq title (match-string 1 string)) "@settitle \\1"))
("today" 0 "@today{}")
("token" 1 "@code{\\1}")
("tt" 0 "@destroy")
("ttindex" 1 (progn (setq cindex t) "@cindex{\\1}"))
("u" 0 "@backslash{}u")
("ulink" 2 "\\1")
("UNIX" 0 "UNIX")
("unspecified" 0 "@dots{}")
("url" 1 "@url{\\1}")
("usepackage" 1 "")
("var" 1 "@var{\\1}")
("verbatiminput" 1 "@code{\\1}")
("version" 0 py2texi-python-version)
("versionadded" 1 "@emph{Added in Python version \\1}")
("versionchanged" 1 "@emph{Changed in Python version \\1}")
("vskip" 1 "")
("vspace" 1 "")
("warning" 1 "@emph{\\1}")
("withsubitem" 2 "\\2")
("XXX" 1 "@strong{\\1}"))
"Associative list of command substitutions.
Each list item is of the form (COMMAND ARGNUM SUBSTITUTION) where:
- COMMAND is LaTeX command name
- ARGNUM is number of (required) command arguments
- SUBSTITUTION substitution for the command. It is evaled and you can
reference command arguments through the \\N regexp notation in strings.")
(defvar py2texi-magic "@documentclass\n"
"\"Magic\" string for auxiliary insertion at the beginning of document.")
(defvar py2texi-dirs '("./" "../texinputs/")
"Where to search LaTeX input files.")
(defvar py2texi-buffer "*py2texi*"
"The name of a buffer where Texinfo is generated.")
(defconst py2texi-xemacs (string-match "^XEmacs" (emacs-version))
"Running under XEmacs?")
(defmacro py2texi-search (regexp &rest body)
`(progn
(goto-char (point-min))
(while (re-search-forward ,regexp nil t)
,@body)))
(defmacro py2texi-search-safe (regexp &rest body)
`(py2texi-search ,regexp
(unless (py2texi-protected)
,@body)))
(defun py2texi-message (message)
"Report message and stop if `py2texi-stop-on-problems' is non-nil."
(if py2texi-stop-on-problems
(error message)
(message message)))
(defun py2texi-backslash-quote (string)
"Double backslahes in STRING."
(let ((i 0))
(save-match-data
(while (setq i (string-match "\\\\" string i))
(setq string (replace-match "\\\\\\\\" t nil string))
(setq i (+ i 2))))
string))
(defun py2texi (file)
"Convert Python LaTeX documentation FILE to Texinfo."
(interactive "fFile to convert: ")
(switch-to-buffer (get-buffer-create py2texi-buffer))
(erase-buffer)
(insert-file file)
(let ((case-fold-search nil)
(title "")
(author "")
(author-address "")
(appendix nil)
(findex nil)
(obindex nil)
(cindex nil)
(moindex nil)
last-if)
(py2texi-process-verbatims)
(py2texi-process-comments)
(py2texi-process-includes)
(py2texi-process-funnyas)
(py2texi-process-environments)
(py2texi-process-commands)
(py2texi-fix-indentation)
(py2texi-fix-nodes)
(py2texi-fix-references)
(py2texi-fix-indices)
(py2texi-process-simple-commands)
(py2texi-fix-fonts)
(py2texi-fix-braces)
(py2texi-fix-backslashes)
(py2texi-destroy-empties)
(py2texi-fix-newlines)
(py2texi-adjust-level))
(let* ((texi-file-name (or py2texi-texi-file-name
(py2texi-texi-file-name file)))
(info-file-name (or py2texi-info-file-name
(py2texi-info-file-name texi-file-name))))
(goto-char (point-min))
(when (looking-at py2texi-magic)
(delete-region (point) (progn (beginning-of-line 2) (point)))
(insert "\\input texinfo @c -*-texinfo-*-\n")
(insert "@setfilename " info-file-name))
(when (re-search-forward "@chapter" nil t)
(texinfo-all-menus-update t))
(goto-char (point-min))
(write-file texi-file-name)
(message (format "You can apply `makeinfo %s' now." texi-file-name))))
(defun py2texi-texi-file-name (filename)
"Generate name of Texinfo file from original file name FILENAME."
(concat filename
(if (string-match "\\.tex$" filename) "i" ".texi")))
(defun py2texi-info-file-name (filename)
"Generate name of info file from original file name FILENAME."
(setq filename (expand-file-name filename))
(let ((directory (file-name-directory filename))
(basename (file-name-nondirectory filename)))
(concat directory "python-"
(substring basename 0 (- (length basename) 4)) "info")))
(defun py2texi-process-verbatims ()
"Process and protect verbatim environments."
(let (delimiter
beg
end)
(py2texi-search-safe "\\\\begin{\\(verbatim\\|displaymath\\)}"
(replace-match "@example")
(setq beg (copy-marker (point) nil))
(re-search-forward "\\\\end{\\(verbatim\\|displaymath\\)}")
(setq end (copy-marker (match-beginning 0) nil))
(replace-match "@end example")
(py2texi-texinfo-escape beg end)
(put-text-property (- beg (length "@example"))
(+ end (length "@end example"))
'py2texi-protected t))
(py2texi-search-safe "\\\\verb\\([^a-z]\\)"
(setq delimiter (match-string 1))
(replace-match "@code{")
(setq beg (copy-marker (point) nil))
(re-search-forward (regexp-quote delimiter))
(setq end (copy-marker (match-beginning 0) nil))
(replace-match "}")
(put-text-property (- beg (length "@code{")) (+ end (length "}"))
'py2texi-protected t)
(py2texi-texinfo-escape beg end))))
(defun py2texi-process-comments ()
"Remove comments."
(let (point)
(py2texi-search-safe "%"
(setq point (point))
(when (save-excursion
(re-search-backward "\\(^\\|[^\\]\\(\\\\\\\\\\)*\\)%\\=" nil t))
(delete-region (1- point)
(save-excursion (beginning-of-line 2) (point)))))))
(defun py2texi-process-includes ()
"Include LaTeX input files.
Do not include .ind files."
(let ((path (file-name-directory file))
filename
dirs
includefile)
(py2texi-search-safe "\\\\input{\\([^}]+\\)}"
(setq filename (match-string 1))
(unless (save-match-data (string-match "\\.tex$" filename))
(setq filename (concat filename ".tex")))
(setq includefile (save-match-data
(string-match "\\.ind\\.tex$" filename)))
(setq dirs py2texi-dirs)
(while (and (not includefile) dirs)
(setq includefile
(concat (file-name-as-directory (car dirs)) filename))
(if (not (file-name-absolute-p includefile))
(setq includefile
(concat (file-name-as-directory path) includefile)))
(unless (file-exists-p includefile)
(setq includefile nil)
(setq dirs (cdr dirs))))
(if includefile
(save-restriction
(narrow-to-region (match-beginning 0) (match-end 0))
(delete-region (point-min) (point-max))
(when (stringp includefile)
(insert-file-contents includefile)
(goto-char (point-min))
(insert "\n")
(py2texi-process-verbatims)
(py2texi-process-comments)
(py2texi-process-includes)))
(replace-match (format "\\\\emph{Included file %s}" filename))
(py2texi-message (format "Input file %s not found" filename))))))
(defun py2texi-process-funnyas ()
"Convert @s."
(py2texi-search-safe "@"
(replace-match "@@")))
(defun py2texi-process-environments ()
"Process LaTeX environments."
(let ((stack ())
kind
environment
parameter
arguments
n
string
description)
(py2texi-search-safe (concat "\\\\\\(begin\\|end\\|item\\)"
"\\({\\([^}]*\\)}\\|[[]\\([^]]*\\)[]]\\|\\)")
(setq kind (match-string 1)
environment (match-string 3)
parameter (match-string 4))
(replace-match "")
(cond
((string= kind "begin")
(setq description (assoc environment py2texi-environments))
(if description
(progn
(setq n (cadr description))
(setq description (cddr description))
(setq string (py2texi-tex-arguments n))
(string-match (py2texi-regexp n) string)
; incorrect but sufficient
(insert (replace-match (eval (car description))
t nil string))
(setq stack (cons (cadr description) stack)))
(py2texi-message (format "Unknown environment: %s" environment))
(setq stack (cons "" stack))))
((string= kind "end")
(insert (eval (car stack)))
(setq stack (cdr stack)))
((string= kind "item")
(insert "\n@item " (or parameter "") "\n"))))
(when stack
(py2texi-message (format "Unclosed environment: %s" (car stack))))))
(defun py2texi-process-commands ()
"Process LaTeX commands."
(let (done
command
command-info
string
n)
(while (not done)
(setq done t)
(py2texi-search-safe "\\\\\\([a-zA-Z*]+\\)\\(\\[[^]]*\\]\\)?"
(setq command (match-string 1))
(setq command-info (assoc command py2texi-commands))
(if command-info
(progn
(setq done nil)
(replace-match "")
(setq command-info (cdr command-info))
(setq n (car command-info))
(setq string (py2texi-tex-arguments n))
(string-match (py2texi-regexp n) string)
; incorrect but sufficient
(insert (replace-match (eval (cadr command-info))
t nil string)))
(py2texi-message (format "Unknown command: %s (not processed)"
command)))))))
(defun py2texi-argument-pattern (count)
(let ((filler "\\(?:[^{}]\\|\\\\{\\|\\\\}\\)*"))
(if (<= count 0)
filler
(concat filler "\\(?:{"
(py2texi-argument-pattern (1- count))
"}" filler "\\)*" filler))))
(defconst py2texi-tex-argument
(concat
"{\\("
(py2texi-argument-pattern 10) ;really at least 10!
"\\)}[ \t%@c\n]*")
"Regexp describing LaTeX command argument including argument separators.")
(defun py2texi-regexp (n)
"Make regexp matching N LaTeX command arguments."
(if (= n 0)
""
(let ((regexp "^[^{]*"))
(while (> n 0)
(setq regexp (concat regexp py2texi-tex-argument))
(setq n (1- n)))
regexp)))
(defun py2texi-tex-arguments (n)
"Remove N LaTeX command arguments and return them as a string."
(let ((point (point))
(i 0)
result
match)
(if (= n 0)
(progn
(when (re-search-forward "\\=\\({}\\| *\\)" nil t)
(replace-match ""))
"")
(while (> n 0)
(unless (re-search-forward
"\\(\\=\\|[^\\\\]\\)\\(\\\\\\\\\\)*\\([{}]\\)" nil t)
(debug))
(if (string= (match-string 3) "{")
(setq i (1+ i))
(setq i (1- i))
(when (<= i 0)
(setq n (1- n)))))
(setq result (buffer-substring-no-properties point (point)))
(while (string-match "\n[ \t]*" result)
(setq result (replace-match " " t nil result)))
(delete-region point (point))
result)))
(defun py2texi-process-simple-commands ()
"Replace single character LaTeX commands."
(let (char)
(py2texi-search-safe "\\\\\\([^a-z]\\)"
(setq char (match-string 1))
(replace-match (format "%s%s"
(if (or (string= char "{")
(string= char "}")
(string= char " "))
"@"
"")
(if (string= char "\\")
"\\\\"
char))))))
(defun py2texi-fix-indentation ()
"Remove white space at the beginning of lines."
(py2texi-search-safe "^[ \t]+"
(replace-match "")))
(defun py2texi-fix-nodes ()
"Remove unwanted characters from nodes and make nodes unique."
(let ((nodes (make-hash-table :test 'equal))
id
counter
string
label
index)
(py2texi-search "^@node +\\(.*\\)$"
(setq string (match-string 1))
(if py2texi-xemacs
(replace-match "@node " t)
(replace-match "" t nil nil 1))
(while (string-match "@label{[^}]*}" string)
(setq label (match-string 0 string))
(setq string (replace-match "" t nil string)))
(while (string-match "@..?index{[^}]*}" string)
(setq index (match-string 0 string))
(setq string (replace-match "" t nil string)))
(while (string-match "@[a-zA-Z]+\\|[{}():]\\|``\\|''" string)
(setq string (replace-match "" t nil string)))
(while (string-match " -- " string)
(setq string (replace-match " - " t nil string)))
(while (string-match "\\." string)
(setq string (replace-match "" t nil string)))
(when (string-match " +$" string)
(setq string (replace-match "" t nil string)))
(when (string-match "^\\(Built-in\\|Standard\\) Module \\|The " string)
(setq string (replace-match "" t nil string)))
(string-match "^[^,]+" string)
(setq id (match-string 0 string))
(setq counter (gethash id nodes))
(if counter
(progn
(setq counter (1+ counter))
(setq string (replace-match (format "\\& %d" counter)
t nil string)))
(setq counter 1))
(setf (gethash id nodes) counter)
(insert string)
(beginning-of-line 3)
(when label
(insert label "\n"))
(when index
(insert index "\n")))))
(defun py2texi-fix-references ()
"Process labels and make references to point to appropriate nodes."
(let ((labels ())
node)
(py2texi-search-safe "@label{\\([^}]*\\)}"
(setq node (save-excursion
(save-match-data
(and (re-search-backward "@node +\\([^,\n]+\\)" nil t)
(match-string 1)))))
(when node
(setq labels (cons (cons (match-string 1) node) labels)))
(replace-match ""))
(py2texi-search-safe "@ref{\\([^}]*\\)}"
(setq node (assoc (match-string 1) labels))
(replace-match "")
(when node
(insert (format "@ref{%s}" (cdr node)))))))
(defun py2texi-fix-indices ()
"Remove unwanted characters from @*index commands and create final indices."
(py2texi-search-safe "@..?index\\>[^\n]*\\(\\)\n"
(replace-match "" t nil nil 1))
(py2texi-search-safe "@..?index\\>[^\n]*\\(\\)"
(replace-match "\n" t nil nil 1))
(py2texi-search-safe "@..?index\\({\\)\\([^}]+\\)\\(}+\\)"
(replace-match " " t nil nil 1)
(replace-match "" t nil nil 3)
(let ((string (match-string 2)))
(save-match-data
(while (string-match "@[a-z]+{" string)
(setq string (replace-match "" nil nil string)))
(while (string-match "{" string)
(setq string (replace-match "" nil nil string))))
(replace-match string t t nil 2)))
(py2texi-search-safe "@..?index\\>.*\\([{}]\\|@[a-z]*\\)"
(replace-match "" t nil nil 1)
(goto-char (match-beginning 0)))
(py2texi-search-safe "[^\n]\\(\\)@..?index\\>"
(replace-match "\n" t nil nil 1))
(goto-char (point-max))
(re-search-backward "@indices")
(replace-match "")
(insert (if moindex
(concat "@node Module Index\n"
"@unnumbered Module Index\n"
"@printindex mo\n")
"")
(if obindex
(concat "@node Class-Exception-Object Index\n"
"@unnumbered Class, Exception, and Object Index\n"
"@printindex ob\n")
"")
(if findex
(concat "@node Function-Method-Variable Index\n"
"@unnumbered Function, Method, and Variable Index\n"
"@printindex fn\n")
"")
(if cindex
(concat "@node Miscellaneous Index\n"
"@unnumbered Miscellaneous Index\n"
"@printindex cp\n")
"")))
(defun py2texi-fix-backslashes ()
"Make backslashes from auxiliary commands."
(py2texi-search-safe "@backslash{}"
(replace-match "\\\\")))
(defun py2texi-fix-fonts ()
"Remove garbage after unstructured font commands."
(let (string)
(py2texi-search-safe "@destroy"
(replace-match "")
(when (eq (preceding-char) ?{)
(forward-char -1)
(setq string (py2texi-tex-arguments 1))
(insert (substring string 1 (1- (length string))))))))
(defun py2texi-fix-braces ()
"Escape braces for Texinfo."
(let (string)
(py2texi-search "{"
(unless (or (py2texi-protected)
(save-excursion
(re-search-backward
"@\\([a-zA-Z]*\\|multitable.*\\){\\=" nil t)))
(forward-char -1)
(setq string (py2texi-tex-arguments 1))
(insert "@" (substring string 0 (1- (length string))) "@}")))))
(defun py2texi-fix-newlines ()
"Remove extra newlines."
(py2texi-search "\n\n\n+"
(replace-match "\n\n"))
(py2texi-search-safe "@item.*\n\n"
(delete-backward-char 1))
(py2texi-search "@end example"
(unless (looking-at "\n\n")
(insert "\n"))))
(defun py2texi-destroy-empties ()
"Remove all comments.
This avoids some makeinfo errors."
(py2texi-search "@c\\>"
(unless (eq (py2texi-protected) t)
(delete-region (- (point) 2) (save-excursion (end-of-line) (point)))
(cond
((looking-at "\n\n")
(delete-char 1))
((save-excursion (re-search-backward "^[ \t]*\\=" nil t))
(delete-region (save-excursion (beginning-of-line) (point))
(1+ (point))))))))
(defun py2texi-adjust-level ()
"Increase heading level to @chapter, if needed.
This is only needed for distutils, so it has a very simple form only."
(goto-char (point-min))
(unless (re-search-forward "@chapter\\>" nil t)
(py2texi-search-safe "@section\\>"
(replace-match "@chapter" t))
(py2texi-search-safe "@\\(sub\\)\\(sub\\)?section\\>"
(replace-match "" nil nil nil 1))))
(defun py2texi-texinfo-escape (beg end)
"Escape Texinfo special characters in region."
(save-excursion
(goto-char beg)
(while (re-search-forward "[@{}]" end t)
(replace-match "@\\&"))))
(defun py2texi-protected ()
"Return protection status of the point before current point."
(get-text-property (1- (point)) 'py2texi-protected))
;;; Announce
(provide 'py2texi)
;;; py2texi.el ends here