diff --git a/docs/docs_writer.py b/docs/docs_writer.py new file mode 100644 index 00000000..4e35718e --- /dev/null +++ b/docs/docs_writer.py @@ -0,0 +1,224 @@ +import os + + +class DocsWriter: + """Utility class used to write the HTML files used on the documentation""" + def __init__(self, filename, type_to_path_function): + """Initializes the writer to the specified output file, + creating the parent directories when used if required. + + 'type_to_path_function' should be a function which, given a type name + and a named argument relative_to, returns the file path for the specified + type, relative to the given filename""" + self.filename = filename + self.handle = None + + # Should be set before calling adding items to the menu + self.menu_separator_tag = None + + # Utility functions TODO There must be a better way + self.type_to_path = lambda t: type_to_path_function(t, relative_to=self.filename) + + # Control signals + self.menu_began = False + self.table_columns = 0 + self.table_columns_left = None + + # High level writing + def write_head(self, title, relative_css_path): + """Writes the head part for the generated document, with the given title and CSS""" + self.write(''' + + + + ''') + + self.write(title) + + self.write(''' + + + + + +
''') + + def set_menu_separator(self, relative_image_path): + """Sets the menu separator. Must be called before adding entries to the menu""" + if relative_image_path: + self.menu_separator_tag = '/' % relative_image_path + else: + self.menu_separator_tag = None + + def add_menu(self, name, link=None): + """Adds a menu entry, will create it if it doesn't exist yet""" + if self.menu_began: + if self.menu_separator_tag: + self.write(self.menu_separator_tag) + else: + # First time, create the menu tag + self.write('') + + def write_title(self, title, level=1): + """Writes a title header in the document body, with an optional depth level""" + self.write('' % level) + self.write(title) + self.write('' % level) + + def write_code(self, tlobject): + """Writes the code for the given 'tlobject' properly formatted ith with hyperlinks""" + self.write('
---')
+        self.write('functions' if tlobject.is_function else 'types')
+        self.write('---\n')
+
+        # Write the function or type and its ID
+        if tlobject.namespace:
+            self.write(tlobject.namespace)
+            self.write('.')
+
+        self.write(tlobject.name)
+        self.write('#')
+        self.write(hex(tlobject.id)[2:].rjust(8, '0'))
+
+        # Write all the arguments (or do nothing if there's none)
+        for arg in tlobject.args:
+            self.write(' ')
+
+            # "Opening" modifiers
+            if arg.generic_definition:
+                self.write('{')
+
+            # Argument name
+            self.write(arg.name)
+            self.write(':')
+
+            # "Opening" modifiers
+            if arg.is_flag:
+                self.write('flags.%d?' % arg.flag_index)
+
+            if arg.is_generic:
+                self.write('!')
+
+            if arg.is_vector:
+                self.write('Vector<' % self.type_to_path('vector'))
+
+            # Argument type
+            if arg.type:
+                self.write('%s' % arg.type)
+            else:
+                self.write('#')
+
+            # "Closing" modifiers
+            if arg.is_vector:
+                self.write('>')
+
+            if arg.generic_definition:
+                self.write('}')
+
+        # Now write the resulting type (result from a function, or type for a constructor)
+        self.write(' = %s' % tlobject.result)
+
+        self.write('
') + + def begin_table(self, column_count): + """Begins a table with the given 'column_count', required to automatically + create the right amount of columns when adding items to the rows""" + self.table_columns = column_count + self.table_columns_left = 0 + self.write('') + + def add_row(self, text, link=None, bold=False, align=None): + """This will create a new row, or add text to the next column + of the previously created, incomplete row, closing it if complete""" + if not self.table_columns_left: + # Starting a new row + self.write('') + self.table_columns_left = self.table_columns + + self.write('') + + if bold: + self.write('') + if link: + self.write('') + + # Finally write the real table data, the given text + self.write(text) + + if link: + self.write('') + if bold: + self.write('') + + self.write('') + + self.table_columns_left -= 1 + if not self.table_columns_left: + self.write('') + + def end_table(self): + # If there was any column left, finish it before closing the table + if self.table_columns_left: + self.write('') + + self.write('
') + + def write_text(self, text): + """Writes a paragraph of text""" + self.write('

') + self.write(text) + self.write('

') + + def end_body(self): + """Ends the whole document. This should be called the last""" + self.write('
') + + # "Low" level writing + def write(self, s): + """Wrapper around handle.write""" + self.handle.write(s) + + # With block + def __enter__(self): + # Sanity check + os.makedirs(os.path.dirname(self.filename), exist_ok=True) + self.handle = open(self.filename, 'w', encoding='utf-8') + return self + + def __exit__(self, exc_type, exc_val, exc_tb): + self.handle.close()