diff options
Diffstat (limited to 'doc/tools/make_rst.py')
-rwxr-xr-x | doc/tools/make_rst.py | 96 |
1 files changed, 85 insertions, 11 deletions
diff --git a/doc/tools/make_rst.py b/doc/tools/make_rst.py index ce09361dfa..2aa4cb8ec1 100755 --- a/doc/tools/make_rst.py +++ b/doc/tools/make_rst.py @@ -10,6 +10,11 @@ import sys import xml.etree.ElementTree as ET from collections import OrderedDict +# Import hardcoded version information from version.py +root_directory = os.path.join(os.path.dirname(os.path.abspath(__file__)), "../../") +sys.path.append(root_directory) # Include the root directory +import version + # Uncomment to do type checks. I have it commented out so it works below Python 3.5 # from typing import List, Dict, TextIO, Tuple, Iterable, Optional, DefaultDict, Any, Union @@ -36,6 +41,7 @@ BASE_STRINGS = [ "Signals", "Enumerations", "Constants", + "Annotations", "Property Descriptions", "Constructor Descriptions", "Method Descriptions", @@ -122,16 +128,18 @@ class MethodDef: class ConstantDef: - def __init__(self, name, value, text): # type: (str, str, Optional[str]) -> None + def __init__(self, name, value, text, bitfield): # type: (str, str, Optional[str], Optional[bool]) -> None self.name = name self.value = value self.text = text + self.is_bitfield = bitfield class EnumDef: - def __init__(self, name): # type: (str) -> None + def __init__(self, name, bitfield): # type: (str, Optional[bool]) -> None self.name = name self.values = OrderedDict() # type: OrderedDict[str, ConstantDef] + self.is_bitfield = bitfield class ThemeItemDef: @@ -155,6 +163,7 @@ class ClassDef: self.methods = OrderedDict() # type: OrderedDict[str, List[MethodDef]] self.operators = OrderedDict() # type: OrderedDict[str, List[MethodDef]] self.signals = OrderedDict() # type: OrderedDict[str, SignalDef] + self.annotations = OrderedDict() # type: OrderedDict[str, List[MethodDef]] self.theme_items = OrderedDict() # type: OrderedDict[str, ThemeItemDef] self.inherits = None # type: Optional[str] self.brief_description = None # type: Optional[str] @@ -305,7 +314,8 @@ class State: constant_name = constant.attrib["name"] value = constant.attrib["value"] enum = constant.get("enum") - constant_def = ConstantDef(constant_name, value, constant.text) + is_bitfield = constant.get("is_bitfield") or False + constant_def = ConstantDef(constant_name, value, constant.text, is_bitfield) if enum is None: if constant_name in class_def.constants: print_error('{}.xml: Duplicate constant "{}".'.format(class_name, constant_name), self) @@ -318,11 +328,32 @@ class State: enum_def = class_def.enums[enum] else: - enum_def = EnumDef(enum) + enum_def = EnumDef(enum, is_bitfield) class_def.enums[enum] = enum_def enum_def.values[constant_name] = constant_def + annotations = class_root.find("annotations") + if annotations is not None: + for annotation in annotations: + assert annotation.tag == "annotation" + + annotation_name = annotation.attrib["name"] + qualifiers = annotation.get("qualifiers") + + params = parse_arguments(annotation) + + desc_element = annotation.find("description") + annotation_desc = None + if desc_element is not None: + annotation_desc = desc_element.text + + annotation_def = MethodDef(annotation_name, return_type, params, annotation_desc, qualifiers) + if annotation_name not in class_def.annotations: + class_def.annotations[annotation_name] = [] + + class_def.annotations[annotation_name].append(annotation_def) + signals = class_root.find("signals") if signals is not None: for signal in signals: @@ -561,12 +592,26 @@ def make_rst_class(class_def, state, dry_run, output_dir): # type: (ClassDef, S else: f = open(os.path.join(output_dir, "class_" + class_name.lower() + ".rst"), "w", encoding="utf-8") - # Warn contributors not to edit this file directly + # Remove the "Edit on Github" button from the online docs page. f.write(":github_url: hide\n\n") - f.write(".. Generated automatically by doc/tools/make_rst.py in Godot's source tree.\n") - f.write(".. DO NOT EDIT THIS FILE, but the " + class_name + ".xml source instead.\n") - f.write(".. The source is found in doc/classes or modules/<name>/doc_classes.\n\n") + # Warn contributors not to edit this file directly. + # Also provide links to the source files for reference. + + git_branch = "master" + if hasattr(version, "docs") and version.docs != "latest": + git_branch = version.docs + + source_xml_path = os.path.relpath(class_def.filepath, root_directory).replace("\\", "/") + source_github_url = "https://github.com/godotengine/godot/tree/{}/{}".format(git_branch, source_xml_path) + generator_github_url = "https://github.com/godotengine/godot/tree/{}/doc/tools/make_rst.py".format(git_branch) + + f.write(".. DO NOT EDIT THIS FILE!!!\n") + f.write(".. Generated automatically from Godot engine sources.\n") + f.write(".. Generator: " + generator_github_url + ".\n") + f.write(".. XML source: " + source_github_url + ".\n\n") + + # Document reference id and header. f.write(".. _class_" + class_name + ":\n\n") f.write(make_heading(class_name, "=", False)) @@ -706,7 +751,11 @@ def make_rst_class(class_def, state, dry_run, output_dir): # type: (ClassDef, S for value in e.values.values(): f.write(".. _class_{}_constant_{}:\n\n".format(class_name, value.name)) - f.write("enum **{}**:\n\n".format(e.name)) + if e.is_bitfield: + f.write("flags **{}**:\n\n".format(e.name)) + else: + f.write("enum **{}**:\n\n".format(e.name)) + for value in e.values.values(): f.write("- **{}** = **{}**".format(value.name, value.value)) if value.text is not None and value.text.strip() != "": @@ -732,6 +781,26 @@ def make_rst_class(class_def, state, dry_run, output_dir): # type: (ClassDef, S f.write("\n\n") + if len(class_def.annotations) > 0: + f.write(make_heading("Annotations", "-")) + index = 0 + + for method_list in class_def.annotations.values(): + for i, m in enumerate(method_list): + if index != 0: + f.write("----\n\n") + + if i == 0: + f.write(".. _class_{}_annotation_{}:\n\n".format(class_name, m.name.strip("@"))) + + ret_type, signature = make_method_signature(class_def, m, "", state) + f.write("- {} {}\n\n".format(ret_type, signature)) + + if m.description is not None and m.description.strip() != "": + f.write(rstize_text(m.description.strip(), state) + "\n\n") + + index += 1 + # Property descriptions if any(not p.overrides for p in class_def.properties.values()) > 0: f.write(make_heading("Property Descriptions", "-")) @@ -857,7 +926,7 @@ def make_rst_class(class_def, state, dry_run, output_dir): # type: (ClassDef, S f.write(make_footer()) -def escape_rst(text, until_pos=-1): # type: (str) -> str +def escape_rst(text, until_pos=-1): # type: (str, int) -> str # Escape \ character, otherwise it ends up as an escape character in rst pos = 0 while True: @@ -1065,6 +1134,11 @@ def rstize_text(text, state): # type: (str, State) -> str print_error('{}.xml: Unresolved signal "{}".'.format(state.current_class, param), state) ref_type = "_signal" + elif cmd.startswith("annotation"): + if method_param not in class_def.annotations: + print_error('{}.xml: Unresolved annotation "{}".'.format(state.current_class, param), state) + ref_type = "_annotation" + elif cmd.startswith("constant"): found = False @@ -1246,7 +1320,7 @@ def rstize_text(text, state): # type: (str, State) -> str return text -def format_table(f, data, remove_empty_columns=False): # type: (TextIO, Iterable[Tuple[str, ...]]) -> None +def format_table(f, data, remove_empty_columns=False): # type: (TextIO, Iterable[Tuple[str, ...]], bool) -> None if len(data) == 0: return |