opencv/doc/plastex/renderer.py

596 lines
18 KiB
Python

import string, re
import sys
from plasTeX.Renderers import Renderer
from plasTeX.Base.TeX import Primitives
# import generated OpenCV function names
# if the file function_names.py does not exist, it
# can be generated using the script find_function_names.sh
try:
from function_names import opencv_function_names
except:
opencv_function_names = []
pass
class XmlRenderer(Renderer):
def default(self, node):
""" Rendering method for all non-text nodes """
s = []
# Handle characters like \&, \$, \%, etc.
if len(node.nodeName) == 1 and node.nodeName not in string.letters:
return self.textDefault(node.nodeName)
# Start tag
s.append('<%s>' % node.nodeName)
# See if we have any attributes to render
if node.hasAttributes():
s.append('<attributes>')
for key, value in node.attributes.items():
# If the key is 'self', don't render it
# these nodes are the same as the child nodes
if key == 'self':
continue
s.append('<%s>%s</%s>' % (key, unicode(value), key))
s.append('</attributes>')
# Invoke rendering on child nodes
s.append(unicode(node))
# End tag
s.append('</%s>' % node.nodeName)
return u'\n'.join(s)
def textDefault(self, node):
""" Rendering method for all text nodes """
return node.replace('&','&amp;').replace('<','&lt;').replace('>','&gt;')
from plasTeX.Renderers import Renderer as BaseRenderer
class reStructuredTextRenderer(BaseRenderer):
aliases = {
'superscript': 'active::^',
'subscript': 'active::_',
'dollar': '$',
'percent': '%',
'opencurly': '{',
'closecurly': '}',
'underscore': '_',
'ampersand': '&',
'hashmark': '#',
'space': ' ',
'tilde': 'active::~',
'at': '@',
'backslash': '\\',
}
def __init__(self, *args, **kwargs):
BaseRenderer.__init__(self, *args, **kwargs)
# Load dictionary with methods
for key in vars(type(self)):
if key.startswith('do__'):
self[self.aliases[key[4:]]] = getattr(self, key)
elif key.startswith('do_'):
self[key[3:]] = getattr(self, key)
self.indent = 0
self.in_func = False
self.in_cvarg = False
self.descriptions = 0
self.after_parameters = False
self.func_short_desc = ''
def do_document(self, node):
return unicode(node)
def do_par(self, node):
if self.indent == -1:
pre = ""
post = ""
else:
pre = "\n" + (" " * self.indent)
post = "\n"
return pre + unicode(node).lstrip(" ") + post
def do_chapter(self, node):
t = str(node.attributes['title'])
section_files = []
for section in node.subsections:
try:
filename = section.filenameoverride
if filename is not None:
section_files.append(filename)
except:
pass
toc = ".. toctree::\n :maxdepth: 2\n\n"
for file in section_files:
if file[-4:] != '.rst':
print >>sys.stderr, "WARNING: unexpected file extension:", file
else:
toc += " %s\n" % file[:-4]
toc += "\n\n"
return "\n\n%s\n%s\n%s\n\n" % ('*' * len(t), t, '*' * len(t)) + toc + unicode(node)
def do_section(self, node):
t = str(node.attributes['title'])
return "\n\n%s\n%s\n\n" % (t, '=' * len(t)) + unicode(node)
def do_subsection(self, node):
t = str(node.attributes['title'])
return "\n\n%s\n%s\n\n" % (t, '-' * len(t)) + unicode(node)
def do_cvdefX(self, node, lang):
if self.language != lang:
return u""
self.indent = -1
self.in_func = False
decl = unicode(node.attributes['a']).rstrip(' ;') # remove trailing ';'
decl_list = decl.split(";")
r = u""
for d in decl_list:
r += u"\n\n.. %s:: %s\n\n" % ({'c' : 'cfunction', 'cpp' : 'cfunction', 'py' : 'function'}[self.language], d.strip())
self.indent = 4
if self.func_short_desc != '':
r += self.ind() + self.func_short_desc + '\n\n'
self.func_short_desc = ''
return r
def do_cvdefC(self, node):
return self.do_cvdefX(node, 'c')
def do_cvcode(self, node):
#body = unicode(node.source).replace(u"\n",u"").replace(u"\\newline", u"\n");
#body = body.replace(u"\\par", u"\n").replace(u"\\cvcode{", "").replace(u"\\", u"")[:-1];
body = unicode(node.source).replace(u"\\newline", u"\n").replace("_ ", "_");
body = body.replace(u"\\par", u"\n").replace(u"\\cvcode{", "").replace(u"\n\n",u"\n");
body = body.replace(u",\n", ",\n ").replace(u"\\", u"")[:-1];
lines = body.split(u"\n")
self.indent += 4
body = "\n".join([u"%s %s" % (self.ind(), s) for s in lines])
r = (u"\n\n%s::\n\n" % self.ind()) + unicode(body) + u"\n\n"
self.indent -= 4
return r
def do_cvdefCpp(self, node):
lang = 'cpp'
if self.language != lang:
return u""
self.indent = -1
self.in_func = False
decl = unicode(node.source).replace(u"\n",u"").replace(u"\\newline", u"").replace(u"_ ", u"_");
decl = decl.replace(u"\\par", u"").replace(u"\\cvdefCpp{", "").replace(u"\\", u"").rstrip(u" ;}");
decl_list = decl.split(";")
r = u""
for d in decl_list:
r += u"\n\n.. %s:: %s\n\n" % ({'c' : 'cfunction', 'cpp' : 'cfunction', 'py' : 'function'}[self.language], d.strip())
self.indent = 4
if self.func_short_desc != '':
r += self.ind() + self.func_short_desc + '\n\n'
self.func_short_desc = ''
return r
def do_cvdefPy(self, node):
return self.do_cvdefX(node, 'py')
def do_description(self, node):
self.descriptions += 1
desc = unicode(node)
self.descriptions -= 1
if self.descriptions == 0:
self.after_parameters = True
return u"\n\n" + desc + u"\n\n"
def do_includegraphics(self, node):
filename = '../' + str(node.attributes['file']).strip()
if not os.path.isfile(filename):
print >>sys.stderr, "WARNING: missing image file", filename
return u""
return u"\n\n%s.. image:: %s\n\n" % (self.ind(), filename)
def do_xfunc(self, node, a='title'):
t = self.get_func_prefix() + unicode(node.attributes[a]).strip()
print "====>", t
label = u"\n\n.. index:: %s\n\n.. _%s:\n\n" % (t, t)
self.in_func = True
self.descriptions = 0
self.after_parameters = False
self.indent = 0
#return u"" + unicode(node)
# Would like to look ahead to reorder things, but cannot see more than 2 ahead
if 0:
print "NODES:", node.source
n = node.nextSibling
while (n != None) and (n.nodeName != 'cvfunc'):
print " ", n.nodeName, len(n.childNodes)
n = n.nextSibling
print "-----"
return label + u"\n\n%s\n%s\n\n" % (t, '-' * len(t)) + unicode(node)
def do_cvfunc(self, node):
return self.do_xfunc(node)
def do_cvclass(self, node):
return self.do_xfunc(node)
def get_func_prefix(self):
return u""
if self.language == 'c':
return u"cv"
if self.language == 'cpp':
return u"cv\\:\\:"
if self.language == 'py':
return u"cv\\."
return u""
def do_cvFunc(self, node):
return self.do_xfunc(node, ['title','alt'][self.language == 'cpp'])
def do_cvCPyFunc(self, node):
return self.do_xfunc(node)
def do_cvCppFunc(self, node):
return self.do_xfunc(node)
def do_cvstruct(self, node):
t = str(node.attributes['title']).strip()
self.after_parameters = False
self.indent = 4
return u".. ctype:: %s" % t + unicode(node)
def do_cvmacro(self, node):
t = str(node.attributes['title']).strip()
self.after_parameters = False
self.indent = 4
return u".. cmacro:: %s" % t + unicode(node)
def showTree(self, node, i = 0):
n = node
while n != None:
print "%s[%s]" % (" " * i, n.nodeName)
if len(n.childNodes) != 0:
self.showTree(n.childNodes[0], i + 4)
n = n.nextSibling
def do_Huge(self, node):
return unicode(node)
def do_tabular(self, node):
if 0:
self.showTree(node)
rows = []
for row in node.childNodes:
cols = []
for col in row.childNodes:
cols.append(unicode(col).strip())
rows.append(cols)
maxes = [ 0 ] * len(rows[0])
for r in rows:
maxes = [ max(m,len(c)) for m,c in zip(maxes, r) ]
sep = "+" + "+".join([ ('-' * (m + 4)) for m in maxes]) + "+"
s = ""
s += sep + "\n"
for r in rows:
#s += "|" + "|".join([ ' ' + c.ljust(m + 3) for c,m in zip(r, maxes) ]) + "|" + "\n"
#s += sep + "\n"
s += self.ind() + "|" + "|".join([ ' ' + c.ljust(m + 3) for c,m in zip(r, maxes) ]) + "|" + "\n"
s += self.ind() + sep + "\n"
return unicode(s)
def do_verbatim(self, node):
return u"\n\n::\n\n " + unicode(node.source.replace('\n', '\n ')) + "\n\n"
def do_index(self, node):
return u""
# No idea why this does not work... JCB
return u"\n\n.. index:: (%s)\n\n" % node.attributes['entry']
def do_label(self, node):
return u""
def fixup_funcname(self, str):
"""
add parentheses to a function name if not already present
"""
str = str.strip()
if str[-1] != ')':
return str + '()'
return str
def gen_reference(self, name):
"""
try to guess whether *name* is a function, struct or macro
and if yes, generate the appropriate reference markup
"""
name = name.strip()
if name[0:2] == 'cv':
return u":cfunc:`%s`" % self.fixup_funcname(name)
elif 'cv'+name in opencv_function_names:
if self.language in ['c', 'cpp']:
return u":cfunc:`cv%s`" % self.fixup_funcname(name)
else:
return u":func:`%s`" % self.fixup_funcname(name)
elif name[0:2] == 'Cv' or name[0:3] == 'Ipl':
return u":ctype:`%s`" % name
elif name[0:2] == 'CV':
return u":cmacro:`%s`" % name
return None
def do_xcross(self, refname):
# try to guess whether t is a function, struct or macro
# and if yes, generate the appropriate reference markup
#rst_ref = self.gen_reference(refname)
#if rst_ref is not None:
# return rst_ref
return u":ref:`%s`" % refname
def do_cross(self, node):
return self.do_xcross(str(node.attributes['name']).strip())
def do_cvCross(self, node):
prefix = self.get_func_prefix()
if self.language == 'cpp':
t = prefix + str(node.attributes['altname']).strip()
return u":ref:`%s`" % t
else:
t = prefix + str(node.attributes['name']).strip()
return self.do_xcross(t)
def do_cvCPyCross(self, node):
t = self.get_func_prefix() + str(node.attributes['name']).strip()
return self.do_xcross(t)
def do_cvCppCross(self, node):
t = self.get_func_prefix() + str(node.attributes['name']).strip()
return u":ref:`%s`" % t
def ind(self):
return u" " * self.indent
def do_cvarg(self, node):
self.indent += 4
# Nested descriptions occur e.g. when a flag parameter can
# be one of several constants. We want to render the inner
# description differently than the outer parameter descriptions.
if self.in_cvarg or self.after_parameters:
defstr = unicode(node.attributes['def'])
assert not (u"\xe2" in unicode(defstr))
self.indent -= 4
param_str = u"\n%s * **%s** - %s\n"
return param_str % (self.ind(), str(node.attributes['item']).strip(), self.fix_quotes(defstr).strip(" "))
# save that we are in a paramater description
self.in_cvarg = True
defstr = unicode(node.attributes['def'])
assert not (u"\xe2" in unicode(defstr))
self.in_cvarg = False
self.indent -= 4
param_str = u"\n%s:param %s: %s"
return param_str % (self.ind(), str(node.attributes['item']).strip(), self.fix_quotes(defstr).strip())
#lines = defstr.split('\n')
#return u"\n%s%s\n%s\n" % (self.ind(), str(node.attributes['item']).strip(), "\n".join([self.ind()+" "+l for l in lines]))
def do_bgroup(self, node):
return u"bgroup(%s)" % node.source
def do_url(self, node):
return unicode(node.attributes['loc'])
def do_enumerate(self, node):
return unicode(node)
def do_itemize(self, node):
return unicode(node)
def do_item(self, node):
#if node.attributes['term'] != None:
if node.attributes.get('term',None):
self.indent += 4
defstr = unicode(node).strip()
assert not (u"\xe2" in unicode(defstr))
self.indent -= 4
return u"\n%s* %s *\n%s %s\n" % (self.ind(), unicode(node.attributes['term']).strip(), self.ind(), defstr)
else:
return u"\n\n%s* %s" % (self.ind(), unicode(node).strip())
def do_textit(self, node):
return "*%s*" % unicode(node.attributes['self'])
def do_texttt(self, node):
t = unicode(node)
# try to guess whether t is a function, struct or macro
# and if yes, generate the appropriate reference markup
rst_ref = self.gen_reference(t)
if rst_ref is not None:
return rst_ref
return u"``%s``" % t
def do__underscore(self, node):
return u"_"
def default(self, node):
print "DEFAULT dropping", node.nodeName
return unicode(node)
def do_lstlisting(self, node):
self.in_func = False
lines = node.source.split('\n')
self.indent += 2
body = "\n".join([u"%s %s" % (self.ind(), s) for s in lines[1:-1]])
r = (u"\n\n%s::\n\n" % self.ind()) + unicode(body) + u"\n\n"
if self.func_short_desc != '':
r = self.ind() + self.func_short_desc + '\n\n' + r
self.func_short_desc = ''
self.indent -= 2
return r
def do_math(self, node):
return u":math:`%s`" % node.source
def do_displaymath(self, node):
words = self.fix_quotes(node.source).strip().split()
return u"\n\n%s.. math::\n\n%s %s\n\n" % (self.ind(), self.ind(), " ".join(words[1:-1]))
def do_maketitle(self, node):
return u""
def do_setcounter(self, node):
return u""
def do_tableofcontents(self, node):
return u""
def do_titleformat(self, node):
return u""
def do_subsubsection(self, node):
return u""
def do_include(self, node):
return u""
def fix_quotes(self, s):
s = s.replace(u'\u2013', "'")
s = s.replace(u'\u2019', "'")
s = s.replace(u'\u2264', "#<2264>")
s = s.replace(u'\xd7', "#<d7>")
return s
def do_cvC(self, node):
if self.language == 'c':
return unicode(node.attributes['a'])
return unicode("")
def do_cvCpp(self, node):
if self.language == 'cpp':
return unicode(node.attributes['a'])
return unicode("")
def do_cvPy(self, node):
if self.language == 'py':
return unicode(node.attributes['a'])
return unicode("")
def do_cvCPy(self, node):
if self.language == 'c' or self.language == 'py':
return unicode(node.attributes['a'])
return unicode("")
def do_ifthenelse(self, node):
# print "IFTHENELSE: [%s],[%s],[%s]" % (node.attributes['test'], str(node.attributes['then']), node.attributes['else'])
print "CONDITION", unicode(node.attributes['test']).strip() == u'true'
if unicode(node.attributes['test']).strip() == u'true':
print "TRUE: [%s]" % str(node.attributes['then'])
return unicode(node.attributes['then'])
else:
return unicode(node.attributes['else'])
def do_equal(self, node):
first = unicode(node.attributes['first']).strip()
second = unicode(node.attributes['second']).strip()
if first == second:
return u'true'
else:
return u'false'
def textDefault(self, node):
if self.in_func:
self.func_short_desc += self.fix_quotes(unicode(node)).strip(" ")
return u""
s = unicode(node)
s = self.fix_quotes(s)
return s
return node.replace('\\_','_')
from plasTeX.TeX import TeX
import os
import pickle
def preprocess_conditionals(fname, suffix, conditionals):
print 'conditionals', conditionals
f = open("../" + fname + ".tex", 'r')
fout = open(fname + suffix + ".tex", 'w')
print 'write', fname + suffix + ".tex"
ifstack=[True]
for l in f.readlines():
ll = l.lstrip()
if ll.startswith("\\if"):
ifstack.append(conditionals.get(ll.rstrip()[3:], False))
elif ll.startswith("\\else"):
ifstack[-1] = not ifstack[-1]
elif ll.startswith("\\fi"):
ifstack.pop()
elif not False in ifstack:
fout.write(l)
f.close()
fout.close()
def parse_documentation_source(language):
# Instantiate a TeX processor and parse the input text
tex = TeX()
tex.ownerDocument.config['files']['split-level'] = 0
master_f = open("../online-opencv.tex", "rt")
out_master_f = open(("../online-opencv-%s.tex" % language), "wt")
flist = []
for l in master_f.readlines():
outl = l
if l.startswith("\\newcommand{\\targetlang}{}"):
outl = l.replace("}", ("%s}" % language))
elif l.startswith("\\input{"):
flist.append(re.findall(r"\{(.+)\}", l)[0])
outl = l.replace("}", ("-%s}" % language))
out_master_f.write(outl)
master_f.close()
out_master_f.close()
index_f = open("index.rst.copy", "rt")
index_lines = list(index_f.readlines())
index_f.close()
out_index_f = open("index.rst", "wt")
header_line = "OpenCV |version| %s Reference" % {"py": "Python", "c": "C", "cpp": "C++"}[language]
index_lines = [header_line + "\n", "="*len(header_line) + "\n", "\n"] + index_lines
for l in index_lines:
out_index_f.write(l)
out_index_f.close()
for f in flist:
preprocess_conditionals(f, '-' + language,
{'C':language=='c', 'Python':language=='py',
'Py':language=='py', 'CPy':(language=='py' or language == 'c'),
'Cpp':language=='cpp', 'plastex':True})
if 1:
tex.input("\\input{online-opencv-%s.tex}" % language)
else:
src0 = r'''
\documentclass{book}
\usepackage{myopencv}
\begin{document}'''
src1 = r'''
\end{document}
'''
lines = list(open("../CvReference.tex"))
LINES = 80
tex.input(src0 + "".join(lines[:LINES]) + src1)
return tex.parse()
language = sys.argv[1]
document = parse_documentation_source(language)
rest = reStructuredTextRenderer()
rest.language = language
rest.render(document)