summaryrefslogtreecommitdiff
path: root/doc/tools/make_rst.py
diff options
context:
space:
mode:
Diffstat (limited to 'doc/tools/make_rst.py')
-rwxr-xr-xdoc/tools/make_rst.py96
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