1 from __future__ import print_function, absolute_import, division
2 from . import get_doxygen_root
5 def format_xml_paragraph(xmlnode):
6 """Format an Doxygen XML segment (principally a detaileddescription)
7 as a paragraph for inclusion in the rst document
18 return [l.rstrip() for l in _DoxygenXmlParagraphFormatter().generic_visit(xmlnode).lines]
21 class _DoxygenXmlParagraphFormatter(object):
22 # This class follows the model of the stdlib's ast.NodeVisitor for tree traversal
23 # where you dispatch on the element type to a different method for each node
24 # during the traverse.
26 # It's supposed to handle paragraphs, references, preformatted text (code blocks), and lists.
30 self.continue_line = False
32 def visit(self, node):
33 method = 'visit_' + node.tag
34 visitor = getattr(self, method, self.generic_visit)
37 def generic_visit(self, node):
38 for child in node.getchildren():
42 def visit_ref(self, node):
43 ref = get_doxygen_root().findall('.//*[@id="%s"]' % node.get('refid'))
46 if ref.tag == 'memberdef':
47 parent = ref.xpath('./ancestor::compounddef/compoundname')[0].text
48 name = ref.find('./name').text
49 real_name = parent + '::' + name
50 elif ref.tag in ('compounddef', 'enumvalue'):
51 name_node = ref.find('./name')
52 real_name = name_node.text if name_node is not None else ''
54 raise NotImplementedError(ref.tag)
58 val = [':cpp:any:`', node.text]
60 val.extend((' <', real_name, '>`'))
63 if node.tail is not None:
66 self.lines[-1] += ''.join(val)
68 def visit_para(self, node):
69 if node.text is not None:
70 if self.continue_line:
71 self.lines[-1] += node.text
73 self.lines.append(node.text)
74 self.generic_visit(node)
76 self.continue_line = False
78 def visit_parametername(self, node):
79 if 'direction' in node.attrib:
80 direction = '[%s] ' % node.get('direction')
84 self.lines.append('**%s** -- %s' % (
85 node.text, direction))
86 self.continue_line = True
88 def visit_parameterlist(self, node):
89 lines = [l for l in type(self)().generic_visit(node).lines if l is not '']
90 self.lines.extend([':parameters:', ''] + ['* %s' % l for l in lines] + [''])
92 def visit_simplesect(self, node):
93 if node.get('kind') == 'return':
94 self.lines.append(':returns: ')
95 self.continue_line = True
96 self.generic_visit(node)
98 def visit_listitem(self, node):
99 self.lines.append(' - ')
100 self.continue_line = True
101 self.generic_visit(node)
103 def visit_preformatted(self, node):
104 segment = [node.text if node.text is not None else '']
105 for n in node.getchildren():
106 segment.append(n.text)
107 if n.tail is not None:
108 segment.append(n.tail)
110 lines = ''.join(segment).split('\n')
111 self.lines.extend(('.. code-block:: C++', ''))
112 self.lines.extend([' ' + l for l in lines])
114 def visit_computeroutput(self, node):
115 c = node.find('preformatted')
117 return self.visit_preformatted(c)
118 return self.visit_preformatted(node)
120 def visit_xrefsect(self, node):
121 if node.find('xreftitle').text == 'Deprecated':
122 sublines = type(self)().generic_visit(node).lines
123 self.lines.extend(['.. admonition:: Deprecated'] + [' ' + s for s in sublines])
125 raise ValueError(node)
127 def visit_subscript(self, node):
128 self.lines[-1] += '\ :sub:`%s` %s' % (node.text, node.tail)