1#!/usr/local/bin/python3.8
2# coding: utf-8
3# Dear future self,
4#
5# You're looking at this file because
6# the parse function finally broke.
7#
8# It's not fixable. You have to rewrite it.
9# Sincerely, past self
10#
11# Also, it's probably at least
12# 2013. Did you ever take
13# that trip to Iceland?
14
15import re
16
17def get_type_link(typ, file):
18    from gen_doc import objects
19
20    if typ == '':
21        return "void"
22    else:
23        if typ in objects:
24            return "cinnamon-js-" + objects[typ].prefix
25        elif file.name + "." + typ in objects:
26            return "cinnamon-js-" + objects[file.name + "." + typ].prefix
27        elif typ.endswith("s") and typ[:-1] in objects:
28            return "cinnamon-js-" + objects[typ[:-1]].prefix
29        elif typ.endswith("s") and file.name + "." + typ[:-1] in objects:
30            return "cinnamon-js-" + objects[file.name + "." + typ[:-1]].prefix
31        elif typ.startswith("Gio"):
32            return typ.replace("Gio.", "G")
33        elif typ.startswith("GLib"):
34            return typ.replace("GLib.", "G")
35        else:
36            return typ.replace('.', '')
37
38def markup(line, obj):
39    line = re.sub('@(\w*)', '<code>\g<1></code>', line)
40    line = re.sub('`([^`]*)`', '<code>\g<1></code>', line)
41    line = re.sub('\*\*([^*]*)\*\*', '<emphasis role="strong">\g<1></emphasis>', line)
42    line = re.sub('\*([^*]*)\*', '<emphasis>\g<1></emphasis>', line)
43
44    def format_type_link(match):
45        res = match.group(1)
46        return '<link linkend="{link}"><code>{name}</code></link>'.format(
47            link = get_type_link(res, obj.file),
48            name = res)
49
50    line = re.sub('#(([\w]*\.)?[\w]+)', format_type_link, line)
51
52    def format_ext_link(match):
53        if match.group(1):
54            full = match.group(1) + match.group(3)
55        else:
56            full = match.group(3)
57
58        if match.group(4):
59            full += match.group(4)
60
61        owner = match.group(1)
62        if owner:
63            owner = owner[:-1] # remove trailing .
64        else:
65            owner = "this"
66
67        thing = match.group(3)
68
69        from gen_doc import objects
70
71        object = None
72        if owner == "this":
73            object = obj.object
74        if owner in objects:
75            object = objects[owner]
76        elif obj.file.name + "." + owner in objects:
77            object = objects[obj.file.name + "." +  owner]
78
79        if object is None:
80            return '<code>{name}</code>'.format(name = full)
81
82        func_names = [x.name for x in object.functions]
83        enum_names = [x.name for x in object.enums]
84        prop_names = [x.name for x in object.properties]
85
86        if thing in prop_names and not full.endswith("()"):
87            return '<link linkend="cinnamon-js-{prefix}--{thing}"><code>{full}</code></link>'.format(
88                prefix = object.prefix,
89                thing = thing,
90                full = full)
91        elif thing in func_names or (thing in enum_names and not full.endswith("()")):
92            return '<link linkend="cinnamon-js-{prefix}-{thing}"><code>{full}</code></link>'.format(
93                prefix = object.prefix,
94                thing = thing,
95                full = full)
96        else:
97            return '<code>{name}</code>'.format(name = full)
98
99    line = re.sub('%(([\w]+\.)?[\w]+\.)?([\w]+)(\(\))?', format_ext_link, line)
100
101    return line
102
103class JSThing():
104    def append_description(self, desc):
105        self.description += desc.replace('<', '&lt;').replace('>', '&gt;')
106
107    def get_xml_description(self, description = None):
108        if description is None:
109            description = self.description
110
111        stuff = description.split('\n')
112        joined = ['']
113
114        in_code = False
115        in_list = False
116
117        for line in stuff:
118            if line.strip() == '```':
119                if in_code:
120                    joined[-1] += '```'
121                    joined.append('')
122                else:
123                    if in_list:
124                        joined[-1] += '\n```'
125                    else:
126                        joined.append('```\n')
127                in_code = not in_code
128                continue
129
130            if in_code:
131                joined[-1] += '\n' + line
132                continue
133
134            line = line.strip()
135            if line == '\\' and in_list:
136                joined[-1] += '\n\n'
137            elif len(line) == 0 or line == '\\':
138                # New line if empty
139                joined.append('')
140                in_list = False
141            else:
142                if joined[-1] == '' and line.startswith('- '):
143                    in_list = True
144                if line.startswith('- '):
145                    joined.append('')
146
147                joined[-1] += ' ' + line
148
149        description = ''
150        in_list = False
151
152        list_buffer = []
153        for line in joined:
154            if line.split('\n')[0].strip() == '```':
155                description += '<informalexample><programlisting>{0}</programlisting></informalexample>'\
156                    .format(line.replace('```', ''))
157                continue
158
159            if line == '':
160                continue
161
162            line = line.strip()
163            if line.startswith('-'):
164                in_list = True
165                list_buffer.append(self.get_xml_description(line[1:]))
166                continue
167
168            if in_list:
169                description += '<itemizedlist>' + \
170                    '\n'.join('<listitem>{0}</listitem>'.format(item) for item in list_buffer) + \
171                    '</itemizedlist>'
172                list_buffer = []
173                in_list = False
174
175            line = markup(line, self)
176            description += '<para>{0}</para>'.format(line)
177
178        if in_list:
179            description += '<itemizedlist>' + \
180                '\n'.join('<listitem>{0}</listitem>'.format(item) for item in list_buffer) + \
181                '</itemizedlist>'
182            list_buffer = []
183
184        return description
185
186    def add_property(self, prop):
187        if prop.name == "short_description":
188            self.short_description = prop
189        else:
190            self.properties.append(prop)
191        prop.file = self.file
192        prop.object = self.object
193
194class JSSignal(JSThing):
195    def __init__ (self, name):
196        self.name = name
197        self.description = ''
198        self.short_description = JSProperty(None, '', '')
199        self.properties = []
200
201class JSFunction(JSThing):
202    def __init__ (self, name):
203        self.name = name
204        self.description = ''
205        self.short_description = JSProperty(None, '', '')
206        self.properties = []
207        self.return_value = JSProperty(None, '', '')
208
209    def set_return(self, retval):
210        self.return_value = retval
211        retval.file = self.file
212        retval.obj = self.object
213
214class JSProperty(JSThing):
215    def __init__ (self, name, arg_type, desc):
216        self.name = name
217        self.arg_type = arg_type if arg_type else ''
218        self.description = ''
219        self.append_description(desc + "\n")
220
221class JSFile(JSThing):
222    def __init__ (self, directory, name):
223        self.directory = directory
224        self.name = name[0].capitalize() + name[1:]
225        self.orig_name = self.name
226        self.imports = "imports.{0}.{1}".format(directory, name)
227        self.prefix = directory + "-" + name
228        self.description = ''
229        self.short_description = JSProperty(None, '', '')
230        self.properties = []
231        self.objects = []
232        self.signals = []
233        self.enums = []
234        self.functions = []
235        self.file = self
236        self.object = self
237
238    def is_interesting(self):
239        return len(self.functions) + len(self.properties) + len(self.description) > 0
240
241    def add_function(self, func):
242        self.functions.append(func)
243        func.file = self
244        func.object = self
245
246    def add_object(self, obj):
247        self.objects.append(obj)
248        obj.parent = self
249        obj.directory = self.directory
250        obj.prefix = self.prefix + "-" + obj.name
251        obj.name = self.name + "-" + obj.name
252        obj.file = self
253
254    def add_enum(self, obj):
255        self.enums.append(obj)
256        obj.parent = self
257        obj.directory = self.directory
258        obj.prefix = self.prefix + "-" + obj.name
259        obj.file = self
260
261class JSObject(JSThing):
262    def __init__ (self, name):
263        self.name = name
264        self.orig_name = name
265        self.inherit = ''
266        self.description = ''
267        self.short_description = JSProperty(None, '', '')
268        self.parent = None
269        self.directory = None
270        self.prefix = None
271        self.functions = []
272        self.properties = []
273        self.signals = []
274        self.enums = []
275        self.object = self
276
277    def add_function(self, func):
278        self.functions.append(func)
279        func.file = self.file
280        func.object = self
281
282    def add_signal(self, signal):
283        self.signals.append(signal)
284        signal.file = self
285        signal.object = self
286
287    def set_inherit(self, inherit):
288        self.inherit = inherit
289
290class JSEnum(JSThing):
291    def __init__ (self, name):
292        self.name = name
293        self.description = ''
294        self.short_description = JSProperty(None, '', '')
295        self.properties = []
296        self.object = self
297
298PART_FORMAT = '''\
299<?xml version='1.0'?>
300<!DOCTYPE book PUBLIC '-//OASIS//DTD DocBook XML V4.3//EN'
301               'http://www.oasis-open.org/docbook/xml/4.3/docbookx.dtd'
302[
303  <!ENTITY % local.common.attrib "xmlns:xi  CDATA  #FIXED 'http://www.w3.org/2003/XInclude'">
304]>
305<part label="imports.{title}">
306  {chapters}
307</part>'''
308
309SGML_CHAPTER_FORMAT = '''
310<chapter id="cinnamon-js-{prefix}-section">
311  <title>{title}</title>
312  {entries}
313</chapter>'''
314
315SGML_ENTRY_FORMAT = '<xi:include href="{directory}/{name}.xml"/>'
316
317FILE_FORMAT = '''\
318<!DOCTYPE refentry PUBLIC '-//OASIS//DTD DocBook XML V4.3//EN'
319'http://www.oasis-open.org/docbook/xml/4.3/docbookx.dtd'
320[
321<!ENTITY % local.common.attrib "xmlns:xi  CDATA  #FIXED 'http://www.w3.org/2003/XInclude'">
322]>
323<refentry id="cinnamon-js-{prefix}">
324  <refmeta>
325    <refentrytitle role="top_of_page" id="cinnamon-js-{prefix}.top_of_page">{name}</refentrytitle>
326    <manvolnum>3</manvolnum>
327    <refmiscinfo>
328      {name}
329    </refmiscinfo>
330  </refmeta>
331  <refnamediv>
332    <refname>{name}</refname>
333    <refpurpose>{short_description}</refpurpose>
334  </refnamediv>
335  {func_header}
336  {prop_header}
337  {signal_header}
338  {enum_header}
339  {hierarchy}
340  {description}
341  {functions}
342  {properties}
343  {signals}
344  {enums}
345</refentry>
346'''
347
348FUNCTION_HEADER_FORMAT = '''
349<refsect1 id="cinnamon-js-{prefix}.functions" role="functions_proto">
350  <title role="functions_proto.title">Functions</title>
351  <informaltable pgwide="1" frame="none">
352    <tgroup cols="2">
353      <colspec colname="functions_return" colwidth="150px"/>
354      <colspec colname="functions_name"/>
355      <tbody>
356        {function_headers}
357      </tbody>
358    </tgroup>
359  </informaltable>
360</refsect1>
361'''
362
363FUNCTION_HEADER_ITEM_FORMAT = '''
364<row>
365  <entry role="function_type">
366    <link linkend="{return_link}">
367      <returnvalue>{return_name}</returnvalue>
368    </link>
369  </entry>
370  <entry role="function_name">
371    <link linkend="cinnamon-js-{prefix}-{name}">{name}</link>&#160;<phrase role="c_punctuation">()</phrase>
372  </entry>
373</row>
374'''
375
376PROPERTY_HEADER_FORMAT = '''
377<refsect1 id="cinnamon-js-{prefix}.properties" role="properties">
378  <title role="properties.title">Properties</title>
379  <informaltable frame="none">
380    <tgroup cols="3">
381      <colspec colname="properties_type" colwidth="150px"/>
382      <colspec colname="properties_name" colwidth="300px"/>
383      <tbody>
384        {property_headers}
385      </tbody>
386    </tgroup>
387  </informaltable>
388</refsect1>
389'''
390
391SIGNAL_HEADER_FORMAT = '''
392<refsect1 id="cinnamon-js-{prefix}.signals" role="signal_proto">
393  <title role="signal_proto.title">Signals</title>
394  <informaltable frame="none">
395    <tgroup cols="3">
396      <colspec colname="signals_return" colwidth="150px" />
397      <colspec colname="signals_name" colwidth="300px" />
398      <tbody>
399        {signal_headers}
400      </tbody>
401    </tgroup>
402  </informaltable>
403</refsect1>
404'''
405
406SIGNAL_HEADER_ITEM_FORMAT = '''
407<row>
408  <entry role="signal_type">
409  </entry>
410  <entry role="signal_name">
411    <link linkend="cinnamon-js-{prefix}-{name}-signal">{name}</link>
412  </entry>
413</row>
414'''
415
416ENUM_HEADER_FORMAT = '''
417<refsect1 id="cinnamon-js-{prefix}.other" role="other_proto">
418  <title role="other_proto.title">Types and Values</title>
419  <informaltable role="enum_members_table" pgwide="1" frame="none">
420    <tgroup cols="2">
421      <colspec colname="name" colwidth="150px"/>
422      <colspec colname="description"/>
423      <tbody>
424        {enum_headers}
425      </tbody>
426    </tgroup>
427  </informaltable>
428</refsect1>
429'''
430
431ENUM_HEADER_ITEM_FORMAT = '''
432<row>
433  <entry role="datatype_keyword">enum</entry>
434  <entry role="function_name">
435    <link linkend="cinnamon-js-{prefix}-{name}">{name}</link>
436  </entry>
437</row>
438'''
439
440PROPERTY_HEADER_ITEM_FORMAT = '''
441<row>
442  <entry role="property_type">
443    <link linkend="{type_link}"><type>{type_name}</type></link>
444  </entry>
445  <entry role="property_name">
446    <link linkend="cinnamon-js-{prefix}--{name}">{name}</link>
447  </entry>
448</row>
449'''
450
451HIERARCHY_FORMAT = '''
452<refsect1 id="cinnamon-js-{prefix}.object-hierarchy" role="object_hierarchy">
453  <title role="object_hierarchy.title">Object Hierarchy</title>
454  <screen>
455    <link linkend="Object">Object</link>
456{hierarchy}
457  </screen>
458</refsect1>
459'''
460
461HIERARCHY_ITEM_FORMAT = '{spacing}<phrase role="lineart">&#9584;&#9472;&#9472;</phrase> <link linkend="cinnamon-js-{prefix}">{name}</link>'
462
463DESCRIPTION_FORMAT = '''
464<refsect1 id="cinnamon-js-{prefix}.description" role="desc">
465  <title role="desc.title">Description</title>
466  {description}
467</refsect1>
468'''
469
470FUNCTIONS_FORMAT = '''
471<refsect1 id="cinnamon-js-{prefix}.functions_details" role="details">
472  <title role="details.title">Functions</title>
473  {functions}
474</refsect1>
475'''
476
477FUNCTION_ITEM_FORMAT = '''
478<refsect2 id="cinnamon-js-{prefix}-{name}" role="function">
479  <title>{name}&#160;()</title>
480  <indexterm zone="cinnamon-js-{prefix}-{name}"><primary>{name}</primary></indexterm>
481  <programlisting language="javascript">
482<link linkend="{return_link}"><returnvalue>{return_type}</returnvalue></link>
483{name} ({inline_params});</programlisting>
484  {description}
485  {params}
486  {return_desc}
487</refsect2>
488'''
489
490SIGNALS_FORMAT = '''
491<refsect1 id="cinnamon-js-{prefix}.signal-details" role="details">
492  <title role="details.title">Signal details</title>
493  {signals}
494</refsect1>
495'''
496
497SIGNAL_ITEM_FORMAT = '''
498<refsect2 id="cinnamon-js-{prefix}-{name}-signal" role="signal">
499  <title>The <literal>“{name}”</literal> signal</title>
500  <indexterm zone="cinnamon-js-{prefix}-{name}-signal"><primary>{prefix}::{name}</primary></indexterm>
501  <programlisting language="javascript">
502user_function ({inline_params});</programlisting>
503  {description}
504  {params}
505</refsect2>
506'''
507
508FUNC_PARAMETERS_FORMAT = '''
509<refsect3 role="parameters">
510  <title>Parameters</title>
511  <informaltable role="parameters_table" pgwide="1" frame="none">
512    <tgroup cols="3">
513      <colspec colname="parameters_name" colwidth="150px"/>
514      <colspec colname="parameters_description"/>
515      <colspec colname="parameters_annotations" colwidth="200px"/>
516      <tbody>
517        {param_items}
518      </tbody>
519    </tgroup>
520  </informaltable>
521</refsect3>
522'''
523
524INLINE_PARAMETER_FORMAT = '<parameter><link linkend="{type_link}"><type>{type_name}</type></link>{name}</parameter>'
525
526FUNC_PARAMETERS_ITEM_FORMAT = '''
527<row>
528  <entry role="parameter_name"><para>{name}</para></entry>
529  <entry role="parameter_description">{description}</entry>
530  <entry role="parameter_annotations"></entry>
531</row>
532'''
533
534FUNC_RETURN_FORMAT = '''
535<refsect3 role="returns">
536  <title>Returns</title>
537  {desc}
538</refsect3>
539'''
540
541PROPERTIES_FORMAT = '''
542<refsect1 id="cinnamon-js-{prefix}.property-details" role="property_details">
543  <title role="property_details.title">Property Details</title>
544  {properties}
545</refsect1>
546'''
547
548PROPERTIES_ITEM_FORMAT = '''
549<refsect2 id="cinnamon-js-{prefix}--{name}" role="property">
550  <title>The <literal>“{name}”</literal> property</title>
551  <indexterm zone="cinnamon-js-{prefix}--{name}">
552    <primary>cinnamon-js-{prefix}:{name}</primary>
553  </indexterm>
554  <programlisting>  {disp_name}  <link linkend="{type_link}"><type>{type_name}</type></link></programlisting>
555  {description}
556</refsect2>
557'''
558
559ENUMS_FORMAT = '''
560<refsect1 id="CinnamonGlobal.other_details" role="details">
561  <title role="details.title">Types and Values</title>
562  {enums}
563</refsect1>
564'''
565
566ENUMS_ITEM_FORMAT = '''
567<refsect2 id="cinnamon-js-{prefix}" role="enum">
568  <title>enum {name}</title>
569  <indexterm zone="{name}"><primary>{name}</primary></indexterm>
570  {description}
571  <refsect3 role="enum_members">
572    <title>Members</title>
573    <informaltable role="enum_members_table" pgwide="1" frame="none">
574      <tgroup cols="2">
575        <colspec colname="enum_members_name" colwidth="300px"/>
576        <colspec colname="enum_members_description"/>
577        <tbody>
578          {enum_items}
579        </tbody>
580      </tgroup>
581    </informaltable>
582  </refsect3>
583</refsect2>
584'''
585
586ENUMS_ITEM_ROW_FORMAT = '''
587<row role="constant">
588  <entry role="enum_member_name"><para id="{name}:CAPS">{name}</para></entry>
589  <entry role="enum_member_description">{description}</entry>
590</row>
591'''
592
593def write_chapters_file(files):
594    chapters = {'ui': [], 'misc': []}
595
596    for _file in files:
597        if not _file.is_interesting() and len(_file.objects) == 0:
598            continue
599
600        entries = []
601        if _file.is_interesting():
602            _file.objects.insert(0, _file)
603
604        entries = [SGML_ENTRY_FORMAT.format(
605            directory = _file.directory,
606            name = obj.name) for obj in _file.objects]
607
608        chapters[_file.directory].append(SGML_CHAPTER_FORMAT.format(
609            prefix = _file.prefix,
610            title = _file.imports,
611            entries = "\n".join(entries)))
612
613    for directory, formatted_chapters in chapters.items():
614        with open(directory + '.xml', 'w') as part_file:
615            part_file.write(PART_FORMAT.format(title=directory, chapters="\n".join(formatted_chapters)))
616
617def create_file(obj):
618    file_obj = open('{0}/{1}.xml'.format(obj.directory, obj.name), 'w', encoding="utf-8")
619    short_description = obj.short_description.description.replace("\n", " ").strip()
620    file_obj.write(FILE_FORMAT.format(
621        prefix = obj.prefix,
622        name = obj.name.replace("-", "."),
623        short_description = markup(short_description, obj),
624        func_header = get_function_header(obj),
625        signal_header = get_signal_header(obj),
626        prop_header = get_properties_header(obj),
627        enum_header = get_enum_header(obj),
628        hierarchy = get_hierarchy(obj),
629        description = get_description(obj),
630        functions = get_functions(obj),
631        signals = get_signals(obj),
632        properties = get_properties(obj),
633        enums = get_enums(obj)))
634
635    file_obj.close()
636
637def get_function_header(obj):
638    if len(obj.functions) == 0:
639        return ""
640
641    functions = [FUNCTION_HEADER_ITEM_FORMAT.format(
642        return_link = get_type_link(func.return_value.arg_type, obj.file),
643        return_name = func.return_value.arg_type,
644        prefix = obj.prefix,
645        name = func.name) for func in obj.functions]
646
647    return FUNCTION_HEADER_FORMAT.format(
648        prefix = obj.prefix,
649        function_headers = "\n".join(functions))
650
651def get_signal_header(obj):
652    if len(obj.signals) == 0:
653        return ""
654
655    signals = [SIGNAL_HEADER_ITEM_FORMAT.format(
656               prefix = obj.prefix,
657               name = sig.name) for sig in obj.signals]
658
659    return SIGNAL_HEADER_FORMAT.format(
660        prefix = obj.prefix,
661        signal_headers = "\n".join(signals))
662
663def get_properties_header(obj):
664    if len(obj.properties) == 0:
665        return ""
666
667    properties = [PROPERTY_HEADER_ITEM_FORMAT.format(
668        type_link = get_type_link(prop.arg_type, obj.file),
669        type_name = prop.arg_type,
670        prefix = obj.prefix,
671        name = prop.name) for prop in obj.properties]
672
673    return PROPERTY_HEADER_FORMAT.format(
674        prefix = obj.prefix,
675        property_headers = "\n".join(properties))
676
677def get_enum_header(obj):
678    if len(obj.enums) == 0:
679        return ""
680
681    enums = [ENUM_HEADER_ITEM_FORMAT.format(
682        prefix = obj.prefix,
683        name = enum.name) for enum in obj.enums]
684
685    return ENUM_HEADER_FORMAT.format(
686        prefix = obj.prefix,
687        enum_headers = "\n".join(enums))
688
689
690def get_hierarchy(obj):
691    from gen_doc import objects
692
693    if isinstance(obj, JSFile):
694        return ""
695
696
697    name = obj.name.replace('-', '.')
698    hierarchy = []
699    try:
700        while True:
701            name = objects[name].inherit
702            if name in hierarchy:
703                break
704            if name:
705                hierarchy.insert(0, name)
706    except KeyError:
707        pass
708
709    count = 1
710    hierarchy_strs = []
711    for item in hierarchy:
712        try:
713            hierarchy_strs.append(HIERARCHY_ITEM_FORMAT.format(
714                spacing = ' ' * count * 4,
715                prefix = objects[item].prefix,
716                name = item))
717        except KeyError:
718            hierarchy_strs.append(HIERARCHY_ITEM_FORMAT.format(
719                spacing = ' ' * count * 4,
720                prefix = "void",
721                name = item))
722        count += 1
723
724    hierarchy_strs.append(HIERARCHY_ITEM_FORMAT.format(
725        spacing = ' ' * count * 4,
726        prefix = "void",
727        name = obj.name.replace('-', '.')))
728
729    return HIERARCHY_FORMAT.format(
730        prefix = obj.prefix,
731        hierarchy = "\n".join(hierarchy_strs))
732
733def get_description(obj):
734    if len(obj.description) == 0:
735        return ""
736
737    return DESCRIPTION_FORMAT.format(
738        prefix=obj.prefix,
739        description = obj.get_xml_description())
740
741def get_functions(obj):
742    if len(obj.functions) == 0:
743        return ""
744
745    functions = []
746
747    for func in obj.functions:
748        inline_params = ""
749        params = ""
750        if len(func.properties) > 0:
751            # Calculate how long the argument types are and make the arguments
752            # align
753            max_length = max(len(x.arg_type) for x in func.properties) + 3
754            # If no parameter has argument types, don't show that silly
755            # whitespace
756            if max_length == 3:
757                max_length = 0
758
759            inline_params = [INLINE_PARAMETER_FORMAT.format(
760                type_link = get_type_link(param.arg_type, obj.file),
761                type_name = param.arg_type,
762                name = " " * (max_length - len(param.arg_type)) + param.name) for param in func.properties]
763
764            inline_params = (',\n' + ' ' * (len(func.name) + 2)).join(inline_params)
765
766            params = [FUNC_PARAMETERS_ITEM_FORMAT.format(
767                name = param.name,
768                description = param.get_xml_description()) for param in func.properties]
769
770            params = FUNC_PARAMETERS_FORMAT.format(param_items = '\n'.join(params))
771
772        return_desc = ""
773        if func.return_value.name is not None:
774            return_desc = FUNC_RETURN_FORMAT.format(desc=func.return_value.get_xml_description())
775
776        functions.append(FUNCTION_ITEM_FORMAT.format(
777            prefix = obj.prefix,
778            name = func.name,
779            return_link = get_type_link(func.return_value.arg_type, obj.file),
780            return_type = func.return_value.arg_type,
781            description = func.get_xml_description(),
782            inline_params = inline_params,
783            params = params,
784            return_desc = return_desc))
785
786    return FUNCTIONS_FORMAT.format(
787        prefix = obj.prefix,
788        functions = "\n".join(functions))
789
790def get_signals(obj):
791    if len(obj.signals) == 0:
792        return ""
793
794    signals = []
795
796    for sig in obj.signals:
797        inline_params = ""
798        params = ""
799        if len(sig.properties) > 0:
800            # Calculate how long the argument types are and make the arguments
801            # align
802            max_length = max(len(x.arg_type) for x in sig.properties) + 3
803            # If no parameter has argument types, don't show that silly
804            # whitespace
805            if max_length == 3:
806                max_length = 0
807
808            inline_params = [INLINE_PARAMETER_FORMAT.format(
809                type_link = get_type_link(param.arg_type, obj.file),
810                type_name = param.arg_type,
811                name = " " * (max_length - len(param.arg_type)) + param.name) for param in sig.properties]
812
813            inline_params = (',\n' + ' ' * (len(sig.name) + 2)).join(inline_params)
814
815            params = [FUNC_PARAMETERS_ITEM_FORMAT.format(
816                name = param.name,
817                description = param.get_xml_description()) for param in sig.properties]
818
819            params = FUNC_PARAMETERS_FORMAT.format(param_items = '\n'.join(params))
820
821        signals.append(SIGNAL_ITEM_FORMAT.format(
822            prefix = obj.prefix,
823            name = sig.name,
824            description = sig.get_xml_description(),
825            inline_params = inline_params,
826            params = params))
827
828    return SIGNALS_FORMAT.format(
829        prefix = obj.prefix,
830        signals = "\n".join(signals))
831
832
833def get_properties(obj):
834    if len(obj.properties) == 0:
835        return ""
836
837    properties = [PROPERTIES_ITEM_FORMAT.format(
838        prefix = obj.prefix,
839        name = prop.name,
840        disp_name = ('“' + prop.name + '”').ljust(25),
841        type_link = get_type_link(prop.arg_type, obj.file),
842        type_name = prop.arg_type,
843        description = prop.get_xml_description()) for prop in obj.properties]
844
845    return PROPERTIES_FORMAT.format(
846        prefix = obj.prefix,
847        properties = "\n".join(properties))
848
849def get_enums(obj):
850    if len(obj.enums) == 0:
851        return ""
852
853    enums = []
854
855    for enum in obj.enums:
856        items = [ENUMS_ITEM_ROW_FORMAT.format(
857            name = item.name,
858            description = item.get_xml_description()) for item in enum.properties]
859
860        enums.append(ENUMS_ITEM_FORMAT.format(
861            prefix = enum.prefix,
862            name = enum.name,
863            description = enum.get_xml_description(),
864            enum_items = "\n".join(items)))
865
866    return ENUMS_FORMAT.format(
867        prefix = obj.prefix,
868        enums = "\n".join(enums))
869