summaryrefslogtreecommitdiffstats
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.py977
1 files changed, 508 insertions, 469 deletions
diff --git a/doc/tools/make_rst.py b/doc/tools/make_rst.py
index 4e735039f7..43e1afe720 100755
--- a/doc/tools/make_rst.py
+++ b/doc/tools/make_rst.py
@@ -87,6 +87,7 @@ BASE_STRINGS = [
"This method may be changed or removed in future versions.",
"This operator may be changed or removed in future versions.",
"This theme property may be changed or removed in future versions.",
+ "[b]Note:[/b] The returned array is [i]copied[/i] and any changes to it will not update the original property value. See [%s] for more details.",
]
strings_l10n: Dict[str, str] = {}
@@ -142,9 +143,23 @@ CLASSES_WITH_CSHARP_DIFFERENCES: List[str] = [
"PackedStringArray",
"PackedVector2Array",
"PackedVector3Array",
+ "PackedVector4Array",
"Variant",
]
+PACKED_ARRAY_TYPES: List[str] = [
+ "PackedByteArray",
+ "PackedColorArray",
+ "PackedFloat32Array",
+ "Packedfloat64Array",
+ "PackedInt32Array",
+ "PackedInt64Array",
+ "PackedStringArray",
+ "PackedVector2Array",
+ "PackedVector3Array",
+ "PackedVector4Array",
+]
+
class State:
def __init__(self) -> None:
@@ -437,7 +452,7 @@ class State:
class TagState:
- def __init__(self, raw: str, name: str, arguments: List[str], closing: bool) -> None:
+ def __init__(self, raw: str, name: str, arguments: str, closing: bool) -> None:
self.raw = raw
self.name = name
@@ -662,17 +677,6 @@ class ScriptLanguageParityCheck:
# Entry point for the RST generator.
def main() -> None:
- # Enable ANSI escape code support on Windows 10 and later (for colored console output).
- # <https://bugs.python.org/issue29059>
- if platform.system().lower() == "windows":
- from ctypes import windll, c_int, byref # type: ignore
-
- stdout_handle = windll.kernel32.GetStdHandle(c_int(-11))
- mode = c_int(0)
- windll.kernel32.GetConsoleMode(c_int(stdout_handle), byref(mode))
- mode = c_int(mode.value | 4)
- windll.kernel32.SetConsoleMode(c_int(stdout_handle), mode)
-
parser = argparse.ArgumentParser()
parser.add_argument("path", nargs="+", help="A path to an XML file or a directory containing XML files to parse.")
parser.add_argument("--filter", default="", help="The filepath pattern for XML files to filter.")
@@ -696,7 +700,25 @@ def main() -> None:
)
args = parser.parse_args()
- should_color = args.color or (hasattr(sys.stdout, "isatty") and sys.stdout.isatty())
+ should_color = bool(args.color or sys.stdout.isatty() or os.environ.get("CI"))
+
+ # Enable ANSI escape code support on Windows 10 and later (for colored console output).
+ # <https://github.com/python/cpython/issues/73245>
+ if should_color and sys.stdout.isatty() and sys.platform == "win32":
+ try:
+ from ctypes import windll, byref, WinError # type: ignore
+ from ctypes.wintypes import DWORD # type: ignore
+
+ stdout_handle = windll.kernel32.GetStdHandle(DWORD(-11))
+ mode = DWORD(0)
+ if not windll.kernel32.GetConsoleMode(stdout_handle, byref(mode)):
+ raise WinError()
+ mode = DWORD(mode.value | 4)
+ if not windll.kernel32.SetConsoleMode(stdout_handle, mode):
+ raise WinError()
+ except Exception:
+ should_color = False
+
STYLES["red"] = "\x1b[91m" if should_color else ""
STYLES["green"] = "\x1b[92m" if should_color else ""
STYLES["yellow"] = "\x1b[93m" if should_color else ""
@@ -889,568 +911,573 @@ def get_git_branch() -> str:
def make_rst_class(class_def: ClassDef, state: State, dry_run: bool, output_dir: str) -> None:
class_name = class_def.name
+ with open(
+ os.devnull if dry_run else os.path.join(output_dir, f"class_{class_name.lower()}.rst"),
+ "w",
+ encoding="utf-8",
+ newline="\n",
+ ) as f:
+ # Remove the "Edit on Github" button from the online docs page.
+ f.write(":github_url: hide\n\n")
+
+ # Add keywords metadata.
+ if class_def.keywords is not None and class_def.keywords != "":
+ f.write(f".. meta::\n\t:keywords: {class_def.keywords}\n\n")
+
+ # Warn contributors not to edit this file directly.
+ # Also provide links to the source files for reference.
+
+ git_branch = get_git_branch()
+ source_xml_path = os.path.relpath(class_def.filepath, root_directory).replace("\\", "/")
+ source_github_url = f"https://github.com/godotengine/godot/tree/{git_branch}/{source_xml_path}"
+ generator_github_url = f"https://github.com/godotengine/godot/tree/{git_branch}/doc/tools/make_rst.py"
+
+ f.write(".. DO NOT EDIT THIS FILE!!!\n")
+ f.write(".. Generated automatically from Godot engine sources.\n")
+ f.write(f".. Generator: {generator_github_url}.\n")
+ f.write(f".. XML source: {source_github_url}.\n\n")
+
+ # Document reference id and header.
+ f.write(f".. _class_{class_name}:\n\n")
+ f.write(make_heading(class_name, "=", False))
+
+ f.write(make_deprecated_experimental(class_def, state))
+
+ ### INHERITANCE TREE ###
+
+ # Ascendants
+ if class_def.inherits:
+ inherits = class_def.inherits.strip()
+ f.write(f'**{translate("Inherits:")}** ')
+ first = True
+ while inherits in state.classes:
+ if not first:
+ f.write(" **<** ")
+ else:
+ first = False
- if dry_run:
- f = open(os.devnull, "w", encoding="utf-8")
- else:
- f = open(os.path.join(output_dir, f"class_{class_name.lower()}.rst"), "w", encoding="utf-8")
-
- # Remove the "Edit on Github" button from the online docs page.
- f.write(":github_url: hide\n\n")
-
- # Add keywords metadata.
- if class_def.keywords is not None and class_def.keywords != "":
- f.write(f".. meta::\n\t:keywords: {class_def.keywords}\n\n")
+ f.write(make_type(inherits, state))
+ inode = state.classes[inherits].inherits
+ if inode:
+ inherits = inode.strip()
+ else:
+ break
+ f.write("\n\n")
- # Warn contributors not to edit this file directly.
- # Also provide links to the source files for reference.
+ # Descendants
+ inherited: List[str] = []
+ for c in state.classes.values():
+ if c.inherits and c.inherits.strip() == class_name:
+ inherited.append(c.name)
+
+ if len(inherited):
+ f.write(f'**{translate("Inherited By:")}** ')
+ for i, child in enumerate(inherited):
+ if i > 0:
+ f.write(", ")
+ f.write(make_type(child, state))
+ f.write("\n\n")
- git_branch = get_git_branch()
- source_xml_path = os.path.relpath(class_def.filepath, root_directory).replace("\\", "/")
- source_github_url = f"https://github.com/godotengine/godot/tree/{git_branch}/{source_xml_path}"
- generator_github_url = f"https://github.com/godotengine/godot/tree/{git_branch}/doc/tools/make_rst.py"
+ ### INTRODUCTION ###
- f.write(".. DO NOT EDIT THIS FILE!!!\n")
- f.write(".. Generated automatically from Godot engine sources.\n")
- f.write(f".. Generator: {generator_github_url}.\n")
- f.write(f".. XML source: {source_github_url}.\n\n")
+ has_description = False
- # Document reference id and header.
- f.write(f".. _class_{class_name}:\n\n")
- f.write(make_heading(class_name, "=", False))
+ # Brief description
+ if class_def.brief_description is not None and class_def.brief_description.strip() != "":
+ has_description = True
- f.write(make_deprecated_experimental(class_def, state))
+ f.write(f"{format_text_block(class_def.brief_description.strip(), class_def, state)}\n\n")
- ### INHERITANCE TREE ###
+ # Class description
+ if class_def.description is not None and class_def.description.strip() != "":
+ has_description = True
- # Ascendants
- if class_def.inherits:
- inherits = class_def.inherits.strip()
- f.write(f'**{translate("Inherits:")}** ')
- first = True
- while inherits in state.classes:
- if not first:
- f.write(" **<** ")
- else:
- first = False
+ f.write(".. rst-class:: classref-introduction-group\n\n")
+ f.write(make_heading("Description", "-"))
- f.write(make_type(inherits, state))
- inode = state.classes[inherits].inherits
- if inode:
- inherits = inode.strip()
- else:
- break
- f.write("\n\n")
+ f.write(f"{format_text_block(class_def.description.strip(), class_def, state)}\n\n")
- # Descendants
- inherited: List[str] = []
- for c in state.classes.values():
- if c.inherits and c.inherits.strip() == class_name:
- inherited.append(c.name)
+ if not has_description:
+ f.write(".. container:: contribute\n\n\t")
+ f.write(
+ translate(
+ "There is currently no description for this class. Please help us by :ref:`contributing one <doc_updating_the_class_reference>`!"
+ )
+ + "\n\n"
+ )
- if len(inherited):
- f.write(f'**{translate("Inherited By:")}** ')
- for i, child in enumerate(inherited):
- if i > 0:
- f.write(", ")
- f.write(make_type(child, state))
- f.write("\n\n")
+ if class_def.name in CLASSES_WITH_CSHARP_DIFFERENCES:
+ f.write(".. note::\n\n\t")
+ f.write(
+ translate(
+ "There are notable differences when using this API with C#. See :ref:`doc_c_sharp_differences` for more information."
+ )
+ + "\n\n"
+ )
- ### INTRODUCTION ###
+ # Online tutorials
+ if len(class_def.tutorials) > 0:
+ f.write(".. rst-class:: classref-introduction-group\n\n")
+ f.write(make_heading("Tutorials", "-"))
- has_description = False
+ for url, title in class_def.tutorials:
+ f.write(f"- {make_link(url, title)}\n\n")
- # Brief description
- if class_def.brief_description is not None and class_def.brief_description.strip() != "":
- has_description = True
+ ### REFERENCE TABLES ###
- f.write(f"{format_text_block(class_def.brief_description.strip(), class_def, state)}\n\n")
+ # Reused container for reference tables.
+ ml: List[Tuple[Optional[str], ...]] = []
- # Class description
- if class_def.description is not None and class_def.description.strip() != "":
- has_description = True
+ # Properties reference table
+ if len(class_def.properties) > 0:
+ f.write(".. rst-class:: classref-reftable-group\n\n")
+ f.write(make_heading("Properties", "-"))
- f.write(".. rst-class:: classref-introduction-group\n\n")
- f.write(make_heading("Description", "-"))
+ ml = []
+ for property_def in class_def.properties.values():
+ type_rst = property_def.type_name.to_rst(state)
+ default = property_def.default_value
+ if default is not None and property_def.overrides:
+ ref = (
+ f":ref:`{property_def.overrides}<class_{property_def.overrides}_property_{property_def.name}>`"
+ )
+ # Not using translate() for now as it breaks table formatting.
+ ml.append((type_rst, property_def.name, f"{default} (overrides {ref})"))
+ else:
+ ref = f":ref:`{property_def.name}<class_{class_name}_property_{property_def.name}>`"
+ ml.append((type_rst, ref, default))
- f.write(f"{format_text_block(class_def.description.strip(), class_def, state)}\n\n")
+ format_table(f, ml, True)
- if not has_description:
- f.write(".. container:: contribute\n\n\t")
- f.write(
- translate(
- "There is currently no description for this class. Please help us by :ref:`contributing one <doc_updating_the_class_reference>`!"
- )
- + "\n\n"
- )
+ # Constructors, Methods, Operators reference tables
+ if len(class_def.constructors) > 0:
+ f.write(".. rst-class:: classref-reftable-group\n\n")
+ f.write(make_heading("Constructors", "-"))
- if class_def.name in CLASSES_WITH_CSHARP_DIFFERENCES:
- f.write(".. note::\n\n\t")
- f.write(
- translate(
- "There are notable differences when using this API with C#. See :ref:`doc_c_sharp_differences` for more information."
- )
- + "\n\n"
- )
+ ml = []
+ for method_list in class_def.constructors.values():
+ for m in method_list:
+ ml.append(make_method_signature(class_def, m, "constructor", state))
- # Online tutorials
- if len(class_def.tutorials) > 0:
- f.write(".. rst-class:: classref-introduction-group\n\n")
- f.write(make_heading("Tutorials", "-"))
+ format_table(f, ml)
- for url, title in class_def.tutorials:
- f.write(f"- {make_link(url, title)}\n\n")
+ if len(class_def.methods) > 0:
+ f.write(".. rst-class:: classref-reftable-group\n\n")
+ f.write(make_heading("Methods", "-"))
- ### REFERENCE TABLES ###
+ ml = []
+ for method_list in class_def.methods.values():
+ for m in method_list:
+ ml.append(make_method_signature(class_def, m, "method", state))
- # Reused container for reference tables.
- ml: List[Tuple[Optional[str], ...]] = []
+ format_table(f, ml)
- # Properties reference table
- if len(class_def.properties) > 0:
- f.write(".. rst-class:: classref-reftable-group\n\n")
- f.write(make_heading("Properties", "-"))
+ if len(class_def.operators) > 0:
+ f.write(".. rst-class:: classref-reftable-group\n\n")
+ f.write(make_heading("Operators", "-"))
- ml = []
- for property_def in class_def.properties.values():
- type_rst = property_def.type_name.to_rst(state)
- default = property_def.default_value
- if default is not None and property_def.overrides:
- ref = f":ref:`{property_def.overrides}<class_{property_def.overrides}_property_{property_def.name}>`"
- # Not using translate() for now as it breaks table formatting.
- ml.append((type_rst, property_def.name, f"{default} (overrides {ref})"))
- else:
- ref = f":ref:`{property_def.name}<class_{class_name}_property_{property_def.name}>`"
- ml.append((type_rst, ref, default))
+ ml = []
+ for method_list in class_def.operators.values():
+ for m in method_list:
+ ml.append(make_method_signature(class_def, m, "operator", state))
- format_table(f, ml, True)
+ format_table(f, ml)
- # Constructors, Methods, Operators reference tables
- if len(class_def.constructors) > 0:
- f.write(".. rst-class:: classref-reftable-group\n\n")
- f.write(make_heading("Constructors", "-"))
+ # Theme properties reference table
+ if len(class_def.theme_items) > 0:
+ f.write(".. rst-class:: classref-reftable-group\n\n")
+ f.write(make_heading("Theme Properties", "-"))
- ml = []
- for method_list in class_def.constructors.values():
- for m in method_list:
- ml.append(make_method_signature(class_def, m, "constructor", state))
+ ml = []
+ for theme_item_def in class_def.theme_items.values():
+ ref = f":ref:`{theme_item_def.name}<class_{class_name}_theme_{theme_item_def.data_name}_{theme_item_def.name}>`"
+ ml.append((theme_item_def.type_name.to_rst(state), ref, theme_item_def.default_value))
- format_table(f, ml)
+ format_table(f, ml, True)
- if len(class_def.methods) > 0:
- f.write(".. rst-class:: classref-reftable-group\n\n")
- f.write(make_heading("Methods", "-"))
+ ### DETAILED DESCRIPTIONS ###
- ml = []
- for method_list in class_def.methods.values():
- for m in method_list:
- ml.append(make_method_signature(class_def, m, "method", state))
+ # Signal descriptions
+ if len(class_def.signals) > 0:
+ f.write(make_separator(True))
+ f.write(".. rst-class:: classref-descriptions-group\n\n")
+ f.write(make_heading("Signals", "-"))
- format_table(f, ml)
+ index = 0
- if len(class_def.operators) > 0:
- f.write(".. rst-class:: classref-reftable-group\n\n")
- f.write(make_heading("Operators", "-"))
+ for signal in class_def.signals.values():
+ if index != 0:
+ f.write(make_separator())
- ml = []
- for method_list in class_def.operators.values():
- for m in method_list:
- ml.append(make_method_signature(class_def, m, "operator", state))
+ # Create signal signature and anchor point.
- format_table(f, ml)
+ f.write(f".. _class_{class_name}_signal_{signal.name}:\n\n")
+ f.write(".. rst-class:: classref-signal\n\n")
- # Theme properties reference table
- if len(class_def.theme_items) > 0:
- f.write(".. rst-class:: classref-reftable-group\n\n")
- f.write(make_heading("Theme Properties", "-"))
+ _, signature = make_method_signature(class_def, signal, "", state)
+ f.write(f"{signature}\n\n")
- ml = []
- for theme_item_def in class_def.theme_items.values():
- ref = f":ref:`{theme_item_def.name}<class_{class_name}_theme_{theme_item_def.data_name}_{theme_item_def.name}>`"
- ml.append((theme_item_def.type_name.to_rst(state), ref, theme_item_def.default_value))
+ # Add signal description, or a call to action if it's missing.
- format_table(f, ml, True)
+ f.write(make_deprecated_experimental(signal, state))
- ### DETAILED DESCRIPTIONS ###
+ if signal.description is not None and signal.description.strip() != "":
+ f.write(f"{format_text_block(signal.description.strip(), signal, state)}\n\n")
+ elif signal.deprecated is None and signal.experimental is None:
+ f.write(".. container:: contribute\n\n\t")
+ f.write(
+ translate(
+ "There is currently no description for this signal. Please help us by :ref:`contributing one <doc_updating_the_class_reference>`!"
+ )
+ + "\n\n"
+ )
- # Signal descriptions
- if len(class_def.signals) > 0:
- f.write(make_separator(True))
- f.write(".. rst-class:: classref-descriptions-group\n\n")
- f.write(make_heading("Signals", "-"))
+ index += 1
- index = 0
+ # Enumeration descriptions
+ if len(class_def.enums) > 0:
+ f.write(make_separator(True))
+ f.write(".. rst-class:: classref-descriptions-group\n\n")
+ f.write(make_heading("Enumerations", "-"))
- for signal in class_def.signals.values():
- if index != 0:
- f.write(make_separator())
+ index = 0
- # Create signal signature and anchor point.
+ for e in class_def.enums.values():
+ if index != 0:
+ f.write(make_separator())
- f.write(f".. _class_{class_name}_signal_{signal.name}:\n\n")
- f.write(".. rst-class:: classref-signal\n\n")
+ # Create enumeration signature and anchor point.
- _, signature = make_method_signature(class_def, signal, "", state)
- f.write(f"{signature}\n\n")
+ f.write(f".. _enum_{class_name}_{e.name}:\n\n")
+ f.write(".. rst-class:: classref-enumeration\n\n")
- # Add signal description, or a call to action if it's missing.
+ if e.is_bitfield:
+ f.write(f"flags **{e.name}**:\n\n")
+ else:
+ f.write(f"enum **{e.name}**:\n\n")
- f.write(make_deprecated_experimental(signal, state))
+ for value in e.values.values():
+ # Also create signature and anchor point for each enum constant.
- if signal.description is not None and signal.description.strip() != "":
- f.write(f"{format_text_block(signal.description.strip(), signal, state)}\n\n")
- elif signal.deprecated is None and signal.experimental is None:
- f.write(".. container:: contribute\n\n\t")
- f.write(
- translate(
- "There is currently no description for this signal. Please help us by :ref:`contributing one <doc_updating_the_class_reference>`!"
- )
- + "\n\n"
- )
+ f.write(f".. _class_{class_name}_constant_{value.name}:\n\n")
+ f.write(".. rst-class:: classref-enumeration-constant\n\n")
- index += 1
+ f.write(f"{e.type_name.to_rst(state)} **{value.name}** = ``{value.value}``\n\n")
- # Enumeration descriptions
- if len(class_def.enums) > 0:
- f.write(make_separator(True))
- f.write(".. rst-class:: classref-descriptions-group\n\n")
- f.write(make_heading("Enumerations", "-"))
+ # Add enum constant description.
- index = 0
+ f.write(make_deprecated_experimental(value, state))
- for e in class_def.enums.values():
- if index != 0:
- f.write(make_separator())
+ if value.text is not None and value.text.strip() != "":
+ f.write(f"{format_text_block(value.text.strip(), value, state)}")
+ elif value.deprecated is None and value.experimental is None:
+ f.write(".. container:: contribute\n\n\t")
+ f.write(
+ translate(
+ "There is currently no description for this enum. Please help us by :ref:`contributing one <doc_updating_the_class_reference>`!"
+ )
+ + "\n\n"
+ )
- # Create enumeration signature and anchor point.
+ f.write("\n\n")
- f.write(f".. _enum_{class_name}_{e.name}:\n\n")
- f.write(".. rst-class:: classref-enumeration\n\n")
+ index += 1
- if e.is_bitfield:
- f.write(f"flags **{e.name}**:\n\n")
- else:
- f.write(f"enum **{e.name}**:\n\n")
+ # Constant descriptions
+ if len(class_def.constants) > 0:
+ f.write(make_separator(True))
+ f.write(".. rst-class:: classref-descriptions-group\n\n")
+ f.write(make_heading("Constants", "-"))
- for value in e.values.values():
- # Also create signature and anchor point for each enum constant.
+ for constant in class_def.constants.values():
+ # Create constant signature and anchor point.
- f.write(f".. _class_{class_name}_constant_{value.name}:\n\n")
- f.write(".. rst-class:: classref-enumeration-constant\n\n")
+ f.write(f".. _class_{class_name}_constant_{constant.name}:\n\n")
+ f.write(".. rst-class:: classref-constant\n\n")
- f.write(f"{e.type_name.to_rst(state)} **{value.name}** = ``{value.value}``\n\n")
+ f.write(f"**{constant.name}** = ``{constant.value}``\n\n")
- # Add enum constant description.
+ # Add constant description.
- f.write(make_deprecated_experimental(value, state))
+ f.write(make_deprecated_experimental(constant, state))
- if value.text is not None and value.text.strip() != "":
- f.write(f"{format_text_block(value.text.strip(), value, state)}")
- elif value.deprecated is None and value.experimental is None:
+ if constant.text is not None and constant.text.strip() != "":
+ f.write(f"{format_text_block(constant.text.strip(), constant, state)}")
+ elif constant.deprecated is None and constant.experimental is None:
f.write(".. container:: contribute\n\n\t")
f.write(
translate(
- "There is currently no description for this enum. Please help us by :ref:`contributing one <doc_updating_the_class_reference>`!"
+ "There is currently no description for this constant. Please help us by :ref:`contributing one <doc_updating_the_class_reference>`!"
)
+ "\n\n"
)
f.write("\n\n")
- index += 1
+ # Annotation descriptions
+ if len(class_def.annotations) > 0:
+ f.write(make_separator(True))
+ f.write(make_heading("Annotations", "-"))
- # Constant descriptions
- if len(class_def.constants) > 0:
- f.write(make_separator(True))
- f.write(".. rst-class:: classref-descriptions-group\n\n")
- f.write(make_heading("Constants", "-"))
+ index = 0
- for constant in class_def.constants.values():
- # Create constant signature and anchor point.
+ for method_list in class_def.annotations.values(): # type: ignore
+ for i, m in enumerate(method_list):
+ if index != 0:
+ f.write(make_separator())
- f.write(f".. _class_{class_name}_constant_{constant.name}:\n\n")
- f.write(".. rst-class:: classref-constant\n\n")
+ # Create annotation signature and anchor point.
- f.write(f"**{constant.name}** = ``{constant.value}``\n\n")
+ if i == 0:
+ f.write(f".. _class_{class_name}_annotation_{m.name}:\n\n")
- # Add constant description.
+ f.write(".. rst-class:: classref-annotation\n\n")
- f.write(make_deprecated_experimental(constant, state))
+ _, signature = make_method_signature(class_def, m, "", state)
+ f.write(f"{signature}\n\n")
- if constant.text is not None and constant.text.strip() != "":
- f.write(f"{format_text_block(constant.text.strip(), constant, state)}")
- elif constant.deprecated is None and constant.experimental is None:
- f.write(".. container:: contribute\n\n\t")
- f.write(
- translate(
- "There is currently no description for this constant. Please help us by :ref:`contributing one <doc_updating_the_class_reference>`!"
- )
- + "\n\n"
- )
+ # Add annotation description, or a call to action if it's missing.
- f.write("\n\n")
+ if m.description is not None and m.description.strip() != "":
+ f.write(f"{format_text_block(m.description.strip(), m, state)}\n\n")
+ else:
+ f.write(".. container:: contribute\n\n\t")
+ f.write(
+ translate(
+ "There is currently no description for this annotation. Please help us by :ref:`contributing one <doc_updating_the_class_reference>`!"
+ )
+ + "\n\n"
+ )
+
+ index += 1
- # Annotation descriptions
- if len(class_def.annotations) > 0:
- f.write(make_separator(True))
- f.write(make_heading("Annotations", "-"))
+ # Property descriptions
+ if any(not p.overrides for p in class_def.properties.values()) > 0:
+ f.write(make_separator(True))
+ f.write(".. rst-class:: classref-descriptions-group\n\n")
+ f.write(make_heading("Property Descriptions", "-"))
- index = 0
+ index = 0
+
+ for property_def in class_def.properties.values():
+ if property_def.overrides:
+ continue
- for method_list in class_def.annotations.values(): # type: ignore
- for i, m in enumerate(method_list):
if index != 0:
f.write(make_separator())
- # Create annotation signature and anchor point.
+ # Create property signature and anchor point.
- if i == 0:
- f.write(f".. _class_{class_name}_annotation_{m.name}:\n\n")
+ f.write(f".. _class_{class_name}_property_{property_def.name}:\n\n")
+ f.write(".. rst-class:: classref-property\n\n")
- f.write(".. rst-class:: classref-annotation\n\n")
+ property_default = ""
+ if property_def.default_value is not None:
+ property_default = f" = {property_def.default_value}"
+ f.write(f"{property_def.type_name.to_rst(state)} **{property_def.name}**{property_default}\n\n")
- _, signature = make_method_signature(class_def, m, "", state)
- f.write(f"{signature}\n\n")
+ # Create property setter and getter records.
- # Add annotation description, or a call to action if it's missing.
+ property_setget = ""
- if m.description is not None and m.description.strip() != "":
- f.write(f"{format_text_block(m.description.strip(), m, state)}\n\n")
- else:
+ if property_def.setter is not None and not property_def.setter.startswith("_"):
+ property_setter = make_setter_signature(class_def, property_def, state)
+ property_setget += f"- {property_setter}\n"
+
+ if property_def.getter is not None and not property_def.getter.startswith("_"):
+ property_getter = make_getter_signature(class_def, property_def, state)
+ property_setget += f"- {property_getter}\n"
+
+ if property_setget != "":
+ f.write(".. rst-class:: classref-property-setget\n\n")
+ f.write(property_setget)
+ f.write("\n")
+
+ # Add property description, or a call to action if it's missing.
+
+ f.write(make_deprecated_experimental(property_def, state))
+
+ if property_def.text is not None and property_def.text.strip() != "":
+ f.write(f"{format_text_block(property_def.text.strip(), property_def, state)}\n\n")
+ if property_def.type_name.type_name in PACKED_ARRAY_TYPES:
+ tmp = f"[b]Note:[/b] The returned array is [i]copied[/i] and any changes to it will not update the original property value. See [{property_def.type_name.type_name}] for more details."
+ f.write(f"{format_text_block(tmp, property_def, state)}\n\n")
+ elif property_def.deprecated is None and property_def.experimental is None:
f.write(".. container:: contribute\n\n\t")
f.write(
translate(
- "There is currently no description for this annotation. Please help us by :ref:`contributing one <doc_updating_the_class_reference>`!"
+ "There is currently no description for this property. Please help us by :ref:`contributing one <doc_updating_the_class_reference>`!"
)
+ "\n\n"
)
index += 1
- # Property descriptions
- if any(not p.overrides for p in class_def.properties.values()) > 0:
- f.write(make_separator(True))
- f.write(".. rst-class:: classref-descriptions-group\n\n")
- f.write(make_heading("Property Descriptions", "-"))
-
- index = 0
-
- for property_def in class_def.properties.values():
- if property_def.overrides:
- continue
-
- if index != 0:
- f.write(make_separator())
+ # Constructor, Method, Operator descriptions
+ if len(class_def.constructors) > 0:
+ f.write(make_separator(True))
+ f.write(".. rst-class:: classref-descriptions-group\n\n")
+ f.write(make_heading("Constructor Descriptions", "-"))
- # Create property signature and anchor point.
+ index = 0
- f.write(f".. _class_{class_name}_property_{property_def.name}:\n\n")
- f.write(".. rst-class:: classref-property\n\n")
+ for method_list in class_def.constructors.values():
+ for i, m in enumerate(method_list):
+ if index != 0:
+ f.write(make_separator())
- property_default = ""
- if property_def.default_value is not None:
- property_default = f" = {property_def.default_value}"
- f.write(f"{property_def.type_name.to_rst(state)} **{property_def.name}**{property_default}\n\n")
+ # Create constructor signature and anchor point.
- # Create property setter and getter records.
+ if i == 0:
+ f.write(f".. _class_{class_name}_constructor_{m.name}:\n\n")
- property_setget = ""
+ f.write(".. rst-class:: classref-constructor\n\n")
- if property_def.setter is not None and not property_def.setter.startswith("_"):
- property_setter = make_setter_signature(class_def, property_def, state)
- property_setget += f"- {property_setter}\n"
+ ret_type, signature = make_method_signature(class_def, m, "", state)
+ f.write(f"{ret_type} {signature}\n\n")
- if property_def.getter is not None and not property_def.getter.startswith("_"):
- property_getter = make_getter_signature(class_def, property_def, state)
- property_setget += f"- {property_getter}\n"
-
- if property_setget != "":
- f.write(".. rst-class:: classref-property-setget\n\n")
- f.write(property_setget)
- f.write("\n")
+ # Add constructor description, or a call to action if it's missing.
- # Add property description, or a call to action if it's missing.
+ f.write(make_deprecated_experimental(m, state))
- f.write(make_deprecated_experimental(property_def, state))
+ if m.description is not None and m.description.strip() != "":
+ f.write(f"{format_text_block(m.description.strip(), m, state)}\n\n")
+ elif m.deprecated is None and m.experimental is None:
+ f.write(".. container:: contribute\n\n\t")
+ f.write(
+ translate(
+ "There is currently no description for this constructor. Please help us by :ref:`contributing one <doc_updating_the_class_reference>`!"
+ )
+ + "\n\n"
+ )
- if property_def.text is not None and property_def.text.strip() != "":
- f.write(f"{format_text_block(property_def.text.strip(), property_def, state)}\n\n")
- elif property_def.deprecated is None and property_def.experimental is None:
- f.write(".. container:: contribute\n\n\t")
- f.write(
- translate(
- "There is currently no description for this property. Please help us by :ref:`contributing one <doc_updating_the_class_reference>`!"
- )
- + "\n\n"
- )
+ index += 1
- index += 1
+ if len(class_def.methods) > 0:
+ f.write(make_separator(True))
+ f.write(".. rst-class:: classref-descriptions-group\n\n")
+ f.write(make_heading("Method Descriptions", "-"))
- # Constructor, Method, Operator descriptions
- if len(class_def.constructors) > 0:
- f.write(make_separator(True))
- f.write(".. rst-class:: classref-descriptions-group\n\n")
- f.write(make_heading("Constructor Descriptions", "-"))
+ index = 0
- index = 0
+ for method_list in class_def.methods.values():
+ for i, m in enumerate(method_list):
+ if index != 0:
+ f.write(make_separator())
- for method_list in class_def.constructors.values():
- for i, m in enumerate(method_list):
- if index != 0:
- f.write(make_separator())
+ # Create method signature and anchor point.
- # Create constructor signature and anchor point.
+ if i == 0:
+ method_qualifier = ""
+ if m.name.startswith("_"):
+ method_qualifier = "private_"
- if i == 0:
- f.write(f".. _class_{class_name}_constructor_{m.name}:\n\n")
+ f.write(f".. _class_{class_name}_{method_qualifier}method_{m.name}:\n\n")
- f.write(".. rst-class:: classref-constructor\n\n")
+ f.write(".. rst-class:: classref-method\n\n")
- ret_type, signature = make_method_signature(class_def, m, "", state)
- f.write(f"{ret_type} {signature}\n\n")
+ ret_type, signature = make_method_signature(class_def, m, "", state)
+ f.write(f"{ret_type} {signature}\n\n")
- # Add constructor description, or a call to action if it's missing.
+ # Add method description, or a call to action if it's missing.
- f.write(make_deprecated_experimental(m, state))
+ f.write(make_deprecated_experimental(m, state))
- if m.description is not None and m.description.strip() != "":
- f.write(f"{format_text_block(m.description.strip(), m, state)}\n\n")
- elif m.deprecated is None and m.experimental is None:
- f.write(".. container:: contribute\n\n\t")
- f.write(
- translate(
- "There is currently no description for this constructor. Please help us by :ref:`contributing one <doc_updating_the_class_reference>`!"
+ if m.description is not None and m.description.strip() != "":
+ f.write(f"{format_text_block(m.description.strip(), m, state)}\n\n")
+ elif m.deprecated is None and m.experimental is None:
+ f.write(".. container:: contribute\n\n\t")
+ f.write(
+ translate(
+ "There is currently no description for this method. Please help us by :ref:`contributing one <doc_updating_the_class_reference>`!"
+ )
+ + "\n\n"
)
- + "\n\n"
- )
- index += 1
-
- if len(class_def.methods) > 0:
- f.write(make_separator(True))
- f.write(".. rst-class:: classref-descriptions-group\n\n")
- f.write(make_heading("Method Descriptions", "-"))
+ index += 1
- index = 0
+ if len(class_def.operators) > 0:
+ f.write(make_separator(True))
+ f.write(".. rst-class:: classref-descriptions-group\n\n")
+ f.write(make_heading("Operator Descriptions", "-"))
- for method_list in class_def.methods.values():
- for i, m in enumerate(method_list):
- if index != 0:
- f.write(make_separator())
+ index = 0
- # Create method signature and anchor point.
+ for method_list in class_def.operators.values():
+ for i, m in enumerate(method_list):
+ if index != 0:
+ f.write(make_separator())
- if i == 0:
- method_qualifier = ""
- if m.name.startswith("_"):
- method_qualifier = "private_"
+ # Create operator signature and anchor point.
- f.write(f".. _class_{class_name}_{method_qualifier}method_{m.name}:\n\n")
+ operator_anchor = f".. _class_{class_name}_operator_{sanitize_operator_name(m.name, state)}"
+ for parameter in m.parameters:
+ operator_anchor += f"_{parameter.type_name.type_name}"
+ operator_anchor += f":\n\n"
+ f.write(operator_anchor)
- f.write(".. rst-class:: classref-method\n\n")
+ f.write(".. rst-class:: classref-operator\n\n")
- ret_type, signature = make_method_signature(class_def, m, "", state)
- f.write(f"{ret_type} {signature}\n\n")
+ ret_type, signature = make_method_signature(class_def, m, "", state)
+ f.write(f"{ret_type} {signature}\n\n")
- # Add method description, or a call to action if it's missing.
+ # Add operator description, or a call to action if it's missing.
- f.write(make_deprecated_experimental(m, state))
+ f.write(make_deprecated_experimental(m, state))
- if m.description is not None and m.description.strip() != "":
- f.write(f"{format_text_block(m.description.strip(), m, state)}\n\n")
- elif m.deprecated is None and m.experimental is None:
- f.write(".. container:: contribute\n\n\t")
- f.write(
- translate(
- "There is currently no description for this method. Please help us by :ref:`contributing one <doc_updating_the_class_reference>`!"
+ if m.description is not None and m.description.strip() != "":
+ f.write(f"{format_text_block(m.description.strip(), m, state)}\n\n")
+ elif m.deprecated is None and m.experimental is None:
+ f.write(".. container:: contribute\n\n\t")
+ f.write(
+ translate(
+ "There is currently no description for this operator. Please help us by :ref:`contributing one <doc_updating_the_class_reference>`!"
+ )
+ + "\n\n"
)
- + "\n\n"
- )
- index += 1
+ index += 1
- if len(class_def.operators) > 0:
- f.write(make_separator(True))
- f.write(".. rst-class:: classref-descriptions-group\n\n")
- f.write(make_heading("Operator Descriptions", "-"))
+ # Theme property descriptions
+ if len(class_def.theme_items) > 0:
+ f.write(make_separator(True))
+ f.write(".. rst-class:: classref-descriptions-group\n\n")
+ f.write(make_heading("Theme Property Descriptions", "-"))
- index = 0
+ index = 0
- for method_list in class_def.operators.values():
- for i, m in enumerate(method_list):
+ for theme_item_def in class_def.theme_items.values():
if index != 0:
f.write(make_separator())
- # Create operator signature and anchor point.
+ # Create theme property signature and anchor point.
- operator_anchor = f".. _class_{class_name}_operator_{sanitize_operator_name(m.name, state)}"
- for parameter in m.parameters:
- operator_anchor += f"_{parameter.type_name.type_name}"
- operator_anchor += f":\n\n"
- f.write(operator_anchor)
+ f.write(f".. _class_{class_name}_theme_{theme_item_def.data_name}_{theme_item_def.name}:\n\n")
+ f.write(".. rst-class:: classref-themeproperty\n\n")
- f.write(".. rst-class:: classref-operator\n\n")
+ theme_item_default = ""
+ if theme_item_def.default_value is not None:
+ theme_item_default = f" = {theme_item_def.default_value}"
+ f.write(f"{theme_item_def.type_name.to_rst(state)} **{theme_item_def.name}**{theme_item_default}\n\n")
- ret_type, signature = make_method_signature(class_def, m, "", state)
- f.write(f"{ret_type} {signature}\n\n")
+ # Add theme property description, or a call to action if it's missing.
- # Add operator description, or a call to action if it's missing.
+ f.write(make_deprecated_experimental(theme_item_def, state))
- f.write(make_deprecated_experimental(m, state))
-
- if m.description is not None and m.description.strip() != "":
- f.write(f"{format_text_block(m.description.strip(), m, state)}\n\n")
- elif m.deprecated is None and m.experimental is None:
+ if theme_item_def.text is not None and theme_item_def.text.strip() != "":
+ f.write(f"{format_text_block(theme_item_def.text.strip(), theme_item_def, state)}\n\n")
+ elif theme_item_def.deprecated is None and theme_item_def.experimental is None:
f.write(".. container:: contribute\n\n\t")
f.write(
translate(
- "There is currently no description for this operator. Please help us by :ref:`contributing one <doc_updating_the_class_reference>`!"
+ "There is currently no description for this theme property. Please help us by :ref:`contributing one <doc_updating_the_class_reference>`!"
)
+ "\n\n"
)
index += 1
- # Theme property descriptions
- if len(class_def.theme_items) > 0:
- f.write(make_separator(True))
- f.write(".. rst-class:: classref-descriptions-group\n\n")
- f.write(make_heading("Theme Property Descriptions", "-"))
-
- index = 0
-
- for theme_item_def in class_def.theme_items.values():
- if index != 0:
- f.write(make_separator())
-
- # Create theme property signature and anchor point.
-
- f.write(f".. _class_{class_name}_theme_{theme_item_def.data_name}_{theme_item_def.name}:\n\n")
- f.write(".. rst-class:: classref-themeproperty\n\n")
-
- theme_item_default = ""
- if theme_item_def.default_value is not None:
- theme_item_default = f" = {theme_item_def.default_value}"
- f.write(f"{theme_item_def.type_name.to_rst(state)} **{theme_item_def.name}**{theme_item_default}\n\n")
-
- # Add theme property description, or a call to action if it's missing.
-
- f.write(make_deprecated_experimental(theme_item_def, state))
-
- if theme_item_def.text is not None and theme_item_def.text.strip() != "":
- f.write(f"{format_text_block(theme_item_def.text.strip(), theme_item_def, state)}\n\n")
- elif theme_item_def.deprecated is None and theme_item_def.experimental is None:
- f.write(".. container:: contribute\n\n\t")
- f.write(
- translate(
- "There is currently no description for this theme property. Please help us by :ref:`contributing one <doc_updating_the_class_reference>`!"
- )
- + "\n\n"
- )
-
- index += 1
-
- f.write(make_footer())
+ f.write(make_footer())
def make_type(klass: str, state: State) -> str:
@@ -1690,54 +1717,52 @@ def make_link(url: str, title: str) -> str:
def make_rst_index(grouped_classes: Dict[str, List[str]], dry_run: bool, output_dir: str) -> None:
- if dry_run:
- f = open(os.devnull, "w", encoding="utf-8")
- else:
- f = open(os.path.join(output_dir, "index.rst"), "w", encoding="utf-8")
+ with open(
+ os.devnull if dry_run else os.path.join(output_dir, "index.rst"), "w", encoding="utf-8", newline="\n"
+ ) as f:
+ # Remove the "Edit on Github" button from the online docs page, and disallow user-contributed notes
+ # on the index page. User-contributed notes are allowed on individual class pages.
+ f.write(":github_url: hide\n:allow_comments: False\n\n")
- # Remove the "Edit on Github" button from the online docs page, and disallow user-contributed notes
- # on the index page. User-contributed notes are allowed on individual class pages.
- f.write(":github_url: hide\n:allow_comments: False\n\n")
+ # Warn contributors not to edit this file directly.
+ # Also provide links to the source files for reference.
- # Warn contributors not to edit this file directly.
- # Also provide links to the source files for reference.
+ git_branch = get_git_branch()
+ generator_github_url = f"https://github.com/godotengine/godot/tree/{git_branch}/doc/tools/make_rst.py"
- git_branch = get_git_branch()
- generator_github_url = f"https://github.com/godotengine/godot/tree/{git_branch}/doc/tools/make_rst.py"
+ f.write(".. DO NOT EDIT THIS FILE!!!\n")
+ f.write(".. Generated automatically from Godot engine sources.\n")
+ f.write(f".. Generator: {generator_github_url}.\n\n")
- f.write(".. DO NOT EDIT THIS FILE!!!\n")
- f.write(".. Generated automatically from Godot engine sources.\n")
- f.write(f".. Generator: {generator_github_url}.\n\n")
+ f.write(".. _doc_class_reference:\n\n")
- f.write(".. _doc_class_reference:\n\n")
+ f.write(make_heading("All classes", "="))
- f.write(make_heading("All classes", "="))
+ for group_name in CLASS_GROUPS:
+ if group_name in grouped_classes:
+ f.write(make_heading(CLASS_GROUPS[group_name], "="))
- for group_name in CLASS_GROUPS:
- if group_name in grouped_classes:
- f.write(make_heading(CLASS_GROUPS[group_name], "="))
-
- f.write(".. toctree::\n")
- f.write(" :maxdepth: 1\n")
- f.write(f" :name: toc-class-ref-{group_name}s\n")
- f.write("\n")
+ f.write(".. toctree::\n")
+ f.write(" :maxdepth: 1\n")
+ f.write(f" :name: toc-class-ref-{group_name}s\n")
+ f.write("\n")
- if group_name in CLASS_GROUPS_BASE:
- f.write(f" class_{CLASS_GROUPS_BASE[group_name].lower()}\n")
+ if group_name in CLASS_GROUPS_BASE:
+ f.write(f" class_{CLASS_GROUPS_BASE[group_name].lower()}\n")
- for class_name in grouped_classes[group_name]:
- if group_name in CLASS_GROUPS_BASE and CLASS_GROUPS_BASE[group_name].lower() == class_name.lower():
- continue
+ for class_name in grouped_classes[group_name]:
+ if group_name in CLASS_GROUPS_BASE and CLASS_GROUPS_BASE[group_name].lower() == class_name.lower():
+ continue
- f.write(f" class_{class_name.lower()}\n")
+ f.write(f" class_{class_name.lower()}\n")
- f.write("\n")
+ f.write("\n")
# Formatting helpers.
-RESERVED_FORMATTING_TAGS = ["i", "b", "u", "code", "kbd", "center", "url", "br"]
+RESERVED_FORMATTING_TAGS = ["i", "b", "u", "lb", "rb", "code", "kbd", "center", "url", "br"]
RESERVED_LAYOUT_TAGS = ["codeblocks"]
RESERVED_CODEBLOCK_TAGS = ["codeblock", "gdscript", "csharp"]
RESERVED_CROSSLINK_TAGS = [
@@ -1762,7 +1787,7 @@ def is_in_tagset(tag_text: str, tagset: List[str]) -> bool:
# Tag with arguments.
if tag_text.startswith(tag + " "):
return True
- # Tag with arguments, special case for [url].
+ # Tag with arguments, special case for [url], [color], and [font].
if tag_text.startswith(tag + "="):
return True
@@ -1771,17 +1796,22 @@ def is_in_tagset(tag_text: str, tagset: List[str]) -> bool:
def get_tag_and_args(tag_text: str) -> TagState:
tag_name = tag_text
- arguments: List[str] = []
+ arguments: str = ""
+
+ delim_pos = -1
+ space_pos = tag_text.find(" ")
+ if space_pos >= 0:
+ delim_pos = space_pos
+
+ # Special case for [url], [color], and [font].
assign_pos = tag_text.find("=")
- if assign_pos >= 0:
- tag_name = tag_text[:assign_pos]
- arguments = [tag_text[assign_pos + 1 :].strip()]
- else:
- space_pos = tag_text.find(" ")
- if space_pos >= 0:
- tag_name = tag_text[:space_pos]
- arguments = [tag_text[space_pos + 1 :].strip()]
+ if assign_pos >= 0 and (delim_pos < 0 or assign_pos < delim_pos):
+ delim_pos = assign_pos
+
+ if delim_pos >= 0:
+ tag_name = tag_text[:delim_pos]
+ arguments = tag_text[delim_pos + 1 :].strip()
closing = False
if tag_name.startswith("/"):
@@ -1969,11 +1999,14 @@ def format_text_block(
state,
)
- tag_text = "\n::\n"
+ if "lang=text" in tag_state.arguments.split(" "):
+ tag_text = "\n.. code:: text\n"
+ else:
+ tag_text = "\n::\n"
inside_code = True
inside_code_tag = tag_state.name
- ignore_code_warnings = "skip-lint" in tag_state.arguments
+ ignore_code_warnings = "skip-lint" in tag_state.arguments.split(" ")
elif is_in_tagset(tag_state.name, ["code"]):
tag_text = "``"
@@ -1981,7 +2014,7 @@ def format_text_block(
inside_code = True
inside_code_tag = "code"
- ignore_code_warnings = "skip-lint" in tag_state.arguments
+ ignore_code_warnings = "skip-lint" in tag_state.arguments.split(" ")
escape_pre = True
if not ignore_code_warnings:
@@ -2078,7 +2111,7 @@ def format_text_block(
# Cross-references to items in this or other class documentation pages.
elif is_in_tagset(tag_state.name, RESERVED_CROSSLINK_TAGS):
- link_target: str = tag_state.arguments[0] if len(tag_state.arguments) > 0 else ""
+ link_target: str = tag_state.arguments
if link_target == "":
print_error(
@@ -2238,7 +2271,7 @@ def format_text_block(
# Formatting directives.
elif is_in_tagset(tag_state.name, ["url"]):
- url_target = tag_state.arguments[0] if len(tag_state.arguments) > 0 else ""
+ url_target = tag_state.arguments
if url_target == "":
print_error(
@@ -2311,6 +2344,12 @@ def format_text_block(
escape_pre = True
tag_text = ""
+ elif tag_state.name == "lb":
+ tag_text = "\\["
+
+ elif tag_state.name == "rb":
+ tag_text = "\\]"
+
elif tag_state.name == "kbd":
tag_text = "`"
if tag_state.closing:
@@ -2433,7 +2472,7 @@ def format_codeblock(
opening_formatted = tag_state.name
if len(tag_state.arguments) > 0:
- opening_formatted += " " + " ".join(tag_state.arguments)
+ opening_formatted += " " + tag_state.arguments
code_text = post_text[len(f"[{opening_formatted}]") : end_pos]
post_text = post_text[end_pos:]