doc/ext/cppdocs.py
author Aravindakshan Babu <akshan@stanford.edu>
Wed, 18 Aug 2010 12:05:18 -0700
branchdev
changeset 220 d07d77561661
parent 134 c270826fd4a8
permissions -rw-r--r--
Removed the points iterator in PersistenceDaigram; replaced it with a __iter__ method. Got rid of some python code in __init__.py, since it was not needed with the above change. Changed the docs to reflect this.

from docutils               import nodes, utils
from docutils.parsers.rst   import directives
from sphinx                 import addnodes
from sphinx.util.compat     import Directive

from sphinx.directives.desc import CDesc

############
# CppClass #
############
class CppClass(nodes.Part, nodes.Element):
    @staticmethod
    def html_visit(visitor, node):
        visitor.body.append('<dl class="class">')
        visitor.body.append(visitor.starttag(node, 'dt'))
        if node['tparams']:
            visitor.body.append('<em class="property">template</em> &lt;')
            tparam_names = ['class ' + tp[0] for tp in node['tparams']]
            visitor.body.append(', '.join(tparam_names))
            visitor.body.append('&gt;<br/>')
            
        visitor.body.append('<em class="property">class</em> ')
        visitor.body.append('<tt class="descname">' + node['name'] + '</tt>')
        visitor.body.append(u'<a class="headerlink" href="#%s" title="%s">\u00B6</a>' % 
                              ('cppclass-'+node['name'], _('Permalink to this class')))
        visitor.body.append('</dt>')
        visitor.body.append('<dd>')

        if node['derives']:
            visitor.body.append('<p>Derives from ')
            for d in node['derives'].split(','):
                dnode ={ 'type': 'cppclass', 'target': d.strip() } 
                Ref.html_visit(visitor, dnode)
                visitor.body.append(d)
                Ref.html_depart(visitor, dnode)
            visitor.body.append('.</p>')

        visitor.body.append('<p>')
        for name, desc in node['tparams']:
            visitor.body.append(name + ' &mdash; ' + desc + '<br/>')
        visitor.body.append('</p>')


    @staticmethod
    def html_depart(visitor, node):
        visitor.body.append('</dd></dl>')


class CppClassDirective(Directive):
    has_content = True
    required_arguments = 1
    final_argument_whitespace = True
    option_spec = { 'derives': directives.unchanged,
                    'tparam':  directives.unchanged }

    def run(self):
        env = self.state.document.settings.env

        cppclass = CppClass()
        cppclass['name'] = self.arguments[0]
        cppclass['derives'] = self.options.get('derives')

        targetname = '%s-%s' % ('cppclass', cppclass['name'])
        targetnode = nodes.target('', '', ids=[targetname])
        self.state.document.note_explicit_target(targetnode)

        indextext = _('%s (C++ class)') % cppclass['name']
        inode = addnodes.index(entries = [('single', indextext, 
                                           'cppclass-' + cppclass['name'], 
                                           cppclass['name'])])

        self.state.nested_parse(self.content, self.content_offset, cppclass)

        return [inode, targetnode, cppclass]

class TParam(nodes.Element):
    pass

class TParamDirective(Directive):
    required_arguments = 1
    optional_arguments = 1
    final_argument_whitespace = True

    def run(self):
        tparam = TParam()

        tparam['name'] = self.arguments[0]
        if len(self.arguments) > 1:
            tparam['description'] = self.arguments[1]

        return [tparam]


#############
# CppMethod #
#############
class CppMethod(nodes.Part, nodes.Element):
    @staticmethod
    def html_visit(visitor, node):
        visitor.body.append(visitor.starttag(node, 'dt'))
        visitor.body.append(node['name'])
        visitor.body.append(u'<a class="headerlink" href="#%s" title="%s">\u00B6</a>' % 
                             ('cppmethod-' + node['classname'] + '::' + node['name'], _('Permalink to this class')))
        visitor.body.append('</dt>')
        visitor.body.append('<dd>')

    @staticmethod
    def html_depart(visitor, node):
        visitor.body.append('</dd></dl>')


class CppMethodDirective(Directive):
    has_content = True
    required_arguments = 1
    final_argument_whitespace = True

    def run(self):
        env = self.state.document.settings.env

        cppmethod = CppMethod()
        cppmethod['name'] = self.arguments[0]            # TODO: parse name

        targetname = '%s-%s' % ('cppmethod', cppmethod['name'])
        targetnode = nodes.target('', '', ids=[targetname])
        self.state.document.note_explicit_target(targetnode)

        indextext = _('%s (C++ method)') % cppmethod['name']
        inode = addnodes.index(entries = [('single', indextext, 
                                           'cppmethod-' + cppmethod['name'], 
                                           cppmethod['name'])])

        self.state.nested_parse(self.content, self.content_offset, cppmethod)

        return [inode, targetnode, cppmethod]


class Ref(nodes.Inline, nodes.TextElement):
    @staticmethod
    def html_visit(visitor, node):
        if node['type'] == 'cppclass':
            visitor.body.append('<a href="#%s-%s">' % (node['type'], node['target']))
        elif node['type'] == 'cppmethod':
            # TODO: check if the name is not fully qualified, and has a parent CppClass node, 
            #       in that case, prepend the name, otherwise
            visitor.body.append('<a href="#%s-%s::%s">' % (node['type'], node['classname'], node['target']))


    @staticmethod
    def html_depart(visitor, node):
        visitor.body.append('</a>')

def cppclass_role(role, rawtext ,text, lineno, inliner, options={}, content=[]):
    text = utils.unescape(text)
    node = Ref(text, text, target=text, type='cppclass')
    node['docname'] = inliner.document.settings.env.docname
    return [node], []

def cppmethod_role(role, rawtext ,text, lineno, inliner, options={}, content=[]):
    text = utils.unescape(text)
    node = Ref(text, text, target=text, type='cppmethod')
    node['docname'] = inliner.document.settings.env.docname
    return [node], []


def process_classnames(app, doctree, fromdocname):
    for node in doctree.traverse(CppClass):
        for method in node.traverse(CppMethod):
            method['classname'] = node['name']
        for ref in node.traverse(Ref):
            if ref['type'] == 'cppmethod':
                ref['classname'] = node['name']

def process_tparams(app, doctree, fromdocname):
    for node in doctree.traverse(CppClass):
        node['tparams'] = []
        for tparam in node.traverse(TParam):
            node['tparams'].append((tparam['name'], tparam['description']))


def process_cfunction_scope(app, doctree, fromdocname):
    for node in doctree.traverse():
        if 'ctype' in node: print node
        if 'cfunction' in node: print node
        
def setup(app):
    app.add_node(Ref,               html=(Ref.html_visit, Ref.html_depart))

    app.add_directive('cppclass',   CppClassDirective)
    app.add_node(CppClass,          html=(CppClass.html_visit, CppClass.html_depart))
    app.add_role('cppclass',        cppclass_role)
    
    app.add_directive('tparam',     TParamDirective)
    app.add_node(TParam,            html=(lambda v,n: '', lambda v,n: ''))
    
    app.add_directive('cppmethod',  CppMethodDirective)
    app.add_node(CppMethod,         html=(CppMethod.html_visit, CppMethod.html_depart))
    app.add_role('cppmethod',       cppmethod_role)

    app.connect('doctree-resolved', process_classnames)
    app.connect('doctree-resolved', process_tparams)
    
    app.connect('doctree-resolved', process_cfunction_scope)