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_verbatim(self, node):
79 if node.text is not None:
80 # remove the leading ' *' of any lines
81 lines = [re.sub('^\s*\*','', l) for l in node.text.split('\n')]
82 # Merge each paragraph together
83 text = re.sub("\n\n", "PaRaGrraphSplit", '\n'.join(lines))
84 text = re.sub('\n', '', text)
85 lines = text.split('PaRaGrraphSplit')
87 # merge content to the built doc
88 if self.continue_line:
89 self.lines[-1] += lines[0]
94 self.generic_visit(node)
96 self.continue_line = False
98 def visit_parametername(self, node):
99 if 'direction' in node.attrib:
100 direction = '[%s] ' % node.get('direction')
104 self.lines.append('**%s** -- %s' % (
105 node.text, direction))
106 self.continue_line = True
108 def visit_parameterlist(self, node):
109 lines = [l for l in type(self)().generic_visit(node).lines if l is not '']
110 self.lines.extend([':parameters:', ''] + ['* %s' % l for l in lines] + [''])
112 def visit_simplesect(self, node):
113 if node.get('kind') == 'return':
114 self.lines.append(':returns: ')
115 self.continue_line = True
116 self.generic_visit(node)
118 def visit_listitem(self, node):
119 self.lines.append(' - ')
120 self.continue_line = True
121 self.generic_visit(node)
123 def visit_preformatted(self, node):
124 segment = [node.text if node.text is not None else '']
125 for n in node.getchildren():
126 segment.append(n.text)
127 if n.tail is not None:
128 segment.append(n.tail)
130 lines = ''.join(segment).split('\n')
131 self.lines.extend(('.. code-block:: C++', ''))
132 self.lines.extend([' ' + l for l in lines])
134 def visit_computeroutput(self, node):
135 c = node.find('preformatted')
137 return self.visit_preformatted(c)
138 return self.visit_preformatted(node)
140 def visit_xrefsect(self, node):
141 if node.find('xreftitle').text == 'Deprecated':
142 sublines = type(self)().generic_visit(node).lines
143 self.lines.extend(['.. admonition:: Deprecated'] + [' ' + s for s in sublines])
145 raise ValueError(node)
147 def visit_subscript(self, node):
148 self.lines[-1] += '\ :sub:`%s` %s' % (node.text, node.tail)