alphashapes2d can handle degenerate inputs (thanks to Taras Galkovskyi for the bug report and the fix)
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> <')
tparam_names = ['class ' + tp[0] for tp in node['tparams']]
visitor.body.append(', '.join(tparam_names))
visitor.body.append('><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 + ' — ' + 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)