Logo AND Algorithmique Numérique Distribuée

Public GIT Repository
autodoxy: properly render verbatim blocks
[simgrid.git] / docs / source / _ext / autodoxy / autodoxy / xmlutils.py
1 from __future__ import print_function, absolute_import, division
2 from . import get_doxygen_root
3 import re
4
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
8
9     Parameters
10     ----------
11     xmlnode
12
13     Returns
14     -------
15     lines
16         A list of lines.
17     """
18     return [l.rstrip() for l in _DoxygenXmlParagraphFormatter().generic_visit(xmlnode).lines]
19
20
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.
25
26     # It's supposed to handle paragraphs, references, preformatted text (code blocks), and lists.
27
28     def __init__(self):
29         self.lines = ['']
30         self.continue_line = False
31
32     def visit(self, node):
33         method = 'visit_' + node.tag
34         visitor = getattr(self, method, self.generic_visit)
35         return visitor(node)
36
37     def generic_visit(self, node):
38         for child in node.getchildren():
39             self.visit(child)
40         return self
41
42     def visit_ref(self, node):
43         ref = get_doxygen_root().findall('.//*[@id="%s"]' % node.get('refid'))
44         if ref:
45             ref = ref[0]
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 ''
53             else:
54                 raise NotImplementedError(ref.tag)
55         else:
56             real_name = None
57
58         val = [':cpp:any:`', node.text]
59         if real_name:
60             val.extend((' <', real_name, '>`'))
61         else:
62             val.append('`')
63         if node.tail is not None:
64             val.append(node.tail)
65
66         self.lines[-1] += ''.join(val)
67
68     def visit_para(self, node):
69         if node.text is not None:
70             if self.continue_line:
71                 self.lines[-1] += node.text
72             else:
73                 self.lines.append(node.text)
74         self.generic_visit(node)
75         self.lines.append('')
76         self.continue_line = False
77
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')
86
87             # merge content to the built doc
88             if self.continue_line:
89                 self.lines[-1] += lines[0]
90                 lines = lines[1:]
91             for l in lines:
92                 self.lines.append('')
93                 self.lines.append(l)
94         self.generic_visit(node)
95         self.lines.append('')
96         self.continue_line = False
97
98     def visit_parametername(self, node):
99         if 'direction' in node.attrib:
100             direction = '[%s] ' % node.get('direction')
101         else:
102             direction = ''
103
104         self.lines.append('**%s** -- %s' % (
105             node.text, direction))
106         self.continue_line = True
107
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] + [''])
111
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)
117
118     def visit_listitem(self, node):
119         self.lines.append('   - ')
120         self.continue_line = True
121         self.generic_visit(node)
122
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)
129
130         lines = ''.join(segment).split('\n')
131         self.lines.extend(('.. code-block:: C++', ''))
132         self.lines.extend(['  ' + l for l in lines])
133
134     def visit_computeroutput(self, node):
135         c = node.find('preformatted')
136         if c is not None:
137             return self.visit_preformatted(c)
138         return self.visit_preformatted(node)
139
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])
144         else:
145             raise ValueError(node)
146
147     def visit_subscript(self, node):
148         self.lines[-1] += '\ :sub:`%s` %s' % (node.text, node.tail)
149