Update to 2.0.0 tree from current Fremantle build
[opencv] / doc / plastex / renderer.py
diff --git a/doc/plastex/renderer.py b/doc/plastex/renderer.py
new file mode 100644 (file)
index 0000000..f593d17
--- /dev/null
@@ -0,0 +1,463 @@
+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_cvexp(self, node):
+    self.indent = -1
+    self.in_func = False
+    decl = unicode(node.attributes[self.language]).rstrip(' ;')  # remove trailing ';'
+    r = u"\n\n.. %s:: %s\n\n" % ({'c' : 'cfunction', 'py' : 'function'}[self.language], decl)
+    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_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_cvfunc(self, node):
+    t = unicode(node.attributes['title']).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_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_cross(self, node):
+    t = str(node.attributes['name']).strip()
+    # 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":ref:`%s`" % str(node.attributes['name']).strip()
+
+  def ind(self):
+    return u" " * self.indent
+
+  def do_cvarg(self, node):
+    self.indent += 4
+
+    print "HELLO", str(node.attributes['item']).strip()
+    # 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())
+
+
+  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:
+      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')
+    body = "\n".join([u"%s    %s" % (self.ind(), s) for s in lines[1:-1]])
+    return u"\n\n%s::\n\n" % self.ind() + unicode(body) + "\n\n"
+
+  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_cvPy(self, node):
+    if 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')
+    ifstack=[True]
+    for l in f.readlines():
+        if l.startswith("\\if"):
+            ifstack.append(conditionals.get(l.rstrip()[3:], False))
+        elif l.startswith("\\else"):
+            ifstack[-1] = not ifstack[-1]
+        elif l.startswith("\\fi"):
+            ifstack.pop()
+        elif ifstack[-1]:
+            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
+    #tex.ownerDocument.config['files']['filename'] = 'cxcore.rst'
+
+    for f in ['CxCore', 'CvReference', 'HighGui']:
+        preprocess_conditionals(f, '-' + language,
+            {'C':language=='c', 'Python':language=='py', '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)