diff --git a/doc/tools/doc_merge.py b/doc/tools/doc_merge.py
deleted file mode 100755
index f6f52f5d66d3..000000000000
--- a/doc/tools/doc_merge.py
+++ /dev/null
@@ -1,237 +0,0 @@
-#!/usr/bin/env python
-# -*- coding: utf-8 -*-
-
-import sys
-import xml.etree.ElementTree as ET
-
-
-tree = ET.parse(sys.argv[1])
-old_doc = tree.getroot()
-
-tree = ET.parse(sys.argv[2])
-new_doc = tree.getroot()
-
-f = file(sys.argv[3], "wb")
-tab = 0
-
-old_classes = {}
-
-
-def write_string(_f, text, newline=True):
- for t in range(tab):
- _f.write("\t")
- _f.write(text)
- if newline:
- _f.write("\n")
-
-
-def escape(ret):
- ret = ret.replace("&", "&")
- ret = ret.replace("<", ">")
- ret = ret.replace(">", "<")
- ret = ret.replace("'", "'")
- ret = ret.replace('"', """)
- return ret
-
-
-def inc_tab():
- global tab
- tab += 1
-
-
-def dec_tab():
- global tab
- tab -= 1
-
-
-write_string(f, '')
-write_string(f, '')
-
-
-def get_tag(node, name):
- tag = ""
- if name in node.attrib:
- tag = " " + name + '="' + escape(node.attrib[name]) + '" '
- return tag
-
-
-def find_method_descr(old_class, name):
-
- methods = old_class.find("methods")
- if methods != None and len(list(methods)) > 0:
- for m in list(methods):
- if m.attrib["name"] == name:
- description = m.find("description")
- if description != None and description.text.strip() != "":
- return description.text
-
- return None
-
-
-def find_signal_descr(old_class, name):
-
- signals = old_class.find("signals")
- if signals != None and len(list(signals)) > 0:
- for m in list(signals):
- if m.attrib["name"] == name:
- description = m.find("description")
- if description != None and description.text.strip() != "":
- return description.text
-
- return None
-
-
-def find_constant_descr(old_class, name):
-
- if old_class is None:
- return None
- constants = old_class.find("constants")
- if constants != None and len(list(constants)) > 0:
- for m in list(constants):
- if m.attrib["name"] == name:
- if m.text.strip() != "":
- return m.text
- return None
-
-
-def write_class(c):
- class_name = c.attrib["name"]
- print("Parsing Class: " + class_name)
- if class_name in old_classes:
- old_class = old_classes[class_name]
- else:
- old_class = None
-
- category = get_tag(c, "category")
- inherits = get_tag(c, "inherits")
- write_string(f, '")
- inc_tab()
-
- write_string(f, "")
-
- if old_class != None:
- old_brief_descr = old_class.find("brief_description")
- if old_brief_descr != None:
- write_string(f, escape(old_brief_descr.text.strip()))
-
- write_string(f, "")
-
- write_string(f, "")
- if old_class != None:
- old_descr = old_class.find("description")
- if old_descr != None:
- write_string(f, escape(old_descr.text.strip()))
-
- write_string(f, "")
-
- methods = c.find("methods")
- if methods != None and len(list(methods)) > 0:
-
- write_string(f, "")
- inc_tab()
-
- for m in list(methods):
- qualifiers = get_tag(m, "qualifiers")
-
- write_string(f, '")
- inc_tab()
-
- for a in list(m):
- if a.tag == "return":
- typ = get_tag(a, "type")
- write_string(f, "")
- write_string(f, "")
- elif a.tag == "argument":
-
- default = get_tag(a, "default")
-
- write_string(
- f,
- '",
- )
- write_string(f, "")
-
- write_string(f, "")
- if old_class != None:
- old_method_descr = find_method_descr(old_class, m.attrib["name"])
- if old_method_descr:
- write_string(f, escape(escape(old_method_descr.strip())))
-
- write_string(f, "")
- dec_tab()
- write_string(f, "")
- dec_tab()
- write_string(f, "")
-
- signals = c.find("signals")
- if signals != None and len(list(signals)) > 0:
-
- write_string(f, "")
- inc_tab()
-
- for m in list(signals):
-
- write_string(f, '')
- inc_tab()
-
- for a in list(m):
- if a.tag == "argument":
-
- write_string(
- f,
- '',
- )
- write_string(f, "")
-
- write_string(f, "")
- if old_class != None:
- old_signal_descr = find_signal_descr(old_class, m.attrib["name"])
- if old_signal_descr:
- write_string(f, escape(old_signal_descr.strip()))
- write_string(f, "")
- dec_tab()
- write_string(f, "")
- dec_tab()
- write_string(f, "")
-
- constants = c.find("constants")
- if constants != None and len(list(constants)) > 0:
-
- write_string(f, "")
- inc_tab()
-
- for m in list(constants):
-
- write_string(f, '')
- old_constant_descr = find_constant_descr(old_class, m.attrib["name"])
- if old_constant_descr:
- write_string(f, escape(old_constant_descr.strip()))
- write_string(f, "")
-
- dec_tab()
- write_string(f, "")
-
- dec_tab()
- write_string(f, "")
-
-
-for c in list(old_doc):
- old_classes[c.attrib["name"]] = c
-
-for c in list(new_doc):
- write_class(c)
-write_string(f, "\n")
diff --git a/doc/tools/makerst.py b/doc/tools/makerst.py
index ed147f31cd3a..5335116c8a68 100755
--- a/doc/tools/makerst.py
+++ b/doc/tools/makerst.py
@@ -1042,6 +1042,8 @@ def make_footer(): # type: () -> str
".. |virtual| replace:: :abbr:`virtual (This method should typically be overridden by the user to have any effect.)`\n"
".. |const| replace:: :abbr:`const (This method has no side effects. It doesn't modify any of the instance's member variables.)`\n"
".. |vararg| replace:: :abbr:`vararg (This method accepts any number of arguments after the ones described here.)`\n"
+ ".. |constructor| replace:: :abbr:`constructor (This method is used to construct a type.)`\n"
+ ".. |operator| replace:: :abbr:`operator (This method describes a valid operator to use with this type as left-hand operand.)`\n"
)
# fmt: on
diff --git a/editor/doc_data.cpp b/editor/doc_data.cpp
index 67671597217b..ae31f685878d 100644
--- a/editor/doc_data.cpp
+++ b/editor/doc_data.cpp
@@ -569,12 +569,15 @@ void DocData::generate(bool p_basic_types) {
method_list.sort();
Variant::get_constructor_list(Variant::Type(i), &method_list);
- for (int j = 0; j < Variant::OP_AND; j++) { //showing above 'and' is pretty confusing and there are a lot of variations
-
+ for (int j = 0; j < Variant::OP_AND; j++) { // Showing above 'and' is pretty confusing and there are a lot of variations.
for (int k = 0; k < Variant::VARIANT_MAX; k++) {
Variant::Type rt = Variant::get_operator_return_type(Variant::Operator(j), Variant::Type(i), Variant::Type(k));
- if (rt != Variant::NIL) {
- //has operator
+ if (rt != Variant::NIL) { // Has operator.
+ // Skip String % operator as it's registered separately for each Variant arg type,
+ // we'll add it manually below.
+ if (i == Variant::STRING && Variant::Operator(j) == Variant::OP_MODULE) {
+ continue;
+ }
MethodInfo mi;
mi.name = "operator " + Variant::get_operator_name(Variant::Operator(j));
mi.return_val.type = rt;
@@ -589,6 +592,21 @@ void DocData::generate(bool p_basic_types) {
}
}
+ if (i == Variant::STRING) {
+ // We skipped % operator above, and we register it manually once for Variant arg type here.
+ MethodInfo mi;
+ mi.name = "operator %";
+ mi.return_val.type = Variant::STRING;
+
+ PropertyInfo arg;
+ arg.name = "right";
+ arg.type = Variant::NIL;
+ arg.usage = PROPERTY_USAGE_NIL_IS_VARIANT;
+ mi.arguments.push_back(arg);
+
+ method_list.push_back(mi);
+ }
+
if (Variant::is_keyed(Variant::Type(i))) {
MethodInfo mi;
mi.name = "operator []";
@@ -1147,7 +1165,7 @@ Error DocData::save_classes(const String &p_default_path, const Map");
+ _write_string(f, 2, "");
if (m.return_type != "") {
String enum_text;